summaryrefslogtreecommitdiffstats
path: root/drivers/ddr/fsl/main.c
diff options
context:
space:
mode:
authorYork Sun <yorksun@freescale.com>2014-08-01 15:51:00 -0700
committerYork Sun <yorksun@freescale.com>2014-09-25 08:36:18 -0700
commit1d71efbb0345ff3a8ac45e62bef36813abe1703e (patch)
treef607e330c200428f1e37a1fd3aba8873efdbb634 /drivers/ddr/fsl/main.c
parente211c12e773881f6bef60143df4764402a56de34 (diff)
downloadtalos-obmc-uboot-1d71efbb0345ff3a8ac45e62bef36813abe1703e.tar.gz
talos-obmc-uboot-1d71efbb0345ff3a8ac45e62bef36813abe1703e.zip
driver/ddr: Restruct driver to allow standalone memory space
U-boot has been initializing DDR for the main memory. The presumption is the memory stays as a big continuous block, either linear or interleaved. This change is to support putting some DDR controllers to separated space without counting into main memory. The standalone memory controller could use different number of DIMM slots. Signed-off-by: York Sun <yorksun@freescale.com>
Diffstat (limited to 'drivers/ddr/fsl/main.c')
-rw-r--r--drivers/ddr/fsl/main.c244
1 files changed, 164 insertions, 80 deletions
diff --git a/drivers/ddr/fsl/main.c b/drivers/ddr/fsl/main.c
index 5e001fcb99..b43b669e41 100644
--- a/drivers/ddr/fsl/main.c
+++ b/drivers/ddr/fsl/main.c
@@ -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);
OpenPOWER on IntegriCloud