From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kuo-Jung Su Date: Fri, 29 Mar 2013 15:06:21 +0800 Subject: [U-Boot] [PATCH 04/11] usb-ehci: add Faraday USB 2.0 EHCI controller support In-Reply-To: <1364540788-13943-1-git-send-email-dantesu@gmail.com> References: <1364540788-13943-1-git-send-email-dantesu@gmail.com> Message-ID: <1364540788-13943-5-git-send-email-dantesu@gmail.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de From: Kuo-Jung Su This patch add supports to both Faraday FUSBH200 and FOTG210, these controllers slightly differ from standard EHCI specification. Signed-off-by: Kuo-Jung Su --- common/usb_hub.c | 5 ++ drivers/usb/host/Makefile | 1 + drivers/usb/host/ehci-faraday.c | 157 +++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci-hcd.c | 11 +++ drivers/usb/host/ehci.h | 5 ++ 5 files changed, 179 insertions(+) create mode 100644 drivers/usb/host/ehci-faraday.c diff --git a/common/usb_hub.c b/common/usb_hub.c index b5eeb62..099696e 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 + /* dante: fusbh200 requires a long long delay ... */ + 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 9a6f982..d5577bd 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -44,6 +44,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..a5a6394 --- /dev/null +++ b/drivers/usb/host/ehci-faraday.c @@ -0,0 +1,157 @@ +/* + * Faraday USB 2.0 EHCI Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su + * + * 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 +#include + +#include "ehci.h" + +#ifndef BIT +#define BIT(nr) (1UL << (nr)) +#endif + +/* Lower Timing for FPGA Mode */ +#define CFG_LOWER_TIMING 0 + +struct faraday_usb_hcd { + uint32_t iobase; +}; + +static struct faraday_usb_hcd faraday_usb_hcd_info[] = { +#ifdef CONFIG_USB_EHCI_BASE + { .iobase = CONFIG_USB_EHCI_BASE, }, +#endif +#ifdef CONFIG_USB_EHCI_BASE1 + { .iobase = CONFIG_USB_EHCI_BASE1, }, +#endif +}; + +#define HCD_REG32(chip, off) \ + *(volatile uint32_t *)((chip)->iobase + (off)) + +static inline int ehci_hci_fotg2xx(struct ehci_hccr *hccr) +{ + uint32_t iobase = (uint32_t)hccr; + return !REG32(iobase + 0x34) || REG32(iobase + 0x34) == 0xffffffff; +} + +/* + * 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 faraday_usb_hcd *hcd = &faraday_usb_hcd_info[index]; + struct ehci_hccr *hccr; + struct ehci_hcor *hcor; + + hccr = (struct ehci_hccr *)hcd->iobase; + hcor = (struct ehci_hcor *)(hcd->iobase + + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); + + if (ehci_hci_fotg2xx(hccr)) { + + /* A-device bus reset */ + HCD_REG32(hcd, 0x80) |= BIT(5); + HCD_REG32(hcd, 0x80) &= ~BIT(4); + mdelay(1); + HCD_REG32(hcd, 0x80) &= ~BIT(5); + HCD_REG32(hcd, 0x80) |= BIT(4); + mdelay(1); + + /* Reset interrupt */ + HCD_REG32(hcd, 0xC0) = 7; + + /* Disable OTG & device interrupts */ + HCD_REG32(hcd, 0xC4) = 3; + + /* Set interrupt polarity to active high */ + HCD_REG32(hcd, 0xC4) |= BIT(3); + + /* In FPGA mode (15MHz <= AHB <= 30MHz), enter half speed mode. */ + if (clk_get_rate("AHB") <= 30000000) { + HCD_REG32(hcd, 0x100) |= BIT(1); + printf("fotg210: AHB is too slow, enter half-speed mode.\n"); + } + +#ifdef CFG_LOWER_TIMING + HCD_REG32(hcd, 0x40) |= 0x0d; +#endif + + } else { + + /* Set interrupt polarity to active high */ + HCD_REG32(hcd, 0x40) |= BIT(3); + + /* In FPGA mode (15MHz <= AHB <= 30MHz), enter half speed mode. */ + if (clk_get_rate("AHB") <= 30000000) { + HCD_REG32(hcd, 0x40) |= BIT(2); + printf("fusbh200: AHB is too slow, enter half-speed mode.\n"); + } + +#ifdef CFG_LOWER_TIMING + HCD_REG32(hcd, 0x34) |= (3 << 2) | (1 << 0); +#endif + + /* Turn on VBUS */ + HCD_REG32(hcd, 0x40) &= ~BIT(4); + + /* Enable over-current & vbus error interrupts */ + HCD_REG32(hcd, 0x44) = 0x1F; + HCD_REG32(hcd, 0x48) |= BIT(1) | BIT(0); + + } + + *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 rc = 0; + int speed; + uint32_t iobase = (uint32_t)hccr; + + if (ehci_hci_fotg2xx(hccr)) + speed = (REG32(iobase + 0x80) >> 22) & 0x03; + else + speed = (REG32(iobase + 0x40) >> 9) & 0x03; + + switch (speed) { + case 0: /* full speed */ + break; + + case 1: /* low speed */ + rc = USB_PORT_STAT_LOW_SPEED; + break; + + case 2: /* high speed */ + rc = USB_PORT_STAT_HIGH_SPEED; + break; + + default: + printf("faraday-usb: invalid device speed\n"); + break; + } + + return rc; +} 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 */ -- 1.7.9.5