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

Kuo-Jung Su
2013-04-26T08:02:37Z

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

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
--
1.7.9.5