diff options
author | wdenk <wdenk> | 2003-09-10 18:20:28 +0000 |
---|---|---|
committer | wdenk <wdenk> | 2003-09-10 18:20:28 +0000 |
commit | 149dded2b178bc0fb62cb6f61b87968d914b580a (patch) | |
tree | 6322023840b11a7210e3030262dc5e6ee42953f0 | |
parent | 7152b1d0b3f8beec8c297d64664e41b4c4ef610a (diff) | |
download | u-boot-imx-149dded2b178bc0fb62cb6f61b87968d914b580a.zip u-boot-imx-149dded2b178bc0fb62cb6f61b87968d914b580a.tar.gz u-boot-imx-149dded2b178bc0fb62cb6f61b87968d914b580a.tar.bz2 |
* Add support for USB Mass Storage Devices (BBB)
(tested with USB memory sticks only)
* Avoid flicker on TRAB's VFD
35 files changed, 2532 insertions, 57 deletions
@@ -1,7 +1,12 @@ ====================================================================== -Changes for U-Boot 0.4.7: +Changes for U-Boot 0.4.8: ====================================================================== +* Add support for USB Mass Storage Devices (BBB) + (tested with USB memory sticks only) + +* Avoid flicker on TRAB's VFD + * Add support for SK98xx driver * Add PCI support for SL8245 board @@ -27,6 +32,10 @@ Changes for U-Boot 0.4.7: * Patch by Yuli Barcohen, 7 Aug 2003: check BCSR to detect if the board is configured in PCI mode +====================================================================== +Changes for U-Boot 0.4.7: +====================================================================== + * Patch by Raghu Krishnaprasad, 7 Aug 2003: add support for Adder II MPC852T module @@ -263,7 +272,7 @@ Changes for U-Boot 0.4.1: - PIC on LWMON board needs delay after power-on - Add missing RSR definitions for MPC8xx - Improve log buffer handling: guarantee clean reset after power-on - - Add support for EXBITGEN board + - Add support for EXBITGEN board (aka "genie") - Add support for SL8245 board * Code cleanup: diff --git a/MAINTAINERS b/MAINTAINERS index 2e748ef..20e68a8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -89,6 +89,7 @@ Wolfgang Denk <wd@denx.de> TQM8255 MPC8255 CPU86 MPC8260 + PM825 MPC8250 PM826 MPC8260 TQM8260 MPC8260 diff --git a/board/mpc8260ads/mpc8260ads.c b/board/mpc8260ads/mpc8260ads.c index 98ae660..14a93be 100644 --- a/board/mpc8260ads/mpc8260ads.c +++ b/board/mpc8260ads/mpc8260ads.c @@ -238,7 +238,9 @@ int board_pre_init (void) long int initdram (int board_type) { +#if CONFIG_ADSTYPE == CFG_PQ2FADS vu_long *bcsr = (vu_long *)CFG_BCSR; +#endif volatile immap_t *immap = (immap_t *) CFG_IMMR; volatile memctl8260_t *memctl = &immap->im_memctl; volatile uchar *ramaddr, c = 0xff; diff --git a/board/trab/trab.c b/board/trab/trab.c index 029fbde..71b3cbe 100644 --- a/board/trab/trab.c +++ b/board/trab/trab.c @@ -105,6 +105,10 @@ int board_init () gpio->PGUP = 0x0; gpio->OPENCR= 0x0; + /* suppress flicker of the VFDs */ + gpio->MISCCR = 0x40; + gpio->PFCON |= (2<<12); + /* arch number of SAMSUNG-Board */ /* MACH_TYPE_SMDK2400 */ /* XXX this isn't really correct, but keep it for now */ diff --git a/common/cmd_nand.c b/common/cmd_nand.c index ce7b5ff..60cdd8e 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -38,7 +38,7 @@ struct nand_oob_config { int eccvalid_pos; /* position of ECC valid flag inside oob -1 = inactive */ } oob_config = { {0}, 0, 0}; -#undef NAND_DEBUG +#define NAND_DEBUG #undef PSYCHO_DEBUG /* ****************** WARNING ********************* diff --git a/common/usb_storage.c b/common/usb_storage.c index a7944b5..7089036 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -2,8 +2,12 @@ * (C) Copyright 2001 * Denis Peter, MPL AG Switzerland * + * For BBB support (C) Copyright 2003 + * Gary Jennejohn, DENX Software Engineering <gj@denx.de> + * * Most of this source has been derived from the Linux USB - * project. + * project. BBB support based on /sys/dev/usb/umass.c from + * FreeBSD. * * See file CREDITS for list of people who contributed to this * project. @@ -30,6 +34,13 @@ * is only tested with a TEAC USB Floppy. Other Massstorages with CBI or CB * transport protocoll may work as well. */ +/* + * New Note: + * Support for USB Mass Storage Devices (BBB) has been added. It has + * only been tested with USB memory sticks. + * Nota bene: if you are using the BBB support with a little-endian + * CPU then you MUST define LITTLEENDIAN in the configuration file! + */ #include <common.h> @@ -71,6 +82,41 @@ static ccb usb_ccb; #define US_CBI_ADSC 0 +/* + * BULK only + */ +#define US_BBB_RESET 0xff +#define US_BBB_GET_MAX_LUN 0xfe + +/* Command Block Wrapper */ +typedef struct { + __u32 dCBWSignature; +# define CBWSIGNATURE 0x43425355 + __u32 dCBWTag; + __u32 dCBWDataTransferLength; + __u8 bCBWFlags; +# define CBWFLAGS_OUT 0x00 +# define CBWFLAGS_IN 0x80 + __u8 bCBWLUN; + __u8 bCDBLength; +# define CBWCDBLENGTH 16 + __u8 CBWCDB[CBWCDBLENGTH]; +} umass_bbb_cbw_t; +#define UMASS_BBB_CBW_SIZE 31 +static __u32 CBWTag = 0; + +/* Command Status Wrapper */ +typedef struct { + __u32 dCSWSignature; +# define CSWSIGNATURE 0x53425355 + __u32 dCSWTag; + __u32 dCSWDataResidue; + __u8 bCSWStatus; +# define CSWSTATUS_GOOD 0x0 +# define CSWSTATUS_FAILED 0x1 +# define CSWSTATUS_PHASE 0x2 +} umass_bbb_csw_t; +#define UMASS_BBB_CSW_SIZE 13 #define USB_MAX_STOR_DEV 5 static int usb_max_devs; /* number of highest available usb device */ @@ -138,6 +184,9 @@ int usb_stor_scan(int mode) unsigned char i; struct usb_device *dev; + /* GJ */ + memset(usb_stor_buf, 0, sizeof(usb_stor_buf)); + if(mode==1) { printf("scanning bus for storage devices...\n"); } @@ -293,6 +342,51 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length) return 0; } +static int usb_stor_BBB_reset(struct us_data *us) +{ + int result; + unsigned int pipe; + + /* + * Reset recovery (5.3.4 in Universal Serial Bus Mass Storage Class) + * + * For Reset Recovery the host shall issue in the following order: + * a) a Bulk-Only Mass Storage Reset + * b) a Clear Feature HALT to the Bulk-In endpoint + * c) a Clear Feature HALT to the Bulk-Out endpoint + * + * This is done in 3 steps. + * + * If the reset doesn't succeed, the device should be port reset. + * + * This comment stolen from FreeBSD's /sys/dev/usb/umass.c. + */ + USB_STOR_PRINTF("BBB_reset\n"); + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + US_BBB_RESET, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + 0, us->ifnum, 0, 0, USB_CNTL_TIMEOUT*5); + if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) + { + USB_STOR_PRINTF("RESET:stall\n"); + return -1; + } + /* long wait for reset */ + wait_ms(150); + USB_STOR_PRINTF("BBB_reset result %d: status %X reset\n",result,us->pusb_dev->status); + pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); + result = usb_clear_halt(us->pusb_dev, pipe); + /* long wait for reset */ + wait_ms(150); + USB_STOR_PRINTF("BBB_reset result %d: status %X clearing IN endpoint\n",result,us->pusb_dev->status); + /* long wait for reset */ + pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + result = usb_clear_halt(us->pusb_dev, pipe); + wait_ms(150); + USB_STOR_PRINTF("BBB_reset result %d: status %X clearing OUT endpoint\n",result,us->pusb_dev->status); + USB_STOR_PRINTF("BBB_reset done\n"); + return 0; +} + /* FIXME: this reset function doesn't really reset the port, and it * should. Actually it should probably do what it's doing here, and * reset the port physically @@ -320,6 +414,52 @@ static int usb_stor_CB_reset(struct us_data *us) return 0; } +/* + * Set up the command for a BBB device. Note that the actual SCSI + * command is copied into cbw.CBWCDB. + */ +int usb_stor_BBB_comdat(ccb *srb, struct us_data *us) +{ + int result; + int actlen; + int dir_in; + unsigned int pipe; + umass_bbb_cbw_t cbw; + + dir_in = US_DIRECTION(srb->cmd[0]); + +#ifdef BBB_COMDAT_TRACE + printf("dir %d lun %d cmdlen %d cmd %p datalen %d pdata %p\n", dir_in, srb->lun, srb->cmdlen, srb->cmd, srb->datalen, srb->pdata); + if (srb->cmdlen) { + for(result = 0;result < srb->cmdlen;result++) + printf("cmd[%d] %#x ", result, srb->cmd[result]); + printf("\n"); + } +#endif + /* sanity checks */ + if (!(srb->cmdlen <= CBWCDBLENGTH)) { + USB_STOR_PRINTF("usb_stor_BBB_comdat:cmdlen too large\n"); + return -1; + } + + /* always OUT to the ep */ + pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + + cbw.dCBWSignature = swap_32(CBWSIGNATURE); + cbw.dCBWTag = swap_32(CBWTag++); + cbw.dCBWDataTransferLength = swap_32(srb->datalen); + cbw.bCBWFlags = (dir_in? CBWFLAGS_IN : CBWFLAGS_OUT); + cbw.bCBWLUN = srb->lun; + cbw.bCDBLength = srb->cmdlen; + /* copy the command data into the CBW command data buffer */ + /* DST SRC LEN!!! */ + memcpy(cbw.CBWCDB, srb->cmd, srb->cmdlen); + result = usb_bulk_msg(us->pusb_dev, pipe, &cbw, UMASS_BBB_CBW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); + if (result < 0) + USB_STOR_PRINTF("usb_stor_BBB_comdat:usb_bulk_msg error\n"); + return result; +} + /* FIXME: we also need a CBI_command which sets up the completion * interrupt, and waits for it */ @@ -422,6 +562,134 @@ int usb_stor_CBI_get_status(ccb *srb, struct us_data *us) #define USB_TRANSPORT_UNKNOWN_RETRY 5 #define USB_TRANSPORT_NOT_READY_RETRY 10 +/* clear a stall on an endpoint - special for BBB devices */ +int usb_stor_BBB_clear_endpt_stall(struct us_data *us, __u8 endpt) +{ + int result; + + /* ENDPOINT_HALT = 0, so set value to 0 */ + result = usb_control_msg(us->pusb_dev, usb_sndctrlpipe(us->pusb_dev,0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, + 0, endpt, 0, 0, USB_CNTL_TIMEOUT*5); + return result; +} + +int usb_stor_BBB_transport(ccb *srb, struct us_data *us) +{ + int result, retry; + int dir_in; + int actlen, data_actlen; + unsigned int pipe, pipein, pipeout; + umass_bbb_csw_t csw; +#ifdef BBB_XPORT_TRACE + unsigned char *ptr; + int index; +#endif + + dir_in = US_DIRECTION(srb->cmd[0]); + + /* COMMAND phase */ + USB_STOR_PRINTF("COMMAND phase\n"); + result = usb_stor_BBB_comdat(srb, us); + if (result < 0) { + USB_STOR_PRINTF("failed to send CBW status %ld\n", + us->pusb_dev->status); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } + wait_ms(5); + pipein = usb_rcvbulkpipe(us->pusb_dev, us->ep_in); + pipeout = usb_sndbulkpipe(us->pusb_dev, us->ep_out); + /* DATA phase + error handling */ + USB_STOR_PRINTF("DATA phase\n"); + data_actlen = 0; + /* no data, go immediately to the STATUS phase */ + if (srb->datalen == 0) + goto st; + if (dir_in) + pipe = pipein; + else + pipe = pipeout; + result = usb_bulk_msg(us->pusb_dev, pipe, srb->pdata, srb->datalen, &data_actlen, USB_CNTL_TIMEOUT*5); + /* special handling of STALL in DATA phase */ + if((result < 0) && (us->pusb_dev->status & USB_ST_STALLED)) { + printf("DATA:stall\n"); + /* clear the STALL on the endpoint */ + result = usb_stor_BBB_clear_endpt_stall(us, dir_in? us->ep_in : us->ep_out); + if (result >= 0) + /* continue on to STATUS phase */ + goto st; + } + if (result < 0) { + USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", + us->pusb_dev->status); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } +#ifdef BBB_XPORT_TRACE + for (index = 0; index < data_actlen; index++) + printf("pdata[%d] %#x ", index, srb->pdata[index]); + printf("\n"); +#endif + /* STATUS phase + error handling */ + st: + retry = 0; + again: + USB_STOR_PRINTF("STATUS phase\n"); + result = usb_bulk_msg(us->pusb_dev, pipein, &csw, UMASS_BBB_CSW_SIZE, &actlen, USB_CNTL_TIMEOUT*5); + /* special handling of STALL in STATUS phase */ + if((result < 0) && (retry < 1) && (us->pusb_dev->status & USB_ST_STALLED)) { + USB_STOR_PRINTF("STATUS:stall\n"); + /* clear the STALL on the endpoint */ + result = usb_stor_BBB_clear_endpt_stall(us, us->ep_in); + if (result >= 0 && (retry++ < 1)) + /* do a retry */ + goto again; + } + if (result < 0) { + USB_STOR_PRINTF("usb_bulk_msg error status %ld\n", + us->pusb_dev->status); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } +#ifdef BBB_XPORT_TRACE + ptr = (unsigned char *)&csw; + for (index = 0; index < UMASS_BBB_CSW_SIZE; index++) + printf("ptr[%d] %#x ", index, ptr[index]); + printf("\n"); +#endif + /* misuse pipe to get the residue */ + pipe = swap_32(csw.dCSWDataResidue); + if (pipe == 0 && srb->datalen != 0 && srb->datalen - data_actlen != 0) + pipe = srb->datalen - data_actlen; + if (CSWSIGNATURE != swap_32(csw.dCSWSignature)) { + USB_STOR_PRINTF("!CSWSIGNATURE\n"); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } else if ((CBWTag - 1) != swap_32(csw.dCSWTag)) { + USB_STOR_PRINTF("!Tag\n"); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } else if (csw.bCSWStatus > CSWSTATUS_PHASE) { + USB_STOR_PRINTF(">PHASE\n"); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } else if (csw.bCSWStatus == CSWSTATUS_PHASE) { + USB_STOR_PRINTF("=PHASE\n"); + usb_stor_BBB_reset(us); + return USB_STOR_TRANSPORT_FAILED; + } else if (data_actlen > srb->datalen) { + USB_STOR_PRINTF("transferred %dB instead of %dB\n", + data_actlen, srb->datalen); + return USB_STOR_TRANSPORT_FAILED; + } else if (csw.bCSWStatus == CSWSTATUS_FAILED) { + USB_STOR_PRINTF("FAILED\n"); + return USB_STOR_TRANSPORT_FAILED; + } + + return result; +} + int usb_stor_CB_transport(ccb *srb, struct us_data *us) { int result,status; @@ -495,29 +763,28 @@ do_retry: return USB_STOR_TRANSPORT_GOOD; /* Check the auto request result */ switch(srb->sense_buf[2]) { - case 0x01: /* Recovered Error */ - return USB_STOR_TRANSPORT_GOOD; - break; - case 0x02: /* Not Ready */ - if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) { - printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n", - srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); - return USB_STOR_TRANSPORT_FAILED; - } - else { - wait_ms(100); - goto do_retry; - } - break; - default: - if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) { - printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n", - srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); - return USB_STOR_TRANSPORT_FAILED; - } - else - goto do_retry; - break; + case 0x01: /* Recovered Error */ + return USB_STOR_TRANSPORT_GOOD; + break; + case 0x02: /* Not Ready */ + if(notready++ > USB_TRANSPORT_NOT_READY_RETRY) { + printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X (NOT READY)\n", + srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); + return USB_STOR_TRANSPORT_FAILED; + } else { + wait_ms(100); + goto do_retry; + } + break; + default: + if(retry++ > USB_TRANSPORT_UNKNOWN_RETRY) { + printf("cmd 0x%02X returned 0x%02X 0x%02X 0x%02X 0x%02X\n", + srb->cmd[0],srb->sense_buf[0],srb->sense_buf[2],srb->sense_buf[12],srb->sense_buf[13]); + return USB_STOR_TRANSPORT_FAILED; + } else { + goto do_retry; + } + break; } return USB_STOR_TRANSPORT_FAILED; } @@ -538,7 +805,8 @@ static int usb_inquiry(ccb *srb,struct us_data *ss) USB_STOR_PRINTF("inquiry returns %d\n",i); if(i==0) break; - }while(retry--); + } while(retry--); + if(!retry) { printf("error in inquiry\n"); return -1; @@ -567,17 +835,18 @@ static int usb_request_sense(ccb *srb,struct us_data *ss) static int usb_test_unit_ready(ccb *srb,struct us_data *ss) { int retries=10; + do { memset(&srb->cmd[0],0,12); srb->cmd[0]=SCSI_TST_U_RDY; srb->cmd[1]=srb->lun<<5; srb->datalen=0; srb->cmdlen=12; - if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) - { + if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) { return 0; } } while(retries--); + return -1; } @@ -594,7 +863,8 @@ static int usb_read_capacity(ccb *srb,struct us_data *ss) if(ss->transport(srb,ss)==USB_STOR_TRANSPORT_GOOD) { return 0; } - }while(retry--); + } while(retry--); + return -1; } @@ -654,8 +924,7 @@ unsigned long usb_stor_read(int device, unsigned long blknr, unsigned long blkcn srb->pdata=(unsigned char *)buf_addr; if(blks>USB_MAX_READ_BLK) { smallblks=USB_MAX_READ_BLK; - } - else { + } else { smallblks=(unsigned short) blks; } retry_it: @@ -751,6 +1020,11 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data ss->transport = usb_stor_CB_transport; ss->transport_reset = usb_stor_CB_reset; break; + case US_PR_BULK: + USB_STOR_PRINTF("Bulk/Bulk/Bulk\n"); + ss->transport = usb_stor_BBB_transport; + ss->transport_reset = usb_stor_BBB_reset; + break; default: printf("USB Starage Transport unknown / not yet implemented\n"); return 0; @@ -793,15 +1067,14 @@ int usb_storage_probe(struct usb_device *dev, unsigned int ifnum,struct us_data return 0; } /* set class specific stuff */ - /* We only handle certain protocols. Currently, this is - * the only one. + /* We only handle certain protocols. Currently, these are + * the only ones. */ - if (ss->subclass != US_SC_UFI) { + if (ss->subclass != US_SC_UFI && ss->subclass != US_SC_SCSI) { printf("Sorry, protocol %d not yet supported.\n",ss->subclass); return 0; } - if(ss->ep_int) /* we had found an interrupt endpoint, prepare irq pipe */ - { + if(ss->ep_int) { /* we had found an interrupt endpoint, prepare irq pipe */ /* set up the IRQ pipe and handler */ ss->irqinterval = (ss->irqinterval > 0) ? ss->irqinterval : 255; @@ -865,6 +1138,19 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t if(cap[0]>(0x200000 * 10)) /* greater than 10 GByte */ cap[0]>>=16; #endif +#ifdef LITTLEENDIAN + cap[0] = ((unsigned long)( + (((unsigned long)(cap[0]) & (unsigned long)0x000000ffUL) << 24) | + (((unsigned long)(cap[0]) & (unsigned long)0x0000ff00UL) << 8) | + (((unsigned long)(cap[0]) & (unsigned long)0x00ff0000UL) >> 8) | + (((unsigned long)(cap[0]) & (unsigned long)0xff000000UL) >> 24) )); + cap[1] = ((unsigned long)( + (((unsigned long)(cap[1]) & (unsigned long)0x000000ffUL) << 24) | + (((unsigned long)(cap[1]) & (unsigned long)0x0000ff00UL) << 8) | + (((unsigned long)(cap[1]) & (unsigned long)0x00ff0000UL) >> 8) | + (((unsigned long)(cap[1]) & (unsigned long)0xff000000UL) >> 24) )); +#endif + /* this assumes bigendian! */ cap[0]+=1; capacity=&cap[0]; blksz=&cap[1]; @@ -881,5 +1167,5 @@ int usb_stor_get_info(struct usb_device *dev,struct us_data *ss,block_dev_desc_t return 1; } -#endif #endif /* CONFIG_USB_STORAGE */ +#endif /* CFG_CMD_USB */ diff --git a/cpu/arm920t/Makefile b/cpu/arm920t/Makefile index e5ec81d..605adf3 100644 --- a/cpu/arm920t/Makefile +++ b/cpu/arm920t/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = lib$(CPU).a START = start.o -OBJS = serial.o interrupts.o cpu.o speed.o +OBJS = serial.o interrupts.o cpu.o speed.o usb_ohci.o all: .depend $(START) $(LIB) diff --git a/cpu/arm920t/usb_ohci.c b/cpu/arm920t/usb_ohci.c new file mode 100644 index 0000000..41ba233 --- /dev/null +++ b/cpu/arm920t/usb_ohci.c @@ -0,0 +1,1553 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB on the S3C2400. + * + * (C) Copyright 2003 + * Gary Jennejohn, DENX Software Engineering <gj@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 + * + * Note: Part of this code has been derived from linux + * + */ +/* + * IMPORTANT NOTES + * 1 - you MUST define LITTLEENDIAN in the configuration file for the + * board or this driver will NOT work! + * 2 - this driver is intended for use with USB Mass Storage Devices + * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes! + */ + +#include <common.h> +/* #include <pci.h> no PCI on the S3C2400 */ + +#ifdef CONFIG_USB_OHCI + +#include <s3c2400.h> +#include <malloc.h> +#include <usb.h> +#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 OHCI_UNLINK_TIMEOUT (CFG_HZ / 10) + +#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; + +/*-------------------------------------------------------------------------*/ + +/* 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); + + 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 */ + +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; + 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; + +#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); */ + /* wait for it to complete */ + timeout = 100; + for (;;) { + /* check whether the controller is done */ + stat = hc_interrupt(); + if (stat < 0) { + stat = 1; + break; + } + if (stat >= 0 && stat != 0xff) { + /* 0xff is returned for an SF-interrupt */ + break; + } + if (--timeout) { + wait_ms(1); + } else { + err("CTL:TIMEOUT"); + stat = 1; + break; + } + } + 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) + /* 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 */ + + 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 ;", + 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); + + /* Choose the interrupts we care about now, others later on demand */ + mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO; + writel (mask, &ohci->regs->intrstatus); + +#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_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) +{ + 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); + + 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 *)S3C24X0_USB_HOST_BASE; + + gohci.flags = 0; + gohci.slot_name = "s3c2400"; + + if (hc_reset (&gohci) < 0) { + hc_release_ohci (&gohci); + /* Initialization failed */ + clk_power->CLKCON &= ~(1 << 4); + 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 */ + clk_power->CLKCON &= ~(1 << 4); + return -1; + } + +#ifdef DEBUG + ohci_dump (&gohci, 1); +#else + wait_ms(1); +#endif + ohci_inited = 1; + return 0; +} + +int usb_lowlevel_stop(void) +{ + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + + /* 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 */ + clk_power->CLKCON &= ~(1 << 4); + return 0; +} + +#endif /* CONFIG_USB_OHCI */ diff --git a/cpu/arm920t/usb_ohci.h b/cpu/arm920t/usb_ohci.h new file mode 100644 index 0000000..26b84e6 --- /dev/null +++ b/cpu/arm920t/usb_ohci.h @@ -0,0 +1,420 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB. + * + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> + * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net> + * + * 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/ppc4xx/405gp_enet.c b/cpu/ppc4xx/405gp_enet.c index 9639c92..c222c71 100644 --- a/cpu/ppc4xx/405gp_enet.c +++ b/cpu/ppc4xx/405gp_enet.c @@ -83,7 +83,7 @@ #if defined(CONFIG_405GP) || defined(CONFIG_440) || defined(CONFIG_405EP) #define EMAC_RESET_TIMEOUT 1000 /* 1000 ms reset timeout */ -#define PHY_AUTONEGOTIATE_TIMEOUT 2000 /* 2000 ms autonegotiate timeout */ +#define PHY_AUTONEGOTIATE_TIMEOUT 4000 /* 4000 ms autonegotiate timeout */ #define NUM_TX_BUFF 1 /* AS.HARNOIS @@ -271,18 +271,18 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) puts ("Waiting for PHY auto negotiation to complete"); i = 0; while (!(reg_short & PHY_BMSR_AUTN_COMP)) { - if ((i++ % 100) == 0) - putc ('.'); - udelay (10000); /* 10 ms */ - miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, ®_short); - /* * Timeout reached ? */ - if (i * 10 > PHY_AUTONEGOTIATE_TIMEOUT) { + if (i > PHY_AUTONEGOTIATE_TIMEOUT) { puts (" TIMEOUT !\n"); break; } + + if ((i++ % 1000) == 0) + putc ('.'); + udelay (1000); /* 1 ms */ + miiphy_read (CONFIG_PHY_ADDR, PHY_BMSR, ®_short); } puts (" done\n"); udelay (500000); /* another 500 ms (results in faster booting) */ diff --git a/disk/part.c b/disk/part.c index 97ed918..7bd48e0 100644 --- a/disk/part.c +++ b/disk/part.c @@ -33,7 +33,9 @@ #define PRINTF(fmt,args...) #endif -#if (CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI) +#if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ + (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ + (CONFIG_COMMANDS & CFG_CMD_USB) ) /* ------------------------------------------------------------------------- */ /* diff --git a/disk/part_dos.c b/disk/part_dos.c index db2c23b..32333c7 100644 --- a/disk/part_dos.c +++ b/disk/part_dos.c @@ -35,7 +35,9 @@ #include <ide.h> #include "part_dos.h" -#if ((CONFIG_COMMANDS & CFG_CMD_IDE) || (CONFIG_COMMANDS & CFG_CMD_SCSI)) && defined(CONFIG_DOS_PARTITION) +#if ((CONFIG_COMMANDS & CFG_CMD_IDE) || \ + (CONFIG_COMMANDS & CFG_CMD_SCSI) || \ + (CONFIG_COMMANDS & CFG_CMD_USB) ) && defined(CONFIG_DOS_PARTITION) /* Convert char[4] in little endian format to the host format integer */ diff --git a/drivers/sk98lin/h/ski2c.h b/drivers/sk98lin/h/ski2c.h index db2d4e6..5316bba 100644 --- a/drivers/sk98lin/h/ski2c.h +++ b/drivers/sk98lin/h/ski2c.h @@ -161,6 +161,8 @@ typedef struct s_Sensor SK_SENSOR; /* * Define READ and WRITE Constants. */ +#undef I2C_READ /* just in case */ +#undef I2C_WRITE /* just in case */ #define I2C_READ 0 #define I2C_WRITE 1 #define I2C_BURST 1 diff --git a/drivers/sk98lin/skaddr.c b/drivers/sk98lin/skaddr.c index 4677111..f248603 100644 --- a/drivers/sk98lin/skaddr.c +++ b/drivers/sk98lin/skaddr.c @@ -218,6 +218,10 @@ * ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + #ifndef lint static const char SysKonnectFileId[] = "@(#) $Id: skaddr.c,v 1.48 2003/02/12 17:09:37 tschilli Exp $ (C) SysKonnect."; @@ -1872,3 +1876,4 @@ SK_U32 ToPortNumber) /* Port2 Index */ } #endif /* __cplusplus */ +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skcsum.c b/drivers/sk98lin/skcsum.c index 9630fad..0fd7030 100644 --- a/drivers/sk98lin/skcsum.c +++ b/drivers/sk98lin/skcsum.c @@ -70,6 +70,10 @@ * ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + #ifdef SK_USE_CSUM /* Check if CSUM is to be used. */ #ifndef lint @@ -921,3 +925,5 @@ SK_EVPARA Param) /* Event dependent parameter. */ } /* SkCsEvent */ #endif /* SK_USE_CSUM */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skge.c b/drivers/sk98lin/skge.c index 49ef8b3..01a72e1 100644 --- a/drivers/sk98lin/skge.c +++ b/drivers/sk98lin/skge.c @@ -340,6 +340,10 @@ * ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + #include "h/skversion.h" #if 0 #include <linux/module.h> @@ -4862,6 +4866,8 @@ int l; #endif +#endif /* CONFIG_SK98 */ + /* * Local variables: * compile-command: "make" diff --git a/drivers/sk98lin/skgehwt.c b/drivers/sk98lin/skgehwt.c index 8996b7f..10c366d 100644 --- a/drivers/sk98lin/skgehwt.c +++ b/drivers/sk98lin/skgehwt.c @@ -73,6 +73,10 @@ ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + /* Event queue and dispatcher */ @@ -211,4 +215,6 @@ SK_IOC Ioc) /* IoContext */ SkTimerDone(pAC,Ioc) ; } +#endif /* CONFIG_SK98 */ + /* End of file */ diff --git a/drivers/sk98lin/skgeinit.c b/drivers/sk98lin/skgeinit.c index 42a6424..cb6e20f 100644 --- a/drivers/sk98lin/skgeinit.c +++ b/drivers/sk98lin/skgeinit.c @@ -393,6 +393,10 @@ * ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + #include "h/skdrv1st.h" #include "h/skdrv2nd.h" @@ -2364,3 +2368,5 @@ int Port) /* Port to configure */ return(0); } /* SkGeInitPort */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skgemib.c b/drivers/sk98lin/skgemib.c index 3f5a7f5..ab85ccd 100644 --- a/drivers/sk98lin/skgemib.c +++ b/drivers/sk98lin/skgemib.c @@ -50,6 +50,10 @@ * ****************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + /* * PRIVATE OID handler function prototypes */ @@ -1054,3 +1058,4 @@ PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTable[] = { SK_PNMI_RO, Vct, 0}, }; +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skgepnmi.c b/drivers/sk98lin/skgepnmi.c index 498c85d..d1c1a3e 100644 --- a/drivers/sk98lin/skgepnmi.c +++ b/drivers/sk98lin/skgepnmi.c @@ -432,6 +432,10 @@ ****************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + static const char SysKonnectFileId[] = "@(#) $Id: skgepnmi.c,v 1.102 2002/12/16 14:03:24 tschilli Exp $" " (C) SysKonnect."; @@ -8303,3 +8307,5 @@ SK_U32 PhysPortIndex) } } /* CheckVctStatus */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skgesirq.c b/drivers/sk98lin/skgesirq.c index 581368e..c7c04b7 100644 --- a/drivers/sk98lin/skgesirq.c +++ b/drivers/sk98lin/skgesirq.c @@ -337,6 +337,10 @@ * ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + /* * Special Interrupt handler * @@ -2408,4 +2412,6 @@ SK_U16 IStatus) /* Interrupt Status */ } /* SkPhyIsrLone */ #endif /* OTHER_PHY */ +#endif /* CONFIG_SK98 */ + /* End of File */ diff --git a/drivers/sk98lin/ski2c.c b/drivers/sk98lin/ski2c.c index 671f76e..b262f29 100644 --- a/drivers/sk98lin/ski2c.c +++ b/drivers/sk98lin/ski2c.c @@ -228,6 +228,10 @@ ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + /* * I2C Protocol */ @@ -1497,3 +1501,5 @@ SK_EVPARA Para) /* Event specific Parameter */ } /* SkI2cEvent*/ #endif /* !SK_DIAG */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/sklm80.c b/drivers/sk98lin/sklm80.c index 51c7cc4..1c96ee3 100644 --- a/drivers/sk98lin/sklm80.c +++ b/drivers/sk98lin/sklm80.c @@ -98,6 +98,10 @@ ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + /* LM80 functions */ @@ -284,3 +288,5 @@ SK_SENSOR *pSen) /* Sensor to be read */ /* Not completed */ return(0); } + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skproc.c b/drivers/sk98lin/skproc.c index a23e55c..ecba704 100644 --- a/drivers/sk98lin/skproc.c +++ b/drivers/sk98lin/skproc.c @@ -70,6 +70,10 @@ * ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + #include <linux/proc_fs.h> #include "h/skdrv1st.h" @@ -511,5 +515,4 @@ char * SkNumber(char * str, long long num, int base, int size, int precision return strorg; } - - +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skqueue.c b/drivers/sk98lin/skqueue.c index c279cd1..c9740e3 100644 --- a/drivers/sk98lin/skqueue.c +++ b/drivers/sk98lin/skqueue.c @@ -87,6 +87,10 @@ ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + /* Event queue and dispatcher */ @@ -233,4 +237,6 @@ SK_IOC Ioc) /* Io context */ return(0) ; } +#endif /* CONFIG_SK98 */ + /* End of file */ diff --git a/drivers/sk98lin/skrlmt.c b/drivers/sk98lin/skrlmt.c index 26b3f74..1e707c9 100644 --- a/drivers/sk98lin/skrlmt.c +++ b/drivers/sk98lin/skrlmt.c @@ -280,6 +280,10 @@ * ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + #ifndef lint static const char SysKonnectFileId[] = "@(#) $Id: skrlmt.c,v 1.68 2003/01/31 15:26:56 rschmidt Exp $ (C) SysKonnect."; @@ -3500,3 +3504,5 @@ SK_EVPARA Para) /* Event-specific parameter */ #ifdef __cplusplus } #endif /* __cplusplus */ + +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/sktimer.c b/drivers/sk98lin/sktimer.c index e8894d2..67431d9 100644 --- a/drivers/sk98lin/sktimer.c +++ b/drivers/sk98lin/sktimer.c @@ -72,6 +72,10 @@ ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + /* Event queue and dispatcher */ @@ -288,4 +292,6 @@ int Restart) /* Do we need to restart the Hardware timer ? */ } } +#endif /* CONFIG_SK98 */ + /* End of file */ diff --git a/drivers/sk98lin/skvpd.c b/drivers/sk98lin/skvpd.c index 68c65d1..f4558fa 100644 --- a/drivers/sk98lin/skvpd.c +++ b/drivers/sk98lin/skvpd.c @@ -160,6 +160,10 @@ * ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + /* Please refer skvpd.txt for infomation how to include this module */ @@ -1323,3 +1327,4 @@ char *msg) /* error log message */ (void)VpdUpdate(pAC, IoC); } +#endif /* CONFIG_SK98 */ diff --git a/drivers/sk98lin/skxmac2.c b/drivers/sk98lin/skxmac2.c index c339eca..9c87b23 100644 --- a/drivers/sk98lin/skxmac2.c +++ b/drivers/sk98lin/skxmac2.c @@ -410,6 +410,10 @@ * ******************************************************************************/ +#include <config.h> + +#ifdef CONFIG_SK98 + #include "h/skdrv1st.h" #include "h/skdrv2nd.h" @@ -4389,4 +4393,6 @@ SK_BOOL StartTest) /* flag for start / get result */ return(0); } /* SkGmCableDiagStatus */ +#endif /* CONFIG_SK98 */ + /* End of file */ diff --git a/drivers/sk98lin/uboot_skb.c b/drivers/sk98lin/uboot_skb.c index 9d86bea..b87ad16 100644 --- a/drivers/sk98lin/uboot_skb.c +++ b/drivers/sk98lin/uboot_skb.c @@ -23,6 +23,10 @@ * MA 02111-1307 USA */ +#include <config.h> + +#ifdef CONFIG_SK98 + #include <common.h> #include "u-boot_compat.h" @@ -114,3 +118,5 @@ void skb_put(struct sk_buff *skb, unsigned int len) { skb->len+=len; } + +#endif /* CONFIG_SK98 */ diff --git a/include/configs/P3G4.h b/include/configs/P3G4.h index 17774a3..7712384 100644 --- a/include/configs/P3G4.h +++ b/include/configs/P3G4.h @@ -99,6 +99,7 @@ #define CONFIG_BOOTP_MASK (CONFIG_BOOTP_DEFAULT | \ CONFIG_BOOTP_BOOTFILESIZE) +#define CONFIG_TIMESTAMP /* Print image info with timestamp */ #define CONFIG_COMMANDS (CONFIG_CMD_DFL | CFG_CMD_ASKENV) diff --git a/include/configs/SL8245.h b/include/configs/SL8245.h index 4b69456..61896d0 100644 --- a/include/configs/SL8245.h +++ b/include/configs/SL8245.h @@ -51,6 +51,8 @@ #define CONFIG_BOOTDELAY 5 +#define CONFIG_TIMESTAMP /* Print image info with timestamp */ + #define CONFIG_COMMANDS (CONFIG_CMD_DFL | CFG_CMD_PCI) /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ @@ -68,7 +70,7 @@ /* Print Buffer Size */ #define CFG_PBSIZE (CFG_CBSIZE + sizeof(CFG_PROMPT) + 16) -#define CFG_MAXARGS 8 /* Max number of command args */ +#define CFG_MAXARGS 32 /* Max number of command args */ #define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ #define CFG_LOAD_ADDR 0x00400000 /* Default load address */ diff --git a/include/configs/Sandpoint8240.h b/include/configs/Sandpoint8240.h index 799d5d6..5bf184e 100644 --- a/include/configs/Sandpoint8240.h +++ b/include/configs/Sandpoint8240.h @@ -46,8 +46,39 @@ #endif #define CONFIG_CONS_INDEX 1 -#define CONFIG_BAUDRATE 115200 -#define CONFIG_DRAM_SPEED 100 /* MHz */ +#define CONFIG_BAUDRATE 9600 + +#define CONFIG_BOOTDELAY 5 /* autoboot after 5 seconds */ + +#define CONFIG_TIMESTAMP /* Print image info with timestamp */ + +#define CONFIG_PREBOOT "echo;" \ + "echo Type \"run net_nfs\" to mount root filesystem over NFS;" \ + "echo" + +#undef CONFIG_BOOTARGS + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "netdev=eth0\0" \ + "nfsargs=setenv bootargs root=/dev/nfs rw " \ + "nfsroot=$(serverip):$(rootpath)\0" \ + "ramargs=setenv bootargs root=/dev/ram rw\0" \ + "addip=setenv bootargs $(bootargs) " \ + "ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask)" \ + ":$(hostname):$(netdev):off panic=1\0" \ + "net_self=tftp $(kernel_addr) $(bootfile);" \ + "tftp $(ramdisk_addr) $(ramdisk);" \ + "run ramargs addip;" \ + "bootm $(kernel_addr) $(ramdisk_addr)\0" \ + "net_nfs=tftp $(kernel_addr) $(bootfile);" \ + "run nfsargs addip;bootm\0" \ + "rootpath=/opt/eldk/ppc_82xx\0" \ + "bootfile=/tftpboot/SP8240/uImage\0" \ + "ramdisk=/tftpboot/SP8240/uRamdisk\0" \ + "kernel_addr=200000\0" \ + "ramdisk_addr=400000\0" \ + "" +#define CONFIG_BOOTCOMMAND "run flash_self" #define CONFIG_COMMANDS ( (CONFIG_CMD_DFL & ~CFG_CMD_AUTOSCRIPT) | \ CFG_CMD_ELF | \ @@ -59,6 +90,7 @@ /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ #include <cmd_confdefs.h> +#define CONFIG_DRAM_SPEED 100 /* MHz */ /* * Miscellaneous configurable options diff --git a/include/configs/trab.h b/include/configs/trab.h index 4c33bdb..d96241a 100644 --- a/include/configs/trab.h +++ b/include/configs/trab.h @@ -1,5 +1,5 @@ /* - * (C) Copyright 2002 + * (C) Copyright 2002-2003 * Gary Jennejohn <gj@denx.de> * * Configuation settings for the TRAB board. @@ -40,6 +40,7 @@ #define CONFIG_S3C2400 1 /* in a SAMSUNG S3C2400 SoC */ #define CONFIG_TRAB 1 /* on a TRAB Board */ #undef CONFIG_TRAB_50MHZ /* run the CPU at 50 MHz */ +#define LITTLEENDIAN 1 /* used by usb_ohci.c */ /* input clock of PLL */ #define CONFIG_SYS_CLK_FREQ 12000000 /* TRAB has 12 MHz input clock */ @@ -67,6 +68,11 @@ #define CFG_EEPROM_PAGE_WRITE_BITS 3 /* 8 bytes page write mode on 24C04 */ #define CFG_EEPROM_PAGE_WRITE_DELAY_MS 10 +/* USB stuff */ +#define CONFIG_USB_OHCI 1 +#define CONFIG_USB_STORAGE 1 +#define CONFIG_DOS_PARTITION 1 + /* * Size of malloc() pool */ @@ -139,6 +145,8 @@ CONFIG_COMMANDS_ADD_HWFLOW | \ CONFIG_COMMANDS_ADD_VFD | \ CONFIG_COMMANDS_ADD_EEPROM | \ + CFG_CMD_USB | \ + CFG_CMD_FAT | \ CONFIG_COMMANDS_I2C ) #else #define CONFIG_COMMANDS (CONFIG_CMD_DFL | \ @@ -147,9 +155,14 @@ CONFIG_COMMANDS_ADD_HWFLOW | \ CONFIG_COMMANDS_ADD_VFD | \ CONFIG_COMMANDS_ADD_EEPROM | \ + CFG_CMD_USB | \ + CFG_CMD_FAT | \ CONFIG_COMMANDS_I2C ) #endif +/* moved up */ +#define CFG_HUSH_PARSER 1 /* use "hush" command parser */ + /* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ #include <cmd_confdefs.h> @@ -164,6 +177,28 @@ #define CONFIG_BOOTCOMMAND "run flash_nfs" #ifndef CONFIG_BIG_FLASH +#ifdef CFG_HUSH_PARSER +#define CONFIG_EXTRA_ENV_SETTINGS \ + "nfs_args=setenv bootargs root=/dev/nfs rw " \ + "nfsroot=$serverip:$rootpath\0" \ + "rootpath=/opt/eldk/arm_920TDI\0" \ + "ram_args=setenv bootargs root=/dev/ram rw\0" \ + "add_net=setenv bootargs $bootargs ethaddr=$ethaddr " \ + "ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname::off\0" \ + "add_misc=setenv bootargs $bootargs console=ttyS0 panic=1\0" \ + "load=tftp 0xC100000 /tftpboot/TRAB/u-boot.bin\0" \ + "update=protect off 1:0-8;era 1:0-8;cp.b 0xc100000 0 $filesize;" \ + "setenv filesize;saveenv\0" \ + "loadfile=/tftpboot/TRAB/uImage\0" \ + "loadaddr=c400000\0" \ + "net_load=tftpboot $loadaddr $loadfile\0" \ + "net_nfs=run net_load nfs_args add_net add_misc;bootm\0" \ + "kernel_addr=00040000\0" \ + "flash_nfs=run nfs_args add_net add_misc;bootm $kernel_addr\0" \ + "mdm_init1=ATZ\0" \ + "mdm_init2=ATS0=1\0" \ + "mdm_flow_control=rts/cts\0" +#else /* !CFG_HUSH_PARSER */ #define CONFIG_EXTRA_ENV_SETTINGS \ "nfs_args=setenv bootargs root=/dev/nfs rw " \ "nfsroot=$(serverip):$(rootpath)\0" \ @@ -184,7 +219,29 @@ "mdm_init1=ATZ\0" \ "mdm_init2=ATS0=1\0" \ "mdm_flow_control=rts/cts\0" +#endif /* CFG_HUSH_PARSER */ #else /* CONFIG_BIG_FLASH */ +#ifdef CFG_HUSH_PARSER +#define CONFIG_EXTRA_ENV_SETTINGS \ + "nfs_args=setenv bootargs root=/dev/nfs rw " \ + "nfsroot=$serverip:$rootpath\0" \ + "rootpath=/opt/eldk/arm_920TDI\0" \ + "ram_args=setenv bootargs root=/dev/ram rw\0" \ + "add_net=setenv bootargs $bootargs ethaddr=$ethaddr " \ + "ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname::off\0" \ + "add_misc=setenv bootargs $bootargs console=ttyS0 panic=1\0" \ + "load=tftp 0xC100000 /tftpboot/TRAB/u-boot.bin\0" \ + "update=protect off 1:0;era 1:0;cp.b 0xc100000 0 $filesize\0" \ + "loadfile=/tftpboot/TRAB/uImage\0" \ + "loadaddr=c400000\0" \ + "net_load=tftpboot $loadaddr $loadfile\0" \ + "net_nfs=run net_load nfs_args add_net add_misc;bootm\0" \ + "kernel_addr=00040000\0" \ + "flash_nfs=run nfs_args add_net add_misc;bootm $kernel_addr\0" \ + "mdm_init1=ATZ\0" \ + "mdm_init2=ATS0=1\0" \ + "mdm_flow_control=rts/cts\0" +#else /* !CFG_HUSH_PARSER */ #define CONFIG_EXTRA_ENV_SETTINGS \ "nfs_args=setenv bootargs root=/dev/nfs rw " \ "nfsroot=$(serverip):$(rootpath)\0" \ @@ -204,6 +261,7 @@ "mdm_init1=ATZ\0" \ "mdm_init2=ATS0=1\0" \ "mdm_flow_control=rts/cts\0" +#endif /* CFG_HUSH_PARSER */ #endif /* CONFIG_BIG_FLASH */ #if 0 /* disabled for development */ @@ -223,7 +281,6 @@ */ #define CFG_LONGHELP /* undef to save memory */ #define CFG_PROMPT "TRAB # " /* Monitor Command Prompt */ -/* #define CFG_HUSH_PARSER 1 */ /* use "hush" command parser */ #ifdef CFG_HUSH_PARSER #define CFG_PROMPT_HUSH_PS2 "> " #endif diff --git a/include/usb.h b/include/usb.h index edb6120..0008a9a 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 */ -#ifdef CONFIG_USB_UHCI +#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) 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); @@ -228,6 +228,11 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size); 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) \ ((unsigned short)( \ (((unsigned short)(x) & (unsigned short)0x00ffU) << 8) | \ @@ -238,6 +243,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate); (((unsigned long)(x) & (unsigned long)0x0000ff00UL) << 8) | \ (((unsigned long)(x) & (unsigned long)0x00ff0000UL) >> 8) | \ (((unsigned long)(x) & (unsigned long)0xff000000UL) >> 24) )) +#endif /* LITTLEENDIAN */ /* * Calling this entity a "pipe" is glorifying it. A USB pipe |