diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2012-11-12 15:28:39 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2012-11-12 15:28:39 +0100 |
commit | f987e832a9e79d2ce8009a5ea9c7b677624b3b30 (patch) | |
tree | 0dd09a5e6b4c60ee0a9916907dfc2cda83f3e496 /arch/arm/mach-tegra/tegra2_usb_phy.c | |
parent | f737b7f46a72c099cf8ac88baff02fbf61b1a47c (diff) | |
parent | fc993d9bc48f772133d8cd156c67c296477db070 (diff) |
Merge branch 'l4t/l4t-r16-r2' into colibri
Conflicts:
arch/arm/mach-tegra/tegra3_usb_phy.c
arch/arm/mach-tegra/usb_phy.c
drivers/usb/gadget/tegra_udc.c
drivers/usb/otg/Makefile
drivers/video/tegra/fb.c
sound/soc/tegra/tegra_pcm.c
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_usb_phy.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_usb_phy.c | 219 |
1 files changed, 171 insertions, 48 deletions
diff --git a/arch/arm/mach-tegra/tegra2_usb_phy.c b/arch/arm/mach-tegra/tegra2_usb_phy.c index 6e0801625614..121a84b2bcb0 100644 --- a/arch/arm/mach-tegra/tegra2_usb_phy.c +++ b/arch/arm/mach-tegra/tegra2_usb_phy.c @@ -47,11 +47,13 @@ #define USB_USBSTS_SRI (1 << 7) #define USB_USBSTS_HCH (1 << 12) +#define USB_USBINTR 0x148 + #define USB_ASYNCLISTADDR 0x158 #define USB_TXFILLTUNING 0x164 #define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16) -#define USB_FIFO_TXFILL_MASK 0x1f0000 +#define USB_FIFO_TXFILL_MASK 0x3f0000 #define ULPI_VIEWPORT 0x170 #define ULPI_WAKEUP (1 << 31) @@ -69,6 +71,7 @@ #define USB_PORTSC_PP (1 << 12) #define USB_PORTSC_LS(x) (((x) & 0x3) << 10) #define USB_PORTSC_SUSP (1 << 7) +#define USB_PORTSC_RESUME (1 << 6) #define USB_PORTSC_OCC (1 << 5) #define USB_PORTSC_PEC (1 << 3) #define USB_PORTSC_PE (1 << 2) @@ -277,6 +280,11 @@ #define DBG(stuff...) do {} while (0) #endif +/* define HSIC phy params */ +#define HSIC_SYNC_START_DELAY 9 +#define HSIC_IDLE_WAIT_DELAY 17 +#define HSIC_ELASTIC_UNDERRUN_LIMIT 16 +#define HSIC_ELASTIC_OVERRUN_LIMIT 16 static DEFINE_SPINLOCK(utmip_pad_lock); static int utmip_pad_count; @@ -605,13 +613,21 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy) val &= ~USB_PHY_CLK_VALID_INT_ENB | USB_PHY_CLK_VALID_INT_STS; writel(val , (base + USB_SUSP_CTRL)); - pr_info("%s: usb device plugged-in\n", __func__); + val = readl(base + USB_USBSTS); if (!(val & USB_USBSTS_PCI)) return IRQ_NONE; + val = readl(base + USB_PORTSC); - val &= ~(USB_PORTSC_WKCN | USB_PORTSC_RWC_BITS); + if (val & USB_PORTSC_CCS) + val &= ~USB_PORTSC_WKCN; + else + val &= ~USB_PORTSC_WKDS; + val &= ~USB_PORTSC_RWC_BITS; writel(val , (base + USB_PORTSC)); + + } else if (!phy->phy_clk_on) { + return IRQ_NONE; } } else if (!phy->phy_clk_on) { return IRQ_NONE; @@ -702,21 +718,27 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy) enable_hotplug = (val & USB_ID_STATUS) ? false : true; } if (enable_hotplug) { + /* Enable wakeup event of device plug-in/plug-out */ val = readl(base + USB_PORTSC); - val |= USB_PORTSC_WKCN; + if (val & USB_PORTSC_CCS) + val |= USB_PORTSC_WKDS; + else + val |= USB_PORTSC_WKCN; writel(val, base + USB_PORTSC); val = readl(base + USB_SUSP_CTRL); val |= USB_PHY_CLK_VALID_INT_ENB; writel(val, base + USB_SUSP_CTRL); } else { - /* Disable PHY clock valid interrupts while going into suspend*/ + /* Disable PHY clock valid interrupts + while going into suspend*/ val = readl(base + USB_SUSP_CTRL); val &= ~USB_PHY_CLK_VALID_INT_ENB; writel(val, base + USB_SUSP_CTRL); } } + /* Disable PHY clock */ if (phy->inst == 2) { val = readl(base + USB_PORTSC); val |= USB_PORTSC_PHCD; @@ -932,7 +954,8 @@ static int utmi_phy_resume(struct tegra_usb_phy *phy) if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RESET, 0, 2500) < 0) { - pr_err("%s: timeout waiting for reset\n", __func__); + pr_err("%s: timeout waiting for reset\n", + __func__); } val = readl(base + USB_USBMODE_REG_OFFSET); @@ -949,7 +972,8 @@ static int utmi_phy_resume(struct tegra_usb_phy *phy) if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS, USB_USBCMD_RS, 2500) < 0) { - pr_err("%s: timeout waiting for run bit\n", __func__); + pr_err("%s: timeout waiting for run bit\n", + __func__); } /* Enable Port Power */ @@ -959,7 +983,8 @@ static int utmi_phy_resume(struct tegra_usb_phy *phy) udelay(10); DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n", - readl(base + USB_USBSTS), readl(base + USB_PORTSC)); + readl(base + USB_USBSTS), + readl(base + USB_PORTSC)); } } else { /* Restoring the pad powers */ @@ -1051,7 +1076,6 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy) { unsigned long val; void __iomem *base = phy->regs; - struct tegra_hsic_config *config = &phy->pdata->u_cfg.hsic; DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); if (phy->phy_clk_on) { @@ -1077,13 +1101,13 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy) writel(val, base + USB_SUSP_CTRL); val = readl(base + UTMIP_XCVR_UHSIC_HSRX_CFG0); - val |= UHSIC_IDLE_WAIT(config->idle_wait_delay); - val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(config->elastic_underrun_limit); - val |= UHSIC_ELASTIC_OVERRUN_LIMIT(config->elastic_overrun_limit); + val |= UHSIC_IDLE_WAIT(HSIC_IDLE_WAIT_DELAY); + val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(HSIC_ELASTIC_UNDERRUN_LIMIT); + val |= UHSIC_ELASTIC_OVERRUN_LIMIT(HSIC_ELASTIC_OVERRUN_LIMIT); writel(val, base + UTMIP_XCVR_UHSIC_HSRX_CFG0); val = readl(base + UHSIC_HSRX_CFG1); - val |= UHSIC_HS_SYNC_START_DLY(config->sync_start_delay); + val |= UHSIC_HS_SYNC_START_DLY(HSIC_SYNC_START_DELAY); writel(val, base + UHSIC_HSRX_CFG1); val = readl(base + UHSIC_MISC_CFG0); @@ -1354,7 +1378,7 @@ static int ulpi_link_phy_open(struct tegra_usb_phy *phy) phy->ulpi_vp = otg_ulpi_create(&ulpi_viewport_access_ops, 0); phy->ulpi_vp->io_priv = phy->regs + ULPI_VIEWPORT; - + phy->linkphy_init = true; return err; } @@ -1450,49 +1474,74 @@ static int ulpi_link_phy_power_on(struct tegra_usb_phy *phy) } val = readl(base + USB_SUSP_CTRL); - val |= UHSIC_RESET; - writel(val, base + USB_SUSP_CTRL); - val = readl(base + ULPI_TIMING_CTRL_0); - val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP; - writel(val, base + ULPI_TIMING_CTRL_0); + /* Case for lp0 */ + if (!(val & UHSIC_RESET)) { + val |= UHSIC_RESET; + writel(val, base + USB_SUSP_CTRL); - val = readl(base + USB_SUSP_CTRL); - val |= ULPI_PHY_ENABLE; - writel(val, base + USB_SUSP_CTRL); + val = 0; + writel(val, base + ULPI_TIMING_CTRL_1); - val = readl(base + USB_SUSP_CTRL); - val |= USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); + ulpi_set_trimmer(phy); - if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, - USB_PHY_CLK_VALID, 2500)) - pr_err("%s: timeout waiting for phy to stabilize\n", __func__); + val = readl(base + ULPI_TIMING_CTRL_0); + val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP; + writel(val, base + ULPI_TIMING_CTRL_0); +#ifdef CONFIG_ARCH_TEGRA_2x_SOC + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, TEGRA_TRI_NORMAL); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, TEGRA_TRI_NORMAL); + tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, TEGRA_TRI_NORMAL); +#endif + val = readl(base + USB_SUSP_CTRL); + val |= ULPI_PHY_ENABLE; + writel(val, base + USB_SUSP_CTRL); - if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, USB_CLKEN, - USB_CLKEN, 2500)) - pr_err("%s: timeout waiting for AHB clock\n", __func__); + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, + USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500) < 0) + pr_err("%s: timeout waiting for phy" \ + "to stabilize\n", __func__); - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); + val = readl(base + USB_TXFILLTUNING); + if ((val & USB_FIFO_TXFILL_MASK) != + USB_FIFO_TXFILL_THRES(0x10)) { + val = USB_FIFO_TXFILL_THRES(0x10); + writel(val, base + USB_TXFILLTUNING); + } + } else { + /* Case for auto resume*/ + val = readl(base + USB_SUSP_CTRL); + val |= USB_SUSP_CLR; + writel(val, base + USB_SUSP_CTRL); - val = 0; - writel(val, base + ULPI_TIMING_CTRL_1); + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, + USB_PHY_CLK_VALID, USB_PHY_CLK_VALID, 2500) < 0) + pr_err("%s: timeout waiting for phy" \ + "to stabilize\n", __func__); - ulpi_set_trimmer(phy); + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, + USB_CLKEN, USB_CLKEN, 2500) < 0) + pr_err("%s: timeout waiting for AHB clock\n", __func__); - /* Fix VbusInvalid due to floating VBUS */ - ret = otg_io_write(phy->ulpi_vp, 0x40, 0x08); - if (ret) { - pr_err("%s: ulpi write failed\n", __func__); - return ret; + val = readl(base + USB_SUSP_CTRL); + val &= ~USB_SUSP_CLR; + writel(val, base + USB_SUSP_CTRL); } + if (phy->linkphy_init) { + /* To be done only incase of coldboot*/ + /* Fix VbusInvalid due to floating VBUS */ + ret = otg_io_write(phy->ulpi_vp, 0x40, 0x08); + if (ret) { + pr_err("%s: ulpi write failed\n", __func__); + return ret; + } - ret = otg_io_write(phy->ulpi_vp, 0x80, 0x0B); - if (ret) { - pr_err("%s: ulpi write failed\n", __func__); - return ret; + ret = otg_io_write(phy->ulpi_vp, 0x80, 0x0B); + if (ret) { + pr_err("%s: ulpi write failed\n", __func__); + return ret; + } + phy->linkphy_init = false; } val = readl(base + USB_PORTSC); @@ -1510,6 +1559,7 @@ static inline void ulpi_link_phy_set_tristate(bool enable) #ifdef CONFIG_ARCH_TEGRA_2x_SOC int tristate = (enable) ? TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL; + tegra_pinmux_set_tristate(TEGRA_PINGROUP_CDEV2, tristate); tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAA, tristate); tegra_pinmux_set_tristate(TEGRA_PINGROUP_UAB, tristate); tegra_pinmux_set_tristate(TEGRA_PINGROUP_UDA, tristate); @@ -1535,6 +1585,7 @@ static void ulpi_link_phy_restore_end(struct tegra_usb_phy *phy) { unsigned long val; void __iomem *base = phy->regs; + int ret; DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); @@ -1543,6 +1594,13 @@ static void ulpi_link_phy_restore_end(struct tegra_usb_phy *phy) writel(val, base + ULPI_TIMING_CTRL_0); ulpi_link_phy_set_tristate(false); + + udelay(10); + ret = otg_io_write(phy->ulpi_vp, 0x55, 0x04); + if (ret) { + pr_err("%s: ulpi write failed\n", __func__); + return; + } } static int ulpi_link_phy_resume(struct tegra_usb_phy *phy) @@ -1562,7 +1620,70 @@ static int ulpi_link_phy_resume(struct tegra_usb_phy *phy) return status; } -static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy, bool enable) +static int ulpi_link_phy_pre_resume(struct tegra_usb_phy *phy, + bool remote_wakeup) +{ + int status = 0; + unsigned long val; + void __iomem *base = phy->regs; + DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst); + + val = readl(base + USB_PORTSC); + if (val & USB_PORTSC_RESUME) { + + val = readl(base + USB_USBCMD); + val &= ~USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + + /* detect remote wakeup */ + msleep(20); + + val = readl(base + USB_PORTSC); + + /* Poll until the controller clears RESUME and SUSPEND */ + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, + USB_PORTSC_RESUME, 0, 2500)) + pr_err("%s: timeout waiting for RESUME\n", __func__); + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, + USB_PORTSC_SUSP, 0, 2500)) + pr_err("%s: timeout waiting for SUSPEND\n", __func__); + + /* Since we skip remote wakeup event, + put controller in suspend again and + resume port later */ + val = readl(base + USB_PORTSC); + val |= USB_PORTSC_SUSP; + writel(val, base + USB_PORTSC); + mdelay(4); + /* Wait until port suspend completes */ + if (usb_phy_reg_status_wait(base + USB_SUSP_CTRL, + USB_PORTSC_SUSP, USB_PORTSC_SUSP, 2500)) + pr_err("%s: timeout waiting for" \ + "PORT_SUSPEND\n", __func__); + + /* Disable interrupts */ + writel(0, base + USB_USBINTR); + /* Clear the run bit to stop SOFs - 2LS WAR */ + val = readl(base + USB_USBCMD); + val &= ~USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + if (usb_phy_reg_status_wait(base + USB_USBSTS, + USB_USBSTS_HCH, USB_USBSTS_HCH, 2000)) { + pr_err("%s: timeout waiting for" \ + "USB_USBSTS_HCH\n", __func__); + } + usb_phy_wait_for_sof(phy); + + val = readl(base + USB_USBCMD); + val |= USB_USBCMD_RS; + writel(val, base + USB_USBCMD); + } + return status; +} + + +static inline void ulpi_pinmux_bypass(struct tegra_usb_phy *phy, + bool enable) { unsigned long val; void __iomem *base = phy->regs; @@ -1795,7 +1916,8 @@ static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy) val = readl(base + ULPIS2S_CTRL); val |= ULPIS2S_ENA; val |= ULPIS2S_SUPPORT_DISCONNECT; - val |= ULPIS2S_SPARE((phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) ? 3 : 1); + val |= ULPIS2S_SPARE((phy->pdata->op_mode == TEGRA_USB_OPMODE_HOST) + ? 3 : 1); val |= ULPIS2S_PLLU_MASTER_BLASTER60; writel(val, base + ULPIS2S_CTRL); @@ -1906,6 +2028,7 @@ static struct tegra_usb_phy_ops ulpi_link_phy_ops = { .power_on = ulpi_link_phy_power_on, .power_off = ulpi_link_phy_power_off, .resume = ulpi_link_phy_resume, + .pre_resume = ulpi_link_phy_pre_resume, }; static struct tegra_usb_phy_ops ulpi_null_phy_ops = { |