1. Article purpose[edit source]
This article explains how to configure the GPIO, EXTI, clocks and regulators system resources shared between the Arm® Cortex®-A7 and the Arm® Cortex®-M4 contexts.
In this article, it is assumed that the system runs in production boot mode where both the Cortex-A7 non-secure and Cortex-M4 contexts are running. The specificities of the engineering boot mode are not covered here.
2. Introduction[edit source]
When a peripheral is assigned to the Cortex®-M4 context (refer to How to assign an internal peripheral to a runtime context for details), the developer has to pay attention to the configuration of the system resources, shared between the Cortex®-A7 and the Cortex®-M4 contexts. It is mandatory to avoid concurrent accesses to these resources from the Cortex®-A7 and the Cortex®-M4.
The system resources can be accessed:
- from the Cortex®-A7 core:
- during the platform boot, by U-Boot or TF-A, (refer to Boot chain overview),
- during the Linux® firmware execution.
- from the Cortex®-M4 by the STM32Cube firmware.
To ensure an exclusive access to these system resources, two strategies are implemented in the STM32MPU Embedded Software distribution:
- a protection by a hardware semaphore (seeHSEM) for GPIO and EXTI configurations,
- an exclusive access by the Cortex-A7 non-secure context. In that case, the Cortex-M4 context relies on the resources manager to configure the clocks and regulators via the Linux kernel .
3. Protecting GPIO and EXTI system resources by hardware semaphores[edit source]
The GPIO and EXTI configurations are protected from concurrent accesses by hardware semaphores from HSEM.
Each execution context must use a hardware semaphore to ensure the exclusive access to the critical registers of the GPIO and EXTI resources.
3.1. Cortex-A7 secure context[edit source]
In the STM32MPU Embedded Software distribution, the TF-A and OP-TEE do not use HSEM protection, since no concurrent accesses to GPIO and EXTI system resource have been identified. Nevertheless this protection has to be taken into account in secure firmware development.
3.2. Cortex-A7 non-secure context[edit source]
3.2.1. U-boot[edit source]
No specific protection is required in U-Boot since it configures the system resources before starting the Cortex-M4 firmware.
3.2.2. Linux kernel[edit source]
The Linux GPIO and EXTI drivers use semaphores to protect the registers from being accessed: these semaphores are defined in the corresponding device tree nodes.
exti: interrupt-controller@5000d000 { compatible = "st,stm32mp1-exti", "syscon"; ... hwlocks = <&hsem 1>; ... }; pinctrl: pin-controller@50002000 { compatible = "st,stm32mp157-pinctrl"; ... hwlocks = <&hsem 0>; ... }
3.3. Cortex-M4 context[edit source]
In the STM32Cube application, the developer must protect the GPIO and EXTI configuration registers by hardware semaphores managed by the HSEM. This can be done by using the lock resource service.
.
void main(void) { GPIO_InitStruct.Pin = USER_BUTTON_PIN; /*HW semaphore Clock enable*/ __HAL_RCC_HSEM_CLK_ENABLE(); PERIPH_LOCK(GPIOA); HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); PERIPH_UNLOCK(GPIOA); ... PERIPH_LOCK(EXTI); HAL_EXTI_SetConfigLine(&hexti, &EXTI_ConfigStructure); PERIPH_UNLOCK(EXTI); }
4. Configuring clock and regulator system resources[edit source]
The Linux kernel provides services, implemented by the resource manager, to control the clock and regulator configuration for the peripherals assigned to the Cortex-M4 context:
- The resource manager configures the clocks and the regulators before the Cortex-M4 starts.
- At runtime, the Cortex-M4 STM32Cube application can ask the resource manager to update the clock and regulator configurations:
- clock rate
- regulator settings
4.1. System resource manager on the Cortex-A7 non-secure context[edit source]
The resource manager Linux Kernel driver is in charge of configuring the clocks and regulators used to operate the peripherals assigned to the Cortex-M4 context. The configurations are defined in the m4_system_resources node of the Linux kernel device tree.
To help developers, the Linux kernel predefines the clock system resources for most of the peripherals that can be assigned to the Cortex-M4 context: see arch/arm/boot/dts/stm32mp15-m4-srm.dtsi .
4.2. System resource management on the Cortex-M4 context[edit source]
As clock and regulator system resources are under the Linux kernel responsibility, the Cortex-M4 context must NOT configure these system resources directly:
- The Cortex-M4 must not set the initial configuration of these resources: this is done by the Linux kernel.
- The Cortex-M4 can use the STM32Cube ResourceManager utility to update the configuration of these resources.
4.3. ADC example[edit source]
This example describes how to configure the system resources of the ADC peripheral assigned to the Cortex-M4 coprocessor.
4.3.1. Device tree on the Cortex-A7 non-secure context[edit source]
- Disable the Linux ADC device node for the Cortex-A7 non-secure context (see How to assign an internal peripheral to a runtime context for details):
&adc {
status = "disabled";
...
};
- Notice that the ADC clocks are already defined in arch/arm/boot/dts/stm32mp15-m4-srm.dtsi .
m4_adc: adc@48003000 { compatible = "rproc-srm-dev"; reg = <0x48003000>; clocks = <&rcc ADC12>, <&rcc ADC12_K>; clock-names = "bus", "adc"; status = "disabled"; };
- Enable the resource manager
&m4_rproc {
m4_system_resources {
status = "okay";
};
};
- Enable the Linux ADC resource node for the Cortex-M4 and assign a regulator to it
&m4_adc { vref-supply = <&vdda>; status = "okay"; };
4.3.2. Firmware update on the Cortex-M4 context[edit source]
No implementation is required to have the resources configured to their initial state.
The below example describes how to update the ADC1 regulator configuration:
- Initialization:
int main(void) { ... /* Initialize the ResourceManager with OpenAMP */ HAL_IPCC_Init(&hipcc); OPENAMP_Init(RPMSG_REMOTE, NULL); ResMgr_Init(NULL, NULL); ... while (1) { /* ResourceManager with OpenAMP polling */ OPENAMP_check_for_message(); /* Application main processing */ ... }
- Update of the regulator voltage:
config_in.regu.index = 0; config_in.regu.enable = 1; config_in.regu.min_voltage_mv = 1000; config_in.regu.max_voltage_mv = 4000; ResMgr_SetConfig(RESMGR_ID_ADC1, NULL, RESMGR_REGU, &config_in, &config_out); log_info("Regulator voltage is now=%ld mv\n", config_out.regu.curr_voltage_mv);