summaryrefslogtreecommitdiff
path: root/zephyr/shim/include/usbc/usb_muxes.h
blob: 9422d4008d65d5267451d81a67df553aa3835beb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
/* Copyright 2022 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#ifndef ZEPHYR_CHROME_USBC_USB_MUXES_H
#define ZEPHYR_CHROME_USBC_USB_MUXES_H

#include <zephyr/devicetree.h>
#include <zephyr/sys/util_macro.h>
#include "usb_mux.h"
#include "usbc/anx7483_usb_mux.h"
#include "usbc/bb_retimer_usb_mux.h"
#include "usbc/it5205_usb_mux.h"
#include "usbc/tcpci_usb_mux.h"
#include "usbc/tusb1064_usb_mux.h"
#include "usbc/virtual_usb_mux.h"

/**
 * @brief List of USB mux drivers compatibles and their configurations. Each
 *        element of list has to have (compatible, config) format.
 */
#define USB_MUX_DRIVERS						\
	(ANX7483_USB_MUX_COMPAT, USB_MUX_CONFIG_ANX7483),	\
	(BB_RETIMER_USB_MUX_COMPAT, USB_MUX_CONFIG_BB_RETIMER),	\
	(IT5205_USB_MUX_COMPAT, USB_MUX_CONFIG_IT5205),		\
	(PS8XXX_USB_MUX_COMPAT, USB_MUX_CONFIG_TCPCI_TCPM),	\
	(TCPCI_TCPM_USB_MUX_COMPAT, USB_MUX_CONFIG_TCPCI_TCPM),	\
	(TUSB1064_USB_MUX_COMPAT, USB_MUX_CONFIG_TUSB1064),	\
	(VIRTUAL_USB_MUX_COMPAT, USB_MUX_CONFIG_VIRTUAL)

/**
 * @brief Get compatible from @p driver
 *
 * @param driver USB mux driver description in format (compatible, config)
 */
#define USB_MUX_DRIVER_GET_COMPAT(driver)	GET_ARG_N(1, __DEBRACKET driver)

/**
 * @brief Get configuration from @p driver
 *
 * @param driver USB mux driver description in format (compatible, config)
 */
#define USB_MUX_DRIVER_GET_CONFIG(driver)	GET_ARG_N(2, __DEBRACKET driver)

/**
 * @brief USB mux port number based on parent node in DTS
 *
 * @param port_id USBC node ID
 */
#define USB_MUX_PORT(port_id)		DT_REG_ADDR(port_id)

/**
 * @brief Name of USB mux structure if node is not EMPTY. Note, that root of
 *        chain is not referred by this name, but usb_muxes[USB_MUX_PORT(id)].
 *
 * @param mux_id USB mux node ID
 */
#define USB_MUX_STRUCT_NAME(mux_id)					\
	COND_CODE_0(IS_EMPTY(mux_id), (DT_CAT(USB_MUX_NODE_, mux_id)), (EMPTY))

/**
 * @brief USB muxes in chain should be constant only if configuration
 *        cannot change in runtime
 */
#define MAYBE_CONST COND_CODE_1(CONFIG_PLATFORM_EC_USB_MUX_RUNTIME_CONFIG, \
				(), (const))

/**
 * @brief Declaration of USB mux structure
 *
 * @param mux_id USB mux node ID
 */
#define USB_MUX_STRUCT_DECLARE(mux_id)					\
	MAYBE_CONST struct usb_mux USB_MUX_STRUCT_NAME(mux_id)

/**
 * @brief Get pointer by referencing @p name or NULL if @p name is EMPTY
 *
 * @param name Identifier to reference
 */
#define USB_MUX_POINTER_OR_NULL(name)					\
	COND_CODE_0(IS_EMPTY(name), (&name), (NULL))

/**
 * @brief Get node id of @p idx USB mux in chain
 *
 * @param idx Position of USB mux in chain
 * @param port_id USBC node ID
 */
#define USB_MUX_GET_CHAIN_N(idx, port_id)				\
	DT_PHANDLE_BY_IDX(port_id, usb_muxes, idx)

/**
 * @brief Get node id of next USB mux in chain or EMPTY if it is last mux
 *
 * @param port_id USBC node ID
 * @param idx Position of USB mux in chain
 */
#define USB_MUX_NEXT(port_id, idx)					\
	GET_ARG_N(2, GET_ARGS_LESS_N(idx,				\
			LISTIFY(DT_PROP_LEN(port_id, usb_muxes),	\
				USB_MUX_GET_CHAIN_N, (,), port_id)),	\
		  EMPTY)

/**
 * @brief Get pointer to next USB mux in chain or NULL if it is last mux
 *
 * @param port_id USBC node ID
 * @param idx Position of USB mux in chain
 */
#define USB_MUX_NEXT_POINTER(port_id, idx)				\
	USB_MUX_POINTER_OR_NULL(USB_MUX_STRUCT_NAME(USB_MUX_NEXT(port_id, idx)))

/**
 * @brief Generate pointer to function from @p cb_name property or NULL
 *        if property doesn't exist
 *
 * @param mux_id USB mux node ID
 * @param cb_name Name of property with callback function
 */
#define USB_MUX_CALLBACK_OR_NULL(mux_id, cb_name)			\
	USB_MUX_POINTER_OR_NULL(DT_STRING_TOKEN_OR(mux_id, cb_name, EMPTY))

/**
 * @brief Set struct usb_mux fields common for all USB muxes and alter flags
 *
 * @param mux_id USB mux node ID
 * @param port_id USBC node ID
 * @param idx Position of USB mux in chain
 * @param flags_mask Mask for bits that should be igonred in flags property
 * @param flags_val Value that should be used instead for masked bits
 */
#define USB_MUX_COMMON_FIELDS_WITH_FLAGS(mux_id, port_id, idx,		\
					 flags_mask, flags_val)		\
	.usb_port = USB_MUX_PORT(port_id),				\
	.next_mux = USB_MUX_NEXT_POINTER(port_id, idx),			\
	.board_init = USB_MUX_CALLBACK_OR_NULL(mux_id, board_init),	\
	.board_set = USB_MUX_CALLBACK_OR_NULL(mux_id, board_set),	\
	.flags = (DT_PROP(mux_id, flags) & ~(flags_mask)) | (flags_val)

/**
 * @brief Set struct usb_mux fields common for all USB muxes
 *
 * @param mux_id USB mux node ID
 * @param port_id USBC node ID
 * @param idx Position of USB mux in chain
 */
#define USB_MUX_COMMON_FIELDS(mux_id, port_id, idx)			\
	USB_MUX_COMMON_FIELDS_WITH_FLAGS(mux_id, port_id, idx, 0, 0)

/**
 * @brief Expands to 1 if @p mux_id has @p compat compatible. It is required
 *        to makes sure that @p compat is expanded before DT_NODE_HAS_COMPAT
 *
 * @param mux_id USB mux node ID
 * @param compat USB mux driver compatible
 */
#define USB_MUX_IS_COMPATIBLE(mux_id, compat)	\
	DT_NODE_HAS_COMPAT(mux_id, compat)

/**
 * @brief Expands to @p driver config if @p mux_id is compatible with @p driver
 *
 * @param driver USB mux driver description in format (compatible, config)
 * @param mux_id USB mux node ID
 */
#define USB_MUX_DRIVER_CONFIG_IF_COMPAT(driver, mux_id)			\
	COND_CODE_1(USB_MUX_IS_COMPATIBLE(				\
			mux_id, USB_MUX_DRIVER_GET_COMPAT(driver)),	\
		   (USB_MUX_DRIVER_GET_CONFIG(driver)), ())

/**
 * @brief Find driver from USB_MUX_DRIVERS that is compatible with @p mux_id
 *
 * @param mux_id USB mux node ID
 */
#define USB_MUX_FIND_DRIVER_CONFIG(mux_id)				\
	FOR_EACH_FIXED_ARG(USB_MUX_DRIVER_CONFIG_IF_COMPAT, (), mux_id,	\
			   USB_MUX_DRIVERS)

/**
 * @brief Get driver configuration macro for @p mux_id and call @p op
 *
 * @param mux_id USB mux node ID
 * @param port_id USBC node ID
 * @param idx Position of USB mux in chain
 * @param op Operation to perform on USB muxes
 */
#define USB_MUX_CALL_OP(mux_id, port_id, idx, op)			\
	op(mux_id, port_id, idx, USB_MUX_FIND_DRIVER_CONFIG(mux_id))

/**
 * @brief Get USB mux node ID and call USB_MUX_CALL_OP
 *
 * @param port_id USBC node ID
 * @param idx Position of USB mux in chain
 * @param op Operation to perform on USB muxes
 */
#define USB_MUX_DO(port_id, idx, op)					\
	USB_MUX_CALL_OP(USB_MUX_GET_CHAIN_N(idx, port_id), port_id, idx, op)

/**
 * @brief Declare USB mux structure
 *
 * @param mux_id USB mux node ID
 * @param port_id USBC node ID
 * @param idx Position of USB mux in chain
 * @param conf Driver configuration function
 */
#define USB_MUX_DECLARE(mux_id, port_id, idx, conf)			\
	extern USB_MUX_STRUCT_DECLARE(mux_id);

/**
 * @brief Define USB mux structure using driver USB_MUX_CONFIG_* macro
 *
 * @param mux_id USB mux node ID
 * @param port_id USBC node ID
 * @param idx Position of USB mux in chain
 * @param conf Driver configuration function
 */
#define USB_MUX_DEFINE(mux_id, port_id, idx, conf)			\
	USB_MUX_STRUCT_DECLARE(mux_id) = conf(mux_id, port_id, idx);

/**
 * @brief Define entry of usb_muxes array using driver USB_MUX_CONFIG_* macro
 *
 * @param mux_id USB mux node ID
 * @param port_id USBC node ID
 * @param idx Position of USB mux in chain
 * @param conf Driver configuration function
 */
#define USB_MUX_ARRAY(mux_id, port_id, idx, conf)			\
	[USB_MUX_PORT(port_id)] = conf(mux_id, port_id, idx),

/**
 * @brief Call @p op with first mux in chain
 *
 * @param port_id USBC node ID
 * @param op Operation to perform on USB mux first in chain. Needs to accept
 *           USB mux node ID, USBC port node ID, position in chain, and driver
 *           config as arguments.
 */
#define USB_MUX_FIRST(port_id, op)					\
	USB_MUX_DO(port_id, 0, op)

/**
 * @brief Call USB_MUX_DO if @p idx is not 0 (is not first mux in chain)
 *
 * @param port_id USBC node ID
 * @param unused2 This argument is expected by DT_FOREACH_PROP_ELEM_VARGS
 * @param idx Position of USB mux in chain
 * @param op Operation to perform on USB muxes
 */
#define USB_MUX_DO_SKIP_FIRST(port_id, unused2, idx, op)		\
	COND_CODE_1(UTIL_BOOL(idx), (USB_MUX_DO(port_id, idx, op)), ())

/**
 * @brief Call @p op with every mux in chain expect the first one
 *
 * @param port_id USBC node ID
 * @param op Operation to perform on USB muxes. Needs to accept USB mux node
 *           ID, USBC port node ID, position in chain, and driver config as
 *           arguments.
 */
#define USB_MUX_NO_FIRST(port_id, op)					\
	DT_FOREACH_PROP_ELEM_VARGS(port_id, usb_muxes,			\
				   USB_MUX_DO_SKIP_FIRST, op)

/**
 * @brief Call @p op if @p idx mux in chain has BB retimer compatible
 *
 * @param port_id USBC node ID
 * @param unused2 This argument is expected by DT_FOREACH_PROP_ELEM_VARGS
 * @param idx Position of USB mux in chain
 * @param op Operation to perform on BB retimer
 */
#define USB_MUX_ONLY_BB_RETIMER(port_id, unused2, idx, op)		\
	COND_CODE_1(USB_MUX_IS_COMPATIBLE(				\
			USB_MUX_GET_CHAIN_N(idx, port_id),		\
			BB_RETIMER_USB_MUX_COMPAT),			\
			(op(USB_MUX_GET_CHAIN_N(idx, port_id), port_id, \
			    idx, BB_RETIMER_CONTROLS_CONFIG)), ())

/**
 * @brief Call @p op with every BB retimer in chain
 *
 * @param port_id USBC node ID
 * @param op Operation to perform on BB retimers. Needs to accept USB mux node
 *           ID, USBC port node ID, position in chain, and driver config as
 *           arguments.
 */
#define USB_MUX_BB_RETIMERS(port_id, op)				\
	DT_FOREACH_PROP_ELEM_VARGS(port_id, usb_muxes,			\
				   USB_MUX_ONLY_BB_RETIMER, op)

/**
 * @brief If @p port_id has usb_muxes property, call @p op with every mux in
 *        chain that passes @p filter
 *
 * @param port_id USBC node ID
 * @param filter Macro that should filter USB muxes and call @p op on them.
 *               It has @p port_id and @p op as arguments. It is called
 *               only for @p port_id that has usb_muxes property.
 * @param op Operation to perform on USB muxes. Needs to accept USB mux node
 *           ID, USBC port node ID, position in chain, and driver config as
 *           arguments.
 */
#define USB_MUX_USBC_PORT_HAS_MUXES(port_id, filter, op)		\
	COND_CODE_1(DT_NODE_HAS_PROP(port_id, usb_muxes),		\
		    (filter(port_id, op)), ())

/**
 * @brief For every USBC port that has muxes, call @p op with every mux in chain
 *        that passes @p filter
 *
 * @param filter Macro that should filter USB muxes and call @p op on them.
 *               It has USBC port node ID and @p op as arguments. It is called
 *               only for USBC ports that have usb_muxes property.
 * @param op Operation to perform on USB muxes. Needs to accept USB mux node
 *           ID, USBC port node ID, position in chain, and driver config as
 *           arguments.
 */
#define USB_MUX_FOREACH_USBC_PORT(filter, op)				\
	DT_FOREACH_STATUS_OKAY_VARGS(named_usbc_port,			\
				     USB_MUX_USBC_PORT_HAS_MUXES,	\
				     filter, op)

/**
 * Forward declare all usb_mux structures e.g.
 * MAYBE_CONST struct usb_mux USB_MUX_NODE_<node_id>;
 */
USB_MUX_FOREACH_USBC_PORT(USB_MUX_NO_FIRST, USB_MUX_DECLARE)

#endif /* ZEPHYR_CHROME_USBC_USB_MUXES_H */