diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc8xxx')
-rw-r--r-- | arch/powerpc/cpu/mpc8xxx/cpu.c | 10 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/common_timing_params.h | 3 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/ctrl_regs.c | 264 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/ddr.h | 1 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/ddr3_dimm_params.c | 6 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c | 30 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/main.c | 40 | ||||
-rw-r--r-- | arch/powerpc/cpu/mpc8xxx/ddr/options.c | 154 |
8 files changed, 345 insertions, 163 deletions
diff --git a/arch/powerpc/cpu/mpc8xxx/cpu.c b/arch/powerpc/cpu/mpc8xxx/cpu.c index dc3da16..97a94f4 100644 --- a/arch/powerpc/cpu/mpc8xxx/cpu.c +++ b/arch/powerpc/cpu/mpc8xxx/cpu.c @@ -110,8 +110,14 @@ struct cpu_type *identify_cpu(u32 ver) } int cpu_numcores() { - struct cpu_type *cpu; - cpu = gd->cpu; + ccsr_pic_t __iomem *pic = (void *)CONFIG_SYS_MPC85xx_PIC_ADDR; + struct cpu_type *cpu = gd->cpu; + + /* better to query feature reporting register than just assume 1 */ + if (cpu == &cpu_type_unknown) + return ((in_be32(&pic->frr) & MPC85xx_PICFRR_NCPU_MASK) >> + MPC85xx_PICFRR_NCPU_SHIFT) + 1; + return cpu->num_cores; } 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 4a282bc..dccb7aa 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) @@ -178,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; @@ -190,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; @@ -427,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, @@ -521,6 +571,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 +613,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 +621,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) @@ -914,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) */ @@ -977,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 @@ -1052,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 @@ -1089,52 +1143,12 @@ 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) +static void set_ddr_eor(fsl_ddr_cfg_regs_t *ddr, const memctl_options_t *popts) { - 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) - ); + if (popts->addr_hash) { + ddr->ddr_eor = 0x40000000; /* address hash enable */ + puts("Addess hashing enabled.\n"); + } } unsigned int @@ -1201,37 +1215,63 @@ 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; + set_csn_config(dimm_number, i, ddr, popts, dimm_params); + 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); + "because n_ranks on DIMM %u is 0\n", i, dimm_number); continue; } 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 +1283,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 +1295,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 +1309,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 +1349,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 +1358,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; } } @@ -1329,10 +1378,12 @@ 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); } + set_ddr_eor(ddr, popts); + #if !defined(CONFIG_FSL_DDR1) set_timing_cfg_0(ddr); #endif @@ -1361,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/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/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 e888e3e..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(); @@ -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, @@ -219,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/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 46731c8..774c0e4 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. */ @@ -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 @@ -212,78 +213,128 @@ 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. */ #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" + 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; - 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")) + 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 (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 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) { + 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 ((pdimm[0].n_ranks != 2)||(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(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; @@ -291,7 +342,48 @@ 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; + fsl_ddr_board_options(popts, pdimm, ctrl_num); 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"); + } +} |