1 /*
2  * Copyright (c) 2022 The Chromium OS Authors
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT usb_c_connector
8 
9 #include <zephyr/devicetree.h>
10 #include <zephyr/init.h>
11 #include <zephyr/smf.h>
12 #include <zephyr/usb_c/usbc.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(usbc_stack, CONFIG_USBC_STACK_LOG_LEVEL);
16 
17 #include "usbc_stack.h"
18 #include "usbc_pe_common_internal.h"
19 #include "usbc_tc_common_internal.h"
20 
21 static int usbc_subsys_init(const struct device *dev);
22 
usbc_handler(void * port_dev)23 static ALWAYS_INLINE void usbc_handler(void *port_dev)
24 {
25 	const struct device *dev = (const struct device *)port_dev;
26 	struct usbc_port_data *port = dev->data;
27 	struct request_value *req;
28 	int32_t request;
29 
30 	req = k_fifo_get(&port->request_fifo, K_NO_WAIT);
31 	request = (req != NULL) ? req->val : REQUEST_NOP;
32 	pe_run(dev, request);
33 	prl_run(dev);
34 	tc_run(dev, request);
35 
36 	if (request == PRIV_PORT_REQUEST_SUSPEND) {
37 		k_thread_suspend(port->port_thread);
38 	}
39 
40 	/* Check if there wasn't any request to do a one more iteration of USB-C state machines */
41 	if (!port->bypass_next_sleep) {
42 		k_msleep(CONFIG_USBC_STATE_MACHINE_CYCLE_TIME);
43 	} else {
44 		port->bypass_next_sleep = false;
45 	}
46 }
47 
48 /* format makes the backslashes exceed 100 lines: */
49 /* clang-format off */
50 #define USBC_SUBSYS_INIT(inst)                                                                     \
51 	K_THREAD_STACK_DEFINE(my_stack_area_##inst, CONFIG_USBC_STACK_SIZE);                       \
52                                                                                                    \
53 	static struct tc_sm_t tc_##inst;                                                           \
54 	static struct policy_engine pe_##inst;                                                     \
55 	static struct protocol_layer_rx_t prl_rx_##inst;                                           \
56 	static struct protocol_layer_tx_t prl_tx_##inst;                                           \
57 	static struct protocol_hard_reset_t prl_hr_##inst;                                         \
58                                                                                                    \
59 	static void run_usbc_##inst(void *port_dev, void *unused1, void *unused2)                  \
60 	{                                                                                          \
61 		while (1) {                                                                        \
62 			usbc_handler(port_dev);                                                    \
63 		}                                                                                  \
64 	}                                                                                          \
65                                                                                                    \
66 	static void create_thread_##inst(const struct device *dev)                                 \
67 	{                                                                                          \
68 		struct usbc_port_data *port = dev->data;                                           \
69                                                                                                    \
70 		port->port_thread = k_thread_create(                                               \
71 			&port->thread_data, my_stack_area_##inst,                                  \
72 			K_THREAD_STACK_SIZEOF(my_stack_area_##inst), run_usbc_##inst, (void *)dev, \
73 			0, 0, CONFIG_USBC_THREAD_PRIORITY, K_ESSENTIAL, K_NO_WAIT);                \
74 		k_thread_suspend(port->port_thread);                                               \
75 	}                                                                                          \
76                                                                                                    \
77 	static struct usbc_port_data usbc_port_data_##inst = {                                     \
78 		.tc = &tc_##inst,                                                                  \
79 		.pe = &pe_##inst,                                                                  \
80 		.prl_rx = &prl_rx_##inst,                                                          \
81 		.prl_tx = &prl_tx_##inst,                                                          \
82 		.prl_hr = &prl_hr_##inst,                                                          \
83 		.tcpc = DEVICE_DT_GET(DT_INST_PROP(inst, tcpc)),                                   \
84 		.vbus = DEVICE_DT_GET(DT_INST_PROP(inst, vbus)),                                   \
85 		.ppc = COND_CODE_1(DT_INST_NODE_HAS_PROP(inst, ppc),                               \
86 				   (DEVICE_DT_GET(DT_INST_PROP(inst, ppc))), (NULL)),              \
87 	};                                                                                         \
88                                                                                                    \
89 	static const struct usbc_port_config usbc_port_config_##inst = {                           \
90 		.create_thread = create_thread_##inst,                                             \
91 	};                                                                                         \
92                                                                                                    \
93 	DEVICE_DT_INST_DEFINE(inst, &usbc_subsys_init, NULL, &usbc_port_data_##inst,               \
94 			      &usbc_port_config_##inst, POST_KERNEL,                               \
95 			      CONFIG_USBC_STACK_INIT_PRIORITY, NULL);
96 /* clang-format on */
DT_INST_FOREACH_STATUS_OKAY(USBC_SUBSYS_INIT)97 DT_INST_FOREACH_STATUS_OKAY(USBC_SUBSYS_INIT)
98 
99 /**
100  * @brief Called by the Device Policy Manager to start the USB-C Subsystem
101  */
102 int usbc_start(const struct device *dev)
103 {
104 	struct usbc_port_data *data = dev->data;
105 
106 	/* Add private start request to fifo */
107 	data->request.val = PRIV_PORT_REQUEST_START;
108 	k_fifo_put(&data->request_fifo, &data->request);
109 
110 	/* Start the port thread */
111 	k_thread_resume(data->port_thread);
112 
113 	return 0;
114 }
115 
116 /**
117  * @brief Called by the Device Policy Manager to suspend the USB-C Subsystem
118  */
usbc_suspend(const struct device * dev)119 int usbc_suspend(const struct device *dev)
120 {
121 	struct usbc_port_data *data = dev->data;
122 
123 	/* Add private suspend request to fifo */
124 	data->request.val = PRIV_PORT_REQUEST_SUSPEND;
125 	k_fifo_put(&data->request_fifo, &data->request);
126 
127 	return 0;
128 }
129 
130 /**
131  * @brief Called by the Device Policy Manager to make a request of the
132  *	  USB-C Subsystem
133  */
usbc_request(const struct device * dev,const enum usbc_policy_request_t req)134 int usbc_request(const struct device *dev, const enum usbc_policy_request_t req)
135 {
136 	struct usbc_port_data *data = dev->data;
137 
138 	/* Add public request to fifo */
139 	data->request.val = req;
140 	k_fifo_put(&data->request_fifo, &data->request);
141 
142 	return 0;
143 }
144 
usbc_bypass_next_sleep(const struct device * dev)145 void usbc_bypass_next_sleep(const struct device *dev)
146 {
147 	struct usbc_port_data *data = dev->data;
148 
149 	data->bypass_next_sleep = true;
150 }
151 
152 /**
153  * @brief Sets the Device Policy Manager's data
154  */
usbc_set_dpm_data(const struct device * dev,void * dpm_data)155 void usbc_set_dpm_data(const struct device *dev, void *dpm_data)
156 {
157 	struct usbc_port_data *data = dev->data;
158 
159 	data->dpm_data = dpm_data;
160 }
161 
162 /**
163  * @brief Gets the Device Policy Manager's data
164  */
usbc_get_dpm_data(const struct device * dev)165 void *usbc_get_dpm_data(const struct device *dev)
166 {
167 	struct usbc_port_data *data = dev->data;
168 
169 	return data->dpm_data;
170 }
171 
172 #ifdef CONFIG_USBC_CSM_SINK_ONLY
173 /**
174  * @brief Set the callback that gets the Sink Capabilities from the
175  *	  Device Policy Manager
176  */
usbc_set_policy_cb_get_snk_cap(const struct device * dev,const policy_cb_get_snk_cap_t policy_cb_get_snk_cap)177 void usbc_set_policy_cb_get_snk_cap(const struct device *dev,
178 				    const policy_cb_get_snk_cap_t policy_cb_get_snk_cap)
179 {
180 	struct usbc_port_data *data = dev->data;
181 
182 	data->policy_cb_get_snk_cap = policy_cb_get_snk_cap;
183 }
184 
185 /**
186  * @brief Set the callback that sends the received Source Capabilities to the
187  *	  Device Policy Manager
188  */
usbc_set_policy_cb_set_src_cap(const struct device * dev,const policy_cb_set_src_cap_t policy_cb_set_src_cap)189 void usbc_set_policy_cb_set_src_cap(const struct device *dev,
190 				    const policy_cb_set_src_cap_t policy_cb_set_src_cap)
191 {
192 	struct usbc_port_data *data = dev->data;
193 
194 	data->policy_cb_set_src_cap = policy_cb_set_src_cap;
195 }
196 
197 /**
198  * @brief Set the callback for requesting the data object (RDO)
199  */
usbc_set_policy_cb_get_rdo(const struct device * dev,const policy_cb_get_rdo_t policy_cb_get_rdo)200 void usbc_set_policy_cb_get_rdo(const struct device *dev,
201 				const policy_cb_get_rdo_t policy_cb_get_rdo)
202 {
203 	struct usbc_port_data *data = dev->data;
204 
205 	data->policy_cb_get_rdo = policy_cb_get_rdo;
206 }
207 
208 /**
209  * @brief Set the callback for checking if Sink Power Supply is at
210  *	  default level
211  */
usbc_set_policy_cb_is_snk_at_default(const struct device * dev,const policy_cb_is_snk_at_default_t policy_cb_is_snk_at_default)212 void usbc_set_policy_cb_is_snk_at_default(
213 	const struct device *dev, const policy_cb_is_snk_at_default_t policy_cb_is_snk_at_default)
214 {
215 	struct usbc_port_data *data = dev->data;
216 
217 	data->policy_cb_is_snk_at_default = policy_cb_is_snk_at_default;
218 }
219 
220 #else /* CONFIG_USBC_CSM_SOURCE_ONLY */
221 
222 /**
223  * @brief Set the callback for sending the Sink Caps to the DPM
224  */
usbc_set_policy_cb_set_port_partner_snk_cap(const struct device * dev,const policy_cb_set_port_partner_snk_cap_t cb)225 void usbc_set_policy_cb_set_port_partner_snk_cap(const struct device *dev,
226 						 const policy_cb_set_port_partner_snk_cap_t cb)
227 {
228 	struct usbc_port_data *data = dev->data;
229 
230 	data->policy_cb_set_port_partner_snk_cap = cb;
231 }
232 
233 /**
234  * @brief Set the callback that gets the Source Capabilities from the
235  *        Device Policy Manager
236  */
usbc_set_policy_cb_get_src_caps(const struct device * dev,const policy_cb_get_src_caps_t cb)237 void usbc_set_policy_cb_get_src_caps(const struct device *dev, const policy_cb_get_src_caps_t cb)
238 {
239 	struct usbc_port_data *data = dev->data;
240 
241 	data->policy_cb_get_src_caps = cb;
242 }
243 
244 /**
245  * @brief Set the callback that gets the Source Rp value from the
246  *        Device Policy Manager
247  */
usbc_set_policy_cb_get_src_rp(const struct device * dev,const policy_cb_get_src_rp_t policy_cb_get_src_rp)248 void usbc_set_policy_cb_get_src_rp(const struct device *dev,
249 				   const policy_cb_get_src_rp_t policy_cb_get_src_rp)
250 {
251 	struct usbc_port_data *data = dev->data;
252 
253 	data->policy_cb_get_src_rp = policy_cb_get_src_rp;
254 }
255 
256 /**
257  * @brief Set the callback that controls the sourcing of VBUS from the
258  *        Device Policy Manager
259  */
usbc_set_policy_cb_src_en(const struct device * dev,const policy_cb_src_en_t policy_cb_src_en)260 void usbc_set_policy_cb_src_en(const struct device *dev, const policy_cb_src_en_t policy_cb_src_en)
261 {
262 	struct usbc_port_data *data = dev->data;
263 
264 	data->policy_cb_src_en = policy_cb_src_en;
265 }
266 
267 /**
268  * @brief Set the callback for checking if a Sink Request is valid
269  */
usbc_set_policy_cb_check_sink_request(const struct device * dev,const policy_cb_check_sink_request_t cb)270 void usbc_set_policy_cb_check_sink_request(const struct device *dev,
271 					   const policy_cb_check_sink_request_t cb)
272 {
273 	struct usbc_port_data *data = dev->data;
274 
275 	data->policy_cb_check_sink_request = cb;
276 }
277 
278 /**
279  * @brief Set the callback for checking if the Source Power Supply is ready
280  */
usbc_set_policy_cb_is_ps_ready(const struct device * dev,const policy_cb_is_ps_ready_t cb)281 void usbc_set_policy_cb_is_ps_ready(const struct device *dev, const policy_cb_is_ps_ready_t cb)
282 {
283 	struct usbc_port_data *data = dev->data;
284 
285 	data->policy_is_ps_ready = cb;
286 }
287 
288 /**
289  * @brief Set the callback for checking if the Present Contract is still valid
290  */
usbc_set_policy_cb_present_contract_is_valid(const struct device * dev,const policy_cb_present_contract_is_valid_t cb)291 void usbc_set_policy_cb_present_contract_is_valid(const struct device *dev,
292 						  const policy_cb_present_contract_is_valid_t cb)
293 {
294 	struct usbc_port_data *data = dev->data;
295 
296 	data->policy_present_contract_is_valid = cb;
297 }
298 
299 /**
300  * @brief Set the callback that requests the use of a new set of Sources Caps if
301  *	  they're available
302  */
usbc_set_policy_cb_change_src_caps(const struct device * dev,const policy_cb_change_src_caps_t cb)303 void usbc_set_policy_cb_change_src_caps(const struct device *dev,
304 					const policy_cb_change_src_caps_t cb)
305 {
306 	struct usbc_port_data *data = dev->data;
307 
308 	data->policy_change_src_caps = cb;
309 }
310 
311 /**
312  * @brief Set the callback that controls the sourcing of VCONN from the
313  *        Device Policy Manager
314  */
usbc_set_vconn_control_cb(const struct device * dev,const tcpc_vconn_control_cb_t cb)315 void usbc_set_vconn_control_cb(const struct device *dev, const tcpc_vconn_control_cb_t cb)
316 {
317 	struct usbc_port_data *data = dev->data;
318 	const struct device *tcpc = data->tcpc;
319 
320 	tcpc_set_vconn_cb(tcpc, cb);
321 }
322 
323 /**
324  * @brief Set the callback that discharges VCONN from the
325  *        Device Policy Manager
326  */
usbc_set_vconn_discharge(const struct device * dev,const tcpc_vconn_discharge_cb_t cb)327 void usbc_set_vconn_discharge(const struct device *dev, const tcpc_vconn_discharge_cb_t cb)
328 {
329 	struct usbc_port_data *data = dev->data;
330 	const struct device *tcpc = data->tcpc;
331 
332 	tcpc_set_vconn_discharge_cb(tcpc, cb);
333 }
334 
335 #endif /* CONFIG_USBC_CSM_SINK_ONLY */
336 
337 /**
338  * @brief Set the callback for the Device Policy Manager policy check
339  */
usbc_set_policy_cb_check(const struct device * dev,const policy_cb_check_t policy_cb_check)340 void usbc_set_policy_cb_check(const struct device *dev, const policy_cb_check_t policy_cb_check)
341 {
342 	struct usbc_port_data *data = dev->data;
343 
344 	data->policy_cb_check = policy_cb_check;
345 }
346 
347 /**
348  * @brief Set the callback for the Device Policy Manager policy change notify
349  */
usbc_set_policy_cb_notify(const struct device * dev,const policy_cb_notify_t policy_cb_notify)350 void usbc_set_policy_cb_notify(const struct device *dev, const policy_cb_notify_t policy_cb_notify)
351 {
352 	struct usbc_port_data *data = dev->data;
353 
354 	data->policy_cb_notify = policy_cb_notify;
355 }
356 
357 /**
358  * @brief Set the callback for the Device Policy Manager policy change notify
359  */
usbc_set_policy_cb_wait_notify(const struct device * dev,const policy_cb_wait_notify_t policy_cb_wait_notify)360 void usbc_set_policy_cb_wait_notify(const struct device *dev,
361 				    const policy_cb_wait_notify_t policy_cb_wait_notify)
362 {
363 	struct usbc_port_data *data = dev->data;
364 
365 	data->policy_cb_wait_notify = policy_cb_wait_notify;
366 }
367 
368 /**
369  * @brief Initialize the USB-C Subsystem
370  */
usbc_subsys_init(const struct device * dev)371 static int usbc_subsys_init(const struct device *dev)
372 {
373 	struct usbc_port_data *data = dev->data;
374 	const struct usbc_port_config *const config = dev->config;
375 	const struct device *tcpc = data->tcpc;
376 
377 	/* Make sure TCPC is ready */
378 	if (!device_is_ready(tcpc)) {
379 		LOG_ERR("TCPC NOT READY");
380 		return -ENODEV;
381 	}
382 
383 	/* Initialize the state machines */
384 	tc_subsys_init(dev);
385 	pe_subsys_init(dev);
386 	prl_subsys_init(dev);
387 
388 	/* Initialize the request fifo */
389 	k_fifo_init(&data->request_fifo);
390 
391 	/* Create the thread for this port */
392 	config->create_thread(dev);
393 	return 0;
394 }
395