Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 1 | /** |
| 2 | * @file |
| 3 | * |
| 4 | * @brief Generic low-level inter-processor mailbox communication API. |
| 5 | */ |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 6 | |
| 7 | /* |
| 8 | * Copyright (c) 2015 Intel Corporation |
| 9 | * |
David B. Kinder | ac74d8b | 2017-01-18 17:01:01 -0800 | [diff] [blame] | 10 | * SPDX-License-Identifier: Apache-2.0 |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 11 | */ |
| 12 | |
| 13 | #ifndef __INCipmh |
| 14 | #define __INCipmh |
| 15 | |
| 16 | /** |
| 17 | * @brief IPM Interface |
| 18 | * @defgroup ipm_interface IPM Interface |
| 19 | * @ingroup io_interfaces |
| 20 | * @{ |
| 21 | */ |
| 22 | |
Anas Nashif | ea8c6aad | 2016-12-23 07:32:56 -0500 | [diff] [blame] | 23 | #include <kernel.h> |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 24 | #include <device.h> |
| 25 | |
Peter Mitsis | a0e4568 | 2016-01-22 12:38:49 -0500 | [diff] [blame] | 26 | #ifdef __cplusplus |
| 27 | extern "C" { |
| 28 | #endif |
| 29 | |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 30 | /** |
Inaky Perez-Gonzalez | 0518063 | 2016-06-15 14:18:38 -0700 | [diff] [blame] | 31 | * @typedef ipm_callback_t |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 32 | * @brief Callback API for incoming IPM messages |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 33 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 34 | * These callbacks execute in interrupt context. Therefore, use only |
| 35 | * interrupt-safe APIS. Registration of callbacks is done via |
| 36 | * @a ipm_register_callback |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 37 | * |
Inaky Perez-Gonzalez | 0518063 | 2016-06-15 14:18:38 -0700 | [diff] [blame] | 38 | * @param "void *context" Arbitrary context pointer provided at |
| 39 | * registration time. |
Kumar Gala | cc334c7 | 2017-04-21 10:55:34 -0500 | [diff] [blame] | 40 | * @param "u32_t id" Message type identifier. |
Inaky Perez-Gonzalez | 0518063 | 2016-06-15 14:18:38 -0700 | [diff] [blame] | 41 | * @param "volatile void *data" Message data pointer. The correct |
| 42 | * amount of data to read out |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 43 | * must be inferred using the message id/upper level protocol. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 44 | */ |
Kumar Gala | cc334c7 | 2017-04-21 10:55:34 -0500 | [diff] [blame] | 45 | typedef void (*ipm_callback_t)(void *context, u32_t id, volatile void *data); |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 46 | |
Inaky Perez-Gonzalez | 0518063 | 2016-06-15 14:18:38 -0700 | [diff] [blame] | 47 | /** |
| 48 | * @typedef ipm_send_t |
| 49 | * @brief Callback API to send IPM messages |
| 50 | * |
| 51 | * See @a ipm_send() for argument definitions. |
| 52 | */ |
Kumar Gala | cc334c7 | 2017-04-21 10:55:34 -0500 | [diff] [blame] | 53 | typedef int (*ipm_send_t)(struct device *ipmdev, int wait, u32_t id, |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 54 | const void *data, int size); |
Inaky Perez-Gonzalez | 0518063 | 2016-06-15 14:18:38 -0700 | [diff] [blame] | 55 | /** |
| 56 | * @typedef ipm_max_data_size_get_t |
| 57 | * @brief Callback API to get maximum data size |
| 58 | * |
| 59 | * See @a ipm_max_data_size_get() for argument definitions. |
| 60 | */ |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 61 | typedef int (*ipm_max_data_size_get_t)(struct device *ipmdev); |
Inaky Perez-Gonzalez | 0518063 | 2016-06-15 14:18:38 -0700 | [diff] [blame] | 62 | |
| 63 | /** |
| 64 | * @typedef ipm_max_id_val_get_t |
| 65 | * @brief Callback API to get the ID's maximum value |
| 66 | * |
| 67 | * See @a ipm_max_id_val_get() for argument definitions. |
| 68 | */ |
Kumar Gala | cc334c7 | 2017-04-21 10:55:34 -0500 | [diff] [blame] | 69 | typedef u32_t (*ipm_max_id_val_get_t)(struct device *ipmdev); |
Inaky Perez-Gonzalez | 0518063 | 2016-06-15 14:18:38 -0700 | [diff] [blame] | 70 | |
| 71 | /** |
| 72 | * @typedef ipm_register_callback_t |
| 73 | * @brief Callback API upon registration |
| 74 | * |
| 75 | * See @a ipm_register_callback() for argument definitions. |
| 76 | */ |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 77 | typedef void (*ipm_register_callback_t)(struct device *port, ipm_callback_t cb, |
| 78 | void *cb_context); |
Inaky Perez-Gonzalez | 0518063 | 2016-06-15 14:18:38 -0700 | [diff] [blame] | 79 | |
| 80 | /** |
| 81 | * @typedef ipm_set_enabled_t |
David B. Kinder | 8b986d7 | 2017-04-18 15:56:26 -0700 | [diff] [blame] | 82 | * @brief Callback API upon enablement of interrupts |
Inaky Perez-Gonzalez | 0518063 | 2016-06-15 14:18:38 -0700 | [diff] [blame] | 83 | * |
| 84 | * See @a ipm_set_enabled() for argument definitions. |
| 85 | */ |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 86 | typedef int (*ipm_set_enabled_t)(struct device *ipmdev, int enable); |
| 87 | |
| 88 | struct ipm_driver_api { |
| 89 | ipm_send_t send; |
| 90 | ipm_register_callback_t register_callback; |
| 91 | ipm_max_data_size_get_t max_data_size_get; |
| 92 | ipm_max_id_val_get_t max_id_val_get; |
| 93 | ipm_set_enabled_t set_enabled; |
| 94 | }; |
| 95 | |
| 96 | /** |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 97 | * @brief Try to send a message over the IPM device. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 98 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 99 | * A message is considered consumed once the remote interrupt handler |
| 100 | * finishes. If there is deferred processing on the remote side, |
| 101 | * or if outgoing messages must be queued and wait on an |
| 102 | * event/semaphore, a high-level driver can implement that. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 103 | * |
| 104 | * There are constraints on how much data can be sent or the maximum value |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 105 | * of id. Use the @a ipm_max_data_size_get and @a ipm_max_id_val_get routines |
| 106 | * to determine them. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 107 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 108 | * The @a size parameter is used only on the sending side to determine |
| 109 | * the amount of data to put in the message registers. It is not passed along |
| 110 | * to the receiving side. The upper-level protocol dictates the amount of |
| 111 | * data read back. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 112 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 113 | * @param ipmdev Driver instance |
Andrew Boie | a4a3323 | 2016-09-14 09:53:59 -0700 | [diff] [blame] | 114 | * @param wait If nonzero, busy-wait for remote to consume the message. The |
| 115 | * message is considered consumed once the remote interrupt handler |
| 116 | * finishes. If there is deferred processing on the remote side, |
| 117 | * or you would like to queue outgoing messages and wait on an |
| 118 | * event/semaphore, you can implement that in a high-level driver |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 119 | * @param id Message identifier. Values are constrained by |
David B. Kinder | d748577 | 2016-08-17 16:33:08 -0700 | [diff] [blame] | 120 | * @a ipm_max_data_size_get since many boards only allow for a |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 121 | * subset of bits in a 32-bit register to store the ID. |
| 122 | * @param data Pointer to the data sent in the message. |
| 123 | * @param size Size of the data. |
| 124 | * |
| 125 | * @retval EBUSY If the remote hasn't yet read the last data sent. |
| 126 | * @retval EMSGSIZE If the supplied data size is unsupported by the driver. |
| 127 | * @retval EINVAL If there was a bad parameter, such as: too-large id value. |
| 128 | * or the device isn't an outbound IPM channel. |
| 129 | * @retval 0 On success. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 130 | */ |
Andrew Boie | 2e60b24 | 2017-10-25 13:14:49 -0700 | [diff] [blame] | 131 | __syscall int ipm_send(struct device *ipmdev, int wait, u32_t id, |
| 132 | const void *data, int size); |
| 133 | |
| 134 | static inline int _impl_ipm_send(struct device *ipmdev, int wait, u32_t id, |
Andrew Boie | 53e6275 | 2016-03-08 10:53:45 -0800 | [diff] [blame] | 135 | const void *data, int size) |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 136 | { |
Marcus Shawcroft | bb4d03b | 2016-10-22 10:02:27 +0100 | [diff] [blame] | 137 | const struct ipm_driver_api *api = ipmdev->driver_api; |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 138 | |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 139 | return api->send(ipmdev, wait, id, data, size); |
| 140 | } |
| 141 | |
| 142 | /** |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 143 | * @brief Register a callback function for incoming messages. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 144 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 145 | * @param ipmdev Driver instance pointer. |
| 146 | * @param cb Callback function to execute on incoming message interrupts. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 147 | * @param context Application-specific context pointer which will be passed |
| 148 | * to the callback function when executed. |
| 149 | */ |
| 150 | static inline void ipm_register_callback(struct device *ipmdev, |
| 151 | ipm_callback_t cb, void *context) |
| 152 | { |
Marcus Shawcroft | bb4d03b | 2016-10-22 10:02:27 +0100 | [diff] [blame] | 153 | const struct ipm_driver_api *api = ipmdev->driver_api; |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 154 | |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 155 | api->register_callback(ipmdev, cb, context); |
| 156 | } |
| 157 | |
| 158 | /** |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 159 | * @brief Return the maximum number of bytes possible in an outbound message. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 160 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 161 | * IPM implementations vary on the amount of data that can be sent in a |
| 162 | * single message since the data payload is typically stored in registers. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 163 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 164 | * @param ipmdev Driver instance pointer. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 165 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 166 | * @return Maximum possible size of a message in bytes. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 167 | */ |
Andrew Boie | 2e60b24 | 2017-10-25 13:14:49 -0700 | [diff] [blame] | 168 | __syscall int ipm_max_data_size_get(struct device *ipmdev); |
| 169 | |
| 170 | static inline int _impl_ipm_max_data_size_get(struct device *ipmdev) |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 171 | { |
Marcus Shawcroft | bb4d03b | 2016-10-22 10:02:27 +0100 | [diff] [blame] | 172 | const struct ipm_driver_api *api = ipmdev->driver_api; |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 173 | |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 174 | return api->max_data_size_get(ipmdev); |
| 175 | } |
| 176 | |
| 177 | |
| 178 | /** |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 179 | * @brief Return the maximum id value possible in an outbound message. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 180 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 181 | * Many IPM implementations store the message's ID in a register with |
| 182 | * some bits reserved for other uses. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 183 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 184 | * @param ipmdev Driver instance pointer. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 185 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 186 | * @return Maximum possible value of a message ID. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 187 | */ |
Andrew Boie | 2e60b24 | 2017-10-25 13:14:49 -0700 | [diff] [blame] | 188 | __syscall u32_t ipm_max_id_val_get(struct device *ipmdev); |
| 189 | |
| 190 | static inline u32_t _impl_ipm_max_id_val_get(struct device *ipmdev) |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 191 | { |
Marcus Shawcroft | bb4d03b | 2016-10-22 10:02:27 +0100 | [diff] [blame] | 192 | const struct ipm_driver_api *api = ipmdev->driver_api; |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 193 | |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 194 | return api->max_id_val_get(ipmdev); |
| 195 | } |
| 196 | |
| 197 | /** |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 198 | * @brief Enable interrupts and callbacks for inbound channels. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 199 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 200 | * @param ipmdev Driver instance pointer. |
| 201 | * @param enable Set to 0 to disable and to nonzero to enable. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 202 | * |
Rodrigo Caballero | 3010de9 | 2016-02-06 16:18:22 -0600 | [diff] [blame] | 203 | * @retval 0 On success. |
| 204 | * @retval EINVAL If it isn't an inbound channel. |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 205 | */ |
Andrew Boie | 2e60b24 | 2017-10-25 13:14:49 -0700 | [diff] [blame] | 206 | __syscall int ipm_set_enabled(struct device *ipmdev, int enable); |
| 207 | |
| 208 | static inline int _impl_ipm_set_enabled(struct device *ipmdev, int enable) |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 209 | { |
Marcus Shawcroft | bb4d03b | 2016-10-22 10:02:27 +0100 | [diff] [blame] | 210 | const struct ipm_driver_api *api = ipmdev->driver_api; |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 211 | |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 212 | return api->set_enabled(ipmdev, enable); |
| 213 | } |
| 214 | |
Peter Mitsis | a0e4568 | 2016-01-22 12:38:49 -0500 | [diff] [blame] | 215 | #ifdef __cplusplus |
| 216 | } |
| 217 | #endif |
| 218 | |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 219 | /** |
| 220 | * @} |
| 221 | */ |
Andrew Boie | 2e60b24 | 2017-10-25 13:14:49 -0700 | [diff] [blame] | 222 | |
| 223 | #include <syscalls/ipm.h> |
| 224 | |
Andrew Boie | 3589695 | 2015-11-12 14:00:47 -0800 | [diff] [blame] | 225 | #endif /* __INCipmh */ |