Arm: tegra: usb: set run bit soon after disabling PMC
Petlozu Pravareshwar [Thu, 9 May 2013 08:51:35 +0000 (13:51 +0530)]
Set run bit soon after disabling the PMC sothat
the delay in revealing the pmc_lock is avoided.
Also add delay in phy_restore_end sothat the resume
will driven for minimum of 20ms.

Bug 1264731

Change-Id: Id9605d9414ef47c6ed49f45e04774af5a92941f8
Signed-off-by: Petlozu Pravareshwar <petlozup@nvidia.com>
Reviewed-on: http://git-master/r/225276
Reviewed-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>

arch/arm/mach-tegra/include/mach/tegra_usb_pmc.h
arch/arm/mach-tegra/tegra_usb_pmc.c
drivers/usb/host/xhci-tegra.c
drivers/usb/phy/tegra11x_usb_phy.c

index 44177a1..e6417fe 100644 (file)
 #define USB_PORTSC_LINE_DM_SET (1 << 0)
 #define USB_PORTSC_LINE_DP_SET (1 << 1)
 
+#define USB_USBCMD             0x130
+#define   USB_USBCMD_RS                (1 << 0)
+#define   USB_CMD_RESET        (1<<1)
+
 #define HOSTPC1_DEVLC          0x1b4
 #define HOSTPC1_DEVLC_PHCD             (1 << 22)
 #define HOSTPC1_DEVLC_PTS(x)           (((x) & 0x7) << 29)
@@ -240,7 +244,8 @@ struct tegra_usb_pmc_ops {
        void (*setup_pmc_wake_detect)(struct tegra_usb_pmc_data *pmc_data);
        void (*powerup_pmc_wake_detect)(struct tegra_usb_pmc_data *pmc_data);
        void (*powerdown_pmc_wake_detect)(struct tegra_usb_pmc_data *pmc_data);
-       void (*disable_pmc_bus_ctrl)(struct tegra_usb_pmc_data *pmc_data);
+       void (*disable_pmc_bus_ctrl)(struct tegra_usb_pmc_data *pmc_data,
+                 int enable_sof);
        void (*power_down_pmc)(struct tegra_usb_pmc_data *pmc_data);
 };
 
@@ -253,6 +258,7 @@ struct tegra_usb_pmc_data {
        enum tegra_usb_phy_interface phy_type;
        enum usb_pmc_port_speed port_speed;
        struct tegra_usb_pmc_ops *pmc_ops;
+       void __iomem *usb_base;
        u32 utmip_rctrl_val;
        u32 utmip_tctrl_val;
 };
index 1f738bd..eb210b8 100644 (file)
@@ -248,15 +248,25 @@ static void utmip_setup_pmc_wake_detect(struct tegra_usb_pmc_data *pmc_data)
        spin_unlock_irqrestore(&pmc_lock, flags);
 }
 
-static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_pmc_data *pmc_data)
+static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_pmc_data *pmc_data,
+                       int enable_sof)
 {
        unsigned long val;
+       void __iomem *usb_base;
        unsigned  int inst = pmc_data->instance;
+       usb_base = pmc_data->usb_base;
 
        DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, pmc_data->instance);
 
        spin_lock_irqsave(&pmc_lock, flags);
 
+       if (pmc_data->controller_type == TEGRA_USB_2_0 && usb_base) {
+               /* disable PMC master control */
+               val = readl(usb_base + UTMIP_PMC_WAKEUP0);
+               val &= ~EVENT_INT_ENB;
+               writel(val, usb_base + UTMIP_PMC_WAKEUP0);
+       }
+
        val = readl(pmc_base + PMC_SLEEP_CFG);
        val &= ~UTMIP_WAKE_VAL(inst, 0xF);
        val |= UTMIP_WAKE_VAL(inst, WAKE_VAL_NONE);
@@ -282,6 +292,12 @@ static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_pmc_data *pmc_data)
        val |= UTMIP_CLR_WAKE_ALARM(inst);
        writel(val, pmc_base + PMC_TRIGGERS);
 
+       if (pmc_data->controller_type == TEGRA_USB_2_0 && enable_sof == 1 &&
+               usb_base) {
+               val = readl(usb_base + USB_USBCMD);
+               val |= USB_USBCMD_RS;
+               writel(val, usb_base + USB_USBCMD);
+       }
        spin_unlock_irqrestore(&pmc_lock, flags);
 }
 
@@ -504,15 +520,25 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_pmc_data *pmc_data)
        DBG("%s:PMC enabled for HSIC remote wakeup\n", __func__);
 }
 
-static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_pmc_data *pmc_data)
+static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_pmc_data *pmc_data,
+                       int enable_sof)
 {
        unsigned long val;
+       void __iomem *usb_base;
        unsigned int inst = pmc_data->instance;
+       usb_base = pmc_data->usb_base;
 
        DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, pmc_data->instance);
 
        spin_lock_irqsave(&pmc_lock, flags);
 
+       if (pmc_data->controller_type == TEGRA_USB_2_0 && usb_base) {
+               /* disable PMC master control */
+               val = readl(usb_base + UTMIP_PMC_WAKEUP0);
+               val &= ~EVENT_INT_ENB;
+               writel(val, usb_base + UTMIP_PMC_WAKEUP0);
+       }
+
        val = readl(pmc_base + PMC_UHSIC_SLEEP_CFG(inst));
        val &= ~UHSIC_WAKE_VAL(inst, WAKE_VAL_ANY);
        val |= UHSIC_WAKE_VAL(inst, WAKE_VAL_NONE);
@@ -532,6 +558,13 @@ static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_pmc_data *pmc_data)
        val |= (UHSIC_CLR_WALK_PTR(inst) | UHSIC_CLR_WAKE_ALARM(inst));
        writel(val, pmc_base + PMC_UHSIC_TRIGGERS(inst));
 
+       if (pmc_data->controller_type == TEGRA_USB_2_0 && enable_sof == 1 &&
+               usb_base) {
+               val = readl(usb_base + USB_USBCMD);
+               val |= USB_USBCMD_RS;
+               writel(val, usb_base + USB_USBCMD);
+       }
+
        spin_unlock_irqrestore(&pmc_lock, flags);
 }
 
index 000b535..1c137b1 100644 (file)
@@ -1768,7 +1768,7 @@ tegra_xhci_host_partition_elpg_exit(struct tegra_xhci_hcd *tegra)
        }
 
        pmc_init();
-       pmc_data.pmc_ops->disable_pmc_bus_ctrl(&pmc_data);
+       pmc_data.pmc_ops->disable_pmc_bus_ctrl(&pmc_data, 0);
 
        tegra->hc_in_elpg = false;
        ret = xhci_resume(tegra->xhci, 0);
index 1abfcc2..ba684ac 100644 (file)
@@ -417,6 +417,7 @@ static void pmc_init(struct tegra_usb_phy *phy)
        pmc_data[phy->inst].instance = phy->inst;
        pmc_data[phy->inst].phy_type = phy->pdata->phy_intf;
        pmc_data[phy->inst].controller_type = TEGRA_USB_2_0;
+       pmc_data[phy->inst].usb_base = phy->regs;
        tegra_usb_pmc_init(&pmc_data[phy->inst]);
 }
 
@@ -797,11 +798,7 @@ static void utmi_phy_close(struct tegra_usb_phy *phy)
 
        val = readl(pmc_base + PMC_SLEEP_CFG);
        if (val & UTMIP_MASTER_ENABLE(phy->inst)) {
-               val = readl(base + UTMIP_PMC_WAKEUP0);
-               val &= ~EVENT_INT_ENB;
-               writel(val, base + UTMIP_PMC_WAKEUP0);
-
-               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 0);
 
                phy->pmc_remote_wakeup = false;
                phy->pmc_hotplug_wakeup = false;
@@ -876,18 +873,13 @@ static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
        unsigned long val;
        void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
        unsigned  int inst = phy->inst;
-       void __iomem *base = phy->regs;
        struct tegra_usb_pmc_data *pmc = &pmc_data[phy->inst];
 
        DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
        val = readl(pmc_base + PMC_SLEEP_CFG);
        if (val & UTMIP_MASTER_ENABLE(inst)) {
                if (!remote_wakeup) {
-                       val = readl(base + UTMIP_PMC_WAKEUP0);
-                       val &= ~EVENT_INT_ENB;
-                       writel(val, base + UTMIP_PMC_WAKEUP0);
-
-                       pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+                       pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 0);
 
                        phy->pmc_remote_wakeup = false;
                        phy->pmc_hotplug_wakeup = false;
@@ -1229,10 +1221,7 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
                                PHY_DBG("%s PMC FPR" \
                                "timeout val = 0x%x instance = %d\n", \
                                __func__, (u32)val, phy->inst);
-                               val = readl(base + UTMIP_PMC_WAKEUP0);
-                               val &= ~EVENT_INT_ENB;
-                               writel(val, base + UTMIP_PMC_WAKEUP0);
-                               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+                               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 0);
                                phy->pmc_remote_wakeup = false;
                                phy->pmc_hotplug_wakeup = false;
                                return;
@@ -1240,20 +1229,14 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
                        wait_time_us--;
                } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP));
 
+               /* Add delay sothat resume will be driven for more than 20 ms */
+               mdelay(10);
                local_irq_save(flags);
-               /* disable PMC master control */
-               val = readl(base + UTMIP_PMC_WAKEUP0);
-               val &= ~EVENT_INT_ENB;
-               writel(val, base + UTMIP_PMC_WAKEUP0);
-               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 1);
                phy->pmc_remote_wakeup = false;
                phy->pmc_hotplug_wakeup = false;
                PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, phy->inst);
 
-               val = readl(base + USB_USBCMD);
-               val |= USB_USBCMD_RS;
-               writel(val, base + USB_USBCMD);
-
                local_irq_restore(flags);
 
                if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
@@ -1271,10 +1254,7 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
                        pr_err("%s: timeout waiting for SOF\n", __func__);
                }
        } else {
-               val = readl(base + UTMIP_PMC_WAKEUP0);
-               val &= ~EVENT_INT_ENB;
-               writel(val, base + UTMIP_PMC_WAKEUP0);
-               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 0);
                phy->pmc_remote_wakeup = false;
                phy->pmc_hotplug_wakeup = false;
                PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, phy->inst);
@@ -1306,10 +1286,7 @@ static int utmi_phy_resume(struct tegra_usb_phy *phy)
                        usb_phy_bringup_host_controller(phy);
                        utmi_phy_restore_end(phy);
                } else {
-                       val = readl(base + UTMIP_PMC_WAKEUP0);
-                       val &= ~EVENT_INT_ENB;
-                       writel(val, base + UTMIP_PMC_WAKEUP0);
-                       pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+                       pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 0);
                        phy->pmc_remote_wakeup = false;
                        phy->pmc_hotplug_wakeup = false;
 
@@ -1621,9 +1598,6 @@ static void uhsic_phy_restore_start(struct tegra_usb_phy *phy)
                DBG("%s: uhsic remote wakeup detected\n", __func__);
        } else {
                if (!((UHSIC_STROBE_VAL(inst) | UHSIC_DATA_VAL(inst)) & val)) {
-                       val = readl(base + UHSIC_PMC_WAKEUP0);
-                       val &= ~EVENT_INT_ENB;
-                       writel(val, base + UHSIC_PMC_WAKEUP0);
 
                        /*
                         * If pmc wakeup is detected after putting controller
@@ -1642,7 +1616,7 @@ static void uhsic_phy_restore_start(struct tegra_usb_phy *phy)
                                phy->ctrlr_suspended = false;
                        }
 
-                       pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+                       pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 0);
                        phy->pmc_remote_wakeup = false;
                } else {
                        DBG("%s(%d): setting pretend connect\n", __func__, __LINE__);
@@ -1674,10 +1648,6 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
                        val = readl(base + USB_PORTSC);
                        udelay(1);
                        if (wait_time_us == 0) {
-                               val = readl(base + UHSIC_PMC_WAKEUP0);
-                               val &= ~EVENT_INT_ENB;
-                               writel(val, base + UHSIC_PMC_WAKEUP0);
-
                        /*
                         * If pmc wakeup is detected after putting controller
                         * in suspend in usb_phy_bringup_host_cotroller,
@@ -1695,7 +1665,7 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
                                phy->ctrlr_suspended = false;
                        }
 
-                               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+                               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 0);
                                phy->pmc_remote_wakeup = false;
                                return;
                        }
@@ -1706,10 +1676,6 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
                local_irq_save(flags);
                irq_disabled = true;
        }
-       /* disable PMC master control */
-       val = readl(base + UHSIC_PMC_WAKEUP0);
-       val &= ~EVENT_INT_ENB;
-       writel(val, base + UHSIC_PMC_WAKEUP0);
 
        /*
         * If pmc wakeup is detected after putting controller in suspend
@@ -1726,13 +1692,9 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
                phy->ctrlr_suspended = false;
        }
 
-       pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+       pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 1);
        phy->pmc_remote_wakeup = false;
 
-       /* Set RUN bit */
-       val = readl(base + USB_USBCMD);
-       val |= USB_USBCMD_RS;
-       writel(val, base + USB_USBCMD);
        /* Restore local irq if disabled before */
        if (irq_disabled)
                local_irq_restore(flags);