1 /*
2 * Copyright (c) 2024 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/drivers/usb/udc.h>
11 #include <zephyr/sys/math_extras.h>
12 #include <zephyr/drivers/clock_control.h>
13 #include <zephyr/drivers/clock_control/clock_control_numaker.h>
14 #include <zephyr/drivers/reset.h>
15 #include <zephyr/drivers/pinctrl.h>
16
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(udc_numaker, CONFIG_UDC_DRIVER_LOG_LEVEL);
19
20 #include <soc.h>
21 #include <NuMicro.h>
22
23 #include "udc_common.h"
24
25 /* USBD notes
26 *
27 * 1. Require 48MHz clock source
28 * (1) Not support HIRC48 as clock source. It involves trim with USB SOF packets
29 * and isn't suitable in HAL.
30 * (2) Instead of HICR48, core clock is required to be multiple of 48MHz e.g. 192MHz,
31 * to generate necessary 48MHz.
32 */
33
34 /* For bus reset, keep 'SE0' (USB spec: SE0 >= 2.5 ms) */
35 #define NUMAKER_USBD_BUS_RESET_DRV_SE0_US 3000
36
37 /* For bus resume, generate 'K' (USB spec: 'K' >= 1 ms) */
38 #define NUMAKER_USBD_BUS_RESUME_DRV_K_US 1500
39
40 /* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, required to be 8-byte aligned */
41 #define NUMAKER_USBD_DMABUF_SIZE_SETUP 8
42 #define NUMAKER_USBD_DMABUF_SIZE_CTRLOUT 64
43 #define NUMAKER_USBD_DMABUF_SIZE_CTRLIN 64
44
45 enum numaker_usbd_msg_type {
46 /* Setup packet received */
47 NUMAKER_USBD_MSG_TYPE_SETUP,
48 /* OUT transaction for specific EP completed */
49 NUMAKER_USBD_MSG_TYPE_OUT,
50 /* IN transaction for specific EP completed */
51 NUMAKER_USBD_MSG_TYPE_IN,
52 /* Re-activate queued transfer for specific EP */
53 NUMAKER_USBD_MSG_TYPE_XFER,
54 /* S/W reconnect */
55 NUMAKER_USBD_MSG_TYPE_SW_RECONN,
56 };
57
58 struct numaker_usbd_msg {
59 enum numaker_usbd_msg_type type;
60 union {
61 struct {
62 enum udc_event_type type;
63 } udc_bus_event;
64 struct {
65 uint8_t packet[8];
66 } setup;
67 struct {
68 uint8_t ep;
69 } out;
70 struct {
71 uint8_t ep;
72 } in;
73 struct {
74 uint8_t ep;
75 } xfer;
76 };
77 };
78
79 /* EP H/W context */
80 struct numaker_usbd_ep {
81 bool valid;
82
83 const struct device *dev; /* Pointer to the containing device */
84
85 uint8_t ep_hw_idx; /* BSP USBD driver EP index EP0, EP1, EP2, etc */
86 uint32_t ep_hw_cfg; /* BSP USBD driver EP configuration */
87
88 /* EP DMA buffer */
89 bool dmabuf_valid;
90 uint32_t dmabuf_base;
91 uint32_t dmabuf_size;
92
93 /* NOTE: On USBD, Setup and CTRL OUT are not completely separated. CTRL OUT MXPLD
94 * can be overridden to 8 by next Setup. To overcome it, we make one copy of CTRL
95 * OUT MXPLD immediately on its interrupt.
96 */
97 uint32_t mxpld_ctrlout;
98
99 /* EP address */
100 bool addr_valid;
101 uint8_t addr;
102
103 /* EP MPS */
104 bool mps_valid;
105 uint16_t mps;
106 };
107
108 /* Immutable device context */
109 struct udc_numaker_config {
110 struct udc_ep_config *ep_cfg_out;
111 struct udc_ep_config *ep_cfg_in;
112 uint32_t ep_cfg_out_size;
113 uint32_t ep_cfg_in_size;
114 USBD_T *base;
115 const struct reset_dt_spec reset;
116 uint32_t clk_modidx;
117 uint32_t clk_src;
118 uint32_t clk_div;
119 const struct device *clkctrl_dev;
120 void (*irq_config_func)(const struct device *dev);
121 void (*irq_unconfig_func)(const struct device *dev);
122 const struct pinctrl_dev_config *pincfg;
123 uint32_t dmabuf_size;
124 bool disallow_iso_inout_same;
125 void (*make_thread)(const struct device *dev);
126 };
127
128 /* EP H/W context manager */
129 struct numaker_usbd_ep_mgmt {
130 /* EP H/W context management
131 *
132 * Allocate-only, and de-allocate all on re-initialize in udc_numaker_init().
133 */
134 uint8_t ep_idx;
135
136 /* DMA buffer management
137 *
138 * Allocate-only, and de-allocate all on re-initialize in udc_numaker_init().
139 */
140 uint32_t dmabuf_pos;
141 };
142
143 /* Mutable device context */
144 struct udc_numaker_data {
145 uint8_t addr; /* Host assigned USB device address */
146
147 struct k_msgq *msgq;
148
149 struct numaker_usbd_ep_mgmt ep_mgmt; /* EP management */
150
151 struct numaker_usbd_ep *ep_pool;
152 uint32_t ep_pool_size;
153
154 struct k_thread thread_data;
155
156 /* Track end of CTRL DATA OUT/STATUS OUT stage
157 *
158 * net_buf can over-allocate for UDC_BUF_GRANULARITY requirement
159 * and net_buf_tailroom() cannot reflect free buffer room exactly
160 * as allocate request. Manually track it instead.
161 */
162 uint32_t ctrlout_tailroom;
163 };
164
numaker_usbd_sw_connect(const struct device * dev)165 static inline void numaker_usbd_sw_connect(const struct device *dev)
166 {
167 const struct udc_numaker_config *config = dev->config;
168 USBD_T *const base = config->base;
169
170 /* Clear all interrupts first for clean */
171 base->INTSTS = base->INTSTS;
172
173 /* Enable relevant interrupts */
174 base->INTEN = USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP | USBD_INT_SOF;
175
176 /* Clear SE0 for connect */
177 base->SE0 &= ~USBD_DRVSE0;
178 }
179
numaker_usbd_sw_disconnect(const struct device * dev)180 static inline void numaker_usbd_sw_disconnect(const struct device *dev)
181 {
182 const struct udc_numaker_config *config = dev->config;
183 USBD_T *const base = config->base;
184
185 /* Set SE0 for disconnect */
186 base->SE0 |= USBD_DRVSE0;
187 }
188
numaker_usbd_sw_reconnect(const struct device * dev)189 static inline void numaker_usbd_sw_reconnect(const struct device *dev)
190 {
191 /* Keep SE0 to trigger bus reset */
192 numaker_usbd_sw_disconnect(dev);
193 k_sleep(K_USEC(NUMAKER_USBD_BUS_RESET_DRV_SE0_US));
194 numaker_usbd_sw_connect(dev);
195 }
196
numaker_usbd_reset_addr(const struct device * dev)197 static inline void numaker_usbd_reset_addr(const struct device *dev)
198 {
199 const struct udc_numaker_config *config = dev->config;
200 struct udc_numaker_data *priv = udc_get_private(dev);
201 USBD_T *const base = config->base;
202
203 base->FADDR = 0;
204 priv->addr = 0;
205 }
206
numaker_usbd_set_addr(const struct device * dev)207 static inline void numaker_usbd_set_addr(const struct device *dev)
208 {
209 const struct udc_numaker_config *config = dev->config;
210 struct udc_numaker_data *priv = udc_get_private(dev);
211 USBD_T *const base = config->base;
212
213 if (base->FADDR != priv->addr) {
214 base->FADDR = priv->addr;
215 }
216 }
217
218 /* USBD EP base by e.g. EP0, EP1, ... */
numaker_usbd_ep_base(const struct device * dev,uint32_t ep_hw_idx)219 static inline USBD_EP_T *numaker_usbd_ep_base(const struct device *dev, uint32_t ep_hw_idx)
220 {
221 const struct udc_numaker_config *config = dev->config;
222 USBD_T *const base = config->base;
223
224 return base->EP + ep_hw_idx;
225 }
226
numaker_usbd_ep_sync_udc_halt(struct numaker_usbd_ep * ep_cur,bool stalled)227 static inline void numaker_usbd_ep_sync_udc_halt(struct numaker_usbd_ep *ep_cur, bool stalled)
228 {
229 const struct device *dev = ep_cur->dev;
230 struct udc_ep_config *ep_cfg;
231
232 __ASSERT_NO_MSG(ep_cur->addr_valid);
233 ep_cfg = udc_get_ep_cfg(dev, ep_cur->addr);
234 ep_cfg->stat.halted = stalled;
235 }
236
numaker_usbd_ep_set_stall(struct numaker_usbd_ep * ep_cur)237 static inline void numaker_usbd_ep_set_stall(struct numaker_usbd_ep *ep_cur)
238 {
239 const struct device *dev = ep_cur->dev;
240 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
241
242 /* Set EP to stalled */
243 ep_base->CFGP |= USBD_CFGP_SSTALL_Msk;
244 numaker_usbd_ep_sync_udc_halt(ep_cur, true);
245 }
246
247 /* Reset EP to unstalled and data toggle bit to 0 */
numaker_usbd_ep_clear_stall_n_data_toggle(struct numaker_usbd_ep * ep_cur)248 static inline void numaker_usbd_ep_clear_stall_n_data_toggle(struct numaker_usbd_ep *ep_cur)
249 {
250 const struct device *dev = ep_cur->dev;
251 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
252
253 /* Reset EP to unstalled */
254 ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk;
255 numaker_usbd_ep_sync_udc_halt(ep_cur, false);
256
257 /* Reset EP data toggle bit to 0 */
258 ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk;
259 }
260
numaker_usbd_send_msg(const struct device * dev,const struct numaker_usbd_msg * msg)261 static int numaker_usbd_send_msg(const struct device *dev, const struct numaker_usbd_msg *msg)
262 {
263 struct udc_numaker_data *priv = udc_get_private(dev);
264 int err;
265
266 err = k_msgq_put(priv->msgq, msg, K_NO_WAIT);
267 if (err < 0) {
268 /* Try to recover by S/W reconnect */
269 struct numaker_usbd_msg msg_reconn = {
270 .type = NUMAKER_USBD_MSG_TYPE_SW_RECONN,
271 };
272
273 LOG_ERR("Message queue overflow");
274
275 /* Discard all not yet received messages for error recovery below */
276 k_msgq_purge(priv->msgq);
277
278 err = k_msgq_put(priv->msgq, &msg_reconn, K_NO_WAIT);
279 if (err < 0) {
280 LOG_ERR("Message queue overflow again");
281 }
282 }
283
284 return err;
285 }
286
numaker_usbd_hw_setup(const struct device * dev)287 static int numaker_usbd_hw_setup(const struct device *dev)
288 {
289 const struct udc_numaker_config *config = dev->config;
290 USBD_T *const base = config->base;
291 int err;
292 struct numaker_scc_subsys scc_subsys;
293
294 /* Reset controller ready? */
295 if (!device_is_ready(config->reset.dev)) {
296 LOG_ERR("Reset controller not ready");
297 return -ENODEV;
298 }
299
300 SYS_UnlockReg();
301
302 /* Configure USB PHY for USBD */
303 SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_USBROLE_Msk) |
304 (SYS_USBPHY_USBROLE_STD_USBD | SYS_USBPHY_USBEN_Msk | SYS_USBPHY_SBO_Msk);
305
306 /* Invoke Clock controller to enable module clock */
307 memset(&scc_subsys, 0x00, sizeof(scc_subsys));
308 scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC;
309 scc_subsys.pcc.clk_modidx = config->clk_modidx;
310 scc_subsys.pcc.clk_src = config->clk_src;
311 scc_subsys.pcc.clk_div = config->clk_div;
312
313 /* Equivalent to CLK_EnableModuleClock() */
314 err = clock_control_on(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys);
315 if (err < 0) {
316 goto cleanup;
317 }
318 /* Equivalent to CLK_SetModuleClock() */
319 err = clock_control_configure(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys,
320 NULL);
321 if (err < 0) {
322 goto cleanup;
323 }
324
325 /* Configure pinmux (NuMaker's SYS MFP) */
326 err = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT);
327 if (err < 0) {
328 goto cleanup;
329 }
330
331 /* Invoke Reset controller to reset module to default state */
332 /* Equivalent to SYS_ResetModule()
333 */
334 reset_line_toggle_dt(&config->reset);
335
336 /* Initialize USBD engine */
337 /* NOTE: BSP USBD driver: ATTR = 0x7D0 */
338 base->ATTR = USBD_ATTR_BYTEM_Msk | BIT(9) | USBD_ATTR_DPPUEN_Msk | USBD_ATTR_USBEN_Msk |
339 BIT(6) | USBD_ATTR_PHYEN_Msk;
340
341 /* Set SE0 for S/W disconnect */
342 numaker_usbd_sw_disconnect(dev);
343
344 /* NOTE: Ignore DT maximum-speed with USBD fixed to full-speed */
345
346 /* Initialize IRQ */
347 config->irq_config_func(dev);
348
349 cleanup:
350
351 SYS_LockReg();
352
353 return err;
354 }
355
numaker_usbd_hw_shutdown(const struct device * dev)356 static void numaker_usbd_hw_shutdown(const struct device *dev)
357 {
358 const struct udc_numaker_config *config = dev->config;
359 USBD_T *const base = config->base;
360 struct numaker_scc_subsys scc_subsys;
361
362 SYS_UnlockReg();
363
364 /* Uninitialize IRQ */
365 config->irq_unconfig_func(dev);
366
367 /* Set SE0 for S/W disconnect */
368 numaker_usbd_sw_disconnect(dev);
369
370 /* Disable USB PHY */
371 base->ATTR &= ~USBD_PHY_EN;
372
373 /* Invoke Clock controller to disable module clock */
374 memset(&scc_subsys, 0x00, sizeof(scc_subsys));
375 scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC;
376 scc_subsys.pcc.clk_modidx = config->clk_modidx;
377
378 /* Equivalent to CLK_DisableModuleClock() */
379 clock_control_off(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys);
380
381 /* Invoke Reset controller to reset module to default state */
382 /* Equivalent to SYS_ResetModule() */
383 reset_line_toggle_dt(&config->reset);
384
385 SYS_LockReg();
386 }
387
388 /* Interrupt top half processing for bus reset */
numaker_usbd_bus_reset_th(const struct device * dev)389 static void numaker_usbd_bus_reset_th(const struct device *dev)
390 {
391 struct udc_numaker_data *priv = udc_get_private(dev);
392 USBD_EP_T *ep_base;
393
394 for (uint32_t i = 0ul; i < priv->ep_pool_size; i++) {
395 ep_base = numaker_usbd_ep_base(dev, EP0 + i);
396
397 /* Cancel EP on-going transaction */
398 ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk;
399
400 /* Reset EP to unstalled */
401 ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk;
402
403 /* Reset EP data toggle bit to 0 */
404 ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk;
405
406 /* Except EP0/EP1 kept resident for CTRL OUT/IN, disable all other EPs */
407 if (i >= 2) {
408 ep_base->CFG = 0;
409 }
410 }
411
412 numaker_usbd_reset_addr(dev);
413 }
414
415 /* USBD SRAM base for DMA */
numaker_usbd_buf_base(const struct device * dev)416 static inline uint32_t numaker_usbd_buf_base(const struct device *dev)
417 {
418 const struct udc_numaker_config *config = dev->config;
419 USBD_T *const base = config->base;
420
421 return ((uint32_t)base + 0x800ul);
422 }
423
424 /* Copy Setup packet to user buffer */
numaker_usbd_setup_copy_to_user(const struct device * dev,uint8_t * usrbuf)425 static void numaker_usbd_setup_copy_to_user(const struct device *dev, uint8_t *usrbuf)
426 {
427 const struct udc_numaker_config *config = dev->config;
428 USBD_T *const base = config->base;
429 uint32_t dmabuf_addr;
430
431 dmabuf_addr = numaker_usbd_buf_base(dev) + (base->STBUFSEG & USBD_STBUFSEG_STBUFSEG_Msk);
432
433 bytecpy(usrbuf, (uint8_t *)dmabuf_addr, 8ul);
434 }
435
436 /* Copy data to user buffer
437 *
438 * size_p holds size to copy/copied on input/output
439 */
numaker_usbd_ep_copy_to_user(struct numaker_usbd_ep * ep_cur,uint8_t * usrbuf,uint32_t * size_p,uint32_t * rmn_p)440 static void numaker_usbd_ep_copy_to_user(struct numaker_usbd_ep *ep_cur, uint8_t *usrbuf,
441 uint32_t *size_p, uint32_t *rmn_p)
442 {
443 const struct device *dev = ep_cur->dev;
444 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
445 uint32_t dmabuf_addr;
446 uint32_t data_rmn;
447
448 __ASSERT_NO_MSG(size_p);
449 __ASSERT_NO_MSG(ep_cur->dmabuf_valid);
450
451 dmabuf_addr = numaker_usbd_buf_base(dev) + ep_base->BUFSEG;
452
453 /* NOTE: See comment on mxpld_ctrlout for why make one copy of CTRL OUT's MXPLD */
454 if (ep_cur->addr == USB_CONTROL_EP_OUT) {
455 data_rmn = ep_cur->mxpld_ctrlout;
456 } else {
457 data_rmn = ep_base->MXPLD;
458 }
459
460 *size_p = MIN(*size_p, data_rmn);
461
462 bytecpy(usrbuf, (uint8_t *)dmabuf_addr, *size_p);
463 data_rmn -= *size_p;
464
465 if (rmn_p) {
466 *rmn_p = data_rmn;
467 }
468 }
469
470 /* Copy data from user buffer
471 *
472 * size_p holds size to copy/copied on input/output
473 */
numaker_usbd_ep_copy_from_user(struct numaker_usbd_ep * ep_cur,const uint8_t * usrbuf,uint32_t * size_p)474 static void numaker_usbd_ep_copy_from_user(struct numaker_usbd_ep *ep_cur, const uint8_t *usrbuf,
475 uint32_t *size_p)
476 {
477 const struct device *dev = ep_cur->dev;
478 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
479 uint32_t dmabuf_addr;
480
481 __ASSERT_NO_MSG(size_p);
482 __ASSERT_NO_MSG(ep_cur->dmabuf_valid);
483 __ASSERT_NO_MSG(ep_cur->mps_valid);
484 __ASSERT_NO_MSG(ep_cur->mps <= ep_cur->dmabuf_size);
485
486 dmabuf_addr = numaker_usbd_buf_base(dev) + ep_base->BUFSEG;
487
488 *size_p = MIN(*size_p, ep_cur->mps);
489
490 bytecpy((uint8_t *)dmabuf_addr, (uint8_t *)usrbuf, *size_p);
491 }
492
numaker_usbd_ep_config_dmabuf(struct numaker_usbd_ep * ep_cur,uint32_t dmabuf_base,uint32_t dmabuf_size)493 static void numaker_usbd_ep_config_dmabuf(struct numaker_usbd_ep *ep_cur, uint32_t dmabuf_base,
494 uint32_t dmabuf_size)
495 {
496 const struct device *dev = ep_cur->dev;
497 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
498
499 ep_base->BUFSEG = dmabuf_base;
500
501 ep_cur->dmabuf_valid = true;
502 ep_cur->dmabuf_base = dmabuf_base;
503 ep_cur->dmabuf_size = dmabuf_size;
504 }
505
numaker_usbd_ep_abort(struct numaker_usbd_ep * ep_cur)506 static void numaker_usbd_ep_abort(struct numaker_usbd_ep *ep_cur)
507 {
508 const struct device *dev = ep_cur->dev;
509 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
510
511 /* Abort EP on-going transaction */
512 ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk;
513
514 if (ep_cur->addr_valid) {
515 udc_ep_set_busy(dev, ep_cur->addr, false);
516 }
517 }
518
519 /* Configure EP major common parts */
numaker_usbd_ep_config_major(struct numaker_usbd_ep * ep_cur,struct udc_ep_config * const ep_cfg)520 static void numaker_usbd_ep_config_major(struct numaker_usbd_ep *ep_cur,
521 struct udc_ep_config *const ep_cfg)
522 {
523 const struct device *dev = ep_cur->dev;
524 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
525
526 ep_cur->mps_valid = true;
527 ep_cur->mps = ep_cfg->mps;
528
529 /* Configure EP transfer type, DATA0/1 toggle, direction, number, etc. */
530 ep_cur->ep_hw_cfg = 0;
531
532 /* Clear STALL Response in Setup stage */
533 if ((ep_cfg->attributes & USB_EP_TRANSFER_TYPE_MASK) == USB_EP_TYPE_CONTROL) {
534 ep_cur->ep_hw_cfg |= USBD_CFG_CSTALL;
535 }
536
537 /* Default to DATA0 */
538 ep_cur->ep_hw_cfg &= ~USBD_CFG_DSQSYNC_Msk;
539
540 /* Endpoint IN/OUT, though, default to disabled */
541 ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_DISABLE;
542
543 /* Isochronous or not */
544 if ((ep_cfg->attributes & USB_EP_TRANSFER_TYPE_MASK) == USB_EP_TYPE_ISO) {
545 ep_cur->ep_hw_cfg |= USBD_CFG_TYPE_ISO;
546 }
547
548 /* Endpoint index */
549 ep_cur->ep_hw_cfg |=
550 (USB_EP_GET_IDX(ep_cfg->addr) << USBD_CFG_EPNUM_Pos) & USBD_CFG_EPNUM_Msk;
551
552 ep_base->CFG = ep_cur->ep_hw_cfg;
553 }
554
numaker_usbd_ep_enable(struct numaker_usbd_ep * ep_cur)555 static void numaker_usbd_ep_enable(struct numaker_usbd_ep *ep_cur)
556 {
557 const struct device *dev = ep_cur->dev;
558 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
559
560 /* For safe, EP (re-)enable from clean state */
561 numaker_usbd_ep_abort(ep_cur);
562 numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur);
563
564 /* Enable EP to IN/OUT */
565 ep_cur->ep_hw_cfg &= ~USBD_CFG_STATE_Msk;
566 if (USB_EP_DIR_IS_IN(ep_cur->addr)) {
567 ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_IN;
568 } else {
569 ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_OUT;
570 }
571
572 ep_base->CFG = ep_cur->ep_hw_cfg;
573
574 /* For USBD, no separate EP interrupt control */
575 }
576
numaker_usbd_ep_disable(struct numaker_usbd_ep * ep_cur)577 static void numaker_usbd_ep_disable(struct numaker_usbd_ep *ep_cur)
578 {
579 const struct device *dev = ep_cur->dev;
580 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
581
582 /* For USBD, no separate EP interrupt control */
583
584 /* Disable EP */
585 ep_cur->ep_hw_cfg = (ep_cur->ep_hw_cfg & ~USBD_CFG_STATE_Msk) | USBD_CFG_EPMODE_DISABLE;
586 ep_base->CFG = ep_cur->ep_hw_cfg;
587 }
588
589 /* Start EP data transaction */
udc_numaker_ep_trigger(struct numaker_usbd_ep * ep_cur,uint32_t len)590 static void udc_numaker_ep_trigger(struct numaker_usbd_ep *ep_cur, uint32_t len)
591 {
592 const struct device *dev = ep_cur->dev;
593 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx);
594
595 if (ep_cur->addr_valid) {
596 udc_ep_set_busy(dev, ep_cur->addr, true);
597 }
598
599 ep_base->MXPLD = len;
600 }
601
numaker_usbd_ep_mgmt_alloc_ep(const struct device * dev)602 static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_alloc_ep(const struct device *dev)
603 {
604 struct udc_numaker_data *priv = udc_get_private(dev);
605 struct numaker_usbd_ep_mgmt *ep_mgmt = &priv->ep_mgmt;
606 struct numaker_usbd_ep *ep_cur = NULL;
607
608 if (ep_mgmt->ep_idx < priv->ep_pool_size) {
609 ep_cur = priv->ep_pool + ep_mgmt->ep_idx;
610 ep_mgmt->ep_idx++;
611
612 __ASSERT_NO_MSG(!ep_cur->valid);
613
614 /* Indicate this EP H/W context is allocated */
615 ep_cur->valid = true;
616 }
617
618 return ep_cur;
619 }
620
621 /* Allocate DMA buffer
622 *
623 * Return -ENOMEM on OOM error, or 0 on success with DMA buffer base/size (rounded up) allocated
624 */
numaker_usbd_ep_mgmt_alloc_dmabuf(const struct device * dev,uint32_t size,uint32_t * dmabuf_base_p,uint32_t * dmabuf_size_p)625 static int numaker_usbd_ep_mgmt_alloc_dmabuf(const struct device *dev, uint32_t size,
626 uint32_t *dmabuf_base_p, uint32_t *dmabuf_size_p)
627 {
628 const struct udc_numaker_config *config = dev->config;
629 struct udc_numaker_data *priv = udc_get_private(dev);
630 struct numaker_usbd_ep_mgmt *ep_mgmt = &priv->ep_mgmt;
631
632 __ASSERT_NO_MSG(dmabuf_base_p);
633 __ASSERT_NO_MSG(dmabuf_size_p);
634
635 /* Required to be 8-byte aligned */
636 size = ROUND_UP(size, 8);
637
638 ep_mgmt->dmabuf_pos += size;
639 if (ep_mgmt->dmabuf_pos > config->dmabuf_size) {
640 ep_mgmt->dmabuf_pos -= size;
641 return -ENOMEM;
642 }
643
644 *dmabuf_base_p = ep_mgmt->dmabuf_pos - size;
645 *dmabuf_size_p = size;
646 return 0;
647 }
648
649 /* Initialize all EP H/W contexts */
numaker_usbd_ep_mgmt_init(const struct device * dev)650 static void numaker_usbd_ep_mgmt_init(const struct device *dev)
651 {
652 const struct udc_numaker_config *config = dev->config;
653 struct udc_numaker_data *priv = udc_get_private(dev);
654 USBD_T *const base = config->base;
655 struct numaker_usbd_ep_mgmt *ep_mgmt = &priv->ep_mgmt;
656
657 struct numaker_usbd_ep *ep_cur;
658 struct numaker_usbd_ep *ep_end;
659
660 /* Initialize all fields to zero for clean state */
661 memset(ep_mgmt, 0x00, sizeof(*ep_mgmt));
662
663 ep_cur = priv->ep_pool;
664 ep_end = priv->ep_pool + priv->ep_pool_size;
665
666 /* Initialize all EP H/W contexts */
667 for (; ep_cur != ep_end; ep_cur++) {
668 /* Zero-initialize */
669 memset(ep_cur, 0x00, sizeof(*ep_cur));
670
671 /* Pointer to the containing device */
672 ep_cur->dev = dev;
673
674 /* BSP USBD driver EP handle */
675 ep_cur->ep_hw_idx = EP0 + (ep_cur - priv->ep_pool);
676 }
677
678 /* Reserve 1st/2nd EP H/W contexts (BSP USBD driver EP0/EP1) for CTRL OUT/IN */
679 ep_mgmt->ep_idx = 2;
680
681 /* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, starting from 0 */
682 ep_mgmt->dmabuf_pos = 0;
683
684 /* Configure DMA buffer for Setup packet */
685 base->STBUFSEG = ep_mgmt->dmabuf_pos;
686 ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_SETUP;
687
688 /* Reserve 1st EP H/W context (BSP USBD driver EP0) for CTRL OUT */
689 ep_cur = priv->ep_pool + 0;
690 ep_cur->valid = true;
691 ep_cur->addr_valid = true;
692 ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_OUT);
693 numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos,
694 NUMAKER_USBD_DMABUF_SIZE_CTRLOUT);
695 ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLOUT;
696 ep_cur->mps_valid = true;
697 ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLOUT;
698
699 /* Reserve 2nd EP H/W context (BSP USBD driver EP1) for CTRL IN */
700 ep_cur = priv->ep_pool + 1;
701 ep_cur->valid = true;
702 ep_cur->addr_valid = true;
703 ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_IN);
704 numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos, NUMAKER_USBD_DMABUF_SIZE_CTRLIN);
705 ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLIN;
706 ep_cur->mps_valid = true;
707 ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLIN;
708 }
709
710 /* Find EP H/W context by EP address */
numaker_usbd_ep_mgmt_find_ep(const struct device * dev,const uint8_t ep)711 static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_find_ep(const struct device *dev,
712 const uint8_t ep)
713 {
714 struct udc_numaker_data *priv = udc_get_private(dev);
715 struct numaker_usbd_ep *ep_cur = priv->ep_pool;
716 struct numaker_usbd_ep *ep_end = priv->ep_pool + priv->ep_pool_size;
717
718 for (; ep_cur != ep_end; ep_cur++) {
719 if (!ep_cur->valid) {
720 continue;
721 }
722
723 if (!ep_cur->addr_valid) {
724 continue;
725 }
726
727 if (ep == ep_cur->addr) {
728 return ep_cur;
729 }
730 }
731
732 return NULL;
733 }
734
735 /* Bind EP H/W context to EP address */
numaker_usbd_ep_mgmt_bind_ep(const struct device * dev,const uint8_t ep)736 static struct numaker_usbd_ep *numaker_usbd_ep_mgmt_bind_ep(const struct device *dev,
737 const uint8_t ep)
738 {
739 struct numaker_usbd_ep *ep_cur = numaker_usbd_ep_mgmt_find_ep(dev, ep);
740
741 if (!ep_cur) {
742 ep_cur = numaker_usbd_ep_mgmt_alloc_ep(dev);
743
744 if (!ep_cur) {
745 return NULL;
746 }
747
748 /* Bind EP H/W context to EP address */
749 ep_cur->addr = ep;
750 ep_cur->addr_valid = true;
751 }
752
753 /* Assert EP H/W context bound to EP address */
754 __ASSERT_NO_MSG(ep_cur->valid);
755 __ASSERT_NO_MSG(ep_cur->addr_valid);
756 __ASSERT_NO_MSG(ep_cur->addr == ep);
757
758 return ep_cur;
759 }
760
numaker_usbd_xfer_out(const struct device * dev,uint8_t ep,bool strict)761 static int numaker_usbd_xfer_out(const struct device *dev, uint8_t ep, bool strict)
762 {
763 struct net_buf *buf;
764 struct numaker_usbd_ep *ep_cur;
765
766 if (!USB_EP_DIR_IS_OUT(ep)) {
767 LOG_ERR("Invalid EP address 0x%02x for data out", ep);
768 return -EINVAL;
769 }
770
771 if (udc_ep_is_busy(dev, ep)) {
772 if (strict) {
773 LOG_ERR("EP 0x%02x busy", ep);
774 return -EAGAIN;
775 }
776
777 return 0;
778 }
779
780 buf = udc_buf_peek(dev, ep);
781 if (buf == NULL) {
782 if (strict) {
783 LOG_ERR("No buffer queued for EP 0x%02x", ep);
784 return -ENODATA;
785 }
786
787 return 0;
788 }
789
790 /* Bind EP H/W context to EP address */
791 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
792 if (!ep_cur) {
793 LOG_ERR("Bind EP H/W context: ep=0x%02x", ep);
794 return -ENODEV;
795 }
796
797 udc_numaker_ep_trigger(ep_cur, ep_cur->mps);
798
799 return 0;
800 }
801
numaker_usbd_xfer_in(const struct device * dev,uint8_t ep,bool strict)802 static int numaker_usbd_xfer_in(const struct device *dev, uint8_t ep, bool strict)
803 {
804 struct net_buf *buf;
805 struct numaker_usbd_ep *ep_cur;
806 uint32_t data_len;
807
808 if (!USB_EP_DIR_IS_IN(ep)) {
809 LOG_ERR("Invalid EP address 0x%02x for data in", ep);
810 return -EINVAL;
811 }
812
813 if (udc_ep_is_busy(dev, ep)) {
814 if (strict) {
815 LOG_ERR("EP 0x%02x busy", ep);
816 return -EAGAIN;
817 }
818
819 return 0;
820 }
821
822 buf = udc_buf_peek(dev, ep);
823 if (buf == NULL) {
824 if (strict) {
825 LOG_ERR("No buffer queued for EP 0x%02x", ep);
826 return -ENODATA;
827 }
828
829 return 0;
830 }
831
832 /* Bind EP H/W context to EP address */
833 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
834 if (!ep_cur) {
835 LOG_ERR("ep=0x%02x", ep);
836 return -ENODEV;
837 }
838
839 data_len = buf->len;
840 if (data_len) {
841 numaker_usbd_ep_copy_from_user(ep_cur, buf->data, &data_len);
842 net_buf_pull(buf, data_len);
843 } else if (udc_ep_buf_has_zlp(buf)) {
844 /* zlp, send exactly once */
845 udc_ep_buf_clear_zlp(buf);
846 } else {
847 /* initially empty net_buf, send exactly once */
848 }
849
850 udc_numaker_ep_trigger(ep_cur, data_len);
851
852 return 0;
853 }
854
numaker_usbd_ctrl_feed_dout(const struct device * dev,const size_t length)855 static int numaker_usbd_ctrl_feed_dout(const struct device *dev, const size_t length)
856 {
857 struct udc_numaker_data *priv = udc_get_private(dev);
858 struct udc_ep_config *ep_cfg;
859 struct net_buf *buf;
860
861 ep_cfg = udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT);
862 if (ep_cfg == NULL) {
863 LOG_ERR("Bind udc_ep_config: ep=0x%02x", USB_CONTROL_EP_OUT);
864 return -ENODEV;
865 }
866
867 buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, length);
868 if (buf == NULL) {
869 LOG_ERR("Allocate net_buf: ep=0x%02x", USB_CONTROL_EP_OUT);
870 return -ENOMEM;
871 }
872 priv->ctrlout_tailroom = length;
873
874 k_fifo_put(&ep_cfg->fifo, buf);
875
876 return numaker_usbd_xfer_out(dev, ep_cfg->addr, true);
877 }
878
879 /* Message handler for Setup transaction completed */
numaker_usbd_msg_handle_setup(const struct device * dev,struct numaker_usbd_msg * msg)880 static int numaker_usbd_msg_handle_setup(const struct device *dev, struct numaker_usbd_msg *msg)
881 {
882 int err;
883 uint8_t ep;
884 struct numaker_usbd_ep *ep_cur;
885 struct net_buf *buf;
886 uint8_t *data_ptr;
887
888 __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_SETUP);
889
890 ep = USB_CONTROL_EP_OUT;
891
892 /* Bind EP H/W context to EP address */
893 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
894 if (!ep_cur) {
895 LOG_ERR("Bind EP H/W context: ep=0x%02x", ep);
896 return -ENODEV;
897 }
898
899 /* We should have reserved 1st/2nd EP H/W contexts for CTRL OUT/IN */
900 __ASSERT_NO_MSG(ep_cur->addr == USB_CONTROL_EP_OUT);
901 __ASSERT_NO_MSG((ep_cur + 1)->addr == USB_CONTROL_EP_IN);
902
903 /* Abort previous CTRL OUT/IN */
904 numaker_usbd_ep_abort(ep_cur);
905 numaker_usbd_ep_abort(ep_cur + 1);
906
907 /* CTRL OUT/IN reset to unstalled by H/W on receive of Setup packet */
908 numaker_usbd_ep_sync_udc_halt(ep_cur, false);
909 numaker_usbd_ep_sync_udc_halt(ep_cur + 1, false);
910
911 buf = udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, 8);
912 if (buf == NULL) {
913 LOG_ERR("Failed to allocate for Setup");
914 return -ENOMEM;
915 }
916
917 udc_ep_buf_set_setup(buf);
918 data_ptr = net_buf_tail(buf);
919 numaker_usbd_setup_copy_to_user(dev, data_ptr);
920 net_buf_add(buf, 8);
921
922 /* Update to next stage of CTRL transfer */
923 udc_ctrl_update_stage(dev, buf);
924
925 if (udc_ctrl_stage_is_data_out(dev)) {
926 /* Allocate and feed buffer for DATA OUT stage */
927 err = numaker_usbd_ctrl_feed_dout(dev, udc_data_stage_length(buf));
928 if (err == -ENOMEM) {
929 err = udc_submit_ep_event(dev, buf, err);
930 }
931 } else if (udc_ctrl_stage_is_data_in(dev)) {
932 err = udc_ctrl_submit_s_in_status(dev);
933 } else {
934 err = udc_ctrl_submit_s_status(dev);
935 }
936
937 return err;
938 }
939
940 /* Message handler for DATA OUT transaction completed */
numaker_usbd_msg_handle_out(const struct device * dev,struct numaker_usbd_msg * msg)941 static int numaker_usbd_msg_handle_out(const struct device *dev, struct numaker_usbd_msg *msg)
942 {
943 struct udc_numaker_data *priv = udc_get_private(dev);
944 int err;
945 uint8_t ep;
946 struct numaker_usbd_ep *ep_cur;
947 struct net_buf *buf;
948 uint8_t *data_ptr;
949 uint32_t data_len;
950 uint32_t data_rmn;
951
952 __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_OUT);
953
954 ep = msg->out.ep;
955
956 udc_ep_set_busy(dev, ep, false);
957
958 /* Bind EP H/W context to EP address */
959 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
960 if (!ep_cur) {
961 LOG_ERR("Bind EP H/W context: ep=0x%02x", ep);
962 return -ENODEV;
963 }
964
965 buf = udc_buf_peek(dev, ep);
966 if (buf == NULL) {
967 LOG_ERR("No buffer queued for ep=0x%02x", ep);
968 return -ENODATA;
969 }
970
971 if (ep == USB_CONTROL_EP_OUT) {
972 __ASSERT_NO_MSG(net_buf_tailroom(buf) >= priv->ctrlout_tailroom);
973 data_len = priv->ctrlout_tailroom;
974 } else {
975 data_len = net_buf_tailroom(buf);
976 }
977 data_ptr = net_buf_tail(buf);
978 numaker_usbd_ep_copy_to_user(ep_cur, data_ptr, &data_len, &data_rmn);
979 net_buf_add(buf, data_len);
980 if (ep == USB_CONTROL_EP_OUT) {
981 __ASSERT_NO_MSG(priv->ctrlout_tailroom >= data_len);
982 priv->ctrlout_tailroom -= data_len;
983 }
984
985 if (data_rmn) {
986 LOG_ERR("Buffer queued for ep=0x%02x cannot accommodate packet", ep);
987 return -ENOBUFS;
988 }
989
990 /* CTRL DATA OUT/STATUS OUT stage completed */
991 if (ep == USB_CONTROL_EP_OUT && priv->ctrlout_tailroom != 0) {
992 goto next_xfer;
993 }
994
995 /* To submit the peeked buffer */
996 udc_buf_get(dev, ep);
997
998 if (ep == USB_CONTROL_EP_OUT) {
999 if (udc_ctrl_stage_is_status_out(dev)) {
1000 /* s-in-status finished */
1001 err = udc_ctrl_submit_status(dev, buf);
1002 if (err < 0) {
1003 LOG_ERR("udc_ctrl_submit_status failed for s-in-status: %d", err);
1004 return err;
1005 }
1006 }
1007
1008 /* Update to next stage of CTRL transfer */
1009 udc_ctrl_update_stage(dev, buf);
1010
1011 if (udc_ctrl_stage_is_status_in(dev)) {
1012 err = udc_ctrl_submit_s_out_status(dev, buf);
1013 if (err < 0) {
1014 LOG_ERR("udc_ctrl_submit_s_out_status failed for s-out-status: %d",
1015 err);
1016 return err;
1017 }
1018 }
1019 } else {
1020 err = udc_submit_ep_event(dev, buf, 0);
1021 if (err < 0) {
1022 LOG_ERR("udc_submit_ep_event failed for ep=0x%02x: %d", ep, err);
1023 return err;
1024 }
1025 }
1026
1027 next_xfer:
1028 /* Continue with next DATA OUT transaction on request */
1029 numaker_usbd_xfer_out(dev, ep, false);
1030
1031 return 0;
1032 }
1033
1034 /* Message handler for DATA IN transaction completed */
numaker_usbd_msg_handle_in(const struct device * dev,struct numaker_usbd_msg * msg)1035 static int numaker_usbd_msg_handle_in(const struct device *dev, struct numaker_usbd_msg *msg)
1036 {
1037 int err;
1038 uint8_t ep;
1039 struct numaker_usbd_ep *ep_cur;
1040 struct net_buf *buf;
1041
1042 __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_IN);
1043
1044 ep = msg->in.ep;
1045
1046 udc_ep_set_busy(dev, ep, false);
1047
1048 /* Bind EP H/W context to EP address */
1049 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep);
1050 if (!ep_cur) {
1051 LOG_ERR("Bind EP H/W context: ep=0x%02x", ep);
1052 return -ENODEV;
1053 }
1054
1055 buf = udc_buf_peek(dev, ep);
1056 if (buf == NULL) {
1057 /* No DATA IN request */
1058 return 0;
1059 }
1060
1061 if (buf->len || udc_ep_buf_has_zlp(buf)) {
1062 goto xfer_next;
1063 }
1064
1065 /* To submit the peeked buffer */
1066 udc_buf_get(dev, ep);
1067
1068 if (ep == USB_CONTROL_EP_IN) {
1069 if (udc_ctrl_stage_is_status_in(dev) || udc_ctrl_stage_is_no_data(dev)) {
1070 /* s-out-status/s-status finished */
1071 err = udc_ctrl_submit_status(dev, buf);
1072 if (err < 0) {
1073 LOG_ERR("udc_ctrl_submit_status failed for s-out-status/s-status: "
1074 "%d",
1075 err);
1076 return err;
1077 }
1078 }
1079
1080 /* Update to next stage of CTRL transfer */
1081 udc_ctrl_update_stage(dev, buf);
1082
1083 if (udc_ctrl_stage_is_status_out(dev)) {
1084 /* DATA IN stage finished, release buffer */
1085 net_buf_unref(buf);
1086
1087 /* Allocate and feed buffer for STATUS OUT stage */
1088 err = numaker_usbd_ctrl_feed_dout(dev, 0);
1089 if (err < 0) {
1090 LOG_ERR("ctrl_feed_dout failed for status out: %d", err);
1091 return err;
1092 }
1093 }
1094 } else {
1095 err = udc_submit_ep_event(dev, buf, 0);
1096 if (err < 0) {
1097 LOG_ERR("udc_submit_ep_event failed for ep=0x%02x: %d", ep, err);
1098 return err;
1099 }
1100 }
1101
1102 xfer_next:
1103 /* Continue with next DATA IN transaction on request */
1104 numaker_usbd_xfer_in(dev, ep, false);
1105
1106 return 0;
1107 }
1108
1109 /* Message handler for queued transfer re-activated */
numaker_usbd_msg_handle_xfer(const struct device * dev,struct numaker_usbd_msg * msg)1110 static int numaker_usbd_msg_handle_xfer(const struct device *dev, struct numaker_usbd_msg *msg)
1111 {
1112 uint8_t ep;
1113
1114 __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_XFER);
1115
1116 ep = msg->xfer.ep;
1117
1118 if (USB_EP_DIR_IS_OUT(ep)) {
1119 numaker_usbd_xfer_out(dev, ep, false);
1120 } else {
1121 numaker_usbd_xfer_in(dev, ep, false);
1122 }
1123
1124 return 0;
1125 }
1126
1127 /* Message handler for S/W reconnect */
numaker_usbd_msg_handle_sw_reconn(const struct device * dev,struct numaker_usbd_msg * msg)1128 static int numaker_usbd_msg_handle_sw_reconn(const struct device *dev, struct numaker_usbd_msg *msg)
1129 {
1130 __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_SW_RECONN);
1131
1132 /* S/W reconnect for error recovery */
1133 numaker_usbd_sw_reconnect(dev);
1134
1135 return 0;
1136 }
1137
numaker_usbd_msg_handler(const struct device * dev)1138 static void numaker_usbd_msg_handler(const struct device *dev)
1139 {
1140 struct udc_numaker_data *priv = udc_get_private(dev);
1141 int err;
1142 struct numaker_usbd_msg msg;
1143
1144 while (true) {
1145 if (k_msgq_get(priv->msgq, &msg, K_FOREVER)) {
1146 continue;
1147 }
1148
1149 err = 0;
1150
1151 udc_lock_internal(dev, K_FOREVER);
1152
1153 switch (msg.type) {
1154 case NUMAKER_USBD_MSG_TYPE_SETUP:
1155 err = numaker_usbd_msg_handle_setup(dev, &msg);
1156 break;
1157
1158 case NUMAKER_USBD_MSG_TYPE_OUT:
1159 err = numaker_usbd_msg_handle_out(dev, &msg);
1160 break;
1161
1162 case NUMAKER_USBD_MSG_TYPE_IN:
1163 err = numaker_usbd_msg_handle_in(dev, &msg);
1164 break;
1165
1166 case NUMAKER_USBD_MSG_TYPE_XFER:
1167 err = numaker_usbd_msg_handle_xfer(dev, &msg);
1168 break;
1169
1170 case NUMAKER_USBD_MSG_TYPE_SW_RECONN:
1171 err = numaker_usbd_msg_handle_sw_reconn(dev, &msg);
1172 break;
1173
1174 default:
1175 __ASSERT_NO_MSG(false);
1176 }
1177
1178 udc_unlock_internal(dev);
1179
1180 if (err) {
1181 udc_submit_event(dev, UDC_EVT_ERROR, err);
1182 }
1183 }
1184 }
1185
numaker_udbd_isr(const struct device * dev)1186 static void numaker_udbd_isr(const struct device *dev)
1187 {
1188 const struct udc_numaker_config *config = dev->config;
1189 struct udc_numaker_data *priv = udc_get_private(dev);
1190 USBD_T *const base = config->base;
1191
1192 struct numaker_usbd_msg msg = {0};
1193
1194 uint32_t volatile usbd_intsts = base->INTSTS;
1195 uint32_t volatile usbd_bus_state = base->ATTR;
1196
1197 /* USB plug-in/unplug */
1198 if (usbd_intsts & USBD_INTSTS_FLDET) {
1199 /* Floating detect */
1200 base->INTSTS = USBD_INTSTS_FLDET;
1201
1202 if (base->VBUSDET & USBD_VBUSDET_VBUSDET_Msk) {
1203 /* USB plug-in */
1204
1205 /* Enable back USB/PHY */
1206 base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
1207
1208 /* UDC stack would handle bottom-half processing */
1209 udc_submit_event(dev, UDC_EVT_VBUS_READY, 0);
1210
1211 LOG_DBG("USB plug-in");
1212 } else {
1213 /* USB unplug */
1214
1215 /* Disable USB */
1216 base->ATTR &= ~USBD_USB_EN;
1217
1218 /* UDC stack would handle bottom-half processing */
1219 udc_submit_event(dev, UDC_EVT_VBUS_REMOVED, 0);
1220
1221 LOG_DBG("USB unplug");
1222 }
1223 }
1224
1225 /* USB wake-up */
1226 if (usbd_intsts & USBD_INTSTS_WAKEUP) {
1227 /* Clear event flag */
1228 base->INTSTS = USBD_INTSTS_WAKEUP;
1229
1230 LOG_DBG("USB wake-up");
1231 }
1232
1233 /* USB reset/suspend/resume */
1234 if (usbd_intsts & USBD_INTSTS_BUS) {
1235 /* Clear event flag */
1236 base->INTSTS = USBD_INTSTS_BUS;
1237
1238 if (usbd_bus_state & USBD_STATE_USBRST) {
1239 /* Bus reset */
1240
1241 /* Enable back USB/PHY */
1242 base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
1243
1244 /* Bus reset top half */
1245 numaker_usbd_bus_reset_th(dev);
1246
1247 /* UDC stack would handle bottom-half processing,
1248 * including reset device address (udc_set_address),
1249 * un-configure device (udc_ep_disable), etc.
1250 */
1251 udc_submit_event(dev, UDC_EVT_RESET, 0);
1252
1253 LOG_DBG("USB reset");
1254 }
1255 if (usbd_bus_state & USBD_STATE_SUSPEND) {
1256 /* Enable USB but disable PHY */
1257 base->ATTR &= ~USBD_PHY_EN;
1258
1259 /* UDC stack would handle bottom-half processing */
1260 udc_submit_event(dev, UDC_EVT_SUSPEND, 0);
1261
1262 LOG_DBG("USB suspend");
1263 }
1264 if (usbd_bus_state & USBD_STATE_RESUME) {
1265 /* Enable back USB/PHY */
1266 base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
1267
1268 /* UDC stack would handle bottom-half processing */
1269 udc_submit_event(dev, UDC_EVT_RESUME, 0);
1270
1271 LOG_DBG("USB resume");
1272 }
1273 }
1274
1275 /* USB SOF */
1276 if (usbd_intsts & USBD_INTSTS_SOFIF_Msk) {
1277 /* Clear event flag */
1278 base->INTSTS = USBD_INTSTS_SOFIF_Msk;
1279
1280 /* UDC stack would handle bottom-half processing */
1281 udc_submit_event(dev, UDC_EVT_SOF, 0);
1282 }
1283
1284 /* USB Setup/EP */
1285 if (usbd_intsts & USBD_INTSTS_USB) {
1286 uint32_t epintsts;
1287
1288 /* Setup event */
1289 if (usbd_intsts & USBD_INTSTS_SETUP) {
1290 USBD_EP_T *ep0_base = numaker_usbd_ep_base(dev, EP0);
1291 USBD_EP_T *ep1_base = numaker_usbd_ep_base(dev, EP1);
1292
1293 /* Clear event flag */
1294 base->INTSTS = USBD_INTSTS_SETUP;
1295
1296 /* Clear the data IN/OUT ready flag of control endpoints */
1297 ep0_base->CFGP |= USBD_CFGP_CLRRDY_Msk;
1298 ep1_base->CFGP |= USBD_CFGP_CLRRDY_Msk;
1299
1300 /* By USB spec, following transactions, regardless of Data/Status stage,
1301 * will always be DATA1
1302 */
1303 ep0_base->CFG |= USBD_CFG_DSQSYNC_Msk;
1304 ep1_base->CFG |= USBD_CFG_DSQSYNC_Msk;
1305
1306 /* Message for bottom-half processing */
1307 /* NOTE: In Zephyr USB device stack, Setup packet is passed via
1308 * CTRL OUT EP
1309 */
1310 msg.type = NUMAKER_USBD_MSG_TYPE_SETUP;
1311 numaker_usbd_setup_copy_to_user(dev, msg.setup.packet);
1312 numaker_usbd_send_msg(dev, &msg);
1313 }
1314
1315 /* EP events */
1316 epintsts = base->EPINTSTS;
1317
1318 base->EPINTSTS = epintsts;
1319
1320 while (epintsts) {
1321 uint32_t ep_hw_idx = u32_count_trailing_zeros(epintsts);
1322 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_hw_idx);
1323 uint8_t ep_dir;
1324 uint8_t ep_idx;
1325 uint8_t ep;
1326
1327 /* We don't enable INNAKEN interrupt, so as long as EP event occurs,
1328 * we can just regard one data transaction has completed (ACK for
1329 * CTRL/BULK/INT or no-ACK for Iso), that is, no need to check EPSTS0,
1330 * EPSTS1, etc.
1331 */
1332
1333 /* EP direction, number, and address */
1334 ep_dir = ((ep_base->CFG & USBD_CFG_STATE_Msk) == USBD_CFG_EPMODE_IN)
1335 ? USB_EP_DIR_IN
1336 : USB_EP_DIR_OUT;
1337 ep_idx = (ep_base->CFG & USBD_CFG_EPNUM_Msk) >> USBD_CFG_EPNUM_Pos;
1338 ep = USB_EP_GET_ADDR(ep_idx, ep_dir);
1339
1340 /* NOTE: See comment in udc_numaker_set_address()'s implementation
1341 * for safe place to change USB device address
1342 */
1343 if (ep == USB_EP_GET_ADDR(0, USB_EP_DIR_IN)) {
1344 numaker_usbd_set_addr(dev);
1345 }
1346
1347 /* NOTE: See comment on mxpld_ctrlout for why make one copy of
1348 * CTRL OUT's MXPLD
1349 */
1350 if (ep == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)) {
1351 struct numaker_usbd_ep *ep_ctrlout = priv->ep_pool + 0;
1352 USBD_EP_T *ep_ctrlout_base =
1353 numaker_usbd_ep_base(dev, ep_ctrlout->ep_hw_idx);
1354
1355 ep_ctrlout->mxpld_ctrlout = ep_ctrlout_base->MXPLD;
1356 }
1357
1358 /* Message for bottom-half processing */
1359 if (USB_EP_DIR_IS_OUT(ep)) {
1360 msg.type = NUMAKER_USBD_MSG_TYPE_OUT;
1361 msg.out.ep = ep;
1362 } else {
1363 msg.type = NUMAKER_USBD_MSG_TYPE_IN;
1364 msg.in.ep = ep;
1365 }
1366 numaker_usbd_send_msg(dev, &msg);
1367
1368 /* Have handled this EP and go next */
1369 epintsts &= ~BIT(ep_hw_idx);
1370 }
1371 }
1372 }
1373
udc_numaker_device_speed(const struct device * dev)1374 static enum udc_bus_speed udc_numaker_device_speed(const struct device *dev)
1375 {
1376 return UDC_BUS_SPEED_FS;
1377 }
1378
udc_numaker_ep_enqueue(const struct device * dev,struct udc_ep_config * const ep_cfg,struct net_buf * buf)1379 static int udc_numaker_ep_enqueue(const struct device *dev, struct udc_ep_config *const ep_cfg,
1380 struct net_buf *buf)
1381 {
1382 struct numaker_usbd_msg msg = {0};
1383
1384 LOG_DBG("%p enqueue %p", dev, buf);
1385 udc_buf_put(ep_cfg, buf);
1386
1387 /* Resume the EP's queued transfer */
1388 if (!ep_cfg->stat.halted) {
1389 msg.type = NUMAKER_USBD_MSG_TYPE_XFER;
1390 msg.xfer.ep = ep_cfg->addr;
1391 numaker_usbd_send_msg(dev, &msg);
1392 }
1393
1394 return 0;
1395 }
1396
udc_numaker_ep_dequeue(const struct device * dev,struct udc_ep_config * const ep_cfg)1397 static int udc_numaker_ep_dequeue(const struct device *dev, struct udc_ep_config *const ep_cfg)
1398 {
1399 struct net_buf *buf;
1400 struct numaker_usbd_ep *ep_cur;
1401
1402 /* Bind EP H/W context to EP address */
1403 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->addr);
1404 if (!ep_cur) {
1405 LOG_ERR("Bind EP H/W context: ep=0x%02x", ep_cfg->addr);
1406 return -ENODEV;
1407 }
1408
1409 numaker_usbd_ep_abort(ep_cur);
1410
1411 buf = udc_buf_get_all(dev, ep_cfg->addr);
1412 if (buf) {
1413 udc_submit_ep_event(dev, buf, -ECONNABORTED);
1414 }
1415
1416 return 0;
1417 }
1418
udc_numaker_ep_set_halt(const struct device * dev,struct udc_ep_config * const ep_cfg)1419 static int udc_numaker_ep_set_halt(const struct device *dev, struct udc_ep_config *const ep_cfg)
1420 {
1421 struct numaker_usbd_ep *ep_cur;
1422
1423 LOG_DBG("Set halt ep 0x%02x", ep_cfg->addr);
1424
1425 /* Bind EP H/W context to EP address */
1426 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->addr);
1427 if (!ep_cur) {
1428 LOG_ERR("Bind EP H/W context: ep=0x%02x", ep_cfg->addr);
1429 return -ENODEV;
1430 }
1431
1432 /* Set EP to stalled */
1433 numaker_usbd_ep_set_stall(ep_cur);
1434
1435 return 0;
1436 }
1437
udc_numaker_ep_clear_halt(const struct device * dev,struct udc_ep_config * const ep_cfg)1438 static int udc_numaker_ep_clear_halt(const struct device *dev, struct udc_ep_config *const ep_cfg)
1439 {
1440 struct numaker_usbd_ep *ep_cur;
1441 struct numaker_usbd_msg msg = {0};
1442
1443 LOG_DBG("Clear halt ep 0x%02x", ep_cfg->addr);
1444
1445 /* Bind EP H/W context to EP address */
1446 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->addr);
1447 if (!ep_cur) {
1448 LOG_ERR("Bind EP H/W context: ep=0x%02x", ep_cfg->addr);
1449 return -ENODEV;
1450 }
1451
1452 /* Reset EP to unstalled and data toggle bit to 0 */
1453 numaker_usbd_ep_clear_stall_n_data_toggle(ep_cur);
1454
1455 /* Resume the EP's queued transfer */
1456 msg.type = NUMAKER_USBD_MSG_TYPE_XFER;
1457 msg.xfer.ep = ep_cfg->addr;
1458 numaker_usbd_send_msg(dev, &msg);
1459
1460 return 0;
1461 }
1462
udc_numaker_ep_enable(const struct device * dev,struct udc_ep_config * const ep_cfg)1463 static int udc_numaker_ep_enable(const struct device *dev, struct udc_ep_config *const ep_cfg)
1464 {
1465 int err;
1466 uint32_t dmabuf_base;
1467 uint32_t dmabuf_size;
1468 struct numaker_usbd_ep *ep_cur;
1469
1470 LOG_DBG("Enable ep 0x%02x", ep_cfg->addr);
1471
1472 /* Bind EP H/W context to EP address */
1473 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->addr);
1474 if (!ep_cur) {
1475 LOG_ERR("Bind EP H/W context: ep=0x%02x", ep_cfg->addr);
1476 return -ENODEV;
1477 }
1478
1479 /* Configure EP DMA buffer */
1480 if (!ep_cur->dmabuf_valid || ep_cur->dmabuf_size < ep_cfg->mps) {
1481 /* Allocate DMA buffer */
1482 err = numaker_usbd_ep_mgmt_alloc_dmabuf(dev, ep_cfg->mps, &dmabuf_base,
1483 &dmabuf_size);
1484 if (err < 0) {
1485 LOG_ERR("Allocate DMA buffer failed");
1486 return err;
1487 }
1488
1489 /* Configure EP DMA buffer */
1490 numaker_usbd_ep_config_dmabuf(ep_cur, dmabuf_base, dmabuf_size);
1491 }
1492
1493 /* Configure EP majorly */
1494 numaker_usbd_ep_config_major(ep_cur, ep_cfg);
1495
1496 /* Enable EP */
1497 numaker_usbd_ep_enable(ep_cur);
1498
1499 return 0;
1500 }
1501
udc_numaker_ep_disable(const struct device * dev,struct udc_ep_config * const ep_cfg)1502 static int udc_numaker_ep_disable(const struct device *dev, struct udc_ep_config *const ep_cfg)
1503 {
1504 struct numaker_usbd_ep *ep_cur;
1505
1506 LOG_DBG("Disable ep 0x%02x", ep_cfg->addr);
1507
1508 /* Bind EP H/W context to EP address */
1509 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->addr);
1510 if (!ep_cur) {
1511 LOG_ERR("Bind EP H/W context: ep=0x%02x", ep_cfg->addr);
1512 return -ENODEV;
1513 }
1514
1515 /* Disable EP */
1516 numaker_usbd_ep_disable(ep_cur);
1517
1518 return 0;
1519 }
1520
udc_numaker_host_wakeup(const struct device * dev)1521 static int udc_numaker_host_wakeup(const struct device *dev)
1522 {
1523 const struct udc_numaker_config *config = dev->config;
1524 USBD_T *const base = config->base;
1525
1526 /* Enable back USB/PHY first */
1527 base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk;
1528
1529 /* Then generate 'K' */
1530 base->ATTR |= USBD_ATTR_RWAKEUP_Msk;
1531 k_sleep(K_USEC(NUMAKER_USBD_BUS_RESUME_DRV_K_US));
1532 base->ATTR ^= USBD_ATTR_RWAKEUP_Msk;
1533
1534 return 0;
1535 }
1536
udc_numaker_set_address(const struct device * dev,const uint8_t addr)1537 static int udc_numaker_set_address(const struct device *dev, const uint8_t addr)
1538 {
1539 struct udc_numaker_data *priv = udc_get_private(dev);
1540
1541 LOG_DBG("Set new address %u for %p", addr, dev);
1542
1543 /* NOTE: Timing for configuring USB device address into H/W is critical. It must be done
1544 * in-between SET_ADDRESS control transfer and next transfer. For this, it is done in
1545 * IN ACK ISR of SET_ADDRESS control transfer.
1546 */
1547 priv->addr = addr;
1548
1549 return 0;
1550 }
1551
udc_numaker_enable(const struct device * dev)1552 static int udc_numaker_enable(const struct device *dev)
1553 {
1554 LOG_DBG("Enable device %p", dev);
1555
1556 /* S/W connect */
1557 numaker_usbd_sw_connect(dev);
1558
1559 return 0;
1560 }
1561
udc_numaker_disable(const struct device * dev)1562 static int udc_numaker_disable(const struct device *dev)
1563 {
1564 LOG_DBG("Enable device %p", dev);
1565
1566 /* S/W disconnect */
1567 numaker_usbd_sw_disconnect(dev);
1568
1569 return 0;
1570 }
1571
udc_numaker_init(const struct device * dev)1572 static int udc_numaker_init(const struct device *dev)
1573 {
1574 int err;
1575
1576 /* Initialize USBD H/W */
1577 err = numaker_usbd_hw_setup(dev);
1578 if (err < 0) {
1579 LOG_ERR("Set up H/W: %d", err);
1580 return err;
1581 }
1582
1583 /* USB device address defaults to 0 */
1584 numaker_usbd_reset_addr(dev);
1585
1586 /* Initialize all EP H/W contexts */
1587 numaker_usbd_ep_mgmt_init(dev);
1588
1589 if (udc_ep_enable_internal(dev, USB_CONTROL_EP_OUT, USB_EP_TYPE_CONTROL, 64, 0)) {
1590 LOG_ERR("Failed to enable control endpoint");
1591 return -EIO;
1592 }
1593
1594 if (udc_ep_enable_internal(dev, USB_CONTROL_EP_IN, USB_EP_TYPE_CONTROL, 64, 0)) {
1595 LOG_ERR("Failed to enable control endpoint");
1596 return -EIO;
1597 }
1598
1599 return 0;
1600 }
1601
udc_numaker_shutdown(const struct device * dev)1602 static int udc_numaker_shutdown(const struct device *dev)
1603 {
1604 struct udc_numaker_data *priv = udc_get_private(dev);
1605
1606 if (udc_ep_disable_internal(dev, USB_CONTROL_EP_OUT)) {
1607 LOG_ERR("Failed to disable control endpoint");
1608 return -EIO;
1609 }
1610
1611 if (udc_ep_disable_internal(dev, USB_CONTROL_EP_IN)) {
1612 LOG_ERR("Failed to disable control endpoint");
1613 return -EIO;
1614 }
1615
1616 /* Uninitialize USBD H/W */
1617 numaker_usbd_hw_shutdown(dev);
1618
1619 /* Purge message queue */
1620 k_msgq_purge(priv->msgq);
1621
1622 return 0;
1623 }
1624
udc_numaker_lock(const struct device * dev)1625 static int udc_numaker_lock(const struct device *dev)
1626 {
1627 return udc_lock_internal(dev, K_FOREVER);
1628 }
1629
udc_numaker_unlock(const struct device * dev)1630 static int udc_numaker_unlock(const struct device *dev)
1631 {
1632 return udc_unlock_internal(dev);
1633 }
1634
udc_numaker_driver_preinit(const struct device * dev)1635 static int udc_numaker_driver_preinit(const struct device *dev)
1636 {
1637 const struct udc_numaker_config *config = dev->config;
1638 struct udc_data *data = dev->data;
1639 int err;
1640
1641 data->caps.rwup = true;
1642 data->caps.addr_before_status = true;
1643 data->caps.mps0 = UDC_MPS0_64;
1644
1645 /* Some soc series don't allow ISO IN/OUT to be assigned the same EP number.
1646 * This is addressed by limiting all OUT/IN EP addresses in top/bottom halves,
1647 * except CTRL OUT/IN.
1648 */
1649
1650 for (int i = 0; i < config->ep_cfg_out_size; i++) {
1651 /* Limit all OUT EP numbers to 0, 1~7 */
1652 if (config->disallow_iso_inout_same && i != 0 && i >= 8) {
1653 continue;
1654 }
1655
1656 config->ep_cfg_out[i].caps.out = 1;
1657 if (i == 0) {
1658 config->ep_cfg_out[i].caps.control = 1;
1659 config->ep_cfg_out[i].caps.mps = 64;
1660 } else {
1661 config->ep_cfg_out[i].caps.bulk = 1;
1662 config->ep_cfg_out[i].caps.interrupt = 1;
1663 config->ep_cfg_out[i].caps.iso = 1;
1664 config->ep_cfg_out[i].caps.mps = 1023;
1665 }
1666
1667 config->ep_cfg_out[i].addr = USB_EP_DIR_OUT | i;
1668 err = udc_register_ep(dev, &config->ep_cfg_out[i]);
1669 if (err != 0) {
1670 LOG_ERR("Failed to register endpoint");
1671 return err;
1672 }
1673 }
1674
1675 for (int i = 0; i < config->ep_cfg_in_size; i++) {
1676 /* Limit all IN EP numbers to 0, 8~15 */
1677 if (config->disallow_iso_inout_same && i != 0 && i < 8) {
1678 continue;
1679 }
1680
1681 config->ep_cfg_in[i].caps.in = 1;
1682 if (i == 0) {
1683 config->ep_cfg_in[i].caps.control = 1;
1684 config->ep_cfg_in[i].caps.mps = 64;
1685 } else {
1686 config->ep_cfg_in[i].caps.bulk = 1;
1687 config->ep_cfg_in[i].caps.interrupt = 1;
1688 config->ep_cfg_in[i].caps.iso = 1;
1689 config->ep_cfg_in[i].caps.mps = 1023;
1690 }
1691
1692 config->ep_cfg_in[i].addr = USB_EP_DIR_IN | i;
1693 err = udc_register_ep(dev, &config->ep_cfg_in[i]);
1694 if (err != 0) {
1695 LOG_ERR("Failed to register endpoint");
1696 return err;
1697 }
1698 }
1699
1700 config->make_thread(dev);
1701
1702 return 0;
1703 }
1704
1705 static const struct udc_api udc_numaker_api = {
1706 .device_speed = udc_numaker_device_speed,
1707 .ep_enqueue = udc_numaker_ep_enqueue,
1708 .ep_dequeue = udc_numaker_ep_dequeue,
1709 .ep_set_halt = udc_numaker_ep_set_halt,
1710 .ep_clear_halt = udc_numaker_ep_clear_halt,
1711 .ep_enable = udc_numaker_ep_enable,
1712 .ep_disable = udc_numaker_ep_disable,
1713 .host_wakeup = udc_numaker_host_wakeup,
1714 .set_address = udc_numaker_set_address,
1715 .enable = udc_numaker_enable,
1716 .disable = udc_numaker_disable,
1717 .init = udc_numaker_init,
1718 .shutdown = udc_numaker_shutdown,
1719 .lock = udc_numaker_lock,
1720 .unlock = udc_numaker_unlock,
1721 };
1722
1723 #define UDC_NUMAKER_DEVICE_DEFINE(inst) \
1724 PINCTRL_DT_INST_DEFINE(inst); \
1725 \
1726 static void udc_numaker_irq_config_func_##inst(const struct device *dev) \
1727 { \
1728 IRQ_CONNECT(DT_INST_IRQN(inst), DT_INST_IRQ(inst, priority), numaker_udbd_isr, \
1729 DEVICE_DT_INST_GET(inst), 0); \
1730 \
1731 irq_enable(DT_INST_IRQN(inst)); \
1732 } \
1733 \
1734 static void udc_numaker_irq_unconfig_func_##inst(const struct device *dev) \
1735 { \
1736 irq_disable(DT_INST_IRQN(inst)); \
1737 } \
1738 \
1739 K_THREAD_STACK_DEFINE(udc_numaker_stack_##inst, CONFIG_UDC_NUMAKER_THREAD_STACK_SIZE); \
1740 \
1741 static void udc_numaker_thread_##inst(void *dev, void *arg1, void *arg2) \
1742 { \
1743 ARG_UNUSED(arg1); \
1744 ARG_UNUSED(arg2); \
1745 numaker_usbd_msg_handler(dev); \
1746 } \
1747 \
1748 static void udc_numaker_make_thread_##inst(const struct device *dev) \
1749 { \
1750 struct udc_numaker_data *priv = udc_get_private(dev); \
1751 \
1752 k_thread_create(&priv->thread_data, udc_numaker_stack_##inst, \
1753 K_THREAD_STACK_SIZEOF(udc_numaker_stack_##inst), \
1754 udc_numaker_thread_##inst, (void *)dev, NULL, NULL, \
1755 K_PRIO_COOP(CONFIG_UDC_NUMAKER_THREAD_PRIORITY), K_ESSENTIAL, \
1756 K_NO_WAIT); \
1757 k_thread_name_set(&priv->thread_data, dev->name); \
1758 } \
1759 \
1760 static struct udc_ep_config \
1761 ep_cfg_out_##inst[MIN(DT_INST_PROP(inst, num_bidir_endpoints), 16)]; \
1762 static struct udc_ep_config \
1763 ep_cfg_in_##inst[MIN(DT_INST_PROP(inst, num_bidir_endpoints), 16)]; \
1764 \
1765 static const struct udc_numaker_config udc_numaker_config_##inst = { \
1766 .ep_cfg_out = ep_cfg_out_##inst, \
1767 .ep_cfg_in = ep_cfg_in_##inst, \
1768 .ep_cfg_out_size = ARRAY_SIZE(ep_cfg_out_##inst), \
1769 .ep_cfg_in_size = ARRAY_SIZE(ep_cfg_in_##inst), \
1770 .make_thread = udc_numaker_make_thread_##inst, \
1771 .base = (USBD_T *)DT_INST_REG_ADDR(inst), \
1772 .reset = RESET_DT_SPEC_INST_GET(inst), \
1773 .clk_modidx = DT_INST_CLOCKS_CELL(inst, clock_module_index), \
1774 .clk_src = DT_INST_CLOCKS_CELL(inst, clock_source), \
1775 .clk_div = DT_INST_CLOCKS_CELL(inst, clock_divider), \
1776 .clkctrl_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(inst))), \
1777 .irq_config_func = udc_numaker_irq_config_func_##inst, \
1778 .irq_unconfig_func = udc_numaker_irq_unconfig_func_##inst, \
1779 .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
1780 .dmabuf_size = DT_INST_PROP(inst, dma_buffer_size), \
1781 .disallow_iso_inout_same = DT_INST_PROP(inst, disallow_iso_in_out_same_number), \
1782 }; \
1783 \
1784 static struct numaker_usbd_ep \
1785 numaker_usbd_ep_pool_##inst[DT_INST_PROP(inst, num_bidir_endpoints)]; \
1786 \
1787 K_MSGQ_DEFINE(numaker_usbd_msgq_##inst, sizeof(struct numaker_usbd_msg), \
1788 CONFIG_UDC_NUMAKER_MSG_QUEUE_SIZE, 4); \
1789 \
1790 static struct udc_numaker_data udc_priv_##inst = { \
1791 .msgq = &numaker_usbd_msgq_##inst, \
1792 .ep_pool = numaker_usbd_ep_pool_##inst, \
1793 .ep_pool_size = DT_INST_PROP(inst, num_bidir_endpoints), \
1794 }; \
1795 \
1796 static struct udc_data udc_data_##inst = { \
1797 .mutex = Z_MUTEX_INITIALIZER(udc_data_##inst.mutex), \
1798 .priv = &udc_priv_##inst, \
1799 }; \
1800 \
1801 DEVICE_DT_INST_DEFINE(inst, udc_numaker_driver_preinit, NULL, &udc_data_##inst, \
1802 &udc_numaker_config_##inst, POST_KERNEL, \
1803 CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &udc_numaker_api);
1804
1805 DT_INST_FOREACH_STATUS_OKAY(UDC_NUMAKER_DEVICE_DEFINE)
1806