Arm: tegra: pmc: fix regression issues
Krishna Yarlagadda [Thu, 7 Feb 2013 14:45:52 +0000 (19:45 +0530)]
Fixed regression created by pmc separation by
adding recent pending changes

Bug 1232698

Change-Id: I5f6e9b87d7252941ea8ddbb115f4197318369a18
Signed-off-by: Krishna Yarlagadda <kyarlagadda@nvidia.com>
Reviewed-on: http://git-master/r/198423
Tested-by: Stephane Dion <sdion@nvidia.com>
Reviewed-by: Venu Byravarasu <vbyravarasu@nvidia.com>

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

index 9e1f936..50d5f39 100644 (file)
@@ -225,7 +225,6 @@ enum usb_pmc_port_speed {
        USB_PMC_PORT_SPEED_LOW,
        USB_PMC_PORT_SPEED_HIGH,
        USB_PMC_PORT_SPEED_UNKNOWN,
-       USB_PMC_PORT_SPEED_SUPER,
 };
 
 struct tegra_usb_pmc_data;
index 89fb5c1..1fa9efe 100644 (file)
@@ -171,33 +171,53 @@ static void utmip_setup_pmc_wake_detect(struct tegra_usb_pmc_data *pmc_data)
        val &= ~BIAS_MASTER_PROG_VAL;
        writel(val, pmc_base + PMC_UTMIP_BIAS_MASTER_CNTRL);
 
-       /* program walk sequence, maintain a J, followed by a driven K
-       * to signal a resume once an wake event is detected */
-       val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
-       val &= ~UTMIP_AP_A;
-       val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_AN_A |
-                               UTMIP_HIGHZ_A |
-               UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_AP_B |
-                               UTMIP_AN_B |
-               UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_AP_C |
-                               UTMIP_AN_C |
-               UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_AP_D |
-                               UTMIP_AN_D;
-       writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
-
-       if (pmc_data->port_speed == USB_PMC_PORT_SPEED_LOW) {
+       /* program walk sequence for remote or hotplug wakeup */
+       if (pmc_data->port_speed < USB_PMC_PORT_SPEED_UNKNOWN) {
+               /* program walk sequence, maintain a J, followed by a driven K
+               * to signal a resume once an wake event is detected */
                val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
-               val &= ~(UTMIP_AN_B | UTMIP_HIGHZ_B | UTMIP_AN_C |
-                       UTMIP_HIGHZ_C | UTMIP_AN_D | UTMIP_HIGHZ_D);
+               val &= ~UTMIP_AP_A;
+               val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_AN_A |
+                                       UTMIP_HIGHZ_A |
+                       UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_AP_B |
+                                       UTMIP_AN_B |
+                       UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_AP_C |
+                                       UTMIP_AN_C |
+                       UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_AP_D |
+                                       UTMIP_AN_D;
                writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+
+               if (pmc_data->port_speed == USB_PMC_PORT_SPEED_LOW) {
+                       val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+                       val &= ~(UTMIP_AN_B | UTMIP_HIGHZ_B | UTMIP_AN_C |
+                               UTMIP_HIGHZ_C | UTMIP_AN_D | UTMIP_HIGHZ_D);
+                       writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+               } else {
+                       val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
+                       val &= ~(UTMIP_AP_B | UTMIP_HIGHZ_B | UTMIP_AP_C |
+                               UTMIP_HIGHZ_C | UTMIP_AP_D | UTMIP_HIGHZ_D |
+                               UTMIP_AN_A);
+                               val |= UTMIP_AP_A;
+                       writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
+               }
        } else {
+               /* program walk sequence, pull down both dp and dn lines,
+               * tristate lines once an hotplug-in wake event is detected */
                val = readl(pmc_base + PMC_SLEEPWALK_REG(inst));
-               val &= ~(UTMIP_AP_B | UTMIP_HIGHZ_B | UTMIP_AP_C |
-                       UTMIP_HIGHZ_C | UTMIP_AP_D | UTMIP_HIGHZ_D |
-                       UTMIP_AN_A);
+               val |= UTMIP_USBOP_RPD_A | UTMIP_USBON_RPD_A | UTMIP_HIGHZ_A;
+               val &= ~UTMIP_AP_A;
+               val &= ~UTMIP_AN_A;
+               val |= UTMIP_USBOP_RPD_B | UTMIP_USBON_RPD_B | UTMIP_HIGHZ_B;
+               val &= ~UTMIP_AP_B;
+               val &= ~UTMIP_AN_B;
+               val |= UTMIP_USBOP_RPD_C | UTMIP_USBON_RPD_C | UTMIP_HIGHZ_C;
+               val &= ~UTMIP_AP_C;
+               val &= ~UTMIP_AN_C;
+               val |= UTMIP_USBOP_RPD_D | UTMIP_USBON_RPD_D | UTMIP_HIGHZ_D;
+               val &= ~UTMIP_AP_D;
+               val &= ~UTMIP_AN_D;
                writel(val, pmc_base + PMC_SLEEPWALK_REG(inst));
        }
-
        /* turn on pad detectors */
        val = readl(pmc_base + PMC_USB_AO);
        val &= ~(USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
@@ -401,6 +421,11 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_pmc_data *pmc_data)
        val |= UHSIC_PWR(inst);
        writel(val, pmc_base + PMC_UHSIC_MASTER_CONFIG(inst));
 
+       /* config debouncer */
+       val = readl(pmc_base + PMC_USB_DEBOUNCE);
+       val |= PMC_USB_DEBOUNCE_VAL(2);
+       writel(val, pmc_base + PMC_USB_DEBOUNCE);
+
        /* Make sure nothing is happening on the line with respect to PMC */
        val = readl(pmc_base + PMC_UHSIC_FAKE(inst));
        val &= ~UHSIC_FAKE_STROBE_VAL(inst);
index adc26c1..19f2c25 100644 (file)
@@ -851,34 +851,6 @@ exit:
        return irq_status;
 }
 
-static int utmi_phy_post_resume(struct tegra_usb_phy *phy)
-{
-       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 PMC is not disabled by now then disable it */
-       if (val & UTMIP_MASTER_ENABLE(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);
-
-               phy->pmc_remote_wakeup = false;
-               phy->pmc_hotplug_wakeup = false;
-               PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
-               }
-
-       return 0;
-}
-
 static int utmi_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
 {
        unsigned long val;
@@ -947,6 +919,16 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
                                                        , __func__);
                }
 
+               pmc_data[phy->inst].port_speed = (readl(base +
+                               HOSTPC1_DEVLC) >> 25) &
+                               HOSTPC1_DEVLC_PSPD_MASK;
+
+               if (pmc_data[phy->inst].port_speed <
+                                       USB_PMC_PORT_SPEED_UNKNOWN)
+                       phy->pmc_remote_wakeup = false;
+               else
+                       phy->pmc_hotplug_wakeup = false;
+
                pmc->pmc_ops->setup_pmc_wake_detect(pmc);
                val = readl(base + UTMIP_PMC_WAKEUP0);
                val |= EVENT_INT_ENB;
@@ -1157,18 +1139,9 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
        val |= HOSTPC1_DEVLC_STS;
        writel(val, base + HOSTPC1_DEVLC);
 
-       pmc_data[phy->inst].port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
-               HOSTPC1_DEVLC_PSPD_MASK;
-
        if (phy->pdata->op_mode == TEGRA_USB_OPMODE_DEVICE)
                pmc->pmc_ops->powerup_pmc_wake_detect(pmc);
 
-       phy->pmc_remote_wakeup = false;
-
-       val = readl(base + UTMIP_PMC_WAKEUP0);
-       val |= EVENT_INT_ENB;
-       writel(val, base + UTMIP_PMC_WAKEUP0);
-
        phy->phy_clk_on = true;
        phy->hw_accessible = true;
 
@@ -1189,27 +1162,11 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
        return 0;
 }
 
-static int uhsic_phy_post_resume(struct tegra_usb_phy *phy)
-{
-       unsigned long val;
-       void __iomem *base = phy->regs;
-
-       DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
-       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);
-       }
-       return 0;
-}
-
 static void utmi_phy_restore_start(struct tegra_usb_phy *phy)
 {
        unsigned long val;
        void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
        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 + UTMIP_STATUS);
@@ -1224,19 +1181,6 @@ static void utmi_phy_restore_start(struct tegra_usb_phy *phy)
           utmi_phy_irq(). */
        if (UTMIP_WALK_PTR_VAL(inst) & val) {
                phy->pmc_remote_wakeup = true;
-       } else if (!phy->pmc_remote_wakeup) {
-               val = readl(pmc_base + PMC_SLEEP_CFG);
-               if (val & UTMIP_MASTER_ENABLE(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);
-
-                       phy->pmc_remote_wakeup = false;
-                       phy->pmc_hotplug_wakeup = false;
-                       PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
-               }
        }
 }
 
@@ -1259,7 +1203,12 @@ 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);
-                               utmi_phy_post_resume(phy);
+                               val = readl(base + UTMIP_PMC_WAKEUP0);
+                               val &= ~EVENT_INT_ENB;
+                               writel(val, base + UTMIP_PMC_WAKEUP0);
+                               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
+                               phy->pmc_remote_wakeup = false;
+                               phy->pmc_hotplug_wakeup = false;
                                return;
                        }
                        wait_time_us--;
@@ -1483,6 +1432,23 @@ static void uhsic_phy_restore_start(struct tegra_usb_phy *phy)
                        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,
+                        * restart bringing up host controller as
+                        * in case of only pmc wakeup.
+                        */
+                       if (phy->pmc_remote_wakeup && phy->ctrlr_suspended) {
+                               usb_phy_bringup_host_controller(phy);
+                               if (usb_phy_reg_status_wait(base + USB_PORTSC,
+                                       (USB_PORTSC_RESUME | USB_PORTSC_SUSP),
+                                               0, FPR_WAIT_TIME_US) < 0)
+                                       pr_err("%s: timeout waiting" \
+                                       "for SUSPEND to clear\n",
+                                               __func__);
+                               phy->ctrlr_suspended = false;
+                       }
+
                        pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
                        phy->pmc_remote_wakeup = false;
                } else {
@@ -1519,9 +1485,25 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
                                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,
+                        * restart bringing up host controller as
+                        * in case of only pmc wakeup.
+                        */
+                       if (phy->pmc_remote_wakeup && phy->ctrlr_suspended) {
+                               usb_phy_bringup_host_controller(phy);
+                               if (usb_phy_reg_status_wait(base + USB_PORTSC,
+                                       (USB_PORTSC_RESUME | USB_PORTSC_SUSP),
+                                               0, FPR_WAIT_TIME_US) < 0)
+                                       pr_err("%s: timeout waiting" \
+                                               " for SUSPEND to clear\n",
+                                               __func__);
+                               phy->ctrlr_suspended = false;
+                       }
+
                                pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
                                phy->pmc_remote_wakeup = false;
-                               uhsic_phy_post_resume(phy);
                                return;
                        }
                        wait_time_us--;
@@ -1530,39 +1512,27 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
                 * context switch b/t disable PMC and set RUN bit ops */
                local_irq_save(flags);
                irq_disabled = true;
-#if 0
-               /* wait for 25 ms to port resume complete */
-               msleep(25);
-               /* disable PMC master control */
-               val = readl(base + UHSIC_PMC_WAKEUP0);
-               val &= ~EVENT_INT_ENB;
-               writel(val, base + UHSIC_PMC_WAKEUP0);
-
-               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
-               phy->pmc_remote_wakeup = false;
-               /* Clear PCI and SRI bits to avoid an interrupt upon resume */
-               val = readl(base + USB_USBSTS);
-               writel(val, base + USB_USBSTS);
-               /* wait to avoid SOF if there is any */
-               if (usb_phy_reg_status_wait(base + USB_USBSTS,
-                       USB_USBSTS_SRI, USB_USBSTS_SRI, 2500)) {
-                       pr_warn("%s: timeout waiting for SOF\n", __func__);
-               }
-               uhsic_phy_post_resume(phy);
-       } else {
-               val = readl(base + UHSIC_PMC_WAKEUP0);
-               val &= ~EVENT_INT_ENB;
-               writel(val, base + UHSIC_PMC_WAKEUP0);
-
-               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
-               phy->pmc_remote_wakeup = false;
-#endif
        }
        /* 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
+        * in usb_phy_bringup_host_cotroller, restart bringing up host
+        * controller as in case of only pmc wakeup.
+        */
+       if (phy->pmc_remote_wakeup && phy->ctrlr_suspended) {
+               usb_phy_bringup_host_controller(phy);
+               if (usb_phy_reg_status_wait(base + USB_PORTSC,
+                       (USB_PORTSC_RESUME | USB_PORTSC_SUSP), 0,
+                               FPR_WAIT_TIME_US) < 0)
+                       pr_err("%s: timeout waiting for SUSPEND to clear\n",
+                               __func__);
+               phy->ctrlr_suspended = false;
+       }
+
        pmc->pmc_ops->disable_pmc_bus_ctrl(pmc);
        phy->pmc_remote_wakeup = false;
 
@@ -1650,7 +1620,7 @@ static int uhsic_phy_open(struct tegra_usb_phy *phy)
        }
 
        pmc_init(phy);
-       pmc->pmc_ops->setup_pmc_wake_detect(pmc);
+       pmc->pmc_ops->powerup_pmc_wake_detect(pmc);
 
        return 0;
 }
@@ -1831,6 +1801,7 @@ static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
 {
        unsigned long val;
        void __iomem *base = phy->regs;
+       bool port_connected;
        struct tegra_usb_pmc_data *pmc = &pmc_data[phy->inst];
 
        DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
@@ -1843,7 +1814,11 @@ static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
        /* Disable interrupts */
        writel(0, base + USB_USBINTR);
 
-       if (phy->pmc_sleepwalk == false) {
+       /* check for port connect status */
+       val = readl(base + USB_PORTSC);
+       port_connected = val & USB_PORTSC_CCS;
+
+       if (phy->pmc_sleepwalk == false && port_connected) {
                pmc->pmc_ops->setup_pmc_wake_detect(pmc);
 
                phy->pmc_remote_wakeup = false;
@@ -1852,6 +1827,8 @@ static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
                val = readl(base + UHSIC_PMC_WAKEUP0);
                val |= EVENT_INT_ENB;
                writel(val, base + UHSIC_PMC_WAKEUP0);
+       } else {
+               phy->pmc_sleepwalk = true;
        }
 
        val = readl(base + HOSTPC1_DEVLC);