linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/10] Tegra XHCI support
@ 2014-05-15  0:32 Andrew Bresticker
  2014-05-15  0:32 ` [RFC PATCH 01/10] clk: tegra: Enable hardware control of PLLE Andrew Bresticker
                   ` (10 more replies)
  0 siblings, 11 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:32 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Andrew Bresticker

This is a first pass at the host and PHY drivers necessary for USB3.0
support on Tegra114 and Tegra124.  The Tegra XHCI host controller requires
external firmware [1] which must be loaded before using any USB ports owned
by the controller.  The XUSB PHY driver handles mapping and enabling of
the UTMI, HSIC, and SuperSpeed pads to the XHCI controller.

Tested on a Venice2 with a variety of USB2.0 and USB3.0 memory sticks
and ethernet dongles.  

Notes:
 - I've included support for Tegra114, but since I don't have Tegra114-based
   hardware, it is completely untested.
 - The PCIe and SATA PHYs also are programmed using the XUSB_PADCTL space
   as well.  At least some of the code can be re-used, specifically with
   respect to lane programming.  I believe Thierry is working on the PCIe
   parts of this.
 - HSIC support is mostly untested and I think there are still some issues
   to work out there.  I do have a Tegra124 board with a HSIC hub so I'll
   try to sort those out.
 - The DT bindings are rough, comments/suggestions very welcome.
 - The XUSB PHY driver doesn't play nice with the existing Tegra USB2.0
   PHY driver, so I've assinged all USB ports to XUSB in the DT for now.
 - Patch 5 is a temporary hack to get to the fuse data.  Internally we
   have this based on Peter's fuse driver series [2], but I haven't seen
   any activity on that upstream lately.

Based on work by:
  a lot of people, but from what I can tell from the L4T tree [3], the
  original authors of the Tegra XHCI driver are:
    Ajay Gupta <ajayg@nvidia.com>
    Bharath Yadav <byadav@nvidia.com>

[1] http://commondatastorage.googleapis.com/chromeos-localmirror/distfiles/xhci-firmware-2014.05.09.00.00.tbz2
[2] http://patchwork.ozlabs.org/patch/314883/
[3] git://nv-tegra.nvidia.com/linux-3.10.git

Andrew Bresticker (8):
  clk: tegra: Fix xusb_hs_src clock hierarchy
  clk: tegra: Initialize xusb clocks
  ARM: tegra: Export function to read USB calibration data
  usb: xhci: Add Tegra XHCI host-controller driver
  phy: Add Tegra XUSB PHY driver
  ARM: tegra124: Bind CAR to syscon device
  ARM: tegra124: Add XHCI controller and PHY
  ARM: tegra124: Enable XHCI on Venice2

Jim Lin (2):
  clk: tegra: Enable hardware control of PLLE
  clk: tegra: Fix xusb_fs_src mux

 .../bindings/phy/nvidia,tegra-xusb-phy.txt         |   76 ++
 .../devicetree/bindings/usb/nvidia,tegra-xhci.txt  |   42 +
 arch/arm/boot/dts/tegra124-venice2.dts             |   46 +-
 arch/arm/boot/dts/tegra124.dtsi                    |   39 +-
 arch/arm/mach-tegra/fuse.c                         |   13 +
 drivers/clk/tegra/clk-id.h                         |    1 +
 drivers/clk/tegra/clk-pll.c                        |   33 +-
 drivers/clk/tegra/clk-tegra-periph.c               |   10 +-
 drivers/clk/tegra/clk-tegra114.c                   |   22 +-
 drivers/clk/tegra/clk-tegra124.c                   |   21 +-
 drivers/phy/Kconfig                                |   11 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-tegra-xusb.c                       | 1171 ++++++++++++++++++++
 drivers/phy/phy-tegra-xusb.h                       |  270 +++++
 drivers/usb/host/Kconfig                           |   12 +
 drivers/usb/host/Makefile                          |    2 +
 drivers/usb/host/xhci-tegra.c                      |  796 +++++++++++++
 drivers/usb/host/xhci-tegra.h                      |  131 +++
 include/dt-bindings/clock/tegra114-car.h           |    3 +-
 include/dt-bindings/clock/tegra124-car.h           |    3 +-
 include/linux/tegra-soc.h                          |    1 +
 include/linux/usb/tegra_xusb.h                     |   66 ++
 22 files changed, 2717 insertions(+), 53 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/phy/nvidia,tegra-xusb-phy.txt
 create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra-xhci.txt
 create mode 100644 drivers/phy/phy-tegra-xusb.c
 create mode 100644 drivers/phy/phy-tegra-xusb.h
 create mode 100644 drivers/usb/host/xhci-tegra.c
 create mode 100644 drivers/usb/host/xhci-tegra.h
 create mode 100644 include/linux/usb/tegra_xusb.h

-- 
1.9.1.423.g4596e3a


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [RFC PATCH 01/10] clk: tegra: Enable hardware control of PLLE
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
@ 2014-05-15  0:32 ` Andrew Bresticker
  2014-05-15  0:32 ` [RFC PATCH 02/10] clk: tegra: Fix xusb_fs_src mux Andrew Bresticker
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:32 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Jim Lin, Andrew Bresticker

From: Jim Lin <jilin@nvidia.com>

Enable hardware control of PLLE spread-spectrum, IDDQ, and enable
controls when enabling PLLE.  The hardware (e.g. XUSB) using PLLE
will use these controls for power-saving optimizations.

Signed-off-by: Jim Lin <jilin@nvidia.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/tegra/clk-pll.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index 0d20241..84ca8b9 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -96,10 +96,20 @@
 	(PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL)
 
 #define PLLE_AUX_PLLP_SEL	BIT(2)
+#define PLLE_AUX_USE_LOCKDET	BIT(3)
 #define PLLE_AUX_ENABLE_SWCTL	BIT(4)
+#define PLLE_AUX_SS_SWCTL	BIT(6)
 #define PLLE_AUX_SEQ_ENABLE	BIT(24)
+#define PLLE_AUX_SEQ_START_STATE BIT(25)
 #define PLLE_AUX_PLLRE_SEL	BIT(28)
 
+#define XUSBIO_PLL_CFG0		0x51c
+#define XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL	BIT(0)
+#define XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL	BIT(2)
+#define XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET	BIT(6)
+#define XUSBIO_PLL_CFG0_SEQ_ENABLE		BIT(24)
+#define XUSBIO_PLL_CFG0_SEQ_START_STATE		BIT(25)
+
 #define PLLE_MISC_PLLE_PTS	BIT(8)
 #define PLLE_MISC_IDDQ_SW_VALUE	BIT(13)
 #define PLLE_MISC_IDDQ_SW_CTRL	BIT(14)
@@ -1318,7 +1328,28 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
 	pll_writel(val, PLLE_SS_CTRL, pll);
 	udelay(1);
 
-	/* TODO: enable hw control of xusb brick pll */
+	/* Enable hw control of xusb brick pll */
+	val = pll_readl_misc(pll);
+	val &= ~PLLE_MISC_IDDQ_SW_CTRL;
+	pll_writel_misc(val, pll);
+
+	val = pll_readl(pll->params->aux_reg, pll);
+	val |= (PLLE_AUX_USE_LOCKDET | PLLE_AUX_SEQ_START_STATE);
+	val &= ~(PLLE_AUX_ENABLE_SWCTL | PLLE_AUX_SS_SWCTL);
+	pll_writel(val, pll->params->aux_reg, pll);
+	udelay(1);
+	val |= PLLE_AUX_SEQ_ENABLE;
+	pll_writel(val, pll->params->aux_reg, pll);
+
+	val = pll_readl(XUSBIO_PLL_CFG0, pll);
+	val |= (XUSBIO_PLL_CFG0_PADPLL_USE_LOCKDET |
+		XUSBIO_PLL_CFG0_SEQ_START_STATE);
+	val &= ~(XUSBIO_PLL_CFG0_CLK_ENABLE_SWCTL |
+		 XUSBIO_PLL_CFG0_PADPLL_RESET_SWCTL);
+	pll_writel(val, XUSBIO_PLL_CFG0, pll);
+	udelay(1);
+	val |= XUSBIO_PLL_CFG0_SEQ_ENABLE;
+	pll_writel(val, XUSBIO_PLL_CFG0, pll);
 
 out:
 	if (pll->lock)
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 02/10] clk: tegra: Fix xusb_fs_src mux
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
  2014-05-15  0:32 ` [RFC PATCH 01/10] clk: tegra: Enable hardware control of PLLE Andrew Bresticker
@ 2014-05-15  0:32 ` Andrew Bresticker
  2014-05-15  0:32 ` [RFC PATCH 03/10] clk: tegra: Fix xusb_hs_src clock hierarchy Andrew Bresticker
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:32 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Jim Lin, Andrew Bresticker

From: Jim Lin <jilin@nvidia.com>

The parent-to-index mapping for xusb_fs_src is incorrect.
Fix it by adding a mux table.

Signed-off-by: Jim Lin <jilin@nvidia.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/tegra/clk-tegra-periph.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 1fa5c3f..a4063bc 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -329,7 +329,9 @@ static u32 mux_clkm_pllp_pllc_pllre_idx[] = {
 static const char *mux_clkm_48M_pllp_480M[] = {
 	"clk_m", "pll_u_48M", "pll_p", "pll_u_480M"
 };
-#define mux_clkm_48M_pllp_480M_idx NULL
+static u32 mux_clkm_48M_pllp_480M_idx[] = {
+	[0] = 0, [1] = 2, [2] = 4, [3] = 6,
+};
 
 static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = {
 	"clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref"
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 03/10] clk: tegra: Fix xusb_hs_src clock hierarchy
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
  2014-05-15  0:32 ` [RFC PATCH 01/10] clk: tegra: Enable hardware control of PLLE Andrew Bresticker
  2014-05-15  0:32 ` [RFC PATCH 02/10] clk: tegra: Fix xusb_fs_src mux Andrew Bresticker
@ 2014-05-15  0:32 ` Andrew Bresticker
  2014-05-15  0:33 ` [RFC PATCH 04/10] clk: tegra: Initialize xusb clocks Andrew Bresticker
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:32 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Andrew Bresticker

Currently the Tegra1x4 clock init code hard-codes the mux setting
for xusb_hs_src and treats it as a fixed-factor clock.  It is,
however, a mux which can be parented by either xusb_ss_src/2 or
pll_u_60M.  Add the fixed-factor clock xusb_ss_div2 and put an
entry in periph_clks[] for the xusb_hs_src mux.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/tegra/clk-id.h               |  1 +
 drivers/clk/tegra/clk-tegra-periph.c     |  6 ++++++
 drivers/clk/tegra/clk-tegra114.c         | 15 +++++----------
 drivers/clk/tegra/clk-tegra124.c         | 15 +++++----------
 include/dt-bindings/clock/tegra114-car.h |  3 ++-
 include/dt-bindings/clock/tegra124-car.h |  3 ++-
 6 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index c39613c..0011d54 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -233,6 +233,7 @@ enum clk_id {
 	tegra_clk_xusb_hs_src,
 	tegra_clk_xusb_ss,
 	tegra_clk_xusb_ss_src,
+	tegra_clk_xusb_ss_div2,
 	tegra_clk_max,
 };
 
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index a4063bc..adf6b81 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -340,6 +340,11 @@ static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = {
 	[0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7,
 };
 
+static const char *mux_ss_60M[] = {
+	"xusb_ss_div2", "pll_u_60M"
+};
+#define mux_ss_60M_idx NULL
+
 static const char *mux_d_audio_clk[] = {
 	"pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync",
 	"i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",
@@ -501,6 +506,7 @@ static struct tegra_periph_init_data periph_clks[] = {
 	XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src),
 	XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src),
 	XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src),
+	NODIV("xusb_hs_src", mux_ss_60M, CLK_SOURCE_XUSB_SS_SRC, 25, MASK(1), 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_hs_src, NULL),
 	XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src),
 };
 
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 80431f0..841f54f 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -142,7 +142,6 @@
 #define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL	BIT(0)
 
 #define CLK_SOURCE_CSITE 0x1d4
-#define CLK_SOURCE_XUSB_SS_SRC 0x610
 #define CLK_SOURCE_EMC 0x19c
 
 /* PLLM override registers */
@@ -834,6 +833,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA114_CLK_XUSB_FALCON_SRC, .present = true },
 	[tegra_clk_xusb_fs_src] = { .dt_id = TEGRA114_CLK_XUSB_FS_SRC, .present = true },
 	[tegra_clk_xusb_ss_src] = { .dt_id = TEGRA114_CLK_XUSB_SS_SRC, .present = true },
+	[tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA114_CLK_XUSB_SS_DIV2, .present = true},
 	[tegra_clk_xusb_dev_src] = { .dt_id = TEGRA114_CLK_XUSB_DEV_SRC, .present = true },
 	[tegra_clk_xusb_dev] = { .dt_id = TEGRA114_CLK_XUSB_DEV, .present = true },
 	[tegra_clk_xusb_hs_src] = { .dt_id = TEGRA114_CLK_XUSB_HS_SRC, .present = true },
@@ -1182,16 +1182,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
 					    void __iomem *pmc_base)
 {
 	struct clk *clk;
-	u32 val;
-
-	/* xusb_hs_src */
-	val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC);
-	val |= BIT(25); /* always select PLLU_60M */
-	writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC);
 
-	clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0,
-					1, 1);
-	clks[TEGRA114_CLK_XUSB_HS_SRC] = clk;
+	/* xusb_ss_div2 */
+	clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
+					1, 2);
+	clks[TEGRA114_CLK_XUSB_SS_DIV2] = clk;
 
 	/* dsia mux */
 	clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index 166e02f..6cabc3d 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -30,7 +30,6 @@
 
 #define CLK_SOURCE_CSITE 0x1d4
 #define CLK_SOURCE_EMC 0x19c
-#define CLK_SOURCE_XUSB_SS_SRC 0x610
 
 #define PLLC_BASE 0x80
 #define PLLC_OUT 0x84
@@ -927,6 +926,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true },
 	[tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true },
 	[tegra_clk_xusb_ss_src] = { .dt_id = TEGRA124_CLK_XUSB_SS_SRC, .present = true },
+	[tegra_clk_xusb_ss_div2] = { .dt_id = TEGRA124_CLK_XUSB_SS_DIV2, .present = true },
 	[tegra_clk_xusb_dev_src] = { .dt_id = TEGRA124_CLK_XUSB_DEV_SRC, .present = true },
 	[tegra_clk_xusb_dev] = { .dt_id = TEGRA124_CLK_XUSB_DEV, .present = true },
 	[tegra_clk_xusb_hs_src] = { .dt_id = TEGRA124_CLK_XUSB_HS_SRC, .present = true },
@@ -1108,16 +1108,11 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base,
 					    void __iomem *pmc_base)
 {
 	struct clk *clk;
-	u32 val;
-
-	/* xusb_hs_src */
-	val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC);
-	val |= BIT(25); /* always select PLLU_60M */
-	writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC);
 
-	clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0,
-					1, 1);
-	clks[TEGRA124_CLK_XUSB_HS_SRC] = clk;
+	/* xusb_ss_div2 */
+	clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0,
+					1, 2);
+	clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk;
 
 	/* dsia mux */
 	clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h
index 6d0d8d8..fc12621 100644
--- a/include/dt-bindings/clock/tegra114-car.h
+++ b/include/dt-bindings/clock/tegra114-car.h
@@ -337,6 +337,7 @@
 #define TEGRA114_CLK_CLK_OUT_3_MUX 308
 #define TEGRA114_CLK_DSIA_MUX 309
 #define TEGRA114_CLK_DSIB_MUX 310
-#define TEGRA114_CLK_CLK_MAX 311
+#define TEGRA114_CLK_XUSB_SS_DIV2 311
+#define TEGRA114_CLK_CLK_MAX 312
 
 #endif	/* _DT_BINDINGS_CLOCK_TEGRA114_CAR_H */
diff --git a/include/dt-bindings/clock/tegra124-car.h b/include/dt-bindings/clock/tegra124-car.h
index 8c1603b..159fd44 100644
--- a/include/dt-bindings/clock/tegra124-car.h
+++ b/include/dt-bindings/clock/tegra124-car.h
@@ -336,6 +336,7 @@
 #define TEGRA124_CLK_DSIA_MUX 309
 #define TEGRA124_CLK_DSIB_MUX 310
 #define TEGRA124_CLK_SOR0_LVDS 311
-#define TEGRA124_CLK_CLK_MAX 312
+#define TEGRA124_CLK_XUSB_SS_DIV2 312
+#define TEGRA124_CLK_CLK_MAX 313
 
 #endif	/* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 04/10] clk: tegra: Initialize xusb clocks
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
                   ` (2 preceding siblings ...)
  2014-05-15  0:32 ` [RFC PATCH 03/10] clk: tegra: Fix xusb_hs_src clock hierarchy Andrew Bresticker
@ 2014-05-15  0:33 ` Andrew Bresticker
  2014-05-15 19:22   ` Stephen Warren
  2014-05-15  0:33 ` [RFC PATCH 05/10] ARM: tegra: Export function to read USB calibration data Andrew Bresticker
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:33 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Andrew Bresticker, Jim Lin

Initialize the XUSB-related clocks with appropriate parents and rates
for both Tegra114 and Tegra124.

Signed-off-by: Jim Lin <jilin@nvidia.com>
Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/clk/tegra/clk-tegra114.c | 7 ++++++-
 drivers/clk/tegra/clk-tegra124.c | 6 ++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 841f54f..b9c8ba2 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -1296,7 +1296,12 @@ static struct tegra_clk_init_table init_table[] __initdata = {
 	{TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0},
 	{TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0},
 	{TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0},
-
+	{TEGRA114_CLK_PLL_RE_VCO, TEGRA114_CLK_CLK_MAX, 612000000, 0},
+	{TEGRA114_CLK_XUSB_SS_SRC, TEGRA114_CLK_PLL_RE_OUT, 122400000, 0},
+	{TEGRA114_CLK_XUSB_FS_SRC, TEGRA114_CLK_PLL_U_48M, 48000000, 0},
+	{TEGRA114_CLK_XUSB_HS_SRC, TEGRA114_CLK_XUSB_SS_DIV2, 61200000, 0},
+	{TEGRA114_CLK_XUSB_FALCON_SRC, TEGRA114_CLK_PLL_P, 204000000, 0},
+	{TEGRA114_CLK_XUSB_HOST_SRC, TEGRA114_CLK_PLL_P, 102000000, 0},
 	/* This MUST be the last entry. */
 	{TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0},
 };
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index 6cabc3d..80d64bf 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -1366,6 +1366,12 @@ static struct tegra_clk_init_table init_table[] __initdata = {
 	{TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1},
 	{TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0},
 	{TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0},
+	{TEGRA124_CLK_PLL_RE_VCO, TEGRA124_CLK_CLK_MAX, 672000000, 0},
+	{TEGRA124_CLK_XUSB_SS_SRC, TEGRA124_CLK_PLL_U_480M, 120000000, 0},
+	{TEGRA124_CLK_XUSB_FS_SRC, TEGRA124_CLK_PLL_U_48M, 48000000, 0},
+	{TEGRA124_CLK_XUSB_HS_SRC, TEGRA124_CLK_PLL_U_60M, 60000000, 0},
+	{TEGRA124_CLK_XUSB_FALCON_SRC, TEGRA124_CLK_PLL_RE_OUT, 224000000, 0},
+	{TEGRA124_CLK_XUSB_HOST_SRC, TEGRA124_CLK_PLL_RE_OUT, 112000000, 0},
 	/* This MUST be the last entry. */
 	{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
 };
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 05/10] ARM: tegra: Export function to read USB calibration data
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
                   ` (3 preceding siblings ...)
  2014-05-15  0:33 ` [RFC PATCH 04/10] clk: tegra: Initialize xusb clocks Andrew Bresticker
@ 2014-05-15  0:33 ` Andrew Bresticker
  2014-05-15 20:39   ` Stephen Warren
  2014-05-15  0:33 ` [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver Andrew Bresticker
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:33 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Andrew Bresticker

Board-specific USB configuration data is stored in FUSE_SKU_CALIB_0.
Export a function to read it so the PHY can be properly configured.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/arm/mach-tegra/fuse.c | 13 +++++++++++++
 include/linux/tegra-soc.h  |  1 +
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c
index c9ac23b..e457ef7 100644
--- a/arch/arm/mach-tegra/fuse.c
+++ b/arch/arm/mach-tegra/fuse.c
@@ -34,6 +34,7 @@
 #define FUSE_UID_HIGH		0x10c
 
 /* Tegra30 and later */
+#define FUSE_USB_CALIB		0x1f0
 #define FUSE_VENDOR_CODE	0x200
 #define FUSE_FAB_CODE		0x204
 #define FUSE_LOT_CODE_0		0x208
@@ -154,6 +155,18 @@ u32 tegra_read_chipid(void)
 	return readl_relaxed(IO_ADDRESS(TEGRA_APB_MISC_BASE) + 0x804);
 }
 
+u32 tegra_read_usb_calibration_data(void)
+{
+	u32 reg;
+
+	tegra_fuse_enable_clk();
+	reg = tegra_fuse_readl(FUSE_USB_CALIB);
+	tegra_fuse_disable_clk();
+
+	return reg;
+}
+EXPORT_SYMBOL(tegra_read_usb_calibration_data);
+
 static void __init tegra20_fuse_init_randomness(void)
 {
 	u32 randomness[2];
diff --git a/include/linux/tegra-soc.h b/include/linux/tegra-soc.h
index 95f611d..492dc95 100644
--- a/include/linux/tegra-soc.h
+++ b/include/linux/tegra-soc.h
@@ -18,5 +18,6 @@
 #define __LINUX_TEGRA_SOC_H_
 
 u32 tegra_read_chipid(void);
+u32 tegra_read_usb_calibration_data(void);
 
 #endif /* __LINUX_TEGRA_SOC_H_ */
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
                   ` (4 preceding siblings ...)
  2014-05-15  0:33 ` [RFC PATCH 05/10] ARM: tegra: Export function to read USB calibration data Andrew Bresticker
@ 2014-05-15  0:33 ` Andrew Bresticker
  2014-05-15  8:17   ` Arnd Bergmann
  2014-05-15  0:33 ` [RFC PATCH 07/10] phy: Add Tegra XUSB PHY driver Andrew Bresticker
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:33 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Andrew Bresticker

Add support for the on-chip XHCI host controller present on NVIDIA
Tegra114 and later SoCs.

The driver is currently very basic: it loads the controller with its
firmware, starts the controller, and is able to service messages sent
by the controller's firmware.  The hardware supports device mode as
well as runtime power-gating, but support for these is not yet
implemented here.

Based on work by:
  Ajay Gupta <ajayg@nvidia.com>
  Bharath Yadav <byadav@nvidia.com>

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 .../devicetree/bindings/usb/nvidia,tegra-xhci.txt  |  42 ++
 drivers/usb/host/Kconfig                           |  12 +
 drivers/usb/host/Makefile                          |   2 +
 drivers/usb/host/xhci-tegra.c                      | 796 +++++++++++++++++++++
 drivers/usb/host/xhci-tegra.h                      | 131 ++++
 include/linux/usb/tegra_xusb.h                     |  66 ++
 6 files changed, 1049 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra-xhci.txt
 create mode 100644 drivers/usb/host/xhci-tegra.c
 create mode 100644 drivers/usb/host/xhci-tegra.h
 create mode 100644 include/linux/usb/tegra_xusb.h

diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra-xhci.txt
new file mode 100644
index 0000000..6d94bd6
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra-xhci.txt
@@ -0,0 +1,42 @@
+NVIDIA Tegra XHCI controller
+
+The device node for the Tegra XHCI host controller present on Tegra114 and
+later SoCs.
+
+Required properties:
+ - compatible: Should be "nvidia,tegra114-xhci" or "nvidia,tegra124-xhci".
+ - reg: Address and length of the register sets.  There should be three
+   entries in the following order: XHCI host registers, FPCI registers, and
+   IPFS registers.
+ - interrupts: Interrupts used by the controller.  There should be two
+   entries in the following order: XHCI host interrupt and firmware mailbox
+   interrupt.
+ - clocks: Handles to XUSB host and falcon clocks.
+ - clock-names: Should be "xusb_host" and "xusb_falcon_src", respecitively.
+ - resets: Handle to XUSB host reset.
+ - reset-names: Should be "xusb_host".
+ - phys: Handle to the XUSB PHY.
+ - phy-names: Should be "xusb".
+ - s1p05v-supply: 1.05V supply regulator.
+ - s1p8v-supply: 1.8V supply regulator.
+ - s3p3v-supply: 3.3V supply regulator.
+
+Example:
+	usb@0,70090000 {
+		compatible = "nvidia,tegra114-xhci", "nvidia,tegra124-xhci";
+		reg = <0x0 0x70090000 0x0 0x8000>,
+		      <0x0 0x70098000 0x0 0x1000>,
+		      <0x0 0x70099000 0x0 0x1000>;
+		interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>;
+		clock-names = "xusb_host", "xusb_falcon_src";
+		resets = <&tegra_car 89>;
+		reset-names = "xusb_host";
+		phy = <&xusb_phy>;
+		phy-names = "xusb";
+		s1p05v-supply = <&vdd_1v05_run>;
+		s3p3v-supply = <&vdd_3v3_lp0>;
+		s1p8v-supply = <&vddio_1v8>;
+	};
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 3d9e540..43f7977 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -29,6 +29,18 @@ if USB_XHCI_HCD
 config USB_XHCI_PLATFORM
 	tristate
 
+config USB_XHCI_TEGRA
+	tristate "Support for NVIDIA Tegra XHCI host controller"
+	depends on ARCH_TEGRA
+	select USB_XHCI_PLATFORM
+	select PHY_TEGRA_XUSB
+	select FW_LOADER
+	---help---
+	  Enables support for the on-chip XHCI controller present on NVIDIA
+	  Tegra114 and later SoCs.
+
+	  If unsure, say N.
+
 endif # USB_XHCI_HCD
 
 config USB_EHCI_HCD
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 7530468..5941d36 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -38,6 +38,8 @@ obj-$(CONFIG_USB_EHCI_MSM)	+= ehci-msm.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= ehci-tegra.o
 obj-$(CONFIG_USB_W90X900_EHCI)	+= ehci-w90x900.o
 
+obj-$(CONFIG_USB_XHCI_TEGRA)	+= xhci-tegra.o
+
 obj-$(CONFIG_USB_OXU210HP_HCD)	+= oxu210hp-hcd.o
 obj-$(CONFIG_USB_ISP116X_HCD)	+= isp116x-hcd.o
 obj-$(CONFIG_USB_ISP1362_HCD)	+= isp1362-hcd.o
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
new file mode 100644
index 0000000..5c705b7
--- /dev/null
+++ b/drivers/usb/host/xhci-tegra.c
@@ -0,0 +1,796 @@
+/*
+ * NVIDIA Tegra XHCI host controller driver
+ *
+ * Copyright (C) 2014 NVIDIA Corporation
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/usb/tegra_xusb.h>
+
+#include "xhci-tegra.h"
+
+struct tegra_xhci_fw_cfgtbl {
+	u32 boot_loadaddr_in_imem;
+	u32 boot_codedfi_offset;
+	u32 boot_codetag;
+	u32 boot_codesize;
+	u32 phys_memaddr;
+	u16 reqphys_memsize;
+	u16 alloc_phys_memsize;
+	u32 rodata_img_offset;
+	u32 rodata_section_start;
+	u32 rodata_section_end;
+	u32 main_fnaddr;
+	u32 fwimg_cksum;
+	u32 fwimg_created_time;
+	u32 imem_resident_start;
+	u32 imem_resident_end;
+	u32 idirect_start;
+	u32 idirect_end;
+	u32 l2_imem_start;
+	u32 l2_imem_end;
+	u32 version_id;
+	u8 init_ddirect;
+	u8 reserved[3];
+	u32 phys_addr_log_buffer;
+	u32 total_log_entries;
+	u32 dequeue_ptr;
+	u32 dummy_var[2];
+	u32 fwimg_len;
+	u8 magic[8];
+	u32 ss_low_power_entry_timeout;
+	u8 num_hsic_port;
+	u8 padding[139]; /* Padding bytes to make 256-bytes cfgtbl */
+};
+
+struct tegra_xhci_soc_config {
+	const char *firmware_file;
+};
+
+struct tegra_xhci_hcd {
+	struct device *dev;
+	struct platform_device *xhci_pdev;
+
+	int mbox_irq;
+	struct notifier_block mbox_nb;
+
+	phys_addr_t host_phys_base;
+	void __iomem *fpci_base;
+	void __iomem *ipfs_base;
+
+	const struct tegra_xhci_soc_config *soc_config;
+
+	struct regulator *xusb_s1p05v_reg;
+	struct regulator *xusb_s3p3v_reg;
+	struct regulator *xusb_s1p8v_reg;
+
+	/* XUSB host clock */
+	struct clk *host_clk;
+	/* XUSB Falcon controller clock */
+	struct clk *falc_clk;
+	/* XUSB host reset */
+	struct reset_control *host_rst;
+
+	/* XUSB PHY */
+	struct phy *phy;
+
+	/* Firmware loading related */
+	void *fw_data;
+	size_t fw_size;
+	dma_addr_t fw_dma_addr;
+};
+
+static RAW_NOTIFIER_HEAD(tegra_xhci_mbox_notifiers);
+static DEFINE_MUTEX(tegra_xhci_mbox_lock);
+
+int tegra_xhci_register_mbox_notifier(struct notifier_block *nb)
+{
+	int ret;
+
+	mutex_lock(&tegra_xhci_mbox_lock);
+	ret = raw_notifier_chain_register(&tegra_xhci_mbox_notifiers, nb);
+	mutex_unlock(&tegra_xhci_mbox_lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(tegra_xhci_register_mbox_notifier);
+
+void tegra_xhci_unregister_mbox_notifier(struct notifier_block *nb)
+{
+	mutex_lock(&tegra_xhci_mbox_lock);
+	raw_notifier_chain_unregister(&tegra_xhci_mbox_notifiers, nb);
+	mutex_unlock(&tegra_xhci_mbox_lock);
+}
+EXPORT_SYMBOL(tegra_xhci_unregister_mbox_notifier);
+
+static inline u32 fpci_readl(struct tegra_xhci_hcd *tegra, u32 addr)
+{
+	return readl(tegra->fpci_base + addr);
+}
+
+static inline void fpci_writel(struct tegra_xhci_hcd *tegra, u32 val, u32 addr)
+{
+	writel(val, tegra->fpci_base + addr);
+}
+
+static inline u32 ipfs_readl(struct tegra_xhci_hcd *tegra, u32 addr)
+{
+	return readl(tegra->ipfs_base + addr);
+}
+
+static inline void ipfs_writel(struct tegra_xhci_hcd *tegra, u32 val, u32 addr)
+{
+	writel(val, tegra->ipfs_base + addr);
+}
+
+static u32 csb_readl(struct tegra_xhci_hcd *tegra, u32 addr)
+{
+	u32 page, offset;
+
+	page = CSB_PAGE_SELECT(addr);
+	offset = CSB_PAGE_OFFSET(addr);
+	fpci_writel(tegra, page, XUSB_CFG_ARU_C11_CSBRANGE);
+	return fpci_readl(tegra, XUSB_CFG_CSB_BASE_ADDR + offset);
+}
+
+static void csb_writel(struct tegra_xhci_hcd *tegra, u32 val, u32 addr)
+{
+	u32 page, offset;
+
+	page = CSB_PAGE_SELECT(addr);
+	offset = CSB_PAGE_OFFSET(addr);
+	fpci_writel(tegra, page, XUSB_CFG_ARU_C11_CSBRANGE);
+	fpci_writel(tegra, val, XUSB_CFG_CSB_BASE_ADDR + offset);
+}
+
+static void tegra_xhci_cfg(struct tegra_xhci_hcd *tegra)
+{
+	u32 reg;
+
+	reg = ipfs_readl(tegra, IPFS_XUSB_HOST_CONFIGURATION_0);
+	reg |= IPFS_EN_FPCI;
+	ipfs_writel(tegra, reg, IPFS_XUSB_HOST_CONFIGURATION_0);
+	udelay(10);
+
+	/* Program Bar0 Space */
+	reg = fpci_readl(tegra, XUSB_CFG_4);
+	reg |= tegra->host_phys_base;
+	fpci_writel(tegra, reg, XUSB_CFG_4);
+	usleep_range(100, 200);
+
+	/* Enable Bus Master */
+	reg = fpci_readl(tegra, XUSB_CFG_1);
+	reg |= XUSB_IO_SPACE_EN | XUSB_MEM_SPACE_EN | XUSB_BUS_MASTER_EN;
+	fpci_writel(tegra, reg, XUSB_CFG_1);
+
+	/* Set intr mask to enable intr assertion */
+	reg = ipfs_readl(tegra, IPFS_XUSB_HOST_INTR_MASK_0);
+	reg |= IPFS_IP_INT_MASK;
+	ipfs_writel(tegra, reg, IPFS_XUSB_HOST_INTR_MASK_0);
+
+	/* Set hysteris to 0x80 */
+	ipfs_writel(tegra, 0x80, IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0);
+}
+
+static int tegra_xhci_mbox_send(struct tegra_xhci_hcd *tegra,
+				enum tegra_xusb_mbox_cmd type, u32 data)
+{
+	struct device *dev = tegra->dev;
+	unsigned long timeout;
+	u32 reg;
+
+	dev_dbg(dev, "MBOX send message 0x%x:0x%x\n", type, data);
+	mutex_lock(&tegra_xhci_mbox_lock);
+
+	timeout = jiffies + msecs_to_jiffies(20);
+	/* Wait for mailbox to become idle */
+	while ((fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_NONE)
+	       && time_is_after_jiffies(timeout)) {
+		mutex_unlock(&tegra_xhci_mbox_lock);
+		usleep_range(100, 200);
+		mutex_lock(&tegra_xhci_mbox_lock);
+	}
+	if (fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_NONE) {
+		dev_err(dev, "Mailbox failed to go idle\n");
+		goto timeout;
+	}
+
+	timeout = jiffies + msecs_to_jiffies(10);
+	/* Acquire mailbox */
+	fpci_writel(tegra, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER);
+	while ((fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_SW) &&
+	       time_is_after_jiffies(timeout)) {
+		mutex_unlock(&tegra_xhci_mbox_lock);
+		usleep_range(100, 200);
+		mutex_lock(&tegra_xhci_mbox_lock);
+		fpci_writel(tegra, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER);
+	}
+	if (fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_SW) {
+		dev_err(dev, "Acquire mailbox timeout\n");
+		goto timeout;
+	}
+
+	reg = (type & CMD_TYPE_MASK) << CMD_TYPE_SHIFT;
+	reg |= (data & CMD_DATA_MASK) << CMD_DATA_SHIFT;
+	fpci_writel(tegra, reg, XUSB_CFG_ARU_MBOX_DATA_IN);
+
+	reg = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD);
+	reg |= MBOX_INT_EN | MBOX_FALC_INT_EN;
+	fpci_writel(tegra, reg, XUSB_CFG_ARU_MBOX_CMD);
+
+	mutex_unlock(&tegra_xhci_mbox_lock);
+
+	return 0;
+timeout:
+	mutex_unlock(&tegra_xhci_mbox_lock);
+	return -ETIMEDOUT;
+}
+
+static irqreturn_t tegra_xhci_mbox_irq(int irq, void *p)
+{
+	struct tegra_xhci_hcd *tegra = (struct tegra_xhci_hcd *)p;
+	struct device *dev = tegra->dev;
+	u32 resp = 0, cmd_type, cmd_data, reg;
+
+	mutex_lock(&tegra_xhci_mbox_lock);
+
+	/* Clear mbox interrupts */
+	reg = fpci_readl(tegra, XUSB_CFG_ARU_SMI_INTR);
+	if (reg & MBOX_SMI_INTR_FW_HANG)
+		dev_err(dev, "Hang up inside firmware\n");
+	fpci_writel(tegra, reg, XUSB_CFG_ARU_SMI_INTR);
+
+	/* Get the mbox message from firmware */
+	reg = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_DATA_OUT);
+	cmd_type = (reg >> CMD_TYPE_SHIFT) & CMD_TYPE_MASK;
+	cmd_data = (reg >> CMD_DATA_SHIFT) & CMD_DATA_MASK;
+
+	/* Decode the message and call the notifiers */
+	dev_dbg(dev, "MBOX receive message 0x%x:0x%x\n", cmd_type, cmd_data);
+	if (cmd_type < MBOX_CMD_MAX) {
+		struct mbox_notifier_data mbox_info;
+
+		mbox_info.msg_data = cmd_data;
+		mbox_info.resp_cmd = 0;
+		mbox_info.resp_data = 0;
+		raw_notifier_call_chain(&tegra_xhci_mbox_notifiers, cmd_type,
+					&mbox_info);
+		if (mbox_info.resp_cmd) {
+			resp = (mbox_info.resp_cmd & CMD_TYPE_MASK) <<
+				CMD_TYPE_SHIFT;
+			resp |= (mbox_info.resp_data & CMD_DATA_MASK) <<
+				CMD_DATA_SHIFT;
+		}
+	} else if (cmd_type == MBOX_CMD_ACK) {
+		dev_dbg(dev, "Firmware responds with ACK\n");
+	} else if (cmd_type == MBOX_CMD_NAK) {
+		dev_err(dev, "Firmware responds with NAK\n");
+	} else {
+		dev_err(dev, "Invalid command %x\n", cmd_type);
+	}
+
+	if (resp) {
+		/* Send ACK/NAK to firmware */
+		fpci_writel(tegra, resp, XUSB_CFG_ARU_MBOX_DATA_IN);
+		reg = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD);
+		reg |= MBOX_INT_EN | MBOX_FALC_INT_EN;
+		fpci_writel(tegra, reg, XUSB_CFG_ARU_MBOX_CMD);
+	} else {
+		/* Clear MBOX_SMI_INT_EN bit */
+		reg = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD);
+		reg &= ~MBOX_SMI_INT_EN;
+		fpci_writel(tegra, reg, XUSB_CFG_ARU_MBOX_CMD);
+		/* Clear mailbox ownership */
+		fpci_writel(tegra, MBOX_OWNER_NONE, XUSB_CFG_ARU_MBOX_OWNER);
+	}
+
+	mutex_unlock(&tegra_xhci_mbox_lock);
+
+	return IRQ_HANDLED;
+}
+
+static int tegra_xhci_default_mbox_notifier(struct notifier_block *nb,
+					    unsigned long event, void *p)
+{
+	struct tegra_xhci_hcd *tegra = container_of(nb, struct tegra_xhci_hcd,
+						    mbox_nb);
+	struct mbox_notifier_data *data = (struct mbox_notifier_data *)p;
+
+	switch (event) {
+	case MBOX_CMD_INC_FALC_CLOCK:
+	case MBOX_CMD_DEC_FALC_CLOCK:
+		data->resp_data = clk_get_rate(tegra->falc_clk) / 1000;
+		if (data->resp_data != data->msg_data)
+			data->resp_cmd = MBOX_CMD_NAK;
+		else
+			data->resp_cmd = MBOX_CMD_ACK;
+		return NOTIFY_STOP;
+	case MBOX_CMD_SET_BW:
+		/* No support for EMC scaling yet */
+		return NOTIFY_STOP;
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static int tegra_xhci_load_firmware(struct tegra_xhci_hcd *tegra)
+{
+	struct device *dev = tegra->dev;
+	struct tegra_xhci_fw_cfgtbl *cfg_tbl;
+	u64 fw_base;
+	u32 val;
+	time_t fw_time;
+	struct tm fw_tm;
+
+	if (csb_readl(tegra, XUSB_CSB_MP_ILOAD_BASE_LO) != 0) {
+		dev_info(dev, "Firmware already loaded, Falcon state 0x%x\n",
+			 csb_readl(tegra, XUSB_FALC_CPUCTL));
+		return 0;
+	}
+
+	cfg_tbl = (struct tegra_xhci_fw_cfgtbl *)tegra->fw_data;
+
+	/* Program the size of DFI into ILOAD_ATTR */
+	csb_writel(tegra, tegra->fw_size, XUSB_CSB_MP_ILOAD_ATTR);
+
+	/*
+	 * Boot code of the firmware reads the ILOAD_BASE registers
+	 * to get to the start of the DFI in system memory.
+	 */
+	fw_base = tegra->fw_dma_addr + sizeof(*cfg_tbl);
+	csb_writel(tegra, fw_base, XUSB_CSB_MP_ILOAD_BASE_LO);
+	csb_writel(tegra, fw_base >> 32, XUSB_CSB_MP_ILOAD_BASE_HI);
+
+	/* Set BOOTPATH to 1 in APMAP. */
+	csb_writel(tegra, APMAP_BOOTPATH, XUSB_CSB_MP_APMAP);
+
+	/* Invalidate L2IMEM. */
+	csb_writel(tegra, L2IMEMOP_INVALIDATE_ALL, XUSB_CSB_MP_L2IMEMOP_TRIG);
+
+	/*
+	 * Initiate fetch of bootcode from system memory into L2IMEM.
+	 * Program bootcode location and size in system memory.
+	 */
+	val = (DIV_ROUND_UP(cfg_tbl->boot_codetag, IMEM_BLOCK_SIZE) &
+	       L2IMEMOP_SIZE_SRC_OFFSET_MASK) << L2IMEMOP_SIZE_SRC_OFFSET_SHIFT;
+	val |= (DIV_ROUND_UP(cfg_tbl->boot_codesize, IMEM_BLOCK_SIZE) &
+		L2IMEMOP_SIZE_SRC_COUNT_MASK) << L2IMEMOP_SIZE_SRC_COUNT_SHIFT;
+	csb_writel(tegra, val, XUSB_CSB_MP_L2IMEMOP_SIZE);
+
+	/* Trigger L2IMEM Load operation. */
+	csb_writel(tegra, L2IMEMOP_LOAD_LOCKED_RESULT,
+		   XUSB_CSB_MP_L2IMEMOP_TRIG);
+
+	/* Setup Falcon Auto-fill */
+	val = DIV_ROUND_UP(cfg_tbl->boot_codesize, IMEM_BLOCK_SIZE);
+	csb_writel(tegra, val, XUSB_FALC_IMFILLCTL);
+
+	val = DIV_ROUND_UP(cfg_tbl->boot_codetag, IMEM_BLOCK_SIZE) &
+		IMFILLRNG1_TAG_MASK;
+	val |= DIV_ROUND_UP(cfg_tbl->boot_codetag + cfg_tbl->boot_codesize,
+			    IMEM_BLOCK_SIZE) << IMFILLRNG1_TAG_HI_SHIFT;
+	csb_writel(tegra, val, XUSB_FALC_IMFILLRNG1);
+
+	csb_writel(tegra, 0, XUSB_FALC_DMACTL);
+	msleep(50);
+
+	csb_writel(tegra, cfg_tbl->boot_codetag, XUSB_FALC_BOOTVEC);
+
+	/* Start Falcon CPU */
+	csb_writel(tegra, CPUCTL_STARTCPU, XUSB_FALC_CPUCTL);
+	usleep_range(1000, 2000);
+
+	fw_time = cfg_tbl->fwimg_created_time;
+	time_to_tm(fw_time, 0, &fw_tm);
+	dev_info(dev,
+		 "Firmware timestamp: %ld-%02d-%02d %02d:%02d:%02d UTC, "
+		 "Falcon state 0x%x\n", fw_tm.tm_year + 1900,
+		 fw_tm.tm_mon + 1, fw_tm.tm_mday, fw_tm.tm_hour,
+		 fw_tm.tm_min, fw_tm.tm_sec,
+		 csb_readl(tegra, XUSB_FALC_CPUCTL));
+
+	/* Bail out if Falcon CPU is not in a good state */
+	if (csb_readl(tegra, XUSB_FALC_CPUCTL) == CPUCTL_STATE_HALTED)
+		return -EIO;
+
+	return 0;
+}
+
+static int tegra_xhci_regulator_init(struct tegra_xhci_hcd *tegra)
+{
+	struct device *dev = tegra->dev;
+	int err = 0;
+
+	tegra->xusb_s3p3v_reg = devm_regulator_get(dev, "s3p3v");
+	if (IS_ERR(tegra->xusb_s3p3v_reg)) {
+		dev_err(dev, "s3p3v regulator not found: %ld.",
+			PTR_ERR(tegra->xusb_s3p3v_reg));
+		return PTR_ERR(tegra->xusb_s3p3v_reg);
+	}
+	err = regulator_enable(tegra->xusb_s3p3v_reg);
+	if (err < 0) {
+		dev_err(dev, "s3p3v regulator enable failed:%d\n", err);
+		return err;
+	}
+
+	tegra->xusb_s1p8v_reg = devm_regulator_get(dev, "s1p8v");
+	if (IS_ERR(tegra->xusb_s1p8v_reg)) {
+		dev_err(dev, "s1p8v regulator not found: %ld.",
+			PTR_ERR(tegra->xusb_s1p8v_reg));
+		err = PTR_ERR(tegra->xusb_s1p8v_reg);
+		goto err_put_s3p3v_reg;
+	} else {
+		err = regulator_enable(tegra->xusb_s1p8v_reg);
+		if (err < 0) {
+			dev_err(dev, "s1p8v regulator enable failed:%d\n", err);
+			goto err_put_s3p3v_reg;
+		}
+	}
+
+	tegra->xusb_s1p05v_reg = devm_regulator_get(dev, "s1p05v");
+	if (IS_ERR(tegra->xusb_s1p05v_reg)) {
+		dev_err(dev, "s1p05v regulator not found: %ld.",
+			PTR_ERR(tegra->xusb_s1p05v_reg));
+		err = PTR_ERR(tegra->xusb_s1p05v_reg);
+		goto err_put_s1p8v_reg;
+	} else {
+		err = regulator_enable(tegra->xusb_s1p05v_reg);
+		if (err < 0) {
+			dev_err(dev,
+				"s1p05v regulator enable failed:%d\n", err);
+			goto err_put_s1p8v_reg;
+		}
+	}
+
+	return 0;
+
+err_put_s1p8v_reg:
+	regulator_disable(tegra->xusb_s1p8v_reg);
+err_put_s3p3v_reg:
+	regulator_disable(tegra->xusb_s3p3v_reg);
+	return err;
+}
+
+static void tegra_xhci_regulator_deinit(struct tegra_xhci_hcd *tegra)
+{
+	regulator_disable(tegra->xusb_s1p05v_reg);
+	regulator_disable(tegra->xusb_s1p8v_reg);
+	regulator_disable(tegra->xusb_s3p3v_reg);
+}
+
+static int tegra_xhci_clk_init(struct tegra_xhci_hcd *tegra)
+{
+	struct device *dev = tegra->dev;
+	int err = 0;
+
+	tegra->host_clk = devm_clk_get(dev, "xusb_host");
+	if (IS_ERR(tegra->host_clk)) {
+		dev_err(dev, "Failed to get xusb_host clk\n");
+		err = PTR_ERR(tegra->host_clk);
+		return err;
+	}
+
+	tegra->falc_clk = devm_clk_get(dev, "xusb_falcon_src");
+	if (IS_ERR(tegra->falc_clk)) {
+		dev_err(dev, "Failed to get xusb_falcon_src clk\n");
+		err = PTR_ERR(tegra->falc_clk);
+		return err;
+	}
+
+	clk_prepare_enable(tegra->host_clk);
+	clk_prepare_enable(tegra->falc_clk);
+
+	return 0;
+}
+
+static void tegra_xhci_clk_deinit(struct tegra_xhci_hcd *tegra)
+{
+	clk_disable_unprepare(tegra->host_clk);
+	clk_disable_unprepare(tegra->falc_clk);
+}
+
+static const struct tegra_xhci_soc_config tegra114_soc_config = {
+	.firmware_file = "tegra11x/tegra_xusb_firmware",
+};
+
+static const struct tegra_xhci_soc_config tegra124_soc_config = {
+	.firmware_file = "tegra12x/tegra_xusb_firmware",
+};
+
+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 },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tegra_xhci_of_match);
+
+static void tegra_xhci_probe_finish(const struct firmware *fw, void *context)
+{
+	struct tegra_xhci_hcd *tegra = context;
+	struct device *dev = tegra->dev;
+	struct platform_device *xhci = NULL;
+	struct resource xhci_resources[2];
+	struct resource	*res;
+	struct tegra_xhci_fw_cfgtbl *cfg_tbl;
+	int ret;
+
+	if (!fw) {
+		dev_err(dev, "Failed to load firmware file\n");
+		ret = -ENOENT;
+		goto out;
+	}
+
+	/* Load Falcon controller with its firmware */
+	cfg_tbl = (struct tegra_xhci_fw_cfgtbl *)fw->data;
+	tegra->fw_size = cfg_tbl->fwimg_len;
+	tegra->fw_data = dma_alloc_coherent(dev, tegra->fw_size,
+					    &tegra->fw_dma_addr,
+					    GFP_KERNEL);
+	if (!tegra->fw_data) {
+		dev_err(dev, "Failed to allocate DMA buffer for firmware\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	memcpy(tegra->fw_data, fw->data, tegra->fw_size);
+
+	ret = tegra_xhci_load_firmware(tegra);
+	if (ret < 0) {
+		dev_err(dev, "Failed to load controller firmware\n");
+		goto out;
+	}
+
+	/* Set up mailbox notifier and interrupt handler */
+	tegra->mbox_nb.notifier_call = tegra_xhci_default_mbox_notifier;
+	ret = tegra_xhci_register_mbox_notifier(&tegra->mbox_nb);
+	if (ret < 0) {
+		dev_err(dev, "Failed to registe mbox handler\n");
+		goto out;
+	}
+	tegra->mbox_irq = platform_get_irq(to_platform_device(dev), 1);
+	if (!tegra->mbox_irq) {
+		dev_err(dev, "Missing MBOX IRQ\n");
+		ret = -ENODEV;
+		goto out;
+	}
+	ret = devm_request_threaded_irq(dev, tegra->mbox_irq, NULL,
+					tegra_xhci_mbox_irq, IRQF_ONESHOT,
+					"tegra_xhci_mbox_irq", tegra);
+	if (ret != 0) {
+		dev_err(dev, "Failed to request MBOX IRQ\n");
+		goto out;
+	}
+
+	/* Create child xhci-plat device */
+	memset(xhci_resources, 0, sizeof(xhci_resources));
+	res = platform_get_resource(to_platform_device(dev), IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(dev, "Missing XHCI IRQ\n");
+		ret = -ENODEV;
+		goto out;
+	}
+	xhci_resources[0].start = res->start;
+	xhci_resources[0].end = res->end;
+	xhci_resources[0].flags = res->flags;
+	xhci_resources[0].name = res->name;
+	res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(dev, "Missing XHCI registers\n");
+		ret = -ENODEV;
+		goto out;
+	}
+	xhci_resources[1].start = res->start;
+	xhci_resources[1].end = res->end;
+	xhci_resources[1].flags = res->flags;
+	xhci_resources[1].name = res->name;
+
+	xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
+	if (!xhci) {
+		dev_err(dev, "Failed to allocate XHCI host\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	xhci->dev.parent = dev;
+	ret = dma_coerce_mask_and_coherent(&xhci->dev,
+					   dev->coherent_dma_mask);
+	if (ret) {
+		dev_err(dev, "Failed to set XHCI dma mask\n");
+		goto out;
+	}
+	ret = platform_device_add_resources(xhci, xhci_resources,
+					    ARRAY_SIZE(xhci_resources));
+	if (ret) {
+		dev_err(dev, "Failed to add XHCI resources\n");
+		goto out;
+	}
+	ret = platform_device_add(xhci);
+	if (ret) {
+		dev_err(dev, "failed to register XHCI device\n");
+		goto out;
+	}
+	tegra->xhci_pdev = xhci;
+
+	/* Enable firmware messages from controller */
+	tegra_xhci_mbox_send(tegra, MBOX_CMD_MSG_ENABLED, 0);
+
+out:
+	release_firmware(fw);
+	if (ret)
+		platform_device_put(xhci);
+}
+
+static int tegra_xhci_probe(struct platform_device *pdev)
+{
+	struct tegra_xhci_hcd *tegra;
+	struct resource	*res;
+	const struct of_device_id *match;
+	int ret;
+
+	BUILD_BUG_ON(sizeof(struct tegra_xhci_fw_cfgtbl) != 256);
+
+	tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
+	if (!tegra) {
+		dev_err(&pdev->dev, "memory alloc failed\n");
+		return -ENOMEM;
+	}
+	platform_set_drvdata(pdev, tegra);
+	tegra->dev = &pdev->dev;
+
+	match = of_match_device(tegra_xhci_of_match, &pdev->dev);
+	if (!match) {
+		dev_err(&pdev->dev, "No device match found\n");
+		return -ENODEV;
+	}
+	tegra->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.
+	 */
+	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+	if (ret)
+		return ret;
+
+	/*
+	 * The firmware needs the XHCI host's base physical address.
+	 * Get it here and save it for later.
+	 */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Missing XHCI registers\n");
+		return -ENODEV;
+	}
+	tegra->host_phys_base = res->start;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	tegra->fpci_base = devm_ioremap_resource(&pdev->dev, res);
+	if (!tegra->fpci_base) {
+		dev_err(&pdev->dev, "Failed to map FPCI registers\n");
+		return -ENOMEM;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res);
+	if (!tegra->ipfs_base) {
+		dev_err(&pdev->dev, "Failed to map IPFS registers\n");
+		return -ENOMEM;
+	}
+
+	tegra->phy = devm_phy_get(&pdev->dev, "xusb");
+	if (IS_ERR(tegra->phy)) {
+		dev_err(&pdev->dev, "Failed to get PHY\n");
+		return PTR_ERR(tegra->phy);
+	}
+	ret = phy_init(tegra->phy);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "PHY initialization failed\n");
+		return ret;
+	}
+
+	tegra->host_rst = devm_reset_control_get(&pdev->dev, "xusb_host");
+	if (IS_ERR(tegra->host_rst)) {
+		dev_err(&pdev->dev, "Failed to get host reset\n");
+		ret = PTR_ERR(tegra->host_rst);
+		goto err_deinit_phy;
+	}
+
+	ret = tegra_xhci_clk_init(tegra);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to initialize XHCI clocks\n");
+		goto err_deinit_phy;
+	}
+
+	ret = tegra_xhci_regulator_init(tegra);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to initialize XHCI regulators\n");
+		goto err_deinit_clk;
+	}
+
+	/* Setup IPFS access and BAR0 space */
+	tegra_xhci_cfg(tegra);
+
+	ret = phy_power_on(tegra->phy);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "PHY power up failed\n");
+		goto err_deinit_regulator;
+	}
+
+	ret = request_firmware_nowait(THIS_MODULE, true,
+				      tegra->soc_config->firmware_file,
+				      tegra->dev, GFP_KERNEL, tegra,
+				      tegra_xhci_probe_finish);
+	if (ret < 0) {
+		dev_err(tegra->dev, "Failed to request firmware\n");
+		goto err_shutdown_phy;
+	}
+
+	return 0;
+
+err_shutdown_phy:
+	phy_power_off(tegra->phy);
+err_deinit_regulator:
+	tegra_xhci_regulator_deinit(tegra);
+err_deinit_clk:
+	tegra_xhci_clk_deinit(tegra);
+err_deinit_phy:
+	phy_exit(tegra->phy);
+
+	return ret;
+}
+
+static int tegra_xhci_remove(struct platform_device *pdev)
+{
+	struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+
+	phy_power_off(tegra->phy);
+	phy_exit(tegra->phy);
+
+	if (tegra->fw_data)
+		dma_free_coherent(tegra->dev, tegra->fw_size, tegra->fw_data,
+				  tegra->fw_dma_addr);
+
+	tegra_xhci_unregister_mbox_notifier(&tegra->mbox_nb);
+	tegra_xhci_regulator_deinit(tegra);
+	tegra_xhci_clk_deinit(tegra);
+
+	return 0;
+}
+
+static struct platform_driver tegra_xhci_driver = {
+	.probe	= tegra_xhci_probe,
+	.remove	= tegra_xhci_remove,
+	.driver	= {
+		.name = "tegra-xhci",
+		.of_match_table = of_match_ptr(tegra_xhci_of_match),
+	},
+};
+module_platform_driver(tegra_xhci_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra XHCI host-controller driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tegra-xhci");
diff --git a/drivers/usb/host/xhci-tegra.h b/drivers/usb/host/xhci-tegra.h
new file mode 100644
index 0000000..b65bfdb
--- /dev/null
+++ b/drivers/usb/host/xhci-tegra.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 NVIDIA Corporation
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __XHCI_TEGRA_H
+#define __XHCI_TEGRA_H
+
+/* FPCI CFG registers */
+#define XUSB_CFG_0				0x0
+#define XUSB_CFG_1				0x4
+#define  XUSB_IO_SPACE_EN			BIT(0)
+#define  XUSB_MEM_SPACE_EN			BIT(1)
+#define  XUSB_BUS_MASTER_EN			BIT(2)
+#define XUSB_CFG_4				0x10
+#define XUSB_CFG_16				0x40
+#define XUSB_CFG_24				0x60
+#define XUSB_CFG_ARU_MBOX_CMD			0xe4
+#define  MBOX_FALC_INT_EN			BIT(27)
+#define  MBOX_PME_INT_EN			BIT(28)
+#define  MBOX_SMI_INT_EN			BIT(29)
+#define  MBOX_XHCI_INT_EN			BIT(30)
+#define  MBOX_INT_EN				BIT(31)
+#define XUSB_CFG_ARU_MBOX_DATA_IN		0xe8
+#define  CMD_DATA_SHIFT				0
+#define  CMD_DATA_MASK				0xffffff
+#define  CMD_TYPE_SHIFT				24
+#define  CMD_TYPE_MASK				0xff
+#define XUSB_CFG_ARU_MBOX_DATA_OUT		0xec
+#define XUSB_CFG_ARU_MBOX_OWNER			0xf0
+#define  MBOX_OWNER_NONE			0
+#define  MBOX_OWNER_FW				1
+#define  MBOX_OWNER_SW				2
+#define XUSB_CFG_FPCICFG			0xf8
+#define XUSB_CFG_ARU_C11PAGESEL0		0x400
+#define XUSB_CFG_ARU_C11PAGESEL1		0x404
+#define XUSB_CFG_ARU_C11_CSBRANGE		0x41c
+#define XUSB_CFG_ARU_SMI_INTR			0x428
+#define  MBOX_SMI_INTR_FW_HANG			BIT(1)
+#define  MBOX_SMI_INTR_EN			BIT(3)
+#define XUSB_CFG_ARU_RST			0x42c
+#define XUSB_CFG_ARU_CONTEXT			0x43c
+#define XUSB_CFG_ARU_FW_SCRATCH			0x440
+#define XUSB_CFG_ARU_CONTEXT_HS_PLS		0x478
+#define XUSB_CFG_ARU_CONTEXT_FS_PLS		0x47c
+#define XUSB_CFG_ARU_CONTEXT_HSFS_SPEED		0x480
+#define XUSB_CFG_ARU_CONTEXT_HSFS_PP		0x484
+#define XUSB_CFG_HSPX_CORE_HSICWRAP		0x658
+#define XUSB_CFG_CSB_BASE_ADDR			0x800
+
+/* IPFS registers */
+#define IPFS_XUSB_HOST_MSI_BAR_SZ_0		0xc0
+#define IPFS_XUSB_HOST_MSI_AXI_BAR_ST_0		0xc4
+#define IPFS_XUSB_HOST_FPCI_BAR_ST_0		0xc8
+#define IPFS_XUSB_HOST_MSI_VEC0_0		0x100
+#define IPFS_XUSB_HOST_MSI_EN_VEC0_0		0x140
+#define IPFS_XUSB_HOST_CONFIGURATION_0		0x180
+#define  IPFS_EN_FPCI				BIT(0)
+#define IPFS_XUSB_HOST_FPCI_ERROR_MASKS_0	0x184
+#define IPFS_XUSB_HOST_INTR_MASK_0		0x188
+#define  IPFS_IP_INT_MASK			BIT(16)
+#define IPFS_XUSB_HOST_IPFS_INTR_ENABLE_0	0x198
+#define IPFS_XUSB_HOST_UFPCI_CONFIG_0		0x19c
+#define IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0	0x1bc
+#define IPFS_XUSB_HOST_MCCIF_FIFOCTRL_0		0x1dc
+
+#define IMEM_BLOCK_SIZE				256
+
+#define CSB_PAGE_SELECT_MASK			0x7fffff
+#define CSB_PAGE_SELECT_SHIFT			9
+#define CSB_PAGE_OFFSET_MASK			0x1ff
+#define CSB_PAGE_SELECT(addr)	((addr) >> (CSB_PAGE_SELECT_SHIFT) &	\
+				 CSB_PAGE_SELECT_MASK)
+#define CSB_PAGE_OFFSET(addr)	((addr) & CSB_PAGE_OFFSET_MASK)
+
+/* Falcon CSB registers */
+#define XUSB_FALC_CPUCTL			0x100
+#define  CPUCTL_STARTCPU			BIT(1)
+#define  CPUCTL_STATE_HALTED			BIT(4)
+#define XUSB_FALC_BOOTVEC			0x104
+#define XUSB_FALC_DMACTL			0x10c
+#define XUSB_FALC_IMFILLRNG1			0x154
+#define  IMFILLRNG1_TAG_MASK			0xffff
+#define  IMFILLRNG1_TAG_HI_SHIFT		16
+#define XUSB_FALC_IMFILLCTL			0x158
+#define XUSB_FALC_CMEMBASE			0x160
+#define XUSB_FALC_DMEMAPERT			0x164
+#define XUSB_FALC_IMEMC_START			0x180
+#define XUSB_FALC_IMEMD_START			0x184
+#define XUSB_FALC_IMEMT_START			0x188
+#define XUSB_FALC_ICD_CMD			0x200
+#define XUSB_FALC_ICD_RDATA			0x20C
+#define XUSB_FALC_SS_PVTPORTSC1			0x116000
+#define XUSB_FALC_SS_PVTPORTSC2			0x116004
+#define XUSB_FALC_SS_PVTPORTSC3			0x116008
+#define XUSB_FALC_HS_PVTPORTSC1			0x116800
+#define XUSB_FALC_HS_PVTPORTSC2			0x116804
+#define XUSB_FALC_HS_PVTPORTSC3			0x116808
+#define XUSB_FALC_FS_PVTPORTSC1			0x117000
+#define XUSB_FALC_FS_PVTPORTSC2			0x117004
+#define XUSB_FALC_FS_PVTPORTSC3			0x117008
+
+/* MP CSB registers */
+#define XUSB_CSB_MP_ILOAD_ATTR			0x101a00
+#define XUSB_CSB_MP_ILOAD_BASE_LO		0x101a04
+#define XUSB_CSB_MP_ILOAD_BASE_HI		0x101a08
+#define XUSB_CSB_MP_L2IMEMOP_SIZE		0x101a10
+#define  L2IMEMOP_SIZE_SRC_OFFSET_SHIFT		8
+#define  L2IMEMOP_SIZE_SRC_OFFSET_MASK		0x3ff
+#define  L2IMEMOP_SIZE_SRC_COUNT_SHIFT		24
+#define  L2IMEMOP_SIZE_SRC_COUNT_MASK		0xff
+#define XUSB_CSB_MP_L2IMEMOP_TRIG		0x101a14
+#define  L2IMEMOP_ACTION_SHIFT			24
+#define  L2IMEMOP_INVALIDATE_ALL		(0x40 << L2IMEMOP_ACTION_SHIFT)
+#define  L2IMEMOP_LOAD_LOCKED_RESULT		(0x11 << L2IMEMOP_ACTION_SHIFT)
+#define XUSB_CSB_MP_APMAP			0x10181c
+#define  APMAP_BOOTPATH				BIT(31)
+
+#endif /* __XHCI_TEGRA_H */
diff --git a/include/linux/usb/tegra_xusb.h b/include/linux/usb/tegra_xusb.h
new file mode 100644
index 0000000..1a654e7
--- /dev/null
+++ b/include/linux/usb/tegra_xusb.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 NVIDIA Corporation
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TEGRA_XUSB_H
+#define __TEGRA_XUSB_H
+
+/* Command requests from the firmware */
+enum tegra_xusb_mbox_cmd {
+	MBOX_CMD_MSG_ENABLED = 1,
+	MBOX_CMD_INC_FALC_CLOCK,
+	MBOX_CMD_DEC_FALC_CLOCK,
+	MBOX_CMD_INC_SSPI_CLOCK,
+	MBOX_CMD_DEC_SSPI_CLOCK,
+	MBOX_CMD_SET_BW, /* no ACK/NAK required */
+	MBOX_CMD_SET_SS_PWR_GATING,
+	MBOX_CMD_SET_SS_PWR_UNGATING,
+	MBOX_CMD_SAVE_DFE_CTLE_CTX,
+	MBOX_CMD_AIRPLANE_MODE_ENABLED, /* unused */
+	MBOX_CMD_AIRPLANE_MODE_DISABLED, /* unused */
+	MBOX_CMD_START_HSIC_IDLE,
+	MBOX_CMD_STOP_HSIC_IDLE,
+	MBOX_CMD_DBC_WAKE_STACK, /* unused */
+	MBOX_CMD_HSIC_PRETEND_CONNECT,
+
+	MBOX_CMD_MAX,
+
+	/* Response message to above commands */
+	MBOX_CMD_ACK = 128,
+	MBOX_CMD_NAK
+};
+
+struct notifier_block;
+
+/*
+ * Tegra XUSB MBOX handler interface:
+ *   - Drivers which may handle mbox messages should register a notifier.
+ *   - The notifier event will be an mbox command (above) and the data will
+ *     be a pointer to struct mbox_notifier_data.
+ *   - If a notifier has handled the message, it should return NOTIFY_STOP
+ *     and populate resp_{cmd,data} appropriately.
+ *   - A resp_cmd of 0 indicates that no response should be sent.
+ */
+struct mbox_notifier_data {
+	u32 msg_data; /* Inbound message data */
+	u32 resp_cmd; /* Response message command */
+	u32 resp_data; /* Response message data */
+};
+
+extern int tegra_xhci_register_mbox_notifier(struct notifier_block *nb);
+extern void tegra_xhci_unregister_mbox_notifier(struct notifier_block *nb);
+
+#endif /* __TEGRA_XUSB_H */
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 07/10] phy: Add Tegra XUSB PHY driver
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
                   ` (5 preceding siblings ...)
  2014-05-15  0:33 ` [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver Andrew Bresticker
@ 2014-05-15  0:33 ` Andrew Bresticker
  2014-05-15  0:33 ` [RFC PATCH 08/10] ARM: tegra124: Bind CAR to syscon device Andrew Bresticker
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:33 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Andrew Bresticker

Add support for the Tegra XUSB PHY present on Tegra114 and Tegra124 SoCs.
This provides all PHY functionality for the Tegra XHCI host-controller
driver and supports UTMI, HSIC, and SuperSpeed interfaces.

While this PHY driver currently only handles USB, the SATA and PCIe
PHYs are programmed in a similar way using the same register set.
The driver could be extended in the future to support these PHY
types as well.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 .../bindings/phy/nvidia,tegra-xusb-phy.txt         |   76 ++
 drivers/phy/Kconfig                                |   11 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-tegra-xusb.c                       | 1171 ++++++++++++++++++++
 drivers/phy/phy-tegra-xusb.h                       |  270 +++++
 5 files changed, 1529 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/nvidia,tegra-xusb-phy.txt
 create mode 100644 drivers/phy/phy-tegra-xusb.c
 create mode 100644 drivers/phy/phy-tegra-xusb.h

diff --git a/Documentation/devicetree/bindings/phy/nvidia,tegra-xusb-phy.txt b/Documentation/devicetree/bindings/phy/nvidia,tegra-xusb-phy.txt
new file mode 100644
index 0000000..6d819f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/nvidia,tegra-xusb-phy.txt
@@ -0,0 +1,76 @@
+NVIDIA Tegra XUSB PHY
+
+The device node for the Tegra XUSB PHY present on Tegra114 and later SoCs.
+
+Required properties:
+ - compatible: Should be "nvidia,tegra114-xusb-phy" or
+   "nvidia,tegra124-xusb-phy".
+ - reg: Address and length of the XUSB_PADCTL register set.
+ - clocks: Handles to XUSB SS, SS source, HS source, FS source, PLL_U_480M,
+   CLK_M, and PLLE.  Note that PLL_U_480M and CLK_M are only necessary
+   on Tegra124.
+ - clock-names: Should be "xusb_ss", "xusb_ss_src", "xusb_hs_src",
+   "xusb_fs_src", "pll_u_480M", "clk_m",and "pll_e" respectively.
+ - resets: Handle to the XUSB SS reset.
+ - reset-names: Should be "xusb_ss".
+ - nvidia,clkrst: Handle to the clock-reset module syscon node.
+ - nvidia,ss-pads: Bitmap of enabled SuperSpeed pads:
+     bit 0 - SuperSpeed port 0
+     bit 1 - SuperSpeed port 1
+ - nvidia,utmi-pads: Bitmap of enabled USB2.0 UTMI pads:
+     bit 0 - UTMI port 0
+     bit 1 - UTMI port 1
+     bit 2 - UTMI port 2 (Tegra124 only)
+ - nvidia,hsic-pads: Bitmap of enabled USB2.0 HSIC pads:
+     bit 0 - HSIC port 0
+     bit 1 - HSIC port 1
+ - nvidia,hsic{0,1}-config: byte array with 9 elements specifiying the
+   configuration for the corresponding HISC port:
+     byte 0 - rx_strobe_trim
+     byte 1 - rx_data_trim
+     byte 2 - tx_rtune_n
+     byte 3 - tx_rtune_p
+     byte 4 - tx_slew_n
+     byte 5 - tx_slew_p
+     byte 6 - auto_term_en
+     byte 7 - strb_trim_val
+     byte 8 - pretend_connect
+   Only required for enabled HISC ports.
+ - nvidia,ss-port{0,1}-map: Mapping from SS port to its corresponding USB2.0
+   port.  Both fields have valid values from 0 to 2 (USB2.0 ports 0, 1, 2).
+   Only required for enabled SS pads.
+ - vbus{1,2,3}-supply: VBUS regulator for the corresponding UTMI pad.
+   Only required when the respective UTMI pad is enabled.
+ - vddio-hsic-supply: HSIC supply regulator.  Only required when HSIC ports
+   are enabled.
+Optional properties:
+ - nvidia,use-sata-lane: Should be set if SS port 1 is mapped to the SATA
+   lane.  Only applicable on Tegra124.
+
+Example:
+	phy@0,7009f000 {
+		compatible = "nvidia,tegra124-xusb-phy";
+		reg = <0x0 0x7009f000 0x0 0x1000>;
+		#phy-cells = <0>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_SS>,
+			 <&tegra_car TEGRA124_CLK_XUSB_SS_SRC>,
+			 <&tegra_car TEGRA124_CLK_XUSB_HS_SRC>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FS_SRC>,
+			 <&tegra_car TEGRA124_CLK_PLL_U_480M>,
+			 <&tegra_car TEGRA124_CLK_CLK_M>,
+			 <&tegra_car TEGRA124_CLK_PLL_E>;
+		clock-names = "xusb_ss", "xusb_ss_src", "xusb_hs_src",
+			      "xusb_fs_src", "pll_u_480M", "clk_m",
+			      "pll_e";
+		resets = <&tegra_car 156>;
+		reset-names = "xusb_ss";
+		nvidia,clkrst = <&tegra_car>;
+		nvidia,ss-pads = <0x3>;
+		nvidia,hsic-pads = <0x0>;
+		nvidia,utmi-pads = <0x7>;
+		nvidia,ss-port0-map = <0>;
+		nvidia,ss-port1-map = <2>;
+		vbus1-supply = <&vdd_usb1_vbus>;
+		vbus2-supply = <&vdd_run_cam>;
+		vbus3-supply = <&vdd_usb3_vbus>;
+	};
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 3bb05f1..8eb65ae 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -159,6 +159,17 @@ config PHY_EXYNOS5250_USB2
 	  particular SoC is compiled in the driver. In case of Exynos 5250 four
 	  phys are available - device, host, HSIC0 and HSIC.
 
+config PHY_TEGRA_XUSB
+	tristate "Support for NVIDIA Tegra XUSB PHY"
+	depends on USB_XHCI_TEGRA
+	select GENERIC_PHY
+	select MFD_SYSCON
+	help
+	  Enable this to support the XUSB PHY present on NVIDIA Tegra114
+	  and later SoCs.  This driver supports UTMI, HSIC, and SuperSpeed
+	  interfaces and handles all host PHY functionality for the Tegra
+	  XHCI host-controller driver.
+
 config PHY_XGENE
 	tristate "APM X-Gene 15Gbps PHY support"
 	depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST)
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 2faf78e..f682a8e 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -17,4 +17,5 @@ obj-$(CONFIG_PHY_SAMSUNG_USB2)		+= phy-samsung-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4210_USB2)	+= phy-exynos4210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS4X12_USB2)	+= phy-exynos4x12-usb2.o
 obj-$(CONFIG_PHY_EXYNOS5250_USB2)	+= phy-exynos5250-usb2.o
+obj-$(CONFIG_PHY_TEGRA_XUSB)		+= phy-tegra-xusb.o
 obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o
diff --git a/drivers/phy/phy-tegra-xusb.c b/drivers/phy/phy-tegra-xusb.c
new file mode 100644
index 0000000..78d2398
--- /dev/null
+++ b/drivers/phy/phy-tegra-xusb.c
@@ -0,0 +1,1171 @@
+/*
+ * NVIDIA Tegra XUSB PHY driver
+ *
+ * Copyright (C) 2014 NVIDIA Corporation
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/tegra-soc.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/resource.h>
+#include <linux/phy/phy.h>
+#include <linux/usb/tegra_xusb.h>
+
+#include "phy-tegra-xusb.h"
+
+struct tegra_xusb_hsic_config {
+	u8 rx_strobe_trim;
+	u8 rx_data_trim;
+	u8 tx_rtune_n;
+	u8 tx_rtune_p;
+	u8 tx_slew_n;
+	u8 tx_slew_p;
+	u8 auto_term_en;
+	u8 strb_trim_val;
+	u8 pretend_connect;
+};
+
+struct tegra_xusb_phy_calib_data {
+	u32 hs_curr_level_pad[TEGRA_XUSB_UTMI_COUNT];
+	u32 hs_iref_cap;
+	u32 hs_term_range_adj;
+	u32 hs_squelch_level;
+};
+
+struct tegra_xusb_phy_board_data {
+	unsigned long utmi_pads;
+	unsigned long hsic_pads;
+	unsigned long ss_pads;
+	bool use_sata_lane;
+	int ss_portmap[TEGRA_XUSB_SS_COUNT];
+	struct tegra_xusb_hsic_config hsic[TEGRA_XUSB_HSIC_COUNT];
+};
+
+struct tegra_xusb_phy_soc_config {
+	bool ss_idle_mode_ovrd;
+	bool has_ctle;
+	bool scale_ss_clk;
+	int num_utmi_pads;
+	u32 rx_wander;
+	u32 rx_eq;
+	u32 cdr_cntl;
+	u32 dfe_cntl;
+	u32 hs_slew;
+	u32 ls_rslew_pad[TEGRA_XUSB_UTMI_COUNT];
+	u32 hs_disc_lvl;
+	u32 spare_in;
+	int hsic_port_offset;
+	const struct tegra_xusb_padctl_regs *padctl_offsets;
+};
+
+struct tegra_xusb_phy {
+	struct device *dev;
+
+	void __iomem *padctl_regs;
+	struct regmap *clkrst_regs;
+
+	struct notifier_block mbox_nb;
+
+	struct clk *ss_src_clk;
+	struct clk *hs_src_clk;
+	struct clk *fs_src_clk;
+	struct clk *ss_clk;
+	struct clk *pll_u_480M;
+	struct clk *clk_m;
+	struct clk *plle;
+	struct reset_control *ss_rst;
+
+	struct regulator *utmi_vbus[TEGRA_XUSB_UTMI_COUNT];
+	struct regulator *vddio_hsic;
+
+	/* DFE and CTLE context */
+	bool ss_ctx_saved[TEGRA_XUSB_SS_COUNT];
+	u8 tap1_val[TEGRA_XUSB_SS_COUNT];
+	u8 amp_val[TEGRA_XUSB_SS_COUNT];
+	u8 ctle_z_val[TEGRA_XUSB_SS_COUNT];
+	u8 ctle_g_val[TEGRA_XUSB_SS_COUNT];
+
+	struct tegra_xusb_phy_board_data board_data;
+	struct tegra_xusb_phy_calib_data calib_data;
+	const struct tegra_xusb_phy_soc_config *soc_config;
+};
+
+static inline u32 padctl_readl(struct tegra_xusb_phy *tegra, u32 reg)
+{
+	BUG_ON(reg == PADCTL_REG_NONE);
+	return readl(tegra->padctl_regs + reg);
+}
+
+static inline void padctl_writel(struct tegra_xusb_phy *tegra, u32 val, u32 reg)
+{
+	BUG_ON(reg == PADCTL_REG_NONE);
+	writel(val, tegra->padctl_regs + reg);
+}
+
+static inline u32 clkrst_readl(struct tegra_xusb_phy *tegra, u32 reg)
+{
+	u32 val;
+
+	regmap_read(tegra->clkrst_regs, reg, &val);
+	return val;
+}
+
+static inline void clkrst_writel(struct tegra_xusb_phy *tegra, u32 val, u32 reg)
+{
+	regmap_write(tegra->clkrst_regs, reg, val);
+}
+
+static void hsic_pad_init(struct tegra_xusb_phy *tegra, int pad)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	struct tegra_xusb_hsic_config *hsic = &tegra->board_data.hsic[pad];
+	u32 reg;
+
+	padregs = tegra->soc_config->padctl_offsets;
+	reg = padctl_readl(tegra, padregs->usb2_hsic_padX_ctlY_0[pad][2]);
+	reg &= ~(USB2_HSIC_RX_STROBE_TRIM(~0) | USB2_HSIC_RX_DATA_TRIM(~0));
+	reg |= USB2_HSIC_RX_STROBE_TRIM(hsic->rx_strobe_trim) |
+		USB2_HSIC_RX_DATA_TRIM(hsic->rx_data_trim);
+	padctl_writel(tegra, reg, padregs->usb2_hsic_padX_ctlY_0[pad][2]);
+
+	reg = padctl_readl(tegra, padregs->usb2_hsic_padX_ctlY_0[pad][0]);
+	reg &= ~(USB2_HSIC_TX_RTUNEP(~0) | USB2_HSIC_TX_RTUNEN(~0) |
+		 USB2_HSIC_TX_SLEWP(~0) | USB2_HSIC_TX_SLEWN(~0));
+	reg |= USB2_HSIC_TX_RTUNEP(hsic->tx_rtune_p) |
+		USB2_HSIC_TX_RTUNEN(hsic->tx_rtune_n) |
+		USB2_HSIC_TX_SLEWP(hsic->tx_slew_p) |
+		USB2_HSIC_TX_SLEWN(hsic->tx_slew_n);
+	padctl_writel(tegra, reg, padregs->usb2_hsic_padX_ctlY_0[pad][0]);
+
+	reg = padctl_readl(tegra, padregs->usb2_hsic_padX_ctlY_0[pad][1]);
+	if (hsic->auto_term_en)
+		reg |= USB2_HSIC_AUTO_TERM_EN;
+	else
+		reg &= ~USB2_HSIC_AUTO_TERM_EN;
+	padctl_writel(tegra, reg, padregs->usb2_hsic_padX_ctlY_0[pad][1]);
+
+	reg = padctl_readl(tegra, padregs->hsic_strb_trim_ctl0);
+	reg &= ~HSIC_STRB_TRIM(~0);
+	reg |= HSIC_STRB_TRIM(hsic->strb_trim_val);
+	padctl_writel(tegra, reg, padregs->hsic_strb_trim_ctl0);
+
+	reg = padctl_readl(tegra, padregs->usb2_pad_mux_0);
+	reg |= USB2_HSIC_PAD_PORT(pad);
+	padctl_writel(tegra, reg, padregs->usb2_pad_mux_0);
+}
+
+static void hsic_pad_enable(struct tegra_xusb_phy *tegra, int pad)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 reg;
+
+	padregs = tegra->soc_config->padctl_offsets;
+
+	reg = padctl_readl(tegra, padregs->usb2_hsic_padX_ctlY_0[pad][1]);
+	reg &= ~(USB2_HSIC_RPD_DATA | USB2_HSIC_RPD_STROBE |
+		 USB2_HSIC_RPU_DATA | USB2_HSIC_RPU_STROBE |
+		 USB2_HSIC_PD_RX | USB2_HSIC_PD_ZI |
+		 USB2_HSIC_PD_TRX | USB2_HSIC_PD_TX);
+	/* Keep HSIC in IDLE */
+	reg |= USB2_HSIC_RPD_DATA | USB2_HSIC_RPU_STROBE;
+	padctl_writel(tegra, reg, padregs->usb2_hsic_padX_ctlY_0[pad][1]);
+}
+
+static void hsic_pad_disable(struct tegra_xusb_phy *tegra, int pad)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 reg;
+
+	padregs = tegra->soc_config->padctl_offsets;
+
+	reg = padctl_readl(tegra, padregs->usb2_hsic_padX_ctlY_0[pad][1]);
+	reg |= (USB2_HSIC_PD_RX | USB2_HSIC_PD_ZI | USB2_HSIC_PD_TRX |
+		USB2_HSIC_PD_TX);
+	padctl_writel(tegra, reg, padregs->usb2_hsic_padX_ctlY_0[pad][1]);
+}
+
+static void hsic_pad_set_idle(struct tegra_xusb_phy *tegra, int pad, bool set)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 reg;
+
+	padregs = tegra->soc_config->padctl_offsets;
+
+	reg = padctl_readl(tegra, padregs->usb2_hsic_padX_ctlY_0[pad][1]);
+	reg &= ~(USB2_HSIC_RPD_DATA | USB2_HSIC_RPD_STROBE |
+		 USB2_HSIC_RPU_DATA | USB2_HSIC_RPU_STROBE);
+	if (set)
+		reg |= USB2_HSIC_RPD_DATA | USB2_HSIC_RPU_STROBE;
+	padctl_writel(tegra, reg, padregs->usb2_hsic_padX_ctlY_0[pad][1]);
+}
+
+static void utmi_pad_init(struct tegra_xusb_phy *tegra, int pad)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 reg;
+
+	padregs = tegra->soc_config->padctl_offsets;
+
+	reg = padctl_readl(tegra, padregs->usb2_bias_pad_ctlY_0[0]);
+	reg &= ~(USB2_BIAS_HS_SQUELCH_LEVEL(~0) |
+		 USB2_BIAS_HS_DISCON_LEVEL(~0));
+	reg |= USB2_BIAS_HS_SQUELCH_LEVEL(tegra->calib_data.hs_squelch_level) |
+		USB2_BIAS_HS_DISCON_LEVEL(tegra->soc_config->hs_disc_lvl);
+	padctl_writel(tegra, reg, padregs->usb2_bias_pad_ctlY_0[0]);
+
+	reg = padctl_readl(tegra, padregs->usb2_pad_mux_0);
+	reg &= ~USB2_OTG_PAD_PORT_MASK(pad);
+	reg |= USB2_OTG_PAD_PORT_OWNER_XUSB(pad);
+	padctl_writel(tegra, reg, padregs->usb2_pad_mux_0);
+
+	reg = padctl_readl(tegra, padregs->usb2_port_cap_0);
+	reg &= ~USB2_PORT_CAP_MASK(pad);
+	reg |= USB2_PORT_CAP_HOST(pad);
+	padctl_writel(tegra, reg, padregs->usb2_port_cap_0);
+
+	reg = padctl_readl(tegra, padregs->usb2_otg_padX_ctlY_0[pad][0]);
+	reg &= ~(USB2_OTG_HS_CURR_LVL(~0) | USB2_OTG_HS_SLEW(~0) |
+		 USB2_OTG_FS_SLEW(~0) | USB2_OTG_LS_RSLEW(~0) |
+		 USB2_OTG_PD | USB2_OTG_PD2 | USB2_OTG_PD_ZI);
+	reg |= USB2_OTG_HS_SLEW(tegra->soc_config->hs_slew) |
+		USB2_OTG_LS_RSLEW(tegra->soc_config->ls_rslew_pad[pad]) |
+		USB2_OTG_HS_CURR_LVL(tegra->calib_data.hs_curr_level_pad[pad]);
+	padctl_writel(tegra, reg, padregs->usb2_otg_padX_ctlY_0[pad][0]);
+
+	reg = padctl_readl(tegra, padregs->usb2_otg_padX_ctlY_0[pad][1]);
+	reg &= ~(USB2_OTG_TERM_RANGE_AD(~0) | USB2_OTG_HS_IREF_CAP(~0) |
+		 USB2_OTG_PD_DR | USB2_OTG_PD_CHRP_FORCE_POWERUP |
+		 USB2_OTG_PD_DISC_FORCE_POWERUP);
+	reg |= USB2_OTG_HS_IREF_CAP(tegra->calib_data.hs_iref_cap) |
+		USB2_OTG_TERM_RANGE_AD(tegra->calib_data.hs_term_range_adj);
+	padctl_writel(tegra, reg, padregs->usb2_otg_padX_ctlY_0[pad][1]);
+}
+
+static void utmi_pads_enable(struct tegra_xusb_phy *tegra)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 val;
+
+	padregs = tegra->soc_config->padctl_offsets;
+
+	val = padctl_readl(tegra, padregs->usb2_bias_pad_ctlY_0[0]);
+	val &= ~USB2_BIAS_PD;
+	padctl_writel(tegra, val, padregs->usb2_bias_pad_ctlY_0[0]);
+}
+
+static void utmi_pads_disable(struct tegra_xusb_phy *tegra)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 val;
+
+	padregs = tegra->soc_config->padctl_offsets;
+
+	val = padctl_readl(tegra, padregs->usb2_bias_pad_ctlY_0[0]);
+	val |= USB2_BIAS_PD;
+	padctl_writel(tegra, val, padregs->usb2_bias_pad_ctlY_0[0]);
+}
+
+static void ss_save_context(struct tegra_xusb_phy *tegra, int pad)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 offset;
+	u32 reg;
+
+	padregs = tegra->soc_config->padctl_offsets;
+	tegra->ss_ctx_saved[pad] = true;
+
+	if (pad == 1 && tegra->board_data.use_sata_lane)
+		offset = padregs->iophy_misc_pad_s0_ctlY_0[5];
+	else
+		offset = padregs->iophy_misc_pad_pX_ctlY_0[pad][5];
+
+	reg = padctl_readl(tegra, offset);
+	reg &= ~IOPHY_MISC_OUT_SEL(~0);
+	reg |= IOPHY_MISC_OUT_SEL(IOPHY_MISC_OUT_SEL_TAP);
+	padctl_writel(tegra, reg, offset);
+
+	reg = padctl_readl(tegra, offset);
+	tegra->tap1_val[pad] = IOPHY_MISC_OUT_TAP_VAL(reg);
+
+	reg = padctl_readl(tegra, offset);
+	reg &= ~IOPHY_MISC_OUT_SEL(~0);
+	reg |= IOPHY_MISC_OUT_SEL(IOPHY_MISC_OUT_SEL_AMP);
+	padctl_writel(tegra, reg, offset);
+
+	reg = padctl_readl(tegra, offset);
+	tegra->amp_val[pad] = IOPHY_MISC_OUT_AMP_VAL(reg);
+
+	reg = padctl_readl(tegra, padregs->iophy_usb3_padX_ctlY_0[pad][3]);
+	reg &= ~IOPHY_USB3_DFE_CNTL_TAP(~0);
+	reg |= IOPHY_USB3_DFE_CNTL_TAP(tegra->tap1_val[pad]);
+	padctl_writel(tegra, reg, padregs->iophy_usb3_padX_ctlY_0[pad][3]);
+
+	reg = padctl_readl(tegra, padregs->iophy_usb3_padX_ctlY_0[pad][3]);
+	reg &= ~IOPHY_USB3_DFE_CNTL_AMP(~0);
+	reg |= IOPHY_USB3_DFE_CNTL_AMP(tegra->amp_val[pad]);
+	padctl_writel(tegra, reg, padregs->iophy_usb3_padX_ctlY_0[pad][3]);
+
+	if (!tegra->soc_config->has_ctle)
+		return;
+
+	reg = padctl_readl(tegra, offset);
+	reg &= ~IOPHY_MISC_OUT_SEL(~0);
+	reg |= IOPHY_MISC_OUT_SEL(IOPHY_MISC_OUT_SEL_LATCH_G_Z);
+	padctl_writel(tegra, reg, offset);
+
+	reg = padctl_readl(tegra, offset);
+	reg &= ~IOPHY_MISC_OUT_SEL(~0);
+	reg |= IOPHY_MISC_OUT_SEL(IOPHY_MISC_OUT_SEL_G_Z);
+	padctl_writel(tegra, reg, offset);
+
+	reg = padctl_readl(tegra, offset);
+	tegra->ctle_g_val[pad] = IOPHY_MISC_OUT_G_Z_VAL(reg);
+
+	reg = padctl_readl(tegra, offset);
+	reg &= ~IOPHY_MISC_OUT_SEL(~0);
+	reg |= IOPHY_MISC_OUT_SEL(IOPHY_MISC_OUT_SEL_CTLE_Z);
+	padctl_writel(tegra, reg, offset);
+
+	reg = padctl_readl(tegra, offset);
+	tegra->ctle_z_val[pad] = IOPHY_MISC_OUT_G_Z_VAL(reg);
+
+	reg = padctl_readl(tegra, padregs->iophy_usb3_padX_ctlY_0[pad][1]);
+	reg &= ~IOPHY_USB3_RX_EQ_Z(~0);
+	reg |= IOPHY_USB3_RX_EQ_Z(tegra->ctle_z_val[pad]);
+	padctl_writel(tegra, reg, padregs->iophy_usb3_padX_ctlY_0[pad][1]);
+
+	reg = padctl_readl(tegra, padregs->iophy_usb3_padX_ctlY_0[pad][1]);
+	reg &= ~IOPHY_USB3_RX_EQ_G(~0);
+	reg |= IOPHY_USB3_RX_EQ_G(tegra->ctle_g_val[pad]);
+	padctl_writel(tegra, reg, padregs->iophy_usb3_padX_ctlY_0[pad][1]);
+}
+
+static void ss_restore_context(struct tegra_xusb_phy *tegra, int pad)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 reg;
+
+	if (!tegra->ss_ctx_saved[pad])
+		return;
+
+	padregs = tegra->soc_config->padctl_offsets;
+
+	reg = padctl_readl(tegra, padregs->iophy_usb3_padX_ctlY_0[pad][3]);
+	reg &= ~(IOPHY_USB3_DFE_CNTL_AMP(~0) |
+		 IOPHY_USB3_DFE_CNTL_TAP(~0));
+	reg |= IOPHY_USB3_DFE_CNTL_AMP(tegra->amp_val[pad]) |
+		IOPHY_USB3_DFE_CNTL_TAP(tegra->tap1_val[pad]);
+	padctl_writel(tegra, reg, padregs->iophy_usb3_padX_ctlY_0[pad][3]);
+
+	if (!tegra->soc_config->has_ctle)
+		return;
+
+	reg = padctl_readl(tegra, padregs->iophy_usb3_padX_ctlY_0[pad][1]);
+	reg &= ~(IOPHY_USB3_RX_EQ_Z(~0) | IOPHY_USB3_RX_EQ_G(~0));
+	reg |= (IOPHY_USB3_RX_EQ_Z(tegra->ctle_z_val[pad]) |
+		IOPHY_USB3_RX_EQ_G(tegra->ctle_g_val[pad]));
+	padctl_writel(tegra, reg, padregs->iophy_usb3_padX_ctlY_0[pad][1]);
+}
+
+/* Disable/enable SS wake logic */
+static void ss_set_wake(struct tegra_xusb_phy *tegra, bool on)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 val;
+	int i;
+
+	padregs = tegra->soc_config->padctl_offsets;
+	val = padctl_readl(tegra, padregs->elpg_program_0);
+	for_each_set_bit(i, &tegra->board_data.ss_pads, TEGRA_XUSB_SS_COUNT) {
+		if (on)
+			val |= SSP_ELPG_CLAMP_EN_EARLY(i);
+		else
+			val &= ~SSP_ELPG_CLAMP_EN_EARLY(i);
+	}
+	padctl_writel(tegra, val, padregs->elpg_program_0);
+
+	/*
+	 * There needs to be a delay between writes to CLAMP_EN_EARLY and
+	 * CLAMP_EN
+	 */
+	udelay(100);
+
+	val = padctl_readl(tegra, padregs->elpg_program_0);
+	for_each_set_bit(i, &tegra->board_data.ss_pads, TEGRA_XUSB_SS_COUNT) {
+		if (on)
+			val |= SSP_ELPG_CLAMP_EN(i);
+		else
+			val &= ~SSP_ELPG_CLAMP_EN(i);
+	}
+	padctl_writel(tegra, val, padregs->elpg_program_0);
+
+	/* Wait for 250us for CLAMP_EN to propagate */
+	if (on)
+		udelay(250);
+
+	val = padctl_readl(tegra, padregs->elpg_program_0);
+	for_each_set_bit(i, &tegra->board_data.ss_pads, TEGRA_XUSB_SS_COUNT) {
+		if (on)
+			val |= SSP_ELPG_VCORE_DOWN(i);
+		else
+			val &= ~SSP_ELPG_VCORE_DOWN(i);
+	}
+	padctl_writel(tegra, val, padregs->elpg_program_0);
+}
+
+static int ss_set_clock_rate(struct tegra_xusb_phy *tegra, unsigned int rate)
+{
+	unsigned int new_parent_rate, old_parent_rate, div;
+	int ret;
+	struct clk *ss_clk = tegra->ss_src_clk;
+
+	if (clk_get_rate(ss_clk) == rate)
+		return 0;
+
+	switch (rate) {
+	case SS_CLK_HIGH_SPEED:
+		/* Reparent to PLLU_480M. Set div first to avoid overclocking */
+		old_parent_rate = clk_get_rate(clk_get_parent(ss_clk));
+		new_parent_rate = clk_get_rate(tegra->pll_u_480M);
+		div = new_parent_rate / rate;
+		ret = clk_set_rate(ss_clk, old_parent_rate / div);
+		if (ret) {
+			dev_err(tegra->dev, "Failed to set SS rate: %d\n",
+				ret);
+			return ret;
+		}
+		ret = clk_set_parent(ss_clk, tegra->pll_u_480M);
+		if (ret) {
+			dev_err(tegra->dev, "Failed to set SS parent: %d\n",
+				ret);
+			return ret;
+		}
+		break;
+	case SS_CLK_LOW_SPEED:
+		/* Reparent to CLK_M */
+		ret = clk_set_parent(ss_clk, tegra->clk_m);
+		if (ret) {
+			dev_err(tegra->dev, "Failed to set SS parent: %d\n",
+				ret);
+			return ret;
+		}
+		ret = clk_set_rate(ss_clk, rate);
+		if (ret) {
+			dev_err(tegra->dev, "Failed to set SS rate: %d\n",
+				ret);
+			return ret;
+		}
+		break;
+	default:
+		dev_err(tegra->dev, "Invalid SS rate: %u\n", rate);
+		return -EINVAL;
+	}
+
+	if (clk_get_rate(ss_clk) != rate) {
+		dev_err(tegra->dev, "SS clock doesn't match requested rate\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void ss_pad_init(struct tegra_xusb_phy *tegra, int pad)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 reg;
+
+	padregs = tegra->soc_config->padctl_offsets;
+	reg = padctl_readl(tegra, padregs->iophy_usb3_padX_ctlY_0[pad][1]);
+	reg &= ~(IOPHY_USB3_RX_WANDER(~0) | IOPHY_USB3_RX_EQ(~0) |
+		 IOPHY_USB3_CDR_CNTL(~0));
+	reg |= IOPHY_USB3_RX_WANDER(tegra->soc_config->rx_wander) |
+		IOPHY_USB3_RX_EQ(tegra->soc_config->rx_eq) |
+		IOPHY_USB3_CDR_CNTL(tegra->soc_config->cdr_cntl);
+	padctl_writel(tegra, reg, padregs->iophy_usb3_padX_ctlY_0[pad][1]);
+
+	padctl_writel(tegra, tegra->soc_config->dfe_cntl,
+		      padregs->iophy_usb3_padX_ctlY_0[pad][3]);
+
+	if (pad == 1 && tegra->board_data.use_sata_lane) {
+		reg = padctl_readl(tegra, padregs->iophy_misc_pad_s0_ctlY_0[4]);
+		reg |= IOPHY_RX_QEYE_EN;
+		padctl_writel(tegra, reg, padregs->iophy_misc_pad_s0_ctlY_0[4]);
+
+		reg = padctl_readl(tegra, padregs->iophy_misc_pad_s0_ctlY_0[1]);
+		reg &= ~IOPHY_SPARE_IN(~0);
+		reg |= IOPHY_SPARE_IN(tegra->soc_config->spare_in);
+		padctl_writel(tegra, reg, padregs->iophy_misc_pad_s0_ctlY_0[1]);
+	} else {
+		reg = padctl_readl(tegra,
+			padregs->iophy_misc_pad_pX_ctlY_0[pad][4]);
+		reg |= IOPHY_RX_QEYE_EN;
+		padctl_writel(tegra, reg,
+			padregs->iophy_misc_pad_pX_ctlY_0[pad][4]);
+
+		reg = padctl_readl(tegra,
+			padregs->iophy_misc_pad_pX_ctlY_0[pad][1]);
+		reg &= ~IOPHY_SPARE_IN(~0);
+		reg |= IOPHY_SPARE_IN(tegra->soc_config->spare_in);
+		padctl_writel(tegra, reg,
+			padregs->iophy_misc_pad_pX_ctlY_0[pad][1]);
+	}
+
+	reg = padctl_readl(tegra, padregs->ss_port_map_0);
+	reg &= ~SS_PORT_MAP_MASK(pad);
+	reg |= (tegra->board_data.ss_portmap[pad] << SS_PORT_MAP_SHIFT(pad)) &
+		SS_PORT_MAP_MASK(pad);
+	padctl_writel(tegra, reg, padregs->ss_port_map_0);
+
+	ss_restore_context(tegra, pad);
+}
+
+static void ss_pad_rx_idle_mode_override(struct tegra_xusb_phy *tegra, int pad)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 reg, offset;
+
+	/* Set RX_IDLE_MODE_OVRD to save power on unused pads */
+	padregs = tegra->soc_config->padctl_offsets;
+	if (pad == 1 && tegra->board_data.use_sata_lane)
+		offset = padregs->iophy_misc_pad_s0_ctlY_0[2];
+	else
+		offset = padregs->iophy_misc_pad_pX_ctlY_0[pad][2];
+	reg = padctl_readl(tegra, offset);
+	reg &= ~IOPHY_RX_IDLE_MODE;
+	reg |= IOPHY_RX_IDLE_MODE_OVRD;
+	padctl_writel(tegra, reg, offset);
+}
+
+static void ss_lanes_init(struct tegra_xusb_phy *tegra)
+{
+	const struct tegra_xusb_padctl_regs *padregs;
+	u32 val;
+
+	padregs = tegra->soc_config->padctl_offsets;
+	if ((tegra->board_data.ss_pads & BIT(1)) &&
+	    tegra->board_data.use_sata_lane) {
+		/* Program SATA pad phy */
+		val = padctl_readl(tegra, padregs->iophy_pll_s0_ctlY_0[0]);
+		val &= ~IOPHY_PLL_PLL0_REFCLK_NDIV(~0);
+		val |= IOPHY_PLL_PLL0_REFCLK_NDIV(0x2);
+		padctl_writel(tegra, val, padregs->iophy_pll_s0_ctlY_0[0]);
+
+		val = padctl_readl(tegra, padregs->iophy_pll_s0_ctlY_0[1]);
+		val &= ~(IOPHY_PLL_XDIGCLK_SEL(~0) | IOPHY_PLL_TXCLKREF_SEL |
+			 IOPHY_PLL_TCLKOUT_EN | IOPHY_PLL_PLL0_CP_CNTL(~0) |
+			 IOPHY_PLL_PLL1_CP_CNTL(~0));
+		val |= IOPHY_PLL_XDIGCLK_SEL(0x7) | IOPHY_PLL_TXCLKREF_SEL |
+			IOPHY_PLL_PLL0_CP_CNTL(0x8) |
+			IOPHY_PLL_PLL1_CP_CNTL(0x8);
+		padctl_writel(tegra, val, padregs->iophy_pll_s0_ctlY_0[1]);
+
+		val = padctl_readl(tegra, padregs->iophy_pll_s0_ctlY_0[2]);
+		val &= ~IOPHY_PLL_RCAL_BYPASS;
+		padctl_writel(tegra, val, padregs->iophy_pll_s0_ctlY_0[2]);
+
+		/* Enable SATA PADPLL clocks */
+		val = clkrst_readl(tegra, SATA_PLL_CFG0_0);
+		val &= ~SATA_PADPLL_RESET_SWCTL;
+		val |= SATA_PADPLL_USE_LOCKDET | SATA_SEQ_START_STATE;
+		clkrst_writel(tegra, val, SATA_PLL_CFG0_0);
+
+		udelay(1);
+
+		val = clkrst_readl(tegra, SATA_PLL_CFG0_0);
+		val |= SATA_SEQ_ENABLE;
+		clkrst_writel(tegra, val, SATA_PLL_CFG0_0);
+	}
+
+	/* Program ownerhsip of lanes */
+	val = padctl_readl(tegra, padregs->usb3_pad_mux_0);
+	if (tegra->board_data.ss_pads & BIT(0)) {
+		/* Port 0 is always mapped to PCIe lane0 */
+		val &= ~USB3_PCIE_PAD_LANE_OWNER(0, ~0);
+		val |= USB3_PCIE_PAD_LANE_OWNER(0, USB3_LANE_OWNER_USB3_SS);
+	}
+	if (tegra->board_data.ss_pads & BIT(1)) {
+		/* Port 1 can either be mapped to SATA lane or PCIe lane1 */
+		if (tegra->board_data.use_sata_lane) {
+			val &= ~USB3_SATA_PAD_LANE_OWNER(~0);
+			val |= USB3_SATA_PAD_LANE_OWNER(USB3_LANE_OWNER_USB3_SS);
+		} else {
+			val &= ~USB3_PCIE_PAD_LANE_OWNER(1, ~0);
+			val |= USB3_PCIE_PAD_LANE_OWNER(1, USB3_LANE_OWNER_USB3_SS);
+		}
+	}
+	padctl_writel(tegra, val, padregs->usb3_pad_mux_0);
+
+	/* Bring enabled lane out of IDDQ */
+	val = padctl_readl(tegra, padregs->usb3_pad_mux_0);
+	if (tegra->board_data.ss_pads & BIT(0))
+		val |= USB3_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK(0);
+	if (tegra->board_data.ss_pads & BIT(1)) {
+		if (tegra->board_data.use_sata_lane)
+			val |= USB3_FORCE_SATA_PAD_IDDQ_DISABLE_MASK;
+		else
+			val |= USB3_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK(1);
+	}
+	padctl_writel(tegra, val, padregs->usb3_pad_mux_0);
+
+	udelay(1);
+
+	/* Release pad muxing logic state latching */
+	val = padctl_readl(tegra, padregs->elpg_program_0);
+	val &= ~AUX_MUX_LP0_CLAMP_EN;
+	padctl_writel(tegra, val, padregs->elpg_program_0);
+
+	udelay(100);
+
+	val &= ~AUX_MUX_LP0_CLAMP_EN_EARLY;
+	padctl_writel(tegra, val, padregs->elpg_program_0);
+
+	udelay(100);
+
+	val &= ~AUX_MUX_LP0_VCORE_DOWN;
+	padctl_writel(tegra, val, padregs->elpg_program_0);
+}
+
+static int tegra_xusb_phy_mbox_notifier(struct notifier_block *nb,
+					unsigned long event, void *p)
+{
+	struct tegra_xusb_phy *tegra = container_of(nb, struct tegra_xusb_phy,
+						    mbox_nb);
+	struct mbox_notifier_data *data = (struct mbox_notifier_data *)p;
+	unsigned long ports;
+	int i, pad, ret = 0;
+
+	switch (event) {
+	case MBOX_CMD_INC_SSPI_CLOCK:
+	case MBOX_CMD_DEC_SSPI_CLOCK:
+		if (!tegra->soc_config->scale_ss_clk) {
+			data->resp_cmd = MBOX_CMD_ACK;
+			data->resp_data = data->msg_data;
+			return NOTIFY_STOP;
+		}
+		ret = ss_set_clock_rate(tegra, data->msg_data * 1000);
+		data->resp_data = clk_get_rate(tegra->ss_src_clk) / 1000;
+		if (ret)
+			data->resp_cmd = MBOX_CMD_NAK;
+		else
+			data->resp_cmd = MBOX_CMD_ACK;
+		return NOTIFY_STOP;
+	case MBOX_CMD_SAVE_DFE_CTLE_CTX:
+		data->resp_data = data->msg_data;
+		if (data->msg_data > TEGRA_XUSB_SS_COUNT) {
+			data->resp_cmd = MBOX_CMD_NAK;
+		} else {
+			ss_save_context(tegra, data->msg_data);
+			data->resp_cmd = MBOX_CMD_ACK;
+		}
+		return NOTIFY_STOP;
+	case MBOX_CMD_START_HSIC_IDLE:
+	case MBOX_CMD_STOP_HSIC_IDLE:
+		ports = data->msg_data;
+		data->resp_data = ports;
+		for_each_set_bit(i, &ports, BITS_PER_LONG) {
+			pad = i - 1 - tegra->soc_config->hsic_port_offset;
+			if (pad > TEGRA_XUSB_HSIC_COUNT) {
+				ret = -EINVAL;
+				break;
+			}
+			if (event == MBOX_CMD_START_HSIC_IDLE)
+				hsic_pad_set_idle(tegra, pad, true);
+			else
+				hsic_pad_set_idle(tegra, pad, false);
+		}
+		if (ret)
+			data->resp_cmd = MBOX_CMD_NAK;
+		else
+			data->resp_cmd = MBOX_CMD_ACK;
+		return NOTIFY_STOP;
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
+static int tegra_xusb_phy_init(struct phy *phy)
+{
+	struct tegra_xusb_phy *tegra = phy_get_drvdata(phy);
+	int ret, i;
+
+	tegra->mbox_nb.notifier_call = tegra_xusb_phy_mbox_notifier;
+	ret = tegra_xhci_register_mbox_notifier(&tegra->mbox_nb);
+	if (ret) {
+		dev_err(tegra->dev, "Failed to register handler\n");
+		return ret;
+	}
+
+	for_each_set_bit(i, &tegra->board_data.utmi_pads, TEGRA_XUSB_UTMI_COUNT)
+		utmi_pad_init(tegra, i);
+
+	for_each_set_bit(i, &tegra->board_data.hsic_pads, TEGRA_XUSB_HSIC_COUNT)
+		hsic_pad_init(tegra, i);
+
+	for (i = 0; i < TEGRA_XUSB_SS_COUNT; i++) {
+		if (tegra->board_data.ss_pads & BIT(i))
+			ss_pad_init(tegra, i);
+		else
+			ss_pad_rx_idle_mode_override(tegra, i);
+	}
+
+	ss_lanes_init(tegra);
+
+	return 0;
+}
+
+static int tegra_xusb_phy_exit(struct phy *phy)
+{
+	struct tegra_xusb_phy *tegra = phy_get_drvdata(phy);
+
+	tegra_xhci_unregister_mbox_notifier(&tegra->mbox_nb);
+
+	return 0;
+}
+
+static int tegra_xusb_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_phy *tegra = phy_get_drvdata(phy);
+	int i, ret;
+
+	for_each_set_bit(i, &tegra->board_data.utmi_pads,
+			 TEGRA_XUSB_UTMI_COUNT) {
+		ret = regulator_enable(tegra->utmi_vbus[i]);
+		if (ret) {
+			dev_err(tegra->dev, "Failed to enable vbus%d\n", i);
+			return ret;
+		}
+	}
+	if (tegra->board_data.hsic_pads) {
+		ret = regulator_enable(tegra->vddio_hsic);
+		if (ret) {
+			dev_err(tegra->dev, "Failed to enable vddio-hsic\n");
+			return ret;
+		}
+	}
+
+	clk_prepare_enable(tegra->plle);
+	clk_prepare_enable(tegra->ss_clk);
+	clk_prepare_enable(tegra->hs_src_clk);
+	clk_prepare_enable(tegra->fs_src_clk);
+	if (tegra->soc_config->scale_ss_clk) {
+		ret = ss_set_clock_rate(tegra, SS_CLK_HIGH_SPEED);
+		if (ret) {
+			dev_err(tegra->dev, "Failed to set xusb_ss rate\n");
+			return ret;
+		}
+	}
+
+	ss_set_wake(tegra, false);
+
+	utmi_pads_enable(tegra);
+
+	for_each_set_bit(i, &tegra->board_data.hsic_pads, TEGRA_XUSB_HSIC_COUNT)
+		hsic_pad_enable(tegra, i);
+
+	return 0;
+}
+
+static int tegra_xusb_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_phy *tegra = phy_get_drvdata(phy);
+	int i;
+
+	for_each_set_bit(i, &tegra->board_data.hsic_pads, TEGRA_XUSB_HSIC_COUNT)
+		hsic_pad_disable(tegra, i);
+	utmi_pads_disable(tegra);
+
+	clk_disable_unprepare(tegra->plle);
+	clk_disable_unprepare(tegra->ss_clk);
+	clk_disable_unprepare(tegra->hs_src_clk);
+	clk_disable_unprepare(tegra->fs_src_clk);
+
+	for_each_set_bit(i, &tegra->board_data.utmi_pads, TEGRA_XUSB_UTMI_COUNT)
+		regulator_disable(tegra->utmi_vbus[i]);
+	if (tegra->board_data.hsic_pads)
+		regulator_disable(tegra->vddio_hsic);
+
+	return 0;
+}
+
+static const struct tegra_xusb_padctl_regs tegra114_padctl_offsets = {
+	.boot_media_0			= 0x0,
+	.usb2_pad_mux_0			= 0x4,
+	.usb2_port_cap_0		= 0x8,
+	.snps_oc_map_0			= 0xc,
+	.usb2_oc_map_0			= 0x10,
+	.ss_port_map_0			= 0x14,
+	.oc_det_0			= 0x18,
+	.elpg_program_0			= 0x1c,
+	.usb2_bchrg_otgpadX_ctlY_0	= {
+		{0x20, PADCTL_REG_NONE},
+		{0x24, PADCTL_REG_NONE},
+		{PADCTL_REG_NONE, PADCTL_REG_NONE}
+	},
+	.usb2_bchrg_bias_pad_0		= 0x28,
+	.usb2_bchrg_tdcd_dbnc_timer_0	= 0x2c,
+	.iophy_pll_p0_ctlY_0		= {0x30, 0x34, 0x38, 0x3c},
+	.iophy_usb3_padX_ctlY_0		= {
+		{0x40, 0x48, 0x50, 0x58},
+		{0x44, 0x4c, 0x54, 0x5c}
+	},
+	.iophy_misc_pad_pX_ctlY_0	= {
+		{0x60, 0x68, 0x70, 0x78, 0x80, 0x88},
+		{0x64, 0x6c, 0x74, 0x7c, 0x84, 0x8c},
+		{PADCTL_REG_NONE, PADCTL_REG_NONE, PADCTL_REG_NONE,
+		 PADCTL_REG_NONE, PADCTL_REG_NONE},
+		{PADCTL_REG_NONE, PADCTL_REG_NONE, PADCTL_REG_NONE,
+		 PADCTL_REG_NONE, PADCTL_REG_NONE},
+		{PADCTL_REG_NONE, PADCTL_REG_NONE, PADCTL_REG_NONE,
+		 PADCTL_REG_NONE, PADCTL_REG_NONE}
+	},
+	.usb2_otg_padX_ctlY_0		= {
+		{0x90, 0x98},
+		{0x94, 0x9c},
+		{PADCTL_REG_NONE, PADCTL_REG_NONE}
+	},
+	.usb2_bias_pad_ctlY_0		= {0xa0, 0xa4},
+	.usb2_hsic_padX_ctlY_0		= {
+		{0xa8, 0xb0, 0xb8},
+		{0xac, 0xb4, 0xbc}
+	},
+	.ulpi_link_trim_ctl0		= 0xc0,
+	.ulpi_null_clk_trim_ctl0	= 0xc4,
+	.hsic_strb_trim_ctl0		= 0xc8,
+	.wake_ctl0			= 0xcc,
+	.pm_spare0			= 0xd0,
+	.usb3_pad_mux_0			= PADCTL_REG_NONE,
+	.iophy_pll_s0_ctlY_0		= {PADCTL_REG_NONE, PADCTL_REG_NONE,
+					   PADCTL_REG_NONE, PADCTL_REG_NONE},
+	.iophy_misc_pad_s0_ctlY_0	= {PADCTL_REG_NONE, PADCTL_REG_NONE,
+					   PADCTL_REG_NONE, PADCTL_REG_NONE,
+					   PADCTL_REG_NONE, PADCTL_REG_NONE},
+};
+
+static const struct tegra_xusb_padctl_regs tegra124_padctl_offsets = {
+	.boot_media_0			= 0x0,
+	.usb2_pad_mux_0			= 0x4,
+	.usb2_port_cap_0		= 0x8,
+	.snps_oc_map_0			= 0xc,
+	.usb2_oc_map_0			= 0x10,
+	.ss_port_map_0			= 0x14,
+	.oc_det_0			= 0x18,
+	.elpg_program_0			= 0x1c,
+	.usb2_bchrg_otgpadX_ctlY_0	= {
+		{0x20, 0x24},
+		{0x28, 0x2c},
+		{0x30, 0x34}
+	},
+	.usb2_bchrg_bias_pad_0		= 0x38,
+	.usb2_bchrg_tdcd_dbnc_timer_0	= 0x3c,
+	.iophy_pll_p0_ctlY_0		= {0x40, 0x44, 0x48, 0x4c},
+	.iophy_usb3_padX_ctlY_0		= {
+		{0x50, 0x58, 0x60, 0x68},
+		{0x54, 0x5c, 0x64, 0x6c}
+	},
+	.iophy_misc_pad_pX_ctlY_0	= {
+		{0x70, 0x78, 0x80, 0x88, 0x90, 0x98},
+		{0x74, 0x7c, 0x84, 0x8c, 0x94, 0x9c},
+		{0xec, 0xf8, 0x104, 0x110, 0x11c, 0x128},
+		{0xf0, 0xfc, 0x108, 0x114, 0x120, 0x12c},
+		{0xf4, 0x100, 0x10c, 0x118, 0x124, 0x130}
+	},
+	.usb2_otg_padX_ctlY_0		= {
+		{0xa0, 0xac},
+		{0xa4, 0xb0},
+		{0xa8, 0xb4}
+	},
+	.usb2_bias_pad_ctlY_0		= {0xb8, 0xbc},
+	.usb2_hsic_padX_ctlY_0		= {
+		{0xc0, 0xc8, 0xd0},
+		{0xc4, 0xcc, 0xd4}
+	},
+	.ulpi_link_trim_ctl0		= 0xd8,
+	.ulpi_null_clk_trim_ctl0	= 0xdc,
+	.hsic_strb_trim_ctl0		= 0xe0,
+	.wake_ctl0			= 0xe4,
+	.pm_spare0			= 0xe8,
+	.usb3_pad_mux_0			= 0x134,
+	.iophy_pll_s0_ctlY_0		= {0x138, 0x13c, 0x140, 0x144},
+	.iophy_misc_pad_s0_ctlY_0	= {0x148, 0x14c, 0x150, 0x154,
+					   0x158, 0x15c},
+};
+
+static const struct tegra_xusb_phy_soc_config tegra114_soc_config = {
+	.has_ctle = false,
+	.scale_ss_clk = false,
+	.num_utmi_pads = 2,
+	.rx_wander = 0x3,
+	.rx_eq = 0x3928,
+	.cdr_cntl = 0x26,
+	.dfe_cntl = 0x002008ee,
+	.hs_slew = 0xe,
+	.ls_rslew_pad = {0x3, 0x0, 0x0},
+	.hs_disc_lvl = 0x5,
+	.spare_in = 0x0,
+	.hsic_port_offset = 5,
+	.padctl_offsets = &tegra114_padctl_offsets,
+};
+
+static const struct tegra_xusb_phy_soc_config tegra124_soc_config = {
+	.has_ctle = true,
+	.scale_ss_clk = true,
+	.num_utmi_pads = 3,
+	.rx_wander = 0xf,
+	.rx_eq = 0xf070,
+	.cdr_cntl = 0x24,
+	.dfe_cntl = 0x002008ee,
+	.hs_slew = 0xe,
+	.ls_rslew_pad = {0x3, 0x0, 0x0},
+	.hs_disc_lvl = 0x5,
+	.spare_in = 0x1,
+	.hsic_port_offset = 6,
+	.padctl_offsets = &tegra124_padctl_offsets,
+};
+
+static struct phy_ops tegra_xusb_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = tegra_xusb_phy_power_on,
+	.power_off = tegra_xusb_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static struct of_device_id tegra_xusb_phy_id_table[] = {
+	{
+		.compatible = "nvidia,tegra114-xusb-phy",
+		.data = &tegra114_soc_config,
+	},
+	{
+		.compatible = "nvidia,tegra124-xusb-phy",
+		.data = &tegra124_soc_config,
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tegra_xusb_phy_id_table);
+
+static int tegra_xusb_phy_parse_dt(struct tegra_xusb_phy *tegra)
+{
+	struct tegra_xusb_phy_board_data *bdata = &tegra->board_data;
+	struct device_node *np = tegra->dev->of_node;
+	u32 val;
+	int ret, i;
+
+	if (of_property_read_u32(np, "nvidia,ss-pads", &val)) {
+		dev_err(tegra->dev, "Missing SS pad map\n");
+		return -EINVAL;
+	}
+	bdata->ss_pads = val;
+	for_each_set_bit(i, &bdata->ss_pads, TEGRA_XUSB_SS_COUNT) {
+		char prop[sizeof("nvidia,ss-portN-map")];
+
+		sprintf(prop, "nvidia,ss-port%d-map", i);
+		ret = of_property_read_u32(np, prop, &val);
+		if (ret) {
+			dev_err(tegra->dev, "Missing SS port %d mapping\n", i);
+			return -EINVAL;
+		}
+		bdata->ss_portmap[i] = val;
+	}
+	bdata->use_sata_lane = of_property_read_bool(np,
+						     "nvidia,use-sata-lane");
+	if (of_property_read_u32(np, "nvidia,hsic-pads", &val)) {
+		dev_err(tegra->dev, "Missing HSIC pad map\n");
+		return -EINVAL;
+	}
+	bdata->hsic_pads = val;
+	for_each_set_bit(i, &bdata->hsic_pads, TEGRA_XUSB_HSIC_COUNT) {
+		char prop[sizeof("nvidia,hsicN-config")];
+
+		sprintf(prop, "nvidia,hsic%d-config", i);
+		ret = of_property_read_u8_array(np, prop,
+						(u8 *)&bdata->hsic[i],
+						sizeof(bdata->hsic[i]));
+		if (ret) {
+			dev_err(tegra->dev, "Missing hsic %d config\n", i);
+			return -EINVAL;
+		}
+	}
+	if (of_property_read_u32(np, "nvidia,utmi-pads", &val)) {
+		dev_err(tegra->dev, "Missing UTMI pad map\n");
+		return -EINVAL;
+	}
+	bdata->utmi_pads = val;
+
+	return 0;
+}
+
+static void tegra_xusb_phy_read_calib_data(struct tegra_xusb_phy *tegra)
+{
+	int i;
+	u32 val;
+
+	val = tegra_read_usb_calibration_data();
+	for (i = 0; i < tegra->soc_config->num_utmi_pads; i++) {
+		tegra->calib_data.hs_curr_level_pad[i] =
+			USB_CALIB_HS_CURR_LVL_PAD(val, i);
+	}
+	tegra->calib_data.hs_term_range_adj = USB_CALIB_HS_TERM_RANGE_ADJ(val);
+	tegra->calib_data.hs_squelch_level = USB_CALIB_HS_SQUELCH_LVL(val);
+	tegra->calib_data.hs_iref_cap = USB_CALIB_HS_IREF_CAP(val);
+}
+
+static int tegra_xusb_phy_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *match;
+	struct resource *res;
+	struct tegra_xusb_phy *tegra;
+	struct phy *phy;
+	struct phy_provider *phy_provider;
+	int err, i;
+
+	tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
+	if (!tegra)
+		return -ENOMEM;
+	tegra->dev = &pdev->dev;
+
+	match = of_match_device(tegra_xusb_phy_id_table, &pdev->dev);
+	if (!match) {
+		dev_err(&pdev->dev, "No matching device found\n");
+		return -ENODEV;
+	}
+	tegra->soc_config = match->data;
+
+	tegra_xusb_phy_read_calib_data(tegra);
+	err = tegra_xusb_phy_parse_dt(tegra);
+	if (err)
+		return err;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tegra->padctl_regs = devm_ioremap_resource(&pdev->dev, res);
+	if (!tegra->padctl_regs) {
+		dev_err(&pdev->dev, "Failed to map padctl regs\n");
+		return -ENOMEM;
+	}
+
+	tegra->clkrst_regs = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+							     "nvidia,clkrst");
+	if (IS_ERR(tegra->clkrst_regs)) {
+		dev_err(&pdev->dev, "Failed to get clkrst regs\n");
+		return PTR_ERR(tegra->clkrst_regs);
+	}
+
+	if (tegra->board_data.hsic_pads) {
+		tegra->vddio_hsic = devm_regulator_get(&pdev->dev,
+						       "vddio-hsic");
+		if (IS_ERR(tegra->vddio_hsic)) {
+			dev_err(&pdev->dev,
+				"Failed to get vddio-hsic regulator\n");
+			return PTR_ERR(tegra->vddio_hsic);
+		}
+	}
+
+	for_each_set_bit(i, &tegra->board_data.utmi_pads,
+			 TEGRA_XUSB_UTMI_COUNT) {
+		char reg_name[sizeof("vbusN")];
+
+		sprintf(reg_name, "vbus%d", i + 1);
+		tegra->utmi_vbus[i] = devm_regulator_get(&pdev->dev, reg_name);
+		if (IS_ERR(tegra->utmi_vbus[i])) {
+			dev_err(&pdev->dev, "Failed to get %s regulator\n",
+				reg_name);
+			return PTR_ERR(tegra->utmi_vbus[i]);
+		}
+	}
+
+	tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss");
+	if (IS_ERR(tegra->ss_rst)) {
+		dev_err(&pdev->dev, "Failed to get SS reset\n");
+		return PTR_ERR(tegra->ss_rst);
+	}
+
+	tegra->ss_src_clk = devm_clk_get(&pdev->dev, "xusb_ss_src");
+	if (IS_ERR(tegra->ss_src_clk)) {
+		dev_err(&pdev->dev, "Failed to get SS source clock\n");
+		return PTR_ERR(tegra->ss_src_clk);
+	}
+	tegra->hs_src_clk = devm_clk_get(&pdev->dev, "xusb_hs_src");
+	if (IS_ERR(tegra->hs_src_clk)) {
+		dev_err(&pdev->dev, "Failed to get HS source clock\n");
+		return PTR_ERR(tegra->hs_src_clk);
+	}
+	tegra->fs_src_clk = devm_clk_get(&pdev->dev, "xusb_fs_src");
+	if (IS_ERR(tegra->fs_src_clk)) {
+		dev_err(&pdev->dev, "Failed to get FS source clock\n");
+		return PTR_ERR(tegra->fs_src_clk);
+	}
+	tegra->ss_clk = devm_clk_get(&pdev->dev, "xusb_ss");
+	if (IS_ERR(tegra->ss_clk)) {
+		dev_err(&pdev->dev, "Failed to get SS clock\n");
+		return PTR_ERR(tegra->ss_clk);
+	}
+	if (tegra->soc_config->scale_ss_clk) {
+		tegra->pll_u_480M = devm_clk_get(&pdev->dev, "pll_u_480M");
+		if (IS_ERR(tegra->pll_u_480M)) {
+			dev_err(&pdev->dev, "Failed to get PLL_U_480M\n");
+			return PTR_ERR(tegra->pll_u_480M);
+		}
+		tegra->clk_m = devm_clk_get(&pdev->dev, "clk_m");
+		if (IS_ERR(tegra->clk_m)) {
+			dev_err(&pdev->dev, "Failed to get clk_m\n");
+			return PTR_ERR(tegra->clk_m);
+		}
+	}
+	tegra->plle = devm_clk_get(&pdev->dev, "pll_e");
+	if (IS_ERR(tegra->plle)) {
+		dev_err(&pdev->dev, "Failed to get PLLE\n");
+		return PTR_ERR(tegra->plle);
+	}
+
+	phy = devm_phy_create(&pdev->dev, &tegra_xusb_phy_ops, NULL);
+	if (IS_ERR(phy)) {
+		dev_err(&pdev->dev, "Failed to create PHY\n");
+		return PTR_ERR(phy);
+	}
+	phy_set_drvdata(phy, tegra);
+	phy_provider = devm_of_phy_provider_register(&pdev->dev,
+						     of_phy_simple_xlate);
+	if (IS_ERR(phy_provider)) {
+		dev_err(&pdev->dev, "Failed to register PHY provider\n");
+		return PTR_ERR(phy_provider);
+	}
+
+	return 0;
+}
+
+static struct platform_driver tegra_xusb_phy_driver = {
+	.probe		= tegra_xusb_phy_probe,
+	.driver		= {
+		.name	= "tegra-xusb-phy",
+		.of_match_table = of_match_ptr(tegra_xusb_phy_id_table),
+	},
+};
+module_platform_driver(tegra_xusb_phy_driver);
+
+MODULE_DESCRIPTION("Tegra XUSB PHY driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tegra-xusb-phy");
diff --git a/drivers/phy/phy-tegra-xusb.h b/drivers/phy/phy-tegra-xusb.h
new file mode 100644
index 0000000..4cfc98b
--- /dev/null
+++ b/drivers/phy/phy-tegra-xusb.h
@@ -0,0 +1,270 @@
+/*
+ * NVIDIA Tegra XUSB PHY driver
+ *
+ * Copyright (C) 2014 NVIDIA Corporation
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PHY_TEGRA_XUSB_H
+#define __PHY_TEGRA_XUSB_H
+
+/* SS pads */
+#define TEGRA_XUSB_SS_P0	BIT(0)
+#define TEGRA_XUSB_SS_P1	BIT(1)
+#define TEGRA_XUSB_SS_COUNT	2
+
+/* UTMI pads */
+#define TEGRA_XUSB_UTMI_P0	BIT(0)
+#define TEGRA_XUSB_UTMI_P1	BIT(1)
+#define TEGRA_XUSB_UTMI_P2	BIT(2)
+#define TEGRA_XUSB_UTMI_COUNT	3
+
+/* HSIC pads */
+#define TEGRA_XUSB_HSIC_P0	BIT(0)
+#define TEGRA_XUSB_HSIC_P1	BIT(1)
+#define TEGRA_XUSB_HSIC_COUNT	2
+
+#define SS_CLK_HIGH_SPEED	120000000
+#define SS_CLK_LOW_SPEED	12000000
+
+/* FUSE_SKU_USB_CALIB_0 bits */
+#define USB_CALIB_HS_CURR_LVL_PAD(reg, p)				\
+	(((p) ? (reg) >> 15 : (reg)) & 0x3f)
+#define USB_CALIB_HS_TERM_RANGE_ADJ(reg)	(((reg) >> 7) & 0xf)
+#define USB_CALIB_HS_SQUELCH_LVL(reg)		(((reg) >> 11) & 0x3)
+#define USB_CALIB_HS_IREF_CAP(reg)		(((reg) >> 13) & 0x3)
+
+/* CLKRST bits */
+#define SATA_PLL_CFG0_0		0x490
+#define SATA_PADPLL_USE_LOCKDET	BIT(2)
+#define SATA_PADPLL_RESET_SWCTL	BIT(0)
+#define SATA_SEQ_ENABLE		BIT(24)
+#define SATA_SEQ_START_STATE	BIT(25)
+
+/* XUSB_PADCTL bits */
+/* USB2_PAD_MUX_0 */
+#define USB2_OTG_PAD_PORT_MASK(p)	(0x3 << (2 * (p)))
+#define USB2_OTG_PAD_PORT_OWNER_SNPS(p) (0x0 << (2 * (p)))
+#define USB2_OTG_PAD_PORT_OWNER_XUSB(p)	(0x1 << (2 * (p)))
+#define USB2_OTG_PAD_PORT_OWNER_UART(p)	(0x2 << (2 * (p)))
+#define USB2_ULPI_PAD_PORT		(0x1 << 12)
+#define USB2_ULPI_PAD_PORT_OWNER_SNPS	(0x0 << 12)
+#define USB2_ULPI_PAD_PORT_OWNER_XUSB	(0x1 << 12)
+#define USB2_HSIC_PAD_PORT(p)		(0x1 << (14 + (p)))
+#define USB2_HSIC_PAD_PORT_OWNER_SNPS(p)	(0x0 << (14 + (p)))
+#define USB2_HSIC_PAD_PORT_OWNER_XUSB(p)	(0x1 << (14 + (p)))
+/* USB2_PORT_CAP_0 */
+#define USB2_PORT_CAP_MASK(p)		(0x3 << (4 * (p)))
+#define USB2_PORT_CAP_HOST(p)		(0x1 << (4 * (p)))
+#define USB2_ULPI_PORT_CAP		(0x1 << 24)
+/* USB2_OC_MAP_0 */
+#define SNPS_OC_MAP_CTRL1		(0x7 << 0)
+#define SNPS_OC_MAP_CTRL2		(0x7 << 3)
+#define SNPS_OC_MAP_CTRL3		(0x7 << 6)
+#define USB2_OC_MAP_PORT0		(0x7 << 0)
+#define USB2_OC_MAP_PORT1		(0x7 << 3)
+#define USB2_OC_MAP_PORT2		(0x7 << 6)
+#define USB2_OC_MAP_PORT(p)		(0x7 << ((p) * 3))
+#define USB2_OC_MAP_PORT0_OC_DETECTED_VBUS_PAD0 (0x4 << 0)
+#define USB2_OC_MAP_PORT1_OC_DETECTED_VBUS_PAD1 (0x5 << 3)
+/* OC_DET_0 */
+#define OC_DET_VBUS_ENABLE0_OC_MAP (0x7 << 10)
+#define OC_DET_VBUS_ENABLE1_OC_MAP (0x7 << 13)
+#define OC_DET_VBUS_ENABLE2_OC_MAP (0x7 << 5)
+#define OC_DET_VBUS_ENABLE_OC_MAP(p)					\
+	((p) == 2 ? OC_DET_VBUS_ENABLE2_OC_MAP :			\
+		(p) ? OC_DET_VBUS_ENABLE1_OC_MAP :			\
+			OC_DET_VBUS_ENABLE0_OC_MAP)
+#define OC_DET_VBUS_EN0_OC_DETECTED_VBUS_PAD0 (0x4 << 10)
+#define OC_DET_VBUS_EN1_OC_DETECTED_VBUS_PAD1 (0x5 << 13)
+#define OC_DET_VBUS_EN2_OC_DETECTED_VBUS_PAD2 (0x6 << 5)
+#define OC_DET_VBUS_EN_OC_DETECTED_VBUS_PAD(p)				\
+	((p) == 2 ? OC_DET_VBUS_EN2_OC_DETECTED_VBUS_PAD2 :		\
+		(p) ? OC_DET_VBUS_EN1_OC_DETECTED_VBUS_PAD1 :		\
+			OC_DET_VBUS_EN0_OC_DETECTED_VBUS_PAD0)
+#define OC_DET_OC_DETECTED_VBUS_PAD0	BIT(20)
+#define OC_DET_OC_DETECTED_VBUS_PAD1	BIT(21)
+#define OC_DET_OC_DETECTED_VBUS_PAD2	BIT(22)
+#define OC_DET_OC_DETECTED_VBUS_PAD(p)	BIT(20 + (p))
+/* SS_PORT_MAP_0 */
+#define SS_PORT_MAP_SHIFT(p)		(4 * (p))
+#define SS_PORT_MAP_MASK(p)		(0xf << SS_PORT_MAP_SHIFT(p))
+#define SS_PORT_MAP_USB2_PORT0		0x0
+#define SS_PORT_MAP_USB2_PORT1		0x1
+#define SS_PORT_MAP_USB2_PORT2		0x2
+/* USB2_OTG_PAD_CTL0_0 */
+#define USB2_OTG_HS_CURR_LVL(x)		((x) & 0x3f)
+#define USB2_OTG_HS_SLEW(x)		(((x) & 0x3f) << 6)
+#define USB2_OTG_FS_SLEW(x)		(((x) & 0x3) << 12)
+#define USB2_OTG_LS_RSLEW(x)		(((x) & 0x3) << 14)
+#define USB2_OTG_LS_FSLEW(x)		(((x) & 0x3) << 16)
+#define USB2_OTG_PD			BIT(19)
+#define USB2_OTG_PD2			BIT(20)
+#define USB2_OTG_PD_ZI			BIT(21)
+/* USB2_OTG_PAD_CTL1_0 */
+#define USB2_OTG_PD_CHRP_FORCE_POWERUP	BIT(0)
+#define USB2_OTG_PD_DISC_FORCE_POWERUP	BIT(1)
+#define USB2_OTG_PD_DR			BIT(2)
+#define USB2_OTG_TERM_RANGE_AD(x)	(((x) & 0xf) << 3)
+#define USB2_OTG_HS_IREF_CAP(x)		(((x) & 0x3) << 9)
+/* USB2_BIAS_PAD_CTL0_0 */
+#define USB2_BIAS_HS_SQUELCH_LEVEL(x)	((x) & 0x3)
+#define USB2_BIAS_HS_DISCON_LEVEL(x)	(((x) & 0x7) << 2)
+#define USB2_BIAS_PD			BIT(12)
+#define USB2_BIAS_PD_TRK		BIT(13)
+/* USB2_BIAS_PAD_CTL1_0 */
+#define USB2_BIAS_RCTRL_VAL(reg)	((reg) & 0xffff)
+#define USB2_BIAS_TCTRL_VAL(reg)	(((reg) >> 16) & 0xffff)
+/* USB2_HSIC_PAD_CTL0_0 */
+#define USB2_HSIC_TX_RTUNEP(x)		(((x) & 0xf) << 0)
+#define USB2_HSIC_TX_RTUNEN(x)		(((x) & 0xf) << 4)
+#define USB2_HSIC_TX_SLEWP(x)		(((x) & 0xf) << 8)
+#define USB2_HSIC_TX_SLEWN(x)		(((x) & 0xf) << 12)
+#define USB2_HSIC_OPT(x)		(((x) & 0xf) << 16)
+/* USB2_HSIC_PAD_CTL1_0 */
+#define USB2_HSIC_AUTO_TERM_EN		BIT(0)
+#define USB2_HSIC_IDDQ			BIT(1)
+#define USB2_HSIC_PD_TX			BIT(2)
+#define USB2_HSIC_PD_TRX		BIT(3)
+#define USB2_HSIC_PD_RX			BIT(4)
+#define USB2_HSIC_PD_ZI			BIT(5)
+#define USB2_HISC_LPBK			BIT(6)
+#define USB2_HSIC_RPD_DATA		BIT(7)
+#define USB2_HSIC_RPD_STROBE		BIT(8)
+#define USB2_HSIC_RPU_DATA		BIT(9)
+#define USB2_HSIC_RPU_STROBE		BIT(10)
+/* USB2_HSIC_PAD_CTL2_0 */
+#define USB2_HSIC_RX_DATA_TRIM(x)	(((x) & 0xf) << 0)
+#define USB2_HSIC_RX_STROBE_TRIM(x)	(((x) & 0xf) << 4)
+#define USB2_HSIC_CALIOUT(x)		(((x) & 0xffff) << 16)
+/* HSIC_STRB_TRIM_CONTROL_0 */
+#define HSIC_STRB_TRIM(x)		((x) & 0x3f)
+/* IOPHY_MISC_PAD_CTL2_0 */
+#define IOPHY_SPARE_IN(x)		(((x) & 0x3) << 28)
+/* IOPHY_MISC_PAD_CTL3_0 */
+#define IOPHY_MISC_CNTL(x)		(((x) & 0xf) << 0)
+#define IOPHY_TX_SEL_LOAD(x)		(((x) & 0xf) << 8)
+#define IOPHY_TX_RDET_T(x)		(((x) & 0x3) << 12)
+#define IOPHY_RX_IDLE_T(x)		(((x) & 0x3) << 14)
+#define IOPHY_TX_RDET_BYP		BIT(16)
+#define IOPHY_RX_IDLE_BYP		BIT(17)
+#define IOPHY_RX_IDLE_MODE		BIT(18)
+#define IOPHY_RX_IDLE_MODE_OVRD		BIT(19)
+#define IOPHY_CDR_TEST(x)		(((x) & 0xfff) << 20)
+/* IOPHY_MISC_PAD_CTL5_0 */
+#define IOPHY_RX_QEYE_EN		BIT(8)
+/* IOPHY_MISC_PAD_CTL6_0 */
+#define IOPHY_MISC_OUT_SEL(x)		(((x) & 0xff) << 16)
+#define IOPHY_MISC_OUT_SEL_TAP		0x32
+#define IOPHY_MISC_OUT_SEL_AMP		0x33
+#define IOPHY_MISC_OUT_SEL_LATCH_G_Z	0xa1
+#define IOPHY_MISC_OUT_SEL_G_Z		0x21
+#define IOPHY_MISC_OUT_SEL_CTLE_Z	0x48
+#define IOPHY_MISC_OUT_TAP_VAL(reg)	(((reg) >> 24) & 0x1f)
+#define IOPHY_MISC_OUT_AMP_VAL(reg)	(((reg) >> 24) & 0x7f)
+#define IOPHY_MISC_OUT_G_Z_VAL(reg)	(((reg) >> 24) & 0x3f)
+/* IOPHY_USB3_PAD_CTL2_0 */
+#define IOPHY_USB3_RX_WANDER(x)		(((x) & 0xf) << 4)
+#define IOPHY_USB3_RX_EQ_G(x)		(((x) & 0x3f) << 8)
+#define IOPHY_USB3_RX_EQ_Z(x)		(((x) & 0x3f) << 16)
+#define IOPHY_USB3_RX_EQ(x)		(((x) & 0xffff) << 8)
+#define IOPHY_USB3_CDR_CNTL(x)		(((x) & 0xff) << 24)
+/* IOPHY_USB3_PAD_CTL4_0 */
+#define IOPHY_USB3_DFE_CNTL_TAP(x)	(((x) & 0x1f) << 24)
+#define IOPHY_USB3_DFE_CNTL_AMP(x)	(((x) & 0x7f) << 16)
+/* IOPHY_PLL_CTL1_0 */
+#define IOPHY_PLL_PLL0_REFCLK_NDIV(x)	(((x) & 0x3) << 20)
+/* IOPHY_PLL_CTL2_0 */
+#define IOPHY_PLL_XDIGCLK_SEL(x)	((x) & 0x7)
+#define IOPHY_PLL_TXCLKREF_SEL		BIT(4)
+#define IOPHY_PLL_TCLKOUT_EN		BIT(12)
+#define IOPHY_PLL_PLL0_CP_CNTL(x)	(((x) & 0xf) << 16)
+#define IOPHY_PLL_PLL1_CP_CNTL(x)	(((x) & 0xf) << 20)
+/* IOPHY_PLL_CTL3_0 */
+#define IOPHY_PLL_RCAL_BYPASS		BIT(7)
+/* USB3_PAD_MUX_0 */
+#define USB3_FORCE_PCIE_PAD_IDDQ_DISABLE_MASK(l)	BIT(1 + (l))
+#define USB3_FORCE_SATA_PAD_IDDQ_DISABLE_MASK		BIT(6)
+#define USB3_PCIE_PAD_LANE_OWNER(l, p)		(((p) & 0x3) << (16 + 2 * (l)))
+#define USB3_SATA_PAD_LANE_OWNER(p)		(((p) & 0x3) << 26)
+#define USB3_LANE_OWNER_PCIE			0x0
+#define USB3_LANE_OWNER_USB3_SS			0x1
+#define USB3_LANE_OWNER_SATA			0x2
+/* ELPG_PROGRAM_0 */
+#define USB2_PORT0_WAKE_INTERRUPT_ENABLE	BIT(0)
+#define USB2_PORT1_WAKE_INTERRUPT_ENABLE	BIT(1)
+#define USB2_PORT2_WAKE_INTERRUPT_ENABLE	BIT(2)
+#define USB2_PORT_WAKE_INTERRUPT_ENABLE(p)	BIT(p)
+#define USB2_HSIC_PORT0_WAKE_INTERRUPT_ENABLE	BIT(3)
+#define USB2_HSIC_PORT1_WAKE_INTERRUPT_ENABLE	BIT(4)
+#define USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(p)	BIT(3 + (p))
+#define SS_PORT0_WAKE_INTERRUPT_ENABLE		BIT(6)
+#define SS_PORT1_WAKE_INTERRUPT_ENABLE		BIT(7)
+#define SS_PORT_WAKE_INTERRUPT_ENABLE(p)	BIT(6 + (p))
+#define USB2_PORT0_WAKEUP_EVENT		BIT(8)
+#define USB2_PORT1_WAKEUP_EVENT		BIT(9)
+#define USB2_PORT2_WAKEUP_EVENT		BIT(10)
+#define USB2_PORT_WAKEUP_EVENT(p)	BIT(8 + (p))
+#define USB2_HSIC_PORT0_WAKEUP_EVENT	BIT(11)
+#define USB2_HSIC_PORT1_WAKEUP_EVENT	BIT(12)
+#define USB2_HSIC_PORT_WAKEUP_EVENT(p)	BIT(11 + (p))
+#define SS_PORT0_WAKEUP_EVENT		BIT(14)
+#define SS_PORT1_WAKEUP_EVENT		BIT(15)
+#define SS_PORT_WAKEUP_EVENT(p)		BIT(14 + (p))
+#define WAKEUP_EVENT_MASK		(0xdf << 8)
+#define SSP0_ELPG_CLAMP_EN		BIT(16)
+#define SSP0_ELPG_CLAMP_EN_EARLY	BIT(17)
+#define SSP0_ELPG_VCORE_DOWN		BIT(18)
+#define SSP1_ELPG_CLAMP_EN		BIT(20)
+#define SSP1_ELPG_CLAMP_EN_EARLY	BIT(21)
+#define SSP1_ELPG_VCORE_DOWN		BIT(22)
+#define SSP_ELPG_CLAMP_EN(p)		BIT(16 + 4 * (p))
+#define SSP_ELPG_CLAMP_EN_EARLY(p)	BIT(17 + 4 * (p))
+#define SSP_ELPG_VCORE_DOWN(p)		BIT(18 + 4 * (p))
+#define AUX_MUX_LP0_CLAMP_EN		BIT(24)
+#define AUX_MUX_LP0_CLAMP_EN_EARLY	BIT(25)
+#define AUX_MUX_LP0_VCORE_DOWN		BIT(26)
+
+#define PADCTL_REG_NONE			((u32)-1)
+
+struct tegra_xusb_padctl_regs {
+	u32 boot_media_0;
+	u32 usb2_pad_mux_0;
+	u32 usb2_port_cap_0;
+	u32 snps_oc_map_0;
+	u32 usb2_oc_map_0;
+	u32 ss_port_map_0;
+	u32 oc_det_0;
+	u32 elpg_program_0;
+	u32 usb2_bchrg_otgpadX_ctlY_0[3][2];
+	u32 usb2_bchrg_bias_pad_0;
+	u32 usb2_bchrg_tdcd_dbnc_timer_0;
+	u32 iophy_pll_p0_ctlY_0[4];
+	u32 iophy_usb3_padX_ctlY_0[2][4];
+	u32 iophy_misc_pad_pX_ctlY_0[5][6];
+	u32 usb2_otg_padX_ctlY_0[3][2];
+	u32 usb2_bias_pad_ctlY_0[2];
+	u32 usb2_hsic_padX_ctlY_0[2][3];
+	u32 ulpi_link_trim_ctl0;
+	u32 ulpi_null_clk_trim_ctl0;
+	u32 hsic_strb_trim_ctl0;
+	u32 wake_ctl0;
+	u32 pm_spare0;
+	u32 usb3_pad_mux_0;
+	u32 iophy_pll_s0_ctlY_0[4];
+	u32 iophy_misc_pad_s0_ctlY_0[6];
+};
+
+#endif /* __PHY_TEGRA_XUSB_H */
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 08/10] ARM: tegra124: Bind CAR to syscon device
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
                   ` (6 preceding siblings ...)
  2014-05-15  0:33 ` [RFC PATCH 07/10] phy: Add Tegra XUSB PHY driver Andrew Bresticker
@ 2014-05-15  0:33 ` Andrew Bresticker
  2014-05-15 19:25   ` Stephen Warren
  2014-05-15  0:33 ` [RFC PATCH 09/10] ARM: tegra124: Add XHCI controller and PHY Andrew Bresticker
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:33 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Andrew Bresticker

The XUSB PHY driver will be accessing the CAR registers through the
syscon interface.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/arm/boot/dts/tegra124.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 197e848..47fb61c 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -115,7 +115,7 @@
 	};
 
 	tegra_car: clock@0,60006000 {
-		compatible = "nvidia,tegra124-car";
+		compatible = "nvidia,tegra124-car", "syscon";
 		reg = <0x0 0x60006000 0x0 0x1000>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 09/10] ARM: tegra124: Add XHCI controller and PHY
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
                   ` (7 preceding siblings ...)
  2014-05-15  0:33 ` [RFC PATCH 08/10] ARM: tegra124: Bind CAR to syscon device Andrew Bresticker
@ 2014-05-15  0:33 ` Andrew Bresticker
  2014-05-15  0:33 ` [RFC PATCH 10/10] ARM: tegra124: Enable XHCI on Venice2 Andrew Bresticker
  2014-05-15 19:33 ` [RFC PATCH 00/10] Tegra XHCI support Stephen Warren
  10 siblings, 0 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:33 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Andrew Bresticker

And nodes for the XHCI host controller and XUSB PHY present on Tegra124.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/arm/boot/dts/tegra124.dtsi | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 47fb61c..ee3209bc 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -462,6 +462,43 @@
 		clock-names = "pclk", "clk32k_in";
 	};
 
+	usb@0,70090000 {
+		compatible = "nvidia,tegra124-xhci";
+		reg = <0x0 0x70090000 0x0 0x8000>,
+		      <0x0 0x70098000 0x0 0x1000>,
+		      <0x0 0x70099000 0x0 0x1000>;
+		interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>;
+		clock-names = "xusb_host", "xusb_falcon_src";
+		resets = <&tegra_car 89>;
+		reset-names = "xusb_host";
+		phys = <&xusb_phy>;
+		phy-names = "xusb";
+		status = "disabled";
+	};
+
+	xusb_phy: phy@0,7009f000 {
+		compatible = "nvidia,tegra124-xusb-phy";
+		reg = <0x0 0x7009f000 0x0 0x1000>;
+		#phy-cells = <0>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_SS>,
+			 <&tegra_car TEGRA124_CLK_XUSB_SS_SRC>,
+			 <&tegra_car TEGRA124_CLK_XUSB_HS_SRC>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FS_SRC>,
+			 <&tegra_car TEGRA124_CLK_PLL_U_480M>,
+			 <&tegra_car TEGRA124_CLK_CLK_M>,
+			 <&tegra_car TEGRA124_CLK_PLL_E>;
+		clock-names = "xusb_ss", "xusb_ss_src", "xusb_hs_src",
+			      "xusb_fs_src", "pll_u_480M", "clk_m",
+			      "pll_e";
+		resets = <&tegra_car 156>;
+		reset-names = "xusb_ss";
+		nvidia,clkrst = <&tegra_car>;
+		status = "disabled";
+	};
+
 	sdhci@0,700b0000 {
 		compatible = "nvidia,tegra124-sdhci";
 		reg = <0x0 0x700b0000 0x0 0x200>;
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [RFC PATCH 10/10] ARM: tegra124: Enable XHCI on Venice2
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
                   ` (8 preceding siblings ...)
  2014-05-15  0:33 ` [RFC PATCH 09/10] ARM: tegra124: Add XHCI controller and PHY Andrew Bresticker
@ 2014-05-15  0:33 ` Andrew Bresticker
  2014-05-15 19:33 ` [RFC PATCH 00/10] Tegra XHCI support Stephen Warren
  10 siblings, 0 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15  0:33 UTC (permalink / raw)
  To: linux-tegra, devicetree, linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Stephen Warren, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap,
	Andrew Bresticker

Enable the XHCI host controller and XUSB PHY on Venice2.  All three
USB2.0 ports are owned by the XHCI controller and the two SuperSpeed
ports are mapped to the external USB2.0 ports.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/arm/boot/dts/tegra124-venice2.dts | 46 ++++++++++++++--------------------
 1 file changed, 19 insertions(+), 27 deletions(-)

diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts
index f0bb842..dcfc0c7 100644
--- a/arch/arm/boot/dts/tegra124-venice2.dts
+++ b/arch/arm/boot/dts/tegra124-venice2.dts
@@ -940,6 +940,25 @@
 		nvidia,sys-clock-req-active-high;
 	};
 
+	usb@0,70090000 {
+		status = "okay";
+		s1p05v-supply = <&vdd_1v05_run>;
+		s3p3v-supply = <&vdd_3v3_lp0>;
+		s1p8v-supply = <&vddio_1v8>;
+	};
+
+	phy@0,7009f000 {
+		status = "okay";
+		nvidia,ss-pads = <0x3>;
+		nvidia,hsic-pads = <0x0>;
+		nvidia,utmi-pads = <0x7>;
+		nvidia,ss-port0-map = <0>;
+		nvidia,ss-port1-map = <2>;
+		vbus1-supply = <&vdd_usb1_vbus>;
+		vbus2-supply = <&vdd_run_cam>;
+		vbus3-supply = <&vdd_usb3_vbus>;
+	};
+
 	sdhci@0,700b0400 {
 		cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
 		power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
@@ -960,33 +979,6 @@
 		};
 	};
 
-	usb@0,7d000000 {
-		status = "okay";
-	};
-
-	usb-phy@0,7d000000 {
-		status = "okay";
-		vbus-supply = <&vdd_usb1_vbus>;
-	};
-
-	usb@0,7d004000 {
-		status = "okay";
-	};
-
-	usb-phy@0,7d004000 {
-		status = "okay";
-		vbus-supply = <&vdd_run_cam>;
-	};
-
-	usb@0,7d008000 {
-		status = "okay";
-	};
-
-	usb-phy@0,7d008000 {
-		status = "okay";
-		vbus-supply = <&vdd_usb3_vbus>;
-	};
-
 	backlight: backlight {
 		compatible = "pwm-backlight";
 
-- 
1.9.1.423.g4596e3a


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver
  2014-05-15  0:33 ` [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver Andrew Bresticker
@ 2014-05-15  8:17   ` Arnd Bergmann
  2014-05-15  9:19     ` Thierry Reding
  2014-05-15 20:18     ` Andrew Bresticker
  0 siblings, 2 replies; 25+ messages in thread
From: Arnd Bergmann @ 2014-05-15  8:17 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: linux-tegra, devicetree, linux-kernel, linux-arm-kernel,
	linux-usb, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Stephen Warren, Thierry Reding, Russell King,
	Peter De Schrijver, Prashant Gaikwad, Mike Turquette,
	Kishon Vijay Abraham I, Greg Kroah-Hartman, Mathias Nyman,
	Grant Likely, Randy Dunlap

On Wednesday 14 May 2014 17:33:02 Andrew Bresticker wrote:
> +
> +int tegra_xhci_register_mbox_notifier(struct notifier_block *nb)
> +{
> +	int ret;
> +
> +	mutex_lock(&tegra_xhci_mbox_lock);
> +	ret = raw_notifier_chain_register(&tegra_xhci_mbox_notifiers, nb);
> +	mutex_unlock(&tegra_xhci_mbox_lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(tegra_xhci_register_mbox_notifier);
> +
> +void tegra_xhci_unregister_mbox_notifier(struct notifier_block *nb)
> +{
> +	mutex_lock(&tegra_xhci_mbox_lock);
> +	raw_notifier_chain_unregister(&tegra_xhci_mbox_notifiers, nb);
> +	mutex_unlock(&tegra_xhci_mbox_lock);
> +}
> +EXPORT_SYMBOL(tegra_xhci_unregister_mbox_notifier);

What driver would use these?

My feeling is that if you have a mailbox that is used by multiple
drivers, you should use a proper mailbox driver to operate them,
and have the drivers register with that API instead of a custom one.

> +	/* Create child xhci-plat device */
> +	memset(xhci_resources, 0, sizeof(xhci_resources));
> +	res = platform_get_resource(to_platform_device(dev), IORESOURCE_IRQ, 0);
> +	if (!res) {
> +		dev_err(dev, "Missing XHCI IRQ\n");
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +	xhci_resources[0].start = res->start;
> +	xhci_resources[0].end = res->end;
> +	xhci_resources[0].flags = res->flags;
> +	xhci_resources[0].name = res->name;
> +	res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
> +	if (!res) {
> +		dev_err(dev, "Missing XHCI registers\n");
> +		ret = -ENODEV;
> +		goto out;
> +	}
> +	xhci_resources[1].start = res->start;
> +	xhci_resources[1].end = res->end;
> +	xhci_resources[1].flags = res->flags;
> +	xhci_resources[1].name = res->name;
> +
> +	xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
> +	if (!xhci) {
> +		dev_err(dev, "Failed to allocate XHCI host\n");
> +		ret = -ENOMEM;
> +		goto out;
> +	}

This does not feel appropriate at all: Rather than creating a child device,
you should have a specific driver that hooks into functions exported
by the xhci core. See Documentation/driver-model/design-patterns.txt

	Arnd


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver
  2014-05-15  8:17   ` Arnd Bergmann
@ 2014-05-15  9:19     ` Thierry Reding
  2014-05-15 13:30       ` Arnd Bergmann
  2014-05-15 20:18     ` Andrew Bresticker
  1 sibling, 1 reply; 25+ messages in thread
From: Thierry Reding @ 2014-05-15  9:19 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Andrew Bresticker, linux-tegra, devicetree, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Stephen Warren,
	Russell King, Peter De Schrijver, Prashant Gaikwad,
	Mike Turquette, Kishon Vijay Abraham I, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Randy Dunlap

[-- Attachment #1: Type: text/plain, Size: 1570 bytes --]

On Thu, May 15, 2014 at 10:17:10AM +0200, Arnd Bergmann wrote:
> On Wednesday 14 May 2014 17:33:02 Andrew Bresticker wrote:
[...]
> > +	/* Create child xhci-plat device */
> > +	memset(xhci_resources, 0, sizeof(xhci_resources));
> > +	res = platform_get_resource(to_platform_device(dev), IORESOURCE_IRQ, 0);
> > +	if (!res) {
> > +		dev_err(dev, "Missing XHCI IRQ\n");
> > +		ret = -ENODEV;
> > +		goto out;
> > +	}
> > +	xhci_resources[0].start = res->start;
> > +	xhci_resources[0].end = res->end;
> > +	xhci_resources[0].flags = res->flags;
> > +	xhci_resources[0].name = res->name;
> > +	res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
> > +	if (!res) {
> > +		dev_err(dev, "Missing XHCI registers\n");
> > +		ret = -ENODEV;
> > +		goto out;
> > +	}
> > +	xhci_resources[1].start = res->start;
> > +	xhci_resources[1].end = res->end;
> > +	xhci_resources[1].flags = res->flags;
> > +	xhci_resources[1].name = res->name;
> > +
> > +	xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
> > +	if (!xhci) {
> > +		dev_err(dev, "Failed to allocate XHCI host\n");
> > +		ret = -ENOMEM;
> > +		goto out;
> > +	}
> 
> This does not feel appropriate at all: Rather than creating a child device,
> you should have a specific driver that hooks into functions exported
> by the xhci core. See Documentation/driver-model/design-patterns.txt

I don't think Documentation/driver-model/design-patterns.txt documents
this. Perhaps this is what you had in mind?

	http://lwn.net/Articles/336262/

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver
  2014-05-15  9:19     ` Thierry Reding
@ 2014-05-15 13:30       ` Arnd Bergmann
  0 siblings, 0 replies; 25+ messages in thread
From: Arnd Bergmann @ 2014-05-15 13:30 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Andrew Bresticker, linux-tegra, devicetree, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Stephen Warren,
	Russell King, Peter De Schrijver, Prashant Gaikwad,
	Mike Turquette, Kishon Vijay Abraham I, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Randy Dunlap

On Thursday 15 May 2014 11:19:40 Thierry Reding wrote:
> > > +
> > > +   xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
> > > +   if (!xhci) {
> > > +           dev_err(dev, "Failed to allocate XHCI host\n");
> > > +           ret = -ENOMEM;
> > > +           goto out;
> > > +   }
> > 
> > This does not feel appropriate at all: Rather than creating a child device,
> > you should have a specific driver that hooks into functions exported
> > by the xhci core. See Documentation/driver-model/design-patterns.txt
> 
> I don't think Documentation/driver-model/design-patterns.txt documents
> this. Perhaps this is what you had in mind?
> 
>         http://lwn.net/Articles/336262/

No, I did mean Documentation/driver-model/design-patterns.txt.

The pattern used in the proposed driver is to create the generic platform_device
as the child of the more specific platform_device.

The normal pattern is to have only one device and embed the generic structure
inside of the more specific structure and use container_of to cast between
the two as needed.

	Arnd

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 04/10] clk: tegra: Initialize xusb clocks
  2014-05-15  0:33 ` [RFC PATCH 04/10] clk: tegra: Initialize xusb clocks Andrew Bresticker
@ 2014-05-15 19:22   ` Stephen Warren
  2014-05-20 15:41     ` Peter De Schrijver
  0 siblings, 1 reply; 25+ messages in thread
From: Stephen Warren @ 2014-05-15 19:22 UTC (permalink / raw)
  To: Andrew Bresticker, Peter De Schrijver, Mike Turquette
  Cc: linux-tegra, devicetree, linux-kernel, linux-arm-kernel,
	linux-usb, Mark Rutland, Prashant Gaikwad, Russell King,
	Mathias Nyman, Pawel Moll, Greg Kroah-Hartman, Ian Campbell,
	Jim Lin, Kishon Vijay Abraham I, Rob Herring, Thierry Reding,
	Randy Dunlap, Kumar Gala, Grant Likely

On 05/14/2014 06:33 PM, Andrew Bresticker wrote:
> Initialize the XUSB-related clocks with appropriate parents and rates
> for both Tegra114 and Tegra124.

These first 4 clock driver patches look plausible to me, although I
didn't look that hard!

Peter or Mike, if they look OK to you, can you please pick them up for
3.16 so that by the time we apply the rest of the patches in this series
for 3.17, the clock dependencies are already there? Thanks.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 08/10] ARM: tegra124: Bind CAR to syscon device
  2014-05-15  0:33 ` [RFC PATCH 08/10] ARM: tegra124: Bind CAR to syscon device Andrew Bresticker
@ 2014-05-15 19:25   ` Stephen Warren
  2014-05-15 20:22     ` Andrew Bresticker
  0 siblings, 1 reply; 25+ messages in thread
From: Stephen Warren @ 2014-05-15 19:25 UTC (permalink / raw)
  To: Andrew Bresticker, linux-tegra
  Cc: devicetree, linux-kernel, linux-arm-kernel, linux-usb,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap

On 05/14/2014 06:33 PM, Andrew Bresticker wrote:
> The XUSB PHY driver will be accessing the CAR registers through the
> syscon interface.

I very strongly don't want to use the syscon concept on Tegra. Instead,
I want only the CAR driver touching the CAR registers. If other drivers
need some CAR registers manipulated, that should happen by that other
driver calling some explicit semantic API in the CAR driver to do so.
Take a look at how the Tegra SMMU and Tegra AHB driver communicate for
an example.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 00/10] Tegra XHCI support
  2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
                   ` (9 preceding siblings ...)
  2014-05-15  0:33 ` [RFC PATCH 10/10] ARM: tegra124: Enable XHCI on Venice2 Andrew Bresticker
@ 2014-05-15 19:33 ` Stephen Warren
  2014-05-15 20:44   ` Andrew Bresticker
  10 siblings, 1 reply; 25+ messages in thread
From: Stephen Warren @ 2014-05-15 19:33 UTC (permalink / raw)
  To: Andrew Bresticker, linux-tegra, devicetree, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap

On 05/14/2014 06:32 PM, Andrew Bresticker wrote:
> This is a first pass at the host and PHY drivers necessary for USB3.0
> support on Tegra114 and Tegra124.  The Tegra XHCI host controller requires
> external firmware [1] which must be loaded before using any USB ports owned
> by the controller.  The XUSB PHY driver handles mapping and enabling of
> the UTMI, HSIC, and SuperSpeed pads to the XHCI controller.
> 
> Tested on a Venice2 with a variety of USB2.0 and USB3.0 memory sticks
> and ethernet dongles.  
> 
> Notes:
>  - I've included support for Tegra114, but since I don't have Tegra114-based
>    hardware, it is completely untested.
>  - The PCIe and SATA PHYs also are programmed using the XUSB_PADCTL space
>    as well.  At least some of the code can be re-used, specifically with
>    respect to lane programming.  I believe Thierry is working on the PCIe
>    parts of this.

If I understand the HW correctly, there's a separate "pad control" HW
block that provides routing/sharing of signals from USB2(?), USB3, SATA,
and PCIe to the pads.

I believe Thierry is working on exposing this block as a pinctrl driver,
or at least something that the other drivers can call into in order to
configure that block. It'd be good if you can co-ordinate with him to
rebase this driver on top of that, rather than (I assume; haven't read
the code yet...) directly manipulating the padctrl registers inside each
of the different drivers. Co-ordinating that could turn out to be
problematic, and presumably if each driver does its own thing, we end up
duplicating defines, code, and DT bindings for configuring the padctrl HW.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver
  2014-05-15  8:17   ` Arnd Bergmann
  2014-05-15  9:19     ` Thierry Reding
@ 2014-05-15 20:18     ` Andrew Bresticker
  2014-05-15 21:16       ` Alan Stern
  2014-05-15 21:18       ` Thierry Reding
  1 sibling, 2 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15 20:18 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: linux-tegra, devicetree, linux-kernel, linux-arm-kernel,
	linux-usb, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Stephen Warren, Thierry Reding, Russell King,
	Peter De Schrijver, Prashant Gaikwad, Mike Turquette,
	Kishon Vijay Abraham I, Greg Kroah-Hartman, Mathias Nyman,
	Grant Likely, Randy Dunlap

Arnd,

On Thu, May 15, 2014 at 1:17 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Wednesday 14 May 2014 17:33:02 Andrew Bresticker wrote:
>> +
>> +int tegra_xhci_register_mbox_notifier(struct notifier_block *nb)
>> +{
>> +     int ret;
>> +
>> +     mutex_lock(&tegra_xhci_mbox_lock);
>> +     ret = raw_notifier_chain_register(&tegra_xhci_mbox_notifiers, nb);
>> +     mutex_unlock(&tegra_xhci_mbox_lock);
>> +
>> +     return ret;
>> +}
>> +EXPORT_SYMBOL(tegra_xhci_register_mbox_notifier);
>> +
>> +void tegra_xhci_unregister_mbox_notifier(struct notifier_block *nb)
>> +{
>> +     mutex_lock(&tegra_xhci_mbox_lock);
>> +     raw_notifier_chain_unregister(&tegra_xhci_mbox_notifiers, nb);
>> +     mutex_unlock(&tegra_xhci_mbox_lock);
>> +}
>> +EXPORT_SYMBOL(tegra_xhci_unregister_mbox_notifier);
>
> What driver would use these?

It's used by just this driver (the host) and the PHY driver (next
patch in series).

> My feeling is that if you have a mailbox that is used by multiple
> drivers, you should use a proper mailbox driver to operate them,
> and have the drivers register with that API instead of a custom one.

Ok, will do.

>> +     /* Create child xhci-plat device */
>> +     memset(xhci_resources, 0, sizeof(xhci_resources));
>> +     res = platform_get_resource(to_platform_device(dev), IORESOURCE_IRQ, 0);
>> +     if (!res) {
>> +             dev_err(dev, "Missing XHCI IRQ\n");
>> +             ret = -ENODEV;
>> +             goto out;
>> +     }
>> +     xhci_resources[0].start = res->start;
>> +     xhci_resources[0].end = res->end;
>> +     xhci_resources[0].flags = res->flags;
>> +     xhci_resources[0].name = res->name;
>> +     res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
>> +     if (!res) {
>> +             dev_err(dev, "Missing XHCI registers\n");
>> +             ret = -ENODEV;
>> +             goto out;
>> +     }
>> +     xhci_resources[1].start = res->start;
>> +     xhci_resources[1].end = res->end;
>> +     xhci_resources[1].flags = res->flags;
>> +     xhci_resources[1].name = res->name;
>> +
>> +     xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
>> +     if (!xhci) {
>> +             dev_err(dev, "Failed to allocate XHCI host\n");
>> +             ret = -ENOMEM;
>> +             goto out;
>> +     }
>
> This does not feel appropriate at all: Rather than creating a child device,
> you should have a specific driver that hooks into functions exported
> by the xhci core. See Documentation/driver-model/design-patterns.txt

This is how DWC3, currently the only in-tree non-PCI XHCI host driver,
is structured - see drivers/usb/dwc3/host.c.  The recently proposed
Armada XHCI driver [1] just adds clock support and a hook in
xhci-plat's probe() to do the platform-specific initialization.
Tegra's XHCI driver initialization is quite a bit more complicated,
mainly due to the need for external firmware and specific ordering
(e.g. firmware messages should only be enabled after the HCD is
created).  I could do away with the xhci-plat sub-device and just
create a Tegra hc_driver, but it seems silly to have three XHCI
platform drivers structured in three different ways.  USB folks, do
you have an opinion on how this should be done?

[1] https://lkml.org/lkml/2014/5/15/208

Thanks,
Andrew

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 08/10] ARM: tegra124: Bind CAR to syscon device
  2014-05-15 19:25   ` Stephen Warren
@ 2014-05-15 20:22     ` Andrew Bresticker
  0 siblings, 0 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15 20:22 UTC (permalink / raw)
  To: Stephen Warren
  Cc: linux-tegra, devicetree, linux-kernel, linux-arm-kernel,
	linux-usb, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap

On Thu, May 15, 2014 at 12:25 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 05/14/2014 06:33 PM, Andrew Bresticker wrote:
>> The XUSB PHY driver will be accessing the CAR registers through the
>> syscon interface.
>
> I very strongly don't want to use the syscon concept on Tegra. Instead,
> I want only the CAR driver touching the CAR registers. If other drivers
> need some CAR registers manipulated, that should happen by that other
> driver calling some explicit semantic API in the CAR driver to do so.
> Take a look at how the Tegra SMMU and Tegra AHB driver communicate for
> an example.

Understood.  I'll fix that up for the next spin.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 05/10] ARM: tegra: Export function to read USB calibration data
  2014-05-15  0:33 ` [RFC PATCH 05/10] ARM: tegra: Export function to read USB calibration data Andrew Bresticker
@ 2014-05-15 20:39   ` Stephen Warren
  0 siblings, 0 replies; 25+ messages in thread
From: Stephen Warren @ 2014-05-15 20:39 UTC (permalink / raw)
  To: Andrew Bresticker, linux-tegra, devicetree, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Mark Rutland, Prashant Gaikwad, Russell King, Mathias Nyman,
	Pawel Moll, Greg Kroah-Hartman, Peter De Schrijver, Ian Campbell,
	Kishon Vijay Abraham I, Rob Herring, Thierry Reding,
	Randy Dunlap, Kumar Gala, Grant Likely, Mike Turquette

On 05/14/2014 06:33 PM, Andrew Bresticker wrote:
> Board-specific USB configuration data is stored in FUSE_SKU_CALIB_0.
> Export a function to read it so the PHY can be properly configured.

This patch seems conceptually fine to me. Presumably once Peter's fuse
driver is fleshed out, it can expose the exact same semantic interface
to drivers.

I suppose one could argue that we should create/use an explicit fuse
subsystem with a standard API that drivers can call into, rather than a
custom API. We can get the appropriate handle to use for that API from a
phandle (plus fuse IDs?) in a DT property (in the XHCI device node,
pointing at the fuse device node) much like any other cross-device
resource reference. I'm not too bothered whether the code actually does
that in the first instance, although we should make sure we add that DT
property (containing all required fuse ID information) so that the code
/can/ work that way if we want it to in the future.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 00/10] Tegra XHCI support
  2014-05-15 19:33 ` [RFC PATCH 00/10] Tegra XHCI support Stephen Warren
@ 2014-05-15 20:44   ` Andrew Bresticker
  0 siblings, 0 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-15 20:44 UTC (permalink / raw)
  To: Stephen Warren
  Cc: linux-tegra, devicetree, linux-kernel, linux-arm-kernel,
	linux-usb, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap

On Thu, May 15, 2014 at 12:33 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 05/14/2014 06:32 PM, Andrew Bresticker wrote:
>> This is a first pass at the host and PHY drivers necessary for USB3.0
>> support on Tegra114 and Tegra124.  The Tegra XHCI host controller requires
>> external firmware [1] which must be loaded before using any USB ports owned
>> by the controller.  The XUSB PHY driver handles mapping and enabling of
>> the UTMI, HSIC, and SuperSpeed pads to the XHCI controller.
>>
>> Tested on a Venice2 with a variety of USB2.0 and USB3.0 memory sticks
>> and ethernet dongles.
>>
>> Notes:
>>  - I've included support for Tegra114, but since I don't have Tegra114-based
>>    hardware, it is completely untested.
>>  - The PCIe and SATA PHYs also are programmed using the XUSB_PADCTL space
>>    as well.  At least some of the code can be re-used, specifically with
>>    respect to lane programming.  I believe Thierry is working on the PCIe
>>    parts of this.
>
> If I understand the HW correctly, there's a separate "pad control" HW
> block that provides routing/sharing of signals from USB2(?), USB3, SATA,
> and PCIe to the pads.
>
> I believe Thierry is working on exposing this block as a pinctrl driver,
> or at least something that the other drivers can call into in order to
> configure that block. It'd be good if you can co-ordinate with him to
> rebase this driver on top of that, rather than (I assume; haven't read
> the code yet...) directly manipulating the padctrl registers inside each
> of the different drivers.

Yes, ideally i'd like to rebase this on top of Theirry's series once
it's ready.  It sounds like there will be a pinctrl driver which
handles the lane muxing between XUSB, PCIe, and SATA and a generic PHY
driver will deal wit the actual PHY programming.  I'm not sure what
the PCIe and SATA PHY drivers will look like, but the XUSB one
requires quite a bit of USB-specific programming of the padctl
registers, so I'm not sure we'll be able to fit all three PHY types
into a single PHY provider driver.  Either way, there's probably a
good deal of PHY code that could be broken out and shared among the
three.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver
  2014-05-15 20:18     ` Andrew Bresticker
@ 2014-05-15 21:16       ` Alan Stern
  2014-05-15 21:18       ` Thierry Reding
  1 sibling, 0 replies; 25+ messages in thread
From: Alan Stern @ 2014-05-15 21:16 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Arnd Bergmann, linux-tegra, devicetree, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Stephen Warren,
	Thierry Reding, Russell King, Peter De Schrijver,
	Prashant Gaikwad, Mike Turquette, Kishon Vijay Abraham I,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Randy Dunlap

On Thu, 15 May 2014, Andrew Bresticker wrote:

> > This does not feel appropriate at all: Rather than creating a child device,
> > you should have a specific driver that hooks into functions exported
> > by the xhci core. See Documentation/driver-model/design-patterns.txt
> 
> This is how DWC3, currently the only in-tree non-PCI XHCI host driver,
> is structured - see drivers/usb/dwc3/host.c.  The recently proposed
> Armada XHCI driver [1] just adds clock support and a hook in
> xhci-plat's probe() to do the platform-specific initialization.
> Tegra's XHCI driver initialization is quite a bit more complicated,
> mainly due to the need for external firmware and specific ordering
> (e.g. firmware messages should only be enabled after the HCD is
> created).  I could do away with the xhci-plat sub-device and just
> create a Tegra hc_driver, but it seems silly to have three XHCI
> platform drivers structured in three different ways.  USB folks, do
> you have an opinion on how this should be done?

Felipe and I have differing opinions.  I prefer not to create an extra 
device level, and he does (that's why the non-PCI EHCI drivers don't do 
it and the dwc3 driver does).  I consider Felipe's approach to be an 
example of the "Midlayer Mistake" anti-pattern from the LWN 
article mentioned earlier in this thread -- I don't know what he thinks 
about my approach.

Anyway, unless I'm totally mistaken, you wouldn't end up with three
platform drivers structured in three different ways.  Either way, your
new driver would be structured like one of the existing two.

Alan Stern


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver
  2014-05-15 20:18     ` Andrew Bresticker
  2014-05-15 21:16       ` Alan Stern
@ 2014-05-15 21:18       ` Thierry Reding
  2014-05-16 16:52         ` Andrew Bresticker
  1 sibling, 1 reply; 25+ messages in thread
From: Thierry Reding @ 2014-05-15 21:18 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Arnd Bergmann, linux-tegra, devicetree, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Stephen Warren,
	Russell King, Peter De Schrijver, Prashant Gaikwad,
	Mike Turquette, Kishon Vijay Abraham I, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Randy Dunlap

[-- Attachment #1: Type: text/plain, Size: 4165 bytes --]

On Thu, May 15, 2014 at 01:18:22PM -0700, Andrew Bresticker wrote:
> Arnd,
> 
> On Thu, May 15, 2014 at 1:17 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> > On Wednesday 14 May 2014 17:33:02 Andrew Bresticker wrote:
> >> +
> >> +int tegra_xhci_register_mbox_notifier(struct notifier_block *nb)
> >> +{
> >> +     int ret;
> >> +
> >> +     mutex_lock(&tegra_xhci_mbox_lock);
> >> +     ret = raw_notifier_chain_register(&tegra_xhci_mbox_notifiers, nb);
> >> +     mutex_unlock(&tegra_xhci_mbox_lock);
> >> +
> >> +     return ret;
> >> +}
> >> +EXPORT_SYMBOL(tegra_xhci_register_mbox_notifier);
> >> +
> >> +void tegra_xhci_unregister_mbox_notifier(struct notifier_block *nb)
> >> +{
> >> +     mutex_lock(&tegra_xhci_mbox_lock);
> >> +     raw_notifier_chain_unregister(&tegra_xhci_mbox_notifiers, nb);
> >> +     mutex_unlock(&tegra_xhci_mbox_lock);
> >> +}
> >> +EXPORT_SYMBOL(tegra_xhci_unregister_mbox_notifier);
> >
> > What driver would use these?
> 
> It's used by just this driver (the host) and the PHY driver (next
> patch in series).
> 
> > My feeling is that if you have a mailbox that is used by multiple
> > drivers, you should use a proper mailbox driver to operate them,
> > and have the drivers register with that API instead of a custom one.
> 
> Ok, will do.
> 
> >> +     /* Create child xhci-plat device */
> >> +     memset(xhci_resources, 0, sizeof(xhci_resources));
> >> +     res = platform_get_resource(to_platform_device(dev), IORESOURCE_IRQ, 0);
> >> +     if (!res) {
> >> +             dev_err(dev, "Missing XHCI IRQ\n");
> >> +             ret = -ENODEV;
> >> +             goto out;
> >> +     }
> >> +     xhci_resources[0].start = res->start;
> >> +     xhci_resources[0].end = res->end;
> >> +     xhci_resources[0].flags = res->flags;
> >> +     xhci_resources[0].name = res->name;
> >> +     res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
> >> +     if (!res) {
> >> +             dev_err(dev, "Missing XHCI registers\n");
> >> +             ret = -ENODEV;
> >> +             goto out;
> >> +     }
> >> +     xhci_resources[1].start = res->start;
> >> +     xhci_resources[1].end = res->end;
> >> +     xhci_resources[1].flags = res->flags;
> >> +     xhci_resources[1].name = res->name;
> >> +
> >> +     xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
> >> +     if (!xhci) {
> >> +             dev_err(dev, "Failed to allocate XHCI host\n");
> >> +             ret = -ENOMEM;
> >> +             goto out;
> >> +     }
> >
> > This does not feel appropriate at all: Rather than creating a child device,
> > you should have a specific driver that hooks into functions exported
> > by the xhci core. See Documentation/driver-model/design-patterns.txt
> 
> This is how DWC3, currently the only in-tree non-PCI XHCI host driver,
> is structured - see drivers/usb/dwc3/host.c.  The recently proposed
> Armada XHCI driver [1] just adds clock support and a hook in
> xhci-plat's probe() to do the platform-specific initialization.

Ugh... that very much sounds like the midlayer mistake. Doing that is
not going to scale in the long run. Everybody will just keep adding
quirks to the initialization until it's become a huge mess.

> Tegra's XHCI driver initialization is quite a bit more complicated,
> mainly due to the need for external firmware and specific ordering
> (e.g. firmware messages should only be enabled after the HCD is
> created).  I could do away with the xhci-plat sub-device and just
> create a Tegra hc_driver, but it seems silly to have three XHCI
> platform drivers structured in three different ways.  USB folks, do
> you have an opinion on how this should be done?

The tendency in other subsystems (and I think this is also true to some
degree for USB, though I'm less familiar with it) is to make common
functions available as a library of helpers so that other drivers can
use them (either directly or by wrapping them in platform-specific
implementations). That allows you to keep the platform-specific code
where it belongs: in the platform-specific driver.

Thierry

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver
  2014-05-15 21:18       ` Thierry Reding
@ 2014-05-16 16:52         ` Andrew Bresticker
  0 siblings, 0 replies; 25+ messages in thread
From: Andrew Bresticker @ 2014-05-16 16:52 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Arnd Bergmann, linux-tegra, devicetree, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Stephen Warren,
	Russell King, Peter De Schrijver, Prashant Gaikwad,
	Mike Turquette, Kishon Vijay Abraham I, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Randy Dunlap

On Thu, May 15, 2014 at 2:18 PM, Thierry Reding
<thierry.reding@gmail.com> wrote:
> On Thu, May 15, 2014 at 01:18:22PM -0700, Andrew Bresticker wrote:
>> Arnd,
>>
>> On Thu, May 15, 2014 at 1:17 AM, Arnd Bergmann <arnd@arndb.de> wrote:
>> > On Wednesday 14 May 2014 17:33:02 Andrew Bresticker wrote:
>> >> +
>> >> +int tegra_xhci_register_mbox_notifier(struct notifier_block *nb)
>> >> +{
>> >> +     int ret;
>> >> +
>> >> +     mutex_lock(&tegra_xhci_mbox_lock);
>> >> +     ret = raw_notifier_chain_register(&tegra_xhci_mbox_notifiers, nb);
>> >> +     mutex_unlock(&tegra_xhci_mbox_lock);
>> >> +
>> >> +     return ret;
>> >> +}
>> >> +EXPORT_SYMBOL(tegra_xhci_register_mbox_notifier);
>> >> +
>> >> +void tegra_xhci_unregister_mbox_notifier(struct notifier_block *nb)
>> >> +{
>> >> +     mutex_lock(&tegra_xhci_mbox_lock);
>> >> +     raw_notifier_chain_unregister(&tegra_xhci_mbox_notifiers, nb);
>> >> +     mutex_unlock(&tegra_xhci_mbox_lock);
>> >> +}
>> >> +EXPORT_SYMBOL(tegra_xhci_unregister_mbox_notifier);
>> >
>> > What driver would use these?
>>
>> It's used by just this driver (the host) and the PHY driver (next
>> patch in series).
>>
>> > My feeling is that if you have a mailbox that is used by multiple
>> > drivers, you should use a proper mailbox driver to operate them,
>> > and have the drivers register with that API instead of a custom one.
>>
>> Ok, will do.
>>
>> >> +     /* Create child xhci-plat device */
>> >> +     memset(xhci_resources, 0, sizeof(xhci_resources));
>> >> +     res = platform_get_resource(to_platform_device(dev), IORESOURCE_IRQ, 0);
>> >> +     if (!res) {
>> >> +             dev_err(dev, "Missing XHCI IRQ\n");
>> >> +             ret = -ENODEV;
>> >> +             goto out;
>> >> +     }
>> >> +     xhci_resources[0].start = res->start;
>> >> +     xhci_resources[0].end = res->end;
>> >> +     xhci_resources[0].flags = res->flags;
>> >> +     xhci_resources[0].name = res->name;
>> >> +     res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 0);
>> >> +     if (!res) {
>> >> +             dev_err(dev, "Missing XHCI registers\n");
>> >> +             ret = -ENODEV;
>> >> +             goto out;
>> >> +     }
>> >> +     xhci_resources[1].start = res->start;
>> >> +     xhci_resources[1].end = res->end;
>> >> +     xhci_resources[1].flags = res->flags;
>> >> +     xhci_resources[1].name = res->name;
>> >> +
>> >> +     xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
>> >> +     if (!xhci) {
>> >> +             dev_err(dev, "Failed to allocate XHCI host\n");
>> >> +             ret = -ENOMEM;
>> >> +             goto out;
>> >> +     }
>> >
>> > This does not feel appropriate at all: Rather than creating a child device,
>> > you should have a specific driver that hooks into functions exported
>> > by the xhci core. See Documentation/driver-model/design-patterns.txt
>>
>> This is how DWC3, currently the only in-tree non-PCI XHCI host driver,
>> is structured - see drivers/usb/dwc3/host.c.  The recently proposed
>> Armada XHCI driver [1] just adds clock support and a hook in
>> xhci-plat's probe() to do the platform-specific initialization.
>
> Ugh... that very much sounds like the midlayer mistake. Doing that is
> not going to scale in the long run. Everybody will just keep adding
> quirks to the initialization until it's become a huge mess.

Agreed - I didn't even bother trying to write the Tegra driver like that.

>> Tegra's XHCI driver initialization is quite a bit more complicated,
>> mainly due to the need for external firmware and specific ordering
>> (e.g. firmware messages should only be enabled after the HCD is
>> created).  I could do away with the xhci-plat sub-device and just
>> create a Tegra hc_driver, but it seems silly to have three XHCI
>> platform drivers structured in three different ways.  USB folks, do
>> you have an opinion on how this should be done?
>
> The tendency in other subsystems (and I think this is also true to some
> degree for USB, though I'm less familiar with it) is to make common
> functions available as a library of helpers so that other drivers can
> use them (either directly or by wrapping them in platform-specific
> implementations). That allows you to keep the platform-specific code
> where it belongs: in the platform-specific driver.

Yes, this is how the non-PCI EHCI host drivers are written.  I'll
structure it more like that for the next spin.

-Andrew

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [RFC PATCH 04/10] clk: tegra: Initialize xusb clocks
  2014-05-15 19:22   ` Stephen Warren
@ 2014-05-20 15:41     ` Peter De Schrijver
  0 siblings, 0 replies; 25+ messages in thread
From: Peter De Schrijver @ 2014-05-20 15:41 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Andrew Bresticker, Mike Turquette, linux-tegra, devicetree,
	linux-kernel, linux-arm-kernel, linux-usb, Mark Rutland,
	Prashant Gaikwad, Russell King, Mathias Nyman, Pawel Moll,
	Greg Kroah-Hartman, Ian Campbell, Jim Lin,
	Kishon Vijay Abraham I, Rob Herring, Thierry Reding,
	Randy Dunlap, Kumar Gala, Grant Likely

On Thu, May 15, 2014 at 09:22:00PM +0200, Stephen Warren wrote:
> On 05/14/2014 06:33 PM, Andrew Bresticker wrote:
> > Initialize the XUSB-related clocks with appropriate parents and rates
> > for both Tegra114 and Tegra124.
> 
> These first 4 clock driver patches look plausible to me, although I
> didn't look that hard!
> 
> Peter or Mike, if they look OK to you, can you please pick them up for
> 3.16 so that by the time we apply the rest of the patches in this series
> for 3.17, the clock dependencies are already there? Thanks.

Looks fine to me. Applied for 3.16, hopefully it will still make it.

Cheers,

Peter.

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2014-05-20 15:41 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-05-15  0:32 [RFC PATCH 00/10] Tegra XHCI support Andrew Bresticker
2014-05-15  0:32 ` [RFC PATCH 01/10] clk: tegra: Enable hardware control of PLLE Andrew Bresticker
2014-05-15  0:32 ` [RFC PATCH 02/10] clk: tegra: Fix xusb_fs_src mux Andrew Bresticker
2014-05-15  0:32 ` [RFC PATCH 03/10] clk: tegra: Fix xusb_hs_src clock hierarchy Andrew Bresticker
2014-05-15  0:33 ` [RFC PATCH 04/10] clk: tegra: Initialize xusb clocks Andrew Bresticker
2014-05-15 19:22   ` Stephen Warren
2014-05-20 15:41     ` Peter De Schrijver
2014-05-15  0:33 ` [RFC PATCH 05/10] ARM: tegra: Export function to read USB calibration data Andrew Bresticker
2014-05-15 20:39   ` Stephen Warren
2014-05-15  0:33 ` [RFC PATCH 06/10] usb: xhci: Add Tegra XHCI host-controller driver Andrew Bresticker
2014-05-15  8:17   ` Arnd Bergmann
2014-05-15  9:19     ` Thierry Reding
2014-05-15 13:30       ` Arnd Bergmann
2014-05-15 20:18     ` Andrew Bresticker
2014-05-15 21:16       ` Alan Stern
2014-05-15 21:18       ` Thierry Reding
2014-05-16 16:52         ` Andrew Bresticker
2014-05-15  0:33 ` [RFC PATCH 07/10] phy: Add Tegra XUSB PHY driver Andrew Bresticker
2014-05-15  0:33 ` [RFC PATCH 08/10] ARM: tegra124: Bind CAR to syscon device Andrew Bresticker
2014-05-15 19:25   ` Stephen Warren
2014-05-15 20:22     ` Andrew Bresticker
2014-05-15  0:33 ` [RFC PATCH 09/10] ARM: tegra124: Add XHCI controller and PHY Andrew Bresticker
2014-05-15  0:33 ` [RFC PATCH 10/10] ARM: tegra124: Enable XHCI on Venice2 Andrew Bresticker
2014-05-15 19:33 ` [RFC PATCH 00/10] Tegra XHCI support Stephen Warren
2014-05-15 20:44   ` Andrew Bresticker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).