1 /*
2 * Copyright (c) 2016 Intel Corporation.
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /**
9 * @file
10 * @brief USB DesignWare device controller driver
11 *
12 * USB DesignWare device controller driver. The driver implements the low
13 * level control routines to deal directly with the hardware.
14 */
15
16 #define DT_DRV_COMPAT snps_dwc2
17
18 #include <string.h>
19 #include <stdio.h>
20
21 #include <zephyr/kernel.h>
22 #include <zephyr/devicetree.h>
23 #include <zephyr/irq.h>
24 #include <zephyr/sys/util.h>
25 #include <zephyr/sys/byteorder.h>
26 #include <zephyr/usb/usb_device.h>
27
28 #include <usb_dwc2_hw.h>
29 #include "usb_dc_dw_stm32.h"
30
31 #include <zephyr/logging/log.h>
32 LOG_MODULE_REGISTER(usb_dc_dw, CONFIG_USB_DRIVER_LOG_LEVEL);
33
34 /* FIXME: The actual number of endpoints should be obtained from GHWCFG4. */
35 enum usb_dw_in_ep_idx {
36 USB_DW_IN_EP_0 = 0,
37 USB_DW_IN_EP_1,
38 USB_DW_IN_EP_2,
39 USB_DW_IN_EP_3,
40 USB_DW_IN_EP_4,
41 USB_DW_IN_EP_5,
42 USB_DW_IN_EP_NUM
43 };
44
45 /* FIXME: The actual number of endpoints should be obtained from GHWCFG2. */
46 enum usb_dw_out_ep_idx {
47 USB_DW_OUT_EP_0 = 0,
48 USB_DW_OUT_EP_1,
49 USB_DW_OUT_EP_2,
50 USB_DW_OUT_EP_3,
51 USB_DW_OUT_EP_NUM
52 };
53
54 #define USB_DW_CORE_RST_TIMEOUT_US 10000
55
56 /* FIXME: The actual MPS depends on endpoint type and bus speed. */
57 #define DW_USB_MAX_PACKET_SIZE 64
58
59 /* Number of SETUP back-to-back packets */
60 #define USB_DW_SUP_CNT 1
61
62 /* Get Data FIFO access register */
63 #define USB_DW_EP_FIFO(base, idx) \
64 (*(uint32_t *)(POINTER_TO_UINT(base) + 0x1000 * (idx + 1)))
65
66 struct usb_dw_config {
67 struct usb_dwc2_reg *const base;
68 struct pinctrl_dev_config *const pcfg;
69 void (*irq_enable_func)(const struct device *dev);
70 int (*clk_enable_func)(void);
71 int (*pwr_on_func)(struct usb_dwc2_reg *const base);
72 };
73
74 /*
75 * USB endpoint private structure.
76 */
77 struct usb_ep_ctrl_prv {
78 uint8_t ep_ena;
79 uint8_t fifo_num;
80 uint32_t fifo_size;
81 uint16_t mps; /* Max ep pkt size */
82 usb_dc_ep_callback cb;/* Endpoint callback function */
83 uint32_t data_len;
84 };
85
86 static void usb_dw_isr_handler(const void *unused);
87
88 /*
89 * USB controller private structure.
90 */
91 struct usb_dw_ctrl_prv {
92 usb_dc_status_callback status_cb;
93 struct usb_ep_ctrl_prv in_ep_ctrl[USB_DW_IN_EP_NUM];
94 struct usb_ep_ctrl_prv out_ep_ctrl[USB_DW_OUT_EP_NUM];
95 int n_tx_fifos;
96 uint8_t attached;
97 };
98
99 #if defined(CONFIG_PINCTRL)
100 #include <zephyr/drivers/pinctrl.h>
101
usb_dw_init_pinctrl(const struct usb_dw_config * const config)102 static int usb_dw_init_pinctrl(const struct usb_dw_config *const config)
103 {
104 const struct pinctrl_dev_config *const pcfg = config->pcfg;
105 int ret = 0;
106
107 if (pcfg == NULL) {
108 LOG_INF("Skip pinctrl configuration");
109 return 0;
110 }
111
112 ret = pinctrl_apply_state(pcfg, PINCTRL_STATE_DEFAULT);
113 if (ret) {
114 LOG_ERR("Failed to apply default pinctrl state (%d)", ret);
115 }
116
117 return ret;
118 }
119 #else
usb_dw_init_pinctrl(const struct usb_dw_config * const config)120 static int usb_dw_init_pinctrl(const struct usb_dw_config *const config)
121 {
122 ARG_UNUSED(config);
123
124 return 0;
125 }
126 #endif
127
128 #define USB_DW_GET_COMPAT_QUIRK_NONE(n) NULL
129
130 #define USB_DW_GET_COMPAT_CLK_QUIRK_0(n) \
131 COND_CODE_1(DT_INST_NODE_HAS_COMPAT(n, st_stm32f4_fsotg), \
132 (clk_enable_st_stm32f4_fsotg_##n), \
133 USB_DW_GET_COMPAT_QUIRK_NONE(n))
134
135 #define USB_DW_GET_COMPAT_PWR_QUIRK_0(n) \
136 COND_CODE_1(DT_INST_NODE_HAS_COMPAT(n, st_stm32f4_fsotg), \
137 (pwr_on_st_stm32f4_fsotg), \
138 USB_DW_GET_COMPAT_QUIRK_NONE(n))
139
140 #define USB_DW_PINCTRL_DT_INST_DEFINE(n) \
141 COND_CODE_1(DT_INST_PINCTRL_HAS_NAME(n, default), \
142 (PINCTRL_DT_INST_DEFINE(n)), ())
143
144 #define USB_DW_PINCTRL_DT_INST_DEV_CONFIG_GET(n) \
145 COND_CODE_1(DT_INST_PINCTRL_HAS_NAME(n, default), \
146 ((void *)PINCTRL_DT_INST_DEV_CONFIG_GET(n)), (NULL))
147
148 #define USB_DW_IRQ_FLAGS_TYPE0(n) 0
149 #define USB_DW_IRQ_FLAGS_TYPE1(n) DT_INST_IRQ(n, type)
150 #define DW_IRQ_FLAGS(n) \
151 _CONCAT(USB_DW_IRQ_FLAGS_TYPE, DT_INST_IRQ_HAS_CELL(n, type))(n)
152
153 #define USB_DW_DEVICE_DEFINE(n) \
154 USB_DW_PINCTRL_DT_INST_DEFINE(n); \
155 USB_DW_QUIRK_ST_STM32F4_FSOTG_DEFINE(n); \
156 \
157 static void usb_dw_irq_enable_func_##n(const struct device *dev) \
158 { \
159 IRQ_CONNECT(DT_INST_IRQN(n), \
160 DT_INST_IRQ(n, priority), \
161 usb_dw_isr_handler, \
162 0, \
163 DW_IRQ_FLAGS(n)); \
164 \
165 irq_enable(DT_INST_IRQN(n)); \
166 } \
167 \
168 static const struct usb_dw_config usb_dw_cfg_##n = { \
169 .base = (struct usb_dwc2_reg *)DT_INST_REG_ADDR(n), \
170 .pcfg = USB_DW_PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
171 .irq_enable_func = usb_dw_irq_enable_func_##n, \
172 .clk_enable_func = USB_DW_GET_COMPAT_CLK_QUIRK_0(n), \
173 .pwr_on_func = USB_DW_GET_COMPAT_PWR_QUIRK_0(n), \
174 }; \
175 \
176 static struct usb_dw_ctrl_prv usb_dw_ctrl_##n;
177
178 USB_DW_DEVICE_DEFINE(0)
179
180 #define usb_dw_ctrl usb_dw_ctrl_0
181 #define usb_dw_cfg usb_dw_cfg_0
182
usb_dw_reg_dump(void)183 static void usb_dw_reg_dump(void)
184 {
185 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
186 uint8_t i;
187
188 LOG_DBG("USB registers: GOTGCTL : 0x%x GOTGINT : 0x%x GAHBCFG : "
189 "0x%x", base->gotgctl, base->gotgint, base->gahbcfg);
190 LOG_DBG(" GUSBCFG : 0x%x GINTSTS : 0x%x GINTMSK : 0x%x",
191 base->gusbcfg, base->gintsts, base->gintmsk);
192 LOG_DBG(" DCFG : 0x%x DCTL : 0x%x DSTS : 0x%x",
193 base->dcfg, base->dctl, base->dsts);
194 LOG_DBG(" DIEPMSK : 0x%x DOEPMSK : 0x%x DAINT : 0x%x",
195 base->diepmsk, base->doepmsk, base->daint);
196 LOG_DBG(" DAINTMSK: 0x%x GHWCFG1 : 0x%x GHWCFG2 : 0x%x",
197 base->daintmsk, base->ghwcfg1, base->ghwcfg2);
198 LOG_DBG(" GHWCFG3 : 0x%x GHWCFG4 : 0x%x",
199 base->ghwcfg3, base->ghwcfg4);
200
201 for (i = 0U; i < USB_DW_OUT_EP_NUM; i++) {
202 LOG_DBG("\n EP %d registers: DIEPCTL : 0x%x DIEPINT : "
203 "0x%x", i, base->in_ep[i].diepctl,
204 base->in_ep[i].diepint);
205 LOG_DBG(" DIEPTSIZ: 0x%x DIEPDMA : 0x%x DOEPCTL : "
206 "0x%x", base->in_ep[i].dieptsiz,
207 base->in_ep[i].diepdma,
208 base->out_ep[i].doepctl);
209 LOG_DBG(" DOEPINT : 0x%x DOEPTSIZ: 0x%x DOEPDMA : "
210 "0x%x", base->out_ep[i].doepint,
211 base->out_ep[i].doeptsiz,
212 base->out_ep[i].doepdma);
213 }
214 }
215
usb_dw_ep_is_valid(uint8_t ep)216 static uint8_t usb_dw_ep_is_valid(uint8_t ep)
217 {
218 uint8_t ep_idx = USB_EP_GET_IDX(ep);
219
220 /* Check if ep enabled */
221 if ((USB_EP_DIR_IS_OUT(ep)) && ep_idx < USB_DW_OUT_EP_NUM) {
222 return 1;
223 } else if ((USB_EP_DIR_IS_IN(ep)) && ep_idx < USB_DW_IN_EP_NUM) {
224 return 1;
225 }
226
227 return 0;
228 }
229
usb_dw_ep_is_enabled(uint8_t ep)230 static uint8_t usb_dw_ep_is_enabled(uint8_t ep)
231 {
232 uint8_t ep_idx = USB_EP_GET_IDX(ep);
233
234 /* Check if ep enabled */
235 if ((USB_EP_DIR_IS_OUT(ep)) &&
236 usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena) {
237 return 1;
238 } else if ((USB_EP_DIR_IS_IN(ep)) &&
239 usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena) {
240 return 1;
241 }
242
243 return 0;
244 }
245
usb_dw_udelay(uint32_t us)246 static inline void usb_dw_udelay(uint32_t us)
247 {
248 k_busy_wait(us);
249 }
250
usb_dw_reset(void)251 static int usb_dw_reset(void)
252 {
253 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
254 uint32_t cnt = 0U;
255
256 /* Wait for AHB master idle state. */
257 while (!(base->grstctl & USB_DWC2_GRSTCTL_AHBIDLE)) {
258 usb_dw_udelay(1);
259
260 if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) {
261 LOG_ERR("USB reset HANG! AHB Idle GRSTCTL=0x%08x",
262 base->grstctl);
263 return -EIO;
264 }
265 }
266
267 /* Core Soft Reset */
268 cnt = 0U;
269 base->grstctl |= USB_DWC2_GRSTCTL_CSFTRST;
270
271 do {
272 if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) {
273 LOG_DBG("USB reset HANG! Soft Reset GRSTCTL=0x%08x",
274 base->grstctl);
275 return -EIO;
276 }
277 usb_dw_udelay(1);
278 } while (base->grstctl & USB_DWC2_GRSTCTL_CSFTRST);
279
280 /* Wait for 3 PHY Clocks */
281 usb_dw_udelay(100);
282
283 return 0;
284 }
285
usb_dw_num_dev_eps(void)286 static int usb_dw_num_dev_eps(void)
287 {
288 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
289
290 return (base->ghwcfg2 >> 10) & 0xf;
291 }
292
usb_dw_flush_tx_fifo(int ep)293 static void usb_dw_flush_tx_fifo(int ep)
294 {
295 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
296 int fnum = usb_dw_ctrl.in_ep_ctrl[ep].fifo_num;
297
298 base->grstctl = (fnum << 6) | (1<<5);
299 while (base->grstctl & (1<<5)) {
300 }
301 }
302
usb_dw_tx_fifo_avail(int ep)303 static int usb_dw_tx_fifo_avail(int ep)
304 {
305 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
306
307 return base->in_ep[ep].dtxfsts & USB_DWC2_DTXFSTS_INEPTXFSPCAVAIL_MASK;
308 }
309
310 /* Choose a FIFO number for an IN endpoint */
usb_dw_set_fifo(uint8_t ep)311 static int usb_dw_set_fifo(uint8_t ep)
312 {
313 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
314 int ep_idx = USB_EP_GET_IDX(ep);
315 volatile uint32_t *reg = &base->in_ep[ep_idx].diepctl;
316 uint32_t val;
317 int fifo = 0;
318 int ded_fifo = !!(base->ghwcfg4 & USB_DWC2_GHWCFG4_DEDFIFOMODE);
319
320 if (!ded_fifo) {
321 /* No support for shared-FIFO mode yet, existing
322 * Zephyr hardware doesn't use it
323 */
324 return -ENOTSUP;
325 }
326
327 /* In dedicated-FIFO mode, all IN endpoints must have a unique
328 * FIFO number associated with them in the TXFNUM field of
329 * DIEPCTLx, with EP0 always being assigned to FIFO zero (the
330 * reset default, so we don't touch it).
331 *
332 * FIXME: would be better (c.f. the dwc2 driver in Linux) to
333 * choose a FIFO based on the hardware depth: we want the
334 * smallest one that fits our configured maximum packet size
335 * for the endpoint. This just picks the next available one.
336 */
337 if (ep_idx != 0) {
338 fifo = ++usb_dw_ctrl.n_tx_fifos;
339 if (fifo >= usb_dw_num_dev_eps()) {
340 return -EINVAL;
341 }
342
343 reg = &base->in_ep[ep_idx].diepctl;
344 val = *reg & ~USB_DWC2_DEPCTL_TXFNUM_MASK;
345 val |= fifo << USB_DWC2_DEPCTL_TXFNUM_POS;
346 *reg = val;
347 }
348
349 usb_dw_ctrl.in_ep_ctrl[ep_idx].fifo_num = fifo;
350
351 usb_dw_flush_tx_fifo(ep_idx);
352
353 val = usb_dw_tx_fifo_avail(ep_idx);
354 usb_dw_ctrl.in_ep_ctrl[ep_idx].fifo_size = val;
355
356 return 0;
357 }
358
usb_dw_ep_set(uint8_t ep,uint32_t ep_mps,enum usb_dc_ep_transfer_type ep_type)359 static int usb_dw_ep_set(uint8_t ep,
360 uint32_t ep_mps, enum usb_dc_ep_transfer_type ep_type)
361 {
362 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
363 volatile uint32_t *p_depctl;
364 uint8_t ep_idx = USB_EP_GET_IDX(ep);
365
366 LOG_DBG("%s ep %x, mps %d, type %d", __func__, ep, ep_mps, ep_type);
367
368 if (USB_EP_DIR_IS_OUT(ep)) {
369 p_depctl = &base->out_ep[ep_idx].doepctl;
370 usb_dw_ctrl.out_ep_ctrl[ep_idx].mps = ep_mps;
371 } else {
372 p_depctl = &base->in_ep[ep_idx].diepctl;
373 usb_dw_ctrl.in_ep_ctrl[ep_idx].mps = ep_mps;
374 }
375
376 if (!ep_idx) {
377 /* Set max packet size for EP0 */
378 *p_depctl &= ~USB_DWC2_DEPCTL0_MPS_MASK;
379
380 switch (ep_mps) {
381 case 8:
382 *p_depctl |= USB_DWC2_DEPCTL0_MPS_8 <<
383 USB_DWC2_DEPCTL_MPS_POS;
384 break;
385 case 16:
386 *p_depctl |= USB_DWC2_DEPCTL0_MPS_16 <<
387 USB_DWC2_DEPCTL_MPS_POS;
388 break;
389 case 32:
390 *p_depctl |= USB_DWC2_DEPCTL0_MPS_32 <<
391 USB_DWC2_DEPCTL_MPS_POS;
392 break;
393 case 64:
394 *p_depctl |= USB_DWC2_DEPCTL0_MPS_64 <<
395 USB_DWC2_DEPCTL_MPS_POS;
396 break;
397 default:
398 return -EINVAL;
399 }
400 /* No need to set EP0 type */
401 } else {
402 /* Set max packet size for EP */
403 if (ep_mps > (USB_DWC2_DEPCTL_MPS_MASK >>
404 USB_DWC2_DEPCTL_MPS_POS)) {
405 return -EINVAL;
406 }
407
408 *p_depctl &= ~USB_DWC2_DEPCTL_MPS_MASK;
409 *p_depctl |= ep_mps << USB_DWC2_DEPCTL_MPS_POS;
410
411 /* Set endpoint type */
412 *p_depctl &= ~USB_DWC2_DEPCTL_EPTYPE_MASK;
413
414 switch (ep_type) {
415 case USB_DC_EP_CONTROL:
416 *p_depctl |= USB_DWC2_DEPCTL_EPTYPE_CONTROL <<
417 USB_DWC2_DEPCTL_EPTYPE_POS;
418 break;
419 case USB_DC_EP_BULK:
420 *p_depctl |= USB_DWC2_DEPCTL_EPTYPE_BULK <<
421 USB_DWC2_DEPCTL_EPTYPE_POS;
422 break;
423 case USB_DC_EP_INTERRUPT:
424 *p_depctl |= USB_DWC2_DEPCTL_EPTYPE_INTERRUPT <<
425 USB_DWC2_DEPCTL_EPTYPE_POS;
426 break;
427 default:
428 return -EINVAL;
429 }
430
431 /* sets the Endpoint Data PID to DATA0 */
432 *p_depctl |= USB_DWC2_DEPCTL_SETD0PID;
433 }
434
435 if (USB_EP_DIR_IS_IN(ep)) {
436 int ret = usb_dw_set_fifo(ep);
437
438 if (ret) {
439 return ret;
440 }
441 }
442
443 return 0;
444 }
445
usb_dw_prep_rx(const uint8_t ep,uint8_t setup)446 static void usb_dw_prep_rx(const uint8_t ep, uint8_t setup)
447 {
448 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
449 enum usb_dw_out_ep_idx ep_idx = USB_EP_GET_IDX(ep);
450 uint32_t ep_mps = usb_dw_ctrl.out_ep_ctrl[ep_idx].mps;
451
452 /* Set max RX size to EP mps so we get an interrupt
453 * each time a packet is received
454 */
455
456 base->out_ep[ep_idx].doeptsiz =
457 (USB_DW_SUP_CNT << USB_DWC2_DOEPTSIZ_SUP_CNT_POS) |
458 (1 << USB_DWC2_DEPTSIZ_PKT_CNT_POS) | ep_mps;
459
460 /* Clear NAK and enable ep */
461 if (!setup) {
462 base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_CNAK;
463 }
464
465 base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_EPENA;
466
467 LOG_DBG("USB OUT EP%d armed", ep_idx);
468 }
469
usb_dw_tx(uint8_t ep,const uint8_t * const data,uint32_t data_len)470 static int usb_dw_tx(uint8_t ep, const uint8_t *const data,
471 uint32_t data_len)
472 {
473 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
474 enum usb_dw_in_ep_idx ep_idx = USB_EP_GET_IDX(ep);
475 uint32_t max_xfer_size, max_pkt_cnt, pkt_cnt, avail_space;
476 uint32_t ep_mps = usb_dw_ctrl.in_ep_ctrl[ep_idx].mps;
477 unsigned int key;
478 uint32_t i;
479
480 /* Wait for FIFO space available */
481 do {
482 avail_space = usb_dw_tx_fifo_avail(ep_idx);
483 if (avail_space == usb_dw_ctrl.in_ep_ctrl[ep_idx].fifo_size) {
484 break;
485 }
486 /* Make sure we don't hog the CPU */
487 k_yield();
488 } while (1);
489
490 key = irq_lock();
491
492 avail_space *= 4U;
493 if (!avail_space) {
494 LOG_ERR("USB IN EP%d no space available, DTXFSTS %x", ep_idx,
495 base->in_ep[ep_idx].dtxfsts);
496 irq_unlock(key);
497 return -EAGAIN;
498 }
499
500 /* For now tx-fifo sizes are not configured (cf usb_dw_set_fifo). Here
501 * we force available fifo size to be a multiple of ep mps in order to
502 * prevent splitting data incorrectly.
503 */
504 avail_space -= avail_space % ep_mps;
505 if (data_len > avail_space) {
506 data_len = avail_space;
507 }
508
509 if (data_len != 0U) {
510 /* Get max packet size and packet count for ep */
511 if (ep_idx == USB_DW_IN_EP_0) {
512 max_pkt_cnt =
513 USB_DWC2_DIEPTSIZ0_PKT_CNT_MASK >>
514 USB_DWC2_DEPTSIZ_PKT_CNT_POS;
515 max_xfer_size =
516 USB_DWC2_DEPTSIZ0_XFER_SIZE_MASK >>
517 USB_DWC2_DEPTSIZ_XFER_SIZE_POS;
518 } else {
519 max_pkt_cnt =
520 USB_DWC2_DIEPTSIZn_PKT_CNT_MASK >>
521 USB_DWC2_DEPTSIZ_PKT_CNT_POS;
522 max_xfer_size =
523 USB_DWC2_DEPTSIZn_XFER_SIZE_MASK >>
524 USB_DWC2_DEPTSIZ_XFER_SIZE_POS;
525 }
526
527 /* Check if transfer len is too big */
528 if (data_len > max_xfer_size) {
529 LOG_WRN("USB IN EP%d len too big (%d->%d)", ep_idx,
530 data_len, max_xfer_size);
531 data_len = max_xfer_size;
532 }
533
534 /*
535 * Program the transfer size and packet count as follows:
536 *
537 * transfer size = N * ep_maxpacket + short_packet
538 * pktcnt = N + (short_packet exist ? 1 : 0)
539 */
540
541 pkt_cnt = DIV_ROUND_UP(data_len, ep_mps);
542 if (pkt_cnt > max_pkt_cnt) {
543 LOG_WRN("USB IN EP%d pkt count too big (%d->%d)",
544 ep_idx, pkt_cnt, pkt_cnt);
545 pkt_cnt = max_pkt_cnt;
546 data_len = pkt_cnt * ep_mps;
547 }
548 } else {
549 /* Zero length packet */
550 pkt_cnt = 1U;
551 }
552
553 /* Set number of packets and transfer size */
554 base->in_ep[ep_idx].dieptsiz =
555 (pkt_cnt << USB_DWC2_DEPTSIZ_PKT_CNT_POS) | data_len;
556
557 /* Clear NAK and enable ep */
558 base->in_ep[ep_idx].diepctl |= (USB_DWC2_DEPCTL_EPENA |
559 USB_DWC2_DEPCTL_CNAK);
560
561 /*
562 * Write data to FIFO, make sure that we are protected against
563 * other USB register accesses. According to "DesignWare Cores
564 * USB 1.1/2.0 Device Subsystem-AHB/VCI Databook": "During FIFO
565 * access, the application must not access the UDC/Subsystem
566 * registers or vendor registers (for ULPI mode). After starting
567 * to access a FIFO, the application must complete the transaction
568 * before accessing the register."
569 */
570 for (i = 0U; i < data_len; i += 4U) {
571 uint32_t val = data[i];
572
573 if (i + 1 < data_len) {
574 val |= ((uint32_t)data[i+1]) << 8;
575 }
576 if (i + 2 < data_len) {
577 val |= ((uint32_t)data[i+2]) << 16;
578 }
579 if (i + 3 < data_len) {
580 val |= ((uint32_t)data[i+3]) << 24;
581 }
582
583 USB_DW_EP_FIFO(base, ep_idx) = val;
584 }
585
586 irq_unlock(key);
587
588 LOG_DBG("USB IN EP%d write %u bytes", ep_idx, data_len);
589
590 return data_len;
591 }
592
usb_dw_init(void)593 static int usb_dw_init(void)
594 {
595 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
596 uint8_t ep;
597 int ret;
598
599 ret = usb_dw_reset();
600 if (ret) {
601 return ret;
602 }
603
604 /*
605 * Force device mode as we do no support other roles or role changes.
606 * Wait 25ms for the change to take effect.
607 */
608 base->gusbcfg |= USB_DWC2_GUSBCFG_FORCEDEVMODE;
609 k_msleep(25);
610
611 #ifdef CONFIG_USB_DW_USB_2_0
612 /* set the PHY interface to be 16-bit UTMI */
613 base->gusbcfg = (base->gusbcfg & ~USB_DWC2_GUSBCFG_PHYIF_16_BIT) |
614 USB_DWC2_GUSBCFG_PHYIF_16_BIT;
615
616 /* Set USB2.0 High Speed */
617 base->dcfg |= USB_DWC2_DCFG_DEVSPD_USBHS20;
618 #else
619 /* Set device speed to Full Speed */
620 base->dcfg |= USB_DWC2_DCFG_DEVSPD_USBFS1148;
621 #endif
622
623 /* Set NAK for all OUT EPs */
624 for (ep = 0U; ep < USB_DW_OUT_EP_NUM; ep++) {
625 base->out_ep[ep].doepctl = USB_DWC2_DEPCTL_SNAK;
626 }
627
628 /* Enable global interrupts */
629 base->gintmsk = USB_DWC2_GINTSTS_OEPINT |
630 USB_DWC2_GINTSTS_IEPINT |
631 USB_DWC2_GINTSTS_ENUMDONE |
632 USB_DWC2_GINTSTS_USBRST |
633 USB_DWC2_GINTSTS_WKUPINT |
634 USB_DWC2_GINTSTS_USBSUSP;
635
636 /* Enable global interrupt */
637 base->gahbcfg |= USB_DWC2_GAHBCFG_GLBINTRMASK;
638
639 /* Call vendor-specific function to enable peripheral */
640 if (usb_dw_cfg.pwr_on_func != NULL) {
641 ret = usb_dw_cfg.pwr_on_func(base);
642 if (ret) {
643 return ret;
644 }
645 }
646
647 /* Disable soft disconnect */
648 base->dctl &= ~USB_DWC2_DCTL_SFTDISCON;
649
650 usb_dw_reg_dump();
651
652 return 0;
653 }
654
usb_dw_handle_reset(void)655 static void usb_dw_handle_reset(void)
656 {
657 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
658
659 LOG_DBG("USB RESET event");
660
661 /* Inform upper layers */
662 if (usb_dw_ctrl.status_cb) {
663 usb_dw_ctrl.status_cb(USB_DC_RESET, NULL);
664 }
665
666 /* Clear device address during reset. */
667 base->dcfg &= ~USB_DWC2_DCFG_DEVADDR_MASK;
668
669 /* enable global EP interrupts */
670 base->doepmsk = 0U;
671 base->gintmsk |= USB_DWC2_GINTSTS_RXFLVL;
672 base->diepmsk |= USB_DWC2_DIEPINT_XFERCOMPL;
673 }
674
usb_dw_handle_enum_done(void)675 static void usb_dw_handle_enum_done(void)
676 {
677 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
678 uint32_t speed;
679
680 speed = (base->dsts & ~USB_DWC2_DSTS_ENUMSPD_MASK) >>
681 USB_DWC2_DSTS_ENUMSPD_POS;
682
683 LOG_DBG("USB ENUM DONE event, %s speed detected",
684 speed == USB_DWC2_DSTS_ENUMSPD_LS6 ? "Low" : "Full");
685
686 /* Inform upper layers */
687 if (usb_dw_ctrl.status_cb) {
688 usb_dw_ctrl.status_cb(USB_DC_CONNECTED, NULL);
689 }
690 }
691
692 /* USB ISR handler */
usb_dw_int_rx_flvl_handler(void)693 static inline void usb_dw_int_rx_flvl_handler(void)
694 {
695 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
696 uint32_t grxstsp = base->grxstsp;
697 uint32_t status, xfer_size;
698 uint8_t ep_idx;
699 usb_dc_ep_callback ep_cb;
700
701 /* Packet in RX FIFO */
702
703 ep_idx = grxstsp & USB_DWC2_GRXSTSR_EPNUM_MASK;
704 status = (grxstsp & USB_DWC2_GRXSTSR_PKTSTS_MASK) >>
705 USB_DWC2_GRXSTSR_PKTSTS_POS;
706 xfer_size = (grxstsp & USB_DWC2_GRXSTSR_BCNT_MASK) >>
707 USB_DWC2_GRXSTSR_BCNT_POS;
708
709 LOG_DBG("USB OUT EP%u: RX_FLVL status %u, size %u",
710 ep_idx, status, xfer_size);
711
712 usb_dw_ctrl.out_ep_ctrl[ep_idx].data_len = xfer_size;
713 ep_cb = usb_dw_ctrl.out_ep_ctrl[ep_idx].cb;
714
715 switch (status) {
716 case USB_DWC2_GRXSTSR_PKTSTS_SETUP:
717 /* Call the registered callback if any */
718 if (ep_cb) {
719 ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_OUT),
720 USB_DC_EP_SETUP);
721 }
722
723 break;
724 case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA:
725 if (ep_cb) {
726 ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_OUT),
727 USB_DC_EP_DATA_OUT);
728 }
729
730 break;
731 case USB_DWC2_GRXSTSR_PKTSTS_OUT_DATA_DONE:
732 case USB_DWC2_GRXSTSR_PKTSTS_SETUP_DONE:
733 break;
734 default:
735 break;
736 }
737 }
738
usb_dw_int_iep_handler(void)739 static inline void usb_dw_int_iep_handler(void)
740 {
741 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
742 uint32_t ep_int_status;
743 uint8_t ep_idx;
744 usb_dc_ep_callback ep_cb;
745
746 for (ep_idx = 0U; ep_idx < USB_DW_IN_EP_NUM; ep_idx++) {
747 if (base->daint & USB_DWC2_DAINT_INEPINT(ep_idx)) {
748 /* Read IN EP interrupt status */
749 ep_int_status = base->in_ep[ep_idx].diepint &
750 base->diepmsk;
751
752 /* Clear IN EP interrupts */
753 base->in_ep[ep_idx].diepint = ep_int_status;
754
755 LOG_DBG("USB IN EP%u interrupt status: 0x%x",
756 ep_idx, ep_int_status);
757
758 ep_cb = usb_dw_ctrl.in_ep_ctrl[ep_idx].cb;
759 if (ep_cb &&
760 (ep_int_status & USB_DWC2_DIEPINT_XFERCOMPL)) {
761
762 /* Call the registered callback */
763 ep_cb(USB_EP_GET_ADDR(ep_idx, USB_EP_DIR_IN),
764 USB_DC_EP_DATA_IN);
765 }
766 }
767 }
768
769 /* Clear interrupt. */
770 base->gintsts = USB_DWC2_GINTSTS_IEPINT;
771 }
772
usb_dw_int_oep_handler(void)773 static inline void usb_dw_int_oep_handler(void)
774 {
775 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
776 uint32_t ep_int_status;
777 uint8_t ep_idx;
778
779 for (ep_idx = 0U; ep_idx < USB_DW_OUT_EP_NUM; ep_idx++) {
780 if (base->daint & USB_DWC2_DAINT_OUTEPINT(ep_idx)) {
781 /* Read OUT EP interrupt status */
782 ep_int_status = base->out_ep[ep_idx].doepint &
783 base->doepmsk;
784
785 /* Clear OUT EP interrupts */
786 base->out_ep[ep_idx].doepint = ep_int_status;
787
788 LOG_DBG("USB OUT EP%u interrupt status: 0x%x\n",
789 ep_idx, ep_int_status);
790 }
791 }
792
793 /* Clear interrupt. */
794 base->gintsts = USB_DWC2_GINTSTS_OEPINT;
795 }
796
usb_dw_isr_handler(const void * unused)797 static void usb_dw_isr_handler(const void *unused)
798 {
799 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
800 uint32_t int_status;
801
802 ARG_UNUSED(unused);
803
804 /* Read interrupt status */
805 while ((int_status = (base->gintsts & base->gintmsk))) {
806
807 LOG_DBG("USB GINTSTS 0x%x", int_status);
808
809 if (int_status & USB_DWC2_GINTSTS_USBRST) {
810 /* Clear interrupt. */
811 base->gintsts = USB_DWC2_GINTSTS_USBRST;
812
813 /* Reset detected */
814 usb_dw_handle_reset();
815 }
816
817 if (int_status & USB_DWC2_GINTSTS_ENUMDONE) {
818 /* Clear interrupt. */
819 base->gintsts = USB_DWC2_GINTSTS_ENUMDONE;
820
821 /* Enumeration done detected */
822 usb_dw_handle_enum_done();
823 }
824
825 if (int_status & USB_DWC2_GINTSTS_USBSUSP) {
826 /* Clear interrupt. */
827 base->gintsts = USB_DWC2_GINTSTS_USBSUSP;
828
829 if (usb_dw_ctrl.status_cb) {
830 usb_dw_ctrl.status_cb(USB_DC_SUSPEND, NULL);
831 }
832 }
833
834 if (int_status & USB_DWC2_GINTSTS_WKUPINT) {
835 /* Clear interrupt. */
836 base->gintsts = USB_DWC2_GINTSTS_WKUPINT;
837
838 if (usb_dw_ctrl.status_cb) {
839 usb_dw_ctrl.status_cb(USB_DC_RESUME, NULL);
840 }
841 }
842
843 if (int_status & USB_DWC2_GINTSTS_RXFLVL) {
844 /* Packet in RX FIFO */
845 usb_dw_int_rx_flvl_handler();
846 }
847
848 if (int_status & USB_DWC2_GINTSTS_IEPINT) {
849 /* IN EP interrupt */
850 usb_dw_int_iep_handler();
851 }
852
853 if (int_status & USB_DWC2_GINTSTS_OEPINT) {
854 /* No OUT interrupt expected in FIFO mode,
855 * just clear interrupt
856 */
857 usb_dw_int_oep_handler();
858 }
859 }
860 }
861
usb_dc_attach(void)862 int usb_dc_attach(void)
863 {
864 int ret;
865
866 if (usb_dw_ctrl.attached) {
867 return 0;
868 }
869
870 if (usb_dw_cfg.clk_enable_func != NULL) {
871 ret = usb_dw_cfg.clk_enable_func();
872 if (ret) {
873 return ret;
874 }
875 }
876
877 ret = usb_dw_init_pinctrl(&usb_dw_cfg);
878 if (ret) {
879 return ret;
880 }
881
882 ret = usb_dw_init();
883 if (ret) {
884 return ret;
885 }
886
887 /* Connect and enable USB interrupt */
888 usb_dw_cfg.irq_enable_func(NULL);
889
890 usb_dw_ctrl.attached = 1U;
891
892 return 0;
893 }
894
usb_dc_detach(void)895 int usb_dc_detach(void)
896 {
897 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
898
899 if (!usb_dw_ctrl.attached) {
900 return 0;
901 }
902
903 irq_disable(DT_INST_IRQN(0));
904
905 /* Enable soft disconnect */
906 base->dctl |= USB_DWC2_DCTL_SFTDISCON;
907
908 usb_dw_ctrl.attached = 0U;
909
910 return 0;
911 }
912
usb_dc_reset(void)913 int usb_dc_reset(void)
914 {
915 int ret;
916
917 ret = usb_dw_reset();
918
919 /* Clear private data */
920 (void)memset(&usb_dw_ctrl, 0, sizeof(usb_dw_ctrl));
921
922 return ret;
923 }
924
usb_dc_set_address(const uint8_t addr)925 int usb_dc_set_address(const uint8_t addr)
926 {
927 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
928
929 if (addr > (USB_DWC2_DCFG_DEVADDR_MASK >> USB_DWC2_DCFG_DEVADDR_POS)) {
930 return -EINVAL;
931 }
932
933 base->dcfg &= ~USB_DWC2_DCFG_DEVADDR_MASK;
934 base->dcfg |= addr << USB_DWC2_DCFG_DEVADDR_POS;
935
936 return 0;
937 }
938
usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg)939 int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg)
940 {
941 uint8_t ep_idx = USB_EP_GET_IDX(cfg->ep_addr);
942
943 LOG_DBG("ep %x, mps %d, type %d", cfg->ep_addr, cfg->ep_mps,
944 cfg->ep_type);
945
946 if ((cfg->ep_type == USB_DC_EP_CONTROL) && ep_idx) {
947 LOG_ERR("invalid endpoint configuration");
948 return -1;
949 }
950
951 if (cfg->ep_mps > DW_USB_MAX_PACKET_SIZE) {
952 LOG_WRN("unsupported packet size");
953 return -1;
954 }
955
956 if (USB_EP_DIR_IS_OUT(cfg->ep_addr) && ep_idx >= USB_DW_OUT_EP_NUM) {
957 LOG_WRN("OUT endpoint address out of range");
958 return -1;
959 }
960
961 if (USB_EP_DIR_IS_IN(cfg->ep_addr) && ep_idx >= USB_DW_IN_EP_NUM) {
962 LOG_WRN("IN endpoint address out of range");
963 return -1;
964 }
965
966 return 0;
967 }
968
usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg)969 int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const ep_cfg)
970 {
971 uint8_t ep;
972
973 if (!ep_cfg) {
974 return -EINVAL;
975 }
976
977 ep = ep_cfg->ep_addr;
978
979 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
980 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
981 return -EINVAL;
982 }
983
984 usb_dw_ep_set(ep, ep_cfg->ep_mps, ep_cfg->ep_type);
985
986 return 0;
987 }
988
usb_dc_ep_set_stall(const uint8_t ep)989 int usb_dc_ep_set_stall(const uint8_t ep)
990 {
991 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
992 uint8_t ep_idx = USB_EP_GET_IDX(ep);
993
994 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
995 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
996 return -EINVAL;
997 }
998
999 if (USB_EP_DIR_IS_OUT(ep)) {
1000 base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_STALL;
1001 } else {
1002 base->in_ep[ep_idx].diepctl |= USB_DWC2_DEPCTL_STALL;
1003 }
1004
1005 return 0;
1006 }
1007
usb_dc_ep_clear_stall(const uint8_t ep)1008 int usb_dc_ep_clear_stall(const uint8_t ep)
1009 {
1010 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
1011 uint8_t ep_idx = USB_EP_GET_IDX(ep);
1012
1013 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1014 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1015 return -EINVAL;
1016 }
1017
1018 if (!ep_idx) {
1019 /* Not possible to clear stall for EP0 */
1020 return -EINVAL;
1021 }
1022
1023 if (USB_EP_DIR_IS_OUT(ep)) {
1024 base->out_ep[ep_idx].doepctl &= ~USB_DWC2_DEPCTL_STALL;
1025 } else {
1026 base->in_ep[ep_idx].diepctl &= ~USB_DWC2_DEPCTL_STALL;
1027 }
1028
1029 return 0;
1030 }
1031
usb_dc_ep_halt(const uint8_t ep)1032 int usb_dc_ep_halt(const uint8_t ep)
1033 {
1034 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
1035 uint8_t ep_idx = USB_EP_GET_IDX(ep);
1036 volatile uint32_t *p_depctl;
1037
1038 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1039 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1040 return -EINVAL;
1041 }
1042
1043 if (!ep_idx) {
1044 /* Cannot disable EP0, just set stall */
1045 usb_dc_ep_set_stall(ep);
1046 } else {
1047 if (USB_EP_DIR_IS_OUT(ep)) {
1048 p_depctl = &base->out_ep[ep_idx].doepctl;
1049 } else {
1050 p_depctl = &base->in_ep[ep_idx].diepctl;
1051 }
1052
1053 /* Set STALL and disable endpoint if enabled */
1054 if (*p_depctl & USB_DWC2_DEPCTL_EPENA) {
1055 *p_depctl |= USB_DWC2_DEPCTL_EPDIS | USB_DWC2_DEPCTL_STALL;
1056 } else {
1057 *p_depctl |= USB_DWC2_DEPCTL_STALL;
1058 }
1059 }
1060
1061 return 0;
1062 }
1063
usb_dc_ep_is_stalled(const uint8_t ep,uint8_t * const stalled)1064 int usb_dc_ep_is_stalled(const uint8_t ep, uint8_t *const stalled)
1065 {
1066 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
1067 uint8_t ep_idx = USB_EP_GET_IDX(ep);
1068
1069 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1070 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1071 return -EINVAL;
1072 }
1073
1074 if (!stalled) {
1075 return -EINVAL;
1076 }
1077
1078 *stalled = 0U;
1079 if (USB_EP_DIR_IS_OUT(ep)) {
1080 if (base->out_ep[ep_idx].doepctl & USB_DWC2_DEPCTL_STALL) {
1081 *stalled = 1U;
1082 }
1083 } else {
1084 if (base->in_ep[ep_idx].diepctl & USB_DWC2_DEPCTL_STALL) {
1085 *stalled = 1U;
1086 }
1087 }
1088
1089 return 0;
1090 }
1091
usb_dc_ep_enable(const uint8_t ep)1092 int usb_dc_ep_enable(const uint8_t ep)
1093 {
1094 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
1095 uint8_t ep_idx = USB_EP_GET_IDX(ep);
1096
1097 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1098 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1099 return -EINVAL;
1100 }
1101
1102 /* enable EP interrupts */
1103 if (USB_EP_DIR_IS_OUT(ep)) {
1104 base->daintmsk |= USB_DWC2_DAINT_OUTEPINT(ep_idx);
1105 } else {
1106 base->daintmsk |= USB_DWC2_DAINT_INEPINT(ep_idx);
1107 }
1108
1109 /* Activate Ep */
1110 if (USB_EP_DIR_IS_OUT(ep)) {
1111 base->out_ep[ep_idx].doepctl |= USB_DWC2_DEPCTL_USBACTEP;
1112 usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena = 1U;
1113 } else {
1114 base->in_ep[ep_idx].diepctl |= USB_DWC2_DEPCTL_USBACTEP;
1115 usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena = 1U;
1116 }
1117
1118 if (USB_EP_DIR_IS_OUT(ep) &&
1119 usb_dw_ctrl.out_ep_ctrl[ep_idx].cb != usb_transfer_ep_callback) {
1120 /* Start reading now, except for transfer managed eps */
1121 usb_dw_prep_rx(ep, 0);
1122 }
1123
1124 return 0;
1125 }
1126
usb_dc_ep_disable(const uint8_t ep)1127 int usb_dc_ep_disable(const uint8_t ep)
1128 {
1129 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
1130 uint8_t ep_idx = USB_EP_GET_IDX(ep);
1131
1132 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1133 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1134 return -EINVAL;
1135 }
1136
1137 /* Disable EP interrupts */
1138 if (USB_EP_DIR_IS_OUT(ep)) {
1139 base->daintmsk &= ~USB_DWC2_DAINT_OUTEPINT(ep_idx);
1140 base->doepmsk &= ~USB_DWC2_DOEPINT_SETUP;
1141 } else {
1142 base->daintmsk &= ~USB_DWC2_DAINT_INEPINT(ep_idx);
1143 base->diepmsk &= ~USB_DWC2_DIEPINT_XFERCOMPL;
1144 base->gintmsk &= ~USB_DWC2_GINTSTS_RXFLVL;
1145 }
1146
1147 /* De-activate, disable and set NAK for Ep */
1148 if (USB_EP_DIR_IS_OUT(ep)) {
1149 base->out_ep[ep_idx].doepctl &=
1150 ~(USB_DWC2_DEPCTL_USBACTEP |
1151 USB_DWC2_DEPCTL_EPENA |
1152 USB_DWC2_DEPCTL_SNAK);
1153 usb_dw_ctrl.out_ep_ctrl[ep_idx].ep_ena = 0U;
1154 } else {
1155 base->in_ep[ep_idx].diepctl &=
1156 ~(USB_DWC2_DEPCTL_USBACTEP |
1157 USB_DWC2_DEPCTL_EPENA |
1158 USB_DWC2_DEPCTL_SNAK);
1159 usb_dw_ctrl.in_ep_ctrl[ep_idx].ep_ena = 0U;
1160 }
1161
1162 return 0;
1163 }
1164
usb_dc_ep_flush(const uint8_t ep)1165 int usb_dc_ep_flush(const uint8_t ep)
1166 {
1167 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
1168 uint8_t ep_idx = USB_EP_GET_IDX(ep);
1169 uint32_t cnt;
1170
1171 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1172 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1173 return -EINVAL;
1174 }
1175
1176 if (USB_EP_DIR_IS_OUT(ep)) {
1177 /* RX FIFO is global and cannot be flushed per EP */
1178 return -EINVAL;
1179 }
1180
1181 /* Each endpoint has dedicated Tx FIFO */
1182 base->grstctl |= ep_idx << USB_DWC2_GRSTCTL_TXFNUM_POS;
1183 base->grstctl |= USB_DWC2_GRSTCTL_TXFFLSH;
1184
1185 cnt = 0U;
1186
1187 do {
1188 if (++cnt > USB_DW_CORE_RST_TIMEOUT_US) {
1189 LOG_ERR("USB TX FIFO flush HANG!");
1190 return -EIO;
1191 }
1192 usb_dw_udelay(1);
1193 } while (base->grstctl & USB_DWC2_GRSTCTL_TXFFLSH);
1194
1195 return 0;
1196 }
1197
usb_dc_ep_write(const uint8_t ep,const uint8_t * const data,const uint32_t data_len,uint32_t * const ret_bytes)1198 int usb_dc_ep_write(const uint8_t ep, const uint8_t *const data,
1199 const uint32_t data_len, uint32_t * const ret_bytes)
1200 {
1201 int ret;
1202
1203 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1204 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1205 return -EINVAL;
1206 }
1207
1208 /* Check if IN ep */
1209 if (USB_EP_GET_DIR(ep) != USB_EP_DIR_IN) {
1210 return -EINVAL;
1211 }
1212
1213 /* Check if ep enabled */
1214 if (!usb_dw_ep_is_enabled(ep)) {
1215 return -EINVAL;
1216 }
1217
1218 ret = usb_dw_tx(ep, data, data_len);
1219 if (ret < 0) {
1220 return ret;
1221 }
1222
1223 if (ret_bytes) {
1224 *ret_bytes = ret;
1225 }
1226
1227 return 0;
1228 }
1229
usb_dc_ep_read_wait(uint8_t ep,uint8_t * data,uint32_t max_data_len,uint32_t * read_bytes)1230 int usb_dc_ep_read_wait(uint8_t ep, uint8_t *data, uint32_t max_data_len,
1231 uint32_t *read_bytes)
1232 {
1233 struct usb_dwc2_reg *const base = usb_dw_cfg.base;
1234 uint8_t ep_idx = USB_EP_GET_IDX(ep);
1235 uint32_t i, j, data_len, bytes_to_copy;
1236
1237 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1238 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1239 return -EINVAL;
1240 }
1241
1242 /* Check if OUT ep */
1243 if (USB_EP_GET_DIR(ep) != USB_EP_DIR_OUT) {
1244 LOG_ERR("Wrong endpoint direction");
1245 return -EINVAL;
1246 }
1247
1248 /* Allow to read 0 bytes */
1249 if (!data && max_data_len) {
1250 LOG_ERR("Wrong arguments");
1251 return -EINVAL;
1252 }
1253
1254 /* Check if ep enabled */
1255 if (!usb_dw_ep_is_enabled(ep)) {
1256 LOG_ERR("Not enabled endpoint");
1257 return -EINVAL;
1258 }
1259
1260 data_len = usb_dw_ctrl.out_ep_ctrl[ep_idx].data_len;
1261
1262 if (!data && !max_data_len) {
1263 /* When both buffer and max data to read are zero return
1264 * the available data in buffer
1265 */
1266 if (read_bytes) {
1267 *read_bytes = data_len;
1268 }
1269 return 0;
1270 }
1271
1272
1273 if (data_len > max_data_len) {
1274 LOG_ERR("Not enough room to copy all the rcvd data!");
1275 bytes_to_copy = max_data_len;
1276 } else {
1277 bytes_to_copy = data_len;
1278 }
1279
1280 LOG_DBG("Read EP%d, req %d, read %d bytes", ep, max_data_len,
1281 bytes_to_copy);
1282
1283 /* Data in the FIFOs is always stored per 32-bit words */
1284 for (i = 0U; i < (bytes_to_copy & ~0x3); i += 4U) {
1285 *(uint32_t *)(data + i) = USB_DW_EP_FIFO(base, ep_idx);
1286 }
1287 if (bytes_to_copy & 0x3) {
1288 /* Not multiple of 4 */
1289 uint32_t last_dw = USB_DW_EP_FIFO(base, ep_idx);
1290
1291 for (j = 0U; j < (bytes_to_copy & 0x3); j++) {
1292 *(data + i + j) =
1293 (sys_cpu_to_le32(last_dw) >> (j * 8U)) & 0xFF;
1294 }
1295 }
1296
1297 usb_dw_ctrl.out_ep_ctrl[ep_idx].data_len -= bytes_to_copy;
1298
1299 if (read_bytes) {
1300 *read_bytes = bytes_to_copy;
1301 }
1302
1303 return 0;
1304
1305 }
1306
usb_dc_ep_read_continue(uint8_t ep)1307 int usb_dc_ep_read_continue(uint8_t ep)
1308 {
1309 uint8_t ep_idx = USB_EP_GET_IDX(ep);
1310
1311 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1312 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1313 return -EINVAL;
1314 }
1315
1316 /* Check if OUT ep */
1317 if (USB_EP_GET_DIR(ep) != USB_EP_DIR_OUT) {
1318 LOG_ERR("Wrong endpoint direction");
1319 return -EINVAL;
1320 }
1321
1322 if (!usb_dw_ctrl.out_ep_ctrl[ep_idx].data_len) {
1323 usb_dw_prep_rx(ep_idx, 0);
1324 }
1325
1326 return 0;
1327 }
1328
usb_dc_ep_read(const uint8_t ep,uint8_t * const data,const uint32_t max_data_len,uint32_t * const read_bytes)1329 int usb_dc_ep_read(const uint8_t ep, uint8_t *const data,
1330 const uint32_t max_data_len, uint32_t * const read_bytes)
1331 {
1332 if (usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes) != 0) {
1333 return -EINVAL;
1334 }
1335
1336 if (!data && !max_data_len) {
1337 /* When both buffer and max data to read are zero the above
1338 * call would fetch the data len and we simply return.
1339 */
1340 return 0;
1341 }
1342
1343 if (usb_dc_ep_read_continue(ep) != 0) {
1344 return -EINVAL;
1345 }
1346
1347 return 0;
1348 }
1349
usb_dc_ep_set_callback(const uint8_t ep,const usb_dc_ep_callback cb)1350 int usb_dc_ep_set_callback(const uint8_t ep, const usb_dc_ep_callback cb)
1351 {
1352 uint8_t ep_idx = USB_EP_GET_IDX(ep);
1353
1354 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1355 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1356 return -EINVAL;
1357 }
1358
1359 if (USB_EP_DIR_IS_IN(ep)) {
1360 usb_dw_ctrl.in_ep_ctrl[ep_idx].cb = cb;
1361 } else {
1362 usb_dw_ctrl.out_ep_ctrl[ep_idx].cb = cb;
1363 }
1364
1365 return 0;
1366 }
1367
usb_dc_set_status_callback(const usb_dc_status_callback cb)1368 void usb_dc_set_status_callback(const usb_dc_status_callback cb)
1369 {
1370 usb_dw_ctrl.status_cb = cb;
1371 }
1372
usb_dc_ep_mps(const uint8_t ep)1373 int usb_dc_ep_mps(const uint8_t ep)
1374 {
1375 enum usb_dw_out_ep_idx ep_idx = USB_EP_GET_IDX(ep);
1376
1377 if (!usb_dw_ctrl.attached || !usb_dw_ep_is_valid(ep)) {
1378 LOG_ERR("Not attached / Invalid endpoint: EP 0x%x", ep);
1379 return -EINVAL;
1380 }
1381
1382 if (USB_EP_DIR_IS_OUT(ep)) {
1383 return usb_dw_ctrl.out_ep_ctrl[ep_idx].mps;
1384 } else {
1385 return usb_dw_ctrl.in_ep_ctrl[ep_idx].mps;
1386 }
1387 }
1388