[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