You are currently reviewing an older revision of this page.
The System Control Processor (SCP) is a dedicated processor that is used to abstract power and system management tasks away from Application Processors (APs). The SCP Firmware provides a software reference implementation for the SCP on the Arm Total Compute Platform.
The primary services of the SCP firmware include:
On the Total Compute platform, the SCP firmware consists of ROM firmware (SCP BL1) and RAM firmware (SCP BL2). The SCP BL1 firmware is responsible for configuring the entire system and subsequently powering up the main CPU core of the AP. The SCP BL2 firmware serves as the runtime firmware for the SCP, implementing the main features and functionalities of the SCP.
This guide describes:
This guide assumes that you already set up the debugging environment as described in the Guide to Set Up Debugging Environment for Total Compute Software Stack.
The guidance given in this guide is based on the Total Compute TC2-2023.10.04 code.Note: Future code updates might introduce changes, so the guidance might not apply to all cases.
This guide includes the following sections:
The Guide to Set Up Debugging Environment for Total Compute Software Stack describes how to set up the Total Compute debugging environment in Arm DS.
There are some considerations to be aware of when setting up the Total Compute debugging environment.
Step 1: Select Cortex-M3 as your target as follows, when debugging the SCP.
Step 2: Enable debug symbol table file, based on the firmware image you want to debug
By default, however, the SCP firmware is compiled without debug symbol tables. Therefore, the following modifications are necessary to enable the debug symbol tables:
build-scripts:diff --git a/config/common.config b/config/common.config index a99008c..032e3ea 100644 --- a/config/common.config +++ b/config/common.config @@ -23,9 +23,9 @@ CMAKE=${TOOLS_DIR}/cmake-3.22.4-linux-x86_64/bin/cmake SCP_OUTDIR=$OUTPUT_DIR/tmp_build/scp/ SCP_SRC=$SRC_DIR/SCP-firmware SCP_LOG_LEVEL="INFO" -SCP_BUILD_RELEASE=1 +SCP_BUILD_RELEASE=0 SCP_COMPILER=$ARM_BARE_METAL/arm-none-eabi -SCP_BUILD_MODE="release" +SCP_BUILD_MODE="debug" SCP_PLATFORM_VARIANT_STD=0 SCP_PLATFORM_VARIANT_EXPERIMENT=1 SCP_PLATFORM_VARIANT_MPMM=2 src/SCP-firmware:
diff --git a/config/common.config b/config/common.config index a99008c..032e3ea 100644 --- a/config/common.config +++ b/config/common.config @@ -23,9 +23,9 @@ CMAKE=${TOOLS_DIR}/cmake-3.22.4-linux-x86_64/bin/cmake SCP_OUTDIR=$OUTPUT_DIR/tmp_build/scp/ SCP_SRC=$SRC_DIR/SCP-firmware SCP_LOG_LEVEL="INFO" -SCP_BUILD_RELEASE=1 +SCP_BUILD_RELEASE=0 SCP_COMPILER=$ARM_BARE_METAL/arm-none-eabi -SCP_BUILD_MODE="release" +SCP_BUILD_MODE="debug" SCP_PLATFORM_VARIANT_STD=0 SCP_PLATFORM_VARIANT_EXPERIMENT=1 SCP_PLATFORM_VARIANT_MPMM=2
diff --git a/framework/src/fwk_dlist.c b/framework/src/fwk_dlist.c index 6fcfd08b..fa3b3ac7 100644 --- a/framework/src/fwk_dlist.c +++ b/framework/src/fwk_dlist.c @@ -73,10 +73,6 @@ void __fwk_dlist_remove( fwk_assert(node->prev != NULL); fwk_assert(node->next != NULL); - assert(__fwk_slist_contains( - (struct fwk_slist *)list, - (struct fwk_slist_node *)node)); - node->prev->next = node->next; node->next->prev = node->prev; diff --git a/framework/src/fwk_slist.c b/framework/src/fwk_slist.c index b4f41006..a9d09d57 100644 --- a/framework/src/fwk_slist.c +++ b/framework/src/fwk_slist.c @@ -108,8 +108,6 @@ struct fwk_slist_node *__fwk_slist_next( fwk_assert(list != NULL); fwk_assert(node != NULL); - fwk_assert(__fwk_slist_contains(list, node)); - return (node->next == (struct fwk_slist_node *)list) ? NULL : node->next; }
You must recompile the SCP firmware image. The commands to recompile the image are different for Android and the Build Root file system:
export PLATFORM=tc2 export TC_GPU=hwr-prebuilt export TC_TARGET_FLAVOR=fvp export FILESYSTEM=android-fvp ./build-scripts/build-scp.sh clean ./build-scripts/build-scp.sh build ./build-scripts/build-scp.sh deploy build-scripts/build-tfa-trusty.sh build build-scripts/build-tfa-trusty.sh deploy #signed BL1 and SCP_BL1 build-scripts/build-rss.sh deploy #update the fip image build-scripts/build-flash-image.sh deploy
export PLATFORM=tc2 export TC_TARGET_FLAVOR=fvp export FILESYSTEM=buildroot ./build-scripts/build-scp.sh clean ./build-scripts/build-scp.sh build ./build-scripts/build-scp.sh deploy build-scripts/build-tfa.sh build build-scripts/build-tfa.sh deploy #signed BL1 and SCP_BL1 build-scripts/build-rss.sh deploy #update the fip image build-scripts/build-flash-image.sh deploy
The symbol table files corresponding to different firmware are as follows:SCP BL1 Firmware:
output/buildroot/tmp_build/scp/scp/bin/tc2-bl1.elf
output/buildroot/tmp_build/scp/scp/bin/tc2-bl2.elf
Step 3: In the Debugger tab of the SCP debug configuration, include corresponding commands in Execute Debugger Commands to add symbol tables, as shown in the following figure. Each time the debugging connection starts, these commands are automatically executed to load the symbol table files.
Step 4: Click the Debug button to enter the following debugging interface, and you can start debugging.
SCP firmware is divided into three layers, the following figure shows an overview of the components of the SCP firmware:
The Cortex Microcontroller Software Interface Standard (CMSIS) provides a standardized interface for system initialization and low-level hardware access. It enables consistent and efficient software development across different Cortex-M processors. CMSIS RTX2 plays a real-time operating system (RTOS) for SCP firmware.
SCP Firmware includes the following firmwares:
Modules are the building blocks of a product firmware. SCP firmware is composed of several modules, which can be either common modules or modules related to a specific platform.
To find out the specific modules that form the SCP firmware on Total Compute platform, see the following Makefile code:
SCP BL1 Firmware (product/tc2/scp_romfw/Firmware.cmake):if(SCP_ENABLE_PLAT_FVP) list(APPEND SCP_MODULES "pl011") list(APPEND SCP_MODULES "ppu-v1") list(APPEND SCP_MODULES "tc2-bl1") list(APPEND SCP_MODULES "bootloader") list(APPEND SCP_MODULES "system-pll") list(APPEND SCP_MODULES "pik-clock") list(APPEND SCP_MODULES "css-clock") list(APPEND SCP_MODULES "clock") list(APPEND SCP_MODULES "gtimer") list(APPEND SCP_MODULES "timer") list(APPEND SCP_MODULES "cmn-booker") list(APPEND SCP_MODULES "sds") list(APPEND SCP_MODULES "mhu2") list(APPEND SCP_MODULES "transport") else() list(APPEND SCP_MODULES "ppu-v1") list(APPEND SCP_MODULES "pl011") list(APPEND SCP_MODULES "msys-rom") list(APPEND SCP_MODULES "snps-umctl") list(APPEND SCP_MODULES "cmn-booker") list(APPEND SCP_MODULES "sds") list(APPEND SCP_MODULES "bootloader") list(APPEND SCP_MODULES "system-pll") list(APPEND SCP_MODULES "pik-clock") list(APPEND SCP_MODULES "css-clock") list(APPEND SCP_MODULES "clock") list(APPEND SCP_MODULES "gtimer") list(APPEND SCP_MODULES "timer") endif() SCP BL2 Firmware (product/tc2/scp_ramfw/Firmware.cmake):list(APPEND SCP_MODULES "armv7m-mpu") list(APPEND SCP_MODULES "pl011") list(APPEND SCP_MODULES "gtimer") list(APPEND SCP_MODULES "timer") list(APPEND SCP_MODULES "ppu-v1") list(APPEND SCP_MODULES "system-power") list(APPEND SCP_MODULES "mhu2") list(APPEND SCP_MODULES "transport") list(APPEND SCP_MODULES "scmi") list(APPEND SCP_MODULES "sds") list(APPEND SCP_MODULES "system-pll") list(APPEND SCP_MODULES "pik-clock") list(APPEND SCP_MODULES "css-clock") list(APPEND SCP_MODULES "clock") list(APPEND SCP_MODULES "power-domain") list(APPEND SCP_MODULES "scmi-power-domain") list(APPEND SCP_MODULES "scmi-system-power") list(APPEND SCP_MODULES "dvfs") list(APPEND SCP_MODULES "scmi-clock") list(APPEND SCP_MODULES "scmi-perf") list(APPEND SCP_MODULES "mock-psu") list(APPEND SCP_MODULES "psu") list(APPEND SCP_MODULES "tc2-system") if(SCP_ENABLE_RESOURCE_PERMISSIONS) list(APPEND SCP_MODULES,"resource-perms") endif()
if(SCP_ENABLE_PLAT_FVP) list(APPEND SCP_MODULES "pl011") list(APPEND SCP_MODULES "ppu-v1") list(APPEND SCP_MODULES "tc2-bl1") list(APPEND SCP_MODULES "bootloader") list(APPEND SCP_MODULES "system-pll") list(APPEND SCP_MODULES "pik-clock") list(APPEND SCP_MODULES "css-clock") list(APPEND SCP_MODULES "clock") list(APPEND SCP_MODULES "gtimer") list(APPEND SCP_MODULES "timer") list(APPEND SCP_MODULES "cmn-booker") list(APPEND SCP_MODULES "sds") list(APPEND SCP_MODULES "mhu2") list(APPEND SCP_MODULES "transport") else() list(APPEND SCP_MODULES "ppu-v1") list(APPEND SCP_MODULES "pl011") list(APPEND SCP_MODULES "msys-rom") list(APPEND SCP_MODULES "snps-umctl") list(APPEND SCP_MODULES "cmn-booker") list(APPEND SCP_MODULES "sds") list(APPEND SCP_MODULES "bootloader") list(APPEND SCP_MODULES "system-pll") list(APPEND SCP_MODULES "pik-clock") list(APPEND SCP_MODULES "css-clock") list(APPEND SCP_MODULES "clock") list(APPEND SCP_MODULES "gtimer") list(APPEND SCP_MODULES "timer") endif()
list(APPEND SCP_MODULES "armv7m-mpu") list(APPEND SCP_MODULES "pl011") list(APPEND SCP_MODULES "gtimer") list(APPEND SCP_MODULES "timer") list(APPEND SCP_MODULES "ppu-v1") list(APPEND SCP_MODULES "system-power") list(APPEND SCP_MODULES "mhu2") list(APPEND SCP_MODULES "transport") list(APPEND SCP_MODULES "scmi") list(APPEND SCP_MODULES "sds") list(APPEND SCP_MODULES "system-pll") list(APPEND SCP_MODULES "pik-clock") list(APPEND SCP_MODULES "css-clock") list(APPEND SCP_MODULES "clock") list(APPEND SCP_MODULES "power-domain") list(APPEND SCP_MODULES "scmi-power-domain") list(APPEND SCP_MODULES "scmi-system-power") list(APPEND SCP_MODULES "dvfs") list(APPEND SCP_MODULES "scmi-clock") list(APPEND SCP_MODULES "scmi-perf") list(APPEND SCP_MODULES "mock-psu") list(APPEND SCP_MODULES "psu") list(APPEND SCP_MODULES "tc2-system") if(SCP_ENABLE_RESOURCE_PERMISSIONS) list(APPEND SCP_MODULES,"resource-perms") endif()
In the SCP, each module does not contain platform-specific information. When compiling modules into firmware, you must provide configuration for each module based on the platform. In the SCP Firmware of the Total Compute platform, you can find the configuration files in the following directories:
SCP BL1 Firmware:product/tc2/scp_romfw/config_bootloader.c product/tc2/scp_romfw/config_clock.c product/tc2/scp_romfw/config_cmn_booker.c product/tc2/scp_romfw/config_css_clock.c product/tc2/scp_romfw/config_gtimer.c product/tc2/scp_romfw/config_mhu2.c product/tc2/scp_romfw/config_msys_rom.c product/tc2/scp_romfw/config_pik_clock.c product/tc2/scp_romfw/config_pl011.c product/tc2/scp_romfw/config_ppu_v1.c product/tc2/scp_romfw/config_sds.c product/tc2/scp_romfw/config_system_pll.c product/tc2/scp_romfw/config_tc2_bl1.c product/tc2/scp_romfw/config_timer.c product/tc2/scp_romfw/config_transport.c product/tc2/scp_romfw/fmw_memory.h SCP BL2 Firmware:product/tc2/scp_ramfw/config_armv7m_mpu.c product/tc2/scp_ramfw/config_clock.c product/tc2/scp_ramfw/config_css_clock.c product/tc2/scp_ramfw/config_dvfs.c product/tc2/scp_ramfw/config_gtimer.c product/tc2/scp_ramfw/config_mhu2.c product/tc2/scp_ramfw/config_mock_psu.c product/tc2/scp_ramfw/config_mpmm.c product/tc2/scp_ramfw/config_pik_clock.c product/tc2/scp_ramfw/config_pl011.c product/tc2/scp_ramfw/config_power_domain.c product/tc2/scp_ramfw/config_ppu_v1.c product/tc2/scp_ramfw/config_psu.c product/tc2/scp_ramfw/config_reg_sensor.c product/tc2/scp_ramfw/config_resource_perms.c product/tc2/scp_ramfw/config_scmi.c product/tc2/scp_ramfw/config_scmi_clock.c product/tc2/scp_ramfw/config_scmi_perf.c product/tc2/scp_ramfw/config_scmi_power_domain.c product/tc2/scp_ramfw/config_scmi_system_power.c product/tc2/scp_ramfw/config_sds.c product/tc2/scp_ramfw/config_sensor.c product/tc2/scp_ramfw/config_system_pll.c product/tc2/scp_ramfw/config_system_power.c product/tc2/scp_ramfw/config_tc2_power_model.c product/tc2/scp_ramfw/config_thermal_mgmt.c product/tc2/scp_ramfw/config_timer.c product/tc2/scp_ramfw/config_traffic_cop.c product/tc2/scp_ramfw/config_transport.c product/tc2/scp_ramfw/fmw_memory.h product/tc2/scp_ramfw/fmw_notification.h
product/tc2/scp_romfw/config_bootloader.c product/tc2/scp_romfw/config_clock.c product/tc2/scp_romfw/config_cmn_booker.c product/tc2/scp_romfw/config_css_clock.c product/tc2/scp_romfw/config_gtimer.c product/tc2/scp_romfw/config_mhu2.c product/tc2/scp_romfw/config_msys_rom.c product/tc2/scp_romfw/config_pik_clock.c product/tc2/scp_romfw/config_pl011.c product/tc2/scp_romfw/config_ppu_v1.c product/tc2/scp_romfw/config_sds.c product/tc2/scp_romfw/config_system_pll.c product/tc2/scp_romfw/config_tc2_bl1.c product/tc2/scp_romfw/config_timer.c product/tc2/scp_romfw/config_transport.c product/tc2/scp_romfw/fmw_memory.h
product/tc2/scp_ramfw/config_armv7m_mpu.c product/tc2/scp_ramfw/config_clock.c product/tc2/scp_ramfw/config_css_clock.c product/tc2/scp_ramfw/config_dvfs.c product/tc2/scp_ramfw/config_gtimer.c product/tc2/scp_ramfw/config_mhu2.c product/tc2/scp_ramfw/config_mock_psu.c product/tc2/scp_ramfw/config_mpmm.c product/tc2/scp_ramfw/config_pik_clock.c product/tc2/scp_ramfw/config_pl011.c product/tc2/scp_ramfw/config_power_domain.c product/tc2/scp_ramfw/config_ppu_v1.c product/tc2/scp_ramfw/config_psu.c product/tc2/scp_ramfw/config_reg_sensor.c product/tc2/scp_ramfw/config_resource_perms.c product/tc2/scp_ramfw/config_scmi.c product/tc2/scp_ramfw/config_scmi_clock.c product/tc2/scp_ramfw/config_scmi_perf.c product/tc2/scp_ramfw/config_scmi_power_domain.c product/tc2/scp_ramfw/config_scmi_system_power.c product/tc2/scp_ramfw/config_sds.c product/tc2/scp_ramfw/config_sensor.c product/tc2/scp_ramfw/config_system_pll.c product/tc2/scp_ramfw/config_system_power.c product/tc2/scp_ramfw/config_tc2_power_model.c product/tc2/scp_ramfw/config_thermal_mgmt.c product/tc2/scp_ramfw/config_timer.c product/tc2/scp_ramfw/config_traffic_cop.c product/tc2/scp_ramfw/config_transport.c product/tc2/scp_ramfw/fmw_memory.h product/tc2/scp_ramfw/fmw_notification.h
Perform the following steps to load and authenticate firmware:
SCP BL1 Firmware:product/tc2/scp_romfw/fmw_memory.h: /* * ROM memory */ #define FMW_MEM0_SIZE SCP_BOOT_ROM_SIZE #define FMW_MEM0_BASE SCP_BOOT_ROM_BASE arch/arm/arm-m/src/arch.ld.S: mem0 (rwx) : ORIGIN = FMW_MEM0_BASE, LENGTH = FMW_MEM0_SIZE
product/tc2/scp_romfw/fmw_memory.h: /* * ROM memory */ #define FMW_MEM0_SIZE SCP_BOOT_ROM_SIZE #define FMW_MEM0_BASE SCP_BOOT_ROM_BASE
arch/arm/arm-m/src/arch.ld.S: mem0 (rwx) : ORIGIN = FMW_MEM0_BASE, LENGTH = FMW_MEM0_SIZE
SCP BL2 Firmware:product/tc2/scp_ramfw/fmw_memory.h: /* RAM */ #define FMW_MEM0_BASE SCP_RAM_BASE #define FMW_MEM0_SIZE SCP_RAM_SIZE arch/arm/arm-m/src/arch.ld.S: mem0 (rwx) : ORIGIN = FMW_MEM0_BASE, LENGTH = FMW_MEM0_SIZE
product/tc2/scp_ramfw/fmw_memory.h: /* RAM */ #define FMW_MEM0_BASE SCP_RAM_BASE #define FMW_MEM0_SIZE SCP_RAM_SIZE
build-scripts/build-rss.sh: sign_image $RSS_SIGN_AP_BL1_NAME \ $RSS_SIGN_AP_BL1_LOAD_ADDRESS $RSS_SIGN_AP_BL1_BIN_SIZE sign_image $RSS_SIGN_SCP_BL1_NAME \ $RSS_SIGN_SCP_BL1_LOAD_ADDRESS $RSS_SIGN_SCP_BL1_BIN_SIZE
sign_image $RSS_SIGN_AP_BL1_NAME \ $RSS_SIGN_AP_BL1_LOAD_ADDRESS $RSS_SIGN_AP_BL1_BIN_SIZE sign_image $RSS_SIGN_SCP_BL1_NAME \ $RSS_SIGN_SCP_BL1_LOAD_ADDRESS $RSS_SIGN_SCP_BL1_BIN_SIZE
build-scripts/build-flash-image.sh: $FIPTOOL update --align 8192 --rss-bl2 $BINDIR/bl2_signed.bin $2 $FIPTOOL update --align 8192 --rss-scp-bl1 $RSS_BINDIR/signed_$RSS_SIGN_SCP_BL1_NAME $2 $FIPTOOL update --align 8192 --rss-ap-bl1 $RSS_BINDIR/signed_$RSS_SIGN_AP_BL1_NAME $2
$FIPTOOL update --align 8192 --rss-bl2 $BINDIR/bl2_signed.bin $2 $FIPTOOL update --align 8192 --rss-scp-bl1 $RSS_BINDIR/signed_$RSS_SIGN_SCP_BL1_NAME $2 $FIPTOOL update --align 8192 --rss-ap-bl1 $RSS_BINDIR/signed_$RSS_SIGN_AP_BL1_NAME $2
The SCP BL2 firmware is loaded and authenticated by the BL2 firmware of the AP. Therefore, the firmware is packaged into the FIP image during the compilation of TF-A. See the following code for reference:
build-scripts/config/tc2.config:SCP_BL2="$SCP_OUTDIR/scp/bin/tc2-bl2.bin"
SCP_BL2="$SCP_OUTDIR/scp/bin/tc2-bl2.bin"
build-scripts/build-flash-image.sh: # create the GPT layout sgdisk $gpt_image \ --set-alignment 16 \ --disk-guid $location_uuid \ \ --new 1:$start_sector_1:+$num_sectors_fip \ --change-name 1:FIP_A \ --typecode 1:$fip_type_uuid \ --partition-guid 1:$FIP_A_uuid \ \ --new 2:$start_sector_2:+$num_sectors_fip \ --change-name 2:FIP_B \ --typecode 2:$fip_type_uuid \ --partition-guid 2:$FIP_B_uuid \ \ --new 3:$start_sector_3:+$num_sectors_metadata \ --change-name 3:FWU-Metadata \ --typecode 3:$metadata_type_uuid \ \ --new 4:$start_sector_4:+$num_sectors_metadata \ --change-name 4:Bkup-FWU-Metadata \ --typecode 4:$metadata_type_uuid # populate the GPT partitions dd if=$fip_bin of=$gpt_image bs=$sector_size seek=$(gdisk -l $gpt_image | grep " FIP_A$" | awk '{print $2}') count=$num_sectors_fip conv=notrunc dd if=$fip_bin of=$gpt_image bs=$sector_size seek=$(gdisk -l $gpt_image | grep " FIP_B$" | awk '{print $2}') count=$num_sectors_fip conv=notrunc
# create the GPT layout sgdisk $gpt_image \ --set-alignment 16 \ --disk-guid $location_uuid \ \ --new 1:$start_sector_1:+$num_sectors_fip \ --change-name 1:FIP_A \ --typecode 1:$fip_type_uuid \ --partition-guid 1:$FIP_A_uuid \ \ --new 2:$start_sector_2:+$num_sectors_fip \ --change-name 2:FIP_B \ --typecode 2:$fip_type_uuid \ --partition-guid 2:$FIP_B_uuid \ \ --new 3:$start_sector_3:+$num_sectors_metadata \ --change-name 3:FWU-Metadata \ --typecode 3:$metadata_type_uuid \ \ --new 4:$start_sector_4:+$num_sectors_metadata \ --change-name 4:Bkup-FWU-Metadata \ --typecode 4:$metadata_type_uuid # populate the GPT partitions dd if=$fip_bin of=$gpt_image bs=$sector_size seek=$(gdisk -l $gpt_image | grep " FIP_A$" | awk '{print $2}') count=$num_sectors_fip conv=notrunc dd if=$fip_bin of=$gpt_image bs=$sector_size seek=$(gdisk -l $gpt_image | grep " FIP_B$" | awk '{print $2}') count=$num_sectors_fip conv=notrunc
-C board.flashloader0.fname=output/buildroot/deploy/tc2//fip_gpt-tc.bin
According to the Guide to Debug RSS Firmware Booting on Total Compute Platform, SCP BL1 Firmware is loaded and verified by the RSS. When the RSS completes the loading and authentication, it releases the SCP CPU from the wait state and waits for the SCP to send it an MHU message before proceeding with the booting process.
The following figure shows the interaction between the RSS and the SCP:
The interaction between the RSS and the SCP consists of the following steps:
Step 1: During the SCP BL1 Firmware start phase, the start API of the tc2_bl1 module is invoked. This function sends an event FWK_ID_EVENT(FWK_MODULE_IDX_TC2_BL1, MOD_BL1_EVENT_RUN).The specific code can be referenced as follows:product/tc2/module/tc2_bl1/src/mod_tc2_bl1.cstatic int tc2_bl1_start(fwk_id_t id) { struct fwk_event event = { .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_TC2_BL1), .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_TC2_BL1), .id = FWK_ID_EVENT(FWK_MODULE_IDX_TC2_BL1, MOD_BL1_EVENT_RUN), }; return fwk_put_event(&event); } The call stack is as follows:#0 tc2_bl1_start() at mod_tc2_bl1.c:136 #1 fwk_module_start_module() at fwk_module.c:385 #2 start_modules() at fwk_module.c:405 #3 fwk_module_start() at fwk_module.c:444 #4 fwk_arch_init() at fwk_arch.c:100 #5 main() at arch_main.c:70 #6 [_mainCRTStartup+0x4E]
static int tc2_bl1_start(fwk_id_t id) { struct fwk_event event = { .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_TC2_BL1), .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_TC2_BL1), .id = FWK_ID_EVENT(FWK_MODULE_IDX_TC2_BL1, MOD_BL1_EVENT_RUN), }; return fwk_put_event(&event); }
#0 tc2_bl1_start() at mod_tc2_bl1.c:136 #1 fwk_module_start_module() at fwk_module.c:385 #2 start_modules() at fwk_module.c:405 #3 fwk_module_start() at fwk_module.c:444 #4 fwk_arch_init() at fwk_arch.c:100 #5 main() at arch_main.c:70 #6 [_mainCRTStartup+0x4E]
Step 2: After start phase, the SCP BL1 Firmware framework notifies the module tc2_bl1 handle above event FWK_ID_EVENT(FWK_MODULE_IDX_TC2_BL1, MOD_BL1_EVENT_RUN). When handling the event, the tc2_bl1 module sends an MHU message to the RSS. The call stack is as follows:#0 raise_interrupt() at mod_mhu2.c:111 #1 transport_trigger_interrupt() at mod_transport.c:415 #2 bl1_deferred_setup() at mod_tc2_bl1.c:80 #3 tc2_bl1_process_notification() at mod_tc2_bl1.c:207 #4 process_next_event() at fwk_core.c:227 #5 fwk_process_event_queue() at fwk_core.c:297 #6 __fwk_run_main_loop() at fwk_core.c:311 #7 fwk_arch_init() at fwk_arch.c:117 #8 main() at arch_main.c:70 #9 [_mainCRTStartup+0x4E]
#0 raise_interrupt() at mod_mhu2.c:111 #1 transport_trigger_interrupt() at mod_transport.c:415 #2 bl1_deferred_setup() at mod_tc2_bl1.c:80 #3 tc2_bl1_process_notification() at mod_tc2_bl1.c:207 #4 process_next_event() at fwk_core.c:227 #5 fwk_process_event_queue() at fwk_core.c:297 #6 __fwk_run_main_loop() at fwk_core.c:311 #7 fwk_arch_init() at fwk_arch.c:117 #8 main() at arch_main.c:70 #9 [_mainCRTStartup+0x4E]
Step 3: After sending the above MHU message to RSS, the SCP BL1 firmware enters a waiting state. The call stack is as follows:#0 fwk_arch_suspend() at fwk_arch.c:140 #1 __fwk_run_main_loop() at fwk_core.c:312 #2 fwk_arch_init() at fwk_arch.c:117 #3 main() at arch_main.c:70 #4 [_mainCRTStartup+0x4E]
#0 fwk_arch_suspend() at fwk_arch.c:140 #1 __fwk_run_main_loop() at fwk_core.c:312 #2 fwk_arch_init() at fwk_arch.c:117 #3 main() at arch_main.c:70 #4 [_mainCRTStartup+0x4E]
Step 4: When RSS receive the MHU message sent by the SCP, the RSS proceeds to continue loading and authenticating the BL1 firmware of the AP.
Step 5: When RSS loads and authentication of the AP's BL1 firmware has completed, RSS sends another MHU message to SCP.
Step 6: When SCP receives this message, it sends out the event MOD_BL1_EVENT_RSS_HANDSHAKE.The call stack is as follows:#0 tc2_signal_message() at mod_tc2_bl1.c:52 #1 transport_signal_message() at mod_transport.c:664 #2 mhu2_isr() at mod_mhu2.c:99 #3 irq_global() at arch_nvic.c:69 #4 [0xFFFFFFF8]
#0 tc2_signal_message() at mod_tc2_bl1.c:52 #1 transport_signal_message() at mod_transport.c:664 #2 mhu2_isr() at mod_mhu2.c:99 #3 irq_global() at arch_nvic.c:69 #4 [0xFFFFFFF8]
Step 7: Then tc2_bl1 module processes the MOD_BL1_EVENT_RSS_HANDSHAKE event.The call stack is as follows:#0 tc2_bl1_process_event() at mod_tc2_bl1.c:149 #1 process_next_event() at fwk_core.c:227 #2 fwk_process_event_queue() at fwk_core.c:297 #3 __fwk_run_main_loop() at fwk_core.c:311 #4 fwk_arch_init() at fwk_arch.c:117 #5 main() at arch_main.c:70 #6 [_mainCRTStartup+0x4E]
#0 tc2_bl1_process_event() at mod_tc2_bl1.c:149 #1 process_next_event() at fwk_core.c:227 #2 fwk_process_event_queue() at fwk_core.c:297 #3 __fwk_run_main_loop() at fwk_core.c:311 #4 fwk_arch_init() at fwk_arch.c:117 #5 main() at arch_main.c:70 #6 [_mainCRTStartup+0x4E]
The AP BL1 firmware is loaded and authenticated by the RSS, as described in the previous section. After the RSS notifies the SCP BL1 firmware through an MHU message, the SCP BL1 firmware continues to power up the primary CPU of the AP. Subsequently, the main CPU of AP starts up to load the SCP BL2 firmware.The following figure shows you the interaction process between the AP and the SCP:
Step 1: SCP power up primary CPU of AP When the SCP receives the MHU message indicating the completion of AP BL1 firmware loading from the RSS, the SCP can power up the primary CPU of AP by programming the PPU registers. This enables the primary CPU of the AP to start executing the BL1 firmware of the AP. See the following code for reference(product/tc2/module/tc2_bl1/src/mod_tc2_bl1.c):
FWK_LOG_INFO("[TC2_BL1] Got ACK from RSS"); /* Power on the primary cluster and cpu */ ctx.ppu_boot_api->power_mode_on(ctx.bl1_config->id_primary_cluster); ctx.ppu_boot_api->power_mode_on(ctx.bl1_config->id_primary_core);
#0 ppu_v1_request_power_mode() at ppu_v1.c:51 #1 ppu_v1_set_power_mode() at ppu_v1.c:70 #2 ppu_power_mode_on() at mod_ppu_v1.c:645 #3 tc2_bl1_process_event() at mod_tc2_bl1.c:178 #4 process_next_event() at fwk_core.c:227 #5 fwk_process_event_queue() at fwk_core.c:297 #6 __fwk_run_main_loop() at fwk_core.c:311 #7 fwk_arch_init() at fwk_arch.c:117 #8 main() at arch_main.c:70 #9 [_mainCRTStartup+0x4E]
Step 2: AP loads and authenticates SCP BL2 firmware When the primary CPU of the AP is powered up, it starts loading and authenticating the SCP BL2 firmware from the FIP file. However, the SCP BL1 firmware must wait until the primary CPU of the AP finishes loading the SCP BL2 firmware before it can proceed to the next step. The SCP and AP communicates through the mechanism of shared memory, using a Shared Data Structure (SDS). The SCP continuously reads the structure TC2_SDS_BOOTLOADER until AP writes the TC2_SDS_BOOTLOADER structure. Then, the SCP proceeds to the next step. See the following code for reference: while (true) { status = mod_bootloader_ctx.sds_api->struct_read( mod_bootloader_ctx.module_config->sds_struct_id, BOOTLOADER_STRUCT_VALID_POS, &image_flags, sizeof(image_flags)); if (status != FWK_SUCCESS) { return status; } if ((image_flags & (uint32_t)IMAGE_FLAGS_VALID_MASK) != (uint32_t)0) { break; } } The call stack is as follows:#0 sds_struct_read() at mod_sds.c:558 #1 load_image() at mod_bootloader.c:105 #2 tc2_bl1_process_event() at mod_tc2_bl1.c:182 #3 process_next_event() at fwk_core.c:227 #4 fwk_process_event_queue() at fwk_core.c:297 #5 __fwk_run_main_loop() at fwk_core.c:311 #6 fwk_arch_init() at fwk_arch.c:117 #7 main() at arch_main.c:70 #8 [_mainCRTStartup+0x4E]
while (true) { status = mod_bootloader_ctx.sds_api->struct_read( mod_bootloader_ctx.module_config->sds_struct_id, BOOTLOADER_STRUCT_VALID_POS, &image_flags, sizeof(image_flags)); if (status != FWK_SUCCESS) { return status; } if ((image_flags & (uint32_t)IMAGE_FLAGS_VALID_MASK) != (uint32_t)0) { break; } }
#0 sds_struct_read() at mod_sds.c:558 #1 load_image() at mod_bootloader.c:105 #2 tc2_bl1_process_event() at mod_tc2_bl1.c:182 #3 process_next_event() at fwk_core.c:227 #4 fwk_process_event_queue() at fwk_core.c:297 #5 __fwk_run_main_loop() at fwk_core.c:311 #6 fwk_arch_init() at fwk_arch.c:117 #7 main() at arch_main.c:70 #8 [_mainCRTStartup+0x4E]
Step 3: Detect SCP BL2 firmware ready and jump to SCP BL2 firmwareWhen the firmware of SCP BL1 firmware detects that structure TC2_SDS_BOOTLOADER is already valid, it proceeds to parse this structure to get the image information of SCP BL2 firmware. Based on this information, the SCP BL2 firmware is copied from shared memory to the SCP SRAM, the address specified in the linker script as SCP_RAM_BASE.Then, the task of SCP BL1 is complete, and then jump to SCP BL2 firmware.See the following code for reference(product/tc2/scp_romfw/config_bootloader.c):static const struct mod_bootloader_config bootloader_module_config = { .source_base = SCP_TRUSTED_RAM_BASE, .source_size = 512 * 1024, .destination_base = SCP_RAM_BASE, .destination_size = SCP_RAM_SIZE, .sds_struct_id = TC2_SDS_BOOTLOADER, }; module/bootloader/src/mod_bootloader_boot.S:mod_bootloader_boot: movs r4, r0 /* Save the destination - it soon points to the vector table */ 1: ldrb r5, [r1], #1 /* Load next byte from source */ strb r5, [r0], #1 /* Store next byte at destination */ subs r2, #1 /* Decrement the size, which we use as the counter... */ bne 1b /* ... until it reaches zero */ str r4, [r3] /* Store vector table address in SCB->VTOR (if it exists) */ ldr r0, [r4] /* Grab new stack pointer from vector table... */ msr msp, r0 /* ... and update the main stack pointer with it */ ldr r0, [r4, #4] /* Load the reset address from the vector table... */ bx r0 /* ... and take a leap of faith */ .pool At this point, the primary CPU of the AP cannot proceed because the SCMI in the SCP firmware might not have completed initialization. Therefore, the primary CPU of the AP must wait for the SCMI initialization in the SCP BL2 firmware to finish before it can continue execution.
static const struct mod_bootloader_config bootloader_module_config = { .source_base = SCP_TRUSTED_RAM_BASE, .source_size = 512 * 1024, .destination_base = SCP_RAM_BASE, .destination_size = SCP_RAM_SIZE, .sds_struct_id = TC2_SDS_BOOTLOADER, };
mod_bootloader_boot: movs r4, r0 /* Save the destination - it soon points to the vector table */ 1: ldrb r5, [r1], #1 /* Load next byte from source */ strb r5, [r0], #1 /* Store next byte at destination */ subs r2, #1 /* Decrement the size, which we use as the counter... */ bne 1b /* ... until it reaches zero */ str r4, [r3] /* Store vector table address in SCB->VTOR (if it exists) */ ldr r0, [r4] /* Grab new stack pointer from vector table... */ msr msp, r0 /* ... and update the main stack pointer with it */ ldr r0, [r4, #4] /* Load the reset address from the vector table... */ bx r0 /* ... and take a leap of faith */ .pool
Step 4: The SCP BL2 firmware initialization The SCP BL2 firmware initializes each SCMI element based on the SCMI configuration on the Total Compute platform. When the initialization of the last element is completed, it sends the event mod_scmi_notification_id_initializedSee the following code for reference:product/tc2/scp_ramfw/config_scmi.c:static const struct fwk_element service_table[ SCP_TC2_SCMI_SERVICE_IDX_COUNT + 1] = { [SCP_TC2_SCMI_SERVICE_IDX_PSCI] = { .name = "PSCI", .data = &((struct mod_scmi_service_config) { .transport_id = FWK_ID_ELEMENT_INIT( FWK_MODULE_IDX_TRANSPORT, SCP_TC2_SCMI_SERVICE_IDX_PSCI), .transport_api_id = FWK_ID_API_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_API_IDX_SCMI_TO_TRANSPORT), .transport_notification_init_id = FWK_ID_NOTIFICATION_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_NOTIFICATION_IDX_INITIALIZED), .scmi_agent_id = SCP_SCMI_AGENT_ID_PSCI, .scmi_p2a_id = FWK_ID_NONE_INIT, }), }, [SCP_TC2_SCMI_SERVICE_IDX_OSPM_0] = { .name = "OSPM0", .data = &((struct mod_scmi_service_config) { .transport_id = FWK_ID_ELEMENT_INIT( FWK_MODULE_IDX_TRANSPORT, SCP_TC2_SCMI_SERVICE_IDX_OSPM_0), .transport_api_id = FWK_ID_API_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_API_IDX_SCMI_TO_TRANSPORT), .transport_notification_init_id = FWK_ID_NOTIFICATION_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_NOTIFICATION_IDX_INITIALIZED), .scmi_agent_id = SCP_SCMI_AGENT_ID_OSPM, .scmi_p2a_id = FWK_ID_NONE_INIT, }), }, [SCP_TC2_SCMI_SERVICE_IDX_OSPM_1] = { .name = "OSPM1", .data = &((struct mod_scmi_service_config) { .transport_id = FWK_ID_ELEMENT_INIT( FWK_MODULE_IDX_TRANSPORT, SCP_TC2_SCMI_SERVICE_IDX_OSPM_1), .transport_api_id = FWK_ID_API_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_API_IDX_SCMI_TO_TRANSPORT), .transport_notification_init_id = FWK_ID_NOTIFICATION_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_NOTIFICATION_IDX_INITIALIZED), .scmi_agent_id = SCP_SCMI_AGENT_ID_OSPM, .scmi_p2a_id = FWK_ID_NONE_INIT, }), }, [SCP_TC2_SCMI_SERVICE_IDX_COUNT] = { 0 } }; module/scmi/src/mod_scmi.c (scmi_start): if (fwk_id_is_equal(config->transport_notification_init_id, FWK_ID_NONE)) { /* Notify that the service is immediately ready */ struct fwk_event scmi_services_initialized_notification = { .id = mod_scmi_notification_id_initialized, .source_id = id, }; return fwk_notification_notify(&scmi_services_initialized_notification, ¬ifications_sent); } The call stack is as follows:#0 scmi_start() at mod_scmi.c:1130 #1 fwk_module_start_elements() at fwk_module.c:363 #2 fwk_module_start_module() at fwk_module.c:394 #3 start_modules() at fwk_module.c:405 #4 fwk_module_start() at fwk_module.c:444 #5 fwk_arch_init() at fwk_arch.c:100 #6 main() at arch_main.c:70 #7 [_mainCRTStartup+0x4E]
static const struct fwk_element service_table[ SCP_TC2_SCMI_SERVICE_IDX_COUNT + 1] = { [SCP_TC2_SCMI_SERVICE_IDX_PSCI] = { .name = "PSCI", .data = &((struct mod_scmi_service_config) { .transport_id = FWK_ID_ELEMENT_INIT( FWK_MODULE_IDX_TRANSPORT, SCP_TC2_SCMI_SERVICE_IDX_PSCI), .transport_api_id = FWK_ID_API_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_API_IDX_SCMI_TO_TRANSPORT), .transport_notification_init_id = FWK_ID_NOTIFICATION_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_NOTIFICATION_IDX_INITIALIZED), .scmi_agent_id = SCP_SCMI_AGENT_ID_PSCI, .scmi_p2a_id = FWK_ID_NONE_INIT, }), }, [SCP_TC2_SCMI_SERVICE_IDX_OSPM_0] = { .name = "OSPM0", .data = &((struct mod_scmi_service_config) { .transport_id = FWK_ID_ELEMENT_INIT( FWK_MODULE_IDX_TRANSPORT, SCP_TC2_SCMI_SERVICE_IDX_OSPM_0), .transport_api_id = FWK_ID_API_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_API_IDX_SCMI_TO_TRANSPORT), .transport_notification_init_id = FWK_ID_NOTIFICATION_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_NOTIFICATION_IDX_INITIALIZED), .scmi_agent_id = SCP_SCMI_AGENT_ID_OSPM, .scmi_p2a_id = FWK_ID_NONE_INIT, }), }, [SCP_TC2_SCMI_SERVICE_IDX_OSPM_1] = { .name = "OSPM1", .data = &((struct mod_scmi_service_config) { .transport_id = FWK_ID_ELEMENT_INIT( FWK_MODULE_IDX_TRANSPORT, SCP_TC2_SCMI_SERVICE_IDX_OSPM_1), .transport_api_id = FWK_ID_API_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_API_IDX_SCMI_TO_TRANSPORT), .transport_notification_init_id = FWK_ID_NOTIFICATION_INIT( FWK_MODULE_IDX_TRANSPORT, MOD_TRANSPORT_NOTIFICATION_IDX_INITIALIZED), .scmi_agent_id = SCP_SCMI_AGENT_ID_OSPM, .scmi_p2a_id = FWK_ID_NONE_INIT, }), }, [SCP_TC2_SCMI_SERVICE_IDX_COUNT] = { 0 } };
if (fwk_id_is_equal(config->transport_notification_init_id, FWK_ID_NONE)) { /* Notify that the service is immediately ready */ struct fwk_event scmi_services_initialized_notification = { .id = mod_scmi_notification_id_initialized, .source_id = id, }; return fwk_notification_notify(&scmi_services_initialized_notification, ¬ifications_sent); }
#0 scmi_start() at mod_scmi.c:1130 #1 fwk_module_start_elements() at fwk_module.c:363 #2 fwk_module_start_module() at fwk_module.c:394 #3 start_modules() at fwk_module.c:405 #4 fwk_module_start() at fwk_module.c:444 #5 fwk_arch_init() at fwk_arch.c:100 #6 main() at arch_main.c:70 #7 [_mainCRTStartup+0x4E]
Step 5: SCP BL2 firmware notifies the AP firmware that it can proceed with the booting processWhen all SCMI modules have completed initialization, the SCP BL2 firmware is ready to handle SCMI requests sent by the AP. At this point, SCP BL2 notifies the AP firmware that it can proceed with the booting process. The SCP BL2 informs the AP that the SCMI stack is initialized by writing the structure TC2_SDS_FEATURE_AVAILABILITY. See the following code for reference:product/tc2/scp_ramfw/config_sds.c: { .name = "Feature Availability", .data = &((struct mod_sds_structure_desc){ .id = TC2_SDS_FEATURE_AVAILABILITY, .size = TC2_SDS_FEATURE_AVAILABILITY_SIZE, .payload = &feature_flags, .region_id = TC2_SDS_REGION_SECURE, .finalize = true, }), }, product/tc2/module/tc2_system/src/mod_tc2_system.c:static int messaging_stack_ready(void) { const struct mod_sds_structure_desc *sds_structure_desc = fwk_module_get_data(sds_feature_availability_id); /* * Write SDS Feature Availability to signal the completion of the messaging * stack */ return mod_ctx.sds_api->struct_write( sds_structure_desc->id, 0, (void *)(&feature_flags), sds_structure_desc->size); } The call stack is as follows:#0 messaging_stack_ready() at mod_tc2_system.c:74 #1 tc2_system_process_notification() at mod_tc2_system.c:220 #2 process_next_event() at fwk_core.c:227 #3 fwk_process_event_queue() at fwk_core.c:297 #4 __fwk_run_main_loop() at fwk_core.c:311 #5 fwk_arch_init() at fwk_arch.c:117 #6 main() at arch_main.c:70 #7 [_mainCRTStartup+0x4E]
{ .name = "Feature Availability", .data = &((struct mod_sds_structure_desc){ .id = TC2_SDS_FEATURE_AVAILABILITY, .size = TC2_SDS_FEATURE_AVAILABILITY_SIZE, .payload = &feature_flags, .region_id = TC2_SDS_REGION_SECURE, .finalize = true, }), },
static int messaging_stack_ready(void) { const struct mod_sds_structure_desc *sds_structure_desc = fwk_module_get_data(sds_feature_availability_id); /* * Write SDS Feature Availability to signal the completion of the messaging * stack */ return mod_ctx.sds_api->struct_write( sds_structure_desc->id, 0, (void *)(&feature_flags), sds_structure_desc->size); }
#0 messaging_stack_ready() at mod_tc2_system.c:74 #1 tc2_system_process_notification() at mod_tc2_system.c:220 #2 process_next_event() at fwk_core.c:227 #3 fwk_process_event_queue() at fwk_core.c:297 #4 __fwk_run_main_loop() at fwk_core.c:311 #5 fwk_arch_init() at fwk_arch.c:117 #6 main() at arch_main.c:70 #7 [_mainCRTStartup+0x4E]
Step 6: The SCP BL2 firmware completes the boot process and enters a state of waiting to receive SCMI messages sent by the AP.The call stack is as follows:#0 fwk_arch_suspend() at fwk_arch.c:140 #1 __fwk_run_main_loop() at fwk_core.c:312 #2 fwk_arch_init() at fwk_arch.c:117 #3 main() at arch_main.c:70 #4 [_mainCRTStartup+0x4E]