diff mbox

[U-Boot,v3,08/11] usb: ehci: add Faraday USB 2.0 EHCI support

Message ID 1366963360-2987-9-git-send-email-dantesu@gmail.com
State Superseded
Delegated to: Marek Vasut
Headers show

Commit Message

Kuo-Jung Su April 26, 2013, 8:02 a.m. UTC
From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch add supports to both Faraday FUSBH200 and FOTG210,
these controllers slightly differ from standard EHCI specification.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
 common/usb_hub.c                |    5 ++
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  122 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |   11 ++++
 drivers/usb/host/ehci.h         |    5 ++
 include/usb/fotg210.h           |   71 +++++++++++++++++++++++
 include/usb/fusbh200.h          |   28 +++++++++
 7 files changed, 243 insertions(+)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

Comments

Marek Vasut April 26, 2013, 12:19 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,
> these controllers slightly differ from standard EHCI specification.

How do they differ?

> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>
> ---
>  common/usb_hub.c                |    5 ++
>  drivers/usb/host/Makefile       |    1 +
>  drivers/usb/host/ehci-faraday.c |  122
> +++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci-hcd.c     | 
>  11 ++++
>  drivers/usb/host/ehci.h         |    5 ++
>  include/usb/fotg210.h           |   71 +++++++++++++++++++++++
>  include/usb/fusbh200.h          |   28 +++++++++
>  7 files changed, 243 insertions(+)
>  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..26d66b8 100644
> --- a/common/usb_hub.c
> +++ b/common/usb_hub.c
> @@ -375,6 +375,11 @@ static int usb_hub_configure(struct usb_device *dev)
>  		return -1;
>  	}
> 
> +#ifdef CONFIG_USB_EHCI_FARADAY
> +	/* Faraday USB 2.0 EHCI chips need a long long delay here */

Why? Do they need it only for root hub or for all the hub down the road as well?

> +	mdelay(250);
> +#endif
> +
>  	if (usb_get_hub_status(dev, buffer) < 0) {
>  		USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",
>  				dev->status);
> 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..adf57d1
> --- /dev/null
> +++ b/drivers/usb/host/ehci-faraday.c
> @@ -0,0 +1,122 @@
> +/*
> + * 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"
> +
> +union ehci_faraday_regs {
> +	struct fusbh200_regs usb;
> +	struct fotg210_regs  otg;
> +};
> +
> +static inline int ehci_hci_fotg2xx(struct ehci_hccr *hccr)
> +{
> +	union ehci_faraday_regs __iomem *regs = (void *)hccr;
> +	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 __iomem *regs;
> +#ifdef CONFIG_USB_EHCI_BASE_LIST
> +	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
> +#else
> +	uint32_t base_list[] = { CONFIG_USB_EHCI_BASE };
> +#endif
> +
> +	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_hci_fotg2xx(hccr)) {
> +		/* A-device bus reset */
> +		/* ... Power off A-device */
> +		setbits_le32(&regs->otg.otgcsr, BIT_MASK(5));

Do these bits not have names?

[...]

> +int ehci_hcd_port_speed(struct ehci_hccr *hccr)
> +{
> +	int ret = 0;
> +	int speed;
> +	union ehci_faraday_regs __iomem *regs = (void *)hccr;
> +
> +	if (ehci_hci_fotg2xx(hccr))
> +		speed = (readl(&regs->otg.otgcsr) >> 22) & 0x03;
> +	else
> +		speed = (readl(&regs->usb.bmcsr) >>  9) & 0x03;

Same here, what're these magic numbers?

> +	switch (speed) {
> +	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;
> +}
> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> index c816878..450d217 100644
> --- a/drivers/usb/host/ehci-hcd.c
> +++ b/drivers/usb/host/ehci-hcd.c
> @@ -149,8 +149,10 @@ static int handshake(uint32_t *ptr, uint32_t mask,
> uint32_t done, int usec) static int ehci_reset(int index)
>  {
>  	uint32_t cmd;
> +#ifndef CONFIG_USB_EHCI_FARADAY
>  	uint32_t tmp;
>  	uint32_t *reg_ptr;
> +#endif
>  	int ret = 0;
> 
>  	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
> @@ -163,6 +165,7 @@ static int ehci_reset(int index)
>  		goto out;
>  	}
> 
> +#ifndef CONFIG_USB_EHCI_FARADAY

Wouldn't it suffice to set your EHCI is not TDI ?

>  	if (ehci_is_TDI()) {
>  		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
>  		tmp = ehci_readl(reg_ptr);
> @@ -172,6 +175,7 @@ static int ehci_reset(int index)
>  #endif
>  		ehci_writel(reg_ptr, tmp);
>  	}
> +#endif	/* !CONFIG_USB_EHCI_FARADAY */

[...]
Kuo-Jung Su April 29, 2013, 3:10 a.m. UTC | #2
2013/4/26 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,
>> these controllers slightly differ from standard EHCI specification.
>
> How do they differ?
>

1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
    are not only un-implemented, but also removed from its register address
    space, which means we have to update the 'struct ehci_hcor' of ehci.h

2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC implementations.
    (It should be a hardware bug, but no one wants to fix it.)

I'll add these description to commit log at next patch.

>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>> ---
>>  common/usb_hub.c                |    5 ++
>>  drivers/usb/host/Makefile       |    1 +
>>  drivers/usb/host/ehci-faraday.c |  122
>> +++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci-hcd.c     |
>>  11 ++++
>>  drivers/usb/host/ehci.h         |    5 ++
>>  include/usb/fotg210.h           |   71 +++++++++++++++++++++++
>>  include/usb/fusbh200.h          |   28 +++++++++
>>  7 files changed, 243 insertions(+)
>>  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..26d66b8 100644
>> --- a/common/usb_hub.c
>> +++ b/common/usb_hub.c
>> @@ -375,6 +375,11 @@ static int usb_hub_configure(struct usb_device *dev)
>>               return -1;
>>       }
>>
>> +#ifdef CONFIG_USB_EHCI_FARADAY
>> +     /* Faraday USB 2.0 EHCI chips need a long long delay here */
>
> Why? Do they need it only for root hub or for all the hub down the road as well?
>

root hub only.

>> +     mdelay(250);
>> +#endif
>> +
>>       if (usb_get_hub_status(dev, buffer) < 0) {
>>               USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",
>>                               dev->status);
>> 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..adf57d1
>> --- /dev/null
>> +++ b/drivers/usb/host/ehci-faraday.c
>> @@ -0,0 +1,122 @@
>> +/*
>> + * 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"
>> +
>> +union ehci_faraday_regs {
>> +     struct fusbh200_regs usb;
>> +     struct fotg210_regs  otg;
>> +};
>> +
>> +static inline int ehci_hci_fotg2xx(struct ehci_hccr *hccr)
>> +{
>> +     union ehci_faraday_regs __iomem *regs = (void *)hccr;
>> +     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 __iomem *regs;
>> +#ifdef CONFIG_USB_EHCI_BASE_LIST
>> +     uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
>> +#else
>> +     uint32_t base_list[] = { CONFIG_USB_EHCI_BASE };
>> +#endif
>> +
>> +     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_hci_fotg2xx(hccr)) {
>> +             /* A-device bus reset */
>> +             /* ... Power off A-device */
>> +             setbits_le32(&regs->otg.otgcsr, BIT_MASK(5));
>
> Do these bits not have names?
>
> [...]
>

Sorry for my laziness, they'll be fixed later.

>> +int ehci_hcd_port_speed(struct ehci_hccr *hccr)
>> +{
>> +     int ret = 0;
>> +     int speed;
>> +     union ehci_faraday_regs __iomem *regs = (void *)hccr;
>> +
>> +     if (ehci_hci_fotg2xx(hccr))
>> +             speed = (readl(&regs->otg.otgcsr) >> 22) & 0x03;
>> +     else
>> +             speed = (readl(&regs->usb.bmcsr) >>  9) & 0x03;
>
> Same here, what're these magic numbers?
>

Sorry for my laziness, they'll be fixed later.

>> +     switch (speed) {
>> +     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;
>> +}
>> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
>> index c816878..450d217 100644
>> --- a/drivers/usb/host/ehci-hcd.c
>> +++ b/drivers/usb/host/ehci-hcd.c
>> @@ -149,8 +149,10 @@ static int handshake(uint32_t *ptr, uint32_t mask,
>> uint32_t done, int usec) static int ehci_reset(int index)
>>  {
>>       uint32_t cmd;
>> +#ifndef CONFIG_USB_EHCI_FARADAY
>>       uint32_t tmp;
>>       uint32_t *reg_ptr;
>> +#endif
>>       int ret = 0;
>>
>>       cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
>> @@ -163,6 +165,7 @@ static int ehci_reset(int index)
>>               goto out;
>>       }
>>
>> +#ifndef CONFIG_USB_EHCI_FARADAY
>
> Wouldn't it suffice to set your EHCI is not TDI ?
>

No, it's surely a TDI design, although we use private registers for
speed detection
(see ehci_hcd_port_speed()) rather then BIT26-27 of PORTSC registers.

>>       if (ehci_is_TDI()) {
>>               reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
>>               tmp = ehci_readl(reg_ptr);
>> @@ -172,6 +175,7 @@ static int ehci_reset(int index)
>>  #endif
>>               ehci_writel(reg_ptr, tmp);
>>       }
>> +#endif       /* !CONFIG_USB_EHCI_FARADAY */
>
> [...]



--
Best wishes,
Kuo-Jung Su
Marek Vasut April 29, 2013, 10:50 p.m. UTC | #3
Dear Kuo-Jung Su,

> 2013/4/26 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,
> >> these controllers slightly differ from standard EHCI specification.
> > 
> > How do they differ?
> 
> 1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
>     are not only un-implemented, but also removed from its register address
>     space, which means we have to update the 'struct ehci_hcor' of ehci.h
> 
> 2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC
> implementations. (It should be a hardware bug, but no one wants to fix
> it.)
> 
> I'll add these description to commit log at next patch.

Mhmmm ... maybe you can add some hooks into ehci-hcd driver instead of poluting 
it with ifdefs ? Weak-aliased functions would probably work best to contain your 
weird stuff in your driver only.

Best regards,
Marek Vasut
Kuo-Jung Su April 30, 2013, 1:32 a.m. UTC | #4
2013/4/30 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> 2013/4/26 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,
>> >> these controllers slightly differ from standard EHCI specification.
>> >
>> > How do they differ?
>>
>> 1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
>>     are not only un-implemented, but also removed from its register address
>>     space, which means we have to update the 'struct ehci_hcor' of ehci.h
>>
>> 2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC
>> implementations. (It should be a hardware bug, but no one wants to fix
>> it.)
>>
>> I'll add these description to commit log at next patch.
>
> Mhmmm ... maybe you can add some hooks into ehci-hcd driver instead of poluting
> it with ifdefs ? Weak-aliased functions would probably work best to contain your
> weird stuff in your driver only.
>

Did you mean 'Not poluting ehci.h with ifdefs' ?

It looks to me that the best way is to leave ehci.h untouched, and
update the ehci_submit_root() as following:
----------------------------
ehci_submit_root()
{
......
#ifdef CONFIG_USB_EHCI_FARADAY
    status_reg = (uint32_t *)((uint8_t *)&ctrl->hcor + 0x30);
#else
    status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
                 le16_to_cpu(req->index) - 1];
#endif
......
}
------------------------------

Would it be acceptable in this way?

If it's not, I'll make this patch as a separate patch with some hooks
into ehci-hcd.

> Best regards,
> Marek Vasut




--
Best wishes,
Kuo-Jung Su
Marek Vasut May 1, 2013, 7:34 p.m. UTC | #5
Dear Kuo-Jung Su,

> 2013/4/30 Marek Vasut <marex@denx.de>:
> > Dear Kuo-Jung Su,
> > 
> >> 2013/4/26 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,
> >> >> these controllers slightly differ from standard EHCI specification.
> >> > 
> >> > How do they differ?
> >> 
> >> 1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
> >> 
> >>     are not only un-implemented, but also removed from its register
> >>     address space, which means we have to update the 'struct ehci_hcor'
> >>     of ehci.h
> >> 
> >> 2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC
> >> implementations. (It should be a hardware bug, but no one wants to fix
> >> it.)
> >> 
> >> I'll add these description to commit log at next patch.
> > 
> > Mhmmm ... maybe you can add some hooks into ehci-hcd driver instead of
> > poluting it with ifdefs ? Weak-aliased functions would probably work
> > best to contain your weird stuff in your driver only.
> 
> Did you mean 'Not poluting ehci.h with ifdefs' ?
> 
> It looks to me that the best way is to leave ehci.h untouched, and
> update the ehci_submit_root() as following:
> ----------------------------
> ehci_submit_root()
> {
> ......
> #ifdef CONFIG_USB_EHCI_FARADAY
>     status_reg = (uint32_t *)((uint8_t *)&ctrl->hcor + 0x30);
> #else
>     status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
>                  le16_to_cpu(req->index) - 1];
> #endif
> ......
> }
> ------------------------------
> 
> Would it be acceptable in this way?
> 
> If it's not, I'll make this patch as a separate patch with some hooks
> into ehci-hcd.

What about defining a

__weak uint32_t get_status_register()
{
...
}

function and override it's implementation in your driver?

Best regards,
Marek Vasut
Kuo-Jung Su May 2, 2013, 1:14 a.m. UTC | #6
2013/5/2 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> 2013/4/30 Marek Vasut <marex@denx.de>:
>> > Dear Kuo-Jung Su,
>> >
>> >> 2013/4/26 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,
>> >> >> these controllers slightly differ from standard EHCI specification.
>> >> >
>> >> > How do they differ?
>> >>
>> >> 1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
>> >>
>> >>     are not only un-implemented, but also removed from its register
>> >>     address space, which means we have to update the 'struct ehci_hcor'
>> >>     of ehci.h
>> >>
>> >> 2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC
>> >> implementations. (It should be a hardware bug, but no one wants to fix
>> >> it.)
>> >>
>> >> I'll add these description to commit log at next patch.
>> >
>> > Mhmmm ... maybe you can add some hooks into ehci-hcd driver instead of
>> > poluting it with ifdefs ? Weak-aliased functions would probably work
>> > best to contain your weird stuff in your driver only.
>>
>> Did you mean 'Not poluting ehci.h with ifdefs' ?
>>
>> It looks to me that the best way is to leave ehci.h untouched, and
>> update the ehci_submit_root() as following:
>> ----------------------------
>> ehci_submit_root()
>> {
>> ......
>> #ifdef CONFIG_USB_EHCI_FARADAY
>>     status_reg = (uint32_t *)((uint8_t *)&ctrl->hcor + 0x30);
>> #else
>>     status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
>>                  le16_to_cpu(req->index) - 1];
>> #endif
>> ......
>> }
>> ------------------------------
>>
>> Would it be acceptable in this way?
>>
>> If it's not, I'll make this patch as a separate patch with some hooks
>> into ehci-hcd.
>
> What about defining a
>
> __weak uint32_t get_status_register()
> {
> ...
> }
>
> function and override it's implementation in your driver?
>

That's a great idea, I'll update it in this way at next version.

Thanks

> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su
Kuo-Jung Su May 7, 2013, 6:26 a.m. UTC | #7
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.

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

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 (2):
  usb: ehci: add Faraday USB 2.0 EHCI support
  usb: gadget: add Faraday FOTG210 USB gadget support

 common/usb_hub.c                  |   13 +-
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  961 +++++++++++++++++++++++++++++++++++++
 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             |  358 ++++++++++++++
 include/usb/fusbh200.h            |   61 +++
 9 files changed, 1616 insertions(+), 37 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..26d66b8 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -375,6 +375,11 @@  static int usb_hub_configure(struct usb_device *dev)
 		return -1;
 	}
 
+#ifdef CONFIG_USB_EHCI_FARADAY
+	/* Faraday USB 2.0 EHCI chips need a long long delay here */
+	mdelay(250);
+#endif
+
 	if (usb_get_hub_status(dev, buffer) < 0) {
 		USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",
 				dev->status);
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..adf57d1
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,122 @@ 
+/*
+ * 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"
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_hci_fotg2xx(struct ehci_hccr *hccr)
+{
+	union ehci_faraday_regs __iomem *regs = (void *)hccr;
+	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 __iomem *regs;
+#ifdef CONFIG_USB_EHCI_BASE_LIST
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+#else
+	uint32_t base_list[] = { CONFIG_USB_EHCI_BASE };
+#endif
+
+	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_hci_fotg2xx(hccr)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, BIT_MASK(5));
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, BIT_MASK(4));
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, BIT_MASK(5));
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, BIT_MASK(4));
+		mdelay(1);
+		/* Disable OTG & device interrupts, interrupt=level-high */
+		writel(0x0b, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(0x07, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BIT_MASK(3));
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BIT_MASK(4));
+		/* 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;
+}
+
+int ehci_hcd_port_speed(struct ehci_hccr *hccr)
+{
+	int ret = 0;
+	int speed;
+	union ehci_faraday_regs __iomem *regs = (void *)hccr;
+
+	if (ehci_hci_fotg2xx(hccr))
+		speed = (readl(&regs->otg.otgcsr) >> 22) & 0x03;
+	else
+		speed = (readl(&regs->usb.bmcsr) >>  9) & 0x03;
+
+	switch (speed) {
+	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;
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..450d217 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -149,8 +149,10 @@  static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 static int ehci_reset(int index)
 {
 	uint32_t cmd;
+#ifndef CONFIG_USB_EHCI_FARADAY
 	uint32_t tmp;
 	uint32_t *reg_ptr;
+#endif
 	int ret = 0;
 
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
@@ -163,6 +165,7 @@  static int ehci_reset(int index)
 		goto out;
 	}
 
+#ifndef CONFIG_USB_EHCI_FARADAY
 	if (ehci_is_TDI()) {
 		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
 		tmp = ehci_readl(reg_ptr);
@@ -172,6 +175,7 @@  static int ehci_reset(int index)
 #endif
 		ehci_writel(reg_ptr, tmp);
 	}
+#endif	/* !CONFIG_USB_EHCI_FARADAY */
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -711,6 +715,9 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
 
 		if (ehci_is_TDI()) {
+#ifdef CONFIG_USB_EHCI_FARADAY
+			tmpbuf[1] |= ehci_hcd_port_speed(ctrl->hccr) >> 8;
+#else
 			switch (PORTSC_PSPD(reg)) {
 			case PORTSC_PSPD_FS:
 				break;
@@ -722,6 +729,7 @@  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 				break;
 			}
+#endif
 		} else {
 			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 		}
@@ -950,10 +958,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/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index d090f0a..9309ede 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -82,6 +82,7 @@  struct ehci_hcor {
 	uint32_t or_periodiclistbase;
 	uint32_t or_asynclistaddr;
 	uint32_t _reserved_0_;
+#ifndef CONFIG_USB_EHCI_FARADAY
 	uint32_t or_burstsize;
 	uint32_t or_txfilltuning;
 #define TXFIFO_THRESH_MASK		(0x3f << 16)
@@ -89,6 +90,7 @@  struct ehci_hcor {
 	uint32_t _reserved_1_[6];
 	uint32_t or_configflag;
 #define FLAG_CF		(1 << 0)	/* true:  we'll support "high speed" */
+#endif  /* #ifndef CONFIG_USB_EHCI_FARADAY */
 	uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
 #define PORTSC_PSPD(x)		(((x) >> 26) & 0x3)
 #define PORTSC_PSPD_FS			0x0
@@ -255,5 +257,8 @@  struct QH {
 /* Low level init functions */
 int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor);
 int ehci_hcd_stop(int index);
+#ifdef CONFIG_USB_EHCI_FARADAY
+int ehci_hcd_port_speed(struct ehci_hccr *hccr);
+#endif
 
 #endif /* USB_EHCI_H */
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..0249afd
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,71 @@ 
+/*
+ * 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 msicr;	/* 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[1];
+	uint32_t cxsr;	/* 0x11c: CX Status Register */
+	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 ioseasr;/* 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 dma_data; /* 0x1d0: DMA CX Data Register */
+};
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..2d514b8
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,28 @@ 
+/*
+ * 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. Schedule 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 */
+};
+
+#endif