drivers: mbox: Introduce MBOX driver class
One limitation of the current IPM API is that it is assuming that the hardware is only exporting one single channel through which the data can be sent or signalling can happen. If the hardware supports multiple channels, the IPM device must be instantiated (possibly in the DT) several times, one for each channel to be able to send data through multiple channels using the same hw peripheral. Also in the current IPM API only one callback can be registered, that means that only one driver is controlling all the signalling happening on all the channels. This patch is introducing a new MBOX API that is supporting multi-channel signalling and data exachange leveraging and extending the previous (and outdated) IPM API. Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
parent
bc41234104
commit
1976f33e87
13 changed files with 623 additions and 1 deletions
|
@ -284,6 +284,7 @@
|
||||||
/drivers/led/ @Mani-Sadhasivam
|
/drivers/led/ @Mani-Sadhasivam
|
||||||
/drivers/led_strip/ @mbolivar-nordic
|
/drivers/led_strip/ @mbolivar-nordic
|
||||||
/drivers/lora/ @Mani-Sadhasivam
|
/drivers/lora/ @Mani-Sadhasivam
|
||||||
|
/drivers/mbox/ @carlocaione
|
||||||
/drivers/memc/ @gmarull
|
/drivers/memc/ @gmarull
|
||||||
/drivers/misc/ @tejlmand
|
/drivers/misc/ @tejlmand
|
||||||
/drivers/misc/ft8xx/ @hubertmis
|
/drivers/misc/ft8xx/ @hubertmis
|
||||||
|
|
|
@ -23,6 +23,7 @@ Peripherals
|
||||||
ipm.rst
|
ipm.rst
|
||||||
kscan.rst
|
kscan.rst
|
||||||
led.rst
|
led.rst
|
||||||
|
mbox.rst
|
||||||
pinmux.rst
|
pinmux.rst
|
||||||
pwm.rst
|
pwm.rst
|
||||||
ps2.rst
|
ps2.rst
|
||||||
|
|
18
doc/reference/peripherals/mbox.rst
Normal file
18
doc/reference/peripherals/mbox.rst
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
.. _mbox_api:
|
||||||
|
|
||||||
|
MBOX
|
||||||
|
####
|
||||||
|
|
||||||
|
Overview
|
||||||
|
********
|
||||||
|
|
||||||
|
An MBOX device is a peripheral capable of passing signals (and data depending
|
||||||
|
on the peripheral) between CPUs and clusters in the system. Each MBOX instance
|
||||||
|
is providing one or more channels, each one targeting one other CPU cluster
|
||||||
|
(multiple channels can target the same cluster).
|
||||||
|
|
||||||
|
|
||||||
|
API Reference
|
||||||
|
*************
|
||||||
|
|
||||||
|
.. doxygengroup:: mbox_interface
|
|
@ -62,3 +62,4 @@ add_subdirectory_ifdef(CONFIG_SYSCON syscon)
|
||||||
add_subdirectory_ifdef(CONFIG_BBRAM bbram)
|
add_subdirectory_ifdef(CONFIG_BBRAM bbram)
|
||||||
add_subdirectory_ifdef(CONFIG_FPGA fpga)
|
add_subdirectory_ifdef(CONFIG_FPGA fpga)
|
||||||
add_subdirectory_ifdef(CONFIG_PINCTRL pinctrl)
|
add_subdirectory_ifdef(CONFIG_PINCTRL pinctrl)
|
||||||
|
add_subdirectory_ifdef(CONFIG_MBOX mbox)
|
||||||
|
|
|
@ -125,4 +125,6 @@ source "drivers/fpga/Kconfig"
|
||||||
|
|
||||||
source "drivers/pinctrl/Kconfig"
|
source "drivers/pinctrl/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/mbox/Kconfig"
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
5
drivers/mbox/CMakeLists.txt
Normal file
5
drivers/mbox/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
zephyr_library()
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_USERSPACE mbox_handlers.c)
|
8
drivers/mbox/Kconfig
Normal file
8
drivers/mbox/Kconfig
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
menuconfig MBOX
|
||||||
|
bool "MBOX drivers"
|
||||||
|
help
|
||||||
|
Include multi-channel interrupt-based inter-processor mailboxes
|
||||||
|
drivers in system configuration
|
45
drivers/mbox/mbox_handlers.c
Normal file
45
drivers/mbox/mbox_handlers.c
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <syscall_handler.h>
|
||||||
|
#include <drivers/mbox.h>
|
||||||
|
|
||||||
|
static inline int z_vrfy_mbox_send(const struct mbox_channel *channel,
|
||||||
|
const struct mbox_msg *msg)
|
||||||
|
{
|
||||||
|
Z_OOPS(Z_SYSCALL_MEMORY_READ(channel, sizeof(struct mbox_channel)));
|
||||||
|
Z_OOPS(Z_SYSCALL_DRIVER_MBOX(channel->dev, send));
|
||||||
|
Z_OOPS(Z_SYSCALL_MEMORY_READ(msg, sizeof(struct mbox_msg)));
|
||||||
|
Z_OOPS(Z_SYSCALL_MEMORY_READ(msg->data, msg->size));
|
||||||
|
|
||||||
|
return z_impl_mbox_send(channel, msg);
|
||||||
|
}
|
||||||
|
#include <syscalls/mbox_send_mrsh.c>
|
||||||
|
|
||||||
|
static inline int z_vrfy_mbox_mtu_get(const struct device *dev)
|
||||||
|
{
|
||||||
|
Z_OOPS(Z_SYSCALL_DRIVER_MBOX(dev, max_data_size_get));
|
||||||
|
|
||||||
|
return z_impl_mbox_mtu_get(dev);
|
||||||
|
}
|
||||||
|
#include <syscalls/mbox_mtu_get_mrsh.c>
|
||||||
|
|
||||||
|
static inline uint32_t z_vrfy_mbox_max_channels_get(const struct device *dev)
|
||||||
|
{
|
||||||
|
Z_OOPS(Z_SYSCALL_DRIVER_MBOX(dev, max_channels_get));
|
||||||
|
|
||||||
|
return z_impl_mbox_max_channels_get(dev);
|
||||||
|
}
|
||||||
|
#include <syscalls/mbox_max_channels_get_mrsh.c>
|
||||||
|
|
||||||
|
static inline int z_vrfy_mbox_set_enabled(const struct mbox_channel *channel, bool enable)
|
||||||
|
{
|
||||||
|
Z_OOPS(Z_SYSCALL_MEMORY_READ(channel, sizeof(struct mbox_channel)));
|
||||||
|
Z_OOPS(Z_SYSCALL_DRIVER_MBOX(channel->dev, set_enabled));
|
||||||
|
|
||||||
|
return z_impl_mbox_set_enabled(channel, enable);
|
||||||
|
}
|
||||||
|
#include <syscalls/mbox_set_enabled_mrsh.c>
|
11
dts/bindings/test/vnd,mbox-zero-cell.yaml
Normal file
11
dts/bindings/test/vnd,mbox-zero-cell.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# Copyright (c) 2021, Carlo Caione <ccaione@baylibre.com>
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: VND MBOX controller (0 cell)
|
||||||
|
|
||||||
|
compatible: "vnd,mbox-zero-cell"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
required: true
|
16
dts/bindings/test/vnd,mbox.yaml
Normal file
16
dts/bindings/test/vnd,mbox.yaml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# Copyright (c) 2021, Carlo Caione <ccaione@baylibre.com>
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
description: VND MBOX controller
|
||||||
|
|
||||||
|
compatible: "vnd,mbox"
|
||||||
|
|
||||||
|
include: mailbox-controller.yaml
|
||||||
|
|
||||||
|
properties:
|
||||||
|
label:
|
||||||
|
type: string
|
||||||
|
required: true
|
||||||
|
|
||||||
|
mbox-cells:
|
||||||
|
- channel
|
464
include/drivers/mbox.h
Normal file
464
include/drivers/mbox.h
Normal file
|
@ -0,0 +1,464 @@
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* @brief Generic low-level multi-channel inter-processor mailbox communication API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_DRIVERS_MBOX_H_
|
||||||
|
#define ZEPHYR_INCLUDE_DRIVERS_MBOX_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief MBOX Interface
|
||||||
|
* @defgroup mbox_interface MBOX Interface
|
||||||
|
* @ingroup io_interfaces
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @code{.unparsed}
|
||||||
|
*
|
||||||
|
* CPU #1 |
|
||||||
|
* +----------+ | +----------+
|
||||||
|
* | +---TX9----+ +--------+--RX8---+ |
|
||||||
|
* | dev A | | | | | CPU #2 |
|
||||||
|
* | <---RX8--+ | | +------+--TX9---> |
|
||||||
|
* +----------+ | | | | | +----------+
|
||||||
|
* +--+-v---v-+--+ |
|
||||||
|
* | | |
|
||||||
|
* | MBOX dev | |
|
||||||
|
* | | |
|
||||||
|
* +--+-^---^--+-+ |
|
||||||
|
* +----------+ | | | | | +----------+
|
||||||
|
* | <---RX2--+ | | +-----+--TX3---> |
|
||||||
|
* | dev B | | | | | CPU #3 |
|
||||||
|
* | +---TX3----+ +--------+--RX2---+ |
|
||||||
|
* +----------+ | +----------+
|
||||||
|
* |
|
||||||
|
*
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* An MBOX device is a peripheral capable of passing signals (and data depending
|
||||||
|
* on the peripheral) between CPUs and clusters in the system. Each MBOX
|
||||||
|
* instance is providing one or more channels, each one targeting one other CPU
|
||||||
|
* cluster (multiple channels can target the same cluster).
|
||||||
|
*
|
||||||
|
* For example in the plot the device 'dev A' is using the TX channel 9 to
|
||||||
|
* signal (or send data to) the CPU #2 and it's expecting data or signals on
|
||||||
|
* the RX channel 8. Thus it can send the message through the channel 9, and it
|
||||||
|
* can register a callback on the channel 8 of the MBOX device.
|
||||||
|
*
|
||||||
|
* This API supports two modes: signalling mode and data transfer mode.
|
||||||
|
*
|
||||||
|
* In signalling mode:
|
||||||
|
* - mbox_mtu_get() must return 0
|
||||||
|
* - mbox_send() must have (msg == NULL)
|
||||||
|
* - the callback must be called with (data == NULL)
|
||||||
|
*
|
||||||
|
* In data transfer mode:
|
||||||
|
* - mbox_mtu_get() must return a (value != 0)
|
||||||
|
* - mbox_send() must have (msg != NULL)
|
||||||
|
* - the callback must be called with (data != NULL)
|
||||||
|
* - The msg content must be the same between sender and receiver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <device.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Message struct (to hold data and its size).
|
||||||
|
*/
|
||||||
|
struct mbox_msg {
|
||||||
|
/** Pointer to the data sent in the message. */
|
||||||
|
const void *data;
|
||||||
|
|
||||||
|
/** Size of the data. */
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides a type to hold an MBOX channel
|
||||||
|
*
|
||||||
|
* Struct type to hold an MBOX device pointer and the channel ID.
|
||||||
|
*/
|
||||||
|
struct mbox_channel {
|
||||||
|
/** MBOX device pointer. */
|
||||||
|
const struct device *dev;
|
||||||
|
|
||||||
|
/** Channel ID. */
|
||||||
|
uint32_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Structure initializer for mbox_channel from devicetree
|
||||||
|
*
|
||||||
|
* This helper macro expands to a static initializer for a @p mbox_channel by
|
||||||
|
* reading the relevant device controller and channel number from the
|
||||||
|
* devicetree.
|
||||||
|
*
|
||||||
|
* Example devicetree fragment:
|
||||||
|
*
|
||||||
|
* mbox1: mbox-controller@... { ... };
|
||||||
|
*
|
||||||
|
* n: node {
|
||||||
|
* mboxes = <&mbox1 8>,
|
||||||
|
* <&mbox1 9>;
|
||||||
|
* mbox-names = "tx", "rx";
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* const struct mbox_channel channel = MBOX_DT_CHANNEL_GET(DT_NODELABEL(n), tx);
|
||||||
|
*
|
||||||
|
* @param node_id Devicetree node identifier for the MBOX device
|
||||||
|
* @param name lowercase-and-underscores name of the mboxes element
|
||||||
|
*/
|
||||||
|
#define MBOX_DT_CHANNEL_GET(node_id, name) \
|
||||||
|
{ \
|
||||||
|
.dev = DEVICE_DT_GET(MBOX_DT_CTLR_BY_NAME(node_id, name)), \
|
||||||
|
.id = MBOX_DT_CHANNEL_ID_BY_NAME(node_id, name), \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the node identifier for the MBOX controller from a mboxes
|
||||||
|
* property by name
|
||||||
|
*
|
||||||
|
* Example devicetree fragment:
|
||||||
|
*
|
||||||
|
* mbox1: mbox-controller@... { ... };
|
||||||
|
*
|
||||||
|
* n: node {
|
||||||
|
* mboxes = <&mbox1 8>,
|
||||||
|
* <&mbox1 9>;
|
||||||
|
* mbox-names = "tx", "rx";
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* MBOX_DT_CTLR_BY_NAME(DT_NODELABEL(n), tx) // DT_NODELABEL(mbox1)
|
||||||
|
* MBOX_DT_CTLR_BY_NAME(DT_NODELABEL(n), rx) // DT_NODELABEL(mbox1)
|
||||||
|
*
|
||||||
|
* @param node_id node identifier for a node with a mboxes property
|
||||||
|
* @param name lowercase-and-underscores name of a mboxes element
|
||||||
|
* as defined by the node's mbox-names property
|
||||||
|
*
|
||||||
|
* @return the node identifier for the MBOX controller in the named element
|
||||||
|
*
|
||||||
|
* @see DT_PHANDLE_BY_NAME()
|
||||||
|
*/
|
||||||
|
#define MBOX_DT_CTLR_BY_NAME(node_id, name) \
|
||||||
|
DT_PHANDLE_BY_NAME(node_id, mboxes, name)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a MBOX channel value by name
|
||||||
|
*
|
||||||
|
* Example devicetree fragment:
|
||||||
|
*
|
||||||
|
* mbox1: mbox@... {
|
||||||
|
* #mbox-cells = <1>;
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* n: node {
|
||||||
|
* mboxes = <&mbox1 1>,
|
||||||
|
* <&mbox1 6>;
|
||||||
|
* mbox-names = "tx", "rx";
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* Bindings fragment for the mbox compatible:
|
||||||
|
*
|
||||||
|
* mbox-cells:
|
||||||
|
* - channel
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* MBOX_DT_CHANNEL_ID_BY_NAME(DT_NODELABEL(n), tx) // 1
|
||||||
|
* MBOX_DT_CHANNEL_ID_BY_NAME(DT_NODELABEL(n), rx) // 6
|
||||||
|
*
|
||||||
|
* @param node_id node identifier for a node with a mboxes property
|
||||||
|
* @param name lowercase-and-underscores name of a mboxes element
|
||||||
|
* as defined by the node's mbox-names property
|
||||||
|
*
|
||||||
|
* @return the channel value in the specifier at the named element or 0 if no
|
||||||
|
* channels are supported
|
||||||
|
*
|
||||||
|
* @see DT_PHA_BY_NAME_OR()
|
||||||
|
*/
|
||||||
|
#define MBOX_DT_CHANNEL_ID_BY_NAME(node_id, name) \
|
||||||
|
DT_PHA_BY_NAME_OR(node_id, mboxes, name, channel, 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef mbox_callback_t
|
||||||
|
*
|
||||||
|
* @brief Callback API for incoming MBOX messages
|
||||||
|
*
|
||||||
|
* These callbacks execute in interrupt context. Therefore, use only
|
||||||
|
* interrupt-safe APIS. Registration of callbacks is done via @a
|
||||||
|
* mbox_register_callback()
|
||||||
|
*
|
||||||
|
* The data parameter must be NULL in signalling mode.
|
||||||
|
*
|
||||||
|
* @param dev Driver instance
|
||||||
|
* @param channel Channel ID
|
||||||
|
* @param user_data Pointer to some private data provided at registration
|
||||||
|
* time
|
||||||
|
* @param data Message struct
|
||||||
|
*/
|
||||||
|
typedef void (*mbox_callback_t)(const struct device *dev, uint32_t channel,
|
||||||
|
void *user_data, struct mbox_msg *data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef mbox_send_t
|
||||||
|
*
|
||||||
|
* @brief Callback API to send MBOX messages
|
||||||
|
*
|
||||||
|
* See @a mbox_send() for function description
|
||||||
|
*
|
||||||
|
* @param dev Driver instance
|
||||||
|
* @param channel Channel ID
|
||||||
|
* @param msg Message struct
|
||||||
|
*
|
||||||
|
* @return See return values for @a mbox_send()
|
||||||
|
*/
|
||||||
|
typedef int (*mbox_send_t)(const struct device *dev, uint32_t channel,
|
||||||
|
const struct mbox_msg *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef mbox_mtu_get_t
|
||||||
|
*
|
||||||
|
* @brief Callback API to get maximum data size
|
||||||
|
*
|
||||||
|
* See @a mbox_mtu_get() for argument definitions.
|
||||||
|
*/
|
||||||
|
typedef int (*mbox_mtu_get_t)(const struct device *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef mbox_register_callback_t
|
||||||
|
*
|
||||||
|
* @brief Callback API upon registration
|
||||||
|
*
|
||||||
|
* See @a mbox_register_callback() for function description
|
||||||
|
*
|
||||||
|
* @param dev Driver instance
|
||||||
|
* @param channel Channel ID
|
||||||
|
* @param cb Callback function to execute on incoming message interrupts.
|
||||||
|
* @param user_data Application-specific data pointer which will be passed
|
||||||
|
* to the callback function when executed.
|
||||||
|
*
|
||||||
|
* @return See return values for @a mbox_register_callback()
|
||||||
|
*/
|
||||||
|
typedef int (*mbox_register_callback_t)(const struct device *dev,
|
||||||
|
uint32_t channel,
|
||||||
|
mbox_callback_t cb,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef mbox_set_enabled_t
|
||||||
|
*
|
||||||
|
* @brief Callback API upon enablement of interrupts
|
||||||
|
*
|
||||||
|
* See @a mbox_set_enabled() for function description
|
||||||
|
*
|
||||||
|
* @param dev Driver instance
|
||||||
|
* @param channel Channel ID
|
||||||
|
* @param enable Set to 0 to disable and to nonzero to enable.
|
||||||
|
*
|
||||||
|
* @return See return values for @a mbox_set_enabled()
|
||||||
|
*/
|
||||||
|
typedef int (*mbox_set_enabled_t)(const struct device *dev, uint32_t channel, bool enable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef mbox_max_channels_get_t
|
||||||
|
*
|
||||||
|
* @brief Callback API to get maximum number of channels
|
||||||
|
*
|
||||||
|
* See @a mbox_max_channels_get() for argument definitions.
|
||||||
|
*/
|
||||||
|
typedef uint32_t (*mbox_max_channels_get_t)(const struct device *dev);
|
||||||
|
|
||||||
|
__subsystem struct mbox_driver_api {
|
||||||
|
mbox_send_t send;
|
||||||
|
mbox_register_callback_t register_callback;
|
||||||
|
mbox_mtu_get_t mtu_get;
|
||||||
|
mbox_max_channels_get_t max_channels_get;
|
||||||
|
mbox_set_enabled_t set_enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize a channel struct
|
||||||
|
*
|
||||||
|
* Initialize an @p mbox_channel passed by the user with a provided MBOX device
|
||||||
|
* and channel ID. This function is needed when the information about the
|
||||||
|
* device and the channel ID is not in the DT. In the DT case
|
||||||
|
* MBOX_DT_CHANNEL_GET() must be used instead.
|
||||||
|
*
|
||||||
|
* @param channel Pointer to the channel struct
|
||||||
|
* @param dev Driver instance
|
||||||
|
* @param ch_id Channel ID
|
||||||
|
*/
|
||||||
|
static inline void mbox_init_channel(struct mbox_channel *channel, const struct device *dev,
|
||||||
|
uint32_t ch_id)
|
||||||
|
{
|
||||||
|
channel->dev = dev;
|
||||||
|
channel->id = ch_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to send a message over the MBOX device.
|
||||||
|
*
|
||||||
|
* Send a message over an @p mbox_channel. The msg parameter must be NULL when
|
||||||
|
* the driver is used for signalling.
|
||||||
|
*
|
||||||
|
* If the msg parameter is not NULL, this data is expected to be delivered on
|
||||||
|
* the receiving side using the data parameter of the receiving callback.
|
||||||
|
*
|
||||||
|
* @param channel Channel instance pointer
|
||||||
|
* @param msg Pointer to the message struct
|
||||||
|
*
|
||||||
|
* @retval -EBUSY If the remote hasn't yet read the last data sent.
|
||||||
|
* @retval -EMSGSIZE If the supplied data size is unsupported by the driver.
|
||||||
|
* @retval -EINVAL If there was a bad parameter, such as: too-large channel
|
||||||
|
* descriptor or the device isn't an outbound MBOX channel.
|
||||||
|
*
|
||||||
|
* @retval 0 On success, negative value on error.
|
||||||
|
*/
|
||||||
|
__syscall int mbox_send(const struct mbox_channel *channel, const struct mbox_msg *msg);
|
||||||
|
|
||||||
|
static inline int z_impl_mbox_send(const struct mbox_channel *channel, const struct mbox_msg *msg)
|
||||||
|
{
|
||||||
|
const struct mbox_driver_api *api =
|
||||||
|
(const struct mbox_driver_api *)channel->dev->api;
|
||||||
|
|
||||||
|
if (api->send == NULL) {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return api->send(channel->dev, channel->id, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a callback function on a channel for incoming messages.
|
||||||
|
*
|
||||||
|
* This function doesn't assume anything concerning the status of the
|
||||||
|
* interrupts. Use @a mbox_set_enabled() to enable or to disable the interrupts
|
||||||
|
* if needed.
|
||||||
|
*
|
||||||
|
* @param channel Channel instance pointer.
|
||||||
|
* @param cb Callback function to execute on incoming message interrupts.
|
||||||
|
* @param user_data Application-specific data pointer which will be passed
|
||||||
|
* to the callback function when executed.
|
||||||
|
*
|
||||||
|
* @retval 0 On success, negative value on error.
|
||||||
|
*/
|
||||||
|
static inline int mbox_register_callback(const struct mbox_channel *channel,
|
||||||
|
mbox_callback_t cb,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
const struct mbox_driver_api *api =
|
||||||
|
(const struct mbox_driver_api *)channel->dev->api;
|
||||||
|
|
||||||
|
if (api->register_callback == NULL) {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return api->register_callback(channel->dev, channel->id, cb, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the maximum number of bytes possible in an outbound message.
|
||||||
|
*
|
||||||
|
* Returns the actual number of bytes that it is possible to send through an
|
||||||
|
* outgoing channel.
|
||||||
|
*
|
||||||
|
* This number can be 0 when the driver only supports signalling or when on the
|
||||||
|
* receiving side the content and size of the message must be retrieved in an
|
||||||
|
* indirect way (i.e. probing some other peripheral, reading memory regions,
|
||||||
|
* etc...).
|
||||||
|
*
|
||||||
|
* If this function returns 0, the msg parameter in @a mbox_send() is expected
|
||||||
|
* to be NULL.
|
||||||
|
*
|
||||||
|
* @param dev Driver instance pointer.
|
||||||
|
*
|
||||||
|
* @return Maximum possible size of a message in bytes, 0 for signalling,
|
||||||
|
* negative value on error.
|
||||||
|
*/
|
||||||
|
__syscall int mbox_mtu_get(const struct device *dev);
|
||||||
|
|
||||||
|
static inline int z_impl_mbox_mtu_get(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct mbox_driver_api *api =
|
||||||
|
(const struct mbox_driver_api *)dev->api;
|
||||||
|
|
||||||
|
if (api->mtu_get == NULL) {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return api->mtu_get(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable interrupts and callbacks for inbound channels.
|
||||||
|
*
|
||||||
|
* @param channel Channel instance pointer.
|
||||||
|
* @param enable Set to 0 to disable and to nonzero to enable.
|
||||||
|
*
|
||||||
|
* @retval 0 On success.
|
||||||
|
* @retval -EINVAL If it isn't an inbound channel.
|
||||||
|
*/
|
||||||
|
__syscall int mbox_set_enabled(const struct mbox_channel *channel, bool enable);
|
||||||
|
|
||||||
|
static inline int z_impl_mbox_set_enabled(const struct mbox_channel *channel, bool enable)
|
||||||
|
{
|
||||||
|
const struct mbox_driver_api *api =
|
||||||
|
(const struct mbox_driver_api *)channel->dev->api;
|
||||||
|
|
||||||
|
if (api->set_enabled == NULL) {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return api->set_enabled(channel->dev, channel->id, enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the maximum number of channels.
|
||||||
|
*
|
||||||
|
* Return the maximum number of channels supported by the hardware.
|
||||||
|
*
|
||||||
|
* @param dev Driver instance pointer.
|
||||||
|
*
|
||||||
|
* @return Maximum possible number of supported channels on success, negative
|
||||||
|
* value on error.
|
||||||
|
*/
|
||||||
|
__syscall uint32_t mbox_max_channels_get(const struct device *dev);
|
||||||
|
|
||||||
|
static inline uint32_t z_impl_mbox_max_channels_get(const struct device *dev)
|
||||||
|
{
|
||||||
|
const struct mbox_driver_api *api =
|
||||||
|
(const struct mbox_driver_api *)dev->api;
|
||||||
|
|
||||||
|
if (api->max_channels_get == NULL) {
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return api->max_channels_get(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <syscalls/mbox.h>
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_DRIVERS_MBOX_H_ */
|
|
@ -221,6 +221,20 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test_mbox: mbox {
|
||||||
|
label = "TEST_MBOX";
|
||||||
|
compatible = "vnd,mbox";
|
||||||
|
#mbox-cells = <1>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
test_mbox_zero_cell: mbox_zero_cell {
|
||||||
|
label = "TEST_MBOX_ZERO_CELL";
|
||||||
|
compatible = "vnd,mbox-zero-cell";
|
||||||
|
#mbox-cells = <0>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
test_spi: spi@33334444 {
|
test_spi: spi@33334444 {
|
||||||
#address-cells = < 1 >;
|
#address-cells = < 1 >;
|
||||||
#size-cells = < 0 >;
|
#size-cells = < 0 >;
|
||||||
|
@ -324,6 +338,8 @@
|
||||||
pinctrl-1 = <&test_pincfg_c &test_pincfg_d>;
|
pinctrl-1 = <&test_pincfg_c &test_pincfg_d>;
|
||||||
pinctrl-2 = <&test_pincfg_d>;
|
pinctrl-2 = <&test_pincfg_d>;
|
||||||
pinctrl-names = "default", "sleep", "f.o.o2";
|
pinctrl-names = "default", "sleep", "f.o.o2";
|
||||||
|
mboxes = <&test_mbox 1>, <&test_mbox 2>, <&test_mbox_zero_cell>;
|
||||||
|
mbox-names = "tx", "rx", "zero";
|
||||||
};
|
};
|
||||||
|
|
||||||
/* there should only be one of these */
|
/* there should only be one of these */
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <devicetree.h>
|
#include <devicetree.h>
|
||||||
#include <device.h>
|
#include <device.h>
|
||||||
#include <drivers/gpio.h>
|
#include <drivers/gpio.h>
|
||||||
|
#include <drivers/mbox.h>
|
||||||
|
|
||||||
#define TEST_CHILDREN DT_PATH(test, test_children)
|
#define TEST_CHILDREN DT_PATH(test, test_children)
|
||||||
#define TEST_DEADBEEF DT_PATH(test, gpio_deadbeef)
|
#define TEST_DEADBEEF DT_PATH(test, gpio_deadbeef)
|
||||||
|
@ -2078,6 +2079,38 @@ static void test_pinctrl(void)
|
||||||
zassert_equal(DT_INST_PINCTRL_HAS_NAME(0, f_o_o2), 0, "");
|
zassert_equal(DT_INST_PINCTRL_HAS_NAME(0, f_o_o2), 0, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_mbox(void)
|
||||||
|
{
|
||||||
|
#undef DT_DRV_COMPAT
|
||||||
|
#define DT_DRV_COMPAT vnd_adc_temp_sensor
|
||||||
|
|
||||||
|
const struct mbox_channel channel_tx = MBOX_DT_CHANNEL_GET(TEST_TEMP, tx);
|
||||||
|
const struct mbox_channel channel_rx = MBOX_DT_CHANNEL_GET(TEST_TEMP, rx);
|
||||||
|
|
||||||
|
zassert_equal(channel_tx.id, 1, "");
|
||||||
|
zassert_equal(channel_rx.id, 2, "");
|
||||||
|
|
||||||
|
zassert_equal(MBOX_DT_CHANNEL_ID_BY_NAME(TEST_TEMP, tx), 1, "");
|
||||||
|
zassert_equal(MBOX_DT_CHANNEL_ID_BY_NAME(TEST_TEMP, rx), 2, "");
|
||||||
|
|
||||||
|
zassert_true(DT_SAME_NODE(MBOX_DT_CTLR_BY_NAME(TEST_TEMP, tx),
|
||||||
|
DT_NODELABEL(test_mbox)), "");
|
||||||
|
zassert_true(DT_SAME_NODE(MBOX_DT_CTLR_BY_NAME(TEST_TEMP, rx),
|
||||||
|
DT_NODELABEL(test_mbox)), "");
|
||||||
|
|
||||||
|
zassert_equal(MBOX_DT_CHANNEL_ID_BY_NAME(TEST_TEMP, tx), 1, "");
|
||||||
|
zassert_equal(MBOX_DT_CHANNEL_ID_BY_NAME(TEST_TEMP, rx), 2, "");
|
||||||
|
|
||||||
|
const struct mbox_channel channel_zero = MBOX_DT_CHANNEL_GET(TEST_TEMP, zero);
|
||||||
|
|
||||||
|
zassert_equal(channel_zero.id, 0, "");
|
||||||
|
|
||||||
|
zassert_equal(MBOX_DT_CHANNEL_ID_BY_NAME(TEST_TEMP, zero), 0, "");
|
||||||
|
|
||||||
|
zassert_true(DT_SAME_NODE(MBOX_DT_CTLR_BY_NAME(TEST_TEMP, zero),
|
||||||
|
DT_NODELABEL(test_mbox_zero_cell)), "");
|
||||||
|
}
|
||||||
|
|
||||||
void test_main(void)
|
void test_main(void)
|
||||||
{
|
{
|
||||||
ztest_test_suite(devicetree_api,
|
ztest_test_suite(devicetree_api,
|
||||||
|
@ -2120,7 +2153,8 @@ void test_main(void)
|
||||||
ztest_unit_test(test_path),
|
ztest_unit_test(test_path),
|
||||||
ztest_unit_test(test_node_name),
|
ztest_unit_test(test_node_name),
|
||||||
ztest_unit_test(test_same_node),
|
ztest_unit_test(test_same_node),
|
||||||
ztest_unit_test(test_pinctrl)
|
ztest_unit_test(test_pinctrl),
|
||||||
|
ztest_unit_test(test_mbox)
|
||||||
);
|
);
|
||||||
ztest_run_test_suite(devicetree_api);
|
ztest_run_test_suite(devicetree_api);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue