From a0e0319691daddef0dbcfa17264ed34356e55bf8 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Fri, 23 Jul 2010 17:02:26 -0700 Subject: [PATCH] [ARM] tegra: Setup USB PHY as recommended by NVIDIA This fixes enumeration issues with some devices Change-Id: I6283a6fb49a9e4505ad388cacdd88ecf1bdf1b9d Signed-off-by: Benoit Goby --- arch/arm/mach-tegra/include/mach/usb_phy.h | 8 ++- arch/arm/mach-tegra/usb_phy.c | 66 +++++++++++++++------- drivers/usb/gadget/fsl_tegra_udc.c | 4 +- drivers/usb/host/ehci-tegra.c | 4 +- 4 files changed, 56 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index 78179ef58fde..285c65cc511c 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -26,9 +26,15 @@ struct tegra_usb_phy { struct clk *pll_u; }; +enum tegra_usb_phy_mode { + TEGRA_USB_PHY_MODE_DEVICE, + TEGRA_USB_PHY_MODE_HOST, +}; + struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs); -int tegra_usb_phy_power_on(struct tegra_usb_phy *phy); +int tegra_usb_phy_power_on(struct tegra_usb_phy *phy, + enum tegra_usb_phy_mode phy_mode); int tegra_usb_phy_power_off(struct tegra_usb_phy *phy); diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 602f4afa1eef..fb829861f5d4 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -35,6 +35,7 @@ #define USB_WAKE_ON_CNNT_EN_DEV (1 << 3) #define USB_WAKE_ON_DISCON_EN_DEV (1 << 4) #define USB_SUSP_CLR (1 << 5) +#define USB_PHY_CLK_VALID (1 << 7) #define UTMIP_RESET (1 << 11) #define UTMIP_PHY_ENABLE (1 << 12) #define USB_SUSP_SET (1 << 14) @@ -54,6 +55,8 @@ #define UTMIP_XCVR_CFG0 0x808 #define UTMIP_XCVR_SETUP(x) (((x) & 0xf) << 0) +#define UTMIP_XCVR_LSRSLEW(x) (((x) & 0x3) << 8) +#define UTMIP_XCVR_LSFSLEW(x) (((x) & 0x3) << 10) #define UTMIP_FORCE_PD_POWERDOWN (1 << 14) #define UTMIP_FORCE_PD2_POWERDOWN (1 << 16) #define UTMIP_FORCE_PDZI_POWERDOWN (1 << 18) @@ -117,10 +120,27 @@ static const u16 udc_debounce_table[] = { 0xFDE8, /* 26 MHz */ }; +static int utmi_phy_wait_stable(struct tegra_usb_phy *phy) +{ + void __iomem *base = phy->regs; + unsigned long timeout = jiffies + HZ; + + while (time_before(jiffies, timeout)) { + if (readl(base + USB_SUSP_CTRL) & USB_PHY_CLK_VALID) + return 0; + udelay(10); + cpu_relax(); + } + if (readl(base + USB_SUSP_CTRL) & USB_PHY_CLK_VALID) + return 0; + else + return -ETIMEDOUT; +} + static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel) { unsigned long val; - void *base = phy->regs; + void __iomem *base = phy->regs; val = readl(base + USB_SUSP_CTRL); val |= UTMIP_RESET; @@ -132,10 +152,6 @@ static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel) writel(val, base + USB1_LEGACY_CTRL); } - val = readl(base + UTMIP_TX_CFG0); - val |= UTMIP_FS_PREABMLE_J; - writel(val, base + UTMIP_TX_CFG0); - val = readl(base + UTMIP_HSRX_CFG0); val &= ~(UTMIP_IDLE_WAIT(~0) | UTMIP_ELASTIC_LIMIT(~0)); val |= UTMIP_IDLE_WAIT(17) | UTMIP_ELASTIC_LIMIT(16); @@ -168,27 +184,31 @@ static void utmi_phy_init(struct tegra_usb_phy *phy, int freq_sel) writel(val, base + UTMIP_PLL_CFG1); } -void utmi_phy_power_on(struct tegra_usb_phy *phy) +void utmi_phy_power_on(struct tegra_usb_phy *phy, + enum tegra_usb_phy_mode phy_mode) { unsigned long val; - void *base = phy->regs; + void __iomem *base = phy->regs; - val = readl(base + USB_SUSP_CTRL); - val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); - writel(val, base + USB_SUSP_CTRL); + if (phy_mode == TEGRA_USB_PHY_MODE_DEVICE) { + val = readl(base + USB_SUSP_CTRL); + val &= ~(USB_WAKE_ON_CNNT_EN_DEV | USB_WAKE_ON_DISCON_EN_DEV); + writel(val, base + USB_SUSP_CTRL); + } val = readl(base + UTMIP_XCVR_CFG0); val &= ~(UTMIP_FORCE_PD_POWERDOWN | UTMIP_FORCE_PD2_POWERDOWN | - UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0) | - UTMIP_XCVR_HSSLEW_MSB(~0)); - val |= UTMIP_XCVR_SETUP(0xF); - /* TODO: slow rise/fall times in host mode */ + UTMIP_FORCE_PDZI_POWERDOWN | UTMIP_XCVR_SETUP(~0)); + if (phy_mode == TEGRA_USB_PHY_MODE_HOST) { + val &= ~(UTMIP_XCVR_LSFSLEW(~0) | UTMIP_XCVR_LSRSLEW(~0)); + val |= UTMIP_XCVR_LSFSLEW(2) | UTMIP_XCVR_LSRSLEW(2); + val |= UTMIP_XCVR_SETUP(0x9); + } else { + val &= ~(UTMIP_XCVR_HSSLEW_MSB(~0)); + val |= UTMIP_XCVR_SETUP(0xF); + } writel(val, base + UTMIP_XCVR_CFG0); - val = readl(base + UTMIP_SPARE_CFG0); - val &= ~FUSE_SETUP_SEL; - writel(val, base + UTMIP_SPARE_CFG0); - val = readl(base + UTMIP_BIAS_CFG0); val &= ~(UTMIP_OTGPD | UTMIP_BIASPD); writel(val, base + UTMIP_BIAS_CFG0); @@ -234,6 +254,9 @@ void utmi_phy_power_on(struct tegra_usb_phy *phy) writel(val, base + USB_SUSP_CTRL); } + if (utmi_phy_wait_stable(phy)) + pr_err("%s: timeout waiting for phy to stabilize\n", __func__); + if (phy->instance == 2) { val = readl(base + USB_PORTSC1); val &= ~USB_PORTSC1_PTS(~0); @@ -244,7 +267,7 @@ void utmi_phy_power_on(struct tegra_usb_phy *phy) void utmi_phy_power_off(struct tegra_usb_phy *phy) { unsigned long val; - void *base = phy->regs; + void __iomem *base = phy->regs; if (phy->instance == 0) { val = readl(base + USB_SUSP_CTRL); @@ -333,12 +356,13 @@ err0: return ERR_PTR(err); } -int tegra_usb_phy_power_on(struct tegra_usb_phy *phy) +int tegra_usb_phy_power_on(struct tegra_usb_phy *phy, + enum tegra_usb_phy_mode phy_mode) { /* TODO usb2 ulpi */ clk_enable(phy->pll_u); if (phy->instance != 1) - utmi_phy_power_on(phy); + utmi_phy_power_on(phy, phy_mode); return 0; } diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c index bdd80df09d85..fc666bbd6b8b 100644 --- a/drivers/usb/gadget/fsl_tegra_udc.c +++ b/drivers/usb/gadget/fsl_tegra_udc.c @@ -56,7 +56,7 @@ int fsl_udc_clk_init(struct platform_device *pdev) goto err1; } - tegra_usb_phy_power_on(phy); + tegra_usb_phy_power_on(phy, TEGRA_USB_PHY_MODE_DEVICE); return 0; err1: @@ -90,5 +90,5 @@ void fsl_udc_clk_suspend(void) void fsl_udc_clk_resume(void) { clk_enable(udc_clk); - tegra_usb_phy_power_on(phy); + tegra_usb_phy_power_on(phy, TEGRA_USB_PHY_MODE_DEVICE); } diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 40eff7f0d323..b93aefb6f3c3 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -50,7 +50,7 @@ static void tegra_ehci_power_up(struct usb_hcd *hcd) struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); clk_enable(tegra->clk); - tegra_usb_phy_power_on(tegra->phy); + tegra_usb_phy_power_on(tegra->phy, TEGRA_USB_PHY_MODE_HOST); tegra->host_resumed = 1; } @@ -419,7 +419,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail_phy; } - tegra_usb_phy_power_on(tegra->phy); + tegra_usb_phy_power_on(tegra->phy, TEGRA_USB_PHY_MODE_HOST); err = tegra_ehci_reset(hcd); if (err) { -- 2.34.1