Intel® Quark™ Microcontroller Software Interface  1.4.0
Intel® Quark™ Microcontroller BSP
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,
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)
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 
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 
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 
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 
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 }
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
int clk_sys_usb_disable(void)
Disable the USB Clock mode.
Definition: clk.c:386
USB connection resumed by the HOST.
Definition: qm_usb.h:27
Interrupt type endpoint.
Definition: qm_usb.h:45
Bulk type endpoint.
Definition: qm_usb.h:44
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
uint16_t max_packet_size
Endpoint max packet size.
Definition: qm_usb.h:53
void * callback_data
Callback user data.
Definition: qm_usb.h:71
Out transaction on this EP.
Definition: qm_usb.h:35
QM_ISR_DECLARE(qm_usb_0_isr)
ISR for USB 0 interrupt.
Definition: qm_usb.c:410
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
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
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
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
Control endpoint.
Definition: qm_usb.h:43
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
USB Endpoint Configuration.
Definition: qm_usb.h:51
USB reset.
Definition: qm_usb.h:22
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
void clk_sys_udelay(uint32_t microseconds)
Idle loop the processor for at least the value given in microseconds.
Definition: clk.c:352
SETUP received.
Definition: qm_usb.h:34
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
USB connection suspended by the HOST.
Definition: qm_usb.h:26
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
USB connection ready and enumeration done.
Definition: qm_usb.h:23
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
int qm_usb_attach(const qm_usb_t usb)
Attach the USB device.
Definition: qm_usb.c:416
qm_usb_ep_status_t
USB Endpoint Callback Status Codes.
Definition: qm_usb.h:33
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
Number of USB controllers.
Definition: qm_soc_regs.h:1944
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_type_t type
Endpoint type.
Definition: qm_usb.h:52
int qm_usb_set_address(const qm_usb_t usb, const uint8_t addr)
Set USB device address.
Definition: qm_usb.c:482
int clk_sys_usb_enable(void)
Enable the USB Clock mode.
Definition: clk.c:356
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
int qm_usb_detach(const qm_usb_t usb)
Detach the USB device.
Definition: qm_usb.c:458
In transaction on this EP.
Definition: qm_usb.h:36
qm_usb_status_t
USB Driver Status Codes.
Definition: qm_usb.h:21