diff options
| -rw-r--r-- | cpu/arm920t/at91rm9200/usb.c | 6 | ||||
| -rw-r--r-- | cpu/arm920t/s3c24x0/Makefile | 2 | ||||
| -rw-r--r-- | cpu/arm920t/s3c24x0/usb.c | 72 | ||||
| -rw-r--r-- | cpu/pxa/usb.c | 5 | ||||
| -rw-r--r-- | drivers/usb_ohci.c | 133 | ||||
| -rw-r--r-- | drivers/usb_ohci.h | 2 | ||||
| -rw-r--r-- | include/configs/trab.h | 5 | 
7 files changed, 199 insertions, 26 deletions
| diff --git a/cpu/arm920t/at91rm9200/usb.c b/cpu/arm920t/at91rm9200/usb.c index 7b83f23eb..98e3cdd58 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 af9e4effc..f81f84dd2 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 000000000..8114034cc --- /dev/null +++ b/cpu/arm920t/s3c24x0/usb.c @@ -0,0 +1,72 @@ +/* + * (C) Copyright 2006 + * DENX Software Engineering <mk@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 <common.h> + +#if defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) +# if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) + +#if defined(CONFIG_S3C2400) +# include <s3c2400.h> +#elif defined(CONFIG_S3C2410) +# include <s3c2410.h> +#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 171615704..bff5bfb6a 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 c32245a24..9b3ca1232 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 <asm/arch/hardware.h> +#if defined(CONFIG_S3C2400) +# include <s3c2400.h> +#elif defined(CONFIG_S3C2410) +# include <s3c2410.h> +#elif defined(CONFIG_ARM920T) +# include <asm/arch/hardware.h> +#elif defined(CONFIG_CPU_MONAHANS) +# include <asm/arch/pxa-regs.h> +#endif  #include <malloc.h>  #include <usb.h>  #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 c37b5f600..a1b36ed83 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 85ee756e0..b6d4bcf17 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   */ |