All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rodolfo Giometti <giometti@linux.it>
To: u-boot@lists.denx.de
Subject: [U-Boot-Users] [PATCH] (modified) USB OHCI support for Au1x00 fixed
Date: Tue, 30 May 2006 16:38:39 +0200	[thread overview]
Message-ID: <20060530143839.GC21734@enneenne.com> (raw)
In-Reply-To: <20060530130732.GA21734@enneenne.com>

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@linux.it>
+ * Eurotech S.p.A. <info@eurotech.it>
+ *
+ * Based on "cpu/mpc5xxx/usb_ohci.c".
+ * Original copyright message:
+ *
+ * (C) Copyright 2003-2004
  * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
  *
+ * (C) Copyright 2004
+ * Pierre Aubert, Staubli Faverges <p.aubert@staubli.com>
+ *
+ * Note: Much of this code has been derived from Linux 2.4
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@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 

      reply	other threads:[~2006-05-30 14:38 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-05-11 14:14 [U-Boot-Users] [PATCH] USB OHCI support for Au1x00 fixed Rodolfo Giometti
2006-05-11 16:24 ` Wolfgang Denk
2006-05-30 13:07   ` [U-Boot-Users] [PATCH] (modified) " Rodolfo Giometti
2006-05-30 14:38     ` Rodolfo Giometti [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20060530143839.GC21734@enneenne.com \
    --to=giometti@linux.it \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.