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

Kuo-Jung Su
2013-04-29T03:10:19Z

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