1 /*
2  * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #pragma once
8 
9 #include "soc/soc_caps.h"
10 /*
11 This header is shared across all targets. Resolve to an empty header for targets
12 that don't support USB OTG.
13 */
14 #if SOC_USB_OTG_SUPPORTED
15 #include <stdint.h>
16 #include <stdbool.h>
17 #include "soc/usb_dwc_struct.h"
18 #include "soc/usb_dwc_cfg.h"
19 #include "hal/usb_dwc_types.h"
20 #include "hal/misc.h"
21 #endif // SOC_USB_OTG_SUPPORTED
22 
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26 
27 #if SOC_USB_OTG_SUPPORTED
28 
29 /* -----------------------------------------------------------------------------
30 --------------------------------- DWC Constants --------------------------------
31 ----------------------------------------------------------------------------- */
32 
33 #define USB_DWC_QTD_LIST_MEM_ALIGN              512
34 #define USB_DWC_FRAME_LIST_MEM_ALIGN            512     // The frame list needs to be 512 bytes aligned (contrary to the databook)
35 
36 /* -----------------------------------------------------------------------------
37 ------------------------------- Global Registers -------------------------------
38 ----------------------------------------------------------------------------- */
39 
40 /*
41  * Interrupt bit masks of the GINTSTS and GINTMSK registers
42  */
43 #define USB_DWC_LL_INTR_CORE_WKUPINT        (1 << 31)
44 #define USB_DWC_LL_INTR_CORE_SESSREQINT     (1 << 30)
45 #define USB_DWC_LL_INTR_CORE_DISCONNINT     (1 << 29)
46 #define USB_DWC_LL_INTR_CORE_CONIDSTSCHNG   (1 << 28)
47 #define USB_DWC_LL_INTR_CORE_PTXFEMP        (1 << 26)
48 #define USB_DWC_LL_INTR_CORE_HCHINT         (1 << 25)
49 #define USB_DWC_LL_INTR_CORE_PRTINT         (1 << 24)
50 #define USB_DWC_LL_INTR_CORE_RESETDET       (1 << 23)
51 #define USB_DWC_LL_INTR_CORE_FETSUSP        (1 << 22)
52 #define USB_DWC_LL_INTR_CORE_INCOMPIP       (1 << 21)
53 #define USB_DWC_LL_INTR_CORE_INCOMPISOIN    (1 << 20)
54 #define USB_DWC_LL_INTR_CORE_OEPINT         (1 << 19)
55 #define USB_DWC_LL_INTR_CORE_IEPINT         (1 << 18)
56 #define USB_DWC_LL_INTR_CORE_EPMIS          (1 << 17)
57 #define USB_DWC_LL_INTR_CORE_EOPF           (1 << 15)
58 #define USB_DWC_LL_INTR_CORE_ISOOUTDROP     (1 << 14)
59 #define USB_DWC_LL_INTR_CORE_ENUMDONE       (1 << 13)
60 #define USB_DWC_LL_INTR_CORE_USBRST         (1 << 12)
61 #define USB_DWC_LL_INTR_CORE_USBSUSP        (1 << 11)
62 #define USB_DWC_LL_INTR_CORE_ERLYSUSP       (1 << 10)
63 #define USB_DWC_LL_INTR_CORE_GOUTNAKEFF     (1 << 7)
64 #define USB_DWC_LL_INTR_CORE_GINNAKEFF      (1 << 6)
65 #define USB_DWC_LL_INTR_CORE_NPTXFEMP       (1 << 5)
66 #define USB_DWC_LL_INTR_CORE_RXFLVL         (1 << 4)
67 #define USB_DWC_LL_INTR_CORE_SOF            (1 << 3)
68 #define USB_DWC_LL_INTR_CORE_OTGINT         (1 << 2)
69 #define USB_DWC_LL_INTR_CORE_MODEMIS        (1 << 1)
70 #define USB_DWC_LL_INTR_CORE_CURMOD         (1 << 0)
71 
72 /*
73  * Bit mask of interrupt generating bits of the the HPRT register. These bits
74  * are ORd into the USB_DWC_LL_INTR_CORE_PRTINT interrupt.
75  *
76  * Note: Some fields of the HPRT are W1C (write 1 clear), this we cannot do a
77  * simple read and write-back to clear the HPRT interrupt bits. Instead we need
78  * a W1C mask the non-interrupt related bits
79  */
80 #define USB_DWC_LL_HPRT_W1C_MSK             (0x2E)
81 #define USB_DWC_LL_HPRT_ENA_MSK             (0x04)
82 #define USB_DWC_LL_INTR_HPRT_PRTOVRCURRCHNG (1 << 5)
83 #define USB_DWC_LL_INTR_HPRT_PRTENCHNG      (1 << 3)
84 #define USB_DWC_LL_INTR_HPRT_PRTCONNDET     (1 << 1)
85 
86 /*
87  * Bit mask of channel interrupts (HCINTi and HCINTMSKi registers)
88  *
89  * Note: Under Scatter/Gather DMA mode, only the following interrupts can be unmasked
90  * - DESC_LS_ROLL
91  * - XCS_XACT_ERR (always unmasked)
92  * - BNAINTR
93  * - CHHLTD
94  * - XFERCOMPL
95  * The remaining interrupt bits will still be set (when the corresponding event occurs)
96  * but will not generate an interrupt. Therefore we must proxy through the
97  * USB_DWC_LL_INTR_CHAN_CHHLTD interrupt to check the other interrupt bits.
98  */
99 #define USB_DWC_LL_INTR_CHAN_DESC_LS_ROLL   (1 << 13)
100 #define USB_DWC_LL_INTR_CHAN_XCS_XACT_ERR   (1 << 12)
101 #define USB_DWC_LL_INTR_CHAN_BNAINTR        (1 << 11)
102 #define USB_DWC_LL_INTR_CHAN_DATATGLERR     (1 << 10)
103 #define USB_DWC_LL_INTR_CHAN_FRMOVRUN       (1 << 9)
104 #define USB_DWC_LL_INTR_CHAN_BBLEER         (1 << 8)
105 #define USB_DWC_LL_INTR_CHAN_XACTERR        (1 << 7)
106 #define USB_DWC_LL_INTR_CHAN_NYET           (1 << 6)
107 #define USB_DWC_LL_INTR_CHAN_ACK            (1 << 5)
108 #define USB_DWC_LL_INTR_CHAN_NAK            (1 << 4)
109 #define USB_DWC_LL_INTR_CHAN_STALL          (1 << 3)
110 #define USB_DWC_LL_INTR_CHAN_AHBERR         (1 << 2)
111 #define USB_DWC_LL_INTR_CHAN_CHHLTD         (1 << 1)
112 #define USB_DWC_LL_INTR_CHAN_XFERCOMPL      (1 << 0)
113 
114 /*
115  * QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode.
116  * Each QTD describes one transfer. Scatter gather mode will automatically split
117  * a transfer into multiple MPS packets. Each QTD is 64bits in size
118  *
119  * Note: The status information part of the QTD is interpreted differently depending
120  * on IN or OUT, and ISO or non-ISO
121  */
122 typedef struct {
123     union {
124         struct {
125             uint32_t xfer_size: 17;
126             uint32_t aqtd_offset: 6;
127             uint32_t aqtd_valid: 1;
128             uint32_t reserved_24: 1;
129             uint32_t intr_cplt: 1;
130             uint32_t eol: 1;
131             uint32_t reserved_27: 1;
132             uint32_t rx_status: 2;
133             uint32_t reserved_30: 1;
134             uint32_t active: 1;
135         } in_non_iso;
136         struct {
137             uint32_t xfer_size: 12;
138             uint32_t reserved_12_24: 13;
139             uint32_t intr_cplt: 1;
140             uint32_t reserved_26_27: 2;
141             uint32_t rx_status: 2;
142             uint32_t reserved_30: 1;
143             uint32_t active: 1;
144         } in_iso;
145         struct {
146             uint32_t xfer_size: 17;
147             uint32_t reserved_17_23: 7;
148             uint32_t is_setup: 1;
149             uint32_t intr_cplt: 1;
150             uint32_t eol: 1;
151             uint32_t reserved_27: 1;
152             uint32_t tx_status: 2;
153             uint32_t reserved_30: 1;
154             uint32_t active: 1;
155         } out_non_iso;
156         struct {
157             uint32_t xfer_size: 12;
158             uint32_t reserved_12_24: 13;
159             uint32_t intr_cplt: 1;
160             uint32_t eol: 1;
161             uint32_t reserved_27: 1;
162             uint32_t tx_status: 2;
163             uint32_t reserved_30: 1;
164             uint32_t active: 1;
165         } out_iso;
166         uint32_t buffer_status_val;
167     };
168     uint8_t *buffer;
169 } usb_dwc_ll_dma_qtd_t;
170 
171 
172 /* -----------------------------------------------------------------------------
173 ------------------------------- Global Registers -------------------------------
174 ----------------------------------------------------------------------------- */
175 
176 // --------------------------- GAHBCFG Register --------------------------------
177 
usb_dwc_ll_gahbcfg_en_dma_mode(usb_dwc_dev_t * hw)178 static inline void usb_dwc_ll_gahbcfg_en_dma_mode(usb_dwc_dev_t *hw)
179 {
180     hw->gahbcfg_reg.dmaen = 1;
181 }
182 
usb_dwc_ll_gahbcfg_en_slave_mode(usb_dwc_dev_t * hw)183 static inline void usb_dwc_ll_gahbcfg_en_slave_mode(usb_dwc_dev_t *hw)
184 {
185     hw->gahbcfg_reg.dmaen = 0;
186 }
187 
usb_dwc_ll_gahbcfg_set_hbstlen(usb_dwc_dev_t * hw,uint32_t burst_len)188 static inline void usb_dwc_ll_gahbcfg_set_hbstlen(usb_dwc_dev_t *hw, uint32_t burst_len)
189 {
190     hw->gahbcfg_reg.hbstlen = burst_len;
191 }
192 
usb_dwc_ll_gahbcfg_en_global_intr(usb_dwc_dev_t * hw)193 static inline void usb_dwc_ll_gahbcfg_en_global_intr(usb_dwc_dev_t *hw)
194 {
195     hw->gahbcfg_reg.glbllntrmsk = 1;
196 }
197 
usb_dwc_ll_gahbcfg_dis_global_intr(usb_dwc_dev_t * hw)198 static inline void usb_dwc_ll_gahbcfg_dis_global_intr(usb_dwc_dev_t *hw)
199 {
200     hw->gahbcfg_reg.glbllntrmsk = 0;
201 }
202 
203 // --------------------------- GUSBCFG Register --------------------------------
204 
usb_dwc_ll_gusbcfg_force_host_mode(usb_dwc_dev_t * hw)205 static inline void usb_dwc_ll_gusbcfg_force_host_mode(usb_dwc_dev_t *hw)
206 {
207     hw->gusbcfg_reg.forcehstmode = 1;
208 }
209 
usb_dwc_ll_gusbcfg_dis_hnp_cap(usb_dwc_dev_t * hw)210 static inline void usb_dwc_ll_gusbcfg_dis_hnp_cap(usb_dwc_dev_t *hw)
211 {
212     hw->gusbcfg_reg.hnpcap = 0;
213 }
214 
usb_dwc_ll_gusbcfg_dis_srp_cap(usb_dwc_dev_t * hw)215 static inline void usb_dwc_ll_gusbcfg_dis_srp_cap(usb_dwc_dev_t *hw)
216 {
217     hw->gusbcfg_reg.srpcap = 0;
218 }
219 
220 // --------------------------- GRSTCTL Register --------------------------------
221 
usb_dwc_ll_grstctl_is_ahb_idle(usb_dwc_dev_t * hw)222 static inline bool usb_dwc_ll_grstctl_is_ahb_idle(usb_dwc_dev_t *hw)
223 {
224     return hw->grstctl_reg.ahbidle;
225 }
226 
usb_dwc_ll_grstctl_is_dma_req_in_progress(usb_dwc_dev_t * hw)227 static inline bool usb_dwc_ll_grstctl_is_dma_req_in_progress(usb_dwc_dev_t *hw)
228 {
229     return hw->grstctl_reg.dmareq;
230 }
231 
usb_dwc_ll_grstctl_flush_nptx_fifo(usb_dwc_dev_t * hw)232 static inline void usb_dwc_ll_grstctl_flush_nptx_fifo(usb_dwc_dev_t *hw)
233 {
234     hw->grstctl_reg.txfnum = 0;     //Set the TX FIFO number to 0 to select the non-periodic TX FIFO
235     hw->grstctl_reg.txfflsh = 1;    //Flush the selected TX FIFO
236     //Wait for the flushing to complete
237     while (hw->grstctl_reg.txfflsh) {
238         ;
239     }
240 }
241 
usb_dwc_ll_grstctl_flush_ptx_fifo(usb_dwc_dev_t * hw)242 static inline void usb_dwc_ll_grstctl_flush_ptx_fifo(usb_dwc_dev_t *hw)
243 {
244     hw->grstctl_reg.txfnum = 1;     //Set the TX FIFO number to 1 to select the periodic TX FIFO
245     hw->grstctl_reg.txfflsh = 1;    //FLush the select TX FIFO
246     //Wait for the flushing to complete
247     while (hw->grstctl_reg.txfflsh) {
248         ;
249     }
250 }
251 
usb_dwc_ll_grstctl_flush_rx_fifo(usb_dwc_dev_t * hw)252 static inline void usb_dwc_ll_grstctl_flush_rx_fifo(usb_dwc_dev_t *hw)
253 {
254     hw->grstctl_reg.rxfflsh = 1;
255     //Wait for the flushing to complete
256     while (hw->grstctl_reg.rxfflsh) {
257         ;
258     }
259 }
260 
usb_dwc_ll_grstctl_reset_frame_counter(usb_dwc_dev_t * hw)261 static inline void usb_dwc_ll_grstctl_reset_frame_counter(usb_dwc_dev_t *hw)
262 {
263     hw->grstctl_reg.frmcntrrst = 1;
264 }
265 
usb_dwc_ll_grstctl_core_soft_reset(usb_dwc_dev_t * hw)266 static inline void usb_dwc_ll_grstctl_core_soft_reset(usb_dwc_dev_t *hw)
267 {
268     hw->grstctl_reg.csftrst = 1;
269 }
270 
usb_dwc_ll_grstctl_is_core_soft_reset_in_progress(usb_dwc_dev_t * hw)271 static inline bool usb_dwc_ll_grstctl_is_core_soft_reset_in_progress(usb_dwc_dev_t *hw)
272 {
273     return hw->grstctl_reg.csftrst;
274 }
275 
276 // --------------------------- GINTSTS Register --------------------------------
277 
278 /**
279  * @brief Reads and clears the global interrupt register
280  *
281  * @param hw Start address of the DWC_OTG registers
282  * @return uint32_t Mask of interrupts
283  */
usb_dwc_ll_gintsts_read_and_clear_intrs(usb_dwc_dev_t * hw)284 static inline uint32_t usb_dwc_ll_gintsts_read_and_clear_intrs(usb_dwc_dev_t *hw)
285 {
286     usb_dwc_gintsts_reg_t gintsts;
287     gintsts.val = hw->gintsts_reg.val;
288     hw->gintsts_reg.val = gintsts.val;  //Write back to clear
289     return gintsts.val;
290 }
291 
292 /**
293  * @brief Clear specific interrupts
294  *
295  * @param hw Start address of the DWC_OTG registers
296  * @param intr_msk Mask of interrupts to clear
297  */
usb_dwc_ll_gintsts_clear_intrs(usb_dwc_dev_t * hw,uint32_t intr_msk)298 static inline void usb_dwc_ll_gintsts_clear_intrs(usb_dwc_dev_t *hw, uint32_t intr_msk)
299 {
300     //All GINTSTS fields are either W1C or read only. So safe to write directly
301     hw->gintsts_reg.val = intr_msk;
302 }
303 
304 // --------------------------- GINTMSK Register --------------------------------
305 
usb_dwc_ll_gintmsk_en_intrs(usb_dwc_dev_t * hw,uint32_t intr_mask)306 static inline void usb_dwc_ll_gintmsk_en_intrs(usb_dwc_dev_t *hw, uint32_t intr_mask)
307 {
308     hw->gintmsk_reg.val |= intr_mask;
309 }
310 
usb_dwc_ll_gintmsk_dis_intrs(usb_dwc_dev_t * hw,uint32_t intr_mask)311 static inline void usb_dwc_ll_gintmsk_dis_intrs(usb_dwc_dev_t *hw, uint32_t intr_mask)
312 {
313     hw->gintmsk_reg.val &= ~intr_mask;
314 }
315 
316 // --------------------------- GRXFSIZ Register --------------------------------
317 
usb_dwc_ll_grxfsiz_set_fifo_size(usb_dwc_dev_t * hw,uint32_t num_lines)318 static inline void usb_dwc_ll_grxfsiz_set_fifo_size(usb_dwc_dev_t *hw, uint32_t num_lines)
319 {
320     //Set size in words
321     HAL_FORCE_MODIFY_U32_REG_FIELD(hw->grxfsiz_reg, rxfdep, num_lines);
322 }
323 
324 // -------------------------- GNPTXFSIZ Register -------------------------------
325 
usb_dwc_ll_gnptxfsiz_set_fifo_size(usb_dwc_dev_t * hw,uint32_t addr,uint32_t num_lines)326 static inline void usb_dwc_ll_gnptxfsiz_set_fifo_size(usb_dwc_dev_t *hw, uint32_t addr, uint32_t num_lines)
327 {
328     usb_dwc_gnptxfsiz_reg_t gnptxfsiz;
329     gnptxfsiz.val = hw->gnptxfsiz_reg.val;
330     HAL_FORCE_MODIFY_U32_REG_FIELD(gnptxfsiz, nptxfstaddr, addr);
331     HAL_FORCE_MODIFY_U32_REG_FIELD(gnptxfsiz, nptxfdep, num_lines);
332     hw->gnptxfsiz_reg.val = gnptxfsiz.val;
333 }
334 
335 // --------------------------- GSNPSID Register --------------------------------
336 
usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t * hw)337 static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw)
338 {
339     return hw->gsnpsid_reg.val;
340 }
341 
342 // --------------------------- GHWCFGx Register --------------------------------
343 
344 /**
345  * @brief Get the hardware configuration regiters of the DWC_OTG controller
346  *
347  * The hardware configuraiton regitsers are read only and indicate the various
348  * features of the DWC_OTG core.
349  *
350  * @param hw Start address of the DWC_OTG registers
351  * @param[out] ghwcfg1 Hardware configuration registesr 1
352  * @param[out] ghwcfg2 Hardware configuration registesr 2
353  * @param[out] ghwcfg3 Hardware configuration registesr 3
354  * @param[out] ghwcfg4 Hardware configuration registesr 4
355  */
usb_dwc_ll_ghwcfg_get_hw_config(usb_dwc_dev_t * hw,uint32_t * ghwcfg1,uint32_t * ghwcfg2,uint32_t * ghwcfg3,uint32_t * ghwcfg4)356 static inline void usb_dwc_ll_ghwcfg_get_hw_config(usb_dwc_dev_t *hw, uint32_t *ghwcfg1, uint32_t *ghwcfg2, uint32_t *ghwcfg3, uint32_t *ghwcfg4)
357 {
358     *ghwcfg1 = hw->ghwcfg1_reg.val;
359     *ghwcfg2 = hw->ghwcfg2_reg.val;
360     *ghwcfg3 = hw->ghwcfg3_reg.val;
361     *ghwcfg4 = hw->ghwcfg4_reg.val;
362 }
363 
364 // --------------------------- HPTXFSIZ Register -------------------------------
365 
usb_dwc_ll_hptxfsiz_set_ptx_fifo_size(usb_dwc_dev_t * hw,uint32_t addr,uint32_t num_lines)366 static inline void usb_dwc_ll_hptxfsiz_set_ptx_fifo_size(usb_dwc_dev_t *hw, uint32_t addr, uint32_t num_lines)
367 {
368     usb_dwc_hptxfsiz_reg_t hptxfsiz;
369     hptxfsiz.val = hw->hptxfsiz_reg.val;
370     HAL_FORCE_MODIFY_U32_REG_FIELD(hptxfsiz, ptxfstaddr, addr);
371     HAL_FORCE_MODIFY_U32_REG_FIELD(hptxfsiz, ptxfsize, num_lines);
372     hw->hptxfsiz_reg.val = hptxfsiz.val;
373 }
374 
375 /* -----------------------------------------------------------------------------
376 -------------------------------- Host Registers --------------------------------
377 ----------------------------------------------------------------------------- */
378 
379 // ----------------------------- HCFG Register ---------------------------------
380 
usb_dwc_ll_hcfg_en_perio_sched(usb_dwc_dev_t * hw)381 static inline void usb_dwc_ll_hcfg_en_perio_sched(usb_dwc_dev_t *hw)
382 {
383     hw->hcfg_reg.perschedena = 1;
384 }
385 
usb_dwc_ll_hcfg_dis_perio_sched(usb_dwc_dev_t * hw)386 static inline void usb_dwc_ll_hcfg_dis_perio_sched(usb_dwc_dev_t *hw)
387 {
388     hw->hcfg_reg.perschedena = 0;
389 }
390 
391 /**
392  * Sets the length of the frame list
393  *
394  * @param num_entires Number of entires in the frame list
395  */
usb_dwc_ll_hcfg_set_num_frame_list_entries(usb_dwc_dev_t * hw,usb_hal_frame_list_len_t num_entries)396 static inline void usb_dwc_ll_hcfg_set_num_frame_list_entries(usb_dwc_dev_t *hw, usb_hal_frame_list_len_t num_entries)
397 {
398     uint32_t frlisten;
399     switch (num_entries) {
400         case USB_HAL_FRAME_LIST_LEN_8:
401             frlisten = 0;
402             break;
403         case USB_HAL_FRAME_LIST_LEN_16:
404             frlisten = 1;
405             break;
406         case USB_HAL_FRAME_LIST_LEN_32:
407             frlisten = 2;
408             break;
409         default: //USB_HAL_FRAME_LIST_LEN_64
410             frlisten = 3;
411             break;
412     }
413     hw->hcfg_reg.frlisten = frlisten;
414 }
415 
usb_dwc_ll_hcfg_en_scatt_gatt_dma(usb_dwc_dev_t * hw)416 static inline void usb_dwc_ll_hcfg_en_scatt_gatt_dma(usb_dwc_dev_t *hw)
417 {
418     hw->hcfg_reg.descdma = 1;
419 }
420 
usb_dwc_ll_hcfg_set_fsls_supp_only(usb_dwc_dev_t * hw)421 static inline void usb_dwc_ll_hcfg_set_fsls_supp_only(usb_dwc_dev_t *hw)
422 {
423     hw->hcfg_reg.fslssupp = 1;
424 }
425 
usb_dwc_ll_hcfg_set_fsls_pclk_sel(usb_dwc_dev_t * hw)426 static inline void usb_dwc_ll_hcfg_set_fsls_pclk_sel(usb_dwc_dev_t *hw)
427 {
428     hw->hcfg_reg.fslspclksel = 1;
429 }
430 
431 /**
432  * @brief Sets some default values to HCFG to operate in Host mode with scatter/gather DMA
433  *
434  * @param hw Start address of the DWC_OTG registers
435  * @param speed Speed to initialize the host port at
436  */
usb_dwc_ll_hcfg_set_defaults(usb_dwc_dev_t * hw,usb_dwc_speed_t speed)437 static inline void usb_dwc_ll_hcfg_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed)
438 {
439     hw->hcfg_reg.descdma = 1;   //Enable scatt/gatt
440     hw->hcfg_reg.fslssupp = 1;  //FS/LS support only
441     /*
442     Indicate to the OTG core what speed the PHY clock is at
443     Note: It seems like our PHY has an implicit 8 divider applied when in LS mode,
444           so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
445     */
446     hw->hcfg_reg.fslspclksel = (speed == USB_DWC_SPEED_FULL) ? 1 : 2;  //PHY clock on esp32-sx for FS/LS-only
447     hw->hcfg_reg.perschedena = 0;   //Disable perio sched
448 }
449 
450 // ----------------------------- HFIR Register ---------------------------------
451 
usb_dwc_ll_hfir_set_defaults(usb_dwc_dev_t * hw,usb_dwc_speed_t speed)452 static inline void usb_dwc_ll_hfir_set_defaults(usb_dwc_dev_t *hw, usb_dwc_speed_t speed)
453 {
454     usb_dwc_hfir_reg_t hfir;
455     hfir.val = hw->hfir_reg.val;
456     hfir.hfirrldctrl = 0;       //Disable dynamic loading
457     /*
458     Set frame interval to be equal to 1ms
459     Note: It seems like our PHY has an implicit 8 divider applied when in LS mode,
460           so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
461     */
462     hfir.frint = (speed == USB_DWC_SPEED_FULL) ? 48000 : 6000; //esp32-sx targets only support FS or LS
463     hw->hfir_reg.val = hfir.val;
464 }
465 
466 // ----------------------------- HFNUM Register --------------------------------
467 
usb_dwc_ll_hfnum_get_frame_time_rem(usb_dwc_dev_t * hw)468 static inline uint32_t usb_dwc_ll_hfnum_get_frame_time_rem(usb_dwc_dev_t *hw)
469 {
470     return HAL_FORCE_READ_U32_REG_FIELD(hw->hfnum_reg, frrem);
471 }
472 
usb_dwc_ll_hfnum_get_frame_num(usb_dwc_dev_t * hw)473 static inline uint32_t usb_dwc_ll_hfnum_get_frame_num(usb_dwc_dev_t *hw)
474 {
475     return hw->hfnum_reg.frnum;
476 }
477 
478 // ---------------------------- HPTXSTS Register -------------------------------
479 
usb_dwc_ll_hptxsts_get_ptxq_top(usb_dwc_dev_t * hw)480 static inline uint32_t usb_dwc_ll_hptxsts_get_ptxq_top(usb_dwc_dev_t *hw)
481 {
482     return HAL_FORCE_READ_U32_REG_FIELD(hw->hptxsts_reg, ptxqtop);
483 }
484 
usb_dwc_ll_hptxsts_get_ptxq_space_avail(usb_dwc_dev_t * hw)485 static inline uint32_t usb_dwc_ll_hptxsts_get_ptxq_space_avail(usb_dwc_dev_t *hw)
486 {
487     return hw->hptxsts_reg.ptxqspcavail;
488 }
489 
usb_dwc_ll_ptxsts_get_ptxf_space_avail(usb_dwc_dev_t * hw)490 static inline uint32_t usb_dwc_ll_ptxsts_get_ptxf_space_avail(usb_dwc_dev_t *hw)
491 {
492     return HAL_FORCE_READ_U32_REG_FIELD(hw->hptxsts_reg, ptxfspcavail);
493 }
494 
495 // ----------------------------- HAINT Register --------------------------------
496 
usb_dwc_ll_haint_get_chan_intrs(usb_dwc_dev_t * hw)497 static inline uint32_t usb_dwc_ll_haint_get_chan_intrs(usb_dwc_dev_t *hw)
498 {
499     return HAL_FORCE_READ_U32_REG_FIELD(hw->haint_reg, haint);
500 }
501 
502 // --------------------------- HAINTMSK Register -------------------------------
503 
usb_dwc_ll_haintmsk_en_chan_intr(usb_dwc_dev_t * hw,uint32_t mask)504 static inline void usb_dwc_ll_haintmsk_en_chan_intr(usb_dwc_dev_t *hw, uint32_t mask)
505 {
506 
507     hw->haintmsk_reg.val |= mask;
508 }
509 
usb_dwc_ll_haintmsk_dis_chan_intr(usb_dwc_dev_t * hw,uint32_t mask)510 static inline void usb_dwc_ll_haintmsk_dis_chan_intr(usb_dwc_dev_t *hw, uint32_t mask)
511 {
512     hw->haintmsk_reg.val &= ~mask;
513 }
514 
515 // --------------------------- HFLBAddr Register -------------------------------
516 
517 /**
518  * @brief Set the base address of the scheduling frame list
519  *
520  * @note For some reason, this address must be 512 bytes aligned or else a bunch of frames will not be scheduled when
521  *       the frame list rolls over. However, according to the databook, there is no mention of the HFLBAddr needing to
522  *       be aligned.
523  *
524  * @param hw Start address of the DWC_OTG registers
525  * @param addr Base address of the scheduling frame list
526  */
usb_dwc_ll_hflbaddr_set_base_addr(usb_dwc_dev_t * hw,uint32_t addr)527 static inline void usb_dwc_ll_hflbaddr_set_base_addr(usb_dwc_dev_t *hw, uint32_t addr)
528 {
529     hw->hflbaddr_reg.hflbaddr = addr;
530 }
531 
532 /**
533  * @brief Get the base address of the scheduling frame list
534  *
535  * @param hw Start address of the DWC_OTG registers
536  * @return uint32_t Base address of the scheduling frame list
537  */
usb_dwc_ll_hflbaddr_get_base_addr(usb_dwc_dev_t * hw)538 static inline uint32_t usb_dwc_ll_hflbaddr_get_base_addr(usb_dwc_dev_t *hw)
539 {
540     return hw->hflbaddr_reg.hflbaddr;
541 }
542 
543 // ----------------------------- HPRT Register ---------------------------------
544 
usb_dwc_ll_hprt_get_speed(usb_dwc_dev_t * hw)545 static inline usb_dwc_speed_t usb_dwc_ll_hprt_get_speed(usb_dwc_dev_t *hw)
546 {
547     return (usb_dwc_speed_t)hw->hprt_reg.prtspd;
548 }
549 
usb_dwc_ll_hprt_get_test_ctl(usb_dwc_dev_t * hw)550 static inline uint32_t usb_dwc_ll_hprt_get_test_ctl(usb_dwc_dev_t *hw)
551 {
552     return hw->hprt_reg.prttstctl;
553 }
554 
usb_dwc_ll_hprt_set_test_ctl(usb_dwc_dev_t * hw,uint32_t test_mode)555 static inline void usb_dwc_ll_hprt_set_test_ctl(usb_dwc_dev_t *hw, uint32_t test_mode)
556 {
557     usb_dwc_hprt_reg_t hprt;
558     hprt.val = hw->hprt_reg.val;
559     hprt.prttstctl = test_mode;
560     hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK);
561 }
562 
usb_dwc_ll_hprt_en_pwr(usb_dwc_dev_t * hw)563 static inline void usb_dwc_ll_hprt_en_pwr(usb_dwc_dev_t *hw)
564 {
565     usb_dwc_hprt_reg_t hprt;
566     hprt.val = hw->hprt_reg.val;
567     hprt.prtpwr = 1;
568     hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK);
569 }
570 
usb_dwc_ll_hprt_dis_pwr(usb_dwc_dev_t * hw)571 static inline void usb_dwc_ll_hprt_dis_pwr(usb_dwc_dev_t *hw)
572 {
573     usb_dwc_hprt_reg_t hprt;
574     hprt.val = hw->hprt_reg.val;
575     hprt.prtpwr = 0;
576     hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK);
577 }
578 
usb_dwc_ll_hprt_get_pwr_line_status(usb_dwc_dev_t * hw)579 static inline uint32_t usb_dwc_ll_hprt_get_pwr_line_status(usb_dwc_dev_t *hw)
580 {
581     return hw->hprt_reg.prtlnsts;
582 }
583 
usb_dwc_ll_hprt_set_port_reset(usb_dwc_dev_t * hw,bool reset)584 static inline void usb_dwc_ll_hprt_set_port_reset(usb_dwc_dev_t *hw, bool reset)
585 {
586     usb_dwc_hprt_reg_t hprt;
587     hprt.val = hw->hprt_reg.val;
588     hprt.prtrst = reset;
589     hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK);
590 }
591 
usb_dwc_ll_hprt_get_port_reset(usb_dwc_dev_t * hw)592 static inline bool usb_dwc_ll_hprt_get_port_reset(usb_dwc_dev_t *hw)
593 {
594     return hw->hprt_reg.prtrst;
595 }
596 
usb_dwc_ll_hprt_set_port_suspend(usb_dwc_dev_t * hw)597 static inline void usb_dwc_ll_hprt_set_port_suspend(usb_dwc_dev_t *hw)
598 {
599     usb_dwc_hprt_reg_t hprt;
600     hprt.val = hw->hprt_reg.val;
601     hprt.prtsusp = 1;
602     hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK);
603 }
604 
usb_dwc_ll_hprt_get_port_suspend(usb_dwc_dev_t * hw)605 static inline bool usb_dwc_ll_hprt_get_port_suspend(usb_dwc_dev_t *hw)
606 {
607     return hw->hprt_reg.prtsusp;
608 }
609 
usb_dwc_ll_hprt_set_port_resume(usb_dwc_dev_t * hw)610 static inline void usb_dwc_ll_hprt_set_port_resume(usb_dwc_dev_t *hw)
611 {
612     usb_dwc_hprt_reg_t hprt;
613     hprt.val = hw->hprt_reg.val;
614     hprt.prtres = 1;
615     hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK);
616 }
617 
usb_dwc_ll_hprt_clr_port_resume(usb_dwc_dev_t * hw)618 static inline void usb_dwc_ll_hprt_clr_port_resume(usb_dwc_dev_t *hw)
619 {
620     usb_dwc_hprt_reg_t hprt;
621     hprt.val = hw->hprt_reg.val;
622     hprt.prtres = 0;
623     hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK);
624 }
625 
usb_dwc_ll_hprt_get_port_resume(usb_dwc_dev_t * hw)626 static inline bool usb_dwc_ll_hprt_get_port_resume(usb_dwc_dev_t *hw)
627 {
628     return hw->hprt_reg.prtres;
629 }
630 
usb_dwc_ll_hprt_get_port_overcur(usb_dwc_dev_t * hw)631 static inline bool usb_dwc_ll_hprt_get_port_overcur(usb_dwc_dev_t *hw)
632 {
633     return hw->hprt_reg.prtovrcurract;
634 }
635 
usb_dwc_ll_hprt_get_port_en(usb_dwc_dev_t * hw)636 static inline bool usb_dwc_ll_hprt_get_port_en(usb_dwc_dev_t *hw)
637 {
638     return hw->hprt_reg.prtena;
639 }
640 
usb_dwc_ll_hprt_port_dis(usb_dwc_dev_t * hw)641 static inline void usb_dwc_ll_hprt_port_dis(usb_dwc_dev_t *hw)
642 {
643     usb_dwc_hprt_reg_t hprt;
644     hprt.val = hw->hprt_reg.val;
645     hprt.prtena = 1;        //W1C to disable
646     //we want to W1C ENA but not W1C the interrupt bits
647     hw->hprt_reg.val = hprt.val & ((~USB_DWC_LL_HPRT_W1C_MSK) | USB_DWC_LL_HPRT_ENA_MSK);
648 }
649 
usb_dwc_ll_hprt_get_conn_status(usb_dwc_dev_t * hw)650 static inline bool usb_dwc_ll_hprt_get_conn_status(usb_dwc_dev_t *hw)
651 {
652     return hw->hprt_reg.prtconnsts;
653 }
654 
usb_dwc_ll_hprt_intr_read_and_clear(usb_dwc_dev_t * hw)655 static inline uint32_t usb_dwc_ll_hprt_intr_read_and_clear(usb_dwc_dev_t *hw)
656 {
657     usb_dwc_hprt_reg_t hprt;
658     hprt.val = hw->hprt_reg.val;
659     //We want to W1C the interrupt bits but not that ENA
660     hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_ENA_MSK);
661     //Return only the interrupt bits
662     return (hprt.val & (USB_DWC_LL_HPRT_W1C_MSK & ~(USB_DWC_LL_HPRT_ENA_MSK)));
663 }
664 
usb_dwc_ll_hprt_intr_clear(usb_dwc_dev_t * hw,uint32_t intr_mask)665 static inline void usb_dwc_ll_hprt_intr_clear(usb_dwc_dev_t *hw, uint32_t intr_mask)
666 {
667     usb_dwc_hprt_reg_t hprt;
668     hprt.val = hw->hprt_reg.val;
669     hw->hprt_reg.val = ((hprt.val & ~USB_DWC_LL_HPRT_ENA_MSK) & ~USB_DWC_LL_HPRT_W1C_MSK) | intr_mask;
670 }
671 
672 //Per Channel registers
673 
674 // --------------------------- HCCHARi Register --------------------------------
675 
usb_dwc_ll_hcchar_enable_chan(volatile usb_dwc_host_chan_regs_t * chan)676 static inline void usb_dwc_ll_hcchar_enable_chan(volatile usb_dwc_host_chan_regs_t *chan)
677 {
678     chan->hcchar_reg.chena = 1;
679 }
680 
usb_dwc_ll_hcchar_chan_is_enabled(volatile usb_dwc_host_chan_regs_t * chan)681 static inline bool usb_dwc_ll_hcchar_chan_is_enabled(volatile usb_dwc_host_chan_regs_t *chan)
682 {
683     return chan->hcchar_reg.chena;
684 }
685 
usb_dwc_ll_hcchar_disable_chan(volatile usb_dwc_host_chan_regs_t * chan)686 static inline void usb_dwc_ll_hcchar_disable_chan(volatile usb_dwc_host_chan_regs_t *chan)
687 {
688     chan->hcchar_reg.chdis = 1;
689 }
690 
usb_dwc_ll_hcchar_set_odd_frame(volatile usb_dwc_host_chan_regs_t * chan)691 static inline void usb_dwc_ll_hcchar_set_odd_frame(volatile usb_dwc_host_chan_regs_t *chan)
692 {
693     chan->hcchar_reg.oddfrm = 1;
694 }
695 
usb_dwc_ll_hcchar_set_even_frame(volatile usb_dwc_host_chan_regs_t * chan)696 static inline void usb_dwc_ll_hcchar_set_even_frame(volatile usb_dwc_host_chan_regs_t *chan)
697 {
698     chan->hcchar_reg.oddfrm = 0;
699 }
700 
usb_dwc_ll_hcchar_set_dev_addr(volatile usb_dwc_host_chan_regs_t * chan,uint32_t addr)701 static inline void usb_dwc_ll_hcchar_set_dev_addr(volatile usb_dwc_host_chan_regs_t *chan, uint32_t addr)
702 {
703     chan->hcchar_reg.devaddr = addr;
704 }
705 
usb_dwc_ll_hcchar_set_ep_type(volatile usb_dwc_host_chan_regs_t * chan,usb_dwc_xfer_type_t type)706 static inline void usb_dwc_ll_hcchar_set_ep_type(volatile usb_dwc_host_chan_regs_t *chan, usb_dwc_xfer_type_t type)
707 {
708     chan->hcchar_reg.eptype = (uint32_t)type;
709 }
710 
711 //Indicates whether channel is commuunicating with a LS device connected via a FS hub. Setting this bit to 1 will cause
712 //each packet to be preceded by a PREamble packet
usb_dwc_ll_hcchar_set_lspddev(volatile usb_dwc_host_chan_regs_t * chan,bool is_ls)713 static inline void usb_dwc_ll_hcchar_set_lspddev(volatile usb_dwc_host_chan_regs_t *chan, bool is_ls)
714 {
715     chan->hcchar_reg.lspddev = is_ls;
716 }
717 
usb_dwc_ll_hcchar_set_dir(volatile usb_dwc_host_chan_regs_t * chan,bool is_in)718 static inline void usb_dwc_ll_hcchar_set_dir(volatile usb_dwc_host_chan_regs_t *chan, bool is_in)
719 {
720     chan->hcchar_reg.epdir = is_in;
721 }
722 
usb_dwc_ll_hcchar_set_ep_num(volatile usb_dwc_host_chan_regs_t * chan,uint32_t num)723 static inline void usb_dwc_ll_hcchar_set_ep_num(volatile usb_dwc_host_chan_regs_t *chan, uint32_t num)
724 {
725     chan->hcchar_reg.epnum = num;
726 }
727 
usb_dwc_ll_hcchar_set_mps(volatile usb_dwc_host_chan_regs_t * chan,uint32_t mps)728 static inline void usb_dwc_ll_hcchar_set_mps(volatile usb_dwc_host_chan_regs_t *chan, uint32_t mps)
729 {
730     chan->hcchar_reg.mps = mps;
731 }
732 
usb_dwc_ll_hcchar_init(volatile usb_dwc_host_chan_regs_t * chan,int dev_addr,int ep_num,int mps,usb_dwc_xfer_type_t type,bool is_in,bool is_ls)733 static inline void usb_dwc_ll_hcchar_init(volatile usb_dwc_host_chan_regs_t *chan, int dev_addr, int ep_num, int mps, usb_dwc_xfer_type_t type, bool is_in, bool is_ls)
734 {
735     //Sets all persistent fields of the channel over its lifetimez
736     usb_dwc_ll_hcchar_set_dev_addr(chan, dev_addr);
737     usb_dwc_ll_hcchar_set_ep_type(chan, type);
738     usb_dwc_ll_hcchar_set_lspddev(chan, is_ls);
739     usb_dwc_ll_hcchar_set_dir(chan, is_in);
740     usb_dwc_ll_hcchar_set_ep_num(chan, ep_num);
741     usb_dwc_ll_hcchar_set_mps(chan, mps);
742 }
743 
744 // ---------------------------- HCINTi Register --------------------------------
745 
usb_dwc_ll_hcint_read_and_clear_intrs(volatile usb_dwc_host_chan_regs_t * chan)746 static inline uint32_t usb_dwc_ll_hcint_read_and_clear_intrs(volatile usb_dwc_host_chan_regs_t *chan)
747 {
748     usb_dwc_hcint_reg_t hcint;
749     hcint.val = chan->hcint_reg.val;
750     chan->hcint_reg.val = hcint.val;
751     return hcint.val;
752 }
753 
754 // --------------------------- HCINTMSKi Register ------------------------------
755 
usb_dwc_ll_hcintmsk_set_intr_mask(volatile usb_dwc_host_chan_regs_t * chan,uint32_t mask)756 static inline void usb_dwc_ll_hcintmsk_set_intr_mask(volatile usb_dwc_host_chan_regs_t *chan, uint32_t mask)
757 {
758     chan->hcintmsk_reg.val = mask;
759 }
760 
761 // ---------------------------- HCTSIZi Register -------------------------------
762 
usb_dwc_ll_hctsiz_set_pid(volatile usb_dwc_host_chan_regs_t * chan,uint32_t data_pid)763 static inline void usb_dwc_ll_hctsiz_set_pid(volatile usb_dwc_host_chan_regs_t *chan, uint32_t data_pid)
764 {
765     if (data_pid == 0) {
766         chan->hctsiz_reg.pid = 0;
767     } else {
768         chan->hctsiz_reg.pid = 2;
769     }
770 }
771 
usb_dwc_ll_hctsiz_get_pid(volatile usb_dwc_host_chan_regs_t * chan)772 static inline uint32_t usb_dwc_ll_hctsiz_get_pid(volatile usb_dwc_host_chan_regs_t *chan)
773 {
774     if (chan->hctsiz_reg.pid == 0) {
775         return 0;   //DATA0
776     } else {
777         return 1;   //DATA1
778     }
779 }
780 
usb_dwc_ll_hctsiz_set_qtd_list_len(volatile usb_dwc_host_chan_regs_t * chan,int qtd_list_len)781 static inline void usb_dwc_ll_hctsiz_set_qtd_list_len(volatile usb_dwc_host_chan_regs_t *chan, int qtd_list_len)
782 {
783     usb_dwc_hctsiz_reg_t hctsiz;
784     hctsiz.val = chan->hctsiz_reg.val;
785     //Set the length of the descriptor list. NTD occupies xfersize[15:8]
786     hctsiz.xfersize &= ~(0xFF << 8);
787     hctsiz.xfersize |= ((qtd_list_len - 1) & 0xFF) << 8;
788     chan->hctsiz_reg.val = hctsiz.val;
789 }
790 
usb_dwc_ll_hctsiz_init(volatile usb_dwc_host_chan_regs_t * chan)791 static inline void usb_dwc_ll_hctsiz_init(volatile usb_dwc_host_chan_regs_t *chan)
792 {
793     usb_dwc_hctsiz_reg_t hctsiz;
794     hctsiz.val = chan->hctsiz_reg.val;
795     hctsiz.dopng = 0;         //Don't do ping
796     /*
797     Set SCHED_INFO which occupies xfersize[7:0]
798     It is always set to 0xFF for full speed and not used in Bulk/Ctrl channels
799     */
800     hctsiz.xfersize |= 0xFF;
801     chan->hctsiz_reg.val = hctsiz.val;
802 }
803 
usb_dwc_ll_hctsiz_set_sched_info(volatile usb_dwc_host_chan_regs_t * chan,int tokens_per_frame,int offset)804 static inline void usb_dwc_ll_hctsiz_set_sched_info(volatile usb_dwc_host_chan_regs_t *chan, int tokens_per_frame, int offset)
805 {
806     // @see USB-OTG databook: Table 5-47
807     // This function is relevant only for HS
808     usb_dwc_hctsiz_reg_t hctsiz;
809     hctsiz.val = chan->hctsiz_reg.val;
810     uint8_t sched_info_val;
811     switch (tokens_per_frame) {
812         case 1:
813             offset %= 8; // If the required offset > 8, we must wrap around to SCHED_INFO size = 8
814             sched_info_val = 0b00000001;
815             break;
816         case 2:
817             offset %= 4;
818             sched_info_val = 0b00010001;
819             break;
820         case 4:
821             offset %= 2;
822             sched_info_val = 0b01010101;
823             break;
824         case 8:
825             offset = 0;
826             sched_info_val = 0b11111111;
827             break;
828         default:
829             abort();
830             break;
831     }
832     sched_info_val <<= offset;
833     hctsiz.xfersize &= ~(0xFF);
834     hctsiz.xfersize |= sched_info_val;
835     chan->hctsiz_reg.val = hctsiz.val;
836 }
837 
838 // ---------------------------- HCDMAi Register --------------------------------
839 
usb_dwc_ll_hcdma_set_qtd_list_addr(volatile usb_dwc_host_chan_regs_t * chan,void * dmaaddr,uint32_t qtd_idx)840 static inline void usb_dwc_ll_hcdma_set_qtd_list_addr(volatile usb_dwc_host_chan_regs_t *chan, void *dmaaddr, uint32_t qtd_idx)
841 {
842     usb_dwc_hcdma_reg_t hcdma;
843     /*
844     Set the base address portion of the field which is dmaaddr[31:9]. This is
845     the based address of the QTD list and must be 512 bytes aligned
846     */
847     hcdma.dmaaddr = ((uint32_t)dmaaddr) & 0xFFFFFE00;
848     //Set the current QTD index in the QTD list which is dmaaddr[8:3]
849     hcdma.dmaaddr |= (qtd_idx & 0x3F) << 3;
850     //dmaaddr[2:0] is reserved thus doesn't not need to be set
851 
852     chan->hcdma_reg.val = hcdma.val;
853 }
854 
usb_dwc_ll_hcdam_get_cur_qtd_idx(usb_dwc_host_chan_regs_t * chan)855 static inline int usb_dwc_ll_hcdam_get_cur_qtd_idx(usb_dwc_host_chan_regs_t *chan)
856 {
857     //The current QTD index is dmaaddr[8:3]
858     return (chan->hcdma_reg.dmaaddr >> 3) & 0x3F;
859 }
860 
861 // ---------------------------- HCDMABi Register -------------------------------
862 
usb_dwc_ll_hcdmab_get_buff_addr(volatile usb_dwc_host_chan_regs_t * chan)863 static inline void *usb_dwc_ll_hcdmab_get_buff_addr(volatile usb_dwc_host_chan_regs_t *chan)
864 {
865     return (void *)chan->hcdmab_reg.hcdmab;
866 }
867 
868 /* -----------------------------------------------------------------------------
869 ---------------------------- Scatter/Gather DMA QTDs ---------------------------
870 ----------------------------------------------------------------------------- */
871 
872 // ---------------------------- Helper Functions -------------------------------
873 
874 /**
875  * @brief Get the base address of a channel's register based on the channel's index
876  *
877  * @param dev Start address of the DWC_OTG registers
878  * @param chan_idx The channel's index
879  * @return usb_dwc_host_chan_regs_t* Pointer to channel's registers
880  */
usb_dwc_ll_chan_get_regs(usb_dwc_dev_t * dev,int chan_idx)881 static inline usb_dwc_host_chan_regs_t *usb_dwc_ll_chan_get_regs(usb_dwc_dev_t *dev, int chan_idx)
882 {
883     return &dev->host_chans[chan_idx];
884 }
885 
886 // ------------------------------ QTD related ----------------------------------
887 
888 #define USB_DWC_LL_QTD_STATUS_SUCCESS      0x0     //If QTD was processed, it indicates the data was transmitted/received successfully
889 #define USB_DWC_LL_QTD_STATUS_PKTERR       0x1     //Data trasnmitted/received with errors (CRC/Timeout/Stuff/False EOP/Excessive NAK).
890 //Note: 0x2 is reserved
891 #define USB_DWC_LL_QTD_STATUS_BUFFER       0x3     //AHB error occurred.
892 #define USB_DWC_LL_QTD_STATUS_NOT_EXECUTED 0x4     //QTD as never processed
893 
894 /**
895  * @brief Set a QTD for a non isochronous IN transfer
896  *
897  * @param qtd Pointer to the QTD
898  * @param data_buff Pointer to buffer containing the data to transfer
899  * @param xfer_len Number of bytes in transfer. Setting 0 will do a zero length IN transfer.
900  *                 Non zero length must be mulitple of the endpoint's MPS.
901  * @param hoc Halt on complete (will generate an interrupt and halt the channel)
902  */
usb_dwc_ll_qtd_set_in(usb_dwc_ll_dma_qtd_t * qtd,uint8_t * data_buff,int xfer_len,bool hoc)903 static inline void usb_dwc_ll_qtd_set_in(usb_dwc_ll_dma_qtd_t *qtd, uint8_t *data_buff, int xfer_len, bool hoc)
904 {
905     qtd->buffer = data_buff;        //Set pointer to data buffer
906     qtd->buffer_status_val = 0;     //Reset all flags to zero
907     qtd->in_non_iso.xfer_size = xfer_len;
908     if (hoc) {
909         qtd->in_non_iso.intr_cplt = 1;  //We need to set this to distinguish between a halt due to a QTD
910         qtd->in_non_iso.eol = 1;        //Used to halt the channel at this qtd
911     }
912     qtd->in_non_iso.active = 1;
913 }
914 
915 /**
916  * @brief Set a QTD for a non isochronous OUT transfer
917  *
918  * @param qtd Poitner to the QTD
919  * @param data_buff Pointer to buffer containing the data to transfer
920  * @param xfer_len Number of bytes to transfer. Setting 0 will do a zero length transfer.
921  *                 For ctrl setup packets, this should be set to 8.
922  * @param hoc Halt on complete (will generate an interrupt)
923  * @param is_setup Indicates whether this is a control transfer setup packet or a normal OUT Data transfer.
924  *                 (As per the USB protocol, setup packets cannot be STALLd or NAKd by the device)
925  */
usb_dwc_ll_qtd_set_out(usb_dwc_ll_dma_qtd_t * qtd,uint8_t * data_buff,int xfer_len,bool hoc,bool is_setup)926 static inline void usb_dwc_ll_qtd_set_out(usb_dwc_ll_dma_qtd_t *qtd, uint8_t *data_buff, int xfer_len, bool hoc, bool is_setup)
927 {
928     qtd->buffer = data_buff;        //Set pointer to data buffer
929     qtd->buffer_status_val = 0;     //Reset all flags to zero
930     qtd->out_non_iso.xfer_size = xfer_len;
931     if (is_setup) {
932         qtd->out_non_iso.is_setup = 1;
933     }
934     if (hoc) {
935         qtd->in_non_iso.intr_cplt = 1;  //We need to set this to distinguish between a halt due to a QTD
936         qtd->in_non_iso.eol = 1;        //Used to halt the channel at this qtd
937     }
938     qtd->out_non_iso.active = 1;
939 }
940 
941 /**
942  * @brief Set a QTD as NULL
943  *
944  * This sets the QTD to a value of 0. This is only useful when you need to insert
945  * blank QTDs into a list of QTDs
946  *
947  * @param qtd Pointer to the QTD
948  */
usb_dwc_ll_qtd_set_null(usb_dwc_ll_dma_qtd_t * qtd)949 static inline void usb_dwc_ll_qtd_set_null(usb_dwc_ll_dma_qtd_t *qtd)
950 {
951     qtd->buffer = NULL;
952     qtd->buffer_status_val = 0;     //Disable qtd by clearing it to zero. Used by interrupt/isoc as an unscheudled frame
953 }
954 
955 /**
956  * @brief Get the status of a QTD
957  *
958  * When a channel get's halted, call this to check whether each QTD was executed successfully
959  *
960  * @param qtd Poitner to the QTD
961  * @param[out] rem_len Number of bytes ramining in the QTD
962  * @param[out] status Status of the QTD
963  */
usb_dwc_ll_qtd_get_status(usb_dwc_ll_dma_qtd_t * qtd,int * rem_len,int * status)964 static inline void usb_dwc_ll_qtd_get_status(usb_dwc_ll_dma_qtd_t *qtd, int *rem_len, int *status)
965 {
966     //Status is the same regardless of IN or OUT
967     if (qtd->in_non_iso.active) {
968         //QTD was never processed
969         *status = USB_DWC_LL_QTD_STATUS_NOT_EXECUTED;
970     } else {
971         *status = qtd->in_non_iso.rx_status;
972     }
973     *rem_len = qtd->in_non_iso.xfer_size;
974     //Clear the QTD just for safety
975     qtd->buffer_status_val = 0;
976 }
977 
978 #endif // SOC_USB_OTG_SUPPORTED
979 
980 #ifdef __cplusplus
981 }
982 #endif
983