diff mbox

[U-Boot,2/3] omap4: add support for EHCI

Message ID 1304975091-21848-2-git-send-email-gilles.chanteperdrix@xenomai.org
State Changes Requested
Headers show

Commit Message

Gilles Chanteperdrix May 9, 2011, 9:04 p.m. UTC
As board may need some specific support, implement inner functions
to be called by the boards implementaions of ehci_hcd_start,
ehci_hcd_stop.

Signed-off-by: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
---
 arch/arm/include/asm/arch-omap4/ehci.h |    8 +
 drivers/usb/host/Makefile              |    1 +
 drivers/usb/host/ehci-omap4.c          |  268 ++++++++++++++++++++++++++++++++
 3 files changed, 277 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/include/asm/arch-omap4/ehci.h
 create mode 100644 drivers/usb/host/ehci-omap4.c

Comments

John Rigby May 18, 2011, 7:50 p.m. UTC | #1
On Mon, May 9, 2011 at 3:04 PM, Gilles Chanteperdrix
<gilles.chanteperdrix@xenomai.org> wrote:

> diff --git a/drivers/usb/host/ehci-omap4.c b/drivers/usb/host/ehci-omap4.c
> new file mode 100644
> index 0000000..19cd286
> --- /dev/null
> +++ b/drivers/usb/host/ehci-omap4.c
> @@ -0,0 +1,268 @@
> +/*
> + * OMAP4 EHCI port, copied from linux/drivers/usb/host/ehci-omap.c
So the file in linux is for both omap[34] yet here in u-boot it is
only for omap4.  I admittedly know very little about EHCI internals
but it seems to me that it would be nice if this could support both in
u-boot.

I see from git history that omap3 support went in some months ago with
only some new routines in beagle.c and no new usb files so could some
omap usb expert explain.

Thanks,
John
Gilles Chanteperdrix May 18, 2011, 7:58 p.m. UTC | #2
On 05/18/2011 09:50 PM, John Rigby wrote:
> On Mon, May 9, 2011 at 3:04 PM, Gilles Chanteperdrix
> <gilles.chanteperdrix@xenomai.org> wrote:
> 
>> diff --git a/drivers/usb/host/ehci-omap4.c b/drivers/usb/host/ehci-omap4.c
>> new file mode 100644
>> index 0000000..19cd286
>> --- /dev/null
>> +++ b/drivers/usb/host/ehci-omap4.c
>> @@ -0,0 +1,268 @@
>> +/*
>> + * OMAP4 EHCI port, copied from linux/drivers/usb/host/ehci-omap.c
> So the file in linux is for both omap[34] yet here in u-boot it is
> only for omap4.  I admittedly know very little about EHCI internals
> but it seems to me that it would be nice if this could support both in
> u-boot.
> 
> I see from git history that omap3 support went in some months ago with
> only some new routines in beagle.c and no new usb files so could some
> omap usb expert explain.

I am far from an expert. But I saw a previous post for EHCI on omap3
saying "this file is sufficiently specific to be specific for each
board". So, I started writing a panda specific board, but found that
there was not really much code specific to panda, and most of the code
was specific to omap4.

This said, there is more than one way to do it on omap4, the processor
can be configured different ways to get EHCI support (as far as I
understood the processor even has two different EHCI controllers). So
maybe a panda-only file was not a bad idea after all...
Wolfgang Denk May 18, 2011, 8:42 p.m. UTC | #3
Dear Gilles Chanteperdrix,

In message <1304975091-21848-2-git-send-email-gilles.chanteperdrix@xenomai.org> you wrote:
> As board may need some specific support, implement inner functions
> to be called by the boards implementaions of ehci_hcd_start,
> ehci_hcd_stop.
> 
> Signed-off-by: Gilles Chanteperdrix <gilles.chanteperdrix@xenomai.org>
...
> + * OMAP4 EHCI port, copied from linux/drivers/usb/host/ehci-omap.c

Can you please provide exact reference?  Please see
http://www.denx.de/wiki/view/U-Boot/Patches#Attributing_Code_Copyrights_Sign
bullet # 4

Thanks.

Best regards,

Wolfgang Denk
diff mbox

Patch

diff --git a/arch/arm/include/asm/arch-omap4/ehci.h b/arch/arm/include/asm/arch-omap4/ehci.h
new file mode 100644
index 0000000..fc84f6a
--- /dev/null
+++ b/arch/arm/include/asm/arch-omap4/ehci.h
@@ -0,0 +1,8 @@ 
+#ifndef EHCI_H
+#define EHCI_H
+
+int omap4_ehci_hcd_init(void);
+
+int omap4_ehci_hcd_stop(void);
+
+#endif /* EHCI_H */
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 51b2494..5a5b971 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -46,6 +46,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_OMAP4) += ehci-omap4.o
 
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
diff --git a/drivers/usb/host/ehci-omap4.c b/drivers/usb/host/ehci-omap4.c
new file mode 100644
index 0000000..19cd286
--- /dev/null
+++ b/drivers/usb/host/ehci-omap4.c
@@ -0,0 +1,268 @@ 
+/*
+ * OMAP4 EHCI port, copied from linux/drivers/usb/host/ehci-omap.c
+ *
+ * Copyright (C) 2007-2010 Texas Instruments, Inc.
+ *	Author: Vikram Pandita <vikram.pandita@ti.com>
+ *	Author: Anand Gadiyar <gadiyar@ti.com>
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/omap4.h>
+#include <asm/arch/sys_proto.h>
+
+#include "ehci.h"
+#include "ehci-core.h"
+
+#define EHCI_BASE (OMAP44XX_L4_CORE_BASE + 0x64C00)
+#define UHH_BASE (OMAP44XX_L4_CORE_BASE + 0x64000)
+#define TLL_BASE (OMAP44XX_L4_CORE_BASE + 0x62000)
+
+/* 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_REVISION				(0x00)
+#define	OMAP_USBTLL_SYSCONFIG				(0x10)
+#define	OMAP_USBTLL_SYSCONFIG_CACTIVITY			(1 << 8)
+#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				(0x14)
+#define	OMAP_USBTLL_SYSSTATUS_RESETDONE			(1 << 0)
+
+#define	OMAP_USBTLL_IRQSTATUS				(0x18)
+#define	OMAP_USBTLL_IRQENABLE				(0x1C)
+
+#define	OMAP_TLL_SHARED_CONF				(0x30)
+#define	OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN		(1 << 6)
+#define	OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN		(1 << 5)
+#define	OMAP_TLL_SHARED_CONF_USB_DIVRATION		(1 << 2)
+#define	OMAP_TLL_SHARED_CONF_FCLK_REQ			(1 << 1)
+#define	OMAP_TLL_SHARED_CONF_FCLK_IS_ON			(1 << 0)
+
+#define	OMAP_TLL_CHANNEL_CONF(num)			(0x040 + 0x004 * num)
+#define	OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF		(1 << 11)
+#define	OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE		(1 << 10)
+#define	OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE		(1 << 9)
+#define	OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE		(1 << 8)
+#define	OMAP_TLL_CHANNEL_CONF_CHANEN			(1 << 0)
+
+#define	OMAP_TLL_ULPI_FUNCTION_CTRL(num)		(0x804 + 0x100 * num)
+#define	OMAP_TLL_ULPI_INTERFACE_CTRL(num)		(0x807 + 0x100 * num)
+#define	OMAP_TLL_ULPI_OTG_CTRL(num)			(0x80A + 0x100 * num)
+#define	OMAP_TLL_ULPI_INT_EN_RISE(num)			(0x80D + 0x100 * num)
+#define	OMAP_TLL_ULPI_INT_EN_FALL(num)			(0x810 + 0x100 * num)
+#define	OMAP_TLL_ULPI_INT_STATUS(num)			(0x813 + 0x100 * num)
+#define	OMAP_TLL_ULPI_INT_LATCH(num)			(0x814 + 0x100 * num)
+#define	OMAP_TLL_ULPI_DEBUG(num)			(0x815 + 0x100 * num)
+#define	OMAP_TLL_ULPI_SCRATCH_REGISTER(num)		(0x816 + 0x100 * num)
+
+#define OMAP_TLL_CHANNEL_COUNT				3
+#define OMAP_TLL_CHANNEL_1_EN_MASK			(1 << 1)
+#define OMAP_TLL_CHANNEL_2_EN_MASK			(1 << 2)
+#define OMAP_TLL_CHANNEL_3_EN_MASK			(1 << 4)
+
+/* UHH Register Set */
+#define	OMAP_UHH_REVISION				(0x00)
+#define	OMAP_UHH_SYSCONFIG				(0x10)
+#define	OMAP_UHH_SYSCONFIG_MIDLEMODE			(1 << 12)
+#define	OMAP_UHH_SYSCONFIG_CACTIVITY			(1 << 8)
+#define	OMAP_UHH_SYSCONFIG_SIDLEMODE			(1 << 3)
+#define	OMAP_UHH_SYSCONFIG_ENAWAKEUP			(1 << 2)
+#define	OMAP_UHH_SYSCONFIG_SOFTRESET			(1 << 1)
+#define	OMAP_UHH_SYSCONFIG_AUTOIDLE			(1 << 0)
+
+#define	OMAP_UHH_SYSSTATUS				(0x14)
+#define	OMAP_UHH_HOSTCONFIG				(0x40)
+#define	OMAP_UHH_HOSTCONFIG_ULPI_BYPASS			(1 << 0)
+#define	OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS		(1 << 0)
+#define	OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS		(1 << 11)
+#define	OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS		(1 << 12)
+#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_P1_CONNECT_STATUS		(1 << 8)
+#define OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS		(1 << 9)
+#define OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS		(1 << 10)
+
+/* OMAP4-specific defines */
+#define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR		(3 << 2)
+#define OMAP4_UHH_SYSCONFIG_NOIDLE			(1 << 2)
+
+#define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR		(3 << 4)
+#define OMAP4_UHH_SYSCONFIG_NOSTDBY			(1 << 4)
+#define OMAP4_UHH_SYSCONFIG_SOFTRESET			(1 << 0)
+
+#define OMAP4_P1_MODE_CLEAR				(3 << 16)
+#define OMAP4_P1_MODE_TLL				(1 << 16)
+#define OMAP4_P1_MODE_HSIC				(3 << 16)
+#define OMAP4_P2_MODE_CLEAR				(3 << 18)
+#define OMAP4_P2_MODE_TLL				(1 << 18)
+#define OMAP4_P2_MODE_HSIC				(3 << 18)
+
+#define OMAP_REV2_TLL_CHANNEL_COUNT			2
+
+#define	OMAP_UHH_DEBUG_CSR				(0x44)
+
+/* EHCI Register Set */
+#define EHCI_INSNREG04					(0xA0)
+#define EHCI_INSNREG04_DISABLE_UNSUSPEND		(1 << 5)
+#define	EHCI_INSNREG05_ULPI				(0xA4)
+#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
+#define	EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT		8
+#define	EHCI_INSNREG05_ULPI_WRDATA_SHIFT		0
+
+int omap4_ehci_hcd_init(void)
+{
+	unsigned long base = get_timer(0);
+	unsigned reg = 0, port = 0;
+	int rc;
+
+	/* USB host, with clock from external phy as port 1 UTMI clock */
+	sr32((void *)0x4A009358, 0, 32, 0x01000002);
+
+	/* FSUSB clk */
+	sr32((void *)0x4a0093d0, 0, 32, 0x2);
+
+	/* USB TLL clock */
+	sr32((void *)0x4a009368, 0, 32, 0x1);
+
+	/* enable the 32K, 48M optional clocks and enable the module */
+	sr32((void *)0x4a0093e0, 0, 32, 0x301);
+
+	/* perform TLL soft reset, and wait until reset is complete */
+	writel(OMAP_USBTLL_SYSCONFIG_SOFTRESET,
+	       TLL_BASE + OMAP_USBTLL_SYSCONFIG);
+
+	/* Wait for TLL reset to complete */
+	while (!(readl(TLL_BASE + OMAP_USBTLL_SYSSTATUS)
+		 & OMAP_USBTLL_SYSSTATUS_RESETDONE))
+		if (get_timer(base) > CONFIG_SYS_HZ) {
+			printf("OMAP4 EHCI error: timeout resetting TLL\n");
+			return -1;
+		}
+
+	writel(OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
+	       OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
+	       OMAP_USBTLL_SYSCONFIG_CACTIVITY,
+	       TLL_BASE + OMAP_USBTLL_SYSCONFIG);
+
+	/* Put UHH in NoIdle/NoStandby mode */
+	reg = readl(UHH_BASE + OMAP_UHH_SYSCONFIG);
+	reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
+	reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
+	reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
+	reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
+	writel(reg, UHH_BASE + OMAP_UHH_SYSCONFIG);
+
+	reg = readl(UHH_BASE + OMAP_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;
+
+	/* Clear port mode fields for PHY mode*/
+	reg &= ~OMAP4_P1_MODE_CLEAR;
+	reg &= ~OMAP4_P2_MODE_CLEAR;
+	writel(reg, UHH_BASE + OMAP_UHH_HOSTCONFIG);
+
+	/*
+	 * 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_BASE + EHCI_INSNREG04);
+
+	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);
+
+	base = get_timer(0);
+
+	writel(reg, EHCI_BASE + EHCI_INSNREG05_ULPI);
+
+	/* Wait for ULPI access completion */
+	while ((readl(EHCI_BASE + EHCI_INSNREG05_ULPI)
+		& (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT)))
+		if (get_timer(base) > CONFIG_SYS_HZ) {
+			printf("OMAP4 EHCI error: timeout resetting phy\n");
+			return -1;
+		}
+
+	hccr = (struct ehci_hccr *)(EHCI_BASE);
+	hcor = (struct ehci_hcor *)((uint32_t) hccr
+			+ HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+	return 0;
+}
+
+int omap4_ehci_hcd_stop(void)
+{
+	unsigned base = get_timer(0);
+
+	writel(OMAP4_UHH_SYSCONFIG_SOFTRESET, UHH_BASE + OMAP_UHH_SYSCONFIG);
+
+#if 0
+	/* We get timeout here */
+	while (!(readl(UHH_BASE + OMAP_UHH_SYSSTATUS) & (1 << 0)))
+		if (get_timer(base) > CONFIG_SYS_HZ) {
+			printf("OMAP4 EHCI error: reset UHH 0 timeout\n");
+			return -ETIMEDOUT;
+		}
+
+	while (!(readl(UHH_BASE + OMAP_UHH_SYSSTATUS) & (1 << 1)))
+		if (get_timer(base) > CONFIG_SYS_HZ) {
+			printf("OMAP4 EHCI error: reset UHH 1 timeout\n");
+			return -ETIMEDOUT;
+		}
+
+	while (!(readl(UHH_BASE + OMAP_UHH_SYSSTATUS) & (1 << 2)))
+		if (get_timer(base) > CONFIG_SYS_HZ) {
+			printf("OMAP4 EHCI error: reset UHH 2 timeout\n");
+			return -ETIMEDOUT;
+		}
+#endif
+
+
+	writel((1 << 1), TLL_BASE + OMAP_USBTLL_SYSCONFIG);
+
+	while (!(readl(TLL_BASE + OMAP_USBTLL_SYSSTATUS) & (1 << 0)))
+		if (get_timer(base) > CONFIG_SYS_HZ) {
+			printf("OMAP4 EHCI error: reset TLL timeout\n");
+			return -ETIMEDOUT;
+		}
+
+	/* Disable clocks */
+	sr32((void *)0x4a0093e0, 0, 32, 0);
+	sr32((void *)0x4a009368, 0, 32, 0);
+	sr32((void *)0x4a0093d0, 0, 32, 0);
+	sr32((void *)0x4A009358, 0, 32, 0);
+
+	return 0;
+}