STM32MP2x系列芯片都有两个相互独立的异构核,一个是Cortex-M33核,一个是Cortex-A35核,两个独立的核在同一个DDR内存运行的时候,就需要配置好各自的DDR内存映射,即要保证各自访问内存不能越界,又要保证两个核数据交互时能访问同一块内存。
目前ST只提供一种默认的内存映射,有时候不能满足各种不同客户的需求,所以这篇文章主要讲解:如何自由的配置Cortex-M33核和Cortex-A35核的内存映射。
STM32MP2 的双核内存共享,本质是在异构核(Cortex-A35 与 Cortex-M33)之间,通过一块双方都能访问的物理内存,配合通知机制(IPCC)与软件协议(RPMsg/OpenAMP),实现可靠的数据交换。其设计需要同时解决“看得见”(内存映射)、“管得住”(安全隔离)和“传得稳”(协议与缓存)三个层面的问题。
STM32MP2x系列MPU芯片比上一代STM32MP15x系列芯片在DDR内存的访问上有很大的区别。STM32MP2x系列的芯片异构核都能直接来访问DDR内存,所以在内存配置的时候要特别注意内存映射表一定要配置清楚。默认的内存配置可以参考这个wiki,DDR前面64MByte的内存空间是预留给OPTEE和Cortex-M33使用的。但是在有些情况下,这个内存配置没法满足客人的需求,例如客人希望扩大CortexM33的数据内存,或者扩大CortexM33和CortexA35的共享内存,就需要扩大DDR前面的64M内存,下面就讲解如何来扩大前面预留的64MDDR内存。
2.1 Linux启动时内存的动态规划
MPU标准的linux启动过程是,先ROM Code运行,然后ROM Code通过启动外设加载第二级启动程序,也就是TF-A BL2,然后TF-A通过FIP文件来加载OP-TEE和U-boot,U-boot起来后再加载kernel并最终运行Linux系统。具体的可以参考这个wiki。TF-A先被加载到MPU内部的SRAM,然后TF-A负责初始化一些基本的电源和DDR内存,然后再把FIP文件中的OP-TEE和Uboot加载到对应的内存中运行,Uboot运行后又需要把kernel加载到对应的DDR内存中,然后运行。所以如果希望修改默认的DDR内存映射表,就需要修改TF-A,Uboot,OP-TEE,kernel的加载地址,防止内存冲突。默认的A35住启动时候,不同启动阶段DDR内存映射如下:

2.2 如何修改TF-A BL2运行后的内存映射表
TF-A加载FIP文件并运行,是通过FCONF文件,也就是通过stm32mp25-fw-config.dtsi这个设备树,这个设备树中引用的STM32MP_HW_CONFIG_BASE和STM32MP_BL33_BASE是在stm32mp2_def.h这个文件中定义的,所以如果希望修改DDR内存映射,只需要修改stm32mp2_def.h这个配置文件。例如下是基于OSTL6.0的BSP,把预留DDR内存再扩大32M的patch:
diff --git a/plat/st/stm32mp2/stm32mp2_def.h b/plat/st/stm32mp2/stm32mp2_def.hindex e26ccbd..51975c4 100644--- a/plat/st/stm32mp2/stm32mp2_def.h+++ b/plat/st/stm32mp2/stm32mp2_def.henum ddr_type {#define STM32MP_FW_CONFIG_MAX_SIZE PAGE_SIZE#define STM32MP_FW_CONFIG_BASESTM32MP_SYSRAM_BASE-#define STM32MP_BL33_BASE(STM32MP_DDR_BASE + U(0x04000000))+#define STM32MP_BL33_BASE(STM32MP_DDR_BASE + U(0x06000000))#define STM32MP_BL33_MAX_SIZEU(0x400000)#define STM32MP_HW_CONFIG_BASE(STM32MP_BL33_BASE + \STM32MP_BL33_MAX_SIZE)
当然这里还需要修改stm32mp257f-ev-ca35tdcid-fw-config.dtsi设备树配置文件,例如下列配置
/ {dtb-registry {soc_fw-config {load-address = <0x0 0x83fc0000>;max-size = <0x40000>;};tos_fw {load-address = <0x0 0x84000000>;max-size = <0x2000000>;};};st-mem-firewall {bl31_context: bl31-context@83fc0000 {reg = <0x0 0x83fc0000 0x0 0x40000>;st,protreg = <RISAFPROT(RISAF_REG_ID(7), RIF_CID0_BF|RIF_CID1_BF,RIF_CID0_BF|RIF_CID1_BF, 0, RIF_SEC, RIF_ENC_EN, RIF_BREN_EN)>;};op_tee: op-tee@84000000 {reg = <0x0 0x84000000 0x0 0x2000000>;st,protreg = <RISAFPROT(RISAF_REG_ID(8), RIF_CID0_BF|RIF_CID1_BF,RIF_CID0_BF|RIF_CID1_BF, 0, RIF_SEC, RIF_ENC_EN, RIF_BREN_EN)>;};};};
2.3 如何修改OP-TEE的内存配置
因为OP-TEE在TF-A运行后,加载到固定地址,后面整个Linux运行这个地址一直不变,这样才能保证U-boot和Kernel能正确访问OP-TEE的服务程序。如下是基于OSTL6.0修改的OP-TEE的补丁文件内容,也是扩大32M内存:
2.4 如何修改U-boot运行的内存配置
U-boot是TF-A加载运行的,所以他本身即要告诉TF-A自己要运行的内存地址,又要保证U-Boot运行后,需要加载kernel和不能访问optee预留地址,当然所以这边需要修改如下的
文件:
diff --git a/arch/arm/mach-stm32mp/Kconfig.25x b/arch/arm/mach-stm32mp/Kconfig.25xindex 2c0f691f..285eee06 100644--- a/arch/arm/mach-stm32mp/Kconfig.25x+++ b/arch/arm/mach-stm32mp/Kconfig.25xconfig TARGET_ST_STM32MP25Xendchoiceconfig TEXT_BASE-default 0x84000000+default 0x86000000config PRE_CON_BUF_ADDR-default 0x84800000+default 0x86800000config PRE_CON_BUF_SZdefault 4096config BOOTSTAGE_STASH_ADDR-default 0x87000000+default 0x89000000if DEBUG_UARTdiff --git a/configs/stm32mp25_defconfig b/configs/stm32mp25_defconfigindex 5b8aab47..f1703db9 100644--- a/configs/stm32mp25_defconfig+++ b/configs/stm32mp25_defconfigCONFIG_ARM=yCONFIG_USE_ARCH_MEMCPY=yCONFIG_ARCH_STM32MP=yCONFIG_SYS_MALLOC_F_LEN=0x500000-CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x90000000+CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x92000000CONFIG_ENV_OFFSET=0x900000CONFIG_ENV_SECT_SIZE=0x40000CONFIG_DEFAULT_DEVICE_TREE="stm32mp257f-ev1"CONFIG_CMD_STM32KEY=yCONFIG_ENV_OFFSET_REDUND=0x940000CONFIG_TARGET_ST_STM32MP25X=yCONFIG_CMD_STM32PROG=y-CONFIG_SYS_LOAD_ADDR=0x84000000+CONFIG_SYS_LOAD_ADDR=0x86000000CONFIG_ENV_ADDR=0x60900000CONFIG_FWU_NUM_IMAGES_PER_BANK=1CONFIG_OF_BOARD_FIXUP=y-CONFIG_SYS_MEMTEST_START=0x84000000-CONFIG_SYS_MEMTEST_END=0x88000000+CONFIG_SYS_MEMTEST_START=0x86000000+CONFIG_SYS_MEMTEST_END=0x8A000000CONFIG_API=yCONFIG_SYS_MMC_MAX_DEVICE=3CONFIG_FIT=yCONFIG_BUTTON=yCONFIG_BUTTON_GPIO=yCONFIG_DFU_TFTP=yCONFIG_USB_FUNCTION_FASTBOOT=y-CONFIG_FASTBOOT_BUF_ADDR=0x84000000+CONFIG_FASTBOOT_BUF_ADDR=0x86000000CONFIG_FASTBOOT_BUF_SIZE=0x2000000CONFIG_FASTBOOT_FLASH=yCONFIG_FASTBOOT_FLASH_MMC_DEV=1diff --git a/include/configs/stm32mp25_common.h b/include/configs/stm32mp25_common.hindex 711b8243..f23896b0 100644--- a/include/configs/stm32mp25_common.h+++ b/include/configs/stm32mp25_common.h* 1M fdt, 1M script, 1M pxe and 1M for overlay* and the ramdisk at the end.*/-#define __KERNEL_COMP_ADDR_R __stringify(0x84000000)+#define __KERNEL_COMP_ADDR_R __stringify(0x86000000)#define __KERNEL_COMP_SIZE_R __stringify(0x04000000)-#define __KERNEL_ADDR_R __stringify(0x8a000000)-#define __FDT_ADDR_R __stringify(0x90000000)-#define __SCRIPT_ADDR_R __stringify(0x90100000)-#define __PXEFILE_ADDR_R __stringify(0x90200000)-#define __FDTOVERLAY_ADDR_R __stringify(0x90300000)-#define __RAMDISK_ADDR_R __stringify(0x90400000)+#define __KERNEL_ADDR_R __stringify(0x8c000000)+#define __FDT_ADDR_R __stringify(0x92000000)+#define __SCRIPT_ADDR_R __stringify(0x92100000)+#define __PXEFILE_ADDR_R __stringify(0x92200000)+#define __FDTOVERLAY_ADDR_R __stringify(0x92300000)+#define __RAMDISK_ADDR_R __stringify(0x92400000)
2.5 如何修改Kernel运行的DDR内存配置
Kernel就稍微简单一些,只需要修改DDR的预留地址,就可以了,当然这里面要注意,OP-TEE,U-boot都需要修改设备树的预留地址,保持内存预留地址一致。
STM32MP2 的双核内存共享,在硬件上是“一块物理内存 + 一个门铃(IPCC) ”,在软件上则体现为“OpenAMP/RPMsg 协议栈 + 设备树预留 + 缓存策略”的协同。理论上的关键约束(映射、隔离、缓存)直接决定了实践中每一步的配置方式。理解这条从物理地址到协议端点的链路,是保证共享内存稳定工作的基础。
因为STM32MP2x系列的芯片Cortex-M核和Cortex-A核对外设的访问和DDR的访问几乎一样没有限制,所以如果默认的内存配置不能满足需求,可以参考这个例子来对内存重新配置。
------------ END ------------