summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra3_usb_phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_usb_phy.c')
-rw-r--r--arch/arm/mach-tegra/tegra3_usb_phy.c346
1 files changed, 259 insertions, 87 deletions
diff --git a/arch/arm/mach-tegra/tegra3_usb_phy.c b/arch/arm/mach-tegra/tegra3_usb_phy.c
index 3a831c59a750..66637f29b19c 100644
--- a/arch/arm/mach-tegra/tegra3_usb_phy.c
+++ b/arch/arm/mach-tegra/tegra3_usb_phy.c
@@ -473,6 +473,11 @@
#define PHY_DBG(stuff...) do {} while (0)
#endif
+/* define HSIC phy params */
+#define HSIC_SYNC_START_DELAY 9
+#define HSIC_IDLE_WAIT_DELAY 17
+#define HSIC_ELASTIC_UNDERRUN_LIMIT 16
+#define HSIC_ELASTIC_OVERRUN_LIMIT 16
static u32 utmip_rctrl_val, utmip_tctrl_val;
static DEFINE_SPINLOCK(utmip_pad_lock);
@@ -632,12 +637,6 @@ static void utmip_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
/* Enable which type of event can trigger a walk,
- in this case usb_line_wake */
- val = readl(pmc_base + PMC_SLEEPWALK_CFG);
- val |= UTMIP_LINEVAL_WALK_EN(inst);
- writel(val, pmc_base + PMC_SLEEPWALK_CFG);
-
- /* Enable which type of event can trigger a walk,
* in this case usb_line_wake */
val = readl(pmc_base + PMC_SLEEPWALK_CFG);
val |= UTMIP_LINEVAL_WALK_EN(inst);
@@ -721,10 +720,6 @@ static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
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(inst) | UTMIP_CLR_WALK_PTR(inst);
- writel(val, pmc_base + PMC_TRIGGERS);
-
val = readl(base + UTMIP_PMC_WAKEUP0);
val &= ~EVENT_INT_ENB;
writel(val, base + UTMIP_PMC_WAKEUP0);
@@ -744,6 +739,11 @@ static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
val |= (USBOP_VAL_PD(inst) | USBON_VAL_PD(inst));
writel(val, pmc_base + PMC_USB_AO);
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UTMIP_CLR_WALK_PTR(inst);
+ val |= UTMIP_CLR_WAKE_ALARM(inst);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
phy->remote_wakeup = false;
PHY_DBG("%s DISABLE_PMC inst = %d\n", __func__, inst);
}
@@ -766,8 +766,7 @@ bool utmi_phy_remotewake_detected(struct tegra_usb_phy *phy)
writel(val, pmc_base + PMC_SLEEP_CFG);
val = readl(pmc_base + PMC_TRIGGERS);
- val |= UTMIP_CLR_WAKE_ALARM(inst) |
- UTMIP_CLR_WALK_PTR(inst);
+ val |= UTMIP_CLR_WAKE_ALARM(inst);
writel(val, pmc_base + PMC_TRIGGERS);
val = readl(base + UTMIP_PMC_WAKEUP0);
@@ -989,7 +988,8 @@ static int usb_phy_bringup_host_controller(struct tegra_usb_phy *phy)
/* Program the field PTC based on the saved speed mode */
val = readl(base + USB_PORTSC);
val &= ~USB_PORTSC_PTC(~0);
- if (phy->port_speed == USB_PHY_PORT_SPEED_HIGH)
+ if ((phy->port_speed == USB_PHY_PORT_SPEED_HIGH) ||
+ (phy->pdata->phy_intf == TEGRA_USB_PHY_INTF_HSIC))
val |= USB_PORTSC_PTC(5);
else if (phy->port_speed == USB_PHY_PORT_SPEED_FULL)
val |= USB_PORTSC_PTC(6);
@@ -1222,19 +1222,23 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy)
{
void __iomem *base = phy->regs;
unsigned long val = 0;
+ bool remote_wakeup = false;
+ int irq_status = IRQ_HANDLED;
if (phy->phy_clk_on) {
DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
DBG("USB_USBSTS[0x%x] USB_PORTSC[0x%x]\n",
- readl(base + USB_USBSTS), readl(base + USB_PORTSC));
+ readl(base + USB_USBSTS), readl(base + USB_PORTSC));
DBG("USB_USBMODE[0x%x] USB_USBCMD[0x%x]\n",
- readl(base + USB_USBMODE), readl(base + USB_USBCMD));
+ readl(base + USB_USBMODE), readl(base + USB_USBCMD));
}
usb_phy_fence_read(phy);
/* check if there is any remote wake event */
- if (utmi_phy_remotewake_detected(phy))
+ if (utmi_phy_remotewake_detected(phy)) {
pr_info("%s: utmip remote wake detected\n", __func__);
+ remote_wakeup = true;
+ }
if (phy->pdata->u_data.host.hot_plug) {
val = readl(base + USB_SUSP_CTRL);
@@ -1242,19 +1246,36 @@ static int utmi_phy_irq(struct tegra_usb_phy *phy)
val &= ~USB_PHY_CLK_VALID_INT_ENB |
USB_PHY_CLK_VALID_INT_STS;
writel(val , (base + USB_SUSP_CTRL));
- pr_info("%s: usb device plugged-in\n", __func__);
- val = readl(base + USB_USBSTS);
- if (!(val & USB_USBSTS_PCI))
- return IRQ_NONE;
- val = readl(base + USB_PORTSC);
- val &= ~(USB_PORTSC_WKCN | USB_PORTSC_RWC_BITS);
- writel(val , (base + USB_PORTSC));
+
+ /* In case of remote wakeup PHY clock will not up
+ immediately, so should not access any controller
+ register but normal plug-in/plug-out should be
+ executed */
+ if (!remote_wakeup) {
+ val = readl(base + USB_USBSTS);
+ if (!(val & USB_USBSTS_PCI)) {
+ irq_status = IRQ_NONE;
+ goto exit;
+ }
+
+ val = readl(base + USB_PORTSC);
+ if (val & USB_PORTSC_CCS)
+ val &= ~USB_PORTSC_WKCN;
+ else
+ val &= ~USB_PORTSC_WKDS;
+ val &= ~USB_PORTSC_RWC_BITS;
+ writel(val , (base + USB_PORTSC));
+ }
} else if (!phy->phy_clk_on) {
- return IRQ_NONE;
+ if (remote_wakeup)
+ irq_status = IRQ_HANDLED;
+ else
+ irq_status = IRQ_NONE;
+ goto exit;
}
}
-
- return IRQ_HANDLED;
+exit:
+ return irq_status;
}
static void utmi_phy_enable_obs_bus(struct tegra_usb_phy *phy)
@@ -1466,8 +1487,12 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
enable_hotplug = (val & USB_ID_STATUS) ? false : true;
}
if (enable_hotplug) {
+ /* Enable wakeup event of device plug-in/plug-out */
val = readl(base + USB_PORTSC);
- val |= USB_PORTSC_WKCN;
+ if (val & USB_PORTSC_CCS)
+ val |= USB_PORTSC_WKDS;
+ else
+ val |= USB_PORTSC_WKCN;
writel(val, base + USB_PORTSC);
val = readl(base + USB_SUSP_CTRL);
@@ -1481,6 +1506,7 @@ static int utmi_phy_power_off(struct tegra_usb_phy *phy)
}
}
+ /* Disable PHY clock */
val = readl(base + HOSTPC1_DEVLC);
val |= HOSTPC1_DEVLC_PHCD;
writel(val, base + HOSTPC1_DEVLC);
@@ -1647,11 +1673,11 @@ static void utmi_phy_restore_start(struct tegra_usb_phy *phy)
if (UTMIP_WALK_PTR_VAL(inst) & val) {
phy->remote_wakeup = true;
} else if(!phy->remote_wakeup) {
- if (!((UTMIP_USBON_VAL(phy->inst) |
- UTMIP_USBOP_VAL(phy->inst)) & val)) {
- utmip_phy_disable_pmc_bus_ctrl(phy);
- }
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ if (val & UTMIP_MASTER_ENABLE(inst))
+ utmip_phy_disable_pmc_bus_ctrl(phy);
}
+
utmi_phy_enable_obs_bus(phy);
}
@@ -1669,7 +1695,9 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
val = readl(base + USB_PORTSC);
udelay(1);
if (wait_time_us == 0) {
- PHY_DBG("%s PMC REMOTE WAKEUP FPR timeout val = 0x%x instance = %d\n", __func__, val, phy->inst);
+ PHY_DBG("%s PMC REMOTE WAKEUP FPR timeout"
+ "val = 0x%lx instance = %d\n",
+ __func__, val, phy->inst);
utmip_phy_disable_pmc_bus_ctrl(phy);
utmi_phy_post_resume(phy);
return;
@@ -1810,6 +1838,31 @@ static void uhsic_powerup_pmc_wake_detect(struct tegra_usb_phy *phy)
mdelay(1);
}
+static void uhsic_powerdown_pmc_wake_detect(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+
+ DBG("%s:%d\n", __func__, __LINE__);
+
+ /* turn off 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);
+
+ /* enable pull downs on HSIC PMC */
+ 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);
+ 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_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
{
unsigned long val;
@@ -1844,6 +1897,30 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
val |= UHSIC_PWR;
writel(val, pmc_base + PMC_UTMIP_MASTER_CONFIG);
+ /* Make sure nothing is happening on the line with respect to PMC */
+ val = readl(pmc_base + PMC_UTMIP_UHSIC_FAKE);
+ val &= ~UHSIC_STROBE_VAL;
+ val &= ~UHSIC_DATA_VAL;
+ writel(val, pmc_base + PMC_UTMIP_UHSIC_FAKE);
+
+ /* Clear walk enable */
+ val = readl(pmc_base + PMC_SLEEPWALK_CFG);
+ val &= ~UHSIC_LINEVAL_WALK_EN;
+ writel(val, pmc_base + PMC_SLEEPWALK_CFG);
+
+ /* Make sure wake value for line is none */
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
+ val |= UHSIC_WAKE_VAL(WAKE_VAL_NONE);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* 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);
/* Enable which type of event can trigger a walk,
* in this case usb_line_wake */
@@ -1860,19 +1937,16 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
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;
@@ -1880,19 +1954,21 @@ static void uhsic_setup_pmc_wake_detect(struct tegra_usb_phy *phy)
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*/
+ /* Setting Wake event*/
val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UHSIC_WAKE_VAL(~0);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
val |= UHSIC_WAKE_VAL(WAKE_VAL_SD10);
+ writel(val, pmc_base + PMC_SLEEP_CFG);
+
+ /* Clear the walk pointers and wake alarm */
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= UHSIC_CLR_WAKE_ALARM_P0 | UHSIC_CLR_WALK_PTR_P0;
+ writel(val, pmc_base + PMC_TRIGGERS);
+
+ /* Turn over pad configuration to PMC for line wake events*/
+ val = readl(pmc_base + PMC_SLEEP_CFG);
val |= UHSIC_MASTER_ENABLE;
writel(val, pmc_base + PMC_SLEEP_CFG);
@@ -1911,14 +1987,10 @@ static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
DBG("%s (%d)\n", __func__, __LINE__);
val = readl(pmc_base + PMC_SLEEP_CFG);
- val &= ~UHSIC_WAKE_VAL(0x0);
+ val &= ~UHSIC_WAKE_VAL(WAKE_VAL_ANY);
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);
@@ -1933,6 +2005,10 @@ static void uhsic_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
val |= (STROBE_VAL_PD_P0 | DATA_VAL_PD_P0);
writel(val, pmc_base + PMC_USB_AO);
+ val = readl(pmc_base + PMC_TRIGGERS);
+ val |= (UHSIC_CLR_WALK_PTR_P0 | UHSIC_CLR_WAKE_ALARM_P0);
+ writel(val, pmc_base + PMC_TRIGGERS);
+
phy->remote_wakeup = false;
}
@@ -1947,12 +2023,12 @@ static bool uhsic_phy_remotewake_detected(struct tegra_usb_phy *phy)
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_ANY);
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;
+ val |= UHSIC_CLR_WAKE_ALARM_P0;
writel(val, pmc_base + PMC_TRIGGERS);
val = readl(base + UHSIC_PMC_WAKEUP0);
@@ -2003,14 +2079,10 @@ static void uhsic_phy_restore_start(struct tegra_usb_phy *phy)
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);
- }
+ 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);
}
}
@@ -2019,7 +2091,7 @@ 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 */
+ int wait_time_us = 25000; /* FPR should be set by this time */
DBG("%s(%d)\n", __func__, __LINE__);
@@ -2035,9 +2107,8 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
return;
}
wait_time_us--;
- } while (!(val & USB_PORTSC_RESUME));
- /* wait for 25 ms to port resume complete */
- msleep(25);
+ } while (val & (USB_PORTSC_RESUME | USB_PORTSC_SUSP));
+
/* disable PMC master control */
uhsic_phy_disable_pmc_bus_ctrl(phy);
@@ -2050,25 +2121,73 @@ static void uhsic_phy_restore_end(struct tegra_usb_phy *phy)
pr_warn("%s: timeout waiting for SOF\n", __func__);
}
uhsic_phy_post_resume(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;
+ }
} 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 hsic_rail_enable(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ if (phy->hsic_reg == NULL) {
+ phy->hsic_reg = regulator_get(NULL, "avdd_hsic");
+ if (IS_ERR_OR_NULL(phy->hsic_reg)) {
+ pr_err("HSIC: Could not get regulator avdd_hsic\n");
+ phy->hsic_reg = NULL;
+ return PTR_ERR(phy->hsic_reg);
+ }
}
+
+ ret = regulator_enable(phy->hsic_reg);
+ if (ret < 0) {
+ pr_err("%s avdd_hsic could not be enabled\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int hsic_rail_disable(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ if (phy->hsic_reg == NULL) {
+ pr_warn("%s: unbalanced disable\n", __func__);
+ return -EIO;
+ }
+
+ ret = regulator_disable(phy->hsic_reg);
+ if (ret < 0) {
+ pr_err("HSIC regulator avdd_hsic cannot be disabled\n");
+ return ret;
+ }
+
+ return 0;
}
static int uhsic_phy_open(struct tegra_usb_phy *phy)
{
unsigned long parent_rate;
int i;
+ int ret;
+
+ phy->hsic_reg = NULL;
+ ret = hsic_rail_enable(phy);
+ if (ret < 0) {
+ pr_err("%s avdd_hsic could not be enabled\n", __func__);
+ return ret;
+ }
DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
parent_rate = clk_get_rate(clk_get_parent(phy->pllu_clk));
@@ -2088,6 +2207,18 @@ static int uhsic_phy_open(struct tegra_usb_phy *phy)
return 0;
}
+static void uhsic_phy_close(struct tegra_usb_phy *phy)
+{
+ int ret;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+ uhsic_powerdown_pmc_wake_detect(phy);
+
+ ret = hsic_rail_disable(phy);
+ if (ret < 0)
+ pr_err("%s avdd_hsic could not be disabled\n", __func__);
+}
+
static int uhsic_phy_irq(struct tegra_usb_phy *phy)
{
usb_phy_fence_read(phy);
@@ -2101,7 +2232,6 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
- struct tegra_hsic_config *config = &phy->pdata->u_cfg.hsic;
DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
@@ -2127,13 +2257,13 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
writel(val, base + USB_SUSP_CTRL);
val = readl(base + UHSIC_HSRX_CFG0);
- val |= UHSIC_IDLE_WAIT(config->idle_wait_delay);
- val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(config->elastic_underrun_limit);
- val |= UHSIC_ELASTIC_OVERRUN_LIMIT(config->elastic_overrun_limit);
+ val |= UHSIC_IDLE_WAIT(HSIC_IDLE_WAIT_DELAY);
+ val |= UHSIC_ELASTIC_UNDERRUN_LIMIT(HSIC_ELASTIC_UNDERRUN_LIMIT);
+ val |= UHSIC_ELASTIC_OVERRUN_LIMIT(HSIC_ELASTIC_OVERRUN_LIMIT);
writel(val, base + UHSIC_HSRX_CFG0);
val = readl(base + UHSIC_HSRX_CFG1);
- val |= UHSIC_HS_SYNC_START_DLY(config->sync_start_delay);
+ val |= UHSIC_HS_SYNC_START_DLY(HSIC_SYNC_START_DELAY);
writel(val, base + UHSIC_HSRX_CFG1);
/* WAR HSIC TX */
@@ -2173,8 +2303,6 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
val = readl(base + HOSTPC1_DEVLC);
val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
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);
@@ -2203,6 +2331,15 @@ static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
phy->phy_clk_on = true;
phy->hw_accessible = true;
+ if (phy->pmc_sleepwalk) {
+ DBG("%s(%d) inst:[%d] restore phy\n", __func__, __LINE__,
+ phy->inst);
+ uhsic_phy_restore_start(phy);
+ usb_phy_bringup_host_controller(phy);
+ uhsic_phy_restore_end(phy);
+ phy->pmc_sleepwalk = false;
+ }
+
return 0;
}
@@ -2224,12 +2361,20 @@ static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
/* Disable interrupts */
writel(0, base + USB_USBINTR);
- uhsic_setup_pmc_wake_detect(phy);
+ if (phy->pmc_sleepwalk == false) {
+ uhsic_setup_pmc_wake_detect(phy);
+ phy->pmc_sleepwalk = true;
+ }
val = readl(base + HOSTPC1_DEVLC);
val |= HOSTPC1_DEVLC_PHCD;
writel(val, base + HOSTPC1_DEVLC);
+ /* Remove power downs for HSIC from PADS CFG1 register */
+ val = readl(base + UHSIC_PADS_CFG1);
+ val |= (UHSIC_PD_BG |UHSIC_PD_TRK | UHSIC_PD_RX |
+ UHSIC_PD_ZI | UHSIC_PD_TX);
+ writel(val, base + UHSIC_PADS_CFG1);
phy->phy_clk_on = false;
phy->hw_accessible = false;
@@ -2251,8 +2396,6 @@ int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy)
val = readl(base + HOSTPC1_DEVLC);
val &= ~(HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK));
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);
writel(val, base + HOSTPC1_DEVLC);
val = readl(base + UHSIC_MISC_CFG0);
@@ -2292,8 +2435,6 @@ static int uhsic_phy_bus_reset(struct tegra_usb_phy *phy)
val = readl(base + HOSTPC1_DEVLC);
val &= ~HOSTPC1_DEVLC_PTS(HOSTPC1_DEVLC_PTS_MASK);
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 */
@@ -2373,10 +2514,6 @@ int uhsic_phy_resume(struct tegra_usb_phy *phy)
{
DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
- uhsic_phy_restore_start(phy);
- usb_phy_bringup_host_controller(phy);
- uhsic_phy_restore_end(phy);
-
return 0;
}
@@ -2528,6 +2665,9 @@ static void ulpi_null_phy_close(struct tegra_usb_phy *phy)
static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy)
{
+ unsigned int val;
+ void __iomem *base = phy->regs;
+
DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
if (!phy->phy_clk_on) {
@@ -2539,6 +2679,9 @@ static int ulpi_null_phy_power_off(struct tegra_usb_phy *phy)
phy->phy_clk_on = false;
phy->hw_accessible = false;
ulpi_null_phy_set_tristate(true);
+ val = readl(base + ULPIS2S_CTRL);
+ val &= ~ULPIS2S_PLLU_MASTER_BLASTER60;
+ writel(val, base + ULPIS2S_CTRL);
return 0;
}
@@ -2563,7 +2706,16 @@ static int ulpi_null_phy_init(struct tegra_usb_phy *phy)
static int ulpi_null_phy_irq(struct tegra_usb_phy *phy)
{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
usb_phy_fence_read(phy);
+ if (phy->bus_reseting){
+ val = readl(base + USB_USBCMD);
+ val |= USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ phy->bus_reseting = false;
+ }
return IRQ_HANDLED;
}
@@ -2589,6 +2741,23 @@ static int ulpi_null_phy_cmd_reset(struct tegra_usb_phy *phy)
return 0;
}
+static int ulpi_phy_bus_reset(struct tegra_usb_phy *phy)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+
+ DBG("%s(%d) inst:[%d]\n", __func__, __LINE__, phy->inst);
+
+ /*DISABLE RUN BIT */
+
+ val = readl(base + USB_USBCMD);
+ val &= ~USB_USBCMD_RS;
+ writel(val, base + USB_USBCMD);
+ phy->bus_reseting = true;
+
+ return 0;
+}
+
static int ulpi_null_phy_restore(struct tegra_usb_phy *phy)
{
struct tegra_ulpi_config *config = &phy->pdata->u_cfg.ulpi;
@@ -2761,6 +2930,7 @@ static int ulpi_null_phy_power_on(struct tegra_usb_phy *phy)
}
udelay(10);
+ phy->bus_reseting = false;
phy->phy_clk_on = true;
phy->hw_accessible = true;
@@ -2823,6 +2993,7 @@ static struct tegra_usb_phy_ops utmi_phy_ops = {
static struct tegra_usb_phy_ops uhsic_phy_ops = {
.open = uhsic_phy_open,
+ .close = uhsic_phy_close,
.irq = uhsic_phy_irq,
.power_on = uhsic_phy_power_on,
.power_off = uhsic_phy_power_off,
@@ -2844,6 +3015,7 @@ static struct tegra_usb_phy_ops ulpi_null_phy_ops = {
.resume = ulpi_null_phy_resume,
.post_resume = ulpi_null_phy_post_resume,
.reset = ulpi_null_phy_cmd_reset,
+ .bus_reset = ulpi_phy_bus_reset,
};
static struct tegra_usb_phy_ops ulpi_link_phy_ops;