From 1a59c3e76977157fdaaf2973772f55e777e5c0ab Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Thu, 30 Jul 2026 16:17:32 +0300 Subject: [PATCH] feat(esp_riscv_trace): add ESP32-C5 support --- .../esp32c5/include/hal/riscv_trace_ll.h | 254 ++++++++++++++++++ components/esp_riscv_trace/Kconfig | 4 +- components/esp_riscv_trace/README.md | 4 +- .../test_apps/.build-test-rules.yml | 2 +- .../esp_riscv_trace/test_apps/basic/README.md | 4 +- .../test_apps/basic/pytest_riscv_trace.py | 4 +- .../esp32c5/include/soc/Kconfig.soc_caps.in | 20 ++ components/soc/esp32c5/include/soc/soc_caps.h | 7 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + components/soc/esp32p4/include/soc/soc_caps.h | 1 + .../esp32s31/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32s31/include/soc/soc_caps.h | 1 + 12 files changed, 302 insertions(+), 7 deletions(-) create mode 100644 components/esp_hal_debug_assist/esp32c5/include/hal/riscv_trace_ll.h diff --git a/components/esp_hal_debug_assist/esp32c5/include/hal/riscv_trace_ll.h b/components/esp_hal_debug_assist/esp32c5/include/hal/riscv_trace_ll.h new file mode 100644 index 00000000000..c0bfcf3f1b6 --- /dev/null +++ b/components/esp_hal_debug_assist/esp32c5/include/hal/riscv_trace_ll.h @@ -0,0 +1,254 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include + +#include "soc/trace_reg.h" +#include "soc/trace_struct.h" +#include "soc/pcr_struct.h" +#include "hal/assert.h" +#include "hal/riscv_trace_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Return the register block for the given core. */ +static inline trace_dev_t *riscv_trace_ll_get_hw(int core) +{ + HAL_ASSERT(core == 0); + (void)core; + return &TRACE; +} + +/*--------------------------------------------------------------------------- + * Clock and reset + *--------------------------------------------------------------------------*/ + +/** @brief Enable or disable the TRACE clock. */ +static inline void riscv_trace_ll_enable_bus_clock(bool enable) +{ + PCR.trace_conf.trace_clk_en = enable; +} + +/** @brief Assert and release the reset of the encoder. */ +static inline void riscv_trace_ll_reset_register(int core) +{ + (void)core; + PCR.trace_conf.trace_rst_en = 1; + PCR.trace_conf.trace_rst_en = 0; +} + +/** @brief Enable the per-module register clock gate. */ +static inline void riscv_trace_ll_enable_module_clock(trace_dev_t *hw, bool enable) +{ + hw->clock_gate.clk_en = enable; +} + +/*--------------------------------------------------------------------------- + * Memory configuration + *--------------------------------------------------------------------------*/ + +static inline void riscv_trace_ll_set_mem_start_addr(trace_dev_t *hw, uint32_t addr) +{ + hw->mem_start_addr.mem_start_addr = addr; +} + +static inline void riscv_trace_ll_set_mem_end_addr(trace_dev_t *hw, uint32_t addr) +{ + hw->mem_end_addr.mem_end_addr = addr; +} + +static inline uint32_t riscv_trace_ll_get_mem_current_addr(trace_dev_t *hw) +{ + return hw->mem_current_addr.mem_current_addr; +} + +/** @brief Reload the current address from the start address. */ +static inline void riscv_trace_ll_update_mem_current_addr(trace_dev_t *hw) +{ + hw->mem_addr_update.mem_current_addr_update = 1; +} + +/*--------------------------------------------------------------------------- + * Status + *--------------------------------------------------------------------------*/ + +static inline uint32_t riscv_trace_ll_get_fifo_status(trace_dev_t *hw) +{ + return hw->fifo_status.val; +} + +/*--------------------------------------------------------------------------- + * Trigger, loop mode and restart + *--------------------------------------------------------------------------*/ + +static inline void riscv_trace_ll_trigger_on(trace_dev_t *hw) +{ + hw->trigger.trigger_on = 1; +} + +static inline void riscv_trace_ll_trigger_off(trace_dev_t *hw) +{ + hw->trigger.trigger_off = 1; +} + +static inline void riscv_trace_ll_set_mem_loop(trace_dev_t *hw, bool loop) +{ + hw->trigger.mem_loop = loop; +} + +static inline void riscv_trace_ll_set_restart_ena(trace_dev_t *hw, bool enable) +{ + hw->trigger.restart_ena = enable; +} + +/*--------------------------------------------------------------------------- + * Encoder options (config register) + *--------------------------------------------------------------------------*/ + +static inline void riscv_trace_ll_set_full_address(trace_dev_t *hw, bool full) +{ + hw->config.full_address = full; +} + +static inline void riscv_trace_ll_set_stall_ena(trace_dev_t *hw, bool enable) +{ + hw->config.stall_ena = enable; +} + +static inline void riscv_trace_ll_set_halt_ena(trace_dev_t *hw, bool enable) +{ + hw->config.halt_ena = enable; +} + +static inline void riscv_trace_ll_set_reset_ena(trace_dev_t *hw, bool enable) +{ + hw->config.reset_ena = enable; +} + +static inline void riscv_trace_ll_set_dm_trigger_ena(trace_dev_t *hw, bool enable) +{ + hw->config.dm_trigger_ena = enable; +} + +/*--------------------------------------------------------------------------- + * Resynchronization + *--------------------------------------------------------------------------*/ + +static inline void riscv_trace_ll_set_resync_mode(trace_dev_t *hw, uint32_t mode) +{ + hw->resync_prolonged.resync_mode = mode; +} + +static inline void riscv_trace_ll_set_resync_threshold(trace_dev_t *hw, uint32_t threshold) +{ + hw->resync_prolonged.resync_prolonged = threshold; +} + +/*--------------------------------------------------------------------------- + * AHB configuration + *--------------------------------------------------------------------------*/ + +static inline void riscv_trace_ll_set_ahb_burst(trace_dev_t *hw, uint32_t hburst) +{ + hw->ahb_config.hburst = hburst; +} + +static inline void riscv_trace_ll_set_ahb_max_incr(trace_dev_t *hw, uint32_t max_incr) +{ + hw->ahb_config.max_incr = max_incr; +} + +/*--------------------------------------------------------------------------- + * Interrupts + *--------------------------------------------------------------------------*/ + +static inline void riscv_trace_ll_set_intr_ena(trace_dev_t *hw, uint32_t mask) +{ + hw->intr_ena.val = mask; +} + +static inline uint32_t riscv_trace_ll_get_intr_raw(trace_dev_t *hw) +{ + return hw->intr_raw.val; +} + +static inline void riscv_trace_ll_clear_intr(trace_dev_t *hw, uint32_t mask) +{ + hw->intr_clr.val = mask; +} + +/*--------------------------------------------------------------------------- + * Filter unit + *--------------------------------------------------------------------------*/ + +static inline void riscv_trace_ll_set_filter_en(trace_dev_t *hw, bool enable) +{ + hw->filter_control.filter_en = enable; +} + +static inline void riscv_trace_ll_set_filter_control(trace_dev_t *hw, bool match_comp, + bool match_privilege, bool match_ecause, + bool match_interrupt) +{ + hw->filter_control.match_comp = match_comp; + hw->filter_control.match_privilege = match_privilege; + hw->filter_control.match_ecause = match_ecause; + hw->filter_control.match_interrupt = match_interrupt; +} + +static inline bool riscv_trace_ll_priv_is_supported(uint32_t priv) +{ + return priv == RISCV_TRACE_PRIV_USER || priv == RISCV_TRACE_PRIV_MACHINE; +} + +static inline void riscv_trace_ll_set_filter_match_control(trace_dev_t *hw, uint32_t priv_choice, + bool intr_value, uint32_t ecause_choice) +{ + // This target has no supervisor mode, so the selector is 1 bit: 0 = user, 1 = machine. + hw->filter_match_control.match_choice_privilege = (priv_choice == RISCV_TRACE_PRIV_MACHINE); + hw->filter_match_control.match_value_interrupt = intr_value; + hw->filter_match_control.match_choice_ecause = ecause_choice; +} + +static inline void riscv_trace_ll_set_p_comparator(trace_dev_t *hw, uint32_t input, + uint32_t function, bool notify) +{ + hw->filter_comparator_control.p_input = input; + hw->filter_comparator_control.p_function = function; + hw->filter_comparator_control.p_notify = notify; +} + +static inline void riscv_trace_ll_set_s_comparator(trace_dev_t *hw, uint32_t input, + uint32_t function, bool notify) +{ + hw->filter_comparator_control.s_input = input; + hw->filter_comparator_control.s_function = function; + hw->filter_comparator_control.s_notify = notify; +} + +static inline void riscv_trace_ll_set_match_mode(trace_dev_t *hw, uint32_t mode) +{ + hw->filter_comparator_control.match_mode = mode; +} + +static inline void riscv_trace_ll_set_p_match_value(trace_dev_t *hw, uint32_t value) +{ + hw->filter_p_comparator_match.p_match = value; +} + +static inline void riscv_trace_ll_set_s_match_value(trace_dev_t *hw, uint32_t value) +{ + hw->filter_s_comparator_match.s_match = value; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_riscv_trace/Kconfig b/components/esp_riscv_trace/Kconfig index b608e1e4a83..d2ce4541f62 100644 --- a/components/esp_riscv_trace/Kconfig +++ b/components/esp_riscv_trace/Kconfig @@ -20,7 +20,7 @@ menu "RISC-V Trace Encoder Configurations" default ESP_RISCV_TRACE_BUFFER_IN_INTERNAL help Where the driver allocates the trace buffer. The encoder writes the buffer over - its AHB master, which can reach both internal and external PSRAM. + its AHB master. PSRAM is only offered on targets whose encoder can reach it. Internal RAM is fastest and always usable. PSRAM frees internal RAM and allows much larger buffers, but is slower (higher risk of FIFO overflow at high trace @@ -30,7 +30,7 @@ menu "RISC-V Trace Encoder Configurations" bool "Internal RAM" config ESP_RISCV_TRACE_BUFFER_IN_EXTERNAL bool "External RAM (PSRAM)" - depends on SPIRAM + depends on SPIRAM && SOC_RISCV_TRACE_MEM_SUPPORT_PSRAM endchoice config ESP_RISCV_TRACE_BUFFER_MEM diff --git a/components/esp_riscv_trace/README.md b/components/esp_riscv_trace/README.md index 3d1d1ed1b97..86d90e6de7d 100644 --- a/components/esp_riscv_trace/README.md +++ b/components/esp_riscv_trace/README.md @@ -42,7 +42,9 @@ The trace buffer must be reachable by the trace encoder AHB master. Driver allocated buffers are placed in internal RAM or PSRAM according to configuration, and are cache-line aligned when that memory is reached through a data cache. Caller-provided buffers are validated for reachable memory and -cache-line alignment. +cache-line alignment. PSRAM placement is only available on targets whose +encoder can reach external RAM (`SOC_RISCV_TRACE_MEM_SUPPORT_PSRAM`); on other +targets the buffer is always internal. In loop memory mode, wrapped buffers need periodic resynchronization packets to remain decodable after the original start sync has been overwritten. diff --git a/components/esp_riscv_trace/test_apps/.build-test-rules.yml b/components/esp_riscv_trace/test_apps/.build-test-rules.yml index 8f9e2890723..ade677a37bb 100644 --- a/components/esp_riscv_trace/test_apps/.build-test-rules.yml +++ b/components/esp_riscv_trace/test_apps/.build-test-rules.yml @@ -3,6 +3,6 @@ components/esp_riscv_trace/test_apps: disable: - if: SOC_RISCV_TRACE_SUPPORTED != 1 - - if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1 + - if: CONFIG_NAME == "psram" and SOC_RISCV_TRACE_MEM_SUPPORT_PSRAM != 1 depends_components: - esp_riscv_trace diff --git a/components/esp_riscv_trace/test_apps/basic/README.md b/components/esp_riscv_trace/test_apps/basic/README.md index 88370737619..c81bb2f165b 100644 --- a/components/esp_riscv_trace/test_apps/basic/README.md +++ b/components/esp_riscv_trace/test_apps/basic/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32-P4 | ESP32-S31 | -| ----------------- | -------- | --------- | +| Supported Targets | ESP32-C5 | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | -------- | --------- | # RISC-V Trace Basic Test App diff --git a/components/esp_riscv_trace/test_apps/basic/pytest_riscv_trace.py b/components/esp_riscv_trace/test_apps/basic/pytest_riscv_trace.py index 578e1d6e0dc..34aad9e75bb 100644 --- a/components/esp_riscv_trace/test_apps/basic/pytest_riscv_trace.py +++ b/components/esp_riscv_trace/test_apps/basic/pytest_riscv_trace.py @@ -16,7 +16,9 @@ def test_riscv_trace(dut: Dut) -> None: @pytest.mark.generic @pytest.mark.parametrize('config', ['psram'], indirect=True) @idf_parametrize( - 'target', soc_filtered_targets('SOC_RISCV_TRACE_SUPPORTED == 1 and SOC_SPIRAM_SUPPORTED == 1'), indirect=['target'] + 'target', + soc_filtered_targets('SOC_RISCV_TRACE_SUPPORTED == 1 and SOC_RISCV_TRACE_MEM_SUPPORT_PSRAM == 1'), + indirect=['target'], ) def test_riscv_trace_psram(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index e76561f2c3f..2c6182f4cef 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -307,6 +307,10 @@ config SOC_SPI_EXTERNAL_NOR_FLASH_SUPPORTED bool default y +config SOC_RISCV_TRACE_SUPPORTED + bool + default y + config SOC_XTAL_SUPPORT_40M bool default y @@ -1618,3 +1622,19 @@ config SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE config SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED bool default y + +config SOC_RISCV_TRACE_HAS_CONFIG_REG + bool + default y + +config SOC_RISCV_TRACE_AHB_CONFIGURABLE + bool + default y + +config SOC_RISCV_TRACE_FILTER_SUPPORTED + bool + default y + +config SOC_RISCV_TRACE_PRIV_WIDTH + int + default 1 diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index ca365e2ccc1..04031dd76c3 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -100,6 +100,7 @@ #define SOC_PHY_SUPPORTED 1 #define SOC_BITSCRAMBLER_SUPPORTED 1 #define SOC_SPI_EXTERNAL_NOR_FLASH_SUPPORTED 1 +#define SOC_RISCV_TRACE_SUPPORTED 1 /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 @@ -645,3 +646,9 @@ #define SOC_LP_CORE_SUPPORT_I2C (1) /*!< LP Core supports I2C */ #define SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE (1) /*!< LP core requests sleep, PMU clears both HP and LP wakeup causes */ #define SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED (1) /*!< LP UART wakeup source is kept triggered */ + +/*-------------------------- RISC-V TRACE CAPS ------------------------------*/ +#define SOC_RISCV_TRACE_HAS_CONFIG_REG (1) /*!< Has the encoder config register */ +#define SOC_RISCV_TRACE_AHB_CONFIGURABLE (1) /*!< AHB write master is configurable */ +#define SOC_RISCV_TRACE_FILTER_SUPPORTED (1) /*!< Has the filter unit */ +#define SOC_RISCV_TRACE_PRIV_WIDTH (1U) /*!< Bits in the privilege field (privilege_width_p) */ diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 8bb4089f429..1f58eb3ff43 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1954,3 +1954,7 @@ config SOC_RISCV_TRACE_FILTER_SUPPORTED config SOC_RISCV_TRACE_PRIV_WIDTH int default 1 + +config SOC_RISCV_TRACE_MEM_SUPPORT_PSRAM + bool + default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index ebc488a1f6a..ff426d0dd10 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -747,3 +747,4 @@ #define SOC_RISCV_TRACE_AHB_CONFIGURABLE (1) /*!< AHB write master is configurable */ #define SOC_RISCV_TRACE_FILTER_SUPPORTED (1) /*!< Has the filter unit */ #define SOC_RISCV_TRACE_PRIV_WIDTH (1U) /*!< Bits in the privilege field (privilege_width_p) */ +#define SOC_RISCV_TRACE_MEM_SUPPORT_PSRAM (1) /*!< Encoder AHB master can reach external PSRAM */ diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 49b47296d69..8626524a683 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -1874,3 +1874,7 @@ config SOC_RISCV_TRACE_FILTER_SUPPORTED config SOC_RISCV_TRACE_PRIV_WIDTH int default 2 + +config SOC_RISCV_TRACE_MEM_SUPPORT_PSRAM + bool + default y diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 0aac0e0b34c..2a21140bd0a 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -697,3 +697,4 @@ #define SOC_RISCV_TRACE_AHB_CONFIGURABLE (1) /*!< AHB write master is configurable */ #define SOC_RISCV_TRACE_FILTER_SUPPORTED (1) /*!< Has the filter unit */ #define SOC_RISCV_TRACE_PRIV_WIDTH (2U) /*!< Bits in the privilege field (privilege_width_p) */ +#define SOC_RISCV_TRACE_MEM_SUPPORT_PSRAM (1) /*!< Encoder AHB master can reach external PSRAM */