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