diff mbox

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

Message ID 1367227275-7713-3-git-send-email-jilin@nvidia.com
State Superseded
Delegated to: Tom Warren
Headers show

Commit Message

Jim Lin April 29, 2013, 9:21 a.m. UTC
Tegra30 and Tegra114 are compatible except
1. T30 takes 55 ms to finish Port Reset. T114 takes
   50 ms.
2. PLL parameters

Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and Tegra114 Dalmore
platforms. All works well.

Signed-off-by: Jim Lin <jilin@nvidia.com>
---
 arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
 arch/arm/include/asm/arch-tegra/usb.h      |  249 ------------------
 arch/arm/include/asm/arch-tegra114/tegra.h |    1 +
 arch/arm/include/asm/arch-tegra114/usb.h   |  287 +++++++++++++++++++++
 arch/arm/include/asm/arch-tegra20/usb.h    |  279 +++++++++++++++++++++
 arch/arm/include/asm/arch-tegra30/usb.h    |  294 ++++++++++++++++++++++
 board/nvidia/common/board.c                |    2 +-
 drivers/usb/host/ehci-hcd.c                |   40 ++-
 drivers/usb/host/ehci-tegra.c              |  376 ++++++++++++++++++++-------
 9 files changed, 1178 insertions(+), 360 deletions(-)
 delete mode 100644 arch/arm/include/asm/arch-tegra/usb.h
 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

Comments

Marek Vasut April 29, 2013, 11:46 p.m. UTC | #1
Dear Jim Lin,

> Tegra30 and Tegra114 are compatible except
> 1. T30 takes 55 ms to finish Port Reset. T114 takes
>    50 ms.
> 2. PLL parameters
> 
> Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and Tegra114 Dalmore
> platforms. All works well.
> 
> Signed-off-by: Jim Lin <jilin@nvidia.com>
> ---
>  arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
>  arch/arm/include/asm/arch-tegra/usb.h      |  249 ------------------
>  arch/arm/include/asm/arch-tegra114/tegra.h |    1 +
>  arch/arm/include/asm/arch-tegra114/usb.h   |  287 +++++++++++++++++++++
>  arch/arm/include/asm/arch-tegra20/usb.h    |  279 +++++++++++++++++++++
>  arch/arm/include/asm/arch-tegra30/usb.h    |  294 ++++++++++++++++++++++

Do we now have three copies of the same stuff ?

[...]
Best regards,
Marek Vasut
Marek Vasut April 30, 2013, 5:09 p.m. UTC | #2
Dear Tom Warren,

> Marek,
> 
> > -----Original Message-----
> > From: Marek Vasut [mailto:marex@denx.de]
> > Sent: Monday, April 29, 2013 4:47 PM
> > To: Jim Lin
> > Cc: u-boot@lists.denx.de; Tom Warren; Stephen Warren
> > Subject: Re: [PATCH 2/3] ARM: Tegra: USB: Add driver support for
> > Tegra30/Tegra114
> > 
> > Dear Jim Lin,
> > 
> > > Tegra30 and Tegra114 are compatible except 1. T30 takes 55 ms to
> > > finish Port Reset. T114 takes
> > > 
> > >    50 ms.
> > > 
> > > 2. PLL parameters
> > > 
> > > Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and Tegra114
> > > Dalmore platforms. All works well.
> > > 
> > > Signed-off-by: Jim Lin <jilin@nvidia.com>
> > > ---
> > > 
> > >  arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
> > >  arch/arm/include/asm/arch-tegra/usb.h      |  249 ------------------
> > >  arch/arm/include/asm/arch-tegra114/tegra.h |    1 +
> > >  arch/arm/include/asm/arch-tegra114/usb.h   |  287
> > 
> > +++++++++++++++++++++
> > 
> > >  arch/arm/include/asm/arch-tegra20/usb.h    |  279
> > 
> > +++++++++++++++++++++
> > 
> > >  arch/arm/include/asm/arch-tegra30/usb.h    |  294
> > 
> > ++++++++++++++++++++++
> > 
> > Do we now have three copies of the same stuff ?
> 
> When only T20 was supported (for USB), there was a common
> (arch-tegra/usb.h) header. That's been moved to arch-tegra20/usb.h, and
> (unfortunately) there are 2 new usb.h files due to the HW differences in
> the registers between T20 and T30/T114.  I don't see any easy way to have
> a common usb.h file for Tegra w/o adding ugly #ifdefs to the USB register
> space struct(s).

Thanks for clearing that up.

Best regards,
Marek Vasut
Tom Rini April 30, 2013, 5:20 p.m. UTC | #3
On Tue, Apr 30, 2013 at 09:21:18AM -0700, Tom Warren wrote:

> Marek,
> 
> > -----Original Message-----
> > From: Marek Vasut [mailto:marex@denx.de]
> > Sent: Monday, April 29, 2013 4:47 PM
> > To: Jim Lin
> > Cc: u-boot@lists.denx.de; Tom Warren; Stephen Warren
> > Subject: Re: [PATCH 2/3] ARM: Tegra: USB: Add driver support for
> > Tegra30/Tegra114
> > 
> > Dear Jim Lin,
> > 
> > > Tegra30 and Tegra114 are compatible except 1. T30 takes 55 ms to
> > > finish Port Reset. T114 takes
> > >    50 ms.
> > > 2. PLL parameters
> > >
> > > Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and Tegra114
> > > Dalmore platforms. All works well.
> > >
> > > Signed-off-by: Jim Lin <jilin@nvidia.com>
> > > ---
> > >  arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
> > >  arch/arm/include/asm/arch-tegra/usb.h      |  249 ------------------
> > >  arch/arm/include/asm/arch-tegra114/tegra.h |    1 +
> > >  arch/arm/include/asm/arch-tegra114/usb.h   |  287
> > +++++++++++++++++++++
> > >  arch/arm/include/asm/arch-tegra20/usb.h    |  279
> > +++++++++++++++++++++
> > >  arch/arm/include/asm/arch-tegra30/usb.h    |  294
> > ++++++++++++++++++++++
> > 
> > Do we now have three copies of the same stuff ?
> 
> When only T20 was supported (for USB), there was a common
> (arch-tegra/usb.h) header. That's been moved to arch-tegra20/usb.h,
> and (unfortunately) there are 2 new usb.h files due to the HW
> differences in the registers between T20 and T30/T114.  I don't see
> any easy way to have a common usb.h file for Tegra w/o adding ugly
> #ifdefs to the USB register space struct(s).

Just how different are they?  Are all of the related defines and masks
different too?  Do we have conflicts? Moved registers?  Just conflicting
values?  A quick peek shows '30' and '114' are pretty similar, except
for masks.  Maybe splitting the struct up so you can discard some of the
reserved gaps, run-time checking to see if we can or cannot use a
particular part of the struct?
Tom Warren May 1, 2013, 4:16 p.m. UTC | #4
Tom,


On Tue, Apr 30, 2013 at 10:20 AM, Tom Rini <trini@ti.com> wrote:

> On Tue, Apr 30, 2013 at 09:21:18AM -0700, Tom Warren wrote:
>
> > Marek,
> >
> > > -----Original Message-----
> > > From: Marek Vasut [mailto:marex@denx.de]
> > > Sent: Monday, April 29, 2013 4:47 PM
> > > To: Jim Lin
> > > Cc: u-boot@lists.denx.de; Tom Warren; Stephen Warren
> > > Subject: Re: [PATCH 2/3] ARM: Tegra: USB: Add driver support for
> > > Tegra30/Tegra114
> > >
> > > Dear Jim Lin,
> > >
> > > > Tegra30 and Tegra114 are compatible except 1. T30 takes 55 ms to
> > > > finish Port Reset. T114 takes
> > > >    50 ms.
> > > > 2. PLL parameters
> > > >
> > > > Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and Tegra114
> > > > Dalmore platforms. All works well.
> > > >
> > > > Signed-off-by: Jim Lin <jilin@nvidia.com>
> > > > ---
> > > >  arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
> > > >  arch/arm/include/asm/arch-tegra/usb.h      |  249 ------------------
> > > >  arch/arm/include/asm/arch-tegra114/tegra.h |    1 +
> > > >  arch/arm/include/asm/arch-tegra114/usb.h   |  287
> > > +++++++++++++++++++++
> > > >  arch/arm/include/asm/arch-tegra20/usb.h    |  279
> > > +++++++++++++++++++++
> > > >  arch/arm/include/asm/arch-tegra30/usb.h    |  294
> > > ++++++++++++++++++++++
> > >
> > > Do we now have three copies of the same stuff ?
> >
> > When only T20 was supported (for USB), there was a common
> > (arch-tegra/usb.h) header. That's been moved to arch-tegra20/usb.h,
> > and (unfortunately) there are 2 new usb.h files due to the HW
> > differences in the registers between T20 and T30/T114.  I don't see
> > any easy way to have a common usb.h file for Tegra w/o adding ugly
> > #ifdefs to the USB register space struct(s).
>
> Just how different are they?  Are all of the related defines and masks
> different too?  Do we have conflicts? Moved registers?  Just conflicting
> values?  A quick peek shows '30' and '114' are pretty similar, except
> for masks.  Maybe splitting the struct up so you can discard some of the
> reserved gaps, run-time checking to see if we can or cannot use a
> particular part of the struct?
>

This is really Jim's patchset (and his specialty), but here's what I know
about Tegra USB regs:

T20 had a gap in the registers @ offset 0x130. T30 (and T114) moved the
offset of the command/status/interrupt regs down to fill in this gap, which
dragged all the subsequent registers back 16 bytes. The two SoCs 'families'
sync up again at offset 0x400 and are pretty much equal from there on out
to 0x840.

The defines are probably 90% the same, with some weirdness for the first
USB controller (USB1) and its PTS/STS bits that differs in offset from the
other 2 controllers (again, no clue why the HW guys would do this).

So we could have the 3 different USB headers in the arch-tegraXX area
contain the register structs, and have a common arch-tegra/usb.h that has
the #defines that are the same, and is included in the arch-tegraxx/usb.h
files. That would reduce this down somewhat, without the ugliness of
#ifdefs in the structs.

What do you think?

Tom

>
> --
> Tom
>
Tom Rini May 1, 2013, 4:45 p.m. UTC | #5
On Wed, May 01, 2013 at 09:16:45AM -0700, Tom Warren wrote:
> Tom,
> 
> 
> On Tue, Apr 30, 2013 at 10:20 AM, Tom Rini <trini@ti.com> wrote:
> 
> > On Tue, Apr 30, 2013 at 09:21:18AM -0700, Tom Warren wrote:
> >
> > > Marek,
> > >
> > > > -----Original Message-----
> > > > From: Marek Vasut [mailto:marex@denx.de]
> > > > Sent: Monday, April 29, 2013 4:47 PM
> > > > To: Jim Lin
> > > > Cc: u-boot@lists.denx.de; Tom Warren; Stephen Warren
> > > > Subject: Re: [PATCH 2/3] ARM: Tegra: USB: Add driver support for
> > > > Tegra30/Tegra114
> > > >
> > > > Dear Jim Lin,
> > > >
> > > > > Tegra30 and Tegra114 are compatible except 1. T30 takes 55 ms to
> > > > > finish Port Reset. T114 takes
> > > > >    50 ms.
> > > > > 2. PLL parameters
> > > > >
> > > > > Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and Tegra114
> > > > > Dalmore platforms. All works well.
> > > > >
> > > > > Signed-off-by: Jim Lin <jilin@nvidia.com>
> > > > > ---
> > > > >  arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
> > > > >  arch/arm/include/asm/arch-tegra/usb.h      |  249 ------------------
> > > > >  arch/arm/include/asm/arch-tegra114/tegra.h |    1 +
> > > > >  arch/arm/include/asm/arch-tegra114/usb.h   |  287
> > > > +++++++++++++++++++++
> > > > >  arch/arm/include/asm/arch-tegra20/usb.h    |  279
> > > > +++++++++++++++++++++
> > > > >  arch/arm/include/asm/arch-tegra30/usb.h    |  294
> > > > ++++++++++++++++++++++
> > > >
> > > > Do we now have three copies of the same stuff ?
> > >
> > > When only T20 was supported (for USB), there was a common
> > > (arch-tegra/usb.h) header. That's been moved to arch-tegra20/usb.h,
> > > and (unfortunately) there are 2 new usb.h files due to the HW
> > > differences in the registers between T20 and T30/T114.  I don't see
> > > any easy way to have a common usb.h file for Tegra w/o adding ugly
> > > #ifdefs to the USB register space struct(s).
> >
> > Just how different are they?  Are all of the related defines and masks
> > different too?  Do we have conflicts? Moved registers?  Just conflicting
> > values?  A quick peek shows '30' and '114' are pretty similar, except
> > for masks.  Maybe splitting the struct up so you can discard some of the
> > reserved gaps, run-time checking to see if we can or cannot use a
> > particular part of the struct?
> >
> 
> This is really Jim's patchset (and his specialty), but here's what I know
> about Tegra USB regs:
> 
> T20 had a gap in the registers @ offset 0x130. T30 (and T114) moved the
> offset of the command/status/interrupt regs down to fill in this gap, which
> dragged all the subsequent registers back 16 bytes. The two SoCs 'families'
> sync up again at offset 0x400 and are pretty much equal from there on out
> to 0x840.
> 
> The defines are probably 90% the same, with some weirdness for the first
> USB controller (USB1) and its PTS/STS bits that differs in offset from the
> other 2 controllers (again, no clue why the HW guys would do this).
> 
> So we could have the 3 different USB headers in the arch-tegraXX area
> contain the register structs, and have a common arch-tegra/usb.h that has
> the #defines that are the same, and is included in the arch-tegraxx/usb.h
> files. That would reduce this down somewhat, without the ugliness of
> #ifdefs in the structs.
> 
> What do you think?

Sounds like the best we can do then.  It's probable that trying to
define USB_REGMAP_GAPSIZE1/2 or whatever to do it on the fly would just
be uglier still.  Thanks!
Marek Vasut May 1, 2013, 7:33 p.m. UTC | #6
Dear Tom Rini,

> On Wed, May 01, 2013 at 09:16:45AM -0700, Tom Warren wrote:
> > Tom,
> > 
> > On Tue, Apr 30, 2013 at 10:20 AM, Tom Rini <trini@ti.com> wrote:
> > > On Tue, Apr 30, 2013 at 09:21:18AM -0700, Tom Warren wrote:
> > > > Marek,
> > > > 
> > > > > -----Original Message-----
> > > > > From: Marek Vasut [mailto:marex@denx.de]
> > > > > Sent: Monday, April 29, 2013 4:47 PM
> > > > > To: Jim Lin
> > > > > Cc: u-boot@lists.denx.de; Tom Warren; Stephen Warren
> > > > > Subject: Re: [PATCH 2/3] ARM: Tegra: USB: Add driver support for
> > > > > Tegra30/Tegra114
> > > > > 
> > > > > Dear Jim Lin,
> > > > > 
> > > > > > Tegra30 and Tegra114 are compatible except 1. T30 takes 55 ms to
> > > > > > finish Port Reset. T114 takes
> > > > > > 
> > > > > >    50 ms.
> > > > > > 
> > > > > > 2. PLL parameters
> > > > > > 
> > > > > > Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and Tegra114
> > > > > > Dalmore platforms. All works well.
> > > > > > 
> > > > > > Signed-off-by: Jim Lin <jilin@nvidia.com>
> > > > > > ---
> > > > > > 
> > > > > >  arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
> > > > > >  arch/arm/include/asm/arch-tegra/usb.h      |  249
> > > > > >  ------------------ arch/arm/include/asm/arch-tegra114/tegra.h |
> > > > > >     1 +
> > > > > >  arch/arm/include/asm/arch-tegra114/usb.h   |  287
> > > > > 
> > > > > +++++++++++++++++++++
> > > > > 
> > > > > >  arch/arm/include/asm/arch-tegra20/usb.h    |  279
> > > > > 
> > > > > +++++++++++++++++++++
> > > > > 
> > > > > >  arch/arm/include/asm/arch-tegra30/usb.h    |  294
> > > > > 
> > > > > ++++++++++++++++++++++
> > > > > 
> > > > > Do we now have three copies of the same stuff ?
> > > > 
> > > > When only T20 was supported (for USB), there was a common
> > > > (arch-tegra/usb.h) header. That's been moved to arch-tegra20/usb.h,
> > > > and (unfortunately) there are 2 new usb.h files due to the HW
> > > > differences in the registers between T20 and T30/T114.  I don't see
> > > > any easy way to have a common usb.h file for Tegra w/o adding ugly
> > > > #ifdefs to the USB register space struct(s).
> > > 
> > > Just how different are they?  Are all of the related defines and masks
> > > different too?  Do we have conflicts? Moved registers?  Just
> > > conflicting values?  A quick peek shows '30' and '114' are pretty
> > > similar, except for masks.  Maybe splitting the struct up so you can
> > > discard some of the reserved gaps, run-time checking to see if we can
> > > or cannot use a particular part of the struct?
> > 
> > This is really Jim's patchset (and his specialty), but here's what I know
> > about Tegra USB regs:
> > 
> > T20 had a gap in the registers @ offset 0x130. T30 (and T114) moved the
> > offset of the command/status/interrupt regs down to fill in this gap,
> > which dragged all the subsequent registers back 16 bytes. The two SoCs
> > 'families' sync up again at offset 0x400 and are pretty much equal from
> > there on out to 0x840.
> > 
> > The defines are probably 90% the same, with some weirdness for the first
> > USB controller (USB1) and its PTS/STS bits that differs in offset from
> > the other 2 controllers (again, no clue why the HW guys would do this).
> > 
> > So we could have the 3 different USB headers in the arch-tegraXX area
> > contain the register structs, and have a common arch-tegra/usb.h that has
> > the #defines that are the same, and is included in the arch-tegraxx/usb.h
> > files. That would reduce this down somewhat, without the ugliness of
> > #ifdefs in the structs.
> > 
> > What do you think?
> 
> Sounds like the best we can do then.  It's probable that trying to
> define USB_REGMAP_GAPSIZE1/2 or whatever to do it on the fly would just
> be uglier still.  Thanks!

This is a problem with the struct-based access indeed. I agree with Tom it'd be 
worth to at least try distilling the common part into header shared between 
those three CPUs.

btw you're also adding some kernel-doc-alike annotations to functions, why don't 
you follow kerneldoc style altogether?

Best regards,
Marek Vasut
Tom Warren May 1, 2013, 11:20 p.m. UTC | #7
On Wed, May 1, 2013 at 12:33 PM, Marek Vasut <marex@denx.de> wrote:

> Dear Tom Rini,
>
> > On Wed, May 01, 2013 at 09:16:45AM -0700, Tom Warren wrote:
> > > Tom,
> > >
> > > On Tue, Apr 30, 2013 at 10:20 AM, Tom Rini <trini@ti.com> wrote:
> > > > On Tue, Apr 30, 2013 at 09:21:18AM -0700, Tom Warren wrote:
> > > > > Marek,
> > > > >
> > > > > > -----Original Message-----
> > > > > > From: Marek Vasut [mailto:marex@denx.de]
> > > > > > Sent: Monday, April 29, 2013 4:47 PM
> > > > > > To: Jim Lin
> > > > > > Cc: u-boot@lists.denx.de; Tom Warren; Stephen Warren
> > > > > > Subject: Re: [PATCH 2/3] ARM: Tegra: USB: Add driver support for
> > > > > > Tegra30/Tegra114
> > > > > >
> > > > > > Dear Jim Lin,
> > > > > >
> > > > > > > Tegra30 and Tegra114 are compatible except 1. T30 takes 55 ms
> to
> > > > > > > finish Port Reset. T114 takes
> > > > > > >
> > > > > > >    50 ms.
> > > > > > >
> > > > > > > 2. PLL parameters
> > > > > > >
> > > > > > > Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and
> Tegra114
> > > > > > > Dalmore platforms. All works well.
> > > > > > >
> > > > > > > Signed-off-by: Jim Lin <jilin@nvidia.com>
> > > > > > > ---
> > > > > > >
> > > > > > >  arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
> > > > > > >  arch/arm/include/asm/arch-tegra/usb.h      |  249
> > > > > > >  ------------------ arch/arm/include/asm/arch-tegra114/tegra.h
> |
> > > > > > >     1 +
> > > > > > >  arch/arm/include/asm/arch-tegra114/usb.h   |  287
> > > > > >
> > > > > > +++++++++++++++++++++
> > > > > >
> > > > > > >  arch/arm/include/asm/arch-tegra20/usb.h    |  279
> > > > > >
> > > > > > +++++++++++++++++++++
> > > > > >
> > > > > > >  arch/arm/include/asm/arch-tegra30/usb.h    |  294
> > > > > >
> > > > > > ++++++++++++++++++++++
> > > > > >
> > > > > > Do we now have three copies of the same stuff ?
> > > > >
> > > > > When only T20 was supported (for USB), there was a common
> > > > > (arch-tegra/usb.h) header. That's been moved to arch-tegra20/usb.h,
> > > > > and (unfortunately) there are 2 new usb.h files due to the HW
> > > > > differences in the registers between T20 and T30/T114.  I don't see
> > > > > any easy way to have a common usb.h file for Tegra w/o adding ugly
> > > > > #ifdefs to the USB register space struct(s).
> > > >
> > > > Just how different are they?  Are all of the related defines and
> masks
> > > > different too?  Do we have conflicts? Moved registers?  Just
> > > > conflicting values?  A quick peek shows '30' and '114' are pretty
> > > > similar, except for masks.  Maybe splitting the struct up so you can
> > > > discard some of the reserved gaps, run-time checking to see if we can
> > > > or cannot use a particular part of the struct?
> > >
> > > This is really Jim's patchset (and his specialty), but here's what I
> know
> > > about Tegra USB regs:
> > >
> > > T20 had a gap in the registers @ offset 0x130. T30 (and T114) moved the
> > > offset of the command/status/interrupt regs down to fill in this gap,
> > > which dragged all the subsequent registers back 16 bytes. The two SoCs
> > > 'families' sync up again at offset 0x400 and are pretty much equal from
> > > there on out to 0x840.
> > >
> > > The defines are probably 90% the same, with some weirdness for the
> first
> > > USB controller (USB1) and its PTS/STS bits that differs in offset from
> > > the other 2 controllers (again, no clue why the HW guys would do this).
> > >
> > > So we could have the 3 different USB headers in the arch-tegraXX area
> > > contain the register structs, and have a common arch-tegra/usb.h that
> has
> > > the #defines that are the same, and is included in the
> arch-tegraxx/usb.h
> > > files. That would reduce this down somewhat, without the ugliness of
> > > #ifdefs in the structs.
> > >
> > > What do you think?
> >
> > Sounds like the best we can do then.  It's probable that trying to
> > define USB_REGMAP_GAPSIZE1/2 or whatever to do it on the fly would just
> > be uglier still.  Thanks!
>
> This is a problem with the struct-based access indeed. I agree with Tom
> it'd be
> worth to at least try distilling the common part into header shared between
> those three CPUs.
>
> btw you're also adding some kernel-doc-alike annotations to functions, why
> don't
> you follow kerneldoc style altogether?
>

I'll let Jim answer that.


>
> Best regards,
> Marek Vasut
>
Tom Warren May 1, 2013, 11:23 p.m. UTC | #8
Adding Jim back into the conversation since he got dropped a couple of
emails back.


On Wed, May 1, 2013 at 4:20 PM, Tom Warren <twarren.nvidia@gmail.com> wrote:

>
>
>
> On Wed, May 1, 2013 at 12:33 PM, Marek Vasut <marex@denx.de> wrote:
>
>> Dear Tom Rini,
>>
>> > On Wed, May 01, 2013 at 09:16:45AM -0700, Tom Warren wrote:
>> > > Tom,
>> > >
>> > > On Tue, Apr 30, 2013 at 10:20 AM, Tom Rini <trini@ti.com> wrote:
>> > > > On Tue, Apr 30, 2013 at 09:21:18AM -0700, Tom Warren wrote:
>> > > > > Marek,
>> > > > >
>> > > > > > -----Original Message-----
>> > > > > > From: Marek Vasut [mailto:marex@denx.de]
>> > > > > > Sent: Monday, April 29, 2013 4:47 PM
>> > > > > > To: Jim Lin
>> > > > > > Cc: u-boot@lists.denx.de; Tom Warren; Stephen Warren
>> > > > > > Subject: Re: [PATCH 2/3] ARM: Tegra: USB: Add driver support for
>> > > > > > Tegra30/Tegra114
>> > > > > >
>> > > > > > Dear Jim Lin,
>> > > > > >
>> > > > > > > Tegra30 and Tegra114 are compatible except 1. T30 takes 55 ms
>> to
>> > > > > > > finish Port Reset. T114 takes
>> > > > > > >
>> > > > > > >    50 ms.
>> > > > > > >
>> > > > > > > 2. PLL parameters
>> > > > > > >
>> > > > > > > Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and
>> Tegra114
>> > > > > > > Dalmore platforms. All works well.
>> > > > > > >
>> > > > > > > Signed-off-by: Jim Lin <jilin@nvidia.com>
>> > > > > > > ---
>> > > > > > >
>> > > > > > >  arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
>> > > > > > >  arch/arm/include/asm/arch-tegra/usb.h      |  249
>> > > > > > >  ------------------
>> arch/arm/include/asm/arch-tegra114/tegra.h |
>> > > > > > >     1 +
>> > > > > > >  arch/arm/include/asm/arch-tegra114/usb.h   |  287
>> > > > > >
>> > > > > > +++++++++++++++++++++
>> > > > > >
>> > > > > > >  arch/arm/include/asm/arch-tegra20/usb.h    |  279
>> > > > > >
>> > > > > > +++++++++++++++++++++
>> > > > > >
>> > > > > > >  arch/arm/include/asm/arch-tegra30/usb.h    |  294
>> > > > > >
>> > > > > > ++++++++++++++++++++++
>> > > > > >
>> > > > > > Do we now have three copies of the same stuff ?
>> > > > >
>> > > > > When only T20 was supported (for USB), there was a common
>> > > > > (arch-tegra/usb.h) header. That's been moved to
>> arch-tegra20/usb.h,
>> > > > > and (unfortunately) there are 2 new usb.h files due to the HW
>> > > > > differences in the registers between T20 and T30/T114.  I don't
>> see
>> > > > > any easy way to have a common usb.h file for Tegra w/o adding ugly
>> > > > > #ifdefs to the USB register space struct(s).
>> > > >
>> > > > Just how different are they?  Are all of the related defines and
>> masks
>> > > > different too?  Do we have conflicts? Moved registers?  Just
>> > > > conflicting values?  A quick peek shows '30' and '114' are pretty
>> > > > similar, except for masks.  Maybe splitting the struct up so you can
>> > > > discard some of the reserved gaps, run-time checking to see if we
>> can
>> > > > or cannot use a particular part of the struct?
>> > >
>> > > This is really Jim's patchset (and his specialty), but here's what I
>> know
>> > > about Tegra USB regs:
>> > >
>> > > T20 had a gap in the registers @ offset 0x130. T30 (and T114) moved
>> the
>> > > offset of the command/status/interrupt regs down to fill in this gap,
>> > > which dragged all the subsequent registers back 16 bytes. The two SoCs
>> > > 'families' sync up again at offset 0x400 and are pretty much equal
>> from
>> > > there on out to 0x840.
>> > >
>> > > The defines are probably 90% the same, with some weirdness for the
>> first
>> > > USB controller (USB1) and its PTS/STS bits that differs in offset from
>> > > the other 2 controllers (again, no clue why the HW guys would do
>> this).
>> > >
>> > > So we could have the 3 different USB headers in the arch-tegraXX area
>> > > contain the register structs, and have a common arch-tegra/usb.h that
>> has
>> > > the #defines that are the same, and is included in the
>> arch-tegraxx/usb.h
>> > > files. That would reduce this down somewhat, without the ugliness of
>> > > #ifdefs in the structs.
>> > >
>> > > What do you think?
>> >
>> > Sounds like the best we can do then.  It's probable that trying to
>> > define USB_REGMAP_GAPSIZE1/2 or whatever to do it on the fly would just
>> > be uglier still.  Thanks!
>>
>> This is a problem with the struct-based access indeed. I agree with Tom
>> it'd be
>> worth to at least try distilling the common part into header shared
>> between
>> those three CPUs.
>>
>> btw you're also adding some kernel-doc-alike annotations to functions,
>> why don't
>> you follow kerneldoc style altogether?
>>
>
> I'll let Jim answer that.
>
>
>>
>> Best regards,
>> Marek Vasut
>>
>
>
Jim Lin May 2, 2013, 9:50 a.m. UTC | #9
On Thu, 2013-05-02 at 03:33 +0800, Marek Vasut wrote:
> Dear Tom Rini,
> 
> > On Wed, May 01, 2013 at 09:16:45AM -0700, Tom Warren wrote:
> > > Tom,
> > > 
> > > On Tue, Apr 30, 2013 at 10:20 AM, Tom Rini <trini@ti.com> wrote:
> > > > On Tue, Apr 30, 2013 at 09:21:18AM -0700, Tom Warren wrote:
> > > > > Marek,
> > > > > 
> > > > > > -----Original Message-----
> > > > > > From: Marek Vasut [mailto:marex@denx.de]
> > > > > > Sent: Monday, April 29, 2013 4:47 PM
> > > > > > To: Jim Lin
> > > > > > Cc: u-boot@lists.denx.de; Tom Warren; Stephen Warren
> > > > > > Subject: Re: [PATCH 2/3] ARM: Tegra: USB: Add driver support for
> > > > > > Tegra30/Tegra114
> > > > > > 
> > > > > > Dear Jim Lin,
> > > > > > 
> > > > > > > Tegra30 and Tegra114 are compatible except 1. T30 takes 55 ms to
> > > > > > > finish Port Reset. T114 takes
> > > > > > > 
> > > > > > >    50 ms.
> > > > > > > 
> > > > > > > 2. PLL parameters
> > > > > > > 
> > > > > > > Tested on Tegra20 Harmony/Seaboard, Tegra30 Cardhu, and Tegra114
> > > > > > > Dalmore platforms. All works well.
> > > > > > > 
> > > > > > > Signed-off-by: Jim Lin <jilin@nvidia.com>
> > > > > > > ---
> > > > > > > 
> > > > > > >  arch/arm/include/asm/arch-tegra/clk_rst.h  |   10 +
> > > > > > >  arch/arm/include/asm/arch-tegra/usb.h      |  249
> > > > > > >  ------------------ arch/arm/include/asm/arch-tegra114/tegra.h |
> > > > > > >     1 +
> > > > > > >  arch/arm/include/asm/arch-tegra114/usb.h   |  287
> > > > > > 
> > > > > > +++++++++++++++++++++
> > > > > > 
> > > > > > >  arch/arm/include/asm/arch-tegra20/usb.h    |  279
> > > > > > 
> > > > > > +++++++++++++++++++++
> > > > > > 
> > > > > > >  arch/arm/include/asm/arch-tegra30/usb.h    |  294
> > > > > > 
> > > > > > ++++++++++++++++++++++
> > > > > > 
> > > > > > Do we now have three copies of the same stuff ?
> > > > > 
> > > > > When only T20 was supported (for USB), there was a common
> > > > > (arch-tegra/usb.h) header. That's been moved to arch-tegra20/usb.h,
> > > > > and (unfortunately) there are 2 new usb.h files due to the HW
> > > > > differences in the registers between T20 and T30/T114.  I don't see
> > > > > any easy way to have a common usb.h file for Tegra w/o adding ugly
> > > > > #ifdefs to the USB register space struct(s).
> > > > 
> > > > Just how different are they?  Are all of the related defines and masks
> > > > different too?  Do we have conflicts? Moved registers?  Just
> > > > conflicting values?  A quick peek shows '30' and '114' are pretty
> > > > similar, except for masks.  Maybe splitting the struct up so you can
> > > > discard some of the reserved gaps, run-time checking to see if we can
> > > > or cannot use a particular part of the struct?
> > > 
> > > This is really Jim's patchset (and his specialty), but here's what I know
> > > about Tegra USB regs:
> > > 
> > > T20 had a gap in the registers @ offset 0x130. T30 (and T114) moved the
> > > offset of the command/status/interrupt regs down to fill in this gap,
> > > which dragged all the subsequent registers back 16 bytes. The two SoCs
> > > 'families' sync up again at offset 0x400 and are pretty much equal from
> > > there on out to 0x840.
> > > 
> > > The defines are probably 90% the same, with some weirdness for the first
> > > USB controller (USB1) and its PTS/STS bits that differs in offset from
> > > the other 2 controllers (again, no clue why the HW guys would do this).
> > > 
> > > So we could have the 3 different USB headers in the arch-tegraXX area
> > > contain the register structs, and have a common arch-tegra/usb.h that has
> > > the #defines that are the same, and is included in the arch-tegraxx/usb.h
> > > files. That would reduce this down somewhat, without the ugliness of
> > > #ifdefs in the structs.
> > > 
> > > What do you think?
> > 
> > Sounds like the best we can do then.  It's probable that trying to
> > define USB_REGMAP_GAPSIZE1/2 or whatever to do it on the fly would just
> > be uglier still.  Thanks!
> 
> This is a problem with the struct-based access indeed. I agree with Tom it'd be 
> worth to at least try distilling the common part into header shared between 
> those three CPUs.
OK. I will add this into next version of patch.

> 
> btw you're also adding some kernel-doc-alike annotations to functions, why don't 
> you follow kerneldoc style altogether?
I don't understand what you meant here.
Could you give me an example? Like what I did is wrong or not good. And
what is correct or better one.
Thanks.

--
nvpublic
Marek Vasut May 2, 2013, 11:38 a.m. UTC | #10
Dear Jim Lin,

[...]

> > 
> > This is a problem with the struct-based access indeed. I agree with Tom
> > it'd be worth to at least try distilling the common part into header
> > shared between those three CPUs.
> 
> OK. I will add this into next version of patch.
> 
> > btw you're also adding some kernel-doc-alike annotations to functions,
> > why don't you follow kerneldoc style altogether?
> 
> I don't understand what you meant here.
> Could you give me an example? Like what I did is wrong or not good. And
> what is correct or better one.

These kinds of annotations:

+/*
+ * Process a list of nodes, adding them to our list of SDMMC ports.
+ *
+ * @param blob          fdt blob
+ * @param node_list     list of nodes to process (any <=0 are ignored)
+ * @param count         number of nodes to process
+ * @return 0 if ok, -1 on error
+ */

See http://www.denx.de/wiki/U-Boot/CodingStyle at the bottom for the right 
style.

Best regards,
Marek Vasut
Stephen Warren May 2, 2013, 7:29 p.m. UTC | #11
On 04/29/2013 03:21 AM, Jim Lin wrote:
> Tegra30 and Tegra114 are compatible except
> 1. T30 takes 55 ms to finish Port Reset. T114 takes
>    50 ms.

Is that 55-vs-50 some aspect of the HW specification itself, or the
overall result of multiple separate delays? I ask because the statement
that one piece of HW differs from another only in a delay, especially
where that delay is enormous in HW terms, seem very unusual.

> diff --git a/arch/arm/include/asm/arch-tegra114/tegra.h b/arch/arm/include/asm/arch-tegra114/tegra.h

> +#define TEGRA_USB1_BASE		0x7D000000

That shouldn't be needed; if some of the module base addresses come from
DT, then they all should, or there's no point using DT.

> diff --git a/arch/arm/include/asm/arch-tegra114/usb.h b/arch/arm/include/asm/arch-tegra114/usb.h

> +#ifndef _TEGRA_USB_H_
> +#define _TEGRA_USB_H_
> +
> +
> +/* USB Controller (USBx_CONTROLLER_) regs */

There's an extra blank line there. The same problem exists elsewhere,
and in the other copies of this file.

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

>  void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
>  {
> -	mdelay(50);
> -	if (((u32) status_reg & TEGRA_USB_ADDR_MASK) != TEGRA_USB1_BASE)
> +	udelay(49990);
> +	if (is_T30_compatible) {

The code shouldn't test against a specific chip version, but rather
against some property of the HW (like the length of the delay). That
way, it will be scalable when we support 10 different Tegra versions and
the mapping from version number to feature isn't easy to represent.

> +		/*
> +		 * Tegra 114 takes 50 ms to assert Port Enable bit.
> +		 * We have to exit earlier. Otherwise ehci-hcd.c will clear
> +		 * our Port Enable bit.
> +		 */
> +		if (is_T114_compatible)
> +			return;
> +		/* Tegra 3 takes about 55 ms to assert Port Enable bit. */
> +		udelay(5010);
> +		return;
> +	}

This looks like an enormous hack. What is it doing? Why? Can't all 3
chips simply loop polling until some enable status bit is set?

> +	udelay(10);
> +	if (((u32)status_reg & TEGRA_USB_ADDR_MASK) != TEGRA_USB1_BASE)
>  		return;

This also should test against a feature, not the identity of the port.
The DT properties nvidia,has-legacy-mode or nvidia,needs-double-reset
might be relevant here?

> @@ -171,7 +177,7 @@ static void set_host_mode(struct fdt_usb *config)
>  	 * bail out in this case.
>  	 */
>  	if (config->dr_mode == DR_MODE_OTG &&
> -		(readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS))
> +	    (readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS))

That's an unrelated whitespace change. Whitespace cleanup should be in a
separate patch first, so it doesn't clutter functional changes.

> @@ -232,45 +240,112 @@ 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);
> -	}
> +				VBUS_SENSE_CTL_MASK,
> +				VBUS_SENSE_CTL_A_SESS_VLD <<
> +				VBUS_SENSE_CTL_SHIFT);

Partially a white-space change. There are many other ws-changes later
that I didn't bother pointing out.

> +	timing = (u32 *)config->params;
> +	if (is_T30_compatible)
> +		goto pll_T30_init;
...
> +	goto pll_init_done;
> +
> +pll_T30_init:
...
> +pll_init_done:

Uggh. Use functions.

> @@ -325,17 +409,37 @@ static int init_utmi_usb_controller(struct fdt_usb *config)
>  	/* Disable ICUSB FS/LS transceiver */
>  	clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
>  
> -	/* Select UTMI parallel interface */
> -	clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
> -			PTS_UTMI << PTS_SHIFT);
> -	clrbits_le32(&usbctlr->port_sc1, STS);
> +	if (!is_T30_compatible) {
> +		/* Select UTMI parallel interface */
> +		if (config->periph_id == PERIPH_ID_USBD) {
> +			clrsetbits_le32(&usbctlr->port_sc1, PTS1_MASK,
> +					PTS_UTMI << PTS1_SHIFT);
> +			clrbits_le32(&usbctlr->port_sc1, STS1);
> +		} else {
> +			clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
> +					PTS_UTMI << PTS_SHIFT);
> +			clrbits_le32(&usbctlr->port_sc1, STS);
> +		}
> +	}

This changes behaviour on Tegra20. While it may be correct, it has
nothing to do with adding Tegra30/114 support, and hence should be a
separate patch earlier in the series.

> +int board_usb_init(const void *blob)

> +	if (!count)
> +		goto skip_T20_process;
> +	err = process_nodes(blob, node_list, count);
> +	if (err) {
> +		printf("%s: Error processing T20 compatible USB node(s)!\n",
> +		       __func__);
> +		return err;
> +	}
> +skip_T20_process:

Uggh. Instead of:

    if (!count)
        goto skip;
    code;
skip:

do:

if (count) {
    code;
}

> +
> +	count = fdtdec_find_aliases_for_id(blob, "usb",
> +			COMPAT_NVIDIA_TEGRA114_USB, node_list, USB_PORTS_MAX);
> +	if (count)
> +		is_T114_compatible = 1;

Don't use globals for that. Or, if you do, just return as soon as you've
found a match, so it's impossible to end up with some Tegra20 and some
Tegra30 controllers both enabled.
Jim Lin May 3, 2013, 10:53 a.m. UTC | #12
On Fri, 2013-05-03 at 03:29 +0800, Stephen Warren wrote:
> On 04/29/2013 03:21 AM, Jim Lin wrote:
> > Tegra30 and Tegra114 are compatible except
> > 1. T30 takes 55 ms to finish Port Reset. T114 takes
> >    50 ms.
> 
> Is that 55-vs-50 some aspect of the HW specification itself, or the
> overall result of multiple separate delays? I ask because the statement
> that one piece of HW differs from another only in a delay, especially
> where that delay is enormous in HW terms, seem very unusual.

50 ms comes from USB 2.0 specification for root port.
55 ms comes from T30 Technical Reference Manual.
Overall result of multiple separate delays.

--
nvpublic
Stephen Warren May 3, 2013, 2:46 p.m. UTC | #13
On 05/03/2013 04:53 AM, Jim Lin wrote:
> On Fri, 2013-05-03 at 03:29 +0800, Stephen Warren wrote:
>> On 04/29/2013 03:21 AM, Jim Lin wrote:
>>> Tegra30 and Tegra114 are compatible except
>>> 1. T30 takes 55 ms to finish Port Reset. T114 takes
>>>    50 ms.
>>
>> Is that 55-vs-50 some aspect of the HW specification itself, or the
>> overall result of multiple separate delays? I ask because the statement
>> that one piece of HW differs from another only in a delay, especially
>> where that delay is enormous in HW terms, seem very unusual.
> 
> 50 ms comes from USB 2.0 specification for root port.
> 55 ms comes from T30 Technical Reference Manual.

OK, I see this value is indeed in the TRM, so I guess the code is OK.

> Overall result of multiple separate delays.

That doesn't seem true though; the TRM simply documents a single 55ms
delay, not a set of delays that add up to 55ms.
diff mbox

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
deleted file mode 100644
index ef6c089..0000000
--- a/arch/arm/include/asm/arch-tegra/usb.h
+++ /dev/null
@@ -1,249 +0,0 @@ 
-/*
- * Copyright (c) 2011 The Chromium OS Authors.
- * 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 _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
-
-#define VBUS_SENSE_CTL_SHIFT			1
-#define VBUS_SENSE_CTL_MASK			(3 << VBUS_SENSE_CTL_SHIFT)
-#define VBUS_SENSE_CTL_VBUS_WAKEUP		0
-#define VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP	1
-#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)
-
-/* USBx_UTMIP_MISC_CFG1 */
-#define UTMIP_PLLU_STABLE_COUNT_SHIFT		6
-#define UTMIP_PLLU_STABLE_COUNT_MASK		\
-				(0xfff << UTMIP_PLLU_STABLE_COUNT_SHIFT)
-#define UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT	18
-#define UTMIP_PLL_ACTIVE_DLY_COUNT_MASK		\
-				(0x1f << UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT)
-#define UTMIP_PHY_XTAL_CLOCKEN			(1 << 30)
-
-/* 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)
-#define UTMIP_XTAL_FREQ_COUNT_SHIFT		0
-#define UTMIP_XTAL_FREQ_COUNT_MASK		0xfff
-
-/* USBx_UTMIP_BIAS_CFG1_0 */
-#define UTMIP_BIAS_PDTRK_COUNT_SHIFT		3
-#define UTMIP_BIAS_PDTRK_COUNT_MASK		\
-				(0x1f << UTMIP_BIAS_PDTRK_COUNT_SHIFT)
-
-#define UTMIP_DEBOUNCE_CFG0_SHIFT		0
-#define UTMIP_DEBOUNCE_CFG0_MASK		0xffff
-
-/* USBx_UTMIP_TX_CFG0_0 */
-#define UTMIP_FS_PREAMBLE_J			(1 << 19)
-
-/* 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)
-
-/* USBx_UTMIP_HSRX_CFG0_0 */
-#define UTMIP_IDLE_WAIT_SHIFT			15
-#define UTMIP_IDLE_WAIT_MASK			(0x1f << UTMIP_IDLE_WAIT_SHIFT)
-#define UTMIP_ELASTIC_LIMIT_SHIFT		10
-#define UTMIP_ELASTIC_LIMIT_MASK		\
-				(0x1f << UTMIP_ELASTIC_LIMIT_SHIFT)
-
-/* USBx_UTMIP_HSRX_CFG0_1 */
-#define UTMIP_HS_SYNC_START_DLY_SHIFT		1
-#define UTMIP_HS_SYNC_START_DLY_MASK		\
-				(0xf << 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
-#define PTS_RESERVED	1
-#define PTS_ULPI		2
-#define PTS_ICUSB_SER	3
-
-#define STS					(1 << 29)
-#define WKOC				(1 << 22)
-#define WKDS				(1 << 21)
-#define WKCN				(1 << 20)
-
-/* USBx_UTMIP_XCVR_CFG0_0 */
-#define UTMIP_FORCE_PD_POWERDOWN		(1 << 14)
-#define UTMIP_FORCE_PD2_POWERDOWN		(1 << 16)
-#define UTMIP_FORCE_PDZI_POWERDOWN		(1 << 18)
-
-/* USBx_UTMIP_XCVR_CFG1_0 */
-#define UTMIP_FORCE_PDDISC_POWERDOWN		(1 << 0)
-#define UTMIP_FORCE_PDCHRP_POWERDOWN		(1 << 2)
-#define UTMIP_FORCE_PDDR_POWERDOWN		(1 << 4)
-
-/* USB3_IF_USB_PHY_VBUS_SENSORS_0 */
-#define VBUS_VLD_STS			(1 << 26)
-
-
-/* Setup USB on the board */
-int board_usb_init(const void *blob);
-
-#endif	/* _TEGRA_USB_H_ */
diff --git a/arch/arm/include/asm/arch-tegra114/tegra.h b/arch/arm/include/asm/arch-tegra114/tegra.h
index 5d426b5..893d229 100644
--- a/arch/arm/include/asm/arch-tegra114/tegra.h
+++ b/arch/arm/include/asm/arch-tegra114/tegra.h
@@ -30,5 +30,6 @@ 
 #define NVBOOTINFOTABLE_BCTPTR 0x4C    /* BCT pointer in BIT in IRAM */
 
 #define MAX_NUM_CPU            4
+#define TEGRA_USB1_BASE		0x7D000000
 
 #endif /* TEGRA114_H */
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..c3ca5fa
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra114/usb.h
@@ -0,0 +1,287 @@ 
+/*
+ * 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 _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[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;
+	uint reserved7_0;
+	uint reserved7_1;
+
+	/* 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;
+};
+
+/* USB1_LEGACY_CTRL */
+#define USB1_NO_LEGACY_MODE		1
+
+#define VBUS_SENSE_CTL_SHIFT			1
+#define VBUS_SENSE_CTL_MASK			(3 << VBUS_SENSE_CTL_SHIFT)
+#define VBUS_SENSE_CTL_VBUS_WAKEUP		0
+#define VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP	1
+#define VBUS_SENSE_CTL_AB_SESS_VLD		2
+#define VBUS_SENSE_CTL_A_SESS_VLD		3
+
+/* USBx_IF_USB_SUSP_CTRL_0 */
+#define UTMIP_PHY_ENB			        (1 << 12)
+#define UTMIP_RESET			        (1 << 11)
+#define USB_PHY_CLK_VALID			(1 << 7)
+#define USB_SUSP_CLR				(1 << 5)
+
+/* USBx_UTMIP_MISC_CFG0 */
+#define UTMIP_SUSPEND_EXIT_ON_EDGE		(1 << 22)
+
+/* USBx_UTMIP_MISC_CFG1 */
+#define UTMIP_PHY_XTAL_CLOCKEN			(1 << 30)
+
+/* Moved to Clock and Reset register space */
+#define UTMIP_PLLU_STABLE_COUNT_SHIFT		6
+#define UTMIP_PLLU_STABLE_COUNT_MASK		\
+				(0xfff << UTMIP_PLLU_STABLE_COUNT_SHIFT)
+/* Moved to Clock and Reset register space */
+#define UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT	18
+#define UTMIP_PLL_ACTIVE_DLY_COUNT_MASK		\
+				(0x1f << UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT)
+
+/* USBx_UTMIP_PLL_CFG1_0 */
+/* Moved to Clock and Reset register space */
+#define UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT	27
+#define UTMIP_PLLU_ENABLE_DLY_COUNT_MASK	\
+				(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
+
+/* USBx_UTMIP_TX_CFG0_0 */
+#define UTMIP_FS_PREAMBLE_J			(1 << 19)
+
+/* USBx_UTMIP_BAT_CHRG_CFG0_0 */
+#define UTMIP_PD_CHRG				1
+
+/* USBx_UTMIP_SPARE_CFG0_0 */
+#define FUSE_SETUP_SEL				(1 << 3)
+
+/* USBx_UTMIP_HSRX_CFG0_0 */
+#define UTMIP_IDLE_WAIT_SHIFT			15
+#define UTMIP_IDLE_WAIT_MASK			(0x1f << UTMIP_IDLE_WAIT_SHIFT)
+#define UTMIP_ELASTIC_LIMIT_SHIFT		10
+#define UTMIP_ELASTIC_LIMIT_MASK		\
+				(0x1f << UTMIP_ELASTIC_LIMIT_SHIFT)
+
+/* USBx_UTMIP_HSRX_CFG0_1 */
+#define UTMIP_HS_SYNC_START_DLY_SHIFT		1
+#define UTMIP_HS_SYNC_START_DLY_MASK		\
+				(0x1f << UTMIP_HS_SYNC_START_DLY_SHIFT)
+
+/* USBx_CONTROLLER_2_USB2D_ICUSB_CTRL_0 */
+#define IC_ENB1					(1 << 3)
+
+/* PORTSC1, USB1, defined for Tegra20 to avoid compiling error */
+#define PTS1_SHIFT				31
+#define PTS1_MASK				(1 << PTS1_SHIFT)
+#define STS1					(1 << 30)
+
+/* USB2D_HOSTPC1_DEVLC_0 */
+#define PTS_SHIFT				29
+#define PTS_MASK				(0x7U << PTS_SHIFT)
+#define PTS_UTMI	0
+#define PTS_RESERVED	1
+#define PTS_ULPI	2
+#define PTS_ICUSB_SER	3
+#define PTS_HSIC	4
+
+#define STS					(1 << 28)
+
+/* SB2_CONTROLLER_2_USB2D_PORTSC1_0 */
+#define WKOC				(1 << 22)
+#define WKDS				(1 << 21)
+#define WKCN				(1 << 20)
+
+/* USBx_UTMIP_XCVR_CFG0_0 */
+#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)
+
+/* USB3_IF_USB_PHY_VBUS_SENSORS_0 */
+#define VBUS_VLD_STS			(1 << 26)
+
+
+/* Setup USB on the board */
+int board_usb_init(const void *blob);
+
+#endif	/* _TEGRA_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..415c0f6
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra20/usb.h
@@ -0,0 +1,279 @@ 
+/*
+ * 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 _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
+
+#define VBUS_SENSE_CTL_SHIFT			1
+#define VBUS_SENSE_CTL_MASK			(3 << VBUS_SENSE_CTL_SHIFT)
+#define VBUS_SENSE_CTL_VBUS_WAKEUP		0
+#define VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP	1
+#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)
+
+/* 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		\
+				(0xfff << UTMIP_PLLU_STABLE_COUNT_SHIFT)
+#define UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT	18
+#define UTMIP_PLL_ACTIVE_DLY_COUNT_MASK		\
+				(0x1f << UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT)
+#define UTMIP_PHY_XTAL_CLOCKEN			(1 << 30)
+
+/* 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)
+#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)
+
+#define UTMIP_DEBOUNCE_CFG0_SHIFT		0
+#define UTMIP_DEBOUNCE_CFG0_MASK		0xffff
+
+/* USBx_UTMIP_TX_CFG0_0 */
+#define UTMIP_FS_PREAMBLE_J			(1 << 19)
+
+/* USBx_UTMIP_BAT_CHRG_CFG0_0 */
+#define UTMIP_PD_CHRG				1
+
+/* USBx_UTMIP_SPARE_CFG0_0 */
+#define FUSE_SETUP_SEL				(1 << 3)
+
+/* USBx_UTMIP_HSRX_CFG0_0 */
+#define UTMIP_IDLE_WAIT_SHIFT			15
+#define UTMIP_IDLE_WAIT_MASK			(0x1f << UTMIP_IDLE_WAIT_SHIFT)
+#define UTMIP_ELASTIC_LIMIT_SHIFT		10
+#define UTMIP_ELASTIC_LIMIT_MASK		\
+				(0x1f << UTMIP_ELASTIC_LIMIT_SHIFT)
+
+/* USBx_UTMIP_HSRX_CFG0_1 */
+#define UTMIP_HS_SYNC_START_DLY_SHIFT		1
+#define UTMIP_HS_SYNC_START_DLY_MASK		\
+				(0xf << UTMIP_HS_SYNC_START_DLY_SHIFT)
+
+/* USBx_CONTROLLER_2_USB2D_ICUSB_CTRL_0 */
+#define IC_ENB1					(1 << 3)
+
+/* PORTSC1, USB1 */
+#define PTS1_SHIFT				31
+#define PTS1_MASK				(1 << PTS1_SHIFT)
+#define STS1					(1 << 30)
+
+/* PORTSC, USB2, USB3 */
+#define PTS_SHIFT				30
+#define PTS_MASK				(3U << PTS_SHIFT)
+#define PTS_UTMI		0
+#define PTS_RESERVED	1
+#define PTS_ULPI		2
+#define PTS_ICUSB_SER	3
+
+#define STS					(1 << 29)
+#define WKOC				(1 << 22)
+#define WKDS				(1 << 21)
+#define WKCN				(1 << 20)
+
+/* USBx_UTMIP_XCVR_CFG0_0 */
+#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_FORCE_PDDISC_POWERDOWN		(1 << 0)
+#define UTMIP_FORCE_PDCHRP_POWERDOWN		(1 << 2)
+#define UTMIP_FORCE_PDDR_POWERDOWN		(1 << 4)
+#define UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT		18
+#define UTMIP_XCVR_TERM_RANGE_ADJ_MASK		\
+			(0xf << UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT)
+
+/* USB3_IF_USB_PHY_VBUS_SENSORS_0 */
+#define VBUS_VLD_STS			(1 << 26)
+
+
+/* Setup USB on the board */
+int board_usb_init(const void *blob);
+
+#endif	/* _TEGRA_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..84049b7
--- /dev/null
+++ b/arch/arm/include/asm/arch-tegra30/usb.h
@@ -0,0 +1,294 @@ 
+/*
+ * 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 _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[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;   /* is this port_sc1 on some controllers? */
+	uint icusb_ctrl;
+
+	/* 0x160 */
+	uint ulpi_viewport;
+	uint reserved7;
+	uint endpt_nak;
+	uint endpt_nak_enable;
+
+	/* 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 reserved11[2];
+	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;
+};
+
+/* USB1_LEGACY_CTRL */
+#define USB1_NO_LEGACY_MODE		1
+
+#define VBUS_SENSE_CTL_SHIFT			1
+#define VBUS_SENSE_CTL_MASK			(3 << VBUS_SENSE_CTL_SHIFT)
+#define VBUS_SENSE_CTL_VBUS_WAKEUP		0
+#define VBUS_SENSE_CTL_AB_SESS_VLD_OR_VBUS_WAKEUP	1
+#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)
+
+/* 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		\
+				(0xfff << UTMIP_PLLU_STABLE_COUNT_SHIFT)
+#define UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT	18
+#define UTMIP_PLL_ACTIVE_DLY_COUNT_MASK		\
+				(0x1f << UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT)
+#define UTMIP_PHY_XTAL_CLOCKEN			(1 << 30)
+
+/* 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)
+#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)
+
+#define UTMIP_DEBOUNCE_CFG0_SHIFT		0
+#define UTMIP_DEBOUNCE_CFG0_MASK		0xffff
+
+/* USBx_UTMIP_TX_CFG0_0 */
+#define UTMIP_FS_PREAMBLE_J			(1 << 19)
+
+/* USBx_UTMIP_BAT_CHRG_CFG0_0 */
+#define UTMIP_PD_CHRG				1
+
+/* USBx_UTMIP_SPARE_CFG0_0 */
+#define FUSE_SETUP_SEL				(1 << 3)
+
+/* USBx_UTMIP_HSRX_CFG0_0 */
+#define UTMIP_IDLE_WAIT_SHIFT			15
+#define UTMIP_IDLE_WAIT_MASK			(0x1f << UTMIP_IDLE_WAIT_SHIFT)
+#define UTMIP_ELASTIC_LIMIT_SHIFT		10
+#define UTMIP_ELASTIC_LIMIT_MASK		\
+				(0x1f << UTMIP_ELASTIC_LIMIT_SHIFT)
+
+/* USBx_UTMIP_HSRX_CFG0_1 */
+#define UTMIP_HS_SYNC_START_DLY_SHIFT		1
+#define UTMIP_HS_SYNC_START_DLY_MASK		\
+				(0xf << UTMIP_HS_SYNC_START_DLY_SHIFT)
+
+/* USBx_CONTROLLER_2_USB2D_ICUSB_CTRL_0 */
+#define IC_ENB1					(1 << 3)
+
+/* PORTSC1, USB1, defined for Tegra20 to avoid compiling error */
+#define PTS1_SHIFT				31
+#define PTS1_MASK				(1 << PTS1_SHIFT)
+#define STS1					(1 << 30)
+
+/* USB2D_HOSTPC1_DEVLC_0 */
+#define PTS_SHIFT				29
+#define PTS_MASK				(0x7U << PTS_SHIFT)
+#define PTS_UTMI	0
+#define PTS_RESERVED	1
+#define PTS_ULPI	2
+#define PTS_ICUSB_SER	3
+#define PTS_HSIC	4
+
+#define STS					(1 << 28)
+
+/* SB2_CONTROLLER_2_USB2D_PORTSC1_0 */
+#define WKOC				(1 << 22)
+#define WKDS				(1 << 21)
+#define WKCN				(1 << 20)
+
+/* USBx_UTMIP_XCVR_CFG0_0 */
+#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)
+
+/* USB3_IF_USB_PHY_VBUS_SENSORS_0 */
+#define VBUS_VLD_STS			(1 << 26)
+
+
+/* Setup USB on the board */
+int board_usb_init(const void *blob);
+
+#endif	/* _TEGRA_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-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..6a55cd2 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -122,6 +122,31 @@  static struct descriptor {
 #define ehci_is_TDI()	(0)
 #endif
 
+int __ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+{
+	return PORTSC_PSPD(reg);
+}
+
+int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+	__attribute__((weak, alias("__ehci_get_port_speed")));
+
+void __ehci_set_usbmode(int index)
+{
+	uint32_t tmp;
+	uint32_t *reg_ptr;
+
+	reg_ptr = (uint32_t *)((u8 *)&ehcic[index].hcor->or_usbcmd + USBMODE);
+	tmp = ehci_readl(reg_ptr);
+	tmp |= USBMODE_CM_HC;
+#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
+	tmp |= USBMODE_BE;
+#endif
+	ehci_writel(reg_ptr, tmp);
+}
+
+void ehci_set_usbmode(int index)
+	__attribute__((weak, alias("__ehci_set_usbmode")));
+
 void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
 {
 	mdelay(50);
@@ -149,8 +174,6 @@  static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 static int ehci_reset(int index)
 {
 	uint32_t cmd;
-	uint32_t tmp;
-	uint32_t *reg_ptr;
 	int ret = 0;
 
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
@@ -163,15 +186,8 @@  static int ehci_reset(int index)
 		goto out;
 	}
 
-	if (ehci_is_TDI()) {
-		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
-		tmp = ehci_readl(reg_ptr);
-		tmp |= USBMODE_CM_HC;
-#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
-		tmp |= USBMODE_BE;
-#endif
-		ehci_writel(reg_ptr, tmp);
-	}
+	if (ehci_is_TDI())
+		ehci_set_usbmode(index);
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -711,7 +727,7 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
 
 		if (ehci_is_TDI()) {
-			switch (PORTSC_PSPD(reg)) {
+			switch (ehci_get_port_speed(ctrl->hcor, reg)) {
 			case PORTSC_PSPD_FS:
 				break;
 			case PORTSC_PSPD_LS:
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 554145a..6b53659 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
@@ -27,7 +27,8 @@ 
 #include <asm/io.h>
 #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 +36,9 @@ 
 
 #include "ehci.h"
 
+#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 \
@@ -74,6 +78,7 @@  enum dr_mode {
 /* Information about a USB port */
 struct fdt_usb {
 	struct usb_ctlr *reg;	/* address of registers in physical memory */
+	int params[PARAM_COUNT]; /* timing parameters */
 	unsigned utmi:1;	/* 1 if port has external tranceiver, else 0 */
 	unsigned ulpi:1;	/* 1 if port has external ULPI transceiver */
 	unsigned enabled:1;	/* 1 to enable, 0 to disable */
@@ -87,55 +92,8 @@  struct fdt_usb {
 
 static struct fdt_usb port[USB_PORTS_MAX];	/* List of valid USB ports */
 static unsigned port_count;			/* Number of available ports */
-
-/*
- * This table has USB timing parameters for each Oscillator frequency we
- * support. There are four sets of values:
- *
- * 1. PLLU configuration information (reference clock is osc/clk_m and
- * PLLU-FOs are fixed at 12MHz/60MHz/480MHz).
- *
- *  Reference frequency     13.0MHz      19.2MHz      12.0MHz      26.0MHz
- *  ----------------------------------------------------------------------
- *      DIVN                960 (0x3c0)  200 (0c8)    960 (3c0h)   960 (3c0)
- *      DIVM                13 (0d)      4 (04)       12 (0c)      26 (1a)
- * Filter frequency (MHz)   1            4.8          6            2
- * CPCON                    1100b        0011b        1100b        1100b
- * LFCON0                   0            0            0            0
- *
- * 2. PLL CONFIGURATION & PARAMETERS for different clock generators:
- *
- * Reference frequency     13.0MHz         19.2MHz         12.0MHz     26.0MHz
- * ---------------------------------------------------------------------------
- * PLLU_ENABLE_DLY_COUNT   02 (0x02)       03 (03)         02 (02)     04 (04)
- * PLLU_STABLE_COUNT       51 (33)         75 (4B)         47 (2F)    102 (66)
- * PLL_ACTIVE_DLY_COUNT    05 (05)         06 (06)         04 (04)     09 (09)
- * XTAL_FREQ_COUNT        127 (7F)        187 (BB)        118 (76)    254 (FE)
- *
- * 3. Debounce values IdDig, Avalid, Bvalid, VbusValid, VbusWakeUp, and
- * SessEnd. Each of these signals have their own debouncer and for each of
- * those one out of two debouncing times can be chosen (BIAS_DEBOUNCE_A or
- * BIAS_DEBOUNCE_B).
- *
- * The values of DEBOUNCE_A and DEBOUNCE_B are calculated as follows:
- *    0xffff -> No debouncing at all
- *    <n> ms = <n> *1000 / (1/19.2MHz) / 4
- *
- * So to program a 1 ms debounce for BIAS_DEBOUNCE_A, we have:
- * BIAS_DEBOUNCE_A[15:0] = 1000 * 19.2 / 4  = 4800 = 0x12c0
- *
- * We need to use only DebounceA for BOOTROM. We don't need the DebounceB
- * values, so we can keep those to default.
- *
- * 4. The 20 microsecond delay after bias cell operation.
- */
-static const unsigned 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 },
-	{ 0x3C0, 0x0C, 0x00, 0xC,   0,  0x02, 0x2F, 0x04, 0x76, 0x7530, 5 },
-	{ 0x3C0, 0x1A, 0x00, 0xC,   0,  0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 }
-};
+static unsigned is_T30_compatible;
+static unsigned is_T114_compatible;
 
 /* UTMIP Idle Wait Delay */
 static const u8 utmip_idle_wait_delay = 17;
@@ -155,14 +113,62 @@  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)
+	udelay(49990);
+	if (is_T30_compatible) {
+		/*
+		 * Tegra 114 takes 50 ms to assert Port Enable bit.
+		 * We have to exit earlier. Otherwise ehci-hcd.c will clear
+		 * our Port Enable bit.
+		 */
+		if (is_T114_compatible)
+			return;
+		/* Tegra 3 takes about 55 ms to assert Port Enable bit. */
+		udelay(5010);
+		return;
+	}
+	udelay(10);
+	if (((u32)status_reg & TEGRA_USB_ADDR_MASK) != TEGRA_USB1_BASE)
 		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)
 {
@@ -171,7 +177,7 @@  static void set_host_mode(struct fdt_usb *config)
 	 * bail out in this case.
 	 */
 	if (config->dr_mode == DR_MODE_OTG &&
-		(readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS))
+	    (readl(&config->reg->phy_vbus_sensors) & VBUS_VLD_STS))
 		return;
 
 	/*
@@ -214,8 +220,10 @@  static int init_utmi_usb_controller(struct fdt_usb *config)
 {
 	u32 val;
 	int loop_count;
-	const unsigned *timing;
+	const u32 *timing;
 	struct usb_ctlr *usbctlr = config->reg;
+	struct clk_rst_ctlr *clkrst;
+	struct usb_ctlr *usb1ctlr;
 
 	clock_enable(config->periph_id);
 
@@ -232,45 +240,112 @@  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);
-	}
+				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 = (u32 *)config->params;
+	if (is_T30_compatible)
+		goto pll_T30_init;
 
 	val = readl(&usbctlr->utmip_misc_cfg1);
 	clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK,
-		timing[PARAM_STABLE_COUNT] << UTMIP_PLLU_STABLE_COUNT_SHIFT);
+			timing[PARAM_STABLE_COUNT] <<
+			UTMIP_PLLU_STABLE_COUNT_SHIFT);
 	clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK,
-		timing[PARAM_ACTIVE_DELAY_COUNT] <<
+			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] <<
+			timing[PARAM_ENABLE_DELAY_COUNT] <<
 			UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT);
 	clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK,
-		timing[PARAM_XTAL_FREQ_COUNT] <<
+			timing[PARAM_XTAL_FREQ_COUNT] <<
 			UTMIP_XTAL_FREQ_COUNT_SHIFT);
 	writel(val, &usbctlr->utmip_pll_cfg1);
+	goto pll_init_done;
+
+pll_T30_init:
+	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 *)TEGRA_USB1_BASE;
+	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);
+pll_init_done:
 
 	/* Setting the tracking length time */
 	clrsetbits_le32(&usbctlr->utmip_bias_cfg1,
-		UTMIP_BIAS_PDTRK_COUNT_MASK,
-		timing[PARAM_BIAS_TIME] << UTMIP_BIAS_PDTRK_COUNT_SHIFT);
+			UTMIP_BIAS_PDTRK_COUNT_MASK,
+			timing[PARAM_BIAS_TIME] <<
+			UTMIP_BIAS_PDTRK_COUNT_SHIFT);
 
 	/* Program debounce time for VBUS to become valid */
 	clrsetbits_le32(&usbctlr->utmip_debounce_cfg0,
-		UTMIP_DEBOUNCE_CFG0_MASK,
-		timing[PARAM_DEBOUNCE_A_TIME] << UTMIP_DEBOUNCE_CFG0_SHIFT);
+			UTMIP_DEBOUNCE_CFG0_MASK,
+			timing[PARAM_DEBOUNCE_A_TIME] <<
+			UTMIP_DEBOUNCE_CFG0_SHIFT);
 
 	setbits_le32(&usbctlr->utmip_tx_cfg0, UTMIP_FS_PREAMBLE_J);
 
@@ -292,15 +367,16 @@  static int init_utmi_usb_controller(struct fdt_usb *config)
 	/* Set PLL enable delay count and Crystal frequency count */
 	val = readl(&usbctlr->utmip_hsrx_cfg0);
 	clrsetbits_le32(&val, UTMIP_IDLE_WAIT_MASK,
-		utmip_idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT);
+			utmip_idle_wait_delay << UTMIP_IDLE_WAIT_SHIFT);
 	clrsetbits_le32(&val, UTMIP_ELASTIC_LIMIT_MASK,
-		utmip_elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT);
+			utmip_elastic_limit << UTMIP_ELASTIC_LIMIT_SHIFT);
 	writel(val, &usbctlr->utmip_hsrx_cfg0);
 
 	/* Configure the UTMIP_HS_SYNC_START_DLY */
 	clrsetbits_le32(&usbctlr->utmip_hsrx_cfg1,
-		UTMIP_HS_SYNC_START_DLY_MASK,
-		utmip_hs_sync_start_delay << UTMIP_HS_SYNC_START_DLY_SHIFT);
+			UTMIP_HS_SYNC_START_DLY_MASK,
+			utmip_hs_sync_start_delay <<
+			UTMIP_HS_SYNC_START_DLY_SHIFT);
 
 	/* Preceed the crystal clock disable by >100ns delay. */
 	udelay(1);
@@ -308,6 +384,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. */
@@ -325,17 +409,37 @@  static int init_utmi_usb_controller(struct fdt_usb *config)
 	/* Disable ICUSB FS/LS transceiver */
 	clrbits_le32(&usbctlr->icusb_ctrl, IC_ENB1);
 
-	/* Select UTMI parallel interface */
-	clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
-			PTS_UTMI << PTS_SHIFT);
-	clrbits_le32(&usbctlr->port_sc1, STS);
+	if (!is_T30_compatible) {
+		/* Select UTMI parallel interface */
+		if (config->periph_id == PERIPH_ID_USBD) {
+			clrsetbits_le32(&usbctlr->port_sc1, PTS1_MASK,
+					PTS_UTMI << PTS1_SHIFT);
+			clrbits_le32(&usbctlr->port_sc1, STS1);
+		} else {
+			clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK,
+					PTS_UTMI << PTS_SHIFT);
+			clrbits_le32(&usbctlr->port_sc1, STS);
+		}
+	}
 
 	/* Deassert power down state */
 	clrbits_le32(&usbctlr->utmip_xcvr_cfg0, UTMIP_FORCE_PD_POWERDOWN |
-		UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN);
+		     UTMIP_FORCE_PD2_POWERDOWN | UTMIP_FORCE_PDZI_POWERDOWN);
 	clrbits_le32(&usbctlr->utmip_xcvr_cfg1, UTMIP_FORCE_PDDISC_POWERDOWN |
-		UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_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 *)TEGRA_USB1_BASE;
+		clrbits_le32(&usb1ctlr->utmip_bias_cfg0, UTMIP_BIASPD);
+		udelay(25);
+		clrbits_le32(&usb1ctlr->utmip_bias_cfg1,
+			     UTMIP_FORCE_PDTRK_POWERDOWN);
+	}
 	return 0;
 }
 
@@ -371,7 +475,7 @@  static int init_ulpi_usb_controller(struct fdt_usb *config)
 
 	/* enable pinmux bypass */
 	setbits_le32(&usbctlr->ulpi_timing_ctrl_0,
-			ULPI_CLKOUT_PINMUX_BYP | ULPI_OUTPUT_PINMUX_BYP);
+		     ULPI_CLKOUT_PINMUX_BYP | ULPI_OUTPUT_PINMUX_BYP);
 
 	/* Select ULPI parallel interface */
 	clrsetbits_le32(&usbctlr->port_sc1, PTS_MASK, PTS_ULPI << PTS_SHIFT);
@@ -431,16 +535,28 @@  static int init_ulpi_usb_controller(struct fdt_usb *config)
 }
 #endif
 
-static void config_clock(const u32 timing[])
+static void config_clock(const u32 *timing)
 {
 	clock_start_pll(CLOCK_ID_USB,
-		timing[PARAM_DIVM], timing[PARAM_DIVN], timing[PARAM_DIVP],
-		timing[PARAM_CPCON], timing[PARAM_LFCON]);
+			timing[PARAM_DIVM], timing[PARAM_DIVN],
+			timing[PARAM_DIVP], timing[PARAM_CPCON],
+			timing[PARAM_LFCON]);
 }
 
-int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
+int fdt_decode_usb(const void *blob, int node, unsigned osc_frequency_hz,
+	struct fdt_usb *config)
 {
 	const char *phy, *mode;
+	int clk_node = 0, rate;
+
+	/* Find the parameters for our oscillator frequency */
+	do {
+		clk_node = fdt_node_offset_by_compatible(blob,
+				clk_node, "nvidia,usbparams");
+		if (clk_node < 0)
+			return -FDT_ERR_NOTFOUND;
+		rate = fdtdec_get_int(blob, clk_node, "osc-frequency", 0);
+	} while (rate != osc_frequency_hz);
 
 	config->reg = (struct usb_ctlr *)fdtdec_get_addr(blob, node, "reg");
 	mode = fdt_getprop(blob, node, "dr_mode", NULL);
@@ -480,27 +596,30 @@  int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
 		config->ulpi, config->periph_id, config->vbus_gpio.gpio,
 		config->phy_reset_gpio.gpio, config->dr_mode);
 
-	return 0;
+	return fdtdec_get_int_array(blob, clk_node, "params",
+		(u32 *)&config->params, PARAM_COUNT);
 }
 
-int board_usb_init(const void *blob)
+/*
+ * Process a list of nodes, adding them to our list of SDMMC ports.
+ *
+ * @param blob          fdt blob
+ * @param node_list     list of nodes to process (any <=0 are ignored)
+ * @param count         number of nodes to process
+ * @return 0 if ok, -1 on error
+ */
+static int process_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;
+	int node, i;
+	int clk_done = 0;
+	unsigned osc_freq = clock_get_rate(CLOCK_ID_OSC);
 
-	/* Set up the USB clocks correctly based on our oscillator frequency */
-	freq = clock_get_osc_freq();
-	config_clock(usb_pll[freq]);
-
-	/* 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",
-				USB_PORTS_MAX);
+			printf("tegrausb: Cannot register more than %d ports\n"
+				, USB_PORTS_MAX);
 			return -1;
 		}
 
@@ -508,11 +627,15 @@  int board_usb_init(const void *blob)
 		node = node_list[i];
 		if (!node)
 			continue;
-		if (fdt_decode_usb(blob, node, &config)) {
+		if (fdt_decode_usb(blob, node, osc_freq, &config)) {
 			debug("Cannot decode USB node %s\n",
 			      fdt_get_name(blob, node, NULL));
 			return -1;
 		}
+		if (!clk_done) {
+			config_clock((u32 *)&config.params);
+			clk_done = 1;
+		}
 		config.initialized = 0;
 
 		/* add new USB port to the list of available ports */
@@ -522,6 +645,49 @@  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;
+
+	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)
+		goto skip_T20_process;
+	err = process_nodes(blob, node_list, count);
+	if (err) {
+		printf("%s: Error processing T20 compatible USB node(s)!\n",
+		       __func__);
+		return err;
+	}
+skip_T20_process:
+
+	count = fdtdec_find_aliases_for_id(blob, "usb",
+			COMPAT_NVIDIA_TEGRA114_USB, node_list, USB_PORTS_MAX);
+	if (count)
+		is_T114_compatible = 1;
+
+	count = fdtdec_find_aliases_for_id(blob, "usb",
+			COMPAT_NVIDIA_TEGRA30_USB, node_list, USB_PORTS_MAX);
+	if (count)
+		is_T30_compatible = 1;
+	else
+		goto skip_T30_process;
+	err = process_nodes(blob, node_list, count);
+	if (count && err) {
+		printf("%s: Error processing T30 compatible USB node(s)!\n",
+		       __func__);
+		return err;
+	}
+skip_T30_process:
+
+	return 0;
+}
+
 /**
  * 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 +730,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;
 }