usb: xhci: tegra: fix compilation with lockdep enabled
[linux-3.10.git] / drivers / usb / host / xhci-tegra.c
index 16864a7..da83737 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * xhci-tegra.c - Nvidia xHCI host controller driver
  *
- * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2013-2014, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
 #include <linux/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/tegra_usb_pad_ctrl.h>
 #include <mach/tegra_usb_pmc.h>
-#include <mach/pm_domains.h>
 #include <mach/mc.h>
 #include <mach/xusb.h>
 
-#include "../../../arch/arm/mach-tegra/iomap.h" /* HACK -- remove */
 #include "xhci-tegra.h"
 #include "xhci.h"
+#include "../../../arch/arm/mach-tegra/iomap.h"
 
 /* macros */
 #define FW_IOCTL_LOG_DEQUEUE_LOW       (4)
        dev_dbg(_dev, "%s: %s @%x = 0x%x\n", __func__, #_reg,           \
                _reg, readl(_base + _reg))
 
-/* PMC register definition */
-#define PMC_PORT_UTMIP_P0              0
-#define PMC_PORT_UTMIP_P1              1
-#define PMC_PORT_UTMIP_P2              2
-#define PMC_PORT_UHSIC_P0              3
-#define PMC_PORT_NUM                   4
+#define PMC_PORTMAP_MASK(map, pad)     (((map) >> 4*(pad)) & 0xF)
+#define GET_SS_PORTMAP(map, p)         (((map) >> 4*(p)) & 0xF)
 
 #define PMC_USB_DEBOUNCE_DEL_0                 0xec
 #define   UTMIP_LINE_DEB_CNT(x)                (((x) & 0xf) << 16)
@@ -178,7 +180,8 @@ struct cfgtbl {
        u8 magic[8];
        u32 SS_low_power_entry_timeout;
        u8 num_hsic_port;
-       u8 padding[139]; /* padding bytes to makeup 256-bytes cfgtbl */
+       u8 ss_portmap;
+       u8 padding[138]; /* padding bytes to makeup 256-bytes cfgtbl */
 };
 
 struct xusb_save_regs {
@@ -348,6 +351,7 @@ struct tegra_xhci_hcd {
        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;
@@ -356,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;
@@ -411,13 +418,30 @@ struct tegra_xhci_hcd {
        struct tegra_xhci_firmware firmware;
 
        struct tegra_xhci_firmware_log log;
+       struct device_attribute hsic_power_attr[XUSB_HSIC_COUNT];
+
+       bool init_done;
 };
 
+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)
 {
@@ -550,9 +574,14 @@ static void pmc_init(struct tegra_xhci_hcd *tegra)
                if (BIT(XUSB_UTMI_INDEX + pad) & tegra->bdata->portmap) {
                        dev_dbg(dev, "%s utmi pad %d\n", __func__, pad);
                        pmc = &pmc_data[pad];
-                       pmc->instance = 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_HIGH;
+                       pmc->port_speed = USB_PMC_PORT_SPEED_UNKNOWN;
                        pmc->controller_type = TEGRA_USB_3_0;
                        tegra_usb_pmc_init(pmc);
                }
@@ -790,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)
@@ -1035,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;
@@ -1128,7 +1159,8 @@ static void fw_log_deinit(struct tegra_xhci_hcd *tegra)
 static int hsic_power_rail_enable(struct tegra_xhci_hcd *tegra)
 {
        struct device *dev = &tegra->pdev->dev;
-       struct tegra_xusb_regulator_name *supply = &tegra->pdata->bdata->supply;
+       const struct tegra_xusb_regulator_name *supply =
+                               &tegra->soc_config->supply;
        int ret;
 
        if (tegra->vddio_hsic_reg)
@@ -1224,6 +1256,14 @@ static int hsic_pad_enable(struct tegra_xhci_hcd *tegra, unsigned pad)
        reg &= ~(PD_RX | HSIC_PD_ZI | PD_TRX | PD_TX);
        writel(reg, base + HSIC_PAD_CTL_1(pad));
 
+       /* Wait for 25 us */
+       usleep_range(25, 50);
+
+       /* Power down tracking circuit */
+       reg = readl(base + HSIC_PAD_CTL_1(pad));
+       reg |= PD_TRX;
+       writel(reg, base + HSIC_PAD_CTL_1(pad));
+
        reg = readl(base + HSIC_STRB_TRIM_CONTROL);
        reg &= ~(STRB_TRIM_VAL(~0));
        reg |= STRB_TRIM_VAL(hsic->strb_trim_val);
@@ -1448,7 +1488,8 @@ 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;
 
@@ -1614,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");
@@ -1663,7 +1704,7 @@ static int tegra_xusb_partitions_clk_init(struct tegra_xhci_hcd *tegra)
                goto get_ss_clk_failed;
        }
 
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2) {
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2) {
                err = clk_enable(tegra->pll_re_vco_clk);
                if (err) {
                        dev_err(&pdev->dev, "Failed to enable refPLLE clk\n");
@@ -1688,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:
@@ -1701,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;
 }
 
@@ -1780,7 +1821,7 @@ 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) {
+       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;
        }
@@ -1827,6 +1868,14 @@ tegra_xusb_request_clk_rate(struct tegra_xhci_hcd *tegra,
        return ret;
 }
 
+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)
 {
@@ -2060,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);
@@ -2074,8 +2123,8 @@ 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*/
@@ -2108,12 +2157,12 @@ 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);
@@ -2122,7 +2171,7 @@ static void tegra_xhci_program_ss_pad(struct tegra_xhci_hcd *tegra,
 
        reg = readl(tegra->padctl_base + MISC_PAD_CTL_2_0(port));
        reg &= ~SPARE_IN(~0);
-       reg |= SPARE_IN(tegra->pdata->spare_in);
+       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)) {
@@ -2132,7 +2181,7 @@ static void tegra_xhci_program_ss_pad(struct tegra_xhci_hcd *tegra,
 
                reg = readl(tegra->padctl_base + MISC_PAD_S0_CTL_2_0);
                reg &= ~SPARE_IN(~0);
-               reg |= SPARE_IN(tegra->pdata->spare_in);
+               reg |= SPARE_IN(tegra->soc_config->spare_in);
                writel(reg, tegra->padctl_base + MISC_PAD_S0_CTL_2_0);
        }
 
@@ -2142,6 +2191,14 @@ static void tegra_xhci_program_ss_pad(struct tegra_xhci_hcd *tegra,
                (port ? TEGRA_XUSB_SS1_PORT_MAP : TEGRA_XUSB_SS0_PORT_MAP));
        writel(reg, tegra->padctl_base + padregs->ss_port_map_0);
 
+       /* 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);
 }
@@ -2159,7 +2216,7 @@ tegra_xhci_padctl_portmap_and_caps(struct tegra_xhci_hcd *tegra)
 
        reg = readl(tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
        reg &= ~(USB2_BIAS_HS_SQUELCH_LEVEL | USB2_BIAS_HS_DISCON_LEVEL);
-       reg |= tegra->pdata->hs_squelch_level | tegra->pdata->hs_disc_lvl;
+       reg |= tegra->cdata->hs_squelch_level | tegra->soc_config->hs_disc_lvl;
        writel(reg, tegra->padctl_base + padregs->usb2_bias_pad_ctl0_0);
 
        reg = readl(tegra->padctl_base + padregs->snps_oc_map_0);
@@ -2401,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.
@@ -2489,6 +2548,10 @@ static int load_firmware(struct tegra_xhci_hcd *tegra, bool resetARU)
                fw_tm.tm_min, fw_tm.tm_sec,
                csb_read(tegra, XUSB_FALC_CPUCTL));
 
+       cfg_tbl->num_hsic_port = 0;
+       for_each_enabled_hsic_pad(pad, tegra)
+               cfg_tbl->num_hsic_port++;
+
        dev_dbg(&pdev->dev, "num_hsic_port %d\n", cfg_tbl->num_hsic_port);
 
        /* return fail if firmware status is not good */
@@ -2508,14 +2571,8 @@ static int load_firmware(struct tegra_xhci_hcd *tegra, bool resetARU)
                dev_err(&pdev->dev, "Controller not ready\n");
                return -EFAULT;
        }
-
-       /* TODO move this into firmware to avoid race */
-       writel(0x0, tegra->fpci_base + XUSB_CFG_ARU_C11PAGESEL0);
-       writel(0x1000, tegra->fpci_base + XUSB_CFG_ARU_C11PAGESEL1);
-       writel(0x10, tegra->fpci_base + XUSB_CFG_HSPX_CORE_HSICWRAP);
-       reg_dump(&pdev->dev, tegra->fpci_base, XUSB_CFG_ARU_C11PAGESEL0);
-       reg_dump(&pdev->dev, tegra->fpci_base, XUSB_CFG_ARU_C11PAGESEL1);
-       reg_dump(&pdev->dev, tegra->fpci_base, XUSB_CFG_HSPX_CORE_HSICWRAP);
+       for_each_enabled_hsic_pad(pad, tegra)
+               hsic_pad_pupd_set(tegra, pad, PUPD_IDLE);
 
        return 0;
 }
@@ -2554,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.
         */
@@ -2655,7 +2715,7 @@ static int tegra_xhci_host_elpg_entry(struct tegra_xhci_hcd *tegra)
        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 */
@@ -2845,7 +2905,6 @@ 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, pad_mux, portmux, portowner;
-       int port;
 
        portmux = USB2_OTG_PAD_PORT_MASK(0) | USB2_OTG_PAD_PORT_MASK(1);
        portowner = USB2_OTG_PAD_PORT_OWNER_XUSB(0) |
@@ -2930,7 +2989,7 @@ tegra_xhci_host_partition_elpg_exit(struct tegra_xhci_hcd *tegra)
                return 0;
 
        clk_enable(tegra->emc_clk);
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
                clk_enable(tegra->pll_re_vco_clk);
 
        if (tegra->lp0_exit) {
@@ -3023,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",
@@ -3086,9 +3146,9 @@ 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);
 
@@ -3134,19 +3194,14 @@ 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_context(tegra, tegra->cmd_data);
                tegra_xhci_save_ctle_context(tegra, tegra->cmd_data);
@@ -3168,7 +3223,7 @@ tegra_xhci_process_mbox_message(struct work_struct *work)
                if (!ret)
                        sw_resp |= CMD_TYPE(MBOX_CMD_ACK);
                else
-                       sw_resp |= CMD_TYPE(MBOX_CMD_ACK);
+                       sw_resp |= CMD_TYPE(MBOX_CMD_NACK);
 
                goto send_sw_response;
 
@@ -3191,24 +3246,38 @@ tegra_xhci_process_mbox_message(struct work_struct *work)
                goto send_sw_response;
 
        case MBOX_CMD_ACK:
-               writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
-               writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
+               xhci_dbg(xhci, "%s firmware responds with ACK\n", __func__);
                break;
        case MBOX_CMD_NACK:
-               writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
-               writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
+               xhci_warn(xhci, "%s firmware responds with NACK\n", __func__);
                break;
        default:
                xhci_err(xhci, "%s: invalid cmdtype %d\n",
                                __func__, tegra->cmd_type);
        }
+
+       /* clear MBOX_SMI_INT_EN bit */
+       cmd = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
+       cmd &= ~MBOX_SMI_INT_EN;
+       writel(cmd, tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
+
+       /* clear mailbox ownership */
+       writel(0, tegra->fpci_base + XUSB_CFG_ARU_MBOX_OWNER);
+
        mutex_unlock(&tegra->mbox_lock);
        return;
 
 send_sw_response:
-       if (((sw_resp >> CMD_TYPE_SHIFT) & CMD_TYPE_MASK) == MBOX_CMD_NACK)
-               xhci_err(xhci, "%s respond fw message 0x%x with NAK\n",
-                               __func__, fw_msg);
+       response = (sw_resp >> CMD_TYPE_SHIFT) & CMD_TYPE_MASK;
+       if (response == MBOX_CMD_NACK)
+               xhci_warn(xhci, "%s respond fw message 0x%x with NACK\n",
+                       __func__, fw_msg);
+       else if (response == MBOX_CMD_ACK)
+               xhci_dbg(xhci, "%s respond fw message 0x%x with ACK\n",
+                       __func__, fw_msg);
+       else
+               xhci_err(xhci, "%s respond fw message 0x%x with %d\n",
+               __func__, fw_msg, response);
 
        writel(sw_resp, tegra->fpci_base + XUSB_CFG_ARU_MBOX_DATA_IN);
        cmd = readl(tegra->fpci_base + XUSB_CFG_ARU_MBOX_CMD);
@@ -3299,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;
@@ -3317,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;
 }
 
@@ -3328,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;
@@ -3350,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;
        }
 
@@ -3368,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;
@@ -3607,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__);
@@ -3615,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) {
@@ -3653,9 +3726,19 @@ static int
 tegra_xhci_resume(struct platform_device *pdev)
 {
        struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+       struct xhci_hcd *xhci = tegra->xhci;
 
        dev_dbg(&pdev->dev, "%s\n", __func__);
 
+       mutex_lock(&tegra->sync_lock);
+       if (!tegra->init_done) {
+               xhci_warn(xhci, "%s: xhci probe not done\n",
+                               __func__);
+               mutex_unlock(&tegra->sync_lock);
+               return -EBUSY;
+       }
+       mutex_unlock(&tegra->sync_lock);
+
        tegra->last_jiffies = jiffies;
 
        disable_irq_wake(tegra->padctl_irq);
@@ -3671,98 +3754,99 @@ tegra_xhci_resume(struct platform_device *pdev)
 }
 #endif
 
+static int init_filesystem_firmware(struct tegra_xhci_hcd *tegra)
+{
+       struct platform_device *pdev = tegra->pdev;
+       int ret;
+
+       ret = request_firmware_nowait(THIS_MODULE, true, firmware_file,
+               &pdev->dev, GFP_KERNEL, tegra, init_filesystem_firmware_done);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "request_firmware failed %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
 
-static int init_bootloader_firmware(struct tegra_xhci_hcd *tegra)
+static void init_filesystem_firmware_done(const struct firmware *fw,
+                                       void *context)
 {
+       struct tegra_xhci_hcd *tegra = context;
        struct platform_device *pdev = tegra->pdev;
-       void __iomem *fw_mmio_base;
-       phys_addr_t fw_mem_phy_addr;
+       struct cfgtbl *fw_cfgtbl;
        size_t fw_size;
+       void *fw_data;
        dma_addr_t fw_dma;
-#ifdef CONFIG_PLATFORM_ENABLE_IOMMU
        int ret;
-       DEFINE_DMA_ATTRS(attrs);
-#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
-       dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
-       fw_dma = dma_map_linear_attrs(&pdev->dev, fw_mem_phy_addr, fw_size,
-                       DMA_TO_DEVICE, &attrs);
-
-       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,
@@ -3797,7 +3881,7 @@ eanble_ss_clk_failed:
        clk_disable(tegra->host_clk);
 
 enable_host_clk_failed:
-       if (tegra->pdata->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
+       if (tegra->soc_config->quirks & TEGRA_XUSB_USE_HS_SRC_CLOCK2)
                clk_disable(tegra->pll_re_vco_clk);
        return err;
 }
@@ -4002,19 +4086,208 @@ static int tegra_xhci_otg_notify(struct notifier_block *nb,
        return NOTIFY_OK;
 }
 
+static void tegra_xusb_read_board_data(struct tegra_xhci_hcd *tegra)
+{
+       struct tegra_xusb_board_data *bdata = tegra->bdata;
+       struct device_node *node = tegra->pdev->dev.of_node;
+       int ret;
+
+       bdata->uses_external_pmic = of_property_read_bool(node,
+                                       "nvidia,uses_external_pmic");
+       bdata->gpio_controls_muxed_ss_lanes = of_property_read_bool(node,
+                                       "nvidia,gpio_controls_muxed_ss_lanes");
+       ret = of_property_read_u32(node, "nvidia,gpio_ss1_sata",
+                                       &bdata->gpio_ss1_sata);
+       ret = of_property_read_u32(node, "nvidia,portmap",
+                                       &bdata->portmap);
+       ret = of_property_read_u32(node, "nvidia,ss_portmap",
+                                       (u32 *) &bdata->ss_portmap);
+       ret = of_property_read_u32(node, "nvidia,lane_owner",
+                                       (u32 *) &bdata->lane_owner);
+       ret = of_property_read_u32(node, "nvidia,ulpicap",
+                                       (u32 *) &bdata->ulpicap);
+       ret = of_property_read_u8_array(node, "nvidia,hsic0",
+                                       (u8 *) &bdata->hsic[0],
+                                       sizeof(bdata->hsic[0]));
+       ret = of_property_read_u8_array(node, "nvidia,hsic1",
+                                       (u8 *) &bdata->hsic[1],
+                                       sizeof(bdata->hsic[0]));
+       /* TODO: Add error conditions check */
+}
+
+static void tegra_xusb_read_calib_data(struct tegra_xhci_hcd *tegra)
+{
+       u32 usb_calib0 = tegra_fuse_readl(FUSE_SKU_USB_CALIB_0);
+       struct tegra_xusb_chip_calib *cdata = tegra->cdata;
+
+       pr_info("tegra_xusb_read_usb_calib: usb_calib0 = 0x%08x\n", usb_calib0);
+       /*
+        * read from usb_calib0 and pass to driver
+        * set HS_CURR_LEVEL (PAD0)     = usb_calib0[5:0]
+        * set TERM_RANGE_ADJ           = usb_calib0[10:7]
+        * set HS_SQUELCH_LEVEL         = usb_calib0[12:11]
+        * set HS_IREF_CAP              = usb_calib0[14:13]
+        * set HS_CURR_LEVEL (PAD1)     = usb_calib0[20:15]
+        */
+
+       cdata->hs_curr_level_pad0 = (usb_calib0 >> 0) & 0x3f;
+       cdata->hs_term_range_adj = (usb_calib0 >> 7) & 0xf;
+       cdata->hs_squelch_level = (usb_calib0 >> 11) & 0x3;
+       cdata->hs_iref_cap = (usb_calib0 >> 13) & 0x3;
+       cdata->hs_curr_level_pad1 = (usb_calib0 >> 15) & 0x3f;
+       cdata->hs_curr_level_pad2 = (usb_calib0 >> 15) & 0x3f;
+}
+
+static const struct tegra_xusb_soc_config tegra114_soc_config = {
+       .pmc_portmap = (TEGRA_XUSB_UTMIP_PMC_PORT0 << 0) |
+                       (TEGRA_XUSB_UTMIP_PMC_PORT2 << 4),
+       .quirks = TEGRA_XUSB_USE_HS_SRC_CLOCK2,
+       .rx_wander = (0x3 << 4),
+       .rx_eq = (0x3928 << 8),
+       .cdr_cntl = (0x26 << 24),
+       .dfe_cntl = 0x002008EE,
+       .hs_slew = (0xE << 6),
+       .ls_rslew_pad0 = (0x3 << 14),
+       .ls_rslew_pad1 = (0x0 << 14),
+       .hs_disc_lvl = (0x7 << 2),
+       .spare_in = 0x0,
+       .supply = {
+               .utmi_vbuses = {"usb_vbus0", "usb_vbus1", "usb_vbus2",},
+               .s3p3v = "hvdd_usb",
+               .s1p8v = "avdd_usb_pll",
+               .vddio_hsic = "vddio_hsic",
+               .s1p05v = "avddio_usb",
+       },
+};
+
+static const struct tegra_xusb_soc_config tegra124_soc_config = {
+       .pmc_portmap = (TEGRA_XUSB_UTMIP_PMC_PORT0 << 0) |
+                       (TEGRA_XUSB_UTMIP_PMC_PORT1 << 4) |
+                       (TEGRA_XUSB_UTMIP_PMC_PORT2 << 8),
+       .rx_wander = (0xF << 4),
+       .rx_eq = (0xF070 << 8),
+       .cdr_cntl = (0x26 << 24),
+       .dfe_cntl = 0x002008EE,
+       .hs_slew = (0xE << 6),
+       .ls_rslew_pad0 = (0x3 << 14),
+       .ls_rslew_pad1 = (0x0 << 14),
+       .ls_rslew_pad2 = (0x0 << 14),
+       .hs_disc_lvl = (0x7 << 2),
+       .spare_in = 0x1,
+       .supply = {
+               .utmi_vbuses = {"usb_vbus0", "usb_vbus1", "usb_vbus2",},
+               .s3p3v = "hvdd_usb",
+               .s1p8v = "avdd_pll_utmip",
+               .vddio_hsic = "vddio_hsic",
+               .s1p05v = "avddio_usb",
+       },
+};
+
+static struct of_device_id tegra_xhci_of_match[] = {
+       { .compatible = "nvidia,tegra114-xhci", .data = &tegra114_soc_config },
+       { .compatible = "nvidia,tegra124-xhci", .data = &tegra124_soc_config },
+       { },
+};
+
+static ssize_t hsic_power_show(struct device *dev,
+                       struct kobj_attribute *attr, char *buf)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+       int pad;
+
+       for_each_enabled_hsic_pad(pad, tegra) {
+               if (&tegra->hsic_power_attr[pad] == attr)
+                       return sprintf(buf, "%d\n", pad);
+       }
+
+       return sprintf(buf, "-1\n");
+}
+
+static ssize_t hsic_power_store(struct device *dev,
+                       struct kobj_attribute *attr, const char *buf, size_t n)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+       enum MBOX_CMD_TYPE msg;
+       unsigned int on;
+       int pad, port;
+       int ret;
+
+       if (sscanf(buf, "%u", &on) != 1)
+               return -EINVAL;
+
+       if (on)
+               msg = MBOX_CMD_AIRPLANE_MODE_DISABLED;
+       else
+               msg = MBOX_CMD_AIRPLANE_MODE_ENABLED;
+
+       for_each_enabled_hsic_pad(pad, tegra) {
+               port = hsic_pad_to_port(pad);
+
+               if (&tegra->hsic_power_attr[pad] == attr) {
+                       hsic_pad_pupd_set(tegra, pad, PUPD_IDLE);
+                       ret = fw_message_send(tegra, msg, BIT(port + 1));
+               }
+       }
+
+       return n;
+}
+
+static void hsic_power_remove_file(struct tegra_xhci_hcd *tegra)
+{
+       struct device *dev = &tegra->pdev->dev;
+       int p;
+
+       for_each_enabled_hsic_pad(p, tegra) {
+               if (attr_name(tegra->hsic_power_attr[p])) {
+                       device_remove_file(dev, &tegra->hsic_power_attr[p]);
+                       kzfree(attr_name(tegra->hsic_power_attr[p]));
+               }
+       }
+
+}
+
+static int hsic_power_create_file(struct tegra_xhci_hcd *tegra)
+{
+       struct device *dev = &tegra->pdev->dev;
+       int p;
+       int err;
+
+       for_each_enabled_hsic_pad(p, tegra) {
+               attr_name(tegra->hsic_power_attr[p]) = kzalloc(16, GFP_KERNEL);
+               if (!attr_name(tegra->hsic_power_attr[p]))
+                       return -ENOMEM;
+
+               snprintf(attr_name(tegra->hsic_power_attr[p]), 16,
+                       "hsic%d_power", p);
+               tegra->hsic_power_attr[p].show = hsic_power_show;
+               tegra->hsic_power_attr[p].store = hsic_power_store;
+               tegra->hsic_power_attr[p].attr.mode = (S_IRUGO | S_IWUSR);
+               sysfs_attr_init(&tegra->hsic_power_attr[p].attr);
+
+               err = device_create_file(dev, &tegra->hsic_power_attr[p]);
+               if (err) {
+                       kzfree(attr_name(tegra->hsic_power_attr[p]));
+                       attr_name(tegra->hsic_power_attr[p]) = 0;
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
 /* TODO: we have to refine error handling in tegra_xhci_probe() */
 static int tegra_xhci_probe(struct platform_device *pdev)
 {
-       const struct hc_driver *driver;
-       struct xhci_hcd *xhci;
        struct tegra_xhci_hcd *tegra;
        struct resource *res;
-       struct usb_hcd  *hcd;
        unsigned pad;
-       unsigned port;
        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);
 
@@ -4026,9 +4299,51 @@ 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;
@@ -4036,20 +4351,22 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        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;
@@ -4067,19 +4384,19 @@ static int tegra_xhci_probe(struct platform_device *pdev)
                if (IS_ERR_OR_NULL(tegra->transceiver)) {
                        dev_err(&pdev->dev, "failed to get usb phy\n");
                        tegra->transceiver = NULL;
-               } else {
-                       otg_set_host(tegra->transceiver->otg, &hcd->self);
-                       tegra->otgnb.notifier_call = tegra_xhci_otg_notify;
-                       usb_register_notifier(tegra->transceiver,
-                               &tegra->otgnb);
                }
        }
+
        /* 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;
        }
 
@@ -4107,13 +4424,15 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        /* reset the pointer back to NULL. driver uses it */
        /* platform_set_drvdata(pdev, NULL); */
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "host");
+       /* request resource host base address */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(&pdev->dev, "mem resource host doesn't exist\n");
                ret = -ENODEV;
                goto err_deinit_usb2_clocks;
        }
        tegra->host_phy_base = res->start;
+       tegra->host_phy_size = resource_size(res);
 
        tegra->host_phy_virt_base = devm_ioremap(&pdev->dev,
                                res->start, resource_size(res));
@@ -4161,24 +4480,49 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        tegra_periph_reset_deassert(tegra->host_clk);
        tegra_periph_reset_deassert(tegra->ss_clk);
 
+       platform_set_drvdata(pdev, tegra);
        fw_log_init(tegra);
        ret = init_firmware(tegra);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to init firmware\n");
                ret = -ENODEV;
-               goto err_deinit_usb2_clocks;
+               goto err_deinit_firmware_log;
        }
 
-       ret = load_firmware(tegra, true /* do reset ARU */);
+       return 0;
+
+err_deinit_firmware_log:
+       fw_log_deinit(tegra);
+err_deinit_usb2_clocks:
+       tegra_usb2_clocks_deinit(tegra);
+err_deinit_tegra_xusb_regulator:
+       tegra_xusb_regulator_deinit(tegra);
+err_deinit_xusb_partition_clk:
+       if (tegra->transceiver)
+               usb_unregister_notifier(tegra->transceiver, &tegra->otgnb);
+
+       tegra_xusb_partitions_clk_deinit(tegra);
+
+       return ret;
+}
+
+static int tegra_xhci_probe2(struct tegra_xhci_hcd *tegra)
+{
+       struct platform_device *pdev = tegra->pdev;
+       const struct hc_driver *driver;
+       int ret;
+       struct resource *res;
+       int irq;
+       struct xhci_hcd *xhci;
+       struct usb_hcd  *hcd;
+       unsigned port;
+
+
+       ret = load_firmware(tegra, false /* do reset ARU */);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to load firmware\n");
-               ret = -ENODEV;
-               goto err_deinit_firmware;
+               return -ENODEV;
        }
-
-       spin_lock_init(&tegra->lock);
-       mutex_init(&tegra->sync_lock);
-       mutex_init(&tegra->mbox_lock);
        pmc_init(tegra);
 
        device_init_wakeup(&pdev->dev, 1);
@@ -4187,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) {
@@ -4218,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) {
@@ -4245,8 +4600,6 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        tegra->mbox_owner = 0xffff;
        INIT_WORK(&tegra->mbox_work, tegra_xhci_process_mbox_message);
 
-       tegra_xhci_enable_fw_message(tegra);
-
        /* do ss partition elpg exit related initialization */
        INIT_WORK(&tegra->ss_elpg_exit_work, ss_partition_elpg_exit_work);
 
@@ -4256,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;
@@ -4265,19 +4619,21 @@ static int tegra_xhci_probe(struct platform_device *pdev)
         * handle wake on connect irqs interrupt from
         * firmware
         */
-       ret = tegra_xhci_request_irq(pdev, "padctl", tegra_xhci_padctl_irq,
+       ret = tegra_xhci_request_irq(pdev, 2, tegra_xhci_padctl_irq,
                        IRQF_SHARED | IRQF_TRIGGER_HIGH,
                        "tegra_xhci_padctl_irq", &tegra->padctl_irq);
        if (ret != 0)
                goto err_remove_usb3_hcd;
 
-       ret = tegra_xhci_request_irq(pdev, "usb2", pmc_usb_phy_wake_isr,
+       /* Register interrupt wake handler for USB2 */
+       ret = tegra_xhci_request_irq(pdev, 4, pmc_usb_phy_wake_isr,
                IRQF_SHARED | IRQF_TRIGGER_HIGH, "pmc_usb_phy_wake_isr",
                &tegra->usb2_irq);
        if (ret != 0)
                goto err_remove_usb3_hcd;
 
-       ret = tegra_xhci_request_irq(pdev, "usb3", pmc_usb_phy_wake_isr,
+       /* Register interrupt wake handler for USB3 */
+       ret = tegra_xhci_request_irq(pdev, 3, pmc_usb_phy_wake_isr,
                IRQF_SHARED | IRQF_TRIGGER_HIGH, "pmc_usb_phy_wake_isr",
                &tegra->usb3_irq);
        if (ret != 0)
@@ -4288,6 +4644,7 @@ static int tegra_xhci_probe(struct platform_device *pdev)
                tegra->dfe_ctx_saved[port] = false;
        }
 
+       tegra_xhci_enable_fw_message(tegra);
        hsic_pad_pretend_connect(tegra);
 
        tegra_xhci_debug_read_pads(tegra);
@@ -4295,6 +4652,10 @@ static int tegra_xhci_probe(struct platform_device *pdev)
        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;
 
@@ -4307,17 +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:
-       if (tegra->transceiver)
-               usb_unregister_notifier(tegra->transceiver, &tegra->otgnb);
-
-       tegra_xusb_partitions_clk_deinit(tegra);
 
        return ret;
 }
@@ -4325,32 +4675,38 @@ err_deinit_xusb_partition_clk:
 static int tegra_xhci_remove(struct platform_device *pdev)
 {
        struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
-       struct xhci_hcd *xhci = NULL;
-       struct usb_hcd *hcd = NULL;
        unsigned pad;
 
        if (tegra == NULL)
                return -EINVAL;
 
-       xhci = tegra->xhci;
-       hcd = xhci_to_hcd(xhci);
+       mutex_lock(&tegra->sync_lock);
 
        for_each_enabled_hsic_pad(pad, tegra) {
                hsic_pad_disable(tegra, pad);
                hsic_power_rail_disable(tegra);
        }
 
-       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);
+       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)
@@ -4359,10 +4715,16 @@ static int tegra_xhci_remove(struct platform_device *pdev)
        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;
 }
 
@@ -4394,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");