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 ARM SCMI utility header
10 : *
11 : * Contains various utility macros and macros used for protocol and
12 : * transport "registration".
13 : */
14 :
15 : #ifndef _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_UTIL_H_
16 : #define _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_UTIL_H_
17 :
18 : /**
19 : * @brief Build protocol name from its ID
20 : *
21 : * Given a protocol ID, this macro builds the protocol
22 : * name. This is done by concatenating the scmi_protocol_
23 : * construct with the given protocol ID.
24 : *
25 : * @param proto protocol ID in decimal format
26 : *
27 : * @return protocol name
28 : */
29 1 : #define SCMI_PROTOCOL_NAME(proto) CONCAT(scmi_protocol_, proto)
30 :
31 : #ifdef CONFIG_ARM_SCMI_TRANSPORT_HAS_STATIC_CHANNELS
32 :
33 : #ifdef CONFIG_ARM_SCMI_MAILBOX_TRANSPORT
34 : /** @brief Check if a protocol node has an associated channel
35 : *
36 : * This macro, when applied to a protocol node, checks if
37 : * the node has a dedicated static channel allocated to it.
38 : * This definition is specific to the mailbox driver and
39 : * each new transport layer driver should define its own
40 : * version of this macro based on the devicetree properties
41 : * that indicate the presence of a dedicated channel.
42 : *
43 : * @param node_id protocol node identifier
44 : * @idx channel index. Should be 0 for TX channels and 1 for
45 : * RX channels
46 : */
47 : #define DT_SCMI_TRANSPORT_PROTO_HAS_CHAN(node_id, idx)\
48 : DT_PROP_HAS_IDX(node_id, shmem, idx)
49 : #else /* CONFIG_ARM_SCMI_MAILBOX_TRANSPORT */
50 : #error "Transport with static channels needs to define HAS_CHAN macro"
51 : #endif /* CONFIG_ARM_SCMI_MAILBOX_TRANSPORT */
52 :
53 : #define SCMI_TRANSPORT_CHAN_NAME(proto, idx) CONCAT(scmi_channel_, proto, _, idx)
54 :
55 : /**
56 : * @brief Declare a TX SCMI channel
57 : *
58 : * Given a node_id for a protocol, this macro declares the SCMI
59 : * TX channel statically bound to said protocol via the "extern"
60 : * qualifier. This is useful when the transport layer driver
61 : * supports static channels since all channel structures are
62 : * defined inside the transport layer driver.
63 : *
64 : * @param node_id protocol node identifier
65 : */
66 : #define DT_SCMI_TRANSPORT_TX_CHAN_DECLARE(node_id) \
67 : COND_CODE_1(DT_SCMI_TRANSPORT_PROTO_HAS_CHAN(node_id, 0), \
68 : (extern struct scmi_channel \
69 : SCMI_TRANSPORT_CHAN_NAME(DT_REG_ADDR_RAW(node_id), 0);), \
70 : (extern struct scmi_channel \
71 : SCMI_TRANSPORT_CHAN_NAME(SCMI_PROTOCOL_BASE, 0);)) \
72 :
73 : /**
74 : * @brief Declare SCMI TX/RX channels
75 : *
76 : * Given a node_id for a protocol, this macro declares the
77 : * SCMI TX and RX channels statically bound to said protocol via
78 : * the "extern" qualifier. Since RX channels are currently not
79 : * supported, this is equivalent to DT_SCMI_TRANSPORT_TX_CHAN_DECLARE().
80 : * Despite this, users should opt for this macro instead of the TX-specific
81 : * one.
82 : *
83 : * @param node_id protocol node identifier
84 : */
85 : #define DT_SCMI_TRANSPORT_CHANNELS_DECLARE(node_id) \
86 : DT_SCMI_TRANSPORT_TX_CHAN_DECLARE(node_id) \
87 :
88 : /**
89 : * @brief Declare SCMI TX/RX channels using node instance number
90 : *
91 : * Same as DT_SCMI_TRANSPORT_CHANNELS_DECLARE() but uses the
92 : * protocol's node instance number and the DT_DRV_COMPAT macro.
93 : *
94 : * @param protocol node instance number
95 : */
96 : #define DT_INST_SCMI_TRANSPORT_CHANNELS_DECLARE(inst) \
97 : DT_SCMI_TRANSPORT_CHANNELS_DECLARE(DT_INST(inst, DT_DRV_COMPAT))
98 :
99 : /**
100 : * @brief Get a reference to a protocol's SCMI TX channel
101 : *
102 : * Given a node_id for a protocol, this macro returns a
103 : * reference to an SCMI TX channel statically bound to said
104 : * protocol.
105 : *
106 : * @param node_id protocol node identifier
107 : *
108 : * @return reference to the struct scmi_channel of the TX channel
109 : * bound to the protocol identifier by node_id
110 : */
111 : #define DT_SCMI_TRANSPORT_TX_CHAN(node_id) \
112 : COND_CODE_1(DT_SCMI_TRANSPORT_PROTO_HAS_CHAN(node_id, 0), \
113 : (&SCMI_TRANSPORT_CHAN_NAME(DT_REG_ADDR_RAW(node_id), 0)), \
114 : (&SCMI_TRANSPORT_CHAN_NAME(SCMI_PROTOCOL_BASE, 0)))
115 :
116 : /**
117 : * @brief Define an SCMI channel for a protocol
118 : *
119 : * This macro defines a struct scmi_channel for a given protocol.
120 : * This should be used by the transport layer driver to statically
121 : * define SCMI channels for the protocols.
122 : *
123 : * @param node_id protocol node identifier
124 : * @param idx channel index. Should be 0 for TX channels and 1
125 : * for RX channels
126 : * @param proto protocol ID in decimal format
127 : */
128 : #define DT_SCMI_TRANSPORT_CHAN_DEFINE(node_id, idx, proto, pdata) \
129 : struct scmi_channel SCMI_TRANSPORT_CHAN_NAME(proto, idx) = \
130 : { \
131 : .data = pdata, \
132 : }
133 :
134 : /**
135 : * @brief Define an SCMI protocol's data
136 : *
137 : * Each SCMI protocol is identified by a struct scmi_protocol
138 : * placed in a linker section called scmi_protocol. Each protocol
139 : * driver is required to use this macro for "registration". Using
140 : * this macro directly is higly discouraged and users should opt
141 : * for macros such as DT_SCMI_PROTOCOL_DEFINE_NODEV() or
142 : * DT_SCMI_PROTOCOL_DEFINE(), which also takes care of the static
143 : * channel declaration (if applicable).
144 : *
145 : * @param node_id protocol node identifier
146 : * @param proto protocol ID in decimal format
147 : * @param pdata protocol private data
148 : */
149 : #define DT_SCMI_PROTOCOL_DATA_DEFINE(node_id, proto, pdata) \
150 : STRUCT_SECTION_ITERABLE(scmi_protocol, SCMI_PROTOCOL_NAME(proto)) = \
151 : { \
152 : .id = proto, \
153 : .tx = DT_SCMI_TRANSPORT_TX_CHAN(node_id), \
154 : .data = pdata, \
155 : }
156 :
157 : #else /* CONFIG_ARM_SCMI_TRANSPORT_HAS_STATIC_CHANNELS */
158 :
159 0 : #define DT_SCMI_TRANSPORT_CHANNELS_DECLARE(node_id)
160 :
161 0 : #define DT_SCMI_PROTOCOL_DATA_DEFINE(node_id, proto, pdata) \
162 : STRUCT_SECTION_ITERABLE(scmi_protocol, SCMI_PROTOCOL_NAME(proto)) = \
163 : { \
164 : .id = proto, \
165 : .data = pdata, \
166 : }
167 :
168 : #endif /* CONFIG_ARM_SCMI_TRANSPORT_HAS_STATIC_CHANNELS */
169 :
170 : /**
171 : * @brief Define an SCMI transport driver
172 : *
173 : * This is merely a wrapper over DEVICE_DT_INST_DEFINE(), but is
174 : * required since transport layer drivers are not allowed to place
175 : * their own init() function in the init section. Instead, transport
176 : * layer drivers place the scmi_core_transport_init() function in the
177 : * init section, which, in turn, will call the transport layer driver
178 : * init() function. This is required because the SCMI core needs to
179 : * perform channel binding and setup during the transport layer driver's
180 : * initialization.
181 : */
182 1 : #define DT_INST_SCMI_TRANSPORT_DEFINE(inst, pm, data, config, level, prio, api) \
183 : DEVICE_DT_INST_DEFINE(inst, &scmi_core_transport_init, \
184 : pm, data, config, level, prio, api)
185 :
186 : /**
187 : * @brief Define an SCMI protocol
188 : *
189 : * This macro performs three important functions:
190 : * 1) It defines a `struct scmi_protocol`, which is
191 : * needed by all protocol drivers to work with the SCMI API.
192 : *
193 : * 2) It declares the static channels bound to the protocol.
194 : * This is only applicable if the transport layer driver
195 : * supports static channels.
196 : *
197 : * 3) It creates a `struct device` a sets the `data` field
198 : * to the newly defined `struct scmi_protocol`. This is
199 : * needed because the protocol driver needs to work with the
200 : * SCMI API **and** the subsystem API.
201 : *
202 : * @param node_id protocol node identifier
203 : * @param init_fn pointer to protocol's initialization function
204 : * @param api pointer to protocol's subsystem API
205 : * @param pm pointer to the protocol's power management resources
206 : * @param data pointer to protocol's private data
207 : * @param config pointer to protocol's private constant data
208 : * @param level protocol initialization level
209 : * @param prio protocol's priority within its initialization level
210 : */
211 : #define DT_SCMI_PROTOCOL_DEFINE(node_id, init_fn, pm, data, config, \
212 1 : level, prio, api) \
213 : DT_SCMI_TRANSPORT_CHANNELS_DECLARE(node_id) \
214 : DT_SCMI_PROTOCOL_DATA_DEFINE(node_id, DT_REG_ADDR_RAW(node_id), data); \
215 : DEVICE_DT_DEFINE(node_id, init_fn, pm, \
216 : &SCMI_PROTOCOL_NAME(DT_REG_ADDR_RAW(node_id)), \
217 : config, level, prio, api)
218 :
219 : /**
220 : * @brief Just like DT_SCMI_PROTOCOL_DEFINE(), but uses an instance
221 : * of a `DT_DRV_COMPAT` compatible instead of a node identifier
222 : *
223 : * @param inst instance number
224 : * @param init_fn pointer to protocol's initialization function
225 : * @param api pointer to protocol's subsystem API
226 : * @param pm pointer to the protocol's power management resources
227 : * @param data pointer to protocol's private data
228 : * @param config pointer to protocol's private constant data
229 : * @param level protocol initialization level
230 : * @param prio protocol's priority within its initialization level
231 : */
232 : #define DT_INST_SCMI_PROTOCOL_DEFINE(inst, init_fn, pm, data, config, \
233 1 : level, prio, api) \
234 : DT_SCMI_PROTOCOL_DEFINE(DT_INST(inst, DT_DRV_COMPAT), init_fn, pm, \
235 : data, config, level, prio, api)
236 :
237 : /**
238 : * @brief Define an SCMI protocol with no device
239 : *
240 : * Variant of DT_SCMI_PROTOCOL_DEFINE(), but no `struct device` is
241 : * created and no initialization function is called during system
242 : * initialization. This is useful for protocols that are not really
243 : * part of a subsystem with an API (e.g: pinctrl).
244 : *
245 : * @param node_id protocol node identifier
246 : * @param data protocol private data
247 : */
248 1 : #define DT_SCMI_PROTOCOL_DEFINE_NODEV(node_id, data) \
249 : DT_SCMI_TRANSPORT_CHANNELS_DECLARE(node_id) \
250 : DT_SCMI_PROTOCOL_DATA_DEFINE(node_id, DT_REG_ADDR_RAW(node_id), data)
251 :
252 : /**
253 : * @brief Create an SCMI message field
254 : *
255 : * Data might not necessarily be encoded in the first
256 : * x bits of an SCMI message parameter/return value.
257 : * This comes in handy when building said parameters/
258 : * return values.
259 : *
260 : * @param x value to encode
261 : * @param mask value to perform bitwise-and with `x`
262 : * @param shift value to left-shift masked `x`
263 : */
264 1 : #define SCMI_FIELD_MAKE(x, mask, shift)\
265 : (((uint32_t)(x) & (mask)) << (shift))
266 :
267 : /**
268 : * @brief SCMI protocol IDs
269 : *
270 : * Each SCMI protocol is identified by an ID. Each
271 : * of these IDs needs to be in decimal since they
272 : * might be used to build protocol and static channel
273 : * names.
274 : */
275 1 : #define SCMI_PROTOCOL_BASE 16
276 0 : #define SCMI_PROTOCOL_POWER_DOMAIN 17
277 0 : #define SCMI_PROTOCOL_SYSTEM 18
278 0 : #define SCMI_PROTOCOL_PERF 19
279 0 : #define SCMI_PROTOCOL_CLOCK 20
280 0 : #define SCMI_PROTOCOL_SENSOR 21
281 0 : #define SCMI_PROTOCOL_RESET_DOMAIN 22
282 0 : #define SCMI_PROTOCOL_VOLTAGE_DOMAIN 23
283 0 : #define SCMI_PROTOCOL_PCAP_MONITOR 24
284 0 : #define SCMI_PROTOCOL_PINCTRL 25
285 :
286 : #endif /* _INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_SCMI_UTIL_H_ */
|