基于STM32MP157的异核间通信(续二)
前面讨论了STM32MP157异核间通信的实例及其基本原理,接下来看一下在A7端Linux下的设备树里和M4端的链接脚本里都是如何配置的。
远程协处理器的资源配置由3部分组成,分别是:外围设备、物理内存和资源表。外围设备的配置通过设备树(stm32mp157c.dtsi)下的m4_system_resources节点进行(一般通过stm32mp157c-m4-srm.dtsi文件进行追加);物理内存(SRAM1~SRAM4)的配置通过设备树(stm32mp157a-basic.dts)下的reserved-memory节点进行;资源表的配置通过OpenAMP库的rsc_table.h、rsc_table.c文件在IDE中进行。以上设备树文件是以野火提供的内核源码为例的,若是其他平台可能上述节点所在的设备树文件名称不一样,但节点名称是固定的,可以在源码dts目录下通过执行命令“grep -nr 节点名称”来查找具体所在的设备树文件。
先来看外围设备的配置,下面是stm32mp157c-m4-srm.dtsi文件中m4_system_resources节点的配置信息。
&m4_rproc { m4_system_resources { #address-cells = <1>; #size-cells = <0>; m4_timers2: timer@40000000 { compatible = "rproc-srm-dev"; reg = <0x40000000>; clocks = <&rcc TIM2_K>; clock-names = "int"; status = "disabled"; }; m4_timers3: timer@40001000 { compatible = "rproc-srm-dev"; reg = <0x40001000>; clocks = <&rcc TIM3_K>; clock-names = "int"; status = "disabled"; }; m4_timers4: timer@40002000 { compatible = "rproc-srm-dev"; reg = <0x40002000>; clocks = <&rcc TIM4_K>; clock-names = "int"; status = "disabled"; }; m4_timers5: timer@40003000 { compatible = "rproc-srm-dev"; reg = <0x40003000>; clocks = <&rcc TIM5_K>; clock-names = "int"; status = "disabled"; }; m4_timers6: timer@40004000 { compatible = "rproc-srm-dev"; reg = <0x40004000>; clocks = <&rcc TIM6_K>; clock-names = "int"; status = "disabled"; }; m4_timers7: timer@40005000 { compatible = "rproc-srm-dev"; reg = <0x40005000>; clocks = <&rcc TIM7_K>; clock-names = "int"; status = "disabled"; }; m4_timers12: timer@40006000 { compatible = "rproc-srm-dev"; reg = <0x40006000>; clocks = <&rcc TIM12_K>; clock-names = "int"; status = "disabled"; }; m4_timers13: timer@40007000 { compatible = "rproc-srm-dev"; reg = <0x40007000>; clocks = <&rcc TIM13_K>; clock-names = "int"; status = "disabled"; }; m4_timers14: timer@40008000 { compatible = "rproc-srm-dev"; reg = <0x40008000>; clocks = <&rcc TIM14_K>; clock-names = "int"; status = "disabled"; }; m4_lptimer1: timer@40009000 { compatible = "rproc-srm-dev"; reg = <0x40009000>; clocks = <&rcc LPTIM1_K>; clock-names = "mux"; status = "disabled"; }; m4_spi2: spi@4000b000 { compatible = "rproc-srm-dev"; reg = <0x4000b000>; clocks = <&rcc SPI2_K>; status = "disabled"; }; m4_i2s2: audio-controller@4000b000 { compatible = "rproc-srm-dev"; reg = <0x4000b000>; status = "disabled"; }; m4_spi3: spi@4000c000 { compatible = "rproc-srm-dev"; reg = <0x4000c000>; clocks = <&rcc SPI3_K>; status = "disabled"; }; m4_i2s3: audio-controller@4000c000 { compatible = "rproc-srm-dev"; reg = <0x4000c000>; status = "disabled"; }; m4_spdifrx: audio-controller@4000d000 { compatible = "rproc-srm-dev"; reg = <0x4000d000>; clocks = <&rcc SPDIF_K>; clock-names = "kclk"; status = "disabled"; }; m4_usart2: serial@4000e000 { compatible = "rproc-srm-dev"; reg = <0x4000e000>; interrupt-parent = <&exti>; interrupts = <27 1>; clocks = <&rcc USART2_K>; status = "disabled"; }; m4_usart3: serial@4000f000 { compatible = "rproc-srm-dev"; reg = <0x4000f000>; interrupt-parent = <&exti>; interrupts = <28 1>; clocks = <&rcc USART3_K>; status = "disabled"; }; m4_uart4: serial@40010000 { compatible = "rproc-srm-dev"; reg = <0x40010000>; interrupt-parent = <&exti>; interrupts = <30 1>; clocks = <&rcc UART4_K>; status = "disabled"; }; m4_uart5: serial@40011000 { compatible = "rproc-srm-dev"; reg = <0x40011000>; interrupt-parent = <&exti>; interrupts = <31 1>; clocks = <&rcc UART5_K>; status = "disabled"; }; m4_i2c1: i2c@40012000 { compatible = "rproc-srm-dev"; reg = <0x40012000>; interrupt-parent = <&exti>; interrupts = <21 1>; clocks = <&rcc I2C1_K>; status = "disabled"; }; m4_i2c2: i2c@40013000 { compatible = "rproc-srm-dev"; reg = <0x40013000>; interrupt-parent = <&exti>; interrupts = <22 1>; clocks = <&rcc I2C2_K>; status = "disabled"; }; m4_i2c3: i2c@40014000 { compatible = "rproc-srm-dev"; reg = <0x40014000>; interrupt-parent = <&exti>; interrupts = <23 1>; clocks = <&rcc I2C3_K>; status = "disabled"; }; m4_i2c5: i2c@40015000 { compatible = "rproc-srm-dev"; reg = <0x40015000>; interrupt-parent = <&exti>; interrupts = <25 1>; clocks = <&rcc I2C5_K>; status = "disabled"; }; m4_cec: cec@40016000 { compatible = "rproc-srm-dev"; reg = <0x40016000>; interrupt-parent = <&exti>; interrupts = <69 1>; clocks = <&rcc CEC_K>, <&rcc CK_LSE>; clock-names = "cec", "hdmi-cec"; status = "disabled"; }; m4_dac: dac@40017000 { compatible = "rproc-srm-dev"; reg = <0x40017000>; clocks = <&rcc DAC12>; clock-names = "pclk"; status = "disabled"; }; m4_uart7: serial@40018000 { compatible = "rproc-srm-dev"; reg = <0x40018000>; interrupt-parent = <&exti>; interrupts = <32 1>; clocks = <&rcc UART7_K>; status = "disabled"; }; m4_uart8: serial@40019000 { compatible = "rproc-srm-dev"; reg = <0x40019000>; interrupt-parent = <&exti>; interrupts = <33 1>; clocks = <&rcc UART8_K>; status = "disabled"; }; m4_timers1: timer@44000000 { compatible = "rproc-srm-dev"; reg = <0x44000000>; clocks = <&rcc TIM1_K>; clock-names = "int"; status = "disabled"; }; m4_timers8: timer@44001000 { compatible = "rproc-srm-dev"; reg = <0x44001000>; clocks = <&rcc TIM8_K>; clock-names = "int"; status = "disabled"; }; m4_usart6: serial@44003000 { compatible = "rproc-srm-dev"; reg = <0x44003000>; interrupt-parent = <&exti>; interrupts = <29 1>; clocks = <&rcc USART6_K>; status = "disabled"; }; m4_spi1: spi@44004000 { compatible = "rproc-srm-dev"; reg = <0x44004000>; clocks = <&rcc SPI1_K>; status = "disabled"; }; m4_i2s1: audio-controller@44004000 { compatible = "rproc-srm-dev"; reg = <0x44004000>; status = "disabled"; }; m4_spi4: spi@44005000 { compatible = "rproc-srm-dev"; reg = <0x44005000>; clocks = <&rcc SPI4_K>; status = "disabled"; }; m4_timers15: timer@44006000 { compatible = "rproc-srm-dev"; reg = <0x44006000>; clocks = <&rcc TIM15_K>; clock-names = "int"; status = "disabled"; }; m4_timers16: timer@44007000 { compatible = "rproc-srm-dev"; reg = <0x44007000>; clocks = <&rcc TIM16_K>; clock-names = "int"; status = "disabled"; }; m4_timers17: timer@44008000 { compatible = "rproc-srm-dev"; reg = <0x44008000>; clocks = <&rcc TIM17_K>; clock-names = "int"; status = "disabled"; }; m4_spi5: spi@44009000 { compatible = "rproc-srm-dev"; reg = <0x44009000>; clocks = <&rcc SPI5_K>; status = "disabled"; }; m4_sai1: sai@4400a000 { compatible = "rproc-srm-dev"; reg = <0x4400a000>; clocks = <&rcc SAI1_K>; clock-names = "sai_ck"; status = "disabled"; }; m4_sai2: sai@4400b000 { compatible = "rproc-srm-dev"; reg = <0x4400b000>; clocks = <&rcc SAI2_K>; clock-names = "sai_ck"; status = "disabled"; }; m4_sai3: sai@4400c000 { compatible = "rproc-srm-dev"; reg = <0x4400c000>; clocks = <&rcc SAI3_K>; clock-names = "sai_ck"; status = "disabled"; }; m4_dfsdm: dfsdm@4400d000 { compatible = "rproc-srm-dev"; reg = <0x4400d000>; clocks = <&rcc DFSDM_K>; clock-names = "dfsdm"; status = "disabled"; }; m4_m_can1: can@4400e000 { compatible = "rproc-srm-dev"; reg = <0x4400e000>, <0x44011000>; clocks = <&rcc FDCAN>, <&rcc FDCAN_K>; clock-names = "hclk", "cclk"; status = "disabled"; }; m4_m_can2: can@4400f000 { compatible = "rproc-srm-dev"; reg = <0x4400f000>, <0x44011000>; clocks = <&rcc FDCAN>, <&rcc FDCAN_K>; clock-names = "hclk", "cclk"; status = "disabled"; }; m4_dma1: dma@48000000 { compatible = "rproc-srm-dev"; reg = <0x48000000>; clocks = <&rcc DMA1>; status = "disabled"; }; m4_dma2: dma@48001000 { compatible = "rproc-srm-dev"; reg = <0x48001000>; clocks = <&rcc DMA2>; status = "disabled"; }; m4_dmamux1: dma-router@48002000 { compatible = "rproc-srm-dev"; reg = <0x48002000>; clocks = <&rcc DMAMUX>; status = "disabled"; }; m4_adc: adc@48003000 { compatible = "rproc-srm-dev"; reg = <0x48003000>; clocks = <&rcc ADC12>, <&rcc ADC12_K>; clock-names = "bus", "adc"; status = "disabled"; }; m4_sdmmc3: sdmmc@48004000 { compatible = "rproc-srm-dev"; reg = <0x48004000>, <0x48005000>; clocks = <&rcc SDMMC3_K>; status = "disabled"; }; m4_usbotg_hs: usb-otg@49000000 { compatible = "rproc-srm-dev"; reg = <0x49000000>; clocks = <&rcc USBO_K>; clock-names = "otg"; status = "disabled"; }; m4_hash2: hash@4c002000 { compatible = "rproc-srm-dev"; reg = <0x4c002000>; clocks = <&rcc HASH2>; status = "disabled"; }; m4_rng2: rng@4c003000 { compatible = "rproc-srm-dev"; reg = <0x4c003000>; clocks = <&rcc RNG2_K>; status = "disabled"; }; m4_crc2: crc@4c004000 { compatible = "rproc-srm-dev"; reg = <0x4c004000>; clocks = <&rcc CRC2>; status = "disabled"; }; m4_cryp2: cryp@4c005000 { compatible = "rproc-srm-dev"; reg = <0x4c005000>; clocks = <&rcc CRYP2>; status = "disabled"; }; m4_dcmi: dcmi@4c006000 { compatible = "rproc-srm-dev"; reg = <0x4c006000>; clocks = <&rcc DCMI>; clock-names = "mclk"; status = "disabled"; }; m4_lptimer2: timer@50021000 { compatible = "rproc-srm-dev"; reg = <0x50021000>; clocks = <&rcc LPTIM2_K>; clock-names = "mux"; status = "disabled"; }; m4_lptimer3: timer@50022000 { compatible = "rproc-srm-dev"; reg = <0x50022000>; clocks = <&rcc LPTIM3_K>; clock-names = "mux"; status = "disabled"; }; m4_lptimer4: timer@50023000 { compatible = "rproc-srm-dev"; reg = <0x50023000>; clocks = <&rcc LPTIM4_K>; clock-names = "mux"; status = "disabled"; }; m4_lptimer5: timer@50024000 { compatible = "rproc-srm-dev"; reg = <0x50024000>; clocks = <&rcc LPTIM5_K>; clock-names = "mux"; status = "disabled"; }; m4_sai4: sai@50027000 { compatible = "rproc-srm-dev"; reg = <0x50027000>; clocks = <&rcc SAI4_K>; clock-names = "sai_ck"; status = "disabled"; }; m4_qspi: qspi@58003000 { compatible = "rproc-srm-dev"; reg = <0x58003000>, <0x70000000>; clocks = <&rcc QSPI_K>; status = "disabled"; }; m4_ethernet0: ethernet@5800a000 { compatible = "rproc-srm-dev"; reg = <0x5800a000>; clock-names = "stmmaceth", "mac-clk-tx", "mac-clk-rx", "ethstp", "syscfg-clk"; clocks = <&rcc ETHMAC>, <&rcc ETHTX>, <&rcc ETHRX>, <&rcc ETHSTP>, <&rcc SYSCFG>; status = "disabled"; }; }; };
从以上可以看出,该节点描述了远程协处理器M4的所有可用外围设备,但它们默认状态是禁用的。要使能某个外设不需要更改设备树,只需要在IDE中进行相关的配置即可, 在通过Remoteproc框架加载M4固件时会自动激活该外设。所以这部分节点内容一般不需要去动它。
接下来看物理内存的配置,下面是stm32mp157a-basic.dts文件中reserved-memory节点的配置信息。
reserved-memory { #address-cells = <1>; #size-cells = <1>; ranges; retram: retram@0x38000000 { compatible = "shared-dma-pool"; reg = <0x38000000 0x10000>; no-map; }; mcuram: mcuram@0x30000000 { compatible = "shared-dma-pool"; reg = <0x30000000 0x40000>; no-map; }; mcuram2: mcuram2@0x10000000 { compatible = "shared-dma-pool"; reg = <0x10000000 0x40000>; no-map; }; vdev0vring0: vdev0vring0@10040000 { compatible = "shared-dma-pool"; reg = <0x10040000 0x2000>; no-map; }; vdev0vring1: vdev0vring1@10042000 { compatible = "shared-dma-pool"; reg = <0x10042000 0x2000>; no-map; }; vdev0buffer: vdev0buffer@10044000 { compatible = "shared-dma-pool"; reg = <0x10044000 0x4000>; no-map; }; gpu_reserved: gpu@d4000000 { reg = <0xd4000000 0x4000000>; no-map; }; };
以上就是SRAM1~SRAM4内存区域的具体配置,这要与IDE的链接脚本中配置(见后面)要一致。关于这部分内存的具体描述可见“基于STM32MP157的异核间通信(续一)”中的相关介绍。
通过上面的配置,物理内存区域被划分成如下形式。

最后来看资源表的配置,这部分在IDE端进行。先看文件rsc_table.c,在其中定义了vring要个数和VirtIO RPMSG的设备ID,如下图所示。

特别要注意,VIRTIO_ID_RPMSG的数值一定要与Linux中有一致才能匹配,该项在内核源码的include/uapi/linux/virtio_ids.h文件中,如下图所示。

接下来看文件openamp_conf.h,在其中定义了收发vring的地址和vring_buffer的地址,并定义了vring的对齐方式和buffer的数量,还定义了两个vring的ID,如下图所示。

上面的定义中,值为-1的表示由A7端(Linux系统)来定义。对齐方式为16位对齐,vring_buffer数量为16个,接收vring为VRING0_ID,发送vring为VRING1_ID。
最后来看物理内存的定义,它位于链接脚本文件STM32MP157AACX_RAM.ld中。这部分要与前面设备树中的定义一致,如下图所示。

在上面的配置中,第一行(RETRAM_interrupts)是M4的中断向量区,这部分一般不动它,第二行(FLASH_text)是固件的代码段部分,即SRAM1部分,第三行(RAM1_data)是固件的数据段部分,即SRAM2部分,这两部分相加刚好等前面配置的256KB,第四行(RAM2_ipc_shm)就是用于通信的共享内存区域,即SRAM3部分,这里只用了32KB。默认配置下,M4并没有使用SRAM4,它被分配给了A7用作DMA的buffer了。
在开发板上加载好M4固件并启动后,可以在目录/sys/kernel/debug/remoteproc/remoteproc0下查看文件carveout_memories和resource_table,就可以看到前面的配置信息了。如下图所示。

到此关于STM32MP157异核间通信的设备树配置和IDE端配置就讨论完了,一般使用默认配置即可,只有在特殊需要时才根据实际情况更改。
下面来看一下异核通信在内核源码中是如何配置的。在内核源码中,进入到Device Drivers一项下,可以找到两项相关配置,如下图所示。

进入Remoteproc drivers下,勾选所有选项,如下图所示。

进入Rpmsg drivers下,勾选最后两项,如下图所示。

上图中的第一项是用于生成rpmsg的字符设备节点的,在前面的例子中,rpmsg设备节点是自定义的,所以这里不要勾选,以免产生冲突。
至此,有关STM32MP157异核通信的技术原理就全部讨论完了。

浙公网安备 33010602011771号