diff --git a/components/esp_hw_support/test_apps/usb_phy/README.md b/components/esp_hw_support/test_apps/usb_phy/README.md index 5b5662288fa89..11e0559833a49 100644 --- a/components/esp_hw_support/test_apps/usb_phy/README.md +++ b/components/esp_hw_support/test_apps/usb_phy/README.md @@ -1,4 +1,4 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # USB: PHY sanity checks diff --git a/components/hal/esp32h4/include/hal/usb_dwc_ll.h b/components/hal/esp32h4/include/hal/usb_dwc_ll.h new file mode 100644 index 0000000000000..7488affb70e1a --- /dev/null +++ b/components/hal/esp32h4/include/hal/usb_dwc_ll.h @@ -0,0 +1,983 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "soc/usb_dwc_struct.h" +#include "soc/usb_dwc_cfg.h" +#include "hal/usb_dwc_types.h" +#include "hal/misc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------- Helper Macros ------------------------------ */ + +// Get USB hardware instance +#define USB_DWC_LL_GET_HW(num) (&USB_DWC) + +/* ----------------------------------------------------------------------------- +--------------------------------- DWC Constants -------------------------------- +----------------------------------------------------------------------------- */ + +#define USB_DWC_QTD_LIST_MEM_ALIGN 512 +#define USB_DWC_FRAME_LIST_MEM_ALIGN 512 // The frame list needs to be 512 bytes aligned (contrary to the databook) + +/* ----------------------------------------------------------------------------- +------------------------------- Global Registers ------------------------------- +----------------------------------------------------------------------------- */ + +/* + * Interrupt bit masks of the GINTSTS and GINTMSK registers + */ +#define USB_DWC_LL_INTR_CORE_WKUPINT (1 << 31) +#define USB_DWC_LL_INTR_CORE_SESSREQINT (1 << 30) +#define USB_DWC_LL_INTR_CORE_DISCONNINT (1 << 29) +#define USB_DWC_LL_INTR_CORE_CONIDSTSCHNG (1 << 28) +#define USB_DWC_LL_INTR_CORE_PTXFEMP (1 << 26) +#define USB_DWC_LL_INTR_CORE_HCHINT (1 << 25) +#define USB_DWC_LL_INTR_CORE_PRTINT (1 << 24) +#define USB_DWC_LL_INTR_CORE_RESETDET (1 << 23) +#define USB_DWC_LL_INTR_CORE_FETSUSP (1 << 22) +#define USB_DWC_LL_INTR_CORE_INCOMPIP (1 << 21) +#define USB_DWC_LL_INTR_CORE_INCOMPISOIN (1 << 20) +#define USB_DWC_LL_INTR_CORE_OEPINT (1 << 19) +#define USB_DWC_LL_INTR_CORE_IEPINT (1 << 18) +#define USB_DWC_LL_INTR_CORE_EPMIS (1 << 17) +#define USB_DWC_LL_INTR_CORE_EOPF (1 << 15) +#define USB_DWC_LL_INTR_CORE_ISOOUTDROP (1 << 14) +#define USB_DWC_LL_INTR_CORE_ENUMDONE (1 << 13) +#define USB_DWC_LL_INTR_CORE_USBRST (1 << 12) +#define USB_DWC_LL_INTR_CORE_USBSUSP (1 << 11) +#define USB_DWC_LL_INTR_CORE_ERLYSUSP (1 << 10) +#define USB_DWC_LL_INTR_CORE_GOUTNAKEFF (1 << 7) +#define USB_DWC_LL_INTR_CORE_GINNAKEFF (1 << 6) +#define USB_DWC_LL_INTR_CORE_NPTXFEMP (1 << 5) +#define USB_DWC_LL_INTR_CORE_RXFLVL (1 << 4) +#define USB_DWC_LL_INTR_CORE_SOF (1 << 3) +#define USB_DWC_LL_INTR_CORE_OTGINT (1 << 2) +#define USB_DWC_LL_INTR_CORE_MODEMIS (1 << 1) +#define USB_DWC_LL_INTR_CORE_CURMOD (1 << 0) + +/* + * Bit mask of interrupt generating bits of the the HPRT register. These bits + * are ORd into the USB_DWC_LL_INTR_CORE_PRTINT interrupt. + * + * Note: Some fields of the HPRT are W1C (write 1 clear), this we cannot do a + * simple read and write-back to clear the HPRT interrupt bits. Instead we need + * a W1C mask the non-interrupt related bits + */ +#define USB_DWC_LL_HPRT_W1C_MSK (0x2E) +#define USB_DWC_LL_HPRT_ENA_MSK (0x04) +#define USB_DWC_LL_INTR_HPRT_PRTOVRCURRCHNG (1 << 5) +#define USB_DWC_LL_INTR_HPRT_PRTENCHNG (1 << 3) +#define USB_DWC_LL_INTR_HPRT_PRTCONNDET (1 << 1) + +/* + * Bit mask of channel interrupts (HCINTi and HCINTMSKi registers) + * + * Note: Under Scatter/Gather DMA mode, only the following interrupts can be unmasked + * - DESC_LS_ROLL + * - XCS_XACT_ERR (always unmasked) + * - BNAINTR + * - CHHLTD + * - XFERCOMPL + * The remaining interrupt bits will still be set (when the corresponding event occurs) + * but will not generate an interrupt. Therefore we must proxy through the + * USB_DWC_LL_INTR_CHAN_CHHLTD interrupt to check the other interrupt bits. + */ +#define USB_DWC_LL_INTR_CHAN_DESC_LS_ROLL (1 << 13) +#define USB_DWC_LL_INTR_CHAN_XCS_XACT_ERR (1 << 12) +#define USB_DWC_LL_INTR_CHAN_BNAINTR (1 << 11) +#define USB_DWC_LL_INTR_CHAN_DATATGLERR (1 << 10) +#define USB_DWC_LL_INTR_CHAN_FRMOVRUN (1 << 9) +#define USB_DWC_LL_INTR_CHAN_BBLEER (1 << 8) +#define USB_DWC_LL_INTR_CHAN_XACTERR (1 << 7) +#define USB_DWC_LL_INTR_CHAN_NYET (1 << 6) +#define USB_DWC_LL_INTR_CHAN_ACK (1 << 5) +#define USB_DWC_LL_INTR_CHAN_NAK (1 << 4) +#define USB_DWC_LL_INTR_CHAN_STALL (1 << 3) +#define USB_DWC_LL_INTR_CHAN_AHBERR (1 << 2) +#define USB_DWC_LL_INTR_CHAN_CHHLTD (1 << 1) +#define USB_DWC_LL_INTR_CHAN_XFERCOMPL (1 << 0) + +/* + * QTD (Queue Transfer Descriptor) structure used in Scatter/Gather DMA mode. + * Each QTD describes one transfer. Scatter gather mode will automatically split + * a transfer into multiple MPS packets. Each QTD is 64bits in size + * + * Note: The status information part of the QTD is interpreted differently depending + * on IN or OUT, and ISO or non-ISO + */ +typedef struct { + union { + struct { + uint32_t xfer_size: 17; + uint32_t aqtd_offset: 6; + uint32_t aqtd_valid: 1; + uint32_t reserved_24: 1; + uint32_t intr_cplt: 1; + uint32_t eol: 1; + uint32_t reserved_27: 1; + uint32_t rx_status: 2; + uint32_t reserved_30: 1; + uint32_t active: 1; + } in_non_iso; + struct { + uint32_t xfer_size: 12; + uint32_t reserved_12_24: 13; + uint32_t intr_cplt: 1; + uint32_t reserved_26_27: 2; + uint32_t rx_status: 2; + uint32_t reserved_30: 1; + uint32_t active: 1; + } in_iso; + struct { + uint32_t xfer_size: 17; + uint32_t reserved_17_23: 7; + uint32_t is_setup: 1; + uint32_t intr_cplt: 1; + uint32_t eol: 1; + uint32_t reserved_27: 1; + uint32_t tx_status: 2; + uint32_t reserved_30: 1; + uint32_t active: 1; + } out_non_iso; + struct { + uint32_t xfer_size: 12; + uint32_t reserved_12_24: 13; + uint32_t intr_cplt: 1; + uint32_t eol: 1; + uint32_t reserved_27: 1; + uint32_t tx_status: 2; + uint32_t reserved_30: 1; + uint32_t active: 1; + } out_iso; + uint32_t buffer_status_val; + }; + uint8_t *buffer; +} usb_dwc_ll_dma_qtd_t; + + +/* ----------------------------------------------------------------------------- +------------------------------- Global Registers ------------------------------- +----------------------------------------------------------------------------- */ + +// --------------------------- GAHBCFG Register -------------------------------- + +static inline void usb_dwc_ll_gahbcfg_en_dma_mode(usb_dwc_dev_t *hw) +{ + hw->gahbcfg_reg.dmaen = 1; +} + +static inline void usb_dwc_ll_gahbcfg_en_slave_mode(usb_dwc_dev_t *hw) +{ + hw->gahbcfg_reg.dmaen = 0; +} + +static inline void usb_dwc_ll_gahbcfg_set_hbstlen(usb_dwc_dev_t *hw, uint32_t burst_len) +{ + hw->gahbcfg_reg.hbstlen = burst_len; +} + +static inline void usb_dwc_ll_gahbcfg_en_global_intr(usb_dwc_dev_t *hw) +{ + hw->gahbcfg_reg.glbllntrmsk = 1; +} + +static inline void usb_dwc_ll_gahbcfg_dis_global_intr(usb_dwc_dev_t *hw) +{ + hw->gahbcfg_reg.glbllntrmsk = 0; +} + +// --------------------------- GUSBCFG Register -------------------------------- + +static inline void usb_dwc_ll_gusbcfg_force_host_mode(usb_dwc_dev_t *hw) +{ + hw->gusbcfg_reg.forcehstmode = 1; +} + +static inline void usb_dwc_ll_gusbcfg_dis_hnp_cap(usb_dwc_dev_t *hw) +{ + hw->gusbcfg_reg.hnpcap = 0; +} + +static inline void usb_dwc_ll_gusbcfg_dis_srp_cap(usb_dwc_dev_t *hw) +{ + hw->gusbcfg_reg.srpcap = 0; +} + +static inline void usb_dwc_ll_gusbcfg_set_timeout_cal(usb_dwc_dev_t *hw, uint8_t tout_cal) +{ + hw->gusbcfg_reg.toutcal = tout_cal; +} + +static inline void usb_dwc_ll_gusbcfg_set_utmi_phy(usb_dwc_dev_t *hw) +{ + hw->gusbcfg_reg.phyif = 1; // 16 bits interface + hw->gusbcfg_reg.ulpiutmisel = 0; // UTMI+ + hw->gusbcfg_reg.physel = 0; // HS PHY +} + +// --------------------------- GRSTCTL Register -------------------------------- + +static inline bool usb_dwc_ll_grstctl_is_ahb_idle(usb_dwc_dev_t *hw) +{ + return hw->grstctl_reg.ahbidle; +} + +static inline bool usb_dwc_ll_grstctl_is_dma_req_in_progress(usb_dwc_dev_t *hw) +{ + return hw->grstctl_reg.dmareq; +} + +static inline void usb_dwc_ll_grstctl_flush_nptx_fifo(usb_dwc_dev_t *hw) +{ + hw->grstctl_reg.txfnum = 0; //Set the TX FIFO number to 0 to select the non-periodic TX FIFO + hw->grstctl_reg.txfflsh = 1; //Flush the selected TX FIFO + //Wait for the flushing to complete + while (hw->grstctl_reg.txfflsh) { + ; + } +} + +static inline void usb_dwc_ll_grstctl_flush_ptx_fifo(usb_dwc_dev_t *hw) +{ + hw->grstctl_reg.txfnum = 1; //Set the TX FIFO number to 1 to select the periodic TX FIFO + hw->grstctl_reg.txfflsh = 1; //FLush the select TX FIFO + //Wait for the flushing to complete + while (hw->grstctl_reg.txfflsh) { + ; + } +} + +static inline void usb_dwc_ll_grstctl_flush_rx_fifo(usb_dwc_dev_t *hw) +{ + hw->grstctl_reg.rxfflsh = 1; + //Wait for the flushing to complete + while (hw->grstctl_reg.rxfflsh) { + ; + } +} + +static inline void usb_dwc_ll_grstctl_reset_frame_counter(usb_dwc_dev_t *hw) +{ + hw->grstctl_reg.frmcntrrst = 1; +} + +static inline void usb_dwc_ll_grstctl_core_soft_reset(usb_dwc_dev_t *hw) +{ + hw->grstctl_reg.csftrst = 1; +} + +static inline bool usb_dwc_ll_grstctl_is_core_soft_reset_in_progress(usb_dwc_dev_t *hw) +{ + return hw->grstctl_reg.csftrst; +} + +// --------------------------- GINTSTS Register -------------------------------- + +/** + * @brief Reads and clears the global interrupt register + * + * @param hw Start address of the DWC_OTG registers + * @return uint32_t Mask of interrupts + */ +static inline uint32_t usb_dwc_ll_gintsts_read_and_clear_intrs(usb_dwc_dev_t *hw) +{ + usb_dwc_gintsts_reg_t gintsts; + gintsts.val = hw->gintsts_reg.val; + hw->gintsts_reg.val = gintsts.val; //Write back to clear + return gintsts.val; +} + +/** + * @brief Clear specific interrupts + * + * @param hw Start address of the DWC_OTG registers + * @param intr_msk Mask of interrupts to clear + */ +static inline void usb_dwc_ll_gintsts_clear_intrs(usb_dwc_dev_t *hw, uint32_t intr_msk) +{ + //All GINTSTS fields are either W1C or read only. So safe to write directly + hw->gintsts_reg.val = intr_msk; +} + +// --------------------------- GINTMSK Register -------------------------------- + +static inline void usb_dwc_ll_gintmsk_en_intrs(usb_dwc_dev_t *hw, uint32_t intr_mask) +{ + hw->gintmsk_reg.val |= intr_mask; +} + +static inline void usb_dwc_ll_gintmsk_dis_intrs(usb_dwc_dev_t *hw, uint32_t intr_mask) +{ + hw->gintmsk_reg.val &= ~intr_mask; +} + +// --------------------------- GRXFSIZ Register -------------------------------- + +static inline void usb_dwc_ll_grxfsiz_set_fifo_size(usb_dwc_dev_t *hw, uint32_t num_lines) +{ + //Set size in words + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->grxfsiz_reg, rxfdep, num_lines); +} + +// -------------------------- GNPTXFSIZ Register ------------------------------- + +static inline void usb_dwc_ll_gnptxfsiz_set_fifo_size(usb_dwc_dev_t *hw, uint32_t addr, uint32_t num_lines) +{ + usb_dwc_gnptxfsiz_reg_t gnptxfsiz; + gnptxfsiz.val = hw->gnptxfsiz_reg.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(gnptxfsiz, nptxfstaddr, addr); + HAL_FORCE_MODIFY_U32_REG_FIELD(gnptxfsiz, nptxfdep, num_lines); + hw->gnptxfsiz_reg.val = gnptxfsiz.val; +} + +// --------------------------- GSNPSID Register -------------------------------- + +static inline uint32_t usb_dwc_ll_gsnpsid_get_id(usb_dwc_dev_t *hw) +{ + return hw->gsnpsid_reg.val; +} + +// --------------------------- GHWCFGx Register -------------------------------- + +static inline unsigned usb_dwc_ll_ghwcfg_get_fifo_depth(usb_dwc_dev_t *hw) +{ + return hw->ghwcfg3_reg.dfifodepth; +} + +static inline unsigned usb_dwc_ll_ghwcfg_get_hsphy_type(usb_dwc_dev_t *hw) +{ + return hw->ghwcfg2_reg.hsphytype; +} + +static inline unsigned usb_dwc_ll_ghwcfg_get_channel_num(usb_dwc_dev_t *hw) +{ + return hw->ghwcfg2_reg.numhstchnl + 1; +} + +// --------------------------- HPTXFSIZ Register ------------------------------- + +static inline void usb_dwc_ll_hptxfsiz_set_ptx_fifo_size(usb_dwc_dev_t *hw, uint32_t addr, uint32_t num_lines) +{ + usb_dwc_hptxfsiz_reg_t hptxfsiz; + hptxfsiz.val = hw->hptxfsiz_reg.val; + HAL_FORCE_MODIFY_U32_REG_FIELD(hptxfsiz, ptxfstaddr, addr); + HAL_FORCE_MODIFY_U32_REG_FIELD(hptxfsiz, ptxfsize, num_lines); + hw->hptxfsiz_reg.val = hptxfsiz.val; +} + +/* ----------------------------------------------------------------------------- +-------------------------------- Host Registers -------------------------------- +----------------------------------------------------------------------------- */ + +// ----------------------------- HCFG Register --------------------------------- + +static inline void usb_dwc_ll_hcfg_en_perio_sched(usb_dwc_dev_t *hw) +{ + hw->hcfg_reg.perschedena = 1; +} + +static inline void usb_dwc_ll_hcfg_dis_perio_sched(usb_dwc_dev_t *hw) +{ + hw->hcfg_reg.perschedena = 0; +} + +/** + * Sets the length of the frame list + * + * @param num_entires Number of entries in the frame list + */ +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) +{ + uint32_t frlisten; + switch (num_entries) { + case USB_HAL_FRAME_LIST_LEN_8: + frlisten = 0; + break; + case USB_HAL_FRAME_LIST_LEN_16: + frlisten = 1; + break; + case USB_HAL_FRAME_LIST_LEN_32: + frlisten = 2; + break; + default: //USB_HAL_FRAME_LIST_LEN_64 + frlisten = 3; + break; + } + hw->hcfg_reg.frlisten = frlisten; +} + +static inline void usb_dwc_ll_hcfg_en_scatt_gatt_dma(usb_dwc_dev_t *hw) +{ + hw->hcfg_reg.descdma = 1; +} + +static inline void usb_dwc_ll_hcfg_set_fsls_supp_only(usb_dwc_dev_t *hw) +{ + hw->hcfg_reg.fslssupp = 1; +} + +/** + * @brief Set FSLS PHY clock + * + * @attention This function should only be called if FSLS PHY is selected + * @param[in] hw Start address of the DWC_OTG registers + */ +static inline void usb_dwc_ll_hcfg_set_fsls_phy_clock(usb_dwc_dev_t *hw) +{ + /* + Indicate to the OTG core what speed the PHY clock is at + Note: FSLS PHY has an implicit 8 divider applied when in LS mode, + so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. + */ + usb_dwc_speed_t speed = (usb_dwc_speed_t)hw->hprt_reg.prtspd; + hw->hcfg_reg.fslspclksel = (speed == USB_DWC_SPEED_FULL) ? 1 : 2; +} + +// ----------------------------- HFIR Register --------------------------------- + +/** + * @brief Set Frame Interval + * + * @attention This function should only be called if FSLS PHY is selected + * @param[in] hw Start address of the DWC_OTG registers + */ +static inline void usb_dwc_ll_hfir_set_frame_interval(usb_dwc_dev_t *hw) +{ + usb_dwc_hfir_reg_t hfir; + hfir.val = hw->hfir_reg.val; + hfir.hfirrldctrl = 0; // Disable dynamic loading + /* + Set frame interval to be equal to 1ms + Note: FSLS PHY has an implicit 8 divider applied when in LS mode, + so the values of FSLSPclkSel and FrInt have to be adjusted accordingly. + */ + usb_dwc_speed_t speed = (usb_dwc_speed_t)hw->hprt_reg.prtspd; + hfir.frint = (speed == USB_DWC_SPEED_FULL) ? 48000 : 6000; + hw->hfir_reg.val = hfir.val; +} + +// ----------------------------- HFNUM Register -------------------------------- + +static inline uint32_t usb_dwc_ll_hfnum_get_frame_time_rem(usb_dwc_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->hfnum_reg, frrem); +} + +static inline uint32_t usb_dwc_ll_hfnum_get_frame_num(usb_dwc_dev_t *hw) +{ + return hw->hfnum_reg.frnum; +} + +// ---------------------------- HPTXSTS Register ------------------------------- + +static inline uint32_t usb_dwc_ll_hptxsts_get_ptxq_top(usb_dwc_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->hptxsts_reg, ptxqtop); +} + +static inline uint32_t usb_dwc_ll_hptxsts_get_ptxq_space_avail(usb_dwc_dev_t *hw) +{ + return hw->hptxsts_reg.ptxqspcavail; +} + +static inline uint32_t usb_dwc_ll_ptxsts_get_ptxf_space_avail(usb_dwc_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->hptxsts_reg, ptxfspcavail); +} + +// ----------------------------- HAINT Register -------------------------------- + +static inline uint32_t usb_dwc_ll_haint_get_chan_intrs(usb_dwc_dev_t *hw) +{ + return HAL_FORCE_READ_U32_REG_FIELD(hw->haint_reg, haint); +} + +// --------------------------- HAINTMSK Register ------------------------------- + +static inline void usb_dwc_ll_haintmsk_en_chan_intr(usb_dwc_dev_t *hw, uint32_t mask) +{ + + hw->haintmsk_reg.val |= mask; +} + +static inline void usb_dwc_ll_haintmsk_dis_chan_intr(usb_dwc_dev_t *hw, uint32_t mask) +{ + hw->haintmsk_reg.val &= ~mask; +} + +// --------------------------- HFLBAddr Register ------------------------------- + +/** + * @brief Set the base address of the scheduling frame list + * + * @note For some reason, this address must be 512 bytes aligned or else a bunch of frames will not be scheduled when + * the frame list rolls over. However, according to the databook, there is no mention of the HFLBAddr needing to + * be aligned. + * + * @param hw Start address of the DWC_OTG registers + * @param addr Base address of the scheduling frame list + */ +static inline void usb_dwc_ll_hflbaddr_set_base_addr(usb_dwc_dev_t *hw, uint32_t addr) +{ + hw->hflbaddr_reg.hflbaddr = addr; +} + +/** + * @brief Get the base address of the scheduling frame list + * + * @param hw Start address of the DWC_OTG registers + * @return uint32_t Base address of the scheduling frame list + */ +static inline uint32_t usb_dwc_ll_hflbaddr_get_base_addr(usb_dwc_dev_t *hw) +{ + return hw->hflbaddr_reg.hflbaddr; +} + +// ----------------------------- HPRT Register --------------------------------- + +static inline usb_dwc_speed_t usb_dwc_ll_hprt_get_speed(usb_dwc_dev_t *hw) +{ + return (usb_dwc_speed_t)hw->hprt_reg.prtspd; +} + +static inline uint32_t usb_dwc_ll_hprt_get_test_ctl(usb_dwc_dev_t *hw) +{ + return hw->hprt_reg.prttstctl; +} + +static inline void usb_dwc_ll_hprt_set_test_ctl(usb_dwc_dev_t *hw, uint32_t test_mode) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + hprt.prttstctl = test_mode; + hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK); +} + +static inline void usb_dwc_ll_hprt_en_pwr(usb_dwc_dev_t *hw) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + hprt.prtpwr = 1; + hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK); +} + +static inline void usb_dwc_ll_hprt_dis_pwr(usb_dwc_dev_t *hw) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + hprt.prtpwr = 0; + hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK); +} + +static inline uint32_t usb_dwc_ll_hprt_get_pwr_line_status(usb_dwc_dev_t *hw) +{ + return hw->hprt_reg.prtlnsts; +} + +static inline void usb_dwc_ll_hprt_set_port_reset(usb_dwc_dev_t *hw, bool reset) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + hprt.prtrst = reset; + hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK); +} + +static inline bool usb_dwc_ll_hprt_get_port_reset(usb_dwc_dev_t *hw) +{ + return hw->hprt_reg.prtrst; +} + +static inline void usb_dwc_ll_hprt_set_port_suspend(usb_dwc_dev_t *hw) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + hprt.prtsusp = 1; + hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK); +} + +static inline bool usb_dwc_ll_hprt_get_port_suspend(usb_dwc_dev_t *hw) +{ + return hw->hprt_reg.prtsusp; +} + +static inline void usb_dwc_ll_hprt_set_port_resume(usb_dwc_dev_t *hw) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + hprt.prtres = 1; + hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK); +} + +static inline void usb_dwc_ll_hprt_clr_port_resume(usb_dwc_dev_t *hw) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + hprt.prtres = 0; + hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_W1C_MSK); +} + +static inline bool usb_dwc_ll_hprt_get_port_resume(usb_dwc_dev_t *hw) +{ + return hw->hprt_reg.prtres; +} + +static inline bool usb_dwc_ll_hprt_get_port_overcur(usb_dwc_dev_t *hw) +{ + return hw->hprt_reg.prtovrcurract; +} + +static inline bool usb_dwc_ll_hprt_get_port_en(usb_dwc_dev_t *hw) +{ + return hw->hprt_reg.prtena; +} + +static inline void usb_dwc_ll_hprt_port_dis(usb_dwc_dev_t *hw) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + hprt.prtena = 1; //W1C to disable + //we want to W1C ENA but not W1C the interrupt bits + hw->hprt_reg.val = hprt.val & ((~USB_DWC_LL_HPRT_W1C_MSK) | USB_DWC_LL_HPRT_ENA_MSK); +} + +static inline bool usb_dwc_ll_hprt_get_conn_status(usb_dwc_dev_t *hw) +{ + return hw->hprt_reg.prtconnsts; +} + +static inline uint32_t usb_dwc_ll_hprt_intr_read_and_clear(usb_dwc_dev_t *hw) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + //We want to W1C the interrupt bits but not that ENA + hw->hprt_reg.val = hprt.val & (~USB_DWC_LL_HPRT_ENA_MSK); + //Return only the interrupt bits + return (hprt.val & (USB_DWC_LL_HPRT_W1C_MSK & ~(USB_DWC_LL_HPRT_ENA_MSK))); +} + +static inline void usb_dwc_ll_hprt_intr_clear(usb_dwc_dev_t *hw, uint32_t intr_mask) +{ + usb_dwc_hprt_reg_t hprt; + hprt.val = hw->hprt_reg.val; + hw->hprt_reg.val = ((hprt.val & ~USB_DWC_LL_HPRT_ENA_MSK) & ~USB_DWC_LL_HPRT_W1C_MSK) | intr_mask; +} + +//Per Channel registers + +// --------------------------- HCCHARi Register -------------------------------- + +static inline void usb_dwc_ll_hcchar_enable_chan(volatile usb_dwc_host_chan_regs_t *chan) +{ + chan->hcchar_reg.chena = 1; +} + +static inline bool usb_dwc_ll_hcchar_chan_is_enabled(volatile usb_dwc_host_chan_regs_t *chan) +{ + return chan->hcchar_reg.chena; +} + +static inline void usb_dwc_ll_hcchar_disable_chan(volatile usb_dwc_host_chan_regs_t *chan) +{ + chan->hcchar_reg.chdis = 1; +} + +static inline void usb_dwc_ll_hcchar_set_odd_frame(volatile usb_dwc_host_chan_regs_t *chan) +{ + chan->hcchar_reg.oddfrm = 1; +} + +static inline void usb_dwc_ll_hcchar_set_even_frame(volatile usb_dwc_host_chan_regs_t *chan) +{ + chan->hcchar_reg.oddfrm = 0; +} + +static inline void usb_dwc_ll_hcchar_set_dev_addr(volatile usb_dwc_host_chan_regs_t *chan, uint32_t addr) +{ + chan->hcchar_reg.devaddr = addr; +} + +static inline void usb_dwc_ll_hcchar_set_ep_type(volatile usb_dwc_host_chan_regs_t *chan, usb_dwc_xfer_type_t type) +{ + chan->hcchar_reg.eptype = (uint32_t)type; +} + +//Indicates whether channel is commuunicating with a LS device connected via a FS hub. Setting this bit to 1 will cause +//each packet to be preceded by a PREamble packet +static inline void usb_dwc_ll_hcchar_set_lspddev(volatile usb_dwc_host_chan_regs_t *chan, bool is_ls) +{ + chan->hcchar_reg.lspddev = is_ls; +} + +static inline void usb_dwc_ll_hcchar_set_dir(volatile usb_dwc_host_chan_regs_t *chan, bool is_in) +{ + chan->hcchar_reg.epdir = is_in; +} + +static inline void usb_dwc_ll_hcchar_set_ep_num(volatile usb_dwc_host_chan_regs_t *chan, uint32_t num) +{ + chan->hcchar_reg.epnum = num; +} + +static inline void usb_dwc_ll_hcchar_set_mps(volatile usb_dwc_host_chan_regs_t *chan, uint32_t mps) +{ + chan->hcchar_reg.mps = mps; +} + +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) +{ + //Sets all persistent fields of the channel over its lifetimez + usb_dwc_ll_hcchar_set_dev_addr(chan, dev_addr); + usb_dwc_ll_hcchar_set_ep_type(chan, type); + usb_dwc_ll_hcchar_set_lspddev(chan, is_ls); + usb_dwc_ll_hcchar_set_dir(chan, is_in); + usb_dwc_ll_hcchar_set_ep_num(chan, ep_num); + usb_dwc_ll_hcchar_set_mps(chan, mps); +} + +// ---------------------------- HCINTi Register -------------------------------- + +static inline uint32_t usb_dwc_ll_hcint_read_and_clear_intrs(volatile usb_dwc_host_chan_regs_t *chan) +{ + usb_dwc_hcint_reg_t hcint; + hcint.val = chan->hcint_reg.val; + chan->hcint_reg.val = hcint.val; + return hcint.val; +} + +// --------------------------- HCINTMSKi Register ------------------------------ + +static inline void usb_dwc_ll_hcintmsk_set_intr_mask(volatile usb_dwc_host_chan_regs_t *chan, uint32_t mask) +{ + chan->hcintmsk_reg.val = mask; +} + +// ---------------------------- HCTSIZi Register ------------------------------- + +static inline void usb_dwc_ll_hctsiz_init(volatile usb_dwc_host_chan_regs_t *chan) +{ + usb_dwc_hctsiz_reg_t hctsiz; + hctsiz.val = chan->hctsiz_reg.val; + hctsiz.dopng = 0; // Don't do ping + hctsiz.pid = 0; // Set PID to DATA0 + /* + * Set SCHED_INFO which occupies xfersize[7:0] + * + * Although the hardware documentation suggests that SCHED_INFO is only used for periodic channels, + * empirical evidence shows that omitting this configuration on non-periodic channels can cause them to freeze. + * Therefore, we set this field for all channels to ensure reliable operation. + */ + hctsiz.xfersize |= 0xFF; + chan->hctsiz_reg.val = hctsiz.val; +} + +static inline void usb_dwc_ll_hctsiz_set_pid(volatile usb_dwc_host_chan_regs_t *chan, uint32_t data_pid) +{ + if (data_pid == 0) { + chan->hctsiz_reg.pid = 0; + } else { + chan->hctsiz_reg.pid = 2; + } +} + +static inline uint32_t usb_dwc_ll_hctsiz_get_pid(volatile usb_dwc_host_chan_regs_t *chan) +{ + if (chan->hctsiz_reg.pid == 0) { + return 0; //DATA0 + } else { + return 1; //DATA1 + } +} + +static inline void usb_dwc_ll_hctsiz_set_qtd_list_len(volatile usb_dwc_host_chan_regs_t *chan, int qtd_list_len) +{ + usb_dwc_hctsiz_reg_t hctsiz; + hctsiz.val = chan->hctsiz_reg.val; + //Set the length of the descriptor list. NTD occupies xfersize[15:8] + hctsiz.xfersize &= ~(0xFF << 8); + hctsiz.xfersize |= ((qtd_list_len - 1) & 0xFF) << 8; + chan->hctsiz_reg.val = hctsiz.val; +} + +/** + * @brief Perform PING protocol + * + * @note This function is here only for compatibility reasons. PING is not relevant on FS only targets + * @param[in] chan Channel registers + * @param[in] enable true: Enable PING, false: Disable PING + */ +static inline void usb_dwc_ll_hctsiz_set_dopng(volatile usb_dwc_host_chan_regs_t *chan, bool enable) +{ +} + +/** + * @brief Set scheduling info for Periodic channel + * + * @note ESP32-H4 is Full-Speed only, so SCHED_INFO is always set to 0xFF + * @attention This function must be called for each periodic channel! + * @see USB-OTG databook: Table 5-47 + * + * @param[in] chan Channel registers + * @param[in] tokens_per_frame Ignored + * @param[in] offset Ignored + */ +static inline void usb_dwc_ll_hctsiz_set_sched_info(volatile usb_dwc_host_chan_regs_t *chan, int tokens_per_frame, int offset) +{ + usb_dwc_hctsiz_reg_t hctsiz; + hctsiz.val = chan->hctsiz_reg.val; + hctsiz.xfersize |= 0xFF; + chan->hctsiz_reg.val = hctsiz.val; +} + +// ---------------------------- HCDMAi Register -------------------------------- + +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) +{ + usb_dwc_hcdma_reg_t hcdma; + /* + Set the base address portion of the field which is dmaaddr[31:9]. This is + the based address of the QTD list and must be 512 bytes aligned + */ + hcdma.dmaaddr = ((uint32_t)dmaaddr) & 0xFFFFFE00; + //Set the current QTD index in the QTD list which is dmaaddr[8:3] + hcdma.dmaaddr |= (qtd_idx & 0x3F) << 3; + //dmaaddr[2:0] is reserved thus doesn't not need to be set + + chan->hcdma_reg.val = hcdma.val; +} + +static inline int usb_dwc_ll_hcdam_get_cur_qtd_idx(usb_dwc_host_chan_regs_t *chan) +{ + //The current QTD index is dmaaddr[8:3] + return (chan->hcdma_reg.dmaaddr >> 3) & 0x3F; +} + +// ---------------------------- HCDMABi Register ------------------------------- + +static inline void *usb_dwc_ll_hcdmab_get_buff_addr(volatile usb_dwc_host_chan_regs_t *chan) +{ + return (void *)chan->hcdmab_reg.hcdmab; +} + +/* ----------------------------------------------------------------------------- +---------------------------- Scatter/Gather DMA QTDs --------------------------- +----------------------------------------------------------------------------- */ + +// ---------------------------- Helper Functions ------------------------------- + +/** + * @brief Get the base address of a channel's register based on the channel's index + * + * @param dev Start address of the DWC_OTG registers + * @param chan_idx The channel's index + * @return usb_dwc_host_chan_regs_t* Pointer to channel's registers + */ +static inline usb_dwc_host_chan_regs_t *usb_dwc_ll_chan_get_regs(usb_dwc_dev_t *dev, int chan_idx) +{ + return &dev->host_chans[chan_idx]; +} + +// ------------------------------ QTD related ---------------------------------- + +#define USB_DWC_LL_QTD_STATUS_SUCCESS 0x0 //If QTD was processed, it indicates the data was transmitted/received successfully +#define USB_DWC_LL_QTD_STATUS_PKTERR 0x1 //Data transmitted/received with errors (CRC/Timeout/Stuff/False EOP/Excessive NAK). +//Note: 0x2 is reserved +#define USB_DWC_LL_QTD_STATUS_BUFFER 0x3 //AHB error occurred. +#define USB_DWC_LL_QTD_STATUS_NOT_EXECUTED 0x4 //QTD as never processed + +/** + * @brief Set a QTD for a non isochronous IN transfer + * + * @param qtd Pointer to the QTD + * @param data_buff Pointer to buffer containing the data to transfer + * @param xfer_len Number of bytes in transfer. Setting 0 will do a zero length IN transfer. + * Non zero length must be multiple of the endpoint's MPS. + * @param hoc Halt on complete (will generate an interrupt and halt the channel) + */ +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) +{ + qtd->buffer = data_buff; //Set pointer to data buffer + qtd->buffer_status_val = 0; //Reset all flags to zero + qtd->in_non_iso.xfer_size = xfer_len; + if (hoc) { + qtd->in_non_iso.intr_cplt = 1; //We need to set this to distinguish between a halt due to a QTD + qtd->in_non_iso.eol = 1; //Used to halt the channel at this qtd + } + qtd->in_non_iso.active = 1; +} + +/** + * @brief Set a QTD for a non isochronous OUT transfer + * + * @param qtd Pointer to the QTD + * @param data_buff Pointer to buffer containing the data to transfer + * @param xfer_len Number of bytes to transfer. Setting 0 will do a zero length transfer. + * For ctrl setup packets, this should be set to 8. + * @param hoc Halt on complete (will generate an interrupt) + * @param is_setup Indicates whether this is a control transfer setup packet or a normal OUT Data transfer. + * (As per the USB protocol, setup packets cannot be STALLd or NAKd by the device) + */ +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) +{ + qtd->buffer = data_buff; //Set pointer to data buffer + qtd->buffer_status_val = 0; //Reset all flags to zero + qtd->out_non_iso.xfer_size = xfer_len; + if (is_setup) { + qtd->out_non_iso.is_setup = 1; + } + if (hoc) { + qtd->in_non_iso.intr_cplt = 1; //We need to set this to distinguish between a halt due to a QTD + qtd->in_non_iso.eol = 1; //Used to halt the channel at this qtd + } + qtd->out_non_iso.active = 1; +} + +/** + * @brief Set a QTD as NULL + * + * This sets the QTD to a value of 0. This is only useful when you need to insert + * blank QTDs into a list of QTDs + * + * @param qtd Pointer to the QTD + */ +static inline void usb_dwc_ll_qtd_set_null(usb_dwc_ll_dma_qtd_t *qtd) +{ + qtd->buffer = NULL; + qtd->buffer_status_val = 0; //Disable qtd by clearing it to zero. Used by interrupt/isoc as an unscheudled frame +} + +/** + * @brief Get the status of a QTD + * + * When a channel gets halted, call this to check whether each QTD was executed successfully + * + * @param qtd Pointer to the QTD + * @param[out] rem_len Number of bytes ramining in the QTD + * @param[out] status Status of the QTD + */ +static inline void usb_dwc_ll_qtd_get_status(usb_dwc_ll_dma_qtd_t *qtd, int *rem_len, int *status) +{ + //Status is the same regardless of IN or OUT + if (qtd->in_non_iso.active) { + //QTD was never processed + *status = USB_DWC_LL_QTD_STATUS_NOT_EXECUTED; + } else { + *status = qtd->in_non_iso.rx_status; + } + *rem_len = qtd->in_non_iso.xfer_size; + //Clear the QTD just for safety + qtd->buffer_status_val = 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/esp32h4/include/hal/usb_wrap_ll.h b/components/hal/esp32h4/include/hal/usb_wrap_ll.h new file mode 100644 index 0000000000000..ff4a08c1d50d2 --- /dev/null +++ b/components/hal/esp32h4/include/hal/usb_wrap_ll.h @@ -0,0 +1,236 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_attr.h" +#include "soc/soc.h" +#include "register/soc/pcr_struct.h" +#include "register/soc/usb_wrap_struct.h" +#include "hal/usb_wrap_types.h" + +/* ----------------------------- Macros & Types ----------------------------- */ + +#define USB_WRAP_LL_EXT_PHY_SUPPORTED 0 // Cannot route to an external FSLS PHY + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------------------------- USB PHY Control ---------------------------- */ + +/** + * @brief Sets default + * + * Some register fields and features of the USB WRAP are redundant on the ESP32-H4. + * This function sets those fields to their appropriate default values. + * + * @param hw Start address of the USB Wrap registers + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_set_defaults(usb_wrap_dev_t *hw) +{ + // Always select internal PHY for H4 + hw->wrap_otg_conf.wrap_phy_sel = 0; + hw->wrap_otg_conf.wrap_usb_pad_enable = 1; +} + +/** + * @brief Enables and sets the override value for the session end signal + * + * @param hw Start address of the USB Wrap registers + * @param sessend Session end override value. True means VBus < 0.2V, false means VBus > 0.8V + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_enable_srp_sessend_override(usb_wrap_dev_t *hw, bool sessend) +{ + hw->wrap_otg_conf.wrap_srp_sessend_value = sessend; + hw->wrap_otg_conf.wrap_srp_sessend_override = 1; +} + +/** + * @brief Disable session end override + * + * @param hw Start address of the USB Wrap registers + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_disable_srp_sessend_override(usb_wrap_dev_t *hw) +{ + hw->wrap_otg_conf.wrap_srp_sessend_override = 0; +} + +/** + * @brief Enables/disables exchanging of the D+/D- pins USB PHY + * + * @param hw Start address of the USB Wrap registers + * @param enable Enables pin exchange, disabled otherwise + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_enable_pin_exchg(usb_wrap_dev_t *hw, bool enable) +{ + if (enable) { + hw->wrap_otg_conf.wrap_exchg_pins = 1; + hw->wrap_otg_conf.wrap_exchg_pins_override = 1; + } else { + hw->wrap_otg_conf.wrap_exchg_pins_override = 0; + hw->wrap_otg_conf.wrap_exchg_pins = 0; + } +} + +/** + * @brief Enables and sets voltage threshold overrides for USB FSLS PHY single-ended inputs + * + * @param hw Start address of the USB Wrap registers + * @param vrefh_step High voltage threshold. 0 to 3 indicating 80mV steps from 1.76V to 2V. + * @param vrefl_step Low voltage threshold. 0 to 3 indicating 80mV steps from 0.8V to 1.04V. + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_enable_vref_override(usb_wrap_dev_t *hw, unsigned int vrefh_step, unsigned int vrefl_step) +{ + hw->wrap_otg_conf.wrap_vrefh = vrefh_step; + hw->wrap_otg_conf.wrap_vrefl = vrefl_step; + hw->wrap_otg_conf.wrap_vref_override = 1; +} + +/** + * @brief Disables voltage threshold overrides for USB FSLS PHY single-ended inputs + * + * @param hw Start address of the USB Wrap registers + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_disable_vref_override(usb_wrap_dev_t *hw) +{ + hw->wrap_otg_conf.wrap_vref_override = 0; +} + +/** + * @brief Enable override of USB FSLS PHY's pull up/down resistors + * + * @param hw Start address of the USB Wrap registers + * @param vals Override values to set + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_enable_pull_override(usb_wrap_dev_t *hw, const usb_wrap_pull_override_vals_t *vals) +{ + hw->wrap_otg_conf.wrap_dp_pullup = vals->dp_pu; + hw->wrap_otg_conf.wrap_dp_pulldown = vals->dp_pd; + hw->wrap_otg_conf.wrap_dm_pullup = vals->dm_pu; + hw->wrap_otg_conf.wrap_dm_pulldown = vals->dm_pd; + hw->wrap_otg_conf.wrap_pad_pull_override = 1; +} + +/** + * @brief Disable override of USB FSLS PHY pull up/down resistors + * + * @param hw Start address of the USB Wrap registers + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_disable_pull_override(usb_wrap_dev_t *hw) +{ + hw->wrap_otg_conf.wrap_pad_pull_override = 0; +} + +/** + * @brief Sets the strength of the pullup resistor + * + * @param hw Start address of the USB Wrap registers + * @param strong True is a ~1.4K pullup, false is a ~2.4K pullup + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_set_pullup_strength(usb_wrap_dev_t *hw, bool strong) +{ + hw->wrap_otg_conf.wrap_pullup_value = strong; +} + +/** + * @brief Check if USB FSLS PHY pads are enabled + * + * @param hw Start address of the USB Wrap registers + * @return True if enabled, false otherwise + */ +FORCE_INLINE_ATTR bool usb_wrap_ll_phy_is_pad_enabled(usb_wrap_dev_t *hw) +{ + return hw->wrap_otg_conf.wrap_usb_pad_enable; +} + +/** + * @brief Enable the USB FSLS PHY pads + * + * @param hw Start address of the USB Wrap registers + * @param enable Whether to enable the USB FSLS PHY pads + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_enable_pad(usb_wrap_dev_t *hw, bool enable) +{ + hw->wrap_otg_conf.wrap_usb_pad_enable = enable; +} + +/** + * @brief Set USB FSLS PHY TX output clock edge + * + * @param hw Start address of the USB Wrap registers + * @param clk_neg_edge True if TX output at negedge, posedge otherwise + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_set_tx_edge(usb_wrap_dev_t *hw, bool clk_neg_edge) +{ + // Not supported on ESP32-H4: no wrap_phy_tx_edge_sel field + (void)hw; + (void)clk_neg_edge; +} + +/* ------------------------------ USB PHY Test ------------------------------ */ + +/** + * @brief Enable the USB FSLS PHY's test mode + * + * @param hw Start address of the USB Wrap registers + * @param enable Whether to enable the USB FSLS PHY's test mode + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_enable_test_mode(usb_wrap_dev_t *hw, bool enable) +{ + /* Not supported on H4: test_conf not present in usb_wrap_dev_t */ + (void)hw; (void)enable; // Corrected to indicate test_conf is not present +} + +/** + * @brief Set the USB FSLS PHY's signal test values + * + * @param hw Start address of the USB Wrap registers + * @param vals Test values to set + */ +FORCE_INLINE_ATTR void usb_wrap_ll_phy_test_mode_set_signals(usb_wrap_dev_t *hw, const usb_wrap_test_mode_vals_t *vals) +{ + /* Not supported on H4: test_conf not present in usb_wrap_dev_t */ + (void)hw; (void)vals; // Corrected to indicate test_conf is not present +} + +/* ----------------------------- RCC Functions ----------------------------- */ + +/** + * Enable the bus clock for USB Wrap module + * @param clk_en True if enable the clock of USB Wrap module + */ +FORCE_INLINE_ATTR void _usb_wrap_ll_enable_bus_clock(bool clk_en) +{ + PCR.usb_device_conf.usb_device_clk_en = clk_en; +} + +// SYSTEM.perip_clk_enx are shared registers, so this function must be used in an atomic way +#define usb_wrap_ll_enable_bus_clock(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + _usb_wrap_ll_enable_bus_clock(__VA_ARGS__); \ + } while(0) + +/** + * @brief Reset the USB Wrap module + */ +FORCE_INLINE_ATTR void _usb_wrap_ll_reset_register(void) +{ + PCR.usb_device_conf.usb_device_rst_en = 1; + PCR.usb_device_conf.usb_device_rst_en = 0; +} + +// SYSTEM.perip_rst_enx are shared registers, so this function must be used in an atomic way +#define usb_wrap_ll_reset_register(...) do { \ + (void)__DECLARE_RCC_ATOMIC_ENV; \ + _usb_wrap_ll_reset_register(__VA_ARGS__); \ + } while(0) + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index f47b135f97731..d794a9aa9bbcc 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -35,6 +35,10 @@ config SOC_ASYNC_MEMCPY_SUPPORTED bool default y +config SOC_USB_OTG_SUPPORTED + bool + default y + config SOC_USB_SERIAL_JTAG_SUPPORTED bool default y @@ -986,3 +990,7 @@ config SOC_CLK_LP_FAST_SUPPORT_XTAL_D2 config SOC_RCC_IS_INDEPENDENT bool default y + +config SOC_USB_OTG_PERIPH_NUM + int + default 1 diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index 919b28176a1b8..c115e39dad737 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -46,6 +46,7 @@ // #define SOC_BT_SUPPORTED 1 // #define SOC_IEEE802154_SUPPORTED 1 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 +#define SOC_USB_OTG_SUPPORTED 1 #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 // #define SOC_TEMP_SENSOR_SUPPORTED 1 // TODO: [ESP32H4] IDF-12404 // #define SOC_SUPPORTS_SECURE_DL_MODE 1 @@ -555,3 +556,6 @@ // #define SOC_BLE_PERIODIC_ADV_ENH_SUPPORTED (1) /*!< Support For BLE Periodic Adv Enhancements */ // #define SOC_BLUFI_SUPPORTED (1) /*!< Support BLUFI */ // #define SOC_BLE_MULTI_CONN_OPTIMIZATION (1) /*!< Support multiple connections optimization */ + +/*-------------------------- USB CAPS ----------------------------------------*/ +#define SOC_USB_OTG_PERIPH_NUM (1U) diff --git a/components/soc/esp32h4/include/soc/usb_dwc_cfg.h b/components/soc/esp32h4/include/soc/usb_dwc_cfg.h new file mode 100644 index 0000000000000..5dad643afcf69 --- /dev/null +++ b/components/soc/esp32h4/include/soc/usb_dwc_cfg.h @@ -0,0 +1,89 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* +Configuration Set ID: 1 +*/ + +/* 3.1 Basic Config Parameters */ +#define OTG_MODE 0 +#define OTG_ARCHITECTURE 2 +#define OTG_SINGLE_POINT 1 +#define OTG_ENABLE_LPM 0 +#define OTG_EN_DED_TX_FIFO 1 +#define OTG_EN_DESC_DMA 1 +#define OTG_MULTI_PROC_INTRPT 0 + +/* 3.2 USB Physical Layer Interface Parameters */ +#define OTG_HSPHY_INTERFACE 0 +#define OTG_FSPHY_INTERFACE 1 +#define OTG_ENABLE_IC_USB 0 +#define OTG_I2C_INTERFACE 0 +#define OTG_ADP_SUPPORT 0 +#define OTG_BC_SUPPORT 0 + +/* 3.3 Device Endpoint Configuration Parameters */ +#define OTG_NUM_EPS 6 +#define OTG_NUM_IN_EPS 5 +#define OTG_NUM_CRL_EPS 0 + +/* 3.4 Host Endpoint Configuration Parameters */ +#define OTG_NUM_HOST_CHAN 8 +#define OTG_EN_PERIO_HOST 1 + +/* 3.5 Endpoint Channel FIFO Configuration Parameters */ +#define OTG_DFIFO_DEPTH 256 +#define OTG_DFIFO_DYNAMIC 1 +#define OTG_RX_DFIFO_DEPTH 256 +#define OTG_TX_HNPERIO_DFIFO_DEPTH 256 +#define OTG_TX_NPERIO_DFIFO_DEPTH 256 +#define OTG_TX_HPERIO_DFIFO_DEPTH 256 +#define OTG_NPERIO_TX_QUEUE_DEPTH 4 +#define OTG_PERIO_TX_QUEUE_DEPTH 8 + +/* 3.6 Additional Configuration Options Parameters */ +#define OTG_TRANS_COUNT_WIDTH 16 +#define OTG_PACKET_COUNT_WIDTH 7 +#define OTG_RM_OPT_FEATURES 1 +#define OTG_EN_PWROPT 1 +#define OTG_SYNC_RESET_TYPE 0 +#define OTG_EN_IDDIG_FILTER 1 +#define OTG_EN_VBUSVALID_FILTER 1 +#define OTG_EN_A_VALID_FILTER 1 +#define OTG_EN_B_VALID_FILTER 1 +#define OTG_EN_SESSIONEND_FILTER 1 +#define OTG_EXCP_CNTL_XFER_FLOW 1 +#define OTG_PWR_CLAMP 0 +#define OTG_PWR_SWITCH_POLARITY 0 + +/* 3.7 Endpoint Direction Parameters */ +#define OTG_EP_DIR_1 0 +#define OTG_EP_DIR_2 0 +#define OTG_EP_DIR_3 0 +#define OTG_EP_DIR_4 0 +#define OTG_EP_DIR_5 0 +#define OTG_EP_DIR_6 0 + +/* 3.8 Device Periodic FIFO Depth Parameters */ + +/* 3.9 Device IN Endpoint FIFO Depth Parameters */ +#define OTG_TX_DINEP_DFIFO_DEPTH_1 256 +#define OTG_TX_DINEP_DFIFO_DEPTH_2 256 +#define OTG_TX_DINEP_DFIFO_DEPTH_3 256 +#define OTG_TX_DINEP_DFIFO_DEPTH_4 256 + +/* 3.10 UTMI-To-UTMI Bridge Component Parameters */ +#define U2UB_EN 0 + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h4/include/soc/usb_dwc_struct.h b/components/soc/esp32h4/include/soc/usb_dwc_struct.h new file mode 100644 index 0000000000000..aa39e9ce293e1 --- /dev/null +++ b/components/soc/esp32h4/include/soc/usb_dwc_struct.h @@ -0,0 +1,1173 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Registers and fields were generated based on a set of configuration options. +// See the ESP32-H4 "usb_dwc_cfg.h" for more details. + +// ---------------------------- Register Types ------------------------------ + +typedef union { + struct { + uint32_t sesreqscs: 1; + uint32_t sesreq: 1; + uint32_t vbvalidoven: 1; + uint32_t vbvalidovval: 1; + uint32_t avalidoven: 1; + uint32_t avalidovval: 1; + uint32_t bvalidoven: 1; + uint32_t bvalidovval: 1; + uint32_t hstnegscs: 1; + uint32_t hnpreq: 1; + uint32_t hstsethnpen: 1; + uint32_t devhnpen: 1; + uint32_t ehen: 1; // codespell:ignore ehen + uint32_t reserved_13: 2; + uint32_t dbncefltrbypass: 1; + uint32_t conidsts: 1; + uint32_t dbnctime: 1; + uint32_t asesvld: 1; + uint32_t bsesvld: 1; + uint32_t otgver: 1; + uint32_t curmod: 1; + uint32_t reserved_22: 5; + uint32_t reserved_27: 1; + uint32_t reserved_28: 4; + }; + uint32_t val; +} usb_dwc_gotgctl_reg_t; + +// ---- All DWC register typedef unions from S3 ---- +typedef union { + struct { + uint32_t reserved_0: 2; + uint32_t sesenddet: 1; + uint32_t reserved_3: 5; + uint32_t sesreqsucstschng: 1; + uint32_t hstnegsucstschng: 1; + uint32_t reserved_10: 7; + uint32_t hstnegdet: 1; + uint32_t adevtoutchg: 1; + uint32_t dbncedone: 1; + uint32_t reserved_20: 1; + uint32_t reserved_21: 11; + }; + uint32_t val; +} usb_dwc_gotgint_reg_t; + +typedef union { + struct { + uint32_t glbllntrmsk: 1; + uint32_t hbstlen: 4; + uint32_t dmaen: 1; + uint32_t reserved_6: 1; + uint32_t nptxfemplvl: 1; + uint32_t ptxfemplvl: 1; + uint32_t reserved_9: 12; + uint32_t remmemsupp: 1; + uint32_t notialldmawrit: 1; + uint32_t ahbsingle: 1; + uint32_t invdescendianess: 1; + uint32_t reserved_25: 7; + }; + uint32_t val; +} usb_dwc_gahbcfg_reg_t; + +typedef union { + struct { + uint32_t toutcal: 3; + uint32_t phyif: 1; + uint32_t ulpiutmisel: 1; + uint32_t fsintf: 1; + uint32_t physel: 1; + uint32_t reserved_7: 1; + uint32_t srpcap: 1; + uint32_t hnpcap: 1; + uint32_t usbtrdtim: 4; + uint32_t reserved_14: 1; + uint32_t phylpwrclksel: 1; + uint32_t reserved_16: 1; + uint32_t reserved_17: 1; + uint32_t reserved_18: 1; + uint32_t reserved_19: 1; + uint32_t reserved_20: 1; + uint32_t reserved_21: 1; + uint32_t termseldlpulse: 1; + uint32_t reserved_23: 1; + uint32_t reserved_24: 1; + uint32_t reserved_25: 1; + uint32_t icusbcap: 1; + uint32_t reserved_27: 1; + uint32_t txenddelay: 1; + uint32_t forcehstmode: 1; + uint32_t forcedevmode: 1; + uint32_t corrupttxpkt: 1; + }; + uint32_t val; +} usb_dwc_gusbcfg_reg_t; + +typedef union { + struct { + uint32_t csftrst: 1; + uint32_t piufssftrst: 1; + uint32_t frmcntrrst: 1; + uint32_t reserved_3: 1; + uint32_t rxfflsh: 1; + uint32_t txfflsh: 1; + uint32_t txfnum: 5; + uint32_t reserved_11: 19; + uint32_t dmareq: 1; + uint32_t ahbidle: 1; + }; + uint32_t val; +} usb_dwc_grstctl_reg_t; + +typedef union { + struct { + uint32_t curmod: 1; + uint32_t modemis: 1; + uint32_t otgint: 1; + uint32_t sof: 1; + uint32_t rxflvl: 1; + uint32_t nptxfemp: 1; + uint32_t ginnakeff: 1; + uint32_t goutnakeff: 1; + uint32_t reserved_8: 1; + uint32_t reserved_9: 1; + uint32_t erlysusp: 1; + uint32_t usbsusp: 1; + uint32_t usbrst: 1; + uint32_t enumdone: 1; + uint32_t isooutdrop: 1; + uint32_t eopf: 1; + uint32_t reserved_16: 1; + uint32_t epmis: 1; + uint32_t iepint: 1; + uint32_t oepint: 1; + uint32_t incompisoin: 1; + uint32_t incompip: 1; + uint32_t fetsusp: 1; + uint32_t resetdet: 1; + uint32_t prtint: 1; + uint32_t hchint: 1; + uint32_t ptxfemp: 1; + uint32_t reserved_27: 1; + uint32_t conidstschng: 1; + uint32_t disconnint: 1; + uint32_t sessreqint: 1; + uint32_t wkupint: 1; + }; + uint32_t val; +} usb_dwc_gintsts_reg_t; + +typedef union { + struct { + uint32_t reserved_0: 1; + uint32_t modemismsk: 1; + uint32_t otgintmsk: 1; + uint32_t sofmsk: 1; + uint32_t rxflvlmsk: 1; + uint32_t nptxfempmsk: 1; + uint32_t ginnakeffmsk: 1; + uint32_t goutnackeffmsk: 1; + uint32_t reserved_8: 1; + uint32_t reserved_9: 1; + uint32_t erlysuspmsk: 1; + uint32_t usbsuspmsk: 1; + uint32_t usbrstmsk: 1; + uint32_t enumdonemsk: 1; + uint32_t isooutdropmsk: 1; + uint32_t eopfmsk: 1; + uint32_t reserved_16: 1; + uint32_t epmismsk: 1; + uint32_t iepintmsk: 1; + uint32_t oepintmsk: 1; + uint32_t incompisoinmsk: 1; + uint32_t incompipmsk: 1; + uint32_t fetsuspmsk: 1; + uint32_t resetdetmsk: 1; + uint32_t prtintmsk: 1; + uint32_t hchintmsk: 1; + uint32_t ptxfempmsk: 1; + uint32_t reserved_27: 1; + uint32_t conidstschngmsk: 1; + uint32_t disconnintmsk: 1; + uint32_t sessreqintmsk: 1; + uint32_t wkupintmsk: 1; + }; + uint32_t val; +} usb_dwc_gintmsk_reg_t; + +typedef union { + struct { + uint32_t chnum: 4; + uint32_t bcnt: 11; + uint32_t dpid: 2; + uint32_t pktsts: 4; + uint32_t fn: 4; + uint32_t reserved_25: 6; + uint32_t reserved_31: 1; + }; + uint32_t val; +} usb_dwc_grxstsr_reg_t; + +typedef union { + struct { + uint32_t chnum: 4; + uint32_t bcnt: 11; + uint32_t dpid: 2; + uint32_t pktsts: 4; + uint32_t fn: 4; + uint32_t reserved_25: 6; + uint32_t reserved_31: 1; + }; + uint32_t val; +} usb_dwc_grxstsp_reg_t; + +typedef union { + struct { + uint32_t rxfdep: 16; + uint32_t reserved_16: 16; + }; + uint32_t val; +} usb_dwc_grxfsiz_reg_t; + +typedef union { + struct { + uint32_t nptxfstaddr: 16; + uint32_t nptxfdep: 16; + }; + uint32_t val; +} usb_dwc_gnptxfsiz_reg_t; + +typedef union { + struct { + uint32_t nptxfspcavail: 16; + uint32_t nptxqspcavail: 8; + uint32_t nptxqtop: 7; + uint32_t reserved_31: 1; + }; + uint32_t val; +} usb_dwc_gnptxsts_reg_t; + +typedef union { + struct { + uint32_t synopsysid; + }; + uint32_t val; +} usb_dwc_gsnpsid_reg_t; + +typedef union { + struct { + uint32_t epdir; + }; + uint32_t val; +} usb_dwc_ghwcfg1_reg_t; + +typedef union { + struct { + uint32_t otgmode: 3; + uint32_t otgarch: 2; + uint32_t singpnt: 1; + uint32_t hsphytype: 2; + uint32_t fsphytype: 2; + uint32_t numdeveps: 4; + uint32_t numhstchnl: 4; + uint32_t periosupport: 1; + uint32_t dynfifosizing: 1; + uint32_t multiprocintrpt: 1; + uint32_t reserved_21: 1; + uint32_t nptxqdepth: 2; + uint32_t ptxqdepth: 2; + uint32_t tknqdepth: 5; + uint32_t reserved_31: 1; + }; + uint32_t val; +} usb_dwc_ghwcfg2_reg_t; + +typedef union { + struct { + uint32_t xfersizewidth: 4; + uint32_t pktsizewidth: 3; + uint32_t otgen: 1; + uint32_t i2cintsel: 1; + uint32_t vndctlsupt: 1; + uint32_t optfeature: 1; + uint32_t rsttype: 1; + uint32_t adpsupport: 1; + uint32_t hsicmode: 1; + uint32_t bcsupport: 1; + uint32_t lpmmode: 1; + uint32_t dfifodepth: 16; + }; + uint32_t val; +} usb_dwc_ghwcfg3_reg_t; + +typedef union { + struct { + uint32_t numdevperioeps: 4; + uint32_t partialpwrdn: 1; + uint32_t ahbfreq: 1; + uint32_t hibernation: 1; + uint32_t extendedhibernation: 1; + uint32_t reserved_8: 4; + uint32_t acgsupt: 1; + uint32_t enhancedlpmsupt: 1; + uint32_t phydatawidth: 2; + uint32_t numctleps: 4; + uint32_t iddqfltr: 1; + uint32_t vbusvalidfltr: 1; + uint32_t avalidfltr: 1; + uint32_t bvalidfltr: 1; + uint32_t sessendfltr: 1; + uint32_t dedfifomode: 1; + uint32_t ineps: 4; + uint32_t descdmaenabled: 1; + uint32_t descdma: 1; + }; + uint32_t val; +} usb_dwc_ghwcfg4_reg_t; + +typedef union { + struct { + uint32_t gdfifocfg: 16; + uint32_t epinfobaseaddr: 16; + }; + uint32_t val; +} usb_dwc_gdfifocfg_reg_t; + +typedef union { + struct { + uint32_t ptxfstaddr: 16; + uint32_t ptxfsize: 16; + }; + uint32_t val; +} usb_dwc_hptxfsiz_reg_t; + +typedef union { + struct { + uint32_t inepntxfstaddr: 16; + uint32_t inepntxfdep: 16; + }; + uint32_t val; +} usb_dwc_dieptxfi_reg_t; + +typedef union { + struct { + uint32_t fslspclksel: 2; + uint32_t fslssupp: 1; + uint32_t reserved_3: 4; + uint32_t ena32khzs: 1; + uint32_t resvalid: 8; + uint32_t reserved_16: 1; + uint32_t reserved_17: 6; + uint32_t descdma: 1; + uint32_t frlisten: 2; + uint32_t perschedena: 1; + uint32_t reserved_27: 4; + uint32_t modechtimen: 1; + }; + uint32_t val; +} usb_dwc_hcfg_reg_t; + +typedef union { + struct { + uint32_t frint: 16; + uint32_t hfirrldctrl: 1; + uint32_t reserved_17: 15; + }; + uint32_t val; +} usb_dwc_hfir_reg_t; + +typedef union { + struct { + uint32_t frnum: 16; + uint32_t frrem: 16; + }; + uint32_t val; +} usb_dwc_hfnum_reg_t; + +typedef union { + struct { + uint32_t ptxfspcavail: 16; + uint32_t ptxqspcavail: 8; + uint32_t ptxqtop: 8; + }; + uint32_t val; +} usb_dwc_hptxsts_reg_t; + +typedef union { + struct { + uint32_t haint: 8; + uint32_t reserved_8: 24; + }; + uint32_t val; +} usb_dwc_haint_reg_t; + +typedef union { + struct { + uint32_t haintmsk: 8; + uint32_t reserved_8: 24; + }; + uint32_t val; +} usb_dwc_haintmsk_reg_t; + +typedef union { + struct { + uint32_t hflbaddr; + }; + uint32_t val; +} usb_dwc_hflbaddr_reg_t; + +typedef union { + struct { + uint32_t prtconnsts: 1; + uint32_t prtconndet: 1; + uint32_t prtena: 1; + uint32_t prtenchng: 1; + uint32_t prtovrcurract: 1; + uint32_t prtovrcurrchng: 1; + uint32_t prtres: 1; + uint32_t prtsusp: 1; + uint32_t prtrst: 1; + uint32_t reserved_9: 1; + uint32_t prtlnsts: 2; + uint32_t prtpwr: 1; + uint32_t prttstctl: 4; + uint32_t prtspd: 2; + uint32_t reserved_19: 13; + }; + uint32_t val; +} usb_dwc_hprt_reg_t; + +typedef union { + struct { + uint32_t mps: 11; + uint32_t epnum: 4; + uint32_t epdir: 1; + uint32_t reserved_16: 1; + uint32_t lspddev: 1; + uint32_t eptype: 2; + uint32_t ec: 2; + uint32_t devaddr: 7; + uint32_t oddfrm: 1; + uint32_t chdis: 1; + uint32_t chena: 1; + }; + uint32_t val; +} usb_dwc_hcchar_reg_t; + +typedef union { + struct { + uint32_t xfercompl: 1; + uint32_t chhltd: 1; + uint32_t ahberr: 1; + uint32_t stall: 1; + uint32_t nack: 1; + uint32_t ack: 1; + uint32_t nyet: 1; + uint32_t xacterr: 1; + uint32_t bblerr: 1; + uint32_t frmovrun: 1; + uint32_t datatglerr: 1; + uint32_t bnaintr: 1; + uint32_t xcs_xact_err: 1; + uint32_t desc_lst_rollintr: 1; + uint32_t reserved_14: 18; + }; + uint32_t val; +} usb_dwc_hcint_reg_t; + +typedef union { + struct { + uint32_t xfercomplmsk: 1; + uint32_t chhltdmsk: 1; + uint32_t ahberrmsk: 1; + uint32_t reserved_3: 1; + uint32_t reserved_4: 1; + uint32_t reserved_5: 1; + uint32_t reserved_6: 1; + uint32_t reserved_7: 1; + uint32_t reserved_8: 1; + uint32_t reserved_9: 1; + uint32_t reserved_10: 1; + uint32_t bnaintrmsk: 1; + uint32_t reserved_12: 1; + uint32_t desc_lst_rollintrmsk: 1; + uint32_t reserved_14: 18; + }; + uint32_t val; +} usb_dwc_hcintmsk_reg_t; + +typedef union { + struct { + uint32_t xfersize: 19; + uint32_t pktcnt: 10; + uint32_t pid: 2; + uint32_t dopng: 1; + }; + uint32_t val; +} usb_dwc_hctsiz_reg_t; + +typedef union { + struct { + uint32_t dmaaddr; + }; + uint32_t val; +} usb_dwc_hcdma_reg_t; + +typedef union { + struct { + uint32_t hcdmab; + }; + uint32_t val; +} usb_dwc_hcdmab_reg_t; + +typedef union { + struct { + uint32_t devspd: 2; + uint32_t nzstsouthshk: 1; + uint32_t ena32khzsusp: 1; + uint32_t devaddr: 7; + uint32_t perfrint: 2; + uint32_t endevoutnak: 1; + uint32_t xcvrdly: 1; + uint32_t erraticintmsk: 1; + uint32_t reserved_16: 2; + uint32_t reserved_18: 5; + uint32_t descdma: 1; + uint32_t perschintvl: 2; + uint32_t resvalid: 6; + }; + uint32_t val; +} usb_dwc_dcfg_reg_t; + +typedef union { + struct { + uint32_t rmtwkupsig: 1; + uint32_t sftdiscon: 1; + uint32_t gnpinnaksts: 1; + uint32_t goutnaksts: 1; + uint32_t tstctl: 3; + uint32_t sgnpinnak: 1; + uint32_t cgnpinnak: 1; + uint32_t sgoutnak: 1; + uint32_t cgoutnak: 1; + uint32_t pwronprgdone: 1; + uint32_t reserved_12: 1; + uint32_t gmc: 2; + uint32_t ignrfrmnum: 1; + uint32_t nakonbble: 1; + uint32_t encontonbna: 1; + uint32_t reserved_18: 1; + uint32_t reserved_19: 13; + }; + uint32_t val; +} usb_dwc_dctl_reg_t; + +typedef union { + struct { + uint32_t suspsts: 1; + uint32_t enumspd: 2; + uint32_t errticerr: 1; + uint32_t reserved_4: 4; + uint32_t soffn: 14; + uint32_t devlnsts: 2; + uint32_t reserved_24: 8; + }; + uint32_t val; +} usb_dwc_dsts_reg_t; + +typedef union { + struct { + uint32_t xfercomplmsk: 1; + uint32_t epdisbldmsk: 1; + uint32_t ahberrmsk: 1; + uint32_t timeoutmsk: 1; + uint32_t intkntxfempmsk: 1; + uint32_t intknepmismsk: 1; + uint32_t inepnakeffmsk: 1; + uint32_t reserved_7: 1; + uint32_t txfifoundrnmsk: 1; + uint32_t bnainintrmsk: 1; + uint32_t reserved_10: 3; + uint32_t nakmsk: 1; + uint32_t reserved_14: 18; + }; + uint32_t val; +} usb_dwc_diepmsk_reg_t; + +typedef union { + struct { + uint32_t xfercomplmsk: 1; + uint32_t epdisbldmsk: 1; + uint32_t ahberrmsk: 1; + uint32_t setupmsk: 1; + uint32_t outtknepdismsk: 1; + uint32_t stsphsercvdmsk: 1; + uint32_t back2backsetup: 1; + uint32_t reserved_7: 1; + uint32_t outpkterrmsk: 1; + uint32_t bnaoutintrmsk: 1; + uint32_t reserved_10: 2; + uint32_t bbleerrmsk: 1; + uint32_t nakmsk: 1; + uint32_t nyetmsk: 1; + uint32_t reserved_15: 17; + }; + uint32_t val; +} usb_dwc_doepmsk_reg_t; + +typedef union { + struct { + uint32_t inepint0: 1; + uint32_t inepint1: 1; + uint32_t inepint2: 1; + uint32_t inepint3: 1; + uint32_t inepint4: 1; + uint32_t inepint5: 1; + uint32_t inepint6: 1; + uint32_t reserved_7: 9; + uint32_t outepint0: 1; + uint32_t outepint1: 1; + uint32_t outepint2: 1; + uint32_t outepint3: 1; + uint32_t outepint4: 1; + uint32_t outepint5: 1; + uint32_t outepint6: 1; + uint32_t reserved_24: 9; + }; + uint32_t val; +} usb_dwc_daint_reg_t; + +typedef union { + struct { + uint32_t inepmsk0: 1; + uint32_t inepmsk1: 1; + uint32_t inepmsk2: 1; + uint32_t inepmsk3: 1; + uint32_t inepmsk4: 1; + uint32_t inepmsk5: 1; + uint32_t inepmsk6: 1; + uint32_t reserved_7: 9; + uint32_t outepmsk0: 1; + uint32_t outepmsk1: 1; + uint32_t outepmsk2: 1; + uint32_t outepmsk3: 1; + uint32_t outepmsk4: 1; + uint32_t outepmsk5: 1; + uint32_t outepmsk6: 1; + uint32_t reserved_24: 9; + }; + uint32_t val; +} usb_dwc_daintmsk_reg_t; + +typedef union { + struct { + uint32_t dvbusdis: 16; + uint32_t reserved_16: 16; + }; + uint32_t val; +} usb_dwc_dvbusdis_reg_t; + +typedef union { + struct { + uint32_t dvbuspulse: 12; + uint32_t reserved_12: 20; + }; + uint32_t val; +} usb_dwc_dvbuspulse_reg_t; + +typedef union { + struct { + uint32_t nonisothren: 1; + uint32_t isothren: 1; + uint32_t txthrlen: 9; + uint32_t ahbthrratio: 2; + uint32_t reserved_13: 3; + uint32_t rxthren: 1; + uint32_t rxthrlen: 9; + uint32_t reserved_26: 1; + uint32_t arbprken: 1; + uint32_t reserved_28: 4; + }; + uint32_t val; +} usb_dwc_dthrctl_reg_t; + +typedef union { + struct { + uint32_t ineptxfempmsk: 16; + uint32_t reserved_16: 16; + }; + uint32_t val; +} usb_dwc_diepempmsk_reg_t; + +typedef union { + struct { + uint32_t mps: 2; + uint32_t reserved_2: 9; + uint32_t reserved_11: 4; + uint32_t usbactep: 1; + uint32_t reserved_16: 1; + uint32_t naksts: 1; + uint32_t eptype: 2; + uint32_t reserved_20: 1; + uint32_t stall: 1; + uint32_t txfnum: 4; + uint32_t cnak: 1; + uint32_t snak: 1; + uint32_t reserved_28: 2; + uint32_t epdis: 1; + uint32_t epena: 1; + }; + uint32_t val; +} usb_dwc_diepctl0_reg_t; + +typedef union { + struct { + uint32_t xfercompl: 1; + uint32_t epdisbld: 1; + uint32_t ahberr: 1; + uint32_t timeout: 1; + uint32_t intkntxfemp: 1; + uint32_t intknepmis: 1; + uint32_t inepnakeff: 1; + uint32_t txfemp: 1; + uint32_t txfifoundrn: 1; + uint32_t bnaintr: 1; + uint32_t reserved_10: 1; + uint32_t pktdrpsts: 1; + uint32_t bbleerr: 1; + uint32_t nakintrpt: 1; + uint32_t nyetintrpt: 1; + uint32_t reserved_15: 17; + }; + uint32_t val; +} usb_dwc_diepint0_reg_t; + +typedef union { + struct { + uint32_t xfersize: 7; + uint32_t reserved_7: 12; + uint32_t pktcnt: 2; + uint32_t reserved_21: 11; + }; + uint32_t val; +} usb_dwc_dieptsiz0_reg_t; + +typedef union { + struct { + uint32_t dmaaddr; + }; + uint32_t val; +} usb_dwc_diepdma0_reg_t; + +typedef union { + struct { + uint32_t ineptxfspcavail: 16; + uint32_t reserved_16: 16; + }; + uint32_t val; +} usb_dwc_dtxfsts0_reg_t; + +typedef union { + struct { + uint32_t dmabufferaddr; + }; + uint32_t val; +} usb_dwc_diepdmab0_reg_t; + +typedef union { + struct { + uint32_t mps: 11; + uint32_t reserved_11: 4; + uint32_t usbactep: 1; + uint32_t dpid: 1; + uint32_t naksts: 1; + uint32_t eptype: 2; + uint32_t reserved_20: 1; + uint32_t stall: 1; + uint32_t txfnum: 4; + uint32_t cnak: 1; + uint32_t snak: 1; + uint32_t setd0pid: 1; + uint32_t setd1pid: 1; + uint32_t epdis: 1; + uint32_t epena: 1; + }; + uint32_t val; +} usb_dwc_diepctl_reg_t; + +typedef union { + struct { + uint32_t xfercompl: 1; + uint32_t epdisbld: 1; + uint32_t ahberr: 1; + uint32_t timeout: 1; + uint32_t intkntxfemp: 1; + uint32_t intknepmis: 1; + uint32_t inepnakeff: 1; + uint32_t txfemp: 1; + uint32_t txfifoundrn: 1; + uint32_t bnaintr: 1; + uint32_t reserved_10: 1; + uint32_t pktdrpsts: 1; + uint32_t bbleerr: 1; + uint32_t nakintrpt: 1; + uint32_t nyetintrpt: 1; + uint32_t reserved_15: 17; + }; + uint32_t val; +} usb_dwc_diepint_reg_t; + +typedef union { + struct { + uint32_t xfersize: 19; + uint32_t pktcnt: 10; + uint32_t mc: 2; + uint32_t reserved: 1; + }; + uint32_t val; +} usb_dwc_dieptsiz_reg_t; + +typedef union { + struct { + uint32_t dmaddr; + }; + uint32_t val; +} usb_dwc_diepdma_reg_t; + +typedef union { + struct { + uint32_t ineptxfspcavail: 16; + uint32_t reserved_16: 16; + }; + uint32_t val; +} usb_dwc_dtxfsts_reg_t; + +typedef union { + struct { + uint32_t dmabufferaddr; + }; + uint32_t val; +} usb_dwc_diepdmab_reg_t; + +typedef union { + struct { + uint32_t mps: 2; + uint32_t reserved_2: 13; + uint32_t usbactep: 1; + uint32_t reserved_16: 1; + uint32_t naksts: 1; + uint32_t eptype: 2; + uint32_t snp: 1; + uint32_t stall: 1; + uint32_t reserved_22: 4; + uint32_t cnak: 1; + uint32_t snak: 1; + uint32_t reserved_28: 2; + uint32_t epdis: 1; + uint32_t epena: 1; + }; + uint32_t val; +} usb_dwc_doepctl0_reg_t; + +typedef union { + struct { + uint32_t xfercompl: 1; + uint32_t epdisbld: 1; + uint32_t ahberr: 1; + uint32_t setup: 1; + uint32_t outtknepdis: 1; + uint32_t stsphsercvd: 1; + uint32_t back2backsetup: 1; + uint32_t reserved_7: 1; + uint32_t outpkterr: 1; + uint32_t bnaintr: 1; + uint32_t reserved_10: 1; + uint32_t pktdrpsts: 1; + uint32_t bbleerr: 1; + uint32_t nakintrpt: 1; + uint32_t nyepintrpt: 1; + uint32_t stuppktrcvd: 1; + uint32_t reserved_16: 16; + }; + uint32_t val; +} usb_dwc_doepint0_reg_t; + +typedef union { + struct { + uint32_t xfersize: 7; + uint32_t reserved_7: 12; + uint32_t pktcnt: 1; + uint32_t reserved_20: 9; + uint32_t supcnt: 2; + uint32_t reserved_31: 1; + }; + uint32_t val; +} usb_dwc_doeptsiz0_reg_t; + +typedef union { + struct { + uint32_t dmaaddr; + }; + uint32_t val; +} usb_dwc_doepdma0_reg_t; + +typedef union { + struct { + uint32_t dmabufferaddr; + }; + uint32_t val; +} usb_dwc_doepdmab0_reg_t; + +typedef union { + struct { + uint32_t mps: 11; + uint32_t reserved_11: 4; + uint32_t usbactep: 1; + uint32_t dpid: 1; + uint32_t naksts: 1; + uint32_t eptype: 2; + uint32_t snp: 1; + uint32_t stall: 1; + uint32_t reserved_22: 4; + uint32_t cnak: 1; + uint32_t snak: 1; + uint32_t setd0pid: 1; + uint32_t setd1pid: 1; + uint32_t epdis: 1; + uint32_t epena: 1; + }; + uint32_t val; +} usb_dwc_doepctl_reg_t; + +typedef union { + struct { + uint32_t xfercompl: 1; + uint32_t epdisbld: 1; + uint32_t ahberr: 1; + uint32_t setup: 1; + uint32_t outtknepdis: 1; + uint32_t stsphsercvd: 1; + uint32_t back2backsetup: 1; + uint32_t reserved_7: 1; + uint32_t outpkterr: 1; + uint32_t bnaintr: 1; + uint32_t reserved_10: 1; + uint32_t pktdrpsts: 1; + uint32_t bbleerr: 1; + uint32_t nakintrpt: 1; + uint32_t nyetintrpt: 1; + uint32_t stuppktrcvd: 1; + uint32_t reserved_16: 16; + }; + uint32_t val; +} usb_dwc_doepint_reg_t; + +typedef union { + struct { + uint32_t xfersize: 19; + uint32_t pktcnt: 10; + uint32_t rxdpid: 2; + uint32_t reserved_31: 1; + }; + uint32_t val; +} usb_dwc_doeptsiz_reg_t; + +typedef union { + struct { + uint32_t dmaaddr; + }; + uint32_t val; +} usb_dwc_doepdma_reg_t; + +typedef union { + struct { + uint32_t dmabufferaddr; + }; + uint32_t val; +} usb_dwc_doepdmab_reg_t; + +typedef union { + struct { + uint32_t stoppclk: 1; + uint32_t gatehclk: 1; + uint32_t pwrclmp: 1; + uint32_t rstpdwnmodule: 1; + uint32_t reserved_4: 1; + uint32_t reserved_5: 1; + uint32_t physleep: 1; + uint32_t l1suspended: 1; + uint32_t resetaftersusp: 1; + uint32_t reserved_9: 1; + uint32_t reserved_10: 1; + uint32_t reserved_11: 1; + uint32_t reserved_12: 1; + uint32_t reserved_13: 1; + uint32_t reserved_14: 18; + }; + uint32_t val; +} usb_dwc_pcgcctl_reg_t; + +typedef struct { + volatile usb_dwc_hcchar_reg_t hcchar_reg; + uint32_t reserved_0x04[1]; + volatile usb_dwc_hcint_reg_t hcint_reg; + volatile usb_dwc_hcintmsk_reg_t hcintmsk_reg; + volatile usb_dwc_hctsiz_reg_t hctsiz_reg; + volatile usb_dwc_hcdma_reg_t hcdma_reg; + uint32_t reserved_0x18[1]; + volatile usb_dwc_hcdmab_reg_t hcdmab_reg; +} usb_dwc_host_chan_regs_t; + +typedef struct { + volatile usb_dwc_diepctl_reg_t diepctl_reg; + uint32_t reserved_0x04[1]; + volatile usb_dwc_diepint_reg_t diepint_reg; + uint32_t reserved_0x0c[1]; + volatile usb_dwc_dieptsiz_reg_t dieptsiz_reg; + volatile usb_dwc_diepdma_reg_t diepdma_reg; + volatile usb_dwc_dtxfsts_reg_t dtxfsts_reg; + volatile usb_dwc_diepdmab_reg_t diepdmab_reg; +} usb_dwc_in_ep_regs_t; + +typedef struct { + volatile usb_dwc_doepctl_reg_t doepctl_reg; + uint32_t reserved_0x04[1]; + volatile usb_dwc_doepint_reg_t doepint_reg; + uint32_t reserved_0x0c[1]; + volatile usb_dwc_doeptsiz_reg_t doeptsiz_reg; + volatile usb_dwc_doepdma_reg_t doepdma_reg; + uint32_t reserved_0x18[1]; + volatile usb_dwc_doepdmab_reg_t doepdmab_reg; +} usb_dwc_out_ep_regs_t; + +typedef struct { + // Global Registers + volatile usb_dwc_gotgctl_reg_t gotgctl_reg; // 0x0000 + volatile usb_dwc_gotgint_reg_t gotgint_reg; // 0x0004 + volatile usb_dwc_gahbcfg_reg_t gahbcfg_reg; // 0x0008 + volatile usb_dwc_gusbcfg_reg_t gusbcfg_reg; // 0x000c + volatile usb_dwc_grstctl_reg_t grstctl_reg; // 0x0010 + volatile usb_dwc_gintsts_reg_t gintsts_reg; // 0x0014 + volatile usb_dwc_gintmsk_reg_t gintmsk_reg; // 0x0018 + volatile usb_dwc_grxstsr_reg_t grxstsr_reg; // 0x001c + volatile usb_dwc_grxstsp_reg_t grxstsp_reg; // 0x0020 + volatile usb_dwc_grxfsiz_reg_t grxfsiz_reg; // 0x0024 + volatile usb_dwc_gnptxfsiz_reg_t gnptxfsiz_reg; // 0x0028 + volatile usb_dwc_gnptxsts_reg_t gnptxsts_reg; // 0x002c + uint32_t reserved_0x0030; // 0x0030 + uint32_t reserved_0x0034; // 0x0034 + uint32_t reserved_0x0038; // 0x0038 + uint32_t reserved_0x003c; // 0x003c + volatile usb_dwc_gsnpsid_reg_t gsnpsid_reg; // 0x0040 + volatile usb_dwc_ghwcfg1_reg_t ghwcfg1_reg; // 0x0044 + volatile usb_dwc_ghwcfg2_reg_t ghwcfg2_reg; // 0x0048 + volatile usb_dwc_ghwcfg3_reg_t ghwcfg3_reg; // 0x004c + volatile usb_dwc_ghwcfg4_reg_t ghwcfg4_reg; // 0x0050 + uint32_t reserved_0x0054; // 0x0054 + uint32_t reserved_0x0058; // 0x0058 + volatile usb_dwc_gdfifocfg_reg_t gdfifocfg_reg; // 0x005c + uint32_t reserved_0x0060; // 0x0060 + uint32_t reserved_0x0064_0x0100[39]; // 0x0064 to 0x0100 + volatile usb_dwc_hptxfsiz_reg_t hptxfsiz_reg; // 0x0100 + volatile usb_dwc_dieptxfi_reg_t dieptxf_regs[4]; // 0x0104 to 0x0110 + usb_dwc_dieptxfi_reg_t reserved_0x0114_0x013c[11]; // 0x0114 to 0x013c + uint32_t reserved_0x140_0x3fc[176]; // 0x0140 to 0x03fc + + // Host Mode Registers + volatile usb_dwc_hcfg_reg_t hcfg_reg; // 0x0400 + volatile usb_dwc_hfir_reg_t hfir_reg; // 0x0404 + volatile usb_dwc_hfnum_reg_t hfnum_reg; // 0x0408 + uint32_t reserved_0x40c[1]; // 0x040c + volatile usb_dwc_hptxsts_reg_t hptxsts_reg; // 0x0410 + volatile usb_dwc_haint_reg_t haint_reg; // 0x0414 + volatile usb_dwc_haintmsk_reg_t haintmsk_reg; // 0x0418 + volatile usb_dwc_hflbaddr_reg_t hflbaddr_reg; // 0x041c + uint32_t reserved_0x420_0x43c[8]; // 0x0420 to 0x043c + volatile usb_dwc_hprt_reg_t hprt_reg; // 0x0440 + uint32_t reserved_0x0444_0x04fc[47]; // 0x0444 to 0x04fc + + // Host Channel Registers + usb_dwc_host_chan_regs_t host_chans[8]; // 0x0500 to 0x05fc + usb_dwc_host_chan_regs_t reserved_0x0600_0x06fc[8]; // 0x0600 to 0x06fc + uint32_t reserved_0x0700_0x07fc[64]; // 0x0700 to 0x07fc + + // Device Mode Registers + volatile usb_dwc_dcfg_reg_t dcfg_reg; // 0x0800 + volatile usb_dwc_dctl_reg_t dctl_reg; // 0x0804 + volatile usb_dwc_dsts_reg_t dsts_reg; // 0x0808 + uint32_t reserved_0x080c[1]; // 0x080c + volatile usb_dwc_diepmsk_reg_t diepmsk_reg; // 0x0810 + volatile usb_dwc_doepmsk_reg_t doepmsk_reg; // 0x0814 + volatile usb_dwc_daint_reg_t daint_reg; // 0x0818 + volatile usb_dwc_daintmsk_reg_t daintmsk_reg; // 0x081c + uint32_t reserved_0x0820; // 0x0820 + uint32_t reserved_0x0824; // 0x0824 + volatile usb_dwc_dvbusdis_reg_t dvbusdis_reg; // 0x0828 + volatile usb_dwc_dvbuspulse_reg_t dvbuspulse_reg; // 0x082c + volatile usb_dwc_dthrctl_reg_t dthrctl_reg; // 0x0830 + volatile usb_dwc_diepempmsk_reg_t diepempmsk_reg; // 0x0834 + uint32_t reserved_0x0838; // 0x0838 + uint32_t reserved_0x083c; // 0x083c + uint32_t reserved_0x0840; // 0x0840 + uint32_t reserved_0x0844_0x087c[15]; // 0x0844 to 0x087c + uint32_t reserved_0x0880; // 0x0880 + uint32_t reserved_0x0884_0x08c0[15]; // 0x0884 to 0x08c0 + uint32_t reserved_0x08c4_0x08fc[16]; // 0x08c4 to 0x08fc + + // Device: IN EP0 registers + volatile usb_dwc_diepctl0_reg_t diepctl0_reg; // 0x0900 + uint32_t reserved_0x0904[1]; // 0x0904 + volatile usb_dwc_diepint0_reg_t diepint0_reg; // 0x0908 + uint32_t reserved_0x090c[1]; // 0x090c + volatile usb_dwc_dieptsiz0_reg_t dieptsiz0_reg; // 0x0910 + volatile usb_dwc_diepdma0_reg_t diepdma0_reg; // 0x0914 + volatile usb_dwc_dtxfsts0_reg_t dtxfsts0_reg; // 0x0918 + volatile usb_dwc_diepdmab0_reg_t diepdmab0_reg; // 0x091c + + // Device: IN EP registers + usb_dwc_in_ep_regs_t in_eps[6]; // 0x0920 to 0x09dc + usb_dwc_in_ep_regs_t reserved_0x09e0_0x0afc[9]; // 0x09e0 to 0x0afc + + // Device: OUT EP0 registers + volatile usb_dwc_doepctl0_reg_t doepctl0_reg; // 0x0b00 + uint32_t reserved_0x0b04[1]; // 0x0b04 + volatile usb_dwc_doepint0_reg_t doepint0_reg; // 0b0b08 + uint32_t reserved_0x0b0c[1]; // 0x0b0c + volatile usb_dwc_doeptsiz0_reg_t doeptsiz0_reg; // 0x0b10 + volatile usb_dwc_doepdma0_reg_t doepdma0_reg; // 0x0b14 + uint32_t reserved_0x0b18[1]; // 0x0b18 + volatile usb_dwc_doepdmab0_reg_t doepdmab0_reg; // 0x0b1c + + // Device: OUT EP registers + usb_dwc_out_ep_regs_t out_eps[6]; // 0x0b20 to 0x0bdc + usb_dwc_out_ep_regs_t reserved_0x0be0_0x0d00[9]; // 0x0be0 to 0x0cfc + uint32_t reserved_0x0d00_0x0dfc[64]; // 0x0d00 to 0x0dfc + + // Power and Clock Gating + volatile usb_dwc_pcgcctl_reg_t pcgcctl_reg; // 0x0e00 + uint32_t reserved_0x0e04[1]; // 0x0e04 + +} usb_dwc_dev_t; + +#ifndef __cplusplus +_Static_assert(sizeof(usb_dwc_dev_t) == 0xe08, "Invalid size of usb_dwc_dev_t structure"); +#endif + +extern usb_dwc_dev_t USB_DWC; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h4/include/soc/usb_struct.h b/components/soc/esp32h4/include/soc/usb_struct.h new file mode 100644 index 0000000000000..c0d64e2826488 --- /dev/null +++ b/components/soc/esp32h4/include/soc/usb_struct.h @@ -0,0 +1,109 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* USB IN EP Register block type */ +typedef struct usb_in_ep_reg { + volatile uint32_t diepctl; + uint32_t reserved; + volatile uint32_t diepint; + uint32_t reserved1; + volatile uint32_t dieptsiz; + volatile uint32_t diepdma; + volatile uint32_t dtxfsts; + uint32_t reserved2; +} usb_in_endpoint_t; + +/* USB OUT EP Register block type */ +typedef struct usb_out_ep_reg { + volatile uint32_t doepctl; + uint32_t reserved; + volatile uint32_t doepint; + uint32_t reserved1; + volatile uint32_t doeptsiz; + volatile uint32_t doepdma; + uint32_t reserved2; + uint32_t reserved3; +} usb_out_endpoint_t; + +typedef struct usb_dev_t { + volatile uint32_t gotgctl; + volatile uint32_t gotgint; + volatile uint32_t gahbcfg; + volatile uint32_t gusbcfg; + volatile uint32_t grstctl; + volatile uint32_t gintsts; + volatile uint32_t gintmsk; + volatile uint32_t grxstsr; + volatile uint32_t grxstsp; + volatile uint32_t grxfsiz; + volatile uint32_t gnptxfsiz; + volatile uint32_t gnptxsts; + uint32_t reserved_0x0030_0x0040[4]; + volatile uint32_t gsnpsid; + volatile uint32_t ghwcfg1; + volatile uint32_t ghwcfg2; + volatile uint32_t ghwcfg3; + volatile uint32_t ghwcfg4; + uint32_t reserved_0x0054_0x005c[2]; + volatile uint32_t gdfifocfg; + uint32_t reserved_0x0060_0x0100[40]; + volatile uint32_t hptxfsiz; + volatile uint32_t dieptxf[4]; + uint32_t reserved_0x0114_0x0140[11]; + uint32_t reserved_0x0140_0x0400[176]; + volatile uint32_t hcfg; + volatile uint32_t hfir; + volatile uint32_t hfnum; + uint32_t reserved0x40C; + volatile uint32_t hptxsts; + volatile uint32_t haint; + volatile uint32_t haintmsk; + volatile uint32_t hflbaddr; + uint32_t reserved0x0420_0x0440[8]; + volatile uint32_t hprt; + uint32_t reserved_0x0444_0x0500[47]; + volatile uint32_t host_chan_regs[128]; + uint32_t reserved_0x0700_0x0800[64]; + volatile uint32_t dcfg; + volatile uint32_t dctl; + volatile uint32_t dsts; + uint32_t reserved0x80c; + volatile uint32_t diepmsk; + volatile uint32_t doepmsk; + volatile uint32_t daint; + volatile uint32_t daintmsk; + uint32_t reserved_0x0820_0x0828[2]; + volatile uint32_t dvbusdis; + volatile uint32_t dvbuspulse; + volatile uint32_t dthrctl; + volatile uint32_t dtknqr4_fifoemptymsk; + uint32_t reserved_0x0838_0x0900[50]; + usb_in_endpoint_t in_ep_reg[7]; + uint32_t reserved_0x09e0_0x0b00[72]; + usb_out_endpoint_t out_ep_reg[7]; + uint32_t reserved_0x0be0_0x0d00[72]; + uint32_t reserved_0x0d00_0x0e00[64]; + uint32_t pcgctrl; + uint32_t reserved_0x0e04; + uint8_t reserved8[0x1000 - 0xe08]; + uint32_t fifo[16][0x400]; + uint8_t reserved0x11000[0x20000 - 0x11000]; + uint32_t dbg_fifo[0x20000]; +} usb_dev_t; + +extern usb_dev_t USB0; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32h4/ld/esp32h4.peripherals.beta5.ld b/components/soc/esp32h4/ld/esp32h4.peripherals.beta5.ld index 91f7983ffc30b..3001f8096bdd1 100644 --- a/components/soc/esp32h4/ld/esp32h4.peripherals.beta5.ld +++ b/components/soc/esp32h4/ld/esp32h4.peripherals.beta5.ld @@ -38,6 +38,7 @@ PROVIDE ( SAMPLE_RATE_CONVERTER = 0x60028000 ); PROVIDE ( ZERO_DET = 0x60029000 ); PROVIDE ( USB_OTG_FS_CORE0 = 0x60040000 ); PROVIDE ( USB_OTG_FS_CORE1 = 0x6007F000 ); +PROVIDE ( USB_DWC = 0x60040000 ); PROVIDE ( USB_WRAP = 0x60080000 ); PROVIDE ( TIMERG0 = 0x60090000 ); PROVIDE ( TIMERG1 = 0x60091000 ); diff --git a/components/soc/esp32h4/ld/esp32h4.peripherals.ld b/components/soc/esp32h4/ld/esp32h4.peripherals.ld index 527f946f507c0..5f8e22449d644 100644 --- a/components/soc/esp32h4/ld/esp32h4.peripherals.ld +++ b/components/soc/esp32h4/ld/esp32h4.peripherals.ld @@ -38,6 +38,7 @@ PROVIDE ( SAMPLE_RATE_CONVERTER = 0x60028000 ); PROVIDE ( ZERO_DET = 0x60029000 ); PROVIDE ( USB_OTG_FS_CORE0 = 0x60040000 ); PROVIDE ( USB_OTG_FS_CORE1 = 0x6007F000 ); +PROVIDE ( USB_DWC = 0x60040000 ); PROVIDE ( USB_WRAP = 0x60080000 ); PROVIDE ( TIMERG0 = 0x60090000 ); PROVIDE ( TIMERG1 = 0x60091000 ); diff --git a/components/soc/esp32h4/usb_dwc_periph.c b/components/soc/esp32h4/usb_dwc_periph.c new file mode 100644 index 0000000000000..0b5c4e43dc752 --- /dev/null +++ b/components/soc/esp32h4/usb_dwc_periph.c @@ -0,0 +1,48 @@ +/* + * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "soc/gpio_sig_map.h" +#include "soc/interrupts.h" +#include "soc/usb_periph.h" + +/* -------------------------------- Private --------------------------------- */ + +static const usb_otg_signal_conn_t otg_signals = { + // Inputs + .iddig = USB_OTG_IDDIG_IN_IDX, + .avalid = USB_OTG_AVALID_IN_IDX, + .bvalid = USB_SRP_BVALID_IN_IDX, + .vbusvalid = USB_OTG_VBUSVALID_IN_IDX, + .sessend = USB_SRP_SESSEND_IN_IDX, + // Outputs + .idpullup = USB_OTG_IDPULLUP_OUT_IDX, + .dppulldown = USB_OTG_DPPULLDOWN_OUT_IDX, + .dmpulldown = USB_OTG_DMPULLDOWN_OUT_IDX, + .drvvbus = USB_OTG_DRVVBUS_OUT_IDX, + .chrgvbus = USB_SRP_CHRGVBUS_OUT_IDX, + .dischrgvbus = USB_SRP_DISCHRGVBUS_OUT_IDX, +}; + +static const usb_internal_phy_io_t internal_phy_io = { + .dp = 21, + .dm = 22, +}; + +/* --------------------------------- Public --------------------------------- */ + +const usb_dwc_info_t usb_dwc_info = { + .controllers = { + [0] = { + .fsls_signals = NULL, + .otg_signals = &otg_signals, + .internal_phy_io = &internal_phy_io, + .supported_phys = USB_PHY_INST_FSLS_INTERN_0, + .irq = ETS_USB_OTG11_INTR_SOURCE, + .irq_2nd_cpu = -1, + }, + }, +}; diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index f0f2d85faca81..6e1a2373fb030 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -20,7 +20,7 @@ API Guides core_dump current-consumption-measurement-modules :ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB: deep-sleep-stub - :SOC_USB_OTG_SUPPORTED: dfu + :SOC_USB_OTG_SUPPORTED and not esp32h4: dfu error-handling :SOC_WIFI_MESH_SUPPORT: esp-wifi-mesh :SOC_SPIRAM_SUPPORTED: external-ram @@ -45,7 +45,7 @@ API Guides tools/index unit-tests host-apps - :SOC_USB_OTG_SUPPORTED and not esp32p4: usb-otg-console + :SOC_USB_OTG_SUPPORTED and not esp32p4 and not esp32h4: usb-otg-console :SOC_USB_SERIAL_JTAG_SUPPORTED: usb-serial-jtag-console :SOC_WIFI_SUPPORTED: wifi :SOC_WIFI_SUPPORTED: wifi-security diff --git a/docs/zh_CN/api-guides/index.rst b/docs/zh_CN/api-guides/index.rst index 15d921cc38cfd..9bf06a34017b0 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -20,7 +20,7 @@ API 指南 core_dump current-consumption-measurement-modules :ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB: deep-sleep-stub - :SOC_USB_OTG_SUPPORTED: dfu + :SOC_USB_OTG_SUPPORTED and not esp32h4: dfu error-handling :SOC_WIFI_MESH_SUPPORT: esp-wifi-mesh :SOC_SPIRAM_SUPPORTED: external-ram @@ -45,7 +45,7 @@ API 指南 tools/index unit-tests host-apps - :SOC_USB_OTG_SUPPORTED and not esp32p4: usb-otg-console + :SOC_USB_OTG_SUPPORTED and not esp32p4 and not esp32h4: usb-otg-console :SOC_USB_SERIAL_JTAG_SUPPORTED: usb-serial-jtag-console :SOC_WIFI_SUPPORTED: wifi :SOC_WIFI_SUPPORTED: wifi-security diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index d8adddd49bfcb..8088e98a5e2e4 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -136,6 +136,9 @@ examples/peripherals/i2s/i2s_advance/i2s_usb: - if: SOC_I2S_SUPPORTED != 1 - if: SOC_I2C_SUPPORTED != 1 - if: SOC_USB_OTG_SUPPORTED != 1 + - if: IDF_TARGET == "esp32h4" + temporary: true + reason: usb_device_uac does not support esp32h4 depends_components: - esp_driver_i2s - esp_driver_i2c @@ -559,6 +562,12 @@ examples/peripherals/usb/device: depends_filepatterns: - examples/peripherals/usb/device/**/* +examples/peripherals/usb/device/cherryusb_serial_device: + disable: + - if: (IDF_TARGET == "esp32h4") or (SOC_USB_OTG_SUPPORTED != 1) + temporary: true + reason: CherryUSB does not support esp32h4 + examples/peripherals/usb/device/tusb_ncm: disable: - if: SOC_USB_OTG_SUPPORTED != 1 or SOC_WIFI_SUPPORTED != 1 @@ -592,6 +601,12 @@ examples/peripherals/usb/host: - components/esp_hw_support/include/esp_private/usb_phy.h - examples/peripherals/usb/host/**/* +examples/peripherals/usb/host/cherryusb_host: + disable: + - if: (IDF_TARGET == "esp32h4") or (SOC_USB_OTG_SUPPORTED != 1) + temporary: true + reason: CherryUSB does not support esp32h4 + examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo: disable: - if: SOC_USB_SERIAL_JTAG_SUPPORTED != 1 diff --git a/examples/peripherals/usb/device/tusb_composite_msc_serialdevice/README.md b/examples/peripherals/usb/device/tusb_composite_msc_serialdevice/README.md index a7a32c4567a1f..8747380d16744 100644 --- a/examples/peripherals/usb/device/tusb_composite_msc_serialdevice/README.md +++ b/examples/peripherals/usb/device/tusb_composite_msc_serialdevice/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # TinyUSB Composite Device (MSC + Serial) Example diff --git a/examples/peripherals/usb/device/tusb_console/README.md b/examples/peripherals/usb/device/tusb_console/README.md index aeccaab2514a7..6d5900884b8c2 100644 --- a/examples/peripherals/usb/device/tusb_console/README.md +++ b/examples/peripherals/usb/device/tusb_console/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # TinyUSB Sample Descriptor diff --git a/examples/peripherals/usb/device/tusb_hid/README.md b/examples/peripherals/usb/device/tusb_hid/README.md index e784742510c3f..66e02acad9429 100644 --- a/examples/peripherals/usb/device/tusb_hid/README.md +++ b/examples/peripherals/usb/device/tusb_hid/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # TinyUSB Human Interface Device Example diff --git a/examples/peripherals/usb/device/tusb_midi/README.md b/examples/peripherals/usb/device/tusb_midi/README.md index 7007230dfec29..b2b3d9d845bbd 100644 --- a/examples/peripherals/usb/device/tusb_midi/README.md +++ b/examples/peripherals/usb/device/tusb_midi/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # TinyUSB MIDI Device Example diff --git a/examples/peripherals/usb/device/tusb_msc/README.md b/examples/peripherals/usb/device/tusb_msc/README.md index 84b9fd3ba4c02..207e1de948cd0 100644 --- a/examples/peripherals/usb/device/tusb_msc/README.md +++ b/examples/peripherals/usb/device/tusb_msc/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # TinyUSB Mass Storage Device Example diff --git a/examples/peripherals/usb/device/tusb_serial_device/README.md b/examples/peripherals/usb/device/tusb_serial_device/README.md index 60ef9a9b44d11..10a62aced3df3 100644 --- a/examples/peripherals/usb/device/tusb_serial_device/README.md +++ b/examples/peripherals/usb/device/tusb_serial_device/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # TinyUSB Serial Device Example diff --git a/examples/peripherals/usb/host/cdc/cdc_acm_host/README.md b/examples/peripherals/usb/host/cdc/cdc_acm_host/README.md index 8e69909f31b5c..1b3f8dda60061 100644 --- a/examples/peripherals/usb/host/cdc/cdc_acm_host/README.md +++ b/examples/peripherals/usb/host/cdc/cdc_acm_host/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # USB CDC-ACM Host Driver Example diff --git a/examples/peripherals/usb/host/cdc/cdc_acm_vcp/README.md b/examples/peripherals/usb/host/cdc/cdc_acm_vcp/README.md index 2883ef061980b..9bd7229b5f2b0 100644 --- a/examples/peripherals/usb/host/cdc/cdc_acm_vcp/README.md +++ b/examples/peripherals/usb/host/cdc/cdc_acm_vcp/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # USB CDC-ACM Virtual COM Port example diff --git a/examples/peripherals/usb/host/hid/README.md b/examples/peripherals/usb/host/hid/README.md index d2efef2792448..e74add4485fae 100644 --- a/examples/peripherals/usb/host/hid/README.md +++ b/examples/peripherals/usb/host/hid/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # USB HID Class example This example implements a basic USB Host HID Class Driver, and demonstrates how to use the driver to communicate with USB HID devices (such as Keyboard and Mouse or both) on the ESP32-S2/S3. Currently, the example only supports the HID boot protocol which should be present on most USB Mouse and Keyboards. The example will continuously scan for the connection of any HID Mouse or Keyboard, and attempt to fetch HID reports from those devices once connected. To quit the example (and shut down the HID driver), users can GPIO0 to low (i.e., pressing the "Boot" button on most ESP dev kits). diff --git a/examples/peripherals/usb/host/msc/README.md b/examples/peripherals/usb/host/msc/README.md index 08bdcda8decbd..04c500ac93820 100644 --- a/examples/peripherals/usb/host/msc/README.md +++ b/examples/peripherals/usb/host/msc/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # USB Mass Storage Class example diff --git a/examples/peripherals/usb/host/usb_host_lib/README.md b/examples/peripherals/usb/host/usb_host_lib/README.md index 3e09beb2438f9..6ca21d3a177c6 100644 --- a/examples/peripherals/usb/host/usb_host_lib/README.md +++ b/examples/peripherals/usb/host/usb_host_lib/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # USB Host Library Example diff --git a/examples/peripherals/usb/host/uvc/README.md b/examples/peripherals/usb/host/uvc/README.md index fb408d0d64cca..8b1f41aa38ac0 100644 --- a/examples/peripherals/usb/host/uvc/README.md +++ b/examples/peripherals/usb/host/uvc/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | +| ----------------- | -------- | -------- | -------- | -------- | # USB Camera Example