Patchwork [U-Boot,04/11] usb-ehci: add Faraday USB 2.0 EHCI controller support

login
register
mail settings
Submitter Kuo-Jung Su
Date March 29, 2013, 7:06 a.m.
Message ID <1364540788-13943-5-git-send-email-dantesu@gmail.com>
Download mbox | patch
Permalink /patch/232378/
State Superseded
Delegated to: Albert ARIBAUD
Headers show

Comments

Kuo-Jung Su - March 29, 2013, 7:06 a.m.
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>
---
 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

--
1.7.9.5
Marek Vasut - March 30, 2013, 6:29 a.m.
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.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>

You want to fix the magic values here, use readl()/writel() to operate 
registers, kill the BIT() macro and review comments in common files.

Best regards,
Marek Vasut
Kuo-Jung Su - April 1, 2013, 1:21 a.m.
2013/3/30 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.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> You want to fix the magic values here, use readl()/writel() to operate
> registers, kill the BIT() macro and review comments in common files.
>
> Best regards,
> Marek Vasut

Got it, thanks

--
Best wishes,
Kuo-Jung Su

Patch

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 <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 <usb.h>
+
+#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 */