From 5800e7ab32c200836e81ab2384817d93105561c5 Mon Sep 17 00:00:00 2001 From: york Date: Fri, 2 Jul 2010 22:25:53 +0000 Subject: powerpc/8xxx: Enable quad-rank DIMMs. 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 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; -- cgit v0.10.2