summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorVinod Atyam <vatyam@nvidia.com>2012-06-08 17:48:39 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-06-14 06:05:54 -0700
commite97981334b3c651799064f2bbc4bc5410f2a63a7 (patch)
tree0e71580aa1205fe5007feb285dcd74365782c993 /arch
parent57f3c5da56ca35b9741be9b8b5593bfec1bdf32a (diff)
ARM: tegra: usb_phy: PMC changes for HSIC remote wakeup
These are the changes for supporting HSIC remote wakeup and phy-off in auto-suspend. Bug 889618 Bug 951061 Change-Id: Ifd8144739c5dea49d8019b42b1a608dd13cc29be Signed-off-by: Vinod Atyam <vatyam@nvidia.com> Reviewed-on: http://git-master/r/107606 Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com> Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/tegra3_usb_phy.c532
1 files changed, 378 insertions, 154 deletions
diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c
index 7253a15af67a..e404382daca0 100644
--- a/arch/arm/mach-tegra/tegra3_usb_phy.c
+++ b/arch/arm/mach-tegra/tegra3_usb_phy.c
@@ -210,6 +210,8 @@
#define UTMIP_PMC_WAKEUP0 0x84c
#define EVENT_INT_ENB (1 << 0)
+#define UHSIC_PMC_WAKEUP0 0xc34
+
#define UTMIP_BIAS_STS0 0x840
#define UTMIP_RCTRL_VAL(x) (((x) & 0xffff) << 0)
#define UTMIP_TCTRL_VAL(x) (((x) & (0xffff << 16)) >> 16)
@@ -252,18 +254,24 @@
#define UHSIC_RPU_DATA (1 << 11)
#define UHSIC_RPU_STROBE (1 << 12)
-#define UHSIC_STAT_CFG0 0xc28
-#define UHSIC_CONNECT_DETECT (1 << 0)
+#define UHSIC_CMD_CFG0 0xc24
+#define UHSIC_PRETEND_CONNECT_DETECT (1 << 5)
+
+#define UHSIC_STAT_CFG0 0xc28
+#define UHSIC_CONNECT_DETECT (1 << 0)
#define PMC_USB_DEBOUNCE 0xec
-#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16)
+#define UTMIP_LINE_DEB_CNT(x) (((x) & 0xf) << 16)
+#define UHSIC_LINE_DEB_CNT(x) (((x) & 0xf) << 20)
#define PMC_USB_AO 0xf0
+
#define PMC_POWER_DOWN_MASK 0xffff
#define HSIC_RESERVED_P0 (3 << 14)
-#define HSIC_STOBE_VAL_PD_P0 (1 << 13)
-#define HSIC_DATA_VAL_PD_P0 (1 << 12)
-#define USB_ID_PD(inst) (1 << ((4*(inst))+3))
+#define STROBE_VAL_PD_P0 (1 << 12)
+#define DATA_VAL_PD_P0 (1 << 13)
+
+#define USB_ID_PD(inst) (1 << ((4*(inst))+3))
#define VBUS_WAKEUP_PD(inst) (1 << ((4*(inst))+2))
#define USBON_VAL_PD(inst) (1 << ((4*(inst))+1))
#define USBON_VAL_PD_P2 (1 << 9)
@@ -278,6 +286,8 @@
#define PMC_USB_AO_VBUS_WAKEUP_PD_P0 (1 << 2)
#define PMC_TRIGGERS 0x1ec
+
+#define UHSIC_CLR_WALK_PTR_P0 (1 << 3)
#define UTMIP_CLR_WALK_PTR(inst) (1 << (inst))
#define UTMIP_CLR_WALK_PTR_P2 (1 << 2)
#define UTMIP_CLR_WALK_PTR_P1 (1 << 1)
@@ -286,7 +296,8 @@
#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(inst) (1 << ((inst)+12))
+#define UHSIC_CLR_WAKE_ALARM_P0 (1 << 15)
#define UTMIP_CLR_WAKE_ALARM_P2 (1 << 14)
#define PMC_PAD_CFG (0x1f4)
@@ -295,17 +306,11 @@
#define PMC_TCTRL_VAL(x) (((x) & 0x1f) << 5)
#define PMC_RCTRL_VAL(x) (((x) & 0x1f) << 0)
-#define UHSIC_SLEEPWALK_REG 0x210
-#define UHSIC_DATA_RPD_D (1 << 25)
-#define UHSIC_STRB_RPD_D (1 << 24)
-#define UHSIC_DATA_RPD_C (1 << 17)
-#define UHSIC_STRB_RPD_C (1 << 16)
-#define UHSIC_DATA_RPD_B (1 << 9)
-#define UHSIC_STRB_RPD_B (1 << 8)
-#define UHSIC_DATA_RPD_A (1 << 1)
-#define UHSIC_STRB_RPD_A (1 << 0)
-
#define PMC_SLEEP_CFG 0x1fc
+
+#define UHSIC_MASTER_ENABLE (1 << 24)
+#define UHSIC_WAKE_VAL(x) (((x) & 0xf) << 28)
+#define WAKE_VAL_SD10 0x2
#define UTMIP_TCTRL_USE_PMC(inst) (1 << ((8*(inst))+3))
#define UTMIP_TCTRL_USE_PMC_P2 (1 << 19)
#define UTMIP_TCTRL_USE_PMC_P1 (1 << 11)
@@ -326,6 +331,9 @@
#define UHSIC_WAKE_VAL_P0(x) (((x) & 0xf) << 28)
#define PMC_SLEEPWALK_CFG 0x200
+
+#define UHSIC_WAKE_WALK_EN_P0 (1 << 30)
+#define UHSIC_LINEVAL_WALK_EN (1 << 31)
#define UTMIP_LINEVAL_WALK_EN(inst) (1 << ((8*(inst))+7))
#define UTMIP_LINEVAL_WALK_EN_P2 (1 << 23)
#define UTMIP_LINEVAL_WALK_EN_P1 (1 << 15)
@@ -362,30 +370,59 @@
#define UTMIP_AN_D (1 << 29)
#define UTMIP_HIGHZ_D (1 << 30)
+#define PMC_SLEEPWALK_UHSIC 0x210
+
+#define UHSIC_STROBE_RPD_A (1 << 0)
+#define UHSIC_DATA_RPD_A (1 << 1)
+#define UHSIC_STROBE_RPU_A (1 << 2)
+#define UHSIC_DATA_RPU_A (1 << 3)
+#define UHSIC_STROBE_RPD_B (1 << 8)
+#define UHSIC_DATA_RPD_B (1 << 9)
+#define UHSIC_STROBE_RPU_B (1 << 10)
+#define UHSIC_DATA_RPU_B (1 << 11)
+#define UHSIC_STROBE_RPD_C (1 << 16)
+#define UHSIC_DATA_RPD_C (1 << 17)
+#define UHSIC_STROBE_RPU_C (1 << 18)
+#define UHSIC_DATA_RPU_C (1 << 19)
+#define UHSIC_STROBE_RPD_D (1 << 24)
+#define UHSIC_DATA_RPD_D (1 << 25)
+#define UHSIC_STROBE_RPU_D (1 << 26)
+#define UHSIC_DATA_RPU_D (1 << 27)
+
#define UTMIP_UHSIC_STATUS 0x214
-#define UTMIP_WALK_PTR_VAL(inst) (0x3 << ((inst)*2))
-#define UTMIP_USBOP_VAL(inst) (1 << ((2*(inst)) + 8))
-#define UTMIP_USBOP_VAL_P2 (1 << 12)
-#define UTMIP_USBOP_VAL_P1 (1 << 10)
-#define UTMIP_USBOP_VAL_P0 (1 << 8)
-#define UTMIP_USBON_VAL(inst) (1 << ((2*(inst)) + 9))
-#define UTMIP_USBON_VAL_P2 (1 << 13)
-#define UTMIP_USBON_VAL_P1 (1 << 11)
-#define UTMIP_USBON_VAL_P0 (1 << 9)
-#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)
-#define UTMIP_WALK_PTR(inst) (1 << ((inst)*2))
-#define UTMIP_WALK_PTR_P2 (1 << 4)
-#define UTMIP_WALK_PTR_P1 (1 << 2)
-#define UTMIP_WALK_PTR_P0 (1 << 0)
-
-#define USB1_PREFETCH_ID 6
-#define USB2_PREFETCH_ID 18
-#define USB3_PREFETCH_ID 17
+
+#define UTMIP_USBOP_VAL(inst) (1 << ((2*(inst)) + 8))
+#define UTMIP_USBOP_VAL_P2 (1 << 12)
+#define UTMIP_USBOP_VAL_P1 (1 << 10)
+#define UTMIP_USBOP_VAL_P0 (1 << 8)
+#define UTMIP_USBON_VAL(inst) (1 << ((2*(inst)) + 9))
+#define UTMIP_USBON_VAL_P2 (1 << 13)
+#define UTMIP_USBON_VAL_P1 (1 << 11)
+#define UTMIP_USBON_VAL_P0 (1 << 9)
+#define UHSIC_WAKE_ALARM (1 << 19)
+#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)
+#define UHSIC_DATA_VAL_P0 (1 << 15)
+#define UHSIC_STROBE_VAL_P0 (1 << 14)
+#define UTMIP_WALK_PTR_VAL(inst) (0x3 << ((inst)*2))
+#define UHSIC_WALK_PTR_VAL (0x3 << 6)
+#define UTMIP_WALK_PTR(inst) (1 << ((inst)*2))
+#define UTMIP_WALK_PTR_P2 (1 << 4)
+#define UTMIP_WALK_PTR_P1 (1 << 2)
+#define UTMIP_WALK_PTR_P0 (1 << 0)
+
+#define USB1_PREFETCH_ID 6
+#define USB2_PREFETCH_ID 18
+#define USB3_PREFETCH_ID 17
#define PMC_UTMIP_UHSIC_FAKE 0x218
+
+#define UHSIC_STROBE_VAL (1 << 12)
+#define UHSIC_DATA_VAL (1 << 13)
+#define UHSIC_STROBE_ENB (1 << 14)
+#define UHSIC_DATA_ENB (1 << 15)
#define USBON_VAL(inst) (1 << ((4*(inst))+1))
#define USBON_VAL_P2 (1 << 9)
#define USBON_VAL_P1 (1 << 5)
@@ -398,8 +435,10 @@
#define PMC_UTMIP_BIAS_MASTER_CNTRL 0x30c
#define BIAS_MASTER_PROG_VAL (1 << 1)
-#define PMC_UTMIP_MASTER_CONFIG 0x310
-#define UTMIP_PWR(inst) (1 << (inst))
+#define PMC_UTMIP_MASTER_CONFIG 0x310
+
+#define UTMIP_PWR(inst) (1 << (inst))
+#define UHSIC_PWR (1 << 3)
#define FUSE_USB_CALIB_0 0x1F0
#define XCVR_SETUP(x) (((x) & 0x7F) << 0)
@@ -851,45 +890,6 @@ static void utmip_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
}
-static void uhsic_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy)
-{
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
- /* turn on pad detectors for HSIC*/
- val = readl(pmc_base + PMC_USB_AO);
- val |= (HSIC_RESERVED_P0 | HSIC_STOBE_VAL_PD_P0 | HSIC_DATA_VAL_PD_P0);
- writel(val, pmc_base + PMC_USB_AO);
-
- /* enable pull downs on HSIC PMC */
- val = UHSIC_STRB_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STRB_RPD_B |
- UHSIC_DATA_RPD_B | UHSIC_STRB_RPD_C | UHSIC_DATA_RPD_C |
- UHSIC_STRB_RPD_D | UHSIC_DATA_RPD_D;
- writel(val, pmc_base + UHSIC_SLEEPWALK_REG);
-
- /* Turn over pad configuration to PMC */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UHSIC_WAKE_VAL_P0(~0);
- val |= UHSIC_WAKE_VAL_P0(WAKE_VAL_NONE) | UHSIC_MASTER_ENABLE_P0;
- writel(val, pmc_base + PMC_SLEEP_CFG);
-}
-
-static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
-{
- unsigned long val;
- void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
-
- /* turn on pad detectors for HSIC*/
- val = readl(pmc_base + PMC_USB_AO);
- val &= ~(HSIC_RESERVED_P0 | HSIC_STOBE_VAL_PD_P0 | HSIC_DATA_VAL_PD_P0);
- writel(val, pmc_base + PMC_USB_AO);
-
- /* Disable PMC master mode by clearing MASTER_EN */
- val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~(UHSIC_MASTER_ENABLE_P0);
- writel(val, pmc_base + PMC_SLEEP_CFG);
- mdelay(1);
-}
#ifdef KERNEL_WARNING
static void usb_phy_power_down_pmc(void)
@@ -915,10 +915,10 @@ static void usb_phy_power_down_pmc(void)
writel(val, pmc_base + PMC_SLEEPWALK_REG(2));
/* enable pull downs on HSIC PMC */
- val = UHSIC_STRB_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STRB_RPD_B |
- UHSIC_DATA_RPD_B | UHSIC_STRB_RPD_C | UHSIC_DATA_RPD_C |
- UHSIC_STRB_RPD_D | UHSIC_DATA_RPD_D;
- writel(val, pmc_base + UHSIC_SLEEPWALK_REG);
+ val = UHSIC_STROBE_RPD_A | UHSIC_DATA_RPD_A | UHSIC_STROBE_RPD_B |
+ UHSIC_DATA_RPD_B | UHSIC_STROBE_RPD_C | UHSIC_DATA_RPD_C |
+ UHSIC_STROBE_RPD_D | UHSIC_DATA_RPD_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
/* Turn over pad configuration to PMC */
val = readl(pmc_base + PMC_SLEEP_CFG);
@@ -962,10 +962,13 @@ static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy)
val &= ~USB_USBMODE_MASK;
val |= USB_USBMODE_HOST;
writel(val, base + USB_USBMODE);
-
val = readl(base + HOSTPC1_DEVLC);
val &= ~HOSTPC1_DEVLC_PTS(~0);
- val |= HOSTPC1_DEVLC_STS;
+
+ if (phy->pdata->phy_intf == TEGRA_USB_PHY_INTF_HSIC)
+ val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
+ else
+ val |= HOSTPC1_DEVLC_STS;
writel(val, base + HOSTPC1_DEVLC);
/* Enable Port Power */
@@ -1763,6 +1766,278 @@ bool utmi_phy_charger_detect(struct tegra_usb_phy *phy)
return status;
}
+static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+ /* turn on pad detectors for HSIC*/
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(HSIC_RESERVED_P0 | STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UHSIC_MASTER_ENABLE_P0);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+ mdelay(1);
+}
+
+static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ bool port_connected;
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* check for port connect status */
+ val = readl(base + USB_PORTSC);
+ port_connected = val & USB_PORTSC_CCS;
+
+ if (!port_connected)
+ return;
+
+ /*Set PMC MASTER bits to do the following
+ * a. Take over the hsic drivers
+ * b. set up such that it will take over resume
+ * if remote wakeup is detected
+ * Prepare PMC to take over suspend-wake detect-drive resume until USB
+ * controller ready
+ */
+
+ /* disable master enable in PMC */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_MASTER_ENABLE_P0;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* UTMIP_PWR_PX=1 for power savings mode */
+ val = readl(pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ val |= UHSIC_PWR;
+ writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+
+
+ /* Enable which type of event can trigger a walk,
+ * in this case usb_line_wake */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val |= UHSIC_LINEVAL_WALK_EN;
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* 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_UHSIC);
+
+ val &= ~UHSIC_DATA_RPU_A;
+ val |= UHSIC_DATA_RPD_A;
+ val &= ~UHSIC_STROBE_RPD_A;
+ val |= UHSIC_STROBE_RPU_A;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ val &= ~UHSIC_DATA_RPD_B;
+ val |= UHSIC_DATA_RPU_B;
+ val &= ~UHSIC_STROBE_RPU_B;
+ val |= UHSIC_STROBE_RPD_B;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ val &= ~UHSIC_DATA_RPD_C;
+ val |= UHSIC_DATA_RPU_C;
+ val &= ~UHSIC_STROBE_RPU_C;
+ val |= UHSIC_STROBE_RPD_C;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ val &= ~UHSIC_DATA_RPD_D;
+ val |= UHSIC_DATA_RPU_D;
+ val &= ~UHSIC_STROBE_RPU_D;
+ val |= UHSIC_STROBE_RPD_D;
+ writel(val, pmc_base + PMC_SLEEPWALK_UHSIC);
+
+ /* turn on pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val &= ~(STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+ /* Add small delay before usb detectors provide stable line values */
+ udelay(1);
+
+ phy->remote_wakeup = false;
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(~0);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_SD10);
+ val |= UHSIC_MASTER_ENABLE;
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val |= EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+
+ DBG("%s:PMC enabled for HSIC remote wakeup\n", __func__);
+}
+
+static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+
+ DBG("%s (%d)\n", __func__, __LINE__);
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(0x0);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0;
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+
+ /* Disable PMC master mode by clearing MASTER_EN */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~(UHSIC_MASTER_ENABLE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* turn off pad detectors */
+ val = readl(pmc_base + PMC_USB_AO);
+ val |= (STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
+ writel(val, pmc_base + PMC_USB_AO);
+
+ phy->remote_wakeup = false;
+}
+
+static bool uhsic_phy_remotewake_detected(struct tegra_usb_phy *phy)
+{
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+ u32 val;
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ if (val & EVENT_INT_ENB) {
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+ if (UHSIC_WAKE_ALARM & val) {
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(0x0);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0;
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ val = readl(base + UHSIC_PMC_WAKEUP0);
+ val &= ~EVENT_INT_ENB;
+ writel(val, base + UHSIC_PMC_WAKEUP0);
+ phy->remote_wakeup = true;
+ DBG("%s:PMC remote wakeup detected for HSIC\n", __func__);
+ return true;
+ }
+ }
+ return false;
+}
+
+static int uhsic_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+ DBG("%s(%d)\n", __func__, __LINE__);
+
+ if (!remote_wakeup)
+ usb_phy_wait_for_sof(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 uhsic_phy_restore_start(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ void __iomem *base = phy->regs;
+
+ val = readl(pmc_base + UTMIP_UHSIC_STATUS);
+
+ /* check whether we wake up from the remote resume */
+ if (UHSIC_WALK_PTR_VAL & val) {
+ phy->remote_wakeup = true;
+ } else {
+ if (!((UHSIC_STROBE_VAL_P0 | UHSIC_DATA_VAL_P0) & val)) {
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+ } else {
+ DBG("%s(%d): setting pretend connect\n", __func__, __LINE__);
+ val = readl(base + UHSIC_CMD_CFG0);
+ val |= UHSIC_PRETEND_CONNECT_DETECT;
+ writel(val, base + UHSIC_CMD_CFG0);
+ }
+ }
+}
+
+static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
+{
+
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ int wait_time_us = 3000; /* FPR should be set by this time */
+
+ DBG("%s(%d)\n", __func__, __LINE__);
+
+ /* check whether we wake up from the remote resume */
+ if (phy->remote_wakeup) {
+ /* wait until FPR bit is set automatically on remote resume */
+ do {
+ val = readl(base + USB_PORTSC);
+ udelay(1);
+ if (wait_time_us == 0) {
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+ uhsic_phy_post_resume(phy);
+ return;
+ }
+ wait_time_us--;
+ } while (!(val & USB_PORTSC_RESUME));
+ /* wait for 25 ms to port resume complete */
+ msleep(25);
+ /* disable PMC master control */
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+
+ /* 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 {
+ uhsic_phy_disable_pmc_bus_ctrl(phy);
+ }
+
+ /* Set RUN bit */
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ if (usb_phy_reg_status_wait(base + USB_USBCMD, USB_USBCMD_RS,
+ USB_USBCMD_RS, 2000)) {
+ pr_err("%s: timeout waiting for USB_USBCMD_RS\n", __func__);
+ return;
+ }
+}
+
static int uhsic_phy_open(struct tegra_usb_phy *phy)
{
unsigned long parent_rate;
@@ -1781,7 +2056,7 @@ static int uhsic_phy_open(struct tegra_usb_phy *phy)
return -EINVAL;
}
- utmip_powerup_pmc_wake_detect(phy);
+ uhsic_powerup_pmc_wake_detect(phy);
return 0;
}
@@ -1789,6 +2064,9 @@ static int uhsic_phy_open(struct tegra_usb_phy *phy)
static int uhsic_phy_irq(struct tegra_usb_phy *phy)
{
usb_phy_fence_read(phy);
+ /* check if there is any remote wake event */
+ if (uhsic_phy_remotewake_detected(phy))
+ pr_info("%s: uhsic remote wake detected\n", __func__);
return IRQ_HANDLED;
}
@@ -1800,8 +2078,6 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- uhsic_powerup_pmc_wake_detect(phy);
-
if (phy->phy_clk_on) {
DBG("%s(%d) inst:[%d] phy clk is already On\n",
__func__, __LINE__, phy->inst);
@@ -1869,6 +2145,7 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK);
val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
+ val &= ~HOSTPC1_DEVLC_STS;
writel(val, base + HOSTPC1_DEVLC);
val = readl(base + USB_TXFILLTUNING);
@@ -1911,17 +2188,17 @@ static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
return 0;
}
- val = readl(base + UHSIC_PADS_CFG1);
- val &= ~UHSIC_RPU_STROBE;
- val |= UHSIC_RPD_STROBE;
- writel(val, base + UHSIC_PADS_CFG1);
+ phy->port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
- val = readl(base + USB_SUSP_CTRL);
- val |= UHSIC_RESET;
- writel(val, base + USB_SUSP_CTRL);
- udelay(30);
+ /* Disable interrupts */
+ writel(0, base + USB_USBINTR);
- uhsic_powerdown_pmc_wake_detect(phy);
+ uhsic_setup_pmc_wake_detect(phy);
+
+ val = readl(base + HOSTPC1_DEVLC);
+ val |= HOSTPC1_DEVLC_PHCD;
+ writel(val, base + HOSTPC1_DEVLC);
phy->phy_clk_on = false;
phy->hw_accessible = false;
@@ -1993,6 +2270,7 @@ static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy)
val |= HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_HSIC);
val &= ~HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_MASK);
val |= HOSTPC1_DEVLC_PSPD(HOSTPC1_DEVLC_PSPD_HIGH_SPEED);
+ val &= ~HOSTPC1_DEVLC_STS;
writel(val, base + HOSTPC1_DEVLC);
/* wait here, otherwise HOSTPC1_DEVLC_PSPD will timeout */
mdelay(5);
@@ -2067,67 +2345,13 @@ static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy)
return 0;
}
-
-int uhsic_phy_pre_resume(struct tegra_usb_phy *phy, bool remote_wakeup)
-{
- DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
-
- usb_phy_wait_for_sof(phy);
-
- return 0;
-}
-
int uhsic_phy_resume(struct tegra_usb_phy *phy)
{
- void __iomem *base = phy->regs;
- unsigned long val;
-
DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- /* Check if the phy resume from LP0. When the phy resume from LP0
- * USB register will be reset.to zero */
- if (!readl(base + USB_ASYNCLISTADDR)) {
-
- val = readl(base + USB_USBCMD);
- val |= USB_CMD_RESET;
- writel(val, base + USB_USBCMD);
-
- if (usb_phy_reg_status_wait(base + USB_USBCMD,
- USB_CMD_RESET, 0, 2500) < 0) {
- pr_err("%s: timeout waiting for reset\n", __func__);
- }
-
- val = readl(base + USB_USBMODE);
- val &= ~USB_USBMODE_MASK;
- val |= USB_USBMODE_HOST;
- writel(val, base + USB_USBMODE);
-
- /* Enable Port Power */
- val = readl(base + USB_PORTSC);
- val |= USB_PORTSC_PP;
- writel(val, base + USB_PORTSC);
- udelay(10);
-
- DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
- readl(base + USB_USBSTS), readl(base + USB_PORTSC));
-
- uhsic_phy_bus_port_power(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);
- }
+ uhsic_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ uhsic_phy_restore_end(phy);
return 0;
}