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