261 lines
7.7 KiB
C
261 lines
7.7 KiB
C
/*
|
|
* Copyright (C) 2010 Michael Grzeschik <mgr@pengutronix.de>
|
|
*
|
|
* This file is released under the GPLv2
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* OMAP USBHOST Register addresses: VIRTUAL ADDRESSES
|
|
*/
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
#include <mfd/twl4030.h>
|
|
#include <usb/twl4030.h>
|
|
#include <mach/ehci.h>
|
|
#include <common.h>
|
|
#include <asm/io.h>
|
|
#include <clock.h>
|
|
#include <gpio.h>
|
|
#include <mach/omap3-silicon.h>
|
|
#include <mach/omap3-clock.h>
|
|
#include <mach/cm-regbits-34xx.h>
|
|
#include <mach/sys_info.h>
|
|
|
|
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(OMAP_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, OMAP_USBTLL_BASE + OMAP_TLL_CHANNEL_CONF(i));
|
|
}
|
|
|
|
/* Program Common TLL register */
|
|
reg = __raw_readl(OMAP_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, OMAP_USBTLL_BASE + OMAP_TLL_SHARED_CONF);
|
|
|
|
/* Enable channels now */
|
|
for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
|
|
reg = __raw_readl(OMAP_USBTLL_BASE + OMAP_TLL_CHANNEL_CONF(i));
|
|
|
|
/* Enable only the reg that is needed */
|
|
if (!(tll_channel_mask & 1<<i))
|
|
continue;
|
|
|
|
reg |= OMAP_TLL_CHANNEL_CONF_CHANEN;
|
|
__raw_writel(reg, OMAP_USBTLL_BASE + OMAP_TLL_CHANNEL_CONF(i));
|
|
|
|
__raw_writeb(0xbe,
|
|
OMAP_USBTLL_BASE + OMAP_TLL_ULPI_SCRATCH_REGISTER(i));
|
|
}
|
|
}
|
|
|
|
int ehci_omap_init(struct omap_hcd *omap)
|
|
{
|
|
uint64_t start;
|
|
int timeout = 1000;
|
|
u8 tll_ch_mask = 0;
|
|
u32 v = 0;
|
|
|
|
if (twl4030_usb_ulpi_init()) {
|
|
printf("ERROR: %s Could not initialize PHY\n",
|
|
__PRETTY_FUNCTION__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
|
|
v = __raw_readl(CM_REG(CLKSEL4_PLL));
|
|
v |= (12 << OMAP3430ES2_PERIPH2_DPLL_DIV_SHIFT);
|
|
v |= (120 << OMAP3430ES2_PERIPH2_DPLL_MULT_SHIFT);
|
|
__raw_writel(v, CM_REG(CLKSEL4_PLL));
|
|
|
|
v = __raw_readl(CM_REG(CLKSEL5_PLL));
|
|
v |= (1 << OMAP3430ES2_DIV_120M_SHIFT);
|
|
__raw_writel(v, CM_REG(CLKSEL5_PLL));
|
|
|
|
v = __raw_readl(CM_REG(CLKEN2_PLL));
|
|
v |= (7 << OMAP3430ES2_PERIPH2_DPLL_FREQSEL_SHIFT);
|
|
v |= (7 << OMAP3430ES2_EN_PERIPH2_DPLL_SHIFT);
|
|
__raw_writel(v, CM_REG(CLKEN2_PLL));
|
|
|
|
/* PRCM settings for USBHOST:
|
|
* Interface clk un-related to domain transition
|
|
*/
|
|
|
|
v = __raw_readl(CM_REG(AIDLE_USBH));
|
|
v |= (0 << OMAP3430ES2_AUTO_USBHOST_SHIFT);
|
|
__raw_writel(v, CM_REG(AIDLE_USBH));
|
|
|
|
/* Disable sleep dependency with MPU and IVA */
|
|
|
|
v = __raw_readl(CM_REG(SLEEPD_USBH));
|
|
v |= (0 << OMAP3430ES2_EN_MPU_SHIFT);
|
|
v |= (0 << OMAP3430ES2_EN_IVA2_SHIFT);
|
|
__raw_writel(v, CM_REG(SLEEPD_USBH));
|
|
|
|
/* Disable Automatic transition of clock */
|
|
v = __raw_readl(CM_REG(CLKSTCTRL_USBH));
|
|
v |= (0 << OMAP3430ES2_CLKTRCTRL_USBHOST_SHIFT);
|
|
__raw_writel(v, CM_REG(CLKSTCTRL_USBH));
|
|
|
|
/* Enable Clocks for USBHOST */
|
|
|
|
/* enable usbhost_ick */
|
|
v = __raw_readl(CM_REG(ICLKEN_USBH));
|
|
v |= (1 << OMAP3430ES2_EN_USBHOST_SHIFT);
|
|
__raw_writel(v, CM_REG(ICLKEN_USBH));
|
|
|
|
/* enable usbhost_120m_fck */
|
|
v = __raw_readl(CM_REG(FCLKEN_USBH));
|
|
v |= (1 << OMAP3430ES2_EN_USBHOST2_SHIFT);
|
|
__raw_writel(v, CM_REG(FCLKEN_USBH));
|
|
|
|
/* enable usbhost_48m_fck */
|
|
v = __raw_readl(CM_REG(FCLKEN_USBH));
|
|
v |= (1 << OMAP3430ES2_EN_USBHOST1_SHIFT);
|
|
__raw_writel(v, CM_REG(FCLKEN_USBH));
|
|
|
|
if (omap->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(CM_REG(FCLKEN3_CORE));
|
|
v |= (1 << OMAP3430ES2_EN_USBTLL_SHIFT);
|
|
__raw_writel(v, CM_REG(FCLKEN3_CORE));
|
|
|
|
/* Configure TLL for 60Mhz clk for ULPI */
|
|
/* enable usbtll_ick */
|
|
v = __raw_readl(CM_REG(ICLKEN3_CORE));
|
|
v |= (1 << OMAP3430ES2_EN_USBTLL_SHIFT);
|
|
__raw_writel(v, CM_REG(ICLKEN3_CORE));
|
|
|
|
v = __raw_readl(CM_REG(AIDLE3_CORE));
|
|
v |= (0 << OMAP3430ES2_AUTO_USBTLL_SHIFT);
|
|
__raw_writel(v, CM_REG(AIDLE3_CORE));
|
|
|
|
/* perform TLL soft reset, and wait until reset is complete */
|
|
__raw_writel(OMAP_USBTLL_SYSCONFIG_SOFTRESET,
|
|
OMAP_USBTLL_BASE + OMAP_USBTLL_SYSCONFIG);
|
|
|
|
/* Wait for TLL reset to complete */
|
|
start = get_time_ns();
|
|
|
|
while (!(__raw_readl(OMAP_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, OMAP_USBTLL_BASE + OMAP_USBTLL_SYSCONFIG);
|
|
|
|
/* Put UHH in NoIdle/NoStandby mode */
|
|
v = __raw_readl(OMAP_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, OMAP_UHH_CONFIG_BASE + OMAP_UHH_SYSCONFIG);
|
|
|
|
v = __raw_readl(OMAP_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() <= CPU_ES2P1) {
|
|
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, OMAP_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;
|
|
}
|