summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorAjay Gupta <ajayg@nvidia.com>2013-03-08 17:19:34 -0800
committerMrutyunjay Sawant <msawant@nvidia.com>2013-04-12 02:01:45 -0700
commit58ec6d62fa6b456906f8b2397e64c8e8516bf420 (patch)
treec4a90bb8d2aef4e326b636ff6ff217cc4402f1a4 /drivers/usb
parent981322cf0afccf45f3d43c8b8849f2de8f2dc2a7 (diff)
usb: xhci: tegra: save restore dfe_cntl and ctle
This is needed as per updated PG. Bug 1247235 Change-Id: I29ef5d11e92175481bf9e091fbd5ed01e8a6a86b Signed-off-by: Ajay Gupta <ajayg@nvidia.com> Reviewed-on: http://git-master/r/217015 Reviewed-by: Jui Chang Kuo <jckuo@nvidia.com> Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Ashutosh Jha <ajha@nvidia.com> Reviewed-by: Henry Lin <henryl@nvidia.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/xhci-tegra.c151
1 files changed, 147 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
index f1e5e872e80c..dbde99635fd4 100644
--- a/drivers/usb/host/xhci-tegra.c
+++ b/drivers/usb/host/xhci-tegra.c
@@ -74,6 +74,7 @@ enum MBOX_CMD_TYPE {
MBOX_CMD_SET_BW,
MBOX_CMD_SET_SS_PWR_GATING,
MBOX_CMD_SET_SS_PWR_UNGATING, /* 8 */
+ MBOX_CMD_SAVE_DFE_CTLE_CTX,
/* needs to be the last cmd */
MBOX_CMD_MAX,
@@ -156,6 +157,15 @@ struct xusb_save_regs {
u32 cfg_order;
u32 cfg_fladj;
u32 cfg_sid;
+ /* DFE and CTLE */
+ u32 tap1_val0;
+ u32 tap1_val1;
+ u32 amp_val0;
+ u32 amp_val1;
+ u32 ctle_z_val0;
+ u32 ctle_z_val1;
+ u32 ctle_g_val0;
+ u32 ctle_g_val1;
};
struct tegra_xhci_firmware {
@@ -181,6 +191,7 @@ struct tegra_xhci_hcd {
bool hs_wake_event;
bool host_resume_req;
bool lp0_exit;
+ bool dfe_ctle_ctx_saved;
unsigned long last_jiffies;
unsigned long host_phy_base;
@@ -861,6 +872,124 @@ static void utmip_biaspd_workaround(struct tegra_xhci_hcd *tegra)
}
}
+static void tegra_xhci_save_dfe_ctle_context(struct tegra_xhci_hcd *tegra)
+{
+ struct xhci_hcd *xhci = tegra->xhci;
+ u32 reg;
+
+ xhci_info(xhci, "saving dfe_cntl and ctle context\n");
+ /* save tap1_val0 for pad0 for dfe_cntl */
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+ reg &= ~(0xff << 16);
+ reg |= (0x32 << 16);
+ writel(reg, tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+ tegra->sregs.tap1_val0 = ((reg & (0x1f << 24)) >> 24);
+
+ /* save tap1_val1 for pad1 for dfe_cntl */
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+ reg &= ~(0xff << 16);
+ reg |= (0x32 << 16);
+ writel(reg, tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+ tegra->sregs.tap1_val1 = ((reg & (0x1f << 24)) >> 24);
+
+ /* save amp_val0 for pad0 for dfe_cntl */
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+ reg &= ~(0xff << 16);
+ reg |= (0x33 << 16);
+ writel(reg, tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+ tegra->sregs.amp_val0 = ((reg & (0x7f << 24)) >> 24);
+
+ /* save amp_val1 for pad1 for dfe_cntl */
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+ reg &= ~(0xff << 16);
+ reg |= (0x33 << 16);
+ writel(reg, tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+ tegra->sregs.amp_val1 = ((reg & (0x7f << 24)) >> 24);
+
+ /* save ctle_z_val0 for pad0 for ctle */
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+ reg &= ~(0xff << 16);
+ reg |= (0x20 << 16);
+ writel(reg, tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+ tegra->sregs.ctle_z_val0 = ((reg & (0x3f << 24)) >> 24);
+
+ /* save ctle_z_val1 for pad1 for ctle */
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+ reg &= ~(0xff << 16);
+ reg |= (0x20 << 16);
+ writel(reg, tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+ tegra->sregs.ctle_z_val1 = ((reg & (0x3f << 24)) >> 24);
+
+ /* save ctle_g_val0 for pad0 for ctle */
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+ reg &= ~(0xff << 16);
+ reg |= (0x21 << 16);
+ writel(reg, tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD0_CTL_6_0);
+ tegra->sregs.ctle_g_val0 = ((reg & (0x3f << 24)) >> 24);
+
+ /* save ctle_g_val1 for pad1 for ctle */
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+ reg &= ~(0xff << 16);
+ reg |= (0x21 << 16);
+ writel(reg, tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+
+ reg = readl(tegra->padctl_base + IOPHY_MISC_PAD1_CTL_6_0);
+ tegra->sregs.ctle_g_val1 = ((reg & (0x3f << 24)) >> 24);
+
+ tegra->dfe_ctle_ctx_saved = true;
+}
+
+static void tegra_xhci_restore_dfe_ctle_context(struct tegra_xhci_hcd *tegra)
+{
+ struct xhci_hcd *xhci = tegra->xhci;
+ u32 reg;
+
+ /* don't restore if not saved */
+ if (tegra->dfe_ctle_ctx_saved == false)
+ return;
+
+ xhci_info(xhci, "restoring dfe_cntl and ctle context\n");
+
+ /* restore dfe_cntl for pad0 */
+ reg = readl(tegra->padctl_base + IOPHY_USB3_PAD0_CTL_4_0);
+ reg &= ~((0x7f << 16) | (0x1f << 24));
+ reg |= ((tegra->sregs.amp_val0 << 16) | (tegra->sregs.tap1_val0 << 24));
+ writel(reg, tegra->padctl_base + IOPHY_USB3_PAD0_CTL_4_0);
+
+ /* restore dfe_cntl for pad1 */
+ reg = readl(tegra->padctl_base + IOPHY_USB3_PAD1_CTL_4_0);
+ reg &= ~((0x7f << 16) | (0x1f << 24));
+ reg |= ((tegra->sregs.amp_val1 << 16) | (tegra->sregs.tap1_val1 << 24));
+ writel(reg, tegra->padctl_base + IOPHY_USB3_PAD1_CTL_4_0);
+
+ /* restore ctle for pad0 */
+ reg = readl(tegra->padctl_base + IOPHY_USB3_PAD0_CTL_2_0);
+ reg &= ~((0x3f << 8) | (0x3f << 16));
+ reg |= ((tegra->sregs.ctle_g_val0 << 8) |
+ (tegra->sregs.ctle_z_val0 << 16));
+ writel(reg, tegra->padctl_base + IOPHY_USB3_PAD0_CTL_2_0);
+
+ /* restore ctle for pad1 */
+ reg = readl(tegra->padctl_base + IOPHY_USB3_PAD1_CTL_2_0);
+ reg &= ~((0x3f << 8) | (0x3f << 16));
+ reg |= ((tegra->sregs.ctle_g_val1 << 8) |
+ (tegra->sregs.ctle_z_val1 << 16));
+ writel(reg, tegra->padctl_base + IOPHY_USB3_PAD1_CTL_2_0);
+}
/* This function assigns the USB ports to the controllers,
* then programs the port capabilities and pad parameters
* of ports assigned to XUSB after booted to OS.
@@ -922,6 +1051,8 @@ tegra_xhci_padctl_portmap_and_caps(struct tegra_xhci_hcd *tegra)
reg = xusb_padctl->dfe_cntl;
writel(reg, tegra->padctl_base + IOPHY_USB3_PAD1_CTL_4_0);
+ tegra_xhci_restore_dfe_ctle_context(tegra);
+
reg = readl(tegra->padctl_base + USB2_OTG_PAD0_CTL_0_0);
reg &= ~((0x3fff << 0) | (0x1f << 19));
reg |= xusb_padctl->hs_slew | xusb_padctl->ls_rslew
@@ -1104,13 +1235,17 @@ static void tegra_xhci_enable_fw_message(struct tegra_xhci_hcd *tegra)
mutex_lock(&tegra->mbox_lock);
- writel(MBOX_OWNER_SW, tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
do {
+ writel(MBOX_OWNER_SW,
+ tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
reg = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
+ usleep_range(10, 20);
} while (reg != MBOX_OWNER_SW && timeout--);
- if ((timeout == 0) && (reg != MBOX_OWNER_SW))
+ if ((timeout == 0) && (reg != MBOX_OWNER_SW)) {
dev_err(&pdev->dev, "Failed to set mbox message owner ID\n");
+ return;
+ }
writel((MBOX_CMD_MSG_ENABLED << MBOX_CMD_SHIFT),
tegra->fpci_base + XUSB_CFG_ARU_MBOX_DATA_IN);
@@ -1136,6 +1271,10 @@ static int load_firmware(struct tegra_xhci_hcd *tegra, bool resetARU)
struct xhci_cap_regs __iomem *cap_regs;
struct xhci_op_regs __iomem *op_regs;
+ /* enable mbox interrupt */
+ writel(readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD) | MBOX_INT_EN,
+ tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
+
/* First thing, reset the ARU. By the time we get to
* loading boot code below, reset would be complete.
* alternatively we can busy wait on rst pending bit.
@@ -1649,8 +1788,6 @@ tegra_xhci_host_partition_elpg_exit(struct tegra_xhci_hcd *tegra)
goto out;
}
- tegra_xhci_enable_fw_message(tegra);
-
pmc_init();
pmc_data.pmc_ops->disable_pmc_bus_ctrl(&pmc_data);
@@ -1768,6 +1905,11 @@ tegra_xhci_process_mbox_message(struct work_struct *work)
xhci_err(xhci, "%s: could not set required mem bw.\n",
__func__);
goto send_sw_response;
+ case MBOX_CMD_SAVE_DFE_CTLE_CTX:
+ tegra_xhci_save_dfe_ctle_context(tegra);
+ tegra_xhci_restore_dfe_ctle_context(tegra);
+ sw_resp |= (MBOX_CMD_ACK << MBOX_CMD_SHIFT);
+ goto send_sw_response;
case MBOX_CMD_ACK:
writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
@@ -2549,6 +2691,7 @@ static int tegra_xhci_probe(struct platform_device *pdev)
tegra->hs_wake_event = false;
tegra->host_resume_req = false;
tegra->lp0_exit = false;
+ tegra->dfe_ctle_ctx_saved = false;
/* reset wake event to NONE */
pmc_reg = readl(tegra->pmc_base + PMC_UTMIP_UHSIC_SLEEP_CFG_0);