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

