]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blobdiff - drivers/usb/host/xhci-tegra.c
usb: xhci: tegra: fix wake from LP1
[sojka/nv-tegra/linux-3.10.git] / drivers / usb / host / xhci-tegra.c
index 8c022655ed51f4395e8b0010aaa9516ca8b66039..0e494ddbadaacdfa4e4e6729e1431ca7fa9c3615 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)
                (_addr & PAGE_OFFSET_MASK);                             \
        })
 
-/* 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 reg_dump(_dev, _base, _reg)                                    \
+       dev_dbg(_dev, "%s: %s @%x = 0x%x\n", __func__, #_reg,           \
+               _reg, readl(_base + _reg))
+
+#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)
@@ -103,6 +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, /* 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,
@@ -166,7 +179,9 @@ struct cfgtbl {
        u32 fwimg_len;
        u8 magic[8];
        u32 SS_low_power_entry_timeout;
-       u8 padding[140]; /* padding bytes to makeup 256-bytes cfgtbl */
+       u8 num_hsic_port;
+       u8 ss_portmap;
+       u8 padding[138]; /* padding bytes to makeup 256-bytes cfgtbl */
 };
 
 struct xusb_save_regs {
@@ -192,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 {
@@ -209,11 +224,13 @@ struct tegra_xhci_firmware_log {
        void *virt_addr;                /* kernel va of the shared log buffer */
        struct log_entry *dequeue;      /* current dequeue pointer (va) */
        struct circ_buf circ;           /* big circular buffer */
+       u32 seq;                        /* log sequence number */
 
        struct task_struct *thread;     /* a thread to consume log */
        struct mutex mutex;
        wait_queue_head_t read_wait;
        wait_queue_head_t write_wait;
+       wait_queue_head_t intr_wait;
        struct dentry *path;
        struct dentry *log_file;
        unsigned long flags;
@@ -322,6 +339,7 @@ struct tegra_xhci_hcd {
        int smi_irq;
        int padctl_irq;
        int usb3_irq;
+       int usb2_irq;
 
        bool ss_wake_event;
        bool ss_pwr_gated;
@@ -329,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;
@@ -340,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;
@@ -348,12 +371,13 @@ 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;
+       struct regulator *vddio_hsic_reg;
+       int vddio_hsic_refcnt;
 
        struct work_struct mbox_work;
        struct work_struct ss_elpg_exit_work;
@@ -384,14 +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)
@@ -399,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)
 {
@@ -434,80 +505,154 @@ static void tegra_xhci_setup_gpio_for_ss_lane(struct tegra_xhci_hcd *tegra)
        }
 }
 
-static void debug_print_portsc(struct xhci_hcd *xhci)
+static u32 xhci_read_portsc(struct xhci_hcd *xhci, unsigned int port)
 {
+       int num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
        __le32 __iomem *addr;
+
+       if (port >= num_ports) {
+               xhci_err(xhci, "%s invalid port %u\n", __func__, port);
+               return -1;
+       }
+
+       addr = &xhci->op_regs->port_status_base + (NUM_PORT_REGS * port);
+       return xhci_readl(xhci, addr);
+}
+
+static void debug_print_portsc(struct xhci_hcd *xhci)
+{
+       __le32 __iomem *addr = &xhci->op_regs->port_status_base;
+       u32 reg;
        int i;
        int ports;
 
        ports = HCS_MAX_PORTS(xhci->hcs_params1);
-       addr = &xhci->op_regs->port_status_base;
        for (i = 0; i < ports; i++) {
-               xhci_dbg(xhci, "%p port %d status reg = 0x%x\n",
-                               addr, i, (unsigned int) xhci_readl(xhci, addr));
+               reg = xhci_read_portsc(xhci, i);
+               xhci_dbg(xhci, "@%p port %d status reg = 0x%x\n",
+                               addr, i, (unsigned int) reg);
                addr += NUM_PORT_REGS;
        }
 }
+static void tegra_xhci_war_for_tctrl_rctrl(struct tegra_xhci_hcd *tegra);
+
+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 void update_speed(struct tegra_xhci_hcd *tegra, u8 port)
+static int update_speed(struct tegra_xhci_hcd *tegra, u8 port)
 {
        struct usb_hcd *hcd = xhci_to_hcd(tegra->xhci);
        u32 portsc;
 
-       portsc = readl(hcd->regs + BAR0_XHCI_OP_PORTSC(port +
-                                               BAR0_XHCI_OP_PORTSC_UTMIP_0));
+       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;
+               return USB_PMC_PORT_SPEED_SUPER;
        else
-               pmc_data.port_speed = USB_PMC_PORT_SPEED_UNKNOWN;
+               return USB_PMC_PORT_SPEED_UNKNOWN;
 }
 
-static void setup_wake_detect(bool setup_wake)
+static void pmc_init(struct tegra_xhci_hcd *tegra)
 {
-       if (setup_wake)
-               pmc_data.pmc_ops->setup_pmc_wake_detect(&pmc_data);
-       else
-               pmc_data.pmc_ops->disable_pmc_bus_ctrl(&pmc_data, 0);
+       struct tegra_usb_pmc_data *pmc;
+       struct device *dev = &tegra->pdev->dev;
+       int 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];
+                       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_init(struct tegra_xhci_hcd *tegra, bool setup_wake)
+static void pmc_setup_wake_detect(struct tegra_xhci_hcd *tegra)
 {
-       u32 portmap = tegra->bdata->portmap;
+       struct tegra_usb_pmc_data *pmc;
+       struct device *dev = &tegra->pdev->dev;
+       u32 portsc;
+       int port;
+       int pad;
+
+       for_each_enabled_hsic_pad(pad, tegra) {
+               dev_dbg(dev, "%s hsic pad %d\n", __func__, pad);
 
-       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);
-               tegra_usb_pmc_init(&pmc_data);
-               setup_wake_detect(setup_wake);
+               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))
+                       pmc->pmc_ops->setup_pmc_wake_detect(pmc);
        }
-       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);
-               tegra_usb_pmc_init(&pmc_data);
-               setup_wake_detect(setup_wake);
+
+       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);
+               }
        }
-       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);
-               tegra_usb_pmc_init(&pmc_data);
-               setup_wake_detect(setup_wake);
+}
+
+static void pmc_disable_bus_ctrl(struct tegra_xhci_hcd *tegra)
+{
+       struct tegra_usb_pmc_data *pmc;
+       struct device *dev = &tegra->pdev->dev;
+       int 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);
        }
-       if (portmap & TEGRA_XUSB_HSIC_P0) {
-               pmc_data.instance = PMC_PORT_UHSIC_P0;
-               pmc_data.phy_type = TEGRA_USB_PHY_INTF_HSIC;
-               update_speed(tegra, pmc_data.instance);
-               tegra_usb_pmc_init(&pmc_data);
-               setup_wake_detect(setup_wake);
+
+       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);
+               }
        }
 }
 
@@ -559,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
@@ -613,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)
@@ -623,6 +829,39 @@ static inline bool circ_buffer_full(struct circ_buf *circ)
        return (space <= FW_LOG_SIZE);
 }
 
+static inline bool fw_log_available(struct tegra_xhci_hcd *tegra)
+{
+       return (tegra->log.dequeue->owner == DRIVER);
+}
+
+/**
+ * fw_log_wait_empty_timeout - wait firmware log thread to clean up shared
+ *     log buffer.
+ * @param tegra:       tegra_xhci_hcd context
+ * @param msec:                timeout value in millisecond
+ * @return true:       shared log buffer is empty,
+ *        false:       shared log buffer isn't empty.
+ */
+static inline bool fw_log_wait_empty_timeout(struct tegra_xhci_hcd *tegra,
+               unsigned timeout)
+{
+       unsigned long target = jiffies + msecs_to_jiffies(timeout);
+       bool ret;
+
+       mutex_lock(&tegra->log.mutex);
+
+       while (fw_log_available(tegra) && time_is_after_jiffies(target)) {
+               mutex_unlock(&tegra->log.mutex);
+               usleep_range(1000, 2000);
+               mutex_lock(&tegra->log.mutex);
+       }
+
+       ret = fw_log_available(tegra);
+       mutex_unlock(&tegra->log.mutex);
+
+       return ret;
+}
+
 /**
  * fw_log_copy - copy firmware log from device's buffer to driver's circular
  *     buffer.
@@ -641,9 +880,8 @@ static inline bool fw_log_copy(struct tegra_xhci_hcd *tegra)
        int buffer_len, copy_len;
        struct log_entry *entry;
        struct log_entry *first = tegra->log.virt_addr;
-       static u32 last_seq = -1;
 
-       while (tegra->log.dequeue->owner == DRIVER) {
+       while (fw_log_available(tegra)) {
 
                /* calculate maximum contiguous driver buffer length */
                head = circ->head;
@@ -658,12 +896,13 @@ static inline bool fw_log_copy(struct tegra_xhci_hcd *tegra)
                entry = tegra->log.dequeue;
                copy_len = 0;
                do {
-                       if ((last_seq + 1) != entry->sequence_no) {
+                       if (tegra->log.seq != entry->sequence_no) {
                                dev_warn(dev,
                                "%s: discontinuous seq no, expect %u get %u\n",
-                               __func__, last_seq + 1, entry->sequence_no);
+                               __func__, tegra->log.seq, entry->sequence_no);
                        }
-                       last_seq = entry->sequence_no;
+                       tegra->log.seq = entry->sequence_no + 1;
+
                        copy_len += FW_LOG_SIZE;
                        buffer_len -= FW_LOG_SIZE;
                        if (!buffer_len)
@@ -702,7 +941,7 @@ static int fw_log_thread(void *data)
                        mutex_unlock(&tegra->log.mutex);
                        dev_info(dev, "%s: circ buffer full\n", __func__);
                        wait_event_interruptible(tegra->log.write_wait,
-                                       !circ_buffer_full(circ));
+                           kthread_should_stop() || !circ_buffer_full(circ));
                        mutex_lock(&tegra->log.mutex);
                }
 
@@ -711,7 +950,8 @@ static int fw_log_thread(void *data)
 
                /* relax if no logs left  */
                if (!logs_left)
-                       schedule_timeout_interruptible(FW_LOG_THREAD_RELAX);
+                       wait_event_interruptible_timeout(tegra->log.intr_wait,
+                               fw_log_available(tegra), FW_LOG_THREAD_RELAX);
        } while (!kthread_should_stop());
 
        dev_dbg(dev, "stop firmware log thread\n");
@@ -806,6 +1046,7 @@ static const struct file_operations firmware_log_fops = {
                .open           = fw_log_file_open,
                .release        = fw_log_file_close,
                .read           = fw_log_file_read,
+               .owner          = THIS_MODULE,
 };
 
 static int fw_log_init(struct tegra_xhci_hcd *tegra)
@@ -823,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;
@@ -841,6 +1084,7 @@ static int fw_log_init(struct tegra_xhci_hcd *tegra)
 
        init_waitqueue_head(&tegra->log.read_wait);
        init_waitqueue_head(&tegra->log.write_wait);
+       init_waitqueue_head(&tegra->log.intr_wait);
 
        mutex_init(&tegra->log.mutex);
 
@@ -888,6 +1132,7 @@ static void fw_log_deinit(struct tegra_xhci_hcd *tegra)
        struct platform_device *pdev = tegra->pdev;
 
        if (test_and_clear_bit(FW_LOG_CONTEXT_VALID, &tegra->log.flags)) {
+
                debugfs_remove(tegra->log.log_file);
                debugfs_remove(tegra->log.path);
 
@@ -895,14 +1140,282 @@ static void fw_log_deinit(struct tegra_xhci_hcd *tegra)
                wake_up_interruptible(&tegra->log.write_wait);
                kthread_stop(tegra->log.thread);
 
+               mutex_lock(&tegra->log.mutex);
                dma_free_writecombine(&pdev->dev, FW_LOG_RING_SIZE,
                        tegra->log.virt_addr, tegra->log.phys_addr);
                vfree(tegra->log.circ.buf);
+               tegra->log.circ.head = tegra->log.circ.tail = 0;
+               mutex_unlock(&tegra->log.mutex);
 
                mutex_destroy(&tegra->log.mutex);
        }
 }
 
+/* hsic pad operations */
+/*
+ * HSIC pads need VDDIO_HSIC power rail turned on to be functional. There is
+ * only one VDDIO_HSIC power rail shared by all HSIC pads.
+ */
+static int hsic_power_rail_enable(struct tegra_xhci_hcd *tegra)
+{
+       struct device *dev = &tegra->pdev->dev;
+       const struct tegra_xusb_regulator_name *supply =
+                               &tegra->soc_config->supply;
+       int ret;
+
+       if (tegra->vddio_hsic_reg)
+               goto done;
+
+       tegra->vddio_hsic_reg = devm_regulator_get(dev, supply->vddio_hsic);
+       if (IS_ERR_OR_NULL(tegra->vddio_hsic_reg)) {
+               dev_err(dev, "%s get vddio_hsic failed\n", __func__);
+               ret = PTR_ERR(tegra->vddio_hsic_reg);
+               goto get_failed;
+       }
+
+       dev_dbg(dev, "%s regulator_enable vddio_hsic\n", __func__);
+       ret = regulator_enable(tegra->vddio_hsic_reg);
+       if (ret < 0) {
+               dev_err(dev, "%s enable vddio_hsic failed\n", __func__);
+               goto enable_failed;
+       }
+
+done:
+       tegra->vddio_hsic_refcnt++;
+       WARN(tegra->vddio_hsic_refcnt > XUSB_HSIC_COUNT,
+                       "vddio_hsic_refcnt exceeds\n");
+       return 0;
+
+enable_failed:
+       devm_regulator_put(tegra->vddio_hsic_reg);
+get_failed:
+       tegra->vddio_hsic_reg = NULL;
+       return ret;
+}
+
+static int hsic_power_rail_disable(struct tegra_xhci_hcd *tegra)
+{
+       struct device *dev = &tegra->pdev->dev;
+       int ret;
+
+       WARN_ON(!tegra->vddio_hsic_reg || !tegra->vddio_hsic_refcnt);
+
+       tegra->vddio_hsic_refcnt--;
+       if (tegra->vddio_hsic_refcnt)
+               return 0;
+
+       dev_dbg(dev, "%s regulator_disable vddio_hsic\n", __func__);
+       ret = regulator_disable(tegra->vddio_hsic_reg);
+       if (ret < 0) {
+               dev_err(dev, "%s disable vddio_hsic failed\n", __func__);
+               tegra->vddio_hsic_refcnt++;
+               return ret;
+       }
+
+       devm_regulator_put(tegra->vddio_hsic_reg);
+       tegra->vddio_hsic_reg = NULL;
+
+       return 0;
+}
+
+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[pad];
+       u32 reg;
+
+       if (pad >= XUSB_HSIC_COUNT) {
+               dev_err(dev, "%s invalid HSIC pad number %d\n", __func__, pad);
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "%s pad %u\n", __func__, pad);
+
+       reg = readl(base + HSIC_PAD_CTL_2(pad));
+       reg &= ~(RX_STROBE_TRIM(~0) | RX_DATA_TRIM(~0));
+       reg |= RX_STROBE_TRIM(hsic->rx_strobe_trim);
+       reg |= RX_DATA_TRIM(hsic->rx_data_trim);
+       writel(reg, base + HSIC_PAD_CTL_2(pad));
+
+       reg = readl(base + HSIC_PAD_CTL_0(pad));
+       reg &= ~(TX_RTUNEP(~0) | TX_RTUNEN(~0) | TX_SLEWP(~0) | TX_SLEWN(~0));
+       reg |= TX_RTUNEP(hsic->tx_rtune_p);
+       reg |= TX_RTUNEN(hsic->tx_rtune_n);
+       reg |= TX_SLEWP(hsic->tx_slew_p);
+       reg |= TX_SLEWN(hsic->tx_slew_n);
+       writel(reg, base + HSIC_PAD_CTL_0(pad));
+
+       reg = readl(base + HSIC_PAD_CTL_1(pad));
+       reg &= ~(RPD_DATA | RPD_STROBE | RPU_DATA | RPU_STROBE);
+       reg |= (RPD_DATA | RPU_STROBE); /* keep HSIC in IDLE */
+       if (hsic->auto_term_en)
+               reg |= AUTO_TERM_EN;
+       else
+               reg &= ~AUTO_TERM_EN;
+       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);
+       writel(reg, base + HSIC_STRB_TRIM_CONTROL);
+
+       reg = readl(base + USB2_PAD_MUX);
+       reg |= USB2_HSIC_PAD_PORT(pad);
+       writel(reg, base + USB2_PAD_MUX);
+
+       reg_dump(dev, base, HSIC_PAD_CTL_0(pad));
+       reg_dump(dev, base, HSIC_PAD_CTL_1(pad));
+       reg_dump(dev, base, HSIC_PAD_CTL_2(pad));
+       reg_dump(dev, base, HSIC_STRB_TRIM_CONTROL);
+       reg_dump(dev, base, USB2_PAD_MUX);
+       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;
+       void __iomem *base = tegra->padctl_base;
+       u32 reg;
+
+       if (pad >= XUSB_HSIC_COUNT) {
+               dev_err(dev, "%s invalid HSIC pad number %d\n", __func__, pad);
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "%s pad %u\n", __func__, pad);
+
+       reg = readl(base + USB2_PAD_MUX);
+       reg &= ~USB2_HSIC_PAD_PORT(pad);
+       writel(reg, base + USB2_PAD_MUX);
+
+       reg = readl(base + HSIC_PAD_CTL_1(pad));
+       reg |= (PD_RX | HSIC_PD_ZI | PD_TRX | PD_TX);
+       writel(reg, base + HSIC_PAD_CTL_1(pad));
+
+       reg_dump(dev, base, HSIC_PAD_CTL_0(pad));
+       reg_dump(dev, base, HSIC_PAD_CTL_1(pad));
+       reg_dump(dev, base, HSIC_PAD_CTL_2(pad));
+       reg_dump(dev, base, USB2_PAD_MUX);
+       return 0;
+}
+
+enum hsic_pad_pupd {
+       PUPD_DISABLE = 0,
+       PUPD_IDLE,
+       PUPD_RESET
+};
+
+static int hsic_pad_pupd_set(struct tegra_xhci_hcd *tegra, unsigned pad,
+       enum hsic_pad_pupd pupd)
+{
+       struct device *dev = &tegra->pdev->dev;
+       void __iomem *base = tegra->padctl_base;
+       u32 reg;
+
+       if (pad >= XUSB_HSIC_COUNT) {
+               dev_err(dev, "%s invalid HSIC pad number %u\n", __func__, pad);
+               return -EINVAL;
+       }
+
+       dev_dbg(dev, "%s pad %u pupd %d\n", __func__, pad, pupd);
+
+       reg = readl(base + HSIC_PAD_CTL_1(pad));
+       reg &= ~(RPD_DATA | RPD_STROBE | RPU_DATA | RPU_STROBE);
+
+       if (pupd == PUPD_IDLE)
+               reg |= (RPD_DATA | RPU_STROBE);
+       else if (pupd == PUPD_RESET)
+               reg |= (RPD_DATA | RPD_STROBE);
+       else if (pupd != PUPD_DISABLE) {
+               dev_err(dev, "%s invalid pupd %d\n", __func__, pupd);
+               return -EINVAL;
+       }
+
+       writel(reg, base + HSIC_PAD_CTL_1(pad));
+
+       reg_dump(dev, base, HSIC_PAD_CTL_1(pad));
+
+       return 0;
+}
+
+
 static void tegra_xhci_debug_read_pads(struct tegra_xhci_hcd *tegra)
 {
        struct tegra_xusb_padctl_regs *padregs = tegra->padregs;
@@ -975,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 =
@@ -994,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 =
@@ -1015,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;
                }
        }
 
@@ -1041,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;
@@ -1099,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;
 }
 
@@ -1158,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");
@@ -1207,49 +1704,20 @@ 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");
                        goto enable_pll_re_vco_clk_failed;
                }
        }
-       /* enable ss clock */
-       err = clk_enable(tegra->host_clk);
-       if (err) {
-               dev_err(&pdev->dev, "Failed to enable host partition clk\n");
-               goto enable_host_clk_failed;
-       }
+       return 0;
 
-       err = clk_enable(tegra->ss_clk);
-       if (err) {
-               dev_err(&pdev->dev, "Failed to enable ss partition clk\n");
-               goto eanble_ss_clk_failed;
-       }
+enable_pll_re_vco_clk_failed:
+       tegra->ss_clk = NULL;
 
-       err = clk_enable(tegra->emc_clk);
-       if (err) {
-               dev_err(&pdev->dev, "Failed to enable xusb.emc clk\n");
-               goto eanble_emc_clk_failed;
-       }
-
-       return 0;
-
-eanble_emc_clk_failed:
-       clk_disable(tegra->ss_clk);
-
-eanble_ss_clk_failed:
-       clk_disable(tegra->host_clk);
-
-enable_host_clk_failed:
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
-               clk_disable(tegra->pll_re_vco_clk);
-
-enable_pll_re_vco_clk_failed:
-       tegra->ss_clk = NULL;
-
-get_ss_clk_failed:
-       tegra->host_clk = NULL;
+get_ss_clk_failed:
+       tegra->host_clk = NULL;
 
 get_host_clk_failed:
        tegra->ss_src_clk = NULL;
@@ -1261,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:
@@ -1274,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;
 }
 
@@ -1323,7 +1791,7 @@ static void tegra_xhci_rx_idle_mode_override(struct tegra_xhci_hcd *tegra,
                        padregs->iophy_misc_pad_p1_ctl3_0);
 
                /* SATA lane also if USB3_SS port1 mapped to it */
-               if (XUSB_DEVICE_ID_T124 == tegra->device_id &&
+               if (XUSB_DEVICE_ID_T114 != tegra->device_id &&
                                tegra->bdata->lane_owner & BIT(0)) {
                        reg = readl(tegra->padctl_base +
                                padregs->iophy_misc_pad_s0_ctl3_0);
@@ -1353,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;
        }
 
@@ -1368,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) {
@@ -1388,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;
@@ -1409,89 +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;
+       }
 
-       if (port == 3 /* SATA pad */)
+       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;
 
-       if (port == 3 /* SATA pad */) {
-               ctl4_offset = padregs->iophy_misc_pad_s0_ctl4_0;
-               ctl2_offset = padregs->iophy_misc_pad_s0_ctl2_0;
-       } else {
-               ctl4_offset = port ? padregs->iophy_usb3_pad1_ctl4_0 :
-                               padregs->iophy_usb3_pad0_ctl4_0;
-               ctl2_offset = port ? padregs->iophy_usb3_pad1_ctl2_0 :
-                               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,
@@ -1515,37 +2056,6 @@ static void tegra_xhci_program_ulpi_pad(struct tegra_xhci_hcd *tegra,
         */
 }
 
-static void tegra_xhci_program_hsic_pad(struct tegra_xhci_hcd *tegra,
-       u8 port)
-{
-       struct tegra_xusb_padctl_regs *padregs = tegra->padregs;
-       u32 ctl0_offset;
-       u32 reg;
-
-       reg = readl(tegra->padctl_base + padregs->usb2_pad_mux_0);
-       reg &= ~(port ? USB2_HSIC_PAD_PORT1 : USB2_HSIC_PAD_PORT0);
-       reg |= port ? USB2_HSIC_PAD_P1_OWNER_XUSB :
-                       USB2_HSIC_PAD_P0_OWNER_XUSB;
-       writel(reg, tegra->padctl_base + padregs->usb2_pad_mux_0);
-
-       ctl0_offset = port ? padregs->usb2_hsic_pad1_ctl0_0 :
-                       padregs->usb2_hsic_pad0_ctl0_0;
-
-       reg = readl(tegra->padctl_base + ctl0_offset);
-       reg &= ~(HSIC_TX_SLEWP | HSIC_TX_SLEWN);
-       writel(reg, tegra->padctl_base + ctl0_offset);
-
-       /* FIXME Program below when more details available
-        * XUSB_PADCTL_HSIC_PAD0_CTL_0_0
-        * XUSB_PADCTL_HSIC_PAD0_CTL_1_0
-        * XUSB_PADCTL_HSIC_PAD0_CTL_2_0
-        * XUSB_PADCTL_HSIC_PAD1_CTL_0_0
-        * XUSB_PADCTL_HSIC_PAD1_CTL_1_0
-        * XUSB_PADCTL_HSIC_PAD1_CTL_2_0
-        * XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_0
-        */
-}
-
 static void tegra_xhci_program_utmip_pad(struct tegra_xhci_hcd *tegra,
        u8 port)
 {
@@ -1599,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);
@@ -1613,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,
@@ -1635,29 +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);
-       /* SATA also if USB3_SS port1 mapped to it */
-       if ((port == 1) && (XUSB_DEVICE_ID_T124 == tegra->device_id) &&
-                       (tegra->bdata->lane_owner & BIT(0)))
-               tegra_xhci_restore_dfe_ctle_context(tegra, 3);
+       /* 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,
@@ -1669,10 +2212,11 @@ tegra_xhci_padctl_portmap_and_caps(struct tegra_xhci_hcd *tegra)
 {
        struct tegra_xusb_padctl_regs *padregs = tegra->padregs;
        u32 reg, oc_bits = 0;
+       unsigned pad;
 
        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);
@@ -1708,7 +2252,7 @@ tegra_xhci_padctl_portmap_and_caps(struct tegra_xhci_hcd *tegra)
 
        reg = readl(tegra->padctl_base + padregs->usb2_oc_map_0);
        reg = USB2_OC_MAP_PORT0 | USB2_OC_MAP_PORT1;
-       if (XUSB_DEVICE_ID_T124 == tegra->device_id)
+       if (tegra->bdata->portmap & TEGRA_XUSB_USB2_P2)
                reg |= USB2_OC_MAP_PORT2;
        writel(reg, tegra->padctl_base + padregs->usb2_oc_map_0);
 
@@ -1719,14 +2263,12 @@ 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_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);
 
-       if (tegra->bdata->portmap & TEGRA_XUSB_HSIC_P0)
-               tegra_xhci_program_hsic_pad(tegra, 0);
-       if (tegra->bdata->portmap & TEGRA_XUSB_HSIC_P1)
-               tegra_xhci_program_hsic_pad(tegra, 1);
-
        if (tegra->bdata->portmap & TEGRA_XUSB_SS_P0) {
                tegra_xhci_program_ss_pad(tegra, 0);
        } else {
@@ -1751,7 +2293,7 @@ tegra_xhci_padctl_portmap_and_caps(struct tegra_xhci_hcd *tegra)
                        padregs->iophy_misc_pad_p1_ctl3_0);
 
                /* SATA lane also if USB3_SS port1 mapped to it but unused */
-               if (XUSB_DEVICE_ID_T124 == tegra->device_id &&
+               if (XUSB_DEVICE_ID_T114 != tegra->device_id &&
                                tegra->bdata->lane_owner & BIT(0)) {
                        reg = readl(tegra->padctl_base +
                                padregs->iophy_misc_pad_s0_ctl3_0);
@@ -1761,7 +2303,7 @@ tegra_xhci_padctl_portmap_and_caps(struct tegra_xhci_hcd *tegra)
                                padregs->iophy_misc_pad_s0_ctl3_0);
                }
        }
-       if (XUSB_DEVICE_ID_T124 == tegra->device_id) {
+       if (XUSB_DEVICE_ID_T114 != tegra->device_id) {
                tegra_xhci_setup_gpio_for_ss_lane(tegra);
                usb3_phy_pad_enable(tegra->bdata->lane_owner);
        }
@@ -1900,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)
@@ -1941,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.
@@ -2029,6 +2548,12 @@ 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 */
        if (csb_read(tegra, XUSB_FALC_CPUCTL) == XUSB_FALC_STATE_HALTED)
                return -EFAULT;
@@ -2046,6 +2571,9 @@ static int load_firmware(struct tegra_xhci_hcd *tegra, bool resetARU)
                dev_err(&pdev->dev, "Controller not ready\n");
                return -EFAULT;
        }
+       for_each_enabled_hsic_pad(pad, tegra)
+               hsic_pad_pupd_set(tegra, pad, PUPD_IDLE);
+
        return 0;
 }
 
@@ -2065,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)
@@ -2082,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.
         */
@@ -2163,24 +2695,15 @@ static int tegra_xhci_host_elpg_entry(struct tegra_xhci_hcd *tegra)
        /* STEP 1.1: Do a context save of XUSB and IPFS registers */
        tegra_xhci_save_xusb_ctx(tegra);
 
-       pmc_init(tegra, 1);
+       /* calculate rctrl_val and tctrl_val */
+       tegra_xhci_war_for_tctrl_rctrl(tegra);
+
+       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) {
@@ -2190,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 */
@@ -2281,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 */
@@ -2298,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);
 }
@@ -2312,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)) {
@@ -2332,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)
@@ -2350,71 +2904,67 @@ static void wait_remote_wakeup_ports(struct usb_hcd *hcd)
 static void tegra_xhci_war_for_tctrl_rctrl(struct tegra_xhci_hcd *tegra)
 {
        struct tegra_xusb_padctl_regs *padregs = tegra->padregs;
-       u32 reg, utmip_rctrl_val, utmip_tctrl_val;
+       u32 reg, utmip_rctrl_val, utmip_tctrl_val, pad_mux, portmux, portowner;
 
-       /* Program XUSB as port owner for all usb2 ports */
-       reg = readl(tegra->padctl_base + padregs->usb2_pad_mux_0);
-       reg &= ~(USB2_OTG_PAD_PORT_MASK(0) | USB2_OTG_PAD_PORT_MASK(1) |
-                       USB2_OTG_PAD_PORT_MASK(2));
-       reg |= USB2_OTG_PAD_PORT_OWNER_XUSB(0) |
-               USB2_OTG_PAD_PORT_OWNER_XUSB(1) | USB2_OTG_PAD_PORT_MASK(2);
-       writel(reg, tegra->padctl_base + padregs->usb2_pad_mux_0);
+       portmux = USB2_OTG_PAD_PORT_MASK(0) | USB2_OTG_PAD_PORT_MASK(1);
+       portowner = USB2_OTG_PAD_PORT_OWNER_XUSB(0) |
+                       USB2_OTG_PAD_PORT_OWNER_XUSB(1);
 
-       /* XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0::PD = 0 and
-        * XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0::PD_TRK = 0
-        */
-       reg = readl(tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
-       reg &= ~((1 << 12) | (1 << 13));
-       writel(reg, tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
-
-       /* wait 20us */
-       usleep_range(20, 30);
-
-       /* Read XUSB_PADCTL:: XUSB_PADCTL_USB2_BIAS_PAD_CTL_1_0
-        * :: TCTRL and RCTRL
-        */
-       reg = readl(tegra->padctl_base + padregs->usb2_bias_pad_ctl1_0);
-       utmip_rctrl_val = RCTRL(reg);
-       utmip_tctrl_val = TCTRL(reg);
-
-       /*
-        * 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);
+       if (XUSB_DEVICE_ID_T114 != tegra->device_id) {
+               portmux |= USB2_OTG_PAD_PORT_MASK(2);
+               portowner |= USB2_OTG_PAD_PORT_OWNER_XUSB(2);
+       }
 
-       xhci_dbg(tegra->xhci, "rctrl_val = 0x%x, tctrl_val = 0x%x\n",
-               pmc_data.utmip_rctrl_val, pmc_data.utmip_tctrl_val);
+       /* Use xusb padctl space only when xusb owns all UTMIP port */
+       pad_mux = readl(tegra->padctl_base + padregs->usb2_pad_mux_0);
+       if ((pad_mux & portmux) == portowner) {
+               /* XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0::PD = 0 and
+                * XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0::PD_TRK = 0
+                */
+               reg = readl(tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
+               reg &= ~((1 << 12) | (1 << 13));
+               writel(reg, tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
 
-       /* XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0::PD = 1 and
-        * XUSB_PADCTL_USB2_BIAS_PAD_CTL_0_0::PD_TRK = 1
-        */
-       reg = readl(tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
-       reg |= (1 << 13);
-       writel(reg, tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
+               /* wait 20us */
+               usleep_range(20, 30);
 
-       /* Program these values into PMC regiseter and program the
-        * PMC override
-        */
-       reg = PMC_TCTRL_VAL(pmc_data.utmip_tctrl_val) |
-               PMC_RCTRL_VAL(pmc_data.utmip_rctrl_val);
-       tegra_usb_pmc_reg_update(PMC_UTMIP_TERM_PAD_CFG, 0xffffffff, reg);
+               /* Read XUSB_PADCTL:: XUSB_PADCTL_USB2_BIAS_PAD_CTL_1_0
+                * :: TCTRL and RCTRL
+                */
+               reg = readl(tegra->padctl_base + padregs->usb2_bias_pad_ctl1_0);
+               utmip_rctrl_val = RCTRL(reg);
+               utmip_tctrl_val = TCTRL(reg);
 
-       reg = UTMIP_RCTRL_USE_PMC_P2 | UTMIP_TCTRL_USE_PMC_P2;
-       tegra_usb_pmc_reg_update(PMC_SLEEP_CFG, reg, reg);
+               /*
+                * tctrl_val = 0x1f - (16 - ffz(utmip_tctrl_val)
+                * rctrl_val = 0x1f - (16 - ffz(utmip_rctrl_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",
+                                       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
+                */
+               reg = readl(tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
+               reg |= (1 << 13);
+               writel(reg, tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
 
-       /* Restore correct port ownership in padctl */
-       reg = readl(tegra->padctl_base + padregs->usb2_pad_mux_0);
-       reg &= ~(USB2_OTG_PAD_PORT_MASK(0) | USB2_OTG_PAD_PORT_MASK(1) |
-                       USB2_OTG_PAD_PORT_MASK(2));
-       if (tegra->bdata->portmap & TEGRA_XUSB_USB2_P0)
-               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)
-               reg |= USB2_OTG_PAD_PORT_OWNER_XUSB(2);
-       writel(reg, tegra->padctl_base + padregs->usb2_pad_mux_0);
+               /* Program these values into PMC regiseter and program the
+                * PMC override.
+                */
+               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);
+               reg = UTMIP_RCTRL_USE_PMC_P2 | UTMIP_TCTRL_USE_PMC_P2;
+               tegra_usb_pmc_reg_update(PMC_SLEEP_CFG, reg, reg);
+       } else {
+               /* Use common PMC API to use SNPS register space */
+               utmi_phy_set_snps_trking_data();
+       }
 }
 
 /* Host ELPG Exit triggered by PADCTL irq */
@@ -2439,10 +2989,8 @@ 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);
-       /* Step 2: Enable clock to host partition */
-       clk_enable(tegra->host_clk);
 
        if (tegra->lp0_exit) {
                u32 reg, oc_bits = 0;
@@ -2491,6 +3039,7 @@ tegra_xhci_host_partition_elpg_exit(struct tegra_xhci_hcd *tegra)
                        __func__, ret);
                goto out;
        }
+       clk_enable(tegra->host_clk);
 
        /* Step 4: Deassert reset to host partition clk */
        tegra_periph_reset_deassert(tegra->host_clk);
@@ -2533,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",
@@ -2540,7 +3090,7 @@ tegra_xhci_host_partition_elpg_exit(struct tegra_xhci_hcd *tegra)
                goto out;
        }
 
-       pmc_init(tegra, 0);
+       pmc_disable_bus_ctrl(tegra);
 
        tegra->hc_in_elpg = false;
        ret = xhci_resume(tegra->xhci, 0);
@@ -2550,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;
@@ -2596,26 +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.
@@ -2644,48 +3194,91 @@ 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);
-               /* SATA lane also if USB3_SS port1 mapped to it */
-               if (tegra->cmd_data == 0x1 &&
-                       XUSB_DEVICE_ID_T124 == tegra->device_id &&
-                               tegra->bdata->lane_owner & BIT(0)) {
-                       tegra_xhci_save_dfe_ctle_context(tegra, 3);
-                       tegra_xhci_restore_dfe_ctle_context(tegra, 3);
+               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 = 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);
+                       mutex_unlock(&tegra->sync_lock);
+                       if (ret)
+                               break;
                }
 
-               sw_resp |= (MBOX_CMD_ACK << MBOX_CMD_SHIFT);
+               sw_resp = CMD_DATA(tegra->cmd_data);
+               if (!ret)
+                       sw_resp |= CMD_TYPE(MBOX_CMD_ACK);
+               else
+                       sw_resp |= CMD_TYPE(MBOX_CMD_NACK);
+
                goto send_sw_response;
+
+       case MBOX_CMD_STOP_HSIC_IDLE:
+               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);
+                       mutex_unlock(&tegra->sync_lock);
+                       if (ret)
+                               break;
+               }
+
+               sw_resp = CMD_DATA(tegra->cmd_data);
+               if (!ret)
+                       sw_resp |= CMD_TYPE(MBOX_CMD_ACK);
+               else
+                       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:
+       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);
        cmd |= MBOX_INT_EN | MBOX_FALC_INT_EN;
@@ -2694,12 +3287,12 @@ send_sw_response:
        mutex_unlock(&tegra->mbox_lock);
 }
 
-static irqreturn_t tegra_xhci_xusb_host_irq(int irq, void *ptrdev)
+static irqreturn_t pmc_usb_phy_wake_isr(int irq, void *data)
 {
-       struct tegra_xhci_hcd *tegra = (struct tegra_xhci_hcd *) ptrdev;
+       struct tegra_xhci_hcd *tegra = (struct tegra_xhci_hcd *) data;
        struct xhci_hcd *xhci = tegra->xhci;
 
-       xhci_dbg(xhci, "%s", __func__);
+       xhci_dbg(xhci, "%s irq %d", __func__, irq);
        return IRQ_HANDLED;
 }
 
@@ -2738,8 +3331,11 @@ static irqreturn_t tegra_xhci_padctl_irq(int irq, void *ptrdev)
 
        if (elpg_program0 & (SS_PORT0_WAKEUP_EVENT | SS_PORT1_WAKEUP_EVENT))
                tegra->ss_wake_event = true;
-       else if (elpg_program0 &
-                       (USB2_PORT0_WAKEUP_EVENT | USB2_PORT1_WAKEUP_EVENT))
+       else if (elpg_program0 & (USB2_PORT0_WAKEUP_EVENT |
+                       USB2_PORT1_WAKEUP_EVENT |
+                       USB2_PORT2_WAKEUP_EVENT |
+                       USB2_HSIC_PORT0_WAKEUP_EVENT |
+                       USB2_HSIC_PORT1_WAKEUP_EVENT))
                tegra->hs_wake_event = true;
 
        if (tegra->ss_wake_event || tegra->hs_wake_event) {
@@ -2772,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;
@@ -2790,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;
 }
 
@@ -2801,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;
@@ -2823,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;
        }
 
@@ -2841,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;
@@ -2906,6 +3503,12 @@ static int tegra_xhci_bus_suspend(struct usb_hcd *hcd)
        tegra_xhci_ss_wake_on_interrupts(tegra->bdata->portmap, true);
        tegra_xhci_hs_wake_on_interrupts(tegra->bdata->portmap, true);
 
+       /* In ELPG, firmware log context is gone. Rewind shared log buffer. */
+       if (fw_log_wait_empty_timeout(tegra, 100))
+               xhci_warn(xhci, "%s still has logs\n", __func__);
+       tegra->log.dequeue = tegra->log.virt_addr;
+       tegra->log.seq = 0;
+
 done:
        /* pads are disabled only if usb2 root hub in xusb is idle */
        /* pads will actually be disabled only when all usb2 ports are idle */
@@ -3005,6 +3608,8 @@ static irqreturn_t tegra_xhci_irq(struct usb_hcd *hcd)
                iret = xhci_irq(hcd);
        spin_unlock(&tegra->lock);
 
+       wake_up_interruptible(&tegra->log.intr_wait);
+
        return iret;
 }
 
@@ -3072,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__);
@@ -3080,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) {
@@ -3091,13 +3699,22 @@ tegra_xhci_suspend(struct platform_device *pdev,
                __func__, tegra->padctl_irq, ret);
        }
 
-       /* enable_irq_wake for hs/fs/ls ports */
+       /* enable_irq_wake for utmip/uhisc wakes */
        ret = enable_irq_wake(tegra->usb3_irq);
        if (ret < 0) {
                xhci_err(xhci,
-               "%s: Couldn't enable USB host mode wakeup, irq=%d, error=%d\n",
+               "%s: Couldn't enable utmip/uhsic wakeup, irq=%d, error=%d\n",
                __func__, tegra->usb3_irq, ret);
        }
+
+       /* enable_irq_wake for utmip/uhisc wakes */
+       ret = enable_irq_wake(tegra->usb2_irq);
+       if (ret < 0) {
+               xhci_err(xhci,
+               "%s: Couldn't enable utmip/uhsic wakeup, irq=%d, error=%d\n",
+               __func__, tegra->usb2_irq, ret);
+       }
+
        regulator_disable(tegra->xusb_s1p8v_reg);
        regulator_disable(tegra->xusb_s1p05v_reg);
        tegra_usb2_clocks_deinit(tegra);
@@ -3109,13 +3726,24 @@ 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);
        disable_irq_wake(tegra->usb3_irq);
+       disable_irq_wake(tegra->usb2_irq);
        tegra->lp0_exit = true;
 
        regulator_enable(tegra->xusb_s1p05v_reg);
@@ -3126,95 +3754,136 @@ 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;
+       }
 
-static int init_bootloader_firmware(struct tegra_xhci_hcd *tegra)
+       return ret;
+}
+
+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,
+               struct platform_device *pdev)
+{
+       int err = 0;
+       /* enable ss clock */
+       err = clk_enable(tegra->host_clk);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to enable host partition clk\n");
+               goto enable_host_clk_failed;
+       }
+
+       err = clk_enable(tegra->ss_clk);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to enable ss partition clk\n");
+               goto eanble_ss_clk_failed;
+       }
+
+       err = clk_enable(tegra->emc_clk);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to enable xusb.emc clk\n");
+               goto eanble_emc_clk_failed;
+       }
+
+       return 0;
+
+eanble_emc_clk_failed:
+       clk_disable(tegra->ss_clk);
+
+eanble_ss_clk_failed:
+       clk_disable(tegra->host_clk);
+
+enable_host_clk_failed:
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
+               clk_disable(tegra->pll_re_vco_clk);
+       return err;
 }
 
 static struct tegra_xusb_padctl_regs t114_padregs_offset = {
@@ -3399,17 +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]);
+
+               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;
-       u32 pmc_reg, val;
+       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);
 
@@ -3421,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;
@@ -3451,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;
        }
 
@@ -3477,16 +4417,22 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        if (ret)
                dev_err(&pdev->dev, "could not unpowergate xusbc partition\n");
 
+       ret = tegra_enable_xusb_clk(tegra, pdev);
+       if (ret)
+               dev_err(&pdev->dev, "could not enable partition clock\n");
+
        /* 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));
@@ -3516,7 +4462,12 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        }
 
        /* calculate rctrl_val and tctrl_val once at boot time */
-       tegra_xhci_war_for_tctrl_rctrl(tegra);
+       /* Issue is only applicable for T114 */
+       if (XUSB_DEVICE_ID_T114 == tegra->device_id)
+               tegra_xhci_war_for_tctrl_rctrl(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);
@@ -3529,20 +4480,50 @@ 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;
        }
+       pmc_init(tegra);
 
        device_init_wakeup(&pdev->dev, 1);
        driver = &tegra_plat_xhci_driver;
@@ -3550,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) {
@@ -3581,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) {
@@ -3603,16 +4595,11 @@ static int tegra_xhci_probe(struct platform_device *pdev)
 
        device_init_wakeup(&hcd->self.root_hub->dev, 1);
        device_init_wakeup(&xhci->shared_hcd->self.root_hub->dev, 1);
-       spin_lock_init(&tegra->lock);
-       mutex_init(&tegra->sync_lock);
-       mutex_init(&tegra->mbox_lock);
 
        /* do mailbox related initializations */
        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);
 
@@ -3622,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;
@@ -3631,39 +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, "usb3", tegra_xhci_xusb_host_irq,
-                       IRQF_SHARED | IRQF_TRIGGER_HIGH, "xusb_host_irq",
-                       &tegra->usb3_irq);
+       /* 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;
 
-       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;
+       /* 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;
 
-       /* reset wake event to NONE */
-       pmc_reg = tegra_usb_pmc_reg_read(PMC_UTMIP_UHSIC_SLEEP_CFG_0);
-       pmc_reg |= UTMIP_WAKE_VAL(0, WAKE_VAL_NONE);
-       pmc_reg |= UTMIP_WAKE_VAL(1, WAKE_VAL_NONE);
-       pmc_reg |= UTMIP_WAKE_VAL(2, WAKE_VAL_NONE);
-       pmc_reg |= UTMIP_WAKE_VAL(3, WAKE_VAL_NONE);
-       tegra_usb_pmc_reg_write(PMC_UTMIP_UHSIC_SLEEP_CFG_0, pmc_reg);
+       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;
 
@@ -3676,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;
 }
@@ -3691,33 +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);
 
-       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);
+       for_each_enabled_hsic_pad(pad, tegra) {
+               hsic_pad_disable(tegra, pad);
+               hsic_power_rail_disable(tegra);
+       }
+
+       if (tegra->init_done) {
+               struct xhci_hcd *xhci = NULL;
+               struct usb_hcd *hcd = NULL;
+
+               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;
 }
 
@@ -3731,16 +4738,12 @@ static void tegra_xhci_shutdown(struct platform_device *pdev)
                return;
 
        if (tegra->hc_in_elpg) {
-               mutex_lock(&tegra->sync_lock);
-               tegra_xhci_host_partition_elpg_exit(tegra);
-               mutex_unlock(&tegra->sync_lock);
+               pmc_disable_bus_ctrl(tegra);
+       } else {
+               xhci = tegra->xhci;
+               hcd = xhci_to_hcd(xhci);
+               xhci_shutdown(hcd);
        }
-
-       fw_log_deinit(tegra);
-
-       xhci = tegra->xhci;
-       hcd = xhci_to_hcd(xhci);
-       xhci_shutdown(hcd);
 }
 
 static struct platform_driver tegra_xhci_driver = {
@@ -3753,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");