]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - drivers/ddr/fsl/main.c
driver/ddr: Restruct driver to allow standalone memory space
[people/ms/u-boot.git] / drivers / ddr / fsl / main.c
index 5e001fcb99474605d0c5fadde287e1ef257184b5..b43b669e41ffc9be2b1bf812de30fa1eb714d6ff 100644 (file)
@@ -135,7 +135,7 @@ __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 ctrl_num, unsigned int dimm_slots_per_ctrl)
 {
        unsigned int i;
        unsigned int i2c_address = 0;
@@ -145,14 +145,14 @@ void fsl_ddr_get_spd(generic_spd_eeprom_t *ctrl_dimms_spd,
                return;
        }
 
-       for (i = 0; i < CONFIG_DIMM_SLOTS_PER_CTLR; i++) {
+       for (i = 0; i < dimm_slots_per_ctrl; 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)
+                     unsigned int ctrl_num, unsigned int dimm_slots_per_ctrl)
 {
 }
 #endif /* SPD_EEPROM_ADDRESSx */
@@ -231,9 +231,11 @@ const char * step_to_string(unsigned int step) {
 static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
                          unsigned int dbw_cap_adj[])
 {
-       int i, j;
+       unsigned int i, j;
        unsigned long long total_mem, current_mem_base, total_ctlr_mem;
        unsigned long long rank_density, ctlr_density = 0;
+       unsigned int first_ctrl = pinfo->first_ctrl;
+       unsigned int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
 
        /*
         * If a reduced data width is requested, but the SPD
@@ -241,7 +243,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
         * computed dimm capacities accordingly before
         * assigning addresses.
         */
-       for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+       for (i = first_ctrl; i <= last_ctrl; i++) {
                unsigned int found = 0;
 
                switch (pinfo->memctl_opts[i].data_bus_width) {
@@ -295,12 +297,12 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
                debug("dbw_cap_adj[%d]=%d\n", i, dbw_cap_adj[i]);
        }
 
-       current_mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+       current_mem_base = pinfo->mem_base;
        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 &
+       if (pinfo->memctl_opts[first_ctrl].memctl_interleaving) {
+               rank_density = pinfo->dimm_params[first_ctrl][0].rank_density >>
+                                       dbw_cap_adj[first_ctrl];
+               switch (pinfo->memctl_opts[first_ctrl].ba_intlv_ctl &
                                        FSL_DDR_CS0_CS1_CS2_CS3) {
                case FSL_DDR_CS0_CS1_CS2_CS3:
                        ctlr_density = 4 * rank_density;
@@ -316,7 +318,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
                }
                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++) {
+               for (i = first_ctrl; i <= last_ctrl; i++) {
                        if (pinfo->memctl_opts[i].memctl_interleaving) {
                                switch (pinfo->memctl_opts[i].memctl_interleaving_mode) {
                                case FSL_DDR_256B_INTERLEAVING:
@@ -372,7 +374,7 @@ static unsigned long long __step_assign_addresses(fsl_ddr_info_t *pinfo,
                 * Simple linear assignment if memory
                 * controllers are not interleaved.
                 */
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+               for (i = first_ctrl; i <= last_ctrl; i++) {
                        total_ctlr_mem = 0;
                        pinfo->common_timing_params[i].base_address =
                                                current_mem_base;
@@ -408,18 +410,23 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 {
        unsigned int i, j;
        unsigned long long total_mem = 0;
-       int assert_reset;
+       int assert_reset = 0;
+       unsigned int first_ctrl =  pinfo->first_ctrl;
+       unsigned int last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
+       __maybe_unused int retval;
+       __maybe_unused bool goodspd = false;
+       __maybe_unused int dimm_slots_per_ctrl = pinfo->dimm_slots_per_ctrl;
 
        fsl_ddr_cfg_regs_t *ddr_reg = pinfo->fsl_ddr_config_reg;
        common_timing_params_t *timing_params = pinfo->common_timing_params;
-       assert_reset = board_need_mem_reset();
+       if (pinfo->board_need_mem_reset)
+               assert_reset = pinfo->board_need_mem_reset();
 
        /* data bus width capacity adjust shift amount */
        unsigned int dbw_capacity_adjust[CONFIG_NUM_DDR_CONTROLLERS];
 
-       for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+       for (i = first_ctrl; i <= last_ctrl; i++)
                dbw_capacity_adjust[i] = 0;
-       }
 
        debug("starting at step %u (%s)\n",
              start_step, step_to_string(start_step));
@@ -428,28 +435,28 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int 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);
+               for (i = first_ctrl; i <= last_ctrl; i++) {
+                       fsl_ddr_get_spd(pinfo->spd_installed_dimms[i], i,
+                                       dimm_slots_per_ctrl);
                }
 
        case STEP_COMPUTE_DIMM_PARMS:
                /* STEP 2:  Compute DIMM parameters from SPD data */
 
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+               for (i = first_ctrl; i <= last_ctrl; i++) {
                        for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
-                               unsigned int retval;
                                generic_spd_eeprom_t *spd =
                                        &(pinfo->spd_installed_dimms[i][j]);
                                dimm_params_t *pdimm =
                                        &(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);
+                                       retval = fsl_ddr_get_dimm_params(pdimm,
+                                                                        i, j);
                                }
 #else
                                if (retval == 2) {
@@ -463,13 +470,26 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
                                        debug("Warning: compute_dimm_parameters"
                                        " non-zero return value for memctl=%u "
                                        "dimm=%u\n", i, j);
+                               } else {
+                                       goodspd = true;
                                }
                        }
                }
+               if (!goodspd) {
+                       /*
+                        * No valid SPD found
+                        * Throw an error if this is for main memory, i.e.
+                        * first_ctrl == 0. Otherwise, siliently return 0
+                        * as the memory size.
+                        */
+                       if (first_ctrl == 0)
+                               printf("Error: No valid SPD detected.\n");
 
+                       return 0;
+               }
 #elif defined(CONFIG_SYS_DDR_RAW_TIMING)
        case STEP_COMPUTE_DIMM_PARMS:
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+               for (i = first_ctrl; i <= last_ctrl; i++) {
                        for (j = 0; j < CONFIG_DIMM_SLOTS_PER_CTLR; j++) {
                                dimm_params_t *pdimm =
                                        &(pinfo->dimm_params[i][j]);
@@ -483,7 +503,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
                 * STEP 3: Compute a common set of timing parameters
                 * suitable for all of the DIMMs on each memory controller
                 */
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+               for (i = first_ctrl; i <= last_ctrl; i++) {
                        debug("Computing lowest common DIMM"
                                " parameters for memctl=%u\n", i);
                        compute_lowest_common_dimm_parameters(
@@ -494,7 +514,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
 
        case STEP_GATHER_OPTS:
                /* STEP 4:  Gather configuration requirements from user */
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+               for (i = first_ctrl; i <= last_ctrl; i++) {
                        debug("Reloading memory controller "
                                "configuration options for memctl=%u\n", i);
                        /*
@@ -516,9 +536,13 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
                        if (timing_params[i].all_dimms_registered)
                                assert_reset = 1;
                }
-               if (assert_reset) {
-                       debug("Asserting mem reset\n");
-                       board_assert_mem_reset();
+               if (assert_reset && !size_only) {
+                       if (pinfo->board_mem_reset) {
+                               debug("Asserting mem reset\n");
+                               pinfo->board_mem_reset();
+                       } else {
+                               debug("Asserting mem reset missing\n");
+                       }
                }
 
        case STEP_ASSIGN_ADDRESSES:
@@ -530,7 +554,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
        case STEP_COMPUTE_REGS:
                /* STEP 6:  compute controller register values */
                debug("FSL Memory ctrl register computation\n");
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+               for (i = first_ctrl; i <= last_ctrl; i++) {
                        if (timing_params[i].ndimms_present == 0) {
                                memset(&ddr_reg[i], 0,
                                        sizeof(fsl_ddr_cfg_regs_t));
@@ -558,7 +582,7 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
                 */
                unsigned int max_end = 0;
 
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+               for (i = first_ctrl; i <= last_ctrl; i++) {
                        for (j = 0; j < CONFIG_CHIP_SELECTS_PER_CTRL; j++) {
                                fsl_ddr_cfg_regs_t *reg = &ddr_reg[i];
                                if (reg->cs[j].config & 0x80000000) {
@@ -578,53 +602,45 @@ fsl_ddr_compute(fsl_ddr_info_t *pinfo, unsigned int start_step,
                }
 
                total_mem = 1 + (((unsigned long long)max_end << 24ULL) |
-                           0xFFFFFFULL) - CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+                           0xFFFFFFULL) - pinfo->mem_base;
        }
 
        return total_mem;
 }
 
-/*
- * fsl_ddr_sdram() -- this is the main function to be called by
- *     initdram() in the board file.
- *
- * It returns amount of memory configured in bytes.
- */
-phys_size_t fsl_ddr_sdram(void)
+phys_size_t __fsl_ddr_sdram(fsl_ddr_info_t *pinfo)
 {
-       unsigned int i;
+       unsigned int i, first_ctrl, last_ctrl;
 #ifdef CONFIG_PPC
        unsigned int law_memctl = LAW_TRGT_IF_DDR_1;
 #endif
        unsigned long long total_memory;
-       fsl_ddr_info_t info;
-       int deassert_reset;
+       int deassert_reset = 0;
 
-       /* Reset info structure. */
-       memset(&info, 0, sizeof(fsl_ddr_info_t));
+       first_ctrl = pinfo->first_ctrl;
+       last_ctrl = first_ctrl + pinfo->num_ctrls - 1;
 
        /* Compute it once normally. */
 #ifdef CONFIG_FSL_DDR_INTERACTIVE
        if (tstc() && (getc() == 'd')) {        /* we got a key press of 'd' */
-               total_memory = fsl_ddr_interactive(&info, 0);
+               total_memory = fsl_ddr_interactive(pinfo, 0);
        } else if (fsl_ddr_interactive_env_var_exists()) {
-               total_memory = fsl_ddr_interactive(&info, 1);
+               total_memory = fsl_ddr_interactive(pinfo, 1);
        } else
 #endif
-               total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 0);
+               total_memory = fsl_ddr_compute(pinfo, 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;
-               }
+       switch (pinfo->memctl_opts[first_ctrl].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(
+                       pinfo->memctl_opts[first_ctrl].
+                       memctl_interleaving_mode);
+               break;
+       default:
+               break;
        }
 
        /*
@@ -637,14 +653,15 @@ phys_size_t fsl_ddr_sdram(void)
         * For non-registered DIMMs, initialization can go through but it is
         * also OK to follow the same flow.
         */
-       deassert_reset = board_need_mem_reset();
-       for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
-               if (info.common_timing_params[i].all_dimms_registered)
+       if (pinfo->board_need_mem_reset)
+               deassert_reset = pinfo->board_need_mem_reset();
+       for (i = first_ctrl; i <= last_ctrl; i++) {
+               if (pinfo->common_timing_params[i].all_dimms_registered)
                        deassert_reset = 1;
        }
-       for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+       for (i = first_ctrl; i <= last_ctrl; i++) {
                debug("Programming controller %u\n", i);
-               if (info.common_timing_params[i].ndimms_present == 0) {
+               if (pinfo->common_timing_params[i].ndimms_present == 0) {
                        debug("No dimms present on controller %u; "
                                        "skipping programming\n", i);
                        continue;
@@ -653,45 +670,58 @@ phys_size_t fsl_ddr_sdram(void)
                 * The following call with step = 1 returns before enabling
                 * the controller. It has to finish with step = 2 later.
                 */
-               fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]), i,
+               fsl_ddr_set_memctl_regs(&(pinfo->fsl_ddr_config_reg[i]), i,
                                        deassert_reset ? 1 : 0);
        }
        if (deassert_reset) {
                /* Use board FPGA or GPIO to deassert reset signal */
-               debug("Deasserting mem reset\n");
-               board_deassert_mem_reset();
-               for (i = 0; i < CONFIG_NUM_DDR_CONTROLLERS; i++) {
+               if (pinfo->board_mem_de_reset) {
+                       debug("Deasserting mem reset\n");
+                       pinfo->board_mem_de_reset();
+               } else {
+                       debug("Deasserting mem reset missing\n");
+               }
+               for (i = first_ctrl; i <= last_ctrl; i++) {
                        /* Call with step = 2 to continue initialization */
-                       fsl_ddr_set_memctl_regs(&(info.fsl_ddr_config_reg[i]),
+                       fsl_ddr_set_memctl_regs(&(pinfo->fsl_ddr_config_reg[i]),
                                                i, 2);
                }
        }
 
 #ifdef CONFIG_PPC
        /* 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) {
+       for (i = first_ctrl; i <= last_ctrl; 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:
+                               if (i % 2)
+                                       break;
                                if (i == 0) {
                                        law_memctl = LAW_TRGT_IF_DDR_INTRLV;
-                                       fsl_ddr_set_lawbar(&info.common_timing_params[i],
+                                       fsl_ddr_set_lawbar(
+                                               &pinfo->common_timing_params[i],
                                                law_memctl, i);
-                               } else if (i == 2) {
+                               }
+#if CONFIG_NUM_DDR_CONTROLLERS > 3
+                               else if (i == 2) {
                                        law_memctl = LAW_TRGT_IF_DDR_INTLV_34;
-                                       fsl_ddr_set_lawbar(&info.common_timing_params[i],
+                                       fsl_ddr_set_lawbar(
+                                               &pinfo->common_timing_params[i],
                                                law_memctl, i);
                                }
+#endif
                                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],
+                                       fsl_ddr_set_lawbar(
+                                               &pinfo->common_timing_params[i],
                                                law_memctl, i);
                                }
                                break;
@@ -700,7 +730,8 @@ phys_size_t fsl_ddr_sdram(void)
                        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],
+                                       fsl_ddr_set_lawbar(
+                                               &pinfo->common_timing_params[i],
                                                law_memctl, i);
                                /* place holder for future 4-way interleaving */
                                break;
@@ -724,8 +755,8 @@ phys_size_t fsl_ddr_sdram(void)
                        default:
                                break;
                        }
-                       fsl_ddr_set_lawbar(&info.common_timing_params[i],
-                                       law_memctl, i);
+                       fsl_ddr_set_lawbar(&pinfo->common_timing_params[i],
+                                          law_memctl, i);
                }
        }
 #endif
@@ -734,7 +765,7 @@ phys_size_t fsl_ddr_sdram(void)
 
 #if !defined(CONFIG_PHYS_64BIT)
        /* Check for 4G or more.  Bad. */
-       if (total_memory >= (1ull << 32)) {
+       if ((first_ctrl == 0) && (total_memory >= (1ull << 32))) {
                puts("Detected ");
                print_size(total_memory, " of memory\n");
                printf("       This U-Boot only supports < 4G of DDR\n");
@@ -748,8 +779,56 @@ phys_size_t fsl_ddr_sdram(void)
 }
 
 /*
- * fsl_ddr_sdram_size() - This function only returns the size of the total
- * memory without setting ddr control registers.
+ * fsl_ddr_sdram(void) -- this is the main function to be
+ * called by initdram() in the board file.
+ *
+ * It returns amount of memory configured in bytes.
+ */
+phys_size_t fsl_ddr_sdram(void)
+{
+       fsl_ddr_info_t info;
+
+       /* Reset info structure. */
+       memset(&info, 0, sizeof(fsl_ddr_info_t));
+       info.mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+       info.first_ctrl = 0;
+       info.num_ctrls = CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS;
+       info.dimm_slots_per_ctrl = CONFIG_DIMM_SLOTS_PER_CTLR;
+       info.board_need_mem_reset = board_need_mem_reset;
+       info.board_mem_reset = board_assert_mem_reset;
+       info.board_mem_de_reset = board_deassert_mem_reset;
+
+       return __fsl_ddr_sdram(&info);
+}
+
+#ifdef CONFIG_SYS_FSL_OTHER_DDR_NUM_CTRLS
+phys_size_t fsl_other_ddr_sdram(unsigned long long base,
+                               unsigned int first_ctrl,
+                               unsigned int num_ctrls,
+                               unsigned int dimm_slots_per_ctrl,
+                               int (*board_need_reset)(void),
+                               void (*board_reset)(void),
+                               void (*board_de_reset)(void))
+{
+       fsl_ddr_info_t info;
+
+       /* Reset info structure. */
+       memset(&info, 0, sizeof(fsl_ddr_info_t));
+       info.mem_base = base;
+       info.first_ctrl = first_ctrl;
+       info.num_ctrls = num_ctrls;
+       info.dimm_slots_per_ctrl = dimm_slots_per_ctrl;
+       info.board_need_mem_reset = board_need_reset;
+       info.board_mem_reset = board_reset;
+       info.board_mem_de_reset = board_de_reset;
+
+       return __fsl_ddr_sdram(&info);
+}
+#endif
+
+/*
+ * fsl_ddr_sdram_size(first_ctrl, last_intlv) - This function only returns the
+ * size of the total memory without setting ddr control registers.
  */
 phys_size_t
 fsl_ddr_sdram_size(void)
@@ -758,6 +837,11 @@ fsl_ddr_sdram_size(void)
        unsigned long long total_memory = 0;
 
        memset(&info, 0 , sizeof(fsl_ddr_info_t));
+       info.mem_base = CONFIG_SYS_FSL_DDR_SDRAM_BASE_PHY;
+       info.first_ctrl = 0;
+       info.num_ctrls = CONFIG_SYS_FSL_DDR_MAIN_NUM_CTRLS;
+       info.dimm_slots_per_ctrl = CONFIG_DIMM_SLOTS_PER_CTLR;
+       info.board_need_mem_reset = NULL;
 
        /* Compute it once normally. */
        total_memory = fsl_ddr_compute(&info, STEP_GET_SPD, 1);