/* ensure sleepwalk logic is disabled */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value &= ~MASTER_ENABLE;
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
/* ensure sleepwalk logics are in low power mode */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value |= MASTER_CFG_SEL;
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
/* set debounce time */
value = ao_readl(priv, XUSB_AO_USB_DEBOUNCE_DEL);
value &= ~UTMIP_LINE_DEB_CNT(~0);
value |= UTMIP_LINE_DEB_CNT(1);
ao_writel(priv, value, XUSB_AO_USB_DEBOUNCE_DEL);
/* ensure fake events of sleepwalk logic are desiabled */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value &= ~(FAKE_USBOP_VAL | FAKE_USBON_VAL |
FAKE_USBOP_EN | FAKE_USBON_EN);
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
/* ensure wake events of sleepwalk logic are not latched */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value &= ~LINE_WAKEUP_EN;
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
/* disable wake event triggers of sleepwalk logic */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value &= ~WAKE_VAL(~0);
value |= WAKE_VAL_NONE;
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
/* power down the line state detectors of the pad */
value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
value |= (USBOP_VAL_PD | USBON_VAL_PD);
ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
/* save state per speed */
value = ao_readl(priv, XUSB_AO_UTMIP_SAVED_STATE(index));
value &= ~SPEED(~0);
switch (speed) { case USB_SPEED_HIGH:
value |= UTMI_HS; break;
/* enable the trigger of the sleepwalk logic */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value |= LINEVAL_WALK_EN;
value &= ~WAKE_WALK_EN;
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
/* reset the walk pointer and clear the alarm of the sleepwalk logic, * as well as capture the configuration of the USB2.0 pad
*/
value = ao_readl(priv, XUSB_AO_UTMIP_TRIGGERS(index));
value |= (CLR_WALK_PTR | CLR_WAKE_ALARM | CAP_CFG);
ao_writel(priv, value, XUSB_AO_UTMIP_TRIGGERS(index));
/* setup the pull-ups and pull-downs of the signals during the four * stages of sleepwalk. * if device is connected, program sleepwalk logic to maintain a J and * keep driving K upon seeing remote wake.
*/
value = USBOP_RPD_A | USBOP_RPD_B | USBOP_RPD_C | USBOP_RPD_D;
value |= USBON_RPD_A | USBON_RPD_B | USBON_RPD_C | USBON_RPD_D;
switch (speed) { case USB_SPEED_HIGH: case USB_SPEED_FULL: /* J state: D+/D- = high/low, K state: D+/D- = low/high */
value |= HIGHZ_A;
value |= AP_A;
value |= AN_B | AN_C | AN_D; if (padctl->soc->supports_lp_cfg_en)
value |= MASTER_ENABLE_B_C_D; break;
case USB_SPEED_LOW: /* J state: D+/D- = low/high, K state: D+/D- = high/low */
value |= HIGHZ_A;
value |= AN_A;
value |= AP_B | AP_C | AP_D; if (padctl->soc->supports_lp_cfg_en)
value |= MASTER_ENABLE_B_C_D; break;
/* power up the line state detectors of the pad */
value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
value &= ~(USBOP_VAL_PD | USBON_VAL_PD);
ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
usleep_range(150, 200);
/* switch the electric control of the USB2.0 pad to XUSB_AO */
value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
value |= FSLS_USE_XUSB_AO | TRK_CTRL_USE_XUSB_AO | RPD_CTRL_USE_XUSB_AO |
RPU_USE_XUSB_AO | VREG_USE_XUSB_AO;
ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
/* set the wake signaling trigger events */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value &= ~WAKE_VAL(~0);
value |= WAKE_VAL_ANY;
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
/* enable the wake detection */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value |= MASTER_ENABLE | LINE_WAKEUP_EN;
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
/* disable the wake detection */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value &= ~(MASTER_ENABLE | LINE_WAKEUP_EN);
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
/* switch the electric control of the USB2.0 pad to XUSB vcore logic */
value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
value &= ~(FSLS_USE_XUSB_AO | TRK_CTRL_USE_XUSB_AO | RPD_CTRL_USE_XUSB_AO |
RPU_USE_XUSB_AO | VREG_USE_XUSB_AO);
ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
/* disable wake event triggers of sleepwalk logic */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
value &= ~WAKE_VAL(~0);
value |= WAKE_VAL_NONE;
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK_CFG(index));
if (padctl->soc->supports_lp_cfg_en) { /* disable the four stages of sleepwalk */
value = ao_readl(priv, XUSB_AO_UTMIP_SLEEPWALK(index));
value &= ~(MASTER_ENABLE_A | MASTER_ENABLE_B_C_D);
ao_writel(priv, value, XUSB_AO_UTMIP_SLEEPWALK(index));
}
/* power down the line state detectors of the port */
value = ao_readl(priv, XUSB_AO_UTMIP_PAD_CFG(index));
value |= USBOP_VAL_PD | USBON_VAL_PD;
ao_writel(priv, value, XUSB_AO_UTMIP_PAD_CFG(index));
/* clear alarm of the sleepwalk logic */
value = ao_readl(priv, XUSB_AO_UTMIP_TRIGGERS(index));
value |= CLR_WAKE_ALARM;
ao_writel(priv, value, XUSB_AO_UTMIP_TRIGGERS(index));
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~ALL_WAKE_EVENTS;
value |= USB2_PORT_WAKEUP_EVENT(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
usleep_range(10, 20);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~ALL_WAKE_EVENTS;
value |= USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~ALL_WAKE_EVENTS;
value &= ~USB2_PORT_WAKE_INTERRUPT_ENABLE(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
usleep_range(10, 20);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~ALL_WAKE_EVENTS;
value |= USB2_PORT_WAKEUP_EVENT(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX)) return;
err = clk_prepare_enable(priv->usb2_trk_clk); if (err < 0)
dev_warn(dev, "failed to enable USB2 trk clock: %d\n", err);
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
value &= ~USB2_TRK_START_TIMER(~0);
value |= USB2_TRK_START_TIMER(0x1e);
value &= ~USB2_TRK_DONE_RESET_TIMER(~0);
value |= USB2_TRK_DONE_RESET_TIMER(0xa);
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
value &= ~BIAS_PAD_PD;
value &= ~HS_SQUELCH_LEVEL(~0);
value |= HS_SQUELCH_LEVEL(priv->calib.hs_squelch);
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
udelay(1);
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
value &= ~USB2_PD_TRK;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
if (padctl->soc->poll_trk_completed) {
err = padctl_readl_poll(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1,
USB2_TRK_COMPLETED, USB2_TRK_COMPLETED, 100); if (err) { /* The failure with polling on trk complete will not * cause the failure of powering on the bias pad.
*/
dev_warn(dev, "failed to poll USB2 trk completed: %d\n", err);
}
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
value |= USB2_TRK_COMPLETED;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
} else {
udelay(100);
}
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2); if (padctl->soc->trk_update_on_idle)
value &= ~CYA_TRK_CODE_UPDATE_ON_IDLE; if (padctl->soc->trk_hw_mode)
value |= USB2_TRK_HW_MODE;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
if (!padctl->soc->trk_hw_mode)
clk_disable_unprepare(priv->usb2_trk_clk);
}
if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX)) return;
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
value |= USB2_PD_TRK;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
if (padctl->soc->trk_hw_mode) {
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
value &= ~USB2_TRK_HW_MODE;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL2);
clk_disable_unprepare(priv->usb2_trk_clk);
}
mutex_lock(&padctl->lock); if (test_bit(index, priv->utmi_pad_enabled)) {
mutex_unlock(&padctl->lock); return;
}
port = tegra_xusb_find_usb2_port(padctl, index); if (!port) {
dev_err(dev, "no port found for USB2 lane %u\n", index);
mutex_unlock(&padctl->lock); return;
}
dev_dbg(dev, "power on UTMI pad %u\n", index);
tegra186_utmi_bias_pad_power_on(padctl);
udelay(2);
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
value &= ~USB2_OTG_PD;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
value &= ~USB2_OTG_PD_DR;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
mutex_lock(&padctl->lock); if (!test_bit(index, priv->utmi_pad_enabled)) {
mutex_unlock(&padctl->lock); return;
}
dev_dbg(padctl->dev, "power down UTMI pad %u\n", index);
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
value |= USB2_OTG_PD;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
value |= USB2_OTG_PD_DR;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
dev_dbg(padctl->dev, "%s id override\n", status ? "set" : "clear");
value = padctl_readl(padctl, USB2_VBUS_ID);
id_override = value & ID_OVERRIDE(~0);
if (status) { if (value & VBUS_OVERRIDE) {
value &= ~VBUS_OVERRIDE;
padctl_writel(padctl, value, USB2_VBUS_ID);
usleep_range(1000, 2000);
value = padctl_readl(padctl, USB2_VBUS_ID);
}
if (id_override != ID_OVERRIDE_GROUNDED) {
value &= ~ID_OVERRIDE(~0);
value |= ID_OVERRIDE_GROUNDED;
padctl_writel(padctl, value, USB2_VBUS_ID);
err = regulator_enable(port->supply); if (err) {
dev_err(padctl->dev, "Failed to enable regulator: %d\n", err); return err;
}
}
} else { if (id_override == ID_OVERRIDE_GROUNDED) { /* * The regulator is disabled only when the role transitions * from USB_ROLE_HOST to USB_ROLE_NONE.
*/
err = regulator_disable(port->supply); if (err) {
dev_err(padctl->dev, "Failed to disable regulator: %d\n", err); return err;
}
value &= ~ID_OVERRIDE(~0);
value |= ID_OVERRIDE_FLOATING;
padctl_writel(padctl, value, USB2_VBUS_ID);
}
}
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
value &= ~TERM_RANGE_ADJ(~0);
value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj);
value &= ~RPD_CTRL(~0);
value |= RPD_CTRL(priv->calib.rpd_ctrl);
padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value |= SSPX_ELPG_CLAMP_EN_EARLY(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
usleep_range(100, 200);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value |= SSPX_ELPG_CLAMP_EN(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value &= ~SSPX_ELPG_CLAMP_EN_EARLY(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
usleep_range(100, 200);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value &= ~SSPX_ELPG_CLAMP_EN(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~ALL_WAKE_EVENTS;
value |= SS_PORT_WAKEUP_EVENT(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
usleep_range(10, 20);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~ALL_WAKE_EVENTS;
value |= SS_PORT_WAKE_INTERRUPT_ENABLE(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~ALL_WAKE_EVENTS;
value &= ~SS_PORT_WAKE_INTERRUPT_ENABLE(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
usleep_range(10, 20);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~ALL_WAKE_EVENTS;
value |= SS_PORT_WAKEUP_EVENT(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
port = tegra_xusb_find_usb3_port(padctl, index); if (!port) {
dev_err(dev, "no port found for USB3 lane %u\n", index); return -ENODEV;
}
usb2 = tegra_xusb_find_usb2_port(padctl, port->port); if (!usb2) {
dev_err(dev, "no companion port found for USB3 lane %u\n",
index); return -ENODEV;
}
mutex_lock(&padctl->lock);
value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CAP);
value &= ~(PORT_CAP_MASK << PORTX_CAP_SHIFT(index));
if (usb2->mode == USB_DR_MODE_UNKNOWN)
value |= (PORT_CAP_DISABLED << PORTX_CAP_SHIFT(index)); elseif (usb2->mode == USB_DR_MODE_PERIPHERAL)
value |= (PORT_CAP_DEVICE << PORTX_CAP_SHIFT(index)); elseif (usb2->mode == USB_DR_MODE_HOST)
value |= (PORT_CAP_HOST << PORTX_CAP_SHIFT(index)); elseif (usb2->mode == USB_DR_MODE_OTG)
value |= (PORT_CAP_OTG << PORTX_CAP_SHIFT(index));
if (padctl->soc->supports_gen2 && port->disable_gen2) {
value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CFG);
value &= ~(PORTX_SPEED_SUPPORT_MASK <<
PORTX_SPEED_SUPPORT_SHIFT(index));
value |= (PORT_SPEED_SUPPORT_GEN1 <<
PORTX_SPEED_SUPPORT_SHIFT(index));
padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CFG);
}
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value &= ~SSPX_ELPG_VCORE_DOWN(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
usleep_range(100, 200);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value &= ~SSPX_ELPG_CLAMP_EN_EARLY(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
usleep_range(100, 200);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value &= ~SSPX_ELPG_CLAMP_EN(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
port = tegra_xusb_find_usb3_port(padctl, index); if (!port) {
dev_err(dev, "no port found for USB3 lane %u\n", index); return -ENODEV;
}
mutex_lock(&padctl->lock);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value |= SSPX_ELPG_CLAMP_EN_EARLY(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
usleep_range(100, 200);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value |= SSPX_ELPG_CLAMP_EN(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
usleep_range(250, 350);
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1);
value |= SSPX_ELPG_VCORE_DOWN(index);
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.