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_ */