The existing approach does not account for interleaving in the DDRs when setting up regions. There is support for MSMC to calculate the regions for each DDR, so modify k3_ddrss_probe to set the regions accordingly for multi-DDR systems.
Signed-off-by: Neha Malcom Francis <n-fran...@ti.com> --- No change since v2 drivers/ram/k3-ddrss/k3-ddrss.c | 62 ++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c index cb1863a6e9a..0f428374818 100644 --- a/drivers/ram/k3-ddrss/k3-ddrss.c +++ b/drivers/ram/k3-ddrss/k3-ddrss.c @@ -829,11 +829,13 @@ static void k3_ddrss_lpddr4_ecc_init(struct k3_ddrss_desc *ddrss) static int k3_ddrss_probe(struct udevice *dev) { - u64 end; + u64 end, bank0, bank1; int ret; struct k3_ddrss_desc *ddrss = dev_get_priv(dev); __maybe_unused u64 ddr_ram_size, ecc_res; + __maybe_unused u32 inst, st; __maybe_unused struct k3_ddrss_ecc_region *range = &ddrss->ecc_range; + __maybe_unused struct k3_msmc *msmc_parent = NULL; debug("%s(dev=%p)\n", __func__, dev); @@ -874,31 +876,67 @@ static int k3_ddrss_probe(struct udevice *dev) k3_ddrss_ddr_inline_ecc_base_size_calc(range); end = ddrss->ecc_range.start + ddrss->ecc_range.range; + inst = ddrss->instance; ddr_ram_size = ddrss->ddr_ram_size; ecc_res = ddrss->ecc_reserved_space; + bank0 = ddrss->ddr_bank_base[0]; + bank1 = ddrss->ddr_bank_base[1]; if (!range->range) { /* Configure entire DDR space by default */ debug("%s: Defaulting to protecting entire DDR space using inline ECC\n", __func__); - ddrss->ecc_range.start = ddrss->ddr_bank_base[0]; + ddrss->ecc_range.start = bank0; ddrss->ecc_range.range = ddr_ram_size - ecc_res; } else { ddrss->ecc_range.start = range->start; ddrss->ecc_range.range = range->range; } - /* - * As we are converting the system address to the DDR controller - * address, account for case when the region is in the second - * bank - */ - if (end > (ddr_ram_size - ecc_res)) - ddrss->ecc_regions[0].range = ddr_ram_size - ecc_res; - else - ddrss->ecc_regions[0].range = ddrss->ecc_range.range; + st = ddrss->ecc_range.start; + + if (!CONFIG_IS_ENABLED(K3_MULTI_DDR)) { + if (end > (ddr_ram_size - ecc_res)) + ddrss->ecc_regions[0].range = ddr_ram_size - ecc_res; + else + ddrss->ecc_regions[0].range = ddrss->ecc_range.range; - ddrss->ecc_regions[0].start = ddrss->ecc_range.start - ddrss->ddr_bank_base[0]; + /* Check in which bank we are */ + if (st > bank1) + ddrss->ecc_regions[0].start = st - bank1 + ddrss->ddr_bank_size[0]; + else + ddrss->ecc_regions[0].start = st - bank0; + } else { + /* For multi-DDR, we rely on MSMC's calculation of regions for each DDR */ + msmc_parent = kzalloc(sizeof(msmc_parent), GFP_KERNEL); + if (!msmc_parent) + return -ENOMEM; + + msmc_parent = dev_get_priv(dev->parent); + if (!msmc_parent) { + printf("%s: could not get MSMC parent to set up inline ECC regions\n", + __func__); + kfree(msmc_parent); + return -EINVAL; + } + + if (msmc_parent->R0[0].start < 0) { + /* Configure entire DDR space by default */ + ddrss->ecc_regions[0].start = ddrss->ddr_bank_base[0]; + ddrss->ecc_regions[0].range = ddr_ram_size - ecc_res; + } else { + end = msmc_parent->R0[inst].start + msmc_parent->R0[inst].range; + + if (end > (ddr_ram_size - ecc_res)) + ddrss->ecc_regions[0].range = ddr_ram_size - ecc_res; + else + ddrss->ecc_regions[0].range = msmc_parent->R0[inst].range; + + ddrss->ecc_regions[0].start = msmc_parent->R0[inst].start; + } + + kfree(msmc_parent); + } k3_ddrss_lpddr4_ecc_init(ddrss); } -- 2.34.1