diff --git a/boards/raspberrypi/common/rpi_pico-led.dtsi b/boards/raspberrypi/common/rpi_pico-led.dtsi index 951e36260f200..f9653ca1f994e 100644 --- a/boards/raspberrypi/common/rpi_pico-led.dtsi +++ b/boards/raspberrypi/common/rpi_pico-led.dtsi @@ -9,6 +9,7 @@ leds { compatible = "gpio-leds"; led0: led_0 { + status = "disabled"; gpios = <&gpio0 25 GPIO_ACTIVE_HIGH>; label = "LED"; }; diff --git a/boards/raspberrypi/rpi_pico/rpi_pico.dts b/boards/raspberrypi/rpi_pico/rpi_pico.dts index 807dc8e780053..01924cb297240 100644 --- a/boards/raspberrypi/rpi_pico/rpi_pico.dts +++ b/boards/raspberrypi/rpi_pico/rpi_pico.dts @@ -8,3 +8,7 @@ #include "rpi_pico-common.dtsi" #include "../common/rpi_pico-led.dtsi" + +&led0 { + status = "okay"; +}; diff --git a/boards/raspberrypi/rpi_pico2/Kconfig.rpi_pico2 b/boards/raspberrypi/rpi_pico2/Kconfig.rpi_pico2 index 6e7a1a4456953..31cbdc000bb27 100644 --- a/boards/raspberrypi/rpi_pico2/Kconfig.rpi_pico2 +++ b/boards/raspberrypi/rpi_pico2/Kconfig.rpi_pico2 @@ -4,3 +4,5 @@ config BOARD_RPI_PICO2 select SOC_RP2350A_M33 if BOARD_RPI_PICO2_RP2350A_M33 || BOARD_RPI_PICO2_RP2350A_M33_W + 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 3b49981114797..66b0c0f37048e 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi @@ -12,19 +12,18 @@ #include "rpi_pico2-pinctrl.dtsi" #include "../common/rpi_pico-led.dtsi" -/ { - chosen { - zephyr,sram = &sram0; - zephyr,flash = &flash0; - zephyr,flash-controller = &qmi; - zephyr,console = &uart0; - zephyr,shell-uart = &uart0; - }; - - 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. + * Bacause of this, we mark all peripherals as "reserved" + * and will only enable them in the core-specific device trees + */ +/ { pico_header: connector { compatible = "raspberrypi,pico-header"; #gpio-cells = <2>; @@ -61,61 +60,64 @@ &flash0 { reg = <0x10000000 DT_SIZE_M(4)>; + status = "reserved"; }; &uart0 { current-speed = <115200>; - status = "okay"; + status = "reserved"; pinctrl-0 = <&uart0_default>; pinctrl-names = "default"; }; gpio0_lo: &gpio0 { - status = "okay"; + status = "reserved"; }; &spi0 { clock-frequency = ; pinctrl-0 = <&spi0_default>; pinctrl-names = "default"; + status = "reserved"; }; &i2c0 { clock-frequency = ; pinctrl-0 = <&i2c0_default>; pinctrl-names = "default"; - status = "okay"; + status = "reserved"; }; &i2c1 { clock-frequency = ; pinctrl-0 = <&i2c1_default>; pinctrl-names = "default"; - status = "okay"; + status = "reserved"; }; &adc { pinctrl-0 = <&adc_default>; pinctrl-names = "default"; - status = "okay"; + status = "reserved"; }; &pwm { pinctrl-0 = <&pwm_ch4b_default>; pinctrl-names = "default"; divider-int-0 = <255>; + status = "reserved"; }; &timer0 { - status = "okay"; + status = "reserved"; }; &wdt0 { - status = "okay"; + status = "reserved"; }; zephyr_udc0: &usbd { - status = "okay"; + status = "reserved"; }; pico_serial: &uart0 {}; diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.dts b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.dts index f96491f44e2e5..8c8aad885f02e 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.dts +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33.dts @@ -20,3 +20,64 @@ * implemented) Hazard3 cores. */ #include "rpi_pico2.dtsi" + +/ { + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; + + aliases { + watchdog0 = &wdt0; + }; +}; + +&flash0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +gpio0_lo: &gpio0 { + status = "okay"; +}; + +&spi0 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; + +&adc { + status = "okay"; +}; + +&pwm { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +zephyr_udc0: &usbd { + status = "okay"; +}; + +&led0 { + status = "okay"; +}; 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 0000000000000..2e1cc31d66bd7 --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.dts @@ -0,0 +1,82 @@ +/* + * 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 + +/* there's nothing specific to the Cortex-M33 cores vs the (not yet + * implemented) Hazard3 cores. + */ +#include "rpi_pico2.dtsi" +#include "rpi_pico2_split.dtsi" + +/delete-node/ &cpu1; + +/ { + chosen { + zephyr,sram = &sram0_cpu0; + zephyr,flash = &flash0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; + + aliases { + watchdog0 = &wdt0; + }; +}; + +&uart0 { + status = "okay"; +}; + +gpio0_lo: &gpio0 { + status = "okay"; +}; + +&led0 { + status = "okay"; +}; + +&flash0 { + status = "okay"; +}; + +&spi0 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; + +&adc { + status = "okay"; +}; + +&pwm { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.yaml b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.yaml new file mode 100644 index 0000000000000..df5640d98df55 --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0.yaml @@ -0,0 +1,16 @@ +identifier: rpi_pico2/rp2350a/m33_cpu0 +name: Raspberry Pi Pico 2 (Cortex-M33 CPU0) +type: mcu +arch: arm +flash: 4096 +ram: 256 +toolchain: + - zephyr + - gnuarmemb +supported: + - clock + - counter + - hwinfo + - i2c + - pwm + - uart diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0_defconfig b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0_defconfig new file mode 100644 index 0000000000000..4da77bdb95c25 --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu0_defconfig @@ -0,0 +1,13 @@ +# 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_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_USE_DT_CODE_PARTITION=y diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.dts b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.dts new file mode 100644 index 0000000000000..5213008293aea --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.dts @@ -0,0 +1,40 @@ +/* + * 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 + +/* there's nothing specific to the Cortex-M33 cores vs the (not yet + * implemented) Hazard3 cores. + */ +#include "rpi_pico2.dtsi" +#include "rpi_pico2_split.dtsi" + +/delete-node/ &cpu0; + +/ { + chosen { + zephyr,sram = &sram0_cpu1; + // Flash is only assigned to CPU0, CPU1 must + // execute from RAM to avoid access conflicts + // You can add a code-partition + // Then add image-source to the &cpu1_launcher on cpu0 + // zephyr,code-partition = &cpu1_slot0_partition; + }; +}; + +zephyr_udc0: &usbd { + status = "okay"; +}; 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 0000000000000..a26ed6a4917f0 --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1.yaml @@ -0,0 +1,13 @@ +identifier: rpi_pico2/rp2350a/m33_cpu1 +name: Raspberry Pi Pico 2 (Cortex-M33 CPU1) +type: mcu +arch: arm +flash: 0 +ram: 256 +toolchain: + - zephyr + - gnuarmemb +supported: + - hwinfo + - uart + - usbd 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 0000000000000..9021cc1a01423 --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_cpu1_defconfig @@ -0,0 +1,13 @@ +# 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_RESET=y +CONFIG_SERIAL=y +CONFIG_UART_CONSOLE=y +CONFIG_UART_INTERRUPT_DRIVEN=y +CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_XIP=n diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_w.dts b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_w.dts index 9c36addf655d7..8ebc23d246abb 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_w.dts +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_w.dts @@ -21,6 +21,67 @@ */ #include "rpi_pico2.dtsi" +/ { + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + }; + + aliases { + watchdog0 = &wdt0; + }; +}; + +&flash0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; +}; + +gpio0_lo: &gpio0 { + status = "okay"; +}; + +&spi0 { + status = "okay"; +}; + +&i2c0 { + status = "okay"; +}; + +&i2c1 { + status = "okay"; +}; + +&adc { + status = "okay"; +}; + +&pwm { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&wdt0 { + status = "okay"; +}; + +zephyr_udc0: &usbd { + status = "okay"; +}; + +&led0 { + status = "okay"; +}; + &pinctrl { pio0_spi0_default: pio0_spi0_default { /* gpio 25 is used for chip select, not assigned to the PIO */ diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_split.dtsi b/boards/raspberrypi/rpi_pico2/rpi_pico2_split.dtsi new file mode 100644 index 0000000000000..58d4b31136466 --- /dev/null +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_split.dtsi @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 Dmitrii Sharshakov + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* CPU0 */ + sram0_cpu0: memory@20000000 { + reg = <0x20000000 DT_SIZE_K(256)>; + }; + + /* CPU1 */ + sram0_cpu1: memory@20040000 { + reg = <0x20040000 DT_SIZE_K(256)>; + }; + + /* Shared and directly mapped */ + sram8: memory@20080000 { + reg = <0x20080000 DT_SIZE_K(4)>; + }; + sram9: memory@20081000 { + reg = <0x20081000 DT_SIZE_K(4)>; + }; + }; +}; diff --git a/drivers/clock_control/Kconfig.rpi_pico b/drivers/clock_control/Kconfig.rpi_pico index 274f7c0eb2816..d15c27c19dbd4 100644 --- a/drivers/clock_control/Kconfig.rpi_pico +++ b/drivers/clock_control/Kconfig.rpi_pico @@ -17,4 +17,11 @@ 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 + default y if SOC_RP2350A_M33_CPU1 + 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 2aa60a3d5e207..e94c2686872d1 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 b/soc/raspberrypi/rpi_pico/rp2350/Kconfig index 2fff7e33392e8..406d46de21108 100644 --- a/soc/raspberrypi/rpi_pico/rp2350/Kconfig +++ b/soc/raspberrypi/rpi_pico/rp2350/Kconfig @@ -18,6 +18,26 @@ config SOC_RP2350A_M33 select CPU_HAS_ARM_SAU select CPU_HAS_FPU +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 CPU_HAS_FPU + +config SOC_RP2350A_M33_CPU1 + 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 CPU_HAS_FPU + config SOC_RP2350B_M33 select ARM select ARM_TRUSTZONE_M @@ -30,10 +50,46 @@ config SOC_RP2350B_M33 config RP2_REQUIRES_IMAGE_DEFINITION_BLOCK bool - default y + # IMAGE_DEF should be used to define the image for booting CPU0 + default y if !SOC_RP2350A_M33_CPU1 # Currently the IDF only supports using the Cortex-M33 cores. Enforce # this at build configuration time. depends on SOC_SERIES_RP2350 && CPU_CORTEX_M33 help Include an Image Definition Block (IMAGE_DEF) to enable the bootroom in RP23XX devices to consider this a valid image in flash. + +config SOC_RP2350_CPU1_ENABLE + bool "Boot the RP2350 CPU1" + default y if IPM || MBOX + depends on SOC_RP2350A_M33_CPU0 + depends on $(dt_nodelabel_enabled,sram0_cpu1) + select SOC_LATE_INIT_HOOK + help + If enabled, the second CPU will be powered up and pointed to its application + entrypoint during SoC late init hook. + +config SOC_RP2350_CPU1_ENABLE_CHECK_VTOR + bool "Check VTOR before booting the second core" + default y + depends on SOC_RP2350_CPU1_ENABLE + help + Verify that VTOR pointers are valid before booting the second CPU. + +if SOC_RP2350A_M33_CPU1 + +# If a code partition is defined for the CPU1 core, +# make sure we relocate the code to be stored in that partition +# Use cpu1_slot0_partition alias to make init code copy this to the RAM +# Running CPU1 from flash is not recommended due to +# access conflicts with CPU0 writes +DT_CHOSEN_CODE_PARTITION = zephyr,code-partition +DT_CHOSEN_SRAM = zephyr,sram + +config BUILD_OUTPUT_ADJUST_LMA + default "$(dt_chosen_partition_addr_hex,$(DT_CHOSEN_CODE_PARTITION)) - \ + $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_SRAM))" if SOC_RP2350A_M33_CPU1 && \ + $(dt_chosen_enabled,$(DT_CHOSEN_CODE_PARTITION)) && \ + $(dt_chosen_enabled,$(DT_CHOSEN_SRAM)) + +endif # SOC_RP2350A_M33_CPU1 diff --git a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.soc b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.soc index 069bc56cfbf32..a17f637f2714c 100644 --- a/soc/raspberrypi/rpi_pico/rp2350/Kconfig.soc +++ b/soc/raspberrypi/rpi_pico/rp2350/Kconfig.soc @@ -20,6 +20,18 @@ config SOC_RP2350A_M33 help Use the RP2350A with a Cortex-M33 core in both 'sockets'. +config SOC_RP2350A_M33_CPU0 + bool + select SOC_RP2350A + help + 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 select SOC_SERIES_RP2350 diff --git a/soc/raspberrypi/rpi_pico/rp2350/soc.c b/soc/raspberrypi/rpi_pico/rp2350/soc.c index 84bcbffc7d97f..505c7b88520c4 100644 --- a/soc/raspberrypi/rpi_pico/rp2350/soc.c +++ b/soc/raspberrypi/rpi_pico/rp2350/soc.c @@ -1,5 +1,7 @@ /* * Copyright (c) 2024 Andrew Featherstone + * Copyright (c) 2025 Dan Collins + * Copyright (c) 2025 Dmitrii Sharshakov * * SPDX-License-Identifier: Apache-2.0 */ @@ -22,3 +24,176 @@ void soc_reset_hook(void) } #endif /* CONFIG_SOC_RESET_HOOK */ + +/* TODO: move this to soc/raspberrypi/rpi_pico/common/soc.c when tested on RP2040 */ +#if defined(CONFIG_SOC_RP2350_CPU1_ENABLE) + +#include +#include +#include + +#include +#include + +LOG_MODULE_REGISTER(soc_rp2350, CONFIG_SOC_LOG_LEVEL); + +#define CPU1_SRAM_ADDR DT_REG_ADDR(DT_NODELABEL(sram0_cpu1)) +#define CPU1_SRAM_SIZE DT_REG_SIZE(DT_NODELABEL(sram0_cpu1)) + +static inline void rpi_pico_mailbox_put_blocking(sio_hw_t *const sio_regs, uint32_t value) +{ + while (!(sio_regs->fifo_st & SIO_FIFO_ST_RDY_BITS)) { + k_busy_wait(1); + } + + sio_regs->fifo_wr = value; + + /* Inform other CPU about FIFO update. */ + __SEV(); +} + +static inline uint32_t rpi_pico_mailbox_pop_blocking(sio_hw_t *const sio_regs) +{ + while (!(sio_regs->fifo_st & SIO_FIFO_ST_VLD_BITS)) { + /* + * Wait for a message to be available in the FIFO. + * Before IRQ is enables, this is signalled by an event + */ + __WFE(); + } + + return sio_regs->fifo_rd; +} + +#if DT_NODE_EXISTS(DT_NODELABEL(cpu1_slot0_partition)) +static void rpi_pico_load_cpu1_image(void) +{ +#if DT_NODE_HAS_COMPAT(DT_GPARENT(DT_NODELABEL(cpu1_slot0_partition)), soc_nv_flash) +/* Flash partitions have addresses relative to the flash base */ +#define CPU1_CODE_ADDR \ + DT_REG_ADDR(DT_GPARENT(DT_NODELABEL(cpu1_slot0_partition))) + \ + DT_REG_ADDR(DT_NODELABEL(cpu1_slot0_partition)) +#else +/* Code in RAM, e.g. a section or debug build */ +#define CPU1_CODE_ADDR DT_REG_ADDR(DT_NODELABEL(cpu1_slot0_partition)) +#endif /* DT_NODE_HAS_COMPAT(DT_GPARENT(DT_NODELABEL(cpu1_slot0_partition)), soc_nv_flash) */ +#define CPU1_CODE_SIZE DT_REG_SIZE(DT_NODELABEL(cpu1_slot0_partition)) + + BUILD_ASSERT((CPU1_SRAM_SIZE >= CPU1_CODE_SIZE), + "Image size must not exceed execution memory size"); + + BUILD_ASSERT(((CPU1_SRAM_ADDR >= CPU1_CODE_ADDR + CPU1_CODE_SIZE) || + (CPU1_CODE_ADDR >= CPU1_SRAM_ADDR + CPU1_SRAM_SIZE)), + "Image source memory must not overlap with execution memory"); + + void *src_mem = (void *)CPU1_CODE_ADDR; + void *exec_mem = (void *)CPU1_SRAM_ADDR; + + LOG_DBG("Copying image from %p to %p", src_mem, exec_mem); + + memcpy(exec_mem, src_mem, MIN(CPU1_SRAM_SIZE, CPU1_CODE_SIZE)); +} +#endif /* DT_NODE_EXISTS(DT_NODELABEL(cpu1_slot0_partition)) */ + +#if CONFIG_SOC_RP2350_CPU1_ENABLE_CHECK_VTOR +static inline bool address_in_range(uint32_t addr, uint32_t base, uint32_t size) +{ + return addr >= base && addr < base + size; +} + +static inline int rpi_pico_validate_vtor(uint32_t cpu1_sp, uint32_t cpu1_pc) +{ + /* Stack pointer shall point within RAM assigned to the core. */ + if (!address_in_range(cpu1_sp, CPU1_SRAM_ADDR, CPU1_SRAM_SIZE)) { + LOG_ERR("CPU1 stack pointer 0x%08x invalid.", cpu1_sp); + return -EINVAL; + } + + LOG_DBG("CPU1 stack pointer: 0x%08x", cpu1_sp); + + /* Initial program counter shall point to the loaded CPU1 code. */ + if (!address_in_range(cpu1_pc, CPU1_SRAM_ADDR, CPU1_SRAM_SIZE)) { + LOG_ERR("CPU1 reset pointer 0x%08x invalid.", cpu1_pc); + return -EINVAL; + } + + LOG_DBG("CPU1 reset pointer: 0x%08x", cpu1_pc); + return 0; +} +#endif /* CONFIG_SOC_RP2350_CPU1_ENABLE_CHECK_VTOR */ + +static int rpi_pico_reset_cpu1(sio_hw_t *const sio_regs, psm_hw_t *const psm_regs) +{ + uint32_t val; + + /* Power off, and wait for it to take effect. */ + hw_set_bits(&psm_regs->frce_off, PSM_FRCE_OFF_PROC1_BITS); + while (!(psm_regs->frce_off & PSM_FRCE_OFF_PROC1_BITS)) { + k_busy_wait(1); + } + + /* + * Power back on, and we can wait for a '0' in the FIFO to know + * that it has come back. + */ + hw_clear_bits(&psm_regs->frce_off, PSM_FRCE_OFF_PROC1_BITS); + val = rpi_pico_mailbox_pop_blocking(sio_regs); + + return val == 0 ? 0 : -EIO; +} + +static void rpi_pico_boot_cpu1(sio_hw_t *const sio_regs, uint32_t vector_table_addr, + uint32_t stack_ptr, uint32_t pc) +{ + /* We synchronise with CPU1 and then we can hand over the memory addresses. */ + uint32_t cmds[] = {0, 0, 1, vector_table_addr, stack_ptr, pc}; + uint32_t seq = 0; + + do { + uint32_t cmd = cmds[seq], rsp; + + if (cmd == 0) { + /* Flush the mailbox by reading all pending messages. */ + while (sio_regs->fifo_st & SIO_FIFO_ST_VLD_BITS) { + (void)sio_regs->fifo_rd; + } + + /* Signal readiness to CPU1 */ + __SEV(); + } + + rpi_pico_mailbox_put_blocking(sio_regs, cmd); + rsp = rpi_pico_mailbox_pop_blocking(sio_regs); + + seq = (cmd == rsp) ? seq + 1 : 0; + } while (seq < ARRAY_SIZE(cmds)); +} + +void soc_late_init_hook(void) +{ +#if DT_NODE_EXISTS(DT_NODELABEL(cpu1_slot0_partition)) + rpi_pico_load_cpu1_image(); +#endif /* DT_NODE_EXISTS(DT_NODELABEL(cpu1_slot0_partition)) */ + + uint32_t cpu1_image_base = CPU1_SRAM_ADDR; + + uint32_t *cpu1_vector_table = (void *)cpu1_image_base; + uint32_t cpu1_sp = cpu1_vector_table[0]; + uint32_t cpu1_pc = cpu1_vector_table[1]; + +#if CONFIG_SOC_RP2350_CPU1_ENABLE_CHECK_VTOR + if (rpi_pico_validate_vtor(cpu1_sp, cpu1_pc) != 0) { + return; + } +#endif /* CONFIG_SOC_RP2350_CPU1_ENABLE_CHECK_VTOR */ + + LOG_DBG("Launching CPU1 with vector table at 0x%p", (void *)cpu1_vector_table); + + if (rpi_pico_reset_cpu1(sio_hw, psm_hw) != 0) { + LOG_ERR("CPU1 reset failed."); + return; + } + + rpi_pico_boot_cpu1(sio_hw, (uint32_t)cpu1_vector_table, cpu1_sp, cpu1_pc); +} +#endif /* defined(CONFIG_SOC_RP2350_CPU1_ENABLE) */ diff --git a/soc/raspberrypi/rpi_pico/soc.yml b/soc/raspberrypi/rpi_pico/soc.yml index fac2f36cd9693..235aebdf12ba2 100644 --- a/soc/raspberrypi/rpi_pico/soc.yml +++ b/soc/raspberrypi/rpi_pico/soc.yml @@ -9,6 +9,8 @@ family: - name: rp2350a cpuclusters: - name: m33 + - name: m33_cpu0 + - name: m33_cpu1 - name: rp2350b cpuclusters: - name: m33