diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c')
-rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 113 |
1 files changed, 74 insertions, 39 deletions
diff --git a/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c b/arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c index 4a282bc52d..69c1c7cb80 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; } } |