Patchwork [U-Boot,v3,2/3] ARM: Tegra: USB: EHCI: Add support for Tegra30/Tegra114

login
register
mail settings
Submitter Jim Lin
Date June 17, 2013, 9:09 a.m.
Message ID <1371460197-17912-2-git-send-email-jilin@nvidia.com>
Download mbox | patch
Permalink /patch/251787/
State Superseded
Delegated to: Tom Warren
Headers show

Comments

Jim Lin - June 17, 2013, 9:09 a.m.
Tegra30 and Tegra114 are compatible except PLL parameters.

Tested on Tegra30 Cardhu, and Tegra114 Dalmore
platforms. All works well.

Signed-off-by: Jim Lin <jilin@nvidia.com>
---
Changes in v2:
 - Move common definitions into arch-tegra/usb.h and
   chip specific definitions into arch-tegraXX(X)/usb.h
 - In ehci-tegra.c, add PLL parameters for Tegra30 and Tegra114.
 - In ehci-tegra.c, use the port pointed by "nvidia,has-legacy-mode"
   to know whether we do special handling on Port Reset.
 - Remove some irrelevant whitespace changes.
 - Use if-else, instead of goto in ehci-tegra.c
   init_utmi_usb_controller().
 - Use original coding for PTS_MASK in ehci-tegra.c
   init_utmi_usb_controller().
   Reason is that these bits are read-only on Tegra20.
   Don't need special handling between USB1 and USB3 ports.
 - Use if-else, instead of goto in ehci-tegra.c board_usb_init().
Changes in v3:
 None

 arch/arm/include/asm/arch-tegra/clk_rst.h |   10 +
 arch/arm/include/asm/arch-tegra/usb.h     |  182 ++++--------------
 arch/arm/include/asm/arch-tegra114/usb.h  |  156 +++++++++++++++
 arch/arm/include/asm/arch-tegra20/usb.h   |  155 +++++++++++++++
 arch/arm/include/asm/arch-tegra30/usb.h   |  168 ++++++++++++++++
 board/nvidia/common/board.c               |    2 +-
 drivers/usb/host/ehci-tegra.c             |  297 +++++++++++++++++++++++++----
 7 files changed, 796 insertions(+), 174 deletions(-)
 create mode 100644 arch/arm/include/asm/arch-tegra114/usb.h
 create mode 100644 arch/arm/include/asm/arch-tegra20/usb.h
 create mode 100644 arch/arm/include/asm/arch-tegra30/usb.h
Thierry Reding - June 17, 2013, 10:43 a.m.
On Mon, Jun 17, 2013 at 05:09:56PM +0800, Jim Lin wrote:
[...]
> diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
> index 8d7a227..f0f81c9 100644
> --- a/board/nvidia/common/board.c
> +++ b/board/nvidia/common/board.c
> @@ -46,7 +46,7 @@
>  #include <asm/arch/emc.h>
>  #endif
>  #ifdef CONFIG_USB_EHCI_TEGRA
> -#include <asm/arch-tegra/usb.h>
> +#include <asm/arch/usb.h>
>  #endif
>  #ifdef CONFIG_TEGRA_MMC
>  #include <asm/arch-tegra/tegra_mmc.h>

With this hunk applied I get the following new build warning:

	../../nvidia/common/board.c: In function 'board_init':
	../../nvidia/common/board.c:171:2: warning: implicit declaration of function 'board_usb_init' [-Wimplicit-function-declaration]
	  board_usb_init(gd->fdt_blob);
	  ^

Reverting that one hunk makes the warning go away again and everything
still builds fine, so I think it can just be removed from the patch.

Besides the one issue I'm still seeing with the very old flash drive,
which might turn out not to be specific to Tegra, this series:

Tested-by: Thierry Reding <thierry.reding@gmail.com>
Stephen Warren - June 17, 2013, 4:44 p.m.
On 06/17/2013 03:09 AM, Jim Lin wrote:
> Tegra30 and Tegra114 are compatible except PLL parameters.
> 
> Tested on Tegra30 Cardhu, and Tegra114 Dalmore
> platforms. All works well.

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

> +static u32 port_clear_csc; /* Port that needs to clear CSC after Port Reset */

What "units" is that variable in? The variable name should be more like
"status_reg_addr_needing_clear_csc".

> +static unsigned is_T30_compatible;
> +static unsigned is_T114_compatible;

Given that there is code in this patch that does:

+	if (is_T30_compatible) {
+		if (is_T114_compatible)

I think those should be is_T30_or_later and is_T114_or_later.

But, testing against SoC version is the wrong way to go. Instead, the
code should set a bunch of feature flags based on the SoC it's running
on during initialization, and then test those feature flags throughout
the code. That way, if Tegra30 and (hypothetical future chips) Tegra200
and Tegra300 need a fix, but Tegra114 doesn't, you don't have to write
tortuous if statements throughout the code, but simply have a lookup
table that maps from SoC ID to the set of feature/fix flags that it needs.

See for example Linux kernel driver drivers/gpio/gpio-tegra.c's
tegra20_gpio_config, tegra30_gpio_config, and tegra_gpio_of_match[], or
drivers/dma/tegra20-apb-dma.c's tegra_dma_of_match[].

> +static const unsigned *get_pll_timing(void)
> +{
> +	const unsigned *timing;
> +
> +	if (is_T30_compatible) {
> +		if (is_T114_compatible)
> +			timing = T114_usb_pll[clock_get_osc_freq()];
> +		else
> +			timing = T30_usb_pll[clock_get_osc_freq()];
> +	} else {
> +		timing = T20_usb_pll[clock_get_osc_freq()];
> +	}
> +
> +	return timing;
> +}

Following on from the feature flag discussion above, it'd be better to
simply include a pointer in the per-SoC configuration table that pointed
at the PLL table. That way, this function could be removed, and replaced
with a simple read through a pointer.

> +int board_usb_init(const void *blob)
> +{
> +	int node_list[USB_PORTS_MAX];
> +	int count, err = 0;
> +
> +	is_T30_compatible = 0;
> +	is_T114_compatible = 0;
> +
> +	/* count may return <0 on error */
> +	count = fdtdec_find_aliases_for_id(blob, "usb",
> +			COMPAT_NVIDIA_TEGRA20_USB, node_list, USB_PORTS_MAX);
> +	if (count) {
> +		err = process_usb_nodes(blob, node_list, count);
> +		if (err)
> +			printf("%s: Error processing T20 USB node!\n",
> +			       __func__);
> +		return err;
> +	}
> +	count = fdtdec_find_aliases_for_id(blob, "usb",
> +			COMPAT_NVIDIA_TEGRA114_USB, node_list, USB_PORTS_MAX);
> +	if (count)
> +		is_T114_compatible = 1;
> +	else
> +		count = fdtdec_find_aliases_for_id(blob, "usb",
> +			COMPAT_NVIDIA_TEGRA30_USB, node_list, USB_PORTS_MAX);
> +	if (count) {
> +		/* T114 is also mostly compatible to T30 */
> +		is_T30_compatible = 1;
> +		err = process_usb_nodes(blob, node_list, count);
> +		if (err) {
> +			if (is_T114_compatible)
> +				printf("%s: Error processing T114 USB node!\n",
> +				       __func__);
> +			else
> +				printf("%s: Error processing T30 USB node!\n",
> +				       __func__);

(Following on from the comment below: Why not just say "USB node" rather
than "T30 USB node" or "T114 USB node" here. That way, you completely
avoid having to write an if statement.

> +		}
> +	}
> +
> +	return err;
> +}

This function is pretty convoluted. It'd be far better to enhance
fdtdec_find_aliases_for_id() to accept a list of compatible values, and
simply return all matching instances in one go.
fdtdec_find_aliases_for_id() should also return the "type" of each
match, so you know if each one is a Tegra20/30/114 port.

Patch

diff --git a/arch/arm/include/asm/arch-tegra/clk_rst.h b/arch/arm/include/asm/arch-tegra/clk_rst.h
index c754ec7..9b8de9c 100644
--- a/arch/arm/include/asm/arch-tegra/clk_rst.h
+++ b/arch/arm/include/asm/arch-tegra/clk_rst.h
@@ -225,6 +225,16 @@  enum {
 	IN_408_OUT_9_6_DIVISOR = 83,
 };
 
+/* CLK_RST_CONTROLLER_UTMIP_PLL_CFG1_0 */
+#define PLLU_POWERDOWN		(1 << 16)
+#define PLL_ENABLE_POWERDOWN	(1 << 14)
+#define PLL_ACTIVE_POWERDOWN	(1 << 12)
+
+/* CLK_RST_CONTROLLER_UTMIP_PLL_CFG2_0 */
+#define UTMIP_FORCE_PD_SAMP_C_POWERDOWN		(1 << 4)
+#define UTMIP_FORCE_PD_SAMP_B_POWERDOWN		(1 << 2)
+#define UTMIP_FORCE_PD_SAMP_A_POWERDOWN		(1 << 0)
+
 /* CLK_RST_CONTROLLER_OSC_CTRL_0 */
 #define OSC_XOBP_SHIFT		1
 #define OSC_XOBP_MASK		(1U << OSC_XOBP_SHIFT)
diff --git a/arch/arm/include/asm/arch-tegra/usb.h b/arch/arm/include/asm/arch-tegra/usb.h
index ef6c089..cefe0d2 100644
--- a/arch/arm/include/asm/arch-tegra/usb.h
+++ b/arch/arm/include/asm/arch-tegra/usb.h
@@ -1,5 +1,6 @@ 
 /*
  * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (c) 2013 NVIDIA Corporation
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -22,120 +23,6 @@ 
 #ifndef _TEGRA_USB_H_
 #define _TEGRA_USB_H_
 
-
-/* USB Controller (USBx_CONTROLLER_) regs */
-struct usb_ctlr {
-	/* 0x000 */
-	uint id;
-	uint reserved0;
-	uint host;
-	uint device;
-
-	/* 0x010 */
-	uint txbuf;
-	uint rxbuf;
-	uint reserved1[2];
-
-	/* 0x020 */
-	uint reserved2[56];
-
-	/* 0x100 */
-	u16 cap_length;
-	u16 hci_version;
-	uint hcs_params;
-	uint hcc_params;
-	uint reserved3[5];
-
-	/* 0x120 */
-	uint dci_version;
-	uint dcc_params;
-	uint reserved4[6];
-
-	/* 0x140 */
-	uint usb_cmd;
-	uint usb_sts;
-	uint usb_intr;
-	uint frindex;
-
-	/* 0x150 */
-	uint reserved5;
-	uint periodic_list_base;
-	uint async_list_addr;
-	uint async_tt_sts;
-
-	/* 0x160 */
-	uint burst_size;
-	uint tx_fill_tuning;
-	uint reserved6;   /* is this port_sc1 on some controllers? */
-	uint icusb_ctrl;
-
-	/* 0x170 */
-	uint ulpi_viewport;
-	uint reserved7;
-	uint endpt_nak;
-	uint endpt_nak_enable;
-
-	/* 0x180 */
-	uint reserved;
-	uint port_sc1;
-	uint reserved8[6];
-
-	/* 0x1a0 */
-	uint reserved9;
-	uint otgsc;
-	uint usb_mode;
-	uint endpt_setup_stat;
-
-	/* 0x1b0 */
-	uint reserved10[20];
-
-	/* 0x200 */
-	uint reserved11[0x80];
-
-	/* 0x400 */
-	uint susp_ctrl;
-	uint phy_vbus_sensors;
-	uint phy_vbus_wakeup_id;
-	uint phy_alt_vbus_sys;
-
-	/* 0x410 */
-	uint usb1_legacy_ctrl;
-	uint reserved12[4];
-
-	/* 0x424 */
-	uint ulpi_timing_ctrl_0;
-	uint ulpi_timing_ctrl_1;
-	uint reserved13[53];
-
-	/* 0x500 */
-	uint reserved14[64 * 3];
-
-	/* 0x800 */
-	uint utmip_pll_cfg0;
-	uint utmip_pll_cfg1;
-	uint utmip_xcvr_cfg0;
-	uint utmip_bias_cfg0;
-
-	/* 0x810 */
-	uint utmip_hsrx_cfg0;
-	uint utmip_hsrx_cfg1;
-	uint utmip_fslsrx_cfg0;
-	uint utmip_fslsrx_cfg1;
-
-	/* 0x820 */
-	uint utmip_tx_cfg0;
-	uint utmip_misc_cfg0;
-	uint utmip_misc_cfg1;
-	uint utmip_debounce_cfg0;
-
-	/* 0x830 */
-	uint utmip_bat_chrg_cfg0;
-	uint utmip_spare_cfg0;
-	uint utmip_xcvr_cfg1;
-	uint utmip_bias_cfg1;
-};
-
-
 /* USB1_LEGACY_CTRL */
 #define USB1_NO_LEGACY_MODE		1
 
@@ -146,25 +33,18 @@  struct usb_ctlr {
 #define VBUS_SENSE_CTL_AB_SESS_VLD		2
 #define VBUS_SENSE_CTL_A_SESS_VLD		3
 
-/* USB2_IF_ULPI_TIMING_CTRL_0 */
-#define ULPI_OUTPUT_PINMUX_BYP			(1 << 10)
-#define ULPI_CLKOUT_PINMUX_BYP			(1 << 11)
-
-/* USB2_IF_ULPI_TIMING_CTRL_1 */
-#define ULPI_DATA_TRIMMER_LOAD			(1 << 0)
-#define ULPI_DATA_TRIMMER_SEL(x)		(((x) & 0x7) << 1)
-#define ULPI_STPDIRNXT_TRIMMER_LOAD		(1 << 16)
-#define ULPI_STPDIRNXT_TRIMMER_SEL(x)	(((x) & 0x7) << 17)
-#define ULPI_DIR_TRIMMER_LOAD			(1 << 24)
-#define ULPI_DIR_TRIMMER_SEL(x)			(((x) & 0x7) << 25)
-
 /* USBx_IF_USB_SUSP_CTRL_0 */
-#define ULPI_PHY_ENB				(1 << 13)
 #define UTMIP_PHY_ENB			        (1 << 12)
 #define UTMIP_RESET			        (1 << 11)
 #define USB_PHY_CLK_VALID			(1 << 7)
 #define USB_SUSP_CLR				(1 << 5)
 
+/* USB2_IF_USB_SUSP_CTRL_0 */
+#define ULPI_PHY_ENB				(1 << 13)
+
+/* USBx_UTMIP_MISC_CFG0 */
+#define UTMIP_SUSPEND_EXIT_ON_EDGE		(1 << 22)
+
 /* USBx_UTMIP_MISC_CFG1 */
 #define UTMIP_PLLU_STABLE_COUNT_SHIFT		6
 #define UTMIP_PLLU_STABLE_COUNT_MASK		\
@@ -177,15 +57,28 @@  struct usb_ctlr {
 /* USBx_UTMIP_PLL_CFG1_0 */
 #define UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT	27
 #define UTMIP_PLLU_ENABLE_DLY_COUNT_MASK	\
-				(0xf << UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT)
+				(0x1f << UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT)
 #define UTMIP_XTAL_FREQ_COUNT_SHIFT		0
 #define UTMIP_XTAL_FREQ_COUNT_MASK		0xfff
 
+/* USBx_UTMIP_BIAS_CFG0_0 */
+#define UTMIP_HSDISCON_LEVEL_MSB		(1 << 24)
+#define UTMIP_OTGPD				(1 << 11)
+#define UTMIP_BIASPD				(1 << 10)
+#define UTMIP_HSDISCON_LEVEL_SHIFT		2
+#define UTMIP_HSDISCON_LEVEL_MASK		\
+				(0x3 << UTMIP_HSDISCON_LEVEL_SHIFT)
+#define UTMIP_HSSQUELCH_LEVEL_SHIFT		0
+#define UTMIP_HSSQUELCH_LEVEL_MASK		\
+				(0x3 << UTMIP_HSSQUELCH_LEVEL_SHIFT)
+
 /* USBx_UTMIP_BIAS_CFG1_0 */
+#define UTMIP_FORCE_PDTRK_POWERDOWN		1
 #define UTMIP_BIAS_PDTRK_COUNT_SHIFT		3
 #define UTMIP_BIAS_PDTRK_COUNT_MASK		\
 				(0x1f << UTMIP_BIAS_PDTRK_COUNT_SHIFT)
 
+/* USBx_UTMIP_DEBOUNCE_CFG0_0 */
 #define UTMIP_DEBOUNCE_CFG0_SHIFT		0
 #define UTMIP_DEBOUNCE_CFG0_MASK		0xffff
 
@@ -195,9 +88,6 @@  struct usb_ctlr {
 /* USBx_UTMIP_BAT_CHRG_CFG0_0 */
 #define UTMIP_PD_CHRG				1
 
-/* USBx_UTMIP_XCVR_CFG0_0 */
-#define UTMIP_XCVR_LSBIAS_SE			(1 << 21)
-
 /* USBx_UTMIP_SPARE_CFG0_0 */
 #define FUSE_SETUP_SEL				(1 << 3)
 
@@ -208,23 +98,26 @@  struct usb_ctlr {
 #define UTMIP_ELASTIC_LIMIT_MASK		\
 				(0x1f << UTMIP_ELASTIC_LIMIT_SHIFT)
 
-/* USBx_UTMIP_HSRX_CFG0_1 */
+/* USBx_UTMIP_HSRX_CFG1_0 */
 #define UTMIP_HS_SYNC_START_DLY_SHIFT		1
 #define UTMIP_HS_SYNC_START_DLY_MASK		\
-				(0xf << UTMIP_HS_SYNC_START_DLY_SHIFT)
+				(0x1f << UTMIP_HS_SYNC_START_DLY_SHIFT)
 
 /* USBx_CONTROLLER_2_USB2D_ICUSB_CTRL_0 */
 #define IC_ENB1					(1 << 3)
 
-/* SB2_CONTROLLER_2_USB2D_PORTSC1_0 */
-#define PTS_SHIFT				30
-#define PTS_MASK				(3U << PTS_SHIFT)
-#define PTS_UTMI		0
+/* PORTSC1, USB1, defined for Tegra20 */
+#define PTS1_SHIFT				31
+#define PTS1_MASK				(1 << PTS1_SHIFT)
+#define STS1					(1 << 30)
+
+#define PTS_UTMI	0
 #define PTS_RESERVED	1
-#define PTS_ULPI		2
+#define PTS_ULPI	2
 #define PTS_ICUSB_SER	3
+#define PTS_HSIC	4
 
-#define STS					(1 << 29)
+/* SB2_CONTROLLER_2_USB2D_PORTSC1_0 */
 #define WKOC				(1 << 22)
 #define WKDS				(1 << 21)
 #define WKCN				(1 << 20)
@@ -233,8 +126,19 @@  struct usb_ctlr {
 #define UTMIP_FORCE_PD_POWERDOWN		(1 << 14)
 #define UTMIP_FORCE_PD2_POWERDOWN		(1 << 16)
 #define UTMIP_FORCE_PDZI_POWERDOWN		(1 << 18)
+#define UTMIP_XCVR_LSBIAS_SE			(1 << 21)
+#define UTMIP_XCVR_HSSLEW_MSB_SHIFT		25
+#define UTMIP_XCVR_HSSLEW_MSB_MASK		\
+			(0x7f << UTMIP_XCVR_HSSLEW_MSB_SHIFT)
+#define UTMIP_XCVR_SETUP_MSB_SHIFT	22
+#define UTMIP_XCVR_SETUP_MSB_MASK	(0x7 << UTMIP_XCVR_SETUP_MSB_SHIFT)
+#define UTMIP_XCVR_SETUP_SHIFT		0
+#define UTMIP_XCVR_SETUP_MASK		(0xf << UTMIP_XCVR_SETUP_SHIFT)
 
 /* USBx_UTMIP_XCVR_CFG1_0 */
+#define UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT		18
+#define UTMIP_XCVR_TERM_RANGE_ADJ_MASK		\
+			(0xf << UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT)
 #define UTMIP_FORCE_PDDISC_POWERDOWN		(1 << 0)
 #define UTMIP_FORCE_PDCHRP_POWERDOWN		(1 << 2)
 #define UTMIP_FORCE_PDDR_POWERDOWN		(1 << 4)
diff --git a/arch/arm/include/asm/arch-tegra114/usb.h b/arch/arm/include/asm/arch-tegra114/usb.h
new file mode 100644
index 0000000..d46048c
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra114/usb.h
@@ -0,0 +1,156 @@ 
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (c) 2013 NVIDIA Corporation
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _TEGRA114_USB_H_
+#define _TEGRA114_USB_H_
+
+/* USB Controller (USBx_CONTROLLER_) regs */
+struct usb_ctlr {
+	/* 0x000 */
+	uint id;
+	uint reserved0;
+	uint host;
+	uint device;
+
+	/* 0x010 */
+	uint txbuf;
+	uint rxbuf;
+	uint reserved1[2];
+
+	/* 0x020 */
+	uint reserved2[56];
+
+	/* 0x100 */
+	u16 cap_length;
+	u16 hci_version;
+	uint hcs_params;
+	uint hcc_params;
+	uint reserved3[5];
+
+	/* 0x120 */
+	uint dci_version;
+	uint dcc_params;
+	uint reserved4[2];
+
+	/* 0x130 */
+	uint usb_cmd;
+	uint usb_sts;
+	uint usb_intr;
+	uint frindex;
+
+	/* 0x140 */
+	uint reserved5;
+	uint periodic_list_base;
+	uint async_list_addr;
+	uint reserved5_1;
+
+	/* 0x150 */
+	uint burst_size;
+	uint tx_fill_tuning;
+	uint reserved6;
+	uint icusb_ctrl;
+
+	/* 0x160 */
+	uint ulpi_viewport;
+	uint reserved7[3];
+
+	/* 0x170 */
+	uint reserved;
+	uint port_sc1;
+	uint reserved8[6];
+
+	/* 0x190 */
+	uint reserved9[8];
+
+	/* 0x1b0 */
+	uint reserved10;
+	uint hostpc1_devlc;
+	uint reserved10_1[2];
+
+	/* 0x1c0 */
+	uint reserved10_2[4];
+
+	/* 0x1d0 */
+	uint reserved10_3[4];
+
+	/* 0x1e0 */
+	uint reserved10_4[4];
+
+	/* 0x1f0 */
+	uint reserved10_5;
+	uint otgsc;
+	uint usb_mode;
+	uint reserved10_6;
+
+	/* 0x200 */
+	uint endpt_nak;
+	uint endpt_nak_enable;
+	uint endpt_setup_stat;
+	uint reserved11_1[0x7D];
+
+	/* 0x400 */
+	uint susp_ctrl;
+	uint phy_vbus_sensors;
+	uint phy_vbus_wakeup_id;
+	uint phy_alt_vbus_sys;
+
+	/* 0x410 */
+	uint usb1_legacy_ctrl;
+	uint reserved12[3];
+
+	/* 0x420 */
+	uint reserved13[56];
+
+	/* 0x500 */
+	uint reserved14[64 * 3];
+
+	/* 0x800 */
+	uint utmip_pll_cfg0;
+	uint utmip_pll_cfg1;
+	uint utmip_xcvr_cfg0;
+	uint utmip_bias_cfg0;
+
+	/* 0x810 */
+	uint utmip_hsrx_cfg0;
+	uint utmip_hsrx_cfg1;
+	uint utmip_fslsrx_cfg0;
+	uint utmip_fslsrx_cfg1;
+
+	/* 0x820 */
+	uint utmip_tx_cfg0;
+	uint utmip_misc_cfg0;
+	uint utmip_misc_cfg1;
+	uint utmip_debounce_cfg0;
+
+	/* 0x830 */
+	uint utmip_bat_chrg_cfg0;
+	uint utmip_spare_cfg0;
+	uint utmip_xcvr_cfg1;
+	uint utmip_bias_cfg1;
+};
+
+/* USB2D_HOSTPC1_DEVLC_0 */
+#define PTS_SHIFT				29
+#define PTS_MASK				(0x7U << PTS_SHIFT)
+
+#define STS					(1 << 28)
+#endif /* _TEGRA114_USB_H_ */
diff --git a/arch/arm/include/asm/arch-tegra20/usb.h b/arch/arm/include/asm/arch-tegra20/usb.h
new file mode 100644
index 0000000..3d94cc7
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra20/usb.h
@@ -0,0 +1,155 @@ 
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (c) 2013 NVIDIA Corporation
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _TEGRA20_USB_H_
+#define _TEGRA20_USB_H_
+
+/* USB Controller (USBx_CONTROLLER_) regs */
+struct usb_ctlr {
+	/* 0x000 */
+	uint id;
+	uint reserved0;
+	uint host;
+	uint device;
+
+	/* 0x010 */
+	uint txbuf;
+	uint rxbuf;
+	uint reserved1[2];
+
+	/* 0x020 */
+	uint reserved2[56];
+
+	/* 0x100 */
+	u16 cap_length;
+	u16 hci_version;
+	uint hcs_params;
+	uint hcc_params;
+	uint reserved3[5];
+
+	/* 0x120 */
+	uint dci_version;
+	uint dcc_params;
+	uint reserved4[6];
+
+	/* 0x140 */
+	uint usb_cmd;
+	uint usb_sts;
+	uint usb_intr;
+	uint frindex;
+
+	/* 0x150 */
+	uint reserved5;
+	uint periodic_list_base;
+	uint async_list_addr;
+	uint async_tt_sts;
+
+	/* 0x160 */
+	uint burst_size;
+	uint tx_fill_tuning;
+	uint reserved6;   /* is this port_sc1 on some controllers? */
+	uint icusb_ctrl;
+
+	/* 0x170 */
+	uint ulpi_viewport;
+	uint reserved7;
+	uint endpt_nak;
+	uint endpt_nak_enable;
+
+	/* 0x180 */
+	uint reserved;
+	uint port_sc1;
+	uint reserved8[6];
+
+	/* 0x1a0 */
+	uint reserved9;
+	uint otgsc;
+	uint usb_mode;
+	uint endpt_setup_stat;
+
+	/* 0x1b0 */
+	uint reserved10[20];
+
+	/* 0x200 */
+	uint reserved11[0x80];
+
+	/* 0x400 */
+	uint susp_ctrl;
+	uint phy_vbus_sensors;
+	uint phy_vbus_wakeup_id;
+	uint phy_alt_vbus_sys;
+
+	/* 0x410 */
+	uint usb1_legacy_ctrl;
+	uint reserved12[4];
+
+	/* 0x424 */
+	uint ulpi_timing_ctrl_0;
+	uint ulpi_timing_ctrl_1;
+	uint reserved13[53];
+
+	/* 0x500 */
+	uint reserved14[64 * 3];
+
+	/* 0x800 */
+	uint utmip_pll_cfg0;
+	uint utmip_pll_cfg1;
+	uint utmip_xcvr_cfg0;
+	uint utmip_bias_cfg0;
+
+	/* 0x810 */
+	uint utmip_hsrx_cfg0;
+	uint utmip_hsrx_cfg1;
+	uint utmip_fslsrx_cfg0;
+	uint utmip_fslsrx_cfg1;
+
+	/* 0x820 */
+	uint utmip_tx_cfg0;
+	uint utmip_misc_cfg0;
+	uint utmip_misc_cfg1;
+	uint utmip_debounce_cfg0;
+
+	/* 0x830 */
+	uint utmip_bat_chrg_cfg0;
+	uint utmip_spare_cfg0;
+	uint utmip_xcvr_cfg1;
+	uint utmip_bias_cfg1;
+};
+
+/* USB2_IF_ULPI_TIMING_CTRL_0 */
+#define ULPI_OUTPUT_PINMUX_BYP			(1 << 10)
+#define ULPI_CLKOUT_PINMUX_BYP			(1 << 11)
+
+/* USB2_IF_ULPI_TIMING_CTRL_1 */
+#define ULPI_DATA_TRIMMER_LOAD			(1 << 0)
+#define ULPI_DATA_TRIMMER_SEL(x)		(((x) & 0x7) << 1)
+#define ULPI_STPDIRNXT_TRIMMER_LOAD		(1 << 16)
+#define ULPI_STPDIRNXT_TRIMMER_SEL(x)	(((x) & 0x7) << 17)
+#define ULPI_DIR_TRIMMER_LOAD			(1 << 24)
+#define ULPI_DIR_TRIMMER_SEL(x)			(((x) & 0x7) << 25)
+
+/* PORTSC, USB2, USB3 */
+#define PTS_SHIFT		30
+#define PTS_MASK		(3U << PTS_SHIFT)
+
+#define STS			(1 << 29)
+#endif /* _TEGRA20_USB_H_ */
diff --git a/arch/arm/include/asm/arch-tegra30/usb.h b/arch/arm/include/asm/arch-tegra30/usb.h
new file mode 100644
index 0000000..ab9b760
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra30/usb.h
@@ -0,0 +1,168 @@ 
+/*
+ * Copyright (c) 2011 The Chromium OS Authors.
+ * Copyright (c) 2013 NVIDIA Corporation
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _TEGRA30_USB_H_
+#define _TEGRA30_USB_H_
+
+/* USB Controller (USBx_CONTROLLER_) regs */
+struct usb_ctlr {
+	/* 0x000 */
+	uint id;
+	uint reserved0;
+	uint host;
+	uint device;
+
+	/* 0x010 */
+	uint txbuf;
+	uint rxbuf;
+	uint reserved1[2];
+
+	/* 0x020 */
+	uint reserved2[56];
+
+	/* 0x100 */
+	u16 cap_length;
+	u16 hci_version;
+	uint hcs_params;
+	uint hcc_params;
+	uint reserved3[5];
+
+	/* 0x120 */
+	uint dci_version;
+	uint dcc_params;
+	uint reserved4[2];
+
+	/* 0x130 */
+	uint usb_cmd;
+	uint usb_sts;
+	uint usb_intr;
+	uint frindex;
+
+	/* 0x140 */
+	uint reserved5;
+	uint periodic_list_base;
+	uint async_list_addr;
+	uint reserved5_1;
+
+	/* 0x150 */
+	uint burst_size;
+	uint tx_fill_tuning;
+	uint reserved6;
+	uint icusb_ctrl;
+
+	/* 0x160 */
+	uint ulpi_viewport;
+	uint reserved7[3];
+
+	/* 0x170 */
+	uint reserved;
+	uint port_sc1;
+	uint reserved8[6];
+
+	/* 0x190 */
+	uint reserved9[8];
+
+	/* 0x1b0 */
+	uint reserved10;
+	uint hostpc1_devlc;
+	uint reserved10_1[2];
+
+	/* 0x1c0 */
+	uint reserved10_2[4];
+
+	/* 0x1d0 */
+	uint reserved10_3[4];
+
+	/* 0x1e0 */
+	uint reserved10_4[4];
+
+	/* 0x1f0 */
+	uint reserved10_5;
+	uint otgsc;
+	uint usb_mode;
+	uint reserved10_6;
+
+	/* 0x200 */
+	uint endpt_nak;
+	uint endpt_nak_enable;
+	uint endpt_setup_stat;
+	uint reserved11_1[0x7D];
+
+	/* 0x400 */
+	uint susp_ctrl;
+	uint phy_vbus_sensors;
+	uint phy_vbus_wakeup_id;
+	uint phy_alt_vbus_sys;
+
+	/* 0x410 */
+	uint usb1_legacy_ctrl;
+	uint reserved12[3];
+
+	/* 0x420 */
+	uint reserved13[56];
+
+	/* 0x500 */
+	uint reserved14[64 * 3];
+
+	/* 0x800 */
+	uint utmip_pll_cfg0;
+	uint utmip_pll_cfg1;
+	uint utmip_xcvr_cfg0;
+	uint utmip_bias_cfg0;
+
+	/* 0x810 */
+	uint utmip_hsrx_cfg0;
+	uint utmip_hsrx_cfg1;
+	uint utmip_fslsrx_cfg0;
+	uint utmip_fslsrx_cfg1;
+
+	/* 0x820 */
+	uint utmip_tx_cfg0;
+	uint utmip_misc_cfg0;
+	uint utmip_misc_cfg1;
+	uint utmip_debounce_cfg0;
+
+	/* 0x830 */
+	uint utmip_bat_chrg_cfg0;
+	uint utmip_spare_cfg0;
+	uint utmip_xcvr_cfg1;
+	uint utmip_bias_cfg1;
+};
+
+/* USB2_IF_ULPI_TIMING_CTRL_0 */
+#define ULPI_OUTPUT_PINMUX_BYP			(1 << 10)
+#define ULPI_CLKOUT_PINMUX_BYP			(1 << 11)
+
+/* USB2_IF_ULPI_TIMING_CTRL_1 */
+#define ULPI_DATA_TRIMMER_LOAD			(1 << 0)
+#define ULPI_DATA_TRIMMER_SEL(x)		(((x) & 0x7) << 1)
+#define ULPI_STPDIRNXT_TRIMMER_LOAD		(1 << 16)
+#define ULPI_STPDIRNXT_TRIMMER_SEL(x)	(((x) & 0x7) << 17)
+#define ULPI_DIR_TRIMMER_LOAD			(1 << 24)
+#define ULPI_DIR_TRIMMER_SEL(x)			(((x) & 0x7) << 25)
+
+/* USB2D_HOSTPC1_DEVLC_0 */
+#define PTS_SHIFT				29
+#define PTS_MASK				(0x7U << PTS_SHIFT)
+
+#define STS					(1 << 28)
+#endif /* _TEGRA30_USB_H_ */
diff --git a/board/nvidia/common/board.c b/board/nvidia/common/board.c
index 8d7a227..f0f81c9 100644
--- a/board/nvidia/common/board.c
+++ b/board/nvidia/common/board.c
@@ -46,7 +46,7 @@ 
 #include <asm/arch/emc.h>
 #endif
 #ifdef CONFIG_USB_EHCI_TEGRA
-#include <asm/arch-tegra/usb.h>
+#include <asm/arch/usb.h>
 #endif
 #ifdef CONFIG_TEGRA_MMC
 #include <asm/arch-tegra/tegra_mmc.h>
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 554145a..4e73915 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -1,6 +1,6 @@ 
 /*
  * Copyright (c) 2011 The Chromium OS Authors.
- * Copyright (c) 2009-2012 NVIDIA Corporation
+ * Copyright (c) 2009-2013 NVIDIA Corporation
  * Copyright (c) 2013 Lucas Stach
  *
  * See file CREDITS for list of people who contributed to this
@@ -28,6 +28,8 @@ 
 #include <asm-generic/gpio.h>
 #include <asm/arch/clock.h>
 #include <asm/arch-tegra/usb.h>
+#include <asm/arch-tegra/clk_rst.h>
+#include <asm/arch/usb.h>
 #include <usb.h>
 #include <usb/ulpi.h>
 #include <libfdt.h>
@@ -35,6 +37,11 @@ 
 
 #include "ehci.h"
 
+#define USB1_ADDR_MASK	0xFFFF0000
+
+#define HOSTPC1_DEVLC	0x84
+#define HOSTPC1_PSPD(x)		(((x) >> 25) & 0x3)
+
 #ifdef CONFIG_USB_ULPI
 	#ifndef CONFIG_USB_ULPI_VIEWPORT
 	#error	"To use CONFIG_USB_ULPI on Tegra Boards you have to also \
@@ -87,6 +94,9 @@  struct fdt_usb {
 
 static struct fdt_usb port[USB_PORTS_MAX];	/* List of valid USB ports */
 static unsigned port_count;			/* Number of available ports */
+static u32 port_clear_csc; /* Port that needs to clear CSC after Port Reset */
+static unsigned is_T30_compatible;
+static unsigned is_T114_compatible;
 
 /*
  * This table has USB timing parameters for each Oscillator frequency we
@@ -129,7 +139,7 @@  static unsigned port_count;			/* Number of available ports */
  *
  * 4. The 20 microsecond delay after bias cell operation.
  */
-static const unsigned usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
+static const unsigned T20_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
 	/* DivN, DivM, DivP, CPCON, LFCON, Delays             Debounce, Bias */
 	{ 0x3C0, 0x0D, 0x00, 0xC,   0,  0x02, 0x33, 0x05, 0x7F, 0x7EF4, 5 },
 	{ 0x0C8, 0x04, 0x00, 0x3,   0,  0x03, 0x4B, 0x06, 0xBB, 0xBB80, 7 },
@@ -137,6 +147,22 @@  static const unsigned usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
 	{ 0x3C0, 0x1A, 0x00, 0xC,   0,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 }
 };
 
+static const unsigned T30_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
+	/* DivN, DivM, DivP, CPCON, LFCON, Delays             Debounce, Bias */
+	{ 0x3C0, 0x0D, 0x00, 0xC,   1,  0x02, 0x33, 0x09, 0x7F, 0x7EF4, 5 },
+	{ 0x0C8, 0x04, 0x00, 0x3,   0,  0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 7 },
+	{ 0x3C0, 0x0C, 0x00, 0xC,   1,  0x02, 0x2F, 0x08, 0x76, 0x7530, 5 },
+	{ 0x3C0, 0x1A, 0x00, 0xC,   1,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 }
+};
+
+static const unsigned T114_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = {
+	/* DivN, DivM, DivP, CPCON, LFCON, Delays             Debounce, Bias */
+	{ 0x3C0, 0x0D, 0x00, 0xC,   2,  0x02, 0x33, 0x09, 0x7F, 0x7EF4, 6 },
+	{ 0x0C8, 0x04, 0x00, 0x3,   2,  0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 8 },
+	{ 0x3C0, 0x0C, 0x00, 0xC,   2,  0x02, 0x2F, 0x08, 0x76, 0x7530, 5 },
+	{ 0x3C0, 0x1A, 0x00, 0xC,   2,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 0xB }
+};
+
 /* UTMIP Idle Wait Delay */
 static const u8 utmip_idle_wait_delay = 17;
 
@@ -156,13 +182,52 @@  static const u8 utmip_hs_sync_start_delay = 9;
 void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
 {
 	mdelay(50);
-	if (((u32) status_reg & TEGRA_USB_ADDR_MASK) != TEGRA_USB1_BASE)
+	/* This is to avoid PORT_ENABLE bit to be cleared in "ehci-hcd.c". */
+	if (is_T30_compatible)
+		*reg |= EHCI_PS_PE;
+
+	if (((u32)status_reg & TEGRA_USB_ADDR_MASK) != port_clear_csc)
 		return;
 	/* For EHCI_PS_CSC to be cleared in ehci_hcd.c */
 	if (ehci_readl(status_reg) & EHCI_PS_CSC)
 		*reg |= EHCI_PS_CSC;
 }
 
+/*
+ * This ehci_set_usbmode overrides the weak function ehci_set_usbmode
+ * in "ehci-hcd.c".
+ */
+void ehci_set_usbmode(int index)
+{
+	struct fdt_usb *config;
+	struct usb_ctlr *usbctlr;
+	uint32_t tmp;
+
+	config = &port[index];
+	usbctlr = config->reg;
+
+	tmp = ehci_readl(&usbctlr->usb_mode);
+	tmp |= USBMODE_CM_HC;
+	ehci_writel(&usbctlr->usb_mode, tmp);
+}
+
+/*
+ * This ehci_get_port_speed overrides the weak function ehci_get_port_speed
+ * in "ehci-hcd.c".
+ */
+int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+{
+	uint32_t tmp;
+	uint32_t *reg_ptr;
+
+	if (is_T30_compatible) {
+		reg_ptr = (uint32_t *)((u8 *)&hcor->or_usbcmd + HOSTPC1_DEVLC);
+		tmp = ehci_readl(reg_ptr);
+		return HOSTPC1_PSPD(tmp);
+	} else
+		return PORTSC_PSPD(reg);
+}
+
 /* Put the port into host mode */
 static void set_host_mode(struct fdt_usb *config)
 {
@@ -209,6 +274,22 @@  void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr)
 		setbits_le32(&usbctlr->susp_ctrl, UTMIP_PHY_ENB);
 }
 
+static const unsigned *get_pll_timing(void)
+{
+	const unsigned *timing;
+
+	if (is_T30_compatible) {
+		if (is_T114_compatible)
+			timing = T114_usb_pll[clock_get_osc_freq()];
+		else
+			timing = T30_usb_pll[clock_get_osc_freq()];
+	} else {
+		timing = T20_usb_pll[clock_get_osc_freq()];
+	}
+
+	return timing;
+}
+
 /* set up the UTMI USB controller with the parameters provided */
 static int init_utmi_usb_controller(struct fdt_usb *config)
 {
@@ -216,6 +297,8 @@  static int init_utmi_usb_controller(struct fdt_usb *config)
 	int loop_count;
 	const unsigned *timing;
 	struct usb_ctlr *usbctlr = config->reg;
+	struct clk_rst_ctlr *clkrst;
+	struct usb_ctlr *usb1ctlr;
 
 	clock_enable(config->periph_id);
 
@@ -232,35 +315,97 @@  static int init_utmi_usb_controller(struct fdt_usb *config)
 	 * To Use the A Session Valid for cable detection logic, VBUS_WAKEUP
 	 * mux must be switched to actually use a_sess_vld threshold.
 	 */
-	if (fdt_gpio_isvalid(&config->vbus_gpio)) {
+	if (config->dr_mode == DR_MODE_OTG &&
+	    fdt_gpio_isvalid(&config->vbus_gpio))
 		clrsetbits_le32(&usbctlr->usb1_legacy_ctrl,
 			VBUS_SENSE_CTL_MASK,
 			VBUS_SENSE_CTL_A_SESS_VLD << VBUS_SENSE_CTL_SHIFT);
-	}
 
 	/*
 	 * PLL Delay CONFIGURATION settings. The following parameters control
 	 * the bring up of the plls.
 	 */
-	timing = usb_pll[clock_get_osc_freq()];
+	timing = get_pll_timing();
 
-	val = readl(&usbctlr->utmip_misc_cfg1);
-	clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK,
-		timing[PARAM_STABLE_COUNT] << UTMIP_PLLU_STABLE_COUNT_SHIFT);
-	clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK,
-		timing[PARAM_ACTIVE_DELAY_COUNT] <<
-			UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT);
-	writel(val, &usbctlr->utmip_misc_cfg1);
+	if (!is_T30_compatible) {
+		val = readl(&usbctlr->utmip_misc_cfg1);
+		clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK,
+				timing[PARAM_STABLE_COUNT] <<
+				UTMIP_PLLU_STABLE_COUNT_SHIFT);
+		clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK,
+				timing[PARAM_ACTIVE_DELAY_COUNT] <<
+				UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT);
+		writel(val, &usbctlr->utmip_misc_cfg1);
 
-	/* Set PLL enable delay count and crystal frequency count */
-	val = readl(&usbctlr->utmip_pll_cfg1);
-	clrsetbits_le32(&val, UTMIP_PLLU_ENABLE_DLY_COUNT_MASK,
-		timing[PARAM_ENABLE_DELAY_COUNT] <<
-			UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT);
-	clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK,
-		timing[PARAM_XTAL_FREQ_COUNT] <<
-			UTMIP_XTAL_FREQ_COUNT_SHIFT);
-	writel(val, &usbctlr->utmip_pll_cfg1);
+		/* Set PLL enable delay count and crystal frequency count */
+		val = readl(&usbctlr->utmip_pll_cfg1);
+		clrsetbits_le32(&val, UTMIP_PLLU_ENABLE_DLY_COUNT_MASK,
+				timing[PARAM_ENABLE_DELAY_COUNT] <<
+				UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT);
+		clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK,
+				timing[PARAM_XTAL_FREQ_COUNT] <<
+				UTMIP_XTAL_FREQ_COUNT_SHIFT);
+		writel(val, &usbctlr->utmip_pll_cfg1);
+	} else {
+		clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
+
+		val = readl(&clkrst->crc_utmip_pll_cfg2);
+		clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK,
+				timing[PARAM_STABLE_COUNT] <<
+				UTMIP_PLLU_STABLE_COUNT_SHIFT);
+		clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK,
+				timing[PARAM_ACTIVE_DELAY_COUNT] <<
+				UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT);
+		writel(val, &clkrst->crc_utmip_pll_cfg2);
+
+		/* Set PLL enable delay count and crystal frequency count */
+		val = readl(&clkrst->crc_utmip_pll_cfg1);
+		clrsetbits_le32(&val, UTMIP_PLLU_ENABLE_DLY_COUNT_MASK,
+				timing[PARAM_ENABLE_DELAY_COUNT] <<
+				UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT);
+		clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK,
+				timing[PARAM_XTAL_FREQ_COUNT] <<
+				UTMIP_XTAL_FREQ_COUNT_SHIFT);
+		writel(val, &clkrst->crc_utmip_pll_cfg1);
+
+		/* Disable Power Down state for PLL */
+		clrbits_le32(&clkrst->crc_utmip_pll_cfg1,
+			     PLLU_POWERDOWN | PLL_ENABLE_POWERDOWN |
+			     PLL_ACTIVE_POWERDOWN);
+
+		/* Recommended PHY settings for EYE diagram */
+		val = readl(&usbctlr->utmip_xcvr_cfg0);
+		clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MASK,
+				0x4 << UTMIP_XCVR_SETUP_SHIFT);
+		clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MSB_MASK,
+				0x3 << UTMIP_XCVR_SETUP_MSB_SHIFT);
+		clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW_MSB_MASK,
+				0x8 << UTMIP_XCVR_HSSLEW_MSB_SHIFT);
+		writel(val, &usbctlr->utmip_xcvr_cfg0);
+		clrsetbits_le32(&usbctlr->utmip_xcvr_cfg1,
+				UTMIP_XCVR_TERM_RANGE_ADJ_MASK,
+				0x7 << UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT);
+
+		/* Some registers can be controlled from USB1 only. */
+		if (config->periph_id != PERIPH_ID_USBD) {
+			clock_enable(PERIPH_ID_USBD);
+			/* Disable Reset if in Reset state */
+			reset_set_enable(PERIPH_ID_USBD, 0);
+		}
+		usb1ctlr = (struct usb_ctlr *)
+			((u32)config->reg & USB1_ADDR_MASK);
+		val = readl(&usb1ctlr->utmip_bias_cfg0);
+		setbits_le32(&val, UTMIP_HSDISCON_LEVEL_MSB);
+		clrsetbits_le32(&val, UTMIP_HSDISCON_LEVEL_MASK,
+				0x1 << UTMIP_HSDISCON_LEVEL_SHIFT);
+		clrsetbits_le32(&val, UTMIP_HSSQUELCH_LEVEL_MASK,
+				0x2 << UTMIP_HSSQUELCH_LEVEL_SHIFT);
+		writel(val, &usb1ctlr->utmip_bias_cfg0);
+
+		/* Miscellaneous setting mentioned in Programming Guide */
+		clrbits_le32(&usbctlr->utmip_misc_cfg0,
+			     UTMIP_SUSPEND_EXIT_ON_EDGE);
+	}
 
 	/* Setting the tracking length time */
 	clrsetbits_le32(&usbctlr->utmip_bias_cfg1,
@@ -308,6 +453,14 @@  static int init_utmi_usb_controller(struct fdt_usb *config)
 	/* Resuscitate crystal clock by setting UTMIP_PHY_XTAL_CLOCKEN */
 	setbits_le32(&usbctlr->utmip_misc_cfg1, UTMIP_PHY_XTAL_CLOCKEN);
 
+	if (is_T30_compatible) {
+		if (config->periph_id == PERIPH_ID_USBD)
+			clrbits_le32(&clkrst->crc_utmip_pll_cfg2,
+				     UTMIP_FORCE_PD_SAMP_A_POWERDOWN);
+		if (config->periph_id == PERIPH_ID_USB3)
+			clrbits_le32(&clkrst->crc_utmip_pll_cfg2,
+				     UTMIP_FORCE_PD_SAMP_C_POWERDOWN);
+	}
 	/* Finished the per-controller init. */
 
 	/* De-assert UTMIP_RESET to bring out of reset. */
@@ -336,6 +489,18 @@  static int init_utmi_usb_controller(struct fdt_usb *config)
 	clrbits_le32(&usbctlr->utmip_xcvr_cfg1, UTMIP_FORCE_PDDISC_POWERDOWN |
 		UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN);
 
+	if (is_T30_compatible) {
+		/*
+		 * BIAS Pad Power Down is common among all 3 USB
+		 * controllers and can be controlled from USB1 only.
+		 */
+		usb1ctlr = (struct usb_ctlr *)
+			((u32)config->reg & USB1_ADDR_MASK);
+		clrbits_le32(&usb1ctlr->utmip_bias_cfg0, UTMIP_BIASPD);
+		udelay(25);
+		clrbits_le32(&usb1ctlr->utmip_bias_cfg1,
+			     UTMIP_FORCE_PDTRK_POWERDOWN);
+	}
 	return 0;
 }
 
@@ -438,7 +603,7 @@  static void config_clock(const u32 timing[])
 		timing[PARAM_CPCON], timing[PARAM_LFCON]);
 }
 
-int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
+static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 {
 	const char *phy, *mode;
 
@@ -466,6 +631,8 @@  int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 	config->enabled = fdtdec_get_is_enabled(blob, node);
 	config->has_legacy_mode = fdtdec_get_bool(blob, node,
 						  "nvidia,has-legacy-mode");
+	if (config->has_legacy_mode)
+		port_clear_csc = (u32) config->reg;
 	config->periph_id = clock_decode_periph_id(blob, node);
 	if (config->periph_id == PERIPH_ID_NONE) {
 		debug("%s: Missing/invalid peripheral ID\n", __func__);
@@ -483,20 +650,22 @@  int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 	return 0;
 }
 
-int board_usb_init(const void *blob)
+/*
+ * process_usb_nodes() - Process a list of USB nodes, adding them to our list
+ *			of USB ports.
+ * @blob:	fdt blob
+ * @node_list:	list of nodes to process (any <=0 are ignored)
+ * @count:	number of nodes to process
+ *
+ * Return:	0 - ok, -1 - error
+ */
+static int process_usb_nodes(const void *blob, int node_list[], int count)
 {
 	struct fdt_usb config;
-	enum clock_osc_freq freq;
-	int node_list[USB_PORTS_MAX];
-	int node, count, i;
-
-	/* Set up the USB clocks correctly based on our oscillator frequency */
-	freq = clock_get_osc_freq();
-	config_clock(usb_pll[freq]);
+	int node, i;
+	int clk_done = 0;
 
-	/* count may return <0 on error */
-	count = fdtdec_find_aliases_for_id(blob, "usb",
-			COMPAT_NVIDIA_TEGRA20_USB, node_list, USB_PORTS_MAX);
+	port_count = 0;
 	for (i = 0; i < count; i++) {
 		if (port_count == USB_PORTS_MAX) {
 			printf("tegrausb: Cannot register more than %d ports\n",
@@ -513,6 +682,10 @@  int board_usb_init(const void *blob)
 			      fdt_get_name(blob, node, NULL));
 			return -1;
 		}
+		if (!clk_done) {
+			config_clock(get_pll_timing());
+			clk_done = 1;
+		}
 		config.initialized = 0;
 
 		/* add new USB port to the list of available ports */
@@ -522,6 +695,48 @@  int board_usb_init(const void *blob)
 	return 0;
 }
 
+int board_usb_init(const void *blob)
+{
+	int node_list[USB_PORTS_MAX];
+	int count, err = 0;
+
+	is_T30_compatible = 0;
+	is_T114_compatible = 0;
+
+	/* count may return <0 on error */
+	count = fdtdec_find_aliases_for_id(blob, "usb",
+			COMPAT_NVIDIA_TEGRA20_USB, node_list, USB_PORTS_MAX);
+	if (count) {
+		err = process_usb_nodes(blob, node_list, count);
+		if (err)
+			printf("%s: Error processing T20 USB node!\n",
+			       __func__);
+		return err;
+	}
+	count = fdtdec_find_aliases_for_id(blob, "usb",
+			COMPAT_NVIDIA_TEGRA114_USB, node_list, USB_PORTS_MAX);
+	if (count)
+		is_T114_compatible = 1;
+	else
+		count = fdtdec_find_aliases_for_id(blob, "usb",
+			COMPAT_NVIDIA_TEGRA30_USB, node_list, USB_PORTS_MAX);
+	if (count) {
+		/* T114 is also mostly compatible to T30 */
+		is_T30_compatible = 1;
+		err = process_usb_nodes(blob, node_list, count);
+		if (err) {
+			if (is_T114_compatible)
+				printf("%s: Error processing T114 USB node!\n",
+				       __func__);
+			else
+				printf("%s: Error processing T30 USB node!\n",
+				       __func__);
+		}
+	}
+
+	return err;
+}
+
 /**
  * Start up the given port number (ports are numbered from 0 on each board).
  * This returns values for the appropriate hccr and hcor addresses to use for
@@ -564,6 +779,20 @@  success:
 	usbctlr = config->reg;
 	*hccr = (struct ehci_hccr *)&usbctlr->cap_length;
 	*hcor = (struct ehci_hcor *)&usbctlr->usb_cmd;
+
+	if (is_T30_compatible) {
+		/* Set to Host mode after Controller Reset was done */
+		clrsetbits_le32(&usbctlr->usb_mode, USBMODE_CM_HC,
+				USBMODE_CM_HC);
+		/* Select UTMI parallel interface after setting host mode */
+		if (config->utmi) {
+			clrsetbits_le32((char *)&usbctlr->usb_cmd +
+					HOSTPC1_DEVLC, PTS_MASK,
+					PTS_UTMI << PTS_SHIFT);
+			clrbits_le32((char *)&usbctlr->usb_cmd +
+				     HOSTPC1_DEVLC, STS);
+		}
+	}
 	return 0;
 }