[PATCH v2 7/9] ram: k3-ddrss: Add support for MSMC calculation of DDR inline ECC regions

Kumar, Udit u-kumar1 at ti.com
Thu Aug 7 06:55:49 CEST 2025


On 7/30/2025 7:07 PM, Neha Malcom Francis wrote:
> Add support for calculation of the protected regions for each DDR in
> multi-DDR systems. Since MSMC is the parent node of the individual DDRs
> as well as responsible for their interleaving, it only makes sense for
> MSMC to contain the logic for dividing the regions.
>
> Signed-off-by: Neha Malcom Francis <n-francis at ti.com>
> ---
>   drivers/ram/k3-ddrss/k3-ddrss.c | 120 ++++++++++++++++++++++++++++++--
>   1 file changed, 113 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/ram/k3-ddrss/k3-ddrss.c b/drivers/ram/k3-ddrss/k3-ddrss.c
> index 2d2558eaa9e..1c2e5e1835b 100644
> --- a/drivers/ram/k3-ddrss/k3-ddrss.c
> +++ b/drivers/ram/k3-ddrss/k3-ddrss.c
> @@ -59,6 +59,7 @@
>   
>   #define SINGLE_DDR_SUBSYSTEM	0x1
>   #define MULTI_DDR_SUBSYSTEM	0x2
> +#define MAX_MULTI_DDR 4
>   
>   #define MULTI_DDR_CFG0  0x00114100
>   #define MULTI_DDR_CFG1  0x00114104
> @@ -82,6 +83,24 @@ enum intrlv_gran {
>   	GRAN_16GB
>   };
>   
> +u64 gran_bytes[] = {
> +	0x80,
> +	0x200,
> +	0x800,
> +	0x1000,
> +	0x4000,
> +	0x8000,
> +	0x80000,
> +	0x40000000,
> +	0x60000000,
> +	0x80000000,
> +	0xC0000000,
> +	0x100000000,
> +	0x180000000,
> +	0x200000000,
> +	0x400000000
> +};
> +
>   enum intrlv_size {
>   	SIZE_0,
>   	SIZE_128MB,
> @@ -121,6 +140,13 @@ enum emif_active {
>   	EMIF_ALL
>   };
>   
> +#define K3_DDRSS_MAX_ECC_REG		3

Please see, adding in patch 2/8 and add/remove in this patch can be avoided


> +
> +struct k3_ddrss_ecc_region {
> +	u64 start;
> +	u64 range;
> +};
> +
>   struct k3_msmc {
>   	enum intrlv_gran gran;
>   	enum intrlv_size size;
> @@ -128,13 +154,7 @@ struct k3_msmc {
>   	enum emif_config config;
>   	enum emif_active active;
>   	u32 num_ddr;
> -};
> -
> -#define K3_DDRSS_MAX_ECC_REG		3
> -
> -struct k3_ddrss_ecc_region {
> -	u64 start;
> -	u64 range;
> +	struct k3_ddrss_ecc_region R0[MAX_MULTI_DDR];
>   };
>   
>   struct k3_ddrss_desc {
> @@ -936,6 +956,80 @@ U_BOOT_DRIVER(k3_ddrss) = {
>   	.priv_auto		= sizeof(struct k3_ddrss_desc),
>   };
>   
> +__maybe_unused static int k3_msmc_calculate_r0_regions(struct k3_msmc *msmc)
> +{
> +	u32 n1;
> +	u32 size, ret = 0;
> +	u32 gran = gran_bytes[msmc->gran];
> +	u32 num_ddr = msmc->num_ddr;
> +	struct k3_ddrss_ecc_region *range = NULL;
> +	struct k3_ddrss_ecc_region R[num_ddr];
> +
> +	range = kzalloc(sizeof(range), GFP_KERNEL);
> +	if (!range) {
> +		ret = -ENOMEM;
> +		return ret;
> +	}
> +
> +	k3_ddrss_ddr_inline_ecc_base_size_calc(range);
> +
> +	if (!range->range) {
> +		ret = -EINVAL;
> +		goto range_err;
> +	}
> +
> +	memset(R, 0, num_ddr);
> +
> +	/* Find the first controller in the range */
> +	n1 = ((range->start / gran) % num_ddr);
> +	size = range->range;
> +
> +	if (size < gran) {
> +		R[n1].start = range->start - 0x80000000;
> +		R[n1].range = range->start + range->range - 0x80000000;
> +	} else {
> +		u32 chunk_start_addr = range->start;
> +		u32 chunk_size = range->range;
> +
> +		while (chunk_size > 0) {
> +			u32 edge;
> +			u32 end = range->start + range->range;
> +
> +			if ((chunk_start_addr % gran) == 0)
> +				edge = chunk_start_addr + gran;
> +			else
> +				edge = ((chunk_start_addr + (gran - 1)) & (-gran));
> +
> +			if (edge > end)
> +				break;
> +
> +			if (R[n1].start == 0)
> +				R[n1].start = chunk_start_addr;
> +
> +			R[n1].range = edge - R[n1].start;
> +			chunk_size = end - edge;
> +			chunk_start_addr = edge;
> +
> +			if (n1 == (num_ddr - 1))
> +				n1 = 0;
> +			else
> +				n1++;
> +		}
> +
> +		for (int i = 0; i < num_ddr; i++)
> +			R[i].start = (R[i].start - 0x80000000 - (gran * i)) / num_ddr;
> +	}
> +
> +	for (int i = 0; i < num_ddr; i++) {
> +		msmc->R0[i].start = R[i].start;
> +		msmc->R0[i].range = R[i].range;
> +	}
> +
> +range_err:
> +	free(range);
> +	return ret;
> +}
> +
>   static int k3_msmc_set_config(struct k3_msmc *msmc)
>   {
>   	u32 ddr_cfg0 = 0;
> @@ -1015,6 +1109,18 @@ static int k3_msmc_probe(struct udevice *dev)
>   	}
>   	msmc->num_ddr = ret;
>   
> +	if (IS_ENABLED(CONFIG_K3_MULTI_DDR) && IS_ENABLED(CONFIG_K3_INLINE_ECC)) {
> +		ret = k3_msmc_calculate_r0_regions(msmc);
> +		if (ret) {
> +			/* Default to enabling inline ECC for entire DDR region */
> +			debug("%s: calculation of inline ECC regions failed, defaulting to entire region\n",
> +			      __func__);
> +
> +			/* Use first R0 entry as a flag to denote MSMC calculation failure */
> +			msmc->R0[0].start = -1;
> +		}
> +	}
> +
>   	return 0;
>   }
>   


More information about the U-Boot mailing list