/* * Copyright (C) 2010 Michael Grzeschik * * This file is released under the GPLv2 * */ /* * OMAP USBHOST Register addresses: VIRTUAL ADDRESSES */ /*-------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include void omap_usb_utmi_init(struct omap_hcd *omap, u8 tll_channel_mask) { unsigned reg; int i; /* Program the 3 TLL channels upfront */ for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) { reg = __raw_readl(OMAP3_USBTLL_BASE + OMAP_TLL_CHANNEL_CONF(i)); /* Disable AutoIdle, BitStuffing and use SDR Mode */ reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); __raw_writel(reg, OMAP3_USBTLL_BASE + OMAP_TLL_CHANNEL_CONF(i)); } /* Program Common TLL register */ reg = __raw_readl(OMAP3_USBTLL_BASE + OMAP_TLL_SHARED_CONF); reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON | OMAP_TLL_SHARED_CONF_USB_DIVRATION | OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN); reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; __raw_writel(reg, OMAP3_USBTLL_BASE + OMAP_TLL_SHARED_CONF); /* Enable channels now */ for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) { reg = __raw_readl(OMAP3_USBTLL_BASE + OMAP_TLL_CHANNEL_CONF(i)); /* Enable only the reg that is needed */ if (!(tll_channel_mask & 1<phy_reset) { /* Refer: ISSUE1 */ if (omap->reset_gpio_port[0] != -EINVAL) { gpio_direction_output(omap->reset_gpio_port[0], 0); } if (omap->reset_gpio_port[1] != -EINVAL) { gpio_direction_output(omap->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ mdelay(10); } /* enable usbtll_fck */ v = __raw_readl(OMAP3_CM_REG(FCLKEN3_CORE)); v |= (1 << OMAP3430ES2_EN_USBTLL_SHIFT); __raw_writel(v, OMAP3_CM_REG(FCLKEN3_CORE)); /* Configure TLL for 60Mhz clk for ULPI */ /* enable usbtll_ick */ v = __raw_readl(OMAP3_CM_REG(ICLKEN3_CORE)); v |= (1 << OMAP3430ES2_EN_USBTLL_SHIFT); __raw_writel(v, OMAP3_CM_REG(ICLKEN3_CORE)); v = __raw_readl(OMAP3_CM_REG(AIDLE3_CORE)); v |= (0 << OMAP3430ES2_AUTO_USBTLL_SHIFT); __raw_writel(v, OMAP3_CM_REG(AIDLE3_CORE)); /* perform TLL soft reset, and wait until reset is complete */ __raw_writel(OMAP_USBTLL_SYSCONFIG_SOFTRESET, OMAP3_USBTLL_BASE + OMAP_USBTLL_SYSCONFIG); /* Wait for TLL reset to complete */ start = get_time_ns(); while (!(__raw_readl(OMAP3_USBTLL_BASE + OMAP_USBTLL_SYSSTATUS) & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { if (is_timeout(start, timeout * USECOND)) { return -ETIMEDOUT; } } /* (1<<3) = no idle mode only for initial debugging */ __raw_writel(OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | OMAP_USBTLL_SYSCONFIG_CACTIVITY, OMAP3_USBTLL_BASE + OMAP_USBTLL_SYSCONFIG); /* Put UHH in NoIdle/NoStandby mode */ v = __raw_readl(OMAP3_UHH_CONFIG_BASE + OMAP_UHH_SYSCONFIG); v |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP | OMAP_UHH_SYSCONFIG_SIDLEMODE | OMAP_UHH_SYSCONFIG_CACTIVITY | OMAP_UHH_SYSCONFIG_MIDLEMODE); v &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; __raw_writel(v, OMAP3_UHH_CONFIG_BASE + OMAP_UHH_SYSCONFIG); v = __raw_readl(OMAP3_UHH_CONFIG_BASE + OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ v |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); v &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) v &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) v &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) v &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; /* Bypass the TLL module for PHY mode operation */ if (get_cpu_rev() <= OMAP34XX_ES2_1) { if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) v &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else v |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) v &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) v |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) v &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) v |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY) v &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) v |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } __raw_writel(v, OMAP3_UHH_CONFIG_BASE + OMAP_UHH_HOSTCONFIG); if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) || (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) || (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) { if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK; /* Enable UTMI mode for required TLL channels */ omap_usb_utmi_init(omap, tll_ch_mask); } if (omap->phy_reset) { /* Refer ISSUE1: * Hold the PHY in RESET for enough time till * PHY is settled and ready */ udelay(10); if (omap->reset_gpio_port[0] != -EINVAL) gpio_direction_output(omap->reset_gpio_port[0], 1); if (omap->reset_gpio_port[1] != -EINVAL) gpio_direction_output(omap->reset_gpio_port[1], 1); } return 0; }