From 3e326ece9eba8184f5d48aa4fb87760a8f6f0f10 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Mon, 22 May 2006 16:33:54 +0200 Subject: This patch adds USB storage support for the delta board. This is the first board to make use of a generic OHCI driver, that calls hooks for board dependant initialization. --- board/delta/delta.c | 52 ++ drivers/Makefile | 2 +- drivers/usb_ohci.c | 1642 +++++++++++++++++++++++++++++++++++ drivers/usb_ohci.h | 422 +++++++++ include/asm-arm/arch-pxa/pxa-regs.h | 23 +- include/configs/delta.h | 11 +- include/da9030.h | 12 + 7 files changed, 2161 insertions(+), 3 deletions(-) create mode 100644 drivers/usb_ohci.c create mode 100644 drivers/usb_ohci.h diff --git a/board/delta/delta.c b/board/delta/delta.c index b127ac8..d9fe8cb 100644 --- a/board/delta/delta.c +++ b/board/delta/delta.c @@ -99,6 +99,52 @@ int board_late_init(void) } +/* board dependant usb stuff */ +int usb_board_init() +{ + /* + * Enable USB host clock. + */ + CKENA |= (CKENA_2_USBHOST | CKENA_20_UDC); + udelay(100); + + /* Configure Port 2 for Host (USB Client Registers) */ + UP2OCR = 0x3000c; + +#if 0 + GPIO2_2 = 0x801; /* USBHPEN - Alt. Fkt. 1 */ + GPIO3_2 = 0x801; /* USBHPWR - Alt. Fkt. 1 */ +#endif + + UHCHR |= UHCHR_FHR; + wait_ms(11); /* udelay(11); */ + UHCHR &= ~UHCHR_FHR; + + UHCHR |= UHCHR_FSBIR; + while (UHCHR & UHCHR_FSBIR) + udelay(1); + +#if 0 + UHCHR |= UHCHR_PCPL; /* USBHPEN is active low */ + UHCHR |= UHCHR_PSPL; /* USBHPWR is active low */ +#endif + + UHCHR &= ~UHCHR_SSEP0; + UHCHR &= ~UHCHR_SSEP1; + UHCHR &= ~UHCHR_SSE; + + return 0; +} + +int usb_board_stop() +{ + /* may not want to do this */ + /* CKENA &= ~(CKENA_2_USBHOST | CKENA_20_UDC); */ + + return 0; +} + + /* * Magic Key Handling, mainly copied from board/lwmon/lwmon.c */ @@ -324,6 +370,12 @@ static void init_DA9030() return; } + val = 0x80; + if(i2c_write(addr, IRQ_MASK_B, 1, &val, 1)) { + printf("Error accessing DA9030 via i2c.\n"); + return; + } + i2c_reg_write(addr, REG_CONTROL_1_97, 0xfd); /* disable LDO1, enable LDO6 */ i2c_reg_write(addr, LDO2_3, 0xd1); /* LDO2 =1,9V, LDO3=3,1V */ i2c_reg_write(addr, LDO4_5, 0xcc); /* LDO2 =1,9V, LDO3=3,1V */ diff --git a/drivers/Makefile b/drivers/Makefile index e6176ed..d5b6811 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -46,7 +46,7 @@ OBJS = 3c589.o 5701rls.o ali512x.o \ sl811_usb.o sm501.o smc91111.o smiLynxEM.o \ status_led.o sym53c8xx.o \ ti_pci1410a.o tigon3.o tsec.o \ - usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \ + usb_ohci.o usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \ videomodes.o w83c553f.o \ ks8695eth.o diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c new file mode 100644 index 0000000..4065489 --- /dev/null +++ b/drivers/usb_ohci.c @@ -0,0 +1,1642 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200. + * + * (C) Copyright 2003 + * Gary Jennejohn, DENX Software Engineering + * + * Note: Much of this code has been derived from Linux 2.4 + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2002 David Brownell + * + * Modified for the MP2USB by (C) Copyright 2005 Eric Benard + * ebenard@eukrea.com - based on s3c24x0's driver + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ +/* + * 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 + * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes! + * 3 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG + * to activate workaround for bug #41 or this driver will NOT work! + */ + +#include +/* #include no PCI on the S3C24X0 */ + +#ifdef CONFIG_USB_OHCI + +#include + +#include +#include +#include "usb_ohci.h" + +/* #define OHCI_USE_NPS /\* force NoPowerSwitching mode *\/ */ +#undef OHCI_VERBOSE_DEBUG /* not always helpful */ + +/* For initializing controller (mask in an HCFS mode too) */ +#define OHCI_CONTROL_INIT \ + (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE + +#define readl(a) (*((vu_long *)(a))) +#define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a)) + +#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) + +#undef 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) +#undef 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 */ +struct ohci_hcca ghcca[1]; +/* a pointer to the aligned storage */ +struct ohci_hcca *phcca; +/* this allocates EDs for all possible endpoints */ +struct ohci_device ohci_dev; +/* urb_priv */ +urb_priv_t urb_priv; +/* RHSC flag */ +int got_rhsc; +/* device which was disconnected */ +struct usb_device *devgone; + +/*-------------------------------------------------------------------------*/ + +/* AMD-756 (D2 rev) reports corrupt register contents in some cases. + * The erratum (#4) description is incorrect. AMD's workaround waits + * till some bits (mostly reserved) are clear; ok for all revs. + */ +#define OHCI_QUIRK_AMD756 0xabcd +#define read_roothub(hc, register, mask) ({ \ + u32 temp = readl (&hc->regs->roothub.register); \ + if (hc->flags & OHCI_QUIRK_AMD756) \ + while (temp & mask) \ + temp = readl (&hc->regs->roothub.register); \ + temp; }) + +static u32 roothub_a (struct ohci *hc) + { return read_roothub (hc, a, 0xfc0fe000); } +static inline u32 roothub_b (struct ohci *hc) + { return readl (&hc->regs->roothub.b); } +static inline u32 roothub_status (struct ohci *hc) + { return readl (&hc->regs->roothub.status); } +static u32 roothub_portstatus (struct ohci *hc, int i) + { return read_roothub (hc, portstatus [i], 0xffe0fce0); } + + +/* forward declaration */ +static int hc_interrupt (void); +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); + +/*-------------------------------------------------------------------------* + * URB support functions + *-------------------------------------------------------------------------*/ + +/* free HCD-private data associated with this URB */ + +static void urb_free_priv (urb_priv_t * urb) +{ + int i; + int last; + struct td * td; + + last = urb->length - 1; + if (last >= 0) { + for (i = 0; i <= last; i++) { + td = urb->td[i]; + if (td) { + td->usb_dev = NULL; + urb->td[i] = NULL; + } + } + } +} + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +static int sohci_get_current_frame_number (struct usb_device * dev); + +/* debug| print the main components of an URB + * small: 0) header + data packets 1) just header */ + +static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer, + int transfer_len, struct devrequest * setup, char * str, int small) +{ + urb_priv_t * purb = &urb_priv; + + dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx", + str, + sohci_get_current_frame_number (dev), + usb_pipedevice (pipe), + usb_pipeendpoint (pipe), + usb_pipeout (pipe)? 'O': 'I', + usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"): + (usb_pipecontrol (pipe)? "CTRL": "BULK"), + purb->actual_length, + transfer_len, dev->status); +#ifdef OHCI_VERBOSE_DEBUG + if (!small) { + int i, len; + + if (usb_pipecontrol (pipe)) { + printf (__FILE__ ": cmd(8):"); + for (i = 0; i < 8 ; i++) + printf (" %02x", ((__u8 *) setup) [i]); + printf ("\n"); + } + if (transfer_len > 0 && buffer) { + printf (__FILE__ ": data(%d/%d):", + purb->actual_length, + transfer_len); + len = usb_pipeout (pipe)? + transfer_len: purb->actual_length; + for (i = 0; i < 16 && i < len; i++) + printf (" %02x", ((__u8 *) buffer) [i]); + printf ("%s\n", i < len? "...": ""); + } + } +#endif +} + +/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/ +void ep_print_int_eds (ohci_t *ohci, char * str) { + int i, j; + __u32 * ed_p; + for (i= 0; i < 32; i++) { + j = 5; + ed_p = &(ohci->hcca->int_table [i]); + if (*ed_p == 0) + 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); + printf (" ed: %4x;", ed->hwINFO); + ed_p = &ed->hwNextED; + } + printf ("\n"); + } +} + +static void ohci_dump_intr_mask (char *label, __u32 mask) +{ + dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s", + label, + mask, + (mask & OHCI_INTR_MIE) ? " MIE" : "", + (mask & OHCI_INTR_OC) ? " OC" : "", + (mask & OHCI_INTR_RHSC) ? " RHSC" : "", + (mask & OHCI_INTR_FNO) ? " FNO" : "", + (mask & OHCI_INTR_UE) ? " UE" : "", + (mask & OHCI_INTR_RD) ? " RD" : "", + (mask & OHCI_INTR_SF) ? " SF" : "", + (mask & OHCI_INTR_WDH) ? " WDH" : "", + (mask & OHCI_INTR_SO) ? " SO" : "" + ); +} + +static void maybe_print_eds (char *label, __u32 value) +{ + ed_t *edp = (ed_t *)value; + + if (value) { + dbg ("%s %08x", label, value); + dbg ("%08x", edp->hwINFO); + dbg ("%08x", edp->hwTailP); + dbg ("%08x", edp->hwHeadP); + dbg ("%08x", edp->hwNextED); + } +} + +static char * hcfs2string (int state) +{ + switch (state) { + case OHCI_USB_RESET: return "reset"; + case OHCI_USB_RESUME: return "resume"; + case OHCI_USB_OPER: return "operational"; + case OHCI_USB_SUSPEND: return "suspend"; + } + return "?"; +} + +/* dump control and status registers */ +static void ohci_dump_status (ohci_t *controller) +{ + struct ohci_regs *regs = controller->regs; + __u32 temp; + + temp = readl (®s->revision) & 0xff; + if (temp != 0x10) + dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f)); + + temp = readl (®s->control); + dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp, + (temp & OHCI_CTRL_RWE) ? " RWE" : "", + (temp & OHCI_CTRL_RWC) ? " RWC" : "", + (temp & OHCI_CTRL_IR) ? " IR" : "", + hcfs2string (temp & OHCI_CTRL_HCFS), + (temp & OHCI_CTRL_BLE) ? " BLE" : "", + (temp & OHCI_CTRL_CLE) ? " CLE" : "", + (temp & OHCI_CTRL_IE) ? " IE" : "", + (temp & OHCI_CTRL_PLE) ? " PLE" : "", + temp & OHCI_CTRL_CBSR + ); + + temp = readl (®s->cmdstatus); + dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp, + (temp & OHCI_SOC) >> 16, + (temp & OHCI_OCR) ? " OCR" : "", + (temp & OHCI_BLF) ? " BLF" : "", + (temp & OHCI_CLF) ? " CLF" : "", + (temp & OHCI_HCR) ? " HCR" : "" + ); + + ohci_dump_intr_mask ("intrstatus", readl (®s->intrstatus)); + ohci_dump_intr_mask ("intrenable", readl (®s->intrenable)); + + maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent)); + + maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead)); + maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent)); + + maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead)); + maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent)); + + maybe_print_eds ("donehead", readl (®s->donehead)); +} + +static void ohci_dump_roothub (ohci_t *controller, int verbose) +{ + __u32 temp, ndp, i; + + temp = roothub_a (controller); + ndp = (temp & RH_A_NDP); +#ifdef CONFIG_AT91C_PQFP_UHPBUG + ndp = (ndp == 2) ? 1:0; +#endif +#if 0 /* def CONFIG_CPU_MONAHANS */ + data_buf [2] = (data_buf [2] == 2) ? 3:0; +#endif + if (verbose) { + dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp, + ((temp & RH_A_POTPGT) >> 24) & 0xff, + (temp & RH_A_NOCP) ? " NOCP" : "", + (temp & RH_A_OCPM) ? " OCPM" : "", + (temp & RH_A_DT) ? " DT" : "", + (temp & RH_A_NPS) ? " NPS" : "", + (temp & RH_A_PSM) ? " PSM" : "", + ndp + ); + temp = roothub_b (controller); + dbg ("roothub.b: %08x PPCM=%04x DR=%04x", + temp, + (temp & RH_B_PPCM) >> 16, + (temp & RH_B_DR) + ); + temp = roothub_status (controller); + dbg ("roothub.status: %08x%s%s%s%s%s%s", + temp, + (temp & RH_HS_CRWE) ? " CRWE" : "", + (temp & RH_HS_OCIC) ? " OCIC" : "", + (temp & RH_HS_LPSC) ? " LPSC" : "", + (temp & RH_HS_DRWE) ? " DRWE" : "", + (temp & RH_HS_OCI) ? " OCI" : "", + (temp & RH_HS_LPS) ? " LPS" : "" + ); + } + + for (i = 0; i < ndp; i++) { + temp = roothub_portstatus (controller, i); + dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s", + i, + temp, + (temp & RH_PS_PRSC) ? " PRSC" : "", + (temp & RH_PS_OCIC) ? " OCIC" : "", + (temp & RH_PS_PSSC) ? " PSSC" : "", + (temp & RH_PS_PESC) ? " PESC" : "", + (temp & RH_PS_CSC) ? " CSC" : "", + + (temp & RH_PS_LSDA) ? " LSDA" : "", + (temp & RH_PS_PPS) ? " PPS" : "", + (temp & RH_PS_PRS) ? " PRS" : "", + (temp & RH_PS_POCI) ? " POCI" : "", + (temp & RH_PS_PSS) ? " PSS" : "", + + (temp & RH_PS_PES) ? " PES" : "", + (temp & RH_PS_CCS) ? " CCS" : "" + ); + } +} + +static void ohci_dump (ohci_t *controller, int verbose) +{ + dbg ("OHCI controller usb-%s state", controller->slot_name); + + /* dumps some of the state we know about */ + ohci_dump_status (controller); + if (verbose) + ep_print_int_eds (controller, "hcca"); + dbg ("hcca frame #%04x", controller->hcca->frame_no); + ohci_dump_roothub (controller, 1); +} + + +#endif /* DEBUG */ + +/*-------------------------------------------------------------------------* + * Interface functions (URB) + *-------------------------------------------------------------------------*/ + +/* get a transfer request */ + +int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, struct devrequest *setup, int interval) +{ + ohci_t *ohci; + ed_t * ed; + urb_priv_t *purb_priv; + int i, size = 0; + + ohci = &gohci; + + /* when controller's hung, permit only roothub cleanup attempts + * such as powering down ports */ + if (ohci->disabled) { + err("sohci_submit_job: EPIPE"); + return -1; + } + + /* every endpoint has a ed, locate and fill it */ + if (!(ed = ep_add_ed (dev, pipe))) { + err("sohci_submit_job: ENOMEM"); + return -1; + } + + /* for the private part of the URB we need the number of TDs (size) */ + switch (usb_pipetype (pipe)) { + case PIPE_BULK: /* one TD for every 4096 Byte */ + size = (transfer_len - 1) / 4096 + 1; + break; + case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */ + size = (transfer_len == 0)? 2: + (transfer_len - 1) / 4096 + 3; + break; + } + + if (size >= (N_URB_TD - 1)) { + err("need %d TDs, only have %d", size, N_URB_TD); + return -1; + } + purb_priv = &urb_priv; + purb_priv->pipe = pipe; + + /* fill the private part of the URB */ + purb_priv->length = size; + purb_priv->ed = ed; + purb_priv->actual_length = 0; + + /* allocate the TDs */ + /* note that td[0] was allocated in ep_add_ed */ + for (i = 0; i < size; i++) { + purb_priv->td[i] = td_alloc (dev); + if (!purb_priv->td[i]) { + purb_priv->length = i; + urb_free_priv (purb_priv); + err("sohci_submit_job: ENOMEM"); + return -1; + } + } + + if (ed->state == ED_NEW || (ed->state & ED_DEL)) { + urb_free_priv (purb_priv); + err("sohci_submit_job: EINVAL"); + return -1; + } + + /* link the ed into a chain if is not already */ + if (ed->state != ED_OPER) + ep_link (ohci, ed); + + /* fill the TDs and link it to the ed */ + td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval); + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +/* tell us the current USB frame number */ + +static int sohci_get_current_frame_number (struct usb_device *usb_dev) +{ + ohci_t *ohci = &gohci; + + return m16_swap (ohci->hcca->frame_no); +} +#endif + +/*-------------------------------------------------------------------------* + * ED handling functions + *-------------------------------------------------------------------------*/ + +/* link an ed into one of the HC chains */ + +static int ep_link (ohci_t *ohci, ed_t *edi) +{ + volatile ed_t *ed = edi; + + ed->state = ED_OPER; + + switch (ed->type) { + case PIPE_CONTROL: + ed->hwNextED = 0; + if (ohci->ed_controltail == NULL) { + writel (ed, &ohci->regs->ed_controlhead); + } else { + ohci->ed_controltail->hwNextED = m32_swap (ed); + } + ed->ed_prev = ohci->ed_controltail; + if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && + !ohci->ed_rm_list[1] && !ohci->sleeping) { + ohci->hc_control |= OHCI_CTRL_CLE; + writel (ohci->hc_control, &ohci->regs->control); + } + ohci->ed_controltail = edi; + break; + + case PIPE_BULK: + ed->hwNextED = 0; + if (ohci->ed_bulktail == NULL) { + writel (ed, &ohci->regs->ed_bulkhead); + } else { + ohci->ed_bulktail->hwNextED = m32_swap (ed); + } + ed->ed_prev = ohci->ed_bulktail; + if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && + !ohci->ed_rm_list[1] && !ohci->sleeping) { + ohci->hc_control |= OHCI_CTRL_BLE; + writel (ohci->hc_control, &ohci->regs->control); + } + ohci->ed_bulktail = edi; + break; + } + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* unlink an ed from one of the HC chains. + * just the link to the ed is unlinked. + * 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) +{ + ed->hwINFO |= m32_swap (OHCI_ED_SKIP); + + switch (ed->type) { + case PIPE_CONTROL: + if (ed->ed_prev == NULL) { + if (!ed->hwNextED) { + ohci->hc_control &= ~OHCI_CTRL_CLE; + writel (ohci->hc_control, &ohci->regs->control); + } + writel (m32_swap (*((__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; + } + break; + + case PIPE_BULK: + if (ed->ed_prev == NULL) { + if (!ed->hwNextED) { + ohci->hc_control &= ~OHCI_CTRL_BLE; + writel (ohci->hc_control, &ohci->regs->control); + } + writel (m32_swap (*((__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; + } + break; + } + ed->state = ED_UNLINK; + return 0; +} + + +/*-------------------------------------------------------------------------*/ + +/* add/reinit an endpoint; this should be done once at the usb_set_configuration command, + * but the USB stack is a little bit stateless so we do it at every transaction + * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK + * in all other cases the state is left unchanged + * the ed info fields are setted anyway even though most of them should not change */ + +static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe) +{ + td_t *td; + ed_t *ed_ret; + volatile ed_t *ed; + + ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) | + (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]; + + if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) { + err("ep_add_ed: pending delete"); + /* pending delete request */ + return NULL; + } + + if (ed->state == ED_NEW) { + ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */ + /* dummy td; end of td list for ed */ + td = td_alloc (usb_dev); + ed->hwTailP = m32_swap (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) + | usb_pipeendpoint (pipe) << 7 + | (usb_pipeisoc (pipe)? 0x8000: 0) + | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) + | usb_pipeslow (pipe) << 13 + | usb_maxpacket (usb_dev, pipe) << 16); + + return ed_ret; +} + +/*-------------------------------------------------------------------------* + * TD handling functions + *-------------------------------------------------------------------------*/ + +/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ + +static void td_fill (ohci_t *ohci, unsigned int info, + void *data, int len, + struct usb_device *dev, int index, urb_priv_t *urb_priv) +{ + volatile td_t *td, *td_pt; +#ifdef OHCI_FILL_TRACE + int i; +#endif + + if (index > urb_priv->length) { + err("index > length"); + return; + } + /* use this td as the next dummy */ + td_pt = urb_priv->td [index]; + td_pt->hwNextTD = 0; + + /* fill the old dummy TD */ + td = urb_priv->td [index] = (td_t *)(m32_swap (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 ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) { + for (i = 0; i < len; i++) + printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]); + printf("\n"); + } +#endif + if (!len) + data = 0; + + td->hwINFO = m32_swap (info); + td->hwCBP = m32_swap (data); + if (data) + td->hwBE = m32_swap (data + len - 1); + else + td->hwBE = 0; + td->hwNextTD = m32_swap (td_pt); + td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000); + + /* append to queue */ + td->ed->hwTailP = td->hwNextTD; +} + +/*-------------------------------------------------------------------------*/ + +/* prepare all TDs of a transfer */ + +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) +{ + ohci_t *ohci = &gohci; + int data_len = transfer_len; + void *data; + int cnt = 0; + __u32 info = 0; + unsigned int toggle = 0; + + /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */ + if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) { + toggle = TD_T_TOGGLE; + } else { + toggle = TD_T_DATA0; + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1); + } + urb->td_cnt = 0; + if (data_len) + data = buffer; + else + data = 0; + + switch (usb_pipetype (pipe)) { + case PIPE_BULK: + info = usb_pipeout (pipe)? + TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ; + while(data_len > 4096) { + td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb); + data += 4096; data_len -= 4096; cnt++; + } + info = usb_pipeout (pipe)? + TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ; + td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb); + cnt++; + + if (!ohci->sleeping) + writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ + break; + + case PIPE_CONTROL: + info = TD_CC | TD_DP_SETUP | TD_T_DATA0; + 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; + /* NOTE: mishandles transfers >8K, some >4K */ + td_fill (ohci, info, data, data_len, dev, cnt++, urb); + } + info = usb_pipeout (pipe)? + TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; + td_fill (ohci, info, data, 0, dev, cnt++, urb); + if (!ohci->sleeping) + writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ + break; + } + if (urb->length != cnt) + dbg("TD LENGTH %d != CNT %d", urb->length, cnt); +} + +/*-------------------------------------------------------------------------* + * Done List handling functions + *-------------------------------------------------------------------------*/ + + +/* calculate the transfer length and update the urb */ + +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); + + + if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL && + ((td->index == 0) || (td->index == lurb_priv->length - 1)))) { + if (tdBE != 0) { + if (td->hwCBP == 0) + lurb_priv->actual_length += tdBE - td->data + 1; + else + lurb_priv->actual_length += tdCBP - td->data; + } + } +} + +/*-------------------------------------------------------------------------*/ + +/* replies to the request have to be on a FIFO basis so + * we reverse the reversed done-list */ + +static td_t * dl_reverse_done_list (ohci_t *ohci) +{ + __u32 td_list_hc; + td_t *td_rev = NULL; + td_t *td_list = NULL; + urb_priv_t *lurb_priv = NULL; + + td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0; + ohci->hcca->done_head = 0; + + while (td_list_hc) { + td_list = (td_t *)td_list_hc; + + if (TD_CC_GET (m32_swap (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)) { + 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_cnt += lurb_priv->length - td_list->index - 1; + } else + td_list->ed->hwHeadP &= m32_swap (0xfffffff2); + } + } + + td_list->next_dl_td = td_rev; + td_rev = td_list; + td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0; + } + return td_list; +} + +/*-------------------------------------------------------------------------*/ + +/* td done list */ +static int dl_done_list (ohci_t *ohci, td_t *td_list) +{ + td_t *td_list_next = NULL; + ed_t *ed; + int cc = 0; + int stat = 0; + /* urb_t *urb; */ + urb_priv_t *lurb_priv; + __u32 tdINFO, edHeadP, edTailP; + + while (td_list) { + td_list_next = td_list->next_dl_td; + + lurb_priv = &urb_priv; + tdINFO = m32_swap (td_list->hwINFO); + + ed = td_list->ed; + + dl_transfer_length(td_list); + + /* error code of transfer */ + cc = TD_CC_GET (tdINFO); + if (cc != 0) { + dbg("ConditionCode %#x", cc); + stat = cc_to_error[cc]; + } + + if (ed->state != ED_NEW) { + edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0; + edTailP = m32_swap (ed->hwTailP); + + /* unlink eds if they are not busy */ + if ((edHeadP == edTailP) && (ed->state == ED_OPER)) + ep_unlink (ohci, ed); + } + + td_list = td_list_next; + } + return stat; +} + +/*-------------------------------------------------------------------------* + * Virtual Root Hub + *-------------------------------------------------------------------------*/ + +/* Device descriptor */ +static __u8 root_hub_dev_des[] = +{ + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x10, /* __u16 bcdUSB; v1.1 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x01, /* __u8 iProduct; */ + 0x00, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + + +/* Configuration descriptor */ +static __u8 root_hub_config_des[] = +{ + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ + 0x00, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static unsigned char root_hub_str_index0[] = +{ + 0x04, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 0x09, /* __u8 lang ID */ + 0x04, /* __u8 lang ID */ +}; + +static unsigned char root_hub_str_index1[] = +{ + 28, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 'O', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'H', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'C', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'I', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'R', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 't', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'H', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'u', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'b', /* __u8 Unicode */ + 0, /* __u8 Unicode */ +}; + +/* Hub class-specific descriptor is constructed dynamically */ + + +/*-------------------------------------------------------------------------*/ + +#define OK(x) len = (x); break +#ifdef DEBUG +#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);} +#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);} +#else +#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status) +#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1]) +#endif +#define RD_RH_STAT roothub_status(&gohci) +#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1) + +/* request to virtual root hub */ + +int rh_check_port_status(ohci_t *controller) +{ + __u32 temp, ndp, i; + int res; + + res = -1; + temp = roothub_a (controller); + ndp = (temp & RH_A_NDP); +#ifdef CONFIG_AT91C_PQFP_UHPBUG + ndp = (ndp == 2) ? 1:0; +#endif + for (i = 0; i < ndp; i++) { + temp = roothub_portstatus (controller, i); + /* check for a device disconnect */ + if (((temp & (RH_PS_PESC | RH_PS_CSC)) == + (RH_PS_PESC | RH_PS_CSC)) && + ((temp & RH_PS_CCS) == 0)) { + res = i; + break; + } + } + return res; +} + +static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, struct devrequest *cmd) +{ + void * data = buffer; + int leni = transfer_len; + int len = 0; + int stat = 0; + __u32 datab[4]; + __u8 *data_buf = (__u8 *)datab; + __u16 bmRType_bReq; + __u16 wValue; + __u16 wIndex; + __u16 wLength; + +#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"); + return 0; + } + + bmRType_bReq = cmd->requesttype | (cmd->request << 8); + wValue = m16_swap (cmd->value); + wIndex = m16_swap (cmd->index); + wLength = m16_swap (cmd->length); + + info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x", + dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength); + + switch (bmRType_bReq) { + /* Request Destination: + without flags: Device, + RH_INTERFACE: interface, + RH_ENDPOINT: endpoint, + RH_CLASS means HUB here, + RH_OTHER | RH_CLASS almost ever means HUB_PORT here + */ + + case RH_GET_STATUS: + *(__u16 *) data_buf = m16_swap (1); OK (2); + case RH_GET_STATUS | RH_INTERFACE: + *(__u16 *) data_buf = m16_swap (0); OK (2); + case RH_GET_STATUS | RH_ENDPOINT: + *(__u16 *) data_buf = m16_swap (0); OK (2); + case RH_GET_STATUS | RH_CLASS: + *(__u32 *) data_buf = m32_swap ( + 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); + + case RH_CLEAR_FEATURE | RH_ENDPOINT: + switch (wValue) { + case (RH_ENDPOINT_STALL): OK (0); + } + break; + + case RH_CLEAR_FEATURE | RH_CLASS: + switch (wValue) { + case RH_C_HUB_LOCAL_POWER: + OK(0); + case (RH_C_HUB_OVER_CURRENT): + WR_RH_STAT(RH_HS_OCIC); OK (0); + } + break; + + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_ENABLE): + WR_RH_PORTSTAT (RH_PS_CCS ); OK (0); + case (RH_PORT_SUSPEND): + WR_RH_PORTSTAT (RH_PS_POCI); OK (0); + case (RH_PORT_POWER): + WR_RH_PORTSTAT (RH_PS_LSDA); OK (0); + case (RH_C_PORT_CONNECTION): + WR_RH_PORTSTAT (RH_PS_CSC ); OK (0); + case (RH_C_PORT_ENABLE): + WR_RH_PORTSTAT (RH_PS_PESC); OK (0); + case (RH_C_PORT_SUSPEND): + WR_RH_PORTSTAT (RH_PS_PSSC); OK (0); + case (RH_C_PORT_OVER_CURRENT): + WR_RH_PORTSTAT (RH_PS_OCIC); OK (0); + case (RH_C_PORT_RESET): + WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); + } + break; + + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + switch (wValue) { + case (RH_PORT_SUSPEND): + WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); + case (RH_PORT_RESET): /* BUG IN HUP CODE *********/ + if (RD_RH_PORTSTAT & RH_PS_CCS) + WR_RH_PORTSTAT (RH_PS_PRS); + OK (0); + case (RH_PORT_POWER): + WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); + case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/ + if (RD_RH_PORTSTAT & RH_PS_CCS) + WR_RH_PORTSTAT (RH_PS_PES ); + OK (0); + } + break; + + case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0); + + case RH_GET_DESCRIPTOR: + switch ((wValue & 0xff00) >> 8) { + case (0x01): /* device descriptor */ + len = min_t(unsigned int, + leni, + min_t(unsigned int, + sizeof (root_hub_dev_des), + wLength)); + data_buf = root_hub_dev_des; OK(len); + case (0x02): /* configuration descriptor */ + len = min_t(unsigned int, + leni, + min_t(unsigned int, + sizeof (root_hub_config_des), + wLength)); + data_buf = root_hub_config_des; OK(len); + case (0x03): /* string descriptors */ + if(wValue==0x0300) { + len = min_t(unsigned int, + leni, + min_t(unsigned int, + sizeof (root_hub_str_index0), + wLength)); + data_buf = root_hub_str_index0; + OK(len); + } + if(wValue==0x0301) { + len = min_t(unsigned int, + leni, + min_t(unsigned int, + sizeof (root_hub_str_index1), + wLength)); + data_buf = root_hub_str_index1; + OK(len); + } + default: + stat = USB_ST_STALLED; + } + break; + + case RH_GET_DESCRIPTOR | RH_CLASS: + { + __u32 temp = roothub_a (&gohci); + + data_buf [0] = 9; /* min length; */ + data_buf [1] = 0x29; + data_buf [2] = temp & RH_A_NDP; +#ifdef CONFIG_AT91C_PQFP_UHPBUG + data_buf [2] = (data_buf [2] == 2) ? 1:0; +#endif +#if 0 /* def CONFIG_CPU_MONAHANS */ + data_buf [2] = (data_buf [2] == 2) ? 3:0; +#endif + + 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? */ + data_buf [3] |= 0x10; +#if 1 + else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */ + data_buf [3] |= 0x8; +#endif + + /* 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 { + 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); + } + + case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1); + + case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0); + + default: + dbg ("unsupported root hub command"); + stat = USB_ST_STALLED; + } + +#ifdef DEBUG + ohci_dump_roothub (&gohci, 1); +#else + wait_ms(1); +#endif + + len = min_t(int, len, leni); + if (data != data_buf) + memcpy (data, data_buf, len); + dev->act_len = len; + dev->status = stat; + +#ifdef DEBUG + 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; +} + +/*-------------------------------------------------------------------------*/ + +/* common code for handling submit messages - used for all but root hub */ +/* accesses. */ +int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, struct devrequest *setup, int interval) +{ + int stat = 0; + int maxsize = usb_maxpacket(dev, pipe); + int timeout; + + /* device pulled? Shortcut the action. */ + if (devgone == dev) { + dev->status = USB_ST_CRC_ERR; + return 0; + } + +#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", + pipe); + return -1; + } + + if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) { + err("sohci_submit_job failed"); + 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) + timeout = BULK_TO; + else + timeout = 100; + + /* wait for it to complete */ + for (;;) { + /* check whether the controller is done */ + stat = hc_interrupt(); + if (stat < 0) { + stat = USB_ST_CRC_ERR; + break; + } + if (stat >= 0 && stat != 0xff) { + /* 0xff is returned for an SF-interrupt */ + break; + } + if (--timeout) { + wait_ms(1); + } else { + err("CTL:TIMEOUT "); + stat = USB_ST_CRC_ERR; + break; + } + } + /* we got an Root Hub Status Change interrupt */ + if (got_rhsc) { +#ifdef DEBUG + ohci_dump_roothub (&gohci, 1); +#endif + got_rhsc = 0; + /* abuse timeout */ + timeout = rh_check_port_status(&gohci); + if (timeout >= 0) { +#if 0 /* this does nothing useful, but leave it here in case that changes */ + /* the called routine adds 1 to the passed value */ + usb_hub_port_connect_change(gohci.rh.dev, timeout - 1); +#endif + /* + * XXX + * This is potentially dangerous because it assumes + * that only one device is ever plugged in! + */ + devgone = dev; + } + } + + 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 */ + urb_free_priv (&urb_priv); + return 0; +} + +/* submit routines called from usb.c */ +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len) +{ + info("submit_bulk_msg"); + return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0); +} + +int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, struct devrequest *setup) +{ + int maxsize = usb_maxpacket(dev, pipe); + + info("submit_control_msg"); +#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", + pipe); + return -1; + } + if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) { + gohci.rh.dev = dev; + /* root hub - redirect */ + return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len, + setup); + } + + return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0); +} + +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, int interval) +{ + info("submit_int_msg"); + return -1; +} + +/*-------------------------------------------------------------------------* + * HC functions + *-------------------------------------------------------------------------*/ + +/* reset the HC and BUS */ + +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"); + while (readl (&ohci->regs->control) & OHCI_CTRL_IR) { + wait_ms (10); + if (--smm_timeout == 0) { + err("USB HC TakeOver failed!"); + return -1; + } + } + } + + /* Disable HC interrupts */ + writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); + + 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); + + /* HC Reset requires max 10 us delay */ + writel (OHCI_HCR, &ohci->regs->cmdstatus); + while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { + if (--timeout == 0) { + err("USB HC reset timed out!"); + return -1; + } + udelay (1); + } + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* Start an OHCI controller, set the BUS operational + * enable interrupts + * connect the virtual root hub */ + +static int hc_start (ohci_t * ohci) +{ + __u32 mask; + unsigned int fminterval; + + ohci->disabled = 1; + + /* Tell the controller where the control and bulk lists are + * The lists are empty now. */ + + writel (0, &ohci->regs->ed_controlhead); + writel (0, &ohci->regs->ed_bulkhead); + + writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */ + + fminterval = 0x2edf; + writel ((fminterval * 9) / 10, &ohci->regs->periodicstart); + fminterval |= ((((fminterval - 210) * 6) / 7) << 16); + writel (fminterval, &ohci->regs->fminterval); + writel (0x628, &ohci->regs->lsthresh); + + /* start controller operations */ + ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; + ohci->disabled = 0; + writel (ohci->hc_control, &ohci->regs->control); + + /* disable all interrupts */ + mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD | + OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC | + OHCI_INTR_OC | OHCI_INTR_MIE); + writel (mask, &ohci->regs->intrdisable); + /* clear all interrupts */ + mask &= ~OHCI_INTR_MIE; + writel (mask, &ohci->regs->intrstatus); + /* Choose the interrupts we care about now - but w/o MIE */ + mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO; + writel (mask, &ohci->regs->intrenable); + +#ifdef OHCI_USE_NPS + /* required for AMD-756 and some Mac platforms */ + writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM, + &ohci->regs->roothub.a); + writel (RH_HS_LPSC, &ohci->regs->roothub.status); +#endif /* OHCI_USE_NPS */ + +#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); + + /* connect the virtual root hub */ + ohci->rh.devnum = 0; + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* an interrupt happens */ + +static int +hc_interrupt (void) +{ + ohci_t *ohci = &gohci; + struct ohci_regs *regs = ohci->regs; + int ints; + int stat = -1; + + if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) { + ints = OHCI_INTR_WDH; + } else { + ints = readl (®s->intrstatus); + } + + /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */ + + if (ints & OHCI_INTR_RHSC) { + got_rhsc = 1; + } + + if (ints & OHCI_INTR_UE) { + ohci->disabled++; + err ("OHCI Unrecoverable Error, controller usb-%s disabled", + ohci->slot_name); + /* e.g. due to PCI Master/Target Abort */ + +#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. */ + /* Count and limit the retries though; either hardware or */ + /* software errors can go forever... */ + hc_reset (ohci); + return -1; + } + + if (ints & OHCI_INTR_WDH) { + wait_ms(1); + writel (OHCI_INTR_WDH, ®s->intrdisable); + stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci)); + writel (OHCI_INTR_WDH, ®s->intrenable); + } + + if (ints & OHCI_INTR_SO) { + dbg("USB Schedule overrun\n"); + writel (OHCI_INTR_SO, ®s->intrenable); + stat = -1; + } + + /* 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; + wait_ms(1); + writel (OHCI_INTR_SF, ®s->intrdisable); + if (ohci->ed_rm_list[frame] != NULL) + writel (OHCI_INTR_SF, ®s->intrenable); + stat = 0xff; + } + + writel (ints, ®s->intrstatus); + return stat; +} + +/*-------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------*/ + +/* De-allocate all resources.. */ + +static void hc_release_ohci (ohci_t *ohci) +{ + dbg ("USB HC release ohci usb-%s", ohci->slot_name); + + if (!ohci->disabled) + hc_reset (ohci); +} + +/*-------------------------------------------------------------------------*/ + +/* + * low level initalisation routine, called from usb.c + */ +static char ohci_inited = 0; + +int usb_lowlevel_init(void) +{ + /* do board dependant init */ + if(usb_board_init()) + return -1; + + memset (&gohci, 0, sizeof (ohci_t)); + memset (&urb_priv, 0, sizeof (urb_priv_t)); + + /* align the storage */ + if ((__u32)&ghcca[0] & 0xff) { + err("HCCA not aligned!!"); + return -1; + } + phcca = &ghcca[0]; + info("aligned ghcca %p", phcca); + memset(&ohci_dev, 0, sizeof(struct ohci_device)); + if ((__u32)&ohci_dev.ed[0] & 0x7) { + err("EDs not aligned!!"); + return -1; + } + memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1)); + if ((__u32)gtd & 0x7) { + err("TDs not aligned!!"); + return -1; + } + ptd = gtd; + gohci.hcca = phcca; + memset (phcca, 0, sizeof (struct ohci_hcca)); + + gohci.disabled = 1; + gohci.sleeping = 0; + gohci.irq = -1; + gohci.regs = (struct ohci_regs *)OHCI_REGS_BASE; + + gohci.flags = 0; + gohci.slot_name = "delta/zylonite"; + + if (hc_reset (&gohci) < 0) { + hc_release_ohci (&gohci); + err ("can't reset usb-%s", gohci.slot_name); + /* Initialization failed disable clocks */ + CKENA &= ~(CKENA_2_USBHOST | CKENA_20_UDC); + return -1; + } + + /* 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) { + err ("can't start usb-%s", gohci.slot_name); + hc_release_ohci (&gohci); + /* Initialization failed */ + CKENA &= ~(CKENA_2_USBHOST | CKENA_20_UDC); + return -1; + } + +#ifdef DEBUG + ohci_dump (&gohci, 1); +#else + wait_ms(1); +#endif + ohci_inited = 1; + return 0; +} + +int usb_lowlevel_stop(void) +{ + /* this gets called really early - before the controller has */ + /* even been initialized! */ + if (!ohci_inited) + return 0; + /* TODO release any interrupts, etc. */ + /* call hc_release_ohci() here ? */ + hc_reset (&gohci); + + /* board dependant cleanup */ + if(usb_board_stop()) + return -1; + + return 0; +} + +#endif /* CONFIG_USB_OHCI */ diff --git a/drivers/usb_ohci.h b/drivers/usb_ohci.h new file mode 100644 index 0000000..7a1d9d9 --- /dev/null +++ b/drivers/usb_ohci.h @@ -0,0 +1,422 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber + * (C) Copyright 2000-2001 David Brownell + * + * usb-ohci.h + */ + +/* functions for doing board specific setup/cleanup */ +extern int usb_board_init(void); +extern int usb_board_stop(void); + +static int cc_to_error[16] = { + +/* mapping of the OHCI CC status to error codes */ + /* No Error */ 0, + /* CRC Error */ USB_ST_CRC_ERR, + /* Bit Stuff */ USB_ST_BIT_ERR, + /* Data Togg */ USB_ST_CRC_ERR, + /* Stall */ USB_ST_STALLED, + /* DevNotResp */ -1, + /* PIDCheck */ USB_ST_BIT_ERR, + /* UnExpPID */ USB_ST_BIT_ERR, + /* DataOver */ USB_ST_BUF_ERR, + /* DataUnder */ USB_ST_BUF_ERR, + /* reservd */ -1, + /* reservd */ -1, + /* BufferOver */ USB_ST_BUF_ERR, + /* BuffUnder */ USB_ST_BUF_ERR, + /* Not Access */ -1, + /* Not Access */ -1 +}; + +/* ED States */ + +#define ED_NEW 0x00 +#define ED_UNLINK 0x01 +#define ED_OPER 0x02 +#define ED_DEL 0x04 +#define ED_URB_DEL 0x08 + +/* usb_ohci_ed */ +struct ed { + __u32 hwINFO; + __u32 hwTailP; + __u32 hwHeadP; + __u32 hwNextED; + + struct ed *ed_prev; + __u8 int_period; + __u8 int_branch; + __u8 int_load; + __u8 int_interval; + __u8 state; + __u8 type; + __u16 last_iso; + struct ed *ed_rm_list; + + struct usb_device *usb_dev; + __u32 unused[3]; +} __attribute((aligned(16))); +typedef struct ed ed_t; + + +/* TD info field */ +#define TD_CC 0xf0000000 +#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) +#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) +#define TD_EC 0x0C000000 +#define TD_T 0x03000000 +#define TD_T_DATA0 0x02000000 +#define TD_T_DATA1 0x03000000 +#define TD_T_TOGGLE 0x00000000 +#define TD_R 0x00040000 +#define TD_DI 0x00E00000 +#define TD_DI_SET(X) (((X) & 0x07)<< 21) +#define TD_DP 0x00180000 +#define TD_DP_SETUP 0x00000000 +#define TD_DP_IN 0x00100000 +#define TD_DP_OUT 0x00080000 + +#define TD_ISO 0x00010000 +#define TD_DEL 0x00020000 + +/* CC Codes */ +#define TD_CC_NOERROR 0x00 +#define TD_CC_CRC 0x01 +#define TD_CC_BITSTUFFING 0x02 +#define TD_CC_DATATOGGLEM 0x03 +#define TD_CC_STALL 0x04 +#define TD_DEVNOTRESP 0x05 +#define TD_PIDCHECKFAIL 0x06 +#define TD_UNEXPECTEDPID 0x07 +#define TD_DATAOVERRUN 0x08 +#define TD_DATAUNDERRUN 0x09 +#define TD_BUFFEROVERRUN 0x0C +#define TD_BUFFERUNDERRUN 0x0D +#define TD_NOTACCESSED 0x0F + + +#define MAXPSW 1 + +struct td { + __u32 hwINFO; + __u32 hwCBP; /* Current Buffer Pointer */ + __u32 hwNextTD; /* Next TD Pointer */ + __u32 hwBE; /* Memory Buffer End Pointer */ + + __u16 hwPSW[MAXPSW]; + __u8 unused; + __u8 index; + struct ed *ed; + struct td *next_dl_td; + struct usb_device *usb_dev; + int transfer_len; + __u32 data; + + __u32 unused2[2]; +} __attribute((aligned(32))); +typedef struct td td_t; + +#define OHCI_ED_SKIP (1 << 14) + +/* + * The HCCA (Host Controller Communications Area) is a 256 byte + * structure defined in the OHCI spec. that the host controller is + * told the base address of. It must be 256-byte aligned. + */ + +#define NUM_INTS 32 /* part of the OHCI standard */ +struct ohci_hcca { + __u32 int_table[NUM_INTS]; /* Interrupt ED table */ + __u16 frame_no; /* current frame number */ + __u16 pad1; /* set to 0 on each frame_no change */ + __u32 done_head; /* info returned for an interrupt */ + u8 reserved_for_hc[116]; +} __attribute((aligned(256))); + + +/* + * Maximum number of root hub ports. + */ +#define MAX_ROOT_PORTS 3 /* maximum OHCI root hub ports */ + +/* + * This is the structure of the OHCI controller's memory mapped I/O + * region. This is Memory Mapped I/O. You must use the readl() and + * writel() macros defined in asm/io.h to access these!! + */ +struct ohci_regs { + /* control and status registers */ + __u32 revision; + __u32 control; + __u32 cmdstatus; + __u32 intrstatus; + __u32 intrenable; + __u32 intrdisable; + /* memory pointers */ + __u32 hcca; + __u32 ed_periodcurrent; + __u32 ed_controlhead; + __u32 ed_controlcurrent; + __u32 ed_bulkhead; + __u32 ed_bulkcurrent; + __u32 donehead; + /* frame counters */ + __u32 fminterval; + __u32 fmremaining; + __u32 fmnumber; + __u32 periodicstart; + __u32 lsthresh; + /* Root hub ports */ + struct ohci_roothub_regs { + __u32 a; + __u32 b; + __u32 status; + __u32 portstatus[MAX_ROOT_PORTS]; + } roothub; +} __attribute((aligned(32))); + + +/* OHCI CONTROL AND STATUS REGISTER MASKS */ + +/* + * HcControl (control) register masks + */ +#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */ +#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */ +#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */ +#define OHCI_CTRL_CLE (1 << 4) /* control list enable */ +#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */ +#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */ +#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ +#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ +#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ + +/* pre-shifted values for HCFS */ +# define OHCI_USB_RESET (0 << 6) +# define OHCI_USB_RESUME (1 << 6) +# define OHCI_USB_OPER (2 << 6) +# define OHCI_USB_SUSPEND (3 << 6) + +/* + * HcCommandStatus (cmdstatus) register masks + */ +#define OHCI_HCR (1 << 0) /* host controller reset */ +#define OHCI_CLF (1 << 1) /* control list filled */ +#define OHCI_BLF (1 << 2) /* bulk list filled */ +#define OHCI_OCR (1 << 3) /* ownership change request */ +#define OHCI_SOC (3 << 16) /* scheduling overrun count */ + +/* + * masks used with interrupt registers: + * HcInterruptStatus (intrstatus) + * HcInterruptEnable (intrenable) + * HcInterruptDisable (intrdisable) + */ +#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ +#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */ +#define OHCI_INTR_SF (1 << 2) /* start frame */ +#define OHCI_INTR_RD (1 << 3) /* resume detect */ +#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ +#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ +#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ +#define OHCI_INTR_OC (1 << 30) /* ownership change */ +#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ + + +/* Virtual Root HUB */ +struct virt_root_hub { + int devnum; /* Address of Root Hub endpoint */ + void *dev; /* was urb */ + void *int_addr; + int send; + int interval; +}; + +/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ + +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 + +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 + +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 + + +/* OHCI ROOT HUB REGISTER MASKS */ + +/* roothub.portstatus [i] bits */ +#define RH_PS_CCS 0x00000001 /* current connect status */ +#define RH_PS_PES 0x00000002 /* port enable status*/ +#define RH_PS_PSS 0x00000004 /* port suspend status */ +#define RH_PS_POCI 0x00000008 /* port over current indicator */ +#define RH_PS_PRS 0x00000010 /* port reset status */ +#define RH_PS_PPS 0x00000100 /* port power status */ +#define RH_PS_LSDA 0x00000200 /* low speed device attached */ +#define RH_PS_CSC 0x00010000 /* connect status change */ +#define RH_PS_PESC 0x00020000 /* port enable status change */ +#define RH_PS_PSSC 0x00040000 /* port suspend status change */ +#define RH_PS_OCIC 0x00080000 /* over current indicator change */ +#define RH_PS_PRSC 0x00100000 /* port reset status change */ + +/* roothub.status bits */ +#define RH_HS_LPS 0x00000001 /* local power status */ +#define RH_HS_OCI 0x00000002 /* over current indicator */ +#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */ +#define RH_HS_LPSC 0x00010000 /* local power status change */ +#define RH_HS_OCIC 0x00020000 /* over current indicator change */ +#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */ + +/* roothub.b masks */ +#define RH_B_DR 0x0000ffff /* device removable flags */ +#define RH_B_PPCM 0xffff0000 /* port power control mask */ + +/* roothub.a masks */ +#define RH_A_NDP (0xff << 0) /* number of downstream ports */ +#define RH_A_PSM (1 << 8) /* power switching mode */ +#define RH_A_NPS (1 << 9) /* no power switching */ +#define RH_A_DT (1 << 10) /* device type (mbz) */ +#define RH_A_OCPM (1 << 11) /* over current protection mode */ +#define RH_A_NOCP (1 << 12) /* no over current protection */ +#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ + +/* urb */ +#define N_URB_TD 48 +typedef struct +{ + ed_t *ed; + __u16 length; /* number of tds associated with this request */ + __u16 td_cnt; /* number of tds already serviced */ + int state; + unsigned long pipe; + int actual_length; + td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */ +} urb_priv_t; +#define URB_DEL 1 + +/* + * This is the full ohci controller description + * + * Note how the "proper" USB information is just + * a subset of what the full implementation needs. (Linus) + */ + + +typedef struct ohci { + struct ohci_hcca *hcca; /* hcca */ + /*dma_addr_t hcca_dma;*/ + + int irq; + int disabled; /* e.g. got a UE, we're hung */ + int sleeping; + unsigned long flags; /* for HC bugs */ + + struct ohci_regs *regs; /* OHCI controller's memory */ + + ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */ + ed_t *ed_bulktail; /* last endpoint of bulk list */ + ed_t *ed_controltail; /* last endpoint of control list */ + int intrstatus; + __u32 hc_control; /* copy of the hc control reg */ + struct usb_device *dev[32]; + struct virt_root_hub rh; + + const char *slot_name; +} ohci_t; + +#define NUM_EDS 8 /* num of preallocated endpoint descriptors */ + +struct ohci_device { + ed_t ed[NUM_EDS]; + int ed_cnt; +}; + +/* hcd */ +/* endpoint */ +static int ep_link(ohci_t * ohci, ed_t * ed); +static int ep_unlink(ohci_t * ohci, ed_t * ed); +static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe); + +/*-------------------------------------------------------------------------*/ + +/* we need more TDs than EDs */ +#define NUM_TD 64 + +/* +1 so we can align the storage */ +td_t gtd[NUM_TD+1]; +/* pointers to aligned storage */ +td_t *ptd; + +/* TDs ... */ +static inline struct td * +td_alloc (struct usb_device *usb_dev) +{ + int i; + struct td *td; + + td = NULL; + for (i = 0; i < NUM_TD; i++) + { + if (ptd[i].usb_dev == NULL) + { + td = &ptd[i]; + td->usb_dev = usb_dev; + break; + } + } + + return td; +} + +static inline void +ed_free (struct ed *ed) +{ + ed->usb_dev = NULL; +} diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index ebda719..c47306c 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -592,9 +592,11 @@ typedef void (*ExcpHndlr) (void) ; #define PMC_REG_BASE __REG(0x40500400) /* Primary Modem Codec */ #define SMC_REG_BASE __REG(0x40500500) /* Secondary Modem Codec */ + /* * USB Device Controller */ +#ifndef CONFIG_CPU_MONAHANS #define UDC_RES1 __REG(0x40600004) /* UDC Undocumented - Reserved1 */ #define UDC_RES2 __REG(0x40600008) /* UDC Undocumented - Reserved2 */ #define UDC_RES3 __REG(0x4060000C) /* UDC Undocumented - Reserved3 */ @@ -749,11 +751,30 @@ typedef void (*ExcpHndlr) (void) ; #define USIR1_IR13 (1 << 5) /* Interrup request ep 13 */ #define USIR1_IR14 (1 << 6) /* Interrup request ep 14 */ #define USIR1_IR15 (1 << 7) /* Interrup request ep 15 */ +#endif /* ! CONFIG_CPU_MONAHANS */ + +#if defined(CONFIG_PXA27X) || defined(CONFIG_CPU_MONAHANS) + +/* + * USB Client Controller (incomplete) + */ +#define UDCCR __REG(0x40600000) +#define UDCICR0 __REG(0x40600004) +#define UDCCIR0 __REG(0x40600008) +#define UDCISR0 __REG(0x4060000c) +#define UDCSIR1 __REG(0x40600010) +#define UDCFNR __REG(0x40600014) +#define UDCOTGICR __REG(0x40600018) +#define UDCOTGISR __REG(0x4060001c) +#define UP2OCR __REG(0x40600020) +#define UP3OCR __REG(0x40600024) + + -#if defined(CONFIG_PXA27X) /* * USB Host Controller */ +#define OHCI_REGS_BASE 0x4C000000 /* required for ohci driver */ #define UHCREV __REG(0x4C000000) #define UHCHCON __REG(0x4C000004) #define UHCCOMS __REG(0x4C000008) diff --git a/include/configs/delta.h b/include/configs/delta.h index 91284fd..0423bcb 100644 --- a/include/configs/delta.h +++ b/include/configs/delta.h @@ -94,13 +94,22 @@ # define CONFIG_COMMANDS ((CONFIG_CMD_DFL \ | CFG_CMD_ENV \ | CFG_CMD_NAND \ - | CFG_CMD_I2C) \ + | CFG_CMD_I2C \ + | CFG_CMD_USB \ + | CFG_CMD_FAT) \ & ~(CFG_CMD_NET \ | CFG_CMD_FLASH \ | CFG_CMD_IMLS)) #endif +#define CONFIG_USB_OHCI 1 +#define CONFIG_USB_STORAGE 1 +#define CONFIG_DOS_PARTITION 1 + +#define LITTLEENDIAN 1 /* used by usb_ohci.c */ + + /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ #include diff --git a/include/da9030.h b/include/da9030.h index 41108b9..3e3b202 100644 --- a/include/da9030.h +++ b/include/da9030.h @@ -104,3 +104,15 @@ #define SYS_CONTROL_A_HWRES_ENABLE (1<<2) #define SYS_CONTROL_A_WDOG_ACTION (1<<3) #define SYS_CONTROL_A_WATCHDOG (1<<7) + +#define MISC_CONTROLB_USB_INT_RISING (1<<2) +#define MISC_CONTROLB_SESSION_VALID_EN (1<<3) + +#define USB_PUMP_USBVE (1<<0) +#define USB_PUMP_USBVEP (1<<1) +#define USB_PUMP_SRP_DETECT (1<<2) +#define USB_PUMP_SESSION_VALID (1<<3) +#define USB_PUMP_VBUS_VALID_4_0 (1<<4) +#define USB_PUMP_VBUS_VALID_4_4 (1<<5) +#define USB_PUMP_EN_USBVE (1<<6) +#define USB_PUMP_EN_USBVEP (1<<7) -- cgit v1.1 From 24e37645e7378b20fa8f20e2996c8fb8e90c70c9 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Tue, 23 May 2006 10:33:11 +0200 Subject: More cleanup for the delta board and the generic usb_ohci driver. Added CFG_USB_BOARD_INIT and CFG_USB_CPU_INIT for enabling board and cpu specific initialization and cleanup hooks respectively. --- board/delta/delta.c | 55 ++------------------------------------ cpu/pxa/Makefile | 2 +- cpu/pxa/usb.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/usb_ohci.c | 59 ++++++++++++++++++++++++++++------------ drivers/usb_ohci.h | 8 ++++++ include/configs/delta.h | 8 ++++-- 6 files changed, 130 insertions(+), 73 deletions(-) create mode 100644 cpu/pxa/usb.c diff --git a/board/delta/delta.c b/board/delta/delta.c index d9fe8cb..6e22774 100644 --- a/board/delta/delta.c +++ b/board/delta/delta.c @@ -1,10 +1,6 @@ /* - * (C) Copyright 2002 - * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net - * - * (C) Copyright 2002 - * Sysgo Real-Time Solutions, GmbH - * Marius Groeger + * (C) Copyright 2006 + * DENX Software Engineering * * See file CREDITS for list of people who contributed to this * project. @@ -98,53 +94,6 @@ int board_late_init(void) return 0; } - -/* board dependant usb stuff */ -int usb_board_init() -{ - /* - * Enable USB host clock. - */ - CKENA |= (CKENA_2_USBHOST | CKENA_20_UDC); - udelay(100); - - /* Configure Port 2 for Host (USB Client Registers) */ - UP2OCR = 0x3000c; - -#if 0 - GPIO2_2 = 0x801; /* USBHPEN - Alt. Fkt. 1 */ - GPIO3_2 = 0x801; /* USBHPWR - Alt. Fkt. 1 */ -#endif - - UHCHR |= UHCHR_FHR; - wait_ms(11); /* udelay(11); */ - UHCHR &= ~UHCHR_FHR; - - UHCHR |= UHCHR_FSBIR; - while (UHCHR & UHCHR_FSBIR) - udelay(1); - -#if 0 - UHCHR |= UHCHR_PCPL; /* USBHPEN is active low */ - UHCHR |= UHCHR_PSPL; /* USBHPWR is active low */ -#endif - - UHCHR &= ~UHCHR_SSEP0; - UHCHR &= ~UHCHR_SSEP1; - UHCHR &= ~UHCHR_SSE; - - return 0; -} - -int usb_board_stop() -{ - /* may not want to do this */ - /* CKENA &= ~(CKENA_2_USBHOST | CKENA_20_UDC); */ - - return 0; -} - - /* * Magic Key Handling, mainly copied from board/lwmon/lwmon.c */ diff --git a/cpu/pxa/Makefile b/cpu/pxa/Makefile index 1af53d6..bd476f1 100644 --- a/cpu/pxa/Makefile +++ b/cpu/pxa/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = lib$(CPU).a START = start.o -OBJS = serial.o interrupts.o cpu.o i2c.o pxafb.o mmc.o +OBJS = serial.o interrupts.o cpu.o i2c.o pxafb.o mmc.o usb.o all: .depend $(START) $(LIB) diff --git a/cpu/pxa/usb.c b/cpu/pxa/usb.c new file mode 100644 index 0000000..e89391c --- /dev/null +++ b/cpu/pxa/usb.c @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2006 + * Markus Klotzbuecher, DENX Software Engineering + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#ifdef CFG_USB_CPU_INIT +# ifdef CONFIG_CPU_MONAHANS +int usb_cpu_init() +{ + /* Enable USB host clock. */ + CKENA |= (CKENA_2_USBHOST | CKENA_20_UDC); + udelay(100); + + /* Configure Port 2 for Host (USB Client Registers) */ + UP2OCR = 0x3000c; + +#if 0 + GPIO2_2 = 0x801; /* USBHPEN - Alt. Fkt. 1 */ + GPIO3_2 = 0x801; /* USBHPWR - Alt. Fkt. 1 */ +#endif + + UHCHR |= UHCHR_FHR; + wait_ms(11); + UHCHR &= ~UHCHR_FHR; + + UHCHR |= UHCHR_FSBIR; + while (UHCHR & UHCHR_FSBIR) + udelay(1); + +#if 0 + UHCHR |= UHCHR_PCPL; /* USBHPEN is active low */ + UHCHR |= UHCHR_PSPL; /* USBHPWR is active low */ +#endif + + UHCHR &= ~UHCHR_SSEP0; + UHCHR &= ~UHCHR_SSEP1; + UHCHR &= ~UHCHR_SSE; + + return 0; +} + +int usb_cpu_stop() +{ + /* may not want to do this */ + /* CKENA &= ~(CKENA_2_USBHOST | CKENA_20_UDC); */ + + return 0; +} +# endif /* CONFIG_CPU_MONAHANS */ +#endif /* CFG_USB_CPU_INIT */ diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index 4065489..f5af719 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -51,7 +51,10 @@ #include #include "usb_ohci.h" -/* #define OHCI_USE_NPS /\* force NoPowerSwitching mode *\/ */ +#ifdef CONFIG_ARM920T +# define OHCI_USE_NPS /* force NoPowerSwitching mode */ +#endif + #undef OHCI_VERBOSE_DEBUG /* not always helpful */ /* For initializing controller (mask in an HCFS mode too) */ @@ -311,9 +314,6 @@ static void ohci_dump_roothub (ohci_t *controller, int verbose) #ifdef CONFIG_AT91C_PQFP_UHPBUG ndp = (ndp == 2) ? 1:0; #endif -#if 0 /* def CONFIG_CPU_MONAHANS */ - data_buf [2] = (data_buf [2] == 2) ? 3:0; -#endif if (verbose) { dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp, ((temp & RH_A_POTPGT) >> 24) & 0xff, @@ -1150,19 +1150,13 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); #ifdef CONFIG_AT91C_PQFP_UHPBUG data_buf [2] = (data_buf [2] == 2) ? 1:0; #endif -#if 0 /* def CONFIG_CPU_MONAHANS */ - data_buf [2] = (data_buf [2] == 2) ? 3:0; -#endif - 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? */ data_buf [3] |= 0x10; -#if 1 else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */ data_buf [3] |= 0x8; -#endif /* corresponds to data_buf[4-7] */ datab [1] = 0; @@ -1557,10 +1551,18 @@ static char ohci_inited = 0; int usb_lowlevel_init(void) { - /* do board dependant init */ - if(usb_board_init()) + +#if CFG_USB_CPU_INIT + /* cpu dependant init */ + if(usb_cpu_init()) return -1; +#endif +#if CFG_USB_BOARD_INIT + /* board dependant init */ + if(usb_board_init()) + return -1; +#endif memset (&gohci, 0, sizeof (ohci_t)); memset (&urb_priv, 0, sizeof (urb_priv_t)); @@ -1588,28 +1590,43 @@ int usb_lowlevel_init(void) gohci.disabled = 1; gohci.sleeping = 0; gohci.irq = -1; - gohci.regs = (struct ohci_regs *)OHCI_REGS_BASE; + gohci.regs = (struct ohci_regs *)CFG_USB_OHCI_REGS_BASE; gohci.flags = 0; - gohci.slot_name = "delta/zylonite"; + gohci.slot_name = CFG_USB_SLOT_NAME; if (hc_reset (&gohci) < 0) { hc_release_ohci (&gohci); err ("can't reset usb-%s", gohci.slot_name); /* Initialization failed disable clocks */ - CKENA &= ~(CKENA_2_USBHOST | CKENA_20_UDC); +#if CFG_USB_BOARD_INIT + /* board dependant cleanup */ + usb_board_stop(); +#endif + +#if CFG_USB_CPU_INIT + /* cpu dependant cleanup */ + usb_cpu_stop(); +#endif return -1; } /* 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) { err ("can't start usb-%s", gohci.slot_name); hc_release_ohci (&gohci); /* Initialization failed */ - CKENA &= ~(CKENA_2_USBHOST | CKENA_20_UDC); +#if CFG_USB_BOARD_INIT + /* board dependant cleanup */ + usb_board_stop(); +#endif + +#if CFG_USB_CPU_INIT + /* cpu dependant cleanup */ + usb_cpu_stop(); +#endif return -1; } @@ -1632,9 +1649,17 @@ int usb_lowlevel_stop(void) /* call hc_release_ohci() here ? */ hc_reset (&gohci); +#if CFG_USB_BOARD_INIT /* board dependant cleanup */ if(usb_board_stop()) return -1; +#endif + +#if CFG_USB_CPU_INIT + /* cpu dependant cleanup */ + if(usb_cpu_stop()) + return -1; +#endif return 0; } diff --git a/drivers/usb_ohci.h b/drivers/usb_ohci.h index 7a1d9d9..c37b5f6 100644 --- a/drivers/usb_ohci.h +++ b/drivers/usb_ohci.h @@ -8,8 +8,16 @@ */ /* functions for doing board specific setup/cleanup */ +#ifdef CFG_USB_BOARD_INIT extern int usb_board_init(void); extern int usb_board_stop(void); +#endif + +#ifdef CFG_USB_CPU_INIT +extern int usb_cpu_init(void); +extern int usb_cpu_stop(void); +#endif + static int cc_to_error[16] = { diff --git a/include/configs/delta.h b/include/configs/delta.h index 0423bcb..e6b05e0 100644 --- a/include/configs/delta.h +++ b/include/configs/delta.h @@ -102,13 +102,17 @@ | CFG_CMD_IMLS)) #endif - +/* USB */ #define CONFIG_USB_OHCI 1 #define CONFIG_USB_STORAGE 1 #define CONFIG_DOS_PARTITION 1 -#define LITTLEENDIAN 1 /* used by usb_ohci.c */ +#undef CFG_USB_BOARD_INIT +#define CFG_USB_CPU_INIT 1 +#define CFG_USB_OHCI_REGS_BASE OHCI_REGS_BASE +#define CFG_USB_SLOT_NAME "delta" +#define LITTLEENDIAN 1 /* used by usb_ohci.c */ /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ #include -- cgit v1.1 From 301f1aa384d0edcae6a22fd9adb933ad71695ecc Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Tue, 23 May 2006 13:38:35 +0200 Subject: Changed the mp2usb (at91rm9200) board to use the generic OHCI driver. Some fixes to the latter. --- cpu/arm920t/at91rm9200/Makefile | 2 +- cpu/arm920t/at91rm9200/usb.c | 47 ++ cpu/arm920t/at91rm9200/usb_ohci.c | 1635 ------------------------------------- cpu/arm920t/at91rm9200/usb_ohci.h | 419 ---------- cpu/pxa/usb.c | 8 +- drivers/usb_ohci.c | 18 +- include/configs/delta.h | 6 +- include/configs/mp2usb.h | 11 +- 8 files changed, 73 insertions(+), 2073 deletions(-) create mode 100644 cpu/arm920t/at91rm9200/usb.c delete mode 100644 cpu/arm920t/at91rm9200/usb_ohci.c delete mode 100644 cpu/arm920t/at91rm9200/usb_ohci.h diff --git a/cpu/arm920t/at91rm9200/Makefile b/cpu/arm920t/at91rm9200/Makefile index aec9cb6..f9fccbc 100644 --- a/cpu/arm920t/at91rm9200/Makefile +++ b/cpu/arm920t/at91rm9200/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = lib$(SOC).a OBJS = bcm5221.o dm9161.o ether.o i2c.o interrupts.o \ - lxt972.o serial.o usb_ohci.o + lxt972.o serial.o usb.o SOBJS = lowlevel_init.o all: .depend $(LIB) diff --git a/cpu/arm920t/at91rm9200/usb.c b/cpu/arm920t/at91rm9200/usb.c new file mode 100644 index 0000000..7b83f23 --- /dev/null +++ b/cpu/arm920t/at91rm9200/usb.c @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2006 + * DENX Software Engineering + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +#if defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) +# ifdef CONFIG_AT91RM9200 + +#include + +int usb_cpu_init() +{ + /* Enable USB host clock. */ + *AT91C_PMC_SCER = AT91C_PMC_UHP; /* 48MHz clock enabled for UHP */ + *AT91C_PMC_PCER = 1 << AT91C_ID_UHP; /* Peripheral Clock Enable Register */ + return 0; +} + +int usb_cpu_stop() +{ + /* Initialization failed */ + *AT91C_PMC_PCDR = 1 << AT91C_ID_UHP; /* Peripheral Clock Disable Register */ + *AT91C_PMC_SCDR = AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */ + return 0; +} +# endif /* CONFIG_AT91RM9200 */ +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/cpu/arm920t/at91rm9200/usb_ohci.c b/cpu/arm920t/at91rm9200/usb_ohci.c deleted file mode 100644 index 5b2c56c..0000000 --- a/cpu/arm920t/at91rm9200/usb_ohci.c +++ /dev/null @@ -1,1635 +0,0 @@ -/* - * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200. - * - * (C) Copyright 2003 - * Gary Jennejohn, DENX Software Engineering - * - * Note: Much of this code has been derived from Linux 2.4 - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2002 David Brownell - * - * Modified for the MP2USB by (C) Copyright 2005 Eric Benard - * ebenard@eukrea.com - based on s3c24x0's driver - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ -/* - * 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 - * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes! - * 3 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG - * to activate workaround for bug #41 or this driver will NOT work! - */ - -#include -/* #include no PCI on the S3C24X0 */ - -#ifdef CONFIG_USB_OHCI - -#include - -#include -#include -#include "usb_ohci.h" - -#define OHCI_USE_NPS /* force NoPowerSwitching mode */ -#undef OHCI_VERBOSE_DEBUG /* not always helpful */ - -/* For initializing controller (mask in an HCFS mode too) */ -#define OHCI_CONTROL_INIT \ - (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE - -#define readl(a) (*((vu_long *)(a))) -#define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a)) - -#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) - -#undef 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) -#undef 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 */ -struct ohci_hcca ghcca[1]; -/* a pointer to the aligned storage */ -struct ohci_hcca *phcca; -/* this allocates EDs for all possible endpoints */ -struct ohci_device ohci_dev; -/* urb_priv */ -urb_priv_t urb_priv; -/* RHSC flag */ -int got_rhsc; -/* device which was disconnected */ -struct usb_device *devgone; - -/*-------------------------------------------------------------------------*/ - -/* AMD-756 (D2 rev) reports corrupt register contents in some cases. - * The erratum (#4) description is incorrect. AMD's workaround waits - * till some bits (mostly reserved) are clear; ok for all revs. - */ -#define OHCI_QUIRK_AMD756 0xabcd -#define read_roothub(hc, register, mask) ({ \ - u32 temp = readl (&hc->regs->roothub.register); \ - if (hc->flags & OHCI_QUIRK_AMD756) \ - while (temp & mask) \ - temp = readl (&hc->regs->roothub.register); \ - temp; }) - -static u32 roothub_a (struct ohci *hc) - { return read_roothub (hc, a, 0xfc0fe000); } -static inline u32 roothub_b (struct ohci *hc) - { return readl (&hc->regs->roothub.b); } -static inline u32 roothub_status (struct ohci *hc) - { return readl (&hc->regs->roothub.status); } -static u32 roothub_portstatus (struct ohci *hc, int i) - { return read_roothub (hc, portstatus [i], 0xffe0fce0); } - - -/* forward declaration */ -static int hc_interrupt (void); -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); - -/*-------------------------------------------------------------------------* - * URB support functions - *-------------------------------------------------------------------------*/ - -/* free HCD-private data associated with this URB */ - -static void urb_free_priv (urb_priv_t * urb) -{ - int i; - int last; - struct td * td; - - last = urb->length - 1; - if (last >= 0) { - for (i = 0; i <= last; i++) { - td = urb->td[i]; - if (td) { - td->usb_dev = NULL; - urb->td[i] = NULL; - } - } - } -} - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG -static int sohci_get_current_frame_number (struct usb_device * dev); - -/* debug| print the main components of an URB - * small: 0) header + data packets 1) just header */ - -static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer, - int transfer_len, struct devrequest * setup, char * str, int small) -{ - urb_priv_t * purb = &urb_priv; - - dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx", - str, - sohci_get_current_frame_number (dev), - usb_pipedevice (pipe), - usb_pipeendpoint (pipe), - usb_pipeout (pipe)? 'O': 'I', - usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"): - (usb_pipecontrol (pipe)? "CTRL": "BULK"), - purb->actual_length, - transfer_len, dev->status); -#ifdef OHCI_VERBOSE_DEBUG - if (!small) { - int i, len; - - if (usb_pipecontrol (pipe)) { - printf (__FILE__ ": cmd(8):"); - for (i = 0; i < 8 ; i++) - printf (" %02x", ((__u8 *) setup) [i]); - printf ("\n"); - } - if (transfer_len > 0 && buffer) { - printf (__FILE__ ": data(%d/%d):", - purb->actual_length, - transfer_len); - len = usb_pipeout (pipe)? - transfer_len: purb->actual_length; - for (i = 0; i < 16 && i < len; i++) - printf (" %02x", ((__u8 *) buffer) [i]); - printf ("%s\n", i < len? "...": ""); - } - } -#endif -} - -/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/ -void ep_print_int_eds (ohci_t *ohci, char * str) { - int i, j; - __u32 * ed_p; - for (i= 0; i < 32; i++) { - j = 5; - ed_p = &(ohci->hcca->int_table [i]); - if (*ed_p == 0) - 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); - printf (" ed: %4x;", ed->hwINFO); - ed_p = &ed->hwNextED; - } - printf ("\n"); - } -} - -static void ohci_dump_intr_mask (char *label, __u32 mask) -{ - dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s", - label, - mask, - (mask & OHCI_INTR_MIE) ? " MIE" : "", - (mask & OHCI_INTR_OC) ? " OC" : "", - (mask & OHCI_INTR_RHSC) ? " RHSC" : "", - (mask & OHCI_INTR_FNO) ? " FNO" : "", - (mask & OHCI_INTR_UE) ? " UE" : "", - (mask & OHCI_INTR_RD) ? " RD" : "", - (mask & OHCI_INTR_SF) ? " SF" : "", - (mask & OHCI_INTR_WDH) ? " WDH" : "", - (mask & OHCI_INTR_SO) ? " SO" : "" - ); -} - -static void maybe_print_eds (char *label, __u32 value) -{ - ed_t *edp = (ed_t *)value; - - if (value) { - dbg ("%s %08x", label, value); - dbg ("%08x", edp->hwINFO); - dbg ("%08x", edp->hwTailP); - dbg ("%08x", edp->hwHeadP); - dbg ("%08x", edp->hwNextED); - } -} - -static char * hcfs2string (int state) -{ - switch (state) { - case OHCI_USB_RESET: return "reset"; - case OHCI_USB_RESUME: return "resume"; - case OHCI_USB_OPER: return "operational"; - case OHCI_USB_SUSPEND: return "suspend"; - } - return "?"; -} - -/* dump control and status registers */ -static void ohci_dump_status (ohci_t *controller) -{ - struct ohci_regs *regs = controller->regs; - __u32 temp; - - temp = readl (®s->revision) & 0xff; - if (temp != 0x10) - dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f)); - - temp = readl (®s->control); - dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp, - (temp & OHCI_CTRL_RWE) ? " RWE" : "", - (temp & OHCI_CTRL_RWC) ? " RWC" : "", - (temp & OHCI_CTRL_IR) ? " IR" : "", - hcfs2string (temp & OHCI_CTRL_HCFS), - (temp & OHCI_CTRL_BLE) ? " BLE" : "", - (temp & OHCI_CTRL_CLE) ? " CLE" : "", - (temp & OHCI_CTRL_IE) ? " IE" : "", - (temp & OHCI_CTRL_PLE) ? " PLE" : "", - temp & OHCI_CTRL_CBSR - ); - - temp = readl (®s->cmdstatus); - dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp, - (temp & OHCI_SOC) >> 16, - (temp & OHCI_OCR) ? " OCR" : "", - (temp & OHCI_BLF) ? " BLF" : "", - (temp & OHCI_CLF) ? " CLF" : "", - (temp & OHCI_HCR) ? " HCR" : "" - ); - - ohci_dump_intr_mask ("intrstatus", readl (®s->intrstatus)); - ohci_dump_intr_mask ("intrenable", readl (®s->intrenable)); - - maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent)); - - maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead)); - maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent)); - - maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead)); - maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent)); - - maybe_print_eds ("donehead", readl (®s->donehead)); -} - -static void ohci_dump_roothub (ohci_t *controller, int verbose) -{ - __u32 temp, ndp, i; - - temp = roothub_a (controller); - ndp = (temp & RH_A_NDP); -#ifdef CONFIG_AT91C_PQFP_UHPBUG - ndp = (ndp == 2) ? 1:0; -#endif - if (verbose) { - dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp, - ((temp & RH_A_POTPGT) >> 24) & 0xff, - (temp & RH_A_NOCP) ? " NOCP" : "", - (temp & RH_A_OCPM) ? " OCPM" : "", - (temp & RH_A_DT) ? " DT" : "", - (temp & RH_A_NPS) ? " NPS" : "", - (temp & RH_A_PSM) ? " PSM" : "", - ndp - ); - temp = roothub_b (controller); - dbg ("roothub.b: %08x PPCM=%04x DR=%04x", - temp, - (temp & RH_B_PPCM) >> 16, - (temp & RH_B_DR) - ); - temp = roothub_status (controller); - dbg ("roothub.status: %08x%s%s%s%s%s%s", - temp, - (temp & RH_HS_CRWE) ? " CRWE" : "", - (temp & RH_HS_OCIC) ? " OCIC" : "", - (temp & RH_HS_LPSC) ? " LPSC" : "", - (temp & RH_HS_DRWE) ? " DRWE" : "", - (temp & RH_HS_OCI) ? " OCI" : "", - (temp & RH_HS_LPS) ? " LPS" : "" - ); - } - - for (i = 0; i < ndp; i++) { - temp = roothub_portstatus (controller, i); - dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s", - i, - temp, - (temp & RH_PS_PRSC) ? " PRSC" : "", - (temp & RH_PS_OCIC) ? " OCIC" : "", - (temp & RH_PS_PSSC) ? " PSSC" : "", - (temp & RH_PS_PESC) ? " PESC" : "", - (temp & RH_PS_CSC) ? " CSC" : "", - - (temp & RH_PS_LSDA) ? " LSDA" : "", - (temp & RH_PS_PPS) ? " PPS" : "", - (temp & RH_PS_PRS) ? " PRS" : "", - (temp & RH_PS_POCI) ? " POCI" : "", - (temp & RH_PS_PSS) ? " PSS" : "", - - (temp & RH_PS_PES) ? " PES" : "", - (temp & RH_PS_CCS) ? " CCS" : "" - ); - } -} - -static void ohci_dump (ohci_t *controller, int verbose) -{ - dbg ("OHCI controller usb-%s state", controller->slot_name); - - /* dumps some of the state we know about */ - ohci_dump_status (controller); - if (verbose) - ep_print_int_eds (controller, "hcca"); - dbg ("hcca frame #%04x", controller->hcca->frame_no); - ohci_dump_roothub (controller, 1); -} - - -#endif /* DEBUG */ - -/*-------------------------------------------------------------------------* - * Interface functions (URB) - *-------------------------------------------------------------------------*/ - -/* get a transfer request */ - -int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup, int interval) -{ - ohci_t *ohci; - ed_t * ed; - urb_priv_t *purb_priv; - int i, size = 0; - - ohci = &gohci; - - /* when controller's hung, permit only roothub cleanup attempts - * such as powering down ports */ - if (ohci->disabled) { - err("sohci_submit_job: EPIPE"); - return -1; - } - - /* every endpoint has a ed, locate and fill it */ - if (!(ed = ep_add_ed (dev, pipe))) { - err("sohci_submit_job: ENOMEM"); - return -1; - } - - /* for the private part of the URB we need the number of TDs (size) */ - switch (usb_pipetype (pipe)) { - case PIPE_BULK: /* one TD for every 4096 Byte */ - size = (transfer_len - 1) / 4096 + 1; - break; - case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */ - size = (transfer_len == 0)? 2: - (transfer_len - 1) / 4096 + 3; - break; - } - - if (size >= (N_URB_TD - 1)) { - err("need %d TDs, only have %d", size, N_URB_TD); - return -1; - } - purb_priv = &urb_priv; - purb_priv->pipe = pipe; - - /* fill the private part of the URB */ - purb_priv->length = size; - purb_priv->ed = ed; - purb_priv->actual_length = 0; - - /* allocate the TDs */ - /* note that td[0] was allocated in ep_add_ed */ - for (i = 0; i < size; i++) { - purb_priv->td[i] = td_alloc (dev); - if (!purb_priv->td[i]) { - purb_priv->length = i; - urb_free_priv (purb_priv); - err("sohci_submit_job: ENOMEM"); - return -1; - } - } - - if (ed->state == ED_NEW || (ed->state & ED_DEL)) { - urb_free_priv (purb_priv); - err("sohci_submit_job: EINVAL"); - return -1; - } - - /* link the ed into a chain if is not already */ - if (ed->state != ED_OPER) - ep_link (ohci, ed); - - /* fill the TDs and link it to the ed */ - td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG -/* tell us the current USB frame number */ - -static int sohci_get_current_frame_number (struct usb_device *usb_dev) -{ - ohci_t *ohci = &gohci; - - return m16_swap (ohci->hcca->frame_no); -} -#endif - -/*-------------------------------------------------------------------------* - * ED handling functions - *-------------------------------------------------------------------------*/ - -/* link an ed into one of the HC chains */ - -static int ep_link (ohci_t *ohci, ed_t *edi) -{ - volatile ed_t *ed = edi; - - ed->state = ED_OPER; - - switch (ed->type) { - case PIPE_CONTROL: - ed->hwNextED = 0; - if (ohci->ed_controltail == NULL) { - writel (ed, &ohci->regs->ed_controlhead); - } else { - ohci->ed_controltail->hwNextED = m32_swap (ed); - } - ed->ed_prev = ohci->ed_controltail; - if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && - !ohci->ed_rm_list[1] && !ohci->sleeping) { - ohci->hc_control |= OHCI_CTRL_CLE; - writel (ohci->hc_control, &ohci->regs->control); - } - ohci->ed_controltail = edi; - break; - - case PIPE_BULK: - ed->hwNextED = 0; - if (ohci->ed_bulktail == NULL) { - writel (ed, &ohci->regs->ed_bulkhead); - } else { - ohci->ed_bulktail->hwNextED = m32_swap (ed); - } - ed->ed_prev = ohci->ed_bulktail; - if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && - !ohci->ed_rm_list[1] && !ohci->sleeping) { - ohci->hc_control |= OHCI_CTRL_BLE; - writel (ohci->hc_control, &ohci->regs->control); - } - ohci->ed_bulktail = edi; - break; - } - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* unlink an ed from one of the HC chains. - * just the link to the ed is unlinked. - * 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) -{ - ed->hwINFO |= m32_swap (OHCI_ED_SKIP); - - switch (ed->type) { - case PIPE_CONTROL: - if (ed->ed_prev == NULL) { - if (!ed->hwNextED) { - ohci->hc_control &= ~OHCI_CTRL_CLE; - writel (ohci->hc_control, &ohci->regs->control); - } - writel (m32_swap (*((__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; - } - break; - - case PIPE_BULK: - if (ed->ed_prev == NULL) { - if (!ed->hwNextED) { - ohci->hc_control &= ~OHCI_CTRL_BLE; - writel (ohci->hc_control, &ohci->regs->control); - } - writel (m32_swap (*((__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; - } - break; - } - ed->state = ED_UNLINK; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -/* add/reinit an endpoint; this should be done once at the usb_set_configuration command, - * but the USB stack is a little bit stateless so we do it at every transaction - * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK - * in all other cases the state is left unchanged - * the ed info fields are setted anyway even though most of them should not change */ - -static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe) -{ - td_t *td; - ed_t *ed_ret; - volatile ed_t *ed; - - ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) | - (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]; - - if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) { - err("ep_add_ed: pending delete"); - /* pending delete request */ - return NULL; - } - - if (ed->state == ED_NEW) { - ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */ - /* dummy td; end of td list for ed */ - td = td_alloc (usb_dev); - ed->hwTailP = m32_swap (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) - | usb_pipeendpoint (pipe) << 7 - | (usb_pipeisoc (pipe)? 0x8000: 0) - | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) - | usb_pipeslow (pipe) << 13 - | usb_maxpacket (usb_dev, pipe) << 16); - - return ed_ret; -} - -/*-------------------------------------------------------------------------* - * TD handling functions - *-------------------------------------------------------------------------*/ - -/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ - -static void td_fill (ohci_t *ohci, unsigned int info, - void *data, int len, - struct usb_device *dev, int index, urb_priv_t *urb_priv) -{ - volatile td_t *td, *td_pt; -#ifdef OHCI_FILL_TRACE - int i; -#endif - - if (index > urb_priv->length) { - err("index > length"); - return; - } - /* use this td as the next dummy */ - td_pt = urb_priv->td [index]; - td_pt->hwNextTD = 0; - - /* fill the old dummy TD */ - td = urb_priv->td [index] = (td_t *)(m32_swap (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 ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) { - for (i = 0; i < len; i++) - printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]); - printf("\n"); - } -#endif - if (!len) - data = 0; - - td->hwINFO = m32_swap (info); - td->hwCBP = m32_swap (data); - if (data) - td->hwBE = m32_swap (data + len - 1); - else - td->hwBE = 0; - td->hwNextTD = m32_swap (td_pt); - td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000); - - /* append to queue */ - td->ed->hwTailP = td->hwNextTD; -} - -/*-------------------------------------------------------------------------*/ - -/* prepare all TDs of a transfer */ - -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) -{ - ohci_t *ohci = &gohci; - int data_len = transfer_len; - void *data; - int cnt = 0; - __u32 info = 0; - unsigned int toggle = 0; - - /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */ - if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) { - toggle = TD_T_TOGGLE; - } else { - toggle = TD_T_DATA0; - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1); - } - urb->td_cnt = 0; - if (data_len) - data = buffer; - else - data = 0; - - switch (usb_pipetype (pipe)) { - case PIPE_BULK: - info = usb_pipeout (pipe)? - TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ; - while(data_len > 4096) { - td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb); - data += 4096; data_len -= 4096; cnt++; - } - info = usb_pipeout (pipe)? - TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ; - td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb); - cnt++; - - if (!ohci->sleeping) - writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ - break; - - case PIPE_CONTROL: - info = TD_CC | TD_DP_SETUP | TD_T_DATA0; - 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; - /* NOTE: mishandles transfers >8K, some >4K */ - td_fill (ohci, info, data, data_len, dev, cnt++, urb); - } - info = usb_pipeout (pipe)? - TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; - td_fill (ohci, info, data, 0, dev, cnt++, urb); - if (!ohci->sleeping) - writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ - break; - } - if (urb->length != cnt) - dbg("TD LENGTH %d != CNT %d", urb->length, cnt); -} - -/*-------------------------------------------------------------------------* - * Done List handling functions - *-------------------------------------------------------------------------*/ - - -/* calculate the transfer length and update the urb */ - -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); - - - if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL && - ((td->index == 0) || (td->index == lurb_priv->length - 1)))) { - if (tdBE != 0) { - if (td->hwCBP == 0) - lurb_priv->actual_length += tdBE - td->data + 1; - else - lurb_priv->actual_length += tdCBP - td->data; - } - } -} - -/*-------------------------------------------------------------------------*/ - -/* replies to the request have to be on a FIFO basis so - * we reverse the reversed done-list */ - -static td_t * dl_reverse_done_list (ohci_t *ohci) -{ - __u32 td_list_hc; - td_t *td_rev = NULL; - td_t *td_list = NULL; - urb_priv_t *lurb_priv = NULL; - - td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0; - ohci->hcca->done_head = 0; - - while (td_list_hc) { - td_list = (td_t *)td_list_hc; - - if (TD_CC_GET (m32_swap (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)) { - 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_cnt += lurb_priv->length - td_list->index - 1; - } else - td_list->ed->hwHeadP &= m32_swap (0xfffffff2); - } - } - - td_list->next_dl_td = td_rev; - td_rev = td_list; - td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0; - } - return td_list; -} - -/*-------------------------------------------------------------------------*/ - -/* td done list */ -static int dl_done_list (ohci_t *ohci, td_t *td_list) -{ - td_t *td_list_next = NULL; - ed_t *ed; - int cc = 0; - int stat = 0; - /* urb_t *urb; */ - urb_priv_t *lurb_priv; - __u32 tdINFO, edHeadP, edTailP; - - while (td_list) { - td_list_next = td_list->next_dl_td; - - lurb_priv = &urb_priv; - tdINFO = m32_swap (td_list->hwINFO); - - ed = td_list->ed; - - dl_transfer_length(td_list); - - /* error code of transfer */ - cc = TD_CC_GET (tdINFO); - if (cc != 0) { - dbg("ConditionCode %#x", cc); - stat = cc_to_error[cc]; - } - - if (ed->state != ED_NEW) { - edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0; - edTailP = m32_swap (ed->hwTailP); - - /* unlink eds if they are not busy */ - if ((edHeadP == edTailP) && (ed->state == ED_OPER)) - ep_unlink (ohci, ed); - } - - td_list = td_list_next; - } - return stat; -} - -/*-------------------------------------------------------------------------* - * Virtual Root Hub - *-------------------------------------------------------------------------*/ - -/* Device descriptor */ -static __u8 root_hub_dev_des[] = -{ - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, /* __u16 bcdUSB; v1.1 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x01, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ - 0x00, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -static unsigned char root_hub_str_index0[] = -{ - 0x04, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 0x09, /* __u8 lang ID */ - 0x04, /* __u8 lang ID */ -}; - -static unsigned char root_hub_str_index1[] = -{ - 28, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 'O', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'C', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'I', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'R', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 't', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'u', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'b', /* __u8 Unicode */ - 0, /* __u8 Unicode */ -}; - -/* Hub class-specific descriptor is constructed dynamically */ - - -/*-------------------------------------------------------------------------*/ - -#define OK(x) len = (x); break -#ifdef DEBUG -#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);} -#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);} -#else -#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status) -#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1]) -#endif -#define RD_RH_STAT roothub_status(&gohci) -#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1) - -/* request to virtual root hub */ - -int rh_check_port_status(ohci_t *controller) -{ - __u32 temp, ndp, i; - int res; - - res = -1; - temp = roothub_a (controller); - ndp = (temp & RH_A_NDP); -#ifdef CONFIG_AT91C_PQFP_UHPBUG - ndp = (ndp == 2) ? 1:0; -#endif - - for (i = 0; i < ndp; i++) { - temp = roothub_portstatus (controller, i); - /* check for a device disconnect */ - if (((temp & (RH_PS_PESC | RH_PS_CSC)) == - (RH_PS_PESC | RH_PS_CSC)) && - ((temp & RH_PS_CCS) == 0)) { - res = i; - break; - } - } - return res; -} - -static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, struct devrequest *cmd) -{ - void * data = buffer; - int leni = transfer_len; - int len = 0; - int stat = 0; - __u32 datab[4]; - __u8 *data_buf = (__u8 *)datab; - __u16 bmRType_bReq; - __u16 wValue; - __u16 wIndex; - __u16 wLength; - -#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"); - return 0; - } - - bmRType_bReq = cmd->requesttype | (cmd->request << 8); - wValue = m16_swap (cmd->value); - wIndex = m16_swap (cmd->index); - wLength = m16_swap (cmd->length); - - info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x", - dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength); - - switch (bmRType_bReq) { - /* Request Destination: - without flags: Device, - RH_INTERFACE: interface, - RH_ENDPOINT: endpoint, - RH_CLASS means HUB here, - RH_OTHER | RH_CLASS almost ever means HUB_PORT here - */ - - case RH_GET_STATUS: - *(__u16 *) data_buf = m16_swap (1); OK (2); - case RH_GET_STATUS | RH_INTERFACE: - *(__u16 *) data_buf = m16_swap (0); OK (2); - case RH_GET_STATUS | RH_ENDPOINT: - *(__u16 *) data_buf = m16_swap (0); OK (2); - case RH_GET_STATUS | RH_CLASS: - *(__u32 *) data_buf = m32_swap ( - 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); - - case RH_CLEAR_FEATURE | RH_ENDPOINT: - switch (wValue) { - case (RH_ENDPOINT_STALL): OK (0); - } - break; - - case RH_CLEAR_FEATURE | RH_CLASS: - switch (wValue) { - case RH_C_HUB_LOCAL_POWER: - OK(0); - case (RH_C_HUB_OVER_CURRENT): - WR_RH_STAT(RH_HS_OCIC); OK (0); - } - break; - - case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_ENABLE): - WR_RH_PORTSTAT (RH_PS_CCS ); OK (0); - case (RH_PORT_SUSPEND): - WR_RH_PORTSTAT (RH_PS_POCI); OK (0); - case (RH_PORT_POWER): - WR_RH_PORTSTAT (RH_PS_LSDA); OK (0); - case (RH_C_PORT_CONNECTION): - WR_RH_PORTSTAT (RH_PS_CSC ); OK (0); - case (RH_C_PORT_ENABLE): - WR_RH_PORTSTAT (RH_PS_PESC); OK (0); - case (RH_C_PORT_SUSPEND): - WR_RH_PORTSTAT (RH_PS_PSSC); OK (0); - case (RH_C_PORT_OVER_CURRENT): - WR_RH_PORTSTAT (RH_PS_OCIC); OK (0); - case (RH_C_PORT_RESET): - WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); - } - break; - - case RH_SET_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_SUSPEND): - WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); - case (RH_PORT_RESET): /* BUG IN HUP CODE *********/ - if (RD_RH_PORTSTAT & RH_PS_CCS) - WR_RH_PORTSTAT (RH_PS_PRS); - OK (0); - case (RH_PORT_POWER): - WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); - case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/ - if (RD_RH_PORTSTAT & RH_PS_CCS) - WR_RH_PORTSTAT (RH_PS_PES ); - OK (0); - } - break; - - case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0); - - case RH_GET_DESCRIPTOR: - switch ((wValue & 0xff00) >> 8) { - case (0x01): /* device descriptor */ - len = min_t(unsigned int, - leni, - min_t(unsigned int, - sizeof (root_hub_dev_des), - wLength)); - data_buf = root_hub_dev_des; OK(len); - case (0x02): /* configuration descriptor */ - len = min_t(unsigned int, - leni, - min_t(unsigned int, - sizeof (root_hub_config_des), - wLength)); - data_buf = root_hub_config_des; OK(len); - case (0x03): /* string descriptors */ - if(wValue==0x0300) { - len = min_t(unsigned int, - leni, - min_t(unsigned int, - sizeof (root_hub_str_index0), - wLength)); - data_buf = root_hub_str_index0; - OK(len); - } - if(wValue==0x0301) { - len = min_t(unsigned int, - leni, - min_t(unsigned int, - sizeof (root_hub_str_index1), - wLength)); - data_buf = root_hub_str_index1; - OK(len); - } - default: - stat = USB_ST_STALLED; - } - break; - - case RH_GET_DESCRIPTOR | RH_CLASS: - { - __u32 temp = roothub_a (&gohci); - - data_buf [0] = 9; /* min length; */ - data_buf [1] = 0x29; - data_buf [2] = temp & RH_A_NDP; -#ifdef CONFIG_AT91C_PQFP_UHPBUG - data_buf [2] = (data_buf [2] == 2) ? 1:0; -#endif - 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? */ - data_buf [3] |= 0x10; - 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) { - data_buf [8] = 0xff; - } 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); - } - - case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1); - - case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0); - - default: - dbg ("unsupported root hub command"); - stat = USB_ST_STALLED; - } - -#ifdef DEBUG - ohci_dump_roothub (&gohci, 1); -#else - wait_ms(1); -#endif - - len = min_t(int, len, leni); - if (data != data_buf) - memcpy (data, data_buf, len); - dev->act_len = len; - dev->status = stat; - -#ifdef DEBUG - 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; -} - -/*-------------------------------------------------------------------------*/ - -/* common code for handling submit messages - used for all but root hub */ -/* accesses. */ -int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup, int interval) -{ - int stat = 0; - int maxsize = usb_maxpacket(dev, pipe); - int timeout; - - /* device pulled? Shortcut the action. */ - if (devgone == dev) { - dev->status = USB_ST_CRC_ERR; - return 0; - } - -#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", - pipe); - return -1; - } - - if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) { - err("sohci_submit_job failed"); - 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) - timeout = BULK_TO; - else - timeout = 100; - - /* wait for it to complete */ - for (;;) { - /* check whether the controller is done */ - stat = hc_interrupt(); - if (stat < 0) { - stat = USB_ST_CRC_ERR; - break; - } - if (stat >= 0 && stat != 0xff) { - /* 0xff is returned for an SF-interrupt */ - break; - } - if (--timeout) { - wait_ms(1); - } else { - err("CTL:TIMEOUT "); - stat = USB_ST_CRC_ERR; - break; - } - } - /* we got an Root Hub Status Change interrupt */ - if (got_rhsc) { -#ifdef DEBUG - ohci_dump_roothub (&gohci, 1); -#endif - got_rhsc = 0; - /* abuse timeout */ - timeout = rh_check_port_status(&gohci); - if (timeout >= 0) { -#if 0 /* this does nothing useful, but leave it here in case that changes */ - /* the called routine adds 1 to the passed value */ - usb_hub_port_connect_change(gohci.rh.dev, timeout - 1); -#endif - /* - * XXX - * This is potentially dangerous because it assumes - * that only one device is ever plugged in! - */ - devgone = dev; - } - } - - 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 */ - urb_free_priv (&urb_priv); - return 0; -} - -/* submit routines called from usb.c */ -int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len) -{ - info("submit_bulk_msg"); - return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0); -} - -int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup) -{ - int maxsize = usb_maxpacket(dev, pipe); - - info("submit_control_msg"); -#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", - pipe); - return -1; - } - if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) { - gohci.rh.dev = dev; - /* root hub - redirect */ - return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len, - setup); - } - - return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0); -} - -int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, int interval) -{ - info("submit_int_msg"); - return -1; -} - -/*-------------------------------------------------------------------------* - * HC functions - *-------------------------------------------------------------------------*/ - -/* reset the HC and BUS */ - -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"); - while (readl (&ohci->regs->control) & OHCI_CTRL_IR) { - wait_ms (10); - if (--smm_timeout == 0) { - err("USB HC TakeOver failed!"); - return -1; - } - } - } - - /* Disable HC interrupts */ - writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); - - 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); - - /* HC Reset requires max 10 us delay */ - writel (OHCI_HCR, &ohci->regs->cmdstatus); - while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { - if (--timeout == 0) { - err("USB HC reset timed out!"); - return -1; - } - udelay (1); - } - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* Start an OHCI controller, set the BUS operational - * enable interrupts - * connect the virtual root hub */ - -static int hc_start (ohci_t * ohci) -{ - __u32 mask; - unsigned int fminterval; - - ohci->disabled = 1; - - /* Tell the controller where the control and bulk lists are - * The lists are empty now. */ - - writel (0, &ohci->regs->ed_controlhead); - writel (0, &ohci->regs->ed_bulkhead); - - writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */ - - fminterval = 0x2edf; - writel ((fminterval * 9) / 10, &ohci->regs->periodicstart); - fminterval |= ((((fminterval - 210) * 6) / 7) << 16); - writel (fminterval, &ohci->regs->fminterval); - writel (0x628, &ohci->regs->lsthresh); - - /* start controller operations */ - ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; - ohci->disabled = 0; - writel (ohci->hc_control, &ohci->regs->control); - - /* disable all interrupts */ - mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD | - OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC | - OHCI_INTR_OC | OHCI_INTR_MIE); - writel (mask, &ohci->regs->intrdisable); - /* clear all interrupts */ - mask &= ~OHCI_INTR_MIE; - writel (mask, &ohci->regs->intrstatus); - /* Choose the interrupts we care about now - but w/o MIE */ - mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO; - writel (mask, &ohci->regs->intrenable); - -#ifdef OHCI_USE_NPS - /* required for AMD-756 and some Mac platforms */ - writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM, - &ohci->regs->roothub.a); - writel (RH_HS_LPSC, &ohci->regs->roothub.status); -#endif /* OHCI_USE_NPS */ - -#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); - - /* connect the virtual root hub */ - ohci->rh.devnum = 0; - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* an interrupt happens */ - -static int -hc_interrupt (void) -{ - ohci_t *ohci = &gohci; - struct ohci_regs *regs = ohci->regs; - int ints; - int stat = -1; - - if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) { - ints = OHCI_INTR_WDH; - } else { - ints = readl (®s->intrstatus); - } - - /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */ - - if (ints & OHCI_INTR_RHSC) { - got_rhsc = 1; - } - - if (ints & OHCI_INTR_UE) { - ohci->disabled++; - err ("OHCI Unrecoverable Error, controller usb-%s disabled", - ohci->slot_name); - /* e.g. due to PCI Master/Target Abort */ - -#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. */ - /* Count and limit the retries though; either hardware or */ - /* software errors can go forever... */ - hc_reset (ohci); - return -1; - } - - if (ints & OHCI_INTR_WDH) { - wait_ms(1); - writel (OHCI_INTR_WDH, ®s->intrdisable); - stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci)); - writel (OHCI_INTR_WDH, ®s->intrenable); - } - - if (ints & OHCI_INTR_SO) { - dbg("USB Schedule overrun\n"); - writel (OHCI_INTR_SO, ®s->intrenable); - stat = -1; - } - - /* 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; - wait_ms(1); - writel (OHCI_INTR_SF, ®s->intrdisable); - if (ohci->ed_rm_list[frame] != NULL) - writel (OHCI_INTR_SF, ®s->intrenable); - stat = 0xff; - } - - writel (ints, ®s->intrstatus); - return stat; -} - -/*-------------------------------------------------------------------------*/ - -/*-------------------------------------------------------------------------*/ - -/* De-allocate all resources.. */ - -static void hc_release_ohci (ohci_t *ohci) -{ - dbg ("USB HC release ohci usb-%s", ohci->slot_name); - - if (!ohci->disabled) - hc_reset (ohci); -} - -/*-------------------------------------------------------------------------*/ - -/* - * low level initalisation routine, called from usb.c - */ -static char ohci_inited = 0; - -int usb_lowlevel_init(void) -{ - /* - * Enable USB host clock. - */ - *AT91C_PMC_SCER = AT91C_PMC_UHP; /* 48MHz clock enabled for UHP */ - *AT91C_PMC_PCER = 1 << AT91C_ID_UHP; /* Peripheral Clock Enable Register */ - - memset (&gohci, 0, sizeof (ohci_t)); - memset (&urb_priv, 0, sizeof (urb_priv_t)); - - /* align the storage */ - if ((__u32)&ghcca[0] & 0xff) { - err("HCCA not aligned!!"); - return -1; - } - phcca = &ghcca[0]; - info("aligned ghcca %p", phcca); - memset(&ohci_dev, 0, sizeof(struct ohci_device)); - if ((__u32)&ohci_dev.ed[0] & 0x7) { - err("EDs not aligned!!"); - return -1; - } - memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1)); - if ((__u32)gtd & 0x7) { - err("TDs not aligned!!"); - return -1; - } - ptd = gtd; - gohci.hcca = phcca; - memset (phcca, 0, sizeof (struct ohci_hcca)); - - gohci.disabled = 1; - gohci.sleeping = 0; - gohci.irq = -1; - gohci.regs = (struct ohci_regs *)AT91_USB_HOST_BASE; - - gohci.flags = 0; - gohci.slot_name = "at91rm9200"; - - if (hc_reset (&gohci) < 0) { - hc_release_ohci (&gohci); - /* Initialization failed */ - *AT91C_PMC_PCER = AT91C_ID_UHP; - *AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */ - return -1; - } - - /* 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) { - err ("can't start usb-%s", gohci.slot_name); - hc_release_ohci (&gohci); - /* Initialization failed */ - *AT91C_PMC_PCER = AT91C_ID_UHP; - *AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */ - return -1; - } - -#ifdef DEBUG - ohci_dump (&gohci, 1); -#else - wait_ms(1); -#endif - ohci_inited = 1; - return 0; -} - -int usb_lowlevel_stop(void) -{ - /* this gets called really early - before the controller has */ - /* even been initialized! */ - if (!ohci_inited) - return 0; - /* TODO release any interrupts, etc. */ - /* call hc_release_ohci() here ? */ - hc_reset (&gohci); - /* may not want to do this */ - *AT91C_PMC_PCER = 1 << AT91C_ID_UHP; - *AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */ - return 0; -} - -#endif /* CONFIG_USB_OHCI */ diff --git a/cpu/arm920t/at91rm9200/usb_ohci.h b/cpu/arm920t/at91rm9200/usb_ohci.h deleted file mode 100644 index ecb4e93..0000000 --- a/cpu/arm920t/at91rm9200/usb_ohci.h +++ /dev/null @@ -1,419 +0,0 @@ -/* - * URB OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber - * (C) Copyright 2000-2001 David Brownell - * - * usb-ohci.h - */ - - -static int cc_to_error[16] = { - -/* mapping of the OHCI CC status to error codes */ - /* No Error */ 0, - /* CRC Error */ USB_ST_CRC_ERR, - /* Bit Stuff */ USB_ST_BIT_ERR, - /* Data Togg */ USB_ST_CRC_ERR, - /* Stall */ USB_ST_STALLED, - /* DevNotResp */ -1, - /* PIDCheck */ USB_ST_BIT_ERR, - /* UnExpPID */ USB_ST_BIT_ERR, - /* DataOver */ USB_ST_BUF_ERR, - /* DataUnder */ USB_ST_BUF_ERR, - /* reservd */ -1, - /* reservd */ -1, - /* BufferOver */ USB_ST_BUF_ERR, - /* BuffUnder */ USB_ST_BUF_ERR, - /* Not Access */ -1, - /* Not Access */ -1 -}; - -/* ED States */ - -#define ED_NEW 0x00 -#define ED_UNLINK 0x01 -#define ED_OPER 0x02 -#define ED_DEL 0x04 -#define ED_URB_DEL 0x08 - -/* usb_ohci_ed */ -struct ed { - __u32 hwINFO; - __u32 hwTailP; - __u32 hwHeadP; - __u32 hwNextED; - - struct ed *ed_prev; - __u8 int_period; - __u8 int_branch; - __u8 int_load; - __u8 int_interval; - __u8 state; - __u8 type; - __u16 last_iso; - struct ed *ed_rm_list; - - struct usb_device *usb_dev; - __u32 unused[3]; -} __attribute((aligned(16))); -typedef struct ed ed_t; - - -/* TD info field */ -#define TD_CC 0xf0000000 -#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) -#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) -#define TD_EC 0x0C000000 -#define TD_T 0x03000000 -#define TD_T_DATA0 0x02000000 -#define TD_T_DATA1 0x03000000 -#define TD_T_TOGGLE 0x00000000 -#define TD_R 0x00040000 -#define TD_DI 0x00E00000 -#define TD_DI_SET(X) (((X) & 0x07)<< 21) -#define TD_DP 0x00180000 -#define TD_DP_SETUP 0x00000000 -#define TD_DP_IN 0x00100000 -#define TD_DP_OUT 0x00080000 - -#define TD_ISO 0x00010000 -#define TD_DEL 0x00020000 - -/* CC Codes */ -#define TD_CC_NOERROR 0x00 -#define TD_CC_CRC 0x01 -#define TD_CC_BITSTUFFING 0x02 -#define TD_CC_DATATOGGLEM 0x03 -#define TD_CC_STALL 0x04 -#define TD_DEVNOTRESP 0x05 -#define TD_PIDCHECKFAIL 0x06 -#define TD_UNEXPECTEDPID 0x07 -#define TD_DATAOVERRUN 0x08 -#define TD_DATAUNDERRUN 0x09 -#define TD_BUFFEROVERRUN 0x0C -#define TD_BUFFERUNDERRUN 0x0D -#define TD_NOTACCESSED 0x0F - - -#define MAXPSW 1 - -struct td { - __u32 hwINFO; - __u32 hwCBP; /* Current Buffer Pointer */ - __u32 hwNextTD; /* Next TD Pointer */ - __u32 hwBE; /* Memory Buffer End Pointer */ - - __u16 hwPSW[MAXPSW]; - __u8 unused; - __u8 index; - struct ed *ed; - struct td *next_dl_td; - struct usb_device *usb_dev; - int transfer_len; - __u32 data; - - __u32 unused2[2]; -} __attribute((aligned(32))); -typedef struct td td_t; - -#define OHCI_ED_SKIP (1 << 14) - -/* - * The HCCA (Host Controller Communications Area) is a 256 byte - * structure defined in the OHCI spec. that the host controller is - * told the base address of. It must be 256-byte aligned. - */ - -#define NUM_INTS 32 /* part of the OHCI standard */ -struct ohci_hcca { - __u32 int_table[NUM_INTS]; /* Interrupt ED table */ - __u16 frame_no; /* current frame number */ - __u16 pad1; /* set to 0 on each frame_no change */ - __u32 done_head; /* info returned for an interrupt */ - u8 reserved_for_hc[116]; -} __attribute((aligned(256))); - - -/* - * Maximum number of root hub ports. - */ -#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */ - -/* - * This is the structure of the OHCI controller's memory mapped I/O - * region. This is Memory Mapped I/O. You must use the readl() and - * writel() macros defined in asm/io.h to access these!! - */ -struct ohci_regs { - /* control and status registers */ - __u32 revision; - __u32 control; - __u32 cmdstatus; - __u32 intrstatus; - __u32 intrenable; - __u32 intrdisable; - /* memory pointers */ - __u32 hcca; - __u32 ed_periodcurrent; - __u32 ed_controlhead; - __u32 ed_controlcurrent; - __u32 ed_bulkhead; - __u32 ed_bulkcurrent; - __u32 donehead; - /* frame counters */ - __u32 fminterval; - __u32 fmremaining; - __u32 fmnumber; - __u32 periodicstart; - __u32 lsthresh; - /* Root hub ports */ - struct ohci_roothub_regs { - __u32 a; - __u32 b; - __u32 status; - __u32 portstatus[MAX_ROOT_PORTS]; - } roothub; -} __attribute((aligned(32))); - - -/* OHCI CONTROL AND STATUS REGISTER MASKS */ - -/* - * HcControl (control) register masks - */ -#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */ -#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */ -#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */ -#define OHCI_CTRL_CLE (1 << 4) /* control list enable */ -#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */ -#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */ -#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ -#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ -#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ - -/* pre-shifted values for HCFS */ -# define OHCI_USB_RESET (0 << 6) -# define OHCI_USB_RESUME (1 << 6) -# define OHCI_USB_OPER (2 << 6) -# define OHCI_USB_SUSPEND (3 << 6) - -/* - * HcCommandStatus (cmdstatus) register masks - */ -#define OHCI_HCR (1 << 0) /* host controller reset */ -#define OHCI_CLF (1 << 1) /* control list filled */ -#define OHCI_BLF (1 << 2) /* bulk list filled */ -#define OHCI_OCR (1 << 3) /* ownership change request */ -#define OHCI_SOC (3 << 16) /* scheduling overrun count */ - -/* - * masks used with interrupt registers: - * HcInterruptStatus (intrstatus) - * HcInterruptEnable (intrenable) - * HcInterruptDisable (intrdisable) - */ -#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ -#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */ -#define OHCI_INTR_SF (1 << 2) /* start frame */ -#define OHCI_INTR_RD (1 << 3) /* resume detect */ -#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ -#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ -#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ -#define OHCI_INTR_OC (1 << 30) /* ownership change */ -#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ - - -/* Virtual Root HUB */ -struct virt_root_hub { - int devnum; /* Address of Root Hub endpoint */ - void *dev; /* was urb */ - void *int_addr; - int send; - int interval; -}; - -/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ - -/* destination of request */ -#define RH_INTERFACE 0x01 -#define RH_ENDPOINT 0x02 -#define RH_OTHER 0x03 - -#define RH_CLASS 0x20 -#define RH_VENDOR 0x40 - -/* Requests: bRequest << 8 | bmRequestType */ -#define RH_GET_STATUS 0x0080 -#define RH_CLEAR_FEATURE 0x0100 -#define RH_SET_FEATURE 0x0300 -#define RH_SET_ADDRESS 0x0500 -#define RH_GET_DESCRIPTOR 0x0680 -#define RH_SET_DESCRIPTOR 0x0700 -#define RH_GET_CONFIGURATION 0x0880 -#define RH_SET_CONFIGURATION 0x0900 -#define RH_GET_STATE 0x0280 -#define RH_GET_INTERFACE 0x0A80 -#define RH_SET_INTERFACE 0x0B00 -#define RH_SYNC_FRAME 0x0C80 -/* Our Vendor Specific Request */ -#define RH_SET_EP 0x2000 - - -/* Hub port features */ -#define RH_PORT_CONNECTION 0x00 -#define RH_PORT_ENABLE 0x01 -#define RH_PORT_SUSPEND 0x02 -#define RH_PORT_OVER_CURRENT 0x03 -#define RH_PORT_RESET 0x04 -#define RH_PORT_POWER 0x08 -#define RH_PORT_LOW_SPEED 0x09 - -#define RH_C_PORT_CONNECTION 0x10 -#define RH_C_PORT_ENABLE 0x11 -#define RH_C_PORT_SUSPEND 0x12 -#define RH_C_PORT_OVER_CURRENT 0x13 -#define RH_C_PORT_RESET 0x14 - -/* Hub features */ -#define RH_C_HUB_LOCAL_POWER 0x00 -#define RH_C_HUB_OVER_CURRENT 0x01 - -#define RH_DEVICE_REMOTE_WAKEUP 0x00 -#define RH_ENDPOINT_STALL 0x01 - -#define RH_ACK 0x01 -#define RH_REQ_ERR -1 -#define RH_NACK 0x00 - - -/* OHCI ROOT HUB REGISTER MASKS */ - -/* roothub.portstatus [i] bits */ -#define RH_PS_CCS 0x00000001 /* current connect status */ -#define RH_PS_PES 0x00000002 /* port enable status*/ -#define RH_PS_PSS 0x00000004 /* port suspend status */ -#define RH_PS_POCI 0x00000008 /* port over current indicator */ -#define RH_PS_PRS 0x00000010 /* port reset status */ -#define RH_PS_PPS 0x00000100 /* port power status */ -#define RH_PS_LSDA 0x00000200 /* low speed device attached */ -#define RH_PS_CSC 0x00010000 /* connect status change */ -#define RH_PS_PESC 0x00020000 /* port enable status change */ -#define RH_PS_PSSC 0x00040000 /* port suspend status change */ -#define RH_PS_OCIC 0x00080000 /* over current indicator change */ -#define RH_PS_PRSC 0x00100000 /* port reset status change */ - -/* roothub.status bits */ -#define RH_HS_LPS 0x00000001 /* local power status */ -#define RH_HS_OCI 0x00000002 /* over current indicator */ -#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */ -#define RH_HS_LPSC 0x00010000 /* local power status change */ -#define RH_HS_OCIC 0x00020000 /* over current indicator change */ -#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */ - -/* roothub.b masks */ -#define RH_B_DR 0x0000ffff /* device removable flags */ -#define RH_B_PPCM 0xffff0000 /* port power control mask */ - -/* roothub.a masks */ -#define RH_A_NDP (0xff << 0) /* number of downstream ports */ -#define RH_A_PSM (1 << 8) /* power switching mode */ -#define RH_A_NPS (1 << 9) /* no power switching */ -#define RH_A_DT (1 << 10) /* device type (mbz) */ -#define RH_A_OCPM (1 << 11) /* over current protection mode */ -#define RH_A_NOCP (1 << 12) /* no over current protection */ -#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ - -/* urb */ -#define N_URB_TD 48 -typedef struct -{ - ed_t *ed; - __u16 length; /* number of tds associated with this request */ - __u16 td_cnt; /* number of tds already serviced */ - int state; - unsigned long pipe; - int actual_length; - td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */ -} urb_priv_t; -#define URB_DEL 1 - -/* - * This is the full ohci controller description - * - * Note how the "proper" USB information is just - * a subset of what the full implementation needs. (Linus) - */ - - -typedef struct ohci { - struct ohci_hcca *hcca; /* hcca */ - /*dma_addr_t hcca_dma;*/ - - int irq; - int disabled; /* e.g. got a UE, we're hung */ - int sleeping; - unsigned long flags; /* for HC bugs */ - - struct ohci_regs *regs; /* OHCI controller's memory */ - - ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */ - ed_t *ed_bulktail; /* last endpoint of bulk list */ - ed_t *ed_controltail; /* last endpoint of control list */ - int intrstatus; - __u32 hc_control; /* copy of the hc control reg */ - struct usb_device *dev[32]; - struct virt_root_hub rh; - - const char *slot_name; -} ohci_t; - -#define NUM_EDS 8 /* num of preallocated endpoint descriptors */ - -struct ohci_device { - ed_t ed[NUM_EDS]; - int ed_cnt; -}; - -/* hcd */ -/* endpoint */ -static int ep_link(ohci_t * ohci, ed_t * ed); -static int ep_unlink(ohci_t * ohci, ed_t * ed); -static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe); - -/*-------------------------------------------------------------------------*/ - -/* we need more TDs than EDs */ -#define NUM_TD 64 - -/* +1 so we can align the storage */ -td_t gtd[NUM_TD+1]; -/* pointers to aligned storage */ -td_t *ptd; - -/* TDs ... */ -static inline struct td * -td_alloc (struct usb_device *usb_dev) -{ - int i; - struct td *td; - - td = NULL; - for (i = 0; i < NUM_TD; i++) - { - if (ptd[i].usb_dev == NULL) - { - td = &ptd[i]; - td->usb_dev = usb_dev; - break; - } - } - - return td; -} - -static inline void -ed_free (struct ed *ed) -{ - ed->usb_dev = NULL; -} diff --git a/cpu/pxa/usb.c b/cpu/pxa/usb.c index e89391c..1716157 100644 --- a/cpu/pxa/usb.c +++ b/cpu/pxa/usb.c @@ -22,10 +22,12 @@ */ #include -#include -#ifdef CFG_USB_CPU_INIT +#if defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) # ifdef CONFIG_CPU_MONAHANS + +#include + int usb_cpu_init() { /* Enable USB host clock. */ @@ -68,4 +70,4 @@ int usb_cpu_stop() return 0; } # endif /* CONFIG_CPU_MONAHANS */ -#endif /* CFG_USB_CPU_INIT */ +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index f5af719..c32245a 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -1552,13 +1552,13 @@ static char ohci_inited = 0; int usb_lowlevel_init(void) { -#if CFG_USB_CPU_INIT +#if CFG_USB_OHCI_CPU_INIT /* cpu dependant init */ if(usb_cpu_init()) return -1; #endif -#if CFG_USB_BOARD_INIT +#if CFG_USB_OHCI_BOARD_INIT /* board dependant init */ if(usb_board_init()) return -1; @@ -1593,18 +1593,18 @@ int usb_lowlevel_init(void) gohci.regs = (struct ohci_regs *)CFG_USB_OHCI_REGS_BASE; gohci.flags = 0; - gohci.slot_name = CFG_USB_SLOT_NAME; + gohci.slot_name = CFG_USB_OHCI_SLOT_NAME; if (hc_reset (&gohci) < 0) { hc_release_ohci (&gohci); err ("can't reset usb-%s", gohci.slot_name); /* Initialization failed disable clocks */ -#if CFG_USB_BOARD_INIT +#if CFG_USB_OHCI_BOARD_INIT /* board dependant cleanup */ usb_board_stop(); #endif -#if CFG_USB_CPU_INIT +#if CFG_USB_OHCI_CPU_INIT /* cpu dependant cleanup */ usb_cpu_stop(); #endif @@ -1618,12 +1618,12 @@ int usb_lowlevel_init(void) err ("can't start usb-%s", gohci.slot_name); hc_release_ohci (&gohci); /* Initialization failed */ -#if CFG_USB_BOARD_INIT +#if CFG_USB_OHCI_BOARD_INIT /* board dependant cleanup */ usb_board_stop(); #endif -#if CFG_USB_CPU_INIT +#if CFG_USB_OHCI_CPU_INIT /* cpu dependant cleanup */ usb_cpu_stop(); #endif @@ -1649,13 +1649,13 @@ int usb_lowlevel_stop(void) /* call hc_release_ohci() here ? */ hc_reset (&gohci); -#if CFG_USB_BOARD_INIT +#if CFG_USB_OHCI_BOARD_INIT /* board dependant cleanup */ if(usb_board_stop()) return -1; #endif -#if CFG_USB_CPU_INIT +#if CFG_USB_OHCI_CPU_INIT /* cpu dependant cleanup */ if(usb_cpu_stop()) return -1; diff --git a/include/configs/delta.h b/include/configs/delta.h index e6b05e0..fea821a 100644 --- a/include/configs/delta.h +++ b/include/configs/delta.h @@ -107,10 +107,10 @@ #define CONFIG_USB_STORAGE 1 #define CONFIG_DOS_PARTITION 1 -#undef CFG_USB_BOARD_INIT -#define CFG_USB_CPU_INIT 1 +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT 1 #define CFG_USB_OHCI_REGS_BASE OHCI_REGS_BASE -#define CFG_USB_SLOT_NAME "delta" +#define CFG_USB_OHCI_SLOT_NAME "delta" #define LITTLEENDIAN 1 /* used by usb_ohci.c */ diff --git a/include/configs/mp2usb.h b/include/configs/mp2usb.h index 04f1f24..edb20f8 100644 --- a/include/configs/mp2usb.h +++ b/include/configs/mp2usb.h @@ -107,6 +107,11 @@ #define CONFIG_DOS_PARTITION 1 #define CONFIG_AT91C_PQFP_UHPBUG 1 +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT 1 +#define CFG_USB_OHCI_REGS_BASE AT91_USB_HOST_BASE +#define CFG_USB_OHCI_SLOT_NAME "at91rm9200" + #undef CONFIG_HARD_I2C #ifdef CONFIG_HARD_I2C @@ -127,7 +132,7 @@ #define CONFIG_COMMANDS \ ((CONFIG_CMD_DFL | \ CFG_CMD_DATE | \ - CFG_CMD_DHCP | \ + CFG_CMD_DHCP | \ CFG_CMD_EEPROM | \ CFG_CMD_I2C | \ CFG_CMD_NFS | \ @@ -136,7 +141,7 @@ #else #define CONFIG_COMMANDS \ ((CONFIG_CMD_DFL | \ - CFG_CMD_DHCP | \ + CFG_CMD_DHCP | \ CFG_CMD_NFS | \ CFG_CMD_SNTP | \ CFG_CMD_USB | \ @@ -156,7 +161,7 @@ #define CONFIG_NR_DRAM_BANKS 1 #define PHYS_SDRAM 0x20000000 -#define PHYS_SDRAM_SIZE 0x08000000 /* 128 megs */ +#define PHYS_SDRAM_SIZE 0x08000000 /* 128 megs */ #define CFG_MEMTEST_START PHYS_SDRAM #define CFG_MEMTEST_END CFG_MEMTEST_START + PHYS_SDRAM_SIZE - 262144 -- cgit v1.1 From ddf83a2fcef1a670c45fc585119dcc1fe062c4a9 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Tue, 30 May 2006 16:56:14 +0200 Subject: Support generic OHCI support for the s3c24x0 cpu. --- cpu/arm920t/at91rm9200/usb.c | 6 ++ cpu/arm920t/s3c24x0/Makefile | 2 +- cpu/arm920t/s3c24x0/usb.c | 72 +++++++++++++++++++++++ cpu/pxa/usb.c | 5 ++ drivers/usb_ohci.c | 133 +++++++++++++++++++++++++++++++++++-------- drivers/usb_ohci.h | 2 + include/configs/trab.h | 5 ++ 7 files changed, 199 insertions(+), 26 deletions(-) create mode 100644 cpu/arm920t/s3c24x0/usb.c diff --git a/cpu/arm920t/at91rm9200/usb.c b/cpu/arm920t/at91rm9200/usb.c index 7b83f23..98e3cdd 100644 --- a/cpu/arm920t/at91rm9200/usb.c +++ b/cpu/arm920t/at91rm9200/usb.c @@ -43,5 +43,11 @@ int usb_cpu_stop() *AT91C_PMC_SCDR = AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */ return 0; } + +int usb_cpu_init_fail() +{ + usb_cpu_stop(); +} + # endif /* CONFIG_AT91RM9200 */ #endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/cpu/arm920t/s3c24x0/Makefile b/cpu/arm920t/s3c24x0/Makefile index af9e4ef..f81f84d 100644 --- a/cpu/arm920t/s3c24x0/Makefile +++ b/cpu/arm920t/s3c24x0/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = lib$(SOC).a OBJS = i2c.o interrupts.o serial.o speed.o \ - usb_ohci.o + usb.o all: .depend $(LIB) diff --git a/cpu/arm920t/s3c24x0/usb.c b/cpu/arm920t/s3c24x0/usb.c new file mode 100644 index 0000000..8114034 --- /dev/null +++ b/cpu/arm920t/s3c24x0/usb.c @@ -0,0 +1,72 @@ +/* + * (C) Copyright 2006 + * DENX Software Engineering + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +#if defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) +# if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) + +#if defined(CONFIG_S3C2400) +# include +#elif defined(CONFIG_S3C2410) +# include +#endif + +int usb_cpu_init() +{ + + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* + * Set the 48 MHz UPLL clocking. Values are taken from + * "PLL value selection guide", 6-23, s3c2400_UM.pdf. + */ + clk_power->UPLLCON = ((40 << 12) + (1 << 4) + 2); + gpio->MISCCR |= 0x8; /* 1 = use pads related USB for USB host */ + + /* + * Enable USB host clock. + */ + clk_power->CLKCON |= (1 << 4); + + return 0; +} + +int usb_cpu_stop() +{ + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + /* may not want to do this */ + clk_power->CLKCON &= ~(1 << 4); + return 0; +} + +int usb_cpu_init_fail() +{ + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + clk_power->CLKCON &= ~(1 << 4); + return 0; +} + +# endif /* defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) */ +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/cpu/pxa/usb.c b/cpu/pxa/usb.c index 1716157..bff5bfb 100644 --- a/cpu/pxa/usb.c +++ b/cpu/pxa/usb.c @@ -66,8 +66,13 @@ int usb_cpu_stop() { /* may not want to do this */ /* CKENA &= ~(CKENA_2_USBHOST | CKENA_20_UDC); */ + return 0; +} +int usb_cpu_init_fail() +{ return 0; } + # endif /* CONFIG_CPU_MONAHANS */ #endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index c32245a..9b3ca12 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -21,7 +21,7 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License @@ -45,13 +45,25 @@ #ifdef CONFIG_USB_OHCI -#include +#if defined(CONFIG_S3C2400) +# include +#elif defined(CONFIG_S3C2410) +# include +#elif defined(CONFIG_ARM920T) +# include +#elif defined(CONFIG_CPU_MONAHANS) +# include +#endif #include #include #include "usb_ohci.h" -#ifdef CONFIG_ARM920T +#undef S3C24X0_merge + +#if defined(CONFIG_ARM920T) || \ + defined(CONFIG_S3C2400) || \ + defined(CONFIG_S3C2410) # define OHCI_USE_NPS /* force NoPowerSwitching mode */ #endif @@ -98,6 +110,12 @@ int got_rhsc; /* device which was disconnected */ struct usb_device *devgone; +#ifdef S3C24X0_merge +/* flag guarding URB transation */ +int urb_finished = 0; +#endif + + /*-------------------------------------------------------------------------*/ /* AMD-756 (D2 rev) reports corrupt register contents in some cases. @@ -402,6 +420,17 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, err("sohci_submit_job: EPIPE"); return -1; } +#ifdef S3C24X0_merge + /* 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; +#endif /* every endpoint has a ed, locate and fill it */ if (!(ed = ep_add_ed (dev, pipe))) { @@ -574,12 +603,14 @@ static int ep_unlink (ohci_t *ohci, ed_t *ed) /*-------------------------------------------------------------------------*/ -/* add/reinit an endpoint; this should be done once at the usb_set_configuration command, - * but the USB stack is a little bit stateless so we do it at every transaction - * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK - * in all other cases the state is left unchanged - * the ed info fields are setted anyway even though most of them should not change */ - +/* add/reinit an endpoint; this should be done once at the + * usb_set_configuration command, but the USB stack is a little bit + * stateless so we do it at every transaction if the state of the ed + * is ED_NEW then a dummy td is added and the state is changed to + * ED_UNLINK in all other cases the state is left unchanged the ed + * info fields are setted anyway even though most of them should not + * change + */ static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe) { td_t *td; @@ -663,7 +694,9 @@ static void td_fill (ohci_t *ohci, unsigned int info, else td->hwBE = 0; td->hwNextTD = m32_swap (td_pt); +#ifndef S3C24X0_merge td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000); +#endif /* append to queue */ td->ed->hwTailP = td->hwNextTD; @@ -830,7 +863,18 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list) dbg("ConditionCode %#x", cc); stat = cc_to_error[cc]; } - +#ifdef S3C24X0_merge + /* see if this done list makes for all TD's of current URB, + * and mark the URB finished if so */ + if (++(lurb_priv->td_cnt) == lurb_priv->length) { + if ((ed->state & (ED_OPER | ED_UNLINK))) + urb_finished = 1; + else + dbg("dl_done_list: strange.., ED state %x, ed->state\n"); + } else + dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt, + lurb_priv->length); +#endif if (ed->state != ED_NEW) { edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0; edTailP = m32_swap (ed->hwTailP); @@ -1172,7 +1216,7 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); } len = min_t(unsigned int, leni, - min_t(unsigned int, data_buf [0], wLength)); + min_t(unsigned int, data_buf [0], wLength)); OK (len); } @@ -1260,18 +1304,38 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, stat = USB_ST_CRC_ERR; break; } + +#ifdef S3C24X0_merge + /* 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)) { +#else if (stat >= 0 && stat != 0xff) { +#endif /* 0xff is returned for an SF-interrupt */ break; } + if (--timeout) { wait_ms(1); } else { err("CTL:TIMEOUT "); +#ifdef S3C24X0_merge + dbg("submit_common_msg: TO status %x\n", stat); + urb_finished = 1; +#endif stat = USB_ST_CRC_ERR; break; } } +#ifndef S3C24X0_merge /* we got an Root Hub Status Change interrupt */ if (got_rhsc) { #ifdef DEBUG @@ -1293,6 +1357,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, devgone = dev; } } +#endif /* S3C24X0_merge */ dev->status = stat; dev->act_len = transfer_len; @@ -1462,24 +1527,40 @@ static int hc_start (ohci_t * ohci) /* an interrupt happens */ -static int -hc_interrupt (void) +static int hc_interrupt (void) { ohci_t *ohci = &gohci; struct ohci_regs *regs = ohci->regs; int ints; int stat = -1; +#ifdef S3C24X0_merge + + if ((ohci->hcca->done_head != 0) && + !(m32_swap (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; + } else if ((ints &= readl (®s->intrenable)) == 0) { + dbg("hc_interrupt: returning..\n"); + return 0xff; + } +#else if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) { ints = OHCI_INTR_WDH; } else { ints = readl (®s->intrstatus); } - +#endif /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */ if (ints & OHCI_INTR_RHSC) { got_rhsc = 1; +#ifdef S3C24X0_merge + stat = 0xff; +#endif } if (ints & OHCI_INTR_UE) { @@ -1552,13 +1633,13 @@ static char ohci_inited = 0; int usb_lowlevel_init(void) { -#if CFG_USB_OHCI_CPU_INIT +#ifdef CFG_USB_OHCI_CPU_INIT /* cpu dependant init */ if(usb_cpu_init()) return -1; #endif -#if CFG_USB_OHCI_BOARD_INIT +#ifdef CFG_USB_OHCI_BOARD_INIT /* board dependant init */ if(usb_board_init()) return -1; @@ -1598,15 +1679,14 @@ int usb_lowlevel_init(void) if (hc_reset (&gohci) < 0) { hc_release_ohci (&gohci); err ("can't reset usb-%s", gohci.slot_name); - /* Initialization failed disable clocks */ -#if CFG_USB_OHCI_BOARD_INIT +#ifdef CFG_USB_OHCI_BOARD_INIT /* board dependant cleanup */ - usb_board_stop(); + usb_board_init_fail(); #endif -#if CFG_USB_OHCI_CPU_INIT +#ifdef CFG_USB_OHCI_CPU_INIT /* cpu dependant cleanup */ - usb_cpu_stop(); + usb_cpu_init_fail(); #endif return -1; } @@ -1618,12 +1698,12 @@ int usb_lowlevel_init(void) err ("can't start usb-%s", gohci.slot_name); hc_release_ohci (&gohci); /* Initialization failed */ -#if CFG_USB_OHCI_BOARD_INIT +#ifdef CFG_USB_OHCI_BOARD_INIT /* board dependant cleanup */ usb_board_stop(); #endif -#if CFG_USB_OHCI_CPU_INIT +#ifdef CFG_USB_OHCI_CPU_INIT /* cpu dependant cleanup */ usb_cpu_stop(); #endif @@ -1634,6 +1714,9 @@ int usb_lowlevel_init(void) ohci_dump (&gohci, 1); #else wait_ms(1); +# ifdef S3C24X0_merge + urb_finished = 1; +# endif #endif ohci_inited = 1; return 0; @@ -1649,13 +1732,13 @@ int usb_lowlevel_stop(void) /* call hc_release_ohci() here ? */ hc_reset (&gohci); -#if CFG_USB_OHCI_BOARD_INIT +#ifdef CFG_USB_OHCI_BOARD_INIT /* board dependant cleanup */ if(usb_board_stop()) return -1; #endif -#if CFG_USB_OHCI_CPU_INIT +#ifdef CFG_USB_OHCI_CPU_INIT /* cpu dependant cleanup */ if(usb_cpu_stop()) return -1; diff --git a/drivers/usb_ohci.h b/drivers/usb_ohci.h index c37b5f6..a1b36ed 100644 --- a/drivers/usb_ohci.h +++ b/drivers/usb_ohci.h @@ -11,11 +11,13 @@ #ifdef CFG_USB_BOARD_INIT extern int usb_board_init(void); extern int usb_board_stop(void); +extern int usb_cpu_init_fail(void); #endif #ifdef CFG_USB_CPU_INIT extern int usb_cpu_init(void); extern int usb_cpu_stop(void); +extern int usb_cpu_init_fail(void); #endif diff --git a/include/configs/trab.h b/include/configs/trab.h index 85ee756..b6d4bcf 100644 --- a/include/configs/trab.h +++ b/include/configs/trab.h @@ -84,6 +84,11 @@ #define CONFIG_USB_STORAGE 1 #define CONFIG_DOS_PARTITION 1 +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT 1 +#define CFG_USB_OHCI_REGS_BASE S3C24X0_USB_HOST_BASE +#define CFG_USB_OHCI_SLOT_NAME "s3c2400" + /* * Size of malloc() pool */ -- cgit v1.1 From 16c8d5e76ae0f78f39a60608574adfe0feb9cc70 Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Wed, 14 Jun 2006 17:45:53 +0200 Subject: Various USB related patches - Add support for mpc8xx USB device. - Add support for Common Device Class - Abstract Control Model USB console. - Add support for flow control in USB slave devices. - Add support for switching between gserial and cdc_acm using environment. - Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h - Update usbcore slightly to ease host enumeration. - Fix non-portable endian problems in usbdcore and usbdcore_ep0. - Add AdderUSB_config as a defconfig to enable usage of the USB console by default with the Adder87x U-Boot port. Patches by Bryan O'Donoghue , 29 May 2006 --- CHANGELOG | 12 + Makefile | 5 +- README | 64 +- drivers/Makefile | 2 +- drivers/usbdcore_ep0.c | 163 ++--- drivers/usbdcore_mpc8xx.c | 1412 +++++++++++++++++++++++++++++++++++++++++++ drivers/usbdcore_omap1510.c | 29 +- drivers/usbtty.c | 707 ++++++++++++++++------ drivers/usbtty.h | 60 +- include/configs/AdderUSB.h | 51 ++ include/usb_cdc_acm.h | 43 ++ include/usbdcore.h | 3 + include/usbdcore_mpc8xx.h | 210 +++++++ include/usbdcore_omap1510.h | 18 +- include/usbdescriptors.h | 38 +- 15 files changed, 2467 insertions(+), 350 deletions(-) create mode 100644 drivers/usbdcore_mpc8xx.c create mode 100644 include/configs/AdderUSB.h create mode 100644 include/usb_cdc_acm.h create mode 100644 include/usbdcore_mpc8xx.h diff --git a/CHANGELOG b/CHANGELOG index 4aab6fc..63d327a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,18 @@ Changes since U-Boot 1.1.4: ====================================================================== +* Various USB related patches + - Add support for mpc8xx USB device. + - Add support for Common Device Class - Abstract Control Model USB console. + - Add support for flow control in USB slave devices. + - Add support for switching between gserial and cdc_acm using environment. + - Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h + - Update usbcore slightly to ease host enumeration. + - Fix non-portable endian problems in usbdcore and usbdcore_ep0. + - Add AdderUSB_config as a defconfig to enable usage of the USB console + by default with the Adder87x U-Boot port. + Patch by Bryan O'Donoghue , 29 May 2006 + * Fix PCI to memory window size problems on PM82x boards We use the "automatic" mode that was used for the MPC8266ADS and MPC8272 boards. Eventually this should be used on all boards?] diff --git a/Makefile b/Makefile index 41a3624..45e850c 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ ifeq ($(HOSTARCH),ppc) CROSS_COMPILE = else ifeq ($(ARCH),ppc) -CROSS_COMPILE = powerpc-linux- +CROSS_COMPILE = ppc_8xx- endif ifeq ($(ARCH),arm) CROSS_COMPILE = arm-linux- @@ -437,6 +437,9 @@ AdderII_config \ @echo "#define CONFIG_MPC852T" > include/config.h) @./mkconfig -a Adder ppc mpc8xx adder +AdderUSB_config: unconfig + @./mkconfig -a AdderUSB ppc mpc8xx adder + ADS860_config \ FADS823_config \ FADS850SAR_config \ diff --git a/README b/README index 3ffef62..25e8971 100644 --- a/README +++ b/README @@ -862,7 +862,69 @@ The following options need to be configured: for differential drivers: 0x00001000 for single ended drivers: 0x00005000 - +- USB Device: + Define the below if you wish to use the USB console. + Once firmware is rebuilt from a serial console issue the + command "setenv stdin usbtty; setenv stdout usbtty" and + attach your usb cable. The Unix command "dmesg" should print + it has found a new device. The environment variable usbtty + can be set to gserial or cdc_acm to enable your device to + appear to a USB host as a Linux gserial device or a + Common Device Class Abstract Control Model serial device. + If you select usbtty = gserial you should be able to enumerate + a Linux host by + # modprobe usbserial vendor=0xVendorID product=0xProductID + else if using cdc_acm, simply setting the environment + variable usbtty to be cdc_acm should suffice. The following + might be defined in YourBoardName.h + + CONFIG_USB_DEVICE + Define this to build a UDC device + + CONFIG_USB_TTY + Define this to have a tty type of device available to + talk to the UDC device + + CFG_CONSOLE_IS_IN_ENV + Define this if you want stdin, stdout &/or stderr to + be set to usbtty. + + mpc8xx: + CFG_USB_EXTC_CLK 0xBLAH + Derive USB clock from external clock "blah" + - CFG_USB_EXTC_CLK 0x02 + + CFG_USB_BRG_CLK 0xBLAH + Derive USB clock from brgclk + - CFG_USB_BRG_CLK 0x04 + + If you have a USB-IF assigned VendorID then you may wish to + define your own vendor specific values either in BoardName.h + or directly in usbd_vendor_info.h. If you don't define + CONFIG_USBD_MANUFACTURER, CONFIG_USBD_PRODUCT_NAME, + CONFIG_USBD_VENDORID and CONFIG_USBD_PRODUCTID, then U-Boot + should pretend to be a Linux device to it's target host. + + CONFIG_USBD_MANUFACTURER + Define this string as the name of your company for + - CONFIG_USBD_MANUFACTURER "my company" + + CONFIG_USBD_PRODUCT_NAME + Define this string as the name of your product + - CONFIG_USBD_PRODUCT_NAME "acme usb device" + + CONFIG_USBD_VENDORID + Define this as your assigned Vendor ID from the USB + Implementors Forum. This *must* be a genuine Vendor ID + to avoid polluting the USB namespace. + - CONFIG_USBD_VENDORID 0xFFFF + + CONFIG_USBD_PRODUCTID + Define this as the unique Product ID + for your device + - CONFIG_USBD_PRODUCTID 0xFFFF + + - MMC Support: The MMC controller on the Intel PXA is supported. To enable this define CONFIG_MMC. The MMC can be diff --git a/drivers/Makefile b/drivers/Makefile index d5b6811..8732e16 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -48,7 +48,7 @@ OBJS = 3c589.o 5701rls.o ali512x.o \ ti_pci1410a.o tigon3.o tsec.o \ usb_ohci.o usbdcore.o usbdcore_ep0.o usbdcore_omap1510.o usbtty.o \ videomodes.o w83c553f.o \ - ks8695eth.o + ks8695eth.o usbdcore_mpc8xx.o all: $(LIB) diff --git a/drivers/usbdcore_ep0.c b/drivers/usbdcore_ep0.c index 260befe..5e7443b 100644 --- a/drivers/usbdcore_ep0.c +++ b/drivers/usbdcore_ep0.c @@ -2,6 +2,9 @@ * (C) Copyright 2003 * Gerry Hamel, geh@ti.com, Texas Instruments * + * (C) Copyright 2006 + * Bryan O'Donoghue, deckard@CodeHermit.ie + * * Based on * linux/drivers/usbd/ep0.c * @@ -39,11 +42,17 @@ * function driver. This may need to change. * * XXX + * + * As alluded to above, a simple callback cdc_recv_setup has been implemented + * in the usb_device data structure to facilicate passing + * Common Device Class packets to a function driver. + * + * XXX */ #include -#if defined(CONFIG_OMAP1510) && defined(CONFIG_USB_DEVICE) +#if defined(CONFIG_USB_DEVICE) #include "usbdcore.h" #if 0 @@ -69,7 +78,7 @@ static int ep0_get_status (struct usb_device_instance *device, char *cp; urb->actual_length = 2; - cp = urb->buffer; + cp = (char*)urb->buffer; cp[0] = cp[1] = 0; switch (requesttype) { @@ -115,7 +124,7 @@ static int ep0_get_one (struct usb_device_instance *device, struct urb *urb, * * Copy configuration data to urb transfer buffer if there is room for it. */ -static void copy_config (struct urb *urb, void *data, int max_length, +void copy_config (struct urb *urb, void *data, int max_length, int max_buf) { int available; @@ -128,10 +137,7 @@ static void copy_config (struct urb *urb, void *data, int max_length, dbg_ep0 (1, "data is NULL"); return; } - if (!(length = *(unsigned char *) data)) { - dbg_ep0 (1, "length is zero"); - return; - } + length = max_length; if (length > max_length) { dbg_ep0 (1, "length: %d >= max_length: %d", length, @@ -192,7 +198,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device, /* setup tx urb */ urb->actual_length = 0; - cp = urb->buffer; + cp = (char*)urb->buffer; dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type)); @@ -200,7 +206,6 @@ static int ep0_get_descriptor (struct usb_device_instance *device, case USB_DESCRIPTOR_TYPE_DEVICE: { struct usb_device_descriptor *device_descriptor; - if (! (device_descriptor = usbd_device_device_descriptor (device, port))) { @@ -214,20 +219,16 @@ static int ep0_get_descriptor (struct usb_device_instance *device, /* correct the correct control endpoint 0 max packet size into the descriptor */ device_descriptor = (struct usb_device_descriptor *) urb->buffer; - device_descriptor->bMaxPacketSize0 = - urb->device->bus->maxpacketsize; } - /*dbg_ep0(3, "copied device configuration, actual_length: %x", urb->actual_length); */ + dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length); break; case USB_DESCRIPTOR_TYPE_CONFIGURATION: { - int bNumInterface; struct usb_configuration_descriptor *configuration_descriptor; struct usb_device_descriptor *device_descriptor; - if (! (device_descriptor = usbd_device_device_descriptor (device, port))) { @@ -251,130 +252,35 @@ static int ep0_get_descriptor (struct usb_device_instance *device, index); return -1; } + dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength)); copy_config (urb, configuration_descriptor, - sizeof (struct - usb_configuration_descriptor), - max); - - - /* iterate across interfaces for specified configuration */ - dbg_ep0 (0, "bNumInterfaces: %d", - configuration_descriptor->bNumInterfaces); - for (bNumInterface = 0; - bNumInterface < - configuration_descriptor->bNumInterfaces; - bNumInterface++) { - int bAlternateSetting; - struct usb_interface_instance - *interface_instance; - - dbg_ep0 (3, "[%d] bNumInterfaces: %d", - bNumInterface, - configuration_descriptor->bNumInterfaces); - - if (! (interface_instance = usbd_device_interface_instance (device, - port, index, bNumInterface))) - { - dbg_ep0 (3, "[%d] interface_instance NULL", - bNumInterface); - return -1; - } - /* iterate across interface alternates */ - for (bAlternateSetting = 0; - bAlternateSetting < interface_instance->alternates; - bAlternateSetting++) { - /*int class; */ - int bNumEndpoint; - struct usb_interface_descriptor *interface_descriptor; - - struct usb_alternate_instance *alternate_instance; - - dbg_ep0 (3, "[%d:%d] alternates: %d", - bNumInterface, - bAlternateSetting, - interface_instance->alternates); - - if (! (alternate_instance = usbd_device_alternate_instance (device, port, index, bNumInterface, bAlternateSetting))) { - dbg_ep0 (3, "[%d] alternate_instance NULL", - bNumInterface); - return -1; - } - /* copy descriptor for this interface */ - copy_config (urb, alternate_instance->interface_descriptor, - sizeof (struct usb_interface_descriptor), - max); - - /*dbg_ep0(3, "[%d:%d] classes: %d endpoints: %d", bNumInterface, bAlternateSetting, */ - /* alternate_instance->classes, alternate_instance->endpoints); */ - - /* iterate across classes for this alternate interface */ -#if 0 - for (class = 0; - class < alternate_instance->classes; - class++) { - struct usb_class_descriptor *class_descriptor; - /*dbg_ep0(3, "[%d:%d:%d] classes: %d", bNumInterface, bAlternateSetting, */ - /* class, alternate_instance->classes); */ - if (!(class_descriptor = usbd_device_class_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, class))) { - dbg_ep0 (3, "[%d] class NULL", - class); - return -1; - } - /* copy descriptor for this class */ - copy_config (urb, class_descriptor, - sizeof (struct usb_class_descriptor), - max); - } -#endif - - /* iterate across endpoints for this alternate interface */ - interface_descriptor = alternate_instance->interface_descriptor; - for (bNumEndpoint = 0; - bNumEndpoint < alternate_instance->endpoints; - bNumEndpoint++) { - struct usb_endpoint_descriptor *endpoint_descriptor; - dbg_ep0 (3, "[%d:%d:%d] endpoint: %d", - bNumInterface, - bAlternateSetting, - bNumEndpoint, - interface_descriptor-> - bNumEndpoints); - if (!(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, index, bNumInterface, bAlternateSetting, bNumEndpoint))) { - dbg_ep0 (3, "[%d] endpoint NULL", - bNumEndpoint); - return -1; - } - /* copy descriptor for this endpoint */ - copy_config (urb, endpoint_descriptor, - sizeof (struct usb_endpoint_descriptor), - max); - } - } - } - dbg_ep0 (3, "lengths: %d %d", - le16_to_cpu (configuration_descriptor->wTotalLength), - urb->actual_length); + cpu_to_le16(configuration_descriptor->wTotalLength), + max); } + break; case USB_DESCRIPTOR_TYPE_STRING: { struct usb_string_descriptor *string_descriptor; - if (!(string_descriptor = usbd_get_string (index))) { + serial_printf("Invalid string index %d\n", index); return -1; } - /*dbg_ep0(3, "string_descriptor: %p", string_descriptor); */ + dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength); copy_config (urb, string_descriptor, string_descriptor->bLength, max); } break; case USB_DESCRIPTOR_TYPE_INTERFACE: + serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n"); return -1; case USB_DESCRIPTOR_TYPE_ENDPOINT: + serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n"); return -1; case USB_DESCRIPTOR_TYPE_HID: { + serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n"); return -1; /* unsupported at this time */ #if 0 int bNumInterface = @@ -403,6 +309,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device, break; case USB_DESCRIPTOR_TYPE_REPORT: { + serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n"); return -1; /* unsupported at this time */ #if 0 int bNumInterface = @@ -434,12 +341,19 @@ static int ep0_get_descriptor (struct usb_device_instance *device, #endif } break; + case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: + { + /* If a USB device supports both a full speed and low speed operation + * we must send a Device_Qualifier descriptor here + */ + return -1; + } default: return -1; } - dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d packet size: %2d", + dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d", urb->buffer, urb->buffer_length, urb->actual_length, device->bus->endpoint_array[0].tx_packetSize); /* @@ -495,6 +409,12 @@ int ep0_recv_setup (struct urb *urb) /* handle USB Standard Request (c.f. USB Spec table 9-2) */ if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) { + if(device->device_state <= STATE_CONFIGURED){ + /* Attempt to handle a CDC specific request if we are + * in the configured state. + */ + return device->cdc_recv_setup(request,urb); + } dbg_ep0 (1, "non standard request: %x", request->bmRequestType & USB_REQ_TYPE_MASK); return -1; /* Stall here */ @@ -567,6 +487,7 @@ int ep0_recv_setup (struct urb *urb) le16_to_cpu (request->wValue) & 0xff); case USB_REQ_GET_CONFIGURATION: + serial_printf("get config %d\n", device->configuration); return ep0_get_one (device, urb, device->configuration); @@ -642,7 +563,6 @@ int ep0_recv_setup (struct urb *urb) /*dbg_ep0(2, "address: %d %d %d", */ /* request->wValue, le16_to_cpu(request->wValue), device->address); */ - serial_printf ("DEVICE_ADDRESS_ASSIGNED.. event?\n"); return 0; case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */ @@ -653,9 +573,10 @@ int ep0_recv_setup (struct urb *urb) /* c.f. 9.4.7 - the top half of wValue is reserved */ /* */ if ((device->configuration = - le16_to_cpu (request->wValue) & 0x7f) != 0) { + le16_to_cpu (request->wValue) & 0xFF80) != 0) { /* c.f. 9.4.7 - zero is the default or addressed state, in our case this */ /* is the same is configuration zero */ + serial_printf("error setting dev->config to zero!\n"); device->configuration = 0; /* TBR - ?????? */ } /* reset interface and alternate settings */ diff --git a/drivers/usbdcore_mpc8xx.c b/drivers/usbdcore_mpc8xx.c new file mode 100644 index 0000000..9bd2c23 --- /dev/null +++ b/drivers/usbdcore_mpc8xx.c @@ -0,0 +1,1412 @@ +/* + * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit + * bodonoghue@CodeHermit.ie + * + * References + * DasUBoot/drivers/usbdcore_omap1510.c, for design and implementation ideas. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* + * Notes : + * 1. #define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX + * packet to force the USB re-transmit protocol. + * + * 2. #define __DEBUG_UDC__ to switch on debug tracing to serial console + * be careful that tracing doesn't create Hiesen-bugs with respect to + * response timeouts to control requests. + * + * 3. This driver should be able to support any higher level driver that + * that wants to do either of the two standard UDC implementations + * Control-Bulk-Interrupt or Bulk-IN/Bulk-Out standards. Hence + * gserial and cdc_acm should work with this code. + * + * 4. NAK events never actually get raised at all, the documentation + * is just wrong ! + * + * 5. For some reason, cbd_datlen is *always* +2 the value it should be. + * this means that having an RX cbd of 16 bytes is not possible, since + * the same size is reported for 14 bytes received as 16 bytes received + * until we can find out why this happens, RX cbds must be limited to 8 + * bytes. TODO: check errata for this behaviour. + * + * 6. Right now this code doesn't support properly powering up with the USB + * cable attached to the USB host my development board the Adder87x doesn't + * have a pull-up fitted to allow this, so it is necessary to power the + * board and *then* attached the USB cable to the host. However somebody + * with a different design in their board may be able to keep the cable + * constantly connected and simply enable/disable a pull-up re + * figure 31.1 in MPC885RM.pdf instead of having to power up the board and + * then attach the cable ! + * + */ +#include +#include + +#if defined(CONFIG_MPC885_FAMILY) && defined(CONFIG_USB_DEVICE) +#include +#include "usbdcore.h" +#include "usbdcore_mpc8xx.h" +#include "usbdcore_ep0.h" + +#define ERR(fmt, args...)\ + serial_printf("ERROR : [%s] %s:%d: "fmt,\ + __FILE__,__FUNCTION__,__LINE__, ##args) +#ifdef __DEBUG_UDC__ + #define DBG(fmt,args...)\ + serial_printf("[%s] %s:%d: "fmt,\ + __FILE__,__FUNCTION__,__LINE__, ##args) +#else + #define DBG(fmt,args...) +#endif + +/* Static Data */ +#ifdef __SIMULATE_ERROR__ + static char err_poison_test = 0; +#endif +static struct mpc8xx_ep ep_ref[MAX_ENDPOINTS]; +static u32 address_base = STATE_NOT_READY; +static mpc8xx_udc_state_t udc_state = 0; +static struct usb_device_instance *udc_device = 0; +static volatile usb_epb_t *endpoints[MAX_ENDPOINTS]; +static volatile cbd_t * tx_cbd[TX_RING_SIZE]; +static volatile cbd_t * rx_cbd[RX_RING_SIZE]; +static volatile immap_t *immr = 0; +static volatile cpm8xx_t *cp = 0; +static volatile usb_pram_t *usb_paramp = 0; +static volatile usb_t *usbp = 0; +static int rx_ct = 0; +static int tx_ct = 0; + +/* Static Function Declarations */ +static void mpc8xx_udc_state_transition_up (usb_device_state_t initial, + usb_device_state_t final); +static void mpc8xx_udc_state_transition_down (usb_device_state_t initial, + usb_device_state_t final); +static void mpc8xx_udc_stall (unsigned int ep); +static void mpc8xx_udc_flush_tx_fifo(int epid); +static void mpc8xx_udc_flush_rx_fifo(void); +static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp); +static void mpc8xx_udc_init_tx(struct usb_endpoint_instance *epi, + struct urb * tx_urb); +static void mpc8xx_udc_dump_request(struct usb_device_request *request); +static void mpc8xx_udc_clock_init (volatile immap_t * immr, + volatile cpm8xx_t * cp); +static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi); +static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp); +static void mpc8xx_udc_ep0_rx(volatile cbd_t * rx_cbdp); +static void mpc8xx_udc_cbd_init (void); +static void mpc8xx_udc_endpoint_init (void); +static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size); +static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment); +static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp); +static void mpc8xx_udc_set_nak (unsigned int ep); +static short mpc8xx_udc_handle_txerr(void); +static void mpc8xx_udc_advance_rx(volatile cbd_t ** rx_cbdp, int epid); + +/****************************************************************************** + Global Linkage + *****************************************************************************/ + +/* udc_init + * + * Do initial bus gluing + */ +int udc_init(void) +{ + /* Init various pointers */ + immr = (immap_t *) CFG_IMMR; + cp = (cpm8xx_t *)&(immr->im_cpm); + usb_paramp = (usb_pram_t*)&(cp->cp_dparam[PROFF_USB]); + usbp = (usb_t *) &(cp->cp_scc[0]); + + memset(ep_ref, 0x00, (sizeof(struct mpc8xx_ep) * MAX_ENDPOINTS)); + + udc_device = 0; + udc_state = STATE_NOT_READY; + + usbp->usmod= 0x00; + usbp->uscom= 0; + + /* Set USB Frame #0, Respond at Address & Get a clock source */ + usbp->usaddr = 0x00; + mpc8xx_udc_clock_init (immr, cp); + + /* PA15, PA14 as perhiperal USBRXD and USBOE */ + immr->im_ioport.iop_padir&= ~0x0003; + immr->im_ioport.iop_papar|= 0x0003; + + /* PC11/PC10 as peripheral USBRXP USBRXN */ + immr->im_ioport.iop_pcso|= 0x0030; + + /* PC7/PC6 as perhiperal USBTXP and USBTXN */ + immr->im_ioport.iop_pcdir|= 0x0300; + immr->im_ioport.iop_pcpar|= 0x0300; + + /* Set the base address */ + address_base = (u32)(cp->cp_dpmem + CPM_USB_BASE); + + /* Initialise endpoints and circular buffers */ + mpc8xx_udc_endpoint_init(); + mpc8xx_udc_cbd_init(); + + /* Assign allocated Dual Port Endpoint descriptors */ + usb_paramp->ep0ptr = (u32)endpoints[0]; + usb_paramp->ep1ptr = (u32)endpoints[1]; + usb_paramp->ep2ptr = (u32)endpoints[2]; + usb_paramp->ep3ptr = (u32)endpoints[3]; + usb_paramp->frame_n = 0; + + DBG("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n", + usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr, + usb_paramp->ep3ptr); + + return 0; +} + +/* udc_irq + * + * Poll for whatever events may have occured + */ +void udc_irq(void) +{ + int epid = 0; + volatile cbd_t * rx_cbdp = 0; + volatile cbd_t * rx_cbdp_base = 0; + + if(udc_state!=STATE_READY){ + return; + } + + if(usbp->usber&USB_E_BSY){ + /* This shouldn't happen. If it does then it's a bug ! */ + usbp->usber|=USB_E_BSY; + mpc8xx_udc_flush_rx_fifo(); + } + + + /* Scan all RX/Bidirectional Endpoints for RX data. */ + for(epid = 0; epidcbd_sc&RX_BD_E)){ + + if(rx_cbdp->cbd_sc&0x1F){ + /* Corrupt data discard it. + * Controller has NAK'd this packet. + */ + mpc8xx_udc_clear_rxbd(rx_cbdp); + + }else{ + if(!epid){ + mpc8xx_udc_ep0_rx(rx_cbdp); + + }else{ + /* Process data */ + mpc8xx_udc_set_nak(epid); + mpc8xx_udc_epn_rx(epid,rx_cbdp); + mpc8xx_udc_clear_rxbd(rx_cbdp); + } + } + + /* Advance RX CBD pointer */ + mpc8xx_udc_advance_rx(&rx_cbdp, epid); + ep_ref[epid].prx = rx_cbdp; + }else{ + /* Advance RX CBD pointer */ + mpc8xx_udc_advance_rx(&rx_cbdp, epid); + } + + }while(rx_cbdp != rx_cbdp_base); + } + + /* Handle TX events as appropiate, the correct place to do this is + * in a tx routine. Perhaps TX on epn was pre-empted by ep0 + */ + + if(usbp->usber&USB_E_TXB){ + usbp->usber|=USB_E_TXB; + } + + if(usbp->usber&(USB_TX_ERRMASK)){ + mpc8xx_udc_handle_txerr(); + } + + /* Switch to the default state, respond at the default address */ + if(usbp->usber&USB_E_RESET){ + usbp->usber|=USB_E_RESET; + usbp->usaddr = 0x00; + udc_device->device_state = STATE_DEFAULT; + } + + /*if(usbp->usber&USB_E_IDLE){ + We could suspend here ! + usbp->usber|=USB_E_IDLE; + DBG("idle state change\n"); + } + if(usbp->usbs){ + We could resume here when IDLE is deasserted ! + Not worth doing, so long as we are self powered though. + }*/ + + return; +} + + + +/* udc_endpoint_write + * + * Write some data to an endpoint + */ +int udc_endpoint_write(struct usb_endpoint_instance *epi) +{ + int ep = 0; + short epid = 1, unnak = 0, ret = 0; + + if(udc_state != STATE_READY){ + ERR("invalid udc_state != STATE_READY!\n"); + return -1; + } + + if(!udc_device || !epi){ + return -1; + } + + if(udc_device->device_state!=STATE_CONFIGURED){ + return -1; + } + + ep = epi->endpoint_address & 0x03; + if(ep >= MAX_ENDPOINTS){ + return -1; + } + + /* Set NAK for all RX endpoints during TX */ + for(epid = 1; epidusep[epid]&( USEP_THS_NAK | USEP_RHS_NAK ))){ + unnak |= 1<bus->endpoint_array[ep],epi->tx_urb); + ret = mpc8xx_udc_ep_tx(&udc_device->bus->endpoint_array[ep]); + + /* Remove temporary NAK */ + for(epid = 1; epid= MAX_ENDPOINTS){ + goto err; + } + epi = &udc_device->bus->endpoint_array[ep]; + if(!epi){ + goto err; + } + + if(!ep_ref[ep].urb){ + ep_ref[ep].urb = usbd_alloc_urb(udc_device, + udc_device->bus->endpoint_array); + if(!ep_ref[ep].urb){ + goto err; + } + }else{ + ep_ref[ep].urb->actual_length = 0; + } + + switch(direction){ + case USB_DIR_IN: + epi->tx_urb = ep_ref[ep].urb; + break; + case USB_DIR_OUT: + epi->rcv_urb = ep_ref[ep].urb; + break; + default: + goto err; + } + return 0; + +err: + udc_state = STATE_ERROR; + return -1; +} + +/* udc_setup_ep + * + * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram + * Isochronous endpoints aren't yet supported! + */ +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, + struct usb_endpoint_instance *epi) +{ + uchar direction = 0; + int ep_attrib = 0; + + if(epi && (ep < MAX_ENDPOINTS)){ + + if(ep == 0){ + if (epi->rcv_attributes!=USB_ENDPOINT_XFER_CONTROL + ||epi->tx_attributes!= + USB_ENDPOINT_XFER_CONTROL){ + + /* ep0 must be a control endpoint*/ + udc_state = STATE_ERROR; + return; + + } + if(!(ep_ref[ep].sc & EP_ATTACHED)){ + mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize, + epi->rcv_packetSize); + } + usbp->usep[ep] = 0x0000; + return; + } + + if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN) { + + direction = 1; + ep_attrib = epi->tx_attributes; + epi->rcv_packetSize = 0; + ep_ref[ep].sc |= USB_DIR_IN; + } else { + + direction = 0; + ep_attrib = epi->rcv_attributes; + epi->tx_packetSize = 0; + ep_ref[ep].sc &= ~USB_DIR_IN; + } + + if(mpc8xx_udc_assign_urb(ep, epi->endpoint_address + &USB_ENDPOINT_DIR_MASK)){ + return; + } + + switch(ep_attrib){ + case USB_ENDPOINT_XFER_CONTROL: + if(!(ep_ref[ep].sc & EP_ATTACHED)){ + mpc8xx_udc_cbd_attach (ep, + epi->tx_packetSize, + epi->rcv_packetSize); + } + usbp->usep[ep] = ep<<12; + epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb; + + break; + case USB_ENDPOINT_XFER_BULK : + case USB_ENDPOINT_XFER_INT: + if(!(ep_ref[ep].sc & EP_ATTACHED)){ + if(direction){ + mpc8xx_udc_cbd_attach (ep, + epi->tx_packetSize, 0); + }else{ + mpc8xx_udc_cbd_attach (ep, + 0, epi->rcv_packetSize); + } + } + usbp->usep[ep]= (ep<<12)|((ep_attrib)<<8); + + break; + case USB_ENDPOINT_XFER_ISOC: + default: + serial_printf("Error endpoint attrib %d>3\n", + ep_attrib); + udc_state = STATE_ERROR; + break; + } + } + +} + +/* udc_connect + * + * Move state, switch on the USB + */ +void udc_connect(void) +{ + /* Enable pull-up resistor on D+ + * TODO: fit a pull-up resistor to drive SE0 for > 2.5us + */ + + if(udc_state!=STATE_ERROR){ + udc_state = STATE_READY; + usbp->usmod|= USMOD_EN; + } +} + +/* udc_disconnect + * + * Disconnect is not used but, is included for completeness + */ +void udc_disconnect(void) +{ + /* Disable pull-up resistor on D- + * TODO: fix a pullup resistor to control this + */ + + if(udc_state!=STATE_ERROR){ + udc_state = STATE_NOT_READY; + } + usbp->usmod&=~USMOD_EN; +} + +/* udc_enable + * + * Grab an EP0 URB, register interest in a subset of USB events + */ +void udc_enable(struct usb_device_instance *device) +{ + if(udc_state == STATE_ERROR){ + return; + } + + udc_device = device; + + if(!ep_ref[0].urb){ + ep_ref[0].urb = usbd_alloc_urb(device, + device->bus->endpoint_array); + } + + /* Register interest in all events except SOF, enable transceiver */ + usbp->usber= 0x03FF; + usbp->usbmr= 0x02F7; + + return; +} + +/* udc_disable + * + * disable the currently hooked device + */ +void udc_disable(void) +{ + int i = 0; + + if(udc_state == STATE_ERROR){ + DBG("Won't disable UDC. udc_state==STATE_ERROR !\n"); + return; + } + + udc_device = 0; + + for(;iusbmr= 0x00; + usbp->usmod= ~USMOD_EN; + udc_state = STATE_NOT_READY; +} + +/* udc_startup_events + * + * Enable the specified device + */ +void udc_startup_events(struct usb_device_instance *device) +{ + udc_enable(device); + if(udc_state == STATE_READY){ + usbd_device_event_irq (device, DEVICE_CREATE, 0); + } +} + +/* udc_set_nak + * + * Allow upper layers to signal lower layers should not accept more RX data + * + */ +void udc_set_nak(int epid) +{ + if(epid){ + mpc8xx_udc_set_nak(epid); + } +} + +/* udc_unset_nak + * + * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint. + * Switch off NAKing on this endpoint to accept more data output from host. + * + */ +void udc_unset_nak (int epid) +{ + if(epid > MAX_ENDPOINTS){ + return; + } + + if(usbp->usep[epid]&(USEP_THS_NAK | USEP_RHS_NAK)){ + usbp->usep[epid]&= ~(USEP_THS_NAK | USEP_RHS_NAK); + __asm__ ("eieio"); + } +} + +/****************************************************************************** + Static Linkage +******************************************************************************/ + +/* udc_state_transition_up + * udc_state_transition_down + * + * Helper functions to implement device state changes. The device states and + * the events that transition between them are: + * + * STATE_ATTACHED + * || /\ + * \/ || + * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET + * || /\ + * \/ || + * STATE_POWERED + * || /\ + * \/ || + * DEVICE_RESET DEVICE_POWER_INTERRUPTION + * || /\ + * \/ || + * STATE_DEFAULT + * || /\ + * \/ || + * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET + * || /\ + * \/ || + * STATE_ADDRESSED + * || /\ + * \/ || + * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED + * || /\ + * \/ || + * STATE_CONFIGURED + * + * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED + * to STATE_CONFIGURED) from the specified initial state to the specified final + * state, passing through each intermediate state on the way. If the initial + * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then + * no state transitions will take place. + * + * udc_state_transition_down transitions down (in the direction from + * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the + * specified final state, passing through each intermediate state on the way. + * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final + * state, then no state transitions will take place. + * + */ + +static void mpc8xx_udc_state_transition_up (usb_device_state_t initial, + usb_device_state_t final) +{ + if (initial < final) { + switch (initial) { + case STATE_ATTACHED: + usbd_device_event_irq (udc_device, + DEVICE_HUB_CONFIGURED, 0); + if (final == STATE_POWERED) + break; + case STATE_POWERED: + usbd_device_event_irq (udc_device, DEVICE_RESET, 0); + if (final == STATE_DEFAULT) + break; + case STATE_DEFAULT: + usbd_device_event_irq (udc_device, + DEVICE_ADDRESS_ASSIGNED, 0); + if (final == STATE_ADDRESSED) + break; + case STATE_ADDRESSED: + usbd_device_event_irq (udc_device, DEVICE_CONFIGURED, + 0); + case STATE_CONFIGURED: + break; + default: + break; + } + } +} + +static void mpc8xx_udc_state_transition_down (usb_device_state_t initial, + usb_device_state_t final) +{ + if (initial > final) { + switch (initial) { + case STATE_CONFIGURED: + usbd_device_event_irq (udc_device, + DEVICE_DE_CONFIGURED, 0); + if (final == STATE_ADDRESSED) + break; + case STATE_ADDRESSED: + usbd_device_event_irq (udc_device, DEVICE_RESET, 0); + if (final == STATE_DEFAULT) + break; + case STATE_DEFAULT: + usbd_device_event_irq (udc_device, + DEVICE_POWER_INTERRUPTION, 0); + if (final == STATE_POWERED) + break; + case STATE_POWERED: + usbd_device_event_irq (udc_device, DEVICE_HUB_RESET, + 0); + case STATE_ATTACHED: + break; + default: + break; + } + } +} + +/* mpc8xx_udc_stall + * + * Force returning of STALL tokens on the given endpoint. Protocol or function + * STALL conditions are permissable here + */ +static void mpc8xx_udc_stall (unsigned int ep) +{ + usbp->usep[ep] |= STALL_BITMASK; +} + +/* mpc8xx_udc_set_nak + * + * Force returning of NAK responses for the given endpoint as a kind of very + * simple flow control + */ +static void mpc8xx_udc_set_nak (unsigned int ep) +{ + usbp->usep[ep] |= NAK_BITMASK; + __asm__ ("eieio"); +} + +/* mpc8xx_udc_handle_txerr + * + * Handle errors relevant to TX. Return a status code to allow calling + * indicative of what if anything happened + */ +static short mpc8xx_udc_handle_txerr() +{ + short ep = 0, ret = 0; + + for(; epusber&(0x10<cbd_sc&0x06){ + ret = 1; + mpc8xx_udc_flush_tx_fifo(ep); + + }else{ + if(usbp->usep[ep]&STALL_BITMASK){ + if(!ep){ + usbp->usep[ep]&= + ~STALL_BITMASK; + } + }/* else NAK */ + } + usbp->usber|=(0x10<cbd_sc & RX_BD_W){ + *rx_cbdp = (volatile cbd_t*) + (endpoints[epid]->rbase + CFG_IMMR); + + }else{ + (*rx_cbdp)++; + } +} + + +/* mpc8xx_udc_flush_tx_fifo + * + * Flush a given TX fifo. Assumes one tx cbd per endpoint + */ +static void mpc8xx_udc_flush_tx_fifo(int epid) +{ + volatile cbd_t * tx_cbdp = 0; + + if(epid > MAX_ENDPOINTS){ + return; + } + + /* TX stop */ + immr->im_cpm.cp_cpcr = ((epid<<2) | 0x1D01); + __asm__ ("eieio"); + while(immr->im_cpm.cp_cpcr & 0x01); + + usbp->uscom = 0x40 | 0; + + /* reset ring */ + tx_cbdp = (cbd_t*)(endpoints[epid]->tbptr + CFG_IMMR); + tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W); + + + endpoints[epid]->tptr = endpoints[epid]->tbase; + endpoints[epid]->tstate = 0x00; + endpoints[epid]->tbcnt = 0x00; + + /* TX start */ + immr->im_cpm.cp_cpcr = ((epid<<2) | 0x2D01); + __asm__ ("eieio"); + while(immr->im_cpm.cp_cpcr & 0x01); + + return; +} + +/* mpc8xx_udc_flush_rx_fifo + * + * For the sake of completeness of the namespace, it seems like + * a good-design-decision (tm) to include mpc8xx_udc_flush_rx_fifo(); + * If RX_BD_E is true => a driver bug either here or in an upper layer + * not polling frequently enough. If RX_BD_E is true we have told the host + * we have accepted data but, the CPM found it had no-where to put that data + * which needless to say would be a bad thing. + */ +static void mpc8xx_udc_flush_rx_fifo() +{ + int i = 0; + for(i = 0;icbd_sc&RX_BD_E)){ + ERR("buf %p used rx data len = 0x%x sc=0x%x!\n", + rx_cbd[i], rx_cbd[i]->cbd_datlen, + rx_cbd[i]->cbd_sc); + + } + } + ERR("BUG : Input over-run\n"); +} + +/* mpc8xx_udc_clear_rxbd + * + * Release control of RX CBD to CP. + */ +static void mpc8xx_udc_clear_rxbd(volatile cbd_t * rx_cbdp) +{ + rx_cbdp->cbd_datlen = 0x0000; + rx_cbdp->cbd_sc= ((rx_cbdp->cbd_sc & RX_BD_W)|(RX_BD_E | RX_BD_I)); + __asm__ ("eieio"); +} + +/* mpc8xx_udc_tx_irq + * + * Parse for tx timeout, control RX or USB reset/busy conditions + * Return -1 on timeout, -2 on fatal error, else return zero + */ +static int mpc8xx_udc_tx_irq(int ep) +{ + int i = 0; + + if(usbp->usber&(USB_TX_ERRMASK)){ + if(mpc8xx_udc_handle_txerr()){ + /* Timeout, controlling function must retry send */ + return -1; + } + } + + if(usbp->usber & (USB_E_RESET|USB_E_BSY)){ + /* Fatal, abandon TX transaction */ + return -2; + } + + if(usbp->usber & USB_E_RXB){ + for(i = 0;icbd_sc&RX_BD_E)){ + if((rx_cbd[i] == ep_ref[0].prx) || ep){ + return -2; + } + } + } + } + + return 0; +} + +/* mpc8xx_udc_ep_tx + * + * Transmit in a re-entrant fashion outbound USB packets. + * Implement retry/timeout mechanism described in USB specification + * Toggle DATA0/DATA1 pids as necessary + * Introduces non-standard tx_retry. The USB standard has no scope for slave + * devices to give up TX, however tx_retry stops us getting stuck in an endless + * TX loop. + */ +static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi) +{ + struct urb *urb = epi->tx_urb; + volatile cbd_t * tx_cbdp = 0; + unsigned int ep = 0, pkt_len = 0, x = 0, tx_retry = 0; + int ret = 0; + + if(!epi || (epi->endpoint_address&0x03)>=MAX_ENDPOINTS || !urb){ + return -1; + } + + ep = epi->endpoint_address & 0x03; + tx_cbdp = (cbd_t*)(endpoints[ep]->tbptr + CFG_IMMR); + + if(tx_cbdp->cbd_sc&TX_BD_R || usbp->usber&USB_E_TXB){ + mpc8xx_udc_flush_tx_fifo(ep); + usbp->usber |= USB_E_TXB; + }; + + while(tx_retry++ < 100){ + ret = mpc8xx_udc_tx_irq(ep); + if(ret == -1){ + /* ignore timeout here */ + }else if(ret == -2){ + /* Abandon TX */ + mpc8xx_udc_flush_tx_fifo(ep); + return -1; + } + + tx_cbdp = (cbd_t*)(endpoints[ep]->tbptr + CFG_IMMR); + while(tx_cbdp->cbd_sc&TX_BD_R){}; + tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc&TX_BD_W); + + pkt_len = urb->actual_length - epi->sent; + + if(pkt_len> epi->tx_packetSize || pkt_len > EP_MAX_PKT){ + pkt_len = MIN(epi->tx_packetSize, EP_MAX_PKT); + } + + for(x=0; xcbd_bufaddr+x)) = + urb->buffer[epi->sent + x]; + } + tx_cbdp->cbd_datlen = pkt_len; + tx_cbdp->cbd_sc|=(CBD_TX_BITMASK | ep_ref[ep].pid); + __asm__ ("eieio"); + + #ifdef __SIMULATE_ERROR__ + if(++err_poison_test == 2){ + err_poison_test = 0; + tx_cbdp->cbd_sc&=~TX_BD_TC; + } + #endif + + usbp->uscom = (USCOM_STR | ep); + + while(!(usbp->usber&USB_E_TXB)){ + ret = mpc8xx_udc_tx_irq(ep); + if(ret == -1){ + /* TX timeout */ + break; + }else if(ret == -2){ + if(usbp->usber & USB_E_TXB){ + usbp->usber|=USB_E_TXB; + } + mpc8xx_udc_flush_tx_fifo(ep); + return -1; + } + }; + + if(usbp->usber & USB_E_TXB){ + usbp->usber|=USB_E_TXB; + } + + /* ACK must be present <= 18bit times from TX */ + if(ret == -1){ + continue; + } + + /* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */ + epi->sent += pkt_len; + epi->last = MIN (urb->actual_length - epi->sent, + epi->tx_packetSize); + TOGGLE_TX_PID(ep_ref[ep].pid); + + if(epi->sent >= epi->tx_urb->actual_length){ + + epi->tx_urb->actual_length = 0; + epi->sent = 0; + + if(ep_ref[ep].sc & EP_SEND_ZLP){ + ep_ref[ep].sc &= ~EP_SEND_ZLP; + }else{ + return 0; + } + } + } + + ERR("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n",ep, epi->sent, + epi->tx_urb->actual_length); + + return -1; +} + +/* mpc8xx_udc_dump_request + * + * Dump a control request to console + */ +static void mpc8xx_udc_dump_request(struct usb_device_request *request) +{ + DBG( + "bmRequestType:%02x bRequest:%02x wValue:%04x " + "wIndex:%04x wLength:%04x ?\n", + request->bmRequestType, + request->bRequest, + request->wValue, + request->wIndex, + request->wLength); + + return; +} + +/* mpc8xx_udc_ep0_rx_setup + * + * Decode received ep0 SETUP packet. return non-zero on error + */ +static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp) +{ + unsigned int x = 0; + struct urb * purb = ep_ref[0].urb; + struct usb_endpoint_instance *epi = + &udc_device->bus->endpoint_array[0]; + + for(; xcbd_datlen; x++){ + *(((unsigned char*)&ep_ref[0].urb->device_request)+x) = + *((unsigned char*)(rx_cbdp->cbd_bufaddr+x)); + } + + mpc8xx_udc_clear_rxbd(rx_cbdp); + + if (ep0_recv_setup(purb)) { + mpc8xx_udc_dump_request(&purb->device_request); + return -1; + } + + if ((purb->device_request.bmRequestType&USB_REQ_DIRECTION_MASK) + == USB_REQ_HOST2DEVICE) { + + switch (purb->device_request.bRequest){ + case USB_REQ_SET_ADDRESS: + /* Send the Status OUT ZLP */ + ep_ref[0].pid = TX_BD_PID_DATA1; + purb->actual_length = 0; + mpc8xx_udc_init_tx(epi,purb); + mpc8xx_udc_ep_tx(epi); + + /* Move to the addressed state */ + usbp->usaddr = udc_device->address; + mpc8xx_udc_state_transition_up(udc_device->device_state, + STATE_ADDRESSED); + return 0; + + case USB_REQ_SET_CONFIGURATION: + if(!purb->device_request.wValue){ + + /* Respond at default address */ + usbp->usaddr = 0x00; + mpc8xx_udc_state_transition_down(udc_device->device_state, + STATE_ADDRESSED); + + } else { + + /* TODO: Support multiple configurations */ + mpc8xx_udc_state_transition_up(udc_device->device_state,STATE_CONFIGURED); + for(x=1; xbus->endpoint_array[x].endpoint_address&USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN){ + ep_ref[x].pid = TX_BD_PID_DATA0; + }else{ + ep_ref[x].pid = RX_BD_PID_DATA0; + } + /* Set configuration must unstall endpoints */ + usbp->usep[x]&=~STALL_BITMASK; + } + + } + break; + default: + /* CDC/Vendor specific */ + break; + } + + /* Send ZLP as ACK in Status OUT phase */ + ep_ref[0].pid = TX_BD_PID_DATA1; + purb->actual_length = 0; + mpc8xx_udc_init_tx(epi,purb); + mpc8xx_udc_ep_tx(epi); + + }else{ + if(purb->actual_length){ + ep_ref[0].pid = TX_BD_PID_DATA1; + mpc8xx_udc_init_tx(epi,purb); + + if(!(purb->actual_length%EP0_MAX_PACKET_SIZE)){ + ep_ref[0].sc |= EP_SEND_ZLP; + } + + if(purb->device_request.wValue== + USB_DESCRIPTOR_TYPE_DEVICE){ + if(le16_to_cpu(purb->device_request.wLength)> + purb->actual_length){ + /* Send EP0_MAX_PACKET_SIZE bytes + * unless correct size requested. + */ + if(purb->actual_length > + epi->tx_packetSize){ + + purb->actual_length = + epi->tx_packetSize; + } + + } + } + mpc8xx_udc_ep_tx(epi); + + }else{ + /* Corrupt SETUP packet? */ + ERR("Zero length data or SETUP with DATA-IN phase ?\n"); + return 1; + } + } + return 0; +} + +/* mpc8xx_udc_init_tx + * + * Setup some basic parameters for a TX transaction + */ +static void mpc8xx_udc_init_tx(struct usb_endpoint_instance *epi, + struct urb * tx_urb) +{ + epi->sent = 0; + epi->last = 0; + epi->tx_urb = tx_urb; +} + +/* mpc8xx_udc_ep0_rx + * + * Receive ep0/control USB data. Parse and possibly send a response. + */ +static void mpc8xx_udc_ep0_rx(volatile cbd_t * rx_cbdp) +{ + if(rx_cbdp->cbd_sc&RX_BD_PID_SETUP){ + + /* Unconditionally accept SETUP packets */ + if(mpc8xx_udc_ep0_rx_setup(rx_cbdp)){ + mpc8xx_udc_stall (0); + } + + } else { + + mpc8xx_udc_clear_rxbd(rx_cbdp); + + if((rx_cbdp->cbd_datlen-2)){ + /* SETUP with a DATA phase + * outside of SETUP packet. + * Reply with STALL. + */ + mpc8xx_udc_stall (0); + } + } +} + +/* mpc8xx_udc_epn_rx + * + * Receive some data from cbd into USB system urb data abstraction + * Upper layers should NAK if there is insufficient RX data space + */ +static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp) +{ + struct usb_endpoint_instance *epi = 0; + struct urb *urb = 0; + unsigned int x = 0; + + if(epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen){ + return 0; + } + + /* USB 2.0 PDF section 8.6.4 + * Discard data with invalid PID it is a resend. + */ + if(ep_ref[epid].pid!=(rx_cbdp->cbd_sc&0xC0)){ + return 1; + } + TOGGLE_RX_PID(ep_ref[epid].pid); + + epi = &udc_device->bus->endpoint_array[epid]; + urb = epi->rcv_urb; + + for(; x<(rx_cbdp->cbd_datlen-2); x++){ + *((unsigned char*)(urb->buffer + urb->actual_length +x)) = + *((unsigned char*)(rx_cbdp->cbd_bufaddr+x)); + } + + if(x){ + usbd_rcv_complete (epi, x, 0); + if(ep_ref[epid].urb->status == RECV_ERROR){ + DBG("RX error unset NAK\n"); + udc_unset_nak(epid); + } + } + return x; +} + +/* mpc8xx_udc_clock_init + * + * Obtain a clock reference for Full Speed Signaling + */ +static void mpc8xx_udc_clock_init (volatile immap_t * immr, + volatile cpm8xx_t * cp) +{ + +#if defined(CFG_USB_EXTC_CLK) + + /* This has been tested with a 48MHz crystal on CLK6 */ + switch(CFG_USB_EXTC_CLK){ + case 1: + immr->im_ioport.iop_papar|= 0x0100; + immr->im_ioport.iop_padir&= ~0x0100; + cp->cp_sicr|= 0x24; + break; + case 2: + immr->im_ioport.iop_papar|= 0x0200; + immr->im_ioport.iop_padir&= ~0x0200; + cp->cp_sicr|= 0x2D; + break; + case 3: + immr->im_ioport.iop_papar|= 0x0400; + immr->im_ioport.iop_padir&= ~0x0400; + cp->cp_sicr|= 0x36; + break; + case 4: + immr->im_ioport.iop_papar|= 0x0800; + immr->im_ioport.iop_padir&= ~0x0800; + cp->cp_sicr|= 0x3F; + break; + default: + udc_state = STATE_ERROR; + break; + } + +#elif defined(CFG_USB_BRGCLK) + + /* This has been tested with brgclk == 50MHz */ + DECLARE_GLOBAL_DATA_PTR; + int divisor = 0; + + if(gd->cpu_clk<48000000L){ + ERR("brgclk is too slow for full-speed USB!\n"); + udc_state = STATE_ERROR; + return; + } + + /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48Mhz) + * but, can /probably/ live with close-ish alternative rates. + */ + divisor = (gd->cpu_clk/48000000L)-1; + cp->cp_sicr &= ~0x0000003F; + + switch(CFG_USB_BRGCLK){ + case 1: + cp->cp_brgc1 |= (divisor|CPM_BRG_EN); + cp->cp_sicr &= ~0x2F; + break; + case 2: + cp->cp_brgc2 |= (divisor|CPM_BRG_EN); + cp->cp_sicr |= 0x00000009; + break; + case 3: + cp->cp_brgc3 |= (divisor|CPM_BRG_EN); + cp->cp_sicr |= 0x00000012; + break; + case 4: + cp->cp_brgc4 = (divisor|CPM_BRG_EN); + cp->cp_sicr |= 0x0000001B; + break; + default: + udc_state = STATE_ERROR; + break; + } + +#else + #error "CFG_USB_EXTC_CLK or CFG_USB_BRGCLK must be defined" +#endif + +} + +/* mpc8xx_udc_cbd_attach + * + * attach a cbd to and endpoint + */ +static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size) +{ + + if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS){ + udc_state = STATE_ERROR; + return; + } + + if (tx_size>USB_MAX_PKT || rx_size>USB_MAX_PKT || + (!tx_size && !rx_size)){ + udc_state = STATE_ERROR; + return; + } + + /* Attach CBD to appropiate Parameter RAM Endpoint data structure */ + if(rx_size){ + endpoints[ep]->rbase = (u32)rx_cbd[rx_ct]; + endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct]; + rx_ct++; + + if(!ep){ + + endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct]; + rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; + rx_ct++; + + }else{ + rx_ct += 2; + endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct]; + rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; + rx_ct++; + } + + /* Where we expect to RX data on this endpoint */ + ep_ref[ep].prx = rx_cbd[rx_ct-1]; + }else{ + + ep_ref[ep].prx = 0; + endpoints[ep]->rbase = 0; + endpoints[ep]->rbptr = 0; + } + + if(tx_size){ + endpoints[ep]->tbase = (u32)tx_cbd[tx_ct]; + endpoints[ep]->tbptr = (u32)tx_cbd[tx_ct]; + tx_ct++; + }else{ + endpoints[ep]->tbase = 0; + endpoints[ep]->tbptr = 0; + } + + endpoints[ep]->tstate = 0; + endpoints[ep]->tbcnt = 0; + endpoints[ep]->mrblr = EP_MAX_PKT; + endpoints[ep]->rfcr = 0x18; + endpoints[ep]->tfcr = 0x18; + ep_ref[ep].sc |= EP_ATTACHED; + + DBG("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n", + ep, endpoints[ep]->rbase, endpoints[ep]->rbptr, endpoints[ep]->tbase, + endpoints[ep]->tbptr, ep_ref[ep].prx); + + return; +} + +/* mpc8xx_udc_cbd_init + * + * Allocate space for a cbd and allocate TX/RX data space + */ +static void mpc8xx_udc_cbd_init (void) +{ + int i = 0; + + for(; icbd_bufaddr = + mpc8xx_udc_alloc(EP_MAX_PKT, sizeof(int)); + + tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W); + tx_cbd[i]->cbd_datlen = 0x0000; + } + + + for(i=0; i< RX_RING_SIZE; i++){ + rx_cbd[i]->cbd_bufaddr = + mpc8xx_udc_alloc(EP_MAX_PKT, sizeof(int)); + rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E); + rx_cbd[i]->cbd_datlen = 0x0000; + + } + + return; +} + +/* mpc8xx_udc_endpoint_init + * + * Attach an endpoint to some dpram + */ +static void mpc8xx_udc_endpoint_init (void) +{ + int i = 0; + + for(; i Entering device setup"); - + do { const int setup_pktsize = 8; unsigned char *datap = @@ -1517,4 +1517,31 @@ void udc_startup_events (struct usb_device_instance *device) udc_enable (device); } +/** + * udc_irq - do pseudo interrupts + */ +void udc_irq(void) +{ + /* Loop while we have interrupts. + * If we don't do this, the input chain + * polling delay is likely to miss + * host requests. + */ + while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) { + /* Handle any new IRQs */ + omap1510_udc_irq (); + omap1510_udc_noniso_irq (); + } +} + +/* Flow control */ +void udc_set_nak(int epid) +{ + /* TODO: implement this functionality in omap1510 */ +} + +void udc_unset_nak (int epid) +{ + /* TODO: implement this functionality in omap1510 */ +} #endif diff --git a/drivers/usbtty.c b/drivers/usbtty.c index ce4a12e..ed96999 100644 --- a/drivers/usbtty.c +++ b/drivers/usbtty.c @@ -1,6 +1,9 @@ /* * (C) Copyright 2003 * Gerry Hamel, geh@ti.com, Texas Instruments + * + * (C) Copyright 2006 + * Bryan O'Donoghue, bodonoghue@codehermit.ie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,20 +28,42 @@ #include #include #include "usbtty.h" +#include "usb_cdc_acm.h" +#include "usbdescriptors.h" +#include /* If defined, override Linux identifiers with + * vendor specific ones */ #if 0 -#define TTYDBG(fmt,args...) serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args) +#define TTYDBG(fmt,args...)\ + serial_printf("[%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args) #else #define TTYDBG(fmt,args...) do{}while(0) #endif -#if 0 -#define TTYERR(fmt,args...) serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,__LINE__,##args) +#if 1 +#define TTYERR(fmt,args...)\ + serial_printf("ERROR![%s] %s %d: "fmt, __FILE__,__FUNCTION__,\ + __LINE__,##args) #else #define TTYERR(fmt,args...) do{}while(0) #endif /* + * Defines + */ +#define NUM_CONFIGS 1 +#define MAX_INTERFACES 2 +#define NUM_ENDPOINTS 3 +#define ACM_TX_ENDPOINT 3 +#define ACM_RX_ENDPOINT 2 +#define GSERIAL_TX_ENDPOINT 2 +#define GSERIAL_RX_ENDPOINT 1 +#define NUM_ACM_INTERFACES 2 +#define NUM_GSERIAL_INTERFACES 1 +#define CONFIG_USBD_DATA_INTERFACE_STR "Bulk Data Interface" +#define CONFIG_USBD_CTRL_INTERFACE_STR "Control Interface" + +/* * Buffers to hold input and output data */ #define USBTTY_BUFFER_SIZE 256 @@ -50,157 +75,336 @@ static circbuf_t usbtty_output; * Instance variables */ static device_t usbttydev; -static struct usb_device_instance device_instance[1]; -static struct usb_bus_instance bus_instance[1]; +static struct usb_device_instance device_instance[1]; +static struct usb_bus_instance bus_instance[1]; static struct usb_configuration_instance config_instance[NUM_CONFIGS]; -static struct usb_interface_instance interface_instance[NUM_INTERFACES]; -static struct usb_alternate_instance alternate_instance[NUM_INTERFACES]; -static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1]; /* one extra for control endpoint */ - -/* - * Static allocation of urbs - */ -#define RECV_ENDPOINT 1 -#define TX_ENDPOINT 2 +static struct usb_interface_instance interface_instance[MAX_INTERFACES]; +static struct usb_alternate_instance alternate_instance[MAX_INTERFACES]; +/* one extra for control endpoint */ +static struct usb_endpoint_instance endpoint_instance[NUM_ENDPOINTS+1]; /* * Global flag */ int usbtty_configured_flag = 0; - /* * Serial number */ static char serial_number[16]; + /* - * Descriptors + * Descriptors, Strings, Local variables. */ + +/* defined and used by usbdcore_ep0.c */ +extern struct usb_string_descriptor **usb_strings; + +/* Indicies, References */ +static unsigned short rx_endpoint = 0; +static unsigned short tx_endpoint = 0; +static unsigned short interface_count = 0; +static struct usb_string_descriptor *usbtty_string_table[STR_COUNT]; + +/* USB Descriptor Strings */ static u8 wstrLang[4] = {4,USB_DT_STRING,0x9,0x4}; static u8 wstrManufacturer[2 + 2*(sizeof(CONFIG_USBD_MANUFACTURER)-1)]; static u8 wstrProduct[2 + 2*(sizeof(CONFIG_USBD_PRODUCT_NAME)-1)]; static u8 wstrSerial[2 + 2*(sizeof(serial_number) - 1)]; static u8 wstrConfiguration[2 + 2*(sizeof(CONFIG_USBD_CONFIGURATION_STR)-1)]; -static u8 wstrInterface[2 + 2*(sizeof(CONFIG_USBD_INTERFACE_STR)-1)]; - -static struct usb_string_descriptor *usbtty_string_table[] = { - (struct usb_string_descriptor*)wstrLang, - (struct usb_string_descriptor*)wstrManufacturer, - (struct usb_string_descriptor*)wstrProduct, - (struct usb_string_descriptor*)wstrSerial, - (struct usb_string_descriptor*)wstrConfiguration, - (struct usb_string_descriptor*)wstrInterface -}; -extern struct usb_string_descriptor **usb_strings; /* defined and used by omap1510_ep0.c */ +static u8 wstrDataInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)]; +static u8 wstrCtrlInterface[2 + 2*(sizeof(CONFIG_USBD_DATA_INTERFACE_STR)-1)]; +/* Standard USB Data Structures */ +static struct usb_interface_descriptor interface_descriptors[MAX_INTERFACES]; +static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS]; +static struct usb_configuration_descriptor *configuration_descriptor = 0; static struct usb_device_descriptor device_descriptor = { - bLength: sizeof(struct usb_device_descriptor), - bDescriptorType: USB_DT_DEVICE, - bcdUSB: USB_BCD_VERSION, - bDeviceClass: USBTTY_DEVICE_CLASS, - bDeviceSubClass: USBTTY_DEVICE_SUBCLASS, - bDeviceProtocol: USBTTY_DEVICE_PROTOCOL, - bMaxPacketSize0: EP0_MAX_PACKET_SIZE, - idVendor: CONFIG_USBD_VENDORID, - idProduct: CONFIG_USBD_PRODUCTID, - bcdDevice: USBTTY_BCD_DEVICE, - iManufacturer: STR_MANUFACTURER, - iProduct: STR_PRODUCT, - iSerialNumber: STR_SERIAL, - bNumConfigurations: NUM_CONFIGS - }; -static struct usb_configuration_descriptor config_descriptors[NUM_CONFIGS] = { - { - bLength: sizeof(struct usb_configuration_descriptor), - bDescriptorType: USB_DT_CONFIG, - wTotalLength: (sizeof(struct usb_configuration_descriptor)*NUM_CONFIGS) + - (sizeof(struct usb_interface_descriptor)*NUM_INTERFACES) + - (sizeof(struct usb_endpoint_descriptor)*NUM_ENDPOINTS), - bNumInterfaces: NUM_INTERFACES, - bConfigurationValue: 1, - iConfiguration: STR_CONFIG, - bmAttributes: BMATTRIBUTE_SELF_POWERED | BMATTRIBUTE_RESERVED, - bMaxPower: USBTTY_MAXPOWER - }, -}; -static struct usb_interface_descriptor interface_descriptors[NUM_INTERFACES] = { - { - bLength: sizeof(struct usb_interface_descriptor), - bDescriptorType: USB_DT_INTERFACE, - bInterfaceNumber: 0, - bAlternateSetting: 0, - bNumEndpoints: NUM_ENDPOINTS, - bInterfaceClass: USBTTY_INTERFACE_CLASS, - bInterfaceSubClass: USBTTY_INTERFACE_SUBCLASS, - bInterfaceProtocol: USBTTY_INTERFACE_PROTOCOL, - iInterface: STR_INTERFACE - }, + .bLength = sizeof(struct usb_device_descriptor), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = cpu_to_le16(USB_BCD_VERSION), + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE, + .idVendor = cpu_to_le16(CONFIG_USBD_VENDORID), + .bcdDevice = cpu_to_le16(USBTTY_BCD_DEVICE), + .iManufacturer = STR_MANUFACTURER, + .iProduct = STR_PRODUCT, + .iSerialNumber = STR_SERIAL, + .bNumConfigurations = NUM_CONFIGS }; -static struct usb_endpoint_descriptor ep_descriptors[NUM_ENDPOINTS] = { - { - bLength: sizeof(struct usb_endpoint_descriptor), - bDescriptorType: USB_DT_ENDPOINT, - bEndpointAddress: CONFIG_USBD_SERIAL_OUT_ENDPOINT | USB_DIR_OUT, - bmAttributes: USB_ENDPOINT_XFER_BULK, - wMaxPacketSize: CONFIG_USBD_SERIAL_OUT_PKTSIZE, - bInterval: 0 - }, - { - bLength: sizeof(struct usb_endpoint_descriptor), - bDescriptorType: USB_DT_ENDPOINT, - bEndpointAddress: CONFIG_USBD_SERIAL_IN_ENDPOINT | USB_DIR_IN, - bmAttributes: USB_ENDPOINT_XFER_BULK, - wMaxPacketSize: CONFIG_USBD_SERIAL_IN_PKTSIZE, - bInterval: 0 - }, - { - bLength: sizeof(struct usb_endpoint_descriptor), - bDescriptorType: USB_DT_ENDPOINT, - bEndpointAddress: CONFIG_USBD_SERIAL_INT_ENDPOINT | USB_DIR_IN, - bmAttributes: USB_ENDPOINT_XFER_INT, - wMaxPacketSize: CONFIG_USBD_SERIAL_INT_PKTSIZE, - bInterval: 0 - }, -}; -static struct usb_endpoint_descriptor *ep_descriptor_ptrs[NUM_ENDPOINTS] = { - &(ep_descriptors[0]), - &(ep_descriptors[1]), - &(ep_descriptors[2]), + + +/* + * Static CDC ACM specific descriptors + */ + +struct acm_config_desc { + struct usb_configuration_descriptor configuration_desc; + + /* Master Interface */ + struct usb_interface_descriptor interface_desc; + + struct usb_class_header_function_descriptor usb_class_header; + struct usb_class_call_management_descriptor usb_class_call_mgt; + struct usb_class_abstract_control_descriptor usb_class_acm; + struct usb_class_union_function_descriptor usb_class_union; + struct usb_endpoint_descriptor notification_endpoint; + + /* Slave Interface */ + struct usb_interface_descriptor data_class_interface; + struct usb_endpoint_descriptor + data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed)); +} __attribute__((packed)); + +static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = { + { + .configuration_desc ={ + .bLength = + sizeof(struct usb_configuration_descriptor), + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = + cpu_to_le16(sizeof(struct acm_config_desc)), + .bNumInterfaces = NUM_ACM_INTERFACES, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG, + .bmAttributes = + BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, + .bMaxPower = USBTTY_MAXPOWER + }, + /* Interface 1 */ + .interface_desc = { + .bLength = sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 0x01, + .bInterfaceClass = + COMMUNICATIONS_INTERFACE_CLASS_CONTROL, + .bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS, + .bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL, + .iInterface = STR_CTRL_INTERFACE, + }, + .usb_class_header = { + .bFunctionLength = + sizeof(struct usb_class_header_function_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_ST_HEADER, + .bcdCDC = cpu_to_le16(110), + }, + .usb_class_call_mgt = { + .bFunctionLength = + sizeof(struct usb_class_call_management_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_ST_CMF, + .bmCapabilities = 0x00, + .bDataInterface = 0x01, + }, + .usb_class_acm = { + .bFunctionLength = + sizeof(struct usb_class_abstract_control_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_ST_ACMF, + .bmCapabilities = 0x00, + }, + .usb_class_union = { + .bFunctionLength = + sizeof(struct usb_class_union_function_descriptor), + .bDescriptorType = CS_INTERFACE, + .bDescriptorSubtype = USB_ST_UF, + .bMasterInterface = 0x00, + .bSlaveInterface0 = 0x01, + }, + .notification_endpoint = { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize + = cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), + .bInterval = 0xFF, + }, + + /* Interface 2 */ + .data_class_interface = { + .bLength = + sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0x01, + .bAlternateSetting = 0x00, + .bNumEndpoints = 0x02, + .bInterfaceClass = + COMMUNICATIONS_INTERFACE_CLASS_DATA, + .bInterfaceSubClass = DATA_INTERFACE_SUBCLASS_NONE, + .bInterfaceProtocol = DATA_INTERFACE_PROTOCOL_NONE, + .iInterface = STR_DATA_INTERFACE, + }, + .data_endpoints = { + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x02 | USB_DIR_OUT, + .bmAttributes = + USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), + .bInterval = 0xFF, + }, + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x03 | USB_DIR_IN, + .bmAttributes = + USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), + .bInterval = 0xFF, + }, + }, + }, +}; + +static struct rs232_emu rs232_desc={ + .dter = 115200, + .stop_bits = 0x00, + .parity = 0x00, + .data_bits = 0x08 }; -/* utility function for converting char* to wide string used by USB */ -static void str2wide (char *str, u16 * wide) -{ - int i; - for (i = 0; i < strlen (str) && str[i]; i++) - wide[i] = (u16) str[i]; -} +/* + * Static Generic Serial specific data + */ + + +struct gserial_config_desc { + + struct usb_configuration_descriptor configuration_desc; + struct usb_interface_descriptor + interface_desc[NUM_GSERIAL_INTERFACES] __attribute__((packed)); + struct usb_endpoint_descriptor + data_endpoints[NUM_ENDPOINTS] __attribute__((packed)); + +} __attribute__((packed)); + +static struct gserial_config_desc +gserial_configuration_descriptors[NUM_CONFIGS] ={ + { + .configuration_desc ={ + .bLength = sizeof(struct usb_configuration_descriptor), + .bDescriptorType = USB_DT_CONFIG, + .wTotalLength = + cpu_to_le16(sizeof(struct gserial_config_desc)), + .bNumInterfaces = NUM_GSERIAL_INTERFACES, + .bConfigurationValue = 1, + .iConfiguration = STR_CONFIG, + .bmAttributes = + BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, + .bMaxPower = USBTTY_MAXPOWER + }, + .interface_desc = { + { + .bLength = + sizeof(struct usb_interface_descriptor), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = NUM_ENDPOINTS, + .bInterfaceClass = + COMMUNICATIONS_INTERFACE_CLASS_VENDOR, + .bInterfaceSubClass = + COMMUNICATIONS_NO_SUBCLASS, + .bInterfaceProtocol = + COMMUNICATIONS_NO_PROTOCOL, + .iInterface = STR_DATA_INTERFACE + }, + }, + .data_endpoints = { + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE), + .bInterval= 0xFF, + }, + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x02 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE), + .bInterval = 0xFF, + }, + { + .bLength = + sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x03 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = + cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), + .bInterval = 0xFF, + }, + }, + }, +}; /* - * Prototypes + * Static Function Prototypes */ + static void usbtty_init_strings (void); static void usbtty_init_instances (void); static void usbtty_init_endpoints (void); - +static void usbtty_init_terminal_type(short type); static void usbtty_event_handler (struct usb_device_instance *device, - usb_device_event_t event, int data); + usb_device_event_t event, int data); +static int usbtty_cdc_setup(struct usb_device_request *request, + struct urb *urb); static int usbtty_configured (void); - static int write_buffer (circbuf_t * buf); static int fill_buffer (circbuf_t * buf); void usbtty_poll (void); -static void pretend_interrupts (void); +/* utility function for converting char* to wide string used by USB */ +static void str2wide (char *str, u16 * wide) +{ + int i; + for (i = 0; i < strlen (str) && str[i]; i++){ + #if defined(__LITTLE_ENDIAN__) + wide[i] = (u16) str[i]; + #elif defined(__BIG_ENDIAN__) + wide[i] = ((u16)(str[i])<<8); + #else + #error "__LITTLE_ENDIAN__ or __BIG_ENDIAN__ undefined" + #endif + } +} /* * Test whether a character is in the RX buffer */ + int usbtty_tstc (void) { + struct usb_endpoint_instance *endpoint = + &endpoint_instance[rx_endpoint]; + + /* If no input data exists, allow more RX to be accepted */ + if(usbtty_input.size <= 0){ + udc_unset_nak(endpoint->endpoint_address&0x03); + } + usbtty_poll (); return (usbtty_input.size > 0); } @@ -210,15 +414,21 @@ int usbtty_tstc (void) * otherwise. When the function is succesfull, the character read is * written into its argument c. */ + int usbtty_getc (void) { char c; + struct usb_endpoint_instance *endpoint = + &endpoint_instance[rx_endpoint]; while (usbtty_input.size <= 0) { + udc_unset_nak(endpoint->endpoint_address&0x03); usbtty_poll (); } buf_pop (&usbtty_input, &c, 1); + udc_set_nak(endpoint->endpoint_address&0x03); + return c; } @@ -238,7 +448,6 @@ void usbtty_putc (const char c) } } - /* usbtty_puts() helper function for finding the next '\n' in a string */ static int next_nl_pos (const char *s) { @@ -252,8 +461,9 @@ static int next_nl_pos (const char *s) } /* - * Output a string to the usb client port. + * Output a string to the usb client port - implementing flow control */ + static void __usbtty_puts (const char *str, int len) { int maxlen = usbtty_output.totalsize; @@ -261,22 +471,19 @@ static void __usbtty_puts (const char *str, int len) /* break str into chunks < buffer size, if needed */ while (len > 0) { - space = maxlen - usbtty_output.size; + usbtty_poll (); + space = maxlen - usbtty_output.size; /* Empty buffer here, if needed, to ensure space... */ - if (space <= 0) { + if (space) { write_buffer (&usbtty_output); - space = maxlen - usbtty_output.size; - if (space <= 0) { - space = len; /* allow old data to be overwritten. */ - } - } - - n = MIN (space, MIN (len, maxlen)); - buf_push (&usbtty_output, str, n); + + n = MIN (space, MIN (len, maxlen)); + buf_push (&usbtty_output, str, n); - str += n; - len -= n; + str += n; + len -= n; + } } } @@ -313,8 +520,10 @@ int drv_usbtty_init (void) { int rc; char * sn; + char * tt; int snlen; + /* Ger seiral number */ if (!(sn = getenv("serial#"))) { sn = "000000000000"; } @@ -327,6 +536,14 @@ int drv_usbtty_init (void) memcpy (serial_number, sn, snlen); serial_number[snlen] = '\0'; + /* Decide on which type of UDC device to be. + */ + + if(!(tt = getenv("usbtty"))) { + tt = "generic"; + } + usbtty_init_terminal_type(strcmp(tt,"cdc_acm")); + /* prepare buffers... */ buf_init (&usbtty_input, USBTTY_BUFFER_SIZE); buf_init (&usbtty_output, USBTTY_BUFFER_SIZE); @@ -337,7 +554,7 @@ int drv_usbtty_init (void) usbtty_init_strings (); usbtty_init_instances (); - udc_startup_events (device_instance); /* Enable our device, initialize udc pointers */ + udc_startup_events (device_instance);/* Enable dev, init udc pointers */ udc_connect (); /* Enable pullup for host detection */ usbtty_init_endpoints (); @@ -362,34 +579,52 @@ static void usbtty_init_strings (void) { struct usb_string_descriptor *string; + usbtty_string_table[STR_LANG] = + (struct usb_string_descriptor*)wstrLang; + string = (struct usb_string_descriptor *) wstrManufacturer; - string->bLength = sizeof (wstrManufacturer); + string->bLength = sizeof(wstrManufacturer); string->bDescriptorType = USB_DT_STRING; str2wide (CONFIG_USBD_MANUFACTURER, string->wData); + usbtty_string_table[STR_MANUFACTURER]=string; + string = (struct usb_string_descriptor *) wstrProduct; - string->bLength = sizeof (wstrProduct); + string->bLength = sizeof(wstrProduct); string->bDescriptorType = USB_DT_STRING; str2wide (CONFIG_USBD_PRODUCT_NAME, string->wData); + usbtty_string_table[STR_PRODUCT]=string; + string = (struct usb_string_descriptor *) wstrSerial; - string->bLength = 2 + 2*strlen(serial_number); + string->bLength = sizeof(serial_number); string->bDescriptorType = USB_DT_STRING; str2wide (serial_number, string->wData); + usbtty_string_table[STR_SERIAL]=string; + string = (struct usb_string_descriptor *) wstrConfiguration; - string->bLength = sizeof (wstrConfiguration); + string->bLength = sizeof(wstrConfiguration); string->bDescriptorType = USB_DT_STRING; str2wide (CONFIG_USBD_CONFIGURATION_STR, string->wData); + usbtty_string_table[STR_CONFIG]=string; + + + string = (struct usb_string_descriptor *) wstrDataInterface; + string->bLength = sizeof(wstrDataInterface); + string->bDescriptorType = USB_DT_STRING; + str2wide (CONFIG_USBD_DATA_INTERFACE_STR, string->wData); + usbtty_string_table[STR_DATA_INTERFACE]=string; - string = (struct usb_string_descriptor *) wstrInterface; - string->bLength = sizeof (wstrInterface); + string = (struct usb_string_descriptor *) wstrCtrlInterface; + string->bLength = sizeof(wstrCtrlInterface); string->bDescriptorType = USB_DT_STRING; - str2wide (CONFIG_USBD_INTERFACE_STR, string->wData); + str2wide (CONFIG_USBD_CTRL_INTERFACE_STR, string->wData); + usbtty_string_table[STR_CTRL_INTERFACE]=string; /* Now, initialize the string table for ep0 handling */ usb_strings = usbtty_string_table; -} +} static void usbtty_init_instances (void) { @@ -400,6 +635,7 @@ static void usbtty_init_instances (void) device_instance->device_state = STATE_INIT; device_instance->device_descriptor = &device_descriptor; device_instance->event = usbtty_event_handler; + device_instance->cdc_recv_setup = usbtty_cdc_setup; device_instance->bus = bus_instance; device_instance->configurations = NUM_CONFIGS; device_instance->configuration_instance_array = config_instance; @@ -415,8 +651,8 @@ static void usbtty_init_instances (void) /* configuration instance */ memset (config_instance, 0, sizeof (struct usb_configuration_instance)); - config_instance->interfaces = NUM_INTERFACES; - config_instance->configuration_descriptor = config_descriptors; + config_instance->interfaces = interface_count; + config_instance->configuration_descriptor = configuration_descriptor; config_instance->interface_instance_array = interface_instance; /* interface instance */ @@ -447,17 +683,22 @@ static void usbtty_init_instances (void) sizeof (struct usb_endpoint_instance)); endpoint_instance[i].endpoint_address = - ep_descriptors[i - 1].bEndpointAddress; + ep_descriptor_ptrs[i - 1]->bEndpointAddress; - endpoint_instance[i].rcv_packetSize = - ep_descriptors[i - 1].wMaxPacketSize; endpoint_instance[i].rcv_attributes = - ep_descriptors[i - 1].bmAttributes; + ep_descriptor_ptrs[i - 1]->bmAttributes; + + endpoint_instance[i].rcv_packetSize = + le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize); + + endpoint_instance[i].tx_attributes = + ep_descriptor_ptrs[i - 1]->bmAttributes; endpoint_instance[i].tx_packetSize = - ep_descriptors[i - 1].wMaxPacketSize; + le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize); + endpoint_instance[i].tx_attributes = - ep_descriptors[i - 1].bmAttributes; + ep_descriptor_ptrs[i - 1]->bmAttributes; urb_link_init (&endpoint_instance[i].rcv); urb_link_init (&endpoint_instance[i].rdy); @@ -480,13 +721,79 @@ static void usbtty_init_endpoints (void) int i; bus_instance->max_endpoints = NUM_ENDPOINTS + 1; - for (i = 0; i <= NUM_ENDPOINTS; i++) { + for (i = 1; i <= NUM_ENDPOINTS; i++) { udc_setup_ep (device_instance, i, &endpoint_instance[i]); } } +/* usbtty_init_terminal_type + * + * Do some late binding for our device type. + */ +static void usbtty_init_terminal_type(short type) +{ + switch(type){ + /* CDC ACM */ + case 0: + /* Assign endpoint descriptors */ + ep_descriptor_ptrs[0] = + &acm_configuration_descriptors[0].notification_endpoint; + ep_descriptor_ptrs[1] = + &acm_configuration_descriptors[0].data_endpoints[0]; + ep_descriptor_ptrs[2] = + &acm_configuration_descriptors[0].data_endpoints[1]; + + /* Enumerate Device Descriptor */ + device_descriptor.bDeviceClass = + COMMUNICATIONS_DEVICE_CLASS; + device_descriptor.idProduct = + cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM); + + /* Assign endpoint indices */ + tx_endpoint = ACM_TX_ENDPOINT; + rx_endpoint = ACM_RX_ENDPOINT; + + /* Configuration Descriptor */ + configuration_descriptor = + (struct usb_configuration_descriptor*) + &acm_configuration_descriptors; + + /* Interface count */ + interface_count = NUM_ACM_INTERFACES; + break; -/*********************************************************************************/ + /* BULK IN/OUT & Default */ + case 1: + default: + /* Assign endpoint descriptors */ + ep_descriptor_ptrs[0] = + &gserial_configuration_descriptors[0].data_endpoints[0]; + ep_descriptor_ptrs[1] = + &gserial_configuration_descriptors[0].data_endpoints[1]; + ep_descriptor_ptrs[2] = + &gserial_configuration_descriptors[0].data_endpoints[2]; + + /* Enumerate Device Descriptor */ + device_descriptor.bDeviceClass = 0xFF; + device_descriptor.idProduct = + cpu_to_le16(CONFIG_USBD_PRODUCTID_GSERIAL); + + /* Assign endpoint indices */ + tx_endpoint = GSERIAL_TX_ENDPOINT; + rx_endpoint = GSERIAL_RX_ENDPOINT; + + /* Configuration Descriptor */ + configuration_descriptor = + (struct usb_configuration_descriptor*) + &gserial_configuration_descriptors; + + /* Interface count */ + interface_count = NUM_GSERIAL_INTERFACES; + break; + } +} + +/******************************************************************************/ static struct urb *next_urb (struct usb_device_instance *device, struct usb_endpoint_instance *endpoint) @@ -525,28 +832,40 @@ static int write_buffer (circbuf_t * buf) if (!usbtty_configured ()) { return 0; } + + struct usb_endpoint_instance *endpoint = + &endpoint_instance[tx_endpoint]; + struct urb *current_urb = NULL; - if (buf->size) { + current_urb = next_urb (device_instance, endpoint); + /* TX data still exists - send it now + */ + if(endpoint->sent < current_urb->actual_length){ + if(udc_endpoint_write (endpoint)){ + /* Write pre-empted by RX */ + return -1; + } + } - struct usb_endpoint_instance *endpoint = - &endpoint_instance[TX_ENDPOINT]; - struct urb *current_urb = NULL; + if (buf->size) { char *dest; int space_avail; int popnum, popped; int total = 0; - /* Break buffer into urb sized pieces, and link each to the endpoint */ + /* Break buffer into urb sized pieces, + * and link each to the endpoint + */ while (buf->size > 0) { - current_urb = next_urb (device_instance, endpoint); + if (!current_urb) { TTYERR ("current_urb is NULL, buf->size %d\n", buf->size); return total; } - dest = current_urb->buffer + + dest = (char*)current_urb->buffer + current_urb->actual_length; space_avail = @@ -562,14 +881,19 @@ static int write_buffer (circbuf_t * buf) current_urb->actual_length += popped; total += popped; - /* If endpoint->last == 0, then transfers have not started on this endpoint */ + /* If endpoint->last == 0, then transfers have + * not started on this endpoint + */ if (endpoint->last == 0) { - udc_endpoint_write (endpoint); + if(udc_endpoint_write (endpoint)){ + /* Write pre-empted by RX */ + return -1; + } } - } /* end while */ + }/* end while */ return total; - } /* end if tx_urb */ + } return 0; } @@ -577,18 +901,22 @@ static int write_buffer (circbuf_t * buf) static int fill_buffer (circbuf_t * buf) { struct usb_endpoint_instance *endpoint = - &endpoint_instance[RECV_ENDPOINT]; + &endpoint_instance[rx_endpoint]; if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) { - unsigned int nb = endpoint->rcv_urb->actual_length; + unsigned int nb = 0; char *src = (char *) endpoint->rcv_urb->buffer; + unsigned int rx_avail = buf->totalsize - buf->size; - buf_push (buf, src, nb); - endpoint->rcv_urb->actual_length = 0; + if(rx_avail >= endpoint->rcv_urb->actual_length){ + nb = endpoint->rcv_urb->actual_length; + buf_push (buf, src, nb); + endpoint->rcv_urb->actual_length = 0; + + } return nb; } - return 0; } @@ -597,7 +925,7 @@ static int usbtty_configured (void) return usbtty_configured_flag; } -/*********************************************************************************/ +/******************************************************************************/ static void usbtty_event_handler (struct usb_device_instance *device, usb_device_event_t event, int data) @@ -619,8 +947,34 @@ static void usbtty_event_handler (struct usb_device_instance *device, } } -/*********************************************************************************/ +/******************************************************************************/ + +int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb) +{ + switch (request->bRequest){ + case ACM_SET_CONTROL_LINE_STATE: /* Implies DTE ready */ + break; + case ACM_SEND_ENCAPSULATED_COMMAND : /* Required */ + break; + case ACM_SET_LINE_ENCODING : /* DTE stop/parity bits + * per character */ + break; + case ACM_GET_ENCAPSULATED_RESPONSE : /* request response */ + break; + case ACM_GET_LINE_ENCODING : /* request DTE rate, + * stop/parity bits */ + memcpy (urb->buffer , &rs232_desc, sizeof(rs232_desc)); + urb->actual_length = sizeof(rs232_desc); + + break; + default: + return 1; + } + return 0; +} + +/******************************************************************************/ /* * Since interrupt handling has not yet been implemented, we use this function @@ -630,36 +984,29 @@ static void usbtty_event_handler (struct usb_device_instance *device, void usbtty_poll (void) { /* New interrupts? */ - pretend_interrupts (); + udc_irq(); - /* Write any output data to host buffer (do this before checking interrupts to avoid missing one) */ + /* Write any output data to host buffer + * (do this before checking interrupts to avoid missing one) + */ if (usbtty_configured ()) { write_buffer (&usbtty_output); } /* New interrupts? */ - pretend_interrupts (); - - /* Check for new data from host.. (do this after checking interrupts to get latest data) */ + udc_irq(); + + /* Check for new data from host.. + * (do this after checking interrupts to get latest data) + */ if (usbtty_configured ()) { fill_buffer (&usbtty_input); } /* New interrupts? */ - pretend_interrupts (); -} + udc_irq(); -static void pretend_interrupts (void) -{ - /* Loop while we have interrupts. - * If we don't do this, the input chain - * polling delay is likely to miss - * host requests. - */ - while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) { - /* Handle any new IRQs */ - omap1510_udc_irq (); - omap1510_udc_noniso_irq (); - } } + + #endif diff --git a/drivers/usbtty.h b/drivers/usbtty.h index 79c2fe5..731b763 100644 --- a/drivers/usbtty.h +++ b/drivers/usbtty.h @@ -2,6 +2,9 @@ * (C) Copyright 2003 * Gerry Hamel, geh@ti.com, Texas Instruments * + * (C) Copyright 2006 + * Bryan O'Donoghue, bodonoghue@codehermit.ie, CodeHermit + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -21,44 +24,47 @@ #ifndef __USB_TTY_H__ #define __USB_TTY_H__ - #include "usbdcore.h" +#if defined(CONFIG_PPC) +#include "usbdcore_mpc8xx.h" +#elif defined(CONFIG_ARM) #include "usbdcore_omap1510.h" +#endif +#include -#define NUM_CONFIGS 1 -#define NUM_INTERFACES 1 -#define NUM_ENDPOINTS 3 +/* If no VendorID/ProductID is defined in config.h, pretend to be Linux + * DO NOT Reuse this Vendor/Product setup with protocol incompatible devices */ -#define EP0_MAX_PACKET_SIZE 64 +#define CONFIG_USBD_VENDORID 0x0525 /* Linux/NetChip */ +#define CONFIG_USBD_PRODUCTID_GSERIAL 0xa4a6 /* gserial */ +#define CONFIG_USBD_PRODUCTID_CDCACM 0xa4a7 /* CDC ACM */ +#define CONFIG_USBD_MANUFACTURER "Das U-Boot" +#define CONFIG_USBD_PRODUCT_NAME U_BOOT_VERSION -#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB" -#define CONFIG_USBD_INTERFACE_STR "Simple Serial Data Interface - Bulk Mode" +#define CONFIG_USBD_CONFIGURATION_STR "TTY via USB" -#define CONFIG_USBD_SERIAL_OUT_ENDPOINT 2 -#define CONFIG_USBD_SERIAL_OUT_PKTSIZE 64 -#define CONFIG_USBD_SERIAL_IN_ENDPOINT 1 -#define CONFIG_USBD_SERIAL_IN_PKTSIZE 64 -#define CONFIG_USBD_SERIAL_INT_ENDPOINT 5 -#define CONFIG_USBD_SERIAL_INT_PKTSIZE 16 - +#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT +#define CONFIG_USBD_SERIAL_OUT_PKTSIZE UDC_OUT_PACKET_SIZE +#define CONFIG_USBD_SERIAL_IN_ENDPOINT UDC_IN_ENDPOINT +#define CONFIG_USBD_SERIAL_IN_PKTSIZE UDC_IN_PACKET_SIZE +#define CONFIG_USBD_SERIAL_INT_ENDPOINT UDC_INT_ENDPOINT +#define CONFIG_USBD_SERIAL_INT_PKTSIZE UDC_INT_PACKET_SIZE +#define CONFIG_USBD_SERIAL_BULK_PKTSIZE UDC_BULK_PACKET_SIZE #define USBTTY_DEVICE_CLASS COMMUNICATIONS_DEVICE_CLASS -#define USBTTY_DEVICE_SUBCLASS COMMUNICATIONS_NO_SUBCLASS -#define USBTTY_DEVICE_PROTOCOL COMMUNICATIONS_NO_PROTOCOL - -#define USBTTY_INTERFACE_CLASS 0xFF /* Vendor Specific */ -#define USBTTY_INTERFACE_SUBCLASS 0x02 -#define USBTTY_INTERFACE_PROTOCOL 0x01 -#define USBTTY_BCD_DEVICE 0x0 -#define USBTTY_MAXPOWER 0x0 +#define USBTTY_BCD_DEVICE 0x00 +#define USBTTY_MAXPOWER 0x00 -#define STR_MANUFACTURER 1 -#define STR_PRODUCT 2 -#define STR_SERIAL 3 -#define STR_CONFIG 4 -#define STR_INTERFACE 5 +#define STR_LANG 0x00 +#define STR_MANUFACTURER 0x01 +#define STR_PRODUCT 0x02 +#define STR_SERIAL 0x03 +#define STR_CONFIG 0x04 +#define STR_DATA_INTERFACE 0x05 +#define STR_CTRL_INTERFACE 0x06 +#define STR_COUNT 0x07 #endif diff --git a/include/configs/AdderUSB.h b/include/configs/AdderUSB.h new file mode 100644 index 0000000..2112e56 --- /dev/null +++ b/include/configs/AdderUSB.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2006 CodeHermit. + * Bryan O'Donoghue + * + * Provides support for USB console on the Analogue & Micro Adder87x + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ADDERUSB__ +#define __ADDERUSB__ + +/* Include the board port */ +#include "Adder.h" + +#define CONFIG_USB_DEVICE /* Include UDC driver */ +#define CONFIG_USB_TTY /* Bind the TTY driver to UDC */ +#define CFG_USB_EXTC_CLK 0x02 /* Oscillator on EXTC_CLK 2 */ +#define CFG_USB_BRG_CLK 0x04 /* or use Baud rate generator 0x04 */ +#define CFG_CONSOLE_IS_IN_ENV /* Console is in env */ + +/* If you have a USB-IF assigned VendorID then you may wish to define + * your own vendor specific values either in BoardName.h or directly in + * usbd_vendor_info.h + */ + +/* +#define CONFIG_USBD_MANUFACTURER "CodeHermit.ie" +#define CONFIG_USBD_PRODUCT_NAME "Das U-Boot" +#define CONFIG_USBD_VENDORID 0xFFFF +#define CONFIG_USBD_PRODUCTID_GSERIAL 0xFFFF +#define CONFIG_USBD_PRODUCTID_CDCACM 0xFFFE +*/ + +#endif /* __ADDERUSB_H__ */ diff --git a/include/usb_cdc_acm.h b/include/usb_cdc_acm.h new file mode 100644 index 0000000..8cb1654 --- /dev/null +++ b/include/usb_cdc_acm.h @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2006 + * Bryan O'Donoghue, deckard@codehermit.ie, CodeHermit + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* ACM Control Requests */ +#define ACM_SEND_ENCAPSULATED_COMMAND 0x00 +#define ACM_GET_ENCAPSULATED_RESPONSE 0x01 +#define ACM_SET_COMM_FEATURE 0x02 +#define ACM_GET_COMM_FEATRUE 0x03 +#define ACM_CLEAR_COMM_FEATURE 0x04 +#define ACM_SET_LINE_ENCODING 0x20 +#define ACM_GET_LINE_ENCODING 0x21 +#define ACM_SET_CONTROL_LINE_STATE 0x22 +#define ACM_SEND_BREAK 0x23 + +/* ACM Notification Codes */ +#define ACM_NETWORK_CONNECTION 0x00 +#define ACM_RESPONSE_AVAILABLE 0x01 +#define ACM_SERIAL_STATE 0x20 + +/* Format of response expected by a ACM_GET_LINE_ENCODING request */ +struct rs232_emu{ + unsigned long dter; + unsigned char stop_bits; + unsigned char parity; + unsigned char data_bits; +}__attribute__((packed)); diff --git a/include/usbdcore.h b/include/usbdcore.h index 6e92df1..cb2be72 100644 --- a/include/usbdcore.h +++ b/include/usbdcore.h @@ -576,6 +576,9 @@ struct usb_device_instance { void (*event) (struct usb_device_instance *device, usb_device_event_t event, int data); + /* Do cdc device specific control requests */ + int (*cdc_recv_setup)(struct usb_device_request *request, struct urb *urb); + /* bus interface */ struct usb_bus_instance *bus; /* which bus interface driver */ diff --git a/include/usbdcore_mpc8xx.h b/include/usbdcore_mpc8xx.h new file mode 100644 index 0000000..e54acd9 --- /dev/null +++ b/include/usbdcore_mpc8xx.h @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2006 Bryan O'Donoghue, CodeHermit + * bodonoghue@codehermit.ie + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +/* Mode Register */ +#define USMOD_EN 0x01 +#define USMOD_HOST 0x02 +#define USMOD_TEST 0x04 +#define USMOD_SFTE 0x08 +#define USMOD_RESUME 0x40 +#define USMOD_LSS 0x80 + +/* Endpoint Registers */ +#define USEP_RHS_NORM 0x00 +#define USEP_RHS_IGNORE 0x01 +#define USEP_RHS_NAK 0x02 +#define USEP_RHS_STALL 0x03 + +#define USEP_THS_NORM 0x00 +#define USEP_THS_IGNORE 0x04 +#define USEP_THS_NAK 0x08 +#define USEP_THS_STALL 0x0C + +#define USEP_RTE 0x10 +#define USEP_MF 0x20 + +#define USEP_TM_CONTROL 0x00 +#define USEP_TM_INT 0x100 +#define USEP_TM_BULK 0x200 +#define USEP_TM_ISO 0x300 + +/* Command Register */ +#define USCOM_EP0 0x00 +#define USCOM_EP1 0x01 +#define USCOM_EP2 0x02 +#define USCOM_EP3 0x03 + +#define USCOM_FLUSH 0x40 +#define USCOM_STR 0x80 + +/* Event Register */ +#define USB_E_RXB 0x0001 +#define USB_E_TXB 0x0002 +#define USB_E_BSY 0x0004 +#define USB_E_SOF 0x0008 +#define USB_E_TXE1 0x0010 +#define USB_E_TXE2 0x0020 +#define USB_E_TXE3 0x0040 +#define USB_E_TXE4 0x0080 +#define USB_TX_ERRMASK (USB_E_TXE1|USB_E_TXE2|USB_E_TXE3|USB_E_TXE4) +#define USB_E_IDLE 0x0100 +#define USB_E_RESET 0x0200 + +/* Mask Register */ +#define USBS_IDLE 0x01 + +/* RX Buffer Descriptor */ +#define RX_BD_OV 0x02 +#define RX_BD_CR 0x04 +#define RX_BD_AB 0x08 +#define RX_BD_NO 0x10 +#define RX_BD_PID_DATA0 0x00 +#define RX_BD_PID_DATA1 0x40 +#define RX_BD_PID_SETUP 0x80 +#define RX_BD_F 0x400 +#define RX_BD_L 0x800 +#define RX_BD_I 0x1000 +#define RX_BD_W 0x2000 +#define RX_BD_E 0x8000 + +/* Useful masks */ +#define RX_BD_PID_BITMASK (RX_BD_PID_DATA1 | RX_BD_PID_SETUP) +#define STALL_BITMASK (USEP_THS_STALL | USEP_RHS_STALL) +#define NAK_BITMASK (USEP_THS_NAK | USEP_RHS_NAK) +#define CBD_TX_BITMASK (TX_BD_R | TX_BD_L | TX_BD_TC | TX_BD_I | TX_BD_CNF) + +/* TX Buffer Descriptor */ +#define TX_BD_UN 0x02 +#define TX_BD_TO 0x04 +#define TX_BD_NO_PID 0x00 +#define TX_BD_PID_DATA0 0x80 +#define TX_BD_PID_DATA1 0xC0 +#define TX_BD_CNF 0x200 +#define TX_BD_TC 0x400 +#define TX_BD_L 0x800 +#define TX_BD_I 0x1000 +#define TX_BD_W 0x2000 +#define TX_BD_R 0x8000 + +/* Implementation specific defines */ + +#define EP_MIN_PACKET_SIZE 0x08 +#define MAX_ENDPOINTS 0x04 +#define FIFO_SIZE 0x10 +#define EP_MAX_PKT FIFO_SIZE +#define TX_RING_SIZE 0x04 +#define RX_RING_SIZE 0x06 +#define USB_MAX_PKT 0x40 +#define TOGGLE_TX_PID(x) x= ((~x)&0x40)|0x80 +#define TOGGLE_RX_PID(x) x^= 0x40 +#define EP_ATTACHED 0x01 /* Endpoint has a urb attached or not */ +#define EP_SEND_ZLP 0x02 /* Send ZLP y/n ? */ + +#define PROFF_USB 0x00000000 +#define CPM_USB_BASE 0x00000A00 + +/* UDC device defines */ +#define EP0_MAX_PACKET_SIZE EP_MAX_PKT +#define UDC_OUT_ENDPOINT 0x02 +#define UDC_OUT_PACKET_SIZE EP_MIN_PACKET_SIZE +#define UDC_IN_ENDPOINT 0x03 +#define UDC_IN_PACKET_SIZE EP_MIN_PACKET_SIZE +#define UDC_INT_ENDPOINT 0x01 +#define UDC_INT_PACKET_SIZE UDC_IN_PACKET_SIZE +#define UDC_BULK_PACKET_SIZE EP_MIN_PACKET_SIZE + +struct mpc8xx_ep { + struct urb * urb; + unsigned char pid; + unsigned char sc; + volatile cbd_t * prx; +}; + +typedef struct mpc8xx_usb{ + char usmod; /* Mode Register */ + char usaddr; /* Slave Address Register */ + char uscom; /* Command Register */ + char res1; /* Reserved */ + ushort usep[4]; + ulong res2; /* Reserved */ + ushort usber; /* Event Register */ + ushort res3; /* Reserved */ + ushort usbmr; /* Mask Register */ + char res4; /* Reserved */ + char usbs; /* Status Register */ + char res5[8]; /* Reserved */ +}usb_t; + +typedef struct mpc8xx_parameter_ram{ + ushort ep0ptr; /* Endpoint Pointer Register 0 */ + ushort ep1ptr; /* Endpoint Pointer Register 1 */ + ushort ep2ptr; /* Endpoint Pointer Register 2 */ + ushort ep3ptr; /* Endpoint Pointer Register 3 */ + uint rstate; /* Receive state */ + uint rptr; /* Receive internal data pointer */ + ushort frame_n; /* Frame number */ + ushort rbcnt; /* Receive byte count */ + uint rtemp; /* Receive temp cp use only */ + uint rxusb; /* Rx Data Temp */ + ushort rxuptr; /* Rx microcode return address temp */ +}usb_pram_t; + +typedef struct endpoint_parameter_block_pointer{ + ushort rbase; /* RxBD base address */ + ushort tbase; /* TxBD base address */ + char rfcr; /* Rx Function code */ + char tfcr; /* Tx Function code */ + ushort mrblr; /* Maximum Receive Buffer Length */ + ushort rbptr; /* RxBD pointer Next Buffer Descriptor */ + ushort tbptr; /* TxBD pointer Next Buffer Descriptor */ + ulong tstate; /* Transmit internal state */ + ulong tptr; /* Transmit internal data pointer */ + ushort tcrc; /* Transmit temp CRC */ + ushort tbcnt; /* Transmit internal bye count */ + ulong ttemp; /* Tx temp */ + ushort txuptr; /* Tx microcode return address */ + ushort res1; /* Reserved */ +}usb_epb_t; + +typedef enum mpc8xx_udc_state{ + STATE_NOT_READY, + STATE_ERROR, + STATE_READY, +}mpc8xx_udc_state_t; + +/* Declarations */ +int udc_init(void); +void udc_irq(void); +int udc_endpoint_write(struct usb_endpoint_instance *endpoint); +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, + struct usb_endpoint_instance *endpoint); +void udc_connect(void); +void udc_disconnect(void); +void udc_enable(struct usb_device_instance *device); +void udc_disable(void); +void udc_startup_events(struct usb_device_instance *device); + +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak (int epid); diff --git a/include/usbdcore_omap1510.h b/include/usbdcore_omap1510.h index 6ea3331..526fcd9 100644 --- a/include/usbdcore_omap1510.h +++ b/include/usbdcore_omap1510.h @@ -161,10 +161,20 @@ #define UDC_VBUS_CTRL (1 << 19) #define UDC_VBUS_MODE (1 << 18) - -void omap1510_udc_irq(void); -void omap1510_udc_noniso_irq(void); - +/* OMAP Endpoint parameters */ +#define EP0_MAX_PACKET_SIZE 64 +#define UDC_OUT_ENDPOINT 2 +#define UDC_OUT_PACKET_SIZE 64 +#define UDC_IN_ENDPOINT 1 +#define UDC_IN_PACKET_SIZE 64 +#define UDC_INT_ENDPOINT 5 +#define UDC_INT_PKTSIZE 16 +#define UDC_BULK_PKTSIZE 16 + +void udc_irq (void); +/* Flow control */ +void udc_set_nak(int epid); +void udc_unset_nak (int epid); /* Higher level functions for abstracting away from specific device */ void udc_endpoint_write(struct usb_endpoint_instance *endpoint); diff --git a/include/usbdescriptors.h b/include/usbdescriptors.h index 2d9f739..8336c18 100644 --- a/include/usbdescriptors.h +++ b/include/usbdescriptors.h @@ -92,33 +92,42 @@ #define COMMUNICATIONS_DEVICE_CLASS 0x02 /* c.f. CDC 4.2 Table 15 */ -#define COMMUNICATIONS_INTERFACE_CLASS 0x02 +#define COMMUNICATIONS_INTERFACE_CLASS_CONTROL 0x02 +#define COMMUNICATIONS_INTERFACE_CLASS_DATA 0x0A +#define COMMUNICATIONS_INTERFACE_CLASS_VENDOR 0x0FF /* c.f. CDC 4.3 Table 16 */ -#define COMMUNICATIONS_NO_SUBCLASS 0x00 +#define COMMUNICATIONS_NO_SUBCLASS 0x00 #define COMMUNICATIONS_DLCM_SUBCLASS 0x01 -#define COMMUNICATIONS_ACM_SUBCLASS 0x02 -#define COMMUNICATIONS_TCM_SUBCLASS 0x03 +#define COMMUNICATIONS_ACM_SUBCLASS 0x02 +#define COMMUNICATIONS_TCM_SUBCLASS 0x03 #define COMMUNICATIONS_MCCM_SUBCLASS 0x04 -#define COMMUNICATIONS_CCM_SUBCLASS 0x05 +#define COMMUNICATIONS_CCM_SUBCLASS 0x05 #define COMMUNICATIONS_ENCM_SUBCLASS 0x06 #define COMMUNICATIONS_ANCM_SUBCLASS 0x07 /* c.f. WMCD 5.1 */ #define COMMUNICATIONS_WHCM_SUBCLASS 0x08 -#define COMMUNICATIONS_DMM_SUBCLASS 0x09 +#define COMMUNICATIONS_DMM_SUBCLASS 0x09 #define COMMUNICATIONS_MDLM_SUBCLASS 0x0a #define COMMUNICATIONS_OBEX_SUBCLASS 0x0b -/* c.f. CDC 4.6 Table 18 */ +/* c.f. CDC 4.4 Table 17 */ +#define COMMUNICATIONS_NO_PROTOCOL 0x00 +#define COMMUNICATIONS_V25TER_PROTOCOL 0x01 /*Common AT Hayes compatible*/ + +/* c.f. CDC 4.5 Table 18 */ #define DATA_INTERFACE_CLASS 0x0a +/* c.f. CDC 4.6 No Table */ +#define DATA_INTERFACE_SUBCLASS_NONE 0x00 /* No subclass pertinent */ + /* c.f. CDC 4.7 Table 19 */ -#define COMMUNICATIONS_NO_PROTOCOL 0x00 +#define DATA_INTERFACE_PROTOCOL_NONE 0x00 /* No class protcol required */ /* c.f. CDC 5.2.3 Table 24 */ -#define CS_INTERFACE 0x24 +#define CS_INTERFACE 0x24 #define CS_ENDPOINT 0x25 /* @@ -128,7 +137,7 @@ * c.f. WMCD 5.3 Table 5.3 */ -#define USB_ST_HEADER 0x00 +#define USB_ST_HEADER 0x00 #define USB_ST_CMF 0x01 #define USB_ST_ACMF 0x02 #define USB_ST_DLMF 0x03 @@ -137,18 +146,18 @@ #define USB_ST_UF 0x06 #define USB_ST_CSF 0x07 #define USB_ST_TOMF 0x08 -#define USB_ST_USBTF 0x09 +#define USB_ST_USBTF 0x09 #define USB_ST_NCT 0x0a #define USB_ST_PUF 0x0b #define USB_ST_EUF 0x0c #define USB_ST_MCMF 0x0d #define USB_ST_CCMF 0x0e #define USB_ST_ENF 0x0f -#define USB_ST_ATMNF 0x10 +#define USB_ST_ATMNF 0x10 #define USB_ST_WHCM 0x11 #define USB_ST_MDLM 0x12 -#define USB_ST_MDLMD 0x13 +#define USB_ST_MDLMD 0x13 #define USB_ST_DMM 0x14 #define USB_ST_OBEX 0x15 #define USB_ST_CS 0x16 @@ -312,7 +321,8 @@ struct usb_class_union_function_descriptor { u8 bDescriptorType; u8 bDescriptorSubtype; /* 0x06 */ u8 bMasterInterface; - u8 bSlaveInterface0[0]; + //u8 bSlaveInterface0[0]; + u8 bSlaveInterface0; } __attribute__ ((packed)); struct usb_class_country_selection_descriptor { -- cgit v1.1 From 386eda022473394ad8f36b86f2bdc9b4cb816291 Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Wed, 14 Jun 2006 18:14:56 +0200 Subject: Code cleanup --- CHANGELOG | 4 +- README | 22 +- drivers/usbdcore_ep0.c | 8 +- drivers/usbdcore_mpc8xx.c | 1124 +++++++++++++++++------------------ drivers/usbdcore_omap1510.c | 4 +- drivers/usbtty.c | 164 ++--- drivers/usbtty.h | 4 +- include/asm-arm/arch-pxa/pxa-regs.h | 2 - include/configs/AdderUSB.h | 8 +- include/usb_cdc_acm.h | 2 +- include/usbdcore_mpc8xx.h | 14 +- include/usbdescriptors.h | 2 +- 12 files changed, 673 insertions(+), 685 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 449db66..bc33482 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,9 @@ Changes since U-Boot 1.1.4: ====================================================================== -* Various USB related patches +* Code cleanup + +* Various USB related patches - Add support for mpc8xx USB device. - Add support for Common Device Class - Abstract Control Model USB console. - Add support for flow control in USB slave devices. diff --git a/README b/README index 284a688..178e51e 100644 --- a/README +++ b/README @@ -870,7 +870,7 @@ The following options need to be configured: attach your usb cable. The Unix command "dmesg" should print it has found a new device. The environment variable usbtty can be set to gserial or cdc_acm to enable your device to - appear to a USB host as a Linux gserial device or a + appear to a USB host as a Linux gserial device or a Common Device Class Abstract Control Model serial device. If you select usbtty = gserial you should be able to enumerate a Linux host by @@ -878,14 +878,14 @@ The following options need to be configured: else if using cdc_acm, simply setting the environment variable usbtty to be cdc_acm should suffice. The following might be defined in YourBoardName.h - + CONFIG_USB_DEVICE Define this to build a UDC device CONFIG_USB_TTY Define this to have a tty type of device available to talk to the UDC device - + CFG_CONSOLE_IS_IN_ENV Define this if you want stdin, stdout &/or stderr to be set to usbtty. @@ -893,15 +893,15 @@ The following options need to be configured: mpc8xx: CFG_USB_EXTC_CLK 0xBLAH Derive USB clock from external clock "blah" - - CFG_USB_EXTC_CLK 0x02 - + - CFG_USB_EXTC_CLK 0x02 + CFG_USB_BRG_CLK 0xBLAH Derive USB clock from brgclk - CFG_USB_BRG_CLK 0x04 - If you have a USB-IF assigned VendorID then you may wish to + If you have a USB-IF assigned VendorID then you may wish to define your own vendor specific values either in BoardName.h - or directly in usbd_vendor_info.h. If you don't define + or directly in usbd_vendor_info.h. If you don't define CONFIG_USBD_MANUFACTURER, CONFIG_USBD_PRODUCT_NAME, CONFIG_USBD_VENDORID and CONFIG_USBD_PRODUCTID, then U-Boot should pretend to be a Linux device to it's target host. @@ -909,7 +909,7 @@ The following options need to be configured: CONFIG_USBD_MANUFACTURER Define this string as the name of your company for - CONFIG_USBD_MANUFACTURER "my company" - + CONFIG_USBD_PRODUCT_NAME Define this string as the name of your product - CONFIG_USBD_PRODUCT_NAME "acme usb device" @@ -919,13 +919,13 @@ The following options need to be configured: Implementors Forum. This *must* be a genuine Vendor ID to avoid polluting the USB namespace. - CONFIG_USBD_VENDORID 0xFFFF - + CONFIG_USBD_PRODUCTID Define this as the unique Product ID for your device - CONFIG_USBD_PRODUCTID 0xFFFF - - + + - MMC Support: The MMC controller on the Intel PXA is supported. To enable this define CONFIG_MMC. The MMC can be diff --git a/drivers/usbdcore_ep0.c b/drivers/usbdcore_ep0.c index 5e7443b..1e44f32 100644 --- a/drivers/usbdcore_ep0.c +++ b/drivers/usbdcore_ep0.c @@ -44,7 +44,7 @@ * XXX * * As alluded to above, a simple callback cdc_recv_setup has been implemented - * in the usb_device data structure to facilicate passing + * in the usb_device data structure to facilicate passing * Common Device Class packets to a function driver. * * XXX @@ -221,7 +221,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device, (struct usb_device_descriptor *) urb->buffer; } - dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length); + dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length); break; case USB_DESCRIPTOR_TYPE_CONFIGURATION: @@ -268,7 +268,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device, serial_printf("Invalid string index %d\n", index); return -1; } - dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength); + dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength); copy_config (urb, string_descriptor, string_descriptor->bLength, max); } break; @@ -344,7 +344,7 @@ static int ep0_get_descriptor (struct usb_device_instance *device, case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: { /* If a USB device supports both a full speed and low speed operation - * we must send a Device_Qualifier descriptor here + * we must send a Device_Qualifier descriptor here */ return -1; } diff --git a/drivers/usbdcore_mpc8xx.c b/drivers/usbdcore_mpc8xx.c index 9bd2c23..e87284b 100644 --- a/drivers/usbdcore_mpc8xx.c +++ b/drivers/usbdcore_mpc8xx.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit - * bodonoghue@CodeHermit.ie + * bodonoghue@CodeHermit.ie * * References * DasUBoot/drivers/usbdcore_omap1510.c, for design and implementation ideas. @@ -12,7 +12,7 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License @@ -24,12 +24,12 @@ /* * Notes : - * 1. #define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX + * 1. #define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX * packet to force the USB re-transmit protocol. * * 2. #define __DEBUG_UDC__ to switch on debug tracing to serial console - * be careful that tracing doesn't create Hiesen-bugs with respect to - * response timeouts to control requests. + * be careful that tracing doesn't create Hiesen-bugs with respect to + * response timeouts to control requests. * * 3. This driver should be able to support any higher level driver that * that wants to do either of the two standard UDC implementations @@ -41,18 +41,18 @@ * * 5. For some reason, cbd_datlen is *always* +2 the value it should be. * this means that having an RX cbd of 16 bytes is not possible, since - * the same size is reported for 14 bytes received as 16 bytes received + * the same size is reported for 14 bytes received as 16 bytes received * until we can find out why this happens, RX cbds must be limited to 8 * bytes. TODO: check errata for this behaviour. * * 6. Right now this code doesn't support properly powering up with the USB - * cable attached to the USB host my development board the Adder87x doesn't - * have a pull-up fitted to allow this, so it is necessary to power the - * board and *then* attached the USB cable to the host. However somebody - * with a different design in their board may be able to keep the cable - * constantly connected and simply enable/disable a pull-up re - * figure 31.1 in MPC885RM.pdf instead of having to power up the board and - * then attach the cable ! + * cable attached to the USB host my development board the Adder87x doesn't + * have a pull-up fitted to allow this, so it is necessary to power the + * board and *then* attached the USB cable to the host. However somebody + * with a different design in their board may be able to keep the cable + * constantly connected and simply enable/disable a pull-up re + * figure 31.1 in MPC885RM.pdf instead of having to power up the board and + * then attach the cable ! * */ #include @@ -60,7 +60,7 @@ #if defined(CONFIG_MPC885_FAMILY) && defined(CONFIG_USB_DEVICE) #include -#include "usbdcore.h" +#include "usbdcore.h" #include "usbdcore_mpc8xx.h" #include "usbdcore_ep0.h" @@ -68,24 +68,24 @@ serial_printf("ERROR : [%s] %s:%d: "fmt,\ __FILE__,__FUNCTION__,__LINE__, ##args) #ifdef __DEBUG_UDC__ - #define DBG(fmt,args...)\ +#define DBG(fmt,args...)\ serial_printf("[%s] %s:%d: "fmt,\ __FILE__,__FUNCTION__,__LINE__, ##args) #else - #define DBG(fmt,args...) +#define DBG(fmt,args...) #endif /* Static Data */ #ifdef __SIMULATE_ERROR__ - static char err_poison_test = 0; +static char err_poison_test = 0; #endif static struct mpc8xx_ep ep_ref[MAX_ENDPOINTS]; static u32 address_base = STATE_NOT_READY; static mpc8xx_udc_state_t udc_state = 0; static struct usb_device_instance *udc_device = 0; -static volatile usb_epb_t *endpoints[MAX_ENDPOINTS]; -static volatile cbd_t * tx_cbd[TX_RING_SIZE]; -static volatile cbd_t * rx_cbd[RX_RING_SIZE]; +static volatile usb_epb_t *endpoints[MAX_ENDPOINTS]; +static volatile cbd_t *tx_cbd[TX_RING_SIZE]; +static volatile cbd_t *rx_cbd[RX_RING_SIZE]; static volatile immap_t *immr = 0; static volatile cpm8xx_t *cp = 0; static volatile usb_pram_t *usb_paramp = 0; @@ -95,87 +95,87 @@ static int tx_ct = 0; /* Static Function Declarations */ static void mpc8xx_udc_state_transition_up (usb_device_state_t initial, - usb_device_state_t final); + usb_device_state_t final); static void mpc8xx_udc_state_transition_down (usb_device_state_t initial, - usb_device_state_t final); + usb_device_state_t final); static void mpc8xx_udc_stall (unsigned int ep); -static void mpc8xx_udc_flush_tx_fifo(int epid); -static void mpc8xx_udc_flush_rx_fifo(void); +static void mpc8xx_udc_flush_tx_fifo (int epid); +static void mpc8xx_udc_flush_rx_fifo (void); static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp); -static void mpc8xx_udc_init_tx(struct usb_endpoint_instance *epi, - struct urb * tx_urb); -static void mpc8xx_udc_dump_request(struct usb_device_request *request); -static void mpc8xx_udc_clock_init (volatile immap_t * immr, - volatile cpm8xx_t * cp); +static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi, + struct urb *tx_urb); +static void mpc8xx_udc_dump_request (struct usb_device_request *request); +static void mpc8xx_udc_clock_init (volatile immap_t * immr, + volatile cpm8xx_t * cp); static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi); static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp); -static void mpc8xx_udc_ep0_rx(volatile cbd_t * rx_cbdp); +static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp); static void mpc8xx_udc_cbd_init (void); static void mpc8xx_udc_endpoint_init (void); static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size); static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment); static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp); static void mpc8xx_udc_set_nak (unsigned int ep); -static short mpc8xx_udc_handle_txerr(void); -static void mpc8xx_udc_advance_rx(volatile cbd_t ** rx_cbdp, int epid); +static short mpc8xx_udc_handle_txerr (void); +static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid); /****************************************************************************** - Global Linkage + Global Linkage *****************************************************************************/ /* udc_init * * Do initial bus gluing */ -int udc_init(void) +int udc_init (void) { /* Init various pointers */ immr = (immap_t *) CFG_IMMR; - cp = (cpm8xx_t *)&(immr->im_cpm); - usb_paramp = (usb_pram_t*)&(cp->cp_dparam[PROFF_USB]); - usbp = (usb_t *) &(cp->cp_scc[0]); + cp = (cpm8xx_t *) & (immr->im_cpm); + usb_paramp = (usb_pram_t *) & (cp->cp_dparam[PROFF_USB]); + usbp = (usb_t *) & (cp->cp_scc[0]); + + memset (ep_ref, 0x00, (sizeof (struct mpc8xx_ep) * MAX_ENDPOINTS)); - memset(ep_ref, 0x00, (sizeof(struct mpc8xx_ep) * MAX_ENDPOINTS)); - udc_device = 0; udc_state = STATE_NOT_READY; - - usbp->usmod= 0x00; - usbp->uscom= 0; - + + usbp->usmod = 0x00; + usbp->uscom = 0; + /* Set USB Frame #0, Respond at Address & Get a clock source */ usbp->usaddr = 0x00; mpc8xx_udc_clock_init (immr, cp); - + /* PA15, PA14 as perhiperal USBRXD and USBOE */ - immr->im_ioport.iop_padir&= ~0x0003; - immr->im_ioport.iop_papar|= 0x0003; - + immr->im_ioport.iop_padir &= ~0x0003; + immr->im_ioport.iop_papar |= 0x0003; + /* PC11/PC10 as peripheral USBRXP USBRXN */ - immr->im_ioport.iop_pcso|= 0x0030; - + immr->im_ioport.iop_pcso |= 0x0030; + /* PC7/PC6 as perhiperal USBTXP and USBTXN */ - immr->im_ioport.iop_pcdir|= 0x0300; - immr->im_ioport.iop_pcpar|= 0x0300; - + immr->im_ioport.iop_pcdir |= 0x0300; + immr->im_ioport.iop_pcpar |= 0x0300; + /* Set the base address */ - address_base = (u32)(cp->cp_dpmem + CPM_USB_BASE); + address_base = (u32) (cp->cp_dpmem + CPM_USB_BASE); /* Initialise endpoints and circular buffers */ - mpc8xx_udc_endpoint_init(); - mpc8xx_udc_cbd_init(); - + mpc8xx_udc_endpoint_init (); + mpc8xx_udc_cbd_init (); + /* Assign allocated Dual Port Endpoint descriptors */ - usb_paramp->ep0ptr = (u32)endpoints[0]; - usb_paramp->ep1ptr = (u32)endpoints[1]; - usb_paramp->ep2ptr = (u32)endpoints[2]; - usb_paramp->ep3ptr = (u32)endpoints[3]; + usb_paramp->ep0ptr = (u32) endpoints[0]; + usb_paramp->ep1ptr = (u32) endpoints[1]; + usb_paramp->ep2ptr = (u32) endpoints[2]; + usb_paramp->ep3ptr = (u32) endpoints[3]; usb_paramp->frame_n = 0; - DBG("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n", - usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr, - usb_paramp->ep3ptr); - + DBG ("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n", + usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr, + usb_paramp->ep3ptr); + return 0; } @@ -183,149 +183,147 @@ int udc_init(void) * * Poll for whatever events may have occured */ -void udc_irq(void) +void udc_irq (void) { int epid = 0; - volatile cbd_t * rx_cbdp = 0; - volatile cbd_t * rx_cbdp_base = 0; + volatile cbd_t *rx_cbdp = 0; + volatile cbd_t *rx_cbdp_base = 0; - if(udc_state!=STATE_READY){ + if (udc_state != STATE_READY) { return; } - - if(usbp->usber&USB_E_BSY){ + + if (usbp->usber & USB_E_BSY) { /* This shouldn't happen. If it does then it's a bug ! */ - usbp->usber|=USB_E_BSY; - mpc8xx_udc_flush_rx_fifo(); + usbp->usber |= USB_E_BSY; + mpc8xx_udc_flush_rx_fifo (); } - /* Scan all RX/Bidirectional Endpoints for RX data. */ - for(epid = 0; epidcbd_sc&RX_BD_E)){ - - if(rx_cbdp->cbd_sc&0x1F){ + + do { + if (!(rx_cbdp->cbd_sc & RX_BD_E)) { + + if (rx_cbdp->cbd_sc & 0x1F) { /* Corrupt data discard it. - * Controller has NAK'd this packet. + * Controller has NAK'd this packet. */ - mpc8xx_udc_clear_rxbd(rx_cbdp); + mpc8xx_udc_clear_rxbd (rx_cbdp); - }else{ - if(!epid){ - mpc8xx_udc_ep0_rx(rx_cbdp); + } else { + if (!epid) { + mpc8xx_udc_ep0_rx (rx_cbdp); - }else{ + } else { /* Process data */ - mpc8xx_udc_set_nak(epid); - mpc8xx_udc_epn_rx(epid,rx_cbdp); - mpc8xx_udc_clear_rxbd(rx_cbdp); - } + mpc8xx_udc_set_nak (epid); + mpc8xx_udc_epn_rx (epid, rx_cbdp); + mpc8xx_udc_clear_rxbd (rx_cbdp); + } } - + /* Advance RX CBD pointer */ - mpc8xx_udc_advance_rx(&rx_cbdp, epid); + mpc8xx_udc_advance_rx (&rx_cbdp, epid); ep_ref[epid].prx = rx_cbdp; - }else{ + } else { /* Advance RX CBD pointer */ - mpc8xx_udc_advance_rx(&rx_cbdp, epid); + mpc8xx_udc_advance_rx (&rx_cbdp, epid); } - }while(rx_cbdp != rx_cbdp_base); + } while (rx_cbdp != rx_cbdp_base); } /* Handle TX events as appropiate, the correct place to do this is * in a tx routine. Perhaps TX on epn was pre-empted by ep0 */ - if(usbp->usber&USB_E_TXB){ - usbp->usber|=USB_E_TXB; + if (usbp->usber & USB_E_TXB) { + usbp->usber |= USB_E_TXB; } - - if(usbp->usber&(USB_TX_ERRMASK)){ - mpc8xx_udc_handle_txerr(); + + if (usbp->usber & (USB_TX_ERRMASK)) { + mpc8xx_udc_handle_txerr (); } /* Switch to the default state, respond at the default address */ - if(usbp->usber&USB_E_RESET){ - usbp->usber|=USB_E_RESET; - usbp->usaddr = 0x00; + if (usbp->usber & USB_E_RESET) { + usbp->usber |= USB_E_RESET; + usbp->usaddr = 0x00; udc_device->device_state = STATE_DEFAULT; } - /*if(usbp->usber&USB_E_IDLE){ - We could suspend here ! - usbp->usber|=USB_E_IDLE; - DBG("idle state change\n"); - } - if(usbp->usbs){ - We could resume here when IDLE is deasserted ! - Not worth doing, so long as we are self powered though. - }*/ + /* if(usbp->usber&USB_E_IDLE){ + We could suspend here ! + usbp->usber|=USB_E_IDLE; + DBG("idle state change\n"); + } + if(usbp->usbs){ + We could resume here when IDLE is deasserted ! + Not worth doing, so long as we are self powered though. + } + */ return; } - - /* udc_endpoint_write * * Write some data to an endpoint */ -int udc_endpoint_write(struct usb_endpoint_instance *epi) +int udc_endpoint_write (struct usb_endpoint_instance *epi) { int ep = 0; short epid = 1, unnak = 0, ret = 0; - if(udc_state != STATE_READY){ - ERR("invalid udc_state != STATE_READY!\n"); + if (udc_state != STATE_READY) { + ERR ("invalid udc_state != STATE_READY!\n"); return -1; } - if(!udc_device || !epi){ + if (!udc_device || !epi) { return -1; } - - if(udc_device->device_state!=STATE_CONFIGURED){ + + if (udc_device->device_state != STATE_CONFIGURED) { return -1; } ep = epi->endpoint_address & 0x03; - if(ep >= MAX_ENDPOINTS){ + if (ep >= MAX_ENDPOINTS) { return -1; } - + /* Set NAK for all RX endpoints during TX */ - for(epid = 1; epidusep[epid]&( USEP_THS_NAK | USEP_RHS_NAK ))){ - unnak |= 1<usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK))) { + unnak |= 1 << epid; } - mpc8xx_udc_set_nak(epid); + mpc8xx_udc_set_nak (epid); } - mpc8xx_udc_init_tx(&udc_device->bus->endpoint_array[ep],epi->tx_urb); - ret = mpc8xx_udc_ep_tx(&udc_device->bus->endpoint_array[ep]); - + mpc8xx_udc_init_tx (&udc_device->bus->endpoint_array[ep], + epi->tx_urb); + ret = mpc8xx_udc_ep_tx (&udc_device->bus->endpoint_array[ep]); + /* Remove temporary NAK */ - for(epid = 1; epid= MAX_ENDPOINTS){ + + if (ep >= MAX_ENDPOINTS) { goto err; } epi = &udc_device->bus->endpoint_array[ep]; - if(!epi){ + if (!epi) { goto err; } - if(!ep_ref[ep].urb){ - ep_ref[ep].urb = usbd_alloc_urb(udc_device, - udc_device->bus->endpoint_array); - if(!ep_ref[ep].urb){ + if (!ep_ref[ep].urb) { + ep_ref[ep].urb = usbd_alloc_urb (udc_device, udc_device->bus->endpoint_array); + if (!ep_ref[ep].urb) { goto err; } - }else{ + } else { ep_ref[ep].urb->actual_length = 0; } - switch(direction){ - case USB_DIR_IN: - epi->tx_urb = ep_ref[ep].urb; - break; - case USB_DIR_OUT: - epi->rcv_urb = ep_ref[ep].urb; - break; - default: - goto err; + switch (direction) { + case USB_DIR_IN: + epi->tx_urb = ep_ref[ep].urb; + break; + case USB_DIR_OUT: + epi->rcv_urb = ep_ref[ep].urb; + break; + default: + goto err; } return 0; -err: + err: udc_state = STATE_ERROR; return -1; } @@ -377,83 +374,84 @@ err: * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram * Isochronous endpoints aren't yet supported! */ -void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, - struct usb_endpoint_instance *epi) +void udc_setup_ep (struct usb_device_instance *device, unsigned int ep, + struct usb_endpoint_instance *epi) { uchar direction = 0; int ep_attrib = 0; - if(epi && (ep < MAX_ENDPOINTS)){ - - if(ep == 0){ - if (epi->rcv_attributes!=USB_ENDPOINT_XFER_CONTROL - ||epi->tx_attributes!= - USB_ENDPOINT_XFER_CONTROL){ + if (epi && (ep < MAX_ENDPOINTS)) { - /* ep0 must be a control endpoint*/ + if (ep == 0) { + if (epi->rcv_attributes != USB_ENDPOINT_XFER_CONTROL + || epi->tx_attributes != + USB_ENDPOINT_XFER_CONTROL) { + + /* ep0 must be a control endpoint */ udc_state = STATE_ERROR; return; } - if(!(ep_ref[ep].sc & EP_ATTACHED)){ - mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize, - epi->rcv_packetSize); + if (!(ep_ref[ep].sc & EP_ATTACHED)) { + mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize, + epi->rcv_packetSize); } usbp->usep[ep] = 0x0000; return; } - - if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) { + + if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN) { direction = 1; ep_attrib = epi->tx_attributes; epi->rcv_packetSize = 0; - ep_ref[ep].sc |= USB_DIR_IN; + ep_ref[ep].sc |= USB_DIR_IN; } else { - + direction = 0; ep_attrib = epi->rcv_attributes; - epi->tx_packetSize = 0; + epi->tx_packetSize = 0; ep_ref[ep].sc &= ~USB_DIR_IN; } - if(mpc8xx_udc_assign_urb(ep, epi->endpoint_address - &USB_ENDPOINT_DIR_MASK)){ + if (mpc8xx_udc_assign_urb (ep, epi->endpoint_address + & USB_ENDPOINT_DIR_MASK)) { return; } - switch(ep_attrib){ - case USB_ENDPOINT_XFER_CONTROL: - if(!(ep_ref[ep].sc & EP_ATTACHED)){ + switch (ep_attrib) { + case USB_ENDPOINT_XFER_CONTROL: + if (!(ep_ref[ep].sc & EP_ATTACHED)) { + mpc8xx_udc_cbd_attach (ep, + epi->tx_packetSize, + epi->rcv_packetSize); + } + usbp->usep[ep] = ep << 12; + epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb; + + break; + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + if (!(ep_ref[ep].sc & EP_ATTACHED)) { + if (direction) { mpc8xx_udc_cbd_attach (ep, - epi->tx_packetSize, - epi->rcv_packetSize); + epi->tx_packetSize, + 0); + } else { + mpc8xx_udc_cbd_attach (ep, + 0, + epi->rcv_packetSize); } - usbp->usep[ep] = ep<<12; - epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb; + } + usbp->usep[ep] = (ep << 12) | ((ep_attrib) << 8); - break; - case USB_ENDPOINT_XFER_BULK : - case USB_ENDPOINT_XFER_INT: - if(!(ep_ref[ep].sc & EP_ATTACHED)){ - if(direction){ - mpc8xx_udc_cbd_attach (ep, - epi->tx_packetSize, 0); - }else{ - mpc8xx_udc_cbd_attach (ep, - 0, epi->rcv_packetSize); - } - } - usbp->usep[ep]= (ep<<12)|((ep_attrib)<<8); - - break; - case USB_ENDPOINT_XFER_ISOC: - default: - serial_printf("Error endpoint attrib %d>3\n", - ep_attrib); - udc_state = STATE_ERROR; - break; + break; + case USB_ENDPOINT_XFER_ISOC: + default: + serial_printf ("Error endpoint attrib %d>3\n", ep_attrib); + udc_state = STATE_ERROR; + break; } } @@ -463,54 +461,53 @@ void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, * * Move state, switch on the USB */ -void udc_connect(void) +void udc_connect (void) { - /* Enable pull-up resistor on D+ + /* Enable pull-up resistor on D+ * TODO: fit a pull-up resistor to drive SE0 for > 2.5us */ - - if(udc_state!=STATE_ERROR){ + + if (udc_state != STATE_ERROR) { udc_state = STATE_READY; - usbp->usmod|= USMOD_EN; + usbp->usmod |= USMOD_EN; } -} +} /* udc_disconnect * * Disconnect is not used but, is included for completeness */ -void udc_disconnect(void) +void udc_disconnect (void) { /* Disable pull-up resistor on D- * TODO: fix a pullup resistor to control this */ - if(udc_state!=STATE_ERROR){ + if (udc_state != STATE_ERROR) { udc_state = STATE_NOT_READY; } - usbp->usmod&=~USMOD_EN; + usbp->usmod &= ~USMOD_EN; } /* udc_enable - * + * * Grab an EP0 URB, register interest in a subset of USB events */ -void udc_enable(struct usb_device_instance *device) +void udc_enable (struct usb_device_instance *device) { - if(udc_state == STATE_ERROR){ + if (udc_state == STATE_ERROR) { return; } udc_device = device; - - if(!ep_ref[0].urb){ - ep_ref[0].urb = usbd_alloc_urb(device, - device->bus->endpoint_array); + + if (!ep_ref[0].urb) { + ep_ref[0].urb = usbd_alloc_urb (device, device->bus->endpoint_array); } /* Register interest in all events except SOF, enable transceiver */ - usbp->usber= 0x03FF; - usbp->usbmr= 0x02F7; + usbp->usber = 0x03FF; + usbp->usbmr = 0x02F7; return; } @@ -519,26 +516,26 @@ void udc_enable(struct usb_device_instance *device) * * disable the currently hooked device */ -void udc_disable(void) +void udc_disable (void) { int i = 0; - if(udc_state == STATE_ERROR){ - DBG("Won't disable UDC. udc_state==STATE_ERROR !\n"); + if (udc_state == STATE_ERROR) { + DBG ("Won't disable UDC. udc_state==STATE_ERROR !\n"); return; } udc_device = 0; - for(;iusbmr= 0x00; - usbp->usmod= ~USMOD_EN; + + usbp->usbmr = 0x00; + usbp->usmod = ~USMOD_EN; udc_state = STATE_NOT_READY; } @@ -546,46 +543,46 @@ void udc_disable(void) * * Enable the specified device */ -void udc_startup_events(struct usb_device_instance *device) +void udc_startup_events (struct usb_device_instance *device) { - udc_enable(device); - if(udc_state == STATE_READY){ + udc_enable (device); + if (udc_state == STATE_READY) { usbd_device_event_irq (device, DEVICE_CREATE, 0); } } /* udc_set_nak - * + * * Allow upper layers to signal lower layers should not accept more RX data * */ -void udc_set_nak(int epid) +void udc_set_nak (int epid) { - if(epid){ - mpc8xx_udc_set_nak(epid); + if (epid) { + mpc8xx_udc_set_nak (epid); } } -/* udc_unset_nak - * +/* udc_unset_nak + * * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint. * Switch off NAKing on this endpoint to accept more data output from host. * */ void udc_unset_nak (int epid) { - if(epid > MAX_ENDPOINTS){ + if (epid > MAX_ENDPOINTS) { return; } - if(usbp->usep[epid]&(USEP_THS_NAK | USEP_RHS_NAK)){ - usbp->usep[epid]&= ~(USEP_THS_NAK | USEP_RHS_NAK); + if (usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK)) { + usbp->usep[epid] &= ~(USEP_THS_NAK | USEP_RHS_NAK); __asm__ ("eieio"); } } /****************************************************************************** - Static Linkage + Static Linkage ******************************************************************************/ /* udc_state_transition_up @@ -633,10 +630,10 @@ void udc_unset_nak (int epid) * state, then no state transitions will take place. * */ - + static void mpc8xx_udc_state_transition_up (usb_device_state_t initial, - usb_device_state_t final) -{ + usb_device_state_t final) +{ if (initial < final) { switch (initial) { case STATE_ATTACHED: @@ -665,13 +662,13 @@ static void mpc8xx_udc_state_transition_up (usb_device_state_t initial, } static void mpc8xx_udc_state_transition_down (usb_device_state_t initial, - usb_device_state_t final) + usb_device_state_t final) { if (initial > final) { switch (initial) { case STATE_CONFIGURED: - usbd_device_event_irq (udc_device, - DEVICE_DE_CONFIGURED, 0); + usbd_device_event_irq (udc_device, + DEVICE_DE_CONFIGURED, 0); if (final == STATE_ADDRESSED) break; case STATE_ADDRESSED: @@ -679,13 +676,13 @@ static void mpc8xx_udc_state_transition_down (usb_device_state_t initial, if (final == STATE_DEFAULT) break; case STATE_DEFAULT: - usbd_device_event_irq (udc_device, - DEVICE_POWER_INTERRUPTION, 0); + usbd_device_event_irq (udc_device, + DEVICE_POWER_INTERRUPTION, 0); if (final == STATE_POWERED) break; case STATE_POWERED: usbd_device_event_irq (udc_device, DEVICE_HUB_RESET, - 0); + 0); case STATE_ATTACHED: break; default: @@ -708,7 +705,7 @@ static void mpc8xx_udc_stall (unsigned int ep) * * Force returning of NAK responses for the given endpoint as a kind of very * simple flow control - */ + */ static void mpc8xx_udc_set_nak (unsigned int ep) { usbp->usep[ep] |= NAK_BITMASK; @@ -720,27 +717,26 @@ static void mpc8xx_udc_set_nak (unsigned int ep) * Handle errors relevant to TX. Return a status code to allow calling * indicative of what if anything happened */ -static short mpc8xx_udc_handle_txerr() +static short mpc8xx_udc_handle_txerr () { short ep = 0, ret = 0; - - for(; epusber&(0x10<usber & (0x10 << ep)) { + /* Timeout or underrun */ - if(tx_cbd[ep]->cbd_sc&0x06){ + if (tx_cbd[ep]->cbd_sc & 0x06) { ret = 1; - mpc8xx_udc_flush_tx_fifo(ep); + mpc8xx_udc_flush_tx_fifo (ep); - }else{ - if(usbp->usep[ep]&STALL_BITMASK){ - if(!ep){ - usbp->usep[ep]&= - ~STALL_BITMASK; + } else { + if (usbp->usep[ep] & STALL_BITMASK) { + if (!ep) { + usbp->usep[ep] &= ~STALL_BITMASK; } - }/* else NAK */ + } /* else NAK */ } - usbp->usber|=(0x10<usber |= (0x10 << ep); } } return ret; @@ -750,13 +746,12 @@ static short mpc8xx_udc_handle_txerr() * * Advance cbd rx */ -static void mpc8xx_udc_advance_rx(volatile cbd_t ** rx_cbdp, int epid) +static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid) { - if((*rx_cbdp)->cbd_sc & RX_BD_W){ - *rx_cbdp = (volatile cbd_t*) - (endpoints[epid]->rbase + CFG_IMMR); - - }else{ + if ((*rx_cbdp)->cbd_sc & RX_BD_W) { + *rx_cbdp = (volatile cbd_t *) (endpoints[epid]->rbase + CFG_IMMR); + + } else { (*rx_cbdp)++; } } @@ -766,34 +761,34 @@ static void mpc8xx_udc_advance_rx(volatile cbd_t ** rx_cbdp, int epid) * * Flush a given TX fifo. Assumes one tx cbd per endpoint */ -static void mpc8xx_udc_flush_tx_fifo(int epid) -{ - volatile cbd_t * tx_cbdp = 0; +static void mpc8xx_udc_flush_tx_fifo (int epid) +{ + volatile cbd_t *tx_cbdp = 0; - if(epid > MAX_ENDPOINTS){ + if (epid > MAX_ENDPOINTS) { return; } /* TX stop */ - immr->im_cpm.cp_cpcr = ((epid<<2) | 0x1D01); + immr->im_cpm.cp_cpcr = ((epid << 2) | 0x1D01); __asm__ ("eieio"); - while(immr->im_cpm.cp_cpcr & 0x01); - + while (immr->im_cpm.cp_cpcr & 0x01); + usbp->uscom = 0x40 | 0; - + /* reset ring */ - tx_cbdp = (cbd_t*)(endpoints[epid]->tbptr + CFG_IMMR); + tx_cbdp = (cbd_t *) (endpoints[epid]->tbptr + CFG_IMMR); tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W); - + endpoints[epid]->tptr = endpoints[epid]->tbase; - endpoints[epid]->tstate = 0x00; - endpoints[epid]->tbcnt = 0x00; + endpoints[epid]->tstate = 0x00; + endpoints[epid]->tbcnt = 0x00; /* TX start */ - immr->im_cpm.cp_cpcr = ((epid<<2) | 0x2D01); + immr->im_cpm.cp_cpcr = ((epid << 2) | 0x2D01); __asm__ ("eieio"); - while(immr->im_cpm.cp_cpcr & 0x01); + while (immr->im_cpm.cp_cpcr & 0x01); return; } @@ -807,28 +802,29 @@ static void mpc8xx_udc_flush_tx_fifo(int epid) * we have accepted data but, the CPM found it had no-where to put that data * which needless to say would be a bad thing. */ -static void mpc8xx_udc_flush_rx_fifo() +static void mpc8xx_udc_flush_rx_fifo () { int i = 0; - for(i = 0;icbd_sc&RX_BD_E)){ - ERR("buf %p used rx data len = 0x%x sc=0x%x!\n", - rx_cbd[i], rx_cbd[i]->cbd_datlen, - rx_cbd[i]->cbd_sc); + + for (i = 0; i < RX_RING_SIZE; i++) { + if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) { + ERR ("buf %p used rx data len = 0x%x sc=0x%x!\n", + rx_cbd[i], rx_cbd[i]->cbd_datlen, + rx_cbd[i]->cbd_sc); } } - ERR("BUG : Input over-run\n"); + ERR ("BUG : Input over-run\n"); } /* mpc8xx_udc_clear_rxbd - * + * * Release control of RX CBD to CP. */ -static void mpc8xx_udc_clear_rxbd(volatile cbd_t * rx_cbdp) +static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp) { rx_cbdp->cbd_datlen = 0x0000; - rx_cbdp->cbd_sc= ((rx_cbdp->cbd_sc & RX_BD_W)|(RX_BD_E | RX_BD_I)); + rx_cbdp->cbd_sc = ((rx_cbdp->cbd_sc & RX_BD_W) | (RX_BD_E | RX_BD_I)); __asm__ ("eieio"); } @@ -837,27 +833,27 @@ static void mpc8xx_udc_clear_rxbd(volatile cbd_t * rx_cbdp) * Parse for tx timeout, control RX or USB reset/busy conditions * Return -1 on timeout, -2 on fatal error, else return zero */ -static int mpc8xx_udc_tx_irq(int ep) +static int mpc8xx_udc_tx_irq (int ep) { int i = 0; - if(usbp->usber&(USB_TX_ERRMASK)){ - if(mpc8xx_udc_handle_txerr()){ + if (usbp->usber & (USB_TX_ERRMASK)) { + if (mpc8xx_udc_handle_txerr ()) { /* Timeout, controlling function must retry send */ return -1; } } - if(usbp->usber & (USB_E_RESET|USB_E_BSY)){ + if (usbp->usber & (USB_E_RESET | USB_E_BSY)) { /* Fatal, abandon TX transaction */ return -2; } - - if(usbp->usber & USB_E_RXB){ - for(i = 0;icbd_sc&RX_BD_E)){ - if((rx_cbd[i] == ep_ref[0].prx) || ep){ - return -2; + + if (usbp->usber & USB_E_RXB) { + for (i = 0; i < RX_RING_SIZE; i++) { + if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) { + if ((rx_cbd[i] == ep_ref[0].prx) || ep) { + return -2; } } } @@ -875,106 +871,106 @@ static int mpc8xx_udc_tx_irq(int ep) * devices to give up TX, however tx_retry stops us getting stuck in an endless * TX loop. */ -static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi) +static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi) { struct urb *urb = epi->tx_urb; - volatile cbd_t * tx_cbdp = 0; + volatile cbd_t *tx_cbdp = 0; unsigned int ep = 0, pkt_len = 0, x = 0, tx_retry = 0; int ret = 0; - - if(!epi || (epi->endpoint_address&0x03)>=MAX_ENDPOINTS || !urb){ + + if (!epi || (epi->endpoint_address & 0x03) >= MAX_ENDPOINTS || !urb) { return -1; } ep = epi->endpoint_address & 0x03; - tx_cbdp = (cbd_t*)(endpoints[ep]->tbptr + CFG_IMMR); - - if(tx_cbdp->cbd_sc&TX_BD_R || usbp->usber&USB_E_TXB){ - mpc8xx_udc_flush_tx_fifo(ep); + tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CFG_IMMR); + + if (tx_cbdp->cbd_sc & TX_BD_R || usbp->usber & USB_E_TXB) { + mpc8xx_udc_flush_tx_fifo (ep); usbp->usber |= USB_E_TXB; }; - while(tx_retry++ < 100){ - ret = mpc8xx_udc_tx_irq(ep); - if(ret == -1){ + while (tx_retry++ < 100) { + ret = mpc8xx_udc_tx_irq (ep); + if (ret == -1) { /* ignore timeout here */ - }else if(ret == -2){ + } else if (ret == -2) { /* Abandon TX */ - mpc8xx_udc_flush_tx_fifo(ep); + mpc8xx_udc_flush_tx_fifo (ep); return -1; - } + } + + tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CFG_IMMR); + while (tx_cbdp->cbd_sc & TX_BD_R) { + }; + tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc & TX_BD_W); - tx_cbdp = (cbd_t*)(endpoints[ep]->tbptr + CFG_IMMR); - while(tx_cbdp->cbd_sc&TX_BD_R){}; - tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc&TX_BD_W); - pkt_len = urb->actual_length - epi->sent; - if(pkt_len> epi->tx_packetSize || pkt_len > EP_MAX_PKT){ - pkt_len = MIN(epi->tx_packetSize, EP_MAX_PKT); + if (pkt_len > epi->tx_packetSize || pkt_len > EP_MAX_PKT) { + pkt_len = MIN (epi->tx_packetSize, EP_MAX_PKT); } - for(x=0; xcbd_bufaddr+x)) = + for (x = 0; x < pkt_len; x++) { + *((unsigned char *) (tx_cbdp->cbd_bufaddr + x)) = urb->buffer[epi->sent + x]; } tx_cbdp->cbd_datlen = pkt_len; - tx_cbdp->cbd_sc|=(CBD_TX_BITMASK | ep_ref[ep].pid); + tx_cbdp->cbd_sc |= (CBD_TX_BITMASK | ep_ref[ep].pid); __asm__ ("eieio"); - #ifdef __SIMULATE_ERROR__ - if(++err_poison_test == 2){ - err_poison_test = 0; - tx_cbdp->cbd_sc&=~TX_BD_TC; - } - #endif +#ifdef __SIMULATE_ERROR__ + if (++err_poison_test == 2) { + err_poison_test = 0; + tx_cbdp->cbd_sc &= ~TX_BD_TC; + } +#endif - usbp->uscom = (USCOM_STR | ep); + usbp->uscom = (USCOM_STR | ep); - while(!(usbp->usber&USB_E_TXB)){ - ret = mpc8xx_udc_tx_irq(ep); - if(ret == -1){ + while (!(usbp->usber & USB_E_TXB)) { + ret = mpc8xx_udc_tx_irq (ep); + if (ret == -1) { /* TX timeout */ break; - }else if(ret == -2){ - if(usbp->usber & USB_E_TXB){ - usbp->usber|=USB_E_TXB; + } else if (ret == -2) { + if (usbp->usber & USB_E_TXB) { + usbp->usber |= USB_E_TXB; } - mpc8xx_udc_flush_tx_fifo(ep); + mpc8xx_udc_flush_tx_fifo (ep); return -1; } }; - if(usbp->usber & USB_E_TXB){ - usbp->usber|=USB_E_TXB; + if (usbp->usber & USB_E_TXB) { + usbp->usber |= USB_E_TXB; } /* ACK must be present <= 18bit times from TX */ - if(ret == -1){ + if (ret == -1) { continue; } - + /* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */ epi->sent += pkt_len; - epi->last = MIN (urb->actual_length - epi->sent, - epi->tx_packetSize); - TOGGLE_TX_PID(ep_ref[ep].pid); + epi->last = MIN (urb->actual_length - epi->sent, epi->tx_packetSize); + TOGGLE_TX_PID (ep_ref[ep].pid); + + if (epi->sent >= epi->tx_urb->actual_length) { - if(epi->sent >= epi->tx_urb->actual_length){ - epi->tx_urb->actual_length = 0; epi->sent = 0; - - if(ep_ref[ep].sc & EP_SEND_ZLP){ + + if (ep_ref[ep].sc & EP_SEND_ZLP) { ep_ref[ep].sc &= ~EP_SEND_ZLP; - }else{ + } else { return 0; } } } - - ERR("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n",ep, epi->sent, - epi->tx_urb->actual_length); + + ERR ("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n", ep, epi->sent, + epi->tx_urb->actual_length); return -1; } @@ -983,126 +979,117 @@ static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi) * * Dump a control request to console */ -static void mpc8xx_udc_dump_request(struct usb_device_request *request) +static void mpc8xx_udc_dump_request (struct usb_device_request *request) { - DBG( - "bmRequestType:%02x bRequest:%02x wValue:%04x " - "wIndex:%04x wLength:%04x ?\n", - request->bmRequestType, - request->bRequest, - request->wValue, - request->wIndex, - request->wLength); + DBG ("bmRequestType:%02x bRequest:%02x wValue:%04x " + "wIndex:%04x wLength:%04x ?\n", + request->bmRequestType, + request->bRequest, + request->wValue, request->wIndex, request->wLength); return; } -/* mpc8xx_udc_ep0_rx_setup - * +/* mpc8xx_udc_ep0_rx_setup + * * Decode received ep0 SETUP packet. return non-zero on error */ static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp) { unsigned int x = 0; - struct urb * purb = ep_ref[0].urb; - struct usb_endpoint_instance *epi = + struct urb *purb = ep_ref[0].urb; + struct usb_endpoint_instance *epi = &udc_device->bus->endpoint_array[0]; - for(; xcbd_datlen; x++){ - *(((unsigned char*)&ep_ref[0].urb->device_request)+x) = - *((unsigned char*)(rx_cbdp->cbd_bufaddr+x)); + for (; x < rx_cbdp->cbd_datlen; x++) { + *(((unsigned char *) &ep_ref[0].urb->device_request) + x) = + *((unsigned char *) (rx_cbdp->cbd_bufaddr + x)); } - - mpc8xx_udc_clear_rxbd(rx_cbdp); - if (ep0_recv_setup(purb)) { - mpc8xx_udc_dump_request(&purb->device_request); + mpc8xx_udc_clear_rxbd (rx_cbdp); + + if (ep0_recv_setup (purb)) { + mpc8xx_udc_dump_request (&purb->device_request); return -1; } - if ((purb->device_request.bmRequestType&USB_REQ_DIRECTION_MASK) + if ((purb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { - switch (purb->device_request.bRequest){ - case USB_REQ_SET_ADDRESS: - /* Send the Status OUT ZLP */ - ep_ref[0].pid = TX_BD_PID_DATA1; - purb->actual_length = 0; - mpc8xx_udc_init_tx(epi,purb); - mpc8xx_udc_ep_tx(epi); - - /* Move to the addressed state */ - usbp->usaddr = udc_device->address; - mpc8xx_udc_state_transition_up(udc_device->device_state, - STATE_ADDRESSED); - return 0; - - case USB_REQ_SET_CONFIGURATION: - if(!purb->device_request.wValue){ - - /* Respond at default address */ - usbp->usaddr = 0x00; - mpc8xx_udc_state_transition_down(udc_device->device_state, - STATE_ADDRESSED); - - } else { - - /* TODO: Support multiple configurations */ - mpc8xx_udc_state_transition_up(udc_device->device_state,STATE_CONFIGURED); - for(x=1; xbus->endpoint_array[x].endpoint_address&USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN){ - ep_ref[x].pid = TX_BD_PID_DATA0; - }else{ - ep_ref[x].pid = RX_BD_PID_DATA0; - } - /* Set configuration must unstall endpoints */ - usbp->usep[x]&=~STALL_BITMASK; + switch (purb->device_request.bRequest) { + case USB_REQ_SET_ADDRESS: + /* Send the Status OUT ZLP */ + ep_ref[0].pid = TX_BD_PID_DATA1; + purb->actual_length = 0; + mpc8xx_udc_init_tx (epi, purb); + mpc8xx_udc_ep_tx (epi); + + /* Move to the addressed state */ + usbp->usaddr = udc_device->address; + mpc8xx_udc_state_transition_up (udc_device->device_state, + STATE_ADDRESSED); + return 0; + + case USB_REQ_SET_CONFIGURATION: + if (!purb->device_request.wValue) { + /* Respond at default address */ + usbp->usaddr = 0x00; + mpc8xx_udc_state_transition_down (udc_device->device_state, + STATE_ADDRESSED); + } else { + /* TODO: Support multiple configurations */ + mpc8xx_udc_state_transition_up (udc_device->device_state, + STATE_CONFIGURED); + for (x = 1; x < MAX_ENDPOINTS; x++) { + if ((udc_device->bus->endpoint_array[x].endpoint_address & USB_ENDPOINT_DIR_MASK) + == USB_DIR_IN) { + ep_ref[x].pid = TX_BD_PID_DATA0; + } else { + ep_ref[x].pid = RX_BD_PID_DATA0; } - + /* Set configuration must unstall endpoints */ + usbp->usep[x] &= ~STALL_BITMASK; } - break; - default: - /* CDC/Vendor specific */ - break; + } + break; + default: + /* CDC/Vendor specific */ + break; } /* Send ZLP as ACK in Status OUT phase */ ep_ref[0].pid = TX_BD_PID_DATA1; purb->actual_length = 0; - mpc8xx_udc_init_tx(epi,purb); - mpc8xx_udc_ep_tx(epi); + mpc8xx_udc_init_tx (epi, purb); + mpc8xx_udc_ep_tx (epi); - }else{ - if(purb->actual_length){ + } else { + + if (purb->actual_length) { ep_ref[0].pid = TX_BD_PID_DATA1; - mpc8xx_udc_init_tx(epi,purb); + mpc8xx_udc_init_tx (epi, purb); - if(!(purb->actual_length%EP0_MAX_PACKET_SIZE)){ + if (!(purb->actual_length % EP0_MAX_PACKET_SIZE)) { ep_ref[0].sc |= EP_SEND_ZLP; } - if(purb->device_request.wValue== - USB_DESCRIPTOR_TYPE_DEVICE){ - if(le16_to_cpu(purb->device_request.wLength)> - purb->actual_length){ + if (purb->device_request.wValue == + USB_DESCRIPTOR_TYPE_DEVICE) { + if (le16_to_cpu (purb->device_request.wLength) + > purb->actual_length) { /* Send EP0_MAX_PACKET_SIZE bytes * unless correct size requested. */ - if(purb->actual_length > - epi->tx_packetSize){ - - purb->actual_length = - epi->tx_packetSize; + if (purb->actual_length > epi->tx_packetSize) { + purb->actual_length = epi->tx_packetSize; } - } } - mpc8xx_udc_ep_tx(epi); + mpc8xx_udc_ep_tx (epi); - }else{ + } else { /* Corrupt SETUP packet? */ - ERR("Zero length data or SETUP with DATA-IN phase ?\n"); + ERR ("Zero length data or SETUP with DATA-IN phase ?\n"); return 1; } } @@ -1113,8 +1100,8 @@ static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp) * * Setup some basic parameters for a TX transaction */ -static void mpc8xx_udc_init_tx(struct usb_endpoint_instance *epi, - struct urb * tx_urb) +static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi, + struct urb *tx_urb) { epi->sent = 0; epi->last = 0; @@ -1125,24 +1112,24 @@ static void mpc8xx_udc_init_tx(struct usb_endpoint_instance *epi, * * Receive ep0/control USB data. Parse and possibly send a response. */ -static void mpc8xx_udc_ep0_rx(volatile cbd_t * rx_cbdp) +static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp) { - if(rx_cbdp->cbd_sc&RX_BD_PID_SETUP){ - + if (rx_cbdp->cbd_sc & RX_BD_PID_SETUP) { + /* Unconditionally accept SETUP packets */ - if(mpc8xx_udc_ep0_rx_setup(rx_cbdp)){ - mpc8xx_udc_stall (0); + if (mpc8xx_udc_ep0_rx_setup (rx_cbdp)) { + mpc8xx_udc_stall (0); } - + } else { - - mpc8xx_udc_clear_rxbd(rx_cbdp); - - if((rx_cbdp->cbd_datlen-2)){ + + mpc8xx_udc_clear_rxbd (rx_cbdp); + + if ((rx_cbdp->cbd_datlen - 2)) { /* SETUP with a DATA phase - * outside of SETUP packet. - * Reply with STALL. - */ + * outside of SETUP packet. + * Reply with STALL. + */ mpc8xx_udc_stall (0); } } @@ -1151,7 +1138,7 @@ static void mpc8xx_udc_ep0_rx(volatile cbd_t * rx_cbdp) /* mpc8xx_udc_epn_rx * * Receive some data from cbd into USB system urb data abstraction - * Upper layers should NAK if there is insufficient RX data space + * Upper layers should NAK if there is insufficient RX data space */ static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp) { @@ -1159,115 +1146,115 @@ static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp) struct urb *urb = 0; unsigned int x = 0; - if(epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen){ + if (epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen) { return 0; } - - /* USB 2.0 PDF section 8.6.4 + + /* USB 2.0 PDF section 8.6.4 * Discard data with invalid PID it is a resend. */ - if(ep_ref[epid].pid!=(rx_cbdp->cbd_sc&0xC0)){ + if (ep_ref[epid].pid != (rx_cbdp->cbd_sc & 0xC0)) { return 1; } - TOGGLE_RX_PID(ep_ref[epid].pid); - + TOGGLE_RX_PID (ep_ref[epid].pid); + epi = &udc_device->bus->endpoint_array[epid]; urb = epi->rcv_urb; - for(; x<(rx_cbdp->cbd_datlen-2); x++){ - *((unsigned char*)(urb->buffer + urb->actual_length +x)) = - *((unsigned char*)(rx_cbdp->cbd_bufaddr+x)); + for (; x < (rx_cbdp->cbd_datlen - 2); x++) { + *((unsigned char *) (urb->buffer + urb->actual_length + x)) = + *((unsigned char *) (rx_cbdp->cbd_bufaddr + x)); } - if(x){ + if (x) { usbd_rcv_complete (epi, x, 0); - if(ep_ref[epid].urb->status == RECV_ERROR){ - DBG("RX error unset NAK\n"); - udc_unset_nak(epid); + if (ep_ref[epid].urb->status == RECV_ERROR) { + DBG ("RX error unset NAK\n"); + udc_unset_nak (epid); } - } + } return x; } /* mpc8xx_udc_clock_init * - * Obtain a clock reference for Full Speed Signaling + * Obtain a clock reference for Full Speed Signaling */ -static void mpc8xx_udc_clock_init (volatile immap_t * immr, - volatile cpm8xx_t * cp) +static void mpc8xx_udc_clock_init (volatile immap_t * immr, + volatile cpm8xx_t * cp) { #if defined(CFG_USB_EXTC_CLK) /* This has been tested with a 48MHz crystal on CLK6 */ - switch(CFG_USB_EXTC_CLK){ - case 1: - immr->im_ioport.iop_papar|= 0x0100; - immr->im_ioport.iop_padir&= ~0x0100; - cp->cp_sicr|= 0x24; - break; - case 2: - immr->im_ioport.iop_papar|= 0x0200; - immr->im_ioport.iop_padir&= ~0x0200; - cp->cp_sicr|= 0x2D; - break; - case 3: - immr->im_ioport.iop_papar|= 0x0400; - immr->im_ioport.iop_padir&= ~0x0400; - cp->cp_sicr|= 0x36; - break; - case 4: - immr->im_ioport.iop_papar|= 0x0800; - immr->im_ioport.iop_padir&= ~0x0800; - cp->cp_sicr|= 0x3F; - break; - default: - udc_state = STATE_ERROR; - break; + switch (CFG_USB_EXTC_CLK) { + case 1: + immr->im_ioport.iop_papar |= 0x0100; + immr->im_ioport.iop_padir &= ~0x0100; + cp->cp_sicr |= 0x24; + break; + case 2: + immr->im_ioport.iop_papar |= 0x0200; + immr->im_ioport.iop_padir &= ~0x0200; + cp->cp_sicr |= 0x2D; + break; + case 3: + immr->im_ioport.iop_papar |= 0x0400; + immr->im_ioport.iop_padir &= ~0x0400; + cp->cp_sicr |= 0x36; + break; + case 4: + immr->im_ioport.iop_papar |= 0x0800; + immr->im_ioport.iop_padir &= ~0x0800; + cp->cp_sicr |= 0x3F; + break; + default: + udc_state = STATE_ERROR; + break; } #elif defined(CFG_USB_BRGCLK) - /* This has been tested with brgclk == 50MHz */ + /* This has been tested with brgclk == 50MHz */ DECLARE_GLOBAL_DATA_PTR; int divisor = 0; - if(gd->cpu_clk<48000000L){ - ERR("brgclk is too slow for full-speed USB!\n"); + if (gd->cpu_clk < 48000000L) { + ERR ("brgclk is too slow for full-speed USB!\n"); udc_state = STATE_ERROR; return; } /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48Mhz) * but, can /probably/ live with close-ish alternative rates. - */ - divisor = (gd->cpu_clk/48000000L)-1; + */ + divisor = (gd->cpu_clk / 48000000L) - 1; cp->cp_sicr &= ~0x0000003F; - - switch(CFG_USB_BRGCLK){ - case 1: - cp->cp_brgc1 |= (divisor|CPM_BRG_EN); - cp->cp_sicr &= ~0x2F; - break; - case 2: - cp->cp_brgc2 |= (divisor|CPM_BRG_EN); - cp->cp_sicr |= 0x00000009; - break; - case 3: - cp->cp_brgc3 |= (divisor|CPM_BRG_EN); - cp->cp_sicr |= 0x00000012; - break; - case 4: - cp->cp_brgc4 = (divisor|CPM_BRG_EN); - cp->cp_sicr |= 0x0000001B; - break; - default: - udc_state = STATE_ERROR; - break; + + switch (CFG_USB_BRGCLK) { + case 1: + cp->cp_brgc1 |= (divisor | CPM_BRG_EN); + cp->cp_sicr &= ~0x2F; + break; + case 2: + cp->cp_brgc2 |= (divisor | CPM_BRG_EN); + cp->cp_sicr |= 0x00000009; + break; + case 3: + cp->cp_brgc3 |= (divisor | CPM_BRG_EN); + cp->cp_sicr |= 0x00000012; + break; + case 4: + cp->cp_brgc4 = (divisor | CPM_BRG_EN); + cp->cp_sicr |= 0x0000001B; + break; + default: + udc_state = STATE_ERROR; + break; } #else - #error "CFG_USB_EXTC_CLK or CFG_USB_BRGCLK must be defined" +#error "CFG_USB_EXTC_CLK or CFG_USB_BRGCLK must be defined" #endif } @@ -1278,51 +1265,51 @@ static void mpc8xx_udc_clock_init (volatile immap_t * immr, */ static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size) { - - if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS){ + + if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS) { udc_state = STATE_ERROR; return; } - if (tx_size>USB_MAX_PKT || rx_size>USB_MAX_PKT || - (!tx_size && !rx_size)){ + if (tx_size > USB_MAX_PKT || rx_size > USB_MAX_PKT || + (!tx_size && !rx_size)) { udc_state = STATE_ERROR; return; } /* Attach CBD to appropiate Parameter RAM Endpoint data structure */ - if(rx_size){ - endpoints[ep]->rbase = (u32)rx_cbd[rx_ct]; - endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct]; + if (rx_size) { + endpoints[ep]->rbase = (u32) rx_cbd[rx_ct]; + endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; rx_ct++; - if(!ep){ - - endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct]; + if (!ep) { + + endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; rx_ct++; - }else{ + } else { rx_ct += 2; - endpoints[ep]->rbptr = (u32)rx_cbd[rx_ct]; + endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; rx_ct++; } /* Where we expect to RX data on this endpoint */ - ep_ref[ep].prx = rx_cbd[rx_ct-1]; - }else{ + ep_ref[ep].prx = rx_cbd[rx_ct - 1]; + } else { ep_ref[ep].prx = 0; endpoints[ep]->rbase = 0; endpoints[ep]->rbptr = 0; } - if(tx_size){ - endpoints[ep]->tbase = (u32)tx_cbd[tx_ct]; - endpoints[ep]->tbptr = (u32)tx_cbd[tx_ct]; + if (tx_size) { + endpoints[ep]->tbase = (u32) tx_cbd[tx_ct]; + endpoints[ep]->tbptr = (u32) tx_cbd[tx_ct]; tx_ct++; - }else{ + } else { endpoints[ep]->tbase = 0; endpoints[ep]->tbptr = 0; } @@ -1330,13 +1317,14 @@ static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size) endpoints[ep]->tstate = 0; endpoints[ep]->tbcnt = 0; endpoints[ep]->mrblr = EP_MAX_PKT; - endpoints[ep]->rfcr = 0x18; + endpoints[ep]->rfcr = 0x18; endpoints[ep]->tfcr = 0x18; ep_ref[ep].sc |= EP_ATTACHED; - DBG("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n", - ep, endpoints[ep]->rbase, endpoints[ep]->rbptr, endpoints[ep]->tbase, - endpoints[ep]->tbptr, ep_ref[ep].prx); + DBG ("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n", + ep, endpoints[ep]->rbase, endpoints[ep]->rbptr, + endpoints[ep]->tbase, endpoints[ep]->tbptr, + ep_ref[ep].prx); return; } @@ -1349,28 +1337,28 @@ static void mpc8xx_udc_cbd_init (void) { int i = 0; - for(; icbd_bufaddr = + mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int)); - for(i=0; i< TX_RING_SIZE; i++){ - tx_cbd[i]->cbd_bufaddr = - mpc8xx_udc_alloc(EP_MAX_PKT, sizeof(int)); - - tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W); + tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W); tx_cbd[i]->cbd_datlen = 0x0000; } - for(i=0; i< RX_RING_SIZE; i++){ - rx_cbd[i]->cbd_bufaddr = - mpc8xx_udc_alloc(EP_MAX_PKT, sizeof(int)); + for (i = 0; i < RX_RING_SIZE; i++) { + rx_cbd[i]->cbd_bufaddr = + mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int)); rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E); rx_cbd[i]->cbd_datlen = 0x0000; @@ -1387,25 +1375,25 @@ static void mpc8xx_udc_endpoint_init (void) { int i = 0; - for(; i Entering device setup"); - + do { const int setup_pktsize = 8; unsigned char *datap = @@ -1518,7 +1518,7 @@ void udc_startup_events (struct usb_device_instance *device) } /** - * udc_irq - do pseudo interrupts + * udc_irq - do pseudo interrupts */ void udc_irq(void) { diff --git a/drivers/usbtty.c b/drivers/usbtty.c index ed96999..d41a00b 100644 --- a/drivers/usbtty.c +++ b/drivers/usbtty.c @@ -1,7 +1,7 @@ /* * (C) Copyright 2003 * Gerry Hamel, geh@ti.com, Texas Instruments - * + * * (C) Copyright 2006 * Bryan O'Donoghue, bodonoghue@codehermit.ie * @@ -31,7 +31,7 @@ #include "usb_cdc_acm.h" #include "usbdescriptors.h" #include /* If defined, override Linux identifiers with - * vendor specific ones */ + * vendor specific ones */ #if 0 #define TTYDBG(fmt,args...)\ @@ -142,10 +142,10 @@ static struct usb_device_descriptor device_descriptor = { struct acm_config_desc { struct usb_configuration_descriptor configuration_desc; - + /* Master Interface */ struct usb_interface_descriptor interface_desc; - + struct usb_class_header_function_descriptor usb_class_header; struct usb_class_call_management_descriptor usb_class_call_mgt; struct usb_class_abstract_control_descriptor usb_class_acm; @@ -154,22 +154,22 @@ struct acm_config_desc { /* Slave Interface */ struct usb_interface_descriptor data_class_interface; - struct usb_endpoint_descriptor + struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS-1] __attribute__((packed)); } __attribute__((packed)); static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = { { .configuration_desc ={ - .bLength = + .bLength = sizeof(struct usb_configuration_descriptor), .bDescriptorType = USB_DT_CONFIG, - .wTotalLength = + .wTotalLength = cpu_to_le16(sizeof(struct acm_config_desc)), .bNumInterfaces = NUM_ACM_INTERFACES, .bConfigurationValue = 1, .iConfiguration = STR_CONFIG, - .bmAttributes = + .bmAttributes = BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, .bMaxPower = USBTTY_MAXPOWER }, @@ -180,62 +180,62 @@ static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = { .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = 0x01, - .bInterfaceClass = + .bInterfaceClass = COMMUNICATIONS_INTERFACE_CLASS_CONTROL, .bInterfaceSubClass = COMMUNICATIONS_ACM_SUBCLASS, .bInterfaceProtocol = COMMUNICATIONS_V25TER_PROTOCOL, .iInterface = STR_CTRL_INTERFACE, }, .usb_class_header = { - .bFunctionLength = + .bFunctionLength = sizeof(struct usb_class_header_function_descriptor), - .bDescriptorType = CS_INTERFACE, + .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_ST_HEADER, .bcdCDC = cpu_to_le16(110), }, .usb_class_call_mgt = { - .bFunctionLength = + .bFunctionLength = sizeof(struct usb_class_call_management_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_ST_CMF, - .bmCapabilities = 0x00, - .bDataInterface = 0x01, + .bmCapabilities = 0x00, + .bDataInterface = 0x01, }, .usb_class_acm = { - .bFunctionLength = + .bFunctionLength = sizeof(struct usb_class_abstract_control_descriptor), .bDescriptorType = CS_INTERFACE, - .bDescriptorSubtype = USB_ST_ACMF, - .bmCapabilities = 0x00, + .bDescriptorSubtype = USB_ST_ACMF, + .bmCapabilities = 0x00, }, .usb_class_union = { - .bFunctionLength = + .bFunctionLength = sizeof(struct usb_class_union_function_descriptor), .bDescriptorType = CS_INTERFACE, .bDescriptorSubtype = USB_ST_UF, - .bMasterInterface = 0x00, - .bSlaveInterface0 = 0x01, + .bMasterInterface = 0x00, + .bSlaveInterface0 = 0x01, }, .notification_endpoint = { - .bLength = + .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x01 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize + .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), .bInterval = 0xFF, }, /* Interface 2 */ .data_class_interface = { - .bLength = + .bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0x01, .bAlternateSetting = 0x00, .bNumEndpoints = 0x02, - .bInterfaceClass = + .bInterfaceClass = COMMUNICATIONS_INTERFACE_CLASS_DATA, .bInterfaceSubClass = DATA_INTERFACE_SUBCLASS_NONE, .bInterfaceProtocol = DATA_INTERFACE_PROTOCOL_NONE, @@ -243,30 +243,30 @@ static struct acm_config_desc acm_configuration_descriptors[NUM_CONFIGS] = { }, .data_endpoints = { { - .bLength = + .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x02 | USB_DIR_OUT, - .bmAttributes = + .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = + .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), .bInterval = 0xFF, }, { - .bLength = + .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x03 | USB_DIR_IN, - .bmAttributes = + .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = + .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_BULK_PKTSIZE), .bInterval = 0xFF, }, }, }, -}; +}; static struct rs232_emu rs232_desc={ .dter = 115200, @@ -282,75 +282,75 @@ static struct rs232_emu rs232_desc={ struct gserial_config_desc { - + struct usb_configuration_descriptor configuration_desc; - struct usb_interface_descriptor + struct usb_interface_descriptor interface_desc[NUM_GSERIAL_INTERFACES] __attribute__((packed)); - struct usb_endpoint_descriptor + struct usb_endpoint_descriptor data_endpoints[NUM_ENDPOINTS] __attribute__((packed)); } __attribute__((packed)); -static struct gserial_config_desc +static struct gserial_config_desc gserial_configuration_descriptors[NUM_CONFIGS] ={ { .configuration_desc ={ .bLength = sizeof(struct usb_configuration_descriptor), .bDescriptorType = USB_DT_CONFIG, - .wTotalLength = + .wTotalLength = cpu_to_le16(sizeof(struct gserial_config_desc)), .bNumInterfaces = NUM_GSERIAL_INTERFACES, .bConfigurationValue = 1, .iConfiguration = STR_CONFIG, - .bmAttributes = + .bmAttributes = BMATTRIBUTE_SELF_POWERED|BMATTRIBUTE_RESERVED, .bMaxPower = USBTTY_MAXPOWER }, .interface_desc = { { - .bLength = + .bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = USB_DT_INTERFACE, .bInterfaceNumber = 0, .bAlternateSetting = 0, .bNumEndpoints = NUM_ENDPOINTS, - .bInterfaceClass = + .bInterfaceClass = COMMUNICATIONS_INTERFACE_CLASS_VENDOR, - .bInterfaceSubClass = + .bInterfaceSubClass = COMMUNICATIONS_NO_SUBCLASS, - .bInterfaceProtocol = + .bInterfaceProtocol = COMMUNICATIONS_NO_PROTOCOL, .iInterface = STR_DATA_INTERFACE }, }, .data_endpoints = { { - .bLength = + .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x01 | USB_DIR_OUT, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = + .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_OUT_PKTSIZE), .bInterval= 0xFF, }, { - .bLength = + .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x02 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = + .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_IN_PKTSIZE), .bInterval = 0xFF, }, { - .bLength = + .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = USB_DT_ENDPOINT, .bEndpointAddress = 0x03 | USB_DIR_IN, .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = + .wMaxPacketSize = cpu_to_le16(CONFIG_USBD_SERIAL_INT_PKTSIZE), .bInterval = 0xFF, }, @@ -368,7 +368,7 @@ static void usbtty_init_endpoints (void); static void usbtty_init_terminal_type(short type); static void usbtty_event_handler (struct usb_device_instance *device, usb_device_event_t event, int data); -static int usbtty_cdc_setup(struct usb_device_request *request, +static int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb); static int usbtty_configured (void); static int write_buffer (circbuf_t * buf); @@ -477,12 +477,12 @@ static void __usbtty_puts (const char *str, int len) /* Empty buffer here, if needed, to ensure space... */ if (space) { write_buffer (&usbtty_output); - + n = MIN (space, MIN (len, maxlen)); buf_push (&usbtty_output, str, n); str += n; - len -= n; + len -= n; } } } @@ -543,7 +543,7 @@ int drv_usbtty_init (void) tt = "generic"; } usbtty_init_terminal_type(strcmp(tt,"cdc_acm")); - + /* prepare buffers... */ buf_init (&usbtty_input, USBTTY_BUFFER_SIZE); buf_init (&usbtty_output, USBTTY_BUFFER_SIZE); @@ -579,7 +579,7 @@ static void usbtty_init_strings (void) { struct usb_string_descriptor *string; - usbtty_string_table[STR_LANG] = + usbtty_string_table[STR_LANG] = (struct usb_string_descriptor*)wstrLang; string = (struct usb_string_descriptor *) wstrManufacturer; @@ -624,7 +624,7 @@ static void usbtty_init_strings (void) /* Now, initialize the string table for ep0 handling */ usb_strings = usbtty_string_table; -} +} static void usbtty_init_instances (void) { @@ -690,7 +690,7 @@ static void usbtty_init_instances (void) endpoint_instance[i].rcv_packetSize = le16_to_cpu(ep_descriptor_ptrs[i - 1]->wMaxPacketSize); - + endpoint_instance[i].tx_attributes = ep_descriptor_ptrs[i - 1]->bmAttributes; @@ -721,30 +721,30 @@ static void usbtty_init_endpoints (void) int i; bus_instance->max_endpoints = NUM_ENDPOINTS + 1; - for (i = 1; i <= NUM_ENDPOINTS; i++) { + for (i = 1; i <= NUM_ENDPOINTS; i++) { udc_setup_ep (device_instance, i, &endpoint_instance[i]); } } /* usbtty_init_terminal_type - * + * * Do some late binding for our device type. */ static void usbtty_init_terminal_type(short type) { switch(type){ - /* CDC ACM */ + /* CDC ACM */ case 0: /* Assign endpoint descriptors */ - ep_descriptor_ptrs[0] = + ep_descriptor_ptrs[0] = &acm_configuration_descriptors[0].notification_endpoint; - ep_descriptor_ptrs[1] = + ep_descriptor_ptrs[1] = &acm_configuration_descriptors[0].data_endpoints[0]; - ep_descriptor_ptrs[2] = + ep_descriptor_ptrs[2] = &acm_configuration_descriptors[0].data_endpoints[1]; /* Enumerate Device Descriptor */ - device_descriptor.bDeviceClass = + device_descriptor.bDeviceClass = COMMUNICATIONS_DEVICE_CLASS; device_descriptor.idProduct = cpu_to_le16(CONFIG_USBD_PRODUCTID_CDCACM); @@ -752,7 +752,7 @@ static void usbtty_init_terminal_type(short type) /* Assign endpoint indices */ tx_endpoint = ACM_TX_ENDPOINT; rx_endpoint = ACM_RX_ENDPOINT; - + /* Configuration Descriptor */ configuration_descriptor = (struct usb_configuration_descriptor*) @@ -766,11 +766,11 @@ static void usbtty_init_terminal_type(short type) case 1: default: /* Assign endpoint descriptors */ - ep_descriptor_ptrs[0] = + ep_descriptor_ptrs[0] = &gserial_configuration_descriptors[0].data_endpoints[0]; - ep_descriptor_ptrs[1] = + ep_descriptor_ptrs[1] = &gserial_configuration_descriptors[0].data_endpoints[1]; - ep_descriptor_ptrs[2] = + ep_descriptor_ptrs[2] = &gserial_configuration_descriptors[0].data_endpoints[2]; /* Enumerate Device Descriptor */ @@ -783,7 +783,7 @@ static void usbtty_init_terminal_type(short type) rx_endpoint = GSERIAL_RX_ENDPOINT; /* Configuration Descriptor */ - configuration_descriptor = + configuration_descriptor = (struct usb_configuration_descriptor*) &gserial_configuration_descriptors; @@ -832,14 +832,14 @@ static int write_buffer (circbuf_t * buf) if (!usbtty_configured ()) { return 0; } - + struct usb_endpoint_instance *endpoint = &endpoint_instance[tx_endpoint]; struct urb *current_urb = NULL; current_urb = next_urb (device_instance, endpoint); - /* TX data still exists - send it now - */ + /* TX data still exists - send it now + */ if(endpoint->sent < current_urb->actual_length){ if(udc_endpoint_write (endpoint)){ /* Write pre-empted by RX */ @@ -854,11 +854,11 @@ static int write_buffer (circbuf_t * buf) int popnum, popped; int total = 0; - /* Break buffer into urb sized pieces, - * and link each to the endpoint + /* Break buffer into urb sized pieces, + * and link each to the endpoint */ while (buf->size > 0) { - + if (!current_urb) { TTYERR ("current_urb is NULL, buf->size %d\n", buf->size); @@ -881,8 +881,8 @@ static int write_buffer (circbuf_t * buf) current_urb->actual_length += popped; total += popped; - /* If endpoint->last == 0, then transfers have - * not started on this endpoint + /* If endpoint->last == 0, then transfers have + * not started on this endpoint */ if (endpoint->last == 0) { if(udc_endpoint_write (endpoint)){ @@ -904,7 +904,7 @@ static int fill_buffer (circbuf_t * buf) &endpoint_instance[rx_endpoint]; if (endpoint->rcv_urb && endpoint->rcv_urb->actual_length) { - unsigned int nb = 0; + unsigned int nb = 0; char *src = (char *) endpoint->rcv_urb->buffer; unsigned int rx_avail = buf->totalsize - buf->size; @@ -913,7 +913,7 @@ static int fill_buffer (circbuf_t * buf) nb = endpoint->rcv_urb->actual_length; buf_push (buf, src, nb); endpoint->rcv_urb->actual_length = 0; - + } return nb; } @@ -958,7 +958,7 @@ int usbtty_cdc_setup(struct usb_device_request *request, struct urb *urb) case ACM_SEND_ENCAPSULATED_COMMAND : /* Required */ break; case ACM_SET_LINE_ENCODING : /* DTE stop/parity bits - * per character */ + * per character */ break; case ACM_GET_ENCAPSULATED_RESPONSE : /* request response */ break; @@ -986,8 +986,8 @@ void usbtty_poll (void) /* New interrupts? */ udc_irq(); - /* Write any output data to host buffer - * (do this before checking interrupts to avoid missing one) + /* Write any output data to host buffer + * (do this before checking interrupts to avoid missing one) */ if (usbtty_configured ()) { write_buffer (&usbtty_output); @@ -995,9 +995,9 @@ void usbtty_poll (void) /* New interrupts? */ udc_irq(); - - /* Check for new data from host.. - * (do this after checking interrupts to get latest data) + + /* Check for new data from host.. + * (do this after checking interrupts to get latest data) */ if (usbtty_configured ()) { fill_buffer (&usbtty_input); diff --git a/drivers/usbtty.h b/drivers/usbtty.h index 731b763..8154e30 100644 --- a/drivers/usbtty.h +++ b/drivers/usbtty.h @@ -33,7 +33,7 @@ #include -/* If no VendorID/ProductID is defined in config.h, pretend to be Linux +/* If no VendorID/ProductID is defined in config.h, pretend to be Linux * DO NOT Reuse this Vendor/Product setup with protocol incompatible devices */ #define CONFIG_USBD_VENDORID 0x0525 /* Linux/NetChip */ @@ -45,7 +45,7 @@ #define CONFIG_USBD_CONFIGURATION_STR "TTY via USB" -#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT +#define CONFIG_USBD_SERIAL_OUT_ENDPOINT UDC_OUT_ENDPOINT #define CONFIG_USBD_SERIAL_OUT_PKTSIZE UDC_OUT_PACKET_SIZE #define CONFIG_USBD_SERIAL_IN_ENDPOINT UDC_IN_ENDPOINT #define CONFIG_USBD_SERIAL_IN_PKTSIZE UDC_IN_PACKET_SIZE diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h index c47306c..e8cb299 100644 --- a/include/asm-arm/arch-pxa/pxa-regs.h +++ b/include/asm-arm/arch-pxa/pxa-regs.h @@ -769,8 +769,6 @@ typedef void (*ExcpHndlr) (void) ; #define UP2OCR __REG(0x40600020) #define UP3OCR __REG(0x40600024) - - /* * USB Host Controller */ diff --git a/include/configs/AdderUSB.h b/include/configs/AdderUSB.h index 2112e56..a4f7f9a 100644 --- a/include/configs/AdderUSB.h +++ b/include/configs/AdderUSB.h @@ -3,7 +3,7 @@ * Bryan O'Donoghue * * Provides support for USB console on the Analogue & Micro Adder87x - * + * * See file CREDITS for list of people who contributed to this * project. * @@ -37,13 +37,13 @@ /* If you have a USB-IF assigned VendorID then you may wish to define * your own vendor specific values either in BoardName.h or directly in - * usbd_vendor_info.h + * usbd_vendor_info.h */ -/* +/* #define CONFIG_USBD_MANUFACTURER "CodeHermit.ie" #define CONFIG_USBD_PRODUCT_NAME "Das U-Boot" -#define CONFIG_USBD_VENDORID 0xFFFF +#define CONFIG_USBD_VENDORID 0xFFFF #define CONFIG_USBD_PRODUCTID_GSERIAL 0xFFFF #define CONFIG_USBD_PRODUCTID_CDCACM 0xFFFE */ diff --git a/include/usb_cdc_acm.h b/include/usb_cdc_acm.h index 8cb1654..87bf50c 100644 --- a/include/usb_cdc_acm.h +++ b/include/usb_cdc_acm.h @@ -34,7 +34,7 @@ #define ACM_RESPONSE_AVAILABLE 0x01 #define ACM_SERIAL_STATE 0x20 -/* Format of response expected by a ACM_GET_LINE_ENCODING request */ +/* Format of response expected by a ACM_GET_LINE_ENCODING request */ struct rs232_emu{ unsigned long dter; unsigned char stop_bits; diff --git a/include/usbdcore_mpc8xx.h b/include/usbdcore_mpc8xx.h index e54acd9..9df62f4 100644 --- a/include/usbdcore_mpc8xx.h +++ b/include/usbdcore_mpc8xx.h @@ -99,7 +99,7 @@ #define TX_BD_TO 0x04 #define TX_BD_NO_PID 0x00 #define TX_BD_PID_DATA0 0x80 -#define TX_BD_PID_DATA1 0xC0 +#define TX_BD_PID_DATA1 0xC0 #define TX_BD_CNF 0x200 #define TX_BD_TC 0x400 #define TX_BD_L 0x800 @@ -151,16 +151,16 @@ typedef struct mpc8xx_usb{ ushort usber; /* Event Register */ ushort res3; /* Reserved */ ushort usbmr; /* Mask Register */ - char res4; /* Reserved */ + char res4; /* Reserved */ char usbs; /* Status Register */ char res5[8]; /* Reserved */ }usb_t; typedef struct mpc8xx_parameter_ram{ - ushort ep0ptr; /* Endpoint Pointer Register 0 */ - ushort ep1ptr; /* Endpoint Pointer Register 1 */ - ushort ep2ptr; /* Endpoint Pointer Register 2 */ - ushort ep3ptr; /* Endpoint Pointer Register 3 */ + ushort ep0ptr; /* Endpoint Pointer Register 0 */ + ushort ep1ptr; /* Endpoint Pointer Register 1 */ + ushort ep2ptr; /* Endpoint Pointer Register 2 */ + ushort ep3ptr; /* Endpoint Pointer Register 3 */ uint rstate; /* Receive state */ uint rptr; /* Receive internal data pointer */ ushort frame_n; /* Frame number */ @@ -198,7 +198,7 @@ int udc_init(void); void udc_irq(void); int udc_endpoint_write(struct usb_endpoint_instance *endpoint); void udc_setup_ep(struct usb_device_instance *device, unsigned int ep, - struct usb_endpoint_instance *endpoint); + struct usb_endpoint_instance *endpoint); void udc_connect(void); void udc_disconnect(void); void udc_enable(struct usb_device_instance *device); diff --git a/include/usbdescriptors.h b/include/usbdescriptors.h index 8336c18..a752097 100644 --- a/include/usbdescriptors.h +++ b/include/usbdescriptors.h @@ -321,7 +321,7 @@ struct usb_class_union_function_descriptor { u8 bDescriptorType; u8 bDescriptorSubtype; /* 0x06 */ u8 bMasterInterface; - //u8 bSlaveInterface0[0]; + /* u8 bSlaveInterface0[0]; */ u8 bSlaveInterface0; } __attribute__ ((packed)); -- cgit v1.1 From 99d70e3a47affb9bae041a2caece7cd516e213b3 Mon Sep 17 00:00:00 2001 From: Wolfgang Denk Date: Mon, 26 Jun 2006 11:06:00 +0200 Subject: More code cleanup --- cpu/arm920t/s3c24x0/usb.c | 6 +++--- drivers/usb_ohci.h | 6 +----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/cpu/arm920t/s3c24x0/usb.c b/cpu/arm920t/s3c24x0/usb.c index 8114034..4bc7961 100644 --- a/cpu/arm920t/s3c24x0/usb.c +++ b/cpu/arm920t/s3c24x0/usb.c @@ -32,7 +32,7 @@ # include #endif -int usb_cpu_init() +int usb_cpu_init (void) { S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); @@ -53,7 +53,7 @@ int usb_cpu_init() return 0; } -int usb_cpu_stop() +int usb_cpu_stop (void) { S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); /* may not want to do this */ @@ -61,7 +61,7 @@ int usb_cpu_stop() return 0; } -int usb_cpu_init_fail() +int usb_cpu_init_fail (void) { S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); clk_power->CLKCON &= ~(1 << 4); diff --git a/drivers/usb_ohci.h b/drivers/usb_ohci.h index a1b36ed..68dd4ec 100644 --- a/drivers/usb_ohci.h +++ b/drivers/usb_ohci.h @@ -7,18 +7,14 @@ * usb-ohci.h */ -/* functions for doing board specific setup/cleanup */ -#ifdef CFG_USB_BOARD_INIT +/* functions for doing board or CPU specific setup/cleanup */ extern int usb_board_init(void); extern int usb_board_stop(void); extern int usb_cpu_init_fail(void); -#endif -#ifdef CFG_USB_CPU_INIT extern int usb_cpu_init(void); extern int usb_cpu_stop(void); extern int usb_cpu_init_fail(void); -#endif static int cc_to_error[16] = { -- cgit v1.1 From 53e336e9ffc51035bdc4e5867631b3378761b4df Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Mon, 27 Nov 2006 11:43:09 +0100 Subject: Modified the mpc5xxx and the ppc4xx cpu to use the generic OHCI driver and adapted board configs TQM5200 and yosemite accordingly. This commit also makes the maximum number of root hub ports configurable (CFG_USB_OHCI_MAX_ROOT_PORTS). --- cpu/mpc5xxx/Makefile | 2 +- cpu/ppc4xx/Makefile | 3 ++- drivers/usb_ohci.c | 13 +++++++++++-- drivers/usb_ohci.h | 13 +++++++++++-- include/configs/TQM5200.h | 7 +++++++ include/configs/delta.h | 1 + include/configs/mp2usb.h | 1 + include/configs/trab.h | 1 + include/configs/yosemite.h | 6 ++++++ 9 files changed, 41 insertions(+), 6 deletions(-) diff --git a/cpu/mpc5xxx/Makefile b/cpu/mpc5xxx/Makefile index a97b625..94f82b2 100644 --- a/cpu/mpc5xxx/Makefile +++ b/cpu/mpc5xxx/Makefile @@ -28,7 +28,7 @@ LIB = lib$(CPU).a START = start.o ASOBJS = io.o firmware_sc_task_bestcomm.impl.o firmware_sc_task.impl.o OBJS = i2c.o traps.o cpu.o cpu_init.o fec.o ide.o interrupts.o \ - loadtask.o pci_mpc5200.o serial.o speed.o usb_ohci.o + loadtask.o pci_mpc5200.o serial.o speed.o usb_ohci.o usb.o all: .depend $(START) $(ASOBJS) $(LIB) diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile index c563457..ca68599 100644 --- a/cpu/ppc4xx/Makefile +++ b/cpu/ppc4xx/Makefile @@ -31,7 +31,8 @@ COBJS = 405gp_pci.o 4xx_enet.o \ bedbug_405.o commproc.o \ cpu.o cpu_init.o i2c.o interrupts.o \ miiphy.o sdram.o serial.o \ - spd_sdram.o speed.o traps.o usb_ohci.o usbdev.o + spd_sdram.o speed.o traps.o \ + usb_ohci.o usbdev.o usb.o OBJS = $(AOBJS) $(COBJS) diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index 9b3ca12..be1a615 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -45,6 +45,7 @@ #ifdef CONFIG_USB_OHCI +/* mk: are these really required? */ #if defined(CONFIG_S3C2400) # include #elif defined(CONFIG_S3C2410) @@ -53,6 +54,8 @@ # include #elif defined(CONFIG_CPU_MONAHANS) # include +#elif defined(CONFIG_MPC5200) +# include #endif #include @@ -557,8 +560,10 @@ static int ep_link (ohci_t *ohci, ed_t *edi) * 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) { + volatile ed_t *ed = edi; + ed->hwINFO |= m32_swap (OHCI_ED_SKIP); switch (ed->type) { @@ -825,6 +830,9 @@ static td_t * dl_reverse_done_list (ohci_t *ohci) } else td_list->ed->hwHeadP &= m32_swap (0xfffffff2); } +#ifdef CONFIG_MPC5200 + td_list->hwNextTD = 0; +#endif } td_list->next_dl_td = td_rev; @@ -1448,7 +1456,8 @@ static int hc_reset (ohci_t *ohci) 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); diff --git a/drivers/usb_ohci.h b/drivers/usb_ohci.h index 68dd4ec..95fbc44 100644 --- a/drivers/usb_ohci.h +++ b/drivers/usb_ohci.h @@ -113,7 +113,9 @@ struct td { __u32 hwNextTD; /* Next TD Pointer */ __u32 hwBE; /* Memory Buffer End Pointer */ +/* #ifndef CONFIG_MPC5200 /\* this seems wrong *\/ */ __u16 hwPSW[MAXPSW]; +/* #endif */ __u8 unused; __u8 index; struct ed *ed; @@ -137,8 +139,13 @@ typedef struct td td_t; #define NUM_INTS 32 /* part of the OHCI standard */ struct ohci_hcca { __u32 int_table[NUM_INTS]; /* Interrupt ED table */ +#if defined(CONFIG_MPC5200) + __u16 pad1; /* set to 0 on each frame_no change */ + __u16 frame_no; /* current frame number */ +#else __u16 frame_no; /* current frame number */ __u16 pad1; /* set to 0 on each frame_no change */ +#endif __u32 done_head; /* info returned for an interrupt */ u8 reserved_for_hc[116]; } __attribute((aligned(256))); @@ -147,7 +154,9 @@ struct ohci_hcca { /* * Maximum number of root hub ports. */ -#define MAX_ROOT_PORTS 3 /* maximum OHCI root hub ports */ +#ifndef CFG_USB_OHCI_MAX_ROOT_PORTS +# error "CFG_USB_OHCI_MAX_ROOT_PORTS undefined!" +#endif /* * This is the structure of the OHCI controller's memory mapped I/O @@ -181,7 +190,7 @@ struct ohci_regs { __u32 a; __u32 b; __u32 status; - __u32 portstatus[MAX_ROOT_PORTS]; + __u32 portstatus[CFG_USB_OHCI_MAX_ROOT_PORTS]; } roothub; } __attribute((aligned(32))); diff --git a/include/configs/TQM5200.h b/include/configs/TQM5200.h index be83b67..832dcdd 100644 --- a/include/configs/TQM5200.h +++ b/include/configs/TQM5200.h @@ -128,6 +128,13 @@ #define CONFIG_USB_OHCI #define ADD_USB_CMD CFG_CMD_USB | CFG_CMD_FAT #define CONFIG_USB_STORAGE + +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT +#define CFG_USB_OHCI_REGS_BASE MPC5XXX_USB +#define CFG_USB_OHCI_SLOT_NAME "mpc5200" +#define CFG_USB_OHCI_MAX_ROOT_PORTS 15 + #else #define ADD_USB_CMD 0 #endif diff --git a/include/configs/delta.h b/include/configs/delta.h index fea821a..0617ad8 100644 --- a/include/configs/delta.h +++ b/include/configs/delta.h @@ -111,6 +111,7 @@ #define CFG_USB_OHCI_CPU_INIT 1 #define CFG_USB_OHCI_REGS_BASE OHCI_REGS_BASE #define CFG_USB_OHCI_SLOT_NAME "delta" +#define CFG_USB_OHCI_MAX_ROOT_PORTS 3 #define LITTLEENDIAN 1 /* used by usb_ohci.c */ diff --git a/include/configs/mp2usb.h b/include/configs/mp2usb.h index edb20f8..d182d49 100644 --- a/include/configs/mp2usb.h +++ b/include/configs/mp2usb.h @@ -111,6 +111,7 @@ #define CFG_USB_OHCI_CPU_INIT 1 #define CFG_USB_OHCI_REGS_BASE AT91_USB_HOST_BASE #define CFG_USB_OHCI_SLOT_NAME "at91rm9200" +#define CFG_USB_OHCI_MAX_ROOT_PORTS 15 #undef CONFIG_HARD_I2C diff --git a/include/configs/trab.h b/include/configs/trab.h index ae97947..33617cd 100644 --- a/include/configs/trab.h +++ b/include/configs/trab.h @@ -88,6 +88,7 @@ #define CFG_USB_OHCI_CPU_INIT 1 #define CFG_USB_OHCI_REGS_BASE S3C24X0_USB_HOST_BASE #define CFG_USB_OHCI_SLOT_NAME "s3c2400" +#define CFG_USB_OHCI_MAX_ROOT_PORTS 15 /* * Size of malloc() pool diff --git a/include/configs/yosemite.h b/include/configs/yosemite.h index a81cf34..e6a02c6 100644 --- a/include/configs/yosemite.h +++ b/include/configs/yosemite.h @@ -216,6 +216,12 @@ #define CONFIG_USB_OHCI #define CONFIG_USB_STORAGE +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT 1 +#define CFG_USB_OHCI_REGS_BASE (CFG_PERIPHERAL_BASE | 0x1000) +#define CFG_USB_OHCI_SLOT_NAME "ppc440" +#define CFG_USB_OHCI_MAX_ROOT_PORTS 15 + /*Comment this out to enable USB 1.1 device*/ #define USB_2_0_DEVICE #endif /*CONFIG_440EP*/ -- cgit v1.1 From 7b59b3c7a8ce2e4b567abf99c1cd667bf35b9418 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Mon, 27 Nov 2006 11:44:58 +0100 Subject: Introduced the configuration option CONFIG_USB_OHCI_NEW in order to be able to choose between the old and the generic OHCI drivers. --- board/trab/auto_update.c | 2 +- cpu/arm920t/at91rm9200/usb.c | 2 +- cpu/arm920t/s3c24x0/usb.c | 2 +- cpu/pxa/usb.c | 2 +- drivers/usb_ohci.c | 4 ++-- include/configs/TQM5200.h | 2 +- include/configs/delta.h | 2 +- include/configs/mp2usb.h | 2 +- include/configs/trab.h | 2 +- include/configs/yosemite.h | 2 +- include/usb.h | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/board/trab/auto_update.c b/board/trab/auto_update.c index d2c8d44..7684499 100644 --- a/board/trab/auto_update.c +++ b/board/trab/auto_update.c @@ -34,7 +34,7 @@ #ifdef CONFIG_AUTO_UPDATE -#ifndef CONFIG_USB_OHCI +#ifndef CONFIG_USB_OHCI_NEW #error "must define CONFIG_USB_OHCI" #endif diff --git a/cpu/arm920t/at91rm9200/usb.c b/cpu/arm920t/at91rm9200/usb.c index 98e3cdd..366262e 100644 --- a/cpu/arm920t/at91rm9200/usb.c +++ b/cpu/arm920t/at91rm9200/usb.c @@ -23,7 +23,7 @@ #include -#if defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) # ifdef CONFIG_AT91RM9200 #include diff --git a/cpu/arm920t/s3c24x0/usb.c b/cpu/arm920t/s3c24x0/usb.c index 4bc7961..ef5d5bf 100644 --- a/cpu/arm920t/s3c24x0/usb.c +++ b/cpu/arm920t/s3c24x0/usb.c @@ -23,7 +23,7 @@ #include -#if defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) # if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) #if defined(CONFIG_S3C2400) diff --git a/cpu/pxa/usb.c b/cpu/pxa/usb.c index bff5bfb..5d273cb 100644 --- a/cpu/pxa/usb.c +++ b/cpu/pxa/usb.c @@ -23,7 +23,7 @@ #include -#if defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) # ifdef CONFIG_CPU_MONAHANS #include diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index be1a615..482633f 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -43,7 +43,7 @@ #include /* #include no PCI on the S3C24X0 */ -#ifdef CONFIG_USB_OHCI +#ifdef CONFIG_USB_OHCI_NEW /* mk: are these really required? */ #if defined(CONFIG_S3C2400) @@ -1756,4 +1756,4 @@ int usb_lowlevel_stop(void) return 0; } -#endif /* CONFIG_USB_OHCI */ +#endif /* CONFIG_USB_OHCI_NEW */ diff --git a/include/configs/TQM5200.h b/include/configs/TQM5200.h index 832dcdd..6c8712b 100644 --- a/include/configs/TQM5200.h +++ b/include/configs/TQM5200.h @@ -125,7 +125,7 @@ /* USB */ #ifdef CONFIG_STK52XX -#define CONFIG_USB_OHCI +#define CONFIG_USB_OHCI_NEW #define ADD_USB_CMD CFG_CMD_USB | CFG_CMD_FAT #define CONFIG_USB_STORAGE diff --git a/include/configs/delta.h b/include/configs/delta.h index 0617ad8..4038f21 100644 --- a/include/configs/delta.h +++ b/include/configs/delta.h @@ -103,7 +103,7 @@ #endif /* USB */ -#define CONFIG_USB_OHCI 1 +#define CONFIG_USB_OHCI_NEW 1 #define CONFIG_USB_STORAGE 1 #define CONFIG_DOS_PARTITION 1 diff --git a/include/configs/mp2usb.h b/include/configs/mp2usb.h index d182d49..2cf78a3 100644 --- a/include/configs/mp2usb.h +++ b/include/configs/mp2usb.h @@ -101,7 +101,7 @@ #undef CONFIG_MODEM_SUPPORT /* disable modem initialization stuff */ -#define CONFIG_USB_OHCI 1 +#define CONFIG_USB_OHCI_NEW 1 #define CONFIG_USB_KEYBOARD 1 #define CONFIG_USB_STORAGE 1 #define CONFIG_DOS_PARTITION 1 diff --git a/include/configs/trab.h b/include/configs/trab.h index 33617cd..acf86d0 100644 --- a/include/configs/trab.h +++ b/include/configs/trab.h @@ -80,7 +80,7 @@ #define CFG_EEPROM_PAGE_WRITE_DELAY_MS 10 /* USB stuff */ -#define CONFIG_USB_OHCI 1 +#define CONFIG_USB_OHCI_NEW 1 #define CONFIG_USB_STORAGE 1 #define CONFIG_DOS_PARTITION 1 diff --git a/include/configs/yosemite.h b/include/configs/yosemite.h index e6a02c6..7f434e9 100644 --- a/include/configs/yosemite.h +++ b/include/configs/yosemite.h @@ -213,7 +213,7 @@ #ifdef CONFIG_440EP /* USB */ -#define CONFIG_USB_OHCI +#define CONFIG_USB_OHCI_NEW #define CONFIG_USB_STORAGE #undef CFG_USB_OHCI_BOARD_INIT diff --git a/include/usb.h b/include/usb.h index bf71554..fafac89 100644 --- a/include/usb.h +++ b/include/usb.h @@ -169,7 +169,7 @@ struct usb_device { * this is how the lowlevel part communicate with the outer world */ -#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || defined (CONFIG_USB_SL811HS) +#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || defined (CONFIG_USB_SL811HS) || defined(CONFIG_USB_OHCI_NEW) int usb_lowlevel_init(void); int usb_lowlevel_stop(void); int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len); -- cgit v1.1 From ae3b770e4eae8e98b6e9e29662e18c47fdf0171f Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Mon, 27 Nov 2006 11:46:46 +0100 Subject: Fix some endianness issues related to the generic ohci driver --- drivers/usb_ohci.c | 60 ++++++++++++++++++++++++++++++++++++++--------- include/configs/IceCube.h | 9 ++++++- include/usb.h | 15 +++++++----- 3 files changed, 66 insertions(+), 18 deletions(-) diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index 482633f..c5e4c38 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -62,15 +62,20 @@ #include #include "usb_ohci.h" -#undef S3C24X0_merge +#define S3C24X0_merge #if defined(CONFIG_ARM920T) || \ defined(CONFIG_S3C2400) || \ - defined(CONFIG_S3C2410) + defined(CONFIG_S3C2410) || \ + defined(CONFIG_440EP) || \ + defined(CONFIG_MPC5200) # define OHCI_USE_NPS /* force NoPowerSwitching mode */ #endif #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 \ @@ -95,8 +100,13 @@ #define info(format, arg...) do {} while(0) #endif -#define m16_swap(x) swap_16(x) -#define m32_swap(x) swap_32(x) +#if defined(CONFIG_440EP) || defined(CONFIG_MPC5200) +# define m16_swap(x) (x) +# define m32_swap(x) (x) +#else +# define m16_swap(x) swap_16(x) +# define m32_swap(x) swap_32(x) +#endif /* global ohci_t */ static ohci_t gohci; @@ -523,7 +533,7 @@ static int ep_link (ohci_t *ohci, ed_t *edi) if (ohci->ed_controltail == NULL) { writel (ed, &ohci->regs->ed_controlhead); } else { - ohci->ed_controltail->hwNextED = m32_swap (ed); + ohci->ed_controltail->hwNextED = m32_swap ((unsigned long)ed); } ed->ed_prev = ohci->ed_controltail; if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && @@ -539,7 +549,7 @@ static int ep_link (ohci_t *ohci, ed_t *edi) if (ohci->ed_bulktail == NULL) { writel (ed, &ohci->regs->ed_bulkhead); } else { - ohci->ed_bulktail->hwNextED = m32_swap (ed); + ohci->ed_bulktail->hwNextED = m32_swap ((unsigned long)ed); } ed->ed_prev = ohci->ed_bulktail; if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && @@ -635,7 +645,7 @@ static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe) ed->hwINFO = m32_swap (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 = m32_swap ((unsigned long)td); ed->hwHeadP = ed->hwTailP; ed->state = ED_UNLINK; ed->type = usb_pipetype (pipe); @@ -693,12 +703,12 @@ static void td_fill (ohci_t *ohci, unsigned int info, data = 0; td->hwINFO = m32_swap (info); - td->hwCBP = m32_swap (data); + td->hwCBP = m32_swap ((unsigned long)data); if (data) - td->hwBE = m32_swap (data + len - 1); + td->hwBE = m32_swap ((unsigned long)(data + len - 1)); else td->hwBE = 0; - td->hwNextTD = m32_swap (td_pt); + td->hwNextTD = m32_swap ((unsigned long)td_pt); #ifndef S3C24X0_merge td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000); #endif @@ -875,7 +885,12 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list) /* see if this done list makes for all TD's of current URB, * and mark the URB finished if so */ if (++(lurb_priv->td_cnt) == lurb_priv->length) { +#if 1 + if ((ed->state & (ED_OPER | ED_UNLINK)) && + (lurb_priv->state != URB_DEL)) +#else if ((ed->state & (ED_OPER | ED_UNLINK))) +#endif urb_finished = 1; else dbg("dl_done_list: strange.., ED state %x, ed->state\n"); @@ -1068,9 +1083,15 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); } bmRType_bReq = cmd->requesttype | (cmd->request << 8); +#if defined(CONFIG_440EP) || defined(CONFIG_MPC5200) + wValue = __swap_16(cmd->value); + wIndex = __swap_16(cmd->index); + wLength = __swap_16(cmd->length); +#else wValue = m16_swap (cmd->value); wIndex = m16_swap (cmd->index); wLength = m16_swap (cmd->length); +#endif /* CONFIG_440EP || CONFIG_MPC5200 */ info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x", dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength); @@ -1084,6 +1105,20 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); RH_OTHER | RH_CLASS almost ever means HUB_PORT here */ +#if defined(CONFIG_440EP) || defined(CONFIG_MPC5200) + case RH_GET_STATUS: + *(__u16 *) data_buf = __swap_16(1); OK (2); + case RH_GET_STATUS | RH_INTERFACE: + *(__u16 *) data_buf = __swap_16(0); OK (2); + case RH_GET_STATUS | RH_ENDPOINT: + *(__u16 *) data_buf = __swap_16(0); OK (2); + case RH_GET_STATUS | RH_CLASS: + *(__u32 *) data_buf = __swap_32( + RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE)); + OK (4); + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + *(__u32 *) data_buf = __swap_32(RD_RH_PORTSTAT); OK (4); +#else case RH_GET_STATUS: *(__u16 *) data_buf = m16_swap (1); OK (2); case RH_GET_STATUS | RH_INTERFACE: @@ -1096,6 +1131,7 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); OK (4); case RH_GET_STATUS | RH_OTHER | RH_CLASS: *(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4); +#endif /* CONFIG_440EP || CONFIG_MPC5200 */ case RH_CLEAR_FEATURE | RH_ENDPOINT: switch (wValue) { @@ -1294,8 +1330,10 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, return -1; } +#if 0 wait_ms(10); /* ohci_dump_status(&gohci); */ +#endif /* allow more time for a BULK device to react - some are slow */ #define BULK_TO 5000 /* timeout in milliseconds */ @@ -1337,6 +1375,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, err("CTL:TIMEOUT "); #ifdef S3C24X0_merge dbg("submit_common_msg: TO status %x\n", stat); + stat = USB_ST_CRC_ERR; urb_finished = 1; #endif stat = USB_ST_CRC_ERR; @@ -1755,5 +1794,4 @@ int usb_lowlevel_stop(void) return 0; } - #endif /* CONFIG_USB_OHCI_NEW */ diff --git a/include/configs/IceCube.h b/include/configs/IceCube.h index 1152f83..8753b9f 100644 --- a/include/configs/IceCube.h +++ b/include/configs/IceCube.h @@ -94,9 +94,16 @@ /* USB */ #if 1 -#define CONFIG_USB_OHCI +#define CONFIG_USB_OHCI_NEW #define ADD_USB_CMD CFG_CMD_USB | CFG_CMD_FAT #define CONFIG_USB_STORAGE + +#undef CFG_USB_OHCI_BOARD_INIT +#define CFG_USB_OHCI_CPU_INIT +#define CFG_USB_OHCI_REGS_BASE MPC5XXX_USB +#define CFG_USB_OHCI_SLOT_NAME "mpc5200" +#define CFG_USB_OHCI_MAX_ROOT_PORTS 15 + #else #define ADD_USB_CMD 0 #endif diff --git a/include/usb.h b/include/usb.h index fafac89..419a7e3 100644 --- a/include/usb.h +++ b/include/usb.h @@ -230,16 +230,12 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate); /* big endian -> little endian conversion */ /* some CPUs are already little endian e.g. the ARM920T */ -#ifdef LITTLEENDIAN -#define swap_16(x) ((unsigned short)(x)) -#define swap_32(x) ((unsigned long)(x)) -#else -#define swap_16(x) \ +#define __swap_16(x) \ ({ unsigned short x_ = (unsigned short)x; \ (unsigned short)( \ ((x_ & 0x00FFU) << 8) | ((x_ & 0xFF00U) >> 8) ); \ }) -#define swap_32(x) \ +#define __swap_32(x) \ ({ unsigned long x_ = (unsigned long)x; \ (unsigned long)( \ ((x_ & 0x000000FFUL) << 24) | \ @@ -247,6 +243,13 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate); ((x_ & 0x00FF0000UL) >> 8) | \ ((x_ & 0xFF000000UL) >> 24) ); \ }) + +#ifdef LITTLEENDIAN +# define swap_16(x) (x) +# define swap_32(x) (x) +#else +# define swap_16(x) __swap_16(x) +# define swap_32(x) __swap_32(x) #endif /* LITTLEENDIAN */ /* -- cgit v1.1 From 58b485776698c3d71ec5a215e392123b4c15afa3 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Mon, 27 Nov 2006 11:51:21 +0100 Subject: Add a small README with information on the generic ohci driver. --- doc/README.generic_usb_ohci | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 doc/README.generic_usb_ohci diff --git a/doc/README.generic_usb_ohci b/doc/README.generic_usb_ohci new file mode 100644 index 0000000..017c69a --- /dev/null +++ b/doc/README.generic_usb_ohci @@ -0,0 +1,43 @@ +Notes on the the generic USB-OHCI driver +======================================== + +This driver (drivers/usb_ohci.[ch]) is the result of the merge of +various existing OHCI drivers that were basically identical beside +cpu/board dependant initalization. This initalization has been moved +into cpu/board directories and are called via the hooks below. + +Configuration options +---------------------- + +CONFIG_USB_OHCI_NEW: enable the new OHCI driver + +CFG_USB_OHCI_BOARD_INIT: call the board dependant hooks: + + - extern int usb_board_init(void); + - extern int usb_board_stop(void); + - extern int usb_cpu_init_fail(void); + +CFG_USB_OHCI_CPU_INIT: call the cpu dependant hooks: + + - extern int usb_cpu_init(void); + - extern int usb_cpu_stop(void); + - extern int usb_cpu_init_fail(void); + +CFG_USB_OHCI_REGS_BASE: defines the base address of the OHCI registers + +CFG_USB_OHCI_SLOT_NAME: slot name + +CFG_USB_OHCI_MAX_ROOT_PORTS: maximal number of ports of the root hub. + + +Endianness issues +------------------ + +The LITTLEENDIAN #define determines if the 'swap_16' and 'swap_32' +macros do byte swapping or not. But some cpus OHCI-controllers such as +ppc4xx and mpc5xxx operate in little endian mode, so some extra ifdefs +were necessary to make this work. + + + + -- cgit v1.1 From ae79f60677c208326535647dcbd5c3ec40dbcb0b Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Mon, 26 Mar 2007 11:21:05 +0200 Subject: USB: remove the S3C24X0_merge #define, which was introduced while merging OHCI drivers. Signed-off-by: Markus Klotzbuecher --- drivers/usb_ohci.c | 56 +++--------------------------------------------------- 1 file changed, 3 insertions(+), 53 deletions(-) diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index c5e4c38..1c3f622 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -62,8 +62,6 @@ #include #include "usb_ohci.h" -#define S3C24X0_merge - #if defined(CONFIG_ARM920T) || \ defined(CONFIG_S3C2400) || \ defined(CONFIG_S3C2410) || \ @@ -123,10 +121,8 @@ int got_rhsc; /* device which was disconnected */ struct usb_device *devgone; -#ifdef S3C24X0_merge /* flag guarding URB transation */ int urb_finished = 0; -#endif /*-------------------------------------------------------------------------*/ @@ -433,7 +429,7 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, err("sohci_submit_job: EPIPE"); return -1; } -#ifdef S3C24X0_merge + /* 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 */ @@ -443,7 +439,6 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, } /* we're about to begin a new transaction here so mark the URB unfinished */ urb_finished = 0; -#endif /* every endpoint has a ed, locate and fill it */ if (!(ed = ep_add_ed (dev, pipe))) { @@ -709,9 +704,6 @@ static void td_fill (ohci_t *ohci, unsigned int info, else td->hwBE = 0; td->hwNextTD = m32_swap ((unsigned long)td_pt); -#ifndef S3C24X0_merge - td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000); -#endif /* append to queue */ td->ed->hwTailP = td->hwNextTD; @@ -881,7 +873,7 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list) dbg("ConditionCode %#x", cc); stat = cc_to_error[cc]; } -#ifdef S3C24X0_merge + /* see if this done list makes for all TD's of current URB, * and mark the URB finished if so */ if (++(lurb_priv->td_cnt) == lurb_priv->length) { @@ -890,7 +882,6 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list) (lurb_priv->state != URB_DEL)) #else if ((ed->state & (ED_OPER | ED_UNLINK))) -#endif urb_finished = 1; else dbg("dl_done_list: strange.., ED state %x, ed->state\n"); @@ -1351,7 +1342,6 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, break; } -#ifdef S3C24X0_merge /* 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 @@ -1362,9 +1352,6 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, * hc_interrupt() gets called again as there needs to be some * more TD's to process still */ if ((stat >= 0) && (stat != 0xff) && (urb_finished)) { -#else - if (stat >= 0 && stat != 0xff) { -#endif /* 0xff is returned for an SF-interrupt */ break; } @@ -1373,38 +1360,13 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, wait_ms(1); } else { err("CTL:TIMEOUT "); -#ifdef S3C24X0_merge dbg("submit_common_msg: TO status %x\n", stat); stat = USB_ST_CRC_ERR; urb_finished = 1; -#endif stat = USB_ST_CRC_ERR; break; } } -#ifndef S3C24X0_merge - /* we got an Root Hub Status Change interrupt */ - if (got_rhsc) { -#ifdef DEBUG - ohci_dump_roothub (&gohci, 1); -#endif - got_rhsc = 0; - /* abuse timeout */ - timeout = rh_check_port_status(&gohci); - if (timeout >= 0) { -#if 0 /* this does nothing useful, but leave it here in case that changes */ - /* the called routine adds 1 to the passed value */ - usb_hub_port_connect_change(gohci.rh.dev, timeout - 1); -#endif - /* - * XXX - * This is potentially dangerous because it assumes - * that only one device is ever plugged in! - */ - devgone = dev; - } - } -#endif /* S3C24X0_merge */ dev->status = stat; dev->act_len = transfer_len; @@ -1582,8 +1544,6 @@ static int hc_interrupt (void) int ints; int stat = -1; -#ifdef S3C24X0_merge - if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) { ints = OHCI_INTR_WDH; @@ -1595,20 +1555,12 @@ static int hc_interrupt (void) dbg("hc_interrupt: returning..\n"); return 0xff; } -#else - if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) { - ints = OHCI_INTR_WDH; - } else { - ints = readl (®s->intrstatus); - } -#endif + /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */ if (ints & OHCI_INTR_RHSC) { got_rhsc = 1; -#ifdef S3C24X0_merge stat = 0xff; -#endif } if (ints & OHCI_INTR_UE) { @@ -1762,9 +1714,7 @@ int usb_lowlevel_init(void) ohci_dump (&gohci, 1); #else wait_ms(1); -# ifdef S3C24X0_merge urb_finished = 1; -# endif #endif ohci_inited = 1; return 0; -- cgit v1.1 From ae00bb4b2944dc64a485ed72a19754b11af7c223 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Mon, 26 Mar 2007 12:03:36 +0200 Subject: PXA: pxa27x USB OHCI support Signed-off-by: Rodolfo Giometti --- README | 1 + cpu/pxa/usb.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/README b/README index 13ff3ff..73a3e80 100644 --- a/README +++ b/README @@ -248,6 +248,7 @@ The following options need to be configured: CONFIG_SA1110 CONFIG_ARM7 CONFIG_PXA250 + CONFIG_PXA27X CONFIG_CPU_MONAHANS MicroBlaze based CPUs: diff --git a/cpu/pxa/usb.c b/cpu/pxa/usb.c index 5d273cb..4ef3ac7 100644 --- a/cpu/pxa/usb.c +++ b/cpu/pxa/usb.c @@ -24,15 +24,21 @@ #include #if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) -# ifdef CONFIG_CPU_MONAHANS +# if defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X) #include int usb_cpu_init() { +#if defined(CONFIG_CPU_MONAHANS) /* Enable USB host clock. */ CKENA |= (CKENA_2_USBHOST | CKENA_20_UDC); udelay(100); +#endif +#if defined(CONFIG_PXA27X) + /* Enable USB host clock. */ + CKEN |= CKEN10_USBHOST; +#endif /* Configure Port 2 for Host (USB Client Registers) */ UP2OCR = 0x3000c; @@ -55,7 +61,12 @@ int usb_cpu_init() UHCHR |= UHCHR_PSPL; /* USBHPWR is active low */ #endif +#if defined(CONFIG_CPU_MONAHANS) UHCHR &= ~UHCHR_SSEP0; +#endif +#if defined(CONFIG_PXA27X) + UHCHR &= ~UHCHR_SSEP2; +#endif UHCHR &= ~UHCHR_SSEP1; UHCHR &= ~UHCHR_SSE; @@ -74,5 +85,5 @@ int usb_cpu_init_fail() return 0; } -# endif /* CONFIG_CPU_MONAHANS */ +# endif /* defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X) */ #endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ -- cgit v1.1 From edf5851be6c17c031d4f71dd5b0a12040b7c50c8 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Tue, 3 Apr 2007 14:27:08 +0200 Subject: USB: cleanup monahans usb support. Remove dead code. Signed-off-by: Markus Klotzbuecher --- cpu/pxa/usb.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/cpu/pxa/usb.c b/cpu/pxa/usb.c index 4ef3ac7..65f457f 100644 --- a/cpu/pxa/usb.c +++ b/cpu/pxa/usb.c @@ -40,12 +40,9 @@ int usb_cpu_init() CKEN |= CKEN10_USBHOST; #endif +#if defined(CONFIG_CPU_MONAHANS) /* Configure Port 2 for Host (USB Client Registers) */ UP2OCR = 0x3000c; - -#if 0 - GPIO2_2 = 0x801; /* USBHPEN - Alt. Fkt. 1 */ - GPIO3_2 = 0x801; /* USBHPWR - Alt. Fkt. 1 */ #endif UHCHR |= UHCHR_FHR; @@ -56,11 +53,6 @@ int usb_cpu_init() while (UHCHR & UHCHR_FSBIR) udelay(1); -#if 0 - UHCHR |= UHCHR_PCPL; /* USBHPEN is active low */ - UHCHR |= UHCHR_PSPL; /* USBHPWR is active low */ -#endif - #if defined(CONFIG_CPU_MONAHANS) UHCHR &= ~UHCHR_SSEP0; #endif @@ -75,8 +67,6 @@ int usb_cpu_init() int usb_cpu_stop() { - /* may not want to do this */ - /* CKENA &= ~(CKENA_2_USBHOST | CKENA_20_UDC); */ return 0; } -- cgit v1.1 From 822af351ad2babc7d99033361a5fcacd30f6bc78 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Tue, 3 Apr 2007 14:27:18 +0200 Subject: Support for the Philips ISP116x HCD (Host Controller Driver) Signed-off-by: Rodolfo Giometti --- drivers/Makefile | 2 +- drivers/isp116x-hcd.c | 1412 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/isp116x.h | 489 +++++++++++++++++ include/usb.h | 5 +- 4 files changed, 1906 insertions(+), 2 deletions(-) create mode 100644 drivers/isp116x-hcd.c create mode 100644 drivers/isp116x.h diff --git a/drivers/Makefile b/drivers/Makefile index 0ca400c..52cd388 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -31,7 +31,7 @@ COBJS = 3c589.o 5701rls.o ali512x.o atmel_usart.o \ bcm570x.o bcm570x_autoneg.o cfb_console.o cfi_flash.o \ cs8900.o ct69000.o dataflash.o dc2114x.o dm9000x.o \ e1000.o eepro100.o \ - i8042.o inca-ip_sw.o keyboard.o \ + i8042.o inca-ip_sw.o isp116x-hcd.o keyboard.o \ lan91c96.o \ natsemi.o ne2000.o netarm_eth.o netconsole.o \ ns16550.o ns8382x.o ns87308.o ns7520_eth.o omap1510_i2c.o \ diff --git a/drivers/isp116x-hcd.c b/drivers/isp116x-hcd.c new file mode 100644 index 0000000..d57b8ec --- /dev/null +++ b/drivers/isp116x-hcd.c @@ -0,0 +1,1412 @@ +/* + * ISP116x HCD (Host Controller Driver) for u-boot. + * + * Copyright (C) 2006-2007 Rodolfo Giometti + * Copyright (C) 2006-2007 Eurotech S.p.A. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Derived in part from the SL811 HCD driver "u-boot/drivers/sl811_usb.c" + * (original copyright message follows): + * + * (C) Copyright 2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This code is based on linux driver for sl811hs chip, source at + * drivers/usb/host/sl811.c: + * + * SL811 Host Controller Interface driver for USB. + * + * Copyright (c) 2003/06, Courage Co., Ltd. + * + * Based on: + * 1.uhci.c by Linus Torvalds, Johannes Erdfelt, Randy Dunlap, + * Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, + * Adam Richter, Gregory P. Smith; + * 2.Original SL811 driver (hc_sl811.o) by Pei Liu + * 3.Rewrited as sl811.o by Yin Aihua + * + * [[GNU/GPL disclaimer]] + * + * and in part from AU1x00 OHCI HCD driver "u-boot/cpu/mips/au1x00_usb_ohci.c" + * (original copyright message follows): + * + * URB OHCI HCD (Host Controller Driver) for USB on the AU1x00. + * + * (C) Copyright 2003 + * Gary Jennejohn, DENX Software Engineering + * + * [[GNU/GPL disclaimer]] + * + * Note: Part of this code has been derived from linux + */ + +#include + +#ifdef CONFIG_USB_ISP116X_HCD +#include +#include +#include +#include + +/* + * ISP116x chips require certain delays between accesses to its + * registers. The following timing options exist. + * + * 1. Configure your memory controller (the best) + * 2. Use ndelay (easiest, poorest). For that, enable the following macro. + * + * Value is in microseconds. + */ +#ifdef ISP116X_HCD_USE_UDELAY +#define UDELAY 1 +#endif + +/* + * On some (slowly?) machines an extra delay after data packing into + * controller's FIFOs is required, * otherwise you may get the following + * error: + * + * uboot> usb start + * (Re)start USB... + * USB: scanning bus for devices... isp116x: isp116x_submit_job: CTL:TIMEOUT + * isp116x: isp116x_submit_job: ****** FIFO not ready! ****** + * + * USB device not responding, giving up (status=4) + * isp116x: isp116x_submit_job: ****** FIFO not empty! ****** + * isp116x: isp116x_submit_job: ****** FIFO not empty! ****** + * isp116x: isp116x_submit_job: ****** FIFO not empty! ****** + * 3 USB Device(s) found + * scanning bus for storage devices... 0 Storage Device(s) found + * + * Value is in milliseconds. + */ +#ifdef ISP116X_HCD_USE_EXTRA_DELAY +#define EXTRA_DELAY 2 +#endif + +/* + * Enable the following defines if you wish enable debugging messages. + */ +#undef DEBUG /* enable debugging messages */ +#undef TRACE /* enable tracing code */ +#undef VERBOSE /* verbose debugging messages */ + +#include "isp116x.h" + +#define DRIVER_VERSION "08 Jan 2007" +static const char hcd_name[] = "isp116x-hcd"; + +struct isp116x isp116x_dev; +struct isp116x_platform_data isp116x_board; +int got_rhsc = 0; /* root hub status change */ +struct usb_device *devgone; /* device which was disconnected */ +int rh_devnum = 0; /* address of Root Hub endpoint */ + +/* ------------------------------------------------------------------------- */ + +#define ALIGN(x,a) (((x)+(a)-1UL)&~((a)-1UL)) +#define min_t(type,x,y) \ + ({ type __x = (x); type __y = (y); __x < __y ? __x : __y; }) + +/* ------------------------------------------------------------------------- */ + +static int isp116x_reset(struct isp116x *isp116x); + +/* --- Debugging functions ------------------------------------------------- */ + +#define isp116x_show_reg(d, r) { \ + if ((r) < 0x20) { \ + DBG("%-12s[%02x]: %08x", #r, \ + r, isp116x_read_reg32(d, r)); \ + } else { \ + DBG("%-12s[%02x]: %04x", #r, \ + r, isp116x_read_reg16(d, r)); \ + } \ +} + +#define isp116x_show_regs(d) { \ + isp116x_show_reg(d, HCREVISION); \ + isp116x_show_reg(d, HCCONTROL); \ + isp116x_show_reg(d, HCCMDSTAT); \ + isp116x_show_reg(d, HCINTSTAT); \ + isp116x_show_reg(d, HCINTENB); \ + isp116x_show_reg(d, HCFMINTVL); \ + isp116x_show_reg(d, HCFMREM); \ + isp116x_show_reg(d, HCFMNUM); \ + isp116x_show_reg(d, HCLSTHRESH); \ + isp116x_show_reg(d, HCRHDESCA); \ + isp116x_show_reg(d, HCRHDESCB); \ + isp116x_show_reg(d, HCRHSTATUS); \ + isp116x_show_reg(d, HCRHPORT1); \ + isp116x_show_reg(d, HCRHPORT2); \ + isp116x_show_reg(d, HCHWCFG); \ + isp116x_show_reg(d, HCDMACFG); \ + isp116x_show_reg(d, HCXFERCTR); \ + isp116x_show_reg(d, HCuPINT); \ + isp116x_show_reg(d, HCuPINTENB); \ + isp116x_show_reg(d, HCCHIPID); \ + isp116x_show_reg(d, HCSCRATCH); \ + isp116x_show_reg(d, HCITLBUFLEN); \ + isp116x_show_reg(d, HCATLBUFLEN); \ + isp116x_show_reg(d, HCBUFSTAT); \ + isp116x_show_reg(d, HCRDITL0LEN); \ + isp116x_show_reg(d, HCRDITL1LEN); \ +} + +#if defined(TRACE) + +static int isp116x_get_current_frame_number(struct usb_device *usb_dev) +{ + struct isp116x *isp116x = &isp116x_dev; + + return isp116x_read_reg32(isp116x, HCFMNUM); +} + +static void dump_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len, char *str) +{ +#if defined(VERBOSE) + int i; +#endif + + DBG("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d stat:%#lx", + str, + isp116x_get_current_frame_number(dev), + usb_pipedevice(pipe), + usb_pipeendpoint(pipe), + usb_pipeout(pipe) ? 'O' : 'I', + usb_pipetype(pipe) < 2 ? + (usb_pipeint(pipe) ? + "INTR" : "ISOC") : + (usb_pipecontrol(pipe) ? "CTRL" : "BULK"), len, dev->status); +#if defined(VERBOSE) + if (len > 0 && buffer) { + printf(__FILE__ ": data(%d):", len); + for (i = 0; i < 16 && i < len; i++) + printf(" %02x", ((__u8 *) buffer)[i]); + printf("%s\n", i < len ? "..." : ""); + } +#endif +} + +#define PTD_DIR_STR(ptd) ({char __c; \ + switch(PTD_GET_DIR(ptd)){ \ + case 0: __c = 's'; break; \ + case 1: __c = 'o'; break; \ + default: __c = 'i'; break; \ + }; __c;}) + +/* + Dump PTD info. The code documents the format + perfectly, right :) +*/ +static inline void dump_ptd(struct ptd *ptd) +{ +#if defined(VERBOSE) + int k; +#endif + + DBG("PTD(ext) : cc:%x %d%c%d %d,%d,%d t:%x %x%x%x", + PTD_GET_CC(ptd), + PTD_GET_FA(ptd), PTD_DIR_STR(ptd), PTD_GET_EP(ptd), + PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd), + PTD_GET_TOGGLE(ptd), + PTD_GET_ACTIVE(ptd), PTD_GET_SPD(ptd), PTD_GET_LAST(ptd)); +#if defined(VERBOSE) + printf("isp116x: %s: PTD(byte): ", __FUNCTION__); + for (k = 0; k < sizeof(struct ptd); ++k) + printf("%02x ", ((u8 *) ptd)[k]); + printf("\n"); +#endif +} + +static inline void dump_ptd_data(struct ptd *ptd, u8 * buf, int type) +{ +#if defined(VERBOSE) + int k; + + if (type == 0 /* 0ut data */ ) { + printf("isp116x: %s: out data: ", __FUNCTION__); + for (k = 0; k < PTD_GET_LEN(ptd); ++k) + printf("%02x ", ((u8 *) buf)[k]); + printf("\n"); + } + if (type == 1 /* 1n data */ ) { + printf("isp116x: %s: in data: ", __FUNCTION__); + for (k = 0; k < PTD_GET_COUNT(ptd); ++k) + printf("%02x ", ((u8 *) buf)[k]); + printf("\n"); + } + + if (PTD_GET_LAST(ptd)) + DBG("--- last PTD ---"); +#endif +} + +#else + +#define dump_msg(dev, pipe, buffer, len, str) do { } while (0) +#define dump_pkt(dev, pipe, buffer, len, setup, str, small) do {} while (0) + +#define dump_ptd(ptd) do {} while (0) +#define dump_ptd_data(ptd, buf, type) do {} while (0) + +#endif + +/* --- Virtual Root Hub ---------------------------------------------------- */ + +/* Device descriptor */ +static __u8 root_hub_dev_des[] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x10, /* __u16 bcdUSB; v1.1 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x01, /* __u8 iProduct; */ + 0x00, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* Configuration descriptor */ +static __u8 root_hub_config_des[] = { + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x00, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ + 0x02, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static unsigned char root_hub_str_index0[] = { + 0x04, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 0x09, /* __u8 lang ID */ + 0x04, /* __u8 lang ID */ +}; + +static unsigned char root_hub_str_index1[] = { + 0x22, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 'I', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'S', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'P', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + '1', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + '1', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + '6', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'x', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'R', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 't', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'H', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'u', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'b', /* __u8 Unicode */ + 0, /* __u8 Unicode */ +}; + +/* + * Hub class-specific descriptor is constructed dynamically + */ + +/* --- Virtual root hub management functions ------------------------------- */ + +static int rh_check_port_status(struct isp116x *isp116x) +{ + u32 temp, ndp, i; + int res; + + res = -1; + temp = isp116x_read_reg32(isp116x, HCRHSTATUS); + ndp = (temp & RH_A_NDP); + for (i = 0; i < ndp; i++) { + temp = isp116x_read_reg32(isp116x, HCRHPORT1 + i); + /* check for a device disconnect */ + if (((temp & (RH_PS_PESC | RH_PS_CSC)) == + (RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0)) { + res = i; + break; + } + } + return res; +} + +/* --- HC management functions --------------------------------------------- */ + +/* Write len bytes to fifo, pad till 32-bit boundary + */ +static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len) +{ + u8 *dp = (u8 *) buf; + u16 *dp2 = (u16 *) buf; + u16 w; + int quot = len % 4; + + if ((unsigned long)dp2 & 1) { + /* not aligned */ + for (; len > 1; len -= 2) { + w = *dp++; + w |= *dp++ << 8; + isp116x_raw_write_data16(isp116x, w); + } + if (len) + isp116x_write_data16(isp116x, (u16) * dp); + } else { + /* aligned */ + for (; len > 1; len -= 2) + isp116x_raw_write_data16(isp116x, *dp2++); + if (len) + isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2)); + } + if (quot == 1 || quot == 2) + isp116x_raw_write_data16(isp116x, 0); +} + +/* Read len bytes from fifo and then read till 32-bit boundary + */ +static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len) +{ + u8 *dp = (u8 *) buf; + u16 *dp2 = (u16 *) buf; + u16 w; + int quot = len % 4; + + if ((unsigned long)dp2 & 1) { + /* not aligned */ + for (; len > 1; len -= 2) { + w = isp116x_raw_read_data16(isp116x); + *dp++ = w & 0xff; + *dp++ = (w >> 8) & 0xff; + } + if (len) + *dp = 0xff & isp116x_read_data16(isp116x); + } else { + /* aligned */ + for (; len > 1; len -= 2) + *dp2++ = isp116x_raw_read_data16(isp116x); + if (len) + *(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x); + } + if (quot == 1 || quot == 2) + isp116x_raw_read_data16(isp116x); +} + +/* Write PTD's and data for scheduled transfers into the fifo ram. + * Fifo must be empty and ready */ +static void pack_fifo(struct isp116x *isp116x, struct usb_device *dev, + unsigned long pipe, struct ptd *ptd, int n, void *data, + int len) +{ + int buflen = n * sizeof(struct ptd) + len; + int i, done; + + DBG("--- pack buffer %p - %d bytes (fifo %d) ---", data, len, buflen); + + isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT); + isp116x_write_reg16(isp116x, HCXFERCTR, buflen); + isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET); + + done = 0; + for (i = 0; i < n; i++) { + DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i])); + + dump_ptd(&ptd[i]); + isp116x_write_data16(isp116x, ptd[i].count); + isp116x_write_data16(isp116x, ptd[i].mps); + isp116x_write_data16(isp116x, ptd[i].len); + isp116x_write_data16(isp116x, ptd[i].faddr); + + dump_ptd_data(&ptd[i], (__u8 *) data + done, 0); + write_ptddata_to_fifo(isp116x, + (__u8 *) data + done, + PTD_GET_LEN(&ptd[i])); + + done += PTD_GET_LEN(&ptd[i]); + } +} + +/* Read the processed PTD's and data from fifo ram back to URBs' buffers. + * Fifo must be full and done */ +static int unpack_fifo(struct isp116x *isp116x, struct usb_device *dev, + unsigned long pipe, struct ptd *ptd, int n, void *data, + int len) +{ + int buflen = n * sizeof(struct ptd) + len; + int i, done, cc, ret; + + isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT); + isp116x_write_reg16(isp116x, HCXFERCTR, buflen); + isp116x_write_addr(isp116x, HCATLPORT); + + ret = TD_CC_NOERROR; + done = 0; + for (i = 0; i < n; i++) { + DBG("i=%d - done=%d - len=%d", i, done, PTD_GET_LEN(&ptd[i])); + + ptd[i].count = isp116x_read_data16(isp116x); + ptd[i].mps = isp116x_read_data16(isp116x); + ptd[i].len = isp116x_read_data16(isp116x); + ptd[i].faddr = isp116x_read_data16(isp116x); + dump_ptd(&ptd[i]); + + read_ptddata_from_fifo(isp116x, + (__u8 *) data + done, + PTD_GET_LEN(&ptd[i])); + dump_ptd_data(&ptd[i], (__u8 *) data + done, 1); + + done += PTD_GET_LEN(&ptd[i]); + + cc = PTD_GET_CC(&ptd[i]); + if (cc == TD_DATAUNDERRUN) { /* underrun is no error... */ + DBG("allowed data underrun"); + cc = TD_CC_NOERROR; + } + if (cc != TD_CC_NOERROR && ret == TD_CC_NOERROR) + ret = cc; + } + + DBG("--- unpack buffer %p - %d bytes (fifo %d) ---", data, len, buflen); + + return ret; +} + +/* Interrupt handling + */ +static int isp116x_interrupt(struct isp116x *isp116x) +{ + u16 irqstat; + u32 intstat; + int ret = 0; + + isp116x_write_reg16(isp116x, HCuPINTENB, 0); + irqstat = isp116x_read_reg16(isp116x, HCuPINT); + isp116x_write_reg16(isp116x, HCuPINT, irqstat); + DBG(">>>>>> irqstat %x <<<<<<", irqstat); + + if (irqstat & HCuPINT_ATL) { + DBG(">>>>>> HCuPINT_ATL <<<<<<"); + ret = 1; + } + + if (irqstat & HCuPINT_OPR) { + intstat = isp116x_read_reg32(isp116x, HCINTSTAT); + isp116x_write_reg32(isp116x, HCINTSTAT, intstat); + DBG(">>>>>> HCuPINT_OPR %x <<<<<<", intstat); + + if (intstat & HCINT_UE) { + ERR("unrecoverable error, controller disabled"); + + /* FIXME: be optimistic, hope that bug won't repeat + * often. Make some non-interrupt context restart the + * controller. Count and limit the retries though; + * either hardware or software errors can go forever... + */ + isp116x_reset(isp116x); + ret = -1; + return -1; + } + + if (intstat & HCINT_RHSC) { + got_rhsc = 1; + ret = 1; + /* When root hub or any of its ports is going + to come out of suspend, it may take more + than 10ms for status bits to stabilize. */ + wait_ms(20); + } + + if (intstat & HCINT_SO) { + ERR("schedule overrun"); + ret = -1; + } + + irqstat &= ~HCuPINT_OPR; + } + + return ret; +} + +#define PTD_NUM 64 /* it should be enougth... */ +struct ptd ptd[PTD_NUM]; +static inline int max_transfer_len(struct usb_device *dev, unsigned long pipe) +{ + return min(PTD_NUM * usb_maxpacket(dev, pipe), PTD_NUM * 16); +} + +/* Do an USB transfer + */ +static int isp116x_submit_job(struct usb_device *dev, unsigned long pipe, + int dir, void *buffer, int len) +{ + struct isp116x *isp116x = &isp116x_dev; + int type = usb_pipetype(pipe); + int epnum = usb_pipeendpoint(pipe); + int max = usb_maxpacket(dev, pipe); + int dir_out = usb_pipeout(pipe); + int speed_low = usb_pipeslow(pipe); + int i, done, stat, timeout, cc; + int retries = 10; + + DBG("------------------------------------------------"); + dump_msg(dev, pipe, buffer, len, "SUBMIT"); + DBG("------------------------------------------------"); + + if (isp116x->disabled) { + ERR("EPIPE"); + dev->status = USB_ST_CRC_ERR; + return -1; + } + + /* device pulled? Shortcut the action. */ + if (devgone == dev) { + ERR("ENODEV"); + dev->status = USB_ST_CRC_ERR; + return USB_ST_CRC_ERR; + } + + if (!max) { + ERR("pipesize for pipe %lx is zero", pipe); + dev->status = USB_ST_CRC_ERR; + return -1; + } + + if (type == PIPE_ISOCHRONOUS) { + ERR("isochronous transfers not supported"); + dev->status = USB_ST_CRC_ERR; + return -1; + } + + /* FIFO not empty? */ + if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL) { + ERR("****** FIFO not empty! ******"); + dev->status = USB_ST_BUF_ERR; + return -1; + } + + retry: + isp116x_write_reg32(isp116x, HCINTSTAT, 0xff); + + /* Prepare the PTD data */ + done = 0; + i = 0; + do { + ptd[i].count = PTD_CC_MSK | PTD_ACTIVE_MSK | + PTD_TOGGLE(usb_gettoggle(dev, epnum, dir_out)); + ptd[i].mps = PTD_MPS(max) | PTD_SPD(speed_low) | PTD_EP(epnum); + ptd[i].len = PTD_LEN(max > len - done ? len - done : max) | + PTD_DIR(dir); + ptd[i].faddr = PTD_FA(usb_pipedevice(pipe)); + + usb_dotoggle(dev, epnum, dir_out); + done += PTD_GET_LEN(&ptd[i]); + i++; + if (i >= PTD_NUM) { + ERR("****** Cannot pack buffer! ******"); + dev->status = USB_ST_BUF_ERR; + return -1; + } + } while (done < len); + ptd[i - 1].mps |= PTD_LAST_MSK; + + /* Pack data into FIFO ram */ + pack_fifo(isp116x, dev, pipe, ptd, i, buffer, len); +#ifdef EXTRA_DELAY + wait_ms(EXTRA_DELAY); +#endif + + /* Start the data transfer */ + + /* Allow more time for a BULK device to react - some are slow */ + if (usb_pipetype(pipe) == PIPE_BULK) + timeout = 5000; + else + timeout = 100; + + /* Wait for it to complete */ + for (;;) { + /* Check whether the controller is done */ + stat = isp116x_interrupt(isp116x); + + if (stat < 0) { + dev->status = USB_ST_CRC_ERR; + break; + } + if (stat > 0) + break; + + /* Check the timeout */ + if (--timeout) + udelay(1); + else { + ERR("CTL:TIMEOUT "); + stat = USB_ST_CRC_ERR; + break; + } + } + + /* We got an Root Hub Status Change interrupt */ + if (got_rhsc) { + isp116x_show_regs(isp116x); + + got_rhsc = 0; + + /* Abuse timeout */ + timeout = rh_check_port_status(isp116x); + if (timeout >= 0) { + /* + * FIXME! NOTE! AAAARGH! + * This is potentially dangerous because it assumes + * that only one device is ever plugged in! + */ + devgone = dev; + } + } + + /* Ok, now we can read transfer status */ + + /* FIFO not ready? */ + if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE)) { + ERR("****** FIFO not ready! ******"); + dev->status = USB_ST_BUF_ERR; + return -1; + } + + /* Unpack data from FIFO ram */ + cc = unpack_fifo(isp116x, dev, pipe, ptd, i, buffer, len); + + /* Mmm... sometime we get 0x0f as cc which is a non sense! + * Just retry the transfer... + */ + if (cc == 0x0f && retries-- > 0) { + usb_dotoggle(dev, epnum, dir_out); + goto retry; + } + + if (cc != TD_CC_NOERROR) { + DBG("****** completition code error %x ******", cc); + switch (cc) { + case TD_CC_BITSTUFFING: + dev->status = USB_ST_BIT_ERR; + break; + case TD_CC_STALL: + dev->status = USB_ST_STALLED; + break; + case TD_BUFFEROVERRUN: + case TD_BUFFERUNDERRUN: + dev->status = USB_ST_BUF_ERR; + break; + default: + dev->status = USB_ST_CRC_ERR; + } + return -cc; + } + + dump_msg(dev, pipe, buffer, len, "SUBMIT(ret)"); + + dev->status = 0; + return done; +} + +/* Adapted from au1x00_usb_ohci.c + */ +static int isp116x_submit_rh_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, + struct devrequest *cmd) +{ + struct isp116x *isp116x = &isp116x_dev; + u32 tmp = 0; + + int leni = transfer_len; + int len = 0; + int stat = 0; + u32 datab[4]; + u8 *data_buf = (u8 *) datab; + u16 bmRType_bReq; + u16 wValue; + u16 wIndex; + u16 wLength; + + if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { + INFO("Root-Hub submit IRQ: NOT implemented"); + return 0; + } + + bmRType_bReq = cmd->requesttype | (cmd->request << 8); + wValue = swap_16(cmd->value); + wIndex = swap_16(cmd->index); + wLength = swap_16(cmd->length); + + DBG("--- HUB ----------------------------------------"); + DBG("submit rh urb, req=%x val=%#x index=%#x len=%d", + bmRType_bReq, wValue, wIndex, wLength); + dump_msg(dev, pipe, buffer, transfer_len, "RH"); + DBG("------------------------------------------------"); + + switch (bmRType_bReq) { + case RH_GET_STATUS: + DBG("RH_GET_STATUS"); + + *(__u16 *) data_buf = swap_16(1); + len = 2; + break; + + case RH_GET_STATUS | RH_INTERFACE: + DBG("RH_GET_STATUS | RH_INTERFACE"); + + *(__u16 *) data_buf = swap_16(0); + len = 2; + break; + + case RH_GET_STATUS | RH_ENDPOINT: + DBG("RH_GET_STATUS | RH_ENDPOINT"); + + *(__u16 *) data_buf = swap_16(0); + len = 2; + break; + + case RH_GET_STATUS | RH_CLASS: + DBG("RH_GET_STATUS | RH_CLASS"); + + tmp = isp116x_read_reg32(isp116x, HCRHSTATUS); + + *(__u32 *) data_buf = swap_32(tmp & ~(RH_HS_CRWE | RH_HS_DRWE)); + len = 4; + break; + + case RH_GET_STATUS | RH_OTHER | RH_CLASS: + DBG("RH_GET_STATUS | RH_OTHER | RH_CLASS"); + + tmp = isp116x_read_reg32(isp116x, HCRHPORT1 + wIndex - 1); + *(__u32 *) data_buf = swap_32(tmp); + isp116x_show_regs(isp116x); + len = 4; + break; + + case RH_CLEAR_FEATURE | RH_ENDPOINT: + DBG("RH_CLEAR_FEATURE | RH_ENDPOINT"); + + switch (wValue) { + case RH_ENDPOINT_STALL: + DBG("C_HUB_ENDPOINT_STALL"); + len = 0; + break; + } + break; + + case RH_CLEAR_FEATURE | RH_CLASS: + DBG("RH_CLEAR_FEATURE | RH_CLASS"); + + switch (wValue) { + case RH_C_HUB_LOCAL_POWER: + DBG("C_HUB_LOCAL_POWER"); + len = 0; + break; + + case RH_C_HUB_OVER_CURRENT: + DBG("C_HUB_OVER_CURRENT"); + isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC); + len = 0; + break; + } + break; + + case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: + DBG("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS"); + + switch (wValue) { + case RH_PORT_ENABLE: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_CCS); + len = 0; + break; + + case RH_PORT_SUSPEND: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_POCI); + len = 0; + break; + + case RH_PORT_POWER: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_LSDA); + len = 0; + break; + + case RH_C_PORT_CONNECTION: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_CSC); + len = 0; + break; + + case RH_C_PORT_ENABLE: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_PESC); + len = 0; + break; + + case RH_C_PORT_SUSPEND: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_PSSC); + len = 0; + break; + + case RH_C_PORT_OVER_CURRENT: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_POCI); + len = 0; + break; + + case RH_C_PORT_RESET: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_PRSC); + len = 0; + break; + + default: + ERR("invalid wValue"); + stat = USB_ST_STALLED; + } + + isp116x_show_regs(isp116x); + + break; + + case RH_SET_FEATURE | RH_OTHER | RH_CLASS: + DBG("RH_SET_FEATURE | RH_OTHER | RH_CLASS"); + + switch (wValue) { + case RH_PORT_SUSPEND: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_PSS); + len = 0; + break; + + case RH_PORT_RESET: + /* Spin until any current reset finishes */ + while (1) { + tmp = + isp116x_read_reg32(isp116x, + HCRHPORT1 + wIndex - 1); + if (!(tmp & RH_PS_PRS)) + break; + wait_ms(1); + } + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_PRS); + wait_ms(10); + + len = 0; + break; + + case RH_PORT_POWER: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_PPS); + len = 0; + break; + + case RH_PORT_ENABLE: + isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, + RH_PS_PES); + len = 0; + break; + + default: + ERR("invalid wValue"); + stat = USB_ST_STALLED; + } + + isp116x_show_regs(isp116x); + + break; + + case RH_SET_ADDRESS: + DBG("RH_SET_ADDRESS"); + + rh_devnum = wValue; + len = 0; + break; + + case RH_GET_DESCRIPTOR: + DBG("RH_GET_DESCRIPTOR: %x, %d", wValue, wLength); + + switch (wValue) { + case (USB_DT_DEVICE << 8): /* device descriptor */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_dev_des), + wLength)); + data_buf = root_hub_dev_des; + break; + + case (USB_DT_CONFIG << 8): /* configuration descriptor */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_config_des), + wLength)); + data_buf = root_hub_config_des; + break; + + case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_str_index0), + wLength)); + data_buf = root_hub_str_index0; + break; + + case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */ + len = min_t(unsigned int, + leni, min_t(unsigned int, + sizeof(root_hub_str_index1), + wLength)); + data_buf = root_hub_str_index1; + break; + + default: + ERR("invalid wValue"); + stat = USB_ST_STALLED; + } + + break; + + case RH_GET_DESCRIPTOR | RH_CLASS: + DBG("RH_GET_DESCRIPTOR | RH_CLASS"); + + tmp = isp116x_read_reg32(isp116x, HCRHDESCA); + + data_buf[0] = 0x09; /* min length; */ + data_buf[1] = 0x29; + data_buf[2] = tmp & RH_A_NDP; + data_buf[3] = 0; + if (tmp & RH_A_PSM) /* per-port power switching? */ + data_buf[3] |= 0x01; + if (tmp & RH_A_NOCP) /* no overcurrent reporting? */ + data_buf[3] |= 0x10; + else if (tmp & RH_A_OCPM) /* per-port overcurrent rep? */ + data_buf[3] |= 0x08; + + /* Corresponds to data_buf[4-7] */ + datab[1] = 0; + data_buf[5] = (tmp & RH_A_POTPGT) >> 24; + + tmp = isp116x_read_reg32(isp116x, HCRHDESCB); + + data_buf[7] = tmp & RH_B_DR; + if (data_buf[2] < 7) + data_buf[8] = 0xff; + else { + data_buf[0] += 2; + data_buf[8] = (tmp & 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)); + break; + + case RH_GET_CONFIGURATION: + DBG("RH_GET_CONFIGURATION"); + + *(__u8 *) data_buf = 0x01; + len = 1; + break; + + case RH_SET_CONFIGURATION: + DBG("RH_SET_CONFIGURATION"); + + isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPSC); + len = 0; + break; + + default: + ERR("*** *** *** unsupported root hub command *** *** ***"); + stat = USB_ST_STALLED; + } + + len = min_t(int, len, leni); + if (buffer != data_buf) + memcpy(buffer, data_buf, len); + + dev->act_len = len; + dev->status = stat; + DBG("dev act_len %d, status %d", dev->act_len, dev->status); + + dump_msg(dev, pipe, buffer, transfer_len, "RH(ret)"); + + return stat; +} + +/* --- Transfer functions -------------------------------------------------- */ + +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len, int interval) +{ + DBG("dev=%p pipe=%#lx buf=%p size=%d int=%d", + dev, pipe, buffer, len, interval); + + return -1; +} + +int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len, struct devrequest *setup) +{ + int devnum = usb_pipedevice(pipe); + int epnum = usb_pipeendpoint(pipe); + int max = max_transfer_len(dev, pipe); + int dir_in = usb_pipein(pipe); + int done, ret; + + /* Control message is for the HUB? */ + if (devnum == rh_devnum) + return isp116x_submit_rh_msg(dev, pipe, buffer, len, setup); + + /* Ok, no HUB message so send the message to the device */ + + /* Setup phase */ + DBG("--- SETUP PHASE --------------------------------"); + usb_settoggle(dev, epnum, 1, 0); + ret = isp116x_submit_job(dev, pipe, + PTD_DIR_SETUP, + setup, sizeof(struct devrequest)); + if (ret < 0) { + DBG("control setup phase error (ret = %d", ret); + return -1; + } + + /* Data phase */ + DBG("--- DATA PHASE ---------------------------------"); + done = 0; + usb_settoggle(dev, epnum, !dir_in, 1); + while (done < len) { + ret = isp116x_submit_job(dev, pipe, + dir_in ? PTD_DIR_IN : PTD_DIR_OUT, + (__u8 *) buffer + done, + max > len - done ? len - done : max); + if (ret < 0) { + DBG("control data phase error (ret = %d)", ret); + return -1; + } + done += ret; + + if (dir_in && ret < max) /* short packet */ + break; + } + + /* Status phase */ + DBG("--- STATUS PHASE -------------------------------"); + usb_settoggle(dev, epnum, !dir_in, 1); + ret = isp116x_submit_job(dev, pipe, + !dir_in ? PTD_DIR_IN : PTD_DIR_OUT, NULL, 0); + if (ret < 0) { + DBG("control status phase error (ret = %d", ret); + return -1; + } + + dev->act_len = done; + + dump_msg(dev, pipe, buffer, len, "DEV(ret)"); + + return done; +} + +int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int len) +{ + int dir_out = usb_pipeout(pipe); + int max = max_transfer_len(dev, pipe); + int done, ret; + + DBG("--- BULK ---------------------------------------"); + DBG("dev=%ld pipe=%ld buf=%p size=%d dir_out=%d", + usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out); + + done = 0; + while (done < len) { + ret = isp116x_submit_job(dev, pipe, + !dir_out ? PTD_DIR_IN : PTD_DIR_OUT, + (__u8 *) buffer + done, + max > len - done ? len - done : max); + if (ret < 0) { + DBG("error on bulk message (ret = %d)", ret); + return -1; + } + + done += ret; + + if (!dir_out && ret < max) /* short packet */ + break; + } + + dev->act_len = done; + + return 0; +} + +/* --- Basic functions ----------------------------------------------------- */ + +static int isp116x_sw_reset(struct isp116x *isp116x) +{ + int retries = 15; + int ret = 0; + + DBG(""); + + isp116x->disabled = 1; + + isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC); + isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR); + while (--retries) { + /* It usually resets within 1 ms */ + wait_ms(1); + if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR)) + break; + } + if (!retries) { + ERR("software reset timeout"); + ret = -1; + } + return ret; +} + +static int isp116x_reset(struct isp116x *isp116x) +{ + unsigned long t; + u16 clkrdy = 0; + int ret, timeout = 15 /* ms */ ; + + DBG(""); + + ret = isp116x_sw_reset(isp116x); + if (ret) + return ret; + + for (t = 0; t < timeout; t++) { + clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY; + if (clkrdy) + break; + wait_ms(1); + } + if (!clkrdy) { + ERR("clock not ready after %dms", timeout); + /* After sw_reset the clock won't report to be ready, if + H_WAKEUP pin is high. */ + ERR("please make sure that the H_WAKEUP pin is pulled low!"); + ret = -1; + } + return ret; +} + +static void isp116x_stop(struct isp116x *isp116x) +{ + u32 val; + + DBG(""); + + isp116x_write_reg16(isp116x, HCuPINTENB, 0); + + /* Switch off ports' power, some devices don't come up + after next 'start' without this */ + val = isp116x_read_reg32(isp116x, HCRHDESCA); + val &= ~(RH_A_NPS | RH_A_PSM); + isp116x_write_reg32(isp116x, HCRHDESCA, val); + isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS); + + isp116x_sw_reset(isp116x); +} + +/* + * Configure the chip. The chip must be successfully reset by now. + */ +static int isp116x_start(struct isp116x *isp116x) +{ + struct isp116x_platform_data *board = isp116x->board; + u32 val; + + DBG(""); + + /* Clear interrupt status and disable all interrupt sources */ + isp116x_write_reg16(isp116x, HCuPINT, 0xff); + isp116x_write_reg16(isp116x, HCuPINTENB, 0); + + isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE); + isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE); + + /* Hardware configuration */ + val = HCHWCFG_DBWIDTH(1); + if (board->sel15Kres) + val |= HCHWCFG_15KRSEL; + /* Remote wakeup won't work without working clock */ + if (board->remote_wakeup_enable) + val |= HCHWCFG_CLKNOTSTOP; + if (board->oc_enable) + val |= HCHWCFG_ANALOG_OC; + isp116x_write_reg16(isp116x, HCHWCFG, val); + + /* --- Root hub configuration */ + val = (25 << 24) & RH_A_POTPGT; + /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to + be always set. Yet, instead, we request individual port + power switching. */ + val |= RH_A_PSM; + /* Report overcurrent per port */ + val |= RH_A_OCPM; + isp116x_write_reg32(isp116x, HCRHDESCA, val); + isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA); + + val = RH_B_PPCM; + isp116x_write_reg32(isp116x, HCRHDESCB, val); + isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB); + + val = 0; + if (board->remote_wakeup_enable) + val |= RH_HS_DRWE; + isp116x_write_reg32(isp116x, HCRHSTATUS, val); + isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS); + + isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf); + + /* Go operational */ + val = HCCONTROL_USB_OPER; + if (board->remote_wakeup_enable) + val |= HCCONTROL_RWE; + isp116x_write_reg32(isp116x, HCCONTROL, val); + + /* Disable ports to avoid race in device enumeration */ + isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS); + isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS); + + isp116x_show_regs(isp116x); + + isp116x->disabled = 0; + + return 0; +} + +/* --- Init functions ------------------------------------------------------ */ + +int isp116x_check_id(struct isp116x *isp116x) +{ + int val; + + val = isp116x_read_reg16(isp116x, HCCHIPID); + if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) { + ERR("invalid chip ID %04x", val); + return -1; + } + + return 0; +} + +int usb_lowlevel_init(void) +{ + struct isp116x *isp116x = &isp116x_dev; + + DBG(""); + + /* Init device registers addr */ + isp116x->addr_reg = (u16 *) ISP116X_HCD_ADDR; + isp116x->data_reg = (u16 *) ISP116X_HCD_DATA; + + /* Setup specific board settings */ +#ifdef ISP116X_HCD_SEL15kRES + isp116x_board.sel15Kres = 1; +#endif +#ifdef ISP116X_HCD_OC_ENABLE + isp116x_board.oc_enable = 1; +#endif +#ifdef ISP116X_HCD_REMOTE_WAKEUP_ENABLE + isp116x_board.remote_wakeup_enable = 1; +#endif + isp116x->board = &isp116x_board; + + /* Try to get ISP116x silicon chip ID */ + if (isp116x_check_id(isp116x) < 0) + return -1; + + isp116x->disabled = 1; + isp116x->sleeping = 0; + + isp116x_reset(isp116x); + isp116x_start(isp116x); + + return 0; +} + +int usb_lowlevel_stop(void) +{ + struct isp116x *isp116x = &isp116x_dev; + + DBG(""); + + if (!isp116x->disabled) + isp116x_stop(isp116x); + + return 0; +} + +#endif /* CONFIG_USB_ISP116X_HCD */ diff --git a/drivers/isp116x.h b/drivers/isp116x.h new file mode 100644 index 0000000..a3ce3b5 --- /dev/null +++ b/drivers/isp116x.h @@ -0,0 +1,489 @@ +/* + * ISP116x register declarations and HCD data structures + * + * Copyright (C) 2007 Rodolfo Giometti + * Copyright (C) 2007 Eurotech S.p.A. + * Copyright (C) 2005 Olav Kongas + * Portions: + * Copyright (C) 2004 Lothar Wassmann + * Copyright (C) 2004 Psion Teklogix + * Copyright (C) 2004 David Brownell + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifdef DEBUG +#define DBG(fmt, args...) \ + printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args) +#else +#define DBG(fmt, args...) do {} while (0) +#endif + +#ifdef VERBOSE +# define VDBG DBG +#else +# define VDBG(fmt, args...) do {} while (0) +#endif + +#define ERR(fmt, args...) \ + printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args) +#define WARN(fmt, args...) \ + printf("isp116x: %s: " fmt "\n" , __FUNCTION__ , ## args) +#define INFO(fmt, args...) \ + printf("isp116x: " fmt "\n" , ## args) + +/* ------------------------------------------------------------------------- */ + +/* us of 1ms frame */ +#define MAX_LOAD_LIMIT 850 + +/* Full speed: max # of bytes to transfer for a single urb + at a time must be < 1024 && must be multiple of 64. + 832 allows transfering 4kiB within 5 frames. */ +#define MAX_TRANSFER_SIZE_FULLSPEED 832 + +/* Low speed: there is no reason to schedule in very big + chunks; often the requested long transfers are for + string descriptors containing short strings. */ +#define MAX_TRANSFER_SIZE_LOWSPEED 64 + +/* Bytetime (us), a rough indication of how much time it + would take to transfer a byte of useful data over USB */ +#define BYTE_TIME_FULLSPEED 1 +#define BYTE_TIME_LOWSPEED 20 + +/* Buffer sizes */ +#define ISP116x_BUF_SIZE 4096 +#define ISP116x_ITL_BUFSIZE 0 +#define ISP116x_ATL_BUFSIZE ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE)) + +#define ISP116x_WRITE_OFFSET 0x80 + +/* --- ISP116x registers/bits ---------------------------------------------- */ + +#define HCREVISION 0x00 +#define HCCONTROL 0x01 +#define HCCONTROL_HCFS (3 << 6) /* host controller + functional state */ +#define HCCONTROL_USB_RESET (0 << 6) +#define HCCONTROL_USB_RESUME (1 << 6) +#define HCCONTROL_USB_OPER (2 << 6) +#define HCCONTROL_USB_SUSPEND (3 << 6) +#define HCCONTROL_RWC (1 << 9) /* remote wakeup connected */ +#define HCCONTROL_RWE (1 << 10) /* remote wakeup enable */ +#define HCCMDSTAT 0x02 +#define HCCMDSTAT_HCR (1 << 0) /* host controller reset */ +#define HCCMDSTAT_SOC (3 << 16) /* scheduling overrun count */ +#define HCINTSTAT 0x03 +#define HCINT_SO (1 << 0) /* scheduling overrun */ +#define HCINT_WDH (1 << 1) /* writeback of done_head */ +#define HCINT_SF (1 << 2) /* start frame */ +#define HCINT_RD (1 << 3) /* resume detect */ +#define HCINT_UE (1 << 4) /* unrecoverable error */ +#define HCINT_FNO (1 << 5) /* frame number overflow */ +#define HCINT_RHSC (1 << 6) /* root hub status change */ +#define HCINT_OC (1 << 30) /* ownership change */ +#define HCINT_MIE (1 << 31) /* master interrupt enable */ +#define HCINTENB 0x04 +#define HCINTDIS 0x05 +#define HCFMINTVL 0x0d +#define HCFMREM 0x0e +#define HCFMNUM 0x0f +#define HCLSTHRESH 0x11 +#define HCRHDESCA 0x12 +#define RH_A_NDP (0x3 << 0) /* # downstream ports */ +#define RH_A_PSM (1 << 8) /* power switching mode */ +#define RH_A_NPS (1 << 9) /* no power switching */ +#define RH_A_DT (1 << 10) /* device type (mbz) */ +#define RH_A_OCPM (1 << 11) /* overcurrent protection + mode */ +#define RH_A_NOCP (1 << 12) /* no overcurrent protection */ +#define RH_A_POTPGT (0xff << 24) /* power on -> power good + time */ +#define HCRHDESCB 0x13 +#define RH_B_DR (0xffff << 0) /* device removable flags */ +#define RH_B_PPCM (0xffff << 16) /* port power control mask */ +#define HCRHSTATUS 0x14 +#define RH_HS_LPS (1 << 0) /* local power status */ +#define RH_HS_OCI (1 << 1) /* over current indicator */ +#define RH_HS_DRWE (1 << 15) /* device remote wakeup + enable */ +#define RH_HS_LPSC (1 << 16) /* local power status change */ +#define RH_HS_OCIC (1 << 17) /* over current indicator + change */ +#define RH_HS_CRWE (1 << 31) /* clear remote wakeup + enable */ +#define HCRHPORT1 0x15 +#define RH_PS_CCS (1 << 0) /* current connect status */ +#define RH_PS_PES (1 << 1) /* port enable status */ +#define RH_PS_PSS (1 << 2) /* port suspend status */ +#define RH_PS_POCI (1 << 3) /* port over current + indicator */ +#define RH_PS_PRS (1 << 4) /* port reset status */ +#define RH_PS_PPS (1 << 8) /* port power status */ +#define RH_PS_LSDA (1 << 9) /* low speed device attached */ +#define RH_PS_CSC (1 << 16) /* connect status change */ +#define RH_PS_PESC (1 << 17) /* port enable status change */ +#define RH_PS_PSSC (1 << 18) /* port suspend status + change */ +#define RH_PS_OCIC (1 << 19) /* over current indicator + change */ +#define RH_PS_PRSC (1 << 20) /* port reset status change */ +#define HCRHPORT_CLRMASK (0x1f << 16) +#define HCRHPORT2 0x16 +#define HCHWCFG 0x20 +#define HCHWCFG_15KRSEL (1 << 12) +#define HCHWCFG_CLKNOTSTOP (1 << 11) +#define HCHWCFG_ANALOG_OC (1 << 10) +#define HCHWCFG_DACK_MODE (1 << 8) +#define HCHWCFG_EOT_POL (1 << 7) +#define HCHWCFG_DACK_POL (1 << 6) +#define HCHWCFG_DREQ_POL (1 << 5) +#define HCHWCFG_DBWIDTH_MASK (0x03 << 3) +#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK) +#define HCHWCFG_INT_POL (1 << 2) +#define HCHWCFG_INT_TRIGGER (1 << 1) +#define HCHWCFG_INT_ENABLE (1 << 0) +#define HCDMACFG 0x21 +#define HCDMACFG_BURST_LEN_MASK (0x03 << 5) +#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK) +#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0) +#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1) +#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2) +#define HCDMACFG_DMA_ENABLE (1 << 4) +#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1) +#define HCDMACFG_CTR_SEL (1 << 2) +#define HCDMACFG_ITLATL_SEL (1 << 1) +#define HCDMACFG_DMA_RW_SELECT (1 << 0) +#define HCXFERCTR 0x22 +#define HCuPINT 0x24 +#define HCuPINT_SOF (1 << 0) +#define HCuPINT_ATL (1 << 1) +#define HCuPINT_AIIEOT (1 << 2) +#define HCuPINT_OPR (1 << 4) +#define HCuPINT_SUSP (1 << 5) +#define HCuPINT_CLKRDY (1 << 6) +#define HCuPINTENB 0x25 +#define HCCHIPID 0x27 +#define HCCHIPID_MASK 0xff00 +#define HCCHIPID_MAGIC 0x6100 +#define HCSCRATCH 0x28 +#define HCSWRES 0x29 +#define HCSWRES_MAGIC 0x00f6 +#define HCITLBUFLEN 0x2a +#define HCATLBUFLEN 0x2b +#define HCBUFSTAT 0x2c +#define HCBUFSTAT_ITL0_FULL (1 << 0) +#define HCBUFSTAT_ITL1_FULL (1 << 1) +#define HCBUFSTAT_ATL_FULL (1 << 2) +#define HCBUFSTAT_ITL0_DONE (1 << 3) +#define HCBUFSTAT_ITL1_DONE (1 << 4) +#define HCBUFSTAT_ATL_DONE (1 << 5) +#define HCRDITL0LEN 0x2d +#define HCRDITL1LEN 0x2e +#define HCITLPORT 0x40 +#define HCATLPORT 0x41 + +/* PTD accessor macros. */ +#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0) +#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK) +#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10) +#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK) +#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11) +#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK) +#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12) +#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK) +#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0) +#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK) +#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10) +#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK) +#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11) +#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK) +#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12) +#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK) +#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0) +#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK) +#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10) +#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK) +#define PTD_GET_B5_5(p) (((p)->len & PTD_B5_5_MSK) >> 13) +#define PTD_B5_5(v) (((v) << 13) & PTD_B5_5_MSK) +#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0) +#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK) +#define PTD_GET_FMT(p) (((p)->faddr & PTD_FMT_MSK) >> 7) +#define PTD_FMT(v) (((v) << 7) & PTD_FMT_MSK) + +/* Hardware transfer status codes -- CC from ptd->count */ +#define TD_CC_NOERROR 0x00 +#define TD_CC_CRC 0x01 +#define TD_CC_BITSTUFFING 0x02 +#define TD_CC_DATATOGGLEM 0x03 +#define TD_CC_STALL 0x04 +#define TD_DEVNOTRESP 0x05 +#define TD_PIDCHECKFAIL 0x06 +#define TD_UNEXPECTEDPID 0x07 +#define TD_DATAOVERRUN 0x08 +#define TD_DATAUNDERRUN 0x09 + /* 0x0A, 0x0B reserved for hardware */ +#define TD_BUFFEROVERRUN 0x0C +#define TD_BUFFERUNDERRUN 0x0D + /* 0x0E, 0x0F reserved for HCD */ +#define TD_NOTACCESSED 0x0F + +/* ------------------------------------------------------------------------- */ + +#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */ +#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE) + +/* Philips transfer descriptor */ +struct ptd { + u16 count; +#define PTD_COUNT_MSK (0x3ff << 0) +#define PTD_TOGGLE_MSK (1 << 10) +#define PTD_ACTIVE_MSK (1 << 11) +#define PTD_CC_MSK (0xf << 12) + u16 mps; +#define PTD_MPS_MSK (0x3ff << 0) +#define PTD_SPD_MSK (1 << 10) +#define PTD_LAST_MSK (1 << 11) +#define PTD_EP_MSK (0xf << 12) + u16 len; +#define PTD_LEN_MSK (0x3ff << 0) +#define PTD_DIR_MSK (3 << 10) +#define PTD_DIR_SETUP (0) +#define PTD_DIR_OUT (1) +#define PTD_DIR_IN (2) +#define PTD_B5_5_MSK (1 << 13) + u16 faddr; +#define PTD_FA_MSK (0x7f << 0) +#define PTD_FMT_MSK (1 << 7) +} __attribute__ ((packed, aligned(2))); + +struct isp116x_ep { + struct usb_device *udev; + struct ptd ptd; + + u8 maxpacket; + u8 epnum; + u8 nextpid; + + u16 length; /* of current packet */ + unsigned char *data; /* to databuf */ + + u16 error_count; +}; + +/* URB struct */ +#define N_URB_TD 48 +#define URB_DEL 1 +typedef struct { + struct isp116x_ep *ed; + void *transfer_buffer; /* (in) associated data buffer */ + int actual_length; /* (return) actual transfer length */ + unsigned long pipe; /* (in) pipe information */ +#if 0 + int state; +#endif +} urb_priv_t; + +struct isp116x_platform_data { + /* Enable internal resistors on downstream ports */ + unsigned sel15Kres:1; + /* On-chip overcurrent detection */ + unsigned oc_enable:1; + /* Enable wakeup by devices on usb bus (e.g. wakeup + by attachment/detachment or by device activity + such as moving a mouse). When chosen, this option + prevents stopping internal clock, increasing + thereby power consumption in suspended state. */ + unsigned remote_wakeup_enable:1; +}; + +struct isp116x { + u16 *addr_reg; + u16 *data_reg; + + struct isp116x_platform_data *board; + + struct dentry *dentry; + unsigned long stat1, stat2, stat4, stat8, stat16; + + /* Status flags */ + unsigned disabled:1; + unsigned sleeping:1; + + /* Root hub registers */ + u32 rhdesca; + u32 rhdescb; + u32 rhstatus; + u32 rhport[2]; + + /* Schedule for the current frame */ + struct isp116x_ep *atl_active; + int atl_buflen; + int atl_bufshrt; + int atl_last_dir; + int atl_finishing; +}; + +/* ------------------------------------------------- */ + +/* Inter-io delay (ns). The chip is picky about access timings; it + * expects at least: + * 150ns delay between consecutive accesses to DATA_REG, + * 300ns delay between access to ADDR_REG and DATA_REG + * OE, WE MUST NOT be changed during these intervals + */ +#if defined(UDELAY) +#define isp116x_delay(h,d) udelay(d) +#else +#define isp116x_delay(h,d) do {} while (0) +#endif + +static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg) +{ + writew(reg & 0xff, isp116x->addr_reg); + isp116x_delay(isp116x, UDELAY); +} + +static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val) +{ + writew(val, isp116x->data_reg); + isp116x_delay(isp116x, UDELAY); +} + +static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val) +{ + __raw_writew(val, isp116x->data_reg); + isp116x_delay(isp116x, UDELAY); +} + +static inline u16 isp116x_read_data16(struct isp116x *isp116x) +{ + u16 val; + + val = readw(isp116x->data_reg); + isp116x_delay(isp116x, UDELAY); + return val; +} + +static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x) +{ + u16 val; + + val = __raw_readw(isp116x->data_reg); + isp116x_delay(isp116x, UDELAY); + return val; +} + +static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val) +{ + writew(val & 0xffff, isp116x->data_reg); + isp116x_delay(isp116x, UDELAY); + writew(val >> 16, isp116x->data_reg); + isp116x_delay(isp116x, UDELAY); +} + +static inline u32 isp116x_read_data32(struct isp116x *isp116x) +{ + u32 val; + + val = (u32) readw(isp116x->data_reg); + isp116x_delay(isp116x, UDELAY); + val |= ((u32) readw(isp116x->data_reg)) << 16; + isp116x_delay(isp116x, UDELAY); + return val; +} + +/* Let's keep register access functions out of line. Hint: + we wait at least 150 ns at every access. +*/ +static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg) +{ + isp116x_write_addr(isp116x, reg); + return isp116x_read_data16(isp116x); +} + +static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg) +{ + isp116x_write_addr(isp116x, reg); + return isp116x_read_data32(isp116x); +} + +static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg, + unsigned val) +{ + isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET); + isp116x_write_data16(isp116x, (u16) (val & 0xffff)); +} + +static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg, + unsigned val) +{ + isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET); + isp116x_write_data32(isp116x, (u32) val); +} + +/* --- USB HUB constants (not OHCI-specific; see hub.h) -------------------- */ + +/* destination of request */ +#define RH_INTERFACE 0x01 +#define RH_ENDPOINT 0x02 +#define RH_OTHER 0x03 + +#define RH_CLASS 0x20 +#define RH_VENDOR 0x40 + +/* Requests: bRequest << 8 | bmRequestType */ +#define RH_GET_STATUS 0x0080 +#define RH_CLEAR_FEATURE 0x0100 +#define RH_SET_FEATURE 0x0300 +#define RH_SET_ADDRESS 0x0500 +#define RH_GET_DESCRIPTOR 0x0680 +#define RH_SET_DESCRIPTOR 0x0700 +#define RH_GET_CONFIGURATION 0x0880 +#define RH_SET_CONFIGURATION 0x0900 +#define RH_GET_STATE 0x0280 +#define RH_GET_INTERFACE 0x0A80 +#define RH_SET_INTERFACE 0x0B00 +#define RH_SYNC_FRAME 0x0C80 +/* Our Vendor Specific Request */ +#define RH_SET_EP 0x2000 + +/* Hub port features */ +#define RH_PORT_CONNECTION 0x00 +#define RH_PORT_ENABLE 0x01 +#define RH_PORT_SUSPEND 0x02 +#define RH_PORT_OVER_CURRENT 0x03 +#define RH_PORT_RESET 0x04 +#define RH_PORT_POWER 0x08 +#define RH_PORT_LOW_SPEED 0x09 + +#define RH_C_PORT_CONNECTION 0x10 +#define RH_C_PORT_ENABLE 0x11 +#define RH_C_PORT_SUSPEND 0x12 +#define RH_C_PORT_OVER_CURRENT 0x13 +#define RH_C_PORT_RESET 0x14 + +/* Hub features */ +#define RH_C_HUB_LOCAL_POWER 0x00 +#define RH_C_HUB_OVER_CURRENT 0x01 + +#define RH_DEVICE_REMOTE_WAKEUP 0x00 +#define RH_ENDPOINT_STALL 0x01 + +#define RH_ACK 0x01 +#define RH_REQ_ERR -1 +#define RH_NACK 0x00 diff --git a/include/usb.h b/include/usb.h index 419a7e3..504ccc4 100644 --- a/include/usb.h +++ b/include/usb.h @@ -169,7 +169,10 @@ struct usb_device { * this is how the lowlevel part communicate with the outer world */ -#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || defined (CONFIG_USB_SL811HS) || defined(CONFIG_USB_OHCI_NEW) +#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || \ + defined(CONFIG_USB_OHCI_NEW) || defined (CONFIG_USB_SL811HS) || \ + defined(CONFIG_USB_ISP116X_HCD) + int usb_lowlevel_init(void); int usb_lowlevel_stop(void); int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,int transfer_len); -- cgit v1.1 From d98c0885ad617fccf21e7c26ef8cb728fbfb2459 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Mon, 23 Apr 2007 13:10:52 +0200 Subject: USB: (Another) delay for crappy USB keys. Some USB keys are slow in giving back an answer when the Root HUB enables power lines. Signed-off-by: Rodolfo Giometti --- drivers/usb_ohci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index 1c3f622..70cb6a3 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -1169,7 +1169,9 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); WR_RH_PORTSTAT (RH_PS_PRS); OK (0); case (RH_PORT_POWER): - WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); + WR_RH_PORTSTAT (RH_PS_PPS ); + wait_ms(100); + OK (0); case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/ if (RD_RH_PORTSTAT & RH_PS_CCS) WR_RH_PORTSTAT (RH_PS_PES ); -- cgit v1.1 From 3a619dd7bed03e8b4d22a3911f90fd12af5376c2 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Mon, 7 May 2007 16:43:56 +0200 Subject: Fix an ancient CHANGELOG conflict --- CHANGELOG | 18 ------------------ CHANGELOG-before-U-Boot-1.1.5 | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index c15cf6a..184e941 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4045,27 +4045,9 @@ Date: Sat Oct 28 02:29:14 2006 +0200 Enable commandline editing and hush shell on all TQM boards. -<<<<<<< master -* Code cleanup - -* Various USB related patches - - Add support for mpc8xx USB device. - - Add support for Common Device Class - Abstract Control Model USB console. - - Add support for flow control in USB slave devices. - - Add support for switching between gserial and cdc_acm using environment. - - Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h - - Update usbcore slightly to ease host enumeration. - - Fix non-portable endian problems in usbdcore and usbdcore_ep0. - - Add AdderUSB_config as a defconfig to enable usage of the USB console - by default with the Adder87x U-Boot port. - Patch by Bryan O'Donoghue , 29 May 2006 - -* Cleanup trab board for GCC-4.x -======= commit 8078f1a5f63a739b8533478f6c2b62fb1e2f79d7 Author: Wolfgang Denk Date: Sat Oct 28 02:28:02 2006 +0200 ->>>>>>> trunk README says CFG_AUTO_COMPLETE, but ocde uses CONFIG_AUTO_COMPLETE diff --git a/CHANGELOG-before-U-Boot-1.1.5 b/CHANGELOG-before-U-Boot-1.1.5 index 727a7b6..2404148 100644 --- a/CHANGELOG-before-U-Boot-1.1.5 +++ b/CHANGELOG-before-U-Boot-1.1.5 @@ -438,6 +438,20 @@ Changes for U-Boot 1.1.5: * Call serial_initialize() before first debug() is used. +* Code cleanup + +* Various USB related patches + - Add support for mpc8xx USB device. + - Add support for Common Device Class - Abstract Control Model USB console. + - Add support for flow control in USB slave devices. + - Add support for switching between gserial and cdc_acm using environment. + - Minor changes to usbdcore_omap1510.c usbdcore_omap1510.h + - Update usbcore slightly to ease host enumeration. + - Fix non-portable endian problems in usbdcore and usbdcore_ep0. + - Add AdderUSB_config as a defconfig to enable usage of the USB console + by default with the Adder87x U-Boot port. + Patch by Bryan O'Donoghue , 29 May 2006 + * Cleanup trab board for GCC-4.x * VoiceBlue update: use new MTD flash partitioning methods, use more -- cgit v1.1 From 8a364f0970de49949d635e60accf463c6443ef8c Mon Sep 17 00:00:00 2001 From: "Nikita V. Youshchenko" Date: Wed, 23 May 2007 12:45:25 +0400 Subject: add missing 'console' var to default mpc8349itx config Signed-off-by: Kim Phillips --- include/configs/MPC8349ITX.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/configs/MPC8349ITX.h b/include/configs/MPC8349ITX.h index 906339e..1bdbcdc 100644 --- a/include/configs/MPC8349ITX.h +++ b/include/configs/MPC8349ITX.h @@ -289,6 +289,7 @@ boards, we say we have two, but don't display a message if we find only one. */ #define CFG_BAUDRATE_TABLE \ {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 115200} +#define CONFIG_CONSOLE ttyS0 #define CONFIG_BAUDRATE 115200 #define CFG_NS16550_COM1 (CFG_IMMR + 0x4500) @@ -670,9 +671,10 @@ boards, we say we have two, but don't display a message if we find only one. */ " ip=" MK_STR(CONFIG_IPADDR) ":" MK_STR(CONFIG_SERVERIP) ":" \ MK_STR(CONFIG_GATEWAYIP) ":" MK_STR(CONFIG_NETMASK) ":" \ MK_STR(CONFIG_HOSTNAME) ":" MK_STR(CONFIG_NETDEV) ":off" \ - " console=ttyS0," MK_STR(CONFIG_BAUDRATE) + " console=" MK_STR(CONFIG_CONSOLE) "," MK_STR(CONFIG_BAUDRATE) #define CONFIG_EXTRA_ENV_SETTINGS \ + "console=" MK_STR(CONFIG_CONSOLE) "\0" \ "netdev=" MK_STR(CONFIG_NETDEV) "\0" \ "uboot=" MK_STR(CONFIG_UBOOTPATH) "\0" \ "tftpflash=tftpboot $loadaddr $uboot; " \ -- cgit v1.1 From 5b1313fb2758ffce8b624457f777d8cc6709608d Mon Sep 17 00:00:00 2001 From: "Nikita V. Youshchenko" Date: Wed, 23 May 2007 12:45:19 +0400 Subject: fix compilation problem for mpc8349itx CFG_RAMBOOT Current include/configs/MPC8349ITX.h does contain some support for building image that will be started from memory (without putting in into flash). It could be triggered by building with TEXT_BASE set to a low value. However, this support is incomplete: using of low TEXT_BASE causes defining configuration macros in inconsistent way, which later leads to compilation errors. In particular. flash support is being disabled, but then flash structures get referenced. This patch fixes this, making it possible to build with low TEXT_BASE. Signed-Off-By: Nikita Youshchenko Signed-off-by: Kim Phillips --- include/configs/MPC8349ITX.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/configs/MPC8349ITX.h b/include/configs/MPC8349ITX.h index 1bdbcdc..0ff6580 100644 --- a/include/configs/MPC8349ITX.h +++ b/include/configs/MPC8349ITX.h @@ -409,6 +409,7 @@ boards, we say we have two, but don't display a message if we find only one. */ #define CFG_ENV_SIZE 0x2000 #else #define CFG_NO_FLASH /* Flash is not usable now */ + #undef CFG_FLASH_CFI_DRIVER #define CFG_ENV_IS_NOWHERE /* Store ENV in memory only */ #define CFG_ENV_ADDR (CFG_MONITOR_BASE - 0x1000) #define CFG_ENV_SIZE 0x2000 @@ -437,7 +438,14 @@ boards, we say we have two, but don't display a message if we find only one. */ #define CONFIG_COMMANDS_I2C 0 #endif -#define CONFIG_COMMANDS (CONFIG_CMD_DFL | \ +#ifdef CFG_NO_FLASH +#define CONFIG_COMMANDS_DEFAULT (CONFIG_CMD_DFL & ~(CFG_CMD_FLASH | \ + CFG_CMD_IMLS)) +#else +#define CONFIG_COMMANDS_DEFAULT CONFIG_CMD_DFL +#endif + +#define CONFIG_COMMANDS (CONFIG_COMMANDS_DEFAULT | \ CONFIG_COMMANDS_CF | \ CFG_CMD_NET | \ CFG_CMD_PING | \ -- cgit v1.1 From 09444143670c9c2243cb7aba9f70b3713d33bed1 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Wed, 6 Jun 2007 10:08:12 +0200 Subject: Change duplicate usb_cpu_init_fail to usb_board_init_fail Thanks to Liew Tsi Chung for pointing this out. Signed-off-by: Markus Klotzbuecher --- drivers/usb_ohci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb_ohci.h b/drivers/usb_ohci.h index 95fbc44..d2b03c0 100644 --- a/drivers/usb_ohci.h +++ b/drivers/usb_ohci.h @@ -10,7 +10,7 @@ /* functions for doing board or CPU specific setup/cleanup */ extern int usb_board_init(void); extern int usb_board_stop(void); -extern int usb_cpu_init_fail(void); +extern int usb_board_init_fail(void); extern int usb_cpu_init(void); extern int usb_cpu_stop(void); -- cgit v1.1 From 9a1d00fa47c1e05e3fdb60b33213af4e18d4c18e Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Wed, 6 Jun 2007 10:08:12 +0200 Subject: ISP116x: delay for crappy USB keys Using some (very) slow USB keys cause the USB host controller buffers are not ready to be read by the CPU so we need an extra delay before reading the USB storage data. Signed-off-by: Rodolfo Giometti --- drivers/isp116x-hcd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/isp116x-hcd.c b/drivers/isp116x-hcd.c index d57b8ec..8e2bc7a 100644 --- a/drivers/isp116x-hcd.c +++ b/drivers/isp116x-hcd.c @@ -550,6 +550,7 @@ static int isp116x_interrupt(struct isp116x *isp116x) if (irqstat & HCuPINT_ATL) { DBG(">>>>>> HCuPINT_ATL <<<<<<"); + udelay(500); ret = 1; } -- cgit v1.1 From fdcfaa1b02268b2899e374b35adf936c911a47eb Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Wed, 6 Jun 2007 10:08:13 +0200 Subject: USB event poll support This patch adds USB event poll support, which could be used in usbkbd and other usb devices driver when the asynchronous interrupt processing is supported. Signed-off-by: Zhang Wei Date: Wed, 6 Jun 2007 10:08:14 +0200 Subject: USB PCI-OHCI, interrupt pipe and usb event poll support This patch added USB PCI-OHCI chips support, interrupt pipe support and usb event poll support. For supporting the USB interrupt pipe, the globe urb_priv is moved to purb in ed struct. Now, we can process several urbs at one time. The interrupt pipe support codes are ported from Linux kernel 2.4. Signed-off-by: Zhang Wei --- drivers/usb_ohci.c | 310 ++++++++++++++++++++++++++++++++++++++++++++--------- drivers/usb_ohci.h | 12 ++- 2 files changed, 267 insertions(+), 55 deletions(-) diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index 70cb6a3..459c809 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -1,5 +1,11 @@ /* - * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200. + * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200 and PCI bus. + * + * Interrupt support is added. Now, it has been tested + * on ULI1575 chip and works well with USB keyboard. + * + * (C) Copyright 2007 + * Zhang Wei, Freescale Semiconductor, Inc. * * (C) Copyright 2003 * Gary Jennejohn, DENX Software Engineering @@ -35,7 +41,7 @@ * 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 - * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes! + * (BBB) and USB keyboard. There is NO support for Isochronous pipes! * 3 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG * to activate workaround for bug #41 or this driver will NOT work! */ @@ -56,6 +62,8 @@ # include #elif defined(CONFIG_MPC5200) # include +#elif defined(CONFIG_PCI_OHCI) +# include #endif #include @@ -66,6 +74,7 @@ defined(CONFIG_S3C2400) || \ defined(CONFIG_S3C2410) || \ defined(CONFIG_440EP) || \ + defined(CONFIG_PCI_OHCI) || \ defined(CONFIG_MPC5200) # define OHCI_USE_NPS /* force NoPowerSwitching mode */ #endif @@ -79,12 +88,19 @@ #define OHCI_CONTROL_INIT \ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE -#define readl(a) (*((vu_long *)(a))) -#define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a)) +#define readl(a) m32_swap(*((vu_long *)(a))) +#define writel(a, b) (*((vu_long *)(b)) = m32_swap((vu_long)a)) #define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) -#undef DEBUG +#ifdef CONFIG_PCI_OHCI +static struct pci_device_id ohci_pci_ids[] = { + {0x10b9, 0x5237}, /* ULI1575 PCI OHCI module ids */ + /* Please add supported PCI OHCI controller ids here */ + {0, 0} +}; +#endif + #ifdef DEBUG #define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg) #else @@ -114,15 +130,11 @@ struct ohci_hcca ghcca[1]; struct ohci_hcca *phcca; /* this allocates EDs for all possible endpoints */ struct ohci_device ohci_dev; -/* urb_priv */ -urb_priv_t urb_priv; /* RHSC flag */ int got_rhsc; /* device which was disconnected */ struct usb_device *devgone; -/* flag guarding URB transation */ -int urb_finished = 0; /*-------------------------------------------------------------------------*/ @@ -177,6 +189,7 @@ static void urb_free_priv (urb_priv_t * urb) } } } + free(urb); } /*-------------------------------------------------------------------------*/ @@ -187,11 +200,10 @@ static int sohci_get_current_frame_number (struct usb_device * dev); /* debug| print the main components of an URB * small: 0) header + data packets 1) just header */ -static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer, +static void pkt_print (urb_priv_t *purb, struct usb_device * dev, + unsigned long pipe, void * buffer, int transfer_len, struct devrequest * setup, char * str, int small) { - urb_priv_t * purb = &urb_priv; - dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx", str, sohci_get_current_frame_number (dev), @@ -200,7 +212,7 @@ static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffe usb_pipeout (pipe)? 'O': 'I', usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"): (usb_pipecontrol (pipe)? "CTRL": "BULK"), - purb->actual_length, + (purb ? purb->actual_length : 0), transfer_len, dev->status); #ifdef OHCI_VERBOSE_DEBUG if (!small) { @@ -214,10 +226,11 @@ static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffe } if (transfer_len > 0 && buffer) { printf (__FILE__ ": data(%d/%d):", - purb->actual_length, + (purb ? purb->actual_length : 0), transfer_len); len = usb_pipeout (pipe)? - transfer_len: purb->actual_length; + transfer_len: + (purb ? purb->actual_length : 0); for (i = 0; i < 16 && i < len; i++) printf (" %02x", ((__u8 *) buffer) [i]); printf ("%s\n", i < len? "...": ""); @@ -413,13 +426,17 @@ static void ohci_dump (ohci_t *controller, int verbose) /* get a transfer request */ -int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup, int interval) +int sohci_submit_job(urb_priv_t *urb, struct devrequest *setup) { ohci_t *ohci; ed_t * ed; - urb_priv_t *purb_priv; + urb_priv_t *purb_priv = urb; int i, size = 0; + struct usb_device *dev = urb->dev; + unsigned long pipe = urb->pipe; + void *buffer = urb->transfer_buffer; + int transfer_len = urb->transfer_buffer_length; + int interval = urb->interval; ohci = &gohci; @@ -430,18 +447,11 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, 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; + urb->finished = 0; /* every endpoint has a ed, locate and fill it */ - if (!(ed = ep_add_ed (dev, pipe))) { + if (!(ed = ep_add_ed (dev, pipe, interval, 1))) { err("sohci_submit_job: ENOMEM"); return -1; } @@ -455,13 +465,17 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, size = (transfer_len == 0)? 2: (transfer_len - 1) / 4096 + 3; break; + case PIPE_INTERRUPT: /* 1 TD */ + size = 1; + break; } + ed->purb = urb; + if (size >= (N_URB_TD - 1)) { err("need %d TDs, only have %d", size, N_URB_TD); return -1; } - purb_priv = &urb_priv; purb_priv->pipe = pipe; /* fill the private part of the URB */ @@ -497,6 +511,40 @@ int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, return 0; } +static inline int sohci_return_job(struct ohci *hc, urb_priv_t *urb) +{ + struct ohci_regs *regs = hc->regs; + + switch (usb_pipetype (urb->pipe)) { + case PIPE_INTERRUPT: + /* implicitly requeued */ + if (urb->dev->irq_handle && + (urb->dev->irq_act_len = urb->actual_length)) { + writel (OHCI_INTR_WDH, ®s->intrenable); + readl (®s->intrenable); /* PCI posting flush */ + urb->dev->irq_handle(urb->dev); + writel (OHCI_INTR_WDH, ®s->intrdisable); + readl (®s->intrdisable); /* PCI posting flush */ + } + urb->actual_length = 0; + td_submit_job ( + urb->dev, + urb->pipe, + urb->transfer_buffer, + urb->transfer_buffer_length, + NULL, + urb, + urb->interval); + break; + case PIPE_CONTROL: + case PIPE_BULK: + break; + default: + return 0; + } + return 1; +} + /*-------------------------------------------------------------------------*/ #ifdef DEBUG @@ -514,13 +562,73 @@ static int sohci_get_current_frame_number (struct usb_device *usb_dev) * ED handling functions *-------------------------------------------------------------------------*/ +/* search for the right branch to insert an interrupt ed into the int tree + * do some load ballancing; + * returns the branch and + * sets the interval to interval = 2^integer (ld (interval)) */ + +static int ep_int_ballance (ohci_t * ohci, int interval, int load) +{ + int i, branch = 0; + + /* search for the least loaded interrupt endpoint + * branch of all 32 branches + */ + for (i = 0; i < 32; i++) + if (ohci->ohci_int_load [branch] > ohci->ohci_int_load [i]) + branch = i; + + branch = branch % interval; + for (i = branch; i < 32; i += interval) + ohci->ohci_int_load [i] += load; + + return branch; +} + +/*-------------------------------------------------------------------------*/ + +/* 2^int( ld (inter)) */ + +static int ep_2_n_interval (int inter) +{ + int i; + for (i = 0; ((inter >> i) > 1 ) && (i < 5); i++); + return 1 << i; +} + +/*-------------------------------------------------------------------------*/ + +/* the int tree is a binary tree + * in order to process it sequentially the indexes of the branches have to be mapped + * the mapping reverses the bits of a word of num_bits length */ + +static int ep_rev (int num_bits, int word) +{ + int i, wout = 0; + + for (i = 0; i < num_bits; i++) + wout |= (((word >> i) & 1) << (num_bits - i - 1)); + return wout; +} + +/*-------------------------------------------------------------------------* + * ED handling functions + *-------------------------------------------------------------------------*/ + /* link an ed into one of the HC chains */ static int ep_link (ohci_t *ohci, ed_t *edi) { volatile ed_t *ed = edi; + int int_branch; + int i; + int inter; + int interval; + int load; + __u32 * ed_p; ed->state = ED_OPER; + ed->int_interval = 0; switch (ed->type) { case PIPE_CONTROL: @@ -554,12 +662,49 @@ static int ep_link (ohci_t *ohci, ed_t *edi) } ohci->ed_bulktail = edi; break; + + case PIPE_INTERRUPT: + load = ed->int_load; + interval = ep_2_n_interval (ed->int_period); + ed->int_interval = interval; + int_branch = ep_int_ballance (ohci, interval, load); + ed->int_branch = int_branch; + + for (i = 0; i < ep_rev (6, interval); i += inter) { + inter = 1; + for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) + int_branch]); + (*ed_p != 0) && (((ed_t *)ed_p)->int_interval >= interval); + ed_p = &(((ed_t *)ed_p)->hwNextED)) + inter = ep_rev (6, ((ed_t *)ed_p)->int_interval); + ed->hwNextED = *ed_p; + *ed_p = m32_swap(ed); + } + break; } return 0; } /*-------------------------------------------------------------------------*/ +/* scan the periodic table to find and unlink this ED */ +static void periodic_unlink ( struct ohci *ohci, volatile struct ed *ed, + unsigned index, unsigned period) +{ + for (; index < NUM_INTS; index += period) { + __u32 *ed_p = &ohci->hcca->int_table [index]; + + /* ED might have been unlinked through another path */ + while (*ed_p != 0) { + if (((struct ed *)m32_swap (ed_p)) == ed) { + *ed_p = ed->hwNextED; + break; + } + ed_p = & (((struct ed *)m32_swap (ed_p))->hwNextED); + } + } +} + + /* unlink an ed from one of the HC chains. * just the link to the ed is unlinked. * the link from the ed still points to another operational ed or 0 @@ -568,6 +713,7 @@ static int ep_link (ohci_t *ohci, ed_t *edi) static int ep_unlink (ohci_t *ohci, ed_t *edi) { volatile ed_t *ed = edi; + int i; ed->hwINFO |= m32_swap (OHCI_ED_SKIP); @@ -605,6 +751,12 @@ static int ep_unlink (ohci_t *ohci, ed_t *edi) ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev; } break; + + case PIPE_INTERRUPT: + periodic_unlink (ohci, ed, 0, 1); + for (i = ed->int_branch; i < 32; i += ed->int_interval) + ohci->ohci_int_load[i] -= ed->int_load; + break; } ed->state = ED_UNLINK; return 0; @@ -621,7 +773,8 @@ static int ep_unlink (ohci_t *ohci, ed_t *edi) * info fields are setted anyway even though most of them should not * change */ -static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe) +static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe, + int interval, int load) { td_t *td; ed_t *ed_ret; @@ -654,6 +807,11 @@ static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe) | usb_pipeslow (pipe) << 13 | usb_maxpacket (usb_dev, pipe) << 16); + if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) { + ed->int_period = interval; + ed->int_load = load; + } + return ed_ret; } @@ -768,6 +926,13 @@ static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buf if (!ohci->sleeping) writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ break; + + case PIPE_INTERRUPT: + info = usb_pipeout (urb->pipe)? + TD_CC | TD_DP_OUT | toggle: + TD_CC | TD_R | TD_DP_IN | toggle; + td_fill (ohci, info, data, data_len, dev, cnt++, urb); + break; } if (urb->length != cnt) dbg("TD LENGTH %d != CNT %d", urb->length, cnt); @@ -783,7 +948,7 @@ static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buf static void dl_transfer_length(td_t * td) { __u32 tdINFO, tdBE, tdCBP; - urb_priv_t *lurb_priv = &urb_priv; + urb_priv_t *lurb_priv = td->ed->purb; tdINFO = m32_swap (td->hwINFO); tdBE = m32_swap (td->hwBE); @@ -820,7 +985,7 @@ static td_t * dl_reverse_done_list (ohci_t *ohci) td_list = (td_t *)td_list_hc; if (TD_CC_GET (m32_swap (td_list->hwINFO))) { - lurb_priv = &urb_priv; + lurb_priv = td_list->ed->purb; dbg(" USB-error/status: %x : %p", TD_CC_GET (m32_swap (td_list->hwINFO)), td_list); if (td_list->ed->hwHeadP & m32_swap (0x1)) { @@ -860,10 +1025,10 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list) while (td_list) { td_list_next = td_list->next_dl_td; - lurb_priv = &urb_priv; tdINFO = m32_swap (td_list->hwINFO); ed = td_list->ed; + lurb_priv = ed->purb; dl_transfer_length(td_list); @@ -882,14 +1047,16 @@ static int dl_done_list (ohci_t *ohci, td_t *td_list) (lurb_priv->state != URB_DEL)) #else if ((ed->state & (ED_OPER | ED_UNLINK))) - urb_finished = 1; +#endif + lurb_priv->finished = sohci_return_job(ohci, + lurb_priv); else dbg("dl_done_list: strange.., ED state %x, ed->state\n"); } else dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt, lurb_priv->length); -#endif - if (ed->state != ED_NEW) { + if (ed->state != ED_NEW && + (usb_pipetype (lurb_priv->pipe) != PIPE_INTERRUPT)) { edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0; edTailP = m32_swap (ed->hwTailP); @@ -1063,8 +1230,7 @@ static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, __u16 wLength; #ifdef DEBUG -urb_priv.actual_length = 0; -pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); +pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); #else wait_ms(1); #endif @@ -1279,9 +1445,7 @@ pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); dev->status = stat; #ifdef DEBUG - if (transfer_len) - urb_priv.actual_length = transfer_len; - pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/); + pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/); #else wait_ms(1); #endif @@ -1299,6 +1463,16 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int stat = 0; int maxsize = usb_maxpacket(dev, pipe); int timeout; + urb_priv_t *urb; + + urb = malloc(sizeof(urb_priv_t)); + memset(urb, 0, sizeof(urb_priv_t)); + + urb->dev = dev; + urb->pipe = pipe; + urb->transfer_buffer = buffer; + urb->transfer_buffer_length = transfer_len; + urb->interval = interval; /* device pulled? Shortcut the action. */ if (devgone == dev) { @@ -1307,8 +1481,8 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, } #ifdef DEBUG - urb_priv.actual_length = 0; - pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); + urb->actual_length = 0; + pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else wait_ms(1); #endif @@ -1318,7 +1492,7 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, return -1; } - if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) { + if (sohci_submit_job(urb, setup) < 0) { err("sohci_submit_job failed"); return -1; } @@ -1353,18 +1527,20 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, * 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)) { + if ((stat >= 0) && (stat != 0xff) && (urb->finished)) { /* 0xff is returned for an SF-interrupt */ break; } if (--timeout) { 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; + urb->finished = 1; stat = USB_ST_CRC_ERR; break; } @@ -1374,13 +1550,14 @@ int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, dev->act_len = transfer_len; #ifdef DEBUG - pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe)); + pkt_print(urb, dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe)); #else wait_ms(1); #endif /* free TDs in urb_priv */ - urb_free_priv (&urb_priv); + if (usb_pipetype (pipe) != PIPE_INTERRUPT) + urb_free_priv (urb); return 0; } @@ -1399,8 +1576,7 @@ int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, info("submit_control_msg"); #ifdef DEBUG - urb_priv.actual_length = 0; - pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); + pkt_print(NULL, dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); #else wait_ms(1); #endif @@ -1423,7 +1599,8 @@ int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int transfer_len, int interval) { info("submit_int_msg"); - return -1; + return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, + interval); } /*-------------------------------------------------------------------------* @@ -1537,6 +1714,12 @@ static int hc_start (ohci_t * ohci) /*-------------------------------------------------------------------------*/ +/* Poll USB interrupt. */ +void usb_event_poll(void) +{ + hc_interrupt(); +} + /* an interrupt happens */ static int hc_interrupt (void) @@ -1587,8 +1770,10 @@ static int hc_interrupt (void) if (ints & OHCI_INTR_WDH) { wait_ms(1); writel (OHCI_INTR_WDH, ®s->intrdisable); + (void)readl (®s->intrdisable); /* flush */ stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci)); writel (OHCI_INTR_WDH, ®s->intrenable); + (void)readl (®s->intrdisable); /* flush */ } if (ints & OHCI_INTR_SO) { @@ -1634,6 +1819,9 @@ static char ohci_inited = 0; int usb_lowlevel_init(void) { +#ifdef CONFIG_PCI_OHCI + pci_dev_t pdev; +#endif #ifdef CFG_USB_OHCI_CPU_INIT /* cpu dependant init */ @@ -1647,7 +1835,6 @@ int usb_lowlevel_init(void) return -1; #endif memset (&gohci, 0, sizeof (ohci_t)); - memset (&urb_priv, 0, sizeof (urb_priv_t)); /* align the storage */ if ((__u32)&ghcca[0] & 0xff) { @@ -1673,7 +1860,25 @@ int usb_lowlevel_init(void) gohci.disabled = 1; gohci.sleeping = 0; gohci.irq = -1; +#ifdef CONFIG_PCI_OHCI + pdev = pci_find_devices(ohci_pci_ids, 0); + + if (pdev != -1) { + u16 vid, did; + u32 base; + pci_read_config_word(pdev, PCI_VENDOR_ID, &vid); + pci_read_config_word(pdev, PCI_DEVICE_ID, &did); + printf("OHCI pci controller (%04x, %04x) found @(%d:%d:%d)\n", + vid, did, (pdev >> 16) & 0xff, + (pdev >> 11) & 0x1f, (pdev >> 8) & 0x7); + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &base); + printf("OHCI regs address 0x%08x\n", base); + gohci.regs = (struct ohci_regs *)base; + } else + return -1; +#else gohci.regs = (struct ohci_regs *)CFG_USB_OHCI_REGS_BASE; +#endif gohci.flags = 0; gohci.slot_name = CFG_USB_OHCI_SLOT_NAME; @@ -1716,7 +1921,6 @@ int usb_lowlevel_init(void) ohci_dump (&gohci, 1); #else wait_ms(1); - urb_finished = 1; #endif ohci_inited = 1; return 0; diff --git a/drivers/usb_ohci.h b/drivers/usb_ohci.h index d2b03c0..380cb4c 100644 --- a/drivers/usb_ohci.h +++ b/drivers/usb_ohci.h @@ -64,7 +64,8 @@ struct ed { struct ed *ed_rm_list; struct usb_device *usb_dev; - __u32 unused[3]; + void *purb; + __u32 unused[2]; } __attribute((aligned(16))); typedef struct ed ed_t; @@ -349,9 +350,14 @@ typedef struct ed_t *ed; __u16 length; /* number of tds associated with this request */ __u16 td_cnt; /* number of tds already serviced */ + struct usb_device *dev; int state; unsigned long pipe; + void *transfer_buffer; + int transfer_buffer_length; + int interval; int actual_length; + int finished; td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */ } urb_priv_t; #define URB_DEL 1 @@ -375,6 +381,7 @@ typedef struct ohci { struct ohci_regs *regs; /* OHCI controller's memory */ + int ohci_int_load[32]; /* load of the 32 Interrupt Chains (for load balancing)*/ ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */ ed_t *ed_bulktail; /* last endpoint of bulk list */ ed_t *ed_controltail; /* last endpoint of control list */ @@ -397,7 +404,8 @@ struct ohci_device { /* endpoint */ static int ep_link(ohci_t * ohci, ed_t * ed); static int ep_unlink(ohci_t * ohci, ed_t * ed); -static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe); +static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe, + int interval, int load); /*-------------------------------------------------------------------------*/ -- cgit v1.1 From a81d1c0b85b13e9d45f2d87de96a51a6e0ef0f82 Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Wed, 6 Jun 2007 10:08:14 +0200 Subject: Add USB PCI-OHCI, USB keyboard and event poll support to the MPC8641HPCN board config file. Signed-off-by: Zhang Wei --- include/configs/MPC8641HPCN.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/include/configs/MPC8641HPCN.h b/include/configs/MPC8641HPCN.h index bbe3505..efac4c5 100644 --- a/include/configs/MPC8641HPCN.h +++ b/include/configs/MPC8641HPCN.h @@ -330,6 +330,17 @@ #undef CONFIG_EEPRO100 #undef CONFIG_TULIP +/************************************************************ + * USB support + ************************************************************/ +#define CONFIG_PCI_OHCI 1 +#define CONFIG_USB_OHCI_NEW 1 +#define CONFIG_USB_KEYBOARD 1 +#define CFG_DEVICE_DEREGISTER +#define CFG_USB_EVENT_POLL 1 +#define CFG_USB_OHCI_SLOT_NAME "ohci_pci" +#define CFG_USB_OHCI_MAX_ROOT_PORTS 15 + #if !defined(CONFIG_PCI_PNP) #define PCI_ENET0_IOADDR 0xe0000000 #define PCI_ENET0_MEMADDR 0xe0000000 @@ -482,6 +493,7 @@ | CFG_CMD_PCI \ | CFG_CMD_I2C \ | CFG_CMD_SCSI \ + | CFG_CMD_USB \ | CFG_CMD_EXT2) \ & \ ~(CFG_CMD_ENV)) @@ -499,6 +511,7 @@ | CFG_CMD_PING \ | CFG_CMD_I2C \ | CFG_CMD_SCSI \ + | CFG_CMD_USB \ | CFG_CMD_EXT2) #else #define CONFIG_COMMANDS (CONFIG_CMD_DFL \ -- cgit v1.1 From 18135125f909948b85d1d6881ab4ac0efb4a1c58 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Wed, 6 Jun 2007 10:08:14 +0200 Subject: Files include/linux/byteorder/{big,little}_endian.h define __BIG_ENDIAN and __LITTLE_ENDIAN. Signed-off-by: Rodolfo Giometti --- drivers/usbtty.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usbtty.c b/drivers/usbtty.c index d41a00b..a3b5013 100644 --- a/drivers/usbtty.c +++ b/drivers/usbtty.c @@ -381,12 +381,12 @@ static void str2wide (char *str, u16 * wide) { int i; for (i = 0; i < strlen (str) && str[i]; i++){ - #if defined(__LITTLE_ENDIAN__) + #if defined(__LITTLE_ENDIAN) wide[i] = (u16) str[i]; - #elif defined(__BIG_ENDIAN__) + #elif defined(__BIG_ENDIAN) wide[i] = ((u16)(str[i])<<8); #else - #error "__LITTLE_ENDIAN__ or __BIG_ENDIAN__ undefined" + #error "__LITTLE_ENDIAN or __BIG_ENDIAN undefined" #endif } } -- cgit v1.1 From fc43be478f2aa37ce38acd85355038866e4162af Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Wed, 6 Jun 2007 11:49:35 +0200 Subject: USB/OHCI: endianness cleanup in the generic ohci driver --- doc/README.generic_usb_ohci | 49 ++++++++++++++++++--------- drivers/usb_ohci.c | 82 ++++++++++++++++----------------------------- 2 files changed, 62 insertions(+), 69 deletions(-) diff --git a/doc/README.generic_usb_ohci b/doc/README.generic_usb_ohci index 017c69a..c343dfd 100644 --- a/doc/README.generic_usb_ohci +++ b/doc/README.generic_usb_ohci @@ -9,35 +9,52 @@ into cpu/board directories and are called via the hooks below. Configuration options ---------------------- -CONFIG_USB_OHCI_NEW: enable the new OHCI driver + CONFIG_USB_OHCI_NEW: enable the new OHCI driver -CFG_USB_OHCI_BOARD_INIT: call the board dependant hooks: + CFG_USB_OHCI_BOARD_INIT: call the board dependant hooks: - - extern int usb_board_init(void); - - extern int usb_board_stop(void); - - extern int usb_cpu_init_fail(void); + - extern int usb_board_init(void); + - extern int usb_board_stop(void); + - extern int usb_cpu_init_fail(void); -CFG_USB_OHCI_CPU_INIT: call the cpu dependant hooks: + CFG_USB_OHCI_CPU_INIT: call the cpu dependant hooks: - - extern int usb_cpu_init(void); - - extern int usb_cpu_stop(void); - - extern int usb_cpu_init_fail(void); + - extern int usb_cpu_init(void); + - extern int usb_cpu_stop(void); + - extern int usb_cpu_init_fail(void); -CFG_USB_OHCI_REGS_BASE: defines the base address of the OHCI registers + CFG_USB_OHCI_REGS_BASE: defines the base address of the OHCI + registers -CFG_USB_OHCI_SLOT_NAME: slot name + CFG_USB_OHCI_SLOT_NAME: slot name -CFG_USB_OHCI_MAX_ROOT_PORTS: maximal number of ports of the root hub. + CFG_USB_OHCI_MAX_ROOT_PORTS: maximal number of ports of the + root hub. Endianness issues ------------------ -The LITTLEENDIAN #define determines if the 'swap_16' and 'swap_32' -macros do byte swapping or not. But some cpus OHCI-controllers such as -ppc4xx and mpc5xxx operate in little endian mode, so some extra ifdefs -were necessary to make this work. +The USB bus operates in little endian, but unfortunately there are +OHCI controllers that operate in big endian such as ppc4xx and +mpc5xxx. For these the config option + CFG_OHCI_BE_CONTROLLER + +needs to be defined. + + +PCI Controllers +---------------- + +You'll need to define + + CONFIG_PCI_OHCI + +PCI Controllers need to do byte swapping on register accesses, so they +should to define: + + CFG_OHCI_SWAP_REG_ACCESS diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index 459c809..3cef576 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -38,31 +38,20 @@ */ /* * IMPORTANT NOTES - * 1 - you MUST define LITTLEENDIAN in the configuration file for the - * board or this driver will NOT work! + * 1 - Read doc/README.generic_usb_ohci * 2 - this driver is intended for use with USB Mass Storage Devices * (BBB) and USB keyboard. There is NO support for Isochronous pipes! - * 3 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG + * 2 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG * to activate workaround for bug #41 or this driver will NOT work! */ #include -/* #include no PCI on the S3C24X0 */ #ifdef CONFIG_USB_OHCI_NEW -/* mk: are these really required? */ -#if defined(CONFIG_S3C2400) -# include -#elif defined(CONFIG_S3C2410) -# include -#elif defined(CONFIG_ARM920T) -# include -#elif defined(CONFIG_CPU_MONAHANS) -# include -#elif defined(CONFIG_MPC5200) -# include -#elif defined(CONFIG_PCI_OHCI) +#include + +#if defined(CONFIG_PCI_OHCI) # include #endif @@ -88,8 +77,16 @@ #define OHCI_CONTROL_INIT \ (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE -#define readl(a) m32_swap(*((vu_long *)(a))) -#define writel(a, b) (*((vu_long *)(b)) = m32_swap((vu_long)a)) +/* + * e.g. PCI controllers need this + */ +#ifdef CFG_OHCI_SWAP_REG_ACCESS +# define readl(a) __swap_16(*((vu_long *)(a))) +# define writel(a, b) (*((vu_long *)(b)) = __swap_32((vu_long)a)) +#else +# define readl(a) (*((vu_long *)(a))) +# define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a)) +#endif /* CFG_OHCI_SWAP_REG_ACCESS */ #define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) @@ -114,13 +111,13 @@ static struct pci_device_id ohci_pci_ids[] = { #define info(format, arg...) do {} while(0) #endif -#if defined(CONFIG_440EP) || defined(CONFIG_MPC5200) -# define m16_swap(x) (x) -# define m32_swap(x) (x) +#ifdef CFG_OHCI_BE_CONTROLLER +# define m16_swap(x) cpu_to_be16(x) +# define m32_swap(x) cpu_to_be32(x) #else -# define m16_swap(x) swap_16(x) -# define m32_swap(x) swap_32(x) -#endif +# define m16_swap(x) cpu_to_le16(x) +# define m32_swap(x) cpu_to_le32(x) +#endif /* CFG_OHCI_BE_CONTROLLER */ /* global ohci_t */ static ohci_t gohci; @@ -1240,15 +1237,9 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe } bmRType_bReq = cmd->requesttype | (cmd->request << 8); -#if defined(CONFIG_440EP) || defined(CONFIG_MPC5200) - wValue = __swap_16(cmd->value); - wIndex = __swap_16(cmd->index); - wLength = __swap_16(cmd->length); -#else - wValue = m16_swap (cmd->value); - wIndex = m16_swap (cmd->index); - wLength = m16_swap (cmd->length); -#endif /* CONFIG_440EP || CONFIG_MPC5200 */ + wValue = cpu_to_le16 (cmd->value); + wIndex = cpu_to_le16 (cmd->index); + wLength = cpu_to_le16 (cmd->length); info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x", dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength); @@ -1262,33 +1253,18 @@ pkt_print(NULL, dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe RH_OTHER | RH_CLASS almost ever means HUB_PORT here */ -#if defined(CONFIG_440EP) || defined(CONFIG_MPC5200) - case RH_GET_STATUS: - *(__u16 *) data_buf = __swap_16(1); OK (2); - case RH_GET_STATUS | RH_INTERFACE: - *(__u16 *) data_buf = __swap_16(0); OK (2); - case RH_GET_STATUS | RH_ENDPOINT: - *(__u16 *) data_buf = __swap_16(0); OK (2); - case RH_GET_STATUS | RH_CLASS: - *(__u32 *) data_buf = __swap_32( - RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE)); - OK (4); - case RH_GET_STATUS | RH_OTHER | RH_CLASS: - *(__u32 *) data_buf = __swap_32(RD_RH_PORTSTAT); OK (4); -#else case RH_GET_STATUS: - *(__u16 *) data_buf = m16_swap (1); OK (2); + *(__u16 *) data_buf = cpu_to_le16 (1); OK (2); case RH_GET_STATUS | RH_INTERFACE: - *(__u16 *) data_buf = m16_swap (0); OK (2); + *(__u16 *) data_buf = cpu_to_le16 (0); OK (2); case RH_GET_STATUS | RH_ENDPOINT: - *(__u16 *) data_buf = m16_swap (0); OK (2); + *(__u16 *) data_buf = cpu_to_le16 (0); OK (2); case RH_GET_STATUS | RH_CLASS: - *(__u32 *) data_buf = m32_swap ( + *(__u32 *) data_buf = 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); -#endif /* CONFIG_440EP || CONFIG_MPC5200 */ + *(__u32 *) data_buf = cpu_to_le32 (RD_RH_PORTSTAT); OK (4); case RH_CLEAR_FEATURE | RH_ENDPOINT: switch (wValue) { -- cgit v1.1 From 72657570b61635c74fa0c3f0e9e7d0671a9d08df Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Wed, 6 Jun 2007 11:49:43 +0200 Subject: USB: ohci fixes and cleanup for mpc5xxx and IceCube board config --- cpu/mpc5xxx/usb.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ include/configs/IceCube.h | 9 ++------ 2 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 cpu/mpc5xxx/usb.c diff --git a/cpu/mpc5xxx/usb.c b/cpu/mpc5xxx/usb.c new file mode 100644 index 0000000..ce709fc --- /dev/null +++ b/cpu/mpc5xxx/usb.c @@ -0,0 +1,54 @@ +/* + * (C) Copyright 2007 + * Markus Klotzbuecher, DENX Software Engineering + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) + +#include + +int usb_cpu_init() +{ + /* Set the USB Clock */ + *(vu_long *)MPC5XXX_CDM_48_FDC = CONFIG_USB_CLOCK; + + /* remove all USB bits first before ORing in ours */ + *(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00807000; + + /* Activate USB port */ + *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= CONFIG_USB_CONFIG; + + return 0; +} + +int usb_cpu_stop() +{ + return 0; +} + +int usb_cpu_init_fail() +{ + return 0; +} + +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/include/configs/IceCube.h b/include/configs/IceCube.h index 4132f4a..551a609 100644 --- a/include/configs/IceCube.h +++ b/include/configs/IceCube.h @@ -93,21 +93,16 @@ #define CONFIG_ISO_PARTITION /* USB */ -#if 1 #define CONFIG_USB_OHCI_NEW #define ADD_USB_CMD CFG_CMD_USB | CFG_CMD_FAT #define CONFIG_USB_STORAGE - +#define CFG_OHCI_BE_CONTROLLER #undef CFG_USB_OHCI_BOARD_INIT -#define CFG_USB_OHCI_CPU_INIT +#define CFG_USB_OHCI_CPU_INIT 1 #define CFG_USB_OHCI_REGS_BASE MPC5XXX_USB #define CFG_USB_OHCI_SLOT_NAME "mpc5200" #define CFG_USB_OHCI_MAX_ROOT_PORTS 15 -#else -#define ADD_USB_CMD 0 -#endif - #define CONFIG_TIMESTAMP /* Print image info with timestamp */ /* -- cgit v1.1 From dace45acd1c1357daa9322099d07c9a9e08b0024 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Wed, 6 Jun 2007 11:49:43 +0200 Subject: USB: ohci fixes and cleanup for ppc4xx and yosemite board. --- cpu/ppc4xx/Makefile | 2 +- cpu/ppc4xx/usb.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++ include/configs/yosemite.h | 1 + 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 cpu/ppc4xx/usb.c diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile index 66fd02c..af9da5b 100644 --- a/cpu/ppc4xx/Makefile +++ b/cpu/ppc4xx/Makefile @@ -32,7 +32,7 @@ COBJS = 405gp_pci.o 440spe_pcie.o 4xx_enet.o \ cpu.o cpu_init.o gpio.o i2c.o interrupts.o \ miiphy.o ndfc.o sdram.o serial.o \ 40x_spd_sdram.o 44x_spd_ddr.o 44x_spd_ddr2.o speed.o \ - tlb.o traps.o usb_ohci.o usbdev.o usb.o \ + tlb.o traps.o usb_ohci.o usb.o usbdev.o \ 440spe_pcie.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/cpu/ppc4xx/usb.c b/cpu/ppc4xx/usb.c new file mode 100644 index 0000000..2837b37 --- /dev/null +++ b/cpu/ppc4xx/usb.c @@ -0,0 +1,50 @@ +/* + * (C) Copyright 2007 + * Markus Klotzbuecher, DENX Software Engineering + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) + +#include "usbdev.h" + +int usb_cpu_init() +{ + +#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) + usb_dev_init(); +#endif + + return 0; +} + +int usb_cpu_stop() +{ + return 0; +} + +int usb_cpu_init_fail() +{ + return 0; +} + +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/include/configs/yosemite.h b/include/configs/yosemite.h index 0a41dff..1d12758 100644 --- a/include/configs/yosemite.h +++ b/include/configs/yosemite.h @@ -234,6 +234,7 @@ /* USB */ #define CONFIG_USB_OHCI_NEW #define CONFIG_USB_STORAGE +#define CFG_OHCI_BE_CONTROLLER #undef CFG_USB_OHCI_BOARD_INIT #define CFG_USB_OHCI_CPU_INIT 1 -- cgit v1.1 From 19d763c35e0b5568eaf0b8adbf7a68ccfe7fa243 Mon Sep 17 00:00:00 2001 From: Markus Klotzbuecher Date: Wed, 6 Jun 2007 11:49:44 +0200 Subject: TRAB, USB: update trab board configuration for use of generic ohci driver --- include/configs/trab.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/configs/trab.h b/include/configs/trab.h index acf86d0..f52d2de 100644 --- a/include/configs/trab.h +++ b/include/configs/trab.h @@ -86,7 +86,8 @@ #undef CFG_USB_OHCI_BOARD_INIT #define CFG_USB_OHCI_CPU_INIT 1 -#define CFG_USB_OHCI_REGS_BASE S3C24X0_USB_HOST_BASE + +#define CFG_USB_OHCI_REGS_BASE 0x14200000 #define CFG_USB_OHCI_SLOT_NAME "s3c2400" #define CFG_USB_OHCI_MAX_ROOT_PORTS 15 -- cgit v1.1 From 9b7464a2c88614e1061f509c48930a3d240d1a35 Mon Sep 17 00:00:00 2001 From: Jason Jin Date: Mon, 11 Jun 2007 15:14:24 +0200 Subject: USB: This patch fix readl in ohci swap reg access. Signed-off-by: Jason Jin --- drivers/usb_ohci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb_ohci.c b/drivers/usb_ohci.c index 3cef576..d6b745f 100644 --- a/drivers/usb_ohci.c +++ b/drivers/usb_ohci.c @@ -81,7 +81,7 @@ * e.g. PCI controllers need this */ #ifdef CFG_OHCI_SWAP_REG_ACCESS -# define readl(a) __swap_16(*((vu_long *)(a))) +# define readl(a) __swap_32(*((vu_long *)(a))) # define writel(a, b) (*((vu_long *)(b)) = __swap_32((vu_long)a)) #else # define readl(a) (*((vu_long *)(a))) -- cgit v1.1 From dcb84b7208ade0bbebbeb56bec9c2c64f8b2eede Mon Sep 17 00:00:00 2001 From: Joe Hamman Date: Thu, 9 Aug 2007 09:08:18 -0500 Subject: tsec: Allow Ten Bit Interface address to be configurable Allow the address of the Ten Bit Interface (TBI) to be changed in the event of a conflict with another device. Signed-off by: Joe Hamman --- drivers/tsec.c | 4 ++-- drivers/tsec.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/tsec.c b/drivers/tsec.c index 60bef9a..c9e7f97 100644 --- a/drivers/tsec.c +++ b/drivers/tsec.c @@ -296,9 +296,9 @@ static int init_phy(struct eth_device *dev) volatile tsec_t *regs = (volatile tsec_t *)(TSEC_BASE_ADDR); /* Assign a Physical address to the TBI */ - regs->tbipa = TBIPA_VALUE; + regs->tbipa = CFG_TBIPA_VALUE; regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE); - regs->tbipa = TBIPA_VALUE; + regs->tbipa = CFG_TBIPA_VALUE; asm("sync"); /* Reset MII (due to new addresses) */ diff --git a/drivers/tsec.h b/drivers/tsec.h index 7bf3dee..2f0092a 100644 --- a/drivers/tsec.h +++ b/drivers/tsec.h @@ -70,7 +70,9 @@ #define miim_end -2 #define miim_read -1 -#define TBIPA_VALUE 0x1f +#ifndef CFG_TBIPA_VALUE + #define CFG_TBIPA_VALUE 0x1f +#endif #define MIIMCFG_INIT_VALUE 0x00000003 #define MIIMCFG_RESET 0x80000000 -- cgit v1.1 From ed8106433522f2ea8933e9808346860d061d7731 Mon Sep 17 00:00:00 2001 From: Zach Sadecki Date: Tue, 31 Jul 2007 12:27:25 -0500 Subject: tsec: fix multiple PHY support The change entitled "Reduce CONFIG_MPC8YXX_TSECx to CONFIG_TSECx" broke multiple PHY support in tsec.c. This fixes it. Signed-off-by: Zach Sadecki Signed-off-by: Kim Phillips --- drivers/tsec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tsec.c b/drivers/tsec.c index c9e7f97..c011123 100644 --- a/drivers/tsec.c +++ b/drivers/tsec.c @@ -71,6 +71,7 @@ static struct tsec_info_struct tsec_info[] = { #else {TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX}, #endif +#else {0, 0, 0}, #endif #if defined(CONFIG_TSEC2) @@ -79,6 +80,7 @@ static struct tsec_info_struct tsec_info[] = { #else {TSEC2_PHY_ADDR, TSEC_GIGABIT, TSEC2_PHYIDX}, #endif +#else {0, 0, 0}, #endif #ifdef CONFIG_MPC85XX_FEC -- cgit v1.1 From ce981dc857adfc8036ca2f6d5d5a06c2a8aa77d6 Mon Sep 17 00:00:00 2001 From: Jason Jin Date: Wed, 8 Aug 2007 08:33:11 +0800 Subject: Add CONFIG_BIOSEMU define to guard all the bios emulator code Signed-off-by: Jason Jin This patch fix the compile issue on the board that did not enable the bios emulator --- drivers/bios_emulator/besys.c | 2 ++ drivers/bios_emulator/bios.c | 2 ++ drivers/bios_emulator/biosemu.c | 3 +++ drivers/bios_emulator/x86emu/debug.c | 4 ++++ drivers/bios_emulator/x86emu/decode.c | 4 ++++ drivers/bios_emulator/x86emu/ops.c | 5 +++++ drivers/bios_emulator/x86emu/ops2.c | 4 ++++ drivers/bios_emulator/x86emu/prim_ops.c | 4 ++++ drivers/bios_emulator/x86emu/sys.c | 4 ++++ 9 files changed, 32 insertions(+) diff --git a/drivers/bios_emulator/besys.c b/drivers/bios_emulator/besys.c index 2a8e1a0..4c4bc8d 100644 --- a/drivers/bios_emulator/besys.c +++ b/drivers/bios_emulator/besys.c @@ -49,6 +49,7 @@ #include "biosemui.h" +#if defined(CONFIG_BIOSEMU) /*------------------------- Global Variables ------------------------------*/ #ifndef __i386__ @@ -717,3 +718,4 @@ void X86API BE_outl(X86EMU_pioAddr port, u32 val) #endif LOG_outpd(port, val); } +#endif diff --git a/drivers/bios_emulator/bios.c b/drivers/bios_emulator/bios.c index ed5437e..7aa1bfb2e 100644 --- a/drivers/bios_emulator/bios.c +++ b/drivers/bios_emulator/bios.c @@ -43,6 +43,7 @@ #include "biosemui.h" +#if defined(CONFIG_BIOSEMU) /*----------------------------- Implementation ----------------------------*/ /**************************************************************************** @@ -319,3 +320,4 @@ void _BE_bios_init(u32 * intrTab) bios_intr_tab[0x6D] = int10; X86EMU_setupIntrFuncs(bios_intr_tab); } +#endif diff --git a/drivers/bios_emulator/biosemu.c b/drivers/bios_emulator/biosemu.c index 06d4ad3..4c3aedf 100644 --- a/drivers/bios_emulator/biosemu.c +++ b/drivers/bios_emulator/biosemu.c @@ -48,6 +48,8 @@ #include "biosemui.h" #include +#if defined(CONFIG_BIOSEMU) + BE_sysEnv _BE_env = {{0}}; static X86EMU_memFuncs _BE_mem __attribute__((section(".got2"))) = { BE_rdb, @@ -368,3 +370,4 @@ int X86API BE_int86x(int intno, RMREGS * in, RMREGS * out, RMSREGS * sregs) sregs->gs = M.x86.R_GS; return out->x.ax; } +#endif diff --git a/drivers/bios_emulator/x86emu/debug.c b/drivers/bios_emulator/x86emu/debug.c index 0f58a69..915739c 100644 --- a/drivers/bios_emulator/x86emu/debug.c +++ b/drivers/bios_emulator/x86emu/debug.c @@ -40,6 +40,8 @@ #include "x86emu/x86emui.h" #include +#if defined(CONFIG_BIOSEMU) + /*----------------------------- Implementation ----------------------------*/ #ifdef DEBUG @@ -459,3 +461,5 @@ void x86emu_dump_xregs(void) printk("NC "); printk("\n"); } + +#endif diff --git a/drivers/bios_emulator/x86emu/decode.c b/drivers/bios_emulator/x86emu/decode.c index 1e2dcfe..879f0a0 100644 --- a/drivers/bios_emulator/x86emu/decode.c +++ b/drivers/bios_emulator/x86emu/decode.c @@ -39,6 +39,8 @@ #include "x86emu/x86emui.h" +#if defined(CONFIG_BIOSEMU) + /*----------------------------- Implementation ----------------------------*/ /**************************************************************************** @@ -1142,3 +1144,5 @@ unsigned decode_rmXX_address(int mod, int rm) return decode_rm01_address(rm); return decode_rm10_address(rm); } + +#endif diff --git a/drivers/bios_emulator/x86emu/ops.c b/drivers/bios_emulator/x86emu/ops.c index d1380ce..d334fb5 100644 --- a/drivers/bios_emulator/x86emu/ops.c +++ b/drivers/bios_emulator/x86emu/ops.c @@ -76,6 +76,9 @@ ****************************************************************************/ #include "x86emu/x86emui.h" + +#if defined(CONFIG_BIOSEMU) + /*----------------------------- Implementation ----------------------------*/ /* constant arrays to do several instructions in just one function */ @@ -5429,3 +5432,5 @@ void (*x86emu_optab[256])(u8) __attribute__ ((section(".got2"))) = /* 0xfe */ x86emuOp_opcFE_byte_RM, /* 0xff */ x86emuOp_opcFF_word_RM, }; + +#endif diff --git a/drivers/bios_emulator/x86emu/ops2.c b/drivers/bios_emulator/x86emu/ops2.c index 631a340..81c0d49 100644 --- a/drivers/bios_emulator/x86emu/ops2.c +++ b/drivers/bios_emulator/x86emu/ops2.c @@ -46,6 +46,8 @@ #include "x86emu/x86emui.h" +#if defined(CONFIG_BIOSEMU) + /*----------------------------- Implementation ----------------------------*/ /**************************************************************************** @@ -1768,3 +1770,5 @@ void (*x86emu_optab2[256])(u8) __attribute__((section(".got2"))) = /* 0xfe */ x86emuOp2_illegal_op, /* 0xff */ x86emuOp2_illegal_op, }; + +#endif diff --git a/drivers/bios_emulator/x86emu/prim_ops.c b/drivers/bios_emulator/x86emu/prim_ops.c index e0827d7..c1152ea 100644 --- a/drivers/bios_emulator/x86emu/prim_ops.c +++ b/drivers/bios_emulator/x86emu/prim_ops.c @@ -100,6 +100,8 @@ #define PRIM_OPS_NO_REDEFINE_ASM #include "x86emu/x86emui.h" +#if defined(CONFIG_BIOSEMU) + /*------------------------- Global Variables ------------------------------*/ static u32 x86emu_parity_tab[8] = @@ -2443,3 +2445,5 @@ DB( if (CHECK_SP_ACCESS()) M.x86.R_SP += 4; return res; } + +#endif diff --git a/drivers/bios_emulator/x86emu/sys.c b/drivers/bios_emulator/x86emu/sys.c index bb7fcd9..566389f 100644 --- a/drivers/bios_emulator/x86emu/sys.c +++ b/drivers/bios_emulator/x86emu/sys.c @@ -41,6 +41,8 @@ #include "x86emu/x86emui.h" +#if defined(CONFIG_BIOSEMU) + /*------------------------- Global Variables ------------------------------*/ X86EMU_sysEnv _X86EMU_env; /* Global emulator machine state */ @@ -320,3 +322,5 @@ void X86EMU_prepareForInt(int num) M.x86.R_IP = mem_access_word(num * 4); M.x86.intr = 0; } + +#endif -- cgit v1.1 From 0dc4279b08ff82472bec2e2c90858602459febe8 Mon Sep 17 00:00:00 2001 From: Jason Jin Date: Wed, 8 Aug 2007 09:01:46 +0800 Subject: Minor fix for bios emulator makefile Add $(obj) to LIB avoiding objects be built in the source dir Signed-off-by: Jason Jin --- drivers/bios_emulator/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bios_emulator/Makefile b/drivers/bios_emulator/Makefile index ba7d436..586e83b 100644 --- a/drivers/bios_emulator/Makefile +++ b/drivers/bios_emulator/Makefile @@ -1,6 +1,6 @@ include $(TOPDIR)/config.mk -LIB := libatibiosemu.a +LIB := $(obj)libatibiosemu.a X86DIR = ./x86emu -- cgit v1.1 From a22806469a8f2b69c829f4fd5361fdebd0cb01b4 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Wed, 8 Aug 2007 04:14:28 -0500 Subject: Treat ppc64 host as ppc Signed-off-by: Kumar Gala --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 988dba8..2ff3e06 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,7 @@ HOSTARCH := $(shell uname -m | \ -e s/arm.*/arm/ \ -e s/sa110/arm/ \ -e s/powerpc/ppc/ \ + -e s/ppc64/ppc/ \ -e s/macppc/ppc/) HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \ -- cgit v1.1 From 1ded0242e437259366792d52b7e9d1e1931d8fa5 Mon Sep 17 00:00:00 2001 From: Lee Nipper Date: Thu, 14 Jun 2007 20:07:33 -0500 Subject: mpc83xx: Add support for 8360 silicon revision 2.1 This change adds 8360 silicon revision 2.1 support to u-boot. Signed-off-by: Lee Nipper Signed-off-by: Kim Phillips --- board/mpc8360emds/mpc8360emds.c | 4 +++- cpu/mpc83xx/cpu.c | 5 ++++- include/mpc83xx.h | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/board/mpc8360emds/mpc8360emds.c b/board/mpc8360emds/mpc8360emds.c index 562eb8b..de4ca1e 100644 --- a/board/mpc8360emds/mpc8360emds.c +++ b/board/mpc8360emds/mpc8360emds.c @@ -103,7 +103,9 @@ int board_early_init_f(void) /* Disable G1TXCLK, G2TXCLK h/w buffers (rev.2 h/w bug workaround) */ if (immr->sysconf.spridr == SPR_8360_REV20 || - immr->sysconf.spridr == SPR_8360E_REV20) + immr->sysconf.spridr == SPR_8360E_REV20 || + immr->sysconf.spridr == SPR_8360_REV21 || + immr->sysconf.spridr == SPR_8360E_REV21) bcsr[0xe] = 0x30; return 0; diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index 841fe82..bfac227 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -113,12 +113,14 @@ int checkcpu(void) case SPR_8360E_REV11: case SPR_8360E_REV12: case SPR_8360E_REV20: + case SPR_8360E_REV21: puts("MPC8360E, "); break; case SPR_8360_REV10: case SPR_8360_REV11: case SPR_8360_REV12: case SPR_8360_REV20: + case SPR_8360_REV21: puts("MPC8360, "); break; case SPR_8323E_REV10: @@ -150,7 +152,8 @@ int checkcpu(void) puts("MPC8313E, "); break; default: - puts("Rev: Unknown revision number.\nWarning: Unsupported cpu revision!\n"); + printf("Rev: Unknown revision number:%08x\n" + "Warning: Unsupported cpu revision!\n",spridr); return 0; } diff --git a/include/mpc83xx.h b/include/mpc83xx.h index 336c0ac..01df06b 100644 --- a/include/mpc83xx.h +++ b/include/mpc83xx.h @@ -86,6 +86,8 @@ #define SPR_8360_REV12 0x80490012 #define SPR_8360E_REV20 0x80480020 #define SPR_8360_REV20 0x80490020 +#define SPR_8360E_REV21 0x80480021 +#define SPR_8360_REV21 0x80490021 #define SPR_8323E_REV10 0x80620010 #define SPR_8323_REV10 0x80630010 -- cgit v1.1 From 5d497e6bf0f5bf63729b4a47b3fd786d3c77a1bc Mon Sep 17 00:00:00 2001 From: "david.saada" Date: Mon, 18 Jun 2007 09:09:53 -0700 Subject: MPC83xx: Fix makefile to generate config.h file in the build directory MPC83xx: Fix the Makefile config sections to generate the include/config.h file in the build directory instead of the source directory. Signed-off-by: David Saada Signed-off-by: Kim Phillips --- Makefile | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 0e6d399..704e480 100644 --- a/Makefile +++ b/Makefile @@ -1666,11 +1666,11 @@ MPC8313ERDB_66_config: unconfig @mkdir -p $(obj)include @echo "" >$(obj)include/config.h ; \ if [ "$(findstring _33_,$@)" ] ; then \ - echo "...33M ..." ; \ + echo -n "...33M ..." ; \ echo "#define CFG_33MHZ" >>$(obj)include/config.h ; \ fi ; \ if [ "$(findstring _66_,$@)" ] ; then \ - echo "...66M..." ; \ + echo -n "...66M..." ; \ echo "#define CFG_66MHZ" >>$(obj)include/config.h ; \ fi ; @$(MKCONFIG) -a MPC8313ERDB ppc mpc83xx mpc8313erdb @@ -1682,7 +1682,7 @@ MPC832XEMDS_SLAVE_config: unconfig @mkdir -p $(obj)include @echo "" >$(obj)include/config.h ; \ if [ "$(findstring _HOST_,$@)" ] ; then \ - echo "... PCI HOST " ; \ + echo -n "... PCI HOST " ; \ echo "#define CONFIG_PCI" >>$(obj)include/config.h ; \ fi ; \ if [ "$(findstring _SLAVE_,$@)" ] ; then \ @@ -1691,11 +1691,11 @@ MPC832XEMDS_SLAVE_config: unconfig echo "#define CONFIG_PCISLAVE" >>$(obj)include/config.h ; \ fi ; \ if [ "$(findstring _33_,$@)" ] ; then \ - echo "...33M ..." ; \ + echo -n "...33M ..." ; \ echo "#define PCI_33M" >>$(obj)include/config.h ; \ fi ; \ if [ "$(findstring _66_,$@)" ] ; then \ - echo "...66M..." ; \ + echo -n "...66M..." ; \ echo "#define PCI_66M" >>$(obj)include/config.h ; \ fi ; @$(MKCONFIG) -a MPC832XEMDS ppc mpc83xx mpc832xemds @@ -1724,7 +1724,7 @@ MPC8360EMDS_SLAVE_config: unconfig @mkdir -p $(obj)include @echo "" >$(obj)include/config.h ; \ if [ "$(findstring _HOST_,$@)" ] ; then \ - echo "... PCI HOST " ; \ + echo -n "... PCI HOST " ; \ echo "#define CONFIG_PCI" >>$(obj)include/config.h ; \ fi ; \ if [ "$(findstring _SLAVE_,$@)" ] ; then \ @@ -1733,11 +1733,11 @@ MPC8360EMDS_SLAVE_config: unconfig echo "#define CONFIG_PCISLAVE" >>$(obj)include/config.h ; \ fi ; \ if [ "$(findstring _33_,$@)" ] ; then \ - echo "...33M ..." ; \ + echo -n "...33M ..." ; \ echo "#define PCI_33M" >>$(obj)include/config.h ; \ fi ; \ if [ "$(findstring _66_,$@)" ] ; then \ - echo "...66M..." ; \ + echo -n "...66M..." ; \ echo "#define PCI_66M" >>$(obj)include/config.h ; \ fi ; @$(MKCONFIG) -a MPC8360EMDS ppc mpc83xx mpc8360emds -- cgit v1.1 From 9546266999f0b9b51372636614211b88d90f0f25 Mon Sep 17 00:00:00 2001 From: Martin Krause Date: Fri, 22 Jun 2007 13:04:22 +0200 Subject: TQM834x: cleanup configuraton Remove irritating #undef DEBUG Signed-off-by: Martin Krause Signed-off-by: Kim Phillips --- include/configs/TQM834x.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/configs/TQM834x.h b/include/configs/TQM834x.h index c3efb7b..661712b 100644 --- a/include/configs/TQM834x.h +++ b/include/configs/TQM834x.h @@ -28,9 +28,6 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define DEBUG -#undef DEBUG - /* * High Level Configuration Options */ -- cgit v1.1 From df33f6b4d6d63693dd9200808b242de1b86cb8e8 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 3 Jul 2007 13:04:34 -0500 Subject: Update SCCR programming in cpu_init_f() to support all 83xx processors Update the cpu_init_f() function in cpu/mpc83xx/cpu_init.c to program the bitfields for all 83xx processors. The code to update some bitfields was compiled only on some processors. Now, the bitfields are programmed as long as the corresponding CFG_SCCR option is defined in the board header file. This means that the board header file should not define any CFG_SCCR macros for bitfields that don't exist on that processor, otherwise the SCCR will be programmed incorrectly. Signed-off-by: Timur Tabi Signed-off-by: Kim Phillips --- cpu/mpc83xx/cpu_init.c | 14 ++++++++++++-- include/mpc83xx.h | 2 ++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c index 3ac9161..53a5f59 100644 --- a/cpu/mpc83xx/cpu_init.c +++ b/cpu/mpc83xx/cpu_init.c @@ -83,20 +83,30 @@ void cpu_init_f (volatile immap_t * im) im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_TSEC2EP) | (CFG_SPCR_TSEC2EP << SPCR_TSEC2EP_SHIFT); #endif -#ifdef CONFIG_MPC834X #ifdef CFG_SCCR_TSEC1CM /* TSEC1 clock mode */ im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC1CM) | (CFG_SCCR_TSEC1CM << SCCR_TSEC1CM_SHIFT); #endif + #ifdef CFG_SCCR_TSEC2CM /* TSEC2 & I2C1 clock mode */ im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC2CM) | (CFG_SCCR_TSEC2CM << SCCR_TSEC2CM_SHIFT); #endif + +#ifdef CFG_SCCR_TSEC1ON + /* TSEC1 clock switch */ + im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC1ON) | (CFG_SCCR_TSEC1ON << SCCR_TSEC1ON_SHIFT); +#endif + +#ifdef CFG_SCCR_TSEC2ON + /* TSEC2 clock switch */ + im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC2ON) | (CFG_SCCR_TSEC2ON << SCCR_TSEC2ON_SHIFT); +#endif + #ifdef CFG_SCCR_USBMPHCM /* USB MPH clock mode */ im->clk.sccr = (im->clk.sccr & ~SCCR_USBMPHCM) | (CFG_SCCR_USBMPHCM << SCCR_USBMPHCM_SHIFT); #endif -#endif /* CONFIG_MPC834X */ #ifdef CFG_SCCR_PCICM /* PCI & DMA clock mode */ diff --git a/include/mpc83xx.h b/include/mpc83xx.h index 01df06b..829dbf9 100644 --- a/include/mpc83xx.h +++ b/include/mpc83xx.h @@ -602,7 +602,9 @@ #define SCCR_TSEC1CM_3 0xC0000000 #define SCCR_TSEC1ON 0x20000000 +#define SCCR_TSEC1ON_SHIFT 29 #define SCCR_TSEC2ON 0x10000000 +#define SCCR_TSEC2ON_SHIFT 28 #endif -- cgit v1.1 From e739bc95797aac4fefc4c75b55c7c78e59d3ea9c Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 3 Jul 2007 13:46:32 -0500 Subject: FSL I2C driver programs the two I2C busses differently The i2c_init() function in fsl_i2c.c programs the two I2C busses differently. The second I2C bus has its slave address programmed incorrectly and is missing a 5-us delay. Signed-off-by: Timur Tabi Signed-off-by: Kim Phillips --- drivers/fsl_i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/fsl_i2c.c b/drivers/fsl_i2c.c index ebae5af..22485ea 100644 --- a/drivers/fsl_i2c.c +++ b/drivers/fsl_i2c.c @@ -69,9 +69,10 @@ i2c_init(int speed, int slaveadd) dev = (struct fsl_i2c *) (CFG_IMMR + CFG_I2C2_OFFSET); writeb(0, &dev->cr); /* stop I2C controller */ + udelay(5); /* let it shutdown in peace */ writeb(0x3F, &dev->fdr); /* set bus speed */ writeb(0x3F, &dev->dfsrr); /* set default filter */ - writeb(slaveadd, &dev->adr); /* write slave address */ + writeb(slaveadd << 1, &dev->adr); /* write slave address */ writeb(0x0, &dev->sr); /* clear status register */ writeb(I2C_CR_MEN, &dev->cr); /* start I2C controller */ #endif /* CFG_I2C2_OFFSET */ -- cgit v1.1 From 66dc2c2dc51f8b88bb8e231bc80cd92eae1d6476 Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Mon, 25 Jun 2007 13:21:12 +0800 Subject: mpc83xx: Revise the MPC8360EMDS readme doc When the rev2.x silicon mount on the MPC8360EMDS baord, and if you are using the u-boot version after the commit 3fc0bd159103b536e1c54c6f4457a09b3aba66ca. to make the ethernet interface usable, we have to setup the jumpers correctly. Signed-off-by: Dave Liu Signed-off-by: Kim Phillips --- doc/README.mpc8360emds | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/doc/README.mpc8360emds b/doc/README.mpc8360emds index c87469f..5f20247 100644 --- a/doc/README.mpc8360emds +++ b/doc/README.mpc8360emds @@ -21,7 +21,13 @@ Freescale MPC8360EMDS Board SW3[1:8]= 0000_0001 refers to bits labeled 1 through 6 is set as "On" and bits labeled 8 is set as "Off". -1.1 For the MPC8360E PB PROTO Board +1.1 There are three type boards for MPC8360E silicon up to now, They are + + * MPC8360E-MDS-PB PROTO (a.k.a 8360SYS PROTOTYPE) + * MPC8360E-MDS-PB PILOT (a.k.a 8360SYS PILOT) + * MPC8360EA-MDS-PB PROTO (a.k.a 8360SYS2 PROTOTYPE) + +1.2 For all the MPC8360EMDS Board First, make sure the board default setting is consistent with the document shipped with your board. Then apply the following setting: @@ -33,6 +39,21 @@ Freescale MPC8360EMDS Board JP6 1-2 on board Oscillator: 66M +1.3 Since different board/chip rev. combinations have AC timing issues, + u-boot forces RGMII-ID (RGMII with Internal Delay) mode on by default + by the patch (mpc83xx: Disable G1TXCLK, G2TXCLK h/w buffers). + + When the rev2.x silicon mount on these boards, and if you are using + u-boot version after this patch, to make the ethernet interfaces usable, + and to enable RGMII-ID on your board, you have to setup the jumpers + correctly. + + * MPC8360E-MDS-PB PROTO + nothing to do + * MPC8360E-MDS-PB PILOT + JP9 and JP8 should be ON + * MPC8360EA-MDS-PB PROTO + JP2 and JP3 should be ON 2. Memory Map -- cgit v1.1 From ff9658d7049bf8c8e8e0a05dbe5e9f7e91aa5a5d Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Mon, 25 Jun 2007 10:41:04 +0800 Subject: mpc83xx: Fix the align bug of SDMA buffer According to the latest user manual, the SDMA temporary buffer base address must be 4KB aligned. Signed-off-by: Dave Liu Signed-off-by: Kim Phillips --- drivers/qe/qe.c | 2 +- drivers/qe/qe.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c index 5f20962..0f5232a 100644 --- a/drivers/qe/qe.c +++ b/drivers/qe/qe.c @@ -98,7 +98,7 @@ static void qe_sdma_init(void) out_be32(&p->sdaqmr, 0); /* Allocate 2KB temporary buffer for sdma */ - sdma_buffer_base = qe_muram_alloc(2048, 64); + sdma_buffer_base = qe_muram_alloc(2048, 4096); out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK); /* Clear sdma status */ diff --git a/drivers/qe/qe.h b/drivers/qe/qe.h index 0bcd0a9..400b1a6 100644 --- a/drivers/qe/qe.h +++ b/drivers/qe/qe.h @@ -29,7 +29,7 @@ #define QE_NUM_OF_BRGS 16 #define UCC_MAX_NUM 8 -#define QE_DATAONLY_BASE (uint)(128) +#define QE_DATAONLY_BASE 0 #define QE_DATAONLY_SIZE (QE_MURAM_SIZE - QE_DATAONLY_BASE) /* QE threads SNUM -- cgit v1.1 From 9be39a67c9f8fef7107f5df09d673005f04d0963 Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Mon, 25 Jun 2007 10:41:56 +0800 Subject: mpc83xx: Add support for the display of reset status 83xx processor family has many reset sources, such as power on reset, software hard reset, software soft reset, JTAG, bus monitor, software watchdog, check stop reset, external hard reset, external software reset. sometimes, to figure out the fault of system, we need to know the cause of reset early before the prompt of u-boot present. Signed-off-by: Dave Liu Signed-off-by: Kim Phillips --- cpu/mpc83xx/cpu_init.c | 36 ++++++++++++++++++++++++++++++++++++ include/common.h | 2 ++ lib_ppc/board.c | 6 ++++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c index 53a5f59..7224979 100644 --- a/cpu/mpc83xx/cpu_init.c +++ b/cpu/mpc83xx/cpu_init.c @@ -257,3 +257,39 @@ int cpu_init_r (void) #endif return 0; } + +/* + * Figure out the cause of the reset + */ +int prt_83xx_rsr(void) +{ + static struct { + ulong mask; + char *desc; + } bits[] = { + { + RSR_SWSR, "Software Soft"}, { + RSR_SWHR, "Software Hard"}, { + RSR_JSRS, "JTAG Soft"}, { + RSR_CSHR, "Check Stop"}, { + RSR_SWRS, "Software Watchdog"}, { + RSR_BMRS, "Bus Monitor"}, { + RSR_SRS, "External/Internal Soft"}, { + RSR_HRS, "External/Internal Hard"} + }; + static int n = sizeof bits / sizeof bits[0]; + ulong rsr = gd->reset_status; + int i; + char *sep; + + puts("Reset Status:"); + + sep = " "; + for (i = 0; i < n; i++) + if (rsr & bits[i].mask) { + printf("%s%s", sep, bits[i].desc); + sep = ", "; + } + puts("\n\n"); + return 0; +} diff --git a/include/common.h b/include/common.h index ac29d3a..a822d28 100644 --- a/include/common.h +++ b/include/common.h @@ -526,6 +526,8 @@ void cpu_init_f (void); int cpu_init_r (void); #if defined(CONFIG_8260) int prt_8260_rsr (void); +#elif defined(CONFIG_MPC83XX) +int prt_83xx_rsr (void); #endif /* $(CPU)/interrupts.c */ diff --git a/lib_ppc/board.c b/lib_ppc/board.c index 325f5c2..c87d46c 100644 --- a/lib_ppc/board.c +++ b/lib_ppc/board.c @@ -309,7 +309,9 @@ init_fnc_t *init_sequence[] = { prt_8260_rsr, prt_8260_clks, #endif /* CONFIG_8260 */ - +#if defined(CONFIG_MPC83XX) + prt_83xx_rsr, +#endif checkcpu, #if defined(CONFIG_MPC5xxx) prt_mpc5xxx_clks, @@ -376,7 +378,7 @@ void board_init_f (ulong bootflag) /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory"); -#if !defined(CONFIG_CPM2) +#if !defined(CONFIG_CPM2) && !defined(CONFIG_MPC83XX) /* Clear initial global data */ memset ((void *) gd, 0, sizeof (gd_t)); #endif -- cgit v1.1 From 26d02c9bbac1751c5e19294f000100b48d43a920 Mon Sep 17 00:00:00 2001 From: Jerry Van Baren Date: Wed, 4 Jul 2007 21:27:30 -0400 Subject: mpc83xx: Replace fdt_node_offset() with fdt_find_node_by_path(). The new name matches more closely the kernel's name, which is also a much better description. These are the mpc83xx changes made necessary by the function name change. Signed-off-by: Wolfgang Grandegger Acked-by: Gerald Van Baren Signed-off-by: Kim Phillips --- board/mpc8360emds/mpc8360emds.c | 5 ++--- board/mpc8360emds/pci.c | 20 +++++++++----------- cpu/mpc83xx/cpu.c | 9 +++------ 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/board/mpc8360emds/mpc8360emds.c b/board/mpc8360emds/mpc8360emds.c index de4ca1e..f63d3ae 100644 --- a/board/mpc8360emds/mpc8360emds.c +++ b/board/mpc8360emds/mpc8360emds.c @@ -30,8 +30,7 @@ #endif #if defined(CONFIG_OF_FLAT_TREE) #include -#endif -#if defined(CONFIG_OF_LIBFDT) +#elif defined(CONFIG_OF_LIBFDT) #include #include #endif @@ -683,7 +682,7 @@ ft_board_setup(void *blob, bd_t *bd) int nodeoffset; int tmp[2]; - nodeoffset = fdt_path_offset (fdt, "/memory"); + nodeoffset = fdt_find_node_by_path(fdt, "/memory"); if (nodeoffset >= 0) { tmp[0] = cpu_to_be32(bd->bi_memstart); tmp[1] = cpu_to_be32(bd->bi_memsize); diff --git a/board/mpc8360emds/pci.c b/board/mpc8360emds/pci.c index 158effe..8d34dbe 100644 --- a/board/mpc8360emds/pci.c +++ b/board/mpc8360emds/pci.c @@ -20,8 +20,7 @@ #include #if defined(CONFIG_OF_FLAT_TREE) #include -#endif -#if defined(CONFIG_OF_LIBFDT) +#elif defined(CONFIG_OF_LIBFDT) #include #include #endif @@ -207,7 +206,7 @@ void pci_init_board(void) /* Switch temporarily to I2C bus #2 */ orig_i2c_bus = i2c_get_bus_num(); - i2c_set_bus_num(1); + i2c_set_bus_num(1); val8 = 0; i2c_write(0x23, 0x6, 1, &val8, 1); @@ -311,26 +310,25 @@ ft_pci_setup(void *blob, bd_t *bd) int err; int tmp[2]; - nodeoffset = fdt_path_offset (fdt, "/" OF_SOC "/pci@8500"); + nodeoffset = fdt_find_node_by_path(fdt, "/" OF_SOC "/pci@8500"); if (nodeoffset >= 0) { tmp[0] = cpu_to_be32(hose[0].first_busno); tmp[1] = cpu_to_be32(hose[0].last_busno); err = fdt_setprop(fdt, nodeoffset, "bus-range", tmp, sizeof(tmp)); } } -#endif /* CONFIG_OF_LIBFDT */ -#ifdef CONFIG_OF_FLAT_TREE +#elif defined(CONFIG_OF_FLAT_TREE) void ft_pci_setup(void *blob, bd_t *bd) { - u32 *p; - int len; + u32 *p; + int len; - p = (u32 *)ft_get_prop(blob, "/" OF_SOC "/pci@8500/bus-range", &len); - if (p != NULL) { + p = (u32 *)ft_get_prop(blob, "/" OF_SOC "/pci@8500/bus-range", &len); + if (p != NULL) { p[0] = hose[0].first_busno; p[1] = hose[0].last_busno; - } + } } #endif /* CONFIG_OF_FLAT_TREE */ #endif /* CONFIG_PCI */ diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index bfac227..40e8d0c 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -33,8 +33,7 @@ #include #if defined(CONFIG_OF_FLAT_TREE) #include -#endif -#if defined(CONFIG_OF_LIBFDT) +#elif defined(CONFIG_OF_LIBFDT) #include #include #endif @@ -490,7 +489,7 @@ ft_cpu_setup(void *blob, bd_t *bd) int j; for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) { - nodeoffset = fdt_path_offset(fdt, fixup_props[j].node); + nodeoffset = fdt_find_node_by_path(fdt, fixup_props[j].node); if (nodeoffset >= 0) { err = (*fixup_props[j].set_fn)(blob, nodeoffset, fixup_props[j].prop, bd); if (err < 0) @@ -501,9 +500,7 @@ ft_cpu_setup(void *blob, bd_t *bd) } } } -#endif - -#if defined(CONFIG_OF_FLAT_TREE) +#elif defined(CONFIG_OF_FLAT_TREE) void ft_cpu_setup(void *blob, bd_t *bd) { -- cgit v1.1 From 8be404459a6b7395415a57bb35e8377e3b2b5acb Mon Sep 17 00:00:00 2001 From: Jerry Van Baren Date: Wed, 4 Jul 2007 21:34:24 -0400 Subject: mpc83xx: Fix errors when CONFIG_OF_LIBFDT is enabled Several node strings were not correct (trailing slashes and properties in the strings) Added setting of the timebase-frequency. Improved error messages and use debug() instead of printf(). Signed-off-by: Gerald Van Baren Signed-off-by: Kim Phillips --- cpu/mpc83xx/cpu.c | 74 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index 40e8d0c..30ecb85 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -339,7 +339,7 @@ static int fdt_set_eth0(void *fdt, int nodeoffset, const char *name, bd_t *bd) if (fdt_get_property(fdt, nodeoffset, name, 0)) { return fdt_setprop(fdt, nodeoffset, name, bd->bi_enetaddr, 6); } - return -FDT_ERR_NOTFOUND; + return 0; } #ifdef CONFIG_HAS_ETH1 /* second onboard ethernet port */ @@ -351,7 +351,7 @@ static int fdt_set_eth1(void *fdt, int nodeoffset, const char *name, bd_t *bd) if (fdt_get_property(fdt, nodeoffset, name, 0)) { return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet1addr, 6); } - return -FDT_ERR_NOTFOUND; + return 0; } #endif #ifdef CONFIG_HAS_ETH2 @@ -364,7 +364,7 @@ static int fdt_set_eth2(void *fdt, int nodeoffset, const char *name, bd_t *bd) if (fdt_get_property(fdt, nodeoffset, name, 0)) { return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet2addr, 6); } - return -FDT_ERR_NOTFOUND; + return 0; } #endif #ifdef CONFIG_HAS_ETH3 @@ -377,7 +377,7 @@ static int fdt_set_eth3(void *fdt, int nodeoffset, const char *name, bd_t *bd) if (fdt_get_property(fdt, nodeoffset, name, 0)) { return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet3addr, 6); } - return -FDT_ERR_NOTFOUND; + return 0; } #endif @@ -391,10 +391,19 @@ static int fdt_set_busfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } +static int fdt_set_tbfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd) +{ + u32 tmp; + /* + * Create or update the property. + */ + tmp = cpu_to_be32(OF_TBCLK); + return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); +} + + /* - * Fixups to the fdt. If "create" is TRUE, the node is created - * unconditionally. If "create" is FALSE, the node is updated - * only if it already exists. + * Fixups to the fdt. */ static const struct { char *node; @@ -402,83 +411,87 @@ static const struct { int (*set_fn)(void *fdt, int nodeoffset, const char *name, bd_t *bd); } fixup_props[] = { { "/cpus/" OF_CPU, - "bus-frequency", - fdt_set_busfreq + "timebase-frequency", + fdt_set_tbfreq }, - { "/cpus/" OF_SOC, + { "/cpus/" OF_CPU, "bus-frequency", fdt_set_busfreq }, - { "/" OF_SOC "/serial@4500/", + { "/cpus/" OF_CPU, + "clock-frequency", + fdt_set_busfreq + }, + { "/" OF_SOC "/serial@4500", "clock-frequency", fdt_set_busfreq }, - { "/" OF_SOC "/serial@4600/", + { "/" OF_SOC "/serial@4600", "clock-frequency", fdt_set_busfreq }, #ifdef CONFIG_TSEC1 - { "/" OF_SOC "/ethernet@24000, + { "/" OF_SOC "/ethernet@24000", "mac-address", fdt_set_eth0 }, - { "/" OF_SOC "/ethernet@24000, + { "/" OF_SOC "/ethernet@24000", "local-mac-address", fdt_set_eth0 }, #endif #ifdef CONFIG_TSEC2 - { "/" OF_SOC "/ethernet@25000, + { "/" OF_SOC "/ethernet@25000", "mac-address", fdt_set_eth1 }, - { "/" OF_SOC "/ethernet@25000, + { "/" OF_SOC "/ethernet@25000", "local-mac-address", fdt_set_eth1 }, #endif #ifdef CONFIG_UEC_ETH1 #if CFG_UEC1_UCC_NUM == 0 /* UCC1 */ - { "/" OF_QE "/ucc@2000/mac-address", + { "/" OF_QE "/ucc@2000", "mac-address", fdt_set_eth0 }, - { "/" OF_QE "/ucc@2000/mac-address", + { "/" OF_QE "/ucc@2000", "local-mac-address", fdt_set_eth0 }, #elif CFG_UEC1_UCC_NUM == 2 /* UCC3 */ - { "/" OF_QE "/ucc@2200/mac-address", + { "/" OF_QE "/ucc@2200", "mac-address", fdt_set_eth0 }, - { "/" OF_QE "/ucc@2200/mac-address", + { "/" OF_QE "/ucc@2200", "local-mac-address", fdt_set_eth0 }, #endif -#endif +#endif /* CONFIG_UEC_ETH1 */ #ifdef CONFIG_UEC_ETH2 #if CFG_UEC2_UCC_NUM == 1 /* UCC2 */ - { "/" OF_QE "/ucc@3000/mac-address", + { "/" OF_QE "/ucc@3000", "mac-address", fdt_set_eth1 }, - { "/" OF_QE "/ucc@3000/mac-address", + { "/" OF_QE "/ucc@3000", "local-mac-address", fdt_set_eth1 }, #elif CFG_UEC1_UCC_NUM == 3 /* UCC4 */ - { "/" OF_QE "/ucc@3200/mac-address", + { "/" OF_QE "/ucc@3200", "mac-address", fdt_set_eth1 }, - { "/" OF_QE "/ucc@3200/mac-address", + { "/" OF_QE "/ucc@3200", "local-mac-address", fdt_set_eth1 }, #endif -#endif +#endif /* CONFIG_UEC_ETH2 */ }; void @@ -491,12 +504,17 @@ ft_cpu_setup(void *blob, bd_t *bd) for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) { nodeoffset = fdt_find_node_by_path(fdt, fixup_props[j].node); if (nodeoffset >= 0) { - err = (*fixup_props[j].set_fn)(blob, nodeoffset, fixup_props[j].prop, bd); + err = fixup_props[j].set_fn(blob, nodeoffset, + fixup_props[j].prop, bd); if (err < 0) - printf("set_fn/libfdt: %s %s returned %s\n", + debug("Problem setting %s = %s: %s\n", fixup_props[j].node, fixup_props[j].prop, fdt_strerror(err)); + } else { + debug("Couldn't find %s: %s\n", + fixup_props[j].node, + fdt_strerror(nodeoffset)); } } } -- cgit v1.1 From f57ac7a7b37109245b69db80839ebee26179966a Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Wed, 25 Jul 2007 19:25:22 -0500 Subject: mpc83xx: fix 8360 and cpu functions to update fdt being passed ..and not the global fdt. Rename local fdt vars to blob so as not to be confused with the global var with the same three-letter name. Signed-off-by: Kim Phillips --- board/mpc8360emds/mpc8360emds.c | 4 ++-- board/mpc8360emds/pci.c | 4 ++-- cpu/mpc83xx/cpu.c | 36 ++++++++++++++++++------------------ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/board/mpc8360emds/mpc8360emds.c b/board/mpc8360emds/mpc8360emds.c index f63d3ae..b109317 100644 --- a/board/mpc8360emds/mpc8360emds.c +++ b/board/mpc8360emds/mpc8360emds.c @@ -682,11 +682,11 @@ ft_board_setup(void *blob, bd_t *bd) int nodeoffset; int tmp[2]; - nodeoffset = fdt_find_node_by_path(fdt, "/memory"); + nodeoffset = fdt_find_node_by_path(blob, "/memory"); if (nodeoffset >= 0) { tmp[0] = cpu_to_be32(bd->bi_memstart); tmp[1] = cpu_to_be32(bd->bi_memsize); - fdt_setprop(fdt, nodeoffset, "reg", tmp, sizeof(tmp)); + fdt_setprop(blob, nodeoffset, "reg", tmp, sizeof(tmp)); } #else u32 *p; diff --git a/board/mpc8360emds/pci.c b/board/mpc8360emds/pci.c index 8d34dbe..8f90471 100644 --- a/board/mpc8360emds/pci.c +++ b/board/mpc8360emds/pci.c @@ -310,11 +310,11 @@ ft_pci_setup(void *blob, bd_t *bd) int err; int tmp[2]; - nodeoffset = fdt_find_node_by_path(fdt, "/" OF_SOC "/pci@8500"); + nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500"); if (nodeoffset >= 0) { tmp[0] = cpu_to_be32(hose[0].first_busno); tmp[1] = cpu_to_be32(hose[0].last_busno); - err = fdt_setprop(fdt, nodeoffset, "bus-range", tmp, sizeof(tmp)); + err = fdt_setprop(blob, nodeoffset, "bus-range", tmp, sizeof(tmp)); } } #elif defined(CONFIG_OF_FLAT_TREE) diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index 30ecb85..adf8083 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -331,74 +331,74 @@ void watchdog_reset (void) /* * "Setter" functions used to add/modify FDT entries. */ -static int fdt_set_eth0(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_eth0(void *blob, int nodeoffset, const char *name, bd_t *bd) { /* * Fix it up if it exists, don't create it if it doesn't exist. */ - if (fdt_get_property(fdt, nodeoffset, name, 0)) { - return fdt_setprop(fdt, nodeoffset, name, bd->bi_enetaddr, 6); + if (fdt_get_property(blob, nodeoffset, name, 0)) { + return fdt_setprop(blob, nodeoffset, name, bd->bi_enetaddr, 6); } return 0; } #ifdef CONFIG_HAS_ETH1 /* second onboard ethernet port */ -static int fdt_set_eth1(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_eth1(void *blob, int nodeoffset, const char *name, bd_t *bd) { /* * Fix it up if it exists, don't create it if it doesn't exist. */ - if (fdt_get_property(fdt, nodeoffset, name, 0)) { - return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet1addr, 6); + if (fdt_get_property(blob, nodeoffset, name, 0)) { + return fdt_setprop(blob, nodeoffset, name, bd->bi_enet1addr, 6); } return 0; } #endif #ifdef CONFIG_HAS_ETH2 /* third onboard ethernet port */ -static int fdt_set_eth2(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_eth2(void *blob, int nodeoffset, const char *name, bd_t *bd) { /* * Fix it up if it exists, don't create it if it doesn't exist. */ - if (fdt_get_property(fdt, nodeoffset, name, 0)) { - return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet2addr, 6); + if (fdt_get_property(blob, nodeoffset, name, 0)) { + return fdt_setprop(blob, nodeoffset, name, bd->bi_enet2addr, 6); } return 0; } #endif #ifdef CONFIG_HAS_ETH3 /* fourth onboard ethernet port */ -static int fdt_set_eth3(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_eth3(void *blob, int nodeoffset, const char *name, bd_t *bd) { /* * Fix it up if it exists, don't create it if it doesn't exist. */ - if (fdt_get_property(fdt, nodeoffset, name, 0)) { - return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet3addr, 6); + if (fdt_get_property(blob, nodeoffset, name, 0)) { + return fdt_setprop(blob, nodeoffset, name, bd->bi_enet3addr, 6); } return 0; } #endif -static int fdt_set_busfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_busfreq(void *blob, int nodeoffset, const char *name, bd_t *bd) { u32 tmp; /* * Create or update the property. */ tmp = cpu_to_be32(bd->bi_busfreq); - return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); + return fdt_setprop(blob, nodeoffset, name, &tmp, sizeof(tmp)); } -static int fdt_set_tbfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_tbfreq(void *blob, int nodeoffset, const char *name, bd_t *bd) { u32 tmp; /* * Create or update the property. */ tmp = cpu_to_be32(OF_TBCLK); - return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); + return fdt_setprop(blob, nodeoffset, name, &tmp, sizeof(tmp)); } @@ -408,7 +408,7 @@ static int fdt_set_tbfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd) static const struct { char *node; char *prop; - int (*set_fn)(void *fdt, int nodeoffset, const char *name, bd_t *bd); + int (*set_fn)(void *blob, int nodeoffset, const char *name, bd_t *bd); } fixup_props[] = { { "/cpus/" OF_CPU, "timebase-frequency", @@ -502,7 +502,7 @@ ft_cpu_setup(void *blob, bd_t *bd) int j; for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) { - nodeoffset = fdt_find_node_by_path(fdt, fixup_props[j].node); + nodeoffset = fdt_find_node_by_path(blob, fixup_props[j].node); if (nodeoffset >= 0) { err = fixup_props[j].set_fn(blob, nodeoffset, fixup_props[j].prop, bd); -- cgit v1.1 From 343d91009d55fc5b3ff8cc940597af6c6aa1d359 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Wed, 25 Jul 2007 19:25:28 -0500 Subject: mpc83xx: fixup generic pci for libfdt add libfdt support to the generic 83xx pci code Signed-off-by: Kim Phillips --- cpu/mpc83xx/pci.c | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/cpu/mpc83xx/pci.c b/cpu/mpc83xx/pci.c index 785d612..2298218 100644 --- a/cpu/mpc83xx/pci.c +++ b/cpu/mpc83xx/pci.c @@ -25,7 +25,14 @@ #include #include + +#if defined(CONFIG_OF_LIBFDT) +#include +#include +#elif defined(CONFIG_OF_FLAT_TREE) #include +#endif + #include #ifdef CONFIG_83XX_GENERIC_PCI @@ -163,7 +170,34 @@ void mpc83xx_pci_init(int num_buses, struct pci_region **reg, int warmboot) pci_init_bus(i, reg[i]); } -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_LIBFDT) +void ft_pci_setup(void *blob, bd_t *bd) +{ + int nodeoffset; + int err; + int tmp[2]; + + if (pci_num_buses < 1) + return; + + nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500"); + if (nodeoffset >= 0) { + tmp[0] = cpu_to_be32(pci_hose[0].first_busno); + tmp[1] = cpu_to_be32(pci_hose[0].last_busno); + err = fdt_setprop(blob, nodeoffset, "bus-range", tmp, sizeof(tmp)); + } + + if (pci_num_buses < 2) + return; + + nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8600"); + if (nodeoffset >= 0) { + tmp[0] = cpu_to_be32(pci_hose[0].first_busno); + tmp[1] = cpu_to_be32(pci_hose[0].last_busno); + err = fdt_setprop(blob, nodeoffset, "bus-range", tmp, sizeof(tmp)); + } +} +#elif CONFIG_OF_FLAT_TREE void ft_pci_setup(void *blob, bd_t *bd) { u32 *p; -- cgit v1.1 From 1c274c4e05b6dc9b24edc8aa618b02f607ee6eed Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Wed, 25 Jul 2007 19:25:33 -0500 Subject: mpc83xx: add support for the MPC8323E RDB MPC8323E based board with 64MB fixed SDRAM, 16MB flash, five 10/100 ethernet ports connected via an ICPlus IP175C switch, one PCI slot, and serial. Features not supported in this patch are SD card interface, 2 USB ports, and the two phone ports. Signed-off-by: Michael Barkowski Signed-off-by: Kim Phillips --- Makefile | 3 + board/freescale/mpc8323erdb/Makefile | 50 +++ board/freescale/mpc8323erdb/config.mk | 28 ++ board/freescale/mpc8323erdb/mpc8323erdb.c | 217 +++++++++++ doc/README.mpc8323erdb | 71 ++++ include/configs/MPC8323ERDB.h | 583 ++++++++++++++++++++++++++++++ 6 files changed, 952 insertions(+) create mode 100644 board/freescale/mpc8323erdb/Makefile create mode 100644 board/freescale/mpc8323erdb/config.mk create mode 100644 board/freescale/mpc8323erdb/mpc8323erdb.c create mode 100644 doc/README.mpc8323erdb create mode 100644 include/configs/MPC8323ERDB.h diff --git a/Makefile b/Makefile index 704e480..2a18a4d 100644 --- a/Makefile +++ b/Makefile @@ -1675,6 +1675,9 @@ MPC8313ERDB_66_config: unconfig fi ; @$(MKCONFIG) -a MPC8313ERDB ppc mpc83xx mpc8313erdb +MPC8323ERDB_config: unconfig + @$(MKCONFIG) -a MPC8323ERDB ppc mpc83xx mpc8323erdb freescale + MPC832XEMDS_config \ MPC832XEMDS_HOST_33_config \ MPC832XEMDS_HOST_66_config \ diff --git a/board/freescale/mpc8323erdb/Makefile b/board/freescale/mpc8323erdb/Makefile new file mode 100644 index 0000000..acc9544 --- /dev/null +++ b/board/freescale/mpc8323erdb/Makefile @@ -0,0 +1,50 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).a + +COBJS := $(BOARD).o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/freescale/mpc8323erdb/config.mk b/board/freescale/mpc8323erdb/config.mk new file mode 100644 index 0000000..fe0d37d --- /dev/null +++ b/board/freescale/mpc8323erdb/config.mk @@ -0,0 +1,28 @@ +# +# (C) Copyright 2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +# +# MPC8323ERDB +# + +TEXT_BASE = 0xFE000000 diff --git a/board/freescale/mpc8323erdb/mpc8323erdb.c b/board/freescale/mpc8323erdb/mpc8323erdb.c new file mode 100644 index 0000000..1886f19 --- /dev/null +++ b/board/freescale/mpc8323erdb/mpc8323erdb.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. + * + * Michael Barkowski + * Based on mpc832xmds file by Dave Liu + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_PCI) +#include +#endif +#if defined(CONFIG_SPD_EEPROM) +#include +#else +#include +#endif + +const qe_iop_conf_t qe_iop_conf_tab[] = { + /* UCC3 */ + {1, 0, 1, 0, 1}, /* TxD0 */ + {1, 1, 1, 0, 1}, /* TxD1 */ + {1, 2, 1, 0, 1}, /* TxD2 */ + {1, 3, 1, 0, 1}, /* TxD3 */ + {1, 9, 1, 0, 1}, /* TxER */ + {1, 12, 1, 0, 1}, /* TxEN */ + {3, 24, 2, 0, 1}, /* TxCLK->CLK10 */ + + {1, 4, 2, 0, 1}, /* RxD0 */ + {1, 5, 2, 0, 1}, /* RxD1 */ + {1, 6, 2, 0, 1}, /* RxD2 */ + {1, 7, 2, 0, 1}, /* RxD3 */ + {1, 8, 2, 0, 1}, /* RxER */ + {1, 10, 2, 0, 1}, /* RxDV */ + {0, 13, 2, 0, 1}, /* RxCLK->CLK9 */ + {1, 11, 2, 0, 1}, /* COL */ + {1, 13, 2, 0, 1}, /* CRS */ + + /* UCC2 */ + {0, 18, 1, 0, 1}, /* TxD0 */ + {0, 19, 1, 0, 1}, /* TxD1 */ + {0, 20, 1, 0, 1}, /* TxD2 */ + {0, 21, 1, 0, 1}, /* TxD3 */ + {0, 27, 1, 0, 1}, /* TxER */ + {0, 30, 1, 0, 1}, /* TxEN */ + {3, 23, 2, 0, 1}, /* TxCLK->CLK3 */ + + {0, 22, 2, 0, 1}, /* RxD0 */ + {0, 23, 2, 0, 1}, /* RxD1 */ + {0, 24, 2, 0, 1}, /* RxD2 */ + {0, 25, 2, 0, 1}, /* RxD3 */ + {0, 26, 1, 0, 1}, /* RxER */ + {0, 28, 2, 0, 1}, /* Rx_DV */ + {3, 21, 2, 0, 1}, /* RxCLK->CLK16 */ + {0, 29, 2, 0, 1}, /* COL */ + {0, 31, 2, 0, 1}, /* CRS */ + + {3, 4, 3, 0, 2}, /* MDIO */ + {3, 5, 1, 0, 2}, /* MDC */ + + {0, 0, 0, 0, QE_IOP_TAB_END}, /* END of table */ +}; + +int board_early_init_f(void) +{ + return 0; +} + +int fixed_sdram(void); + +long int initdram(int board_type) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + u32 msize = 0; + + if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32) im) + return -1; + + /* DDR SDRAM - Main SODIMM */ + im->sysconf.ddrlaw[0].bar = CFG_DDR_BASE & LAWBAR_BAR; + + msize = fixed_sdram(); + + puts("\n DDR RAM: "); + + /* return total bus SDRAM size(bytes) -- DDR */ + return (msize * 1024 * 1024); +} + +/************************************************************************* + * fixed sdram init -- doesn't use serial presence detect. + ************************************************************************/ +int fixed_sdram(void) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + u32 msize = 0; + u32 ddr_size; + u32 ddr_size_log2; + + msize = CFG_DDR_SIZE; + for (ddr_size = msize << 20, ddr_size_log2 = 0; + (ddr_size > 1); ddr_size = ddr_size >> 1, ddr_size_log2++) { + if (ddr_size & 1) { + return -1; + } + } + im->sysconf.ddrlaw[0].ar = + LAWAR_EN | ((ddr_size_log2 - 1) & LAWAR_SIZE); + im->ddr.sdram_clk_cntl = CFG_DDR_CLK_CNTL; + im->ddr.csbnds[0].csbnds = CFG_DDR_CS0_BNDS; + im->ddr.cs_config[0] = CFG_DDR_CS0_CONFIG; + im->ddr.timing_cfg_0 = CFG_DDR_TIMING_0; + im->ddr.timing_cfg_1 = CFG_DDR_TIMING_1; + im->ddr.timing_cfg_2 = CFG_DDR_TIMING_2; + im->ddr.timing_cfg_3 = CFG_DDR_TIMING_3; + im->ddr.sdram_cfg = CFG_DDR_SDRAM_CFG; + im->ddr.sdram_cfg2 = CFG_DDR_SDRAM_CFG2; + im->ddr.sdram_mode = CFG_DDR_MODE; + im->ddr.sdram_mode2 = CFG_DDR_MODE2; + im->ddr.sdram_interval = CFG_DDR_INTERVAL; + __asm__ __volatile__ ("sync"); + udelay(200); + + im->ddr.sdram_cfg |= SDRAM_CFG_MEM_EN; + __asm__ __volatile__ ("sync"); + return msize; +} + +int checkboard(void) +{ + puts("Board: Freescale MPC8323ERDB\n"); + return 0; +} + +static struct pci_region pci_regions[] = { + { + bus_start: CFG_PCI1_MEM_BASE, + phys_start: CFG_PCI1_MEM_PHYS, + size: CFG_PCI1_MEM_SIZE, + flags: PCI_REGION_MEM | PCI_REGION_PREFETCH + }, + { + bus_start: CFG_PCI1_MMIO_BASE, + phys_start: CFG_PCI1_MMIO_PHYS, + size: CFG_PCI1_MMIO_SIZE, + flags: PCI_REGION_MEM + }, + { + bus_start: CFG_PCI1_IO_BASE, + phys_start: CFG_PCI1_IO_PHYS, + size: CFG_PCI1_IO_SIZE, + flags: PCI_REGION_IO + } +}; + +void pci_init_board(void) +{ + volatile immap_t *immr = (volatile immap_t *)CFG_IMMR; + volatile clk83xx_t *clk = (volatile clk83xx_t *)&immr->clk; + volatile law83xx_t *pci_law = immr->sysconf.pcilaw; + struct pci_region *reg[] = { pci_regions }; + + /* Enable all 3 PCI_CLK_OUTPUTs. */ + clk->occr |= 0xe0000000; + + /* Configure PCI Local Access Windows */ + pci_law[0].bar = CFG_PCI1_MEM_PHYS & LAWBAR_BAR; + pci_law[0].ar = LBLAWAR_EN | LBLAWAR_512MB; + + pci_law[1].bar = CFG_PCI1_IO_PHYS & LAWBAR_BAR; + pci_law[1].ar = LBLAWAR_EN | LBLAWAR_1MB; + + mpc83xx_pci_init(1, reg, 0); +} + +#if defined(CONFIG_OF_BOARD_SETUP) + +/* + * Prototypes of functions that we use. + */ +void ft_cpu_setup(void *blob, bd_t *bd); + +#ifdef CONFIG_PCI +void ft_pci_setup(void *blob, bd_t *bd); +#endif + +void +ft_board_setup(void *blob, bd_t *bd) +{ + int nodeoffset; + int tmp[2]; + + nodeoffset = fdt_find_node_by_path(blob, "/memory"); + if (nodeoffset >= 0) { + tmp[0] = cpu_to_be32(bd->bi_memstart); + tmp[1] = cpu_to_be32(bd->bi_memsize); + fdt_setprop(blob, nodeoffset, "reg", tmp, sizeof(tmp)); + } + + ft_cpu_setup(blob, bd); + +#ifdef CONFIG_PCI + ft_pci_setup(blob, bd); +#endif +} +#endif /* CONFIG_OF_BOARD_SETUP */ diff --git a/doc/README.mpc8323erdb b/doc/README.mpc8323erdb new file mode 100644 index 0000000..6f89829 --- /dev/null +++ b/doc/README.mpc8323erdb @@ -0,0 +1,71 @@ +Freescale MPC8323ERDB Board +----------------------------------------- + +1. Memory Map + The memory map looks like this: + + 0x0000_0000 0x03ff_ffff DDR 64M + 0x8000_0000 0x8fff_ffff PCI MEM 256M + 0x9000_0000 0x9fff_ffff PCI_MMIO 256M + 0xe000_0000 0xe00f_ffff IMMR 1M + 0xd000_0000 0xd3ff_ffff PCI IO 64M + 0xfe00_0000 0xfeff_ffff NOR FLASH (CS0) 16M + +2. Compilation + + Assuming you're using BASH (or similar) as your shell: + + export CROSS_COMPILE=your-cross-compiler-prefix- + make distclean + make MPC8323ERDB_config + make + +3. Downloading and Flashing Images + +3.1 Reflash U-boot Image using U-boot + + N.b, have an alternate means of programming + the flash available if the new u-boot doesn't boot. + + First try a: + + tftpboot $loadaddr $uboot + + to make sure that the TFTP load will succeed before + an erase goes ahead and wipes out your current firmware. + Then do a: + + run tftpflash + + which is a shorter version of the manual sequence: + + tftp $loadaddr u-boot.bin + protect off fe000000 +$filesize + erase fe000000 +$filesize + cp.b $loadaddr fe000000 $filesize + + To keep your old u-boot's environment variables, do a: + + saveenv + + prior to resetting the board. + +3.2 Downloading and Booting Linux Kernel + + Ensure that all networking-related environment variables are set + properly (including ipaddr, serverip, gatewayip (if needed), + netmask, ethaddr, eth1addr, rootpath (if using NFS root), + fdtfile, and bootfile). + + Then, do one of the following, depending on whether you + want an NFS root or a ramdisk root: + + run nfsboot + + or + + run ramboot + +4 Notes + + The console baudrate for MPC8323ERDB is 115200bps. diff --git a/include/configs/MPC8323ERDB.h b/include/configs/MPC8323ERDB.h new file mode 100644 index 0000000..376973b --- /dev/null +++ b/include/configs/MPC8323ERDB.h @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#undef DEBUG + +/* + * High Level Configuration Options + */ +#define CONFIG_E300 1 /* E300 family */ +#define CONFIG_QE 1 /* Has QE */ +#define CONFIG_MPC83XX 1 /* MPC83xx family */ +#define CONFIG_MPC832X 1 /* MPC832x CPU specific */ + +#define CONFIG_PCI 1 +#define CONFIG_83XX_GENERIC_PCI 1 + +/* + * System Clock Setup + */ +#define CONFIG_83XX_CLKIN 66666667 /* in Hz */ + +#ifndef CONFIG_SYS_CLK_FREQ +#define CONFIG_SYS_CLK_FREQ CONFIG_83XX_CLKIN +#endif + +/* + * Hardware Reset Configuration Word + */ +#define CFG_HRCW_LOW (\ + HRCWL_LCL_BUS_TO_SCB_CLK_1X1 |\ + HRCWL_DDR_TO_SCB_CLK_2X1 |\ + HRCWL_VCO_1X2 |\ + HRCWL_CSB_TO_CLKIN_2X1 |\ + HRCWL_CORE_TO_CSB_2_5X1 |\ + HRCWL_CE_PLL_VCO_DIV_2 |\ + HRCWL_CE_PLL_DIV_1X1 |\ + HRCWL_CE_TO_PLL_1X3) + +#define CFG_HRCW_HIGH (\ + HRCWH_PCI_HOST |\ + HRCWH_PCI1_ARBITER_ENABLE |\ + HRCWH_CORE_ENABLE |\ + HRCWH_FROM_0X00000100 |\ + HRCWH_BOOTSEQ_DISABLE |\ + HRCWH_SW_WATCHDOG_DISABLE |\ + HRCWH_ROM_LOC_LOCAL_16BIT |\ + HRCWH_BIG_ENDIAN |\ + HRCWH_LALE_NORMAL) + +/* + * System IO Config + */ +#define CFG_SICRL 0x00000000 + +#define CONFIG_BOARD_EARLY_INIT_F /* call board_pre_init */ + +/* + * IMMR new address + */ +#define CFG_IMMR 0xE0000000 + +/* + * DDR Setup + */ +#define CFG_DDR_BASE 0x00000000 /* DDR is system memory */ +#define CFG_SDRAM_BASE CFG_DDR_BASE +#define CFG_DDR_SDRAM_BASE CFG_DDR_BASE +#define CFG_DDRCDR 0x73000002 /* DDR II voltage is 1.8V */ + +#undef CONFIG_SPD_EEPROM +#if defined(CONFIG_SPD_EEPROM) +/* Determine DDR configuration from I2C interface + */ +#define SPD_EEPROM_ADDRESS 0x51 /* DDR SODIMM */ +#else +/* Manually set up DDR parameters + */ +#define CFG_DDR_SIZE 64 /* MB */ +#define CFG_DDR_CS0_CONFIG 0x80840101 +#define CFG_DDR_TIMING_0 0x00220802 +#define CFG_DDR_TIMING_1 0x3935d322 +#define CFG_DDR_TIMING_2 0x0f9048ca +#define CFG_DDR_TIMING_3 0x00000000 +#define CFG_DDR_CLK_CNTL 0x02000000 +#define CFG_DDR_MODE 0x44400232 +#define CFG_DDR_MODE2 0x8000c000 +#define CFG_DDR_INTERVAL 0x03200064 +#define CFG_DDR_CS0_BNDS 0x00000003 +#define CFG_DDR_SDRAM_CFG 0x43080000 +#define CFG_DDR_SDRAM_CFG2 0x00401000 +#endif + +/* + * Memory test + */ +#undef CFG_DRAM_TEST /* memory test, takes time */ +#define CFG_MEMTEST_START 0x00030000 /* memtest region */ +#define CFG_MEMTEST_END 0x03f00000 + +/* + * The reserved memory + */ +#define CFG_MONITOR_BASE TEXT_BASE /* start of monitor */ + +#if (CFG_MONITOR_BASE < CFG_FLASH_BASE) +#define CFG_RAMBOOT +#else +#undef CFG_RAMBOOT +#endif + +#define CFG_MONITOR_LEN (256 * 1024) /* Reserve 256 kB for Mon */ +#define CFG_MALLOC_LEN (128 * 1024) /* Reserved for malloc */ + +/* + * Initial RAM Base Address Setup + */ +#define CFG_INIT_RAM_LOCK 1 +#define CFG_INIT_RAM_ADDR 0xE6000000 /* Initial RAM address */ +#define CFG_INIT_RAM_END 0x1000 /* End of used area in RAM */ +#define CFG_GBL_DATA_SIZE 0x100 /* num bytes initial data */ +#define CFG_GBL_DATA_OFFSET (CFG_INIT_RAM_END - CFG_GBL_DATA_SIZE) + +/* + * Local Bus Configuration & Clock Setup + */ +#define CFG_LCRR (LCRR_DBYP | LCRR_CLKDIV_2) +#define CFG_LBC_LBCR 0x00000000 + +/* + * FLASH on the Local Bus + */ +#define CFG_FLASH_CFI /* use the Common Flash Interface */ +#define CFG_FLASH_CFI_DRIVER /* use the CFI driver */ +#define CFG_FLASH_BASE 0xFE000000 /* FLASH base address */ +#define CFG_FLASH_SIZE 16 /* FLASH size is 16M */ + +#define CFG_LBLAWBAR0_PRELIM CFG_FLASH_BASE /* Window base at flash base */ +#define CFG_LBLAWAR0_PRELIM 0x80000018 /* 32MB window size */ + +#define CFG_BR0_PRELIM (CFG_FLASH_BASE | /* Flash Base address */ \ + (2 << BR_PS_SHIFT) | /* 16 bit port size */ \ + BR_V) /* valid */ +#define CFG_OR0_PRELIM 0xfe006ff7 /* 16MB Flash size */ + +#define CFG_MAX_FLASH_BANKS 1 /* number of banks */ +#define CFG_MAX_FLASH_SECT 128 /* sectors per device */ + +#undef CFG_FLASH_CHECKSUM + +/* + * SDRAM on the Local Bus + */ +#undef CFG_LB_SDRAM /* The board has not SRDAM on local bus */ + +#ifdef CFG_LB_SDRAM +#define CFG_LBC_SDRAM_BASE 0xF0000000 /* SDRAM base address */ +#define CFG_LBC_SDRAM_SIZE 64 /* LBC SDRAM is 64MB */ + +#define CFG_LBLAWBAR2_PRELIM CFG_LBC_SDRAM_BASE +#define CFG_LBLAWAR2_PRELIM 0x80000019 /* 64MB */ + +/*local bus BR2, OR2 definition for SDRAM if soldered on the EPB board */ +/* + * Base Register 2 and Option Register 2 configure SDRAM. + * The SDRAM base address, CFG_LBC_SDRAM_BASE, is 0xf0000000. + * + * For BR2, need: + * Base address of 0xf0000000 = BR[0:16] = 1111 0000 0000 0000 0 + * port size = 32-bits = BR2[19:20] = 11 + * no parity checking = BR2[21:22] = 00 + * SDRAM for MSEL = BR2[24:26] = 011 + * Valid = BR[31] = 1 + * + * 0 4 8 12 16 20 24 28 + * 1111 0000 0000 0000 0001 1000 0110 0001 = f0001861 + * + * CFG_LBC_SDRAM_BASE should be masked and OR'ed into + * the top 17 bits of BR2. + */ + +#define CFG_BR2_PRELIM 0xf0001861 /*Port size=32bit, MSEL=SDRAM */ + +/* + * The SDRAM size in MB, CFG_LBC_SDRAM_SIZE, is 64. + * + * For OR2, need: + * 64MB mask for AM, OR2[0:7] = 1111 1100 + * XAM, OR2[17:18] = 11 + * 9 columns OR2[19-21] = 010 + * 13 rows OR2[23-25] = 100 + * EAD set for extra time OR[31] = 1 + * + * 0 4 8 12 16 20 24 28 + * 1111 1100 0000 0000 0110 1001 0000 0001 = fc006901 + */ + +#define CFG_OR2_PRELIM 0xfc006901 + +#define CFG_LBC_LSRT 0x32000000 /* LB sdram refresh timer, about 6us */ +#define CFG_LBC_MRTPR 0x20000000 /* LB refresh timer prescal, 266MHz/32 */ + +/* + * LSDMR masks + */ +#define CFG_LBC_LSDMR_OP_NORMAL (0 << (31 - 4)) +#define CFG_LBC_LSDMR_OP_ARFRSH (1 << (31 - 4)) +#define CFG_LBC_LSDMR_OP_SRFRSH (2 << (31 - 4)) +#define CFG_LBC_LSDMR_OP_MRW (3 << (31 - 4)) +#define CFG_LBC_LSDMR_OP_PRECH (4 << (31 - 4)) +#define CFG_LBC_LSDMR_OP_PCHALL (5 << (31 - 4)) +#define CFG_LBC_LSDMR_OP_ACTBNK (6 << (31 - 4)) +#define CFG_LBC_LSDMR_OP_RWINV (7 << (31 - 4)) + +#define CFG_LBC_LSDMR_COMMON 0x0063b723 + +/* + * SDRAM Controller configuration sequence. + */ +#define CFG_LBC_LSDMR_1 ( CFG_LBC_LSDMR_COMMON \ + | CFG_LBC_LSDMR_OP_PCHALL) +#define CFG_LBC_LSDMR_2 ( CFG_LBC_LSDMR_COMMON \ + | CFG_LBC_LSDMR_OP_ARFRSH) +#define CFG_LBC_LSDMR_3 ( CFG_LBC_LSDMR_COMMON \ + | CFG_LBC_LSDMR_OP_ARFRSH) +#define CFG_LBC_LSDMR_4 ( CFG_LBC_LSDMR_COMMON \ + | CFG_LBC_LSDMR_OP_MRW) +#define CFG_LBC_LSDMR_5 ( CFG_LBC_LSDMR_COMMON \ + | CFG_LBC_LSDMR_OP_NORMAL) + +#endif + +/* + * Windows to access PIB via local bus + */ +#define CFG_LBLAWBAR3_PRELIM 0xf8008000 /* windows base 0xf8008000 */ +#define CFG_LBLAWAR3_PRELIM 0x8000000f /* windows size 64KB */ + +/* + * Serial Port + */ +#define CONFIG_CONS_INDEX 1 +#undef CONFIG_SERIAL_SOFTWARE_FIFO +#define CFG_NS16550 +#define CFG_NS16550_SERIAL +#define CFG_NS16550_REG_SIZE 1 +#define CFG_NS16550_CLK get_bus_freq(0) + +#define CFG_BAUDRATE_TABLE \ + {300, 600, 1200, 2400, 4800, 9600, 19200, 38400,115200} + +#define CFG_NS16550_COM1 (CFG_IMMR+0x4500) +#define CFG_NS16550_COM2 (CFG_IMMR+0x4600) + +#define CONFIG_CMDLINE_EDITING 1 /* add command line history */ +/* Use the HUSH parser */ +#define CFG_HUSH_PARSER +#ifdef CFG_HUSH_PARSER +#define CFG_PROMPT_HUSH_PS2 "> " +#endif + +/* pass open firmware flat tree */ +#define CONFIG_OF_LIBFDT 1 +#define CONFIG_OF_BOARD_SETUP 1 + +#define OF_CPU "PowerPC,8323@0" +#define OF_SOC "soc8323@e0000000" +#define OF_QE "qe@e0100000" +#define OF_TBCLK (bd->bi_busfreq / 4) +#define OF_STDOUT_PATH "/soc8323@e0000000/serial@4500" + +/* I2C */ +#define CONFIG_HARD_I2C /* I2C with hardware support */ +#undef CONFIG_SOFT_I2C /* I2C bit-banged */ +#define CONFIG_FSL_I2C +#define CFG_I2C_SPEED 400000 /* I2C speed and slave address */ +#define CFG_I2C_SLAVE 0x7F +#define CFG_I2C_NOPROBES {0x51} /* Don't probe these addrs */ +#define CFG_I2C_OFFSET 0x3000 + +/* + * Config on-board RTC + */ +#define CONFIG_RTC_DS1374 /* use ds1374 rtc via i2c */ +#define CFG_I2C_RTC_ADDR 0x68 /* at address 0x68 */ + +/* + * General PCI + * Addresses are mapped 1-1. + */ +#define CFG_PCI1_MEM_BASE 0x80000000 +#define CFG_PCI1_MEM_PHYS CFG_PCI1_MEM_BASE +#define CFG_PCI1_MEM_SIZE 0x10000000 /* 256M */ +#define CFG_PCI1_MMIO_BASE 0x90000000 +#define CFG_PCI1_MMIO_PHYS CFG_PCI1_MMIO_BASE +#define CFG_PCI1_MMIO_SIZE 0x10000000 /* 256M */ +#define CFG_PCI1_IO_BASE 0xd0000000 +#define CFG_PCI1_IO_PHYS CFG_PCI1_IO_BASE +#define CFG_PCI1_IO_SIZE 0x04000000 /* 64M */ + +#ifdef CONFIG_PCI + +#define CONFIG_NET_MULTI +#define CONFIG_PCI_PNP /* do pci plug-and-play */ + +#undef CONFIG_EEPRO100 +#undef CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ +#define CFG_PCI_SUBSYS_VENDORID 0x1957 /* Freescale */ + +#endif /* CONFIG_PCI */ + + +#ifndef CONFIG_NET_MULTI +#define CONFIG_NET_MULTI 1 +#endif + +/* + * QE UEC ethernet configuration + */ +#define CONFIG_UEC_ETH +#define CONFIG_ETHPRIME "Freescale GETH" + +#define CONFIG_UEC_ETH1 /* ETH3 */ + +#ifdef CONFIG_UEC_ETH1 +#define CFG_UEC1_UCC_NUM 2 /* UCC3 */ +#define CFG_UEC1_RX_CLK QE_CLK9 +#define CFG_UEC1_TX_CLK QE_CLK10 +#define CFG_UEC1_ETH_TYPE FAST_ETH +#define CFG_UEC1_PHY_ADDR 4 +#define CFG_UEC1_INTERFACE_MODE ENET_100_MII +#endif + +#define CONFIG_UEC_ETH2 /* ETH4 */ + +#ifdef CONFIG_UEC_ETH2 +#define CFG_UEC2_UCC_NUM 1 /* UCC2 */ +#define CFG_UEC2_RX_CLK QE_CLK16 +#define CFG_UEC2_TX_CLK QE_CLK3 +#define CFG_UEC2_ETH_TYPE FAST_ETH +#define CFG_UEC2_PHY_ADDR 0 +#define CFG_UEC2_INTERFACE_MODE ENET_100_MII +#endif + +/* + * Environment + */ +#ifndef CFG_RAMBOOT + #define CFG_ENV_IS_IN_FLASH 1 + #define CFG_ENV_ADDR (CFG_MONITOR_BASE + 0x40000) + #define CFG_ENV_SECT_SIZE 0x40000 /* 256K(one sector) for env */ + #define CFG_ENV_SIZE 0x2000 +#else + #define CFG_NO_FLASH 1 /* Flash is not usable now */ + #define CFG_ENV_IS_NOWHERE 1 /* Store ENV in memory only */ + #define CFG_ENV_ADDR (CFG_MONITOR_BASE - 0x1000) + #define CFG_ENV_SIZE 0x2000 +#endif + +#define CONFIG_LOADS_ECHO 1 /* echo on for serial download */ +#define CFG_LOADS_BAUD_CHANGE 1 /* allow baudrate change */ + +/* + * BOOTP options + */ +#define CONFIG_BOOTP_BOOTFILESIZE +#define CONFIG_BOOTP_BOOTPATH +#define CONFIG_BOOTP_GATEWAY +#define CONFIG_BOOTP_HOSTNAME + +/* + * Command line configuration. + */ +#include + +#define CONFIG_CMD_PING +#define CONFIG_CMD_I2C +#define CONFIG_CMD_ASKENV + +#if defined(CONFIG_PCI) + #define CONFIG_CMD_PCI +#endif +#if defined(CFG_RAMBOOT) + #undef CONFIG_CMD_ENV + #undef CONFIG_CMD_LOADS +#endif + +#undef CONFIG_WATCHDOG /* watchdog disabled */ + +/* + * Miscellaneous configurable options + */ +#define CFG_LONGHELP /* undef to save memory */ +#define CFG_LOAD_ADDR 0x2000000 /* default load address */ +#define CFG_PROMPT "=> " /* Monitor Command Prompt */ + +#if (CONFIG_CMD_KGDB) + #define CFG_CBSIZE 1024 /* Console I/O Buffer Size */ +#else + #define CFG_CBSIZE 256 /* Console I/O Buffer Size */ +#endif + +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */ +#define CFG_MAXARGS 16 /* max number of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ +#define CFG_HZ 1000 /* decrementer freq: 1ms ticks */ + +/* + * For booting Linux, the board info and command line data + * have to be in the first 8 MB of memory, since this is + * the maximum mapped by the Linux kernel during initialization. + */ +#define CFG_BOOTMAPSZ (8 << 20) /* Initial Memory map for Linux */ + +/* + * Core HID Setup + */ +#define CFG_HID0_INIT 0x000000000 +#define CFG_HID0_FINAL HID0_ENABLE_MACHINE_CHECK +#define CFG_HID2 HID2_HBE + +/* + * Cache Config + */ +#define CFG_DCACHE_SIZE 16384 +#define CFG_CACHELINE_SIZE 32 +#if defined(CONFIG_CMD_KGDB) +#define CFG_CACHELINE_SHIFT 5 /*log base 2 of the above value */ +#endif + +/* + * MMU Setup + */ + +/* DDR: cache cacheable */ +#define CFG_IBAT0L (CFG_SDRAM_BASE | BATL_PP_10 | BATL_MEMCOHERENCE) +#define CFG_IBAT0U (CFG_SDRAM_BASE | BATU_BL_256M | BATU_VS | BATU_VP) +#define CFG_DBAT0L CFG_IBAT0L +#define CFG_DBAT0U CFG_IBAT0U + +/* IMMRBAR & PCI IO: cache-inhibit and guarded */ +#define CFG_IBAT1L (CFG_IMMR | BATL_PP_10 | \ + BATL_CACHEINHIBIT | BATL_GUARDEDSTORAGE) +#define CFG_IBAT1U (CFG_IMMR | BATU_BL_4M | BATU_VS | BATU_VP) +#define CFG_DBAT1L CFG_IBAT1L +#define CFG_DBAT1U CFG_IBAT1U + +/* FLASH: icache cacheable, but dcache-inhibit and guarded */ +#define CFG_IBAT2L (CFG_FLASH_BASE | BATL_PP_10 | BATL_MEMCOHERENCE) +#define CFG_IBAT2U (CFG_FLASH_BASE | BATU_BL_32M | BATU_VS | BATU_VP) +#define CFG_DBAT2L (CFG_FLASH_BASE | BATL_PP_10 | \ + BATL_CACHEINHIBIT | BATL_GUARDEDSTORAGE) +#define CFG_DBAT2U CFG_IBAT2U + +#define CFG_IBAT3L (0) +#define CFG_IBAT3U (0) +#define CFG_DBAT3L CFG_IBAT3L +#define CFG_DBAT3U CFG_IBAT3U + +/* Stack in dcache: cacheable, no memory coherence */ +#define CFG_IBAT4L (CFG_INIT_RAM_ADDR | BATL_PP_10) +#define CFG_IBAT4U (CFG_INIT_RAM_ADDR | BATU_BL_128K | BATU_VS | BATU_VP) +#define CFG_DBAT4L CFG_IBAT4L +#define CFG_DBAT4U CFG_IBAT4U + +#ifdef CONFIG_PCI +/* PCI MEM space: cacheable */ +#define CFG_IBAT5L (CFG_PCI1_MEM_PHYS | BATL_PP_10 | BATL_MEMCOHERENCE) +#define CFG_IBAT5U (CFG_PCI1_MEM_PHYS | BATU_BL_256M | BATU_VS | BATU_VP) +#define CFG_DBAT5L CFG_IBAT5L +#define CFG_DBAT5U CFG_IBAT5U +/* PCI MMIO space: cache-inhibit and guarded */ +#define CFG_IBAT6L (CFG_PCI1_MMIO_PHYS | BATL_PP_10 | \ + BATL_CACHEINHIBIT | BATL_GUARDEDSTORAGE) +#define CFG_IBAT6U (CFG_PCI1_MMIO_PHYS | BATU_BL_256M | BATU_VS | BATU_VP) +#define CFG_DBAT6L CFG_IBAT6L +#define CFG_DBAT6U CFG_IBAT6U +#else +#define CFG_IBAT5L (0) +#define CFG_IBAT5U (0) +#define CFG_IBAT6L (0) +#define CFG_IBAT6U (0) +#define CFG_DBAT5L CFG_IBAT5L +#define CFG_DBAT5U CFG_IBAT5U +#define CFG_DBAT6L CFG_IBAT6L +#define CFG_DBAT6U CFG_IBAT6U +#endif + +/* Nothing in BAT7 */ +#define CFG_IBAT7L (0) +#define CFG_IBAT7U (0) +#define CFG_DBAT7L CFG_IBAT7L +#define CFG_DBAT7U CFG_IBAT7U + +/* + * Internal Definitions + * + * Boot Flags + */ +#define BOOTFLAG_COLD 0x01 /* Normal Power-On: Boot from FLASH */ +#define BOOTFLAG_WARM 0x02 /* Software reboot */ + +#if (CONFIG_CMD_KGDB) +#define CONFIG_KGDB_BAUDRATE 230400 /* speed of kgdb serial port */ +#define CONFIG_KGDB_SER_INDEX 2 /* which serial port to use */ +#endif + +/* + * Environment Configuration + */ +#define CONFIG_ENV_OVERWRITE + +#define CONFIG_ETHADDR 00:04:9f:ef:03:01 +#define CONFIG_HAS_ETH1 /* add support for "eth1addr" */ +#define CONFIG_ETH1ADDR 00:04:9f:ef:03:02 + +#define CONFIG_IPADDR 10.0.0.2 +#define CONFIG_SERVERIP 10.0.0.1 +#define CONFIG_GATEWAYIP 10.0.0.1 +#define CONFIG_NETMASK 255.0.0.0 +#define CONFIG_NETDEV eth1 + +#define CONFIG_HOSTNAME mpc8323erdb +#define CONFIG_ROOTPATH /nfsroot +#define CONFIG_RAMDISKFILE rootfs.ext2.gz.uboot +#define CONFIG_BOOTFILE uImage +#define CONFIG_UBOOTPATH u-boot.bin /* U-Boot image on TFTP server */ +#define CONFIG_FDTFILE mpc832x_rdb.dtb + +#define CONFIG_LOADADDR 200000 /* default location for tftp and bootm */ +#define CONFIG_BOOTDELAY -1 /* -1 disables auto-boot */ +#define CONFIG_BAUDRATE 115200 + +#define XMK_STR(x) #x +#define MK_STR(x) XMK_STR(x) + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "netdev=" MK_STR(CONFIG_NETDEV) "\0" \ + "uboot=" MK_STR(CONFIG_UBOOTPATH) "\0" \ + "tftpflash=tftp $loadaddr $uboot;" \ + "protect off " MK_STR(TEXT_BASE) " +$filesize; " \ + "erase " MK_STR(TEXT_BASE) " +$filesize; " \ + "cp.b $loadaddr " MK_STR(TEXT_BASE) " $filesize; " \ + "protect on " MK_STR(TEXT_BASE) " +$filesize; " \ + "cmp.b $loadaddr " MK_STR(TEXT_BASE) " $filesize\0" \ + "fdtaddr=400000\0" \ + "fdtfile=" MK_STR(CONFIG_FDTFILE) "\0" \ + "ramdiskaddr=1000000\0" \ + "ramdiskfile=" MK_STR(CONFIG_RAMDISKFILE) "\0" \ + "console=ttyS0\0" \ + "setbootargs=setenv bootargs " \ + "root=$rootdev rw console=$console,$baudrate $othbootargs\0" \ + "setipargs=setenv bootargs nfsroot=$serverip:$rootpath " \ + "ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname:$netdev:off " \ + "root=$rootdev rw console=$console,$baudrate $othbootargs\0" + +#define CONFIG_NFSBOOTCOMMAND \ + "setenv rootdev /dev/nfs;" \ + "run setbootargs;" \ + "run setipargs;" \ + "tftp $loadaddr $bootfile;" \ + "tftp $fdtaddr $fdtfile;" \ + "bootm $loadaddr - $fdtaddr" + +#define CONFIG_RAMBOOTCOMMAND \ + "setenv rootdev /dev/ram;" \ + "run setbootargs;" \ + "tftp $ramdiskaddr $ramdiskfile;" \ + "tftp $loadaddr $bootfile;" \ + "tftp $fdtaddr $fdtfile;" \ + "bootm $loadaddr $ramdiskaddr $fdtaddr" + +#undef MK_STR +#undef XMK_STR + +#endif /* __CONFIG_H */ -- cgit v1.1 From 036575c544cf1b69654d8fb334bda69c6ff3da36 Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Sat, 4 Aug 2007 13:37:39 +0800 Subject: mpc83xx: Correct the burst length for DDR2 with 32 bits The burst length should be 4 for DDR2 with 32 bits bus Signed-off-by: Dave Liu --- cpu/mpc83xx/spd_sdram.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cpu/mpc83xx/spd_sdram.c b/cpu/mpc83xx/spd_sdram.c index 647813f..2c17cee 100644 --- a/cpu/mpc83xx/spd_sdram.c +++ b/cpu/mpc83xx/spd_sdram.c @@ -574,7 +574,10 @@ long int spd_sdram() /* Check DIMM data bus width */ if (spd.dataw_lsb == 0x20) { - burstlen = 0x03; /* 32 bit data bus, burst len is 8 */ + if (spd.mem_type == SPD_MEMTYPE_DDR) + burstlen = 0x03; /* 32 bit data bus, burst len is 8 */ + if (spd.mem_type == SPD_MEMTYPE_DDR2) + burstlen = 0x02; /* 32 bit data bus, burst len is 4 */ printf("\n DDR DIMM: data bus width is 32 bit"); } else { burstlen = 0x02; /* Others act as 64 bit bus, burst len is 4 */ @@ -730,8 +733,12 @@ long int spd_sdram() sdram_cfg |= 0x10000000; /* The DIMM is 32bit width */ - if (spd.dataw_lsb == 0x20) - sdram_cfg |= 0x000C0000; + if (spd.dataw_lsb == 0x20) { + if (spd.mem_type == SPD_MEMTYPE_DDR) + sdram_cfg |= 0x000C0000; + if (spd.mem_type == SPD_MEMTYPE_DDR2) + sdram_cfg |= 0x00080000; + } ddrc_ecc_enable = 0; -- cgit v1.1 From daab8c67d2defef73dc26ab07f0c3afd1b05d019 Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Wed, 1 Aug 2007 15:00:15 +0800 Subject: mpc83xx: Consolidate the ECC support of 83xx Remove the duplicated source code of ecc command on the .c, for reused, move these code to cpu/mpc83xx directory. Signed-off-by: Dave Liu Signed-off-by: Kim Phillips --- board/mpc8349emds/mpc8349emds.c | 327 --------------------------------- board/mpc8360emds/mpc8360emds.c | 378 -------------------------------------- cpu/mpc83xx/Makefile | 2 +- cpu/mpc83xx/ecc.c | 390 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 391 insertions(+), 706 deletions(-) create mode 100644 cpu/mpc83xx/ecc.c diff --git a/board/mpc8349emds/mpc8349emds.c b/board/mpc8349emds/mpc8349emds.c index 071591e..521d1bb 100644 --- a/board/mpc8349emds/mpc8349emds.c +++ b/board/mpc8349emds/mpc8349emds.c @@ -29,7 +29,6 @@ #include #include #include -#include #if defined(CONFIG_SPD_EEPROM) #include #endif @@ -258,332 +257,6 @@ void sdram_init(void) } #endif -#if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD) -/* - * ECC user commands - */ -void ecc_print_status(void) -{ - volatile immap_t *immap = (immap_t *)CFG_IMMR; - volatile ddr83xx_t *ddr = &immap->ddr; - - printf("\nECC mode: %s\n\n", (ddr->sdram_cfg & SDRAM_CFG_ECC_EN) ? "ON" : "OFF"); - - /* Interrupts */ - printf("Memory Error Interrupt Enable:\n"); - printf(" Multiple-Bit Error Interrupt Enable: %d\n", - (ddr->err_int_en & ECC_ERR_INT_EN_MBEE) ? 1 : 0); - printf(" Single-Bit Error Interrupt Enable: %d\n", - (ddr->err_int_en & ECC_ERR_INT_EN_SBEE) ? 1 : 0); - printf(" Memory Select Error Interrupt Enable: %d\n\n", - (ddr->err_int_en & ECC_ERR_INT_EN_MSEE) ? 1 : 0); - - /* Error disable */ - printf("Memory Error Disable:\n"); - printf(" Multiple-Bit Error Disable: %d\n", - (ddr->err_disable & ECC_ERROR_DISABLE_MBED) ? 1 : 0); - printf(" Sinle-Bit Error Disable: %d\n", - (ddr->err_disable & ECC_ERROR_DISABLE_SBED) ? 1 : 0); - printf(" Memory Select Error Disable: %d\n\n", - (ddr->err_disable & ECC_ERROR_DISABLE_MSED) ? 1 : 0); - - /* Error injection */ - printf("Memory Data Path Error Injection Mask High/Low: %08lx %08lx\n", - ddr->data_err_inject_hi, ddr->data_err_inject_lo); - - printf("Memory Data Path Error Injection Mask ECC:\n"); - printf(" ECC Mirror Byte: %d\n", - (ddr->ecc_err_inject & ECC_ERR_INJECT_EMB) ? 1 : 0); - printf(" ECC Injection Enable: %d\n", - (ddr->ecc_err_inject & ECC_ERR_INJECT_EIEN) ? 1 : 0); - printf(" ECC Error Injection Mask: 0x%02x\n\n", - ddr->ecc_err_inject & ECC_ERR_INJECT_EEIM); - - /* SBE counter/threshold */ - printf("Memory Single-Bit Error Management (0..255):\n"); - printf(" Single-Bit Error Threshold: %d\n", - (ddr->err_sbe & ECC_ERROR_MAN_SBET) >> ECC_ERROR_MAN_SBET_SHIFT); - printf(" Single-Bit Error Counter: %d\n\n", - (ddr->err_sbe & ECC_ERROR_MAN_SBEC) >> ECC_ERROR_MAN_SBEC_SHIFT); - - /* Error detect */ - printf("Memory Error Detect:\n"); - printf(" Multiple Memory Errors: %d\n", - (ddr->err_detect & ECC_ERROR_DETECT_MME) ? 1 : 0); - printf(" Multiple-Bit Error: %d\n", - (ddr->err_detect & ECC_ERROR_DETECT_MBE) ? 1 : 0); - printf(" Single-Bit Error: %d\n", - (ddr->err_detect & ECC_ERROR_DETECT_SBE) ? 1 : 0); - printf(" Memory Select Error: %d\n\n", - (ddr->err_detect & ECC_ERROR_DETECT_MSE) ? 1 : 0); - - /* Capture data */ - printf("Memory Error Address Capture: 0x%08lx\n", ddr->capture_address); - printf("Memory Data Path Read Capture High/Low: %08lx %08lx\n", - ddr->capture_data_hi, ddr->capture_data_lo); - printf("Memory Data Path Read Capture ECC: 0x%02x\n\n", - ddr->capture_ecc & CAPTURE_ECC_ECE); - - printf("Memory Error Attributes Capture:\n"); - printf(" Data Beat Number: %d\n", - (ddr->capture_attributes & ECC_CAPT_ATTR_BNUM) >> ECC_CAPT_ATTR_BNUM_SHIFT); - printf(" Transaction Size: %d\n", - (ddr->capture_attributes & ECC_CAPT_ATTR_TSIZ) >> ECC_CAPT_ATTR_TSIZ_SHIFT); - printf(" Transaction Source: %d\n", - (ddr->capture_attributes & ECC_CAPT_ATTR_TSRC) >> ECC_CAPT_ATTR_TSRC_SHIFT); - printf(" Transaction Type: %d\n", - (ddr->capture_attributes & ECC_CAPT_ATTR_TTYP) >> ECC_CAPT_ATTR_TTYP_SHIFT); - printf(" Error Information Valid: %d\n\n", - ddr->capture_attributes & ECC_CAPT_ATTR_VLD); -} - -int do_ecc ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) -{ - volatile immap_t *immap = (immap_t *)CFG_IMMR; - volatile ddr83xx_t *ddr = &immap->ddr; - volatile u32 val; - u64 *addr, count, val64; - register u64 *i; - - if (argc > 4) { - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; - } - - if (argc == 2) { - if (strcmp(argv[1], "status") == 0) { - ecc_print_status(); - return 0; - } else if (strcmp(argv[1], "captureclear") == 0) { - ddr->capture_address = 0; - ddr->capture_data_hi = 0; - ddr->capture_data_lo = 0; - ddr->capture_ecc = 0; - ddr->capture_attributes = 0; - return 0; - } - } - - if (argc == 3) { - if (strcmp(argv[1], "sbecnt") == 0) { - val = simple_strtoul(argv[2], NULL, 10); - if (val > 255) { - printf("Incorrect Counter value, should be 0..255\n"); - return 1; - } - - val = (val << ECC_ERROR_MAN_SBEC_SHIFT); - val |= (ddr->err_sbe & ECC_ERROR_MAN_SBET); - - ddr->err_sbe = val; - return 0; - } else if (strcmp(argv[1], "sbethr") == 0) { - val = simple_strtoul(argv[2], NULL, 10); - if (val > 255) { - printf("Incorrect Counter value, should be 0..255\n"); - return 1; - } - - val = (val << ECC_ERROR_MAN_SBET_SHIFT); - val |= (ddr->err_sbe & ECC_ERROR_MAN_SBEC); - - ddr->err_sbe = val; - return 0; - } else if (strcmp(argv[1], "errdisable") == 0) { - val = ddr->err_disable; - - if (strcmp(argv[2], "+sbe") == 0) { - val |= ECC_ERROR_DISABLE_SBED; - } else if (strcmp(argv[2], "+mbe") == 0) { - val |= ECC_ERROR_DISABLE_MBED; - } else if (strcmp(argv[2], "+mse") == 0) { - val |= ECC_ERROR_DISABLE_MSED; - } else if (strcmp(argv[2], "+all") == 0) { - val |= (ECC_ERROR_DISABLE_SBED | - ECC_ERROR_DISABLE_MBED | - ECC_ERROR_DISABLE_MSED); - } else if (strcmp(argv[2], "-sbe") == 0) { - val &= ~ECC_ERROR_DISABLE_SBED; - } else if (strcmp(argv[2], "-mbe") == 0) { - val &= ~ECC_ERROR_DISABLE_MBED; - } else if (strcmp(argv[2], "-mse") == 0) { - val &= ~ECC_ERROR_DISABLE_MSED; - } else if (strcmp(argv[2], "-all") == 0) { - val &= ~(ECC_ERROR_DISABLE_SBED | - ECC_ERROR_DISABLE_MBED | - ECC_ERROR_DISABLE_MSED); - } else { - printf("Incorrect err_disable field\n"); - return 1; - } - - ddr->err_disable = val; - __asm__ __volatile__ ("sync"); - __asm__ __volatile__ ("isync"); - return 0; - } else if (strcmp(argv[1], "errdetectclr") == 0) { - val = ddr->err_detect; - - if (strcmp(argv[2], "mme") == 0) { - val |= ECC_ERROR_DETECT_MME; - } else if (strcmp(argv[2], "sbe") == 0) { - val |= ECC_ERROR_DETECT_SBE; - } else if (strcmp(argv[2], "mbe") == 0) { - val |= ECC_ERROR_DETECT_MBE; - } else if (strcmp(argv[2], "mse") == 0) { - val |= ECC_ERROR_DETECT_MSE; - } else if (strcmp(argv[2], "all") == 0) { - val |= (ECC_ERROR_DETECT_MME | - ECC_ERROR_DETECT_MBE | - ECC_ERROR_DETECT_SBE | - ECC_ERROR_DETECT_MSE); - } else { - printf("Incorrect err_detect field\n"); - return 1; - } - - ddr->err_detect = val; - return 0; - } else if (strcmp(argv[1], "injectdatahi") == 0) { - val = simple_strtoul(argv[2], NULL, 16); - - ddr->data_err_inject_hi = val; - return 0; - } else if (strcmp(argv[1], "injectdatalo") == 0) { - val = simple_strtoul(argv[2], NULL, 16); - - ddr->data_err_inject_lo = val; - return 0; - } else if (strcmp(argv[1], "injectecc") == 0) { - val = simple_strtoul(argv[2], NULL, 16); - if (val > 0xff) { - printf("Incorrect ECC inject mask, should be 0x00..0xff\n"); - return 1; - } - val |= (ddr->ecc_err_inject & ~ECC_ERR_INJECT_EEIM); - - ddr->ecc_err_inject = val; - return 0; - } else if (strcmp(argv[1], "inject") == 0) { - val = ddr->ecc_err_inject; - - if (strcmp(argv[2], "en") == 0) - val |= ECC_ERR_INJECT_EIEN; - else if (strcmp(argv[2], "dis") == 0) - val &= ~ECC_ERR_INJECT_EIEN; - else - printf("Incorrect command\n"); - - ddr->ecc_err_inject = val; - __asm__ __volatile__ ("sync"); - __asm__ __volatile__ ("isync"); - return 0; - } else if (strcmp(argv[1], "mirror") == 0) { - val = ddr->ecc_err_inject; - - if (strcmp(argv[2], "en") == 0) - val |= ECC_ERR_INJECT_EMB; - else if (strcmp(argv[2], "dis") == 0) - val &= ~ECC_ERR_INJECT_EMB; - else - printf("Incorrect command\n"); - - ddr->ecc_err_inject = val; - return 0; - } - } - - if (argc == 4) { - if (strcmp(argv[1], "test") == 0) { - addr = (u64 *)simple_strtoul(argv[2], NULL, 16); - count = simple_strtoul(argv[3], NULL, 16); - - if ((u32)addr % 8) { - printf("Address not alligned on double word boundary\n"); - return 1; - } - - disable_interrupts(); - icache_disable(); - - for (i = addr; i < addr + count; i++) { - /* enable injects */ - ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN; - __asm__ __volatile__ ("sync"); - __asm__ __volatile__ ("isync"); - - /* write memory location injecting errors */ - *i = 0x1122334455667788ULL; - __asm__ __volatile__ ("sync"); - - /* disable injects */ - ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN; - __asm__ __volatile__ ("sync"); - __asm__ __volatile__ ("isync"); - - /* read data, this generates ECC error */ - val64 = *i; - __asm__ __volatile__ ("sync"); - - /* disable errors for ECC */ - ddr->err_disable |= ~ECC_ERROR_ENABLE; - __asm__ __volatile__ ("sync"); - __asm__ __volatile__ ("isync"); - - /* re-initialize memory, write the location again - * NOT injecting errors this time */ - *i = 0xcafecafecafecafeULL; - __asm__ __volatile__ ("sync"); - - /* enable errors for ECC */ - ddr->err_disable &= ECC_ERROR_ENABLE; - __asm__ __volatile__ ("sync"); - __asm__ __volatile__ ("isync"); - } - - icache_enable(); - enable_interrupts(); - - return 0; - } - } - - printf ("Usage:\n%s\n", cmdtp->usage); - return 1; -} - -U_BOOT_CMD( - ecc, 4, 0, do_ecc, - "ecc - support for DDR ECC features\n", - "status - print out status info\n" - "ecc captureclear - clear capture regs data\n" - "ecc sbecnt - set Single-Bit Error counter\n" - "ecc sbethr - set Single-Bit Threshold\n" - "ecc errdisable - clear/set disable Memory Error Disable, flag:\n" - " [-|+]sbe - Single-Bit Error\n" - " [-|+]mbe - Multiple-Bit Error\n" - " [-|+]mse - Memory Select Error\n" - " [-|+]all - all errors\n" - "ecc errdetectclr - clear Memory Error Detect, flag:\n" - " mme - Multiple Memory Errors\n" - " sbe - Single-Bit Error\n" - " mbe - Multiple-Bit Error\n" - " mse - Memory Select Error\n" - " all - all errors\n" - "ecc injectdatahi - set Memory Data Path Error Injection Mask High\n" - "ecc injectdatalo - set Memory Data Path Error Injection Mask Low\n" - "ecc injectecc - set ECC Error Injection Mask\n" - "ecc inject - enable/disable error injection\n" - "ecc mirror - enable/disable mirror byte\n" - "ecc test - test mem region:\n" - " - enables injects\n" - " - writes pattern injecting errors\n" - " - disables injects\n" - " - reads pattern back, generates error\n" - " - re-inits memory" -); -#endif /* if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD) */ - #if defined(CONFIG_OF_FLAT_TREE) && defined(CONFIG_OF_BOARD_SETUP) void ft_board_setup(void *blob, bd_t *bd) diff --git a/board/mpc8360emds/mpc8360emds.c b/board/mpc8360emds/mpc8360emds.c index b109317..3fa093d 100644 --- a/board/mpc8360emds/mpc8360emds.c +++ b/board/mpc8360emds/mpc8360emds.c @@ -1,8 +1,6 @@ /* * Copyright (C) 2006 Freescale Semiconductor, Inc. - * * Dave Liu - * based on board/mpc8349emds/mpc8349emds.c * * See file CREDITS for list of people who contributed to this * project. @@ -19,7 +17,6 @@ #include #include #include -#include #if defined(CONFIG_PCI) #include #endif @@ -288,381 +285,6 @@ void sdram_init(void) } #endif -#if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD) -/* - * ECC user commands - */ -void ecc_print_status(void) -{ - volatile immap_t *immap = (immap_t *) CFG_IMMR; - volatile ddr83xx_t *ddr = &immap->ddr; - - printf("\nECC mode: %s\n\n", - (ddr->sdram_cfg & SDRAM_CFG_ECC_EN) ? "ON" : "OFF"); - - /* Interrupts */ - printf("Memory Error Interrupt Enable:\n"); - printf(" Multiple-Bit Error Interrupt Enable: %d\n", - (ddr->err_int_en & ECC_ERR_INT_EN_MBEE) ? 1 : 0); - printf(" Single-Bit Error Interrupt Enable: %d\n", - (ddr->err_int_en & ECC_ERR_INT_EN_SBEE) ? 1 : 0); - printf(" Memory Select Error Interrupt Enable: %d\n\n", - (ddr->err_int_en & ECC_ERR_INT_EN_MSEE) ? 1 : 0); - - /* Error disable */ - printf("Memory Error Disable:\n"); - printf(" Multiple-Bit Error Disable: %d\n", - (ddr->err_disable & ECC_ERROR_DISABLE_MBED) ? 1 : 0); - printf(" Sinle-Bit Error Disable: %d\n", - (ddr->err_disable & ECC_ERROR_DISABLE_SBED) ? 1 : 0); - printf(" Memory Select Error Disable: %d\n\n", - (ddr->err_disable & ECC_ERROR_DISABLE_MSED) ? 1 : 0); - - /* Error injection */ - printf("Memory Data Path Error Injection Mask High/Low: %08lx %08lx\n", - ddr->data_err_inject_hi, ddr->data_err_inject_lo); - - printf("Memory Data Path Error Injection Mask ECC:\n"); - printf(" ECC Mirror Byte: %d\n", - (ddr->ecc_err_inject & ECC_ERR_INJECT_EMB) ? 1 : 0); - printf(" ECC Injection Enable: %d\n", - (ddr->ecc_err_inject & ECC_ERR_INJECT_EIEN) ? 1 : 0); - printf(" ECC Error Injection Mask: 0x%02x\n\n", - ddr->ecc_err_inject & ECC_ERR_INJECT_EEIM); - - /* SBE counter/threshold */ - printf("Memory Single-Bit Error Management (0..255):\n"); - printf(" Single-Bit Error Threshold: %d\n", - (ddr->err_sbe & ECC_ERROR_MAN_SBET) >> ECC_ERROR_MAN_SBET_SHIFT); - printf(" Single-Bit Error Counter: %d\n\n", - (ddr->err_sbe & ECC_ERROR_MAN_SBEC) >> ECC_ERROR_MAN_SBEC_SHIFT); - - /* Error detect */ - printf("Memory Error Detect:\n"); - printf(" Multiple Memory Errors: %d\n", - (ddr->err_detect & ECC_ERROR_DETECT_MME) ? 1 : 0); - printf(" Multiple-Bit Error: %d\n", - (ddr->err_detect & ECC_ERROR_DETECT_MBE) ? 1 : 0); - printf(" Single-Bit Error: %d\n", - (ddr->err_detect & ECC_ERROR_DETECT_SBE) ? 1 : 0); - printf(" Memory Select Error: %d\n\n", - (ddr->err_detect & ECC_ERROR_DETECT_MSE) ? 1 : 0); - - /* Capture data */ - printf("Memory Error Address Capture: 0x%08lx\n", ddr->capture_address); - printf("Memory Data Path Read Capture High/Low: %08lx %08lx\n", - ddr->capture_data_hi, ddr->capture_data_lo); - printf("Memory Data Path Read Capture ECC: 0x%02x\n\n", - ddr->capture_ecc & CAPTURE_ECC_ECE); - - printf("Memory Error Attributes Capture:\n"); - printf(" Data Beat Number: %d\n", - (ddr->capture_attributes & ECC_CAPT_ATTR_BNUM) >> - ECC_CAPT_ATTR_BNUM_SHIFT); - printf(" Transaction Size: %d\n", - (ddr->capture_attributes & ECC_CAPT_ATTR_TSIZ) >> - ECC_CAPT_ATTR_TSIZ_SHIFT); - printf(" Transaction Source: %d\n", - (ddr->capture_attributes & ECC_CAPT_ATTR_TSRC) >> - ECC_CAPT_ATTR_TSRC_SHIFT); - printf(" Transaction Type: %d\n", - (ddr->capture_attributes & ECC_CAPT_ATTR_TTYP) >> - ECC_CAPT_ATTR_TTYP_SHIFT); - printf(" Error Information Valid: %d\n\n", - ddr->capture_attributes & ECC_CAPT_ATTR_VLD); -} - -int do_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) -{ - volatile immap_t *immap = (immap_t *) CFG_IMMR; - volatile ddr83xx_t *ddr = &immap->ddr; - volatile u32 val; - u64 *addr; - u32 count; - register u64 *i; - u32 ret[2]; - u32 pattern[2]; - u32 writeback[2]; - - /* The pattern is written into memory to generate error */ - pattern[0] = 0xfedcba98UL; - pattern[1] = 0x76543210UL; - - /* After injecting error, re-initialize the memory with the value */ - writeback[0] = 0x01234567UL; - writeback[1] = 0x89abcdefUL; - - if (argc > 4) { - printf("Usage:\n%s\n", cmdtp->usage); - return 1; - } - - if (argc == 2) { - if (strcmp(argv[1], "status") == 0) { - ecc_print_status(); - return 0; - } else if (strcmp(argv[1], "captureclear") == 0) { - ddr->capture_address = 0; - ddr->capture_data_hi = 0; - ddr->capture_data_lo = 0; - ddr->capture_ecc = 0; - ddr->capture_attributes = 0; - return 0; - } - } - if (argc == 3) { - if (strcmp(argv[1], "sbecnt") == 0) { - val = simple_strtoul(argv[2], NULL, 10); - if (val > 255) { - printf("Incorrect Counter value, " - "should be 0..255\n"); - return 1; - } - - val = (val << ECC_ERROR_MAN_SBEC_SHIFT); - val |= (ddr->err_sbe & ECC_ERROR_MAN_SBET); - - ddr->err_sbe = val; - return 0; - } else if (strcmp(argv[1], "sbethr") == 0) { - val = simple_strtoul(argv[2], NULL, 10); - if (val > 255) { - printf("Incorrect Counter value, " - "should be 0..255\n"); - return 1; - } - - val = (val << ECC_ERROR_MAN_SBET_SHIFT); - val |= (ddr->err_sbe & ECC_ERROR_MAN_SBEC); - - ddr->err_sbe = val; - return 0; - } else if (strcmp(argv[1], "errdisable") == 0) { - val = ddr->err_disable; - - if (strcmp(argv[2], "+sbe") == 0) { - val |= ECC_ERROR_DISABLE_SBED; - } else if (strcmp(argv[2], "+mbe") == 0) { - val |= ECC_ERROR_DISABLE_MBED; - } else if (strcmp(argv[2], "+mse") == 0) { - val |= ECC_ERROR_DISABLE_MSED; - } else if (strcmp(argv[2], "+all") == 0) { - val |= (ECC_ERROR_DISABLE_SBED | - ECC_ERROR_DISABLE_MBED | - ECC_ERROR_DISABLE_MSED); - } else if (strcmp(argv[2], "-sbe") == 0) { - val &= ~ECC_ERROR_DISABLE_SBED; - } else if (strcmp(argv[2], "-mbe") == 0) { - val &= ~ECC_ERROR_DISABLE_MBED; - } else if (strcmp(argv[2], "-mse") == 0) { - val &= ~ECC_ERROR_DISABLE_MSED; - } else if (strcmp(argv[2], "-all") == 0) { - val &= ~(ECC_ERROR_DISABLE_SBED | - ECC_ERROR_DISABLE_MBED | - ECC_ERROR_DISABLE_MSED); - } else { - printf("Incorrect err_disable field\n"); - return 1; - } - - ddr->err_disable = val; - __asm__ __volatile__("sync"); - __asm__ __volatile__("isync"); - return 0; - } else if (strcmp(argv[1], "errdetectclr") == 0) { - val = ddr->err_detect; - - if (strcmp(argv[2], "mme") == 0) { - val |= ECC_ERROR_DETECT_MME; - } else if (strcmp(argv[2], "sbe") == 0) { - val |= ECC_ERROR_DETECT_SBE; - } else if (strcmp(argv[2], "mbe") == 0) { - val |= ECC_ERROR_DETECT_MBE; - } else if (strcmp(argv[2], "mse") == 0) { - val |= ECC_ERROR_DETECT_MSE; - } else if (strcmp(argv[2], "all") == 0) { - val |= (ECC_ERROR_DETECT_MME | - ECC_ERROR_DETECT_MBE | - ECC_ERROR_DETECT_SBE | - ECC_ERROR_DETECT_MSE); - } else { - printf("Incorrect err_detect field\n"); - return 1; - } - - ddr->err_detect = val; - return 0; - } else if (strcmp(argv[1], "injectdatahi") == 0) { - val = simple_strtoul(argv[2], NULL, 16); - - ddr->data_err_inject_hi = val; - return 0; - } else if (strcmp(argv[1], "injectdatalo") == 0) { - val = simple_strtoul(argv[2], NULL, 16); - - ddr->data_err_inject_lo = val; - return 0; - } else if (strcmp(argv[1], "injectecc") == 0) { - val = simple_strtoul(argv[2], NULL, 16); - if (val > 0xff) { - printf("Incorrect ECC inject mask, " - "should be 0x00..0xff\n"); - return 1; - } - val |= (ddr->ecc_err_inject & ~ECC_ERR_INJECT_EEIM); - - ddr->ecc_err_inject = val; - return 0; - } else if (strcmp(argv[1], "inject") == 0) { - val = ddr->ecc_err_inject; - - if (strcmp(argv[2], "en") == 0) - val |= ECC_ERR_INJECT_EIEN; - else if (strcmp(argv[2], "dis") == 0) - val &= ~ECC_ERR_INJECT_EIEN; - else - printf("Incorrect command\n"); - - ddr->ecc_err_inject = val; - __asm__ __volatile__("sync"); - __asm__ __volatile__("isync"); - return 0; - } else if (strcmp(argv[1], "mirror") == 0) { - val = ddr->ecc_err_inject; - - if (strcmp(argv[2], "en") == 0) - val |= ECC_ERR_INJECT_EMB; - else if (strcmp(argv[2], "dis") == 0) - val &= ~ECC_ERR_INJECT_EMB; - else - printf("Incorrect command\n"); - - ddr->ecc_err_inject = val; - return 0; - } - } - if (argc == 4) { - if (strcmp(argv[1], "testdw") == 0) { - addr = (u64 *) simple_strtoul(argv[2], NULL, 16); - count = simple_strtoul(argv[3], NULL, 16); - - if ((u32) addr % 8) { - printf("Address not alligned on " - "double word boundary\n"); - return 1; - } - disable_interrupts(); - - for (i = addr; i < addr + count; i++) { - - /* enable injects */ - ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN; - __asm__ __volatile__("sync"); - __asm__ __volatile__("isync"); - - /* write memory location injecting errors */ - ppcDWstore((u32 *) i, pattern); - __asm__ __volatile__("sync"); - - /* disable injects */ - ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN; - __asm__ __volatile__("sync"); - __asm__ __volatile__("isync"); - - /* read data, this generates ECC error */ - ppcDWload((u32 *) i, ret); - __asm__ __volatile__("sync"); - - /* re-initialize memory, double word write the location again, - * generates new ECC code this time */ - ppcDWstore((u32 *) i, writeback); - __asm__ __volatile__("sync"); - } - enable_interrupts(); - return 0; - } - if (strcmp(argv[1], "testword") == 0) { - addr = (u64 *) simple_strtoul(argv[2], NULL, 16); - count = simple_strtoul(argv[3], NULL, 16); - - if ((u32) addr % 8) { - printf("Address not alligned on " - "double word boundary\n"); - return 1; - } - disable_interrupts(); - - for (i = addr; i < addr + count; i++) { - - /* enable injects */ - ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN; - __asm__ __volatile__("sync"); - __asm__ __volatile__("isync"); - - /* write memory location injecting errors */ - *(u32 *) i = 0xfedcba98UL; - __asm__ __volatile__("sync"); - - /* sub double word write, - * bus will read-modify-write, - * generates ECC error */ - *((u32 *) i + 1) = 0x76543210UL; - __asm__ __volatile__("sync"); - - /* disable injects */ - ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN; - __asm__ __volatile__("sync"); - __asm__ __volatile__("isync"); - - /* re-initialize memory, - * double word write the location again, - * generates new ECC code this time */ - ppcDWstore((u32 *) i, writeback); - __asm__ __volatile__("sync"); - } - enable_interrupts(); - return 0; - } - } - printf("Usage:\n%s\n", cmdtp->usage); - return 1; -} - -U_BOOT_CMD(ecc, 4, 0, do_ecc, - "ecc - support for DDR ECC features\n", - "status - print out status info\n" - "ecc captureclear - clear capture regs data\n" - "ecc sbecnt - set Single-Bit Error counter\n" - "ecc sbethr - set Single-Bit Threshold\n" - "ecc errdisable - clear/set disable Memory Error Disable, flag:\n" - " [-|+]sbe - Single-Bit Error\n" - " [-|+]mbe - Multiple-Bit Error\n" - " [-|+]mse - Memory Select Error\n" - " [-|+]all - all errors\n" - "ecc errdetectclr - clear Memory Error Detect, flag:\n" - " mme - Multiple Memory Errors\n" - " sbe - Single-Bit Error\n" - " mbe - Multiple-Bit Error\n" - " mse - Memory Select Error\n" - " all - all errors\n" - "ecc injectdatahi - set Memory Data Path Error Injection Mask High\n" - "ecc injectdatalo - set Memory Data Path Error Injection Mask Low\n" - "ecc injectecc - set ECC Error Injection Mask\n" - "ecc inject - enable/disable error injection\n" - "ecc mirror - enable/disable mirror byte\n" - "ecc testdw - test mem region with double word access:\n" - " - enables injects\n" - " - writes pattern injecting errors with double word access\n" - " - disables injects\n" - " - reads pattern back with double word access, generates error\n" - " - re-inits memory\n" - "ecc testword - test mem region with word access:\n" - " - enables injects\n" - " - writes pattern injecting errors with word access\n" - " - writes pattern with word access, generates error\n" - " - disables injects\n" " - re-inits memory"); -#endif /* if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD) */ - #if (defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT)) \ && defined(CONFIG_OF_BOARD_SETUP) diff --git a/cpu/mpc83xx/Makefile b/cpu/mpc83xx/Makefile index bb96f77..2329970 100644 --- a/cpu/mpc83xx/Makefile +++ b/cpu/mpc83xx/Makefile @@ -29,7 +29,7 @@ LIB = $(obj)lib$(CPU).a START = start.o COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o \ - spd_sdram.o qe_io.o pci.o + spd_sdram.o ecc.o qe_io.o pci.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/mpc83xx/ecc.c b/cpu/mpc83xx/ecc.c new file mode 100644 index 0000000..6f13094 --- /dev/null +++ b/cpu/mpc83xx/ecc.c @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. + * + * Dave Liu + * based on the contribution of Marian Balakowicz + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include + +#if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD) +void ecc_print_status(void) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + volatile ddr83xx_t *ddr = &immap->ddr; + + printf("\nECC mode: %s\n\n", + (ddr->sdram_cfg & SDRAM_CFG_ECC_EN) ? "ON" : "OFF"); + + /* Interrupts */ + printf("Memory Error Interrupt Enable:\n"); + printf(" Multiple-Bit Error Interrupt Enable: %d\n", + (ddr->err_int_en & ECC_ERR_INT_EN_MBEE) ? 1 : 0); + printf(" Single-Bit Error Interrupt Enable: %d\n", + (ddr->err_int_en & ECC_ERR_INT_EN_SBEE) ? 1 : 0); + printf(" Memory Select Error Interrupt Enable: %d\n\n", + (ddr->err_int_en & ECC_ERR_INT_EN_MSEE) ? 1 : 0); + + /* Error disable */ + printf("Memory Error Disable:\n"); + printf(" Multiple-Bit Error Disable: %d\n", + (ddr->err_disable & ECC_ERROR_DISABLE_MBED) ? 1 : 0); + printf(" Sinle-Bit Error Disable: %d\n", + (ddr->err_disable & ECC_ERROR_DISABLE_SBED) ? 1 : 0); + printf(" Memory Select Error Disable: %d\n\n", + (ddr->err_disable & ECC_ERROR_DISABLE_MSED) ? 1 : 0); + + /* Error injection */ + printf("Memory Data Path Error Injection Mask High/Low: %08lx %08lx\n", + ddr->data_err_inject_hi, ddr->data_err_inject_lo); + + printf("Memory Data Path Error Injection Mask ECC:\n"); + printf(" ECC Mirror Byte: %d\n", + (ddr->ecc_err_inject & ECC_ERR_INJECT_EMB) ? 1 : 0); + printf(" ECC Injection Enable: %d\n", + (ddr->ecc_err_inject & ECC_ERR_INJECT_EIEN) ? 1 : 0); + printf(" ECC Error Injection Mask: 0x%02x\n\n", + ddr->ecc_err_inject & ECC_ERR_INJECT_EEIM); + + /* SBE counter/threshold */ + printf("Memory Single-Bit Error Management (0..255):\n"); + printf(" Single-Bit Error Threshold: %d\n", + (ddr->err_sbe & ECC_ERROR_MAN_SBET) >> ECC_ERROR_MAN_SBET_SHIFT); + printf(" Single-Bit Error Counter: %d\n\n", + (ddr->err_sbe & ECC_ERROR_MAN_SBEC) >> ECC_ERROR_MAN_SBEC_SHIFT); + + /* Error detect */ + printf("Memory Error Detect:\n"); + printf(" Multiple Memory Errors: %d\n", + (ddr->err_detect & ECC_ERROR_DETECT_MME) ? 1 : 0); + printf(" Multiple-Bit Error: %d\n", + (ddr->err_detect & ECC_ERROR_DETECT_MBE) ? 1 : 0); + printf(" Single-Bit Error: %d\n", + (ddr->err_detect & ECC_ERROR_DETECT_SBE) ? 1 : 0); + printf(" Memory Select Error: %d\n\n", + (ddr->err_detect & ECC_ERROR_DETECT_MSE) ? 1 : 0); + + /* Capture data */ + printf("Memory Error Address Capture: 0x%08lx\n", ddr->capture_address); + printf("Memory Data Path Read Capture High/Low: %08lx %08lx\n", + ddr->capture_data_hi, ddr->capture_data_lo); + printf("Memory Data Path Read Capture ECC: 0x%02x\n\n", + ddr->capture_ecc & CAPTURE_ECC_ECE); + + printf("Memory Error Attributes Capture:\n"); + printf(" Data Beat Number: %d\n", + (ddr->capture_attributes & ECC_CAPT_ATTR_BNUM) >> + ECC_CAPT_ATTR_BNUM_SHIFT); + printf(" Transaction Size: %d\n", + (ddr->capture_attributes & ECC_CAPT_ATTR_TSIZ) >> + ECC_CAPT_ATTR_TSIZ_SHIFT); + printf(" Transaction Source: %d\n", + (ddr->capture_attributes & ECC_CAPT_ATTR_TSRC) >> + ECC_CAPT_ATTR_TSRC_SHIFT); + printf(" Transaction Type: %d\n", + (ddr->capture_attributes & ECC_CAPT_ATTR_TTYP) >> + ECC_CAPT_ATTR_TTYP_SHIFT); + printf(" Error Information Valid: %d\n\n", + ddr->capture_attributes & ECC_CAPT_ATTR_VLD); +} + +int do_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + volatile ddr83xx_t *ddr = &immap->ddr; + volatile u32 val; + u64 *addr; + u32 count; + register u64 *i; + u32 ret[2]; + u32 pattern[2]; + u32 writeback[2]; + + /* The pattern is written into memory to generate error */ + pattern[0] = 0xfedcba98UL; + pattern[1] = 0x76543210UL; + + /* After injecting error, re-initialize the memory with the value */ + writeback[0] = 0x01234567UL; + writeback[1] = 0x89abcdefUL; + + if (argc > 4) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if (argc == 2) { + if (strcmp(argv[1], "status") == 0) { + ecc_print_status(); + return 0; + } else if (strcmp(argv[1], "captureclear") == 0) { + ddr->capture_address = 0; + ddr->capture_data_hi = 0; + ddr->capture_data_lo = 0; + ddr->capture_ecc = 0; + ddr->capture_attributes = 0; + return 0; + } + } + if (argc == 3) { + if (strcmp(argv[1], "sbecnt") == 0) { + val = simple_strtoul(argv[2], NULL, 10); + if (val > 255) { + printf("Incorrect Counter value, " + "should be 0..255\n"); + return 1; + } + + val = (val << ECC_ERROR_MAN_SBEC_SHIFT); + val |= (ddr->err_sbe & ECC_ERROR_MAN_SBET); + + ddr->err_sbe = val; + return 0; + } else if (strcmp(argv[1], "sbethr") == 0) { + val = simple_strtoul(argv[2], NULL, 10); + if (val > 255) { + printf("Incorrect Counter value, " + "should be 0..255\n"); + return 1; + } + + val = (val << ECC_ERROR_MAN_SBET_SHIFT); + val |= (ddr->err_sbe & ECC_ERROR_MAN_SBEC); + + ddr->err_sbe = val; + return 0; + } else if (strcmp(argv[1], "errdisable") == 0) { + val = ddr->err_disable; + + if (strcmp(argv[2], "+sbe") == 0) { + val |= ECC_ERROR_DISABLE_SBED; + } else if (strcmp(argv[2], "+mbe") == 0) { + val |= ECC_ERROR_DISABLE_MBED; + } else if (strcmp(argv[2], "+mse") == 0) { + val |= ECC_ERROR_DISABLE_MSED; + } else if (strcmp(argv[2], "+all") == 0) { + val |= (ECC_ERROR_DISABLE_SBED | + ECC_ERROR_DISABLE_MBED | + ECC_ERROR_DISABLE_MSED); + } else if (strcmp(argv[2], "-sbe") == 0) { + val &= ~ECC_ERROR_DISABLE_SBED; + } else if (strcmp(argv[2], "-mbe") == 0) { + val &= ~ECC_ERROR_DISABLE_MBED; + } else if (strcmp(argv[2], "-mse") == 0) { + val &= ~ECC_ERROR_DISABLE_MSED; + } else if (strcmp(argv[2], "-all") == 0) { + val &= ~(ECC_ERROR_DISABLE_SBED | + ECC_ERROR_DISABLE_MBED | + ECC_ERROR_DISABLE_MSED); + } else { + printf("Incorrect err_disable field\n"); + return 1; + } + + ddr->err_disable = val; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + return 0; + } else if (strcmp(argv[1], "errdetectclr") == 0) { + val = ddr->err_detect; + + if (strcmp(argv[2], "mme") == 0) { + val |= ECC_ERROR_DETECT_MME; + } else if (strcmp(argv[2], "sbe") == 0) { + val |= ECC_ERROR_DETECT_SBE; + } else if (strcmp(argv[2], "mbe") == 0) { + val |= ECC_ERROR_DETECT_MBE; + } else if (strcmp(argv[2], "mse") == 0) { + val |= ECC_ERROR_DETECT_MSE; + } else if (strcmp(argv[2], "all") == 0) { + val |= (ECC_ERROR_DETECT_MME | + ECC_ERROR_DETECT_MBE | + ECC_ERROR_DETECT_SBE | + ECC_ERROR_DETECT_MSE); + } else { + printf("Incorrect err_detect field\n"); + return 1; + } + + ddr->err_detect = val; + return 0; + } else if (strcmp(argv[1], "injectdatahi") == 0) { + val = simple_strtoul(argv[2], NULL, 16); + + ddr->data_err_inject_hi = val; + return 0; + } else if (strcmp(argv[1], "injectdatalo") == 0) { + val = simple_strtoul(argv[2], NULL, 16); + + ddr->data_err_inject_lo = val; + return 0; + } else if (strcmp(argv[1], "injectecc") == 0) { + val = simple_strtoul(argv[2], NULL, 16); + if (val > 0xff) { + printf("Incorrect ECC inject mask, " + "should be 0x00..0xff\n"); + return 1; + } + val |= (ddr->ecc_err_inject & ~ECC_ERR_INJECT_EEIM); + + ddr->ecc_err_inject = val; + return 0; + } else if (strcmp(argv[1], "inject") == 0) { + val = ddr->ecc_err_inject; + + if (strcmp(argv[2], "en") == 0) + val |= ECC_ERR_INJECT_EIEN; + else if (strcmp(argv[2], "dis") == 0) + val &= ~ECC_ERR_INJECT_EIEN; + else + printf("Incorrect command\n"); + + ddr->ecc_err_inject = val; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + return 0; + } else if (strcmp(argv[1], "mirror") == 0) { + val = ddr->ecc_err_inject; + + if (strcmp(argv[2], "en") == 0) + val |= ECC_ERR_INJECT_EMB; + else if (strcmp(argv[2], "dis") == 0) + val &= ~ECC_ERR_INJECT_EMB; + else + printf("Incorrect command\n"); + + ddr->ecc_err_inject = val; + return 0; + } + } + if (argc == 4) { + if (strcmp(argv[1], "testdw") == 0) { + addr = (u64 *) simple_strtoul(argv[2], NULL, 16); + count = simple_strtoul(argv[3], NULL, 16); + + if ((u32) addr % 8) { + printf("Address not alligned on " + "double word boundary\n"); + return 1; + } + disable_interrupts(); + + for (i = addr; i < addr + count; i++) { + + /* enable injects */ + ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + + /* write memory location injecting errors */ + ppcDWstore((u32 *) i, pattern); + __asm__ __volatile__("sync"); + + /* disable injects */ + ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + + /* read data, this generates ECC error */ + ppcDWload((u32 *) i, ret); + __asm__ __volatile__("sync"); + + /* re-initialize memory, double word write the location again, + * generates new ECC code this time */ + ppcDWstore((u32 *) i, writeback); + __asm__ __volatile__("sync"); + } + enable_interrupts(); + return 0; + } + if (strcmp(argv[1], "testword") == 0) { + addr = (u64 *) simple_strtoul(argv[2], NULL, 16); + count = simple_strtoul(argv[3], NULL, 16); + + if ((u32) addr % 8) { + printf("Address not alligned on " + "double word boundary\n"); + return 1; + } + disable_interrupts(); + + for (i = addr; i < addr + count; i++) { + + /* enable injects */ + ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + + /* write memory location injecting errors */ + *(u32 *) i = 0xfedcba98UL; + __asm__ __volatile__("sync"); + + /* sub double word write, + * bus will read-modify-write, + * generates ECC error */ + *((u32 *) i + 1) = 0x76543210UL; + __asm__ __volatile__("sync"); + + /* disable injects */ + ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + + /* re-initialize memory, + * double word write the location again, + * generates new ECC code this time */ + ppcDWstore((u32 *) i, writeback); + __asm__ __volatile__("sync"); + } + enable_interrupts(); + return 0; + } + } + printf("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +U_BOOT_CMD(ecc, 4, 0, do_ecc, + "ecc - support for DDR ECC features\n", + "status - print out status info\n" + "ecc captureclear - clear capture regs data\n" + "ecc sbecnt - set Single-Bit Error counter\n" + "ecc sbethr - set Single-Bit Threshold\n" + "ecc errdisable - clear/set disable Memory Error Disable, flag:\n" + " [-|+]sbe - Single-Bit Error\n" + " [-|+]mbe - Multiple-Bit Error\n" + " [-|+]mse - Memory Select Error\n" + " [-|+]all - all errors\n" + "ecc errdetectclr - clear Memory Error Detect, flag:\n" + " mme - Multiple Memory Errors\n" + " sbe - Single-Bit Error\n" + " mbe - Multiple-Bit Error\n" + " mse - Memory Select Error\n" + " all - all errors\n" + "ecc injectdatahi - set Memory Data Path Error Injection Mask High\n" + "ecc injectdatalo - set Memory Data Path Error Injection Mask Low\n" + "ecc injectecc - set ECC Error Injection Mask\n" + "ecc inject - enable/disable error injection\n" + "ecc mirror - enable/disable mirror byte\n" + "ecc testdw - test mem region with double word access:\n" + " - enables injects\n" + " - writes pattern injecting errors with double word access\n" + " - disables injects\n" + " - reads pattern back with double word access, generates error\n" + " - re-inits memory\n" + "ecc testword - test mem region with word access:\n" + " - enables injects\n" + " - writes pattern injecting errors with word access\n" + " - writes pattern with word access, generates error\n" + " - disables injects\n" " - re-inits memory"); +#endif -- cgit v1.1 From 47e8bc846759e037b8af0e5f9c9f9cfa7a1050c3 Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Wed, 1 Aug 2007 15:00:59 +0800 Subject: mpc83xx: Correct the README for DDR ECC Update the README for DDR ECC, change the name to README.mpc83xx.ddrecc. Signed-off-by: Dave Liu Signed-off-by: Kim Phillips --- doc/README.mpc8349emds.ddrecc | 154 ------------------------------------------ doc/README.mpc83xx.ddrecc | 154 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 154 deletions(-) delete mode 100644 doc/README.mpc8349emds.ddrecc create mode 100644 doc/README.mpc83xx.ddrecc diff --git a/doc/README.mpc8349emds.ddrecc b/doc/README.mpc8349emds.ddrecc deleted file mode 100644 index eb249c3..0000000 --- a/doc/README.mpc8349emds.ddrecc +++ /dev/null @@ -1,154 +0,0 @@ -Overview -======== - -The overall usage pattern for ECC diagnostic commands is the following: - - * (injecting errors is initially disabled) - - * define inject mask (which tells the DDR controller what type of errors - we'll be injecting: single/multiple bit etc.) - - * enable injecting errors - from now on the controller injects errors as - indicated in the inject mask - -IMPORTANT NOTICE: enabling injecting multiple-bit errors is potentially -dangerous as such errors are NOT corrected by the controller. Therefore caution -should be taken when enabling the injection of multiple-bit errors: it is only -safe when used on a carefully selected memory area and used under control of -the 'ecc test' command (see example 'Injecting Multiple-Bit Errors' below). In -particular, when you simply set the multiple-bit errors in inject mask and -enable injection, U-Boot is very likely to hang quickly as the errors will be -injected when it accesses its code, data etc. - - -Use cases for DDR 'ecc' command: -================================ - -Before executing particular tests reset target board or clear status registers: - -=> ecc captureclear -=> ecc errdetectclr all -=> ecc sbecnt 0 - - -Injecting Single-Bit Errors ---------------------------- - -1. Set 1 bit in Data Path Error Inject Mask - -=> ecc injectdatahi 1 - -2. Run test over some memory region - -=> ecc test 200000 10 - -3. Check ECC status - -=> ecc status -... -Memory Data Path Error Injection Mask High/Low: 00000001 00000000 -... -Memory Single-Bit Error Management (0..255): - Single-Bit Error Threshold: 255 - Single Bit Error Counter: 16 -... -Memory Error Detect: - Multiple Memory Errors: 0 - Multiple-Bit Error: 0 - Single-Bit Error: 0 -... - -16 errors were generated, Single-Bit Error flag was not set as Single Bit Error -Counter did not reach Single-Bit Error Threshold. - -4. Make sure used memory region got re-initialized with 0xcafecafe pattern - -=> md 200000 -00200000: cafecafe cafecafe cafecafe cafecafe ................ -00200010: cafecafe cafecafe cafecafe cafecafe ................ -00200020: cafecafe cafecafe cafecafe cafecafe ................ -00200030: cafecafe cafecafe cafecafe cafecafe ................ -00200040: cafecafe cafecafe cafecafe cafecafe ................ -00200050: cafecafe cafecafe cafecafe cafecafe ................ -00200060: cafecafe cafecafe cafecafe cafecafe ................ -00200070: cafecafe cafecafe cafecafe cafecafe ................ -00200080: deadbeef deadbeef deadbeef deadbeef ................ -00200090: deadbeef deadbeef deadbeef deadbeef ................ - - -Injecting Multiple-Bit Errors ------------------------------ - -1. Set more than 1 bit in Data Path Error Inject Mask - -=> ecc injectdatahi 5 - -2. Run test over some memory region - -=> ecc test 200000 10 - -3. Check ECC status - -=> ecc status -... -Memory Data Path Error Injection Mask High/Low: 00000005 00000000 -... -Memory Error Detect: - Multiple Memory Errors: 1 - Multiple-Bit Error: 1 - Single-Bit Error: 0 -... - -Observe that both Multiple Memory Errors and Multiple-Bit Error flags are set. - -4. Make sure used memory region got re-initialized with 0xcafecafe pattern - -=> md 200000 -00200000: cafecafe cafecafe cafecafe cafecafe ................ -00200010: cafecafe cafecafe cafecafe cafecafe ................ -00200020: cafecafe cafecafe cafecafe cafecafe ................ -00200030: cafecafe cafecafe cafecafe cafecafe ................ -00200040: cafecafe cafecafe cafecafe cafecafe ................ -00200050: cafecafe cafecafe cafecafe cafecafe ................ -00200060: cafecafe cafecafe cafecafe cafecafe ................ -00200070: cafecafe cafecafe cafecafe cafecafe ................ -00200080: deadbeef deadbeef deadbeef deadbeef ................ -00200090: deadbeef deadbeef deadbeef deadbeef ................ - - -Test Single-Bit Error Counter and Threshold -------------------------------------------- - -1. Set 1 bit in Data Path Error Inject Mask - -=> ecc injectdatahi 1 - -2. Enable error injection - -=> ecc inject en - -3. Let u-boot run for a with Single-Bit error injection enabled - -4. Disable error injection - -=> ecc inject dis - -4. Check status - -=> ecc status - -... -Memory Single-Bit Error Management (0..255): - Single-Bit Error Threshold: 255 - Single Bit Error Counter: 60 - -Memory Error Detect: - Multiple Memory Errors: 1 - Multiple-Bit Error: 0 - Single-Bit Error: 1 -... - -Observe that Single-Bit Error is 'on' which means that Single-Bit Error Counter -reached Single-Bit Error Threshold. Multiple Memory Errors bit is also 'on', that -is Counter reached Threshold more than one time (it wraps back after reaching -Threshold). diff --git a/doc/README.mpc83xx.ddrecc b/doc/README.mpc83xx.ddrecc new file mode 100644 index 0000000..0029f08 --- /dev/null +++ b/doc/README.mpc83xx.ddrecc @@ -0,0 +1,154 @@ +Overview +======== + +The overall usage pattern for ECC diagnostic commands is the following: + + * (injecting errors is initially disabled) + + * define inject mask (which tells the DDR controller what type of errors + we'll be injecting: single/multiple bit etc.) + + * enable injecting errors - from now on the controller injects errors as + indicated in the inject mask + +IMPORTANT NOTICE: enabling injecting multiple-bit errors is potentially +dangerous as such errors are NOT corrected by the controller. Therefore caution +should be taken when enabling the injection of multiple-bit errors: it is only +safe when used on a carefully selected memory area and used under control of +the 'ecc testdw' 'ecc testword' command (see example 'Injecting Multiple-Bit +Errors' below). In particular, when you simply set the multiple-bit errors in +inject mask and enable injection, U-Boot is very likely to hang quickly as the +errors will be injected when it accesses its code, data etc. + + +Use cases for DDR 'ecc' command: +================================ + +Before executing particular tests reset target board or clear status registers: + +=> ecc captureclear +=> ecc errdetectclr all +=> ecc sbecnt 0 + + +Injecting Single-Bit Errors +--------------------------- + +1. Set 1 bit in Data Path Error Inject Mask + +=> ecc injectdatahi 1 + +2. Run test over some memory region + +=> ecc testdw 200000 10 + +3. Check ECC status + +=> ecc status +... +Memory Data Path Error Injection Mask High/Low: 00000001 00000000 +... +Memory Single-Bit Error Management (0..255): + Single-Bit Error Threshold: 255 + Single Bit Error Counter: 16 +... +Memory Error Detect: + Multiple Memory Errors: 0 + Multiple-Bit Error: 0 + Single-Bit Error: 0 +... + +16 errors were generated, Single-Bit Error flag was not set as Single Bit Error +Counter did not reach Single-Bit Error Threshold. + +4. Make sure used memory region got re-initialized with 0x0123456789abcdef + +=> md 200000 +00200000: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200010: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200020: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200030: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200040: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200050: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200060: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200070: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200080: deadbeef deadbeef deadbeef deadbeef ................ +00200090: deadbeef deadbeef deadbeef deadbeef ................ + +Injecting Multiple-Bit Errors +----------------------------- + +1. Set more than 1 bit in Data Path Error Inject Mask + +=> ecc injectdatahi 1 +=> ecc injectdatalo 1 + +2. Run test over some memory region + +=> ecc testword 200000 1 + +3. Check ECC status + +=> ecc status +... +Memory Data Path Error Injection Mask High/Low: 00000001 00000001 +... +Memory Error Detect: + Multiple Memory Errors: 0 + Multiple-Bit Error: 1 + Single-Bit Error: 0 +... + +The Multiple Memory Errors flags not set and Multiple-Bit Error flags are set. + +4. Make sure used memory region got re-initialized with 0x0123456789abcdef + +=> md 200000 +00200000: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200010: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200020: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200030: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200040: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200050: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200060: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200070: 01234567 89abcdef 01234567 89abcdef .#Eg.....#Eg.... +00200080: deadbeef deadbeef deadbeef deadbeef ................ +00200090: deadbeef deadbeef deadbeef deadbeef ................ + + +Test Single-Bit Error Counter and Threshold +------------------------------------------- + +1. Set 1 bit in Data Path Error Inject Mask + +=> ecc injectdatahi 1 + +2. Enable error injection + +=> ecc inject en + +3. Let u-boot run for a with Single-Bit error injection enabled + +4. Disable error injection + +=> ecc inject dis + +4. Check status + +=> ecc status + +... +Memory Single-Bit Error Management (0..255): + Single-Bit Error Threshold: 255 + Single Bit Error Counter: 199 + +Memory Error Detect: + Multiple Memory Errors: 1 + Multiple-Bit Error: 0 + Single-Bit Error: 1 +... + +Observe that Single-Bit Error is 'on' which means that Single-Bit Error Counter +reached Single-Bit Error Threshold. Multiple Memory Errors bit is also 'on', that +is Counter reached Threshold more than one time (it wraps back after reaching +Threshold). -- cgit v1.1 From 99c2fdab91bc633e46fb41dbaa629f87ccf6e00f Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Mon, 6 Aug 2007 18:18:34 -0500 Subject: mpc83xx: fix ITX[GP] O=builddir builds make: *** No rule to make target `/work/wd/tmp/board/mpc8349itx/u-boot.lds', needed by `/work/wd/tmp/u-boot'. Stop. Both the ITX and ITX-GP fail when you use "make O= ..." or "BUILD_DIR= ./MAKEALL ..." Signed-off-by: Kim Phillips --- board/mpc8349itx/config.mk | 6 ------ 1 file changed, 6 deletions(-) diff --git a/board/mpc8349itx/config.mk b/board/mpc8349itx/config.mk index 1901fdc..79f1765 100644 --- a/board/mpc8349itx/config.mk +++ b/board/mpc8349itx/config.mk @@ -29,9 +29,3 @@ sinclude $(OBJTREE)/board/$(BOARDDIR)/config.tmp ifndef TEXT_BASE TEXT_BASE = 0xFEF00000 endif - -ifneq ($(OBJTREE),$(SRCTREE)) -# We are building u-boot in a separate directory, use generated -# .lds script from OBJTREE directory. -LDSCRIPT := $(OBJTREE)/board/$(BOARDDIR)/u-boot.lds -endif -- cgit v1.1 From f7c086e94e8ce9aad7268af97f73aa6884686f27 Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Thu, 2 Aug 2007 17:41:14 +0200 Subject: Move 64bit division from avr32 to generic lib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the 64bit division from lib_avr32 to lib_generic. With this, all boards can do_div/__div64_32 if needed, not only avr one. Code is put to lib_generic, so no larger memory footprint if not used. No code modifications. Thanks for proposal by HÃ¥vard Skinnemoen. Signed-off-by: Dirk Behme --- include/asm-avr32/div64.h | 39 ---------------------------------- include/div64.h | 39 ++++++++++++++++++++++++++++++++++ lib_avr32/Makefile | 2 +- lib_avr32/div64.c | 54 ----------------------------------------------- lib_generic/Makefile | 2 +- lib_generic/div64.c | 52 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 93 insertions(+), 95 deletions(-) delete mode 100644 include/asm-avr32/div64.h create mode 100644 include/div64.h delete mode 100644 lib_avr32/div64.c create mode 100644 lib_generic/div64.c diff --git a/include/asm-avr32/div64.h b/include/asm-avr32/div64.h deleted file mode 100644 index 2e0ba83..0000000 --- a/include/asm-avr32/div64.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _ASM_GENERIC_DIV64_H -#define _ASM_GENERIC_DIV64_H -/* - * Copyright (C) 2003 Bernardo Innocenti - * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h - * - * The semantics of do_div() are: - * - * uint32_t do_div(uint64_t *n, uint32_t base) - * { - * uint32_t remainder = *n % base; - * *n = *n / base; - * return remainder; - * } - * - * NOTE: macro parameter n is evaluated multiple times, - * beware of side effects! - */ - -#include - -extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); - -/* The unnecessary pointer compare is there - * to check for type safety (n must be 64bit) - */ -# define do_div(n,base) ({ \ - uint32_t __base = (base); \ - uint32_t __rem; \ - (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ - if (((n) >> 32) == 0) { \ - __rem = (uint32_t)(n) % __base; \ - (n) = (uint32_t)(n) / __base; \ - } else \ - __rem = __div64_32(&(n), __base); \ - __rem; \ - }) - -#endif /* _ASM_GENERIC_DIV64_H */ diff --git a/include/div64.h b/include/div64.h new file mode 100644 index 0000000..2e0ba83 --- /dev/null +++ b/include/div64.h @@ -0,0 +1,39 @@ +#ifndef _ASM_GENERIC_DIV64_H +#define _ASM_GENERIC_DIV64_H +/* + * Copyright (C) 2003 Bernardo Innocenti + * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h + * + * The semantics of do_div() are: + * + * uint32_t do_div(uint64_t *n, uint32_t base) + * { + * uint32_t remainder = *n % base; + * *n = *n / base; + * return remainder; + * } + * + * NOTE: macro parameter n is evaluated multiple times, + * beware of side effects! + */ + +#include + +extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); + +/* The unnecessary pointer compare is there + * to check for type safety (n must be 64bit) + */ +# define do_div(n,base) ({ \ + uint32_t __base = (base); \ + uint32_t __rem; \ + (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ + if (((n) >> 32) == 0) { \ + __rem = (uint32_t)(n) % __base; \ + (n) = (uint32_t)(n) / __base; \ + } else \ + __rem = __div64_32(&(n), __base); \ + __rem; \ + }) + +#endif /* _ASM_GENERIC_DIV64_H */ diff --git a/lib_avr32/Makefile b/lib_avr32/Makefile index cf20836..bb2938f 100644 --- a/lib_avr32/Makefile +++ b/lib_avr32/Makefile @@ -29,7 +29,7 @@ LIB = $(obj)lib$(ARCH).a SOBJS = memset.o -COBJS = board.o interrupts.o avr32_linux.o div64.o +COBJS = board.o interrupts.o avr32_linux.o SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/lib_avr32/div64.c b/lib_avr32/div64.c deleted file mode 100644 index 99726e3..0000000 --- a/lib_avr32/div64.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2003 Bernardo Innocenti - * - * Based on former do_div() implementation from asm-parisc/div64.h: - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang - * - * - * Generic C version of 64bit/32bit division and modulo, with - * 64bit result and 32bit remainder. - * - * The fast case for (n>>32 == 0) is handled inline by do_div(). - * - * Code generated for this function might be very inefficient - * for some CPUs. __div64_32() can be overridden by linking arch-specific - * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S. - */ - -#include - -#include - -uint32_t __div64_32(uint64_t *n, uint32_t base) -{ - uint64_t rem = *n; - uint64_t b = base; - uint64_t res, d = 1; - uint32_t high = rem >> 32; - - /* Reduce the thing a bit first */ - res = 0; - if (high >= base) { - high /= base; - res = (uint64_t) high << 32; - rem -= (uint64_t) (high*base) << 32; - } - - while ((int64_t)b > 0 && b < rem) { - b = b+b; - d = d+d; - } - - do { - if (rem >= b) { - rem -= b; - res += d; - } - b >>= 1; - d >>= 1; - } while (d); - - *n = res; - return rem; -} diff --git a/lib_generic/Makefile b/lib_generic/Makefile index b2091c5..bf37752 100644 --- a/lib_generic/Makefile +++ b/lib_generic/Makefile @@ -27,7 +27,7 @@ LIB = $(obj)libgeneric.a COBJS = bzlib.o bzlib_crctable.o bzlib_decompress.o \ bzlib_randtable.o bzlib_huffman.o \ - crc32.o ctype.o display_options.o ldiv.o sha1.o \ + crc32.o ctype.o display_options.o div64.o ldiv.o sha1.o \ string.o vsprintf.o zlib.o SRCS := $(COBJS:.o=.c) diff --git a/lib_generic/div64.c b/lib_generic/div64.c new file mode 100644 index 0000000..d9951b5 --- /dev/null +++ b/lib_generic/div64.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2003 Bernardo Innocenti + * + * Based on former do_div() implementation from asm-parisc/div64.h: + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang + * + * + * Generic C version of 64bit/32bit division and modulo, with + * 64bit result and 32bit remainder. + * + * The fast case for (n>>32 == 0) is handled inline by do_div(). + * + * Code generated for this function might be very inefficient + * for some CPUs. __div64_32() can be overridden by linking arch-specific + * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S. + */ + +#include + +uint32_t __div64_32(uint64_t *n, uint32_t base) +{ + uint64_t rem = *n; + uint64_t b = base; + uint64_t res, d = 1; + uint32_t high = rem >> 32; + + /* Reduce the thing a bit first */ + res = 0; + if (high >= base) { + high /= base; + res = (uint64_t) high << 32; + rem -= (uint64_t) (high*base) << 32; + } + + while ((int64_t)b > 0 && b < rem) { + b = b+b; + d = d+d; + } + + do { + if (rem >= b) { + rem -= b; + res += d; + } + b >>= 1; + d >>= 1; + } while (d); + + *n = res; + return rem; +} -- cgit v1.1 From 3a6d56c20989fe27360afe743bd2a7ad4d76e48f Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Thu, 2 Aug 2007 17:42:08 +0200 Subject: Make use of generic 64bit division in nand_util.c Use generic 64bit division in nand_util.c. This makes nand_util.c independent of any toolchain 64bit division. Signed-off-by: Dirk Behme --- drivers/nand/nand_util.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/nand/nand_util.c b/drivers/nand/nand_util.c index 88c1df6..aee8727 100644 --- a/drivers/nand/nand_util.c +++ b/drivers/nand/nand_util.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -208,10 +209,10 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) } if (!opts->quiet) { - int percent = (int) - ((unsigned long long) + unsigned long long n =(unsigned long long) (erase.addr+meminfo->erasesize-opts->offset) - * 100 / erase_length); + * 100; + int percent = (int)do_div(n, erase_length); /* output progress message only at whole percent * steps to reduce the number of messages printed @@ -475,10 +476,9 @@ int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts) imglen -= readlen; if (!opts->quiet) { - int percent = (int) - ((unsigned long long) - (opts->length-imglen) * 100 - / opts->length); + unsigned long long n = (unsigned long long) + (opts->length-imglen) * 100; + int percent = (int)do_div(n, opts->length); /* output progress message only at whole percent * steps to reduce the number of messages printed * on (slow) serial consoles @@ -651,10 +651,9 @@ int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts) } if (!opts->quiet) { - int percent = (int) - ((unsigned long long) - (opts->length-imglen) * 100 - / opts->length); + unsigned long long n = (unsigned long long) + (opts->length-imglen) * 100; + int percent = (int)do_div(n ,opts->length); /* output progress message only at whole percent * steps to reduce the number of messages printed * on (slow) serial consoles -- cgit v1.1 From c74b2108e31fe09bd1c5d291c3cf360510d4f13e Mon Sep 17 00:00:00 2001 From: Sergey Kubushyn Date: Fri, 10 Aug 2007 20:26:18 +0200 Subject: [ARM] TI DaVinci support, hopefully final Add support for the following DaVinci boards: - DV_EVM - SCHMOOGIE - SONATA Changes: - Split into separate board directories - Removed changes to MTD_DEBUG (or whatever it's called) - New CONFIG_CMD party line followed - Some cosmetic fixes, cleanup etc. - Patches against the latest U-Boot tree as of now. - Fixed CONFIG_CMD_NET in net files. - Fixed CONFIG_CMD_EEPROM for schmoogie. - Made sure it compiles and works (forceenv() link problem) on SCHMOOGIE and DV_EVM. Can't check if it works on SONATA, don't have a board any more, but it at least compiles. Here is an excerpt from session log on SCHMOOGIE... U-Boot 1.2.0-g6c33c785-dirty (Aug 7 2007 - 13:07:17) DRAM: 128 MB NAND: 128 MiB In: serial Out: serial Err: serial ARM Clock : 297MHz DDR Clock : 162MHz ETH PHY : DP83848 @ 0x01 U-Boot > iprobe Valid chip addresses: 1B 38 3A 3D 3F 50 5D 6F U-Boot > ping 192.168.253.10 host 192.168.253.10 is alive U-Boot > Signed-off-by: Sergey Kubushyn Acked-by: Dirk Behme Acked-by: Zach Sadecki Acked-by: Stefan Roese --- CREDITS | 4 + MAINTAINERS | 6 + MAKEALL | 3 +- Makefile | 9 + board/davinci/dv-evm/Makefile | 52 +++ board/davinci/dv-evm/board_init.S | 29 ++ board/davinci/dv-evm/config.mk | 39 ++ board/davinci/dv-evm/dv_board.c | 211 +++++++++ board/davinci/dv-evm/u-boot.lds | 52 +++ board/davinci/schmoogie/Makefile | 52 +++ board/davinci/schmoogie/board_init.S | 29 ++ board/davinci/schmoogie/config.mk | 39 ++ board/davinci/schmoogie/dv_board.c | 253 +++++++++++ board/davinci/schmoogie/u-boot.lds | 52 +++ board/davinci/sonata/Makefile | 52 +++ board/davinci/sonata/board_init.S | 100 +++++ board/davinci/sonata/config.mk | 39 ++ board/davinci/sonata/dv_board.c | 208 +++++++++ board/davinci/sonata/u-boot.lds | 52 +++ common/cmd_nvedit.c | 15 +- cpu/arm926ejs/davinci/Makefile | 49 +++ cpu/arm926ejs/davinci/dp83848.c | 156 +++++++ cpu/arm926ejs/davinci/ether.c | 652 ++++++++++++++++++++++++++++ cpu/arm926ejs/davinci/i2c.c | 351 +++++++++++++++ cpu/arm926ejs/davinci/lowlevel_init.S | 707 +++++++++++++++++++++++++++++++ cpu/arm926ejs/davinci/lxt972.c | 142 +++++++ cpu/arm926ejs/davinci/nand.c | 389 +++++++++++++++++ cpu/arm926ejs/davinci/reset.S | 77 ++++ cpu/arm926ejs/davinci/timer.c | 165 ++++++++ include/_exports.h | 3 + include/asm-arm/arch-davinci/emac_defs.h | 311 ++++++++++++++ include/asm-arm/arch-davinci/emif_defs.h | 61 +++ include/asm-arm/arch-davinci/hardware.h | 166 ++++++++ include/asm-arm/arch-davinci/i2c_defs.h | 94 ++++ include/asm-arm/arch-davinci/nand_defs.h | 161 +++++++ include/common.h | 3 + include/configs/davinci_dvevm.h | 214 ++++++++++ include/configs/davinci_schmoogie.h | 157 +++++++ include/configs/davinci_sonata.h | 209 +++++++++ include/dp83848.h | 88 ++++ include/exports.h | 3 + lib_arm/board.c | 7 + net/eth.c | 5 + 43 files changed, 5464 insertions(+), 2 deletions(-) create mode 100644 board/davinci/dv-evm/Makefile create mode 100644 board/davinci/dv-evm/board_init.S create mode 100644 board/davinci/dv-evm/config.mk create mode 100644 board/davinci/dv-evm/dv_board.c create mode 100644 board/davinci/dv-evm/u-boot.lds create mode 100644 board/davinci/schmoogie/Makefile create mode 100644 board/davinci/schmoogie/board_init.S create mode 100644 board/davinci/schmoogie/config.mk create mode 100644 board/davinci/schmoogie/dv_board.c create mode 100644 board/davinci/schmoogie/u-boot.lds create mode 100644 board/davinci/sonata/Makefile create mode 100644 board/davinci/sonata/board_init.S create mode 100644 board/davinci/sonata/config.mk create mode 100644 board/davinci/sonata/dv_board.c create mode 100644 board/davinci/sonata/u-boot.lds create mode 100644 cpu/arm926ejs/davinci/Makefile create mode 100644 cpu/arm926ejs/davinci/dp83848.c create mode 100644 cpu/arm926ejs/davinci/ether.c create mode 100644 cpu/arm926ejs/davinci/i2c.c create mode 100644 cpu/arm926ejs/davinci/lowlevel_init.S create mode 100644 cpu/arm926ejs/davinci/lxt972.c create mode 100644 cpu/arm926ejs/davinci/nand.c create mode 100644 cpu/arm926ejs/davinci/reset.S create mode 100644 cpu/arm926ejs/davinci/timer.c create mode 100644 include/asm-arm/arch-davinci/emac_defs.h create mode 100644 include/asm-arm/arch-davinci/emif_defs.h create mode 100644 include/asm-arm/arch-davinci/hardware.h create mode 100644 include/asm-arm/arch-davinci/i2c_defs.h create mode 100644 include/asm-arm/arch-davinci/nand_defs.h create mode 100644 include/configs/davinci_dvevm.h create mode 100644 include/configs/davinci_schmoogie.h create mode 100644 include/configs/davinci_sonata.h create mode 100644 include/dp83848.h diff --git a/CREDITS b/CREDITS index 7af1b80..4c8b896 100644 --- a/CREDITS +++ b/CREDITS @@ -252,6 +252,10 @@ E: Raghu.Krishnaprasad@fci.com D: Support for Adder-II MPC852T evaluation board W: http://www.forcecomputers.com +N: Sergey Kubushyn +E: ksi@koi8.net +D: Support for various TI DaVinci based boards. + N: Bernhard Kuhn E: bkuhn@metrowerks.com D Support for Coldfire CPU; Support for Motorola M5272C3 and M5282EVB boards diff --git a/MAINTAINERS b/MAINTAINERS index 693b115..865f6fe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -444,6 +444,12 @@ Nishant Kamat omap1610h2 ARM926EJS +Sergey Kubushyn + + DV-EVM ARM926EJS + SONATA ARM926EJS + SCHMOOGIE ARM926EJS + Prakash Kumar cerf250 xscale diff --git a/MAKEALL b/MAKEALL index 3e186cc..c672b51 100755 --- a/MAKEALL +++ b/MAKEALL @@ -220,7 +220,8 @@ LIST_ARM9=" \ omap1610h2 omap1610inn omap730p2 sbc2410x \ scb9328 smdk2400 smdk2410 trab \ VCMA9 versatile versatileab versatilepb \ - voiceblue \ + voiceblue davinci_dvevm davinci_schmoogie \ + davinci_sonata " ######################################################################### diff --git a/Makefile b/Makefile index 0e6d399..87ddb1c 100644 --- a/Makefile +++ b/Makefile @@ -2018,6 +2018,15 @@ omap1510inn_config : unconfig omap5912osk_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm926ejs omap5912osk NULL omap +davinci_dvevm_config : unconfig + @$(MKCONFIG) $(@:_config=) arm arm926ejs dv-evm davinci davinci + +davinci_schmoogie_config : unconfig + @$(MKCONFIG) $(@:_config=) arm arm926ejs schmoogie davinci davinci + +davinci_sonata_config : unconfig + @$(MKCONFIG) $(@:_config=) arm arm926ejs sonata davinci davinci + omap1610inn_config \ omap1610inn_cs0boot_config \ omap1610inn_cs3boot_config \ diff --git a/board/davinci/dv-evm/Makefile b/board/davinci/dv-evm/Makefile new file mode 100644 index 0000000..fa00138 --- /dev/null +++ b/board/davinci/dv-evm/Makefile @@ -0,0 +1,52 @@ +# +# (C) Copyright 2000, 2001, 2002 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).a + +COBJS := dv_board.o +SOBJS := board_init.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak *~ .depend + +######################################################################### +# This is for $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/davinci/dv-evm/board_init.S b/board/davinci/dv-evm/board_init.S new file mode 100644 index 0000000..22d8adc --- /dev/null +++ b/board/davinci/dv-evm/board_init.S @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * Board-specific low level initialization code. Called at the very end + * of cpu/arm926ejs/davinci/lowlevel_init.S. Just returns if there is no + * initialization required. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +.globl dv_board_init +dv_board_init: + + mov pc, lr diff --git a/board/davinci/dv-evm/config.mk b/board/davinci/dv-evm/config.mk new file mode 100644 index 0000000..aa89d0e --- /dev/null +++ b/board/davinci/dv-evm/config.mk @@ -0,0 +1,39 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, +# David Mueller, ELSOFT AG, +# +# (C) Copyright 2003 +# Texas Instruments, +# Swaminathan +# +# Davinci EVM board (ARM925EJS) cpu +# see http://www.ti.com/ for more information on Texas Instruments +# +# Davinci EVM has 1 bank of 256 MB DDR RAM +# Physical Address: +# 8000'0000 to 9000'0000 +# +# Copyright (C) 2007 Sergey Kubushyn +# +# Visioneering Corp. Sonata board (ARM926EJS) cpu +# +# Sonata board has 1 bank of 128 MB DDR RAM +# Physical Address: +# 8000'0000 to 8800'0000 +# +# Razorstream, LLC. SCHMOOGIE board (ARM926EJS) cpu +# +# Schmoogie board has 1 bank of 128 MB DDR RAM +# Physical Address: +# 8000'0000 to 8800'0000 +# +# Linux-Kernel is expected to be at 8000'8000, entry 8000'8000 +# (mem base + reserved) +# +# we load ourself to 8108 '0000 +# +# + +#Provide at least 16MB spacing between us and the Linux Kernel image +TEXT_BASE = 0x81080000 diff --git a/board/davinci/dv-evm/dv_board.c b/board/davinci/dv-evm/dv_board.c new file mode 100644 index 0000000..94925ec --- /dev/null +++ b/board/davinci/dv-evm/dv_board.c @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * Parts are shamelessly stolen from various TI sources, original copyright + * follows: + * ----------------------------------------------------------------- + * + * Copyright (C) 2004 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + */ + +#include +#include +#include +#include + +#define MACH_TYPE_DAVINCI_EVM 901 + +extern void i2c_init(int speed, int slaveaddr); +extern void timer_init(void); +extern int eth_hw_init(void); +extern phy_t phy; + + +/* Works on Always On power domain only (no PD argument) */ +void lpsc_on(unsigned int id) +{ + dv_reg_p mdstat, mdctl; + + if (id >= DAVINCI_LPSC_GEM) + return; /* Don't work on DSP Power Domain */ + + mdstat = REG_P(PSC_MDSTAT_BASE + (id * 4)); + mdctl = REG_P(PSC_MDCTL_BASE + (id * 4)); + + while (REG(PSC_PTSTAT) & 0x01) {;} + + if ((*mdstat & 0x1f) == 0x03) + return; /* Already on and enabled */ + + *mdctl |= 0x03; + + /* Special treatment for some modules as for sprue14 p.7.4.2 */ + if ( (id == DAVINCI_LPSC_VPSSSLV) || + (id == DAVINCI_LPSC_EMAC) || + (id == DAVINCI_LPSC_EMAC_WRAPPER) || + (id == DAVINCI_LPSC_MDIO) || + (id == DAVINCI_LPSC_USB) || + (id == DAVINCI_LPSC_ATA) || + (id == DAVINCI_LPSC_VLYNQ) || + (id == DAVINCI_LPSC_UHPI) || + (id == DAVINCI_LPSC_DDR_EMIF) || + (id == DAVINCI_LPSC_AEMIF) || + (id == DAVINCI_LPSC_MMC_SD) || + (id == DAVINCI_LPSC_MEMSTICK) || + (id == DAVINCI_LPSC_McBSP) || + (id == DAVINCI_LPSC_GPIO) + ) + *mdctl |= 0x200; + + REG(PSC_PTCMD) = 0x01; + + while (REG(PSC_PTSTAT) & 0x03) {;} + while ((*mdstat & 0x1f) != 0x03) {;} /* Probably an overkill... */ +} + +void dsp_on(void) +{ + int i; + + if (REG(PSC_PDSTAT1) & 0x1f) + return; /* Already on */ + + REG(PSC_GBLCTL) |= 0x01; + REG(PSC_PDCTL1) |= 0x01; + REG(PSC_PDCTL1) &= ~0x100; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) &= 0xfffffeff; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) &= 0xfffffeff; + REG(PSC_PTCMD) = 0x02; + + for (i = 0; i < 100; i++) { + if (REG(PSC_EPCPR) & 0x02) + break; + } + + REG(PSC_CHP_SHRTSW) = 0x01; + REG(PSC_PDCTL1) |= 0x100; + REG(PSC_EPCCR) = 0x02; + + for (i = 0; i < 100; i++) { + if (!(REG(PSC_PTSTAT) & 0x02)) + break; + } + + REG(PSC_GBLCTL) &= ~0x1f; +} + + +int board_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + /* arch number of the board */ + gd->bd->bi_arch_number = MACH_TYPE_DAVINCI_EVM; + + /* address of boot parameters */ + gd->bd->bi_boot_params = LINUX_BOOT_PARAM_ADDR; + + /* Workaround for TMS320DM6446 errata 1.3.22 */ + REG(PSC_SILVER_BULLET) = 0; + + /* Power on required peripherals */ + lpsc_on(DAVINCI_LPSC_EMAC); + lpsc_on(DAVINCI_LPSC_EMAC_WRAPPER); + lpsc_on(DAVINCI_LPSC_MDIO); + lpsc_on(DAVINCI_LPSC_I2C); + lpsc_on(DAVINCI_LPSC_UART0); + lpsc_on(DAVINCI_LPSC_TIMER1); + lpsc_on(DAVINCI_LPSC_GPIO); + + /* Powerup the DSP */ + dsp_on(); + + /* Bringup UART0 out of reset */ + REG(UART0_PWREMU_MGMT) = 0x0000e003; + + /* Enable GIO3.3V cells used for EMAC */ + REG(VDD3P3V_PWDN) = 0; + + /* Enable UART0 MUX lines */ + REG(PINMUX1) |= 1; + + /* Enable EMAC and AEMIF pins */ + REG(PINMUX0) = 0x80000c1f; + + /* Enable I2C pin Mux */ + REG(PINMUX1) |= (1 << 7); + + /* Set the Bus Priority Register to appropriate value */ + REG(VBPR) = 0x20; + + timer_init(); + + return(0); +} + +int misc_init_r (void) +{ + u_int8_t tmp[20], buf[10]; + int i = 0; + int clk = 0; + + clk = ((REG(PLL2_PLLM) + 1) * 27) / ((REG(PLL2_DIV2) & 0x1f) + 1); + + printf ("ARM Clock : %dMHz\n", ((REG(PLL1_PLLM) + 1) * 27 ) / 2); + printf ("DDR Clock : %dMHz\n", (clk / 2)); + + /* Set Ethernet MAC address from EEPROM */ + if (i2c_read(CFG_I2C_EEPROM_ADDR, 0x7f00, CFG_I2C_EEPROM_ADDR_LEN, buf, 6)) { + printf("\nEEPROM @ 0x%02x read FAILED!!!\n", CFG_I2C_EEPROM_ADDR); + } else { + tmp[0] = 0xff; + for (i = 0; i < 6; i++) + tmp[0] &= buf[i]; + + if ((tmp[0] != 0xff) && (getenv("ethaddr") == NULL)) { + sprintf((char *)&tmp[0], "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + setenv("ethaddr", (char *)&tmp[0]); + } + } + + if (!eth_hw_init()) { + printf("ethernet init failed!\n"); + } else { + printf("ETH PHY : %s\n", phy.name); + } + + i2c_read (0x39, 0x00, 1, (u_int8_t *)&i, 1); + + setenv ("videostd", ((i & 0x80) ? "pal" : "ntsc")); + + return(0); +} + +int dram_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + + return(0); +} diff --git a/board/davinci/dv-evm/u-boot.lds b/board/davinci/dv-evm/u-boot.lds new file mode 100644 index 0000000..710b2a2 --- /dev/null +++ b/board/davinci/dv-evm/u-boot.lds @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + . = ALIGN(4); + .text : + { + cpu/arm926ejs/start.o (.text) + *(.text) + } + . = ALIGN(4); + .rodata : { *(.rodata) } + . = ALIGN(4); + .data : { *(.data) } + . = ALIGN(4); + .got : { *(.got) } + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} diff --git a/board/davinci/schmoogie/Makefile b/board/davinci/schmoogie/Makefile new file mode 100644 index 0000000..fa00138 --- /dev/null +++ b/board/davinci/schmoogie/Makefile @@ -0,0 +1,52 @@ +# +# (C) Copyright 2000, 2001, 2002 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).a + +COBJS := dv_board.o +SOBJS := board_init.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak *~ .depend + +######################################################################### +# This is for $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/davinci/schmoogie/board_init.S b/board/davinci/schmoogie/board_init.S new file mode 100644 index 0000000..22d8adc --- /dev/null +++ b/board/davinci/schmoogie/board_init.S @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * Board-specific low level initialization code. Called at the very end + * of cpu/arm926ejs/davinci/lowlevel_init.S. Just returns if there is no + * initialization required. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +.globl dv_board_init +dv_board_init: + + mov pc, lr diff --git a/board/davinci/schmoogie/config.mk b/board/davinci/schmoogie/config.mk new file mode 100644 index 0000000..aa89d0e --- /dev/null +++ b/board/davinci/schmoogie/config.mk @@ -0,0 +1,39 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, +# David Mueller, ELSOFT AG, +# +# (C) Copyright 2003 +# Texas Instruments, +# Swaminathan +# +# Davinci EVM board (ARM925EJS) cpu +# see http://www.ti.com/ for more information on Texas Instruments +# +# Davinci EVM has 1 bank of 256 MB DDR RAM +# Physical Address: +# 8000'0000 to 9000'0000 +# +# Copyright (C) 2007 Sergey Kubushyn +# +# Visioneering Corp. Sonata board (ARM926EJS) cpu +# +# Sonata board has 1 bank of 128 MB DDR RAM +# Physical Address: +# 8000'0000 to 8800'0000 +# +# Razorstream, LLC. SCHMOOGIE board (ARM926EJS) cpu +# +# Schmoogie board has 1 bank of 128 MB DDR RAM +# Physical Address: +# 8000'0000 to 8800'0000 +# +# Linux-Kernel is expected to be at 8000'8000, entry 8000'8000 +# (mem base + reserved) +# +# we load ourself to 8108 '0000 +# +# + +#Provide at least 16MB spacing between us and the Linux Kernel image +TEXT_BASE = 0x81080000 diff --git a/board/davinci/schmoogie/dv_board.c b/board/davinci/schmoogie/dv_board.c new file mode 100644 index 0000000..b15c5f7 --- /dev/null +++ b/board/davinci/schmoogie/dv_board.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * Parts are shamelessly stolen from various TI sources, original copyright + * follows: + * ----------------------------------------------------------------- + * + * Copyright (C) 2004 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + */ + +#include +#include +#include +#include + +#define MACH_TYPE_SCHMOOGIE 1255 + +extern void i2c_init(int speed, int slaveaddr); +extern void timer_init(void); +extern int eth_hw_init(void); +extern phy_t phy; + + +/* Works on Always On power domain only (no PD argument) */ +void lpsc_on(unsigned int id) +{ + dv_reg_p mdstat, mdctl; + + if (id >= DAVINCI_LPSC_GEM) + return; /* Don't work on DSP Power Domain */ + + mdstat = REG_P(PSC_MDSTAT_BASE + (id * 4)); + mdctl = REG_P(PSC_MDCTL_BASE + (id * 4)); + + while (REG(PSC_PTSTAT) & 0x01) {;} + + if ((*mdstat & 0x1f) == 0x03) + return; /* Already on and enabled */ + + *mdctl |= 0x03; + + /* Special treatment for some modules as for sprue14 p.7.4.2 */ + if ( (id == DAVINCI_LPSC_VPSSSLV) || + (id == DAVINCI_LPSC_EMAC) || + (id == DAVINCI_LPSC_EMAC_WRAPPER) || + (id == DAVINCI_LPSC_MDIO) || + (id == DAVINCI_LPSC_USB) || + (id == DAVINCI_LPSC_ATA) || + (id == DAVINCI_LPSC_VLYNQ) || + (id == DAVINCI_LPSC_UHPI) || + (id == DAVINCI_LPSC_DDR_EMIF) || + (id == DAVINCI_LPSC_AEMIF) || + (id == DAVINCI_LPSC_MMC_SD) || + (id == DAVINCI_LPSC_MEMSTICK) || + (id == DAVINCI_LPSC_McBSP) || + (id == DAVINCI_LPSC_GPIO) + ) + *mdctl |= 0x200; + + REG(PSC_PTCMD) = 0x01; + + while (REG(PSC_PTSTAT) & 0x03) {;} + while ((*mdstat & 0x1f) != 0x03) {;} /* Probably an overkill... */ +} + +void dsp_on(void) +{ + int i; + + if (REG(PSC_PDSTAT1) & 0x1f) + return; /* Already on */ + + REG(PSC_GBLCTL) |= 0x01; + REG(PSC_PDCTL1) |= 0x01; + REG(PSC_PDCTL1) &= ~0x100; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) &= 0xfffffeff; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) &= 0xfffffeff; + REG(PSC_PTCMD) = 0x02; + + for (i = 0; i < 100; i++) { + if (REG(PSC_EPCPR) & 0x02) + break; + } + + REG(PSC_CHP_SHRTSW) = 0x01; + REG(PSC_PDCTL1) |= 0x100; + REG(PSC_EPCCR) = 0x02; + + for (i = 0; i < 100; i++) { + if (!(REG(PSC_PTSTAT) & 0x02)) + break; + } + + REG(PSC_GBLCTL) &= ~0x1f; +} + + +int board_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + /* arch number of the board */ + gd->bd->bi_arch_number = MACH_TYPE_SCHMOOGIE; + + /* address of boot parameters */ + gd->bd->bi_boot_params = LINUX_BOOT_PARAM_ADDR; + + /* Workaround for TMS320DM6446 errata 1.3.22 */ + REG(PSC_SILVER_BULLET) = 0; + + /* Power on required peripherals */ + lpsc_on(DAVINCI_LPSC_EMAC); + lpsc_on(DAVINCI_LPSC_EMAC_WRAPPER); + lpsc_on(DAVINCI_LPSC_MDIO); + lpsc_on(DAVINCI_LPSC_I2C); + lpsc_on(DAVINCI_LPSC_UART0); + lpsc_on(DAVINCI_LPSC_TIMER1); + lpsc_on(DAVINCI_LPSC_GPIO); + + /* Powerup the DSP */ + dsp_on(); + + /* Bringup UART0 out of reset */ + REG(UART0_PWREMU_MGMT) = 0x0000e003; + + /* Enable GIO3.3V cells used for EMAC */ + REG(VDD3P3V_PWDN) = 0; + + /* Enable UART0 MUX lines */ + REG(PINMUX1) |= 1; + + /* Enable EMAC and AEMIF pins */ + REG(PINMUX0) = 0x80000c1f; + + /* Enable I2C pin Mux */ + REG(PINMUX1) |= (1 << 7); + + /* Set the Bus Priority Register to appropriate value */ + REG(VBPR) = 0x20; + + timer_init(); + + return(0); +} + +int misc_init_r (void) +{ + u_int8_t tmp[20], buf[10]; + int i = 0; + int clk = 0; + + /* Set serial number from UID chip */ + u_int8_t crc_tbl[256] = { + 0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, + 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41, + 0x9d, 0xc3, 0x21, 0x7f, 0xfc, 0xa2, 0x40, 0x1e, + 0x5f, 0x01, 0xe3, 0xbd, 0x3e, 0x60, 0x82, 0xdc, + 0x23, 0x7d, 0x9f, 0xc1, 0x42, 0x1c, 0xfe, 0xa0, + 0xe1, 0xbf, 0x5d, 0x03, 0x80, 0xde, 0x3c, 0x62, + 0xbe, 0xe0, 0x02, 0x5c, 0xdf, 0x81, 0x63, 0x3d, + 0x7c, 0x22, 0xc0, 0x9e, 0x1d, 0x43, 0xa1, 0xff, + 0x46, 0x18, 0xfa, 0xa4, 0x27, 0x79, 0x9b, 0xc5, + 0x84, 0xda, 0x38, 0x66, 0xe5, 0xbb, 0x59, 0x07, + 0xdb, 0x85, 0x67, 0x39, 0xba, 0xe4, 0x06, 0x58, + 0x19, 0x47, 0xa5, 0xfb, 0x78, 0x26, 0xc4, 0x9a, + 0x65, 0x3b, 0xd9, 0x87, 0x04, 0x5a, 0xb8, 0xe6, + 0xa7, 0xf9, 0x1b, 0x45, 0xc6, 0x98, 0x7a, 0x24, + 0xf8, 0xa6, 0x44, 0x1a, 0x99, 0xc7, 0x25, 0x7b, + 0x3a, 0x64, 0x86, 0xd8, 0x5b, 0x05, 0xe7, 0xb9, + 0x8c, 0xd2, 0x30, 0x6e, 0xed, 0xb3, 0x51, 0x0f, + 0x4e, 0x10, 0xf2, 0xac, 0x2f, 0x71, 0x93, 0xcd, + 0x11, 0x4f, 0xad, 0xf3, 0x70, 0x2e, 0xcc, 0x92, + 0xd3, 0x8d, 0x6f, 0x31, 0xb2, 0xec, 0x0e, 0x50, + 0xaf, 0xf1, 0x13, 0x4d, 0xce, 0x90, 0x72, 0x2c, + 0x6d, 0x33, 0xd1, 0x8f, 0x0c, 0x52, 0xb0, 0xee, + 0x32, 0x6c, 0x8e, 0xd0, 0x53, 0x0d, 0xef, 0xb1, + 0xf0, 0xae, 0x4c, 0x12, 0x91, 0xcf, 0x2d, 0x73, + 0xca, 0x94, 0x76, 0x28, 0xab, 0xf5, 0x17, 0x49, + 0x08, 0x56, 0xb4, 0xea, 0x69, 0x37, 0xd5, 0x8b, + 0x57, 0x09, 0xeb, 0xb5, 0x36, 0x68, 0x8a, 0xd4, + 0x95, 0xcb, 0x29, 0x77, 0xf4, 0xaa, 0x48, 0x16, + 0xe9, 0xb7, 0x55, 0x0b, 0x88, 0xd6, 0x34, 0x6a, + 0x2b, 0x75, 0x97, 0xc9, 0x4a, 0x14, 0xf6, 0xa8, + 0x74, 0x2a, 0xc8, 0x96, 0x15, 0x4b, 0xa9, 0xf7, + 0xb6, 0xe8, 0x0a, 0x54, 0xd7, 0x89, 0x6b, 0x35 + }; + + clk = ((REG(PLL2_PLLM) + 1) * 27) / ((REG(PLL2_DIV2) & 0x1f) + 1); + + printf ("ARM Clock : %dMHz\n", ((REG(PLL1_PLLM) + 1) * 27 ) / 2); + printf ("DDR Clock : %dMHz\n", (clk / 2)); + + /* Set serial number from UID chip */ + if (i2c_read(CFG_UID_ADDR, 0, 1, buf, 8)) { + printf("\nUID @ 0x%02x read FAILED!!!\n", CFG_UID_ADDR); + forceenv("serial#", "FAILED"); + } else { + if (buf[0] != 0x70) { /* Device Family Code */ + printf("\nUID @ 0x%02x read FAILED!!!\n", CFG_UID_ADDR); + forceenv("serial#", "FAILED"); + } + } + /* Now check CRC */ + tmp[0] = 0; + for (i = 0; i < 8; i++) + tmp[0] = crc_tbl[tmp[0] ^ buf[i]]; + + if (tmp[0] != 0) { + printf("\nUID @ 0x%02x - BAD CRC!!!\n", CFG_UID_ADDR); + forceenv("serial#", "FAILED"); + } else { + /* CRC OK, set "serial" env variable */ + sprintf((char *)&tmp[0], "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", + buf[6], buf[5], buf[4], buf[3], buf[2], buf[1]); + forceenv("serial#", (char *)&tmp[0]); + } + + if (!eth_hw_init()) { + printf("ethernet init failed!\n"); + } else { + printf("ETH PHY : %s\n", phy.name); + } + + return(0); +} + +int dram_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + + return(0); +} diff --git a/board/davinci/schmoogie/u-boot.lds b/board/davinci/schmoogie/u-boot.lds new file mode 100644 index 0000000..710b2a2 --- /dev/null +++ b/board/davinci/schmoogie/u-boot.lds @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + . = ALIGN(4); + .text : + { + cpu/arm926ejs/start.o (.text) + *(.text) + } + . = ALIGN(4); + .rodata : { *(.rodata) } + . = ALIGN(4); + .data : { *(.data) } + . = ALIGN(4); + .got : { *(.got) } + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} diff --git a/board/davinci/sonata/Makefile b/board/davinci/sonata/Makefile new file mode 100644 index 0000000..fa00138 --- /dev/null +++ b/board/davinci/sonata/Makefile @@ -0,0 +1,52 @@ +# +# (C) Copyright 2000, 2001, 2002 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).a + +COBJS := dv_board.o +SOBJS := board_init.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak *~ .depend + +######################################################################### +# This is for $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/davinci/sonata/board_init.S b/board/davinci/sonata/board_init.S new file mode 100644 index 0000000..fbb9ea7 --- /dev/null +++ b/board/davinci/sonata/board_init.S @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * Board-specific low level initialization code. Called at the very end + * of cpu/arm926ejs/davinci/lowlevel_init.S. Just returns if there is no + * initialization required. + * + * For _OLDER_ Sonata boards sets up GPIO4 to control NAND WP line. Newer + * Sonata boards, AFAIK, don't use this so it's just return by default. Ask + * Visioneering if they reinvented the wheel once again to make sure :) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +.globl dv_board_init +dv_board_init: +#ifdef SONATA_BOARD_GPIOWP + /* Set PINMUX0 to enable GPIO4 */ + ldr r0, _PINMUX0 + ldr r1, GPIO4_EN_MASK + ldr r2, [r0] + and r2, r2, r1 + str r2, [r0] + + /* Enable GPIO LPSC module */ + ldr r0, PTSTAT + +gpio_ptstat_loop1: + ldr r2, [r0] + tst r2, $0x00000001 + bne gpio_ptstat_loop1 + + ldr r1, MDCTL_GPIO + ldr r2, [r1] + and r2, r2, $0xfffffff8 + orr r2, r2, $0x00000003 + str r2, [r1] + + orr r2, r2, $0x00000200 + str r2, [r1] + + ldr r1, PTCMD + mov r2, $0x00000001 + str r2, [r1] + +gpio_ptstat_loop2: + ldr r2, [r0] + tst r2, $0x00000001 + bne gpio_ptstat_loop2 + + ldr r0, MDSTAT_GPIO +gpio_mdstat_loop: + ldr r2, [r0] + and r2, r2, $0x0000001f + teq r2, $0x00000003 + bne gpio_mdstat_loop + + /* GPIO4 -> output */ + ldr r0, GPIO_DIR01 + mov r1, $0x10 + ldr r2, [r0] + bic r2, r2, r0 + str r2, [r0] + + /* Set it to 0 (Write Protect) */ + ldr r0, GPIO_CLR_DATA01 + str r1, [r0] +#endif + + mov pc, lr + +#ifdef SONATA_BOARD_GPIOWP +.ltorg + +GPIO4_EN_MASK: + .word 0xf77fffff +MDCTL_GPIO: + .word 0x01c41a68 +MDSTAT_GPIO: + .word 0x01c41868 +GPIO_DIR01: + .word 0x01c67010 +GPIO_CLR_DATA01: + .word 0x01c6701c +#endif diff --git a/board/davinci/sonata/config.mk b/board/davinci/sonata/config.mk new file mode 100644 index 0000000..aa89d0e --- /dev/null +++ b/board/davinci/sonata/config.mk @@ -0,0 +1,39 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, +# David Mueller, ELSOFT AG, +# +# (C) Copyright 2003 +# Texas Instruments, +# Swaminathan +# +# Davinci EVM board (ARM925EJS) cpu +# see http://www.ti.com/ for more information on Texas Instruments +# +# Davinci EVM has 1 bank of 256 MB DDR RAM +# Physical Address: +# 8000'0000 to 9000'0000 +# +# Copyright (C) 2007 Sergey Kubushyn +# +# Visioneering Corp. Sonata board (ARM926EJS) cpu +# +# Sonata board has 1 bank of 128 MB DDR RAM +# Physical Address: +# 8000'0000 to 8800'0000 +# +# Razorstream, LLC. SCHMOOGIE board (ARM926EJS) cpu +# +# Schmoogie board has 1 bank of 128 MB DDR RAM +# Physical Address: +# 8000'0000 to 8800'0000 +# +# Linux-Kernel is expected to be at 8000'8000, entry 8000'8000 +# (mem base + reserved) +# +# we load ourself to 8108 '0000 +# +# + +#Provide at least 16MB spacing between us and the Linux Kernel image +TEXT_BASE = 0x81080000 diff --git a/board/davinci/sonata/dv_board.c b/board/davinci/sonata/dv_board.c new file mode 100644 index 0000000..7b0a459 --- /dev/null +++ b/board/davinci/sonata/dv_board.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * Parts are shamelessly stolen from various TI sources, original copyright + * follows: + * ----------------------------------------------------------------- + * + * Copyright (C) 2004 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + */ + +#include +#include +#include +#include + +#define MACH_TYPE_SONATA 1254 + +extern void i2c_init(int speed, int slaveaddr); +extern void timer_init(void); +extern int eth_hw_init(void); +extern phy_t phy; + + +/* Works on Always On power domain only (no PD argument) */ +void lpsc_on(unsigned int id) +{ + dv_reg_p mdstat, mdctl; + + if (id >= DAVINCI_LPSC_GEM) + return; /* Don't work on DSP Power Domain */ + + mdstat = REG_P(PSC_MDSTAT_BASE + (id * 4)); + mdctl = REG_P(PSC_MDCTL_BASE + (id * 4)); + + while (REG(PSC_PTSTAT) & 0x01) {;} + + if ((*mdstat & 0x1f) == 0x03) + return; /* Already on and enabled */ + + *mdctl |= 0x03; + + /* Special treatment for some modules as for sprue14 p.7.4.2 */ + if ( (id == DAVINCI_LPSC_VPSSSLV) || + (id == DAVINCI_LPSC_EMAC) || + (id == DAVINCI_LPSC_EMAC_WRAPPER) || + (id == DAVINCI_LPSC_MDIO) || + (id == DAVINCI_LPSC_USB) || + (id == DAVINCI_LPSC_ATA) || + (id == DAVINCI_LPSC_VLYNQ) || + (id == DAVINCI_LPSC_UHPI) || + (id == DAVINCI_LPSC_DDR_EMIF) || + (id == DAVINCI_LPSC_AEMIF) || + (id == DAVINCI_LPSC_MMC_SD) || + (id == DAVINCI_LPSC_MEMSTICK) || + (id == DAVINCI_LPSC_McBSP) || + (id == DAVINCI_LPSC_GPIO) + ) + *mdctl |= 0x200; + + REG(PSC_PTCMD) = 0x01; + + while (REG(PSC_PTSTAT) & 0x03) {;} + while ((*mdstat & 0x1f) != 0x03) {;} /* Probably an overkill... */ +} + +void dsp_on(void) +{ + int i; + + if (REG(PSC_PDSTAT1) & 0x1f) + return; /* Already on */ + + REG(PSC_GBLCTL) |= 0x01; + REG(PSC_PDCTL1) |= 0x01; + REG(PSC_PDCTL1) &= ~0x100; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) &= 0xfffffeff; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) &= 0xfffffeff; + REG(PSC_PTCMD) = 0x02; + + for (i = 0; i < 100; i++) { + if (REG(PSC_EPCPR) & 0x02) + break; + } + + REG(PSC_CHP_SHRTSW) = 0x01; + REG(PSC_PDCTL1) |= 0x100; + REG(PSC_EPCCR) = 0x02; + + for (i = 0; i < 100; i++) { + if (!(REG(PSC_PTSTAT) & 0x02)) + break; + } + + REG(PSC_GBLCTL) &= ~0x1f; +} + + +int board_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + /* arch number of the board */ + gd->bd->bi_arch_number = MACH_TYPE_SONATA; + + /* address of boot parameters */ + gd->bd->bi_boot_params = LINUX_BOOT_PARAM_ADDR; + + /* Workaround for TMS320DM6446 errata 1.3.22 */ + REG(PSC_SILVER_BULLET) = 0; + + /* Power on required peripherals */ + lpsc_on(DAVINCI_LPSC_EMAC); + lpsc_on(DAVINCI_LPSC_EMAC_WRAPPER); + lpsc_on(DAVINCI_LPSC_MDIO); + lpsc_on(DAVINCI_LPSC_I2C); + lpsc_on(DAVINCI_LPSC_UART0); + lpsc_on(DAVINCI_LPSC_TIMER1); + lpsc_on(DAVINCI_LPSC_GPIO); + + /* Powerup the DSP */ + dsp_on(); + + /* Bringup UART0 out of reset */ + REG(UART0_PWREMU_MGMT) = 0x0000e003; + + /* Enable GIO3.3V cells used for EMAC */ + REG(VDD3P3V_PWDN) = 0; + + /* Enable UART0 MUX lines */ + REG(PINMUX1) |= 1; + + /* Enable EMAC and AEMIF pins */ + REG(PINMUX0) = 0x80000c1f; + + /* Enable I2C pin Mux */ + REG(PINMUX1) |= (1 << 7); + + /* Set the Bus Priority Register to appropriate value */ + REG(VBPR) = 0x20; + + timer_init(); + + return(0); +} + +int misc_init_r (void) +{ + u_int8_t tmp[20], buf[10]; + int i = 0; + int clk = 0; + + + clk = ((REG(PLL2_PLLM) + 1) * 27) / ((REG(PLL2_DIV2) & 0x1f) + 1); + + printf ("ARM Clock : %dMHz\n", ((REG(PLL1_PLLM) + 1) * 27 ) / 2); + printf ("DDR Clock : %dMHz\n", (clk / 2)); + + /* Set Ethernet MAC address from EEPROM */ + if (i2c_read(CFG_I2C_EEPROM_ADDR, 0x7f00, CFG_I2C_EEPROM_ADDR_LEN, buf, 6)) { + printf("\nEEPROM @ 0x%02x read FAILED!!!\n", CFG_I2C_EEPROM_ADDR); + } else { + tmp[0] = 0xff; + for (i = 0; i < 6; i++) + tmp[0] &= buf[i]; + + if ((tmp[0] != 0xff) && (getenv("ethaddr") == NULL)) { + sprintf((char *)&tmp[0], "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + setenv("ethaddr", (char *)&tmp[0]); + } + } + + if (!eth_hw_init()) { + printf("ethernet init failed!\n"); + } else { + printf("ETH PHY : %s\n", phy.name); + } + + return(0); +} + +int dram_init(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + gd->bd->bi_dram[0].start = PHYS_SDRAM_1; + gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; + + return(0); +} diff --git a/board/davinci/sonata/u-boot.lds b/board/davinci/sonata/u-boot.lds new file mode 100644 index 0000000..710b2a2 --- /dev/null +++ b/board/davinci/sonata/u-boot.lds @@ -0,0 +1,52 @@ +/* + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + . = ALIGN(4); + .text : + { + cpu/arm926ejs/start.o (.text) + *(.text) + } + . = ALIGN(4); + .rodata : { *(.rodata) } + . = ALIGN(4); + .data : { *(.data) } + . = ALIGN(4); + .got : { *(.got) } + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} diff --git a/common/cmd_nvedit.c b/common/cmd_nvedit.c index de5a514..1db0fc3 100644 --- a/common/cmd_nvedit.c +++ b/common/cmd_nvedit.c @@ -193,7 +193,12 @@ int _do_setenv (int flag, int argc, char *argv[]) * Ethernet Address and serial# can be set only once, * ver is readonly. */ +#ifdef CONFIG_HAS_UID + /* Allow serial# forced overwrite with 0xdeaf4add flag */ + if ( ((strcmp (name, "serial#") == 0) && (flag != 0xdeaf4add)) || +#else if ( (strcmp (name, "serial#") == 0) || +#endif ((strcmp (name, "ethaddr") == 0) #if defined(CONFIG_OVERWRITE_ETHADDR_ONCE) && defined(CONFIG_ETHADDR) && (strcmp ((char *)env_get_addr(oldval),MK_STR(CONFIG_ETHADDR)) != 0) @@ -397,7 +402,15 @@ void setenv (char *varname, char *varvalue) _do_setenv (0, 3, argv); } -int do_setenv ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +#ifdef CONFIG_HAS_UID +void forceenv (char *varname, char *varvalue) +{ + char *argv[4] = { "forceenv", varname, varvalue, NULL }; + _do_setenv (0xdeaf4add, 3, argv); +} +#endif + +int do_setenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { if (argc < 2) { printf ("Usage:\n%s\n", cmdtp->usage); diff --git a/cpu/arm926ejs/davinci/Makefile b/cpu/arm926ejs/davinci/Makefile new file mode 100644 index 0000000..0f77f40 --- /dev/null +++ b/cpu/arm926ejs/davinci/Makefile @@ -0,0 +1,49 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).a + +COBJS = timer.o ether.o lxt972.o dp83848.o i2c.o nand.o +SOBJS = lowlevel_init.o reset.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/arm926ejs/davinci/dp83848.c b/cpu/arm926ejs/davinci/dp83848.c new file mode 100644 index 0000000..5719845 --- /dev/null +++ b/cpu/arm926ejs/davinci/dp83848.c @@ -0,0 +1,156 @@ +/* + * National Semiconductor DP83848 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * -------------------------------------------------------- + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +int dp83848_is_phy_connected(int phy_addr) +{ + u_int16_t id1, id2; + + if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID1_REG, &id1)) + return(0); + if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID2_REG, &id2)) + return(0); + + if ((id1 == DP83848_PHYID1_OUI) && (id2 == DP83848_PHYID2_OUI)) + return(1); + + return(0); +} + +int dp83848_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR; + + if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp)) + return(0); + + if (!(tmp & DP83848_LINK_STATUS)) /* link up? */ + return(0); + + if (!dm644x_eth_phy_read(phy_addr, DP83848_PHY_STAT_REG, &tmp)) + return(0); + + /* Speed doesn't matter, there is no setting for it in EMAC... */ + if (tmp & DP83848_SPEED) { + if (tmp & DP83848_DUPLEX) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); + } else { + if (tmp & DP83848_DUPLEX) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); + } + + return(0); +} + + +int dp83848_init_phy(int phy_addr) +{ + int ret = 1; + + if (!dp83848_get_link_speed(phy_addr)) { + /* Try another time */ + udelay(100000); + ret = dp83848_get_link_speed(phy_addr); + } + + /* Disable PHY Interrupts */ + dm644x_eth_phy_write(phy_addr, DP83848_PHY_INTR_CTRL_REG, 0); + + return(ret); +} + + +int dp83848_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + + if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp &= ~DP83848_AUTONEG; /* remove autonegotiation enable */ + tmp |= DP83848_ISOLATE; /* Electrically isolate PHY */ + dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /* Set the Auto_negotiation Advertisement Register + * MII advertising for Next page, 100BaseTxFD and HD, + * 10BaseTFD and HD, IEEE 802.3 + */ + tmp = DP83848_NP | DP83848_TX_FDX | DP83848_TX_HDX | + DP83848_10_FDX | DP83848_10_HDX | DP83848_AN_IEEE_802_3; + dm644x_eth_phy_write(phy_addr, DP83848_ANA_REG, tmp); + + + /* Read Control Register */ + if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp)) + return(0); + + tmp |= DP83848_SPEED_SELECT | DP83848_AUTONEG | DP83848_DUPLEX_MODE; + dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /* Restart Auto_negotiation */ + tmp |= DP83848_RESTART_AUTONEG; + dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /*check AutoNegotiate complete */ + udelay(10000); + if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp)) + return(0); + + if (!(tmp & DP83848_AUTONEG_COMP)) + return(0); + + return (dp83848_get_link_speed(phy_addr)); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/cpu/arm926ejs/davinci/ether.c b/cpu/arm926ejs/davinci/ether.c new file mode 100644 index 0000000..9ec1ee7 --- /dev/null +++ b/cpu/arm926ejs/davinci/ether.c @@ -0,0 +1,652 @@ +/* + * Ethernet driver for TI TMS320DM644x (DaVinci) chips. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright + * follows: + * + * ---------------------------------------------------------------------------- + * + * dm644x_emac.c + * + * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM + * + * Copyright (C) 2005 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + + * Modifications: + * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot. + * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors + * + */ +#include +#include +#include +#include +#include + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +unsigned int emac_dbg = 0; +#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) + +/* Internal static functions */ +static int dm644x_eth_hw_init (void); +static int dm644x_eth_open (void); +static int dm644x_eth_close (void); +static int dm644x_eth_send_packet (volatile void *packet, int length); +static int dm644x_eth_rcv_packet (void); +static void dm644x_eth_mdio_enable(void); + +static int gen_init_phy(int phy_addr); +static int gen_is_phy_connected(int phy_addr); +static int gen_get_link_speed(int phy_addr); +static int gen_auto_negotiate(int phy_addr); + +/* Wrappers exported to the U-Boot proper */ +int eth_hw_init(void) +{ + return(dm644x_eth_hw_init()); +} + +int eth_init(bd_t * bd) +{ + return(dm644x_eth_open()); +} + +void eth_halt(void) +{ + dm644x_eth_close(); +} + +int eth_send(volatile void *packet, int length) +{ + return(dm644x_eth_send_packet(packet, length)); +} + +int eth_rx(void) +{ + return(dm644x_eth_rcv_packet()); +} + +void eth_mdio_enable(void) +{ + dm644x_eth_mdio_enable(); +} +/* End of wrappers */ + + +static u_int8_t dm644x_eth_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +/* + * This function must be called before emac_open() if you want to override + * the default mac address. + */ +void dm644x_eth_set_mac_addr(const u_int8_t *addr) +{ + int i; + + for (i = 0; i < sizeof (dm644x_eth_mac_addr); i++) { + dm644x_eth_mac_addr[i] = addr[i]; + } +} + +/* EMAC Addresses */ +static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; +static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; +static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR; + +/* EMAC descriptors */ +static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); +static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); +static volatile emac_desc *emac_rx_active_head = 0; +static volatile emac_desc *emac_rx_active_tail = 0; +static int emac_rx_queue_active = 0; + +/* Receive packet buffers */ +static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + +/* PHY address for a discovered PHY (0xff - not found) */ +static volatile u_int8_t active_phy_addr = 0xff; + +phy_t phy; + +static void dm644x_eth_mdio_enable(void) +{ + u_int32_t clkdiv; + + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + + adap_mdio->CONTROL = (clkdiv & 0xff) | + MDIO_CONTROL_ENABLE | + MDIO_CONTROL_FAULT | + MDIO_CONTROL_FAULT_ENABLE; + + while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;} +} + +/* + * Tries to find an active connected PHY. Returns 1 if address if found. + * If no active PHY (or more than one PHY) found returns 0. + * Sets active_phy_addr variable. + */ +static int dm644x_eth_phy_detect(void) +{ + u_int32_t phy_act_state; + int i; + + active_phy_addr = 0xff; + + if ((phy_act_state = adap_mdio->ALIVE) == 0) + return(0); /* No active PHYs */ + + debug_emac("dm644x_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); + + for (i = 0; i < 32; i++) { + if (phy_act_state & (1 << i)) { + if (phy_act_state & ~(1 << i)) + return(0); /* More than one PHY */ + else { + active_phy_addr = i; + return(1); + } + } + } + + return(0); /* Just to make GCC happy */ +} + + +/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ +int dm644x_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) +{ + int tmp; + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_READ | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16); + + /* Wait for command to complete */ + while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;} + + if (tmp & MDIO_USERACCESS0_ACK) { + *data = tmp & 0xffff; + return(1); + } + + *data = -1; + return(0); +} + +/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ +int dm644x_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) +{ + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_WRITE | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16) | + (data & 0xffff); + + /* Wait for command to complete */ + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + return(1); +} + +/* PHY functions for a generic PHY */ +static int gen_init_phy(int phy_addr) +{ + int ret = 1; + + if (gen_get_link_speed(phy_addr)) { + /* Try another time */ + ret = gen_get_link_speed(phy_addr); + } + + return(ret); +} + +static int gen_is_phy_connected(int phy_addr) +{ + u_int16_t dummy; + + return(dm644x_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy)); +} + +static int gen_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + + if (dm644x_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04)) + return(1); + + return(0); +} + +static int gen_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + + if (!dm644x_eth_phy_read(phy_addr, PHY_BMCR, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp |= PHY_BMCR_AUTON; + dm644x_eth_phy_write(phy_addr, PHY_BMCR, tmp); + + /*check AutoNegotiate complete */ + udelay (10000); + if (!dm644x_eth_phy_read(phy_addr, PHY_BMSR, &tmp)) + return(0); + + if (!(tmp & PHY_BMSR_AUTN_COMP)) + return(0); + + return(gen_get_link_speed(phy_addr)); +} +/* End of generic PHY functions */ + + + +#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +static int dm644x_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) +{ + return(dm644x_eth_phy_read(addr, reg, value) ? 0 : 1); +} + +static int dm644x_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value) +{ + return(dm644x_eth_phy_write(addr, reg, value) ? 0 : 1); +} + +int dm644x_eth_miiphy_initialize(bd_t *bis) +{ + miiphy_register(phy.name, dm644x_mii_phy_read, dm644x_mii_phy_write); + + return(1); +} +#endif + +/* + * This function initializes the emac hardware. It does NOT initialize + * EMAC modules power or pin multiplexors, that is done by board_init() + * much earlier in bootup process. Returns 1 on success, 0 otherwise. + */ +static int dm644x_eth_hw_init(void) +{ + u_int32_t phy_id; + u_int16_t tmp; + int i; + + dm644x_eth_mdio_enable(); + + for (i = 0; i < 256; i++) { + if (adap_mdio->ALIVE) + break; + udelay(10); + } + + if (i >= 256) { + printf("No ETH PHY detected!!!\n"); + return(0); + } + + /* Find if a PHY is connected and get it's address */ + if (!dm644x_eth_phy_detect()) + return(0); + + /* Get PHY ID and initialize phy_ops for a detected PHY */ + if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id = (tmp << 16) & 0xffff0000; + + if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id |= tmp & 0x0000ffff; + + switch (phy_id) { + case PHY_LXT972: + sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr); + phy.init = lxt972_init_phy; + phy.is_phy_connected = lxt972_is_phy_connected; + phy.get_link_speed = lxt972_get_link_speed; + phy.auto_negotiate = lxt972_auto_negotiate; + break; + case PHY_DP83848: + sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr); + phy.init = dp83848_init_phy; + phy.is_phy_connected = dp83848_is_phy_connected; + phy.get_link_speed = dp83848_get_link_speed; + phy.auto_negotiate = dp83848_auto_negotiate; + break; + default: + sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); + phy.init = gen_init_phy; + phy.is_phy_connected = gen_is_phy_connected; + phy.get_link_speed = gen_get_link_speed; + phy.auto_negotiate = gen_auto_negotiate; + } + + return(1); +} + + +/* Eth device open */ +static int dm644x_eth_open(void) +{ + dv_reg_p addr; + u_int32_t clkdiv, cnt; + volatile emac_desc *rx_desc; + + debug_emac("+ emac_open\n"); + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + while (adap_emac->SOFTRESET != 0) {;} + adap_ewrap->EWCTL = 0; + for (cnt = 0; cnt < 5; cnt++) { + clkdiv = adap_ewrap->EWCTL; + } + + rx_desc = emac_rx_desc; + + adap_emac->TXCONTROL = 0x01; + adap_emac->RXCONTROL = 0x01; + + /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */ + /* Using channel 0 only - other channels are disabled */ + adap_emac->MACINDEX = 0; + adap_emac->MACADDRHI = + (dm644x_eth_mac_addr[3] << 24) | + (dm644x_eth_mac_addr[2] << 16) | + (dm644x_eth_mac_addr[1] << 8) | + (dm644x_eth_mac_addr[0]); + adap_emac->MACADDRLO = + (dm644x_eth_mac_addr[5] << 8) | + (dm644x_eth_mac_addr[4]); + + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Set source MAC address - REQUIRED */ + adap_emac->MACSRCADDRHI = + (dm644x_eth_mac_addr[3] << 24) | + (dm644x_eth_mac_addr[2] << 16) | + (dm644x_eth_mac_addr[1] << 8) | + (dm644x_eth_mac_addr[0]); + adap_emac->MACSRCADDRLO = + (dm644x_eth_mac_addr[4] << 8) | + (dm644x_eth_mac_addr[5]); + + /* Set DMA 8 TX / 8 RX Head pointers to 0 */ + addr = &adap_emac->TX0HDP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + addr = &adap_emac->RX0HDP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + /* Clear Statistics (do this before setting MacControl register) */ + addr = &adap_emac->RXGOODFRAMES; + for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) + *addr++ = 0; + + /* No multicast addressing */ + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Create RX queue and set receive process in place */ + emac_rx_active_head = emac_rx_desc; + for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { + rx_desc->next = (u_int32_t)(rx_desc + 1); + rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_desc++; + } + + /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ + rx_desc--; + rx_desc->next = 0; + emac_rx_active_tail = rx_desc; + emac_rx_queue_active = 1; + + /* Enable TX/RX */ + adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE; + adap_emac->RXBUFFEROFFSET = 0; + + /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ + adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN; + + /* Enable ch 0 only */ + adap_emac->RXUNICASTSET = 0x01; + + /* Enable MII interface and Full duplex mode */ + adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE); + + /* Init MDIO & get link state */ + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT); + + if (!phy.get_link_speed(active_phy_addr)) + return(0); + + /* Start receive process */ + adap_emac->RX0HDP = (u_int32_t)emac_rx_desc; + + debug_emac("- emac_open\n"); + + return(1); +} + +/* EMAC Channel Teardown */ +static void dm644x_eth_ch_teardown(int ch) +{ + dv_reg dly = 0xff; + dv_reg cnt; + + debug_emac("+ emac_ch_teardown\n"); + + if (ch == EMAC_CH_TX) { + /* Init TX channel teardown */ + adap_emac->TXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) { + /* Wait here for Tx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->TX0CP = cnt; + adap_emac->TX0HDP = 0; + } else { + /* Init RX channel teardown */ + adap_emac->RXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) { + /* Wait here for Rx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->RX0CP = cnt; + adap_emac->RX0HDP = 0; + } + + debug_emac("- emac_ch_teardown\n"); +} + +/* Eth device close */ +static int dm644x_eth_close(void) +{ + debug_emac("+ emac_close\n"); + + dm644x_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ + dm644x_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + adap_ewrap->EWCTL = 0; + + debug_emac("- emac_close\n"); + return(1); +} + +static int tx_send_loop = 0; + +/* + * This function sends a single packet on the network and returns + * positive number (number of bytes transmitted) or negative for error + */ +static int dm644x_eth_send_packet(volatile void *packet, int length) +{ + int ret_status = -1; + tx_send_loop = 0; + + /* Return error if no link */ + if (!phy.get_link_speed(active_phy_addr)) + { + printf("WARN: emac_send_packet: No link\n"); + return (ret_status); + } + + /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ + if (length < EMAC_MIN_ETHERNET_PKT_SIZE) + { + length = EMAC_MIN_ETHERNET_PKT_SIZE; + } + + /* Populate the TX descriptor */ + emac_tx_desc->next = 0; + emac_tx_desc->buffer = (u_int8_t *)packet; + emac_tx_desc->buff_off_len = (length & 0xffff); + emac_tx_desc->pkt_flag_len = ((length & 0xffff) | + EMAC_CPPI_SOP_BIT | + EMAC_CPPI_OWNERSHIP_BIT | + EMAC_CPPI_EOP_BIT); + /* Send the packet */ + adap_emac->TX0HDP = (unsigned int)emac_tx_desc; + + /* Wait for packet to complete or link down */ + while (1) { + if (!phy.get_link_speed(active_phy_addr)) { + dm644x_eth_ch_teardown(EMAC_CH_TX); + return (ret_status); + } + if (adap_emac->TXINTSTATRAW & 0x01) { + ret_status = length; + break; + } + tx_send_loop++; + } + + return(ret_status); +} + +/* + * This function handles receipt of a packet from the network + */ +static int dm644x_eth_rcv_packet(void) +{ + volatile emac_desc *rx_curr_desc; + volatile emac_desc *curr_desc; + volatile emac_desc *tail_desc; + int status, ret = -1; + + rx_curr_desc = emac_rx_active_head; + status = rx_curr_desc->pkt_flag_len; + if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) { + if (status & EMAC_CPPI_RX_ERROR_FRAME) { + /* Error in packet - discard it and requeue desc */ + printf("WARN: emac_rcv_pkt: Error in packet\n"); + } else { + NetReceive(rx_curr_desc->buffer, (rx_curr_desc->buff_off_len & 0xffff)); + ret = rx_curr_desc->buff_off_len & 0xffff; + } + + /* Ack received packet descriptor */ + adap_emac->RX0CP = (unsigned int)rx_curr_desc; + curr_desc = rx_curr_desc; + emac_rx_active_head = (volatile emac_desc *)rx_curr_desc->next; + + if (status & EMAC_CPPI_EOQ_BIT) { + if (emac_rx_active_head) { + adap_emac->RX0HDP = (unsigned int)emac_rx_active_head; + } else { + emac_rx_queue_active = 0; + printf("INFO:emac_rcv_packet: RX Queue not active\n"); + } + } + + /* Recycle RX descriptor */ + rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_curr_desc->next = 0; + + if (emac_rx_active_head == 0) { + printf("INFO: emac_rcv_pkt: active queue head = 0\n"); + emac_rx_active_head = curr_desc; + emac_rx_active_tail = curr_desc; + if (emac_rx_queue_active != 0) { + adap_emac->RX0HDP = (unsigned int)emac_rx_active_head; + printf("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); + emac_rx_queue_active = 1; + } + } else { + tail_desc = emac_rx_active_tail; + emac_rx_active_tail = curr_desc; + tail_desc->next = (unsigned int)curr_desc; + status = tail_desc->pkt_flag_len; + if (status & EMAC_CPPI_EOQ_BIT) { + adap_emac->RX0HDP = (unsigned int)curr_desc; + status &= ~EMAC_CPPI_EOQ_BIT; + tail_desc->pkt_flag_len = status; + } + } + return(ret); + } + return(0); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_TI_EMAC */ diff --git a/cpu/arm926ejs/davinci/i2c.c b/cpu/arm926ejs/davinci/i2c.c new file mode 100644 index 0000000..af9dc03 --- /dev/null +++ b/cpu/arm926ejs/davinci/i2c.c @@ -0,0 +1,351 @@ +/* + * TI DaVinci (TMS320DM644x) I2C driver. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * -------------------------------------------------------- + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +#ifdef CONFIG_DRIVER_DAVINCI_I2C + +#include +#include +#include + +#define CHECK_NACK() \ + do {\ + if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\ + REG(I2C_CON) = 0;\ + return(1);\ + }\ + } while (0) + + +static int wait_for_bus(void) +{ + int stat, timeout; + + REG(I2C_STAT) = 0xffff; + + for (timeout = 0; timeout < 10; timeout++) { + if (!((stat = REG(I2C_STAT)) & I2C_STAT_BB)) { + REG(I2C_STAT) = 0xffff; + return(0); + } + + REG(I2C_STAT) = stat; + udelay(50000); + } + + REG(I2C_STAT) = 0xffff; + return(1); +} + + +static int poll_i2c_irq(int mask) +{ + int stat, timeout; + + for (timeout = 0; timeout < 10; timeout++) { + udelay(1000); + stat = REG(I2C_STAT); + if (stat & mask) { + return(stat); + } + } + + REG(I2C_STAT) = 0xffff; + return(stat | I2C_TIMEOUT); +} + + +void flush_rx(void) +{ + int dummy; + + while (1) { + if (!(REG(I2C_STAT) & I2C_STAT_RRDY)) + break; + + dummy = REG(I2C_DRR); + REG(I2C_STAT) = I2C_STAT_RRDY; + udelay(1000); + } +} + + +void i2c_init(int speed, int slaveadd) +{ + u_int32_t div, psc; + + if (REG(I2C_CON) & I2C_CON_EN) { + REG(I2C_CON) = 0; + udelay (50000); + } + + psc = 2; + div = (CFG_HZ_CLOCK / ((psc + 1) * speed)) - 10; /* SCLL + SCLH */ + REG(I2C_PSC) = psc; /* 27MHz / (2 + 1) = 9MHz */ + REG(I2C_SCLL) = (div * 50) / 100; /* 50% Duty */ + REG(I2C_SCLH) = div - REG(I2C_SCLL); + + REG(I2C_OA) = slaveadd; + REG(I2C_CNT) = 0; + + /* Interrupts must be enabled or I2C module won't work */ + REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE | + I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE; + + /* Now enable I2C controller (get it out of reset) */ + REG(I2C_CON) = I2C_CON_EN; + + udelay(1000); +} + + +int i2c_probe(u_int8_t chip) +{ + int rc = 1; + + if (chip == REG(I2C_OA)) { + return(rc); + } + + REG(I2C_CON) = 0; + if (wait_for_bus()) {return(1);} + + /* try to read one byte from current (or only) address */ + REG(I2C_CNT) = 1; + REG(I2C_SA) = chip; + REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP); + udelay (50000); + + if (!(REG(I2C_STAT) & I2C_STAT_NACK)) { + rc = 0; + flush_rx(); + REG(I2C_STAT) = 0xffff; + } else { + REG(I2C_STAT) = 0xffff; + REG(I2C_CON) |= I2C_CON_STP; + udelay(20000); + if (wait_for_bus()) {return(1);} + } + + flush_rx(); + REG(I2C_STAT) = 0xffff; + REG(I2C_CNT) = 0; + return(rc); +} + + +int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len) +{ + u_int32_t tmp; + int i; + + if ((alen < 0) || (alen > 2)) { + printf("%s(): bogus address length %x\n", __FUNCTION__, alen); + return(1); + } + + if (wait_for_bus()) {return(1);} + + if (alen != 0) { + /* Start address phase */ + tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX; + REG(I2C_CNT) = alen; + REG(I2C_SA) = chip; + REG(I2C_CON) = tmp; + + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + switch (alen) { + case 2: + /* Send address MSByte */ + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = (addr >> 8) & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + /* No break, fall through */ + case 1: + /* Send address LSByte */ + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = addr & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY); + + CHECK_NACK(); + + if (!(tmp & I2C_STAT_ARDY)) { + REG(I2C_CON) = 0; + return(1); + } + } + } + + /* Address phase is over, now read 'len' bytes and stop */ + tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP; + REG(I2C_CNT) = len & 0xffff; + REG(I2C_SA) = chip; + REG(I2C_CON) = tmp; + + for (i = 0; i < len; i++) { + tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR); + + CHECK_NACK(); + + if (tmp & I2C_STAT_RRDY) { + buf[i] = REG(I2C_DRR); + } else { + REG(I2C_CON) = 0; + return(1); + } + } + + tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK); + + CHECK_NACK(); + + if (!(tmp & I2C_STAT_SCD)) { + REG(I2C_CON) = 0; + return(1); + } + + flush_rx(); + REG(I2C_STAT) = 0xffff; + REG(I2C_CNT) = 0; + REG(I2C_CON) = 0; + + return(0); +} + + +int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len) +{ + u_int32_t tmp; + int i; + + if ((alen < 0) || (alen > 2)) { + printf("%s(): bogus address length %x\n", __FUNCTION__, alen); + return(1); + } + if (len < 0) { + printf("%s(): bogus length %x\n", __FUNCTION__, len); + return(1); + } + + if (wait_for_bus()) {return(1);} + + /* Start address phase */ + tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP; + REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen; + REG(I2C_SA) = chip; + REG(I2C_CON) = tmp; + + switch (alen) { + case 2: + /* Send address MSByte */ + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = (addr >> 8) & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + /* No break, fall through */ + case 1: + /* Send address LSByte */ + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = addr & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + } + + for (i = 0; i < len; i++) { + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = buf[i]; + } else { + return(1); + } + } + + tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK); + + CHECK_NACK(); + + if (!(tmp & I2C_STAT_SCD)) { + REG(I2C_CON) = 0; + return(1); + } + + flush_rx(); + REG(I2C_STAT) = 0xffff; + REG(I2C_CNT) = 0; + REG(I2C_CON) = 0; + + return(0); +} + + +u_int8_t i2c_reg_read(u_int8_t chip, u_int8_t reg) +{ + u_int8_t tmp; + + i2c_read(chip, reg, 1, &tmp, 1); + return(tmp); +} + + +void i2c_reg_write(u_int8_t chip, u_int8_t reg, u_int8_t val) +{ + u_int8_t tmp; + + i2c_write(chip, reg, 1, &tmp, 1); +} + +#endif /* CONFIG_DRIVER_DAVINCI_I2C */ diff --git a/cpu/arm926ejs/davinci/lowlevel_init.S b/cpu/arm926ejs/davinci/lowlevel_init.S new file mode 100644 index 0000000..bbc48ec --- /dev/null +++ b/cpu/arm926ejs/davinci/lowlevel_init.S @@ -0,0 +1,707 @@ +/* + * Low-level board setup code for TI DaVinci SoC based boards. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * Partially based on TI sources, original copyrights follow: + */ + +/* + * Board specific setup info + * + * (C) Copyright 2003 + * Texas Instruments, + * Kshitij Gupta + * + * Modified for OMAP 1610 H2 board by Nishant Kamat, Jan 2004 + * + * Modified for OMAP 5912 OSK board by Rishi Bhattacharya, Apr 2004 + * See file CREDITS for list of people who contributed to this + * project. + * + * Modified for DV-EVM board by Rishi Bhattacharya, Apr 2005 + * See file CREDITS for list of people who contributed to this + * project. + * + * Modified for DV-EVM board by Swaminathan S, Nov 2005 + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +.globl lowlevel_init +lowlevel_init: + + /*-------------------------------------------------------* + * Mask all IRQs by setting all bits in the EINT default * + *-------------------------------------------------------*/ + mov r1, $0 + ldr r0, =EINT_ENABLE0 + str r1, [r0] + ldr r0, =EINT_ENABLE1 + str r1, [r0] + + /*------------------------------------------------------* + * Put the GEM in reset * + *------------------------------------------------------*/ + + /* Put the GEM in reset */ + ldr r8, PSC_GEM_FLAG_CLEAR + ldr r6, MDCTL_GEM + ldr r7, [r6] + and r7, r7, r8 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x02 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStopGem: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x02 + bne checkStatClkStopGem + + /* Check for GEM Reset Completion */ +checkGemStatClkStop: + ldr r6, MDSTAT_GEM + ldr r7, [r6] + ands r7, r7, $0x100 + bne checkGemStatClkStop + + /* Do this for enabling a WDT initiated reset this is a workaround + for a chip bug. Not required under normal situations */ + ldr r6, P1394 + mov r10, $0 + str r10, [r6] + + /*------------------------------------------------------* + * Enable L1 & L2 Memories in Fast mode * + *------------------------------------------------------*/ + ldr r6, DFT_ENABLE + mov r10, $0x01 + str r10, [r6] + + ldr r6, MMARG_BRF0 + ldr r10, MMARG_BRF0_VAL + str r10, [r6] + + ldr r6, DFT_ENABLE + mov r10, $0 + str r10, [r6] + + /*------------------------------------------------------* + * DDR2 PLL Initialization * + *------------------------------------------------------*/ + + /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */ + mov r10, $0 + ldr r6, PLL2_CTL + ldr r7, PLL_CLKSRC_MASK + ldr r8, [r6] + and r8, r8, r7 + mov r9, r10, lsl $8 + orr r8, r8, r9 + str r8, [r6] + + /* Select the PLLEN source */ + ldr r7, PLL_ENSRC_MASK + and r8, r8, r7 + str r8, [r6] + + /* Bypass the PLL */ + ldr r7, PLL_BYPASS_MASK + and r8, r8, r7 + str r8, [r6] + + /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */ + mov r10, $0x20 +WaitPPL2Loop: + subs r10, r10, $1 + bne WaitPPL2Loop + + /* Reset the PLL */ + ldr r7, PLL_RESET_MASK + and r8, r8, r7 + str r8, [r6] + + /* Power up the PLL */ + ldr r7, PLL_PWRUP_MASK + and r8, r8, r7 + str r8, [r6] + + /* Enable the PLL from Disable Mode */ + ldr r7, PLL_DISABLE_ENABLE_MASK + and r8, r8, r7 + str r8, [r6] + + /* Program the PLL Multiplier */ + ldr r6, PLL2_PLLM + mov r2, $0x17 /* 162 MHz */ + str r2, [r6] + + /* Program the PLL2 Divisor Value */ + ldr r6, PLL2_DIV2 + mov r3, $0x01 + str r3, [r6] + + /* Program the PLL2 Divisor Value */ + ldr r6, PLL2_DIV1 + mov r4, $0x0b /* 54 MHz */ + str r4, [r6] + + /* PLL2 DIV2 MMR */ + ldr r8, PLL2_DIV_MASK + ldr r6, PLL2_DIV2 + ldr r9, [r6] + and r8, r8, r9 + mov r9, $0x01 + mov r9, r9, lsl $15 + orr r8, r8, r9 + str r8, [r6] + + /* Program the GOSET bit to take new divider values */ + ldr r6, PLL2_PLLCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Wait for Done */ + ldr r6, PLL2_PLLSTAT +doneLoop_0: + ldr r7, [r6] + ands r7, r7, $0x01 + bne doneLoop_0 + + /* PLL2 DIV1 MMR */ + ldr r8, PLL2_DIV_MASK + ldr r6, PLL2_DIV1 + ldr r9, [r6] + and r8, r8, r9 + mov r9, $0x01 + mov r9, r9, lsl $15 + orr r8, r8, r9 + str r8, [r6] + + /* Program the GOSET bit to take new divider values */ + ldr r6, PLL2_PLLCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Wait for Done */ + ldr r6, PLL2_PLLSTAT +doneLoop: + ldr r7, [r6] + ands r7, r7, $0x01 + bne doneLoop + + /* Wait for PLL to Reset Properly */ + mov r10, $0x218 +ResetPPL2Loop: + subs r10, r10, $1 + bne ResetPPL2Loop + + /* Bring PLL out of Reset */ + ldr r6, PLL2_CTL + ldr r8, [r6] + orr r8, r8, $0x08 + str r8, [r6] + + /* Wait for PLL to Lock */ + ldr r10, PLL_LOCK_COUNT +PLL2Lock: + subs r10, r10, $1 + bne PLL2Lock + + /* Enable the PLL */ + ldr r6, PLL2_CTL + ldr r8, [r6] + orr r8, r8, $0x01 + str r8, [r6] + + /*------------------------------------------------------* + * Issue Soft Reset to DDR Module * + *------------------------------------------------------*/ + + /* Shut down the DDR2 LPSC Module */ + ldr r8, PSC_FLAG_CLEAR + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + and r7, r7, r8 + orr r7, r7, $0x03 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStop: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkStop + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkStop: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $0x1f + cmp r7, $0x03 + bne checkDDRStatClkStop + + /*------------------------------------------------------* + * Program DDR2 MMRs for 162MHz Setting * + *------------------------------------------------------*/ + + /* Program PHY Control Register */ + ldr r6, DDRCTL + ldr r7, DDRCTL_VAL + str r7, [r6] + + /* Program SDRAM Bank Config Register */ + ldr r6, SDCFG + ldr r7, SDCFG_VAL + str r7, [r6] + + /* Program SDRAM TIM-0 Config Register */ + ldr r6, SDTIM0 + ldr r7, SDTIM0_VAL_162MHz + str r7, [r6] + + /* Program SDRAM TIM-1 Config Register */ + ldr r6, SDTIM1 + ldr r7, SDTIM1_VAL_162MHz + str r7, [r6] + + /* Program the SDRAM Bank Config Control Register */ + ldr r10, MASK_VAL + ldr r8, SDCFG + ldr r9, SDCFG_VAL + and r9, r9, r10 + str r9, [r8] + + /* Program SDRAM SDREF Config Register */ + ldr r6, SDREF + ldr r7, SDREF_VAL + str r7, [r6] + + /*------------------------------------------------------* + * Issue Soft Reset to DDR Module * + *------------------------------------------------------*/ + + /* Issue a Dummy DDR2 read/write */ + ldr r8, DDR2_START_ADDR + ldr r7, DUMMY_VAL + str r7, [r8] + ldr r7, [r8] + + /* Shut down the DDR2 LPSC Module */ + ldr r8, PSC_FLAG_CLEAR + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + and r7, r7, r8 + orr r7, r7, $0x01 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStop2: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkStop2 + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkStop2: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $0x1f + cmp r7, $0x01 + bne checkDDRStatClkStop2 + + /*------------------------------------------------------* + * Turn DDR2 Controller Clocks On * + *------------------------------------------------------*/ + + /* Enable the DDR2 LPSC Module */ + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + orr r7, r7, $0x03 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkEn2: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkEn2 + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkEn2: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $0x1f + cmp r7, $0x03 + bne checkDDRStatClkEn2 + + /* DDR Writes and Reads */ + ldr r6, CFGTEST + mov r3, $0x01 + str r3, [r6] + + /*------------------------------------------------------* + * System PLL Initialization * + *------------------------------------------------------*/ + + /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */ + mov r2, $0 + ldr r6, PLL1_CTL + ldr r7, PLL_CLKSRC_MASK + ldr r8, [r6] + and r8, r8, r7 + mov r9, r2, lsl $8 + orr r8, r8, r9 + str r8, [r6] + + /* Select the PLLEN source */ + ldr r7, PLL_ENSRC_MASK + and r8, r8, r7 + str r8, [r6] + + /* Bypass the PLL */ + ldr r7, PLL_BYPASS_MASK + and r8, r8, r7 + str r8, [r6] + + /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */ + mov r10, $0x20 + +WaitLoop: + subs r10, r10, $1 + bne WaitLoop + + /* Reset the PLL */ + ldr r7, PLL_RESET_MASK + and r8, r8, r7 + str r8, [r6] + + /* Disable the PLL */ + orr r8, r8, $0x10 + str r8, [r6] + + /* Power up the PLL */ + ldr r7, PLL_PWRUP_MASK + and r8, r8, r7 + str r8, [r6] + + /* Enable the PLL from Disable Mode */ + ldr r7, PLL_DISABLE_ENABLE_MASK + and r8, r8, r7 + str r8, [r6] + + /* Program the PLL Multiplier */ + ldr r6, PLL1_PLLM + mov r3, $0x15 /* For 594MHz */ + str r3, [r6] + + /* Wait for PLL to Reset Properly */ + mov r10, $0xff + +ResetLoop: + subs r10, r10, $1 + bne ResetLoop + + /* Bring PLL out of Reset */ + ldr r6, PLL1_CTL + orr r8, r8, $0x08 + str r8, [r6] + + /* Wait for PLL to Lock */ + ldr r10, PLL_LOCK_COUNT + +PLL1Lock: + subs r10, r10, $1 + bne PLL1Lock + + /* Enable the PLL */ + orr r8, r8, $0x01 + str r8, [r6] + + nop + nop + nop + nop + + /*------------------------------------------------------* + * AEMIF configuration for NOR Flash (double check) * + *------------------------------------------------------*/ + ldr r0, _PINMUX0 + ldr r1, _DEV_SETTING + str r1, [r0] + + ldr r0, WAITCFG + ldr r1, WAITCFG_VAL + ldr r2, [r0] + orr r2, r2, r1 + str r2, [r0] + + ldr r0, ACFG3 + ldr r1, ACFG3_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + ldr r0, ACFG4 + ldr r1, ACFG4_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + ldr r0, ACFG5 + ldr r1, ACFG5_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + /*--------------------------------------* + * VTP manual Calibration * + *--------------------------------------*/ + ldr r0, VTPIOCR + ldr r1, VTP_MMR0 + str r1, [r0] + + ldr r0, VTPIOCR + ldr r1, VTP_MMR1 + str r1, [r0] + + /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */ + ldr r10, VTP_LOCK_COUNT +VTPLock: + subs r10, r10, $1 + bne VTPLock + + ldr r6, DFT_ENABLE + mov r10, $0x01 + str r10, [r6] + + ldr r6, DDRVTPR + ldr r7, [r6] + and r7, r7, $0x1f + and r8, r7, $0x3e0 + orr r8, r7, r8 + ldr r7, VTP_RECAL + orr r8, r7, r8 + ldr r7, VTP_EN + orr r8, r7, r8 + str r8, [r0] + + + /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */ + ldr r10, VTP_LOCK_COUNT +VTP1Lock: + subs r10, r10, $1 + bne VTP1Lock + + ldr r1, [r0] + ldr r2, VTP_MASK + and r2, r1, r2 + str r2, [r0] + + ldr r6, DFT_ENABLE + mov r10, $0 + str r10, [r6] + + /* + * Call board-specific lowlevel init. + * That MUST be present and THAT returns + * back to arch calling code with "mov pc, lr." + */ + b dv_board_init + +.ltorg + +_PINMUX0: + .word 0x01c40000 /* Device Configuration Registers */ +_PINMUX1: + .word 0x01c40004 /* Device Configuration Registers */ + +_DEV_SETTING: + .word 0x00000c1f + +WAITCFG: + .word 0x01e00004 +WAITCFG_VAL: + .word 0 +ACFG3: + .word 0x01e00014 +ACFG3_VAL: + .word 0x3ffffffd +ACFG4: + .word 0x01e00018 +ACFG4_VAL: + .word 0x3ffffffd +ACFG5: + .word 0x01e0001c +ACFG5_VAL: + .word 0x3ffffffd + +MDCTL_DDR2: + .word 0x01c41a34 +MDSTAT_DDR2: + .word 0x01c41834 + +PTCMD: + .word 0x01c41120 +PTSTAT: + .word 0x01c41128 + +EINT_ENABLE0: + .word 0x01c48018 +EINT_ENABLE1: + .word 0x01c4801c + +PSC_FLAG_CLEAR: + .word 0xffffffe0 +PSC_GEM_FLAG_CLEAR: + .word 0xfffffeff + +/* DDR2 MMR & CONFIGURATION VALUES, 162 MHZ clock */ +DDRCTL: + .word 0x200000e4 +DDRCTL_VAL: + .word 0x50006405 +SDREF: + .word 0x2000000c +SDREF_VAL: + .word 0x000005c3 +SDCFG: + .word 0x20000008 +SDCFG_VAL: +#ifdef DDR_4BANKS + .word 0x00178622 +#elif defined DDR_8BANKS + .word 0x00178632 +#else +#error "Unknown DDR configuration!!!" +#endif +SDTIM0: + .word 0x20000010 +SDTIM0_VAL_162MHz: + .word 0x28923211 +SDTIM1: + .word 0x20000014 +SDTIM1_VAL_162MHz: + .word 0x0016c722 +VTPIOCR: + .word 0x200000f0 /* VTP IO Control register */ +DDRVTPR: + .word 0x01c42030 /* DDR VPTR MMR */ +VTP_MMR0: + .word 0x201f +VTP_MMR1: + .word 0xa01f +DFT_ENABLE: + .word 0x01c4004c +VTP_LOCK_COUNT: + .word 0x5b0 +VTP_MASK: + .word 0xffffdfff +VTP_RECAL: + .word 0x40000 +VTP_EN: + .word 0x02000 +CFGTEST: + .word 0x80010000 +MASK_VAL: + .word 0x00000fff + +/* GEM Power Up & LPSC Control Register */ +MDCTL_GEM: + .word 0x01c41a9c +MDSTAT_GEM: + .word 0x01c4189c + +/* For WDT reset chip bug */ +P1394: + .word 0x01c41a20 + +PLL_CLKSRC_MASK: + .word 0xfffffeff /* Mask the Clock Mode bit */ +PLL_ENSRC_MASK: + .word 0xffffffdf /* Select the PLLEN source */ +PLL_BYPASS_MASK: + .word 0xfffffffe /* Put the PLL in BYPASS */ +PLL_RESET_MASK: + .word 0xfffffff7 /* Put the PLL in Reset Mode */ +PLL_PWRUP_MASK: + .word 0xfffffffd /* PLL Power up Mask Bit */ +PLL_DISABLE_ENABLE_MASK: + .word 0xffffffef /* Enable the PLL from Disable */ +PLL_LOCK_COUNT: + .word 0x2000 + +/* PLL1-SYSTEM PLL MMRs */ +PLL1_CTL: + .word 0x01c40900 +PLL1_PLLM: + .word 0x01c40910 + +/* PLL2-SYSTEM PLL MMRs */ +PLL2_CTL: + .word 0x01c40d00 +PLL2_PLLM: + .word 0x01c40d10 +PLL2_DIV1: + .word 0x01c40d18 +PLL2_DIV2: + .word 0x01c40d1c +PLL2_PLLCMD: + .word 0x01c40d38 +PLL2_PLLSTAT: + .word 0x01c40d3c +PLL2_DIV_MASK: + .word 0xffff7fff + +MMARG_BRF0: + .word 0x01c42010 /* BRF margin mode 0 (R/W)*/ +MMARG_BRF0_VAL: + .word 0x00444400 + +DDR2_START_ADDR: + .word 0x80000000 +DUMMY_VAL: + .word 0xa55aa55a diff --git a/cpu/arm926ejs/davinci/lxt972.c b/cpu/arm926ejs/davinci/lxt972.c new file mode 100644 index 0000000..6eeb6e5 --- /dev/null +++ b/cpu/arm926ejs/davinci/lxt972.c @@ -0,0 +1,142 @@ +/* + * Intel LXT971/LXT972 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * -------------------------------------------------------- + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +int lxt972_is_phy_connected(int phy_addr) +{ + u_int16_t id1, id2; + + if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_ID1, &id1)) + return(0); + if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_ID2, &id2)) + return(0); + + if ((id1 == (0x0013)) && ((id2 & 0xfff0) == 0x78e0)) + return(1); + + return(0); +} + +int lxt972_get_link_speed(int phy_addr) +{ + u_int16_t stat1, tmp; + volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR; + + if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_STAT2, &stat1)) + return(0); + + if (!(stat1 & PHY_LXT971_STAT2_LINK)) /* link up? */ + return(0); + + if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp)) + return(0); + + tmp |= PHY_LXT971_DIG_CFG_MII_DRIVE; + + dm644x_eth_phy_write(phy_addr, PHY_LXT971_DIG_CFG, tmp); + /* Read back */ + if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp)) + return(0); + + + /* Speed doesn't matter, there is no setting for it in EMAC... */ + if (stat1 & PHY_LXT971_STAT2_100BTX) { + if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); + } else { + if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); + } + + return(0); +} + + +int lxt972_init_phy(int phy_addr) +{ + int ret = 1; + + if (!lxt972_get_link_speed(phy_addr)) { + /* Try another time */ + ret = lxt972_get_link_speed(phy_addr); + } + + /* Disable PHY Interrupts */ + dm644x_eth_phy_write(phy_addr, PHY_LXT971_INT_ENABLE, 0); + + return(ret); +} + + +int lxt972_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + + if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_CTRL, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp |= PHY_COMMON_CTRL_RES_AUTO; + dm644x_eth_phy_write(phy_addr, PHY_COMMON_CTRL, tmp); + + /*check AutoNegotiate complete */ + udelay (10000); + if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_STAT, &tmp)) + return(0); + + if (!(tmp & PHY_COMMON_STAT_AN_COMP)) + return(0); + + return (lxt972_get_link_speed(phy_addr)); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/cpu/arm926ejs/davinci/nand.c b/cpu/arm926ejs/davinci/nand.c new file mode 100644 index 0000000..127be9f --- /dev/null +++ b/cpu/arm926ejs/davinci/nand.c @@ -0,0 +1,389 @@ +/* + * NAND driver for TI DaVinci based boards. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * Based on Linux DaVinci NAND driver by TI. Original copyright follows: + */ + +/* + * + * linux/drivers/mtd/nand/nand_davinci.c + * + * NAND Flash Driver + * + * Copyright (C) 2006 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + * + * Overview: + * This is a device driver for the NAND flash device found on the + * DaVinci board which utilizes the Samsung k9k2g08 part. + * + Modifications: + ver. 1.0: Feb 2005, Vinod/Sudhakar + - + * + */ + +#include + +#ifdef CFG_USE_NAND +#if !defined(CFG_NAND_LEGACY) + +#include +#include +#include + +extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; + +static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip *this = mtd->priv; + u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W; + + IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); + + switch (cmd) { + case NAND_CTL_SETCLE: + IO_ADDR_W |= MASK_CLE; + break; + case NAND_CTL_SETALE: + IO_ADDR_W |= MASK_ALE; + break; + } + + this->IO_ADDR_W = (void *)IO_ADDR_W; +} + +/* Set WP on deselect, write enable on select */ +static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) +{ +#define GPIO_SET_DATA01 0x01c67018 +#define GPIO_CLR_DATA01 0x01c6701c +#define GPIO_NAND_WP (1 << 4) +#ifdef SONATA_BOARD_GPIOWP + if (chip < 0) { + REG(GPIO_CLR_DATA01) |= GPIO_NAND_WP; + } else { + REG(GPIO_SET_DATA01) |= GPIO_NAND_WP; + } +#endif +} + +#ifdef CFG_NAND_HW_ECC +#ifdef CFG_NAND_LARGEPAGE +static struct nand_oobinfo davinci_nand_oobinfo = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 12, + .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, + .oobfree = { {2, 6}, {12, 12}, {28, 12}, {44, 12}, {60, 4} } +}; +#elif defined(CFG_NAND_SMALLPAGE) +static struct nand_oobinfo davinci_nand_oobinfo = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 3, + .eccpos = {0, 1, 2}, + .oobfree = { {6, 2}, {8, 8} } +}; +#else +#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!" +#endif + +static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) +{ + emifregs emif_addr; + int dummy; + + emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + + dummy = emif_addr->NANDF1ECC; + dummy = emif_addr->NANDF2ECC; + dummy = emif_addr->NANDF3ECC; + dummy = emif_addr->NANDF4ECC; + + emif_addr->NANDFCR |= (1 << 8); +} + +static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t region) +{ + u_int32_t ecc = 0; + emifregs emif_base_addr; + + emif_base_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + + if (region == 1) + ecc = emif_base_addr->NANDF1ECC; + else if (region == 2) + ecc = emif_base_addr->NANDF2ECC; + else if (region == 3) + ecc = emif_base_addr->NANDF3ECC; + else if (region == 4) + ecc = emif_base_addr->NANDF4ECC; + + return(ecc); +} + +static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +{ + u_int32_t tmp; + int region, n; + struct nand_chip *this = mtd->priv; + + n = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; + + region = 1; + while (n--) { + tmp = nand_davinci_readecc(mtd, region); + *ecc_code++ = tmp; + *ecc_code++ = tmp >> 16; + *ecc_code++ = ((tmp >> 8) & 0x0f) | ((tmp >> 20) & 0xf0); + region++; + } + return(0); +} + +static void nand_davinci_gen_true_ecc(u_int8_t *ecc_buf) +{ + u_int32_t tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xf0) << 20) | ((ecc_buf[2] & 0x0f) << 8); + + ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp)); + ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp)); + ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp)); +} + +static int nand_davinci_compare_ecc(u_int8_t *ecc_nand, u_int8_t *ecc_calc, u_int8_t *page_data) +{ + u_int32_t i; + u_int8_t tmp0_bit[8], tmp1_bit[8], tmp2_bit[8]; + u_int8_t comp0_bit[8], comp1_bit[8], comp2_bit[8]; + u_int8_t ecc_bit[24]; + u_int8_t ecc_sum = 0; + u_int8_t find_bit = 0; + u_int32_t find_byte = 0; + int is_ecc_ff; + + is_ecc_ff = ((*ecc_nand == 0xff) && (*(ecc_nand + 1) == 0xff) && (*(ecc_nand + 2) == 0xff)); + + nand_davinci_gen_true_ecc(ecc_nand); + nand_davinci_gen_true_ecc(ecc_calc); + + for (i = 0; i <= 2; i++) { + *(ecc_nand + i) = ~(*(ecc_nand + i)); + *(ecc_calc + i) = ~(*(ecc_calc + i)); + } + + for (i = 0; i < 8; i++) { + tmp0_bit[i] = *ecc_nand % 2; + *ecc_nand = *ecc_nand / 2; + } + + for (i = 0; i < 8; i++) { + tmp1_bit[i] = *(ecc_nand + 1) % 2; + *(ecc_nand + 1) = *(ecc_nand + 1) / 2; + } + + for (i = 0; i < 8; i++) { + tmp2_bit[i] = *(ecc_nand + 2) % 2; + *(ecc_nand + 2) = *(ecc_nand + 2) / 2; + } + + for (i = 0; i < 8; i++) { + comp0_bit[i] = *ecc_calc % 2; + *ecc_calc = *ecc_calc / 2; + } + + for (i = 0; i < 8; i++) { + comp1_bit[i] = *(ecc_calc + 1) % 2; + *(ecc_calc + 1) = *(ecc_calc + 1) / 2; + } + + for (i = 0; i < 8; i++) { + comp2_bit[i] = *(ecc_calc + 2) % 2; + *(ecc_calc + 2) = *(ecc_calc + 2) / 2; + } + + for (i = 0; i< 6; i++) + ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2]; + + for (i = 0; i < 8; i++) + ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i]; + + for (i = 0; i < 8; i++) + ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i]; + + ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0]; + ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1]; + + for (i = 0; i < 24; i++) + ecc_sum += ecc_bit[i]; + + switch (ecc_sum) { + case 0: + /* Not reached because this function is not called if + ECC values are equal */ + return 0; + case 1: + /* Uncorrectable error */ + DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); + return(-1); + case 12: + /* Correctable error */ + find_byte = (ecc_bit[23] << 8) + + (ecc_bit[21] << 7) + + (ecc_bit[19] << 6) + + (ecc_bit[17] << 5) + + (ecc_bit[15] << 4) + + (ecc_bit[13] << 3) + + (ecc_bit[11] << 2) + + (ecc_bit[9] << 1) + + ecc_bit[7]; + + find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; + + DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", find_byte, find_bit); + + page_data[find_byte] ^= (1 << find_bit); + + return(0); + default: + if (is_ecc_ff) { + if (ecc_calc[0] == 0 && ecc_calc[1] == 0 && ecc_calc[2] == 0) + return(0); + } + DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n"); + return(-1); + } +} + +static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) +{ + struct nand_chip *this; + int block_count = 0, i, rc; + + this = mtd->priv; + block_count = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; + for (i = 0; i < block_count; i++) { + if (memcmp(read_ecc, calc_ecc, 3) != 0) { + rc = nand_davinci_compare_ecc(read_ecc, calc_ecc, dat); + if (rc < 0) { + return(rc); + } + } + read_ecc += 3; + calc_ecc += 3; + dat += 512; + } + return(0); +} +#endif + +static int nand_davinci_dev_ready(struct mtd_info *mtd) +{ + emifregs emif_addr; + + emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + + return(emif_addr->NANDFSR & 0x1); +} + +static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this, int state) +{ + while(!nand_davinci_dev_ready(mtd)) {;} + *NAND_CE0CLE = NAND_STATUS; + return(*NAND_CE0DATA); +} + +static void nand_flash_init(void) +{ + u_int32_t acfg1 = 0x3ffffffc; + u_int32_t acfg2 = 0x3ffffffc; + u_int32_t acfg3 = 0x3ffffffc; + u_int32_t acfg4 = 0x3ffffffc; + emifregs emif_regs; + + /*------------------------------------------------------------------* + * NAND FLASH CHIP TIMEOUT @ 459 MHz * + * * + * AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz * + * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns * + * * + *------------------------------------------------------------------*/ + acfg1 = 0 + | (0 << 31 ) /* selectStrobe */ + | (0 << 30 ) /* extWait */ + | (1 << 26 ) /* writeSetup 10 ns */ + | (3 << 20 ) /* writeStrobe 40 ns */ + | (1 << 17 ) /* writeHold 10 ns */ + | (1 << 13 ) /* readSetup 10 ns */ + | (5 << 7 ) /* readStrobe 60 ns */ + | (1 << 4 ) /* readHold 10 ns */ + | (3 << 2 ) /* turnAround ?? ns */ + | (0 << 0 ) /* asyncSize 8-bit bus */ + ; + + emif_regs = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + + emif_regs->AWCCR |= 0x10000000; + emif_regs->AB1CR = acfg1; /* 0x08244128 */; + emif_regs->AB2CR = acfg2; + emif_regs->AB3CR = acfg3; + emif_regs->AB4CR = acfg4; + emif_regs->NANDFCR = 0x00000101; +} + +int board_nand_init(struct nand_chip *nand) +{ + nand->IO_ADDR_R = (void __iomem *)NAND_CE0DATA; + nand->IO_ADDR_W = (void __iomem *)NAND_CE0DATA; + nand->chip_delay = 0; + nand->select_chip = nand_davinci_select_chip; +#ifdef CFG_NAND_USE_FLASH_BBT + nand->options = NAND_USE_FLASH_BBT; +#endif +#ifdef CFG_NAND_HW_ECC +#ifdef CFG_NAND_LARGEPAGE + nand->eccmode = NAND_ECC_HW12_2048; +#elif defined(CFG_NAND_SMALLPAGE) + nand->eccmode = NAND_ECC_HW3_512; +#else +#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!" +#endif + nand->autooob = &davinci_nand_oobinfo; + nand->calculate_ecc = nand_davinci_calculate_ecc; + nand->correct_data = nand_davinci_correct_data; + nand->enable_hwecc = nand_davinci_enable_hwecc; +#else + nand->eccmode = NAND_ECC_SOFT; +#endif + + /* Set address of hardware control function */ + nand->hwcontrol = nand_davinci_hwcontrol; + + nand->dev_ready = nand_davinci_dev_ready; + nand->waitfunc = nand_davinci_waitfunc; + + nand_flash_init(); + + return(0); +} + +#else +#error "U-Boot legacy NAND support not available for DaVinci chips" +#endif +#endif /* CFG_USE_NAND */ diff --git a/cpu/arm926ejs/davinci/reset.S b/cpu/arm926ejs/davinci/reset.S new file mode 100644 index 0000000..a687d44 --- /dev/null +++ b/cpu/arm926ejs/davinci/reset.S @@ -0,0 +1,77 @@ +/* + * Processor reset using WDT for TI TMS320DM644x SoC. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * ----------------------------------------------------- + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +.globl reset_cpu +reset_cpu: + ldr r0, WDT_TGCR + mov r1, $0x08 + str r1, [r0] + ldr r1, [r0] + orr r1, r1, $0x03 + str r1, [r0] + mov r1, $0 + ldr r0, WDT_TIM12 + str r1, [r0] + ldr r0, WDT_TIM34 + str r1, [r0] + ldr r0, WDT_PRD12 + str r1, [r0] + ldr r0, WDT_PRD34 + str r1, [r0] + ldr r0, WDT_TCR + ldr r1, [r0] + orr r1, r1, $0x40 + str r1, [r0] + ldr r0, WDT_WDTCR + ldr r1, [r0] + orr r1, r1, $0x4000 + str r1, [r0] + ldr r1, WDTCR_VAL1 + str r1, [r0] + ldr r1, WDTCR_VAL2 + str r1, [r0] + nop + nop + nop + nop +reset_cpu_loop: + b reset_cpu_loop + +WDT_TGCR: + .word 0x01c21c24 +WDT_TIM12: + .word 0x01c21c10 +WDT_TIM34: + .word 0x01c21c14 +WDT_PRD12: + .word 0x01c21c18 +WDT_PRD34: + .word 0x01c21c1c +WDT_TCR: + .word 0x01c21c20 +WDT_WDTCR: + .word 0x01c21c28 +WDTCR_VAL1: + .word 0xa5c64000 +WDTCR_VAL2: + .word 0xda7e4000 diff --git a/cpu/arm926ejs/davinci/timer.c b/cpu/arm926ejs/davinci/timer.c new file mode 100644 index 0000000..c6b1dda --- /dev/null +++ b/cpu/arm926ejs/davinci/timer.c @@ -0,0 +1,165 @@ +/* + * (C) Copyright 2003 + * Texas Instruments + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Alex Zuepke + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. + * + * Copyright (C) 2007 Sergey Kubushyn + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +typedef volatile struct { + u_int32_t pid12; + u_int32_t emumgt_clksped; + u_int32_t gpint_en; + u_int32_t gpdir_dat; + u_int32_t tim12; + u_int32_t tim34; + u_int32_t prd12; + u_int32_t prd34; + u_int32_t tcr; + u_int32_t tgcr; + u_int32_t wdtcr; + u_int32_t tlgc; + u_int32_t tlmr; +} davinci_timer; + +davinci_timer *timer = (davinci_timer *)CFG_TIMERBASE; + +#define TIMER_LOAD_VAL (CFG_HZ_CLOCK / CFG_HZ) +#define READ_TIMER timer->tim34 + +static ulong timestamp; +static ulong lastinc; + +int timer_init(void) +{ + /* We are using timer34 in unchained 32-bit mode, full speed */ + timer->tcr = 0x0; + timer->tgcr = 0x0; + timer->tgcr = 0x06; + timer->tim34 = 0x0; + timer->prd34 = TIMER_LOAD_VAL; + lastinc = 0; + timer->tcr = 0x80 << 16; + timestamp = 0; + + return(0); +} + +void reset_timer(void) +{ + reset_timer_masked(); +} + +ulong get_timer(ulong base) +{ + return(get_timer_masked() - base); +} + +void set_timer(ulong t) +{ + timestamp = t; +} + +void udelay(unsigned long usec) +{ + udelay_masked(usec); +} + +void reset_timer_masked(void) +{ + lastinc = READ_TIMER; + timestamp = 0; +} + +ulong get_timer_raw(void) +{ + ulong now = READ_TIMER; + + if (now >= lastinc) { + /* normal mode */ + timestamp += now - lastinc; + } else { + /* overflow ... */ + timestamp += now + TIMER_LOAD_VAL - lastinc; + } + lastinc = now; + return timestamp; +} + +ulong get_timer_masked(void) +{ + return(get_timer_raw() / TIMER_LOAD_VAL); +} + +void udelay_masked(unsigned long usec) +{ + ulong tmo; + ulong endtime; + signed long diff; + + tmo = CFG_HZ_CLOCK / 1000; + tmo *= usec; + tmo /= 1000; + + endtime = get_timer_raw() + tmo; + + do { + ulong now = get_timer_raw(); + diff = endtime - now; + } while (diff >= 0); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return(get_timer(0)); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + ulong tbclk; + + tbclk = CFG_HZ; + return(tbclk); +} diff --git a/include/_exports.h b/include/_exports.h index da6e088..af43885 100644 --- a/include/_exports.h +++ b/include/_exports.h @@ -14,6 +14,9 @@ EXPORT_FUNC(vprintf) EXPORT_FUNC(do_reset) EXPORT_FUNC(getenv) EXPORT_FUNC(setenv) +#ifdef CONFIG_HAS_UID +EXPORT_FUNC(forceenv) +#endif EXPORT_FUNC(simple_strtoul) EXPORT_FUNC(simple_strtol) EXPORT_FUNC(strcmp) diff --git a/include/asm-arm/arch-davinci/emac_defs.h b/include/asm-arm/arch-davinci/emac_defs.h new file mode 100644 index 0000000..0e10116 --- /dev/null +++ b/include/asm-arm/arch-davinci/emac_defs.h @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * Based on: + * + * ---------------------------------------------------------------------------- + * + * dm644x_emac.h + * + * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM + * + * Copyright (C) 2005 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + + * Modifications: + * ver. 1.0: Sep 2005, TI PSP Team - Created EMAC version for uBoot. + * + */ + +#ifndef _DM644X_EMAC_H_ +#define _DM644X_EMAC_H_ + +#include + +#define EMAC_BASE_ADDR (0x01c80000) +#define EMAC_WRAPPER_BASE_ADDR (0x01c81000) +#define EMAC_WRAPPER_RAM_ADDR (0x01c82000) +#define EMAC_MDIO_BASE_ADDR (0x01c84000) + +/* MDIO module input frequency */ +#define EMAC_MDIO_BUS_FREQ 99000000 /* PLL/6 - 99 MHz */ +/* MDIO clock output frequency */ +#define EMAC_MDIO_CLOCK_FREQ 2000000 /* 2.0 MHz */ + +/* Ethernet Min/Max packet size */ +#define EMAC_MIN_ETHERNET_PKT_SIZE 60 +#define EMAC_MAX_ETHERNET_PKT_SIZE 1518 +#define EMAC_PKT_ALIGN 18 /* 1518 + 18 = 1536 (packet aligned on 32 byte boundry) */ + +/* Number of RX packet buffers + * NOTE: Only 1 buffer supported as of now + */ +#define EMAC_MAX_RX_BUFFERS 10 + + +/*********************************************** + ******** Internally used macros *************** + ***********************************************/ + +#define EMAC_CH_TX 1 +#define EMAC_CH_RX 0 + +/* Each descriptor occupies 4 words, lets start RX desc's at 0 and + * reserve space for 64 descriptors max + */ +#define EMAC_RX_DESC_BASE 0x0 +#define EMAC_TX_DESC_BASE 0x1000 + +/* EMAC Teardown value */ +#define EMAC_TEARDOWN_VALUE 0xfffffffc + +/* MII Status Register */ +#define MII_STATUS_REG 1 + +/* Number of statistics registers */ +#define EMAC_NUM_STATS 36 + + +/* EMAC Descriptor */ +typedef volatile struct _emac_desc +{ + u_int32_t next; /* Pointer to next descriptor in chain */ + u_int8_t *buffer; /* Pointer to data buffer */ + u_int32_t buff_off_len; /* Buffer Offset(MSW) and Length(LSW) */ + u_int32_t pkt_flag_len; /* Packet Flags(MSW) and Length(LSW) */ +} emac_desc; + +/* CPPI bit positions */ +#define EMAC_CPPI_SOP_BIT (0x80000000) +#define EMAC_CPPI_EOP_BIT (0x40000000) +#define EMAC_CPPI_OWNERSHIP_BIT (0x20000000) +#define EMAC_CPPI_EOQ_BIT (0x10000000) +#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT (0x08000000) +#define EMAC_CPPI_PASS_CRC_BIT (0x04000000) + +#define EMAC_CPPI_RX_ERROR_FRAME (0x03fc0000) + +#define EMAC_MACCONTROL_MIIEN_ENABLE (0x20) +#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1) + +#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000) +#define EMAC_RXMBPENABLE_RXBROADEN (0x2000) + + +#define MDIO_CONTROL_IDLE (0x80000000) +#define MDIO_CONTROL_ENABLE (0x40000000) +#define MDIO_CONTROL_FAULT_ENABLE (0x40000) +#define MDIO_CONTROL_FAULT (0x80000) +#define MDIO_USERACCESS0_GO (0x80000000) +#define MDIO_USERACCESS0_WRITE_READ (0x0) +#define MDIO_USERACCESS0_WRITE_WRITE (0x40000000) +#define MDIO_USERACCESS0_ACK (0x20000000) + +/* Ethernet MAC Registers Structure */ +typedef struct { + dv_reg TXIDVER; + dv_reg TXCONTROL; + dv_reg TXTEARDOWN; + u_int8_t RSVD0[4]; + dv_reg RXIDVER; + dv_reg RXCONTROL; + dv_reg RXTEARDOWN; + u_int8_t RSVD1[100]; + dv_reg TXINTSTATRAW; + dv_reg TXINTSTATMASKED; + dv_reg TXINTMASKSET; + dv_reg TXINTMASKCLEAR; + dv_reg MACINVECTOR; + u_int8_t RSVD2[12]; + dv_reg RXINTSTATRAW; + dv_reg RXINTSTATMASKED; + dv_reg RXINTMASKSET; + dv_reg RXINTMASKCLEAR; + dv_reg MACINTSTATRAW; + dv_reg MACINTSTATMASKED; + dv_reg MACINTMASKSET; + dv_reg MACINTMASKCLEAR; + u_int8_t RSVD3[64]; + dv_reg RXMBPENABLE; + dv_reg RXUNICASTSET; + dv_reg RXUNICASTCLEAR; + dv_reg RXMAXLEN; + dv_reg RXBUFFEROFFSET; + dv_reg RXFILTERLOWTHRESH; + u_int8_t RSVD4[8]; + dv_reg RX0FLOWTHRESH; + dv_reg RX1FLOWTHRESH; + dv_reg RX2FLOWTHRESH; + dv_reg RX3FLOWTHRESH; + dv_reg RX4FLOWTHRESH; + dv_reg RX5FLOWTHRESH; + dv_reg RX6FLOWTHRESH; + dv_reg RX7FLOWTHRESH; + dv_reg RX0FREEBUFFER; + dv_reg RX1FREEBUFFER; + dv_reg RX2FREEBUFFER; + dv_reg RX3FREEBUFFER; + dv_reg RX4FREEBUFFER; + dv_reg RX5FREEBUFFER; + dv_reg RX6FREEBUFFER; + dv_reg RX7FREEBUFFER; + dv_reg MACCONTROL; + dv_reg MACSTATUS; + dv_reg EMCONTROL; + dv_reg FIFOCONTROL; + dv_reg MACCONFIG; + dv_reg SOFTRESET; + u_int8_t RSVD5[88]; + dv_reg MACSRCADDRLO; + dv_reg MACSRCADDRHI; + dv_reg MACHASH1; + dv_reg MACHASH2; + dv_reg BOFFTEST; + dv_reg TPACETEST; + dv_reg RXPAUSE; + dv_reg TXPAUSE; + u_int8_t RSVD6[16]; + dv_reg RXGOODFRAMES; + dv_reg RXBCASTFRAMES; + dv_reg RXMCASTFRAMES; + dv_reg RXPAUSEFRAMES; + dv_reg RXCRCERRORS; + dv_reg RXALIGNCODEERRORS; + dv_reg RXOVERSIZED; + dv_reg RXJABBER; + dv_reg RXUNDERSIZED; + dv_reg RXFRAGMENTS; + dv_reg RXFILTERED; + dv_reg RXQOSFILTERED; + dv_reg RXOCTETS; + dv_reg TXGOODFRAMES; + dv_reg TXBCASTFRAMES; + dv_reg TXMCASTFRAMES; + dv_reg TXPAUSEFRAMES; + dv_reg TXDEFERRED; + dv_reg TXCOLLISION; + dv_reg TXSINGLECOLL; + dv_reg TXMULTICOLL; + dv_reg TXEXCESSIVECOLL; + dv_reg TXLATECOLL; + dv_reg TXUNDERRUN; + dv_reg TXCARRIERSENSE; + dv_reg TXOCTETS; + dv_reg FRAME64; + dv_reg FRAME65T127; + dv_reg FRAME128T255; + dv_reg FRAME256T511; + dv_reg FRAME512T1023; + dv_reg FRAME1024TUP; + dv_reg NETOCTETS; + dv_reg RXSOFOVERRUNS; + dv_reg RXMOFOVERRUNS; + dv_reg RXDMAOVERRUNS; + u_int8_t RSVD7[624]; + dv_reg MACADDRLO; + dv_reg MACADDRHI; + dv_reg MACINDEX; + u_int8_t RSVD8[244]; + dv_reg TX0HDP; + dv_reg TX1HDP; + dv_reg TX2HDP; + dv_reg TX3HDP; + dv_reg TX4HDP; + dv_reg TX5HDP; + dv_reg TX6HDP; + dv_reg TX7HDP; + dv_reg RX0HDP; + dv_reg RX1HDP; + dv_reg RX2HDP; + dv_reg RX3HDP; + dv_reg RX4HDP; + dv_reg RX5HDP; + dv_reg RX6HDP; + dv_reg RX7HDP; + dv_reg TX0CP; + dv_reg TX1CP; + dv_reg TX2CP; + dv_reg TX3CP; + dv_reg TX4CP; + dv_reg TX5CP; + dv_reg TX6CP; + dv_reg TX7CP; + dv_reg RX0CP; + dv_reg RX1CP; + dv_reg RX2CP; + dv_reg RX3CP; + dv_reg RX4CP; + dv_reg RX5CP; + dv_reg RX6CP; + dv_reg RX7CP; +} emac_regs; + +/* EMAC Wrapper Registers Structure */ +typedef struct { + u_int8_t RSVD0[4100]; + dv_reg EWCTL; + dv_reg EWINTTCNT; +} ewrap_regs; + + +/* EMAC MDIO Registers Structure */ +typedef struct { + dv_reg VERSION; + dv_reg CONTROL; + dv_reg ALIVE; + dv_reg LINK; + dv_reg LINKINTRAW; + dv_reg LINKINTMASKED; + u_int8_t RSVD0[8]; + dv_reg USERINTRAW; + dv_reg USERINTMASKED; + dv_reg USERINTMASKSET; + dv_reg USERINTMASKCLEAR; + u_int8_t RSVD1[80]; + dv_reg USERACCESS0; + dv_reg USERPHYSEL0; + dv_reg USERACCESS1; + dv_reg USERPHYSEL1; +} mdio_regs; + +int dm644x_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data); +int dm644x_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data); + +typedef struct +{ + char name[64]; + int (*init)(int phy_addr); + int (*is_phy_connected)(int phy_addr); + int (*get_link_speed)(int phy_addr); + int (*auto_negotiate)(int phy_addr); +} phy_t; + +#define PHY_LXT972 (0x001378e2) +int lxt972_is_phy_connected(int phy_addr); +int lxt972_get_link_speed(int phy_addr); +int lxt972_init_phy(int phy_addr); +int lxt972_auto_negotiate(int phy_addr); + +#define PHY_DP83848 (0x20005c90) +int dp83848_is_phy_connected(int phy_addr); +int dp83848_get_link_speed(int phy_addr); +int dp83848_init_phy(int phy_addr); +int dp83848_auto_negotiate(int phy_addr); + +#endif /* _DM644X_EMAC_H_ */ diff --git a/include/asm-arm/arch-davinci/emif_defs.h b/include/asm-arm/arch-davinci/emif_defs.h new file mode 100644 index 0000000..646fc77 --- /dev/null +++ b/include/asm-arm/arch-davinci/emif_defs.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _EMIF_DEFS_H_ +#define _EMIF_DEFS_H_ + +#include + +typedef struct { + dv_reg ERCSR; + dv_reg AWCCR; + dv_reg SDBCR; + dv_reg SDRCR; + dv_reg AB1CR; + dv_reg AB2CR; + dv_reg AB3CR; + dv_reg AB4CR; + dv_reg SDTIMR; + dv_reg DDRSR; + dv_reg DDRPHYCR; + dv_reg DDRPHYSR; + dv_reg TOTAR; + dv_reg TOTACTR; + dv_reg DDRPHYID_REV; + dv_reg SDSRETR; + dv_reg EIRR; + dv_reg EIMR; + dv_reg EIMSR; + dv_reg EIMCR; + dv_reg IOCTRLR; + dv_reg IOSTATR; + u_int8_t RSVD0[8]; + dv_reg NANDFCR; + dv_reg NANDFSR; + u_int8_t RSVD1[8]; + dv_reg NANDF1ECC; + dv_reg NANDF2ECC; + dv_reg NANDF3ECC; + dv_reg NANDF4ECC; +} emif_registers; + +typedef emif_registers *emifregs; +#endif diff --git a/include/asm-arm/arch-davinci/hardware.h b/include/asm-arm/arch-davinci/hardware.h new file mode 100644 index 0000000..ebcdcfe --- /dev/null +++ b/include/asm-arm/arch-davinci/hardware.h @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * Based on: + * + * ------------------------------------------------------------------------- + * + * linux/include/asm-arm/arch-davinci/hardware.h + * + * Copyright (C) 2006 Texas Instruments. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#include +#include + +#define REG(addr) (*(volatile unsigned int *)(addr)) +#define REG_P(addr) ((volatile unsigned int *)(addr)) + +typedef volatile unsigned int dv_reg; +typedef volatile unsigned int * dv_reg_p; + +/* + * Base register addresses + */ +#define DAVINCI_DMA_3PCC_BASE (0x01c00000) +#define DAVINCI_DMA_3PTC0_BASE (0x01c10000) +#define DAVINCI_DMA_3PTC1_BASE (0x01c10400) +#define DAVINCI_UART0_BASE (0x01c20000) +#define DAVINCI_UART1_BASE (0x01c20400) +#define DAVINCI_UART2_BASE (0x01c20800) +#define DAVINCI_I2C_BASE (0x01c21000) +#define DAVINCI_TIMER0_BASE (0x01c21400) +#define DAVINCI_TIMER1_BASE (0x01c21800) +#define DAVINCI_WDOG_BASE (0x01c21c00) +#define DAVINCI_PWM0_BASE (0x01c22000) +#define DAVINCI_PWM1_BASE (0x01c22400) +#define DAVINCI_PWM2_BASE (0x01c22800) +#define DAVINCI_SYSTEM_MODULE_BASE (0x01c40000) +#define DAVINCI_PLL_CNTRL0_BASE (0x01c40800) +#define DAVINCI_PLL_CNTRL1_BASE (0x01c40c00) +#define DAVINCI_PWR_SLEEP_CNTRL_BASE (0x01c41000) +#define DAVINCI_SYSTEM_DFT_BASE (0x01c42000) +#define DAVINCI_ARM_INTC_BASE (0x01c48000) +#define DAVINCI_IEEE1394_BASE (0x01c60000) +#define DAVINCI_USB_OTG_BASE (0x01c64000) +#define DAVINCI_CFC_ATA_BASE (0x01c66000) +#define DAVINCI_SPI_BASE (0x01c66800) +#define DAVINCI_GPIO_BASE (0x01c67000) +#define DAVINCI_UHPI_BASE (0x01c67800) +#define DAVINCI_VPSS_REGS_BASE (0x01c70000) +#define DAVINCI_EMAC_CNTRL_REGS_BASE (0x01c80000) +#define DAVINCI_EMAC_WRAPPER_CNTRL_REGS_BASE (0x01c81000) +#define DAVINCI_EMAC_WRAPPER_RAM_BASE (0x01c82000) +#define DAVINCI_MDIO_CNTRL_REGS_BASE (0x01c84000) +#define DAVINCI_IMCOP_BASE (0x01cc0000) +#define DAVINCI_ASYNC_EMIF_CNTRL_BASE (0x01e00000) +#define DAVINCI_VLYNQ_BASE (0x01e01000) +#define DAVINCI_MCBSP_BASE (0x01e02000) +#define DAVINCI_MMC_SD_BASE (0x01e10000) +#define DAVINCI_MS_BASE (0x01e20000) +#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE (0x02000000) +#define DAVINCI_ASYNC_EMIF_DATA_CE1_BASE (0x04000000) +#define DAVINCI_ASYNC_EMIF_DATA_CE2_BASE (0x06000000) +#define DAVINCI_ASYNC_EMIF_DATA_CE3_BASE (0x08000000) +#define DAVINCI_VLYNQ_REMOTE_BASE (0x0c000000) + +/* Power and Sleep Controller (PSC) Domains */ +#define DAVINCI_GPSC_ARMDOMAIN 0 +#define DAVINCI_GPSC_DSPDOMAIN 1 + +#define DAVINCI_LPSC_VPSSMSTR 0 +#define DAVINCI_LPSC_VPSSSLV 1 +#define DAVINCI_LPSC_TPCC 2 +#define DAVINCI_LPSC_TPTC0 3 +#define DAVINCI_LPSC_TPTC1 4 +#define DAVINCI_LPSC_EMAC 5 +#define DAVINCI_LPSC_EMAC_WRAPPER 6 +#define DAVINCI_LPSC_MDIO 7 +#define DAVINCI_LPSC_IEEE1394 8 +#define DAVINCI_LPSC_USB 9 +#define DAVINCI_LPSC_ATA 10 +#define DAVINCI_LPSC_VLYNQ 11 +#define DAVINCI_LPSC_UHPI 12 +#define DAVINCI_LPSC_DDR_EMIF 13 +#define DAVINCI_LPSC_AEMIF 14 +#define DAVINCI_LPSC_MMC_SD 15 +#define DAVINCI_LPSC_MEMSTICK 16 +#define DAVINCI_LPSC_McBSP 17 +#define DAVINCI_LPSC_I2C 18 +#define DAVINCI_LPSC_UART0 19 +#define DAVINCI_LPSC_UART1 20 +#define DAVINCI_LPSC_UART2 21 +#define DAVINCI_LPSC_SPI 22 +#define DAVINCI_LPSC_PWM0 23 +#define DAVINCI_LPSC_PWM1 24 +#define DAVINCI_LPSC_PWM2 25 +#define DAVINCI_LPSC_GPIO 26 +#define DAVINCI_LPSC_TIMER0 27 +#define DAVINCI_LPSC_TIMER1 28 +#define DAVINCI_LPSC_TIMER2 29 +#define DAVINCI_LPSC_SYSTEM_SUBSYS 30 +#define DAVINCI_LPSC_ARM 31 +#define DAVINCI_LPSC_SCR2 32 +#define DAVINCI_LPSC_SCR3 33 +#define DAVINCI_LPSC_SCR4 34 +#define DAVINCI_LPSC_CROSSBAR 35 +#define DAVINCI_LPSC_CFG27 36 +#define DAVINCI_LPSC_CFG3 37 +#define DAVINCI_LPSC_CFG5 38 +#define DAVINCI_LPSC_GEM 39 +#define DAVINCI_LPSC_IMCOP 40 + +/* Some PSC defines */ +#define PSC_CHP_SHRTSW (0x01c40038) +#define PSC_GBLCTL (0x01c41010) +#define PSC_EPCPR (0x01c41070) +#define PSC_EPCCR (0x01c41078) +#define PSC_PTCMD (0x01c41120) +#define PSC_PTSTAT (0x01c41128) +#define PSC_PDSTAT (0x01c41200) +#define PSC_PDSTAT1 (0x01c41204) +#define PSC_PDCTL (0x01c41300) +#define PSC_PDCTL1 (0x01c41304) + +#define PSC_MDCTL_BASE (0x01c41a00) +#define PSC_MDSTAT_BASE (0x01c41800) + +#define VDD3P3V_PWDN (0x01c40048) +#define UART0_PWREMU_MGMT (0x01c20030) + +#define PSC_SILVER_BULLET (0x01c41a20) + +/* Some PLL defines */ +#define PLL1_PLLM (0x01c40910) +#define PLL2_PLLM (0x01c40d10) +#define PLL2_DIV2 (0x01c40d1c) + +/* Miscellania... */ +#define VBPR (0x20000020) +#define PINMUX0 (0x01c40000) +#define PINMUX1 (0x01c40004) + +#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/include/asm-arm/arch-davinci/i2c_defs.h b/include/asm-arm/arch-davinci/i2c_defs.h new file mode 100644 index 0000000..2e902e1 --- /dev/null +++ b/include/asm-arm/arch-davinci/i2c_defs.h @@ -0,0 +1,94 @@ +/* + * (C) Copyright 2004 + * Texas Instruments, + * + * Some changes copyright (C) 2007 Sergey Kubushyn + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _DAVINCI_I2C_H_ +#define _DAVINCI_I2C_H_ + +#define I2C_WRITE 0 +#define I2C_READ 1 + +#define I2C_BASE 0x01c21000 + +#define I2C_OA (I2C_BASE + 0x00) +#define I2C_IE (I2C_BASE + 0x04) +#define I2C_STAT (I2C_BASE + 0x08) +#define I2C_SCLL (I2C_BASE + 0x0c) +#define I2C_SCLH (I2C_BASE + 0x10) +#define I2C_CNT (I2C_BASE + 0x14) +#define I2C_DRR (I2C_BASE + 0x18) +#define I2C_SA (I2C_BASE + 0x1c) +#define I2C_DXR (I2C_BASE + 0x20) +#define I2C_CON (I2C_BASE + 0x24) +#define I2C_IV (I2C_BASE + 0x28) +#define I2C_PSC (I2C_BASE + 0x30) + +/* I2C masks */ + +/* I2C Interrupt Enable Register (I2C_IE): */ +#define I2C_IE_SCD_IE (1 << 5) /* Stop condition detect interrupt enable */ +#define I2C_IE_XRDY_IE (1 << 4) /* Transmit data ready interrupt enable */ +#define I2C_IE_RRDY_IE (1 << 3) /* Receive data ready interrupt enable */ +#define I2C_IE_ARDY_IE (1 << 2) /* Register access ready interrupt enable */ +#define I2C_IE_NACK_IE (1 << 1) /* No acknowledgment interrupt enable */ +#define I2C_IE_AL_IE (1 << 0) /* Arbitration lost interrupt enable */ + +/* I2C Status Register (I2C_STAT): */ + +#define I2C_STAT_BB (1 << 12) /* Bus busy */ +#define I2C_STAT_ROVR (1 << 11) /* Receive overrun */ +#define I2C_STAT_XUDF (1 << 10) /* Transmit underflow */ +#define I2C_STAT_AAS (1 << 9) /* Address as slave */ +#define I2C_STAT_SCD (1 << 5) /* Stop condition detect */ +#define I2C_STAT_XRDY (1 << 4) /* Transmit data ready */ +#define I2C_STAT_RRDY (1 << 3) /* Receive data ready */ +#define I2C_STAT_ARDY (1 << 2) /* Register access ready */ +#define I2C_STAT_NACK (1 << 1) /* No acknowledgment interrupt enable */ +#define I2C_STAT_AL (1 << 0) /* Arbitration lost interrupt enable */ + + +/* I2C Interrupt Code Register (I2C_INTCODE): */ + +#define I2C_INTCODE_MASK 7 +#define I2C_INTCODE_NONE 0 +#define I2C_INTCODE_AL 1 /* Arbitration lost */ +#define I2C_INTCODE_NAK 2 /* No acknowledgement/general call */ +#define I2C_INTCODE_ARDY 3 /* Register access ready */ +#define I2C_INTCODE_RRDY 4 /* Rcv data ready */ +#define I2C_INTCODE_XRDY 5 /* Xmit data ready */ +#define I2C_INTCODE_SCD 6 /* Stop condition detect */ + + +/* I2C Configuration Register (I2C_CON): */ + +#define I2C_CON_EN (1 << 5) /* I2C module enable */ +#define I2C_CON_STB (1 << 4) /* Start byte mode (master mode only) */ +#define I2C_CON_MST (1 << 10) /* Master/slave mode */ +#define I2C_CON_TRX (1 << 9) /* Transmitter/receiver mode (master mode only) */ +#define I2C_CON_XA (1 << 8) /* Expand address */ +#define I2C_CON_STP (1 << 11) /* Stop condition (master mode only) */ +#define I2C_CON_STT (1 << 13) /* Start condition (master mode only) */ + +#define I2C_TIMEOUT 0xffff0000 /* Timeout mask for poll_i2c_irq() */ + +#endif diff --git a/include/asm-arm/arch-davinci/nand_defs.h b/include/asm-arm/arch-davinci/nand_defs.h new file mode 100644 index 0000000..619bd47 --- /dev/null +++ b/include/asm-arm/arch-davinci/nand_defs.h @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * Parts shamelesly stolen from Linux Kernel source tree. + * + * ------------------------------------------------------------ + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#ifndef _NAND_DEFS_H_ +#define _NAND_DEFS_H_ + +#include + +#define MASK_CLE 0x10 +#define MASK_ALE 0x0a + +#define NAND_CE0CLE ((volatile u_int8_t *)(CFG_NAND_BASE + 0x10)) +#define NAND_CE0ALE ((volatile u_int8_t *)(CFG_NAND_BASE + 0x0a)) +#define NAND_CE0DATA ((volatile u_int8_t *)CFG_NAND_BASE) + +typedef struct { + u_int32_t NRCSR; + u_int32_t AWCCR; + u_int8_t RSVD0[8]; + u_int32_t AB1CR; + u_int32_t AB2CR; + u_int32_t AB3CR; + u_int32_t AB4CR; + u_int8_t RSVD1[32]; + u_int32_t NIRR; + u_int32_t NIMR; + u_int32_t NIMSR; + u_int32_t NIMCR; + u_int8_t RSVD2[16]; + u_int32_t NANDFCR; + u_int32_t NANDFSR; + u_int8_t RSVD3[8]; + u_int32_t NANDF1ECC; + u_int32_t NANDF2ECC; + u_int32_t NANDF3ECC; + u_int32_t NANDF4ECC; + u_int8_t RSVD4[4]; + u_int32_t IODFTECR; + u_int32_t IODFTGCR; + u_int8_t RSVD5[4]; + u_int32_t IODFTMRLR; + u_int32_t IODFTMRMR; + u_int32_t IODFTMRMSBR; + u_int8_t RSVD6[20]; + u_int32_t MODRNR; + u_int8_t RSVD7[76]; + u_int32_t CE0DATA; + u_int32_t CE0ALE; + u_int32_t CE0CLE; + u_int8_t RSVD8[4]; + u_int32_t CE1DATA; + u_int32_t CE1ALE; + u_int32_t CE1CLE; + u_int8_t RSVD9[4]; + u_int32_t CE2DATA; + u_int32_t CE2ALE; + u_int32_t CE2CLE; + u_int8_t RSVD10[4]; + u_int32_t CE3DATA; + u_int32_t CE3ALE; + u_int32_t CE3CLE; +} nand_registers; + +typedef volatile nand_registers *nandregs; + +#define NAND_READ_START 0x00 +#define NAND_READ_END 0x30 +#define NAND_STATUS 0x70 + +#ifdef CFG_NAND_HW_ECC +#define NAND_Ecc_P1e (1 << 0) +#define NAND_Ecc_P2e (1 << 1) +#define NAND_Ecc_P4e (1 << 2) +#define NAND_Ecc_P8e (1 << 3) +#define NAND_Ecc_P16e (1 << 4) +#define NAND_Ecc_P32e (1 << 5) +#define NAND_Ecc_P64e (1 << 6) +#define NAND_Ecc_P128e (1 << 7) +#define NAND_Ecc_P256e (1 << 8) +#define NAND_Ecc_P512e (1 << 9) +#define NAND_Ecc_P1024e (1 << 10) +#define NAND_Ecc_P2048e (1 << 11) + +#define NAND_Ecc_P1o (1 << 16) +#define NAND_Ecc_P2o (1 << 17) +#define NAND_Ecc_P4o (1 << 18) +#define NAND_Ecc_P8o (1 << 19) +#define NAND_Ecc_P16o (1 << 20) +#define NAND_Ecc_P32o (1 << 21) +#define NAND_Ecc_P64o (1 << 22) +#define NAND_Ecc_P128o (1 << 23) +#define NAND_Ecc_P256o (1 << 24) +#define NAND_Ecc_P512o (1 << 25) +#define NAND_Ecc_P1024o (1 << 26) +#define NAND_Ecc_P2048o (1 << 27) + +#define TF(v) (v ? 1 : 0) + +#define P2048e(a) (TF(a & NAND_Ecc_P2048e) << 0) +#define P2048o(a) (TF(a & NAND_Ecc_P2048o) << 1) +#define P1e(a) (TF(a & NAND_Ecc_P1e) << 2) +#define P1o(a) (TF(a & NAND_Ecc_P1o) << 3) +#define P2e(a) (TF(a & NAND_Ecc_P2e) << 4) +#define P2o(a) (TF(a & NAND_Ecc_P2o) << 5) +#define P4e(a) (TF(a & NAND_Ecc_P4e) << 6) +#define P4o(a) (TF(a & NAND_Ecc_P4o) << 7) + +#define P8e(a) (TF(a & NAND_Ecc_P8e) << 0) +#define P8o(a) (TF(a & NAND_Ecc_P8o) << 1) +#define P16e(a) (TF(a & NAND_Ecc_P16e) << 2) +#define P16o(a) (TF(a & NAND_Ecc_P16o) << 3) +#define P32e(a) (TF(a & NAND_Ecc_P32e) << 4) +#define P32o(a) (TF(a & NAND_Ecc_P32o) << 5) +#define P64e(a) (TF(a & NAND_Ecc_P64e) << 6) +#define P64o(a) (TF(a & NAND_Ecc_P64o) << 7) + +#define P128e(a) (TF(a & NAND_Ecc_P128e) << 0) +#define P128o(a) (TF(a & NAND_Ecc_P128o) << 1) +#define P256e(a) (TF(a & NAND_Ecc_P256e) << 2) +#define P256o(a) (TF(a & NAND_Ecc_P256o) << 3) +#define P512e(a) (TF(a & NAND_Ecc_P512e) << 4) +#define P512o(a) (TF(a & NAND_Ecc_P512o) << 5) +#define P1024e(a) (TF(a & NAND_Ecc_P1024e) << 6) +#define P1024o(a) (TF(a & NAND_Ecc_P1024o) << 7) + +#define P8e_s(a) (TF(a & NAND_Ecc_P8e) << 0) +#define P8o_s(a) (TF(a & NAND_Ecc_P8o) << 1) +#define P16e_s(a) (TF(a & NAND_Ecc_P16e) << 2) +#define P16o_s(a) (TF(a & NAND_Ecc_P16o) << 3) +#define P1e_s(a) (TF(a & NAND_Ecc_P1e) << 4) +#define P1o_s(a) (TF(a & NAND_Ecc_P1o) << 5) +#define P2e_s(a) (TF(a & NAND_Ecc_P2e) << 6) +#define P2o_s(a) (TF(a & NAND_Ecc_P2o) << 7) + +#define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) +#define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) +#endif + +#endif diff --git a/include/common.h b/include/common.h index ac29d3a..229e64b 100644 --- a/include/common.h +++ b/include/common.h @@ -241,6 +241,9 @@ int saveenv (void); void inline setenv (char *, char *); #else void setenv (char *, char *); +#ifdef CONFIG_HAS_UID +void forceenv (char *, char *); +#endif #endif /* CONFIG_PPC */ #ifdef CONFIG_ARM # include diff --git a/include/configs/davinci_dvevm.h b/include/configs/davinci_dvevm.h new file mode 100644 index 0000000..8ecd059 --- /dev/null +++ b/include/configs/davinci_dvevm.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H +#include + +/* + * Define this to make U-Boot skip low level initialization when loaded + * by initial bootloader. Not required by NAND U-Boot version but IS + * required for a NOR version used to burn the real NOR U-Boot into + * NOR Flash. NAND and NOR support for DaVinci chips is mutually exclusive + * so it is NOT possible to build a U-Boot with both NAND and NOR routines. + * NOR U-Boot is loaded directly from Flash so it must perform all the + * low level initialization itself. NAND version is loaded by an initial + * bootloader (UBL in TI-ese) that performs such an initialization so it's + * skipped in NAND version. The third DaVinci boot mode loads a bootloader + * via UART0 and that bootloader in turn loads and runs U-Boot (or whatever) + * performing low level init prior to loading. All that means we can NOT use + * NAND version to put U-Boot into NOR because it doesn't have NOR support and + * we can NOT use NOR version because it performs low level initialization + * effectively destroying itself in DDR memory. That's why a separate NOR + * version with this define is needed. It is loaded via UART, then one uses + * it to somehow download a proper NOR version built WITHOUT this define to + * RAM (tftp?) and burn it to NOR Flash. I would be probably able to squeeze + * NOR support into the initial bootloader so it won't be needed but DaVinci + * static RAM might be too small for this (I have something like 2Kbytes left + * as of now, without NOR support) so this might've not happened... + * +#define CONFIG_NOR_UART_BOOT + */ + +/*=======*/ +/* Board */ +/*=======*/ +#define DV_EVM +#define CFG_NAND_SMALLPAGE +#define CFG_USE_NOR +/*===================*/ +/* SoC Configuration */ +/*===================*/ +#define CONFIG_ARM926EJS /* arm926ejs CPU core */ +#define CONFIG_SYS_CLK_FREQ 297000000 /* Arm Clock frequency */ +#define CFG_TIMERBASE 0x01c21400 /* use timer 0 */ +#define CFG_HZ_CLOCK 27000000 /* Timer Input clock freq */ +#define CFG_HZ 1000 +/*====================================================*/ +/* EEPROM definitions for Atmel 24C256BN SEEPROM chip */ +/* on Sonata/DV_EVM board. No EEPROM on schmoogie. */ +/*====================================================*/ +#define CFG_I2C_EEPROM_ADDR_LEN 2 +#define CFG_I2C_EEPROM_ADDR 0x50 +#define CFG_EEPROM_PAGE_WRITE_BITS 6 +#define CFG_EEPROM_PAGE_WRITE_DELAY_MS 20 +/*=============*/ +/* Memory Info */ +/*=============*/ +#define CFG_MALLOC_LEN (0x10000 + 128*1024) /* malloc() len */ +#define CFG_GBL_DATA_SIZE 128 /* reserved for initial data */ +#define CFG_MEMTEST_START 0x80000000 /* memtest start address */ +#define CFG_MEMTEST_END 0x81000000 /* 16MB RAM test */ +#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ +#define CONFIG_STACKSIZE (256*1024) /* regular stack */ +#define PHYS_SDRAM_1 0x80000000 /* DDR Start */ +#define PHYS_SDRAM_1_SIZE 0x10000000 /* DDR size 256MB */ +#define DDR_8BANKS /* 8-bank DDR2 (256MB) */ +/*====================*/ +/* Serial Driver info */ +/*====================*/ +#define CFG_NS16550 +#define CFG_NS16550_SERIAL +#define CFG_NS16550_REG_SIZE 4 /* NS16550 register size */ +#define CFG_NS16550_COM1 0x01c20000 /* Base address of UART0 */ +#define CFG_NS16550_CLK 27000000 /* Input clock to NS16550 */ +#define CONFIG_CONS_INDEX 1 /* use UART0 for console */ +#define CONFIG_BAUDRATE 115200 /* Default baud rate */ +#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } +/*===================*/ +/* I2C Configuration */ +/*===================*/ +#define CONFIG_HARD_I2C +#define CONFIG_DRIVER_DAVINCI_I2C +#define CFG_I2C_SPEED 80000 /* 100Kbps won't work, silicon bug */ +#define CFG_I2C_SLAVE 10 /* Bogus, master-only in U-Boot */ +/*==================================*/ +/* Network & Ethernet Configuration */ +/*==================================*/ +#define CONFIG_DRIVER_TI_EMAC +#define CONFIG_MII +#define CONFIG_BOOTP_DEFAULT +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_NET_RETRY_COUNT 10 +/*=====================*/ +/* Flash & Environment */ +/*=====================*/ +#ifdef CFG_USE_NAND +#undef CFG_ENV_IS_IN_FLASH +#define CFG_NO_FLASH +#define CFG_ENV_IS_IN_NAND /* U-Boot env in NAND Flash */ +#ifdef CFG_NAND_SMALLPAGE +#define CFG_ENV_SECT_SIZE 512 /* Env sector Size */ +#define CFG_ENV_SIZE SZ_16K +#else +#define CFG_ENV_SECT_SIZE 2048 /* Env sector Size */ +#define CFG_ENV_SIZE SZ_128K +#endif +#define CONFIG_SKIP_LOWLEVEL_INIT /* U-Boot is loaded by a bootloader */ +#define CONFIG_SKIP_RELOCATE_UBOOT /* to a proper address, init done */ +#define CFG_NAND_BASE 0x02000000 +#define CFG_NAND_HW_ECC +#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */ +#define NAND_MAX_CHIPS 1 +#define CFG_ENV_OFFSET 0x0 /* Block 0--not used by bootcode */ +#define DEF_BOOTM "" +#elif defined(CFG_USE_NOR) +#ifdef CONFIG_NOR_UART_BOOT +#define CONFIG_SKIP_LOWLEVEL_INIT /* U-Boot is loaded by a bootloader */ +#define CONFIG_SKIP_RELOCATE_UBOOT /* to a proper address, init done */ +#else +#undef CONFIG_SKIP_LOWLEVEL_INIT +#undef CONFIG_SKIP_RELOCATE_UBOOT +#endif +#define CFG_ENV_IS_IN_FLASH +#undef CFG_NO_FLASH +#define CFG_FLASH_CFI_DRIVER +#define CFG_FLASH_CFI +#define CFG_MAX_FLASH_BANKS 1 /* max number of flash banks */ +#define CFG_FLASH_SECT_SZ 0x10000 /* 64KB sect size AMD Flash */ +#define CFG_ENV_OFFSET (CFG_FLASH_SECT_SZ*3) +#define PHYS_FLASH_1 0x02000000 /* CS2 Base address */ +#define CFG_FLASH_BASE PHYS_FLASH_1 /* Flash Base for U-Boot */ +#define PHYS_FLASH_SIZE 0x2000000 /* Flash size 32MB */ +#define CFG_MAX_FLASH_SECT (PHYS_FLASH_SIZE/CFG_FLASH_SECT_SZ) +#define CFG_ENV_SECT_SIZE CFG_FLASH_SECT_SZ /* Env sector Size */ +#endif +/*==============================*/ +/* U-Boot general configuration */ +/*==============================*/ +#undef CONFIG_USE_IRQ /* No IRQ/FIQ in U-Boot */ +#define CONFIG_MISC_INIT_R +#undef CONFIG_BOOTDELAY +#define CONFIG_BOOTFILE "uImage" /* Boot file name */ +#define CFG_PROMPT "U-Boot > " /* Monitor Command Prompt */ +#define CFG_CBSIZE 1024 /* Console I/O Buffer Size */ +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print buffer sz */ +#define CFG_MAXARGS 16 /* max number of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ +#define CFG_LOAD_ADDR 0x80700000 /* default Linux kernel load address */ +#define CONFIG_VERSION_VARIABLE +#define CONFIG_AUTO_COMPLETE /* Won't work with hush so far, may be later */ +#define CFG_HUSH_PARSER +#define CFG_PROMPT_HUSH_PS2 "> " +#define CONFIG_CMDLINE_EDITING +#define CFG_LONGHELP +#define CONFIG_CRC32_VERIFY +#define CONFIG_MX_CYCLIC +/*===================*/ +/* Linux Information */ +/*===================*/ +#define LINUX_BOOT_PARAM_ADDR 0x80000100 +#define CONFIG_CMDLINE_TAG +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_BOOTARGS "mem=120M console=ttyS0,115200n8 root=/dev/hda1 rw noinitrd ip=dhcp" +#define CONFIG_BOOTCOMMAND "setenv setboot setenv bootargs \\$(bootargs) video=dm64xxfb:output=\\$(videostd);run setboot; bootm 0x2050000" +/*=================*/ +/* U-Boot commands */ +/*=================*/ +#include +#define CONFIG_CMD_ASKENV +#define CONFIG_CMD_DHCP +#define CONFIG_CMD_DIAG +#define CONFIG_CMD_I2C +#define CONFIG_CMD_MII +#define CONFIG_CMD_PING +#define CONFIG_CMD_SAVES +#define CONFIG_CMD_EEPROM +#undef CONFIG_CMD_BDI +#undef CONFIG_CMD_FPGA +#undef CONFIG_CMD_SETGETDCR +#ifdef CFG_USE_NAND +#undef CONFIG_CMD_FLASH +#undef CONFIG_CMD_IMLS +#define CONFIG_CMD_NAND +#elif defined(CFG_USE_NOR) +#define CONFIG_CMD_JFFS2 +#else +#error "Either CFG_USE_NAND or CFG_USE_NOR _MUST_ be defined !!!" +#endif +/*=======================*/ +/* KGDB support (if any) */ +/*=======================*/ +#ifdef CONFIG_CMD_KGDB +#define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ +#define CONFIG_KGDB_SER_INDEX 1 /* which serial port to use */ +#endif +#endif /* __CONFIG_H */ diff --git a/include/configs/davinci_schmoogie.h b/include/configs/davinci_schmoogie.h new file mode 100644 index 0000000..96c9a30 --- /dev/null +++ b/include/configs/davinci_schmoogie.h @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H +#include + +/*=======*/ +/* Board */ +/*=======*/ +#define SCHMOOGIE +#define CFG_NAND_LARGEPAGE +#define CFG_USE_NAND +/*===================*/ +/* SoC Configuration */ +/*===================*/ +#define CONFIG_ARM926EJS /* arm926ejs CPU core */ +#define CONFIG_SYS_CLK_FREQ 297000000 /* Arm Clock frequency */ +#define CFG_TIMERBASE 0x01c21400 /* use timer 0 */ +#define CFG_HZ_CLOCK 27000000 /* Timer Input clock freq */ +#define CFG_HZ 1000 +/*=============*/ +/* Memory Info */ +/*=============*/ +#define CFG_MALLOC_LEN (0x10000 + 256*1024) /* malloc() len */ +#define CFG_GBL_DATA_SIZE 128 /* reserved for initial data */ +#define CFG_MEMTEST_START 0x80000000 /* memtest start address */ +#define CFG_MEMTEST_END 0x81000000 /* 16MB RAM test */ +#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ +#define CONFIG_STACKSIZE (256*1024) /* regular stack */ +#define PHYS_SDRAM_1 0x80000000 /* DDR Start */ +#define PHYS_SDRAM_1_SIZE 0x08000000 /* DDR size 128MB */ +#define DDR_4BANKS /* 4-bank DDR2 (128MB) */ +/*====================*/ +/* Serial Driver info */ +/*====================*/ +#define CFG_NS16550 +#define CFG_NS16550_SERIAL +#define CFG_NS16550_REG_SIZE 4 /* NS16550 register size */ +#define CFG_NS16550_COM1 0x01c20000 /* Base address of UART0 */ +#define CFG_NS16550_CLK 27000000 /* Input clock to NS16550 */ +#define CONFIG_CONS_INDEX 1 /* use UART0 for console */ +#define CONFIG_BAUDRATE 115200 /* Default baud rate */ +#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } +/*===================*/ +/* I2C Configuration */ +/*===================*/ +#define CONFIG_HARD_I2C +#define CONFIG_DRIVER_DAVINCI_I2C +#define CFG_I2C_SPEED 80000 /* 100Kbps won't work, silicon bug */ +#define CFG_I2C_SLAVE 10 /* Bogus, master-only in U-Boot */ +/*==================================*/ +/* Network & Ethernet Configuration */ +/*==================================*/ +#define CONFIG_DRIVER_TI_EMAC +#define CONFIG_MII +#define CONFIG_BOOTP_DEFAULT +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_NET_RETRY_COUNT 10 +#define CONFIG_OVERWRITE_ETHADDR_ONCE +/*=====================*/ +/* Flash & Environment */ +/*=====================*/ +#undef CFG_ENV_IS_IN_FLASH +#define CFG_NO_FLASH +#define CFG_ENV_IS_IN_NAND /* U-Boot env in NAND Flash */ +#define CFG_ENV_SECT_SIZE 2048 /* Env sector Size */ +#define CFG_ENV_SIZE SZ_128K +#define CONFIG_SKIP_LOWLEVEL_INIT /* U-Boot is loaded by a bootloader */ +#define CONFIG_SKIP_RELOCATE_UBOOT /* to a proper address, init done */ +#define CFG_NAND_BASE 0x02000000 +#define CFG_NAND_HW_ECC +#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */ +#define NAND_MAX_CHIPS 1 +#define CFG_ENV_OFFSET 0x0 /* Block 0--not used by bootcode */ +/*=====================*/ +/* Board related stuff */ +/*=====================*/ +#define CONFIG_RTC_DS1307 /* RTC chip on SCHMOOGIE */ +#define CFG_I2C_RTC_ADDR 0x6f /* RTC chip I2C address */ +#define CONFIG_HAS_UID +#define CONFIG_UID_DS28CM00 /* Unique ID on SCHMOOGIE */ +#define CFG_UID_ADDR 0x50 /* UID chip I2C address */ +/*==============================*/ +/* U-Boot general configuration */ +/*==============================*/ +#undef CONFIG_USE_IRQ /* No IRQ/FIQ in U-Boot */ +#define CONFIG_MISC_INIT_R +#undef CONFIG_BOOTDELAY +#define CONFIG_BOOTFILE "uImage" /* Boot file name */ +#define CFG_PROMPT "U-Boot > " /* Monitor Command Prompt */ +#define CFG_CBSIZE 1024 /* Console I/O Buffer Size */ +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print buffer sz */ +#define CFG_MAXARGS 16 /* max number of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ +#define CFG_LOAD_ADDR 0x80700000 /* default Linux kernel load address */ +#define CONFIG_VERSION_VARIABLE +#define CONFIG_AUTO_COMPLETE /* Won't work with hush so far, may be later */ +#define CFG_HUSH_PARSER +#define CFG_PROMPT_HUSH_PS2 "> " +#define CONFIG_CMDLINE_EDITING +#define CFG_LONGHELP +#define CONFIG_CRC32_VERIFY +#define CONFIG_MX_CYCLIC +/*===================*/ +/* Linux Information */ +/*===================*/ +#define LINUX_BOOT_PARAM_ADDR 0x80000100 +#define CONFIG_CMDLINE_TAG +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_BOOTARGS "mem=56M console=ttyS0,115200n8 root=/dev/hda1 rw noinitrd ip=dhcp" +#define CONFIG_BOOTCOMMAND "setenv setboot setenv bootargs \\$(bootargs) video=dm64xxfb:output=\\$(videostd);run setboot" +/*=================*/ +/* U-Boot commands */ +/*=================*/ +#include +#define CONFIG_CMD_ASKENV +#define CONFIG_CMD_DHCP +#define CONFIG_CMD_DIAG +#define CONFIG_CMD_I2C +#define CONFIG_CMD_MII +#define CONFIG_CMD_PING +#define CONFIG_CMD_SAVES +#define CONFIG_CMD_DATE +#define CONFIG_CMD_NAND +#undef CONFIG_CMD_EEPROM +#undef CONFIG_CMD_BDI +#undef CONFIG_CMD_FPGA +#undef CONFIG_CMD_SETGETDCR +#undef CONFIG_CMD_FLASH +#undef CONFIG_CMD_IMLS +/*=======================*/ +/* KGDB support (if any) */ +/*=======================*/ +#ifdef CONFIG_CMD_KGDB +#define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ +#define CONFIG_KGDB_SER_INDEX 1 /* which serial port to use */ +#endif +#endif /* __CONFIG_H */ diff --git a/include/configs/davinci_sonata.h b/include/configs/davinci_sonata.h new file mode 100644 index 0000000..de8c4fa --- /dev/null +++ b/include/configs/davinci_sonata.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2007 Sergey Kubushyn + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H +#include + +/* + * Define this to make U-Boot skip low level initialization when loaded + * by initial bootloader. Not required by NAND U-Boot version but IS + * required for a NOR version used to burn the real NOR U-Boot into + * NOR Flash. NAND and NOR support for DaVinci chips is mutually exclusive + * so it is NOT possible to build a U-Boot with both NAND and NOR routines. + * NOR U-Boot is loaded directly from Flash so it must perform all the + * low level initialization itself. NAND version is loaded by an initial + * bootloader (UBL in TI-ese) that performs such an initialization so it's + * skipped in NAND version. The third DaVinci boot mode loads a bootloader + * via UART0 and that bootloader in turn loads and runs U-Boot (or whatever) + * performing low level init prior to loading. All that means we can NOT use + * NAND version to put U-Boot into NOR because it doesn't have NOR support and + * we can NOT use NOR version because it performs low level initialization + * effectively destroying itself in DDR memory. That's why a separate NOR + * version with this define is needed. It is loaded via UART, then one uses + * it to somehow download a proper NOR version built WITHOUT this define to + * RAM (tftp?) and burn it to NOR Flash. I would be probably able to squeeze + * NOR support into the initial bootloader so it won't be needed but DaVinci + * static RAM might be too small for this (I have something like 2Kbytes left + * as of now, without NOR support) so this might've not happened... + * +#define CONFIG_NOR_UART_BOOT + */ + +/*=======*/ +/* Board */ +/*=======*/ +#define SONATA_BOARD +#define CFG_NAND_SMALLPAGE +#define CFG_USE_NOR +/*===================*/ +/* SoC Configuration */ +/*===================*/ +#define CONFIG_ARM926EJS /* arm926ejs CPU core */ +#define CONFIG_SYS_CLK_FREQ 297000000 /* Arm Clock frequency */ +#define CFG_TIMERBASE 0x01c21400 /* use timer 0 */ +#define CFG_HZ_CLOCK 27000000 /* Timer Input clock freq */ +#define CFG_HZ 1000 +/*====================================================*/ +/* EEPROM definitions for Atmel 24C256BN SEEPROM chip */ +/* on Sonata/DV_EVM board. No EEPROM on schmoogie. */ +/*====================================================*/ +#define CFG_I2C_EEPROM_ADDR_LEN 2 +#define CFG_I2C_EEPROM_ADDR 0x50 +#define CFG_EEPROM_PAGE_WRITE_BITS 6 +#define CFG_EEPROM_PAGE_WRITE_DELAY_MS 20 +/*=============*/ +/* Memory Info */ +/*=============*/ +#define CFG_MALLOC_LEN (0x10000 + 128*1024) /* malloc() len */ +#define CFG_GBL_DATA_SIZE 128 /* reserved for initial data */ +#define CFG_MEMTEST_START 0x80000000 /* memtest start address */ +#define CFG_MEMTEST_END 0x81000000 /* 16MB RAM test */ +#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ +#define CONFIG_STACKSIZE (256*1024) /* regular stack */ +#define PHYS_SDRAM_1 0x80000000 /* DDR Start */ +#define PHYS_SDRAM_1_SIZE 0x08000000 /* DDR size 128MB */ +#define DDR_4BANKS /* 4-bank DDR2 (128MB) */ +/*====================*/ +/* Serial Driver info */ +/*====================*/ +#define CFG_NS16550 +#define CFG_NS16550_SERIAL +#define CFG_NS16550_REG_SIZE 4 /* NS16550 register size */ +#define CFG_NS16550_COM1 0x01c20000 /* Base address of UART0 */ +#define CFG_NS16550_CLK 27000000 /* Input clock to NS16550 */ +#define CONFIG_CONS_INDEX 1 /* use UART0 for console */ +#define CONFIG_BAUDRATE 115200 /* Default baud rate */ +#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } +/*===================*/ +/* I2C Configuration */ +/*===================*/ +#define CONFIG_HARD_I2C +#define CONFIG_DRIVER_DAVINCI_I2C +#define CFG_I2C_SPEED 80000 /* 100Kbps won't work, silicon bug */ +#define CFG_I2C_SLAVE 10 /* Bogus, master-only in U-Boot */ +/*==================================*/ +/* Network & Ethernet Configuration */ +/*==================================*/ +#define CONFIG_DRIVER_TI_EMAC +#define CONFIG_MII +#define CONFIG_BOOTP_DEFAULT +#define CONFIG_BOOTP_DNS +#define CONFIG_BOOTP_DNS2 +#define CONFIG_BOOTP_SEND_HOSTNAME +#define CONFIG_NET_RETRY_COUNT 10 +/*=====================*/ +/* Flash & Environment */ +/*=====================*/ +#ifdef CFG_USE_NAND +#undef CFG_ENV_IS_IN_FLASH +#define CFG_NO_FLASH +#define CFG_ENV_IS_IN_NAND /* U-Boot env in NAND Flash */ +#define CFG_ENV_SECT_SIZE 512 /* Env sector Size */ +#define CFG_ENV_SIZE SZ_16K +#define CONFIG_SKIP_LOWLEVEL_INIT /* U-Boot is loaded by a bootloader */ +#define CONFIG_SKIP_RELOCATE_UBOOT /* to a proper address, init done */ +#define CFG_NAND_BASE 0x02000000 +#define CFG_NAND_HW_ECC +#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */ +#define NAND_MAX_CHIPS 1 +#define CFG_ENV_OFFSET 0x0 /* Block 0--not used by bootcode */ +#define DEF_BOOTM "" +#elif defined(CFG_USE_NOR) +#ifdef CONFIG_NOR_UART_BOOT +#define CONFIG_SKIP_LOWLEVEL_INIT /* U-Boot is loaded by a bootloader */ +#define CONFIG_SKIP_RELOCATE_UBOOT /* to a proper address, init done */ +#else +#undef CONFIG_SKIP_LOWLEVEL_INIT +#undef CONFIG_SKIP_RELOCATE_UBOOT +#endif +#define CFG_ENV_IS_IN_FLASH +#undef CFG_NO_FLASH +#define CFG_FLASH_CFI_DRIVER +#define CFG_FLASH_CFI +#define CFG_MAX_FLASH_BANKS 1 /* max number of flash banks */ +#define CFG_FLASH_SECT_SZ 0x20000 /* 128KB sect size AMD Flash */ +#define CFG_ENV_OFFSET (CFG_FLASH_SECT_SZ*2) +#define PHYS_FLASH_1 0x02000000 /* CS2 Base address */ +#define CFG_FLASH_BASE PHYS_FLASH_1 /* Flash Base for U-Boot */ +#define PHYS_FLASH_SIZE 0x2000000 /* Flash size 32MB */ +#define CFG_MAX_FLASH_SECT (PHYS_FLASH_SIZE/CFG_FLASH_SECT_SZ) +#define CFG_ENV_SECT_SIZE CFG_FLASH_SECT_SZ /* Env sector Size */ +#endif +/*==============================*/ +/* U-Boot general configuration */ +/*==============================*/ +#undef CONFIG_USE_IRQ /* No IRQ/FIQ in U-Boot */ +#define CONFIG_MISC_INIT_R +#undef CONFIG_BOOTDELAY +#define CONFIG_BOOTFILE "uImage" /* Boot file name */ +#define CFG_PROMPT "U-Boot > " /* Monitor Command Prompt */ +#define CFG_CBSIZE 1024 /* Console I/O Buffer Size */ +#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print buffer sz */ +#define CFG_MAXARGS 16 /* max number of command args */ +#define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ +#define CFG_LOAD_ADDR 0x80700000 /* default Linux kernel load address */ +#define CONFIG_VERSION_VARIABLE +#define CONFIG_AUTO_COMPLETE /* Won't work with hush so far, may be later */ +#define CFG_HUSH_PARSER +#define CFG_PROMPT_HUSH_PS2 "> " +#define CONFIG_CMDLINE_EDITING +#define CFG_LONGHELP +#define CONFIG_CRC32_VERIFY +#define CONFIG_MX_CYCLIC +/*===================*/ +/* Linux Information */ +/*===================*/ +#define LINUX_BOOT_PARAM_ADDR 0x80000100 +#define CONFIG_CMDLINE_TAG +#define CONFIG_SETUP_MEMORY_TAGS +#define CONFIG_BOOTARGS "mem=56M console=ttyS0,115200n8 root=/dev/hda1 rw noinitrd ip=dhcp" +#define CONFIG_BOOTCOMMAND "setenv setboot setenv bootargs \\$(bootargs) video=dm64xxfb:output=\\$(videostd);run setboot; bootm 0x2060000" +/*=================*/ +/* U-Boot commands */ +/*=================*/ +#include +#define CONFIG_CMD_ASKENV +#define CONFIG_CMD_DHCP +#define CONFIG_CMD_DIAG +#define CONFIG_CMD_I2C +#define CONFIG_CMD_MII +#define CONFIG_CMD_PING +#define CONFIG_CMD_SAVES +#define CONFIG_CMD_EEPROM +#undef CONFIG_CMD_BDI +#undef CONFIG_CMD_FPGA +#undef CONFIG_CMD_SETGETDCR +#ifdef CFG_USE_NAND +#undef CONFIG_CMD_FLASH +#undef CONFIG_CMD_IMLS +#define CONFIG_CMD_NAND +#elif defined(CFG_USE_NOR) +#define CONFIG_CMD_JFFS2 +#else +#error "Either CFG_USE_NAND or CFG_USE_NOR _MUST_ be defined !!!" +#endif +/*=======================*/ +/* KGDB support (if any) */ +/*=======================*/ +#ifdef CONFIG_CMD_KGDB +#define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ +#define CONFIG_KGDB_SER_INDEX 1 /* which serial port to use */ +#endif +#endif /* __CONFIG_H */ diff --git a/include/dp83848.h b/include/dp83848.h new file mode 100644 index 0000000..274bc4c --- /dev/null +++ b/include/dp83848.h @@ -0,0 +1,88 @@ +/* + * DP83848 ethernet Physical layer + * + * Copyright (C) 2007 Sergey Kubushyn + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + + +/* National Semiconductor PHYSICAL LAYER TRANSCEIVER DP83848 */ + +#define DP83848_CTL_REG 0x0 /* Basic Mode Control Reg */ +#define DP83848_STAT_REG 0x1 /* Basic Mode Status Reg */ +#define DP83848_PHYID1_REG 0x2 /* PHY Idendifier Reg 1 */ +#define DP83848_PHYID2_REG 0x3 /* PHY Idendifier Reg 2 */ +#define DP83848_ANA_REG 0x4 /* Auto_Neg Advt Reg */ +#define DP83848_ANLPA_REG 0x5 /* Auto_neg Link Partner Ability Reg */ +#define DP83848_ANE_REG 0x6 /* Auto-neg Expansion Reg */ +#define DP83848_PHY_STAT_REG 0x10 /* PHY Status Register */ +#define DP83848_PHY_INTR_CTRL_REG 0x11 /* PHY Interrupt Control Register */ +#define DP83848_PHY_CTRL_REG 0x19 /* PHY Status Register */ + +/*--Bit definitions: DP83848_CTL_REG */ +#define DP83848_RESET (1 << 15) /* 1= S/W Reset */ +#define DP83848_LOOPBACK (1 << 14) /* 1=loopback Enabled */ +#define DP83848_SPEED_SELECT (1 << 13) +#define DP83848_AUTONEG (1 << 12) +#define DP83848_POWER_DOWN (1 << 11) +#define DP83848_ISOLATE (1 << 10) +#define DP83848_RESTART_AUTONEG (1 << 9) +#define DP83848_DUPLEX_MODE (1 << 8) +#define DP83848_COLLISION_TEST (1 << 7) + +/*--Bit definitions: DP83848_STAT_REG */ +#define DP83848_100BASE_T4 (1 << 15) +#define DP83848_100BASE_TX_FD (1 << 14) +#define DP83848_100BASE_TX_HD (1 << 13) +#define DP83848_10BASE_T_FD (1 << 12) +#define DP83848_10BASE_T_HD (1 << 11) +#define DP83848_MF_PREAMB_SUPPR (1 << 6) +#define DP83848_AUTONEG_COMP (1 << 5) +#define DP83848_RMT_FAULT (1 << 4) +#define DP83848_AUTONEG_ABILITY (1 << 3) +#define DP83848_LINK_STATUS (1 << 2) +#define DP83848_JABBER_DETECT (1 << 1) +#define DP83848_EXTEND_CAPAB (1 << 0) + +/*--definitions: DP83848_PHYID1 */ +#define DP83848_PHYID1_OUI 0x2000 +#define DP83848_PHYID2_OUI 0x5c90 + +/*--Bit definitions: DP83848_ANAR, DP83848_ANLPAR */ +#define DP83848_NP (1 << 15) +#define DP83848_ACK (1 << 14) +#define DP83848_RF (1 << 13) +#define DP83848_PAUSE (1 << 10) +#define DP83848_T4 (1 << 9) +#define DP83848_TX_FDX (1 << 8) +#define DP83848_TX_HDX (1 << 7) +#define DP83848_10_FDX (1 << 6) +#define DP83848_10_HDX (1 << 5) +#define DP83848_AN_IEEE_802_3 0x0001 + +/*--Bit definitions: DP83848_ANER */ +#define DP83848_PDF (1 << 4) +#define DP83848_LP_NP_ABLE (1 << 3) +#define DP83848_NP_ABLE (1 << 2) +#define DP83848_PAGE_RX (1 << 1) +#define DP83848_LP_AN_ABLE (1 << 0) + +/*--Bit definitions: DP83848_PHY_STAT */ +#define DP83848_RX_ERR_LATCH (1 << 13) +#define DP83848_POLARITY_STAT (1 << 12) +#define DP83848_FALSE_CAR_SENSE (1 << 11) +#define DP83848_SIG_DETECT (1 << 10) +#define DP83848_DESCRAM_LOCK (1 << 9) +#define DP83848_PAGE_RCV (1 << 8) +#define DP83848_PHY_RMT_FAULT (1 << 6) +#define DP83848_JABBER (1 << 5) +#define DP83848_AUTONEG_COMPLETE (1 << 4) +#define DP83848_LOOPBACK_STAT (1 << 3) +#define DP83848_DUPLEX (1 << 2) +#define DP83848_SPEED (1 << 1) +#define DP83848_LINK (1 << 0) diff --git a/include/exports.h b/include/exports.h index 0516da9..d6512cb 100644 --- a/include/exports.h +++ b/include/exports.h @@ -25,6 +25,9 @@ char *getenv (char *name); void setenv (char *varname, char *varvalue); long simple_strtol(const char *cp,char **endp,unsigned int base); int strcmp(const char * cs,const char * ct); +#ifdef CONFIG_HAS_UID +void forceenv (char *varname, char *varvalue); +#endif #if defined(CONFIG_CMD_I2C) int i2c_write (uchar, uint, int , uchar* , int); int i2c_read (uchar, uint, int , uchar* , int); diff --git a/lib_arm/board.c b/lib_arm/board.c index 8f4e19b..d37e5da 100644 --- a/lib_arm/board.c +++ b/lib_arm/board.c @@ -364,6 +364,13 @@ void start_armboot (void) enable_interrupts (); /* Perform network card initialisation if necessary */ +#ifdef CONFIG_DRIVER_TI_EMAC +extern void dm644x_eth_set_mac_addr (const u_int8_t *addr); + if (getenv ("ethaddr")) { + dm644x_eth_set_mac_addr(gd->bd->bi_enetaddr); + } +#endif + #ifdef CONFIG_DRIVER_CS8900 cs8900_get_enetaddr (gd->bd->bi_enetaddr); #endif diff --git a/net/eth.c b/net/eth.c index 6576ee4..c8f92a5 100644 --- a/net/eth.c +++ b/net/eth.c @@ -464,6 +464,8 @@ extern int at91rm9200_miiphy_initialize(bd_t *bis); extern int emac4xx_miiphy_initialize(bd_t *bis); extern int mcf52x2_miiphy_initialize(bd_t *bis); extern int ns7520_miiphy_initialize(bd_t *bis); +extern int dm644x_eth_miiphy_initialize(bd_t *bis); + int eth_initialize(bd_t *bis) { @@ -484,6 +486,9 @@ int eth_initialize(bd_t *bis) #if defined(CONFIG_NETARM) ns7520_miiphy_initialize(bis); #endif +#if defined(CONFIG_DRIVER_TI_EMAC) + dm644x_eth_miiphy_initialize(bis); +#endif return 0; } #endif -- cgit v1.1 From c2c0ab4aff86622b837a48a0e560351f9afafb95 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 10 Aug 2007 20:34:58 +0200 Subject: Conding style cleanup Signed-off-by: Stefan Roese --- cpu/arm926ejs/davinci/ether.c | 2 -- cpu/arm926ejs/davinci/lowlevel_init.S | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cpu/arm926ejs/davinci/ether.c b/cpu/arm926ejs/davinci/ether.c index 9ec1ee7..32e81d1 100644 --- a/cpu/arm926ejs/davinci/ether.c +++ b/cpu/arm926ejs/davinci/ether.c @@ -252,7 +252,6 @@ static int gen_auto_negotiate(int phy_addr) { u_int16_t tmp; - if (!dm644x_eth_phy_read(phy_addr, PHY_BMCR, &tmp)) return(0); @@ -273,7 +272,6 @@ static int gen_auto_negotiate(int phy_addr) /* End of generic PHY functions */ - #if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) static int dm644x_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) { diff --git a/cpu/arm926ejs/davinci/lowlevel_init.S b/cpu/arm926ejs/davinci/lowlevel_init.S index bbc48ec..a87c112 100644 --- a/cpu/arm926ejs/davinci/lowlevel_init.S +++ b/cpu/arm926ejs/davinci/lowlevel_init.S @@ -545,7 +545,7 @@ VTP1Lock: mov r10, $0 str r10, [r6] - /* + /* * Call board-specific lowlevel init. * That MUST be present and THAT returns * back to arch calling code with "mov pc, lr." -- cgit v1.1 From 49bb59912d21aacb507eb81fd21fb7af650c706c Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Fri, 10 Aug 2007 15:48:59 +0800 Subject: mpc83xx: Suppress the warning 'burstlen' suppress the warning 'burstlen' of spd_sdram. Signed-off-by: Dave Liu --- cpu/mpc83xx/spd_sdram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu/mpc83xx/spd_sdram.c b/cpu/mpc83xx/spd_sdram.c index 2c17cee..54f0c83 100644 --- a/cpu/mpc83xx/spd_sdram.c +++ b/cpu/mpc83xx/spd_sdram.c @@ -576,7 +576,7 @@ long int spd_sdram() if (spd.dataw_lsb == 0x20) { if (spd.mem_type == SPD_MEMTYPE_DDR) burstlen = 0x03; /* 32 bit data bus, burst len is 8 */ - if (spd.mem_type == SPD_MEMTYPE_DDR2) + else burstlen = 0x02; /* 32 bit data bus, burst len is 4 */ printf("\n DDR DIMM: data bus width is 32 bit"); } else { -- cgit v1.1 From 2628114ec564f969f34b5f7105fbd168cb8c9c3f Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Fri, 10 Aug 2007 13:28:25 -0500 Subject: README: Remove outdated cpu type, board type, and NAME_config lists Signed-off-by: Kim Phillips --- README | 140 ++--------------------------------------------------------------- 1 file changed, 4 insertions(+), 136 deletions(-) diff --git a/README b/README index 0df024f..398ea7e 100644 --- a/README +++ b/README @@ -228,114 +228,9 @@ build a config tool - later. The following options need to be configured: -- CPU Type: Define exactly one of - - PowerPC based CPUs: - ------------------- - CONFIG_MPC823, CONFIG_MPC850, CONFIG_MPC855, CONFIG_MPC860 - or CONFIG_MPC5xx - or CONFIG_MPC8220 - or CONFIG_MPC824X, CONFIG_MPC8260 - or CONFIG_MPC85xx - or CONFIG_IOP480 - or CONFIG_405GP - or CONFIG_405EP - or CONFIG_440 - or CONFIG_MPC74xx - or CONFIG_750FX - - ARM based CPUs: - --------------- - CONFIG_SA1110 - CONFIG_ARM7 - CONFIG_PXA250 - CONFIG_PXA27X - CONFIG_CPU_MONAHANS - - MicroBlaze based CPUs: - ---------------------- - CONFIG_MICROBLAZE - - Nios-2 based CPUs: - ---------------------- - CONFIG_NIOS2 - - AVR32 based CPUs: - ---------------------- - CONFIG_AT32AP - -- Board Type: Define exactly one of - - PowerPC based boards: - --------------------- - - CONFIG_ADCIOP CONFIG_FPS860L CONFIG_OXC - CONFIG_ADS860 CONFIG_GEN860T CONFIG_PCI405 - CONFIG_AMX860 CONFIG_GENIETV CONFIG_PCIPPC2 - CONFIG_AP1000 CONFIG_GTH CONFIG_PCIPPC6 - CONFIG_AR405 CONFIG_gw8260 CONFIG_pcu_e - CONFIG_BAB7xx CONFIG_hermes CONFIG_PIP405 - CONFIG_BC3450 CONFIG_hymod CONFIG_PM826 - CONFIG_c2mon CONFIG_IAD210 CONFIG_ppmc8260 - CONFIG_CANBT CONFIG_ICU862 CONFIG_QS823 - CONFIG_CCM CONFIG_IP860 CONFIG_QS850 - CONFIG_CMI CONFIG_IPHASE4539 CONFIG_QS860T - CONFIG_cogent_mpc8260 CONFIG_IVML24 CONFIG_RBC823 - CONFIG_cogent_mpc8xx CONFIG_IVML24_128 CONFIG_RPXClassic - CONFIG_CPCI405 CONFIG_IVML24_256 CONFIG_RPXlite - CONFIG_CPCI4052 CONFIG_IVMS8 CONFIG_RPXsuper - CONFIG_CPCIISER4 CONFIG_IVMS8_128 CONFIG_rsdproto - CONFIG_CPU86 CONFIG_IVMS8_256 CONFIG_sacsng - CONFIG_CRAYL1 CONFIG_JSE CONFIG_Sandpoint8240 - CONFIG_CSB272 CONFIG_LANTEC CONFIG_Sandpoint8245 - CONFIG_CU824 CONFIG_LITE5200B CONFIG_sbc8260 - CONFIG_DASA_SIM CONFIG_lwmon CONFIG_sbc8560 - CONFIG_DB64360 CONFIG_MBX CONFIG_SM850 - CONFIG_DB64460 CONFIG_MBX860T CONFIG_SPD823TS - CONFIG_DU405 CONFIG_MHPC CONFIG_STXGP3 - CONFIG_DUET_ADS CONFIG_MIP405 CONFIG_SXNI855T - CONFIG_EBONY CONFIG_MOUSSE CONFIG_TQM823L - CONFIG_ELPPC CONFIG_MPC8260ADS CONFIG_TQM8260 - CONFIG_ELPT860 CONFIG_MPC8540ADS CONFIG_TQM850L - CONFIG_ep8260 CONFIG_MPC8540EVAL CONFIG_TQM855L - CONFIG_ERIC CONFIG_MPC8560ADS CONFIG_TQM860L - CONFIG_ESTEEM192E CONFIG_MUSENKI CONFIG_TTTech - CONFIG_ETX094 CONFIG_MVS1 CONFIG_UTX8245 - CONFIG_EVB64260 CONFIG_NETPHONE CONFIG_V37 - CONFIG_FADS823 CONFIG_NETTA CONFIG_W7OLMC - CONFIG_FADS850SAR CONFIG_NETVIA CONFIG_W7OLMG - CONFIG_FADS860T CONFIG_NX823 CONFIG_WALNUT - CONFIG_FLAGADM CONFIG_OCRTC CONFIG_ZPC1900 - CONFIG_FPS850L CONFIG_ORSG CONFIG_ZUMA - - ARM based boards: - ----------------- - - CONFIG_ARMADILLO, CONFIG_AT91RM9200DK, CONFIG_CERF250, - CONFIG_CSB637, CONFIG_DELTA, CONFIG_DNP1110, - CONFIG_EP7312, CONFIG_H2_OMAP1610, CONFIG_HHP_CRADLE, - CONFIG_IMPA7, CONFIG_INNOVATOROMAP1510, CONFIG_INNOVATOROMAP1610, - CONFIG_KB9202, CONFIG_LART, CONFIG_LPD7A400, - CONFIG_LUBBOCK, CONFIG_OSK_OMAP5912, CONFIG_OMAP2420H4, - CONFIG_PLEB2, CONFIG_SHANNON, CONFIG_P2_OMAP730, - CONFIG_SMDK2400, CONFIG_SMDK2410, CONFIG_TRAB, - CONFIG_VCMA9 - - MicroBlaze based boards: - ------------------------ - - CONFIG_SUZAKU - - Nios-2 based boards: - ------------------------ - - CONFIG_PCI5441 CONFIG_PK1C20 - CONFIG_EP1C20 CONFIG_EP1S10 CONFIG_EP1S40 - - AVR32 based boards: - ------------------- - - CONFIG_ATSTK1000 +- CPU Type: Define exactly one, e.g. CONFIG_MPC85XX. + +- Board Type: Define exactly one, e.g. CONFIG_MPC8540ADS. - CPU Daughterboard Type: (if CONFIG_ATSTK1000 is defined) Define exactly one of @@ -2492,34 +2387,7 @@ is done by typing: make NAME_config where "NAME_config" is the name of one of the existing -configurations; the following names are supported: - - ADCIOP_config FPS860L_config omap730p2_config - ADS860_config GEN860T_config pcu_e_config - Alaska8220_config - AR405_config GENIETV_config PIP405_config - at91rm9200dk_config GTH_config QS823_config - CANBT_config hermes_config QS850_config - cmi_mpc5xx_config hymod_config QS860T_config - cogent_common_config IP860_config RPXlite_config - cogent_mpc8260_config IVML24_config RPXlite_DW_config - cogent_mpc8xx_config IVMS8_config RPXsuper_config - CPCI405_config JSE_config rsdproto_config - CPCIISER4_config LANTEC_config Sandpoint8240_config - csb272_config lwmon_config sbc8260_config - CU824_config MBX860T_config sbc8560_33_config - DUET_ADS_config MBX_config sbc8560_66_config - EBONY_config mpc7448hpc2_config SM850_config - ELPT860_config MPC8260ADS_config SPD823TS_config - ESTEEM192E_config MPC8540ADS_config stxgp3_config - ETX094_config MPC8540EVAL_config SXNI855T_config - FADS823_config NMPC8560ADS_config TQM823L_config - FADS850SAR_config NETVIA_config TQM850L_config - FADS860T_config omap1510inn_config TQM855L_config - FPS850L_config omap1610h2_config TQM860L_config - omap1610inn_config walnut_config - omap5912osk_config Yukon8220_config - omap2420h4_config ZPC1900_config +configurations; see the main Makefile for supported names. Note: for some board special configuration names may exist; check if additional information is available from the board vendor; for -- cgit v1.1 From fb56579ffe7ef3275b7036bb7b924e5a0d32bd70 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Fri, 10 Aug 2007 15:34:48 -0500 Subject: make MAKEALL more immune to merge conflicts ..by placing board entries one per line, as suggested by jdl. Signed-off-by: Kim Phillips --- MAKEALL | 587 ++++++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 439 insertions(+), 148 deletions(-) diff --git a/MAKEALL b/MAKEALL index c672b51..129c14c 100755 --- a/MAKEALL +++ b/MAKEALL @@ -26,124 +26,281 @@ LIST="" ## MPC5xx Systems ######################################################################### -LIST_5xx=" \ - cmi_mpc5xx \ +LIST_5xx=" \ + cmi_mpc5xx \ " ######################################################################### ## MPC5xxx Systems ######################################################################### -LIST_5xxx=" \ - BC3450 cm5200 cpci5200 EVAL5200 \ - fo300 icecube_5100 icecube_5200 lite5200b \ - mcc200 mecp5200 motionpro o2dnt \ - pf5200 PM520 TB5200 Total5100 \ - Total5200 Total5200_Rev2 TQM5200 TQM5200_B \ - TQM5200S v38b \ +LIST_5xxx=" \ + BC3450 \ + cm5200 \ + cpci5200 \ + EVAL5200 \ + fo300 \ + icecube_5100 \ + icecube_5200 \ + lite5200b \ + mcc200 \ + mecp5200 \ + motionpro \ + o2dnt \ + pf5200 \ + PM520 \ + TB5200 \ + Total5100 \ + Total5200 \ + Total5200_Rev2 \ + TQM5200 \ + TQM5200_B \ + TQM5200S \ + v38b \ " ######################################################################### ## MPC512x Systems ######################################################################### -LIST_512x=" \ - ads5121 \ +LIST_512x=" \ + ads5121 \ " ######################################################################### ## MPC8xx Systems ######################################################################### -LIST_8xx=" \ - Adder87x GENIETV MBX860T R360MPI \ - AdderII GTH MHPC RBC823 \ - ADS860 hermes MPC86xADS rmu \ - AMX860 IAD210 MPC885ADS RPXClassic \ - c2mon ICU862_100MHz MVS1 RPXlite \ - CCM IP860 NETPHONE RPXlite_DW \ - cogent_mpc8xx IVML24 NETTA RRvision \ - ELPT860 IVML24_128 NETTA2 SM850 \ - EP88x IVML24_256 NETTA_ISDN spc1920 \ - ESTEEM192E IVMS8 NETVIA SPD823TS \ - ETX094 IVMS8_128 NETVIA_V2 svm_sc8xx \ - FADS823 IVMS8_256 NX823 SXNI855T \ - FADS850SAR KUP4K pcu_e TOP860 \ - FADS860T KUP4X QS823 TQM823L \ - FLAGADM LANTEC QS850 TQM823L_LCD \ - FPS850L lwmon QS860T TQM850L \ - GEN860T MBX quantum TQM855L \ - GEN860T_SC TQM860L \ - TQM885D \ - uc100 \ - v37 \ +LIST_8xx=" \ + Adder87x \ + AdderII \ + ADS860 \ + AMX860 \ + c2mon \ + CCM \ + cogent_mpc8xx \ + ELPT860 \ + EP88x \ + ESTEEM192E \ + ETX094 \ + FADS823 \ + FADS850SAR \ + FADS860T \ + FLAGADM \ + FPS850L \ + GEN860T \ + GEN860T_SC \ + GENIETV \ + GTH \ + hermes \ + IAD210 \ + ICU862_100MHz \ + IP860 \ + IVML24 \ + IVML24_128 \ + IVML24_256 \ + IVMS8 \ + IVMS8_128 \ + IVMS8_256 \ + KUP4K \ + KUP4X \ + LANTEC \ + lwmon \ + MBX \ + MBX860T \ + MHPC \ + MPC86xADS \ + MPC885ADS \ + MVS1 \ + NETPHONE \ + NETTA \ + NETTA2 \ + NETTA_ISDN \ + NETVIA \ + NETVIA_V2 \ + NX823 \ + pcu_e \ + QS823 \ + QS850 \ + QS860T \ + quantum \ + R360MPI \ + RBC823 \ + rmu \ + RPXClassic \ + RPXlite \ + RPXlite_DW \ + RRvision \ + SM850 \ + spc1920 \ + SPD823TS \ + svm_sc8xx \ + SXNI855T \ + TOP860 \ + TQM823L \ + TQM823L_LCD \ + TQM850L \ + TQM855L \ + TQM860L \ + TQM885D \ + uc100 \ + v37 \ " ######################################################################### ## PPC4xx Systems ######################################################################### -LIST_4xx=" \ - acadia acadia_nand ADCIOP alpr \ - AP1000 AR405 ASH405 bamboo \ - bamboo_nand bubinga CANBT CMS700 \ - CPCI2DP CPCI405 CPCI4052 CPCI405AB \ - CPCI405DT CPCI440 CPCIISER4 CRAYL1 \ - csb272 csb472 DASA_SIM DP405 \ - DU405 ebony ERIC EXBITGEN \ - G2000 HH405 HUB405 JSE \ - KAREF katmai luan lwmon5 \ - METROBOX MIP405 MIP405T ML2 \ - ml300 ocotea OCRTC ORSG \ - p3p440 PCI405 pcs440ep PIP405 \ - PLU405 PMC405 PPChameleonEVB sbc405 \ - sc3 sequoia sequoia_nand taishan \ - VOH405 VOM405 W7OLMC W7OLMG \ - walnut WUH405 XPEDITE1K yellowstone \ - yosemite yucca \ +LIST_4xx=" \ + acadia \ + acadia_nand \ + ADCIOP \ + alpr \ + AP1000 \ + AR405 \ + ASH405 \ + bamboo \ + bamboo_nand \ + bubinga \ + CANBT \ + CMS700 \ + CPCI2DP \ + CPCI405 \ + CPCI4052 \ + CPCI405AB \ + CPCI405DT \ + CPCI440 \ + CPCIISER4 \ + CRAYL1 \ + csb272 \ + csb472 \ + DASA_SIM \ + DP405 \ + DU405 \ + ebony \ + ERIC \ + EXBITGEN \ + G2000 \ + HH405 \ + HUB405 \ + JSE \ + KAREF \ + katmai \ + luan \ + lwmon5 \ + METROBOX \ + MIP405 \ + MIP405T \ + ML2 \ + ml300 \ + ocotea \ + OCRTC \ + ORSG \ + p3p440 \ + PCI405 \ + pcs440ep \ + PIP405 \ + PLU405 \ + PMC405 \ + PPChameleonEVB \ + sbc405 \ + sc3 \ + sequoia \ + sequoia_nand \ + taishan \ + VOH405 \ + VOM405 \ + W7OLMC \ + W7OLMG \ + walnut \ + WUH405 \ + XPEDITE1K \ + yellowstone \ + yosemite \ + yucca \ " ######################################################################### ## MPC8220 Systems ######################################################################### -LIST_8220=" \ - Alaska8220 Yukon8220 \ +LIST_8220=" \ + Alaska8220 \ + Yukon8220 \ " ######################################################################### ## MPC824x Systems ######################################################################### -LIST_824x=" \ - A3000 barco BMW CPC45 \ - CU824 debris eXalion HIDDEN_DRAGON \ - MOUSSE MUSENKI MVBLUE \ - OXC PN62 Sandpoint8240 Sandpoint8245 \ - sbc8240 SL8245 utx8245 \ +LIST_824x=" \ + A3000 \ + barco \ + BMW \ + CPC45 \ + CU824 \ + debris \ + eXalion \ + HIDDEN_DRAGON \ + MOUSSE \ + MUSENKI \ + MVBLUE \ + OXC \ + PN62 \ + Sandpoint8240 \ + Sandpoint8245 \ + sbc8240 \ + SL8245 \ + utx8245 \ " ######################################################################### ## MPC8260 Systems (includes 8250, 8255 etc.) ######################################################################### -LIST_8260=" \ - atc cogent_mpc8260 CPU86 CPU87 \ - ep8248 ep8260 ep82xxm gw8260 \ - hymod IPHASE4539 ISPAN MPC8260ADS \ - MPC8266ADS MPC8272ADS PM826 PM828 \ - ppmc8260 Rattler8248 RPXsuper rsdproto \ - sacsng sbc8260 SCM TQM8260_AC \ - TQM8260_AD TQM8260_AE ZPC1900 \ +LIST_8260=" \ + atc \ + cogent_mpc8260 \ + CPU86 \ + CPU87 \ + ep8248 \ + ep8260 \ + ep82xxm \ + gw8260 \ + hymod \ + IPHASE4539 \ + ISPAN \ + MPC8260ADS \ + MPC8266ADS \ + MPC8272ADS \ + PM826 \ + PM828 \ + ppmc8260 \ + Rattler8248 \ + RPXsuper \ + rsdproto \ + sacsng \ + sbc8260 \ + SCM \ + TQM8260_AC \ + TQM8260_AD \ + TQM8260_AE \ + ZPC1900 \ " ######################################################################### ## MPC83xx Systems (includes 8349, etc.) ######################################################################### -LIST_83xx=" \ - MPC8313ERDB_33 MPC8313ERDB_66 MPC832XEMDS MPC8349EMDS \ - MPC8349ITX MPC8349ITXGP MPC8360EMDS sbc8349 \ - TQM834x \ +LIST_83xx=" \ + MPC8313ERDB_33 \ + MPC8313ERDB_66 \ + MPC832XEMDS \ + MPC8349EMDS \ + MPC8349ITX \ + MPC8349ITXGP \ + MPC8360EMDS \ + sbc8349 \ + TQM834x \ " @@ -151,124 +308,226 @@ LIST_83xx=" \ ## MPC85xx Systems (includes 8540, 8560 etc.) ######################################################################### -LIST_85xx=" \ - MPC8540ADS MPC8540EVAL MPC8541CDS MPC8544DS \ - MPC8548CDS MPC8555CDS MPC8560ADS MPC8568MDS \ - PM854 PM856 sbc8540 sbc8560 \ - stxgp3 stxssa TQM8540 TQM8541 \ - TQM8555 TQM8560 \ +LIST_85xx=" \ + MPC8540ADS \ + MPC8540EVAL \ + MPC8541CDS \ + MPC8544DS \ + MPC8548CDS \ + MPC8555CDS \ + MPC8560ADS \ + MPC8568MDS \ + PM854 \ + PM856 \ + sbc8540 \ + sbc8560 \ + stxgp3 \ + stxssa \ + TQM8540 \ + TQM8541 \ + TQM8555 \ + TQM8560 \ " ######################################################################### ## MPC86xx Systems ######################################################################### -LIST_86xx=" \ - MPC8641HPCN \ +LIST_86xx=" \ + MPC8641HPCN \ " ######################################################################### ## 74xx/7xx Systems ######################################################################### -LIST_74xx=" \ - DB64360 DB64460 EVB64260 P3G4 \ - p3m7448 PCIPPC2 PCIPPC6 ZUMA \ - mpc7448hpc2 +LIST_74xx=" \ + DB64360 \ + DB64460 \ + EVB64260 \ + mpc7448hpc2 \ + P3G4 \ + p3m7448 \ + PCIPPC2 \ + PCIPPC6 \ + ZUMA \ " -LIST_7xx=" \ - BAB7xx CPCI750 ELPPC p3m750 \ - ppmc7xx \ +LIST_7xx=" \ + BAB7xx \ + CPCI750 \ + ELPPC \ + p3m750 \ + ppmc7xx \ " -LIST_ppc="${LIST_5xx} ${LIST_5xxx} \ - ${LIST_8xx} \ - ${LIST_8220} ${LIST_824x} ${LIST_8260} \ - ${LIST_83xx} \ - ${LIST_85xx} \ - ${LIST_86xx} \ - ${LIST_4xx} \ - ${LIST_74xx} ${LIST_7xx}" +LIST_ppc=" \ + ${LIST_5xx} \ + ${LIST_5xxx} \ + ${LIST_8xx} \ + ${LIST_8220} \ + ${LIST_824x} \ + ${LIST_8260} \ + ${LIST_83xx} \ + ${LIST_85xx} \ + ${LIST_86xx} \ + ${LIST_4xx} \ + ${LIST_74xx} \ + ${LIST_7xx} \ +" ######################################################################### ## StrongARM Systems ######################################################################### -LIST_SA="assabet dnp1110 gcplus lart shannon" +LIST_SA=" \ + assabet \ + dnp1110 \ + gcplus \ + lart \ + shannon \ +" ######################################################################### ## ARM7 Systems ######################################################################### -LIST_ARM7=" \ - armadillo B2 ep7312 evb4510 \ - impa7 integratorap ap7 ap720t \ - lpc2292sodimm modnet50 SMN42 \ +LIST_ARM7=" \ + ap7 \ + ap720t \ + armadillo \ + B2 \ + ep7312 \ + evb4510 \ + impa7 \ + integratorap \ + lpc2292sodimm \ + modnet50 \ + SMN42 \ " ######################################################################### ## ARM9 Systems ######################################################################### -LIST_ARM9=" \ - at91rm9200dk cmc_pu2 \ - ap920t ap922_XA10 ap926ejs ap946es \ - ap966 cp920t cp922_XA10 cp926ejs \ - cp946es cp966 lpd7a400 mp2usb \ - mx1ads mx1fs2 netstar omap1510inn \ - omap1610h2 omap1610inn omap730p2 sbc2410x \ - scb9328 smdk2400 smdk2410 trab \ - VCMA9 versatile versatileab versatilepb \ - voiceblue davinci_dvevm davinci_schmoogie \ - davinci_sonata +LIST_ARM9=" \ + at91rm9200dk \ + cmc_pu2 \ + ap920t \ + ap922_XA10 \ + ap926ejs \ + ap946es \ + ap966 \ + cp920t \ + cp922_XA10 \ + cp926ejs \ + cp946es \ + cp966 \ + lpd7a400 \ + mp2usb \ + mx1ads \ + mx1fs2 \ + netstar \ + omap1510inn \ + omap1610h2 \ + omap1610inn \ + omap730p2 \ + sbc2410x \ + scb9328 \ + smdk2400 \ + smdk2410 \ + trab \ + VCMA9 \ + versatile \ + versatileab \ + versatilepb \ + voiceblue \ + davinci_dvevm \ + davinci_schmoogie \ + davinci_sonata \ " ######################################################################### ## ARM10 Systems ######################################################################### -LIST_ARM10=" \ - integratorcp cp1026 \ +LIST_ARM10=" \ + integratorcp \ + cp1026 \ " ######################################################################### ## ARM11 Systems ######################################################################### -LIST_ARM11=" \ - cp1136 omap2420h4 \ +LIST_ARM11=" \ + cp1136 \ + omap2420h4 \ " ######################################################################### ## Xscale Systems ######################################################################### -LIST_pxa=" \ - adsvix cerf250 cradle csb226 \ - delta innokom lubbock pleb2 \ - pxa255_idp wepep250 xaeniax xm250 \ - xsengine zylonite \ +LIST_pxa=" \ + adsvix \ + cerf250 \ + cradle \ + csb226 \ + delta \ + innokom \ + lubbock \ + pleb2 \ + pxa255_idp \ + wepep250 \ + xaeniax \ + xm250 \ + xsengine \ + zylonite \ " -LIST_ixp="ixdp425 ixdpg425 pdnb3 scpu" +LIST_ixp=" \ + ixdp425 \ + ixdpg425 \ + pdnb3 \ + scpu \ +" -LIST_arm=" \ - ${LIST_SA} \ - ${LIST_ARM7} ${LIST_ARM9} ${LIST_ARM10} ${LIST_ARM11} \ - ${LIST_pxa} ${LIST_ixp} \ +LIST_arm=" \ + ${LIST_SA} \ + ${LIST_ARM7} \ + ${LIST_ARM9} \ + ${LIST_ARM10} \ + ${LIST_ARM11} \ + ${LIST_pxa} \ + ${LIST_ixp} \ " ######################################################################### ## MIPS Systems (default = big endian) ######################################################################### -LIST_mips4kc="incaip" +LIST_mips4kc=" \ + incaip \ +" -LIST_mips5kc="purple" +LIST_mips5kc=" \ + purple \ +" -LIST_au1xx0="dbau1000 dbau1100 dbau1500 dbau1550 dbau1550_el gth2" +LIST_au1xx0=" \ + dbau1000 \ + dbau1100 \ + dbau1500 \ + dbau1550 \ + dbau1550_el \ + gth2 \ +" -LIST_mips="${LIST_mips4kc} ${LIST_mips5kc} ${LIST_au1xx0}" +LIST_mips=" \ + ${LIST_mips4kc} \ + ${LIST_mips5kc} \ + ${LIST_au1xx0} \ +" ######################################################################### ## MIPS Systems (little endian) @@ -278,36 +537,55 @@ LIST_mips4kc_el="" LIST_mips5kc_el="" -LIST_au1xx0_el="dbau1550_el" +LIST_au1xx0_el=" \ + dbau1550_el \ +" -LIST_mips_el="${LIST_mips4kc_el} ${LIST_mips5kc_el} ${LIST_au1xx0_el}" +LIST_mips_el=" \ + ${LIST_mips4kc_el} \ + ${LIST_mips5kc_el} \ + ${LIST_au1xx0_el} \ +" ######################################################################### ## i386 Systems ######################################################################### -LIST_I486="sc520_cdp sc520_spunk sc520_spunk_rel" +LIST_I486=" \ + sc520_cdp \ + sc520_spunk \ + sc520_spunk_rel \ +" -LIST_x86="${LIST_I486}" +LIST_x86=" \ + ${LIST_I486} \ +" ######################################################################### ## NIOS Systems ######################################################################### -LIST_nios=" \ - ADNPESC1 ADNPESC1_base_32 \ - ADNPESC1_DNPEVA2_base_32 \ - DK1C20 DK1C20_standard_32 \ - DK1S10 DK1S10_standard_32 DK1S10_mtx_ldk_20 \ +LIST_nios=" \ + ADNPESC1 \ + ADNPESC1_base_32 \ + ADNPESC1_DNPEVA2_base_32\ + DK1C20 \ + DK1C20_standard_32 \ + DK1S10 \ + DK1S10_standard_32 \ + DK1S10_mtx_ldk_20 \ " ######################################################################### ## Nios-II Systems ######################################################################### -LIST_nios2=" \ - EP1C20 EP1S10 EP1S40 \ - PCI5441 PK1C20 \ +LIST_nios2=" \ + EP1C20 \ + EP1S10 \ + EP1S40 \ + PCI5441 \ + PK1C20 \ " ######################################################################### @@ -315,31 +593,44 @@ LIST_nios2=" \ ######################################################################### LIST_microblaze=" \ - suzaku ml401 xupv2p + suzaku \ + ml401 \ + xupv2p \ " ######################################################################### ## ColdFire Systems ######################################################################### -LIST_coldfire=" \ - cobra5272 EB+MCF-EV123 EB+MCF-EV123_internal \ - idmr M5271EVB M5272C3 M5282EVB \ - TASREG r5200 M5271EVB \ +LIST_coldfire=" \ + cobra5272 \ + EB+MCF-EV123 \ + EB+MCF-EV123_internal \ + idmr \ + M5271EVB \ + M5272C3 \ + M5282EVB \ + TASREG \ + r5200 \ " ######################################################################### ## AVR32 Systems ######################################################################### -LIST_avr32="atstk1002" +LIST_avr32=" \ + atstk1002 \ +" ######################################################################### ## Blackfin Systems ######################################################################### -LIST_blackfin=" \ - bf533-ezkit bf533-stamp bf537-stamp bf561-ezkit \ +LIST_blackfin=" \ + bf533-ezkit \ + bf533-stamp \ + bf537-stamp \ + bf561-ezkit \ " #----------------------------------------------------------------------- -- cgit v1.1