From: Ye Li <[email protected]>

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 <[email protected]>
Signed-off-by: Alice Guo <[email protected]>
---
 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@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

Reply via email to