Line data Source code
1 1 : /** 2 : * @file 3 : * 4 : * @brief Generic low-level inter-processor mailbox communication API. 5 : */ 6 : 7 : /* 8 : * Copyright (c) 2015 Intel Corporation 9 : * 10 : * SPDX-License-Identifier: Apache-2.0 11 : */ 12 : 13 : #ifndef ZEPHYR_INCLUDE_DRIVERS_IPM_H_ 14 : #define ZEPHYR_INCLUDE_DRIVERS_IPM_H_ 15 : 16 : /** 17 : * @brief IPM Interface 18 : * @defgroup ipm_interface IPM Interface 19 : * @since 1.0 20 : * @version 1.0.0 21 : * @ingroup io_interfaces 22 : * @{ 23 : */ 24 : 25 : #include <zephyr/kernel.h> 26 : #include <zephyr/device.h> 27 : 28 : #ifdef __cplusplus 29 : extern "C" { 30 : #endif 31 : 32 : /** 33 : * @typedef ipm_callback_t 34 : * @brief Callback API for incoming IPM messages 35 : * 36 : * These callbacks execute in interrupt context. Therefore, use only 37 : * interrupt-safe APIS. Registration of callbacks is done via 38 : * @a ipm_register_callback 39 : * 40 : * @param ipmdev Driver instance 41 : * @param user_data Pointer to some private data provided at registration 42 : * time. 43 : * @param id Message type identifier. 44 : * @param data Message data pointer. The correct amount of data to read out 45 : * must be inferred using the message id/upper level protocol. 46 : */ 47 1 : typedef void (*ipm_callback_t)(const struct device *ipmdev, void *user_data, 48 : uint32_t id, volatile void *data); 49 : 50 : /** 51 : * @typedef ipm_send_t 52 : * @brief Callback API to send IPM messages 53 : * 54 : * See @a ipm_send() for argument definitions. 55 : */ 56 1 : typedef int (*ipm_send_t)(const struct device *ipmdev, int wait, uint32_t id, 57 : const void *data, int size); 58 : /** 59 : * @typedef ipm_max_data_size_get_t 60 : * @brief Callback API to get maximum data size 61 : * 62 : * See @a ipm_max_data_size_get() for argument definitions. 63 : */ 64 1 : typedef int (*ipm_max_data_size_get_t)(const struct device *ipmdev); 65 : 66 : /** 67 : * @typedef ipm_max_id_val_get_t 68 : * @brief Callback API to get the ID's maximum value 69 : * 70 : * See @a ipm_max_id_val_get() for argument definitions. 71 : */ 72 1 : typedef uint32_t (*ipm_max_id_val_get_t)(const struct device *ipmdev); 73 : 74 : /** 75 : * @typedef ipm_register_callback_t 76 : * @brief Callback API upon registration 77 : * 78 : * See @a ipm_register_callback() for argument definitions. 79 : */ 80 1 : typedef void (*ipm_register_callback_t)(const struct device *port, 81 : ipm_callback_t cb, 82 : void *user_data); 83 : 84 : /** 85 : * @typedef ipm_set_enabled_t 86 : * @brief Callback API upon enablement of interrupts 87 : * 88 : * See @a ipm_set_enabled() for argument definitions. 89 : */ 90 1 : typedef int (*ipm_set_enabled_t)(const struct device *ipmdev, int enable); 91 : 92 : /** 93 : * @typedef ipm_complete_t 94 : * @brief Callback API upon command completion 95 : * 96 : * See @a ipm_complete() for argument definitions. 97 : */ 98 1 : typedef void (*ipm_complete_t)(const struct device *ipmdev); 99 : 100 0 : __subsystem struct ipm_driver_api { 101 0 : ipm_send_t send; 102 0 : ipm_register_callback_t register_callback; 103 0 : ipm_max_data_size_get_t max_data_size_get; 104 0 : ipm_max_id_val_get_t max_id_val_get; 105 0 : ipm_set_enabled_t set_enabled; 106 : #ifdef CONFIG_IPM_CALLBACK_ASYNC 107 : ipm_complete_t complete; 108 : #endif 109 : }; 110 : 111 : /** 112 : * @brief Try to send a message over the IPM device. 113 : * 114 : * A message is considered consumed once the remote interrupt handler 115 : * finishes. If there is deferred processing on the remote side, 116 : * or if outgoing messages must be queued and wait on an 117 : * event/semaphore, a high-level driver can implement that. 118 : * 119 : * There are constraints on how much data can be sent or the maximum value 120 : * of id. Use the @a ipm_max_data_size_get and @a ipm_max_id_val_get routines 121 : * to determine them. 122 : * 123 : * The @a size parameter is used only on the sending side to determine 124 : * the amount of data to put in the message registers. It is not passed along 125 : * to the receiving side. The upper-level protocol dictates the amount of 126 : * data read back. 127 : * 128 : * @param ipmdev Driver instance 129 : * @param wait If nonzero, busy-wait for remote to consume the message. The 130 : * message is considered consumed once the remote interrupt handler 131 : * finishes. If there is deferred processing on the remote side, 132 : * or you would like to queue outgoing messages and wait on an 133 : * event/semaphore, you can implement that in a high-level driver 134 : * @param id Message identifier. Values are constrained by 135 : * @a ipm_max_data_size_get since many boards only allow for a 136 : * subset of bits in a 32-bit register to store the ID. 137 : * @param data Pointer to the data sent in the message. 138 : * @param size Size of the data. 139 : * 140 : * @retval -EBUSY If the remote hasn't yet read the last data sent. 141 : * @retval -EMSGSIZE If the supplied data size is unsupported by the driver. 142 : * @retval -EINVAL If there was a bad parameter, such as: too-large id value. 143 : * or the device isn't an outbound IPM channel. 144 : * @retval 0 On success. 145 : */ 146 1 : __syscall int ipm_send(const struct device *ipmdev, int wait, uint32_t id, 147 : const void *data, int size); 148 : 149 : static inline int z_impl_ipm_send(const struct device *ipmdev, int wait, 150 : uint32_t id, 151 : const void *data, int size) 152 : { 153 : const struct ipm_driver_api *api = 154 : (const struct ipm_driver_api *)ipmdev->api; 155 : 156 : return api->send(ipmdev, wait, id, data, size); 157 : } 158 : 159 : /** 160 : * @brief Register a callback function for incoming messages. 161 : * 162 : * @param ipmdev Driver instance pointer. 163 : * @param cb Callback function to execute on incoming message interrupts. 164 : * @param user_data Application-specific data pointer which will be passed 165 : * to the callback function when executed. 166 : */ 167 1 : static inline void ipm_register_callback(const struct device *ipmdev, 168 : ipm_callback_t cb, void *user_data) 169 : { 170 : const struct ipm_driver_api *api = 171 : (const struct ipm_driver_api *)ipmdev->api; 172 : 173 : api->register_callback(ipmdev, cb, user_data); 174 : } 175 : 176 : /** 177 : * @brief Return the maximum number of bytes possible in an outbound message. 178 : * 179 : * IPM implementations vary on the amount of data that can be sent in a 180 : * single message since the data payload is typically stored in registers. 181 : * 182 : * @param ipmdev Driver instance pointer. 183 : * 184 : * @return Maximum possible size of a message in bytes. 185 : */ 186 1 : __syscall int ipm_max_data_size_get(const struct device *ipmdev); 187 : 188 : static inline int z_impl_ipm_max_data_size_get(const struct device *ipmdev) 189 : { 190 : const struct ipm_driver_api *api = 191 : (const struct ipm_driver_api *)ipmdev->api; 192 : 193 : return api->max_data_size_get(ipmdev); 194 : } 195 : 196 : 197 : /** 198 : * @brief Return the maximum id value possible in an outbound message. 199 : * 200 : * Many IPM implementations store the message's ID in a register with 201 : * some bits reserved for other uses. 202 : * 203 : * @param ipmdev Driver instance pointer. 204 : * 205 : * @return Maximum possible value of a message ID. 206 : */ 207 1 : __syscall uint32_t ipm_max_id_val_get(const struct device *ipmdev); 208 : 209 : static inline uint32_t z_impl_ipm_max_id_val_get(const struct device *ipmdev) 210 : { 211 : const struct ipm_driver_api *api = 212 : (const struct ipm_driver_api *)ipmdev->api; 213 : 214 : return api->max_id_val_get(ipmdev); 215 : } 216 : 217 : /** 218 : * @brief Enable interrupts and callbacks for inbound channels. 219 : * 220 : * @param ipmdev Driver instance pointer. 221 : * @param enable Set to 0 to disable and to nonzero to enable. 222 : * 223 : * @retval 0 On success. 224 : * @retval -EINVAL If it isn't an inbound channel. 225 : */ 226 1 : __syscall int ipm_set_enabled(const struct device *ipmdev, int enable); 227 : 228 : static inline int z_impl_ipm_set_enabled(const struct device *ipmdev, 229 : int enable) 230 : { 231 : const struct ipm_driver_api *api = 232 : (const struct ipm_driver_api *)ipmdev->api; 233 : 234 : return api->set_enabled(ipmdev, enable); 235 : } 236 : 237 : /** 238 : * @brief Signal asynchronous command completion 239 : * 240 : * Some IPM backends have an ability to deliver a command 241 : * asynchronously. The callback will be invoked in interrupt context, 242 : * but the message (including the provided data pointer) will stay 243 : * "active" and unacknowledged until later code (presumably in thread 244 : * mode) calls ipm_complete(). 245 : * 246 : * This function is, obviously, a noop on drivers without async 247 : * support. 248 : * 249 : * @param ipmdev Driver instance pointer. 250 : */ 251 1 : __syscall void ipm_complete(const struct device *ipmdev); 252 : 253 : static inline void z_impl_ipm_complete(const struct device *ipmdev) 254 : { 255 : #ifdef CONFIG_IPM_CALLBACK_ASYNC 256 : const struct ipm_driver_api *api = 257 : (const struct ipm_driver_api *)ipmdev->api; 258 : 259 : if (api->complete != NULL) { 260 : api->complete(ipmdev); 261 : } 262 : #endif 263 : } 264 : 265 : #ifdef __cplusplus 266 : } 267 : #endif 268 : 269 : /** 270 : * @} 271 : */ 272 : 273 : #include <zephyr/syscalls/ipm.h> 274 : 275 : #endif /* ZEPHYR_INCLUDE_DRIVERS_IPM_H_ */