diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi b/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi index 3b49981114797..7e255b8d2c16e 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2.dtsi @@ -19,6 +19,7 @@ zephyr,flash-controller = &qmi; zephyr,console = &uart0; zephyr,shell-uart = &uart0; + zephyr,ipc = &ipc; }; aliases { diff --git a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_defconfig b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_defconfig index 4da77bdb95c25..6c3add8aa39a2 100644 --- a/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_defconfig +++ b/boards/raspberrypi/rpi_pico2/rpi_pico2_rp2350a_m33_defconfig @@ -11,3 +11,4 @@ CONFIG_SERIAL=y CONFIG_UART_CONSOLE=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_USE_DT_CODE_PARTITION=y +CONFIG_MBOX=y diff --git a/drivers/mbox/CMakeLists.txt b/drivers/mbox/CMakeLists.txt index 6a45598684fef..35ea42cfebe71 100644 --- a/drivers/mbox/CMakeLists.txt +++ b/drivers/mbox/CMakeLists.txt @@ -23,3 +23,4 @@ zephyr_library_sources_ifdef(CONFIG_MBOX_TI_OMAP_MAILBOX mbox_ti_omap.c) zephyr_library_sources_ifdef(CONFIG_MBOX_RENESAS_RZ_MHU mbox_renesas_rz_mhu.c) zephyr_library_sources_ifdef(CONFIG_MBOX_MHUV3 mbox_mhuv3.c) zephyr_library_sources_ifdef(CONFIG_MBOX_TI_SECURE_PROXY mbox_ti_secproxy.c) +zephyr_library_sources_ifdef(CONFIG_MBOX_RPI_PICO mbox_rpi_pico.c) diff --git a/drivers/mbox/Kconfig b/drivers/mbox/Kconfig index 8649df6808195..ec28b51f8ab0b 100644 --- a/drivers/mbox/Kconfig +++ b/drivers/mbox/Kconfig @@ -27,6 +27,7 @@ source "drivers/mbox/Kconfig.ti_omap" source "drivers/mbox/Kconfig.renesas_rz" source "drivers/mbox/Kconfig.mhuv3" source "drivers/mbox/Kconfig.ti_secproxy" +source "drivers/mbox/Kconfig.rpi_pico" config MBOX_INIT_PRIORITY int "MBOX init priority" diff --git a/drivers/mbox/Kconfig.rpi_pico b/drivers/mbox/Kconfig.rpi_pico new file mode 100644 index 0000000000000..4ee0f7a6dc82f --- /dev/null +++ b/drivers/mbox/Kconfig.rpi_pico @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Igalia S.L. +# SPDX-License-Identifier: Apache-2.0 + +config MBOX_RPI_PICO + bool "Inter-processor mailbox driver for the RP2350/RP2040 SoCs" + default y + depends on DT_HAS_RASPBERRYPI_PICO_MBOX_ENABLED + help + Raspberry Pi Pico mailbox driver based on the RP2350/RP2040 + inter-processor FIFOs. diff --git a/drivers/mbox/mbox_rpi_pico.c b/drivers/mbox/mbox_rpi_pico.c new file mode 100644 index 0000000000000..5dc57040497ae --- /dev/null +++ b/drivers/mbox/mbox_rpi_pico.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2025 Igalia S.L. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +/* pico-sdk includes */ +#include + + +#define DT_DRV_COMPAT raspberrypi_pico_mbox + +LOG_MODULE_REGISTER(mbox_rpi_pico, CONFIG_MBOX_LOG_LEVEL); + +#define sev() __asm__ volatile("sev" : : : "memory") +#define MAILBOX_MBOX_SIZE sizeof(uint32_t) +#define MAILBOX_DEV_NAME mbox0 + +struct rpi_pico_mailbox_data { + const struct device *dev; + mbox_callback_t cb; + void *user_data; +}; + +static struct rpi_pico_mailbox_data rpi_pico_mbox_data; + + +/* + * Clears the ROE and WOF flags, if set. + */ +static inline void fifo_clear_status(void) +{ + sio_hw->fifo_st = 0xff; +} + +/* + * Returns true if the write FIFO isn't full. Returns false otherwise. + */ +static inline bool fifo_write_ready(void) +{ + return sio_hw->fifo_st & SIO_FIFO_ST_RDY_BITS; +} + +/* + * Returns true if the read FIFO has data available, ie. sent by the + * other core. Returns false otherwise. + */ +static inline bool fifo_read_valid(void) +{ + return sio_hw->fifo_st & SIO_FIFO_ST_VLD_BITS; +} + +/* + * Discard any data in the read FIFO. + */ +static inline void fifo_drain(void) +{ + while (fifo_read_valid()) { + (void)sio_hw->fifo_rd; + } +} + +static int rpi_pico_mbox_send(const struct device *dev, + uint32_t channel, const struct mbox_msg *msg) +{ + ARG_UNUSED(dev); + ARG_UNUSED(channel); + + if (!fifo_write_ready()) { + return -EBUSY; + } + if (msg->size > MAILBOX_MBOX_SIZE) { + return -EMSGSIZE; + } + LOG_DBG("CPU %d: send IP data: %d", sio_hw->cpuid, *((int *)msg->data)); + sio_hw->fifo_wr = *((uint32_t *)(msg->data)); + sev(); + + return 0; +} + +static int rpi_pico_mbox_register_callback(const struct device *dev, + uint32_t channel, + mbox_callback_t cb, + void *user_data) +{ + ARG_UNUSED(channel); + + struct rpi_pico_mailbox_data *data = dev->data; + uint32_t key; + + key = irq_lock(); + data->cb = cb; + data->user_data = user_data; + irq_unlock(key); + + return 0; +} + +static int rpi_pico_mbox_mtu_get(const struct device *dev) +{ + ARG_UNUSED(dev); + + return MAILBOX_MBOX_SIZE; +} + +static uint32_t rpi_pico_mbox_max_channels_get(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* Only one channel per CPU supported. */ + return 1; +} + +static int rpi_pico_mbox_set_enabled(const struct device *dev, + uint32_t channel, bool enable) +{ + ARG_UNUSED(dev); + ARG_UNUSED(channel); + + if (enable) { + irq_enable(DT_INST_IRQ_BY_NAME(0, MAILBOX_DEV_NAME, irq)); + } else { + irq_disable(DT_INST_IRQ_BY_NAME(0, MAILBOX_DEV_NAME, irq)); + } + + return 0; +} + +static void rpi_pico_mbox_isr(const struct device *dev) +{ + struct rpi_pico_mailbox_data *data = dev->data; + + /* + * Ignore the interrupt if it was triggered by anything that's + * not a FIFO receive event. + * + * NOTE: the interrupt seems to be triggered when it's first + * enabled even when the FIFO is empty. + */ + if (!fifo_read_valid()) { + LOG_DBG("Interrupt received on empty FIFO: ignored."); + return; + } + + if (data->cb != NULL) { + uint32_t d = sio_hw->fifo_rd; + struct mbox_msg msg = { + .data = &d, + .size = sizeof(d)}; + data->cb(dev, 0, data->user_data, &msg); + } + fifo_drain(); +} + +static int rpi_pico_mbox_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + LOG_DBG("Initial FIFO status: 0x%x", sio_hw->fifo_st); + LOG_DBG("FIFO depth: %d", DT_INST_PROP(0, fifo_depth)); + irq_disable(DT_INST_IRQ_BY_NAME(0, MAILBOX_DEV_NAME, irq)); + fifo_drain(); + fifo_clear_status(); + LOG_DBG("FIFO status after setup: 0x%x", sio_hw->fifo_st); + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, MAILBOX_DEV_NAME, irq), + DT_INST_IRQ_BY_NAME(0, MAILBOX_DEV_NAME, priority), + rpi_pico_mbox_isr, DEVICE_DT_INST_GET(0), 0); + + return 0; +} + +static DEVICE_API(mbox, rpi_pico_mbox_driver_api) = { + .send = rpi_pico_mbox_send, + .register_callback = rpi_pico_mbox_register_callback, + .mtu_get = rpi_pico_mbox_mtu_get, + .max_channels_get = rpi_pico_mbox_max_channels_get, + .set_enabled = rpi_pico_mbox_set_enabled, +}; + +DEVICE_DT_INST_DEFINE( + 0, + rpi_pico_mbox_init, + NULL, + &rpi_pico_mbox_data, + NULL, + POST_KERNEL, + CONFIG_MBOX_INIT_PRIORITY, + &rpi_pico_mbox_driver_api); diff --git a/dts/arm/raspberrypi/rpi_pico/rp2040.dtsi b/dts/arm/raspberrypi/rpi_pico/rp2040.dtsi index 9a0626e487705..0d45cc7529972 100644 --- a/dts/arm/raspberrypi/rpi_pico/rp2040.dtsi +++ b/dts/arm/raspberrypi/rpi_pico/rp2040.dtsi @@ -435,6 +435,34 @@ alarms-count = <1>; status = "disabled"; }; + + sio: sio@d0000000 { + compatible = "raspberrypi,pico-sio"; + reg = <0xd0000000 0x180>; + + mbox: mbox { + compatible = "raspberrypi,pico-mbox"; + interrupts = <15 RPI_PICO_DEFAULT_IRQ_PRIORITY>, + <16 RPI_PICO_DEFAULT_IRQ_PRIORITY>; + interrupt-names = "mbox0", "mbox1"; + fifo-depth = <8>; + #mbox-cells = <0>; + status = "okay"; + }; + }; + + ipc: ipc { + /* + * The zephyr,mbox-ipm driver expects two mailbox + * channels, but the mailbox block in the RP2040 + * implements a single instance per core. Point the + * two driver channels to the same single mbox. + */ + compatible = "zephyr,mbox-ipm"; + mboxes = <&mbox>, <&mbox>; + mbox-names = "tx", "rx"; + status = "okay"; + }; }; pinctrl: pin-controller { diff --git a/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi b/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi index 4f16a54c02ecd..19168f18546b8 100644 --- a/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi +++ b/dts/arm/raspberrypi/rpi_pico/rp2350.dtsi @@ -453,6 +453,33 @@ interrupt-names = "irq0", "irq1"; status = "disabled"; }; + + sio: sio@d0000000 { + compatible = "raspberrypi,pico-sio"; + reg = <0xd0000000 DT_SIZE_K(80)>; + + mbox: mbox { + compatible = "raspberrypi,pico-mbox"; + interrupts = <25 RPI_PICO_DEFAULT_IRQ_PRIORITY>; + interrupt-names = "mbox0"; + fifo-depth = <4>; + #mbox-cells = <0>; + status = "okay"; + }; + }; + + ipc: ipc { + /* + * The zephyr,mbox-ipm driver expects two mailbox + * channels, but the mailbox block in the RP2350 + * implements a single instance per core. Point the + * two driver channels to the same single mbox. + */ + compatible = "zephyr,mbox-ipm"; + mboxes = <&mbox>, <&mbox>; + mbox-names = "tx", "rx"; + status = "okay"; + }; }; pinctrl: pin-controller { diff --git a/dts/bindings/mbox/raspberrypi,pico-mbox.yaml b/dts/bindings/mbox/raspberrypi,pico-mbox.yaml new file mode 100644 index 0000000000000..a49d4e2737718 --- /dev/null +++ b/dts/bindings/mbox/raspberrypi,pico-mbox.yaml @@ -0,0 +1,14 @@ +# Copyright (c) 2025 Igalia S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: Raspberry Pi Pico interprocessor mailbox + +compatible: "raspberrypi,pico-mbox" + +include: [base.yaml, mailbox-controller.yaml] + +properties: + fifo-depth: + type: int + description: number of entries that the mailbox FIFO can hold + required: true diff --git a/dts/bindings/misc/raspberrypi,pico-sio.yaml b/dts/bindings/misc/raspberrypi,pico-sio.yaml new file mode 100644 index 0000000000000..729df8e28f17b --- /dev/null +++ b/dts/bindings/misc/raspberrypi,pico-sio.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2025 Igalia S.L. +# SPDX-License-Identifier: Apache-2.0 + +description: Raspberry Pi Pico SIO + +compatible: "raspberrypi,pico-sio" + +include: base.yaml