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

Neha Malcom Francis n-francis at ti.com
Mon Jan 27 15:22:17 CET 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 | 43 +++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c
index 205dce51799..8429dddeb58 100644
--- a/drivers/ram/k3-ddrss/k3-ddrss.c
+++ b/drivers/ram/k3-ddrss/k3-ddrss.c
@@ -808,8 +808,10 @@ static int k3_ddrss_probe(struct udevice *dev)
 	u64 end;
 	int ret;
 	struct k3_ddrss_desc *ddrss = dev_get_priv(dev);
+	__maybe_unused u32 inst, ddr_ram_size, ecc_res;
 	__maybe_unused struct k3_ddrss_data *ddrss_data = (struct k3_ddrss_data *)dev_get_driver_data(dev);
 	__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);
 
@@ -863,14 +865,51 @@ static int k3_ddrss_probe(struct udevice *dev)
 			ddrss->ecc_range.range = range->range;
 		}
 
+#if !CONFIG_IS_ENABLED(K3_MULTI_DDR)
 		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;
 
-		if (end > (ddrss->ddr_ram_size - ddrss->ecc_reserved_space))
-			ddrss->ecc_regions[0].range = ddrss->ddr_ram_size - ddrss->ecc_reserved_space;
+		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];
+#else
+
+		/* In case multi-DDR, we rely on MSMC's calculation of regions for each DDR */
+		msmc_parent = kzalloc(sizeof(msmc_parent), GFP_KERNEL);
+		if (!msmc_parent) {
+			debug("%s: failed to allocate msmc_parent\n", __func__);
+			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);
+#endif
 
 		k3_ddrss_lpddr4_ecc_init(ddrss);
 	}
-- 
2.34.1



More information about the U-Boot mailing list