LCOV - code coverage report
Current view: top level - zephyr/drivers - mbox.h Coverage Total Hit
Test: new.info Lines: 95.2 % 21 20
Test Date: 2025-09-05 16:43:28

            Line data    Source code
       1            0 : /*
       2              :  * Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
       3              :  * SPDX-License-Identifier: Apache-2.0
       4              :  */
       5              : 
       6              : #ifndef ZEPHYR_INCLUDE_DRIVERS_MBOX_H_
       7              : #define ZEPHYR_INCLUDE_DRIVERS_MBOX_H_
       8              : 
       9              : #include <errno.h>
      10              : #include <stdint.h>
      11              : #include <stdlib.h>
      12              : 
      13              : #include <zephyr/device.h>
      14              : #include <zephyr/devicetree.h>
      15              : 
      16              : #ifdef __cplusplus
      17              : extern "C" {
      18              : #endif
      19              : 
      20              : /**
      21              :  * @brief MBOX Interface
      22              :  * @defgroup mbox_interface MBOX Interface
      23              :  * @since 1.0
      24              :  * @version 0.1.0
      25              :  * @ingroup io_interfaces
      26              :  * @{
      27              :  *
      28              :  * @code{.unparsed}
      29              :  *
      30              :  *                      CPU #1        |
      31              :  * +----------+                       |        +----------+
      32              :  * |          +---TX9----+   +--------+--RX8---+          |
      33              :  * |  dev A   |          |   |        |        |  CPU #2  |
      34              :  * |          <---RX8--+ |   | +------+--TX9--->          |
      35              :  * +----------+        | |   | |      |        +----------+
      36              :  *                  +--+-v---v-+--+   |
      37              :  *                  |             |   |
      38              :  *                  |   MBOX dev  |   |
      39              :  *                  |             |   |
      40              :  *                  +--+-^---^--+-+   |
      41              :  * +----------+        | |   |  |     |        +----------+
      42              :  * |          <---RX2--+ |   |  +-----+--TX3--->          |
      43              :  * |  dev B   |          |   |        |        |  CPU #3  |
      44              :  * |          +---TX3----+   +--------+--RX2---+          |
      45              :  * +----------+                       |        +----------+
      46              :  *                                    |
      47              :  *
      48              :  * @endcode
      49              :  *
      50              :  * An MBOX device is a peripheral capable of passing signals (and data depending
      51              :  * on the peripheral) between CPUs and clusters in the system. Each MBOX
      52              :  * instance is providing one or more channels, each one targeting one other CPU
      53              :  * cluster (multiple channels can target the same cluster).
      54              :  *
      55              :  * For example in the plot the device 'dev A' is using the TX channel 9 to
      56              :  * signal (or send data to) the CPU #2 and it's expecting data or signals on
      57              :  * the RX channel 8. Thus it can send the message through the channel 9, and it
      58              :  * can register a callback on the channel 8 of the MBOX device.
      59              :  *
      60              :  * This API supports two modes: signalling mode and data transfer mode.
      61              :  *
      62              :  * In signalling mode:
      63              :  *  - mbox_mtu_get() must return 0
      64              :  *  - mbox_send() must have (msg == NULL)
      65              :  *  - the callback must be called with (data == NULL)
      66              :  *
      67              :  * In data transfer mode:
      68              :  *  - mbox_mtu_get() must return a (value != 0)
      69              :  *  - mbox_send() must have (msg != NULL)
      70              :  *  - the callback must be called with (data != NULL)
      71              :  *  - The msg content must be the same between sender and receiver
      72              :  *
      73              :  */
      74              : 
      75              : /** @brief Type for MBOX channel identifiers */
      76            1 : typedef uint32_t mbox_channel_id_t;
      77              : 
      78              : /** @brief Message struct (to hold data and its size). */
      79            1 : struct mbox_msg {
      80              :         /** Pointer to the data sent in the message. */
      81            1 :         const void *data;
      82              :         /** Size of the data. */
      83            1 :         size_t size;
      84              : };
      85              : 
      86              : /** @brief MBOX specification from DT */
      87            1 : struct mbox_dt_spec {
      88              :         /** MBOX device pointer. */
      89            1 :         const struct device *dev;
      90              :         /** Channel ID. */
      91            1 :         mbox_channel_id_t channel_id;
      92              : };
      93              : 
      94              : /**
      95              :  * @brief Structure initializer for struct mbox_dt_spec from devicetree
      96              :  *
      97              :  * This helper macro expands to a static initializer for a struct mbox_dt_spec
      98              :  * by reading the relevant device controller and channel number from the
      99              :  * devicetree.
     100              :  *
     101              :  * Example devicetree fragment:
     102              :  *
     103              :  * @code{.devicetree}
     104              :  *     n: node {
     105              :  *             mboxes = <&mbox1 8>,
     106              :  *                      <&mbox1 9>;
     107              :  *             mbox-names = "tx", "rx";
     108              :  *     };
     109              :  * @endcode
     110              :  *
     111              :  * Example usage:
     112              :  *
     113              :  * @code{.c}
     114              :  *     const struct mbox_dt_spec spec = MBOX_DT_SPEC_GET(DT_NODELABEL(n), tx);
     115              :  * @endcode
     116              :  *
     117              :  * @param node_id Devicetree node identifier for the MBOX device
     118              :  * @param name lowercase-and-underscores name of the mboxes element
     119              :  *
     120              :  * @return static initializer for a struct mbox_dt_spec
     121              :  */
     122            1 : #define MBOX_DT_SPEC_GET(node_id, name)                                        \
     123              :         {                                                                      \
     124              :                 .dev = DEVICE_DT_GET(DT_MBOX_CTLR_BY_NAME(node_id, name)),     \
     125              :                 .channel_id = DT_MBOX_CHANNEL_BY_NAME(node_id, name),          \
     126              :         }
     127              : 
     128              : /**
     129              :  * @brief Instance version of MBOX_DT_CHANNEL_GET()
     130              :  *
     131              :  * @param inst DT_DRV_COMPAT instance number
     132              :  * @param name lowercase-and-underscores name of the mboxes element
     133              :  *
     134              :  * @return static initializer for a struct mbox_dt_spec
     135              :  */
     136            1 : #define MBOX_DT_SPEC_INST_GET(inst, name)                                      \
     137              :         MBOX_DT_SPEC_GET(DT_DRV_INST(inst), name)
     138              : 
     139              : /** @cond INTERNAL_HIDDEN */
     140              : 
     141              : /**
     142              :  * @brief Callback API for incoming MBOX messages
     143              :  *
     144              :  * These callbacks execute in interrupt context. Therefore, use only
     145              :  * interrupt-safe APIs. Registration of callbacks is done via
     146              :  * mbox_register_callback()
     147              :  *
     148              :  * The data parameter must be NULL in signalling mode.
     149              :  *
     150              :  * @param dev MBOX device instance
     151              :  * @param channel_id Channel ID
     152              :  * @param user_data Pointer to some private data provided at registration time
     153              :  * @param data Message struct
     154              :  */
     155              : typedef void (*mbox_callback_t)(const struct device *dev,
     156              :                                 mbox_channel_id_t channel_id, void *user_data,
     157              :                                 struct mbox_msg *data);
     158              : 
     159              : /**
     160              :  * @brief Callback API to send MBOX messages
     161              :  *
     162              :  * @param dev MBOX device instance
     163              :  * @param channel_id Channel ID
     164              :  * @param msg Message struct
     165              :  *
     166              :  * @return See the return values for mbox_send()
     167              :  * @see mbox_send()
     168              :  */
     169              : typedef int (*mbox_send_t)(const struct device *dev,
     170              :                            mbox_channel_id_t channel_id,
     171              :                            const struct mbox_msg *msg);
     172              : 
     173              : /**
     174              :  * @brief Callback API to get maximum data size
     175              :  *
     176              :  * @param dev MBOX device instance
     177              :  *
     178              :  * @return See the return values for mbox_mtu_get()
     179              :  * @see mbox_mtu_get()
     180              :  */
     181              : typedef int (*mbox_mtu_get_t)(const struct device *dev);
     182              : 
     183              : /**
     184              :  * @brief Callback API upon registration
     185              :  *
     186              :  * @param dev MBOX device instance
     187              :  * @param channel_id Channel ID
     188              :  * @param cb Callback function to execute on incoming message interrupts.
     189              :  * @param user_data Application-specific data pointer which will be passed to
     190              :  *                  the callback function when executed.
     191              :  *
     192              :  * @return See return values for mbox_register_callback()
     193              :  * @see mbox_register_callback()
     194              :  */
     195              : typedef int (*mbox_register_callback_t)(const struct device *dev,
     196              :                                         mbox_channel_id_t channel_id,
     197              :                                         mbox_callback_t cb, void *user_data);
     198              : 
     199              : /**
     200              :  * @brief Callback API upon enablement of interrupts
     201              :  *
     202              :  * @param dev MBOX device instance
     203              :  * @param channel_id Channel ID
     204              :  * @param enabled Set to 0 to disable and to nonzero to enable.
     205              :  *
     206              :  * @return See return values for mbox_set_enabled()
     207              :  * @see mbox_set_enabled()
     208              :  */
     209              : typedef int (*mbox_set_enabled_t)(const struct device *dev,
     210              :                                   mbox_channel_id_t channel_id, bool enabled);
     211              : 
     212              : /**
     213              :  * @brief Callback API to get maximum number of channels
     214              :  *
     215              :  * @param dev MBOX device instance
     216              :  *
     217              :  * @return See return values for mbox_max_channels_get()
     218              :  * @see mbox_max_channels_get()
     219              :  */
     220              : typedef uint32_t (*mbox_max_channels_get_t)(const struct device *dev);
     221              : 
     222              : __subsystem struct mbox_driver_api {
     223              :         mbox_send_t send;
     224              :         mbox_register_callback_t register_callback;
     225              :         mbox_mtu_get_t mtu_get;
     226              :         mbox_max_channels_get_t max_channels_get;
     227              :         mbox_set_enabled_t set_enabled;
     228              : };
     229              : 
     230              : /** @endcond */
     231              : 
     232              : /**
     233              :  * @brief Validate if MBOX device instance from a struct mbox_dt_spec is ready.
     234              :  *
     235              :  * @param spec MBOX specification from devicetree
     236              :  *
     237              :  * @return See return values for mbox_send()
     238              :  */
     239            1 : static inline bool mbox_is_ready_dt(const struct mbox_dt_spec *spec)
     240              : {
     241              :         return device_is_ready(spec->dev);
     242              : }
     243              : 
     244              : /**
     245              :  * @brief Try to send a message over the MBOX device.
     246              :  *
     247              :  * Send a message over an struct mbox_channel. The msg parameter must be NULL
     248              :  * when the driver is used for signalling.
     249              :  *
     250              :  * If the msg parameter is not NULL, this data is expected to be delivered on
     251              :  * the receiving side using the data parameter of the receiving callback.
     252              :  *
     253              :  * @param dev MBOX device instance
     254              :  * @param channel_id MBOX channel identifier
     255              :  * @param msg Message
     256              :  *
     257              :  * @retval 0         On success.
     258              :  * @retval -EBUSY    If the remote hasn't yet read the last data sent.
     259              :  * @retval -EMSGSIZE If the supplied data size is unsupported by the driver.
     260              :  * @retval -EINVAL   If there was a bad parameter, such as: too-large channel
     261              :  *                   descriptor or the device isn't an outbound MBOX channel.
     262              :  */
     263            1 : __syscall int mbox_send(const struct device *dev, mbox_channel_id_t channel_id,
     264              :                         const struct mbox_msg *msg);
     265              : 
     266              : static inline int z_impl_mbox_send(const struct device *dev,
     267              :                                    mbox_channel_id_t channel_id,
     268              :                                    const struct mbox_msg *msg)
     269              : {
     270              :         const struct mbox_driver_api *api =
     271              :                 (const struct mbox_driver_api *)dev->api;
     272              : 
     273              :         if (api->send == NULL) {
     274              :                 return -ENOSYS;
     275              :         }
     276              : 
     277              :         return api->send(dev, channel_id, msg);
     278              : }
     279              : 
     280              : /**
     281              :  * @brief Try to send a message over the MBOX device from a struct mbox_dt_spec.
     282              :  *
     283              :  * @param spec MBOX specification from devicetree
     284              :  * @param msg Message
     285              :  *
     286              :  * @return See return values for mbox_send()
     287              :  */
     288            1 : static inline int mbox_send_dt(const struct mbox_dt_spec *spec,
     289              :                                const struct mbox_msg *msg)
     290              : {
     291              :         return mbox_send(spec->dev, spec->channel_id, msg);
     292              : }
     293              : 
     294              : /**
     295              :  * @brief Register a callback function on a channel for incoming messages.
     296              :  *
     297              :  * This function doesn't assume anything concerning the status of the
     298              :  * interrupts. Use mbox_set_enabled() to enable or to disable the interrupts
     299              :  * if needed.
     300              :  *
     301              :  * @param dev MBOX device instance
     302              :  * @param channel_id MBOX channel identifier
     303              :  * @param cb Callback function to execute on incoming message interrupts.
     304              :  * @param user_data Application-specific data pointer which will be passed
     305              :  *                  to the callback function when executed.
     306              :  *
     307              :  * @retval 0      On success.
     308              :  * @retval -errno Negative errno on error.
     309              :  */
     310            1 : static inline int mbox_register_callback(const struct device *dev,
     311              :                                          mbox_channel_id_t channel_id,
     312              :                                          mbox_callback_t cb,
     313              :                                          void *user_data)
     314              : {
     315              :         const struct mbox_driver_api *api =
     316              :                 (const struct mbox_driver_api *)dev->api;
     317              : 
     318              :         if (api->register_callback == NULL) {
     319              :                 return -ENOSYS;
     320              :         }
     321              : 
     322              :         return api->register_callback(dev, channel_id, cb, user_data);
     323              : }
     324              : 
     325              : /**
     326              :  * @brief Register a callback function on a channel for incoming messages from a
     327              :  *        struct mbox_dt_spec.
     328              :  *
     329              :  * @param spec MBOX specification from devicetree
     330              :  * @param cb Callback function to execute on incoming message interrupts.
     331              :  * @param user_data Application-specific data pointer which will be passed
     332              :  *                  to the callback function when executed.
     333              :  *
     334              :  * @return See return values for mbox_register_callback()
     335              :  */
     336            1 : static inline int mbox_register_callback_dt(const struct mbox_dt_spec *spec,
     337              :                                             mbox_callback_t cb, void *user_data)
     338              : {
     339              :         return mbox_register_callback(spec->dev, spec->channel_id, cb,
     340              :                                       user_data);
     341              : }
     342              : 
     343              : /**
     344              :  * @brief Return the maximum number of bytes possible in an outbound message.
     345              :  *
     346              :  * Returns the actual number of bytes that it is possible to send through an
     347              :  * outgoing channel.
     348              :  *
     349              :  * This number can be 0 when the driver only supports signalling or when on the
     350              :  * receiving side the content and size of the message must be retrieved in an
     351              :  * indirect way (i.e. probing some other peripheral, reading memory regions,
     352              :  * etc...).
     353              :  *
     354              :  * If this function returns 0, the msg parameter in mbox_send() is expected
     355              :  * to be NULL.
     356              :  *
     357              :  * @param dev MBOX device instance.
     358              :  *
     359              :  * @retval >0     Maximum possible size of a message in bytes
     360              :  * @retval 0      Indicates signalling
     361              :  * @retval -errno Negative errno on error.
     362              :  */
     363            1 : __syscall int mbox_mtu_get(const struct device *dev);
     364              : 
     365              : static inline int z_impl_mbox_mtu_get(const struct device *dev)
     366              : {
     367              :         const struct mbox_driver_api *api =
     368              :                 (const struct mbox_driver_api *)dev->api;
     369              : 
     370              :         if (api->mtu_get == NULL) {
     371              :                 return -ENOSYS;
     372              :         }
     373              : 
     374              :         return api->mtu_get(dev);
     375              : }
     376              : 
     377              : /**
     378              :  * @brief Return the maximum number of bytes possible in an outbound message
     379              :  *        from struct mbox_dt_spec.
     380              :  *
     381              :  * @param spec MBOX specification from devicetree
     382              :  *
     383              :  * @return See return values for mbox_register_callback()
     384              :  */
     385            1 : static inline int mbox_mtu_get_dt(const struct mbox_dt_spec *spec)
     386              : {
     387              :         return mbox_mtu_get(spec->dev);
     388              : }
     389              : 
     390              : /**
     391              :  * @brief Enable (disable) interrupts and callbacks for inbound channels.
     392              :  *
     393              :  * Enable interrupt for the channel when the parameter 'enable' is set to true.
     394              :  * Disable it otherwise.
     395              :  *
     396              :  * Immediately after calling this function with 'enable' set to true, the
     397              :  * channel is considered enabled and ready to receive signal and messages (even
     398              :  * already pending), so the user must take care of installing a proper callback
     399              :  * (if needed) using mbox_register_callback() on the channel before enabling
     400              :  * it. For this reason it is recommended that all the channels are disabled at
     401              :  * probe time.
     402              :  *
     403              :  * Enabling a channel for which there is no installed callback is considered
     404              :  * undefined behavior (in general the driver must take care of gracefully
     405              :  * handling spurious interrupts with no installed callback).
     406              :  *
     407              :  * @param dev MBOX device instance
     408              :  * @param channel_id MBOX channel identifier
     409              :  * @param enabled Enable (true) or disable (false) the channel.
     410              :  *
     411              :  * @retval 0         On success.
     412              :  * @retval -EINVAL   If it isn't an inbound channel.
     413              :  * @retval -EALREADY If channel is already @p enabled.
     414              :  */
     415            1 : __syscall int mbox_set_enabled(const struct device *dev,
     416              :                                mbox_channel_id_t channel_id, bool enabled);
     417              : 
     418              : static inline int z_impl_mbox_set_enabled(const struct device *dev,
     419              :                                           mbox_channel_id_t channel_id,
     420              :                                           bool enabled)
     421              : {
     422              :         const struct mbox_driver_api *api =
     423              :                 (const struct mbox_driver_api *)dev->api;
     424              : 
     425              :         if (api->set_enabled == NULL) {
     426              :                 return -ENOSYS;
     427              :         }
     428              : 
     429              :         return api->set_enabled(dev, channel_id, enabled);
     430              : }
     431              : 
     432              : /**
     433              :  * @brief Enable (disable) interrupts and callbacks for inbound channels from a
     434              :  *        struct mbox_dt_spec.
     435              :  *
     436              :  * @param spec MBOX specification from devicetree
     437              :  * @param enabled Enable (true) or disable (false) the channel.
     438              :  *
     439              :  * @return See return values for mbox_set_enabled()
     440              :  */
     441            1 : static inline int mbox_set_enabled_dt(const struct mbox_dt_spec *spec,
     442              :                                       bool enabled)
     443              : {
     444              :         return mbox_set_enabled(spec->dev, spec->channel_id, enabled);
     445              : }
     446              : 
     447              : /**
     448              :  * @brief Return the maximum number of channels.
     449              :  *
     450              :  * Return the maximum number of channels supported by the hardware.
     451              :  *
     452              :  * @param dev MBOX device instance.
     453              :  *
     454              :  * @return >0     Maximum possible number of supported channels on success
     455              :  * @return -errno Negative errno on error.
     456              :  */
     457            1 : __syscall uint32_t mbox_max_channels_get(const struct device *dev);
     458              : 
     459              : static inline uint32_t z_impl_mbox_max_channels_get(const struct device *dev)
     460              : {
     461              :         const struct mbox_driver_api *api =
     462              :                 (const struct mbox_driver_api *)dev->api;
     463              : 
     464              :         if (api->max_channels_get == NULL) {
     465              :                 return -ENOSYS;
     466              :         }
     467              : 
     468              :         return api->max_channels_get(dev);
     469              : }
     470              : 
     471              : /**
     472              :  * @brief Return the maximum number of channels from a struct mbox_dt_spec.
     473              :  *
     474              :  * @param spec MBOX specification from devicetree
     475              :  *
     476              :  * @return See return values for mbox_max_channels_get()
     477              :  */
     478            1 : static inline int mbox_max_channels_get_dt(const struct mbox_dt_spec *spec)
     479              : {
     480              :         return mbox_max_channels_get(spec->dev);
     481              : }
     482              : 
     483              : /** @} */
     484              : 
     485              : #ifdef __cplusplus
     486              : }
     487              : #endif
     488              : 
     489              : #include <zephyr/syscalls/mbox.h>
     490              : 
     491              : #endif /* ZEPHYR_INCLUDE_DRIVERS_MBOX_H_ */
        

Generated by: LCOV version 2.0-1