Intel® Quark™ Microcontroller Software Interface 1.4.0 Intel® Quark™ Microcontroller BSP

- Main Page
- Modules
- Data Structures
- Files

- File List

qm_usb.c
1 /*
2 * {% copyright %}
3 */
4
5 #include "qm_usb.h"
6 #include "clk.h"
7 #include <string.h>
8
9 /** USB registers masks */
10 #define QM_USB_GRSTCTL_AHB_IDLE BIT(31)
11 #define QM_USB_GRSTCTL_TX_FNUM_OFFSET (6)
12 #define QM_USB_GRSTCTL_TX_FFLSH BIT(5)
13 #define QM_USB_GRSTCTL_C_SFT_RST BIT(0)
14 #define QM_USB_GAHBCFG_DMA_EN BIT(5)
15 #define QM_USB_GAHBCFG_GLB_INTR_MASK BIT(0)
16 #define QM_USB_DCTL_SFT_DISCON BIT(1)
17 #define QM_USB_GINTSTS_WK_UP_INT BIT(31)
18 #define QM_USB_GINTSTS_OEP_INT BIT(19)
19 #define QM_USB_GINTSTS_IEP_INT BIT(18)
20 #define QM_USB_GINTSTS_ENUM_DONE BIT(13)
21 #define QM_USB_GINTSTS_USB_RST BIT(12)
22 #define QM_USB_GINTSTS_USB_SUSP BIT(11)
23 #define QM_USB_GINTSTS_RX_FLVL BIT(4)
24 #define QM_USB_GINTSTS_OTG_INT BIT(2)
25 #define QM_USB_DCFG_DEV_SPD_LS (0x2)
26 #define QM_USB_DCFG_DEV_SPD_FS (0x3)
27 #define QM_USB_DCFG_DEV_ADDR_MASK (0x7F << 4)
28 #define QM_USB_DCFG_DEV_ADDR_OFFSET (4)
29 #define QM_USB_DAINT_IN_EP_INT(ep) (1 << (ep))
30 #define QM_USB_DAINT_OUT_EP_INT(ep) (0x10000 << (ep))
31 #define QM_USB_DEPCTL_EP_ENA BIT(31)
32 #define QM_USB_DEPCTL_EP_DIS BIT(30)
33 #define QM_USB_DEPCTL_SETDOPID BIT(28)
34 #define QM_USB_DEPCTL_SNAK BIT(27)
35 #define QM_USB_DEPCTL_CNAK BIT(26)
36 #define QM_USB_DEPCTL_STALL BIT(21)
37 #define QM_USB_DEPCTL_EP_TYPE_MASK (0x3 << 18)
38 #define QM_USB_DEPCTL_EP_TYPE_OFFSET (18)
39 #define QM_USB_DEPCTL_EP_TYPE_CONTROL (0)
40 #define QM_USB_DEPCTL_EP_TYPE_ISO (0x1)
41 #define QM_USB_DEPCTL_EP_TYPE_BULK (0x2)
42 #define QM_USB_DEPCTL_EP_TYPE_INTERRUPT (0x3)
43 #define QM_USB_DEPCTL_USB_ACT_EP BIT(15)
44 #define QM_USB_DEPCTL0_MSP_MASK (0x3)
45 #define QM_USB_DEPCTL0_MSP_8 (0x3)
46 #define QM_USB_DEPCTL0_MSP_16 (0x2)
47 #define QM_USB_DEPCTL0_MSP_32 (0x1)
48 #define QM_USB_DEPCTL0_MSP_64 (0)
49 #define QM_USB_DEPCTLn_MSP_MASK (0x3FF)
50 #define QM_USB_DEPCTL_MSP_OFFSET (0)
51 #define QM_USB_DOEPTSIZ_SUP_CNT_MASK (0x3 << 29)
52 #define QM_USB_DOEPTSIZ_SUP_CNT_OFFSET (29)
53 #define QM_USB_DOEPTSIZ0_PKT_CNT_MASK (0x1 << 19)
54 #define QM_USB_DOEPTSIZn_PKT_CNT_MASK (0x3FF << 19)
55 #define QM_USB_DIEPTSIZ0_PKT_CNT_MASK (0x3 << 19)
56 #define QM_USB_DIEPTSIZn_PKT_CNT_MASK (0x3FF << 19)
57 #define QM_USB_DEPTSIZ_PKT_CNT_OFFSET (19)
58 #define QM_USB_DEPTSIZ0_XFER_SIZE_MASK (0x7F)
59 #define QM_USB_DEPTSIZn_XFER_SIZE_MASK (0x7FFFF)
60 #define QM_USB_DEPTSIZ_XFER_SIZE_OFFSET (0)
61 #define QM_USB_DIEPINT_XFER_COMPL BIT(0)
62 #define QM_USB_DIEPINT_TX_FEMP BIT(7)
63 #define QM_USB_DIEPINT_XFER_COMPL BIT(0)
64 #define QM_USB_DOEPINT_SET_UP BIT(3)
65 #define QM_USB_DOEPINT_XFER_COMPL BIT(0)
66 #define QM_USB_DSTS_ENUM_SPD_MASK (0x3)
67 #define QM_USB_DSTS_ENUM_SPD_OFFSET (1)
68 #define QM_USB_DSTS_ENUM_LS (2)
69 #define QM_USB_DSTS_ENUM_FS (3)
70 #define QM_USB_GRXSTSR_EP_NUM_MASK (0xF << 0)
71 #define QM_USB_GRXSTSR_PKT_STS_MASK (0xF << 17)
72 #define QM_USB_GRXSTSR_PKT_STS_OFFSET (17)
73 #define QM_USB_GRXSTSR_PKT_CNT_MASK (0x7FF << 4)
74 #define QM_USB_GRXSTSR_PKT_CNT_OFFSET (4)
75 #define QM_USB_GRXSTSR_PKT_STS_OUT_DATA (2)
76 #define QM_USB_GRXSTSR_PKT_STS_OUT_DATA_DONE (3)
77 #define QM_USB_GRXSTSR_PKT_STS_SETUP_DONE (4)
78 #define QM_USB_GRXSTSR_PKT_STS_SETUP (6)
79 #define QM_USB_DTXFSTS_TXF_SPC_AVAIL_MASK (0xFFFF)
80
81 #define QM_USB_CORE_RST_TIMEOUT_US (10000)
82 #define QM_USB_PLL_TIMEOUT_US (100)
83
84 /** Check if an Endpoint is of direction IN. */
85 #define IS_IN_EP(ep) (ep < QM_USB_IN_EP_NUM)
86
87 /** Number of SETUP back-to-back packets */
88 #define QM_USB_SUP_CNT (1)
89
90 #if (UNIT_TEST)
91 #define QM_USB_EP_FIFO(ep) (ep)
92 #else
93 #define QM_USB_EP_FIFO(ep) (*(uint32_t *)(QM_USB_0_BASE + 0x1000 * (ep + 1)))
94 #endif
95
96 /*
97 * Endpoint instance data.
98 */
99 typedef struct {
100 bool enabled;
101 uint32_t data_len;
102 const qm_usb_ep_config_t *ep_config;
103 } usb_ep_priv_t;
104
105 /*
106 * USB controller instance data.
107 */
108 typedef struct {
109 qm_usb_status_callback_t status_callback;
110 usb_ep_priv_t ep_ctrl[QM_USB_IN_EP_NUM + QM_USB_OUT_EP_NUM];
111 bool attached;
112 void *user_data;
113 } usb_priv_t;
114
115 static usb_priv_t usb_ctrl[QM_USB_NUM];
116
117 static bool usb_dc_ep_is_valid(const qm_usb_ep_idx_t ep)
118 {
119 return (ep < QM_USB_IN_EP_NUM + QM_USB_OUT_EP_NUM);
120 }
121
122 static int usb_dc_reset(const qm_usb_t usb)
123 {
124 uint32_t cnt = 0;
125
126 /* Wait for AHB master idle state. */
127 while (!(QM_USB[usb].grstctl & QM_USB_GRSTCTL_AHB_IDLE)) {
128 clk_sys_udelay(1);
129 if (++cnt > QM_USB_CORE_RST_TIMEOUT_US) {
130 return -EIO;
131 }
132 }
133
134 /* Core Soft Reset */
135 cnt = 0;
136 QM_USB[usb].grstctl |= QM_USB_GRSTCTL_C_SFT_RST;
137 do {
138 if (++cnt > QM_USB_CORE_RST_TIMEOUT_US) {
139 return -EIO;
140 }
141 clk_sys_udelay(1);
142 } while (QM_USB[usb].grstctl & QM_USB_GRSTCTL_C_SFT_RST);
143
144 /* Wait for 3 PHY Clocks */
145 clk_sys_udelay(100);
146
147 return 0;
148 }
149
150 static void usb_dc_prep_rx(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
151 uint8_t setup)
152 {
153 /* We know this is an OUT EP always. */
154 const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
155 const uint16_t ep_mps =
156 usb_ctrl[usb].ep_ctrl[ep].ep_config->max_packet_size;
157
158 /* Set max RX size to EP mps so we get an interrupt
159 * each time a packet is received
160 */
161
162 QM_USB[usb].out_ep_reg[ep_idx].doeptsiz =
163 (QM_USB_SUP_CNT << QM_USB_DOEPTSIZ_SUP_CNT_OFFSET) |
164 (1 << QM_USB_DEPTSIZ_PKT_CNT_OFFSET) | ep_mps;
165
166 /* Clear NAK and enable ep */
167 if (!setup) {
168 QM_USB[usb].out_ep_reg[ep_idx].doepctl |= QM_USB_DEPCTL_CNAK;
169 }
170 QM_USB[usb].out_ep_reg[ep_idx].doepctl |= QM_USB_DEPCTL_EP_ENA;
171 }
172
173 static int usb_dc_tx(const qm_usb_t usb, uint8_t ep, const uint8_t *const data,
174 uint32_t data_len)
175 {
176 uint32_t max_xfer_size, max_pkt_cnt, pkt_cnt, avail_space;
177 const uint16_t ep_mps =
178 usb_ctrl[usb].ep_ctrl[ep].ep_config->max_packet_size;
179 uint32_t i;
180
181 /* Check if FIFO space available */
182 avail_space = QM_USB[usb].in_ep_reg[ep].dtxfsts &
183 QM_USB_DTXFSTS_TXF_SPC_AVAIL_MASK;
184 avail_space *= 4;
185 if (!avail_space) {
186 return -EAGAIN;
187 }
188
189 if (data_len > avail_space)
190 data_len = avail_space;
191
192 if (data_len != 0) {
193 /* Get max packet size and packet count for ep */
194 if (ep == QM_USB_IN_EP_0) {
195 max_pkt_cnt = QM_USB_DIEPTSIZ0_PKT_CNT_MASK >>
196 QM_USB_DEPTSIZ_PKT_CNT_OFFSET;
197 max_xfer_size = QM_USB_DEPTSIZ0_XFER_SIZE_MASK >>
198 QM_USB_DEPTSIZ_XFER_SIZE_OFFSET;
199 } else {
200 max_pkt_cnt = QM_USB_DIEPTSIZn_PKT_CNT_MASK >>
201 QM_USB_DEPTSIZ_PKT_CNT_OFFSET;
202 max_xfer_size = QM_USB_DEPTSIZn_XFER_SIZE_MASK >>
203 QM_USB_DEPTSIZ_XFER_SIZE_OFFSET;
204 }
205
206 /* Check if transfer len is too big */
207 if (data_len > max_xfer_size) {
208 data_len = max_xfer_size;
209 }
210
211 /*
212 * Program the transfer size and packet count as follows:
213 *
214 * transfer size = N * ep_maxpacket + short_packet
215 * pktcnt = N + (short_packet exist ? 1 : 0)
216 */
217 pkt_cnt = (data_len + ep_mps - 1) / ep_mps;
218
219 if (pkt_cnt > max_pkt_cnt) {
220 pkt_cnt = max_pkt_cnt;
221 data_len = pkt_cnt * ep_mps;
222 }
223 } else {
224 /* Zero length packet */
225 pkt_cnt = 1;
226 }
227
228 /* Set number of packets and transfer size */
229 QM_USB[usb].in_ep_reg[ep].dieptsiz =
230 (pkt_cnt << QM_USB_DEPTSIZ_PKT_CNT_OFFSET) | data_len;
231
232 /* Clear NAK and enable ep */
233 QM_USB[usb].in_ep_reg[ep].diepctl |= QM_USB_DEPCTL_CNAK;
234 QM_USB[usb].in_ep_reg[ep].diepctl |= QM_USB_DEPCTL_EP_ENA;
235
236 /* Write data to FIFO */
237 for (i = 0; i < data_len; i += 4)
238 QM_USB_EP_FIFO(ep) = *(uint32_t *)(data + i);
239
240 return data_len;
241 }
242
243 static void usb_dc_handle_reset(const qm_usb_t usb)
244 {
245 if (usb_ctrl[usb].status_callback) {
246 usb_ctrl[usb].status_callback(usb_ctrl[usb].user_data, 0,
247 QM_USB_RESET);
248 }
249
250 /* Set device address to zero after reset */
251 QM_USB[usb].dcfg &= ~QM_USB_DCFG_DEV_ADDR_MASK;
252
253 /* enable global EP interrupts */
254 QM_USB[usb].doepmsk = 0;
255 QM_USB[usb].gintmsk |= QM_USB_GINTSTS_RX_FLVL;
256 QM_USB[usb].diepmsk |= QM_USB_DIEPINT_XFER_COMPL;
257 }
258
259 static void usb_dc_handle_enum_done(const qm_usb_t usb)
260 {
261 if (usb_ctrl[usb].status_callback) {
262 usb_ctrl[usb].status_callback(usb_ctrl[usb].user_data, 0,
263 QM_USB_CONNECTED);
264 }
265 }
266
267 static __inline__ void handle_rx_fifo(const qm_usb_t usb)
268 {
269 const uint32_t grxstsp = QM_USB[usb].grxstsp;
270
271 const uint8_t ep_idx =
272 (grxstsp & QM_USB_GRXSTSR_EP_NUM_MASK) + QM_USB_IN_EP_NUM;
273 const uint32_t status = (grxstsp & QM_USB_GRXSTSR_PKT_STS_MASK) >>
274 QM_USB_GRXSTSR_PKT_STS_OFFSET;
275 const uint32_t xfer_size = (grxstsp & QM_USB_GRXSTSR_PKT_CNT_MASK) >>
276 QM_USB_GRXSTSR_PKT_CNT_OFFSET;
277 const qm_usb_ep_config_t *const ep_cfg =
278 usb_ctrl[usb].ep_ctrl[ep_idx].ep_config;
279
280 void (*ep_cb)(void *data, int error, qm_usb_ep_idx_t ep,
281 qm_usb_ep_status_t cb_status) = ep_cfg->callback;
282
283 usb_ctrl[usb].ep_ctrl[ep_idx].data_len = xfer_size;
284
285 if (ep_cb) {
286 const qm_usb_status_t usb_status =
287 (status == QM_USB_GRXSTSR_PKT_STS_SETUP)
288 ? QM_USB_EP_SETUP
289 : QM_USB_EP_DATA_OUT;
290
291 ep_cb(ep_cfg->callback_data, 0, ep_idx, usb_status);
292 }
293 }
294
295 static __inline__ void handle_in_ep_intr(const qm_usb_t usb)
296 {
297 uint32_t ep_intr_sts;
298 uint8_t ep_idx;
299 void (*ep_cb)(void *data, int error, qm_usb_ep_idx_t ep,
300 qm_usb_ep_status_t cb_status);
301
302 for (ep_idx = 0; ep_idx < QM_USB_IN_EP_NUM; ep_idx++) {
303 if (QM_USB[usb].daint & QM_USB_DAINT_IN_EP_INT(ep_idx)) {
304 /* Read IN EP interrupt status. */
305 ep_intr_sts = QM_USB[usb].in_ep_reg[ep_idx].diepint &
306 QM_USB[usb].diepmsk;
307
308 /* Clear IN EP interrupts. */
309 QM_USB[usb].in_ep_reg[ep_idx].diepint = ep_intr_sts;
310
311 ep_cb =
312 usb_ctrl[usb].ep_ctrl[ep_idx].ep_config->callback;
313
314 if (ep_intr_sts & QM_USB_DIEPINT_XFER_COMPL && ep_cb) {
315 ep_cb(usb_ctrl[usb]
316 .ep_ctrl[ep_idx]
317 .ep_config->callback_data,
318 0, ep_idx, QM_USB_EP_DATA_IN);
319 }
320 }
321 }
322
323 /* Clear interrupt. */
324 QM_USB[usb].gintsts = QM_USB_GINTSTS_IEP_INT;
325 }
326
327 static __inline__ void handle_out_ep_intr(const qm_usb_t usb)
328 {
329 uint32_t ep_intr_sts;
330 uint8_t ep_idx;
331
332 /* No OUT interrupt expected in FIFO mode, just clear
333 * interrupts. */
334 for (ep_idx = 0; ep_idx < QM_USB_OUT_EP_NUM; ep_idx++) {
335 if (QM_USB[usb].daint & QM_USB_DAINT_OUT_EP_INT(ep_idx)) {
336 /* Read OUT EP interrupt status. */
337 ep_intr_sts = QM_USB[usb].out_ep_reg[ep_idx].doepint &
338 QM_USB[usb].doepmsk;
339
340 /* Clear OUT EP interrupts. */
341 QM_USB[usb].out_ep_reg[ep_idx].doepint = ep_intr_sts;
342 }
343 }
344
345 /* Clear interrupt. */
346 QM_USB[usb].gintsts = QM_USB_GINTSTS_OEP_INT;
347 }
348
349 /* USB ISR handler */
350 static void usb_dc_isr_handler(const qm_usb_t usb)
351 {
352 uint32_t int_status;
353
354 /* Read interrupt status */
355 while ((int_status = (QM_USB[usb].gintsts & QM_USB[usb].gintmsk))) {
356
357 if (int_status & QM_USB_GINTSTS_USB_RST) {
358 /* Clear interrupt. */
359 QM_USB[usb].gintsts = QM_USB_GINTSTS_USB_RST;
360
361 /* Reset detected */
362 usb_dc_handle_reset(usb);
363 }
364
365 if (int_status & QM_USB_GINTSTS_ENUM_DONE) {
366 /* Clear interrupt. */
367 QM_USB[usb].gintsts = QM_USB_GINTSTS_ENUM_DONE;
368
369 /* Enumeration done detected */
370 usb_dc_handle_enum_done(usb);
371 }
372
373 if (int_status & QM_USB_GINTSTS_USB_SUSP) {
374 /* Clear interrupt. */
375 QM_USB[usb].gintsts = QM_USB_GINTSTS_USB_SUSP;
376
377 if (usb_ctrl[usb].status_callback) {
378 usb_ctrl[usb].status_callback(
379 usb_ctrl[usb].user_data, 0, QM_USB_SUSPEND);
380 }
381 }
382
383 if (int_status & QM_USB_GINTSTS_WK_UP_INT) {
384 /* Clear interrupt. */
385 QM_USB[usb].gintsts = QM_USB_GINTSTS_WK_UP_INT;
386
387 if (usb_ctrl[usb].status_callback) {
388 usb_ctrl[usb].status_callback(
389 usb_ctrl[usb].user_data, 0, QM_USB_RESUME);
390 }
391 }
392
393 if (int_status & QM_USB_GINTSTS_RX_FLVL) {
394 /* Packet in RX FIFO. */
395 handle_rx_fifo(usb);
396 }
397
398 if (int_status & QM_USB_GINTSTS_IEP_INT) {
399 /* IN EP interrupt. */
400 handle_in_ep_intr(usb);
401 }
402
403 if (int_status & QM_USB_GINTSTS_OEP_INT) {
404 /* OUT EP interrupt. */
405 handle_out_ep_intr(usb);
406 }
407 }
408 }
409
410 QM_ISR_DECLARE(qm_usb_0_isr)
411 {
412 usb_dc_isr_handler(QM_USB_0);
413 QM_ISR_EOI(QM_IRQ_USB_0_INT_VECTOR);
414 }
415
416 int qm_usb_attach(const qm_usb_t usb)
417 {
418 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
419
420 uint8_t ep;
421
422 if (usb_ctrl[usb].attached) {
423 return 0;
424 }
425
426 clk_sys_usb_enable();
427
428 const int ret = usb_dc_reset(usb);
429 if (ret)
430 return ret;
431
432 /* Set device speed to FS */
433 QM_USB[usb].dcfg |= QM_USB_DCFG_DEV_SPD_FS;
434
435 /* No FIFO setup needed, the default values are used. */
436 /* Set NAK for all OUT EPs. */
437 for (ep = 0; ep < QM_USB_OUT_EP_NUM; ep++) {
438 QM_USB[usb].out_ep_reg[ep].doepctl = QM_USB_DEPCTL_SNAK;
439 }
440
441 /* Enable global interrupts. */
442 QM_USB[usb].gintmsk =
443 QM_USB_GINTSTS_OEP_INT | QM_USB_GINTSTS_IEP_INT |
444 QM_USB_GINTSTS_ENUM_DONE | QM_USB_GINTSTS_USB_RST |
445 QM_USB_GINTSTS_WK_UP_INT | QM_USB_GINTSTS_USB_SUSP;
446
447 /* Enable global interrupt. */
448 QM_USB[usb].gahbcfg |= QM_USB_GAHBCFG_GLB_INTR_MASK;
449
450 /* Disable soft disconnect. */
451 QM_USB[usb].dctl &= ~QM_USB_DCTL_SFT_DISCON;
452
453 usb_ctrl[usb].attached = true;
454
455 return 0;
456 }
457
458 int qm_usb_detach(const qm_usb_t usb)
459 {
460 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
461
462 if (!usb_ctrl[usb].attached) {
463 return 0;
464 }
465
466 clk_sys_usb_disable();
467
468 /* Enable soft disconnect. */
469 QM_USB[usb].dctl |= QM_USB_DCTL_SFT_DISCON;
470
471 usb_ctrl[usb].attached = false;
472
473 return 0;
474 }
475
476 int qm_usb_reset(const qm_usb_t usb)
477 {
478 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
479 return usb_dc_reset(usb);
480 }
481
482 int qm_usb_set_address(const qm_usb_t usb, const uint8_t addr)
483 {
484 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
485 QM_CHECK(addr <
486 (QM_USB_DCFG_DEV_ADDR_MASK >> QM_USB_DCFG_DEV_ADDR_OFFSET),
487 -EINVAL);
488
489 QM_USB[usb].dcfg &= ~QM_USB_DCFG_DEV_ADDR_MASK;
490 QM_USB[usb].dcfg |= addr << QM_USB_DCFG_DEV_ADDR_OFFSET;
491
492 return 0;
493 }
494
495 int qm_usb_ep_set_config(const qm_usb_t usb,
496 const qm_usb_ep_config_t *const ep_cfg)
497 {
498 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
499 QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
500 QM_CHECK(ep_cfg, -EINVAL);
501 if (!usb_dc_ep_is_valid(ep_cfg->ep)) {
502 return -EINVAL;
503 }
504
505 volatile uint32_t *p_depctl;
506 const uint8_t ep_idx = ep_cfg->ep < QM_USB_IN_EP_NUM
507 ? ep_cfg->ep
508 : ep_cfg->ep - QM_USB_IN_EP_NUM;
509
510 if (!IS_IN_EP(ep_cfg->ep)) {
511 p_depctl = &QM_USB[usb].out_ep_reg[ep_idx].doepctl;
512 } else {
513 p_depctl = &QM_USB[usb].in_ep_reg[ep_idx].diepctl;
514 }
515
516 usb_ctrl[usb].ep_ctrl[ep_cfg->ep].ep_config = ep_cfg;
517
518 if (!ep_idx) {
519 /* Set max packet size for EP0 */
520 *p_depctl &= ~QM_USB_DEPCTL0_MSP_MASK;
521 switch (ep_cfg->max_packet_size) {
522 case 8:
523 *p_depctl |= QM_USB_DEPCTL0_MSP_8
524 << QM_USB_DEPCTL_MSP_OFFSET;
525 break;
526 case 16:
527 *p_depctl |= QM_USB_DEPCTL0_MSP_16
528 << QM_USB_DEPCTL_MSP_OFFSET;
529 break;
530 case 32:
531 *p_depctl |= QM_USB_DEPCTL0_MSP_32
532 << QM_USB_DEPCTL_MSP_OFFSET;
533 break;
534 case 64:
535 *p_depctl |= QM_USB_DEPCTL0_MSP_64
536 << QM_USB_DEPCTL_MSP_OFFSET;
537 break;
538 default:
539 return -EINVAL;
540 }
541 /* No need to set EP0 type */
542 } else {
543 /* Set max packet size for EP */
544 if (ep_cfg->max_packet_size >
545 (QM_USB_DEPCTLn_MSP_MASK >> QM_USB_DEPCTL_MSP_OFFSET))
546 return -EINVAL;
547
548 *p_depctl &= ~QM_USB_DEPCTLn_MSP_MASK;
549 *p_depctl |= ep_cfg->max_packet_size
550 << QM_USB_DEPCTL_MSP_OFFSET;
551
552 /* Set endpoint type */
553 *p_depctl &= ~QM_USB_DEPCTL_EP_TYPE_MASK;
554 switch (ep_cfg->type) {
555 case QM_USB_EP_CONTROL:
556 *p_depctl |= QM_USB_DEPCTL_EP_TYPE_CONTROL
557 << QM_USB_DEPCTL_EP_TYPE_OFFSET;
558 break;
559 case QM_USB_EP_BULK:
560 *p_depctl |= QM_USB_DEPCTL_EP_TYPE_BULK
561 << QM_USB_DEPCTL_EP_TYPE_OFFSET;
562 break;
563 case QM_USB_EP_INTERRUPT:
564 *p_depctl |= QM_USB_DEPCTL_EP_TYPE_INTERRUPT
565 << QM_USB_DEPCTL_EP_TYPE_OFFSET;
566 break;
567 default:
568 return -EINVAL;
569 }
570
571 /* sets the Endpoint Data PID to DATA0 */
572 *p_depctl |= QM_USB_DEPCTL_SETDOPID;
573 }
574
575 return 0;
576 }
577
578 int qm_usb_ep_set_stall_state(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
579 const bool is_stalled)
580 {
581 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
582 QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
583 if (!usb_dc_ep_is_valid(ep)) {
584 return -EINVAL;
585 }
586
587 const uint8_t ep_idx = IS_IN_EP(ep) ? ep : ep - QM_USB_IN_EP_NUM;
588
589 if (!is_stalled && !ep_idx) {
590 /* Not possible to clear stall for EP0 */
591 return -EINVAL;
592 }
593
594 if (IS_IN_EP(ep)) {
595 uint32_t reg = QM_USB[usb].in_ep_reg[ep_idx].diepctl;
596 reg ^= (-is_stalled ^ reg) & QM_USB_DEPCTL_STALL;
597 QM_USB[usb].in_ep_reg[ep_idx].diepctl = reg;
598
599 return 0;
600 }
601
602 uint32_t reg = QM_USB[usb].out_ep_reg[ep_idx].doepctl;
603 reg ^= (-is_stalled ^ reg) & QM_USB_DEPCTL_STALL;
604 QM_USB[usb].out_ep_reg[ep_idx].doepctl = reg;
605
606 return 0;
607 }
608
609 int qm_usb_ep_halt(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
610 {
611 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
612 QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
613 if (!usb_dc_ep_is_valid(ep)) {
614 return -EINVAL;
615 }
616
617 const uint8_t ep_idx = IS_IN_EP(ep) ? ep : ep - QM_USB_IN_EP_NUM;
618 volatile uint32_t *p_depctl;
619
620 /* Cannot disable EP0, just set stall */
621 if (!ep_idx) {
622 return qm_usb_ep_set_stall_state(usb, ep, true);
623 }
624
625 if (!IS_IN_EP(ep)) {
626 p_depctl = &QM_USB[usb].out_ep_reg[ep_idx].doepctl;
627 } else {
628 p_depctl = &QM_USB[usb].in_ep_reg[ep_idx].diepctl;
629 }
630
631 /* Set STALL and disable endpoint if enabled */
632 *p_depctl |= QM_USB_DEPCTL_STALL;
633 if (*p_depctl & QM_USB_DEPCTL_EP_ENA) {
634 *p_depctl |= QM_USB_DEPCTL_EP_DIS;
635 }
636
637 return 0;
638 }
639
640 int qm_usb_ep_is_stalled(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
641 bool *stalled)
642 {
643 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
644 QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
645 QM_CHECK(stalled, -EINVAL);
646 if (!usb_dc_ep_is_valid(ep)) {
647 return -EINVAL;
648 }
649
650 volatile uint32_t *p_depctl;
651
652 if (IS_IN_EP(ep)) {
653 p_depctl = &QM_USB[usb].in_ep_reg[ep].diepctl;
654 } else {
655 const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
656 p_depctl = &QM_USB[usb].out_ep_reg[ep_idx].doepctl;
657 }
658
659 *stalled = !!(*p_depctl & QM_USB_DEPCTL_STALL);
660
661 return 0;
662 }
663
664 int qm_usb_ep_enable(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
665 {
666 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
667 QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
668 if (!usb_dc_ep_is_valid(ep)) {
669 return -EINVAL;
670 }
671
672 usb_ctrl[usb].ep_ctrl[ep].enabled = true;
673
674 if (IS_IN_EP(ep)) {
675 /* Enable EP interrupts. */
676 QM_USB[usb].daintmsk |= QM_USB_DAINT_IN_EP_INT(ep);
677
678 /* Activate EP. */
679 QM_USB[usb].in_ep_reg[ep].diepctl |= QM_USB_DEPCTL_USB_ACT_EP;
680 } else {
681 const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
682
683 /* Enable EP interrupts. */
684 QM_USB[usb].daintmsk |= QM_USB_DAINT_OUT_EP_INT(ep_idx);
685
686 /* Activate EP. */
687 QM_USB[usb].out_ep_reg[ep_idx].doepctl |=
688 QM_USB_DEPCTL_USB_ACT_EP;
689
690 /* Prepare EP for rx. */
691 usb_dc_prep_rx(usb, ep, 0);
692 }
693
694 return 0;
695 }
696
697 int qm_usb_ep_disable(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
698 {
699 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
700 if (!usb_dc_ep_is_valid(ep)) {
701 return -EINVAL;
702 }
703
704 /* Disable EP intr then de-activate, disable and set NAK. */
705 if (!IS_IN_EP(ep)) {
706 const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
707
708 QM_USB[usb].daintmsk &= ~QM_USB_DAINT_OUT_EP_INT(ep_idx);
709 QM_USB[usb].doepmsk &= ~QM_USB_DOEPINT_SET_UP;
710 QM_USB[usb].out_ep_reg[ep_idx].doepctl &=
711 ~(QM_USB_DEPCTL_USB_ACT_EP | QM_USB_DEPCTL_EP_ENA |
712 QM_USB_DEPCTL_SNAK);
713 } else {
714 QM_USB[usb].daintmsk &= ~QM_USB_DAINT_IN_EP_INT(ep);
715 QM_USB[usb].diepmsk &= ~QM_USB_DIEPINT_XFER_COMPL;
716 QM_USB[usb].gintmsk &= ~QM_USB_GINTSTS_RX_FLVL;
717 QM_USB[usb].in_ep_reg[ep].diepctl &=
718 ~(QM_USB_DEPCTL_USB_ACT_EP | QM_USB_DEPCTL_EP_ENA |
719 QM_USB_DEPCTL_SNAK);
720 }
721
722 usb_ctrl[usb].ep_ctrl[ep].enabled = false;
723
724 return 0;
725 }
726
727 int qm_usb_ep_flush(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
728 {
729 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
730 QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
731 if (!usb_dc_ep_is_valid(ep)) {
732 return -EINVAL;
733 }
734 /*
735 *
736 * RX FIFO is global and cannot be flushed per EP, but it can
737 * be through bit 4 from GRSTCTL. For now we don't flush it
738 * here since both FIFOs are always flushed during the Core
739 * Soft Reset done at usb_dc_reset(), which is called on both
740 * qm_usb_attach() and qm_usb_reset().
741 */
742 if (!IS_IN_EP(ep)) {
743 return -EINVAL;
744 }
745
746 /* Each IN endpoint has dedicated Tx FIFO. */
747 QM_USB[usb].grstctl |= ep << QM_USB_GRSTCTL_TX_FNUM_OFFSET;
748 QM_USB[usb].grstctl |= QM_USB_GRSTCTL_TX_FFLSH;
749
750 uint32_t cnt = 0;
751 do {
752 if (++cnt > QM_USB_CORE_RST_TIMEOUT_US) {
753 return -EIO;
754 }
755 clk_sys_udelay(1);
756 } while (QM_USB[usb].grstctl & QM_USB_GRSTCTL_TX_FFLSH);
757
758 return 0;
759 }
760
761 int qm_usb_ep_write(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
762 const uint8_t *const data, const uint32_t data_len,
763 uint32_t *const ret_bytes)
764 {
765 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
766 QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
767 if (!usb_dc_ep_is_valid(ep)) {
768 return -EINVAL;
769 }
770 if (!IS_IN_EP(ep)) {
771 return -EINVAL;
772 }
773
774 /* Check if IN EP is enabled */
775 if (!usb_ctrl[usb].ep_ctrl[ep].enabled) {
776 return -EINVAL;
777 }
778
779 const int ret = usb_dc_tx(usb, ep, data, data_len);
780 if (ret < 0) {
781 return ret;
782 }
783
784 if (ret_bytes) {
785 *ret_bytes = ret;
786 }
787
788 return 0;
789 }
790
791 int qm_usb_ep_read(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
792 uint8_t *const data, const uint32_t max_data_len,
793 uint32_t *const read_bytes)
794 {
795 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
796 QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
797 QM_CHECK(data, -EINVAL);
798 if (!usb_dc_ep_is_valid(ep)) {
799 return -EINVAL;
800 }
801 if (IS_IN_EP(ep)) {
802 return -EINVAL;
803 }
804
805 uint32_t i, j, data_len, bytes_to_copy;
806
807 /* Check if OUT EP enabled */
808 if (!usb_ctrl[usb].ep_ctrl[ep].enabled) {
809 return -EINVAL;
810 }
811
812 data_len = usb_ctrl[usb].ep_ctrl[ep].data_len;
813
814 if (data_len > max_data_len) {
815 bytes_to_copy = max_data_len;
816 } else {
817 bytes_to_copy = data_len;
818 }
819
820 const uint8_t ep_idx = ep - QM_USB_IN_EP_NUM;
821 /* Data in the FIFOs is always stored per 32-bit words. */
822 for (i = 0; i < (bytes_to_copy & ~0x3); i += 4) {
823 *(uint32_t *)(data + i) = QM_USB_EP_FIFO(ep_idx);
824 }
825 if (bytes_to_copy & 0x3) {
826 /* Not multiple of 4. */
827 uint32_t last_dw = QM_USB_EP_FIFO(ep_idx);
828
829 for (j = 0; j < (bytes_to_copy & 0x3); j++) {
830 *(data + i + j) = (last_dw >> (8 * j)) & 0xFF;
831 }
832 }
833
834 usb_ctrl[usb].ep_ctrl[ep].data_len -= bytes_to_copy;
835
836 if (read_bytes) {
837 *read_bytes = bytes_to_copy;
838 }
839
840 /* Prepare ep for rx if all the data frames were read. */
841 if (!usb_ctrl[usb].ep_ctrl[ep].data_len) {
842 usb_dc_prep_rx(usb, ep, 0);
843 }
844
845 return 0;
846 }
847
848 int qm_usb_set_status_callback(const qm_usb_t usb,
849 const qm_usb_status_callback_t cb)
850 {
851 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
852
853 usb_ctrl[usb].status_callback = cb;
854 return 0;
855 }
856
857 int qm_usb_ep_get_bytes_read(const qm_usb_t usb, const qm_usb_ep_idx_t ep,
858 uint32_t *const read_bytes)
859 {
860 QM_CHECK(usb < QM_USB_NUM, -EINVAL);
861 QM_CHECK(usb_ctrl[usb].attached, -EINVAL);
862 QM_CHECK(read_bytes, -EINVAL);
863 if (!usb_dc_ep_is_valid(ep)) {
864 return -EINVAL;
865 }
866 if (IS_IN_EP(ep)) {
867 return -EINVAL;
868 }
869
870 /* Check if OUT EP enabled. */
871 if (!usb_ctrl[usb].ep_ctrl[ep].enabled) {
872 return -EINVAL;
873 }
874
875 *read_bytes = usb_ctrl[usb].ep_ctrl[ep].data_len;
876
877 return 0;
878 }
qm_usb_ep_enable
int qm_usb_ep_enable(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
Enable the selected endpoint.
Definition: qm_usb.c:664
clk_sys_usb_disable
int clk_sys_usb_disable(void)
Disable the USB Clock mode.
Definition: clk.c:386
QM_USB_RESUME
USB connection resumed by the HOST.
Definition: qm_usb.h:27
QM_USB_EP_INTERRUPT
Interrupt type endpoint.
Definition: qm_usb.h:45
QM_USB_EP_BULK
Bulk type endpoint.
Definition: qm_usb.h:44
qm_usb_ep_flush
int qm_usb_ep_flush(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
Flush the selected IN endpoint TX FIFO.
Definition: qm_usb.c:727
qm_usb_ep_config_t::max_packet_size
uint16_t max_packet_size
Endpoint max packet size.
Definition: qm_usb.h:53
qm_usb_ep_config_t::callback_data
void * callback_data
Callback user data.
Definition: qm_usb.h:71
QM_USB_EP_DATA_OUT
Out transaction on this EP.
Definition: qm_usb.h:35
QM_ISR_DECLARE
QM_ISR_DECLARE(qm_usb_0_isr)
ISR for USB 0 interrupt.
Definition: qm_usb.c:410
qm_usb_ep_is_stalled
int qm_usb_ep_is_stalled(const qm_usb_t usb, const qm_usb_ep_idx_t ep, bool *stalled)
Check stall condition for the selected endpoint.
Definition: qm_usb.c:640
qm_usb_ep_get_bytes_read
int qm_usb_ep_get_bytes_read(const qm_usb_t usb, const qm_usb_ep_idx_t ep, uint32_t *const read_bytes)
Check how many bytes are available on OUT endpoint.
Definition: qm_usb.c:857
qm_usb_status_callback_t
void(* qm_usb_status_callback_t)(void *data, int error, qm_usb_status_t status)
Callback function signature for the device status.
Definition: qm_usb.h:82
qm_usb_ep_halt
int qm_usb_ep_halt(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
Halt the selected endpoint.
Definition: qm_usb.c:609
QM_USB_EP_CONTROL
Control endpoint.
Definition: qm_usb.h:43
qm_usb_ep_set_config
int qm_usb_ep_set_config(const qm_usb_t usb, const qm_usb_ep_config_t *const ep_cfg)
Configure endpoint.
Definition: qm_usb.c:495
qm_usb_ep_config_t
USB Endpoint Configuration.
Definition: qm_usb.h:51
QM_USB_RESET
USB reset.
Definition: qm_usb.h:22
qm_usb_reset
int qm_usb_reset(const qm_usb_t usb)
Reset the USB device controller back to it's initial state.
Definition: qm_usb.c:476
clk_sys_udelay
void clk_sys_udelay(uint32_t microseconds)
Idle loop the processor for at least the value given in microseconds.
Definition: clk.c:352
QM_USB_EP_SETUP
SETUP received.
Definition: qm_usb.h:34
qm_usb_ep_config_t::callback
void(* callback)(void *data, int error, qm_usb_ep_idx_t ep, qm_usb_ep_status_t status)
Callback for the USB Endpoint status.
Definition: qm_usb.h:69
QM_USB_SUSPEND
USB connection suspended by the HOST.
Definition: qm_usb.h:26
qm_usb_ep_read
int qm_usb_ep_read(const qm_usb_t usb, const qm_usb_ep_idx_t ep, uint8_t *const data, const uint32_t max_data_len, uint32_t *const read_bytes)
Read data from OUT endpoint.
Definition: qm_usb.c:791
QM_USB_CONNECTED
USB connection ready and enumeration done.
Definition: qm_usb.h:23
qm_usb_set_status_callback
int qm_usb_set_status_callback(const qm_usb_t usb, const qm_usb_status_callback_t cb)
Set USB device controller status callback.
Definition: qm_usb.c:848
qm_usb_attach
int qm_usb_attach(const qm_usb_t usb)
Attach the USB device.
Definition: qm_usb.c:416
qm_usb_ep_status_t
qm_usb_ep_status_t
USB Endpoint Callback Status Codes.
Definition: qm_usb.h:33
qm_usb_ep_set_stall_state
int qm_usb_ep_set_stall_state(const qm_usb_t usb, const qm_usb_ep_idx_t ep, const bool is_stalled)
Set / Clear stall condition for the selected endpoint.
Definition: qm_usb.c:578
qm_usb_t
qm_usb_t
Number of USB controllers.
Definition: qm_soc_regs.h:1944
qm_usb_ep_disable
int qm_usb_ep_disable(const qm_usb_t usb, const qm_usb_ep_idx_t ep)
Disable the selected endpoint.
Definition: qm_usb.c:697
qm_usb_ep_config_t::type
qm_usb_ep_type_t type
Endpoint type.
Definition: qm_usb.h:52
qm_usb_set_address
int qm_usb_set_address(const qm_usb_t usb, const uint8_t addr)
Set USB device address.
Definition: qm_usb.c:482
clk_sys_usb_enable
int clk_sys_usb_enable(void)
Enable the USB Clock mode.
Definition: clk.c:356
qm_usb_ep_write
int qm_usb_ep_write(const qm_usb_t usb, const qm_usb_ep_idx_t ep, const uint8_t *const data, const uint32_t data_len, uint32_t *const ret_bytes)
Write data to the specified IN endpoint.
Definition: qm_usb.c:761
qm_usb_detach
int qm_usb_detach(const qm_usb_t usb)
Detach the USB device.
Definition: qm_usb.c:458
QM_USB_EP_DATA_IN
In transaction on this EP.
Definition: qm_usb.h:36
qm_usb_status_t
qm_usb_status_t
USB Driver Status Codes.
Definition: qm_usb.h:21