usb: xhci: tegra: program lane owner for usb3_ss port
Ajay Gupta [Sat, 15 Jun 2013 00:05:30 +0000 (17:05 -0700)]
Bug 1301052

Change-Id: Icfadcdf02415e3bcb0c09b5deb9bb6e7a15f5cdf
Signed-off-by: Ajay Gupta <ajayg@nvidia.com>
Reviewed-on: http://git-master/r/242040
Reviewed-by: Ashutosh Jha <ajha@nvidia.com>
Reviewed-by: Seema Khowala <seemaj@nvidia.com>

arch/arm/mach-tegra/board-ardbeg.c
arch/arm/mach-tegra/include/mach/tegra_usb_pad_ctrl.h
arch/arm/mach-tegra/include/mach/xusb.h
drivers/platform/tegra/tegra_usb_pad_ctrl.c
drivers/usb/host/xhci-tegra.c

index 080864e..9a42e0d 100644 (file)
@@ -670,6 +670,8 @@ static void ardbeg_xusb_init(void)
 {
        int usb_port_owner_info = tegra_get_usb_port_owner_info();
 
+       xusb_bdata.lane_owner = (u8) tegra_get_lane_owner_info();
+
        if (!(usb_port_owner_info & UTMI1_PORT_OWNER_XUSB))
                xusb_bdata.portmap &= ~(TEGRA_XUSB_USB2_P0 | TEGRA_XUSB_SS_P0);
 
index 6a5d2ec..6ab5f58 100644 (file)
 #define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK2     (1 << 3)
 #define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK3     (1 << 4)
 #define XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK4     (1 << 5)
+#define XUSB_PADCTL_USB3_PAD_MUX_FORCE_SATA_PAD_IDDQ_DISABLE_MASK0     (1 << 6)
 #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE0        (0x3 << 16)
 #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE1        (0x3 << 18)
 #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE2        (0x3 << 20)
 #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE3        (0x3 << 22)
 #define XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE4        (0x3 << 24)
+#define XUSB_PADCTL_USB3_PAD_MUX_SATA_PAD_LANE0        (0x3 << 26)
+#define XUSB_PADCTL_USB3_PAD_MUX_SATA_PAD_LANE0_OWNER_USB3_SS  (0x1 << 26)
+#define XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE0_OWNER_USB3_SS  (0x1 << 16)
+#define XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE1_OWNER_USB3_SS  (0x1 << 18)
 
 int utmi_phy_pad_disable(void);
 int utmi_phy_pad_enable(void);
+int usb3_phy_pad_enable(u8 lane_owner);
 #ifdef CONFIG_ARCH_TEGRA_12x_SOC
 int pcie_phy_pad_enable(int lane_owner);
 #endif
index 5098688..b3c3e55 100644 (file)
@@ -52,6 +52,7 @@ struct tegra_xusb_board_data {
         */
        u8      ss_portmap;
        u8      ulpicap;
+       u8      lane_owner;
 };
 
 struct tegra_xusb_platform_data {
index effb905..0d7a0af 100644 (file)
@@ -107,6 +107,71 @@ out:
 }
 EXPORT_SYMBOL_GPL(utmi_phy_pad_disable);
 
+int usb3_phy_pad_enable(u8 lane_owner)
+{
+       unsigned long val, flags;
+       void __iomem *pad_base = IO_ADDRESS(TEGRA_XUSB_PADCTL_BASE);
+
+       spin_lock_irqsave(&xusb_padctl_lock, flags);
+
+       /*
+        * program ownership of lanes owned by USB3 based on odmdata[28:30]
+        * odmdata[28] = 0 (SATA lane owner = SATA),
+        * odmdata[28] = 1 (SATA lane owner = USB3_SS port1)
+        * odmdata[29] = 0 (PCIe lane1 owner = PCIe),
+        * odmdata[29] = 1 (PCIe lane1 owner = USB3_SS port1)
+        * odmdata[30] = 0 (PCIe lane0 owner = PCIe),
+        * odmdata[30] = 1 (PCIe lane0 owner = USB3_SS port0)
+        * FIXME: Check any GPIO settings needed ?
+        */
+       val = readl(pad_base + XUSB_PADCTL_USB3_PAD_MUX_0);
+       /* USB3_SS port1 can either be mapped to SATA lane or PCIe lane1 */
+       if (lane_owner & BIT(0)) {
+               val &= ~XUSB_PADCTL_USB3_PAD_MUX_SATA_PAD_LANE0;
+               val |= XUSB_PADCTL_USB3_PAD_MUX_SATA_PAD_LANE0_OWNER_USB3_SS;
+       } else if (lane_owner & BIT(1)) {
+               val &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE1;
+               val |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE1_OWNER_USB3_SS;
+       }
+       /* USB_SS port0 is alwasy mapped to PCIe lane0 */
+       if (lane_owner & BIT(2)) {
+               val &= ~XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE0;
+               val |= XUSB_PADCTL_USB3_PAD_MUX_PCIE_PAD_LANE0_OWNER_USB3_SS;
+       }
+       writel(val, pad_base + XUSB_PADCTL_USB3_PAD_MUX_0);
+
+       /* Bring enabled lane out of IDDQ */
+       val = readl(pad_base + XUSB_PADCTL_USB3_PAD_MUX_0);
+       if (lane_owner & BIT(0))
+               val |= XUSB_PADCTL_USB3_PAD_MUX_FORCE_SATA_PAD_IDDQ_DISABLE_MASK0;
+       else if (lane_owner & BIT(1))
+               val |= XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK1;
+       if (lane_owner & BIT(2))
+               val |= XUSB_PADCTL_USB3_PAD_MUX_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK0;
+       writel(val, pad_base + XUSB_PADCTL_USB3_PAD_MUX_0);
+
+       udelay(1);
+
+       /* clear AUX_MUX_LP0 related bits in ELPG_PROGRAM */
+       val = readl(pad_base + XUSB_PADCTL_ELPG_PROGRAM_0);
+       val &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
+       writel(val, pad_base + XUSB_PADCTL_ELPG_PROGRAM_0);
+
+       udelay(100);
+
+       val &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
+       writel(val, pad_base + XUSB_PADCTL_ELPG_PROGRAM_0);
+
+       udelay(100);
+
+       val &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
+       writel(val, pad_base + XUSB_PADCTL_ELPG_PROGRAM_0);
+
+       spin_unlock_irqrestore(&xusb_padctl_lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb3_phy_pad_enable);
+
 #ifdef CONFIG_ARCH_TEGRA_12x_SOC
 int pcie_phy_pad_enable(int lane_owner)
 {
index ae76179..d4bcad0 100644 (file)
@@ -870,6 +870,22 @@ static void tegra_xhci_rx_idle_mode_override(struct tegra_xhci_hcd *tegra,
                }
                writel(reg, tegra->padctl_base +
                        padregs->iophy_misc_pad_p1_ctl3_0);
+
+               /* SATA lane also if USB3_SS port1 mapped to it */
+               if (XUSB_DEVICE_ID_T124 == tegra->device_id &&
+                               tegra->bdata->lane_owner & BIT(0)) {
+                       reg = readl(tegra->padctl_base +
+                               padregs->iophy_misc_pad_s0_ctl3_0);
+                       if (enable) {
+                               reg &= ~RX_IDLE_MODE;
+                               reg |= RX_IDLE_MODE_OVRD;
+                       } else {
+                               reg |= RX_IDLE_MODE;
+                               reg &= ~RX_IDLE_MODE_OVRD;
+                       }
+                       writel(reg, tegra->padctl_base +
+                               padregs->iophy_misc_pad_s0_ctl3_0);
+               }
        }
 }
 
@@ -1091,7 +1107,10 @@ static void tegra_xhci_save_dfe_ctle_context(struct tegra_xhci_hcd *tegra,
 
        xhci_info(xhci, "saving dfe_cntl and ctle context for port %d\n", port);
 
-       offset = port ? padregs->iophy_misc_pad_p1_ctl6_0 :
+       if (port == 3 /* SATA pad */)
+               offset = padregs->iophy_misc_pad_s0_ctl6_0;
+       else
+               offset = port ? padregs->iophy_misc_pad_p1_ctl6_0 :
                                padregs->iophy_misc_pad_p0_ctl6_0;
 
        /* save tap1_val[] for the port for dfe_cntl */
@@ -1144,10 +1163,15 @@ static void tegra_xhci_restore_dfe_ctle_context(struct tegra_xhci_hcd *tegra,
        if (tegra->dfe_ctle_ctx_saved == false)
                return;
 
-       ctl4_offset = port ? padregs->iophy_usb3_pad1_ctl4_0 :
+       if (port == 3 /* SATA pad */) {
+               ctl4_offset = padregs->iophy_misc_pad_s0_ctl4_0;
+               ctl2_offset = padregs->iophy_misc_pad_s0_ctl2_0;
+       } else {
+               ctl4_offset = port ? padregs->iophy_usb3_pad1_ctl4_0 :
                                padregs->iophy_usb3_pad0_ctl4_0;
-       ctl2_offset = port ? padregs->iophy_usb3_pad1_ctl2_0 :
+               ctl2_offset = port ? padregs->iophy_usb3_pad1_ctl2_0 :
                                padregs->iophy_usb3_pad0_ctl2_0;
+       }
 
        xhci_info(xhci, "restoring dfe_cntl/ctle context of port %d\n", port);
 
@@ -1328,6 +1352,10 @@ static void tegra_xhci_program_ss_pad(struct tegra_xhci_hcd *tegra,
        writel(reg, tegra->padctl_base + padregs->ss_port_map_0);
 
        tegra_xhci_restore_dfe_ctle_context(tegra, port);
+       /* SATA also if USB3_SS port1 mapped to it */
+       if ((port == 1) && (XUSB_DEVICE_ID_T124 == tegra->device_id) &&
+                       (tegra->bdata->lane_owner & BIT(0)))
+               tegra_xhci_restore_dfe_ctle_context(tegra, 3);
 }
 
 /* This function assigns the USB ports to the controllers,
@@ -1408,7 +1436,21 @@ tegra_xhci_padctl_portmap_and_caps(struct tegra_xhci_hcd *tegra)
                reg |= RX_IDLE_MODE_OVRD;
                writel(reg, tegra->padctl_base +
                        padregs->iophy_misc_pad_p1_ctl3_0);
+
+               /* SATA lane also if USB3_SS port1 mapped to it but unused */
+               if (XUSB_DEVICE_ID_T124 == tegra->device_id &&
+                               tegra->bdata->lane_owner & BIT(0)) {
+                       reg = readl(tegra->padctl_base +
+                               padregs->iophy_misc_pad_s0_ctl3_0);
+                       reg &= ~RX_IDLE_MODE;
+                       reg |= RX_IDLE_MODE_OVRD;
+                       writel(reg, tegra->padctl_base +
+                               padregs->iophy_misc_pad_s0_ctl3_0);
+               }
        }
+       if (XUSB_DEVICE_ID_T124 == tegra->device_id)
+               usb3_phy_pad_enable(tegra->bdata->lane_owner);
+
 }
 
 /* This function read XUSB registers and stores in device context */
@@ -2287,6 +2329,14 @@ tegra_xhci_process_mbox_message(struct work_struct *work)
        case MBOX_CMD_SAVE_DFE_CTLE_CTX:
                tegra_xhci_save_dfe_ctle_context(tegra, tegra->cmd_data);
                tegra_xhci_restore_dfe_ctle_context(tegra, tegra->cmd_data);
+               /* SATA lane also if USB3_SS port1 mapped to it */
+               if (tegra->cmd_data == 0x1 &&
+                       XUSB_DEVICE_ID_T124 == tegra->device_id &&
+                               tegra->bdata->lane_owner & BIT(0)) {
+                       tegra_xhci_save_dfe_ctle_context(tegra, 3);
+                       tegra_xhci_restore_dfe_ctle_context(tegra, 3);
+               }
+
                sw_resp |= (MBOX_CMD_ACK << MBOX_CMD_SHIFT);
                goto send_sw_response;
        case MBOX_CMD_ACK: