Check DDR interleaving mode
authorHaiying Wang <Haiying.Wang@freescale.com>
Fri, 3 Oct 2008 16:37:10 +0000 (12:37 -0400)
committerWolfgang Denk <wd@denx.de>
Sat, 18 Oct 2008 19:54:05 +0000 (21:54 +0200)
* Check DDR interleaving mode from environment by reading memctl_intlv_ctl and
ba_intlv_ctl.
* Print DDR interleaving mode information
* Add doc/README.fsl-ddr to describe the interleaving setting

Signed-off-by: Haiying Wang <Haiying.Wang@freescale.com>
cpu/mpc8xxx/ddr/main.c
cpu/mpc8xxx/ddr/options.c
doc/README.fsl-ddr [new file with mode: 0644]

index 700b8971729f84dccced25b04306bc682d7f59d5..21a16d97e12c5e75ab6dcaf1fef891805a78de2b 100644 (file)
@@ -164,6 +164,24 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo,
        }
        if (j == 2) {
                *memctl_interleaving = 1;
+
+               printf("\nMemory controller interleaving enabled: ");
+
+               switch (pinfo->memctl_opts[0].memctl_interleaving_mode) {
+               case FSL_DDR_CACHE_LINE_INTERLEAVING:
+                       printf("Cache-line interleaving!\n");
+                       break;
+               case FSL_DDR_PAGE_INTERLEAVING:
+                       printf("Page interleaving!\n");
+                       break;
+               case FSL_DDR_BANK_INTERLEAVING:
+                       printf("Bank interleaving!\n");
+                       break;
+               case FSL_DDR_SUPERBANK_INTERLEAVING:
+                       printf("Super bank interleaving\n");
+               default:
+                       break;
+               }
        }
 
        /* Check that all controllers are rank interleaving. */
@@ -175,6 +193,25 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo,
        }
        if (j == 2) {
                *rank_interleaving = 1;
+
+               printf("Bank(chip-select) interleaving enabled: ");
+
+               switch (pinfo->memctl_opts[0].ba_intlv_ctl &
+                                               FSL_DDR_CS0_CS1_CS2_CS3) {
+               case FSL_DDR_CS0_CS1_CS2_CS3:
+                       printf("CS0+CS1+CS2+CS3\n");
+                       break;
+               case FSL_DDR_CS0_CS1:
+                       printf("CS0+CS1\n");
+                       break;
+               case FSL_DDR_CS2_CS3:
+                       printf("CS2+CS3\n");
+                       break;
+               case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+                       printf("CS0+CS1 and CS2+CS3\n");
+               default:
+                       break;
+               }
        }
 
        if (*memctl_interleaving) {
index 99b56856641c6305f3256b0c4e3429c68cc84460..714e88d7fa5e10ca7d7ed647e9c985764e31ec21 100644 (file)
@@ -22,6 +22,7 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
                        unsigned int ctrl_num)
 {
        unsigned int i;
+       const char *p;
 
        /* Chip select options. */
 
@@ -181,17 +182,86 @@ unsigned int populate_memctl_options(int all_DIMMs_registered,
 #error "FIXME determine four activates for DDR3"
 #endif
 
-       /* ODT should only be used for DDR2 */
-
-       /* FIXME? */
-
        /*
-        * Interleaving checks.
+        * Check interleaving configuration from environment.
+        * 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.
+        *
+        * XXX: Attempt to set both 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 ((p = getenv("memctl_intlv_ctl")) != NULL) {
+               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\
+                               are controller interleaved, force non memory \
+                               controller interleaving\n");
+                       popts->memctl_interleaving = 0;
+               } else {
+                       popts->memctl_interleaving = 1;
+                       if (strcmp(p, "cacheline") == 0)
+                               popts->memctl_interleaving_mode =
+                                       FSL_DDR_CACHE_LINE_INTERLEAVING;
+                       else if (strcmp(p, "page") == 0)
+                               popts->memctl_interleaving_mode =
+                                       FSL_DDR_PAGE_INTERLEAVING;
+                       else if (strcmp(p, "bank") == 0)
+                               popts->memctl_interleaving_mode =
+                                       FSL_DDR_BANK_INTERLEAVING;
+                       else if (strcmp(p, "superbank") == 0)
+                               popts->memctl_interleaving_mode =
+                                       FSL_DDR_SUPERBANK_INTERLEAVING;
+                       else
+                               popts->memctl_interleaving_mode =
+                                               simple_strtoul(p, NULL, 0);
+               }
+       }
+
+       if( (p = getenv("ba_intlv_ctl")) != NULL) {
+               if (strcmp(p, "cs0_cs1") == 0)
+                       popts->ba_intlv_ctl = FSL_DDR_CS0_CS1;
+               else if (strcmp(p, "cs2_cs3") == 0)
+                       popts->ba_intlv_ctl = FSL_DDR_CS2_CS3;
+               else if (strcmp(p, "cs0_cs1_and_cs2_cs3") == 0)
+                       popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_AND_CS2_CS3;
+               else if (strcmp(p, "cs0_cs1_cs2_cs3") == 0)
+                       popts->ba_intlv_ctl = FSL_DDR_CS0_CS1_CS2_CS3;
+               else
+                       popts->ba_intlv_ctl = simple_strtoul(p, NULL, 0);
+
+               switch (popts->ba_intlv_ctl & FSL_DDR_CS0_CS1_CS2_CS3) {
+               case FSL_DDR_CS0_CS1_CS2_CS3:
+               case FSL_DDR_CS0_CS1:
+                       if (pdimm[0].n_ranks != 2) {
+                               popts->ba_intlv_ctl = 0;
+                               printf("No enough bank(chip-select) for \
+                                       CS0+CS1, force non-interleaving!\n");
+                       }
+                       break;
+               case FSL_DDR_CS2_CS3:
+                       if (pdimm[1].n_ranks !=2){
+                               popts->ba_intlv_ctl = 0;
+                               printf("No enough bank(CS) for CS2+CS3, \
+                                       force non-interleaving!\n");
+                       }
+                       break;
+               case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+                       if ((pdimm[0].n_ranks != 2)||(pdimm[1].n_ranks != 2)) {
+                               popts->ba_intlv_ctl = 0;
+                               printf("No enough bank(CS) for CS0+CS1 or \
+                                        CS2+CS3, force non-interleaving!\n");
+                       }
+                       break;
+               default:
+                       popts->ba_intlv_ctl = 0;
+                       break;
+               }
+       }
 
        fsl_ddr_board_options(popts, pdimm, ctrl_num);
 
diff --git a/doc/README.fsl-ddr b/doc/README.fsl-ddr
new file mode 100644 (file)
index 0000000..9c2224f
--- /dev/null
@@ -0,0 +1,69 @@
+
+Table of interleaving modes supported in cpu/8xxx/ddr/
+======================================================
+  +-------------+---------------------------------------------------------+
+  |             |                   Rank Interleaving                     |
+  |             +--------+-----------+-----------+------------+-----------+
+  |Memory       |        |           |           |    2x2     |    4x1    |
+  |Controller   |  None  | 2x1 lower | 2x1 upper | {CS0+CS1}, | {CS0+CS1+ |
+  |Interleaving |        | {CS0+CS1} | {CS2+CS3} | {CS2+CS3}  |  CS2+CS3} |
+  +-------------+--------+-----------+-----------+------------+-----------+
+  |None         |  Yes   | Yes       | Yes       | Yes        | Yes       |
+  +-------------+--------+-----------+-----------+------------+-----------+
+  |Cacheline    |  Yes   | Yes       | No        | No, Only(*)| Yes       |
+  |             |CS0 Only|           |           | {CS0+CS1}  |           |
+  +-------------+--------+-----------+-----------+------------+-----------+
+  |Page         |  Yes   | Yes       | No        | No, Only(*)| Yes       |
+  |             |CS0 Only|           |           | {CS0+CS1}  |           |
+  +-------------+--------+-----------+-----------+------------+-----------+
+  |Bank         |  Yes   | Yes       | No        | No, Only(*)| Yes       |
+  |             |CS0 Only|           |           | {CS0+CS1}  |           |
+  +-------------+--------+-----------+-----------+------------+-----------+
+  |Superbank    |  No    | Yes       | No        | No, Only(*)| Yes       |
+  |             |        |           |           | {CS0+CS1}  |           |
+  +-------------+--------+-----------+-----------+------------+-----------+
+ (*) Although the hardware can be configured with memory controller
+ interleaving using "2x2" rank interleaving, it only interleaves {CS0+CS1}
+ from each controller. {CS2+CS3} on each controller are only rank
+ interleaved on that controller.
+
+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"                                         \
+        ......
+
+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
+
+  # cacheline interleaving
+  setenv memctl_intlv_ctl 0 or setenv memctl_intlv_ctl cacheline
+
+  # page interleaving
+  setenv memctl_intlv_ctl 1 or setenv memctl_intlv_ctl page
+
+  # bank interleaving
+  setenv memctl_intlv_ctl 2 or setenv memctl_intlv_ctl bank
+
+  # superbank
+  setenv memctl_intlv_ctl 3 or setenv memctl_intlv_ctl superbank
+
+  # disable bank (chip-select) interleaving
+  setenv ba_intlv_ctl
+
+  # bank(chip-select) interleaving cs0+cs1
+  setenv ba_intlv_ctl 0x40 or setenv ba_intlv_ctl cs0_cs1
+
+  # bank(chip-select) interleaving cs2+cs3
+  setenv ba_intlv_ctl 0x20 or setenv ba_intlv_ctl 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
+
+  # bank(chip-select) interleaving (cs0+cs1+cs2+cs3) (4x1)
+  setenv ba_intlv_ctl 0x04 or setenv ba_intlv_ctl cs0_cs1_cs2_cs3