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 non-zero, busy-wait indefinitely for the remote to consume
130 : * the message. The message is considered consumed
131 : * once the remote interrupt handler finishes.
132 : * If there is deferred processing on the remote side,
133 : * or you would like to queue outgoing messages and wait on an
134 : * event/semaphore, you can implement that in a high-level driver
135 : * @param id Message identifier. Values are constrained by
136 : * @a ipm_max_data_size_get since many boards only allow for a
137 : * subset of bits in a 32-bit register to store the ID.
138 : * @param data Pointer to the data sent in the message.
139 : * @param size Size of the data.
140 : *
141 : * @retval -EBUSY If the remote hasn't yet read the last data sent.
142 : * @retval -EMSGSIZE If the supplied data size is unsupported by the driver.
143 : * @retval -EINVAL If there was a bad parameter, such as: too-large id value.
144 : * or the device isn't an outbound IPM channel.
145 : * @retval 0 On success.
146 : */
147 1 : __syscall int ipm_send(const struct device *ipmdev, int wait, uint32_t id,
148 : const void *data, int size);
149 :
150 : static inline int z_impl_ipm_send(const struct device *ipmdev, int wait,
151 : uint32_t id,
152 : const void *data, int size)
153 : {
154 : const struct ipm_driver_api *api =
155 : (const struct ipm_driver_api *)ipmdev->api;
156 :
157 : return api->send(ipmdev, wait, id, data, size);
158 : }
159 :
160 : /**
161 : * @brief Register a callback function for incoming messages.
162 : *
163 : * @param ipmdev Driver instance pointer.
164 : * @param cb Callback function to execute on incoming message interrupts.
165 : * @param user_data Application-specific data pointer which will be passed
166 : * to the callback function when executed.
167 : */
168 1 : static inline void ipm_register_callback(const struct device *ipmdev,
169 : ipm_callback_t cb, void *user_data)
170 : {
171 : const struct ipm_driver_api *api =
172 : (const struct ipm_driver_api *)ipmdev->api;
173 :
174 : api->register_callback(ipmdev, cb, user_data);
175 : }
176 :
177 : /**
178 : * @brief Return the maximum number of bytes possible in an outbound message.
179 : *
180 : * IPM implementations vary on the amount of data that can be sent in a
181 : * single message since the data payload is typically stored in registers.
182 : *
183 : * @param ipmdev Driver instance pointer.
184 : *
185 : * @return Maximum possible size of a message in bytes.
186 : */
187 1 : __syscall int ipm_max_data_size_get(const struct device *ipmdev);
188 :
189 : static inline int z_impl_ipm_max_data_size_get(const struct device *ipmdev)
190 : {
191 : const struct ipm_driver_api *api =
192 : (const struct ipm_driver_api *)ipmdev->api;
193 :
194 : return api->max_data_size_get(ipmdev);
195 : }
196 :
197 :
198 : /**
199 : * @brief Return the maximum id value possible in an outbound message.
200 : *
201 : * Many IPM implementations store the message's ID in a register with
202 : * some bits reserved for other uses.
203 : *
204 : * @param ipmdev Driver instance pointer.
205 : *
206 : * @return Maximum possible value of a message ID.
207 : */
208 1 : __syscall uint32_t ipm_max_id_val_get(const struct device *ipmdev);
209 :
210 : static inline uint32_t z_impl_ipm_max_id_val_get(const struct device *ipmdev)
211 : {
212 : const struct ipm_driver_api *api =
213 : (const struct ipm_driver_api *)ipmdev->api;
214 :
215 : return api->max_id_val_get(ipmdev);
216 : }
217 :
218 : /**
219 : * @brief Enable interrupts and callbacks for inbound channels.
220 : *
221 : * @param ipmdev Driver instance pointer.
222 : * @param enable Set to 0 to disable and to nonzero to enable.
223 : *
224 : * @retval 0 On success.
225 : * @retval -EINVAL If it isn't an inbound channel.
226 : */
227 1 : __syscall int ipm_set_enabled(const struct device *ipmdev, int enable);
228 :
229 : static inline int z_impl_ipm_set_enabled(const struct device *ipmdev,
230 : int enable)
231 : {
232 : const struct ipm_driver_api *api =
233 : (const struct ipm_driver_api *)ipmdev->api;
234 :
235 : return api->set_enabled(ipmdev, enable);
236 : }
237 :
238 : /**
239 : * @brief Signal asynchronous command completion
240 : *
241 : * Some IPM backends have an ability to deliver a command
242 : * asynchronously. The callback will be invoked in interrupt context,
243 : * but the message (including the provided data pointer) will stay
244 : * "active" and unacknowledged until later code (presumably in thread
245 : * mode) calls ipm_complete().
246 : *
247 : * This function is, obviously, a noop on drivers without async
248 : * support.
249 : *
250 : * @param ipmdev Driver instance pointer.
251 : */
252 1 : __syscall void ipm_complete(const struct device *ipmdev);
253 :
254 : static inline void z_impl_ipm_complete(const struct device *ipmdev)
255 : {
256 : #ifdef CONFIG_IPM_CALLBACK_ASYNC
257 : const struct ipm_driver_api *api =
258 : (const struct ipm_driver_api *)ipmdev->api;
259 :
260 : if (api->complete != NULL) {
261 : api->complete(ipmdev);
262 : }
263 : #endif
264 : }
265 :
266 : #ifdef __cplusplus
267 : }
268 : #endif
269 :
270 : /**
271 : * @}
272 : */
273 :
274 : #include <zephyr/syscalls/ipm.h>
275 :
276 : #endif /* ZEPHYR_INCLUDE_DRIVERS_IPM_H_ */
|