[PATCH v2 01/13] imx9: scmi: Get DDR size through SM SCMI API
alice.guo at oss.nxp.com
alice.guo at oss.nxp.com
Sat Feb 28 01:22:19 CET 2026
From: Ye Li <ye.li at nxp.com>
System Manager(SM) has implemented the MISC protocol to retrieve DDR
information. Using this API, U-Boot can obtain the DDR size dynamically
instead of relying on static configuration macros.
This change addresses the DDR ECC enabled case, where 1/8 of the total
DDR size is reserved for ECC data. The scmi_misc_ddrinfo() returns the
DDR size with EEC overhead already deducted.
Implementation details:
- Query the DDR size via scmi_misc_ddrinfo()
- Replace direct REG_DDR_CS[0,1]_BNDS register reads with SCMI call
- Switch from PHYS_SDRAM[x]_SIZE macros to runtime detection
- Secure memory size is set to 2GB (0x80000000)
- For backward compatibility with older SM firmware, fall back to
static PHYS_SDRAM[x]_SIZE configuration if the SCMI call fails
Signed-off-by: Ye Li <ye.li at nxp.com>
Signed-off-by: Alice Guo <alice.guo at nxp.com>
---
arch/arm/include/asm/mach-imx/sys_proto.h | 37 +++++++++++++++
arch/arm/mach-imx/imx9/scmi/soc.c | 75 +++++++++++++++++++++++++------
include/scmi_protocols.h | 3 +-
3 files changed, 100 insertions(+), 15 deletions(-)
diff --git a/arch/arm/include/asm/mach-imx/sys_proto.h b/arch/arm/include/asm/mach-imx/sys_proto.h
index 46da7a1eff5..13857b921a0 100644
--- a/arch/arm/include/asm/mach-imx/sys_proto.h
+++ b/arch/arm/include/asm/mach-imx/sys_proto.h
@@ -254,6 +254,43 @@ struct scmi_rom_passover_get_out {
u32 passover[(sizeof(rom_passover_t) + 8) / 4];
};
+/**
+ * struct scmi_ddr_info_out - Get DDR memory region info
+ * @status: Error code
+ * @attributes: Region attributes:
+ * Bit[31] ECC enable.
+ * Set to 1 if ECC enabled.
+ * Set to 0 if ECC disabled or not configured.
+ * Bits[30:18] Reserved, must be zero.
+ * Bits[17:16] Number of DDR memory regions.
+ * Bits[15:11] Reserved, must be zero.
+ * Bits[10:8] Width.
+ * Bus width is 16 << this field.
+ * So 0=16, 1=32, 2=64, etc.
+ * Bits[7:5] Reserved, must be zero.
+ * Bits[4:0] DDR type.
+ * Set to 0 if LPDDR5.
+ * Set to 1 if LPDDR5X.
+ * Set to 2 if LPDDR4.
+ * Set to 3 if LPDDR4X
+ * @mts: DDR speed in megatransfers per second
+ * @startlow: The lower 32 bits of the physical start address of the region
+ * @starthigh: The upper 32 bits of the physical start address of the region
+ * @endlow: The lower 32 bits of the physical end address of the region. This
+ * excludes any DDR used to store ECC data
+ * @endhigh: The upper 32 bits of the physical end address of the region. This
+ * excludes any DDR used to store ECC data
+ */
+struct scmi_ddr_info_out {
+ s32 status;
+ u32 attributes;
+ u32 mts;
+ u32 startlow;
+ u32 starthigh;
+ u32 endlow;
+ u32 endhigh;
+};
+
#endif
/* For i.MX ULP */
diff --git a/arch/arm/mach-imx/imx9/scmi/soc.c b/arch/arm/mach-imx/imx9/scmi/soc.c
index c1458ccca3c..2ac2a93e796 100644
--- a/arch/arm/mach-imx/imx9/scmi/soc.c
+++ b/arch/arm/mach-imx/imx9/scmi/soc.c
@@ -58,6 +58,34 @@ uint32_t scmi_get_rom_data(rom_passover_t *rom_data)
return 0;
}
+int scmi_misc_ddrinfo(u32 ddrc_id, struct scmi_ddr_info_out *out)
+{
+ u32 in = ddrc_id;
+ struct scmi_msg msg = {
+ .protocol_id = SCMI_PROTOCOL_ID_IMX_MISC,
+ .message_id = SCMI_MISC_DDR_INFO_GET,
+ .in_msg = (u8 *)&in,
+ .in_msg_sz = sizeof(in),
+ .out_msg = (u8 *)out,
+ .out_msg_sz = sizeof(*out),
+ };
+ int ret;
+ struct udevice *dev;
+
+ ret = uclass_get_device_by_name(UCLASS_CLK, "protocol at 14", &dev);
+ if (ret)
+ return ret;
+
+ ret = devm_scmi_process_msg(dev, &msg);
+ if (ret != 0 || out->status != 0) {
+ printf("Failed to get ddr cfg, scmi_err = %d\n",
+ out->status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
#if IS_ENABLED(CONFIG_ENV_IS_IN_MMC)
__weak int board_mmc_get_env_dev(int devno)
{
@@ -335,25 +363,44 @@ void enable_caches(void)
__weak int board_phys_sdram_size(phys_size_t *size)
{
+ struct scmi_ddr_info_out ddr_info = {0};
+ int ret;
+ u32 ddrc_id = 0, ddrc_num = 1;
phys_size_t start, end;
- phys_size_t val;
if (!size)
return -EINVAL;
- val = readl(REG_DDR_CS0_BNDS);
- start = (val >> 16) << 24;
- end = (val & 0xFFFF);
- end = end ? end + 1 : 0;
- end = end << 24;
- *size = end - start;
-
- val = readl(REG_DDR_CS1_BNDS);
- start = (val >> 16) << 24;
- end = (val & 0xFFFF);
- end = end ? end + 1 : 0;
- end = end << 24;
- *size += end - start;
+ *size = 0;
+ do {
+ ret = scmi_misc_ddrinfo(ddrc_id++, &ddr_info);
+ if (ret) {
+ /* if get DDR info failed, fall to default config */
+ *size = PHYS_SDRAM_SIZE;
+#ifdef PHYS_SDRAM_2_SIZE
+ *size += PHYS_SDRAM_2_SIZE;
+#endif
+ return 0;
+ } else {
+ ddrc_num = ((ddr_info.attributes >> 16) & 0x3);
+ start = ddr_info.starthigh;
+ start <<= 32;
+ start += ddr_info.startlow;
+
+ end = ddr_info.endhigh;
+ end <<= 32;
+ end += ddr_info.endlow;
+
+ *size += end + 1 - start;
+
+ debug("ddr info attr 0x%x, start 0x%x 0x%x, end 0x%x 0x%x, mts %u\n",
+ ddr_info.attributes, ddr_info.starthigh, ddr_info.startlow,
+ ddr_info.endhigh, ddr_info.endlow, ddr_info.mts);
+ }
+ } while (ddrc_id < ddrc_num);
+
+ /* SM reports total DDR size, need remove secure memory */
+ *size -= PHYS_SDRAM - 0x80000000;
return 0;
}
diff --git a/include/scmi_protocols.h b/include/scmi_protocols.h
index ecab021b472..555ffa0a61b 100644
--- a/include/scmi_protocols.h
+++ b/include/scmi_protocols.h
@@ -54,7 +54,8 @@ enum scmi_discovery_id {
};
enum scmi_imx_misc_message_id {
- SCMI_MISC_ROM_PASSOVER_GET = 0x7
+ SCMI_MISC_ROM_PASSOVER_GET = 0x7,
+ SCMI_MISC_DDR_INFO_GET = 0x22,
};
/*
--
2.43.0
More information about the U-Boot
mailing list