diff options
author | Stefan Roese <sr@denx.de> | 2005-08-01 14:41:48 (GMT) |
---|---|---|
committer | Stefan Roese <stefan@debian.(none)> | 2005-08-01 14:41:48 (GMT) |
commit | c157d8e219694f5c3dea1ed3826668bdc67ca093 (patch) | |
tree | 0db7954a0b50e4b5f2a5da2e007ea82a965c6663 /cpu | |
parent | 15f36a5efd31fe608b43dc197ebbd80d3cecbe44 (diff) | |
download | u-boot-c157d8e219694f5c3dea1ed3826668bdc67ca093.tar.xz |
Add support for AMCC PPC440EP/GR eval boards Yosemite and Yellowstone.
Patch by Steven Blakeslee, 27 Jul 2005
Diffstat (limited to 'cpu')
-rw-r--r-- | cpu/ppc4xx/405gp_enet.c | 30 | ||||
-rw-r--r-- | cpu/ppc4xx/405gp_pci.c | 6 | ||||
-rw-r--r-- | cpu/ppc4xx/440gx_enet.c | 44 | ||||
-rw-r--r-- | cpu/ppc4xx/Makefile | 2 | ||||
-rw-r--r-- | cpu/ppc4xx/cpu.c | 44 | ||||
-rw-r--r-- | cpu/ppc4xx/cpu_init.c | 4 | ||||
-rw-r--r-- | cpu/ppc4xx/interrupts.c | 5 | ||||
-rw-r--r-- | cpu/ppc4xx/serial.c | 13 | ||||
-rw-r--r-- | cpu/ppc4xx/spd_sdram.c | 2343 | ||||
-rw-r--r-- | cpu/ppc4xx/speed.c | 95 | ||||
-rw-r--r-- | cpu/ppc4xx/start.S | 39 | ||||
-rw-r--r-- | cpu/ppc4xx/usb_ohci.c | 1648 | ||||
-rw-r--r-- | cpu/ppc4xx/usb_ohci.h | 410 | ||||
-rw-r--r-- | cpu/ppc4xx/usbdev.c | 214 | ||||
-rw-r--r-- | cpu/ppc4xx/usbdev.h | 31 | ||||
-rw-r--r-- | cpu/ppc4xx/vecnum.h | 1 |
16 files changed, 3686 insertions, 1243 deletions
diff --git a/cpu/ppc4xx/405gp_enet.c b/cpu/ppc4xx/405gp_enet.c index 9d8e2b6..9c17e31 100644 --- a/cpu/ppc4xx/405gp_enet.c +++ b/cpu/ppc4xx/405gp_enet.c @@ -227,7 +227,12 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) /* wait for reset */ while (mfdcr (malmcr) & MAL_CR_MMSR) { }; -#if defined(CONFIG_440) +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) + out32 (ZMII_FER, 0); + udelay(100); + /* set RII mode */ + out32 (ZMII_FER, ZMII_RMII | ZMII_MDI0); +#elif defined(CONFIG_440) /* set RMII mode */ out32 (ZMII_FER, ZMII_RMII | ZMII_MDI0); #endif /* CONFIG_440 */ @@ -461,6 +466,18 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) out32(ZMII_SSR, in32(ZMII_SSR) | 0x10000000); else out32(ZMII_SSR, in32(ZMII_SSR) & ~0x10000000); +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) + mfsdr(sdr_mfr, reg); + /* set speed */ + if (speed == _100BASET) { + out32(ZMII_SSR, in32(ZMII_SSR) | 0x10000000); + reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_100M; + } else { + reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_10M; + out32(ZMII_SSR, in32(ZMII_SSR) & ~0x10000000); + } + mtsdr(sdr_mfr, reg); +#endif #endif /* Enable broadcast and indvidual address */ @@ -498,11 +515,6 @@ static int ppc_4xx_eth_init (struct eth_device *dev, bd_t * bis) /* * Connect interrupt service routines */ -#if !defined(CONFIG_405EP) - /* 405EP has one EWU interrupt */ - irq_install_handler (VECNUM_EWU0 + (hw_p->devnum * 2), - (interrupt_handler_t *) enetInt, dev); -#endif irq_install_handler (VECNUM_ETH0 + (hw_p->devnum * 2), (interrupt_handler_t *) enetInt, dev); } @@ -993,12 +1005,6 @@ int ppc_4xx_eth_initialize (bd_t * bis) mtdcr (malrxdeir, 0xffffffff); /* clear pending interrupts */ mtdcr (malier, mal_ier); -#if defined(CONFIG_405EP) - /* 405EP has one EWU interrupt */ - irq_install_handler (VECNUM_EWU0, - (interrupt_handler_t *) enetInt, - dev); -#endif /* install MAL interrupt handler */ irq_install_handler (VECNUM_MS, (interrupt_handler_t *) enetInt, diff --git a/cpu/ppc4xx/405gp_pci.c b/cpu/ppc4xx/405gp_pci.c index 4f1754a..ebbcfd5 100644 --- a/cpu/ppc4xx/405gp_pci.c +++ b/cpu/ppc4xx/405gp_pci.c @@ -437,7 +437,7 @@ void pci_440_init (struct pci_controller *hose) * The PCI initialization sequence enable bit must be set ... if not abort * pci setup since updating the bit requires chip reset. *--------------------------------------------------------------------------*/ -#if defined (CONFIG_440_GX) +#if defined (CONFIG_440_GX) || defined (CONFIG_440_EP) || defined(CONFIG_440_GR) mfsdr(sdr_sdstp1,strap); if ( (strap & 0x00010000) == 0 ){ printf("PCI: SDR0_STRP1[PISE] not set.\n"); @@ -498,7 +498,7 @@ void pci_440_init (struct pci_controller *hose) #if defined(CONFIG_440_GX) out32r( PCIX0_BRDGOPT1, 0x04000060 ); /* PLB Rq pri highest */ out32r( PCIX0_BRDGOPT2, in32(PCIX0_BRDGOPT2) | 0x83 ); /* Enable host config, clear Timeout, ensure int src1 */ -#else +#elif defined(PCIX0_BRDGOPT1) out32r( PCIX0_BRDGOPT1, 0x10000060 ); /* PLB Rq pri highest */ out32r( PCIX0_BRDGOPT2, in32(PCIX0_BRDGOPT2) | 1 ); /* Enable host config */ #endif @@ -531,7 +531,9 @@ void pci_440_init (struct pci_controller *hose) #ifdef CONFIG_PCI_SCAN_SHOW printf("PCI: Bus Dev VenId DevId Class Int\n"); #endif +#if !defined(CONFIG_440_EP) && !defined(CONFIG_440_GR) out16r( PCIX0_CMD, in16r( PCIX0_CMD ) | PCI_COMMAND_MASTER); +#endif hose->last_busno = pci_hose_scan(hose); } } diff --git a/cpu/ppc4xx/440gx_enet.c b/cpu/ppc4xx/440gx_enet.c index 871f83b..24e6ef3 100644 --- a/cpu/ppc4xx/440gx_enet.c +++ b/cpu/ppc4xx/440gx_enet.c @@ -167,6 +167,8 @@ static void ppc_440x_eth_halt (struct eth_device *dev) /* EMAC RESET */ out32 (EMAC_M0 + hw_p->hw_addr, EMAC_M0_SRST); + hw_p->print_speed = 1; /* print speed message again next time */ + return; } @@ -277,7 +279,9 @@ static int ppc_440x_eth_init (struct eth_device *dev, bd_t * bis) unsigned short devnum; unsigned short reg_short; sys_info_t sysinfo; +#if defined(CONFIG_440_GX) int ethgroup; +#endif EMAC_440GX_HW_PST hw_p = dev->priv; @@ -289,7 +293,6 @@ static int ppc_440x_eth_init (struct eth_device *dev, bd_t * bis) /* Need to get the OPB frequency so we can access the PHY */ get_sys_info (&sysinfo); - msr = mfmsr (); mtmsr (msr & ~(MSR_EE)); /* disable interrupts */ @@ -320,7 +323,12 @@ static int ppc_440x_eth_init (struct eth_device *dev, bd_t * bis) /* MAL Channel RESET */ /* 1st reset MAL channel */ /* Note: writing a 0 to a channel has no effect */ +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) + mtdcr (maltxcarr, (MAL_TXRX_CASR >> (hw_p->devnum*2))); +#else mtdcr (maltxcarr, (MAL_TXRX_CASR >> hw_p->devnum)); +#endif + mtdcr (malrxcarr, (MAL_TXRX_CASR >> hw_p->devnum)); /* wait for reset */ @@ -354,7 +362,9 @@ static int ppc_440x_eth_init (struct eth_device *dev, bd_t * bis) out32 (ZMII_FER, 0); udelay (100); -#if defined(CONFIG_440_GX) +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) + out32 (ZMII_FER, (ZMII_FER_RMII | ZMII_FER_MDI) << ZMII_FER_V (devnum)); +#elif defined(CONFIG_440_GX) ethgroup = ppc_440x_eth_setup_bridge(devnum, bis); #else if ((devnum == 0) || (devnum == 1)) { @@ -499,6 +509,15 @@ static int ppc_440x_eth_init (struct eth_device *dev, bd_t * bis) (int) speed, (duplex == HALF) ? "HALF" : "FULL"); } +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) + mfsdr(sdr_mfr, reg); + if (speed == 100) { + reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_100M; + } else { + reg = (reg & ~SDR0_MFR_ZMII_MODE_MASK) | SDR0_MFR_ZMII_MODE_RMII_10M; + } + mtsdr(sdr_mfr, reg); +#endif /* Set ZMII/RGMII speed according to the phy link speed */ reg = in32 (ZMII_SSR); if ( (speed == 100) || (speed == 1000) ) @@ -618,8 +637,12 @@ static int ppc_440x_eth_init (struct eth_device *dev, bd_t * bis) switch (devnum) { case 1: /* setup MAL tx & rx channel pointers */ - mtdcr (maltxbattr, 0x0); +#if defined (CONFIG_440_EP) || defined (CONFIG_440_GR) + mtdcr (maltxctp2r, hw_p->tx); +#else mtdcr (maltxctp1r, hw_p->tx); +#endif + mtdcr (maltxbattr, 0x0); mtdcr (malrxbattr, 0x0); mtdcr (malrxctp1r, hw_p->rx); /* set RX buffer size */ @@ -658,7 +681,11 @@ static int ppc_440x_eth_init (struct eth_device *dev, bd_t * bis) } /* Enable MAL transmit and receive channels */ +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) + mtdcr (maltxcasr, (MAL_TXRX_CASR >> (hw_p->devnum*2))); +#else mtdcr (maltxcasr, (MAL_TXRX_CASR >> hw_p->devnum)); +#endif mtdcr (malrxcasr, (MAL_TXRX_CASR >> hw_p->devnum)); /* set transmit enable & receive enable */ @@ -1148,19 +1175,24 @@ static int ppc_440x_eth_rx (struct eth_device *dev) int ppc_440x_eth_initialize (bd_t * bis) { static int virgin = 0; - unsigned long pfc1; struct eth_device *dev; int eth_num = 0; - EMAC_440GX_HW_PST hw = NULL; +#if defined(CONFIG_440_GX) + unsigned long pfc1; + mfsdr (sdr_pfc1, pfc1); pfc1 &= ~(0x01e00000); pfc1 |= 0x01200000; mtsdr (sdr_pfc1, pfc1); +#endif /* set phy num and mode */ bis->bi_phynum[0] = CONFIG_PHY_ADDR; +#if defined(CONFIG_PHY1_ADDR) bis->bi_phynum[1] = CONFIG_PHY1_ADDR; +#endif +#if defined(CONFIG_440_GX) bis->bi_phynum[2] = CONFIG_PHY2_ADDR; bis->bi_phynum[3] = CONFIG_PHY3_ADDR; bis->bi_phymode[0] = 0; @@ -1171,6 +1203,7 @@ int ppc_440x_eth_initialize (bd_t * bis) #if defined (CONFIG_440_GX) ppc_440x_eth_setup_bridge(0, bis); #endif +#endif for (eth_num = 0; eth_num < EMAC_NUM_DEV; eth_num++) { @@ -1256,6 +1289,7 @@ int ppc_440x_eth_initialize (bd_t * bis) } hw->devnum = eth_num; + hw->print_speed = 1; sprintf (dev->name, "ppc_440x_eth%d", eth_num); dev->priv = (void *) hw; diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile index a841109..5b16754 100644 --- a/cpu/ppc4xx/Makefile +++ b/cpu/ppc4xx/Makefile @@ -31,7 +31,7 @@ COBJS = 405gp_enet.o 405gp_pci.o 440gx_enet.o \ bedbug_405.o commproc.o \ cpu.o cpu_init.o i2c.o interrupts.o \ miiphy.o miiphy_440.o sdram.o serial.o \ - spd_sdram.o speed.o traps.o + spd_sdram.o speed.o traps.o usb_ohci.o usbdev.o OBJS = $(AOBJS) $(COBJS) diff --git a/cpu/ppc4xx/cpu.c b/cpu/ppc4xx/cpu.c index 06acb81..ae45a23 100644 --- a/cpu/ppc4xx/cpu.c +++ b/cpu/ppc4xx/cpu.c @@ -71,17 +71,17 @@ int checkcpu (void) get_sys_info(&sys_info); #ifdef CONFIG_405GP - puts ("IBM PowerPC 405GP"); + puts ("AMCC PowerPC 405GP"); if (pvr == PVR_405GPR_RB) { putc('r'); } puts (" Rev. "); #endif #ifdef CONFIG_405CR - puts ("IBM PowerPC 405CR Rev. "); + puts ("AMCC PowerPC 405CR Rev. "); #endif #ifdef CONFIG_405EP - puts ("IBM PowerPC 405EP Rev. "); + puts ("AMCC PowerPC 405EP Rev. "); #endif switch (pvr) { case PVR_405GP_RB: @@ -152,10 +152,10 @@ int checkcpu (void) #endif #if defined(CONFIG_440) - puts ("IBM PowerPC 440 G"); + puts ("AMCC PowerPC 440 "); switch(pvr) { case PVR_440GP_RB: - puts("P Rev. B"); + puts("GP Rev. B"); /* See errata 1.12: CHIP_4 */ if ((mfdcr(cpc0_sys0) != mfdcr(cpc0_strp0)) || (mfdcr(cpc0_sys1) != mfdcr(cpc0_strp1)) ){ @@ -167,19 +167,35 @@ int checkcpu (void) } break; case PVR_440GP_RC: - puts("P Rev. C"); + puts("GP Rev. C"); break; case PVR_440GX_RA: - puts("X Rev. A"); + puts("GX Rev. A"); break; case PVR_440GX_RB: - puts("X Rev. B"); + puts("GX Rev. B"); break; case PVR_440GX_RC: - puts("X Rev. C"); + puts("GX Rev. C"); break; +#if defined(CONFIG_440_GR) + case PVR_440EP_RA: + puts("GR Rev. A"); + break; + case PVR_440EP_RB: + puts("GR Rev. B"); + break; +#else + case PVR_440EP_RA: + puts("EP Rev. A"); + break; + case PVR_440EP_RB: + puts("EP Rev. B"); + break; +#endif + default: - printf (" UNKNOWN (PVR=%08x)", pvr); + printf ("UNKNOWN (PVR=%08x)", pvr); break; } #endif @@ -193,6 +209,12 @@ int checkcpu (void) int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { +#if defined(CONFIG_YOSEMITE) || defined(CONFIG_YELLOWSTONE) + /*give reset to BCSR*/ + *(unsigned char*)(CFG_BCSR_BASE | 0x06) = 0x09; + +#else + /* * Initiate system reset in debug control register DBCR */ @@ -202,6 +224,8 @@ int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) #else __asm__ __volatile__("mtspr 0x3f2, 3"); #endif + +#endif/* defined(CONFIG_YOSEMITE) || defined(CONFIG_YELLOWSTONE)*/ return 1; } diff --git a/cpu/ppc4xx/cpu_init.c b/cpu/ppc4xx/cpu_init.c index 25508e7..74f0135 100644 --- a/cpu/ppc4xx/cpu_init.c +++ b/cpu/ppc4xx/cpu_init.c @@ -188,7 +188,11 @@ cpu_init_f (void) unsigned long val; val = mfspr(tcr); +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) + val |= 0xb8000000; /* generate system reset after 1.34 seconds */ +#else val |= 0xf0000000; /* generate system reset after 2.684 seconds */ +#endif mtspr(tcr, val); val = mfspr(tsr); diff --git a/cpu/ppc4xx/interrupts.c b/cpu/ppc4xx/interrupts.c index 90899dd..c0e51f9 100644 --- a/cpu/ppc4xx/interrupts.c +++ b/cpu/ppc4xx/interrupts.c @@ -430,7 +430,10 @@ void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg) #endif /* CONFIG_440_GX */ #endif /* CONFIG_440 */ - if (irqa[i].handler != NULL) { + /* + * print warning when replacing with a different irq vector + */ + if ((irqa[i].handler != NULL) && (irqa[i].handler != handler)) { printf ("Interrupt vector %d: handler 0x%x replacing 0x%x\n", vec, (uint) handler, (uint) irqa[i].handler); } diff --git a/cpu/ppc4xx/serial.c b/cpu/ppc4xx/serial.c index 4abd3fc..92f8ddb 100644 --- a/cpu/ppc4xx/serial.c +++ b/cpu/ppc4xx/serial.c @@ -269,9 +269,14 @@ int serial_tstc () #if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_440) || defined(CONFIG_405EP) #if defined(CONFIG_440) +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) +#define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000300 +#define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000400 +#else #define UART0_BASE CFG_PERIPHERAL_BASE + 0x00000200 #define UART1_BASE CFG_PERIPHERAL_BASE + 0x00000300 -#if defined(CONFIG_440_GX) +#endif +#if defined(CONFIG_440_GX) || defined(CONFIG_440_EP) || defined(CONFIG_440_GR) #define CR0_MASK 0xdfffffff #define CR0_EXTCLK_ENA 0x00800000 #define CR0_UDIV_POS 0 @@ -301,14 +306,14 @@ int serial_tstc () #if defined(CONFIG_UART1_CONSOLE) #define ACTING_UART0_BASE UART1_BASE #define ACTING_UART1_BASE UART0_BASE -#if defined(CONFIG_440_GX) +#if defined(CONFIG_440_GX) || defined(CONFIG_440_EP) || defined(CONFIG_440_GR) #define UART0_SDR sdr_uart1 #define UART1_SDR sdr_uart0 #endif /* CONFIG_440_GX */ #else #define ACTING_UART0_BASE UART0_BASE #define ACTING_UART1_BASE UART1_BASE -#if defined(CONFIG_440_GX) +#if defined(CONFIG_440_GX) || defined(CONFIG_440_EP) || defined(CONFIG_440_GR) #define UART0_SDR sdr_uart0 #define UART1_SDR sdr_uart1 #endif /* CONFIG_440_GX */ @@ -460,7 +465,7 @@ int serial_init(void) serial_divs (gd->baudrate, &udiv, &bdiv); #endif -#if defined(CONFIG_440_GX) +#if defined(CONFIG_440_GX) || defined(CONFIG_440_EP) || defined(CONFIG_440_GR) reg |= udiv << CR0_UDIV_POS; /* set the UART divisor */ #if defined(CONFIG_SERIAL_MULTI) if (UART0_BASE == dev_base) { diff --git a/cpu/ppc4xx/spd_sdram.c b/cpu/ppc4xx/spd_sdram.c index 794a72c..520107a 100644 --- a/cpu/ppc4xx/spd_sdram.c +++ b/cpu/ppc4xx/spd_sdram.c @@ -16,6 +16,9 @@ * Jun Gu, Artesyn Technology, jung@artesyncp.com * Support for IBM 440 based on OpenBIOS draminit.c from IBM. * + * (C) Copyright 2005 + * Stefan Roese, DENX Software Engineering, sr@denx.de. + * * See file CREDITS for list of people who contributed to this * project. * @@ -53,7 +56,9 @@ #define CFG_I2C_SLAVE 0xFE #endif -#ifndef CONFIG_440 /* for 405 WALNUT board */ +#define ONE_BILLION 1000000000 + +#ifndef CONFIG_440 /* for 405 WALNUT/SYCAMORE/BUBINGA boards */ #define SDRAM0_CFG_DCE 0x80000000 #define SDRAM0_CFG_SRE 0x40000000 @@ -111,7 +116,7 @@ int spd_read(uint addr); long int spd_sdram(int(read_spd)(uint addr)) { - int bus_period,tmp,row,col; + int tmp,row,col; int total_size,bank_size,bank_code; int ecc_on; int mode; @@ -141,226 +146,189 @@ long int spd_sdram(int(read_spd)(uint addr)) int t_rc; int min_cas; - if(read_spd == 0){ - read_spd=spd_read; - /* - * Make sure I2C controller is initialized - * before continuing. - */ - i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE); - } - + PPC405_SYS_INFO sys_info; + unsigned long bus_period_x_10; /* - * Calculate the bus period, we do it this - * way to minimize stack utilization. + * get the board info */ -#ifndef CONFIG_405EP - tmp = (mfdcr(pllmd) >> (31-6)) & 0xf; /* get FBDV bits */ - tmp = CONFIG_SYS_CLK_FREQ * tmp; /* get plb freq */ -#else - { - unsigned long freqCPU; - unsigned long pllmr0; - unsigned long pllmr1; - unsigned long pllFbkDiv; - unsigned long pllPlbDiv; - unsigned long pllmr0_ccdv; - - /* - * Read PLL Mode registers - */ - pllmr0 = mfdcr (cpc0_pllmr0); - pllmr1 = mfdcr (cpc0_pllmr1); - - pllFbkDiv = ((pllmr1 & PLLMR1_FBMUL_MASK) >> 20); - if (pllFbkDiv == 0) { - pllFbkDiv = 16; - } - pllPlbDiv = ((pllmr0 & PLLMR0_CPU_TO_PLB_MASK) >> 16) + 1; - - /* - * Determine CPU clock frequency - */ - pllmr0_ccdv = ((pllmr0 & PLLMR0_CPU_DIV_MASK) >> 20) + 1; - if (pllmr1 & PLLMR1_SSCS_MASK) { - freqCPU = (CONFIG_SYS_CLK_FREQ * pllFbkDiv) / pllmr0_ccdv; - } else { - freqCPU = CONFIG_SYS_CLK_FREQ / pllmr0_ccdv; - } + get_sys_info(&sys_info); + bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10); + if (read_spd == 0){ + read_spd=spd_read; /* - * Determine PLB clock frequency + * Make sure I2C controller is initialized + * before continuing. */ - tmp = freqCPU / pllPlbDiv; + i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE); } -#endif - bus_period = sdram_HZ_to_ns(tmp); /* get sdram speed */ /* Make shure we are using SDRAM */ - if (read_spd(2) != 0x04){ - SPD_ERR("SDRAM - non SDRAM memory module found\n"); - } - -/*------------------------------------------------------------------ - configure memory timing register + if (read_spd(2) != 0x04) { + SPD_ERR("SDRAM - non SDRAM memory module found\n"); + } - data from DIMM: - 27 IN Row Precharge Time ( t RP) - 29 MIN RAS to CAS Delay ( t RCD) - 127 Component and Clock Detail ,clk0-clk3, junction temp, CAS - -------------------------------------------------------------------*/ + /* ------------------------------------------------------------------ + * configure memory timing register + * + * data from DIMM: + * 27 IN Row Precharge Time ( t RP) + * 29 MIN RAS to CAS Delay ( t RCD) + * 127 Component and Clock Detail ,clk0-clk3, junction temp, CAS + * -------------------------------------------------------------------*/ - /* - * first figure out which cas latency mode to use - * use the min supported mode - */ + /* + * first figure out which cas latency mode to use + * use the min supported mode + */ tmp = read_spd(127) & 0x6; - if(tmp == 0x02){ /* only cas = 2 supported */ - min_cas = 2; + if (tmp == 0x02){ /* only cas = 2 supported */ + min_cas = 2; /* t_ck = read_spd(9); */ /* t_ac = read_spd(10); */ - } - else if (tmp == 0x04){ /* only cas = 3 supported */ - min_cas = 3; + } else if (tmp == 0x04) { /* only cas = 3 supported */ + min_cas = 3; /* t_ck = read_spd(9); */ /* t_ac = read_spd(10); */ - } - else if (tmp == 0x06){ /* 2,3 supported, so use 2 */ - min_cas = 2; + } else if (tmp == 0x06) { /* 2,3 supported, so use 2 */ + min_cas = 2; /* t_ck = read_spd(23); */ /* t_ac = read_spd(24); */ - } - else { - SPD_ERR("SDRAM - unsupported CAS latency \n"); + } else { + SPD_ERR("SDRAM - unsupported CAS latency \n"); } - /* get some timing values, t_rp,t_rcd,t_ras,t_rc - */ - t_rp = read_spd(27); - t_rcd = read_spd(29); - t_ras = read_spd(30); - t_rc = t_ras + t_rp; - - /* The following timing calcs subtract 1 before deviding. - * this has effect of using ceiling instead of floor rounding, - * and also subtracting 1 to convert number to reg value - */ - /* set up CASL */ - sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT; - /* set up PTA */ - sdram0_tr |= (((t_rp - 1)/bus_period) & 0x3) << SDRAM0_TR_PTA_SHIFT; - /* set up CTP */ - tmp = ((t_rc - t_rcd - t_rp -1) / bus_period) & 0x3; - if(tmp<1) tmp=1; - sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT; - /* set LDF = 2 cycles, reg value = 1 */ - sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT; - /* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */ - tmp = ( (t_rc - 1) / bus_period)-3; - if(tmp<0)tmp=0; - if(tmp>6)tmp=6; + /* get some timing values, t_rp,t_rcd,t_ras,t_rc + */ + t_rp = read_spd(27); + t_rcd = read_spd(29); + t_ras = read_spd(30); + t_rc = t_ras + t_rp; + + /* The following timing calcs subtract 1 before deviding. + * this has effect of using ceiling instead of floor rounding, + * and also subtracting 1 to convert number to reg value + */ + /* set up CASL */ + sdram0_tr = (min_cas - 1) << SDRAM0_TR_CASL_SHIFT; + /* set up PTA */ + sdram0_tr |= ((((t_rp - 1) * 10)/bus_period_x_10) & 0x3) << SDRAM0_TR_PTA_SHIFT; + /* set up CTP */ + tmp = (((t_rc - t_rcd - t_rp -1) * 10) / bus_period_x_10) & 0x3; + if (tmp < 1) + tmp = 1; + sdram0_tr |= tmp << SDRAM0_TR_CTP_SHIFT; + /* set LDF = 2 cycles, reg value = 1 */ + sdram0_tr |= 1 << SDRAM0_TR_LDF_SHIFT; + /* set RFTA = t_rfc/bus_period, use t_rfc = t_rc */ + tmp = (((t_rc - 1) * 10) / bus_period_x_10) - 3; + if (tmp < 0) + tmp = 0; + if (tmp > 6) + tmp = 6; sdram0_tr |= tmp << SDRAM0_TR_RFTA_SHIFT; - /* set RCD = t_rcd/bus_period*/ - sdram0_tr |= (((t_rcd - 1) / bus_period) &0x3) << SDRAM0_TR_RCD_SHIFT ; + /* set RCD = t_rcd/bus_period*/ + sdram0_tr |= ((((t_rcd - 1) * 10) / bus_period_x_10) &0x3) << SDRAM0_TR_RCD_SHIFT ; -/*------------------------------------------------------------------ - configure RTR register - -------------------------------------------------------------------*/ - row = read_spd(3); - col = read_spd(4); - tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */ - switch(tmp){ + /*------------------------------------------------------------------ + * configure RTR register + * -------------------------------------------------------------------*/ + row = read_spd(3); + col = read_spd(4); + tmp = read_spd(12) & 0x7f ; /* refresh type less self refresh bit */ + switch (tmp) { case 0x00: - tmp=15625; - break; + tmp = 15625; + break; case 0x01: - tmp=15625/4; - break; + tmp = 15625 / 4; + break; case 0x02: - tmp=15625/2; - break; + tmp = 15625 / 2; + break; case 0x03: - tmp=15625*2; - break; + tmp = 15625 * 2; + break; case 0x04: - tmp=15625*4; - break; + tmp = 15625 * 4; + break; case 0x05: - tmp=15625*8; - break; + tmp = 15625 * 8; + break; default: - SPD_ERR("SDRAM - Bad refresh period \n"); + SPD_ERR("SDRAM - Bad refresh period \n"); } /* convert from nsec to bus cycles */ - tmp = tmp/bus_period; - sdram0_rtr = (tmp & 0x3ff8)<< SDRAM0_RTR_SHIFT; + tmp = (tmp * 10) / bus_period_x_10; + sdram0_rtr = (tmp & 0x3ff8) << SDRAM0_RTR_SHIFT; -/*------------------------------------------------------------------ - determine the number of banks used - -------------------------------------------------------------------*/ + /*------------------------------------------------------------------ + * determine the number of banks used + * -------------------------------------------------------------------*/ /* byte 7:6 is module data width */ - if(read_spd(7) != 0) - SPD_ERR("SDRAM - unsupported module width\n"); + if (read_spd(7) != 0) + SPD_ERR("SDRAM - unsupported module width\n"); tmp = read_spd(6); if (tmp < 32) - SPD_ERR("SDRAM - unsupported module width\n"); + SPD_ERR("SDRAM - unsupported module width\n"); else if (tmp < 64) - bank_cnt=1; /* one bank per sdram side */ + bank_cnt = 1; /* one bank per sdram side */ else if (tmp < 73) - bank_cnt=2; /* need two banks per side */ + bank_cnt = 2; /* need two banks per side */ else if (tmp < 161) - bank_cnt=4; /* need four banks per side */ + bank_cnt = 4; /* need four banks per side */ else - SPD_ERR("SDRAM - unsupported module width\n"); + SPD_ERR("SDRAM - unsupported module width\n"); /* byte 5 is the module row count (refered to as dimm "sides") */ tmp = read_spd(5); - if(tmp==1); - else if(tmp==2) bank_cnt *=2; - else if(tmp==4) bank_cnt *=4; - else bank_cnt = 8; /* 8 is an error code */ + if (tmp == 1) + ; + else if (tmp==2) + bank_cnt *= 2; + else if (tmp==4) + bank_cnt *= 4; + else + bank_cnt = 8; /* 8 is an error code */ - if(bank_cnt > 4) /* we only have 4 banks to work with */ - SPD_ERR("SDRAM - unsupported module rows for this width\n"); + if (bank_cnt > 4) /* we only have 4 banks to work with */ + SPD_ERR("SDRAM - unsupported module rows for this width\n"); /* now check for ECC ability of module. We only support ECC * on 32 bit wide devices with 8 bit ECC. */ - if ( (read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8) ){ - sdram0_ecccfg=0xf<<SDRAM0_ECCCFG_SHIFT; - ecc_on = 1; - } - else{ - sdram0_ecccfg=0; - ecc_on = 0; + if ((read_spd(11)==2) && (read_spd(6)==40) && (read_spd(14)==8)) { + sdram0_ecccfg = 0xf << SDRAM0_ECCCFG_SHIFT; + ecc_on = 1; + } else { + sdram0_ecccfg = 0; + ecc_on = 0; } -/*------------------------------------------------------------------ - calculate total size - -------------------------------------------------------------------*/ + /*------------------------------------------------------------------ + * calculate total size + * -------------------------------------------------------------------*/ /* calculate total size and do sanity check */ tmp = read_spd(31); - total_size=1<<22; /* total_size = 4MB */ + total_size = 1 << 22; /* total_size = 4MB */ /* now multiply 4M by the smallest device row density */ /* note that we don't support asymetric rows */ - while (((tmp & 0x0001) == 0) && (tmp != 0)){ - total_size= total_size<<1; - tmp = tmp>>1; - } + while (((tmp & 0x0001) == 0) && (tmp != 0)) { + total_size = total_size << 1; + tmp = tmp >> 1; + } total_size *= read_spd(5); /* mult by module rows (dimm sides) */ -/*------------------------------------------------------------------ - map rows * cols * banks to a mode - -------------------------------------------------------------------*/ + /*------------------------------------------------------------------ + * map rows * cols * banks to a mode + * -------------------------------------------------------------------*/ - switch( row ) - { + switch (row) { case 11: - switch ( col ) - { + switch (col) { case 8: mode=4; /* mode 5 */ break; @@ -369,12 +337,11 @@ long int spd_sdram(int(read_spd)(uint addr)) mode=0; /* mode 1 */ break; default: - SPD_ERR("SDRAM - unsupported mode\n"); + SPD_ERR("SDRAM - unsupported mode\n"); } break; case 12: - switch ( col ) - { + switch (col) { case 8: mode=3; /* mode 4 */ break; @@ -383,37 +350,36 @@ long int spd_sdram(int(read_spd)(uint addr)) mode=1; /* mode 2 */ break; default: - SPD_ERR("SDRAM - unsupported mode\n"); + SPD_ERR("SDRAM - unsupported mode\n"); } break; case 13: - switch ( col ) - { + switch (col) { case 8: mode=5; /* mode 6 */ break; case 9: case 10: - if (read_spd(17) ==2 ) - mode=6; /* mode 7 */ + if (read_spd(17) == 2) + mode = 6; /* mode 7 */ else - mode=2; /* mode 3 */ + mode = 2; /* mode 3 */ break; case 11: - mode=2; /* mode 3 */ + mode = 2; /* mode 3 */ break; default: - SPD_ERR("SDRAM - unsupported mode\n"); + SPD_ERR("SDRAM - unsupported mode\n"); } break; default: - SPD_ERR("SDRAM - unsupported mode\n"); + SPD_ERR("SDRAM - unsupported mode\n"); } -/*------------------------------------------------------------------ - using the calculated values, compute the bank - config register values. - -------------------------------------------------------------------*/ + /*------------------------------------------------------------------ + * using the calculated values, compute the bank + * config register values. + * -------------------------------------------------------------------*/ sdram0_b1cr = 0; sdram0_b2cr = 0; sdram0_b3cr = 0; @@ -421,44 +387,46 @@ long int spd_sdram(int(read_spd)(uint addr)) /* compute the size of each bank */ bank_size = total_size / bank_cnt; /* convert bank size to bank size code for ppc4xx - by takeing log2(bank_size) - 22 */ - tmp=bank_size; /* start with tmp = bank_size */ - bank_code=0; /* and bank_code = 0 */ - while (tmp>1){ /* this takes log2 of tmp */ + by takeing log2(bank_size) - 22 */ + tmp = bank_size; /* start with tmp = bank_size */ + bank_code = 0; /* and bank_code = 0 */ + while (tmp > 1) { /* this takes log2 of tmp */ bank_code++; /* and stores result in bank_code */ - tmp=tmp>>1; - } /* bank_code is now log2(bank_size) */ - bank_code-=22; /* subtract 22 to get the code */ + tmp = tmp >> 1; + } /* bank_code is now log2(bank_size) */ + bank_code -= 22; /* subtract 22 to get the code */ tmp = SDRAM0_BXCR_SZ(bank_code) | SDRAM0_BXCR_AM(mode) | 1; - sdram0_b0cr = (bank_size) * 0 | tmp; + sdram0_b0cr = (bank_size * 0) | tmp; #ifndef CONFIG_405EP /* not on PPC405EP */ - if(bank_cnt>1) sdram0_b2cr = (bank_size) * 1 | tmp; - if(bank_cnt>2) sdram0_b1cr = (bank_size) * 2 | tmp; - if(bank_cnt>3) sdram0_b3cr = (bank_size) * 3 | tmp; + if (bank_cnt > 1) + sdram0_b2cr = (bank_size * 1) | tmp; + if (bank_cnt > 2) + sdram0_b1cr = (bank_size * 2) | tmp; + if (bank_cnt > 3) + sdram0_b3cr = (bank_size * 3) | tmp; #else /* PPC405EP chip only supports two SDRAM banks */ - if(bank_cnt>1) sdram0_b1cr = (bank_size) * 1 | tmp; - if(bank_cnt>2) total_size -= (bank_size) * (bank_cnt - 2); + if (bank_cnt > 1) + sdram0_b1cr = (bank_size * 1) | tmp; + if (bank_cnt > 2) + total_size = 2 * bank_size; #endif - /* * enable sdram controller DCE=1 * enable burst read prefetch to 32 bytes BRPF=2 * leave other functions off */ -/*------------------------------------------------------------------ - now that we've done our calculations, we are ready to - program all the registers. - -------------------------------------------------------------------*/ - + /*------------------------------------------------------------------ + * now that we've done our calculations, we are ready to + * program all the registers. + * -------------------------------------------------------------------*/ #define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data) /* disable memcontroller so updates work */ - sdram0_cfg = 0; - mtsdram0( mem_mcopt1, sdram0_cfg ); + mtsdram0( mem_mcopt1, 0 ); #ifndef CONFIG_405EP /* not on PPC405EP */ mtsdram0( mem_besra , sdram0_besr0 ); @@ -479,15 +447,10 @@ long int spd_sdram(int(read_spd)(uint addr)) /* SDRAM have a power on delay, 500 micro should do */ udelay(500); sdram0_cfg = SDRAM0_CFG_DCE | SDRAM0_CFG_BRPF(1) | SDRAM0_CFG_ECCDD | SDRAM0_CFG_EMDULR; - if(ecc_on) sdram0_cfg |= SDRAM0_CFG_MEMCHK; - mtsdram0( mem_mcopt1, sdram0_cfg ); - + if (ecc_on) + sdram0_cfg |= SDRAM0_CFG_MEMCHK; + mtsdram0(mem_mcopt1, sdram0_cfg); - /* kernel 2.4.2 from mvista has a bug with memory over 128MB */ -#ifdef MVISTA_MEM_BUG - if (total_size > 128*1024*1024 ) - total_size=128*1024*1024; -#endif return (total_size); } @@ -504,8 +467,8 @@ int spd_read(uint addr) #else /* CONFIG_440 */ /*----------------------------------------------------------------------------- -| Memory Controller Options 0 -+-----------------------------------------------------------------------------*/ + | Memory Controller Options 0 + +-----------------------------------------------------------------------------*/ #define SDRAM_CFG0_DCEN 0x80000000 /* SDRAM Controller Enable */ #define SDRAM_CFG0_MCHK_MASK 0x30000000 /* Memory data errchecking mask */ #define SDRAM_CFG0_MCHK_NON 0x00000000 /* No ECC generation */ @@ -520,39 +483,39 @@ int spd_read(uint addr) #define SDRAM_CFG0_PDP 0x00200000 /* Page deallocation policy */ /*----------------------------------------------------------------------------- -| Memory Controller Options 1 -+-----------------------------------------------------------------------------*/ + | Memory Controller Options 1 + +-----------------------------------------------------------------------------*/ #define SDRAM_CFG1_SRE 0x80000000 /* Self-Refresh Entry */ #define SDRAM_CFG1_PMEN 0x40000000 /* Power Management Enable */ /*-----------------------------------------------------------------------------+ -| SDRAM DEVPOT Options -+-----------------------------------------------------------------------------*/ + | SDRAM DEVPOT Options + +-----------------------------------------------------------------------------*/ #define SDRAM_DEVOPT_DLL 0x80000000 #define SDRAM_DEVOPT_DS 0x40000000 /*-----------------------------------------------------------------------------+ -| SDRAM MCSTS Options -+-----------------------------------------------------------------------------*/ + | SDRAM MCSTS Options + +-----------------------------------------------------------------------------*/ #define SDRAM_MCSTS_MRSC 0x80000000 #define SDRAM_MCSTS_SRMS 0x40000000 #define SDRAM_MCSTS_CIS 0x20000000 /*----------------------------------------------------------------------------- -| SDRAM Refresh Timer Register -+-----------------------------------------------------------------------------*/ + | SDRAM Refresh Timer Register + +-----------------------------------------------------------------------------*/ #define SDRAM_RTR_RINT_MASK 0xFFFF0000 #define SDRAM_RTR_RINT_ENCODE(n) (((n) << 16) & SDRAM_RTR_RINT_MASK) #define sdram_HZ_to_ns(hertz) (1000000000/(hertz)) /*-----------------------------------------------------------------------------+ -| SDRAM UABus Base Address Reg -+-----------------------------------------------------------------------------*/ + | SDRAM UABus Base Address Reg + +-----------------------------------------------------------------------------*/ #define SDRAM_UABBA_UBBA_MASK 0x0000000F /*-----------------------------------------------------------------------------+ -| Memory Bank 0-7 configuration -+-----------------------------------------------------------------------------*/ + | Memory Bank 0-7 configuration + +-----------------------------------------------------------------------------*/ #define SDRAM_BXCR_SDBA_MASK 0xff800000 /* Base address */ #define SDRAM_BXCR_SDSZ_MASK 0x000e0000 /* Size */ #define SDRAM_BXCR_SDSZ_8 0x00020000 /* 8M */ @@ -570,8 +533,8 @@ int spd_read(uint addr) #define SDRAM_BXCR_SDBE 0x00000001 /* Memory Bank Enable */ /*-----------------------------------------------------------------------------+ -| SDRAM TR0 Options -+-----------------------------------------------------------------------------*/ + | SDRAM TR0 Options + +-----------------------------------------------------------------------------*/ #define SDRAM_TR0_SDWR_MASK 0x80000000 #define SDRAM_TR0_SDWR_2_CLK 0x00000000 #define SDRAM_TR0_SDWR_3_CLK 0x80000000 @@ -609,8 +572,8 @@ int spd_read(uint addr) #define SDRAM_TR0_SDRD_4_CLK 0x00000003 /*-----------------------------------------------------------------------------+ -| SDRAM TR1 Options -+-----------------------------------------------------------------------------*/ + | SDRAM TR1 Options + +-----------------------------------------------------------------------------*/ #define SDRAM_TR1_RDSS_MASK 0xC0000000 #define SDRAM_TR1_RDSS_TR0 0x00000000 #define SDRAM_TR1_RDSS_TR1 0x40000000 @@ -630,8 +593,8 @@ int spd_read(uint addr) #define SDRAM_TR1_RDCT_MAX 0x000001FF /*-----------------------------------------------------------------------------+ -| SDRAM WDDCTR Options -+-----------------------------------------------------------------------------*/ + | SDRAM WDDCTR Options + +-----------------------------------------------------------------------------*/ #define SDRAM_WDDCTR_WRCP_MASK 0xC0000000 #define SDRAM_WDDCTR_WRCP_0DEG 0x00000000 #define SDRAM_WDDCTR_WRCP_90DEG 0x40000000 @@ -639,8 +602,8 @@ int spd_read(uint addr) #define SDRAM_WDDCTR_DCD_MASK 0x000001FF /*-----------------------------------------------------------------------------+ -| SDRAM CLKTR Options -+-----------------------------------------------------------------------------*/ + | SDRAM CLKTR Options + +-----------------------------------------------------------------------------*/ #define SDRAM_CLKTR_CLKP_MASK 0xC0000000 #define SDRAM_CLKTR_CLKP_0DEG 0x00000000 #define SDRAM_CLKTR_CLKP_90DEG 0x40000000 @@ -648,18 +611,17 @@ int spd_read(uint addr) #define SDRAM_CLKTR_DCDT_MASK 0x000001FF /*-----------------------------------------------------------------------------+ -| SDRAM DLYCAL Options -+-----------------------------------------------------------------------------*/ + | SDRAM DLYCAL Options + +-----------------------------------------------------------------------------*/ #define SDRAM_DLYCAL_DLCV_MASK 0x000003FC #define SDRAM_DLYCAL_DLCV_ENCODE(x) (((x)<<2) & SDRAM_DLYCAL_DLCV_MASK) #define SDRAM_DLYCAL_DLCV_DECODE(x) (((x) & SDRAM_DLYCAL_DLCV_MASK)>>2) /*-----------------------------------------------------------------------------+ -| General Definition -+-----------------------------------------------------------------------------*/ + | General Definition + +-----------------------------------------------------------------------------*/ #define DEFAULT_SPD_ADDR1 0x53 #define DEFAULT_SPD_ADDR2 0x52 -#define ONE_BILLION 1000000000 #define MAXBANKS 4 /* at most 4 dimm banks */ #define MAX_SPD_BYTES 256 #define NUMHALFCYCLES 4 @@ -670,22 +632,22 @@ int spd_read(uint addr) #define FALSE 0 const unsigned long test[NUMMEMTESTS][NUMMEMWORDS] = { - {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, - 0xFFFFFFFF, 0xFFFFFFFF}, - {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, - 0x00000000, 0x00000000}, - {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, - 0x55555555, 0x55555555}, - {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, - 0xAAAAAAAA, 0xAAAAAAAA}, - {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, - 0x5A5A5A5A, 0x5A5A5A5A}, - {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, - 0xA5A5A5A5, 0xA5A5A5A5}, - {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, - 0x55AA55AA, 0x55AA55AA}, - {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, - 0xAA55AA55, 0xAA55AA55} + {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, + 0xFFFFFFFF, 0xFFFFFFFF}, + {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, + 0x00000000, 0x00000000}, + {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, + 0x55555555, 0x55555555}, + {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, + 0xAAAAAAAA, 0xAAAAAAAA}, + {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, + 0x5A5A5A5A, 0x5A5A5A5A}, + {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, + 0xA5A5A5A5, 0xA5A5A5A5}, + {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, + 0x55AA55AA, 0x55AA55AA}, + {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, + 0xAA55AA55, 0xAA55AA55} }; @@ -696,14 +658,14 @@ void get_spd_info(unsigned long* dimm_populated, unsigned long num_dimm_banks); void check_mem_type - (unsigned long* dimm_populated, - unsigned char* iic0_dimm_addr, - unsigned long num_dimm_banks); +(unsigned long* dimm_populated, + unsigned char* iic0_dimm_addr, + unsigned long num_dimm_banks); void check_volt_type - (unsigned long* dimm_populated, - unsigned char* iic0_dimm_addr, - unsigned long num_dimm_banks); +(unsigned long* dimm_populated, + unsigned char* iic0_dimm_addr, + unsigned long num_dimm_banks); void program_cfg0(unsigned long* dimm_populated, unsigned char* iic0_dimm_addr, @@ -741,14 +703,14 @@ long program_bxcr(unsigned long* dimm_populated, */ long int spd_sdram(void) { - unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS; - unsigned long dimm_populated[sizeof(iic0_dimm_addr)]; - unsigned long total_size; - unsigned long cfg0; - unsigned long mcsts; - unsigned long num_dimm_banks; /* on board dimm banks */ + unsigned char iic0_dimm_addr[] = SPD_EEPROM_ADDRESS; + unsigned long dimm_populated[sizeof(iic0_dimm_addr)]; + unsigned long total_size; + unsigned long cfg0; + unsigned long mcsts; + unsigned long num_dimm_banks; /* on board dimm banks */ - num_dimm_banks = sizeof(iic0_dimm_addr); + num_dimm_banks = sizeof(iic0_dimm_addr); /* * Make sure I2C controller is initialized @@ -756,90 +718,90 @@ long int spd_sdram(void) { */ i2c_init(CFG_I2C_SPEED, CFG_I2C_SLAVE); - /* - * Read the SPD information using I2C interface. Check to see if the - * DIMM slots are populated. - */ - get_spd_info(dimm_populated, iic0_dimm_addr, num_dimm_banks); + /* + * Read the SPD information using I2C interface. Check to see if the + * DIMM slots are populated. + */ + get_spd_info(dimm_populated, iic0_dimm_addr, num_dimm_banks); - /* - * Check the memory type for the dimms plugged. - */ - check_mem_type(dimm_populated, iic0_dimm_addr, num_dimm_banks); + /* + * Check the memory type for the dimms plugged. + */ + check_mem_type(dimm_populated, iic0_dimm_addr, num_dimm_banks); - /* - * Check the voltage type for the dimms plugged. - */ - check_volt_type(dimm_populated, iic0_dimm_addr, num_dimm_banks); + /* + * Check the voltage type for the dimms plugged. + */ + check_volt_type(dimm_populated, iic0_dimm_addr, num_dimm_banks); #if defined(CONFIG_440_GX) - /* - * Soft-reset SDRAM controller. - */ - mtsdr(sdr_srst, SDR0_SRST_DMC); - mtsdr(sdr_srst, 0x00000000); + /* + * Soft-reset SDRAM controller. + */ + mtsdr(sdr_srst, SDR0_SRST_DMC); + mtsdr(sdr_srst, 0x00000000); #endif - /* - * program 440GP SDRAM controller options (SDRAM0_CFG0) - */ - program_cfg0(dimm_populated, iic0_dimm_addr, num_dimm_banks); - - /* - * program 440GP SDRAM controller options (SDRAM0_CFG1) - */ - program_cfg1(dimm_populated, iic0_dimm_addr, num_dimm_banks); - - /* - * program SDRAM refresh register (SDRAM0_RTR) - */ - program_rtr(dimm_populated, iic0_dimm_addr, num_dimm_banks); - - /* - * program SDRAM Timing Register 0 (SDRAM0_TR0) - */ - program_tr0(dimm_populated, iic0_dimm_addr, num_dimm_banks); - - /* - * program the BxCR registers to find out total sdram installed - */ - total_size = program_bxcr(dimm_populated, iic0_dimm_addr, - num_dimm_banks); - - /* - * program SDRAM Clock Timing Register (SDRAM0_CLKTR) - */ - mtsdram(mem_clktr, 0x40000000); - - /* - * delay to ensure 200 usec has elapsed - */ - udelay(400); - - /* - * enable the memory controller - */ - mfsdram(mem_cfg0, cfg0); - mtsdram(mem_cfg0, cfg0 | SDRAM_CFG0_DCEN); - - /* - * wait for SDRAM_CFG0_DC_EN to complete - */ - while(1) { - mfsdram(mem_mcsts, mcsts); - if ((mcsts & SDRAM_MCSTS_MRSC) != 0) { - break; + /* + * program 440GP SDRAM controller options (SDRAM0_CFG0) + */ + program_cfg0(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /* + * program 440GP SDRAM controller options (SDRAM0_CFG1) + */ + program_cfg1(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /* + * program SDRAM refresh register (SDRAM0_RTR) + */ + program_rtr(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /* + * program SDRAM Timing Register 0 (SDRAM0_TR0) + */ + program_tr0(dimm_populated, iic0_dimm_addr, num_dimm_banks); + + /* + * program the BxCR registers to find out total sdram installed + */ + total_size = program_bxcr(dimm_populated, iic0_dimm_addr, + num_dimm_banks); + + /* + * program SDRAM Clock Timing Register (SDRAM0_CLKTR) + */ + mtsdram(mem_clktr, 0x40000000); + + /* + * delay to ensure 200 usec has elapsed + */ + udelay(400); + + /* + * enable the memory controller + */ + mfsdram(mem_cfg0, cfg0); + mtsdram(mem_cfg0, cfg0 | SDRAM_CFG0_DCEN); + + /* + * wait for SDRAM_CFG0_DC_EN to complete + */ + while (1) { + mfsdram(mem_mcsts, mcsts); + if ((mcsts & SDRAM_MCSTS_MRSC) != 0) { + break; + } } - } - /* - * program SDRAM Timing Register 1, adding some delays - */ - program_tr1(); + /* + * program SDRAM Timing Register 1, adding some delays + */ + program_tr1(); - /* - * if ECC is enabled, initialize parity bits - */ + /* + * if ECC is enabled, initialize parity bits + */ return total_size; } @@ -847,76 +809,78 @@ long int spd_sdram(void) { unsigned char spd_read(uchar chip, uint addr) { unsigned char data[2]; - if (i2c_read(chip, addr, 1, data, 1) == 0) - return data[0]; - else - return 0; + if (i2c_probe(chip) == 0) { + if (i2c_read(chip, addr, 1, data, 1) == 0) { + return data[0]; + } + } + + return 0; } void get_spd_info(unsigned long* dimm_populated, unsigned char* iic0_dimm_addr, unsigned long num_dimm_banks) { - unsigned long dimm_num; - unsigned long dimm_found; - unsigned char num_of_bytes; - unsigned char total_size; - - dimm_found = FALSE; - for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { - num_of_bytes = 0; - total_size = 0; - - num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0); - total_size = spd_read(iic0_dimm_addr[dimm_num], 1); - - if ((num_of_bytes != 0) && (total_size != 0)) { - dimm_populated[dimm_num] = TRUE; - dimm_found = TRUE; + unsigned long dimm_num; + unsigned long dimm_found; + unsigned char num_of_bytes; + unsigned char total_size; + + dimm_found = FALSE; + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + num_of_bytes = 0; + total_size = 0; + + num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0); + total_size = spd_read(iic0_dimm_addr[dimm_num], 1); + + if ((num_of_bytes != 0) && (total_size != 0)) { + dimm_populated[dimm_num] = TRUE; + dimm_found = TRUE; #if 0 - printf("DIMM slot %lu: populated\n", dimm_num); + printf("DIMM slot %lu: populated\n", dimm_num); #endif - } - else { - dimm_populated[dimm_num] = FALSE; + } else { + dimm_populated[dimm_num] = FALSE; #if 0 - printf("DIMM slot %lu: Not populated\n", dimm_num); + printf("DIMM slot %lu: Not populated\n", dimm_num); #endif + } } - } - if (dimm_found == FALSE) { - printf("ERROR - No memory installed. Install a DDR-SDRAM DIMM.\n\n"); - hang(); - } + if (dimm_found == FALSE) { + printf("ERROR - No memory installed. Install a DDR-SDRAM DIMM.\n\n"); + hang(); + } } void check_mem_type(unsigned long* dimm_populated, unsigned char* iic0_dimm_addr, unsigned long num_dimm_banks) { - unsigned long dimm_num; - unsigned char dimm_type; - - for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { - if (dimm_populated[dimm_num] == TRUE) { - dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2); - switch (dimm_type) { - case 7: + unsigned long dimm_num; + unsigned char dimm_type; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] == TRUE) { + dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2); + switch (dimm_type) { + case 7: #if 0 - printf("DIMM slot %lu: DDR SDRAM detected\n", dimm_num); + printf("DIMM slot %lu: DDR SDRAM detected\n", dimm_num); #endif - break; - default: - printf("ERROR: Unsupported DIMM detected in slot %lu.\n", - dimm_num); - printf("Only DDR SDRAM DIMMs are supported.\n"); - printf("Replace the DIMM module with a supported DIMM.\n\n"); - hang(); - break; - } + break; + default: + printf("ERROR: Unsupported DIMM detected in slot %lu.\n", + dimm_num); + printf("Only DDR SDRAM DIMMs are supported.\n"); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + break; + } + } } - } } @@ -924,894 +888,877 @@ void check_volt_type(unsigned long* dimm_populated, unsigned char* iic0_dimm_addr, unsigned long num_dimm_banks) { - unsigned long dimm_num; - unsigned long voltage_type; - - for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { - if (dimm_populated[dimm_num] == TRUE) { - voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8); - if (voltage_type != 0x04) { - printf("ERROR: DIMM %lu with unsupported voltage level.\n", - dimm_num); - hang(); - } - else { + unsigned long dimm_num; + unsigned long voltage_type; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] == TRUE) { + voltage_type = spd_read(iic0_dimm_addr[dimm_num], 8); + if (voltage_type != 0x04) { + printf("ERROR: DIMM %lu with unsupported voltage level.\n", + dimm_num); + hang(); + } else { #if 0 - printf("DIMM %lu voltage level supported.\n", dimm_num); + printf("DIMM %lu voltage level supported.\n", dimm_num); #endif - } - break; + } + break; + } } - } } void program_cfg0(unsigned long* dimm_populated, unsigned char* iic0_dimm_addr, unsigned long num_dimm_banks) { - unsigned long dimm_num; - unsigned long cfg0; - unsigned long ecc_enabled; - unsigned char ecc; - unsigned char attributes; - unsigned long data_width; - unsigned long dimm_32bit; - unsigned long dimm_64bit; - - /* - * get Memory Controller Options 0 data - */ - mfsdram(mem_cfg0, cfg0); - - /* - * clear bits - */ - cfg0 &= ~(SDRAM_CFG0_DCEN | SDRAM_CFG0_MCHK_MASK | - SDRAM_CFG0_RDEN | SDRAM_CFG0_PMUD | - SDRAM_CFG0_DMWD_MASK | - SDRAM_CFG0_UIOS_MASK | SDRAM_CFG0_PDP); - - - /* - * FIXME: assume the DDR SDRAMs in both banks are the same - */ - ecc_enabled = TRUE; - for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { - if (dimm_populated[dimm_num] == TRUE) { - ecc = spd_read(iic0_dimm_addr[dimm_num], 11); - if (ecc != 0x02) { - ecc_enabled = FALSE; - } - - /* - * program Registered DIMM Enable - */ - attributes = spd_read(iic0_dimm_addr[dimm_num], 21); - if ((attributes & 0x02) != 0x00) { - cfg0 |= SDRAM_CFG0_RDEN; - } - - /* - * program DDR SDRAM Data Width - */ - data_width = - (unsigned long)spd_read(iic0_dimm_addr[dimm_num],6) + - (((unsigned long)spd_read(iic0_dimm_addr[dimm_num],7)) << 8); - if (data_width == 64 || data_width == 72) { - dimm_64bit = TRUE; - cfg0 |= SDRAM_CFG0_DMWD_64; - } - else if (data_width == 32 || data_width == 40) { - dimm_32bit = TRUE; - cfg0 |= SDRAM_CFG0_DMWD_32; - } - else { - printf("WARNING: DIMM with datawidth of %lu bits.\n", - data_width); - printf("Only DIMMs with 32 or 64 bit datawidths supported.\n"); - hang(); - } - break; + unsigned long dimm_num; + unsigned long cfg0; + unsigned long ecc_enabled; + unsigned char ecc; + unsigned char attributes; + unsigned long data_width; + unsigned long dimm_32bit; + unsigned long dimm_64bit; + + /* + * get Memory Controller Options 0 data + */ + mfsdram(mem_cfg0, cfg0); + + /* + * clear bits + */ + cfg0 &= ~(SDRAM_CFG0_DCEN | SDRAM_CFG0_MCHK_MASK | + SDRAM_CFG0_RDEN | SDRAM_CFG0_PMUD | + SDRAM_CFG0_DMWD_MASK | + SDRAM_CFG0_UIOS_MASK | SDRAM_CFG0_PDP); + + + /* + * FIXME: assume the DDR SDRAMs in both banks are the same + */ + ecc_enabled = TRUE; + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] == TRUE) { + ecc = spd_read(iic0_dimm_addr[dimm_num], 11); + if (ecc != 0x02) { + ecc_enabled = FALSE; + } + + /* + * program Registered DIMM Enable + */ + attributes = spd_read(iic0_dimm_addr[dimm_num], 21); + if ((attributes & 0x02) != 0x00) { + cfg0 |= SDRAM_CFG0_RDEN; + } + + /* + * program DDR SDRAM Data Width + */ + data_width = + (unsigned long)spd_read(iic0_dimm_addr[dimm_num],6) + + (((unsigned long)spd_read(iic0_dimm_addr[dimm_num],7)) << 8); + if (data_width == 64 || data_width == 72) { + dimm_64bit = TRUE; + cfg0 |= SDRAM_CFG0_DMWD_64; + } else if (data_width == 32 || data_width == 40) { + dimm_32bit = TRUE; + cfg0 |= SDRAM_CFG0_DMWD_32; + } else { + printf("WARNING: DIMM with datawidth of %lu bits.\n", + data_width); + printf("Only DIMMs with 32 or 64 bit datawidths supported.\n"); + hang(); + } + break; + } } - } - - /* - * program Memory Data Error Checking - */ - if (ecc_enabled == TRUE) { - cfg0 |= SDRAM_CFG0_MCHK_GEN; - } - else { - cfg0 |= SDRAM_CFG0_MCHK_NON; - } - - /* - * program Page Management Unit - */ - cfg0 |= SDRAM_CFG0_PMUD; - - /* - * program Memory Controller Options 0 - * Note: DCEN must be enabled after all DDR SDRAM controller - * configuration registers get initialized. - */ - mtsdram(mem_cfg0, cfg0); + + /* + * program Memory Data Error Checking + */ + if (ecc_enabled == TRUE) { + cfg0 |= SDRAM_CFG0_MCHK_GEN; + } else { + cfg0 |= SDRAM_CFG0_MCHK_NON; + } + + /* + * program Page Management Unit + */ + cfg0 |= SDRAM_CFG0_PMUD; + + /* + * program Memory Controller Options 0 + * Note: DCEN must be enabled after all DDR SDRAM controller + * configuration registers get initialized. + */ + mtsdram(mem_cfg0, cfg0); } void program_cfg1(unsigned long* dimm_populated, unsigned char* iic0_dimm_addr, unsigned long num_dimm_banks) { - unsigned long cfg1; - mfsdram(mem_cfg1, cfg1); - - /* - * Self-refresh exit, disable PM - */ - cfg1 &= ~(SDRAM_CFG1_SRE | SDRAM_CFG1_PMEN); - - /* - * program Memory Controller Options 1 - */ - mtsdram(mem_cfg1, cfg1); + unsigned long cfg1; + mfsdram(mem_cfg1, cfg1); + + /* + * Self-refresh exit, disable PM + */ + cfg1 &= ~(SDRAM_CFG1_SRE | SDRAM_CFG1_PMEN); + + /* + * program Memory Controller Options 1 + */ + mtsdram(mem_cfg1, cfg1); } void program_rtr (unsigned long* dimm_populated, unsigned char* iic0_dimm_addr, unsigned long num_dimm_banks) { - unsigned long dimm_num; - unsigned long bus_period_x_10; - unsigned long refresh_rate = 0; - unsigned char refresh_rate_type; - unsigned long refresh_interval; - unsigned long sdram_rtr; - PPC440_SYS_INFO sys_info; - - /* - * get the board info - */ - get_sys_info(&sys_info); - bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10); - - - for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { - if (dimm_populated[dimm_num] == TRUE) { - refresh_rate_type = 0x7F & spd_read(iic0_dimm_addr[dimm_num], 12); - switch (refresh_rate_type) { - case 0x00: - refresh_rate = 15625; - break; - case 0x01: - refresh_rate = 15625/4; - break; - case 0x02: - refresh_rate = 15625/2; - break; - case 0x03: - refresh_rate = 15626*2; - break; - case 0x04: - refresh_rate = 15625*4; - break; - case 0x05: - refresh_rate = 15625*8; - break; - default: - printf("ERROR: DIMM %lu, unsupported refresh rate/type.\n", - dimm_num); - printf("Replace the DIMM module with a supported DIMM.\n"); - break; - } + unsigned long dimm_num; + unsigned long bus_period_x_10; + unsigned long refresh_rate = 0; + unsigned char refresh_rate_type; + unsigned long refresh_interval; + unsigned long sdram_rtr; + PPC440_SYS_INFO sys_info; + + /* + * get the board info + */ + get_sys_info(&sys_info); + bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10); + - break; + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] == TRUE) { + refresh_rate_type = 0x7F & spd_read(iic0_dimm_addr[dimm_num], 12); + switch (refresh_rate_type) { + case 0x00: + refresh_rate = 15625; + break; + case 0x01: + refresh_rate = 15625/4; + break; + case 0x02: + refresh_rate = 15625/2; + break; + case 0x03: + refresh_rate = 15626*2; + break; + case 0x04: + refresh_rate = 15625*4; + break; + case 0x05: + refresh_rate = 15625*8; + break; + default: + printf("ERROR: DIMM %lu, unsupported refresh rate/type.\n", + dimm_num); + printf("Replace the DIMM module with a supported DIMM.\n"); + break; + } + + break; + } } - } - refresh_interval = refresh_rate * 10 / bus_period_x_10; - sdram_rtr = (refresh_interval & 0x3ff8) << 16; + refresh_interval = refresh_rate * 10 / bus_period_x_10; + sdram_rtr = (refresh_interval & 0x3ff8) << 16; - /* - * program Refresh Timer Register (SDRAM0_RTR) - */ - mtsdram(mem_rtr, sdram_rtr); + /* + * program Refresh Timer Register (SDRAM0_RTR) + */ + mtsdram(mem_rtr, sdram_rtr); } void program_tr0 (unsigned long* dimm_populated, unsigned char* iic0_dimm_addr, unsigned long num_dimm_banks) { - unsigned long dimm_num; - unsigned long tr0; - unsigned char wcsbc; - unsigned char t_rp_ns; - unsigned char t_rcd_ns; - unsigned char t_ras_ns; - unsigned long t_rp_clk; - unsigned long t_ras_rcd_clk; - unsigned long t_rcd_clk; - unsigned long t_rfc_clk; - unsigned long plb_check; - unsigned char cas_bit; - unsigned long cas_index; - unsigned char cas_2_0_available; - unsigned char cas_2_5_available; - unsigned char cas_3_0_available; - unsigned long cycle_time_ns_x_10[3]; - unsigned long tcyc_3_0_ns_x_10; - unsigned long tcyc_2_5_ns_x_10; - unsigned long tcyc_2_0_ns_x_10; - unsigned long tcyc_reg; - unsigned long bus_period_x_10; - PPC440_SYS_INFO sys_info; - unsigned long residue; - - /* - * get the board info - */ - get_sys_info(&sys_info); - bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10); - - /* - * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits - */ - mfsdram(mem_tr0, tr0); - tr0 &= ~(SDRAM_TR0_SDWR_MASK | SDRAM_TR0_SDWD_MASK | - SDRAM_TR0_SDCL_MASK | SDRAM_TR0_SDPA_MASK | - SDRAM_TR0_SDCP_MASK | SDRAM_TR0_SDLD_MASK | - SDRAM_TR0_SDRA_MASK | SDRAM_TR0_SDRD_MASK); - - /* - * initialization - */ - wcsbc = 0; - t_rp_ns = 0; - t_rcd_ns = 0; - t_ras_ns = 0; - cas_2_0_available = TRUE; - cas_2_5_available = TRUE; - cas_3_0_available = TRUE; - tcyc_2_0_ns_x_10 = 0; - tcyc_2_5_ns_x_10 = 0; - tcyc_3_0_ns_x_10 = 0; - - for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { - if (dimm_populated[dimm_num] == TRUE) { - wcsbc = spd_read(iic0_dimm_addr[dimm_num], 15); - t_rp_ns = spd_read(iic0_dimm_addr[dimm_num], 27) >> 2; - t_rcd_ns = spd_read(iic0_dimm_addr[dimm_num], 29) >> 2; - t_ras_ns = spd_read(iic0_dimm_addr[dimm_num], 30); - cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18); - - for (cas_index = 0; cas_index < 3; cas_index++) { - switch (cas_index) { - case 0: - tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9); - break; - case 1: - tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 23); - break; - default: - tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 25); - break; - } + unsigned long dimm_num; + unsigned long tr0; + unsigned char wcsbc; + unsigned char t_rp_ns; + unsigned char t_rcd_ns; + unsigned char t_ras_ns; + unsigned long t_rp_clk; + unsigned long t_ras_rcd_clk; + unsigned long t_rcd_clk; + unsigned long t_rfc_clk; + unsigned long plb_check; + unsigned char cas_bit; + unsigned long cas_index; + unsigned char cas_2_0_available; + unsigned char cas_2_5_available; + unsigned char cas_3_0_available; + unsigned long cycle_time_ns_x_10[3]; + unsigned long tcyc_3_0_ns_x_10; + unsigned long tcyc_2_5_ns_x_10; + unsigned long tcyc_2_0_ns_x_10; + unsigned long tcyc_reg; + unsigned long bus_period_x_10; + PPC440_SYS_INFO sys_info; + unsigned long residue; - if ((tcyc_reg & 0x0F) >= 10) { - printf("ERROR: Tcyc incorrect for DIMM in slot %lu\n", - dimm_num); - hang(); - } + /* + * get the board info + */ + get_sys_info(&sys_info); + bus_period_x_10 = ONE_BILLION / (sys_info.freqPLB / 10); - cycle_time_ns_x_10[cas_index] = - (((tcyc_reg & 0xF0) >> 4) * 10) + (tcyc_reg & 0x0F); - } - - cas_index = 0; - - if ((cas_bit & 0x80) != 0) { - cas_index += 3; - } - else if ((cas_bit & 0x40) != 0) { - cas_index += 2; - } - else if ((cas_bit & 0x20) != 0) { - cas_index += 1; - } - - if (((cas_bit & 0x10) != 0) && (cas_index < 3)) { - tcyc_3_0_ns_x_10 = cycle_time_ns_x_10[cas_index]; - cas_index++; - } - else { - if (cas_index != 0) { - cas_index++; - } - cas_3_0_available = FALSE; - } - - if (((cas_bit & 0x08) != 0) || (cas_index < 3)) { - tcyc_2_5_ns_x_10 = cycle_time_ns_x_10[cas_index]; - cas_index++; - } - else { - if (cas_index != 0) { - cas_index++; - } - cas_2_5_available = FALSE; - } - - if (((cas_bit & 0x04) != 0) || (cas_index < 3)) { - tcyc_2_0_ns_x_10 = cycle_time_ns_x_10[cas_index]; - cas_index++; - } - else { - if (cas_index != 0) { - cas_index++; + /* + * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits + */ + mfsdram(mem_tr0, tr0); + tr0 &= ~(SDRAM_TR0_SDWR_MASK | SDRAM_TR0_SDWD_MASK | + SDRAM_TR0_SDCL_MASK | SDRAM_TR0_SDPA_MASK | + SDRAM_TR0_SDCP_MASK | SDRAM_TR0_SDLD_MASK | + SDRAM_TR0_SDRA_MASK | SDRAM_TR0_SDRD_MASK); + + /* + * initialization + */ + wcsbc = 0; + t_rp_ns = 0; + t_rcd_ns = 0; + t_ras_ns = 0; + cas_2_0_available = TRUE; + cas_2_5_available = TRUE; + cas_3_0_available = TRUE; + tcyc_2_0_ns_x_10 = 0; + tcyc_2_5_ns_x_10 = 0; + tcyc_3_0_ns_x_10 = 0; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] == TRUE) { + wcsbc = spd_read(iic0_dimm_addr[dimm_num], 15); + t_rp_ns = spd_read(iic0_dimm_addr[dimm_num], 27) >> 2; + t_rcd_ns = spd_read(iic0_dimm_addr[dimm_num], 29) >> 2; + t_ras_ns = spd_read(iic0_dimm_addr[dimm_num], 30); + cas_bit = spd_read(iic0_dimm_addr[dimm_num], 18); + + for (cas_index = 0; cas_index < 3; cas_index++) { + switch (cas_index) { + case 0: + tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 9); + break; + case 1: + tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 23); + break; + default: + tcyc_reg = spd_read(iic0_dimm_addr[dimm_num], 25); + break; + } + + if ((tcyc_reg & 0x0F) >= 10) { + printf("ERROR: Tcyc incorrect for DIMM in slot %lu\n", + dimm_num); + hang(); + } + + cycle_time_ns_x_10[cas_index] = + (((tcyc_reg & 0xF0) >> 4) * 10) + (tcyc_reg & 0x0F); + } + + cas_index = 0; + + if ((cas_bit & 0x80) != 0) { + cas_index += 3; + } else if ((cas_bit & 0x40) != 0) { + cas_index += 2; + } else if ((cas_bit & 0x20) != 0) { + cas_index += 1; + } + + if (((cas_bit & 0x10) != 0) && (cas_index < 3)) { + tcyc_3_0_ns_x_10 = cycle_time_ns_x_10[cas_index]; + cas_index++; + } else { + if (cas_index != 0) { + cas_index++; + } + cas_3_0_available = FALSE; + } + + if (((cas_bit & 0x08) != 0) || (cas_index < 3)) { + tcyc_2_5_ns_x_10 = cycle_time_ns_x_10[cas_index]; + cas_index++; + } else { + if (cas_index != 0) { + cas_index++; + } + cas_2_5_available = FALSE; + } + + if (((cas_bit & 0x04) != 0) || (cas_index < 3)) { + tcyc_2_0_ns_x_10 = cycle_time_ns_x_10[cas_index]; + cas_index++; + } else { + if (cas_index != 0) { + cas_index++; + } + cas_2_0_available = FALSE; + } + + break; } - cas_2_0_available = FALSE; - } + } + + /* + * Program SD_WR and SD_WCSBC fields + */ + tr0 |= SDRAM_TR0_SDWR_2_CLK; /* Write Recovery: 2 CLK */ + switch (wcsbc) { + case 0: + tr0 |= SDRAM_TR0_SDWD_0_CLK; + break; + default: + tr0 |= SDRAM_TR0_SDWD_1_CLK; + break; + } + + /* + * Program SD_CASL field + */ + if ((cas_2_0_available == TRUE) && + (bus_period_x_10 >= tcyc_2_0_ns_x_10)) { + tr0 |= SDRAM_TR0_SDCL_2_0_CLK; + } else if ((cas_2_5_available == TRUE) && + (bus_period_x_10 >= tcyc_2_5_ns_x_10)) { + tr0 |= SDRAM_TR0_SDCL_2_5_CLK; + } else if ((cas_3_0_available == TRUE) && + (bus_period_x_10 >= tcyc_3_0_ns_x_10)) { + tr0 |= SDRAM_TR0_SDCL_3_0_CLK; + } else { + printf("ERROR: No supported CAS latency with the installed DIMMs.\n"); + printf("Only CAS latencies of 2.0, 2.5, and 3.0 are supported.\n"); + printf("Make sure the PLB speed is within the supported range.\n"); + hang(); + } + + /* + * Calculate Trp in clock cycles and round up if necessary + * Program SD_PTA field + */ + t_rp_clk = sys_info.freqPLB * t_rp_ns / ONE_BILLION; + plb_check = ONE_BILLION * t_rp_clk / t_rp_ns; + if (sys_info.freqPLB != plb_check) { + t_rp_clk++; + } + switch ((unsigned long)t_rp_clk) { + case 0: + case 1: + case 2: + tr0 |= SDRAM_TR0_SDPA_2_CLK; + break; + case 3: + tr0 |= SDRAM_TR0_SDPA_3_CLK; + break; + default: + tr0 |= SDRAM_TR0_SDPA_4_CLK; + break; + } + + /* + * Program SD_CTP field + */ + t_ras_rcd_clk = sys_info.freqPLB * (t_ras_ns - t_rcd_ns) / ONE_BILLION; + plb_check = ONE_BILLION * t_ras_rcd_clk / (t_ras_ns - t_rcd_ns); + if (sys_info.freqPLB != plb_check) { + t_ras_rcd_clk++; + } + switch (t_ras_rcd_clk) { + case 0: + case 1: + case 2: + tr0 |= SDRAM_TR0_SDCP_2_CLK; + break; + case 3: + tr0 |= SDRAM_TR0_SDCP_3_CLK; + break; + case 4: + tr0 |= SDRAM_TR0_SDCP_4_CLK; + break; + default: + tr0 |= SDRAM_TR0_SDCP_5_CLK; + break; + } + + /* + * Program SD_LDF field + */ + tr0 |= SDRAM_TR0_SDLD_2_CLK; + + /* + * Program SD_RFTA field + * FIXME tRFC hardcoded as 75 nanoseconds + */ + t_rfc_clk = sys_info.freqPLB / (ONE_BILLION / 75); + residue = sys_info.freqPLB % (ONE_BILLION / 75); + if (residue >= (ONE_BILLION / 150)) { + t_rfc_clk++; + } + switch (t_rfc_clk) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + tr0 |= SDRAM_TR0_SDRA_6_CLK; + break; + case 7: + tr0 |= SDRAM_TR0_SDRA_7_CLK; + break; + case 8: + tr0 |= SDRAM_TR0_SDRA_8_CLK; + break; + case 9: + tr0 |= SDRAM_TR0_SDRA_9_CLK; + break; + case 10: + tr0 |= SDRAM_TR0_SDRA_10_CLK; + break; + case 11: + tr0 |= SDRAM_TR0_SDRA_11_CLK; + break; + case 12: + tr0 |= SDRAM_TR0_SDRA_12_CLK; + break; + default: + tr0 |= SDRAM_TR0_SDRA_13_CLK; + break; + } - break; + /* + * Program SD_RCD field + */ + t_rcd_clk = sys_info.freqPLB * t_rcd_ns / ONE_BILLION; + plb_check = ONE_BILLION * t_rcd_clk / t_rcd_ns; + if (sys_info.freqPLB != plb_check) { + t_rcd_clk++; + } + switch (t_rcd_clk) { + case 0: + case 1: + case 2: + tr0 |= SDRAM_TR0_SDRD_2_CLK; + break; + case 3: + tr0 |= SDRAM_TR0_SDRD_3_CLK; + break; + default: + tr0 |= SDRAM_TR0_SDRD_4_CLK; + break; } - } - - /* - * Program SD_WR and SD_WCSBC fields - */ - tr0 |= SDRAM_TR0_SDWR_2_CLK; /* Write Recovery: 2 CLK */ - switch (wcsbc) { - case 0: - tr0 |= SDRAM_TR0_SDWD_0_CLK; - break; - default: - tr0 |= SDRAM_TR0_SDWD_1_CLK; - break; - } - - /* - * Program SD_CASL field - */ - if ((cas_2_0_available == TRUE) && - (bus_period_x_10 >= tcyc_2_0_ns_x_10)) { - tr0 |= SDRAM_TR0_SDCL_2_0_CLK; - } - else if((cas_2_5_available == TRUE) && - (bus_period_x_10 >= tcyc_2_5_ns_x_10)) { - tr0 |= SDRAM_TR0_SDCL_2_5_CLK; - } - else if((cas_3_0_available == TRUE) && - (bus_period_x_10 >= tcyc_3_0_ns_x_10)) { - tr0 |= SDRAM_TR0_SDCL_3_0_CLK; - } - else { - printf("ERROR: No supported CAS latency with the installed DIMMs.\n"); - printf("Only CAS latencies of 2.0, 2.5, and 3.0 are supported.\n"); - printf("Make sure the PLB speed is within the supported range.\n"); - hang(); - } - - /* - * Calculate Trp in clock cycles and round up if necessary - * Program SD_PTA field - */ - t_rp_clk = sys_info.freqPLB * t_rp_ns / ONE_BILLION; - plb_check = ONE_BILLION * t_rp_clk / t_rp_ns; - if (sys_info.freqPLB != plb_check) { - t_rp_clk++; - } - switch ((unsigned long)t_rp_clk) { - case 0: - case 1: - case 2: - tr0 |= SDRAM_TR0_SDPA_2_CLK; - break; - case 3: - tr0 |= SDRAM_TR0_SDPA_3_CLK; - break; - default: - tr0 |= SDRAM_TR0_SDPA_4_CLK; - break; - } - - /* - * Program SD_CTP field - */ - t_ras_rcd_clk = sys_info.freqPLB * (t_ras_ns - t_rcd_ns) / ONE_BILLION; - plb_check = ONE_BILLION * t_ras_rcd_clk / (t_ras_ns - t_rcd_ns); - if (sys_info.freqPLB != plb_check) { - t_ras_rcd_clk++; - } - switch (t_ras_rcd_clk) { - case 0: - case 1: - case 2: - tr0 |= SDRAM_TR0_SDCP_2_CLK; - break; - case 3: - tr0 |= SDRAM_TR0_SDCP_3_CLK; - break; - case 4: - tr0 |= SDRAM_TR0_SDCP_4_CLK; - break; - default: - tr0 |= SDRAM_TR0_SDCP_5_CLK; - break; - } - - /* - * Program SD_LDF field - */ - tr0 |= SDRAM_TR0_SDLD_2_CLK; - - /* - * Program SD_RFTA field - * FIXME tRFC hardcoded as 75 nanoseconds - */ - t_rfc_clk = sys_info.freqPLB / (ONE_BILLION / 75); - residue = sys_info.freqPLB % (ONE_BILLION / 75); - if (residue >= (ONE_BILLION / 150)) { - t_rfc_clk++; - } - switch (t_rfc_clk) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - tr0 |= SDRAM_TR0_SDRA_6_CLK; - break; - case 7: - tr0 |= SDRAM_TR0_SDRA_7_CLK; - break; - case 8: - tr0 |= SDRAM_TR0_SDRA_8_CLK; - break; - case 9: - tr0 |= SDRAM_TR0_SDRA_9_CLK; - break; - case 10: - tr0 |= SDRAM_TR0_SDRA_10_CLK; - break; - case 11: - tr0 |= SDRAM_TR0_SDRA_11_CLK; - break; - case 12: - tr0 |= SDRAM_TR0_SDRA_12_CLK; - break; - default: - tr0 |= SDRAM_TR0_SDRA_13_CLK; - break; - } - - /* - * Program SD_RCD field - */ - t_rcd_clk = sys_info.freqPLB * t_rcd_ns / ONE_BILLION; - plb_check = ONE_BILLION * t_rcd_clk / t_rcd_ns; - if (sys_info.freqPLB != plb_check) { - t_rcd_clk++; - } - switch (t_rcd_clk) { - case 0: - case 1: - case 2: - tr0 |= SDRAM_TR0_SDRD_2_CLK; - break; - case 3: - tr0 |= SDRAM_TR0_SDRD_3_CLK; - break; - default: - tr0 |= SDRAM_TR0_SDRD_4_CLK; - break; - } #if 0 - printf("tr0: %x\n", tr0); + printf("tr0: %x\n", tr0); #endif - mtsdram(mem_tr0, tr0); + mtsdram(mem_tr0, tr0); } void program_tr1 (void) { - unsigned long tr0; - unsigned long tr1; - unsigned long cfg0; - unsigned long ecc_temp; - unsigned long dlycal; - unsigned long dly_val; - unsigned long i, j, k; - unsigned long bxcr_num; - unsigned long max_pass_length; - unsigned long current_pass_length; - unsigned long current_fail_length; - unsigned long current_start; - unsigned long rdclt; - unsigned long rdclt_offset; - long max_start; - long max_end; - long rdclt_average; - unsigned char window_found; - unsigned char fail_found; - unsigned char pass_found; - unsigned long * membase; - PPC440_SYS_INFO sys_info; - - /* - * get the board info - */ - get_sys_info(&sys_info); - - /* - * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits - */ - mfsdram(mem_tr1, tr1); - tr1 &= ~(SDRAM_TR1_RDSS_MASK | SDRAM_TR1_RDSL_MASK | - SDRAM_TR1_RDCD_MASK | SDRAM_TR1_RDCT_MASK); - - mfsdram(mem_tr0, tr0); - if (((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) && - (sys_info.freqPLB > 100000000)) { - tr1 |= SDRAM_TR1_RDSS_TR2; - tr1 |= SDRAM_TR1_RDSL_STAGE3; - tr1 |= SDRAM_TR1_RDCD_RCD_1_2; - } - else { - tr1 |= SDRAM_TR1_RDSS_TR1; - tr1 |= SDRAM_TR1_RDSL_STAGE2; - tr1 |= SDRAM_TR1_RDCD_RCD_0_0; - } - - /* - * save CFG0 ECC setting to a temporary variable and turn ECC off - */ - mfsdram(mem_cfg0, cfg0); - ecc_temp = cfg0 & SDRAM_CFG0_MCHK_MASK; - mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | SDRAM_CFG0_MCHK_NON); - - /* - * get the delay line calibration register value - */ - mfsdram(mem_dlycal, dlycal); - dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2; - - max_pass_length = 0; - max_start = 0; - max_end = 0; - current_pass_length = 0; - current_fail_length = 0; - current_start = 0; - rdclt_offset = 0; - window_found = FALSE; - fail_found = FALSE; - pass_found = FALSE; + unsigned long tr0; + unsigned long tr1; + unsigned long cfg0; + unsigned long ecc_temp; + unsigned long dlycal; + unsigned long dly_val; + unsigned long i, j, k; + unsigned long bxcr_num; + unsigned long max_pass_length; + unsigned long current_pass_length; + unsigned long current_fail_length; + unsigned long current_start; + unsigned long rdclt; + unsigned long rdclt_offset; + long max_start; + long max_end; + long rdclt_average; + unsigned char window_found; + unsigned char fail_found; + unsigned char pass_found; + unsigned long * membase; + PPC440_SYS_INFO sys_info; + + /* + * get the board info + */ + get_sys_info(&sys_info); + + /* + * get SDRAM Timing Register 0 (SDRAM_TR0) and clear bits + */ + mfsdram(mem_tr1, tr1); + tr1 &= ~(SDRAM_TR1_RDSS_MASK | SDRAM_TR1_RDSL_MASK | + SDRAM_TR1_RDCD_MASK | SDRAM_TR1_RDCT_MASK); + + mfsdram(mem_tr0, tr0); + if (((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) && + (sys_info.freqPLB > 100000000)) { + tr1 |= SDRAM_TR1_RDSS_TR2; + tr1 |= SDRAM_TR1_RDSL_STAGE3; + tr1 |= SDRAM_TR1_RDCD_RCD_1_2; + } else { + tr1 |= SDRAM_TR1_RDSS_TR1; + tr1 |= SDRAM_TR1_RDSL_STAGE2; + tr1 |= SDRAM_TR1_RDCD_RCD_0_0; + } + + /* + * save CFG0 ECC setting to a temporary variable and turn ECC off + */ + mfsdram(mem_cfg0, cfg0); + ecc_temp = cfg0 & SDRAM_CFG0_MCHK_MASK; + mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | SDRAM_CFG0_MCHK_NON); + + /* + * get the delay line calibration register value + */ + mfsdram(mem_dlycal, dlycal); + dly_val = SDRAM_DLYCAL_DLCV_DECODE(dlycal) << 2; + + max_pass_length = 0; + max_start = 0; + max_end = 0; + current_pass_length = 0; + current_fail_length = 0; + current_start = 0; + rdclt_offset = 0; + window_found = FALSE; + fail_found = FALSE; + pass_found = FALSE; #ifdef DEBUG - printf("Starting memory test "); + printf("Starting memory test "); #endif - for (k = 0; k < NUMHALFCYCLES; k++) { - for (rdclt = 0; rdclt < dly_val; rdclt++) { - /* - * Set the timing reg for the test. - */ - mtsdram(mem_tr1, (tr1 | SDRAM_TR1_RDCT_ENCODE(rdclt))); - - for (bxcr_num = 0; bxcr_num < MAXBXCR; bxcr_num++) { - mtdcr(memcfga, mem_b0cr + (bxcr_num<<2)); - if ((mfdcr(memcfgd) & SDRAM_BXCR_SDBE) == SDRAM_BXCR_SDBE) { - /* Bank is enabled */ - membase = (unsigned long*) - (mfdcr(memcfgd) & SDRAM_BXCR_SDBA_MASK); - - /* - * Run the short memory test - */ - for (i = 0; i < NUMMEMTESTS; i++) { - for (j = 0; j < NUMMEMWORDS; j++) { - membase[j] = test[i][j]; - ppcDcbf((unsigned long)&(membase[j])); + for (k = 0; k < NUMHALFCYCLES; k++) { + for (rdclt = 0; rdclt < dly_val; rdclt++) { + /* + * Set the timing reg for the test. + */ + mtsdram(mem_tr1, (tr1 | SDRAM_TR1_RDCT_ENCODE(rdclt))); + + for (bxcr_num = 0; bxcr_num < MAXBXCR; bxcr_num++) { + mtdcr(memcfga, mem_b0cr + (bxcr_num<<2)); + if ((mfdcr(memcfgd) & SDRAM_BXCR_SDBE) == SDRAM_BXCR_SDBE) { + /* Bank is enabled */ + membase = (unsigned long*) + (mfdcr(memcfgd) & SDRAM_BXCR_SDBA_MASK); + + /* + * Run the short memory test + */ + for (i = 0; i < NUMMEMTESTS; i++) { + for (j = 0; j < NUMMEMWORDS; j++) { + membase[j] = test[i][j]; + ppcDcbf((unsigned long)&(membase[j])); + } + + for (j = 0; j < NUMMEMWORDS; j++) { + if (membase[j] != test[i][j]) { + ppcDcbf((unsigned long)&(membase[j])); + break; + } + ppcDcbf((unsigned long)&(membase[j])); + } + + if (j < NUMMEMWORDS) { + break; + } + } + + /* + * see if the rdclt value passed + */ + if (i < NUMMEMTESTS) { + break; + } + } } - for (j = 0; j < NUMMEMWORDS; j++) { - if (membase[j] != test[i][j]) { - ppcDcbf((unsigned long)&(membase[j])); - break; - } - ppcDcbf((unsigned long)&(membase[j])); + if (bxcr_num == MAXBXCR) { + if (fail_found == TRUE) { + pass_found = TRUE; + if (current_pass_length == 0) { + current_start = rdclt_offset + rdclt; + } + + current_fail_length = 0; + current_pass_length++; + + if (current_pass_length > max_pass_length) { + max_pass_length = current_pass_length; + max_start = current_start; + max_end = rdclt_offset + rdclt; + } + } + } else { + current_pass_length = 0; + current_fail_length++; + + if (current_fail_length >= (dly_val>>2)) { + if (fail_found == FALSE) { + fail_found = TRUE; + } else if (pass_found == TRUE) { + window_found = TRUE; + break; + } + } } - - if (j < NUMMEMWORDS) { - break; - } - } - - /* - * see if the rdclt value passed - */ - if (i < NUMMEMTESTS) { - break; - } } - } - - if (bxcr_num == MAXBXCR) { - if (fail_found == TRUE) { - pass_found = TRUE; - if (current_pass_length == 0) { - current_start = rdclt_offset + rdclt; - } - - current_fail_length = 0; - current_pass_length++; - - if (current_pass_length > max_pass_length) { - max_pass_length = current_pass_length; - max_start = current_start; - max_end = rdclt_offset + rdclt; - } - } - } - else { - current_pass_length = 0; - current_fail_length++; - - if (current_fail_length >= (dly_val>>2)) { - if (fail_found == FALSE) { - fail_found = TRUE; - } - else if (pass_found == TRUE) { - window_found = TRUE; +#ifdef DEBUG + printf("."); +#endif + if (window_found == TRUE) { break; - } } - } + + tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK; + rdclt_offset += dly_val; } #ifdef DEBUG - printf("."); + printf("\n"); #endif - if (window_found == TRUE) { - break; + + /* + * make sure we find the window + */ + if (window_found == FALSE) { + printf("ERROR: Cannot determine a common read delay.\n"); + hang(); } - tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK; - rdclt_offset += dly_val; - } -#ifdef DEBUG - printf("\n"); -#endif + /* + * restore the orignal ECC setting + */ + mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | ecc_temp); + + /* + * set the SDRAM TR1 RDCD value + */ + tr1 &= ~SDRAM_TR1_RDCD_MASK; + if ((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) { + tr1 |= SDRAM_TR1_RDCD_RCD_1_2; + } else { + tr1 |= SDRAM_TR1_RDCD_RCD_0_0; + } - /* - * make sure we find the window - */ - if (window_found == FALSE) { - printf("ERROR: Cannot determine a common read delay.\n"); - hang(); - } - - /* - * restore the orignal ECC setting - */ - mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | ecc_temp); - - /* - * set the SDRAM TR1 RDCD value - */ - tr1 &= ~SDRAM_TR1_RDCD_MASK; - if ((tr0 & SDRAM_TR0_SDCL_MASK) == SDRAM_TR0_SDCL_2_5_CLK) { - tr1 |= SDRAM_TR1_RDCD_RCD_1_2; - } - else { - tr1 |= SDRAM_TR1_RDCD_RCD_0_0; - } - - /* - * set the SDRAM TR1 RDCLT value - */ - tr1 &= ~SDRAM_TR1_RDCT_MASK; - while (max_end >= (dly_val<<1)) { - max_end -= (dly_val<<1); - max_start -= (dly_val<<1); - } - - rdclt_average = ((max_start + max_end) >> 1); - if (rdclt_average >= 0x60) - while(1); - - if (rdclt_average < 0) { - rdclt_average = 0; - } - - if (rdclt_average >= dly_val) { - rdclt_average -= dly_val; - tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK; - } - tr1 |= SDRAM_TR1_RDCT_ENCODE(rdclt_average); + /* + * set the SDRAM TR1 RDCLT value + */ + tr1 &= ~SDRAM_TR1_RDCT_MASK; + while (max_end >= (dly_val << 1)) { + max_end -= (dly_val << 1); + max_start -= (dly_val << 1); + } + + rdclt_average = ((max_start + max_end) >> 1); + if (rdclt_average >= 0x60) + while (1) + ; + + if (rdclt_average < 0) { + rdclt_average = 0; + } + + if (rdclt_average >= dly_val) { + rdclt_average -= dly_val; + tr1 = tr1 ^ SDRAM_TR1_RDCD_MASK; + } + tr1 |= SDRAM_TR1_RDCT_ENCODE(rdclt_average); #if 0 - printf("tr1: %x\n", tr1); + printf("tr1: %x\n", tr1); #endif - /* - * program SDRAM Timing Register 1 TR1 - */ - mtsdram(mem_tr1, tr1); + /* + * program SDRAM Timing Register 1 TR1 + */ + mtsdram(mem_tr1, tr1); } unsigned long program_bxcr(unsigned long* dimm_populated, unsigned char* iic0_dimm_addr, unsigned long num_dimm_banks) { - unsigned long dimm_num; - unsigned long bxcr_num; - unsigned long bank_base_addr; - unsigned long bank_size_bytes; - unsigned long cr; - unsigned long i; - unsigned long temp; - unsigned char num_row_addr; - unsigned char num_col_addr; - unsigned char num_banks; - unsigned char bank_size_id; - - - /* - * Set the BxCR regs. First, wipe out the bank config registers. - */ - for (bxcr_num = 0; bxcr_num < MAXBXCR; bxcr_num++) { - mtdcr(memcfga, mem_b0cr + (bxcr_num << 2)); - mtdcr(memcfgd, 0x00000000); - } - - /* - * reset the bank_base address - */ - bank_base_addr = CFG_SDRAM_BASE; - - for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { - if (dimm_populated[dimm_num] == TRUE) { - num_row_addr = spd_read(iic0_dimm_addr[dimm_num], 3); - num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4); - num_banks = spd_read(iic0_dimm_addr[dimm_num], 5); - bank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31); - - /* - * Set the SDRAM0_BxCR regs - */ - cr = 0; - bank_size_bytes = 4 * 1024 * 1024 * bank_size_id; - switch (bank_size_id) { - case 0x02: - cr |= SDRAM_BXCR_SDSZ_8; - break; - case 0x04: - cr |= SDRAM_BXCR_SDSZ_16; - break; - case 0x08: - cr |= SDRAM_BXCR_SDSZ_32; - break; - case 0x10: - cr |= SDRAM_BXCR_SDSZ_64; - break; - case 0x20: - cr |= SDRAM_BXCR_SDSZ_128; - break; - case 0x40: - cr |= SDRAM_BXCR_SDSZ_256; - break; - case 0x80: - cr |= SDRAM_BXCR_SDSZ_512; - break; - default: - printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n", - dimm_num); - printf("ERROR: Unsupported value for the banksize: %d.\n", - bank_size_id); - printf("Replace the DIMM module with a supported DIMM.\n\n"); - hang(); - } + unsigned long dimm_num; + unsigned long bxcr_num; + unsigned long bank_base_addr; + unsigned long bank_size_bytes; + unsigned long cr; + unsigned long i; + unsigned long temp; + unsigned char num_row_addr; + unsigned char num_col_addr; + unsigned char num_banks; + unsigned char bank_size_id; - switch (num_col_addr) { - case 0x08: - cr |= SDRAM_BXCR_SDAM_1; - break; - case 0x09: - cr |= SDRAM_BXCR_SDAM_2; - break; - case 0x0A: - cr |= SDRAM_BXCR_SDAM_3; - break; - case 0x0B: - cr |= SDRAM_BXCR_SDAM_4; - break; - default: - printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n", - dimm_num); - printf("ERROR: Unsupported value for number of " - "column addresses: %d.\n", num_col_addr); - printf("Replace the DIMM module with a supported DIMM.\n\n"); - hang(); - } - - /* - * enable the bank - */ - cr |= SDRAM_BXCR_SDBE; - - /*------------------------------------------------------------------ - | This next section is hardware dependent and must be programmed - | to match the hardware. - +-----------------------------------------------------------------*/ - if (dimm_num == 0) { - for (i = 0; i < num_banks; i++) { - mtdcr(memcfga, mem_b0cr + (i << 2)); - temp = mfdcr(memcfgd) & ~(SDRAM_BXCR_SDBA_MASK | - SDRAM_BXCR_SDSZ_MASK | - SDRAM_BXCR_SDAM_MASK | - SDRAM_BXCR_SDBE); - cr |= temp; - cr |= bank_base_addr & SDRAM_BXCR_SDBA_MASK; - mtdcr(memcfgd, cr); - bank_base_addr += bank_size_bytes; - } - } - else { - for (i = 0; i < num_banks; i++) { - mtdcr(memcfga, mem_b2cr + (i << 2)); - temp = mfdcr(memcfgd) & ~(SDRAM_BXCR_SDBA_MASK | - SDRAM_BXCR_SDSZ_MASK | - SDRAM_BXCR_SDAM_MASK | - SDRAM_BXCR_SDBE); - cr |= temp; - cr |= bank_base_addr & SDRAM_BXCR_SDBA_MASK; - mtdcr(memcfgd, cr); - bank_base_addr += bank_size_bytes; + + /* + * Set the BxCR regs. First, wipe out the bank config registers. + */ + for (bxcr_num = 0; bxcr_num < MAXBXCR; bxcr_num++) { + mtdcr(memcfga, mem_b0cr + (bxcr_num << 2)); + mtdcr(memcfgd, 0x00000000); + } + + /* + * reset the bank_base address + */ + bank_base_addr = CFG_SDRAM_BASE; + + for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { + if (dimm_populated[dimm_num] == TRUE) { + num_row_addr = spd_read(iic0_dimm_addr[dimm_num], 3); + num_col_addr = spd_read(iic0_dimm_addr[dimm_num], 4); + num_banks = spd_read(iic0_dimm_addr[dimm_num], 5); + bank_size_id = spd_read(iic0_dimm_addr[dimm_num], 31); + + /* + * Set the SDRAM0_BxCR regs + */ + cr = 0; + bank_size_bytes = 4 * 1024 * 1024 * bank_size_id; + switch (bank_size_id) { + case 0x02: + cr |= SDRAM_BXCR_SDSZ_8; + break; + case 0x04: + cr |= SDRAM_BXCR_SDSZ_16; + break; + case 0x08: + cr |= SDRAM_BXCR_SDSZ_32; + break; + case 0x10: + cr |= SDRAM_BXCR_SDSZ_64; + break; + case 0x20: + cr |= SDRAM_BXCR_SDSZ_128; + break; + case 0x40: + cr |= SDRAM_BXCR_SDSZ_256; + break; + case 0x80: + cr |= SDRAM_BXCR_SDSZ_512; + break; + default: + printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n", + dimm_num); + printf("ERROR: Unsupported value for the banksize: %d.\n", + bank_size_id); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + } + + switch (num_col_addr) { + case 0x08: + cr |= SDRAM_BXCR_SDAM_1; + break; + case 0x09: + cr |= SDRAM_BXCR_SDAM_2; + break; + case 0x0A: + cr |= SDRAM_BXCR_SDAM_3; + break; + case 0x0B: + cr |= SDRAM_BXCR_SDAM_4; + break; + default: + printf("DDR-SDRAM: DIMM %lu BxCR configuration.\n", + dimm_num); + printf("ERROR: Unsupported value for number of " + "column addresses: %d.\n", num_col_addr); + printf("Replace the DIMM module with a supported DIMM.\n\n"); + hang(); + } + + /* + * enable the bank + */ + cr |= SDRAM_BXCR_SDBE; + + /*------------------------------------------------------------------ + | This next section is hardware dependent and must be programmed + | to match the hardware. + +-----------------------------------------------------------------*/ + if (dimm_num == 0) { + for (i = 0; i < num_banks; i++) { + mtdcr(memcfga, mem_b0cr + (i << 2)); + temp = mfdcr(memcfgd) & ~(SDRAM_BXCR_SDBA_MASK | + SDRAM_BXCR_SDSZ_MASK | + SDRAM_BXCR_SDAM_MASK | + SDRAM_BXCR_SDBE); + cr |= temp; + cr |= bank_base_addr & SDRAM_BXCR_SDBA_MASK; + mtdcr(memcfgd, cr); + bank_base_addr += bank_size_bytes; + } + } else { + for (i = 0; i < num_banks; i++) { + mtdcr(memcfga, mem_b2cr + (i << 2)); + temp = mfdcr(memcfgd) & ~(SDRAM_BXCR_SDBA_MASK | + SDRAM_BXCR_SDSZ_MASK | + SDRAM_BXCR_SDAM_MASK | + SDRAM_BXCR_SDBE); + cr |= temp; + cr |= bank_base_addr & SDRAM_BXCR_SDBA_MASK; + mtdcr(memcfgd, cr); + bank_base_addr += bank_size_bytes; + } + } } - } } - } - return(bank_base_addr); + return(bank_base_addr); } void program_ecc (unsigned long num_bytes) { - unsigned long bank_base_addr; - unsigned long current_address; - unsigned long end_address; - unsigned long address_increment; - unsigned long cfg0; - - /* - * get Memory Controller Options 0 data - */ - mfsdram(mem_cfg0, cfg0); - - /* - * reset the bank_base address - */ - bank_base_addr = CFG_SDRAM_BASE; - - if ((cfg0 & SDRAM_CFG0_MCHK_MASK) != SDRAM_CFG0_MCHK_NON) { - mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | - SDRAM_CFG0_MCHK_GEN); - - if ((cfg0 & SDRAM_CFG0_DMWD_MASK) == SDRAM_CFG0_DMWD_32) { - address_increment = 4; - } - else { - address_increment = 8; - } + unsigned long bank_base_addr; + unsigned long current_address; + unsigned long end_address; + unsigned long address_increment; + unsigned long cfg0; - current_address = (unsigned long)(bank_base_addr); - end_address = (unsigned long)(bank_base_addr) + num_bytes; + /* + * get Memory Controller Options 0 data + */ + mfsdram(mem_cfg0, cfg0); - while (current_address < end_address) { - *((unsigned long*)current_address) = 0x00000000; - current_address += address_increment; - } + /* + * reset the bank_base address + */ + bank_base_addr = CFG_SDRAM_BASE; + + if ((cfg0 & SDRAM_CFG0_MCHK_MASK) != SDRAM_CFG0_MCHK_NON) { + mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | + SDRAM_CFG0_MCHK_GEN); + + if ((cfg0 & SDRAM_CFG0_DMWD_MASK) == SDRAM_CFG0_DMWD_32) { + address_increment = 4; + } else { + address_increment = 8; + } + + current_address = (unsigned long)(bank_base_addr); + end_address = (unsigned long)(bank_base_addr) + num_bytes; - mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | - SDRAM_CFG0_MCHK_CHK); - } + while (current_address < end_address) { + *((unsigned long*)current_address) = 0x00000000; + current_address += address_increment; + } + + mtsdram(mem_cfg0, (cfg0 & ~SDRAM_CFG0_MCHK_MASK) | + SDRAM_CFG0_MCHK_CHK); + } } #endif /* CONFIG_440 */ diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c index 0d6d88a..7a4af75 100644 --- a/cpu/ppc4xx/speed.c +++ b/cpu/ppc4xx/speed.c @@ -194,7 +194,96 @@ ulong get_PCI_freq (void) #elif defined(CONFIG_440) -#if !defined(CONFIG_440_GX) + +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) +void get_sys_info (sys_info_t *sysInfo) +{ + unsigned long temp; + unsigned long reg; + unsigned long lfdiv; + unsigned long m; + unsigned long prbdv0; + /* + WARNING: ASSUMES the following: + ENG=1 + PRADV0=1 + PRBDV0=1 + */ + + /* Decode CPR0_PLLD0 for divisors */ + mfclk(clk_plld, reg); + temp = (reg & PLLD_FWDVA_MASK) >> 16; + sysInfo->pllFwdDivA = temp ? temp : 16; + temp = (reg & PLLD_FWDVB_MASK) >> 8; + sysInfo->pllFwdDivB = temp ? temp: 8 ; + temp = (reg & PLLD_FBDV_MASK) >> 24; + sysInfo->pllFbkDiv = temp ? temp : 32; + lfdiv = reg & PLLD_LFBDV_MASK; + + mfclk(clk_opbd, reg); + temp = (reg & OPBDDV_MASK) >> 24; + sysInfo->pllOpbDiv = temp ? temp : 4; + + mfclk(clk_perd, reg); + temp = (reg & PERDV_MASK) >> 24; + sysInfo->pllExtBusDiv = temp ? temp : 8; + + mfclk(clk_primbd, reg); + temp = (reg & PRBDV_MASK) >> 24; + prbdv0 = temp ? temp : 8; + + mfclk(clk_spcid, reg); + temp = (reg & SPCID_MASK) >> 24; + sysInfo->pllPciDiv = temp ? temp : 4; + + /* Calculate 'M' based on feedback source */ + mfsdr(sdr_sdstp0, reg); + temp = (reg & PLLSYS0_SEL_MASK) >> 27; + if (temp == 0) { /* PLL output */ + /* Figure which pll to use */ + mfclk(clk_pllc, reg); + temp = (reg & PLLC_SRC_MASK) >> 29; + if (!temp) /* PLLOUTA */ + m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivA; + else /* PLLOUTB */ + m = sysInfo->pllFbkDiv * lfdiv * sysInfo->pllFwdDivB; + } + else if (temp == 1) /* CPU output */ + m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivA; + else /* PerClk */ + m = sysInfo->pllExtBusDiv * sysInfo->pllOpbDiv * sysInfo->pllFwdDivB; + + /* Now calculate the individual clocks */ + sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1); + sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA; + sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB/prbdv0; + sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv; + sysInfo->freqEPB = sysInfo->freqPLB/sysInfo->pllExtBusDiv; + sysInfo->freqPCI = sysInfo->freqPLB/sysInfo->pllPciDiv; + + /* Figure which timer source to use */ + if (mfspr(ccr1) & 0x0080) { /* External Clock, assume same as SYS_CLK */ + temp = sysInfo->freqProcessor / 2; /* Max extern clock speed */ + if (CONFIG_SYS_CLK_FREQ > temp) + sysInfo->freqTmrClk = temp; + else + sysInfo->freqTmrClk = CONFIG_SYS_CLK_FREQ; + } + else /* Internal clock */ + sysInfo->freqTmrClk = sysInfo->freqProcessor; +} +/******************************************** + * get_PCI_freq + * return PCI bus freq in Hz + *********************************************/ +ulong get_PCI_freq (void) +{ + sys_info_t sys_info; + get_sys_info (&sys_info); + return sys_info.freqPCI; +} + +#elif !defined(CONFIG_440_GX) void get_sys_info (sys_info_t * sysInfo) { unsigned long strp0; @@ -220,8 +309,8 @@ void get_sys_info (sys_info_t * sysInfo) sysInfo->freqVCOMhz = (m * CONFIG_SYS_CLK_FREQ) + (m>>1); sysInfo->freqProcessor = sysInfo->freqVCOMhz/sysInfo->pllFwdDivA; sysInfo->freqPLB = sysInfo->freqVCOMhz/sysInfo->pllFwdDivB; - if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */ - sysInfo->freqPLB >>= 1; + if( get_pvr() == PVR_440GP_RB ) /* Rev B divs an extra 2 -- geez! */ + sysInfo->freqPLB >>= 1; sysInfo->freqOPB = sysInfo->freqPLB/sysInfo->pllOpbDiv; sysInfo->freqEPB = sysInfo->freqOPB/sysInfo->pllExtBusDiv; diff --git a/cpu/ppc4xx/start.S b/cpu/ppc4xx/start.S index 3473baa..3a8ff2b 100644 --- a/cpu/ppc4xx/start.S +++ b/cpu/ppc4xx/start.S @@ -344,7 +344,7 @@ _start: lis r1,0x0002 /* set CE bit (Critical Exceptions) */ ori r1,r1,0x1000 /* set ME bit (Machine Exceptions) */ mtmsr r1 /* change MSR */ -#else +#elif !defined(CONFIG_440_EP) && !defined(CONFIG_440_GR) bl __440gx_msr_set b __440gx_msr_continue @@ -377,6 +377,21 @@ __440gx_msr_continue: /* Setup the internal SRAM */ /*----------------------------------------------------------------*/ li r0,0 +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) + /* Clear Dcache to use as RAM */ + lis r3,CFG_INIT_RAM_ADDR@h + li r4,CFG_INIT_RAM_END@l + rlwinm. r5,r4,0,27,31 + rlwinm r5,r4,27,5,31 + beq ..d_ran + addi r5,r5,0x0001 +..d_ran: + mtctr r5 +..d_ag: + dcbz r0,r3 + addi r3,r3,32 + bdnz ..d_ag +#else #if defined (CONFIG_440_GX) mtdcr l2_cache_cfg,r0 /* Ensure L2 Cache is off */ #endif @@ -408,6 +423,7 @@ __440gx_msr_continue: ori r1,r1,0x0380 /* 8k rw */ mtdcr isram0_sb0cr,r1 #endif +#endif /*----------------------------------------------------------------*/ /* Setup the stack in internal SRAM */ @@ -957,7 +973,7 @@ invalidate_icache: invalidate_dcache: addi r6,0,0x0000 /* clear GPR 6 */ /* Do loop for # of dcache congruence classes. */ -#if defined(CONFIG_440_GX) +#if defined(CONFIG_440_GX) || defined(CONFIG_440_EP) || defined(CONFIG_440_GR) lis r7, (CFG_DCACHE_SIZE / CFG_CACHELINE_SIZE / 2)@ha /* TBS for large sized cache */ ori r7, r7, (CFG_DCACHE_SIZE / CFG_CACHELINE_SIZE / 2)@l #else @@ -983,7 +999,7 @@ flush_dcache: mtdccr r10 /* do loop for # of congruence classes. */ -#if defined(CONFIG_440_GX) +#if defined(CONFIG_440_GX) || defined(CONFIG_440_EP) || defined(CONFIG_440_GR) lis r10,(CFG_DCACHE_SIZE / CFG_CACHELINE_SIZE / 2)@ha /* TBS: for large cache sizes */ ori r10,r10,(CFG_DCACHE_SIZE / CFG_CACHELINE_SIZE / 2)@l lis r11,(CFG_DCACHE_SIZE / 2)@ha /* D cache set size - 2 way sets */ @@ -1210,6 +1226,15 @@ ppcSync: */ .globl relocate_code relocate_code: +#if defined(CONFIG_440_EP) || defined(CONFIG_440_GR) + dccci 0,0 /* Invalidate data cache, now no longer our stack */ + sync + addi r1,r0,0x0000 /* Tlb entry #0 */ + tlbre r0,r1,0x0002 /* Read contents */ + ori r0,r0,0x0c00 /* Or in the inhibit, write through bit */ + tlbwe r0,r1,0x0002 /* Save it out */ + isync +#endif mr r1, r3 /* Set new stack pointer */ mr r9, r4 /* Save copy of Init Data pointer */ mr r10, r5 /* Save copy of Destination Address */ @@ -1433,7 +1458,7 @@ trap_reloc: #ifdef CONFIG_405EP ppc405ep_init: -#ifdef CONFIG_BUBINGA405EP +#ifdef CONFIG_BUBINGA /* * Initialize EBC chip selects 1 & 4 and GPIO pins (for alternate * function) to support FPGA and NVRAM accesses below. @@ -1513,7 +1538,7 @@ ppc405ep_init: #endif addi r3,0,CPC0_PCI_HOST_CFG_EN -#ifdef CONFIG_BUBINGA405EP +#ifdef CONFIG_BUBINGA /* !----------------------------------------------------------------------- ! Check FPGA for PCI internal/external arbitration @@ -1548,7 +1573,7 @@ ppc405ep_init: /* and CPU has been reset */ /* so skip to next section */ -#ifdef CONFIG_BUBINGA405EP +#ifdef CONFIG_BUBINGA /* !----------------------------------------------------------------------- ! Read NVRAM to get value to write in PLLMR. @@ -1583,7 +1608,7 @@ ppc405ep_init: cmpi cr0,0,r5,1 /* See if PLL is locked */ beq pll_write ..no_pllset: -#endif /* CONFIG_BUBINGA405EP */ +#endif /* CONFIG_BUBINGA */ addis r3,0,PLLMR0_DEFAULT@h /* PLLMR0 default value */ ori r3,r3,PLLMR0_DEFAULT@l /* */ diff --git a/cpu/ppc4xx/usb_ohci.c b/cpu/ppc4xx/usb_ohci.c new file mode 100644 index 0000000..6176709 --- /dev/null +++ b/cpu/ppc4xx/usb_ohci.c @@ -0,0 +1,1648 @@ +/* + * URB OHCI HCD (Host Controller Driver) for USB on the PPC 440. + * + * (C) Copyright 2003-2004 + * Gary Jennejohn, DENX Software Engineering <gj@denx.de> + * + * (C) Copyright 2004 + * Pierre Aubert, Staubli Faverges <p.aubert@staubli.com> + * + * Note: Much of this code has been derived from Linux 2.4 + * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> + * (C) Copyright 2000-2002 David Brownell + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ +/* + * IMPORTANT NOTES + * 1 - 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> + +#ifdef CONFIG_USB_OHCI + +#include <malloc.h> +#include <usb.h> +#include "usb_ohci.h" +#include "usbdev.h" + +#define OHCI_USE_NPS /* force NoPowerSwitching mode */ +#undef OHCI_VERBOSE_DEBUG /* not always helpful */ +#undef DEBUG +#undef SHOW_INFO +#undef OHCI_FILL_TRACE + +/* For initializing controller (mask in an HCFS mode too) */ +#define OHCI_CONTROL_INIT \ + (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE + +#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; }) + +#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) +#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) + +#if 1 +#define ohci_cpu_to_le16(x) (x) +#define ohci_cpu_to_le32(x) (x) +#else +#define ohci_cpu_to_le16(x) swap_16(x) +#define ohci_cpu_to_le32(x) swap_32(x) +#endif + +/* global ohci_t */ +static ohci_t gohci; +/* this must be aligned to a 256 byte boundary */ +struct ohci_hcca ghcca[1]; +/* a pointer to the aligned storage */ +struct ohci_hcca *phcca; +/* this allocates EDs for all possible endpoints */ +struct ohci_device ohci_dev; +/* urb_priv */ +urb_priv_t urb_priv; +/* RHSC flag */ +int got_rhsc; +/* device which was disconnected */ +struct usb_device *devgone; + +/*-------------------------------------------------------------------------*/ + +/* AMD-756 (D2 rev) reports corrupt register contents in some cases. + * The erratum (#4) description is incorrect. AMD's workaround waits + * till some bits (mostly reserved) are clear; ok for all revs. + */ +#define OHCI_QUIRK_AMD756 0xabcd +#define read_roothub(hc, register, mask) ({ \ + u32 temp = readl (&hc->regs->roothub.register); \ + if (hc->flags & OHCI_QUIRK_AMD756) \ + while (temp & mask) \ + temp = readl (&hc->regs->roothub.register); \ + temp; }) + +static u32 roothub_a(struct ohci *hc) +{ + return read_roothub(hc, a, 0xfc0fe000); +} +static inline u32 roothub_b(struct ohci *hc) +{ + return readl(&hc->regs->roothub.b); +} +static inline u32 roothub_status(struct ohci *hc) +{ + return readl(&hc->regs->roothub.status); +} +static u32 roothub_portstatus(struct ohci *hc, int i) +{ + return read_roothub(hc, portstatus[i], 0xffe0fce0); +} + +/* forward declaration */ +static int hc_interrupt(void); +static void +td_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, struct devrequest *setup, urb_priv_t * urb, + int interval); + +/*-------------------------------------------------------------------------* + * URB support functions + *-------------------------------------------------------------------------*/ + +/* free HCD-private data associated with this URB */ + +static void urb_free_priv(urb_priv_t * urb) +{ + int i; + int last; + struct td *td; + + last = urb->length - 1; + if (last >= 0) { + for (i = 0; i <= last; i++) { + td = urb->td[i]; + if (td) { + td->usb_dev = NULL; + urb->td[i] = NULL; + } + } + } +} + +/*-------------------------------------------------------------------------*/ + +#ifdef DEBUG +static int sohci_get_current_frame_number(struct usb_device *dev); + +/* debug| print the main components of an URB + * small: 0) header + data packets 1) just header */ + +static void pkt_print(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, struct devrequest *setup, char *str, + int small) +{ + urb_priv_t *purb = &urb_priv; + + dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx", + str, + sohci_get_current_frame_number(dev), + usb_pipedevice(pipe), + usb_pipeendpoint(pipe), + usb_pipeout(pipe) ? 'O' : 'I', + usb_pipetype(pipe) < 2 ? (usb_pipeint(pipe) ? "INTR" : "ISOC") : + (usb_pipecontrol(pipe) ? "CTRL" : "BULK"), + purb->actual_length, transfer_len, dev->status); +#ifdef OHCI_VERBOSE_DEBUG + if (!small) { + int i, len; + + if (usb_pipecontrol(pipe)) { + printf(__FILE__ ": cmd(8):"); + for (i = 0; i < 8; i++) + printf(" %02x", ((__u8 *) setup)[i]); + printf("\n"); + } + if (transfer_len > 0 && buffer) { + printf(__FILE__ ": data(%d/%d):", + purb->actual_length, transfer_len); + len = usb_pipeout(pipe) ? + transfer_len : purb->actual_length; + for (i = 0; i < 16 && i < len; i++) + printf(" %02x", ((__u8 *) buffer)[i]); + printf("%s\n", i < len ? "..." : ""); + } + } +#endif +} + +/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/ +void ep_print_int_eds(ohci_t * ohci, char *str) +{ + int i, j; + __u32 *ed_p; + for (i = 0; i < 32; i++) { + j = 5; + ed_p = &(ohci->hcca->int_table[i]); + if (*ed_p == 0) + continue; + printf(__FILE__ ": %s branch int %2d(%2x):", str, i, i); + while (*ed_p != 0 && j--) { + ed_t *ed = (ed_t *) ohci_cpu_to_le32(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 ohci_cpu_to_le16(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 = + ohci_cpu_to_le32((unsigned long)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 = + ohci_cpu_to_le32((unsigned long)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 * edi) +{ + volatile ed_t *ed = edi; + + ed->hwINFO |= ohci_cpu_to_le32(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(ohci_cpu_to_le32(*((__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 *) + ohci_cpu_to_le32(*((__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(ohci_cpu_to_le32(*((__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 *) + ohci_cpu_to_le32(*((__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 = ohci_cpu_to_le32(OHCI_ED_SKIP); /* skip ed */ + /* dummy td; end of td list for ed */ + td = td_alloc(usb_dev); + ed->hwTailP = ohci_cpu_to_le32((unsigned long)td); + ed->hwHeadP = ed->hwTailP; + ed->state = ED_UNLINK; + ed->type = usb_pipetype(pipe); + ohci_dev.ed_cnt++; + } + + ed->hwINFO = ohci_cpu_to_le32(usb_pipedevice(pipe) + | usb_pipeendpoint(pipe) << 7 + | (usb_pipeisoc(pipe) ? 0x8000 : 0) + | (usb_pipecontrol(pipe) ? 0 + : (usb_pipeout(pipe) ? 0x800 : 0x1000)) + | 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 *) (ohci_cpu_to_le32(urb_priv->ed->hwTailP) & ~0xf); + + td->ed = urb_priv->ed; + td->next_dl_td = NULL; + td->index = index; + td->data = (__u32) data; +#ifdef OHCI_FILL_TRACE + if ((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 = ohci_cpu_to_le32(info); + td->hwCBP = ohci_cpu_to_le32((unsigned long)data); + if (data) + td->hwBE = ohci_cpu_to_le32((unsigned long)(data + len - 1)); + else + td->hwBE = 0; + td->hwNextTD = ohci_cpu_to_le32((unsigned long)td_pt); + td->hwPSW[0] = ohci_cpu_to_le16(((__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 = ohci_cpu_to_le32(td->hwINFO); + tdBE = ohci_cpu_to_le32(td->hwBE); + tdCBP = ohci_cpu_to_le32(td->hwCBP); + + if (!(usb_pipetype(lurb_priv->pipe) == PIPE_CONTROL && + ((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 = ohci_cpu_to_le32(ohci->hcca->done_head) & 0xfffffff0; + ohci->hcca->done_head = 0; + + while (td_list_hc) { + td_list = (td_t *) td_list_hc; + + if (TD_CC_GET(ohci_cpu_to_le32(td_list->hwINFO))) { + lurb_priv = &urb_priv; + dbg(" USB-error/status: %x : %p", + TD_CC_GET(ohci_cpu_to_le32(td_list->hwINFO)), + td_list); + if (td_list->ed->hwHeadP & ohci_cpu_to_le32(0x1)) { + if (lurb_priv + && ((td_list->index + 1) < + lurb_priv->length)) { + td_list->ed->hwHeadP = + (lurb_priv-> + td[lurb_priv->length - + 1]-> + hwNextTD & + ohci_cpu_to_le32(0xfffffff0)) | + (td_list->ed-> + hwHeadP & ohci_cpu_to_le32(0x2)); + lurb_priv->td_cnt += + lurb_priv->length - td_list->index - + 1; + } else + td_list->ed->hwHeadP &= + ohci_cpu_to_le32(0xfffffff2); + } +#ifdef CONFIG_MPC5200 + td_list->hwNextTD = 0; +#endif + } + + td_list->next_dl_td = td_rev; + td_rev = td_list; + td_list_hc = ohci_cpu_to_le32(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 = 0xff; + /* 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 = ohci_cpu_to_le32(td_list->hwINFO); + + ed = td_list->ed; + + dl_transfer_length(td_list); + + /* error code of transfer */ + cc = TD_CC_GET(tdINFO); + if (++(lurb_priv->td_cnt) == lurb_priv->length) { + if ((ed->state & (ED_OPER | ED_UNLINK)) + && (lurb_priv->state != URB_DEL)) { + dbg("ConditionCode %#x", cc); + stat = cc_to_error[cc]; + } + } + + if (ed->state != ED_NEW) { + edHeadP = ohci_cpu_to_le32(ed->hwHeadP) & 0xfffffff0; + edTailP = ohci_cpu_to_le32(ed->hwTailP); + + /* unlink eds if they are not busy */ + if ((edHeadP == edTailP) && (ed->state == ED_OPER)) + ep_unlink(ohci, ed); + } + + td_list = td_list_next; + } + return stat; +} + +/*-------------------------------------------------------------------------* + * Virtual Root Hub + *-------------------------------------------------------------------------*/ + +/* Device descriptor */ +static __u8 root_hub_dev_des[] = { + 0x12, /* __u8 bLength; */ + 0x01, /* __u8 bDescriptorType; Device */ + 0x10, /* __u16 bcdUSB; v1.1 */ + 0x01, + 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ + 0x00, /* __u8 bDeviceSubClass; */ + 0x00, /* __u8 bDeviceProtocol; */ + 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ + 0x00, /* __u16 idVendor; */ + 0x00, + 0x00, /* __u16 idProduct; */ + 0x00, + 0x00, /* __u16 bcdDevice; */ + 0x00, + 0x00, /* __u8 iManufacturer; */ + 0x01, /* __u8 iProduct; */ + 0x00, /* __u8 iSerialNumber; */ + 0x01 /* __u8 bNumConfigurations; */ +}; + +/* Configuration descriptor */ +static __u8 root_hub_config_des[] = { + 0x09, /* __u8 bLength; */ + 0x02, /* __u8 bDescriptorType; Configuration */ + 0x19, /* __u16 wTotalLength; */ + 0x00, + 0x01, /* __u8 bNumInterfaces; */ + 0x01, /* __u8 bConfigurationValue; */ + 0x00, /* __u8 iConfiguration; */ + 0x40, /* __u8 bmAttributes; + Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ + 0x00, /* __u8 MaxPower; */ + + /* interface */ + 0x09, /* __u8 if_bLength; */ + 0x04, /* __u8 if_bDescriptorType; Interface */ + 0x00, /* __u8 if_bInterfaceNumber; */ + 0x00, /* __u8 if_bAlternateSetting; */ + 0x01, /* __u8 if_bNumEndpoints; */ + 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ + 0x00, /* __u8 if_bInterfaceSubClass; */ + 0x00, /* __u8 if_bInterfaceProtocol; */ + 0x00, /* __u8 if_iInterface; */ + + /* endpoint */ + 0x07, /* __u8 ep_bLength; */ + 0x05, /* __u8 ep_bDescriptorType; Endpoint */ + 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ + 0x03, /* __u8 ep_bmAttributes; Interrupt */ + 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ + 0x00, + 0xff /* __u8 ep_bInterval; 255 ms */ +}; + +static unsigned char root_hub_str_index0[] = { + 0x04, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 0x09, /* __u8 lang ID */ + 0x04, /* __u8 lang ID */ +}; + +static unsigned char root_hub_str_index1[] = { + 28, /* __u8 bLength; */ + 0x03, /* __u8 bDescriptorType; String-descriptor */ + 'O', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'H', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'C', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'I', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'R', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'o', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 't', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + ' ', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'H', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'u', /* __u8 Unicode */ + 0, /* __u8 Unicode */ + 'b', /* __u8 Unicode */ + 0, /* __u8 Unicode */ +}; + +/* Hub class-specific descriptor is constructed dynamically */ + +/*-------------------------------------------------------------------------*/ + +#define OK(x) len = (x); break +#ifdef DEBUG +#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);} +#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);} +#else +#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status) +#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1]) +#endif +#define RD_RH_STAT roothub_status(&gohci) +#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1) + +/* request to virtual root hub */ + +int rh_check_port_status(ohci_t * controller) +{ + __u32 temp, ndp, i; + int res; + + res = -1; + temp = roothub_a(controller); + ndp = (temp & RH_A_NDP); + for (i = 0; i < ndp; i++) { + temp = roothub_portstatus(controller, i); + /* check for a device disconnect */ + if (((temp & (RH_PS_PESC | RH_PS_CSC)) == + (RH_PS_PESC | RH_PS_CSC)) && ((temp & RH_PS_CCS) == 0)) { + res = i; + break; + } + } + return res; +} + +static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, + struct devrequest *cmd) +{ + void *data = buffer; + int leni = transfer_len; + int len = 0; + int stat = 0; + __u32 datab[4]; + __u8 *data_buf = (__u8 *) datab; + __u16 bmRType_bReq; + __u16 wValue; + __u16 wIndex; + __u16 wLength; + +#ifdef DEBUG + urb_priv.actual_length = 0; + pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", + usb_pipein(pipe)); +#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); +#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) */ ); +#endif + + return stat; +} + +/*-------------------------------------------------------------------------*/ + +/* common code for handling submit messages - used for all but root hub */ +/* accesses. */ +int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, struct devrequest *setup, int interval) +{ + int stat = 0; + int maxsize = usb_maxpacket(dev, pipe); + int timeout; + + /* device pulled? Shortcut the action. */ + if (devgone == dev) { + dev->status = USB_ST_CRC_ERR; + return 0; + } +#ifdef DEBUG + urb_priv.actual_length = 0; + pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", + usb_pipein(pipe)); +#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; + } + + /* allow more time for a BULK device to react - some are slow */ +#define BULK_TO 5000 /* timeout in milliseconds */ + if (usb_pipetype(pipe) == PIPE_BULK) + timeout = BULK_TO; + else + timeout = 100; + + /* wait for it to complete */ + for (;;) { + /* check whether the controller is done */ + stat = hc_interrupt(); + if (stat < 0) { + stat = USB_ST_CRC_ERR; + break; + } + if (stat >= 0 && stat < 0xff) { + /* 0xff is returned for an SF-interrupt */ + break; + } + if (--timeout) { + wait_ms(1); + } else { + err("CTL:TIMEOUT "); + stat = USB_ST_CRC_ERR; + break; + } + } + /* we got an Root Hub Status Change interrupt */ + if (got_rhsc) { +#ifdef DEBUG + ohci_dump_roothub(&gohci, 1); +#endif + got_rhsc = 0; + /* abuse timeout */ + timeout = rh_check_port_status(&gohci); + if (timeout >= 0) { +#if 0 /* this does nothing useful, but leave it here in case that changes */ + /* the called routine adds 1 to the passed value */ + usb_hub_port_connect_change(gohci.rh.dev, timeout - 1); +#endif + /* + * XXX + * This is potentially dangerous because it assumes + * that only one device is ever plugged in! + */ + devgone = dev; + } + } + + dev->status = stat; + dev->act_len = transfer_len; + +#ifdef DEBUG + pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", + usb_pipein(pipe)); +#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)); +#endif + if (!maxsize) { + err("submit_control_message: pipesize for pipe %lx is zero", + pipe); + return -1; + } + if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) { + gohci.rh.dev = dev; + /* root hub - redirect */ + return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len, + setup); + } + + return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0); +} + +int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int transfer_len, int interval) +{ + info("submit_int_msg"); + return -1; +} + +/*-------------------------------------------------------------------------* + * HC functions + *-------------------------------------------------------------------------*/ + +/* reset the HC and BUS */ + +static int hc_reset(ohci_t * ohci) +{ + int timeout = 30; + int smm_timeout = 50; /* 0,5 sec */ + + 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) */ + ohci->hc_control = 0; + writel(ohci->hc_control, &ohci->regs->control); + + /* HC Reset requires max 10 us delay */ + writel(OHCI_HCR, &ohci->regs->cmdstatus); + while ((readl(&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { + if (--timeout == 0) { + err("USB HC reset timed out!"); + return -1; + } + udelay(1); + } + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* Start an OHCI controller, set the BUS operational + * enable interrupts + * connect the virtual root hub */ + +static int hc_start(ohci_t * ohci) +{ + __u32 mask; + unsigned int fminterval; + + ohci->disabled = 1; + + /* Tell the controller where the control and bulk lists are + * The lists are empty now. */ + + writel(0, &ohci->regs->ed_controlhead); + writel(0, &ohci->regs->ed_bulkhead); + + writel((__u32) ohci->hcca, &ohci->regs->hcca); /* a reset clears this */ + + fminterval = 0x2edf; + writel((fminterval * 9) / 10, &ohci->regs->periodicstart); + fminterval |= ((((fminterval - 210) * 6) / 7) << 16); + writel(fminterval, &ohci->regs->fminterval); + writel(0x628, &ohci->regs->lsthresh); + + /* start controller operations */ + ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; + ohci->disabled = 0; + writel(ohci->hc_control, &ohci->regs->control); + + /* disable all interrupts */ + mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD | + OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC | + OHCI_INTR_OC | OHCI_INTR_MIE); + writel(mask, &ohci->regs->intrdisable); + /* clear all interrupts */ + mask &= ~OHCI_INTR_MIE; + writel(mask, &ohci->regs->intrstatus); + /* Choose the interrupts we care about now - but w/o MIE */ + mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO; + writel(mask, &ohci->regs->intrenable); + +#ifdef OHCI_USE_NPS + /* required for AMD-756 and some Mac platforms */ + writel((roothub_a(ohci) | RH_A_NPS) & ~RH_A_PSM, + &ohci->regs->roothub.a); + writel(RH_HS_LPSC, &ohci->regs->roothub.status); +#endif /* OHCI_USE_NPS */ + +#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);}) + /* POTPGT delay is bits 24-31, in 2 ms units. */ + mdelay((roothub_a(ohci) >> 23) & 0x1fe); + + /* connect the virtual root hub */ + ohci->rh.devnum = 0; + + return 0; +} + +/*-------------------------------------------------------------------------*/ + +/* an interrupt happens */ + +static int hc_interrupt(void) +{ + ohci_t *ohci = &gohci; + struct ohci_regs *regs = ohci->regs; + int ints; + int stat = -1; + + if ((ohci->hcca->done_head != 0) + && !(ohci_cpu_to_le32(ohci->hcca->done_head) & 0x01)) { + ints = OHCI_INTR_WDH; + } else { + ints = readl(®s->intrstatus); + } + + /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */ + + if (ints & OHCI_INTR_RHSC) { + got_rhsc = 1; + } + + if (ints & OHCI_INTR_UE) { + ohci->disabled++; + err("OHCI Unrecoverable Error, controller usb-%s disabled", + ohci->slot_name); + /* e.g. due to PCI Master/Target Abort */ + +#ifdef DEBUG + ohci_dump(ohci, 1); +#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) { + 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 = ohci_cpu_to_le16(ohci->hcca->frame_no) & 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) +{ + + 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 *)(CFG_PERIPHERAL_BASE | 0x1000); + + gohci.flags = 0; + gohci.slot_name = "ppc440"; + + if (hc_reset(&gohci) < 0) { + hc_release_ohci(&gohci); + return -1; + } + + if (hc_start(&gohci) < 0) { + err("can't start usb-%s", gohci.slot_name); + hc_release_ohci(&gohci); + return -1; + } +#ifdef DEBUG + ohci_dump(&gohci, 1); +#endif + ohci_inited = 1; + + /* init the device driver */ + usb_dev_init(); + + return 0; +} + +int usb_lowlevel_stop(void) +{ + /* this gets called really early - before the controller has */ + /* even been initialized! */ + if (!ohci_inited) + return 0; + /* TODO release any interrupts, etc. */ + /* call hc_release_ohci() here ? */ + hc_reset(&gohci); + return 0; +} + +#endif /* CONFIG_USB_OHCI */ diff --git a/cpu/ppc4xx/usb_ohci.h b/cpu/ppc4xx/usb_ohci.h new file mode 100644 index 0000000..706e05e --- /dev/null +++ b/cpu/ppc4xx/usb_ohci.h @@ -0,0 +1,410 @@ +/* + * 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 */ +#if defined(CONFIG_MPC5200) + __u16 pad1; /* set to 0 on each frame_no change */ + __u16 frame_no; /* current frame number */ +#else + __u16 frame_no; /* current frame number */ + __u16 pad1; /* set to 0 on each frame_no change */ +#endif + __u32 done_head; /* info returned for an interrupt */ + u8 reserved_for_hc[116]; +} __attribute((aligned(256))); + +/* + * 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/usbdev.c b/cpu/ppc4xx/usbdev.c new file mode 100644 index 0000000..f0901ac --- /dev/null +++ b/cpu/ppc4xx/usbdev.c @@ -0,0 +1,214 @@ +/*USB 1.1,2.0 device*/ + +#include <common.h> +#include <asm/processor.h> + +#ifdef CONFIG_440_EP + +#include <usb.h> +#include "usbdev.h" +#include "vecnum.h" + +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 + +unsigned char set_value = -1; + +void process_endpoints(unsigned short usb2d0_intrin) +{ + /*will hold the packet received */ + struct usb_device_descriptor usb_device_packet; + struct usb_config_descriptor usb_config_packet; + struct usb_string_descriptor usb_string_packet; + struct devrequest setup_packet; + unsigned int *setup_packet_pt; + unsigned char *packet_pt; + int temp, temp1; + + int i; + + /*printf("{USB device} - endpoint 0x%X \n", usb2d0_intrin); */ + + /*set usb address, seems to not work unless it is done in the next + interrupt, so that is why it is done this way */ + if (set_value != -1) + *(unsigned char *)USB2D0_FADDR_8 = set_value; + + /*endpoint 1 */ + if (usb2d0_intrin & 0x01) { + setup_packet_pt = (unsigned int *)&setup_packet; + + /*copy packet */ + setup_packet_pt[0] = *(unsigned int *)USB2D0_FIFO_0; + setup_packet_pt[1] = *(unsigned int *)USB2D0_FIFO_0; + temp = *(unsigned int *)USB2D0_FIFO_0; + temp1 = *(unsigned int *)USB2D0_FIFO_0; + + /*do some swapping */ + setup_packet.value = swap_16(setup_packet.value); + setup_packet.index = swap_16(setup_packet.index); + setup_packet.length = swap_16(setup_packet.length); + + /*clear rx packet */ + *(unsigned short *)USB2D0_INCSR0_8 = 0x48; + + /*printf("0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", setup_packet.requesttype, + setup_packet.request, setup_packet.value, + setup_packet.index, setup_packet.length, temp, temp1 ); */ + + switch (setup_packet.request) { + case USB_REQ_GET_DESCRIPTOR: + + switch (setup_packet.value >> 8) { + case USB_DT_DEVICE: + /*create packet */ + usb_device_packet.bLength = 18; + usb_device_packet.bDescriptorType = + USB_DT_DEVICE; +#ifdef USB_2_0_DEVICE + usb_device_packet.bcdUSB = swap_16(0x200); +#else + usb_device_packet.bcdUSB = swap_16(0x110); +#endif + usb_device_packet.bDeviceClass = 0xff; + usb_device_packet.bDeviceSubClass = 0; + usb_device_packet.bDeviceProtocol = 0; + usb_device_packet.bMaxPacketSize0 = 32; + usb_device_packet.idVendor = swap_16(1); + usb_device_packet.idProduct = swap_16(2); + usb_device_packet.bcdDevice = swap_16(0x300); + usb_device_packet.iManufacturer = 1; + usb_device_packet.iProduct = 1; + usb_device_packet.iSerialNumber = 1; + usb_device_packet.bNumConfigurations = 1; + + /*put packet in fifo */ + packet_pt = (unsigned char *)&usb_device_packet; + break; + + case USB_DT_CONFIG: + /*create packet */ + usb_config_packet.bLength = 9; + usb_config_packet.bDescriptorType = + USB_DT_CONFIG; + usb_config_packet.wTotalLength = swap_16(25); + usb_config_packet.bNumInterfaces = 1; + usb_config_packet.bConfigurationValue = 1; + usb_config_packet.iConfiguration = 0; + usb_config_packet.bmAttributes = 0x40; + usb_config_packet.MaxPower = 0; + + /*put packet in fifo */ + packet_pt = (unsigned char *)&usb_config_packet; + break; + + case USB_DT_STRING: + /*create packet */ + usb_string_packet.bLength = 2; + usb_string_packet.bDescriptorType = + USB_DT_STRING; + usb_string_packet.wData[0] = 0x0094; + + /*put packet in fifo */ + packet_pt = (unsigned char *)&usb_string_packet; + break; + } + + /*put packet in fifo */ + for (i = 0; i < (setup_packet.length); i++) { + *(unsigned char *)USB2D0_FIFO_0 = packet_pt[i]; + } + + /*give tx command */ + *(unsigned short *)USB2D0_INCSR0_8 = 0x0a; + + break; + + case USB_REQ_SET_ADDRESS: + + /*copy usb address */ + set_value = setup_packet.value; + + break; + } + + } +} + +void process_other(unsigned char usb2d0_intrusb) +{ + + /*check for sof */ + if (usb2d0_intrusb & 0x08) { + /*printf("{USB device} - sof detected\n"); */ + } + + /*check for reset */ + if (usb2d0_intrusb & 0x04) { + /*printf("{USB device} - reset detected\n"); */ + + /*copy usb address of zero, need to do this when usb reset */ + set_value = 0; + } + + if (usb2d0_intrusb & 0x02) { + /*printf("{USB device} - resume detected\n"); */ + } + + if (usb2d0_intrusb & 0x01) { + /*printf("{USB device} - suspend detected\n"); */ + } +} + +int usbInt(void) +{ + /*Must read these 2 registers and use values to clear interrupts. If you + do not read them then the interrupt will not be cleared. If you do not + use the variable the optimizer will not do a read. */ + volatile unsigned short usb2d0_intrin = + *(unsigned short *)USB2D0_INTRIN_16; + volatile unsigned char usb2d0_intrusb = + *(unsigned char *)USB2D0_INTRUSB_8; + + /*check if there was an endpoint interrupt */ + if (usb2d0_intrin != 0) { + process_endpoints(usb2d0_intrin); + } + + /*check for other interrupts */ + if (usb2d0_intrusb != 0) { + process_other(usb2d0_intrusb); + } + + return 0; +} + +void usb_dev_init() +{ +#ifdef USB_2_0_DEVICE + printf("USB 2.0 Device init\n"); + /*select 2.0 device */ + mtsdr(sdr_usb0, 0x0); /* 2.0 */ + + /*usb dev init */ + *(unsigned char *)USB2D0_POWER_8 = 0xa1; /* 2.0 */ +#else + printf("USB 1.1 Device init\n"); + /*select 1.1 device */ + mtsdr(sdr_usb0, 0x2); /* 1.1 */ + + /*usb dev init */ + *(unsigned char *)USB2D0_POWER_8 = 0xc0; /* 1.1 */ +#endif + + /*enable interrupts */ + *(unsigned char *)USB2D0_INTRUSBE_8 = 0x0f; + + irq_install_handler(VECNUM_USBDEV, (interrupt_handler_t *) usbInt, + NULL); +} + +#endif /*CONFIG_440_EP */ diff --git a/cpu/ppc4xx/usbdev.h b/cpu/ppc4xx/usbdev.h new file mode 100644 index 0000000..3446d98 --- /dev/null +++ b/cpu/ppc4xx/usbdev.h @@ -0,0 +1,31 @@ +#include <config.h> + +/*Common Registers*/ +#define USB2D0_INTRIN_16 (CFG_USB_DEVICE | 0x100) +#define USB2D0_POWER_8 (CFG_USB_DEVICE | 0x102) +#define USB2D0_FADDR_8 (CFG_USB_DEVICE | 0x103) +#define USB2D0_INTRINE_16 (CFG_USB_DEVICE | 0x104) +#define USB2D0_INTROUT_16 (CFG_USB_DEVICE | 0x106) +#define USB2D0_INTRUSBE_8 (CFG_USB_DEVICE | 0x108) +#define USB2D0_INTRUSB_8 (CFG_USB_DEVICE | 0x109) +#define USB2D0_INTROUTE_16 (CFG_USB_DEVICE | 0x10a) +#define USB2D0_TSTMODE_8 (CFG_USB_DEVICE | 0x10c) +#define USB2D0_INDEX_8 (CFG_USB_DEVICE | 0x10d) +#define USB2D0_FRAME_16 (CFG_USB_DEVICE | 0x10e) + +/*Indexed Registers*/ +#define USB2D0_INCSR0_8 (CFG_USB_DEVICE | 0x110) +#define USB2D0_INCSR_16 (CFG_USB_DEVICE | 0x110) +#define USB2D0_INMAXP_16 (CFG_USB_DEVICE | 0x112) +#define USB2D0_OUTCSR_16 (CFG_USB_DEVICE | 0x114) +#define USB2D0_OUTMAXP_16 (CFG_USB_DEVICE | 0x116) +#define USB2D0_OUTCOUNT0_8 (CFG_USB_DEVICE | 0x11a) +#define USB2D0_OUTCOUNT_16 (CFG_USB_DEVICE | 0x11a) + +/*FIFOs*/ +#define USB2D0_FIFO_0 (CFG_USB_DEVICE | 0x120) +#define USB2D0_FIFO_1 (CFG_USB_DEVICE | 0x124) +#define USB2D0_FIFO_2 (CFG_USB_DEVICE | 0x128) +#define USB2D0_FIFO_3 (CFG_USB_DEVICE | 0x12c) + +void usb_dev_init(void); diff --git a/cpu/ppc4xx/vecnum.h b/cpu/ppc4xx/vecnum.h index d493a5d..1038975 100644 --- a/cpu/ppc4xx/vecnum.h +++ b/cpu/ppc4xx/vecnum.h @@ -69,6 +69,7 @@ #define VECNUM_MS (32 + 0 ) /* MAL SERR */ #define VECNUM_TXDE (32 + 1 ) /* MAL TXDE */ #define VECNUM_RXDE (32 + 2 ) /* MAL RXDE */ +#define VECNUM_USBDEV (32 + 23) /* USB 1.1/USB 2.0 Device */ #define VECNUM_ETH0 (32 + 28) /* Ethernet 0 interrupt status */ #define VECNUM_EWU0 (32 + 29) /* Ethernet 0 wakeup */ |