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 (®s->intrstatus);
- }
+ if ((ohci->hcca->done_head != 0) &&
+ !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) {
+
+ ints = OHCI_INTR_WDH;
+
+ } else if ((ints = readl (®s->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 (®s->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, ®s->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, ®s->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, ®s->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
prev parent 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.