diff --git a/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml b/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml index dca9ea6e5c5..14434dcd9c9 100644 --- a/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml +++ b/components/esp_driver_usb_serial_jtag/test_apps/.build-test-rules.yml @@ -7,7 +7,7 @@ components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag: temporary: true reason: p4 rev3 migration # TODO: IDF-14364 disable_test: - - if: IDF_TARGET in ["esp32c5", "esp32h4", "esp32h21"] + - if: IDF_TARGET in ["esp32c5", "esp32h4", "esp32h21", "esp32s31"] temporary: true reason: No runners. depends_components: @@ -25,7 +25,7 @@ components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs: temporary: true reason: p4 rev3 migration # TODO: IDF-14364 disable_test: - - if: IDF_TARGET in ["esp32c5", "esp32h4", "esp32h21"] + - if: IDF_TARGET in ["esp32c5", "esp32h4", "esp32h21", "esp32s31"] temporary: true reason: No runners. depends_components: diff --git a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md index f7cc913548f..ce613aa5e5d 100644 --- a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md +++ b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | --------- | diff --git a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs/README.md b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs/README.md index f7cc913548f..ce613aa5e5d 100644 --- a/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs/README.md +++ b/components/esp_driver_usb_serial_jtag/test_apps/usb_serial_jtag_vfs/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | --------- | diff --git a/components/esp_hal_usb/esp32s31/include/hal/usb_serial_jtag_ll.h b/components/esp_hal_usb/esp32s31/include/hal/usb_serial_jtag_ll.h new file mode 100644 index 00000000000..b933a4c646e --- /dev/null +++ b/components/esp_hal_usb/esp32s31/include/hal/usb_serial_jtag_ll.h @@ -0,0 +1,364 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "esp_attr.h" +#include "soc/cnnt_sys_struct.h" +#include "soc/lp_system_struct.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/usb_serial_jtag_struct.h" +#include "hal/usb_serial_jtag_types.h" +#include "hal/misc.h" + +/* ----------------------------- Macros & Types ----------------------------- */ + +#define USB_SERIAL_JTAG_LL_SELECT_PHY_SUPPORTED 1 // Can route to an external FSLS PHY + +#define USB_SERIAL_JTAG_LL_INTR_MASK (0x7ffff) // All interrupts mask + +// Define USB_SERIAL_JTAG interrupts +// Note the hardware has more interrupts, but they're only useful for debugging +// the hardware. +typedef enum { + USB_SERIAL_JTAG_INTR_SOF = (1 << 1), + USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT = (1 << 2), + USB_SERIAL_JTAG_INTR_SERIAL_IN_EMPTY = (1 << 3), + USB_SERIAL_JTAG_INTR_TOKEN_REC_IN_EP1 = (1 << 8), + USB_SERIAL_JTAG_INTR_BUS_RESET = (1 << 9), + USB_SERIAL_JTAG_INTR_EP1_ZERO_PAYLOAD = (1 << 10), +} usb_serial_jtag_ll_intr_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----------------------------- USJ Peripheral ----------------------------- */ + +/** + * @brief Enable the USB_SERIAL_JTAG interrupt based on the given mask. + * + * @param mask The bitmap of the interrupts need to be enabled. + * + * @return None + */ +static inline void usb_serial_jtag_ll_ena_intr_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.int_ena.val |= mask; +} + +/** + * @brief Disable the USB_SERIAL_JTAG interrupt based on the given mask. + * + * @param mask The bitmap of the interrupts need to be disabled. + * + * @return None + */ +static inline void usb_serial_jtag_ll_disable_intr_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.int_ena.val &= (~mask); +} + +/** + * @brief Get the USB_SERIAL_JTAG interrupt status. + * + * @return The USB_SERIAL_JTAG interrupt status. + */ +static inline uint32_t usb_serial_jtag_ll_get_intsts_mask(void) +{ + return USB_SERIAL_JTAG.int_st.val; +} + +/** + * @brief Get the USB_SERIAL_JTAG raw interrupt status. + * + * @return The USB_SERIAL_JTAG raw interrupt status. + */ +static inline __attribute__((always_inline)) uint32_t usb_serial_jtag_ll_get_intraw_mask(void) +{ + return USB_SERIAL_JTAG.int_raw.val; +} + +/** + * @brief Clear the USB_SERIAL_JTAG interrupt status based on the given mask. + * + * @param mask The bitmap of the interrupts need to be cleared. + * + * @return None + */ +static inline __attribute__((always_inline)) void usb_serial_jtag_ll_clr_intsts_mask(uint32_t mask) +{ + USB_SERIAL_JTAG.int_clr.val = mask; +} + +/** + * @brief Get status of enabled interrupt. + * + * @return interrupt enable value + */ +static inline uint32_t usb_serial_jtag_ll_get_intr_ena_status(void) +{ + return USB_SERIAL_JTAG.int_ena.val; +} + +/** + * @brief Read the bytes from the USB_SERIAL_JTAG rxfifo. + * + * @param buf The data buffer. + * @param rd_len The data length needs to be read. + * + * @return amount of bytes read + */ +static inline int usb_serial_jtag_ll_read_rxfifo(uint8_t *buf, uint32_t rd_len) +{ + int i; + for (i = 0; i < (int)rd_len; i++) { + if (!USB_SERIAL_JTAG.ep1_conf.serial_out_ep_data_avail) { + break; + } + buf[i] = USB_SERIAL_JTAG.ep1.val; + } + return i; +} + +/** + * @brief Write byte to the USB_SERIAL_JTAG txfifo. Only writes bytes as long / if there + * is room in the buffer. + * + * @param buf The data buffer. + * @param wr_len The data length needs to be written. + * + * @return Amount of bytes actually written. May be less than wr_len. + */ +static inline int usb_serial_jtag_ll_write_txfifo(const uint8_t *buf, uint32_t wr_len) +{ + int i; + for (i = 0; i < (int)wr_len; i++) { + if (!USB_SERIAL_JTAG.ep1_conf.serial_in_ep_data_free) { + break; + } + USB_SERIAL_JTAG.ep1.val = buf[i]; + } + return i; +} + +/** + * @brief Returns 1 if the USB_SERIAL_JTAG rxfifo has data available. + * + * @return 0 if no data available, 1 if data available + */ +static inline int usb_serial_jtag_ll_rxfifo_data_available(void) +{ + return USB_SERIAL_JTAG.ep1_conf.serial_out_ep_data_avail; +} + +/** + * @brief Returns 1 if the USB_SERIAL_JTAG txfifo has room. + * + * @return 0 if no data available, 1 if data available + */ +static inline int usb_serial_jtag_ll_txfifo_writable(void) +{ + return USB_SERIAL_JTAG.ep1_conf.serial_in_ep_data_free; +} + +/** + * @brief Flushes the TX buffer, that is, make it available for the + * host to pick up. + * + * @note When fifo is full (with 64 byte), HW will flush the buffer automatically, + * if this function is called directly after, this effectively turns into a + * no-op. Because a 64-byte packet will be interpreted as a not-complete USB + * transaction, you need to transfer either more data or a zero-length packet + * for the data to actually end up at the program listening to the CDC-ACM + * serial port. To send a zero-length packet, call + * usb_serial_jtag_ll_txfifo_flush() again when + * usb_serial_jtag_ll_txfifo_writable() returns true. + * + * @return na + */ +static inline void usb_serial_jtag_ll_txfifo_flush(void) +{ + USB_SERIAL_JTAG.ep1_conf.wr_done = 1; +} + +/** + * @brief Enable USJ JTAG bridge + * + * If enabled, USJ is disconnected from internal JTAG interface. JTAG interface + * is routed through GPIO matrix instead. + * + * @param enable Enable USJ JTAG bridge + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_jtag_bridge(bool enable) +{ + USB_SERIAL_JTAG.conf0.usb_jtag_bridge_en = enable; +} + +/* ---------------------------- USB PHY Control ---------------------------- */ + +/** + * @brief Sets PHY defaults + * + * Some PHY register fields/features of the USJ are redundant on the ESP32-S31. + * This function those fields are set to the appropriate default values. + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_defaults(void) +{ + // External FSLS PHY is not supported + USB_SERIAL_JTAG.conf0.usb_pad_enable = 1; +} + +/** + * @brief Select the internal USB FSLS PHY for the USJ + * + * @param phy_idx Selected PHY's index + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_select(unsigned int phy_idx) +{ + // Enable SW control mapping USB_WRAP and USJ to USB FSLS PHY 0 and 1 + LP_SYS.usb_ctrl.sw_hw_usb_phy_sel = 1; + /* + For 'sw_usb_phy_sel': + False - USJ mapped to USB FSLS PHY 0, USB_WRAP mapped to USB FSLS PHY 1 + True - USJ mapped to USB FSLS PHY 1, USB_WRAP mapped to USB FSLS PHY 0 + */ + switch (phy_idx) { + case 0: + LP_SYS.usb_ctrl.sw_usb_phy_sel = false; + break; + case 1: + LP_SYS.usb_ctrl.sw_usb_phy_sel = true; + break; + default: + break; + } +} + +/** + * @brief Enables/disables exchanging of the D+/D- pins USB PHY + * + * @param enable Enables pin exchange, disabled otherwise + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_pin_exchg(bool enable) +{ + if (enable) { + USB_SERIAL_JTAG.conf0.exchg_pins = 1; + USB_SERIAL_JTAG.conf0.exchg_pins_override = 1; + } else { + USB_SERIAL_JTAG.conf0.exchg_pins_override = 0; + USB_SERIAL_JTAG.conf0.exchg_pins = 0; + } +} + +/** + * @brief Enables and sets voltage threshold overrides for USB FSLS PHY single-ended inputs + * + * @param vrefh_step High voltage threshold. 0 to 3 indicating 80mV steps from 1.76V to 2V. + * @param vrefl_step Low voltage threshold. 0 to 3 indicating 80mV steps from 0.8V to 1.04V. + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_vref_override(unsigned int vrefh_step, unsigned int vrefl_step) +{ + USB_SERIAL_JTAG.conf0.vrefh = vrefh_step; + USB_SERIAL_JTAG.conf0.vrefl = vrefl_step; + USB_SERIAL_JTAG.conf0.vref_override = 1; +} + +/** + * @brief Disables voltage threshold overrides for USB FSLS PHY single-ended inputs + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_disable_vref_override(void) +{ + USB_SERIAL_JTAG.conf0.vref_override = 0; +} + +/** + * @brief Enable override of USB FSLS PHY's pull up/down resistors + * + * @param vals Override values to set + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_pull_override(const usb_serial_jtag_pull_override_vals_t *vals) +{ + USB_SERIAL_JTAG.conf0.dp_pullup = vals->dp_pu; + USB_SERIAL_JTAG.conf0.dp_pulldown = vals->dp_pd; + USB_SERIAL_JTAG.conf0.dm_pullup = vals->dm_pu; + USB_SERIAL_JTAG.conf0.dm_pulldown = vals->dm_pd; + USB_SERIAL_JTAG.conf0.pad_pull_override = 1; +} + +/** + * @brief Disable override of USB FSLS PHY pull up/down resistors + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_disable_pull_override(void) +{ + USB_SERIAL_JTAG.conf0.pad_pull_override = 0; +} + +/** + * @brief Sets the strength of the pullup resistor + * + * @param strong True is a ~1.4K pullup, false is a ~2.4K pullup + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_set_pullup_strength(bool strong) +{ + USB_SERIAL_JTAG.conf0.pullup_value = strong; +} + +/** + * @brief Check if USB FSLS PHY pads are enabled + * + * @return True if enabled, false otherwise + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_phy_is_pad_enabled(void) +{ + return USB_SERIAL_JTAG.conf0.usb_pad_enable; +} + +/** + * @brief Enable the USB FSLS PHY pads + * + * @param enable Whether to enable the USB FSLS PHY pads + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_phy_enable_pad(bool enable) +{ + USB_SERIAL_JTAG.conf0.usb_pad_enable = enable; +} + +/* ----------------------------- RCC Functions ----------------------------- */ + +/** + * @brief Enable the bus clock for USJ module + * @param clk_en True if enable the clock of USJ module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_enable_bus_clock(bool clk_en) +{ + HP_SYS_CLKRST.usb_device_ctrl0.reg_usb_device_apb_clk_en = clk_en; + CNNT_SYS_REG.sys_hp_usb_device_ctrl.sys_usb_device_48m_clk_en = clk_en; +} + +/** + * @brief Reset the USJ module + */ +FORCE_INLINE_ATTR void usb_serial_jtag_ll_reset_register(void) +{ + CNNT_SYS_REG.sys_hp_usb_device_ctrl.sys_usb_device_rst_en = 1; + CNNT_SYS_REG.sys_hp_usb_device_ctrl.sys_usb_device_rst_en = 0; +} + +/** + * Get the enable status of the USJ module + * + * @return Return true if USJ module is enabled + */ +FORCE_INLINE_ATTR bool usb_serial_jtag_ll_module_is_enabled(void) +{ + return (HP_SYS_CLKRST.usb_device_ctrl0.reg_usb_device_apb_clk_en && CNNT_SYS_REG.sys_hp_usb_device_ctrl.sys_usb_device_48m_clk_en); +} + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 174d24e7528..a7e29fb4012 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -111,6 +111,10 @@ config SOC_TEMP_SENSOR_SUPPORTED bool default y +config SOC_USB_SERIAL_JTAG_SUPPORTED + bool + default y + config SOC_ULP_SUPPORTED bool default y diff --git a/components/soc/esp32s31/include/soc/interrupts.h b/components/soc/esp32s31/include/soc/interrupts.h index 6c19ab5e038..b0f27550f9f 100644 --- a/components/soc/esp32s31/include/soc/interrupts.h +++ b/components/soc/esp32s31/include/soc/interrupts.h @@ -18,7 +18,7 @@ extern "C" typedef enum { ETS_SYS_ICM_INTR_SOURCE = 0, ETS_AXI_PERF_MON_INTR_SOURCE, - ETS_USB_DEVICE_INTR_SOURCE, + ETS_USB_SERIAL_JTAG_INTR_SOURCE, ETS_SDIO_HOST_INTR_SOURCE, ETS_SPI2_INTR_SOURCE, ETS_SPI3_INTR_SOURCE, diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 8579638b62e..2f908cf7191 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -49,8 +49,9 @@ #define SOC_PARLIO_LCD_SUPPORTED 1 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 #define SOC_USB_OTG_SUPPORTED 1 -// #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 // TODO: [ESP32S31] IDF-14788 #define SOC_TEMP_SENSOR_SUPPORTED 1 +#define SOC_USB_SERIAL_JTAG_SUPPORTED 1 +// #define SOC_TEMP_SENSOR_SUPPORTED 1 // TODO: [ESP32S31] IDF-14799 // #define SOC_SUPPORTS_SECURE_DL_MODE 1 // TODO: [ESP32S31] IDF-14629 #define SOC_ULP_SUPPORTED 1 #define SOC_LP_CORE_SUPPORTED 1 diff --git a/components/soc/esp32s31/interrupts.c b/components/soc/esp32s31/interrupts.c index b5e65dda252..f7270cb3d2f 100644 --- a/components/soc/esp32s31/interrupts.c +++ b/components/soc/esp32s31/interrupts.c @@ -9,7 +9,7 @@ const char *const esp_isr_names[] = { [ETS_SYS_ICM_INTR_SOURCE] = "SYS_ICM", [ETS_AXI_PERF_MON_INTR_SOURCE] = "AXI_PERF_MON", - [ETS_USB_DEVICE_INTR_SOURCE] = "USB_DEVICE", + [ETS_USB_SERIAL_JTAG_INTR_SOURCE] = "USB_SERIAL_JTAG", [ETS_SDIO_HOST_INTR_SOURCE] = "SDIO_HOST", [ETS_SPI2_INTR_SOURCE] = "SPI2", [ETS_SPI3_INTR_SOURCE] = "SPI3", diff --git a/components/soc/esp32s31/register/soc/cnnt_sys_struct.h b/components/soc/esp32s31/register/soc/cnnt_sys_struct.h index df75afada3f..caf012f8c57 100644 --- a/components/soc/esp32s31/register/soc/cnnt_sys_struct.h +++ b/components/soc/esp32s31/register/soc/cnnt_sys_struct.h @@ -608,6 +608,7 @@ typedef struct { volatile cnnt_sys_gmac_ctrl2_reg_t sys_gmac_ctrl2; } cnnt_dev_t; +extern cnnt_dev_t CNNT_SYS_REG; #ifndef __cplusplus _Static_assert(sizeof(cnnt_dev_t) == 0x6c, "Invalid size of cnnt_dev_t structure"); diff --git a/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md b/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md index 5ff6f835db6..2d6f7434a9f 100644 --- a/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md +++ b/examples/peripherals/usb_serial_jtag/usb_serial_jtag_echo/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | -| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | +| Supported Targets | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-H4 | ESP32-P4 | ESP32-S3 | ESP32-S31 | +| ----------------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- | --------- | # USB SERIAL JTAG Echo Example diff --git a/examples/system/sysview_tracing/pytest_sysview_tracing.py b/examples/system/sysview_tracing/pytest_sysview_tracing.py index 5e49b839f39..ac8d9b52d70 100644 --- a/examples/system/sysview_tracing/pytest_sysview_tracing.py +++ b/examples/system/sysview_tracing/pytest_sysview_tracing.py @@ -176,7 +176,7 @@ def test_sysview_tracing_uart_c2(dut: IdfDut) -> None: @pytest.mark.usb_serial_jtag @idf_parametrize('target', soc_filtered_targets('SOC_USB_SERIAL_JTAG_SUPPORTED == 1'), indirect=['target']) @pytest.mark.parametrize('config', [pytest.param('sysview_usj')], indirect=True) -@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='lack of runner # TODO: IDFCI-10703') +@pytest.mark.temp_skip_ci(targets=['esp32h4', 'esp32s31'], reason='lack of runner # TODO: IDFCI-10703') def test_sysview_tracing_usj_serial(dut: IdfDut) -> None: time.sleep(1) # wait for USJ port to be ready usj_port = '/dev/serial_ports/ttyACM-esp32'