From 7fd1f1479fb2ae722c08280d67a423b867cbdafc Mon Sep 17 00:00:00 2001 From: Dan Collins Date: Sun, 29 Jun 2025 20:24:43 +1200 Subject: [PATCH 1/3] soc: rp2350: integrate support for second CPU core This commit introduces a means to build Zephyr for both Cortex M33 cores of the RP2350, and for CPU0 to boot CPU1. It includes a partition table for the rpi_pico2 board that demonstrates how the two cores can operate independently. Signed-off-by: Dan Collins --- .../common/rpi_pico-pinctrl-common.dtsi | 10 ++ .../raspberrypi/rpi_pico2/Kconfig.rpi_pico2 | 3 +- boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi | 109 +++++++----------- .../rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.dts | 91 +++++++++++++++ ...3.yaml => rpi_pico2_rp2350a_m33_cpu0.yaml} | 6 +- ...g => rpi_pico2_rp2350a_m33_cpu0_defconfig} | 0 ...m33.dts => rpi_pico2_rp2350a_m33_cpu1.dts} | 20 +++- .../rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.yaml | 20 ++++ .../rpi_pico2_rp2350a_m33_cpu1_defconfig | 14 +++ modules/hal_rpi_pico/Kconfig | 11 ++ soc/raspberrypi/rpi_pico/common/mailbox.h | 46 ++++++++ .../rpi_pico/rp2350/CMakeLists.txt | 5 + soc/raspberrypi/rpi_pico/rp2350/Kconfig | 23 +++- .../rpi_pico/rp2350/Kconfig.defconfig | 8 +- .../Kconfig.defconfig_rp2350a_cm33_cpu0 | 20 ++++ .../Kconfig.defconfig_rp2350a_cm33_cpu1 | 19 +++ soc/raspberrypi/rpi_pico/rp2350/Kconfig.soc | 10 +- soc/raspberrypi/rpi_pico/rp2350/soc.c | 105 ++++++++++++++++- soc/raspberrypi/rpi_pico/soc.yml | 3 +- 19 files changed, 436 insertions(+), 87 deletions(-) create mode 100644 boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.dts rename boards/raspberrypi/rpi_pico2/{rpi_pico2_rp2350a_m33.yaml => rpi_pico2_rp2350a_m33_cpu0.yaml} (67%) rename boards/raspberrypi/rpi_pico2/{rpi_pico2_rp2350a_m33_defconfig => rpi_pico2_rp2350a_m33_cpu0_defconfig} (100%) rename boards/raspberrypi/rpi_pico2/{rpi_pico2_rp2350a_m33.dts => rpi_pico2_rp2350a_m33_cpu1.dts} (60%) create mode 100644 boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.yaml create mode 100644 boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1_defconfig create mode 100644 soc/raspberrypi/rpi_pico/common/mailbox.h create mode 100644 soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu0 create mode 100644 soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu1 diff --git a/boards/raspberrypi/common/rpi_pico-pinctrl-common.dtsi b/boards/raspberrypi/common/rpi_pico-pinctrl-common.dtsi index 66ccfd208959..2966637a910c 100644 --- a/boards/raspberrypi/common/rpi_pico-pinctrl-common.dtsi +++ b/boards/raspberrypi/common/rpi_pico-pinctrl-common.dtsi @@ -15,6 +15,16 @@ }; }; + uart1_default: uart1_default { + group1 { + pinmux = ; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + i2c0_default: i2c0_default { group1 { pinmux = , ; diff --git a/boards/raspberrypi/rpi_pico2/Kconfig.rpi_pico2 b/boards/raspberrypi/rpi_pico2/Kconfig.rpi_pico2 index bcce97758fbe..5094b641b69a 100644 --- a/boards/raspberrypi/rpi_pico2/Kconfig.rpi_pico2 +++ b/boards/raspberrypi/rpi_pico2/Kconfig.rpi_pico2 @@ -2,4 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 config BOARD_RPI_PICO2 - select SOC_RP2350A_M33 if BOARD_RPI_PICO2_RP2350A_M33 + select SOC_RP2350A_M33_CPU0 if BOARD_RPI_PICO2_RP2350A_M33_CPU0 + select SOC_RP2350A_M33_CPU1 if BOARD_RPI_PICO2_RP2350A_M33_CPU1 diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi b/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi index 522413c94f1a..6d758fe9c11f 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi @@ -10,21 +10,17 @@ #include #include "rpi_pico2-pinctrl.dtsi" -#include "../common/rpi_pico-led.dtsi" -/ { - chosen { - zephyr,sram = &sram0; - zephyr,flash = &flash0; - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - zephyr,code-partition = &code_partition; - }; - - aliases { - watchdog0 = &wdt0; - }; +/* + * We need to be careful about shared definitions in this + * device tree. Zephyr will run start up code on peripherals + * that are present here - meaning it will get run twice. + * Best case, this is a bit wasteful as the bus accesses are + * arbitrated. Worst case, the peripherals are left in an + * unknown state based on the order of access. + */ +/ { pico_header: connector { compatible = "raspberrypi,pico-header"; #gpio-cells = <2>; @@ -79,70 +75,45 @@ /* * Usable flash. Starts at 0x100, after the image definition block. - * The partition size is 4MB minus the 0x100 bytes taken by the + * The partition size is 2 MB minus the 0x100 bytes taken by the * image definition. */ - code_partition: partition@100 { - label = "code-partition"; - reg = <0x100 (DT_SIZE_M(4) - 0x100)>; + code_partition_cpu0: partition@100 { + label = "code-partition-cpu0"; + reg = <0x100 (DT_SIZE_M(2) - 0x100)>; read-only; }; - }; -}; -&uart0 { - current-speed = <115200>; - status = "okay"; - pinctrl-0 = <&uart0_default>; - pinctrl-names = "default"; -}; - -gpio0_lo: &gpio0 { - status = "okay"; -}; - -&spi0 { - clock-frequency = ; - pinctrl-0 = <&spi0_default>; - pinctrl-names = "default"; -}; - -&i2c0 { - clock-frequency = ; - pinctrl-0 = <&i2c0_default>; - pinctrl-names = "default"; - status = "okay"; -}; - -&i2c1 { - clock-frequency = ; - pinctrl-0 = <&i2c1_default>; - pinctrl-names = "default"; - status = "okay"; -}; - -&adc { - pinctrl-0 = <&adc_default>; - pinctrl-names = "default"; - status = "okay"; + /* + * Code for the second CPU uses the upper 2 MB of flash. + */ + code_partition_cpu1: partition@200000 { + label = "code-partition-cpu1"; + reg = <0x200000 DT_SIZE_M(2)>; + read-only; + }; + }; }; -&pwm { - pinctrl-0 = <&pwm_ch4b_default>; - pinctrl-names = "default"; - divider-int-0 = <255>; -}; +/ { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; -&timer0 { - status = "okay"; -}; + /* SRAM0-3 */ + sram0_cpu0: cpu0@20000000 { + reg = <0x20000000 DT_SIZE_K(256)>; + }; -&wdt0 { - status = "okay"; -}; + /* SRAM4-7 */ + sram0_cpu1: cpu1@20040000 { + reg = <0x20040000 DT_SIZE_K(256)>; + }; -zephyr_udc0: &usbd { - status = "okay"; + /* SRAM8-9 */ + sram0_shared: shared@20080000 { + reg = <0x20080000 DT_SIZE_K(8)>; + }; + }; }; - -pico_serial: &uart0 {}; diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.dts b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.dts new file mode 100644 index 000000000000..d20e9ab94ef1 --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.dts @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024 Andrew Featherstone + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +/* The build system assumes that there's a cpucluster-specific file. + * + * This file provides composition of the device tree: + * 1. The common features of the SoC + * 2. Core-specific configuration. + * 3. Board-specific configuration. + */ +#include +#include + +#include "rpi_pico2.dtsi" +#include "../common/rpi_pico-led.dtsi" + +/ { + chosen { + zephyr,sram = &sram0_cpu0; + zephyr,flash = &flash0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,code-partition = &code_partition_cpu0; + }; + + aliases { + watchdog0 = &wdt0; + }; +}; + +&uart0 { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; +}; + +gpio0_lo: &gpio0 { + status = "okay"; +}; + +&spi0 { + clock-frequency = ; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; +}; + +&i2c0 { + clock-frequency = ; + pinctrl-0 = <&i2c0_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&i2c1 { + clock-frequency = ; + pinctrl-0 = <&i2c1_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&adc { + pinctrl-0 = <&adc_default>; + pinctrl-names = "default"; + status = "okay"; +}; + +&pwm { + pinctrl-0 = <&pwm_ch4b_default>; + pinctrl-names = "default"; + divider-int-0 = <255>; +}; + +&timer0 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +zephyr_udc0: &usbd { + status = "okay"; +}; + +pico_serial: &uart0 {}; diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.yaml b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.yaml similarity index 67% rename from boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.yaml rename to boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.yaml index f83082393e07..eaa3b0db2d50 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.yaml +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.yaml @@ -1,9 +1,9 @@ -identifier: rpi_pico2/rp2350a/m33 -name: Raspberry Pi Pico 2 (Cortex-M33) +identifier: rpi_pico2/rp2350a/m33_cpu0 +name: Raspberry Pi Pico 2 (Cortex-M33 CPU0) type: mcu arch: arm flash: 4096 -ram: 520 +ram: 264 toolchain: - zephyr - gnuarmemb diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_defconfig b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0_defconfig similarity index 100% rename from boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_defconfig rename to boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0_defconfig diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.dts b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.dts similarity index 60% rename from boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.dts rename to boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.dts index f96491f44e2e..f8dba476b12e 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.dts +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.dts @@ -16,7 +16,21 @@ #include #include -/* there's nothing specific to the Cortex-M33 cores vs the (not yet - * implemented) Hazard3 cores. - */ #include "rpi_pico2.dtsi" + +/ { + chosen { + zephyr,sram = &sram0_cpu1; + zephyr,flash = &flash0; + zephyr,console = &uart1; + zephyr,shell-uart = &uart1; + zephyr,code-partition = &code_partition_cpu1; + }; +}; + +&uart1 { + current-speed = <115200>; + status = "okay"; + pinctrl-0 = <&uart1_default>; + pinctrl-names = "default"; +}; diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.yaml b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.yaml new file mode 100644 index 000000000000..b47f01d4dac2 --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.yaml @@ -0,0 +1,20 @@ +identifier: rpi_pico2/rp2350a/m33_cpu1 +name: Raspberry Pi Pico 2 (Cortex-M33 CPU1) +type: mcu +arch: arm +flash: 4096 +ram: 264 +toolchain: + - zephyr + - gnuarmemb +supported: + - adc + - clock + - counter + - dma + - gpio + - hwinfo + - i2c + - pwm + - spi + - uart diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1_defconfig b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1_defconfig new file mode 100644 index 000000000000..8bd68e351139 --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1_defconfig @@ -0,0 +1,14 @@ +# This configuration is orthogonal to whether the Cortex-M33 or Hazard3 cores +# are in use, but Zephyr does not support providing a qualifier-agnostic +# _defconfig file. +CONFIG_BUILD_OUTPUT_HEX=y +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_CLOCK_CONTROL=y +CONFIG_CONSOLE=y +CONFIG_GPIO=y +CONFIG_RESET=y +CONFIG_SERIAL=y +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=150000000 +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_USE_DT_CODE_PARTITION=y diff --git a/modules/hal_rpi_pico/Kconfig b/modules/hal_rpi_pico/Kconfig index 3c37c84f4c01..99b4d338325f 100644 --- a/modules/hal_rpi_pico/Kconfig +++ b/modules/hal_rpi_pico/Kconfig @@ -54,3 +54,14 @@ config PICOSDK_USE_RTC bool help Use the RTC driver from pico-sdk + +config PICOSDK_USE_SYNC + bool + help + Use the sync support from pico-sdk + +config PICOSDK_USE_MULTICORE + bool + select PICOSDK_USE_SYNC + help + Use the multicore support from pico-sdk diff --git a/soc/raspberrypi/rpi_pico/common/mailbox.h b/soc/raspberrypi/rpi_pico/common/mailbox.h new file mode 100644 index 000000000000..38dd71fe2d7c --- /dev/null +++ b/soc/raspberrypi/rpi_pico/common/mailbox.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 Dan Collins + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file Mailbox interface for the Raspberry Pi RP2 family processors + */ + +#ifndef _RPI_PICO_MAILBOX_H_ +#define _RPI_PICO_MAILBOX_H_ + +#include +#include "cmsis_gcc.h" + +static inline void mailbox_put_blocking(uint32_t value) +{ + while (!(sio_hw->fifo_st & SIO_FIFO_ST_RDY_BITS)) { + ; + } + + sio_hw->fifo_wr = value; + + /* Inform other CPU about FIFO update. */ + __SEV(); +} + +static inline uint32_t mailbox_pop_blocking(void) +{ + while (!(sio_hw->fifo_st & SIO_FIFO_ST_VLD_BITS)) { + __WFE(); + } + + return sio_hw->fifo_rd; +} + +static inline void mailbox_flush(void) +{ + /* Read all valid data from the mailbox. */ + while (sio_hw->fifo_st & SIO_FIFO_ST_VLD_BITS) { + (void)sio_hw->fifo_rd; + } +} + +#endif /* _RPI_PICO_MAILBOX_H_ */ diff --git a/soc/raspberrypi/rpi_pico/rp2350/CMakeLists.txt b/soc/raspberrypi/rpi_pico/rp2350/CMakeLists.txt index 8f48fc01aba9..19ddf3bb8839 100644 --- a/soc/raspberrypi/rpi_pico/rp2350/CMakeLists.txt +++ b/soc/raspberrypi/rpi_pico/rp2350/CMakeLists.txt @@ -7,4 +7,9 @@ zephyr_library_sources(soc.c) zephyr_include_directories(.) +# CPU0 needs an IMAGE_DEF for the boot ROM, while CPU1 does not! +if(CONFIG_SOC_RP2350A_M33_CPU0) set(SOC_LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld CACHE INTERNAL "") +else() +set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "SoC Linker script") +endif() diff --git a/soc/raspberrypi/rpi_pico/rp2350/Kconfig b/soc/raspberrypi/rpi_pico/rp2350/Kconfig index 35ebf8ad5809..32ac621dc5ea 100644 --- a/soc/raspberrypi/rpi_pico/rp2350/Kconfig +++ b/soc/raspberrypi/rpi_pico/rp2350/Kconfig @@ -7,9 +7,18 @@ config SOC_SERIES_RP2350 select HAS_RPI_PICO select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE select SOC_RESET_HOOK + +config SOC_RP2350A_M33_CPU0 + select ARM + select ARM_TRUSTZONE_M + select CPU_CORTEX_M_HAS_SYSTICK + select CPU_CORTEX_M_HAS_VTOR + select CPU_CORTEX_M33 + select CPU_HAS_ARM_MPU + select CPU_HAS_ARM_SAU select XIP -config SOC_RP2350A_M33 +config SOC_RP2350A_M33_CPU1 select ARM select ARM_TRUSTZONE_M select CPU_CORTEX_M_HAS_SYSTICK @@ -38,3 +47,15 @@ config RP2_REQUIRES_IMAGE_DEFINITION_BLOCK help Include an Image Definition Block (IMAGE_DEF) to enable the bootroom in RP23XX devices to consider this a valid image in flash. + +if SOC_RP2350A_M33_CPU0 + +config SOC_RP2350A_BOOT_CPU1 + bool "Apply boot sequence for CPU1 during system init" + help + Applies the boot sequence required to start the second CPU core. The + partition table in the device tree defines the flash address used + for the CPU1 image. The vector table, initial stack pointer and + entry point are loaded from the image at this address. + +endif diff --git a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig index 4fed033b8048..04ea95c170db 100644 --- a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig +++ b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig @@ -5,12 +5,6 @@ if SOC_SERIES_RP2350 -config BUILD_OUTPUT_UF2_USE_FLASH_BASE - default y if RP2_REQUIRES_IMAGE_DEFINITION_BLOCK - -config BUILD_OUTPUT_UF2_USE_FLASH_OFFSET - default y if !RP2_REQUIRES_IMAGE_DEFINITION_BLOCK - config NUM_IRQS default 52 @@ -19,4 +13,6 @@ DT_CLK_SYS_PATH := $(dt_nodelabel_path,clk_sys) config SYS_CLOCK_HW_CYCLES_PER_SEC default $(dt_node_int_prop_int,$(DT_CLK_SYS_PATH),clock-frequency) +rsource "Kconfig.defconfig_*" + endif # SOC_SERIES_RP2350 diff --git a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu0 b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu0 new file mode 100644 index 000000000000..00a654cefa34 --- /dev/null +++ b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu0 @@ -0,0 +1,20 @@ +# Raspberry Pi RP2350 MCU line +# ARM Cortex M33, CPU0 + +# Copyright (c) 2025 Dan Collins +# SPDX-License-Identifier: Apache-2.0 + +if SOC_RP2350A_M33_CPU0 + +# For CPU0, we need to use the base address of the flash rather than the +# code address - because the image definition block needs to be at the +# start of flash for the boot ROM to find it. If we don't have the image +# definition block, then we should just use the offset. + +config BUILD_OUTPUT_UF2_USE_FLASH_BASE + default y if RP2_REQUIRES_IMAGE_DEFINITION_BLOCK + +config BUILD_OUTPUT_UF2_USE_FLASH_OFFSET + default y if !RP2_REQUIRES_IMAGE_DEFINITION_BLOCK + +endif # SOC_RP2350A_M33_CPU0 diff --git a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu1 b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu1 new file mode 100644 index 000000000000..da3e4245e4c2 --- /dev/null +++ b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu1 @@ -0,0 +1,19 @@ +# Raspberry Pi RP2350 MCU line +# ARM Cortex M33, CPU1 + +# Copyright (c) 2025 Dan Collins +# SPDX-License-Identifier: Apache-2.0 + +if SOC_RP2350A_M33_CPU1 + +# For CPU1, we need to use both the base address of flash as well as the +# offset - as our partition table puts the code section well above the +# base address of the flash. + +config BUILD_OUTPUT_UF2_USE_FLASH_BASE + default y + +config BUILD_OUTPUT_UF2_USE_FLASH_OFFSET + default y + +endif # SOC_RP2350A_M33_CPU1 diff --git a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.soc b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.soc index 069bc56cfbf3..7702eb84ec08 100644 --- a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.soc +++ b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.soc @@ -14,11 +14,17 @@ config SOC_RP2350A bool select SOC_SERIES_RP2350 -config SOC_RP2350A_M33 +config SOC_RP2350A_M33_CPU0 bool select SOC_RP2350A help - Use the RP2350A with a Cortex-M33 core in both 'sockets'. + Use the RP2350A with a Cortex-M33 core as CPU0. + +config SOC_RP2350A_M33_CPU1 + bool + select SOC_RP2350A + help + Use the RP2350A with a Cortex-M33 core as CPU1. config SOC_RP2350B bool diff --git a/soc/raspberrypi/rpi_pico/rp2350/soc.c b/soc/raspberrypi/rpi_pico/rp2350/soc.c index 84bcbffc7d97..7243fdba645c 100644 --- a/soc/raspberrypi/rpi_pico/rp2350/soc.c +++ b/soc/raspberrypi/rpi_pico/rp2350/soc.c @@ -12,13 +12,116 @@ * for the Raspberry Pi RP235xx (RP2350A, RP2350B, RP2354A, RP2354B). */ +#include +#include +#include +#include +#include + +#define LOG_LEVEL CONFIG_SOC_LOG_LEVEL +LOG_MODULE_DECLARE(soc); + #if CONFIG_SOC_RESET_HOOK #include - void soc_reset_hook(void) { runtime_init_per_core_enable_coprocessors(); } #endif /* CONFIG_SOC_RESET_HOOK */ + +#if CONFIG_SOC_RP2350A_BOOT_CPU1 + +#include +#include "common/mailbox.h" + +static inline bool address_in_range(uint32_t addr, uint32_t base, uint32_t size) +{ + return addr >= base && addr < base + size; +} + +static int reset_cpu1(void) +{ + uint32_t val; + + /* Power off, and wait for it to take effect. */ + hw_set_bits(&psm_hw->frce_off, PSM_FRCE_OFF_PROC1_BITS); + while (!(psm_hw->frce_off & PSM_FRCE_OFF_PROC1_BITS)) { + ; + } + + /* Power back on, and we can wait for a '0' in the FIFO to know + * that it has come back. + */ + hw_clear_bits(&psm_hw->frce_off, PSM_FRCE_OFF_PROC1_BITS); + val = mailbox_pop_blocking(); + + return val == 0 ? 0 : -EIO; +} + +static void boot_cpu1(uint32_t vector_table_addr, uint32_t stack_ptr, uint32_t reset_ptr) +{ + /* We synchronise with CPU1 and then we can hand over the memory addresses. */ + uint32_t cmds[] = {0, 0, 1, vector_table_addr, stack_ptr, reset_ptr}; + uint32_t seq = 0; + + do { + uint32_t cmd = cmds[seq], rsp; + + if (cmd == 0) { + mailbox_flush(); + __SEV(); + } + + mailbox_put_blocking(cmd); + rsp = mailbox_pop_blocking(); + + seq = cmd == rsp ? seq + 1 : 0; + } while (seq < ARRAY_SIZE(cmds)); +} + +static int enable_cpu1(void) +{ + /* Flash addresses are defined in our partition table from the device tree. */ + uint32_t cpu1_flash_base = + DT_REG_ADDR(DT_NODELABEL(flash0)) + DT_REG_ADDR(DT_NODELABEL(code_partition_cpu1)); + uint32_t cpu1_flash_size = DT_REG_SIZE(DT_NODELABEL(code_partition_cpu1)); + + uint32_t *cpu1_vector_table = (uint32_t *)cpu1_flash_base; + uint32_t cpu1_stack_ptr = cpu1_vector_table[0]; + uint32_t cpu1_reset_ptr = cpu1_vector_table[1]; + + /* RAM address used to check arguments. */ + uint32_t sram0_start = DT_REG_ADDR(DT_NODELABEL(sram0)); + uint32_t sram0_size = DT_REG_SIZE(DT_NODELABEL(sram0)); + + /* Stack pointer shall point within RAM. */ + if (!address_in_range(cpu1_stack_ptr, sram0_start, sram0_size)) { + LOG_ERR("CPU1 stack pointer invalid."); + return -EINVAL; + } + + /* Reset pointer shall point to code within the CPU1 partition. */ + if (!address_in_range(cpu1_reset_ptr, cpu1_flash_base, cpu1_flash_size)) { + LOG_ERR("CPU1 reset pointer invalid."); + return -EINVAL; + } + + LOG_DBG("CPU1 vector table at 0x%p", cpu1_vector_table); + LOG_DBG("CPU1 stack pointer at 0x%08x", cpu1_stack_ptr); + LOG_DBG("CPU1 reset pointer at 0x%08x", cpu1_reset_ptr); + + if (reset_cpu1() != 0) { + LOG_ERR("CPU1 reset failed."); + return -EIO; + } + + boot_cpu1((uint32_t)cpu1_vector_table, cpu1_stack_ptr, cpu1_reset_ptr); + + return 0; +} + +SYS_INIT(enable_cpu1, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); + +#endif /* CONFIG_SOC_RP2350A_BOOT_CPU1 */ diff --git a/soc/raspberrypi/rpi_pico/soc.yml b/soc/raspberrypi/rpi_pico/soc.yml index fac2f36cd969..4463de53f0ff 100644 --- a/soc/raspberrypi/rpi_pico/soc.yml +++ b/soc/raspberrypi/rpi_pico/soc.yml @@ -8,7 +8,8 @@ family: socs: - name: rp2350a cpuclusters: - - name: m33 + - name: m33_cpu0 + - name: m33_cpu1 - name: rp2350b cpuclusters: - name: m33 From 3836ff847aa85d07f2074821b632d9fb93929042 Mon Sep 17 00:00:00 2001 From: Dan Collins Date: Sun, 29 Jun 2025 20:26:38 +1200 Subject: [PATCH 2/3] soc: rp2350: skip clock initialisation for cpu1 We don't want to reinitialise the clock control when we boot the second core - so this commit introduces a means to skip initialisation (i.e. assume it is already initialised). Signed-off-by: Dan Collins --- drivers/clock_control/Kconfig.rpi_pico | 6 +++ .../clock_control/clock_control_rpi_pico.c | 47 +++++++++++-------- .../Kconfig.defconfig_rp2350a_cm33_cpu1 | 4 ++ 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/drivers/clock_control/Kconfig.rpi_pico b/drivers/clock_control/Kconfig.rpi_pico index 274f7c0eb281..8e141883153b 100644 --- a/drivers/clock_control/Kconfig.rpi_pico +++ b/drivers/clock_control/Kconfig.rpi_pico @@ -17,4 +17,10 @@ config RPI_PICO_ROSC_USE_MEASURED_FREQ Instead of the dts value, use the value measured by the frequency counter as the rosc frequency. +config RPI_PICO_SKIP_CLOCK_INIT + bool + help + Skip clock initialisation - which is needed when running Zephyr + on the second CPU core. + endif # CLOCK_CONTROL_RPI_PICO diff --git a/drivers/clock_control/clock_control_rpi_pico.c b/drivers/clock_control/clock_control_rpi_pico.c index 2aa60a3d5e20..e94c2686872d 100644 --- a/drivers/clock_control/clock_control_rpi_pico.c +++ b/drivers/clock_control/clock_control_rpi_pico.c @@ -278,23 +278,6 @@ uint64_t rpi_pico_frequency_count(const struct device *dev, clock_control_subsys ((fc0->result & CLOCKS_FC0_RESULT_FRAC_BITS) * 1000 / CLOCKS_FC0_RESULT_FRAC_BITS); } -static int rpi_pico_rosc_write(const struct device *dev, io_rw_32 *addr, uint32_t value) -{ - hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS); - - if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) { - return -EINVAL; - } - - *addr = value; - - if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) { - return -EINVAL; - } - - return 0; -} - /** * Get source clock id of this clock * @@ -621,14 +604,17 @@ static int clock_control_rpi_pico_get_rate(const struct device *dev, clock_contr return 0; } -void rpi_pico_clkid_tuple_swap(struct rpi_pico_clkid_tuple *lhs, struct rpi_pico_clkid_tuple *rhs) +#if !defined(CONFIG_RPI_PICO_SKIP_CLOCK_INIT) +static void rpi_pico_clkid_tuple_swap(struct rpi_pico_clkid_tuple *lhs, + struct rpi_pico_clkid_tuple *rhs) { struct rpi_pico_clkid_tuple tmp = *lhs; *lhs = *rhs; *rhs = tmp; } -void rpi_pico_clkid_tuple_reorder_by_dependencies(struct rpi_pico_clkid_tuple *tuples, size_t len) +static void rpi_pico_clkid_tuple_reorder_by_dependencies(struct rpi_pico_clkid_tuple *tuples, + size_t len) { uint32_t sorted_idx = 0; uint32_t checked_idx = 0; @@ -645,6 +631,23 @@ void rpi_pico_clkid_tuple_reorder_by_dependencies(struct rpi_pico_clkid_tuple *t } } +static int rpi_pico_rosc_write(const struct device *dev, io_rw_32 *addr, uint32_t value) +{ + hw_clear_bits(&rosc_hw->status, ROSC_STATUS_BADWRITE_BITS); + + if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) { + return -EINVAL; + } + + *addr = value; + + if (rosc_hw->status & ROSC_STATUS_BADWRITE_BITS) { + return -EINVAL; + } + + return 0; +} + static int clock_control_rpi_pico_init(const struct device *dev) { const uint32_t cycles_per_tick = CLOCK_FREQ_xosc / 1000000; @@ -782,6 +785,12 @@ static int clock_control_rpi_pico_init(const struct device *dev) return 0; } +#else +static int clock_control_rpi_pico_init(const struct device *dev) +{ + return 0; +} +#endif static DEVICE_API(clock_control, clock_control_rpi_pico_api) = { .on = clock_control_rpi_pico_on, diff --git a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu1 b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu1 index da3e4245e4c2..0c2145327bf3 100644 --- a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu1 +++ b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.defconfig_rp2350a_cm33_cpu1 @@ -16,4 +16,8 @@ config BUILD_OUTPUT_UF2_USE_FLASH_BASE config BUILD_OUTPUT_UF2_USE_FLASH_OFFSET default y +# Don't initialise the clock controller on CPU1 as this is handled by CPU0! +config RPI_PICO_SKIP_CLOCK_INIT + default y if SOC_RP2350A_M33_CPU1 + endif # SOC_RP2350A_M33_CPU1 From 82e6f0042ce5b042e8112bbf98fea85c5930883b Mon Sep 17 00:00:00 2001 From: Dan Collins Date: Sat, 28 Jun 2025 07:52:04 +1200 Subject: [PATCH 3/3] drivers: pi_pico: add ipm drivers This commit introduces an interprocess mailbox driver for the Raspberry Pi Pico. Signed-off-by: Dan Collins --- drivers/ipm/CMakeLists.txt | 1 + drivers/ipm/Kconfig | 1 + drivers/ipm/Kconfig.rpi_pico | 8 ++++ drivers/ipm/ipm_rpi_pico.c | 88 ++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 drivers/ipm/Kconfig.rpi_pico create mode 100644 drivers/ipm/ipm_rpi_pico.c diff --git a/drivers/ipm/CMakeLists.txt b/drivers/ipm/CMakeLists.txt index ca2aa03591c3..02ff646beb41 100644 --- a/drivers/ipm/CMakeLists.txt +++ b/drivers/ipm/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_IPM_STM32_IPCC ipm_stm32_ipcc.c) zephyr_library_sources_ifdef(CONFIG_IPM_NRFX ipm_nrfx_ipc.c) zephyr_library_sources_ifdef(CONFIG_IPM_STM32_HSEM ipm_stm32_hsem.c) zephyr_library_sources_ifdef(CONFIG_IPM_CAVS_HOST ipm_cavs_host.c) +zephyr_library_sources_ifdef(CONFIG_IPM_RPI_PICO ipm_rpi_pico.c) zephyr_library_sources_ifdef(CONFIG_IPM_SEDI ipm_sedi.c) zephyr_library_sources_ifdef(CONFIG_IPM_IVSHMEM ipm_ivshmem.c) zephyr_library_sources_ifdef(CONFIG_ESP32_SOFT_IPM ipm_esp32.c) diff --git a/drivers/ipm/Kconfig b/drivers/ipm/Kconfig index ba4571ed7581..d0b204acac3d 100644 --- a/drivers/ipm/Kconfig +++ b/drivers/ipm/Kconfig @@ -76,6 +76,7 @@ source "drivers/ipm/Kconfig.imx" source "drivers/ipm/Kconfig.stm32" source "drivers/ipm/Kconfig.intel_adsp" source "drivers/ipm/Kconfig.ivshmem" +source "drivers/ipm/Kconfig.rpi_pico" source "drivers/ipm/Kconfig.sedi" diff --git a/drivers/ipm/Kconfig.rpi_pico b/drivers/ipm/Kconfig.rpi_pico new file mode 100644 index 000000000000..e71d759da510 --- /dev/null +++ b/drivers/ipm/Kconfig.rpi_pico @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2025 Dan Collins + +config IPM_RPI_PICO + bool "Raspberry Pi Pico IPM Driver" + default y if DT_HAS_RPI_PICO_IPM_ENABLED + help + This option enables the Raspberry Pi Pico Inter-process mailbox driver. diff --git a/drivers/ipm/ipm_rpi_pico.c b/drivers/ipm/ipm_rpi_pico.c new file mode 100644 index 000000000000..a8269b89d9d0 --- /dev/null +++ b/drivers/ipm/ipm_rpi_pico.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025 Dan Collins + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#define DT_DRV_COMPAT rpi_pico_ipc_mailbox + +#include +#include + +#include +LOG_MODULE_REGISTER(ipm_rpi_pico, CONFIG_IPM_LOG_LEVEL); + +#include + +struct rpi_pico_mailbox_config { + void (*irq_config_func)(const struct device *dev); +}; + +struct rpi_pico_mailbox_data { + ipm_callback_t cb; + void *user_data; +}; + +static struct rpi_pico_mailbox_config rpi_pico_mailbox_config; +static struct rpi_pico_mailbox_data rpi_pico_mailbox_data; + +static int rpi_pico_mailbox_send(const struct device *dev, int wait, uint32_t id, const void *data, int size) +{ + ARG_UNUSED(data); + ARG_UNUSED(size); + + return 0; +} + +static void rpi_pico_mailbox_register_callback(const struct device *dev, ipm_callback_t cb, void *user_data) +{ + struct rpi_pico_mailbox_data *data = dev->data; + + data->cb = cb; + data->user_data = user_data; +} + +static int rpi_pico_mailbox_max_data_size_get(const struct device *dev) +{ + ARG_UNUSED(dev); + /* FIFO mailbox allows a single 32 bit value to be sent - and we + * use that as the channel identifier. */ + return 0; +} + +static unsigned int rpi_pico_mailbox_max_id_val_get(const struct device *dev) +{ + ARG_UNUSED(dev); + /* FIFO mailbox allows a single 32 bit value to be sent - and we + * use that as the channel identifier. */ + return UINT32_MAX; +} + +static int rpi_pico_mailbox_set_enabled(const struct device *dev, int enable) +{ + ARG_UNUSED(dev); + ARG_UNUSED(enable); + return 0; +} + + +static int rpi_pico_mailbox_init(const struct device *dev) +{ + return 0; +} + +static DEVICE_API(ipm, rpi_pico_mailbox_driver_api) = { + .send = rpi_pico_mailbox_send, + .register_callback = rpi_pico_mailbox_register_callback, + .max_data_size_get = rpi_pico_mailbox_max_data_size_get, + .max_id_val_get = rpi_pico_mailbox_max_id_val_get, + .set_enabled = rpi_pico_mailbox_set_enabled, +}; + +DEVICE_DT_INST_DEFINE(0, + &rpi_pico_mailbox_init, + NULL, + &rpi_pico_mailbox_data, &rpi_pico_mailbox_config, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &rpi_pico_mailbox_driver_api);