diff options
| author | wdenk <wdenk> | 2004-06-09 00:34:46 +0000 | 
|---|---|---|
| committer | wdenk <wdenk> | 2004-06-09 00:34:46 +0000 | 
| commit | 97d80fc3912e517ee40e269abf534a006025da5c (patch) | |
| tree | 85ea07788f8eb1eb6589ecb3e125433620ed815b | |
| parent | 6bdd1377af6d1a17b3b18df06b52362a1b67ad3d (diff) | |
| download | olio-uboot-2014.01-97d80fc3912e517ee40e269abf534a006025da5c.tar.xz olio-uboot-2014.01-97d80fc3912e517ee40e269abf534a006025da5c.zip | |
Patches Part 1 by Jon Loeliger, 11 May 2004:
Dynamically handle REV1 and REV2 MPC85xx parts.
  (Jon Loeliger, 10-May-2004).
New consistent memory map and Local Access Window across MPC85xx line.
New CCSRBAR at 0xE000_0000 now.
Add RAPID I/O memory map.
New memory map in README.MPC85xxads
  (Kumar Gala, 10-May-2004)
Better board and CPU identification on MPC85xx boards at boot.
  (Jon Loeliger, 10-May-2004)
SDRAM clock control fixes on MPC8540ADS & MPC8560 boards.
Some configuration options for MPC8540ADS & MPC8560ADS cleaned up.
  (Jim Robertson, 10-May-2004)
Rewrite of the MPC85xx Three Speed Ethernet Controller (TSEC) driver.
Supports multiple PHYs.
  (Andy Fleming, 10-May-2004)
Some README.MPC85xxads updates.
  (Kumar Gala, 10-May-2004)
Copyright updates for "Freescale"
  (Andy Fleming, 10-May-2004)
| -rw-r--r-- | CHANGELOG | 21 | ||||
| -rw-r--r-- | board/mpc8540ads/config.mk | 1 | ||||
| -rw-r--r-- | board/mpc8540ads/init.S | 48 | ||||
| -rw-r--r-- | board/mpc8540ads/mpc8540ads.c | 44 | ||||
| -rw-r--r-- | board/mpc8560ads/config.mk | 1 | ||||
| -rw-r--r-- | board/mpc8560ads/init.S | 50 | ||||
| -rw-r--r-- | board/mpc8560ads/mpc8560ads.c | 36 | ||||
| -rw-r--r-- | common/cmd_bdinfo.c | 13 | ||||
| -rw-r--r-- | cpu/mpc85xx/cpu.c | 91 | ||||
| -rw-r--r-- | cpu/mpc85xx/spd_sdram.c | 316 | ||||
| -rw-r--r-- | cpu/mpc85xx/speed.c | 4 | ||||
| -rw-r--r-- | cpu/mpc85xx/start.S | 66 | ||||
| -rw-r--r-- | cpu/mpc85xx/tsec.c | 790 | ||||
| -rw-r--r-- | cpu/mpc85xx/tsec.h | 179 | 
14 files changed, 1174 insertions, 486 deletions
| @@ -2,6 +2,27 @@  Changes since U-Boot 1.1.1:  ====================================================================== +* Patches Part 1 by Jon Loeliger, 11 May 2004: +  Dynamically handle REV1 and REV2 MPC85xx parts. +    (Jon Loeliger, 10-May-2004). +  New consistent memory map and Local Access Window across MPC85xx line. +  New CCSRBAR at 0xE000_0000 now. +  Add RAPID I/O memory map. +  New memory map in README.MPC85xxads +    (Kumar Gala, 10-May-2004) +  Better board and CPU identification on MPC85xx boards at boot. +    (Jon Loeliger, 10-May-2004) +  SDRAM clock control fixes on MPC8540ADS & MPC8560 boards. +  Some configuration options for MPC8540ADS & MPC8560ADS cleaned up. +    (Jim Robertson, 10-May-2004) +  Rewrite of the MPC85xx Three Speed Ethernet Controller (TSEC) driver. +  Supports multiple PHYs. +    (Andy Fleming, 10-May-2004) +  Some README.MPC85xxads updates. +    (Kumar Gala, 10-May-2004) +  Copyright updates for "Freescale" +    (Andy Fleming, 10-May-2004) +  * Patch by Stephen Williams, 11 May 2004:    Add flash support for ST M29W040B    Reduce JSE specific flash.c to remove dead code. diff --git a/board/mpc8540ads/config.mk b/board/mpc8540ads/config.mk index 186a2f20d..92f893197 100644 --- a/board/mpc8540ads/config.mk +++ b/board/mpc8540ads/config.mk @@ -1,3 +1,4 @@ +# Copyright 2004 Freescale Semiconductor.  # Modified by Xianghua Xiao, X.Xiao@motorola.com  # (C) Copyright 2002,Motorola Inc.  # diff --git a/board/mpc8540ads/init.S b/board/mpc8540ads/init.S index 8c2ca65a9..486fdc86c 100644 --- a/board/mpc8540ads/init.S +++ b/board/mpc8540ads/init.S @@ -1,4 +1,5 @@  /* + * Copyright 2004 Freescale Semiconductor.  * Copyright (C) 2002,2003, Motorola Inc.  * Xianghua Xiao <X.Xiao@motorola.com>  * @@ -136,43 +137,58 @@ tlb1_entry:    #endif  	entry_end -/* LAW(Local Access Window) configuration: - * 0000_0000-0800_0000: DDR(128M) -or- larger - * f000_0000-f3ff_ffff: PCI(256M) - * f400_0000-f7ff_ffff: RapidIO(128M) - * f800_0000-ffff_ffff: localbus(128M) - *   f800_0000-fbff_ffff: LBC SDRAM(64M) - *   fc00_0000-fdef_ffff: LBC BCSR,RTC,etc(31M) - *   fdf0_0000-fdff_ffff: CCSRBAR(1M) - *   fe00_0000-ffff_ffff: Flash(32M) - * Note: CCSRBAR and L2-as-SRAM don't need configure Local Access - *       Window. +/* + * LAW(Local Access Window) configuration: + * + * 0x0000_0000     0x7fff_ffff     DDR                     2G + * 0x8000_0000     0x9fff_ffff     PCI MEM                 512M + * 0xe000_0000     0xe000_ffff     CCSR                    1M + * 0xe200_0000     0xe2ff_ffff     PCI IO                  16M + * 0xf000_0000     0xf7ff_ffff     SDRAM                   128M + * 0xf800_0000     0xf80f_ffff     BCSR                    1M + * 0xff00_0000     0xffff_ffff     FLASH (boot bank)       16M + * + * Note: CCSRBAR and L2-as-SRAM don't need a configured Local Access Window.   * Note: If flash is 8M at default position(last 8M),no LAW needed.   */  #if !defined(CONFIG_SPD_EEPROM)  #define LAWBAR0 ((CFG_DDR_SDRAM_BASE>>12) & 0xfffff) -#define LAWAR0 	(LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & LAWAR_SIZE_128M)) +#define LAWAR0	(LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & LAWAR_SIZE_128M))  #else  #define LAWBAR0 0  #define LAWAR0  ((LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & LAWAR_SIZE_128M)) & ~LAWAR_EN)  #endif  #define LAWBAR1 ((CFG_PCI_MEM_BASE>>12) & 0xfffff) -#define LAWAR1 	(LAWAR_EN | LAWAR_TRGT_IF_PCIX | (LAWAR_SIZE & LAWAR_SIZE_256M)) +#define LAWAR1	(LAWAR_EN | LAWAR_TRGT_IF_PCIX | (LAWAR_SIZE & LAWAR_SIZE_512M)) +/* + * This is not so much the SDRAM map as it is the whole localbus map. + */  #if !defined(CONFIG_RAM_AS_FLASH)  #define LAWBAR2 ((CFG_LBC_SDRAM_BASE>>12) & 0xfffff) -#define LAWAR2 	(LAWAR_EN | LAWAR_TRGT_IF_LBC | (LAWAR_SIZE & LAWAR_SIZE_128M)) +#define LAWAR2	(LAWAR_EN | LAWAR_TRGT_IF_LBC | (LAWAR_SIZE & LAWAR_SIZE_256M))  #else  #define LAWBAR2 0  #define LAWAR2 ((LAWAR_TRGT_IF_LBC | (LAWAR_SIZE & LAWAR_SIZE_128M)) & ~LAWAR_EN)  #endif +#define LAWBAR3 ((CFG_PCI_IO_BASE>>12) & 0xfffff) +#define LAWAR3	(LAWAR_EN | LAWAR_TRGT_IF_PCIX | (LAWAR_SIZE & LAWAR_SIZE_16M)) + +/* + * Rapid IO at 0xc000_0000 for 512 M + */ +#define LAWBAR4 ((CFG_RAPID_IO_BASE>>12) & 0xfffff) +#define LAWAR4	(LAWAR_EN | LAWAR_TRGT_IF_PCIX | (LAWAR_SIZE & LAWAR_SIZE_512M)) + +  	.section .bootpg, "ax"  	.globl	law_entry  law_entry:  	entry_start -	.long 0x03 -	.long LAWBAR0,LAWAR0,LAWBAR1,LAWAR1,LAWBAR2,LAWAR2 +	.long 0x05 +	.long LAWBAR0,LAWAR0,LAWBAR1,LAWAR1,LAWBAR2,LAWAR2,LAWBAR3,LAWAR3 +	.long LAWBAR4,LAWAR4  	entry_end diff --git a/board/mpc8540ads/mpc8540ads.c b/board/mpc8540ads/mpc8540ads.c index 0644de882..2694d62d2 100644 --- a/board/mpc8540ads/mpc8540ads.c +++ b/board/mpc8540ads/mpc8540ads.c @@ -1,4 +1,4 @@ -/* + /*   * (C) Copyright 2002,2003, Motorola Inc.   * Xianghua Xiao, (X.Xiao@motorola.com)   * @@ -33,6 +33,13 @@ extern long int spd_sdram (void);  long int fixed_sdram (void); +#if defined(CONFIG_DDR_ECC) +void dma_init(void); +uint dma_check(void); +int dma_xfer(void *dest, uint count, void *src); +#endif + +  /* MPC8540ADS Board Status & Control Registers */  #if 0  typedef struct bscr_ { @@ -60,24 +67,11 @@ int board_early_init_f (void)  int checkboard (void)  { -	sys_info_t sysinfo; - -	get_sys_info (&sysinfo); - -	printf ("Board: Motorola MPC8540ADS Board\n"); -	printf ("\tCPU: %lu MHz\n", sysinfo.freqProcessor / 1000000); -	printf ("\tCCB: %lu MHz\n", sysinfo.freqSystemBus / 1000000); -	printf ("\tDDR: %lu MHz\n", sysinfo.freqSystemBus / 2000000); -	if((CFG_LBC_LCRR & 0x0f) == 2 || (CFG_LBC_LCRR & 0x0f) == 4 \ -		|| (CFG_LBC_LCRR & 0x0f) == 8) { -		printf ("\tLBC: %lu MHz\n", sysinfo.freqSystemBus / 1000000 /(CFG_LBC_LCRR & 0x0f)); -	} else { -		printf("\tLBC: unknown\n"); -	} -	printf("L1 D-cache 32KB, L1 I-cache 32KB enabled.\n"); -	return (0); +	puts("Board: ADS\n"); +	return 0;  } +  long int initdram (int board_type)  {  	long dram_size = 0; @@ -91,8 +85,9 @@ long int initdram (int board_type)  #if !defined(CONFIG_RAM_AS_FLASH) || defined(CONFIG_DDR_DLL)  	volatile ccsr_gur_t *gur= &immap->im_gur;  #endif +  #if defined(CONFIG_DDR_DLL) -	uint temp_ddrdll = 0; +       uint temp_ddrdll = 0;  	/* Work around to stabilize DDR DLL */  	temp_ddrdll = gur->ddrdllcr; @@ -112,9 +107,16 @@ long int initdram (int board_type)  	if(sysinfo.freqSystemBus/(CFG_LBC_LCRR & 0x0f) < 66000000) {  		lbc->lcrr = (CFG_LBC_LCRR & 0x0fffffff)| 0x80000000;  	} else { -#if defined(CONFIG_MPC85xx_REV1) /* need change CLKDIV before enable DLL */ -		lbc->lcrr = 0x10000004; /* default CLKDIV is 8, change it to 4 temporarily */ -#endif +		uint pvr = get_pvr(); + +		if (pvr == PVR_85xx_REV1) { +			/* +			 * Need change CLKDIV before enable DLL. +			 * Default CLKDIV is 8, change it to 4 +			 * temporarily. +			 */ +		    lbc->lcrr = 0x10000004; +		}  		lbc->lcrr = CFG_LBC_LCRR & 0x7fffffff;  		udelay(200);  		temp_lbcdll = gur->lbcdllcr; diff --git a/board/mpc8560ads/config.mk b/board/mpc8560ads/config.mk index 698fdaa94..53e3edb26 100644 --- a/board/mpc8560ads/config.mk +++ b/board/mpc8560ads/config.mk @@ -1,3 +1,4 @@ +# Copyright 2004 Freescale Semiconductor.  # Modified by Xianghua Xiao, X.Xiao@motorola.com  # (C) Copyright 2002,2003 Motorola Inc.  # diff --git a/board/mpc8560ads/init.S b/board/mpc8560ads/init.S index c716ef13b..486fdc86c 100644 --- a/board/mpc8560ads/init.S +++ b/board/mpc8560ads/init.S @@ -1,4 +1,5 @@  /* + * Copyright 2004 Freescale Semiconductor.  * Copyright (C) 2002,2003, Motorola Inc.  * Xianghua Xiao <X.Xiao@motorola.com>  * @@ -136,43 +137,58 @@ tlb1_entry:    #endif  	entry_end -/* LAW(Local Access Window) configuration: - * 0000_0000-0800_0000: DDR(128M) -or- larger - * f000_0000-f3ff_ffff: PCI(256M) - * f400_0000-f7ff_ffff: RapidIO(128M) - * f800_0000-ffff_ffff: localbus(128M) - *   f800_0000-fbff_ffff: LBC SDRAM(64M) - *   fc00_0000-fdef_ffff: LBC BCSR,RTC,etc(31M) - *   fdf0_0000-fdff_ffff: CCSRBAR(1M) - *   fe00_0000-ffff_ffff: Flash(32M) - * Note: CCSRBAR and L2-as-SRAM don't need configure Local Access - *       Window. +/* + * LAW(Local Access Window) configuration: + * + * 0x0000_0000     0x7fff_ffff     DDR                     2G + * 0x8000_0000     0x9fff_ffff     PCI MEM                 512M + * 0xe000_0000     0xe000_ffff     CCSR                    1M + * 0xe200_0000     0xe2ff_ffff     PCI IO                  16M + * 0xf000_0000     0xf7ff_ffff     SDRAM                   128M + * 0xf800_0000     0xf80f_ffff     BCSR                    1M + * 0xff00_0000     0xffff_ffff     FLASH (boot bank)       16M + * + * Note: CCSRBAR and L2-as-SRAM don't need a configured Local Access Window.   * Note: If flash is 8M at default position(last 8M),no LAW needed.   */  #if !defined(CONFIG_SPD_EEPROM)  #define LAWBAR0 ((CFG_DDR_SDRAM_BASE>>12) & 0xfffff) -#define LAWAR0  (LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & LAWAR_SIZE_128M)) +#define LAWAR0	(LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & LAWAR_SIZE_128M))  #else  #define LAWBAR0 0  #define LAWAR0  ((LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & LAWAR_SIZE_128M)) & ~LAWAR_EN)  #endif  #define LAWBAR1 ((CFG_PCI_MEM_BASE>>12) & 0xfffff) -#define LAWAR1  (LAWAR_EN | LAWAR_TRGT_IF_PCIX | (LAWAR_SIZE & LAWAR_SIZE_256M)) +#define LAWAR1	(LAWAR_EN | LAWAR_TRGT_IF_PCIX | (LAWAR_SIZE & LAWAR_SIZE_512M)) +/* + * This is not so much the SDRAM map as it is the whole localbus map. + */  #if !defined(CONFIG_RAM_AS_FLASH)  #define LAWBAR2 ((CFG_LBC_SDRAM_BASE>>12) & 0xfffff) -#define LAWAR2  (LAWAR_EN | LAWAR_TRGT_IF_LBC | (LAWAR_SIZE & LAWAR_SIZE_128M)) +#define LAWAR2	(LAWAR_EN | LAWAR_TRGT_IF_LBC | (LAWAR_SIZE & LAWAR_SIZE_256M))  #else  #define LAWBAR2 0  #define LAWAR2 ((LAWAR_TRGT_IF_LBC | (LAWAR_SIZE & LAWAR_SIZE_128M)) & ~LAWAR_EN)  #endif +#define LAWBAR3 ((CFG_PCI_IO_BASE>>12) & 0xfffff) +#define LAWAR3	(LAWAR_EN | LAWAR_TRGT_IF_PCIX | (LAWAR_SIZE & LAWAR_SIZE_16M)) + +/* + * Rapid IO at 0xc000_0000 for 512 M + */ +#define LAWBAR4 ((CFG_RAPID_IO_BASE>>12) & 0xfffff) +#define LAWAR4	(LAWAR_EN | LAWAR_TRGT_IF_PCIX | (LAWAR_SIZE & LAWAR_SIZE_512M)) + +  	.section .bootpg, "ax" -	.globl  law_entry +	.globl	law_entry  law_entry:  	entry_start -	.long 0x03 -	.long LAWBAR0,LAWAR0,LAWBAR1,LAWAR1,LAWBAR2,LAWAR2 +	.long 0x05 +	.long LAWBAR0,LAWAR0,LAWBAR1,LAWAR1,LAWBAR2,LAWAR2,LAWBAR3,LAWAR3 +	.long LAWBAR4,LAWAR4  	entry_end diff --git a/board/mpc8560ads/mpc8560ads.c b/board/mpc8560ads/mpc8560ads.c index 823ab0d2a..2fa96e085 100644 --- a/board/mpc8560ads/mpc8560ads.c +++ b/board/mpc8560ads/mpc8560ads.c @@ -1,4 +1,5 @@  /* + * Copyright 2004 Freescale Semiconductor.   * (C) Copyright 2003,Motorola Inc.   * Xianghua Xiao, (X.Xiao@motorola.com)   * @@ -236,26 +237,11 @@ void reset_phy (void)  #endif /* CONFIG_MII */  } +  int checkboard (void)  { -	sys_info_t sysinfo; - -	get_sys_info (&sysinfo); - -	printf ("Board: Motorola MPC8560ADS Board\n"); -	printf ("\tCPU: %lu MHz\n", sysinfo.freqProcessor / 1000000); -	printf ("\tCCB: %lu MHz\n", sysinfo.freqSystemBus / 1000000); -	printf ("\tDDR: %lu MHz\n", sysinfo.freqSystemBus / 2000000); -	if((CFG_LBC_LCRR & 0x0f) == 2 || (CFG_LBC_LCRR & 0x0f) == 4 \ -		|| (CFG_LBC_LCRR & 0x0f) == 8) { -		printf ("\tLBC: %lu MHz\n", sysinfo.freqSystemBus / 1000000 /(CFG_LBC_LCRR & 0x0f)); -	} else { -		printf("\tLBC: unknown\n"); -	} -	printf("\tCPM: %lu Mhz\n", sysinfo.freqSystemBus / 1000000); -	printf("L1 D-cache 32KB, L1 I-cache 32KB enabled.\n"); - -	return (0); +	puts("Board: ADS\n"); +	return 0;  } @@ -272,6 +258,7 @@ long int initdram (int board_type)  #if !defined(CONFIG_RAM_AS_FLASH) || defined(CONFIG_DDR_DLL)  	volatile ccsr_gur_t *gur= &immap->im_gur;  #endif +  #if defined(CONFIG_DDR_DLL)  	uint temp_ddrdll = 0; @@ -293,9 +280,16 @@ long int initdram (int board_type)  	if(sysinfo.freqSystemBus/(CFG_LBC_LCRR & 0x0f) < 66000000) {  		lbc->lcrr = (CFG_LBC_LCRR & 0x0fffffff)| 0x80000000;  	} else { -#if defined(CONFIG_MPC85xx_REV1) /* need change CLKDIV before enable DLL */ -		lbc->lcrr = 0x10000004; /* default CLKDIV is 8, change it to 4 temporarily */ -#endif +		uint pvr = get_pvr(); + +		if (pvr == PVR_85xx_REV1) { +			/* +			 * Need change CLKDIV before enable DLL. +			 * Default CLKDIV is 8, change it to 4 +			 * temporarily. +			 */ +		    lbc->lcrr = 0x10000004; +		}  		lbc->lcrr = CFG_LBC_LCRR & 0x7fffffff;  		udelay(200);  		temp_lbcdll = gur->lbcdllcr; diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index 28be4b65c..f67893992 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -55,11 +55,13 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  	print_num ("flashoffset",   bd->bi_flashoffset	);  	print_num ("sramstart",	    bd->bi_sramstart	);  	print_num ("sramsize",	    bd->bi_sramsize	); -#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) || defined(CONFIG_E500) +#if defined(CONFIG_5xx)  || defined(CONFIG_8xx) || \ +    defined(CONFIG_8260) || defined(CONFIG_E500)  	print_num ("immr_base",	    bd->bi_immr_base	);  #endif  	print_num ("bootflags",	    bd->bi_bootflags	); -#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405EP) || defined(CONFIG_XILINX_ML300) +#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || \ +    defined(CONFIG_405EP) || defined(CONFIG_XILINX_ML300)  	print_str ("procfreq",	    strmhz(buf, bd->bi_procfreq));  	print_str ("plb_busfreq",	    strmhz(buf, bd->bi_plb_busfreq));  #if defined(CONFIG_405GP) || defined(CONFIG_405EP) || defined(CONFIG_XILINX_ML300) @@ -81,14 +83,15 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])  	for (i=0; i<6; ++i) {  		printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);  	} -#if (defined CONFIG_PN62) || (defined CONFIG_PPCHAMELEONEVB) \ -    || (defined CONFIG_MPC8540ADS) || (defined CONFIG_MPC8560ADS) +#if (defined CONFIG_PN62) || (defined CONFIG_PPCHAMELEONEVB) || \ +    (defined CONFIG_MPC8540ADS) || (defined CONFIG_MPC8560ADS) || \ +    (defined CONFIG_MPC8555CDS)  	puts ("\neth1addr    =");  	for (i=0; i<6; ++i) {  		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet1addr[i]);  	}  #endif /* CONFIG_PN62 */ -#if defined(CONFIG_MPC8540ADS) || defined(CONFIG_MPC8560ADS) +#if defined(CONFIG_MPC8540ADS) || defined(CONFIG_MPC8560ADS) || defined(CONFIG_MPC8555CDS)         puts ("\neth2addr    =");         for (i=0; i<6; ++i) {  		printf ("%c%02X", i ? ':' : ' ', bd->bi_enet2addr[i]); diff --git a/cpu/mpc85xx/cpu.c b/cpu/mpc85xx/cpu.c index 64f27820a..55593d995 100644 --- a/cpu/mpc85xx/cpu.c +++ b/cpu/mpc85xx/cpu.c @@ -1,4 +1,5 @@  /* + * Copyright 2004 Freescale Semiconductor.   * (C) Copyright 2002, 2003 Motorola Inc.   * Xianghua Xiao (X.Xiao@motorola.com)   * @@ -33,17 +34,87 @@  int checkcpu (void)  { -	uint pir = get_pir(); -	uint pvr = get_pvr(); +	sys_info_t sysinfo; +	uint lcrr;		/* local bus clock ratio register */ +	uint clkdiv;		/* clock divider portion of lcrr */ +	uint pvr, svr; +	uint ver; +	uint major, minor; -	printf("Motorola PowerPC ProcessorID=%08x Rev. ",pir); -	switch(pvr) { +	puts("Freescale PowerPC\n"); + +	pvr = get_pvr(); +	ver = PVR_VER(pvr); +	major = PVR_MAJ(pvr); +	minor = PVR_MIN(pvr); + +	printf("    Core: "); +	switch (ver) { +	case PVR_VER(PVR_85xx): +	    puts("E500"); +	    break;  	default: -		printf("PVR=%08x", pvr); +	    puts("Unknown"); +	    break; +	} +	printf(", Version: %d.%d, (0x%08x)\n", major, minor, pvr); + +	svr = get_svr(); +	ver = SVR_VER(svr); +	major = SVR_MAJ(svr); +	minor = SVR_MIN(svr); + +	puts("    System: "); +	switch (ver) { +	case SVR_8540: +		puts("8540"); +		break; +	case SVR_8541: +		puts("8541");  		break; +	case SVR_8555: +		puts("8555"); +		break; +	case SVR_8560: +		puts("8560"); +		break; +	default: +		puts("Unknown"); +		break; +	} +	printf(", Version: %d.%d, (0x%08x)\n", major, minor, svr); + +	get_sys_info(&sysinfo); + +	puts("    Clocks: "); +	printf("CPU:%4lu MHz, ", sysinfo.freqProcessor / 1000000); +	printf("CCB:%4lu MHz, ", sysinfo.freqSystemBus / 1000000); +	printf("DDR:%4lu MHz, ", sysinfo.freqSystemBus / 2000000); + +#if defined(CFG_LBC_LCRR) +	lcrr = CFG_LBC_LCRR; +#else +	{ +	    volatile immap_t *immap = (immap_t *)CFG_IMMR; +	    volatile ccsr_lbc_t *lbc= &immap->im_lbc; + +	    lcrr = lbc->lcrr; +	} +#endif +	clkdiv = lcrr & 0x0f; +	if (clkdiv == 2 || clkdiv == 4 || clkdiv == 8) { +		printf("LBC:%4lu MHz\n", +		       sysinfo.freqSystemBus / 1000000 / clkdiv); +	} else { +		printf("    LBC: unknown (lcrr: 0x%08x)\n", lcrr);  	} -	printf("\n"); +	if (ver == SVR_8560) { +		printf("    CPM: %lu Mhz\n", +		       sysinfo.freqSystemBus / 1000000); +	} + +	puts("    L1 D-cache 32KB, L1 I-cache 32KB enabled.\n");  	return 0;  } @@ -57,8 +128,12 @@ int do_reset (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])  	 * Initiate hard reset in debug control register DBCR0  	 * Make sure MSR[DE] = 1  	 */ -	__asm__ __volatile__("lis   3, 0x7000" ::: "r3"); -	mtspr(DBCR0,3); +	unsigned long val; + +	val = mfspr(DBCR0); +	val |= 0x70000000; +	mtspr(DBCR0,val); +  	return 1;  } diff --git a/cpu/mpc85xx/spd_sdram.c b/cpu/mpc85xx/spd_sdram.c index ccd06e96a..02b29ad62 100644 --- a/cpu/mpc85xx/spd_sdram.c +++ b/cpu/mpc85xx/spd_sdram.c @@ -1,4 +1,5 @@  /* + * Copyright 2004 Freescale Semiconductor.   * (C) Copyright 2003 Motorola Inc.   * Xianghua Xiao (X.Xiao@motorola.com)   * @@ -29,15 +30,7 @@  #ifdef CONFIG_SPD_EEPROM -#undef DEBUG - -#if defined(DEBUG) -#define DEB(x)      x -#else -#define DEB(x) -#endif - -#define ns2clk(ns) ((ns) / (2000000000 /get_bus_freq(0) + 1)) +#define ns2clk(ns) ((ns) / (2000000000 /get_bus_freq(0) + 1) + 1)  long int spd_sdram(void) {      	volatile immap_t *immap = (immap_t *)CFG_IMMR; @@ -61,64 +54,62 @@ long int spd_sdram(void) {  	ddr->cs0_bnds = ((spd.row_dens>>2) - 1);  	ddr->cs0_config = ( 1<<31 | (spd.nrow_addr-12)<<8 | (spd.ncol_addr-8) ); -	DEB(printf("\n")); -	DEB(printf("cs0_bnds = 0x%08x\n",ddr->cs0_bnds)); -	DEB(printf("cs0_config = 0x%08x\n",ddr->cs0_config)); +	debug ("\n"); +	debug ("cs0_bnds = 0x%08x\n",ddr->cs0_bnds); +	debug ("cs0_config = 0x%08x\n",ddr->cs0_config);  	if ( spd.nrows == 2 ) {  		ddr->cs1_bnds = ((spd.row_dens<<14) | ((spd.row_dens>>1) - 1));  		ddr->cs1_config = ( 1<<31 | (spd.nrow_addr-12)<<8 | (spd.ncol_addr-8) ); -		DEB(printf("cs1_bnds = 0x%08x\n",ddr->cs1_bnds)); -		DEB(printf("cs1_config = 0x%08x\n",ddr->cs1_config)); +		debug ("cs1_bnds = 0x%08x\n",ddr->cs1_bnds); +		debug ("cs1_config = 0x%08x\n",ddr->cs1_config);  	}  	memsize = spd.nrows * (4 * spd.row_dens); -	if( spd.mem_type == 0x07 ) { -		printf("DDR module detected, total size:%dMB.\n",memsize); -	} else { +	if( spd.mem_type != 0x07 ) {  		printf("No DDR module found!\n");  		return 0;  	} -	switch(memsize) { -		case 16: -			tmp = 7;     /* TLB size */ -			tmp1 = 1;    /* TLB entry number */ -			tmp2 = 23;   /* Local Access Window size */ -			break; -		case 32: -			tmp = 7; -			tmp1 = 2; -			tmp2 = 24; -			break; -		case 64: -			tmp = 8; -			tmp1 = 1; -			tmp2 = 25; -			break; -		case 128: -			tmp = 8; -			tmp1 = 2; -			tmp2 = 26; -			break; -		case 256: -			tmp = 9; -			tmp1 = 1; -			tmp2 = 27; -			break; -		case 512: -			tmp = 9; -			tmp1 = 2; -			tmp2 = 28; -			break; -		case 1024: -			tmp = 10; -			tmp1 = 1; -			tmp2 = 29; -			break; -		default: -			printf("DDR:we only added support 16M,32M,64M,128M,256M,512M and 1G DDR I.\n"); -			return 0; -			break; +	switch (memsize) { +	case 16: +		tmp = 7;		/* TLB size */ +		tmp1 = 1;		/* TLB entry number */ +		tmp2 = 23;		/* Local Access Window size */ +		break; +	case 32: +		tmp = 7; +		tmp1 = 2; +		tmp2 = 24; +		break; +	case 64: +		tmp = 8; +		tmp1 = 1; +		tmp2 = 25; +		break; +	case 128: +		tmp = 8; +		tmp1 = 2; +		tmp2 = 26; +		break; +	case 256: +		tmp = 9; +		tmp1 = 1; +		tmp2 = 27; +		break; +	case 512: +		tmp = 9; +		tmp1 = 2; +		tmp2 = 28; +		break; +	case 1024: +		tmp = 10; +		tmp1 = 1; +		tmp2 = 29; +		break; +	default: +		printf ("DDR:we only added support 16M,32M,64M,128M,256M,512M and 1G DDR I.\n"); +		return 0; +		break;  	}  	/* configure DDR TLB to TLB1 Entry 4,5 */ @@ -127,12 +118,12 @@ long int spd_sdram(void) {  	mtspr(MAS2, TLB1_MAS2(((CFG_DDR_SDRAM_BASE>>12) & 0xfffff),0,0,0,0,0,0,0,0));  	mtspr(MAS3, TLB1_MAS3(((CFG_DDR_SDRAM_BASE>>12) & 0xfffff),0,0,0,0,0,1,0,1,0,1));  	asm volatile("isync;msync;tlbwe;isync"); -	DEB(printf("DDR:MAS0=0x%08x\n",TLB1_MAS0(1,4,0))); -	DEB(printf("DDR:MAS1=0x%08x\n",TLB1_MAS1(1,1,0,0,tmp))); -	DEB(printf("DDR:MAS2=0x%08x\n",TLB1_MAS2(((CFG_DDR_SDRAM_BASE>>12) \ -		& 0xfffff),0,0,0,0,0,0,0,0))); -	DEB(printf("DDR:MAS3=0x%08x\n",TLB1_MAS3(((CFG_DDR_SDRAM_BASE>>12) \ -		& 0xfffff),0,0,0,0,0,1,0,1,0,1))); +	debug ("DDR:MAS0=0x%08x\n",TLB1_MAS0(1,4,0)); +	debug ("DDR:MAS1=0x%08x\n",TLB1_MAS1(1,1,0,0,tmp)); +	debug ("DDR:MAS2=0x%08x\n",TLB1_MAS2(((CFG_DDR_SDRAM_BASE>>12) \ +		& 0xfffff),0,0,0,0,0,0,0,0)); +	debug ("DDR:MAS3=0x%08x\n",TLB1_MAS3(((CFG_DDR_SDRAM_BASE>>12) \ +		& 0xfffff),0,0,0,0,0,1,0,1,0,1));  	if(tmp1 == 2) {  		mtspr(MAS0, TLB1_MAS0(1,5,0)); @@ -142,28 +133,28 @@ long int spd_sdram(void) {  		mtspr(MAS3, TLB1_MAS3((((CFG_DDR_SDRAM_BASE+(memsize*1024*1024)/2)>>12) \  			& 0xfffff),0,0,0,0,0,1,0,1,0,1));  		asm volatile("isync;msync;tlbwe;isync"); -		DEB(printf("DDR:MAS0=0x%08x\n",TLB1_MAS0(1,5,0))); -		DEB(printf("DDR:MAS1=0x%08x\n",TLB1_MAS1(1,1,0,0,tmp))); -		DEB(printf("DDR:MAS2=0x%08x\n",TLB1_MAS2((((CFG_DDR_SDRAM_BASE \ -			+(memsize*1024*1024)/2)>>12) & 0xfffff),0,0,0,0,0,0,0,0))); -		DEB(printf("DDR:MAS3=0x%08x\n",TLB1_MAS3((((CFG_DDR_SDRAM_BASE \ -			+(memsize*1024*1024)/2)>>12) & 0xfffff),0,0,0,0,0,1,0,1,0,1))); +		debug ("DDR:MAS0=0x%08x\n",TLB1_MAS0(1,5,0)); +		debug ("DDR:MAS1=0x%08x\n",TLB1_MAS1(1,1,0,0,tmp)); +		debug ("DDR:MAS2=0x%08x\n",TLB1_MAS2((((CFG_DDR_SDRAM_BASE \ +			+(memsize*1024*1024)/2)>>12) & 0xfffff),0,0,0,0,0,0,0,0)); +		debug ("DDR:MAS3=0x%08x\n",TLB1_MAS3((((CFG_DDR_SDRAM_BASE \ +			+(memsize*1024*1024)/2)>>12) & 0xfffff),0,0,0,0,0,1,0,1,0,1));  	}  #if defined(CONFIG_RAM_AS_FLASH)  	ecm->lawbar2 = ((CFG_DDR_SDRAM_BASE>>12) & 0xfffff);  	ecm->lawar2 = (LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & tmp2)); -	DEB(printf("DDR:LAWBAR2=0x%08x\n",ecm->lawbar2)); -	DEB(printf("DDR:LARAR2=0x%08x\n",ecm->lawar2)); +	debug ("DDR:LAWBAR2=0x%08x\n",ecm->lawbar2); +	debug ("DDR:LARAR2=0x%08x\n",ecm->lawar2);  #else  	ecm->lawbar1 = ((CFG_DDR_SDRAM_BASE>>12) & 0xfffff);  	ecm->lawar1 = (LAWAR_EN | LAWAR_TRGT_IF_DDR | (LAWAR_SIZE & tmp2)); -	DEB(printf("DDR:LAWBAR1=0x%08x\n",ecm->lawbar1)); -	DEB(printf("DDR:LARAR1=0x%08x\n",ecm->lawar1)); +	debug ("DDR:LAWBAR1=0x%08x\n",ecm->lawbar1); +	debug ("DDR:LARAR1=0x%08x\n",ecm->lawar1);  #endif  	tmp = 20000/(((spd.clk_cycle & 0xF0) >> 4) * 10 + (spd.clk_cycle & 0x0f)); -	DEB(printf("DDR:Module maximum data rate is: %dMhz\n",tmp)); +	debug ("DDR:Module maximum data rate is: %dMhz\n",tmp);  	/* find the largest CAS */  	if(spd.cas_lat & 0x40) { @@ -186,13 +177,16 @@ long int spd_sdram(void) {  	}  	tmp1 = get_bus_freq(0)/1000000; -	if(tmp1<230 && tmp1>=90 && tmp>=230) {         /* 90~230 range, treated as DDR 200 */ +	if(tmp1<230 && tmp1>=90 && tmp>=230) { +		/* 90~230 range, treated as DDR 200 */  		if(spd.clk_cycle3 == 0xa0) caslat -= 2;  		else if(spd.clk_cycle2 == 0xa0) caslat--; -	} else if(tmp1<280 && tmp1>=230 && tmp>=280) { /* 230-280 range, treated as DDR 266 */ +	} else if(tmp1<280 && tmp1>=230 && tmp>=280) { +		/* 230-280 range, treated as DDR 266 */  		if(spd.clk_cycle3 == 0x75) caslat -= 2;  		else if(spd.clk_cycle2 == 0x75) caslat--; -	} else if(tmp1<350 && tmp1>=280 && tmp>=350) { /* 280~350 range, treated as DDR 333 */ +	} else if(tmp1<350 && tmp1>=280 && tmp>=350) { +		/* 280~350 range, treated as DDR 333 */  		if(spd.clk_cycle3 == 0x60) caslat -= 2;  		else if(spd.clk_cycle2 == 0x60) caslat--;  	} else if(tmp1<90 || tmp1 >=350) { /* DDR rate out-of-range */ @@ -200,9 +194,10 @@ long int spd_sdram(void) {  		return 0;  	} -	/* note: caslat must also be programmed into ddr->sdram_mode register */ -	/* note: WRREC(Twr) and WRTORD(Twtr) are not in SPD,use conservative value here */ -#if 1 +	/* note: caslat must also be programmed into ddr->sdram_mode +	   register */ +	/* note: WRREC(Twr) and WRTORD(Twtr) are not in SPD,use +	   conservative value here */  	ddr->timing_cfg_1 = 	(((ns2clk(spd.trp/4) & 0x07) << 28 ) | \  				((ns2clk(spd.tras) & 0x0f ) << 24 ) | \  				((ns2clk(spd.trcd/4) & 0x07) << 20 ) | \ @@ -210,72 +205,66 @@ long int spd_sdram(void) {  				(((ns2clk(spd.sset[6]) - 8) & 0x0f) << 12 ) | \  				( 0x300 ) | \  				((ns2clk(spd.trrd/4) & 0x07) << 4) | 1); -#else -	ddr->timing_cfg_1 = 0x37344321; -	caslat = 4; -#endif -	DEB(printf("DDR:timing_cfg_1=0x%08x\n",ddr->timing_cfg_1)); -	/* note: hand-coded value for timing_cfg_2, see Errata DDR1*/ -#if defined(CONFIG_MPC85xx_REV1) +	debug ("DDR:timing_cfg_1=0x%08x\n",ddr->timing_cfg_1); +  	ddr->timing_cfg_2 = 0x00000800; -#endif -	DEB(printf("DDR:timing_cfg_2=0x%08x\n",ddr->timing_cfg_2)); +	debug ("DDR:timing_cfg_2=0x%08x\n",ddr->timing_cfg_2);  	/* only DDR I is supported, DDR I and II have different mode-register-set definition */  	/* burst length is always 4 */  	switch(caslat) { -		case 2: -			ddr->sdram_mode = 0x52; /* 1.5 */ -			break; -		case 3: -			ddr->sdram_mode = 0x22; /* 2.0 */ -			break; -		case 4: -			ddr->sdram_mode = 0x62; /* 2.5 */ -			break; -		case 5: -			ddr->sdram_mode = 0x32; /* 3.0 */ -			break; -		default: -			printf("DDR:only CAS Latency 1.5,2.0,2.5,3.0 is supported.\n"); -			return 0; +	case 2: +		ddr->sdram_mode = 0x52; /* 1.5 */ +		break; +	case 3: +		ddr->sdram_mode = 0x22; /* 2.0 */ +		break; +	case 4: +		ddr->sdram_mode = 0x62; /* 2.5 */ +		break; +	case 5: +		ddr->sdram_mode = 0x32; /* 3.0 */ +		break; +	default: +		printf("DDR:only CAS Latency 1.5,2.0,2.5,3.0 is supported.\n"); +		return 0;  	} -	DEB(printf("DDR:sdram_mode=0x%08x\n",ddr->sdram_mode)); +	debug ("DDR:sdram_mode=0x%08x\n",ddr->sdram_mode);  	switch(spd.refresh) { -		case 0x00: -		case 0x80: -			tmp = ns2clk(15625); -			break; -		case 0x01: -		case 0x81: -			tmp = ns2clk(3900); -			break; -		case 0x02: -		case 0x82: -			tmp = ns2clk(7800); -			break; -		case 0x03: -		case 0x83: -			tmp = ns2clk(31300); -			break; -		case 0x04: -		case 0x84: -			tmp = ns2clk(62500); -			break; -		case 0x05: -		case 0x85: -			tmp = ns2clk(125000); -			break; -		default: -			tmp = 0x512; -			break; +	case 0x00: +	case 0x80: +		tmp = ns2clk(15625); +		break; +	case 0x01: +	case 0x81: +		tmp = ns2clk(3900); +		break; +	case 0x02: +	case 0x82: +		tmp = ns2clk(7800); +		break; +	case 0x03: +	case 0x83: +		tmp = ns2clk(31300); +		break; +	case 0x04: +	case 0x84: +		tmp = ns2clk(62500); +		break; +	case 0x05: +	case 0x85: +		tmp = ns2clk(125000); +		break; +	default: +		tmp = 0x512; +		break;  	}  	/* set BSTOPRE to 0x100 for page mode, if auto-charge is used, set BSTOPRE = 0 */  	ddr->sdram_interval = ((tmp & 0x3fff) << 16) | 0x100; -	DEB(printf("DDR:sdram_interval=0x%08x\n",ddr->sdram_interval)); +	debug ("DDR:sdram_interval=0x%08x\n",ddr->sdram_interval);  	/* is this an ECC DDR chip? */  #if defined(CONFIG_DDR_ECC) @@ -283,24 +272,71 @@ long int spd_sdram(void) {  		ddr->err_disable = 0x0000000d;  		ddr->err_sbe = 0x00ff0000;  	} -	DEB(printf("DDR:err_disable=0x%08x\n",ddr->err_disable)); -	DEB(printf("DDR:err_sbe=0x%08x\n",ddr->err_sbe)); +	debug ("DDR:err_disable=0x%08x\n",ddr->err_disable); +	debug ("DDR:err_sbe=0x%08x\n",ddr->err_sbe);  #endif  	asm("sync;isync;msync");  	udelay(500); -	/* registered or unbuffered? */ +#ifdef MPC85xx_DDR_SDRAM_CLK_CNTL +	/* Setup the clock control (8555 and later) +	 * SDRAM_CLK_CNTL[0] = Source synchronous enable == 1 +	 * SDRAM_CLK_CNTL[5-7] = Clock Adjust == 3 (3/4 cycle late) +	 */ +	ddr->sdram_clk_cntl = 0x83000000; +#endif + +	/* Figure out the settings for the sdram_cfg register.  Build up +	 * the entire register in 'tmp' before writing since the write into +	 * the register will actually enable the memory controller, and all +	 * settings must be done before enabling. +	 * +	 * sdram_cfg[0]   = 1 (ddr sdram logic enable) +	 * sdram_cfg[1]   = 1 (self-refresh-enable) +	 * sdram_cfg[6:7] = 2 (SDRAM type = DDR SDRAM) +	 */ +	tmp = 0xc2000000; + +	/* sdram_cfg[3] = RD_EN - registered DIMM enable +	 *   A value of 0x26 indicates micron registered DIMMS (micron.com) +	 */ +	if (spd.mod_attr == 0x26) { +		tmp |= 0x10000000; +	} +  #if defined(CONFIG_DDR_ECC) -	ddr->sdram_cfg = (spd.config == 0x02)?0x20000000:0x0; +	/* If the user wanted ECC (enabled via sdram_cfg[2]) */ +	if (spd.config == 0x02) { +		tmp |= 0x20000000; +	} +#endif + + +	/* +	 * REV1 uses 1T timing. +	 * REV2 may use 1T or 2T as configured by the user. +	 */ +	{ +		uint pvr = get_pvr(); + +		if (pvr != PVR_85xx_REV1) { +#if defined(CONFIG_DDR_2T_TIMING) +			/* +			 * Enable 2T timing by setting sdram_cfg[16]. +			 */ +			tmp |= 0x8000;  #endif -	ddr->sdram_cfg = 0xc2000000|((spd.mod_attr == 0x20) ? 0x0 : \ -		((spd.mod_attr == 0x26) ? 0x10000000:0x0)); +		} +	} + +	ddr->sdram_cfg = tmp; +  	asm("sync;isync;msync");  	udelay(500); -	DEB(printf("DDR:sdram_cfg=0x%08x\n",ddr->sdram_cfg)); +	debug ("DDR:sdram_cfg=0x%08x\n",ddr->sdram_cfg);      	return (memsize*1024*1024);  } diff --git a/cpu/mpc85xx/speed.c b/cpu/mpc85xx/speed.c index a720cff3b..d40cd8c48 100644 --- a/cpu/mpc85xx/speed.c +++ b/cpu/mpc85xx/speed.c @@ -1,4 +1,5 @@  /* + * Copyright 2004 Freescale Semiconductor.   * (C) Copyright 2003 Motorola Inc.   * Xianghua Xiao, (X.Xiao@motorola.com)   * @@ -30,10 +31,9 @@  /* --------------------------------------------------------------- */ -#define ONE_BILLION        1000000000 -  void get_sys_info (sys_info_t * sysInfo)  { +	DECLARE_GLOBAL_DATA_PTR;  	volatile immap_t    *immap = (immap_t *)CFG_IMMR;  	volatile ccsr_gur_t *gur = &immap->im_gur;  	uint plat_ratio,e500_ratio; diff --git a/cpu/mpc85xx/start.S b/cpu/mpc85xx/start.S index b2baf02eb..040b88dee 100644 --- a/cpu/mpc85xx/start.S +++ b/cpu/mpc85xx/start.S @@ -1,4 +1,5 @@  /* + * Copyright 2004 Freescale Semiconductor.   * Copyright (C) 2003  Motorola,Inc.   * Xianghua Xiao<X.Xiao@motorola.com>   * @@ -83,18 +84,39 @@      .globl _start_e500  _start_e500: -#if defined(CONFIG_MPC85xx_REV1) +	mfspr	r0, PVR +	lis	r1, PVR_85xx_REV1@h +	ori	r1, r1, PVR_85xx_REV1@l +	cmpw	r0, r1 +	bne	1f + +	/* Semi-bogus errata fixup for Rev 1 */  	li	r0,0x2000  	mtspr	977,r0 -#endif -	/* Clear and set up some registers. Note: Some registers need strict -	 * synchronization by sync/mbar/msync/isync when being "mtspr". +	/* +	 * Before invalidating MMU L1/L2, read TLB1 Entry 0 and then +	 * write it back immediately to fixup a Rev 1 bug (Errata CPU4) +	 * for this initial TLB1 entry 0, otherwise the TLB1 entry 0 +	 * will be invalidated (incorrectly). +	 */ +	lis	r2,0x1000 +	mtspr	MAS0,r2 +	tlbre +	tlbwe +	isync + +1: +	/* +	 * Clear and set up some registers. +	 * Note: Some registers need strict synchronization by +	 * sync/mbar/msync/isync when being "mtspr".  	 * BookE: isync before PID,tlbivax,tlbwe  	 * BookE: isync after MSR,PID; msync_isync after tlbivax & tlbwe  	 * E500:  msync,isync before L1CSR0 -	 * E500:  isync after BBEAR,BBTAR,BUCSR,DBCR0,DBCR1,HID0,HID1,L1CSR0 -	 *        L1CSR1, MAS[0,1,2,3,4,6],MMUCSR0, PID[0,1,2],SPEFCSR +	 * E500:  isync after BBEAR,BBTAR,BUCSR,DBCR0,DBCR1,HID0,HID1, +	 *        L1CSR0, L1CSR1, MAS[0,1,2,3,4,6],MMUCSR0, PID[0,1,2], +	 *        SPEFCSR  	 */  	/* invalidate d-cache */ @@ -173,7 +195,8 @@ _start_e500:  	isync  	/* Setup interrupt vectors */ -	mtspr IVPR, r0 +	lis     r1,0xfff8 +	mtspr IVPR, r1  	li      r1,0x0100  	mtspr	IVOR0,r1	/* 0: Critical input */ @@ -203,21 +226,15 @@ _start_e500:  	li	r1,0x2000  	mtspr	IVOR15,r1	/* 15: Debug */ -	/* invalidate MMU L1/L2 */ -	/* Note: before invalidate MMU L1/L2, we read TLB1 Entry 0 and then -	 * write it back immediately to fixup a bug(Errata CPU4)  for this initial -	 * TLB1 entry 0,otherwise the TLB1 entry 0 will be invalidated. +	/* +	 * Invalidate MMU L1/L2 +	 * +	 * Note: There is a fixup earlier for Errata CPU4 on +	 * Rev 1 parts that must precede this MMU invalidation.  	 */ -#if defined(CONFIG_MPC85xx_REV1) -	lis	r2,0x1000 -	mtspr	MAS0,r2 -	tlbre -	tlbwe -	isync  	li      r2, 0x001e  	mtspr   MMUCSR0, r2  	isync -#endif  	/* After reset, CCSRBAR is located at CFG_CCSRBAR_DEFAULT, i.e.  	 * 0xff700000-0xff800000. We need add a TLB1 entry for this 1MB @@ -278,9 +295,11 @@ _start_e500:  	li 	r3,4  	li	r4,0  	tlbivax	r4,r3 -#if defined(CONFIG_MPC85xx_REV1) /* Errata CPU6 */ -	nop -#endif +	/* +	 * To avoid REV1 Errata CPU6 issues, make sure +	 * the instruction following tlbivax is not a store. +	 */ +  	/* set up local access windows, defined at board/<boardname>/init.S */  	lis	r7,CFG_CCSRBAR@h @@ -781,6 +800,11 @@ get_pvr:  	mfspr	r3, PVR  	blr +	.globl get_svr +get_svr: +	mfspr	r3, SVR +	blr +  	.globl wr_tcr  wr_tcr:  	mtspr	TCR, r3 diff --git a/cpu/mpc85xx/tsec.c b/cpu/mpc85xx/tsec.c index 2d0517af2..0d858ed97 100644 --- a/cpu/mpc85xx/tsec.c +++ b/cpu/mpc85xx/tsec.c @@ -1,13 +1,14 @@  /*   * tsec.c - * Motorola Three Speed Ethernet Controller driver + * Freescale Three Speed Ethernet Controller driver   *   * This software may be used and distributed according to the   * terms of the GNU Public License, Version 2, incorporated   * herein by reference.   * + * Copyright 2004 Freescale Semiconductor.   * (C) Copyright 2003, Motorola, Inc. - * maintained by Xianghua Xiao (x.xiao@motorola.com) + * maintained by Jon Loeliger (loeliger@freescale.com)   * author Andy Fleming   *   */ @@ -26,9 +27,9 @@  #undef TSEC_DEBUG  #ifdef TSEC_DEBUG -#define DBGPRINT(x) printf(x) +#define DBGPRINT(x,y) printf(x,y)  #else -#define DBGPRINT(x) +#define DBGPRINT(x,y)  #endif  static uint rxIdx;	/* index of the current RX buffer */ @@ -39,6 +40,59 @@ typedef volatile struct rtxbd {  	rxbd8_t rxbd[PKTBUFSRX];  }  RTXBD; +struct tsec_info_struct { +	unsigned int phyaddr; +	unsigned int gigabit; +	unsigned int phyregidx; +}; + + +/* The tsec_info structure contains 3 values which the + * driver uses to determine how to operate a given ethernet + * device.  For now, the structure is initialized with the + * knowledge that all current implementations have 2 TSEC + * devices, and one FEC.  The information needed is: + *  phyaddr - The address of the PHY which is attached to + *      the given device. + * + *  gigabit - This variable indicates whether the device + *      supports gigabit speed ethernet + * + *  phyregidx - This variable specifies which ethernet device + *      controls the MII Management registers which are connected + *      to the PHY.  For 8540/8560, only TSEC1 (index 0) has + *      access to the PHYs, so all of the entries have "0". + * + * The values specified in the table are taken from the board's + * config file in include/configs/.  When implementing a new + * board with ethernet capability, it is necessary to define: + *   TSEC1_PHY_ADDR + *   TSEC1_PHYIDX + *   TSEC2_PHY_ADDR + *   TSEC2_PHYIDX + * + * and for 8560: + *   FEC_PHY_ADDR + *   FEC_PHYIDX + */ +static struct tsec_info_struct tsec_info[] = { +#ifdef CONFIG_MPC85XX_TSEC1 +	{TSEC1_PHY_ADDR, 1, TSEC1_PHYIDX}, +#endif +#ifdef CONFIG_MPC85XX_TSEC2 +	{TSEC2_PHY_ADDR, 1, TSEC2_PHYIDX}, +#endif +#ifdef CONFIG_MPC85XX_FEC +	{FEC_PHY_ADDR, 0, FEC_PHYIDX}, +#endif +}; + +#define MAXCONTROLLERS 3 + +static int relocated = 0; + +static struct tsec_private *privlist[MAXCONTROLLERS]; +  #ifdef __GNUC__  static RTXBD rtx __attribute__ ((aligned(8)));  #else @@ -49,31 +103,48 @@ static int tsec_send(struct eth_device* dev, volatile void *packet, int length);  static int tsec_recv(struct eth_device* dev);  static int tsec_init(struct eth_device* dev, bd_t * bd);  static void tsec_halt(struct eth_device* dev); -static void init_registers(tsec_t *regs); -static void startup_tsec(tsec_t *regs); -static void init_phy(tsec_t *regs); -uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset); +static void init_registers(volatile tsec_t *regs); +static void startup_tsec(struct eth_device *dev); +static int init_phy(struct eth_device *dev); +void write_phy_reg(struct tsec_private *priv, uint regnum, uint value); +uint read_phy_reg(struct tsec_private *priv, uint regnum); +struct phy_info * get_phy_info(struct eth_device *dev); +void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd); +static void adjust_link(struct eth_device *dev); +static void relocate_cmds(void); -static int	phy_id = -1; - -/* Initialize device structure.  returns 0 on failure, 1 on - * success */ -int tsec_initialize(bd_t *bis) +/* Initialize device structure. Returns success if PHY + * initialization succeeded (i.e. if it recognizes the PHY) + */ +int tsec_initialize(bd_t *bis, int index)  {  	struct eth_device* dev;  	int i; -	tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR); +	struct tsec_private *priv;  	dev = (struct eth_device*) malloc(sizeof *dev); -	if(dev == NULL) +	if(NULL == dev)  		return 0;  	memset(dev, 0, sizeof *dev); -	sprintf(dev->name, "MOTO ETHERNET"); +	priv = (struct tsec_private *) malloc(sizeof(*priv)); + +	if(NULL == priv) +		return 0; + +	privlist[index] = priv; +	priv->regs = (volatile tsec_t *)(TSEC_BASE_ADDR + index*TSEC_SIZE); +	priv->phyregs = (volatile tsec_t *)(TSEC_BASE_ADDR + +			tsec_info[index].phyregidx*TSEC_SIZE); + +	priv->phyaddr = tsec_info[index].phyaddr; +	priv->gigabit = tsec_info[index].gigabit; + +	sprintf(dev->name, "MOTO ENET%d", index);  	dev->iobase = 0; -	dev->priv   = 0; +	dev->priv   = priv;  	dev->init   = tsec_init;  	dev->halt   = tsec_halt;  	dev->send   = tsec_send; @@ -85,70 +156,32 @@ int tsec_initialize(bd_t *bis)  	eth_register(dev); -	/* Reconfigure the PHY to advertise everything here -	 * so that it works with both gigabit and 10/100 */ -#ifdef CONFIG_PHY_M88E1011 -	/* Assign a Physical address to the TBI */ -	regs->tbipa=TBIPA_VALUE; - -	/* reset the management interface */ -	regs->miimcfg=MIIMCFG_RESET; - -	regs->miimcfg=MIIMCFG_INIT_VALUE; - -	/* Wait until the bus is free */ -	while(regs->miimind & MIIMIND_BUSY); - -	/* Locate PHYs.  Skip TBIPA, which we know is 31. -	*/ -	for (i=0; i<31; i++) { -		if (read_phy_reg(regs, i, 2) == 0x141) { -			if (phy_id == -1) -				phy_id = i; -#ifdef TSEC_DEBUG -			printf("Found Marvell PHY at 0x%02x\n", i); -#endif -		} -	} -#ifdef TSEC_DEBUG -	printf("Using PHY ID 0x%02x\n", phy_id); -#endif -	write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_RESET); - -	RESET_ERRATA(regs, phy_id); -	/* Configure the PHY to advertise gbit and 10/100 */ -	write_phy_reg(regs, phy_id, MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT); -	write_phy_reg(regs, phy_id, MIIM_ANAR, MIIM_ANAR_INIT); +	/* Reset the MAC */ +	priv->regs->maccfg1 |= MACCFG1_SOFT_RESET; +	priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET); -	/* Reset the PHY so the new settings take effect */ -	write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_RESET); -#endif -	return 1; +	/* Try to initialize PHY here, and return */ +	return init_phy(dev);  }  /* Initializes data structures and registers for the controller, - * and brings the interface up */ + * and brings the interface up.  Returns the link status, meaning + * that it returns success if the link is up, failure otherwise. + * This allows u-boot to find the first active controller. */  int tsec_init(struct eth_device* dev, bd_t * bd)  { -	tsec_t *regs;  	uint tempval;  	char tmpbuf[MAC_ADDR_LEN];  	int i; - -	regs = (tsec_t *)(TSEC_BASE_ADDR); +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs;  	/* Make sure the controller is stopped */  	tsec_halt(dev); -	/* Reset the MAC */ -	regs->maccfg1 |= MACCFG1_SOFT_RESET; - -	/* Clear MACCFG1[Soft_Reset] */ -	regs->maccfg1 &= ~(MACCFG1_SOFT_RESET); - -	/* Init MACCFG2.  Defaults to GMII/MII */ +	/* Init MACCFG2.  Defaults to GMII */  	regs->maccfg2 = MACCFG2_INIT_SETTINGS;  	/* Init ECNTRL */ @@ -157,7 +190,7 @@ int tsec_init(struct eth_device* dev, bd_t * bd)  	/* Copy the station address into the address registers.  	 * Backwards, because little endian MACS are dumb */  	for(i=0;i<MAC_ADDR_LEN;i++) { -		tmpbuf[MAC_ADDR_LEN - 1 - i] = bd->bi_enetaddr[i]; +		tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i];  	}  	(uint)(regs->macstnaddr1) = *((uint *)(tmpbuf)); @@ -165,9 +198,6 @@ int tsec_init(struct eth_device* dev, bd_t * bd)  	(uint)(regs->macstnaddr2) = tempval; -	/* Initialize the PHY */ -	init_phy(regs); -  	/* reset the indices to zero */  	rxIdx = 0;  	txIdx = 0; @@ -176,27 +206,49 @@ int tsec_init(struct eth_device* dev, bd_t * bd)  	init_registers(regs);  	/* Ready the device for tx/rx */ -	startup_tsec(regs); +	startup_tsec(dev); -	return 1; +	/* If there's no link, fail */ +	return priv->link; + +} + +/* Write value to the device's PHY through the registers + * specified in priv, modifying the register specified in regnum. + * It will wait for the write to be done (or for a timeout to + * expire) before exiting + */ +void write_phy_reg(struct tsec_private *priv, uint regnum, uint value) +{ +	volatile tsec_t *regbase = priv->phyregs; +	uint phyid = priv->phyaddr; +	int timeout=1000000; + +	regbase->miimadd = (phyid << 8) | regnum; +	regbase->miimcon = value; +	asm("msync"); + +	timeout=1000000; +	while((regbase->miimind & MIIMIND_BUSY) && timeout--);  } -/* Reads from the register at offset in the PHY at phyid, */ -/* using the register set defined in regbase.  It waits until the */ -/* bits in the miimstat are valid (miimind notvalid bit cleared), */ -/* and then passes those bits on to the variable specified in */ -/* value */ -/* Before it does the read, it needs to clear the command field */ -uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset) +/* Reads register regnum on the device's PHY through the + * registers specified in priv.  It lowers and raises the read + * command, and waits for the data to become valid (miimind + * notvalid bit cleared), and the bus to cease activity (miimind + * busy bit cleared), and then returns the value + */ +uint read_phy_reg(struct tsec_private *priv, uint regnum)  {  	uint value; +	volatile tsec_t *regbase = priv->phyregs; +	uint phyid = priv->phyaddr; -	/* Put the address of the phy, and the register number into -	 * MIIMADD -	 */ -	regbase->miimadd = (phyid << 8) | offset; +	/* Put the address of the phy, and the register +	 * number into MIIMADD */ +	regbase->miimadd = (phyid << 8) | regnum;  	/* Clear the command register, and wait */  	regbase->miimcom = 0; @@ -215,115 +267,169 @@ uint read_phy_reg(tsec_t *regbase, uint phyid, uint offset)  	return value;  } -/* Setup the PHY */ -static void init_phy(tsec_t *regs) + +/* Discover which PHY is attached to the device, and configure it + * properly.  If the PHY is not recognized, then return 0 + * (failure).  Otherwise, return 1 + */ +static int init_phy(struct eth_device *dev)  { -	uint testval; -	unsigned int timeout = TSEC_TIMEOUT; +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	struct phy_info *curphy;  	/* Assign a Physical address to the TBI */ -	regs->tbipa=TBIPA_VALUE; +	priv->regs->tbipa=TBIPA_VALUE; -	/* reset the management interface */ -	regs->miimcfg=MIIMCFG_RESET; +	if(0 == relocated) +		relocate_cmds(); -	regs->miimcfg=MIIMCFG_INIT_VALUE; +	/* Get the cmd structure corresponding to the attached +	 * PHY */ +	curphy = get_phy_info(dev); -	/* Wait until the bus is free */ -	while(regs->miimind & MIIMIND_BUSY); +	if(NULL == curphy) { +		printf("%s: No PHY found\n", dev->name); -#ifdef CONFIG_PHY_CIS8201 -	/* override PHY config settings */ -	write_phy_reg(regs, 0, MIIM_AUX_CONSTAT, MIIM_AUXCONSTAT_INIT); +		return 0; +	} -	/* Set up interface mode */ -	write_phy_reg(regs, 0, MIIM_EXT_CON1, MIIM_EXTCON1_INIT); -#endif +	priv->phyinfo = curphy; -	/* Set the PHY to gigabit, full duplex, Auto-negotiate */ -	write_phy_reg(regs, phy_id, MIIM_CONTROL, MIIM_CONTROL_INIT); +	phy_run_commands(priv, priv->phyinfo->config); -	/* Wait until STATUS indicates Auto-Negotiation is done */ -	DBGPRINT("Waiting for Auto-negotiation to complete\n"); -	testval=read_phy_reg(regs, phy_id, MIIM_STATUS); +	return 1; +} -	while((!(testval & MIIM_STATUS_AN_DONE))&& timeout--) { -		testval=read_phy_reg(regs, phy_id, MIIM_STATUS); -	} -	if(testval & MIIM_STATUS_AN_DONE) -		DBGPRINT("Auto-negotiation done\n"); +/* Returns which value to write to the control register. */ +/* For 10/100, the value is slightly different */ +uint mii_cr_init(uint mii_reg, struct tsec_private *priv) +{ +	if(priv->gigabit) +		return MIIM_CONTROL_INIT;  	else -		DBGPRINT("Auto-negotiation timed-out.\n"); +		return MIIM_CR_INIT; +} -#ifdef CONFIG_PHY_CIS8201 -	/* Find out what duplexity (duplicity?) we have */ -	/* Read it twice to make sure */ -	testval=read_phy_reg(regs, phy_id, MIIM_AUX_CONSTAT); -	if(testval & MIIM_AUXCONSTAT_DUPLEX) { -		DBGPRINT("Enet starting in full duplex\n"); -		regs->maccfg2 |= MACCFG2_FULL_DUPLEX; -	} else { -		DBGPRINT("Enet starting in half duplex\n"); -		regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX; -	} +/* Parse the status register for link, and then do + * auto-negotiation */ +uint mii_parse_sr(uint mii_reg, struct tsec_private *priv) +{ +	uint timeout = TSEC_TIMEOUT; -	/* Also, we look to see what speed we are at -	 * if Gigabit, MACCFG2 goes in GMII, otherwise, -	 * MII mode. -	 */ -	if((testval & MIIM_AUXCONSTAT_SPEED) != MIIM_AUXCONSTAT_GBIT) { -		if((testval & MIIM_AUXCONSTAT_SPEED) == MIIM_AUXCONSTAT_100) -			DBGPRINT("Enet starting in 100BT\n"); -		else -			DBGPRINT("Enet starting in 10BT\n"); +	if(mii_reg & MIIM_STATUS_LINK) +		priv->link = 1; +	else +		priv->link = 0; -		/* mark the mode in MACCFG2 */ -		regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII); -	} else { -		DBGPRINT("Enet starting in 1000BT\n"); +	if(priv->link) { +		while((!(mii_reg & MIIM_STATUS_AN_DONE)) && timeout--) +			mii_reg = read_phy_reg(priv, MIIM_STATUS);  	} -#endif +	return 0; +} + -#ifdef CONFIG_PHY_M88E1011 -	/* Read the PHY to see what speed and duplex we are */ -	testval=read_phy_reg(regs, phy_id, MIIM_PHY_STATUS); +/* Parse the 88E1011's status register for speed and duplex + * information */ +uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private *priv) +{ +	uint speed; -	timeout = TSEC_TIMEOUT; -	while((!(testval & MIIM_PHYSTAT_SPDDONE)) && timeout--) { -		testval = read_phy_reg(regs,phy_id,MIIM_PHY_STATUS); +	if(mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) +		priv->duplexity = 1; +	else +		priv->duplexity = 0; + +	speed = (mii_reg &MIIM_88E1011_PHYSTAT_SPEED); + +	switch(speed) { +		case MIIM_88E1011_PHYSTAT_GBIT: +			priv->speed = 1000; +			break; +		case MIIM_88E1011_PHYSTAT_100: +			priv->speed = 100; +			break; +		default: +			priv->speed = 10;  	} -	if(!(testval & MIIM_PHYSTAT_SPDDONE)) -		DBGPRINT("Enet: Speed not resolved\n"); +	return 0; +} + -	testval=read_phy_reg(regs, phy_id, MIIM_PHY_STATUS); -	if(testval & MIIM_PHYSTAT_DUPLEX) { -		DBGPRINT("Enet starting in Full Duplex\n"); -		regs->maccfg2 |= MACCFG2_FULL_DUPLEX; -	} else { -		DBGPRINT("Enet starting in Half Duplex\n"); -		regs->maccfg2 &= ~MACCFG2_FULL_DUPLEX; +/* Parse the cis8201's status register for speed and duplex + * information */ +uint mii_parse_cis8201(uint mii_reg, struct tsec_private *priv) +{ +	uint speed; + +	if(mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX) +		priv->duplexity = 1; +	else +		priv->duplexity = 0; + +	speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED; +	switch(speed) { +		case MIIM_CIS8201_AUXCONSTAT_GBIT: +			priv->speed = 1000; +			break; +		case MIIM_CIS8201_AUXCONSTAT_100: +			priv->speed = 100; +			break; +		default: +			priv->speed = 10; +			break;  	} -	if(!((testval&MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_GBIT)) { -		if((testval & MIIM_PHYSTAT_SPEED) == MIIM_PHYSTAT_100) -			DBGPRINT("Enet starting in 100BT\n"); -		else -			DBGPRINT("Enet starting in 10BT\n"); +	return 0; +} -		regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) | MACCFG2_MII); -	} else { -		DBGPRINT("Enet starting in 1000BT\n"); + +/* Parse the DM9161's status register for speed and duplex + * information */ +uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private *priv) +{ +	if(mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H)) +		priv->speed = 100; +	else +		priv->speed = 10; + +	if(mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F)) +		priv->duplexity = 1; +	else +		priv->duplexity = 0; + +	return 0; +} + + +/* Hack to write all 4 PHYs with the LED values */ +uint mii_cis8204_fixled(uint mii_reg, struct tsec_private *priv) +{ +	uint phyid; +	volatile tsec_t *regbase = priv->phyregs; +	int timeout=1000000; + +	for(phyid=0;phyid<4;phyid++) { +		regbase->miimadd = (phyid << 8) | mii_reg; +		regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT; +		asm("msync"); + +		timeout=1000000; +		while((regbase->miimind & MIIMIND_BUSY) && timeout--);  	} -#endif +	return MIIM_CIS8204_SLEDCON_INIT;  } -static void init_registers(tsec_t *regs) +/* Initialized required registers to appropriate values, zeroing + * those we don't care about (unless zero is bad, in which case, + * choose a more appropriate value) */ +static void init_registers(volatile tsec_t *regs)  {  	/* Clear IEVENT */  	regs->ievent = IEVENT_INIT_CLEAR; @@ -365,9 +471,51 @@ static void init_registers(tsec_t *regs)  } -static void startup_tsec(tsec_t *regs) + +/* Configure maccfg2 based on negotiated speed and duplex + * reported by PHY handling code */ +static void adjust_link(struct eth_device *dev) +{ +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs; + +	if(priv->link) { +		if(priv->duplexity != 0) +			regs->maccfg2 |= MACCFG2_FULL_DUPLEX; +		else +			regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX); + +		switch(priv->speed) { +			case 1000: +				regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) +					| MACCFG2_GMII); +				break; +			case 100: +			case 10: +				regs->maccfg2 = ((regs->maccfg2&~(MACCFG2_IF)) +					| MACCFG2_MII); +				break; +			default: +				printf("%s: Speed was bad\n", dev->name); +				break; +		} + +		printf("Speed: %d, %s duplex\n", priv->speed, +				(priv->duplexity) ? "full" : "half"); + +	} else { +		printf("%s: No link.\n", dev->name); +	} +} + + +/* Set up the buffers and their descriptors, and bring up the + * interface */ +static void startup_tsec(struct eth_device *dev)  {  	int i; +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs;  	/* Point to the buffer descriptors */  	regs->tbase = (unsigned int)(&rtx.txbd[txIdx]); @@ -389,6 +537,10 @@ static void startup_tsec(tsec_t *regs)  	}  	rtx.txbd[TX_BUF_CNT -1].status |= TXBD_WRAP; +	/* Start up the PHY */ +	phy_run_commands(priv, priv->phyinfo->startup); +	adjust_link(dev); +  	/* Enable Transmit and Receive */  	regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN); @@ -406,12 +558,13 @@ static int tsec_send(struct eth_device* dev, volatile void *packet, int length)  {  	int i;  	int result = 0; -	tsec_t * regs = (tsec_t *)(TSEC_BASE_ADDR); +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs;  	/* Find an empty buffer descriptor */  	for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {  		if (i >= TOUT_LOOP) { -			DBGPRINT("tsec: tx buffers full\n"); +			DBGPRINT("%s: tsec: tx buffers full\n", dev->name);  			return result;  		}  	} @@ -426,7 +579,7 @@ static int tsec_send(struct eth_device* dev, volatile void *packet, int length)  	/* Wait for buffer to be transmitted */  	for(i=0; rtx.txbd[txIdx].status & TXBD_READY; i++) {  		if (i >= TOUT_LOOP) { -			DBGPRINT("tsec: tx error\n"); +			DBGPRINT("%s: tsec: tx error\n", dev->name);  			return result;  		}  	} @@ -440,7 +593,8 @@ static int tsec_send(struct eth_device* dev, volatile void *packet, int length)  static int tsec_recv(struct eth_device* dev)  {  	int length; -	tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR); +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs;  	while(!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { @@ -449,6 +603,9 @@ static int tsec_recv(struct eth_device* dev)  		/* Send the packet up if there were no errors */  		if (!(rtx.rxbd[rxIdx].status & RXBD_STATS)) {  			NetReceive(NetRxPackets[rxIdx], length - 4); +		} else { +			printf("Got error %x\n", +					(rtx.rxbd[rxIdx].status & RXBD_STATS));  		}  		rtx.rxbd[rxIdx].length = 0; @@ -469,9 +626,11 @@ static int tsec_recv(struct eth_device* dev)  } +/* Stop the interface */  static void tsec_halt(struct eth_device* dev)  { -	tsec_t *regs = (tsec_t *)(TSEC_BASE_ADDR); +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	volatile tsec_t *regs = priv->regs;  	regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS);  	regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS); @@ -480,25 +639,288 @@ static void tsec_halt(struct eth_device* dev)  	regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN); +	/* Shut down the PHY, as needed */ +	phy_run_commands(priv, priv->phyinfo->shutdown); +} + + +struct phy_info phy_info_M88E1011S = { +	0x01410c6, +	"Marvell 88E1011S", +	4, +	(struct phy_cmd[]) { /* config */ +		/* Reset and configure the PHY */ +		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, +		{0x1d, 0x1f, NULL}, +		{0x1e, 0x200c, NULL}, +		{0x1d, 0x5, NULL}, +		{0x1e, 0x0, NULL}, +		{0x1e, 0x100, NULL}, +		{MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, +		{MIIM_ANAR, MIIM_ANAR_INIT, NULL}, +		{MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, +		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		/* Status is read once to clear old link state */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; + +struct phy_info phy_info_cis8204 = { +	0x3f11, +	"Cicada Cis8204", +	6, +	(struct phy_cmd[]) { /* config */ +		/* Override PHY config settings */ +		{MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, +		/* Configure some basic stuff */ +		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, +		{MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT, &mii_cis8204_fixled}, +		{MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT, NULL}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		/* Read the Status (2x to make sure link is right) */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; + +/* Cicada 8201 */ +struct phy_info phy_info_cis8201 = { +	0xfc41, +	"CIS8201", +	4, +	(struct phy_cmd[]) { /* config */ +		/* Override PHY config settings */ +		{MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, +		/* Set up the interface mode */ +		{MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, +		/* Configure some basic stuff */ +		{MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		/* Read the Status (2x to make sure link is right) */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; + + +struct phy_info phy_info_dm9161 = { +	0x0181b88, +	"Davicom DM9161E", +	4, +	(struct phy_cmd[]) { /* config */ +		{MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL}, +		/* Do not bypass the scrambler/descrambler */ +		{MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL}, +		/* Clear 10BTCSR to default */ +		{MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL}, +		/* Configure some basic stuff */ +		{MIIM_CONTROL, MIIM_CR_INIT, NULL}, +		/* Restart Auto Negotiation */ +		{MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* startup */ +		/* Status is read once to clear old link state */ +		{MIIM_STATUS, miim_read, NULL}, +		/* Auto-negotiate */ +		{MIIM_STATUS, miim_read, &mii_parse_sr}, +		/* Read the status */ +		{MIIM_DM9161_SCSR, miim_read, &mii_parse_dm9161_scsr}, +		{miim_end,} +	}, +	(struct phy_cmd[]) { /* shutdown */ +		{miim_end,} +	}, +}; + +struct phy_info *phy_info[] = { +#if 0 +	&phy_info_cis8201, +#endif +	&phy_info_cis8204, +	&phy_info_M88E1011S, +	&phy_info_dm9161, +	NULL +}; + + +/* Grab the identifier of the device's PHY, and search through + * all of the known PHYs to see if one matches.  If so, return + * it, if not, return NULL */ +struct phy_info * get_phy_info(struct eth_device *dev) +{ +	struct tsec_private *priv = (struct tsec_private *)dev->priv; +	uint phy_reg, phy_ID; +	int i; +	struct phy_info *theInfo = NULL; + +	/* Grab the bits from PHYIR1, and put them in the upper half */ +	phy_reg = read_phy_reg(priv, MIIM_PHYIR1); +	phy_ID = (phy_reg & 0xffff) << 16; + +	/* Grab the bits from PHYIR2, and put them in the lower half */ +	phy_reg = read_phy_reg(priv, MIIM_PHYIR2); +	phy_ID |= (phy_reg & 0xffff); + +	/* loop through all the known PHY types, and find one that */ +	/* matches the ID we read from the PHY. */ +	for(i=0; phy_info[i]; i++) { +		if(phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) +			theInfo = phy_info[i]; +	} + +	if(theInfo == NULL) +	{ +		printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID); +		return NULL; +	} else { +		printf("%s: PHY is %s (%x)\n", dev->name, theInfo->name, +				phy_ID); +	} + +	return theInfo; +} + + +/* Execute the given series of commands on the given device's + * PHY, running functions as necessary*/ +void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd) +{ +	int i; +	uint result; +	volatile tsec_t *phyregs = priv->phyregs; + +	phyregs->miimcfg = MIIMCFG_RESET; + +	phyregs->miimcfg = MIIMCFG_INIT_VALUE; + +	while(phyregs->miimind & MIIMIND_BUSY); + +	for(i=0;cmd->mii_reg != miim_end;i++) { +		if(cmd->mii_data == miim_read) { +			result = read_phy_reg(priv, cmd->mii_reg); + +			if(cmd->funct != NULL) +				(*(cmd->funct))(result, priv); + +		} else { +			if(cmd->funct != NULL) +				result = (*(cmd->funct))(cmd->mii_reg, priv); +			else +				result = cmd->mii_data; + +			write_phy_reg(priv, cmd->mii_reg, result); + +		} +		cmd++; +	} +} + + +/* Relocate the function pointers in the phy cmd lists */ +static void relocate_cmds(void) +{ +	struct phy_cmd **cmdlistptr; +	struct phy_cmd *cmd; +	int i,j,k; +	DECLARE_GLOBAL_DATA_PTR; + +	for(i=0; phy_info[i]; i++) { +		/* First thing's first: relocate the pointers to the +		 * PHY command structures (the structs were done) */ +		phy_info[i] = (struct phy_info *) ((uint)phy_info[i] +				+ gd->reloc_off); +		phy_info[i]->name += gd->reloc_off; +		phy_info[i]->config = +			(struct phy_cmd *)((uint)phy_info[i]->config +					   + gd->reloc_off); +		phy_info[i]->startup = +			(struct phy_cmd *)((uint)phy_info[i]->startup +					   + gd->reloc_off); +		phy_info[i]->shutdown = +			(struct phy_cmd *)((uint)phy_info[i]->shutdown +					   + gd->reloc_off); + +		cmdlistptr = &phy_info[i]->config; +		j=0; +		for(;cmdlistptr <= &phy_info[i]->shutdown;cmdlistptr++) { +			k=0; +			for(cmd=*cmdlistptr;cmd->mii_reg != miim_end;cmd++) { +				/* Only relocate non-NULL pointers */ +				if(cmd->funct) +					cmd->funct += gd->reloc_off; + +				k++; +			} +			j++; +		} +	} + +	relocated = 1;  } +  #ifndef CONFIG_BITBANGMII + +struct tsec_private * get_priv_for_phy(unsigned char phyaddr) +{ +	int i; + +	for(i=0;i<MAXCONTROLLERS;i++) { +		if(privlist[i]->phyaddr == phyaddr) +			return privlist[i]; +	} + +	return NULL; +} +  /*   * Read a MII PHY register.   *   * Returns: - *   0 on success + *  0 on success   */ -int miiphy_read(unsigned char  addr, -		unsigned char  reg, -		unsigned short *value) +int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value)  { -	tsec_t *regs; -	unsigned short rv; +	unsigned short ret; +	struct tsec_private *priv = get_priv_for_phy(addr); -	regs = (tsec_t *)(TSEC_BASE_ADDR); -	rv = (unsigned short)read_phy_reg(regs, addr, reg); -	*value = rv; +	if(NULL == priv) { +		printf("Can't read PHY at address %d\n", addr); +		return -1; +	} + +	ret = (unsigned short)read_phy_reg(priv, reg); +	*value = ret;  	return 0;  } @@ -507,18 +929,22 @@ int miiphy_read(unsigned char  addr,   * Write a MII PHY register.   *   * Returns: - *   0 on success + *  0 on success   */ -int miiphy_write(unsigned char  addr, -		 unsigned char  reg, -		 unsigned short value) +int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value)  { -	tsec_t *regs; +	struct tsec_private *priv = get_priv_for_phy(addr); + +	if(NULL == priv) { +		printf("Can't write PHY at address %d\n", addr); +		return -1; +	} -	regs = (tsec_t *)(TSEC_BASE_ADDR); -	write_phy_reg(regs, addr, reg, value); +	write_phy_reg(priv, reg, value);  	return 0;  } +  #endif /* CONFIG_BITBANGMII */ +  #endif /* CONFIG_TSEC_ENET */ diff --git a/cpu/mpc85xx/tsec.h b/cpu/mpc85xx/tsec.h index db4169ca4..275bbd264 100644 --- a/cpu/mpc85xx/tsec.h +++ b/cpu/mpc85xx/tsec.h @@ -7,6 +7,7 @@   *  terms of the GNU Public License, Version 2, incorporated   *  herein by reference.   * + * Copyright 2004 Freescale Semiconductor.   * (C) Copyright 2003, Motorola, Inc.   * maintained by Xianghua Xiao (x.xiao@motorola.com)   * author Andy Fleming @@ -19,15 +20,13 @@  #include <net.h>  #include <mpc85xx.h> -/* TSEC1 is offset 0x24000, TSEC2 is offset 0x25000 -#define TSEC_BASE_ADDR	(CFG_IMMR + 0x25000) -*/  #define TSEC_BASE_ADDR	(CFG_IMMR + 0x24000) -#define TSEC_MEM_SIZE	0x01000 +#define TSEC_SIZE	0x01000  #define MAC_ADDR_LEN 6 -#define TSEC_TIMEOUT 	1000000 +/* #define TSEC_TIMEOUT 	1000000 */ +#define TSEC_TIMEOUT 1000  #define TOUT_LOOP 	1000000  /* MAC register bits */ @@ -47,11 +46,15 @@  #define MACCFG2_INIT_SETTINGS	0x00007205  #define MACCFG2_FULL_DUPLEX	0x00000001  #define MACCFG2_IF              0x00000300 +#define MACCFG2_GMII		0x00000200  #define MACCFG2_MII             0x00000100  #define ECNTRL_INIT_SETTINGS	0x00001000  #define ECNTRL_TBI_MODE         0x00000020 +#define miim_end -2 +#define miim_read -1 +  #define TBIPA_VALUE		0x1f  #define MIIMCFG_INIT_VALUE	0x00000003  #define MIIMCFG_RESET		0x80000000 @@ -60,52 +63,84 @@  #define MIIMIND_NOTVALID        0x00000004  #define MIIM_CONTROL            0x00 +#define MIIM_CONTROL_RESET	0x00009140  #define MIIM_CONTROL_INIT       0x00001140  #define MIIM_ANEN               0x00001000 -#define MIIM_CONTROL_RESET	0x00009140 + +#define MIIM_CR                 0x00 +#define MIIM_CR_RST		0x00008000 +#define MIIM_CR_INIT	        0x00001000  #define MIIM_STATUS		0x1  #define MIIM_STATUS_AN_DONE 	0x00000020 +#define MIIM_STATUS_LINK	0x0004 -#define MIIM_GBIT_CONTROL	0x9 -#define MIIM_GBIT_CONTROL_INIT	0xe00 +#define MIIM_PHYIR1		0x2 +#define MIIM_PHYIR2		0x3 -#define MIIM_TBI_ANEX		0x6 -#define MIIM_TBI_ANEX_NP	0x00000004 -#define MIIM_TBI_ANEX_PRX	0x00000002 +#define MIIM_ANAR		0x4 +#define MIIM_ANAR_INIT		0x1e1  #define MIIM_TBI_ANLPBPA	0x5  #define MIIM_TBI_ANLPBPA_HALF	0x00000040  #define MIIM_TBI_ANLPBPA_FULL	0x00000020 -#ifdef CONFIG_PHY_CIS8201 -#define MIIM_AUX_CONSTAT	0x1c -#define MIIM_AUXCONSTAT_INIT	0x0004 -#define MIIM_AUXCONSTAT_DUPLEX	0x0020 -#define MIIM_AUXCONSTAT_SPEED   0x0018 -#define MIIM_AUXCONSTAT_GBIT    0x0010 -#define MIIM_AUXCONSTAT_100     0x0008 +#define MIIM_TBI_ANEX		0x6 +#define MIIM_TBI_ANEX_NP	0x00000004 +#define MIIM_TBI_ANEX_PRX	0x00000002 + +#define MIIM_GBIT_CONTROL	0x9 +#define MIIM_GBIT_CONTROL_INIT	0xe00 -#define MIIM_EXT_CON1		0x17 -#define MIIM_EXTCON1_INIT	0x0000 +/* Cicada Auxiliary Control/Status Register */ +#define MIIM_CIS8201_AUX_CONSTAT        0x1c +#define MIIM_CIS8201_AUXCONSTAT_INIT    0x0004 +#define MIIM_CIS8201_AUXCONSTAT_DUPLEX  0x0020 +#define MIIM_CIS8201_AUXCONSTAT_SPEED   0x0018 +#define MIIM_CIS8201_AUXCONSTAT_GBIT    0x0010 +#define MIIM_CIS8201_AUXCONSTAT_100     0x0008 -#endif +/* Cicada Extended Control Register 1 */ +#define MIIM_CIS8201_EXT_CON1           0x17 +#define MIIM_CIS8201_EXTCON1_INIT       0x0000 -#ifdef CONFIG_PHY_M88E1011 -#define MIIM_ANAR		0x4 -#define MIIM_ANAR_INIT		0x1e1 +/* Cicada 8204 Extended PHY Control Register 1 */ +#define MIIM_CIS8204_EPHY_CON		0x17 +#define MIIM_CIS8204_EPHYCON_INIT	0x0006 + +/* Cicada 8204 Serial LED Control Register */ +#define MIIM_CIS8204_SLED_CON		0x1b +#define MIIM_CIS8204_SLEDCON_INIT	0x1115  #define MIIM_GBIT_CON		0x09  #define MIIM_GBIT_CON_ADVERT	0x0e00 -#define MIIM_PHY_STATUS         0x11 -#define MIIM_PHYSTAT_SPEED      0xc000 -#define MIIM_PHYSTAT_GBIT       0x8000 -#define MIIM_PHYSTAT_100        0x4000 -#define MIIM_PHYSTAT_DUPLEX     0x2000 -#define MIIM_PHYSTAT_SPDDONE	0x0800 -#define MIIM_PHYSTAT_LINK	0x0400 -#endif +/* 88E1011 PHY Status Register */ +#define MIIM_88E1011_PHY_STATUS         0x11 +#define MIIM_88E1011_PHYSTAT_SPEED      0xc000 +#define MIIM_88E1011_PHYSTAT_GBIT       0x8000 +#define MIIM_88E1011_PHYSTAT_100        0x4000 +#define MIIM_88E1011_PHYSTAT_DUPLEX     0x2000 +#define MIIM_88E1011_PHYSTAT_SPDDONE	0x0800 +#define MIIM_88E1011_PHYSTAT_LINK	0x0400 + +/* DM9161 Control register values */ +#define MIIM_DM9161_CR_STOP	0x0400 +#define MIIM_DM9161_CR_RSTAN	0x1200 + +#define MIIM_DM9161_SCR		0x10 +#define MIIM_DM9161_SCR_INIT	0x0610 + +/* DM9161 Specified Configuration and Status Register */ +#define MIIM_DM9161_SCSR	0x11 +#define MIIM_DM9161_SCSR_100F	0x8000 +#define MIIM_DM9161_SCSR_100H	0x4000 +#define MIIM_DM9161_SCSR_10F	0x2000 +#define MIIM_DM9161_SCSR_10H	0x1000 + +/* DM9161 10BT Configuration/Status */ +#define MIIM_DM9161_10BTCSR	0x12 +#define MIIM_DM9161_10BTCSR_INIT	0x7800  #define MIIM_READ_COMMAND       0x00000001 @@ -120,27 +155,6 @@  #define TSTAT_CLEAR_THALT       0x80000000  #define RSTAT_CLEAR_RHALT       0x00800000 -/* Write value to the PHY at phyid to the register at offset, */ -/* using the register space defined in regbase.  Note that */ -/* miimcfg needs to have the clock speed setup correctly.  This */ -/* macro will wait until the write is done before it finishes */ -#define write_phy_reg(regbase, phyid, offset, value) do { \ -	int timeout=1000000; \ -	regbase->miimadd = (phyid << 8) | offset; \ -	regbase->miimcon = value; \ -	asm("msync"); \ -	while((regbase->miimind & MIIMIND_BUSY) && timeout--); \ -} while(0) - - -/* This works around errata in reseting the PHY */ -#define RESET_ERRATA(regs, ID) do { \ -	write_phy_reg(regs, (ID), 0x1d, 0x1f); \ -	write_phy_reg(regs, (ID), 0x1e, 0x200c); \ -	write_phy_reg(regs, (ID), 0x1d, 0x5); \ -	write_phy_reg(regs, (ID), 0x1e, 0x0); \ -	write_phy_reg(regs, (ID), 0x1e, 0x100); \ -} while(0)  #define IEVENT_INIT_CLEAR	0xffffffff  #define IEVENT_BABR		0x80000000 @@ -402,4 +416,63 @@ typedef struct tsec  	uint	resc00[256];  } tsec_t; +struct tsec_private { +	volatile tsec_t *regs; +	volatile tsec_t *phyregs; +	struct phy_info *phyinfo; +	uint phyaddr; +	uint gigabit; +	uint link; +	uint duplexity; +	uint speed; +}; + + +/* + * struct phy_cmd:  A command for reading or writing a PHY register + * + * mii_reg:  The register to read or write + * + * mii_data:  For writes, the value to put in the register. + * 	A value of -1 indicates this is a read. + * + * funct: A function pointer which is invoked for each command. + * 	For reads, this function will be passed the value read + *	from the PHY, and process it. + *	For writes, the result of this function will be written + *	to the PHY register + */ +struct phy_cmd { +    uint mii_reg; +    uint mii_data; +    uint (*funct) (uint mii_reg, struct tsec_private* priv); +}; + +/* struct phy_info: a structure which defines attributes for a PHY + * + * id will contain a number which represents the PHY.  During + * startup, the driver will poll the PHY to find out what its + * UID--as defined by registers 2 and 3--is.  The 32-bit result + * gotten from the PHY will be shifted right by "shift" bits to + * discard any bits which may change based on revision numbers + * unimportant to functionality + * + * The struct phy_cmd entries represent pointers to an arrays of + * commands which tell the driver what to do to the PHY. + */ +struct phy_info { +    uint id; +    char *name; +    uint shift; +    /* Called to configure the PHY, and modify the controller +     * based on the results */ +    struct phy_cmd *config; + +    /* Called when starting up the controller */ +    struct phy_cmd *startup; + +    /* Called when bringing down the controller */ +    struct phy_cmd *shutdown; +}; +  #endif /* __TSEC_H */ |