powerpc/8xxx: Enable quad-rank DIMMs.
authoryork <yorksun@freescale.com>
Fri, 2 Jul 2010 22:25:53 +0000 (22:25 +0000)
committerKumar Gala <galak@kernel.crashing.org>
Mon, 26 Jul 2010 18:16:09 +0000 (13:16 -0500)
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
arch/powerpc/cpu/mpc8xxx/ddr/lc_common_dimm_params.c
arch/powerpc/cpu/mpc8xxx/ddr/options.c
arch/powerpc/include/asm/fsl_ddr_sdram.h

index 69c1c7cb803030fb77dcb39ed464defd2d70f651..6e73b1d31433ca2d9b075895bb57cee9f7e08c6a 100644 (file)
@@ -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);
        }
 
index e888e3ea562d2feb78afcdcb402941f3fb9331e9..ce6c148d0966114ffaeae4908ae392bd9efaf2fe 100644 (file)
@@ -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,
index ebbdb69c0df42d8264ebc417538ac57455277bdb..1d5f3e2cdd4d492cb2a164ff178feaa34ef22c13 100644 (file)
@@ -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;
index 02920dbfd7bc08e993d22ccf878f120eeb58e983..431327e94d69843d0a33a8c45b93d597ff19a710 100644 (file)
@@ -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;