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