All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/9] Tegra XHCI support
@ 2014-06-18  6:16 ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Mark Rutland, Russell King, Mathias Nyman, Pawel Moll,
	Ian Campbell, Andrew Bresticker, Greg Kroah-Hartman,
	Linus Walleij, Randy Dunlap, Kishon Vijay Abraham I,
	Grant Likely, Rob Herring, Thierry Reding, Kumar Gala,
	Stephen Warren, Alan Stern, Arnd Bergmann

This series adds support for XHCI on NVIDIA Tegra SoCs.  This includes:
 - extending the XUSB pad controller driver to support the USB PHY
   types (UTMI, HSIC, and USB3),
 - adding a driver for the mailbox used to communicate with the XHCI
   controller's firmware, and
 - adding a XHCI host-controller driver.

Based on Stephen Warren's for-next branch plus Thierry Reding's XUSB
pad controller driver [1].

Tested on Venice2 and Jetson TK1 with a variety of USB2.0 and USB3.0 memory
sticks and ethernet dongles using controller firmware from the ChromiumOS
tree [2].

Notes:
 - 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 later.
 - The XUSB padctl driver doesn't play nice with the existing Tegra USB2.0
   PHY driver, so all ports should be assigned to the XHCI controller.

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>

Changes from RFC:
 - Dropped Tegra114 support.
 - Split out mailbox into separate driver.
 - Stopped using child xhci-plat device in XHCI host-controller driver.
 - Added PHY support to Thierry's XUSB padctl driver instead of in a separate
   USB PHY driver.
 - Added Jetson TK1 support.
 - Misc. cleanups.

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

Andrew Bresticker (9):
  of: Add NVIDIA Tegra XUSB mailbox binding
  mailbox: Add NVIDIA Tegra XUSB mailbox driver
  of: Update Tegra XUSB pad controller binding for USB
  pinctrl: tegra-xusb: Add USB PHY support
  of: Add NVIDIA Tegra XHCI controller binding
  usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  ARM: tegra: Add Tegra124 XUSB mailbox and XHCI controller
  ARM: tegra: jetson-tk1: Add XHCI support
  ARM: tegra: venice2: Add XHCI support

 .../bindings/mailbox/nvidia,tegra124-xusb-mbox.txt |   25 +
 .../pinctrl/nvidia,tegra124-xusb-padctl.txt        |   53 +-
 .../bindings/usb/nvidia,tegra124-xhci.txt          |   76 ++
 arch/arm/boot/dts/tegra124-jetson-tk1.dts          |   43 +-
 arch/arm/boot/dts/tegra124-venice2.dts             |   72 +-
 arch/arm/boot/dts/tegra124.dtsi                    |   31 +
 drivers/mailbox/Kconfig                            |    7 +
 drivers/mailbox/Makefile                           |    2 +
 drivers/mailbox/tegra-xusb-mbox.c                  |  308 ++++++
 drivers/pinctrl/pinctrl-tegra-xusb.c               | 1106 +++++++++++++++++++-
 drivers/usb/host/Kconfig                           |   12 +
 drivers/usb/host/Makefile                          |    2 +
 drivers/usb/host/xhci-tegra.c                      |  900 ++++++++++++++++
 include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h   |    7 +
 include/linux/tegra-xusb-mbox.h                    |   98 ++
 15 files changed, 2673 insertions(+), 69 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
 create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
 create mode 100644 drivers/mailbox/tegra-xusb-mbox.c
 create mode 100644 drivers/usb/host/xhci-tegra.c
 create mode 100644 include/linux/tegra-xusb-mbox.h

-- 
2.0.0.526.g5318336

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

* [PATCH v1 0/9] Tegra XHCI support
@ 2014-06-18  6:16 ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

This series adds support for XHCI on NVIDIA Tegra SoCs.  This includes:
 - extending the XUSB pad controller driver to support the USB PHY
   types (UTMI, HSIC, and USB3),
 - adding a driver for the mailbox used to communicate with the XHCI
   controller's firmware, and
 - adding a XHCI host-controller driver.

Based on Stephen Warren's for-next branch plus Thierry Reding's XUSB
pad controller driver [1].

Tested on Venice2 and Jetson TK1 with a variety of USB2.0 and USB3.0 memory
sticks and ethernet dongles using controller firmware from the ChromiumOS
tree [2].

Notes:
 - 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 later.
 - The XUSB padctl driver doesn't play nice with the existing Tegra USB2.0
   PHY driver, so all ports should be assigned to the XHCI controller.

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>

Changes from RFC:
 - Dropped Tegra114 support.
 - Split out mailbox into separate driver.
 - Stopped using child xhci-plat device in XHCI host-controller driver.
 - Added PHY support to Thierry's XUSB padctl driver instead of in a separate
   USB PHY driver.
 - Added Jetson TK1 support.
 - Misc. cleanups.

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

Andrew Bresticker (9):
  of: Add NVIDIA Tegra XUSB mailbox binding
  mailbox: Add NVIDIA Tegra XUSB mailbox driver
  of: Update Tegra XUSB pad controller binding for USB
  pinctrl: tegra-xusb: Add USB PHY support
  of: Add NVIDIA Tegra XHCI controller binding
  usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  ARM: tegra: Add Tegra124 XUSB mailbox and XHCI controller
  ARM: tegra: jetson-tk1: Add XHCI support
  ARM: tegra: venice2: Add XHCI support

 .../bindings/mailbox/nvidia,tegra124-xusb-mbox.txt |   25 +
 .../pinctrl/nvidia,tegra124-xusb-padctl.txt        |   53 +-
 .../bindings/usb/nvidia,tegra124-xhci.txt          |   76 ++
 arch/arm/boot/dts/tegra124-jetson-tk1.dts          |   43 +-
 arch/arm/boot/dts/tegra124-venice2.dts             |   72 +-
 arch/arm/boot/dts/tegra124.dtsi                    |   31 +
 drivers/mailbox/Kconfig                            |    7 +
 drivers/mailbox/Makefile                           |    2 +
 drivers/mailbox/tegra-xusb-mbox.c                  |  308 ++++++
 drivers/pinctrl/pinctrl-tegra-xusb.c               | 1106 +++++++++++++++++++-
 drivers/usb/host/Kconfig                           |   12 +
 drivers/usb/host/Makefile                          |    2 +
 drivers/usb/host/xhci-tegra.c                      |  900 ++++++++++++++++
 include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h   |    7 +
 include/linux/tegra-xusb-mbox.h                    |   98 ++
 15 files changed, 2673 insertions(+), 69 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
 create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
 create mode 100644 drivers/mailbox/tegra-xusb-mbox.c
 create mode 100644 drivers/usb/host/xhci-tegra.c
 create mode 100644 include/linux/tegra-xusb-mbox.h

-- 
2.0.0.526.g5318336


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

* [PATCH v1 0/9] Tegra XHCI support
@ 2014-06-18  6:16 ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

This series adds support for XHCI on NVIDIA Tegra SoCs.  This includes:
 - extending the XUSB pad controller driver to support the USB PHY
   types (UTMI, HSIC, and USB3),
 - adding a driver for the mailbox used to communicate with the XHCI
   controller's firmware, and
 - adding a XHCI host-controller driver.

Based on Stephen Warren's for-next branch plus Thierry Reding's XUSB
pad controller driver [1].

Tested on Venice2 and Jetson TK1 with a variety of USB2.0 and USB3.0 memory
sticks and ethernet dongles using controller firmware from the ChromiumOS
tree [2].

Notes:
 - 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 later.
 - The XUSB padctl driver doesn't play nice with the existing Tegra USB2.0
   PHY driver, so all ports should be assigned to the XHCI controller.

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>

Changes from RFC:
 - Dropped Tegra114 support.
 - Split out mailbox into separate driver.
 - Stopped using child xhci-plat device in XHCI host-controller driver.
 - Added PHY support to Thierry's XUSB padctl driver instead of in a separate
   USB PHY driver.
 - Added Jetson TK1 support.
 - Misc. cleanups.

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

Andrew Bresticker (9):
  of: Add NVIDIA Tegra XUSB mailbox binding
  mailbox: Add NVIDIA Tegra XUSB mailbox driver
  of: Update Tegra XUSB pad controller binding for USB
  pinctrl: tegra-xusb: Add USB PHY support
  of: Add NVIDIA Tegra XHCI controller binding
  usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  ARM: tegra: Add Tegra124 XUSB mailbox and XHCI controller
  ARM: tegra: jetson-tk1: Add XHCI support
  ARM: tegra: venice2: Add XHCI support

 .../bindings/mailbox/nvidia,tegra124-xusb-mbox.txt |   25 +
 .../pinctrl/nvidia,tegra124-xusb-padctl.txt        |   53 +-
 .../bindings/usb/nvidia,tegra124-xhci.txt          |   76 ++
 arch/arm/boot/dts/tegra124-jetson-tk1.dts          |   43 +-
 arch/arm/boot/dts/tegra124-venice2.dts             |   72 +-
 arch/arm/boot/dts/tegra124.dtsi                    |   31 +
 drivers/mailbox/Kconfig                            |    7 +
 drivers/mailbox/Makefile                           |    2 +
 drivers/mailbox/tegra-xusb-mbox.c                  |  308 ++++++
 drivers/pinctrl/pinctrl-tegra-xusb.c               | 1106 +++++++++++++++++++-
 drivers/usb/host/Kconfig                           |   12 +
 drivers/usb/host/Makefile                          |    2 +
 drivers/usb/host/xhci-tegra.c                      |  900 ++++++++++++++++
 include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h   |    7 +
 include/linux/tegra-xusb-mbox.h                    |   98 ++
 15 files changed, 2673 insertions(+), 69 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
 create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
 create mode 100644 drivers/mailbox/tegra-xusb-mbox.c
 create mode 100644 drivers/usb/host/xhci-tegra.c
 create mode 100644 include/linux/tegra-xusb-mbox.h

-- 
2.0.0.526.g5318336

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

* [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
  2014-06-18  6:16 ` Andrew Bresticker
  (?)
@ 2014-06-18  6:16     ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Add device-tree bindings for the Tegra XUSB mailbox which will be used
for communication between the Tegra XHCI controller and the host.

Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 .../bindings/mailbox/nvidia,tegra124-xusb-mbox.txt | 25 ++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt

diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
new file mode 100644
index 0000000..c1833e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
@@ -0,0 +1,25 @@
+NVIDIA Tegra XUSB mailbox
+=========================
+
+The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
+communicate with the host.
+
+Required properties:
+--------------------
+ - compatible: Should be "nvidia,tegra124-xusb-mbox".
+ - reg: Address and length of the XUSB FPCI registers.
+ - interrupts: XUSB mailbox interrupt.
+
+Example:
+--------
+	mbox: mailbox@0,70098000 {
+		compatible = "nvidia,tegra124-xusb-mbox";
+		reg = <0x0 0x70098000 0x0 0x1000>;
+		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	usb@0,70090000 {
+		...
+		nvidia,xusb-mbox = <&mbox>;
+		...
+	};
-- 
2.0.0.526.g5318336

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

* [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
@ 2014-06-18  6:16     ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Add device-tree bindings for the Tegra XUSB mailbox which will be used
for communication between the Tegra XHCI controller and the host.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 .../bindings/mailbox/nvidia,tegra124-xusb-mbox.txt | 25 ++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt

diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
new file mode 100644
index 0000000..c1833e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
@@ -0,0 +1,25 @@
+NVIDIA Tegra XUSB mailbox
+=========================
+
+The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
+communicate with the host.
+
+Required properties:
+--------------------
+ - compatible: Should be "nvidia,tegra124-xusb-mbox".
+ - reg: Address and length of the XUSB FPCI registers.
+ - interrupts: XUSB mailbox interrupt.
+
+Example:
+--------
+	mbox: mailbox@0,70098000 {
+		compatible = "nvidia,tegra124-xusb-mbox";
+		reg = <0x0 0x70098000 0x0 0x1000>;
+		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	usb@0,70090000 {
+		...
+		nvidia,xusb-mbox = <&mbox>;
+		...
+	};
-- 
2.0.0.526.g5318336


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

* [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
@ 2014-06-18  6:16     ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

Add device-tree bindings for the Tegra XUSB mailbox which will be used
for communication between the Tegra XHCI controller and the host.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 .../bindings/mailbox/nvidia,tegra124-xusb-mbox.txt | 25 ++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt

diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
new file mode 100644
index 0000000..c1833e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
@@ -0,0 +1,25 @@
+NVIDIA Tegra XUSB mailbox
+=========================
+
+The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
+communicate with the host.
+
+Required properties:
+--------------------
+ - compatible: Should be "nvidia,tegra124-xusb-mbox".
+ - reg: Address and length of the XUSB FPCI registers.
+ - interrupts: XUSB mailbox interrupt.
+
+Example:
+--------
+	mbox: mailbox at 0,70098000 {
+		compatible = "nvidia,tegra124-xusb-mbox";
+		reg = <0x0 0x70098000 0x0 0x1000>;
+		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	usb at 0,70090000 {
+		...
+		nvidia,xusb-mbox = <&mbox>;
+		...
+	};
-- 
2.0.0.526.g5318336

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

* [PATCH v1 2/9] mailbox: Add NVIDIA Tegra XUSB mailbox driver
  2014-06-18  6:16 ` Andrew Bresticker
@ 2014-06-18  6:16   ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

The Tegra XHCI controller communicates requests to the host through
a mailbox interface.  Host drivers which can handle these requests,
such as the Tegra XUSB pad controller driver and upcoming Tegra XHCI
host controller driver, can send messages and register to be notified
of incoming messages.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/mailbox/Kconfig           |   7 +
 drivers/mailbox/Makefile          |   2 +
 drivers/mailbox/tegra-xusb-mbox.c | 308 ++++++++++++++++++++++++++++++++++++++
 include/linux/tegra-xusb-mbox.h   |  98 ++++++++++++
 4 files changed, 415 insertions(+)
 create mode 100644 drivers/mailbox/tegra-xusb-mbox.c
 create mode 100644 include/linux/tegra-xusb-mbox.h

diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index c8b5c13..510c44a 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -50,4 +50,11 @@ config OMAP_MBOX_KFIFO_SIZE
 	  Specify the default size of mailbox's kfifo buffers (bytes).
 	  This can also be changed at runtime (via the mbox_kfifo_size
 	  module parameter).
+
+config TEGRA_XUSB_MBOX
+	bool "NVIDIA Tegra XUSB mailbox support"
+	depends on ARCH_TEGRA
+	help
+	  Mailbox driver used for communication with the firmware on the
+	  on-chip XHCI controller present on NVIDIA Tegra124 SoCs.
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index e0facb3..8cc53ef 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -5,3 +5,5 @@ obj-$(CONFIG_OMAP1_MBOX)	+= mailbox_omap1.o
 mailbox_omap1-objs		:= mailbox-omap1.o
 obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox_omap2.o
 mailbox_omap2-objs		:= mailbox-omap2.o
+
+obj-$(CONFIG_TEGRA_XUSB_MBOX)	+= tegra-xusb-mbox.o
diff --git a/drivers/mailbox/tegra-xusb-mbox.c b/drivers/mailbox/tegra-xusb-mbox.c
new file mode 100644
index 0000000..a4d2929
--- /dev/null
+++ b/drivers/mailbox/tegra-xusb-mbox.c
@@ -0,0 +1,308 @@
+/*
+ * NVIDIA Tegra XUSB mailbox 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/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/tegra-xusb-mbox.h>
+
+#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_ARU_SMI_INTR			0x428
+#define  MBOX_SMI_INTR_FW_HANG			BIT(1)
+#define  MBOX_SMI_INTR_EN			BIT(3)
+
+#define XUSB_MBOX_IDLE_TIMEOUT		20
+#define XUSB_MBOX_ACQUIRE_TIMEOUT	10
+
+struct tegra_xusb_mbox {
+	struct device *dev;
+	int irq;
+	struct raw_notifier_head notifiers;
+	struct mutex lock;
+	void __iomem *regs;
+};
+
+static struct platform_driver tegra_xusb_mbox_driver;
+
+int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
+				      struct notifier_block *nb)
+{
+	int ret;
+
+	mutex_lock(&mbox->lock);
+	ret = raw_notifier_chain_register(&mbox->notifiers, nb);
+	mutex_unlock(&mbox->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(tegra_xusb_mbox_register_notifier);
+
+void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
+					 struct notifier_block *nb)
+{
+	mutex_lock(&mbox->lock);
+	raw_notifier_chain_unregister(&mbox->notifiers, nb);
+	mutex_unlock(&mbox->lock);
+}
+EXPORT_SYMBOL(tegra_xusb_mbox_unregister_notifier);
+
+static int tegra_xusb_mbox_match_node(struct device *dev, void *data)
+{
+	struct device_node *np = data;
+
+	return dev->of_node == np;
+}
+
+struct tegra_xusb_mbox *
+tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop)
+{
+	struct tegra_xusb_mbox *mbox;
+	struct device_node *mbox_np;
+	struct device *dev;
+
+	mbox_np = of_parse_phandle(np, prop, 0);
+	if (!mbox_np)
+		return ERR_PTR(-ENODEV);
+
+	dev = driver_find_device(&tegra_xusb_mbox_driver.driver, NULL, mbox_np,
+				 tegra_xusb_mbox_match_node);
+	if (!dev) {
+		mbox = ERR_PTR(-EPROBE_DEFER);
+		goto out;
+	}
+	mbox = dev_get_drvdata(dev);
+out:
+	of_node_put(mbox_np);
+	return mbox;
+}
+EXPORT_SYMBOL(tegra_xusb_mbox_lookup_by_phandle);
+
+static inline u32 mbox_readl(struct tegra_xusb_mbox *mbox, unsigned long offset)
+{
+	return readl(mbox->regs + offset);
+}
+
+static inline void mbox_writel(struct tegra_xusb_mbox *mbox, u32 val,
+			       unsigned long offset)
+{
+	writel(val, mbox->regs + offset);
+}
+
+static inline u32 mbox_pack_msg(u32 cmd, u32 data)
+{
+	u32 msg;
+
+	msg = (cmd & CMD_TYPE_MASK) << CMD_TYPE_SHIFT;
+	msg |= (data & CMD_DATA_MASK) << CMD_DATA_SHIFT;
+
+	return msg;
+}
+
+static inline void mbox_unpack_msg(u32 msg, u32 *cmd, u32 *data)
+{
+	*cmd = (msg >> CMD_TYPE_SHIFT) & CMD_TYPE_MASK;
+	*data = (msg >> CMD_DATA_SHIFT) & CMD_DATA_MASK;
+}
+
+int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
+			 enum tegra_xusb_mbox_cmd type, u32 data)
+{
+	unsigned long timeout;
+	u32 reg;
+
+	dev_dbg(mbox->dev, "MBOX send message 0x%x:0x%x\n", type, data);
+	mutex_lock(&mbox->lock);
+
+	/* Wait for mailbox to become idle */
+	timeout = jiffies + msecs_to_jiffies(XUSB_MBOX_IDLE_TIMEOUT);
+	while ((mbox_readl(mbox, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_NONE)
+	       && time_is_after_jiffies(timeout)) {
+		mutex_unlock(&mbox->lock);
+		usleep_range(100, 200);
+		mutex_lock(&mbox->lock);
+	}
+	if (mbox_readl(mbox, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_NONE) {
+		dev_err(mbox->dev, "Mailbox failed to go idle\n");
+		goto timeout;
+	}
+
+	/* Acquire mailbox */
+	timeout = jiffies + msecs_to_jiffies(XUSB_MBOX_ACQUIRE_TIMEOUT);
+	mbox_writel(mbox, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER);
+	while ((mbox_readl(mbox, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_SW) &&
+	       time_is_after_jiffies(timeout)) {
+		mutex_unlock(&mbox->lock);
+		usleep_range(100, 200);
+		mutex_lock(&mbox->lock);
+		mbox_writel(mbox, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER);
+	}
+	if (mbox_readl(mbox, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_SW) {
+		dev_err(mbox->dev, "Acquire mailbox timeout\n");
+		goto timeout;
+	}
+
+	mbox_writel(mbox, mbox_pack_msg(type, data), XUSB_CFG_ARU_MBOX_DATA_IN);
+	reg = mbox_readl(mbox, XUSB_CFG_ARU_MBOX_CMD);
+	reg |= MBOX_INT_EN | MBOX_FALC_INT_EN;
+	mbox_writel(mbox, reg, XUSB_CFG_ARU_MBOX_CMD);
+
+	mutex_unlock(&mbox->lock);
+
+	return 0;
+timeout:
+	mutex_unlock(&mbox->lock);
+	return -ETIMEDOUT;
+}
+
+static irqreturn_t tegra_xusb_mbox_irq(int irq, void *p)
+{
+	struct tegra_xusb_mbox *mbox = (struct tegra_xusb_mbox *)p;
+	u32 resp = 0, cmd_in, data_in, reg;
+
+	mutex_lock(&mbox->lock);
+
+	/* Clear mbox interrupts */
+	reg = mbox_readl(mbox, XUSB_CFG_ARU_SMI_INTR);
+	if (reg & MBOX_SMI_INTR_FW_HANG)
+		dev_err(mbox->dev, "Hang up inside firmware\n");
+	mbox_writel(mbox, reg, XUSB_CFG_ARU_SMI_INTR);
+
+	/* Get the mbox message from firmware */
+	reg = mbox_readl(mbox, XUSB_CFG_ARU_MBOX_DATA_OUT);
+	mbox_unpack_msg(reg, &cmd_in, &data_in);
+
+	/* Decode the message and call the notifiers */
+	dev_dbg(mbox->dev, "MBOX receive message 0x%x:0x%x\n", cmd_in, data_in);
+	if (cmd_in < MBOX_CMD_MAX) {
+		struct tegra_xusb_mbox_msg msg;
+
+		msg.data_in = data_in;
+		msg.cmd_out = 0;
+		msg.data_out = 0;
+		raw_notifier_call_chain(&mbox->notifiers, cmd_in, &msg);
+		if (msg.cmd_out)
+			resp = mbox_pack_msg(msg.cmd_out, msg.data_out);
+	} else if (cmd_in == MBOX_CMD_ACK) {
+		dev_dbg(mbox->dev, "Firmware responds with ACK\n");
+	} else if (cmd_in == MBOX_CMD_NAK) {
+		dev_err(mbox->dev, "Firmware responds with NAK\n");
+	} else {
+		dev_err(mbox->dev, "Invalid command: 0x%x\n", cmd_in);
+	}
+
+	if (resp) {
+		/* Send ACK/NAK to firmware */
+		mbox_writel(mbox, resp, XUSB_CFG_ARU_MBOX_DATA_IN);
+		reg = mbox_readl(mbox, XUSB_CFG_ARU_MBOX_CMD);
+		reg |= MBOX_INT_EN | MBOX_FALC_INT_EN;
+		mbox_writel(mbox, reg, XUSB_CFG_ARU_MBOX_CMD);
+	} else {
+		/* Clear MBOX_SMI_INT_EN bit */
+		reg = mbox_readl(mbox, XUSB_CFG_ARU_MBOX_CMD);
+		reg &= ~MBOX_SMI_INT_EN;
+		mbox_writel(mbox, reg, XUSB_CFG_ARU_MBOX_CMD);
+		/* Clear mailbox ownership */
+		mbox_writel(mbox, MBOX_OWNER_NONE, XUSB_CFG_ARU_MBOX_OWNER);
+	}
+
+	mutex_unlock(&mbox->lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct of_device_id tegra_xusb_mbox_of_match[] = {
+	{ .compatible = "nvidia,tegra124-xusb-mbox" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tegra_xusb_mbox_of_match);
+
+static int tegra_xusb_mbox_probe(struct platform_device *pdev)
+{
+	struct tegra_xusb_mbox *mbox;
+	struct resource *res;
+	int ret;
+
+	mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	mbox->dev = &pdev->dev;
+	mutex_init(&mbox->lock);
+	RAW_INIT_NOTIFIER_HEAD(&mbox->notifiers);
+	platform_set_drvdata(pdev, mbox);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+	mbox->regs = devm_ioremap_nocache(mbox->dev, res->start,
+					  resource_size(res));
+	if (!mbox->regs)
+		return -ENOMEM;
+
+	mbox->irq = platform_get_irq(pdev, 0);
+	if (mbox->irq < 0)
+		return mbox->irq;
+	ret = devm_request_threaded_irq(mbox->dev, mbox->irq, NULL,
+					tegra_xusb_mbox_irq, IRQF_ONESHOT,
+					dev_name(mbox->dev), mbox);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int tegra_xusb_mbox_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver tegra_xusb_mbox_driver = {
+	.probe	= tegra_xusb_mbox_probe,
+	.remove	= tegra_xusb_mbox_remove,
+	.driver	= {
+		.name = "tegra-xusb-mbox",
+		.of_match_table = of_match_ptr(tegra_xusb_mbox_of_match),
+	},
+};
+module_platform_driver(tegra_xusb_mbox_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra XUSB mailbox driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tegra-xusb-mailbox");
diff --git a/include/linux/tegra-xusb-mbox.h b/include/linux/tegra-xusb-mbox.h
new file mode 100644
index 0000000..d31b6da
--- /dev/null
+++ b/include/linux/tegra-xusb-mbox.h
@@ -0,0 +1,98 @@
+/*
+ * 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_MBOX_H
+#define __TEGRA_XUSB_MBOX_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;
+struct tegra_xusb_mbox;
+
+/*
+ * 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 tegra_xusb_mbox_msg.
+ *   - If a notifier has handled the message, it should return NOTIFY_STOP
+ *     and populate {cmd,data}_out appropriately.
+ *   - A cmd_out of 0 indicates that no response should be sent.
+ */
+struct tegra_xusb_mbox_msg {
+	u32 data_in;
+	enum tegra_xusb_mbox_cmd cmd_out;
+	u32 data_out;
+};
+
+#ifdef CONFIG_TEGRA_XUSB_MBOX
+extern int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
+					     struct notifier_block *nb);
+extern void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
+						struct notifier_block *nb);
+extern int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
+				enum tegra_xusb_mbox_cmd cmd, u32 data);
+extern struct tegra_xusb_mbox *
+tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop);
+#else
+static inline int
+tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
+				  struct notifier_block *nb)
+{
+	return -ENOSYS;
+}
+static inline void
+tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
+				    struct notifier_block *nb)
+{
+}
+static inline int
+tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
+		     enum tegra_xusb_mbox_cmd cmd, u32 data)
+{
+	return -ENOSYS;
+}
+static inline struct tegra_xusb_mbox *
+tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif
+
+#endif /* __TEGRA_XUSB_MBOX_H */
-- 
2.0.0.526.g5318336


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

* [PATCH v1 2/9] mailbox: Add NVIDIA Tegra XUSB mailbox driver
@ 2014-06-18  6:16   ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

The Tegra XHCI controller communicates requests to the host through
a mailbox interface.  Host drivers which can handle these requests,
such as the Tegra XUSB pad controller driver and upcoming Tegra XHCI
host controller driver, can send messages and register to be notified
of incoming messages.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/mailbox/Kconfig           |   7 +
 drivers/mailbox/Makefile          |   2 +
 drivers/mailbox/tegra-xusb-mbox.c | 308 ++++++++++++++++++++++++++++++++++++++
 include/linux/tegra-xusb-mbox.h   |  98 ++++++++++++
 4 files changed, 415 insertions(+)
 create mode 100644 drivers/mailbox/tegra-xusb-mbox.c
 create mode 100644 include/linux/tegra-xusb-mbox.h

diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index c8b5c13..510c44a 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -50,4 +50,11 @@ config OMAP_MBOX_KFIFO_SIZE
 	  Specify the default size of mailbox's kfifo buffers (bytes).
 	  This can also be changed at runtime (via the mbox_kfifo_size
 	  module parameter).
+
+config TEGRA_XUSB_MBOX
+	bool "NVIDIA Tegra XUSB mailbox support"
+	depends on ARCH_TEGRA
+	help
+	  Mailbox driver used for communication with the firmware on the
+	  on-chip XHCI controller present on NVIDIA Tegra124 SoCs.
 endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index e0facb3..8cc53ef 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -5,3 +5,5 @@ obj-$(CONFIG_OMAP1_MBOX)	+= mailbox_omap1.o
 mailbox_omap1-objs		:= mailbox-omap1.o
 obj-$(CONFIG_OMAP2PLUS_MBOX)	+= mailbox_omap2.o
 mailbox_omap2-objs		:= mailbox-omap2.o
+
+obj-$(CONFIG_TEGRA_XUSB_MBOX)	+= tegra-xusb-mbox.o
diff --git a/drivers/mailbox/tegra-xusb-mbox.c b/drivers/mailbox/tegra-xusb-mbox.c
new file mode 100644
index 0000000..a4d2929
--- /dev/null
+++ b/drivers/mailbox/tegra-xusb-mbox.c
@@ -0,0 +1,308 @@
+/*
+ * NVIDIA Tegra XUSB mailbox 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/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/tegra-xusb-mbox.h>
+
+#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_ARU_SMI_INTR			0x428
+#define  MBOX_SMI_INTR_FW_HANG			BIT(1)
+#define  MBOX_SMI_INTR_EN			BIT(3)
+
+#define XUSB_MBOX_IDLE_TIMEOUT		20
+#define XUSB_MBOX_ACQUIRE_TIMEOUT	10
+
+struct tegra_xusb_mbox {
+	struct device *dev;
+	int irq;
+	struct raw_notifier_head notifiers;
+	struct mutex lock;
+	void __iomem *regs;
+};
+
+static struct platform_driver tegra_xusb_mbox_driver;
+
+int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
+				      struct notifier_block *nb)
+{
+	int ret;
+
+	mutex_lock(&mbox->lock);
+	ret = raw_notifier_chain_register(&mbox->notifiers, nb);
+	mutex_unlock(&mbox->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL(tegra_xusb_mbox_register_notifier);
+
+void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
+					 struct notifier_block *nb)
+{
+	mutex_lock(&mbox->lock);
+	raw_notifier_chain_unregister(&mbox->notifiers, nb);
+	mutex_unlock(&mbox->lock);
+}
+EXPORT_SYMBOL(tegra_xusb_mbox_unregister_notifier);
+
+static int tegra_xusb_mbox_match_node(struct device *dev, void *data)
+{
+	struct device_node *np = data;
+
+	return dev->of_node == np;
+}
+
+struct tegra_xusb_mbox *
+tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop)
+{
+	struct tegra_xusb_mbox *mbox;
+	struct device_node *mbox_np;
+	struct device *dev;
+
+	mbox_np = of_parse_phandle(np, prop, 0);
+	if (!mbox_np)
+		return ERR_PTR(-ENODEV);
+
+	dev = driver_find_device(&tegra_xusb_mbox_driver.driver, NULL, mbox_np,
+				 tegra_xusb_mbox_match_node);
+	if (!dev) {
+		mbox = ERR_PTR(-EPROBE_DEFER);
+		goto out;
+	}
+	mbox = dev_get_drvdata(dev);
+out:
+	of_node_put(mbox_np);
+	return mbox;
+}
+EXPORT_SYMBOL(tegra_xusb_mbox_lookup_by_phandle);
+
+static inline u32 mbox_readl(struct tegra_xusb_mbox *mbox, unsigned long offset)
+{
+	return readl(mbox->regs + offset);
+}
+
+static inline void mbox_writel(struct tegra_xusb_mbox *mbox, u32 val,
+			       unsigned long offset)
+{
+	writel(val, mbox->regs + offset);
+}
+
+static inline u32 mbox_pack_msg(u32 cmd, u32 data)
+{
+	u32 msg;
+
+	msg = (cmd & CMD_TYPE_MASK) << CMD_TYPE_SHIFT;
+	msg |= (data & CMD_DATA_MASK) << CMD_DATA_SHIFT;
+
+	return msg;
+}
+
+static inline void mbox_unpack_msg(u32 msg, u32 *cmd, u32 *data)
+{
+	*cmd = (msg >> CMD_TYPE_SHIFT) & CMD_TYPE_MASK;
+	*data = (msg >> CMD_DATA_SHIFT) & CMD_DATA_MASK;
+}
+
+int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
+			 enum tegra_xusb_mbox_cmd type, u32 data)
+{
+	unsigned long timeout;
+	u32 reg;
+
+	dev_dbg(mbox->dev, "MBOX send message 0x%x:0x%x\n", type, data);
+	mutex_lock(&mbox->lock);
+
+	/* Wait for mailbox to become idle */
+	timeout = jiffies + msecs_to_jiffies(XUSB_MBOX_IDLE_TIMEOUT);
+	while ((mbox_readl(mbox, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_NONE)
+	       && time_is_after_jiffies(timeout)) {
+		mutex_unlock(&mbox->lock);
+		usleep_range(100, 200);
+		mutex_lock(&mbox->lock);
+	}
+	if (mbox_readl(mbox, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_NONE) {
+		dev_err(mbox->dev, "Mailbox failed to go idle\n");
+		goto timeout;
+	}
+
+	/* Acquire mailbox */
+	timeout = jiffies + msecs_to_jiffies(XUSB_MBOX_ACQUIRE_TIMEOUT);
+	mbox_writel(mbox, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER);
+	while ((mbox_readl(mbox, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_SW) &&
+	       time_is_after_jiffies(timeout)) {
+		mutex_unlock(&mbox->lock);
+		usleep_range(100, 200);
+		mutex_lock(&mbox->lock);
+		mbox_writel(mbox, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER);
+	}
+	if (mbox_readl(mbox, XUSB_CFG_ARU_MBOX_OWNER) != MBOX_OWNER_SW) {
+		dev_err(mbox->dev, "Acquire mailbox timeout\n");
+		goto timeout;
+	}
+
+	mbox_writel(mbox, mbox_pack_msg(type, data), XUSB_CFG_ARU_MBOX_DATA_IN);
+	reg = mbox_readl(mbox, XUSB_CFG_ARU_MBOX_CMD);
+	reg |= MBOX_INT_EN | MBOX_FALC_INT_EN;
+	mbox_writel(mbox, reg, XUSB_CFG_ARU_MBOX_CMD);
+
+	mutex_unlock(&mbox->lock);
+
+	return 0;
+timeout:
+	mutex_unlock(&mbox->lock);
+	return -ETIMEDOUT;
+}
+
+static irqreturn_t tegra_xusb_mbox_irq(int irq, void *p)
+{
+	struct tegra_xusb_mbox *mbox = (struct tegra_xusb_mbox *)p;
+	u32 resp = 0, cmd_in, data_in, reg;
+
+	mutex_lock(&mbox->lock);
+
+	/* Clear mbox interrupts */
+	reg = mbox_readl(mbox, XUSB_CFG_ARU_SMI_INTR);
+	if (reg & MBOX_SMI_INTR_FW_HANG)
+		dev_err(mbox->dev, "Hang up inside firmware\n");
+	mbox_writel(mbox, reg, XUSB_CFG_ARU_SMI_INTR);
+
+	/* Get the mbox message from firmware */
+	reg = mbox_readl(mbox, XUSB_CFG_ARU_MBOX_DATA_OUT);
+	mbox_unpack_msg(reg, &cmd_in, &data_in);
+
+	/* Decode the message and call the notifiers */
+	dev_dbg(mbox->dev, "MBOX receive message 0x%x:0x%x\n", cmd_in, data_in);
+	if (cmd_in < MBOX_CMD_MAX) {
+		struct tegra_xusb_mbox_msg msg;
+
+		msg.data_in = data_in;
+		msg.cmd_out = 0;
+		msg.data_out = 0;
+		raw_notifier_call_chain(&mbox->notifiers, cmd_in, &msg);
+		if (msg.cmd_out)
+			resp = mbox_pack_msg(msg.cmd_out, msg.data_out);
+	} else if (cmd_in == MBOX_CMD_ACK) {
+		dev_dbg(mbox->dev, "Firmware responds with ACK\n");
+	} else if (cmd_in == MBOX_CMD_NAK) {
+		dev_err(mbox->dev, "Firmware responds with NAK\n");
+	} else {
+		dev_err(mbox->dev, "Invalid command: 0x%x\n", cmd_in);
+	}
+
+	if (resp) {
+		/* Send ACK/NAK to firmware */
+		mbox_writel(mbox, resp, XUSB_CFG_ARU_MBOX_DATA_IN);
+		reg = mbox_readl(mbox, XUSB_CFG_ARU_MBOX_CMD);
+		reg |= MBOX_INT_EN | MBOX_FALC_INT_EN;
+		mbox_writel(mbox, reg, XUSB_CFG_ARU_MBOX_CMD);
+	} else {
+		/* Clear MBOX_SMI_INT_EN bit */
+		reg = mbox_readl(mbox, XUSB_CFG_ARU_MBOX_CMD);
+		reg &= ~MBOX_SMI_INT_EN;
+		mbox_writel(mbox, reg, XUSB_CFG_ARU_MBOX_CMD);
+		/* Clear mailbox ownership */
+		mbox_writel(mbox, MBOX_OWNER_NONE, XUSB_CFG_ARU_MBOX_OWNER);
+	}
+
+	mutex_unlock(&mbox->lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct of_device_id tegra_xusb_mbox_of_match[] = {
+	{ .compatible = "nvidia,tegra124-xusb-mbox" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tegra_xusb_mbox_of_match);
+
+static int tegra_xusb_mbox_probe(struct platform_device *pdev)
+{
+	struct tegra_xusb_mbox *mbox;
+	struct resource *res;
+	int ret;
+
+	mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox), GFP_KERNEL);
+	if (!mbox)
+		return -ENOMEM;
+	mbox->dev = &pdev->dev;
+	mutex_init(&mbox->lock);
+	RAW_INIT_NOTIFIER_HEAD(&mbox->notifiers);
+	platform_set_drvdata(pdev, mbox);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+	mbox->regs = devm_ioremap_nocache(mbox->dev, res->start,
+					  resource_size(res));
+	if (!mbox->regs)
+		return -ENOMEM;
+
+	mbox->irq = platform_get_irq(pdev, 0);
+	if (mbox->irq < 0)
+		return mbox->irq;
+	ret = devm_request_threaded_irq(mbox->dev, mbox->irq, NULL,
+					tegra_xusb_mbox_irq, IRQF_ONESHOT,
+					dev_name(mbox->dev), mbox);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int tegra_xusb_mbox_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver tegra_xusb_mbox_driver = {
+	.probe	= tegra_xusb_mbox_probe,
+	.remove	= tegra_xusb_mbox_remove,
+	.driver	= {
+		.name = "tegra-xusb-mbox",
+		.of_match_table = of_match_ptr(tegra_xusb_mbox_of_match),
+	},
+};
+module_platform_driver(tegra_xusb_mbox_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra XUSB mailbox driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tegra-xusb-mailbox");
diff --git a/include/linux/tegra-xusb-mbox.h b/include/linux/tegra-xusb-mbox.h
new file mode 100644
index 0000000..d31b6da
--- /dev/null
+++ b/include/linux/tegra-xusb-mbox.h
@@ -0,0 +1,98 @@
+/*
+ * 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_MBOX_H
+#define __TEGRA_XUSB_MBOX_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;
+struct tegra_xusb_mbox;
+
+/*
+ * 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 tegra_xusb_mbox_msg.
+ *   - If a notifier has handled the message, it should return NOTIFY_STOP
+ *     and populate {cmd,data}_out appropriately.
+ *   - A cmd_out of 0 indicates that no response should be sent.
+ */
+struct tegra_xusb_mbox_msg {
+	u32 data_in;
+	enum tegra_xusb_mbox_cmd cmd_out;
+	u32 data_out;
+};
+
+#ifdef CONFIG_TEGRA_XUSB_MBOX
+extern int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
+					     struct notifier_block *nb);
+extern void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
+						struct notifier_block *nb);
+extern int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
+				enum tegra_xusb_mbox_cmd cmd, u32 data);
+extern struct tegra_xusb_mbox *
+tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop);
+#else
+static inline int
+tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
+				  struct notifier_block *nb)
+{
+	return -ENOSYS;
+}
+static inline void
+tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
+				    struct notifier_block *nb)
+{
+}
+static inline int
+tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
+		     enum tegra_xusb_mbox_cmd cmd, u32 data)
+{
+	return -ENOSYS;
+}
+static inline struct tegra_xusb_mbox *
+tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop)
+{
+	return ERR_PTR(-ENOSYS);
+}
+#endif
+
+#endif /* __TEGRA_XUSB_MBOX_H */
-- 
2.0.0.526.g5318336

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

* [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
  2014-06-18  6:16 ` Andrew Bresticker
@ 2014-06-18  6:16   ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Add new bindings used for USB support by the Tegra XUSB pad controller.
This includes additional PHY types, USB-specific pinconfig properties, etc.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 .../pinctrl/nvidia,tegra124-xusb-padctl.txt        | 53 ++++++++++++++++++++--
 include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h   |  7 +++
 2 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
index 2f9c0bd..6181019 100644
--- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
@@ -21,6 +21,12 @@ Required properties:
   - padctl
 - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
   See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
+- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
+
+Optional properties:
+-------------------
+- vbus-otg-{0,1,2}-supply: VBUS regulator for the corresponding UTMI pad.
+- vddio-hsic-supply: VDDIO regulator for the HSIC pads.
 
 Lane muxing:
 ------------
@@ -50,6 +56,16 @@ Optional properties:
   pin or group should be assigned to. Valid values for function names are
   listed below.
 - nvidia,iddq: Enables IDDQ mode of the lane. (0: no, 1: yes)
+- nvidia,usb3-port-num: USB3 port (0 or 1) to which the lane is mapped.
+- nvidia,usb2-port-num: USB2 port (0, 1, or 2) to which the lane is mapped.
+- nvidia,hsic-strobe-trim: HSIC strobe trimmer value.
+- nvidia,hsic-rx-strobe-trim: HSIC RX strobe trimmer value.
+- nvidia,hsic-rx-data-trim: HSIC RX data trimmer value.
+- nvidia,hsic-tx-rtune-n: HSIC TX RTUNEN value.
+- nvidia,hsic-tx-rtune-p: HSIC TX RTUNEP value.
+- nvidia,hsic-tx-slew-n: HSIC TX SLEWN value.
+- nvidia,hsic-tx-slew-p: HSIC TX SLEWP value.
+- nvidia,hsic-auto-term: Enables HSIC AUTO_TERM. (0: no, 1: yes)
 
 Note that not all of these properties are valid for all lanes. Lanes can be
 divided into three groups:
@@ -58,18 +74,25 @@ divided into three groups:
 
     Valid functions for this group are: "snps", "xusb", "uart", "rsvd".
 
-    The nvidia,iddq property does not apply to this group.
+    The nvidia,iddq, nvidia,usb3-port-num, nvidia,usb2-port-num, and
+    nvidia,hsic-* properties do not apply to this group.
 
   - ulpi-0, hsic-0, hsic-1:
 
     Valid functions for this group are: "snps", "xusb".
 
-    The nvidia,iddq property does not apply to this group.
+    The nvidia,iddq, nvidia,usb3-port-num, and nvidia,usb2-port-num
+    properties do not apply to this group.  The nvidia,hsic-*  properties
+    apply only to the pins hsic-{0,1} when the function is xusb.
 
   - pcie-0, pcie-1, pcie-2, pcie-3, pcie-4, sata-0:
 
     Valid functions for this group are: "pcie", "usb3", "sata", "rsvd".
 
+    The nvidia,usb3-port-num and nvidia,usb2-port-num properties only
+    apply and are required when the function is usb3.  The nvidia,hsic-*
+    properties do not apply to this group.
+
 
 Example:
 ========
@@ -83,6 +106,8 @@ SoC file extract:
 		resets = <&tegra_car 142>;
 		reset-names = "padctl";
 
+		nvidia,xusb-mbox = <&mbox>;
+
 		#phy-cells = <1>;
 	};
 
@@ -100,15 +125,35 @@ Board file extract:
 
 	...
 
+	usb@0,70090000 {
+		...
+
+		phys = <&padctl 5>, <&padctl 6>, <&padctl 7>;
+		phy-names = "utmi-1", "utmi-2", "usb3-0";
+
+		...
+	}
+
+	...
+
 	padctl: padctl@0,7009f000 {
 		pinctrl-0 = <&padctl_default>;
 		pinctrl-names = "default";
 
+		vbus-otg-2-supply = <&vdd_usb3_vbus>;
+
 		padctl_default: pinmux {
-			usb3 {
-				nvidia,lanes = "pcie-0", "pcie-1";
+			otg {
+				nvidia,lanes = "otg-1", "otg-2";
+				nvidia,function = "xusb";
+			};
+
+			usb3p0 {
+				nvidia,lanes = "pcie-0";
 				nvidia,function = "usb3";
 				nvidia,iddq = <0>;
+				nvidia,usb3-port-num = <0>;
+				nvidia,usb2-port-num = <2>;
 			};
 
 			pcie {
diff --git a/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h b/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h
index 914d56d..c83a4d4 100644
--- a/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h
+++ b/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h
@@ -3,5 +3,12 @@
 
 #define TEGRA_XUSB_PADCTL_PCIE 0
 #define TEGRA_XUSB_PADCTL_SATA 1
+#define TEGRA_XUSB_PADCTL_USB3_P0 2
+#define TEGRA_XUSB_PADCTL_USB3_P1 3
+#define TEGRA_XUSB_PADCTL_UTMI_P0 4
+#define TEGRA_XUSB_PADCTL_UTMI_P1 5
+#define TEGRA_XUSB_PADCTL_UTMI_P2 6
+#define TEGRA_XUSB_PADCTL_HSIC_P0 7
+#define TEGRA_XUSB_PADCTL_HSIC_P1 8
 
 #endif /* _DT_BINDINGS_PINCTRL_TEGRA_XUSB_H */
-- 
2.0.0.526.g5318336

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

* [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
@ 2014-06-18  6:16   ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

Add new bindings used for USB support by the Tegra XUSB pad controller.
This includes additional PHY types, USB-specific pinconfig properties, etc.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 .../pinctrl/nvidia,tegra124-xusb-padctl.txt        | 53 ++++++++++++++++++++--
 include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h   |  7 +++
 2 files changed, 56 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
index 2f9c0bd..6181019 100644
--- a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
@@ -21,6 +21,12 @@ Required properties:
   - padctl
 - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
   See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
+- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
+
+Optional properties:
+-------------------
+- vbus-otg-{0,1,2}-supply: VBUS regulator for the corresponding UTMI pad.
+- vddio-hsic-supply: VDDIO regulator for the HSIC pads.
 
 Lane muxing:
 ------------
@@ -50,6 +56,16 @@ Optional properties:
   pin or group should be assigned to. Valid values for function names are
   listed below.
 - nvidia,iddq: Enables IDDQ mode of the lane. (0: no, 1: yes)
+- nvidia,usb3-port-num: USB3 port (0 or 1) to which the lane is mapped.
+- nvidia,usb2-port-num: USB2 port (0, 1, or 2) to which the lane is mapped.
+- nvidia,hsic-strobe-trim: HSIC strobe trimmer value.
+- nvidia,hsic-rx-strobe-trim: HSIC RX strobe trimmer value.
+- nvidia,hsic-rx-data-trim: HSIC RX data trimmer value.
+- nvidia,hsic-tx-rtune-n: HSIC TX RTUNEN value.
+- nvidia,hsic-tx-rtune-p: HSIC TX RTUNEP value.
+- nvidia,hsic-tx-slew-n: HSIC TX SLEWN value.
+- nvidia,hsic-tx-slew-p: HSIC TX SLEWP value.
+- nvidia,hsic-auto-term: Enables HSIC AUTO_TERM. (0: no, 1: yes)
 
 Note that not all of these properties are valid for all lanes. Lanes can be
 divided into three groups:
@@ -58,18 +74,25 @@ divided into three groups:
 
     Valid functions for this group are: "snps", "xusb", "uart", "rsvd".
 
-    The nvidia,iddq property does not apply to this group.
+    The nvidia,iddq, nvidia,usb3-port-num, nvidia,usb2-port-num, and
+    nvidia,hsic-* properties do not apply to this group.
 
   - ulpi-0, hsic-0, hsic-1:
 
     Valid functions for this group are: "snps", "xusb".
 
-    The nvidia,iddq property does not apply to this group.
+    The nvidia,iddq, nvidia,usb3-port-num, and nvidia,usb2-port-num
+    properties do not apply to this group.  The nvidia,hsic-*  properties
+    apply only to the pins hsic-{0,1} when the function is xusb.
 
   - pcie-0, pcie-1, pcie-2, pcie-3, pcie-4, sata-0:
 
     Valid functions for this group are: "pcie", "usb3", "sata", "rsvd".
 
+    The nvidia,usb3-port-num and nvidia,usb2-port-num properties only
+    apply and are required when the function is usb3.  The nvidia,hsic-*
+    properties do not apply to this group.
+
 
 Example:
 ========
@@ -83,6 +106,8 @@ SoC file extract:
 		resets = <&tegra_car 142>;
 		reset-names = "padctl";
 
+		nvidia,xusb-mbox = <&mbox>;
+
 		#phy-cells = <1>;
 	};
 
@@ -100,15 +125,35 @@ Board file extract:
 
 	...
 
+	usb at 0,70090000 {
+		...
+
+		phys = <&padctl 5>, <&padctl 6>, <&padctl 7>;
+		phy-names = "utmi-1", "utmi-2", "usb3-0";
+
+		...
+	}
+
+	...
+
 	padctl: padctl at 0,7009f000 {
 		pinctrl-0 = <&padctl_default>;
 		pinctrl-names = "default";
 
+		vbus-otg-2-supply = <&vdd_usb3_vbus>;
+
 		padctl_default: pinmux {
-			usb3 {
-				nvidia,lanes = "pcie-0", "pcie-1";
+			otg {
+				nvidia,lanes = "otg-1", "otg-2";
+				nvidia,function = "xusb";
+			};
+
+			usb3p0 {
+				nvidia,lanes = "pcie-0";
 				nvidia,function = "usb3";
 				nvidia,iddq = <0>;
+				nvidia,usb3-port-num = <0>;
+				nvidia,usb2-port-num = <2>;
 			};
 
 			pcie {
diff --git a/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h b/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h
index 914d56d..c83a4d4 100644
--- a/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h
+++ b/include/dt-bindings/pinctrl/pinctrl-tegra-xusb.h
@@ -3,5 +3,12 @@
 
 #define TEGRA_XUSB_PADCTL_PCIE 0
 #define TEGRA_XUSB_PADCTL_SATA 1
+#define TEGRA_XUSB_PADCTL_USB3_P0 2
+#define TEGRA_XUSB_PADCTL_USB3_P1 3
+#define TEGRA_XUSB_PADCTL_UTMI_P0 4
+#define TEGRA_XUSB_PADCTL_UTMI_P1 5
+#define TEGRA_XUSB_PADCTL_UTMI_P2 6
+#define TEGRA_XUSB_PADCTL_HSIC_P0 7
+#define TEGRA_XUSB_PADCTL_HSIC_P1 8
 
 #endif /* _DT_BINDINGS_PINCTRL_TEGRA_XUSB_H */
-- 
2.0.0.526.g5318336

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

* [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
  2014-06-18  6:16 ` Andrew Bresticker
  (?)
@ 2014-06-18  6:16     ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

In addition to the PCIe and SATA PHYs, the XUSB pad controller also
supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
PCIe or SATA lane and is mapped to one of the three UTMI ports.

Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 drivers/pinctrl/pinctrl-tegra-xusb.c | 1106 +++++++++++++++++++++++++++++++++-
 1 file changed, 1089 insertions(+), 17 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
index 2405646..67056ab 100644
--- a/drivers/pinctrl/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/pinctrl-tegra-xusb.c
@@ -14,22 +14,55 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/phy/phy.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/reset.h>
+#include <linux/tegra-soc.h>
+#include <linux/tegra-xusb-mbox.h>
 
 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
 
 #include "core.h"
 #include "pinctrl-utils.h"
 
+#define TEGRA_XUSB_PADCTL_USB3_PORTS 2
+#define TEGRA_XUSB_PADCTL_UTMI_PORTS 3
+#define TEGRA_XUSB_PADCTL_HSIC_PORTS 2
+
+#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? 15 : 0)
+#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f
+#define FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT 13
+#define FUSE_SKU_CALIB_HS_IREF_CAP_MASK 0x3
+#define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT 11
+#define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK 0x3
+#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7
+#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf
+
+#define XUSB_PADCTL_USB2_PORT_CAP 0x008
+#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(x) ((x) * 4)
+#define XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK 0x3
+#define XUSB_PADCTL_USB2_PORT_CAP_DISABLED 0x0
+#define XUSB_PADCTL_USB2_PORT_CAP_HOST 0x1
+#define XUSB_PADCTL_USB2_PORT_CAP_DEVICE 0x2
+#define XUSB_PADCTL_USB2_PORT_CAP_OTG 0x3
+
+#define XUSB_PADCTL_SS_PORT_MAP 0x014
+#define XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(x) ((x) * 4)
+#define XUSB_PADCTL_SS_PORT_MAP_PORT_MASK 0x7
+
 #define XUSB_PADCTL_ELPG_PROGRAM 0x01c
 #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
 #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
 #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
+#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4))
+#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(x) \
+							(1 << (17 + (x) * 4))
+#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4))
 
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
@@ -41,6 +74,104 @@
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
 
+#define XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(x) (0x058 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT 24
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK 0xff
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT 16
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK 0x3f
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT 8
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK 0x3f
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT 8
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK 0xffff
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT 4
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK 0x7
+
+#define XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(x) (0x068 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT 24
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK 0x1f
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT 16
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK 0x7f
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(x) ((x) < 2 ? 0x078 + (x) * 4 : \
+					       0x0f8 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT 28
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK 0x3
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(x) ((x) < 2 ? 0x090 + (x) * 4 : \
+					       0x11c + (x) * 4)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN (1 << 8)
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(x) ((x) < 2 ? 0x098 + (x) * 4 : \
+					       0x128 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT 24
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK 0x3f
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK 0x1f
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK 0x7f
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT 16
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK 0xff
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z 0x21
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP 0x32
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP 0x33
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z 0x48
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z 0xa1
+
+#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x0a0 + (x) * 4)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 21)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 20)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 19)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT 14
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK 0x3
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT 6
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK 0x3f
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f
+
+#define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x0ac + (x) * 4)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT 9
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK 0x3
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0x7
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0)
+
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0b8
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 12)
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 2
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x3
+
+#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x0c0 + (x) * 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT 12
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT 8
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT 4
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT 0
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK 0x7
+
+#define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x0c8 + (x) * 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE (1 << 10)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA (1 << 9)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE (1 << 8)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA (1 << 7)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI (1 << 5)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX (1 << 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX (1 << 3)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX (1 << 2)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN (1 << 0)
+
+#define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x0d0 + (x) * 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 4
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0x7
+
+#define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x0e0
+#define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK 0x1f
+
 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
@@ -52,6 +183,12 @@
 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
 
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14c
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15c
+
 struct tegra_xusb_padctl_function {
 	const char *name;
 	const char * const *groups;
@@ -72,6 +209,16 @@ struct tegra_xusb_padctl_soc {
 
 	const struct tegra_xusb_padctl_lane *lanes;
 	unsigned int num_lanes;
+
+	u32 rx_wander;
+	u32 rx_eq;
+	u32 cdr_cntl;
+	u32 dfe_cntl;
+	u32 hs_slew;
+	u32 ls_rslew[TEGRA_XUSB_PADCTL_UTMI_PORTS];
+	u32 hs_discon_level;
+	u32 spare_in;
+	int hsic_port_offset;
 };
 
 struct tegra_xusb_padctl_lane {
@@ -86,6 +233,22 @@ struct tegra_xusb_padctl_lane {
 	unsigned int num_funcs;
 };
 
+struct tegra_xusb_fuse_calibration {
+	u32 hs_curr_level[TEGRA_XUSB_PADCTL_UTMI_PORTS];
+	u32 hs_iref_cap;
+	u32 hs_term_range_adj;
+	u32 hs_squelch_level;
+};
+
+struct tegra_xusb_usb3_port {
+	unsigned int lane;
+	bool context_saved;
+	u32 tap1_val;
+	u32 amp_val;
+	u32 ctle_z_val;
+	u32 ctle_g_val;
+};
+
 struct tegra_xusb_padctl {
 	struct device *dev;
 	void __iomem *regs;
@@ -93,13 +256,22 @@ struct tegra_xusb_padctl {
 	struct reset_control *rst;
 
 	const struct tegra_xusb_padctl_soc *soc;
+	struct tegra_xusb_fuse_calibration calib;
 	struct pinctrl_dev *pinctrl;
 	struct pinctrl_desc desc;
 
 	struct phy_provider *provider;
-	struct phy *phys[2];
+	struct phy *phys[9];
 
 	unsigned int enable;
+
+	struct tegra_xusb_mbox *mbox;
+	struct notifier_block mbox_nb;
+
+	struct tegra_xusb_usb3_port usb3_ports[TEGRA_XUSB_PADCTL_USB3_PORTS];
+	unsigned int utmi_enable;
+	struct regulator *vbus[TEGRA_XUSB_PADCTL_UTMI_PORTS];
+	struct regulator *vddio_hsic;
 };
 
 static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value,
@@ -114,6 +286,42 @@ static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
 	return readl(padctl->regs + offset);
 }
 
+#define PIN_OTG_0   0
+#define PIN_OTG_1   1
+#define PIN_OTG_2   2
+#define PIN_ULPI_0  3
+#define PIN_HSIC_0  4
+#define PIN_HSIC_1  5
+#define PIN_PCIE_0  6
+#define PIN_PCIE_1  7
+#define PIN_PCIE_2  8
+#define PIN_PCIE_3  9
+#define PIN_PCIE_4 10
+#define PIN_SATA_0 11
+
+static inline bool is_hsic_lane(unsigned int lane)
+{
+	return lane >= PIN_HSIC_0 && lane <= PIN_HSIC_1;
+}
+
+static inline bool is_pcie_sata_lane(unsigned int lane)
+{
+	return lane >= PIN_PCIE_0 && lane <= PIN_SATA_0;
+}
+
+static int lane_to_usb3_port(struct tegra_xusb_padctl *padctl,
+			     unsigned int lane)
+{
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_USB3_PORTS; i++) {
+		if (padctl->usb3_ports[i].lane == lane)
+			return i;
+	}
+
+	return -1;
+}
+
 static int tegra_xusb_padctl_get_groups_count(struct pinctrl_dev *pinctrl)
 {
 	struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
@@ -131,6 +339,16 @@ static const char *tegra_xusb_padctl_get_group_name(struct pinctrl_dev *pinctrl,
 
 enum tegra_xusb_padctl_param {
 	TEGRA_XUSB_PADCTL_IDDQ,
+	TEGRA_XUSB_PADCTL_USB3_PORT_NUM,
+	TEGRA_XUSB_PADCTL_USB2_PORT_NUM,
+	TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM,
+	TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM,
+	TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP,
+	TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM,
 };
 
 static const struct tegra_xusb_padctl_property {
@@ -138,6 +356,16 @@ static const struct tegra_xusb_padctl_property {
 	enum tegra_xusb_padctl_param param;
 } properties[] = {
 	{ "nvidia,iddq", TEGRA_XUSB_PADCTL_IDDQ },
+	{ "nvidia,usb3-port-num", TEGRA_XUSB_PADCTL_USB3_PORT_NUM },
+	{ "nvidia,usb2-port-num", TEGRA_XUSB_PADCTL_USB2_PORT_NUM },
+	{ "nvidia,hsic-strobe-trim", TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM },
+	{ "nvidia,hsic-rx-strobe-trim", TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM },
+	{ "nvidia,hsic-rx-data-trim", TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM },
+	{ "nvidia,hsic-tx-rtune-n", TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN },
+	{ "nvidia,hsic-tx-rtune-p", TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP },
+	{ "nvidia,hsic-tx-rslew-n", TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN },
+	{ "nvidia,hsic-tx-rslew-p", TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP },
+	{ "nvidia,hsic-auto-term", TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM },
 };
 
 #define TEGRA_XUSB_PADCTL_PACK(param, value) ((param) << 16 | (value))
@@ -321,6 +549,7 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 	struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 	const struct tegra_xusb_padctl_lane *lane;
 	enum tegra_xusb_padctl_param param;
+	int port;
 	u32 value;
 
 	param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(*config);
@@ -330,7 +559,125 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 	case TEGRA_XUSB_PADCTL_IDDQ:
 		value = padctl_readl(padctl, lane->offset);
 		value = (value >> lane->iddq) & 0x1;
-		*config = TEGRA_XUSB_PADCTL_PACK(param, value);
+		break;
+
+	case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
+		value = lane_to_usb3_port(padctl, group);
+		if (value < 0) {
+			dev_err(padctl->dev,
+				"Lane %d not mapped to USB3 port\n", group);
+			return -EINVAL;
+		}
+		break;
+
+	case TEGRA_XUSB_PADCTL_USB2_PORT_NUM:
+		port = lane_to_usb3_port(padctl, group);
+		if (port < 0) {
+			dev_err(padctl->dev,
+				"Lane %d not mapped to USB2 port\n", group);
+			return -EINVAL;
+		}
+
+		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP) >>
+			XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port);
+		value &= XUSB_PADCTL_SS_PORT_MAP_PORT_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		value = padctl_readl(padctl,
+				     XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
+		value &= XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+		if (value & XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN)
+			value = 1;
+		else
+			value = 0;
 		break;
 
 	default:
@@ -339,6 +686,7 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 		return -ENOTSUPP;
 	}
 
+	*config = TEGRA_XUSB_PADCTL_PACK(param, value);
 	return 0;
 }
 
@@ -351,7 +699,7 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
 	const struct tegra_xusb_padctl_lane *lane;
 	enum tegra_xusb_padctl_param param;
 	unsigned long value;
-	unsigned int i;
+	unsigned int i, port;
 	u32 regval;
 
 	lane = &padctl->soc->lanes[group];
@@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
 			padctl_writel(padctl, regval, lane->offset);
 			break;
 
+		case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
+			if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
+				dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
+					value);
+				return -EINVAL;
+			}
+			if (!is_pcie_sata_lane(group)) {
+				dev_err(padctl->dev,
+					"USB3 port not applicable for pin %d\n",
+					group);
+				return -EINVAL;
+			}
+			padctl->usb3_ports[value].lane = group;
+			break;
+
+		case TEGRA_XUSB_PADCTL_USB2_PORT_NUM:
+			if (value >= TEGRA_XUSB_PADCTL_UTMI_PORTS) {
+				dev_err(padctl->dev, "Invalid USB2 port: %lu\n",
+					value);
+				return -EINVAL;
+			}
+			if (!is_pcie_sata_lane(group)) {
+				dev_err(padctl->dev,
+					"USB2 port not applicable for pin %d\n",
+					group);
+				return -EINVAL;
+			}
+			port = lane_to_usb3_port(padctl, group);
+			if (port < 0) {
+				dev_err(padctl->dev,
+					"Pin %d not mapped to USB3 port\n",
+					group);
+				break;
+			}
+
+			regval = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
+			regval &= ~(XUSB_PADCTL_SS_PORT_MAP_PORT_MASK <<
+				    XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port));
+			regval |= value <<
+				XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port);
+			padctl_writel(padctl, regval, XUSB_PADCTL_SS_PORT_MAP);
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			value &= XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK;
+			padctl_writel(padctl, value,
+				      XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL1(port));
+			if (!value)
+				regval &= ~XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN;
+			else
+				regval |= XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL1(port));
+			break;
+
 		default:
 			dev_err(padctl->dev,
 				"invalid configuration parameter: %04x\n",
@@ -595,6 +1130,459 @@ static const struct phy_ops sata_phy_ops = {
 	.owner = THIS_MODULE,
 };
 
+static int usb3_phy_to_port(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_USB3_PORTS; i++) {
+		if (phy == padctl->phys[TEGRA_XUSB_PADCTL_USB3_P0 + i])
+			break;
+	}
+	BUG_ON(i == TEGRA_XUSB_PADCTL_USB3_PORTS);
+
+	return i;
+}
+
+static int usb3_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = usb3_phy_to_port(phy);
+	int lane = padctl->usb3_ports[port].lane;
+	u32 value, offset;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
+	value |= (padctl->soc->rx_wander <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
+		 (padctl->soc->cdr_cntl <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT) |
+		 (padctl->soc->rx_eq <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT);
+	if (padctl->usb3_ports[port].context_saved) {
+		value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+			   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT));
+		value |= (padctl->usb3_ports[port].ctle_g_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+			 (padctl->usb3_ports[port].ctle_z_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT);
+	}
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+
+	value = padctl->soc->dfe_cntl;
+	if (padctl->usb3_ports[port].context_saved) {
+		value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+			   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT));
+		value |= (padctl->usb3_ports[port].tap1_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+			 (padctl->usb3_ports[port].amp_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT);
+	}
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port));
+
+	offset = (lane == PIN_SATA_0) ? XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 :
+		XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(lane - PIN_PCIE_0);
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT);
+	value |= padctl->soc->spare_in <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	offset = (lane == PIN_SATA_0) ? XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 :
+		XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(lane - PIN_PCIE_0);
+	value = padctl_readl(padctl, offset);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	usleep_range(100, 200);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static int usb3_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = usb3_phy_to_port(phy);
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	usleep_range(100, 200);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	usleep_range(250, 350);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static void usb3_phy_save_context(struct tegra_xusb_padctl *padctl, int port)
+{
+	int lane = padctl->usb3_ports[port].lane;
+	u32 value, offset;
+
+	padctl->usb3_ports[port].context_saved = true;
+
+	offset = (lane == PIN_SATA_0) ? XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 :
+		XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(lane - PIN_PCIE_0);
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].tap1_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK;
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].amp_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port));
+	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT));
+	value |= (padctl->usb3_ports[port].tap1_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+		 (padctl->usb3_ports[port].amp_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port));
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].ctle_g_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK;
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].ctle_z_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT));
+	value |= (padctl->usb3_ports[port].ctle_g_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+		 (padctl->usb3_ports[port].ctle_z_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+}
+
+static const struct phy_ops usb3_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = usb3_phy_power_on,
+	.power_off = usb3_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int utmi_phy_to_port(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_UTMI_PORTS; i++) {
+		if (phy == padctl->phys[TEGRA_XUSB_PADCTL_UTMI_P0 + i])
+			break;
+	}
+	BUG_ON(i == TEGRA_XUSB_PADCTL_UTMI_PORTS);
+
+	return i;
+}
+
+static int utmi_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = utmi_phy_to_port(phy);
+	int ret;
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK <<
+		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
+		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK <<
+		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT));
+	value |= (padctl->calib.hs_squelch_level <<
+		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
+		 (padctl->soc->hs_discon_level <<
+		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
+	value &= ~(XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK <<
+		   XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(port));
+	value |= XUSB_PADCTL_USB2_PORT_CAP_HOST <<
+		XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(port));
+	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) |
+		   (XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT) |
+		   (XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT) |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI);
+	value |= padctl->calib.hs_curr_level[port] <<
+		XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT;
+	value |= padctl->soc->hs_slew <<
+		XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT;
+	value |= padctl->soc->ls_rslew[port] <<
+		XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(port));
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
+	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
+		   (XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT) |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP);
+	value |= (padctl->calib.hs_term_range_adj <<
+		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
+		 (padctl->calib.hs_iref_cap <<
+		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
+
+	ret = regulator_enable(padctl->vbus[port]);
+	if (ret)
+		return ret;
+
+	mutex_lock(&padctl->lock);
+
+	if (padctl->utmi_enable++ > 0)
+		goto out;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+
+out:
+	mutex_unlock(&padctl->lock);
+	return 0;
+}
+
+static int utmi_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = utmi_phy_to_port(phy);
+	u32 value;
+
+	regulator_disable(padctl->vbus[port]);
+
+	mutex_lock(&padctl->lock);
+
+	if (WARN_ON(padctl->utmi_enable == 0))
+		goto out;
+
+	if (--padctl->utmi_enable > 0)
+		goto out;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+
+out:
+	mutex_unlock(&padctl->lock);
+	return 0;
+}
+
+static const struct phy_ops utmi_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = utmi_phy_power_on,
+	.power_off = utmi_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int hsic_phy_to_port(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_HSIC_PORTS; i++) {
+		if (phy == padctl->phys[TEGRA_XUSB_PADCTL_HSIC_P0 + i])
+			break;
+	}
+	BUG_ON(i == TEGRA_XUSB_PADCTL_HSIC_PORTS);
+
+	return i;
+}
+
+static int hsic_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = hsic_phy_to_port(phy);
+	int ret;
+	u32 value;
+
+	ret = regulator_enable(padctl->vddio_hsic);
+	if (ret)
+		return ret;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX);
+	value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE;
+	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+
+	return 0;
+}
+
+static int hsic_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = hsic_phy_to_port(phy);
+	u32 value;
+
+	regulator_disable(padctl->vddio_hsic);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+	value |= XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX;
+	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+
+	return 0;
+}
+
+static void hsic_phy_set_idle(struct tegra_xusb_padctl *padctl, int port,
+			      bool set)
+{
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+	if (set)
+		value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
+			 XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE;
+	else
+		value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
+			   XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE);
+	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+}
+
+static const struct phy_ops hsic_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = hsic_phy_power_on,
+	.power_off = hsic_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int tegra_xusb_phy_mbox_notifier(struct notifier_block *nb,
+					unsigned long event, void *p)
+{
+	struct tegra_xusb_padctl *padctl = container_of(nb,
+						struct tegra_xusb_padctl,
+						mbox_nb);
+	struct tegra_xusb_mbox_msg *msg = (struct tegra_xusb_mbox_msg *)p;
+	u32 ports;
+	int i;
+
+	switch (event) {
+	case MBOX_CMD_SAVE_DFE_CTLE_CTX:
+		msg->data_out = msg->data_in;
+		if (msg->data_in > TEGRA_XUSB_PADCTL_USB3_PORTS) {
+			msg->cmd_out = MBOX_CMD_NAK;
+		} else {
+			usb3_phy_save_context(padctl, msg->data_in);
+			msg->cmd_out = MBOX_CMD_ACK;
+		}
+		return NOTIFY_STOP;
+	case MBOX_CMD_START_HSIC_IDLE:
+	case MBOX_CMD_STOP_HSIC_IDLE:
+		ports = msg->data_in >> (padctl->soc->hsic_port_offset + 1);
+		msg->data_out = msg->data_in;
+		for (i = 0; i < TEGRA_XUSB_PADCTL_HSIC_PORTS; i++) {
+			if (!(ports & BIT(i)))
+				continue;
+			if (event == MBOX_CMD_START_HSIC_IDLE)
+				hsic_phy_set_idle(padctl, i, true);
+			else
+				hsic_phy_set_idle(padctl, i, false);
+		}
+		msg->cmd_out = MBOX_CMD_ACK;
+		return NOTIFY_STOP;
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
 static struct phy *tegra_xusb_padctl_xlate(struct device *dev,
 					   struct of_phandle_args *args)
 {
@@ -610,19 +1598,6 @@ static struct phy *tegra_xusb_padctl_xlate(struct device *dev,
 	return padctl->phys[index];
 }
 
-#define PIN_OTG_0   0
-#define PIN_OTG_1   1
-#define PIN_OTG_2   2
-#define PIN_ULPI_0  3
-#define PIN_HSIC_0  4
-#define PIN_HSIC_1  5
-#define PIN_PCIE_0  6
-#define PIN_PCIE_1  7
-#define PIN_PCIE_2  8
-#define PIN_PCIE_3  9
-#define PIN_PCIE_4 10
-#define PIN_SATA_0 11
-
 static const struct pinctrl_pin_desc tegra124_pins[] = {
 	PINCTRL_PIN(PIN_OTG_0,  "otg-0"),
 	PINCTRL_PIN(PIN_OTG_1,  "otg-1"),
@@ -780,6 +1755,15 @@ static const struct tegra_xusb_padctl_soc tegra124_soc = {
 	.functions = tegra124_functions,
 	.num_lanes = ARRAY_SIZE(tegra124_lanes),
 	.lanes = tegra124_lanes,
+	.rx_wander = 0xf,
+	.rx_eq = 0xf070,
+	.cdr_cntl = 0x24,
+	.dfe_cntl = 0x002008ee,
+	.hs_slew = 0xe,
+	.ls_rslew = {0x3, 0x0, 0x0},
+	.hs_discon_level = 0x5,
+	.spare_in = 0x1,
+	.hsic_port_offset = 6,
 };
 
 static const struct of_device_id tegra_xusb_padctl_of_match[] = {
@@ -788,13 +1772,40 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match);
 
+static int tegra_xusb_read_fuse_calibration(struct tegra_xusb_padctl *padctl)
+{
+	int i, ret;
+	u32 value;
+
+	ret = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_UTMI_PORTS; i++) {
+		padctl->calib.hs_curr_level[i] =
+			(value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) &
+			FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK;
+	}
+	padctl->calib.hs_iref_cap =
+		(value >> FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT) &
+		FUSE_SKU_CALIB_HS_IREF_CAP_MASK;
+	padctl->calib.hs_term_range_adj =
+		(value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) &
+		FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK;
+	padctl->calib.hs_squelch_level =
+		(value >> FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT) &
+		FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK;
+
+	return 0;
+}
+
 static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 {
 	struct tegra_xusb_padctl *padctl;
 	const struct of_device_id *match;
 	struct resource *res;
 	struct phy *phy;
-	int err;
+	int err, i;
 
 	padctl = devm_kzalloc(&pdev->dev, sizeof(*padctl), GFP_KERNEL);
 	if (!padctl)
@@ -812,6 +1823,10 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 	if (IS_ERR(padctl->regs))
 		return PTR_ERR(padctl->regs);
 
+	err = tegra_xusb_read_fuse_calibration(padctl);
+	if (err < 0)
+		return err;
+
 	padctl->rst = devm_reset_control_get(&pdev->dev, NULL);
 	if (IS_ERR(padctl->rst))
 		return PTR_ERR(padctl->rst);
@@ -852,6 +1867,54 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 	padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy;
 	phy_set_drvdata(phy, padctl);
 
+	for (i = 0; i < TEGRA_XUSB_PADCTL_USB3_PORTS; i++) {
+		phy = devm_phy_create(&pdev->dev, &usb3_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			err = PTR_ERR(phy);
+			goto unregister;
+		}
+
+		padctl->phys[TEGRA_XUSB_PADCTL_USB3_P0 + i] = phy;
+		phy_set_drvdata(phy, padctl);
+	}
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_UTMI_PORTS; i++) {
+		char reg_name[sizeof("vbus-otg-N")];
+
+		sprintf(reg_name, "vbus-otg-%d", i);
+		padctl->vbus[i] = devm_regulator_get(&pdev->dev, reg_name);
+		if (IS_ERR(padctl->vbus[i])) {
+			err = PTR_ERR(padctl->vbus[i]);
+			goto unregister;
+		}
+
+		phy = devm_phy_create(&pdev->dev, &utmi_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			err = PTR_ERR(phy);
+			goto unregister;
+		}
+
+		padctl->phys[TEGRA_XUSB_PADCTL_UTMI_P0 + i] = phy;
+		phy_set_drvdata(phy, padctl);
+	}
+
+	padctl->vddio_hsic = devm_regulator_get(&pdev->dev, "vddio-hsic");
+	if (IS_ERR(padctl->vddio_hsic)) {
+		err = PTR_ERR(padctl->vddio_hsic);
+		goto unregister;
+	}
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_HSIC_PORTS; i++) {
+		phy = devm_phy_create(&pdev->dev, &hsic_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			err = PTR_ERR(phy);
+			goto unregister;
+		}
+
+		padctl->phys[TEGRA_XUSB_PADCTL_HSIC_P0 + i] = phy;
+		phy_set_drvdata(phy, padctl);
+	}
+
 	padctl->provider = devm_of_phy_provider_register(&pdev->dev,
 							 tegra_xusb_padctl_xlate);
 	if (err < 0) {
@@ -859,6 +1922,13 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 		goto unregister;
 	}
 
+	padctl->mbox = tegra_xusb_mbox_lookup_by_phandle(pdev->dev.of_node,
+							 "nvidia,xusb-mbox");
+	if (IS_ERR(padctl->mbox))
+		return PTR_ERR(padctl->mbox);
+	padctl->mbox_nb.notifier_call = tegra_xusb_phy_mbox_notifier;
+	tegra_xusb_mbox_register_notifier(padctl->mbox, &padctl->mbox_nb);
+
 	return 0;
 
 unregister:
@@ -873,6 +1943,8 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev)
 	struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev);
 	int err;
 
+	tegra_xusb_mbox_unregister_notifier(padctl->mbox, &padctl->mbox_nb);
+
 	pinctrl_unregister(padctl->pinctrl);
 
 	err = reset_control_assert(padctl->rst);
-- 
2.0.0.526.g5318336

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

* [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-18  6:16     ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

In addition to the PCIe and SATA PHYs, the XUSB pad controller also
supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
PCIe or SATA lane and is mapped to one of the three UTMI ports.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/pinctrl/pinctrl-tegra-xusb.c | 1106 +++++++++++++++++++++++++++++++++-
 1 file changed, 1089 insertions(+), 17 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
index 2405646..67056ab 100644
--- a/drivers/pinctrl/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/pinctrl-tegra-xusb.c
@@ -14,22 +14,55 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/phy/phy.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/reset.h>
+#include <linux/tegra-soc.h>
+#include <linux/tegra-xusb-mbox.h>
 
 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
 
 #include "core.h"
 #include "pinctrl-utils.h"
 
+#define TEGRA_XUSB_PADCTL_USB3_PORTS 2
+#define TEGRA_XUSB_PADCTL_UTMI_PORTS 3
+#define TEGRA_XUSB_PADCTL_HSIC_PORTS 2
+
+#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? 15 : 0)
+#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f
+#define FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT 13
+#define FUSE_SKU_CALIB_HS_IREF_CAP_MASK 0x3
+#define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT 11
+#define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK 0x3
+#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7
+#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf
+
+#define XUSB_PADCTL_USB2_PORT_CAP 0x008
+#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(x) ((x) * 4)
+#define XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK 0x3
+#define XUSB_PADCTL_USB2_PORT_CAP_DISABLED 0x0
+#define XUSB_PADCTL_USB2_PORT_CAP_HOST 0x1
+#define XUSB_PADCTL_USB2_PORT_CAP_DEVICE 0x2
+#define XUSB_PADCTL_USB2_PORT_CAP_OTG 0x3
+
+#define XUSB_PADCTL_SS_PORT_MAP 0x014
+#define XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(x) ((x) * 4)
+#define XUSB_PADCTL_SS_PORT_MAP_PORT_MASK 0x7
+
 #define XUSB_PADCTL_ELPG_PROGRAM 0x01c
 #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
 #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
 #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
+#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4))
+#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(x) \
+							(1 << (17 + (x) * 4))
+#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4))
 
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
@@ -41,6 +74,104 @@
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
 
+#define XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(x) (0x058 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT 24
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK 0xff
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT 16
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK 0x3f
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT 8
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK 0x3f
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT 8
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK 0xffff
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT 4
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK 0x7
+
+#define XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(x) (0x068 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT 24
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK 0x1f
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT 16
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK 0x7f
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(x) ((x) < 2 ? 0x078 + (x) * 4 : \
+					       0x0f8 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT 28
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK 0x3
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(x) ((x) < 2 ? 0x090 + (x) * 4 : \
+					       0x11c + (x) * 4)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN (1 << 8)
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(x) ((x) < 2 ? 0x098 + (x) * 4 : \
+					       0x128 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT 24
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK 0x3f
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK 0x1f
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK 0x7f
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT 16
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK 0xff
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z 0x21
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP 0x32
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP 0x33
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z 0x48
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z 0xa1
+
+#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x0a0 + (x) * 4)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 21)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 20)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 19)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT 14
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK 0x3
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT 6
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK 0x3f
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f
+
+#define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x0ac + (x) * 4)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT 9
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK 0x3
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0x7
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0)
+
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0b8
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 12)
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 2
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x3
+
+#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x0c0 + (x) * 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT 12
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT 8
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT 4
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT 0
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK 0x7
+
+#define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x0c8 + (x) * 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE (1 << 10)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA (1 << 9)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE (1 << 8)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA (1 << 7)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI (1 << 5)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX (1 << 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX (1 << 3)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX (1 << 2)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN (1 << 0)
+
+#define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x0d0 + (x) * 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 4
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0x7
+
+#define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x0e0
+#define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK 0x1f
+
 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
@@ -52,6 +183,12 @@
 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
 
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14c
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15c
+
 struct tegra_xusb_padctl_function {
 	const char *name;
 	const char * const *groups;
@@ -72,6 +209,16 @@ struct tegra_xusb_padctl_soc {
 
 	const struct tegra_xusb_padctl_lane *lanes;
 	unsigned int num_lanes;
+
+	u32 rx_wander;
+	u32 rx_eq;
+	u32 cdr_cntl;
+	u32 dfe_cntl;
+	u32 hs_slew;
+	u32 ls_rslew[TEGRA_XUSB_PADCTL_UTMI_PORTS];
+	u32 hs_discon_level;
+	u32 spare_in;
+	int hsic_port_offset;
 };
 
 struct tegra_xusb_padctl_lane {
@@ -86,6 +233,22 @@ struct tegra_xusb_padctl_lane {
 	unsigned int num_funcs;
 };
 
+struct tegra_xusb_fuse_calibration {
+	u32 hs_curr_level[TEGRA_XUSB_PADCTL_UTMI_PORTS];
+	u32 hs_iref_cap;
+	u32 hs_term_range_adj;
+	u32 hs_squelch_level;
+};
+
+struct tegra_xusb_usb3_port {
+	unsigned int lane;
+	bool context_saved;
+	u32 tap1_val;
+	u32 amp_val;
+	u32 ctle_z_val;
+	u32 ctle_g_val;
+};
+
 struct tegra_xusb_padctl {
 	struct device *dev;
 	void __iomem *regs;
@@ -93,13 +256,22 @@ struct tegra_xusb_padctl {
 	struct reset_control *rst;
 
 	const struct tegra_xusb_padctl_soc *soc;
+	struct tegra_xusb_fuse_calibration calib;
 	struct pinctrl_dev *pinctrl;
 	struct pinctrl_desc desc;
 
 	struct phy_provider *provider;
-	struct phy *phys[2];
+	struct phy *phys[9];
 
 	unsigned int enable;
+
+	struct tegra_xusb_mbox *mbox;
+	struct notifier_block mbox_nb;
+
+	struct tegra_xusb_usb3_port usb3_ports[TEGRA_XUSB_PADCTL_USB3_PORTS];
+	unsigned int utmi_enable;
+	struct regulator *vbus[TEGRA_XUSB_PADCTL_UTMI_PORTS];
+	struct regulator *vddio_hsic;
 };
 
 static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value,
@@ -114,6 +286,42 @@ static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
 	return readl(padctl->regs + offset);
 }
 
+#define PIN_OTG_0   0
+#define PIN_OTG_1   1
+#define PIN_OTG_2   2
+#define PIN_ULPI_0  3
+#define PIN_HSIC_0  4
+#define PIN_HSIC_1  5
+#define PIN_PCIE_0  6
+#define PIN_PCIE_1  7
+#define PIN_PCIE_2  8
+#define PIN_PCIE_3  9
+#define PIN_PCIE_4 10
+#define PIN_SATA_0 11
+
+static inline bool is_hsic_lane(unsigned int lane)
+{
+	return lane >= PIN_HSIC_0 && lane <= PIN_HSIC_1;
+}
+
+static inline bool is_pcie_sata_lane(unsigned int lane)
+{
+	return lane >= PIN_PCIE_0 && lane <= PIN_SATA_0;
+}
+
+static int lane_to_usb3_port(struct tegra_xusb_padctl *padctl,
+			     unsigned int lane)
+{
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_USB3_PORTS; i++) {
+		if (padctl->usb3_ports[i].lane == lane)
+			return i;
+	}
+
+	return -1;
+}
+
 static int tegra_xusb_padctl_get_groups_count(struct pinctrl_dev *pinctrl)
 {
 	struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
@@ -131,6 +339,16 @@ static const char *tegra_xusb_padctl_get_group_name(struct pinctrl_dev *pinctrl,
 
 enum tegra_xusb_padctl_param {
 	TEGRA_XUSB_PADCTL_IDDQ,
+	TEGRA_XUSB_PADCTL_USB3_PORT_NUM,
+	TEGRA_XUSB_PADCTL_USB2_PORT_NUM,
+	TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM,
+	TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM,
+	TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP,
+	TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM,
 };
 
 static const struct tegra_xusb_padctl_property {
@@ -138,6 +356,16 @@ static const struct tegra_xusb_padctl_property {
 	enum tegra_xusb_padctl_param param;
 } properties[] = {
 	{ "nvidia,iddq", TEGRA_XUSB_PADCTL_IDDQ },
+	{ "nvidia,usb3-port-num", TEGRA_XUSB_PADCTL_USB3_PORT_NUM },
+	{ "nvidia,usb2-port-num", TEGRA_XUSB_PADCTL_USB2_PORT_NUM },
+	{ "nvidia,hsic-strobe-trim", TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM },
+	{ "nvidia,hsic-rx-strobe-trim", TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM },
+	{ "nvidia,hsic-rx-data-trim", TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM },
+	{ "nvidia,hsic-tx-rtune-n", TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN },
+	{ "nvidia,hsic-tx-rtune-p", TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP },
+	{ "nvidia,hsic-tx-rslew-n", TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN },
+	{ "nvidia,hsic-tx-rslew-p", TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP },
+	{ "nvidia,hsic-auto-term", TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM },
 };
 
 #define TEGRA_XUSB_PADCTL_PACK(param, value) ((param) << 16 | (value))
@@ -321,6 +549,7 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 	struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 	const struct tegra_xusb_padctl_lane *lane;
 	enum tegra_xusb_padctl_param param;
+	int port;
 	u32 value;
 
 	param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(*config);
@@ -330,7 +559,125 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 	case TEGRA_XUSB_PADCTL_IDDQ:
 		value = padctl_readl(padctl, lane->offset);
 		value = (value >> lane->iddq) & 0x1;
-		*config = TEGRA_XUSB_PADCTL_PACK(param, value);
+		break;
+
+	case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
+		value = lane_to_usb3_port(padctl, group);
+		if (value < 0) {
+			dev_err(padctl->dev,
+				"Lane %d not mapped to USB3 port\n", group);
+			return -EINVAL;
+		}
+		break;
+
+	case TEGRA_XUSB_PADCTL_USB2_PORT_NUM:
+		port = lane_to_usb3_port(padctl, group);
+		if (port < 0) {
+			dev_err(padctl->dev,
+				"Lane %d not mapped to USB2 port\n", group);
+			return -EINVAL;
+		}
+
+		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP) >>
+			XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port);
+		value &= XUSB_PADCTL_SS_PORT_MAP_PORT_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		value = padctl_readl(padctl,
+				     XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
+		value &= XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+		if (value & XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN)
+			value = 1;
+		else
+			value = 0;
 		break;
 
 	default:
@@ -339,6 +686,7 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 		return -ENOTSUPP;
 	}
 
+	*config = TEGRA_XUSB_PADCTL_PACK(param, value);
 	return 0;
 }
 
@@ -351,7 +699,7 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
 	const struct tegra_xusb_padctl_lane *lane;
 	enum tegra_xusb_padctl_param param;
 	unsigned long value;
-	unsigned int i;
+	unsigned int i, port;
 	u32 regval;
 
 	lane = &padctl->soc->lanes[group];
@@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
 			padctl_writel(padctl, regval, lane->offset);
 			break;
 
+		case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
+			if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
+				dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
+					value);
+				return -EINVAL;
+			}
+			if (!is_pcie_sata_lane(group)) {
+				dev_err(padctl->dev,
+					"USB3 port not applicable for pin %d\n",
+					group);
+				return -EINVAL;
+			}
+			padctl->usb3_ports[value].lane = group;
+			break;
+
+		case TEGRA_XUSB_PADCTL_USB2_PORT_NUM:
+			if (value >= TEGRA_XUSB_PADCTL_UTMI_PORTS) {
+				dev_err(padctl->dev, "Invalid USB2 port: %lu\n",
+					value);
+				return -EINVAL;
+			}
+			if (!is_pcie_sata_lane(group)) {
+				dev_err(padctl->dev,
+					"USB2 port not applicable for pin %d\n",
+					group);
+				return -EINVAL;
+			}
+			port = lane_to_usb3_port(padctl, group);
+			if (port < 0) {
+				dev_err(padctl->dev,
+					"Pin %d not mapped to USB3 port\n",
+					group);
+				break;
+			}
+
+			regval = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
+			regval &= ~(XUSB_PADCTL_SS_PORT_MAP_PORT_MASK <<
+				    XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port));
+			regval |= value <<
+				XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port);
+			padctl_writel(padctl, regval, XUSB_PADCTL_SS_PORT_MAP);
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			value &= XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK;
+			padctl_writel(padctl, value,
+				      XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL1(port));
+			if (!value)
+				regval &= ~XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN;
+			else
+				regval |= XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL1(port));
+			break;
+
 		default:
 			dev_err(padctl->dev,
 				"invalid configuration parameter: %04x\n",
@@ -595,6 +1130,459 @@ static const struct phy_ops sata_phy_ops = {
 	.owner = THIS_MODULE,
 };
 
+static int usb3_phy_to_port(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_USB3_PORTS; i++) {
+		if (phy == padctl->phys[TEGRA_XUSB_PADCTL_USB3_P0 + i])
+			break;
+	}
+	BUG_ON(i == TEGRA_XUSB_PADCTL_USB3_PORTS);
+
+	return i;
+}
+
+static int usb3_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = usb3_phy_to_port(phy);
+	int lane = padctl->usb3_ports[port].lane;
+	u32 value, offset;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
+	value |= (padctl->soc->rx_wander <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
+		 (padctl->soc->cdr_cntl <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT) |
+		 (padctl->soc->rx_eq <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT);
+	if (padctl->usb3_ports[port].context_saved) {
+		value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+			   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT));
+		value |= (padctl->usb3_ports[port].ctle_g_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+			 (padctl->usb3_ports[port].ctle_z_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT);
+	}
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+
+	value = padctl->soc->dfe_cntl;
+	if (padctl->usb3_ports[port].context_saved) {
+		value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+			   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT));
+		value |= (padctl->usb3_ports[port].tap1_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+			 (padctl->usb3_ports[port].amp_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT);
+	}
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port));
+
+	offset = (lane == PIN_SATA_0) ? XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 :
+		XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(lane - PIN_PCIE_0);
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT);
+	value |= padctl->soc->spare_in <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	offset = (lane == PIN_SATA_0) ? XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 :
+		XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(lane - PIN_PCIE_0);
+	value = padctl_readl(padctl, offset);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	usleep_range(100, 200);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static int usb3_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = usb3_phy_to_port(phy);
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	usleep_range(100, 200);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	usleep_range(250, 350);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static void usb3_phy_save_context(struct tegra_xusb_padctl *padctl, int port)
+{
+	int lane = padctl->usb3_ports[port].lane;
+	u32 value, offset;
+
+	padctl->usb3_ports[port].context_saved = true;
+
+	offset = (lane == PIN_SATA_0) ? XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 :
+		XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(lane - PIN_PCIE_0);
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].tap1_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK;
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].amp_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port));
+	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT));
+	value |= (padctl->usb3_ports[port].tap1_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+		 (padctl->usb3_ports[port].amp_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port));
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].ctle_g_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK;
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].ctle_z_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT));
+	value |= (padctl->usb3_ports[port].ctle_g_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+		 (padctl->usb3_ports[port].ctle_z_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+}
+
+static const struct phy_ops usb3_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = usb3_phy_power_on,
+	.power_off = usb3_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int utmi_phy_to_port(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_UTMI_PORTS; i++) {
+		if (phy == padctl->phys[TEGRA_XUSB_PADCTL_UTMI_P0 + i])
+			break;
+	}
+	BUG_ON(i == TEGRA_XUSB_PADCTL_UTMI_PORTS);
+
+	return i;
+}
+
+static int utmi_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = utmi_phy_to_port(phy);
+	int ret;
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK <<
+		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
+		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK <<
+		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT));
+	value |= (padctl->calib.hs_squelch_level <<
+		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
+		 (padctl->soc->hs_discon_level <<
+		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
+	value &= ~(XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK <<
+		   XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(port));
+	value |= XUSB_PADCTL_USB2_PORT_CAP_HOST <<
+		XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(port));
+	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) |
+		   (XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT) |
+		   (XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT) |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI);
+	value |= padctl->calib.hs_curr_level[port] <<
+		XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT;
+	value |= padctl->soc->hs_slew <<
+		XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT;
+	value |= padctl->soc->ls_rslew[port] <<
+		XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(port));
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
+	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
+		   (XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT) |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP);
+	value |= (padctl->calib.hs_term_range_adj <<
+		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
+		 (padctl->calib.hs_iref_cap <<
+		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
+
+	ret = regulator_enable(padctl->vbus[port]);
+	if (ret)
+		return ret;
+
+	mutex_lock(&padctl->lock);
+
+	if (padctl->utmi_enable++ > 0)
+		goto out;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+
+out:
+	mutex_unlock(&padctl->lock);
+	return 0;
+}
+
+static int utmi_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = utmi_phy_to_port(phy);
+	u32 value;
+
+	regulator_disable(padctl->vbus[port]);
+
+	mutex_lock(&padctl->lock);
+
+	if (WARN_ON(padctl->utmi_enable == 0))
+		goto out;
+
+	if (--padctl->utmi_enable > 0)
+		goto out;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+
+out:
+	mutex_unlock(&padctl->lock);
+	return 0;
+}
+
+static const struct phy_ops utmi_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = utmi_phy_power_on,
+	.power_off = utmi_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int hsic_phy_to_port(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_HSIC_PORTS; i++) {
+		if (phy == padctl->phys[TEGRA_XUSB_PADCTL_HSIC_P0 + i])
+			break;
+	}
+	BUG_ON(i == TEGRA_XUSB_PADCTL_HSIC_PORTS);
+
+	return i;
+}
+
+static int hsic_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = hsic_phy_to_port(phy);
+	int ret;
+	u32 value;
+
+	ret = regulator_enable(padctl->vddio_hsic);
+	if (ret)
+		return ret;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX);
+	value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE;
+	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+
+	return 0;
+}
+
+static int hsic_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = hsic_phy_to_port(phy);
+	u32 value;
+
+	regulator_disable(padctl->vddio_hsic);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+	value |= XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX;
+	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+
+	return 0;
+}
+
+static void hsic_phy_set_idle(struct tegra_xusb_padctl *padctl, int port,
+			      bool set)
+{
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+	if (set)
+		value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
+			 XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE;
+	else
+		value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
+			   XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE);
+	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+}
+
+static const struct phy_ops hsic_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = hsic_phy_power_on,
+	.power_off = hsic_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int tegra_xusb_phy_mbox_notifier(struct notifier_block *nb,
+					unsigned long event, void *p)
+{
+	struct tegra_xusb_padctl *padctl = container_of(nb,
+						struct tegra_xusb_padctl,
+						mbox_nb);
+	struct tegra_xusb_mbox_msg *msg = (struct tegra_xusb_mbox_msg *)p;
+	u32 ports;
+	int i;
+
+	switch (event) {
+	case MBOX_CMD_SAVE_DFE_CTLE_CTX:
+		msg->data_out = msg->data_in;
+		if (msg->data_in > TEGRA_XUSB_PADCTL_USB3_PORTS) {
+			msg->cmd_out = MBOX_CMD_NAK;
+		} else {
+			usb3_phy_save_context(padctl, msg->data_in);
+			msg->cmd_out = MBOX_CMD_ACK;
+		}
+		return NOTIFY_STOP;
+	case MBOX_CMD_START_HSIC_IDLE:
+	case MBOX_CMD_STOP_HSIC_IDLE:
+		ports = msg->data_in >> (padctl->soc->hsic_port_offset + 1);
+		msg->data_out = msg->data_in;
+		for (i = 0; i < TEGRA_XUSB_PADCTL_HSIC_PORTS; i++) {
+			if (!(ports & BIT(i)))
+				continue;
+			if (event == MBOX_CMD_START_HSIC_IDLE)
+				hsic_phy_set_idle(padctl, i, true);
+			else
+				hsic_phy_set_idle(padctl, i, false);
+		}
+		msg->cmd_out = MBOX_CMD_ACK;
+		return NOTIFY_STOP;
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
 static struct phy *tegra_xusb_padctl_xlate(struct device *dev,
 					   struct of_phandle_args *args)
 {
@@ -610,19 +1598,6 @@ static struct phy *tegra_xusb_padctl_xlate(struct device *dev,
 	return padctl->phys[index];
 }
 
-#define PIN_OTG_0   0
-#define PIN_OTG_1   1
-#define PIN_OTG_2   2
-#define PIN_ULPI_0  3
-#define PIN_HSIC_0  4
-#define PIN_HSIC_1  5
-#define PIN_PCIE_0  6
-#define PIN_PCIE_1  7
-#define PIN_PCIE_2  8
-#define PIN_PCIE_3  9
-#define PIN_PCIE_4 10
-#define PIN_SATA_0 11
-
 static const struct pinctrl_pin_desc tegra124_pins[] = {
 	PINCTRL_PIN(PIN_OTG_0,  "otg-0"),
 	PINCTRL_PIN(PIN_OTG_1,  "otg-1"),
@@ -780,6 +1755,15 @@ static const struct tegra_xusb_padctl_soc tegra124_soc = {
 	.functions = tegra124_functions,
 	.num_lanes = ARRAY_SIZE(tegra124_lanes),
 	.lanes = tegra124_lanes,
+	.rx_wander = 0xf,
+	.rx_eq = 0xf070,
+	.cdr_cntl = 0x24,
+	.dfe_cntl = 0x002008ee,
+	.hs_slew = 0xe,
+	.ls_rslew = {0x3, 0x0, 0x0},
+	.hs_discon_level = 0x5,
+	.spare_in = 0x1,
+	.hsic_port_offset = 6,
 };
 
 static const struct of_device_id tegra_xusb_padctl_of_match[] = {
@@ -788,13 +1772,40 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match);
 
+static int tegra_xusb_read_fuse_calibration(struct tegra_xusb_padctl *padctl)
+{
+	int i, ret;
+	u32 value;
+
+	ret = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_UTMI_PORTS; i++) {
+		padctl->calib.hs_curr_level[i] =
+			(value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) &
+			FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK;
+	}
+	padctl->calib.hs_iref_cap =
+		(value >> FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT) &
+		FUSE_SKU_CALIB_HS_IREF_CAP_MASK;
+	padctl->calib.hs_term_range_adj =
+		(value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) &
+		FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK;
+	padctl->calib.hs_squelch_level =
+		(value >> FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT) &
+		FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK;
+
+	return 0;
+}
+
 static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 {
 	struct tegra_xusb_padctl *padctl;
 	const struct of_device_id *match;
 	struct resource *res;
 	struct phy *phy;
-	int err;
+	int err, i;
 
 	padctl = devm_kzalloc(&pdev->dev, sizeof(*padctl), GFP_KERNEL);
 	if (!padctl)
@@ -812,6 +1823,10 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 	if (IS_ERR(padctl->regs))
 		return PTR_ERR(padctl->regs);
 
+	err = tegra_xusb_read_fuse_calibration(padctl);
+	if (err < 0)
+		return err;
+
 	padctl->rst = devm_reset_control_get(&pdev->dev, NULL);
 	if (IS_ERR(padctl->rst))
 		return PTR_ERR(padctl->rst);
@@ -852,6 +1867,54 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 	padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy;
 	phy_set_drvdata(phy, padctl);
 
+	for (i = 0; i < TEGRA_XUSB_PADCTL_USB3_PORTS; i++) {
+		phy = devm_phy_create(&pdev->dev, &usb3_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			err = PTR_ERR(phy);
+			goto unregister;
+		}
+
+		padctl->phys[TEGRA_XUSB_PADCTL_USB3_P0 + i] = phy;
+		phy_set_drvdata(phy, padctl);
+	}
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_UTMI_PORTS; i++) {
+		char reg_name[sizeof("vbus-otg-N")];
+
+		sprintf(reg_name, "vbus-otg-%d", i);
+		padctl->vbus[i] = devm_regulator_get(&pdev->dev, reg_name);
+		if (IS_ERR(padctl->vbus[i])) {
+			err = PTR_ERR(padctl->vbus[i]);
+			goto unregister;
+		}
+
+		phy = devm_phy_create(&pdev->dev, &utmi_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			err = PTR_ERR(phy);
+			goto unregister;
+		}
+
+		padctl->phys[TEGRA_XUSB_PADCTL_UTMI_P0 + i] = phy;
+		phy_set_drvdata(phy, padctl);
+	}
+
+	padctl->vddio_hsic = devm_regulator_get(&pdev->dev, "vddio-hsic");
+	if (IS_ERR(padctl->vddio_hsic)) {
+		err = PTR_ERR(padctl->vddio_hsic);
+		goto unregister;
+	}
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_HSIC_PORTS; i++) {
+		phy = devm_phy_create(&pdev->dev, &hsic_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			err = PTR_ERR(phy);
+			goto unregister;
+		}
+
+		padctl->phys[TEGRA_XUSB_PADCTL_HSIC_P0 + i] = phy;
+		phy_set_drvdata(phy, padctl);
+	}
+
 	padctl->provider = devm_of_phy_provider_register(&pdev->dev,
 							 tegra_xusb_padctl_xlate);
 	if (err < 0) {
@@ -859,6 +1922,13 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 		goto unregister;
 	}
 
+	padctl->mbox = tegra_xusb_mbox_lookup_by_phandle(pdev->dev.of_node,
+							 "nvidia,xusb-mbox");
+	if (IS_ERR(padctl->mbox))
+		return PTR_ERR(padctl->mbox);
+	padctl->mbox_nb.notifier_call = tegra_xusb_phy_mbox_notifier;
+	tegra_xusb_mbox_register_notifier(padctl->mbox, &padctl->mbox_nb);
+
 	return 0;
 
 unregister:
@@ -873,6 +1943,8 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev)
 	struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev);
 	int err;
 
+	tegra_xusb_mbox_unregister_notifier(padctl->mbox, &padctl->mbox_nb);
+
 	pinctrl_unregister(padctl->pinctrl);
 
 	err = reset_control_assert(padctl->rst);
-- 
2.0.0.526.g5318336


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

* [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-18  6:16     ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

In addition to the PCIe and SATA PHYs, the XUSB pad controller also
supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
PCIe or SATA lane and is mapped to one of the three UTMI ports.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 drivers/pinctrl/pinctrl-tegra-xusb.c | 1106 +++++++++++++++++++++++++++++++++-
 1 file changed, 1089 insertions(+), 17 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
index 2405646..67056ab 100644
--- a/drivers/pinctrl/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/pinctrl-tegra-xusb.c
@@ -14,22 +14,55 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/phy/phy.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/reset.h>
+#include <linux/tegra-soc.h>
+#include <linux/tegra-xusb-mbox.h>
 
 #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
 
 #include "core.h"
 #include "pinctrl-utils.h"
 
+#define TEGRA_XUSB_PADCTL_USB3_PORTS 2
+#define TEGRA_XUSB_PADCTL_UTMI_PORTS 3
+#define TEGRA_XUSB_PADCTL_HSIC_PORTS 2
+
+#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? 15 : 0)
+#define FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK 0x3f
+#define FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT 13
+#define FUSE_SKU_CALIB_HS_IREF_CAP_MASK 0x3
+#define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT 11
+#define FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK 0x3
+#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT 7
+#define FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK 0xf
+
+#define XUSB_PADCTL_USB2_PORT_CAP 0x008
+#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(x) ((x) * 4)
+#define XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK 0x3
+#define XUSB_PADCTL_USB2_PORT_CAP_DISABLED 0x0
+#define XUSB_PADCTL_USB2_PORT_CAP_HOST 0x1
+#define XUSB_PADCTL_USB2_PORT_CAP_DEVICE 0x2
+#define XUSB_PADCTL_USB2_PORT_CAP_OTG 0x3
+
+#define XUSB_PADCTL_SS_PORT_MAP 0x014
+#define XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(x) ((x) * 4)
+#define XUSB_PADCTL_SS_PORT_MAP_PORT_MASK 0x7
+
 #define XUSB_PADCTL_ELPG_PROGRAM 0x01c
 #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
 #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
 #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
+#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(x) (1 << (18 + (x) * 4))
+#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(x) \
+							(1 << (17 + (x) * 4))
+#define XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN(x) (1 << (16 + (x) * 4))
 
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
@@ -41,6 +74,104 @@
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
 #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
 
+#define XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(x) (0x058 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT 24
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK 0xff
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT 16
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK 0x3f
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT 8
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK 0x3f
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT 8
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK 0xffff
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT 4
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK 0x7
+
+#define XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(x) (0x068 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT 24
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK 0x1f
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT 16
+#define XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK 0x7f
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(x) ((x) < 2 ? 0x078 + (x) * 4 : \
+					       0x0f8 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT 28
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK 0x3
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(x) ((x) < 2 ? 0x090 + (x) * 4 : \
+					       0x11c + (x) * 4)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN (1 << 8)
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(x) ((x) < 2 ? 0x098 + (x) * 4 : \
+					       0x128 + (x) * 4)
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT 24
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK 0x3f
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK 0x1f
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK 0x7f
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT 16
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK 0xff
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z 0x21
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP 0x32
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP 0x33
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z 0x48
+#define XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z 0xa1
+
+#define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x0a0 + (x) * 4)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI (1 << 21)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 (1 << 20)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD (1 << 19)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT 14
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK 0x3
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT 6
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK 0x3f
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT 0
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK 0x3f
+
+#define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x0ac + (x) * 4)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT 9
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK 0x3
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT 3
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK 0x7
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR (1 << 2)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP (1 << 1)
+#define XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP (1 << 0)
+
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x0b8
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD (1 << 12)
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT 2
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK 0x7
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT 0
+#define XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK 0x3
+
+#define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x0c0 + (x) * 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT 12
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT 8
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT 4
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT 0
+#define XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK 0x7
+
+#define XUSB_PADCTL_HSIC_PADX_CTL1(x) (0x0c8 + (x) * 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE (1 << 10)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA (1 << 9)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE (1 << 8)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA (1 << 7)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI (1 << 5)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX (1 << 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX (1 << 3)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX (1 << 2)
+#define XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN (1 << 0)
+
+#define XUSB_PADCTL_HSIC_PADX_CTL2(x) (0x0d0 + (x) * 4)
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT 4
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK 0x7
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT 0
+#define XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK 0x7
+
+#define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL 0x0e0
+#define XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK 0x1f
+
 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
 #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
@@ -52,6 +183,12 @@
 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
 #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
 
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 0x14c
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 0x158
+
+#define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 0x15c
+
 struct tegra_xusb_padctl_function {
 	const char *name;
 	const char * const *groups;
@@ -72,6 +209,16 @@ struct tegra_xusb_padctl_soc {
 
 	const struct tegra_xusb_padctl_lane *lanes;
 	unsigned int num_lanes;
+
+	u32 rx_wander;
+	u32 rx_eq;
+	u32 cdr_cntl;
+	u32 dfe_cntl;
+	u32 hs_slew;
+	u32 ls_rslew[TEGRA_XUSB_PADCTL_UTMI_PORTS];
+	u32 hs_discon_level;
+	u32 spare_in;
+	int hsic_port_offset;
 };
 
 struct tegra_xusb_padctl_lane {
@@ -86,6 +233,22 @@ struct tegra_xusb_padctl_lane {
 	unsigned int num_funcs;
 };
 
+struct tegra_xusb_fuse_calibration {
+	u32 hs_curr_level[TEGRA_XUSB_PADCTL_UTMI_PORTS];
+	u32 hs_iref_cap;
+	u32 hs_term_range_adj;
+	u32 hs_squelch_level;
+};
+
+struct tegra_xusb_usb3_port {
+	unsigned int lane;
+	bool context_saved;
+	u32 tap1_val;
+	u32 amp_val;
+	u32 ctle_z_val;
+	u32 ctle_g_val;
+};
+
 struct tegra_xusb_padctl {
 	struct device *dev;
 	void __iomem *regs;
@@ -93,13 +256,22 @@ struct tegra_xusb_padctl {
 	struct reset_control *rst;
 
 	const struct tegra_xusb_padctl_soc *soc;
+	struct tegra_xusb_fuse_calibration calib;
 	struct pinctrl_dev *pinctrl;
 	struct pinctrl_desc desc;
 
 	struct phy_provider *provider;
-	struct phy *phys[2];
+	struct phy *phys[9];
 
 	unsigned int enable;
+
+	struct tegra_xusb_mbox *mbox;
+	struct notifier_block mbox_nb;
+
+	struct tegra_xusb_usb3_port usb3_ports[TEGRA_XUSB_PADCTL_USB3_PORTS];
+	unsigned int utmi_enable;
+	struct regulator *vbus[TEGRA_XUSB_PADCTL_UTMI_PORTS];
+	struct regulator *vddio_hsic;
 };
 
 static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value,
@@ -114,6 +286,42 @@ static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
 	return readl(padctl->regs + offset);
 }
 
+#define PIN_OTG_0   0
+#define PIN_OTG_1   1
+#define PIN_OTG_2   2
+#define PIN_ULPI_0  3
+#define PIN_HSIC_0  4
+#define PIN_HSIC_1  5
+#define PIN_PCIE_0  6
+#define PIN_PCIE_1  7
+#define PIN_PCIE_2  8
+#define PIN_PCIE_3  9
+#define PIN_PCIE_4 10
+#define PIN_SATA_0 11
+
+static inline bool is_hsic_lane(unsigned int lane)
+{
+	return lane >= PIN_HSIC_0 && lane <= PIN_HSIC_1;
+}
+
+static inline bool is_pcie_sata_lane(unsigned int lane)
+{
+	return lane >= PIN_PCIE_0 && lane <= PIN_SATA_0;
+}
+
+static int lane_to_usb3_port(struct tegra_xusb_padctl *padctl,
+			     unsigned int lane)
+{
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_USB3_PORTS; i++) {
+		if (padctl->usb3_ports[i].lane == lane)
+			return i;
+	}
+
+	return -1;
+}
+
 static int tegra_xusb_padctl_get_groups_count(struct pinctrl_dev *pinctrl)
 {
 	struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
@@ -131,6 +339,16 @@ static const char *tegra_xusb_padctl_get_group_name(struct pinctrl_dev *pinctrl,
 
 enum tegra_xusb_padctl_param {
 	TEGRA_XUSB_PADCTL_IDDQ,
+	TEGRA_XUSB_PADCTL_USB3_PORT_NUM,
+	TEGRA_XUSB_PADCTL_USB2_PORT_NUM,
+	TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM,
+	TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM,
+	TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN,
+	TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP,
+	TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM,
 };
 
 static const struct tegra_xusb_padctl_property {
@@ -138,6 +356,16 @@ static const struct tegra_xusb_padctl_property {
 	enum tegra_xusb_padctl_param param;
 } properties[] = {
 	{ "nvidia,iddq", TEGRA_XUSB_PADCTL_IDDQ },
+	{ "nvidia,usb3-port-num", TEGRA_XUSB_PADCTL_USB3_PORT_NUM },
+	{ "nvidia,usb2-port-num", TEGRA_XUSB_PADCTL_USB2_PORT_NUM },
+	{ "nvidia,hsic-strobe-trim", TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM },
+	{ "nvidia,hsic-rx-strobe-trim", TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM },
+	{ "nvidia,hsic-rx-data-trim", TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM },
+	{ "nvidia,hsic-tx-rtune-n", TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN },
+	{ "nvidia,hsic-tx-rtune-p", TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP },
+	{ "nvidia,hsic-tx-rslew-n", TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN },
+	{ "nvidia,hsic-tx-rslew-p", TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP },
+	{ "nvidia,hsic-auto-term", TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM },
 };
 
 #define TEGRA_XUSB_PADCTL_PACK(param, value) ((param) << 16 | (value))
@@ -321,6 +549,7 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 	struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
 	const struct tegra_xusb_padctl_lane *lane;
 	enum tegra_xusb_padctl_param param;
+	int port;
 	u32 value;
 
 	param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(*config);
@@ -330,7 +559,125 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 	case TEGRA_XUSB_PADCTL_IDDQ:
 		value = padctl_readl(padctl, lane->offset);
 		value = (value >> lane->iddq) & 0x1;
-		*config = TEGRA_XUSB_PADCTL_PACK(param, value);
+		break;
+
+	case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
+		value = lane_to_usb3_port(padctl, group);
+		if (value < 0) {
+			dev_err(padctl->dev,
+				"Lane %d not mapped to USB3 port\n", group);
+			return -EINVAL;
+		}
+		break;
+
+	case TEGRA_XUSB_PADCTL_USB2_PORT_NUM:
+		port = lane_to_usb3_port(padctl, group);
+		if (port < 0) {
+			dev_err(padctl->dev,
+				"Lane %d not mapped to USB2 port\n", group);
+			return -EINVAL;
+		}
+
+		value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP) >>
+			XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port);
+		value &= XUSB_PADCTL_SS_PORT_MAP_PORT_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		value = padctl_readl(padctl,
+				     XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
+		value &= XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL2(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL0(port)) >>
+			XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT;
+		value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK;
+		break;
+
+	case TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM:
+		if (!is_hsic_lane(group)) {
+			dev_err(padctl->dev, "Pin %d not an HSIC\n", group);
+			return -EINVAL;
+		}
+
+		port = group - PIN_HSIC_0;
+		value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+		if (value & XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN)
+			value = 1;
+		else
+			value = 0;
 		break;
 
 	default:
@@ -339,6 +686,7 @@ static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
 		return -ENOTSUPP;
 	}
 
+	*config = TEGRA_XUSB_PADCTL_PACK(param, value);
 	return 0;
 }
 
@@ -351,7 +699,7 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
 	const struct tegra_xusb_padctl_lane *lane;
 	enum tegra_xusb_padctl_param param;
 	unsigned long value;
-	unsigned int i;
+	unsigned int i, port;
 	u32 regval;
 
 	lane = &padctl->soc->lanes[group];
@@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
 			padctl_writel(padctl, regval, lane->offset);
 			break;
 
+		case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
+			if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
+				dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
+					value);
+				return -EINVAL;
+			}
+			if (!is_pcie_sata_lane(group)) {
+				dev_err(padctl->dev,
+					"USB3 port not applicable for pin %d\n",
+					group);
+				return -EINVAL;
+			}
+			padctl->usb3_ports[value].lane = group;
+			break;
+
+		case TEGRA_XUSB_PADCTL_USB2_PORT_NUM:
+			if (value >= TEGRA_XUSB_PADCTL_UTMI_PORTS) {
+				dev_err(padctl->dev, "Invalid USB2 port: %lu\n",
+					value);
+				return -EINVAL;
+			}
+			if (!is_pcie_sata_lane(group)) {
+				dev_err(padctl->dev,
+					"USB2 port not applicable for pin %d\n",
+					group);
+				return -EINVAL;
+			}
+			port = lane_to_usb3_port(padctl, group);
+			if (port < 0) {
+				dev_err(padctl->dev,
+					"Pin %d not mapped to USB3 port\n",
+					group);
+				break;
+			}
+
+			regval = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_MAP);
+			regval &= ~(XUSB_PADCTL_SS_PORT_MAP_PORT_MASK <<
+				    XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port));
+			regval |= value <<
+				XUSB_PADCTL_SS_PORT_MAP_PORTX_SHIFT(port);
+			padctl_writel(padctl, regval, XUSB_PADCTL_SS_PORT_MAP);
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_STROBE_TRIM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			value &= XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL_STRB_TRIM_MASK;
+			padctl_writel(padctl, value,
+				      XUSB_PADCTL_HSIC_STRB_TRIM_CONTROL);
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_RX_STROBE_TRIM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL2_RX_STROBE_TRIM_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_RX_DATA_TRIM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL2_RX_DATA_TRIM_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL2(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEN:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEN_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RTUNEP:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RTUNEP_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWN:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWN_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_TX_RSLEWP:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			value &= XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			regval &= ~(XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_MASK <<
+				    XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT);
+			regval |= value <<
+				XUSB_PADCTL_HSIC_PAD_CTL0_TX_RSLEWP_SHIFT;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL0(port));
+			break;
+
+		case TEGRA_XUSB_PADCTL_HSIC_AUTO_TERM:
+			if (!is_hsic_lane(group)) {
+				dev_err(padctl->dev, "Pin %d not an HSIC\n",
+					group);
+				return -EINVAL;
+			}
+
+			port = group - PIN_HSIC_0;
+			regval = padctl_readl(padctl,
+					      XUSB_PADCTL_HSIC_PADX_CTL1(port));
+			if (!value)
+				regval &= ~XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN;
+			else
+				regval |= XUSB_PADCTL_HSIC_PAD_CTL1_AUTO_TERM_EN;
+			padctl_writel(padctl, regval,
+				      XUSB_PADCTL_HSIC_PADX_CTL1(port));
+			break;
+
 		default:
 			dev_err(padctl->dev,
 				"invalid configuration parameter: %04x\n",
@@ -595,6 +1130,459 @@ static const struct phy_ops sata_phy_ops = {
 	.owner = THIS_MODULE,
 };
 
+static int usb3_phy_to_port(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_USB3_PORTS; i++) {
+		if (phy == padctl->phys[TEGRA_XUSB_PADCTL_USB3_P0 + i])
+			break;
+	}
+	BUG_ON(i == TEGRA_XUSB_PADCTL_USB3_PORTS);
+
+	return i;
+}
+
+static int usb3_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = usb3_phy_to_port(phy);
+	int lane = padctl->usb3_ports[port].lane;
+	u32 value, offset;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
+	value |= (padctl->soc->rx_wander <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
+		 (padctl->soc->cdr_cntl <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT) |
+		 (padctl->soc->rx_eq <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT);
+	if (padctl->usb3_ports[port].context_saved) {
+		value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+			   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT));
+		value |= (padctl->usb3_ports[port].ctle_g_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+			 (padctl->usb3_ports[port].ctle_z_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT);
+	}
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+
+	value = padctl->soc->dfe_cntl;
+	if (padctl->usb3_ports[port].context_saved) {
+		value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+			   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK <<
+			    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT));
+		value |= (padctl->usb3_ports[port].tap1_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+			 (padctl->usb3_ports[port].amp_val <<
+			  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT);
+	}
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port));
+
+	offset = (lane == PIN_SATA_0) ? XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL2 :
+		XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL2(lane - PIN_PCIE_0);
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT);
+	value |= padctl->soc->spare_in <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL2_SPARE_IN_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	offset = (lane == PIN_SATA_0) ? XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL5 :
+		XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL5(lane - PIN_PCIE_0);
+	value = padctl_readl(padctl, offset);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL5_RX_QEYE_EN;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	usleep_range(100, 200);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value &= ~XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static int usb3_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = usb3_phy_to_port(phy);
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	usleep_range(100, 200);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_CLAMP_EN_EARLY(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	usleep_range(250, 350);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
+	value |= XUSB_PADCTL_ELPG_PROGRAM_SSPX_ELPG_VCORE_DOWN(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
+
+	return 0;
+}
+
+static void usb3_phy_save_context(struct tegra_xusb_padctl *padctl, int port)
+{
+	int lane = padctl->usb3_ports[port].lane;
+	u32 value, offset;
+
+	padctl->usb3_ports[port].context_saved = true;
+
+	offset = (lane == PIN_SATA_0) ? XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL6 :
+		XUSB_PADCTL_IOPHY_MISC_PAD_PX_CTL6(lane - PIN_PCIE_0);
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_TAP <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].tap1_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_TAP_MASK;
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_AMP <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].amp_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_AMP_MASK;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port));
+	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT));
+	value |= (padctl->usb3_ports[port].tap1_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_TAP_SHIFT) |
+		 (padctl->usb3_ports[port].amp_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL4_DFE_CNTL_AMP_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL4(port));
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_LATCH_G_Z <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_G_Z <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].ctle_g_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK;
+
+	value = padctl_readl(padctl, offset);
+	value &= ~(XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_MASK <<
+		   XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT);
+	value |= XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_CTLE_Z <<
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SEL_SHIFT;
+	padctl_writel(padctl, value, offset);
+
+	value = padctl_readl(padctl, offset) >>
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_SHIFT;
+	padctl->usb3_ports[port].ctle_z_val = value &
+		XUSB_PADCTL_IOPHY_MISC_PAD_CTL6_MISC_OUT_G_Z_MASK;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_MASK <<
+		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT));
+	value |= (padctl->usb3_ports[port].ctle_g_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_G_SHIFT) |
+		 (padctl->usb3_ports[port].ctle_z_val <<
+		  XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_Z_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
+}
+
+static const struct phy_ops usb3_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = usb3_phy_power_on,
+	.power_off = usb3_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int utmi_phy_to_port(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_UTMI_PORTS; i++) {
+		if (phy == padctl->phys[TEGRA_XUSB_PADCTL_UTMI_P0 + i])
+			break;
+	}
+	BUG_ON(i == TEGRA_XUSB_PADCTL_UTMI_PORTS);
+
+	return i;
+}
+
+static int utmi_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = utmi_phy_to_port(phy);
+	int ret;
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	value &= ~((XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_MASK <<
+		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
+		   (XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_MASK <<
+		    XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT));
+	value |= (padctl->calib.hs_squelch_level <<
+		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_SQUELCH_LEVEL_SHIFT) |
+		 (padctl->soc->hs_discon_level <<
+		  XUSB_PADCTL_USB2_BIAS_PAD_CTL0_HS_DISCON_LEVEL_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
+	value &= ~(XUSB_PADCTL_USB2_PORT_CAP_PORT_CAP_MASK <<
+		   XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(port));
+	value |= XUSB_PADCTL_USB2_PORT_CAP_HOST <<
+		XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_SHIFT(port);
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(port));
+	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT) |
+		   (XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT) |
+		   (XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT) |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD2 |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL0_PD_ZI);
+	value |= padctl->calib.hs_curr_level[port] <<
+		XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_CURR_LEVEL_SHIFT;
+	value |= padctl->soc->hs_slew <<
+		XUSB_PADCTL_USB2_OTG_PAD_CTL0_HS_SLEW_SHIFT;
+	value |= padctl->soc->ls_rslew[port] <<
+		XUSB_PADCTL_USB2_OTG_PAD_CTL0_LS_RSLEW_SHIFT;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(port));
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
+	value &= ~((XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
+		   (XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_MASK <<
+		    XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT) |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DR |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_CHRP_FORCE_POWERUP |
+		   XUSB_PADCTL_USB2_OTG_PAD_CTL1_PD_DISC_FORCE_POWERUP);
+	value |= (padctl->calib.hs_term_range_adj <<
+		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_TERM_RANGE_ADJ_SHIFT) |
+		 (padctl->calib.hs_iref_cap <<
+		  XUSB_PADCTL_USB2_OTG_PAD_CTL1_HS_IREF_CAP_SHIFT);
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(port));
+
+	ret = regulator_enable(padctl->vbus[port]);
+	if (ret)
+		return ret;
+
+	mutex_lock(&padctl->lock);
+
+	if (padctl->utmi_enable++ > 0)
+		goto out;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	value &= ~XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+
+out:
+	mutex_unlock(&padctl->lock);
+	return 0;
+}
+
+static int utmi_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = utmi_phy_to_port(phy);
+	u32 value;
+
+	regulator_disable(padctl->vbus[port]);
+
+	mutex_lock(&padctl->lock);
+
+	if (WARN_ON(padctl->utmi_enable == 0))
+		goto out;
+
+	if (--padctl->utmi_enable > 0)
+		goto out;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+	value |= XUSB_PADCTL_USB2_BIAS_PAD_CTL0_PD;
+	padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0);
+
+out:
+	mutex_unlock(&padctl->lock);
+	return 0;
+}
+
+static const struct phy_ops utmi_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = utmi_phy_power_on,
+	.power_off = utmi_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int hsic_phy_to_port(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int i;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_HSIC_PORTS; i++) {
+		if (phy == padctl->phys[TEGRA_XUSB_PADCTL_HSIC_P0 + i])
+			break;
+	}
+	BUG_ON(i == TEGRA_XUSB_PADCTL_HSIC_PORTS);
+
+	return i;
+}
+
+static int hsic_phy_power_on(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = hsic_phy_to_port(phy);
+	int ret;
+	u32 value;
+
+	ret = regulator_enable(padctl->vddio_hsic);
+	if (ret)
+		return ret;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+	value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_STROBE |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_RPU_DATA |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX |
+		   XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX);
+	value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE;
+	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+
+	return 0;
+}
+
+static int hsic_phy_power_off(struct phy *phy)
+{
+	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
+	int port = hsic_phy_to_port(phy);
+	u32 value;
+
+	regulator_disable(padctl->vddio_hsic);
+
+	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+	value |= XUSB_PADCTL_HSIC_PAD_CTL1_PD_RX |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_ZI |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_TRX |
+		 XUSB_PADCTL_HSIC_PAD_CTL1_PD_TX;
+	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+
+	return 0;
+}
+
+static void hsic_phy_set_idle(struct tegra_xusb_padctl *padctl, int port,
+			      bool set)
+{
+	u32 value;
+
+	value = padctl_readl(padctl, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+	if (set)
+		value |= XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
+			 XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE;
+	else
+		value &= ~(XUSB_PADCTL_HSIC_PAD_CTL1_RPD_DATA |
+			   XUSB_PADCTL_HSIC_PAD_CTL1_RPU_STROBE);
+	padctl_writel(padctl, value, XUSB_PADCTL_HSIC_PADX_CTL1(port));
+}
+
+static const struct phy_ops hsic_phy_ops = {
+	.init = tegra_xusb_phy_init,
+	.exit = tegra_xusb_phy_exit,
+	.power_on = hsic_phy_power_on,
+	.power_off = hsic_phy_power_off,
+	.owner = THIS_MODULE,
+};
+
+static int tegra_xusb_phy_mbox_notifier(struct notifier_block *nb,
+					unsigned long event, void *p)
+{
+	struct tegra_xusb_padctl *padctl = container_of(nb,
+						struct tegra_xusb_padctl,
+						mbox_nb);
+	struct tegra_xusb_mbox_msg *msg = (struct tegra_xusb_mbox_msg *)p;
+	u32 ports;
+	int i;
+
+	switch (event) {
+	case MBOX_CMD_SAVE_DFE_CTLE_CTX:
+		msg->data_out = msg->data_in;
+		if (msg->data_in > TEGRA_XUSB_PADCTL_USB3_PORTS) {
+			msg->cmd_out = MBOX_CMD_NAK;
+		} else {
+			usb3_phy_save_context(padctl, msg->data_in);
+			msg->cmd_out = MBOX_CMD_ACK;
+		}
+		return NOTIFY_STOP;
+	case MBOX_CMD_START_HSIC_IDLE:
+	case MBOX_CMD_STOP_HSIC_IDLE:
+		ports = msg->data_in >> (padctl->soc->hsic_port_offset + 1);
+		msg->data_out = msg->data_in;
+		for (i = 0; i < TEGRA_XUSB_PADCTL_HSIC_PORTS; i++) {
+			if (!(ports & BIT(i)))
+				continue;
+			if (event == MBOX_CMD_START_HSIC_IDLE)
+				hsic_phy_set_idle(padctl, i, true);
+			else
+				hsic_phy_set_idle(padctl, i, false);
+		}
+		msg->cmd_out = MBOX_CMD_ACK;
+		return NOTIFY_STOP;
+	default:
+		return NOTIFY_DONE;
+	}
+}
+
 static struct phy *tegra_xusb_padctl_xlate(struct device *dev,
 					   struct of_phandle_args *args)
 {
@@ -610,19 +1598,6 @@ static struct phy *tegra_xusb_padctl_xlate(struct device *dev,
 	return padctl->phys[index];
 }
 
-#define PIN_OTG_0   0
-#define PIN_OTG_1   1
-#define PIN_OTG_2   2
-#define PIN_ULPI_0  3
-#define PIN_HSIC_0  4
-#define PIN_HSIC_1  5
-#define PIN_PCIE_0  6
-#define PIN_PCIE_1  7
-#define PIN_PCIE_2  8
-#define PIN_PCIE_3  9
-#define PIN_PCIE_4 10
-#define PIN_SATA_0 11
-
 static const struct pinctrl_pin_desc tegra124_pins[] = {
 	PINCTRL_PIN(PIN_OTG_0,  "otg-0"),
 	PINCTRL_PIN(PIN_OTG_1,  "otg-1"),
@@ -780,6 +1755,15 @@ static const struct tegra_xusb_padctl_soc tegra124_soc = {
 	.functions = tegra124_functions,
 	.num_lanes = ARRAY_SIZE(tegra124_lanes),
 	.lanes = tegra124_lanes,
+	.rx_wander = 0xf,
+	.rx_eq = 0xf070,
+	.cdr_cntl = 0x24,
+	.dfe_cntl = 0x002008ee,
+	.hs_slew = 0xe,
+	.ls_rslew = {0x3, 0x0, 0x0},
+	.hs_discon_level = 0x5,
+	.spare_in = 0x1,
+	.hsic_port_offset = 6,
 };
 
 static const struct of_device_id tegra_xusb_padctl_of_match[] = {
@@ -788,13 +1772,40 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match);
 
+static int tegra_xusb_read_fuse_calibration(struct tegra_xusb_padctl *padctl)
+{
+	int i, ret;
+	u32 value;
+
+	ret = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_UTMI_PORTS; i++) {
+		padctl->calib.hs_curr_level[i] =
+			(value >> FUSE_SKU_CALIB_HS_CURR_LEVEL_PADX_SHIFT(i)) &
+			FUSE_SKU_CALIB_HS_CURR_LEVEL_PAD_MASK;
+	}
+	padctl->calib.hs_iref_cap =
+		(value >> FUSE_SKU_CALIB_HS_IREF_CAP_SHIFT) &
+		FUSE_SKU_CALIB_HS_IREF_CAP_MASK;
+	padctl->calib.hs_term_range_adj =
+		(value >> FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_SHIFT) &
+		FUSE_SKU_CALIB_HS_TERM_RANGE_ADJ_MASK;
+	padctl->calib.hs_squelch_level =
+		(value >> FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_SHIFT) &
+		FUSE_SKU_CALIB_HS_SQUELCH_LEVEL_MASK;
+
+	return 0;
+}
+
 static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 {
 	struct tegra_xusb_padctl *padctl;
 	const struct of_device_id *match;
 	struct resource *res;
 	struct phy *phy;
-	int err;
+	int err, i;
 
 	padctl = devm_kzalloc(&pdev->dev, sizeof(*padctl), GFP_KERNEL);
 	if (!padctl)
@@ -812,6 +1823,10 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 	if (IS_ERR(padctl->regs))
 		return PTR_ERR(padctl->regs);
 
+	err = tegra_xusb_read_fuse_calibration(padctl);
+	if (err < 0)
+		return err;
+
 	padctl->rst = devm_reset_control_get(&pdev->dev, NULL);
 	if (IS_ERR(padctl->rst))
 		return PTR_ERR(padctl->rst);
@@ -852,6 +1867,54 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 	padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy;
 	phy_set_drvdata(phy, padctl);
 
+	for (i = 0; i < TEGRA_XUSB_PADCTL_USB3_PORTS; i++) {
+		phy = devm_phy_create(&pdev->dev, &usb3_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			err = PTR_ERR(phy);
+			goto unregister;
+		}
+
+		padctl->phys[TEGRA_XUSB_PADCTL_USB3_P0 + i] = phy;
+		phy_set_drvdata(phy, padctl);
+	}
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_UTMI_PORTS; i++) {
+		char reg_name[sizeof("vbus-otg-N")];
+
+		sprintf(reg_name, "vbus-otg-%d", i);
+		padctl->vbus[i] = devm_regulator_get(&pdev->dev, reg_name);
+		if (IS_ERR(padctl->vbus[i])) {
+			err = PTR_ERR(padctl->vbus[i]);
+			goto unregister;
+		}
+
+		phy = devm_phy_create(&pdev->dev, &utmi_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			err = PTR_ERR(phy);
+			goto unregister;
+		}
+
+		padctl->phys[TEGRA_XUSB_PADCTL_UTMI_P0 + i] = phy;
+		phy_set_drvdata(phy, padctl);
+	}
+
+	padctl->vddio_hsic = devm_regulator_get(&pdev->dev, "vddio-hsic");
+	if (IS_ERR(padctl->vddio_hsic)) {
+		err = PTR_ERR(padctl->vddio_hsic);
+		goto unregister;
+	}
+
+	for (i = 0; i < TEGRA_XUSB_PADCTL_HSIC_PORTS; i++) {
+		phy = devm_phy_create(&pdev->dev, &hsic_phy_ops, NULL);
+		if (IS_ERR(phy)) {
+			err = PTR_ERR(phy);
+			goto unregister;
+		}
+
+		padctl->phys[TEGRA_XUSB_PADCTL_HSIC_P0 + i] = phy;
+		phy_set_drvdata(phy, padctl);
+	}
+
 	padctl->provider = devm_of_phy_provider_register(&pdev->dev,
 							 tegra_xusb_padctl_xlate);
 	if (err < 0) {
@@ -859,6 +1922,13 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
 		goto unregister;
 	}
 
+	padctl->mbox = tegra_xusb_mbox_lookup_by_phandle(pdev->dev.of_node,
+							 "nvidia,xusb-mbox");
+	if (IS_ERR(padctl->mbox))
+		return PTR_ERR(padctl->mbox);
+	padctl->mbox_nb.notifier_call = tegra_xusb_phy_mbox_notifier;
+	tegra_xusb_mbox_register_notifier(padctl->mbox, &padctl->mbox_nb);
+
 	return 0;
 
 unregister:
@@ -873,6 +1943,8 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev)
 	struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev);
 	int err;
 
+	tegra_xusb_mbox_unregister_notifier(padctl->mbox, &padctl->mbox_nb);
+
 	pinctrl_unregister(padctl->pinctrl);
 
 	err = reset_control_assert(padctl->rst);
-- 
2.0.0.526.g5318336

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

* [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
  2014-06-18  6:16 ` Andrew Bresticker
  (?)
@ 2014-06-18  6:16   ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Mark Rutland, Russell King, Mathias Nyman, Pawel Moll,
	Ian Campbell, Andrew Bresticker, Greg Kroah-Hartman,
	Linus Walleij, Randy Dunlap, Kishon Vijay Abraham I,
	Grant Likely, Rob Herring, Thierry Reding, Kumar Gala,
	Stephen Warren, Alan Stern, Arnd Bergmann

Add device-tree binding documentation for the XHCI controller present
on Tegra124 and later SoCs.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 .../bindings/usb/nvidia,tegra124-xhci.txt          | 76 ++++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt

diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
new file mode 100644
index 0000000..fdb8624
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
@@ -0,0 +1,76 @@
+NVIDIA Tegra XHCI controller
+============================
+
+The Tegra XHCI controller supports both USB2 and USB3 interfaces exposed
+by the Tegra XUSB pad controller.
+
+Required properties:
+--------------------
+ - compatible: Should be "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: XHCI host interrupt.
+ - clocks: Must contain an entry for each entry in clock-names.
+   See ../clock/clock-bindings.txt for details.
+ - clock-names: Must include the following entries:
+    - xusb_host
+    - xusb_falcon_src
+    - xusb_ss
+    - xusb_ss_src
+    - xusb_hs_src
+    - xusb_fs_src
+    - pll_u_480m
+    - clk_m
+    - pll_e
+ - resets: Must contain an entry for each entry in reset-names.
+   See ../reset/reset.txt for details.
+ - reset-names: Must include the following entries:
+   - xusb_host
+   - xusb_ss
+ - nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
+
+Optional properties:
+--------------------
+ - phys: Must contain an entry for each entry in phy-names.
+   See ../phy/phy-bindings.txt for details.
+ - phy-names: Should include an entry for each PHY used by the controller.
+   May be a subset of the following:
+    - utmi-{0,1,2}
+    - hsic-{0,1}
+    - usb3-{0,1}
+ - s1p05v-supply: 1.05V supply regulator.
+ - s1p8v-supply: 1.8V supply regulator.
+ - s3p3v-supply: 3.3V supply regulator.
+
+Example:
+--------
+	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>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>,
+			 <&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_host", "xusb_falcon_src", "xusb_ss",
+			      "xusb_ss_src", "xusb_hs_src", "xusb_fs_src",
+			      "pll_u_480m", "clk_m", "pll_e";
+		resets = <&tegra_car 89>, <&tegra_car 156>;
+		reset-names = "xusb_host", "xusb_ss";
+		nvidia,xusb-mbox = <&mbox>;
+		phys = <&padctl TEGRA_XUSB_PADCTL_UTMI_P1>, /* mini-PCIe USB */
+		       <&padctl TEGRA_XUSB_PADCTL_UTMI_P2>, /* USB A */
+		       <&padctl TEGRA_XUSB_PADCTL_USB3_P0>; /* USB A */
+		phy-names = "utmi-1", "utmi-2", "usb3-0";
+		s1p05v-supply = <&vdd_1v05_run>;
+		s3p3v-supply = <&vdd_3v3_lp0>;
+		s1p8v-supply = <&vddio_1v8>;
+	};
-- 
2.0.0.526.g5318336

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

* [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-18  6:16   ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Add device-tree binding documentation for the XHCI controller present
on Tegra124 and later SoCs.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 .../bindings/usb/nvidia,tegra124-xhci.txt          | 76 ++++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt

diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
new file mode 100644
index 0000000..fdb8624
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
@@ -0,0 +1,76 @@
+NVIDIA Tegra XHCI controller
+============================
+
+The Tegra XHCI controller supports both USB2 and USB3 interfaces exposed
+by the Tegra XUSB pad controller.
+
+Required properties:
+--------------------
+ - compatible: Should be "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: XHCI host interrupt.
+ - clocks: Must contain an entry for each entry in clock-names.
+   See ../clock/clock-bindings.txt for details.
+ - clock-names: Must include the following entries:
+    - xusb_host
+    - xusb_falcon_src
+    - xusb_ss
+    - xusb_ss_src
+    - xusb_hs_src
+    - xusb_fs_src
+    - pll_u_480m
+    - clk_m
+    - pll_e
+ - resets: Must contain an entry for each entry in reset-names.
+   See ../reset/reset.txt for details.
+ - reset-names: Must include the following entries:
+   - xusb_host
+   - xusb_ss
+ - nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
+
+Optional properties:
+--------------------
+ - phys: Must contain an entry for each entry in phy-names.
+   See ../phy/phy-bindings.txt for details.
+ - phy-names: Should include an entry for each PHY used by the controller.
+   May be a subset of the following:
+    - utmi-{0,1,2}
+    - hsic-{0,1}
+    - usb3-{0,1}
+ - s1p05v-supply: 1.05V supply regulator.
+ - s1p8v-supply: 1.8V supply regulator.
+ - s3p3v-supply: 3.3V supply regulator.
+
+Example:
+--------
+	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>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>,
+			 <&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_host", "xusb_falcon_src", "xusb_ss",
+			      "xusb_ss_src", "xusb_hs_src", "xusb_fs_src",
+			      "pll_u_480m", "clk_m", "pll_e";
+		resets = <&tegra_car 89>, <&tegra_car 156>;
+		reset-names = "xusb_host", "xusb_ss";
+		nvidia,xusb-mbox = <&mbox>;
+		phys = <&padctl TEGRA_XUSB_PADCTL_UTMI_P1>, /* mini-PCIe USB */
+		       <&padctl TEGRA_XUSB_PADCTL_UTMI_P2>, /* USB A */
+		       <&padctl TEGRA_XUSB_PADCTL_USB3_P0>; /* USB A */
+		phy-names = "utmi-1", "utmi-2", "usb3-0";
+		s1p05v-supply = <&vdd_1v05_run>;
+		s3p3v-supply = <&vdd_3v3_lp0>;
+		s1p8v-supply = <&vddio_1v8>;
+	};
-- 
2.0.0.526.g5318336


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

* [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-18  6:16   ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

Add device-tree binding documentation for the XHCI controller present
on Tegra124 and later SoCs.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 .../bindings/usb/nvidia,tegra124-xhci.txt          | 76 ++++++++++++++++++++++
 1 file changed, 76 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt

diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
new file mode 100644
index 0000000..fdb8624
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
@@ -0,0 +1,76 @@
+NVIDIA Tegra XHCI controller
+============================
+
+The Tegra XHCI controller supports both USB2 and USB3 interfaces exposed
+by the Tegra XUSB pad controller.
+
+Required properties:
+--------------------
+ - compatible: Should be "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: XHCI host interrupt.
+ - clocks: Must contain an entry for each entry in clock-names.
+   See ../clock/clock-bindings.txt for details.
+ - clock-names: Must include the following entries:
+    - xusb_host
+    - xusb_falcon_src
+    - xusb_ss
+    - xusb_ss_src
+    - xusb_hs_src
+    - xusb_fs_src
+    - pll_u_480m
+    - clk_m
+    - pll_e
+ - resets: Must contain an entry for each entry in reset-names.
+   See ../reset/reset.txt for details.
+ - reset-names: Must include the following entries:
+   - xusb_host
+   - xusb_ss
+ - nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
+
+Optional properties:
+--------------------
+ - phys: Must contain an entry for each entry in phy-names.
+   See ../phy/phy-bindings.txt for details.
+ - phy-names: Should include an entry for each PHY used by the controller.
+   May be a subset of the following:
+    - utmi-{0,1,2}
+    - hsic-{0,1}
+    - usb3-{0,1}
+ - s1p05v-supply: 1.05V supply regulator.
+ - s1p8v-supply: 1.8V supply regulator.
+ - s3p3v-supply: 3.3V supply regulator.
+
+Example:
+--------
+	usb at 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>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>,
+			 <&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_host", "xusb_falcon_src", "xusb_ss",
+			      "xusb_ss_src", "xusb_hs_src", "xusb_fs_src",
+			      "pll_u_480m", "clk_m", "pll_e";
+		resets = <&tegra_car 89>, <&tegra_car 156>;
+		reset-names = "xusb_host", "xusb_ss";
+		nvidia,xusb-mbox = <&mbox>;
+		phys = <&padctl TEGRA_XUSB_PADCTL_UTMI_P1>, /* mini-PCIe USB */
+		       <&padctl TEGRA_XUSB_PADCTL_UTMI_P2>, /* USB A */
+		       <&padctl TEGRA_XUSB_PADCTL_USB3_P0>; /* USB A */
+		phy-names = "utmi-1", "utmi-2", "usb3-0";
+		s1p05v-supply = <&vdd_1v05_run>;
+		s3p3v-supply = <&vdd_3v3_lp0>;
+		s1p8v-supply = <&vddio_1v8>;
+	};
-- 
2.0.0.526.g5318336

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-06-18  6:16 ` Andrew Bresticker
  (?)
@ 2014-06-18  6:16     ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Add support for the on-chip XHCI host controller present on Tegra 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-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
  Bharath Yadav <byadav-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>

Signed-off-by: Andrew Bresticker <abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 drivers/usb/host/Kconfig      |  12 +
 drivers/usb/host/Makefile     |   2 +
 drivers/usb/host/xhci-tegra.c | 900 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 914 insertions(+)
 create mode 100644 drivers/usb/host/xhci-tegra.c

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 61b7817..a8fb138 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -37,6 +37,18 @@ config USB_XHCI_MVEBU
 	  Say 'Y' to enable the support for the xHCI host controller
 	  found in Marvell Armada 375/38x ARM SOCs.
 
+config USB_XHCI_TEGRA
+	tristate "NVIDIA Tegra XHCI support"
+	depends on ARCH_TEGRA
+	select PINCTRL_TEGRA_XUSB
+	select TEGRA_XUSB_MBOX
+	select FW_LOADER
+	---help---
+	  Enables support for the on-chip XHCI controller present on NVIDIA
+	  Tegra124 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 af89a90..cbba340 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -41,6 +41,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..609374e
--- /dev/null
+++ b/drivers/usb/host/xhci-tegra.c
@@ -0,0 +1,900 @@
+/*
+ * 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/tegra-xusb-mbox.h>
+
+#include "xhci.h"
+
+#define TEGRA_XHCI_UTMI_PHYS 3
+#define TEGRA_XHCI_HSIC_PHYS 2
+#define TEGRA_XHCI_USB3_PHYS 2
+#define TEGRA_XHCI_MAX_PHYS (TEGRA_XHCI_UTMI_PHYS + TEGRA_XHCI_HSIC_PHYS + \
+			     TEGRA_XHCI_USB3_PHYS)
+
+#define TEGRA_XHCI_SS_CLK_HIGH_SPEED 120000000
+#define TEGRA_XHCI_SS_CLK_LOW_SPEED 12000000
+
+/* FPCI CFG registers */
+#define XUSB_CFG_1				0x004
+#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				0x010
+#define XUSB_CFG_ARU_C11_CSBRANGE		0x41c
+#define XUSB_CFG_CSB_BASE_ADDR			0x800
+
+/* IPFS registers */
+#define IPFS_XUSB_HOST_CONFIGURATION_0		0x180
+#define  IPFS_EN_FPCI				BIT(0)
+#define IPFS_XUSB_HOST_INTR_MASK_0		0x188
+#define  IPFS_IP_INT_MASK			BIT(16)
+#define IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0	0x1bc
+
+#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
+
+/* 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)
+
+#define IMEM_BLOCK_SIZE				256
+
+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 usb_hcd *hcd;
+
+	int irq;
+
+	void __iomem *fpci_base;
+	void __iomem *ipfs_base;
+
+	const struct tegra_xhci_soc_config *soc_config;
+
+	struct notifier_block mbox_nb;
+	struct tegra_xusb_mbox *mbox;
+
+	struct regulator *s1p05v_reg;
+	struct regulator *s3p3v_reg;
+	struct regulator *s1p8v_reg;
+
+	struct clk *host_clk;
+	struct clk *falc_clk;
+	struct clk *ss_clk;
+	struct clk *ss_src_clk;
+	struct clk *hs_src_clk;
+	struct clk *fs_src_clk;
+	struct clk *pll_u_480m;
+	struct clk *clk_m;
+	struct clk *pll_e;
+
+	struct reset_control *host_rst;
+	struct reset_control *ss_rst;
+
+	struct phy *phys[TEGRA_XHCI_MAX_PHYS];
+
+	/* Firmware loading related */
+	void *fw_data;
+	size_t fw_size;
+	dma_addr_t fw_dma_addr;
+	bool fw_loaded;
+};
+
+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->hcd->rsrc_start;
+	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_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_set_ss_clk(struct tegra_xhci_hcd *tegra,
+				 unsigned long rate)
+{
+	unsigned long new_parent_rate, old_parent_rate;
+	int ret, div;
+	struct clk *clk = tegra->ss_src_clk;
+
+	if (clk_get_rate(clk) == rate)
+		return 0;
+
+	switch (rate) {
+	case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
+		/* Reparent to PLLU_480M. Set div first to avoid overclocking */
+		old_parent_rate = clk_get_rate(clk_get_parent(clk));
+		new_parent_rate = clk_get_rate(tegra->pll_u_480m);
+		div = new_parent_rate / rate;
+		ret = clk_set_rate(clk, old_parent_rate / div);
+		if (ret)
+			return ret;
+		ret = clk_set_parent(clk, tegra->pll_u_480m);
+		if (ret)
+			return ret;
+		break;
+	case TEGRA_XHCI_SS_CLK_LOW_SPEED:
+		/* Reparent to CLK_M */
+		ret = clk_set_parent(clk, tegra->clk_m);
+		if (ret)
+			return ret;
+		ret = clk_set_rate(clk, rate);
+		if (ret)
+			return ret;
+		break;
+	default:
+		dev_err(tegra->dev, "Invalid SS rate: %lu\n", rate);
+		return -EINVAL;
+	}
+
+	if (clk_get_rate(clk) != rate) {
+		dev_err(tegra->dev, "SS clock doesn't match requested rate\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra_xhci_clk_enable(struct tegra_xhci_hcd *tegra)
+{
+	clk_prepare_enable(tegra->pll_e);
+	clk_prepare_enable(tegra->host_clk);
+	clk_prepare_enable(tegra->ss_clk);
+	clk_prepare_enable(tegra->falc_clk);
+	clk_prepare_enable(tegra->fs_src_clk);
+	clk_prepare_enable(tegra->hs_src_clk);
+
+	return tegra_xhci_set_ss_clk(tegra, TEGRA_XHCI_SS_CLK_HIGH_SPEED);
+}
+
+static void tegra_xhci_clk_disable(struct tegra_xhci_hcd *tegra)
+{
+	clk_disable_unprepare(tegra->pll_e);
+	clk_disable_unprepare(tegra->host_clk);
+	clk_disable_unprepare(tegra->ss_clk);
+	clk_disable_unprepare(tegra->falc_clk);
+	clk_disable_unprepare(tegra->fs_src_clk);
+	clk_disable_unprepare(tegra->hs_src_clk);
+}
+
+static int tegra_xhci_regulator_enable(struct tegra_xhci_hcd *tegra)
+{
+	int ret;
+
+	ret = regulator_enable(tegra->s3p3v_reg);
+	if (ret < 0)
+		return ret;
+	ret = regulator_enable(tegra->s1p8v_reg);
+	if (ret < 0)
+		goto disable_s3p3v;
+	ret = regulator_enable(tegra->s1p05v_reg);
+	if (ret < 0)
+		goto disable_s1p8v;
+
+	return 0;
+
+disable_s1p8v:
+	regulator_disable(tegra->s1p8v_reg);
+disable_s3p3v:
+	regulator_disable(tegra->s3p3v_reg);
+	return ret;
+}
+
+static void tegra_xhci_regulator_disable(struct tegra_xhci_hcd *tegra)
+{
+	regulator_disable(tegra->s1p05v_reg);
+	regulator_disable(tegra->s1p8v_reg);
+	regulator_disable(tegra->s3p3v_reg);
+}
+
+static int tegra_xhci_phy_enable(struct tegra_xhci_hcd *tegra)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tegra->phys); i++) {
+		ret = phy_init(tegra->phys[i]);
+		if (ret)
+			goto disable_phy;
+		ret = phy_power_on(tegra->phys[i]);
+		if (ret) {
+			phy_exit(tegra->phys[i]);
+			goto disable_phy;
+		}
+	}
+
+	return 0;
+disable_phy:
+	for (i = i - 1; i >= 0; i--) {
+		phy_power_off(tegra->phys[i]);
+		phy_exit(tegra->phys[i]);
+	}
+	return ret;
+}
+
+static void tegra_xhci_phy_disable(struct tegra_xhci_hcd *tegra)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tegra->phys); i++) {
+		phy_power_off(tegra->phys[i]);
+		phy_exit(tegra->phys[i]);
+	}
+}
+
+static int tegra_xhci_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 tegra_xusb_mbox_msg *msg = (struct tegra_xusb_mbox_msg *)p;
+	int ret;
+
+	switch (event) {
+	case MBOX_CMD_INC_SSPI_CLOCK:
+	case MBOX_CMD_DEC_SSPI_CLOCK:
+		ret = tegra_xhci_set_ss_clk(tegra, msg->data_in * 1000);
+		msg->data_out = clk_get_rate(tegra->ss_src_clk) / 1000;
+		if (ret)
+			msg->cmd_out = MBOX_CMD_NAK;
+		else
+			msg->cmd_out = MBOX_CMD_ACK;
+		return NOTIFY_STOP;
+	case MBOX_CMD_INC_FALC_CLOCK:
+	case MBOX_CMD_DEC_FALC_CLOCK:
+		msg->data_out = clk_get_rate(tegra->falc_clk) / 1000;
+		if (msg->data_in != msg->data_out)
+			msg->cmd_out = MBOX_CMD_NAK;
+		else
+			msg->cmd_out = 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 void tegra_xhci_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+	xhci->quirks |= XHCI_PLAT;
+}
+
+static int tegra_xhci_setup(struct usb_hcd *hcd)
+{
+	return xhci_gen_setup(hcd, tegra_xhci_quirks);
+}
+
+static const struct hc_driver tegra_xhci_hc_driver = {
+	.description =		"tegra-xhci-hcd",
+	.product_desc =		"Tegra xHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct xhci_hcd *),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			xhci_irq,
+	.flags =		HCD_MEMORY | HCD_USB3 | HCD_SHARED,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		tegra_xhci_setup,
+	.start =		xhci_run,
+	.stop =			xhci_stop,
+	.shutdown =		xhci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		xhci_urb_enqueue,
+	.urb_dequeue =		xhci_urb_dequeue,
+	.alloc_dev =		xhci_alloc_dev,
+	.free_dev =		xhci_free_dev,
+	.alloc_streams =	xhci_alloc_streams,
+	.free_streams =		xhci_free_streams,
+	.add_endpoint =		xhci_add_endpoint,
+	.drop_endpoint =	xhci_drop_endpoint,
+	.endpoint_reset =	xhci_endpoint_reset,
+	.check_bandwidth =	xhci_check_bandwidth,
+	.reset_bandwidth =	xhci_reset_bandwidth,
+	.address_device =	xhci_address_device,
+	.enable_device =	xhci_enable_device,
+	.update_hub_device =	xhci_update_hub_device,
+	.reset_device =		xhci_discover_or_reset_device,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	xhci_get_frame,
+
+	/* Root hub support */
+	.hub_control =		xhci_hub_control,
+	.hub_status_data =	xhci_hub_status_data,
+	.bus_suspend =		xhci_bus_suspend,
+	.bus_resume =		xhci_bus_resume,
+};
+
+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,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 xhci_hcd *xhci = NULL;
+	struct tegra_xhci_fw_cfgtbl *cfg_tbl;
+	int ret;
+
+	if (!fw)
+		goto put_usb2_hcd;
+
+	/* 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)
+		goto put_usb2_hcd;
+	memcpy(tegra->fw_data, fw->data, tegra->fw_size);
+
+	ret = tegra_xhci_load_firmware(tegra);
+	if (ret < 0)
+		goto put_usb2_hcd;
+
+	ret = usb_add_hcd(tegra->hcd, tegra->irq, IRQF_SHARED);
+	if (ret < 0)
+		goto put_usb2_hcd;
+	device_wakeup_enable(tegra->hcd->self.controller);
+
+	/*
+	 * USB 2.0 roothub is stored in drvdata now. Swap it with the Tegra HCD.
+	 */
+	tegra->hcd = dev_get_drvdata(dev);
+	dev_set_drvdata(dev, tegra);
+	xhci = hcd_to_xhci(tegra->hcd);
+	xhci->shared_hcd = usb_create_shared_hcd(&tegra_xhci_hc_driver,
+						 dev, dev_name(dev),
+						 tegra->hcd);
+	if (!xhci->shared_hcd)
+		goto dealloc_usb2_hcd;
+
+	/*
+	 * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
+	 * is called by usb_add_hcd().
+	 */
+	*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
+	ret = usb_add_hcd(xhci->shared_hcd, tegra->irq, IRQF_SHARED);
+	if (ret < 0)
+		goto put_usb3_hcd;
+
+	/* Enable firmware messages from controller */
+	ret = tegra_xusb_mbox_send(tegra->mbox, MBOX_CMD_MSG_ENABLED, 0);
+	if (ret < 0)
+		goto dealloc_usb3_hcd;
+
+	tegra->fw_loaded = true;
+	release_firmware(fw);
+	return;
+
+dealloc_usb3_hcd:
+	usb_remove_hcd(xhci->shared_hcd);
+put_usb3_hcd:
+	usb_put_hcd(xhci->shared_hcd);
+dealloc_usb2_hcd:
+	usb_remove_hcd(tegra->hcd);
+	kfree(xhci);
+put_usb2_hcd:
+	usb_put_hcd(tegra->hcd);
+	tegra->hcd = NULL;
+	release_firmware(fw);
+}
+
+static int tegra_xhci_probe(struct platform_device *pdev)
+{
+	struct tegra_xhci_hcd *tegra;
+	struct usb_hcd *hcd;
+	struct resource	*res;
+	struct phy *phy;
+	const struct of_device_id *match;
+	int ret, i, j;
+
+	BUILD_BUG_ON(sizeof(struct tegra_xhci_fw_cfgtbl) != 256);
+
+	tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
+	if (!tegra)
+		return -ENOMEM;
+	tegra->dev = &pdev->dev;
+	platform_set_drvdata(pdev, tegra);
+
+	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;
+
+	hcd = usb_create_hcd(&tegra_xhci_hc_driver, &pdev->dev,
+				    dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+	tegra->hcd = hcd;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(hcd->regs)) {
+		ret = PTR_ERR(hcd->regs);
+		goto put_hcd;
+	}
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	tegra->fpci_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tegra->fpci_base)) {
+		ret = PTR_ERR(tegra->fpci_base);
+		goto put_hcd;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tegra->ipfs_base)) {
+		ret = PTR_ERR(tegra->ipfs_base);
+		goto put_hcd;
+	}
+
+	tegra->irq = platform_get_irq(pdev, 0);
+	if (tegra->irq < 0) {
+		ret = tegra->irq;
+		goto put_hcd;
+	}
+
+	tegra->host_rst = devm_reset_control_get(&pdev->dev, "xusb_host");
+	if (IS_ERR(tegra->host_rst)) {
+		ret = PTR_ERR(tegra->host_rst);
+		goto put_hcd;
+	}
+	tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss");
+	if (IS_ERR(tegra->ss_rst)) {
+		ret = PTR_ERR(tegra->ss_rst);
+		goto put_hcd;
+	}
+
+	tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
+	if (IS_ERR(tegra->host_clk)) {
+		ret = PTR_ERR(tegra->host_clk);
+		goto put_hcd;
+	}
+	tegra->falc_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src");
+	if (IS_ERR(tegra->falc_clk)) {
+		ret = PTR_ERR(tegra->falc_clk);
+		goto put_hcd;
+	}
+	tegra->ss_clk = devm_clk_get(&pdev->dev, "xusb_ss");
+	if (IS_ERR(tegra->ss_clk)) {
+		ret = PTR_ERR(tegra->ss_clk);
+		goto put_hcd;
+	}
+	tegra->ss_src_clk = devm_clk_get(&pdev->dev, "xusb_ss_src");
+	if (IS_ERR(tegra->ss_src_clk)) {
+		ret = PTR_ERR(tegra->ss_src_clk);
+		goto put_hcd;
+	}
+	tegra->hs_src_clk = devm_clk_get(&pdev->dev, "xusb_hs_src");
+	if (IS_ERR(tegra->hs_src_clk)) {
+		ret = PTR_ERR(tegra->hs_src_clk);
+		goto put_hcd;
+	}
+	tegra->fs_src_clk = devm_clk_get(&pdev->dev, "xusb_fs_src");
+	if (IS_ERR(tegra->fs_src_clk)) {
+		ret = PTR_ERR(tegra->fs_src_clk);
+		goto put_hcd;
+	}
+	tegra->pll_u_480m = devm_clk_get(&pdev->dev, "pll_u_480m");
+	if (IS_ERR(tegra->pll_u_480m)) {
+		ret = PTR_ERR(tegra->pll_u_480m);
+		goto put_hcd;
+	}
+	tegra->clk_m = devm_clk_get(&pdev->dev, "clk_m");
+	if (IS_ERR(tegra->clk_m)) {
+		ret = PTR_ERR(tegra->clk_m);
+		goto put_hcd;
+	}
+	tegra->pll_e = devm_clk_get(&pdev->dev, "pll_e");
+	if (IS_ERR(tegra->pll_e)) {
+		ret = PTR_ERR(tegra->pll_e);
+		goto put_hcd;
+	}
+	ret = tegra_xhci_clk_enable(tegra);
+	if (ret)
+		goto put_hcd;
+
+	tegra->s3p3v_reg = devm_regulator_get(&pdev->dev, "s3p3v");
+	if (IS_ERR(tegra->s3p3v_reg)) {
+		ret = PTR_ERR(tegra->s3p3v_reg);
+		dev_info(&pdev->dev, "s3p3v get failed: %d\n", ret);
+		goto disable_clk;
+	}
+	tegra->s1p8v_reg = devm_regulator_get(&pdev->dev, "s1p8v");
+	if (IS_ERR(tegra->s1p8v_reg)) {
+		ret = PTR_ERR(tegra->s1p8v_reg);
+		dev_info(&pdev->dev, "s1p8v get failed: %d\n", ret);
+		goto disable_clk;
+	}
+	tegra->s1p05v_reg = devm_regulator_get(&pdev->dev, "s1p05v");
+	if (IS_ERR(tegra->s1p05v_reg)) {
+		ret = PTR_ERR(tegra->s1p05v_reg);
+		dev_info(&pdev->dev, "s1p05v get failed: %d\n", ret);
+		goto disable_clk;
+	}
+	ret = tegra_xhci_regulator_enable(tegra);
+	if (ret)
+		goto disable_clk;
+
+	tegra->mbox = tegra_xusb_mbox_lookup_by_phandle(pdev->dev.of_node,
+							"nvidia,xusb-mbox");
+	if (IS_ERR(tegra->mbox))
+		goto disable_regulator;
+	tegra->mbox_nb.notifier_call = tegra_xhci_mbox_notifier;
+	tegra_xusb_mbox_register_notifier(tegra->mbox, &tegra->mbox_nb);
+
+	j = 0;
+	for (i = 0; i < TEGRA_XHCI_UTMI_PHYS; i++) {
+		char prop[sizeof("utmi-N")];
+
+		sprintf(prop, "utmi-%d", i);
+		phy = devm_phy_optional_get(&pdev->dev, prop);
+		if (IS_ERR(phy)) {
+			ret = PTR_ERR(phy);
+			goto unregister_notifier;
+		}
+		tegra->phys[j++] = phy;
+	}
+	for (i = 0; i < TEGRA_XHCI_HSIC_PHYS; i++) {
+		char prop[sizeof("hsic-N")];
+
+		sprintf(prop, "hsic-%d", i);
+		phy = devm_phy_optional_get(&pdev->dev, prop);
+		if (IS_ERR(phy)) {
+			ret = PTR_ERR(phy);
+			goto unregister_notifier;
+		}
+		tegra->phys[j++] = phy;
+	}
+	for (i = 0; i < TEGRA_XHCI_USB3_PHYS; i++) {
+		char prop[sizeof("usb3-N")];
+
+		sprintf(prop, "usb3-%d", i);
+		phy = devm_phy_optional_get(&pdev->dev, prop);
+		if (IS_ERR(phy)) {
+			ret = PTR_ERR(phy);
+			goto unregister_notifier;
+		}
+		tegra->phys[j++] = phy;
+	}
+
+	/* Setup IPFS access and BAR0 space */
+	tegra_xhci_cfg(tegra);
+
+	ret = tegra_xhci_phy_enable(tegra);
+	if (ret < 0)
+		goto unregister_notifier;
+
+	ret = request_firmware_nowait(THIS_MODULE, true,
+				      tegra->soc_config->firmware_file,
+				      tegra->dev, GFP_KERNEL, tegra,
+				      tegra_xhci_probe_finish);
+	if (ret < 0)
+		goto disable_phy;
+
+	return 0;
+
+disable_phy:
+	tegra_xhci_phy_disable(tegra);
+unregister_notifier:
+	tegra_xusb_mbox_unregister_notifier(tegra->mbox, &tegra->mbox_nb);
+disable_regulator:
+	tegra_xhci_regulator_disable(tegra);
+disable_clk:
+	tegra_xhci_clk_disable(tegra);
+put_hcd:
+	usb_put_hcd(hcd);
+	return ret;
+}
+
+static int tegra_xhci_remove(struct platform_device *pdev)
+{
+	struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+	struct usb_hcd *hcd = tegra->hcd;
+	struct xhci_hcd *xhci;
+
+	if (tegra->fw_loaded) {
+		xhci = hcd_to_xhci(hcd);
+		usb_remove_hcd(xhci->shared_hcd);
+		usb_put_hcd(xhci->shared_hcd);
+		usb_remove_hcd(hcd);
+		usb_put_hcd(hcd);
+		kfree(xhci);
+	} else if (hcd) {
+		/* Unbound after probe(), but before firmware loading. */
+		usb_put_hcd(hcd);
+	}
+
+	if (tegra->fw_data)
+		dma_free_coherent(tegra->dev, tegra->fw_size, tegra->fw_data,
+				  tegra->fw_dma_addr);
+
+	tegra_xusb_mbox_unregister_notifier(tegra->mbox, &tegra->mbox_nb);
+	tegra_xhci_phy_disable(tegra);
+	tegra_xhci_regulator_disable(tegra);
+	tegra_xhci_clk_disable(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");
-- 
2.0.0.526.g5318336

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-18  6:16     ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Add support for the on-chip XHCI host controller present on Tegra 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>
---
 drivers/usb/host/Kconfig      |  12 +
 drivers/usb/host/Makefile     |   2 +
 drivers/usb/host/xhci-tegra.c | 900 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 914 insertions(+)
 create mode 100644 drivers/usb/host/xhci-tegra.c

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 61b7817..a8fb138 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -37,6 +37,18 @@ config USB_XHCI_MVEBU
 	  Say 'Y' to enable the support for the xHCI host controller
 	  found in Marvell Armada 375/38x ARM SOCs.
 
+config USB_XHCI_TEGRA
+	tristate "NVIDIA Tegra XHCI support"
+	depends on ARCH_TEGRA
+	select PINCTRL_TEGRA_XUSB
+	select TEGRA_XUSB_MBOX
+	select FW_LOADER
+	---help---
+	  Enables support for the on-chip XHCI controller present on NVIDIA
+	  Tegra124 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 af89a90..cbba340 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -41,6 +41,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..609374e
--- /dev/null
+++ b/drivers/usb/host/xhci-tegra.c
@@ -0,0 +1,900 @@
+/*
+ * 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/tegra-xusb-mbox.h>
+
+#include "xhci.h"
+
+#define TEGRA_XHCI_UTMI_PHYS 3
+#define TEGRA_XHCI_HSIC_PHYS 2
+#define TEGRA_XHCI_USB3_PHYS 2
+#define TEGRA_XHCI_MAX_PHYS (TEGRA_XHCI_UTMI_PHYS + TEGRA_XHCI_HSIC_PHYS + \
+			     TEGRA_XHCI_USB3_PHYS)
+
+#define TEGRA_XHCI_SS_CLK_HIGH_SPEED 120000000
+#define TEGRA_XHCI_SS_CLK_LOW_SPEED 12000000
+
+/* FPCI CFG registers */
+#define XUSB_CFG_1				0x004
+#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				0x010
+#define XUSB_CFG_ARU_C11_CSBRANGE		0x41c
+#define XUSB_CFG_CSB_BASE_ADDR			0x800
+
+/* IPFS registers */
+#define IPFS_XUSB_HOST_CONFIGURATION_0		0x180
+#define  IPFS_EN_FPCI				BIT(0)
+#define IPFS_XUSB_HOST_INTR_MASK_0		0x188
+#define  IPFS_IP_INT_MASK			BIT(16)
+#define IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0	0x1bc
+
+#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
+
+/* 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)
+
+#define IMEM_BLOCK_SIZE				256
+
+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 usb_hcd *hcd;
+
+	int irq;
+
+	void __iomem *fpci_base;
+	void __iomem *ipfs_base;
+
+	const struct tegra_xhci_soc_config *soc_config;
+
+	struct notifier_block mbox_nb;
+	struct tegra_xusb_mbox *mbox;
+
+	struct regulator *s1p05v_reg;
+	struct regulator *s3p3v_reg;
+	struct regulator *s1p8v_reg;
+
+	struct clk *host_clk;
+	struct clk *falc_clk;
+	struct clk *ss_clk;
+	struct clk *ss_src_clk;
+	struct clk *hs_src_clk;
+	struct clk *fs_src_clk;
+	struct clk *pll_u_480m;
+	struct clk *clk_m;
+	struct clk *pll_e;
+
+	struct reset_control *host_rst;
+	struct reset_control *ss_rst;
+
+	struct phy *phys[TEGRA_XHCI_MAX_PHYS];
+
+	/* Firmware loading related */
+	void *fw_data;
+	size_t fw_size;
+	dma_addr_t fw_dma_addr;
+	bool fw_loaded;
+};
+
+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->hcd->rsrc_start;
+	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_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_set_ss_clk(struct tegra_xhci_hcd *tegra,
+				 unsigned long rate)
+{
+	unsigned long new_parent_rate, old_parent_rate;
+	int ret, div;
+	struct clk *clk = tegra->ss_src_clk;
+
+	if (clk_get_rate(clk) == rate)
+		return 0;
+
+	switch (rate) {
+	case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
+		/* Reparent to PLLU_480M. Set div first to avoid overclocking */
+		old_parent_rate = clk_get_rate(clk_get_parent(clk));
+		new_parent_rate = clk_get_rate(tegra->pll_u_480m);
+		div = new_parent_rate / rate;
+		ret = clk_set_rate(clk, old_parent_rate / div);
+		if (ret)
+			return ret;
+		ret = clk_set_parent(clk, tegra->pll_u_480m);
+		if (ret)
+			return ret;
+		break;
+	case TEGRA_XHCI_SS_CLK_LOW_SPEED:
+		/* Reparent to CLK_M */
+		ret = clk_set_parent(clk, tegra->clk_m);
+		if (ret)
+			return ret;
+		ret = clk_set_rate(clk, rate);
+		if (ret)
+			return ret;
+		break;
+	default:
+		dev_err(tegra->dev, "Invalid SS rate: %lu\n", rate);
+		return -EINVAL;
+	}
+
+	if (clk_get_rate(clk) != rate) {
+		dev_err(tegra->dev, "SS clock doesn't match requested rate\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra_xhci_clk_enable(struct tegra_xhci_hcd *tegra)
+{
+	clk_prepare_enable(tegra->pll_e);
+	clk_prepare_enable(tegra->host_clk);
+	clk_prepare_enable(tegra->ss_clk);
+	clk_prepare_enable(tegra->falc_clk);
+	clk_prepare_enable(tegra->fs_src_clk);
+	clk_prepare_enable(tegra->hs_src_clk);
+
+	return tegra_xhci_set_ss_clk(tegra, TEGRA_XHCI_SS_CLK_HIGH_SPEED);
+}
+
+static void tegra_xhci_clk_disable(struct tegra_xhci_hcd *tegra)
+{
+	clk_disable_unprepare(tegra->pll_e);
+	clk_disable_unprepare(tegra->host_clk);
+	clk_disable_unprepare(tegra->ss_clk);
+	clk_disable_unprepare(tegra->falc_clk);
+	clk_disable_unprepare(tegra->fs_src_clk);
+	clk_disable_unprepare(tegra->hs_src_clk);
+}
+
+static int tegra_xhci_regulator_enable(struct tegra_xhci_hcd *tegra)
+{
+	int ret;
+
+	ret = regulator_enable(tegra->s3p3v_reg);
+	if (ret < 0)
+		return ret;
+	ret = regulator_enable(tegra->s1p8v_reg);
+	if (ret < 0)
+		goto disable_s3p3v;
+	ret = regulator_enable(tegra->s1p05v_reg);
+	if (ret < 0)
+		goto disable_s1p8v;
+
+	return 0;
+
+disable_s1p8v:
+	regulator_disable(tegra->s1p8v_reg);
+disable_s3p3v:
+	regulator_disable(tegra->s3p3v_reg);
+	return ret;
+}
+
+static void tegra_xhci_regulator_disable(struct tegra_xhci_hcd *tegra)
+{
+	regulator_disable(tegra->s1p05v_reg);
+	regulator_disable(tegra->s1p8v_reg);
+	regulator_disable(tegra->s3p3v_reg);
+}
+
+static int tegra_xhci_phy_enable(struct tegra_xhci_hcd *tegra)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tegra->phys); i++) {
+		ret = phy_init(tegra->phys[i]);
+		if (ret)
+			goto disable_phy;
+		ret = phy_power_on(tegra->phys[i]);
+		if (ret) {
+			phy_exit(tegra->phys[i]);
+			goto disable_phy;
+		}
+	}
+
+	return 0;
+disable_phy:
+	for (i = i - 1; i >= 0; i--) {
+		phy_power_off(tegra->phys[i]);
+		phy_exit(tegra->phys[i]);
+	}
+	return ret;
+}
+
+static void tegra_xhci_phy_disable(struct tegra_xhci_hcd *tegra)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tegra->phys); i++) {
+		phy_power_off(tegra->phys[i]);
+		phy_exit(tegra->phys[i]);
+	}
+}
+
+static int tegra_xhci_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 tegra_xusb_mbox_msg *msg = (struct tegra_xusb_mbox_msg *)p;
+	int ret;
+
+	switch (event) {
+	case MBOX_CMD_INC_SSPI_CLOCK:
+	case MBOX_CMD_DEC_SSPI_CLOCK:
+		ret = tegra_xhci_set_ss_clk(tegra, msg->data_in * 1000);
+		msg->data_out = clk_get_rate(tegra->ss_src_clk) / 1000;
+		if (ret)
+			msg->cmd_out = MBOX_CMD_NAK;
+		else
+			msg->cmd_out = MBOX_CMD_ACK;
+		return NOTIFY_STOP;
+	case MBOX_CMD_INC_FALC_CLOCK:
+	case MBOX_CMD_DEC_FALC_CLOCK:
+		msg->data_out = clk_get_rate(tegra->falc_clk) / 1000;
+		if (msg->data_in != msg->data_out)
+			msg->cmd_out = MBOX_CMD_NAK;
+		else
+			msg->cmd_out = 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 void tegra_xhci_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+	xhci->quirks |= XHCI_PLAT;
+}
+
+static int tegra_xhci_setup(struct usb_hcd *hcd)
+{
+	return xhci_gen_setup(hcd, tegra_xhci_quirks);
+}
+
+static const struct hc_driver tegra_xhci_hc_driver = {
+	.description =		"tegra-xhci-hcd",
+	.product_desc =		"Tegra xHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct xhci_hcd *),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			xhci_irq,
+	.flags =		HCD_MEMORY | HCD_USB3 | HCD_SHARED,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		tegra_xhci_setup,
+	.start =		xhci_run,
+	.stop =			xhci_stop,
+	.shutdown =		xhci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		xhci_urb_enqueue,
+	.urb_dequeue =		xhci_urb_dequeue,
+	.alloc_dev =		xhci_alloc_dev,
+	.free_dev =		xhci_free_dev,
+	.alloc_streams =	xhci_alloc_streams,
+	.free_streams =		xhci_free_streams,
+	.add_endpoint =		xhci_add_endpoint,
+	.drop_endpoint =	xhci_drop_endpoint,
+	.endpoint_reset =	xhci_endpoint_reset,
+	.check_bandwidth =	xhci_check_bandwidth,
+	.reset_bandwidth =	xhci_reset_bandwidth,
+	.address_device =	xhci_address_device,
+	.enable_device =	xhci_enable_device,
+	.update_hub_device =	xhci_update_hub_device,
+	.reset_device =		xhci_discover_or_reset_device,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	xhci_get_frame,
+
+	/* Root hub support */
+	.hub_control =		xhci_hub_control,
+	.hub_status_data =	xhci_hub_status_data,
+	.bus_suspend =		xhci_bus_suspend,
+	.bus_resume =		xhci_bus_resume,
+};
+
+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,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 xhci_hcd *xhci = NULL;
+	struct tegra_xhci_fw_cfgtbl *cfg_tbl;
+	int ret;
+
+	if (!fw)
+		goto put_usb2_hcd;
+
+	/* 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)
+		goto put_usb2_hcd;
+	memcpy(tegra->fw_data, fw->data, tegra->fw_size);
+
+	ret = tegra_xhci_load_firmware(tegra);
+	if (ret < 0)
+		goto put_usb2_hcd;
+
+	ret = usb_add_hcd(tegra->hcd, tegra->irq, IRQF_SHARED);
+	if (ret < 0)
+		goto put_usb2_hcd;
+	device_wakeup_enable(tegra->hcd->self.controller);
+
+	/*
+	 * USB 2.0 roothub is stored in drvdata now. Swap it with the Tegra HCD.
+	 */
+	tegra->hcd = dev_get_drvdata(dev);
+	dev_set_drvdata(dev, tegra);
+	xhci = hcd_to_xhci(tegra->hcd);
+	xhci->shared_hcd = usb_create_shared_hcd(&tegra_xhci_hc_driver,
+						 dev, dev_name(dev),
+						 tegra->hcd);
+	if (!xhci->shared_hcd)
+		goto dealloc_usb2_hcd;
+
+	/*
+	 * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
+	 * is called by usb_add_hcd().
+	 */
+	*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
+	ret = usb_add_hcd(xhci->shared_hcd, tegra->irq, IRQF_SHARED);
+	if (ret < 0)
+		goto put_usb3_hcd;
+
+	/* Enable firmware messages from controller */
+	ret = tegra_xusb_mbox_send(tegra->mbox, MBOX_CMD_MSG_ENABLED, 0);
+	if (ret < 0)
+		goto dealloc_usb3_hcd;
+
+	tegra->fw_loaded = true;
+	release_firmware(fw);
+	return;
+
+dealloc_usb3_hcd:
+	usb_remove_hcd(xhci->shared_hcd);
+put_usb3_hcd:
+	usb_put_hcd(xhci->shared_hcd);
+dealloc_usb2_hcd:
+	usb_remove_hcd(tegra->hcd);
+	kfree(xhci);
+put_usb2_hcd:
+	usb_put_hcd(tegra->hcd);
+	tegra->hcd = NULL;
+	release_firmware(fw);
+}
+
+static int tegra_xhci_probe(struct platform_device *pdev)
+{
+	struct tegra_xhci_hcd *tegra;
+	struct usb_hcd *hcd;
+	struct resource	*res;
+	struct phy *phy;
+	const struct of_device_id *match;
+	int ret, i, j;
+
+	BUILD_BUG_ON(sizeof(struct tegra_xhci_fw_cfgtbl) != 256);
+
+	tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
+	if (!tegra)
+		return -ENOMEM;
+	tegra->dev = &pdev->dev;
+	platform_set_drvdata(pdev, tegra);
+
+	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;
+
+	hcd = usb_create_hcd(&tegra_xhci_hc_driver, &pdev->dev,
+				    dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+	tegra->hcd = hcd;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(hcd->regs)) {
+		ret = PTR_ERR(hcd->regs);
+		goto put_hcd;
+	}
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	tegra->fpci_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tegra->fpci_base)) {
+		ret = PTR_ERR(tegra->fpci_base);
+		goto put_hcd;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tegra->ipfs_base)) {
+		ret = PTR_ERR(tegra->ipfs_base);
+		goto put_hcd;
+	}
+
+	tegra->irq = platform_get_irq(pdev, 0);
+	if (tegra->irq < 0) {
+		ret = tegra->irq;
+		goto put_hcd;
+	}
+
+	tegra->host_rst = devm_reset_control_get(&pdev->dev, "xusb_host");
+	if (IS_ERR(tegra->host_rst)) {
+		ret = PTR_ERR(tegra->host_rst);
+		goto put_hcd;
+	}
+	tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss");
+	if (IS_ERR(tegra->ss_rst)) {
+		ret = PTR_ERR(tegra->ss_rst);
+		goto put_hcd;
+	}
+
+	tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
+	if (IS_ERR(tegra->host_clk)) {
+		ret = PTR_ERR(tegra->host_clk);
+		goto put_hcd;
+	}
+	tegra->falc_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src");
+	if (IS_ERR(tegra->falc_clk)) {
+		ret = PTR_ERR(tegra->falc_clk);
+		goto put_hcd;
+	}
+	tegra->ss_clk = devm_clk_get(&pdev->dev, "xusb_ss");
+	if (IS_ERR(tegra->ss_clk)) {
+		ret = PTR_ERR(tegra->ss_clk);
+		goto put_hcd;
+	}
+	tegra->ss_src_clk = devm_clk_get(&pdev->dev, "xusb_ss_src");
+	if (IS_ERR(tegra->ss_src_clk)) {
+		ret = PTR_ERR(tegra->ss_src_clk);
+		goto put_hcd;
+	}
+	tegra->hs_src_clk = devm_clk_get(&pdev->dev, "xusb_hs_src");
+	if (IS_ERR(tegra->hs_src_clk)) {
+		ret = PTR_ERR(tegra->hs_src_clk);
+		goto put_hcd;
+	}
+	tegra->fs_src_clk = devm_clk_get(&pdev->dev, "xusb_fs_src");
+	if (IS_ERR(tegra->fs_src_clk)) {
+		ret = PTR_ERR(tegra->fs_src_clk);
+		goto put_hcd;
+	}
+	tegra->pll_u_480m = devm_clk_get(&pdev->dev, "pll_u_480m");
+	if (IS_ERR(tegra->pll_u_480m)) {
+		ret = PTR_ERR(tegra->pll_u_480m);
+		goto put_hcd;
+	}
+	tegra->clk_m = devm_clk_get(&pdev->dev, "clk_m");
+	if (IS_ERR(tegra->clk_m)) {
+		ret = PTR_ERR(tegra->clk_m);
+		goto put_hcd;
+	}
+	tegra->pll_e = devm_clk_get(&pdev->dev, "pll_e");
+	if (IS_ERR(tegra->pll_e)) {
+		ret = PTR_ERR(tegra->pll_e);
+		goto put_hcd;
+	}
+	ret = tegra_xhci_clk_enable(tegra);
+	if (ret)
+		goto put_hcd;
+
+	tegra->s3p3v_reg = devm_regulator_get(&pdev->dev, "s3p3v");
+	if (IS_ERR(tegra->s3p3v_reg)) {
+		ret = PTR_ERR(tegra->s3p3v_reg);
+		dev_info(&pdev->dev, "s3p3v get failed: %d\n", ret);
+		goto disable_clk;
+	}
+	tegra->s1p8v_reg = devm_regulator_get(&pdev->dev, "s1p8v");
+	if (IS_ERR(tegra->s1p8v_reg)) {
+		ret = PTR_ERR(tegra->s1p8v_reg);
+		dev_info(&pdev->dev, "s1p8v get failed: %d\n", ret);
+		goto disable_clk;
+	}
+	tegra->s1p05v_reg = devm_regulator_get(&pdev->dev, "s1p05v");
+	if (IS_ERR(tegra->s1p05v_reg)) {
+		ret = PTR_ERR(tegra->s1p05v_reg);
+		dev_info(&pdev->dev, "s1p05v get failed: %d\n", ret);
+		goto disable_clk;
+	}
+	ret = tegra_xhci_regulator_enable(tegra);
+	if (ret)
+		goto disable_clk;
+
+	tegra->mbox = tegra_xusb_mbox_lookup_by_phandle(pdev->dev.of_node,
+							"nvidia,xusb-mbox");
+	if (IS_ERR(tegra->mbox))
+		goto disable_regulator;
+	tegra->mbox_nb.notifier_call = tegra_xhci_mbox_notifier;
+	tegra_xusb_mbox_register_notifier(tegra->mbox, &tegra->mbox_nb);
+
+	j = 0;
+	for (i = 0; i < TEGRA_XHCI_UTMI_PHYS; i++) {
+		char prop[sizeof("utmi-N")];
+
+		sprintf(prop, "utmi-%d", i);
+		phy = devm_phy_optional_get(&pdev->dev, prop);
+		if (IS_ERR(phy)) {
+			ret = PTR_ERR(phy);
+			goto unregister_notifier;
+		}
+		tegra->phys[j++] = phy;
+	}
+	for (i = 0; i < TEGRA_XHCI_HSIC_PHYS; i++) {
+		char prop[sizeof("hsic-N")];
+
+		sprintf(prop, "hsic-%d", i);
+		phy = devm_phy_optional_get(&pdev->dev, prop);
+		if (IS_ERR(phy)) {
+			ret = PTR_ERR(phy);
+			goto unregister_notifier;
+		}
+		tegra->phys[j++] = phy;
+	}
+	for (i = 0; i < TEGRA_XHCI_USB3_PHYS; i++) {
+		char prop[sizeof("usb3-N")];
+
+		sprintf(prop, "usb3-%d", i);
+		phy = devm_phy_optional_get(&pdev->dev, prop);
+		if (IS_ERR(phy)) {
+			ret = PTR_ERR(phy);
+			goto unregister_notifier;
+		}
+		tegra->phys[j++] = phy;
+	}
+
+	/* Setup IPFS access and BAR0 space */
+	tegra_xhci_cfg(tegra);
+
+	ret = tegra_xhci_phy_enable(tegra);
+	if (ret < 0)
+		goto unregister_notifier;
+
+	ret = request_firmware_nowait(THIS_MODULE, true,
+				      tegra->soc_config->firmware_file,
+				      tegra->dev, GFP_KERNEL, tegra,
+				      tegra_xhci_probe_finish);
+	if (ret < 0)
+		goto disable_phy;
+
+	return 0;
+
+disable_phy:
+	tegra_xhci_phy_disable(tegra);
+unregister_notifier:
+	tegra_xusb_mbox_unregister_notifier(tegra->mbox, &tegra->mbox_nb);
+disable_regulator:
+	tegra_xhci_regulator_disable(tegra);
+disable_clk:
+	tegra_xhci_clk_disable(tegra);
+put_hcd:
+	usb_put_hcd(hcd);
+	return ret;
+}
+
+static int tegra_xhci_remove(struct platform_device *pdev)
+{
+	struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+	struct usb_hcd *hcd = tegra->hcd;
+	struct xhci_hcd *xhci;
+
+	if (tegra->fw_loaded) {
+		xhci = hcd_to_xhci(hcd);
+		usb_remove_hcd(xhci->shared_hcd);
+		usb_put_hcd(xhci->shared_hcd);
+		usb_remove_hcd(hcd);
+		usb_put_hcd(hcd);
+		kfree(xhci);
+	} else if (hcd) {
+		/* Unbound after probe(), but before firmware loading. */
+		usb_put_hcd(hcd);
+	}
+
+	if (tegra->fw_data)
+		dma_free_coherent(tegra->dev, tegra->fw_size, tegra->fw_data,
+				  tegra->fw_dma_addr);
+
+	tegra_xusb_mbox_unregister_notifier(tegra->mbox, &tegra->mbox_nb);
+	tegra_xhci_phy_disable(tegra);
+	tegra_xhci_regulator_disable(tegra);
+	tegra_xhci_clk_disable(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");
-- 
2.0.0.526.g5318336


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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-18  6:16     ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

Add support for the on-chip XHCI host controller present on Tegra 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>
---
 drivers/usb/host/Kconfig      |  12 +
 drivers/usb/host/Makefile     |   2 +
 drivers/usb/host/xhci-tegra.c | 900 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 914 insertions(+)
 create mode 100644 drivers/usb/host/xhci-tegra.c

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 61b7817..a8fb138 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -37,6 +37,18 @@ config USB_XHCI_MVEBU
 	  Say 'Y' to enable the support for the xHCI host controller
 	  found in Marvell Armada 375/38x ARM SOCs.
 
+config USB_XHCI_TEGRA
+	tristate "NVIDIA Tegra XHCI support"
+	depends on ARCH_TEGRA
+	select PINCTRL_TEGRA_XUSB
+	select TEGRA_XUSB_MBOX
+	select FW_LOADER
+	---help---
+	  Enables support for the on-chip XHCI controller present on NVIDIA
+	  Tegra124 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 af89a90..cbba340 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -41,6 +41,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..609374e
--- /dev/null
+++ b/drivers/usb/host/xhci-tegra.c
@@ -0,0 +1,900 @@
+/*
+ * 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/tegra-xusb-mbox.h>
+
+#include "xhci.h"
+
+#define TEGRA_XHCI_UTMI_PHYS 3
+#define TEGRA_XHCI_HSIC_PHYS 2
+#define TEGRA_XHCI_USB3_PHYS 2
+#define TEGRA_XHCI_MAX_PHYS (TEGRA_XHCI_UTMI_PHYS + TEGRA_XHCI_HSIC_PHYS + \
+			     TEGRA_XHCI_USB3_PHYS)
+
+#define TEGRA_XHCI_SS_CLK_HIGH_SPEED 120000000
+#define TEGRA_XHCI_SS_CLK_LOW_SPEED 12000000
+
+/* FPCI CFG registers */
+#define XUSB_CFG_1				0x004
+#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				0x010
+#define XUSB_CFG_ARU_C11_CSBRANGE		0x41c
+#define XUSB_CFG_CSB_BASE_ADDR			0x800
+
+/* IPFS registers */
+#define IPFS_XUSB_HOST_CONFIGURATION_0		0x180
+#define  IPFS_EN_FPCI				BIT(0)
+#define IPFS_XUSB_HOST_INTR_MASK_0		0x188
+#define  IPFS_IP_INT_MASK			BIT(16)
+#define IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0	0x1bc
+
+#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
+
+/* 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)
+
+#define IMEM_BLOCK_SIZE				256
+
+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 usb_hcd *hcd;
+
+	int irq;
+
+	void __iomem *fpci_base;
+	void __iomem *ipfs_base;
+
+	const struct tegra_xhci_soc_config *soc_config;
+
+	struct notifier_block mbox_nb;
+	struct tegra_xusb_mbox *mbox;
+
+	struct regulator *s1p05v_reg;
+	struct regulator *s3p3v_reg;
+	struct regulator *s1p8v_reg;
+
+	struct clk *host_clk;
+	struct clk *falc_clk;
+	struct clk *ss_clk;
+	struct clk *ss_src_clk;
+	struct clk *hs_src_clk;
+	struct clk *fs_src_clk;
+	struct clk *pll_u_480m;
+	struct clk *clk_m;
+	struct clk *pll_e;
+
+	struct reset_control *host_rst;
+	struct reset_control *ss_rst;
+
+	struct phy *phys[TEGRA_XHCI_MAX_PHYS];
+
+	/* Firmware loading related */
+	void *fw_data;
+	size_t fw_size;
+	dma_addr_t fw_dma_addr;
+	bool fw_loaded;
+};
+
+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->hcd->rsrc_start;
+	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_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_set_ss_clk(struct tegra_xhci_hcd *tegra,
+				 unsigned long rate)
+{
+	unsigned long new_parent_rate, old_parent_rate;
+	int ret, div;
+	struct clk *clk = tegra->ss_src_clk;
+
+	if (clk_get_rate(clk) == rate)
+		return 0;
+
+	switch (rate) {
+	case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
+		/* Reparent to PLLU_480M. Set div first to avoid overclocking */
+		old_parent_rate = clk_get_rate(clk_get_parent(clk));
+		new_parent_rate = clk_get_rate(tegra->pll_u_480m);
+		div = new_parent_rate / rate;
+		ret = clk_set_rate(clk, old_parent_rate / div);
+		if (ret)
+			return ret;
+		ret = clk_set_parent(clk, tegra->pll_u_480m);
+		if (ret)
+			return ret;
+		break;
+	case TEGRA_XHCI_SS_CLK_LOW_SPEED:
+		/* Reparent to CLK_M */
+		ret = clk_set_parent(clk, tegra->clk_m);
+		if (ret)
+			return ret;
+		ret = clk_set_rate(clk, rate);
+		if (ret)
+			return ret;
+		break;
+	default:
+		dev_err(tegra->dev, "Invalid SS rate: %lu\n", rate);
+		return -EINVAL;
+	}
+
+	if (clk_get_rate(clk) != rate) {
+		dev_err(tegra->dev, "SS clock doesn't match requested rate\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int tegra_xhci_clk_enable(struct tegra_xhci_hcd *tegra)
+{
+	clk_prepare_enable(tegra->pll_e);
+	clk_prepare_enable(tegra->host_clk);
+	clk_prepare_enable(tegra->ss_clk);
+	clk_prepare_enable(tegra->falc_clk);
+	clk_prepare_enable(tegra->fs_src_clk);
+	clk_prepare_enable(tegra->hs_src_clk);
+
+	return tegra_xhci_set_ss_clk(tegra, TEGRA_XHCI_SS_CLK_HIGH_SPEED);
+}
+
+static void tegra_xhci_clk_disable(struct tegra_xhci_hcd *tegra)
+{
+	clk_disable_unprepare(tegra->pll_e);
+	clk_disable_unprepare(tegra->host_clk);
+	clk_disable_unprepare(tegra->ss_clk);
+	clk_disable_unprepare(tegra->falc_clk);
+	clk_disable_unprepare(tegra->fs_src_clk);
+	clk_disable_unprepare(tegra->hs_src_clk);
+}
+
+static int tegra_xhci_regulator_enable(struct tegra_xhci_hcd *tegra)
+{
+	int ret;
+
+	ret = regulator_enable(tegra->s3p3v_reg);
+	if (ret < 0)
+		return ret;
+	ret = regulator_enable(tegra->s1p8v_reg);
+	if (ret < 0)
+		goto disable_s3p3v;
+	ret = regulator_enable(tegra->s1p05v_reg);
+	if (ret < 0)
+		goto disable_s1p8v;
+
+	return 0;
+
+disable_s1p8v:
+	regulator_disable(tegra->s1p8v_reg);
+disable_s3p3v:
+	regulator_disable(tegra->s3p3v_reg);
+	return ret;
+}
+
+static void tegra_xhci_regulator_disable(struct tegra_xhci_hcd *tegra)
+{
+	regulator_disable(tegra->s1p05v_reg);
+	regulator_disable(tegra->s1p8v_reg);
+	regulator_disable(tegra->s3p3v_reg);
+}
+
+static int tegra_xhci_phy_enable(struct tegra_xhci_hcd *tegra)
+{
+	int ret;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tegra->phys); i++) {
+		ret = phy_init(tegra->phys[i]);
+		if (ret)
+			goto disable_phy;
+		ret = phy_power_on(tegra->phys[i]);
+		if (ret) {
+			phy_exit(tegra->phys[i]);
+			goto disable_phy;
+		}
+	}
+
+	return 0;
+disable_phy:
+	for (i = i - 1; i >= 0; i--) {
+		phy_power_off(tegra->phys[i]);
+		phy_exit(tegra->phys[i]);
+	}
+	return ret;
+}
+
+static void tegra_xhci_phy_disable(struct tegra_xhci_hcd *tegra)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tegra->phys); i++) {
+		phy_power_off(tegra->phys[i]);
+		phy_exit(tegra->phys[i]);
+	}
+}
+
+static int tegra_xhci_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 tegra_xusb_mbox_msg *msg = (struct tegra_xusb_mbox_msg *)p;
+	int ret;
+
+	switch (event) {
+	case MBOX_CMD_INC_SSPI_CLOCK:
+	case MBOX_CMD_DEC_SSPI_CLOCK:
+		ret = tegra_xhci_set_ss_clk(tegra, msg->data_in * 1000);
+		msg->data_out = clk_get_rate(tegra->ss_src_clk) / 1000;
+		if (ret)
+			msg->cmd_out = MBOX_CMD_NAK;
+		else
+			msg->cmd_out = MBOX_CMD_ACK;
+		return NOTIFY_STOP;
+	case MBOX_CMD_INC_FALC_CLOCK:
+	case MBOX_CMD_DEC_FALC_CLOCK:
+		msg->data_out = clk_get_rate(tegra->falc_clk) / 1000;
+		if (msg->data_in != msg->data_out)
+			msg->cmd_out = MBOX_CMD_NAK;
+		else
+			msg->cmd_out = 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 void tegra_xhci_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+	xhci->quirks |= XHCI_PLAT;
+}
+
+static int tegra_xhci_setup(struct usb_hcd *hcd)
+{
+	return xhci_gen_setup(hcd, tegra_xhci_quirks);
+}
+
+static const struct hc_driver tegra_xhci_hc_driver = {
+	.description =		"tegra-xhci-hcd",
+	.product_desc =		"Tegra xHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct xhci_hcd *),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			xhci_irq,
+	.flags =		HCD_MEMORY | HCD_USB3 | HCD_SHARED,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		tegra_xhci_setup,
+	.start =		xhci_run,
+	.stop =			xhci_stop,
+	.shutdown =		xhci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		xhci_urb_enqueue,
+	.urb_dequeue =		xhci_urb_dequeue,
+	.alloc_dev =		xhci_alloc_dev,
+	.free_dev =		xhci_free_dev,
+	.alloc_streams =	xhci_alloc_streams,
+	.free_streams =		xhci_free_streams,
+	.add_endpoint =		xhci_add_endpoint,
+	.drop_endpoint =	xhci_drop_endpoint,
+	.endpoint_reset =	xhci_endpoint_reset,
+	.check_bandwidth =	xhci_check_bandwidth,
+	.reset_bandwidth =	xhci_reset_bandwidth,
+	.address_device =	xhci_address_device,
+	.enable_device =	xhci_enable_device,
+	.update_hub_device =	xhci_update_hub_device,
+	.reset_device =		xhci_discover_or_reset_device,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	xhci_get_frame,
+
+	/* Root hub support */
+	.hub_control =		xhci_hub_control,
+	.hub_status_data =	xhci_hub_status_data,
+	.bus_suspend =		xhci_bus_suspend,
+	.bus_resume =		xhci_bus_resume,
+};
+
+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,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 xhci_hcd *xhci = NULL;
+	struct tegra_xhci_fw_cfgtbl *cfg_tbl;
+	int ret;
+
+	if (!fw)
+		goto put_usb2_hcd;
+
+	/* 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)
+		goto put_usb2_hcd;
+	memcpy(tegra->fw_data, fw->data, tegra->fw_size);
+
+	ret = tegra_xhci_load_firmware(tegra);
+	if (ret < 0)
+		goto put_usb2_hcd;
+
+	ret = usb_add_hcd(tegra->hcd, tegra->irq, IRQF_SHARED);
+	if (ret < 0)
+		goto put_usb2_hcd;
+	device_wakeup_enable(tegra->hcd->self.controller);
+
+	/*
+	 * USB 2.0 roothub is stored in drvdata now. Swap it with the Tegra HCD.
+	 */
+	tegra->hcd = dev_get_drvdata(dev);
+	dev_set_drvdata(dev, tegra);
+	xhci = hcd_to_xhci(tegra->hcd);
+	xhci->shared_hcd = usb_create_shared_hcd(&tegra_xhci_hc_driver,
+						 dev, dev_name(dev),
+						 tegra->hcd);
+	if (!xhci->shared_hcd)
+		goto dealloc_usb2_hcd;
+
+	/*
+	 * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
+	 * is called by usb_add_hcd().
+	 */
+	*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
+	ret = usb_add_hcd(xhci->shared_hcd, tegra->irq, IRQF_SHARED);
+	if (ret < 0)
+		goto put_usb3_hcd;
+
+	/* Enable firmware messages from controller */
+	ret = tegra_xusb_mbox_send(tegra->mbox, MBOX_CMD_MSG_ENABLED, 0);
+	if (ret < 0)
+		goto dealloc_usb3_hcd;
+
+	tegra->fw_loaded = true;
+	release_firmware(fw);
+	return;
+
+dealloc_usb3_hcd:
+	usb_remove_hcd(xhci->shared_hcd);
+put_usb3_hcd:
+	usb_put_hcd(xhci->shared_hcd);
+dealloc_usb2_hcd:
+	usb_remove_hcd(tegra->hcd);
+	kfree(xhci);
+put_usb2_hcd:
+	usb_put_hcd(tegra->hcd);
+	tegra->hcd = NULL;
+	release_firmware(fw);
+}
+
+static int tegra_xhci_probe(struct platform_device *pdev)
+{
+	struct tegra_xhci_hcd *tegra;
+	struct usb_hcd *hcd;
+	struct resource	*res;
+	struct phy *phy;
+	const struct of_device_id *match;
+	int ret, i, j;
+
+	BUILD_BUG_ON(sizeof(struct tegra_xhci_fw_cfgtbl) != 256);
+
+	tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
+	if (!tegra)
+		return -ENOMEM;
+	tegra->dev = &pdev->dev;
+	platform_set_drvdata(pdev, tegra);
+
+	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;
+
+	hcd = usb_create_hcd(&tegra_xhci_hc_driver, &pdev->dev,
+				    dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+	tegra->hcd = hcd;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(hcd->regs)) {
+		ret = PTR_ERR(hcd->regs);
+		goto put_hcd;
+	}
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	tegra->fpci_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tegra->fpci_base)) {
+		ret = PTR_ERR(tegra->fpci_base);
+		goto put_hcd;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+	tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tegra->ipfs_base)) {
+		ret = PTR_ERR(tegra->ipfs_base);
+		goto put_hcd;
+	}
+
+	tegra->irq = platform_get_irq(pdev, 0);
+	if (tegra->irq < 0) {
+		ret = tegra->irq;
+		goto put_hcd;
+	}
+
+	tegra->host_rst = devm_reset_control_get(&pdev->dev, "xusb_host");
+	if (IS_ERR(tegra->host_rst)) {
+		ret = PTR_ERR(tegra->host_rst);
+		goto put_hcd;
+	}
+	tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss");
+	if (IS_ERR(tegra->ss_rst)) {
+		ret = PTR_ERR(tegra->ss_rst);
+		goto put_hcd;
+	}
+
+	tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
+	if (IS_ERR(tegra->host_clk)) {
+		ret = PTR_ERR(tegra->host_clk);
+		goto put_hcd;
+	}
+	tegra->falc_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src");
+	if (IS_ERR(tegra->falc_clk)) {
+		ret = PTR_ERR(tegra->falc_clk);
+		goto put_hcd;
+	}
+	tegra->ss_clk = devm_clk_get(&pdev->dev, "xusb_ss");
+	if (IS_ERR(tegra->ss_clk)) {
+		ret = PTR_ERR(tegra->ss_clk);
+		goto put_hcd;
+	}
+	tegra->ss_src_clk = devm_clk_get(&pdev->dev, "xusb_ss_src");
+	if (IS_ERR(tegra->ss_src_clk)) {
+		ret = PTR_ERR(tegra->ss_src_clk);
+		goto put_hcd;
+	}
+	tegra->hs_src_clk = devm_clk_get(&pdev->dev, "xusb_hs_src");
+	if (IS_ERR(tegra->hs_src_clk)) {
+		ret = PTR_ERR(tegra->hs_src_clk);
+		goto put_hcd;
+	}
+	tegra->fs_src_clk = devm_clk_get(&pdev->dev, "xusb_fs_src");
+	if (IS_ERR(tegra->fs_src_clk)) {
+		ret = PTR_ERR(tegra->fs_src_clk);
+		goto put_hcd;
+	}
+	tegra->pll_u_480m = devm_clk_get(&pdev->dev, "pll_u_480m");
+	if (IS_ERR(tegra->pll_u_480m)) {
+		ret = PTR_ERR(tegra->pll_u_480m);
+		goto put_hcd;
+	}
+	tegra->clk_m = devm_clk_get(&pdev->dev, "clk_m");
+	if (IS_ERR(tegra->clk_m)) {
+		ret = PTR_ERR(tegra->clk_m);
+		goto put_hcd;
+	}
+	tegra->pll_e = devm_clk_get(&pdev->dev, "pll_e");
+	if (IS_ERR(tegra->pll_e)) {
+		ret = PTR_ERR(tegra->pll_e);
+		goto put_hcd;
+	}
+	ret = tegra_xhci_clk_enable(tegra);
+	if (ret)
+		goto put_hcd;
+
+	tegra->s3p3v_reg = devm_regulator_get(&pdev->dev, "s3p3v");
+	if (IS_ERR(tegra->s3p3v_reg)) {
+		ret = PTR_ERR(tegra->s3p3v_reg);
+		dev_info(&pdev->dev, "s3p3v get failed: %d\n", ret);
+		goto disable_clk;
+	}
+	tegra->s1p8v_reg = devm_regulator_get(&pdev->dev, "s1p8v");
+	if (IS_ERR(tegra->s1p8v_reg)) {
+		ret = PTR_ERR(tegra->s1p8v_reg);
+		dev_info(&pdev->dev, "s1p8v get failed: %d\n", ret);
+		goto disable_clk;
+	}
+	tegra->s1p05v_reg = devm_regulator_get(&pdev->dev, "s1p05v");
+	if (IS_ERR(tegra->s1p05v_reg)) {
+		ret = PTR_ERR(tegra->s1p05v_reg);
+		dev_info(&pdev->dev, "s1p05v get failed: %d\n", ret);
+		goto disable_clk;
+	}
+	ret = tegra_xhci_regulator_enable(tegra);
+	if (ret)
+		goto disable_clk;
+
+	tegra->mbox = tegra_xusb_mbox_lookup_by_phandle(pdev->dev.of_node,
+							"nvidia,xusb-mbox");
+	if (IS_ERR(tegra->mbox))
+		goto disable_regulator;
+	tegra->mbox_nb.notifier_call = tegra_xhci_mbox_notifier;
+	tegra_xusb_mbox_register_notifier(tegra->mbox, &tegra->mbox_nb);
+
+	j = 0;
+	for (i = 0; i < TEGRA_XHCI_UTMI_PHYS; i++) {
+		char prop[sizeof("utmi-N")];
+
+		sprintf(prop, "utmi-%d", i);
+		phy = devm_phy_optional_get(&pdev->dev, prop);
+		if (IS_ERR(phy)) {
+			ret = PTR_ERR(phy);
+			goto unregister_notifier;
+		}
+		tegra->phys[j++] = phy;
+	}
+	for (i = 0; i < TEGRA_XHCI_HSIC_PHYS; i++) {
+		char prop[sizeof("hsic-N")];
+
+		sprintf(prop, "hsic-%d", i);
+		phy = devm_phy_optional_get(&pdev->dev, prop);
+		if (IS_ERR(phy)) {
+			ret = PTR_ERR(phy);
+			goto unregister_notifier;
+		}
+		tegra->phys[j++] = phy;
+	}
+	for (i = 0; i < TEGRA_XHCI_USB3_PHYS; i++) {
+		char prop[sizeof("usb3-N")];
+
+		sprintf(prop, "usb3-%d", i);
+		phy = devm_phy_optional_get(&pdev->dev, prop);
+		if (IS_ERR(phy)) {
+			ret = PTR_ERR(phy);
+			goto unregister_notifier;
+		}
+		tegra->phys[j++] = phy;
+	}
+
+	/* Setup IPFS access and BAR0 space */
+	tegra_xhci_cfg(tegra);
+
+	ret = tegra_xhci_phy_enable(tegra);
+	if (ret < 0)
+		goto unregister_notifier;
+
+	ret = request_firmware_nowait(THIS_MODULE, true,
+				      tegra->soc_config->firmware_file,
+				      tegra->dev, GFP_KERNEL, tegra,
+				      tegra_xhci_probe_finish);
+	if (ret < 0)
+		goto disable_phy;
+
+	return 0;
+
+disable_phy:
+	tegra_xhci_phy_disable(tegra);
+unregister_notifier:
+	tegra_xusb_mbox_unregister_notifier(tegra->mbox, &tegra->mbox_nb);
+disable_regulator:
+	tegra_xhci_regulator_disable(tegra);
+disable_clk:
+	tegra_xhci_clk_disable(tegra);
+put_hcd:
+	usb_put_hcd(hcd);
+	return ret;
+}
+
+static int tegra_xhci_remove(struct platform_device *pdev)
+{
+	struct tegra_xhci_hcd *tegra = platform_get_drvdata(pdev);
+	struct usb_hcd *hcd = tegra->hcd;
+	struct xhci_hcd *xhci;
+
+	if (tegra->fw_loaded) {
+		xhci = hcd_to_xhci(hcd);
+		usb_remove_hcd(xhci->shared_hcd);
+		usb_put_hcd(xhci->shared_hcd);
+		usb_remove_hcd(hcd);
+		usb_put_hcd(hcd);
+		kfree(xhci);
+	} else if (hcd) {
+		/* Unbound after probe(), but before firmware loading. */
+		usb_put_hcd(hcd);
+	}
+
+	if (tegra->fw_data)
+		dma_free_coherent(tegra->dev, tegra->fw_size, tegra->fw_data,
+				  tegra->fw_dma_addr);
+
+	tegra_xusb_mbox_unregister_notifier(tegra->mbox, &tegra->mbox_nb);
+	tegra_xhci_phy_disable(tegra);
+	tegra_xhci_regulator_disable(tegra);
+	tegra_xhci_clk_disable(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");
-- 
2.0.0.526.g5318336

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

* [PATCH v1 7/9] ARM: tegra: Add Tegra124 XUSB mailbox and XHCI controller
  2014-06-18  6:16 ` Andrew Bresticker
  (?)
@ 2014-06-18  6:16     ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Add nodes for the Tegra XUSB mailbox and Tegra XHCI controller.
Update the XUSB pad controller node with a phandle to the XUSB
mailbox.

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

diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 514e490..4e1cd92 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -480,11 +480,42 @@
 		status = "disabled";
 	};
 
+	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>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>,
+			 <&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_host", "xusb_falcon_src", "xusb_ss",
+			      "xusb_ss_src", "xusb_hs_src", "xusb_fs_src",
+			      "pll_u_480m", "clk_m", "pll_e";
+		resets = <&tegra_car 89>, <&tegra_car 156>;
+		reset-names = "xusb_host", "xusb_ss";
+		nvidia,xusb-mbox = <&mbox>;
+		status = "disabled";
+	};
+
+	mbox: mailbox@0,70098000 {
+		compatible = "nvidia,tegra124-xusb-mbox";
+		reg = <0x0 0x70098000 0x0 0x1000>;
+		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
 	padctl: padctl@0,7009f000 {
 		compatible = "nvidia,tegra124-xusb-padctl";
 		reg = <0x0 0x7009f000 0x0 0x1000>;
 		resets = <&tegra_car 142>;
 		reset-names = "padctl";
+		nvidia,xusb-mbox = <&mbox>;
 
 		#phy-cells = <1>;
 	};
-- 
2.0.0.526.g5318336

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

* [PATCH v1 7/9] ARM: tegra: Add Tegra124 XUSB mailbox and XHCI controller
@ 2014-06-18  6:16     ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Add nodes for the Tegra XUSB mailbox and Tegra XHCI controller.
Update the XUSB pad controller node with a phandle to the XUSB
mailbox.

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

diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 514e490..4e1cd92 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -480,11 +480,42 @@
 		status = "disabled";
 	};
 
+	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>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>,
+			 <&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_host", "xusb_falcon_src", "xusb_ss",
+			      "xusb_ss_src", "xusb_hs_src", "xusb_fs_src",
+			      "pll_u_480m", "clk_m", "pll_e";
+		resets = <&tegra_car 89>, <&tegra_car 156>;
+		reset-names = "xusb_host", "xusb_ss";
+		nvidia,xusb-mbox = <&mbox>;
+		status = "disabled";
+	};
+
+	mbox: mailbox@0,70098000 {
+		compatible = "nvidia,tegra124-xusb-mbox";
+		reg = <0x0 0x70098000 0x0 0x1000>;
+		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
 	padctl: padctl@0,7009f000 {
 		compatible = "nvidia,tegra124-xusb-padctl";
 		reg = <0x0 0x7009f000 0x0 0x1000>;
 		resets = <&tegra_car 142>;
 		reset-names = "padctl";
+		nvidia,xusb-mbox = <&mbox>;
 
 		#phy-cells = <1>;
 	};
-- 
2.0.0.526.g5318336


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

* [PATCH v1 7/9] ARM: tegra: Add Tegra124 XUSB mailbox and XHCI controller
@ 2014-06-18  6:16     ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

Add nodes for the Tegra XUSB mailbox and Tegra XHCI controller.
Update the XUSB pad controller node with a phandle to the XUSB
mailbox.

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

diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 514e490..4e1cd92 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -480,11 +480,42 @@
 		status = "disabled";
 	};
 
+	usb at 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>;
+		clocks = <&tegra_car TEGRA124_CLK_XUSB_HOST>,
+			 <&tegra_car TEGRA124_CLK_XUSB_FALCON_SRC>,
+			 <&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_host", "xusb_falcon_src", "xusb_ss",
+			      "xusb_ss_src", "xusb_hs_src", "xusb_fs_src",
+			      "pll_u_480m", "clk_m", "pll_e";
+		resets = <&tegra_car 89>, <&tegra_car 156>;
+		reset-names = "xusb_host", "xusb_ss";
+		nvidia,xusb-mbox = <&mbox>;
+		status = "disabled";
+	};
+
+	mbox: mailbox at 0,70098000 {
+		compatible = "nvidia,tegra124-xusb-mbox";
+		reg = <0x0 0x70098000 0x0 0x1000>;
+		interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
 	padctl: padctl at 0,7009f000 {
 		compatible = "nvidia,tegra124-xusb-padctl";
 		reg = <0x0 0x7009f000 0x0 0x1000>;
 		resets = <&tegra_car 142>;
 		reset-names = "padctl";
+		nvidia,xusb-mbox = <&mbox>;
 
 		#phy-cells = <1>;
 	};
-- 
2.0.0.526.g5318336

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

* [PATCH v1 8/9] ARM: tegra: jetson-tk1: Add XHCI support
  2014-06-18  6:16 ` Andrew Bresticker
@ 2014-06-18  6:16   ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Assign USB ports previously owned by the EHCI controllers to the XHCI
controller.  There is a mini-PCIe USB port (UTMI port 1) and a USB A
connector (UTMI port 2, USB3 port 0).  PCIe lane 0 is used for USB3
port 0.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/arm/boot/dts/tegra124-jetson-tk1.dts | 43 ++++++++++++++++---------------
 1 file changed, 22 insertions(+), 21 deletions(-)

diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
index 11c1650..cea2d2b 100644
--- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
@@ -1619,15 +1619,35 @@
 		nvidia,sys-clock-req-active-high;
 	};
 
+	usb@0,70090000 {
+		status = "okay";
+		phys = <&padctl TEGRA_XUSB_PADCTL_UTMI_P1>, /* mini-PCIe USB */
+		       <&padctl TEGRA_XUSB_PADCTL_UTMI_P2>, /* USB A */
+		       <&padctl TEGRA_XUSB_PADCTL_USB3_P0>; /* USB A */
+		phy-names = "utmi-1", "utmi-2", "usb3-0";
+		s1p05v-supply = <&vdd_1v05_run>;
+		s3p3v-supply = <&vdd_3v3_lp0>;
+		s1p8v-supply = <&vddio_1v8>;
+	};
+
 	padctl@0,7009f000 {
 		pinctrl-0 = <&padctl_default>;
 		pinctrl-names = "default";
 
+		vbus-otg-2-supply = <&vdd_usb3_vbus>;
+
 		padctl_default: pinmux {
-			usb3 {
-				nvidia,lanes = "pcie-0", "pcie-1";
+			otg {
+				nvidia,lanes = "otg-1", "otg-2";
+				nvidia,function = "xusb";
+			};
+
+			usb3p0 {
+				nvidia,lanes = "pcie-0";
 				nvidia,function = "usb3";
 				nvidia,iddq = <0>;
+				nvidia,usb3-port-num = <0>;
+				nvidia,usb2-port-num = <2>;
 			};
 
 			pcie {
@@ -1668,25 +1688,6 @@
 		};
 	};
 
-	/* mini-PCIe USB */
-	usb@0,7d004000 {
-		status = "okay";
-	};
-
-	usb-phy@0,7d004000 {
-		status = "okay";
-	};
-
-	/* USB A connector */
-	usb@0,7d008000 {
-		status = "okay";
-	};
-
-	usb-phy@0,7d008000 {
-		status = "okay";
-		vbus-supply = <&vdd_usb3_vbus>;
-	};
-
 	clocks {
 		compatible = "simple-bus";
 		#address-cells = <1>;
-- 
2.0.0.526.g5318336


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

* [PATCH v1 8/9] ARM: tegra: jetson-tk1: Add XHCI support
@ 2014-06-18  6:16   ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

Assign USB ports previously owned by the EHCI controllers to the XHCI
controller.  There is a mini-PCIe USB port (UTMI port 1) and a USB A
connector (UTMI port 2, USB3 port 0).  PCIe lane 0 is used for USB3
port 0.

Signed-off-by: Andrew Bresticker <abrestic@chromium.org>
---
 arch/arm/boot/dts/tegra124-jetson-tk1.dts | 43 ++++++++++++++++---------------
 1 file changed, 22 insertions(+), 21 deletions(-)

diff --git a/arch/arm/boot/dts/tegra124-jetson-tk1.dts b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
index 11c1650..cea2d2b 100644
--- a/arch/arm/boot/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/boot/dts/tegra124-jetson-tk1.dts
@@ -1619,15 +1619,35 @@
 		nvidia,sys-clock-req-active-high;
 	};
 
+	usb at 0,70090000 {
+		status = "okay";
+		phys = <&padctl TEGRA_XUSB_PADCTL_UTMI_P1>, /* mini-PCIe USB */
+		       <&padctl TEGRA_XUSB_PADCTL_UTMI_P2>, /* USB A */
+		       <&padctl TEGRA_XUSB_PADCTL_USB3_P0>; /* USB A */
+		phy-names = "utmi-1", "utmi-2", "usb3-0";
+		s1p05v-supply = <&vdd_1v05_run>;
+		s3p3v-supply = <&vdd_3v3_lp0>;
+		s1p8v-supply = <&vddio_1v8>;
+	};
+
 	padctl at 0,7009f000 {
 		pinctrl-0 = <&padctl_default>;
 		pinctrl-names = "default";
 
+		vbus-otg-2-supply = <&vdd_usb3_vbus>;
+
 		padctl_default: pinmux {
-			usb3 {
-				nvidia,lanes = "pcie-0", "pcie-1";
+			otg {
+				nvidia,lanes = "otg-1", "otg-2";
+				nvidia,function = "xusb";
+			};
+
+			usb3p0 {
+				nvidia,lanes = "pcie-0";
 				nvidia,function = "usb3";
 				nvidia,iddq = <0>;
+				nvidia,usb3-port-num = <0>;
+				nvidia,usb2-port-num = <2>;
 			};
 
 			pcie {
@@ -1668,25 +1688,6 @@
 		};
 	};
 
-	/* mini-PCIe USB */
-	usb at 0,7d004000 {
-		status = "okay";
-	};
-
-	usb-phy at 0,7d004000 {
-		status = "okay";
-	};
-
-	/* USB A connector */
-	usb at 0,7d008000 {
-		status = "okay";
-	};
-
-	usb-phy at 0,7d008000 {
-		status = "okay";
-		vbus-supply = <&vdd_usb3_vbus>;
-	};
-
 	clocks {
 		compatible = "simple-bus";
 		#address-cells = <1>;
-- 
2.0.0.526.g5318336

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

* [PATCH v1 9/9] ARM: tegra: venice2: Add XHCI support
  2014-06-18  6:16 ` Andrew Bresticker
@ 2014-06-18  6:16   ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Mathias Nyman, Grant Likely,
	Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann,
	Andrew Bresticker

Assign ports previously owned by the EHCI controllers to the XHCI
controller.  There are two external USB ports (UTMI ports 0/2 and
USB3 ports 0/1) and an internal USB port (UTMI port 1).  PCIe lanes
0 and 1 are used by the USB3 ports.

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

diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts
index f1a5bac..bf88c81 100644
--- a/arch/arm/boot/dts/tegra124-venice2.dts
+++ b/arch/arm/boot/dts/tegra124-venice2.dts
@@ -878,6 +878,51 @@
 		status = "okay";
 	};
 
+	usb@0,70090000 {
+		status = "okay";
+		phys = <&padctl TEGRA_XUSB_PADCTL_UTMI_P0>,
+		       <&padctl TEGRA_XUSB_PADCTL_UTMI_P1>,
+		       <&padctl TEGRA_XUSB_PADCTL_UTMI_P2>,
+		       <&padctl TEGRA_XUSB_PADCTL_USB3_P0>,
+		       <&padctl TEGRA_XUSB_PADCTL_USB3_P1>;
+		phy-names = "utmi-0", "utmi-1", "utmi-2", "usb3-0", "usb3-1";
+		s1p05v-supply = <&vdd_1v05_run>;
+		s3p3v-supply = <&vdd_3v3_lp0>;
+		s1p8v-supply = <&vddio_1v8>;
+	};
+
+	padctl@0,7009f000 {
+		pinctrl-0 = <&padctl_default>;
+		pinctrl-names = "default";
+
+		vbus-otg-0-supply = <&vdd_usb1_vbus>;
+		vbus-otg-1-supply = <&vdd_run_cam>;
+		vbus-otg-2-supply = <&vdd_usb3_vbus>;
+
+		padctl_default: pinmux {
+			otg {
+				nvidia,lanes = "otg-0", "otg-1", "otg-2";
+				nvidia,function = "xusb";
+			};
+
+			usb3p0 {
+				nvidia,lanes = "pcie-0";
+				nvidia,function = "usb3";
+				nvidia,iddq = <0>;
+				nvidia,usb3-port-num = <0>;
+				nvidia,usb2-port-num = <0>;
+			};
+
+			usb3p1 {
+				nvidia,lanes = "pcie-1";
+				nvidia,function = "usb3";
+				nvidia,iddq = <0>;
+				nvidia,usb3-port-num = <1>;
+				nvidia,usb2-port-num = <2>;
+			};
+		};
+	};
+
 	sdhci@0,700b0400 {
 		cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
 		power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
@@ -898,33 +943,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";
 
-- 
2.0.0.526.g5318336

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

* [PATCH v1 9/9] ARM: tegra: venice2: Add XHCI support
@ 2014-06-18  6:16   ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-18  6:16 UTC (permalink / raw)
  To: linux-arm-kernel

Assign ports previously owned by the EHCI controllers to the XHCI
controller.  There are two external USB ports (UTMI ports 0/2 and
USB3 ports 0/1) and an internal USB port (UTMI port 1).  PCIe lanes
0 and 1 are used by the USB3 ports.

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

diff --git a/arch/arm/boot/dts/tegra124-venice2.dts b/arch/arm/boot/dts/tegra124-venice2.dts
index f1a5bac..bf88c81 100644
--- a/arch/arm/boot/dts/tegra124-venice2.dts
+++ b/arch/arm/boot/dts/tegra124-venice2.dts
@@ -878,6 +878,51 @@
 		status = "okay";
 	};
 
+	usb at 0,70090000 {
+		status = "okay";
+		phys = <&padctl TEGRA_XUSB_PADCTL_UTMI_P0>,
+		       <&padctl TEGRA_XUSB_PADCTL_UTMI_P1>,
+		       <&padctl TEGRA_XUSB_PADCTL_UTMI_P2>,
+		       <&padctl TEGRA_XUSB_PADCTL_USB3_P0>,
+		       <&padctl TEGRA_XUSB_PADCTL_USB3_P1>;
+		phy-names = "utmi-0", "utmi-1", "utmi-2", "usb3-0", "usb3-1";
+		s1p05v-supply = <&vdd_1v05_run>;
+		s3p3v-supply = <&vdd_3v3_lp0>;
+		s1p8v-supply = <&vddio_1v8>;
+	};
+
+	padctl at 0,7009f000 {
+		pinctrl-0 = <&padctl_default>;
+		pinctrl-names = "default";
+
+		vbus-otg-0-supply = <&vdd_usb1_vbus>;
+		vbus-otg-1-supply = <&vdd_run_cam>;
+		vbus-otg-2-supply = <&vdd_usb3_vbus>;
+
+		padctl_default: pinmux {
+			otg {
+				nvidia,lanes = "otg-0", "otg-1", "otg-2";
+				nvidia,function = "xusb";
+			};
+
+			usb3p0 {
+				nvidia,lanes = "pcie-0";
+				nvidia,function = "usb3";
+				nvidia,iddq = <0>;
+				nvidia,usb3-port-num = <0>;
+				nvidia,usb2-port-num = <0>;
+			};
+
+			usb3p1 {
+				nvidia,lanes = "pcie-1";
+				nvidia,function = "usb3";
+				nvidia,iddq = <0>;
+				nvidia,usb3-port-num = <1>;
+				nvidia,usb2-port-num = <2>;
+			};
+		};
+	};
+
 	sdhci at 0,700b0400 {
 		cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
 		power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
@@ -898,33 +943,6 @@
 		};
 	};
 
-	usb at 0,7d000000 {
-		status = "okay";
-	};
-
-	usb-phy at 0,7d000000 {
-		status = "okay";
-		vbus-supply = <&vdd_usb1_vbus>;
-	};
-
-	usb at 0,7d004000 {
-		status = "okay";
-	};
-
-	usb-phy at 0,7d004000 {
-		status = "okay";
-		vbus-supply = <&vdd_run_cam>;
-	};
-
-	usb at 0,7d008000 {
-		status = "okay";
-	};
-
-	usb-phy at 0,7d008000 {
-		status = "okay";
-		vbus-supply = <&vdd_usb3_vbus>;
-	};
-
 	backlight: backlight {
 		compatible = "pwm-backlight";
 
-- 
2.0.0.526.g5318336

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-06-18  6:16     ` Andrew Bresticker
  (?)
@ 2014-06-20 16:58         ` Julius Werner
  -1 siblings, 0 replies; 111+ messages in thread
From: Julius Werner @ 2014-06-20 16:58 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, LKML,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Stephen Warren, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I

> +static const struct hc_driver tegra_xhci_hc_driver = {
> +       .description =          "tegra-xhci-hcd",
> +       .product_desc =         "Tegra xHCI Host Controller",
> +       .hcd_priv_size =        sizeof(struct xhci_hcd *),
> +
> +       /*
> +        * generic hardware linkage
> +        */
> +       .irq =                  xhci_irq,
> +       .flags =                HCD_MEMORY | HCD_USB3 | HCD_SHARED,
> +
> +       /*
> +        * basic lifecycle operations
> +        */
> +       .reset =                tegra_xhci_setup,
> +       .start =                xhci_run,
> +       .stop =                 xhci_stop,
> +       .shutdown =             xhci_shutdown,
> +
> +       /*
> +        * managing i/o requests and associated device resources
> +        */
> +       .urb_enqueue =          xhci_urb_enqueue,
> +       .urb_dequeue =          xhci_urb_dequeue,
> +       .alloc_dev =            xhci_alloc_dev,
> +       .free_dev =             xhci_free_dev,
> +       .alloc_streams =        xhci_alloc_streams,
> +       .free_streams =         xhci_free_streams,
> +       .add_endpoint =         xhci_add_endpoint,
> +       .drop_endpoint =        xhci_drop_endpoint,
> +       .endpoint_reset =       xhci_endpoint_reset,
> +       .check_bandwidth =      xhci_check_bandwidth,
> +       .reset_bandwidth =      xhci_reset_bandwidth,
> +       .address_device =       xhci_address_device,
> +       .enable_device =        xhci_enable_device,
> +       .update_hub_device =    xhci_update_hub_device,
> +       .reset_device =         xhci_discover_or_reset_device,
> +
> +       /*
> +        * scheduling support
> +        */
> +       .get_frame_number =     xhci_get_frame,
> +
> +       /* Root hub support */
> +       .hub_control =          xhci_hub_control,
> +       .hub_status_data =      xhci_hub_status_data,
> +       .bus_suspend =          xhci_bus_suspend,
> +       .bus_resume =           xhci_bus_resume,
> +};

I know I missed the first round of discussion where this was
suggested, but I don't think it's a good idea to pull the whole
hc_driver structure out into every platform implementation. It will
lead to duplication, then to future additions only being applied to
some of the implementations and everything getting out of sync. This
is already a problem with the PCI/plat split (e.g. the LPM functions
were only added to xhci-pci even though they should apply to both).
Also, if I'm not mistaken this code would fail to compile as a module
(you are referencing lots of symbols that are internal to the xhci-hcd
module).

I think at the very least you should add a function
"xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
even better to xhci.c and use it for PCI as well) that initializes all
function pointers to the default (internal) symbols, and can then be
overridden afterwards.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-20 16:58         ` Julius Werner
  0 siblings, 0 replies; 111+ messages in thread
From: Julius Werner @ 2014-06-20 16:58 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, LKML, linux-arm-kernel,
	linux-usb, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Randy Dunlap, Stephen Warren, Thierry Reding,
	Russell King, Linus Walleij, Greg Kroah-Hartman, Mathias Nyman,
	Grant Likely, Alan Stern, Kishon Vijay Abraham I, Arnd Bergmann

> +static const struct hc_driver tegra_xhci_hc_driver = {
> +       .description =          "tegra-xhci-hcd",
> +       .product_desc =         "Tegra xHCI Host Controller",
> +       .hcd_priv_size =        sizeof(struct xhci_hcd *),
> +
> +       /*
> +        * generic hardware linkage
> +        */
> +       .irq =                  xhci_irq,
> +       .flags =                HCD_MEMORY | HCD_USB3 | HCD_SHARED,
> +
> +       /*
> +        * basic lifecycle operations
> +        */
> +       .reset =                tegra_xhci_setup,
> +       .start =                xhci_run,
> +       .stop =                 xhci_stop,
> +       .shutdown =             xhci_shutdown,
> +
> +       /*
> +        * managing i/o requests and associated device resources
> +        */
> +       .urb_enqueue =          xhci_urb_enqueue,
> +       .urb_dequeue =          xhci_urb_dequeue,
> +       .alloc_dev =            xhci_alloc_dev,
> +       .free_dev =             xhci_free_dev,
> +       .alloc_streams =        xhci_alloc_streams,
> +       .free_streams =         xhci_free_streams,
> +       .add_endpoint =         xhci_add_endpoint,
> +       .drop_endpoint =        xhci_drop_endpoint,
> +       .endpoint_reset =       xhci_endpoint_reset,
> +       .check_bandwidth =      xhci_check_bandwidth,
> +       .reset_bandwidth =      xhci_reset_bandwidth,
> +       .address_device =       xhci_address_device,
> +       .enable_device =        xhci_enable_device,
> +       .update_hub_device =    xhci_update_hub_device,
> +       .reset_device =         xhci_discover_or_reset_device,
> +
> +       /*
> +        * scheduling support
> +        */
> +       .get_frame_number =     xhci_get_frame,
> +
> +       /* Root hub support */
> +       .hub_control =          xhci_hub_control,
> +       .hub_status_data =      xhci_hub_status_data,
> +       .bus_suspend =          xhci_bus_suspend,
> +       .bus_resume =           xhci_bus_resume,
> +};

I know I missed the first round of discussion where this was
suggested, but I don't think it's a good idea to pull the whole
hc_driver structure out into every platform implementation. It will
lead to duplication, then to future additions only being applied to
some of the implementations and everything getting out of sync. This
is already a problem with the PCI/plat split (e.g. the LPM functions
were only added to xhci-pci even though they should apply to both).
Also, if I'm not mistaken this code would fail to compile as a module
(you are referencing lots of symbols that are internal to the xhci-hcd
module).

I think at the very least you should add a function
"xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
even better to xhci.c and use it for PCI as well) that initializes all
function pointers to the default (internal) symbols, and can then be
overridden afterwards.

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-20 16:58         ` Julius Werner
  0 siblings, 0 replies; 111+ messages in thread
From: Julius Werner @ 2014-06-20 16:58 UTC (permalink / raw)
  To: linux-arm-kernel

> +static const struct hc_driver tegra_xhci_hc_driver = {
> +       .description =          "tegra-xhci-hcd",
> +       .product_desc =         "Tegra xHCI Host Controller",
> +       .hcd_priv_size =        sizeof(struct xhci_hcd *),
> +
> +       /*
> +        * generic hardware linkage
> +        */
> +       .irq =                  xhci_irq,
> +       .flags =                HCD_MEMORY | HCD_USB3 | HCD_SHARED,
> +
> +       /*
> +        * basic lifecycle operations
> +        */
> +       .reset =                tegra_xhci_setup,
> +       .start =                xhci_run,
> +       .stop =                 xhci_stop,
> +       .shutdown =             xhci_shutdown,
> +
> +       /*
> +        * managing i/o requests and associated device resources
> +        */
> +       .urb_enqueue =          xhci_urb_enqueue,
> +       .urb_dequeue =          xhci_urb_dequeue,
> +       .alloc_dev =            xhci_alloc_dev,
> +       .free_dev =             xhci_free_dev,
> +       .alloc_streams =        xhci_alloc_streams,
> +       .free_streams =         xhci_free_streams,
> +       .add_endpoint =         xhci_add_endpoint,
> +       .drop_endpoint =        xhci_drop_endpoint,
> +       .endpoint_reset =       xhci_endpoint_reset,
> +       .check_bandwidth =      xhci_check_bandwidth,
> +       .reset_bandwidth =      xhci_reset_bandwidth,
> +       .address_device =       xhci_address_device,
> +       .enable_device =        xhci_enable_device,
> +       .update_hub_device =    xhci_update_hub_device,
> +       .reset_device =         xhci_discover_or_reset_device,
> +
> +       /*
> +        * scheduling support
> +        */
> +       .get_frame_number =     xhci_get_frame,
> +
> +       /* Root hub support */
> +       .hub_control =          xhci_hub_control,
> +       .hub_status_data =      xhci_hub_status_data,
> +       .bus_suspend =          xhci_bus_suspend,
> +       .bus_resume =           xhci_bus_resume,
> +};

I know I missed the first round of discussion where this was
suggested, but I don't think it's a good idea to pull the whole
hc_driver structure out into every platform implementation. It will
lead to duplication, then to future additions only being applied to
some of the implementations and everything getting out of sync. This
is already a problem with the PCI/plat split (e.g. the LPM functions
were only added to xhci-pci even though they should apply to both).
Also, if I'm not mistaken this code would fail to compile as a module
(you are referencing lots of symbols that are internal to the xhci-hcd
module).

I think at the very least you should add a function
"xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
even better to xhci.c and use it for PCI as well) that initializes all
function pointers to the default (internal) symbols, and can then be
overridden afterwards.

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

* Re: [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
  2014-06-18  6:16     ` Andrew Bresticker
  (?)
@ 2014-06-25 21:42         ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:42 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add device-tree bindings for the Tegra XUSB mailbox which will be used
> for communication between the Tegra XHCI controller and the host.

Sorry for the slow review.

> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt

> +NVIDIA Tegra XUSB mailbox
> +=========================
> +
> +The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
> +communicate with the host.

Isn't the mailbox an internal implementation detail of the XUSB controller.

In other words, I'd naively think that there isn't a standalone generic
mailbox that can be used by anything, but we just happen to want to use
for XUSB. Rather, there's an XUSB controller, and part of the interface
to that controller is a mailbox.

As such, I don't think we want a standalone mailbox node in DT. Rather,
we should add the required reg and interrupt values into the XUSB DT node.

The driver for that XUSB HW module can either:

a) Register as both a mailbox driver and an EHCI driver.

b) Spawn a child device to instantiate the mailbox driver.

Perhaps (b) could be assisted by using the MFD framework?
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
@ 2014-06-25 21:42         ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:42 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree, linux-doc, linux-tegra,
	linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add device-tree bindings for the Tegra XUSB mailbox which will be used
> for communication between the Tegra XHCI controller and the host.

Sorry for the slow review.

> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt

> +NVIDIA Tegra XUSB mailbox
> +=========================
> +
> +The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
> +communicate with the host.

Isn't the mailbox an internal implementation detail of the XUSB controller.

In other words, I'd naively think that there isn't a standalone generic
mailbox that can be used by anything, but we just happen to want to use
for XUSB. Rather, there's an XUSB controller, and part of the interface
to that controller is a mailbox.

As such, I don't think we want a standalone mailbox node in DT. Rather,
we should add the required reg and interrupt values into the XUSB DT node.

The driver for that XUSB HW module can either:

a) Register as both a mailbox driver and an EHCI driver.

b) Spawn a child device to instantiate the mailbox driver.

Perhaps (b) could be assisted by using the MFD framework?

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

* [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
@ 2014-06-25 21:42         ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:42 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add device-tree bindings for the Tegra XUSB mailbox which will be used
> for communication between the Tegra XHCI controller and the host.

Sorry for the slow review.

> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt

> +NVIDIA Tegra XUSB mailbox
> +=========================
> +
> +The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
> +communicate with the host.

Isn't the mailbox an internal implementation detail of the XUSB controller.

In other words, I'd naively think that there isn't a standalone generic
mailbox that can be used by anything, but we just happen to want to use
for XUSB. Rather, there's an XUSB controller, and part of the interface
to that controller is a mailbox.

As such, I don't think we want a standalone mailbox node in DT. Rather,
we should add the required reg and interrupt values into the XUSB DT node.

The driver for that XUSB HW module can either:

a) Register as both a mailbox driver and an EHCI driver.

b) Spawn a child device to instantiate the mailbox driver.

Perhaps (b) could be assisted by using the MFD framework?

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

* Re: [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
  2014-06-18  6:16   ` Andrew Bresticker
  (?)
@ 2014-06-25 21:46       ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:46 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add new bindings used for USB support by the Tegra XUSB pad controller.
> This includes additional PHY types, USB-specific pinconfig properties, etc.

> diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt

> @@ -21,6 +21,12 @@ Required properties:
>    - padctl
>  - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
>    See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
> +- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.

Why does the padctrl code need access to the XUSB mailbox? Isn't the
padctrl HW module something that provides services to the XUSB code. I
would have expected the XUSB node to reference the padctrl node. If
notifications need to be sent back from XUSB padctrl to XUSB, then that
seems like an internal SW detail that doesn't need to be represented in DT.

> +Optional properties:
> +-------------------
> +- vbus-otg-{0,1,2}-supply: VBUS regulator for the corresponding UTMI pad.

Isn't VBUS something that's controlled by the USB PHY? I think the PHYs
are part of the XUSB controller, whereas the XUSB pad control is just
the low level IO pad HW.

> +- nvidia,usb3-port-num: USB3 port (0 or 1) to which the lane is mapped.
> +- nvidia,usb2-port-num: USB2 port (0, 1, or 2) to which the lane is mapped.
> +- nvidia,hsic-strobe-trim: HSIC strobe trimmer value.
> +- nvidia,hsic-rx-strobe-trim: HSIC RX strobe trimmer value.
> +- nvidia,hsic-rx-data-trim: HSIC RX data trimmer value.
> +- nvidia,hsic-tx-rtune-n: HSIC TX RTUNEN value.
> +- nvidia,hsic-tx-rtune-p: HSIC TX RTUNEP value.
> +- nvidia,hsic-tx-slew-n: HSIC TX SLEWN value.
> +- nvidia,hsic-tx-slew-p: HSIC TX SLEWP value.
> +- nvidia,hsic-auto-term: Enables HSIC AUTO_TERM. (0: no, 1: yes)

I wonder if some of that isn't part of the PHY not the pads?

>      Valid functions for this group are: "snps", "xusb", "uart", "rsvd".
>  
> -    The nvidia,iddq property does not apply to this group.
> +    The nvidia,iddq, nvidia,usb3-port-num, nvidia,usb2-port-num, and
> +    nvidia,hsic-* properties do not apply to this group.

Given the increased number of properties we now have, it seems better to
list the properties that *do* apply to each group, rather than those
that don't.

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

* Re: [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
@ 2014-06-25 21:46       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:46 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree, linux-doc, linux-tegra,
	linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add new bindings used for USB support by the Tegra XUSB pad controller.
> This includes additional PHY types, USB-specific pinconfig properties, etc.

> diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt

> @@ -21,6 +21,12 @@ Required properties:
>    - padctl
>  - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
>    See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
> +- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.

Why does the padctrl code need access to the XUSB mailbox? Isn't the
padctrl HW module something that provides services to the XUSB code. I
would have expected the XUSB node to reference the padctrl node. If
notifications need to be sent back from XUSB padctrl to XUSB, then that
seems like an internal SW detail that doesn't need to be represented in DT.

> +Optional properties:
> +-------------------
> +- vbus-otg-{0,1,2}-supply: VBUS regulator for the corresponding UTMI pad.

Isn't VBUS something that's controlled by the USB PHY? I think the PHYs
are part of the XUSB controller, whereas the XUSB pad control is just
the low level IO pad HW.

> +- nvidia,usb3-port-num: USB3 port (0 or 1) to which the lane is mapped.
> +- nvidia,usb2-port-num: USB2 port (0, 1, or 2) to which the lane is mapped.
> +- nvidia,hsic-strobe-trim: HSIC strobe trimmer value.
> +- nvidia,hsic-rx-strobe-trim: HSIC RX strobe trimmer value.
> +- nvidia,hsic-rx-data-trim: HSIC RX data trimmer value.
> +- nvidia,hsic-tx-rtune-n: HSIC TX RTUNEN value.
> +- nvidia,hsic-tx-rtune-p: HSIC TX RTUNEP value.
> +- nvidia,hsic-tx-slew-n: HSIC TX SLEWN value.
> +- nvidia,hsic-tx-slew-p: HSIC TX SLEWP value.
> +- nvidia,hsic-auto-term: Enables HSIC AUTO_TERM. (0: no, 1: yes)

I wonder if some of that isn't part of the PHY not the pads?

>      Valid functions for this group are: "snps", "xusb", "uart", "rsvd".
>  
> -    The nvidia,iddq property does not apply to this group.
> +    The nvidia,iddq, nvidia,usb3-port-num, nvidia,usb2-port-num, and
> +    nvidia,hsic-* properties do not apply to this group.

Given the increased number of properties we now have, it seems better to
list the properties that *do* apply to each group, rather than those
that don't.

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

* [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
@ 2014-06-25 21:46       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:46 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add new bindings used for USB support by the Tegra XUSB pad controller.
> This includes additional PHY types, USB-specific pinconfig properties, etc.

> diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt

> @@ -21,6 +21,12 @@ Required properties:
>    - padctl
>  - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
>    See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
> +- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.

Why does the padctrl code need access to the XUSB mailbox? Isn't the
padctrl HW module something that provides services to the XUSB code. I
would have expected the XUSB node to reference the padctrl node. If
notifications need to be sent back from XUSB padctrl to XUSB, then that
seems like an internal SW detail that doesn't need to be represented in DT.

> +Optional properties:
> +-------------------
> +- vbus-otg-{0,1,2}-supply: VBUS regulator for the corresponding UTMI pad.

Isn't VBUS something that's controlled by the USB PHY? I think the PHYs
are part of the XUSB controller, whereas the XUSB pad control is just
the low level IO pad HW.

> +- nvidia,usb3-port-num: USB3 port (0 or 1) to which the lane is mapped.
> +- nvidia,usb2-port-num: USB2 port (0, 1, or 2) to which the lane is mapped.
> +- nvidia,hsic-strobe-trim: HSIC strobe trimmer value.
> +- nvidia,hsic-rx-strobe-trim: HSIC RX strobe trimmer value.
> +- nvidia,hsic-rx-data-trim: HSIC RX data trimmer value.
> +- nvidia,hsic-tx-rtune-n: HSIC TX RTUNEN value.
> +- nvidia,hsic-tx-rtune-p: HSIC TX RTUNEP value.
> +- nvidia,hsic-tx-slew-n: HSIC TX SLEWN value.
> +- nvidia,hsic-tx-slew-p: HSIC TX SLEWP value.
> +- nvidia,hsic-auto-term: Enables HSIC AUTO_TERM. (0: no, 1: yes)

I wonder if some of that isn't part of the PHY not the pads?

>      Valid functions for this group are: "snps", "xusb", "uart", "rsvd".
>  
> -    The nvidia,iddq property does not apply to this group.
> +    The nvidia,iddq, nvidia,usb3-port-num, nvidia,usb2-port-num, and
> +    nvidia,hsic-* properties do not apply to this group.

Given the increased number of properties we now have, it seems better to
list the properties that *do* apply to each group, rather than those
that don't.

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
  2014-06-18  6:16   ` Andrew Bresticker
  (?)
@ 2014-06-25 21:52       ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:52 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add device-tree binding documentation for the XHCI controller present
> on Tegra124 and later SoCs.

> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt

> +Required properties:
> +--------------------

> + - clock-names: Must include the following entries:
> +    - xusb_host
> +    - xusb_falcon_src
> +    - xusb_ss
> +    - xusb_ss_src
> +    - xusb_hs_src
> +    - xusb_fs_src
> +    - pll_u_480m
> +    - clk_m
> +    - pll_e

> + - reset-names: Must include the following entries:
> +   - xusb_host
> +   - xusb_ss

Usually the CAR has a reset control for each clock. So, I would expect
as many entries in reset-names as in clock-names. Even if the SW doesn't
currently touch all the reset lines, we should make sure the binding
requires them to be present so that any DT will contain the entries if
they're ever needed in the future.

In the CAR documentation, I see "XUSB_DEV" as a clock/reset bit. Is that
missing from the list above?

> + - nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.

As mentioned earlier, I think that's an internal implementation detail.
Shouldn't the two nodes be squashed together?

> +Optional properties:

> + - s1p05v-supply: 1.05V supply regulator.
> + - s1p8v-supply: 1.8V supply regulator.
> + - s3p3v-supply: 3.3V supply regulator.

What are those supplies for? I would have expected any input to the SoC
to have a name that described its purpose, and the pins and DT
properties would be named to match.

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 21:52       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:52 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree, linux-doc, linux-tegra,
	linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add device-tree binding documentation for the XHCI controller present
> on Tegra124 and later SoCs.

> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt

> +Required properties:
> +--------------------

> + - clock-names: Must include the following entries:
> +    - xusb_host
> +    - xusb_falcon_src
> +    - xusb_ss
> +    - xusb_ss_src
> +    - xusb_hs_src
> +    - xusb_fs_src
> +    - pll_u_480m
> +    - clk_m
> +    - pll_e

> + - reset-names: Must include the following entries:
> +   - xusb_host
> +   - xusb_ss

Usually the CAR has a reset control for each clock. So, I would expect
as many entries in reset-names as in clock-names. Even if the SW doesn't
currently touch all the reset lines, we should make sure the binding
requires them to be present so that any DT will contain the entries if
they're ever needed in the future.

In the CAR documentation, I see "XUSB_DEV" as a clock/reset bit. Is that
missing from the list above?

> + - nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.

As mentioned earlier, I think that's an internal implementation detail.
Shouldn't the two nodes be squashed together?

> +Optional properties:

> + - s1p05v-supply: 1.05V supply regulator.
> + - s1p8v-supply: 1.8V supply regulator.
> + - s3p3v-supply: 3.3V supply regulator.

What are those supplies for? I would have expected any input to the SoC
to have a name that described its purpose, and the pins and DT
properties would be named to match.

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

* [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 21:52       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add device-tree binding documentation for the XHCI controller present
> on Tegra124 and later SoCs.

> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt

> +Required properties:
> +--------------------

> + - clock-names: Must include the following entries:
> +    - xusb_host
> +    - xusb_falcon_src
> +    - xusb_ss
> +    - xusb_ss_src
> +    - xusb_hs_src
> +    - xusb_fs_src
> +    - pll_u_480m
> +    - clk_m
> +    - pll_e

> + - reset-names: Must include the following entries:
> +   - xusb_host
> +   - xusb_ss

Usually the CAR has a reset control for each clock. So, I would expect
as many entries in reset-names as in clock-names. Even if the SW doesn't
currently touch all the reset lines, we should make sure the binding
requires them to be present so that any DT will contain the entries if
they're ever needed in the future.

In the CAR documentation, I see "XUSB_DEV" as a clock/reset bit. Is that
missing from the list above?

> + - nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.

As mentioned earlier, I think that's an internal implementation detail.
Shouldn't the two nodes be squashed together?

> +Optional properties:

> + - s1p05v-supply: 1.05V supply regulator.
> + - s1p8v-supply: 1.8V supply regulator.
> + - s3p3v-supply: 3.3V supply regulator.

What are those supplies for? I would have expected any input to the SoC
to have a name that described its purpose, and the pins and DT
properties would be named to match.

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
  2014-06-18  6:16   ` Andrew Bresticker
  (?)
@ 2014-06-25 21:54       ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:54 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add device-tree binding documentation for the XHCI controller present
> on Tegra124 and later SoCs.

> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt

> + - clock-names: Must include the following entries:
> +    - xusb_host
> +    - xusb_falcon_src
> +    - xusb_ss
> +    - xusb_ss_src
> +    - xusb_hs_src
> +    - xusb_fs_src

Looking at include/dt-bindings/clock/tegra124-car.h I see a few entries
potentially missing here:

#define TEGRA124_CLK_XUSB_HOST_SRC 252
#define TEGRA124_CLK_XUSB_DEV_SRC 256
#define TEGRA124_CLK_XUSB_DEV 257
#define TEGRA124_CLK_XUSB_SS_DIV2 312

> +    - pll_u_480m

Not just pll_u?

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 21:54       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:54 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree, linux-doc, linux-tegra,
	linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add device-tree binding documentation for the XHCI controller present
> on Tegra124 and later SoCs.

> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt

> + - clock-names: Must include the following entries:
> +    - xusb_host
> +    - xusb_falcon_src
> +    - xusb_ss
> +    - xusb_ss_src
> +    - xusb_hs_src
> +    - xusb_fs_src

Looking at include/dt-bindings/clock/tegra124-car.h I see a few entries
potentially missing here:

#define TEGRA124_CLK_XUSB_HOST_SRC 252
#define TEGRA124_CLK_XUSB_DEV_SRC 256
#define TEGRA124_CLK_XUSB_DEV 257
#define TEGRA124_CLK_XUSB_SS_DIV2 312

> +    - pll_u_480m

Not just pll_u?

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

* [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 21:54       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 21:54 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add device-tree binding documentation for the XHCI controller present
> on Tegra124 and later SoCs.

> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt

> + - clock-names: Must include the following entries:
> +    - xusb_host
> +    - xusb_falcon_src
> +    - xusb_ss
> +    - xusb_ss_src
> +    - xusb_hs_src
> +    - xusb_fs_src

Looking at include/dt-bindings/clock/tegra124-car.h I see a few entries
potentially missing here:

#define TEGRA124_CLK_XUSB_HOST_SRC 252
#define TEGRA124_CLK_XUSB_DEV_SRC 256
#define TEGRA124_CLK_XUSB_DEV 257
#define TEGRA124_CLK_XUSB_SS_DIV2 312

> +    - pll_u_480m

Not just pll_u?

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

* Re: [PATCH v1 2/9] mailbox: Add NVIDIA Tegra XUSB mailbox driver
  2014-06-18  6:16   ` Andrew Bresticker
  (?)
@ 2014-06-25 22:02       ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 22:02 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> The Tegra XHCI controller communicates requests to the host through
> a mailbox interface.  Host drivers which can handle these requests,
> such as the Tegra XUSB pad controller driver and upcoming Tegra XHCI
> host controller driver, can send messages and register to be notified
> of incoming messages.

> diff --git a/include/linux/tegra-xusb-mbox.h b/include/linux/tegra-xusb-mbox.h

> +extern int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
> +					     struct notifier_block *nb);
> +extern void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
> +						struct notifier_block *nb);
> +extern int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
> +				enum tegra_xusb_mbox_cmd cmd, u32 data);
> +extern struct tegra_xusb_mbox *
> +tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop);

This seems to use a custom API. I've seen mention of a mailbox
subsystem, and I assume that has a standardized API. Should this driver
implement that instead?
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 2/9] mailbox: Add NVIDIA Tegra XUSB mailbox driver
@ 2014-06-25 22:02       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 22:02 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree, linux-doc, linux-tegra,
	linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> The Tegra XHCI controller communicates requests to the host through
> a mailbox interface.  Host drivers which can handle these requests,
> such as the Tegra XUSB pad controller driver and upcoming Tegra XHCI
> host controller driver, can send messages and register to be notified
> of incoming messages.

> diff --git a/include/linux/tegra-xusb-mbox.h b/include/linux/tegra-xusb-mbox.h

> +extern int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
> +					     struct notifier_block *nb);
> +extern void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
> +						struct notifier_block *nb);
> +extern int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
> +				enum tegra_xusb_mbox_cmd cmd, u32 data);
> +extern struct tegra_xusb_mbox *
> +tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop);

This seems to use a custom API. I've seen mention of a mailbox
subsystem, and I assume that has a standardized API. Should this driver
implement that instead?

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

* [PATCH v1 2/9] mailbox: Add NVIDIA Tegra XUSB mailbox driver
@ 2014-06-25 22:02       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 22:02 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> The Tegra XHCI controller communicates requests to the host through
> a mailbox interface.  Host drivers which can handle these requests,
> such as the Tegra XUSB pad controller driver and upcoming Tegra XHCI
> host controller driver, can send messages and register to be notified
> of incoming messages.

> diff --git a/include/linux/tegra-xusb-mbox.h b/include/linux/tegra-xusb-mbox.h

> +extern int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
> +					     struct notifier_block *nb);
> +extern void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
> +						struct notifier_block *nb);
> +extern int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
> +				enum tegra_xusb_mbox_cmd cmd, u32 data);
> +extern struct tegra_xusb_mbox *
> +tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop);

This seems to use a custom API. I've seen mention of a mailbox
subsystem, and I assume that has a standardized API. Should this driver
implement that instead?

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
  2014-06-18  6:16     ` Andrew Bresticker
@ 2014-06-25 22:12       ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 22:12 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree, linux-doc, linux-tegra,
	linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
> PCIe or SATA lane and is mapped to one of the three UTMI ports.
> 

> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c

> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>  			padctl_writel(padctl, regval, lane->offset);
>  			break;
>  
> +		case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
> +			if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
> +				dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
> +					value);
> +				return -EINVAL;
> +			}
> +			if (!is_pcie_sata_lane(group)) {
> +				dev_err(padctl->dev,
> +					"USB3 port not applicable for pin %d\n",
> +					group);
> +				return -EINVAL;
> +			}
> +			padctl->usb3_ports[value].lane = group;
> +			break;

It feels odd to use pinctrl for a SW-only purpose. In other words, that
chunk of code isn't writing the pinconf data to HW, but rather some
internal variable.

Perhaps it would make more sense for the DT binding to represent this
data directly in a custom property that's parsed at probe() time. That
way, pinctrl only touches "real" HW stuff.

> +static int usb3_phy_power_on(struct phy *phy)
> +{
> +	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
> +	int port = usb3_phy_to_port(phy);
> +	int lane = padctl->usb3_ports[port].lane;
> +	u32 value, offset;
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
> +	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
> +		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
> +		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
> +		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
> +		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
> +		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));

Hmm. So there is a lot of "PHY" stuff here after all.

However, the PHYs implemented here appear to implement very low-level
I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
somewhat higher-level; they're more USB-oriented than just IO pad
oriented. Do you know which level of abstraction a Linux PHY object is
supposed to be? I could never get an answer when I asked before.

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

* [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-25 22:12       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 22:12 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
> PCIe or SATA lane and is mapped to one of the three UTMI ports.
> 

> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c

> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>  			padctl_writel(padctl, regval, lane->offset);
>  			break;
>  
> +		case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
> +			if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
> +				dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
> +					value);
> +				return -EINVAL;
> +			}
> +			if (!is_pcie_sata_lane(group)) {
> +				dev_err(padctl->dev,
> +					"USB3 port not applicable for pin %d\n",
> +					group);
> +				return -EINVAL;
> +			}
> +			padctl->usb3_ports[value].lane = group;
> +			break;

It feels odd to use pinctrl for a SW-only purpose. In other words, that
chunk of code isn't writing the pinconf data to HW, but rather some
internal variable.

Perhaps it would make more sense for the DT binding to represent this
data directly in a custom property that's parsed at probe() time. That
way, pinctrl only touches "real" HW stuff.

> +static int usb3_phy_power_on(struct phy *phy)
> +{
> +	struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
> +	int port = usb3_phy_to_port(phy);
> +	int lane = padctl->usb3_ports[port].lane;
> +	u32 value, offset;
> +
> +	value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
> +	value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
> +		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
> +		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
> +		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
> +		   (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
> +		    XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));

Hmm. So there is a lot of "PHY" stuff here after all.

However, the PHYs implemented here appear to implement very low-level
I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
somewhat higher-level; they're more USB-oriented than just IO pad
oriented. Do you know which level of abstraction a Linux PHY object is
supposed to be? I could never get an answer when I asked before.

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

* Re: [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
  2014-06-25 21:46       ` Stephen Warren
  (?)
@ 2014-06-25 22:25         ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 22:25 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

Thanks for the review Stephen!

On Wed, Jun 25, 2014 at 2:46 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add new bindings used for USB support by the Tegra XUSB pad controller.
>> This includes additional PHY types, USB-specific pinconfig properties, etc.
>
>> diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
>
>> @@ -21,6 +21,12 @@ Required properties:
>>    - padctl
>>  - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
>>    See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
>> +- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
>
> Why does the padctrl code need access to the XUSB mailbox?

The XUSB firmware sends messages which make requests of the PHY (XUSB
pad controller), such as idling/un-idling the HSIC PHYs or saving USB3
PHY context.

> Isn't the padctrl HW module something that provides services to the XUSB
> code. I would have expected the XUSB node to reference the padctrl node.

The XUSB padctrl HW does provide services to the XUSB host in the form
of PHYs and it is through the PHY bindings that the host references
the padctrl node.

> If notifications need to be sent back from XUSB padctrl to XUSB, then that
> seems like an internal SW detail that doesn't need to be represented in DT.

I think you mean notifications need to be sent back from the XUSB host
to the XUSB padctrl?  This is what the mailbox is for and I chose to
have the padctrl refer to the mailbox since messages are sent from the
mailbox which make requests to the PHY specifically and not the host
(see above).

>> +Optional properties:
>> +-------------------
>> +- vbus-otg-{0,1,2}-supply: VBUS regulator for the corresponding UTMI pad.
>
> Isn't VBUS something that's controlled by the USB PHY? I think the PHYs
> are part of the XUSB controller, whereas the XUSB pad control is just
> the low level IO pad HW.

In the next patch in the series I extend the XUSB padctrl driver to
provide USB PHY support as it already does for SATA and PCIe.  Since
XUSB padctrl is also the PHY provider, I put the USB PHY properties
here.

>> +- nvidia,usb3-port-num: USB3 port (0 or 1) to which the lane is mapped.
>> +- nvidia,usb2-port-num: USB2 port (0, 1, or 2) to which the lane is mapped.
>> +- nvidia,hsic-strobe-trim: HSIC strobe trimmer value.
>> +- nvidia,hsic-rx-strobe-trim: HSIC RX strobe trimmer value.
>> +- nvidia,hsic-rx-data-trim: HSIC RX data trimmer value.
>> +- nvidia,hsic-tx-rtune-n: HSIC TX RTUNEN value.
>> +- nvidia,hsic-tx-rtune-p: HSIC TX RTUNEP value.
>> +- nvidia,hsic-tx-slew-n: HSIC TX SLEWN value.
>> +- nvidia,hsic-tx-slew-p: HSIC TX SLEWP value.
>> +- nvidia,hsic-auto-term: Enables HSIC AUTO_TERM. (0: no, 1: yes)
>
> I wonder if some of that isn't part of the PHY not the pads?

See above.

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

* Re: [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
@ 2014-06-25 22:25         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 22:25 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

Thanks for the review Stephen!

On Wed, Jun 25, 2014 at 2:46 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add new bindings used for USB support by the Tegra XUSB pad controller.
>> This includes additional PHY types, USB-specific pinconfig properties, etc.
>
>> diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
>
>> @@ -21,6 +21,12 @@ Required properties:
>>    - padctl
>>  - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
>>    See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
>> +- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
>
> Why does the padctrl code need access to the XUSB mailbox?

The XUSB firmware sends messages which make requests of the PHY (XUSB
pad controller), such as idling/un-idling the HSIC PHYs or saving USB3
PHY context.

> Isn't the padctrl HW module something that provides services to the XUSB
> code. I would have expected the XUSB node to reference the padctrl node.

The XUSB padctrl HW does provide services to the XUSB host in the form
of PHYs and it is through the PHY bindings that the host references
the padctrl node.

> If notifications need to be sent back from XUSB padctrl to XUSB, then that
> seems like an internal SW detail that doesn't need to be represented in DT.

I think you mean notifications need to be sent back from the XUSB host
to the XUSB padctrl?  This is what the mailbox is for and I chose to
have the padctrl refer to the mailbox since messages are sent from the
mailbox which make requests to the PHY specifically and not the host
(see above).

>> +Optional properties:
>> +-------------------
>> +- vbus-otg-{0,1,2}-supply: VBUS regulator for the corresponding UTMI pad.
>
> Isn't VBUS something that's controlled by the USB PHY? I think the PHYs
> are part of the XUSB controller, whereas the XUSB pad control is just
> the low level IO pad HW.

In the next patch in the series I extend the XUSB padctrl driver to
provide USB PHY support as it already does for SATA and PCIe.  Since
XUSB padctrl is also the PHY provider, I put the USB PHY properties
here.

>> +- nvidia,usb3-port-num: USB3 port (0 or 1) to which the lane is mapped.
>> +- nvidia,usb2-port-num: USB2 port (0, 1, or 2) to which the lane is mapped.
>> +- nvidia,hsic-strobe-trim: HSIC strobe trimmer value.
>> +- nvidia,hsic-rx-strobe-trim: HSIC RX strobe trimmer value.
>> +- nvidia,hsic-rx-data-trim: HSIC RX data trimmer value.
>> +- nvidia,hsic-tx-rtune-n: HSIC TX RTUNEN value.
>> +- nvidia,hsic-tx-rtune-p: HSIC TX RTUNEP value.
>> +- nvidia,hsic-tx-slew-n: HSIC TX SLEWN value.
>> +- nvidia,hsic-tx-slew-p: HSIC TX SLEWP value.
>> +- nvidia,hsic-auto-term: Enables HSIC AUTO_TERM. (0: no, 1: yes)
>
> I wonder if some of that isn't part of the PHY not the pads?

See above.

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

* [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
@ 2014-06-25 22:25         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 22:25 UTC (permalink / raw)
  To: linux-arm-kernel

Thanks for the review Stephen!

On Wed, Jun 25, 2014 at 2:46 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add new bindings used for USB support by the Tegra XUSB pad controller.
>> This includes additional PHY types, USB-specific pinconfig properties, etc.
>
>> diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
>
>> @@ -21,6 +21,12 @@ Required properties:
>>    - padctl
>>  - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
>>    See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
>> +- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
>
> Why does the padctrl code need access to the XUSB mailbox?

The XUSB firmware sends messages which make requests of the PHY (XUSB
pad controller), such as idling/un-idling the HSIC PHYs or saving USB3
PHY context.

> Isn't the padctrl HW module something that provides services to the XUSB
> code. I would have expected the XUSB node to reference the padctrl node.

The XUSB padctrl HW does provide services to the XUSB host in the form
of PHYs and it is through the PHY bindings that the host references
the padctrl node.

> If notifications need to be sent back from XUSB padctrl to XUSB, then that
> seems like an internal SW detail that doesn't need to be represented in DT.

I think you mean notifications need to be sent back from the XUSB host
to the XUSB padctrl?  This is what the mailbox is for and I chose to
have the padctrl refer to the mailbox since messages are sent from the
mailbox which make requests to the PHY specifically and not the host
(see above).

>> +Optional properties:
>> +-------------------
>> +- vbus-otg-{0,1,2}-supply: VBUS regulator for the corresponding UTMI pad.
>
> Isn't VBUS something that's controlled by the USB PHY? I think the PHYs
> are part of the XUSB controller, whereas the XUSB pad control is just
> the low level IO pad HW.

In the next patch in the series I extend the XUSB padctrl driver to
provide USB PHY support as it already does for SATA and PCIe.  Since
XUSB padctrl is also the PHY provider, I put the USB PHY properties
here.

>> +- nvidia,usb3-port-num: USB3 port (0 or 1) to which the lane is mapped.
>> +- nvidia,usb2-port-num: USB2 port (0, 1, or 2) to which the lane is mapped.
>> +- nvidia,hsic-strobe-trim: HSIC strobe trimmer value.
>> +- nvidia,hsic-rx-strobe-trim: HSIC RX strobe trimmer value.
>> +- nvidia,hsic-rx-data-trim: HSIC RX data trimmer value.
>> +- nvidia,hsic-tx-rtune-n: HSIC TX RTUNEN value.
>> +- nvidia,hsic-tx-rtune-p: HSIC TX RTUNEP value.
>> +- nvidia,hsic-tx-slew-n: HSIC TX SLEWN value.
>> +- nvidia,hsic-tx-slew-p: HSIC TX SLEWP value.
>> +- nvidia,hsic-auto-term: Enables HSIC AUTO_TERM. (0: no, 1: yes)
>
> I wonder if some of that isn't part of the PHY not the pads?

See above.

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

* Re: [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
  2014-06-25 21:42         ` Stephen Warren
  (?)
@ 2014-06-25 22:37             ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 22:37 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 2:42 PM, Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add device-tree bindings for the Tegra XUSB mailbox which will be used
>> for communication between the Tegra XHCI controller and the host.
>
> Sorry for the slow review.
>
>> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
>
>> +NVIDIA Tegra XUSB mailbox
>> +=========================
>> +
>> +The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
>> +communicate with the host.
>
> Isn't the mailbox an internal implementation detail of the XUSB controller.
>
> In other words, I'd naively think that there isn't a standalone generic
> mailbox that can be used by anything, but we just happen to want to use
> for XUSB. Rather, there's an XUSB controller, and part of the interface
> to that controller is a mailbox.

Yes, the mailbox isn't an actual piece of hardware but rather the
interface through which the XUSB host and AP communicate.

> As such, I don't think we want a standalone mailbox node in DT. Rather,
> we should add the required reg and interrupt values into the XUSB DT node.
>
> The driver for that XUSB HW module can either:
>
> a) Register as both a mailbox driver and an EHCI driver.
>
> b) Spawn a child device to instantiate the mailbox driver.
>
> Perhaps (b) could be assisted by using the MFD framework?

So in the RFC series I did something like (a) where the XUSB host
handled the mailbox interrupt with both the PHY and host could
registering notifiers to handle the messages.  It was suggested by
Arnd though that I make a separate mailbox driver.  Instead of having
a both a host and mailbox node, I could have a single XUSB host node
and have the mailbox driver bind to that - thoughts?
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
@ 2014-06-25 22:37             ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 22:37 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 2:42 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add device-tree bindings for the Tegra XUSB mailbox which will be used
>> for communication between the Tegra XHCI controller and the host.
>
> Sorry for the slow review.
>
>> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
>
>> +NVIDIA Tegra XUSB mailbox
>> +=========================
>> +
>> +The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
>> +communicate with the host.
>
> Isn't the mailbox an internal implementation detail of the XUSB controller.
>
> In other words, I'd naively think that there isn't a standalone generic
> mailbox that can be used by anything, but we just happen to want to use
> for XUSB. Rather, there's an XUSB controller, and part of the interface
> to that controller is a mailbox.

Yes, the mailbox isn't an actual piece of hardware but rather the
interface through which the XUSB host and AP communicate.

> As such, I don't think we want a standalone mailbox node in DT. Rather,
> we should add the required reg and interrupt values into the XUSB DT node.
>
> The driver for that XUSB HW module can either:
>
> a) Register as both a mailbox driver and an EHCI driver.
>
> b) Spawn a child device to instantiate the mailbox driver.
>
> Perhaps (b) could be assisted by using the MFD framework?

So in the RFC series I did something like (a) where the XUSB host
handled the mailbox interrupt with both the PHY and host could
registering notifiers to handle the messages.  It was suggested by
Arnd though that I make a separate mailbox driver.  Instead of having
a both a host and mailbox node, I could have a single XUSB host node
and have the mailbox driver bind to that - thoughts?

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

* [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
@ 2014-06-25 22:37             ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 25, 2014 at 2:42 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add device-tree bindings for the Tegra XUSB mailbox which will be used
>> for communication between the Tegra XHCI controller and the host.
>
> Sorry for the slow review.
>
>> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
>
>> +NVIDIA Tegra XUSB mailbox
>> +=========================
>> +
>> +The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
>> +communicate with the host.
>
> Isn't the mailbox an internal implementation detail of the XUSB controller.
>
> In other words, I'd naively think that there isn't a standalone generic
> mailbox that can be used by anything, but we just happen to want to use
> for XUSB. Rather, there's an XUSB controller, and part of the interface
> to that controller is a mailbox.

Yes, the mailbox isn't an actual piece of hardware but rather the
interface through which the XUSB host and AP communicate.

> As such, I don't think we want a standalone mailbox node in DT. Rather,
> we should add the required reg and interrupt values into the XUSB DT node.
>
> The driver for that XUSB HW module can either:
>
> a) Register as both a mailbox driver and an EHCI driver.
>
> b) Spawn a child device to instantiate the mailbox driver.
>
> Perhaps (b) could be assisted by using the MFD framework?

So in the RFC series I did something like (a) where the XUSB host
handled the mailbox interrupt with both the PHY and host could
registering notifiers to handle the messages.  It was suggested by
Arnd though that I make a separate mailbox driver.  Instead of having
a both a host and mailbox node, I could have a single XUSB host node
and have the mailbox driver bind to that - thoughts?

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-06-18  6:16     ` Andrew Bresticker
@ 2014-06-25 22:37       ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 22:37 UTC (permalink / raw)
  To: Andrew Bresticker, devicetree, linux-doc, linux-tegra,
	linux-kernel, linux-arm-kernel, linux-usb
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Mathias Nyman, Grant Likely, Alan Stern,
	Kishon Vijay Abraham I, Arnd Bergmann

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add support for the on-chip XHCI host controller present on Tegra 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>

> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig

> +config USB_XHCI_TEGRA
> +	tristate "NVIDIA Tegra XHCI support"
> +	depends on ARCH_TEGRA
> +	select PINCTRL_TEGRA_XUSB
> +	select TEGRA_XUSB_MBOX
> +	select FW_LOADER

I think at least some of those should be depends. In particular, the
mbox driver patch said:

+config TEGRA_XUSB_MBOX
+	bool "NVIDIA Tegra XUSB mailbox support"

which means the option is user-selectable. Either MBOX should be
invisible and selected here, or it should be visible with USB_XHCI_TEGRA
depending on it.

> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c

> +#define TEGRA_XHCI_UTMI_PHYS 3
> +#define TEGRA_XHCI_HSIC_PHYS 2
> +#define TEGRA_XHCI_USB3_PHYS 2
> +#define TEGRA_XHCI_MAX_PHYS (TEGRA_XHCI_UTMI_PHYS + TEGRA_XHCI_HSIC_PHYS + \
> +			     TEGRA_XHCI_USB3_PHYS)

Do those numbers need to be synchronized with the XUSB padctrl driver at
all?

> +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);
> +}

I assume some higher level has the required locking or single-threading
so that the keyhole register accesses don't get interleaved?

> +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->hcd->rsrc_start;

Don't you need to mask out the original value here? I guess whatever is
being written is probably always the same, but it seems scary to assume
that a bootloader, or previous version of a module during development,
didn't write something unexpected there. Perhaps if the HW module's
reset is pulsed we don't need to worry though.

> +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;

Are there endianness or CPU word size (e.g. ARMv8) issues here; this is
casting the content of a data file to a CPU data structure.

> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
> +				 unsigned long rate)

> +	switch (rate) {
> +	case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
> +		/* Reparent to PLLU_480M. Set div first to avoid overclocking */
> +		old_parent_rate = clk_get_rate(clk_get_parent(clk));
> +		new_parent_rate = clk_get_rate(tegra->pll_u_480m);
> +		div = new_parent_rate / rate;
> +		ret = clk_set_rate(clk, old_parent_rate / div);
> +		if (ret)
> +			return ret;
> +		ret = clk_set_parent(clk, tegra->pll_u_480m);
> +		if (ret)
> +			return ret;

Don't you need to call clk_set_rate() again after reparenting, since the
divisor will be different, and the rounding too.

> +static int tegra_xhci_regulator_enable(struct tegra_xhci_hcd *tegra)
> +{
> +	int ret;
> +
> +	ret = regulator_enable(tegra->s3p3v_reg);
> +	if (ret < 0)
> +		return ret;
> +	ret = regulator_enable(tegra->s1p8v_reg);
> +	if (ret < 0)
> +		goto disable_s3p3v;
> +	ret = regulator_enable(tegra->s1p05v_reg);
> +	if (ret < 0)
> +		goto disable_s1p8v;

Would regulator_bulk_enable() save any code here? Similar in _disable().

> +static const struct tegra_xhci_soc_config tegra124_soc_config = {
> +	.firmware_file = "tegra12x/tegra_xusb_firmware",
> +};

I would prefer an "nvidia/" prefix so everything gets namespaced by vendor.

"tegra12x" isn't the name of the chip, but rather "Tegra124".

"tegra_" and "_firmware" seem redundant, since they're implied by parent
directories.

So, how about "nvidia/tegra124/xusb"? (perhaps with .img or .bin file
extension)

> +static int tegra_xhci_probe(struct platform_device *pdev)

> +	tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
> +	if (IS_ERR(tegra->host_clk)) {
> +		ret = PTR_ERR(tegra->host_clk);
> +		goto put_hcd;
> +	}
> +	tegra->falc_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src");
> +	if (IS_ERR(tegra->falc_clk)) {
> +		ret = PTR_ERR(tegra->falc_clk);
> +		goto put_hcd;
> +	}
...

Seems like devm_clk_get_bulk() would be useful:-)

> +	for (i = 0; i < TEGRA_XHCI_UTMI_PHYS; i++) {
> +		char prop[sizeof("utmi-N")];
> +
> +		sprintf(prop, "utmi-%d", i);

Since this loop is cut/paste 3 times just with the string
"utmi"/"hsic"/"usb3" being different, does it make sense to add an outer
loop over an array of strings instead of duplicating the loo?

> +	ret = request_firmware_nowait(THIS_MODULE, true,
> +				      tegra->soc_config->firmware_file,
> +				      tegra->dev, GFP_KERNEL, tegra,
> +				      tegra_xhci_probe_finish);

I'm not familiar with that API. I assume the point is this works in allh
the following situations:

* Driver is built-in, probes before rootfs is available, firmware
eventually gets loaded a few seconds after rootfs is available.

* Driver is a module and gets loaded from an initrd, firmware is loaded
from initrd essentially immediately.

* Driver is a module and gets loaded from an initrd, firmware eventually
gets loaded a few seconds after rootfs is available.

* Driver is a module and gets loaded from rootfs, firmware is loaded
from rootfs essentially immediately.

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-25 22:37       ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 22:37 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
> Add support for the on-chip XHCI host controller present on Tegra 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>

> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig

> +config USB_XHCI_TEGRA
> +	tristate "NVIDIA Tegra XHCI support"
> +	depends on ARCH_TEGRA
> +	select PINCTRL_TEGRA_XUSB
> +	select TEGRA_XUSB_MBOX
> +	select FW_LOADER

I think at least some of those should be depends. In particular, the
mbox driver patch said:

+config TEGRA_XUSB_MBOX
+	bool "NVIDIA Tegra XUSB mailbox support"

which means the option is user-selectable. Either MBOX should be
invisible and selected here, or it should be visible with USB_XHCI_TEGRA
depending on it.

> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c

> +#define TEGRA_XHCI_UTMI_PHYS 3
> +#define TEGRA_XHCI_HSIC_PHYS 2
> +#define TEGRA_XHCI_USB3_PHYS 2
> +#define TEGRA_XHCI_MAX_PHYS (TEGRA_XHCI_UTMI_PHYS + TEGRA_XHCI_HSIC_PHYS + \
> +			     TEGRA_XHCI_USB3_PHYS)

Do those numbers need to be synchronized with the XUSB padctrl driver at
all?

> +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);
> +}

I assume some higher level has the required locking or single-threading
so that the keyhole register accesses don't get interleaved?

> +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->hcd->rsrc_start;

Don't you need to mask out the original value here? I guess whatever is
being written is probably always the same, but it seems scary to assume
that a bootloader, or previous version of a module during development,
didn't write something unexpected there. Perhaps if the HW module's
reset is pulsed we don't need to worry though.

> +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;

Are there endianness or CPU word size (e.g. ARMv8) issues here; this is
casting the content of a data file to a CPU data structure.

> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
> +				 unsigned long rate)

> +	switch (rate) {
> +	case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
> +		/* Reparent to PLLU_480M. Set div first to avoid overclocking */
> +		old_parent_rate = clk_get_rate(clk_get_parent(clk));
> +		new_parent_rate = clk_get_rate(tegra->pll_u_480m);
> +		div = new_parent_rate / rate;
> +		ret = clk_set_rate(clk, old_parent_rate / div);
> +		if (ret)
> +			return ret;
> +		ret = clk_set_parent(clk, tegra->pll_u_480m);
> +		if (ret)
> +			return ret;

Don't you need to call clk_set_rate() again after reparenting, since the
divisor will be different, and the rounding too.

> +static int tegra_xhci_regulator_enable(struct tegra_xhci_hcd *tegra)
> +{
> +	int ret;
> +
> +	ret = regulator_enable(tegra->s3p3v_reg);
> +	if (ret < 0)
> +		return ret;
> +	ret = regulator_enable(tegra->s1p8v_reg);
> +	if (ret < 0)
> +		goto disable_s3p3v;
> +	ret = regulator_enable(tegra->s1p05v_reg);
> +	if (ret < 0)
> +		goto disable_s1p8v;

Would regulator_bulk_enable() save any code here? Similar in _disable().

> +static const struct tegra_xhci_soc_config tegra124_soc_config = {
> +	.firmware_file = "tegra12x/tegra_xusb_firmware",
> +};

I would prefer an "nvidia/" prefix so everything gets namespaced by vendor.

"tegra12x" isn't the name of the chip, but rather "Tegra124".

"tegra_" and "_firmware" seem redundant, since they're implied by parent
directories.

So, how about "nvidia/tegra124/xusb"? (perhaps with .img or .bin file
extension)

> +static int tegra_xhci_probe(struct platform_device *pdev)

> +	tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
> +	if (IS_ERR(tegra->host_clk)) {
> +		ret = PTR_ERR(tegra->host_clk);
> +		goto put_hcd;
> +	}
> +	tegra->falc_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src");
> +	if (IS_ERR(tegra->falc_clk)) {
> +		ret = PTR_ERR(tegra->falc_clk);
> +		goto put_hcd;
> +	}
...

Seems like devm_clk_get_bulk() would be useful:-)

> +	for (i = 0; i < TEGRA_XHCI_UTMI_PHYS; i++) {
> +		char prop[sizeof("utmi-N")];
> +
> +		sprintf(prop, "utmi-%d", i);

Since this loop is cut/paste 3 times just with the string
"utmi"/"hsic"/"usb3" being different, does it make sense to add an outer
loop over an array of strings instead of duplicating the loo?

> +	ret = request_firmware_nowait(THIS_MODULE, true,
> +				      tegra->soc_config->firmware_file,
> +				      tegra->dev, GFP_KERNEL, tegra,
> +				      tegra_xhci_probe_finish);

I'm not familiar with that API. I assume the point is this works in allh
the following situations:

* Driver is built-in, probes before rootfs is available, firmware
eventually gets loaded a few seconds after rootfs is available.

* Driver is a module and gets loaded from an initrd, firmware is loaded
from initrd essentially immediately.

* Driver is a module and gets loaded from an initrd, firmware eventually
gets loaded a few seconds after rootfs is available.

* Driver is a module and gets loaded from rootfs, firmware is loaded
from rootfs essentially immediately.

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

* Re: [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
  2014-06-25 22:37             ` Andrew Bresticker
  (?)
@ 2014-06-25 23:00                 ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 23:00 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 04:37 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 2:42 PM, Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add device-tree bindings for the Tegra XUSB mailbox which will be used
>>> for communication between the Tegra XHCI controller and the host.
>>
>> Sorry for the slow review.
>>
>>> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
>>
>>> +NVIDIA Tegra XUSB mailbox
>>> +=========================
>>> +
>>> +The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
>>> +communicate with the host.
>>
>> Isn't the mailbox an internal implementation detail of the XUSB controller.
>>
>> In other words, I'd naively think that there isn't a standalone generic
>> mailbox that can be used by anything, but we just happen to want to use
>> for XUSB. Rather, there's an XUSB controller, and part of the interface
>> to that controller is a mailbox.
> 
> Yes, the mailbox isn't an actual piece of hardware but rather the
> interface through which the XUSB host and AP communicate.
> 
>> As such, I don't think we want a standalone mailbox node in DT. Rather,
>> we should add the required reg and interrupt values into the XUSB DT node.
>>
>> The driver for that XUSB HW module can either:
>>
>> a) Register as both a mailbox driver and an EHCI driver.
>>
>> b) Spawn a child device to instantiate the mailbox driver.
>>
>> Perhaps (b) could be assisted by using the MFD framework?
> 
> So in the RFC series I did something like (a) where the XUSB host
> handled the mailbox interrupt with both the PHY and host could
> registering notifiers to handle the messages.  It was suggested by
> Arnd though that I make a separate mailbox driver.  Instead of having
> a both a host and mailbox node, I could have a single XUSB host node
> and have the mailbox driver bind to that - thoughts?

Yes, that sounds like what I meant by (b) above. I don't think you can
actually have 2 drivers bind to the same DT node though, so it'd have to
work something like:

* XUSB host node causes a platform device to be instantiated
* XUSB host driver probe()s against that
* XUSB host driver's probe() creates a platform device for the mailbox
* XUSB mailbox driver probe()s against that.

Or, perhaps go completely MFD, and have 2 child devices (XUSB host and
XUSB mailbox) instantiated by the MFD parent, which is what is in the DT.
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
@ 2014-06-25 23:00                 ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 23:00 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 04:37 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 2:42 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add device-tree bindings for the Tegra XUSB mailbox which will be used
>>> for communication between the Tegra XHCI controller and the host.
>>
>> Sorry for the slow review.
>>
>>> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
>>
>>> +NVIDIA Tegra XUSB mailbox
>>> +=========================
>>> +
>>> +The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
>>> +communicate with the host.
>>
>> Isn't the mailbox an internal implementation detail of the XUSB controller.
>>
>> In other words, I'd naively think that there isn't a standalone generic
>> mailbox that can be used by anything, but we just happen to want to use
>> for XUSB. Rather, there's an XUSB controller, and part of the interface
>> to that controller is a mailbox.
> 
> Yes, the mailbox isn't an actual piece of hardware but rather the
> interface through which the XUSB host and AP communicate.
> 
>> As such, I don't think we want a standalone mailbox node in DT. Rather,
>> we should add the required reg and interrupt values into the XUSB DT node.
>>
>> The driver for that XUSB HW module can either:
>>
>> a) Register as both a mailbox driver and an EHCI driver.
>>
>> b) Spawn a child device to instantiate the mailbox driver.
>>
>> Perhaps (b) could be assisted by using the MFD framework?
> 
> So in the RFC series I did something like (a) where the XUSB host
> handled the mailbox interrupt with both the PHY and host could
> registering notifiers to handle the messages.  It was suggested by
> Arnd though that I make a separate mailbox driver.  Instead of having
> a both a host and mailbox node, I could have a single XUSB host node
> and have the mailbox driver bind to that - thoughts?

Yes, that sounds like what I meant by (b) above. I don't think you can
actually have 2 drivers bind to the same DT node though, so it'd have to
work something like:

* XUSB host node causes a platform device to be instantiated
* XUSB host driver probe()s against that
* XUSB host driver's probe() creates a platform device for the mailbox
* XUSB mailbox driver probe()s against that.

Or, perhaps go completely MFD, and have 2 child devices (XUSB host and
XUSB mailbox) instantiated by the MFD parent, which is what is in the DT.

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

* [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding
@ 2014-06-25 23:00                 ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 23:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/25/2014 04:37 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 2:42 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add device-tree bindings for the Tegra XUSB mailbox which will be used
>>> for communication between the Tegra XHCI controller and the host.
>>
>> Sorry for the slow review.
>>
>>> diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra124-xusb-mbox.txt
>>
>>> +NVIDIA Tegra XUSB mailbox
>>> +=========================
>>> +
>>> +The Tegra XUSB mailbox is used by the Tegra XHCI controller's firmware to
>>> +communicate with the host.
>>
>> Isn't the mailbox an internal implementation detail of the XUSB controller.
>>
>> In other words, I'd naively think that there isn't a standalone generic
>> mailbox that can be used by anything, but we just happen to want to use
>> for XUSB. Rather, there's an XUSB controller, and part of the interface
>> to that controller is a mailbox.
> 
> Yes, the mailbox isn't an actual piece of hardware but rather the
> interface through which the XUSB host and AP communicate.
> 
>> As such, I don't think we want a standalone mailbox node in DT. Rather,
>> we should add the required reg and interrupt values into the XUSB DT node.
>>
>> The driver for that XUSB HW module can either:
>>
>> a) Register as both a mailbox driver and an EHCI driver.
>>
>> b) Spawn a child device to instantiate the mailbox driver.
>>
>> Perhaps (b) could be assisted by using the MFD framework?
> 
> So in the RFC series I did something like (a) where the XUSB host
> handled the mailbox interrupt with both the PHY and host could
> registering notifiers to handle the messages.  It was suggested by
> Arnd though that I make a separate mailbox driver.  Instead of having
> a both a host and mailbox node, I could have a single XUSB host node
> and have the mailbox driver bind to that - thoughts?

Yes, that sounds like what I meant by (b) above. I don't think you can
actually have 2 drivers bind to the same DT node though, so it'd have to
work something like:

* XUSB host node causes a platform device to be instantiated
* XUSB host driver probe()s against that
* XUSB host driver's probe() creates a platform device for the mailbox
* XUSB mailbox driver probe()s against that.

Or, perhaps go completely MFD, and have 2 child devices (XUSB host and
XUSB mailbox) instantiated by the MFD parent, which is what is in the DT.

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
  2014-06-25 21:52       ` Stephen Warren
  (?)
@ 2014-06-25 23:01         ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:01 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 2:52 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add device-tree binding documentation for the XHCI controller present
>> on Tegra124 and later SoCs.
>
>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>
>> +Required properties:
>> +--------------------
>
>> + - clock-names: Must include the following entries:
>> +    - xusb_host
>> +    - xusb_falcon_src
>> +    - xusb_ss
>> +    - xusb_ss_src
>> +    - xusb_hs_src
>> +    - xusb_fs_src
>> +    - pll_u_480m
>> +    - clk_m
>> +    - pll_e
>
>> + - reset-names: Must include the following entries:
>> +   - xusb_host
>> +   - xusb_ss
>
> Usually the CAR has a reset control for each clock. So, I would expect
> as many entries in reset-names as in clock-names. Even if the SW doesn't
> currently touch all the reset lines, we should make sure the binding
> requires them to be present so that any DT will contain the entries if
> they're ever needed in the future.

The xusb_{falcon,host,hs,fs,ss}_src clocks all share the same reset
bit (143), so I can add a single entry for those.

> In the CAR documentation, I see "XUSB_DEV" as a clock/reset bit. Is that
> missing from the list above?

This is used when XUSB is in device mode, which the driver does not
support.  I can add those clocks here though if you want.

>> +Optional properties:
>
>> + - s1p05v-supply: 1.05V supply regulator.
>> + - s1p8v-supply: 1.8V supply regulator.
>> + - s3p3v-supply: 3.3V supply regulator.
>
> What are those supplies for? I would have expected any input to the SoC
> to have a name that described its purpose, and the pins and DT
> properties would be named to match.

I *think* this what they are from looking at the schematic, but I'll
have to ask around:
 - s1p05v: avddio_pex, dvddio_pex, and maybe avdd_pll_erefe
 - s1p8v: avdd_pll_utmip
 - s3p3v: avdd_usb, hvdd_pex, hvdd_pex_pll_e
Should these be separated out as they are for PCIe?

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 23:01         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:01 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 2:52 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add device-tree binding documentation for the XHCI controller present
>> on Tegra124 and later SoCs.
>
>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>
>> +Required properties:
>> +--------------------
>
>> + - clock-names: Must include the following entries:
>> +    - xusb_host
>> +    - xusb_falcon_src
>> +    - xusb_ss
>> +    - xusb_ss_src
>> +    - xusb_hs_src
>> +    - xusb_fs_src
>> +    - pll_u_480m
>> +    - clk_m
>> +    - pll_e
>
>> + - reset-names: Must include the following entries:
>> +   - xusb_host
>> +   - xusb_ss
>
> Usually the CAR has a reset control for each clock. So, I would expect
> as many entries in reset-names as in clock-names. Even if the SW doesn't
> currently touch all the reset lines, we should make sure the binding
> requires them to be present so that any DT will contain the entries if
> they're ever needed in the future.

The xusb_{falcon,host,hs,fs,ss}_src clocks all share the same reset
bit (143), so I can add a single entry for those.

> In the CAR documentation, I see "XUSB_DEV" as a clock/reset bit. Is that
> missing from the list above?

This is used when XUSB is in device mode, which the driver does not
support.  I can add those clocks here though if you want.

>> +Optional properties:
>
>> + - s1p05v-supply: 1.05V supply regulator.
>> + - s1p8v-supply: 1.8V supply regulator.
>> + - s3p3v-supply: 3.3V supply regulator.
>
> What are those supplies for? I would have expected any input to the SoC
> to have a name that described its purpose, and the pins and DT
> properties would be named to match.

I *think* this what they are from looking at the schematic, but I'll
have to ask around:
 - s1p05v: avddio_pex, dvddio_pex, and maybe avdd_pll_erefe
 - s1p8v: avdd_pll_utmip
 - s3p3v: avdd_usb, hvdd_pex, hvdd_pex_pll_e
Should these be separated out as they are for PCIe?

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

* [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 23:01         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 25, 2014 at 2:52 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add device-tree binding documentation for the XHCI controller present
>> on Tegra124 and later SoCs.
>
>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>
>> +Required properties:
>> +--------------------
>
>> + - clock-names: Must include the following entries:
>> +    - xusb_host
>> +    - xusb_falcon_src
>> +    - xusb_ss
>> +    - xusb_ss_src
>> +    - xusb_hs_src
>> +    - xusb_fs_src
>> +    - pll_u_480m
>> +    - clk_m
>> +    - pll_e
>
>> + - reset-names: Must include the following entries:
>> +   - xusb_host
>> +   - xusb_ss
>
> Usually the CAR has a reset control for each clock. So, I would expect
> as many entries in reset-names as in clock-names. Even if the SW doesn't
> currently touch all the reset lines, we should make sure the binding
> requires them to be present so that any DT will contain the entries if
> they're ever needed in the future.

The xusb_{falcon,host,hs,fs,ss}_src clocks all share the same reset
bit (143), so I can add a single entry for those.

> In the CAR documentation, I see "XUSB_DEV" as a clock/reset bit. Is that
> missing from the list above?

This is used when XUSB is in device mode, which the driver does not
support.  I can add those clocks here though if you want.

>> +Optional properties:
>
>> + - s1p05v-supply: 1.05V supply regulator.
>> + - s1p8v-supply: 1.8V supply regulator.
>> + - s3p3v-supply: 3.3V supply regulator.
>
> What are those supplies for? I would have expected any input to the SoC
> to have a name that described its purpose, and the pins and DT
> properties would be named to match.

I *think* this what they are from looking at the schematic, but I'll
have to ask around:
 - s1p05v: avddio_pex, dvddio_pex, and maybe avdd_pll_erefe
 - s1p8v: avdd_pll_utmip
 - s3p3v: avdd_usb, hvdd_pex, hvdd_pex_pll_e
Should these be separated out as they are for PCIe?

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
  2014-06-25 21:54       ` Stephen Warren
  (?)
@ 2014-06-25 23:02           ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:02 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 2:54 PM, Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add device-tree binding documentation for the XHCI controller present
>> on Tegra124 and later SoCs.
>
>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>
>> + - clock-names: Must include the following entries:
>> +    - xusb_host
>> +    - xusb_falcon_src
>> +    - xusb_ss
>> +    - xusb_ss_src
>> +    - xusb_hs_src
>> +    - xusb_fs_src
>
> Looking at include/dt-bindings/clock/tegra124-car.h I see a few entries
> potentially missing here:
>
> #define TEGRA124_CLK_XUSB_HOST_SRC 252
> #define TEGRA124_CLK_XUSB_DEV_SRC 256
> #define TEGRA124_CLK_XUSB_DEV 257
> #define TEGRA124_CLK_XUSB_SS_DIV2 312

The driver doesn't use them, so I didn't put them in the binding.

>> +    - pll_u_480m
>
> Not just pll_u?

We specifically want pll_u_480M as that's what we use as the parent of
xusb_ss_src when scaling it to 120Mhz.

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 23:02           ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:02 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 2:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add device-tree binding documentation for the XHCI controller present
>> on Tegra124 and later SoCs.
>
>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>
>> + - clock-names: Must include the following entries:
>> +    - xusb_host
>> +    - xusb_falcon_src
>> +    - xusb_ss
>> +    - xusb_ss_src
>> +    - xusb_hs_src
>> +    - xusb_fs_src
>
> Looking at include/dt-bindings/clock/tegra124-car.h I see a few entries
> potentially missing here:
>
> #define TEGRA124_CLK_XUSB_HOST_SRC 252
> #define TEGRA124_CLK_XUSB_DEV_SRC 256
> #define TEGRA124_CLK_XUSB_DEV 257
> #define TEGRA124_CLK_XUSB_SS_DIV2 312

The driver doesn't use them, so I didn't put them in the binding.

>> +    - pll_u_480m
>
> Not just pll_u?

We specifically want pll_u_480M as that's what we use as the parent of
xusb_ss_src when scaling it to 120Mhz.

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

* [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 23:02           ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 25, 2014 at 2:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add device-tree binding documentation for the XHCI controller present
>> on Tegra124 and later SoCs.
>
>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>
>> + - clock-names: Must include the following entries:
>> +    - xusb_host
>> +    - xusb_falcon_src
>> +    - xusb_ss
>> +    - xusb_ss_src
>> +    - xusb_hs_src
>> +    - xusb_fs_src
>
> Looking at include/dt-bindings/clock/tegra124-car.h I see a few entries
> potentially missing here:
>
> #define TEGRA124_CLK_XUSB_HOST_SRC 252
> #define TEGRA124_CLK_XUSB_DEV_SRC 256
> #define TEGRA124_CLK_XUSB_DEV 257
> #define TEGRA124_CLK_XUSB_SS_DIV2 312

The driver doesn't use them, so I didn't put them in the binding.

>> +    - pll_u_480m
>
> Not just pll_u?

We specifically want pll_u_480M as that's what we use as the parent of
xusb_ss_src when scaling it to 120Mhz.

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

* Re: [PATCH v1 2/9] mailbox: Add NVIDIA Tegra XUSB mailbox driver
  2014-06-25 22:02       ` Stephen Warren
  (?)
@ 2014-06-25 23:07         ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:07 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 3:02 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> The Tegra XHCI controller communicates requests to the host through
>> a mailbox interface.  Host drivers which can handle these requests,
>> such as the Tegra XUSB pad controller driver and upcoming Tegra XHCI
>> host controller driver, can send messages and register to be notified
>> of incoming messages.
>
>> diff --git a/include/linux/tegra-xusb-mbox.h b/include/linux/tegra-xusb-mbox.h
>
>> +extern int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
>> +                                          struct notifier_block *nb);
>> +extern void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
>> +                                             struct notifier_block *nb);
>> +extern int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
>> +                             enum tegra_xusb_mbox_cmd cmd, u32 data);
>> +extern struct tegra_xusb_mbox *
>> +tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop);
>
> This seems to use a custom API. I've seen mention of a mailbox
> subsystem, and I assume that has a standardized API. Should this driver
> implement that instead?

All the mailbox drivers currently use a custom API, but there is
indeed a patch series floating around to create a generic mailbox
framework, though it hasn't landed in -next yet.  I can take a look at
how this driver would fit into that framework.

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

* Re: [PATCH v1 2/9] mailbox: Add NVIDIA Tegra XUSB mailbox driver
@ 2014-06-25 23:07         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:07 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 3:02 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> The Tegra XHCI controller communicates requests to the host through
>> a mailbox interface.  Host drivers which can handle these requests,
>> such as the Tegra XUSB pad controller driver and upcoming Tegra XHCI
>> host controller driver, can send messages and register to be notified
>> of incoming messages.
>
>> diff --git a/include/linux/tegra-xusb-mbox.h b/include/linux/tegra-xusb-mbox.h
>
>> +extern int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
>> +                                          struct notifier_block *nb);
>> +extern void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
>> +                                             struct notifier_block *nb);
>> +extern int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
>> +                             enum tegra_xusb_mbox_cmd cmd, u32 data);
>> +extern struct tegra_xusb_mbox *
>> +tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop);
>
> This seems to use a custom API. I've seen mention of a mailbox
> subsystem, and I assume that has a standardized API. Should this driver
> implement that instead?

All the mailbox drivers currently use a custom API, but there is
indeed a patch series floating around to create a generic mailbox
framework, though it hasn't landed in -next yet.  I can take a look at
how this driver would fit into that framework.

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

* [PATCH v1 2/9] mailbox: Add NVIDIA Tegra XUSB mailbox driver
@ 2014-06-25 23:07         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 25, 2014 at 3:02 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> The Tegra XHCI controller communicates requests to the host through
>> a mailbox interface.  Host drivers which can handle these requests,
>> such as the Tegra XUSB pad controller driver and upcoming Tegra XHCI
>> host controller driver, can send messages and register to be notified
>> of incoming messages.
>
>> diff --git a/include/linux/tegra-xusb-mbox.h b/include/linux/tegra-xusb-mbox.h
>
>> +extern int tegra_xusb_mbox_register_notifier(struct tegra_xusb_mbox *mbox,
>> +                                          struct notifier_block *nb);
>> +extern void tegra_xusb_mbox_unregister_notifier(struct tegra_xusb_mbox *mbox,
>> +                                             struct notifier_block *nb);
>> +extern int tegra_xusb_mbox_send(struct tegra_xusb_mbox *mbox,
>> +                             enum tegra_xusb_mbox_cmd cmd, u32 data);
>> +extern struct tegra_xusb_mbox *
>> +tegra_xusb_mbox_lookup_by_phandle(struct device_node *np, const char *prop);
>
> This seems to use a custom API. I've seen mention of a mailbox
> subsystem, and I assume that has a standardized API. Should this driver
> implement that instead?

All the mailbox drivers currently use a custom API, but there is
indeed a patch series floating around to create a generic mailbox
framework, though it hasn't landed in -next yet.  I can take a look at
how this driver would fit into that framework.

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
  2014-06-25 23:01         ` Andrew Bresticker
  (?)
@ 2014-06-25 23:13             ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 23:13 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 05:01 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 2:52 PM, Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add device-tree binding documentation for the XHCI controller present
>>> on Tegra124 and later SoCs.
>>
>>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>>
>>> +Required properties:
>>> +--------------------
>>
>>> + - clock-names: Must include the following entries:
>>> +    - xusb_host
>>> +    - xusb_falcon_src
>>> +    - xusb_ss
>>> +    - xusb_ss_src
>>> +    - xusb_hs_src
>>> +    - xusb_fs_src
>>> +    - pll_u_480m
>>> +    - clk_m
>>> +    - pll_e
>>
>>> + - reset-names: Must include the following entries:
>>> +   - xusb_host
>>> +   - xusb_ss
>>
>> Usually the CAR has a reset control for each clock. So, I would expect
>> as many entries in reset-names as in clock-names. Even if the SW doesn't
>> currently touch all the reset lines, we should make sure the binding
>> requires them to be present so that any DT will contain the entries if
>> they're ever needed in the future.
> 
> The xusb_{falcon,host,hs,fs,ss}_src clocks all share the same reset
> bit (143), so I can add a single entry for those.
> 
>> In the CAR documentation, I see "XUSB_DEV" as a clock/reset bit. Is that
>> missing from the list above?
> 
> This is used when XUSB is in device mode, which the driver does not
> support.  I can add those clocks here though if you want.

That'd be a good idea. That way, the DT doesn't have to change later.

>>> +Optional properties:
>>
>>> + - s1p05v-supply: 1.05V supply regulator.
>>> + - s1p8v-supply: 1.8V supply regulator.
>>> + - s3p3v-supply: 3.3V supply regulator.
>>
>> What are those supplies for? I would have expected any input to the SoC
>> to have a name that described its purpose, and the pins and DT
>> properties would be named to match.
> 
> I *think* this what they are from looking at the schematic, but I'll
> have to ask around:
>  - s1p05v: avddio_pex, dvddio_pex, and maybe avdd_pll_erefe
>  - s1p8v: avdd_pll_utmip
>  - s3p3v: avdd_usb, hvdd_pex, hvdd_pex_pll_e
> Should these be separated out as they are for PCIe?

Yes, I think they should be separated. I wonder if the supplies for PCIe
shouldn't have been added to the XUSB padctrl rather than PCIe node
though? It probably doesn't matter much either way.

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 23:13             ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 23:13 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 05:01 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 2:52 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add device-tree binding documentation for the XHCI controller present
>>> on Tegra124 and later SoCs.
>>
>>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>>
>>> +Required properties:
>>> +--------------------
>>
>>> + - clock-names: Must include the following entries:
>>> +    - xusb_host
>>> +    - xusb_falcon_src
>>> +    - xusb_ss
>>> +    - xusb_ss_src
>>> +    - xusb_hs_src
>>> +    - xusb_fs_src
>>> +    - pll_u_480m
>>> +    - clk_m
>>> +    - pll_e
>>
>>> + - reset-names: Must include the following entries:
>>> +   - xusb_host
>>> +   - xusb_ss
>>
>> Usually the CAR has a reset control for each clock. So, I would expect
>> as many entries in reset-names as in clock-names. Even if the SW doesn't
>> currently touch all the reset lines, we should make sure the binding
>> requires them to be present so that any DT will contain the entries if
>> they're ever needed in the future.
> 
> The xusb_{falcon,host,hs,fs,ss}_src clocks all share the same reset
> bit (143), so I can add a single entry for those.
> 
>> In the CAR documentation, I see "XUSB_DEV" as a clock/reset bit. Is that
>> missing from the list above?
> 
> This is used when XUSB is in device mode, which the driver does not
> support.  I can add those clocks here though if you want.

That'd be a good idea. That way, the DT doesn't have to change later.

>>> +Optional properties:
>>
>>> + - s1p05v-supply: 1.05V supply regulator.
>>> + - s1p8v-supply: 1.8V supply regulator.
>>> + - s3p3v-supply: 3.3V supply regulator.
>>
>> What are those supplies for? I would have expected any input to the SoC
>> to have a name that described its purpose, and the pins and DT
>> properties would be named to match.
> 
> I *think* this what they are from looking at the schematic, but I'll
> have to ask around:
>  - s1p05v: avddio_pex, dvddio_pex, and maybe avdd_pll_erefe
>  - s1p8v: avdd_pll_utmip
>  - s3p3v: avdd_usb, hvdd_pex, hvdd_pex_pll_e
> Should these be separated out as they are for PCIe?

Yes, I think they should be separated. I wonder if the supplies for PCIe
shouldn't have been added to the XUSB padctrl rather than PCIe node
though? It probably doesn't matter much either way.

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

* [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 23:13             ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 23:13 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/25/2014 05:01 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 2:52 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add device-tree binding documentation for the XHCI controller present
>>> on Tegra124 and later SoCs.
>>
>>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>>
>>> +Required properties:
>>> +--------------------
>>
>>> + - clock-names: Must include the following entries:
>>> +    - xusb_host
>>> +    - xusb_falcon_src
>>> +    - xusb_ss
>>> +    - xusb_ss_src
>>> +    - xusb_hs_src
>>> +    - xusb_fs_src
>>> +    - pll_u_480m
>>> +    - clk_m
>>> +    - pll_e
>>
>>> + - reset-names: Must include the following entries:
>>> +   - xusb_host
>>> +   - xusb_ss
>>
>> Usually the CAR has a reset control for each clock. So, I would expect
>> as many entries in reset-names as in clock-names. Even if the SW doesn't
>> currently touch all the reset lines, we should make sure the binding
>> requires them to be present so that any DT will contain the entries if
>> they're ever needed in the future.
> 
> The xusb_{falcon,host,hs,fs,ss}_src clocks all share the same reset
> bit (143), so I can add a single entry for those.
> 
>> In the CAR documentation, I see "XUSB_DEV" as a clock/reset bit. Is that
>> missing from the list above?
> 
> This is used when XUSB is in device mode, which the driver does not
> support.  I can add those clocks here though if you want.

That'd be a good idea. That way, the DT doesn't have to change later.

>>> +Optional properties:
>>
>>> + - s1p05v-supply: 1.05V supply regulator.
>>> + - s1p8v-supply: 1.8V supply regulator.
>>> + - s3p3v-supply: 3.3V supply regulator.
>>
>> What are those supplies for? I would have expected any input to the SoC
>> to have a name that described its purpose, and the pins and DT
>> properties would be named to match.
> 
> I *think* this what they are from looking at the schematic, but I'll
> have to ask around:
>  - s1p05v: avddio_pex, dvddio_pex, and maybe avdd_pll_erefe
>  - s1p8v: avdd_pll_utmip
>  - s3p3v: avdd_usb, hvdd_pex, hvdd_pex_pll_e
> Should these be separated out as they are for PCIe?

Yes, I think they should be separated. I wonder if the supplies for PCIe
shouldn't have been added to the XUSB padctrl rather than PCIe node
though? It probably doesn't matter much either way.

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
  2014-06-25 23:02           ` Andrew Bresticker
  (?)
@ 2014-06-25 23:14               ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 23:14 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 05:02 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 2:54 PM, Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add device-tree binding documentation for the XHCI controller present
>>> on Tegra124 and later SoCs.
>>
>>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>>
>>> + - clock-names: Must include the following entries:
>>> +    - xusb_host
>>> +    - xusb_falcon_src
>>> +    - xusb_ss
>>> +    - xusb_ss_src
>>> +    - xusb_hs_src
>>> +    - xusb_fs_src
>>
>> Looking at include/dt-bindings/clock/tegra124-car.h I see a few entries
>> potentially missing here:
>>
>> #define TEGRA124_CLK_XUSB_HOST_SRC 252
>> #define TEGRA124_CLK_XUSB_DEV_SRC 256
>> #define TEGRA124_CLK_XUSB_DEV 257
>> #define TEGRA124_CLK_XUSB_SS_DIV2 312
> 
> The driver doesn't use them, so I didn't put them in the binding.

I think we should add them in case we need them later. Best to fully
describe the HW rather than the parts of the HW that SW currently uses.

>>> +    - pll_u_480m
>>
>> Not just pll_u?
> 
> We specifically want pll_u_480M as that's what we use as the parent of
> xusb_ss_src when scaling it to 120Mhz.

OK. I recall text in the TRM implying that SW should just leave PLL_U
alone and not fiddle with the separate output clocks. Still, if we have
a clock ID for each output, and it's the correct parent for the clock,
then it does make sense to use that ID.
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 23:14               ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 23:14 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 05:02 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 2:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add device-tree binding documentation for the XHCI controller present
>>> on Tegra124 and later SoCs.
>>
>>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>>
>>> + - clock-names: Must include the following entries:
>>> +    - xusb_host
>>> +    - xusb_falcon_src
>>> +    - xusb_ss
>>> +    - xusb_ss_src
>>> +    - xusb_hs_src
>>> +    - xusb_fs_src
>>
>> Looking at include/dt-bindings/clock/tegra124-car.h I see a few entries
>> potentially missing here:
>>
>> #define TEGRA124_CLK_XUSB_HOST_SRC 252
>> #define TEGRA124_CLK_XUSB_DEV_SRC 256
>> #define TEGRA124_CLK_XUSB_DEV 257
>> #define TEGRA124_CLK_XUSB_SS_DIV2 312
> 
> The driver doesn't use them, so I didn't put them in the binding.

I think we should add them in case we need them later. Best to fully
describe the HW rather than the parts of the HW that SW currently uses.

>>> +    - pll_u_480m
>>
>> Not just pll_u?
> 
> We specifically want pll_u_480M as that's what we use as the parent of
> xusb_ss_src when scaling it to 120Mhz.

OK. I recall text in the TRM implying that SW should just leave PLL_U
alone and not fiddle with the separate output clocks. Still, if we have
a clock ID for each output, and it's the correct parent for the clock,
then it does make sense to use that ID.

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

* [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding
@ 2014-06-25 23:14               ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-25 23:14 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/25/2014 05:02 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 2:54 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add device-tree binding documentation for the XHCI controller present
>>> on Tegra124 and later SoCs.
>>
>>> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xhci.txt
>>
>>> + - clock-names: Must include the following entries:
>>> +    - xusb_host
>>> +    - xusb_falcon_src
>>> +    - xusb_ss
>>> +    - xusb_ss_src
>>> +    - xusb_hs_src
>>> +    - xusb_fs_src
>>
>> Looking at include/dt-bindings/clock/tegra124-car.h I see a few entries
>> potentially missing here:
>>
>> #define TEGRA124_CLK_XUSB_HOST_SRC 252
>> #define TEGRA124_CLK_XUSB_DEV_SRC 256
>> #define TEGRA124_CLK_XUSB_DEV 257
>> #define TEGRA124_CLK_XUSB_SS_DIV2 312
> 
> The driver doesn't use them, so I didn't put them in the binding.

I think we should add them in case we need them later. Best to fully
describe the HW rather than the parts of the HW that SW currently uses.

>>> +    - pll_u_480m
>>
>> Not just pll_u?
> 
> We specifically want pll_u_480M as that's what we use as the parent of
> xusb_ss_src when scaling it to 120Mhz.

OK. I recall text in the TRM implying that SW should just leave PLL_U
alone and not fiddle with the separate output clocks. Still, if we have
a clock ID for each output, and it's the correct parent for the clock,
then it does make sense to use that ID.

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
  2014-06-25 22:12       ` Stephen Warren
  (?)
@ 2014-06-25 23:30         ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:30 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann, bal

On Wed, Jun 25, 2014 at 3:12 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
>> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
>> PCIe or SATA lane and is mapped to one of the three UTMI ports.
>>
>
>> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
>
>> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>>                       padctl_writel(padctl, regval, lane->offset);
>>                       break;
>>
>> +             case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
>> +                     if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
>> +                             dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
>> +                                     value);
>> +                             return -EINVAL;
>> +                     }
>> +                     if (!is_pcie_sata_lane(group)) {
>> +                             dev_err(padctl->dev,
>> +                                     "USB3 port not applicable for pin %d\n",
>> +                                     group);
>> +                             return -EINVAL;
>> +                     }
>> +                     padctl->usb3_ports[value].lane = group;
>> +                     break;
>
> It feels odd to use pinctrl for a SW-only purpose. In other words, that
> chunk of code isn't writing the pinconf data to HW, but rather some
> internal variable.

Well the mapping of lanes to USB3 ports is a hardware property and we
do use it when programming the hardware later to choose which set of
lane registers to program given a USB3 port, but it's true that it's
not some value we program into HW directly.

> Perhaps it would make more sense for the DT binding to represent this
> data directly in a custom property that's parsed at probe() time. That
> way, pinctrl only touches "real" HW stuff.

I'm on the fence about this.  If you or others feel strongly about
this then I can make it a separate DT property and move it out of the
pinctrl properties.

>> +static int usb3_phy_power_on(struct phy *phy)
>> +{
>> +     struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
>> +     int port = usb3_phy_to_port(phy);
>> +     int lane = padctl->usb3_ports[port].lane;
>> +     u32 value, offset;
>> +
>> +     value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
>> +     value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
>
> Hmm. So there is a lot of "PHY" stuff here after all.
>
> However, the PHYs implemented here appear to implement very low-level
> I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
> somewhat higher-level; they're more USB-oriented than just IO pad
> oriented. Do you know which level of abstraction a Linux PHY object is
> supposed to be? I could never get an answer when I asked before.

The only other PHY driver I've worked with (Exynos USB2/3 PHYs) also
mainly only did low-level pad control stuff, but looking at a couple
of other USB PHYs (MSM, MV), there appear to be others that have
higher-level USB stuff in the PHY driver.  Perhaps Kishon or Felipe
could offer us some guidance?

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-25 23:30         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:30 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann, balbi

On Wed, Jun 25, 2014 at 3:12 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
>> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
>> PCIe or SATA lane and is mapped to one of the three UTMI ports.
>>
>
>> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
>
>> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>>                       padctl_writel(padctl, regval, lane->offset);
>>                       break;
>>
>> +             case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
>> +                     if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
>> +                             dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
>> +                                     value);
>> +                             return -EINVAL;
>> +                     }
>> +                     if (!is_pcie_sata_lane(group)) {
>> +                             dev_err(padctl->dev,
>> +                                     "USB3 port not applicable for pin %d\n",
>> +                                     group);
>> +                             return -EINVAL;
>> +                     }
>> +                     padctl->usb3_ports[value].lane = group;
>> +                     break;
>
> It feels odd to use pinctrl for a SW-only purpose. In other words, that
> chunk of code isn't writing the pinconf data to HW, but rather some
> internal variable.

Well the mapping of lanes to USB3 ports is a hardware property and we
do use it when programming the hardware later to choose which set of
lane registers to program given a USB3 port, but it's true that it's
not some value we program into HW directly.

> Perhaps it would make more sense for the DT binding to represent this
> data directly in a custom property that's parsed at probe() time. That
> way, pinctrl only touches "real" HW stuff.

I'm on the fence about this.  If you or others feel strongly about
this then I can make it a separate DT property and move it out of the
pinctrl properties.

>> +static int usb3_phy_power_on(struct phy *phy)
>> +{
>> +     struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
>> +     int port = usb3_phy_to_port(phy);
>> +     int lane = padctl->usb3_ports[port].lane;
>> +     u32 value, offset;
>> +
>> +     value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
>> +     value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
>
> Hmm. So there is a lot of "PHY" stuff here after all.
>
> However, the PHYs implemented here appear to implement very low-level
> I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
> somewhat higher-level; they're more USB-oriented than just IO pad
> oriented. Do you know which level of abstraction a Linux PHY object is
> supposed to be? I could never get an answer when I asked before.

The only other PHY driver I've worked with (Exynos USB2/3 PHYs) also
mainly only did low-level pad control stuff, but looking at a couple
of other USB PHYs (MSM, MV), there appear to be others that have
higher-level USB stuff in the PHY driver.  Perhaps Kishon or Felipe
could offer us some guidance?

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

* [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-25 23:30         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-25 23:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 25, 2014 at 3:12 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
>> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
>> PCIe or SATA lane and is mapped to one of the three UTMI ports.
>>
>
>> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
>
>> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>>                       padctl_writel(padctl, regval, lane->offset);
>>                       break;
>>
>> +             case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
>> +                     if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
>> +                             dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
>> +                                     value);
>> +                             return -EINVAL;
>> +                     }
>> +                     if (!is_pcie_sata_lane(group)) {
>> +                             dev_err(padctl->dev,
>> +                                     "USB3 port not applicable for pin %d\n",
>> +                                     group);
>> +                             return -EINVAL;
>> +                     }
>> +                     padctl->usb3_ports[value].lane = group;
>> +                     break;
>
> It feels odd to use pinctrl for a SW-only purpose. In other words, that
> chunk of code isn't writing the pinconf data to HW, but rather some
> internal variable.

Well the mapping of lanes to USB3 ports is a hardware property and we
do use it when programming the hardware later to choose which set of
lane registers to program given a USB3 port, but it's true that it's
not some value we program into HW directly.

> Perhaps it would make more sense for the DT binding to represent this
> data directly in a custom property that's parsed at probe() time. That
> way, pinctrl only touches "real" HW stuff.

I'm on the fence about this.  If you or others feel strongly about
this then I can make it a separate DT property and move it out of the
pinctrl properties.

>> +static int usb3_phy_power_on(struct phy *phy)
>> +{
>> +     struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
>> +     int port = usb3_phy_to_port(phy);
>> +     int lane = padctl->usb3_ports[port].lane;
>> +     u32 value, offset;
>> +
>> +     value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
>> +     value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
>
> Hmm. So there is a lot of "PHY" stuff here after all.
>
> However, the PHYs implemented here appear to implement very low-level
> I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
> somewhat higher-level; they're more USB-oriented than just IO pad
> oriented. Do you know which level of abstraction a Linux PHY object is
> supposed to be? I could never get an answer when I asked before.

The only other PHY driver I've worked with (Exynos USB2/3 PHYs) also
mainly only did low-level pad control stuff, but looking at a couple
of other USB PHYs (MSM, MV), there appear to be others that have
higher-level USB stuff in the PHY driver.  Perhaps Kishon or Felipe
could offer us some guidance?

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-06-25 22:37       ` Stephen Warren
  (?)
@ 2014-06-26  0:06         ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-26  0:06 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add support for the on-chip XHCI host controller present on Tegra 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>
>
>> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
>
>> +config USB_XHCI_TEGRA
>> +     tristate "NVIDIA Tegra XHCI support"
>> +     depends on ARCH_TEGRA
>> +     select PINCTRL_TEGRA_XUSB
>> +     select TEGRA_XUSB_MBOX
>> +     select FW_LOADER
>
> I think at least some of those should be depends. In particular, the
> mbox driver patch said:
>
> +config TEGRA_XUSB_MBOX
> +       bool "NVIDIA Tegra XUSB mailbox support"
>
> which means the option is user-selectable. Either MBOX should be
> invisible and selected here, or it should be visible with USB_XHCI_TEGRA
> depending on it.

Annoyingly, TEGRA_XUSB_MBOX isn't selectable unless MAILBOX is
selected, so I think I will make USB_XHCI_TEGRA depend on
TEGRA_XUSB_MBOX.

>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
>
>> +#define TEGRA_XHCI_UTMI_PHYS 3
>> +#define TEGRA_XHCI_HSIC_PHYS 2
>> +#define TEGRA_XHCI_USB3_PHYS 2
>> +#define TEGRA_XHCI_MAX_PHYS (TEGRA_XHCI_UTMI_PHYS + TEGRA_XHCI_HSIC_PHYS + \
>> +                          TEGRA_XHCI_USB3_PHYS)
>
> Do those numbers need to be synchronized with the XUSB padctrl driver at
> all?

Oops, yeah, these probably belong in a header somewhere.

>> +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);
>> +}
>
> I assume some higher level has the required locking or single-threading
> so that the keyhole register accesses don't get interleaved?

Yes, we only touch these in the firmware loading path which is single-threaded.

>> +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->hcd->rsrc_start;
>
> Don't you need to mask out the original value here? I guess whatever is
> being written is probably always the same, but it seems scary to assume
> that a bootloader, or previous version of a module during development,
> didn't write something unexpected there. Perhaps if the HW module's
> reset is pulsed we don't need to worry though.

Hmm, so I left this part mostly identical to what the downstream
kernels do, but the more I look at it the more it looks wrong.  The
TRM says that BASE_ADDRESS is XUSB_CFG_4[31:15] and the rest are flags
(which we avoid over-writing because the base address is 64K aligned),
but we just slam the physical address of the host in there.  I'll get
some clarification on what exactly needs to be programmed into this
register.

>> +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;
>
> Are there endianness or CPU word size (e.g. ARMv8) issues here; this is
> casting the content of a data file to a CPU data structure.

I don't think there are word-size issues, but I suppose there could be
endianness issues.

>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>> +                              unsigned long rate)
>
>> +     switch (rate) {
>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>> +             div = new_parent_rate / rate;
>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>> +             if (ret)
>> +                     return ret;
>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>> +             if (ret)
>> +                     return ret;
>
> Don't you need to call clk_set_rate() again after reparenting, since the
> divisor will be different, and the rounding too.

Nope, the divider we set before remains in-tact after clk_set_parent().

>> +static int tegra_xhci_regulator_enable(struct tegra_xhci_hcd *tegra)
>> +{
>> +     int ret;
>> +
>> +     ret = regulator_enable(tegra->s3p3v_reg);
>> +     if (ret < 0)
>> +             return ret;
>> +     ret = regulator_enable(tegra->s1p8v_reg);
>> +     if (ret < 0)
>> +             goto disable_s3p3v;
>> +     ret = regulator_enable(tegra->s1p05v_reg);
>> +     if (ret < 0)
>> +             goto disable_s1p8v;
>
> Would regulator_bulk_enable() save any code here? Similar in _disable().

Yes, will do.

>> +static const struct tegra_xhci_soc_config tegra124_soc_config = {
>> +     .firmware_file = "tegra12x/tegra_xusb_firmware",
>> +};
>
> I would prefer an "nvidia/" prefix so everything gets namespaced by vendor.
>
> "tegra12x" isn't the name of the chip, but rather "Tegra124".
>
> "tegra_" and "_firmware" seem redundant, since they're implied by parent
> directories.
>
> So, how about "nvidia/tegra124/xusb"? (perhaps with .img or .bin file
> extension)

Sounds good to me.

>> +static int tegra_xhci_probe(struct platform_device *pdev)
>
>> +     tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
>> +     if (IS_ERR(tegra->host_clk)) {
>> +             ret = PTR_ERR(tegra->host_clk);
>> +             goto put_hcd;
>> +     }
>> +     tegra->falc_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src");
>> +     if (IS_ERR(tegra->falc_clk)) {
>> +             ret = PTR_ERR(tegra->falc_clk);
>> +             goto put_hcd;
>> +     }
> ...
>
> Seems like devm_clk_get_bulk() would be useful:-)

Indeed...

>> +     for (i = 0; i < TEGRA_XHCI_UTMI_PHYS; i++) {
>> +             char prop[sizeof("utmi-N")];
>> +
>> +             sprintf(prop, "utmi-%d", i);
>
> Since this loop is cut/paste 3 times just with the string
> "utmi"/"hsic"/"usb3" being different, does it make sense to add an outer
> loop over an array of strings instead of duplicating the loo?

Ok, will do.

>> +     ret = request_firmware_nowait(THIS_MODULE, true,
>> +                                   tegra->soc_config->firmware_file,
>> +                                   tegra->dev, GFP_KERNEL, tegra,
>> +                                   tegra_xhci_probe_finish);
>
> I'm not familiar with that API. I assume the point is this works in allh
> the following situations:
>
> * Driver is built-in, probes before rootfs is available, firmware
> eventually gets loaded a few seconds after rootfs is available.
>
> * Driver is a module and gets loaded from an initrd, firmware is loaded
> from initrd essentially immediately.
>
> * Driver is a module and gets loaded from an initrd, firmware eventually
> gets loaded a few seconds after rootfs is available.
>
> * Driver is a module and gets loaded from rootfs, firmware is loaded
> from rootfs essentially immediately.

Yes, this will handle all those cases.  If the rootfs is not available
at the time request_firmware{_nowait} is called, however, you'll need
to use the userspace firmware loader interface (or have a tool that
does it automatically) once it does become available.  See
Documentation/firmware_class/README for details.

For testing (and in the ChromiumOS tree), we build the firmware into
the kernel image with CONFIG_EXTRA_FIRMWARE.

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-26  0:06         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-26  0:06 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add support for the on-chip XHCI host controller present on Tegra 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>
>
>> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
>
>> +config USB_XHCI_TEGRA
>> +     tristate "NVIDIA Tegra XHCI support"
>> +     depends on ARCH_TEGRA
>> +     select PINCTRL_TEGRA_XUSB
>> +     select TEGRA_XUSB_MBOX
>> +     select FW_LOADER
>
> I think at least some of those should be depends. In particular, the
> mbox driver patch said:
>
> +config TEGRA_XUSB_MBOX
> +       bool "NVIDIA Tegra XUSB mailbox support"
>
> which means the option is user-selectable. Either MBOX should be
> invisible and selected here, or it should be visible with USB_XHCI_TEGRA
> depending on it.

Annoyingly, TEGRA_XUSB_MBOX isn't selectable unless MAILBOX is
selected, so I think I will make USB_XHCI_TEGRA depend on
TEGRA_XUSB_MBOX.

>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
>
>> +#define TEGRA_XHCI_UTMI_PHYS 3
>> +#define TEGRA_XHCI_HSIC_PHYS 2
>> +#define TEGRA_XHCI_USB3_PHYS 2
>> +#define TEGRA_XHCI_MAX_PHYS (TEGRA_XHCI_UTMI_PHYS + TEGRA_XHCI_HSIC_PHYS + \
>> +                          TEGRA_XHCI_USB3_PHYS)
>
> Do those numbers need to be synchronized with the XUSB padctrl driver at
> all?

Oops, yeah, these probably belong in a header somewhere.

>> +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);
>> +}
>
> I assume some higher level has the required locking or single-threading
> so that the keyhole register accesses don't get interleaved?

Yes, we only touch these in the firmware loading path which is single-threaded.

>> +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->hcd->rsrc_start;
>
> Don't you need to mask out the original value here? I guess whatever is
> being written is probably always the same, but it seems scary to assume
> that a bootloader, or previous version of a module during development,
> didn't write something unexpected there. Perhaps if the HW module's
> reset is pulsed we don't need to worry though.

Hmm, so I left this part mostly identical to what the downstream
kernels do, but the more I look at it the more it looks wrong.  The
TRM says that BASE_ADDRESS is XUSB_CFG_4[31:15] and the rest are flags
(which we avoid over-writing because the base address is 64K aligned),
but we just slam the physical address of the host in there.  I'll get
some clarification on what exactly needs to be programmed into this
register.

>> +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;
>
> Are there endianness or CPU word size (e.g. ARMv8) issues here; this is
> casting the content of a data file to a CPU data structure.

I don't think there are word-size issues, but I suppose there could be
endianness issues.

>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>> +                              unsigned long rate)
>
>> +     switch (rate) {
>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>> +             div = new_parent_rate / rate;
>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>> +             if (ret)
>> +                     return ret;
>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>> +             if (ret)
>> +                     return ret;
>
> Don't you need to call clk_set_rate() again after reparenting, since the
> divisor will be different, and the rounding too.

Nope, the divider we set before remains in-tact after clk_set_parent().

>> +static int tegra_xhci_regulator_enable(struct tegra_xhci_hcd *tegra)
>> +{
>> +     int ret;
>> +
>> +     ret = regulator_enable(tegra->s3p3v_reg);
>> +     if (ret < 0)
>> +             return ret;
>> +     ret = regulator_enable(tegra->s1p8v_reg);
>> +     if (ret < 0)
>> +             goto disable_s3p3v;
>> +     ret = regulator_enable(tegra->s1p05v_reg);
>> +     if (ret < 0)
>> +             goto disable_s1p8v;
>
> Would regulator_bulk_enable() save any code here? Similar in _disable().

Yes, will do.

>> +static const struct tegra_xhci_soc_config tegra124_soc_config = {
>> +     .firmware_file = "tegra12x/tegra_xusb_firmware",
>> +};
>
> I would prefer an "nvidia/" prefix so everything gets namespaced by vendor.
>
> "tegra12x" isn't the name of the chip, but rather "Tegra124".
>
> "tegra_" and "_firmware" seem redundant, since they're implied by parent
> directories.
>
> So, how about "nvidia/tegra124/xusb"? (perhaps with .img or .bin file
> extension)

Sounds good to me.

>> +static int tegra_xhci_probe(struct platform_device *pdev)
>
>> +     tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
>> +     if (IS_ERR(tegra->host_clk)) {
>> +             ret = PTR_ERR(tegra->host_clk);
>> +             goto put_hcd;
>> +     }
>> +     tegra->falc_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src");
>> +     if (IS_ERR(tegra->falc_clk)) {
>> +             ret = PTR_ERR(tegra->falc_clk);
>> +             goto put_hcd;
>> +     }
> ...
>
> Seems like devm_clk_get_bulk() would be useful:-)

Indeed...

>> +     for (i = 0; i < TEGRA_XHCI_UTMI_PHYS; i++) {
>> +             char prop[sizeof("utmi-N")];
>> +
>> +             sprintf(prop, "utmi-%d", i);
>
> Since this loop is cut/paste 3 times just with the string
> "utmi"/"hsic"/"usb3" being different, does it make sense to add an outer
> loop over an array of strings instead of duplicating the loo?

Ok, will do.

>> +     ret = request_firmware_nowait(THIS_MODULE, true,
>> +                                   tegra->soc_config->firmware_file,
>> +                                   tegra->dev, GFP_KERNEL, tegra,
>> +                                   tegra_xhci_probe_finish);
>
> I'm not familiar with that API. I assume the point is this works in allh
> the following situations:
>
> * Driver is built-in, probes before rootfs is available, firmware
> eventually gets loaded a few seconds after rootfs is available.
>
> * Driver is a module and gets loaded from an initrd, firmware is loaded
> from initrd essentially immediately.
>
> * Driver is a module and gets loaded from an initrd, firmware eventually
> gets loaded a few seconds after rootfs is available.
>
> * Driver is a module and gets loaded from rootfs, firmware is loaded
> from rootfs essentially immediately.

Yes, this will handle all those cases.  If the rootfs is not available
at the time request_firmware{_nowait} is called, however, you'll need
to use the userspace firmware loader interface (or have a tool that
does it automatically) once it does become available.  See
Documentation/firmware_class/README for details.

For testing (and in the ChromiumOS tree), we build the firmware into
the kernel image with CONFIG_EXTRA_FIRMWARE.

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-26  0:06         ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-26  0:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>> Add support for the on-chip XHCI host controller present on Tegra 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>
>
>> diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
>
>> +config USB_XHCI_TEGRA
>> +     tristate "NVIDIA Tegra XHCI support"
>> +     depends on ARCH_TEGRA
>> +     select PINCTRL_TEGRA_XUSB
>> +     select TEGRA_XUSB_MBOX
>> +     select FW_LOADER
>
> I think at least some of those should be depends. In particular, the
> mbox driver patch said:
>
> +config TEGRA_XUSB_MBOX
> +       bool "NVIDIA Tegra XUSB mailbox support"
>
> which means the option is user-selectable. Either MBOX should be
> invisible and selected here, or it should be visible with USB_XHCI_TEGRA
> depending on it.

Annoyingly, TEGRA_XUSB_MBOX isn't selectable unless MAILBOX is
selected, so I think I will make USB_XHCI_TEGRA depend on
TEGRA_XUSB_MBOX.

>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
>
>> +#define TEGRA_XHCI_UTMI_PHYS 3
>> +#define TEGRA_XHCI_HSIC_PHYS 2
>> +#define TEGRA_XHCI_USB3_PHYS 2
>> +#define TEGRA_XHCI_MAX_PHYS (TEGRA_XHCI_UTMI_PHYS + TEGRA_XHCI_HSIC_PHYS + \
>> +                          TEGRA_XHCI_USB3_PHYS)
>
> Do those numbers need to be synchronized with the XUSB padctrl driver at
> all?

Oops, yeah, these probably belong in a header somewhere.

>> +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);
>> +}
>
> I assume some higher level has the required locking or single-threading
> so that the keyhole register accesses don't get interleaved?

Yes, we only touch these in the firmware loading path which is single-threaded.

>> +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->hcd->rsrc_start;
>
> Don't you need to mask out the original value here? I guess whatever is
> being written is probably always the same, but it seems scary to assume
> that a bootloader, or previous version of a module during development,
> didn't write something unexpected there. Perhaps if the HW module's
> reset is pulsed we don't need to worry though.

Hmm, so I left this part mostly identical to what the downstream
kernels do, but the more I look at it the more it looks wrong.  The
TRM says that BASE_ADDRESS is XUSB_CFG_4[31:15] and the rest are flags
(which we avoid over-writing because the base address is 64K aligned),
but we just slam the physical address of the host in there.  I'll get
some clarification on what exactly needs to be programmed into this
register.

>> +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;
>
> Are there endianness or CPU word size (e.g. ARMv8) issues here; this is
> casting the content of a data file to a CPU data structure.

I don't think there are word-size issues, but I suppose there could be
endianness issues.

>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>> +                              unsigned long rate)
>
>> +     switch (rate) {
>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>> +             div = new_parent_rate / rate;
>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>> +             if (ret)
>> +                     return ret;
>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>> +             if (ret)
>> +                     return ret;
>
> Don't you need to call clk_set_rate() again after reparenting, since the
> divisor will be different, and the rounding too.

Nope, the divider we set before remains in-tact after clk_set_parent().

>> +static int tegra_xhci_regulator_enable(struct tegra_xhci_hcd *tegra)
>> +{
>> +     int ret;
>> +
>> +     ret = regulator_enable(tegra->s3p3v_reg);
>> +     if (ret < 0)
>> +             return ret;
>> +     ret = regulator_enable(tegra->s1p8v_reg);
>> +     if (ret < 0)
>> +             goto disable_s3p3v;
>> +     ret = regulator_enable(tegra->s1p05v_reg);
>> +     if (ret < 0)
>> +             goto disable_s1p8v;
>
> Would regulator_bulk_enable() save any code here? Similar in _disable().

Yes, will do.

>> +static const struct tegra_xhci_soc_config tegra124_soc_config = {
>> +     .firmware_file = "tegra12x/tegra_xusb_firmware",
>> +};
>
> I would prefer an "nvidia/" prefix so everything gets namespaced by vendor.
>
> "tegra12x" isn't the name of the chip, but rather "Tegra124".
>
> "tegra_" and "_firmware" seem redundant, since they're implied by parent
> directories.
>
> So, how about "nvidia/tegra124/xusb"? (perhaps with .img or .bin file
> extension)

Sounds good to me.

>> +static int tegra_xhci_probe(struct platform_device *pdev)
>
>> +     tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
>> +     if (IS_ERR(tegra->host_clk)) {
>> +             ret = PTR_ERR(tegra->host_clk);
>> +             goto put_hcd;
>> +     }
>> +     tegra->falc_clk = devm_clk_get(&pdev->dev, "xusb_falcon_src");
>> +     if (IS_ERR(tegra->falc_clk)) {
>> +             ret = PTR_ERR(tegra->falc_clk);
>> +             goto put_hcd;
>> +     }
> ...
>
> Seems like devm_clk_get_bulk() would be useful:-)

Indeed...

>> +     for (i = 0; i < TEGRA_XHCI_UTMI_PHYS; i++) {
>> +             char prop[sizeof("utmi-N")];
>> +
>> +             sprintf(prop, "utmi-%d", i);
>
> Since this loop is cut/paste 3 times just with the string
> "utmi"/"hsic"/"usb3" being different, does it make sense to add an outer
> loop over an array of strings instead of duplicating the loo?

Ok, will do.

>> +     ret = request_firmware_nowait(THIS_MODULE, true,
>> +                                   tegra->soc_config->firmware_file,
>> +                                   tegra->dev, GFP_KERNEL, tegra,
>> +                                   tegra_xhci_probe_finish);
>
> I'm not familiar with that API. I assume the point is this works in allh
> the following situations:
>
> * Driver is built-in, probes before rootfs is available, firmware
> eventually gets loaded a few seconds after rootfs is available.
>
> * Driver is a module and gets loaded from an initrd, firmware is loaded
> from initrd essentially immediately.
>
> * Driver is a module and gets loaded from an initrd, firmware eventually
> gets loaded a few seconds after rootfs is available.
>
> * Driver is a module and gets loaded from rootfs, firmware is loaded
> from rootfs essentially immediately.

Yes, this will handle all those cases.  If the rootfs is not available
at the time request_firmware{_nowait} is called, however, you'll need
to use the userspace firmware loader interface (or have a tool that
does it automatically) once it does become available.  See
Documentation/firmware_class/README for details.

For testing (and in the ChromiumOS tree), we build the firmware into
the kernel image with CONFIG_EXTRA_FIRMWARE.

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-06-26  0:06         ` Andrew Bresticker
  (?)
@ 2014-06-26 18:07             ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-26 18:07 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 06:06 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add support for the on-chip XHCI host controller present on Tegra 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.

>>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c

>>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>>> +                              unsigned long rate)
>>
>>> +     switch (rate) {
>>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>>> +             div = new_parent_rate / rate;
>>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>>> +             if (ret)
>>> +                     return ret;
>>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>>> +             if (ret)
>>> +                     return ret;
>>
>> Don't you need to call clk_set_rate() again after reparenting, since the
>> divisor will be different, and the rounding too.
> 
> Nope, the divider we set before remains in-tact after clk_set_parent().

Oh I see, the clk_set_rate() call is setting up div so it's appropriate
after the new parent is selected.

Wouldn't it be better to just stop the clock, assert reset, reparent the
clock, and then set the desired rate directly?

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-26 18:07             ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-26 18:07 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 06:06 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add support for the on-chip XHCI host controller present on Tegra 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.

>>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c

>>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>>> +                              unsigned long rate)
>>
>>> +     switch (rate) {
>>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>>> +             div = new_parent_rate / rate;
>>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>>> +             if (ret)
>>> +                     return ret;
>>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>>> +             if (ret)
>>> +                     return ret;
>>
>> Don't you need to call clk_set_rate() again after reparenting, since the
>> divisor will be different, and the rounding too.
> 
> Nope, the divider we set before remains in-tact after clk_set_parent().

Oh I see, the clk_set_rate() call is setting up div so it's appropriate
after the new parent is selected.

Wouldn't it be better to just stop the clock, assert reset, reparent the
clock, and then set the desired rate directly?

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-26 18:07             ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-26 18:07 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/25/2014 06:06 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add support for the on-chip XHCI host controller present on Tegra 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.

>>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c

>>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>>> +                              unsigned long rate)
>>
>>> +     switch (rate) {
>>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>>> +             div = new_parent_rate / rate;
>>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>>> +             if (ret)
>>> +                     return ret;
>>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>>> +             if (ret)
>>> +                     return ret;
>>
>> Don't you need to call clk_set_rate() again after reparenting, since the
>> divisor will be different, and the rounding too.
> 
> Nope, the divider we set before remains in-tact after clk_set_parent().

Oh I see, the clk_set_rate() call is setting up div so it's appropriate
after the new parent is selected.

Wouldn't it be better to just stop the clock, assert reset, reparent the
clock, and then set the desired rate directly?

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
  2014-06-25 23:30         ` Andrew Bresticker
  (?)
@ 2014-06-26 18:08           ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-26 18:08 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann, bal

On 06/25/2014 05:30 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 3:12 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
>>> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
>>> PCIe or SATA lane and is mapped to one of the three UTMI ports.
>>>
>>
>>> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
>>
>>> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>>>                       padctl_writel(padctl, regval, lane->offset);
>>>                       break;
>>>
>>> +             case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
>>> +                     if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
>>> +                             dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
>>> +                                     value);
>>> +                             return -EINVAL;
>>> +                     }
>>> +                     if (!is_pcie_sata_lane(group)) {
>>> +                             dev_err(padctl->dev,
>>> +                                     "USB3 port not applicable for pin %d\n",
>>> +                                     group);
>>> +                             return -EINVAL;
>>> +                     }
>>> +                     padctl->usb3_ports[value].lane = group;
>>> +                     break;
>>
>> It feels odd to use pinctrl for a SW-only purpose. In other words, that
>> chunk of code isn't writing the pinconf data to HW, but rather some
>> internal variable.
> 
> Well the mapping of lanes to USB3 ports is a hardware property and we
> do use it when programming the hardware later to choose which set of
> lane registers to program given a USB3 port, but it's true that it's
> not some value we program into HW directly.
> 
>> Perhaps it would make more sense for the DT binding to represent this
>> data directly in a custom property that's parsed at probe() time. That
>> way, pinctrl only touches "real" HW stuff.
> 
> I'm on the fence about this.  If you or others feel strongly about
> this then I can make it a separate DT property and move it out of the
> pinctrl properties.

I'd certainly prefer to use pinctrl bindings only for things that get
directly written into HW. Other configuration data should be easy to
retrieve directly from properties.

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-26 18:08           ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-26 18:08 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann, balbi

On 06/25/2014 05:30 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 3:12 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
>>> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
>>> PCIe or SATA lane and is mapped to one of the three UTMI ports.
>>>
>>
>>> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
>>
>>> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>>>                       padctl_writel(padctl, regval, lane->offset);
>>>                       break;
>>>
>>> +             case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
>>> +                     if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
>>> +                             dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
>>> +                                     value);
>>> +                             return -EINVAL;
>>> +                     }
>>> +                     if (!is_pcie_sata_lane(group)) {
>>> +                             dev_err(padctl->dev,
>>> +                                     "USB3 port not applicable for pin %d\n",
>>> +                                     group);
>>> +                             return -EINVAL;
>>> +                     }
>>> +                     padctl->usb3_ports[value].lane = group;
>>> +                     break;
>>
>> It feels odd to use pinctrl for a SW-only purpose. In other words, that
>> chunk of code isn't writing the pinconf data to HW, but rather some
>> internal variable.
> 
> Well the mapping of lanes to USB3 ports is a hardware property and we
> do use it when programming the hardware later to choose which set of
> lane registers to program given a USB3 port, but it's true that it's
> not some value we program into HW directly.
> 
>> Perhaps it would make more sense for the DT binding to represent this
>> data directly in a custom property that's parsed at probe() time. That
>> way, pinctrl only touches "real" HW stuff.
> 
> I'm on the fence about this.  If you or others feel strongly about
> this then I can make it a separate DT property and move it out of the
> pinctrl properties.

I'd certainly prefer to use pinctrl bindings only for things that get
directly written into HW. Other configuration data should be easy to
retrieve directly from properties.

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

* [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-26 18:08           ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-26 18:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/25/2014 05:30 PM, Andrew Bresticker wrote:
> On Wed, Jun 25, 2014 at 3:12 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
>>> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
>>> PCIe or SATA lane and is mapped to one of the three UTMI ports.
>>>
>>
>>> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
>>
>>> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>>>                       padctl_writel(padctl, regval, lane->offset);
>>>                       break;
>>>
>>> +             case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
>>> +                     if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
>>> +                             dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
>>> +                                     value);
>>> +                             return -EINVAL;
>>> +                     }
>>> +                     if (!is_pcie_sata_lane(group)) {
>>> +                             dev_err(padctl->dev,
>>> +                                     "USB3 port not applicable for pin %d\n",
>>> +                                     group);
>>> +                             return -EINVAL;
>>> +                     }
>>> +                     padctl->usb3_ports[value].lane = group;
>>> +                     break;
>>
>> It feels odd to use pinctrl for a SW-only purpose. In other words, that
>> chunk of code isn't writing the pinconf data to HW, but rather some
>> internal variable.
> 
> Well the mapping of lanes to USB3 ports is a hardware property and we
> do use it when programming the hardware later to choose which set of
> lane registers to program given a USB3 port, but it's true that it's
> not some value we program into HW directly.
> 
>> Perhaps it would make more sense for the DT binding to represent this
>> data directly in a custom property that's parsed at probe() time. That
>> way, pinctrl only touches "real" HW stuff.
> 
> I'm on the fence about this.  If you or others feel strongly about
> this then I can make it a separate DT property and move it out of the
> pinctrl properties.

I'd certainly prefer to use pinctrl bindings only for things that get
directly written into HW. Other configuration data should be easy to
retrieve directly from properties.

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

* Re: [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
  2014-06-25 22:25         ` Andrew Bresticker
  (?)
@ 2014-06-26 20:00           ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-26 20:00 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 04:25 PM, Andrew Bresticker wrote:
> Thanks for the review Stephen!
> 
> On Wed, Jun 25, 2014 at 2:46 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add new bindings used for USB support by the Tegra XUSB pad controller.
>>> This includes additional PHY types, USB-specific pinconfig properties, etc.
>>
>>> diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
>>
>>> @@ -21,6 +21,12 @@ Required properties:
>>>    - padctl
>>>  - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
>>>    See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
>>> +- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
>>
>> Why does the padctrl code need access to the XUSB mailbox?
> 
> The XUSB firmware sends messages which make requests of the PHY (XUSB
> pad controller), such as idling/un-idling the HSIC PHYs or saving USB3
> PHY context.
> 
>> Isn't the padctrl HW module something that provides services to the XUSB
>> code. I would have expected the XUSB node to reference the padctrl node.
> 
> The XUSB padctrl HW does provide services to the XUSB host in the form
> of PHYs and it is through the PHY bindings that the host references
> the padctrl node.
> 
>> If notifications need to be sent back from XUSB padctrl to XUSB, then that
>> seems like an internal SW detail that doesn't need to be represented in DT.
> 
> I think you mean notifications need to be sent back from the XUSB host
> to the XUSB padctrl?  This is what the mailbox is for and I chose to
> have the padctrl refer to the mailbox since messages are sent from the
> mailbox which make requests to the PHY specifically and not the host
> (see above).

I've looked at the details of the mailbox messages a bit more now. It
seems that the firmware running on the XUSB controller sends a variety
of different messages, some of which are relevant to the XHCI controller
driver and some relevant to the PHY/PAD driver. It's a pity these
different message streams are intermixed, but I guess that's not changing.

As such, I think at this stage it does make sense for the mailbox to be
represented as a separate node, with each of the XHCI controller and USB
PADCTL nodes referring to the mailbox node by phandle.

I'm still not 100% sure about whether the PHY driver is the same level
of abstraction intended by the Linux kernel's PHY layer. Pending that
discussion's results, the "PHY" message from the firmware may not go to
a Linux kernel PHY but some layer above which might get subsumed into
the overall XHCI controller driver, which would change my argument above
a bit.

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

* Re: [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
@ 2014-06-26 20:00           ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-26 20:00 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/25/2014 04:25 PM, Andrew Bresticker wrote:
> Thanks for the review Stephen!
> 
> On Wed, Jun 25, 2014 at 2:46 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add new bindings used for USB support by the Tegra XUSB pad controller.
>>> This includes additional PHY types, USB-specific pinconfig properties, etc.
>>
>>> diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
>>
>>> @@ -21,6 +21,12 @@ Required properties:
>>>    - padctl
>>>  - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
>>>    See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
>>> +- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
>>
>> Why does the padctrl code need access to the XUSB mailbox?
> 
> The XUSB firmware sends messages which make requests of the PHY (XUSB
> pad controller), such as idling/un-idling the HSIC PHYs or saving USB3
> PHY context.
> 
>> Isn't the padctrl HW module something that provides services to the XUSB
>> code. I would have expected the XUSB node to reference the padctrl node.
> 
> The XUSB padctrl HW does provide services to the XUSB host in the form
> of PHYs and it is through the PHY bindings that the host references
> the padctrl node.
> 
>> If notifications need to be sent back from XUSB padctrl to XUSB, then that
>> seems like an internal SW detail that doesn't need to be represented in DT.
> 
> I think you mean notifications need to be sent back from the XUSB host
> to the XUSB padctrl?  This is what the mailbox is for and I chose to
> have the padctrl refer to the mailbox since messages are sent from the
> mailbox which make requests to the PHY specifically and not the host
> (see above).

I've looked at the details of the mailbox messages a bit more now. It
seems that the firmware running on the XUSB controller sends a variety
of different messages, some of which are relevant to the XHCI controller
driver and some relevant to the PHY/PAD driver. It's a pity these
different message streams are intermixed, but I guess that's not changing.

As such, I think at this stage it does make sense for the mailbox to be
represented as a separate node, with each of the XHCI controller and USB
PADCTL nodes referring to the mailbox node by phandle.

I'm still not 100% sure about whether the PHY driver is the same level
of abstraction intended by the Linux kernel's PHY layer. Pending that
discussion's results, the "PHY" message from the firmware may not go to
a Linux kernel PHY but some layer above which might get subsumed into
the overall XHCI controller driver, which would change my argument above
a bit.

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

* [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB
@ 2014-06-26 20:00           ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-26 20:00 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/25/2014 04:25 PM, Andrew Bresticker wrote:
> Thanks for the review Stephen!
> 
> On Wed, Jun 25, 2014 at 2:46 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>> Add new bindings used for USB support by the Tegra XUSB pad controller.
>>> This includes additional PHY types, USB-specific pinconfig properties, etc.
>>
>>> diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-xusb-padctl.txt
>>
>>> @@ -21,6 +21,12 @@ Required properties:
>>>    - padctl
>>>  - #phy-cells: Should be 1. The specifier is the index of the PHY to reference.
>>>    See <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> for the list of valid values.
>>> +- nvidia,xusb-mbox: Handle to the Tegra XUSB mailbox node.
>>
>> Why does the padctrl code need access to the XUSB mailbox?
> 
> The XUSB firmware sends messages which make requests of the PHY (XUSB
> pad controller), such as idling/un-idling the HSIC PHYs or saving USB3
> PHY context.
> 
>> Isn't the padctrl HW module something that provides services to the XUSB
>> code. I would have expected the XUSB node to reference the padctrl node.
> 
> The XUSB padctrl HW does provide services to the XUSB host in the form
> of PHYs and it is through the PHY bindings that the host references
> the padctrl node.
> 
>> If notifications need to be sent back from XUSB padctrl to XUSB, then that
>> seems like an internal SW detail that doesn't need to be represented in DT.
> 
> I think you mean notifications need to be sent back from the XUSB host
> to the XUSB padctrl?  This is what the mailbox is for and I chose to
> have the padctrl refer to the mailbox since messages are sent from the
> mailbox which make requests to the PHY specifically and not the host
> (see above).

I've looked at the details of the mailbox messages a bit more now. It
seems that the firmware running on the XUSB controller sends a variety
of different messages, some of which are relevant to the XHCI controller
driver and some relevant to the PHY/PAD driver. It's a pity these
different message streams are intermixed, but I guess that's not changing.

As such, I think at this stage it does make sense for the mailbox to be
represented as a separate node, with each of the XHCI controller and USB
PADCTL nodes referring to the mailbox node by phandle.

I'm still not 100% sure about whether the PHY driver is the same level
of abstraction intended by the Linux kernel's PHY layer. Pending that
discussion's results, the "PHY" message from the firmware may not go to
a Linux kernel PHY but some layer above which might get subsumed into
the overall XHCI controller driver, which would change my argument above
a bit.

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
  2014-06-25 23:30         ` Andrew Bresticker
  (?)
@ 2014-06-27 15:00           ` Felipe Balbi
  -1 siblings, 0 replies; 111+ messages in thread
From: Felipe Balbi @ 2014-06-27 15:00 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Stephen Warren, devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I

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

On Wed, Jun 25, 2014 at 04:30:48PM -0700, Andrew Bresticker wrote:
> >> +static int usb3_phy_power_on(struct phy *phy)
> >> +{
> >> +     struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
> >> +     int port = usb3_phy_to_port(phy);
> >> +     int lane = padctl->usb3_ports[port].lane;
> >> +     u32 value, offset;
> >> +
> >> +     value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
> >> +     value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
> >> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
> >> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
> >> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
> >> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
> >> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
> >
> > Hmm. So there is a lot of "PHY" stuff here after all.
> >
> > However, the PHYs implemented here appear to implement very low-level
> > I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
> > somewhat higher-level; they're more USB-oriented than just IO pad
> > oriented. Do you know which level of abstraction a Linux PHY object is
> > supposed to be? I could never get an answer when I asked before.
> 
> The only other PHY driver I've worked with (Exynos USB2/3 PHYs) also
> mainly only did low-level pad control stuff, but looking at a couple
> of other USB PHYs (MSM, MV), there appear to be others that have
> higher-level USB stuff in the PHY driver.  Perhaps Kishon or Felipe
> could offer us some guidance?

well, if you're adding a new driver, I'd rather see folks moving over to
the generic phy framework (drivers/phy) because we're trying really hard
to get rid of drivers/usb/phy/. And I think, in your case, it's actually
ok to use pinctrl because you actually are muxing pads to the USB3 PHY,
you just do it lazyly.

my 2 cents

-- 
balbi

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

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-27 15:00           ` Felipe Balbi
  0 siblings, 0 replies; 111+ messages in thread
From: Felipe Balbi @ 2014-06-27 15:00 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Stephen Warren, devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann, balbi

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

On Wed, Jun 25, 2014 at 04:30:48PM -0700, Andrew Bresticker wrote:
> >> +static int usb3_phy_power_on(struct phy *phy)
> >> +{
> >> +     struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
> >> +     int port = usb3_phy_to_port(phy);
> >> +     int lane = padctl->usb3_ports[port].lane;
> >> +     u32 value, offset;
> >> +
> >> +     value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
> >> +     value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
> >> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
> >> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
> >> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
> >> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
> >> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
> >
> > Hmm. So there is a lot of "PHY" stuff here after all.
> >
> > However, the PHYs implemented here appear to implement very low-level
> > I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
> > somewhat higher-level; they're more USB-oriented than just IO pad
> > oriented. Do you know which level of abstraction a Linux PHY object is
> > supposed to be? I could never get an answer when I asked before.
> 
> The only other PHY driver I've worked with (Exynos USB2/3 PHYs) also
> mainly only did low-level pad control stuff, but looking at a couple
> of other USB PHYs (MSM, MV), there appear to be others that have
> higher-level USB stuff in the PHY driver.  Perhaps Kishon or Felipe
> could offer us some guidance?

well, if you're adding a new driver, I'd rather see folks moving over to
the generic phy framework (drivers/phy) because we're trying really hard
to get rid of drivers/usb/phy/. And I think, in your case, it's actually
ok to use pinctrl because you actually are muxing pads to the USB3 PHY,
you just do it lazyly.

my 2 cents

-- 
balbi

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

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

* [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-27 15:00           ` Felipe Balbi
  0 siblings, 0 replies; 111+ messages in thread
From: Felipe Balbi @ 2014-06-27 15:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jun 25, 2014 at 04:30:48PM -0700, Andrew Bresticker wrote:
> >> +static int usb3_phy_power_on(struct phy *phy)
> >> +{
> >> +     struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
> >> +     int port = usb3_phy_to_port(phy);
> >> +     int lane = padctl->usb3_ports[port].lane;
> >> +     u32 value, offset;
> >> +
> >> +     value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
> >> +     value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
> >> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
> >> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
> >> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
> >> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
> >> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
> >
> > Hmm. So there is a lot of "PHY" stuff here after all.
> >
> > However, the PHYs implemented here appear to implement very low-level
> > I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
> > somewhat higher-level; they're more USB-oriented than just IO pad
> > oriented. Do you know which level of abstraction a Linux PHY object is
> > supposed to be? I could never get an answer when I asked before.
> 
> The only other PHY driver I've worked with (Exynos USB2/3 PHYs) also
> mainly only did low-level pad control stuff, but looking at a couple
> of other USB PHYs (MSM, MV), there appear to be others that have
> higher-level USB stuff in the PHY driver.  Perhaps Kishon or Felipe
> could offer us some guidance?

well, if you're adding a new driver, I'd rather see folks moving over to
the generic phy framework (drivers/phy) because we're trying really hard
to get rid of drivers/usb/phy/. And I think, in your case, it's actually
ok to use pinctrl because you actually are muxing pads to the USB3 PHY,
you just do it lazyly.

my 2 cents

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140627/87a7c7d7/attachment.sig>

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
  2014-06-27 15:00           ` Felipe Balbi
  (?)
@ 2014-06-27 16:05             ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-27 16:05 UTC (permalink / raw)
  To: balbi, Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

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

On 06/27/2014 09:00 AM, Felipe Balbi wrote:
> On Wed, Jun 25, 2014 at 04:30:48PM -0700, Andrew Bresticker wrote:
>>>> +static int usb3_phy_power_on(struct phy *phy)
>>>> +{
>>>> +     struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
>>>> +     int port = usb3_phy_to_port(phy);
>>>> +     int lane = padctl->usb3_ports[port].lane;
>>>> +     u32 value, offset;
>>>> +
>>>> +     value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
>>>> +     value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
>>>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
>>>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
>>>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
>>>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
>>>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
>>>
>>> Hmm. So there is a lot of "PHY" stuff here after all.
>>>
>>> However, the PHYs implemented here appear to implement very low-level
>>> I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
>>> somewhat higher-level; they're more USB-oriented than just IO pad
>>> oriented. Do you know which level of abstraction a Linux PHY object is
>>> supposed to be? I could never get an answer when I asked before.
>>
>> The only other PHY driver I've worked with (Exynos USB2/3 PHYs) also
>> mainly only did low-level pad control stuff, but looking at a couple
>> of other USB PHYs (MSM, MV), there appear to be others that have
>> higher-level USB stuff in the PHY driver.  Perhaps Kishon or Felipe
>> could offer us some guidance?
> 
> well, if you're adding a new driver, I'd rather see folks moving over to
> the generic phy framework (drivers/phy) because we're trying really hard
> to get rid of drivers/usb/phy/. And I think, in your case, it's actually
> ok to use pinctrl because you actually are muxing pads to the USB3 PHY,
> you just do it lazyly.

What I'm looking for is a good definition of exactly what a PHY is
supposed to be in Linux.

Is it purely something that turns some IO pads/drivers off/on, and
nothing more?

Or, does the PHY concept encompass protocol-specific concepts such as
USB VBUS enable, USB VBUS detection, USB OTG switching,
UTMI-vs-ULPI-vs-HSIC selection... all of which are irrelevant of the PHY
(or at least IO pads) are used for SATA or PCIe instead.

This obviously affects which code goes in the PHY driver, and which in
the EHCI/XHCI controller driver.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-27 16:05             ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-27 16:05 UTC (permalink / raw)
  To: balbi, Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

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

On 06/27/2014 09:00 AM, Felipe Balbi wrote:
> On Wed, Jun 25, 2014 at 04:30:48PM -0700, Andrew Bresticker wrote:
>>>> +static int usb3_phy_power_on(struct phy *phy)
>>>> +{
>>>> +     struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
>>>> +     int port = usb3_phy_to_port(phy);
>>>> +     int lane = padctl->usb3_ports[port].lane;
>>>> +     u32 value, offset;
>>>> +
>>>> +     value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
>>>> +     value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
>>>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
>>>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
>>>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
>>>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
>>>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
>>>
>>> Hmm. So there is a lot of "PHY" stuff here after all.
>>>
>>> However, the PHYs implemented here appear to implement very low-level
>>> I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
>>> somewhat higher-level; they're more USB-oriented than just IO pad
>>> oriented. Do you know which level of abstraction a Linux PHY object is
>>> supposed to be? I could never get an answer when I asked before.
>>
>> The only other PHY driver I've worked with (Exynos USB2/3 PHYs) also
>> mainly only did low-level pad control stuff, but looking at a couple
>> of other USB PHYs (MSM, MV), there appear to be others that have
>> higher-level USB stuff in the PHY driver.  Perhaps Kishon or Felipe
>> could offer us some guidance?
> 
> well, if you're adding a new driver, I'd rather see folks moving over to
> the generic phy framework (drivers/phy) because we're trying really hard
> to get rid of drivers/usb/phy/. And I think, in your case, it's actually
> ok to use pinctrl because you actually are muxing pads to the USB3 PHY,
> you just do it lazyly.

What I'm looking for is a good definition of exactly what a PHY is
supposed to be in Linux.

Is it purely something that turns some IO pads/drivers off/on, and
nothing more?

Or, does the PHY concept encompass protocol-specific concepts such as
USB VBUS enable, USB VBUS detection, USB OTG switching,
UTMI-vs-ULPI-vs-HSIC selection... all of which are irrelevant of the PHY
(or at least IO pads) are used for SATA or PCIe instead.

This obviously affects which code goes in the PHY driver, and which in
the EHCI/XHCI controller driver.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

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

* [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-27 16:05             ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-27 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/27/2014 09:00 AM, Felipe Balbi wrote:
> On Wed, Jun 25, 2014 at 04:30:48PM -0700, Andrew Bresticker wrote:
>>>> +static int usb3_phy_power_on(struct phy *phy)
>>>> +{
>>>> +     struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
>>>> +     int port = usb3_phy_to_port(phy);
>>>> +     int lane = padctl->usb3_ports[port].lane;
>>>> +     u32 value, offset;
>>>> +
>>>> +     value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_USB3_PADX_CTL2(port));
>>>> +     value &= ~((XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_MASK <<
>>>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_WANDER_SHIFT) |
>>>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_MASK <<
>>>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_RX_EQ_SHIFT) |
>>>> +                (XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_MASK <<
>>>> +                 XUSB_PADCTL_IOPHY_USB3_PAD_CTL2_CDR_CNTL_SHIFT));
>>>
>>> Hmm. So there is a lot of "PHY" stuff here after all.
>>>
>>> However, the PHYs implemented here appear to implement very low-level
>>> I/O pad code, whereas the PHYs we have for our USB 2.0 controller are
>>> somewhat higher-level; they're more USB-oriented than just IO pad
>>> oriented. Do you know which level of abstraction a Linux PHY object is
>>> supposed to be? I could never get an answer when I asked before.
>>
>> The only other PHY driver I've worked with (Exynos USB2/3 PHYs) also
>> mainly only did low-level pad control stuff, but looking at a couple
>> of other USB PHYs (MSM, MV), there appear to be others that have
>> higher-level USB stuff in the PHY driver.  Perhaps Kishon or Felipe
>> could offer us some guidance?
> 
> well, if you're adding a new driver, I'd rather see folks moving over to
> the generic phy framework (drivers/phy) because we're trying really hard
> to get rid of drivers/usb/phy/. And I think, in your case, it's actually
> ok to use pinctrl because you actually are muxing pads to the USB3 PHY,
> you just do it lazyly.

What I'm looking for is a good definition of exactly what a PHY is
supposed to be in Linux.

Is it purely something that turns some IO pads/drivers off/on, and
nothing more?

Or, does the PHY concept encompass protocol-specific concepts such as
USB VBUS enable, USB VBUS detection, USB OTG switching,
UTMI-vs-ULPI-vs-HSIC selection... all of which are irrelevant of the PHY
(or at least IO pads) are used for SATA or PCIe instead.

This obviously affects which code goes in the PHY driver, and which in
the EHCI/XHCI controller driver.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 901 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140627/0734a569/attachment.sig>

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-06-26 18:07             ` Stephen Warren
  (?)
@ 2014-06-27 21:19               ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-27 21:19 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Thu, Jun 26, 2014 at 11:07 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/25/2014 06:06 PM, Andrew Bresticker wrote:
>> On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>>> Add support for the on-chip XHCI host controller present on Tegra 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.

>>>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c

>>>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>>>> +                              unsigned long rate)
>>>
>>>> +     switch (rate) {
>>>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>>>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>>>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>>>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>>>> +             div = new_parent_rate / rate;
>>>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>>>> +             if (ret)
>>>> +                     return ret;
>>>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>>>> +             if (ret)
>>>> +                     return ret;
>>>
>>> Don't you need to call clk_set_rate() again after reparenting, since the
>>> divisor will be different, and the rounding too.
>>
>> Nope, the divider we set before remains in-tact after clk_set_parent().
>
> Oh I see, the clk_set_rate() call is setting up div so it's appropriate
> after the new parent is selected.
>
> Wouldn't it be better to just stop the clock, assert reset, reparent the
> clock, and then set the desired rate directly?

I'm not sure how that would be better than making it more obvious as
to how we arrive at the final rate.  Keep in mind that the XHCI host
is running at this point (we usually get the scale-up message as a
USB3 device is being enumerated) and that disabling the clock and/or
asserting reset to the SS partition clock may not be the best idea...

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-27 21:19               ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-27 21:19 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On Thu, Jun 26, 2014 at 11:07 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/25/2014 06:06 PM, Andrew Bresticker wrote:
>> On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>>> Add support for the on-chip XHCI host controller present on Tegra 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.

>>>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c

>>>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>>>> +                              unsigned long rate)
>>>
>>>> +     switch (rate) {
>>>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>>>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>>>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>>>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>>>> +             div = new_parent_rate / rate;
>>>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>>>> +             if (ret)
>>>> +                     return ret;
>>>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>>>> +             if (ret)
>>>> +                     return ret;
>>>
>>> Don't you need to call clk_set_rate() again after reparenting, since the
>>> divisor will be different, and the rounding too.
>>
>> Nope, the divider we set before remains in-tact after clk_set_parent().
>
> Oh I see, the clk_set_rate() call is setting up div so it's appropriate
> after the new parent is selected.
>
> Wouldn't it be better to just stop the clock, assert reset, reparent the
> clock, and then set the desired rate directly?

I'm not sure how that would be better than making it more obvious as
to how we arrive at the final rate.  Keep in mind that the XHCI host
is running at this point (we usually get the scale-up message as a
USB3 device is being enumerated) and that disabling the clock and/or
asserting reset to the SS partition clock may not be the best idea...

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-27 21:19               ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-27 21:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 26, 2014 at 11:07 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/25/2014 06:06 PM, Andrew Bresticker wrote:
>> On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>>> Add support for the on-chip XHCI host controller present on Tegra 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.

>>>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c

>>>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>>>> +                              unsigned long rate)
>>>
>>>> +     switch (rate) {
>>>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>>>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>>>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>>>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>>>> +             div = new_parent_rate / rate;
>>>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>>>> +             if (ret)
>>>> +                     return ret;
>>>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>>>> +             if (ret)
>>>> +                     return ret;
>>>
>>> Don't you need to call clk_set_rate() again after reparenting, since the
>>> divisor will be different, and the rounding too.
>>
>> Nope, the divider we set before remains in-tact after clk_set_parent().
>
> Oh I see, the clk_set_rate() call is setting up div so it's appropriate
> after the new parent is selected.
>
> Wouldn't it be better to just stop the clock, assert reset, reparent the
> clock, and then set the desired rate directly?

I'm not sure how that would be better than making it more obvious as
to how we arrive at the final rate.  Keep in mind that the XHCI host
is running at this point (we usually get the scale-up message as a
USB3 device is being enumerated) and that disabling the clock and/or
asserting reset to the SS partition clock may not be the best idea...

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
  2014-06-26 18:08           ` Stephen Warren
  (?)
@ 2014-06-27 21:22             ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-27 21:22 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann, bal

On Thu, Jun 26, 2014 at 11:08 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/25/2014 05:30 PM, Andrew Bresticker wrote:
>> On Wed, Jun 25, 2014 at 3:12 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>>> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
>>>> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
>>>> PCIe or SATA lane and is mapped to one of the three UTMI ports.
>>>>
>>>
>>>> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
>>>
>>>> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>>>>                       padctl_writel(padctl, regval, lane->offset);
>>>>                       break;
>>>>
>>>> +             case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
>>>> +                     if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
>>>> +                             dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
>>>> +                                     value);
>>>> +                             return -EINVAL;
>>>> +                     }
>>>> +                     if (!is_pcie_sata_lane(group)) {
>>>> +                             dev_err(padctl->dev,
>>>> +                                     "USB3 port not applicable for pin %d\n",
>>>> +                                     group);
>>>> +                             return -EINVAL;
>>>> +                     }
>>>> +                     padctl->usb3_ports[value].lane = group;
>>>> +                     break;
>>>
>>> It feels odd to use pinctrl for a SW-only purpose. In other words, that
>>> chunk of code isn't writing the pinconf data to HW, but rather some
>>> internal variable.
>>
>> Well the mapping of lanes to USB3 ports is a hardware property and we
>> do use it when programming the hardware later to choose which set of
>> lane registers to program given a USB3 port, but it's true that it's
>> not some value we program into HW directly.
>>
>>> Perhaps it would make more sense for the DT binding to represent this
>>> data directly in a custom property that's parsed at probe() time. That
>>> way, pinctrl only touches "real" HW stuff.
>>
>> I'm on the fence about this.  If you or others feel strongly about
>> this then I can make it a separate DT property and move it out of the
>> pinctrl properties.
>
> I'd certainly prefer to use pinctrl bindings only for things that get
> directly written into HW. Other configuration data should be easy to
> retrieve directly from properties.

Ok, I'll make a separate DT property for the USB3 port <-> lane
assignments then.

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

* Re: [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-27 21:22             ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-27 21:22 UTC (permalink / raw)
  To: Stephen Warren
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann, balbi

On Thu, Jun 26, 2014 at 11:08 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/25/2014 05:30 PM, Andrew Bresticker wrote:
>> On Wed, Jun 25, 2014 at 3:12 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>>> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
>>>> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
>>>> PCIe or SATA lane and is mapped to one of the three UTMI ports.
>>>>
>>>
>>>> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
>>>
>>>> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>>>>                       padctl_writel(padctl, regval, lane->offset);
>>>>                       break;
>>>>
>>>> +             case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
>>>> +                     if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
>>>> +                             dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
>>>> +                                     value);
>>>> +                             return -EINVAL;
>>>> +                     }
>>>> +                     if (!is_pcie_sata_lane(group)) {
>>>> +                             dev_err(padctl->dev,
>>>> +                                     "USB3 port not applicable for pin %d\n",
>>>> +                                     group);
>>>> +                             return -EINVAL;
>>>> +                     }
>>>> +                     padctl->usb3_ports[value].lane = group;
>>>> +                     break;
>>>
>>> It feels odd to use pinctrl for a SW-only purpose. In other words, that
>>> chunk of code isn't writing the pinconf data to HW, but rather some
>>> internal variable.
>>
>> Well the mapping of lanes to USB3 ports is a hardware property and we
>> do use it when programming the hardware later to choose which set of
>> lane registers to program given a USB3 port, but it's true that it's
>> not some value we program into HW directly.
>>
>>> Perhaps it would make more sense for the DT binding to represent this
>>> data directly in a custom property that's parsed at probe() time. That
>>> way, pinctrl only touches "real" HW stuff.
>>
>> I'm on the fence about this.  If you or others feel strongly about
>> this then I can make it a separate DT property and move it out of the
>> pinctrl properties.
>
> I'd certainly prefer to use pinctrl bindings only for things that get
> directly written into HW. Other configuration data should be easy to
> retrieve directly from properties.

Ok, I'll make a separate DT property for the USB3 port <-> lane
assignments then.

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

* [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support
@ 2014-06-27 21:22             ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-06-27 21:22 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jun 26, 2014 at 11:08 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 06/25/2014 05:30 PM, Andrew Bresticker wrote:
>> On Wed, Jun 25, 2014 at 3:12 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>>> In addition to the PCIe and SATA PHYs, the XUSB pad controller also
>>>> supports 3 UTMI, 2 HSIC, and 2 USB3 PHYs.  Each USB3 PHY uses a single
>>>> PCIe or SATA lane and is mapped to one of the three UTMI ports.
>>>>
>>>
>>>> diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
>>>
>>>> @@ -372,6 +720,193 @@ static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
>>>>                       padctl_writel(padctl, regval, lane->offset);
>>>>                       break;
>>>>
>>>> +             case TEGRA_XUSB_PADCTL_USB3_PORT_NUM:
>>>> +                     if (value >= TEGRA_XUSB_PADCTL_USB3_PORTS) {
>>>> +                             dev_err(padctl->dev, "Invalid USB3 port: %lu\n",
>>>> +                                     value);
>>>> +                             return -EINVAL;
>>>> +                     }
>>>> +                     if (!is_pcie_sata_lane(group)) {
>>>> +                             dev_err(padctl->dev,
>>>> +                                     "USB3 port not applicable for pin %d\n",
>>>> +                                     group);
>>>> +                             return -EINVAL;
>>>> +                     }
>>>> +                     padctl->usb3_ports[value].lane = group;
>>>> +                     break;
>>>
>>> It feels odd to use pinctrl for a SW-only purpose. In other words, that
>>> chunk of code isn't writing the pinconf data to HW, but rather some
>>> internal variable.
>>
>> Well the mapping of lanes to USB3 ports is a hardware property and we
>> do use it when programming the hardware later to choose which set of
>> lane registers to program given a USB3 port, but it's true that it's
>> not some value we program into HW directly.
>>
>>> Perhaps it would make more sense for the DT binding to represent this
>>> data directly in a custom property that's parsed at probe() time. That
>>> way, pinctrl only touches "real" HW stuff.
>>
>> I'm on the fence about this.  If you or others feel strongly about
>> this then I can make it a separate DT property and move it out of the
>> pinctrl properties.
>
> I'd certainly prefer to use pinctrl bindings only for things that get
> directly written into HW. Other configuration data should be easy to
> retrieve directly from properties.

Ok, I'll make a separate DT property for the USB3 port <-> lane
assignments then.

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-06-27 21:19               ` Andrew Bresticker
  (?)
@ 2014-06-27 22:01                 ` Stephen Warren
  -1 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-27 22:01 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/27/2014 03:19 PM, Andrew Bresticker wrote:
> On Thu, Jun 26, 2014 at 11:07 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/25/2014 06:06 PM, Andrew Bresticker wrote:
>>> On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>>>> Add support for the on-chip XHCI host controller present on Tegra 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.
> 
>>>>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
> 
>>>>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>>>>> +                              unsigned long rate)
>>>>
>>>>> +     switch (rate) {
>>>>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>>>>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>>>>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>>>>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>>>>> +             div = new_parent_rate / rate;
>>>>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>>>>> +             if (ret)
>>>>> +                     return ret;
>>>>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>>>>> +             if (ret)
>>>>> +                     return ret;
>>>>
>>>> Don't you need to call clk_set_rate() again after reparenting, since the
>>>> divisor will be different, and the rounding too.
>>>
>>> Nope, the divider we set before remains in-tact after clk_set_parent().
>>
>> Oh I see, the clk_set_rate() call is setting up div so it's appropriate
>> after the new parent is selected.
>>
>> Wouldn't it be better to just stop the clock, assert reset, reparent the
>> clock, and then set the desired rate directly?
> 
> I'm not sure how that would be better than making it more obvious as
> to how we arrive at the final rate.  Keep in mind that the XHCI host
> is running at this point (we usually get the scale-up message as a
> USB3 device is being enumerated) and that disabling the clock and/or
> asserting reset to the SS partition clock may not be the best idea...

Oh, this happens while the device is running rather than when
initializing it? Applying reset is probably a bad idea then. Still,
perhaps stopping the clock for a short time is fine? What about:

clk_disable_unprepare(clk);
clk_set_parent(clk, tegra->pll_u_480m);
clk_set_rate(clk, rate);
clk_prepare_enable(clk);

That seems much more direct to me. The code above feels over-complex to me.

If the clock really can't be stopped, then I suppose the existing code
in the patch is fine. I'd like to see a final clk_get_rate(clk) call
added, and the value compared against the expected value, to make sure
no rounding/truncation of the divider happened though.

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-27 22:01                 ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-27 22:01 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel,
	linux-arm-kernel, linux-usb, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Thierry Reding, Russell King, Linus Walleij, Greg Kroah-Hartman,
	Mathias Nyman, Grant Likely, Alan Stern, Kishon Vijay Abraham I,
	Arnd Bergmann

On 06/27/2014 03:19 PM, Andrew Bresticker wrote:
> On Thu, Jun 26, 2014 at 11:07 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/25/2014 06:06 PM, Andrew Bresticker wrote:
>>> On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>>>> Add support for the on-chip XHCI host controller present on Tegra 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.
> 
>>>>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
> 
>>>>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>>>>> +                              unsigned long rate)
>>>>
>>>>> +     switch (rate) {
>>>>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>>>>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>>>>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>>>>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>>>>> +             div = new_parent_rate / rate;
>>>>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>>>>> +             if (ret)
>>>>> +                     return ret;
>>>>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>>>>> +             if (ret)
>>>>> +                     return ret;
>>>>
>>>> Don't you need to call clk_set_rate() again after reparenting, since the
>>>> divisor will be different, and the rounding too.
>>>
>>> Nope, the divider we set before remains in-tact after clk_set_parent().
>>
>> Oh I see, the clk_set_rate() call is setting up div so it's appropriate
>> after the new parent is selected.
>>
>> Wouldn't it be better to just stop the clock, assert reset, reparent the
>> clock, and then set the desired rate directly?
> 
> I'm not sure how that would be better than making it more obvious as
> to how we arrive at the final rate.  Keep in mind that the XHCI host
> is running at this point (we usually get the scale-up message as a
> USB3 device is being enumerated) and that disabling the clock and/or
> asserting reset to the SS partition clock may not be the best idea...

Oh, this happens while the device is running rather than when
initializing it? Applying reset is probably a bad idea then. Still,
perhaps stopping the clock for a short time is fine? What about:

clk_disable_unprepare(clk);
clk_set_parent(clk, tegra->pll_u_480m);
clk_set_rate(clk, rate);
clk_prepare_enable(clk);

That seems much more direct to me. The code above feels over-complex to me.

If the clock really can't be stopped, then I suppose the existing code
in the patch is fine. I'd like to see a final clk_get_rate(clk) call
added, and the value compared against the expected value, to make sure
no rounding/truncation of the divider happened though.

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-06-27 22:01                 ` Stephen Warren
  0 siblings, 0 replies; 111+ messages in thread
From: Stephen Warren @ 2014-06-27 22:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 06/27/2014 03:19 PM, Andrew Bresticker wrote:
> On Thu, Jun 26, 2014 at 11:07 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>> On 06/25/2014 06:06 PM, Andrew Bresticker wrote:
>>> On Wed, Jun 25, 2014 at 3:37 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>> On 06/18/2014 12:16 AM, Andrew Bresticker wrote:
>>>>> Add support for the on-chip XHCI host controller present on Tegra 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.
> 
>>>>> diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c
> 
>>>>> +static int tegra_xhci_set_ss_clk(struct tegra_xhci_hcd *tegra,
>>>>> +                              unsigned long rate)
>>>>
>>>>> +     switch (rate) {
>>>>> +     case TEGRA_XHCI_SS_CLK_HIGH_SPEED:
>>>>> +             /* Reparent to PLLU_480M. Set div first to avoid overclocking */
>>>>> +             old_parent_rate = clk_get_rate(clk_get_parent(clk));
>>>>> +             new_parent_rate = clk_get_rate(tegra->pll_u_480m);
>>>>> +             div = new_parent_rate / rate;
>>>>> +             ret = clk_set_rate(clk, old_parent_rate / div);
>>>>> +             if (ret)
>>>>> +                     return ret;
>>>>> +             ret = clk_set_parent(clk, tegra->pll_u_480m);
>>>>> +             if (ret)
>>>>> +                     return ret;
>>>>
>>>> Don't you need to call clk_set_rate() again after reparenting, since the
>>>> divisor will be different, and the rounding too.
>>>
>>> Nope, the divider we set before remains in-tact after clk_set_parent().
>>
>> Oh I see, the clk_set_rate() call is setting up div so it's appropriate
>> after the new parent is selected.
>>
>> Wouldn't it be better to just stop the clock, assert reset, reparent the
>> clock, and then set the desired rate directly?
> 
> I'm not sure how that would be better than making it more obvious as
> to how we arrive at the final rate.  Keep in mind that the XHCI host
> is running at this point (we usually get the scale-up message as a
> USB3 device is being enumerated) and that disabling the clock and/or
> asserting reset to the SS partition clock may not be the best idea...

Oh, this happens while the device is running rather than when
initializing it? Applying reset is probably a bad idea then. Still,
perhaps stopping the clock for a short time is fine? What about:

clk_disable_unprepare(clk);
clk_set_parent(clk, tegra->pll_u_480m);
clk_set_rate(clk, rate);
clk_prepare_enable(clk);

That seems much more direct to me. The code above feels over-complex to me.

If the clock really can't be stopped, then I suppose the existing code
in the patch is fine. I'd like to see a final clk_get_rate(clk) call
added, and the value compared against the expected value, to make sure
no rounding/truncation of the divider happened though.

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-06-20 16:58         ` Julius Werner
  (?)
@ 2014-07-08 21:52             ` Andrew Bresticker
  -1 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-07-08 21:52 UTC (permalink / raw)
  To: Julius Werner, linux-usb-u79uwXL29TY76Z2rM5mHXA, Mathias Nyman,
	Alan Stern
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, LKML,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Stephen Warren, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Grant Likely, Kishon Vijay Abraham I,
	Arnd Bergmann

On Fri, Jun 20, 2014 at 9:58 AM, Julius Werner <jwerner-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> wrote:
>> +static const struct hc_driver tegra_xhci_hc_driver = {
>> +       .description =          "tegra-xhci-hcd",
>> +       .product_desc =         "Tegra xHCI Host Controller",
>> +       .hcd_priv_size =        sizeof(struct xhci_hcd *),
>> +
>> +       /*
>> +        * generic hardware linkage
>> +        */
>> +       .irq =                  xhci_irq,
>> +       .flags =                HCD_MEMORY | HCD_USB3 | HCD_SHARED,
>> +
>> +       /*
>> +        * basic lifecycle operations
>> +        */
>> +       .reset =                tegra_xhci_setup,
>> +       .start =                xhci_run,
>> +       .stop =                 xhci_stop,
>> +       .shutdown =             xhci_shutdown,
>> +
>> +       /*
>> +        * managing i/o requests and associated device resources
>> +        */
>> +       .urb_enqueue =          xhci_urb_enqueue,
>> +       .urb_dequeue =          xhci_urb_dequeue,
>> +       .alloc_dev =            xhci_alloc_dev,
>> +       .free_dev =             xhci_free_dev,
>> +       .alloc_streams =        xhci_alloc_streams,
>> +       .free_streams =         xhci_free_streams,
>> +       .add_endpoint =         xhci_add_endpoint,
>> +       .drop_endpoint =        xhci_drop_endpoint,
>> +       .endpoint_reset =       xhci_endpoint_reset,
>> +       .check_bandwidth =      xhci_check_bandwidth,
>> +       .reset_bandwidth =      xhci_reset_bandwidth,
>> +       .address_device =       xhci_address_device,
>> +       .enable_device =        xhci_enable_device,
>> +       .update_hub_device =    xhci_update_hub_device,
>> +       .reset_device =         xhci_discover_or_reset_device,
>> +
>> +       /*
>> +        * scheduling support
>> +        */
>> +       .get_frame_number =     xhci_get_frame,
>> +
>> +       /* Root hub support */
>> +       .hub_control =          xhci_hub_control,
>> +       .hub_status_data =      xhci_hub_status_data,
>> +       .bus_suspend =          xhci_bus_suspend,
>> +       .bus_resume =           xhci_bus_resume,
>> +};
>
> I know I missed the first round of discussion where this was
> suggested, but I don't think it's a good idea to pull the whole
> hc_driver structure out into every platform implementation. It will
> lead to duplication, then to future additions only being applied to
> some of the implementations and everything getting out of sync. This
> is already a problem with the PCI/plat split (e.g. the LPM functions
> were only added to xhci-pci even though they should apply to both).
> Also, if I'm not mistaken this code would fail to compile as a module
> (you are referencing lots of symbols that are internal to the xhci-hcd
> module).

You're right Julius, this won't build as a module without a few EXPORT_SYMBOLs.

> I think at the very least you should add a function
> "xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
> even better to xhci.c and use it for PCI as well) that initializes all
> function pointers to the default (internal) symbols, and can then be
> overridden afterwards.

Currently all XHCI host drivers (PCI, platform, MVEBU) will be built
into the xhci-hcd module.  I could append the Tegra driver to that
module or introduce a xhci_init_driver() like EHCI does as Julius
suggests.  USB folks, do you have a preference?
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-07-08 21:52             ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-07-08 21:52 UTC (permalink / raw)
  To: Julius Werner, linux-usb, Mathias Nyman, Alan Stern
  Cc: devicetree, linux-doc, linux-tegra, LKML, linux-arm-kernel,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Grant Likely,
	Kishon Vijay Abraham I, Arnd Bergmann

On Fri, Jun 20, 2014 at 9:58 AM, Julius Werner <jwerner@chromium.org> wrote:
>> +static const struct hc_driver tegra_xhci_hc_driver = {
>> +       .description =          "tegra-xhci-hcd",
>> +       .product_desc =         "Tegra xHCI Host Controller",
>> +       .hcd_priv_size =        sizeof(struct xhci_hcd *),
>> +
>> +       /*
>> +        * generic hardware linkage
>> +        */
>> +       .irq =                  xhci_irq,
>> +       .flags =                HCD_MEMORY | HCD_USB3 | HCD_SHARED,
>> +
>> +       /*
>> +        * basic lifecycle operations
>> +        */
>> +       .reset =                tegra_xhci_setup,
>> +       .start =                xhci_run,
>> +       .stop =                 xhci_stop,
>> +       .shutdown =             xhci_shutdown,
>> +
>> +       /*
>> +        * managing i/o requests and associated device resources
>> +        */
>> +       .urb_enqueue =          xhci_urb_enqueue,
>> +       .urb_dequeue =          xhci_urb_dequeue,
>> +       .alloc_dev =            xhci_alloc_dev,
>> +       .free_dev =             xhci_free_dev,
>> +       .alloc_streams =        xhci_alloc_streams,
>> +       .free_streams =         xhci_free_streams,
>> +       .add_endpoint =         xhci_add_endpoint,
>> +       .drop_endpoint =        xhci_drop_endpoint,
>> +       .endpoint_reset =       xhci_endpoint_reset,
>> +       .check_bandwidth =      xhci_check_bandwidth,
>> +       .reset_bandwidth =      xhci_reset_bandwidth,
>> +       .address_device =       xhci_address_device,
>> +       .enable_device =        xhci_enable_device,
>> +       .update_hub_device =    xhci_update_hub_device,
>> +       .reset_device =         xhci_discover_or_reset_device,
>> +
>> +       /*
>> +        * scheduling support
>> +        */
>> +       .get_frame_number =     xhci_get_frame,
>> +
>> +       /* Root hub support */
>> +       .hub_control =          xhci_hub_control,
>> +       .hub_status_data =      xhci_hub_status_data,
>> +       .bus_suspend =          xhci_bus_suspend,
>> +       .bus_resume =           xhci_bus_resume,
>> +};
>
> I know I missed the first round of discussion where this was
> suggested, but I don't think it's a good idea to pull the whole
> hc_driver structure out into every platform implementation. It will
> lead to duplication, then to future additions only being applied to
> some of the implementations and everything getting out of sync. This
> is already a problem with the PCI/plat split (e.g. the LPM functions
> were only added to xhci-pci even though they should apply to both).
> Also, if I'm not mistaken this code would fail to compile as a module
> (you are referencing lots of symbols that are internal to the xhci-hcd
> module).

You're right Julius, this won't build as a module without a few EXPORT_SYMBOLs.

> I think at the very least you should add a function
> "xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
> even better to xhci.c and use it for PCI as well) that initializes all
> function pointers to the default (internal) symbols, and can then be
> overridden afterwards.

Currently all XHCI host drivers (PCI, platform, MVEBU) will be built
into the xhci-hcd module.  I could append the Tegra driver to that
module or introduce a xhci_init_driver() like EHCI does as Julius
suggests.  USB folks, do you have a preference?

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-07-08 21:52             ` Andrew Bresticker
  0 siblings, 0 replies; 111+ messages in thread
From: Andrew Bresticker @ 2014-07-08 21:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jun 20, 2014 at 9:58 AM, Julius Werner <jwerner@chromium.org> wrote:
>> +static const struct hc_driver tegra_xhci_hc_driver = {
>> +       .description =          "tegra-xhci-hcd",
>> +       .product_desc =         "Tegra xHCI Host Controller",
>> +       .hcd_priv_size =        sizeof(struct xhci_hcd *),
>> +
>> +       /*
>> +        * generic hardware linkage
>> +        */
>> +       .irq =                  xhci_irq,
>> +       .flags =                HCD_MEMORY | HCD_USB3 | HCD_SHARED,
>> +
>> +       /*
>> +        * basic lifecycle operations
>> +        */
>> +       .reset =                tegra_xhci_setup,
>> +       .start =                xhci_run,
>> +       .stop =                 xhci_stop,
>> +       .shutdown =             xhci_shutdown,
>> +
>> +       /*
>> +        * managing i/o requests and associated device resources
>> +        */
>> +       .urb_enqueue =          xhci_urb_enqueue,
>> +       .urb_dequeue =          xhci_urb_dequeue,
>> +       .alloc_dev =            xhci_alloc_dev,
>> +       .free_dev =             xhci_free_dev,
>> +       .alloc_streams =        xhci_alloc_streams,
>> +       .free_streams =         xhci_free_streams,
>> +       .add_endpoint =         xhci_add_endpoint,
>> +       .drop_endpoint =        xhci_drop_endpoint,
>> +       .endpoint_reset =       xhci_endpoint_reset,
>> +       .check_bandwidth =      xhci_check_bandwidth,
>> +       .reset_bandwidth =      xhci_reset_bandwidth,
>> +       .address_device =       xhci_address_device,
>> +       .enable_device =        xhci_enable_device,
>> +       .update_hub_device =    xhci_update_hub_device,
>> +       .reset_device =         xhci_discover_or_reset_device,
>> +
>> +       /*
>> +        * scheduling support
>> +        */
>> +       .get_frame_number =     xhci_get_frame,
>> +
>> +       /* Root hub support */
>> +       .hub_control =          xhci_hub_control,
>> +       .hub_status_data =      xhci_hub_status_data,
>> +       .bus_suspend =          xhci_bus_suspend,
>> +       .bus_resume =           xhci_bus_resume,
>> +};
>
> I know I missed the first round of discussion where this was
> suggested, but I don't think it's a good idea to pull the whole
> hc_driver structure out into every platform implementation. It will
> lead to duplication, then to future additions only being applied to
> some of the implementations and everything getting out of sync. This
> is already a problem with the PCI/plat split (e.g. the LPM functions
> were only added to xhci-pci even though they should apply to both).
> Also, if I'm not mistaken this code would fail to compile as a module
> (you are referencing lots of symbols that are internal to the xhci-hcd
> module).

You're right Julius, this won't build as a module without a few EXPORT_SYMBOLs.

> I think at the very least you should add a function
> "xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
> even better to xhci.c and use it for PCI as well) that initializes all
> function pointers to the default (internal) symbols, and can then be
> overridden afterwards.

Currently all XHCI host drivers (PCI, platform, MVEBU) will be built
into the xhci-hcd module.  I could append the Tegra driver to that
module or introduce a xhci_init_driver() like EHCI does as Julius
suggests.  USB folks, do you have a preference?

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-07-08 21:52             ` Andrew Bresticker
  (?)
@ 2014-07-09 14:08                 ` Alan Stern
  -1 siblings, 0 replies; 111+ messages in thread
From: Alan Stern @ 2014-07-09 14:08 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Julius Werner, linux-usb-u79uwXL29TY76Z2rM5mHXA, Mathias Nyman,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, LKML,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Stephen Warren, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Grant Likely

On Tue, 8 Jul 2014, Andrew Bresticker wrote:

> > I think at the very least you should add a function
> > "xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
> > even better to xhci.c and use it for PCI as well) that initializes all
> > function pointers to the default (internal) symbols, and can then be
> > overridden afterwards.
> 
> Currently all XHCI host drivers (PCI, platform, MVEBU) will be built
> into the xhci-hcd module.  I could append the Tegra driver to that
> module or introduce a xhci_init_driver() like EHCI does as Julius
> suggests.  USB folks, do you have a preference?

As the EHCI maintainer, I naturally approve of Julius's suggestion.  

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-07-09 14:08                 ` Alan Stern
  0 siblings, 0 replies; 111+ messages in thread
From: Alan Stern @ 2014-07-09 14:08 UTC (permalink / raw)
  To: Andrew Bresticker
  Cc: Julius Werner, linux-usb, Mathias Nyman, devicetree, linux-doc,
	linux-tegra, LKML, linux-arm-kernel, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Stephen Warren, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman, Grant Likely, Kishon Vijay Abraham I,
	Arnd Bergmann

On Tue, 8 Jul 2014, Andrew Bresticker wrote:

> > I think at the very least you should add a function
> > "xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
> > even better to xhci.c and use it for PCI as well) that initializes all
> > function pointers to the default (internal) symbols, and can then be
> > overridden afterwards.
> 
> Currently all XHCI host drivers (PCI, platform, MVEBU) will be built
> into the xhci-hcd module.  I could append the Tegra driver to that
> module or introduce a xhci_init_driver() like EHCI does as Julius
> suggests.  USB folks, do you have a preference?

As the EHCI maintainer, I naturally approve of Julius's suggestion.  

Alan Stern


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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-07-09 14:08                 ` Alan Stern
  0 siblings, 0 replies; 111+ messages in thread
From: Alan Stern @ 2014-07-09 14:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, 8 Jul 2014, Andrew Bresticker wrote:

> > I think at the very least you should add a function
> > "xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
> > even better to xhci.c and use it for PCI as well) that initializes all
> > function pointers to the default (internal) symbols, and can then be
> > overridden afterwards.
> 
> Currently all XHCI host drivers (PCI, platform, MVEBU) will be built
> into the xhci-hcd module.  I could append the Tegra driver to that
> module or introduce a xhci_init_driver() like EHCI does as Julius
> suggests.  USB folks, do you have a preference?

As the EHCI maintainer, I naturally approve of Julius's suggestion.  

Alan Stern

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
  2014-07-09 14:08                 ` Alan Stern
  (?)
@ 2014-07-10 10:40                     ` Arnd Bergmann
  -1 siblings, 0 replies; 111+ messages in thread
From: Arnd Bergmann @ 2014-07-10 10:40 UTC (permalink / raw)
  To: Alan Stern
  Cc: Andrew Bresticker, Julius Werner,
	linux-usb-u79uwXL29TY76Z2rM5mHXA, Mathias Nyman,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, LKML,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Randy Dunlap,
	Stephen Warren, Thierry Reding, Russell King, Linus Walleij,
	Greg Kroah-Hartman

On Wednesday 09 July 2014, Alan Stern wrote:
> On Tue, 8 Jul 2014, Andrew Bresticker wrote:
> 
> > > I think at the very least you should add a function
> > > "xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
> > > even better to xhci.c and use it for PCI as well) that initializes all
> > > function pointers to the default (internal) symbols, and can then be
> > > overridden afterwards.
> > 
> > Currently all XHCI host drivers (PCI, platform, MVEBU) will be built
> > into the xhci-hcd module.  I could append the Tegra driver to that
> > module or introduce a xhci_init_driver() like EHCI does as Julius
> > suggests.  USB folks, do you have a preference?
> 
> As the EHCI maintainer, I naturally approve of Julius's suggestion.  

I'm not a USB maintainer, but I also agree that's the best way forward,
since it's similar to what all other similar drivers in the kernel do.

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-07-10 10:40                     ` Arnd Bergmann
  0 siblings, 0 replies; 111+ messages in thread
From: Arnd Bergmann @ 2014-07-10 10:40 UTC (permalink / raw)
  To: Alan Stern
  Cc: Andrew Bresticker, Julius Werner, linux-usb, Mathias Nyman,
	devicetree, linux-doc, linux-tegra, LKML, linux-arm-kernel,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Randy Dunlap, Stephen Warren, Thierry Reding, Russell King,
	Linus Walleij, Greg Kroah-Hartman, Grant Likely,
	Kishon Vijay Abraham I

On Wednesday 09 July 2014, Alan Stern wrote:
> On Tue, 8 Jul 2014, Andrew Bresticker wrote:
> 
> > > I think at the very least you should add a function
> > > "xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
> > > even better to xhci.c and use it for PCI as well) that initializes all
> > > function pointers to the default (internal) symbols, and can then be
> > > overridden afterwards.
> > 
> > Currently all XHCI host drivers (PCI, platform, MVEBU) will be built
> > into the xhci-hcd module.  I could append the Tegra driver to that
> > module or introduce a xhci_init_driver() like EHCI does as Julius
> > suggests.  USB folks, do you have a preference?
> 
> As the EHCI maintainer, I naturally approve of Julius's suggestion.  

I'm not a USB maintainer, but I also agree that's the best way forward,
since it's similar to what all other similar drivers in the kernel do.

	Arnd

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

* [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver
@ 2014-07-10 10:40                     ` Arnd Bergmann
  0 siblings, 0 replies; 111+ messages in thread
From: Arnd Bergmann @ 2014-07-10 10:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday 09 July 2014, Alan Stern wrote:
> On Tue, 8 Jul 2014, Andrew Bresticker wrote:
> 
> > > I think at the very least you should add a function
> > > "xhci_default_driver(struct hc_driver *driver)" to xhci-plat.c (or
> > > even better to xhci.c and use it for PCI as well) that initializes all
> > > function pointers to the default (internal) symbols, and can then be
> > > overridden afterwards.
> > 
> > Currently all XHCI host drivers (PCI, platform, MVEBU) will be built
> > into the xhci-hcd module.  I could append the Tegra driver to that
> > module or introduce a xhci_init_driver() like EHCI does as Julius
> > suggests.  USB folks, do you have a preference?
> 
> As the EHCI maintainer, I naturally approve of Julius's suggestion.  

I'm not a USB maintainer, but I also agree that's the best way forward,
since it's similar to what all other similar drivers in the kernel do.

	Arnd

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

end of thread, other threads:[~2014-07-10 10:42 UTC | newest]

Thread overview: 111+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-18  6:16 [PATCH v1 0/9] Tegra XHCI support Andrew Bresticker
2014-06-18  6:16 ` Andrew Bresticker
2014-06-18  6:16 ` Andrew Bresticker
2014-06-18  6:16 ` [PATCH v1 2/9] mailbox: Add NVIDIA Tegra XUSB mailbox driver Andrew Bresticker
2014-06-18  6:16   ` Andrew Bresticker
     [not found]   ` <1403072180-4944-3-git-send-email-abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2014-06-25 22:02     ` Stephen Warren
2014-06-25 22:02       ` Stephen Warren
2014-06-25 22:02       ` Stephen Warren
2014-06-25 23:07       ` Andrew Bresticker
2014-06-25 23:07         ` Andrew Bresticker
2014-06-25 23:07         ` Andrew Bresticker
2014-06-18  6:16 ` [PATCH v1 3/9] of: Update Tegra XUSB pad controller binding for USB Andrew Bresticker
2014-06-18  6:16   ` Andrew Bresticker
     [not found]   ` <1403072180-4944-4-git-send-email-abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2014-06-25 21:46     ` Stephen Warren
2014-06-25 21:46       ` Stephen Warren
2014-06-25 21:46       ` Stephen Warren
2014-06-25 22:25       ` Andrew Bresticker
2014-06-25 22:25         ` Andrew Bresticker
2014-06-25 22:25         ` Andrew Bresticker
2014-06-26 20:00         ` Stephen Warren
2014-06-26 20:00           ` Stephen Warren
2014-06-26 20:00           ` Stephen Warren
2014-06-18  6:16 ` [PATCH v1 5/9] of: Add NVIDIA Tegra XHCI controller binding Andrew Bresticker
2014-06-18  6:16   ` Andrew Bresticker
2014-06-18  6:16   ` Andrew Bresticker
     [not found]   ` <1403072180-4944-6-git-send-email-abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2014-06-25 21:52     ` Stephen Warren
2014-06-25 21:52       ` Stephen Warren
2014-06-25 21:52       ` Stephen Warren
2014-06-25 23:01       ` Andrew Bresticker
2014-06-25 23:01         ` Andrew Bresticker
2014-06-25 23:01         ` Andrew Bresticker
     [not found]         ` <CAL1qeaG=nLxDHrsVuuL9c-JdKB+TrNN785+8v=hb0MAFJ=5juw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-06-25 23:13           ` Stephen Warren
2014-06-25 23:13             ` Stephen Warren
2014-06-25 23:13             ` Stephen Warren
2014-06-25 21:54     ` Stephen Warren
2014-06-25 21:54       ` Stephen Warren
2014-06-25 21:54       ` Stephen Warren
     [not found]       ` <53AB4530.2050106-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2014-06-25 23:02         ` Andrew Bresticker
2014-06-25 23:02           ` Andrew Bresticker
2014-06-25 23:02           ` Andrew Bresticker
     [not found]           ` <CAL1qeaHThKVBoY0fikFCh9X00BFNJ=XKfovOBwztEyOVjHBLjg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-06-25 23:14             ` Stephen Warren
2014-06-25 23:14               ` Stephen Warren
2014-06-25 23:14               ` Stephen Warren
     [not found] ` <1403072180-4944-1-git-send-email-abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2014-06-18  6:16   ` [PATCH v1 1/9] of: Add NVIDIA Tegra XUSB mailbox binding Andrew Bresticker
2014-06-18  6:16     ` Andrew Bresticker
2014-06-18  6:16     ` Andrew Bresticker
     [not found]     ` <1403072180-4944-2-git-send-email-abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2014-06-25 21:42       ` Stephen Warren
2014-06-25 21:42         ` Stephen Warren
2014-06-25 21:42         ` Stephen Warren
     [not found]         ` <53AB422E.4040707-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2014-06-25 22:37           ` Andrew Bresticker
2014-06-25 22:37             ` Andrew Bresticker
2014-06-25 22:37             ` Andrew Bresticker
     [not found]             ` <CAL1qeaFPjq9nqA2GDZZW+=DZsddWCkUjJcnRsfPkBWj8gmFsiw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-06-25 23:00               ` Stephen Warren
2014-06-25 23:00                 ` Stephen Warren
2014-06-25 23:00                 ` Stephen Warren
2014-06-18  6:16   ` [PATCH v1 4/9] pinctrl: tegra-xusb: Add USB PHY support Andrew Bresticker
2014-06-18  6:16     ` Andrew Bresticker
2014-06-18  6:16     ` Andrew Bresticker
2014-06-25 22:12     ` Stephen Warren
2014-06-25 22:12       ` Stephen Warren
2014-06-25 23:30       ` Andrew Bresticker
2014-06-25 23:30         ` Andrew Bresticker
2014-06-25 23:30         ` Andrew Bresticker
2014-06-26 18:08         ` Stephen Warren
2014-06-26 18:08           ` Stephen Warren
2014-06-26 18:08           ` Stephen Warren
2014-06-27 21:22           ` Andrew Bresticker
2014-06-27 21:22             ` Andrew Bresticker
2014-06-27 21:22             ` Andrew Bresticker
2014-06-27 15:00         ` Felipe Balbi
2014-06-27 15:00           ` Felipe Balbi
2014-06-27 15:00           ` Felipe Balbi
2014-06-27 16:05           ` Stephen Warren
2014-06-27 16:05             ` Stephen Warren
2014-06-27 16:05             ` Stephen Warren
2014-06-18  6:16   ` [PATCH v1 6/9] usb: xhci: Add NVIDIA Tegra XHCI host-controller driver Andrew Bresticker
2014-06-18  6:16     ` Andrew Bresticker
2014-06-18  6:16     ` Andrew Bresticker
     [not found]     ` <1403072180-4944-7-git-send-email-abrestic-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
2014-06-20 16:58       ` Julius Werner
2014-06-20 16:58         ` Julius Werner
2014-06-20 16:58         ` Julius Werner
     [not found]         ` <CAODwPW-HSY3RoBi9VEhHSJ98drTsdche-2=mKfAViXWaUa3X1g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-08 21:52           ` Andrew Bresticker
2014-07-08 21:52             ` Andrew Bresticker
2014-07-08 21:52             ` Andrew Bresticker
     [not found]             ` <CAL1qeaHT8Yz7kRY3Qm5i+bYCF4D5BT=BVZ6BMfQufyaQFkt0mw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-07-09 14:08               ` Alan Stern
2014-07-09 14:08                 ` Alan Stern
2014-07-09 14:08                 ` Alan Stern
     [not found]                 ` <Pine.LNX.4.44L0.1407091001150.873-100000-IYeN2dnnYyZXsRXLowluHWD2FQJk+8+b@public.gmane.org>
2014-07-10 10:40                   ` Arnd Bergmann
2014-07-10 10:40                     ` Arnd Bergmann
2014-07-10 10:40                     ` Arnd Bergmann
2014-06-25 22:37     ` Stephen Warren
2014-06-25 22:37       ` Stephen Warren
2014-06-26  0:06       ` Andrew Bresticker
2014-06-26  0:06         ` Andrew Bresticker
2014-06-26  0:06         ` Andrew Bresticker
     [not found]         ` <CAL1qeaFhfYdW06Md10eGVYWBrRR+f1yykVYHNp5+9-t1C9joPQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-06-26 18:07           ` Stephen Warren
2014-06-26 18:07             ` Stephen Warren
2014-06-26 18:07             ` Stephen Warren
2014-06-27 21:19             ` Andrew Bresticker
2014-06-27 21:19               ` Andrew Bresticker
2014-06-27 21:19               ` Andrew Bresticker
2014-06-27 22:01               ` Stephen Warren
2014-06-27 22:01                 ` Stephen Warren
2014-06-27 22:01                 ` Stephen Warren
2014-06-18  6:16   ` [PATCH v1 7/9] ARM: tegra: Add Tegra124 XUSB mailbox and XHCI controller Andrew Bresticker
2014-06-18  6:16     ` Andrew Bresticker
2014-06-18  6:16     ` Andrew Bresticker
2014-06-18  6:16 ` [PATCH v1 8/9] ARM: tegra: jetson-tk1: Add XHCI support Andrew Bresticker
2014-06-18  6:16   ` Andrew Bresticker
2014-06-18  6:16 ` [PATCH v1 9/9] ARM: tegra: venice2: " Andrew Bresticker
2014-06-18  6:16   ` Andrew Bresticker

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.