From 6441c76ef48e266a1ef7ec14f3643f70c9879ac5 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Fri, 3 Apr 2026 22:01:56 +0800 Subject: [PATCH] feat(ppa): add support for ESP32S31 --- components/esp_driver_ppa/src/ppa_blend.c | 46 +- components/esp_driver_ppa/src/ppa_core.c | 13 +- components/esp_driver_ppa/src/ppa_fill.c | 12 +- components/esp_driver_ppa/src/ppa_priv.h | 3 +- components/esp_driver_ppa/src/ppa_srm.c | 28 +- components/esp_driver_ppa/test_apps/README.md | 4 +- .../test_apps/main/ppa_performance.h | 14 +- .../esp_driver_ppa/test_apps/pytest_ppa.py | 1 + .../test_apps/sdkconfig.defaults.esp32s31 | 3 + .../esp_hal_ppa/esp32p4/include/hal/ppa_ll.h | 49 +- .../esp_hal_ppa/esp32s31/include/hal/ppa_ll.h | 1295 +++++++++++++++++ components/esp_hal_ppa/ppa_hal.c | 3 + .../esp32s31/include/soc/Kconfig.soc_caps.in | 4 + .../soc/esp32s31/include/soc/soc_caps.h | 2 +- .../soc/esp32s31/register/soc/ppa_reg.h | 42 +- .../soc/esp32s31/register/soc/ppa_struct.h | 21 +- docs/doxygen/Doxyfile_esp32s31 | 2 + docs/en/api-reference/peripherals/ppa.rst | 2 +- docs/zh_CN/api-reference/peripherals/ppa.rst | 2 +- 19 files changed, 1467 insertions(+), 79 deletions(-) create mode 100644 components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32s31 create mode 100644 components/esp_hal_ppa/esp32s31/include/hal/ppa_ll.h diff --git a/components/esp_driver_ppa/src/ppa_blend.c b/components/esp_driver_ppa/src/ppa_blend.c index e3cd6816c04..f80252f60c9 100644 --- a/components/esp_driver_ppa/src/ppa_blend.c +++ b/components/esp_driver_ppa/src/ppa_blend.c @@ -260,26 +260,34 @@ esp_err_t ppa_do_blend(ppa_client_handle_t ppa_client, const ppa_blend_oper_conf // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) // Write back in_bg_buffer, in_fg_buffer extended windows (alignment not necessary on C2M direction) - uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; - uint32_t in_bg_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in_bg.blend_cm); // bits - // Usually C2M can let the msync do alignment internally, however, it only do L1-cacheline-size alignment for L1->L2, and then L2-cacheline-size alignment for L2->mem - // While M2C direction manual alignment is L2-cacheline-size alignment for mem->L2->L1 - // Mismatching writeback and invalidate data size could cause synchronization error if in_bg/fg_buffer and out_buffer are the same one - uint32_t in_bg_ext_window = (uint32_t)config->in_bg.buffer + config->in_bg.block_offset_y * config->in_bg.pic_w * in_bg_pixel_depth / 8; - uint32_t in_bg_ext_window_aligned = PPA_ALIGN_DOWN(in_bg_ext_window, buf_alignment_size); - uint32_t in_bg_ext_window_len = config->in_bg.pic_w * config->in_bg.block_h * in_bg_pixel_depth / 8; - esp_cache_msync((void *)in_bg_ext_window_aligned, PPA_ALIGN_UP(in_bg_ext_window_len + (in_bg_ext_window - in_bg_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_C2M); - uint32_t in_fg_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in_fg.blend_cm); // bits - uint32_t in_fg_ext_window = (uint32_t)config->in_fg.buffer + config->in_fg.block_offset_y * config->in_fg.pic_w * in_fg_pixel_depth / 8; - // Same for fg_buffer msync, do manual alignment - uint32_t in_fg_ext_window_aligned = PPA_ALIGN_DOWN(in_fg_ext_window, buf_alignment_size); - uint32_t in_fg_ext_window_len = config->in_fg.pic_w * config->in_fg.block_h * in_fg_pixel_depth / 8; - esp_cache_msync((void *)in_fg_ext_window_aligned, PPA_ALIGN_UP(in_fg_ext_window_len + (in_fg_ext_window - in_fg_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_C2M); + size_t in_bg_buf_alignment = esp_ptr_external_ram(config->in_bg.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (in_bg_buf_alignment > 0) { + uint32_t in_bg_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in_bg.blend_cm); // bits + // Usually C2M can let the msync do alignment internally, however, it only do L1-cacheline-size alignment for L1->L2, and then L2-cacheline-size alignment for L2->mem + // While M2C direction manual alignment is L2-cacheline-size alignment for mem->L2->L1 + // Mismatching writeback and invalidate data size could cause synchronization error if in_bg/fg_buffer and out_buffer are the same one + uint32_t in_bg_ext_window = (uint32_t)config->in_bg.buffer + config->in_bg.block_offset_y * config->in_bg.pic_w * in_bg_pixel_depth / 8; + uint32_t in_bg_ext_window_aligned = PPA_ALIGN_DOWN(in_bg_ext_window, in_bg_buf_alignment); + uint32_t in_bg_ext_window_len = config->in_bg.pic_w * config->in_bg.block_h * in_bg_pixel_depth / 8; + esp_cache_msync((void *)in_bg_ext_window_aligned, PPA_ALIGN_UP(in_bg_ext_window_len + (in_bg_ext_window - in_bg_ext_window_aligned), in_bg_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_C2M); + } + size_t in_fg_buf_alignment = esp_ptr_external_ram(config->in_fg.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (in_fg_buf_alignment > 0) { + uint32_t in_fg_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in_fg.blend_cm); // bits + uint32_t in_fg_ext_window = (uint32_t)config->in_fg.buffer + config->in_fg.block_offset_y * config->in_fg.pic_w * in_fg_pixel_depth / 8; + // Same for fg_buffer msync, do manual alignment + uint32_t in_fg_ext_window_aligned = PPA_ALIGN_DOWN(in_fg_ext_window, in_fg_buf_alignment); + uint32_t in_fg_ext_window_len = config->in_fg.pic_w * config->in_fg.block_h * in_fg_pixel_depth / 8; + esp_cache_msync((void *)in_fg_ext_window_aligned, PPA_ALIGN_UP(in_fg_ext_window_len + (in_fg_ext_window - in_fg_ext_window_aligned), in_fg_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_C2M); + } // Invalidate out_buffer extended window (alignment strict on M2C direction) - uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; - uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size); - uint32_t out_ext_window_len = config->out.pic_w * config->in_bg.block_h * out_pixel_depth / 8; - esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C); + size_t out_buf_alignment = esp_ptr_external_ram(config->out.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (out_buf_alignment > 0) { + uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; + uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, out_buf_alignment); + uint32_t out_ext_window_len = config->out.pic_w * config->in_bg.block_h * out_pixel_depth / 8; + esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), out_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_M2C); + } esp_err_t ret = ESP_OK; ppa_trans_t *trans_elm = NULL; diff --git a/components/esp_driver_ppa/src/ppa_core.c b/components/esp_driver_ppa/src/ppa_core.c index d0047524b04..49289c22dc3 100644 --- a/components/esp_driver_ppa/src/ppa_core.c +++ b/components/esp_driver_ppa/src/ppa_core.c @@ -67,11 +67,11 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin size_t alignment = MAX(DMA2D_LL_DESC_ALIGNMENT, data_cache_line_size); _lock_acquire(&s_platform.mutex); - if (s_platform.dma_desc_mem_size == 0) { + if (s_platform.srm_engine_ref_count + s_platform.blend_engine_ref_count == 0) { + // Initialize the platform level alignment requirements s_platform.dma_desc_mem_size = PPA_ALIGN_UP(sizeof(dma2d_descriptor_align8_t), alignment); - } - if (s_platform.buf_alignment_size == 0) { - esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &s_platform.buf_alignment_size); + esp_cache_get_alignment(MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA, &s_platform.int_mem_align); + esp_cache_get_alignment(MALLOC_CAP_SPIRAM | MALLOC_CAP_DMA, &s_platform.ext_mem_align); } if (config->engine == PPA_ENGINE_TYPE_SRM) { @@ -540,10 +540,11 @@ esp_err_t ppa_set_rgb2gray_formula(uint8_t r_weight, uint8_t g_weight, uint8_t b bool ppa_check_buffer_alignment(ppa_client_handle_t ppa_client, const void *pic_blk_config, bool is_input, uint32_t block_width) { // 1. check with cache line size alignment (output buffer only) - uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; if (!is_input) { ppa_out_pic_blk_config_t *out_pic_blk_config = (ppa_out_pic_blk_config_t *)pic_blk_config; - if (((uint32_t)out_pic_blk_config->buffer & (buf_alignment_size - 1)) != 0 || (out_pic_blk_config->buffer_size & (buf_alignment_size - 1)) != 0) { + size_t alignment = esp_ptr_external_ram(out_pic_blk_config->buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + // if cache line size alignment is 0, means no msync is needed, so no check is needed + if (alignment > 0 && (((uint32_t)out_pic_blk_config->buffer & (alignment - 1)) != 0 || (out_pic_blk_config->buffer_size & (alignment - 1)) != 0)) { ESP_LOGE(TAG, "out.buffer addr or out.buffer_size not aligned to cache line size"); return false; } diff --git a/components/esp_driver_ppa/src/ppa_fill.c b/components/esp_driver_ppa/src/ppa_fill.c index 70fe4278d91..12682780bc9 100644 --- a/components/esp_driver_ppa/src/ppa_fill.c +++ b/components/esp_driver_ppa/src/ppa_fill.c @@ -116,11 +116,13 @@ esp_err_t ppa_do_fill(ppa_client_handle_t ppa_client, const ppa_fill_oper_config // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) // Write back and invalidate buffer extended window (alignment not necessary on C2M direction, but alignment strict on M2C direction) - uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; - uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; - uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size); - uint32_t out_ext_window_len = config->out.pic_w * config->fill_block_h * out_pixel_depth / 8; - esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); + size_t out_buf_alignment = esp_ptr_external_ram(config->out.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (out_buf_alignment > 0) { + uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; + uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, out_buf_alignment); + uint32_t out_ext_window_len = config->out.pic_w * config->fill_block_h * out_pixel_depth / 8; + esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), out_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); + } esp_err_t ret = ESP_OK; ppa_trans_t *trans_elm = NULL; diff --git a/components/esp_driver_ppa/src/ppa_priv.h b/components/esp_driver_ppa/src/ppa_priv.h index 4f629f4bb85..d6ff470c8af 100644 --- a/components/esp_driver_ppa/src/ppa_priv.h +++ b/components/esp_driver_ppa/src/ppa_priv.h @@ -244,7 +244,8 @@ struct ppa_platform_t { ppa_blend_engine_t *blending; // Pointer to the PPA blending engine uint32_t srm_engine_ref_count; // Reference count used to protect PPA SRM engine acquire and release uint32_t blend_engine_ref_count; // Reference count used to protect PPA blending engine acquire and release - size_t buf_alignment_size; // Alignment requirement for the outgoing buffer addr and size to satisfy cache line size + size_t int_mem_align; // Alignment requirement for the internal outgoing buffer to satisfy cache line size + size_t ext_mem_align; // Alignment requirement for the external outgoing buffer to satisfy cache line size uint32_t dma_desc_mem_size; // Alignment requirement for the 2D-DMA descriptor to satisfy cache line size }; diff --git a/components/esp_driver_ppa/src/ppa_srm.c b/components/esp_driver_ppa/src/ppa_srm.c index 88b7d6cfeed..cbd7e109f78 100644 --- a/components/esp_driver_ppa/src/ppa_srm.c +++ b/components/esp_driver_ppa/src/ppa_srm.c @@ -12,6 +12,7 @@ #include "esp_cache.h" #include "esp_memory_utils.h" #include "soc/dma2d_channel.h" +#include "sdkconfig.h" static const char *TAG = "ppa_srm"; @@ -153,6 +154,7 @@ 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); +#if CONFIG_IDF_TARGET_ESP32P4 // 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; @@ -171,6 +173,7 @@ bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel bypass_mb_order = true; } ppa_ll_srm_bypass_mb_order(platform->hal.dev, bypass_mb_order); +#endif ppa_ll_srm_start(platform->hal.dev); @@ -256,17 +259,22 @@ esp_err_t ppa_do_scale_rotate_mirror(ppa_client_handle_t ppa_client, const ppa_s // Write back and invalidate necessary data (note that the window content is not continuous in the buffer) // Write back in_buffer extended window (alignment not necessary on C2M direction) - uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size; - uint32_t in_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in.srm_cm); // bits - uint32_t in_ext_window = (uint32_t)config->in.buffer + config->in.block_offset_y * config->in.pic_w * in_pixel_depth / 8; - uint32_t in_ext_window_len = config->in.pic_w * config->in.block_h * in_pixel_depth / 8; - esp_cache_msync((void *)in_ext_window, in_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); + size_t in_buf_alignment = esp_ptr_external_ram(config->in.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (in_buf_alignment > 0) { + uint32_t in_pixel_depth = color_hal_pixel_format_fourcc_get_bit_depth((esp_color_fourcc_t)config->in.srm_cm); // bits + uint32_t in_ext_window = (uint32_t)config->in.buffer + config->in.block_offset_y * config->in.pic_w * in_pixel_depth / 8; + uint32_t in_ext_window_len = config->in.pic_w * config->in.block_h * in_pixel_depth / 8; + esp_cache_msync((void *)in_ext_window, in_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED); + } // Invalidate out_buffer extended window (alignment strict on M2C direction) - uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; - uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size); - uint32_t out_ext_window_len = config->out.pic_w * new_block_h * out_pixel_depth / 8; // actual ext_window_len must be less than or equal to this, since actual block_h <= new_block_h (may round down) - assert(out_ext_window + out_ext_window_len <= (uint32_t)config->out.buffer + config->out.buffer_size); - esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_M2C); + size_t out_buf_alignment = esp_ptr_external_ram(config->out.buffer) ? ppa_client->engine->platform->ext_mem_align : ppa_client->engine->platform->int_mem_align; + if (out_buf_alignment > 0) { + uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8; + uint32_t out_ext_window_aligned = PPA_ALIGN_DOWN(out_ext_window, out_buf_alignment); + uint32_t out_ext_window_len = config->out.pic_w * new_block_h * out_pixel_depth / 8; // actual ext_window_len must be less than or equal to this, since actual block_h <= new_block_h (may round down) + assert(out_ext_window + out_ext_window_len <= (uint32_t)config->out.buffer + config->out.buffer_size); + esp_cache_msync((void *)out_ext_window_aligned, PPA_ALIGN_UP(out_ext_window_len + (out_ext_window - out_ext_window_aligned), out_buf_alignment), ESP_CACHE_MSYNC_FLAG_DIR_M2C); + } esp_err_t ret = ESP_OK; ppa_trans_t *trans_elm = NULL; diff --git a/components/esp_driver_ppa/test_apps/README.md b/components/esp_driver_ppa/test_apps/README.md index 909282018f2..6980aa681b4 100644 --- a/components/esp_driver_ppa/test_apps/README.md +++ b/components/esp_driver_ppa/test_apps/README.md @@ -1,2 +1,2 @@ -| Supported Targets | ESP32-P4 | -| ----------------- | -------- | +| Supported Targets | ESP32-P4 | ESP32-S31 | +| ----------------- | -------- | --------- | diff --git a/components/esp_driver_ppa/test_apps/main/ppa_performance.h b/components/esp_driver_ppa/test_apps/main/ppa_performance.h index edab08fc14b..0dc047aed1d 100644 --- a/components/esp_driver_ppa/test_apps/main/ppa_performance.h +++ b/components/esp_driver_ppa/test_apps/main/ppa_performance.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -15,6 +15,7 @@ */ #if CONFIG_IDF_TARGET_ESP32P4 + #if CONFIG_ESP32P4_SELECTS_REV_LESS_V3 #define PPA_SRM_MIN_PERFORMANCE_PX_PER_SEC (21000 * 1000) // k_min #define PPA_SRM_TIME_OFFSET (-26000) // b_approx @@ -28,4 +29,15 @@ #define PPA_FILL_MIN_PERFORMANCE_PX_PER_SEC (150000 * 1000) // k_min #define PPA_FILL_TIME_OFFSET (-106000) // b_approx + +#elif CONFIG_IDF_TARGET_ESP32S31 + +#define PPA_SRM_MIN_PERFORMANCE_PX_PER_SEC (25900 * 1000) // k_min +#define PPA_SRM_TIME_OFFSET (-64000) // b_approx + +#define PPA_BLEND_MIN_PERFORMANCE_PX_PER_SEC (22000 * 1000) // k_min +#define PPA_BLEND_TIME_OFFSET (-57000) // b_approx + +#define PPA_FILL_MIN_PERFORMANCE_PX_PER_SEC (79800 * 1000) // k_min +#define PPA_FILL_TIME_OFFSET (-137000) // b_approx #endif diff --git a/components/esp_driver_ppa/test_apps/pytest_ppa.py b/components/esp_driver_ppa/test_apps/pytest_ppa.py index 688a0fcccd6..797e50d36d9 100644 --- a/components/esp_driver_ppa/test_apps/pytest_ppa.py +++ b/components/esp_driver_ppa/test_apps/pytest_ppa.py @@ -42,5 +42,6 @@ def test_ppa_esp32p4_rev1(dut: Dut) -> None: indirect=True, ) @idf_parametrize('target', soc_filtered_targets('SOC_PPA_SUPPORTED == 1'), indirect=['target']) +@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='TODO: IDFCI-10377 no runner yet') def test_ppa_flash_encryption(dut: Dut) -> None: dut.run_all_single_board_cases() diff --git a/components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32s31 b/components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32s31 new file mode 100644 index 00000000000..a773458c533 --- /dev/null +++ b/components/esp_driver_ppa/test_apps/sdkconfig.defaults.esp32s31 @@ -0,0 +1,3 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_SPEED_200M=y diff --git a/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h b/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h index c45e66806ed..b20fc4c909c 100644 --- a/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h +++ b/components/esp_hal_ppa/esp32p4/include/hal/ppa_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,6 +28,10 @@ extern "C" { #endif +typedef enum { + PPA_LL_MEM_LP_MODE_SHUT_DOWN, // memory will be powered down during low power stage +} ppa_ll_mem_lp_mode_t; + /** * @brief Enumeration of PPA SRM macro block size options */ @@ -81,6 +85,48 @@ static inline void ppa_ll_reset_register(void) ppa_ll_reset_register(__VA_ARGS__); \ } while(0) +/** + * @brief Force power on the PPA memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_force_power_on(ppa_dev_t *dev) +{ + (void)dev; +} + +/** + * @brief Force the PPA memory block into low power mode, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_force_low_power(ppa_dev_t *dev) +{ + (void)dev; +} + +/** + * @brief Power control the PPA memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_power_by_pmu(ppa_dev_t *dev) +{ + (void)dev; +} + +/** + * @brief Set low power mode for PPA memory block + * + * @param dev Peripheral instance address + * @param mode PPA memory low power mode in low power stage + */ +static inline void ppa_ll_mem_set_low_power_mode(ppa_dev_t *dev, ppa_ll_mem_lp_mode_t mode) +{ + (void)dev; + HAL_ASSERT(mode == PPA_LL_MEM_LP_MODE_SHUT_DOWN); +} + /** * @brief Configure the RGB888 to GRAY8 color conversion coefficients for SRM and Blending (excluding Fill) * @@ -1110,6 +1156,7 @@ static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, ppa_fill fill_color_data = ((yuv_data->y) << 24) | ((yuv_data->v) << 16) | ((yuv_data->y) << 8) | (yuv_data->u); break; } + // Non-typical YUV420, U and V components have to be the same value // case PPA_FILL_COLOR_MODE_YUV420: { // color_macroblock_yuv_data_t *yuv_data = (color_macroblock_yuv_data_t *)data; // if (yuv_data->u != yuv_data->v) { diff --git a/components/esp_hal_ppa/esp32s31/include/hal/ppa_ll.h b/components/esp_hal_ppa/esp32s31/include/hal/ppa_ll.h new file mode 100644 index 00000000000..25d6a92132f --- /dev/null +++ b/components/esp_hal_ppa/esp32s31/include/hal/ppa_ll.h @@ -0,0 +1,1295 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "hal/ppa_types.h" +#include "hal/color_types.h" +#include "soc/ppa_struct.h" +#include "soc/ppa_reg.h" +#include "soc/hp_sys_clkrst_struct.h" +#include "soc/hp_system_struct.h" +#include "hal/assert.h" +#include "hal/misc.h" +#include "hal/config.h" + +#define PPA_LL_GET_HW &PPA + +#define PPA_LL_BLEND0_CLUT_MEM_ADDR_OFFSET 0x400 +#define PPA_LL_BLEND1_CLUT_MEM_ADDR_OFFSET 0x800 + +#define PPA_LL_SRM_SCALING_INT_MAX (PPA_SRM_SCAL_X_INT_V + 1) +#define PPA_LL_SRM_SCALING_FRAG_MAX (PPA_SRM_SCAL_X_FRAG_V + 1) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + PPA_LL_MEM_LP_MODE_DEEP_SLEEP, // memory will enter deep sleep during low power stage, keep memory data + PPA_LL_MEM_LP_MODE_LIGHT_SLEEP, // memory will enter light sleep during low power stage, keep memory data + PPA_LL_MEM_LP_MODE_SHUT_DOWN, // memory will be powered down during low power stage + PPA_LL_MEM_LP_MODE_DISABLE, // disable the low power stage +} ppa_ll_mem_lp_mode_t; + +/** + * @brief Enumeration of PPA SRM macro block size options + */ +typedef enum { + PPA_LL_SRM_MB_SIZE_16_16, /*!< SRM engine processes with a macro block size of 16 x 16 */ + PPA_LL_SRM_MB_SIZE_32_32, /*!< SRM engine processes with a macro block size of 32 x 32 */ +} ppa_ll_srm_mb_size_t; + +/** + * @brief Enumeration of PPA blending mode + */ +typedef enum { + PPA_LL_BLEND_TRANS_MODE_BLEND, /*!< Blending engine performs blend operation */ + PPA_LL_BLEND_TRANS_MODE_FILL, /*!< Blending engine performs fill operation */ + PPA_LL_BLEND_TRANS_MODE_BYPASS_BLEND, /*!< Blending engine bypasses blender, background will be output directly. Useful for color space conversion (ARGB). */ +} ppa_ll_blend_trans_mode_t; + +///////////////////////////////////// Common ///////////////////////////////////////// +/** + * @brief Enable or disable the PPA peripheral bus clock + * + * @param enable Set true to enable, false to disable + */ +static inline void ppa_ll_enable_bus_clock(bool enable) +{ + HP_SYS_CLKRST.ppa_ctrl0.reg_ppa_sys_clk_en = enable; +} + +/** + * @brief Reset the PPA module + */ +static inline void ppa_ll_reset_register(void) +{ + HP_SYS_CLKRST.ppa_ctrl0.reg_ppa_rst_en = 1; + HP_SYS_CLKRST.ppa_ctrl0.reg_ppa_rst_en = 0; +} + +/** + * @brief Force power on the PPA memory block, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_force_power_on(ppa_dev_t *dev) +{ + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_force_ctrl = 1; + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_lp_en = 0; +} + +/** + * @brief Force the PPA memory block into low power mode, regardless of the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_force_low_power(ppa_dev_t *dev) +{ + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_force_ctrl = 1; + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_lp_en = 1; +} + +/** + * @brief Power control the PPA memory block by the outside PMU logic + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_mem_power_by_pmu(ppa_dev_t *dev) +{ + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_force_ctrl = 0; + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_lp_en = 0; +} + +/** + * @brief Set low power mode for PPA memory block + * + * @param dev Peripheral instance address + * @param mode PPA memory low power mode in low power stage + */ +static inline void ppa_ll_mem_set_low_power_mode(ppa_dev_t *dev, ppa_ll_mem_lp_mode_t mode) +{ + HP_SYSTEM.sys_ppa_mem_lp_ctrl.sys_ppa_sprf_mem_lp_mode = mode; +} + +/** + * @brief Configure the RGB888 to GRAY8 color conversion coefficients for SRM and Blending (excluding Fill) + * + * The gray value is calculated as: gray = (r_coeff * R + g_coeff * G + b_coeff * B) >> 8 + * + * @param dev Peripheral instance address + * @param r_coeff Coefficient for Red channel, range 0-255 + * @param g_coeff Coefficient for Green channel, range 0-255 + * @param b_coeff Coefficient for Blue channel, range 0-255 + */ +static inline void ppa_ll_set_rgb2gray_coeff(ppa_dev_t *dev, uint8_t r_coeff, uint8_t g_coeff, uint8_t b_coeff) +{ + HAL_ASSERT((r_coeff + g_coeff + b_coeff == 256) && "Sum of RGB to GRAY coefficients must be 256"); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rgb2gray, rgb2gray_r, r_coeff); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rgb2gray, rgb2gray_g, g_coeff); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->rgb2gray, rgb2gray_b, b_coeff); +} + +///////////////////////// Scaling, Rotating, Mirroring (SRM) ////////////////////////////// +/** + * @brief Reset PPA scaling-rotating-mirroring engine + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_srm_reset(ppa_dev_t *dev) +{ + dev->srm_scal_rotate.scal_rotate_rst = 1; + dev->srm_scal_rotate.scal_rotate_rst = 0; +} + +/** + * @brief Set PPA scaling coefficient in X direction + * + * @param dev Peripheral instance address + * @param x_int The integrated part of scaling coefficient in X direction, 0 - 255 + * @param x_frag The fragment part of scaling coefficient in X direction, 0 - 15. Corresponding fractional value is x_frag/16. + */ +static inline void ppa_ll_srm_set_scaling_x(ppa_dev_t *dev, uint32_t x_int, uint32_t x_frag) +{ + HAL_ASSERT(x_int <= PPA_SRM_SCAL_X_INT_V && x_frag <= PPA_SRM_SCAL_X_FRAG_V); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->srm_scal_rotate, srm_scal_x_int, x_int); + dev->srm_scal_rotate.srm_scal_x_frag = x_frag; +} + +/** + * @brief Set PPA scaling coefficient in Y direction + * + * @param dev Peripheral instance address + * @param y_int The integrated part of scaling coefficient in Y direction, 0 - 255 + * @param y_frag The fragment part of scaling coefficient in Y direction, 0 - 15. Corresponding fractional value is y_frag/16. + */ +static inline void ppa_ll_srm_set_scaling_y(ppa_dev_t *dev, uint32_t y_int, uint32_t y_frag) +{ + HAL_ASSERT(y_int <= PPA_SRM_SCAL_Y_INT_V && y_frag <= PPA_SRM_SCAL_Y_FRAG_V); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->srm_scal_rotate, srm_scal_y_int, y_int); + dev->srm_scal_rotate.srm_scal_y_frag = y_frag; +} + +/** + * @brief Set PPA rotation angle (in the counterclockwise direction) + * + * @param dev Peripheral instance address + * @param angle One of the values in ppa_srm_rotation_angle_t + */ +static inline void ppa_ll_srm_set_rotation_angle(ppa_dev_t *dev, ppa_srm_rotation_angle_t angle) +{ + uint32_t val = 0; + switch (angle) { + case PPA_SRM_ROTATION_ANGLE_0: + val = 0; + break; + case PPA_SRM_ROTATION_ANGLE_90: + val = 1; + break; + case PPA_SRM_ROTATION_ANGLE_180: + val = 2; + break; + case PPA_SRM_ROTATION_ANGLE_270: + val = 3; + break; + default: + // Unsupported rotation angle + abort(); + } + dev->srm_scal_rotate.srm_rotate_angle = val; +} + +/** + * @brief Enable PPA image mirror in X direction + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_srm_enable_mirror_x(ppa_dev_t *dev, bool enable) +{ + dev->srm_scal_rotate.srm_mirror_x = enable; +} + +/** + * @brief Enable PPA image mirror in Y direction + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_srm_enable_mirror_y(ppa_dev_t *dev, bool enable) +{ + dev->srm_scal_rotate.srm_mirror_y = enable; +} + +/** + * @brief Start PPA scaling and rotating engine to perform PPA SRM + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_srm_start(ppa_dev_t *dev) +{ + dev->srm_scal_rotate.scal_rotate_start = 1; +} + +/** + * @brief Set PPA SRM input side YUV422 data format packing order + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_srm_color_mode_t + */ +static inline void ppa_ll_srm_set_rx_yuv422_pack_order(ppa_dev_t *dev, ppa_srm_color_mode_t color_mode) +{ + switch (color_mode) { + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + dev->srm_color_mode.yuv422_rx_byte_order = 3; + break; + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + dev->srm_color_mode.yuv422_rx_byte_order = 2; + break; + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + dev->srm_color_mode.yuv422_rx_byte_order = 1; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + dev->srm_color_mode.yuv422_rx_byte_order = 0; + break; + default: + // Unsupported YUV422 pack order + abort(); + } +} + +/** + * @brief Check if the given color mode is supported by PPA SRM engine + * + * @param color_mode One of the values in ppa_srm_color_mode_t + * @return true if supported; false if not supported + */ +static inline bool ppa_ll_srm_is_color_mode_supported(ppa_srm_color_mode_t color_mode) +{ + switch (color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + case PPA_SRM_COLOR_MODE_RGB888: + case PPA_SRM_COLOR_MODE_RGB565: + case PPA_SRM_COLOR_MODE_YUV420: + case PPA_SRM_COLOR_MODE_YUV444: // YUV444 not supported by PPA hardware, but can be converted by 2D-DMA before PPA, and not supported as output color mode + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + case PPA_SRM_COLOR_MODE_GRAY8: + return true; + default: + return false; + } +} + +/** + * @brief Set the source image color mode for PPA Scaling-Rotating-Mirroring engine RX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_srm_color_mode_t + */ +static inline void ppa_ll_srm_set_rx_color_mode(ppa_dev_t *dev, ppa_srm_color_mode_t color_mode) +{ + uint32_t val = 0; + bool is_yuv422 __attribute__((unused)) = false; + switch (color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_SRM_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_SRM_COLOR_MODE_RGB565: + val = 2; + break; + case PPA_SRM_COLOR_MODE_YUV420: + val = 8; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + val = 9; + is_yuv422 = true; + break; + case PPA_SRM_COLOR_MODE_GRAY8: + val = 12; + break; + default: + // Unsupported SRM rx color mode + abort(); + } + dev->srm_color_mode.srm_rx_cm = val; + + // set YUV422 packing order + if (is_yuv422) { + ppa_ll_srm_set_rx_yuv422_pack_order(dev, color_mode); + } +} + +/** + * @brief Set the destination image color mode for PPA Scaling-Rotating-Mirroring engine TX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_srm_color_mode_t + */ +static inline void ppa_ll_srm_set_tx_color_mode(ppa_dev_t *dev, ppa_srm_color_mode_t color_mode) +{ + uint32_t val = 0; + switch (color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_SRM_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_SRM_COLOR_MODE_RGB565: + val = 2; + break; + case PPA_SRM_COLOR_MODE_YUV420: + val = 8; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + val = 9; + break; + case PPA_SRM_COLOR_MODE_GRAY8: + val = 12; + break; + default: + // Unsupported SRM tx color mode + abort(); + } + dev->srm_color_mode.srm_tx_cm = val; +} + +/** + * @brief Set YUV to RGB protocol when PPA SRM RX pixel color space is YUV + * + * @param dev Peripheral instance address + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t + */ +static inline void ppa_ll_srm_set_rx_yuv2rgb_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) +{ + switch (std) { + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: + dev->srm_color_mode.yuv2rgb_protocol = 0; + break; + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: + dev->srm_color_mode.yuv2rgb_protocol = 1; + break; + default: + // Unsupported RGB-YUV conversion standard + abort(); + } +} + +/** + * @brief Set RGB to YUV protocol when PPA SRM TX pixel color space is YUV + * + * @param dev Peripheral instance address + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t + */ +static inline void ppa_ll_srm_set_tx_rgb2yuv_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) +{ + switch (std) { + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: + dev->srm_color_mode.rgb2yuv_protocol = 0; + break; + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: + dev->srm_color_mode.rgb2yuv_protocol = 1; + break; + default: + // Unsupported RGB-YUV conversion standard + abort(); + } +} + +/** + * @brief Set PPA SRM YUV input range + * + * @param dev Peripheral instance address + * @param range One of color range options in ppa_color_range_t + */ +static inline void ppa_ll_srm_set_rx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) +{ + switch (range) { + case PPA_COLOR_RANGE_LIMIT: + dev->srm_color_mode.yuv_rx_range = 0; + break; + case PPA_COLOR_RANGE_FULL: + dev->srm_color_mode.yuv_rx_range = 1; + break; + default: + // Unsupported color range + abort(); + } +} + +/** + * @brief Set PPA SRM YUV output range + * + * @param dev Peripheral instance address + * @param range One of color range options in ppa_color_range_t + */ +static inline void ppa_ll_srm_set_tx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) +{ + switch (range) { + case PPA_COLOR_RANGE_LIMIT: + dev->srm_color_mode.yuv_tx_range = 0; + break; + case PPA_COLOR_RANGE_FULL: + dev->srm_color_mode.yuv_tx_range = 1; + break; + default: + // Unsupported color range + abort(); + } +} + +/** + * @brief Enable PPA SRM input data swap in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_srm_enable_rx_rgb_swap(ppa_dev_t *dev, bool enable) +{ + dev->srm_byte_order.srm_rx_rgb_swap_en = enable; +} + +/** + * @brief Enable PPA SRM input data swap in byte (The Byte0 and Byte1 would be swapped while byte 2 and byte 3 would be swappped) + * + * Only supported when input color mode is ARGB8888 or RGB565. + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_srm_enable_rx_byte_swap(ppa_dev_t *dev, bool enable) +{ + dev->srm_byte_order.srm_rx_byte_swap_en = enable; +} + +/** + * @brief Configure PPA SRM alpha value update mode + * + * @param dev Peripheral instance address + * @param mode Alpha value update mode, one of the values in ppa_alpha_update_mode_t + * @param val When PPA_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) + * When PPA_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) + * When other modes are selected, this field is not used + */ +static inline void ppa_ll_srm_configure_rx_alpha(ppa_dev_t *dev, ppa_alpha_update_mode_t mode, uint32_t val) +{ + switch (mode) { + case PPA_ALPHA_NO_CHANGE: + dev->srm_fix_alpha.srm_rx_alpha_mod = 0; + dev->srm_fix_alpha.srm_rx_alpha_inv = 0; + break; + case PPA_ALPHA_FIX_VALUE: + dev->srm_fix_alpha.srm_rx_alpha_mod = 1; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->srm_fix_alpha, srm_rx_fix_alpha, val); + dev->srm_fix_alpha.srm_rx_alpha_inv = 0; + break; + case PPA_ALPHA_SCALE: + dev->srm_fix_alpha.srm_rx_alpha_mod = 2; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->srm_fix_alpha, srm_rx_fix_alpha, val); + dev->srm_fix_alpha.srm_rx_alpha_inv = 0; + break; + case PPA_ALPHA_INVERT: + dev->srm_fix_alpha.srm_rx_alpha_mod = 0; + dev->srm_fix_alpha.srm_rx_alpha_inv = 1; + break; + default: + // Unsupported alpha update mode + abort(); + } +} + +/** + * @brief Get the current configured PPA SRM macro block size + * + * @param dev Peripheral instance address + * @return The current configured macro block size, one of the values in ppa_ll_srm_mb_size_t + */ +static inline ppa_ll_srm_mb_size_t ppa_ll_srm_get_mb_size(ppa_dev_t *dev) +{ + return (dev->srm_byte_order.srm_bk_size_sel == 0) ? PPA_LL_SRM_MB_SIZE_32_32 : PPA_LL_SRM_MB_SIZE_16_16; +} + +/** + * @brief Set PPA SRM macro block size + * + * @param dev Peripheral instance address + * @param mb_size Macro block size to be set, one of the values in ppa_ll_srm_mb_size_t + */ +static inline void ppa_ll_srm_set_mb_size(ppa_dev_t *dev, ppa_ll_srm_mb_size_t mb_size) +{ + switch (mb_size) { + case PPA_LL_SRM_MB_SIZE_16_16: + dev->srm_byte_order.srm_bk_size_sel = 1; + break; + case PPA_LL_SRM_MB_SIZE_32_32: + dev->srm_byte_order.srm_bk_size_sel = 0; + break; + default: + // Unsupported SRM macro block size + abort(); + } +} + +/** + * @brief Retrieve the 2D-DMA descriptor port mode block size (in pixel) according to the PPA SRM input color mode and configured macro block size + * + * @param dev Peripheral instance address + * @param in_color_mode Input color mode, one of the values in ppa_srm_color_mode_t + * @param mb_size SRM macro block size, one of the values in ppa_ll_srm_mb_size_t + * @param[out] block_h Returned block horizontal width + * @param[out] block_v Returned block wvertical height + */ +static inline void ppa_ll_srm_get_dma_dscr_port_mode_block_size(ppa_dev_t *dev, ppa_srm_color_mode_t in_color_mode, ppa_ll_srm_mb_size_t mb_size, uint32_t *block_h, uint32_t *block_v) +{ + if (mb_size == PPA_LL_SRM_MB_SIZE_16_16) { + switch (in_color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + case PPA_SRM_COLOR_MODE_RGB888: + case PPA_SRM_COLOR_MODE_RGB565: + case PPA_SRM_COLOR_MODE_GRAY8: + *block_h = 18; + *block_v = 18; + break; + case PPA_SRM_COLOR_MODE_YUV420: + *block_h = 20; + *block_v = 20; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + *block_h = 20; + *block_v = 18; + break; + default: + // Unsupported SRM input color mode + *block_h = 0; + *block_v = 0; + } + } else if (mb_size == PPA_LL_SRM_MB_SIZE_32_32) { + switch (in_color_mode) { + case PPA_SRM_COLOR_MODE_ARGB8888: + case PPA_SRM_COLOR_MODE_RGB888: + case PPA_SRM_COLOR_MODE_RGB565: + case PPA_SRM_COLOR_MODE_GRAY8: + *block_h = 34; + *block_v = 34; + break; + case PPA_SRM_COLOR_MODE_YUV420: + *block_h = 36; + *block_v = 36; + break; + case PPA_SRM_COLOR_MODE_YUV422_UYVY: + case PPA_SRM_COLOR_MODE_YUV422_VYUY: + case PPA_SRM_COLOR_MODE_YUV422_YUYV: + case PPA_SRM_COLOR_MODE_YUV422_YVYU: + *block_h = 36; + *block_v = 34; + break; + default: + // Unsupported SRM input color mode + *block_h = 0; + *block_v = 0; + } + } else { + // Unsupported SRM macro block size + *block_h = 0; + *block_v = 0; + } +} + +/** + * @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->srm_byte_order.srm_macro_bk_ro_bypass = enable; +} + +//////////////////////////////////// Blending //////////////////////////////////////// +/* + * Alpha Blending Calculation: + * 1. A_bg, A_fg first convert to A_bg', A_fg' according to blend_fix_alpha register configuration + * 2. Then do blending + * A_out = A_bg' + A_fg' - A_bg' * A_fg' + * C_out_r/g/b = (C_bg_r/g/b * A_bg' * (1 - A_fg') + C_fg_r/g/b * A_fg') / A_out + */ + +/** + * @brief Reset PPA blending engine + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_reset(ppa_dev_t *dev) +{ + dev->blend_trans_mode.blend_rst = 1; + dev->blend_trans_mode.blend_rst = 0; +} + +/** + * @brief Start PPA blending engine to perform PPA Blending + * + * @param dev Peripheral instance address + * @param trans_mode Blending engine transfer mode, one of the values in ppa_ll_blend_trans_mode_t + */ +static inline void ppa_ll_blend_start(ppa_dev_t *dev, ppa_ll_blend_trans_mode_t trans_mode) +{ + switch (trans_mode) { + case PPA_LL_BLEND_TRANS_MODE_BLEND: + dev->blend_trans_mode.blend_bypass = 0; + dev->blend_trans_mode.blend_fix_pixel_fill_en = 0; + break; + case PPA_LL_BLEND_TRANS_MODE_FILL: + dev->blend_trans_mode.blend_bypass = 0; + dev->blend_trans_mode.blend_fix_pixel_fill_en = 1; + break; + case PPA_LL_BLEND_TRANS_MODE_BYPASS_BLEND: + dev->blend_trans_mode.blend_bypass = 1; + dev->blend_trans_mode.blend_fix_pixel_fill_en = 0; + break; + default: + // Unsupported blending trans mode + abort(); + } + dev->blend_trans_mode.blend_en = 1; + dev->blend_trans_mode.blend_trans_mode_update = 1; +} + +/** + * @brief Set PPA blending source image background YUV422 data format packing order + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_blend_color_mode_t + */ +static inline void ppa_ll_blend_set_rx_bg_yuv422_pack_order(ppa_dev_t *dev, ppa_blend_color_mode_t color_mode) +{ + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_YUV422_YVYU: + dev->blend_color_mode.blend0_rx_yuv422_byte_order = 3; + break; + case PPA_BLEND_COLOR_MODE_YUV422_YUYV: + dev->blend_color_mode.blend0_rx_yuv422_byte_order = 2; + break; + case PPA_BLEND_COLOR_MODE_YUV422_VYUY: + dev->blend_color_mode.blend0_rx_yuv422_byte_order = 1; + break; + case PPA_BLEND_COLOR_MODE_YUV422_UYVY: + dev->blend_color_mode.blend0_rx_yuv422_byte_order = 0; + break; + default: + // Unsupported YUV422 pack order + abort(); + } +} + +/** + * @brief Check if the given color mode is supported by PPA blending engine + * + * @param color_mode One of the values in ppa_blend_color_mode_t + * @return true if supported (by any of rx_bg, rx_fg, tx); false if not supported + */ +static inline bool ppa_ll_blend_is_color_mode_supported(ppa_blend_color_mode_t color_mode) +{ + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_ARGB8888: + case PPA_BLEND_COLOR_MODE_RGB888: + case PPA_BLEND_COLOR_MODE_RGB565: + case PPA_BLEND_COLOR_MODE_A8: + case PPA_BLEND_COLOR_MODE_A4: + // case PPA_BLEND_COLOR_MODE_L8: + // case PPA_BLEND_COLOR_MODE_L4: + case PPA_BLEND_COLOR_MODE_YUV420: + case PPA_BLEND_COLOR_MODE_YUV422_UYVY: + case PPA_BLEND_COLOR_MODE_YUV422_VYUY: + case PPA_BLEND_COLOR_MODE_YUV422_YUYV: + case PPA_BLEND_COLOR_MODE_YUV422_YVYU: + case PPA_BLEND_COLOR_MODE_GRAY8: + return true; + default: + return false; + } +} + +/** + * @brief Set the source image color mode for background for PPA blending engine RX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_blend_color_mode_t (some color modes may not be applicable to rx bg) + */ +static inline void ppa_ll_blend_set_rx_bg_color_mode(ppa_dev_t *dev, ppa_blend_color_mode_t color_mode) +{ + uint32_t val = 0; + bool is_yuv422 __attribute__((unused)) = false; + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_BLEND_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_BLEND_COLOR_MODE_RGB565: + val = 2; + break; + // case PPA_BLEND_COLOR_MODE_L8: + // val = 4; + // break; + // case PPA_BLEND_COLOR_MODE_L4: + // val = 5; + // break; + case PPA_BLEND_COLOR_MODE_YUV420: + val = 8; + break; + case PPA_BLEND_COLOR_MODE_YUV422_UYVY: + case PPA_BLEND_COLOR_MODE_YUV422_VYUY: + case PPA_BLEND_COLOR_MODE_YUV422_YUYV: + case PPA_BLEND_COLOR_MODE_YUV422_YVYU: + val = 9; + is_yuv422 = true; + break; + case PPA_BLEND_COLOR_MODE_GRAY8: + val = 12; + break; + default: + // Unsupported blending rx background color mode + abort(); + } + dev->blend_color_mode.blend0_rx_cm = val; + + // set YUV422 packing order + if (is_yuv422) { + ppa_ll_blend_set_rx_bg_yuv422_pack_order(dev, color_mode); + } +} + +/** + * @brief Set the source image color mode for foreground for PPA blending engine RX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_blend_color_mode_t + */ +static inline void ppa_ll_blend_set_rx_fg_color_mode(ppa_dev_t *dev, ppa_blend_color_mode_t color_mode) +{ + uint32_t val = 0; + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_BLEND_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_BLEND_COLOR_MODE_RGB565: + val = 2; + break; + // case PPA_BLEND_COLOR_MODE_L8: + // val = 4; + // break; + // case PPA_BLEND_COLOR_MODE_L4: + // val = 5; + // break; + case PPA_BLEND_COLOR_MODE_A8: + val = 6; + break; + case PPA_BLEND_COLOR_MODE_A4: + val = 7; + break; + default: + // Unsupported blending rx foreground color mode + abort(); + } + dev->blend_color_mode.blend1_rx_cm = val; +} + +/** + * @brief Set the destination image color mode for PPA blending engine TX + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_blend_color_mode_t (some color modes may not be applicable to tx) + */ +static inline void ppa_ll_blend_set_tx_color_mode(ppa_dev_t *dev, ppa_blend_color_mode_t color_mode) +{ + uint32_t val = 0; + switch (color_mode) { + case PPA_BLEND_COLOR_MODE_ARGB8888: + val = 0; + break; + case PPA_BLEND_COLOR_MODE_RGB888: + val = 1; + break; + case PPA_BLEND_COLOR_MODE_RGB565: + val = 2; + break; + case PPA_BLEND_COLOR_MODE_YUV420: + val = 8; + break; + case PPA_BLEND_COLOR_MODE_YUV422_UYVY: + val = 9; + break; + case PPA_BLEND_COLOR_MODE_GRAY8: + val = 12; + break; + default: + // Unsupported blending tx color mode + abort(); + } + dev->blend_color_mode.blend_tx_cm = val; +} + +/** + * @brief Set YUV to RGB protocol when PPA blending source image background pixel color space is YUV + * + * @param dev Peripheral instance address + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t + */ +static inline void ppa_ll_blend_set_rx_bg_yuv2rgb_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) +{ + switch (std) { + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: + dev->blend_color_mode.blend0_rx_yuv2rgb_protocol = 0; + break; + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: + dev->blend_color_mode.blend0_rx_yuv2rgb_protocol = 1; + break; + default: + // Unsupported RGB-YUV conversion standard + abort(); + } +} + +/** + * @brief Set RGB to YUV protocol when PPA blending destination image pixel color space is YUV + * + * @param dev Peripheral instance address + * @param std One of the RGB-YUV conversion standards in ppa_color_conv_std_rgb_yuv_t + */ +static inline void ppa_ll_blend_set_tx_rgb2yuv_std(ppa_dev_t *dev, ppa_color_conv_std_rgb_yuv_t std) +{ + switch (std) { + case PPA_COLOR_CONV_STD_RGB_YUV_BT601: + dev->blend_color_mode.blend_tx_rgb2yuv_protocol = 0; + break; + case PPA_COLOR_CONV_STD_RGB_YUV_BT709: + dev->blend_color_mode.blend_tx_rgb2yuv_protocol = 1; + break; + default: + // Unsupported RGB-YUV conversion standard + abort(); + } +} + +/** + * @brief Set PPA blending source image background YUV input range + * + * @param dev Peripheral instance address + * @param range One of color range options in ppa_color_range_t + */ +static inline void ppa_ll_blend_set_rx_bg_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) +{ + switch (range) { + case PPA_COLOR_RANGE_LIMIT: + dev->blend_color_mode.blend0_rx_yuv_range = 0; + break; + case PPA_COLOR_RANGE_FULL: + dev->blend_color_mode.blend0_rx_yuv_range = 1; + break; + default: + // Unsupported color range + abort(); + } +} + +/** + * @brief Set PPA blending destination image YUV output range + * + * @param dev Peripheral instance address + * @param range One of color range options in ppa_color_range_t + */ +static inline void ppa_ll_blend_set_tx_yuv_range(ppa_dev_t *dev, ppa_color_range_t range) +{ + switch (range) { + case PPA_COLOR_RANGE_LIMIT: + dev->blend_color_mode.blend_tx_yuv_range = 0; + break; + case PPA_COLOR_RANGE_FULL: + dev->blend_color_mode.blend_tx_yuv_range = 1; + break; + default: + // Unsupported color range + abort(); + } +} + +/** + * @brief Enable PPA blending input background data wrap in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_blend_enable_rx_bg_rgb_swap(ppa_dev_t *dev, bool enable) +{ + dev->blend_byte_order.blend0_rx_rgb_swap_en = enable; +} + +/** + * @brief Enable PPA blending input foreground data wrap in RGB (e.g. ARGB becomes BGRA, RGB becomes BGR) + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_blend_enable_rx_fg_rgb_swap(ppa_dev_t *dev, bool enable) +{ + dev->blend_byte_order.blend1_rx_rgb_swap_en = enable; +} + +/** + * @brief Enable PPA blending input background data swap in byte (The Byte0 and Byte1 would be swapped while byte 2 and byte 3 would be swappped) + * + * Only supported when input color mode is ARGB8888 or RGB565. + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_blend_enable_rx_bg_byte_swap(ppa_dev_t *dev, bool enable) +{ + dev->blend_byte_order.blend0_rx_byte_swap_en = enable; +} + +/** + * @brief Enable PPA blending input foreground data swap in byte (The Byte0 and Byte1 would be swapped while byte 2 and byte 3 would be swappped) + * + * Only supported when input color mode is ARGB8888 or RGB565. + * + * @param dev Peripheral instance address + * @param enable True to enable; False to disable + */ +static inline void ppa_ll_blend_enable_rx_fg_byte_swap(ppa_dev_t *dev, bool enable) +{ + dev->blend_byte_order.blend1_rx_byte_swap_en = enable; +} + +/** + * @brief Configure PPA blending input background alpha value update mode + * + * @param dev Peripheral instance address + * @param mode Alpha value update mode, one of the values in ppa_alpha_update_mode_t + * @param val When PPA_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) + * When PPA_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) + * When other modes are selected, this field is not used + */ +static inline void ppa_ll_blend_configure_rx_bg_alpha(ppa_dev_t *dev, ppa_alpha_update_mode_t mode, uint32_t val) +{ + switch (mode) { + case PPA_ALPHA_NO_CHANGE: + dev->blend_fix_alpha.blend0_rx_alpha_mod = 0; + dev->blend_fix_alpha.blend0_rx_alpha_inv = 0; + break; + case PPA_ALPHA_FIX_VALUE: + dev->blend_fix_alpha.blend0_rx_alpha_mod = 1; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend0_rx_fix_alpha, val); + dev->blend_fix_alpha.blend0_rx_alpha_inv = 0; + break; + case PPA_ALPHA_SCALE: + dev->blend_fix_alpha.blend0_rx_alpha_mod = 2; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend0_rx_fix_alpha, val); + dev->blend_fix_alpha.blend0_rx_alpha_inv = 0; + break; + case PPA_ALPHA_INVERT: + dev->blend_fix_alpha.blend0_rx_alpha_mod = 0; + dev->blend_fix_alpha.blend0_rx_alpha_inv = 1; + break; + default: + // Unsupported alpha update mode + abort(); + } +} + +/** + * @brief Configure PPA blending input foreground alpha value update mode + * + * @param dev Peripheral instance address + * @param mode Alpha value update mode, one of the values in ppa_alpha_update_mode_t + * @param val When PPA_ALPHA_FIX_VALUE mode is selected, val is the alpha value to be replaced with (output_alpha = val) + * When PPA_ALPHA_SCALE mode is selected, val/256 is the multiplier to the input alpha value (output_alpha = input_alpha * val / 256) + * When other modes are selected, this field is not used + */ +static inline void ppa_ll_blend_configure_rx_fg_alpha(ppa_dev_t *dev, ppa_alpha_update_mode_t mode, uint32_t val) +{ + switch (mode) { + case PPA_ALPHA_NO_CHANGE: + dev->blend_fix_alpha.blend1_rx_alpha_mod = 0; + dev->blend_fix_alpha.blend1_rx_alpha_inv = 0; + break; + case PPA_ALPHA_FIX_VALUE: + dev->blend_fix_alpha.blend1_rx_alpha_mod = 1; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend1_rx_fix_alpha, val); + dev->blend_fix_alpha.blend1_rx_alpha_inv = 0; + break; + case PPA_ALPHA_SCALE: + dev->blend_fix_alpha.blend1_rx_alpha_mod = 2; + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_fix_alpha, blend1_rx_fix_alpha, val); + dev->blend_fix_alpha.blend1_rx_alpha_inv = 0; + break; + case PPA_ALPHA_INVERT: + dev->blend_fix_alpha.blend1_rx_alpha_mod = 0; + dev->blend_fix_alpha.blend1_rx_alpha_inv = 1; + break; + default: + // Unsupported alpha update mode + abort(); + } +} + +/** + * @brief Configure PPA blending pixel filling image block + * + * The color to be filled is directly relying on the blend_tx_fix_pixel register field value. + * For fill operation, the data does not go through any color space conversion in the blending engine. + * + * @param dev Peripheral instance address + * @param color_mode One of the values in ppa_fill_color_mode_t + * @param data The point of the fix data to be filled to the image block pixels + * @param hb The horizontal width of image block that would be filled in fix pixel filling mode. The unit is pixel. + * @param vb The vertical height of image block that would be filled in fix pixel filling mode. The unit is pixel. + */ +static inline void ppa_ll_blend_configure_filling_block(ppa_dev_t *dev, ppa_fill_color_mode_t color_mode, void *data, uint32_t hb, uint32_t vb) +{ + HAL_ASSERT(hb <= PPA_BLEND_HB_V && vb <= PPA_BLEND_VB_V); + uint32_t fill_color_data = 0; + switch (color_mode) { + case PPA_FILL_COLOR_MODE_ARGB8888: + case PPA_FILL_COLOR_MODE_RGB888: + case PPA_FILL_COLOR_MODE_RGB565: + case PPA_FILL_COLOR_MODE_GRAY8: + fill_color_data = *(uint32_t *)data; + break; + case PPA_FILL_COLOR_MODE_YUV422_UYVY: { + color_macroblock_yuv_data_t *yuv_data = (color_macroblock_yuv_data_t *)data; + fill_color_data = ((yuv_data->y) << 24) | ((yuv_data->v) << 16) | ((yuv_data->y) << 8) | (yuv_data->u); + break; + } + // Non-typical YUV420, U and V components have to be the same value + // case PPA_FILL_COLOR_MODE_YUV420: { + // color_macroblock_yuv_data_t *yuv_data = (color_macroblock_yuv_data_t *)data; + // if (yuv_data->u != yuv_data->v) { + // abort(); + // } + // fill_color_data = ((yuv_data->y) << 16) | ((yuv_data->y) << 8) | (yuv_data->v); + // break; + // } + default: + // Unsupported filling color mode + abort(); + } + dev->blend_fix_pixel.blend_tx_fix_pixel = fill_color_data; + dev->blend_tx_size.blend_hb = hb; + dev->blend_tx_size.blend_vb = vb; +} + +/** + * @brief Configure PPA blending input foreground fixed RGB color for A4/A8 color mode + * + * @param dev Peripheral instance address + * @param rgb RGB color for A4/A8 mode in RGB888 format + */ +static inline void ppa_ll_blend_set_rx_fg_fix_rgb(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_rgb, blend1_rx_b, rgb->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_rgb, blend1_rx_g, rgb->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->blend_rgb, blend1_rx_r, rgb->r); +} + +/* + * Color-key Calculation: + * 1) When FG in ck range, but BG not in ck range, then outputs BG pixel value. + * 2) When BG in ck range, but FG not in ck range, then depends on FG_BG_REVERSE value: if FG_BG_REVERSE = 0, outputs BG pixel value; otherwise, outputs FG pixel value. + * 3) When FG and BG both in their ck ranges, then outputs ck default color. + * 4) When FG and BG both not in their ck ranges, then it goes through normal Alpha Blending calculation. + */ + +/** + * @brief Configure PPA blending input background color-key threshold + * + * @param dev Peripheral instance address + * @param rgb_thres_low Color-key lower threshold of background in RGB888 format + * @param rgb_thres_high Color-key higher threshold of background in RGB888 format + */ +static inline void ppa_ll_blend_configure_rx_bg_ck_range(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb_thres_low, color_pixel_rgb888_data_t *rgb_thres_high) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_low, colorkey_bg_b_low, rgb_thres_low->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_low, colorkey_bg_g_low, rgb_thres_low->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_low, colorkey_bg_r_low, rgb_thres_low->r); + + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_high, colorkey_bg_b_high, rgb_thres_high->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_high, colorkey_bg_g_high, rgb_thres_high->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_bg_high, colorkey_bg_r_high, rgb_thres_high->r); +} + +/** + * @brief Configure PPA blending input foreground color-key threshold + * + * @param dev Peripheral instance address + * @param rgb_thres_low Color-key lower threshold of foreground in RGB888 format + * @param rgb_thres_high Color-key higher threshold of foreground in RGB888 format + */ +static inline void ppa_ll_blend_configure_rx_fg_ck_range(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb_thres_low, color_pixel_rgb888_data_t *rgb_thres_high) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_low, colorkey_fg_b_low, rgb_thres_low->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_low, colorkey_fg_g_low, rgb_thres_low->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_low, colorkey_fg_r_low, rgb_thres_low->r); + + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_high, colorkey_fg_b_high, rgb_thres_high->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_high, colorkey_fg_g_high, rgb_thres_high->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_fg_high, colorkey_fg_r_high, rgb_thres_high->r); +} + +/** + * @brief Configure PPA blending default RGB value when foreground and background both in color-key range + * + * @param dev Peripheral instance address + * @param rgb Default RGB value in RGB888 format + */ +static inline void ppa_ll_blend_set_ck_default_rgb(ppa_dev_t *dev, color_pixel_rgb888_data_t *rgb) +{ + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_default, colorkey_default_b, rgb->b); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_default, colorkey_default_g, rgb->g); + HAL_FORCE_MODIFY_U32_REG_FIELD(dev->ck_default, colorkey_default_r, rgb->r); +} + +/** + * @brief Configure whether to reverse the output when PPA blending pixel in background color-key range but not in foreground color-key range + * + * @param dev Peripheral instance address + * @param enable True then output the foreground pixel value; False then output the background pixel value + */ +static inline void ppa_ll_blend_enable_ck_fg_bg_reverse(ppa_dev_t *dev, bool enable) +{ + dev->ck_default.colorkey_fg_bg_reverse = enable; +} + +/////////////////////////// Color Look-Up Table (CLUT) /////////////////////////////// +/** + * @brief Configure PPA CLUT mem access mode + * + * @param dev Peripheral instance address + * @param fifo_mode True to access through fifo mode; False to access through memory mode + */ +static inline void ppa_ll_configure_clut_access_mode(ppa_dev_t *dev, bool fifo_mode) +{ + dev->clut_conf.apb_fifo_mask = !fifo_mode; +} + +/** + * @brief Force clock and power on for PPA blending BLEND CLUT mem + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_enable_clut_mem(ppa_dev_t *dev) +{ + dev->clut_conf.blend_clut_mem_clk_ena = 1; + dev->clut_conf.blend_clut_mem_force_pu = 1; // force clut mem remain power when memory domain PD +} + +/** + * @brief Force clock and power off for PPA blending BLEND CLUT mem + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_disable_clut_mem(ppa_dev_t *dev) +{ + dev->clut_conf.blend_clut_mem_clk_ena = 0; + dev->clut_conf.blend_clut_mem_force_pu = 0; +} + +/** + * @brief Reset PPA blending BLEND0 CLUT mem and read address + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_reset_rx_bg_clut_mem(ppa_dev_t *dev) +{ + dev->clut_conf.blend0_clut_mem_rst = 1; + dev->clut_conf.blend0_clut_mem_rst = 0; + dev->clut_conf.blend0_clut_mem_rdaddr_rst = 1; + dev->clut_conf.blend0_clut_mem_rdaddr_rst = 0; +} + +/** + * @brief Reset PPA blending BLEND1 CLUT mem and read address + * + * @param dev Peripheral instance address + */ +static inline void ppa_ll_blend_reset_rx_fg_clut_mem(ppa_dev_t *dev) +{ + dev->clut_conf.blend1_clut_mem_rst = 1; + dev->clut_conf.blend1_clut_mem_rst = 0; + dev->clut_conf.blend1_clut_mem_rdaddr_rst = 1; + dev->clut_conf.blend1_clut_mem_rdaddr_rst = 0; +} + +/** + * @brief Write PPA blending BLEND0 CLUT mem entry through FIFO mode + * + * @param dev Peripheral instance address + * @param data The data to be written into BLEND0 CLUT entry in ARGB8888 format + */ +static inline void ppa_ll_blend_wr_rx_bg_clut_data_by_fifo(ppa_dev_t *dev, uint32_t data) +{ + dev->blend0_clut_data.rdwr_word_blend0_clut = data; +} + +/** + * @brief Write PPA blending BLEND1 CLUT mem entry through FIFO mode + * + * @param dev Peripheral instance address + * @param data The data to be written into BLEND1 CLUT entry in ARGB8888 format + */ +static inline void ppa_ll_blend_wr_rx_fg_clut_data_by_fifo(ppa_dev_t *dev, uint32_t data) +{ + dev->blend1_clut_data.rdwr_word_blend1_clut = data; +} + +/** + * @brief Write PPA blending BLEND0 CLUT mem entry through memory mode + * + * @param dev Peripheral instance address + * @param idx Entry index to the CLUT mem + * @param data The data to be written into BLEND0 CLUT entry in ARGB8888 format + */ +static inline void ppa_ll_blend_wr_rx_bg_clut_data_by_mem(ppa_dev_t *dev, uint32_t idx, uint32_t data) +{ + volatile uint32_t *blend0_clut_mem = (uint32_t *)((uint32_t)dev + PPA_LL_BLEND0_CLUT_MEM_ADDR_OFFSET); + blend0_clut_mem[idx] = data; +} + +/** + * @brief Write PPA blending BLEND1 CLUT mem entry through memory mode + * + * @param dev Peripheral instance address + * @param idx Entry index to the CLUT mem + * @param data The data to be written into BLEND1 CLUT entry in ARGB8888 format + */ +static inline void ppa_ll_blend_wr_rx_fg_clut_data_by_mem(ppa_dev_t *dev, uint32_t idx, uint32_t data) +{ + volatile uint32_t *blend1_clut_mem = (uint32_t *)((uint32_t)dev + PPA_LL_BLEND1_CLUT_MEM_ADDR_OFFSET); + blend1_clut_mem[idx] = data; +} + +#ifdef __cplusplus +} +#endif diff --git a/components/esp_hal_ppa/ppa_hal.c b/components/esp_hal_ppa/ppa_hal.c index 5f057f54281..b44a2d42696 100644 --- a/components/esp_hal_ppa/ppa_hal.c +++ b/components/esp_hal_ppa/ppa_hal.c @@ -6,10 +6,13 @@ #include #include "hal/ppa_hal.h" +#include "hal/ppa_ll.h" void ppa_hal_init(ppa_hal_context_t *hal) { hal->dev = PPA_LL_GET_HW; + ppa_ll_mem_power_by_pmu(hal->dev); + ppa_ll_mem_set_low_power_mode(hal->dev, PPA_LL_MEM_LP_MODE_SHUT_DOWN); } void ppa_hal_deinit(ppa_hal_context_t *hal) diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 12bd0757356..68fa5a39f9c 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -215,6 +215,10 @@ config SOC_TOUCH_SENSOR_SUPPORTED bool default y +config SOC_PPA_SUPPORTED + bool + default y + config SOC_MODEM_CLOCK_SUPPORTED bool default y diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 5d2d08c9d31..a205bdbc5f5 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -96,7 +96,7 @@ #define SOC_SPI_FLASH_SUPPORTED 1 // TODO: [ESP32S31] IDF-14777 #define SOC_TOUCH_SENSOR_SUPPORTED 1 // #define SOC_RNG_SUPPORTED 1 // TODO: [ESP32S31] IDF-14632 -// #define SOC_PPA_SUPPORTED 1 // TODO: [ESP32S31] IDF-14769 +#define SOC_PPA_SUPPORTED 1 // #define SOC_LIGHT_SLEEP_SUPPORTED 1 // TODO: [ESP32S31] IDF-14645 // #define SOC_DEEP_SLEEP_SUPPORTED 1 // TODO: [ESP32S31] IDF-14643 #define SOC_MODEM_CLOCK_SUPPORTED 1 diff --git a/components/soc/esp32s31/register/soc/ppa_reg.h b/components/soc/esp32s31/register/soc/ppa_reg.h index 9e606e08383..5052c2748c7 100644 --- a/components/soc/esp32s31/register/soc/ppa_reg.h +++ b/components/soc/esp32s31/register/soc/ppa_reg.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -272,20 +272,20 @@ extern "C" { #define PPA_YUV_TX_RANGE_M (PPA_YUV_TX_RANGE_V << PPA_YUV_TX_RANGE_S) #define PPA_YUV_TX_RANGE_V 0x00000001U #define PPA_YUV_TX_RANGE_S 9 -/** PPA_YUV2RGB_PROTOCAL : R/W; bitpos: [10]; default: 0; +/** PPA_YUV2RGB_PROTOCOL : R/W; bitpos: [10]; default: 0; * YUV to RGB protocol when reg_sr_rx_cm is 4'd8. 0: BT601. 1: BT709 */ -#define PPA_YUV2RGB_PROTOCAL (BIT(10)) -#define PPA_YUV2RGB_PROTOCAL_M (PPA_YUV2RGB_PROTOCAL_V << PPA_YUV2RGB_PROTOCAL_S) -#define PPA_YUV2RGB_PROTOCAL_V 0x00000001U -#define PPA_YUV2RGB_PROTOCAL_S 10 -/** PPA_RGB2YUV_PROTOCAL : R/W; bitpos: [11]; default: 0; +#define PPA_YUV2RGB_PROTOCOL (BIT(10)) +#define PPA_YUV2RGB_PROTOCOL_M (PPA_YUV2RGB_PROTOCOL_V << PPA_YUV2RGB_PROTOCOL_S) +#define PPA_YUV2RGB_PROTOCOL_V 0x00000001U +#define PPA_YUV2RGB_PROTOCOL_S 10 +/** PPA_RGB2YUV_PROTOCOL : R/W; bitpos: [11]; default: 0; * RGB to YUV protocol when reg_sr_tx_cm is 4'd8. 0: BT601. 1: BT709 */ -#define PPA_RGB2YUV_PROTOCAL (BIT(11)) -#define PPA_RGB2YUV_PROTOCAL_M (PPA_RGB2YUV_PROTOCAL_V << PPA_RGB2YUV_PROTOCAL_S) -#define PPA_RGB2YUV_PROTOCAL_V 0x00000001U -#define PPA_RGB2YUV_PROTOCAL_S 11 +#define PPA_RGB2YUV_PROTOCOL (BIT(11)) +#define PPA_RGB2YUV_PROTOCOL_M (PPA_RGB2YUV_PROTOCOL_V << PPA_RGB2YUV_PROTOCOL_S) +#define PPA_RGB2YUV_PROTOCOL_V 0x00000001U +#define PPA_RGB2YUV_PROTOCOL_S 11 /** PPA_YUV422_RX_BYTE_ORDER : R/W; bitpos: [13:12]; default: 0; * YUV422 input byte order when reg_sr_rx_cm is 4'd9. 0: YVYU, 1:YUYV, 2: VYUY, 3: UYVY (high addr -> low addr) */ @@ -336,20 +336,20 @@ extern "C" { #define PPA_BLEND_TX_YUV_RANGE_M (PPA_BLEND_TX_YUV_RANGE_V << PPA_BLEND_TX_YUV_RANGE_S) #define PPA_BLEND_TX_YUV_RANGE_V 0x00000001U #define PPA_BLEND_TX_YUV_RANGE_S 13 -/** PPA_BLEND0_RX_YUV2RGB_PROTOCAL : R/W; bitpos: [14]; default: 0; +/** PPA_BLEND0_RX_YUV2RGB_PROTOCOL : R/W; bitpos: [14]; default: 0; * YUV to RGB protocol when blend0 rx cm is yuv. 0: BT601. 1: BT709 */ -#define PPA_BLEND0_RX_YUV2RGB_PROTOCAL (BIT(14)) -#define PPA_BLEND0_RX_YUV2RGB_PROTOCAL_M (PPA_BLEND0_RX_YUV2RGB_PROTOCAL_V << PPA_BLEND0_RX_YUV2RGB_PROTOCAL_S) -#define PPA_BLEND0_RX_YUV2RGB_PROTOCAL_V 0x00000001U -#define PPA_BLEND0_RX_YUV2RGB_PROTOCAL_S 14 -/** PPA_BLEND_TX_RGB2YUV_PROTOCAL : R/W; bitpos: [15]; default: 0; +#define PPA_BLEND0_RX_YUV2RGB_PROTOCOL (BIT(14)) +#define PPA_BLEND0_RX_YUV2RGB_PROTOCOL_M (PPA_BLEND0_RX_YUV2RGB_PROTOCOL_V << PPA_BLEND0_RX_YUV2RGB_PROTOCOL_S) +#define PPA_BLEND0_RX_YUV2RGB_PROTOCOL_V 0x00000001U +#define PPA_BLEND0_RX_YUV2RGB_PROTOCOL_S 14 +/** PPA_BLEND_TX_RGB2YUV_PROTOCOL : R/W; bitpos: [15]; default: 0; * RGB to YUV protocol when blend tx cm is yuv. 0: BT601. 1: BT709 */ -#define PPA_BLEND_TX_RGB2YUV_PROTOCAL (BIT(15)) -#define PPA_BLEND_TX_RGB2YUV_PROTOCAL_M (PPA_BLEND_TX_RGB2YUV_PROTOCAL_V << PPA_BLEND_TX_RGB2YUV_PROTOCAL_S) -#define PPA_BLEND_TX_RGB2YUV_PROTOCAL_V 0x00000001U -#define PPA_BLEND_TX_RGB2YUV_PROTOCAL_S 15 +#define PPA_BLEND_TX_RGB2YUV_PROTOCOL (BIT(15)) +#define PPA_BLEND_TX_RGB2YUV_PROTOCOL_M (PPA_BLEND_TX_RGB2YUV_PROTOCOL_V << PPA_BLEND_TX_RGB2YUV_PROTOCOL_S) +#define PPA_BLEND_TX_RGB2YUV_PROTOCOL_V 0x00000001U +#define PPA_BLEND_TX_RGB2YUV_PROTOCOL_S 15 /** PPA_BLEND0_RX_YUV422_BYTE_ORDER : R/W; bitpos: [17:16]; default: 0; * YUV422 input byte order when reg_sr_rx_cm is 4'd9. 0: YVYU, 1:YUYV, 2: VYUY, 3: UYVY (high addr -> low addr) */ diff --git a/components/soc/esp32s31/register/soc/ppa_struct.h b/components/soc/esp32s31/register/soc/ppa_struct.h index e500ee68e02..b103ff384ed 100644 --- a/components/soc/esp32s31/register/soc/ppa_struct.h +++ b/components/soc/esp32s31/register/soc/ppa_struct.h @@ -1,5 +1,5 @@ /** - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 OR MIT */ @@ -108,14 +108,14 @@ typedef union { * YUV output range when reg_sr_tx_cm is 4'd8. 0: limit range. 1: full range */ uint32_t yuv_tx_range:1; - /** yuv2rgb_protocal : R/W; bitpos: [10]; default: 0; + /** yuv2rgb_protocol : R/W; bitpos: [10]; default: 0; * YUV to RGB protocol when reg_sr_rx_cm is 4'd8. 0: BT601. 1: BT709 */ - uint32_t yuv2rgb_protocal:1; - /** rgb2yuv_protocal : R/W; bitpos: [11]; default: 0; + uint32_t yuv2rgb_protocol:1; + /** rgb2yuv_protocol : R/W; bitpos: [11]; default: 0; * RGB to YUV protocol when reg_sr_tx_cm is 4'd8. 0: BT601. 1: BT709 */ - uint32_t rgb2yuv_protocal:1; + uint32_t rgb2yuv_protocol:1; /** yuv422_rx_byte_order : R/W; bitpos: [13:12]; default: 0; * YUV422 input byte order when reg_sr_rx_cm is 4'd9. 0: YVYU, 1:YUYV, 2: VYUY, 3: UYVY (high addr -> low addr) */ @@ -153,14 +153,14 @@ typedef union { * YUV output range when blend tx cm is yuv. 0: limit range. 1: full range */ uint32_t blend_tx_yuv_range:1; - /** blend0_rx_yuv2rgb_protocal : R/W; bitpos: [14]; default: 0; + /** blend0_rx_yuv2rgb_protocol : R/W; bitpos: [14]; default: 0; * YUV to RGB protocol when blend0 rx cm is yuv. 0: BT601. 1: BT709 */ - uint32_t blend0_rx_yuv2rgb_protocal:1; - /** blend_tx_rgb2yuv_protocal : R/W; bitpos: [15]; default: 0; + uint32_t blend0_rx_yuv2rgb_protocol:1; + /** blend_tx_rgb2yuv_protocol : R/W; bitpos: [15]; default: 0; * RGB to YUV protocol when blend tx cm is yuv. 0: BT601. 1: BT709 */ - uint32_t blend_tx_rgb2yuv_protocal:1; + uint32_t blend_tx_rgb2yuv_protocol:1; /** blend0_rx_yuv422_byte_order : R/W; bitpos: [17:16]; default: 0; * YUV422 input byte order when reg_sr_rx_cm is 4'd9. 0: YVYU, 1:YUYV, 2: VYUY, 3: UYVY (high addr -> low addr) */ @@ -969,7 +969,7 @@ typedef union { } ppa_date_reg_t; -typedef struct { +typedef struct ppa_dev_t { volatile ppa_blend0_clut_data_reg_t blend0_clut_data; volatile ppa_blend1_clut_data_reg_t blend1_clut_data; uint32_t reserved_008; @@ -1013,6 +1013,7 @@ typedef struct { volatile ppa_date_reg_t date; } ppa_dev_t; +extern ppa_dev_t PPA; #ifndef __cplusplus _Static_assert(sizeof(ppa_dev_t) == 0x104, "Invalid size of ppa_dev_t structure"); diff --git a/docs/doxygen/Doxyfile_esp32s31 b/docs/doxygen/Doxyfile_esp32s31 index 3dae6279e8c..6019e724bcd 100644 --- a/docs/doxygen/Doxyfile_esp32s31 +++ b/docs/doxygen/Doxyfile_esp32s31 @@ -4,6 +4,8 @@ INPUT += \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_decode.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_encode.h \ $(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_types.h \ + $(PROJECT_PATH)/components/esp_driver_ppa/include/driver/ppa.h \ + $(PROJECT_PATH)/components/esp_hal_ppa/include/hal/ppa_types.h \ $(PROJECT_PATH)/components/esp_driver_touch_sens/hw_ver3/include/driver/touch_version_types.h \ $(PROJECT_PATH)/components/esp_driver_touch_sens/include/driver/touch_sens.h \ $(PROJECT_PATH)/components/esp_driver_touch_sens/include/driver/touch_sens_types.h\ diff --git a/docs/en/api-reference/peripherals/ppa.rst b/docs/en/api-reference/peripherals/ppa.rst index 9ae45f3a9e2..f314b2add91 100644 --- a/docs/en/api-reference/peripherals/ppa.rst +++ b/docs/en/api-reference/peripherals/ppa.rst @@ -139,7 +139,7 @@ The PPA requires certain buffer alignment rules to ensure memory access correctn - Cache line alignment (output buffer only): - - The ``out.buffer`` address and ``out.buffer_size`` must be aligned to the cache line size (see Kconfig option :ref:`CONFIG_CACHE_L2_CACHE_LINE_SIZE`). + - The ``out.buffer`` address and ``out.buffer_size`` must be aligned to the cache line size, if the buffer is located in a memory region that is cacheable. - Flash encryption alignment (when flash encryption is enabled and the buffers are located in external memory): diff --git a/docs/zh_CN/api-reference/peripherals/ppa.rst b/docs/zh_CN/api-reference/peripherals/ppa.rst index f1e2e37003e..f1dc9f850bb 100644 --- a/docs/zh_CN/api-reference/peripherals/ppa.rst +++ b/docs/zh_CN/api-reference/peripherals/ppa.rst @@ -139,7 +139,7 @@ PPA 缓存区需要满足以下对齐要求,以确保存储器访问的正确 - 缓冲行对齐(仅针对输出缓存区): - - ``out.buffer`` 地址和 ``out.buffer_size`` 大小必须与缓冲行大小对齐(请参阅 Kconfig 选项 :ref:`CONFIG_CACHE_L2_CACHE_LINE_SIZE`)。 + - 如果输出缓冲区位于一个可缓存的内存区域,则 ``out.buffer`` 地址和 ``out.buffer_size`` 大小必须与缓冲行大小对齐。 - 存储加密对齐(当存储加密启用且缓冲区位于外部存储空间时):