diff --git a/components/esp_hal_usb/CMakeLists.txt b/components/esp_hal_usb/CMakeLists.txt index e2af7d7064..14461d6ec6 100644 --- a/components/esp_hal_usb/CMakeLists.txt +++ b/components/esp_hal_usb/CMakeLists.txt @@ -11,9 +11,14 @@ if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${target}/include") list(APPEND includes "${target}/include") endif() -# USB-DWC related source files and USB FSLS PHY wrapper +# USB-DWC related source files if(CONFIG_SOC_USB_OTG_SUPPORTED) - list(APPEND srcs "usb_dwc_hal.c" "usb_wrap_hal.c" "${target}/usb_dwc_periph.c") + list(APPEND srcs "usb_dwc_hal.c" "${target}/usb_dwc_periph.c") +endif() + +# USB FSLS PHY wrapper +if(CONFIG_SOC_USB_FSLS_PHY_NUM GREATER 0) + list(APPEND srcs "usb_wrap_hal.c") endif() # USB UTMI PHY diff --git a/components/esp_hal_usb/esp32p4/include/hal/usb_utmi_ll.h b/components/esp_hal_usb/esp32p4/include/hal/usb_utmi_ll.h index f64250a66e..1c2978f95b 100644 --- a/components/esp_hal_usb/esp32p4/include/hal/usb_utmi_ll.h +++ b/components/esp_hal_usb/esp32p4/include/hal/usb_utmi_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +12,10 @@ #include "soc/hp_sys_clkrst_struct.h" #include "soc/hp_system_struct.h" #include "soc/usb_utmi_struct.h" +#include "hal/config.h" +#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 +#include "soc/lp_system_struct.h" +#endif #ifdef __cplusplus extern "C" { @@ -81,6 +85,29 @@ FORCE_INLINE_ATTR void _usb_utmi_ll_reset_register(void) _usb_utmi_ll_reset_register(__VA_ARGS__); \ } while(0) +/** + * @brief Enable/disable 15k pulldown resistors on D+/D- lines + * + * In USB Host mode, 15k pulldown resistors must be connected on both D+ and D-. + * In USB Device mode, pulldown resistors must be disconnected. + * + * @note On ESP32-P4 v3+, pulldowns are no longer controlled by USB-OTG peripheral + * and must be controlled by software via LP_SYS registers. + * On earlier revisions, pulldowns are controlled by USB-OTG hardware. + * + * @param[in] enable true to connect pulldowns (Host mode), false to disconnect (Device mode) + */ +FORCE_INLINE_ATTR void usb_utmi_ll_enable_data_pulldowns(bool enable) +{ +#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 + LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dppulldown = enable; + LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dmpulldown = enable; +#else + // On pre-v3 ESP32-P4, pulldowns are controlled by the USB-OTG peripheral + (void)enable; +#endif +} + /** * @brief Enable precise detection of VBUS * diff --git a/components/esp_hal_usb/esp32s31/include/hal/usb_dwc_ll.h b/components/esp_hal_usb/esp32s31/include/hal/usb_dwc_ll.h new file mode 100644 index 0000000000..96be68454e --- /dev/null +++ b/components/esp_hal_usb/esp32s31/include/hal/usb_dwc_ll.h @@ -0,0 +1,1104 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include +#include "esp_attr.h" +#include "soc/usb_dwc_struct.h" +#include "hal/usb_dwc_types.h" +#include "hal/misc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------- Helper Macros ------------------------------ */ + +// S31 has one USB DWC controller (HS) +#define USB_DWC_LL_GET_HW(num) (&USB_OTGHS) + +/* ----------------------------------------------------------------------------- +--------------------------------- 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_en_hnp_cap(usb_dwc_dev_t *hw) +{ + hw->gusbcfg_reg.hnpcap = 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) +{ + // Start core soft reset + hw->grstctl_reg.csftrst = 1; + + // Wait for the reset to complete + while (!(hw->grstctl_reg.csftrstdone)) { + ; + } + + usb_dwc_grstctl_reg_t grstctl; + grstctl.val = hw->grstctl_reg.val; + grstctl.csftrst = 0; // Clear RESET bit once reset is done + grstctl.csftrstdone = 1; // Write 1 to clear RESET_DONE bit + hw->grstctl_reg.val = grstctl.val; +} + +// --------------------------- 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; +} + +/** + * @brief Get transfer size counter width + * + * For each transfer, the USB-DWC core keeps track of number of bytes for the particular transfer. + * Hence, maximum transfer size is limited by (2^xfer_size_width - 1) bytes + * + * Minimum transfer size counter width is 11. So value of 0 of xfersizewidth field in the register must be interpreted as 11. + * + * @see USB-DWC databook Table 5-26 + * @param[in] hw Start address of the DWC_OTG registers + * @return Effective bitwidth of the transfer size counter + */ +static inline unsigned usb_dwc_ll_ghwcfg_get_xfer_size_width(usb_dwc_dev_t *hw) +{ + return hw->ghwcfg3_reg.xfersizewidth + 11; +} + +/** + * @brief Get packet counter width + * + * For each transfer, the USB-DWC core keeps track of the number of packets needed for the particular transfer + * and its endpoint's Maximum Packet Size. + * Hence, maximum transfer size is limited by MPS * (2^packet_counter_width - 1) + * + * Minimum packet counter width is 4. So value of 0 of pktsizewidth field in the register must be interpreted as 4. + * + * @see USB-DWC databook Table 5-26 + * @param[in] hw Start address of the DWC_OTG registers + * @return Effective bitwidth of the packet counter + */ +static inline unsigned usb_dwc_ll_ghwcfg_get_packet_size_width(usb_dwc_dev_t *hw) +{ + return hw->ghwcfg3_reg.pktsizewidth + 4; +} + +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 + * + * PING protocol is automatically enabled if High-Speed device responds with NYET in Scatter-Gather DMA mode. + * The application must disable PING for next transfer. + * Relevant only for OUT transfers. + * + * @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) +{ + chan->hctsiz_reg.dopng = (uint32_t)(enable && !chan->hcchar_reg.epdir); +} + +/** + * @brief Set scheduling info for Periodic channel + * + * @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 HS: Number of tokens per frame FS: Must be set 8 + * @param[in] offset Offset of the channel + */ +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; + uint8_t sched_info_val; + switch (tokens_per_frame) { + case 1: + offset %= 8; // If the required offset > 8, we must wrap around to SCHED_INFO size = 8 + sched_info_val = 0b00000001; + break; + case 2: + offset %= 4; + sched_info_val = 0b00010001; + break; + case 4: + offset %= 2; + sched_info_val = 0b01010101; + break; + case 8: + offset = 0; + sched_info_val = 0b11111111; + break; + default: + abort(); + break; + } + sched_info_val <<= offset; + hctsiz.xfersize &= ~(0xFF); + hctsiz.xfersize |= sched_info_val; + 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; +} + +/** + * @brief Get the current BVALID override configuration. + * + * @param[out] Get the current BVALID override configuration. + */ +FORCE_INLINE_ATTR bool usb_dwc_ll_get_bvalid_override(usb_dwc_dev_t *hw) +{ + return hw->gotgctl_reg.bvalidoven; +} + +/** + * @brief Enable BVALID override in USB OTG controller. + * + * When enabled, the controller ignores the hardware-detected VBUS BVALID signal + * and uses the software-defined override value instead. This is typically used + * to reduce USB leakage current during sleep by forcing BVALID low. + */ +FORCE_INLINE_ATTR void usb_dwc_ll_enable_bvalid_override(usb_dwc_dev_t *hw, bool override) +{ + hw->gotgctl_reg.bvalidoven = override; +} + +// ---------------------------- Power and Clock Gating Register -------------------------------- +FORCE_INLINE_ATTR void usb_dwc_ll_set_stoppclk(usb_dwc_dev_t *hw, bool stop) +{ + hw->pcgcctl_reg.stoppclk = stop; +} + +FORCE_INLINE_ATTR bool usb_dwc_ll_get_stoppclk_st(usb_dwc_dev_t *hw) +{ + return hw->pcgcctl_reg.stoppclk; +} + +FORCE_INLINE_ATTR void usb_dwc_ll_set_gatehclk(usb_dwc_dev_t *hw, bool gate) +{ + hw->pcgcctl_reg.gatehclk = gate; +} + +FORCE_INLINE_ATTR bool usb_dwc_ll_get_gatehclk_st(usb_dwc_dev_t *hw) +{ + return hw->pcgcctl_reg.gatehclk; +} + +FORCE_INLINE_ATTR bool usb_dwc_ll_get_physleep_st(usb_dwc_dev_t *hw) +{ + return hw->pcgcctl_reg.physleep; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_usb/esp32s31/include/hal/usb_utmi_ll.h b/components/esp_hal_usb/esp32s31/include/hal/usb_utmi_ll.h new file mode 100644 index 0000000000..25b64f7d03 --- /dev/null +++ b/components/esp_hal_usb/esp32s31/include/hal/usb_utmi_ll.h @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_attr.h" +#include "soc/soc.h" +#include "soc/cnnt_sys_struct.h" +#include "soc/hp_alive_sys_struct.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/reg_base.h" +#include "soc/usb_utmi_struct.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------------------------- USB PHY Control ---------------------------- */ + +#define USB_UTMI_LL_CNNT_SYS_REG ((volatile cnnt_dev_t *)DR_REG_CNNT_SYS_REG_BASE) + +/** + * @brief Configure Low-Speed mode + * + * @param[in] hw Beginning address of the peripheral registers + * @param[in] parallel Parallel or serial LS mode + */ +FORCE_INLINE_ATTR void usb_utmi_ll_configure_ls(usb_utmi_dev_t *hw, bool parallel) +{ + hw->fc_06.ls_par_en = parallel; + hw->fc_06.ls_kpalv_en = 1; +} + +/* ----------------------------- RCC Functions ----------------------------- */ + +/** + * @brief Enable/disable bus clock for USB UTMI PHY and USB OTG HS controller + * + * @param[in] clk_en True to enable, false to disable + */ +FORCE_INLINE_ATTR void _usb_utmi_ll_enable_bus_clock(bool clk_en) +{ + cnnt_sys_usb_otg20_ctrl_reg_t sys_usb_otg20_ctrl; + + HP_SYS_CLKRST.usb_otghs_ctrl0.reg_usb_otghs_apb_clk_en = clk_en; + HP_SYS_CLKRST.usb_otghs_ctrl0.reg_usb_otghs_sys_clk_en = clk_en; + + sys_usb_otg20_ctrl.val = USB_UTMI_LL_CNNT_SYS_REG->sys_usb_otg20_ctrl.val; + sys_usb_otg20_ctrl.sys_usb_otg20_utmifs_clk_en = clk_en; + sys_usb_otg20_ctrl.sys_usb_otg20_phyref_clk_en = clk_en; + USB_UTMI_LL_CNNT_SYS_REG->sys_usb_otg20_ctrl.val = sys_usb_otg20_ctrl.val; + + // Enable/disable PHY PLL (must be force-enabled on ESP32-S31, as the default is off) + HP_ALIVE_SYS.usb_otghs_ctrl.reg_usb_otghs_phy_pll_force_en = clk_en; + HP_ALIVE_SYS.usb_otghs_ctrl.reg_usb_otghs_phy_pll_en = clk_en; +} + +// HP_SYS_CLKRST.usb_otghs_ctrl0 and sys_usb_otg20_ctrl only contain USB OTG fields, no atomic wrapper needed +#define usb_utmi_ll_enable_bus_clock(...) _usb_utmi_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Get USB UTMI bus clock status + * + * @return true if enabled, false otherwise + */ +FORCE_INLINE_ATTR bool _usb_utmi_ll_bus_clock_is_enabled(void) +{ + return HP_SYS_CLKRST.usb_otghs_ctrl0.reg_usb_otghs_apb_clk_en && + HP_SYS_CLKRST.usb_otghs_ctrl0.reg_usb_otghs_sys_clk_en && + USB_UTMI_LL_CNNT_SYS_REG->sys_usb_otg20_ctrl.sys_usb_otg20_utmifs_clk_en && + USB_UTMI_LL_CNNT_SYS_REG->sys_usb_otg20_ctrl.sys_usb_otg20_phyref_clk_en; +} + +/** + * @brief Reset USB UTMI PHY and USB OTG HS controller + * + * @note PHY reset must be de-asserted before controller reset, + * so that the PHY is stable when the controller starts. + */ +FORCE_INLINE_ATTR void _usb_utmi_ll_reset_register(void) +{ + cnnt_sys_usb_otg20_ctrl_reg_t sys_usb_otg20_ctrl; + + sys_usb_otg20_ctrl.val = USB_UTMI_LL_CNNT_SYS_REG->sys_usb_otg20_ctrl.val; + + // Assert all resets + sys_usb_otg20_ctrl.sys_usb_otg20_ahb_rst_en = 1; + sys_usb_otg20_ctrl.sys_usb_otg20_apb_rst_en = 1; + sys_usb_otg20_ctrl.sys_usb_otg20_phy_rst_en = 1; + USB_UTMI_LL_CNNT_SYS_REG->sys_usb_otg20_ctrl.val = sys_usb_otg20_ctrl.val; + + // De-assert PHY reset first + sys_usb_otg20_ctrl.sys_usb_otg20_phy_rst_en = 0; + USB_UTMI_LL_CNNT_SYS_REG->sys_usb_otg20_ctrl.val = sys_usb_otg20_ctrl.val; + + // De-assert controller resets + sys_usb_otg20_ctrl.sys_usb_otg20_ahb_rst_en = 0; + sys_usb_otg20_ctrl.sys_usb_otg20_apb_rst_en = 0; + USB_UTMI_LL_CNNT_SYS_REG->sys_usb_otg20_ctrl.val = sys_usb_otg20_ctrl.val; +} + +// sys_usb_otg20_ctrl only contains USB OTG fields, no atomic wrapper needed +#define usb_utmi_ll_reset_register(...) _usb_utmi_ll_reset_register(__VA_ARGS__) + +/** + * @brief Enable/disable 15k pulldown resistors on D+/D- lines + * + * In USB Host mode, 15k pulldown resistors must be connected on both D+ and D-. + * In USB Device mode, pulldown resistors must be disconnected. + * + * @param[in] enable true to connect pulldowns (Host mode), false to disconnect (Device mode) + */ +FORCE_INLINE_ATTR void usb_utmi_ll_enable_data_pulldowns(bool enable) +{ + HP_ALIVE_SYS.usb_ctrl.usb_otghs_phy_dppulldown = enable; + HP_ALIVE_SYS.usb_ctrl.usb_otghs_phy_dmpulldown = enable; +} + +/** + * @brief Enable precise VBUS/disconnection detection path + * + * @param[in] enable Enable/disable precise detection + */ +FORCE_INLINE_ATTR void usb_utmi_ll_enable_precise_detection(bool enable) +{ + HP_ALIVE_SYS.usb_otghs_ctrl.reg_usb_otghs_phy_otg_suspendm = enable; + HP_ALIVE_SYS.usb_otghs_ctrl.reg_usb_otghs_phy_suspendm = enable; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_usb/esp32s31/usb_dwc_periph.c b/components/esp_hal_usb/esp32s31/usb_dwc_periph.c new file mode 100644 index 0000000000..9c48cac873 --- /dev/null +++ b/components/esp_hal_usb/esp32s31/usb_dwc_periph.c @@ -0,0 +1,24 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "soc/interrupts.h" +#include "soc/usb_periph.h" + +/* --------------------------------- Public --------------------------------- */ + +const usb_dwc_info_t usb_dwc_info = { + .controllers = { + [0] = { + .fsls_signals = NULL, + .otg_signals = NULL, + .internal_phy_io = NULL, // HS PHY is not mapped to any GPIO + .supported_phys = USB_PHY_INST_UTMI_0, + .irq = ETS_USB_OTGHS_INTR_SOURCE, + .irq_2nd_cpu = ETS_USB_OTGHS_ENDP_MULTI_PROC_INTR_SOURCE, + }, + }, +}; diff --git a/components/esp_hal_usb/include/hal/usb_utmi_hal.h b/components/esp_hal_usb/include/hal/usb_utmi_hal.h index dcb859a21c..ad7ba50f6c 100644 --- a/components/esp_hal_usb/include/hal/usb_utmi_hal.h +++ b/components/esp_hal_usb/include/hal/usb_utmi_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -57,6 +57,16 @@ void _usb_utmi_hal_disable(void); #define usb_utmi_hal_disable(...) do {(void)__DECLARE_RCC_ATOMIC_ENV; _usb_utmi_hal_disable(__VA_ARGS__);} while(0) #endif +/** + * @brief Enable/disable 15k pulldown resistors on D+/D- lines + * + * In USB Host mode, 15k pulldown resistors must be connected on both D+ and D-. + * In USB Device mode, pulldown resistors must be disconnected. + * + * @param[in] enable true to connect pulldowns (Host mode), false to disconnect (Device mode) + */ +void usb_utmi_hal_enable_data_pulldowns(bool enable); + #endif // (SOC_USB_UTMI_PHY_NUM > 0) #ifdef __cplusplus diff --git a/components/esp_hal_usb/include/hal/usb_wrap_hal.h b/components/esp_hal_usb/include/hal/usb_wrap_hal.h index 0571072add..f931eee7f5 100644 --- a/components/esp_hal_usb/include/hal/usb_wrap_hal.h +++ b/components/esp_hal_usb/include/hal/usb_wrap_hal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -8,17 +8,17 @@ #include #include "soc/soc_caps.h" -#if (SOC_USB_OTG_PERIPH_NUM > 0) +#if (SOC_USB_FSLS_PHY_NUM > 0) #include "soc/usb_wrap_struct.h" #include "hal/usb_wrap_ll.h" -#endif // (SOC_USB_OTG_PERIPH_NUM > 0) +#endif // (SOC_USB_FSLS_PHY_NUM > 0) #include "hal/usb_wrap_types.h" #ifdef __cplusplus extern "C" { #endif -#if (SOC_USB_OTG_PERIPH_NUM > 0) +#if (SOC_USB_FSLS_PHY_NUM > 0) /** * @brief HAL context type of USB WRAP driver @@ -112,7 +112,7 @@ static inline void usb_wrap_hal_phy_test_mode_set_signals(usb_wrap_hal_context_t usb_wrap_ll_phy_test_mode_set_signals(hal->dev, vals); } -#endif // (SOC_USB_OTG_PERIPH_NUM > 0) +#endif // (SOC_USB_FSLS_PHY_NUM > 0) #ifdef __cplusplus } diff --git a/components/esp_hal_usb/include/hal/usb_wrap_types.h b/components/esp_hal_usb/include/hal/usb_wrap_types.h index a8727f0ef8..166f53d4ed 100644 --- a/components/esp_hal_usb/include/hal/usb_wrap_types.h +++ b/components/esp_hal_usb/include/hal/usb_wrap_types.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,7 +13,7 @@ extern "C" { #endif -#if (SOC_USB_OTG_PERIPH_NUM > 0) +#if (SOC_USB_FSLS_PHY_NUM > 0) /** * @brief USB WRAP pull up/down resistor override values @@ -46,7 +46,7 @@ typedef struct { bool rx_rcv; /**< Differential receive data from D+ and D- lines */ } usb_wrap_test_mode_vals_t; -#endif // (SOC_USB_OTG_PERIPH_NUM > 0) +#endif // (SOC_USB_FSLS_PHY_NUM > 0) #ifdef __cplusplus } diff --git a/components/esp_hal_usb/usb_dwc_hal.c b/components/esp_hal_usb/usb_dwc_hal.c index c2e0b44656..d6a5d6bedc 100644 --- a/components/esp_hal_usb/usb_dwc_hal.c +++ b/components/esp_hal_usb/usb_dwc_hal.c @@ -109,9 +109,9 @@ static void set_defaults(usb_dwc_hal_context_t *hal) hbstlen = 1; //Set AHB burst to INCR to workaround hardware errata } #endif // SOC_IS(ESP32S2) -#if SOC_IS(ESP32P4) +#if SOC_IS(ESP32P4) || SOC_IS(ESP32S31) /* - * ESP32P4-specific initialization: Clear USB PHY suspend state set during system boot. + * ESP32P4/ESP32S31-specific initialization: Clear USB PHY suspend state set during system boot. * * During system initialization (see clk_gate_ll.h:periph_ll_clk_gate_set_default), the USB PHY * is forced into suspend mode before disabling clocks to prevent USB leakage current and ensure @@ -123,7 +123,7 @@ static void set_defaults(usb_dwc_hal_context_t *hal) */ usb_dwc_ll_enable_bvalid_override(hal->dev, false); usb_dwc_ll_set_stoppclk(hal->dev, false); -#endif // SOC_IS(ESP32P4) +#endif // SOC_IS(ESP32P4) || SOC_IS(ESP32S31) usb_dwc_ll_gahbcfg_set_hbstlen(hal->dev, hbstlen); //Set AHB burst mode //GUSBCFG register usb_dwc_ll_gusbcfg_dis_hnp_cap(hal->dev); //Disable HNP diff --git a/components/esp_hal_usb/usb_utmi_hal.c b/components/esp_hal_usb/usb_utmi_hal.c index cb7ceb49ba..137f493d99 100644 --- a/components/esp_hal_usb/usb_utmi_hal.c +++ b/components/esp_hal_usb/usb_utmi_hal.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -23,6 +23,11 @@ void _usb_utmi_hal_init(usb_utmi_hal_context_t *hal) usb_utmi_ll_configure_ls(hal->dev, true); } +void usb_utmi_hal_enable_data_pulldowns(bool enable) +{ + usb_utmi_ll_enable_data_pulldowns(enable); +} + void _usb_utmi_hal_disable(void) { _usb_utmi_ll_enable_bus_clock(false); diff --git a/components/esp_hal_usb/usb_wrap_hal.c b/components/esp_hal_usb/usb_wrap_hal.c index d0218ead6f..94cfd15c54 100644 --- a/components/esp_hal_usb/usb_wrap_hal.c +++ b/components/esp_hal_usb/usb_wrap_hal.c @@ -1,11 +1,9 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ -#include "soc/soc_caps.h" -#include "hal/usb_wrap_ll.h" #include "hal/usb_wrap_hal.h" void _usb_wrap_hal_init(usb_wrap_hal_context_t *hal) 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 11e0559833..05af37abeb 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-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32-H4 | ESP32-P4 | ESP32-S2 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | -------- | --------- | # USB: PHY sanity checks diff --git a/components/esp_hw_support/test_apps/usb_phy/main/test_app_main.c b/components/esp_hw_support/test_apps/usb_phy/main/test_app_main.c index d8c9119f73..071581bdfe 100644 --- a/components/esp_hw_support/test_apps/usb_phy/main/test_app_main.c +++ b/components/esp_hw_support/test_apps/usb_phy/main/test_app_main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: CC0-1.0 */ @@ -8,12 +8,12 @@ #include "unity_test_runner.h" #include "unity_test_utils_memory.h" #include "esp_private/usb_phy.h" -#include "hal/usb_wrap_ll.h" // For USB_WRAP_LL_EXT_PHY_SUPPORTED symbol -#include "soc/soc_caps.h" // For SOC_USB_UTMI_PHY_NUM symbol +#include "soc/soc_caps.h" #include "sdkconfig.h" // For CONFIG_IDF_TARGET_*** -#if USB_WRAP_LL_EXT_PHY_SUPPORTED -#define EXT_PHY_SUPPORTED 1 +#if (SOC_USB_FSLS_PHY_NUM > 0) +#include "hal/usb_wrap_ll.h" +#define EXT_PHY_SUPPORTED USB_WRAP_LL_EXT_PHY_SUPPORTED #else #define EXT_PHY_SUPPORTED 0 #endif @@ -24,6 +24,18 @@ #define UTMI_PHY_SUPPORTED 0 #endif +#if CONFIG_IDF_TARGET_ESP32S31 +#define INT_PHY_ALIASES_UTMI 1 +#else +#define INT_PHY_ALIASES_UTMI 0 +#endif + +#if (SOC_USB_FSLS_PHY_NUM > 0) || INT_PHY_ALIASES_UTMI +#define INT_PHY_SUPPORTED 1 +#else +#define INT_PHY_SUPPORTED 0 +#endif + void setUp(void) { unity_utils_record_free_mem(); @@ -55,12 +67,15 @@ void app_main(void) } /** - * Test init and deinit of internal FSLS PHY + * Test init and deinit of the internal PHY target + * + * On UTMI-only targets, the internal PHY target can be mapped to UTMI for + * backward compatibility. * * 1. Init + deinit in Host mode * 2. Init + deinit in Device mode */ -TEST_CASE("Init internal FSLS PHY", "[phy]") +TEST_CASE("Init internal PHY target", "[phy]") { // Host mode usb_phy_handle_t phy_handle = NULL; @@ -72,9 +87,14 @@ TEST_CASE("Init internal FSLS PHY", "[phy]") .ext_io_conf = NULL, .otg_io_conf = NULL, }; +#if INT_PHY_SUPPORTED TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle)); TEST_ASSERT_NOT_NULL(phy_handle); TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle)); +#else + TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle)); + TEST_ASSERT_NULL(phy_handle); +#endif // Device mode usb_phy_handle_t phy_handle_2 = NULL; @@ -86,9 +106,14 @@ TEST_CASE("Init internal FSLS PHY", "[phy]") .ext_io_conf = NULL, .otg_io_conf = NULL, }; +#if INT_PHY_SUPPORTED TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config_2, &phy_handle_2)); TEST_ASSERT_NOT_NULL(phy_handle_2); TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle_2)); +#else + TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_new_phy(&phy_config_2, &phy_handle_2)); + TEST_ASSERT_NULL(phy_handle_2); +#endif } /** @@ -156,10 +181,14 @@ TEST_CASE("Init internal UTMI PHY", "[phy]") } /** - * Test init and deinit of all PHYs at the same time multiple times + * Test init and deinit of all available PHY targets multiple times */ TEST_CASE("Init all PHYs in a loop", "[phy]") { +#if !INT_PHY_SUPPORTED + TEST_IGNORE_MESSAGE("Internal PHY target is not supported on this target"); +#endif + for (int i = 0; i < 2; i++) { usb_phy_handle_t phy_handle = NULL; usb_phy_handle_t phy_handle_2 = NULL; @@ -174,11 +203,14 @@ TEST_CASE("Init all PHYs in a loop", "[phy]") TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle)); TEST_ASSERT_NOT_NULL(phy_handle); - // Our current targets support either UTMI or external PHY - // so if/else suffice here -#if UTMI_PHY_SUPPORTED + // UTMI-only targets can alias the internal PHY target to UTMI, in + // which case a second UTMI allocation must fail because it is the same + // physical PHY instance. +#if UTMI_PHY_SUPPORTED && !INT_PHY_ALIASES_UTMI phy_config.target = USB_PHY_TARGET_UTMI; -#else + TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle_2)); + TEST_ASSERT_NOT_NULL(phy_handle_2); +#elif EXT_PHY_SUPPORTED phy_config.target = USB_PHY_TARGET_EXT; const usb_phy_ext_io_conf_t ext_io_conf = { // Some random values .vp_io_num = 1, @@ -191,12 +223,18 @@ TEST_CASE("Init all PHYs in a loop", "[phy]") .fs_edge_sel_io_num = 1, }; phy_config.ext_io_conf = &ext_io_conf; -#endif TEST_ASSERT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle_2)); TEST_ASSERT_NOT_NULL(phy_handle_2); +#elif INT_PHY_ALIASES_UTMI + phy_config.target = USB_PHY_TARGET_UTMI; + TEST_ASSERT_NOT_EQUAL(ESP_OK, usb_new_phy(&phy_config, &phy_handle_2)); + TEST_ASSERT_NULL(phy_handle_2); +#endif TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle)); - TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle_2)); + if (phy_handle_2) { + TEST_ASSERT_EQUAL(ESP_OK, usb_del_phy(phy_handle_2)); + } } } diff --git a/components/esp_hw_support/usb_phy/usb_phy.c b/components/esp_hw_support/usb_phy/usb_phy.c index 543c1310b8..c95e764d04 100644 --- a/components/esp_hw_support/usb_phy/usb_phy.c +++ b/components/esp_hw_support/usb_phy/usb_phy.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -25,6 +25,12 @@ #include "esp_sleep.h" #endif +#if (SOC_USB_FSLS_PHY_NUM > 0) +#define USB_PHY_FSLS_EXT_PHY_SUPPORTED USB_WRAP_LL_EXT_PHY_SUPPORTED +#else +#define USB_PHY_FSLS_EXT_PHY_SUPPORTED 0 +#endif + static const char *USBPHY_TAG = "usb_phy"; #define USBPHY_NOT_INIT_ERR_STR "USB_PHY is not initialized" @@ -37,7 +43,9 @@ struct phy_context_t { usb_phy_status_t status; /**< PHY status */ usb_otg_mode_t otg_mode; /**< USB OTG mode */ usb_phy_ext_io_conf_t *iopins; /**< external PHY I/O pins */ +#if (SOC_USB_FSLS_PHY_NUM > 0) usb_wrap_hal_context_t wrap_hal; /**< USB WRAP HAL context */ +#endif }; typedef struct { @@ -138,24 +146,15 @@ esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode) // we support only fixed PHY to USB-DWC mapping: // USB-DWC2.0 <-> UTMI PHY // USB-DWC1.1 <-> FSLS PHY +#if (SOC_USB_UTMI_PHY_NUM > 0) if (handle->target == USB_PHY_TARGET_UTMI) { - // ESP32-P4 v3 changed connection between USB-OTG peripheral and UTMI PHY. - // On v3 the 15k pulldown resistors on D+/D- are no longer controlled by USB-OTG, - // but must be controlled directly by this software driver. -#if CONFIG_IDF_TARGET_ESP32P4 && !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 -#include "soc/lp_system_struct.h" - if (mode == USB_OTG_MODE_HOST) { - // Host must connect 15k pulldown resistors on D+ / D- - LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dppulldown = 1; - LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dmpulldown = 1; - } else { - // Device must not connect any pulldown resistors on D+ / D- - LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dppulldown = 0; - LP_SYS.hp_usb_otghs_phy_ctrl.hp_utmiotg_dmpulldown = 0; - } -#endif // !CONFIG_ESP32P4_SELECTS_REV_LESS_V3 + // On some targets, the 15k pulldown resistors on D+/D- are not controlled + // by the USB-OTG peripheral, but must be controlled by software. + // Host mode: connect pulldowns; Device mode: disconnect pulldowns. + usb_utmi_hal_enable_data_pulldowns(mode == USB_OTG_MODE_HOST); return ESP_OK; } +#endif const usb_otg_signal_conn_t *otg_sig = usb_dwc_info.controllers[otg11_index].otg_signals; assert(otg_sig); @@ -164,6 +163,7 @@ esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode) gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->bvalid, GPIO_MATRIX_CONST_ZERO_INPUT, false); gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->vbusvalid, GPIO_MATRIX_CONST_ONE_INPUT, false); // receiving a valid Vbus from host gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->avalid, GPIO_MATRIX_CONST_ONE_INPUT, false); // HIGH to force USB host mode +#if (SOC_USB_FSLS_PHY_NUM > 0) if (handle->target == USB_PHY_TARGET_INT) { // Configure pull resistors for host usb_wrap_pull_override_vals_t vals = { @@ -174,6 +174,7 @@ esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode) }; usb_wrap_hal_phy_enable_pull_override(&handle->wrap_hal, &vals); } +#endif } else if (mode == USB_OTG_MODE_DEVICE) { gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->iddig, GPIO_MATRIX_CONST_ONE_INPUT, false); // connected connector is mini-B side gpio_ll_set_input_signal_matrix_source(GPIO_LL_GET_HW(0), otg_sig->bvalid, GPIO_MATRIX_CONST_ONE_INPUT, false); // HIGH to force USB device mode @@ -233,6 +234,18 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r } #endif +#if CONFIG_IDF_TARGET_ESP32S31 + /* + * ESP32-S31 exposes only the UTMI PHY to the USB OTG controller. + * Keep backward compatibility with applications that still request + * the legacy internal PHY target by aliasing it to UTMI. + */ + if (config->controller == USB_PHY_CTRL_OTG && phy_target == USB_PHY_TARGET_INT) { + ESP_LOGW(USBPHY_TAG, "Using UTMI PHY instead of requested internal PHY"); + phy_target = USB_PHY_TARGET_UTMI; + } +#endif + #if SOC_USB_UTMI_PHY_NO_POWER_OFF_ISO if (phy_target == USB_PHY_TARGET_UTMI) { esp_deep_sleep_register_hook(&sleep_usb_suppress_deepsleep_leakage); @@ -243,7 +256,10 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r ESP_RETURN_ON_FALSE(phy_target < USB_PHY_TARGET_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified PHY argument is invalid"); ESP_RETURN_ON_FALSE(config->controller < USB_PHY_CTRL_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified source argument is invalid"); ESP_RETURN_ON_FALSE(phy_target != USB_PHY_TARGET_EXT || config->ext_io_conf, ESP_ERR_INVALID_ARG, USBPHY_TAG, "ext_io_conf must be provided for ext PHY"); -#if !USB_WRAP_LL_EXT_PHY_SUPPORTED +#if !SOC_USB_FSLS_PHY_NUM + ESP_RETURN_ON_FALSE(phy_target != USB_PHY_TARGET_INT, ESP_ERR_NOT_SUPPORTED, USBPHY_TAG, "Internal FSLS PHY not supported on this target"); + ESP_RETURN_ON_FALSE(phy_target != USB_PHY_TARGET_EXT, ESP_ERR_NOT_SUPPORTED, USBPHY_TAG, "Ext PHY not supported on this target"); +#elif !USB_PHY_FSLS_EXT_PHY_SUPPORTED ESP_RETURN_ON_FALSE(phy_target != USB_PHY_TARGET_EXT, ESP_ERR_NOT_SUPPORTED, USBPHY_TAG, "Ext PHY not supported on this target"); #endif #if !SOC_USB_UTMI_PHY_NUM @@ -276,20 +292,26 @@ esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_r phy_context->controller = config->controller; phy_context->status = USB_PHY_STATUS_IN_USE; +#if (SOC_USB_FSLS_PHY_NUM > 0) if (phy_target != USB_PHY_TARGET_UTMI) { PERIPH_RCC_ATOMIC() { usb_wrap_hal_init(&phy_context->wrap_hal); } } else { -#if (SOC_USB_UTMI_PHY_NUM > 0) - usb_utmi_hal_context_t utmi_hal_context; // Unused for now - PERIPH_RCC_ATOMIC() { - usb_utmi_hal_init(&utmi_hal_context); - } #endif + if (phy_target == USB_PHY_TARGET_UTMI) { +#if (SOC_USB_UTMI_PHY_NUM > 0) + usb_utmi_hal_context_t utmi_hal_context; // Unused for now + PERIPH_RCC_ATOMIC() { + usb_utmi_hal_init(&utmi_hal_context); + } +#endif + } +#if (SOC_USB_FSLS_PHY_NUM > 0) } +#endif if (config->controller == USB_PHY_CTRL_OTG) { -#if USB_WRAP_LL_EXT_PHY_SUPPORTED +#if USB_PHY_FSLS_EXT_PHY_SUPPORTED usb_wrap_hal_phy_set_external(&phy_context->wrap_hal, (phy_target == USB_PHY_TARGET_EXT)); #endif } @@ -345,7 +367,9 @@ static void phy_uninstall(void) p_phy_ctrl_obj = NULL; PERIPH_RCC_ATOMIC() { // Disable USB peripheral without reset the module +#if (SOC_USB_FSLS_PHY_NUM > 0) usb_wrap_hal_disable(); +#endif #if (SOC_USB_UTMI_PHY_NUM > 0) usb_utmi_hal_disable(); #endif @@ -363,10 +387,12 @@ esp_err_t usb_del_phy(usb_phy_handle_t handle) p_phy_ctrl_obj->ref_count--; if (handle->target == USB_PHY_TARGET_EXT) { p_phy_ctrl_obj->external_phy = NULL; +#if (SOC_USB_FSLS_PHY_NUM > 0) } else if (handle->target == USB_PHY_TARGET_INT) { // Clear pullup and pulldown loads on D+ / D-, and disable the pads usb_wrap_hal_phy_disable_pull_override(&handle->wrap_hal); p_phy_ctrl_obj->fsls_phy = NULL; +#endif } else { // USB_PHY_TARGET_UTMI p_phy_ctrl_obj->utmi_phy = NULL; } diff --git a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in index 10f1cf84e6..c97a20edaa 100644 --- a/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32h4/include/soc/Kconfig.soc_caps.in @@ -1159,6 +1159,10 @@ config SOC_USB_OTG_PERIPH_NUM int default 1 +config SOC_USB_FSLS_PHY_NUM + int + default 1 + config SOC_ASRC_SUPPORTED bool default y diff --git a/components/soc/esp32h4/include/soc/soc_caps.h b/components/soc/esp32h4/include/soc/soc_caps.h index f6de827b8b..74aef76b99 100644 --- a/components/soc/esp32h4/include/soc/soc_caps.h +++ b/components/soc/esp32h4/include/soc/soc_caps.h @@ -543,6 +543,7 @@ /*-------------------------- USB CAPS ----------------------------------------*/ #define SOC_USB_OTG_PERIPH_NUM (1U) +#define SOC_USB_FSLS_PHY_NUM (1U) /*---------------------------------- ASRC CAPS ----------------------------------*/ #define SOC_ASRC_SUPPORTED (1) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 5d09e5d5ac..338930d1c4 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1163,6 +1163,10 @@ config SOC_USB_OTG_PERIPH_NUM int default 2 +config SOC_USB_FSLS_PHY_NUM + int + default 1 + config SOC_USB_UTMI_PHY_NUM int default 1 diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index f2c4403265..cb269c9c26 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -430,6 +430,7 @@ // USB OTG Caps #define SOC_USB_OTG_PERIPH_NUM (2U) +#define SOC_USB_FSLS_PHY_NUM (1U) // USB PHY Caps #define SOC_USB_UTMI_PHY_NUM (1U) diff --git a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in index a469825836..87efef0536 100644 --- a/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s2/include/soc/Kconfig.soc_caps.in @@ -707,6 +707,10 @@ config SOC_USB_OTG_PERIPH_NUM int default 1 +config SOC_USB_FSLS_PHY_NUM + int + default 1 + config SOC_SHA_DMA_MAX_BUFFER_SIZE int default 3968 diff --git a/components/soc/esp32s2/include/soc/soc_caps.h b/components/soc/esp32s2/include/soc/soc_caps.h index a2017850d6..2621012d4e 100644 --- a/components/soc/esp32s2/include/soc/soc_caps.h +++ b/components/soc/esp32s2/include/soc/soc_caps.h @@ -325,6 +325,7 @@ /*-------------------------- USB CAPS ----------------------------------------*/ #define SOC_USB_OTG_PERIPH_NUM (1U) +#define SOC_USB_FSLS_PHY_NUM (1U) /*--------------------------- SHA CAPS ---------------------------------------*/ /* Max amount of bytes in a single DMA operation is 4095, diff --git a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in index 254414f368..fe0a48c1b4 100644 --- a/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s3/include/soc/Kconfig.soc_caps.in @@ -803,6 +803,10 @@ config SOC_USB_OTG_PERIPH_NUM int default 1 +config SOC_USB_FSLS_PHY_NUM + int + default 1 + config SOC_SHA_DMA_MAX_BUFFER_SIZE int default 3968 diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index f219121458..d12fc77af9 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -337,6 +337,7 @@ /*-------------------------- USB CAPS ----------------------------------------*/ #define SOC_USB_OTG_PERIPH_NUM (1U) +#define SOC_USB_FSLS_PHY_NUM (1U) /*--------------------------- SHA CAPS ---------------------------------------*/ /* Max amount of bytes in a single DMA operation is 4095, diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index c6dda3dd63..0055bf514d 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -43,6 +43,10 @@ config SOC_ASYNC_MEMCPY_SUPPORTED bool default y +config SOC_USB_OTG_SUPPORTED + bool + default y + config SOC_EFUSE_KEY_PURPOSE_FIELD bool default y @@ -131,6 +135,18 @@ config SOC_REGI2C_SUPPORTED bool default y +config SOC_USB_OTG_PERIPH_NUM + int + default 1 + +config SOC_USB_FSLS_PHY_NUM + int + default 0 + +config SOC_USB_UTMI_PHY_NUM + int + default 1 + config SOC_XTAL_SUPPORT_40M bool default y diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 1f641a41b5..e6113dd6c5 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -44,7 +44,7 @@ #define SOC_ETM_SUPPORTED 1 // #define SOC_PARLIO_SUPPORTED 1 // TODO: [ESP32S31] IDF-14711 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 -// #define SOC_USB_OTG_SUPPORTED 1 // TODO: [ESP32S31] IDF-14701 +#define SOC_USB_OTG_SUPPORTED 1 // #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 // TODO: [ESP32S31] IDF-14788 // #define SOC_TEMP_SENSOR_SUPPORTED 1 // TODO: [ESP32S31] IDF-14799 // #define SOC_SUPPORTS_SECURE_DL_MODE 1 // TODO: [ESP32S31] IDF-14629 @@ -102,6 +102,11 @@ #define SOC_CORDIC_SUPPORTED 1 #define SOC_REGI2C_SUPPORTED 1 +/*-------------------------- USB CAPS ----------------------------------------*/ +#define SOC_USB_OTG_PERIPH_NUM (1U) +#define SOC_USB_FSLS_PHY_NUM (0U) +#define SOC_USB_UTMI_PHY_NUM (1U) + /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 diff --git a/components/soc/esp32s31/include/soc/usb_dwc_struct.h b/components/soc/esp32s31/include/soc/usb_dwc_struct.h new file mode 100644 index 0000000000..7b2e0b08c9 --- /dev/null +++ b/components/soc/esp32s31/include/soc/usb_dwc_struct.h @@ -0,0 +1,1378 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* +Registers and fields were generated based on a set of USB-DWC configuration options. +ESP32-S31 uses the High Speed USB-DWC register layout with a single controller instance. + +List of changes v4.00a -> v4.30a +- GRSTCTL register now contains the CSftRstDone bit which indicates the completion of a soft reset. +*/ + +/* ---------------------------- 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; + +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 ddrsel: 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 ulpifsls: 1; + uint32_t ulpiautores: 1; + uint32_t ulpiclksusm: 1; + uint32_t ulpiextvbusdrv: 1; + uint32_t ulpiextvbusindicator: 1; + uint32_t termseldlpulse: 1; + uint32_t complement: 1; + uint32_t indicator: 1; + uint32_t ulpi: 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: 18; + uint32_t csftrstdone: 1; + 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 regdata: 8; + uint32_t vctrl: 8; + uint32_t regaddr: 6; + uint32_t regwr: 1; + uint32_t reserved_23: 2; + uint32_t newregreq: 1; + uint32_t vstsbsy: 1; + uint32_t vstsdone: 1; + uint32_t reserved_28: 3; + uint32_t disulpidrvr: 1; + }; + uint32_t val; +} usb_dwc_gpvndctl_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 pmuintsel: 1; + uint32_t pmuactv: 1; + uint32_t reserved_2: 1; + uint32_t pwrdnclmp: 1; + uint32_t pwrdnrst_n: 1; + uint32_t pwrdnswtch: 1; + uint32_t disablevbus: 1; + uint32_t reserved_7: 1; + uint32_t reserved_8: 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: 1; + uint32_t srpdetect: 1; + uint32_t srpdetectmsk: 1; + uint32_t stschngint: 1; + uint32_t stschngintmsk: 1; + uint32_t linestate: 2; + uint32_t iddig: 1; + uint32_t bsessvld: 1; + uint32_t adpint: 1; + uint32_t reserved_24: 5; + uint32_t reserved_29: 3; + }; + uint32_t val; +} usb_dwc_gpwrdn_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 prbdschg: 2; + uint32_t prbdelta: 2; + uint32_t prbper: 2; + uint32_t rtim: 11; + uint32_t enaprb: 1; + uint32_t enasns: 1; + uint32_t adpres: 1; + uint32_t adpen: 1; + uint32_t adpprbint: 1; + uint32_t adpsnsint: 1; + uint32_t adptoutint: 1; + uint32_t adpprbintmsk: 1; + uint32_t adpsnsintmsk: 1; + uint32_t adptoutmsk: 1; + uint32_t ar: 2; + uint32_t reserved_29: 3; + }; + uint32_t val; +} usb_dwc_gadpctl_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: 16; + uint32_t reserved_16: 16; + }; + uint32_t val; +} usb_dwc_haint_reg_t; + +typedef union { + struct { + uint32_t haintmsk: 16; + uint32_t reserved_16: 16; + }; + 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 prtaddr: 7; + uint32_t hubaddr: 7; + uint32_t xactpos: 2; + uint32_t compsplt: 1; + uint32_t reserved_17: 14; + uint32_t spltena: 1; + }; + uint32_t val; +} usb_dwc_hcsplt_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; // Note: Width depends on OTG_TRANS_COUNT_WIDTH (see databook). + uint32_t pktcnt: 10; // Note: Width depends on OTG_PACKET_COUNT_WIDTH (see databook). + 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 inepint7: 1; + uint32_t inepint8: 1; + uint32_t inepint9: 1; + uint32_t inepint10: 1; + uint32_t inepint11: 1; + uint32_t inepint12: 1; + uint32_t inepint13: 1; + uint32_t inepint14: 1; + uint32_t inepint15: 1; + 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 outepint7: 1; + uint32_t outepint8: 1; + uint32_t outepint9: 1; + uint32_t outepint10: 1; + uint32_t outepint11: 1; + uint32_t outepint12: 1; + uint32_t outepint13: 1; + uint32_t outepint14: 1; + uint32_t outepint15: 1; + }; + 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 inepmsk7: 1; + uint32_t inepmsk8: 1; + uint32_t inepmsk9: 1; + uint32_t inepmsk10: 1; + uint32_t inepmsk11: 1; + uint32_t inepmsk12: 1; + uint32_t inepmsk13: 1; + uint32_t inepmsk14: 1; + uint32_t inepmsk15: 1; + 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 outepmsk7: 1; + uint32_t outepmsk8: 1; + uint32_t outepmsk9: 1; + uint32_t outepmsk10: 1; + uint32_t outepmsk11: 1; + uint32_t outepmsk12: 1; + uint32_t outepmsk13: 1; + uint32_t outepmsk14: 1; + uint32_t outepmsk15: 1; + }; + 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 echinepint: 16; + uint32_t echoutepint: 16; + }; + uint32_t val; +} usb_dwc_deachint_reg_t; + +typedef union { + struct { + uint32_t echinepmsk0: 1; + uint32_t echinepmsk1: 1; + uint32_t echinepmsk2: 1; + uint32_t echinepmsk3: 1; + uint32_t echinepmsk4: 1; + uint32_t echinepmsk5: 1; + uint32_t echinepmsk6: 1; + uint32_t echinepmsk7: 1; + uint32_t echinepmsk8: 1; + uint32_t echinepmsk9: 1; + uint32_t echinepmsk10: 1; + uint32_t echinepmsk11: 1; + uint32_t echinepmsk12: 1; + uint32_t echinepmsk13: 1; + uint32_t echinepmsk14: 1; + uint32_t echinepmsk15: 1; + uint32_t echoutepmsk0: 1; + uint32_t echoutepmsk1: 1; + uint32_t echoutepmsk2: 1; + uint32_t echoutepmsk3: 1; + uint32_t echoutepmsk4: 1; + uint32_t echoutepmsk5: 1; + uint32_t echoutepmsk6: 1; + uint32_t echoutepmsk7: 1; + uint32_t echoutepmsk8: 1; + uint32_t echoutepmsk9: 1; + uint32_t echoutepmsk10: 1; + uint32_t echoutepmsk11: 1; + uint32_t echoutepmsk12: 1; + uint32_t echoutepmsk13: 1; + uint32_t echoutepmsk14: 1; + uint32_t echoutepmsk15: 1; + }; + uint32_t val; +} usb_dwc_deachintmsk_reg_t; + +typedef union { + struct { + uint32_t xfercomplmsl: 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_diepeachmski_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 reserved_5: 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_doepeachmski_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; // Note: Width depends on OTG_TRANS_COUNT_WIDTH (see databook). + uint32_t pktcnt: 10; // Note: Width depends on OTG_PACKET_COUNT_WIDTH (see databook). + 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; // Note: Width depends on OTG_TRANS_COUNT_WIDTH (see databook). + uint32_t pktcnt: 10; // Note: Width depends on OTG_PACKET_COUNT_WIDTH (see databook). + 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; + +/* --------------------------- Register Groups ------------------------------ */ + +typedef struct { + volatile usb_dwc_hcchar_reg_t hcchar_reg; // 0x00 + volatile usb_dwc_hcsplt_reg_t hcsplt_reg; // 0x04 + volatile usb_dwc_hcint_reg_t hcint_reg; // 0x08 + volatile usb_dwc_hcintmsk_reg_t hcintmsk_reg; // 0x0c + volatile usb_dwc_hctsiz_reg_t hctsiz_reg; // 0x10 + volatile usb_dwc_hcdma_reg_t hcdma_reg; // 0x14 + uint32_t reserved_0x18[1]; // 0x18 + volatile usb_dwc_hcdmab_reg_t hcdmab_reg; // 0x1c +} usb_dwc_host_chan_regs_t; + +typedef struct { + volatile usb_dwc_diepctl_reg_t diepctl_reg; // 0x00 + uint32_t reserved_0x04[1]; // 0x04 + volatile usb_dwc_diepint_reg_t diepint_reg; // 0x08 + uint32_t reserved_0x0c[1]; // 0x0c + volatile usb_dwc_dieptsiz_reg_t dieptsiz_reg; // 0x10 + volatile usb_dwc_diepdma_reg_t diepdma_reg; // 0x14 + volatile usb_dwc_dtxfsts_reg_t dtxfsts_reg; // 0x18 + volatile usb_dwc_diepdmab_reg_t diepdmab_reg; // 0x1c +} usb_dwc_in_ep_regs_t; + +typedef struct { + volatile usb_dwc_doepctl_reg_t doepctl_reg; // 0x00 + uint32_t reserved_0x04[1]; // 0x04 + volatile usb_dwc_doepint_reg_t doepint_reg; // 0x08 + uint32_t reserved_0x0c[1]; // 0x0c + volatile usb_dwc_doeptsiz_reg_t doeptsiz_reg; // 0x10 + volatile usb_dwc_doepdma_reg_t doepdma_reg; // 0x14 + uint32_t reserved_0x18[1]; // 0x18 + volatile usb_dwc_doepdmab_reg_t doepdmab_reg; // 0x1c +} usb_dwc_out_ep_regs_t; + +/* --------------------------- Register Layout ------------------------------ */ + +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 + volatile usb_dwc_gpvndctl_reg_t gpvndctl_reg; // 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 + volatile usb_dwc_gpwrdn_reg_t gpwrdn_reg; // 0x0058 + volatile usb_dwc_gdfifocfg_reg_t gdfifocfg_reg; // 0x005c + volatile usb_dwc_gadpctl_reg_t gadpctl_reg; // 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 dieptxfi_regs[7]; // 0x0104 to 0x011c (depends on OTG_NUM_IN_EPS) + usb_dwc_dieptxfi_reg_t reserved_0x0120_0x013c[8]; // 0x0120 to 0x013c (depends on OTG_NUM_IN_EPS) + 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[16]; // 0x0500 to 0x06fc (depends on OTG_NUM_HOST_CHAN) + uint32_t reserved_0x0704_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 + volatile usb_dwc_deachint_reg_t deachint_reg; // 0x0838 + volatile usb_dwc_deachintmsk_reg_t deachintmsk_reg; // 0x083c + volatile usb_dwc_diepeachmski_reg_t diepeachmsk0_reg; // 0x0840 + volatile usb_dwc_diepeachmski_reg_t diepeachmsk[15]; // 0x0844 to 0x087c (depends on OTG_NUM_EPS) + volatile usb_dwc_doepeachmski_reg_t doepeachmsk0_reg; // 0x0880 + volatile usb_dwc_doepeachmski_reg_t doepeachmsk[15]; // 0x0884 to 0x08c0 (depends on OTG_NUM_EPS) + 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[15]; // 0x0920 to 0x0afc (depends on OTG_NUM_EPS) + + // 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[15]; // 0x0b20 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_OTGHS; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32s31/ld/esp32s31.peripherals.ld b/components/soc/esp32s31/ld/esp32s31.peripherals.ld index 698f517a87..8e891d4fc1 100644 --- a/components/soc/esp32s31/ld/esp32s31.peripherals.ld +++ b/components/soc/esp32s31/ld/esp32s31.peripherals.ld @@ -19,6 +19,7 @@ PROVIDE ( RMTMEM = 0x20355800 ); PROVIDE ( BITSCRAMBLER = 0x20356000 ); PROVIDE ( ASRC = 0x20357000 ); PROVIDE ( CNNT_SYS_REG = 0x20359000 ); +PROVIDE ( USB_UTMI = 0x20380000 ); PROVIDE ( MCPWM0 = 0x20381000 ); PROVIDE ( MCPWM1 = 0x20382000 ); PROVIDE ( MCPWM2 = 0x20383000 ); diff --git a/components/soc/esp32s31/register/soc/usb_utmi_struct.h b/components/soc/esp32s31/register/soc/usb_utmi_struct.h new file mode 100644 index 0000000000..1a0b61efb7 --- /dev/null +++ b/components/soc/esp32s31/register/soc/usb_utmi_struct.h @@ -0,0 +1,229 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Following register description is taken from + * U2OPHYT40LL USB 2.0 OTG PHY specification v2.0 + */ + +typedef union { + struct { + /** clk_gate_rx : R/W; bitpos: [0]; default 2'b0; + * Clock Gating Control Signal for Rx. + * 2'b0 Lower power consumption + * 2'b1 Lowest power consumption mode + * 2'b2 Normal power consumption mode + */ + uint32_t clk_gate_rx: 2; + /** clk_gate_tx : R/W; bitpos: [2]; default: 1'b0; + * Clock Gating Control Signal for Rx. + * 1'b0 Low power consumption mode + * 1'b1 Normal power consumption mode + */ + uint32_t clk_gate_tx: 1; + /** adj_res_fs : Reserved; bitpos: [3]; default: 0; + * Fine tune the 45ohm termination resistor (FS) + * Reserved + */ + uint32_t adj_res_fs: 2; + /** adj_res_hs : R/W; bitpos: [5]; default: 3'b100; + * Fine tune the 45ohm termination resistor (HS) + * 3'b000 40 Ohm + * 3'b100 45 Ohm + * 3'b110 50 Ohm + */ + uint32_t adj_res_hs: 3; + uint32_t reserved_8: 24; + }; + uint32_t val; +} usb_utmi_fc_00_reg_t; + +typedef union { + struct { + /** adj_vref_sq : R/W; bitpos: [0]; default: 4'b0010; + * Squelch detection threshold voltage control bits + * 4'b0000 92 mV + * 4'b0010 124 mV + * 4'b0011 152 mV + */ + uint32_t adj_vref_sq: 4; + /** adj_pw_hs : R/W; bitpos: [4]; default: 4'b1111; + * Super power saving with reduced output swing mode control bits (for HS mode only) + * 4'b0001 100 mV output swing + * 4'b0011 200 mV output swing + * 4'b0111 300 mV output swing + * 4'b1111 400 mV output swing + */ + uint32_t adj_pw_hs: 4; + uint32_t reserved_8: 24; + }; + uint32_t val; +} usb_utmi_fc_01_reg_t; + +typedef union { + struct { + /** adj_iref_res : R/W; bitpos: [0]; default: 4'b0111 + * Internal bias current adjustment control bits + * 4'b0000 125 uA + * 4'b0111 100 uA + * 4'b1111 78 uA + */ + uint32_t adj_iref_res: 4; + /** adj_vsw_hs : R/W; bitpos: [4]; default: 3'b100 + * Output eye shape adjustment control bits + * 3'b000 320 mV + * 3'b100 400 mV + * 3'b111 460 mV + */ + uint32_t adj_vsw_hs: 3; + uint32_t reserved_7: 25; + }; + uint32_t val; +} usb_utmi_fc_02_reg_t; + +typedef union { + struct { + /** adj_pll : R/W; bitpos: [0]; default: 4'b0101 + * PLL adjustment signal + */ + uint32_t adj_pll: 4; + /** adj_osc : R/W; bitpos: [4]; default: 3'b000 + * TX Clock phase adjust signal + */ + uint32_t adj_txclk_phase: 3; + uint32_t reserved_7: 25; + }; + uint32_t val; +} usb_utmi_fc_03_reg_t; + +typedef union { + struct { + /** test_sel : R/W; bitpos: [0]; default: 8'b0 + * The PHY has test_sel register here, which normally drives DTO (Digital Test Output) signal. + * In our implementation output of this register is left floating and DTO is driven from Probe module. + * Thus writing to this register has no effect and is renamed to 'reserved' + */ + uint32_t reserved: 8; + uint32_t reserved_8: 24; + }; + uint32_t val; +} usb_utmi_fc_04_reg_t; + +typedef union { + struct { + /** rxgap_fix_en : R/W; bitpos: [0]; default: 1'b1 + * RXGAP fix enable + */ + uint32_t rxgap_fix_en: 1; + /** counter_sel : R/W; bitpos: [1]; default: 1'b0 + * SIE_input sample enable + */ + uint32_t counter_sel: 1; + /** clk_sel : R/W; bitpos: [2]; default: 1'b0 + * CLK60_30 source select + */ + uint32_t clk_sel: 1; + /** phy_mode_sel : R/W; bitpos: [3]; default: 1'b0 + * PHY MODE select + */ + uint32_t phy_mode_sel: 1; + /** uni_bidi_i : R/W; bitpos: [4]; default: 1'b0 + * UNI_BIDI signal + */ + uint32_t uni_bidi_i: 1; + /** short_5v : R/W; bitpos: [5]; default: 1'b0 + * SHORT_5V signal + */ + uint32_t short_5v: 1; + /** short_5v_enable : R/W; bitpos: [6]; default: 1'b1 + * SHORT_5V_ENABLE signal + */ + uint32_t short_5v_enable: 1; + /** usable_en : R/W; bitpos: [7]; default: 1'b1 + * compare_begin delay time select + */ + uint32_t usable_en: 1; + uint32_t reserved_8: 24; + }; + uint32_t val; +} usb_utmi_fc_05_reg_t; + +typedef union { + struct { + /** ls_par_en : R/W; bitpos: [0]; default: 1'b0 + * LS mode with parallel enable + */ + uint32_t ls_par_en: 1; + /** det_fseop_en : R/W; bitpos: [1]; default: 1'b0 + * FS EOP detect enable + */ + uint32_t det_fseop_en: 1; + /** pre_hphy_lsie : R/W; bitpos: [2]; default: 1'b0 + * Dis_preamble enable + */ + uint32_t pre_hphy_lsie: 1; + /** ls_kpalv_en : R/W; bitpos: [3]; default: 1'b0 + * LS mode keep alive enable + */ + uint32_t ls_kpalv_en: 1; + /** hs_tx2rx_dly_cnt_sel : R/W; bitpos: [4]; default: 3'b100 + * PHY High-SPeed bus turn-around time select + */ + uint32_t hs_tx2rx_dly_cnt_sel: 3; + uint32_t reserved_7: 25; + }; + uint32_t val; +} usb_utmi_fc_06_reg_t; + +typedef union { + struct { + /** cnt_num : R/W; bitpos: [1:0]; default: 2'b00 + * 3 ms counter select + * 00: 392us (Default) + * 01: 682us + * 10: 1.36ms + * 11: 2.72ms + */ + uint32_t cnt_num: 2; + /** clk480_sel : R/W; bitpos: [2]; default: 1'b0 + * CLK_480 output time select + * 0: CLK_480 is valid after a delay time when PLL is locked + * 1: CLK_480 is valid immediately after PLL is locked + */ + uint32_t clk480_sel: 1; + uint32_t reserved_3: 29; + }; + uint32_t val; +} usb_utmi_fc_07_reg_t; + +typedef struct usb_utmi_dev_t { + volatile usb_utmi_fc_00_reg_t fc_00; + volatile usb_utmi_fc_01_reg_t fc_01; + volatile usb_utmi_fc_02_reg_t fc_02; + volatile usb_utmi_fc_03_reg_t fc_03; + volatile usb_utmi_fc_04_reg_t fc_04; + volatile usb_utmi_fc_05_reg_t fc_05; + volatile usb_utmi_fc_06_reg_t fc_06; + volatile usb_utmi_fc_07_reg_t fc_07; +} usb_utmi_dev_t; + +extern usb_utmi_dev_t USB_UTMI; + +#ifndef __cplusplus +_Static_assert(sizeof(usb_utmi_dev_t) == 0x20, "Invalid size of usb_utmi_dev_t structure"); +#endif + +#ifdef __cplusplus +} +#endif diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index e9f63ce099..7abc2cf783 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -21,7 +21,7 @@ API Guides core_dump current-consumption-measurement-modules :ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB: deep-sleep-stub - :SOC_USB_OTG_SUPPORTED and not esp32h4: dfu + :SOC_USB_OTG_SUPPORTED and not esp32h4 and not esp32s31: dfu error-handling :SOC_WIFI_MESH_SUPPORT: esp-wifi-mesh :SOC_SPIRAM_SUPPORTED: external-ram @@ -46,7 +46,7 @@ API Guides tools/index unit-tests host-apps - :SOC_USB_OTG_SUPPORTED and not esp32p4 and not esp32h4: usb-otg-console + :SOC_USB_OTG_SUPPORTED and not esp32p4 and not esp32h4 and not esp32s31: usb-otg-console :SOC_USB_SERIAL_JTAG_SUPPORTED: usb-serial-jtag-console :SOC_WIFI_SUPPORTED: wifi-driver/index :SOC_WIFI_SUPPORTED: wifi-security diff --git a/docs/zh_CN/api-guides/index.rst b/docs/zh_CN/api-guides/index.rst index 69ec6e4134..4e0cf1ccad 100644 --- a/docs/zh_CN/api-guides/index.rst +++ b/docs/zh_CN/api-guides/index.rst @@ -21,7 +21,7 @@ API 指南 core_dump current-consumption-measurement-modules :ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB: deep-sleep-stub - :SOC_USB_OTG_SUPPORTED and not esp32h4: dfu + :SOC_USB_OTG_SUPPORTED and not esp32h4 and not esp32s31: dfu error-handling :SOC_WIFI_MESH_SUPPORT: esp-wifi-mesh :SOC_SPIRAM_SUPPORTED: external-ram @@ -46,7 +46,7 @@ API 指南 tools/index unit-tests host-apps - :SOC_USB_OTG_SUPPORTED and not esp32p4 and not esp32h4: usb-otg-console + :SOC_USB_OTG_SUPPORTED and not esp32p4 and not esp32h4 and not esp32s31: usb-otg-console :SOC_USB_SERIAL_JTAG_SUPPORTED: usb-serial-jtag-console :SOC_WIFI_SUPPORTED: wifi-driver/index :SOC_WIFI_SUPPORTED: wifi-security diff --git a/examples/peripherals/.build-test-rules.yml b/examples/peripherals/.build-test-rules.yml index 914bc63235..a712d5d59e 100644 --- a/examples/peripherals/.build-test-rules.yml +++ b/examples/peripherals/.build-test-rules.yml @@ -183,9 +183,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" + - if: IDF_TARGET in ["esp32h4", "esp32s31"] temporary: true - reason: usb_device_uac does not support esp32h4 + reason: usb_device_uac does not support esp32h4 or esp32s31 depends_components: - esp_driver_i2s - esp_driver_dma @@ -782,6 +782,9 @@ examples/peripherals/uart/uart_echo_rs485: examples/peripherals/usb/device: disable: - if: SOC_USB_OTG_SUPPORTED != 1 + - if: IDF_TARGET == "esp32s31" + temporary: true + reason: USB device examples do not support esp32s31 yet disable_test: - if: IDF_TARGET not in ["esp32s2", "esp32p4"] temporary: true @@ -796,9 +799,9 @@ examples/peripherals/usb/device: examples/peripherals/usb/device/cherryusb_serial_device: disable: - - if: (IDF_TARGET == "esp32h4") or (SOC_USB_OTG_SUPPORTED != 1) + - if: (IDF_TARGET in ["esp32h4", "esp32s31"]) or (SOC_USB_OTG_SUPPORTED != 1) temporary: true - reason: CherryUSB does not support esp32h4 + reason: CherryUSB does not support esp32h4 or esp32s31 examples/peripherals/usb/device/tusb_ncm: disable: @@ -816,6 +819,9 @@ examples/peripherals/usb/device/tusb_ncm: examples/peripherals/usb/host: disable: - if: SOC_USB_OTG_SUPPORTED != 1 + - if: IDF_TARGET == "esp32s31" + temporary: true + reason: USB host examples do not support esp32s31 yet disable_test: - if: IDF_TARGET not in ["esp32s3", "esp32p4"] temporary: true @@ -832,9 +838,9 @@ examples/peripherals/usb/host: examples/peripherals/usb/host/cherryusb_host: disable: - - if: (IDF_TARGET == "esp32h4") or (SOC_USB_OTG_SUPPORTED != 1) + - if: (IDF_TARGET in ["esp32h4", "esp32s31"]) or (SOC_USB_OTG_SUPPORTED != 1) temporary: true - reason: CherryUSB does not support esp32h4 + reason: CherryUSB does not support esp32h4 or esp32s31 examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo: disable: