diff mbox

[U-Boot,v4,1/2] usb: ehci: add Faraday USB 2.0 EHCI support

Message ID 1367907970-11903-2-git-send-email-dantesu@gmail.com
State Superseded
Delegated to: Marek Vasut
Headers show

Commit Message

Kuo-Jung Su May 7, 2013, 6:26 a.m. UTC
From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch add supports to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI as
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. Since U-boot doesn't support ISOC,
   we don't have to worry that.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 common/usb_hub.c                |   13 +-
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  146 ++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |  104 ++++++++----
 include/usb/fotg210.h           |  358 +++++++++++++++++++++++++++++++++++++++
 include/usb/fusbh200.h          |   61 +++++++
 6 files changed, 646 insertions(+), 37 deletions(-)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5

Comments

Marek Vasut May 7, 2013, 9:42 p.m. UTC | #1
Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> This patch add supports to both Faraday FUSBH200 and FOTG210,
> the differences between Faraday EHCI and standard EHCI as
> listed bellow:
> 
> 1. The PORTSC starts at 0x30 instead of 0x44.
> 2. The CONFIGFLAG(0x40) is not only un-implemented, and
>    also has its address removed.
> 3. Faraday EHCI is a TDI design, but it doesn't
>    compatible with the general TDI implementation
>    found at both U-Boot and Linux.
> 4. The ISOC descriptors differs from standard EHCI in
>    several ways. Since U-boot doesn't support ISOC,
>    we don't have to worry that.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>
> ---
> Changes for v4:
>    - Use only macro constants and named bit/mask
>    - Use weak-aliased functions for tdi implementation and
>      also portsc registers to avoid poluting ehci.h with ifdefs
> 
> Changes for v3:
>    - Coding Style cleanup.
>    - Drop bit fields from c struct.
>    - Drop macros for wirtel()/readl(), call them directly.
>    - Always insert a blank line between declarations and code.
>    - Replace all the infinite wait loop with a timeout.
>    - Add '__iomem' to all the declaration of HW register pointers.
> 
> Changes for v2:
>    - Coding Style cleanup.
>    - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>    - Use structure based hardware registers to replace the macro constants.
>    - Replace BIT() with BIT_MASK().
>    - echi-faraday: Remove debug codes.
> 
>  common/usb_hub.c                |   13 +-
>  drivers/usb/host/Makefile       |    1 +
>  drivers/usb/host/ehci-faraday.c |  146 ++++++++++++++++
>  drivers/usb/host/ehci-hcd.c     |  104 ++++++++----
>  include/usb/fotg210.h           |  358
> +++++++++++++++++++++++++++++++++++++++ include/usb/fusbh200.h          | 
>  61 +++++++
>  6 files changed, 646 insertions(+), 37 deletions(-)
>  create mode 100644 drivers/usb/host/ehci-faraday.c
>  create mode 100644 include/usb/fotg210.h
>  create mode 100644 include/usb/fusbh200.h
> 
> diff --git a/common/usb_hub.c b/common/usb_hub.c
> index b5eeb62..3c6cb69 100644

Please split the EHCI changes from this patch.

> --- a/common/usb_hub.c
> +++ b/common/usb_hub.c
> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device *dev)
>  			portstatus = le16_to_cpu(portsts->wPortStatus);
>  			portchange = le16_to_cpu(portsts->wPortChange);
> 
> +#ifdef CONFIG_USB_EHCI_FARADAY
> +			/* Faraday EHCI needs a long long delay here */
> +			if (!portchange && !portstatus) {
> +				if (get_timer(start) < 250)
> +					continue;
> +			}
> +#endif

I'd say just call a weak function here, in case some other non-EHCI compliant 
controller happened to need this too. btw. does it need to be 250 ms or can you 
poll for readiness somehow ?

>  			if ((portchange & USB_PORT_STAT_C_CONNECTION) ==
>  				(portstatus & USB_PORT_STAT_CONNECTION))
>  				break;
> @@ -441,7 +449,9 @@ static int usb_hub_configure(struct usb_device *dev)
>  					i + 1, portstatus);
>  			usb_clear_port_feature(dev, i + 1,
>  						USB_PORT_FEAT_C_ENABLE);
> -
> +			/* The following hack causes a ghost device problem
> +			 * to Faraday EHCI */

Invalid multiline comment style (not that the one right below is a shining 
example of a valid one :-( ).

/*
 * This is how you
 * do multiline comments.
 */

> +#ifndef CONFIG_USB_EHCI_FARADAY
>  			/* EM interference sometimes causes bad shielded USB
>  			 * devices to be shutdown by the hub, this hack enables
>  			 * them again. Works at least with mouse driver */
> @@ -453,6 +463,7 @@ static int usb_hub_configure(struct usb_device *dev)
>  						"re-enabling...\n", i + 1);
>  					usb_hub_port_connect_change(dev, i);
>  			}
> +#endif
>  		}
>  		if (portstatus & USB_PORT_STAT_SUSPEND) {
>  			USB_HUB_PRINTF("port %d suspend change\n", i + 1);

[...]
Kuo-Jung Su May 8, 2013, 2:18 a.m. UTC | #2
2013/5/8 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> This patch add supports to both Faraday FUSBH200 and FOTG210,
>> the differences between Faraday EHCI and standard EHCI as
>> listed bellow:
>>
>> 1. The PORTSC starts at 0x30 instead of 0x44.
>> 2. The CONFIGFLAG(0x40) is not only un-implemented, and
>>    also has its address removed.
>> 3. Faraday EHCI is a TDI design, but it doesn't
>>    compatible with the general TDI implementation
>>    found at both U-Boot and Linux.
>> 4. The ISOC descriptors differs from standard EHCI in
>>    several ways. Since U-boot doesn't support ISOC,
>>    we don't have to worry that.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>> ---
>> Changes for v4:
>>    - Use only macro constants and named bit/mask
>>    - Use weak-aliased functions for tdi implementation and
>>      also portsc registers to avoid poluting ehci.h with ifdefs
>>
>> Changes for v3:
>>    - Coding Style cleanup.
>>    - Drop bit fields from c struct.
>>    - Drop macros for wirtel()/readl(), call them directly.
>>    - Always insert a blank line between declarations and code.
>>    - Replace all the infinite wait loop with a timeout.
>>    - Add '__iomem' to all the declaration of HW register pointers.
>>
>> Changes for v2:
>>    - Coding Style cleanup.
>>    - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>>    - Use structure based hardware registers to replace the macro constants.
>>    - Replace BIT() with BIT_MASK().
>>    - echi-faraday: Remove debug codes.
>>
>>  common/usb_hub.c                |   13 +-
>>  drivers/usb/host/Makefile       |    1 +
>>  drivers/usb/host/ehci-faraday.c |  146 ++++++++++++++++
>>  drivers/usb/host/ehci-hcd.c     |  104 ++++++++----
>>  include/usb/fotg210.h           |  358
>> +++++++++++++++++++++++++++++++++++++++ include/usb/fusbh200.h          |
>>  61 +++++++
>>  6 files changed, 646 insertions(+), 37 deletions(-)
>>  create mode 100644 drivers/usb/host/ehci-faraday.c
>>  create mode 100644 include/usb/fotg210.h
>>  create mode 100644 include/usb/fusbh200.h
>>
>> diff --git a/common/usb_hub.c b/common/usb_hub.c
>> index b5eeb62..3c6cb69 100644
>
> Please split the EHCI changes from this patch.
>

Got it, thanks

>> --- a/common/usb_hub.c
>> +++ b/common/usb_hub.c
>> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device *dev)
>>                       portstatus = le16_to_cpu(portsts->wPortStatus);
>>                       portchange = le16_to_cpu(portsts->wPortChange);
>>
>> +#ifdef CONFIG_USB_EHCI_FARADAY
>> +                     /* Faraday EHCI needs a long long delay here */
>> +                     if (!portchange && !portstatus) {
>> +                             if (get_timer(start) < 250)
>> +                                     continue;
>> +                     }
>> +#endif
>
> I'd say just call a weak function here, in case some other non-EHCI compliant
> controller happened to need this too. btw. does it need to be 250 ms or can you
> poll for readiness somehow ?
>

Got it, thanks. I'll add a weak function later,
and about the 250 ms is actually an estimated value.
The delay time is actually board specific, it looks to me
that it's somehow related to the number of usb host controllers
and the attached usb flash drivers.

For example:

1.  A369 - FUSBH200: a usb flash driver attached
     A369 - FOTG210: nothing attached
=> no extra delay required.

2.  A369 - FUSBH200: nothing attached
     A369 - FOTG210: a usb flash driver attached
=> no extra delay required.

3. A369 - FUSBH200: a usb flash driver attached
    A369 - FOTG210: a usb flash driver attached
=> The 2nd ehci host requires 200 ms extra delay to detect the attached device.
     So I put a 250ms here for safe.

>>                       if ((portchange & USB_PORT_STAT_C_CONNECTION) ==
>>                               (portstatus & USB_PORT_STAT_CONNECTION))
>>                               break;
>> @@ -441,7 +449,9 @@ static int usb_hub_configure(struct usb_device *dev)
>>                                       i + 1, portstatus);
>>                       usb_clear_port_feature(dev, i + 1,
>>                                               USB_PORT_FEAT_C_ENABLE);
>> -
>> +                     /* The following hack causes a ghost device problem
>> +                      * to Faraday EHCI */
>
> Invalid multiline comment style (not that the one right below is a shining
> example of a valid one :-( ).
>
> /*
>  * This is how you
>  * do multiline comments.
>  */
>

Got it, thanks!

>> +#ifndef CONFIG_USB_EHCI_FARADAY
>>                       /* EM interference sometimes causes bad shielded USB
>>                        * devices to be shutdown by the hub, this hack enables
>>                        * them again. Works at least with mouse driver */
>> @@ -453,6 +463,7 @@ static int usb_hub_configure(struct usb_device *dev)
>>                                               "re-enabling...\n", i + 1);
>>                                       usb_hub_port_connect_change(dev, i);
>>                       }
>> +#endif
>>               }
>>               if (portstatus & USB_PORT_STAT_SUSPEND) {
>>                       USB_HUB_PRINTF("port %d suspend change\n", i + 1);
>
> [...]



--
Best wishes,
Kuo-Jung Su
Marek Vasut May 8, 2013, 3:09 a.m. UTC | #3
Dear Kuo-Jung Su,

[...]

> >> --- a/common/usb_hub.c
> >> +++ b/common/usb_hub.c
> >> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device
> >> *dev)
> >> 
> >>                       portstatus = le16_to_cpu(portsts->wPortStatus);
> >>                       portchange = le16_to_cpu(portsts->wPortChange);
> >> 
> >> +#ifdef CONFIG_USB_EHCI_FARADAY
> >> +                     /* Faraday EHCI needs a long long delay here */
> >> +                     if (!portchange && !portstatus) {
> >> +                             if (get_timer(start) < 250)
> >> +                                     continue;
> >> +                     }
> >> +#endif
> > 
> > I'd say just call a weak function here, in case some other non-EHCI
> > compliant controller happened to need this too. btw. does it need to be
> > 250 ms or can you poll for readiness somehow ?
> 
> Got it, thanks. I'll add a weak function later,
> and about the 250 ms is actually an estimated value.
> The delay time is actually board specific, it looks to me
> that it's somehow related to the number of usb host controllers
> and the attached usb flash drivers.
> 
> For example:
> 
> 1.  A369 - FUSBH200: a usb flash driver attached
>      A369 - FOTG210: nothing attached
> => no extra delay required.
> 
> 2.  A369 - FUSBH200: nothing attached
>      A369 - FOTG210: a usb flash driver attached
> => no extra delay required.
> 
> 3. A369 - FUSBH200: a usb flash driver attached
>     A369 - FOTG210: a usb flash driver attached
> => The 2nd ehci host requires 200 ms extra delay to detect the attached
> device. So I put a 250ms here for safe.

Urgh, isn't it a PHY problem then? Or can this not be solved like 
board/genesi/mx51_efikamx/efikamx-usb.c board_ehci_hcd_postinit() or such 
function?

[...]

Best regards,
Marek Vasut
Kuo-Jung Su May 8, 2013, 5:41 a.m. UTC | #4
2013/5/8 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
> [...]
>
>> >> --- a/common/usb_hub.c
>> >> +++ b/common/usb_hub.c
>> >> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device
>> >> *dev)
>> >>
>> >>                       portstatus = le16_to_cpu(portsts->wPortStatus);
>> >>                       portchange = le16_to_cpu(portsts->wPortChange);
>> >>
>> >> +#ifdef CONFIG_USB_EHCI_FARADAY
>> >> +                     /* Faraday EHCI needs a long long delay here */
>> >> +                     if (!portchange && !portstatus) {
>> >> +                             if (get_timer(start) < 250)
>> >> +                                     continue;
>> >> +                     }
>> >> +#endif
>> >
>> > I'd say just call a weak function here, in case some other non-EHCI
>> > compliant controller happened to need this too. btw. does it need to be
>> > 250 ms or can you poll for readiness somehow ?
>>
>> Got it, thanks. I'll add a weak function later,
>> and about the 250 ms is actually an estimated value.
>> The delay time is actually board specific, it looks to me
>> that it's somehow related to the number of usb host controllers
>> and the attached usb flash drivers.
>>
>> For example:
>>
>> 1.  A369 - FUSBH200: a usb flash driver attached
>>      A369 - FOTG210: nothing attached
>> => no extra delay required.
>>
>> 2.  A369 - FUSBH200: nothing attached
>>      A369 - FOTG210: a usb flash driver attached
>> => no extra delay required.
>>
>> 3. A369 - FUSBH200: a usb flash driver attached
>>     A369 - FOTG210: a usb flash driver attached
>> => The 2nd ehci host requires 200 ms extra delay to detect the attached
>> device. So I put a 250ms here for safe.
>
> Urgh, isn't it a PHY problem then? Or can this not be solved like
> board/genesi/mx51_efikamx/efikamx-usb.c board_ehci_hcd_postinit() or such
> function?
>

It looks to me that it's something related to root hub reset.
And now I've found that adding a extra delay to usb_hub_power_on()
would help to resolve this issue.
So I plan to add a new macro constant for it.
For example:

1. Add this to README:
CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
interval for usb hub power-on delay.(minimum 100msec)

2. Update usb_hub.c as bellow:
static void usb_hub_power_on(struct usb_hub_device *hub)
{
......
    /* Wait at least 100 msec for power to become stable */
    mdelay(max(pgood_delay, USB_HUB_MIN_POWER_ON_DELAY));
}

> [...]
>
> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su
Marek Vasut May 8, 2013, 11:52 a.m. UTC | #5
Dear Kuo-Jung Su,

> 2013/5/8 Marek Vasut <marex@denx.de>:
> > Dear Kuo-Jung Su,
> > 
> > [...]
> > 
> >> >> --- a/common/usb_hub.c
> >> >> +++ b/common/usb_hub.c
> >> >> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device
> >> >> *dev)
> >> >> 
> >> >>                       portstatus = le16_to_cpu(portsts->wPortStatus);
> >> >>                       portchange = le16_to_cpu(portsts->wPortChange);
> >> >> 
> >> >> +#ifdef CONFIG_USB_EHCI_FARADAY
> >> >> +                     /* Faraday EHCI needs a long long delay here */
> >> >> +                     if (!portchange && !portstatus) {
> >> >> +                             if (get_timer(start) < 250)
> >> >> +                                     continue;
> >> >> +                     }
> >> >> +#endif
> >> > 
> >> > I'd say just call a weak function here, in case some other non-EHCI
> >> > compliant controller happened to need this too. btw. does it need to
> >> > be 250 ms or can you poll for readiness somehow ?
> >> 
> >> Got it, thanks. I'll add a weak function later,
> >> and about the 250 ms is actually an estimated value.
> >> The delay time is actually board specific, it looks to me
> >> that it's somehow related to the number of usb host controllers
> >> and the attached usb flash drivers.
> >> 
> >> For example:
> >> 
> >> 1.  A369 - FUSBH200: a usb flash driver attached
> >> 
> >>      A369 - FOTG210: nothing attached
> >> 
> >> => no extra delay required.
> >> 
> >> 2.  A369 - FUSBH200: nothing attached
> >> 
> >>      A369 - FOTG210: a usb flash driver attached
> >> 
> >> => no extra delay required.
> >> 
> >> 3. A369 - FUSBH200: a usb flash driver attached
> >> 
> >>     A369 - FOTG210: a usb flash driver attached
> >> 
> >> => The 2nd ehci host requires 200 ms extra delay to detect the attached
> >> device. So I put a 250ms here for safe.
> > 
> > Urgh, isn't it a PHY problem then? Or can this not be solved like
> > board/genesi/mx51_efikamx/efikamx-usb.c board_ehci_hcd_postinit() or such
> > function?
> 
> It looks to me that it's something related to root hub reset.
> And now I've found that adding a extra delay to usb_hub_power_on()
> would help to resolve this issue.
> So I plan to add a new macro constant for it.
> For example:
> 
> 1. Add this to README:
> CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
> interval for usb hub power-on delay.(minimum 100msec)
> 
> 2. Update usb_hub.c as bellow:
> static void usb_hub_power_on(struct usb_hub_device *hub)
> {
> ......
>     /* Wait at least 100 msec for power to become stable */
>     mdelay(max(pgood_delay, USB_HUB_MIN_POWER_ON_DELAY));
> }

Let's try it.

Best regards,
Marek Vasut
Kuo-Jung Su May 9, 2013, 1:51 a.m. UTC | #6
2013/5/8 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> 2013/5/8 Marek Vasut <marex@denx.de>:
>> > Dear Kuo-Jung Su,
>> >
>> > [...]
>> >
>> >> >> --- a/common/usb_hub.c
>> >> >> +++ b/common/usb_hub.c
>> >> >> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device
>> >> >> *dev)
>> >> >>
>> >> >>                       portstatus = le16_to_cpu(portsts->wPortStatus);
>> >> >>                       portchange = le16_to_cpu(portsts->wPortChange);
>> >> >>
>> >> >> +#ifdef CONFIG_USB_EHCI_FARADAY
>> >> >> +                     /* Faraday EHCI needs a long long delay here */
>> >> >> +                     if (!portchange && !portstatus) {
>> >> >> +                             if (get_timer(start) < 250)
>> >> >> +                                     continue;
>> >> >> +                     }
>> >> >> +#endif
>> >> >
>> >> > I'd say just call a weak function here, in case some other non-EHCI
>> >> > compliant controller happened to need this too. btw. does it need to
>> >> > be 250 ms or can you poll for readiness somehow ?
>> >>
>> >> Got it, thanks. I'll add a weak function later,
>> >> and about the 250 ms is actually an estimated value.
>> >> The delay time is actually board specific, it looks to me
>> >> that it's somehow related to the number of usb host controllers
>> >> and the attached usb flash drivers.
>> >>
>> >> For example:
>> >>
>> >> 1.  A369 - FUSBH200: a usb flash driver attached
>> >>
>> >>      A369 - FOTG210: nothing attached
>> >>
>> >> => no extra delay required.
>> >>
>> >> 2.  A369 - FUSBH200: nothing attached
>> >>
>> >>      A369 - FOTG210: a usb flash driver attached
>> >>
>> >> => no extra delay required.
>> >>
>> >> 3. A369 - FUSBH200: a usb flash driver attached
>> >>
>> >>     A369 - FOTG210: a usb flash driver attached
>> >>
>> >> => The 2nd ehci host requires 200 ms extra delay to detect the attached
>> >> device. So I put a 250ms here for safe.
>> >
>> > Urgh, isn't it a PHY problem then? Or can this not be solved like
>> > board/genesi/mx51_efikamx/efikamx-usb.c board_ehci_hcd_postinit() or such
>> > function?
>>
>> It looks to me that it's something related to root hub reset.
>> And now I've found that adding a extra delay to usb_hub_power_on()
>> would help to resolve this issue.
>> So I plan to add a new macro constant for it.
>> For example:
>>
>> 1. Add this to README:
>> CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
>> interval for usb hub power-on delay.(minimum 100msec)
>>
>> 2. Update usb_hub.c as bellow:
>> static void usb_hub_power_on(struct usb_hub_device *hub)
>> {
>> ......
>>     /* Wait at least 100 msec for power to become stable */
>>     mdelay(max(pgood_delay, USB_HUB_MIN_POWER_ON_DELAY));
>> }
>
> Let's try it.
>

Got it, thanks

> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su
Kuo-Jung Su May 9, 2013, 3:20 a.m. UTC | #7
From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. And since U-boot doesn't support ISOC,
   we don't have to worry about that.

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device as a time.

Changes for v5:
   - Split up EHCI changeset
   - usb_hub: replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.
   - ehci-faraday: fix the invalid multi-line comment style.
   - gadget-fotg210: coding style cleanup.
   - gadget-fotg210: drop postfix '__iomem' from struct fotg210_regs
   - gadget-fotg210: use permanent delay for hardware reset
   - gadget-fotg210: drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - gadget-fotg210: drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

Kuo-Jung Su (4):
  usb: make usb hub minimum power-on delay configurable
  usb: add weak-aliased functions EHCI portsc & tdi routines
  usb: ehci: add Faraday USB 2.0 EHCI support
  usb: gadget: add Faraday FOTG210 USB gadget support

 README                            |    3 +
 common/usb_hub.c                  |   15 +-
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 drivers/usb/host/Makefile         |    1 +
 drivers/usb/host/ehci-faraday.c   |  146 ++++++
 drivers/usb/host/ehci-hcd.c       |  104 ++--
 include/usb/fotg210.h             |  364 ++++++++++++++
 include/usb/fusbh200.h            |   61 +++
 10 files changed, 1613 insertions(+), 38 deletions(-)
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5
diff mbox

Patch

diff --git a/common/usb_hub.c b/common/usb_hub.c
index b5eeb62..3c6cb69 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -419,6 +419,14 @@  static int usb_hub_configure(struct usb_device *dev)
 			portstatus = le16_to_cpu(portsts->wPortStatus);
 			portchange = le16_to_cpu(portsts->wPortChange);

+#ifdef CONFIG_USB_EHCI_FARADAY
+			/* Faraday EHCI needs a long long delay here */
+			if (!portchange && !portstatus) {
+				if (get_timer(start) < 250)
+					continue;
+			}
+#endif
+
 			if ((portchange & USB_PORT_STAT_C_CONNECTION) ==
 				(portstatus & USB_PORT_STAT_CONNECTION))
 				break;
@@ -441,7 +449,9 @@  static int usb_hub_configure(struct usb_device *dev)
 					i + 1, portstatus);
 			usb_clear_port_feature(dev, i + 1,
 						USB_PORT_FEAT_C_ENABLE);
-
+			/* The following hack causes a ghost device problem
+			 * to Faraday EHCI */
+#ifndef CONFIG_USB_EHCI_FARADAY
 			/* EM interference sometimes causes bad shielded USB
 			 * devices to be shutdown by the hub, this hack enables
 			 * them again. Works at least with mouse driver */
@@ -453,6 +463,7 @@  static int usb_hub_configure(struct usb_device *dev)
 						"re-enabling...\n", i + 1);
 					usb_hub_port_connect_change(dev, i);
 			}
+#endif
 		}
 		if (portstatus & USB_PORT_STAT_SUSPEND) {
 			USB_HUB_PRINTF("port %d suspend change\n", i + 1);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 87a5970..98f2a10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -43,6 +43,7 @@  COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..1be9369
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,146 @@ 
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+#ifndef CONFIG_USB_EHCI_BASE_LIST
+#define CONFIG_USB_EHCI_BASE_LIST	{ CONFIG_USB_EHCI_BASE }
+#endif
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
+{
+	return !readl(&regs->usb.easstr);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	union ehci_faraday_regs *regs;
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+
+	if (index < 0 || index >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[index];
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_is_fotg2xx(regs)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* Disable OTG & DEV interrupts, triggered at level-high */
+		writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
+		/* Disable all interrupts */
+		writel(0x00, &regs->usb.bmier);
+		writel(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+/*
+ * This ehci_tdi_reset() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+void ehci_tdi_reset(struct ehci_hcor *hcor)
+{
+	/* nothing needs to be done */
+}
+
+/*
+ * This ehci_port_speed() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+{
+	int spd, ret = 0;
+	union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10);
+
+	if (ehci_is_fotg2xx(regs))
+		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+	else
+		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+	switch (spd) {
+	case 0:    /* full speed */
+		break;
+	case 1:    /* low  speed */
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+	case 2:    /* high speed */
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * This ehci_get_portsc_register() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	/* Faraday EHCI has one and only one portsc register */
+	if (port > 0) {
+		printf("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+	return (uint32_t *)((uint8_t *)hcor + 0x20);
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..36ad897 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -117,10 +117,50 @@  static struct descriptor {
 };

 #if defined(CONFIG_EHCI_IS_TDI)
-#define ehci_is_TDI()	(1)
-#else
-#define ehci_is_TDI()	(0)
+# define ehci_is_TDI()	(1)
+
+/* put TDI/ARC silicon into EHCI mode */
+void __ehci_tdi_reset(struct ehci_hcor *hcor)
+{
+	uint32_t tmp, *reg_ptr;
+
+	reg_ptr = (uint32_t *)((uint8_t *) + 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_tdi_reset(struct ehci_hcor *hcor)
+	__attribute__((weak, alias("__ehci_tdi_reset")));
+
+int __ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+{
+	int ret = 0;
+
+	switch (PORTSC_PSPD(portsc)) {
+	case PORTSC_PSPD_FS:
+		break;
+	case PORTSC_PSPD_LS:
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+	case PORTSC_PSPD_HS:
+	default:
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+	}
+
+	return ret;
+}
+
+int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+	__attribute__((weak, alias("__ehci_port_speed")));
+
+#else  /* CONFIG_EHCI_IS_TDI */
+# define ehci_is_TDI()	(0)
+#endif /* CONFIG_EHCI_IS_TDI */

 void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
 {
@@ -149,8 +189,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 +201,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_tdi_reset(ehcic[index].hcor);

 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -573,10 +604,12 @@  ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
 	} else {
 		dev->act_len = 0;
+#ifndef CONFIG_USB_EHCI_FARADAY
 		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
 		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
 		      ehci_readl(&ctrl->hcor->or_portsc[0]),
 		      ehci_readl(&ctrl->hcor->or_portsc[1]));
+#endif
 	}

 	free(qtd);
@@ -597,6 +630,18 @@  static inline int min3(int a, int b, int c)
 	return a;
 }

+uint32_t *__ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		printf("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	return (uint32_t *)&hcor->or_portsc[port];
+}
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+	__attribute__((weak, alias("__ehci_get_portsc_register")));
+
 int
 ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		 int length, struct devrequest *req)
@@ -609,13 +654,10 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	uint32_t *status_reg;
 	struct ehci_ctrl *ctrl = dev->controller;

-	if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-		printf("The request port(%d) is not configured\n",
-			le16_to_cpu(req->index) - 1);
+	status_reg = ehci_get_portsc_register(ctrl->hcor,
+		le16_to_cpu(req->index) - 1);
+	if (!status_reg)
 		return -1;
-	}
-	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
-						le16_to_cpu(req->index) - 1];
 	srclen = 0;

 	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
@@ -709,23 +751,10 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[0] |= USB_PORT_STAT_RESET;
 		if (reg & EHCI_PS_PP)
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
-
-		if (ehci_is_TDI()) {
-			switch (PORTSC_PSPD(reg)) {
-			case PORTSC_PSPD_FS:
-				break;
-			case PORTSC_PSPD_LS:
-				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
-				break;
-			case PORTSC_PSPD_HS:
-			default:
-				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
-				break;
-			}
-		} else {
+		if (ehci_is_TDI())
+			tmpbuf[1] |= ehci_port_speed(ctrl->hcor, reg) >> 8;
+		else
 			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
-		}
-
 		if (reg & EHCI_PS_CSC)
 			tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
 		if (reg & EHCI_PS_PEC)
@@ -950,10 +979,13 @@  int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);

+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..15b7f01
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,358 @@ 
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FOTG210_H
+#define _FOTG210_H
+
+struct fotg210_regs {
+	/* USB Host Controller */
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t rsvd1[3];
+	uint32_t miscr;	/* 0x40: Miscellaneous Register */
+	uint32_t rsvd2[15];
+	/* USB OTG Controller */
+	uint32_t otgcsr;/* 0x80: OTG Control Status Register */
+	uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */
+	uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */
+	uint32_t rsvd3[13];
+	uint32_t isr;	/* 0xC0: Global Interrupt Status Register */
+	uint32_t imr;	/* 0xC4: Global Interrupt Mask Register */
+	uint32_t rsvd4[14];
+	/* USB Device Controller */
+	uint32_t dev_ctrl;/* 0x100: Device Control Register */
+	uint32_t dev_addr;/* 0x104: Device Address Register */
+	uint32_t dev_test;/* 0x108: Device Test Register */
+	uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */
+	uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */
+	uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */
+	uint32_t rsvd5[2];
+	uint32_t cxfifo;/* 0x120: CX FIFO Register */
+	uint32_t idle;	/* 0x124: IDLE Counter Register */
+	uint32_t rsvd6[2];
+	uint32_t gimr;	/* 0x130: Group Interrupt Mask Register */
+	uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */
+	uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */
+	uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */
+	uint32_t gisr;	/* 0x140: Group Interrupt Status Register */
+	uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */
+	uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */
+	uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */
+	uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */
+	uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */
+	uint32_t isoeasr;/* 0x158: ISOC Error/Abort Status Register */
+	uint32_t rsvd7[1];
+	uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */
+	uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */
+	uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */
+	uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */
+	uint32_t fifomap;/* 0x1a8: FIFO Map Register */
+	uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */
+	uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */
+	uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */
+	uint32_t rsvd8[1];
+	uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */
+	uint32_t dma_addr; /* 0x1cc: DMA Address Register */
+	uint32_t ep0_data; /* 0x1d0: EP0 Setup Packet PIO Register */
+};
+
+/* Miscellaneous Register */
+#define MISCR_SUSPEND  (1 << 6) /* Put transceiver in suspend mode */
+#define MISCR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define MISCR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define MISCR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* OTG Control Status Register */
+#define OTGCSR_SPD_HIGH     (2 << 22) /* Speed of the attached device (host) */
+#define OTGCSR_SPD_LOW      (1 << 22)
+#define OTGCSR_SPD_FULL     (0 << 22)
+#define OTGCSR_SPD_MASK     (3 << 22)
+#define OTGCSR_SPD_SHIFT    22
+#define OTGCSR_SPD(x)       (((x) >> 22) & 0x03)
+#define OTGCSR_DEV_A        (0 << 21) /* Acts as A-device */
+#define OTGCSR_DEV_B        (1 << 21) /* Acts as B-device */
+#define OTGCSR_ROLE_H       (0 << 20) /* Acts as Host */
+#define OTGCSR_ROLE_D       (1 << 20) /* Acts as Device */
+#define OTGCSR_A_VBUS_VLD   (1 << 19) /* A-device VBUS Valid */
+#define OTGCSR_A_SESS_VLD   (1 << 18) /* A-device Session Valid */
+#define OTGCSR_B_SESS_VLD   (1 << 17) /* B-device Session Valid */
+#define OTGCSR_B_SESS_END   (1 << 16) /* B-device Session End */
+#define OTGCSR_HFT_LONG     (1 << 11) /* HDISCON noise filter = 270 us*/
+#define OTGCSR_HFT          (0 << 11) /* HDISCON noise filter = 135 us*/
+#define OTGCSR_VFT_LONG     (1 << 10) /* VBUS noise filter = 472 us*/
+#define OTGCSR_VFT          (0 << 10) /* VBUS noise filter = 135 us*/
+#define OTGCSR_IDFT_LONG    (1 << 9)  /* ID noise filter = 4 ms*/
+#define OTGCSR_IDFT         (0 << 9)  /* ID noise filter = 3 ms*/
+#define OTGCSR_A_SRPR_VBUS  (0 << 8)  /* A-device: SRP responds to VBUS */
+#define OTGCSR_A_SRPR_DATA  (1 << 8)  /* A-device: SRP responds to DATA-LINE */
+#define OTGCSR_A_SRP_EN     (1 << 7)  /* A-device SRP detection enabled */
+#define OTGCSR_A_HNP        (1 << 6)  /* Set role=A-device with HNP enabled */
+#define OTGCSR_A_BUSDROP    (1 << 5)  /* A-device drop bus (power-down) */
+#define OTGCSR_A_BUSREQ     (1 << 4)  /* A-device request bus */
+#define OTGCSR_B_VBUS_DISC  (1 << 2)  /* B-device discharges VBUS */
+#define OTGCSR_B_HNP        (1 << 1)  /* B-device enable HNP */
+#define OTGCSR_B_BUSREQ     (1 << 0)  /* B-device request bus */
+
+/* OTG Interrupt Status Register */
+#define OTGISR_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGISR_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGISR_OVD          (1 << 10) /* over-current detected */
+#define OTGISR_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGISR_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGISR_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGISR_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGISR_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGISR_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* OTG Interrupt Enable Register */
+#define OTGIER_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGIER_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGIER_OVD          (1 << 10) /* over-current detected */
+#define OTGIER_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGIER_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGIER_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGIER_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGIER_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGIER_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* Global Interrupt Status Register */
+#define ISR_HOST            (1 << 2)  /* USB Host interrupt */
+#define ISR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define ISR_DEV             (1 << 0)  /* USB Device interrupt */
+
+/* Global Interrupt Mask Register */
+#define IMR_IRQLH           (1 << 3)  /* Interrupt triggered at level-high */
+#define IMR_IRQLL           (0 << 3)  /* Interrupt triggered at level-low */
+#define IMR_HOST            (1 << 2)  /* USB Host interrupt */
+#define IMR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define IMR_DEV             (1 << 0)  /* USB Device interrupt */
+
+/* Device Control Register */
+#define DEVCTRL_FS_FORCED   (1 << 9)  /* Forced to be Full-Speed Mode */
+#define DEVCTRL_HS          (1 << 6)  /* High Speed Mode */
+#define DEVCTRL_FS          (0 << 6)  /* Full Speed Mode */
+#define DEVCTRL_EN          (1 << 5)  /* Chip Enable */
+#define DEVCTRL_RESET       (1 << 4)  /* Chip Software Reset */
+#define DEVCTRL_SUSPEND     (1 << 3)  /* Enter Suspend Mode */
+#define DEVCTRL_GIRQ_EN     (1 << 2)  /* Global Interrupt Enabled */
+#define DEVCTRL_HALFSPD     (1 << 1)  /* Half speed mode for FPGA test */
+#define DEVCTRL_RWAKEUP     (1 << 0)  /* Enable remote wake-up */
+
+/* Device Address Register */
+#define DEVADDR_CONF        (1 << 7)  /* SET_CONFIGURATION has been executed */
+#define DEVADDR_ADDR(x)     ((x) & 0x7f)
+#define DEVADDR_ADDR_MASK   0x7f
+
+/* Device Test Register */
+#define DEVTEST_NOSOF       (1 << 6)  /* Do not generate SOF */
+#define DEVTEST_TST_MODE    (1 << 5)  /* Enter Test Mode */
+#define DEVTEST_TST_NOTS    (1 << 4)  /* Do not toggle sequence */
+#define DEVTEST_TST_NOCRC   (1 << 3)  /* Do not append CRC */
+#define DEVTEST_TST_CLREA   (1 << 2)  /* Clear External Side Address */
+#define DEVTEST_TST_CXLP    (1 << 1)  /* EP0 loopback test */
+#define DEVTEST_TST_CLRFF   (1 << 0)  /* Clear FIFO */
+
+/* SOF Frame Number Register */
+#define SOFFNR_UFN(x)       (((x) >> 11) & 0x7) /* SOF Micro-Frame Number */
+#define SOFFNR_FNR(x)       ((x) & 0x7ff) /* SOF Frame Number */
+
+/* SOF Mask Timer Register */
+#define SOFMTR_TMR(x)       ((x) & 0xffff)
+
+/* PHY Test Mode Selector Register */
+#define PHYTMSR_TST_PKT     (1 << 4) /* Packet send test */
+#define PHYTMSR_TST_SE0NAK  (1 << 3) /* High-Speed quiescent state */
+#define PHYTMSR_TST_KSTA    (1 << 2) /* High-Speed K state */
+#define PHYTMSR_TST_JSTA    (1 << 1) /* High-Speed J state */
+#define PHYTMSR_UNPLUG      (1 << 0) /* Enable soft-detachment */
+
+/* CX FIFO Register */
+#define CXFIFO_BYTES(x)     (((x) >> 24) & 0x7f) /* CX/EP0 FIFO byte count */
+#define CXFIFO_FIFOE(x)     (1 << (((x) & 0x03) + 8)) /* EPx FIFO empty */
+#define CXFIFO_FIFOE_FIFO0  (1 << 8)
+#define CXFIFO_FIFOE_FIFO1  (1 << 9)
+#define CXFIFO_FIFOE_FIFO2  (1 << 10)
+#define CXFIFO_FIFOE_FIFO3  (1 << 11)
+#define CXFIFO_FIFOE_MASK   (0x0f << 8)
+#define CXFIFO_CXFIFOE      (1 << 5) /* CX FIFO empty */
+#define CXFIFO_CXFIFOF      (1 << 4) /* CX FIFO full */
+#define CXFIFO_CXFIFOCLR    (1 << 3) /* CX FIFO clear */
+#define CXFIFO_CXSTALL      (1 << 2) /* CX Stall */
+#define CXFIFO_TSTPKTFIN    (1 << 1) /* Test packet data transfer finished */
+#define CXFIFO_CXFIN        (1 << 0) /* CX data transfer finished */
+
+/* IDLE Counter Register */
+#define IDLE_MS(x)          ((x) & 0x07) /* PHY suspend delay = x ms */
+
+/* Group Interrupt Mask(Disable) Register */
+#define GIMR_GRP2           (1 << 2) /* Disable interrupt group 2 */
+#define GIMR_GRP1           (1 << 1) /* Disable interrupt group 1 */
+#define GIMR_GRP0           (1 << 0) /* Disable interrupt group 0 */
+
+/* Group Interrupt Mask(Disable) Register 0 (CX) */
+#define GIMR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GIMR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GIMR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GIMR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GIMR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GIMR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+
+/* Group Interrupt Mask(Disable) Register 1 (FIFO) */
+#define GIMR1_FIFO_IN(x)    (1 << (((x) & 3) + 16))    /* FIFOx IN */
+#define GIMR1_FIFO_TX(x)    GIMR1_FIFO_IN(x)
+#define GIMR1_FIFO_OUT(x)   (1 << (((x) & 3) * 2))     /* FIFOx OUT */
+#define GIMR1_FIFO_SPK(x)   (1 << (((x) & 3) * 2 + 1)) /* FIFOx SHORT PACKET */
+#define GIMR1_FIFO_RX(x)    (GIMR1_FIFO_OUT(x) | GIMR1_FIFO_SPK(x))
+
+/* Group Interrupt Mask(Disable) Register 2 (Device) */
+#define GIMR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GIMR2_IDLE          (1 << 9)  /* Device idle */
+#define GIMR2_DMAERR        (1 << 8)  /* DMA error */
+#define GIMR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GIMR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GIMR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GIMR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GIMR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GIMR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GIMR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GIMR2_RESET         (1 << 0)  /* Reset Interrupt */
+
+/* Group Interrupt Status Register */
+#define GISR_GRP2           (1 << 2) /* Disable interrupt group 2 */
+#define GISR_GRP1           (1 << 1) /* Disable interrupt group 1 */
+#define GISR_GRP0           (1 << 0) /* Disable interrupt group 0 */
+
+/* Group Interrupt Status Register 0 (CX) */
+#define GISR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GISR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GISR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GISR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GISR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GISR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+
+/* Group Interrupt Status Register 1 (FIFO) */
+#define GISR1_IN_FIFO(x)    (1 << (((x) & 0x03) + 16))    /* FIFOx IN */
+#define GISR1_OUT_FIFO(x)   (1 << (((x) & 0x03) * 2))     /* FIFOx OUT */
+#define GISR1_SPK_FIFO(x)   (1 << (((x) & 0x03) * 2 + 1)) /* FIFOx SPK */
+#define GISR1_RX_FIFO(x)    (3 << (((x) & 0x03) * 2))     /* FIFOx OUT/SPK */
+
+/* Group Interrupt Status Register 2 (Device) */
+#define GISR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GISR2_IDLE          (1 << 9)  /* Device idle */
+#define GISR2_DMAERR        (1 << 8)  /* DMA error */
+#define GISR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GISR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GISR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GISR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GISR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GISR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GISR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GISR2_RESET         (1 << 0)  /* Reset Interrupt */
+
+/* Receive Zero-Length-Packet Register */
+#define RXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP rx interrupt */
+
+/* Transfer Zero-Length-Packet Register */
+#define TXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP tx interrupt */
+
+/* ISOC Error/Abort Status Register */
+#define ISOEASR_EP(x)       (0x10001 << ((x) - 1)) /* EPx ISOC Error/Abort */
+
+/* IN Endpoint Register */
+#define IEP_SENDZLP         (1 << 15)     /* Send Zero-Length-Packet */
+#define IEP_TNRHB(x)        (((x) & 0x03) << 13) \
+	/* Transaction Number for High-Bandwidth EP(ISOC) */
+#define IEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define IEP_STALL           (1 << 11)     /* Stall */
+#define IEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* OUT Endpoint Register */
+#define OEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define OEP_STALL           (1 << 11)     /* Stall */
+#define OEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* Endpoint Map Register (EP1 ~ EP4) */
+#define EPMAP14_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 0)
+#define EPMAP14_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 4)
+#define EPMAP14_SET(ep, in, out) \
+	do { \
+		EPMAP14_SET_IN(ep, in); \
+		EPMAP14_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP14_DEFAULT     0x33221100 /* EP1->FIFO0, EP2->FIFO1... */
+
+/* Endpoint Map Register (EP5 ~ EP8) */
+#define EPMAP58_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 0)
+#define EPMAP58_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 4)
+#define EPMAP58_SET(ep, in, out) \
+	do { \
+		EPMAP58_SET_IN(ep, in); \
+		EPMAP58_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP58_DEFAULT     0x00000000 /* All EPx->FIFO0 */
+
+/* FIFO Map Register */
+#define FIFOMAP_BIDIR       (2 << 4)
+#define FIFOMAP_IN          (1 << 4)
+#define FIFOMAP_OUT         (0 << 4)
+#define FIFOMAP_DIR_MASK    0x30
+#define FIFOMAP_EP(x)       ((x) & 0x0f)
+#define FIFOMAP_EP_MASK     0x0f
+#define FIFOMAP_CFG_MASK    0x3f
+#define FIFOMAP_DEFAULT     0x04030201 /* FIFO0->EP1, FIFO1->EP2... */
+#define FIFOMAP(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Configuration Register */
+#define FIFOCFG_EN          (1 << 5)
+#define FIFOCFG_BLKSZ_1024  (1 << 4)
+#define FIFOCFG_BLKSZ_512   (0 << 4)
+#define FIFOCFG_3BLK        (2 << 2)
+#define FIFOCFG_2BLK        (1 << 2)
+#define FIFOCFG_1BLK        (0 << 2)
+#define FIFOCFG_NBLK_MASK   3
+#define FIFOCFG_NBLK_SHIFT  2
+#define FIFOCFG_INTR        (3 << 0)
+#define FIFOCFG_BULK        (2 << 0)
+#define FIFOCFG_ISOC        (1 << 0)
+#define FIFOCFG_RSVD        (0 << 0)  /* Reserved */
+#define FIFOCFG_TYPE_MASK   3
+#define FIFOCFG_TYPE_SHIFT  0
+#define FIFOCFG_CFG_MASK    0x3f
+#define FIFOCFG(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Control Status Register */
+#define FIFOCSR_RESET       (1 << 12) /* FIFO Reset */
+#define FIFOCSR_BYTES(x)    ((x) & 0x7ff) /* Length(bytes) for OUT-EP/FIFO */
+
+/* DMA Target FIFO Register */
+#define DMAFIFO_CX          (1 << 4) /* DMA FIFO = CX FIFO */
+#define DMAFIFO_FIFO(x)     (1 << ((x) & 0x3)) /* DMA FIFO = FIFOx */
+
+/* DMA Control Register */
+#define DMACTRL_LEN(x)      (((x) & 0x1ffff) << 8) /* DMA length (Bytes) */
+#define DMACTRL_LEN_SHIFT   8
+#define DMACTRL_CLRFF       (1 << 4) /* Clear FIFO upon DMA abort */
+#define DMACTRL_ABORT       (1 << 3) /* DMA abort */
+#define DMACTRL_IO2IO       (1 << 2) /* IO to IO */
+#define DMACTRL_FIFO2MEM    (0 << 1) /* FIFO to Memory */
+#define DMACTRL_MEM2FIFO    (1 << 1) /* Memory to FIFO */
+#define DMACTRL_START       (1 << 0) /* DMA start */
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..8a9c488
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,61 @@ 
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FUSBH200_H
+#define _FUSBH200_H
+
+struct fusbh200_regs {
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t easstr;/* 0x34: EOF&Async. Sched. Sleep Timer Register */
+	uint32_t rsvd[2];
+	uint32_t bmcsr;	/* 0x40: Bus Monitor Control Status Register */
+	uint32_t bmisr;	/* 0x44: Bus Monitor Interrupt Status Register */
+	uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */
+};
+
+/* EOF & Async. Schedule Sleep Timer Register */
+#define EASSTR_RUNNING  (1 << 6) /* Put transceiver in running/resume mode */
+#define EASSTR_SUSPEND  (0 << 6) /* Put transceiver in suspend mode */
+#define EASSTR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define EASSTR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define EASSTR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* Bus Monitor Control Status Register */
+#define BMCSR_SPD_HIGH  (2 << 9) /* Speed of the attached device */
+#define BMCSR_SPD_LOW   (1 << 9)
+#define BMCSR_SPD_FULL  (0 << 9)
+#define BMCSR_SPD_MASK  (3 << 9)
+#define BMCSR_SPD_SHIFT 9
+#define BMCSR_SPD(x)    ((x >> 9) & 0x03)
+#define BMCSR_VBUS      (1 << 8) /* VBUS Valid */
+#define BMCSR_VBUS_OFF  (1 << 4) /* VBUS Off */
+#define BMCSR_VBUS_ON   (0 << 4) /* VBUS On */
+#define BMCSR_IRQLH     (1 << 3) /* IRQ triggered at level-high */
+#define BMCSR_IRQLL     (0 << 3) /* IRQ triggered at level-low */
+#define BMCSR_HALFSPD   (1 << 2) /* Half speed mode for FPGA test */
+#define BMCSR_HFT_LONG  (1 << 1) /* HDISCON noise filter = 270 us*/
+#define BMCSR_HFT       (0 << 1) /* HDISCON noise filter = 135 us*/
+#define BMCSR_VFT_LONG  (1 << 1) /* VBUS noise filter = 472 us*/
+#define BMCSR_VFT       (0 << 1) /* VBUS noise filter = 135 us*/
+
+/* Bus Monitor Interrupt Status Register */
+/* Bus Monitor Interrupt Enable Register */
+#define BMISR_DMAERR    (1 << 4) /* DMA error */
+#define BMISR_DMA       (1 << 3) /* DMA complete */
+#define BMISR_DEVRM     (1 << 2) /* device removed */
+#define BMISR_OVD       (1 << 1) /* over-current detected */
+#define BMISR_VBUSERR   (1 << 0) /* VBUS error */
+
+#endif