Message ID | 1366963360-2987-9-git-send-email-dantesu@gmail.com |
---|---|
State | Superseded |
Delegated to: | Marek Vasut |
Headers | show |
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(®s->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 *)®s->usb.hccr; > + hcor = (struct ehci_hcor *)®s->usb.hcor; > + > + if (ehci_hci_fotg2xx(hccr)) { > + /* A-device bus reset */ > + /* ... Power off A-device */ > + setbits_le32(®s->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(®s->otg.otgcsr) >> 22) & 0x03; > + else > + speed = (readl(®s->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 */ [...]
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(®s->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 *)®s->usb.hccr; >> + hcor = (struct ehci_hcor *)®s->usb.hcor; >> + >> + if (ehci_hci_fotg2xx(hccr)) { >> + /* A-device bus reset */ >> + /* ... Power off A-device */ >> + setbits_le32(®s->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(®s->otg.otgcsr) >> 22) & 0x03; >> + else >> + speed = (readl(®s->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
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
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
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
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
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 --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(®s->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 *)®s->usb.hccr; + hcor = (struct ehci_hcor *)®s->usb.hcor; + + if (ehci_hci_fotg2xx(hccr)) { + /* A-device bus reset */ + /* ... Power off A-device */ + setbits_le32(®s->otg.otgcsr, BIT_MASK(5)); + /* ... Drop vbus and bus traffic */ + clrbits_le32(®s->otg.otgcsr, BIT_MASK(4)); + mdelay(1); + /* ... Power on A-device */ + clrbits_le32(®s->otg.otgcsr, BIT_MASK(5)); + /* ... Drive vbus and bus traffic */ + setbits_le32(®s->otg.otgcsr, BIT_MASK(4)); + mdelay(1); + /* Disable OTG & device interrupts, interrupt=level-high */ + writel(0x0b, ®s->otg.imr); + /* Clear all interrupt status */ + writel(0x07, ®s->otg.isr); + } else { + /* Interrupt=level-high */ + setbits_le32(®s->usb.bmcsr, BIT_MASK(3)); + /* VBUS on */ + clrbits_le32(®s->usb.bmcsr, BIT_MASK(4)); + /* Disable all interrupts */ + writel(0x00, ®s->usb.bmier); + writel(0x1f, ®s->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(®s->otg.otgcsr) >> 22) & 0x03; + else + speed = (readl(®s->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