X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=cpu%2Fppc4xx%2F44x_spd_ddr2.c;h=ec76b718bccb1f2b86215259bc16f20f80f9d8fc;hb=d9ee843d54c54776e1fdb86336ce554906a87331;hp=5fef27b984d57073b74b71e825b389cfbd69d46e;hpb=375c2c9e57ea5b8d678475379378f4774aa9cb88;p=u-boot diff --git a/cpu/ppc4xx/44x_spd_ddr2.c b/cpu/ppc4xx/44x_spd_ddr2.c index 5fef27b984..ec76b718bc 100644 --- a/cpu/ppc4xx/44x_spd_ddr2.c +++ b/cpu/ppc4xx/44x_spd_ddr2.c @@ -1,9 +1,12 @@ /* * cpu/ppc4xx/44x_spd_ddr2.c * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a - * DDR2 controller (non Denali Core). Those are 440SP/SPe. + * DDR2 controller (non Denali Core). Those currently are: * - * (C) Copyright 2007 + * 405: 405EX + * 440/460: 440SP/440SPe/460EX/460GT + * + * (C) Copyright 2007-2008 * Stefan Roese, DENX Software Engineering, sr@denx.de. * * COPYRIGHT AMCC CORPORATION 2004 @@ -40,9 +43,11 @@ #include #include #include +#include #if defined(CONFIG_SPD_EEPROM) && \ - (defined(CONFIG_440SP) || defined(CONFIG_440SPE)) + (defined(CONFIG_440SP) || defined(CONFIG_440SPE) || \ + defined(CONFIG_460EX) || defined(CONFIG_460GT)) /*-----------------------------------------------------------------------------+ * Defines @@ -109,9 +114,7 @@ /* Defines for the Read Cycle Delay test */ #define NUMMEMTESTS 8 #define NUMMEMWORDS 8 -#define NUMLOOPS 256 /* memory test loops */ - -#undef CONFIG_ECC_ERROR_RESET /* test-only: see description below, at check_ecc() */ +#define NUMLOOPS 64 /* memory test loops */ /* * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory @@ -120,10 +123,10 @@ * memory. * * If at some time this restriction doesn't apply anymore, just define - * CFG_ENABLE_SDRAM_CACHE in the board config file and this code should setup + * CONFIG_4xx_DCACHE in the board config file and this code should setup * everything correctly. */ -#ifdef CFG_ENABLE_SDRAM_CACHE +#ifdef CONFIG_4xx_DCACHE #define MY_TLB_WORD2_I_ENABLE 0 /* enable caching on SDRAM */ #else #define MY_TLB_WORD2_I_ENABLE TLB_WORD2_I_ENABLE /* disable caching on SDRAM */ @@ -138,6 +141,26 @@ void __spd_ddr_init_hang (void) } void spd_ddr_init_hang (void) __attribute__((weak, alias("__spd_ddr_init_hang"))); +/* + * To provide an interface for board specific config values in this common + * DDR setup code, we implement he "weak" default functions here. They return + * the default value back to the caller. + * + * Please see include/configs/yucca.h for an example fora board specific + * implementation. + */ +u32 __ddr_wrdtr(u32 default_val) +{ + return default_val; +} +u32 ddr_wrdtr(u32) __attribute__((weak, alias("__ddr_wrdtr"))); + +u32 __ddr_clktr(u32 default_val) +{ + return default_val; +} +u32 ddr_clktr(u32) __attribute__((weak, alias("__ddr_clktr"))); + /* Private Structure Definitions */ @@ -154,7 +177,6 @@ typedef enum ddr_cas_id { * Prototypes *-----------------------------------------------------------------------------*/ static unsigned long sdram_memsize(void); -void program_tlb(u32 phys_addr, u32 virt_addr, u32 size, u32 tlb_word2_i_value); static void get_spd_info(unsigned long *dimm_populated, unsigned char *iic0_dimm_addr, unsigned long num_dimm_banks); @@ -216,12 +238,9 @@ static void test(void); #else static void DQS_calibration_process(void); #endif -#if defined(DEBUG) static void ppc440sp_sdram_register_dump(void); -#endif int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); void dcbz_area(u32 start_address, u32 num_bytes); -void dflush(void); static u32 mfdcr_any(u32 dcr) { @@ -372,9 +391,9 @@ long int initdram(int board_type) unsigned char spd1[MAX_SPD_BYTES]; unsigned char *dimm_spd[MAXDIMMS]; unsigned long dimm_populated[MAXDIMMS]; - unsigned long num_dimm_banks; /* on board dimm banks */ + unsigned long num_dimm_banks; /* on board dimm banks */ unsigned long val; - ddr_cas_id_t selected_cas; + ddr_cas_id_t selected_cas = DDR_CAS_5; /* preset to silence compiler */ int write_recovery; unsigned long dram_size = 0; @@ -469,17 +488,14 @@ long int initdram(int board_type) *-----------------------------------------------------------------*/ mfsdram(SDRAM_WRDTR, val); mtsdram(SDRAM_WRDTR, (val & ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK)) | - (SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_90_DEG_ADV)); + ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_90_DEG_ADV)); /*------------------------------------------------------------------ * Set the SDRAM Clock Timing Register *-----------------------------------------------------------------*/ mfsdram(SDRAM_CLKTR, val); -#ifdef CFG_44x_DDR2_CKTR_180 - mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) | SDRAM_CLKTR_CLKP_180_DEG_ADV); -#else - mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) | SDRAM_CLKTR_CLKP_0_DEG); -#endif + mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) | + ddr_clktr(SDRAM_CLKTR_CLKP_0_DEG)); /*------------------------------------------------------------------ * Program the BxCF registers. @@ -538,7 +554,12 @@ long int initdram(int board_type) dram_size = sdram_memsize(); /* and program tlb entries for this size (dynamic) */ - program_tlb(0, 0, dram_size, MY_TLB_WORD2_I_ENABLE); + + /* + * Program TLB entries with caches enabled, for best performace + * while auto-calibrating and ECC generation + */ + program_tlb(0, 0, dram_size, 0); /*------------------------------------------------------------------ * DQS calibration. @@ -549,12 +570,25 @@ long int initdram(int board_type) /*------------------------------------------------------------------ * If ecc is enabled, initialize the parity bits. *-----------------------------------------------------------------*/ - program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, MY_TLB_WORD2_I_ENABLE); + program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, 0); #endif -#ifdef DEBUG + /* + * Now after initialization (auto-calibration and ECC generation) + * remove the TLB entries with caches enabled and program again with + * desired cache functionality + */ + remove_tlb(0, dram_size); + program_tlb(0, 0, dram_size, MY_TLB_WORD2_I_ENABLE); + ppc440sp_sdram_register_dump(); -#endif + + /* + * Clear potential errors resulting from auto-calibration. + * If not done, then we could get an interrupt later on when + * exceptions are enabled. + */ + set_mcsr(get_mcsr()); return dram_size; } @@ -596,10 +630,9 @@ static void get_spd_info(unsigned long *dimm_populated, } } -#ifdef CONFIG_ADD_RAM_INFO void board_add_ram_info(int use_default) { - PPC440_SYS_INFO board_cfg; + PPC4xx_SYS_INFO board_cfg; u32 val; if (is_ecc_enabled()) @@ -617,7 +650,6 @@ void board_add_ram_info(int use_default) val = (val & SDRAM_MMODE_DCL_MASK) >> 4; printf(", CL%d)", val); } -#endif /*------------------------------------------------------------------ * For the memory DIMMs installed, this routine verifies that they @@ -718,7 +750,7 @@ static void check_frequency(unsigned long *dimm_populated, unsigned long calc_cycle_time; unsigned long sdram_freq; unsigned long sdr_ddrpll; - PPC440_SYS_INFO board_cfg; + PPC4xx_SYS_INFO board_cfg; /*------------------------------------------------------------------ * Get the board configuration info. @@ -1330,7 +1362,7 @@ static void program_mode(unsigned long *dimm_populated, unsigned long max_4_0_tcyc_ns_x_100; unsigned long max_5_0_tcyc_ns_x_100; unsigned long cycle_time_ns_x_100[3]; - PPC440_SYS_INFO board_cfg; + PPC4xx_SYS_INFO board_cfg; unsigned char cas_2_0_available; unsigned char cas_2_5_available; unsigned char cas_3_0_available; @@ -1617,7 +1649,7 @@ static void program_rtr(unsigned long *dimm_populated, unsigned char *iic0_dimm_addr, unsigned long num_dimm_banks) { - PPC440_SYS_INFO board_cfg; + PPC4xx_SYS_INFO board_cfg; unsigned long max_refresh_rate; unsigned long dimm_num; unsigned long refresh_rate_type; @@ -1714,7 +1746,7 @@ static void program_tr(unsigned long *dimm_populated, unsigned long sdram_freq; unsigned long sdr_ddrpll; - PPC440_SYS_INFO board_cfg; + PPC4xx_SYS_INFO board_cfg; /*------------------------------------------------------------------ * Get the board configuration info. @@ -2025,14 +2057,10 @@ static void program_bxcf(unsigned long *dimm_populated, /*------------------------------------------------------------------ * Set the BxCF regs. First, wipe out the bank config registers. *-----------------------------------------------------------------*/ - mtdcr(SDRAMC_CFGADDR, SDRAM_MB0CF); - mtdcr(SDRAMC_CFGDATA, 0x00000000); - mtdcr(SDRAMC_CFGADDR, SDRAM_MB1CF); - mtdcr(SDRAMC_CFGDATA, 0x00000000); - mtdcr(SDRAMC_CFGADDR, SDRAM_MB2CF); - mtdcr(SDRAMC_CFGDATA, 0x00000000); - mtdcr(SDRAMC_CFGADDR, SDRAM_MB3CF); - mtdcr(SDRAMC_CFGDATA, 0x00000000); + mtsdram(SDRAM_MB0CF, 0x00000000); + mtsdram(SDRAM_MB1CF, 0x00000000); + mtsdram(SDRAM_MB2CF, 0x00000000); + mtsdram(SDRAM_MB3CF, 0x00000000); mode = SDRAM_BXCF_M_BE_ENABLE; @@ -2053,7 +2081,7 @@ static void program_bxcf(unsigned long *dimm_populated, if (num_banks == 4) ind = 0; else - ind = 5; + ind = 5 << 8; switch (num_col_addr) { case 0x08: mode |= (SDRAM_BXCF_M_AM_0 + ind); @@ -2084,8 +2112,9 @@ static void program_bxcf(unsigned long *dimm_populated, bank_0_populated = 1; for (ind_rank = 0; ind_rank < num_ranks; ind_rank++) { - mtdcr(SDRAMC_CFGADDR, SDRAM_MB0CF + ((dimm_num + bank_0_populated + ind_rank) << 2)); - mtdcr(SDRAMC_CFGDATA, mode); + mtsdram(SDRAM_MB0CF + + ((dimm_num + bank_0_populated + ind_rank) << 2), + mode); } } } @@ -2107,6 +2136,7 @@ static void program_memory_queue(unsigned long *dimm_populated, unsigned long baseadd_size; unsigned long i; unsigned long bank_0_populated = 0; + unsigned long total_size = 0; /*------------------------------------------------------------------ * Reset the rank_base_address. @@ -2129,28 +2159,38 @@ static void program_memory_queue(unsigned long *dimm_populated, * Set the sizes *-----------------------------------------------------------------*/ baseadd_size = 0; - rank_size_bytes = 4 * 1024 * 1024 * rank_size_id; switch (rank_size_id) { + case 0x01: + baseadd_size |= SDRAM_RXBAS_SDSZ_1024; + total_size = 1024; + break; case 0x02: - baseadd_size |= SDRAM_RXBAS_SDSZ_8; + baseadd_size |= SDRAM_RXBAS_SDSZ_2048; + total_size = 2048; break; case 0x04: - baseadd_size |= SDRAM_RXBAS_SDSZ_16; + baseadd_size |= SDRAM_RXBAS_SDSZ_4096; + total_size = 4096; break; case 0x08: baseadd_size |= SDRAM_RXBAS_SDSZ_32; + total_size = 32; break; case 0x10: baseadd_size |= SDRAM_RXBAS_SDSZ_64; + total_size = 64; break; case 0x20: baseadd_size |= SDRAM_RXBAS_SDSZ_128; + total_size = 128; break; case 0x40: baseadd_size |= SDRAM_RXBAS_SDSZ_256; + total_size = 256; break; case 0x80: baseadd_size |= SDRAM_RXBAS_SDSZ_512; + total_size = 512; break; default: printf("DDR-SDRAM: DIMM %d memory queue configuration.\n", @@ -2160,6 +2200,7 @@ static void program_memory_queue(unsigned long *dimm_populated, printf("Replace the DIMM module with a supported DIMM.\n\n"); spd_ddr_init_hang (); } + rank_size_bytes = total_size << 20; if ((dimm_populated[dimm_num] != SDRAM_NONE) && (dimm_num == 1)) bank_0_populated = 1; @@ -2172,6 +2213,19 @@ static void program_memory_queue(unsigned long *dimm_populated, } } } + +#if defined(CONFIG_460EX) || defined(CONFIG_460GT) + /* + * Enable high bandwidth access on 460EX/GT. + * This should/could probably be done on other + * PPC's too, like 440SPe. + * This is currently not used, but with this setup + * it is possible to use it later on in e.g. the Linux + * EMAC driver for performance gain. + */ + mtdcr(SDRAM_PLBADDULL, 0x00000000); /* MQ0_BAUL */ + mtdcr(SDRAM_PLBADDUHB, 0x00000008); /* MQ0_BAUH */ +#endif } /*-----------------------------------------------------------------------------+ @@ -2248,39 +2302,6 @@ static void program_ecc(unsigned long *dimm_populated, return; } -#ifdef CONFIG_ECC_ERROR_RESET -/* - * Check for ECC errors and reset board upon any error here - * - * On the Katmai 440SPe eval board, from time to time, the first - * lword write access after DDR2 initializazion with ECC checking - * enabled, leads to an ECC error. I couldn't find a configuration - * without this happening. On my board with the current setup it - * happens about 1 from 10 times. - * - * The ECC modules used for testing are: - * - Kingston ValueRAM KVR667D2E5/512 (tested with 1 and 2 DIMM's) - * - * This has to get fixed for the Katmai and tested for the other - * board (440SP/440SPe) that will eventually use this code in the - * future. - * - * 2007-03-01, sr - */ -static void check_ecc(void) -{ - u32 val; - - mfsdram(SDRAM_ECCCR, val); - if (val != 0) { - printf("\nECC error: MCIF0_ECCES=%08lx MQ0_ESL=%08lx address=%08lx\n", - val, mfdcr(0x4c), mfdcr(0x4e)); - printf("ECC error occured, resetting board...\n"); - do_reset(NULL, 0, 0, NULL); - } -} -#endif - static void wait_ddr_idle(void) { u32 val; @@ -2337,7 +2358,8 @@ static void program_ecc_addr(unsigned long start_address, } else { /* ECC bit set method for cached memory */ dcbz_area(start_address, num_bytes); - dflush(); + /* Write modified dcache lines back to memory */ + clean_dcache_range(start_address, start_address + num_bytes); } blank_string(strlen(str)); @@ -2355,15 +2377,6 @@ static void program_ecc_addr(unsigned long start_address, sync(); eieio(); wait_ddr_idle(); - -#ifdef CONFIG_ECC_ERROR_RESET - /* - * One write to 0 is enough to trigger this ECC error - * (see description above) - */ - out_be32(0, 0x12345678); - check_ecc(); -#endif } } #endif @@ -2389,17 +2402,10 @@ static void program_DQS_calibration(unsigned long *dimm_populated, * Read sample cycle auto-update enable *-----------------------------------------------------------------*/ - /* - * Modified for the Katmai platform: with some DIMMs, the DDR2 - * controller automatically selects the T2 read cycle, but this - * proves unreliable. Go ahead and force the DDR2 controller - * to use the T4 sample and disable the automatic update of the - * RDSS field. - */ mfsdram(SDRAM_RDCC, val); mtsdram(SDRAM_RDCC, (val & ~(SDRAM_RDCC_RDSS_MASK | SDRAM_RDCC_RSAE_MASK)) - | (SDRAM_RDCC_RDSS_T4 | SDRAM_RDCC_RSAE_DISABLE)); + | SDRAM_RDCC_RSAE_ENABLE); /*------------------------------------------------------------------ * Program RQDC register @@ -2492,10 +2498,7 @@ static void DQS_calibration_process(void) { unsigned long rfdc_reg; unsigned long rffd; - unsigned long rqdc_reg; - unsigned long rqfd; unsigned long val; - long rqfd_average; long rffd_average; long max_start; long min_end; @@ -2513,10 +2516,14 @@ static void DQS_calibration_process(void) long max_end; unsigned char fail_found; unsigned char pass_found; +#if !defined(CONFIG_DDR_RQDC_FIXED) + u32 rqdc_reg; + u32 rqfd; u32 rqfd_start; + u32 rqfd_average; + int loopi = 0; char str[] = "Auto calibration -"; char slash[] = "\\|/-\\|/-"; - int loopi = 0; /*------------------------------------------------------------------ * Test to determine the best read clock delay tuning bits. @@ -2551,6 +2558,16 @@ calibration_loop: mfsdram(SDRAM_RQDC, rqdc_reg); mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) | SDRAM_RQDC_RQFD_ENCODE(rqfd_start)); +#else /* CONFIG_DDR_RQDC_FIXED */ + /* + * On Katmai the complete auto-calibration somehow doesn't seem to + * produce the best results, meaning optimal values for RQFD/RFFD. + * This was discovered by GDA using a high bandwidth scope, + * analyzing the DDR2 signals. GDA provided a fixed value for RQFD, + * so now on Katmai "only" RFFD is auto-calibrated. + */ + mtsdram(SDRAM_RQDC, CONFIG_DDR_RQDC_FIXED); +#endif /* CONFIG_DDR_RQDC_FIXED */ max_start = 0; min_end = 0; @@ -2635,6 +2652,7 @@ calibration_loop: /* now fix RFDC[RFFD] found and find RQDC[RQFD] */ mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average)); +#if !defined(CONFIG_DDR_RQDC_FIXED) max_pass_length = 0; max_start = 0; max_end = 0; @@ -2703,11 +2721,10 @@ calibration_loop: printf("\nERROR: Cannot determine a common read delay for the " "DIMM(s) installed.\n"); debug("%s[%d] ERROR : \n", __FUNCTION__,__LINE__); + ppc440sp_sdram_register_dump(); spd_ddr_init_hang (); } - blank_string(strlen(str)); - if (rqfd_average < 0) rqfd_average = 0; @@ -2718,12 +2735,31 @@ calibration_loop: (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) | SDRAM_RQDC_RQFD_ENCODE(rqfd_average)); + blank_string(strlen(str)); +#endif /* CONFIG_DDR_RQDC_FIXED */ + + /* + * Now complete RDSS configuration as mentioned on page 7 of the AMCC + * PowerPC440SP/SPe DDR2 application note: + * "DDR1/DDR2 Initialization Sequence and Dynamic Tuning" + */ + mfsdram(SDRAM_RTSR, val); + if ((val & SDRAM_RTSR_TRK1SM_MASK) == SDRAM_RTSR_TRK1SM_ATPLS1) { + mfsdram(SDRAM_RDCC, val); + if ((val & SDRAM_RDCC_RDSS_MASK) != SDRAM_RDCC_RDSS_T4) { + val += 0x40000000; + mtsdram(SDRAM_RDCC, val); + } + } + mfsdram(SDRAM_DLCR, val); debug("%s[%d] DLCR: 0x%08X\n", __FUNCTION__, __LINE__, val); mfsdram(SDRAM_RQDC, val); debug("%s[%d] RQDC: 0x%08X\n", __FUNCTION__, __LINE__, val); mfsdram(SDRAM_RFDC, val); debug("%s[%d] RFDC: 0x%08X\n", __FUNCTION__, __LINE__, val); + mfsdram(SDRAM_RDCC, val); + debug("%s[%d] RDCC: 0x%08X\n", __FUNCTION__, __LINE__, val); } #else /* calibration test with hardvalues */ /*-----------------------------------------------------------------------------+ @@ -3028,5 +3064,9 @@ static void ppc440sp_sdram_register_dump(void) dcr_data = mfdcr(SDRAM_R3BAS); printf(" MQ3_B0BAS = 0x%08X\n", dcr_data); } +#else +static void ppc440sp_sdram_register_dump(void) +{ +} #endif #endif /* CONFIG_SPD_EEPROM */