[PATCH v2 8/9] ram: k3-ddrss: Add support for partial inline ECC in multi-DDR systems

Neha Malcom Francis n-francis at ti.com
Wed Jul 30 15:37:19 CEST 2025


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-francis at ti.com>
---
 drivers/ram/k3-ddrss/k3-ddrss.c | 58 ++++++++++++++++++++++++++++-----
 1 file changed, 50 insertions(+), 8 deletions(-)

diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c
index 1c2e5e1835b..e00711a2235 100644
--- a/drivers/ram/k3-ddrss/k3-ddrss.c
+++ b/drivers/ram/k3-ddrss/k3-ddrss.c
@@ -828,11 +828,12 @@ 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 u32 ddr_ram_size, ecc_res;
+	__maybe_unused u32 inst, ddr_ram_size, ecc_res, 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);
 
@@ -873,26 +874,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;
 		}
 
-		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



More information about the U-Boot mailing list