From a035a90ef6ac6e17a889a717b5c72a98e577c993 Mon Sep 17 00:00:00 2001 From: morris Date: Wed, 10 Jun 2026 16:07:55 +0800 Subject: [PATCH] feat(mipi_dsi): replace the fbcopy driver by the async color conver driver --- components/esp_lcd/CMakeLists.txt | 4 - components/esp_lcd/dsi/esp_lcd_panel_dpi.c | 82 +++---- .../esp_lcd/priv_include/esp_async_fbcpy.h | 90 ------- components/esp_lcd/src/esp_async_fbcpy.c | 219 ------------------ 4 files changed, 36 insertions(+), 359 deletions(-) delete mode 100644 components/esp_lcd/priv_include/esp_async_fbcpy.h delete mode 100644 components/esp_lcd/src/esp_async_fbcpy.c diff --git a/components/esp_lcd/CMakeLists.txt b/components/esp_lcd/CMakeLists.txt index 795856ff2fc..f5044ee4a5e 100644 --- a/components/esp_lcd/CMakeLists.txt +++ b/components/esp_lcd/CMakeLists.txt @@ -13,10 +13,6 @@ set(includes "include" "interface") set(priv_requires "esp_mm" "esp_psram" "esp_pm" "esp_driver_i2s" "esp_driver_dma") set(public_requires "esp_driver_gpio" "esp_driver_i2c" "esp_driver_spi" "esp_driver_parlio" "esp_hal_lcd") -if(CONFIG_SOC_DMA2D_SUPPORTED) - list(APPEND srcs "src/esp_async_fbcpy.c") -endif() - if(CONFIG_SOC_I2C_SUPPORTED) list(APPEND srcs "i2c/esp_lcd_panel_io_i2c.c") endif() diff --git a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c index 246f1509ad2..3c38f45aca2 100644 --- a/components/esp_lcd/dsi/esp_lcd_panel_dpi.c +++ b/components/esp_lcd/dsi/esp_lcd_panel_dpi.c @@ -6,11 +6,11 @@ #include #include "esp_lcd_panel_interface.h" #include "esp_lcd_mipi_dsi.h" +#include "esp_async_color_convert.h" #include "esp_intr_alloc.h" #include "esp_clk_tree.h" #include "esp_cache.h" #include "mipi_dsi_priv.h" -#include "esp_async_fbcpy.h" #include "esp_memory_utils.h" #include "esp_private/dw_gdma.h" #include "hal/color_hal.h" @@ -45,8 +45,7 @@ struct esp_lcd_dpi_panel_t { esp_lcd_panel_draw_bitmap_hook_t draw_bitmap_hook; // Draw bitmap hook function void* hook_ctx; // Hook context bool (*on_hook_end)(esp_lcd_panel_handle_t panel); // Callback to be invoked when the draw bitmap hook completes its operation - esp_async_fbcpy_handle_t fbcpy_handle; // Use DMA2D to do frame buffer copy (only when using DMA2D draw bitmap hook) - SemaphoreHandle_t draw_sem; // A semaphore used to synchronize the draw operations when DMA2D is used + async_color_convert_handle_t fbcpy_handle; // Async color convert handle used for same-format DMA2D frame buffer copy #if CONFIG_PM_ENABLE esp_pm_lock_handle_t pm_lock; // Power management lock @@ -66,24 +65,18 @@ static bool dpi_panel_draw_bitmap_hook_end(esp_lcd_panel_t *panel) return false; } -static bool async_fbcpy_done_cb(esp_async_fbcpy_handle_t mcp, esp_async_fbcpy_event_data_t *event, void *cb_args) +static bool async_fbcpy_done_cb(async_color_convert_handle_t conv_hdl, async_color_convert_event_data_t *event, void *cb_args) { bool need_yield = false; esp_lcd_dpi_panel_t *dpi_panel = (esp_lcd_dpi_panel_t *)cb_args; - - // release the draw semaphore first - BaseType_t task_woken = pdFALSE; - xSemaphoreGiveFromISR(dpi_panel->draw_sem, &task_woken); - if (task_woken == pdTRUE) { - need_yield = true; - } + (void)conv_hdl; + (void)event; if (dpi_panel->on_hook_end) { if (dpi_panel->on_hook_end(&dpi_panel->base)) { need_yield = true; } } - return need_yield; } @@ -489,28 +482,31 @@ static esp_err_t dpi_panel_draw_bitmap_dma2d_hook(esp_lcd_panel_t *panel, const { ESP_LOGV(TAG, "copy draw buffer by DMA2D"); esp_lcd_dpi_panel_t *dpi_panel = __containerof(panel, esp_lcd_dpi_panel_t, base); - // ensure the previous draw operation is finished - ESP_RETURN_ON_FALSE(xSemaphoreTake(dpi_panel->draw_sem, 0) == pdTRUE, ESP_ERR_INVALID_STATE, - TAG, "previous draw operation is not finished"); + (void)hook_ctx; - esp_async_fbcpy_trans_desc_t fbcpy_trans_config = { + async_color_convert_request_t fbcpy_trans_config = { .src_buffer = hook_data->src_data, .dst_buffer = hook_data->dst_data, - .src_buffer_size_x = hook_data->src_x_size, - .src_buffer_size_y = hook_data->src_y_size, - .dst_buffer_size_x = hook_data->dst_x_size, - .dst_buffer_size_y = hook_data->dst_y_size, - .src_offset_x = hook_data->src_x_start, - .src_offset_y = hook_data->src_y_start, - .dst_offset_x = hook_data->dst_x_start, - .dst_offset_y = hook_data->dst_y_start, - .copy_size_x = hook_data->src_x_end - hook_data->src_x_start, - .copy_size_y = hook_data->src_y_end - hook_data->src_y_start, - .pixel_format_fourcc_id = dpi_panel->in_color_format, + .src_stride = hook_data->src_x_size, + .src_height = hook_data->src_y_size, + .dst_stride = hook_data->dst_x_size, + .dst_height = hook_data->dst_y_size, + .src_x = hook_data->src_x_start, + .src_y = hook_data->src_y_start, + .dst_x = hook_data->dst_x_start, + .dst_y = hook_data->dst_y_start, + .copy_width = hook_data->src_x_end - hook_data->src_x_start, + .copy_height = hook_data->src_y_end - hook_data->src_y_start, + // For this DMA2D hook we only do window copy from draw buffer to frame buffer. + // Source and destination color formats are intentionally set to the same value to disable CSC. + .src_color_format = dpi_panel->in_color_format, + .dst_color_format = dpi_panel->in_color_format, }; - // save the on_hook_end callback, and invoke it when the async memcpy is done + // The async color convert backend owns source/destination cache sync for the + // DMA2D copy path, so the LCD driver should not perform extra cache sync here. + // Save the completion callback and invoke it when the async frame buffer copy finishes. dpi_panel->on_hook_end = hook_data->on_hook_end; - ESP_RETURN_ON_ERROR(esp_async_fbcpy(dpi_panel->fbcpy_handle, &fbcpy_trans_config, async_fbcpy_done_cb, dpi_panel), TAG, "async memcpy failed"); + ESP_RETURN_ON_ERROR(esp_async_color_convert(dpi_panel->fbcpy_handle, &fbcpy_trans_config, async_fbcpy_done_cb, dpi_panel), TAG, "async frame buffer copy failed"); return ESP_OK; } @@ -535,13 +531,11 @@ esp_err_t esp_lcd_dpi_panel_enable_dma2d(esp_lcd_panel_handle_t panel) // Check if built-in DMA2D draw bitmap hook is registered ESP_RETURN_ON_FALSE(!dpi_panel->fbcpy_handle, ESP_ERR_INVALID_STATE, TAG, "draw bitmap DMA2D hook is already registered"); - // Initialize DMA2D resources - esp_async_fbcpy_config_t fbcpy_config = {}; - ESP_RETURN_ON_ERROR(esp_async_fbcpy_install(&fbcpy_config, &dpi_panel->fbcpy_handle), TAG, "install async memcpy 2d failed"); + // Initialize the async color convert backend used by the built-in DMA2D copy hook. + // Use its default backlog to queue multiple frame buffer copy requests. + async_color_convert_config_t fbcpy_config = {}; + ESP_RETURN_ON_ERROR(esp_async_color_convert_install_dma2d(&fbcpy_config, &dpi_panel->fbcpy_handle), TAG, "install async frame buffer copy backend failed"); - dpi_panel->draw_sem = xSemaphoreCreateBinaryWithCaps(DSI_MEM_ALLOC_CAPS); - ESP_GOTO_ON_FALSE(dpi_panel->draw_sem, ESP_ERR_NO_MEM, err, TAG, "no memory for draw semaphore"); - xSemaphoreGive(dpi_panel->draw_sem); // Register the DMA2D draw bitmap hook esp_lcd_panel_hooks_t hooks = { .draw_bitmap_hook = dpi_panel_draw_bitmap_dma2d_hook, @@ -552,13 +546,10 @@ esp_err_t esp_lcd_dpi_panel_enable_dma2d(esp_lcd_panel_handle_t panel) err: if (dpi_panel->fbcpy_handle) { - esp_async_fbcpy_uninstall(dpi_panel->fbcpy_handle); + esp_async_color_convert_uninstall(dpi_panel->fbcpy_handle); dpi_panel->fbcpy_handle = NULL; } - if (dpi_panel->draw_sem) { - vSemaphoreDeleteWithCaps(dpi_panel->draw_sem); - dpi_panel->draw_sem = NULL; - } + dpi_panel->on_hook_end = NULL; return ret; } @@ -575,13 +566,10 @@ esp_err_t esp_lcd_dpi_panel_disable_dma2d(esp_lcd_panel_handle_t panel) }; ESP_RETURN_ON_ERROR(esp_lcd_dpi_panel_register_hooks(panel, &hooks, NULL), TAG, "unregister DMA2D draw bitmap hook failed"); if (dpi_panel->fbcpy_handle) { - ESP_RETURN_ON_ERROR(esp_async_fbcpy_uninstall(dpi_panel->fbcpy_handle), TAG, "uninstall DMA2D failed"); + ESP_RETURN_ON_ERROR(esp_async_color_convert_uninstall(dpi_panel->fbcpy_handle), TAG, "uninstall DMA2D failed"); dpi_panel->fbcpy_handle = NULL; } - if (dpi_panel->draw_sem) { - vSemaphoreDeleteWithCaps(dpi_panel->draw_sem); - dpi_panel->draw_sem = NULL; - } + dpi_panel->on_hook_end = NULL; return ESP_OK; } @@ -647,7 +635,9 @@ static esp_err_t dpi_panel_draw_bitmap_2d(esp_lcd_panel_t *panel, int x_start, i } } else if (dpi_panel->draw_bitmap_hook) { // copy using draw bitmap hook ESP_LOGV(TAG, "copy draw buffer by draw bitmap hook"); - // Note, whether the previous draw operation is finished should be ensured by the hook + // Note, whether the previous draw operation is finished should be ensured by the hook. + // For the built-in DMA2D hook, cache maintenance of the source and destination + // buffers is handled inside the async color convert driver. esp_lcd_draw_bitmap_hook_data_t hook_data = { .dst_data = frame_buffer, diff --git a/components/esp_lcd/priv_include/esp_async_fbcpy.h b/components/esp_lcd/priv_include/esp_async_fbcpy.h deleted file mode 100644 index 481b3aed2b7..00000000000 --- a/components/esp_lcd/priv_include/esp_async_fbcpy.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "esp_err.h" -#include "hal/color_types.h" - -/** - * @brief Async FrameBuffer copy context - */ -typedef struct esp_async_fbcpy_context_t *esp_async_fbcpy_handle_t; - -/** - * @brief Async FrameBuffer copy configuration - */ -typedef struct { -} esp_async_fbcpy_config_t; - -/** - * @brief Install Async FrameBuffer copy driver - * - * @param config Async FrameBuffer copy configuration - * @param mcp Returned Async FrameBuffer copy handle - * @return - * - ESP_OK: Install Async FrameBuffer copy driver successfully - * - ESP_ERR_INVALID_ARG: Install Async FrameBuffer copy driver failed because of invalid argument - * - ESP_ERR_NO_MEM: Install Async FrameBuffer copy driver failed because of out of memory - * - ESP_FAIL: Install Async FrameBuffer copy driver failed because of other error - */ -esp_err_t esp_async_fbcpy_install(const esp_async_fbcpy_config_t *config, esp_async_fbcpy_handle_t *mcp); - -/** - * @brief Uninstall Async FrameBuffer copy driver - * - * @param mcp Async FrameBuffer copy handle - * @return - * - ESP_OK: Uninstall Async FrameBuffer copy driver successfully - * - ESP_ERR_INVALID_ARG: Uninstall Async FrameBuffer copy driver failed because of invalid argument - * - ESP_FAIL: Uninstall Async FrameBuffer copy driver failed because of other error - */ -esp_err_t esp_async_fbcpy_uninstall(esp_async_fbcpy_handle_t mcp); - -/** - * @brief Async FrameBuffer copy transaction descriptor - */ -typedef struct { - const void *src_buffer; /*!< Source buffer */ - void *dst_buffer; /*!< Destination buffer */ - size_t src_buffer_size_x; /*!< Source buffer size in x direction, size count in the number of pixels */ - size_t src_buffer_size_y; /*!< Source buffer size in y direction, size count in the number of pixels */ - size_t dst_buffer_size_x; /*!< Destination buffer size in x direction, size count in the number of pixels */ - size_t dst_buffer_size_y; /*!< Destination buffer size in y direction, size count in the number of pixels */ - size_t src_offset_x; /*!< Copy action will start from this offset in source buffer in the x direction, offset count in the number of pixels */ - size_t src_offset_y; /*!< Copy action will start from this offset in source buffer in the y direction, offset count in the number of pixels */ - size_t dst_offset_x; /*!< Copy action will start from this offset in destination buffer in the x direction, offset count in the number of pixels */ - size_t dst_offset_y; /*!< Copy action will start from this offset in destination buffer in the y direction, offset count in the number of pixels */ - size_t copy_size_x; /*!< Copy size in the x direction, size count in the number of pixels */ - size_t copy_size_y; /*!< Copy size in the y direction, size count in the number of pixels */ - esp_color_fourcc_t pixel_format_fourcc_id; /*!< Pixel format unique ID */ -} esp_async_fbcpy_trans_desc_t; - -/** - * @brief Async FrameBuffer copy event data - */ -typedef struct { -} esp_async_fbcpy_event_data_t; - -/** - * @brief Async FrameBuffer copy event callback prototype - */ -typedef bool (*esp_async_fbcpy_event_callback_t)(esp_async_fbcpy_handle_t mcp, esp_async_fbcpy_event_data_t *event_data, void *cb_args); - -/** - * @brief Start Async FrameBuffer copy transaction - * - * @param mcp Async FrameBuffer copy handle - * @param transaction Async FrameBuffer copy transaction descriptor - * @param memcpy_done_cb Callback function that will be invoked when Async FrameBuffer copy transaction finishes - * @param cb_args User data - * @return - * - ESP_OK: Start Async FrameBuffer copy transaction successfully - * - ESP_ERR_INVALID_ARG: Start Async FrameBuffer copy transaction failed because of invalid argument - * - ESP_FAIL: Start Async FrameBuffer copy transaction failed because of other error - */ -esp_err_t esp_async_fbcpy(esp_async_fbcpy_handle_t mcp, esp_async_fbcpy_trans_desc_t* transaction, - esp_async_fbcpy_event_callback_t memcpy_done_cb, void *cb_args); diff --git a/components/esp_lcd/src/esp_async_fbcpy.c b/components/esp_lcd/src/esp_async_fbcpy.c deleted file mode 100644 index 448e0d996de..00000000000 --- a/components/esp_lcd/src/esp_async_fbcpy.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_check.h" -#include "esp_cache.h" -#include "esp_heap_caps.h" -#include "soc/dma2d_channel.h" -#include "hal/cache_hal.h" -#include "hal/cache_ll.h" -#include "hal/dma2d_ll.h" -#include "esp_private/dma2d.h" -#include "esp_async_fbcpy.h" - -#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) - -static const char *TAG = "async_fbcpy"; - -typedef struct esp_async_fbcpy_context_t { - dma2d_pool_handle_t client; // DMA2D client - dma2d_descriptor_t* tx_desc; // DMA2D TX descriptor - dma2d_descriptor_t* rx_desc; // DMA2D RX descriptor - dma2d_trans_t* trans_desc; // DMA2D transaction descriptor - size_t dma_desc_size; // DMA2D descriptor size - esp_async_fbcpy_event_callback_t memcpy_done_cb; // memory copy done callback - void *cb_args; // callback arguments -} esp_async_fbcpy_context_t; - -static esp_err_t async_fbcpy_del_context(esp_async_fbcpy_context_t* ctx) -{ - if (ctx->tx_desc) { - free(ctx->tx_desc); - } - if (ctx->rx_desc) { - free(ctx->rx_desc); - } - if (ctx->trans_desc) { - free(ctx->trans_desc); - } - if (ctx->client) { - dma2d_release_pool(ctx->client); - } - free(ctx); - return ESP_OK; -} - -esp_err_t esp_async_fbcpy_install(const esp_async_fbcpy_config_t *config, esp_async_fbcpy_handle_t *mcp) -{ - esp_err_t ret = ESP_OK; - esp_async_fbcpy_context_t *ctx = NULL; - dma2d_trans_t* trans_desc = NULL; - dma2d_descriptor_t* dma_tx_desc = NULL; - dma2d_descriptor_t* dma_rx_desc = NULL; - dma2d_pool_handle_t dma2d_client = NULL; - - ESP_RETURN_ON_FALSE(config && mcp, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - // allocate context memory - ctx = heap_caps_calloc(1, sizeof(esp_async_fbcpy_context_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - ESP_GOTO_ON_FALSE(ctx, ESP_ERR_NO_MEM, err, TAG, "no mem for esp_async_fbcpy_context_t"); - // according to the dma2d design, the transaction descriptor is also saved by the user - trans_desc = heap_caps_calloc(1, dma2d_get_trans_elm_size(), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - ESP_GOTO_ON_FALSE(trans_desc, ESP_ERR_NO_MEM, err, TAG, "no mem for trans_desc"); - ctx->trans_desc = trans_desc; - // allocate memory for DMA descriptor, the descriptor must be allocated from the internal memory, and alignment to the cache line size - uint32_t data_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); - size_t alignment = MAX(DMA2D_LL_DESC_ALIGNMENT, data_cache_line_size); - size_t dma_desc_mem_size = ALIGN_UP(sizeof(dma2d_descriptor_align8_t), alignment); - dma_tx_desc = heap_caps_aligned_calloc(alignment, 1, dma_desc_mem_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - dma_rx_desc = heap_caps_aligned_calloc(alignment, 1, dma_desc_mem_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - ESP_GOTO_ON_FALSE(dma_tx_desc && dma_rx_desc, ESP_ERR_NO_MEM, err, TAG, "no memory for DMA2D descriptors"); - ctx->tx_desc = dma_tx_desc; - ctx->rx_desc = dma_rx_desc; - ctx->dma_desc_size = dma_desc_mem_size; - - // initialize DMA2D client - dma2d_pool_config_t dma2d_client_config = {}; // all follow default configurations - ESP_GOTO_ON_ERROR(dma2d_acquire_pool(&dma2d_client_config, &dma2d_client), err, TAG, "create DMA2D client failed"); - ctx->client = dma2d_client; - - *mcp = ctx; - return ESP_OK; - -err: - if (ctx) { - async_fbcpy_del_context(ctx); - } - return ret; -} - -esp_err_t esp_async_fbcpy_uninstall(esp_async_fbcpy_handle_t mcp) -{ - ESP_RETURN_ON_FALSE(mcp, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - return async_fbcpy_del_context(mcp); -} - -static void async_memcpy_setup_dma2d_descriptor(esp_async_fbcpy_context_t* mcp_ctx, esp_async_fbcpy_trans_desc_t* transaction) -{ - dma2d_descriptor_t* tx_desc = mcp_ctx->tx_desc; - dma2d_descriptor_t* rx_desc = mcp_ctx->rx_desc; - size_t dma_desc_size = mcp_ctx->dma_desc_size; - uint8_t dma2d_pbyte = dma2d_desc_pixel_format_to_pbyte_value(transaction->pixel_format_fourcc_id); - - tx_desc->buffer = (void*)transaction->src_buffer; - tx_desc->next = NULL; - tx_desc->dma2d_en = 1; - tx_desc->suc_eof = 1; - tx_desc->ha_length = transaction->src_buffer_size_x; - tx_desc->va_size = transaction->src_buffer_size_y; - tx_desc->hb_length = transaction->copy_size_x; - tx_desc->vb_size = transaction->copy_size_y; - tx_desc->x = transaction->src_offset_x; - tx_desc->y = transaction->src_offset_y; - tx_desc->pbyte = dma2d_pbyte; - tx_desc->mode = DMA2D_DESCRIPTOR_BLOCK_RW_MODE_SINGLE; - tx_desc->owner = DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA; - - rx_desc->buffer = transaction->dst_buffer; - rx_desc->next = NULL; - rx_desc->dma2d_en = 1; - rx_desc->suc_eof = 1; - rx_desc->ha_length = transaction->dst_buffer_size_x; - rx_desc->va_size = transaction->dst_buffer_size_y; - rx_desc->hb_length = transaction->copy_size_x; - rx_desc->vb_size = transaction->copy_size_y; - rx_desc->x = transaction->dst_offset_x; - rx_desc->y = transaction->dst_offset_y; - rx_desc->pbyte = dma2d_pbyte; - rx_desc->mode = DMA2D_DESCRIPTOR_BLOCK_RW_MODE_SINGLE; - rx_desc->owner = DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA; - - esp_cache_msync(tx_desc, dma_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); - esp_cache_msync(rx_desc, dma_desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); -} - -static bool dma2d_memcpy_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data) -{ - bool need_yield = false; - esp_async_fbcpy_context_t* mcp = (esp_async_fbcpy_context_t*)user_data; - - if (mcp->memcpy_done_cb) { - need_yield = mcp->memcpy_done_cb(mcp, NULL, mcp->cb_args); - } - - return need_yield; -} - -static bool dma2d_job_picked_cb(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_data) -{ - esp_async_fbcpy_context_t* mcp = (esp_async_fbcpy_context_t*)user_data; - dma2d_channel_handle_t tx_chan = NULL; - dma2d_channel_handle_t rx_chan = NULL; - for (uint32_t i = 0; i < num_chans; i++) { - if (dma2d_chans[i].dir == DMA2D_CHANNEL_DIRECTION_TX) { - tx_chan = dma2d_chans[i].chan; - } - if (dma2d_chans[i].dir == DMA2D_CHANNEL_DIRECTION_RX) { - rx_chan = dma2d_chans[i].chan; - } - } - dma2d_trigger_t trig_periph = { - .periph = DMA2D_TRIG_PERIPH_M2M, - .periph_sel_id = SOC_DMA2D_TRIG_PERIPH_M2M_TX, - }; - dma2d_connect(tx_chan, &trig_periph); - trig_periph.periph_sel_id = SOC_DMA2D_TRIG_PERIPH_M2M_RX; - dma2d_connect(rx_chan, &trig_periph); - - dma2d_rx_event_callbacks_t dma_cbs = { - .on_recv_eof = dma2d_memcpy_done_cb, - }; - dma2d_register_rx_event_callbacks(rx_chan, &dma_cbs, mcp); - - // 2D-DMA channel data burst length is set to the maximum burst length by default, which meets the encryption alignment restriction - // so even if flash encryption is enabled, it can work properly - - dma2d_set_desc_addr(tx_chan, (intptr_t)(mcp->tx_desc)); - dma2d_set_desc_addr(rx_chan, (intptr_t)(mcp->rx_desc)); - - dma2d_start(tx_chan); - dma2d_start(rx_chan); - - return false; -} - -esp_err_t esp_async_fbcpy(esp_async_fbcpy_handle_t mcp, esp_async_fbcpy_trans_desc_t* transaction, esp_async_fbcpy_event_callback_t memcpy_done_cb, void *cb_args) -{ - ESP_RETURN_ON_FALSE(mcp && transaction, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE(transaction->copy_size_x > 0 && transaction->copy_size_y > 0, ESP_ERR_INVALID_ARG, TAG, "invalid copy size"); - mcp->memcpy_done_cb = memcpy_done_cb; - mcp->cb_args = cb_args; - - // Write back the user's draw buffer only when it is behind cache, so that the DMA can see the correct data. - // Note, the user src buffer may not be contiguous, write back from the head to the tail anyways. - size_t bits_per_pixel = color_hal_pixel_format_fourcc_get_bit_depth(transaction->pixel_format_fourcc_id); - size_t copy_head = (transaction->src_offset_x + transaction->src_offset_y * transaction->src_buffer_size_x) * bits_per_pixel / 8; - size_t copy_size = (transaction->copy_size_x + (transaction->copy_size_y - 1) * transaction->src_buffer_size_x) * bits_per_pixel / 8; - void *copy_start = (void *)((const uint8_t *)transaction->src_buffer + copy_head); - size_t cache_line_size = esp_cache_get_line_size_by_addr(copy_start); - if (cache_line_size > 0) { - ESP_RETURN_ON_ERROR(esp_cache_msync(copy_start, copy_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED), TAG, "writeback draw buffer failed"); - } - - // mount the data to the DMA descriptor - async_memcpy_setup_dma2d_descriptor(mcp, transaction); - - // submit the DMA2D request - static dma2d_trans_config_t dma2d_trans_conf = { - .tx_channel_num = 1, - .rx_channel_num = 1, - .channel_flags = DMA2D_CHANNEL_FUNCTION_FLAG_SIBLING, - .on_job_picked = dma2d_job_picked_cb, - }; - dma2d_trans_conf.user_config = mcp; - ESP_RETURN_ON_ERROR(dma2d_enqueue(mcp->client, &dma2d_trans_conf, mcp->trans_desc), TAG, "DMA2D enqueue failed"); - return ESP_OK; -}