diff --git a/components/esp_hw_support/CMakeLists.txt b/components/esp_hw_support/CMakeLists.txt index 0807483723..b4804f7bad 100644 --- a/components/esp_hw_support/CMakeLists.txt +++ b/components/esp_hw_support/CMakeLists.txt @@ -84,6 +84,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "ldo/esp_ldo_regulator.c") endif() + if(CONFIG_SOC_DEBUG_PROBE_SUPPORTED) + list(APPEND srcs "debug_probe/debug_probe.c") + endif() + if(CONFIG_SOC_ASYNC_MEMCPY_SUPPORTED) list(APPEND srcs "dma/esp_async_memcpy.c") if(CONFIG_SOC_GDMA_SUPPORTED) @@ -177,8 +181,11 @@ else() list(APPEND priv_requires "esp_system") endif() +set(public_include_dirs "include" "include/soc" "include/soc/${target}" + "dma/include" "ldo/include" "debug_probe/include") + idf_component_register(SRCS ${srcs} - INCLUDE_DIRS include include/soc include/soc/${target} dma/include ldo/include + INCLUDE_DIRS ${public_include_dirs} PRIV_INCLUDE_DIRS port/include include/esp_private REQUIRES ${requires} PRIV_REQUIRES "${priv_requires}" diff --git a/components/esp_hw_support/debug_probe/debug_probe.c b/components/esp_hw_support/debug_probe/debug_probe.c new file mode 100644 index 0000000000..94574427b8 --- /dev/null +++ b/components/esp_hw_support/debug_probe/debug_probe.c @@ -0,0 +1,221 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "esp_log.h" +#include "esp_check.h" +#include "esp_heap_caps.h" +#include "soc/soc_caps.h" +#include "soc/debug_probe_periph.h" +#include "hal/debug_probe_ll.h" +#include "esp_private/debug_probe.h" +#include "esp_rom_gpio.h" +#include "driver/gpio.h" + +static const char *TAG = "dbg_probe"; + +typedef struct debug_probe_unit_t debug_probe_unit_t; +typedef struct debug_probe_channel_t debug_probe_channel_t; + +struct debug_probe_unit_t { + int unit_id; // unit id + debug_probe_channel_t *channels[DEBUG_PROBE_LL_CHANNELS_PER_UNIT]; // channels installed in this unit +}; + +struct debug_probe_channel_t { + debug_probe_unit_t *unit; // the unit this channel belongs to + int chan_id; // channel id +}; + +typedef struct debug_probe_platform_t { + _lock_t mutex; // platform level mutex lock + debug_probe_unit_t *units[SOC_DEBUG_PROBE_NUM_UNIT]; // debug probe units +} debug_probe_platform_t; + +static debug_probe_platform_t s_platform; // singleton platform + +static esp_err_t debug_probe_unit_destroy(debug_probe_unit_t *unit) +{ + int unit_id = unit->unit_id; + + // remove the unit from the platform + _lock_acquire(&s_platform.mutex); + s_platform.units[unit_id] = NULL; + _lock_release(&s_platform.mutex); + + // disable the probe output + debug_probe_ll_enable_unit(unit_id, false); + // free the memory + free(unit); + return ESP_OK; +} + +esp_err_t debug_probe_new_unit(const debug_probe_unit_config_t *config, debug_probe_unit_handle_t *out_handle) +{ + esp_err_t ret = ESP_OK; + debug_probe_unit_t *unit = NULL; + int unit_id = -1; + ESP_RETURN_ON_FALSE(config && out_handle, ESP_ERR_INVALID_ARG, TAG, "invalid args"); + + // search for a free unit slot + _lock_acquire(&s_platform.mutex); + for (int i = 0; i < SOC_DEBUG_PROBE_NUM_UNIT; i++) { + if (s_platform.units[i] == NULL) { + unit_id = i; + unit = calloc(1, sizeof(debug_probe_unit_t)); + s_platform.units[i] = unit; + break; + } + } + _lock_release(&s_platform.mutex); + ESP_RETURN_ON_FALSE(unit_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free unit slot"); + ESP_RETURN_ON_FALSE(unit, ESP_ERR_NO_MEM, TAG, "no mem for unit"); + unit->unit_id = unit_id; + + // configure the GPIOs + gpio_config_t monitor_io_conf = { + .mode = GPIO_MODE_OUTPUT, + .pin_bit_mask = 0, + }; + for (int i = 0; i < SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH; i++) { + // skip unused IOs + if (config->probe_out_gpio_nums[i] < 0) { + continue; + } + monitor_io_conf.pin_bit_mask |= (1ULL << config->probe_out_gpio_nums[i]); + } + if (monitor_io_conf.pin_bit_mask) { + ESP_GOTO_ON_ERROR(gpio_config(&monitor_io_conf), err, TAG, "gpio_config failed"); + } + + // connect the probe output signals to the GPIOs + for (int i = 0; i < SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH; i++) { + if (config->probe_out_gpio_nums[i] < 0) { + continue; + } + esp_rom_gpio_connect_out_signal(config->probe_out_gpio_nums[i], + debug_probe_periph_signals.units[unit_id].out_sig[i], + false, false); + } + + // enable the probe unit + debug_probe_ll_enable_unit(unit_id, true); + + *out_handle = unit; + return ESP_OK; + +err: + if (unit) { + debug_probe_unit_destroy(unit); + } + return ret; +} + +esp_err_t debug_probe_del_unit(debug_probe_unit_handle_t unit) +{ + ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid args"); + // if there's any channel still being used, return error + int channel_in_use = -1; + _lock_acquire(&s_platform.mutex); + for (int i = 0; i < DEBUG_PROBE_LL_CHANNELS_PER_UNIT; i++) { + if (unit->channels[i]) { + channel_in_use = i; + break; + } + } + _lock_release(&s_platform.mutex); + ESP_RETURN_ON_FALSE(channel_in_use < 0, ESP_ERR_INVALID_STATE, TAG, "channel %d still in use", channel_in_use); + return debug_probe_unit_destroy(unit); +} + +static esp_err_t debug_probe_channel_destroy(debug_probe_channel_t *chan) +{ + debug_probe_unit_t *unit = chan->unit; + int unit_id = unit->unit_id; + int chan_id = chan->chan_id; + + // remove the channel from the unit + _lock_acquire(&s_platform.mutex); + unit->channels[chan_id] = NULL; + _lock_release(&s_platform.mutex); + + // disable the probe channel + debug_probe_ll_enable_channel(unit_id, chan_id, false); + // free the memory + free(chan); + return ESP_OK; +} + +esp_err_t debug_probe_new_channel(debug_probe_unit_handle_t unit, const debug_probe_channel_config_t *config, debug_probe_channel_handle_t *out_handle) +{ + debug_probe_channel_t *chan = NULL; + int chan_id = -1; + ESP_RETURN_ON_FALSE(unit && config && out_handle, ESP_ERR_INVALID_ARG, TAG, "invalid args"); + int unit_id = unit->unit_id; + + // search for a free channel slot + _lock_acquire(&s_platform.mutex); + for (int i = 0; i < DEBUG_PROBE_LL_CHANNELS_PER_UNIT; i++) { + if (unit->channels[i] == NULL) { + chan_id = i; + chan = calloc(1, sizeof(debug_probe_channel_t)); + unit->channels[i] = chan; + break; + } + } + _lock_release(&s_platform.mutex); + ESP_RETURN_ON_FALSE(chan_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free chan slot"); + ESP_RETURN_ON_FALSE(chan, ESP_ERR_NO_MEM, TAG, "no mem for chan"); + chan->chan_id = chan_id; + chan->unit = unit; + + // one channel can only monitor one target module + debug_probe_ll_channel_set_target_module(unit_id, chan_id, config->target_module); + debug_probe_ll_enable_channel(unit_id, chan_id, true); + + *out_handle = chan; + return ESP_OK; +} + +esp_err_t debug_probe_del_channel(debug_probe_channel_handle_t chan) +{ + ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid args"); + return debug_probe_channel_destroy(chan); +} + +esp_err_t debug_probe_chan_add_signal_by_byte(debug_probe_channel_handle_t chan, uint8_t byte_idx, uint8_t sig_group) +{ + ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid args"); + ESP_RETURN_ON_FALSE(byte_idx < 4, ESP_ERR_INVALID_ARG, TAG, "byte_idx out of range"); + ESP_RETURN_ON_FALSE(sig_group < 16, ESP_ERR_INVALID_ARG, TAG, "sig_group out of range"); + debug_probe_unit_t *unit = chan->unit; + debug_probe_ll_channel_add_signal_group(unit->unit_id, chan->chan_id, byte_idx, sig_group); + return ESP_OK; +} + +esp_err_t debug_probe_unit_merge16(debug_probe_unit_handle_t unit, debug_probe_channel_handle_t chan0, debug_probe_split_u16_t split_of_chan0, + debug_probe_channel_handle_t chan1, debug_probe_split_u16_t split_of_chan1) +{ + ESP_RETURN_ON_FALSE(unit && chan0 && chan1, ESP_ERR_INVALID_ARG, TAG, "invalid args"); + ESP_RETURN_ON_FALSE(chan0->unit == unit && chan1->unit == unit, ESP_ERR_INVALID_ARG, TAG, "chan not belong to unit"); + int unit_id = unit->unit_id; + debug_probe_ll_set_lower16_output(unit_id, chan0->chan_id, split_of_chan0); + debug_probe_ll_set_upper16_output(unit_id, chan1->chan_id, split_of_chan1); + return ESP_OK; +} + +esp_err_t debug_probe_unit_read(debug_probe_unit_handle_t unit, uint32_t *value) +{ + ESP_RETURN_ON_FALSE(unit && value, ESP_ERR_INVALID_ARG, TAG, "invalid args"); + int unit_id = unit->unit_id; + *value = debug_probe_ll_read_output(unit_id); + return ESP_OK; +} diff --git a/components/esp_hw_support/debug_probe/include/esp_private/debug_probe.h b/components/esp_hw_support/debug_probe/include/esp_private/debug_probe.h new file mode 100644 index 0000000000..0afb1c8ffe --- /dev/null +++ b/components/esp_hw_support/debug_probe/include/esp_private/debug_probe.h @@ -0,0 +1,157 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "soc/gpio_num.h" +#include "debug_probe_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Handle type of a debug probe unit + */ +typedef struct debug_probe_unit_t *debug_probe_unit_handle_t; + +/** + * @brief Handle type of a debug probe channel + */ +typedef struct debug_probe_channel_t *debug_probe_channel_handle_t; + +/** + * @brief Configuration for a debug probe unit + */ +typedef struct { + gpio_num_t probe_out_gpio_nums[DEBUG_PROBE_MAX_OUTPUT_WIDTH]; ///< GPIO numbers for probe output +} debug_probe_unit_config_t; + +/** + * @brief Create a new debug probe unit + * + * @param[in] config Configuration for the debug probe unit + * @param[out] out_handle Handle of the created debug probe unit + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the configuration is invalid + * - ESP_ERR_NOT_FOUND if there is no free unit slot + * - ESP_ERR_NO_MEM if memory allocation failed + * - ESP_FAIL if an internal error occurred + */ +esp_err_t debug_probe_new_unit(const debug_probe_unit_config_t *config, debug_probe_unit_handle_t *out_handle); + +/** + * @brief Delete a debug probe unit + * + * @param[in] unit Handle of the debug probe unit + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the handle is invalid + * - ESP_FAIL if an internal error occurred + */ +esp_err_t debug_probe_del_unit(debug_probe_unit_handle_t unit); + +/** + * @brief Configuration for a debug probe channel + */ +typedef struct { + debug_probe_target_t target_module; ///< Target module of the debug probe channel +} debug_probe_channel_config_t; + +/** + * @brief Create a new debug probe channel in a unit + * + * @param[in] unit Handle of the debug probe unit + * @param[in] config Configuration for the debug probe channel + * @param[out] out_handle Handle of the created debug probe channel + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the handle or configuration is invalid + * - ESP_ERR_NOT_FOUND if there is no free channel slot + * - ESP_ERR_NO_MEM if memory allocation failed + * - ESP_FAIL if an internal error occurred + */ +esp_err_t debug_probe_new_channel(debug_probe_unit_handle_t unit, const debug_probe_channel_config_t *config, debug_probe_channel_handle_t *out_handle); + +/** + * @brief Delete a debug probe channel + * + * @param[in] chan Handle of the debug probe channel + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the handle is invalid + * - ESP_FAIL if an internal error occurred + */ +esp_err_t debug_probe_del_channel(debug_probe_channel_handle_t chan); + +/** + * @brief Add signals to a debug probe channel + * + * @note The n-th byte of channel output comes from the n-th byte in the sig_group. + * @note The signals to be added must aligned to the byte boundary. + * byte_idx = 0: signal 0-7 in the group + * byte_idx = 1: signal 8-15 in the group + * ... + * @note If you add the signals from different groups but with the same byte_idx, only the last added signal will be effective. + * @note You can save up to 32 signals in a channel, but in the end, only the part of them (e.g. upper or lower 16 signals) can be output to the GPIO pads. + * + * @param[in] chan Handle of the debug probe channel + * @param[in] byte_idx Byte index of the signals, ranges from 0 to 3 + * @param[in] sig_group Signal group of the signal, ranges from 0 to 15 + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the parameters are invalid + * - ESP_FAIL if an internal error occurred + */ +esp_err_t debug_probe_chan_add_signal_by_byte(debug_probe_channel_handle_t chan, uint8_t byte_idx, uint8_t sig_group); + +/** + * @brief Merge the part of the channel output to the debug probe unit output + * + * +----upper16---+ + * chan_0 ---+ | + * +----lower16---+ + * | + * +-------unit_output[31:0] + * | + * +----upper16---+ + * chan_1 ---+ | + * +----lower16---+ + * + * @param[in] unit Handle of the debug probe unit + * @param[in] chan0 Handle of the debug probe channel 0, whose output will be merged to the lower 16 signals of the unit output + * @param[in] split_of_chan0 Part of the channel 0 output to be merged + * @param[in] chan1 Handle of the debug probe channel 1, whose output will be merged to the upper 16 signals of the unit output + * @param[in] split_of_chan1 Part of the channel 1 output to be merged + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the parameters are invalid + * - ESP_FAIL if an internal error occurred + */ +esp_err_t debug_probe_unit_merge16(debug_probe_unit_handle_t unit, debug_probe_channel_handle_t chan0, debug_probe_split_u16_t split_of_chan0, + debug_probe_channel_handle_t chan1, debug_probe_split_u16_t split_of_chan1); + +/** + * @brief Read the value of the debug probe unit + * + * @note Only the lower 16 signals of the probe unit can be routed to the GPIO pads. + * + * @param[in] unit Handle of the debug probe unit + * @param[out] value Current value of the debug probe unit output + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if the handle or value is invalid + * - ESP_FAIL if an internal error occurred + */ +esp_err_t debug_probe_unit_read(debug_probe_unit_handle_t unit, uint32_t *value); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/debug_probe/include/esp_private/debug_probe_types.h b/components/esp_hw_support/debug_probe/include/esp_private/debug_probe_types.h new file mode 100644 index 0000000000..ac54ca66ec --- /dev/null +++ b/components/esp_hw_support/debug_probe/include/esp_private/debug_probe_types.h @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include +#include "esp_err.h" +#include "soc/soc_caps.h" +#include "hal/debug_probe_types.h" +#if SOC_DEBUG_PROBE_SUPPORTED +#include "soc/debug_probe_targets.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_DEBUG_PROBE_SUPPORTED +#define DEBUG_PROBE_MAX_OUTPUT_WIDTH SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH +typedef soc_debug_probe_target_t debug_probe_target_t; +#else +#define DEBUG_PROBE_MAX_OUTPUT_WIDTH 16 +typedef int debug_probe_target_t; +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt index 5bd97e4951..b58624d47c 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt @@ -16,6 +16,10 @@ if(CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX OR CONFIG_SOC_GPIO_CLOCKOUT_BY_IO_MUX list(APPEND srcs "test_esp_clock_output.c") endif() +if(CONFIG_SOC_DEBUG_PROBE_SUPPORTED) + list(APPEND srcs "test_debug_probe.c") +endif() + if(CONFIG_SOC_ETM_SUPPORTED) list(APPEND srcs "test_etm_core.c") endif() diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_debug_probe.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_debug_probe.c new file mode 100644 index 0000000000..e9af7da1e9 --- /dev/null +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_debug_probe.c @@ -0,0 +1,86 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "unity.h" +#include "soc/soc_caps.h" +#include "hal/debug_probe_ll.h" +#include "esp_private/debug_probe.h" + +TEST_CASE("debug probe install & uninstall", "[debug_probe]") +{ + debug_probe_unit_config_t unit_config = { + .probe_out_gpio_nums = {0}, + }; + debug_probe_unit_handle_t probe_units[SOC_DEBUG_PROBE_NUM_UNIT] = {0}; + printf("install debug probe exhaustively\r\n"); + for (int i = 0; i < SOC_DEBUG_PROBE_NUM_UNIT; i++) { + TEST_ESP_OK(debug_probe_new_unit(&unit_config, &probe_units[i])); + } + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, debug_probe_new_unit(&unit_config, &probe_units[0])); + + debug_probe_channel_config_t chan_config = { + .target_module = 1, + }; + debug_probe_channel_handle_t probe_chans[SOC_DEBUG_PROBE_NUM_UNIT][DEBUG_PROBE_LL_CHANNELS_PER_UNIT] = {0}; + for (int i = 0; i < SOC_DEBUG_PROBE_NUM_UNIT; i++) { + for (int j = 0; j < DEBUG_PROBE_LL_CHANNELS_PER_UNIT; j++) { + TEST_ESP_OK(debug_probe_new_channel(probe_units[i], &chan_config, &probe_chans[i][j])); + } + TEST_ESP_ERR(ESP_ERR_NOT_FOUND, debug_probe_new_channel(probe_units[i], &chan_config, &probe_chans[i][0])); + } + + for (int i = 0; i < SOC_DEBUG_PROBE_NUM_UNIT; i++) { + for (int j = 0; j < DEBUG_PROBE_LL_CHANNELS_PER_UNIT; j++) { + TEST_ESP_OK(debug_probe_del_channel(probe_chans[i][j])); + } + TEST_ESP_OK(debug_probe_del_unit(probe_units[i])); + } +} + +TEST_CASE("debug probe read", "[debug_probe]") +{ + debug_probe_unit_config_t unit_config = { + .probe_out_gpio_nums = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + } + }; + debug_probe_unit_handle_t probe_unit = NULL; + TEST_ESP_OK(debug_probe_new_unit(&unit_config, &probe_unit)); + + // allocate two channels from the unit, each channel monitor different target module + debug_probe_channel_handle_t probe_chans[2] = {0}; + for (int i = 0; i < 2; i++) { + debug_probe_channel_config_t chan_config = { + .target_module = i + 1, + }; + TEST_ESP_OK(debug_probe_new_channel(probe_unit, &chan_config, &probe_chans[i])); + + // group15[7:0] contains the debug target module ID + TEST_ESP_OK(debug_probe_chan_add_signal_by_byte(probe_chans[i], 0, 15)); + TEST_ESP_OK(debug_probe_chan_add_signal_by_byte(probe_chans[i], 1, 15)); + TEST_ESP_OK(debug_probe_chan_add_signal_by_byte(probe_chans[i], 2, 15)); + TEST_ESP_OK(debug_probe_chan_add_signal_by_byte(probe_chans[i], 3, 15)); + } + + TEST_ESP_OK(debug_probe_unit_merge16(probe_unit, + probe_chans[0], DEBUG_PROBE_SPLIT_LOWER16, + probe_chans[1], DEBUG_PROBE_SPLIT_LOWER16)); + uint32_t probe_result = 0; + TEST_ESP_OK(debug_probe_unit_read(probe_unit, &probe_result)); + printf("probe result: 0x%"PRIx32"\r\n", probe_result); + TEST_ASSERT_EQUAL_HEX32(0x20001, probe_result); + + // free resources + for (int i = 0; i < 2; i++) { + TEST_ESP_OK(debug_probe_del_channel(probe_chans[i])); + } + TEST_ESP_OK(debug_probe_del_unit(probe_unit)); +} diff --git a/components/hal/esp32p4/include/hal/debug_probe_ll.h b/components/hal/esp32p4/include/hal/debug_probe_ll.h new file mode 100644 index 0000000000..dd9f539230 --- /dev/null +++ b/components/hal/esp32p4/include/hal/debug_probe_ll.h @@ -0,0 +1,122 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include +#include "hal/misc.h" +#include "hal/assert.h" +#include "soc/debug_probe_targets.h" +#include "soc/hp_system_struct.h" +#include "hal/debug_probe_types.h" + +/** + * @brief Define how many channels are there in one debug probe unit + */ +#define DEBUG_PROBE_LL_CHANNELS_PER_UNIT 2 + +#ifdef __cplusplus +extern "C" { +#endif + +// translate the HAL types into register values +#define DEBUG_PROBE_LL_PART_TO_REG_VAL(part) ((uint8_t[]) {0, 1}[(part)]) + +/** + * @brief Enable the debug probe module + * + * @param en true: enable, false: disable + */ +static inline void debug_probe_ll_enable_unit(int unit_id, bool en) +{ + HP_SYSTEM.probea_ctrl.reg_probe_global_en = en; +} + +/** + * @brief Enable a specific channel in the debug probe unit + * + * @param channel channel number (only support 0 and 1) + * @param en true: enable, false: disable + */ +static inline void debug_probe_ll_enable_channel(int unit_id, int channel, bool en) +{ + // channel 0 is always enabled + if (channel == 1) { + HP_SYSTEM.probeb_ctrl.reg_probe_b_en = en; + } +} + +/** + * @brief Set the target module for a probe channel + * + * @param channel channel number (only support 0 and 1) + * @param target_module target module, see soc_debug_probe_target_t + */ +static inline void debug_probe_ll_channel_set_target_module(int unit_id, uint8_t channel, soc_debug_probe_target_t target_module) +{ + if (channel == 0) { + HP_SYSTEM.probea_ctrl.reg_probe_a_top_sel = target_module; + } else { + HP_SYSTEM.probeb_ctrl.reg_probe_b_top_sel = target_module; + } +} + +/** + * @brief Add signals from a specific group to the probe channel + * + * @note One sig_group contains 4 bytes of signals. The sig_byte_idx is used to select the byte in the sig_group. + * + * @param channel channel number (only support 0 and 1) + * @param sig_byte_idx signal byte index (0-3) + * @param sig_group signal group (0-15) + */ +static inline void debug_probe_ll_channel_add_signal_group(int unit_id, uint8_t channel, uint8_t sig_byte_idx, uint8_t sig_group) +{ + if (channel == 0) { + HP_SYSTEM.probea_ctrl.reg_probe_a_mod_sel &= ~(0xf << (sig_byte_idx * 4)); + HP_SYSTEM.probea_ctrl.reg_probe_a_mod_sel |= (sig_group << (sig_byte_idx * 4)); + } else { + HP_SYSTEM.probeb_ctrl.reg_probe_b_mod_sel &= ~(0xf << (sig_byte_idx * 4)); + HP_SYSTEM.probeb_ctrl.reg_probe_b_mod_sel |= (sig_group << (sig_byte_idx * 4)); + } +} + +/** + * @brief Set the lower 16 bits of the probe output + * + * @param part where does the probe_top_out[15:0] come from + */ +static inline void debug_probe_ll_set_lower16_output(int unit_id, int channel, debug_probe_split_u16_t part) +{ + HP_SYSTEM.probea_ctrl.reg_probe_l_sel = channel * 2 + DEBUG_PROBE_LL_PART_TO_REG_VAL(part); +} + +/** + * @brief Set the upper 16 bits of the probe output + * + * @param part where does the probe_top_out[31:16] come from + */ +static inline void debug_probe_ll_set_upper16_output(int unit_id, int channel, debug_probe_split_u16_t part) +{ + HP_SYSTEM.probea_ctrl.reg_probe_h_sel = channel * 2 + DEBUG_PROBE_LL_PART_TO_REG_VAL(part); +} + +/** + * @brief Read the value that currently being probed + * + * @note ESP32P4 can only route the LSB probe_top_out[15:0] to the GPIO pad. But the register still saves 32 signal bits. + * + * @return the value that currently being probed + */ +static inline uint32_t debug_probe_ll_read_output(int unit_id) +{ + return HP_SYSTEM.probe_out.reg_probe_top_out; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/hal/include/hal/debug_probe_types.h b/components/hal/include/hal/debug_probe_types.h new file mode 100644 index 0000000000..654a5de015 --- /dev/null +++ b/components/hal/include/hal/debug_probe_types.h @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The 32bit debug probe output can be split into two 16bit parts + */ +typedef enum { + DEBUG_PROBE_SPLIT_LOWER16, ///< The lower 16 signals of the debug probe output + DEBUG_PROBE_SPLIT_UPPER16, ///< The upper 16 signals of the debug probe output +} debug_probe_split_u16_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 42f8128835..cc16c9b544 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -33,6 +33,10 @@ if(CONFIG_SOC_DEDICATED_GPIO_SUPPORTED) list(APPEND srcs "${target_folder}/dedic_gpio_periph.c") endif() +if(CONFIG_SOC_DEBUG_PROBE_SUPPORTED) + list(APPEND srcs "${target_folder}/debug_probe_periph.c") +endif() + if(CONFIG_SOC_EMAC_SUPPORTED) list(APPEND srcs "${target_folder}/emac_periph.c") endif() diff --git a/components/soc/esp32p4/debug_probe_periph.c b/components/soc/esp32p4/debug_probe_periph.c new file mode 100644 index 0000000000..5c7746dd5c --- /dev/null +++ b/components/soc/esp32p4/debug_probe_periph.c @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "soc/gpio_sig_map.h" +#include "soc/debug_probe_periph.h" + +const debug_probe_signal_conn_t debug_probe_periph_signals = { + .units = { + [0] = { + .out_sig = { + [0] = HP_PROBE_TOP_OUT0_IDX, + [1] = HP_PROBE_TOP_OUT1_IDX, + [2] = HP_PROBE_TOP_OUT2_IDX, + [3] = HP_PROBE_TOP_OUT3_IDX, + [4] = HP_PROBE_TOP_OUT4_IDX, + [5] = HP_PROBE_TOP_OUT5_IDX, + [6] = HP_PROBE_TOP_OUT6_IDX, + [7] = HP_PROBE_TOP_OUT7_IDX, + [8] = HP_PROBE_TOP_OUT8_IDX, + [9] = HP_PROBE_TOP_OUT9_IDX, + [10] = HP_PROBE_TOP_OUT10_IDX, + [11] = HP_PROBE_TOP_OUT11_IDX, + [12] = HP_PROBE_TOP_OUT12_IDX, + [13] = HP_PROBE_TOP_OUT13_IDX, + [14] = HP_PROBE_TOP_OUT14_IDX, + [15] = HP_PROBE_TOP_OUT15_IDX, + } + } + } +}; diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 407dabbe59..f8b40edfc7 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -267,6 +267,10 @@ config SOC_ASSIST_DEBUG_SUPPORTED bool default y +config SOC_DEBUG_PROBE_SUPPORTED + bool + default y + config SOC_WDT_SUPPORTED bool default y @@ -639,6 +643,14 @@ config SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER bool default y +config SOC_DEBUG_PROBE_NUM_UNIT + int + default 1 + +config SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH + int + default 16 + config SOC_GPIO_SUPPORT_FORCE_HOLD bool default y diff --git a/components/soc/esp32p4/include/soc/debug_probe_targets.h b/components/soc/esp32p4/include/soc/debug_probe_targets.h new file mode 100644 index 0000000000..a3890d570a --- /dev/null +++ b/components/soc/esp32p4/include/soc/debug_probe_targets.h @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Target module that we want to attach the probe to + * + * @note The target module ID can be obtained from the prob_grp15[7:0] + */ +typedef enum { + DEBUG_PROBE_TARGET_MIPI_CSI_HOST = 0, // MIPI CSI Host + DEBUG_PROBE_TARGET_AXI_GDMA = 1, // AXI GDMA + DEBUG_PROBE_TARGET_I3C = 2, // I3C + DEBUG_PROBE_TARGET_HP_TCM = 3, // HP TCM Memory + DEBUG_PROBE_TARGET_USB_OTG_FS = 4, // USB OTG FS (1.1) + DEBUG_PROBE_TARGET_MIPI_CSI_BRG = 5, // MIPI CSI Bridge + DEBUG_PROBE_TARGET_MSPI_PSRAM = 6, // MSPI PSRAM + DEBUG_PROBE_TARGET_MIPI_DSI_BRG = 7, // MIPI DSI Bridge + DEBUG_PROBE_TARGET_DW_GDMA = 8, // DW GDMA + DEBUG_PROBE_TARGET_AXI_ICM = 9, // AXI ICM matrix + DEBUG_PROBE_TARGET_L2_MEM = 10, // L2 Memory + DEBUG_PROBE_TARGET_BIT_SCRAMBLER = 11, // Bit Scrambler + DEBUG_PROBE_TARGET_MSPI_FLASH = 12, // MSPI Flash + DEBUG_PROBE_TARGET_L1_CACHE = 13, // L1 Cache + DEBUG_PROBE_TARGET_HP_CORE = 14, // HP Core + DEBUG_PROBE_TARGET_L2_CACHE = 15, // L2 Cache + DEBUG_PROBE_TARGET_LP_PROBE_IN = 16, // LP System Probe In + DEBUG_PROBE_TARGET_USJ = 17, // USB Serial JTAG + DEBUG_PROBE_TARGET_EMAC = 18, // EMAC + DEBUG_PROBE_TARGET_JPEG = 19, // JPEG + DEBUG_PROBE_TARGET_PPA = 20, // PPA + DEBUG_PROBE_TARGET_DMA2D = 21, // DMA2D + DEBUG_PROBE_TARGET_LEDC = 22, // LEDC + DEBUG_PROBE_TARGET_SDMMC = 23, // SDMMC + DEBUG_PROBE_TARGET_ISP = 24, // ISP + DEBUG_PROBE_TARGET_USB_OTG_HS = 25, // USB OTG HS (2.0) + DEBUG_PROBE_TARGET_H264 = 26, // H264 + DEBUG_PROBE_TARGET_MCPWM0 = 27, // MCPWM0 + DEBUG_PROBE_TARGET_MCPWM1 = 28, // MCPWM1 + DEBUG_PROBE_TARGET_REGDMA = 29, // REGDMA + DEBUG_PROBE_TARGET_PVT = 30, // PVT +} soc_debug_probe_target_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 3f9dfd3bd8..4760b27096 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -85,6 +85,7 @@ #define SOC_SDMMC_HOST_SUPPORTED 1 #define SOC_CLK_TREE_SUPPORTED 1 #define SOC_ASSIST_DEBUG_SUPPORTED 1 +#define SOC_DEBUG_PROBE_SUPPORTED 1 #define SOC_WDT_SUPPORTED 1 #define SOC_SPI_FLASH_SUPPORTED 1 #define SOC_TOUCH_SENSOR_SUPPORTED 1 @@ -95,6 +96,7 @@ #define SOC_DEEP_SLEEP_SUPPORTED 1 #define SOC_PM_SUPPORTED 1 + /*-------------------------- XTAL CAPS ---------------------------------------*/ #define SOC_XTAL_SUPPORT_40M 1 @@ -252,6 +254,9 @@ #define SOC_GPIO_CLOCKOUT_CHANNEL_NUM (2) #define SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER (1) +#define SOC_DEBUG_PROBE_NUM_UNIT (1U) // Number of debug probe units +#define SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH (16) // Maximum width of the debug probe output in each unit + // Support to force hold all IOs #define SOC_GPIO_SUPPORT_FORCE_HOLD (1) // Support to hold a single digital I/O when the digital domain is powered off diff --git a/components/soc/include/soc/debug_probe_periph.h b/components/soc/include/soc/debug_probe_periph.h new file mode 100644 index 0000000000..d125678403 --- /dev/null +++ b/components/soc/include/soc/debug_probe_periph.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include +#include "soc/soc_caps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if SOC_DEBUG_PROBE_SUPPORTED +typedef struct { + struct { + const int out_sig[SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH]; + } units[SOC_DEBUG_PROBE_NUM_UNIT]; +} debug_probe_signal_conn_t; + +extern const debug_probe_signal_conn_t debug_probe_periph_signals; + +#endif // SOC_DEBUG_PROBE_SUPPORTED +#ifdef __cplusplus +} +#endif