-
Notifications
You must be signed in to change notification settings - Fork 8.1k
driver: inter-processor mailbox for Raspberry Pi Pico #94502
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
r-c-n
wants to merge
2
commits into
zephyrproject-rtos:main
Choose a base branch
from
r-c-n:rcn-rpi-pico-mbox
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
/* | ||
* Copyright (c) 2025 Igalia S.L. | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#include <zephyr/logging/log.h> | ||
#include <zephyr/drivers/mbox.h> | ||
#include <zephyr/devicetree.h> | ||
#include <zephyr/irq.h> | ||
/* pico-sdk includes */ | ||
#include <hardware/structs/sio.h> | ||
|
||
|
||
#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); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably send the channel number here. Most consumers expect more than one channel, but do not send data.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case the mailbox has only one channel from the point of view of the core that sends the message, right? Actually, the concept of "channel" isn't used in the driver at all.
But yes, it still may be useful to add it to the debug message to know how the caller called the function.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant for consumers it'll probably be better if the mailbox provided more channels, rather than data transfer.
What are you using it for? I use IPM in my branch for IPC subsystem, and so I need more than one channel, but signaling only, no data (data resides in shared memory and access is controlled by two mailbox channels)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we're talking about different things here...
What I did here is a direct mapping of the hardware functionality, with no further abstractions. This handles the SIO mailboxes. According to the docs, there are only two FIFOs (let's call them A and B), one core can only read from A and write to B, while the other can only read from B and write to A. From the point of view of each of the cores, there's only one single channel. Unless we mean different things when we say "channel" in this context.
When you say the data resides in shared memory and the access is controlled by the mailbox channels, I understand that's handled by the IPC mechanism you implemented on top of the mailboxes (ie. a region of memory shared between the cores and a signalling mechanism using the mailboxes). When I mention "data" in the driver, I mean the data that goes through the mailboxes. In the RP2350 each mailbox can hold 4 4-byte messages, for instance. You can ignore the data and use a mailbox for signalling events only, or you can use it to signal an event and carry some data with it (a memory address, for instance).
In the end, the use case will be inter-processor communication, but what I'm doing here is to provide low-level access to the hardware peripheral so that the IPM can be implemented on top of it. For example, using zephyr,mbox-imp as an adaptor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, let's leave this to maintainers, because that's really use-case dependent