[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