1 /*
2  * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #pragma once
8 
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12 
13 #include <stdint.h>
14 #include <stdbool.h>
15 #include "soc/usbh_struct.h"
16 #include "hal/usb_types_private.h"
17 #include "hal/misc.h"
18 
19 
20 /* -----------------------------------------------------------------------------
21 ------------------------------- Global Registers -------------------------------
22 ----------------------------------------------------------------------------- */
23 
24 /*
25  * Interrupt bit masks of the GINTSTS and GINTMSK registers
26  */
27 #define USB_LL_INTR_CORE_WKUPINT        (1 << 31)
28 #define USB_LL_INTR_CORE_SESSREQINT     (1 << 30)
29 #define USB_LL_INTR_CORE_DISCONNINT     (1 << 29)
30 #define USB_LL_INTR_CORE_CONIDSTSCHNG   (1 << 28)
31 #define USB_LL_INTR_CORE_PTXFEMP        (1 << 26)
32 #define USB_LL_INTR_CORE_HCHINT         (1 << 25)
33 #define USB_LL_INTR_CORE_PRTINT         (1 << 24)
34 #define USB_LL_INTR_CORE_RESETDET       (1 << 23)
35 #define USB_LL_INTR_CORE_FETSUSP        (1 << 22)
36 #define USB_LL_INTR_CORE_INCOMPIP       (1 << 21)
37 #define USB_LL_INTR_CORE_INCOMPISOIN    (1 << 20)
38 #define USB_LL_INTR_CORE_OEPINT         (1 << 19)
39 #define USB_LL_INTR_CORE_IEPINT         (1 << 18)
40 #define USB_LL_INTR_CORE_EPMIS          (1 << 17)
41 #define USB_LL_INTR_CORE_EOPF           (1 << 15)
42 #define USB_LL_INTR_CORE_ISOOUTDROP     (1 << 14)
43 #define USB_LL_INTR_CORE_ENUMDONE       (1 << 13)
44 #define USB_LL_INTR_CORE_USBRST         (1 << 12)
45 #define USB_LL_INTR_CORE_USBSUSP        (1 << 11)
46 #define USB_LL_INTR_CORE_ERLYSUSP       (1 << 10)
47 #define USB_LL_INTR_CORE_GOUTNAKEFF     (1 << 7)
48 #define USB_LL_INTR_CORE_GINNAKEFF      (1 << 6)
49 #define USB_LL_INTR_CORE_NPTXFEMP       (1 << 5)
50 #define USB_LL_INTR_CORE_RXFLVL         (1 << 4)
51 #define USB_LL_INTR_CORE_SOF            (1 << 3)
52 #define USB_LL_INTR_CORE_OTGINT         (1 << 2)
53 #define USB_LL_INTR_CORE_MODEMIS        (1 << 1)
54 #define USB_LL_INTR_CORE_CURMOD         (1 << 0)
55 
56 /*
57  * Bit mask of interrupt generating bits of the the HPRT register. These bits
58  * are ORd into the USB_LL_INTR_CORE_PRTINT interrupt.
59  *
60  * Note: Some fields of the HPRT are W1C (write 1 clear), this we cannot do a
61  * simple read and write-back to clear the HPRT interrupt bits. Instead we need
62  * a W1C mask the non-interrupt related bits
63  */
64 #define USBH_LL_HPRT_W1C_MSK                (0x2E)
65 #define USBH_LL_HPRT_ENA_MSK                (0x04)
66 #define USBH_LL_INTR_HPRT_PRTOVRCURRCHNG    (1 << 5)
67 #define USBH_LL_INTR_HPRT_PRTENCHNG         (1 << 3)
68 #define USBH_LL_INTR_HPRT_PRTCONNDET        (1 << 1)
69 
70 /*
71  * Bit mask of channel interrupts (HCINTi and HCINTMSKi registers)
72  *
73  * Note: Under Scatter/Gather DMA mode, only the following interrupts can be unmasked
74  * - DESC_LS_ROLL
75  * - XCS_XACT_ERR (always unmasked)
76  * - BNAINTR
77  * - CHHLTD
78  * - XFERCOMPL
79  * The remaining interrupt bits will still be set (when the corresponding event occurs)
80  * but will not generate an interrupt. Therefore we must proxy through the
81  * USBH_LL_INTR_CHAN_CHHLTD interrupt to check the other interrupt bits.
82  */
83 #define USBH_LL_INTR_CHAN_DESC_LS_ROLL      (1 << 13)
84 #define USBH_LL_INTR_CHAN_XCS_XACT_ERR      (1 << 12)
85 #define USBH_LL_INTR_CHAN_BNAINTR           (1 << 11)
86 #define USBH_LL_INTR_CHAN_DATATGLERR        (1 << 10)
87 #define USBH_LL_INTR_CHAN_FRMOVRUN          (1 << 9)
88 #define USBH_LL_INTR_CHAN_BBLEER            (1 << 8)
89 #define USBH_LL_INTR_CHAN_XACTERR           (1 << 7)
90 #define USBH_LL_INTR_CHAN_NYET              (1 << 6)
91 #define USBH_LL_INTR_CHAN_ACK               (1 << 5)
92 #define USBH_LL_INTR_CHAN_NAK               (1 << 4)
93 #define USBH_LL_INTR_CHAN_STALL             (1 << 3)
94 #define USBH_LL_INTR_CHAN_AHBERR            (1 << 2)
95 #define USBH_LL_INTR_CHAN_CHHLTD            (1 << 1)
96 #define USBH_LL_INTR_CHAN_XFERCOMPL         (1 << 0)
97 
98 /*
99  * QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode.
100  * Each QTD describes one transfer. Scatter gather mode will automatically split
101  * a transfer into multiple MPS packets. Each QTD is 64bits in size
102  *
103  * Note: The status information part of the QTD is interpreted differently depending
104  * on IN or OUT, and ISO or non-ISO
105  */
106 typedef struct {
107     union {
108         struct {
109             uint32_t xfer_size: 17;
110             uint32_t aqtd_offset: 6;
111             uint32_t aqtd_valid: 1;
112             uint32_t reserved_24: 1;
113             uint32_t intr_cplt: 1;
114             uint32_t eol: 1;
115             uint32_t reserved_27: 1;
116             uint32_t rx_status: 2;
117             uint32_t reserved_30: 1;
118             uint32_t active: 1;
119         } in_non_iso;
120         struct {
121             uint32_t xfer_size: 12;
122             uint32_t reserved_12_24: 13;
123             uint32_t intr_cplt: 1;
124             uint32_t reserved_26_27: 2;
125             uint32_t rx_status: 2;
126             uint32_t reserved_30: 1;
127             uint32_t active: 1;
128         } in_iso;
129         struct {
130             uint32_t xfer_size: 17;
131             uint32_t reserved_17_23: 7;
132             uint32_t is_setup: 1;
133             uint32_t intr_cplt: 1;
134             uint32_t eol: 1;
135             uint32_t reserved_27: 1;
136             uint32_t tx_status: 2;
137             uint32_t reserved_30: 1;
138             uint32_t active: 1;
139         } out_non_iso;
140         struct {
141             uint32_t xfer_size: 12;
142             uint32_t reserved_12_24: 13;
143             uint32_t intr_cplt: 1;
144             uint32_t eol: 1;
145             uint32_t reserved_27: 1;
146             uint32_t tx_status: 2;
147             uint32_t reserved_30: 1;
148             uint32_t active: 1;
149         } out_iso;
150         uint32_t buffer_status_val;
151     };
152     uint8_t *buffer;
153 } usbh_ll_dma_qtd_t;
154 
155 
156 /* -----------------------------------------------------------------------------
157 ------------------------------- Global Registers -------------------------------
158 ----------------------------------------------------------------------------- */
159 
160 // --------------------------- GAHBCFG Register --------------------------------
161 
usb_ll_en_dma_mode(usbh_dev_t * hw)162 static inline void usb_ll_en_dma_mode(usbh_dev_t *hw)
163 {
164     hw->gahbcfg_reg.dmaen = 1;
165 }
166 
usb_ll_en_slave_mode(usbh_dev_t * hw)167 static inline void usb_ll_en_slave_mode(usbh_dev_t *hw)
168 {
169     hw->gahbcfg_reg.dmaen = 0;
170 }
171 
usb_ll_set_hbstlen(usbh_dev_t * hw,uint32_t burst_len)172 static inline void usb_ll_set_hbstlen(usbh_dev_t *hw, uint32_t burst_len)
173 {
174     hw->gahbcfg_reg.hbstlen = burst_len;
175 }
176 
usb_ll_en_global_intr(usbh_dev_t * hw)177 static inline void usb_ll_en_global_intr(usbh_dev_t *hw)
178 {
179     hw->gahbcfg_reg.glbllntrmsk = 1;
180 }
181 
usb_ll_dis_global_intr(usbh_dev_t * hw)182 static inline void usb_ll_dis_global_intr(usbh_dev_t *hw)
183 {
184     hw->gahbcfg_reg.glbllntrmsk = 0;
185 }
186 
187 // --------------------------- GUSBCFG Register --------------------------------
188 
usb_ll_set_host_mode(usbh_dev_t * hw)189 static inline void usb_ll_set_host_mode(usbh_dev_t *hw)
190 {
191     hw->gusbcfg_reg.forcehstmode = 1;
192 }
193 
usb_ll_dis_hnp_cap(usbh_dev_t * hw)194 static inline void usb_ll_dis_hnp_cap(usbh_dev_t *hw)
195 {
196     hw->gusbcfg_reg.hnpcap = 0;
197 }
198 
usb_ll_dis_srp_cap(usbh_dev_t * hw)199 static inline void usb_ll_dis_srp_cap(usbh_dev_t *hw)
200 {
201     hw->gusbcfg_reg.srpcap = 0;
202 }
203 
204 // --------------------------- GRSTCTL Register --------------------------------
205 
usb_ll_check_ahb_idle(usbh_dev_t * hw)206 static inline bool usb_ll_check_ahb_idle(usbh_dev_t *hw)
207 {
208     return hw->grstctl_reg.ahbidle;
209 }
210 
usb_ll_check_dma_req_in_progress(usbh_dev_t * hw)211 static inline bool usb_ll_check_dma_req_in_progress(usbh_dev_t *hw)
212 {
213     return hw->grstctl_reg.dmareq;
214 }
215 
usb_ll_flush_nptx_fifo(usbh_dev_t * hw)216 static inline void usb_ll_flush_nptx_fifo(usbh_dev_t *hw)
217 {
218     hw->grstctl_reg.txfnum = 0;     //Set the TX FIFO number to 0 to select the non-periodic TX FIFO
219     hw->grstctl_reg.txfflsh = 1;    //Flush the selected TX FIFO
220     //Wait for the flushing to complete
221     while (hw->grstctl_reg.txfflsh) {
222         ;
223     }
224 }
225 
usb_ll_flush_ptx_fifo(usbh_dev_t * hw)226 static inline void usb_ll_flush_ptx_fifo(usbh_dev_t *hw)
227 {
228     hw->grstctl_reg.txfnum = 1;     //Set the TX FIFO number to 1 to select the periodic TX FIFO
229     hw->grstctl_reg.txfflsh = 1;    //FLush the select TX FIFO
230     //Wait for the flushing to complete
231     while (hw->grstctl_reg.txfflsh) {
232         ;
233     }
234 }
235 
usb_ll_flush_rx_fifo(usbh_dev_t * hw)236 static inline void usb_ll_flush_rx_fifo(usbh_dev_t *hw)
237 {
238     hw->grstctl_reg.rxfflsh = 1;
239     //Wait for the flushing to complete
240     while (hw->grstctl_reg.rxfflsh) {
241         ;
242     }
243 }
244 
usb_ll_reset_frame_counter(usbh_dev_t * hw)245 static inline void usb_ll_reset_frame_counter(usbh_dev_t *hw)
246 {
247     hw->grstctl_reg.frmcntrrst = 1;
248 }
249 
usb_ll_core_soft_reset(usbh_dev_t * hw)250 static inline void usb_ll_core_soft_reset(usbh_dev_t *hw)
251 {
252     hw->grstctl_reg.csftrst = 1;
253 }
254 
usb_ll_check_core_soft_reset(usbh_dev_t * hw)255 static inline bool usb_ll_check_core_soft_reset(usbh_dev_t *hw)
256 {
257     return hw->grstctl_reg.csftrst;
258 }
259 
260 // --------------------------- GINTSTS Register --------------------------------
261 
262 /**
263  * @brief Reads and clears the global interrupt register
264  *
265  * @param hw Start address of the DWC_OTG registers
266  * @return uint32_t Mask of interrupts
267  */
usb_ll_intr_read_and_clear(usbh_dev_t * hw)268 static inline uint32_t usb_ll_intr_read_and_clear(usbh_dev_t *hw)
269 {
270     usb_gintsts_reg_t gintsts;
271     gintsts.val = hw->gintsts_reg.val;
272     hw->gintsts_reg.val = gintsts.val;  //Write back to clear
273     return gintsts.val;
274 }
275 
276 /**
277  * @brief Clear specific interrupts
278  *
279  * @param hw Start address of the DWC_OTG registers
280  * @param intr_msk Mask of interrupts to clear
281  */
usb_ll_intr_clear(usbh_dev_t * hw,uint32_t intr_msk)282 static inline void usb_ll_intr_clear(usbh_dev_t *hw, uint32_t intr_msk)
283 {
284     //All GINTSTS fields are either W1C or read only. So safe to write directly
285     hw->gintsts_reg.val = intr_msk;
286 }
287 
288 // --------------------------- GINTMSK Register --------------------------------
289 
usb_ll_en_intrs(usbh_dev_t * hw,uint32_t intr_mask)290 static inline void usb_ll_en_intrs(usbh_dev_t *hw, uint32_t intr_mask)
291 {
292     hw->gintmsk_reg.val |= intr_mask;
293 }
294 
usb_ll_dis_intrs(usbh_dev_t * hw,uint32_t intr_mask)295 static inline void usb_ll_dis_intrs(usbh_dev_t *hw, uint32_t intr_mask)
296 {
297     hw->gintmsk_reg.val &= ~intr_mask;
298 }
299 
300 // --------------------------- GRXFSIZ Register --------------------------------
301 
usb_ll_set_rx_fifo_size(usbh_dev_t * hw,uint32_t num_lines)302 static inline void usb_ll_set_rx_fifo_size(usbh_dev_t *hw, uint32_t num_lines)
303 {
304     //Set size in words
305     HAL_FORCE_MODIFY_U32_REG_FIELD(hw->grxfsiz_reg, rxfdep, num_lines);
306 }
307 
308 // -------------------------- GNPTXFSIZ Register -------------------------------
309 
usb_ll_set_nptx_fifo_size(usbh_dev_t * hw,uint32_t addr,uint32_t num_lines)310 static inline void usb_ll_set_nptx_fifo_size(usbh_dev_t *hw, uint32_t addr, uint32_t num_lines)
311 {
312     usb_gnptxfsiz_reg_t gnptxfsiz;
313     gnptxfsiz.val = hw->gnptxfsiz_reg.val;
314     HAL_FORCE_MODIFY_U32_REG_FIELD(gnptxfsiz, nptxfstaddr, addr);
315     HAL_FORCE_MODIFY_U32_REG_FIELD(gnptxfsiz, nptxfdep, num_lines);
316     hw->gnptxfsiz_reg.val = gnptxfsiz.val;
317 }
318 
usb_ll_get_controller_core_id(usbh_dev_t * hw)319 static inline uint32_t usb_ll_get_controller_core_id(usbh_dev_t *hw)
320 {
321     return hw->gsnpsid_reg.val;
322 }
323 
324 /**
325  * @brief Get the hardware configuration regiters of the DWC_OTG controller
326  *
327  * The hardware configuraiton regitsers are read only and indicate the various
328  * features of the DWC_OTG core.
329  *
330  * @param hw Start address of the DWC_OTG registers
331  * @param[out] ghwcfg1 Hardware configuration registesr 1
332  * @param[out] ghwcfg2 Hardware configuration registesr 2
333  * @param[out] ghwcfg3 Hardware configuration registesr 3
334  * @param[out] ghwcfg4 Hardware configuration registesr 4
335  */
usb_ll_get_hardware_config(usbh_dev_t * hw,uint32_t * ghwcfg1,uint32_t * ghwcfg2,uint32_t * ghwcfg3,uint32_t * ghwcfg4)336 static inline void usb_ll_get_hardware_config(usbh_dev_t *hw, uint32_t *ghwcfg1, uint32_t *ghwcfg2, uint32_t *ghwcfg3, uint32_t *ghwcfg4)
337 {
338     *ghwcfg1 = hw->ghwcfg1_reg.val;
339     *ghwcfg2 = hw->ghwcfg2_reg.val;
340     *ghwcfg3 = hw->ghwcfg3_reg.val;
341     *ghwcfg4 = hw->ghwcfg4_reg.val;
342 }
343 
344 // --------------------------- HPTXFSIZ Register -------------------------------
345 
usbh_ll_set_ptx_fifo_size(usbh_dev_t * hw,uint32_t addr,uint32_t num_lines)346 static inline void usbh_ll_set_ptx_fifo_size(usbh_dev_t *hw, uint32_t addr, uint32_t num_lines)
347 {
348     usb_hptxfsiz_reg_t hptxfsiz;
349     hptxfsiz.val = hw->hptxfsiz_reg.val;
350     HAL_FORCE_MODIFY_U32_REG_FIELD(hptxfsiz, ptxfstaddr, addr);
351     HAL_FORCE_MODIFY_U32_REG_FIELD(hptxfsiz, ptxfsize, num_lines);
352     hw->hptxfsiz_reg.val = hptxfsiz.val;
353 }
354 
355 /* -----------------------------------------------------------------------------
356 -------------------------------- Host Registers --------------------------------
357 ----------------------------------------------------------------------------- */
358 
359 // ----------------------------- HCFG Register ---------------------------------
360 
usbh_ll_hcfg_en_perio_sched(usbh_dev_t * hw)361 static inline void usbh_ll_hcfg_en_perio_sched(usbh_dev_t *hw)
362 {
363     hw->hcfg_reg.perschedena = 1;
364 }
365 
usbh_ll_hcfg_dis_perio_sched(usbh_dev_t * hw)366 static inline void usbh_ll_hcfg_dis_perio_sched(usbh_dev_t *hw)
367 {
368     hw->hcfg_reg.perschedena = 0;
369 }
370 
371 /**
372  * Sets the length of the frame list
373  *
374  * @param num_entires Number of entires in the frame list
375  */
usbh_ll_hcfg_set_num_frame_list_entries(usbh_dev_t * hw,usb_hal_frame_list_len_t num_entries)376 static inline void usbh_ll_hcfg_set_num_frame_list_entries(usbh_dev_t *hw, usb_hal_frame_list_len_t num_entries)
377 {
378     uint32_t frlisten;
379     switch (num_entries) {
380         case USB_HAL_FRAME_LIST_LEN_8:
381             frlisten = 0;
382             break;
383         case USB_HAL_FRAME_LIST_LEN_16:
384             frlisten = 1;
385             break;
386         case USB_HAL_FRAME_LIST_LEN_32:
387             frlisten = 2;
388             break;
389         default: //USB_HAL_FRAME_LIST_LEN_64
390             frlisten = 3;
391             break;
392     }
393     hw->hcfg_reg.frlisten = frlisten;
394 }
395 
usbh_ll_hcfg_en_scatt_gatt_dma(usbh_dev_t * hw)396 static inline void usbh_ll_hcfg_en_scatt_gatt_dma(usbh_dev_t *hw)
397 {
398     hw->hcfg_reg.descdma = 1;
399 }
400 
usbh_ll_hcfg_set_fsls_supp_only(usbh_dev_t * hw)401 static inline void usbh_ll_hcfg_set_fsls_supp_only(usbh_dev_t *hw)
402 {
403     hw->hcfg_reg.fslssupp = 1;
404 }
405 
usbh_ll_hcfg_set_fsls_pclk_sel(usbh_dev_t * hw)406 static inline void usbh_ll_hcfg_set_fsls_pclk_sel(usbh_dev_t *hw)
407 {
408     hw->hcfg_reg.fslspclksel = 1;
409 }
410 
411 /**
412  * @brief Sets some default values to HCFG to operate in Host mode with scatter/gather DMA
413  *
414  * @param hw Start address of the DWC_OTG registers
415  * @param speed Speed to initialize the host port at
416  */
usbh_ll_hcfg_set_defaults(usbh_dev_t * hw,usb_priv_speed_t speed)417 static inline void usbh_ll_hcfg_set_defaults(usbh_dev_t *hw, usb_priv_speed_t speed)
418 {
419     hw->hcfg_reg.descdma = 1;   //Enable scatt/gatt
420     hw->hcfg_reg.fslssupp = 1;  //FS/LS support only
421     /*
422     Indicate to the OTG core what speed the PHY clock is at
423     Note: It seems like our PHY has an implicit 8 divider applied when in LS mode,
424           so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
425     */
426     hw->hcfg_reg.fslspclksel = (speed == USB_PRIV_SPEED_FULL) ? 1 : 2;  //PHY clock on esp32-sx for FS/LS-only
427     hw->hcfg_reg.perschedena = 0;   //Disable perio sched
428 }
429 
430 // ----------------------------- HFIR Register ---------------------------------
431 
usbh_ll_hfir_set_defaults(usbh_dev_t * hw,usb_priv_speed_t speed)432 static inline void usbh_ll_hfir_set_defaults(usbh_dev_t *hw, usb_priv_speed_t speed)
433 {
434     usb_hfir_reg_t hfir;
435     hfir.val = hw->hfir_reg.val;
436     hfir.hfirrldctrl = 0;       //Disable dynamic loading
437     /*
438     Set frame interval to be equal to 1ms
439     Note: It seems like our PHY has an implicit 8 divider applied when in LS mode,
440           so the values of FSLSPclkSel and FrInt have to be adjusted accordingly.
441     */
442     hfir.frint = (speed == USB_PRIV_SPEED_FULL) ? 48000 : 6000; //esp32-sx targets only support FS or LS
443     hw->hfir_reg.val = hfir.val;
444 }
445 
446 // ----------------------------- HFNUM Register --------------------------------
447 
usbh_ll_get_frm_time_rem(usbh_dev_t * hw)448 static inline uint32_t usbh_ll_get_frm_time_rem(usbh_dev_t *hw)
449 {
450     return HAL_FORCE_READ_U32_REG_FIELD(hw->hfnum_reg, frrem);
451 }
452 
usbh_ll_get_frm_num(usbh_dev_t * hw)453 static inline uint32_t usbh_ll_get_frm_num(usbh_dev_t *hw)
454 {
455     return hw->hfnum_reg.frnum;
456 }
457 
458 // ---------------------------- HPTXSTS Register -------------------------------
459 
usbh_ll_get_p_tx_queue_top(usbh_dev_t * hw)460 static inline uint32_t usbh_ll_get_p_tx_queue_top(usbh_dev_t *hw)
461 {
462     return HAL_FORCE_READ_U32_REG_FIELD(hw->hptxsts_reg, ptxqtop);
463 }
464 
usbh_ll_get_p_tx_queue_space_avail(usbh_dev_t * hw)465 static inline uint32_t usbh_ll_get_p_tx_queue_space_avail(usbh_dev_t *hw)
466 {
467     return hw->hptxsts_reg.ptxqspcavail;
468 }
469 
usbh_ll_get_p_tx_fifo_space_avail(usbh_dev_t * hw)470 static inline uint32_t usbh_ll_get_p_tx_fifo_space_avail(usbh_dev_t *hw)
471 {
472     return HAL_FORCE_READ_U32_REG_FIELD(hw->hptxsts_reg, ptxfspcavail);
473 }
474 
475 // ----------------------------- HAINT Register --------------------------------
476 
usbh_ll_get_chan_intrs_msk(usbh_dev_t * hw)477 static inline uint32_t usbh_ll_get_chan_intrs_msk(usbh_dev_t *hw)
478 {
479     return HAL_FORCE_READ_U32_REG_FIELD(hw->haint_reg, haint);
480 }
481 
482 // --------------------------- HAINTMSK Register -------------------------------
483 
usbh_ll_haintmsk_en_chan_intr(usbh_dev_t * hw,uint32_t mask)484 static inline void usbh_ll_haintmsk_en_chan_intr(usbh_dev_t *hw, uint32_t mask)
485 {
486 
487     hw->haintmsk_reg.val |= mask;
488 }
489 
usbh_ll_haintmsk_dis_chan_intr(usbh_dev_t * hw,uint32_t mask)490 static inline void usbh_ll_haintmsk_dis_chan_intr(usbh_dev_t *hw, uint32_t mask)
491 {
492     hw->haintmsk_reg.val &= ~mask;
493 }
494 
495 // --------------------------- HFLBAddr Register -------------------------------
496 
497 /**
498  * @brief Set the base address of the scheduling frame list
499  *
500  * @note For some reason, this address must be 512 bytes aligned or else a bunch of frames will not be scheduled when
501  *       the frame list rolls over. However, according to the databook, there is no mention of the HFLBAddr needing to
502  *       be aligned.
503  *
504  * @param hw Start address of the DWC_OTG registers
505  * @param addr Base address of the scheduling frame list
506  */
usbh_ll_set_frame_list_base_addr(usbh_dev_t * hw,uint32_t addr)507 static inline void usbh_ll_set_frame_list_base_addr(usbh_dev_t *hw, uint32_t addr)
508 {
509     hw->hflbaddr_reg.hflbaddr = addr;
510 }
511 
512 /**
513  * @brief Get the base address of the scheduling frame list
514  *
515  * @param hw Start address of the DWC_OTG registers
516  * @return uint32_t Base address of the scheduling frame list
517  */
usbh_ll_get_frame_list_base_addr(usbh_dev_t * hw)518 static inline uint32_t usbh_ll_get_frame_list_base_addr(usbh_dev_t *hw)
519 {
520     return hw->hflbaddr_reg.hflbaddr;
521 }
522 
523 // ----------------------------- HPRT Register ---------------------------------
524 
usbh_ll_hprt_get_speed(usbh_dev_t * hw)525 static inline usb_priv_speed_t usbh_ll_hprt_get_speed(usbh_dev_t *hw)
526 {
527     usb_priv_speed_t speed;
528     //esp32-s2 and esp32-s3 only support FS or LS
529     switch (hw->hprt_reg.prtspd) {
530         case 1:
531             speed = USB_PRIV_SPEED_FULL;
532             break;
533         default:
534             speed = USB_PRIV_SPEED_LOW;
535             break;
536     }
537     return speed;
538 }
539 
usbh_ll_hprt_get_test_ctl(usbh_dev_t * hw)540 static inline uint32_t usbh_ll_hprt_get_test_ctl(usbh_dev_t *hw)
541 {
542     return hw->hprt_reg.prttstctl;
543 }
544 
usbh_ll_hprt_set_test_ctl(usbh_dev_t * hw,uint32_t test_mode)545 static inline void usbh_ll_hprt_set_test_ctl(usbh_dev_t *hw, uint32_t test_mode)
546 {
547     usb_hprt_reg_t hprt;
548     hprt.val = hw->hprt_reg.val;
549     hprt.prttstctl = test_mode;
550     hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
551 }
552 
usbh_ll_hprt_en_pwr(usbh_dev_t * hw)553 static inline void usbh_ll_hprt_en_pwr(usbh_dev_t *hw)
554 {
555     usb_hprt_reg_t hprt;
556     hprt.val = hw->hprt_reg.val;
557     hprt.prtpwr = 1;
558     hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
559 }
560 
usbh_ll_hprt_dis_pwr(usbh_dev_t * hw)561 static inline void usbh_ll_hprt_dis_pwr(usbh_dev_t *hw)
562 {
563     usb_hprt_reg_t hprt;
564     hprt.val = hw->hprt_reg.val;
565     hprt.prtpwr = 0;
566     hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
567 }
568 
usbh_ll_hprt_get_pwr_line_status(usbh_dev_t * hw)569 static inline uint32_t usbh_ll_hprt_get_pwr_line_status(usbh_dev_t *hw)
570 {
571     return hw->hprt_reg.prtlnsts;
572 }
573 
usbh_ll_hprt_set_port_reset(usbh_dev_t * hw,bool reset)574 static inline void usbh_ll_hprt_set_port_reset(usbh_dev_t *hw, bool reset)
575 {
576     usb_hprt_reg_t hprt;
577     hprt.val = hw->hprt_reg.val;
578     hprt.prtrst = reset;
579     hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
580 }
581 
usbh_ll_hprt_get_port_reset(usbh_dev_t * hw)582 static inline bool usbh_ll_hprt_get_port_reset(usbh_dev_t *hw)
583 {
584     return hw->hprt_reg.prtrst;
585 }
586 
usbh_ll_hprt_set_port_suspend(usbh_dev_t * hw)587 static inline void usbh_ll_hprt_set_port_suspend(usbh_dev_t *hw)
588 {
589     usb_hprt_reg_t hprt;
590     hprt.val = hw->hprt_reg.val;
591     hprt.prtsusp = 1;
592     hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
593 }
594 
usbh_ll_hprt_get_port_suspend(usbh_dev_t * hw)595 static inline bool usbh_ll_hprt_get_port_suspend(usbh_dev_t *hw)
596 {
597     return hw->hprt_reg.prtsusp;
598 }
599 
usbh_ll_hprt_set_port_resume(usbh_dev_t * hw)600 static inline void usbh_ll_hprt_set_port_resume(usbh_dev_t *hw)
601 {
602     usb_hprt_reg_t hprt;
603     hprt.val = hw->hprt_reg.val;
604     hprt.prtres = 1;
605     hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
606 }
607 
usbh_ll_hprt_clr_port_resume(usbh_dev_t * hw)608 static inline void usbh_ll_hprt_clr_port_resume(usbh_dev_t *hw)
609 {
610     usb_hprt_reg_t hprt;
611     hprt.val = hw->hprt_reg.val;
612     hprt.prtres = 0;
613     hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_W1C_MSK);
614 }
615 
usbh_ll_hprt_get_port_resume(usbh_dev_t * hw)616 static inline bool usbh_ll_hprt_get_port_resume(usbh_dev_t *hw)
617 {
618     return hw->hprt_reg.prtres;
619 }
620 
usbh_ll_hprt_get_port_overcur(usbh_dev_t * hw)621 static inline bool usbh_ll_hprt_get_port_overcur(usbh_dev_t *hw)
622 {
623     return hw->hprt_reg.prtovrcurract;
624 }
625 
usbh_ll_hprt_get_port_en(usbh_dev_t * hw)626 static inline bool usbh_ll_hprt_get_port_en(usbh_dev_t *hw)
627 {
628     return hw->hprt_reg.prtena;
629 }
630 
usbh_ll_hprt_port_dis(usbh_dev_t * hw)631 static inline void usbh_ll_hprt_port_dis(usbh_dev_t *hw)
632 {
633     usb_hprt_reg_t hprt;
634     hprt.val = hw->hprt_reg.val;
635     hprt.prtena = 1;        //W1C to disable
636     //we want to W1C ENA but not W1C the interrupt bits
637     hw->hprt_reg.val = hprt.val & ((~USBH_LL_HPRT_W1C_MSK) | USBH_LL_HPRT_ENA_MSK);
638 }
639 
usbh_ll_hprt_get_conn_status(usbh_dev_t * hw)640 static inline bool usbh_ll_hprt_get_conn_status(usbh_dev_t *hw)
641 {
642     return hw->hprt_reg.prtconnsts;
643 }
644 
usbh_ll_hprt_intr_read_and_clear(usbh_dev_t * hw)645 static inline uint32_t usbh_ll_hprt_intr_read_and_clear(usbh_dev_t *hw)
646 {
647     usb_hprt_reg_t hprt;
648     hprt.val = hw->hprt_reg.val;
649     //We want to W1C the interrupt bits but not that ENA
650     hw->hprt_reg.val = hprt.val & (~USBH_LL_HPRT_ENA_MSK);
651     //Return only the interrupt bits
652     return (hprt.val & (USBH_LL_HPRT_W1C_MSK & ~(USBH_LL_HPRT_ENA_MSK)));
653 }
654 
usbh_ll_hprt_intr_clear(usbh_dev_t * hw,uint32_t intr_mask)655 static inline void usbh_ll_hprt_intr_clear(usbh_dev_t *hw, uint32_t intr_mask)
656 {
657     usb_hprt_reg_t hprt;
658     hprt.val = hw->hprt_reg.val;
659     hw->hprt_reg.val = ((hprt.val & ~USBH_LL_HPRT_ENA_MSK) & ~USBH_LL_HPRT_W1C_MSK) | intr_mask;
660 }
661 
662 //Per Channel registers
663 
664 // --------------------------- HCCHARi Register --------------------------------
665 
usbh_ll_chan_start(volatile usb_host_chan_regs_t * chan)666 static inline void usbh_ll_chan_start(volatile usb_host_chan_regs_t *chan)
667 {
668     chan->hcchar_reg.chena = 1;
669 }
670 
usbh_ll_chan_is_active(volatile usb_host_chan_regs_t * chan)671 static inline bool usbh_ll_chan_is_active(volatile usb_host_chan_regs_t *chan)
672 {
673     return chan->hcchar_reg.chena;
674 }
675 
usbh_ll_chan_halt(volatile usb_host_chan_regs_t * chan)676 static inline void usbh_ll_chan_halt(volatile usb_host_chan_regs_t *chan)
677 {
678     chan->hcchar_reg.chdis = 1;
679 }
680 
usbh_ll_chan_xfer_odd_frame(volatile usb_host_chan_regs_t * chan)681 static inline void usbh_ll_chan_xfer_odd_frame(volatile usb_host_chan_regs_t *chan)
682 {
683     chan->hcchar_reg.oddfrm = 1;
684 }
685 
usbh_ll_chan_xfer_even_frame(volatile usb_host_chan_regs_t * chan)686 static inline void usbh_ll_chan_xfer_even_frame(volatile usb_host_chan_regs_t *chan)
687 {
688     chan->hcchar_reg.oddfrm = 0;
689 }
690 
usbh_ll_chan_set_dev_addr(volatile usb_host_chan_regs_t * chan,uint32_t addr)691 static inline void usbh_ll_chan_set_dev_addr(volatile usb_host_chan_regs_t *chan, uint32_t addr)
692 {
693     chan->hcchar_reg.devaddr = addr;
694 }
695 
usbh_ll_chan_set_ep_type(volatile usb_host_chan_regs_t * chan,usb_priv_xfer_type_t type)696 static inline void usbh_ll_chan_set_ep_type(volatile usb_host_chan_regs_t *chan, usb_priv_xfer_type_t type)
697 {
698     uint32_t ep_type;
699     switch (type) {
700         case USB_PRIV_XFER_TYPE_CTRL:
701             ep_type = 0;
702             break;
703         case USB_PRIV_XFER_TYPE_ISOCHRONOUS:
704             ep_type = 1;
705             break;
706         case USB_PRIV_XFER_TYPE_BULK:
707             ep_type = 2;
708             break;
709         default:    //USB_PRIV_XFER_TYPE_INTR
710             ep_type = 3;
711             break;
712     }
713     chan->hcchar_reg.eptype = ep_type;
714 }
715 
716 //Indicates whether channel is commuunicating with a LS device connected via a FS hub. Setting this bit to 1 will cause
717 //each packet to be preceded by a PREamble packet
usbh_ll_chan_set_lspddev(volatile usb_host_chan_regs_t * chan,bool is_ls)718 static inline void usbh_ll_chan_set_lspddev(volatile usb_host_chan_regs_t *chan, bool is_ls)
719 {
720     chan->hcchar_reg.lspddev = is_ls;
721 }
722 
usbh_ll_chan_set_dir(volatile usb_host_chan_regs_t * chan,bool is_in)723 static inline void usbh_ll_chan_set_dir(volatile usb_host_chan_regs_t *chan, bool is_in)
724 {
725     chan->hcchar_reg.epdir = is_in;
726 }
727 
usbh_ll_chan_set_ep_num(volatile usb_host_chan_regs_t * chan,uint32_t num)728 static inline void usbh_ll_chan_set_ep_num(volatile usb_host_chan_regs_t *chan, uint32_t num)
729 {
730     chan->hcchar_reg.epnum = num;
731 }
732 
usbh_ll_chan_set_mps(volatile usb_host_chan_regs_t * chan,uint32_t mps)733 static inline void usbh_ll_chan_set_mps(volatile usb_host_chan_regs_t *chan, uint32_t mps)
734 {
735     chan->hcchar_reg.mps = mps;
736 }
737 
usbh_ll_chan_hcchar_init(volatile usb_host_chan_regs_t * chan,int dev_addr,int ep_num,int mps,usb_priv_xfer_type_t type,bool is_in,bool is_ls)738 static inline void usbh_ll_chan_hcchar_init(volatile usb_host_chan_regs_t *chan, int dev_addr, int ep_num, int mps, usb_priv_xfer_type_t type, bool is_in, bool is_ls)
739 {
740     //Sets all persistent fields of the channel over its lifetimez
741     usbh_ll_chan_set_dev_addr(chan, dev_addr);
742     usbh_ll_chan_set_ep_type(chan, type);
743     usbh_ll_chan_set_lspddev(chan, is_ls);
744     usbh_ll_chan_set_dir(chan, is_in);
745     usbh_ll_chan_set_ep_num(chan, ep_num);
746     usbh_ll_chan_set_mps(chan, mps);
747 }
748 
749 // ---------------------------- HCINTi Register --------------------------------
750 
usbh_ll_chan_intr_read_and_clear(volatile usb_host_chan_regs_t * chan)751 static inline uint32_t usbh_ll_chan_intr_read_and_clear(volatile usb_host_chan_regs_t *chan)
752 {
753     usb_hcint_reg_t hcint;
754     hcint.val = chan->hcint_reg.val;
755     chan->hcint_reg.val = hcint.val;
756     return hcint.val;
757 }
758 
759 // --------------------------- HCINTMSKi Register ------------------------------
760 
usbh_ll_chan_set_intr_mask(volatile usb_host_chan_regs_t * chan,uint32_t mask)761 static inline void usbh_ll_chan_set_intr_mask(volatile usb_host_chan_regs_t *chan, uint32_t mask)
762 {
763     chan->hcintmsk_reg.val = mask;
764 }
765 
766 // ---------------------- HCTSIZi and HCDMAi Registers -------------------------
767 
usbh_ll_chan_set_pid(volatile usb_host_chan_regs_t * chan,uint32_t data_pid)768 static inline void usbh_ll_chan_set_pid(volatile usb_host_chan_regs_t *chan, uint32_t data_pid)
769 {
770     if (data_pid == 0) {
771         chan->hctsiz_reg.pid = 0;
772     } else {
773         chan->hctsiz_reg.pid = 2;
774     }
775 }
776 
usbh_ll_chan_get_pid(volatile usb_host_chan_regs_t * chan)777 static inline uint32_t usbh_ll_chan_get_pid(volatile usb_host_chan_regs_t *chan) {
778     if (chan->hctsiz_reg.pid == 0) {
779         return 0;   //DATA0
780     } else {
781         return 1;   //DATA1
782     }
783 }
784 
usbh_ll_chan_set_dma_addr_non_iso(volatile usb_host_chan_regs_t * chan,void * dmaaddr,uint32_t qtd_idx)785 static inline void usbh_ll_chan_set_dma_addr_non_iso(volatile usb_host_chan_regs_t *chan,
786                                                     void *dmaaddr,
787                                                     uint32_t qtd_idx)
788 {
789     //Set HCDMAi
790     chan->hcdma_reg.val = 0;
791     chan->hcdma_reg.non_iso.dmaaddr = (((uint32_t)dmaaddr) >> 9) & 0x7FFFFF;  //MSB of 512 byte aligned address
792     chan->hcdma_reg.non_iso.ctd = qtd_idx;
793 }
794 
usbh_ll_chan_get_ctd(usb_host_chan_regs_t * chan)795 static inline int usbh_ll_chan_get_ctd(usb_host_chan_regs_t *chan)
796 {
797     return chan->hcdma_reg.non_iso.ctd;
798 }
799 
usbh_ll_chan_hctsiz_init(volatile usb_host_chan_regs_t * chan)800 static inline void usbh_ll_chan_hctsiz_init(volatile usb_host_chan_regs_t *chan)
801 {
802     chan->hctsiz_reg.dopng = 0;         //Don't do ping
803     HAL_FORCE_MODIFY_U32_REG_FIELD(chan->hctsiz_reg, sched_info, 0xFF); //Schedinfo is always 0xFF for fullspeed. Not used in Bulk/Ctrl channels
804 }
805 
usbh_ll_chan_set_qtd_list_len(volatile usb_host_chan_regs_t * chan,int qtd_list_len)806 static inline void usbh_ll_chan_set_qtd_list_len(volatile usb_host_chan_regs_t *chan, int qtd_list_len)
807 {
808     HAL_FORCE_MODIFY_U32_REG_FIELD(chan->hctsiz_reg, ntd, qtd_list_len - 1);    //Set the length of the descriptor list
809 }
810 
811 // ---------------------------- HCDMABi Register -------------------------------
812 
usbh_ll_chan_get_cur_buff_addr(volatile usb_host_chan_regs_t * chan)813 static inline void *usbh_ll_chan_get_cur_buff_addr(volatile usb_host_chan_regs_t *chan)
814 {
815     return (void *)chan->hcdmab_reg.hcdmab;
816 }
817 
818 /* -----------------------------------------------------------------------------
819 ---------------------------- Scatter/Gather DMA QTDs ---------------------------
820 ----------------------------------------------------------------------------- */
821 
822 // ---------------------------- Helper Functions -------------------------------
823 
824 /**
825  * @brief Get the base address of a channel's register based on the channel's index
826  *
827  * @param dev Start address of the DWC_OTG registers
828  * @param chan_idx The channel's index
829  * @return usb_host_chan_regs_t* Pointer to channel's registers
830  */
usbh_ll_get_chan_regs(usbh_dev_t * dev,int chan_idx)831 static inline usb_host_chan_regs_t *usbh_ll_get_chan_regs(usbh_dev_t *dev, int chan_idx)
832 {
833     return &dev->host_chans[chan_idx];
834 }
835 
836 // ------------------------------ QTD related ----------------------------------
837 
838 #define USBH_LL_QTD_STATUS_SUCCESS      0x0     //If QTD was processed, it indicates the data was transmitted/received successfully
839 #define USBH_LL_QTD_STATUS_PKTERR       0x1     //Data trasnmitted/received with errors (CRC/Timeout/Stuff/False EOP/Excessive NAK).
840 //Note: 0x2 is reserved
841 #define USBH_LL_QTD_STATUS_BUFFER       0x3     //AHB error occurred.
842 #define USBH_LL_QTD_STATUS_NOT_EXECUTED 0x4     //QTD as never processed
843 
844 /**
845  * @brief Set a QTD for a non isochronous IN transfer
846  *
847  * @param qtd Pointer to the QTD
848  * @param data_buff Pointer to buffer containing the data to transfer
849  * @param xfer_len Number of bytes in transfer. Setting 0 will do a zero length IN transfer.
850  *                 Non zero length must be mulitple of the endpoint's MPS.
851  * @param hoc Halt on complete (will generate an interrupt and halt the channel)
852  */
usbh_ll_set_qtd_in(usbh_ll_dma_qtd_t * qtd,uint8_t * data_buff,int xfer_len,bool hoc)853 static inline void usbh_ll_set_qtd_in(usbh_ll_dma_qtd_t *qtd, uint8_t *data_buff, int xfer_len, bool hoc)
854 {
855     qtd->buffer = data_buff;        //Set pointer to data buffer
856     qtd->buffer_status_val = 0;     //Reset all flags to zero
857     qtd->in_non_iso.xfer_size = xfer_len;
858     if (hoc) {
859         qtd->in_non_iso.intr_cplt = 1;  //We need to set this to distinguish between a halt due to a QTD
860         qtd->in_non_iso.eol = 1;        //Used to halt the channel at this qtd
861     }
862     qtd->in_non_iso.active = 1;
863 }
864 
865 /**
866  * @brief Set a QTD for a non isochronous OUT transfer
867  *
868  * @param qtd Poitner to the QTD
869  * @param data_buff Pointer to buffer containing the data to transfer
870  * @param xfer_len Number of bytes to transfer. Setting 0 will do a zero length transfer.
871  *                 For ctrl setup packets, this should be set to 8.
872  * @param hoc Halt on complete (will generate an interrupt)
873  * @param is_setup Indicates whether this is a control transfer setup packet or a normal OUT Data transfer.
874  *                 (As per the USB protocol, setup packets cannot be STALLd or NAKd by the device)
875  */
usbh_ll_set_qtd_out(usbh_ll_dma_qtd_t * qtd,uint8_t * data_buff,int xfer_len,bool hoc,bool is_setup)876 static inline void usbh_ll_set_qtd_out(usbh_ll_dma_qtd_t *qtd, uint8_t *data_buff, int xfer_len, bool hoc, bool is_setup)
877 {
878     qtd->buffer = data_buff;        //Set pointer to data buffer
879     qtd->buffer_status_val = 0;     //Reset all flags to zero
880     qtd->out_non_iso.xfer_size = xfer_len;
881     if (is_setup) {
882         qtd->out_non_iso.is_setup = 1;
883     }
884     if (hoc) {
885         qtd->in_non_iso.intr_cplt = 1;  //We need to set this to distinguish between a halt due to a QTD
886         qtd->in_non_iso.eol = 1;        //Used to halt the channel at this qtd
887     }
888     qtd->out_non_iso.active = 1;
889 }
890 
891 /**
892  * @brief Set a QTD as NULL
893  *
894  * This sets the QTD to a value of 0. This is only useful when you need to insert
895  * blank QTDs into a list of QTDs
896  *
897  * @param qtd Pointer to the QTD
898  */
usbh_ll_set_qtd_null(usbh_ll_dma_qtd_t * qtd)899 static inline void usbh_ll_set_qtd_null(usbh_ll_dma_qtd_t *qtd)
900 {
901     qtd->buffer = NULL;
902     qtd->buffer_status_val = 0;     //Disable qtd by clearing it to zero. Used by interrupt/isoc as an unscheudled frame
903 }
904 
905 /**
906  * @brief Get the status of a QTD
907  *
908  * When a channel get's halted, call this to check whether each QTD was executed successfully
909  *
910  * @param qtd Poitner to the QTD
911  * @param[out] rem_len Number of bytes ramining in the QTD
912  * @param[out] status Status of the QTD
913  */
usbh_ll_get_qtd_status(usbh_ll_dma_qtd_t * qtd,int * rem_len,int * status)914 static inline void usbh_ll_get_qtd_status(usbh_ll_dma_qtd_t *qtd, int *rem_len, int *status)
915 {
916     //Status is the same regardless of IN or OUT
917     if (qtd->in_non_iso.active) {
918         //QTD was never processed
919         *status = USBH_LL_QTD_STATUS_NOT_EXECUTED;
920     } else {
921         *status = qtd->in_non_iso.rx_status;
922     }
923     *rem_len = qtd->in_non_iso.xfer_size;
924     //Clear the QTD just for safety
925     qtd->buffer_status_val = 0;
926 }
927 
928 #ifdef __cplusplus
929 }
930 #endif
931