From f503b44805e7239be608cb97ebb20ca05ec36ff0 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 20 Oct 2025 17:39:17 +0800 Subject: [PATCH] fix(ppa): fix potential SRM operation stuck on DMA issue Apply a workaound to bypass macro block order function in PPA SRM when specific conditions are met to avoid SRM operation getting stuck --- components/esp_driver_ppa/src/ppa_srm.c | 22 +++++ .../esp_driver_ppa/test_apps/main/test_ppa.c | 84 +++++++++++++++++++ components/hal/esp32p4/include/hal/ppa_ll.h | 11 +++ 3 files changed, 117 insertions(+) diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c index 582021b0ac..25a3269329 100644 --- a/components/esp_driver_ppa/src/ppa_srm.c +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -156,6 +156,28 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel ppa_ll_srm_enable_mirror_x(platform->hal.dev, srm_trans_desc->mirror_x); ppa_ll_srm_enable_mirror_y(platform->hal.dev, srm_trans_desc->mirror_y); + // Hardware bug workaround (DIG-734) + uint32_t w_out = srm_trans_desc->in.block_w * srm_trans_desc->scale_x_int + srm_trans_desc->in.block_w * srm_trans_desc->scale_x_frag / PPA_LL_SRM_SCALING_FRAG_MAX; + uint32_t w_divisor = (ppa_out_color_mode == PPA_SRM_COLOR_MODE_ARGB8888 || ppa_out_color_mode == PPA_SRM_COLOR_MODE_RGB888) ? 32 : 64; + uint32_t w_left = w_out % w_divisor; + w_left = (w_left == 0) ? w_divisor : w_left; + uint32_t h_mb = (ppa_ll_srm_get_mb_size(platform->hal.dev) == PPA_LL_SRM_MB_SIZE_16_16) ? 16 : 32; + uint32_t h_in_left = srm_trans_desc->in.block_h % h_mb; + h_in_left = (h_in_left == 0) ? h_mb : h_in_left; + uint32_t h_left = h_in_left * srm_trans_desc->scale_y_int + h_in_left * srm_trans_desc->scale_y_frag / PPA_LL_SRM_SCALING_FRAG_MAX; + const uint32_t dma2d_fifo_depth_bits = 12 * 128; + color_space_pixel_format_t out_pixel_format = { + .color_type_id = ppa_out_color_mode, + }; + uint32_t out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format); + bool bypass_mb_order = false; + if (((w_out > w_divisor) || (srm_trans_desc->in.block_h > h_mb)) && // will be cut into more than one trans unit + ((w_left * h_left * out_pixel_depth) < dma2d_fifo_depth_bits) + ) { + bypass_mb_order = true; + } + ppa_ll_srm_bypass_mb_order(platform->hal.dev, bypass_mb_order); + ppa_ll_srm_start(platform->hal.dev); // No need to yield diff --git a/components/esp_driver_ppa/test_apps/main/test_ppa.c b/components/esp_driver_ppa/test_apps/main/test_ppa.c index 011add8c2e..8684e6ee15 100644 --- a/components/esp_driver_ppa/test_apps/main/test_ppa.c +++ b/components/esp_driver_ppa/test_apps/main/test_ppa.c @@ -18,6 +18,7 @@ #include "hal/color_hal.h" #include "esp_cache.h" #include "ppa_performance.h" +#include "esp_random.h" #define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) @@ -837,3 +838,86 @@ TEST_CASE("ppa_fill_performance", "[PPA]") free(out_buf); } + +TEST_CASE("ppa_srm_stress_test", "[PPA]") +{ + // Configurable parameters + const uint32_t w = 200; + const uint32_t h = 200; + const ppa_srm_color_mode_t in_cm = PPA_SRM_COLOR_MODE_RGB565; + const ppa_srm_color_mode_t out_cm = PPA_SRM_COLOR_MODE_RGB565; + const ppa_srm_rotation_angle_t rotation = PPA_SRM_ROTATION_ANGLE_0; + const float scale_x = 1.0; + const float scale_y = 1.0; + + color_space_pixel_format_t in_pixel_format = { + .color_type_id = in_cm, + }; + color_space_pixel_format_t out_pixel_format = { + .color_type_id = out_cm, + }; + + uint32_t in_buf_size = w * h * color_hal_pixel_format_get_bit_depth(in_pixel_format) / 8; + uint32_t out_buf_size = ALIGN_UP(w * h * color_hal_pixel_format_get_bit_depth(out_pixel_format) / 8, 64); + uint8_t *out_buf = heap_caps_aligned_calloc(4, out_buf_size, sizeof(uint8_t), MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(out_buf); + uint8_t *in_buf = heap_caps_aligned_calloc(4, in_buf_size, sizeof(uint8_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT | MALLOC_CAP_DMA); + TEST_ASSERT_NOT_NULL(in_buf); + + ppa_client_handle_t ppa_client_handle; + ppa_client_config_t ppa_client_config = { + .oper_type = PPA_OPERATION_SRM, + .max_pending_trans_num = 1, + }; + TEST_ESP_OK(ppa_register_client(&ppa_client_config, &ppa_client_handle)); + + // Test on different sizes of the block + int test_iterations = 50; + while (test_iterations-- > 0) { + uint32_t block_w_initial = esp_random() % (w - 100); + uint32_t block_h_initial = esp_random() % (h - 100); + block_w_initial = (block_w_initial == 0) ? 1 : block_w_initial; + block_h_initial = (block_h_initial == 0) ? 1 : block_h_initial; + uint32_t block_w = 0; + uint32_t block_h = 0; + for (int i = 0; i < 100; i++) { + block_w = block_w_initial + i; + block_h = block_h_initial + i; + // printf("block_w = %ld, block_h = %ld\n", block_w, block_h); + ppa_srm_oper_config_t oper_config = { + .in.buffer = in_buf, + .in.pic_w = w, + .in.pic_h = h, + .in.block_w = block_w, + .in.block_h = block_h, + .in.block_offset_x = 0, + .in.block_offset_y = 0, + .in.srm_cm = in_cm, + + .out.buffer = out_buf, + .out.buffer_size = out_buf_size, + .out.pic_w = block_w, + .out.pic_h = block_h, + .out.block_offset_x = 0, + .out.block_offset_y = 0, + .out.srm_cm = out_cm, + + .rotation_angle = rotation, + .scale_x = scale_x, + .scale_y = scale_y, + + .rgb_swap = 0, + .byte_swap = 0, + + .mode = PPA_TRANS_MODE_BLOCKING, + }; + + TEST_ESP_OK(ppa_do_scale_rotate_mirror(ppa_client_handle, &oper_config)); + } + } + + TEST_ESP_OK(ppa_unregister_client(ppa_client_handle)); + + free(in_buf); + free(out_buf); +} diff --git a/components/hal/esp32p4/include/hal/ppa_ll.h b/components/hal/esp32p4/include/hal/ppa_ll.h index 60159b65c7..cf4e5786d5 100644 --- a/components/hal/esp32p4/include/hal/ppa_ll.h +++ b/components/hal/esp32p4/include/hal/ppa_ll.h @@ -600,6 +600,17 @@ static inline void ppa_ll_srm_get_dma_dscr_port_mode_block_size(ppa_dev_t *dev, } } +/** + * @brief Whether to bypass the macro block order function in PPA SRM + * + * @param dev Peripheral instance address + * @param enable True to bypass; False to not bypass + */ +static inline void ppa_ll_srm_bypass_mb_order(ppa_dev_t *dev, bool enable) +{ + dev->sr_byte_order.sr_macro_bk_ro_bypass = enable; +} + //////////////////////////////////// Blending //////////////////////////////////////// /* * Alpha Blending Calculation: