[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 (®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
More information about the U-Boot
mailing list