1 /*
2  * Copyright (c) 2023 Nuvoton Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nuvoton_numaker_usbd
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/usb/usb_device.h>
11 #include <zephyr/dt-bindings/usb/usb.h>
12 #include <zephyr/sys/math_extras.h>
13 #include <zephyr/drivers/clock_control.h>
14 #include <zephyr/drivers/clock_control/clock_control_numaker.h>
15 #include <zephyr/drivers/reset.h>
16 #include <zephyr/drivers/pinctrl.h>
17 
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(usb_dc_numaker, CONFIG_USB_DRIVER_LOG_LEVEL);
20 
21 #include <soc.h>
22 #include <NuMicro.h>
23 
24 /* USBD notes
25  *
26  * 1. Require 48MHz clock source
27  *    (1) Not support HIRC48 as clock source. It involves trim with USB SOF packets
28  *        and isn't suitable in HAL.
29  *    (2) Instead of HICR48, core clock is required to be multiple of 48MHz e.g. 192MHz,
30  *        to generate necessary 48MHz.
31  */
32 
33 /* For bus reset, keep 'SE0' (USB spec: SE0 >= 2.5 ms) */
34 #define NUMAKER_USBD_BUS_RESET_DRV_SE0_US 3000
35 
36 /* For bus resume, generate 'K' (USB spec: 'K' >= 1 ms) */
37 #define NUMAKER_USBD_BUS_RESUME_DRV_K_US 1500
38 
39 /* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, required to be 8-byte aligned */
40 #define NUMAKER_USBD_DMABUF_SIZE_SETUP   8
41 #define NUMAKER_USBD_DMABUF_SIZE_CTRLOUT 64
42 #define NUMAKER_USBD_DMABUF_SIZE_CTRLIN  64
43 
44 /* Maximum number of EP contexts across all instances
45  * This is to static-allocate EP contexts which can accommodate all instances.
46  * The number of effective EP contexts per instance is passed on through its
47  * num_bidir_endpoints, which must not be larger than this.
48  */
49 #define NUMAKER_USBD_EP_MAXNUM 25ul
50 
51 /* Message type */
52 #define NUMAKER_USBD_MSG_TYPE_SW_RECONN 0 /* S/W reconnect */
53 #define NUMAKER_USBD_MSG_TYPE_CB_STATE  1 /* Callback for usb_dc_status_code */
54 #define NUMAKER_USBD_MSG_TYPE_CB_EP     2 /* Callback for usb_dc_ep_cb_status_code */
55 
56 /* Message structure */
57 struct numaker_usbd_msg {
58 	uint32_t type;
59 	union {
60 		struct {
61 			enum usb_dc_status_code status_code;
62 		} cb_device;
63 		struct {
64 			uint8_t ep;
65 			enum usb_dc_ep_cb_status_code status_code;
66 		} cb_ep;
67 	};
68 };
69 
70 /* Immutable device context */
71 struct numaker_usbd_config {
72 	USBD_T *base;
73 	const struct reset_dt_spec reset;
74 	uint32_t clk_modidx;
75 	uint32_t clk_src;
76 	uint32_t clk_div;
77 	const struct device *clkctrl_dev;
78 	void (*irq_config_func)(const struct device *dev);
79 	void (*irq_unconfig_func)(const struct device *dev);
80 	const struct pinctrl_dev_config *pincfg;
81 	uint32_t num_bidir_endpoints;
82 	uint32_t dmabuf_size;
83 	bool disallow_iso_inout_same;
84 };
85 
86 /* EP context */
87 struct numaker_usbd_ep {
88 	bool valid;
89 
90 	bool nak_clr; /* NAK cleared (ACK next transaction) */
91 
92 	const struct device *dev; /* Pointer to the containing device */
93 
94 	uint8_t ep_hw_idx;  /* BSP USBD driver EP index EP0, EP1, EP2, etc */
95 	uint32_t ep_hw_cfg; /* BSP USBD driver EP configuration */
96 
97 	/* EP DMA buffer */
98 	bool dmabuf_valid;
99 	uint32_t dmabuf_base;
100 	uint32_t dmabuf_size;
101 
102 	/* On USBD, no H/W FIFO. Simulate based on above DMA buffer with
103 	 * one-shot implementation
104 	 */
105 	uint32_t read_fifo_pos;
106 	uint32_t read_fifo_used;
107 	uint32_t write_fifo_pos;
108 	uint32_t write_fifo_free;
109 
110 	/* NOTE: On USBD, Setup and CTRL OUT are not completely separated. CTRL OUT MXPLD
111 	 * can be overridden to 8 by next Setup. To overcome it, we make one copy of CTRL
112 	 * OUT MXPLD immediately on its interrupt.
113 	 */
114 	uint32_t mxpld_ctrlout;
115 
116 	/* EP address */
117 	bool addr_valid;
118 	uint8_t addr;
119 
120 	/* EP MPS */
121 	bool mps_valid;
122 	uint16_t mps;
123 
124 	usb_dc_ep_callback cb; /* EP callback function */
125 };
126 
127 /* EP context manager */
128 struct numaker_usbd_ep_mgmt {
129 	/* EP context management
130 	 *
131 	 * Allocate-only, and de-allocate all on re-initialize in usb_dc_attach().
132 	 */
133 	uint8_t ep_idx;
134 
135 	/* DMA buffer management
136 	 *
137 	 * Allocate-only, and de-allocate all on re-initialize in usb_dc_attach().
138 	 */
139 	uint32_t dmabuf_pos;
140 
141 	/* Pass Setup packet from ISR to thread */
142 	bool new_setup;
143 	struct usb_setup_packet setup_packet;
144 
145 	struct numaker_usbd_ep ep_pool[NUMAKER_USBD_EP_MAXNUM];
146 };
147 
148 /* Mutable device context */
149 struct numaker_usbd_data {
150 	uint8_t addr; /* Host assigned USB device address */
151 
152 	struct k_mutex sync_mutex;
153 
154 	/* Enable interrupt top/bottom halves processing
155 	 *
156 	 * Registered callbacks may use mutex or other kernel functions which are not supported
157 	 * in interrupt context
158 	 */
159 	struct k_msgq msgq;
160 	struct numaker_usbd_msg msgq_buf[CONFIG_USB_DC_NUMAKER_MSG_QUEUE_SIZE];
161 
162 	K_KERNEL_STACK_MEMBER(msg_hdlr_thread_stack,
163 			      CONFIG_USB_DC_NUMAKER_MSG_HANDLER_THREAD_STACK_SIZE);
164 	struct k_thread msg_hdlr_thread;
165 
166 	usb_dc_status_callback status_cb; /* Status callback function */
167 
168 	struct numaker_usbd_ep_mgmt ep_mgmt; /* EP management */
169 };
170 
171 static inline const struct device *numaker_usbd_device_get(void);
172 
numaker_usbd_lock(const struct device * dev)173 static inline void numaker_usbd_lock(const struct device *dev)
174 {
175 	struct numaker_usbd_data *data = dev->data;
176 
177 	k_mutex_lock(&data->sync_mutex, K_FOREVER);
178 }
179 
numaker_usbd_unlock(const struct device * dev)180 static inline void numaker_usbd_unlock(const struct device *dev)
181 {
182 	struct numaker_usbd_data *data = dev->data;
183 
184 	k_mutex_unlock(&data->sync_mutex);
185 }
186 
numaker_usbd_sw_connect(const struct device * dev)187 static inline void numaker_usbd_sw_connect(const struct device *dev)
188 {
189 	const struct numaker_usbd_config *config = dev->config;
190 	USBD_T *const base = config->base;
191 
192 	/* Clear all interrupts first for clean */
193 	base->INTSTS = base->INTSTS;
194 
195 	/* Enable relevant interrupts */
196 	base->INTEN = USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP | USBD_INT_SOF;
197 
198 	/* Clear SE0 for connect */
199 	base->SE0 &= ~USBD_DRVSE0;
200 }
201 
numaker_usbd_sw_disconnect(const struct device * dev)202 static inline void numaker_usbd_sw_disconnect(const struct device *dev)
203 {
204 	const struct numaker_usbd_config *config = dev->config;
205 	USBD_T *const base = config->base;
206 
207 	/* Set SE0 for disconnect */
208 	base->SE0 |= USBD_DRVSE0;
209 }
210 
numaker_usbd_sw_reconnect(const struct device * dev)211 static inline void numaker_usbd_sw_reconnect(const struct device *dev)
212 {
213 	/* Keep SE0 to trigger bus reset */
214 	numaker_usbd_sw_disconnect(dev);
215 	k_sleep(K_USEC(NUMAKER_USBD_BUS_RESET_DRV_SE0_US));
216 	numaker_usbd_sw_connect(dev);
217 }
218 
numaker_usbd_reset_addr(const struct device * dev)219 static inline void numaker_usbd_reset_addr(const struct device *dev)
220 {
221 	const struct numaker_usbd_config *config = dev->config;
222 	struct numaker_usbd_data *data = dev->data;
223 	USBD_T *const base = config->base;
224 
225 	base->FADDR = 0;
226 	data->addr = 0;
227 }
228 
numaker_usbd_set_addr(const struct device * dev)229 static inline void numaker_usbd_set_addr(const struct device *dev)
230 {
231 	const struct numaker_usbd_config *config = dev->config;
232 	struct numaker_usbd_data *data = dev->data;
233 	USBD_T *const base = config->base;
234 
235 	if (base->FADDR != data->addr) {
236 		base->FADDR = data->addr;
237 	}
238 }
239 
240 /* USBD EP base by e.g. EP0, EP1, ... */
numaker_usbd_ep_base(const struct device * dev,uint32_t ep_hw_idx)241 static inline USBD_EP_T *numaker_usbd_ep_base(const struct device *dev, uint32_t ep_hw_idx)
242 {
243 	const struct numaker_usbd_config *config = dev->config;
244 	USBD_T *const base = config->base;
245 
246 	return base->EP + ep_hw_idx;
247 }
248 
numaker_usbd_ep_fifo_max(struct numaker_usbd_ep * ep_cur)249 static inline uint32_t numaker_usbd_ep_fifo_max(struct numaker_usbd_ep *ep_cur)
250 {
251 	/* NOTE: For one-shot implementation, effective size of EP FIFO is limited to EP MPS */
252 	__ASSERT_NO_MSG(ep_cur->dmabuf_valid);
253 	__ASSERT_NO_MSG(ep_cur->mps_valid);
254 	__ASSERT_NO_MSG(ep_cur->mps <= ep_cur->dmabuf_size);
255 	return ep_cur->mps;
256 }
257 
numaker_usbd_ep_fifo_used(struct numaker_usbd_ep * ep_cur)258 static inline uint32_t numaker_usbd_ep_fifo_used(struct numaker_usbd_ep *ep_cur)
259 {
260 	__ASSERT_NO_MSG(ep_cur->dmabuf_valid);
261 
262 	return USB_EP_DIR_IS_OUT(ep_cur->addr)
263 		       ? ep_cur->read_fifo_used
264 		       : numaker_usbd_ep_fifo_max(ep_cur) - ep_cur->write_fifo_free;
265 }
266 
267 /* Reset EP FIFO
268  *
269  * NOTE: EP FIFO is based on EP DMA buffer, which may not be configured yet.
270  */
numaker_usbd_ep_fifo_reset(struct numaker_usbd_ep * ep_cur)271 static void numaker_usbd_ep_fifo_reset(struct numaker_usbd_ep *ep_cur)
272 {
273 	if (ep_cur->dmabuf_valid && ep_cur->mps_valid) {
274 		if (USB_EP_DIR_IS_OUT(ep_cur->addr)) {
275 			/* Read FIFO */
276 			ep_cur->read_fifo_pos = ep_cur->dmabuf_base;
277 			ep_cur->read_fifo_used = 0;
278 		} else {
279 			/* Write FIFO */
280 			ep_cur->write_fifo_pos = ep_cur->dmabuf_base;
281 			ep_cur->write_fifo_free = numaker_usbd_ep_fifo_max(ep_cur);
282 		}
283 	}
284 }
285 
numaker_usbd_ep_set_stall(struct numaker_usbd_ep * ep_cur)286 static inline void numaker_usbd_ep_set_stall(struct numaker_usbd_ep *ep_cur)
287 {
288 	const struct device *dev = ep_cur->dev;
289 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
290 
291 	/* Set EP to stalled */
292 	ep_base->CFGP |= USBD_CFGP_SSTALL_Msk;
293 }
294 
295 /* Reset EP to unstalled and data toggle bit to 0 */
numaker_usbd_ep_clear_stall_n_data_toggle(struct numaker_usbd_ep * ep_cur)296 static inline void numaker_usbd_ep_clear_stall_n_data_toggle(struct numaker_usbd_ep *ep_cur)
297 {
298 	const struct device *dev = ep_cur->dev;
299 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
300 
301 	/* Reset EP to unstalled */
302 	ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk;
303 
304 	/* Reset EP data toggle bit to 0 */
305 	ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk;
306 }
307 
numaker_usbd_ep_is_stalled(struct numaker_usbd_ep * ep_cur)308 static inline bool numaker_usbd_ep_is_stalled(struct numaker_usbd_ep *ep_cur)
309 {
310 	const struct device *dev = ep_cur->dev;
311 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
312 
313 	return ep_base->CFGP & USBD_CFGP_SSTALL_Msk;
314 }
315 
numaker_usbd_send_msg(const struct device * dev,const struct numaker_usbd_msg * msg)316 static int numaker_usbd_send_msg(const struct device *dev, const struct numaker_usbd_msg *msg)
317 {
318 	struct numaker_usbd_data *data = dev->data;
319 	int rc;
320 
321 	rc = k_msgq_put(&data->msgq, msg, K_NO_WAIT);
322 	if (rc < 0) {
323 		/* Try to recover by S/W reconnect */
324 		struct numaker_usbd_msg msg_reconn = {
325 			.type = NUMAKER_USBD_MSG_TYPE_SW_RECONN,
326 		};
327 
328 		LOG_ERR("Message queue overflow");
329 
330 		/* Discard all not yet received messages for error recovery below */
331 		k_msgq_purge(&data->msgq);
332 
333 		rc = k_msgq_put(&data->msgq, &msg_reconn, K_NO_WAIT);
334 		if (rc < 0) {
335 			LOG_ERR("Message queue overflow again");
336 		}
337 	}
338 
339 	return rc;
340 }
341 
numaker_usbd_hw_setup(const struct device * dev)342 static int numaker_usbd_hw_setup(const struct device *dev)
343 {
344 	const struct numaker_usbd_config *config = dev->config;
345 	USBD_T *const base = config->base;
346 	int rc;
347 	struct numaker_scc_subsys scc_subsys;
348 
349 	/* Reset controller ready? */
350 	if (!device_is_ready(config->reset.dev)) {
351 		LOG_ERR("Reset controller not ready");
352 		return -ENODEV;
353 	}
354 
355 	SYS_UnlockReg();
356 
357 	/* Configure USB PHY for USBD */
358 	SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_USBROLE_Msk) |
359 		      (SYS_USBPHY_USBROLE_STD_USBD | SYS_USBPHY_USBEN_Msk | SYS_USBPHY_SBO_Msk);
360 
361 	/* Invoke Clock controller to enable module clock */
362 	memset(&scc_subsys, 0x00, sizeof(scc_subsys));
363 	scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC;
364 	scc_subsys.pcc.clk_modidx = config->clk_modidx;
365 	scc_subsys.pcc.clk_src = config->clk_src;
366 	scc_subsys.pcc.clk_div = config->clk_div;
367 
368 	/* Equivalent to CLK_EnableModuleClock() */
369 	rc = clock_control_on(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys);
370 	if (rc < 0) {
371 		goto cleanup;
372 	}
373 	/* Equivalent to CLK_SetModuleClock() */
374 	rc = clock_control_configure(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys,
375 				     NULL);
376 	if (rc < 0) {
377 		goto cleanup;
378 	}
379 
380 	/* Configure pinmux (NuMaker's SYS MFP) */
381 	rc = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
382 	if (rc < 0) {
383 		goto cleanup;
384 	}
385 
386 	/* Invoke Reset controller to reset module to default state */
387 	/* Equivalent to SYS_ResetModule()
388 	 */
389 	reset_line_toggle_dt(&config->reset);
390 
391 	/* Initialize USBD engine */
392 	/* NOTE: BSP USBD driver: ATTR = 0x7D0 */
393 	base->ATTR = USBD_ATTR_BYTEM_Msk | BIT(9) | USBD_ATTR_DPPUEN_Msk | USBD_ATTR_USBEN_Msk |
394 		     BIT(6) | USBD_ATTR_PHYEN_Msk;
395 
396 	/* Set SE0 for S/W disconnect */
397 	numaker_usbd_sw_disconnect(dev);
398 
399 	/* NOTE: Ignore DT maximum-speed with USBD fixed to full-speed */
400 
401 	/* Initialize IRQ */
402 	config->irq_config_func(dev);
403 
404 cleanup:
405 
406 	SYS_LockReg();
407 
408 	return rc;
409 }
410 
numaker_usbd_hw_shutdown(const struct device * dev)411 static void numaker_usbd_hw_shutdown(const struct device *dev)
412 {
413 	const struct numaker_usbd_config *config = dev->config;
414 	USBD_T *const base = config->base;
415 	struct numaker_scc_subsys scc_subsys;
416 
417 	SYS_UnlockReg();
418 
419 	/* Uninitialize IRQ */
420 	config->irq_unconfig_func(dev);
421 
422 	/* Set SE0 for S/W disconnect */
423 	numaker_usbd_sw_disconnect(dev);
424 
425 	/* Disable USB PHY */
426 	base->ATTR &= ~USBD_PHY_EN;
427 
428 	/* Invoke Clock controller to disable module clock */
429 	memset(&scc_subsys, 0x00, sizeof(scc_subsys));
430 	scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC;
431 	scc_subsys.pcc.clk_modidx = config->clk_modidx;
432 
433 	/* Equivalent to CLK_DisableModuleClock() */
434 	clock_control_off(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys);
435 
436 	/* Invoke Reset controller to reset module to default state */
437 	/* Equivalent to SYS_ResetModule() */
438 	reset_line_toggle_dt(&config->reset);
439 
440 	SYS_LockReg();
441 }
442 
443 /* Interrupt top half processing for bus reset */
numaker_usbd_bus_reset_th(const struct device * dev)444 static void numaker_usbd_bus_reset_th(const struct device *dev)
445 {
446 	const struct numaker_usbd_config *config = dev->config;
447 	USBD_EP_T *ep_base;
448 
449 	for (uint32_t i = 0ul; i < config->num_bidir_endpoints; i++) {
450 		ep_base = numaker_usbd_ep_base(dev, EP0 + i);
451 
452 		/* Cancel EP on-going transaction */
453 		ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk;
454 
455 		/* Reset EP to unstalled */
456 		ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk;
457 
458 		/* Reset EP data toggle bit to 0 */
459 		ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk;
460 
461 		/* Except EP0/EP1 kept resident for CTRL OUT/IN, disable all other EPs */
462 		if (i >= 2) {
463 			ep_base->CFG = 0;
464 		}
465 	}
466 
467 	numaker_usbd_reset_addr(dev);
468 }
469 
numaker_usbd_remote_wakeup(const struct device * dev)470 static void numaker_usbd_remote_wakeup(const struct device *dev)
471 {
472 	const struct numaker_usbd_config *config = dev->config;
473 	USBD_T *const base = config->base;
474 
475 	/* Enable back USB/PHY first */
476 	base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
477 
478 	/* Then generate 'K' */
479 	base->ATTR |= USBD_ATTR_RWAKEUP_Msk;
480 	k_sleep(K_USEC(NUMAKER_USBD_BUS_RESUME_DRV_K_US));
481 	base->ATTR ^= USBD_ATTR_RWAKEUP_Msk;
482 }
483 
484 /* USBD SRAM base for DMA */
numaker_usbd_buf_base(const struct device * dev)485 static inline uint32_t numaker_usbd_buf_base(const struct device *dev)
486 {
487 	const struct numaker_usbd_config *config = dev->config;
488 	USBD_T *const base = config->base;
489 
490 	return ((uint32_t)base + 0x800ul);
491 }
492 
493 /* Copy to user buffer from Setup FIFO */
numaker_usbd_setup_fifo_copy_to_user(const struct device * dev,uint8_t * usrbuf)494 static void numaker_usbd_setup_fifo_copy_to_user(const struct device *dev, uint8_t *usrbuf)
495 {
496 	const struct numaker_usbd_config *config = dev->config;
497 	USBD_T *const base = config->base;
498 	uint32_t dmabuf_addr;
499 
500 	dmabuf_addr = numaker_usbd_buf_base(dev) + (base->STBUFSEG & USBD_STBUFSEG_STBUFSEG_Msk);
501 
502 	bytecpy(usrbuf, (uint8_t *)dmabuf_addr, 8ul);
503 }
504 
505 /* Copy data to user buffer from EP FIFO
506  *
507  * size_p holds size to copy/copied on input/output
508  */
numaker_usbd_ep_fifo_copy_to_user(struct numaker_usbd_ep * ep_cur,uint8_t * usrbuf,uint32_t * size_p)509 static int numaker_usbd_ep_fifo_copy_to_user(struct numaker_usbd_ep *ep_cur, uint8_t *usrbuf,
510 					     uint32_t *size_p)
511 {
512 	const struct device *dev = ep_cur->dev;
513 	uint32_t dmabuf_addr;
514 
515 	__ASSERT_NO_MSG(size_p);
516 	__ASSERT_NO_MSG(ep_cur->dmabuf_valid);
517 
518 	dmabuf_addr = numaker_usbd_buf_base(dev) + ep_cur->read_fifo_pos;
519 
520 	/* Clamp to read FIFO used count */
521 	*size_p = MIN(*size_p, numaker_usbd_ep_fifo_used(ep_cur));
522 
523 	bytecpy(usrbuf, (uint8_t *)dmabuf_addr, *size_p);
524 
525 	/* Advance read FIFO */
526 	ep_cur->read_fifo_pos += *size_p;
527 	ep_cur->read_fifo_used -= *size_p;
528 	if (ep_cur->read_fifo_used == 0) {
529 		ep_cur->read_fifo_pos = ep_cur->dmabuf_base;
530 	}
531 
532 	return 0;
533 }
534 
535 /* Copy data from user buffer to EP FIFO
536  *
537  * size_p holds size to copy/copied on input/output
538  */
numaker_usbd_ep_fifo_copy_from_user(struct numaker_usbd_ep * ep_cur,const uint8_t * usrbuf,uint32_t * size_p)539 static int numaker_usbd_ep_fifo_copy_from_user(struct numaker_usbd_ep *ep_cur,
540 					       const uint8_t *usrbuf, uint32_t *size_p)
541 {
542 	const struct device *dev = ep_cur->dev;
543 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
544 	uint32_t dmabuf_addr;
545 	uint32_t fifo_free;
546 
547 	__ASSERT_NO_MSG(size_p);
548 	__ASSERT_NO_MSG(ep_cur->dmabuf_valid);
549 	__ASSERT_NO_MSG(ep_cur->mps_valid);
550 	__ASSERT_NO_MSG(ep_cur->mps <= ep_cur->dmabuf_size);
551 
552 	dmabuf_addr = numaker_usbd_buf_base(dev) + ep_base->BUFSEG;
553 	fifo_free = numaker_usbd_ep_fifo_max(ep_cur) - numaker_usbd_ep_fifo_used(ep_cur);
554 
555 	*size_p = MIN(*size_p, fifo_free);
556 
557 	bytecpy((uint8_t *)dmabuf_addr, (uint8_t *)usrbuf, *size_p);
558 
559 	/* Advance write FIFO */
560 	ep_cur->write_fifo_pos += *size_p;
561 	ep_cur->write_fifo_free -= *size_p;
562 	if (ep_cur->write_fifo_free == 0) {
563 		ep_cur->write_fifo_pos = ep_cur->dmabuf_base;
564 	}
565 
566 	return 0;
567 }
568 
569 /* Update EP read/write FIFO on DATA OUT/IN completed */
numaker_usbd_ep_fifo_update(struct numaker_usbd_ep * ep_cur)570 static void numaker_usbd_ep_fifo_update(struct numaker_usbd_ep *ep_cur)
571 {
572 	const struct device *dev = ep_cur->dev;
573 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
574 
575 	__ASSERT_NO_MSG(ep_cur->addr_valid);
576 	__ASSERT_NO_MSG(ep_cur->dmabuf_valid);
577 
578 	if (USB_EP_DIR_IS_OUT(ep_cur->addr)) {
579 		/* Read FIFO */
580 		/* NOTE: For one-shot implementation, FIFO gets updated from empty. */
581 		ep_cur->read_fifo_pos = ep_cur->dmabuf_base;
582 		/* NOTE: See comment on mxpld_ctrlout for why make one copy of CTRL OUT's MXPLD */
583 		if (USB_EP_GET_IDX(ep_cur->addr) == 0) {
584 			ep_cur->read_fifo_used = ep_cur->mxpld_ctrlout;
585 		} else {
586 			ep_cur->read_fifo_used = ep_base->MXPLD;
587 		}
588 	} else {
589 		/* Write FIFO */
590 		/* NOTE: For one-shot implementation, FIFO gets to empty. */
591 		ep_cur->write_fifo_pos = ep_cur->dmabuf_base;
592 		ep_cur->write_fifo_free = numaker_usbd_ep_fifo_max(ep_cur);
593 	}
594 }
595 
numaker_usbd_ep_config_dmabuf(struct numaker_usbd_ep * ep_cur,uint32_t dmabuf_base,uint32_t dmabuf_size)596 static void numaker_usbd_ep_config_dmabuf(struct numaker_usbd_ep *ep_cur, uint32_t dmabuf_base,
597 					  uint32_t dmabuf_size)
598 {
599 	const struct device *dev = ep_cur->dev;
600 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
601 
602 	ep_base->BUFSEG = dmabuf_base;
603 
604 	ep_cur->dmabuf_valid = true;
605 	ep_cur->dmabuf_base = dmabuf_base;
606 	ep_cur->dmabuf_size = dmabuf_size;
607 }
608 
numaker_usbd_ep_abort(struct numaker_usbd_ep * ep_cur)609 static void numaker_usbd_ep_abort(struct numaker_usbd_ep *ep_cur)
610 {
611 	const struct device *dev = ep_cur->dev;
612 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
613 
614 	/* Abort EP on-going transaction */
615 	ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk;
616 
617 	/* Need to clear NAK for next transaction */
618 	ep_cur->nak_clr = false;
619 }
620 
621 /* Configure EP major common parts */
numaker_usbd_ep_config_major(struct numaker_usbd_ep * ep_cur,const struct usb_dc_ep_cfg_data * const ep_cfg)622 static void numaker_usbd_ep_config_major(struct numaker_usbd_ep *ep_cur,
623 					 const struct usb_dc_ep_cfg_data *const ep_cfg)
624 {
625 	const struct device *dev = ep_cur->dev;
626 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
627 
628 	ep_cur->mps_valid = true;
629 	ep_cur->mps = ep_cfg->ep_mps;
630 
631 	/* Configure EP transfer type, DATA0/1 toggle, direction, number, etc. */
632 	ep_cur->ep_hw_cfg = 0;
633 
634 	/* Clear STALL Response in Setup stage */
635 	if (ep_cfg->ep_type == USB_DC_EP_CONTROL) {
636 		ep_cur->ep_hw_cfg |= USBD_CFG_CSTALL;
637 	}
638 
639 	/* Default to DATA0 */
640 	ep_cur->ep_hw_cfg &= ~USBD_CFG_DSQSYNC_Msk;
641 
642 	/* Endpoint IN/OUT, though, default to disabled */
643 	ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_DISABLE;
644 
645 	/* Isochronous or not */
646 	if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) {
647 		ep_cur->ep_hw_cfg |= USBD_CFG_TYPE_ISO;
648 	}
649 
650 	/* Endpoint index */
651 	ep_cur->ep_hw_cfg |=
652 		(USB_EP_GET_IDX(ep_cfg->ep_addr) << USBD_CFG_EPNUM_Pos) & USBD_CFG_EPNUM_Msk;
653 
654 	ep_base->CFG = ep_cur->ep_hw_cfg;
655 }
656 
numaker_usbd_ep_enable(struct numaker_usbd_ep * ep_cur)657 static void numaker_usbd_ep_enable(struct numaker_usbd_ep *ep_cur)
658 {
659 	const struct device *dev = ep_cur->dev;
660 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
661 
662 	/* For safe, EP (re-)enable from clean state */
663 	numaker_usbd_ep_abort(ep_cur);
664 	numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur);
665 	numaker_usbd_ep_fifo_reset(ep_cur);
666 
667 	/* Enable EP to IN/OUT */
668 	ep_cur->ep_hw_cfg &= ~USBD_CFG_STATE_Msk;
669 	if (USB_EP_DIR_IS_IN(ep_cur->addr)) {
670 		ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_IN;
671 	} else {
672 		ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_OUT;
673 	}
674 
675 	ep_base->CFG = ep_cur->ep_hw_cfg;
676 
677 	/* For USBD, no separate EP interrupt control */
678 }
679 
numaker_usbd_ep_disable(struct numaker_usbd_ep * ep_cur)680 static void numaker_usbd_ep_disable(struct numaker_usbd_ep *ep_cur)
681 {
682 	const struct device *dev = ep_cur->dev;
683 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
684 
685 	/* For USBD, no separate EP interrupt control */
686 
687 	/* Disable EP */
688 	ep_cur->ep_hw_cfg = (ep_cur->ep_hw_cfg & ~USBD_CFG_STATE_Msk) | USBD_CFG_EPMODE_DISABLE;
689 	ep_base->CFG = ep_cur->ep_hw_cfg;
690 }
691 
692 /* Start EP data transaction */
numaker_usbd_ep_trigger(struct numaker_usbd_ep * ep_cur,uint32_t len)693 static void numaker_usbd_ep_trigger(struct numaker_usbd_ep *ep_cur, uint32_t len)
694 {
695 	const struct device *dev = ep_cur->dev;
696 	USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
697 
698 	ep_base->MXPLD = len;
699 }
700 
numaker_usbd_ep_mgmt_alloc_ep(const struct device * dev)701 static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_alloc_ep(const struct device *dev)
702 {
703 	const struct numaker_usbd_config *config = dev->config;
704 	struct numaker_usbd_data *data = dev->data;
705 	struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt;
706 	struct numaker_usbd_ep *ep_cur = NULL;
707 
708 	if (ep_mgmt->ep_idx < config->num_bidir_endpoints) {
709 		ep_cur = ep_mgmt->ep_pool + ep_mgmt->ep_idx;
710 		ep_mgmt->ep_idx++;
711 
712 		__ASSERT_NO_MSG(!ep_cur->valid);
713 
714 		/* Indicate this EP context is allocated */
715 		ep_cur->valid = true;
716 	}
717 
718 	return ep_cur;
719 }
720 
721 /* Allocate DMA buffer
722  *
723  * Return -ENOMEM  on OOM error, or 0 on success with DMA buffer base/size (rounded up) allocated
724  */
numaker_usbd_ep_mgmt_alloc_dmabuf(const struct device * dev,uint32_t size,uint32_t * dmabuf_base_p,uint32_t * dmabuf_size_p)725 static int numaker_usbd_ep_mgmt_alloc_dmabuf(const struct device *dev, uint32_t size,
726 					     uint32_t *dmabuf_base_p, uint32_t *dmabuf_size_p)
727 {
728 	const struct numaker_usbd_config *config = dev->config;
729 	struct numaker_usbd_data *data = dev->data;
730 	struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt;
731 
732 	__ASSERT_NO_MSG(dmabuf_base_p);
733 	__ASSERT_NO_MSG(dmabuf_size_p);
734 
735 	/* Required to be 8-byte aligned */
736 	size = ROUND_UP(size, 8);
737 
738 	ep_mgmt->dmabuf_pos += size;
739 	if (ep_mgmt->dmabuf_pos > config->dmabuf_size) {
740 		ep_mgmt->dmabuf_pos -= size;
741 		return -ENOMEM;
742 	}
743 
744 	*dmabuf_base_p = ep_mgmt->dmabuf_pos - size;
745 	*dmabuf_size_p = size;
746 	return 0;
747 }
748 
749 /* Initialize all endpoint-related */
numaker_usbd_ep_mgmt_init(const struct device * dev)750 static void numaker_usbd_ep_mgmt_init(const struct device *dev)
751 {
752 	const struct numaker_usbd_config *config = dev->config;
753 	struct numaker_usbd_data *data = dev->data;
754 	USBD_T *const base = config->base;
755 	struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt;
756 
757 	struct numaker_usbd_ep *ep_cur;
758 	struct numaker_usbd_ep *ep_end;
759 
760 	/* Initialize all fields to zero except persistent */
761 	memset(ep_mgmt, 0x00, sizeof(*ep_mgmt));
762 
763 	ep_cur = ep_mgmt->ep_pool;
764 	ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints;
765 
766 	/* Initialize all EP contexts */
767 	for (; ep_cur != ep_end; ep_cur++) {
768 		/* Pointer to the containing device */
769 		ep_cur->dev = dev;
770 
771 		/* BSP USBD driver EP handle */
772 		ep_cur->ep_hw_idx = EP0 + (ep_cur - ep_mgmt->ep_pool);
773 	}
774 
775 	/* Reserve 1st/2nd EP contexts (BSP USBD driver EP0/EP1) for CTRL OUT/IN */
776 	ep_mgmt->ep_idx = 2;
777 
778 	/* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, starting from 0 */
779 	ep_mgmt->dmabuf_pos = 0;
780 
781 	/* Configure DMA buffer for Setup packet */
782 	base->STBUFSEG = ep_mgmt->dmabuf_pos;
783 	ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_SETUP;
784 
785 	/* Reserve 1st EP context (BSP USBD driver EP0) for CTRL OUT */
786 	ep_cur = ep_mgmt->ep_pool + 0;
787 	ep_cur->valid = true;
788 	ep_cur->addr_valid = true;
789 	ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_OUT);
790 	numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos,
791 				      NUMAKER_USBD_DMABUF_SIZE_CTRLOUT);
792 	ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLOUT;
793 	ep_cur->mps_valid = true;
794 	ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLOUT;
795 
796 	/* Reserve 2nd EP context (BSP USBD driver EP1) for CTRL IN */
797 	ep_cur = ep_mgmt->ep_pool + 1;
798 	ep_cur->valid = true;
799 	ep_cur->addr_valid = true;
800 	ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_IN);
801 	numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos, NUMAKER_USBD_DMABUF_SIZE_CTRLIN);
802 	ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLIN;
803 	ep_cur->mps_valid = true;
804 	ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLIN;
805 }
806 
807 /* Find EP context by EP address */
numaker_usbd_ep_mgmt_find_ep(const struct device * dev,const uint8_t ep)808 static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_find_ep(const struct device *dev,
809 							    const uint8_t ep)
810 {
811 	const struct numaker_usbd_config *config = dev->config;
812 	struct numaker_usbd_data *data = dev->data;
813 	struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt;
814 	struct numaker_usbd_ep *ep_cur = ep_mgmt->ep_pool;
815 	struct numaker_usbd_ep *ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints;
816 
817 	for (; ep_cur != ep_end; ep_cur++) {
818 		if (!ep_cur->valid) {
819 			continue;
820 		}
821 
822 		if (!ep_cur->addr_valid) {
823 			continue;
824 		}
825 
826 		if (ep == ep_cur->addr) {
827 			return ep_cur;
828 		}
829 	}
830 
831 	return NULL;
832 }
833 
834 /* Bind EP context to EP address */
numaker_usbd_ep_mgmt_bind_ep(const struct device * dev,const uint8_t ep)835 static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_bind_ep(const struct device *dev,
836 							    const uint8_t ep)
837 {
838 	struct numaker_usbd_ep *ep_cur = numaker_usbd_ep_mgmt_find_ep(dev, ep);
839 
840 	if (!ep_cur) {
841 		ep_cur = numaker_usbd_ep_mgmt_alloc_ep(dev);
842 
843 		if (!ep_cur) {
844 			return NULL;
845 		}
846 
847 		/* Bind EP context to EP address */
848 		ep_cur->addr = ep;
849 		ep_cur->addr_valid = true;
850 	}
851 
852 	/* Assert EP context bound to EP address */
853 	__ASSERT_NO_MSG(ep_cur->valid);
854 	__ASSERT_NO_MSG(ep_cur->addr_valid);
855 	__ASSERT_NO_MSG(ep_cur->addr == ep);
856 
857 	return ep_cur;
858 }
859 
860 /* Interrupt bottom half processing for bus reset */
numaker_usbd_bus_reset_bh(const struct device * dev)861 static void numaker_usbd_bus_reset_bh(const struct device *dev)
862 {
863 	const struct numaker_usbd_config *config = dev->config;
864 	struct numaker_usbd_data *data = dev->data;
865 	struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt;
866 
867 	struct numaker_usbd_ep *ep_cur = ep_mgmt->ep_pool;
868 	struct numaker_usbd_ep *ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints;
869 
870 	for (; ep_cur != ep_end; ep_cur++) {
871 		/* Reset EP FIFO */
872 		numaker_usbd_ep_fifo_reset(ep_cur);
873 
874 		/* Abort EP on-going transaction and signal H/W relinquishes DMA buffer ownership */
875 		numaker_usbd_ep_abort(ep_cur);
876 
877 		/* Reset EP to unstalled and data toggle bit to 0 */
878 		numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur);
879 	}
880 
881 	numaker_usbd_reset_addr(dev);
882 }
883 
884 /* Interrupt bottom half processing for Setup/EP data transaction */
numaker_usbd_ep_bh(struct numaker_usbd_ep * ep_cur,enum usb_dc_ep_cb_status_code status_code)885 static void numaker_usbd_ep_bh(struct numaker_usbd_ep *ep_cur,
886 			       enum usb_dc_ep_cb_status_code status_code)
887 {
888 	const struct device *dev = ep_cur->dev;
889 	struct numaker_usbd_data *data = dev->data;
890 	struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt;
891 
892 	if (status_code == USB_DC_EP_SETUP) {
893 		/* Zephyr USB device stack passes Setup packet via CTRL OUT EP. */
894 		__ASSERT_NO_MSG(ep_cur->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT));
895 
896 		if (numaker_usbd_ep_fifo_used(ep_cur)) {
897 			LOG_WRN("New Setup will override previous Control OUT data");
898 		}
899 
900 		/* We should have reserved 1st/2nd EP contexts for CTRL OUT/IN */
901 		__ASSERT_NO_MSG(ep_cur->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT));
902 		__ASSERT_NO_MSG((ep_cur + 1)->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_IN));
903 
904 		/* Reset CTRL OUT/IN FIFO due to new Setup packet */
905 		numaker_usbd_ep_fifo_reset(ep_cur);
906 		numaker_usbd_ep_fifo_reset(ep_cur + 1);
907 
908 		/* Relinquish CTRL OUT/IN DMA buffer ownership on behalf of H/W */
909 		numaker_usbd_ep_abort(ep_cur);
910 		numaker_usbd_ep_abort(ep_cur + 1);
911 
912 		/* Mark new Setup packet for read */
913 		numaker_usbd_setup_fifo_copy_to_user(dev, (uint8_t *)&ep_mgmt->setup_packet);
914 		ep_mgmt->new_setup = true;
915 	} else if (status_code == USB_DC_EP_DATA_OUT) {
916 		__ASSERT_NO_MSG(USB_EP_DIR_IS_OUT(ep_cur->addr));
917 
918 		/* Update EP read FIFO */
919 		numaker_usbd_ep_fifo_update(ep_cur);
920 
921 		/* Need to clear NAK for next transaction */
922 		ep_cur->nak_clr = false;
923 	} else if (status_code == USB_DC_EP_DATA_IN) {
924 		__ASSERT_NO_MSG(USB_EP_DIR_IS_IN(ep_cur->addr));
925 
926 		/* Update EP write FIFO */
927 		numaker_usbd_ep_fifo_update(ep_cur);
928 
929 		/* Need to clear NAK for next transaction */
930 		ep_cur->nak_clr = false;
931 	}
932 }
933 
934 /* Message handler for S/W reconnect */
numaker_usbd_msg_sw_reconn(const struct device * dev,struct numaker_usbd_msg * msg)935 static void numaker_usbd_msg_sw_reconn(const struct device *dev, struct numaker_usbd_msg *msg)
936 {
937 	__ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_SW_RECONN);
938 
939 	/* S/W reconnect for error recovery */
940 	numaker_usbd_lock(dev);
941 	numaker_usbd_sw_reconnect(dev);
942 	numaker_usbd_unlock(dev);
943 }
944 
945 /* Message handler for callback for usb_dc_status_code */
numaker_usbd_msg_cb_state(const struct device * dev,struct numaker_usbd_msg * msg)946 static void numaker_usbd_msg_cb_state(const struct device *dev, struct numaker_usbd_msg *msg)
947 {
948 	struct numaker_usbd_data *data = dev->data;
949 
950 	__ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_CB_STATE);
951 
952 	/* Interrupt bottom half processing for bus reset */
953 	if (msg->cb_device.status_code == USB_DC_RESET) {
954 		numaker_usbd_lock(dev);
955 		numaker_usbd_bus_reset_bh(dev);
956 		numaker_usbd_unlock(dev);
957 	}
958 
959 	/* NOTE: Don't run callback with our mutex locked, or we may encounter
960 	 * deadlock because the Zephyr USB device stack can have its own
961 	 * synchronization.
962 	 */
963 	if (data->status_cb) {
964 		data->status_cb(msg->cb_device.status_code, NULL);
965 	} else {
966 		LOG_WRN("No status callback: status_code=%d", msg->cb_device.status_code);
967 	}
968 }
969 
970 /* Message handler for callback for usb_dc_ep_cb_status_code */
numaker_usbd_msg_cb_ep(const struct device * dev,struct numaker_usbd_msg * msg)971 static void numaker_usbd_msg_cb_ep(const struct device *dev, struct numaker_usbd_msg *msg)
972 {
973 	uint8_t ep;
974 	struct numaker_usbd_ep *ep_cur;
975 
976 	__ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_CB_EP);
977 
978 	ep = msg->cb_ep.ep;
979 
980 	/* Bind EP context to EP address */
981 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
982 
983 	if (!ep_cur) {
984 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
985 		return;
986 	}
987 
988 	/* Interrupt bottom half processing for EP */
989 	numaker_usbd_lock(dev);
990 	numaker_usbd_ep_bh(ep_cur, msg->cb_ep.status_code);
991 	numaker_usbd_unlock(dev);
992 
993 	/* NOTE: Same as above, don't run callback with our mutex locked */
994 	if (ep_cur->cb) {
995 		ep_cur->cb(ep, msg->cb_ep.status_code);
996 	} else {
997 		LOG_WRN("No EP callback: ep=0x%02x, status_code=%d", ep, msg->cb_ep.status_code);
998 	}
999 }
1000 
1001 /* Interrupt bottom half processing
1002  *
1003  * This thread is used to not run Zephyr USB device stack and callbacks in interrupt
1004  * context. This is because callbacks from this stack may use mutex or other kernel functions
1005  * which are not supported in interrupt context.
1006  */
numaker_usbd_msg_hdlr_thread_main(void * arg1,void * arg2,void * arg3)1007 static void numaker_usbd_msg_hdlr_thread_main(void *arg1, void *arg2, void *arg3)
1008 {
1009 	const struct device *dev = (const struct device *)arg1;
1010 	struct numaker_usbd_data *data = dev->data;
1011 
1012 	struct numaker_usbd_msg msg;
1013 
1014 	__ASSERT_NO_MSG(arg1);
1015 	ARG_UNUSED(arg2);
1016 	ARG_UNUSED(arg3);
1017 
1018 	while (true) {
1019 		if (k_msgq_get(&data->msgq, &msg, K_FOREVER)) {
1020 			continue;
1021 		}
1022 
1023 		switch (msg.type) {
1024 		case NUMAKER_USBD_MSG_TYPE_SW_RECONN:
1025 			numaker_usbd_msg_sw_reconn(dev, &msg);
1026 			break;
1027 
1028 		case NUMAKER_USBD_MSG_TYPE_CB_STATE:
1029 			numaker_usbd_msg_cb_state(dev, &msg);
1030 			break;
1031 
1032 		case NUMAKER_USBD_MSG_TYPE_CB_EP:
1033 			numaker_usbd_msg_cb_ep(dev, &msg);
1034 			break;
1035 
1036 		default:
1037 			__ASSERT_NO_MSG(false);
1038 		}
1039 	}
1040 }
1041 
numaker_udbd_isr(const struct device * dev)1042 static void numaker_udbd_isr(const struct device *dev)
1043 {
1044 	const struct numaker_usbd_config *config = dev->config;
1045 	struct numaker_usbd_data *data = dev->data;
1046 	USBD_T *const base = config->base;
1047 	struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt;
1048 
1049 	struct numaker_usbd_msg msg = {0};
1050 
1051 	uint32_t volatile usbd_intsts = base->INTSTS;
1052 	uint32_t volatile usbd_bus_state = base->ATTR;
1053 
1054 	/* USB plug-in/unplug */
1055 	if (usbd_intsts & USBD_INTSTS_FLDET) {
1056 		/* Floating detect */
1057 		base->INTSTS = USBD_INTSTS_FLDET;
1058 
1059 		if (base->VBUSDET & USBD_VBUSDET_VBUSDET_Msk) {
1060 			/* USB plug-in */
1061 
1062 			/* Enable back USB/PHY */
1063 			base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
1064 
1065 			/* Message for bottom-half processing */
1066 			msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE;
1067 			msg.cb_device.status_code = USB_DC_CONNECTED;
1068 			numaker_usbd_send_msg(dev, &msg);
1069 
1070 			LOG_DBG("USB plug-in");
1071 		} else {
1072 			/* USB unplug */
1073 
1074 			/* Disable USB */
1075 			base->ATTR &= ~USBD_USB_EN;
1076 
1077 			/* Message for bottom-half processing */
1078 			msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE;
1079 			msg.cb_device.status_code = USB_DC_DISCONNECTED;
1080 			numaker_usbd_send_msg(dev, &msg);
1081 
1082 			LOG_DBG("USB unplug");
1083 		}
1084 	}
1085 
1086 	/* USB wake-up */
1087 	if (usbd_intsts & USBD_INTSTS_WAKEUP) {
1088 		/* Clear event flag */
1089 		base->INTSTS = USBD_INTSTS_WAKEUP;
1090 
1091 		LOG_DBG("USB wake-up");
1092 	}
1093 
1094 	/* USB reset/suspend/resume */
1095 	if (usbd_intsts & USBD_INTSTS_BUS) {
1096 		/* Clear event flag */
1097 		base->INTSTS = USBD_INTSTS_BUS;
1098 
1099 		if (usbd_bus_state & USBD_STATE_USBRST) {
1100 			/* Bus reset */
1101 
1102 			/* Enable back USB/PHY */
1103 			base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
1104 
1105 			/* Bus reset top half */
1106 			numaker_usbd_bus_reset_th(dev);
1107 
1108 			/* Message for bottom-half processing */
1109 			msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE;
1110 			msg.cb_device.status_code = USB_DC_RESET;
1111 			numaker_usbd_send_msg(dev, &msg);
1112 
1113 			LOG_DBG("USB reset");
1114 		}
1115 		if (usbd_bus_state & USBD_STATE_SUSPEND) {
1116 			/* Enable USB but disable PHY */
1117 			base->ATTR &= ~USBD_PHY_EN;
1118 
1119 			/* Message for bottom-half processing */
1120 			msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE;
1121 			msg.cb_device.status_code = USB_DC_SUSPEND;
1122 			numaker_usbd_send_msg(dev, &msg);
1123 
1124 			LOG_DBG("USB suspend");
1125 		}
1126 		if (usbd_bus_state & USBD_STATE_RESUME) {
1127 			/* Enable back USB/PHY */
1128 			base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
1129 
1130 			/* Message for bottom-half processing */
1131 			msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE;
1132 			msg.cb_device.status_code = USB_DC_RESUME;
1133 			numaker_usbd_send_msg(dev, &msg);
1134 
1135 			LOG_DBG("USB resume");
1136 		}
1137 	}
1138 
1139 	/* USB SOF */
1140 	if (usbd_intsts & USBD_INTSTS_SOFIF_Msk) {
1141 		/* Clear event flag */
1142 		base->INTSTS = USBD_INTSTS_SOFIF_Msk;
1143 
1144 		/* Message for bottom-half processing */
1145 		msg.type = NUMAKER_USBD_MSG_TYPE_CB_STATE;
1146 		msg.cb_device.status_code = USB_DC_SOF;
1147 		numaker_usbd_send_msg(dev, &msg);
1148 	}
1149 
1150 	/* USB Setup/EP */
1151 	if (usbd_intsts & USBD_INTSTS_USB) {
1152 		uint32_t epintsts;
1153 
1154 		/* Setup event */
1155 		if (usbd_intsts & USBD_INTSTS_SETUP) {
1156 			USBD_EP_T *ep0_base = numaker_usbd_ep_base(dev, EP0);
1157 			USBD_EP_T *ep1_base = numaker_usbd_ep_base(dev, EP1);
1158 
1159 			/* Clear event flag */
1160 			base->INTSTS = USBD_INTSTS_SETUP;
1161 
1162 			/* Clear the data IN/OUT ready flag of control endpoints */
1163 			ep0_base->CFGP |= USBD_CFGP_CLRRDY_Msk;
1164 			ep1_base->CFGP |= USBD_CFGP_CLRRDY_Msk;
1165 
1166 			/* By USB spec, following transactions, regardless of Data/Status stage,
1167 			 * will always be DATA1
1168 			 */
1169 			ep0_base->CFG |= USBD_CFG_DSQSYNC_Msk;
1170 			ep1_base->CFG |= USBD_CFG_DSQSYNC_Msk;
1171 
1172 			/* Message for bottom-half processing */
1173 			/* NOTE: In Zephyr USB device stack, Setup packet is passed via
1174 			 * CTRL OUT EP
1175 			 */
1176 			msg.type = NUMAKER_USBD_MSG_TYPE_CB_EP;
1177 			msg.cb_ep.ep = USB_EP_GET_ADDR(0, USB_EP_DIR_OUT);
1178 			msg.cb_ep.status_code = USB_DC_EP_SETUP;
1179 			numaker_usbd_send_msg(dev, &msg);
1180 		}
1181 
1182 		/* EP events */
1183 		epintsts = base->EPINTSTS;
1184 
1185 		base->EPINTSTS = epintsts;
1186 
1187 		while (epintsts) {
1188 			uint32_t ep_hw_idx = u32_count_trailing_zeros(epintsts);
1189 			USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_hw_idx);
1190 			uint8_t ep_dir;
1191 			uint8_t ep_idx;
1192 			uint8_t ep;
1193 
1194 			/* We don't enable INNAKEN interrupt, so as long as EP event occurs,
1195 			 * we can just regard one data transaction has completed (ACK for
1196 			 * CTRL/BULK/INT or no-ACK for Iso), that is, no need to check EPSTS0,
1197 			 * EPSTS1, etc.
1198 			 */
1199 
1200 			/* EP direction, number, and address */
1201 			ep_dir = ((ep_base->CFG & USBD_CFG_STATE_Msk) == USBD_CFG_EPMODE_IN)
1202 					 ? USB_EP_DIR_IN
1203 					 : USB_EP_DIR_OUT;
1204 			ep_idx = (ep_base->CFG & USBD_CFG_EPNUM_Msk) >> USBD_CFG_EPNUM_Pos;
1205 			ep = USB_EP_GET_ADDR(ep_idx, ep_dir);
1206 
1207 			/* NOTE: See comment in usb_dc_set_address()'s implementation
1208 			 * for safe place to change USB device address
1209 			 */
1210 			if (ep == USB_EP_GET_ADDR(0, USB_EP_DIR_IN)) {
1211 				numaker_usbd_set_addr(dev);
1212 			}
1213 
1214 			/* NOTE: See comment on mxpld_ctrlout for why make one copy of
1215 			 * CTRL OUT's MXPLD
1216 			 */
1217 			if (ep == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)) {
1218 				struct numaker_usbd_ep *ep_ctrlout = ep_mgmt->ep_pool + 0;
1219 				USBD_EP_T *ep_ctrlout_base =
1220 					numaker_usbd_ep_base(dev, ep_ctrlout->ep_hw_idx);
1221 
1222 				ep_ctrlout->mxpld_ctrlout = ep_ctrlout_base->MXPLD;
1223 			}
1224 
1225 			/* Message for bottom-half processing */
1226 			msg.type = NUMAKER_USBD_MSG_TYPE_CB_EP;
1227 			msg.cb_ep.ep = ep;
1228 			msg.cb_ep.status_code =
1229 				USB_EP_DIR_IS_IN(ep) ? USB_DC_EP_DATA_IN : USB_DC_EP_DATA_OUT;
1230 			numaker_usbd_send_msg(dev, &msg);
1231 
1232 			/* Have handled this EP and go next */
1233 			epintsts &= ~BIT(ep_hw_idx);
1234 		}
1235 	}
1236 }
1237 
1238 /* Zephyr USB device controller API implementation */
1239 
usb_dc_attach(void)1240 int usb_dc_attach(void)
1241 {
1242 	const struct device *dev = numaker_usbd_device_get();
1243 	int rc;
1244 
1245 	numaker_usbd_lock(dev);
1246 
1247 	/* Initialize USB DC H/W */
1248 	rc = numaker_usbd_hw_setup(dev);
1249 	if (rc < 0) {
1250 		LOG_ERR("Set up H/W");
1251 		goto cleanup;
1252 	}
1253 
1254 	/* USB device address defaults to 0 */
1255 	numaker_usbd_reset_addr(dev);
1256 
1257 	/* Initialize all EPs */
1258 	numaker_usbd_ep_mgmt_init(dev);
1259 
1260 	/* S/W connect */
1261 	numaker_usbd_sw_connect(dev);
1262 
1263 	LOG_DBG("attached");
1264 
1265 cleanup:
1266 
1267 	if (rc < 0) {
1268 		usb_dc_detach();
1269 	}
1270 
1271 	numaker_usbd_unlock(dev);
1272 
1273 	return rc;
1274 }
1275 
usb_dc_detach(void)1276 int usb_dc_detach(void)
1277 {
1278 	const struct device *dev = numaker_usbd_device_get();
1279 	struct numaker_usbd_data *data = dev->data;
1280 
1281 	LOG_DBG("detached");
1282 
1283 	numaker_usbd_lock(dev);
1284 
1285 	/* S/W disconnect */
1286 	numaker_usbd_sw_disconnect(dev);
1287 
1288 	/* Uninitialize USB DC H/W */
1289 	numaker_usbd_hw_shutdown(numaker_usbd_device_get());
1290 
1291 	/* Purge message queue */
1292 	k_msgq_purge(&data->msgq);
1293 
1294 	numaker_usbd_unlock(dev);
1295 
1296 	return 0;
1297 }
1298 
usb_dc_reset(void)1299 int usb_dc_reset(void)
1300 {
1301 	const struct device *dev = numaker_usbd_device_get();
1302 
1303 	LOG_DBG("usb_dc_reset");
1304 
1305 	numaker_usbd_lock(dev);
1306 
1307 	usb_dc_detach();
1308 	usb_dc_attach();
1309 
1310 	numaker_usbd_unlock(dev);
1311 
1312 	return 0;
1313 }
1314 
usb_dc_set_address(const uint8_t addr)1315 int usb_dc_set_address(const uint8_t addr)
1316 {
1317 	const struct device *dev = numaker_usbd_device_get();
1318 	struct numaker_usbd_data *data = dev->data;
1319 
1320 	LOG_DBG("USB device address=%u (0x%02x)", addr, addr);
1321 
1322 	numaker_usbd_lock(dev);
1323 
1324 	/* NOTE: Timing for configuring USB device address into H/W is critical. It must be done
1325 	 * in-between SET_ADDRESS control transfer and next transfer. For this, it is done in
1326 	 * IN ACK ISR of SET_ADDRESS control transfer.
1327 	 */
1328 	data->addr = addr;
1329 
1330 	numaker_usbd_unlock(dev);
1331 
1332 	return 0;
1333 }
1334 
usb_dc_set_status_callback(const usb_dc_status_callback cb)1335 void usb_dc_set_status_callback(const usb_dc_status_callback cb)
1336 {
1337 	const struct device *dev = numaker_usbd_device_get();
1338 	struct numaker_usbd_data *data = dev->data;
1339 
1340 	numaker_usbd_lock(dev);
1341 
1342 	data->status_cb = cb;
1343 
1344 	numaker_usbd_unlock(dev);
1345 }
1346 
usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const ep_cfg)1347 int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data *const ep_cfg)
1348 {
1349 	const struct device *dev = numaker_usbd_device_get();
1350 	const struct numaker_usbd_config *config = dev->config;
1351 	int rc = 0;
1352 	struct numaker_usbd_ep *ep_cur;
1353 
1354 	numaker_usbd_lock(dev);
1355 
1356 	/* For safe, require EP number for control transfer to be 0 */
1357 	if ((ep_cfg->ep_type == USB_DC_EP_CONTROL) && USB_EP_GET_IDX(ep_cfg->ep_addr) != 0) {
1358 		LOG_ERR("EP number for control transfer must be 0");
1359 		rc = -ENOTSUP;
1360 		goto cleanup;
1361 	}
1362 
1363 	/* Some soc series don't allow ISO IN/OUT to be assigned the same EP number.
1364 	 * This is addressed by limiting all OUT/IN EP addresses in top/bottom halves,
1365 	 * except CTRL OUT/IN.
1366 	 */
1367 	if (config->disallow_iso_inout_same && ep_cfg->ep_type != USB_DC_EP_CONTROL) {
1368 		/* Limit all OUT EP addresses in top-half, except CTRL OUT */
1369 		if (USB_EP_DIR_IS_OUT(ep_cfg->ep_addr) && USB_EP_GET_IDX(ep_cfg->ep_addr) >= 8) {
1370 			LOG_DBG("Support only ISO OUT EP address 0x01~0x07: 0x%02x",
1371 				ep_cfg->ep_addr);
1372 			rc = -ENOTSUP;
1373 			goto cleanup;
1374 		}
1375 
1376 		/* Limit all IN EP addresses in bottom-half , except CTRL IN */
1377 		if (USB_EP_DIR_IS_IN(ep_cfg->ep_addr) && USB_EP_GET_IDX(ep_cfg->ep_addr) < 8) {
1378 			LOG_DBG("Support only ISO IN EP address 0x88~0x8F: 0x%02x",
1379 				ep_cfg->ep_addr);
1380 			rc = -ENOTSUP;
1381 			goto cleanup;
1382 		}
1383 	}
1384 
1385 	/* To respect this capability check, pre-bind EP context to EP address,
1386 	 * and pre-determined its type
1387 	 */
1388 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->ep_addr);
1389 	if (!ep_cur) {
1390 		LOG_ERR("Bind EP context: ep=0x%02x", ep_cfg->ep_addr);
1391 		rc = -ENOMEM;
1392 		goto cleanup;
1393 	}
1394 
1395 cleanup:
1396 
1397 	numaker_usbd_unlock(dev);
1398 
1399 	return rc;
1400 }
1401 
usb_dc_ep_set_callback(const uint8_t ep,const usb_dc_ep_callback cb)1402 int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb)
1403 {
1404 	const struct device *dev = numaker_usbd_device_get();
1405 	int rc = 0;
1406 	struct numaker_usbd_ep *ep_cur;
1407 
1408 	numaker_usbd_lock(dev);
1409 
1410 	/* Bind EP context to EP address */
1411 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1412 
1413 	if (!ep_cur) {
1414 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1415 		rc = -ENOMEM;
1416 		goto cleanup;
1417 	}
1418 
1419 	ep_cur->cb = cb;
1420 
1421 cleanup:
1422 
1423 	numaker_usbd_unlock(dev);
1424 
1425 	return rc;
1426 }
1427 
usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg)1428 int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data *const ep_cfg)
1429 {
1430 	const struct device *dev = numaker_usbd_device_get();
1431 	int rc = 0;
1432 	uint32_t dmabuf_base;
1433 	uint32_t dmabuf_size;
1434 	struct numaker_usbd_ep *ep_cur;
1435 
1436 	LOG_DBG("EP=0x%02x, MPS=%d, Type=%d", ep_cfg->ep_addr, ep_cfg->ep_mps, ep_cfg->ep_type);
1437 
1438 	numaker_usbd_lock(dev);
1439 
1440 	/* Bind EP context to EP address */
1441 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->ep_addr);
1442 
1443 	if (!ep_cur) {
1444 		LOG_ERR("Bind EP context: ep=0x%02x", ep_cfg->ep_addr);
1445 		rc = -ENOMEM;
1446 		goto cleanup;
1447 	}
1448 
1449 	/* Configure EP DMA buffer */
1450 	if (!ep_cur->dmabuf_valid || ep_cur->dmabuf_size < ep_cfg->ep_mps) {
1451 		/* Allocate DMA buffer */
1452 		rc = numaker_usbd_ep_mgmt_alloc_dmabuf(dev, ep_cfg->ep_mps, &dmabuf_base,
1453 						       &dmabuf_size);
1454 		if (rc < 0) {
1455 			LOG_ERR("Allocate DMA buffer failed");
1456 			goto cleanup;
1457 		}
1458 
1459 		/* Configure EP DMA buffer */
1460 		numaker_usbd_ep_config_dmabuf(ep_cur, dmabuf_base, dmabuf_size);
1461 	}
1462 
1463 	/* Configure EP majorly */
1464 	numaker_usbd_ep_config_major(ep_cur, ep_cfg);
1465 
1466 cleanup:
1467 
1468 	numaker_usbd_unlock(dev);
1469 
1470 	return rc;
1471 }
1472 
usb_dc_ep_set_stall(const uint8_t ep)1473 int usb_dc_ep_set_stall(const uint8_t ep)
1474 {
1475 	const struct device *dev = numaker_usbd_device_get();
1476 	int rc = 0;
1477 	struct numaker_usbd_ep *ep_cur;
1478 
1479 	LOG_DBG("Set stall: ep=0x%02x", ep);
1480 
1481 	numaker_usbd_lock(dev);
1482 
1483 	/* Bind EP context to EP address */
1484 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1485 
1486 	if (!ep_cur) {
1487 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1488 		rc = -ENOMEM;
1489 		goto cleanup;
1490 	}
1491 
1492 	/* Set EP to stalled */
1493 	numaker_usbd_ep_set_stall(ep_cur);
1494 
1495 cleanup:
1496 
1497 	numaker_usbd_unlock(dev);
1498 
1499 	return rc;
1500 }
1501 
usb_dc_ep_clear_stall(const uint8_t ep)1502 int usb_dc_ep_clear_stall(const uint8_t ep)
1503 {
1504 	const struct device *dev = numaker_usbd_device_get();
1505 	int rc = 0;
1506 	struct numaker_usbd_ep *ep_cur;
1507 
1508 	LOG_DBG("Clear stall: ep=0x%02x", ep);
1509 
1510 	numaker_usbd_lock(dev);
1511 
1512 	/* Bind EP context to EP address */
1513 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1514 
1515 	if (!ep_cur) {
1516 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1517 		rc = -ENOMEM;
1518 		goto cleanup;
1519 	}
1520 
1521 	/* Reset EP to unstalled and data toggle bit to 0 */
1522 	numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur);
1523 
1524 cleanup:
1525 
1526 	numaker_usbd_unlock(dev);
1527 
1528 	return rc;
1529 }
1530 
usb_dc_ep_is_stalled(const uint8_t ep,uint8_t * const stalled)1531 int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled)
1532 {
1533 	const struct device *dev = numaker_usbd_device_get();
1534 	int rc = 0;
1535 	struct numaker_usbd_ep *ep_cur;
1536 
1537 	if (!stalled) {
1538 		return -EINVAL;
1539 	}
1540 
1541 	numaker_usbd_lock(dev);
1542 
1543 	/* Bind EP context to EP address */
1544 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1545 
1546 	if (!ep_cur) {
1547 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1548 		rc = -ENOMEM;
1549 		goto cleanup;
1550 	}
1551 
1552 	*stalled = numaker_usbd_ep_is_stalled(ep_cur);
1553 
1554 cleanup:
1555 
1556 	numaker_usbd_unlock(dev);
1557 
1558 	return rc;
1559 }
1560 
usb_dc_ep_halt(const uint8_t ep)1561 int usb_dc_ep_halt(const uint8_t ep)
1562 {
1563 	return usb_dc_ep_set_stall(ep);
1564 }
1565 
usb_dc_ep_enable(const uint8_t ep)1566 int usb_dc_ep_enable(const uint8_t ep)
1567 {
1568 	const struct device *dev = numaker_usbd_device_get();
1569 	int rc = 0;
1570 	struct numaker_usbd_ep *ep_cur;
1571 
1572 	LOG_DBG("Enable: ep=0x%02x", ep);
1573 
1574 	numaker_usbd_lock(dev);
1575 
1576 	/* Bind EP context to EP address */
1577 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1578 
1579 	if (!ep_cur) {
1580 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1581 		rc = -ENOMEM;
1582 		goto cleanup;
1583 	}
1584 
1585 	numaker_usbd_ep_enable(ep_cur);
1586 
1587 	/* Trigger OUT transaction manually, or H/W will continue to reply NAK because
1588 	 * Zephyr USB device stack is unclear on kicking off by invoking usb_dc_ep_read()
1589 	 * or friends. We needn't do this for CTRL OUT because Setup sequence will involve
1590 	 * this.
1591 	 */
1592 	if (USB_EP_DIR_IS_OUT(ep) && USB_EP_GET_IDX(ep) != 0) {
1593 		rc = usb_dc_ep_read_continue(ep);
1594 		if (rc < 0) {
1595 			goto cleanup;
1596 		}
1597 	}
1598 
1599 cleanup:
1600 
1601 	numaker_usbd_unlock(dev);
1602 
1603 	return rc;
1604 }
1605 
usb_dc_ep_disable(const uint8_t ep)1606 int usb_dc_ep_disable(const uint8_t ep)
1607 {
1608 	const struct device *dev = numaker_usbd_device_get();
1609 	int rc = 0;
1610 	struct numaker_usbd_ep *ep_cur;
1611 
1612 	LOG_DBG("Disable: ep=0x%02x", ep);
1613 
1614 	numaker_usbd_lock(dev);
1615 
1616 	/* Bind EP context to EP address */
1617 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1618 
1619 	if (!ep_cur) {
1620 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1621 		rc = -ENOMEM;
1622 		goto cleanup;
1623 	}
1624 
1625 	numaker_usbd_ep_disable(ep_cur);
1626 
1627 cleanup:
1628 
1629 	numaker_usbd_unlock(dev);
1630 
1631 	return rc;
1632 }
1633 
usb_dc_ep_flush(const uint8_t ep)1634 int usb_dc_ep_flush(const uint8_t ep)
1635 {
1636 	const struct device *dev = numaker_usbd_device_get();
1637 	int rc = 0;
1638 	struct numaker_usbd_ep *ep_cur;
1639 
1640 	LOG_DBG("ep=0x%02x", ep);
1641 
1642 	numaker_usbd_lock(dev);
1643 
1644 	/* Bind EP context to EP address */
1645 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1646 
1647 	if (!ep_cur) {
1648 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1649 		rc = -ENOMEM;
1650 		goto cleanup;
1651 	}
1652 
1653 	numaker_usbd_ep_fifo_reset(ep_cur);
1654 
1655 cleanup:
1656 
1657 	numaker_usbd_unlock(dev);
1658 
1659 	return rc;
1660 }
1661 
usb_dc_ep_write(const uint8_t ep,const uint8_t * const data_buf,const uint32_t data_len,uint32_t * const ret_bytes)1662 int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data_buf, const uint32_t data_len,
1663 		    uint32_t *const ret_bytes)
1664 {
1665 	const struct device *dev = numaker_usbd_device_get();
1666 	int rc = 0;
1667 	struct numaker_usbd_ep *ep_cur;
1668 	uint32_t data_len_act;
1669 
1670 	numaker_usbd_lock(dev);
1671 
1672 	/* Bind EP context to EP address */
1673 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1674 
1675 	if (!ep_cur) {
1676 		LOG_ERR("ep=0x%02x", ep);
1677 		rc = -ENOMEM;
1678 		goto cleanup;
1679 	}
1680 
1681 	if (!USB_EP_DIR_IS_IN(ep)) {
1682 		LOG_ERR("Invalid EP address 0x%02x for write", ep);
1683 		rc = -EINVAL;
1684 		goto cleanup;
1685 	}
1686 
1687 	/* For USBD, avoid duplicate NAK clear */
1688 	if (ep_cur->nak_clr) {
1689 		LOG_WRN("ep 0x%02x busy", ep);
1690 		rc = -EAGAIN;
1691 		goto cleanup;
1692 	}
1693 
1694 	/* For one-shot implementation, don't trigger next DATA IN with write FIFO not empty. */
1695 	if (numaker_usbd_ep_fifo_used(ep_cur)) {
1696 		LOG_WRN("ep 0x%02x: Write FIFO not empty for one-shot implementation", ep);
1697 		rc = -EAGAIN;
1698 		goto cleanup;
1699 	}
1700 
1701 	/* NOTE: Null data or zero data length are valid, used for ZLP */
1702 	if (data_buf && data_len) {
1703 		data_len_act = data_len;
1704 		rc = numaker_usbd_ep_fifo_copy_from_user(ep_cur, data_buf, &data_len_act);
1705 		if (rc < 0) {
1706 			LOG_ERR("Copy to FIFO from user buffer");
1707 			goto cleanup;
1708 		}
1709 	} else {
1710 		data_len_act = 0;
1711 	}
1712 
1713 	/* Now H/W actually owns EP DMA buffer */
1714 	numaker_usbd_ep_trigger(ep_cur, data_len_act);
1715 
1716 	/* NOTE: For one-shot implementation, at most MPS size can be written, though,
1717 	 * null 'ret_bytes' requires all data written.
1718 	 */
1719 	if (ret_bytes) {
1720 		*ret_bytes = data_len_act;
1721 	} else if (data_len_act != data_len) {
1722 		LOG_ERR("Expected write all %d bytes, but actual %d bytes written", data_len,
1723 			data_len_act);
1724 		rc = -EIO;
1725 		goto cleanup;
1726 	}
1727 
1728 cleanup:
1729 
1730 	numaker_usbd_unlock(dev);
1731 
1732 	return rc;
1733 }
1734 
usb_dc_ep_read(const uint8_t ep,uint8_t * const data,const uint32_t max_data_len,uint32_t * const read_bytes)1735 int usb_dc_ep_read(const uint8_t ep, uint8_t *const data, const uint32_t max_data_len,
1736 		   uint32_t *const read_bytes)
1737 {
1738 	const struct device *dev = numaker_usbd_device_get();
1739 	int rc = 0;
1740 
1741 	numaker_usbd_lock(dev);
1742 
1743 	rc = usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes);
1744 	if (rc < 0) {
1745 		goto cleanup;
1746 	}
1747 
1748 	rc = usb_dc_ep_read_continue(ep);
1749 	if (rc < 0) {
1750 		goto cleanup;
1751 	}
1752 
1753 cleanup:
1754 
1755 	numaker_usbd_unlock(dev);
1756 
1757 	return rc;
1758 }
1759 
usb_dc_ep_read_wait(uint8_t ep,uint8_t * data_buf,uint32_t max_data_len,uint32_t * read_bytes)1760 int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data_buf, uint32_t max_data_len, uint32_t *read_bytes)
1761 {
1762 	const struct device *dev = numaker_usbd_device_get();
1763 	struct numaker_usbd_data *data = dev->data;
1764 	int rc = 0;
1765 	struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt;
1766 	struct numaker_usbd_ep *ep_cur;
1767 	uint32_t data_len_act = 0;
1768 
1769 	numaker_usbd_lock(dev);
1770 
1771 	/* Bind EP context to EP address */
1772 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1773 
1774 	if (!ep_cur) {
1775 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1776 		rc = -ENOMEM;
1777 		goto cleanup;
1778 	}
1779 
1780 	if (!USB_EP_DIR_IS_OUT(ep)) {
1781 		LOG_ERR("Invalid EP address 0x%02x for read", ep);
1782 		rc = -EINVAL;
1783 		goto cleanup;
1784 	}
1785 
1786 	/* Special handling for USB_CONTROL_EP_OUT on Setup packet */
1787 	if (ep == USB_CONTROL_EP_OUT && ep_mgmt->new_setup) {
1788 		if (!data_buf || max_data_len != 8) {
1789 			LOG_ERR("Invalid parameter for reading Setup packet");
1790 			rc = -EINVAL;
1791 			goto cleanup;
1792 		}
1793 
1794 		memcpy(data_buf, &ep_mgmt->setup_packet, 8);
1795 		ep_mgmt->new_setup = false;
1796 
1797 		if (read_bytes) {
1798 			*read_bytes = 8;
1799 		}
1800 
1801 		goto cleanup;
1802 	}
1803 
1804 	/* For one-shot implementation, don't read FIFO with EP busy. */
1805 	if (ep_cur->nak_clr) {
1806 		LOG_WRN("ep 0x%02x busy", ep);
1807 		rc = -EAGAIN;
1808 		goto cleanup;
1809 	}
1810 
1811 	/* NOTE: Null data and zero data length is valid, used for returning number of
1812 	 * available bytes for read
1813 	 */
1814 	if (data_buf) {
1815 		data_len_act = max_data_len;
1816 		rc = numaker_usbd_ep_fifo_copy_to_user(ep_cur, data_buf, &data_len_act);
1817 		if (rc < 0) {
1818 			LOG_ERR("Copy from FIFO to user buffer");
1819 			goto cleanup;
1820 		}
1821 
1822 		if (read_bytes) {
1823 			*read_bytes = data_len_act;
1824 		}
1825 	} else if (max_data_len) {
1826 		LOG_ERR("Null data but non-zero data length");
1827 		rc = -EINVAL;
1828 		goto cleanup;
1829 	} else {
1830 		if (read_bytes) {
1831 			*read_bytes = numaker_usbd_ep_fifo_used(ep_cur);
1832 		}
1833 	}
1834 
1835 	/* Suppress further USB_DC_EP_DATA_OUT events by replying NAK or disabling interrupt
1836 	 *
1837 	 * For USBD, further control is unnecessary because NAK is automatically replied until
1838 	 * next USBD_SET_PAYLOAD_LEN().
1839 	 */
1840 
1841 cleanup:
1842 
1843 	numaker_usbd_unlock(dev);
1844 
1845 	return rc;
1846 }
1847 
usb_dc_ep_read_continue(uint8_t ep)1848 int usb_dc_ep_read_continue(uint8_t ep)
1849 {
1850 	const struct device *dev = numaker_usbd_device_get();
1851 	int rc = 0;
1852 	struct numaker_usbd_ep *ep_cur;
1853 
1854 	numaker_usbd_lock(dev);
1855 
1856 	/* Bind EP context to EP address */
1857 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1858 
1859 	if (!ep_cur) {
1860 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1861 		rc = -ENOMEM;
1862 		goto cleanup;
1863 	}
1864 
1865 	if (!USB_EP_DIR_IS_OUT(ep)) {
1866 		LOG_ERR("Invalid EP address 0x%02x for read", ep);
1867 		rc = -EINVAL;
1868 		goto cleanup;
1869 	}
1870 
1871 	/* Avoid duplicate NAK clear */
1872 	if (ep_cur->nak_clr) {
1873 		rc = 0;
1874 		goto cleanup;
1875 	}
1876 
1877 	/* For one-shot implementation, don't trigger next DATA OUT, or overwrite. */
1878 	if (numaker_usbd_ep_fifo_used(ep_cur)) {
1879 		goto cleanup;
1880 	}
1881 
1882 	__ASSERT_NO_MSG(ep_cur->mps_valid);
1883 	numaker_usbd_ep_trigger(ep_cur, ep_cur->mps);
1884 
1885 cleanup:
1886 
1887 	numaker_usbd_unlock(dev);
1888 
1889 	return rc;
1890 }
1891 
usb_dc_ep_mps(const uint8_t ep)1892 int usb_dc_ep_mps(const uint8_t ep)
1893 {
1894 	const struct device *dev = numaker_usbd_device_get();
1895 	int rc = 0;
1896 	struct numaker_usbd_ep *ep_cur;
1897 	uint16_t ep_mps = 0;
1898 
1899 	numaker_usbd_lock(dev);
1900 
1901 	/* Bind EP context to EP address */
1902 	ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1903 
1904 	if (!ep_cur) {
1905 		LOG_ERR("Bind EP context: ep=0x%02x", ep);
1906 		rc = -ENOMEM;
1907 		goto cleanup;
1908 	}
1909 
1910 	__ASSERT_NO_MSG(ep_cur->mps_valid);
1911 	ep_mps = ep_cur->mps;
1912 
1913 cleanup:
1914 
1915 	numaker_usbd_unlock(dev);
1916 
1917 	return rc == 0 ? ep_mps : rc;
1918 }
1919 
usb_dc_wakeup_request(void)1920 int usb_dc_wakeup_request(void)
1921 {
1922 	const struct device *dev = numaker_usbd_device_get();
1923 	int rc = 0;
1924 
1925 	LOG_DBG("Remote wakeup");
1926 
1927 	numaker_usbd_lock(dev);
1928 
1929 	numaker_usbd_remote_wakeup(dev);
1930 
1931 	numaker_usbd_unlock(dev);
1932 
1933 	return rc;
1934 }
1935 
numaker_udbd_init(const struct device * dev)1936 static int numaker_udbd_init(const struct device *dev)
1937 {
1938 	struct numaker_usbd_data *data = dev->data;
1939 	int rc = 0;
1940 
1941 	/* Initialize all fields to zero */
1942 	memset(data, 0x00, sizeof(*data));
1943 
1944 	k_mutex_init(&data->sync_mutex);
1945 
1946 	/* Set up interrupt top/bottom halves processing */
1947 
1948 	k_msgq_init(&data->msgq, (char *)data->msgq_buf, sizeof(struct numaker_usbd_msg),
1949 		    CONFIG_USB_DC_NUMAKER_MSG_QUEUE_SIZE);
1950 
1951 	k_thread_create(&data->msg_hdlr_thread, data->msg_hdlr_thread_stack,
1952 			CONFIG_USB_DC_NUMAKER_MSG_HANDLER_THREAD_STACK_SIZE,
1953 			numaker_usbd_msg_hdlr_thread_main, (void *)dev, NULL, NULL, K_PRIO_COOP(2),
1954 			0, K_NO_WAIT);
1955 
1956 	k_thread_name_set(&data->msg_hdlr_thread, "numaker_usbd");
1957 
1958 	return rc;
1959 }
1960 
1961 #define USB_DC_NUMAKER_INIT(inst)                                                                  \
1962 	PINCTRL_DT_INST_DEFINE(inst);                                                              \
1963                                                                                                    \
1964 	static void numaker_usbd_irq_config_func_##inst(const struct device *dev)                  \
1965 	{                                                                                          \
1966 		IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), numaker_udbd_isr,     \
1967 			    DEVICE_DT_INST_GET(inst), 0);                                          \
1968                                                                                                    \
1969 		irq_enable(DT_INST_IRQN(inst));                                                    \
1970 	}                                                                                          \
1971                                                                                                    \
1972 	static void numaker_uusbd_irq_unconfig_func_##inst(const struct device *dev)               \
1973 	{                                                                                          \
1974 		irq_disable(DT_INST_IRQN(inst));                                                   \
1975 	}                                                                                          \
1976                                                                                                    \
1977 	static const struct numaker_usbd_config numaker_usbd_config_##inst = {                     \
1978 		.base = (USBD_T *)DT_INST_REG_ADDR(inst),                                          \
1979 		.reset = RESET_DT_SPEC_INST_GET(inst),                                             \
1980 		.clk_modidx = DT_INST_CLOCKS_CELL(inst, clock_module_index),                       \
1981 		.clk_src = DT_INST_CLOCKS_CELL(inst, clock_source),                                \
1982 		.clk_div = DT_INST_CLOCKS_CELL(inst, clock_divider),                               \
1983 		.clkctrl_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))),                \
1984 		.irq_config_func = numaker_usbd_irq_config_func_##inst,                            \
1985 		.irq_unconfig_func = numaker_uusbd_irq_unconfig_func_##inst,                       \
1986 		.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst),                                    \
1987 		.num_bidir_endpoints = DT_INST_PROP(inst, num_bidir_endpoints),                    \
1988 		.dmabuf_size = DT_INST_PROP(inst, dma_buffer_size),                                \
1989 		.disallow_iso_inout_same = DT_INST_PROP(inst, disallow_iso_in_out_same_number),    \
1990 	};                                                                                         \
1991                                                                                                    \
1992 	static struct numaker_usbd_data numaker_usbd_data_##inst;                                  \
1993                                                                                                    \
1994 	BUILD_ASSERT(DT_INST_PROP(inst, num_bidir_endpoints) <= NUMAKER_USBD_EP_MAXNUM,            \
1995 		     "num_bidir_endpoints exceeds support limit by USBD driver");                  \
1996                                                                                                    \
1997 	DEVICE_DT_INST_DEFINE(inst, numaker_udbd_init, NULL, &numaker_usbd_data_##inst,            \
1998 			      &numaker_usbd_config_##inst, POST_KERNEL,                            \
1999 			      CONFIG_KERNEL_INIT_PRIORITY_DEVICE, NULL);
2000 
2001 USB_DC_NUMAKER_INIT(0);
2002 
2003 /* Get USB DC device context instance 0 */
numaker_usbd_device_get(void)2004 static inline const struct device *numaker_usbd_device_get(void)
2005 {
2006 	return DEVICE_DT_INST_GET(0);
2007 }
2008