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