[U-Boot] [PATCH 1/8] powerpc/8xxx: Enabled hwconfig for memory interleaving

Replace environmental variables memctl_intlv_ctl and ba_intlv_ctl with hwconfig parameters. The syntax is
setenv hwconfig "fsl_ddr:ctlr_intlv=<mode>,bank_intlv=<mode>"
The mode values for memory controller interleaving are cacheline page bank superbank
The mode values for bank interleaving are cs0_cs1 cs2_cs3 cs0_cs1_and_cs2_cs3 cs0_cs1_cs2_cs3
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 40 ++++++++++++++++++++------------ doc/README.fsl-ddr | 25 +++++++++++-------- 2 files changed, 39 insertions(+), 26 deletions(-)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c index 46731c8..11281b7 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -8,6 +8,7 @@ */
#include <common.h> +#include <hwconfig.h> #include <asm/fsl_ddr_sdram.h>
#include "ddr.h" @@ -23,7 +24,6 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, unsigned int ctrl_num) { unsigned int i; - const char *p;
/* Chip select options. */
@@ -221,7 +221,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, * should be a subset of the requested configuration. */ #if (CONFIG_NUM_DDR_CONTROLLERS > 1) - if ((p = getenv("memctl_intlv_ctl")) != NULL) { + if (hwconfig_sub("fsl_ddr", "ctlr_intlv")) { if (pdimm[0].n_ranks == 0) { printf("There is no rank on CS0. Because only rank on " "CS0 and ranks chip-select interleaved with CS0" @@ -230,37 +230,47 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, popts->memctl_interleaving = 0; } else { popts->memctl_interleaving = 1; - if (strcmp(p, "cacheline") == 0) + /* test null first. if CONFIG_HWCONFIG is not defined + * hwconfig_arg_cmp returns non-zero */ + if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "null")) { + popts->memctl_interleaving = 0; + debug("memory controller interleaving disabled.\n"); + } else if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "cacheline")) popts->memctl_interleaving_mode = FSL_DDR_CACHE_LINE_INTERLEAVING; - else if (strcmp(p, "page") == 0) + else if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "page")) popts->memctl_interleaving_mode = FSL_DDR_PAGE_INTERLEAVING; - else if (strcmp(p, "bank") == 0) + else if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "bank")) popts->memctl_interleaving_mode = FSL_DDR_BANK_INTERLEAVING; - else if (strcmp(p, "superbank") == 0) + else if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "superbank")) popts->memctl_interleaving_mode = FSL_DDR_SUPERBANK_INTERLEAVING; - else - popts->memctl_interleaving_mode = - simple_strtoul(p, NULL, 0); + else { + popts->memctl_interleaving = 0; + printf("hwconfig has unrecognized parameter for ctlr_intlv.\n"); + } } } #endif
- if( ((p = getenv("ba_intlv_ctl")) != NULL) && + if ((hwconfig_sub("fsl_ddr", "bank_intlv")) && (CONFIG_CHIP_SELECTS_PER_CTRL > 1)) { - if (strcmp(p, "cs0_cs1") == 0) + /* test null first. if CONFIG_HWCONFIG is not defined, + * hwconfig_arg_cmp returns non-zero */ + if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "null")) + printf("bank interleaving disabled.\n"); + else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs0_cs1")) popts->ba_intlv_ctl = FSL_DDR_CS0_CS1; - else if (strcmp(p, "cs2_cs3") == 0) + else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs2_cs3")) popts->ba_intlv_ctl = FSL_DDR_CS2_CS3; - else if (strcmp(p, "cs0_cs1_and_cs2_cs3") == 0) + else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs0_cs1_and_cs2_cs3")) popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_AND_CS2_CS3; - else if (strcmp(p, "cs0_cs1_cs2_cs3") == 0) + else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs0_cs1_cs2_cs3")) popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3; else - popts->ba_intlv_ctl = simple_strtoul(p, NULL, 0); + printf("hwconfig has unrecognized parameter for ba_intlv_ctl.\n");
switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { case FSL_DDR_CS0_CS1_CS2_CS3: diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr index 9c2224f..6e4f6e9 100644 --- a/doc/README.fsl-ddr +++ b/doc/README.fsl-ddr @@ -32,38 +32,41 @@ The ways to configure the ddr interleaving mode 1. In board header file(e.g.MPC8572DS.h), add default interleaving setting under "CONFIG_EXTRA_ENV_SETTINGS", like: #define CONFIG_EXTRA_ENV_SETTINGS \ - "memctl_intlv_ctl=2\0" \ + "hwconfig=fsl_ddr:ctlr_intlv=bank" \ ......
2. Run u-boot "setenv" command to configure the memory interleaving mode. Either numerical or string value is accepted.
# disable memory controller interleaving - setenv memctl_intlv_ctl + setenv hwconfig "fsl_ddr:ctlr_intlv=null"
# cacheline interleaving - setenv memctl_intlv_ctl 0 or setenv memctl_intlv_ctl cacheline + setenv hwconfig "fsl_ddr:ctlr_intlv=cacheline"
# page interleaving - setenv memctl_intlv_ctl 1 or setenv memctl_intlv_ctl page + setenv hwconfig "fsl_ddr:ctlr_intlv=page"
# bank interleaving - setenv memctl_intlv_ctl 2 or setenv memctl_intlv_ctl bank + setenv hwconfig "fsl_ddr:ctlr_intlv=bank"
# superbank - setenv memctl_intlv_ctl 3 or setenv memctl_intlv_ctl superbank + setenv hwconfig "fsl_ddr:ctlr_intlv=superbank"
# disable bank (chip-select) interleaving - setenv ba_intlv_ctl + setenv hwconfig "fsl_ddr:bank_intlv=null"
# bank(chip-select) interleaving cs0+cs1 - setenv ba_intlv_ctl 0x40 or setenv ba_intlv_ctl cs0_cs1 + setenv hwconfig "fsl_ddr:bank_intlv=cs0_cs1"
# bank(chip-select) interleaving cs2+cs3 - setenv ba_intlv_ctl 0x20 or setenv ba_intlv_ctl cs2_cs3 + setenv hwconfig "fsl_ddr:bank_intlv=cs2_cs3"
# bank(chip-select) interleaving (cs0+cs1) and (cs2+cs3) (2x2) - setenv ba_intlv_ctl 0x60 or setenv ba_intlv_ctl cs0_cs1_and_cs2_cs3 + setenv hwconfig "fsl_ddr:bank_intlv=cs0_cs1_and_cs2_cs3"
# bank(chip-select) interleaving (cs0+cs1+cs2+cs3) (4x1) - setenv ba_intlv_ctl 0x04 or setenv ba_intlv_ctl cs0_cs1_cs2_cs3 + setenv hwconfig "fsl_ddr:bank_intlv=cs0_cs1_cs2_cs3" + + The above memory controller interleaving and bank interleaving can be mixed. The syntax is + setenv hwconfig "fsl_ddr:ctlr_intlv=cacheline,bank_intlv=cs0_cs1"

From: york yorksun@freescale.com
Verified on MPC8641HPCN with four DDR2 dimms. Each dimm has dual rank with 512MB each rank.
Also check dimm size and rank size for memory controller interleaving
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 113 +++++++++++++++++++---------- arch/powerpc/cpu/mpc8xxx/ddr/ddr.h | 1 + arch/powerpc/cpu/mpc8xxx/ddr/main.c | 40 +++++----- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 107 +++++++++++++++++++++++----- board/freescale/mpc8641hpcn/mpc8641hpcn.c | 2 + doc/README.fsl-ddr | 3 + include/configs/MPC8641HPCN.h | 2 + 7 files changed, 191 insertions(+), 77 deletions(-)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index 4a282bc..69c1c7c 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -1201,20 +1201,28 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, /* Chip Select Memory Bounds (CSn_BNDS) */ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { unsigned long long ea = 0, sa = 0; - - if (popts->ba_intlv_ctl && (i > 0) && - ((popts->ba_intlv_ctl & 0x60) != FSL_DDR_CS2_CS3 )) { - /* Don't set up boundaries for other CS - * other than CS0, if bank interleaving - * is enabled and not CS2+CS3 interleaved. + unsigned int cs_per_dimm + = CONFIG_CHIP_SELECTS_PER_CTRL / CONFIG_DIMM_SLOTS_PER_CTLR; + unsigned int dimm_number + = i / cs_per_dimm; + unsigned long long rank_density + = dimm_params[dimm_number].rank_density; + + if (((i == 1) && (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1)) || + ((i == 2) && (popts->ba_intlv_ctl & 0x04)) || + ((i == 3) && (popts->ba_intlv_ctl & FSL_DDR_CS2_CS3))) { + /* + * Don't set up boundaries for unused CS + * cs1 for cs0_cs1, cs0_cs1_and_cs2_cs3, cs0_cs1_cs2_cs3 + * cs2 for cs0_cs1_cs2_cs3 + * cs3 for cs2_cs3, cs0_cs1_and_cs2_cs3, cs0_cs1_cs2_cs3 * But we need to set the ODT_RD_CFG and * ODT_WR_CFG for CS1_CONFIG here. */ set_csn_config(i, ddr, popts, dimm_params); - break; + continue; } - - if (dimm_params[i/2].n_ranks == 0) { + if (dimm_params[dimm_number].n_ranks == 0) { debug("Skipping setup of CS%u " "because n_ranks on DIMM %u is 0\n", i, i/2); continue; @@ -1222,16 +1230,34 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, if (popts->memctl_interleaving && popts->ba_intlv_ctl) { /* * This works superbank 2CS - * There are 2 memory controllers configured + * There are 2 or more memory controllers configured * identically, memory is interleaved between them, * and each controller uses rank interleaving within * itself. Therefore the starting and ending address * on each controller is twice the amount present on * each controller. */ - unsigned long long rank_density - = dimm_params[0].capacity; - ea = (2 * (rank_density >> dbw_cap_adj)) - 1; + unsigned long long ctlr_density = 0; + switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { + case FSL_DDR_CS0_CS1: + case FSL_DDR_CS0_CS1_AND_CS2_CS3: + ctlr_density = dimm_params[0].rank_density * 2; + break; + case FSL_DDR_CS2_CS3: + ctlr_density = dimm_params[0].rank_density; + break; + case FSL_DDR_CS0_CS1_CS2_CS3: + /* + * The four CS interleaving should have been verified by + * populate_memctl_options() + */ + ctlr_density = dimm_params[0].rank_density * 4; + break; + default: + break; + } + ea = (CONFIG_NUM_DDR_CONTROLLERS * + (ctlr_density >> dbw_cap_adj)) - 1; } else if (!popts->memctl_interleaving && popts->ba_intlv_ctl) { /* @@ -1243,8 +1269,6 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, * controller needs to be programmed into its * respective CS0_BNDS. */ - unsigned long long rank_density - = dimm_params[i/2].rank_density; switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { case FSL_DDR_CS0_CS1_CS2_CS3: /* CS0+CS1+CS2+CS3 interleaving, only CS0_CNDS @@ -1257,9 +1281,13 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, /* CS0+CS1 and CS2+CS3 interleaving, CS0_CNDS * and CS2_CNDS need to be set. */ - if (!(i&1)) { - sa = dimm_params[i/2].base_address; - ea = sa + (i * (rank_density >> + if ((i == 2) && (dimm_number == 0)) { + sa = dimm_params[dimm_number].base_address + + 2 * (rank_density >> dbw_cap_adj); + ea = sa + 2 * (rank_density >> dbw_cap_adj) - 1; + } else { + sa = dimm_params[dimm_number].base_address; + ea = sa + (2 * (rank_density >> dbw_cap_adj)) - 1; } break; @@ -1267,16 +1295,31 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, /* CS0+CS1 interleaving, CS0_CNDS needs * to be set */ - sa = common_dimm->base_address; - ea = sa + (2 * (rank_density >> dbw_cap_adj))-1; + if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) { + sa = dimm_params[dimm_number].base_address; + ea = sa + (rank_density >> dbw_cap_adj) - 1; + sa += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); + ea += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); + } else { + sa = 0; + ea = 0; + } + if (i == 0) + ea += (rank_density >> dbw_cap_adj); break; case FSL_DDR_CS2_CS3: /* CS2+CS3 interleaving*/ - if (i == 2) { - sa = dimm_params[i/2].base_address; - ea = sa + (2 * (rank_density >> - dbw_cap_adj)) - 1; + if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) { + sa = dimm_params[dimm_number].base_address; + ea = sa + (rank_density >> dbw_cap_adj) - 1; + sa += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); + ea += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); + } else { + sa = 0; + ea = 0; } + if (i == 2) + ea += (rank_density >> dbw_cap_adj); break; default: /* No bank(chip-select) interleaving */ break; @@ -1292,8 +1335,6 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, * memory in the two CS0 ranks. */ if (i == 0) { - unsigned long long rank_density - = dimm_params[0].rank_density; ea = (2 * (rank_density >> dbw_cap_adj)) - 1; }
@@ -1303,20 +1344,14 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, * No rank interleaving and no memory controller * interleaving. */ - unsigned long long rank_density - = dimm_params[i/2].rank_density; - sa = dimm_params[i/2].base_address; + sa = dimm_params[dimm_number].base_address; ea = sa + (rank_density >> dbw_cap_adj) - 1; - if (i&1) { - if ((dimm_params[i/2].n_ranks == 1)) { - /* Odd chip select, single-rank dimm */ - sa = 0; - ea = 0; - } else { - /* Odd chip select, dual-rank DIMM */ - sa += rank_density >> dbw_cap_adj; - ea += rank_density >> dbw_cap_adj; - } + if (dimm_params[dimm_number].n_ranks > (i % cs_per_dimm)) { + sa += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); + ea += (i % cs_per_dimm) * (rank_density >> dbw_cap_adj); + } else { + sa = 0; + ea = 0; } }
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h b/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h index f122075..98acb8d 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ddr.h @@ -73,6 +73,7 @@ extern unsigned int populate_memctl_options(int all_DIMMs_registered, memctl_options_t *popts, dimm_params_t *pdimm, unsigned int ctrl_num); +extern void check_interleaving_options(fsl_ddr_info_t *pinfo);
extern unsigned int mclk_to_picos(unsigned int mclk); extern unsigned int get_memory_clk_period_ps(void); diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/main.c b/arch/powerpc/cpu/mpc8xxx/ddr/main.c index faa1af9..6d582e9 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/main.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/main.c @@ -100,8 +100,8 @@ const char * step_to_string(unsigned int step) {
int step_assign_addresses(fsl_ddr_info_t *pinfo, unsigned int dbw_cap_adj[], - unsigned int *memctl_interleaving, - unsigned int *rank_interleaving) + unsigned int *all_memctl_interleaving, + unsigned int *all_ctlr_rank_interleaving) { int i, j;
@@ -152,30 +152,30 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo, } }
- /* - * Check if all controllers are configured for memory - * controller interleaving. - */ j = 0; - for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { - if (pinfo->memctl_opts[i].memctl_interleaving) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + if (pinfo->memctl_opts[i].memctl_interleaving) j++; - } - } - if (j == 2) - *memctl_interleaving = 1; + /* + * Not support less than all memory controllers interleaving + * if more than two controllers + */ + if (j == CONFIG_NUM_DDR_CONTROLLERS) + *all_memctl_interleaving = 1;
/* Check that all controllers are rank interleaving. */ j = 0; - for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { - if (pinfo->memctl_opts[i].ba_intlv_ctl) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + if (pinfo->memctl_opts[i].ba_intlv_ctl) j++; - } - } - if (j == 2) - *rank_interleaving = 1; + /* + * All memory controllers must be populated to qualify for + * all controller rank interleaving + */ + if (j == CONFIG_NUM_DDR_CONTROLLERS) + *all_ctlr_rank_interleaving = 1;
- if (*memctl_interleaving) { + if (*all_memctl_interleaving) { unsigned long long addr, total_mem_per_ctlr = 0; /* * If interleaving between memory controllers, @@ -316,7 +316,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step) &pinfo->memctl_opts[i], pinfo->dimm_params[i], i); } - + check_interleaving_options(pinfo); case STEP_ASSIGN_ADDRESSES: /* STEP 5: Assign addresses to chip selects */ step_assign_addresses(pinfo, diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c index 11281b7..ebbdb69 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -212,10 +212,9 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, * Please refer to doc/README.fsl-ddr for the detail. * * If memory controller interleaving is enabled, then the data - * bus widths must be programmed identically for the 2 memory - * controllers. + * bus widths must be programmed identically for all memory controllers. * - * XXX: Attempt to set both controllers to the same chip select + * XXX: Attempt to set all controllers to the same chip select * interleaving mode. It will do a best effort to get the * requested ranks interleaved together such that the result * should be a subset of the requested configuration. @@ -223,15 +222,17 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, #if (CONFIG_NUM_DDR_CONTROLLERS > 1) if (hwconfig_sub("fsl_ddr", "ctlr_intlv")) { if (pdimm[0].n_ranks == 0) { - printf("There is no rank on CS0. Because only rank on " - "CS0 and ranks chip-select interleaved with CS0" + printf("There is no rank on CS0 for controller %d. Because only" + " rank on CS0 and ranks chip-select interleaved with CS0" " are controller interleaved, force non memory " - "controller interleaving\n"); + "controller interleaving\n", ctrl_num); popts->memctl_interleaving = 0; } else { popts->memctl_interleaving = 1; - /* test null first. if CONFIG_HWCONFIG is not defined - * hwconfig_arg_cmp returns non-zero */ + /* + * test null first. if CONFIG_HWCONFIG is not defined + * hwconfig_arg_cmp returns non-zero + */ if (hwconfig_subarg_cmp("fsl_ddr", "ctlr_intlv", "null")) { popts->memctl_interleaving = 0; debug("memory controller interleaving disabled.\n"); @@ -254,13 +255,12 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, } } #endif - if ((hwconfig_sub("fsl_ddr", "bank_intlv")) && (CONFIG_CHIP_SELECTS_PER_CTRL > 1)) { /* test null first. if CONFIG_HWCONFIG is not defined, * hwconfig_arg_cmp returns non-zero */ if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "null")) - printf("bank interleaving disabled.\n"); + debug("bank interleaving disabled.\n"); else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs0_cs1")) popts->ba_intlv_ctl = FSL_DDR_CS0_CS1; else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs2_cs3")) @@ -270,30 +270,70 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, else if (hwconfig_subarg_cmp("fsl_ddr", "bank_intlv", "cs0_cs1_cs2_cs3")) popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3; else - printf("hwconfig has unrecognized parameter for ba_intlv_ctl.\n"); - + printf("hwconfig has unrecognized parameter for bank_intlv.\n"); switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { case FSL_DDR_CS0_CS1_CS2_CS3: +#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) + if (pdimm[0].n_ranks != 4) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(chip-select) for " + "CS0+CS1+CS2+CS3 on controller %d, " + "force non-interleaving!\n", ctrl_num); + } +#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) + if ((pdimm[0].n_ranks != 2) && (pdimm[1].n_ranks != 2)) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(chip-select) for " + "CS0+CS1+CS2+CS3 on controller %d, " + "force non-interleaving!\n", ctrl_num); + } + if (pdimm[0].capacity != pdimm[1].capacity) { + popts->ba_intlv_ctl = 0; + printf("Not identical DIMM size for " + "CS0+CS1+CS2+CS3 on controller %d, " + "force non-interleaving!\n", ctrl_num); + } +#endif + break; case FSL_DDR_CS0_CS1: if (pdimm[0].n_ranks != 2) { popts->ba_intlv_ctl = 0; printf("Not enough bank(chip-select) for " - "CS0+CS1, force non-interleaving!\n"); + "CS0+CS1 on controller %d, " + "force non-interleaving!\n", ctrl_num); } break; case FSL_DDR_CS2_CS3: - if (pdimm[1].n_ranks !=2){ +#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) + if (pdimm[0].n_ranks != 4) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(chip-select) for CS2+CS3 " + "on controller %d, force non-interleaving!\n", ctrl_num); + } +#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) + if (pdimm[1].n_ranks != 2) { popts->ba_intlv_ctl = 0; - printf("Not enough bank(CS) for CS2+CS3, " - "force non-interleaving!\n"); + printf("Not enough bank(chip-select) for CS2+CS3 " + "on controller %d, force non-interleaving!\n", ctrl_num); } +#endif break; case FSL_DDR_CS0_CS1_AND_CS2_CS3: +#if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) + if (pdimm[0].n_ranks != 4) { + popts->ba_intlv_ctl = 0; + printf("Not enough bank(CS) for CS0+CS1 and " + "CS2+CS3 on controller %d, " + "force non-interleaving!\n", ctrl_num); + } +#elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) if ((pdimm[0].n_ranks != 2)||(pdimm[1].n_ranks != 2)) { popts->ba_intlv_ctl = 0; - printf("Not enough bank(CS) for CS0+CS1 or " - "CS2+CS3, force non-interleaving!\n"); + printf("Not enough bank(CS) for CS0+CS1 and " + "CS2+CS3 on controller %d, " + "force non-interleaving!\n", ctrl_num); } +#endif break; default: popts->ba_intlv_ctl = 0; @@ -305,3 +345,34 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
return 0; } + +void check_interleaving_options(fsl_ddr_info_t *pinfo) +{ + int i, j, check_n_ranks, intlv_fixed = 0; + unsigned long long check_rank_density; + /* + * Check if all controllers are configured for memory + * controller interleaving. Identical dimms are recommended. At least + * the size should be checked. + */ + j = 0; + check_n_ranks = pinfo->dimm_params[0][0].n_ranks; + check_rank_density = pinfo->dimm_params[0][0].rank_density; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + if ((pinfo->memctl_opts[i].memctl_interleaving) && \ + (check_rank_density == pinfo->dimm_params[i][0].rank_density) && \ + (check_n_ranks == pinfo->dimm_params[i][0].n_ranks)) { + j++; + } + } + if (j != CONFIG_NUM_DDR_CONTROLLERS) { + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + if (pinfo->memctl_opts[i].memctl_interleaving) { + pinfo->memctl_opts[i].memctl_interleaving = 0; + intlv_fixed = 1; + } + if (intlv_fixed) + printf("Not all DIMMs are identical in size. " + "Memory controller interleaving disabled.\n"); + } +} diff --git a/board/freescale/mpc8641hpcn/mpc8641hpcn.c b/board/freescale/mpc8641hpcn/mpc8641hpcn.c index d86ca12..fee310a 100644 --- a/board/freescale/mpc8641hpcn/mpc8641hpcn.c +++ b/board/freescale/mpc8641hpcn/mpc8641hpcn.c @@ -60,6 +60,8 @@ int checkboard(void) return 0; }
+const char *board_hwconfig = "foo:bar=baz"; +const char *cpu_hwconfig = "foo:bar=baz";
phys_size_t initdram(int board_type) diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr index 6e4f6e9..8c37bbe 100644 --- a/doc/README.fsl-ddr +++ b/doc/README.fsl-ddr @@ -27,6 +27,9 @@ Table of interleaving modes supported in cpu/8xxx/ddr/ from each controller. {CS2+CS3} on each controller are only rank interleaved on that controller.
+ For memory controller interleaving, identical DIMMs are suggested. Software + doesn't check the size or organization of interleaved DIMMs. + The ways to configure the ddr interleaving mode ============================================== 1. In board header file(e.g.MPC8572DS.h), add default interleaving setting diff --git a/include/configs/MPC8641HPCN.h b/include/configs/MPC8641HPCN.h index 0d1f779..974cb6b 100644 --- a/include/configs/MPC8641HPCN.h +++ b/include/configs/MPC8641HPCN.h @@ -122,6 +122,8 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); #define CONFIG_SYS_CCSRBAR_PHYS CONFIG_SYS_CCSRBAR_PHYS_LOW #endif
+#define CONFIG_HWCONFIG /* use hwconfig to control memory interleaving */ + /* * DDR Setup */

From: york yorksun@freescale.com
Previous code presumes each DIMM has up to two rank (chip select). Newer DDR controller supports up to four chip select on one DIMM.
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 52 ++++++++++++++----- .../cpu/mpc8xxx/ddr/lc_common_dimm_params.c | 12 +++++ arch/powerpc/cpu/mpc8xxx/ddr/options.c | 17 ++++--- arch/powerpc/include/asm/fsl_ddr_sdram.h | 1 + 4 files changed, 61 insertions(+), 21 deletions(-)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index 69c1c7c..6e73b1d 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -93,7 +93,7 @@ static inline unsigned int compute_cas_write_latency(void) }
/* Chip Select Configuration (CSn_CONFIG) */ -static void set_csn_config(int i, fsl_ddr_cfg_regs_t *ddr, +static void set_csn_config(int dimm_number, int i, fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts, const dimm_params_t *dimm_params) { @@ -106,28 +106,49 @@ static void set_csn_config(int i, fsl_ddr_cfg_regs_t *ddr, unsigned int ba_bits_cs_n = 0; /* Num of bank bits for SDRAM on CSn */ unsigned int row_bits_cs_n = 0; /* Num of row bits for SDRAM on CSn */ unsigned int col_bits_cs_n = 0; /* Num of ocl bits for SDRAM on CSn */ + int go_config = 0;
/* Compute CS_CONFIG only for existing ranks of each DIMM. */ - if ((((i&1) == 0) - && (dimm_params[i/2].n_ranks == 1)) - || (dimm_params[i/2].n_ranks == 2)) { - unsigned int n_banks_per_sdram_device; - cs_n_en = 1; - if (i == 0) { + switch (i) { + case 0: + if (dimm_params[dimm_number].n_ranks > 0) { + go_config = 1; /* These fields only available in CS0_CONFIG */ intlv_en = popts->memctl_interleaving; intlv_ctl = popts->memctl_interleaving_mode; } + break; + case 1: + if ((dimm_number == 0 && dimm_params[0].n_ranks > 1) || \ + (dimm_number == 1 && dimm_params[1].n_ranks > 0)) + go_config = 1; + break; + case 2: + if ((dimm_number == 0 && dimm_params[0].n_ranks > 2) || \ + (dimm_number > 1 && dimm_params[dimm_number].n_ranks > 0)) + go_config = 1; + break; + case 3: + if ((dimm_number == 0 && dimm_params[0].n_ranks > 3) || \ + (dimm_number == 1 && dimm_params[1].n_ranks > 1) || \ + (dimm_number == 3 && dimm_params[3].n_ranks > 0)) + go_config = 1; + break; + default: + break; + } + if (go_config) { + unsigned int n_banks_per_sdram_device; + cs_n_en = 1; ap_n_en = popts->cs_local_opts[i].auto_precharge; odt_rd_cfg = popts->cs_local_opts[i].odt_rd_cfg; odt_wr_cfg = popts->cs_local_opts[i].odt_wr_cfg; n_banks_per_sdram_device - = dimm_params[i/2].n_banks_per_sdram_device; + = dimm_params[dimm_number].n_banks_per_sdram_device; ba_bits_cs_n = __ilog2(n_banks_per_sdram_device) - 2; - row_bits_cs_n = dimm_params[i/2].n_row_addr - 12; - col_bits_cs_n = dimm_params[i/2].n_col_addr - 8; + row_bits_cs_n = dimm_params[dimm_number].n_row_addr - 12; + col_bits_cs_n = dimm_params[dimm_number].n_col_addr - 8; } - ddr->cs[i].config = (0 | ((cs_n_en & 0x1) << 31) | ((intlv_en & 0x3) << 29) @@ -521,6 +542,7 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr, unsigned int d_init; /* DRAM data initialization */ unsigned int rcw_en = 0; /* Register Control Word Enable */ unsigned int md_en = 0; /* Mirrored DIMM Enable */ + unsigned int qd_en = 0; /* quad-rank DIMM Enable */
dll_rst_dis = 1; /* Make this configurable */ dqs_cfg = popts->DQS_config; @@ -562,6 +584,7 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr, #if defined(CONFIG_FSL_DDR3) md_en = popts->mirrored_dimm; #endif + qd_en = popts->quad_rank_present ? 1 : 0; ddr->ddr_sdram_cfg_2 = (0 | ((frc_sr & 0x1) << 31) | ((sr_ie & 0x1) << 30) @@ -569,6 +592,7 @@ static void set_ddr_sdram_cfg_2(fsl_ddr_cfg_regs_t *ddr, | ((dqs_cfg & 0x3) << 26) | ((odt_cfg & 0x3) << 21) | ((num_pr & 0xf) << 12) + | (qd_en << 9) | ((obc_cfg & 0x1) << 6) | ((ap_en & 0x1) << 5) | ((d_init & 0x1) << 4) @@ -1219,12 +1243,12 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, * But we need to set the ODT_RD_CFG and * ODT_WR_CFG for CS1_CONFIG here. */ - set_csn_config(i, ddr, popts, dimm_params); + set_csn_config(dimm_number, i, ddr, popts, dimm_params); continue; } if (dimm_params[dimm_number].n_ranks == 0) { debug("Skipping setup of CS%u " - "because n_ranks on DIMM %u is 0\n", i, i/2); + "because n_ranks on DIMM %u is 0\n", i, dimm_number); continue; } if (popts->memctl_interleaving && popts->ba_intlv_ctl) { @@ -1364,7 +1388,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, );
debug("FSLDDR: cs[%d]_bnds = 0x%08x\n", i, ddr->cs[i].bnds); - set_csn_config(i, ddr, popts, dimm_params); + set_csn_config(dimm_number, i, ddr, popts, dimm_params); set_csn_config_2(i, ddr); }
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c index e888e3e..ce6c148 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c @@ -118,6 +118,18 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, temp1++; continue; } + if (dimm_params[i].n_ranks == 4 && i != 0) { + printf("Found Quad-rank DIMM in wrong bank, ignored." + " Software may not run as expected.\n"); + temp1++; + continue; + } + if (dimm_params[i].n_ranks == 4 && \ + CONFIG_CHIP_SELECTS_PER_CTRL/CONFIG_DIMM_SLOTS_PER_CTLR < 4) { + printf("Found Quad-rank DIMM, not able to support."); + temp1++; + continue; + }
/* * Find minimum tCKmax_ps to find fastest slow speed, diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c index ebbdb69..1d5f3e2 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -274,14 +274,14 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) { case FSL_DDR_CS0_CS1_CS2_CS3: #if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) - if (pdimm[0].n_ranks != 4) { + if (pdimm[0].n_ranks < 4) { popts->ba_intlv_ctl = 0; printf("Not enough bank(chip-select) for " "CS0+CS1+CS2+CS3 on controller %d, " "force non-interleaving!\n", ctrl_num); } #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) - if ((pdimm[0].n_ranks != 2) && (pdimm[1].n_ranks != 2)) { + if ((pdimm[0].n_ranks < 2) && (pdimm[1].n_ranks < 2)) { popts->ba_intlv_ctl = 0; printf("Not enough bank(chip-select) for " "CS0+CS1+CS2+CS3 on controller %d, " @@ -296,7 +296,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, #endif break; case FSL_DDR_CS0_CS1: - if (pdimm[0].n_ranks != 2) { + if (pdimm[0].n_ranks < 2) { popts->ba_intlv_ctl = 0; printf("Not enough bank(chip-select) for " "CS0+CS1 on controller %d, " @@ -305,13 +305,13 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, break; case FSL_DDR_CS2_CS3: #if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) - if (pdimm[0].n_ranks != 4) { + if (pdimm[0].n_ranks < 4) { popts->ba_intlv_ctl = 0; printf("Not enough bank(chip-select) for CS2+CS3 " "on controller %d, force non-interleaving!\n", ctrl_num); } #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) - if (pdimm[1].n_ranks != 2) { + if (pdimm[1].n_ranks < 2) { popts->ba_intlv_ctl = 0; printf("Not enough bank(chip-select) for CS2+CS3 " "on controller %d, force non-interleaving!\n", ctrl_num); @@ -320,14 +320,14 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, break; case FSL_DDR_CS0_CS1_AND_CS2_CS3: #if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) - if (pdimm[0].n_ranks != 4) { + if (pdimm[0].n_ranks < 4) { popts->ba_intlv_ctl = 0; printf("Not enough bank(CS) for CS0+CS1 and " "CS2+CS3 on controller %d, " "force non-interleaving!\n", ctrl_num); } #elif (CONFIG_DIMM_SLOTS_PER_CTLR == 2) - if ((pdimm[0].n_ranks != 2)||(pdimm[1].n_ranks != 2)) { + if ((pdimm[0].n_ranks < 2) || (pdimm[1].n_ranks < 2)) { popts->ba_intlv_ctl = 0; printf("Not enough bank(CS) for CS0+CS1 and " "CS2+CS3 on controller %d, " @@ -341,6 +341,9 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, } }
+ if (pdimm[0].n_ranks == 4) + popts->quad_rank_present = 1; + fsl_ddr_board_options(popts, pdimm, ctrl_num);
return 0; diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h index 02920db..431327e 100644 --- a/arch/powerpc/include/asm/fsl_ddr_sdram.h +++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h @@ -172,6 +172,7 @@ typedef struct memctl_options_s { unsigned int OTF_burst_chop_en; /* mirrior DIMMs for DDR3 */ unsigned int mirrored_dimm; + unsigned int quad_rank_present;
/* Global Timing Parameters */ unsigned int cas_latency_override;

From: york yorksun@freescale.com
For 85xx silicon which supports address hashing, it can be activated by hwconfig.
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc85xx/ddr-gen3.c | 2 ++ arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 10 ++++++++++ arch/powerpc/cpu/mpc8xxx/ddr/options.c | 7 +++++++ arch/powerpc/include/asm/fsl_ddr_sdram.h | 2 ++ doc/README.fsl-ddr | 15 +++++++++++++-- 5 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c index 0691ca4..e46dcb7 100644 --- a/arch/powerpc/cpu/mpc85xx/ddr-gen3.c +++ b/arch/powerpc/cpu/mpc85xx/ddr-gen3.c @@ -33,6 +33,8 @@ void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs, return; }
+ out_be32(&ddr->eor, regs->ddr_eor); + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { if (i == 0) { out_be32(&ddr->cs0_bnds, regs->cs[i].bnds); diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index 6e73b1d..ff0ddd1 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -1161,6 +1161,14 @@ static void set_ddr_sdram_rcw_2(fsl_ddr_cfg_regs_t *ddr) ); }
+static void set_ddr_eor(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts) +{ + if (popts->addr_hash) { + ddr->ddr_eor = 0x40000000; /* address hash enable */ + puts("Addess hashing enabled.\n"); + } +} + unsigned int check_fsl_memctl_config_regs(const fsl_ddr_cfg_regs_t *ddr) { @@ -1392,6 +1400,8 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, set_csn_config_2(i, ddr); }
+ set_ddr_eor(ddr, popts); + #if !defined(CONFIG_FSL_DDR1) set_timing_cfg_0(ddr); #endif diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c index 1d5f3e2..e4805d3 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -341,6 +341,13 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, } }
+ if (hwconfig_sub("fsl_ddr", "addr_hash")) { + if (hwconfig_subarg_cmp("fsl_ddr", "addr_hash", "null")) + popts->addr_hash = 0; + else if (hwconfig_subarg_cmp("fsl_ddr", "addr_hash", "true")) + popts->addr_hash = 1; + } + if (pdimm[0].n_ranks == 4) popts->quad_rank_present = 1;
diff --git a/arch/powerpc/include/asm/fsl_ddr_sdram.h b/arch/powerpc/include/asm/fsl_ddr_sdram.h index 431327e..d576eb8 100644 --- a/arch/powerpc/include/asm/fsl_ddr_sdram.h +++ b/arch/powerpc/include/asm/fsl_ddr_sdram.h @@ -119,6 +119,7 @@ typedef struct fsl_ddr_cfg_regs_s { unsigned int ddr_sr_cntr; unsigned int ddr_sdram_rcw_1; unsigned int ddr_sdram_rcw_2; + unsigned int ddr_eor; } fsl_ddr_cfg_regs_t;
typedef struct memctl_options_partial_s { @@ -156,6 +157,7 @@ typedef struct memctl_options_s { unsigned int memctl_interleaving; unsigned int memctl_interleaving_mode; unsigned int ba_intlv_ctl; + unsigned int addr_hash;
/* Operational mode parameters */ unsigned int ECC_mode; /* Use ECC? */ diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr index 8c37bbe..e108a0d 100644 --- a/doc/README.fsl-ddr +++ b/doc/README.fsl-ddr @@ -71,5 +71,16 @@ The ways to configure the ddr interleaving mode # bank(chip-select) interleaving (cs0+cs1+cs2+cs3) (4x1) setenv hwconfig "fsl_ddr:bank_intlv=cs0_cs1_cs2_cs3"
- The above memory controller interleaving and bank interleaving can be mixed. The syntax is - setenv hwconfig "fsl_ddr:ctlr_intlv=cacheline,bank_intlv=cs0_cs1" +Memory controller address hashing +================================== +If the DDR controller supports address hashing, it can be enabled by hwconfig. + +Syntax is: +hwconfig=fsl_ddr:addr_hash=true + +Combination of hwconfig +======================= +Hwconfig can be combined with multiple parameters, for example, on a supported +platform + +hwconfig=fsl_ddr:addr_hash=true,ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3

From: york yorksun@freescale.com
Enabled registered DIMMs using data from SPD. RDIMMs have registers which need to be configured before using. The register configuration words are stored in SPD byte 60~116 (JEDEC standard No.21-C). Software should read those RCWs and put into DDR controller before initialization.
Signed-off-by: York Sun yorksun@freescale.com --- .../powerpc/cpu/mpc8xxx/ddr/common_timing_params.h | 3 + arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 81 ++++++++------------ arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c | 6 +- .../cpu/mpc8xxx/ddr/lc_common_dimm_params.c | 18 ++++- arch/powerpc/include/asm/fsl_ddr_dimm_params.h | 3 + include/ddr_spd.h | 14 ++++ 6 files changed, 72 insertions(+), 53 deletions(-)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/common_timing_params.h b/arch/powerpc/cpu/mpc8xxx/ddr/common_timing_params.h index 5aea517..06706ed 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/common_timing_params.h +++ b/arch/powerpc/cpu/mpc8xxx/ddr/common_timing_params.h @@ -48,6 +48,9 @@ typedef struct {
unsigned long long total_mem; unsigned long long base_address; + + /* DDR3 RDIMM */ + unsigned char rcw[16]; /* Register Control Word 0-15 */ } common_timing_params_t;
#endif diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index ff0ddd1..b2962d2 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -448,6 +448,35 @@ static void set_timing_cfg_2(fsl_ddr_cfg_regs_t *ddr, debug("FSLDDR: timing_cfg_2 = 0x%08x\n", ddr->timing_cfg_2); }
+/* DDR SDRAM Register Control Word */ +static void set_ddr_sdram_rcw(fsl_ddr_cfg_regs_t *ddr, + const common_timing_params_t *common_dimm) +{ + if (common_dimm->all_DIMMs_registered + && !common_dimm->all_DIMMs_unbuffered) { + ddr->ddr_sdram_rcw_1 = + common_dimm->rcw[0] << 28 | \ + common_dimm->rcw[1] << 24 | \ + common_dimm->rcw[2] << 20 | \ + common_dimm->rcw[3] << 16 | \ + common_dimm->rcw[4] << 12 | \ + common_dimm->rcw[5] << 8 | \ + common_dimm->rcw[6] << 4 | \ + common_dimm->rcw[7]; + ddr->ddr_sdram_rcw_2 = + common_dimm->rcw[8] << 28 | \ + common_dimm->rcw[9] << 24 | \ + common_dimm->rcw[10] << 20 | \ + common_dimm->rcw[11] << 16 | \ + common_dimm->rcw[12] << 12 | \ + common_dimm->rcw[13] << 8 | \ + common_dimm->rcw[14] << 4 | \ + common_dimm->rcw[15]; + debug("FSLDDR: ddr_sdram_rcw_1 = 0x%08x\n", ddr->ddr_sdram_rcw_1); + debug("FSLDDR: ddr_sdram_rcw_2 = 0x%08x\n", ddr->ddr_sdram_rcw_2); + } +} + /* DDR SDRAM control configuration (DDR_SDRAM_CFG) */ static void set_ddr_sdram_cfg(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts, @@ -938,6 +967,7 @@ static void set_ddr_sdram_clk_cntl(fsl_ddr_cfg_regs_t *ddr,
clk_adjust = popts->clk_adjust; ddr->ddr_sdram_clk_cntl = (clk_adjust & 0xF) << 23; + debug("FSLDDR: clk_cntl = 0x%08x\n", ddr->ddr_sdram_clk_cntl); }
/* DDR Initialization Address (DDR_INIT_ADDR) */ @@ -1113,54 +1143,6 @@ static void set_ddr_sr_cntr(fsl_ddr_cfg_regs_t *ddr, unsigned int sr_it) ddr->ddr_sr_cntr = (sr_it & 0xF) << 16; }
-/* DDR SDRAM Register Control Word 1 (DDR_SDRAM_RCW_1) */ -static void set_ddr_sdram_rcw_1(fsl_ddr_cfg_regs_t *ddr) -{ - unsigned int rcw0 = 0; /* RCW0: Register Control Word 0 */ - unsigned int rcw1 = 0; /* RCW1: Register Control Word 1 */ - unsigned int rcw2 = 0; /* RCW2: Register Control Word 2 */ - unsigned int rcw3 = 0; /* RCW3: Register Control Word 3 */ - unsigned int rcw4 = 0; /* RCW4: Register Control Word 4 */ - unsigned int rcw5 = 0; /* RCW5: Register Control Word 5 */ - unsigned int rcw6 = 0; /* RCW6: Register Control Word 6 */ - unsigned int rcw7 = 0; /* RCW7: Register Control Word 7 */ - - ddr->ddr_sdram_rcw_1 = (0 - | ((rcw0 & 0xF) << 28) - | ((rcw1 & 0xF) << 24) - | ((rcw2 & 0xF) << 20) - | ((rcw3 & 0xF) << 16) - | ((rcw4 & 0xF) << 12) - | ((rcw5 & 0xF) << 8) - | ((rcw6 & 0xF) << 4) - | ((rcw7 & 0xF) << 0) - ); -} - -/* DDR SDRAM Register Control Word 2 (DDR_SDRAM_RCW_2) */ -static void set_ddr_sdram_rcw_2(fsl_ddr_cfg_regs_t *ddr) -{ - unsigned int rcw8 = 0; /* RCW0: Register Control Word 8 */ - unsigned int rcw9 = 0; /* RCW1: Register Control Word 9 */ - unsigned int rcw10 = 0; /* RCW2: Register Control Word 10 */ - unsigned int rcw11 = 0; /* RCW3: Register Control Word 11 */ - unsigned int rcw12 = 0; /* RCW4: Register Control Word 12 */ - unsigned int rcw13 = 0; /* RCW5: Register Control Word 13 */ - unsigned int rcw14 = 0; /* RCW6: Register Control Word 14 */ - unsigned int rcw15 = 0; /* RCW7: Register Control Word 15 */ - - ddr->ddr_sdram_rcw_2 = (0 - | ((rcw8 & 0xF) << 28) - | ((rcw9 & 0xF) << 24) - | ((rcw10 & 0xF) << 20) - | ((rcw11 & 0xF) << 16) - | ((rcw12 & 0xF) << 12) - | ((rcw13 & 0xF) << 8) - | ((rcw14 & 0xF) << 4) - | ((rcw15 & 0xF) << 0) - ); -} - static void set_ddr_eor(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts) { if (popts->addr_hash) { @@ -1430,8 +1412,7 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts,
set_ddr_sr_cntr(ddr, sr_it);
- set_ddr_sdram_rcw_1(ddr); - set_ddr_sdram_rcw_2(ddr); + set_ddr_sdram_rcw(ddr, common_dimm);
return check_fsl_memctl_config_regs(ddr); } diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c index d4199ba..29cea53 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c @@ -90,6 +90,7 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd, { unsigned int retval; unsigned int mtb_ps; + int i;
if (spd->mem_type) { if (spd->mem_type != SPD_MEMTYPE_DDR3) { @@ -131,8 +132,11 @@ ddr_compute_dimm_parameters(const ddr3_spd_eeprom_t *spd, case 0x01: /* RDIMM */ case 0x05: /* Mini-RDIMM */ pdimm->registered_dimm = 1; /* register buffered */ + for (i = 0; i < 16; i += 2) { + pdimm->rcw[i] = spd->mod_section.registered.rcw[i/2] & 0x0F; + pdimm->rcw[i+1] = (spd->mod_section.registered.rcw[i/2] >> 4) & 0x0F; + } break; - case 0x02: /* UDIMM */ case 0x03: /* SO-DIMM */ case 0x04: /* Micro-DIMM */ diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c index ce6c148..029e566 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c @@ -76,7 +76,7 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, common_timing_params_t *outpdimm, unsigned int number_of_dimms) { - unsigned int i; + unsigned int i, j;
unsigned int tCKmin_X_ps = 0; unsigned int tCKmax_ps = 0xFFFFFFFF; @@ -98,7 +98,7 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, unsigned int tDQSQ_max_ps = 0; unsigned int tQHS_ps = 0;
- unsigned int temp1, temp2; + unsigned int temp1, temp2, temp3; unsigned int additive_latency = 0; #if !defined(CONFIG_FSL_DDR3) const unsigned int mclk_ps = get_memory_clk_period_ps(); @@ -231,6 +231,20 @@ compute_lowest_common_dimm_parameters(const dimm_params_t *dimm_params, "DIMMs detected!\n"); }
+ temp1 = 0; + if (outpdimm->all_DIMMs_registered) + for (j = 0; j < 16; j++) { + outpdimm->rcw[j] = dimm_params[0].rcw[j]; + for (i = 1; i < number_of_dimms; i++) + if (dimm_params[i].rcw[j] != dimm_params[0].rcw[j]) { + temp3 = 1; + break; + } + } + + if (temp1 != 0) + printf("ERROR: Mix different RDIMM detected!\n"); + #if defined(CONFIG_FSL_DDR3) if (compute_cas_latency_ddr3(dimm_params, outpdimm, number_of_dimms)) return 1; diff --git a/arch/powerpc/include/asm/fsl_ddr_dimm_params.h b/arch/powerpc/include/asm/fsl_ddr_dimm_params.h index 55923e0..be82602 100644 --- a/arch/powerpc/include/asm/fsl_ddr_dimm_params.h +++ b/arch/powerpc/include/asm/fsl_ddr_dimm_params.h @@ -81,6 +81,9 @@ typedef struct dimm_params_s { unsigned int tRTP_ps; /* byte 38, spd->trtp */ unsigned int tDQSQ_max_ps; /* byte 44, spd->tdqsq */ unsigned int tQHS_ps; /* byte 45, spd->tqhs */ + + /* DDR3 RDIMM */ + unsigned char rcw[16]; /* Register Control Word 0-15 */ } dimm_params_t;
extern unsigned int ddr_compute_dimm_parameters( diff --git a/include/ddr_spd.h b/include/ddr_spd.h index 10402c5..710e528 100644 --- a/include/ddr_spd.h +++ b/include/ddr_spd.h @@ -243,6 +243,20 @@ typedef struct ddr3_spd_eeprom_s { unsigned char mod_thickness; /* 62 (Registered) Reference Raw Card Used */ unsigned char ref_raw_card; + /* 63 DIMM Module Attributes */ + unsigned char modu_attr; + /* 64 RDIMM Thermal Heat Spreader Solution */ + unsigned char thermal; + /* 65 Register Manufacturer ID Code, Least Significant Byte */ + unsigned char reg_id_lo; + /* 66 Register Manufacturer ID Code, Most Significant Byte */ + unsigned char reg_id_hi; + /* 67 Register Revision Number */ + unsigned char reg_rev; + /* 68 Register Type */ + unsigned char reg_type; + /* 69-76 RC1,3,5...15 (MS Nibble) / RC0,2,4...14 (LS Nibble) */ + unsigned char rcw[8]; } registered; unsigned char uc[57]; /* 60-116 Module-Specific Section */ } mod_section;

From: york yorksun@freescale.com
Changes for P2020DS DDR applies to other 8xxx platform
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 14 +++++++------- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 1 + 2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index b2962d2..dccb7aa 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c @@ -199,7 +199,7 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr) unsigned char act_pd_exit_mclk; /* Precharge powerdown exit timing (tXP). */ unsigned char pre_pd_exit_mclk; - /* Precharge powerdown exit timing (tAXPD). */ + /* ODT powerdown exit timing (tAXPD). */ unsigned char taxpd_mclk; /* Mode register set cycle time (tMRD). */ unsigned char tmrd_mclk; @@ -211,13 +211,13 @@ static void set_timing_cfg_0(fsl_ddr_cfg_regs_t *ddr) * we use the tXP instead of it. * tXP=max(3nCK, 7.5ns) for DDR3. * spec has not the tAXPD, we use - * tAXPD=8, need design to confirm. + * tAXPD=1, need design to confirm. */ int tXP = max((get_memory_clk_period_ps() * 3), 7500); /* unit=ps */ act_pd_exit_mclk = picos_to_mclk(tXP); /* Mode register MR0[A12] is '1' - fast exit */ pre_pd_exit_mclk = act_pd_exit_mclk; - taxpd_mclk = 8; + taxpd_mclk = 1; tmrd_mclk = 4; /* set the turnaround time */ trwt_mclk = 1; @@ -1031,9 +1031,9 @@ static void set_timing_cfg_5(fsl_ddr_cfg_regs_t *ddr) unsigned int wodt_off = 0; /* Write to ODT off */
#if defined(CONFIG_FSL_DDR3) - rodt_on = 3; /* 2 clocks */ + rodt_on = 2; /* 2 clocks */ rodt_off = 4; /* 4 clocks */ - wodt_on = 2; /* 1 clocks */ + wodt_on = 1; /* 1 clocks */ wodt_off = 4; /* 4 clocks */ #endif
@@ -1106,9 +1106,9 @@ static void set_ddr_wrlvl_cntl(fsl_ddr_cfg_regs_t *ddr, unsigned int wrlvl_en, /* * Write leveling repetition time * at least tWLO + 6 clocks clocks - * we set it 32 + * we set it 64 */ - wrlvl_wlr = 0x5; + wrlvl_wlr = 0x6; /* * Write leveling start time * The value use for the DQS_ADJUST for the first sample diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/options.c b/arch/powerpc/cpu/mpc8xxx/ddr/options.c index e4805d3..774c0e4 100644 --- a/arch/powerpc/cpu/mpc8xxx/ddr/options.c +++ b/arch/powerpc/cpu/mpc8xxx/ddr/options.c @@ -204,6 +204,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered, * meet the tQDSS under different loading. */ popts->wrlvl_en = 1; + popts->zq_en = 1; popts->wrlvl_override = 0; #endif

From: york yorksun@freescale.com
Enabled SPD Enabled DDR2 Enabled hwconfig
Signed-off-by: York Sun yorksun@freescale.com --- Makefile | 1 + board/freescale/p2020ds/ddr.c | 56 ++++++++++++++++++------------------- board/freescale/p2020ds/p2020ds.c | 7 +++- include/configs/P2020DS.h | 6 ++++ 4 files changed, 39 insertions(+), 31 deletions(-)
diff --git a/Makefile b/Makefile index 9cf58bd..82d2c25 100644 --- a/Makefile +++ b/Makefile @@ -1781,6 +1781,7 @@ P2010RDB_config \ P2010RDB_NAND_config \ P2010RDB_SDCARD_config \ P2010RDB_SPIFLASH_config \ +P2020DS_DDR2_config \ P2020RDB_config \ P2020RDB_NAND_config \ P2020RDB_SDCARD_config \ diff --git a/board/freescale/p2020ds/ddr.c b/board/freescale/p2020ds/ddr.c index b9c0cb2..30d640f 100644 --- a/board/freescale/p2020ds/ddr.c +++ b/board/freescale/p2020ds/ddr.c @@ -12,7 +12,7 @@ #include <asm/fsl_ddr_sdram.h> #include <asm/fsl_ddr_dimm_params.h>
-static void get_spd(ddr3_spd_eeprom_t *spd, unsigned char i2c_address) +static void get_spd(generic_spd_eeprom_t *spd, unsigned char i2c_address) { i2c_read(i2c_address, 0, 1, (uchar *)spd, sizeof(ddr3_spd_eeprom_t)); } @@ -22,7 +22,7 @@ unsigned int fsl_ddr_get_mem_data_rate(void) return get_ddr_freq(0); }
-void fsl_ddr_get_spd(ddr3_spd_eeprom_t *ctrl_dimms_spd, +void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, unsigned int ctrl_num) { unsigned int i; @@ -51,27 +51,26 @@ typedef struct { * cpo 2-0x1E (30) */
- -/* XXX: these values need to be checked for all interleaving modes. */ -/* XXX: No reliable dual-rank 800 MHz setting has been found. It may - * seem reliable, but errors will appear when memory intensive - * program is run. */ -/* XXX: Single rank at 800 MHz is OK. */ const board_specific_parameters_t board_specific_parameters[][20] = { { /* memory controller 0 */ /* lo| hi| num| clk| cpo|wrdata|2T */ /* mhz| mhz|ranks|adjst| | delay| */ - { 0, 333, 2, 6, 7, 3, 0}, - {334, 400, 2, 6, 9, 3, 0}, - {401, 549, 2, 6, 11, 3, 0}, - {550, 680, 2, 1, 10, 5, 0}, - {681, 850, 2, 1, 12, 5, 1}, - { 0, 333, 1, 6, 7, 3, 0}, - {334, 400, 1, 6, 9, 3, 0}, - {401, 549, 1, 6, 11, 3, 0}, - {550, 680, 1, 1, 10, 5, 0}, - {681, 850, 1, 1, 12, 5, 0} +#ifdef CONFIG_FSL_DDR2 + { 0, 333, 2, 4, 0x1f, 2, 0}, + {334, 400, 2, 4, 0x1f, 2, 0}, + {401, 549, 2, 4, 0x1f, 2, 0}, + {550, 680, 2, 4, 0x1f, 3, 0}, + {681, 850, 2, 4, 0x1f, 4, 0}, + { 0, 333, 1, 4, 0x1f, 2, 0}, + {334, 400, 1, 4, 0x1f, 2, 0}, + {401, 549, 1, 4, 0x1f, 2, 0}, + {550, 680, 1, 4, 0x1f, 3, 0}, + {681, 850, 1, 4, 0x1f, 4, 0} +#else + { 0, 850, 2, 4, 0x1f, 4, 0}, + { 0, 850, 1, 4, 0x1f, 4, 0} +#endif }, };
@@ -92,18 +91,8 @@ void fsl_ddr_board_options(memctl_options_t *popts, * odt_wr_cfg to 3 for the even CS, 0 for the odd CS. */ for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { - if (i&1) { /* odd CS */ popts->cs_local_opts[i].odt_rd_cfg = 0; - popts->cs_local_opts[i].odt_wr_cfg = 0; - } else { /* even CS */ - if (CONFIG_DIMM_SLOTS_PER_CTLR == 1) { - popts->cs_local_opts[i].odt_rd_cfg = 0; - popts->cs_local_opts[i].odt_wr_cfg = 4; - } else if (CONFIG_DIMM_SLOTS_PER_CTLR == 2) { - popts->cs_local_opts[i].odt_rd_cfg = 3; - popts->cs_local_opts[i].odt_wr_cfg = 3; - } - } + popts->cs_local_opts[i].odt_wr_cfg = 1; }
/* Get clk_adjust, cpo, write_data_delay,2T, according to the board ddr @@ -127,4 +116,13 @@ void fsl_ddr_board_options(memctl_options_t *popts, * - number of DIMMs installed */ popts->half_strength_driver_enable = 0; + popts->wrlvl_en = 1; + /* Write leveling override */ + popts->wrlvl_override = 1; + popts->wrlvl_sample = 0xa; + popts->wrlvl_start = 0x7; + /* Rtt and Rtt_WR override */ + popts->rtt_override = 1; + popts->rtt_override_value = DDR3_RTT_120_OHM; + popts->rtt_wr_override_value = 0; /* Rtt_WR= dynamic ODT off */ } diff --git a/board/freescale/p2020ds/p2020ds.c b/board/freescale/p2020ds/p2020ds.c index 3fd1b34..608ff91 100644 --- a/board/freescale/p2020ds/p2020ds.c +++ b/board/freescale/p2020ds/p2020ds.c @@ -69,13 +69,16 @@ int checkboard(void) return 0; }
+const char *board_hwconfig = "foo:bar=baz"; +const char *cpu_hwconfig = "foo:bar=baz"; + phys_size_t initdram(int board_type) { phys_size_t dram_size = 0;
puts("Initializing....");
-#ifdef CONFIG_SPD_EEPROM +#ifdef CONFIG_DDR_SPD dram_size = fsl_ddr_sdram(); #else dram_size = fixed_sdram(); @@ -94,7 +97,7 @@ phys_size_t initdram(int board_type) return dram_size; }
-#if !defined(CONFIG_SPD_EEPROM) +#if !defined(CONFIG_DDR_SPD) /* * Fixed sdram init -- doesn't use serial presence detect. */ diff --git a/include/configs/P2020DS.h b/include/configs/P2020DS.h index e70c673..ee21d8b 100644 --- a/include/configs/P2020DS.h +++ b/include/configs/P2020DS.h @@ -92,7 +92,11 @@
/* DDR Setup */ #define CONFIG_VERY_BIG_RAM +#ifdef CONFIG_MK_DDR2 +#define CONFIG_FSL_DDR2 +#else #define CONFIG_FSL_DDR3 1 +#endif #undef CONFIG_FSL_DDR_INTERACTIVE
/* ECC will be enabled based on perf_mode environment variable */ @@ -109,6 +113,7 @@ #define CONFIG_CHIP_SELECTS_PER_CTRL 2
/* I2C addresses of SPD EEPROMs */ +#define CONFIG_DDR_SPD #define CONFIG_SYS_SPD_BUS_NUM 0 /* SPD EEPROM located on I2C bus 0 */ #define SPD_EEPROM_ADDRESS1 0x51 /* CTLR 0 DIMM 0 */
@@ -228,6 +233,7 @@
#define CONFIG_BOARD_EARLY_INIT_R /* call board_early_init_r function */
+#define CONFIG_HWCONFIG /* enable hwconfig */ #define CONFIG_FSL_NGPIXIS /* use common ngPIXIS code */
#ifdef CONFIG_FSL_NGPIXIS

From: york yorksun@freescale.com
If enabled in config file and hwconfig, the memory test is performed after DDR initialization when U-boot stills runs in flash and cache. Whole memory is testable. However, only the low 2GB space is mapped for DDR. The testing is conducted in the 2GB window and uses TLBs to map the higher physical address into the 2GB window if the total memory is more than 2GB. After the testing, DDR is remapped with up to 2GB memory from the lowest address.
Memory testing has different patterns which may be improved later.
If memory test fails, DDR DIMM SPD and DDR controller registers are dumped. All zero values are omitted for better viewing.
A worker function __setup_ddr_tlbs() is introduced to implemente more control on physical address mapping.
Signed-off-by: York Sun yorksun@freescale.com --- arch/powerpc/cpu/mpc85xx/Makefile | 2 + arch/powerpc/cpu/mpc85xx/memtest.c | 369 ++++++++++++++++++++++++++++++++++++ arch/powerpc/cpu/mpc85xx/tlb.c | 16 +- doc/README.fsl-ddr | 39 ++++ 4 files changed, 420 insertions(+), 6 deletions(-) create mode 100644 arch/powerpc/cpu/mpc85xx/memtest.c
diff --git a/arch/powerpc/cpu/mpc85xx/Makefile b/arch/powerpc/cpu/mpc85xx/Makefile index 4ee0e9a..c0fc9ba 100644 --- a/arch/powerpc/cpu/mpc85xx/Makefile +++ b/arch/powerpc/cpu/mpc85xx/Makefile @@ -60,6 +60,8 @@ COBJS-$(CONFIG_P2010) += ddr-gen3.o COBJS-$(CONFIG_P2020) += ddr-gen3.o COBJS-$(CONFIG_PPC_P4080) += ddr-gen3.o
+COBJS-${CONFIG_SYS_DRAM_TEST} += memtest.o + COBJS-$(CONFIG_CPM2) += ether_fcc.o COBJS-$(CONFIG_OF_LIBFDT) += fdt.o COBJS-$(CONFIG_MP) += mp.o diff --git a/arch/powerpc/cpu/mpc85xx/memtest.c b/arch/powerpc/cpu/mpc85xx/memtest.c new file mode 100644 index 0000000..7ad3326 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/memtest.c @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * York Sun yorksun@freescale.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <hwconfig.h> +#include <asm/processor.h> +#include <asm/mmu.h> +#include <asm/fsl_ddr_sdram.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Board-specific functions defined in each board's ddr.c */ +void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num); +void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn, + phys_addr_t *rpn); +unsigned int __setup_ddr_tlbs(phys_addr_t p_addr, unsigned int memsize_in_meg); + +#define PATTERN(pattern, address) (pattern == 0x12345678 ? address : pattern) + +#define TOTAL_PROGRESS_DOTS 45 +#define TOTAL_PROGRESS_NUMBERS 9 +#define PROGRESS_DOTS_PER_NUMBER (TOTAL_PROGRESS_DOTS/TOTAL_PROGRESS_NUMBERS) +#define TEST_SHOW_PROGRESS(scale, dots, digit, dots_sub) \ +{ \ + dots -= (dots_sub); \ + if ((scale > 0) && (dots <= 0)) { \ + if ((digit % PROGRESS_DOTS_PER_NUMBER) == 0) \ + printf("%d", digit / PROGRESS_DOTS_PER_NUMBER); \ + else \ + putc('.'); \ + digit--; \ + dots += (scale); \ + } \ +} + +#if defined(CONFIG_SYS_DRAM_TEST) +void dump_spd_ddr_reg(void) +{ + int i, j, k, m; + u8 *p_8; + u32 *p_32; + ccsr_ddr_t *ddr[CONFIG_NUM_DDR_CONTROLLERS]; + generic_spd_eeprom_t + spd[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR]; + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + fsl_ddr_get_spd(spd[i], i); + } + puts("SPD data of all dimms (zero vaule is omitted)...\n"); + puts("Byte (hex) "); + k = 1; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) + printf("Dimm%d ", k++); + puts("\n"); + for (k = 0; k < sizeof(generic_spd_eeprom_t); k++) { + m = 0; + printf("%3d (0x%02x) ", k, k); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + p_8 = (u8 *) &spd[i][j]; + if (p_8[k]) { + printf("0x%02x ", p_8[k]); + m++; + } else + puts(" "); + } + } + if (m) + puts("\n"); + else + puts("\r"); + } + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + switch (i) { + case 0: + ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR; + break; +#ifdef CONFIG_SYS_MPC85xx_DDR2_ADDR + case 1: + ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR; + break; +#endif + default: + printf("%s unexpected controller number = %u\n", + __FUNCTION__, i); + return; + } + } + printf("DDR registers dump for all controllers " + "(zero vaule is omitted)...\n"); + puts("Offset (hex) "); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + printf(" Base + 0x%04x", (u32)ddr[i] & 0xFFFF); + puts("\n"); + for (k = 0; k < sizeof(ccsr_ddr_t)/4; k++) { + m = 0; + printf("%6d (0x%04x)", k * 4, k * 4); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + p_32 = (u32 *) ddr[i]; + if (p_32[k]) { + printf(" 0x%08x", p_32[k]); + m++; + } else + puts(" "); + } + if (m) + puts("\n"); + else + puts("\r"); + } + puts("\n"); +} + +#define MODULOMASK 0x3F +#define MODULOX 16 +int pattern_test(u32 start_addr, u32 size, u32 pattern, u64 offset) +{ + const int MaxError = 10; + volatile u32 *p; + u32 ptr, buffer, end_addr = start_addr + size; + int error = 0; + int digit, dots; + int scale; + + puts("Pattern: Moving Inversions "); + if (pattern == 0x12345678) + puts("Address March\n"); + else + printf("0x%08x\n", pattern); + + scale = (int)(((size >> 20) + TOTAL_PROGRESS_DOTS - 1) / + TOTAL_PROGRESS_DOTS); + digit = TOTAL_PROGRESS_DOTS; + dots = 0; + for (p = (volatile u32 *)(start_addr & 0xfffffffc); + p < (volatile u32 *)(end_addr & 0xfffffffc); p++) { + *p = PATTERN(pattern, (u32)p); + if (((u32)p % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); + } + puts("Filled with pattern.\n"); + digit = TOTAL_PROGRESS_DOTS; + dots = 0; + for (ptr = (start_addr & 0xfffffffc); + ptr < (end_addr & 0xfffffffc); ptr += sizeof(u32)) { + p = (volatile u32 *) ptr; + buffer = *p; + if (buffer != PATTERN(pattern, ptr)) { + error++; + printf("\nAddress 0x%08llx, Write 0x%08x, Read 0x%08x", + offset + ptr, PATTERN(pattern, ptr), buffer); + if (error > MaxError) + break; + } + *p = ~PATTERN(pattern, ptr); + if ((ptr % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); + } + if (error == 0) + puts("Verified and written with complement.\n"); + else { + puts("\nFailed!\n\n"); + return error; + } + digit = TOTAL_PROGRESS_DOTS; + dots = 0; + for (ptr = ((end_addr - 1) & 0xfffffffc); + ptr > (start_addr & 0xfffffffc); ptr -= sizeof(u32)) { + p = (volatile u32 *) ptr; + buffer = *p; + if (buffer != ~PATTERN(pattern, ptr)) { + error++; + printf("\nAddress 0x%08llx, Write 0x%08x, Read 0x%08x", + offset + ptr, ~PATTERN(pattern, ptr), buffer); + if (error > MaxError) + break; + } + *p = PATTERN(pattern, ptr); + if ((ptr % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); + } + if (error == 0) + puts("Verified OK.\n\n"); + else { + puts("\nFailed!\n\n"); + return error; + } + + printf("Pattern: Modulo-%d ", MODULOX); + if (pattern == 0x12345678) + puts("Address March\n"); + else + printf(" 0x%08x\n", pattern); + digit = TOTAL_PROGRESS_DOTS; + dots = 0; + for (ptr = (start_addr & 0xfffffffc); + ptr < (end_addr & 0xfffffffc); ptr += sizeof(u32)) { + p = (volatile u32 *) ptr; + if (ptr & MODULOMASK) + *p = PATTERN(pattern, ptr); + else + *p = ~PATTERN(pattern, ptr); + if (ptr % (1 << 20) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); + } + puts("Filled with pattern.\n"); + scale = (int)(((size / MODULOX / sizeof(u32)) + TOTAL_PROGRESS_DOTS - 1) / + TOTAL_PROGRESS_DOTS); + digit = TOTAL_PROGRESS_DOTS; + dots = 0; + for (ptr = (start_addr & 0xfffffffc); + ptr < (end_addr & 0xfffffffc); ptr += sizeof(u32)) { + if (ptr & MODULOMASK) + break; + } + for (; ptr < (end_addr & 0xfffffffc); ptr += MODULOX * sizeof(u32)) { + p = (volatile u32 *) ptr; + buffer = *p; + if (buffer != PATTERN(pattern, ptr)) { + error++; + printf("\nAddress 0x%08llx, Write 0x%08x, Read 0x%08x", + ptr + offset, PATTERN(pattern, ptr), buffer); + if (error > MaxError) + break; + } + TEST_SHOW_PROGRESS(scale, dots, digit, 1); + } + if (error == 0) + puts("OK.\n\n"); + else + puts("\nFailed!\n\n"); + return error; +} + +/* + * This funciton is called before U-boot relocates itself to RAM + * The L1 cache should be locked and L2 cache is not enabled yet + */ +int __testdram(phys_addr_t p_addr, u32 size, int simple_test) +{ + + u32 vstart = CONFIG_SYS_DDR_SDRAM_BASE; + u32 vend = vstart + size; + int failed = 0; + unsigned long epn; + u32 tsize, valid, ptr; + phys_addr_t rpn = 0; + int ddr_esel; + + puts("DDR memory testing...\n"); + size = min(size, CONFIG_MAX_MEM_MAPPED); + ptr = vstart; + while (ptr < vend) { + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + disable_tlb(ddr_esel); + } + ptr += TSIZE_TO_BYTES(tsize); + } + /* Setup new tlb to cover the physical address */ + __setup_ddr_tlbs(p_addr, size>>20); + + ptr = vstart; + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + } else { + printf("TLB error in function %s\n", __FUNCTION__); + return -1; + } + + printf("Testing 0x%08llx - 0x%08llx\n", + (u64)vstart + rpn, (u64)vstart + rpn + size - 1); + + failed = pattern_test(vstart, size, 0, rpn); + if (!simple_test) { + if (failed == 0) + failed = pattern_test(vstart, size, 0xaaaaaaaa, rpn); + if (failed == 0) + pattern_test(vstart, size, 0x55555555, rpn); + if (failed == 0) + failed = pattern_test(vstart, size, 0xffffffff, rpn); + if (failed == 0) + failed = pattern_test(vstart, size, 0x12345678, rpn); + } + if (failed != 0) + dump_spd_ddr_reg(); + + /* disable the TLBs for this testing */ + ptr = vstart; + while (ptr < vend) { + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + disable_tlb(ddr_esel); + } + ptr += TSIZE_TO_BYTES(tsize); + } + + return failed; +} + +int testdram(void) +{ + int simple_test, failed = 0; + phys_addr_t test_cap, p_addr = CONFIG_SYS_DDR_SDRAM_BASE; + phys_size_t p_size; + if (hwconfig("memtest")) { + if (hwconfig_arg_cmp("memtest", "null") || \ + (!hwconfig_arg_cmp("memtest", "true") && \ + !hwconfig_arg_cmp("memtest", "simple"))) { + puts("memtest is not enabled in hwconfig, skipped.\n"); + return 0; + } + simple_test = hwconfig_arg_cmp("memtest", "simple"); + p_size = min(gd->ram_size, CONFIG_MAX_MEM_MAPPED); +#if !defined(CONFIG_PHYS_64BIT) || \ + !defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS) || \ + (CONFIG_SYS_INIT_RAM_ADDR_PHYS < 0x100000000ull) + if (gd->ram_size > CONFIG_MAX_MEM_MAPPED) { + puts("Cannot test more than "); + print_size(CONFIG_MAX_MEM_MAPPED, + " without proper 36BIT support.\n"); + } + test_cap = p_size; +#else + test_cap = gd->ram_size; +#endif + while (p_addr < test_cap - 1) { + if (__testdram(p_addr, (u32)p_size, simple_test) != 0) + failed++; + p_addr += p_size; + p_size = min(test_cap - p_addr, CONFIG_MAX_MEM_MAPPED); + } + if (failed) + printf("\nWarning: Memory test failed." + " Software may not run as expected.\n"); + puts("Remap DDR "); + setup_ddr_tlbs(gd->ram_size>>20); + puts("\n"); + } else + puts("memtest is not set in hwconfig, skipped.\n"); + return 0; +} +#endif diff --git a/arch/powerpc/cpu/mpc85xx/tlb.c b/arch/powerpc/cpu/mpc85xx/tlb.c index f2833a5..019fab7 100644 --- a/arch/powerpc/cpu/mpc85xx/tlb.c +++ b/arch/powerpc/cpu/mpc85xx/tlb.c @@ -245,7 +245,8 @@ void init_addr_map(void) } #endif
-unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) +unsigned int +__setup_ddr_tlbs(phys_addr_t p_addr, unsigned int memsize_in_meg) { int i; unsigned int tlb_size; @@ -275,21 +276,24 @@ unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg)
tlb_size = (camsize - 10) / 2;
- set_tlb(1, ram_tlb_address, ram_tlb_address, + set_tlb(1, ram_tlb_address, p_addr, MAS3_SX|MAS3_SW|MAS3_SR, 0, 0, ram_tlb_index, tlb_size, 1);
size -= 1ULL << camsize; memsize -= 1ULL << camsize; ram_tlb_address += 1UL << camsize; + p_addr += 1UL << camsize; }
if (memsize) print_size(memsize, " left unmapped\n"); - - /* - * Confirm that the requested amount of memory was mapped. - */ return memsize_in_meg; } + +unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) +{ + return + __setup_ddr_tlbs(CONFIG_SYS_DDR_SDRAM_BASE, memsize_in_meg); +} #endif /* !CONFIG_NAND_SPL */ diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr index e108a0d..f5deb4f 100644 --- a/doc/README.fsl-ddr +++ b/doc/README.fsl-ddr @@ -78,6 +78,45 @@ If the DDR controller supports address hashing, it can be enabled by hwconfig. Syntax is: hwconfig=fsl_ddr:addr_hash=true
+ +Memory testing options for mpc85xx +================================== +1. Memory test can be done one U-boot prompt comes up using mtest, or +2. Memory test can be done with a built-in function, activated at compile time + and by hwconfig. + In order to enable the built-in memory test, CONFIG_SYS_DRAM_TEST needs to be + defined in board configuraiton header file. Hwconfig is also required. To test + memory bigger than 2GB, 36BIT support is needed. Memory is tested within a 2GB + window. TLBs are used to map the virtual 2GB window to physical address so that + all physical memory can be tested. + + Syntax of hwconfig + hwconfig=memtest:true or + hwconfig=memtest:simple + + The "simple" test uses one pattern and "true" uses more patterns. The testing + patterns include moving inversions and modulo-16. + +Moving inversions +================= +Moving inversions test takes a pattern (eg. 0x00000000) and fills the memory with +the pattern for the first round. The software then takes the second round to check +each address against the pattern, if matched the complement data is written back +and software moves on to next address, all the way to the end. In the third round, +software checks the complement of pattern of each address. + +Modulo-16 +========= +Modulo-16 is a test for selected address. In the first round, software fills the +memory with a pattern and the complement of the pattern every 16-sizeof(int). In +the second round, software checks the complement of the pattern at selected address. + +Patterns +======== +Built-in patterns are 0x00000000, 0xAAAAAAAA, 0x55555555, 0xFFFFFFFF and Address +Marching (i.e. the address of the cell). + + Combination of hwconfig ======================= Hwconfig can be combined with multiple parameters, for example, on a supported

Dear Kumar Gala,
In message 1279120502-6289-8-git-send-email-galak@kernel.crashing.org you wrote:
From: york yorksun@freescale.com
If enabled in config file and hwconfig, the memory test is performed after DDR initialization when U-boot stills runs in flash and cache. Whole memory is testable. However, only the low 2GB space is mapped for DDR. The testing is conducted in the 2GB window and uses TLBs to map the higher physical address into the 2GB window if the total memory is more than 2GB. After the testing, DDR is remapped with up to 2GB memory from the lowest address.
Memory testing has different patterns which may be improved later.
If memory test fails, DDR DIMM SPD and DDR controller registers are dumped. All zero values are omitted for better viewing.
A worker function __setup_ddr_tlbs() is introduced to implemente more control on physical address mapping.
Signed-off-by: York Sun yorksun@freescale.com
arch/powerpc/cpu/mpc85xx/Makefile | 2 + arch/powerpc/cpu/mpc85xx/memtest.c | 369 ++++++++++++++++++++++++++++++++++++
NAK.
Please do not reinvent the wheel and add yet another meory test. Use one of the existing memory tests we already have - post/drivers/memory.c comes to mind.
Best regards,
Wolfgang Denk

On Wed, Jul 14, 2010 at 3:16 PM, Wolfgang Denk wd@denx.de wrote:
NAK.
Please do not reinvent the wheel and add yet another meory test. Use one of the existing memory tests we already have - post/drivers/memory.c comes to mind.
That code is not capable of testing more than 2GB of RAM. It assumes that memory has already been initialized, but on PowerPC parts, we only ever map 2GB of DDR. We need a memory test that covers all of DDR, but that requries PowerPC-specific code to create sliding TLB windows during the memory test.

Dear Timur Tabi,
In message AANLkTim6yjF6ORogtqE0vqiVqZqxu-EkkUhDTmJMgPqu@mail.gmail.com you wrote:
NAK.
Please do not reinvent the wheel and add yet another meory test. Use one of the existing memory tests we already have - post/drivers/memory.c comes to mind.
That code is not capable of testing more than 2GB of RAM. It assumes that memory has already been initialized, but on PowerPC parts, we only ever map 2GB of DDR. We need a memory test that covers all of DDR, but that requries PowerPC-specific code to create sliding TLB windows during the memory test.
Then please extend the existing code and add the missing features.
We already have too many different implementations of a memory test in U-Boot, and I will not accept adding yet another one.
Best regards,
Wolfgang Denk

Wolfgang,
On Thu, 2010-07-15 at 11:07 +0200, Wolfgang Denk wrote:
Dear Timur Tabi,
In message AANLkTim6yjF6ORogtqE0vqiVqZqxu-EkkUhDTmJMgPqu@mail.gmail.com you wrote:
NAK.
Please do not reinvent the wheel and add yet another meory test. Use one of the existing memory tests we already have - post/drivers/memory.c comes to mind.
That code is not capable of testing more than 2GB of RAM. It assumes that memory has already been initialized, but on PowerPC parts, we only ever map 2GB of DDR. We need a memory test that covers all of DDR, but that requries PowerPC-specific code to create sliding TLB windows during the memory test.
Then please extend the existing code and add the missing features.
We already have too many different implementations of a memory test in U-Boot, and I will not accept adding yet another one.
I can reuse your testing code but have to move the desired code out of memory.c file to avoid the need for CONFIG_POST and CONFIG_SYS_POST_MEMORY. I also add a progress indicator. My testing target is 2GB at a time, up to physically memory size which is easily over 8GB. Without progress indicator, it feels hung when it is actually running.
Please take a look at the patch below.
Regards,
York
From 58002b8f549ca114583b72f541032fb106b6bf66 Mon Sep 17 00:00:00 2001
From: York Sun yorksun@freescale.com Date: Wed, 23 Jun 2010 11:18:48 -0500 Subject: [PATCH] Add memory test feature for mpc85xx.
Reuse memory test code for POST. Move the actually pattern generator and testing out of POST.
If enabled in config file and hwconfig, the memory test is performed after DDR initialization when U-boot stills runs in flash and cache. Whole memory is testable. However, only the low 2GB space is mapped for DDR. The testing is conducted in the 2GB window and uses TLBs to map the higher physical address into the 2GB window if the total memory is more than 2GB. After the testing, DDR is remapped with up to 2GB memory from the lowest address.
If memory test fails, DDR DIMM SPD and DDR controller registers are dumped. All zero values are omitted for better viewing.
A worker function __setup_ddr_tlbs() is introduced to implemente more control on physical address mapping.
Signed-off-by: York Sun yorksun@freescale.com ---
This patch is for discussion where to put the memory test code.
arch/powerpc/cpu/mpc85xx/Makefile | 2 + arch/powerpc/cpu/mpc85xx/memtest.c | 220 +++++++++++++ arch/powerpc/cpu/mpc85xx/tlb.c | 16 +- doc/README.fsl-ddr | 13 +- post/drivers/Makefile | 2 +- post/drivers/memory.c | 426 +------------------------- post/drivers/{memory.c => memtest_pattern.c} | 147 ++++++--- 7 files changed, 346 insertions(+), 480 deletions(-) create mode 100644 arch/powerpc/cpu/mpc85xx/memtest.c copy post/drivers/{memory.c => memtest_pattern.c} (79%)
diff --git a/arch/powerpc/cpu/mpc85xx/Makefile b/arch/powerpc/cpu/mpc85xx/Makefile index 2c12ef2..383de6a 100644 --- a/arch/powerpc/cpu/mpc85xx/Makefile +++ b/arch/powerpc/cpu/mpc85xx/Makefile @@ -62,6 +62,8 @@ COBJS-$(CONFIG_PPC_P3041) += ddr-gen3.o COBJS-$(CONFIG_PPC_P4080) += ddr-gen3.o COBJS-$(CONFIG_PPC_P5020) += ddr-gen3.o
+COBJS-${CONFIG_SYS_DRAM_TEST} += memtest.o $(TOPDIR)/post/drivers/memtest_pattern.o + COBJS-$(CONFIG_CPM2) += ether_fcc.o COBJS-$(CONFIG_OF_LIBFDT) += fdt.o COBJS-$(CONFIG_FSL_CORENET) += liodn.o liodn_r1.o diff --git a/arch/powerpc/cpu/mpc85xx/memtest.c b/arch/powerpc/cpu/mpc85xx/memtest.c new file mode 100644 index 0000000..b873136 --- /dev/null +++ b/arch/powerpc/cpu/mpc85xx/memtest.c @@ -0,0 +1,220 @@ +/* + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * York Sun yorksun@freescale.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <hwconfig.h> +#include <asm/processor.h> +#include <asm/mmu.h> +#include <asm/fsl_ddr_sdram.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Board-specific functions defined in each board's ddr.c */ +void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd, + unsigned int ctrl_num); +void read_tlbcam_entry(int idx, u32 *valid, u32 *tsize, unsigned long *epn, + phys_addr_t *rpn); +unsigned int __setup_ddr_tlbs(phys_addr_t p_addr, unsigned int memsize_in_meg); + +int memory_post_tests (unsigned long start, unsigned long size); + +#if defined(CONFIG_SYS_DRAM_TEST) +void dump_spd_ddr_reg(void) +{ + int i, j, k, m; + u8 *p_8; + u32 *p_32; + ccsr_ddr_t *ddr[CONFIG_NUM_DDR_CONTROLLERS]; + generic_spd_eeprom_t + spd[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR]; + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + fsl_ddr_get_spd(spd[i], i); + + puts("SPD data of all dimms (zero vaule is omitted)...\n"); + puts("Byte (hex) "); + k = 1; + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) + printf("Dimm%d ", k++); + puts("\n"); + for (k = 0; k < sizeof(generic_spd_eeprom_t); k++) { + m = 0; + printf("%3d (0x%02x) ", k, k); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) { + p_8 = (u8 *) &spd[i][j]; + if (p_8[k]) { + printf("0x%02x ", p_8[k]); + m++; + } else + puts(" "); + } + } + if (m) + puts("\n"); + else + puts("\r"); + } + + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + switch (i) { + case 0: + ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR_ADDR; + break; +#ifdef CONFIG_SYS_MPC85xx_DDR2_ADDR + case 1: + ddr[i] = (void *)CONFIG_SYS_MPC85xx_DDR2_ADDR; + break; +#endif + default: + printf("%s unexpected controller number = %u\n", + __func__, i); + return; + } + } + printf("DDR registers dump for all controllers " + "(zero vaule is omitted)...\n"); + puts("Offset (hex) "); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) + printf(" Base + 0x%04x", (u32)ddr[i] & 0xFFFF); + puts("\n"); + for (k = 0; k < sizeof(ccsr_ddr_t)/4; k++) { + m = 0; + printf("%6d (0x%04x)", k * 4, k * 4); + for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) { + p_32 = (u32 *) ddr[i]; + if (p_32[k]) { + printf(" 0x%08x", p_32[k]); + m++; + } else + puts(" "); + } + if (m) + puts("\n"); + else + puts("\r"); + } + puts("\n"); +} + +/* + * This funciton is called before U-boot relocates itself to RAM + * The L1 cache should be locked and L2 cache is not enabled yet + */ +int __testdram(phys_addr_t p_addr, u32 size) +{ + + u32 vstart = CONFIG_SYS_DDR_SDRAM_BASE; + u32 vend = vstart + size; + int failed = 0; + unsigned long epn; + u32 tsize, valid, ptr; + phys_addr_t rpn = 0; + int ddr_esel; + + puts("DDR memory testing...\n"); + size = min(size, CONFIG_MAX_MEM_MAPPED); + ptr = vstart; + while (ptr < vend) { + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + disable_tlb(ddr_esel); + } + ptr += TSIZE_TO_BYTES(tsize); + } + /* Setup new tlb to cover the physical address */ + __setup_ddr_tlbs(p_addr, size>>20); + + ptr = vstart; + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + } else { + printf("TLB error in function %s\n", __func__); + return -1; + } + + printf("Testing 0x%08llx - 0x%08llx\n", + (u64)vstart + rpn, (u64)vstart + rpn + size - 1); + + failed = memory_post_tests(vstart, size); + if (failed != 0) + dump_spd_ddr_reg(); + + /* disable the TLBs for this testing */ + ptr = vstart; + while (ptr < vend) { + ddr_esel = find_tlb_idx((void *)ptr, 1); + if (ddr_esel != -1) { + read_tlbcam_entry(ddr_esel, &valid, &tsize, &epn, &rpn); + disable_tlb(ddr_esel); + } + ptr += TSIZE_TO_BYTES(tsize); + } + + return failed; +} + +int testdram(void) +{ + int failed = 0; + phys_addr_t test_cap, p_addr = CONFIG_SYS_DDR_SDRAM_BASE; + phys_size_t p_size; + if (hwconfig("memtest")) { + if (hwconfig_arg_cmp("memtest", "null") || \ + (!hwconfig_arg_cmp("memtest", "true"))) { + puts("memtest is not enabled in hwconfig, skipped.\n"); + return 0; + } + p_size = min(gd->ram_size, CONFIG_MAX_MEM_MAPPED); +#if !defined(CONFIG_PHYS_64BIT) || \ + !defined(CONFIG_SYS_INIT_RAM_ADDR_PHYS) || \ + (CONFIG_SYS_INIT_RAM_ADDR_PHYS < 0x100000000ull) + if (gd->ram_size > CONFIG_MAX_MEM_MAPPED) { + puts("Cannot test more than "); + print_size(CONFIG_MAX_MEM_MAPPED, + " without proper 36BIT support.\n"); + } + test_cap = p_size; +#else + test_cap = gd->ram_size; +#endif + while (p_addr < test_cap - 1) { + if (__testdram(p_addr, (u32)p_size) != 0) + failed++; + p_addr += p_size; + p_size = min(test_cap - p_addr, CONFIG_MAX_MEM_MAPPED); + } + if (failed) + printf("\nWarning: Memory test failed." + " Software may not run as expected.\n"); + puts("Remap DDR "); + setup_ddr_tlbs(gd->ram_size>>20); + puts("\n"); + } else + puts("memtest is not set in hwconfig, skipped.\n"); + return 0; +} +#endif diff --git a/arch/powerpc/cpu/mpc85xx/tlb.c b/arch/powerpc/cpu/mpc85xx/tlb.c index f2833a5..019fab7 100644 --- a/arch/powerpc/cpu/mpc85xx/tlb.c +++ b/arch/powerpc/cpu/mpc85xx/tlb.c @@ -245,7 +245,8 @@ void init_addr_map(void) } #endif
-unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) +unsigned int +__setup_ddr_tlbs(phys_addr_t p_addr, unsigned int memsize_in_meg) { int i; unsigned int tlb_size; @@ -275,21 +276,24 @@ unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg)
tlb_size = (camsize - 10) / 2;
- set_tlb(1, ram_tlb_address, ram_tlb_address, + set_tlb(1, ram_tlb_address, p_addr, MAS3_SX|MAS3_SW|MAS3_SR, 0, 0, ram_tlb_index, tlb_size, 1);
size -= 1ULL << camsize; memsize -= 1ULL << camsize; ram_tlb_address += 1UL << camsize; + p_addr += 1UL << camsize; }
if (memsize) print_size(memsize, " left unmapped\n"); - - /* - * Confirm that the requested amount of memory was mapped. - */ return memsize_in_meg; } + +unsigned int setup_ddr_tlbs(unsigned int memsize_in_meg) +{ + return + __setup_ddr_tlbs(CONFIG_SYS_DDR_SDRAM_BASE, memsize_in_meg); +} #endif /* !CONFIG_NAND_SPL */ diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr index e108a0d..4c528ac 100644 --- a/doc/README.fsl-ddr +++ b/doc/README.fsl-ddr @@ -78,9 +78,20 @@ If the DDR controller supports address hashing, it can be enabled by hwconfig. Syntax is: hwconfig=fsl_ddr:addr_hash=true
+ +Memory testing options for mpc85xx +================================== +1. Memory test can be done one U-boot prompt comes up using mtest, or +2. Memory test can be done with a built-in function, activated at compile time + and by hwconfig. + In order to enable the built-in memory test, CONFIG_SYS_DRAM_TEST needs to be + defined in board configuraiton header file. Hwconfig is also required. To test + memory bigger than 2GB, 36BIT support is needed. Memory is tested within a 2GB + Combination of hwconfig ======================= Hwconfig can be combined with multiple parameters, for example, on a supported platform
-hwconfig=fsl_ddr:addr_hash=true,ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3 +hwconfig=fsl_ddr:addr_hash=true,ctlr_intlv=cacheline,bank_intlv=cs0_cs1_cs2_cs3,;memtest=true + diff --git a/post/drivers/Makefile b/post/drivers/Makefile index 0b6cdf5..6f67b9c 100644 --- a/post/drivers/Makefile +++ b/post/drivers/Makefile @@ -24,6 +24,6 @@ include $(TOPDIR)/config.mk
LIB = libpostdrivers.a
-COBJS-$(CONFIG_HAS_POST) += i2c.o memory.o rtc.o +COBJS-$(CONFIG_HAS_POST) += i2c.o memtest_pattern.o memory.o rtc.o
include $(TOPDIR)/post/rules.mk diff --git a/post/drivers/memory.c b/post/drivers/memory.c index 0062360..ee11e4b 100644 --- a/post/drivers/memory.c +++ b/post/drivers/memory.c @@ -22,436 +22,12 @@ */
#include <common.h> - -/* Memory test - * - * General observations: - * o The recommended test sequence is to test the data lines: if they are - * broken, nothing else will work properly. Then test the address - * lines. Finally, test the cells in the memory now that the test - * program knows that the address and data lines work properly. - * This sequence also helps isolate and identify what is faulty. - * - * o For the address line test, it is a good idea to use the base - * address of the lowest memory location, which causes a '1' bit to - * walk through a field of zeros on the address lines and the highest - * memory location, which causes a '0' bit to walk through a field of - * '1's on the address line. - * - * o Floating buses can fool memory tests if the test routine writes - * a value and then reads it back immediately. The problem is, the - * write will charge the residual capacitance on the data bus so the - * bus retains its state briefely. When the test program reads the - * value back immediately, the capacitance of the bus can allow it - * to read back what was written, even though the memory circuitry - * is broken. To avoid this, the test program should write a test - * pattern to the target location, write a different pattern elsewhere - * to charge the residual capacitance in a differnt manner, then read - * the target location back. - * - * o Always read the target location EXACTLY ONCE and save it in a local - * variable. The problem with reading the target location more than - * once is that the second and subsequent reads may work properly, - * resulting in a failed test that tells the poor technician that - * "Memory error at 00000000, wrote aaaaaaaa, read aaaaaaaa" which - * doesn't help him one bit and causes puzzled phone calls. Been there, - * done that. - * - * Data line test: - * --------------- - * This tests data lines for shorts and opens by forcing adjacent data - * to opposite states. Because the data lines could be routed in an - * arbitrary manner the must ensure test patterns ensure that every case - * is tested. By using the following series of binary patterns every - * combination of adjacent bits is test regardless of routing. - * - * ...101010101010101010101010 - * ...110011001100110011001100 - * ...111100001111000011110000 - * ...111111110000000011111111 - * - * Carrying this out, gives us six hex patterns as follows: - * - * 0xaaaaaaaaaaaaaaaa - * 0xcccccccccccccccc - * 0xf0f0f0f0f0f0f0f0 - * 0xff00ff00ff00ff00 - * 0xffff0000ffff0000 - * 0xffffffff00000000 - * - * To test for short and opens to other signals on our boards, we - * simply test with the 1's complemnt of the paterns as well, resulting - * in twelve patterns total. - * - * After writing a test pattern. a special pattern 0x0123456789ABCDEF is - * written to a different address in case the data lines are floating. - * Thus, if a byte lane fails, you will see part of the special - * pattern in that byte lane when the test runs. For example, if the - * xx__xxxxxxxxxxxx byte line fails, you will see aa23aaaaaaaaaaaa - * (for the 'a' test pattern). - * - * Address line test: - * ------------------ - * This function performs a test to verify that all the address lines - * hooked up to the RAM work properly. If there is an address line - * fault, it usually shows up as two different locations in the address - * map (related by the faulty address line) mapping to one physical - * memory storage location. The artifact that shows up is writing to - * the first location "changes" the second location. - * - * To test all address lines, we start with the given base address and - * xor the address with a '1' bit to flip one address line. For each - * test, we shift the '1' bit left to test the next address line. - * - * In the actual code, we start with address sizeof(ulong) since our - * test pattern we use is a ulong and thus, if we tried to test lower - * order address bits, it wouldn't work because our pattern would - * overwrite itself. - * - * Example for a 4 bit address space with the base at 0000: - * 0000 <- base - * 0001 <- test 1 - * 0010 <- test 2 - * 0100 <- test 3 - * 1000 <- test 4 - * Example for a 4 bit address space with the base at 0010: - * 0010 <- base - * 0011 <- test 1 - * 0000 <- (below the base address, skipped) - * 0110 <- test 2 - * 1010 <- test 3 - * - * The test locations are successively tested to make sure that they are - * not "mirrored" onto the base address due to a faulty address line. - * Note that the base and each test location are related by one address - * line flipped. Note that the base address need not be all zeros. - * - * Memory tests 1-4: - * ----------------- - * These tests verify RAM using sequential writes and reads - * to/from RAM. There are several test cases that use different patterns to - * verify RAM. Each test case fills a region of RAM with one pattern and - * then reads the region back and compares its contents with the pattern. - * The following patterns are used: - * - * 1a) zero pattern (0x00000000) - * 1b) negative pattern (0xffffffff) - * 1c) checkerboard pattern (0x55555555) - * 1d) checkerboard pattern (0xaaaaaaaa) - * 2) bit-flip pattern ((1 << (offset % 32)) - * 3) address pattern (offset) - * 4) address pattern (~offset) - * - * Being run in normal mode, the test verifies only small 4Kb - * regions of RAM around each 1Mb boundary. For example, for 64Mb - * RAM the following areas are verified: 0x00000000-0x00000800, - * 0x000ff800-0x00100800, 0x001ff800-0x00200800, ..., 0x03fff800- - * 0x04000000. If the test is run in slow-test mode, it verifies - * the whole RAM. - */ - #include <post.h> -#include <watchdog.h>
-#if CONFIG_POST & CONFIG_SYS_POST_MEMORY +#if (CONFIG_POST & CONFIG_SYS_POST_MEMORY)
DECLARE_GLOBAL_DATA_PTR;
-/* - * Define INJECT_*_ERRORS for testing error detection in the presence of - * _good_ hardware. - */ -#undef INJECT_DATA_ERRORS -#undef INJECT_ADDRESS_ERRORS - -#ifdef INJECT_DATA_ERRORS -#warning "Injecting data line errors for testing purposes" -#endif - -#ifdef INJECT_ADDRESS_ERRORS -#warning "Injecting address line errors for testing purposes" -#endif - - -/* - * This function performs a double word move from the data at - * the source pointer to the location at the destination pointer. - * This is helpful for testing memory on processors which have a 64 bit - * wide data bus. - * - * On those PowerPC with FPU, use assembly and a floating point move: - * this does a 64 bit move. - * - * For other processors, let the compiler generate the best code it can. - */ -static void move64(const unsigned long long *src, unsigned long long *dest) -{ -#if defined(CONFIG_MPC8260) || defined(CONFIG_MPC824X) - asm ("lfd 0, 0(3)\n\t" /* fpr0 = *scr */ - "stfd 0, 0(4)" /* *dest = fpr0 */ - : : : "fr0" ); /* Clobbers fr0 */ - return; -#else - *dest = *src; -#endif -} - -/* - * This is 64 bit wide test patterns. Note that they reside in ROM - * (which presumably works) and the tests write them to RAM which may - * not work. - * - * The "otherpattern" is written to drive the data bus to values other - * than the test pattern. This is for detecting floating bus lines. - * - */ -const static unsigned long long pattern[] = { - 0xaaaaaaaaaaaaaaaaULL, - 0xccccccccccccccccULL, - 0xf0f0f0f0f0f0f0f0ULL, - 0xff00ff00ff00ff00ULL, - 0xffff0000ffff0000ULL, - 0xffffffff00000000ULL, - 0x00000000ffffffffULL, - 0x0000ffff0000ffffULL, - 0x00ff00ff00ff00ffULL, - 0x0f0f0f0f0f0f0f0fULL, - 0x3333333333333333ULL, - 0x5555555555555555ULL -}; -const unsigned long long otherpattern = 0x0123456789abcdefULL; - - -static int memory_post_dataline(unsigned long long * pmem) -{ - unsigned long long temp64 = 0; - int num_patterns = sizeof(pattern)/ sizeof(pattern[0]); - int i; - unsigned int hi, lo, pathi, patlo; - int ret = 0; - - for ( i = 0; i < num_patterns; i++) { - move64(&(pattern[i]), pmem++); - /* - * Put a different pattern on the data lines: otherwise they - * may float long enough to read back what we wrote. - */ - move64(&otherpattern, pmem--); - move64(pmem, &temp64); - -#ifdef INJECT_DATA_ERRORS - temp64 ^= 0x00008000; -#endif - - if (temp64 != pattern[i]){ - pathi = (pattern[i]>>32) & 0xffffffff; - patlo = pattern[i] & 0xffffffff; - - hi = (temp64>>32) & 0xffffffff; - lo = temp64 & 0xffffffff; - - post_log ("Memory (date line) error at %08x, " - "wrote %08x%08x, read %08x%08x !\n", - pmem, pathi, patlo, hi, lo); - ret = -1; - } - } - return ret; -} - -static int memory_post_addrline(ulong *testaddr, ulong *base, ulong size) -{ - ulong *target; - ulong *end; - ulong readback; - ulong xor; - int ret = 0; - - end = (ulong *)((ulong)base + size); /* pointer arith! */ - xor = 0; - for(xor = sizeof(ulong); xor > 0; xor <<= 1) { - target = (ulong *)((ulong)testaddr ^ xor); - if((target >= base) && (target < end)) { - *testaddr = ~*target; - readback = *target; - -#ifdef INJECT_ADDRESS_ERRORS - if(xor == 0x00008000) { - readback = *testaddr; - } -#endif - if(readback == *testaddr) { - post_log ("Memory (address line) error at %08x<->%08x, " - "XOR value %08x !\n", - testaddr, target, xor); - ret = -1; - } - } - } - return ret; -} - -static int memory_post_test1 (unsigned long start, - unsigned long size, - unsigned long val) -{ - unsigned long i; - ulong *mem = (ulong *) start; - ulong readback; - int ret = 0; - - for (i = 0; i < size / sizeof (ulong); i++) { - mem[i] = val; - if (i % 1024 == 0) - WATCHDOG_RESET (); - } - - for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { - readback = mem[i]; - if (readback != val) { - post_log ("Memory error at %08x, " - "wrote %08x, read %08x !\n", - mem + i, val, readback); - - ret = -1; - break; - } - if (i % 1024 == 0) - WATCHDOG_RESET (); - } - - return ret; -} - -static int memory_post_test2 (unsigned long start, unsigned long size) -{ - unsigned long i; - ulong *mem = (ulong *) start; - ulong readback; - int ret = 0; - - for (i = 0; i < size / sizeof (ulong); i++) { - mem[i] = 1 << (i % 32); - if (i % 1024 == 0) - WATCHDOG_RESET (); - } - - for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { - readback = mem[i]; - if (readback != (1 << (i % 32))) { - post_log ("Memory error at %08x, " - "wrote %08x, read %08x !\n", - mem + i, 1 << (i % 32), readback); - - ret = -1; - break; - } - if (i % 1024 == 0) - WATCHDOG_RESET (); - } - - return ret; -} - -static int memory_post_test3 (unsigned long start, unsigned long size) -{ - unsigned long i; - ulong *mem = (ulong *) start; - ulong readback; - int ret = 0; - - for (i = 0; i < size / sizeof (ulong); i++) { - mem[i] = i; - if (i % 1024 == 0) - WATCHDOG_RESET (); - } - - for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { - readback = mem[i]; - if (readback != i) { - post_log ("Memory error at %08x, " - "wrote %08x, read %08x !\n", - mem + i, i, readback); - - ret = -1; - break; - } - if (i % 1024 == 0) - WATCHDOG_RESET (); - } - - return ret; -} - -static int memory_post_test4 (unsigned long start, unsigned long size) -{ - unsigned long i; - ulong *mem = (ulong *) start; - ulong readback; - int ret = 0; - - for (i = 0; i < size / sizeof (ulong); i++) { - mem[i] = ~i; - if (i % 1024 == 0) - WATCHDOG_RESET (); - } - - for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { - readback = mem[i]; - if (readback != ~i) { - post_log ("Memory error at %08x, " - "wrote %08x, read %08x !\n", - mem + i, ~i, readback); - - ret = -1; - break; - } - if (i % 1024 == 0) - WATCHDOG_RESET (); - } - - return ret; -} - -static int memory_post_tests (unsigned long start, unsigned long size) -{ - int ret = 0; - - if (ret == 0) - ret = memory_post_dataline ((unsigned long long *)start); - WATCHDOG_RESET (); - if (ret == 0) - ret = memory_post_addrline ((ulong *)start, (ulong *)start, size); - WATCHDOG_RESET (); - if (ret == 0) - ret = memory_post_addrline ((ulong *)(start + size - 8), - (ulong *)start, size); - WATCHDOG_RESET (); - if (ret == 0) - ret = memory_post_test1 (start, size, 0x00000000); - WATCHDOG_RESET (); - if (ret == 0) - ret = memory_post_test1 (start, size, 0xffffffff); - WATCHDOG_RESET (); - if (ret == 0) - ret = memory_post_test1 (start, size, 0x55555555); - WATCHDOG_RESET (); - if (ret == 0) - ret = memory_post_test1 (start, size, 0xaaaaaaaa); - WATCHDOG_RESET (); - if (ret == 0) - ret = memory_post_test2 (start, size); - WATCHDOG_RESET (); - if (ret == 0) - ret = memory_post_test3 (start, size); - WATCHDOG_RESET (); - if (ret == 0) - ret = memory_post_test4 (start, size); - WATCHDOG_RESET (); - - return ret; -} - int memory_post_test (int flags) { int ret = 0; diff --git a/post/drivers/memory.c b/post/drivers/memtest_pattern.c similarity index 79% copy from post/drivers/memory.c copy to post/drivers/memtest_pattern.c index 0062360..713de29 100644 --- a/post/drivers/memory.c +++ b/post/drivers/memtest_pattern.c @@ -22,7 +22,6 @@ */
#include <common.h> - /* Memory test * * General observations: @@ -150,12 +149,31 @@ * the whole RAM. */
-#include <post.h> #include <watchdog.h>
-#if CONFIG_POST & CONFIG_SYS_POST_MEMORY +#if (CONFIG_POST & CONFIG_SYS_POST_MEMORY) | defined(CONFIG_SYS_DRAM_TEST) +#ifdef CONFIG_POST +#define test_log(fmt, args...) test_log(fmt, ##args) +#else +#define test_log(fmt, args...) printf(fmt, ##args) +#endif
-DECLARE_GLOBAL_DATA_PTR; +/* The follow is progress indicator, borrowed from flash programming code */ +#define TOTAL_PROGRESS_DOTS 45 +#define TOTAL_PROGRESS_NUMBERS 9 +#define PROGRESS_DOTS_PER_NUMBER (TOTAL_PROGRESS_DOTS/TOTAL_PROGRESS_NUMBERS) +#define TEST_SHOW_PROGRESS(scale, dots, digit, dots_sub) \ +{ \ + dots -= (dots_sub); \ + if ((scale > 0) && (dots <= 0)) { \ + if ((digit % PROGRESS_DOTS_PER_NUMBER) == 0) \ + printf("%d", digit / PROGRESS_DOTS_PER_NUMBER); \ + else \ + putc('.'); \ + digit--; \ + dots += (scale); \ + } \ +}
/* * Define INJECT_*_ERRORS for testing error detection in the presence of @@ -230,6 +248,7 @@ static int memory_post_dataline(unsigned long long * pmem) unsigned int hi, lo, pathi, patlo; int ret = 0;
+ test_log("Data line test "); for ( i = 0; i < num_patterns; i++) { move64(&(pattern[i]), pmem++); /* @@ -250,12 +269,16 @@ static int memory_post_dataline(unsigned long long * pmem) hi = (temp64>>32) & 0xffffffff; lo = temp64 & 0xffffffff;
- post_log ("Memory (date line) error at %08x, " + test_log("Memory (date line) error at %p, " "wrote %08x%08x, read %08x%08x !\n", pmem, pathi, patlo, hi, lo); ret = -1; } } + if (ret) + test_log("failed\n"); + else + test_log("passed\n"); return ret; }
@@ -267,6 +290,7 @@ static int memory_post_addrline(ulong *testaddr, ulong *base, ulong size) ulong xor; int ret = 0;
+ test_log("Address line test "); end = (ulong *)((ulong)base + size); /* pointer arith! */ xor = 0; for(xor = sizeof(ulong); xor > 0; xor <<= 1) { @@ -281,13 +305,17 @@ static int memory_post_addrline(ulong *testaddr, ulong *base, ulong size) } #endif if(readback == *testaddr) { - post_log ("Memory (address line) error at %08x<->%08x, " - "XOR value %08x !\n", + test_log("Memory (address line) error at %p<->%p, " + "XOR value %08lx !\n", testaddr, target, xor); ret = -1; } } } + if (ret) + test_log("failed\n"); + else + test_log("passed\n"); return ret; }
@@ -299,18 +327,27 @@ static int memory_post_test1 (unsigned long start, ulong *mem = (ulong *) start; ulong readback; int ret = 0; + int digit = TOTAL_PROGRESS_DOTS; + int dots = 0; + int scale = (int)(((size >> 20) / sizeof(ulong) + TOTAL_PROGRESS_DOTS - 1) / TOTAL_PROGRESS_DOTS);
+ test_log("Pattern test %08lx\n", val); for (i = 0; i < size / sizeof (ulong); i++) { mem[i] = val; if (i % 1024 == 0) WATCHDOG_RESET (); + if ((i % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); } + test_log("Filled with pattern\n"); + digit = TOTAL_PROGRESS_DOTS; + dots = 0;
for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { readback = mem[i]; if (readback != val) { - post_log ("Memory error at %08x, " - "wrote %08x, read %08x !\n", + test_log("Memory error at %p, " + "wrote %08lx, read %08lx !\n", mem + i, val, readback);
ret = -1; @@ -318,7 +355,11 @@ static int memory_post_test1 (unsigned long start, } if (i % 1024 == 0) WATCHDOG_RESET (); + if ((i % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); } + if (!ret) + test_log("Verifed\n");
return ret; } @@ -329,18 +370,28 @@ static int memory_post_test2 (unsigned long start, unsigned long size) ulong *mem = (ulong *) start; ulong readback; int ret = 0; + int digit = TOTAL_PROGRESS_DOTS; + int dots = 0; + int scale = (int)(((size >> 20) / sizeof(ulong) + TOTAL_PROGRESS_DOTS - 1) / TOTAL_PROGRESS_DOTS); + + test_log("Bit flip pattern test\n");
for (i = 0; i < size / sizeof (ulong); i++) { mem[i] = 1 << (i % 32); if (i % 1024 == 0) WATCHDOG_RESET (); + if ((i % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); } + test_log("Filled with pattern\n"); + digit = TOTAL_PROGRESS_DOTS; + dots = 0;
for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { readback = mem[i]; if (readback != (1 << (i % 32))) { - post_log ("Memory error at %08x, " - "wrote %08x, read %08x !\n", + test_log("Memory error at %p, " + "wrote %08x, read %08lx !\n", mem + i, 1 << (i % 32), readback);
ret = -1; @@ -348,7 +399,11 @@ static int memory_post_test2 (unsigned long start, unsigned long size) } if (i % 1024 == 0) WATCHDOG_RESET (); + if ((i % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); } + if (!ret) + test_log("Verifed\n");
return ret; } @@ -359,18 +414,28 @@ static int memory_post_test3 (unsigned long start, unsigned long size) ulong *mem = (ulong *) start; ulong readback; int ret = 0; + int digit = TOTAL_PROGRESS_DOTS; + int dots = 0; + int scale = (int)(((size >> 20) / sizeof(ulong) + TOTAL_PROGRESS_DOTS - 1) / TOTAL_PROGRESS_DOTS); + + test_log("Address pattern (offset)\n");
for (i = 0; i < size / sizeof (ulong); i++) { mem[i] = i; if (i % 1024 == 0) WATCHDOG_RESET (); + if ((i % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); } + test_log("Filled with pattern\n"); + digit = TOTAL_PROGRESS_DOTS; + dots = 0;
for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { readback = mem[i]; if (readback != i) { - post_log ("Memory error at %08x, " - "wrote %08x, read %08x !\n", + test_log("Memory error at %p, " + "wrote %08lx, read %08lx !\n", mem + i, i, readback);
ret = -1; @@ -378,8 +443,11 @@ static int memory_post_test3 (unsigned long start, unsigned long size) } if (i % 1024 == 0) WATCHDOG_RESET (); + if ((i % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); } - + if (!ret) + test_log("Verifed\n"); return ret; }
@@ -389,18 +457,28 @@ static int memory_post_test4 (unsigned long start, unsigned long size) ulong *mem = (ulong *) start; ulong readback; int ret = 0; + int digit = TOTAL_PROGRESS_DOTS; + int dots = 0; + int scale = (int)(((size >> 20) / sizeof(ulong) + TOTAL_PROGRESS_DOTS - 1) / TOTAL_PROGRESS_DOTS); + + test_log("Address pattern (!offset)\n");
for (i = 0; i < size / sizeof (ulong); i++) { mem[i] = ~i; if (i % 1024 == 0) WATCHDOG_RESET (); + if ((i % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); } + test_log("Filled with pattern\n"); + digit = TOTAL_PROGRESS_DOTS; + dots = 0;
for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) { readback = mem[i]; if (readback != ~i) { - post_log ("Memory error at %08x, " - "wrote %08x, read %08x !\n", + test_log("Memory error at %p, " + "wrote %08lx, read %08lx !\n", mem + i, ~i, readback);
ret = -1; @@ -408,12 +486,16 @@ static int memory_post_test4 (unsigned long start, unsigned long size) } if (i % 1024 == 0) WATCHDOG_RESET (); + if ((i % (1 << 20)) == 0) + TEST_SHOW_PROGRESS(scale, dots, digit, 1); } + if (!ret) + test_log("Verifed\n");
return ret; }
-static int memory_post_tests (unsigned long start, unsigned long size) +int memory_post_tests(unsigned long start, unsigned long size) { int ret = 0;
@@ -451,33 +533,4 @@ static int memory_post_tests (unsigned long start, unsigned long size)
return ret; } - -int memory_post_test (int flags) -{ - int ret = 0; - bd_t *bd = gd->bd; - unsigned long memsize = (bd->bi_memsize >= 256 << 20 ? - 256 << 20 : bd->bi_memsize) - (1 << 20); - - /* Limit area to be tested with the board info struct */ - if (CONFIG_SYS_SDRAM_BASE + memsize > (ulong)bd) - memsize = (ulong)bd - CONFIG_SYS_SDRAM_BASE; - - if (flags & POST_SLOWTEST) { - ret = memory_post_tests (CONFIG_SYS_SDRAM_BASE, memsize); - } else { /* POST_NORMAL */ - - unsigned long i; - - for (i = 0; i < (memsize >> 20) && ret == 0; i++) { - if (ret == 0) - ret = memory_post_tests (i << 20, 0x800); - if (ret == 0) - ret = memory_post_tests ((i << 20) + 0xff800, 0x800); - } - } - - return ret; -} - -#endif /* CONFIG_POST & CONFIG_SYS_POST_MEMORY */ +#endif /* (CONFIG_POST & CONFIG_SYS_POST_MEMORY) | defined(CONFIG_SYS_DRAM_TEST) */

Dear York Sun,
In message 1280351179.8571.63.camel@oslab-l1 you wrote:
We already have too many different implementations of a memory test in U-Boot, and I will not accept adding yet another one.
I can reuse your testing code but have to move the desired code out of memory.c file to avoid the need for CONFIG_POST and CONFIG_SYS_POST_MEMORY. I also add a progress indicator. My testing
NAK, and NAK.
Please integrate your code into the existing POST framework instead, as a number of other boards already did.
A progress indicator may be a nice little toy, but how does it integrate into the POST framework?
target is 2GB at a time, up to physically memory size which is easily over 8GB. Without progress indicator, it feels hung when it is actually running.
Yes, memory testing takes time. In the context of a power-on self test (and this is what you are doing, right?) we should take care to fit it into the existing framework, though.
Please take a look at the patch below.
Instead of integrating your needs into an existing framework you invent yet another one. I don't want to have this, sorry.
Best regards,
Wolfgang Denk

On Jul 14, 2010, at 10:15 AM, Kumar Gala wrote:
From: york yorksun@freescale.com
Enabled SPD Enabled DDR2 Enabled hwconfig
Signed-off-by: York Sun yorksun@freescale.com
Makefile | 1 + board/freescale/p2020ds/ddr.c | 56 ++++++++++++++++++------------------- board/freescale/p2020ds/p2020ds.c | 7 +++- include/configs/P2020DS.h | 6 ++++ 4 files changed, 39 insertions(+), 31 deletions(-)
applied to 85xx
- k

On Jul 14, 2010, at 10:15 AM, Kumar Gala wrote:
From: york yorksun@freescale.com
Changes for P2020DS DDR applies to other 8xxx platform
Signed-off-by: York Sun yorksun@freescale.com
arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 14 +++++++------- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 1 + 2 files changed, 8 insertions(+), 7 deletions(-)
applied to 85xx
- k

On Jul 14, 2010, at 10:14 AM, Kumar Gala wrote:
From: york yorksun@freescale.com
Enabled registered DIMMs using data from SPD. RDIMMs have registers which need to be configured before using. The register configuration words are stored in SPD byte 60~116 (JEDEC standard No.21-C). Software should read those RCWs and put into DDR controller before initialization.
Signed-off-by: York Sun yorksun@freescale.com
.../powerpc/cpu/mpc8xxx/ddr/common_timing_params.h | 3 + arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 81 ++++++++------------ arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c | 6 +- .../cpu/mpc8xxx/ddr/lc_common_dimm_params.c | 18 ++++- arch/powerpc/include/asm/fsl_ddr_dimm_params.h | 3 + include/ddr_spd.h | 14 ++++ 6 files changed, 72 insertions(+), 53 deletions(-)
applied to 85xx
- k

On Jul 14, 2010, at 10:14 AM, Kumar Gala wrote:
From: york yorksun@freescale.com
For 85xx silicon which supports address hashing, it can be activated by hwconfig.
Signed-off-by: York Sun yorksun@freescale.com
arch/powerpc/cpu/mpc85xx/ddr-gen3.c | 2 ++ arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 10 ++++++++++ arch/powerpc/cpu/mpc8xxx/ddr/options.c | 7 +++++++ arch/powerpc/include/asm/fsl_ddr_sdram.h | 2 ++ doc/README.fsl-ddr | 15 +++++++++++++-- 5 files changed, 34 insertions(+), 2 deletions(-)
applied to 85xx
- k

On Jul 14, 2010, at 10:14 AM, Kumar Gala wrote:
From: york yorksun@freescale.com
Previous code presumes each DIMM has up to two rank (chip select). Newer DDR controller supports up to four chip select on one DIMM.
Signed-off-by: York Sun yorksun@freescale.com
arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 52 ++++++++++++++----- .../cpu/mpc8xxx/ddr/lc_common_dimm_params.c | 12 +++++ arch/powerpc/cpu/mpc8xxx/ddr/options.c | 17 ++++--- arch/powerpc/include/asm/fsl_ddr_sdram.h | 1 + 4 files changed, 61 insertions(+), 21 deletions(-)
applied to 85xx
- k

On Jul 14, 2010, at 10:14 AM, Kumar Gala wrote:
From: york yorksun@freescale.com
Verified on MPC8641HPCN with four DDR2 dimms. Each dimm has dual rank with 512MB each rank.
Also check dimm size and rank size for memory controller interleaving
Signed-off-by: York Sun yorksun@freescale.com
arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 113 +++++++++++++++++++---------- arch/powerpc/cpu/mpc8xxx/ddr/ddr.h | 1 + arch/powerpc/cpu/mpc8xxx/ddr/main.c | 40 +++++----- arch/powerpc/cpu/mpc8xxx/ddr/options.c | 107 +++++++++++++++++++++++----- board/freescale/mpc8641hpcn/mpc8641hpcn.c | 2 + doc/README.fsl-ddr | 3 + include/configs/MPC8641HPCN.h | 2 + 7 files changed, 191 insertions(+), 77 deletions(-)
applied to 85xx
- k

On Jul 14, 2010, at 10:14 AM, Kumar Gala wrote:
Replace environmental variables memctl_intlv_ctl and ba_intlv_ctl with hwconfig parameters. The syntax is
setenv hwconfig "fsl_ddr:ctlr_intlv=<mode>,bank_intlv=<mode>"
The mode values for memory controller interleaving are cacheline page bank superbank
The mode values for bank interleaving are cs0_cs1 cs2_cs3 cs0_cs1_and_cs2_cs3 cs0_cs1_cs2_cs3
Signed-off-by: York Sun yorksun@freescale.com
arch/powerpc/cpu/mpc8xxx/ddr/options.c | 40 ++++++++++++++++++++------------ doc/README.fsl-ddr | 25 +++++++++++-------- 2 files changed, 39 insertions(+), 26 deletions(-)
applied to 85xx
- k
participants (4)
-
Kumar Gala
-
Timur Tabi
-
Wolfgang Denk
-
York Sun