diff options
author | Rakesh Bodla <rbodla@nvidia.com> | 2011-08-23 11:19:52 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:48:32 -0800 |
commit | 3acee8dd88ec37b2b5dc09e2a70470631a9f2ddd (patch) | |
tree | b956d9085c775af3459d22e7a4504bbb9a17c6eb | |
parent | c0f3ebafb74e967615e8167c285717b8f8168a7b (diff) |
usb: ehci: tegra: correct sequence for 2LS bit time
Corrected the sequence for 2LS bit time to all the
USB controller for proper suspend and resume.
Bug 860452
Original-Change-Id: Ia656893e1e9f54ea149a4039d2933867d95093f3
Reviewed-on: http://git-master/r/48472
Reviewed-by: Rakesh Bodla <rbodla@nvidia.com>
Tested-by: Rakesh Bodla <rbodla@nvidia.com>
Reviewed-by: Hanumanth Venkateswa Moganty <vmoganty@nvidia.com>
Rebase-Id: Ra58611e2110d90601a6b2a051657e3bb4427f76f
-rw-r--r-- | arch/arm/mach-tegra/usb_phy.c | 145 | ||||
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 45 |
2 files changed, 123 insertions, 67 deletions
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index 9393cc6822e7..93d330a91227 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -382,6 +382,7 @@ #define UTMIP_WAKE_VAL_P0(x) (((x) & 0xf) << 4) #define WAKE_VAL_NONE 0xc #define WAKE_VAL_FSJ 0x2 +#define WAKE_VAL_FSK 0x1 #define PMC_SLEEP_CFG 0x1fc #define UTMIP_TCTRL_USE_PMC(inst) (1 << ((8*(inst))+3)) @@ -420,6 +421,7 @@ #define UTMIP_CAP_CFG_P2 (1 << 6) #define UTMIP_CAP_CFG_P1 (1 << 5) #define UTMIP_CAP_CFG_P0 (1 << 4) +#define UTMIP_CLR_WAKE_ALARM(inst) (1 << ((inst)+12)) #define UTMIP_CLR_WAKE_ALARM_P2 (1 << 14) #define PMC_PAD_CFG (0x1f4) @@ -457,7 +459,10 @@ #define UTMIP_UHSIC_STATUS 0x214 #define UTMIP_WALK_PTR_P2(x) (((x) & 0x3) << 4) -#define WAKE_ALARM_P2 (1 << 18) +#define UTMIP_WAKE_ALARM(inst) (1 << ((inst) + 16)) +#define UTMIP_WAKE_ALARM_P2 (1 << 18) +#define UTMIP_WAKE_ALARM_P1 (1 << 17) +#define UTMIP_WAKE_ALARM_P0 (1 << 16) #endif /* Common registers */ @@ -989,7 +994,9 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) #else if(phy->instance == 2) { writel(0, base + ICUSB_CTRL); + } + if (phy->mode == TEGRA_USB_PHY_MODE_HOST) { val = readl(base + TEGRA_USB_USBMODE_REG_OFFSET); writel((val | TEGRA_USB_USBMODE_HOST), (base + TEGRA_USB_USBMODE_REG_OFFSET)); @@ -1009,6 +1016,12 @@ static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy) unsigned long val, pmc_pad_cfg_val; void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); unsigned int inst = phy->instance; + void __iomem *base = phy->regs; + bool port_connected; + + /* check for port connect status */ + val = readl(base + USB_PORTSC1); + port_connected = val & USB_PORTSC1_CCS; /*Set PMC MASTER bits to do the following * a. Take over the UTMI drivers @@ -1126,7 +1139,10 @@ static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy) /* Turn over pad configuration to PMC */ val = readl(pmc_base + PMC_SLEEP_CFG); val &= ~UTMIP_WAKE_VAL(inst, ~0); - val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_FSJ); + if (port_connected) + val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_FSK); + else + val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_FSJ); val |= UTMIP_MASTER_ENABLE(inst) | UTMIP_FSLS_USE_PMC(inst); writel(val, pmc_base + PMC_SLEEP_CFG); } @@ -1138,7 +1154,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) void __iomem *base = phy->regs; #ifndef CONFIG_ARCH_TEGRA_2x_SOC - if (phy->instance == 2) + if (phy->mode == TEGRA_USB_PHY_MODE_HOST) utmip_setup_pmc_wake_detect(phy); #endif if (phy->mode == TEGRA_USB_PHY_MODE_DEVICE) { @@ -1208,25 +1224,31 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) return 0; } -static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd) +static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy) { +#ifndef CONFIG_ARCH_TEGRA_2x_SOC unsigned long val; - void __iomem *base = phy->regs; void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); unsigned int inst = phy->instance; + /* Disable PMC master mode by clearing MASTER_EN */ + val = readl(pmc_base + PMC_SLEEP_CFG); + val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) | + UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst)); + writel(val, pmc_base + PMC_SLEEP_CFG); +#endif +} + +static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd) +{ #ifdef CONFIG_ARCH_TEGRA_2x_SOC + unsigned long val; + void __iomem *base = phy->regs; val = readl(base + UTMIP_TX_CFG0); val |= UTMIP_HS_DISCON_DISABLE; writel(val, base + UTMIP_TX_CFG0); #else - if (inst == 2) { - /* Disable PMC master mode by clearing MASTER_EN */ - val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~(UTMIP_RCTRL_USE_PMC(inst) | UTMIP_TCTRL_USE_PMC(inst) | - UTMIP_FSLS_USE_PMC(inst) | UTMIP_MASTER_ENABLE(inst)); - writel(val, pmc_base + PMC_SLEEP_CFG); - } + utmip_phy_disable_pmc_bus_ctrl(phy); #endif return 0; @@ -1238,27 +1260,25 @@ static int utmi_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd) void __iomem *base = phy->regs; #ifndef CONFIG_ARCH_TEGRA_2x_SOC - if (phy->instance == 2) { - /* Change the UTMIP OBS bus to drive SE0 */ - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); - val |= UTMIP_DPDM_OBSERVE_SEL_FS_SE0; - writel(val, base + UTMIP_MISC_CFG0); - - /* Wait for 3us(2 LS bit times) */ - udelay (3); - - /* Release UTMIP OBS bus */ - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE; - writel(val, base + UTMIP_MISC_CFG0); - - /* Release DP/DM pulldown for Host mode */ - val = readl(base + UTMIP_MISC_CFG0); - val &= ~(FORCE_PULLDN_DM | FORCE_PULLDN_DP | - COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS); - writel(val, base + UTMIP_MISC_CFG0); - } + /* Change the UTMIP OBS bus to drive SE0 */ + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); + val |= UTMIP_DPDM_OBSERVE_SEL_FS_SE0; + writel(val, base + UTMIP_MISC_CFG0); + + /* Wait for 3us(2 LS bit times) */ + udelay (3); + + /* Release UTMIP OBS bus */ + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_DPDM_OBSERVE; + writel(val, base + UTMIP_MISC_CFG0); + + /* Release DP/DM pulldown for Host mode */ + val = readl(base + UTMIP_MISC_CFG0); + val &= ~(FORCE_PULLDN_DM | FORCE_PULLDN_DP | + COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS); + writel(val, base + UTMIP_MISC_CFG0); #else val = readl(base + UTMIP_TX_CFG0); val &= ~UTMIP_HS_DISCON_DISABLE; @@ -1327,26 +1347,24 @@ static void utmi_phy_restore_start(struct tegra_usb_phy *phy, unsigned long val; void __iomem *base = phy->regs; - if (phy->instance == 2) { - /* Force DP/DM pulldown active for Host mode */ - val = readl(base + UTMIP_MISC_CFG0); - val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP | - COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS; - writel(val, base + UTMIP_MISC_CFG0); - val = readl(base + UTMIP_MISC_CFG0); - val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); - if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) - val |= UTMIP_DPDM_OBSERVE_SEL_FS_J; - else - val |= UTMIP_DPDM_OBSERVE_SEL_FS_K; - writel(val, base + UTMIP_MISC_CFG0); - udelay(1); + /* Force DP/DM pulldown active for Host mode */ + val = readl(base + UTMIP_MISC_CFG0); + val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP | + COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS; + writel(val, base + UTMIP_MISC_CFG0); + val = readl(base + UTMIP_MISC_CFG0); + val &= ~UTMIP_DPDM_OBSERVE_SEL(~0); + if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) + val |= UTMIP_DPDM_OBSERVE_SEL_FS_J; + else + val |= UTMIP_DPDM_OBSERVE_SEL_FS_K; + writel(val, base + UTMIP_MISC_CFG0); + udelay(1); - val = readl(base + UTMIP_MISC_CFG0); - val |= UTMIP_DPDM_OBSERVE; - writel(val, base + UTMIP_MISC_CFG0); - udelay(10); - } + val = readl(base + UTMIP_MISC_CFG0); + val |= UTMIP_DPDM_OBSERVE; + writel(val, base + UTMIP_MISC_CFG0); + udelay(10); #endif } @@ -2198,8 +2216,10 @@ void tegra_usb_phy_clk_enable(struct tegra_usb_phy *phy) void tegra_usb_phy_close(struct tegra_usb_phy *phy) { - if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) + if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) { utmip_pad_close(phy); + utmip_phy_disable_pmc_bus_ctrl(phy); + } else if (phy->usb_phy_type == TEGRA_USB_PHY_TYPE_LINK_ULPI && phy->clk) clk_put(phy->clk); if (phy->mode == TEGRA_USB_PHY_MODE_HOST) { @@ -2440,22 +2460,23 @@ int __init tegra_usb_phy_init(struct usb_phy_plat_data *pdata, int size) int tegra_usb_phy_clear_connect_intr(struct tegra_usb_phy *phy) { + u32 ret = -EIO; +#ifndef CONFIG_ARCH_TEGRA_2x_SOC void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); void __iomem *base = phy->regs; + unsigned int inst = phy->instance; u32 val; - u32 ret = -EIO; -#ifndef CONFIG_ARCH_TEGRA_2x_SOC val = readl(pmc_base + UTMIP_UHSIC_STATUS); - val &= WAKE_ALARM_P2; + val &= UTMIP_WAKE_ALARM(inst); if (val) { val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~UTMIP_WAKE_VAL_P2(0x0); - val |= UTMIP_WAKE_VAL_P2(0xc); + val &= ~UTMIP_WAKE_VAL(inst, 0x0); + val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE); writel(val, pmc_base + PMC_SLEEP_CFG); val = readl(pmc_base + PMC_TRIGGERS); - val |= UTMIP_CLR_WAKE_ALARM_P2 | UTMIP_CLR_WALK_PTR_P2; + val |= UTMIP_CLR_WAKE_ALARM(inst) | UTMIP_CLR_WALK_PTR(inst); writel(val, pmc_base + PMC_TRIGGERS); val = readl(base + UTMIP_PMC_WAKEUP0); @@ -2463,11 +2484,11 @@ int tegra_usb_phy_clear_connect_intr(struct tegra_usb_phy *phy) writel(val, base + UTMIP_PMC_WAKEUP0); val = readl(pmc_base + PMC_SLEEP_CFG); - val &= ~(UTMIP_MASTER_ENABLE_P2 |UTMIP_FSLS_USE_PMC_P2 | - UTMIP_RCTRL_USE_PMC_P2 |UTMIP_TCTRL_USE_PMC_P2); + val &= ~(UTMIP_MASTER_ENABLE(inst) |UTMIP_FSLS_USE_PMC(inst) | + UTMIP_RCTRL_USE_PMC(inst) |UTMIP_TCTRL_USE_PMC(inst)); writel(val, pmc_base + PMC_SLEEP_CFG); ret = 0; } - return ret; #endif + return ret; } diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 4b7f9719b673..a63a06f9793f 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -50,6 +50,9 @@ #define TEGRA_HSIC_CONNECTION_MAX_RETRIES 5 #define HOSTPC_REG_OFFSET 0x1b4 +#define HOSTPC1_DEVLC_STS (1 << 28) +#define HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29) + struct tegra_ehci_hcd { struct ehci_hcd *ehci; struct tegra_usb_phy *phy; @@ -164,8 +167,12 @@ static void irq_work(struct work_struct *irq_work) struct tegra_ehci_hcd *tegra = container_of(irq_work, struct tegra_ehci_hcd, irq_work); hcd = ehci_to_hcd(tegra->ehci); - if (!tegra->host_resumed) + if (!tegra->host_resumed) { +#ifdef CONFIG_USB_HOTPLUG + clk_enable(tegra->clk); +#endif tegra_ehci_power_up(hcd, false); + } } static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) @@ -219,7 +226,9 @@ static int tegra_ehci_hub_control( int ports = HCS_N_PORTS(ehci->hcs_params); u32 temp, status; u32 __iomem *status_reg; +#ifdef CONFIG_ARCH_TEGRA_2x_SOC u32 usbsts_reg; +#endif unsigned long flags; int retval = 0; unsigned selector; @@ -511,9 +520,19 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd) /* Force the phy to keep data lines in suspend state */ tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed); + if (tegra->ehci->has_hostpc) + ehci_reset(ehci); + /* Enable host mode */ tdi_reset(ehci); + if (tegra->ehci->has_hostpc) { + val = readl(hcd->regs + HOSTPC_REG_OFFSET); + val &= ~HOSTPC1_DEVLC_PTS(~0); + val |= HOSTPC1_DEVLC_STS; + writel(val, hcd->regs + HOSTPC_REG_OFFSET); + } + /* Enable Port Power */ val = readl(&hw->port_status[0]); val |= PORT_POWER; @@ -919,9 +938,9 @@ static int tegra_ehci_urb_enqueue ( struct tegra_ehci_hcd *pdata; int xfertype; int transfer_buffer_length; - pdata = dev_get_drvdata(hcd->self.controller); struct ehci_hcd *ehci = hcd_to_ehci(hcd); unsigned long flags; + pdata = dev_get_drvdata(hcd->self.controller); xfertype = usb_endpoint_type(&urb->ep->desc); transfer_buffer_length = urb->transfer_buffer_length; @@ -1157,9 +1176,16 @@ static int tegra_ehci_resume(struct platform_device *pdev) struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); - if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) + if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) { +#ifdef CONFIG_USB_HOTPLUG + clk_enable(tegra->clk); +#endif return 0; + } +#ifdef CONFIG_USB_HOTPLUG + clk_enable(tegra->clk); +#endif return tegra_usb_resume(hcd, true); } @@ -1167,14 +1193,23 @@ static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state) { struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); + int ret; - if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) + if ((tegra->bus_suspended) && (tegra->power_down_on_bus_suspend)) { +#ifdef CONFIG_USB_HOTPLUG + clk_disable(tegra->clk); +#endif return 0; + } if (time_before(jiffies, tegra->ehci->next_statechange)) msleep(10); - return tegra_usb_suspend(hcd, true); + ret = tegra_usb_suspend(hcd, true); +#ifdef CONFIG_USB_HOTPLUG + clk_disable(tegra->clk); +#endif + return ret; } #endif |