]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - arch/powerpc/cpu/mpc8xxx/ddr/main.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / arch / powerpc / cpu / mpc8xxx / ddr / main.c
index bb96d66a9df5774e6a2cbeb6ed011266b40fe8c4..7a8636de166ac4ca6e2c69eda2faa7fc2a65d6f2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ * Copyright 2008-2012 Freescale Semiconductor, Inc.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  */
 
 #include <common.h>
+#include <i2c.h>
 #include <asm/fsl_ddr_sdram.h>
+#include <asm/fsl_law.h>
 
 #include "ddr.h"
 
-extern void fsl_ddr_set_lawbar(
+void fsl_ddr_set_lawbar(
                const common_timing_params_t *memctl_common_params,
                unsigned int memctl_interleaved,
                unsigned int ctrl_num);
+void fsl_ddr_set_intl3r(const unsigned int granule_size);
 
 /* processor specific function */
 extern void fsl_ddr_set_memctl_regs(const fsl_ddr_cfg_regs_t *regs,
                                   unsigned int ctrl_num);
 
-/* Board-specific functions defined in each board's ddr.c */
-extern void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
-                          unsigned int ctrl_num);
+#if defined(SPD_EEPROM_ADDRESS) || \
+    defined(SPD_EEPROM_ADDRESS1) || defined(SPD_EEPROM_ADDRESS2) || \
+    defined(SPD_EEPROM_ADDRESS3) || defined(SPD_EEPROM_ADDRESS4)
+#if (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+       [0][0] = SPD_EEPROM_ADDRESS,
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 1) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+       [0][0] = SPD_EEPROM_ADDRESS1,   /* controller 1 */
+       [0][1] = SPD_EEPROM_ADDRESS2,   /* controller 1 */
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+       [0][0] = SPD_EEPROM_ADDRESS1,   /* controller 1 */
+       [1][0] = SPD_EEPROM_ADDRESS2,   /* controller 2 */
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 2) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+       [0][0] = SPD_EEPROM_ADDRESS1,   /* controller 1 */
+       [0][1] = SPD_EEPROM_ADDRESS2,   /* controller 1 */
+       [1][0] = SPD_EEPROM_ADDRESS3,   /* controller 2 */
+       [1][1] = SPD_EEPROM_ADDRESS4,   /* controller 2 */
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 1)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+       [0][0] = SPD_EEPROM_ADDRESS1,   /* controller 1 */
+       [1][0] = SPD_EEPROM_ADDRESS2,   /* controller 2 */
+       [2][0] = SPD_EEPROM_ADDRESS3,   /* controller 3 */
+};
+#elif (CONFIG_NUM_DDR_CONTROLLERS == 3) && (CONFIG_DIMM_SLOTS_PER_CTLR == 2)
+u8 spd_i2c_addr[CONFIG_NUM_DDR_CONTROLLERS][CONFIG_DIMM_SLOTS_PER_CTLR] = {
+       [0][0] = SPD_EEPROM_ADDRESS1,   /* controller 1 */
+       [0][1] = SPD_EEPROM_ADDRESS2,   /* controller 1 */
+       [1][0] = SPD_EEPROM_ADDRESS3,   /* controller 2 */
+       [1][1] = SPD_EEPROM_ADDRESS4,   /* controller 2 */
+       [2][0] = SPD_EEPROM_ADDRESS5,   /* controller 3 */
+       [2][1] = SPD_EEPROM_ADDRESS6,   /* controller 3 */
+};
+
+#endif
+
+static void __get_spd(generic_spd_eeprom_t *spd, u8 i2c_address)
+{
+       int ret = i2c_read(i2c_address, 0, 1, (uchar *)spd,
+                               sizeof(generic_spd_eeprom_t));
+
+       if (ret) {
+               if (i2c_address ==
+#ifdef SPD_EEPROM_ADDRESS
+                               SPD_EEPROM_ADDRESS
+#elif defined(SPD_EEPROM_ADDRESS1)
+                               SPD_EEPROM_ADDRESS1
+#endif
+                               ) {
+                       printf("DDR: failed to read SPD from address %u\n",
+                               i2c_address);
+               } else {
+                       debug("DDR: failed to read SPD from address %u\n",
+                               i2c_address);
+               }
+               memset(spd, 0, sizeof(generic_spd_eeprom_t));
+       }
+}
+
+__attribute__((weak, alias("__get_spd")))
+void get_spd(generic_spd_eeprom_t *spd, u8 i2c_address);
+
+void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
+                     unsigned int ctrl_num)
+{
+       unsigned int i;
+       unsigned int i2c_address = 0;
+
+       if (ctrl_num >= CONFIG_NUM_DDR_CONTROLLERS) {
+               printf("%s unexpected ctrl_num = %u\n", __FUNCTION__, ctrl_num);
+               return;
+       }
+
+       for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) {
+               i2c_address = spd_i2c_addr[ctrl_num][i];
+               get_spd(&(ctrl_dimms_spd[i]), i2c_address);
+       }
+}
+#else
+void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
+                     unsigned int ctrl_num)
+{
+}
+#endif /* SPD_EEPROM_ADDRESSx */
 
 /*
  * ASSUMPTIONS:
@@ -75,7 +165,6 @@ extern void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
  *                             |  interleaving
  */
 
-#ifdef DEBUG
 const char *step_string_tbl[] = {
        "STEP_GET_SPD",
        "STEP_COMPUTE_DIMM_PARMS",
@@ -96,14 +185,13 @@ const char * step_to_string(unsigned int step) {
 
        return step_string_tbl[s];
 }
-#endif
 
-int step_assign_addresses(fsl_ddr_info_t *pinfo,
-                         unsigned int dbw_cap_adj[],
-                         unsigned int *all_memctl_interleaving,
-                         unsigned int *all_ctlr_rank_interleaving)
+static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
+                         unsigned int dbw_cap_adj[])
 {
        int i, j;
+       unsigned long long total_mem, current_mem_base, total_ctlr_mem;
+       unsigned long long rank_density, ctlr_density = 0;
 
        /*
         * If a reduced data width is requested, but the SPD
@@ -117,7 +205,19 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo,
                switch (pinfo->memctl_opts[i].data_bus_width) {
                case 2:
                        /* 16-bit */
-                       printf("can't handle 16-bit mode yet\n");
+                       for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+                               unsigned int dw;
+                               if (!pinfo->dimm_params[i][j].n_ranks)
+                                       continue;
+                               dw = pinfo->dimm_params[i][j].primary_sdram_width;
+                               if ((dw == 72 || dw == 64)) {
+                                       dbw_cap_adj[i] = 2;
+                                       break;
+                               } else if ((dw == 40 || dw == 32)) {
+                                       dbw_cap_adj[i] = 1;
+                                       break;
+                               }
+                       }
                        break;
 
                case 1:
@@ -150,95 +250,120 @@ int step_assign_addresses(fsl_ddr_info_t *pinfo,
                                "specified controller %u\n", i);
                        return 1;
                }
+               debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]);
        }
 
-       j = 0;
-       for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
-               if (pinfo->memctl_opts[i].memctl_interleaving)
-                       j++;
-       /*
-        * 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)
-                       j++;
-       /*
-        * 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 (*all_memctl_interleaving) {
-               unsigned long long addr, total_mem_per_ctlr = 0;
-               /*
-                * If interleaving between memory controllers,
-                * make each controller start at a base address
-                * of 0.
-                *
-                * Also, if bank interleaving (chip select
-                * interleaving) is enabled on each memory
-                * controller, CS0 needs to be programmed to
-                * cover the entire memory range on that memory
-                * controller
-                *
-                * Bank interleaving also implies that each
-                * addressed chip select is identical in size.
-                */
-
+       current_mem_base = 0ull;
+       total_mem = 0;
+       if (pinfo->memctl_opts[0].memctl_interleaving) {
+               rank_density = pinfo->dimm_params[0][0].rank_density >>
+                                       dbw_cap_adj[0];
+               switch (pinfo->memctl_opts[0].ba_intlv_ctl &
+                                       FSL_DDR_CS0_CS1_CS2_CS3) {
+               case FSL_DDR_CS0_CS1_CS2_CS3:
+                       ctlr_density = 4 * rank_density;
+                       break;
+               case FSL_DDR_CS0_CS1:
+               case FSL_DDR_CS0_CS1_AND_CS2_CS3:
+                       ctlr_density = 2 * rank_density;
+                       break;
+               case FSL_DDR_CS2_CS3:
+               default:
+                       ctlr_density = rank_density;
+                       break;
+               }
+               debug("rank density is 0x%llx, ctlr density is 0x%llx\n",
+                       rank_density, ctlr_density);
                for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-                       addr = 0;
-                       pinfo->common_timing_params[i].base_address = 0ull;
-                       for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
-                               unsigned long long cap
-                                       = pinfo->dimm_params[i][j].capacity;
-
-                               pinfo->dimm_params[i][j].base_address = addr;
-                               addr += cap >> dbw_cap_adj[i];
-                               total_mem_per_ctlr += cap >> dbw_cap_adj[i];
+                       if (pinfo->memctl_opts[i].memctl_interleaving) {
+                               switch (pinfo->memctl_opts[i].memctl_interleaving_mode) {
+                               case FSL_DDR_CACHE_LINE_INTERLEAVING:
+                               case FSL_DDR_PAGE_INTERLEAVING:
+                               case FSL_DDR_BANK_INTERLEAVING:
+                               case FSL_DDR_SUPERBANK_INTERLEAVING:
+                                       total_ctlr_mem = 2 * ctlr_density;
+                                       break;
+                               case FSL_DDR_3WAY_1KB_INTERLEAVING:
+                               case FSL_DDR_3WAY_4KB_INTERLEAVING:
+                               case FSL_DDR_3WAY_8KB_INTERLEAVING:
+                                       total_ctlr_mem = 3 * ctlr_density;
+                                       break;
+                               case FSL_DDR_4WAY_1KB_INTERLEAVING:
+                               case FSL_DDR_4WAY_4KB_INTERLEAVING:
+                               case FSL_DDR_4WAY_8KB_INTERLEAVING:
+                                       total_ctlr_mem = 4 * ctlr_density;
+                                       break;
+                               default:
+                                       panic("Unknown interleaving mode");
+                               }
+                               pinfo->common_timing_params[i].base_address =
+                                                       current_mem_base;
+                               pinfo->common_timing_params[i].total_mem =
+                                                       total_ctlr_mem;
+                               total_mem = current_mem_base + total_ctlr_mem;
+                               debug("ctrl %d base 0x%llx\n", i, current_mem_base);
+                               debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
+                       } else {
+                               /* when 3rd controller not interleaved */
+                               current_mem_base = total_mem;
+                               total_ctlr_mem = 0;
+                               pinfo->common_timing_params[i].base_address =
+                                                       current_mem_base;
+                               for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+                                       unsigned long long cap =
+                                               pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i];
+                                       pinfo->dimm_params[i][j].base_address =
+                                               current_mem_base;
+                                       debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base);
+                                       current_mem_base += cap;
+                                       total_ctlr_mem += cap;
+                               }
+                               debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
+                               pinfo->common_timing_params[i].total_mem =
+                                                       total_ctlr_mem;
+                               total_mem += total_ctlr_mem;
                        }
                }
-               pinfo->common_timing_params[0].total_mem = total_mem_per_ctlr;
        } else {
                /*
                 * Simple linear assignment if memory
                 * controllers are not interleaved.
                 */
-               unsigned long long cur_memsize = 0;
                for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-                       u64 total_mem_per_ctlr = 0;
+                       total_ctlr_mem = 0;
                        pinfo->common_timing_params[i].base_address =
-                                               cur_memsize;
+                                               current_mem_base;
                        for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
                                /* Compute DIMM base addresses. */
                                unsigned long long cap =
-                                       pinfo->dimm_params[i][j].capacity;
+                                       pinfo->dimm_params[i][j].capacity >> dbw_cap_adj[i];
                                pinfo->dimm_params[i][j].base_address =
-                                       cur_memsize;
-                               cur_memsize += cap >> dbw_cap_adj[i];
-                               total_mem_per_ctlr += cap >> dbw_cap_adj[i];
+                                       current_mem_base;
+                               debug("ctrl %d dimm %d base 0x%llx\n", i, j, current_mem_base);
+                               current_mem_base += cap;
+                               total_ctlr_mem += cap;
                        }
+                       debug("ctrl %d total 0x%llx\n", i, total_ctlr_mem);
                        pinfo->common_timing_params[i].total_mem =
-                                                       total_mem_per_ctlr;
+                                                       total_ctlr_mem;
+                       total_mem += total_ctlr_mem;
                }
        }
+       debug("Total mem by %s is 0x%llx\n", __func__, total_mem);
 
-       return 0;
+       return total_mem;
 }
 
+/* Use weak function to allow board file to override the address assignment */
+__attribute__((weak, alias("__step_assign_addresses")))
+unsigned long long step_assign_addresses(fsl_ddr_info_t *pinfo,
+                         unsigned int dbw_cap_adj[]);
+
 unsigned long long
 fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
                                       unsigned int size_only)
 {
        unsigned int i, j;
-       unsigned int all_controllers_memctl_interleaving = 0;
-       unsigned int all_controllers_rank_interleaving = 0;
        unsigned long long total_mem = 0;
 
        fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg;
@@ -256,6 +381,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 
        switch (start_step) {
        case STEP_GET_SPD:
+#if defined(CONFIG_DDR_SPD) || defined(CONFIG_SPD_EEPROM)
                /* STEP 1:  Gather all DIMM SPD data */
                for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
                        fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i);
@@ -273,12 +399,21 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
                                        &(pinfo->dimm_params[i][j]);
 
                                retval = compute_dimm_parameters(spd, pdimm, i);
+#ifdef CONFIG_SYS_DDR_RAW_TIMING
+                               if (!i && !j && retval) {
+                                       printf("SPD error on controller %d! "
+                                       "Trying fallback to raw timing "
+                                       "calculation\n", i);
+                                       fsl_ddr_get_dimm_params(pdimm, i, j);
+                               }
+#else
                                if (retval == 2) {
                                        printf("Error: compute_dimm_parameters"
                                        " non-zero returned FATAL value "
                                        "for memctl=%u dimm=%u\n", i, j);
                                        return 0;
                                }
+#endif
                                if (retval) {
                                        debug("Warning: compute_dimm_parameters"
                                        " non-zero return value for memctl=%u "
@@ -287,6 +422,17 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
                        }
                }
 
+#elif defined(CONFIG_SYS_DDR_RAW_TIMING)
+       case STEP_COMPUTE_DIMM_PARMS:
+               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+                       for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
+                               dimm_params_t *pdimm =
+                                       &(pinfo->dimm_params[i][j]);
+                               fsl_ddr_get_dimm_params(pdimm, i, j);
+                       }
+               }
+               debug("Filling dimm parameters from board specific file\n");
+#endif
        case STEP_COMPUTE_COMMON_PARMS:
                /*
                 * STEP 3: Compute a common set of timing parameters
@@ -317,17 +463,14 @@ 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,
-                               dbw_capacity_adjust,
-                               &all_controllers_memctl_interleaving,
-                               &all_controllers_rank_interleaving);
+               check_interleaving_options(pinfo);
+               total_mem = step_assign_addresses(pinfo, dbw_capacity_adjust);
 
        case STEP_COMPUTE_REGS:
                /* STEP 6:  compute controller register values */
-               debug("FSL Memory ctrl cg register computation\n");
+               debug("FSL Memory ctrl register computation\n");
                for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
                        if (timing_params[i].ndimms_present == 0) {
                                memset(&ddr_reg[i], 0,
@@ -347,21 +490,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
                break;
        }
 
-       /* Compute the total amount of memory. */
-
-       /*
-        * If bank interleaving but NOT memory controller interleaving
-        * CS_BNDS describe the quantity of memory on each memory
-        * controller, so the total is the sum across.
-        */
-       if (!all_controllers_memctl_interleaving
-           && all_controllers_rank_interleaving) {
-               total_mem = 0;
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-                       total_mem += timing_params[i].total_mem;
-               }
-
-       } else {
+       {
                /*
                 * Compute the amount of memory available just by
                 * looking for the highest valid CSn_BNDS value.
@@ -399,7 +528,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 phys_size_t fsl_ddr_sdram(void)
 {
        unsigned int i;
-       unsigned int memctl_interleaved;
+       unsigned int law_memctl = LAW_TRGT_IF_DDR_1;
        unsigned long long total_memory;
        fsl_ddr_info_t info;
 
@@ -407,33 +536,26 @@ phys_size_t fsl_ddr_sdram(void)
        memset(&info, 0, sizeof(fsl_ddr_info_t));
 
        /* Compute it once normally. */
-       total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0);
-
-       /* Check for memory controller interleaving. */
-       memctl_interleaved = 0;
-       for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-               memctl_interleaved +=
-                       info.memctl_opts[i].memctl_interleaving;
-       }
-
-       if (memctl_interleaved) {
-               if (memctl_interleaved == CONFIG_NUM_DDR_CONTROLLERS) {
-                       debug("memctl interleaving\n");
-                       /*
-                        * Change the meaning of memctl_interleaved
-                        * to be "boolean".
-                        */
-                       memctl_interleaved = 1;
-               } else {
-                       printf("Warning: memctl interleaving not "
-                               "properly configured on all controllers\n");
-                       memctl_interleaved = 0;
-                       for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++)
-                               info.memctl_opts[i].memctl_interleaving = 0;
-                       debug("Recomputing with memctl_interleaving off.\n");
-                       total_memory = fsl_ddr_compute(&info,
-                                                      STEP_ASSIGN_ADDRESSES,
-                                                      0);
+#ifdef CONFIG_FSL_DDR_INTERACTIVE
+       if (tstc() && (getc() == 'd')) {        /* we got a key press of 'd' */
+               total_memory = fsl_ddr_interactive(&info, 0);
+       } else if (fsl_ddr_interactive_env_var_exists()) {
+               total_memory = fsl_ddr_interactive(&info, 1);
+       } else
+#endif
+               total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0);
+
+       /* setup 3-way interleaving before enabling DDRC */
+       if (info.memctl_opts[0].memctl_interleaving) {
+               switch (info.memctl_opts[0].memctl_interleaving_mode) {
+               case FSL_DDR_3WAY_1KB_INTERLEAVING:
+               case FSL_DDR_3WAY_4KB_INTERLEAVING:
+               case FSL_DDR_3WAY_8KB_INTERLEAVING:
+                       fsl_ddr_set_intl3r(
+                               info.memctl_opts[0].memctl_interleaving_mode);
+                       break;
+               default:
+                       break;
                }
        }
 
@@ -449,24 +571,68 @@ phys_size_t fsl_ddr_sdram(void)
                fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i);
        }
 
-       if (memctl_interleaved) {
-               const unsigned int ctrl_num = 0;
-
-               /* Only set LAWBAR1 if memory controller interleaving is on. */
-               fsl_ddr_set_lawbar(&info.common_timing_params[0],
-                                        memctl_interleaved, ctrl_num);
-       } else {
-               /*
-                * Memory controller interleaving is NOT on;
-                * set each lawbar individually.
-                */
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+       /* program LAWs */
+       for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+               if (info.memctl_opts[i].memctl_interleaving) {
+                       switch (info.memctl_opts[i].memctl_interleaving_mode) {
+                       case FSL_DDR_CACHE_LINE_INTERLEAVING:
+                       case FSL_DDR_PAGE_INTERLEAVING:
+                       case FSL_DDR_BANK_INTERLEAVING:
+                       case FSL_DDR_SUPERBANK_INTERLEAVING:
+                               if (i == 0) {
+                                       law_memctl = LAW_TRGT_IF_DDR_INTRLV;
+                                       fsl_ddr_set_lawbar(&info.common_timing_params[i],
+                                               law_memctl, i);
+                               } else if (i == 2) {
+                                       law_memctl = LAW_TRGT_IF_DDR_INTLV_34;
+                                       fsl_ddr_set_lawbar(&info.common_timing_params[i],
+                                               law_memctl, i);
+                               }
+                               break;
+                       case FSL_DDR_3WAY_1KB_INTERLEAVING:
+                       case FSL_DDR_3WAY_4KB_INTERLEAVING:
+                       case FSL_DDR_3WAY_8KB_INTERLEAVING:
+                               law_memctl = LAW_TRGT_IF_DDR_INTLV_123;
+                               if (i == 0) {
+                                       fsl_ddr_set_lawbar(&info.common_timing_params[i],
+                                               law_memctl, i);
+                               }
+                               break;
+                       case FSL_DDR_4WAY_1KB_INTERLEAVING:
+                       case FSL_DDR_4WAY_4KB_INTERLEAVING:
+                       case FSL_DDR_4WAY_8KB_INTERLEAVING:
+                               law_memctl = LAW_TRGT_IF_DDR_INTLV_1234;
+                               if (i == 0)
+                                       fsl_ddr_set_lawbar(&info.common_timing_params[i],
+                                               law_memctl, i);
+                               /* place holder for future 4-way interleaving */
+                               break;
+                       default:
+                               break;
+                       }
+               } else {
+                       switch (i) {
+                       case 0:
+                               law_memctl = LAW_TRGT_IF_DDR_1;
+                               break;
+                       case 1:
+                               law_memctl = LAW_TRGT_IF_DDR_2;
+                               break;
+                       case 2:
+                               law_memctl = LAW_TRGT_IF_DDR_3;
+                               break;
+                       case 3:
+                               law_memctl = LAW_TRGT_IF_DDR_4;
+                               break;
+                       default:
+                               break;
+                       }
                        fsl_ddr_set_lawbar(&info.common_timing_params[i],
-                                                0, i);
+                                       law_memctl, i);
                }
        }
 
-       debug("total_memory = %llu\n", total_memory);
+       debug("total_memory by %s = %llu\n", __func__, total_memory);
 
 #if !defined(CONFIG_PHYS_64BIT)
        /* Check for 4G or more.  Bad. */