Line data Source code
1 1 : /*
2 : * Copyright 2024 NXP
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : /**
8 : * @file
9 : * @brief Public APIs for the SCMI transport layer drivers
10 : */
11 :
12 : #ifndef _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_TRANSPORT_H_
13 : #define _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_TRANSPORT_H_
14 :
15 : #include <zephyr/device.h>
16 : #include <zephyr/kernel.h>
17 :
18 : struct scmi_message;
19 : struct scmi_channel;
20 :
21 : /**
22 : * @typedef scmi_channel_cb
23 : *
24 : * @brief Callback function for message replies
25 : *
26 : * This function should be called by the transport layer
27 : * driver whenever a reply to a previously sent message
28 : * has been received. Its purpose is to notifying the SCMI
29 : * core of the reply's arrival so that proper action can
30 : * be taken.
31 : *
32 : * @param chan pointer to SCMI channel on which the reply
33 : * arrived
34 : */
35 1 : typedef void (*scmi_channel_cb)(struct scmi_channel *chan);
36 :
37 : /**
38 : * @struct scmi_channel
39 : * @brief SCMI channel structure
40 : *
41 : * An SCMI channel is a medium through which a protocol
42 : * is able to transmit/receive messages. Each of the SCMI
43 : * channels is represented by a `struct scmi_channel`.
44 : */
45 1 : struct scmi_channel {
46 : /**
47 : * channel lock. This is meant to be initialized
48 : * and used only by the SCMI core to assure that
49 : * only one protocol can send/receive messages
50 : * through a channel at a given moment.
51 : */
52 1 : struct k_mutex lock;
53 : /**
54 : * binary semaphore. This is meant to be initialized
55 : * and used only by the SCMI core. Its purpose is to
56 : * signal that a reply has been received.
57 : */
58 1 : struct k_sem sem;
59 : /** channel private data */
60 1 : void *data;
61 : /**
62 : * callback function. This is meant to be set by
63 : * the SCMI core and should be called by the SCMI
64 : * transport layer driver whenever a reply has
65 : * been received.
66 : */
67 1 : scmi_channel_cb cb;
68 : /** is the channel ready to be used by a protocol? */
69 1 : bool ready;
70 : };
71 :
72 0 : struct scmi_transport_api {
73 0 : int (*init)(const struct device *transport);
74 0 : int (*send_message)(const struct device *transport,
75 : struct scmi_channel *chan,
76 : struct scmi_message *msg);
77 0 : int (*setup_chan)(const struct device *transport,
78 : struct scmi_channel *chan,
79 : bool tx);
80 0 : int (*read_message)(const struct device *transport,
81 : struct scmi_channel *chan,
82 : struct scmi_message *msg);
83 0 : bool (*channel_is_free)(const struct device *transport,
84 : struct scmi_channel *chan);
85 : struct scmi_channel *(*request_channel)(const struct device *transport,
86 : uint32_t proto, bool tx);
87 : };
88 :
89 : /**
90 : * @brief Request an SCMI channel dynamically
91 : *
92 : * Whenever the SCMI transport layer driver doesn't support
93 : * static channel allocation, the SCMI core will try to bind
94 : * a channel to a protocol dynamically using this function.
95 : * Note that no setup needs to be performed on the channel
96 : * in this function as the core will also call the channel
97 : * setup() function.
98 : *
99 : * @param transport pointer to the device structure for the
100 : * transport layer
101 : * @param proto ID of the protocol for which the core is
102 : * requesting the channel
103 : * @param tx true if the channel is TX, false if RX
104 : *
105 : * @retval pointer to SCMI channel that's to be bound
106 : * to the protocol
107 : * @retval NULL if operation was not successful
108 : */
109 : static inline struct scmi_channel *
110 1 : scmi_transport_request_channel(const struct device *transport,
111 : uint32_t proto, bool tx)
112 : {
113 : const struct scmi_transport_api *api =
114 : (const struct scmi_transport_api *)transport->api;
115 :
116 : if (api->request_channel) {
117 : return api->request_channel(transport, proto, tx);
118 : }
119 :
120 : return NULL;
121 : }
122 :
123 : /**
124 : * @brief Perform initialization for the transport layer driver
125 : *
126 : * The transport layer driver can't be initialized directly
127 : * (i.e via a call to its init() function) during system initialization.
128 : * This is because the macro used to define an SCMI transport places
129 : * `scmi_core_transport_init()` in the init section instead of the
130 : * driver's init() function. As such, `scmi_core_transport_init()`
131 : * needs to call this function to perfrom transport layer driver
132 : * initialization if required.
133 : *
134 : * This operation is optional.
135 : *
136 : * @param transport pointer to the device structure for the
137 : * transport layer
138 : *
139 : * @retval 0 if successful
140 : * @retval negative errno code if failure
141 : */
142 1 : static inline int scmi_transport_init(const struct device *transport)
143 : {
144 : const struct scmi_transport_api *api =
145 : (const struct scmi_transport_api *)transport->api;
146 :
147 : if (api->init) {
148 : return api->init(transport);
149 : }
150 :
151 : return 0;
152 : }
153 :
154 : /**
155 : * @brief Setup an SCMI channel
156 : *
157 : * Before being able to send/receive messages, an SCMI channel needs
158 : * to be prepared, which is what this function does. If it returns
159 : * successfully, an SCMI protocol will be able to use this channel
160 : * to send/receive messages.
161 : *
162 : * @param transport pointer to the device structure for the
163 : * transport layer
164 : * @param chan pointer to SCMI channel to be prepared
165 : * @param tx true if the channel is TX, false if RX
166 : *
167 : * @retval 0 if successful
168 : * @retval negative errno code if failure
169 : */
170 1 : static inline int scmi_transport_setup_chan(const struct device *transport,
171 : struct scmi_channel *chan,
172 : bool tx)
173 : {
174 : const struct scmi_transport_api *api =
175 : (const struct scmi_transport_api *)transport->api;
176 :
177 : if (!api || !api->setup_chan) {
178 : return -ENOSYS;
179 : }
180 :
181 : return api->setup_chan(transport, chan, tx);
182 : }
183 :
184 : /**
185 : * @brief Send an SCMI channel
186 : *
187 : * Send an SCMI message using given SCMI channel. This function is
188 : * not allowed to block.
189 : *
190 : * @param transport pointer to the device structure for the
191 : * transport layer
192 : * @param chan pointer to SCMI channel on which the message
193 : * is to be sent
194 : * @param msg pointer to message the caller wishes to send
195 : *
196 : * @retval 0 if successful
197 : * @retval negative errno code if failure
198 : */
199 1 : static inline int scmi_transport_send_message(const struct device *transport,
200 : struct scmi_channel *chan,
201 : struct scmi_message *msg)
202 : {
203 : const struct scmi_transport_api *api =
204 : (const struct scmi_transport_api *)transport->api;
205 :
206 : if (!api || !api->send_message) {
207 : return -ENOSYS;
208 : }
209 :
210 : return api->send_message(transport, chan, msg);
211 : }
212 :
213 : /**
214 : * @brief Read an SCMI message
215 : *
216 : * @param transport pointer to the device structure for the
217 : * transport layer
218 : * @param chan pointer to SCMI channel on which the message
219 : * is to be read
220 : * @param msg pointer to message the caller wishes to read
221 : *
222 : * @retval 0 if successful
223 : * @retval negative errno code if failure
224 : */
225 1 : static inline int scmi_transport_read_message(const struct device *transport,
226 : struct scmi_channel *chan,
227 : struct scmi_message *msg)
228 : {
229 : const struct scmi_transport_api *api =
230 : (const struct scmi_transport_api *)transport->api;
231 :
232 : if (!api || !api->read_message) {
233 : return -ENOSYS;
234 : }
235 :
236 : return api->read_message(transport, chan, msg);
237 : }
238 :
239 : /**
240 : * @brief Check if an SCMI channel is free
241 : *
242 : * @param transport pointer to the device structure for
243 : * the transport layer
244 : * @param chan pointer to SCMI channel the query is to be
245 : * performed on
246 : *
247 : * @retval 0 if successful
248 : * @retval negative errno code if failure
249 : */
250 1 : static inline bool scmi_transport_channel_is_free(const struct device *transport,
251 : struct scmi_channel *chan)
252 : {
253 : const struct scmi_transport_api *api =
254 : (const struct scmi_transport_api *)transport->api;
255 :
256 : if (!api || !api->channel_is_free) {
257 : return -ENOSYS;
258 : }
259 :
260 : return api->channel_is_free(transport, chan);
261 : }
262 :
263 : /**
264 : * @brief Perfrom SCMI core initialization
265 : *
266 : * @param transport pointer to the device structure for
267 : * the transport layer
268 : *
269 : * @retval 0 if successful
270 : * @retval negative errno code if failure
271 : */
272 1 : int scmi_core_transport_init(const struct device *transport);
273 :
274 : #endif /* _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_TRANSPORT_H_ */
|