From 200eb866dc681031bf932459c9787ecd9846209d Mon Sep 17 00:00:00 2001 From: morris Date: Mon, 7 Aug 2023 18:50:50 +0800 Subject: [PATCH 1/2] feat(gdma): support hardware crc calculation On ESP32-P4, the GDMA peripherals support CRC calculating. --- components/esp_hw_support/dma/gdma.c | 53 +++++++- .../esp_hw_support/include/esp_private/gdma.h | 43 ++++++ .../test_apps/dma/main/test_gdma.c | 115 ++++++++++++++++ components/hal/CMakeLists.txt | 4 + .../hal/esp32p4/include/hal/ahb_dma_ll.h | 124 ++++++++++++++++++ .../hal/esp32p4/include/hal/axi_dma_ll.h | 124 ++++++++++++++++++ components/hal/esp32p4/include/hal/gdma_ll.h | 15 +++ components/hal/gdma_hal_ahb_v2.c | 63 ++++++++- components/hal/gdma_hal_axi.c | 63 ++++++++- components/hal/gdma_hal_crc_gen.c | 87 ++++++++++++ components/hal/gdma_hal_top.c | 17 +++ components/hal/include/hal/gdma_hal.h | 27 ++++ .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32p4/include/soc/ahb_dma_reg.h | 72 +++++----- .../soc/esp32p4/include/soc/ahb_dma_struct.h | 16 +-- .../soc/esp32p4/include/soc/axi_dma_reg.h | 72 +++++----- .../soc/esp32p4/include/soc/axi_dma_struct.h | 12 +- components/soc/esp32p4/include/soc/soc_caps.h | 1 + 18 files changed, 823 insertions(+), 89 deletions(-) create mode 100644 components/hal/gdma_hal_crc_gen.c diff --git a/components/esp_hw_support/dma/gdma.c b/components/esp_hw_support/dma/gdma.c index ce246ca09d..87ffa7e244 100644 --- a/components/esp_hw_support/dma/gdma.c +++ b/components/esp_hw_support/dma/gdma.c @@ -257,7 +257,7 @@ esp_err_t gdma_connect(gdma_channel_handle_t dma_chan, gdma_trigger_t trig_perip gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; bool periph_conflict = false; - // + if (trig_periph.bus_id != SOC_GDMA_BUS_ANY) { ESP_RETURN_ON_FALSE(trig_periph.bus_id == group->bus_id, ESP_ERR_INVALID_ARG, TAG, "peripheral and DMA system bus mismatch"); @@ -404,6 +404,57 @@ esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority) return ESP_OK; } +#if SOC_GDMA_SUPPORT_CRC +esp_err_t gdma_config_crc_calculator(gdma_channel_handle_t dma_chan, const gdma_crc_calculator_config_t *config) +{ + ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + gdma_pair_t *pair = dma_chan->pair; + gdma_group_t *group = pair->group; + gdma_hal_context_t *hal = &group->hal; + switch (group->bus_id) { +#if SOC_AHB_GDMA_SUPPORTED + case SOC_GDMA_BUS_AHB: + ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AHB_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width"); + break; +#endif // SOC_AHB_GDMA_SUPPORTED +#if SOC_AXI_GDMA_SUPPORTED + case SOC_GDMA_BUS_AXI: + ESP_RETURN_ON_FALSE(config->crc_bit_width <= GDMA_LL_AXI_MAX_CRC_BIT_WIDTH, ESP_ERR_INVALID_ARG, TAG, "invalid crc bit width"); + break; +#endif // SOC_AXI_GDMA_SUPPORTED + default: + ESP_LOGE(TAG, "invalid bus id: %d", group->bus_id); + return ESP_ERR_INVALID_ARG; + } + + // clear the previous CRC result + gdma_hal_clear_crc(hal, pair->pair_id, dma_chan->direction); + + // set polynomial and initial value + gdma_hal_crc_config_t hal_config = { + .crc_bit_width = config->crc_bit_width, + .poly_hex = config->poly_hex, + .init_value = config->init_value, + .reverse_data_mask = config->reverse_data_mask, + }; + gdma_hal_set_crc_poly(hal, pair->pair_id, dma_chan->direction, &hal_config); + + return ESP_OK; +} + +esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result) +{ + ESP_RETURN_ON_FALSE(dma_chan && result, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + gdma_pair_t *pair = dma_chan->pair; + gdma_group_t *group = pair->group; + gdma_hal_context_t *hal = &group->hal; + + *result = gdma_hal_get_crc_result(hal, pair->pair_id, dma_chan->direction); + + return ESP_OK; +} +#endif // SOC_GDMA_SUPPORT_CRC + esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_tx_event_callbacks_t *cbs, void *user_data) { ESP_RETURN_ON_FALSE(dma_chan && cbs && dma_chan->direction == GDMA_CHANNEL_DIRECTION_TX, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); diff --git a/components/esp_hw_support/include/esp_private/gdma.h b/components/esp_hw_support/include/esp_private/gdma.h index 73093b019c..460309580c 100644 --- a/components/esp_hw_support/include/esp_private/gdma.h +++ b/components/esp_hw_support/include/esp_private/gdma.h @@ -354,6 +354,7 @@ esp_err_t gdma_append(gdma_channel_handle_t dma_chan); */ esp_err_t gdma_reset(gdma_channel_handle_t dma_chan); +#if SOC_GDMA_SUPPORT_ETM /** * @brief GDMA ETM event configuration */ @@ -400,6 +401,7 @@ typedef struct { * - ESP_FAIL: Get ETM task failed because of other error */ esp_err_t gdma_new_etm_task(gdma_channel_handle_t dma_chan, const gdma_etm_task_config_t *config, esp_etm_task_handle_t *out_task); +#endif // SOC_GDMA_SUPPORT_ETM /** * @brief Get the mask of free M2M trigger IDs @@ -417,6 +419,47 @@ esp_err_t gdma_new_etm_task(gdma_channel_handle_t dma_chan, const gdma_etm_task_ */ esp_err_t gdma_get_free_m2m_trig_id_mask(gdma_channel_handle_t dma_chan, uint32_t *mask); +#if SOC_GDMA_SUPPORT_CRC +/** + * @brief CRC Calculator configuration + */ +typedef struct { + uint32_t init_value; /*!< CRC initial value */ + uint32_t crc_bit_width; /*!< CRC bit width */ + uint32_t poly_hex; /*!< Polynomial Formula, in hex */ + bool reverse_data_mask; /*!< Reverse data mask, used when you want to reverse the input data (a.k.a, refin) */ +} gdma_crc_calculator_config_t; + +/** + * @brief Configure CRC Calculator + * + * @note This function must be called before `gdma_start`. + * @note The CRC Calculator will reset itself automatically if the DMA stops and starts again. + * + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] config CRC Calculator configuration + * @return + * - ESP_OK: Configure CRC Calculator successfully + * - ESP_ERR_INVALID_ARG: Configure CRC Calculator failed because of invalid argument + * - ESP_FAIL: Configure CRC Calculator failed because of other error + */ +esp_err_t gdma_config_crc_calculator(gdma_channel_handle_t dma_chan, const gdma_crc_calculator_config_t *config); + +/** + * @brief Get CRC Calculator result + * + * @note You need to call this function before a new DMA transaction starts, otherwise the CRC results may be overridden. + * + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[out] result Returned CRC result + * @return + * - ESP_OK: Get CRC result successfully + * - ESP_ERR_INVALID_ARG: Get CRC result failed because of invalid argument + * - ESP_FAIL: Get CRC result failed because of other error + */ +esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result); +#endif // SOC_GDMA_SUPPORT_CRC + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/test_apps/dma/main/test_gdma.c b/components/esp_hw_support/test_apps/dma/main/test_gdma.c index 37c79af66b..ba9d2eb333 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_gdma.c +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -299,3 +300,117 @@ TEST_CASE("GDMA M2M Mode", "[GDMA]") TEST_ESP_OK(gdma_del_channel(rx_chan)); #endif // SOC_AXI_GDMA_SUPPORTED } + +#if SOC_GDMA_SUPPORT_CRC +typedef struct { + uint32_t init_value; + uint32_t crc_bit_width; + uint32_t poly_hex; + bool reverse_data_mask; + uint32_t expected_result; +} test_crc_case_t; +static test_crc_case_t crc_test_cases[] = { + // CRC8, x^8+x^2+x+1 + [0] = { + .crc_bit_width = 8, + .init_value = 0x00, + .poly_hex = 0x07, + .expected_result = 0xC6, + }, + [1] = { + .crc_bit_width = 8, + .init_value = 0x00, + .poly_hex = 0x07, + .reverse_data_mask = true, // refin = true + .expected_result = 0xDE, + }, + // CRC16, x^16+x^12+x^5+1 + [2] = { + .crc_bit_width = 16, + .init_value = 0xFFFF, + .poly_hex = 0x1021, + .expected_result = 0x5289, + }, + // CRC32, x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 + [3] = { + .crc_bit_width = 32, + .init_value = 0xFFFFFFFF, + .poly_hex = 0x04C11DB7, + .expected_result = 0x63B3E283, + } +}; + +// CRC online: https://www.lddgo.net/en/encrypt/crc +static void test_gdma_crc_calculation(gdma_channel_handle_t tx_chan, int test_num_crc_algorithm) +{ + uint32_t crc_result = 0; + const char *test_input_string = "Share::Connect::Innovate"; + size_t input_data_size = strlen(test_input_string); + printf("Calculate CRC value for string: \"%s\"\r\n", test_input_string); + + gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0); + // get a free DMA trigger ID + uint32_t free_m2m_id_mask = 0; + gdma_get_free_m2m_trig_id_mask(tx_chan, &free_m2m_id_mask); + m2m_trigger.instance_id = __builtin_ctz(free_m2m_id_mask); + TEST_ESP_OK(gdma_connect(tx_chan, m2m_trigger)); + + uint8_t *src_buf = heap_caps_aligned_calloc(64, 1, 256, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(src_buf); + dma_descriptor_align8_t *tx_descs = (dma_descriptor_align8_t *) src_buf; + uint8_t *src_data = src_buf + 64; + memcpy(src_data, test_input_string, input_data_size); + + tx_descs->buffer = src_data; + tx_descs->dw0.size = 256 - 64; + tx_descs->dw0.length = input_data_size; + tx_descs->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA; + tx_descs->dw0.suc_eof = 1; + tx_descs->next = NULL; + +#if CONFIG_IDF_TARGET_ESP32P4 + // do write-back for the buffer because it's in the cache + Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)src_buf, 256); +#endif + + for (int i = 0; i < test_num_crc_algorithm; i++) { + gdma_crc_calculator_config_t crc_config = { + .crc_bit_width = crc_test_cases[i].crc_bit_width, + .init_value = crc_test_cases[i].init_value, + .poly_hex = crc_test_cases[i].poly_hex, + .reverse_data_mask = crc_test_cases[i].reverse_data_mask, + }; + TEST_ESP_OK(gdma_config_crc_calculator(tx_chan, &crc_config)); + TEST_ESP_OK(gdma_reset(tx_chan)); + TEST_ESP_OK(gdma_start(tx_chan, (intptr_t)tx_descs)); + // simply wait for the transfer done + vTaskDelay(pdMS_TO_TICKS(100)); + TEST_ESP_OK(gdma_crc_get_result(tx_chan, &crc_result)); + printf("CRC Result: 0x%"PRIx32"\r\n", crc_result); + TEST_ASSERT_EQUAL(crc_test_cases[i].expected_result, crc_result); + } + + free(src_buf); +} + +TEST_CASE("GDMA CRC Calculation", "[GDMA]") +{ + gdma_channel_handle_t tx_chan = NULL; + gdma_channel_alloc_config_t tx_chan_alloc_config = { + .direction = GDMA_CHANNEL_DIRECTION_TX, + }; +#if SOC_AHB_GDMA_SUPPORTED + printf("Test CRC calculation for AHB GDMA\r\n"); + TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan)); + test_gdma_crc_calculation(tx_chan, 4); + TEST_ESP_OK(gdma_del_channel(tx_chan)); +#endif // SOC_AHB_GDMA_SUPPORTED + +#if SOC_AXI_GDMA_SUPPORTED + printf("Test CRC calculation for AXI GDMA\r\n"); + TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan)); + test_gdma_crc_calculation(tx_chan, 3); + TEST_ESP_OK(gdma_del_channel(tx_chan)); +#endif // SOC_AXI_GDMA_SUPPORTED +} +#endif // SOC_GDMA_SUPPORT_CRC diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 55f1c8057b..0f9b9e4bdf 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -91,6 +91,10 @@ if(NOT BOOTLOADER_BUILD) list(APPEND srcs "gdma_hal_top.c") endif() + if(CONFIG_SOC_GDMA_SUPPORT_CRC) + list(APPEND srcs "gdma_hal_crc_gen.c") + endif() + if(CONFIG_SOC_AHB_GDMA_VERSION EQUAL 1) list(APPEND srcs "gdma_hal_ahb_v1.c") endif() diff --git a/components/hal/esp32p4/include/hal/ahb_dma_ll.h b/components/hal/esp32p4/include/hal/ahb_dma_ll.h index 2f4d880821..4db5bd3975 100644 --- a/components/hal/esp32p4/include/hal/ahb_dma_ll.h +++ b/components/hal/esp32p4/include/hal/ahb_dma_ll.h @@ -8,6 +8,8 @@ #include #include #include +#include "hal/assert.h" +#include "hal/misc.h" #include "hal/gdma_types.h" #include "hal/gdma_ll.h" #include "soc/ahb_dma_struct.h" @@ -500,6 +502,128 @@ static inline void ahb_dma_ll_tx_enable_etm_task(ahb_dma_dev_t *dev, uint32_t ch dev->channel[channel].out.out_conf0.out_etm_en_chn = enable; } +///////////////////////////////////// CRC-TX ///////////////////////////////////////// + +/** + * @brief Clear the CRC result for the TX channel + */ +static inline void ahb_dma_ll_tx_crc_clear(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->out_crc[channel].crc_clear.out_crc_clear_chn_reg = 1; + dev->out_crc[channel].crc_clear.out_crc_clear_chn_reg = 0; +} + +/** + * @brief Set CRC width for TX channel + */ +static inline void ahb_dma_ll_tx_crc_set_width(ahb_dma_dev_t *dev, uint32_t channel, uint32_t width) +{ + HAL_ASSERT(width <= 32); + dev->out_crc[channel].crc_width.tx_crc_width_chn = (width - 1) / 8; +} + +/** + * @brief Set CRC initial value for TX channel + */ +static inline void ahb_dma_ll_tx_crc_set_init_value(ahb_dma_dev_t *dev, uint32_t channel, uint32_t value) +{ + dev->out_crc[channel].crc_init_data.out_crc_init_data_chn = value; +} + +/** + * @brief Get CRC result for TX channel + */ +static inline uint32_t ahb_dma_ll_tx_crc_get_result(ahb_dma_dev_t *dev, uint32_t channel) +{ + return dev->out_crc[channel].crc_final_result.out_crc_final_result_chn; +} + +/** + * @brief Latch the CRC configuration to the hardware, TX channel + */ +static inline void ahb_dma_ll_tx_crc_latch_config(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->out_crc[channel].crc_width.tx_crc_latch_flag_chn = 1; + dev->out_crc[channel].crc_width.tx_crc_latch_flag_chn = 0; +} + +/** + * @brief Set the lfsr and data mask that used by the Parallel CRC calculation formula for a given CRC bit, TX channel + */ +static inline void ahb_dma_ll_tx_crc_set_lfsr_data_mask(ahb_dma_dev_t *dev, uint32_t channel, uint32_t crc_bit, + uint32_t lfsr_mask, uint32_t data_mask, bool reverse_data_mask) +{ + dev->out_crc[channel].crc_en_addr.tx_crc_en_addr_chn = crc_bit; + dev->out_crc[channel].crc_en_wr_data.tx_crc_en_wr_data_chn = lfsr_mask; + dev->out_crc[channel].crc_data_en_addr.tx_crc_data_en_addr_chn = crc_bit; + if (reverse_data_mask) { + // "& 0xff" because the hardware only support 8-bit data + data_mask = _bitwise_reverse(data_mask & 0xFF); + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->out_crc[channel].crc_data_en_wr_data, tx_crc_data_en_wr_data_chn, data_mask); +} + +///////////////////////////////////// CRC-RX ///////////////////////////////////////// + +/** + * @brief Clear the CRC result for the RX channel + */ +static inline void ahb_dma_ll_rx_crc_clear(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->in_crc[channel].crc_clear.in_crc_clear_chn_reg = 1; + dev->in_crc[channel].crc_clear.in_crc_clear_chn_reg = 0; +} + +/** + * @brief Set CRC width for RX channel + */ +static inline void ahb_dma_ll_rx_crc_set_width(ahb_dma_dev_t *dev, uint32_t channel, uint32_t width) +{ + HAL_ASSERT(width <= 32); + dev->in_crc[channel].crc_width.rx_crc_width_chn = (width - 1) / 8; +} + +/** + * @brief Set CRC initial value for RX channel + */ +static inline void ahb_dma_ll_rx_crc_set_init_value(ahb_dma_dev_t *dev, uint32_t channel, uint32_t value) +{ + dev->in_crc[channel].crc_init_data.in_crc_init_data_chn = value; +} + +/** + * @brief Get CRC result for RX channel + */ +static inline uint32_t ahb_dma_ll_rx_crc_get_result(ahb_dma_dev_t *dev, uint32_t channel) +{ + return dev->in_crc[channel].crc_final_result.in_crc_final_result_chn; +} + +/** + * @brief Latch the CRC configuration to the hardware, RX channel + */ +static inline void ahb_dma_ll_rx_crc_latch_config(ahb_dma_dev_t *dev, uint32_t channel) +{ + dev->in_crc[channel].crc_width.rx_crc_latch_flag_chn = 1; + dev->in_crc[channel].crc_width.rx_crc_latch_flag_chn = 0; +} + +/** + * @brief Set the lfsr and data mask that used by the Parallel CRC calculation formula for a given CRC bit, RX channel + */ +static inline void ahb_dma_ll_rx_crc_set_lfsr_data_mask(ahb_dma_dev_t *dev, uint32_t channel, uint32_t crc_bit, + uint32_t lfsr_mask, uint32_t data_mask, bool reverse_data_mask) +{ + dev->in_crc[channel].crc_en_addr.rx_crc_en_addr_chn = crc_bit; + dev->in_crc[channel].crc_en_wr_data.rx_crc_en_wr_data_chn = lfsr_mask; + dev->in_crc[channel].crc_data_en_addr.rx_crc_data_en_addr_chn = crc_bit; + if (reverse_data_mask) { + // "& 0xff" because the hardware only support 8-bit data + data_mask = _bitwise_reverse(data_mask & 0xFF); + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->in_crc[channel].crc_data_en_wr_data, rx_crc_data_en_wr_data_chn, data_mask); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/axi_dma_ll.h b/components/hal/esp32p4/include/hal/axi_dma_ll.h index f044cc6707..bbcf01fde7 100644 --- a/components/hal/esp32p4/include/hal/axi_dma_ll.h +++ b/components/hal/esp32p4/include/hal/axi_dma_ll.h @@ -8,6 +8,8 @@ #include #include #include +#include "hal/assert.h" +#include "hal/misc.h" #include "hal/gdma_types.h" #include "hal/gdma_ll.h" #include "soc/axi_dma_struct.h" @@ -446,6 +448,128 @@ static inline void axi_dma_ll_tx_enable_etm_task(axi_dma_dev_t *dev, uint32_t ch dev->out[channel].conf.out_conf0.out_etm_en_chn = enable; } +///////////////////////////////////// CRC-TX ///////////////////////////////////////// + +/** + * @brief Clear the CRC result for the TX channel + */ +static inline void axi_dma_ll_tx_crc_clear(axi_dma_dev_t *dev, uint32_t channel) +{ + dev->out[channel].crc.out_crc_clear.out_crc_clear_chn_reg = 1; + dev->out[channel].crc.out_crc_clear.out_crc_clear_chn_reg = 0; +} + +/** + * @brief Set CRC width for TX channel + */ +static inline void axi_dma_ll_tx_crc_set_width(axi_dma_dev_t *dev, uint32_t channel, uint32_t width) +{ + HAL_ASSERT(width <= 16); + dev->out[channel].crc.tx_crc_width.tx_crc_width_chn = (width - 1) / 8; +} + +/** + * @brief Set CRC initial value for TX channel + */ +static inline void axi_dma_ll_tx_crc_set_init_value(axi_dma_dev_t *dev, uint32_t channel, uint32_t value) +{ + dev->out[channel].crc.out_crc_init_data.out_crc_init_data_chn = value; +} + +/** + * @brief Get CRC result for TX channel + */ +static inline uint32_t axi_dma_ll_tx_crc_get_result(axi_dma_dev_t *dev, uint32_t channel) +{ + return dev->out[channel].crc.out_crc_final_result.out_crc_final_result_chn; +} + +/** + * @brief Latch the CRC configuration to the hardware, TX channel + */ +static inline void axi_dma_ll_tx_crc_latch_config(axi_dma_dev_t *dev, uint32_t channel) +{ + dev->out[channel].crc.tx_crc_width.tx_crc_latch_flag_chn = 1; + dev->out[channel].crc.tx_crc_width.tx_crc_latch_flag_chn = 0; +} + +/** + * @brief Set the lfsr and data mask that used by the Parallel CRC calculation formula for a given CRC bit, TX channel + */ +static inline void axi_dma_ll_tx_crc_set_lfsr_data_mask(axi_dma_dev_t *dev, uint32_t channel, uint32_t crc_bit, + uint32_t lfsr_mask, uint32_t data_mask, bool reverse_data_mask) +{ + dev->out[channel].crc.tx_crc_en_addr.tx_crc_en_addr_chn = crc_bit; + dev->out[channel].crc.tx_crc_en_wr_data.tx_crc_en_wr_data_chn = lfsr_mask; + dev->out[channel].crc.tx_crc_data_en_addr.tx_crc_data_en_addr_chn = crc_bit; + if (reverse_data_mask) { + // "& 0xff" because the hardware only support 8-bit data + data_mask = _bitwise_reverse(data_mask & 0xFF); + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->out[channel].crc.tx_crc_data_en_wr_data, tx_crc_data_en_wr_data_chn, data_mask); +} + +///////////////////////////////////// CRC-RX ///////////////////////////////////////// + +/** + * @brief Clear the CRC result for the RX channel + */ +static inline void axi_dma_ll_rx_crc_clear(axi_dma_dev_t *dev, uint32_t channel) +{ + dev->in[channel].crc.in_crc_clear.in_crc_clear_chn_reg = 1; + dev->in[channel].crc.in_crc_clear.in_crc_clear_chn_reg = 0; +} + +/** + * @brief Set CRC width for RX channel + */ +static inline void axi_dma_ll_rx_crc_set_width(axi_dma_dev_t *dev, uint32_t channel, uint32_t width) +{ + HAL_ASSERT(width <= 16); + dev->in[channel].crc.rx_crc_width.rx_crc_width_chn = (width - 1) / 8; +} + +/** + * @brief Set CRC initial value for RX channel + */ +static inline void axi_dma_ll_rx_crc_set_init_value(axi_dma_dev_t *dev, uint32_t channel, uint32_t value) +{ + dev->in[channel].crc.in_crc_init_data.in_crc_init_data_chn = value; +} + +/** + * @brief Get CRC result for RX channel + */ +static inline uint32_t axi_dma_ll_rx_crc_get_result(axi_dma_dev_t *dev, uint32_t channel) +{ + return dev->in[channel].crc.in_crc_final_result.in_crc_final_result_chn; +} + +/** + * @brief Latch the CRC configuration to the hardware, RX channel + */ +static inline void axi_dma_ll_rx_crc_latch_config(axi_dma_dev_t *dev, uint32_t channel) +{ + dev->in[channel].crc.rx_crc_width.rx_crc_latch_flag_chn = 1; + dev->in[channel].crc.rx_crc_width.rx_crc_latch_flag_chn = 0; +} + +/** + * @brief Set the lfsr and data mask that used by the Parallel CRC calculation formula for a given CRC bit, RX channel + */ +static inline void axi_dma_ll_rx_crc_set_lfsr_data_mask(axi_dma_dev_t *dev, uint32_t channel, uint32_t crc_bit, + uint32_t lfsr_mask, uint32_t data_mask, bool reverse_data_mask) +{ + dev->in[channel].crc.rx_crc_en_addr.rx_crc_en_addr_chn = crc_bit; + dev->in[channel].crc.rx_crc_en_wr_data.rx_crc_en_wr_data_chn = lfsr_mask; + dev->in[channel].crc.rx_crc_data_en_addr.rx_crc_data_en_addr_chn = crc_bit; + if (reverse_data_mask) { + // "& 0xff" because the hardware only support 8-bit data + data_mask = _bitwise_reverse(data_mask & 0xFF); + } + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->in[channel].crc.rx_crc_data_en_wr_data, rx_crc_data_en_wr_data_chn, data_mask); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/gdma_ll.h b/components/hal/esp32p4/include/hal/gdma_ll.h index 649620bd3e..f29f33feb1 100644 --- a/components/hal/esp32p4/include/hal/gdma_ll.h +++ b/components/hal/esp32p4/include/hal/gdma_ll.h @@ -10,6 +10,8 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif @@ -40,6 +42,19 @@ extern "C" { #define GDMA_LL_AXI_NUM_GROUPS 1 // Number of AXI GDMA groups #define GDMA_LL_AXI_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AXI group +#define GDMA_LL_PARALLEL_CRC_DATA_WIDTH 8 // Parallel CRC data width is fixed to 8bits +#define GDMA_LL_AHB_MAX_CRC_BIT_WIDTH 32 // Max CRC bit width supported by AHB GDMA +#define GDMA_LL_AXI_MAX_CRC_BIT_WIDTH 16 // Max CRC bit width supported by AXI GDMA + +__attribute__((always_inline)) +static inline uint8_t _bitwise_reverse(uint8_t n) +{ + n = ((n & 0xf0) >> 4) | ((n & 0x0f) << 4); + n = ((n & 0xcc) >> 2) | ((n & 0x33) << 2); + n = ((n & 0xaa) >> 1) | ((n & 0x55) << 1); + return n; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/gdma_hal_ahb_v2.c b/components/hal/gdma_hal_ahb_v2.c index 348f878baf..58a0dcfa1c 100644 --- a/components/hal/gdma_hal_ahb_v2.c +++ b/components/hal/gdma_hal_ahb_v2.c @@ -150,9 +150,66 @@ uint32_t gdma_ahb_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gd } } +#if SOC_GDMA_SUPPORT_CRC +void gdma_ahb_hal_clear_crc(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir) +{ + if (dir == GDMA_CHANNEL_DIRECTION_RX) { + ahb_dma_ll_rx_crc_clear(hal->ahb_dma_dev, chan_id); + } else { + ahb_dma_ll_tx_crc_clear(hal->ahb_dma_dev, chan_id); + } +} + +void gdma_ahb_hal_set_crc_poly(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, const gdma_hal_crc_config_t *config) +{ + uint32_t init_value = config->init_value; + uint32_t crc_bit_width = config->crc_bit_width; + uint32_t poly_hex = config->poly_hex; + // bit matrix for parallel CRC + uint32_t lfsr_matrix[crc_bit_width]; + uint32_t data_matrix[GDMA_LL_PARALLEL_CRC_DATA_WIDTH]; + uint32_t lfsr_mask = 0; + uint32_t data_mask = 0; + // build the parallel CRC matrix first, later we will extract the control mask from it + gdma_hal_build_parallel_crc_matrix(crc_bit_width, poly_hex, GDMA_LL_PARALLEL_CRC_DATA_WIDTH, + lfsr_matrix, data_matrix); + if (dir == GDMA_CHANNEL_DIRECTION_RX) { + ahb_dma_ll_rx_crc_set_init_value(hal->ahb_dma_dev, chan_id, init_value); + ahb_dma_ll_rx_crc_set_width(hal->ahb_dma_dev, chan_id, crc_bit_width); + for (uint32_t i = 0; i < crc_bit_width; i++) { + // extract the control mask from the matrix, for each CRC bit + data_mask = gdma_hal_get_data_mask_from_matrix(data_matrix, GDMA_LL_PARALLEL_CRC_DATA_WIDTH, i); + lfsr_mask = gdma_hal_get_lfsr_mask_from_matrix(lfsr_matrix, crc_bit_width, i); + ahb_dma_ll_rx_crc_set_lfsr_data_mask(hal->ahb_dma_dev, chan_id, i, lfsr_mask, data_mask, config->reverse_data_mask); + ahb_dma_ll_rx_crc_latch_config(hal->ahb_dma_dev, chan_id); + } + } else { + ahb_dma_ll_tx_crc_set_init_value(hal->ahb_dma_dev, chan_id, init_value); + ahb_dma_ll_tx_crc_set_width(hal->ahb_dma_dev, chan_id, crc_bit_width); + for (uint32_t i = 0; i < crc_bit_width; i++) { + // extract the control mask from the matrix, for each CRC bit + data_mask = gdma_hal_get_data_mask_from_matrix(data_matrix, GDMA_LL_PARALLEL_CRC_DATA_WIDTH, i); + lfsr_mask = gdma_hal_get_lfsr_mask_from_matrix(lfsr_matrix, crc_bit_width, i); + ahb_dma_ll_tx_crc_set_lfsr_data_mask(hal->ahb_dma_dev, chan_id, i, lfsr_mask, data_mask, config->reverse_data_mask); + ahb_dma_ll_tx_crc_latch_config(hal->ahb_dma_dev, chan_id); + } + } +} + +uint32_t gdma_ahb_hal_get_crc_result(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir) +{ + if (dir == GDMA_CHANNEL_DIRECTION_RX) { + return ahb_dma_ll_rx_crc_get_result(hal->ahb_dma_dev, chan_id); + } else { + return ahb_dma_ll_tx_crc_get_result(hal->ahb_dma_dev, chan_id); + } +} +#endif // SOC_GDMA_SUPPORT_CRC + void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) { hal->ahb_dma_dev = AHB_DMA_LL_GET_HW(config->group_id - GDMA_LL_AHB_GROUP_START_ID); + hal->priv_data = &gdma_ahb_hal_priv_data; hal->start_with_desc = gdma_ahb_hal_start_with_desc; hal->stop = gdma_ahb_hal_stop; hal->append = gdma_ahb_hal_append; @@ -167,5 +224,9 @@ void gdma_ahb_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) hal->read_intr_status = gdma_ahb_hal_read_intr_status; hal->get_intr_status_reg = gdma_ahb_hal_get_intr_status_reg; hal->get_eof_desc_addr = gdma_ahb_hal_get_eof_desc_addr; - hal->priv_data = &gdma_ahb_hal_priv_data; +#if SOC_GDMA_SUPPORT_CRC + hal->clear_crc = gdma_ahb_hal_clear_crc; + hal->set_crc_poly = gdma_ahb_hal_set_crc_poly; + hal->get_crc_result = gdma_ahb_hal_get_crc_result; +#endif // SOC_GDMA_SUPPORT_CRC } diff --git a/components/hal/gdma_hal_axi.c b/components/hal/gdma_hal_axi.c index 3555181c41..9b23c035a6 100644 --- a/components/hal/gdma_hal_axi.c +++ b/components/hal/gdma_hal_axi.c @@ -150,9 +150,66 @@ uint32_t gdma_axi_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gd } } +#if SOC_GDMA_SUPPORT_CRC +void gdma_axi_hal_clear_crc(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir) +{ + if (dir == GDMA_CHANNEL_DIRECTION_RX) { + axi_dma_ll_rx_crc_clear(hal->axi_dma_dev, chan_id); + } else { + axi_dma_ll_tx_crc_clear(hal->axi_dma_dev, chan_id); + } +} + +void gdma_axi_hal_set_crc_poly(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, const gdma_hal_crc_config_t *config) +{ + uint32_t init_value = config->init_value; + uint32_t crc_bit_width = config->crc_bit_width; + uint32_t poly_hex = config->poly_hex; + // bit matrix for parallel CRC + uint32_t lfsr_matrix[crc_bit_width]; + uint32_t data_matrix[GDMA_LL_PARALLEL_CRC_DATA_WIDTH]; + uint32_t lfsr_mask = 0; + uint32_t data_mask = 0; + // build the parallel CRC matrix first, later we will extract the control mask from it + gdma_hal_build_parallel_crc_matrix(crc_bit_width, poly_hex, GDMA_LL_PARALLEL_CRC_DATA_WIDTH, + lfsr_matrix, data_matrix); + if (dir == GDMA_CHANNEL_DIRECTION_RX) { + axi_dma_ll_rx_crc_set_init_value(hal->axi_dma_dev, chan_id, init_value); + axi_dma_ll_rx_crc_set_width(hal->axi_dma_dev, chan_id, crc_bit_width); + for (uint32_t i = 0; i < crc_bit_width; i++) { + // extract the control mask from the matrix, for each CRC bit + data_mask = gdma_hal_get_data_mask_from_matrix(data_matrix, GDMA_LL_PARALLEL_CRC_DATA_WIDTH, i); + lfsr_mask = gdma_hal_get_lfsr_mask_from_matrix(lfsr_matrix, crc_bit_width, i); + axi_dma_ll_rx_crc_set_lfsr_data_mask(hal->axi_dma_dev, chan_id, i, lfsr_mask, data_mask, config->reverse_data_mask); + axi_dma_ll_rx_crc_latch_config(hal->axi_dma_dev, chan_id); + } + } else { + axi_dma_ll_tx_crc_set_init_value(hal->axi_dma_dev, chan_id, init_value); + axi_dma_ll_tx_crc_set_width(hal->axi_dma_dev, chan_id, crc_bit_width); + for (uint32_t i = 0; i < crc_bit_width; i++) { + // extract the control mask from the matrix, for each CRC bit + data_mask = gdma_hal_get_data_mask_from_matrix(data_matrix, GDMA_LL_PARALLEL_CRC_DATA_WIDTH, i); + lfsr_mask = gdma_hal_get_lfsr_mask_from_matrix(lfsr_matrix, crc_bit_width, i); + axi_dma_ll_tx_crc_set_lfsr_data_mask(hal->axi_dma_dev, chan_id, i, lfsr_mask, data_mask, config->reverse_data_mask); + axi_dma_ll_tx_crc_latch_config(hal->axi_dma_dev, chan_id); + } + } +} + +uint32_t gdma_axi_hal_get_crc_result(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir) +{ + if (dir == GDMA_CHANNEL_DIRECTION_RX) { + return axi_dma_ll_rx_crc_get_result(hal->axi_dma_dev, chan_id); + } else { + return axi_dma_ll_tx_crc_get_result(hal->axi_dma_dev, chan_id); + } +} +#endif // SOC_GDMA_SUPPORT_CRC + void gdma_axi_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) { hal->axi_dma_dev = AXI_DMA_LL_GET_HW(config->group_id - GDMA_LL_AXI_GROUP_START_ID); + hal->priv_data = &gdma_axi_hal_priv_data; hal->start_with_desc = gdma_axi_hal_start_with_desc; hal->stop = gdma_axi_hal_stop; hal->append = gdma_axi_hal_append; @@ -167,5 +224,9 @@ void gdma_axi_hal_init(gdma_hal_context_t *hal, const gdma_hal_config_t *config) hal->read_intr_status = gdma_axi_hal_read_intr_status; hal->get_intr_status_reg = gdma_axi_hal_get_intr_status_reg; hal->get_eof_desc_addr = gdma_axi_hal_get_eof_desc_addr; - hal->priv_data = &gdma_axi_hal_priv_data; +#if SOC_GDMA_SUPPORT_CRC + hal->clear_crc = gdma_axi_hal_clear_crc; + hal->set_crc_poly = gdma_axi_hal_set_crc_poly; + hal->get_crc_result = gdma_axi_hal_get_crc_result; +#endif // SOC_GDMA_SUPPORT_CRC } diff --git a/components/hal/gdma_hal_crc_gen.c b/components/hal/gdma_hal_crc_gen.c new file mode 100644 index 0000000000..3123d82134 --- /dev/null +++ b/components/hal/gdma_hal_crc_gen.c @@ -0,0 +1,87 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +// +// Serially shift {data_in,lfsr_cur} N times to get {lfsr_next} +// +static uint32_t lfsr_serial_shift_crc(uint32_t data_in, uint32_t lfsr_cur, + size_t crc_width, uint32_t crc_poly_hex, + size_t num_bits_to_shift) +{ + uint32_t lfsr_next = lfsr_cur; + + for (int j = 0; j < num_bits_to_shift; j++) { + uint32_t lfsr_upper_bit = lfsr_next >> (crc_width - 1); + + // shift the entire LFSR + for (int i = crc_width - 1; i > 0; i--) { + lfsr_next &= ~(1 << i); + if (crc_poly_hex & (1 << i)) { + // lfsr_next[i] = lfsr_next[i - 1] ^ lfsr_upper_bit ^ data_in[j]; + lfsr_next |= (((lfsr_next >> (i - 1)) ^ lfsr_upper_bit ^ (data_in >> j)) & 0x01) << i; + } else { + // lfsr_next[i] = lfsr_next[i - 1]; + lfsr_next |= (lfsr_next & (1 << (i - 1))) << 1; + } + } + // lfsr_next[0] = lfsr_upper_bit ^ data_in[j]; + lfsr_next &= ~0x01; + lfsr_next |= (lfsr_upper_bit ^ (data_in >> j)) & 0x01; + } + + return lfsr_next; +} + +void gdma_hal_build_parallel_crc_matrix(int crc_width, uint32_t crc_poly_hex, int data_width, + uint32_t *lfsr_transform_matrix, uint32_t *data_transform_matrix) +{ + int N = crc_width; + int M = data_width; + uint32_t lfsr_cur = 0; // N-bit LFSR + uint32_t lfsr_next = 0; // N-bit LFSR + uint32_t data_in = 0; // M-bit data + + // LFSR-2-LFSR matrix[NxN], data_in=0 + for (int n1 = 0; n1 < N; n1++) { + lfsr_cur = 1 << n1; + lfsr_next = lfsr_serial_shift_crc(data_in, lfsr_cur, + crc_width, crc_poly_hex, + data_width); + lfsr_transform_matrix[n1] = lfsr_next; + } + + // Data-2-LFSR matrix[MxN], lfsr_cur=0 + lfsr_cur = 0; + for (int m1 = 0; m1 < M; m1++) { + data_in = 1 << m1; + lfsr_next = lfsr_serial_shift_crc(data_in, lfsr_cur, + crc_width, crc_poly_hex, + data_width); + // Invert CRC data bits + data_transform_matrix[M - m1 - 1] = lfsr_next; + } +} + +uint32_t gdma_hal_get_data_mask_from_matrix(uint32_t *data_transform_matrix, int data_width, int crc_bit) +{ + uint32_t data_mask = 0; + for (int j = 0; j < data_width; j++) { + data_mask |= (data_transform_matrix[j] & (1 << crc_bit)) ? (1 << j) : 0; + } + return data_mask; +} + +uint32_t gdma_hal_get_lfsr_mask_from_matrix(uint32_t *lfsr_transform_matrix, int crc_width, int crc_bit) +{ + uint32_t lfsr_mask = 0; + for (int j = 0; j < crc_width; j++) { + lfsr_mask |= (lfsr_transform_matrix[j] & (1 << crc_bit)) ? (1 << j) : 0; + } + return lfsr_mask; +} diff --git a/components/hal/gdma_hal_top.c b/components/hal/gdma_hal_top.c index ccbcd608a6..2e01d3e9ed 100644 --- a/components/hal/gdma_hal_top.c +++ b/components/hal/gdma_hal_top.c @@ -89,3 +89,20 @@ uint32_t gdma_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gdma_c { return hal->get_eof_desc_addr(hal, chan_id, dir, is_success); } + +#if SOC_GDMA_SUPPORT_CRC +void gdma_hal_clear_crc(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir) +{ + hal->clear_crc(hal, chan_id, dir); +} + +void gdma_hal_set_crc_poly(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, const gdma_hal_crc_config_t *config) +{ + hal->set_crc_poly(hal, chan_id, dir, config); +} + +uint32_t gdma_hal_get_crc_result(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir) +{ + return hal->get_crc_result(hal, chan_id, dir); +} +#endif // SOC_GDMA_SUPPORT_CRC diff --git a/components/hal/include/hal/gdma_hal.h b/components/hal/include/hal/gdma_hal.h index 6bd5221e64..f43792d0d9 100644 --- a/components/hal/include/hal/gdma_hal.h +++ b/components/hal/include/hal/gdma_hal.h @@ -36,6 +36,13 @@ typedef struct { int group_id; /*!< GDMA group ID */ } gdma_hal_config_t; +typedef struct { + uint32_t init_value; /*!< CRC initial value */ + uint32_t crc_bit_width; /*!< CRC bit width */ + uint32_t poly_hex; /*!< Polynomial Formula, in hex */ + bool reverse_data_mask; /*!< Reverse data mask */ +} gdma_hal_crc_config_t; + /** * @brief GDMA HAL private data */ @@ -80,6 +87,11 @@ struct gdma_hal_context_t { void (*clear_intr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, uint32_t intr_event_mask); /// Clear the channel interrupt uint32_t (*read_intr_status)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); /// Read the channel interrupt status uint32_t (*get_eof_desc_addr)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool is_success); /// Get the address of the descriptor with success/error EOF flag set +#if SOC_GDMA_SUPPORT_CRC + void (*clear_crc)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); /// Clear the CRC interim results + void (*set_crc_poly)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, const gdma_hal_crc_config_t *config); /// Set the CRC polynomial + uint32_t (*get_crc_result)(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); /// Get the CRC result +#endif // SOC_GDMA_SUPPORT_CRC }; void gdma_hal_deinit(gdma_hal_context_t *hal); @@ -114,6 +126,21 @@ uint32_t gdma_hal_read_intr_status(gdma_hal_context_t *hal, int chan_id, gdma_ch uint32_t gdma_hal_get_eof_desc_addr(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, bool is_success); +#if SOC_GDMA_SUPPORT_CRC +void gdma_hal_build_parallel_crc_matrix(int crc_width, uint32_t crc_poly_hex, int data_width, + uint32_t *lfsr_transform_matrix, uint32_t *data_transform_matrix); + +uint32_t gdma_hal_get_data_mask_from_matrix(uint32_t *data_transform_matrix, int data_width, int crc_bit); + +uint32_t gdma_hal_get_lfsr_mask_from_matrix(uint32_t *lfsr_transform_matrix, int crc_width, int crc_bit); + +void gdma_hal_clear_crc(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); + +void gdma_hal_set_crc_poly(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir, const gdma_hal_crc_config_t *config); + +uint32_t gdma_hal_get_crc_result(gdma_hal_context_t *hal, int chan_id, gdma_channel_direction_t dir); +#endif // SOC_GDMA_SUPPORT_CRC + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 17d6b9c0b6..75cfb4af06 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -247,6 +247,10 @@ config SOC_AHB_GDMA_VERSION int default 2 +config SOC_GDMA_SUPPORT_CRC + bool + default y + config SOC_GDMA_NUM_GROUPS_MAX int default 2 diff --git a/components/soc/esp32p4/include/soc/ahb_dma_reg.h b/components/soc/esp32p4/include/soc/ahb_dma_reg.h index 11cedbf1d8..d5611013d7 100644 --- a/components/soc/esp32p4/include/soc/ahb_dma_reg.h +++ b/components/soc/esp32p4/include/soc/ahb_dma_reg.h @@ -3124,7 +3124,7 @@ extern "C" { #define AHB_DMA_OUT_CRC_INIT_DATA_CH0_S 0 /** AHB_DMA_TX_CRC_WIDTH_CH0_REG register - * This register is used to confiig tx ch0 crc result width,2'b00 mean crc_width + * This register is used to config tx ch0 crc result width,2'b00 mean crc_width * <=8bit,2'b01 8 Date: Thu, 24 Aug 2023 16:09:24 +0800 Subject: [PATCH 2/2] refactor(gdma): add reset and clock control in LL driver --- components/esp_hw_support/dma/gdma.c | 16 ++++++- components/hal/esp32c2/include/hal/gdma_ll.h | 29 ++++++++++++ components/hal/esp32c3/include/hal/gdma_ll.h | 29 ++++++++++++ components/hal/esp32c6/include/hal/gdma_ll.h | 21 +++++++++ components/hal/esp32h2/include/hal/gdma_ll.h | 21 +++++++++ .../hal/esp32p4/include/hal/clk_gate_ll.h | 16 ------- components/hal/esp32p4/include/hal/gdma_ll.h | 44 +++++++++++++++++-- components/hal/esp32s3/include/hal/gdma_ll.h | 29 ++++++++++++ 8 files changed, 183 insertions(+), 22 deletions(-) diff --git a/components/esp_hw_support/dma/gdma.c b/components/esp_hw_support/dma/gdma.c index 87ffa7e244..ac2b2a7934 100644 --- a/components/esp_hw_support/dma/gdma.c +++ b/components/esp_hw_support/dma/gdma.c @@ -48,6 +48,13 @@ static const char *TAG = "gdma"; +#if !SOC_RCC_IS_INDEPENDENT +// Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section +#define GDMA_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define GDMA_RCC_ATOMIC() +#endif + #define GDMA_INVALID_PERIPH_TRIG (0x3F) #define SEARCH_REQUEST_RX_CHANNEL (1 << 0) #define SEARCH_REQUEST_TX_CHANNEL (1 << 1) @@ -615,7 +622,9 @@ static void gdma_release_group_handle(gdma_group_t *group) if (do_deinitialize) { gdma_hal_deinit(&group->hal); - periph_module_disable(gdma_periph_signals.groups[group_id].module); + GDMA_RCC_ATOMIC() { + gdma_ll_enable_bus_clock(group_id, false); + } free(group); ESP_LOGD(TAG, "del group %d", group_id); } @@ -646,7 +655,10 @@ static gdma_group_t *gdma_acquire_group_handle(int group_id, void (*hal_init)(gd group->group_id = group_id; group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; // enable APB to access GDMA registers - periph_module_enable(gdma_periph_signals.groups[group_id].module); + GDMA_RCC_ATOMIC() { + gdma_ll_enable_bus_clock(group_id, true); + gdma_ll_reset_register(group_id); + } gdma_hal_config_t config = { .group_id = group_id, }; diff --git a/components/hal/esp32c2/include/hal/gdma_ll.h b/components/hal/esp32c2/include/hal/gdma_ll.h index f9e474cdab..7747ca3378 100644 --- a/components/hal/esp32c2/include/hal/gdma_ll.h +++ b/components/hal/esp32c2/include/hal/gdma_ll.h @@ -11,6 +11,7 @@ #include "hal/gdma_types.h" #include "soc/gdma_struct.h" #include "soc/gdma_reg.h" +#include "soc/system_struct.h" #ifdef __cplusplus extern "C" { @@ -47,6 +48,34 @@ extern "C" { #define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number ///////////////////////////////////// Common ///////////////////////////////////////// + +/** + * @brief Enable the bus clock for the DMA module + */ +static inline void gdma_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + SYSTEM.perip_clk_en1.dma_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define gdma_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the DMA module + */ +static inline void gdma_ll_reset_register(int group_id) +{ + (void)group_id; + SYSTEM.perip_rst_en1.dma_rst = 1; + SYSTEM.perip_rst_en1.dma_rst = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_reset_register(__VA_ARGS__) + /** * @brief Force enable register clock */ diff --git a/components/hal/esp32c3/include/hal/gdma_ll.h b/components/hal/esp32c3/include/hal/gdma_ll.h index 4c15879756..d3deb43181 100644 --- a/components/hal/esp32c3/include/hal/gdma_ll.h +++ b/components/hal/esp32c3/include/hal/gdma_ll.h @@ -11,6 +11,7 @@ #include "hal/gdma_types.h" #include "soc/gdma_struct.h" #include "soc/gdma_reg.h" +#include "soc/system_struct.h" #ifdef __cplusplus extern "C" { @@ -47,6 +48,34 @@ extern "C" { #define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number ///////////////////////////////////// Common ///////////////////////////////////////// + +/** + * @brief Enable the bus clock for the DMA module + */ +static inline void gdma_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + SYSTEM.perip_clk_en1.reg_dma_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define gdma_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the DMA module + */ +static inline void gdma_ll_reset_register(int group_id) +{ + (void)group_id; + SYSTEM.perip_rst_en1.reg_dma_rst = 1; + SYSTEM.perip_rst_en1.reg_dma_rst = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_reset_register(__VA_ARGS__) + /** * @brief Force enable register clock */ diff --git a/components/hal/esp32c6/include/hal/gdma_ll.h b/components/hal/esp32c6/include/hal/gdma_ll.h index 15ebf4a08f..bdccf27035 100644 --- a/components/hal/esp32c6/include/hal/gdma_ll.h +++ b/components/hal/esp32c6/include/hal/gdma_ll.h @@ -12,6 +12,7 @@ #include "soc/gdma_struct.h" #include "soc/gdma_reg.h" #include "soc/soc_etm_source.h" +#include "soc/pcr_struct.h" #ifdef __cplusplus extern "C" { @@ -91,6 +92,26 @@ extern "C" { }}}[group][chan][task] ///////////////////////////////////// Common ///////////////////////////////////////// + +/** + * @brief Enable the bus clock for the DMA module + */ +static inline void gdma_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + PCR.gdma_conf.gdma_clk_en = enable; +} + +/** + * @brief Reset the DMA module + */ +static inline void gdma_ll_reset_register(int group_id) +{ + (void)group_id; + PCR.gdma_conf.gdma_rst_en = 1; + PCR.gdma_conf.gdma_rst_en = 0; +} + /** * @brief Force enable register clock */ diff --git a/components/hal/esp32h2/include/hal/gdma_ll.h b/components/hal/esp32h2/include/hal/gdma_ll.h index 15ebf4a08f..bdccf27035 100644 --- a/components/hal/esp32h2/include/hal/gdma_ll.h +++ b/components/hal/esp32h2/include/hal/gdma_ll.h @@ -12,6 +12,7 @@ #include "soc/gdma_struct.h" #include "soc/gdma_reg.h" #include "soc/soc_etm_source.h" +#include "soc/pcr_struct.h" #ifdef __cplusplus extern "C" { @@ -91,6 +92,26 @@ extern "C" { }}}[group][chan][task] ///////////////////////////////////// Common ///////////////////////////////////////// + +/** + * @brief Enable the bus clock for the DMA module + */ +static inline void gdma_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + PCR.gdma_conf.gdma_clk_en = enable; +} + +/** + * @brief Reset the DMA module + */ +static inline void gdma_ll_reset_register(int group_id) +{ + (void)group_id; + PCR.gdma_conf.gdma_rst_en = 1; + PCR.gdma_conf.gdma_rst_en = 0; +} + /** * @brief Force enable register clock */ diff --git a/components/hal/esp32p4/include/hal/clk_gate_ll.h b/components/hal/esp32p4/include/hal/clk_gate_ll.h index 2de987c382..1003eb81a8 100644 --- a/components/hal/esp32p4/include/hal/clk_gate_ll.h +++ b/components/hal/esp32p4/include/hal/clk_gate_ll.h @@ -60,10 +60,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph) return HP_SYS_CLKRST_REG_TWAI1_CLK_EN; case PERIPH_TWAI2_MODULE: return HP_SYS_CLKRST_REG_TWAI2_CLK_EN; - case PERIPH_AHB_PDMA_MODULE: - return HP_SYS_CLKRST_REG_AHB_PDMA_SYS_CLK_EN; - case PERIPH_AXI_PDMA_MODULE: - return HP_SYS_CLKRST_REG_AXI_PDMA_SYS_CLK_EN; case PERIPH_GPSPI_MODULE: return HP_SYS_CLKRST_REG_GPSPI2_HS_CLK_EN; case PERIPH_GPSPI2_MODULE: @@ -120,8 +116,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en switch (periph) { case PERIPH_PVT_MODULE: return HP_SYS_CLKRST_REG_RST_EN_PVT_TOP; - case PERIPH_GDMA_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_GDMA; case PERIPH_MSPI_FLASH_MODULE: return HP_SYS_CLKRST_REG_RST_EN_MSPI_AXI; case PERIPH_MSPI_PSRAM_MODULE: @@ -138,10 +132,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en return HP_SYS_CLKRST_REG_RST_EN_DMA2D; case PERIPH_PPA_MODULE: return HP_SYS_CLKRST_REG_RST_EN_PPA; - case PERIPH_AHB_PDMA_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_AHB_PDMA; - case PERIPH_AXI_PDMA_MODULE: - return HP_SYS_CLKRST_REG_RST_EN_AXI_PDMA; case PERIPH_SYSTIMER_MODULE: return HP_SYS_CLKRST_REG_RST_EN_STIMER; case PERIPH_UART0_MODULE: @@ -222,9 +212,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en static inline uint32_t periph_ll_get_clk_en_reg(periph_module_t periph) { switch (periph) { - case PERIPH_AHB_PDMA_MODULE: - case PERIPH_AXI_PDMA_MODULE: - return HP_SYS_CLKRST_SOC_CLK_CTRL1_REG; case PERIPH_MSPI_FLASH_MODULE: case PERIPH_MSPI_PSRAM_MODULE: return HP_SYS_CLKRST_PERI_CLK_CTRL00_REG; @@ -290,7 +277,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) { switch (periph) { case PERIPH_PVT_MODULE: - case PERIPH_GDMA_MODULE: case PERIPH_MSPI_FLASH_MODULE: case PERIPH_MSPI_PSRAM_MODULE: case PERIPH_ISP_MODULE: @@ -298,8 +284,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph) case PERIPH_DMA2D_MODULE: return HP_SYS_CLKRST_HP_RST_EN0_REG; case PERIPH_PPA_MODULE: - case PERIPH_AHB_PDMA_MODULE: - case PERIPH_AXI_PDMA_MODULE: case PERIPH_SYSTIMER_MODULE: case PERIPH_UART0_MODULE: case PERIPH_UART1_MODULE: diff --git a/components/hal/esp32p4/include/hal/gdma_ll.h b/components/hal/esp32p4/include/hal/gdma_ll.h index f29f33feb1..f282a23a7d 100644 --- a/components/hal/esp32p4/include/hal/gdma_ll.h +++ b/components/hal/esp32p4/include/hal/gdma_ll.h @@ -11,10 +11,8 @@ #pragma once #include - -#ifdef __cplusplus -extern "C" { -#endif +#include +#include "soc/hp_sys_clkrst_struct.h" #define GDMA_LL_CHANNEL_MAX_PRIORITY 5 // supported priority levels: [0,5] @@ -46,6 +44,44 @@ extern "C" { #define GDMA_LL_AHB_MAX_CRC_BIT_WIDTH 32 // Max CRC bit width supported by AHB GDMA #define GDMA_LL_AXI_MAX_CRC_BIT_WIDTH 16 // Max CRC bit width supported by AXI GDMA +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Enable the bus clock for the DMA module + */ +static inline void gdma_ll_enable_bus_clock(int group_id, bool enable) +{ + if (group_id == 0) { + HP_SYS_CLKRST.soc_clk_ctrl1.reg_ahb_pdma_sys_clk_en = enable; + } else { + HP_SYS_CLKRST.soc_clk_ctrl1.reg_axi_pdma_sys_clk_en = enable; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define gdma_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the DMA module + */ +static inline void gdma_ll_reset_register(int group_id) +{ + if (group_id == 0) { + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_ahb_pdma = 1; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_ahb_pdma = 0; + } else { + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_axi_pdma = 1; + HP_SYS_CLKRST.hp_rst_en1.reg_rst_en_axi_pdma = 0; + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_reset_register(__VA_ARGS__) + __attribute__((always_inline)) static inline uint8_t _bitwise_reverse(uint8_t n) { diff --git a/components/hal/esp32s3/include/hal/gdma_ll.h b/components/hal/esp32s3/include/hal/gdma_ll.h index 53bebb0fde..ff923dd82f 100644 --- a/components/hal/esp32s3/include/hal/gdma_ll.h +++ b/components/hal/esp32s3/include/hal/gdma_ll.h @@ -12,6 +12,7 @@ #include "hal/gdma_types.h" #include "soc/gdma_struct.h" #include "soc/gdma_reg.h" +#include "soc/system_struct.h" #ifdef __cplusplus extern "C" { @@ -60,6 +61,34 @@ extern "C" { #define GDMA_LL_AHB_PAIRS_PER_GROUP 5 // Number of GDMA pairs in each AHB group ///////////////////////////////////// Common ///////////////////////////////////////// + +/** + * @brief Enable the bus clock for the DMA module + */ +static inline void gdma_ll_enable_bus_clock(int group_id, bool enable) +{ + (void)group_id; + SYSTEM.perip_clk_en1.dma_clk_en = enable; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define gdma_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the DMA module + */ +static inline void gdma_ll_reset_register(int group_id) +{ + (void)group_id; + SYSTEM.perip_rst_en1.dma_rst = 1; + SYSTEM.perip_rst_en1.dma_rst = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define gdma_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; gdma_ll_reset_register(__VA_ARGS__) + /** * @brief Force enable register clock */