All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [RFC USB PATCH] USB ehci fix and test on ixp4xx hardware
@ 2008-12-12 10:00 Michael Trimarchi
  2008-12-12 10:19 ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 6+ messages in thread
From: Michael Trimarchi @ 2008-12-12 10:00 UTC (permalink / raw)
  To: u-boot

EHCI fix code and ixp4xx test.
USB ehci configuration parameter:

#define CONFIG_CMD_USB          1
#define CONFIG_USB_STORAGE      1
#define CONFIG_USB_EHCI
#define CONFIG_USB_EHCI_IXP4XX          1
#define CONFIG_EHCI_IS_TDI              1
#define CONFIG_EHCI_DESC_BIG_ENDIAN     1
#define CONFIG_EHCI_MMIO_BIG_ENDIAN     1
#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2
#define CONFIG_LEGACY_USB_INIT_SEQ      1

2 USB Device(s) found
       scanning bus for storage devices... 0 Storage Device(s) found
=> usb tree

Device Tree:
  1  Hub (1.5MBit/s, 0mA)
  |  u-boot EHCI Host Controller
  |
  |+-2  Mass Storage (12MBit/s, 100mA)
       Sony Storage Media 0C07040930296

=>

Signed-off-by: Michael Trimarchi <trimarchimichael@yahoo.it>

---
 drivers/usb/usb_ehci.h      |   49 ++++++++++--------
 drivers/usb/usb_ehci_core.c |  122 ++++++++++++++++++++++++++----------------
 2 files changed, 102 insertions(+), 69 deletions(-)

diff --git a/drivers/usb/usb_ehci.h b/drivers/usb/usb_ehci.h
index 90b137a..9e8e7b2 100644
--- a/drivers/usb/usb_ehci.h
+++ b/drivers/usb/usb_ehci.h
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2007-2008, Juniper Networks, Inc.
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -21,6 +22,10 @@
 #ifndef USB_EHCI_H
 #define USB_EHCI_H
 
+#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
+#error "USB EHCI define MAX_ROOT_PORTS"
+#endif
+
 /* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */
 #define DeviceRequest \
 	((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8)
@@ -45,10 +50,12 @@ struct ehci_hccr {
 #define HC_LENGTH(p)		(((p) >> 0) & 0x00ff)
 #define HC_VERSION(p)		(((p) >> 16) & 0xffff)
 	uint32_t cr_hcsparams;
+#define HCS_PPC(p)		((p) & (1 << 4))
+#define HCS_INDICATOR(p)        ((p) & (1 << 16)) /* Port indicators */
 #define HCS_N_PORTS(p)		(((p) >> 0) & 0xf)
 	uint32_t cr_hccparams;
 	uint8_t cr_hcsp_portrt[8];
-};
+} __attribute__ ((packed));
 
 struct ehci_hcor {
 	uint32_t or_usbcmd;
@@ -71,9 +78,9 @@ struct ehci_hcor {
 	uint32_t _reserved_[9];
 	uint32_t or_configflag;
 #define FLAG_CF		(1 << 0)	/* true:  we'll support "high speed" */
-	uint32_t or_portsc[2];
+	uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
 	uint32_t or_systune;
-};
+} __attribute__ ((packed));
 
 #define USBMODE		0x68		/* USB Device mode */
 #define USBMODE_SDIS	(1 << 3)	/* Stream disable */
@@ -123,26 +130,24 @@ struct usb_linux_config_descriptor {
 #define cpu_to_hc32(x)		cpu_to_le32((x))
 #endif
 
-#define EHCI_PS_WKOC_E		0x00400000	/* RW wake on over current */
-#define EHCI_PS_WKDSCNNT_E	0x00200000	/* RW wake on disconnect */
-#define EHCI_PS_WKCNNT_E	0x00100000	/* RW wake on connect */
-#define EHCI_PS_PTC		0x000f0000	/* RW port test control */
-#define EHCI_PS_PIC		0x0000c000	/* RW port indicator control */
-#define EHCI_PS_PO		0x00002000	/* RW port owner */
-#define EHCI_PS_PP		0x00001000	/* RW,RO port power */
-#define EHCI_PS_LS		0x00000c00	/* RO line status */
-#define EHCI_PS_PR		0x00000100	/* RW port reset */
-#define EHCI_PS_SUSP		0x00000080	/* RW suspend */
-#define EHCI_PS_FPR		0x00000040	/* RW force port resume */
-#define EHCI_PS_OCC		0x00000020	/* RWC over current change */
-#define EHCI_PS_OCA		0x00000010	/* RO over current active */
-#define EHCI_PS_PEC		0x00000008	/* RWC port enable change */
-#define EHCI_PS_PE		0x00000004	/* RW port enable */
-#define EHCI_PS_CSC		0x00000002	/* RWC connect status change */
-#define EHCI_PS_CS		0x00000001	/* RO connect status */
+#define EHCI_PS_WKOC_E		(1 << 22)	/* RW wake on over current */
+#define EHCI_PS_WKDSCNNT_E	(1 << 21)	/* RW wake on disconnect */
+#define EHCI_PS_WKCNNT_E	(1 << 20)	/* RW wake on connect */
+#define EHCI_PS_PO		(1 << 13)	/* RW port owner */
+#define EHCI_PS_PP		(1 << 12)	/* RW,RO port power */
+#define EHCI_PS_LS		(3 << 10)	/* RO line status */
+#define EHCI_PS_PR		(1 << 8)	/* RW port reset */
+#define EHCI_PS_SUSP		(1 << 7)	/* RW suspend */
+#define EHCI_PS_FPR		(1 << 6)	/* RW force port resume */
+#define EHCI_PS_OCC		(1 << 5)	/* RWC over current change */
+#define EHCI_PS_OCA		(1 << 4)	/* RO over current active */
+#define EHCI_PS_PEC		(1 << 3)	/* RWC port enable change */
+#define EHCI_PS_PE		(1 << 2)	/* RW port enable */
+#define EHCI_PS_CSC		(1 << 1)	/* RWC connect status change */
+#define EHCI_PS_CS		(1 << 0)	/* RO connect status */
 #define EHCI_PS_CLEAR		(EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC)
 
-#define EHCI_PS_IS_LOWSPEED(x)	(((x) & EHCI_PS_LS) == 0x00000400)
+#define EHCI_PS_IS_LOWSPEED(x)	(((x) & EHCI_PS_LS) == (1 << 10))
 
 /*
  * Schedule Interface Space.
@@ -178,7 +183,7 @@ struct QH {
 };
 
 /* Low level intit functions */
-
 int ehci_hcd_init(void);
 int ehci_hcd_stop(void);
+
 #endif /* USB_EHCI_H */
diff --git a/drivers/usb/usb_ehci_core.c b/drivers/usb/usb_ehci_core.c
index ec50874..167867e 100644
--- a/drivers/usb/usb_ehci_core.c
+++ b/drivers/usb/usb_ehci_core.c
@@ -1,6 +1,7 @@
 /*-
  * Copyright (c) 2007-2008, Juniper Networks, Inc.
  * Copyright (c) 2008, Excito Elektronik i Sk?ne AB
+ * Copyright (c) 2008, Michael Trimarchi <trimarchimichael@yahoo.it>
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -18,7 +19,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
  */
-#define DEBUG
 #include <common.h>
 #include <asm/byteorder.h>
 #include <usb.h>
@@ -99,6 +99,12 @@ static struct descriptor {
 	},
 };
 
+#if defined CONFIG_EHCI_IS_TDI
+#define ehci_is_TDI()	1
+#else
+#define ehci_is_TDI()	0
+#endif
+
 static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int msec)
 {
 	uint32_t result;
@@ -131,7 +137,7 @@ static int ehci_reset(void)
 	cmd = ehci_readl(&hcor->or_usbcmd);
 	cmd |= CMD_RESET;
 	ehci_writel(&hcor->or_usbcmd, cmd);
-	ret = handshake(&hcor->or_usbcmd, CMD_RESET, 0, 250);
+	ret = handshake((uint32_t *)&hcor->or_usbcmd, CMD_RESET, 0, 250);
 	if (ret < 0) {
 		printf("EHCI fail to reset\n");
 		goto out;
@@ -427,7 +433,15 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	void *srcptr = NULL;
 	int len, srclen;
 	uint32_t reg;
+	uint32_t *status_reg;
 
+	if (le16_to_cpu(req->index) >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		printf("The request port(%d) is not configured\n",
+			le16_to_cpu(req->index) - 1);
+		return -1;
+	}
+	status_reg = (uint32_t *)&hcor->or_portsc[
+						le16_to_cpu(req->index) - 1];
 	srclen = 0;
 
 	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
@@ -506,8 +520,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		break;
 	case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
 		memset(tmpbuf, 0, 4);
-		reg = ehci_readl(&hcor->or_portsc[le16_to_cpu(req->index)
-				   - 1]);
+		reg = ehci_readl(status_reg);
 		if (reg & EHCI_PS_CS)
 			tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
 		if (reg & EHCI_PS_PE)
@@ -516,8 +529,19 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[0] |= USB_PORT_STAT_SUSPEND;
 		if (reg & EHCI_PS_OCA)
 			tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT;
-		if (reg & EHCI_PS_PR)
-			tmpbuf[0] |= USB_PORT_STAT_RESET;
+		if (reg & EHCI_PS_PR &&
+		    (portreset & (1 << le16_to_cpu(req->index)))) {
+			int ret;
+			/* force reset to complete */
+			reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR);
+			ehci_writel(status_reg, reg);
+			ret = handshake(status_reg, EHCI_PS_PR, 0, 2);
+			if (!ret)
+				tmpbuf[0] |= USB_PORT_STAT_RESET;
+			else
+				printf("port(%d) reset error\n",
+					le16_to_cpu(req->index) - 1);
+		}
 		if (reg & EHCI_PS_PP)
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
 		tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
@@ -530,73 +554,71 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT;
 		if (portreset & (1 << le16_to_cpu(req->index)))
 			tmpbuf[2] |= USB_PORT_STAT_C_RESET;
+
 		srcptr = tmpbuf;
 		srclen = 4;
 		break;
 	case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
-		reg = ehci_readl(&hcor->or_portsc[le16_to_cpu(req->index) - 1]);
+		reg = ehci_readl(status_reg);
 		reg &= ~EHCI_PS_CLEAR;
 		switch (le16_to_cpu(req->value)) {
 		case USB_PORT_FEAT_ENABLE:
 			reg |= EHCI_PS_PE;
+			ehci_writel(status_reg, reg);
 			break;
 		case USB_PORT_FEAT_POWER:
-			reg |= EHCI_PS_PP;
+			if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams))) {
+				reg |= EHCI_PS_PP;
+				ehci_writel(status_reg, reg);
+			}
 			break;
 		case USB_PORT_FEAT_RESET:
-			debug("USB FEAT RESET\n");
-			if (EHCI_PS_IS_LOWSPEED(reg)) {
+			if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS &&
+			    !ehci_is_TDI() &&
+			    EHCI_PS_IS_LOWSPEED(reg)) {
 				/* Low speed device, give up ownership. */
+				debug("port %d low speed --> companion\n",
+				      req->index - 1);
 				reg |= EHCI_PS_PO;
+				ehci_writel(status_reg, reg);
 				break;
+			} else {
+				reg |= EHCI_PS_PR;
+				reg &= ~EHCI_PS_PE;
+				ehci_writel(status_reg, reg);
+				/*
+				 * caller must wait, then call GetPortStatus
+				 * usb 2.0 specification say 50 ms resets on
+				 * root
+				 */
+				wait_ms(50);
+				portreset |= 1 << le16_to_cpu(req->index);
 			}
-			/* Start reset sequence. */
-			reg &= ~EHCI_PS_PE;
-			reg |= EHCI_PS_PR;
-			ehci_writel(&hcor->or_portsc[
-				le16_to_cpu(req->index) - 1], reg);
-			/* Wait for reset to complete. */
-			wait_ms(500);
-			/* Terminate reset sequence. */
-			reg &= ~EHCI_PS_PR;
-			/* TODO: is it only fsl chip that requires this
-			 * manual setting of port enable?
-			 */
-			reg |= EHCI_PS_PE;
-			ehci_writel(&hcor->or_portsc[
-				le16_to_cpu(req->index) - 1], reg);
-			/* Wait for HC to complete reset. */
-			wait_ms(10);
-			reg =
-			    ehci_readl(&hcor->or_portsc[le16_to_cpu(req->index)
-							- 1]);
-			reg &= ~EHCI_PS_CLEAR;
-			if ((reg & EHCI_PS_PE) == 0) {
-				/* Not a high speed device, give up
-				 * ownership. */
-				reg |= EHCI_PS_PO;
-				break;
-			}
-			portreset |= 1 << le16_to_cpu(req->index);
 			break;
 		default:
 			debug("unknown feature %x\n", le16_to_cpu(req->value));
 			goto unknown;
 		}
-		ehci_writel(&hcor->or_portsc[le16_to_cpu(req->index) - 1], reg);
+		/* unblock posted writes */
+		ehci_readl(&hcor->or_usbcmd);
 		break;
 	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
-		reg = ehci_readl(&hcor->or_portsc[le16_to_cpu(req->index) - 1]);
-		reg &= ~EHCI_PS_CLEAR;
+		reg = ehci_readl(status_reg);
 		switch (le16_to_cpu(req->value)) {
 		case USB_PORT_FEAT_ENABLE:
 			reg &= ~EHCI_PS_PE;
 			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE;
+			break;
+		case USB_PORT_FEAT_POWER:
+			if (HCS_PPC(ehci_readl(&hccr->cr_hcsparams)))
+				reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP);
 		case USB_PORT_FEAT_C_CONNECTION:
-			reg |= EHCI_PS_CSC;
+			reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC;
 			break;
 		case USB_PORT_FEAT_OVER_CURRENT:
-			reg |= EHCI_PS_OCC;
+			reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC;
 			break;
 		case USB_PORT_FEAT_C_RESET:
 			portreset &= ~(1 << le16_to_cpu(req->index));
@@ -605,7 +627,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			debug("unknown feature %x\n", le16_to_cpu(req->value));
 			goto unknown;
 		}
-		ehci_writel(&hcor->or_portsc[le16_to_cpu(req->index) - 1], reg);
+		ehci_writel(status_reg, reg);
+		/* unblock posted write */
+		ehci_readl(&hcor->or_usbcmd);
 		break;
 	default:
 		debug("Unknown request\n");
@@ -665,9 +689,11 @@ int usb_lowlevel_init(void)
 	reg = ehci_readl(&hccr->cr_hcsparams);
 	descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
 	printf("Register %x NbrPorts %d\n", reg, descriptor.hub.bNbrPorts);
-	if (reg & 0x10000)	/* Port Indicators */
+	/* Port Indicators */
+	if (HCS_INDICATOR(reg))
 		descriptor.hub.wHubCharacteristics |= 0x80;
-	if (reg & 0x10)		/* Port Power Control */
+	/* Port Power Control */
+	if (HCS_PPC(reg))
 		descriptor.hub.wHubCharacteristics |= 0x01;
 
 	/* Start the host controller. */
@@ -682,9 +708,11 @@ int usb_lowlevel_init(void)
 	cmd = ehci_readl(&hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&hcor->or_configflag, cmd);
-	/* unblock posted writes */
+	/* unblock posted write */
 	cmd = ehci_readl(&hcor->or_usbcmd);
 	wait_ms(5);
+	reg = HC_VERSION(ehci_readl(&hccr->cr_capbase));
+	printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
 
 	rootdev = 0;
 
-- 
1.5.6.5

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2008-12-12 11:40 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-12 10:00 [U-Boot] [RFC USB PATCH] USB ehci fix and test on ixp4xx hardware Michael Trimarchi
2008-12-12 10:19 ` Jean-Christophe PLAGNIOL-VILLARD
2008-12-12 10:35   ` michael
2008-12-12 10:39   ` Stefan Roese
2008-12-12 10:42     ` [U-Boot] [RFC USB PATCH] USB ehci fix and test on ixp4xx?hardware Jean-Christophe PLAGNIOL-VILLARD
2008-12-12 11:40     ` [U-Boot] [RFC USB PATCH] USB ehci fix and test on ixp4xx hardware Remy Bohmer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.