[U-Boot] [PATCH 1/6] omap4: usb: Add omap-ehci support
Govindraj.R
govindraj.ti at gmail.com
Wed Dec 14 13:21:22 CET 2011
From: "Govindraj.R" <govindraj.raja at ti.com>
Adds ehci-omap and two funcs omap_ehci_hcd_init/omap_ehci_hcd_stop
Which can be called from any board file implementing the ehci_hcd_init/reset.
One can pass the port modes from board file and configure the usb host
to ulpi-phy mode or hsic mode.
Signed-off-by: Govindraj.R <govindraj.raja at ti.com>
---
arch/arm/include/asm/ehci-omap.h | 168 +++++++++++++++++++++++++++++++
drivers/usb/host/Makefile | 1 +
drivers/usb/host/ehci-omap.c | 202 ++++++++++++++++++++++++++++++++++++++
3 files changed, 371 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/include/asm/ehci-omap.h
create mode 100644 drivers/usb/host/ehci-omap.c
diff --git a/arch/arm/include/asm/ehci-omap.h b/arch/arm/include/asm/ehci-omap.h
new file mode 100644
index 0000000..c1af798
--- /dev/null
+++ b/arch/arm/include/asm/ehci-omap.h
@@ -0,0 +1,168 @@
+/*
+ * OMAP EHCI port support
+ * Based on LINUX KERNEL
+ * drivers/usb/host/ehci-omap.c and drivers/mfd/omap-usb-host.c
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com*
+ * Author: Govindraj R <govindraj.raja at ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EHCI_H
+#define EHCI_H
+
+#define OMAP_EHCI_BASE (OMAP44XX_L4_CORE_BASE + 0x64C00)
+#define OMAP_UHH_BASE (OMAP44XX_L4_CORE_BASE + 0x64000)
+#define OMAP_TLL_BASE (OMAP44XX_L4_CORE_BASE + 0x62000)
+
+/* Alt CLK SRC FOR AUX CLK 3 to USB3220C external PHY */
+#define SCRM_ALTCLKSRC 0x4a30A110UL
+#define SCRM_AUXCLK3 0x4A30A31CUL
+
+/* UHH, TLL and opt clocks */
+#define CM_L3INIT_HSUSBHOST_CLKCTRL 0x4A009358UL
+
+#define HSUSBHOST_CLKCTRL_CLKSEL_UTMI_P1_MASK (1 << 24)
+
+/* ULPI */
+#define ULPI_SET(a) (a + 1)
+#define ULPI_CLR(a) (a + 2)
+
+#define ULPI_FUNC_CTRL 0x04
+
+#define ULPI_FUNC_CTRL_RESET (1 << 5)
+
+/* TLL Register Set */
+#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3)
+#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2)
+#define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1)
+#define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0)
+#define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0)
+
+#define OMAP_REV2_TLL_CHANNEL_COUNT 2
+
+#define OMAP_TLL_CHANNEL_CONF(num) (0x004 * num)
+#define OMAP_TLL_CHANNEL_CONF_DRVVBUS (1 << 16)
+#define OMAP_TLL_CHANNEL_CONF_CHRGVBUS (1 << 15)
+#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11)
+#define OMAP_TLL_CHANNEL_CONF_CHANMODE_TRANSPARENT_UTMI (2 << 1)
+#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0)
+
+/* UHH Register Set */
+#define OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN (1 << 2)
+#define OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN (1 << 3)
+#define OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN (1 << 4)
+#define OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN (1 << 5)
+#define OMAP_UHH_HOSTCONFIG_APP_START_CLK (1 << 31)
+
+#define OMAP_UHH_SYSCONFIG_SOFTRESET (1 << 0)
+#define OMAP_UHH_SYSCONFIG_IDLEMODE_CLEAR (3 << 2)
+#define OMAP_UHH_SYSCONFIG_NOIDLE (1 << 2)
+
+#define OMAP_UHH_SYSCONFIG_STDBYMODE_CLEAR (3 << 4)
+#define OMAP_UHH_SYSCONFIG_NOSTDBY (1 << 4)
+#define OMAP_UHH_SYSCONFIG_SOFTRESET (1 << 0)
+#define OMAP_UHH_SYSSTATUS_EHCI_RESETDONE (1 << 2)
+
+#define OMAP_P1_MODE_CLEAR (3 << 16)
+#define OMAP_P1_MODE_TLL (1 << 16)
+#define OMAP_P1_MODE_HSIC (3 << 16)
+#define OMAP_P2_MODE_CLEAR (3 << 18)
+#define OMAP_P2_MODE_TLL (1 << 18)
+#define OMAP_P2_MODE_HSIC (3 << 18)
+
+/* EHCI Register Set */
+#define EHCI_INSNREG04_DISABLE_UNSUSPEND (1 << 5)
+#define EHCI_INSNREG05_ULPI_CONTROL_SHIFT 31
+#define EHCI_INSNREG05_ULPI_PORTSEL_SHIFT 24
+#define EHCI_INSNREG05_ULPI_OPSEL_SHIFT 22
+#define EHCI_INSNREG05_ULPI_REGADD_SHIFT 16
+
+enum usbhs_omap_port_mode {
+ OMAP_USBHS_PORT_MODE_UNUSED,
+ OMAP_EHCI_PORT_MODE_PHY,
+ OMAP_EHCI_PORT_MODE_TLL,
+ OMAP_EHCI_PORT_MODE_HSIC,
+};
+
+#define is_ehci_phy_mode(x) (x == OMAP_EHCI_PORT_MODE_PHY)
+#define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL)
+#define is_ehci_hsic_mode(x) (x == OMAP_EHCI_PORT_MODE_HSIC)
+
+#ifdef CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS
+#define OMAP_HS_USB_PORTS CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS
+#else
+#define OMAP_HS_USB_PORTS 3
+#endif
+
+struct omap_usbhs_board_data {
+ enum usbhs_omap_port_mode port_mode[OMAP_HS_USB_PORTS];
+};
+
+struct omap_usbtll {
+ u32 rev; /* 0x00 */
+ u32 hwinfo; /* 0x04 */
+ u8 pad1[0x8];
+ u32 sysc; /* 0x10 */
+ u32 syss; /* 0x14 */
+ u32 irqst; /* 0x18 */
+ u32 irqen; /* 0x1c */
+ u8 pad2[0x10];
+ u32 shared_conf; /* 0x30 */
+ u8 pad3[0xc];
+ u32 channel_conf; /* 0x40 */
+};
+
+struct omap_uhh {
+ u32 rev; /* 0x00 */
+ u32 hwinfo; /* 0x04 */
+ u8 pad1[0x8];
+ u32 sysc; /* 0x10 */
+ u32 syss; /* 0x14 */
+ u8 pad2[0x28];
+ u32 hostconfig; /* 0x40 */
+ u32 debugcsr; /* 0x44 */
+};
+
+struct omap_ehci {
+ u32 hccapbase; /* 0x00 */
+ u32 hcsparams; /* 0x04 */
+ u32 hccparams; /* 0x08 */
+ u8 pad1[0x04];
+ u32 usbcmd; /* 0x10 */
+ u32 usbsts; /* 0x14 */
+ u32 usbintr; /* 0x18 */
+ u32 frindex; /* 0x1c */
+ u32 ctrldssegment; /* 0x20 */
+ u32 periodiclistbase; /* 0x24 */
+ u32 asysnclistaddr; /* 0x28 */
+ u8 pad2[0x24];
+ u32 configflag; /* 0x50 */
+ u32 portsc_i; /* 0x54 */
+ u8 pad3[0x38];
+ u32 insreg00; /* 0x90 */
+ u32 insreg01; /* 0x94 */
+ u32 insreg02; /* 0x98 */
+ u32 insreg03; /* 0x9c */
+ u32 insreg04; /* 0xa0 */
+ u32 insreg05_utmi_ulpi; /* 0xa4 */
+ u32 insreg06; /* 0xa8 */
+ u32 insreg07; /* 0xac */
+ u32 insreg08; /* 0xb0 */
+};
+
+int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata);
+int omap_ehci_hcd_stop(void);
+
+#endif /* EHCI_H */
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 77e217f..f90db23 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -48,6 +48,7 @@ COBJS-$(CONFIG_USB_EHCI_IXP4XX) += ehci-ixp.o
COBJS-$(CONFIG_USB_EHCI_KIRKWOOD) += ehci-kirkwood.o
COBJS-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
COBJS-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
+COBJS-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
new file mode 100644
index 0000000..3682819
--- /dev/null
+++ b/drivers/usb/host/ehci-omap.c
@@ -0,0 +1,202 @@
+/*
+ * OMAP EHCI port support
+ * Based on LINUX KERNEL
+ * drivers/usb/host/ehci-omap.c and drivers/mfd/omap-usb-host.c
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com*
+ * Author: Govindraj R <govindraj.raja at ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/omap.h>
+#include <asm/ehci-omap.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+
+struct omap_uhh *const uhh = (struct omap_uhh *)OMAP_UHH_BASE;
+struct omap_usbtll *const usbtll = (struct omap_usbtll *)OMAP_TLL_BASE;
+struct omap_ehci *const ehci = (struct omap_ehci *)OMAP_EHCI_BASE;
+
+static int omap_uhh_reset(void)
+{
+ unsigned long init = get_timer(0);
+
+ /* perform UHH soft reset, and wait until reset is complete */
+ writel(OMAP_UHH_SYSCONFIG_SOFTRESET, &uhh->sysc);
+
+ /* Wait for UHH reset to complete */
+ while (!(readl(&uhh->syss) & OMAP_UHH_SYSSTATUS_EHCI_RESETDONE))
+ if (get_timer(init) > CONFIG_SYS_HZ) {
+ printf("OMAP UHH error: timeout resetting ehci\n");
+ return -EL3RST;
+ }
+
+ return 0;
+}
+
+static int omap_ehci_tll_reset(void)
+{
+ unsigned long init = get_timer(0);
+
+ /* perform TLL soft reset, and wait until reset is complete */
+ writel(OMAP_USBTLL_SYSCONFIG_SOFTRESET, &usbtll->sysc);
+
+ /* Wait for TLL reset to complete */
+ while (!(readl(&usbtll->syss) & OMAP_USBTLL_SYSSTATUS_RESETDONE))
+ if (get_timer(init) > CONFIG_SYS_HZ) {
+ printf("OMAP EHCI error: timeout resetting TLL\n");
+ return -EL3RST;
+ }
+
+ return 0;
+}
+
+static int omap_ehci_soft_phy_reset(int port)
+{
+ unsigned int reg = 0;
+ unsigned long init = get_timer(0);
+
+ reg = ULPI_FUNC_CTRL_RESET
+ /* FUNCTION_CTRL_SET register */
+ | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT)
+ /* Write */
+ | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT)
+ /* PORTn */
+ | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT)
+ /* start ULPI access*/
+ | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT);
+
+ writel(reg, &ehci->insreg05_utmi_ulpi);
+
+ /* Wait for ULPI access completion */
+ while ((readl(&ehci->insreg05_utmi_ulpi)
+ & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT)))
+ if (get_timer(init) > CONFIG_SYS_HZ) {
+ printf("OMAP EHCI error: timeout resetting phy\n");
+ return -EL3RST;
+ }
+
+ return 0;
+}
+
+static void omap_usbhs_hsic_init(void)
+{
+ unsigned int reg;
+ int i;
+
+ /* Enable channels now */
+ for (i = 0; i < OMAP_REV2_TLL_CHANNEL_COUNT; i++) {
+ reg = readl(&usbtll->channel_conf + OMAP_TLL_CHANNEL_CONF(i));
+
+ reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_TRANSPARENT_UTMI
+ | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF
+ | OMAP_TLL_CHANNEL_CONF_DRVVBUS
+ | OMAP_TLL_CHANNEL_CONF_CHRGVBUS
+ | OMAP_TLL_CHANNEL_CONF_CHANEN;
+
+ writel(reg, &usbtll->channel_conf + OMAP_TLL_CHANNEL_CONF(i));
+ }
+}
+
+int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata)
+{
+ unsigned int i, reg = 0;
+ int ret = 0;
+
+ ret = omap_uhh_reset();
+ if (ret)
+ return ret;
+
+ ret = omap_ehci_tll_reset();
+ if (ret)
+ return ret;
+
+ writel(OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
+ OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
+ OMAP_USBTLL_SYSCONFIG_AUTOIDLE,
+ &usbtll->sysc);
+
+ /* Put UHH in NoIdle/NoStandby mode */
+ reg = readl(&uhh->sysc);
+ reg &= ~OMAP_UHH_SYSCONFIG_IDLEMODE_CLEAR;
+ reg |= OMAP_UHH_SYSCONFIG_NOIDLE;
+ reg &= ~OMAP_UHH_SYSCONFIG_STDBYMODE_CLEAR;
+ reg |= OMAP_UHH_SYSCONFIG_NOSTDBY;
+ writel(reg, &uhh->sysc);
+
+ reg = readl(&uhh->hostconfig);
+
+ /* setup ULPI bypass and burst configurations */
+ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
+ | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN
+ | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN);
+ reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN;
+ reg |= OMAP_UHH_HOSTCONFIG_APP_START_CLK;
+
+ /* Clear port mode fields for PHY mode*/
+ reg &= ~OMAP_P1_MODE_CLEAR;
+ reg &= ~OMAP_P2_MODE_CLEAR;
+
+ if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
+ reg |= OMAP_P1_MODE_HSIC;
+
+ if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
+ reg |= OMAP_P2_MODE_HSIC;
+
+ writel(reg, &uhh->hostconfig);
+
+ if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]) ||
+ is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
+ omap_usbhs_hsic_init();
+
+ /*
+ * An undocumented "feature" in the OMAP3 EHCI controller,
+ * causes suspended ports to be taken out of suspend when
+ * the USBCMD.Run/Stop bit is cleared (for example when
+ * we do ehci_bus_suspend).
+ * This breaks suspend-resume if the root-hub is allowed
+ * to suspend. Writing 1 to this undocumented register bit
+ * disables this feature and restores normal behavior.
+ */
+ writel(EHCI_INSNREG04_DISABLE_UNSUSPEND, &ehci->insreg04);
+
+ for (i = 0; i < OMAP_HS_USB_PORTS; i++)
+ if (is_ehci_phy_mode(usbhs_pdata->port_mode[i])) {
+ ret = omap_ehci_soft_phy_reset(i);
+ if (ret)
+ return ret;
+ }
+
+ hccr = (struct ehci_hccr *)(OMAP_EHCI_BASE);
+ hcor = (struct ehci_hcor *)((uint32_t) hccr
+ + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+ return ret;
+}
+
+int omap_ehci_hcd_stop(void)
+{
+ if (omap_uhh_reset() < 0)
+ return -1;
+
+ if (omap_ehci_tll_reset() < 0)
+ return -1;
+
+ return 0;
+}
--
1.7.5.4
More information about the U-Boot
mailing list