diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/tegra3_usb_phy.c | 532 |
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; } |