LCOV - code coverage report
Current view: top level - zephyr/drivers - mbox.h Coverage Total Hit
Test: new.info Lines: 100.0 % 21 21
Test Date: 2025-09-25 19:22:35

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

Generated by: LCOV version 2.0-1