usb: xhci: tegra: fix compilation with lockdep enabled
[linux-3.10.git] / drivers / usb / host / xhci-tegra.c
index 15fe870..da83737 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * xhci-tegra.c - Nvidia xHCI host controller driver
  *
- * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
 #include <linux/debugfs.h>
 #include <linux/kthread.h>
 #include <linux/gpio.h>
+#include <linux/usb/otg.h>
+#include <linux/clk/tegra.h>
+#include <linux/tegra-powergate.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/tegra-fuse.h>
+#include <linux/tegra_pm_domains.h>
 
-#include <mach/powergate.h>
-#include <mach/clk.h>
 #include <mach/tegra_usb_pad_ctrl.h>
 #include <mach/tegra_usb_pmc.h>
-#include <mach/pm_domains.h>
 #include <mach/mc.h>
 #include <mach/xusb.h>
 
-#include "../../../arch/arm/mach-tegra/iomap.h" /* HACK -- remove */
 #include "xhci-tegra.h"
 #include "xhci.h"
+#include "../../../arch/arm/mach-tegra/iomap.h"
 
 /* macros */
 #define FW_IOCTL_LOG_DEQUEUE_LOW       (4)
        dev_dbg(_dev, "%s: %s @%x = 0x%x\n", __func__, #_reg,           \
                _reg, readl(_base + _reg))
 
-/* PMC register definition */
-#define PMC_PORT_UTMIP_P0              0
-#define PMC_PORT_UTMIP_P1              1
-#define PMC_PORT_UTMIP_P2              2
-#define PMC_PORT_UHSIC_P0              3
-#define PMC_PORT_NUM                   4
+#define PMC_PORTMAP_MASK(map, pad)     (((map) >> 4*(pad)) & 0xF)
+#define GET_SS_PORTMAP(map, p)         (((map) >> 4*(p)) & 0xF)
 
 #define PMC_USB_DEBOUNCE_DEL_0                 0xec
 #define   UTMIP_LINE_DEB_CNT(x)                (((x) & 0xf) << 16)
@@ -107,10 +110,12 @@ enum MBOX_CMD_TYPE {
        MBOX_CMD_SET_SS_PWR_GATING,
        MBOX_CMD_SET_SS_PWR_UNGATING, /* 8 */
        MBOX_CMD_SAVE_DFE_CTLE_CTX,
-       MBOX_CMD_AIRPLANE_MODE_ENABLED,
-       MBOX_CMD_AIRPLANE_MODE_DISABLED, /* 11 */
+       MBOX_CMD_AIRPLANE_MODE_ENABLED, /* unused */
+       MBOX_CMD_AIRPLANE_MODE_DISABLED, /* 11, unused */
        MBOX_CMD_STAR_HSIC_IDLE,
        MBOX_CMD_STOP_HSIC_IDLE,
+       MBOX_CMD_DBC_WAKE_STACK, /* unused */
+       MBOX_CMD_HSIC_PRETEND_CONNECT,
 
        /* needs to be the last cmd */
        MBOX_CMD_MAX,
@@ -175,7 +180,8 @@ struct cfgtbl {
        u8 magic[8];
        u32 SS_low_power_entry_timeout;
        u8 num_hsic_port;
-       u8 padding[139]; /* padding bytes to makeup 256-bytes cfgtbl */
+       u8 ss_portmap;
+       u8 padding[138]; /* padding bytes to makeup 256-bytes cfgtbl */
 };
 
 struct xusb_save_regs {
@@ -201,10 +207,10 @@ struct xusb_save_regs {
        u32 cfg_fladj;
        u32 cfg_sid;
        /* DFE and CTLE */
-       u32 tap1_val[2];
-       u32 amp_val[2];
-       u32 ctle_z_val[2];
-       u32 ctle_g_val[2];
+       u32 tap1_val[XUSB_SS_PORT_COUNT];
+       u32 amp_val[XUSB_SS_PORT_COUNT];
+       u32 ctle_z_val[XUSB_SS_PORT_COUNT];
+       u32 ctle_g_val[XUSB_SS_PORT_COUNT];
 };
 
 struct tegra_xhci_firmware {
@@ -341,9 +347,11 @@ struct tegra_xhci_hcd {
        bool hs_wake_event;
        bool host_resume_req;
        bool lp0_exit;
-       bool dfe_ctle_ctx_saved;
+       bool dfe_ctx_saved[XUSB_SS_PORT_COUNT];
+       bool ctle_ctx_saved[XUSB_SS_PORT_COUNT];
        unsigned long last_jiffies;
        unsigned long host_phy_base;
+       unsigned long host_phy_size;
        void __iomem *host_phy_virt_base;
 
        void __iomem *padctl_base;
@@ -352,7 +360,10 @@ struct tegra_xhci_hcd {
 
        struct tegra_xusb_platform_data *pdata;
        struct tegra_xusb_board_data *bdata;
+       struct tegra_xusb_chip_calib *cdata;
        struct tegra_xusb_padctl_regs *padregs;
+       const struct tegra_xusb_soc_config *soc_config;
+       u64 tegra_xusb_dmamask;
 
        /* mailbox variables */
        struct mutex mbox_lock;
@@ -360,9 +371,8 @@ struct tegra_xhci_hcd {
        u32 cmd_type;
        u32 cmd_data;
 
-       struct regulator *xusb_s5p0v_reg;
-       struct regulator *xusb_s5p0v1_reg;
-       struct regulator *xusb_s5p0v2_reg;
+       struct regulator *xusb_utmi_vbus_regs[XUSB_UTMI_COUNT];
+
        struct regulator *xusb_s1p05v_reg;
        struct regulator *xusb_s3p3v_reg;
        struct regulator *xusb_s1p8v_reg;
@@ -398,15 +408,39 @@ struct tegra_xhci_hcd {
        bool usb3_rh_suspend;
        bool hc_in_elpg;
 
+       /* otg transceiver */
+       struct usb_phy *transceiver;
+       struct notifier_block otgnb;
+
+       unsigned long usb2_rh_remote_wakeup_ports; /* one bit per port */
        unsigned long usb3_rh_remote_wakeup_ports; /* one bit per port */
        /* firmware loading related */
        struct tegra_xhci_firmware firmware;
 
        struct tegra_xhci_firmware_log log;
+       struct device_attribute hsic_power_attr[XUSB_HSIC_COUNT];
+
+       bool init_done;
 };
 
-static struct tegra_usb_pmc_data pmc_data;
+static int tegra_xhci_probe2(struct tegra_xhci_hcd *tegra);
+static int tegra_xhci_remove(struct platform_device *pdev);
+static void init_filesystem_firmware_done(const struct firmware *fw,
+                                       void *context);
+
+static struct tegra_usb_pmc_data pmc_data[XUSB_UTMI_COUNT];
 static struct tegra_usb_pmc_data pmc_hsic_data[XUSB_HSIC_COUNT];
+static void save_ctle_context(struct tegra_xhci_hcd *tegra,
+       u8 port)  __attribute__ ((unused));
+
+#define FIRMWARE_FILE "tegra_xusb_firmware"
+static char *firmware_file = FIRMWARE_FILE;
+#define FIRMWARE_FILE_HELP     \
+       "used to specify firmware file of Tegra XHCI host controller. "\
+       "Default value is \"" FIRMWARE_FILE "\"."
+
+module_param(firmware_file, charp, S_IRUGO);
+MODULE_PARM_DESC(firmware_file, FIRMWARE_FILE_HELP);
 
 /* functions */
 static inline struct tegra_xhci_hcd *hcd_to_tegra_xhci(struct usb_hcd *hcd)
@@ -414,14 +448,36 @@ static inline struct tegra_xhci_hcd *hcd_to_tegra_xhci(struct usb_hcd *hcd)
        return (struct tegra_xhci_hcd *) dev_get_drvdata(hcd->self.controller);
 }
 
-#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
 static inline void must_have_sync_lock(struct tegra_xhci_hcd *tegra)
 {
+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
        WARN_ON(tegra->sync_lock.owner != current);
-}
-#else
-static inline void must_have_sync_lock(struct tegra_xhci_hcd *tegra)
 #endif
+}
+
+#define for_each_enabled_hsic_pad(_pad, _tegra_xhci_hcd)               \
+       for (_pad = find_next_enabled_hsic_pad(_tegra_xhci_hcd, 0);     \
+           (_pad < XUSB_HSIC_COUNT) && (_pad >= 0);                    \
+           _pad = find_next_enabled_hsic_pad(_tegra_xhci_hcd, _pad + 1))
+
+static inline int find_next_enabled_pad(struct tegra_xhci_hcd *tegra,
+                                               int start, int last)
+{
+       unsigned long portmap = tegra->bdata->portmap;
+       return find_next_bit(&portmap, last , start);
+}
+
+static inline int find_next_enabled_hsic_pad(struct tegra_xhci_hcd *tegra,
+                                               int curr_pad)
+{
+       int start = XUSB_HSIC_INDEX + curr_pad;
+       int last = XUSB_HSIC_INDEX + XUSB_HSIC_COUNT;
+
+       if ((curr_pad < 0) || (curr_pad >= XUSB_HSIC_COUNT))
+               return -1;
+
+       return find_next_enabled_pad(tegra, start, last) - XUSB_HSIC_INDEX;
+}
 
 static void tegra_xhci_setup_gpio_for_ss_lane(struct tegra_xhci_hcd *tegra)
 {
@@ -480,62 +536,32 @@ static void debug_print_portsc(struct xhci_hcd *xhci)
 }
 static void tegra_xhci_war_for_tctrl_rctrl(struct tegra_xhci_hcd *tegra);
 
-static void update_speed(struct tegra_xhci_hcd *tegra, u8 port, bool setup_wake)
+static bool is_otg_host(struct tegra_xhci_hcd *tegra)
+{
+       if (!tegra->transceiver)
+               return true;
+       else if (tegra->transceiver->state == OTG_STATE_A_HOST)
+               return true;
+       else
+               return false;
+}
+
+static int update_speed(struct tegra_xhci_hcd *tegra, u8 port)
 {
        struct usb_hcd *hcd = xhci_to_hcd(tegra->xhci);
        u32 portsc;
 
-       /* we don't need speed information to disable PMC */
-       if (!setup_wake)
-               return;
-
        portsc = readl(hcd->regs + BAR0_XHCI_OP_PORTSC(port));
        if (DEV_FULLSPEED(portsc))
-               pmc_data.port_speed = USB_PMC_PORT_SPEED_FULL;
+               return USB_PMC_PORT_SPEED_FULL;
        else if (DEV_HIGHSPEED(portsc))
-               pmc_data.port_speed = USB_PMC_PORT_SPEED_HIGH;
+               return USB_PMC_PORT_SPEED_HIGH;
        else if (DEV_LOWSPEED(portsc))
-               pmc_data.port_speed = USB_PMC_PORT_SPEED_LOW;
+               return USB_PMC_PORT_SPEED_LOW;
        else if (DEV_SUPERSPEED(portsc))
-               pmc_data.port_speed = USB_PMC_PORT_SPEED_SUPER;
-       else
-               pmc_data.port_speed = USB_PMC_PORT_SPEED_UNKNOWN;
-}
-
-static void setup_wake_detect(bool setup_wake)
-{
-       if (setup_wake)
-               pmc_data.pmc_ops->setup_pmc_wake_detect(&pmc_data);
+               return USB_PMC_PORT_SPEED_SUPER;
        else
-               pmc_data.pmc_ops->disable_pmc_bus_ctrl(&pmc_data, 0);
-}
-
-static void pmc_setup(struct tegra_xhci_hcd *tegra, bool setup_wake)
-{
-       u32 portmap = tegra->bdata->portmap;
-
-       pmc_data.controller_type = TEGRA_USB_3_0;
-       if (portmap & TEGRA_XUSB_USB2_P0) {
-               pmc_data.instance = (tegra->pdata->pmc_portmap >> 0) & 0xf;
-               pmc_data.phy_type = TEGRA_USB_PHY_INTF_UTMI;
-               update_speed(tegra, pmc_data.instance, setup_wake);
-               tegra_usb_pmc_init(&pmc_data);
-               setup_wake_detect(setup_wake);
-       }
-       if (portmap & TEGRA_XUSB_USB2_P1) {
-               pmc_data.instance = (tegra->pdata->pmc_portmap >> 4) & 0xf;
-               pmc_data.phy_type = TEGRA_USB_PHY_INTF_UTMI;
-               update_speed(tegra, pmc_data.instance, setup_wake);
-               tegra_usb_pmc_init(&pmc_data);
-               setup_wake_detect(setup_wake);
-       }
-       if (portmap & TEGRA_XUSB_USB2_P2) {
-               pmc_data.instance = (tegra->pdata->pmc_portmap >> 8) & 0xf;
-               pmc_data.phy_type = TEGRA_USB_PHY_INTF_UTMI;
-               update_speed(tegra, pmc_data.instance, setup_wake);
-               tegra_usb_pmc_init(&pmc_data);
-               setup_wake_detect(setup_wake);
-       }
+               return USB_PMC_PORT_SPEED_UNKNOWN;
 }
 
 static void pmc_init(struct tegra_xhci_hcd *tegra)
@@ -544,19 +570,32 @@ static void pmc_init(struct tegra_xhci_hcd *tegra)
        struct device *dev = &tegra->pdev->dev;
        int pad;
 
-       for (pad = 0; pad < XUSB_HSIC_COUNT; pad++) {
-               if (BIT(XUSB_HSIC_INDEX + pad) & tegra->bdata->portmap) {
-                       dev_dbg(dev, "%s hsic pad %d\n", __func__, pad);
-
-                       pmc = &pmc_hsic_data[pad];
-                       pmc->instance = pad + 1;
-                       pmc->phy_type = TEGRA_USB_PHY_INTF_HSIC;
-                       pmc->port_speed = USB_PMC_PORT_SPEED_HIGH;
+       for (pad = 0; pad < XUSB_UTMI_COUNT; pad++) {
+               if (BIT(XUSB_UTMI_INDEX + pad) & tegra->bdata->portmap) {
+                       dev_dbg(dev, "%s utmi pad %d\n", __func__, pad);
+                       pmc = &pmc_data[pad];
+                       if (tegra->soc_config->pmc_portmap)
+                               pmc->instance = PMC_PORTMAP_MASK(
+                                               tegra->soc_config->pmc_portmap,
+                                               pad);
+                       else
+                               pmc->instance = pad;
+                       pmc->phy_type = TEGRA_USB_PHY_INTF_UTMI;
+                       pmc->port_speed = USB_PMC_PORT_SPEED_UNKNOWN;
                        pmc->controller_type = TEGRA_USB_3_0;
                        tegra_usb_pmc_init(pmc);
                }
        }
 
+       for_each_enabled_hsic_pad(pad, tegra) {
+               dev_dbg(dev, "%s hsic pad %d\n", __func__, pad);
+               pmc = &pmc_hsic_data[pad];
+               pmc->instance = pad + 1;
+               pmc->phy_type = TEGRA_USB_PHY_INTF_HSIC;
+               pmc->port_speed = USB_PMC_PORT_SPEED_HIGH;
+               pmc->controller_type = TEGRA_USB_3_0;
+               tegra_usb_pmc_init(pmc);
+       }
 }
 
 static void pmc_setup_wake_detect(struct tegra_xhci_hcd *tegra)
@@ -567,17 +606,29 @@ static void pmc_setup_wake_detect(struct tegra_xhci_hcd *tegra)
        int port;
        int pad;
 
-       for (pad = 0; pad < XUSB_HSIC_COUNT; pad++) {
-               if (BIT(XUSB_HSIC_INDEX + pad) & tegra->bdata->portmap) {
-                       dev_dbg(dev, "%s hsic pad %d\n", __func__, pad);
+       for_each_enabled_hsic_pad(pad, tegra) {
+               dev_dbg(dev, "%s hsic pad %d\n", __func__, pad);
 
-                       pmc = &pmc_hsic_data[pad];
-                       port = hsic_pad_to_port(pad);
-                       portsc = xhci_read_portsc(tegra->xhci, port);
-                       dev_dbg(dev, "%s hsic pad %d portsc 0x%x\n",
-                                       __func__, pad, portsc);
+               pmc = &pmc_hsic_data[pad];
+               port = hsic_pad_to_port(pad);
+               portsc = xhci_read_portsc(tegra->xhci, port);
+               dev_dbg(dev, "%s hsic pad %d portsc 0x%x\n",
+                       __func__, pad, portsc);
 
-                       if (((int) portsc != -1) && (portsc & PORT_CONNECT))
+               if (((int) portsc != -1) && (portsc & PORT_CONNECT))
+                       pmc->pmc_ops->setup_pmc_wake_detect(pmc);
+       }
+
+       for (pad = 0; pad < XUSB_UTMI_COUNT; pad++) {
+               if (BIT(XUSB_UTMI_INDEX + pad) & tegra->bdata->portmap) {
+                       dev_dbg(dev, "%s utmi pad %d\n", __func__, pad);
+                       pmc = &pmc_data[pad];
+                       pmc->port_speed = update_speed(tegra, pad);
+                       if (pad == 0) {
+                               if (is_otg_host(tegra))
+                                       pmc->pmc_ops->setup_pmc_wake_detect(
+                                                                       pmc);
+                       } else
                                pmc->pmc_ops->setup_pmc_wake_detect(pmc);
                }
        }
@@ -589,11 +640,17 @@ static void pmc_disable_bus_ctrl(struct tegra_xhci_hcd *tegra)
        struct device *dev = &tegra->pdev->dev;
        int pad;
 
-       for (pad = 0; pad < XUSB_HSIC_COUNT; pad++) {
-               if (BIT(XUSB_HSIC_INDEX + pad) & tegra->bdata->portmap) {
-                       dev_dbg(dev, "%s hsic pad %d\n", __func__, pad);
+       for_each_enabled_hsic_pad(pad, tegra) {
+               dev_dbg(dev, "%s hsic pad %d\n", __func__, pad);
+
+               pmc = &pmc_hsic_data[pad];
+               pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 0);
+       }
 
-                       pmc = &pmc_hsic_data[pad];
+       for (pad = 0; pad < XUSB_UTMI_COUNT; pad++) {
+               if (BIT(XUSB_UTMI_INDEX + pad) & tegra->bdata->portmap) {
+                       dev_dbg(dev, "%s utmi pad %d\n", __func__, pad);
+                       pmc = &pmc_data[pad];
                        pmc->pmc_ops->disable_pmc_bus_ctrl(pmc, 0);
                }
        }
@@ -647,6 +704,67 @@ void csb_write(struct tegra_xhci_hcd *tegra, u32 addr, u32 data)
                        input_addr, data);
 }
 
+static int fw_message_send(struct tegra_xhci_hcd *tegra,
+       enum MBOX_CMD_TYPE type, u32 data)
+{
+       struct device *dev = &tegra->pdev->dev;
+       void __iomem *base = tegra->fpci_base;
+       unsigned long target;
+       u32 reg;
+
+       dev_dbg(dev, "%s type %d data 0x%x\n", __func__, type, data);
+
+       mutex_lock(&tegra->mbox_lock);
+
+       target = jiffies + msecs_to_jiffies(20);
+       /* wait mailbox to become idle, timeout in 20ms */
+       while (((reg = readl(base + XUSB_CFG_ARU_MBOX_OWNER)) != 0) &&
+               time_is_after_jiffies(target)) {
+               mutex_unlock(&tegra->mbox_lock);
+               usleep_range(100, 200);
+               mutex_lock(&tegra->mbox_lock);
+       }
+
+       if (reg != 0) {
+               dev_err(dev, "%s mailbox is still busy\n", __func__);
+               goto timeout;
+       }
+
+       target = jiffies + msecs_to_jiffies(10);
+       /* acquire mailbox , timeout in 10ms */
+       writel(MBOX_OWNER_SW, base + XUSB_CFG_ARU_MBOX_OWNER);
+       while (((reg = readl(base + XUSB_CFG_ARU_MBOX_OWNER)) != MBOX_OWNER_SW)
+               && time_is_after_jiffies(target)) {
+               mutex_unlock(&tegra->mbox_lock);
+               usleep_range(100, 200);
+               mutex_lock(&tegra->mbox_lock);
+               writel(MBOX_OWNER_SW, base + XUSB_CFG_ARU_MBOX_OWNER);
+       }
+
+       if (reg != MBOX_OWNER_SW) {
+               dev_err(dev, "%s acquire mailbox timeout\n", __func__);
+               goto timeout;
+       }
+
+       reg = CMD_TYPE(type) | CMD_DATA(data);
+       writel(reg, base + XUSB_CFG_ARU_MBOX_DATA_IN);
+
+       reg = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
+       reg |= MBOX_INT_EN | MBOX_FALC_INT_EN;
+       writel(reg, tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
+
+       mutex_unlock(&tegra->mbox_lock);
+       return 0;
+
+timeout:
+       reg_dump(dev, base, XUSB_CFG_ARU_MBOX_CMD);
+       reg_dump(dev, base, XUSB_CFG_ARU_MBOX_DATA_IN);
+       reg_dump(dev, base, XUSB_CFG_ARU_MBOX_DATA_OUT);
+       reg_dump(dev, base, XUSB_CFG_ARU_MBOX_OWNER);
+       mutex_unlock(&tegra->mbox_lock);
+       return -ETIMEDOUT;
+}
+
 /**
  * fw_log_next - find next log entry in a tegra_xhci_firmware_log context.
  *     This function takes care of wrapping. That means when current log entry
@@ -701,7 +819,7 @@ static inline void fw_log_update_deq_pointer(
        reg |= ((physical_addr >> 16) & 0xffff); /* higher 16-bits */
        iowrite32(reg, tegra->fpci_base + XUSB_CFG_ARU_FW_SCRATCH);
 
-       dev_dbg(dev, "new 0x%p physical addr 0x%x\n", deq, physical_addr);
+       dev_dbg(dev, "new 0x%p physical addr 0x%x\n", deq, (u32)physical_addr);
 }
 
 static inline bool circ_buffer_full(struct circ_buf *circ)
@@ -727,7 +845,7 @@ static inline bool fw_log_available(struct tegra_xhci_hcd *tegra)
 static inline bool fw_log_wait_empty_timeout(struct tegra_xhci_hcd *tegra,
                unsigned timeout)
 {
-       u32 target = jiffies + msecs_to_jiffies(timeout);
+       unsigned long target = jiffies + msecs_to_jiffies(timeout);
        bool ret;
 
        mutex_lock(&tegra->log.mutex);
@@ -946,8 +1064,10 @@ static int fw_log_init(struct tegra_xhci_hcd *tegra)
                return -ENOMEM;
        }
 
-       dev_info(&pdev->dev, "%d bytes log buffer physical 0x%u virtual 0x%p\n",
-               FW_LOG_RING_SIZE, tegra->log.phys_addr, tegra->log.virt_addr);
+       dev_info(&pdev->dev,
+               "%d bytes log buffer physical 0x%u virtual 0x%p\n",
+               FW_LOG_RING_SIZE, (u32)tegra->log.phys_addr,
+               tegra->log.virt_addr);
 
        memset(tegra->log.virt_addr, 0, FW_LOG_RING_SIZE);
        tegra->log.dequeue = tegra->log.virt_addr;
@@ -1039,7 +1159,8 @@ static void fw_log_deinit(struct tegra_xhci_hcd *tegra)
 static int hsic_power_rail_enable(struct tegra_xhci_hcd *tegra)
 {
        struct device *dev = &tegra->pdev->dev;
-       struct tegra_xusb_regulator_name *supply = &tegra->pdata->bdata->supply;
+       const struct tegra_xusb_regulator_name *supply =
+                               &tegra->soc_config->supply;
        int ret;
 
        if (tegra->vddio_hsic_reg)
@@ -1101,7 +1222,7 @@ static int hsic_pad_enable(struct tegra_xhci_hcd *tegra, unsigned pad)
 {
        struct device *dev = &tegra->pdev->dev;
        void __iomem *base = tegra->padctl_base;
-       struct tegra_xusb_hsic_config *hsic = &tegra->bdata->hsic;
+       struct tegra_xusb_hsic_config *hsic = &tegra->bdata->hsic[pad];
        u32 reg;
 
        if (pad >= XUSB_HSIC_COUNT) {
@@ -1135,6 +1256,14 @@ static int hsic_pad_enable(struct tegra_xhci_hcd *tegra, unsigned pad)
        reg &= ~(PD_RX | HSIC_PD_ZI | PD_TRX | PD_TX);
        writel(reg, base + HSIC_PAD_CTL_1(pad));
 
+       /* Wait for 25 us */
+       usleep_range(25, 50);
+
+       /* Power down tracking circuit */
+       reg = readl(base + HSIC_PAD_CTL_1(pad));
+       reg |= PD_TRX;
+       writel(reg, base + HSIC_PAD_CTL_1(pad));
+
        reg = readl(base + HSIC_STRB_TRIM_CONTROL);
        reg &= ~(STRB_TRIM_VAL(~0));
        reg |= STRB_TRIM_VAL(hsic->strb_trim_val);
@@ -1152,6 +1281,73 @@ static int hsic_pad_enable(struct tegra_xhci_hcd *tegra, unsigned pad)
        return 0;
 }
 
+static void hsic_pad_pretend_connect(struct tegra_xhci_hcd *tegra)
+{
+       struct device *dev = &tegra->pdev->dev;
+       struct tegra_xusb_hsic_config *hsic;
+       struct usb_device *hs_root_hub = tegra->xhci->main_hcd->self.root_hub;
+       int pad;
+       u32 portsc;
+       int port;
+       int enabled_pads = 0;
+       unsigned long wait_ports = 0;
+       unsigned long target;
+
+       for_each_enabled_hsic_pad(pad, tegra) {
+               hsic = &tegra->bdata->hsic[pad];
+               if (hsic->pretend_connect)
+                       enabled_pads++;
+       }
+
+       if (enabled_pads == 0) {
+               dev_dbg(dev, "%s no hsic pretend_connect enabled\n", __func__);
+               return;
+       }
+
+       usb_disable_autosuspend(hs_root_hub);
+
+       for_each_enabled_hsic_pad(pad, tegra) {
+               hsic = &tegra->bdata->hsic[pad];
+               if (!hsic->pretend_connect)
+                       continue;
+
+               port = hsic_pad_to_port(pad);
+               portsc = xhci_read_portsc(tegra->xhci, port);
+               dev_dbg(dev, "%s pad %u portsc 0x%x\n", __func__, pad, portsc);
+
+               if (!(portsc & PORT_CONNECT)) {
+                       /* firmware wants 1-based port index */
+                       fw_message_send(tegra,
+                               MBOX_CMD_HSIC_PRETEND_CONNECT, BIT(port + 1));
+               }
+
+               set_bit(port, &wait_ports);
+       }
+
+       /* wait till port reaches U0 */
+       target = jiffies + msecs_to_jiffies(500);
+       do {
+               for_each_set_bit(port, &wait_ports, BITS_PER_LONG) {
+                       portsc = xhci_read_portsc(tegra->xhci, port);
+                       pad = port_to_hsic_pad(port);
+                       dev_dbg(dev, "%s pad %u portsc 0x%x\n", __func__,
+                               pad, portsc);
+                       if ((PORT_PLS_MASK & portsc) == XDEV_U0)
+                               clear_bit(port, &wait_ports);
+               }
+
+               if (wait_ports)
+                       usleep_range(1000, 5000);
+       } while (wait_ports && time_is_after_jiffies(target));
+
+       if (wait_ports)
+               dev_warn(dev, "%s HSIC pad(s) didn't reach U0.\n", __func__);
+
+       usb_enable_autosuspend(hs_root_hub);
+
+       return;
+}
+
 static int hsic_pad_disable(struct tegra_xhci_hcd *tegra, unsigned pad)
 {
        struct device *dev = &tegra->pdev->dev;
@@ -1292,7 +1488,9 @@ static void tegra_xhci_cfg(struct tegra_xhci_hcd *tegra)
 static int tegra_xusb_regulator_init(struct tegra_xhci_hcd *tegra,
                struct platform_device *pdev)
 {
-       struct tegra_xusb_regulator_name *supply = &tegra->bdata->supply;
+       const struct tegra_xusb_regulator_name *supply =
+                               &tegra->soc_config->supply;
+       int i;
        int err = 0;
 
        tegra->xusb_s3p3v_reg =
@@ -1311,19 +1509,33 @@ static int tegra_xusb_regulator_init(struct tegra_xhci_hcd *tegra,
                }
        }
 
-       tegra->xusb_s5p0v_reg = devm_regulator_get(&pdev->dev, supply->s5p0v);
-       if (IS_ERR(tegra->xusb_s5p0v_reg)) {
-               dev_err(&pdev->dev, "5p0v regulator not found: %ld."
-                       , PTR_ERR(tegra->xusb_s5p0v_reg));
-               err = PTR_ERR(tegra->xusb_s5p0v_reg);
-               goto err_put_s3p3v_reg;
-       } else {
-               err = regulator_enable(tegra->xusb_s5p0v_reg);
-               if (err < 0) {
-                       dev_err(&pdev->dev,
-                               "5p0v: regulator enable failed:%d\n", err);
-                       goto err_put_s3p3v_reg;
+       /* enable utmi vbuses */
+       memset(tegra->xusb_utmi_vbus_regs, 0,
+                       sizeof(tegra->xusb_utmi_vbus_regs));
+       for (i = 0; i < XUSB_UTMI_COUNT; i++) {
+               struct regulator *reg = NULL;
+               const char *reg_name = supply->utmi_vbuses[i];
+               if (BIT(XUSB_UTMI_INDEX + i) & tegra->bdata->portmap) {
+                       if (i == 0 && tegra->transceiver)
+                               continue;
+                       reg = devm_regulator_get(&pdev->dev, reg_name);
+                       if (IS_ERR(reg)) {
+                               dev_err(&pdev->dev,
+                                       "%s regulator not found: %ld.",
+                                       reg_name, PTR_ERR(reg));
+                               err = PTR_ERR(reg);
+                       } else {
+                               err = regulator_enable(reg);
+                               if (err < 0) {
+                                       dev_err(&pdev->dev,
+                                       "%s: regulator enable failed: %d\n",
+                                       reg_name, err);
+                               }
+                       }
+                       if (err)
+                               goto err_put_utmi_vbus_reg;
                }
+               tegra->xusb_utmi_vbus_regs[i] = reg;
        }
 
        tegra->xusb_s1p8v_reg =
@@ -1332,13 +1544,13 @@ static int tegra_xusb_regulator_init(struct tegra_xhci_hcd *tegra,
                dev_err(&pdev->dev, "1p8v regulator not found: %ld."
                        , PTR_ERR(tegra->xusb_s1p8v_reg));
                err = PTR_ERR(tegra->xusb_s1p8v_reg);
-               goto err_put_s5p0v_reg;
+               goto err_put_utmi_vbus_reg;
        } else {
                err = regulator_enable(tegra->xusb_s1p8v_reg);
                if (err < 0) {
                        dev_err(&pdev->dev,
                        "1p8v: regulator enable failed:%d\n", err);
-                       goto err_put_s5p0v_reg;
+                       goto err_put_utmi_vbus_reg;
                }
        }
 
@@ -1358,56 +1570,20 @@ static int tegra_xusb_regulator_init(struct tegra_xhci_hcd *tegra,
                }
        }
 
-       if (tegra->bdata->uses_different_vbus_per_port) {
-               tegra->xusb_s5p0v1_reg = devm_regulator_get(&pdev->dev,
-                                               supply->s5p0v1);
-               if (IS_ERR(tegra->xusb_s5p0v1_reg)) {
-                       dev_err(&pdev->dev, "5p0v1 regulator not found: %ld."
-                               , PTR_ERR(tegra->xusb_s5p0v1_reg));
-                       err = PTR_ERR(tegra->xusb_s5p0v1_reg);
-                       goto err_put_s1p05v_reg;
-               } else {
-                       err = regulator_enable(tegra->xusb_s5p0v1_reg);
-                       if (err < 0) {
-                               dev_err(&pdev->dev,
-                               "5p0v1: regulator enable failed:%d\n", err);
-                               goto err_put_s1p05v_reg;
-                       }
-               }
-
-               tegra->xusb_s5p0v2_reg = devm_regulator_get(&pdev->dev,
-                                               supply->s5p0v2);
-               if (IS_ERR(tegra->xusb_s5p0v2_reg)) {
-                       dev_err(&pdev->dev, "5p0v2 regulator not found: %ld."
-                               , PTR_ERR(tegra->xusb_s5p0v2_reg));
-                       err = PTR_ERR(tegra->xusb_s5p0v2_reg);
-                       goto err_put_s1p5v1_reg;
-               } else {
-                       err = regulator_enable(tegra->xusb_s5p0v2_reg);
-                       if (err < 0) {
-                               dev_err(&pdev->dev,
-                               "5p0v2: regulator enable failed:%d\n", err);
-                               goto err_put_s1p5v1_reg;
-                       }
-               }
-       }
        return err;
 
-err_put_s1p5v1_reg:
-       if (tegra->bdata->uses_different_vbus_per_port)
-               regulator_disable(tegra->xusb_s5p0v1_reg);
-err_put_s1p05v_reg:
-       regulator_disable(tegra->xusb_s1p05v_reg);
 err_put_s1p8v_reg:
        regulator_disable(tegra->xusb_s1p8v_reg);
-err_put_s5p0v_reg:
-       regulator_disable(tegra->xusb_s5p0v_reg);
-err_put_s3p3v_reg:
+err_put_utmi_vbus_reg:
+       for (i = 0; i < XUSB_UTMI_COUNT; i++) {
+               struct regulator *reg = tegra->xusb_utmi_vbus_regs[i];
+               if (!IS_ERR_OR_NULL(reg))
+                       regulator_disable(reg);
+       }
        regulator_disable(tegra->xusb_s3p3v_reg);
 err_null_regulator:
-       tegra->xusb_s5p0v_reg = NULL;
-       tegra->xusb_s5p0v1_reg = NULL;
-       tegra->xusb_s5p0v2_reg = NULL;
+       for (i = 0; i < XUSB_UTMI_COUNT; i++)
+               tegra->xusb_utmi_vbus_regs[i] = NULL;
        tegra->xusb_s1p05v_reg = NULL;
        tegra->xusb_s3p3v_reg = NULL;
        tegra->xusb_s1p8v_reg = NULL;
@@ -1416,20 +1592,24 @@ err_null_regulator:
 
 static void tegra_xusb_regulator_deinit(struct tegra_xhci_hcd *tegra)
 {
+       int i;
+
        regulator_disable(tegra->xusb_s1p05v_reg);
        regulator_disable(tegra->xusb_s1p8v_reg);
-       regulator_disable(tegra->xusb_s5p0v_reg);
-       regulator_disable(tegra->xusb_s3p3v_reg);
-       if (tegra->bdata->uses_different_vbus_per_port) {
-               regulator_disable(tegra->xusb_s5p0v1_reg);
-               regulator_disable(tegra->xusb_s5p0v2_reg);
+
+       for (i = 0; i < XUSB_UTMI_COUNT; i++) {
+               if (BIT(XUSB_UTMI_INDEX + i) & tegra->bdata->portmap) {
+                       struct regulator *reg = tegra->xusb_utmi_vbus_regs[i];
+                       if (!IS_ERR_OR_NULL(reg))
+                               regulator_disable(reg);
+                       tegra->xusb_utmi_vbus_regs[i] = NULL;
+               }
        }
 
+       regulator_disable(tegra->xusb_s3p3v_reg);
+
        tegra->xusb_s1p05v_reg = NULL;
        tegra->xusb_s1p8v_reg = NULL;
-       tegra->xusb_s5p0v_reg = NULL;
-       tegra->xusb_s5p0v1_reg = NULL;
-       tegra->xusb_s5p0v2_reg = NULL;
        tegra->xusb_s3p3v_reg = NULL;
 }
 
@@ -1475,7 +1655,7 @@ static int tegra_xusb_partitions_clk_init(struct tegra_xhci_hcd *tegra)
                return PTR_ERR(tegra->emc_clk);
        }
 
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2) {
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2) {
                tegra->pll_re_vco_clk = devm_clk_get(&pdev->dev, "pll_re_vco");
                if (IS_ERR(tegra->pll_re_vco_clk)) {
                        dev_err(&pdev->dev, "Failed to get refPLLE clock\n");
@@ -1524,7 +1704,7 @@ static int tegra_xusb_partitions_clk_init(struct tegra_xhci_hcd *tegra)
                goto get_ss_clk_failed;
        }
 
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2) {
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2) {
                err = clk_enable(tegra->pll_re_vco_clk);
                if (err) {
                        dev_err(&pdev->dev, "Failed to enable refPLLE clk\n");
@@ -1549,7 +1729,7 @@ clk_get_clk_m_failed:
        tegra->pll_u_480M = NULL;
 
 get_pll_u_480M_failed:
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
                tegra->pll_re_vco_clk = NULL;
 
 get_pll_re_vco_clk_failed:
@@ -1562,14 +1742,14 @@ static void tegra_xusb_partitions_clk_deinit(struct tegra_xhci_hcd *tegra)
 {
        clk_disable(tegra->ss_clk);
        clk_disable(tegra->host_clk);
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
                clk_disable(tegra->pll_re_vco_clk);
        tegra->ss_clk = NULL;
        tegra->host_clk = NULL;
        tegra->ss_src_clk = NULL;
        tegra->clk_m = NULL;
        tegra->pll_u_480M = NULL;
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
                tegra->pll_re_vco_clk = NULL;
 }
 
@@ -1641,8 +1821,8 @@ tegra_xusb_request_clk_rate(struct tegra_xhci_hcd *tegra,
        int fw_req_rate = rate, cur_rate;
 
        /* Do not handle clock change as needed for HS disconnect issue */
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2) {
-               *sw_resp = fw_req_rate | (MBOX_CMD_ACK << MBOX_CMD_SHIFT);
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2) {
+               *sw_resp = CMD_DATA(fw_req_rate) | CMD_TYPE(MBOX_CMD_ACK);
                return ret;
        }
 
@@ -1656,7 +1836,7 @@ tegra_xusb_request_clk_rate(struct tegra_xhci_hcd *tegra,
 
        if (fw_req_rate == cur_rate) {
                cmd_ack = MBOX_CMD_ACK;
-               *sw_resp = fw_req_rate;
+
        } else {
 
                if (clk_handle == tegra->ss_src_clk && fw_req_rate == 12000) {
@@ -1676,20 +1856,27 @@ tegra_xusb_request_clk_rate(struct tegra_xhci_hcd *tegra,
                        tegra_xhci_rx_idle_mode_override(tegra, false);
                }
 
-               *sw_resp = clk_get_rate(clk_handle);
-               *sw_resp /= 1000;
+               cur_rate = (clk_get_rate(clk_handle) / 1000);
 
-               if (*sw_resp != fw_req_rate) {
+               if (cur_rate != fw_req_rate) {
                        xhci_err(tegra->xhci, "cur_rate=%d, fw_req_rate=%d\n",
                                cur_rate, fw_req_rate);
                        cmd_ack = MBOX_CMD_NACK;
                }
        }
-       *sw_resp |= (cmd_ack << MBOX_CMD_SHIFT);
+       *sw_resp = CMD_DATA(cur_rate) | CMD_TYPE(cmd_ack);
        return ret;
 }
 
-static void tegra_xhci_save_dfe_ctle_context(struct tegra_xhci_hcd *tegra,
+static void tegra_xusb_set_bw(struct tegra_xhci_hcd *tegra, unsigned int bw)
+{
+       unsigned int freq_khz;
+
+       freq_khz = tegra_emc_bw_to_freq_req(bw);
+       clk_set_rate(tegra->emc_clk, freq_khz * 1000);
+}
+
+static void tegra_xhci_save_dfe_context(struct tegra_xhci_hcd *tegra,
        u8 port)
 {
        struct xhci_hcd *xhci = tegra->xhci;
@@ -1697,86 +1884,155 @@ static void tegra_xhci_save_dfe_ctle_context(struct tegra_xhci_hcd *tegra,
        u32 offset;
        u32 reg;
 
-       xhci_info(xhci, "saving dfe_cntl and ctle context for port %d\n", port);
+       if (port > (XUSB_SS_PORT_COUNT - 1)) {
+               pr_err("%s invalid SS port number %u\n", __func__, port);
+               return;
+       }
+
+       xhci_info(xhci, "saving restore DFE context for port %d\n", port);
 
        /* if port1 is mapped to SATA lane then read from SATA register */
        if (port == 1 && XUSB_DEVICE_ID_T114 != tegra->device_id &&
                        tegra->bdata->lane_owner & BIT(0))
                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;
+               offset = MISC_PAD_CTL_6_0(port);
 
-       /* save tap1_val[] for the port for dfe_cntl */
+       /*
+        * Value set to IOPHY_MISC_PAD_x_CTL_6 where x P0/P1/S0/ is from,
+        * T114 refer PG USB3_FW_Programming_Guide_Host.doc section 14.3.10
+        * T124 refer PG T124_USB3_FW_Programming_Guide_Host.doc section 14.3.10
+        */
        reg = readl(tegra->padctl_base + offset);
-       reg &= ~(0xff << 16);
-       reg |= (0x32 << 16);
+       reg &= ~MISC_OUT_SEL(~0);
+       reg |= MISC_OUT_SEL(0x32);
        writel(reg, tegra->padctl_base + offset);
 
        reg = readl(tegra->padctl_base + offset);
-       tegra->sregs.tap1_val[port] = ((reg & (0x1f << 24)) >> 24);
+       tegra->sregs.tap1_val[port] = MISC_OUT_TAP_VAL(reg);
 
-       /* save amp_val[] for the port for dfe_cntl */
        reg = readl(tegra->padctl_base + offset);
-       reg &= ~(0xff << 16);
-       reg |= (0x33 << 16);
+       reg &= ~MISC_OUT_SEL(~0);
+       reg |= MISC_OUT_SEL(0x33);
        writel(reg, tegra->padctl_base + offset);
 
        reg = readl(tegra->padctl_base + offset);
-       tegra->sregs.amp_val[port] = ((reg & (0x7f << 24)) >> 24);
+       tegra->sregs.amp_val[port] = MISC_OUT_AMP_VAL(reg);
+
+       reg = readl(tegra->padctl_base + USB3_PAD_CTL_4_0(port));
+       reg &= ~DFE_CNTL_TAP_VAL(~0);
+       reg |= DFE_CNTL_TAP_VAL(tegra->sregs.tap1_val[port]);
+       writel(reg, tegra->padctl_base + USB3_PAD_CTL_4_0(port));
+
+       reg = readl(tegra->padctl_base + USB3_PAD_CTL_4_0(port));
+       reg &= ~DFE_CNTL_AMP_VAL(~0);
+       reg |= DFE_CNTL_AMP_VAL(tegra->sregs.amp_val[port]);
+       writel(reg, tegra->padctl_base + USB3_PAD_CTL_4_0(port));
+
+       tegra->dfe_ctx_saved[port] = true;
+}
+
+static void save_ctle_context(struct tegra_xhci_hcd *tegra,
+       u8 port)
+{
+       struct xhci_hcd *xhci = tegra->xhci;
+       struct tegra_xusb_padctl_regs *padregs = tegra->padregs;
+       u32 offset;
+       u32 reg;
+
+       if (port > (XUSB_SS_PORT_COUNT - 1)) {
+               pr_err("%s invalid SS port number %u\n", __func__, port);
+               return;
+       }
+
+       xhci_info(xhci, "saving restore CTLE context for port %d\n", port);
+
+       /* if port1 is mapped to SATA lane then read from SATA register */
+       if (port == 1 && XUSB_DEVICE_ID_T114 != tegra->device_id &&
+                       tegra->bdata->lane_owner & BIT(0))
+               offset = padregs->iophy_misc_pad_s0_ctl6_0;
+       else
+               offset = MISC_PAD_CTL_6_0(port);
+
+       /*
+        * Value set to IOPHY_MISC_PAD_x_CTL_6 where x P0/P1/S0/ is from,
+        * T114 refer PG USB3_FW_Programming_Guide_Host.doc section 14.3.10
+        * T124 refer PG T124_USB3_FW_Programming_Guide_Host.doc section 14.3.10
+        */
+       reg = readl(tegra->padctl_base + offset);
+       reg &= ~MISC_OUT_SEL(~0);
+       reg |= MISC_OUT_SEL(0xa1);
+       writel(reg, tegra->padctl_base + offset);
 
-       /* save ctle_z_val[] for the port for ctle */
        reg = readl(tegra->padctl_base + offset);
-       reg &= ~(0xff << 16);
-       reg |= (0x20 << 16);
+       reg &= ~MISC_OUT_SEL(~0);
+       reg |= MISC_OUT_SEL(0x21);
        writel(reg, tegra->padctl_base + offset);
 
        reg = readl(tegra->padctl_base + offset);
-       tegra->sregs.ctle_z_val[port] = ((reg & (0x3f << 24)) >> 24);
+       tegra->sregs.ctle_g_val[port] = MISC_OUT_G_Z_VAL(reg);
 
-       /* save ctle_g_val[] for the port for ctle */
        reg = readl(tegra->padctl_base + offset);
-       reg &= ~(0xff << 16);
-       reg |= (0x21 << 16);
+       reg &= ~MISC_OUT_SEL(~0);
+       reg |= MISC_OUT_SEL(0x48);
        writel(reg, tegra->padctl_base + offset);
 
        reg = readl(tegra->padctl_base + offset);
-       tegra->sregs.ctle_g_val[port] = ((reg & (0x3f << 24)) >> 24);
-       tegra->dfe_ctle_ctx_saved = true;
+       tegra->sregs.ctle_z_val[port] = MISC_OUT_G_Z_VAL(reg);
+
+       reg = readl(tegra->padctl_base + USB3_PAD_CTL_2_0(port));
+       reg &= ~RX_EQ_Z_VAL(~0);
+       reg |= RX_EQ_Z_VAL(tegra->sregs.ctle_z_val[port]);
+       writel(reg, tegra->padctl_base + USB3_PAD_CTL_2_0(port));
+
+       reg = readl(tegra->padctl_base + USB3_PAD_CTL_2_0(port));
+       reg &= ~RX_EQ_G_VAL(~0);
+       reg |= RX_EQ_G_VAL(tegra->sregs.ctle_g_val[port]);
+       writel(reg, tegra->padctl_base + USB3_PAD_CTL_2_0(port));
+
+       tegra->ctle_ctx_saved[port] = true;
 }
 
-static void tegra_xhci_restore_dfe_ctle_context(struct tegra_xhci_hcd *tegra,
+static void tegra_xhci_restore_dfe_context(struct tegra_xhci_hcd *tegra,
        u8 port)
 {
        struct xhci_hcd *xhci = tegra->xhci;
-       struct tegra_xusb_padctl_regs *padregs = tegra->padregs;
-       u32 ctl4_offset, ctl2_offset;
        u32 reg;
 
        /* don't restore if not saved */
-       if (tegra->dfe_ctle_ctx_saved == false)
+       if (tegra->dfe_ctx_saved[port] == false)
                return;
 
-       ctl4_offset = port ? padregs->iophy_usb3_pad1_ctl4_0 :
-                       padregs->iophy_usb3_pad0_ctl4_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);
+       xhci_info(xhci, "restoring dfe context of port %d\n", port);
 
        /* restore dfe_cntl for the port */
-       reg = readl(tegra->padctl_base + ctl4_offset);
-       reg &= ~((0x7f << 16) | (0x1f << 24));
-       reg |= ((tegra->sregs.amp_val[port] << 16) |
-               (tegra->sregs.tap1_val[port] << 24));
-       writel(reg, tegra->padctl_base + ctl4_offset);
+       reg = readl(tegra->padctl_base + USB3_PAD_CTL_4_0(port));
+       reg &= ~(DFE_CNTL_AMP_VAL(~0) |
+                       DFE_CNTL_TAP_VAL(~0));
+       reg |= DFE_CNTL_AMP_VAL(tegra->sregs.amp_val[port]) |
+               DFE_CNTL_TAP_VAL(tegra->sregs.tap1_val[port]);
+       writel(reg, tegra->padctl_base + USB3_PAD_CTL_4_0(port));
+}
+
+void restore_ctle_context(struct tegra_xhci_hcd *tegra,
+       u8 port)
+{
+       struct xhci_hcd *xhci = tegra->xhci;
+       u32 reg;
+
+       /* don't restore if not saved */
+       if (tegra->ctle_ctx_saved[port] == false)
+               return;
+
+       xhci_info(xhci, "restoring CTLE context of port %d\n", port);
 
        /* restore ctle for the port */
-       reg = readl(tegra->padctl_base + ctl2_offset);
-       reg &= ~((0x3f << 8) | (0x3f << 16));
-       reg |= ((tegra->sregs.ctle_g_val[port] << 8) |
-               (tegra->sregs.ctle_z_val[port] << 16));
-       writel(reg, tegra->padctl_base + ctl2_offset);
+       reg = readl(tegra->padctl_base + USB3_PAD_CTL_2_0(port));
+       reg &= ~(RX_EQ_Z_VAL(~0) |
+                       RX_EQ_G_VAL(~0));
+       reg |= (RX_EQ_Z_VAL(tegra->sregs.ctle_z_val[port]) |
+               RX_EQ_G_VAL(tegra->sregs.ctle_g_val[port]));
+       writel(reg, tegra->padctl_base + USB3_PAD_CTL_2_0(port));
 }
 
 static void tegra_xhci_program_ulpi_pad(struct tegra_xhci_hcd *tegra,
@@ -1853,13 +2109,13 @@ static void tegra_xhci_program_utmip_pad(struct tegra_xhci_hcd *tegra,
                USB2_OTG_FS_SLEW | USB2_OTG_LS_RSLEW |
                USB2_OTG_PD | USB2_OTG_PD2 | USB2_OTG_PD_ZI);
 
-       reg |= tegra->pdata->hs_slew;
-       reg |= (port == 2) ? tegra->pdata->ls_rslew_pad2 :
-                       port ? tegra->pdata->ls_rslew_pad1 :
-                       tegra->pdata->ls_rslew_pad0;
-       reg |= (port == 2) ? tegra->pdata->hs_curr_level_pad2 :
-                       port ? tegra->pdata->hs_curr_level_pad1 :
-                       tegra->pdata->hs_curr_level_pad0;
+       reg |= tegra->soc_config->hs_slew;
+       reg |= (port == 2) ? tegra->soc_config->ls_rslew_pad2 :
+                       port ? tegra->soc_config->ls_rslew_pad1 :
+                       tegra->soc_config->ls_rslew_pad0;
+       reg |= (port == 2) ? tegra->cdata->hs_curr_level_pad2 :
+                       port ? tegra->cdata->hs_curr_level_pad1 :
+                       tegra->cdata->hs_curr_level_pad0;
        writel(reg, tegra->padctl_base + ctl0_offset);
 
        reg = readl(tegra->padctl_base + ctl1_offset);
@@ -1867,9 +2123,21 @@ static void tegra_xhci_program_utmip_pad(struct tegra_xhci_hcd *tegra,
                | USB2_OTG_PD_CHRP_FORCE_POWERUP
                | USB2_OTG_PD_DISC_FORCE_POWERUP
                | USB2_OTG_PD_DR);
-       reg |= (tegra->pdata->hs_iref_cap << 9) |
-               (tegra->pdata->hs_term_range_adj << 3);
+       reg |= (tegra->cdata->hs_iref_cap << 9) |
+               (tegra->cdata->hs_term_range_adj << 3);
        writel(reg, tegra->padctl_base + ctl1_offset);
+
+       /*Release OTG port if not in host mode*/
+
+       if ((port == 0) && !is_otg_host(tegra))
+               tegra_xhci_release_otg_port(true);
+}
+
+static inline bool xusb_use_sata_lane(struct tegra_xhci_hcd *tegra)
+{
+       return ((XUSB_DEVICE_ID_T114 == tegra->device_id) ? false
+       : ((tegra->bdata->portmap & TEGRA_XUSB_SS_P1)
+               && (tegra->bdata->lane_owner & BIT(0))));
 }
 
 static void tegra_xhci_program_ss_pad(struct tegra_xhci_hcd *tegra,
@@ -1889,25 +2157,50 @@ static void tegra_xhci_program_ss_pad(struct tegra_xhci_hcd *tegra,
        reg = readl(tegra->padctl_base + ctl2_offset);
        reg &= ~(IOPHY_USB3_RXWANDER | IOPHY_USB3_RXEQ |
                IOPHY_USB3_CDRCNTL);
-       reg |= tegra->pdata->rx_wander | tegra->pdata->rx_eq |
-               tegra->pdata->cdr_cntl;
+       reg |= tegra->soc_config->rx_wander | tegra->soc_config->rx_eq |
+               tegra->soc_config->cdr_cntl;
        writel(reg, tegra->padctl_base + ctl2_offset);
 
        reg = readl(tegra->padctl_base + ctl4_offset);
-       reg = tegra->pdata->dfe_cntl;
+       reg = tegra->soc_config->dfe_cntl;
        writel(reg, tegra->padctl_base + ctl4_offset);
 
        reg = readl(tegra->padctl_base + ctl5_offset);
        reg |= RX_QEYE_EN;
        writel(reg, tegra->padctl_base + ctl5_offset);
 
+       reg = readl(tegra->padctl_base + MISC_PAD_CTL_2_0(port));
+       reg &= ~SPARE_IN(~0);
+       reg |= SPARE_IN(tegra->soc_config->spare_in);
+       writel(reg, tegra->padctl_base + MISC_PAD_CTL_2_0(port));
+
+       if (xusb_use_sata_lane(tegra)) {
+               reg = readl(tegra->padctl_base + MISC_PAD_S0_CTL_5_0);
+               reg |= RX_QEYE_EN;
+               writel(reg, tegra->padctl_base + MISC_PAD_S0_CTL_5_0);
+
+               reg = readl(tegra->padctl_base + MISC_PAD_S0_CTL_2_0);
+               reg &= ~SPARE_IN(~0);
+               reg |= SPARE_IN(tegra->soc_config->spare_in);
+               writel(reg, tegra->padctl_base + MISC_PAD_S0_CTL_2_0);
+       }
+
        reg = readl(tegra->padctl_base + padregs->ss_port_map_0);
        reg &= ~(port ? SS_PORT_MAP_P1 : SS_PORT_MAP_P0);
        reg |= (tegra->bdata->ss_portmap &
                (port ? TEGRA_XUSB_SS1_PORT_MAP : TEGRA_XUSB_SS0_PORT_MAP));
        writel(reg, tegra->padctl_base + padregs->ss_port_map_0);
 
-       tegra_xhci_restore_dfe_ctle_context(tegra, port);
+       /* Make sure the SS port capability set correctly */
+       reg = readl(tegra->padctl_base + padregs->usb2_port_cap_0);
+       reg &= ~USB2_PORT_CAP_MASK(
+                       GET_SS_PORTMAP(tegra->bdata->ss_portmap, port));
+       reg |= USB2_PORT_CAP_HOST(
+                       GET_SS_PORTMAP(tegra->bdata->ss_portmap, port));
+       writel(reg, tegra->padctl_base + padregs->usb2_port_cap_0);
+
+       tegra_xhci_restore_dfe_context(tegra, port);
+       tegra_xhci_restore_ctle_context(tegra, port);
 }
 
 /* This function assigns the USB ports to the controllers,
@@ -1923,7 +2216,7 @@ tegra_xhci_padctl_portmap_and_caps(struct tegra_xhci_hcd *tegra)
 
        reg = readl(tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
        reg &= ~(USB2_BIAS_HS_SQUELCH_LEVEL | USB2_BIAS_HS_DISCON_LEVEL);
-       reg |= tegra->pdata->hs_squelch_level | tegra->pdata->hs_disc_lvl;
+       reg |= tegra->cdata->hs_squelch_level | tegra->soc_config->hs_disc_lvl;
        writel(reg, tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
 
        reg = readl(tegra->padctl_base + padregs->snps_oc_map_0);
@@ -1970,10 +2263,8 @@ tegra_xhci_padctl_portmap_and_caps(struct tegra_xhci_hcd *tegra)
        if (tegra->bdata->portmap & TEGRA_XUSB_USB2_P2)
                tegra_xhci_program_utmip_pad(tegra, 2);
 
-       for (pad = 0; pad < XUSB_HSIC_COUNT; pad++) {
-               if (BIT(XUSB_HSIC_INDEX + pad) & tegra->bdata->portmap)
-                       hsic_pad_enable(tegra, pad);
-       }
+       for_each_enabled_hsic_pad(pad, tegra)
+               hsic_pad_enable(tegra, pad);
 
        if (tegra->bdata->portmap & TEGRA_XUSB_ULPI_P0)
                tegra_xhci_program_ulpi_pad(tegra, 0);
@@ -2151,32 +2442,7 @@ tegra_xhci_restore_ctx(struct tegra_xhci_hcd *tegra)
 
 static void tegra_xhci_enable_fw_message(struct tegra_xhci_hcd *tegra)
 {
-       struct platform_device *pdev = tegra->pdev;
-       u32 reg, timeout = 0xff, cmd;
-
-       mutex_lock(&tegra->mbox_lock);
-
-       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)) {
-               dev_err(&pdev->dev, "Failed to set mbox message owner ID\n");
-               mutex_unlock(&tegra->mbox_lock);
-               return;
-       }
-
-       writel((MBOX_CMD_MSG_ENABLED << MBOX_CMD_SHIFT),
-                       tegra->fpci_base + XUSB_CFG_ARU_MBOX_DATA_IN);
-
-       cmd = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
-       cmd |= MBOX_INT_EN | MBOX_FALC_INT_EN;
-       writel(cmd, tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
-
-       mutex_unlock(&tegra->mbox_lock);
+       fw_message_send(tegra, MBOX_CMD_MSG_ENABLED, 0 /* no data needed */);
 }
 
 static int load_firmware(struct tegra_xhci_hcd *tegra, bool resetARU)
@@ -2192,10 +2458,12 @@ static int load_firmware(struct tegra_xhci_hcd *tegra, bool resetARU)
        u32 usbsts, count = 0xff;
        struct xhci_cap_regs __iomem *cap_regs;
        struct xhci_op_regs __iomem *op_regs;
+       int pad;
 
-       /* enable mbox interrupt */
-       writel(readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD) | MBOX_INT_EN,
-               tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
+       /* Program SS port map config */
+       cfg_tbl->ss_portmap = 0x0;
+       cfg_tbl->ss_portmap |=
+               (tegra->bdata->portmap & ((1 << XUSB_SS_PORT_COUNT) - 1));
 
        /* First thing, reset the ARU. By the time we get to
         * loading boot code below, reset would be complete.
@@ -2280,6 +2548,10 @@ static int load_firmware(struct tegra_xhci_hcd *tegra, bool resetARU)
                fw_tm.tm_min, fw_tm.tm_sec,
                csb_read(tegra, XUSB_FALC_CPUCTL));
 
+       cfg_tbl->num_hsic_port = 0;
+       for_each_enabled_hsic_pad(pad, tegra)
+               cfg_tbl->num_hsic_port++;
+
        dev_dbg(&pdev->dev, "num_hsic_port %d\n", cfg_tbl->num_hsic_port);
 
        /* return fail if firmware status is not good */
@@ -2299,14 +2571,8 @@ static int load_firmware(struct tegra_xhci_hcd *tegra, bool resetARU)
                dev_err(&pdev->dev, "Controller not ready\n");
                return -EFAULT;
        }
-
-       /* TODO move this into firmware to avoid race */
-       writel(0x0, tegra->fpci_base + XUSB_CFG_ARU_C11PAGESEL0);
-       writel(0x1000, tegra->fpci_base + XUSB_CFG_ARU_C11PAGESEL1);
-       writel(0x10, tegra->fpci_base + XUSB_CFG_HSPX_CORE_HSICWRAP);
-       reg_dump(&pdev->dev, tegra->fpci_base, XUSB_CFG_ARU_C11PAGESEL0);
-       reg_dump(&pdev->dev, tegra->fpci_base, XUSB_CFG_ARU_C11PAGESEL1);
-       reg_dump(&pdev->dev, tegra->fpci_base, XUSB_CFG_HSPX_CORE_HSICWRAP);
+       for_each_enabled_hsic_pad(pad, tegra)
+               hsic_pad_pupd_set(tegra, pad, PUPD_IDLE);
 
        return 0;
 }
@@ -2327,7 +2593,8 @@ static void tegra_xhci_release_port_ownership(struct tegra_xhci_hcd *tegra,
 
        if (!release) {
                if (tegra->bdata->portmap & TEGRA_XUSB_USB2_P0)
-                       reg |= USB2_OTG_PAD_PORT_OWNER_XUSB(0);
+                       if (is_otg_host(tegra))
+                               reg |= USB2_OTG_PAD_PORT_OWNER_XUSB(0);
                if (tegra->bdata->portmap & TEGRA_XUSB_USB2_P1)
                        reg |= USB2_OTG_PAD_PORT_OWNER_XUSB(1);
                if (tegra->bdata->portmap & TEGRA_XUSB_USB2_P2)
@@ -2344,6 +2611,9 @@ static int tegra_xhci_ss_elpg_entry(struct tegra_xhci_hcd *tegra)
 
        must_have_sync_lock(tegra);
 
+       /* update maximum BW requirement to 0 */
+       tegra_xusb_set_bw(tegra, 0);
+
        /* This is SS partition ELPG entry
         * STEP 0: firmware will set WOC WOD bits in PVTPORTSC2 regs.
         */
@@ -2428,25 +2698,12 @@ static int tegra_xhci_host_elpg_entry(struct tegra_xhci_hcd *tegra)
        /* calculate rctrl_val and tctrl_val */
        tegra_xhci_war_for_tctrl_rctrl(tegra);
 
-       pmc_setup(tegra, 1);
        pmc_setup_wake_detect(tegra);
 
        tegra_xhci_hs_wake_on_interrupts(tegra->bdata->portmap, true);
        xhci_dbg(xhci, "%s: PMC_UTMIP_UHSIC_SLEEP_CFG_0 = %x\n", __func__,
                tegra_usb_pmc_reg_read(PMC_UTMIP_UHSIC_SLEEP_CFG_0));
 
-       /* STEP 4: Assert reset to host clk and disable host clk */
-       tegra_periph_reset_assert(tegra->host_clk);
-
-       clk_disable(tegra->host_clk);
-
-       /* wait 150us */
-       usleep_range(150, 200);
-
-       /* flush MC client of XUSB_HOST */
-       tegra_powergate_mc_flush(TEGRA_POWERGATE_XUSBC);
-
-       /* STEP 4: Powergate host partition */
        /* tegra_powergate_partition also does partition reset assert */
        ret = tegra_powergate_partition(TEGRA_POWERGATE_XUSBC);
        if (ret) {
@@ -2456,8 +2713,9 @@ static int tegra_xhci_host_elpg_entry(struct tegra_xhci_hcd *tegra)
                return ret;
        }
        tegra->host_pwr_gated = true;
+       clk_disable(tegra->host_clk);
 
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
                clk_disable(tegra->pll_re_vco_clk);
        clk_disable(tegra->emc_clk);
        /* set port ownership to SNPS */
@@ -2547,10 +2805,11 @@ static void ss_partition_elpg_exit_work(struct work_struct *work)
 }
 
 /* read pmc WAKE2_STATUS register to know if SS port caused remote wake */
-static void update_remote_wakeup_ports_pmc(struct tegra_xhci_hcd *tegra)
+static void update_remote_wakeup_ports(struct tegra_xhci_hcd *tegra)
 {
        struct xhci_hcd *xhci = tegra->xhci;
        u32 wake2_status;
+       int port;
 
 #define PMC_WAKE2_STATUS       0x168
 #define PADCTL_WAKE            (1 << (58 - 32)) /* PADCTL is WAKE#58 */
@@ -2564,6 +2823,15 @@ static void update_remote_wakeup_ports_pmc(struct tegra_xhci_hcd *tegra)
                tegra_usb_pmc_reg_write(PMC_WAKE2_STATUS, PADCTL_WAKE);
        }
 
+       /* set all usb2 ports with RESUME link state as wakup ports  */
+       for (port = 0; port < xhci->num_usb2_ports; port++) {
+               u32 portsc = xhci_readl(xhci, xhci->usb2_ports[port]);
+               if ((portsc & PORT_PLS_MASK) == XDEV_RESUME)
+                       set_bit(port, &tegra->usb2_rh_remote_wakeup_ports);
+       }
+
+       xhci_dbg(xhci, "%s: usb2 roothub remote_wakeup_ports 0x%lx\n",
+                       __func__, tegra->usb2_rh_remote_wakeup_ports);
        xhci_dbg(xhci, "%s: usb3 roothub remote_wakeup_ports 0x%lx\n",
                        __func__, tegra->usb3_rh_remote_wakeup_ports);
 }
@@ -2578,18 +2846,26 @@ static void wait_remote_wakeup_ports(struct usb_hcd *hcd)
        __le32 __iomem  **port_array;
        unsigned char *rh;
        unsigned int retry = 64;
+       struct xhci_bus_state *bus_state;
 
+       bus_state = &xhci->bus_state[hcd_index(hcd)];
 
        if (hcd == xhci->shared_hcd) {
                port_array = xhci->usb3_ports;
                num_ports = xhci->num_usb3_ports;
                remote_wakeup_ports = &tegra->usb3_rh_remote_wakeup_ports;
                rh = "usb3 roothub";
-       } else
-               return;
+       } else {
+               port_array = xhci->usb2_ports;
+               num_ports = xhci->num_usb2_ports;
+               remote_wakeup_ports = &tegra->usb2_rh_remote_wakeup_ports;
+               rh = "usb2 roothub";
+       }
 
        while (*remote_wakeup_ports && retry--) {
                for_each_set_bit(port, remote_wakeup_ports, num_ports) {
+                       bool can_continue;
+
                        portsc = xhci_readl(xhci, port_array[port]);
 
                        if (!(portsc & PORT_CONNECT)) {
@@ -2598,11 +2874,23 @@ static void wait_remote_wakeup_ports(struct usb_hcd *hcd)
                                continue;
                        }
 
-                       if ((portsc & PORT_PLS_MASK) == XDEV_U0)
+                       if (hcd == xhci->shared_hcd) {
+                               can_continue =
+                                       (portsc & PORT_PLS_MASK) == XDEV_U0;
+                       } else {
+                               unsigned long flags;
+
+                               spin_lock_irqsave(&xhci->lock, flags);
+                               can_continue =
+                               test_bit(port, &bus_state->resuming_ports);
+                               spin_unlock_irqrestore(&xhci->lock, flags);
+                       }
+
+                       if (can_continue)
                                clear_bit(port, remote_wakeup_ports);
                        else
                                xhci_dbg(xhci, "%s: %s port %d status 0x%x\n",
-                                               __func__, rh, port, portsc);
+                                       __func__, rh, port, portsc);
                }
 
                if (*remote_wakeup_ports)
@@ -2651,11 +2939,11 @@ static void tegra_xhci_war_for_tctrl_rctrl(struct tegra_xhci_hcd *tegra)
                 * tctrl_val = 0x1f - (16 - ffz(utmip_tctrl_val)
                 * rctrl_val = 0x1f - (16 - ffz(utmip_rctrl_val)
                 */
-               pmc_data.utmip_rctrl_val = 0xf + ffz(utmip_rctrl_val);
-               pmc_data.utmip_tctrl_val = 0xf + ffz(utmip_tctrl_val);
-
+               utmip_rctrl_val = 0xf + ffz(utmip_rctrl_val);
+               utmip_tctrl_val = 0xf + ffz(utmip_tctrl_val);
+               utmi_phy_update_trking_data(utmip_tctrl_val, utmip_rctrl_val);
                xhci_dbg(tegra->xhci, "rctrl_val = 0x%x, tctrl_val = 0x%x\n",
-                       pmc_data.utmip_rctrl_val, pmc_data.utmip_tctrl_val);
+                                       utmip_rctrl_val, utmip_tctrl_val);
 
                /* XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0::PD = 1 and
                 * XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0::PD_TRK = 1
@@ -2665,17 +2953,17 @@ static void tegra_xhci_war_for_tctrl_rctrl(struct tegra_xhci_hcd *tegra)
                writel(reg, tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
 
                /* Program these values into PMC regiseter and program the
-                * PMC override
+                * PMC override.
                 */
-               reg = PMC_TCTRL_VAL(pmc_data.utmip_tctrl_val) |
-                       PMC_RCTRL_VAL(pmc_data.utmip_rctrl_val);
+               reg = PMC_TCTRL_VAL(utmip_tctrl_val) |
+                               PMC_RCTRL_VAL(utmip_rctrl_val);
                tegra_usb_pmc_reg_update(PMC_UTMIP_TERM_PAD_CFG,
-                       0xffffffff, reg);
-
+                                       0xffffffff, reg);
                reg = UTMIP_RCTRL_USE_PMC_P2 | UTMIP_TCTRL_USE_PMC_P2;
                tegra_usb_pmc_reg_update(PMC_SLEEP_CFG, reg, reg);
        } else {
-               /* TODO use common PMC API to use SNPS register space */
+               /* Use common PMC API to use SNPS register space */
+               utmi_phy_set_snps_trking_data();
        }
 }
 
@@ -2701,7 +2989,7 @@ tegra_xhci_host_partition_elpg_exit(struct tegra_xhci_hcd *tegra)
                return 0;
 
        clk_enable(tegra->emc_clk);
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
                clk_enable(tegra->pll_re_vco_clk);
 
        if (tegra->lp0_exit) {
@@ -2794,6 +3082,7 @@ tegra_xhci_host_partition_elpg_exit(struct tegra_xhci_hcd *tegra)
                        csb_read(tegra, XUSB_FALC_FS_PVTPORTSC3));
        debug_print_portsc(xhci);
 
+       tegra_xhci_enable_fw_message(tegra);
        ret = load_firmware(tegra, false /* EPLG exit, do not reset ARU */);
        if (ret < 0) {
                xhci_err(xhci, "%s: failed to load firmware %d\n",
@@ -2801,7 +3090,6 @@ tegra_xhci_host_partition_elpg_exit(struct tegra_xhci_hcd *tegra)
                goto out;
        }
 
-       pmc_setup(tegra, 0);
        pmc_disable_bus_ctrl(tegra);
 
        tegra->hc_in_elpg = false;
@@ -2812,7 +3100,7 @@ tegra_xhci_host_partition_elpg_exit(struct tegra_xhci_hcd *tegra)
                goto out;
        }
 
-       update_remote_wakeup_ports_pmc(tegra);
+       update_remote_wakeup_ports(tegra);
 
        if (tegra->hs_wake_event)
                tegra->hs_wake_event = false;
@@ -2858,28 +3146,26 @@ tegra_xhci_process_mbox_message(struct work_struct *work)
        struct tegra_xhci_hcd *tegra = container_of(work, struct tegra_xhci_hcd,
                                        mbox_work);
        struct xhci_hcd *xhci = tegra->xhci;
-       unsigned int freq_khz;
        int pad, port;
        unsigned long ports;
+       enum MBOX_CMD_TYPE response;
 
        mutex_lock(&tegra->mbox_lock);
 
-       /* get the owner id */
-       tegra->mbox_owner = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
-       tegra->mbox_owner &= MBOX_OWNER_ID_MASK;
-
        /* get the mbox message from firmware */
        fw_msg = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_DATA_OUT);
 
        data_in = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_DATA_IN);
        if (data_in) {
+               dev_warn(&tegra->pdev->dev, "%s data_in 0x%x\n",
+                       __func__, data_in);
                mutex_unlock(&tegra->mbox_lock);
                return;
        }
 
        /* get cmd type and cmd data */
-       tegra->cmd_type = (fw_msg & MBOX_CMD_TYPE_MASK) >> MBOX_CMD_SHIFT;
-       tegra->cmd_data = (fw_msg & MBOX_CMD_DATA_MASK);
+       tegra->cmd_type = (fw_msg >> CMD_TYPE_SHIFT) & CMD_TYPE_MASK;
+       tegra->cmd_data = (fw_msg >> CMD_DATA_SHIFT) & CMD_DATA_MASK;
 
        /* decode the message and make appropriate requests to
         * clock or powergating module.
@@ -2908,28 +3194,23 @@ tegra_xhci_process_mbox_message(struct work_struct *work)
                        xhci_err(xhci, "%s: could not set required ss rate.\n",
                                __func__);
                goto send_sw_response;
+
        case MBOX_CMD_SET_BW:
                /* fw sends BW request in MByte/sec */
-               freq_khz = tegra_emc_bw_to_freq_req(tegra->cmd_data << 10);
-               clk_set_rate(tegra->emc_clk, freq_khz * 1000);
-
-               /* clear MBOX_SMI_INT_EN bit */
-               cmd = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
-               cmd &= ~MBOX_SMI_INT_EN;
-               writel(cmd, tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
-
-               /* clear mbox owner as ACK will not be sent for this request */
-               writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
+               mutex_lock(&tegra->sync_lock);
+               tegra_xusb_set_bw(tegra, tegra->cmd_data << 10);
+               mutex_unlock(&tegra->sync_lock);
                break;
+
        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);
-               sw_resp |= tegra->cmd_data | (MBOX_CMD_ACK << MBOX_CMD_SHIFT);
+               tegra_xhci_save_dfe_context(tegra, tegra->cmd_data);
+               tegra_xhci_save_ctle_context(tegra, tegra->cmd_data);
+               sw_resp = CMD_DATA(tegra->cmd_data) | CMD_TYPE(MBOX_CMD_ACK);
                goto send_sw_response;
 
        case MBOX_CMD_STAR_HSIC_IDLE:
-               ports = sw_resp = tegra->cmd_data;
-               for_each_set_bit(port, &ports, MBOX_CMD_SHIFT) {
+               ports = tegra->cmd_data;
+               for_each_set_bit(port, &ports, BITS_PER_LONG) {
                        pad = port_to_hsic_pad(port - 1);
                        mutex_lock(&tegra->sync_lock);
                        ret = hsic_pad_pupd_set(tegra, pad, PUPD_IDLE);
@@ -2938,16 +3219,17 @@ tegra_xhci_process_mbox_message(struct work_struct *work)
                                break;
                }
 
+               sw_resp = CMD_DATA(tegra->cmd_data);
                if (!ret)
-                       sw_resp |= (MBOX_CMD_ACK << MBOX_CMD_SHIFT);
+                       sw_resp |= CMD_TYPE(MBOX_CMD_ACK);
                else
-                       sw_resp |= (MBOX_CMD_NACK << MBOX_CMD_SHIFT);
+                       sw_resp |= CMD_TYPE(MBOX_CMD_NACK);
 
                goto send_sw_response;
 
        case MBOX_CMD_STOP_HSIC_IDLE:
-               ports = sw_resp = tegra->cmd_data;
-               for_each_set_bit(port, &ports, MBOX_CMD_SHIFT) {
+               ports = tegra->cmd_data;
+               for_each_set_bit(port, &ports, BITS_PER_LONG) {
                        pad = port_to_hsic_pad(port - 1);
                        mutex_lock(&tegra->sync_lock);
                        ret = hsic_pad_pupd_set(tegra, pad, PUPD_DISABLE);
@@ -2956,32 +3238,46 @@ tegra_xhci_process_mbox_message(struct work_struct *work)
                                break;
                }
 
+               sw_resp = CMD_DATA(tegra->cmd_data);
                if (!ret)
-                       sw_resp |= (MBOX_CMD_ACK << MBOX_CMD_SHIFT);
+                       sw_resp |= CMD_TYPE(MBOX_CMD_ACK);
                else
-                       sw_resp |= (MBOX_CMD_NACK << MBOX_CMD_SHIFT);
-
+                       sw_resp |= CMD_TYPE(MBOX_CMD_NACK);
                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);
+               xhci_dbg(xhci, "%s firmware responds with ACK\n", __func__);
                break;
        case MBOX_CMD_NACK:
-               writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
-               writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
+               xhci_warn(xhci, "%s firmware responds with NACK\n", __func__);
                break;
        default:
                xhci_err(xhci, "%s: invalid cmdtype %d\n",
                                __func__, tegra->cmd_type);
        }
+
+       /* clear MBOX_SMI_INT_EN bit */
+       cmd = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
+       cmd &= ~MBOX_SMI_INT_EN;
+       writel(cmd, tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
+
+       /* clear mailbox ownership */
+       writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
+
        mutex_unlock(&tegra->mbox_lock);
        return;
 
 send_sw_response:
-       if (((sw_resp & MBOX_CMD_TYPE_MASK) >> MBOX_CMD_SHIFT) == MBOX_CMD_NACK)
-               xhci_err(xhci, "%s respond fw message 0x%x with NAK\n",
-                               __func__, fw_msg);
+       response = (sw_resp >> CMD_TYPE_SHIFT) & CMD_TYPE_MASK;
+       if (response == MBOX_CMD_NACK)
+               xhci_warn(xhci, "%s respond fw message 0x%x with NACK\n",
+                       __func__, fw_msg);
+       else if (response == MBOX_CMD_ACK)
+               xhci_dbg(xhci, "%s respond fw message 0x%x with ACK\n",
+                       __func__, fw_msg);
+       else
+               xhci_err(xhci, "%s respond fw message 0x%x with %d\n",
+               __func__, fw_msg, response);
 
        writel(sw_resp, tegra->fpci_base + XUSB_CFG_ARU_MBOX_DATA_IN);
        cmd = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
@@ -3072,12 +3368,13 @@ static irqreturn_t tegra_xhci_smi_irq(int irq, void *ptrdev)
         */
 
        temp = readl(tegra->fpci_base + XUSB_CFG_ARU_SMI_INTR);
-
-       /* write 1 to clear SMI INTR en bit ( bit 3 ) */
-       temp = MBOX_SMI_INTR_EN;
        writel(temp, tegra->fpci_base + XUSB_CFG_ARU_SMI_INTR);
 
-       schedule_work(&tegra->mbox_work);
+       xhci_dbg(tegra->xhci, "SMI INTR status 0x%x\n", temp);
+       if (temp & SMI_INTR_STATUS_FW_REINIT)
+               xhci_err(tegra->xhci, "Firmware reinit.\n");
+       if (temp & SMI_INTR_STATUS_MBOX)
+               schedule_work(&tegra->mbox_work);
 
        spin_unlock(&tegra->lock);
        return IRQ_HANDLED;
@@ -3090,7 +3387,7 @@ static void tegra_xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
         * here that the generic code does not try to make a pci_dev from our
         * dev struct in order to setup MSI
         */
-       xhci->quirks |= XHCI_BROKEN_MSI;
+       xhci->quirks |= XHCI_PLAT;
        xhci->quirks &= ~XHCI_SPURIOUS_REBOOT;
 }
 
@@ -3101,20 +3398,20 @@ static int xhci_plat_setup(struct usb_hcd *hcd)
 }
 
 static int tegra_xhci_request_mem_region(struct platform_device *pdev,
-       const char *name, void __iomem **region)
+       int num, void __iomem **region)
 {
        struct resource *res;
        void __iomem *mem;
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, num);
        if (!res) {
-               dev_err(&pdev->dev, "memory resource %s doesn't exist\n", name);
+               dev_err(&pdev->dev, "memory resource %d doesn't exist\n", num);
                return -ENODEV;
        }
 
        mem = devm_request_and_ioremap(&pdev->dev, res);
        if (!mem) {
-               dev_err(&pdev->dev, "failed to ioremap for %s\n", name);
+               dev_err(&pdev->dev, "failed to ioremap for %d\n", num);
                return -EFAULT;
        }
        *region = mem;
@@ -3123,16 +3420,16 @@ static int tegra_xhci_request_mem_region(struct platform_device *pdev,
 }
 
 static int tegra_xhci_request_irq(struct platform_device *pdev,
-       const char *rscname, irq_handler_t handler, unsigned long irqflags,
+       int num, irq_handler_t handler, unsigned long irqflags,
        const char *devname, int *irq_no)
 {
        int ret;
        struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
        struct resource *res;
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, rscname);
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, num);
        if (!res) {
-               dev_err(&pdev->dev, "irq resource %s doesn't exist\n", rscname);
+               dev_err(&pdev->dev, "irq resource %d doesn't exist\n", num);
                return -ENODEV;
        }
 
@@ -3141,7 +3438,7 @@ static int tegra_xhci_request_irq(struct platform_device *pdev,
        if (ret != 0) {
                dev_err(&pdev->dev,
                        "failed to request_irq for %s (irq %d), error = %d\n",
-                       devname, res->start, ret);
+                       devname, (int)res->start, ret);
                return ret;
        }
        *irq_no = res->start;
@@ -3380,6 +3677,12 @@ tegra_xhci_suspend(struct platform_device *pdev,
        int ret = 0;
 
        mutex_lock(&tegra->sync_lock);
+       if (!tegra->init_done) {
+               xhci_warn(xhci, "%s: xhci probe not done\n",
+                               __func__);
+               mutex_unlock(&tegra->sync_lock);
+               return -EBUSY;
+       }
        if (!tegra->hc_in_elpg) {
                xhci_warn(xhci, "%s: lp0 suspend entry while elpg not done\n",
                                __func__);
@@ -3388,9 +3691,6 @@ tegra_xhci_suspend(struct platform_device *pdev,
        }
        mutex_unlock(&tegra->sync_lock);
 
-       tegra_xhci_ss_wake_on_interrupts(tegra->bdata->portmap, false);
-       tegra_xhci_hs_wake_on_interrupts(tegra->bdata->portmap, false);
-
        /* enable_irq_wake for ss ports */
        ret = enable_irq_wake(tegra->padctl_irq);
        if (ret < 0) {
@@ -3426,9 +3726,19 @@ static int
 tegra_xhci_resume(struct platform_device *pdev)
 {
        struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+       struct xhci_hcd *xhci = tegra->xhci;
 
        dev_dbg(&pdev->dev, "%s\n", __func__);
 
+       mutex_lock(&tegra->sync_lock);
+       if (!tegra->init_done) {
+               xhci_warn(xhci, "%s: xhci probe not done\n",
+                               __func__);
+               mutex_unlock(&tegra->sync_lock);
+               return -EBUSY;
+       }
+       mutex_unlock(&tegra->sync_lock);
+
        tegra->last_jiffies = jiffies;
 
        disable_irq_wake(tegra->padctl_irq);
@@ -3444,95 +3754,99 @@ tegra_xhci_resume(struct platform_device *pdev)
 }
 #endif
 
+static int init_filesystem_firmware(struct tegra_xhci_hcd *tegra)
+{
+       struct platform_device *pdev = tegra->pdev;
+       int ret;
+
+       ret = request_firmware_nowait(THIS_MODULE, true, firmware_file,
+               &pdev->dev, GFP_KERNEL, tegra, init_filesystem_firmware_done);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "request_firmware failed %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
 
-static int init_bootloader_firmware(struct tegra_xhci_hcd *tegra)
+static void init_filesystem_firmware_done(const struct firmware *fw,
+                                       void *context)
 {
+       struct tegra_xhci_hcd *tegra = context;
        struct platform_device *pdev = tegra->pdev;
-       void __iomem *fw_mmio_base;
-       phys_addr_t fw_mem_phy_addr;
+       struct cfgtbl *fw_cfgtbl;
        size_t fw_size;
+       void *fw_data;
        dma_addr_t fw_dma;
-#ifdef CONFIG_PLATFORM_ENABLE_IOMMU
        int ret;
-#endif
-
-       /* bootloader saved firmware memory address in PMC SCRATCH34 register */
-       fw_mem_phy_addr = tegra_usb_pmc_reg_read(PMC_SCRATCH34);
 
-       fw_mmio_base = devm_ioremap_nocache(&pdev->dev,
-                       fw_mem_phy_addr, sizeof(struct cfgtbl));
+       mutex_lock(&tegra->sync_lock);
 
-       if (!fw_mmio_base) {
-                       dev_err(&pdev->dev, "error mapping fw memory 0x%x\n",
-                                       fw_mem_phy_addr);
-                       return -ENOMEM;
+       if (fw == NULL) {
+               dev_err(&pdev->dev,
+                       "failed to init firmware from filesystem: %s\n",
+                       firmware_file);
+               goto err_firmware_done;
        }
 
-       fw_size = ioread32(fw_mmio_base + FW_SIZE_OFFSET);
-       devm_iounmap(&pdev->dev, fw_mmio_base);
+       fw_cfgtbl = (struct cfgtbl *) fw->data;
+       fw_size = fw_cfgtbl->fwimg_len;
+       dev_info(&pdev->dev, "Firmware File: %s (%d Bytes)\n",
+                       firmware_file, fw_size);
 
-       fw_mmio_base = devm_ioremap_nocache(&pdev->dev,
-                       fw_mem_phy_addr, fw_size);
-       if (!fw_mmio_base) {
-                       dev_err(&pdev->dev, "error mapping fw memory 0x%x\n",
-                                       fw_mem_phy_addr);
-                       return -ENOMEM;
+       fw_data = dma_alloc_coherent(&pdev->dev, fw_size,
+                       &fw_dma, GFP_KERNEL);
+       if (!fw_data) {
+               dev_err(&pdev->dev, "%s: dma_alloc_coherent failed\n",
+                       __func__);
+               goto err_firmware_done;
        }
 
-       dev_info(&pdev->dev, "Firmware Memory: phy 0x%x mapped 0x%p (%d Bytes)\n",
-                       fw_mem_phy_addr, fw_mmio_base, fw_size);
-
-#ifdef CONFIG_PLATFORM_ENABLE_IOMMU
-       fw_dma = dma_map_linear(&pdev->dev, fw_mem_phy_addr, fw_size,
-                       DMA_TO_DEVICE);
-       if (fw_dma == DMA_ERROR_CODE) {
-               dev_err(&pdev->dev, "%s: dma_map_linear failed\n",
-                               __func__);
-               ret = -ENOMEM;
-               goto error_iounmap;
-       }
-#else
-       fw_dma = fw_mem_phy_addr;
-#endif
-       dev_info(&pdev->dev, "Firmware DMA Memory: dma 0x%p (%d Bytes)\n",
-                       (void *) fw_dma, fw_size);
+       memcpy(fw_data, fw->data, fw_size);
+       dev_info(&pdev->dev,
+               "Firmware DMA Memory: dma 0x%p mapped 0x%p (%d Bytes)\n",
+               (void *) fw_dma, fw_data, fw_size);
 
        /* all set and ready to go */
-       tegra->firmware.data = fw_mmio_base;
+       tegra->firmware.data = fw_data;
        tegra->firmware.dma = fw_dma;
        tegra->firmware.size = fw_size;
 
-       return 0;
+       ret = tegra_xhci_probe2(tegra);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "%s: failed to probe: %d\n", __func__, ret);
+               goto err_firmware_done;
+       }
 
-#ifdef CONFIG_PLATFORM_ENABLE_IOMMU
-error_iounmap:
-       devm_iounmap(&pdev->dev, fw_mmio_base);
-       return ret;
-#endif
+       release_firmware(fw);
+       mutex_unlock(&tegra->sync_lock);
+       return;
+
+err_firmware_done:
+       release_firmware(fw);
+       mutex_unlock(&tegra->sync_lock);
+       device_release_driver(&pdev->dev);
 }
 
-static void deinit_bootloader_firmware(struct tegra_xhci_hcd *tegra)
+static void deinit_filesystem_firmware(struct tegra_xhci_hcd *tegra)
 {
        struct platform_device *pdev = tegra->pdev;
-       void __iomem *fw_mmio_base = tegra->firmware.data;
 
-#ifdef CONFIG_PLATFORM_ENABLE_IOMMU
-       dma_unmap_single(&pdev->dev, tegra->firmware.dma,
-                       tegra->firmware.size, DMA_TO_DEVICE);
-#endif
-       devm_iounmap(&pdev->dev, fw_mmio_base);
+       if (tegra->firmware.data) {
+               dma_free_coherent(&pdev->dev, tegra->firmware.size,
+                       tegra->firmware.data, tegra->firmware.dma);
+       }
 
        memset(&tegra->firmware, 0, sizeof(tegra->firmware));
 }
-
 static int init_firmware(struct tegra_xhci_hcd *tegra)
 {
-       return init_bootloader_firmware(tegra);
+       return init_filesystem_firmware(tegra);
 }
 
 static void deinit_firmware(struct tegra_xhci_hcd *tegra)
 {
-       deinit_bootloader_firmware(tegra);
+       return deinit_filesystem_firmware(tegra);
 }
 
 static int tegra_enable_xusb_clk(struct tegra_xhci_hcd *tegra,
@@ -3567,7 +3881,7 @@ eanble_ss_clk_failed:
        clk_disable(tegra->host_clk);
 
 enable_host_clk_failed:
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
                clk_disable(tegra->pll_re_vco_clk);
        return err;
 }
@@ -3754,18 +4068,226 @@ static struct tegra_xusb_padctl_regs t124_padregs_offset = {
        .iophy_misc_pad_s0_ctl6_0       = 0x15c,
 };
 
+/* FIXME: using notifier to transfer control to host from suspend
+ * for otg port when xhci is in elpg. Find  better alternative
+ */
+static int tegra_xhci_otg_notify(struct notifier_block *nb,
+                                  unsigned long event, void *unused)
+{
+       struct tegra_xhci_hcd *tegra = container_of(nb,
+                                       struct tegra_xhci_hcd, otgnb);
+
+       if ((event == USB_EVENT_ID))
+               if (tegra->hc_in_elpg) {
+                       schedule_work(&tegra->host_elpg_exit_work);
+                       tegra->host_resume_req = true;
+       }
+
+       return NOTIFY_OK;
+}
+
+static void tegra_xusb_read_board_data(struct tegra_xhci_hcd *tegra)
+{
+       struct tegra_xusb_board_data *bdata = tegra->bdata;
+       struct device_node *node = tegra->pdev->dev.of_node;
+       int ret;
+
+       bdata->uses_external_pmic = of_property_read_bool(node,
+                                       "nvidia,uses_external_pmic");
+       bdata->gpio_controls_muxed_ss_lanes = of_property_read_bool(node,
+                                       "nvidia,gpio_controls_muxed_ss_lanes");
+       ret = of_property_read_u32(node, "nvidia,gpio_ss1_sata",
+                                       &bdata->gpio_ss1_sata);
+       ret = of_property_read_u32(node, "nvidia,portmap",
+                                       &bdata->portmap);
+       ret = of_property_read_u32(node, "nvidia,ss_portmap",
+                                       (u32 *) &bdata->ss_portmap);
+       ret = of_property_read_u32(node, "nvidia,lane_owner",
+                                       (u32 *) &bdata->lane_owner);
+       ret = of_property_read_u32(node, "nvidia,ulpicap",
+                                       (u32 *) &bdata->ulpicap);
+       ret = of_property_read_u8_array(node, "nvidia,hsic0",
+                                       (u8 *) &bdata->hsic[0],
+                                       sizeof(bdata->hsic[0]));
+       ret = of_property_read_u8_array(node, "nvidia,hsic1",
+                                       (u8 *) &bdata->hsic[1],
+                                       sizeof(bdata->hsic[0]));
+       /* TODO: Add error conditions check */
+}
+
+static void tegra_xusb_read_calib_data(struct tegra_xhci_hcd *tegra)
+{
+       u32 usb_calib0 = tegra_fuse_readl(FUSE_SKU_USB_CALIB_0);
+       struct tegra_xusb_chip_calib *cdata = tegra->cdata;
+
+       pr_info("tegra_xusb_read_usb_calib: usb_calib0 = 0x%08x\n", usb_calib0);
+       /*
+        * read from usb_calib0 and pass to driver
+        * set HS_CURR_LEVEL (PAD0)     = usb_calib0[5:0]
+        * set TERM_RANGE_ADJ           = usb_calib0[10:7]
+        * set HS_SQUELCH_LEVEL         = usb_calib0[12:11]
+        * set HS_IREF_CAP              = usb_calib0[14:13]
+        * set HS_CURR_LEVEL (PAD1)     = usb_calib0[20:15]
+        */
+
+       cdata->hs_curr_level_pad0 = (usb_calib0 >> 0) & 0x3f;
+       cdata->hs_term_range_adj = (usb_calib0 >> 7) & 0xf;
+       cdata->hs_squelch_level = (usb_calib0 >> 11) & 0x3;
+       cdata->hs_iref_cap = (usb_calib0 >> 13) & 0x3;
+       cdata->hs_curr_level_pad1 = (usb_calib0 >> 15) & 0x3f;
+       cdata->hs_curr_level_pad2 = (usb_calib0 >> 15) & 0x3f;
+}
+
+static const struct tegra_xusb_soc_config tegra114_soc_config = {
+       .pmc_portmap = (TEGRA_XUSB_UTMIP_PMC_PORT0 << 0) |
+                       (TEGRA_XUSB_UTMIP_PMC_PORT2 << 4),
+       .quirks = TEGRA_XUSB_USE_HS_SRC_CLOCK2,
+       .rx_wander = (0x3 << 4),
+       .rx_eq = (0x3928 << 8),
+       .cdr_cntl = (0x26 << 24),
+       .dfe_cntl = 0x002008EE,
+       .hs_slew = (0xE << 6),
+       .ls_rslew_pad0 = (0x3 << 14),
+       .ls_rslew_pad1 = (0x0 << 14),
+       .hs_disc_lvl = (0x7 << 2),
+       .spare_in = 0x0,
+       .supply = {
+               .utmi_vbuses = {"usb_vbus0", "usb_vbus1", "usb_vbus2",},
+               .s3p3v = "hvdd_usb",
+               .s1p8v = "avdd_usb_pll",
+               .vddio_hsic = "vddio_hsic",
+               .s1p05v = "avddio_usb",
+       },
+};
+
+static const struct tegra_xusb_soc_config tegra124_soc_config = {
+       .pmc_portmap = (TEGRA_XUSB_UTMIP_PMC_PORT0 << 0) |
+                       (TEGRA_XUSB_UTMIP_PMC_PORT1 << 4) |
+                       (TEGRA_XUSB_UTMIP_PMC_PORT2 << 8),
+       .rx_wander = (0xF << 4),
+       .rx_eq = (0xF070 << 8),
+       .cdr_cntl = (0x26 << 24),
+       .dfe_cntl = 0x002008EE,
+       .hs_slew = (0xE << 6),
+       .ls_rslew_pad0 = (0x3 << 14),
+       .ls_rslew_pad1 = (0x0 << 14),
+       .ls_rslew_pad2 = (0x0 << 14),
+       .hs_disc_lvl = (0x7 << 2),
+       .spare_in = 0x1,
+       .supply = {
+               .utmi_vbuses = {"usb_vbus0", "usb_vbus1", "usb_vbus2",},
+               .s3p3v = "hvdd_usb",
+               .s1p8v = "avdd_pll_utmip",
+               .vddio_hsic = "vddio_hsic",
+               .s1p05v = "avddio_usb",
+       },
+};
+
+static struct of_device_id tegra_xhci_of_match[] = {
+       { .compatible = "nvidia,tegra114-xhci", .data = &tegra114_soc_config },
+       { .compatible = "nvidia,tegra124-xhci", .data = &tegra124_soc_config },
+       { },
+};
+
+static ssize_t hsic_power_show(struct device *dev,
+                       struct kobj_attribute *attr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+       int pad;
+
+       for_each_enabled_hsic_pad(pad, tegra) {
+               if (&tegra->hsic_power_attr[pad] == attr)
+                       return sprintf(buf, "%d\n", pad);
+       }
+
+       return sprintf(buf, "-1\n");
+}
+
+static ssize_t hsic_power_store(struct device *dev,
+                       struct kobj_attribute *attr, const char *buf, size_t n)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+       enum MBOX_CMD_TYPE msg;
+       unsigned int on;
+       int pad, port;
+       int ret;
+
+       if (sscanf(buf, "%u", &on) != 1)
+               return -EINVAL;
+
+       if (on)
+               msg = MBOX_CMD_AIRPLANE_MODE_DISABLED;
+       else
+               msg = MBOX_CMD_AIRPLANE_MODE_ENABLED;
+
+       for_each_enabled_hsic_pad(pad, tegra) {
+               port = hsic_pad_to_port(pad);
+
+               if (&tegra->hsic_power_attr[pad] == attr) {
+                       hsic_pad_pupd_set(tegra, pad, PUPD_IDLE);
+                       ret = fw_message_send(tegra, msg, BIT(port + 1));
+               }
+       }
+
+       return n;
+}
+
+static void hsic_power_remove_file(struct tegra_xhci_hcd *tegra)
+{
+       struct device *dev = &tegra->pdev->dev;
+       int p;
+
+       for_each_enabled_hsic_pad(p, tegra) {
+               if (attr_name(tegra->hsic_power_attr[p])) {
+                       device_remove_file(dev, &tegra->hsic_power_attr[p]);
+                       kzfree(attr_name(tegra->hsic_power_attr[p]));
+               }
+       }
+
+}
+
+static int hsic_power_create_file(struct tegra_xhci_hcd *tegra)
+{
+       struct device *dev = &tegra->pdev->dev;
+       int p;
+       int err;
+
+       for_each_enabled_hsic_pad(p, tegra) {
+               attr_name(tegra->hsic_power_attr[p]) = kzalloc(16, GFP_KERNEL);
+               if (!attr_name(tegra->hsic_power_attr[p]))
+                       return -ENOMEM;
+
+               snprintf(attr_name(tegra->hsic_power_attr[p]), 16,
+                       "hsic%d_power", p);
+               tegra->hsic_power_attr[p].show = hsic_power_show;
+               tegra->hsic_power_attr[p].store = hsic_power_store;
+               tegra->hsic_power_attr[p].attr.mode = (S_IRUGO | S_IWUSR);
+               sysfs_attr_init(&tegra->hsic_power_attr[p].attr);
+
+               err = device_create_file(dev, &tegra->hsic_power_attr[p]);
+               if (err) {
+                       kzfree(attr_name(tegra->hsic_power_attr[p]));
+                       attr_name(tegra->hsic_power_attr[p]) = 0;
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
 /* TODO: we have to refine error handling in tegra_xhci_probe() */
 static int tegra_xhci_probe(struct platform_device *pdev)
 {
-       const struct hc_driver *driver;
-       struct xhci_hcd *xhci;
        struct tegra_xhci_hcd *tegra;
        struct resource *res;
-       struct usb_hcd  *hcd;
        unsigned pad;
        u32 val;
        int ret;
        int irq;
+       const struct tegra_xusb_soc_config *soc_config;
+       const struct of_device_id *match;
 
        BUILD_BUG_ON(sizeof(struct cfgtbl) != 256);
 
@@ -3777,24 +4299,74 @@ static int tegra_xhci_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "memory alloc failed\n");
                return -ENOMEM;
        }
+       mutex_init(&tegra->sync_lock);
+       spin_lock_init(&tegra->lock);
+       mutex_init(&tegra->mbox_lock);
+
+       tegra->init_done = false;
+
+       tegra->bdata = devm_kzalloc(&pdev->dev, sizeof(
+                                       struct tegra_xusb_board_data),
+                                       GFP_KERNEL);
+       if (!tegra->bdata) {
+               dev_err(&pdev->dev, "memory alloc failed\n");
+               return -ENOMEM;
+       }
+       tegra->cdata = devm_kzalloc(&pdev->dev, sizeof(
+                                       struct tegra_xusb_chip_calib),
+                                       GFP_KERNEL);
+       if (!tegra->cdata) {
+               dev_err(&pdev->dev, "memory alloc failed\n");
+               return -ENOMEM;
+       }
+       match = of_match_device(tegra_xhci_of_match, &pdev->dev);
+       if (!match) {
+               dev_err(&pdev->dev, "Error: No device match found\n");
+               return -ENODEV;
+       }
+       soc_config = match->data;
+       /* Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       tegra->tegra_xusb_dmamask = DMA_BIT_MASK(64);
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &tegra->tegra_xusb_dmamask;
+
        tegra->pdev = pdev;
+       tegra_xusb_read_calib_data(tegra);
+       tegra_xusb_read_board_data(tegra);
        tegra->pdata = dev_get_platdata(&pdev->dev);
-       tegra->bdata = tegra->pdata->bdata;
+       tegra->bdata->portmap = tegra->pdata->portmap;
+       tegra->bdata->hsic[0].pretend_connect =
+                               tegra->pdata->pretend_connect_0;
+       if (tegra->bdata->portmap == NULL)
+               return -ENODEV;
+       tegra->bdata->lane_owner = tegra->pdata->lane_owner;
+       tegra->soc_config = soc_config;
+       tegra->ss_pwr_gated = false;
+       tegra->host_pwr_gated = false;
+       tegra->hc_in_elpg = false;
+       tegra->hs_wake_event = false;
+       tegra->host_resume_req = false;
+       tegra->lp0_exit = false;
 
-       ret = tegra_xhci_request_mem_region(pdev, "padctl",
-                       &tegra->padctl_base);
+       /* request resource padctl base address */
+       ret = tegra_xhci_request_mem_region(pdev, 3, &tegra->padctl_base);
        if (ret) {
                dev_err(&pdev->dev, "failed to map padctl\n");
                return ret;
        }
 
-       ret = tegra_xhci_request_mem_region(pdev, "fpci", &tegra->fpci_base);
+       /* request resource fpci base address */
+       ret = tegra_xhci_request_mem_region(pdev, 1, &tegra->fpci_base);
        if (ret) {
                dev_err(&pdev->dev, "failed to map fpci\n");
                return ret;
        }
 
-       ret = tegra_xhci_request_mem_region(pdev, "ipfs", &tegra->ipfs_base);
+       /* request resource ipfs base address */
+       ret = tegra_xhci_request_mem_region(pdev, 2, &tegra->ipfs_base);
        if (ret) {
                dev_err(&pdev->dev, "failed to map ipfs\n");
                return ret;
@@ -3807,12 +4379,24 @@ static int tegra_xhci_probe(struct platform_device *pdev)
                return ret;
        }
 
+       if (tegra->bdata->portmap & TEGRA_XUSB_USB2_P0) {
+               tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+               if (IS_ERR_OR_NULL(tegra->transceiver)) {
+                       dev_err(&pdev->dev, "failed to get usb phy\n");
+                       tegra->transceiver = NULL;
+               }
+       }
+
        /* Enable power rails to the PAD,VBUS
         * and pull-up voltage.Initialize the regulators
         */
        ret = tegra_xusb_regulator_init(tegra, pdev);
        if (ret) {
                dev_err(&pdev->dev, "failed to initialize xusb regulator\n");
+               if (ret == -ENODEV) {
+                       ret = -EPROBE_DEFER;
+                       dev_err(&pdev->dev, "Retry at a later stage\n");
+               }
                goto err_deinit_xusb_partition_clk;
        }
 
@@ -3840,13 +4424,15 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        /* reset the pointer back to NULL. driver uses it */
        /* platform_set_drvdata(pdev, NULL); */
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "host");
+       /* request resource host base address */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(&pdev->dev, "mem resource host doesn't exist\n");
                ret = -ENODEV;
                goto err_deinit_usb2_clocks;
        }
        tegra->host_phy_base = res->start;
+       tegra->host_phy_size = resource_size(res);
 
        tegra->host_phy_virt_base = devm_ioremap(&pdev->dev,
                                res->start, resource_size(res));
@@ -3880,10 +4466,8 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        if (XUSB_DEVICE_ID_T114 == tegra->device_id)
                tegra_xhci_war_for_tctrl_rctrl(tegra);
 
-       for (pad = 0; pad < XUSB_HSIC_COUNT; pad++) {
-               if (BIT(XUSB_HSIC_INDEX + pad) & tegra->bdata->portmap)
-                       hsic_power_rail_enable(tegra);
-       }
+       for_each_enabled_hsic_pad(pad, tegra)
+               hsic_power_rail_enable(tegra);
 
        /* Program the XUSB pads to take ownership of ports */
        tegra_xhci_padctl_portmap_and_caps(tegra);
@@ -3896,24 +4480,49 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        tegra_periph_reset_deassert(tegra->host_clk);
        tegra_periph_reset_deassert(tegra->ss_clk);
 
+       platform_set_drvdata(pdev, tegra);
        fw_log_init(tegra);
        ret = init_firmware(tegra);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to init firmware\n");
                ret = -ENODEV;
-               goto err_deinit_usb2_clocks;
+               goto err_deinit_firmware_log;
        }
 
-       ret = load_firmware(tegra, true /* do reset ARU */);
+       return 0;
+
+err_deinit_firmware_log:
+       fw_log_deinit(tegra);
+err_deinit_usb2_clocks:
+       tegra_usb2_clocks_deinit(tegra);
+err_deinit_tegra_xusb_regulator:
+       tegra_xusb_regulator_deinit(tegra);
+err_deinit_xusb_partition_clk:
+       if (tegra->transceiver)
+               usb_unregister_notifier(tegra->transceiver, &tegra->otgnb);
+
+       tegra_xusb_partitions_clk_deinit(tegra);
+
+       return ret;
+}
+
+static int tegra_xhci_probe2(struct tegra_xhci_hcd *tegra)
+{
+       struct platform_device *pdev = tegra->pdev;
+       const struct hc_driver *driver;
+       int ret;
+       struct resource *res;
+       int irq;
+       struct xhci_hcd *xhci;
+       struct usb_hcd  *hcd;
+       unsigned port;
+
+
+       ret = load_firmware(tegra, false /* do reset ARU */);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to load firmware\n");
-               ret = -ENODEV;
-               goto err_deinit_firmware;
+               return -ENODEV;
        }
-
-       spin_lock_init(&tegra->lock);
-       mutex_init(&tegra->sync_lock);
-       mutex_init(&tegra->mbox_lock);
        pmc_init(tegra);
 
        device_init_wakeup(&pdev->dev, 1);
@@ -3922,24 +4531,26 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
        if (!hcd) {
                dev_err(&pdev->dev, "failed to create usb2 hcd\n");
-               ret = -ENOMEM;
-               goto err_deinit_firmware;
+               return -ENOMEM;
        }
 
-       ret = tegra_xhci_request_mem_region(pdev, "host", &hcd->regs);
+       /* request resource host base address */
+       ret = tegra_xhci_request_mem_region(pdev, 0, &hcd->regs);
        if (ret) {
                dev_err(&pdev->dev, "failed to map host\n");
                goto err_put_usb2_hcd;
        }
-       hcd->rsrc_start = res->start;
-       hcd->rsrc_len = resource_size(res);
+       hcd->rsrc_start = tegra->host_phy_base;
+       hcd->rsrc_len = tegra->host_phy_size;
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "host");
+       /* Register interrupt handler for HOST */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(&pdev->dev, "irq resource host doesn't exist\n");
                ret = -ENODEV;
                goto err_put_usb2_hcd;
        }
+
        irq = res->start;
        ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (ret) {
@@ -3953,6 +4564,15 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        tegra->xhci = xhci;
        platform_set_drvdata(pdev, tegra);
 
+       if (tegra->bdata->portmap & TEGRA_XUSB_USB2_P0) {
+               if (!IS_ERR_OR_NULL(tegra->transceiver)) {
+                       otg_set_host(tegra->transceiver->otg, &hcd->self);
+                       tegra->otgnb.notifier_call = tegra_xhci_otg_notify;
+                       usb_register_notifier(tegra->transceiver,
+                               &tegra->otgnb);
+               }
+       }
+
        xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
                                                dev_name(&pdev->dev), hcd);
        if (!xhci->shared_hcd) {
@@ -3980,8 +4600,6 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        tegra->mbox_owner = 0xffff;
        INIT_WORK(&tegra->mbox_work, tegra_xhci_process_mbox_message);
 
-       tegra_xhci_enable_fw_message(tegra);
-
        /* do ss partition elpg exit related initialization */
        INIT_WORK(&tegra->ss_elpg_exit_work, ss_partition_elpg_exit_work);
 
@@ -3991,7 +4609,8 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        /* Register interrupt handler for SMI line to handle mailbox
         * interrupt from firmware
         */
-       ret = tegra_xhci_request_irq(pdev, "host-smi", tegra_xhci_smi_irq,
+
+       ret = tegra_xhci_request_irq(pdev, 1, tegra_xhci_smi_irq,
                        IRQF_SHARED, "tegra_xhci_mbox_irq", &tegra->smi_irq);
        if (ret != 0)
                goto err_remove_usb3_hcd;
@@ -4000,37 +4619,43 @@ static int tegra_xhci_probe(struct platform_device *pdev)
         * handle wake on connect irqs interrupt from
         * firmware
         */
-       ret = tegra_xhci_request_irq(pdev, "padctl", tegra_xhci_padctl_irq,
+       ret = tegra_xhci_request_irq(pdev, 2, tegra_xhci_padctl_irq,
                        IRQF_SHARED | IRQF_TRIGGER_HIGH,
                        "tegra_xhci_padctl_irq", &tegra->padctl_irq);
        if (ret != 0)
                goto err_remove_usb3_hcd;
 
-       ret = tegra_xhci_request_irq(pdev, "usb2", pmc_usb_phy_wake_isr,
+       /* Register interrupt wake handler for USB2 */
+       ret = tegra_xhci_request_irq(pdev, 4, pmc_usb_phy_wake_isr,
                IRQF_SHARED | IRQF_TRIGGER_HIGH, "pmc_usb_phy_wake_isr",
                &tegra->usb2_irq);
        if (ret != 0)
                goto err_remove_usb3_hcd;
 
-       ret = tegra_xhci_request_irq(pdev, "usb3", pmc_usb_phy_wake_isr,
+       /* Register interrupt wake handler for USB3 */
+       ret = tegra_xhci_request_irq(pdev, 3, pmc_usb_phy_wake_isr,
                IRQF_SHARED | IRQF_TRIGGER_HIGH, "pmc_usb_phy_wake_isr",
                &tegra->usb3_irq);
        if (ret != 0)
                goto err_remove_usb3_hcd;
 
-       tegra->ss_pwr_gated = false;
-       tegra->host_pwr_gated = false;
-       tegra->hc_in_elpg = false;
-       tegra->hs_wake_event = false;
-       tegra->host_resume_req = false;
-       tegra->lp0_exit = false;
-       tegra->dfe_ctle_ctx_saved = false;
+       for (port = 0; port < XUSB_SS_PORT_COUNT; port++) {
+               tegra->ctle_ctx_saved[port] = false;
+               tegra->dfe_ctx_saved[port] = false;
+       }
+
+       tegra_xhci_enable_fw_message(tegra);
+       hsic_pad_pretend_connect(tegra);
 
        tegra_xhci_debug_read_pads(tegra);
        utmi_phy_pad_enable();
        utmi_phy_iddq_override(false);
 
        tegra_pd_add_device(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
+       hsic_power_create_file(tegra);
+       tegra->init_done = true;
 
        return 0;
 
@@ -4043,14 +4668,6 @@ err_remove_usb2_hcd:
        usb_remove_hcd(hcd);
 err_put_usb2_hcd:
        usb_put_hcd(hcd);
-err_deinit_firmware:
-       deinit_firmware(tegra);
-err_deinit_usb2_clocks:
-       tegra_usb2_clocks_deinit(tegra);
-err_deinit_tegra_xusb_regulator:
-       tegra_xusb_regulator_deinit(tegra);
-err_deinit_xusb_partition_clk:
-       tegra_xusb_partitions_clk_deinit(tegra);
 
        return ret;
 }
@@ -4058,45 +4675,56 @@ err_deinit_xusb_partition_clk:
 static int tegra_xhci_remove(struct platform_device *pdev)
 {
        struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
-       struct xhci_hcd *xhci = NULL;
-       struct usb_hcd *hcd = NULL;
        unsigned pad;
 
        if (tegra == NULL)
                return -EINVAL;
 
-       xhci = tegra->xhci;
-       hcd = xhci_to_hcd(xhci);
+       mutex_lock(&tegra->sync_lock);
 
-       for (pad = 0; pad < XUSB_HSIC_COUNT; pad++) {
-               if (BIT(XUSB_HSIC_INDEX + pad) & tegra->bdata->portmap)
-                       hsic_pad_disable(tegra, pad);
+       for_each_enabled_hsic_pad(pad, tegra) {
+               hsic_pad_disable(tegra, pad);
+               hsic_power_rail_disable(tegra);
        }
 
-       for (pad = 0; pad < XUSB_HSIC_COUNT; pad++) {
-               if (BIT(XUSB_HSIC_INDEX + pad) & tegra->bdata->portmap)
-                       hsic_power_rail_disable(tegra);
-       }
+       if (tegra->init_done) {
+               struct xhci_hcd *xhci = NULL;
+               struct usb_hcd *hcd = NULL;
 
-       devm_free_irq(&pdev->dev, tegra->usb3_irq, tegra);
-       devm_free_irq(&pdev->dev, tegra->padctl_irq, tegra);
-       devm_free_irq(&pdev->dev, tegra->smi_irq, tegra);
-       usb_remove_hcd(xhci->shared_hcd);
-       usb_put_hcd(xhci->shared_hcd);
-       usb_remove_hcd(hcd);
-       usb_put_hcd(hcd);
-       kfree(xhci);
+               xhci = tegra->xhci;
+               hcd = xhci_to_hcd(xhci);
+
+               devm_free_irq(&pdev->dev, tegra->usb3_irq, tegra);
+               devm_free_irq(&pdev->dev, tegra->padctl_irq, tegra);
+               devm_free_irq(&pdev->dev, tegra->smi_irq, tegra);
+               usb_remove_hcd(xhci->shared_hcd);
+               usb_put_hcd(xhci->shared_hcd);
+               usb_remove_hcd(hcd);
+               usb_put_hcd(hcd);
+               kfree(xhci);
+       }
 
        deinit_firmware(tegra);
        fw_log_deinit(tegra);
+
        tegra_xusb_regulator_deinit(tegra);
+
+       if (tegra->transceiver)
+               usb_unregister_notifier(tegra->transceiver, &tegra->otgnb);
+
        tegra_usb2_clocks_deinit(tegra);
        if (!tegra->hc_in_elpg)
                tegra_xusb_partitions_clk_deinit(tegra);
+
        utmi_phy_pad_disable();
        utmi_phy_iddq_override(true);
 
        tegra_pd_remove_device(&pdev->dev);
+       platform_set_drvdata(pdev, NULL);
+
+       hsic_power_remove_file(tegra);
+       mutex_unlock(&tegra->sync_lock);
+
        return 0;
 }
 
@@ -4110,9 +4738,7 @@ static void tegra_xhci_shutdown(struct platform_device *pdev)
                return;
 
        if (tegra->hc_in_elpg) {
-               mutex_lock(&tegra->sync_lock);
-               pmc_setup(tegra, 0);
-               mutex_unlock(&tegra->sync_lock);
+               pmc_disable_bus_ctrl(tegra);
        } else {
                xhci = tegra->xhci;
                hcd = xhci_to_hcd(xhci);
@@ -4130,6 +4756,7 @@ static struct platform_driver tegra_xhci_driver = {
 #endif
        .driver = {
                .name = "tegra-xhci",
+               .of_match_table = tegra_xhci_of_match,
        },
 };
 MODULE_ALIAS("platform:tegra-xhci");