[U-Boot-Users] [PATCH] (modified) USB OHCI support for Au1x00 fixed

Rodolfo Giometti giometti at linux.it
Tue May 30 16:38:39 CEST 2006


On Tue, May 30, 2006 at 03:07:32PM +0200, Rodolfo Giometti wrote:
> Hello,
> 
> here my "modified" and smaller patch for USB OHCI support on au1x00. I
> removed unneeded modifications.

Sorry, I forgot the patch...

Rodolfo

-- 

GNU/Linux Solutions                  e-mail:    giometti at enneenne.com
Linux Device Driver                             giometti at gnudd.com
Embedded Systems                     		giometti at linux.it
UNIX programming                     phone:     +39 349 2432127
-------------- next part --------------
diff --git a/cpu/mips/au1x00_usb_ohci.c b/cpu/mips/au1x00_usb_ohci.c
index dbf72dc..67d4eb3 100644
--- a/cpu/mips/au1x00_usb_ohci.c
+++ b/cpu/mips/au1x00_usb_ohci.c
@@ -1,9 +1,23 @@
 /*
  * URB OHCI HCD (Host Controller Driver) for USB on the AU1x00.
  *
- * (C) Copyright 2003
+ * (C) Copyright 2006
+ * Rodolfo Giometti <giometti at linux.it>
+ * Eurotech S.p.A. <info at eurotech.it>
+ *
+ * Based on "cpu/mpc5xxx/usb_ohci.c".
+ * Original copyright message:
+ *
+ * (C) Copyright 2003-2004
  * Gary Jennejohn, DENX Software Engineering <gj at denx.de>
  *
+ * (C) Copyright 2004
+ * Pierre Aubert, Staubli Faverges <p.aubert at staubli.com>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg at vienna.at>
+ * (C) Copyright 2000-2002 David Brownell
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -22,76 +36,49 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
  *
- * Note: Part of this code has been derived from linux
- *
  */
 /*
  * IMPORTANT NOTES
- * 1 - you MUST define LITTLEENDIAN in the configuration file for the
- *     board or this driver will NOT work!
- * 2 - this driver is intended for use with USB Mass Storage Devices
+ * 1 - this driver is intended for use with USB Mass Storage Devices
  *     (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
  */
 
-#include <config.h>
-
-#if defined(CONFIG_AU1X00) && defined(CONFIG_USB_OHCI)
+#include <common.h>
 
-/* #include <pci.h> no PCI on the AU1x00 */
+#ifdef CONFIG_USB_OHCI
 
-#include <common.h>
 #include <malloc.h>
-#include <asm/io.h>
-#include <asm/au1x00.h>
 #include <usb.h>
 #include "au1x00_usb_ohci.h"
 
-#define OHCI_USE_NPS		/* force NoPowerSwitching mode */
-#define OHCI_VERBOSE_DEBUG	/* not always helpful */
-#define OHCI_FILL_TRACE
-
-#define USBH_ENABLE_BE (1<<0)
-#define USBH_ENABLE_C  (1<<1)
-#define USBH_ENABLE_E  (1<<2)
-#define USBH_ENABLE_CE (1<<3)
-#define USBH_ENABLE_RD (1<<4)
-
-#ifdef LITTLEENDIAN
-#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C)
-#else
-#define USBH_ENABLE_INIT (USBH_ENABLE_CE | USBH_ENABLE_E | USBH_ENABLE_C | USBH_ENABLE_BE)
-#endif
+#include <asm-mips/au1x00.h>
+#include <asm-mips/io.h>
+#include <asm-mips/addrspace.h>
 
+#define OHCI_USE_NPS		/* force NoPowerSwitching mode */
+#undef OHCI_VERBOSE_DEBUG	/* not always helpful */
+#undef DEBUG
+#undef SHOW_INFO
+#undef OHCI_FILL_TRACE
 
 /* For initializing controller (mask in an HCFS mode too) */
 #define OHCI_CONTROL_INIT \
 	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
 
-#undef readl
-#undef writel
-
-#define readl(a)     au_readl((long)(a))
-#define writel(v,a)  au_writel((v),(int)(a))
-
 #define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
 
-#define DEBUG
 #ifdef DEBUG
 #define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
 #else
 #define dbg(format, arg...) do {} while(0)
 #endif /* DEBUG */
 #define err(format, arg...) printf("ERROR: " format "\n", ## arg)
-#define SHOW_INFO
 #ifdef SHOW_INFO
 #define info(format, arg...) printf("INFO: " format "\n", ## arg)
 #else
 #define info(format, arg...) do {} while(0)
 #endif
 
-#define m16_swap(x) swap_16(x)
-#define m32_swap(x) swap_32(x)
-
 /* global ohci_t */
 static ohci_t gohci;
 /* this must be aligned to a 256 byte boundary */
@@ -106,6 +93,8 @@ urb_priv_t urb_priv;
 int got_rhsc;
 /* device which was disconnected */
 struct usb_device *devgone;
+/* flag guarding URB transation */
+int urb_finished = 0;
 
 /*-------------------------------------------------------------------------*/
 
@@ -219,7 +208,7 @@ void ep_print_int_eds (ohci_t *ohci, cha
 		    continue;
 		printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
 		while (*ed_p != 0 && j--) {
-			ed_t *ed = (ed_t *)m32_swap(ed_p);
+			ed_t *ed = (ed_t *)ohci_cpu_to_le32(ed_p);
 			printf (" ed: %4x;", ed->hwINFO);
 			ed_p = &ed->hwNextED;
 		}
@@ -384,7 +373,6 @@ static void ohci_dump (ohci_t *controlle
 	ohci_dump_roothub (controller, 1);
 }
 
-
 #endif /* DEBUG */
 
 /*-------------------------------------------------------------------------*
@@ -410,6 +398,16 @@ int sohci_submit_job(struct usb_device *
 		return -1;
 	}
 
+	/* if we have an unfinished URB from previous transaction let's
+	 * fail and scream as quickly as possible so as not to corrupt
+	 * further communication */
+	if (!urb_finished) {
+		err("sohci_submit_job: URB NOT FINISHED");
+		return -1;
+	}
+	/* we're about to begin a new transaction here so mark the URB unfinished */
+	urb_finished = 0;
+
 	/* every endpoint has a ed, locate and fill it */
 	if (!(ed = ep_add_ed (dev, pipe))) {
 		err("sohci_submit_job: ENOMEM");
@@ -476,7 +474,7 @@ static int sohci_get_current_frame_numbe
 {
 	ohci_t *ohci = &gohci;
 
-	return m16_swap (ohci->hcca->frame_no);
+	return ohci_cpu_to_le16 (ohci->hcca->frame_no);
 }
 #endif
 
@@ -496,9 +494,9 @@ static int ep_link (ohci_t *ohci, ed_t *
 	case PIPE_CONTROL:
 		ed->hwNextED = 0;
 		if (ohci->ed_controltail == NULL) {
-			writel ((long)ed, &ohci->regs->ed_controlhead);
+			writel (virt_to_phys(ed), &ohci->regs->ed_controlhead);
 		} else {
-			ohci->ed_controltail->hwNextED = m32_swap (ed);
+			ohci->ed_controltail->hwNextED = ohci_cpu_to_le32 (ed);
 		}
 		ed->ed_prev = ohci->ed_controltail;
 		if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
@@ -512,9 +510,9 @@ static int ep_link (ohci_t *ohci, ed_t *
 	case PIPE_BULK:
 		ed->hwNextED = 0;
 		if (ohci->ed_bulktail == NULL) {
-			writel ((long)ed, &ohci->regs->ed_bulkhead);
+			writel (virt_to_phys(ed), &ohci->regs->ed_bulkhead);
 		} else {
-			ohci->ed_bulktail->hwNextED = m32_swap (ed);
+			ohci->ed_bulktail->hwNextED = ohci_cpu_to_le32 (ed);
 		}
 		ed->ed_prev = ohci->ed_bulktail;
 		if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
@@ -535,9 +533,11 @@ static int ep_link (ohci_t *ohci, ed_t *
  * the link from the ed still points to another operational ed or 0
  * so the HC can eventually finish the processing of the unlinked ed */
 
-static int ep_unlink (ohci_t *ohci, ed_t *ed)
+static int ep_unlink (ohci_t *ohci, ed_t *edi)
 {
-	ed->hwINFO |= m32_swap (OHCI_ED_SKIP);
+	volatile ed_t *ed = edi;
+
+	ed->hwINFO |= ohci_cpu_to_le32 (OHCI_ED_SKIP);
 
 	switch (ed->type) {
 	case PIPE_CONTROL:
@@ -546,14 +546,14 @@ static int ep_unlink (ohci_t *ohci, ed_t
 				ohci->hc_control &= ~OHCI_CTRL_CLE;
 				writel (ohci->hc_control, &ohci->regs->control);
 			}
-			writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
+			writel (ohci_cpu_to_le32 (virt_to_phys(*((__u32 *)&ed->hwNextED))), &ohci->regs->ed_controlhead);
 		} else {
 			ed->ed_prev->hwNextED = ed->hwNextED;
 		}
 		if (ohci->ed_controltail == ed) {
 			ohci->ed_controltail = ed->ed_prev;
 		} else {
-			((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+			((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
 		}
 		break;
 
@@ -563,14 +563,14 @@ static int ep_unlink (ohci_t *ohci, ed_t
 				ohci->hc_control &= ~OHCI_CTRL_BLE;
 				writel (ohci->hc_control, &ohci->regs->control);
 			}
-			writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
+			writel (ohci_cpu_to_le32 (virt_to_phys(*((__u32 *)&ed->hwNextED))), &ohci->regs->ed_bulkhead);
 		} else {
 			ed->ed_prev->hwNextED = ed->hwNextED;
 		}
 		if (ohci->ed_bulktail == ed) {
 			ohci->ed_bulktail = ed->ed_prev;
 		} else {
-			((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
+			((ed_t *)ohci_cpu_to_le32 (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
 		}
 		break;
 	}
@@ -594,7 +594,7 @@ static ed_t * ep_add_ed (struct usb_devi
 	volatile ed_t *ed;
 
 	ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
-			(usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
+			      (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
 
 	if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
 		err("ep_add_ed: pending delete");
@@ -603,17 +603,17 @@ static ed_t * ep_add_ed (struct usb_devi
 	}
 
 	if (ed->state == ED_NEW) {
-		ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */
+		ed->hwINFO = ohci_cpu_to_le32 (OHCI_ED_SKIP); /* skip ed */
 		/* dummy td; end of td list for ed */
 		td = td_alloc (usb_dev);
-		ed->hwTailP = m32_swap (td);
+		ed->hwTailP = ohci_cpu_to_le32 (virt_to_phys(td));
 		ed->hwHeadP = ed->hwTailP;
 		ed->state = ED_UNLINK;
 		ed->type = usb_pipetype (pipe);
 		ohci_dev.ed_cnt++;
 	}
 
-	ed->hwINFO = m32_swap (usb_pipedevice (pipe)
+	ed->hwINFO = ohci_cpu_to_le32 (usb_pipedevice (pipe)
 			| usb_pipeendpoint (pipe) << 7
 			| (usb_pipeisoc (pipe)? 0x8000: 0)
 			| (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
@@ -647,29 +647,31 @@ static void td_fill (ohci_t *ohci, unsig
 	td_pt->hwNextTD = 0;
 
 	/* fill the old dummy TD */
-	td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf);
+	td = urb_priv->td [index] = \
+	     (td_t *) phys_to_virt((ohci_cpu_to_le32 (urb_priv->ed->hwTailP) & ~0xf));
 
 	td->ed = urb_priv->ed;
 	td->next_dl_td = NULL;
 	td->index = index;
 	td->data = (__u32)data;
 #ifdef OHCI_FILL_TRACE
-	if (1 || ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe))) {
+	if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) {
+		printf("td->data: ");
 		for (i = 0; i < len; i++)
-		printf("td->data[%d] %#2x\n",i, ((unsigned char *)(td->data+0x80000000))[i]);
+			printf("%#2x ", ((unsigned char *)td->data)[i]);
+		printf("\n");
 	}
 #endif
 	if (!len)
 		data = 0;
 
-	td->hwINFO = m32_swap (info);
-	td->hwCBP = m32_swap (data);
+	td->hwINFO = ohci_cpu_to_le32 (info);
+	td->hwCBP = virt_to_phys(ohci_cpu_to_le32 (data));
 	if (data)
-		td->hwBE = m32_swap (data + len - 1);
+		td->hwBE = ohci_cpu_to_le32 (virt_to_phys(data + len - 1));
 	else
 		td->hwBE = 0;
-	td->hwNextTD = m32_swap (td_pt);
-	td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000);
+	td->hwNextTD = ohci_cpu_to_le32 (virt_to_phys(td_pt));
 
 	/* append to queue */
 	td->ed->hwTailP = td->hwNextTD;
@@ -679,8 +681,6 @@ static void td_fill (ohci_t *ohci, unsig
 
 /* prepare all TDs of a transfer */
 
-#define kseg_to_phys(x)	  ((void *)((__u32)(x) - 0x80000000))
-
 static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
 	int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
 {
@@ -700,7 +700,7 @@ static void td_submit_job (struct usb_de
 	}
 	urb->td_cnt = 0;
 	if (data_len)
-		data = kseg_to_phys(buffer);
+		data = buffer;
 	else
 		data = 0;
 
@@ -723,7 +723,7 @@ static void td_submit_job (struct usb_de
 
 	case PIPE_CONTROL:
 		info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
-		td_fill (ohci, info, kseg_to_phys(setup), 8, dev, cnt++, urb);
+		td_fill (ohci, info, setup, 8, dev, cnt++, urb);
 		if (data_len > 0) {
 			info = usb_pipeout (pipe)?
 				TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
@@ -753,9 +753,9 @@ static void dl_transfer_length(td_t * td
 	__u32 tdINFO, tdBE, tdCBP;
 	urb_priv_t *lurb_priv = &urb_priv;
 
-	tdINFO = m32_swap (td->hwINFO);
-	tdBE   = m32_swap (td->hwBE);
-	tdCBP  = m32_swap (td->hwCBP);
+	tdINFO = ohci_cpu_to_le32 (td->hwINFO);
+	tdBE   = ohci_cpu_to_le32 (td->hwBE);
+	tdCBP  = ohci_cpu_to_le32 (td->hwCBP);
 
 
 	if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
@@ -781,30 +781,30 @@ static td_t * dl_reverse_done_list (ohci
 	td_t *td_list = NULL;
 	urb_priv_t *lurb_priv = NULL;
 
-	td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0;
+	td_list_hc = ohci_cpu_to_le32 (ohci->hcca->done_head) & 0xfffffff0;
 	ohci->hcca->done_head = 0;
 
 	while (td_list_hc) {
-		td_list = (td_t *)td_list_hc;
+		td_list = (td_t *) phys_to_virt(td_list_hc);
 
-		if (TD_CC_GET (m32_swap (td_list->hwINFO))) {
+		if (TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO))) {
 			lurb_priv = &urb_priv;
 			dbg(" USB-error/status: %x : %p",
-					TD_CC_GET (m32_swap (td_list->hwINFO)), td_list);
-			if (td_list->ed->hwHeadP & m32_swap (0x1)) {
+				TD_CC_GET (ohci_cpu_to_le32 (td_list->hwINFO)), td_list);
+			if (td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x1)) {
 				if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
 					td_list->ed->hwHeadP =
-						(lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) |
-									(td_list->ed->hwHeadP & m32_swap (0x2));
+						(lurb_priv->td[lurb_priv->length - 1]->hwNextTD & ohci_cpu_to_le32 (0xfffffff0)) |
+									(td_list->ed->hwHeadP & ohci_cpu_to_le32 (0x2));
 					lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
 				} else
-					td_list->ed->hwHeadP &= m32_swap (0xfffffff2);
+					td_list->ed->hwHeadP &= ohci_cpu_to_le32 (0xfffffff2);
 			}
 		}
 
 		td_list->next_dl_td = td_rev;
 		td_rev = td_list;
-		td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0;
+		td_list_hc = ohci_cpu_to_le32 (td_list->hwNextTD) & 0xfffffff0;
 	}
 	return td_list;
 }
@@ -826,7 +826,7 @@ static int dl_done_list (ohci_t *ohci, t
 		td_list_next = td_list->next_dl_td;
 
 		lurb_priv = &urb_priv;
-		tdINFO = m32_swap (td_list->hwINFO);
+		tdINFO = ohci_cpu_to_le32 (td_list->hwINFO);
 
 		ed = td_list->ed;
 
@@ -834,14 +834,18 @@ static int dl_done_list (ohci_t *ohci, t
 
 		/* error code of transfer */
 		cc = TD_CC_GET (tdINFO);
-		if (cc != 0) {
-			dbg("ConditionCode %#x", cc);
-			stat = cc_to_error[cc];
+		if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+			if ((ed->state & (ED_OPER | ED_UNLINK))
+					&& (lurb_priv->state != URB_DEL)) {
+				dbg("ConditionCode %#x", cc);
+				stat = cc_to_error[cc];
+				urb_finished = 1;
+			}
 		}
 
 		if (ed->state != ED_NEW) {
-			edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
-			edTailP = m32_swap (ed->hwTailP);
+			edHeadP = ohci_cpu_to_le32 (ed->hwHeadP) & 0xfffffff0;
+			edTailP = ohci_cpu_to_le32 (ed->hwTailP);
 
 			/* unlink eds if they are not busy */
 			if ((edHeadP == edTailP) && (ed->state == ED_OPER))
@@ -1012,8 +1016,6 @@ static int ohci_submit_rh_msg(struct usb
 #ifdef DEBUG
 urb_priv.actual_length = 0;
 pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
-#else
-	wait_ms(1);
 #endif
 	if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
 		info("Root-Hub submit IRQ: NOT implemented");
@@ -1021,9 +1023,9 @@ pkt_print(dev, pipe, buffer, transfer_le
 	}
 
 	bmRType_bReq  = cmd->requesttype | (cmd->request << 8);
-	wValue	      = m16_swap (cmd->value);
-	wIndex	      = m16_swap (cmd->index);
-	wLength	      = m16_swap (cmd->length);
+	wValue	      = ohci_cpu_to_le16 (cmd->value);
+	wIndex	      = ohci_cpu_to_le16 (cmd->index);
+	wLength	      = ohci_cpu_to_le16 (cmd->length);
 
 	info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
 		dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
@@ -1038,17 +1040,17 @@ pkt_print(dev, pipe, buffer, transfer_le
 	*/
 
 	case RH_GET_STATUS:
-			*(__u16 *) data_buf = m16_swap (1); OK (2);
+			*(__u16 *) data_buf = ohci_cpu_to_le16 (1); OK (2);
 	case RH_GET_STATUS | RH_INTERFACE:
-			*(__u16 *) data_buf = m16_swap (0); OK (2);
+			*(__u16 *) data_buf = ohci_cpu_to_le16 (0); OK (2);
 	case RH_GET_STATUS | RH_ENDPOINT:
-			*(__u16 *) data_buf = m16_swap (0); OK (2);
+			*(__u16 *) data_buf = ohci_cpu_to_le16 (0); OK (2);
 	case RH_GET_STATUS | RH_CLASS:
-			*(__u32 *) data_buf = m32_swap (
+			*(__u32 *) data_buf = ohci_cpu_to_le32 (
 				RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
 			OK (4);
 	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-			*(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
+			*(__u32 *) data_buf = ohci_cpu_to_le32 (RD_RH_PORTSTAT); OK (4);
 
 	case RH_CLEAR_FEATURE | RH_ENDPOINT:
 		switch (wValue) {
@@ -1146,38 +1148,38 @@ pkt_print(dev, pipe, buffer, transfer_le
 		break;
 
 	case RH_GET_DESCRIPTOR | RH_CLASS:
-	    {
-		    __u32 temp = roothub_a (&gohci);
+	{
+		__u32 temp = roothub_a (&gohci);
 
-		    data_buf [0] = 9;		/* min length; */
-		    data_buf [1] = 0x29;
-		    data_buf [2] = temp & RH_A_NDP;
-		    data_buf [3] = 0;
-		    if (temp & RH_A_PSM)	/* per-port power switching? */
+		data_buf [0] = 9;           /* min length; */
+		data_buf [1] = 0x29;
+		data_buf [2] = temp & RH_A_NDP;
+		data_buf [3] = 0;
+		if (temp & RH_A_PSM)        /* per-port power switching? */
 			data_buf [3] |= 0x1;
-		    if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
+		if (temp & RH_A_NOCP)	/* no overcurrent reporting? */
 			data_buf [3] |= 0x10;
-		    else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
+		else if (temp & RH_A_OCPM)	/* per-port overcurrent reporting? */
 			data_buf [3] |= 0x8;
 
-		    /* corresponds to data_buf[4-7] */
-		    datab [1] = 0;
-		    data_buf [5] = (temp & RH_A_POTPGT) >> 24;
-		    temp = roothub_b (&gohci);
-		    data_buf [7] = temp & RH_B_DR;
-		    if (data_buf [2] < 7) {
+		/* corresponds to data_buf[4-7] */
+		datab [1] = 0;
+		data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+		temp = roothub_b (&gohci);
+		data_buf [7] = temp & RH_B_DR;
+		if (data_buf [2] < 7) {
 			data_buf [8] = 0xff;
-		    } else {
+		} else {
 			data_buf [0] += 2;
 			data_buf [8] = (temp & RH_B_DR) >> 8;
 			data_buf [10] = data_buf [9] = 0xff;
-		    }
-
-		    len = min_t(unsigned int, leni,
-			      min_t(unsigned int, data_buf [0], wLength));
-		    OK (len);
 		}
 
+		len = min_t(unsigned int, leni,
+			min_t(unsigned int, data_buf [0], wLength));
+		OK (len);
+	}
+
 	case RH_GET_CONFIGURATION:	*(__u8 *) data_buf = 0x01; OK (1);
 
 	case RH_SET_CONFIGURATION:	WR_RH_STAT (0x10000); OK (0);
@@ -1189,8 +1191,6 @@ pkt_print(dev, pipe, buffer, transfer_le
 
 #ifdef	DEBUG
 	ohci_dump_roothub (&gohci, 1);
-#else
-	wait_ms(1);
 #endif
 
 	len = min_t(int, len, leni);
@@ -1203,8 +1203,6 @@ pkt_print(dev, pipe, buffer, transfer_le
 	if (transfer_len)
 		urb_priv.actual_length = transfer_len;
 	pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
-#else
-	wait_ms(1);
 #endif
 
 	return stat;
@@ -1230,8 +1228,6 @@ int submit_common_msg(struct usb_device 
 #ifdef DEBUG
 	urb_priv.actual_length = 0;
 	pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
-#else
-	wait_ms(1);
 #endif
 	if (!maxsize) {
 		err("submit_common_message: pipesize for pipe %lx is zero",
@@ -1244,9 +1240,6 @@ int submit_common_msg(struct usb_device 
 		return -1;
 	}
 
-	wait_ms(10);
-	/* ohci_dump_status(&gohci); */
-
 	/* allow more time for a BULK device to react - some are slow */
 #define BULK_TO	 5000	/* timeout in milliseconds */
 	if (usb_pipetype (pipe) == PIPE_BULK)
@@ -1254,7 +1247,6 @@ int submit_common_msg(struct usb_device 
 	else
 		timeout = 100;
 
-	timeout *= 4;
 	/* wait for it to complete */
 	for (;;) {
 		/* check whether the controller is done */
@@ -1263,18 +1255,34 @@ int submit_common_msg(struct usb_device 
 			stat = USB_ST_CRC_ERR;
 			break;
 		}
-		if (stat >= 0 && stat != 0xff) {
+
+		/* NOTE: since we are not interrupt driven in U-Boot and always
+		 * handle only one URB at a time, we cannot assume the
+		 * transaction finished on the first successful return from
+		 * hc_interrupt().. unless the flag for current URB is set,
+		 * meaning that all TD's to/from device got actually
+		 * transferred and processed. If the current URB is not
+		 * finished we need to re-iterate this loop so as
+		 * hc_interrupt() gets called again as there needs to be some
+		 * more TD's to process still */
+		if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
 			/* 0xff is returned for an SF-interrupt */
 			break;
 		}
+
 		if (--timeout) {
-			udelay(250); /* wait_ms(1); */
+			wait_ms(1);
+			if (!urb_finished)
+				dbg("\%");
 		} else {
 			err("CTL:TIMEOUT ");
+			dbg("submit_common_msg: TO status %x\n", stat);
 			stat = USB_ST_CRC_ERR;
+			urb_finished = 1;
 			break;
 		}
 	}
+#if 0
 	/* we got an Root Hub Status Change interrupt */
 	if (got_rhsc) {
 #ifdef DEBUG
@@ -1296,14 +1304,13 @@ int submit_common_msg(struct usb_device 
 			devgone = dev;
 		}
 	}
+#endif
 
 	dev->status = stat;
 	dev->act_len = transfer_len;
 
 #ifdef DEBUG
 	pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
-#else
-	wait_ms(1);
 #endif
 
 	/* free TDs in urb_priv */
@@ -1328,8 +1335,6 @@ int submit_control_msg(struct usb_device
 #ifdef DEBUG
 	urb_priv.actual_length = 0;
 	pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
-#else
-	wait_ms(1);
 #endif
 	if (!maxsize) {
 		err("submit_control_message: pipesize for pipe %lx is zero",
@@ -1364,6 +1369,8 @@ static int hc_reset (ohci_t *ohci)
 	int timeout = 30;
 	int smm_timeout = 50; /* 0,5 sec */
 
+	dbg("%s\n", __FUNCTION__);
+
 	if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
 		writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
 		info("USB HC TakeOver from SMM");
@@ -1379,12 +1386,13 @@ static int hc_reset (ohci_t *ohci)
 	/* Disable HC interrupts */
 	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
 
-	dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;",
+	dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
 		ohci->slot_name,
 		readl (&ohci->regs->control));
 
 	/* Reset USB (needed by some controllers) */
-	writel (0, &ohci->regs->control);
+	ohci->hc_control = 0;
+	writel (ohci->hc_control, &ohci->regs->control);
 
 	/* HC Reset requires max 10 us delay */
 	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
@@ -1417,7 +1425,7 @@ static int hc_start (ohci_t * ohci)
 	writel (0, &ohci->regs->ed_controlhead);
 	writel (0, &ohci->regs->ed_bulkhead);
 
-	writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
+	writel (virt_to_phys(ohci->hcca), &ohci->regs->hcca); /* a reset clears this */
 
 	fminterval = 0x2edf;
 	writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
@@ -1451,7 +1459,7 @@ static int hc_start (ohci_t * ohci)
 
 #define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
 	/* POTPGT delay is bits 24-31, in 2 ms units. */
-	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+	wait_ms((roothub_a (ohci) >> 23) & 0x1fe);
 
 	/* connect the virtual root hub */
 	ohci->rh.devnum = 0;
@@ -1470,17 +1478,26 @@ hc_interrupt (void)
 	struct ohci_regs *regs = ohci->regs;
 	int ints;
 	int stat = -1;
+	td_t *tmp;
 
-	if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) {
-		ints =	OHCI_INTR_WDH;
-	} else {
-		ints = readl (&regs->intrstatus);
-	}
+	if ((ohci->hcca->done_head != 0) &&
+	     !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
+
+		ints =  OHCI_INTR_WDH;
+
+	} else if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+		ohci->disabled++;
+		err ("%s device removed!", ohci->slot_name);
+		return -1;
 
-	/* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+	} else if ((ints &= readl (&regs->intrenable)) == 0) {
+		dbg("hc_interrupt: returning..\n");
+		return 0xff;
+	}
 
 	if (ints & OHCI_INTR_RHSC) {
 		got_rhsc = 1;
+		stat = 0xff;
 	}
 
 	if (ints & OHCI_INTR_UE) {
@@ -1491,8 +1508,6 @@ hc_interrupt (void)
 
 #ifdef	DEBUG
 		ohci_dump (ohci, 1);
-#else
-	wait_ms(1);
 #endif
 		/* FIXME: be optimistic, hope that bug won't repeat often. */
 		/* Make some non-interrupt context restart the controller. */
@@ -1503,9 +1518,9 @@ hc_interrupt (void)
 	}
 
 	if (ints & OHCI_INTR_WDH) {
-		wait_ms(1);
 		writel (OHCI_INTR_WDH, &regs->intrdisable);
-		stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
+		tmp = dl_reverse_done_list (ohci);
+		stat = dl_done_list (ohci, tmp);
 		writel (OHCI_INTR_WDH, &regs->intrenable);
 	}
 
@@ -1517,7 +1532,7 @@ hc_interrupt (void)
 
 	/* FIXME:  this assumes SOF (1/ms) interrupts don't get lost... */
 	if (ints & OHCI_INTR_SF) {
-		unsigned int frame = m16_swap (ohci->hcca->frame_no) & 1;
+		unsigned int frame = ohci_cpu_to_le16 (ohci->hcca->frame_no) & 1;
 		wait_ms(1);
 		writel (OHCI_INTR_SF, &regs->intrdisable);
 		if (ohci->ed_rm_list[frame] != NULL)
@@ -1559,7 +1574,6 @@ static void hc_release_ohci (ohci_t *ohc
 			: "=r" (__res));				\
 	__res;								\
 })
-
 #define read_c0_prid()		__read_32bit_c0_register($15, 0)
 
 /*
@@ -1567,13 +1581,23 @@ static void hc_release_ohci (ohci_t *ohc
  */
 static char ohci_inited = 0;
 
+#define USBH_ENABLE_BE (1<<0)
+#define USBH_ENABLE_C  (1<<1)
+#define USBH_ENABLE_E  (1<<2)
+#define USBH_ENABLE_CE (1<<3)
+#define USBH_ENABLE_RD (1<<4)
+
 int usb_lowlevel_init(void)
 {
 	u32 pin_func;
-	u32 sys_freqctrl, sys_clksrc;
+	u32 sys_freqctrl, sys_clksrc, ohci_control;
 	u32 prid = read_c0_prid();
+	int count = 3000;
 
-	dbg("in usb_lowlevel_init\n");
+	/* Set AUX clock to 12MHz * 8 = 96 MHz */
+	au_writel(8, SYS_AUXPLL);
+	au_writel(0, SYS_PININPUTEN);
+	udelay(100);
 
 	/* zero and disable FREQ2 */
 	sys_freqctrl = au_readl(SYS_FREQCTRL0);
@@ -1581,6 +1605,17 @@ int usb_lowlevel_init(void)
 	au_writel(sys_freqctrl, SYS_FREQCTRL0);
 
 	/* zero and disable USBH/USBD clocks */
+#ifdef CONFIG_AU1100
+	sys_clksrc = au_readl(SYS_CLKSRC);
+	sys_clksrc &= ~0x0000001F;
+	au_writel(sys_clksrc, SYS_CLKSRC);
+
+	sys_freqctrl = au_readl(SYS_FREQCTRL0);
+	sys_freqctrl &= ~0xFFF00000;
+
+	sys_clksrc = au_readl(SYS_CLKSRC);
+	sys_clksrc &= ~0x0000001F;
+#else
 	sys_clksrc = au_readl(SYS_CLKSRC);
 	sys_clksrc &= ~0x00007FE0;
 	au_writel(sys_clksrc, SYS_CLKSRC);
@@ -1590,6 +1625,7 @@ int usb_lowlevel_init(void)
 
 	sys_clksrc = au_readl(SYS_CLKSRC);
 	sys_clksrc &= ~0x00007FE0;
+#endif
 
 	switch (prid & 0x000000FF) {
 	case 0x00: /* DA */
@@ -1618,9 +1654,15 @@ int usb_lowlevel_init(void)
 		break;
 	}
 
-	/*
-	 * Route 48MHz FREQ2 into USB Host and/or Device
-	 */
+ 	/* Route 48MHz FREQ2 into USB Host (and/or Device) */
+#ifdef CONFIG_AU1100
+	sys_clksrc |= ((4<<2) | (0<<1) | (0<<0) );
+	au_writel(sys_clksrc, SYS_CLKSRC);
+
+	/* Set USB functionality pin state as host */
+	pin_func = au_readl(SYS_PINFUNC) & ~0x8000;
+	au_writel(pin_func, SYS_PINFUNC);
+#else
 	sys_clksrc |= ((4<<12) | (0<<11) | (0<<10));
 	au_writel(sys_clksrc, SYS_CLKSRC);
 
@@ -1630,22 +1672,10 @@ int usb_lowlevel_init(void)
 	au_writel(pin_func, SYS_PINFUNC);
 	au_writel(0x2800, SYS_TRIOUTCLR);
 	au_writel(0x0030, SYS_OUTPUTCLR);
+#endif
 
 	dbg("OHCI board setup complete\n");
 
-	/* enable host controller */
-	au_writel(USBH_ENABLE_CE, USB_HOST_CONFIG);
-	udelay(1000);
-	au_writel(USBH_ENABLE_INIT, USB_HOST_CONFIG);
-	udelay(1000);
-
-	/* wait for reset complete (read register twice; see au1500 errata) */
-	while (au_readl(USB_HOST_CONFIG),
-	       !(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
-		udelay(1000);
-
-	dbg("OHCI clock running\n");
-
 	memset (&gohci, 0, sizeof (ohci_t));
 	memset (&urb_priv, 0, sizeof (urb_priv_t));
 
@@ -1673,35 +1703,53 @@ int usb_lowlevel_init(void)
 	gohci.disabled = 1;
 	gohci.sleeping = 0;
 	gohci.irq = -1;
-	gohci.regs = (struct ohci_regs *)(USB_OHCI_BASE | 0xA0000000);
+	gohci.regs = (struct ohci_regs *) 0xB0100000;
 
 	gohci.flags = 0;
 	gohci.slot_name = "au1x00";
 
-	dbg("OHCI revision: 0x%08x\n"
-	       "  RH: a: 0x%08x b: 0x%08x\n",
-	       readl(&gohci.regs->revision),
-	       readl(&gohci.regs->roothub.a), readl(&gohci.regs->roothub.b));
+	dbg("OHCI revision: 0x%08x\nRH: a: 0x%08x b: 0x%08x\n",
+		readl(&gohci.regs->revision),
+		readl(&gohci.regs->roothub.a), readl(&gohci.regs->roothub.b));
+
+	/* enable host controller */
+	au_writel(USBH_ENABLE_CE | USBH_ENABLE_C, USB_HOST_CONFIG);
+	udelay(1000);
+	au_writel(USBH_ENABLE_CE | USBH_ENABLE_C | USBH_ENABLE_E, USB_HOST_CONFIG);
+	udelay(1000);
+
+	/* set the reset state */
+	ohci_control = readl(&gohci.regs->control);
+	ohci_control &= ~OHCI_CTRL_HCFS;
+	writel(ohci_control, &gohci.regs->control);
+
+	/* wait for reset complete (read register twice; see au1500 errata) */
+	while (au_readl(USB_HOST_CONFIG),
+	       !(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD)) {
+		udelay(1000);
+		if (--count == 0) {
+			err("unable to reset USB host!!");
+			return -1;
+		}
+	}
+	
+	dbg("OHCI clock running\n");
 
 	if (hc_reset (&gohci) < 0)
 		goto errout;
 
-	/* FIXME this is a second HC reset; why?? */
-	writel (gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control);
-	wait_ms (10);
-
 	if (hc_start (&gohci) < 0)
 		goto errout;
 
 #ifdef	DEBUG
 	ohci_dump (&gohci, 1);
-#else
-	wait_ms(1);
 #endif
 	ohci_inited = 1;
+	urb_finished = 1;
+
 	return 0;
 
-  errout:
+errout:
 	err("OHCI initialization error\n");
 	hc_release_ohci (&gohci);
 	/* Initialization failed */
@@ -1718,9 +1766,10 @@ int usb_lowlevel_stop(void)
 	/* TODO release any interrupts, etc. */
 	/* call hc_release_ohci() here ? */
 	hc_reset (&gohci);
-	/* may not want to do this */
+
 	/* Disable clock */
 	au_writel(readl(USB_HOST_CONFIG) & ~USBH_ENABLE_CE, USB_HOST_CONFIG);
+
 	return 0;
 }
 
diff --git a/include/usb.h b/include/usb.h
index 39d7f23..210a420 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -247,6 +247,8 @@ int usb_set_interface(struct usb_device 
 		((x_ & 0xFF000000UL) >> 24) ); \
 	})
 #endif /* LITTLEENDIAN */
+#define ohci_cpu_to_le16(x) swap_16(x)
+#define ohci_cpu_to_le32(x) swap_32(x)
 
 /*
  * Calling this entity a "pipe" is glorifying it. A USB pipe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://lists.denx.de/pipermail/u-boot/attachments/20060530/db40133d/attachment.pgp 


More information about the U-Boot mailing list