From mboxrd@z Thu Jan 1 00:00:00 1970 From: Rodolfo Giometti Date: Tue, 30 May 2006 16:38:39 +0200 Subject: [U-Boot-Users] [PATCH] (modified) USB OHCI support for Au1x00 fixed In-Reply-To: <20060530130732.GA21734@enneenne.com> References: <20060511141459.GC15748@enneenne.com> <20060511162451.4295A353BE7@atlas.denx.de> <20060530130732.GA21734@enneenne.com> Message-ID: <20060530143839.GC21734@enneenne.com> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 + * Eurotech S.p.A. + * + * Based on "cpu/mpc5xxx/usb_ohci.c". + * Original copyright message: + * + * (C) Copyright 2003-2004 * Gary Jennejohn, DENX Software Engineering * + * (C) Copyright 2004 + * Pierre Aubert, Staubli Faverges + * + * Note: Much of this code has been derived from Linux 2.4 + * (C) Copyright 1999 Roman Weissgaerber + * (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 - -#if defined(CONFIG_AU1X00) && defined(CONFIG_USB_OHCI) +#include -/* #include no PCI on the AU1x00 */ +#ifdef CONFIG_USB_OHCI -#include #include -#include -#include #include #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 +#include +#include +#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