From: "Govindraj.R" <govindraj.r...@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.r...@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.r...@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.r...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to