Skip to content

Commit 12d4804

Browse files
committed
Merge branch 'feature/esp32p4_ppa_driver_support_v5.3' into 'release/v5.3'
feat(ppa): add PPA driver support for ESP32P4 (v5.3) See merge request espressif/esp-idf!31074
2 parents e148263 + 10f89fe commit 12d4804

File tree

41 files changed

+2931
-169
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2931
-169
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
set(srcs)
2+
set(public_include "include")
3+
if(CONFIG_SOC_PPA_SUPPORTED)
4+
list(APPEND srcs "src/ppa_core.c"
5+
"src/ppa_srm.c"
6+
"src/ppa_blend.c"
7+
"src/ppa_fill.c")
8+
endif()
9+
10+
idf_component_register(SRCS ${srcs}
11+
INCLUDE_DIRS ${public_include}
12+
PRIV_REQUIRES esp_mm esp_pm
13+
)

components/esp_driver_ppa/include/driver/ppa.h

Lines changed: 292 additions & 0 deletions
Large diffs are not rendered by default.

components/esp_driver_ppa/src/ppa_blend.c

Lines changed: 287 additions & 0 deletions
Large diffs are not rendered by default.

components/esp_driver_ppa/src/ppa_core.c

Lines changed: 515 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include "esp_check.h"
8+
#include "driver/ppa.h"
9+
#include "ppa_priv.h"
10+
#include "esp_private/dma2d.h"
11+
#include "hal/ppa_ll.h"
12+
#include "esp_cache.h"
13+
#include "esp_memory_utils.h"
14+
#include "soc/dma2d_channel.h"
15+
16+
static const char *TAG = "ppa_fill";
17+
18+
bool ppa_fill_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config)
19+
{
20+
assert(num_chans == 1 && dma2d_chans && user_config);
21+
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)user_config;
22+
assert(trans_on_picked_desc->trigger_periph == DMA2D_TRIG_PERIPH_PPA_BLEND && trans_on_picked_desc->fill_desc && trans_on_picked_desc->ppa_engine);
23+
24+
ppa_fill_oper_t *fill_trans_desc = (ppa_fill_oper_t *)trans_on_picked_desc->fill_desc;
25+
ppa_blend_engine_t *blend_engine = __containerof(trans_on_picked_desc->ppa_engine, ppa_blend_engine_t, base);
26+
ppa_platform_t *platform = blend_engine->base.platform;
27+
28+
// Reset blending engine
29+
ppa_ll_blend_reset(platform->hal.dev);
30+
31+
// Get the required 2D-DMA channel handles
32+
assert(dma2d_chans[0].dir == DMA2D_CHANNEL_DIRECTION_RX);
33+
dma2d_channel_handle_t dma2d_rx_chan = dma2d_chans[0].chan;
34+
35+
color_space_pixel_format_t out_pixel_format = {
36+
.color_type_id = fill_trans_desc->out.fill_cm,
37+
};
38+
39+
// Fill 2D-DMA descriptors
40+
blend_engine->dma_rx_desc->vb_size = fill_trans_desc->fill_block_h;
41+
blend_engine->dma_rx_desc->hb_length = fill_trans_desc->fill_block_w;
42+
blend_engine->dma_rx_desc->err_eof = 0;
43+
blend_engine->dma_rx_desc->dma2d_en = 1;
44+
blend_engine->dma_rx_desc->suc_eof = 1;
45+
blend_engine->dma_rx_desc->owner = DMA2D_DESCRIPTOR_BUFFER_OWNER_DMA;
46+
blend_engine->dma_rx_desc->va_size = fill_trans_desc->out.pic_h;
47+
blend_engine->dma_rx_desc->ha_length = fill_trans_desc->out.pic_w;
48+
blend_engine->dma_rx_desc->pbyte = dma2d_desc_pixel_format_to_pbyte_value(out_pixel_format);
49+
blend_engine->dma_rx_desc->y = fill_trans_desc->out.block_offset_y;
50+
blend_engine->dma_rx_desc->x = fill_trans_desc->out.block_offset_x;
51+
blend_engine->dma_rx_desc->mode = DMA2D_DESCRIPTOR_BLOCK_RW_MODE_SINGLE;
52+
blend_engine->dma_rx_desc->buffer = (void *)fill_trans_desc->out.buffer;
53+
blend_engine->dma_rx_desc->next = NULL;
54+
55+
esp_cache_msync((void *)blend_engine->dma_rx_desc, platform->dma_desc_mem_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
56+
57+
// Configure 2D-DMA channels
58+
dma2d_trigger_t trig_periph = {
59+
.periph = DMA2D_TRIG_PERIPH_PPA_BLEND,
60+
.periph_sel_id = SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_RX,
61+
};
62+
dma2d_connect(dma2d_rx_chan, &trig_periph);
63+
64+
dma2d_transfer_ability_t dma_transfer_ability = {
65+
.data_burst_length = fill_trans_desc->data_burst_length,
66+
.desc_burst_en = true,
67+
.mb_size = DMA2D_MACRO_BLOCK_SIZE_NONE,
68+
};
69+
dma2d_set_transfer_ability(dma2d_rx_chan, &dma_transfer_ability);
70+
71+
dma2d_rx_event_callbacks_t dma_event_cbs = {
72+
.on_recv_eof = ppa_transaction_done_cb,
73+
};
74+
dma2d_register_rx_event_callbacks(dma2d_rx_chan, &dma_event_cbs, (void *)trans_on_picked_desc->trans_elm);
75+
76+
dma2d_set_desc_addr(dma2d_rx_chan, (intptr_t)blend_engine->dma_rx_desc);
77+
dma2d_start(dma2d_rx_chan);
78+
79+
// Configure PPA Blending engine
80+
ppa_ll_blend_configure_filling_block(platform->hal.dev, &fill_trans_desc->fill_argb_color, fill_trans_desc->fill_block_w, fill_trans_desc->fill_block_h);
81+
ppa_ll_blend_set_tx_color_mode(platform->hal.dev, fill_trans_desc->out.fill_cm);
82+
83+
ppa_ll_blend_start(platform->hal.dev, PPA_LL_BLEND_TRANS_MODE_FILL);
84+
85+
// No need to yield
86+
return false;
87+
}
88+
89+
esp_err_t ppa_do_fill(ppa_client_handle_t ppa_client, const ppa_fill_oper_config_t *config)
90+
{
91+
ESP_RETURN_ON_FALSE(ppa_client && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
92+
ESP_RETURN_ON_FALSE(ppa_client->oper_type == PPA_OPERATION_FILL, ESP_ERR_INVALID_ARG, TAG, "client is not for fill operations");
93+
ESP_RETURN_ON_FALSE(config->mode <= PPA_TRANS_MODE_NON_BLOCKING, ESP_ERR_INVALID_ARG, TAG, "invalid mode");
94+
// out_buffer ptr cannot in flash region
95+
ESP_RETURN_ON_FALSE(esp_ptr_internal(config->out.buffer) || esp_ptr_external_ram(config->out.buffer), ESP_ERR_INVALID_ARG, TAG, "invalid out.buffer addr");
96+
uint32_t buf_alignment_size = (uint32_t)ppa_client->engine->platform->buf_alignment_size;
97+
ESP_RETURN_ON_FALSE(((uint32_t)config->out.buffer & (buf_alignment_size - 1)) == 0 && (config->out.buffer_size & (buf_alignment_size - 1)) == 0,
98+
ESP_ERR_INVALID_ARG, TAG, "out.buffer addr or out.buffer_size not aligned to cache line size");
99+
color_space_pixel_format_t out_pixel_format = {
100+
.color_type_id = config->out.fill_cm,
101+
};
102+
uint32_t out_pixel_depth = color_hal_pixel_format_get_bit_depth(out_pixel_format);
103+
uint32_t out_pic_len = config->out.pic_w * config->out.pic_h * out_pixel_depth / 8;
104+
ESP_RETURN_ON_FALSE(out_pic_len <= config->out.buffer_size, ESP_ERR_INVALID_ARG, TAG, "out.pic_w/h mismatch with out.buffer_size");
105+
// To reduce complexity, color_mode, fill_block_w/h correctness are checked in their corresponding LL functions
106+
107+
// Write back and invalidate necessary data (note that the window content is not continuous in the buffer)
108+
// Write back and invalidate buffer extended window (alignment not necessary on C2M direction, but alignment strict on M2C direction)
109+
uint32_t out_ext_window = (uint32_t)config->out.buffer + config->out.block_offset_y * config->out.pic_w * out_pixel_depth / 8;
110+
uint32_t out_ext_window_len = config->out.pic_w * config->fill_block_h * out_pixel_depth / 8;
111+
esp_cache_msync((void *)PPA_ALIGN_DOWN(out_ext_window, buf_alignment_size), PPA_ALIGN_UP(out_ext_window_len, buf_alignment_size), ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
112+
113+
esp_err_t ret = ESP_OK;
114+
ppa_trans_t *trans_elm = NULL;
115+
if (xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0)) {
116+
dma2d_trans_config_t *dma_trans_desc = trans_elm->trans_desc;
117+
118+
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = dma_trans_desc->user_config;
119+
120+
ppa_fill_oper_t *fill_trans_desc = (ppa_fill_oper_t *)trans_on_picked_desc->fill_desc;
121+
memcpy(fill_trans_desc, config, sizeof(ppa_fill_oper_config_t));
122+
fill_trans_desc->data_burst_length = ppa_client->data_burst_length;
123+
124+
trans_on_picked_desc->ppa_engine = ppa_client->engine;
125+
trans_on_picked_desc->trigger_periph = DMA2D_TRIG_PERIPH_PPA_BLEND;
126+
127+
dma_trans_desc->tx_channel_num = 0;
128+
dma_trans_desc->rx_channel_num = 1;
129+
dma_trans_desc->channel_flags = 0;
130+
dma_trans_desc->specified_tx_channel_mask = 0;
131+
dma_trans_desc->specified_rx_channel_mask = 0;
132+
133+
trans_elm->client = ppa_client;
134+
trans_elm->user_data = config->user_data;
135+
xSemaphoreTake(trans_elm->sem, 0); // Ensure no transaction semaphore before transaction starts
136+
137+
ret = ppa_do_operation(ppa_client, ppa_client->engine, trans_elm, config->mode);
138+
if (ret != ESP_OK) {
139+
ppa_recycle_transaction(ppa_client, trans_elm);
140+
}
141+
} else {
142+
ret = ESP_FAIL;
143+
ESP_LOGE(TAG, "exceed maximum pending transactions for the client, consider increase max_pending_trans_num");
144+
}
145+
return ret;
146+
}
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#pragma once
8+
9+
#include <stdint.h>
10+
#include <sys/queue.h>
11+
#include "sdkconfig.h"
12+
#include "driver/ppa.h"
13+
#include "freertos/FreeRTOS.h"
14+
#include "freertos/semphr.h"
15+
#include "esp_private/dma2d.h"
16+
#include "hal/dma2d_types.h"
17+
#include "hal/ppa_types.h"
18+
#include "hal/ppa_hal.h"
19+
#include "esp_pm.h"
20+
21+
#ifdef __cplusplus
22+
extern "C" {
23+
#endif
24+
25+
#define PPA_MEM_ALLOC_CAPS (MALLOC_CAP_DEFAULT)
26+
27+
#define PPA_PM_LOCK_NAME_LEN_MAX 16
28+
29+
#define PPA_CHECK_CM_SUPPORT_BYTE_SWAP(str, color_type_id) \
30+
ESP_RETURN_ON_FALSE(color_type_id == COLOR_TYPE_ID(COLOR_SPACE_ARGB, COLOR_PIXEL_ARGB8888) || color_type_id == COLOR_TYPE_ID(COLOR_SPACE_RGB, COLOR_PIXEL_RGB565), \
31+
ESP_ERR_INVALID_ARG, TAG, str "_cm does not support byte_swap");
32+
33+
#define PPA_CHECK_CM_SUPPORT_RGB_SWAP(str, color_type_id) \
34+
ESP_RETURN_ON_FALSE(COLOR_SPACE_TYPE(color_type_id) == COLOR_SPACE_ARGB || COLOR_SPACE_TYPE(color_type_id) == COLOR_SPACE_RGB, \
35+
ESP_ERR_INVALID_ARG, TAG, str "_cm does not support rgb_swap");
36+
37+
#define PPA_ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
38+
#define PPA_ALIGN_DOWN(num, align) ((num) & ~((align) - 1))
39+
40+
typedef struct ppa_platform_t ppa_platform_t;
41+
42+
/******************************** ENGINE *************************************/
43+
// PPA module contains SRM engine and Blending engine
44+
45+
typedef struct ppa_engine_t ppa_engine_t;
46+
47+
struct ppa_engine_t {
48+
ppa_platform_t *platform; // PPA driver platform
49+
ppa_engine_type_t type; // Type of the PPA engine
50+
portMUX_TYPE spinlock; // Engine level spinlock
51+
SemaphoreHandle_t sem; // Semaphore for whether the engine is processing a transaction
52+
STAILQ_HEAD(trans, ppa_trans_s) trans_stailq; // link head of pending transactions for the PPA engine
53+
#if CONFIG_PM_ENABLE
54+
esp_pm_lock_handle_t pm_lock; // Power management lock
55+
#endif
56+
};
57+
58+
typedef struct ppa_srm_engine_t {
59+
ppa_engine_t base; // PPA engine base structure
60+
dma2d_descriptor_t *dma_tx_desc; // Into PPA SRM engine direction 2D-DMA descriptor
61+
dma2d_descriptor_t *dma_rx_desc; // Out from PPA SRM engine direction 2D-DMA descriptor
62+
} ppa_srm_engine_t;
63+
64+
typedef struct ppa_blend_engine_t {
65+
ppa_engine_t base; // PPA engine base structure
66+
dma2d_descriptor_t *dma_tx_bg_desc; // Into PPA Blending engine direction background channel 2D-DMA descriptor
67+
dma2d_descriptor_t *dma_tx_fg_desc; // Into PPA Blending engine direction foreground channel 2D-DMA descriptor
68+
dma2d_descriptor_t *dma_rx_desc; // Out from PPA blending engine direction 2D-DMA descriptor
69+
} ppa_blend_engine_t;
70+
71+
typedef struct {
72+
ppa_engine_type_t engine; // Engine type
73+
} ppa_engine_config_t;
74+
75+
/******************************** CLIENT *************************************/
76+
77+
typedef struct ppa_client_t ppa_client_t;
78+
79+
struct ppa_client_t {
80+
ppa_operation_t oper_type; // The PPA operation type that the client wants to do in speciality
81+
ppa_engine_t *engine; // Pointer to the PPA engine that in charge of performing the PPA operation
82+
uint32_t trans_cnt; // Number of pending PPA transactions
83+
portMUX_TYPE spinlock; // Client level spinlock
84+
ppa_event_callback_t done_cb; // Transaction done callback
85+
QueueHandle_t trans_elm_ptr_queue; // Queue that contains the pointers to the allocated memory to save the transaction contexts
86+
ppa_data_burst_length_t data_burst_length; // The desired data burst length for all the transactions of the client
87+
};
88+
89+
/****************************** OPERATION ************************************/
90+
91+
// The elements in this structure listed first are identical to the elements in structure `ppa_srm_oper_config_t`
92+
// With adding a few extra elements at the end
93+
// This allows memcpy
94+
typedef struct {
95+
ppa_in_pic_blk_config_t in;
96+
ppa_out_pic_blk_config_t out;
97+
98+
// scale-rotate-mirror manipulation
99+
ppa_srm_rotation_angle_t rotation_angle;
100+
float scale_x;
101+
float scale_y;
102+
bool mirror_x;
103+
bool mirror_y;
104+
105+
// input data manipulation
106+
bool rgb_swap;
107+
bool byte_swap;
108+
ppa_alpha_update_mode_t alpha_update_mode;
109+
union {
110+
uint32_t alpha_fix_val;
111+
float alpha_scale_ratio;
112+
};
113+
114+
ppa_trans_mode_t mode;
115+
void *user_data;
116+
117+
uint32_t scale_x_int; // Calculation result for the integral part of the scale_x to be directly written to register
118+
uint32_t scale_x_frag; // Calculation result for the fractional part of the scale_x to be directly written to register
119+
uint32_t scale_y_int; // Calculation result for the integral part of the scale_y to be directly written to register
120+
uint32_t scale_y_frag; // Calculation result for the fractional part of the scale_y to be directly written to register
121+
uint32_t alpha_value; // Calculation result for the fix alpha value to be directly written to register
122+
ppa_data_burst_length_t data_burst_length; // Data burst length for the transaction, information passed from the client
123+
} ppa_srm_oper_t;
124+
125+
// The elements in this structure listed first are identical to the elements in structure `ppa_blend_oper_config_t`
126+
// With adding a few extra elements at the end
127+
// This allows memcpy
128+
typedef struct {
129+
ppa_in_pic_blk_config_t in_bg;
130+
ppa_in_pic_blk_config_t in_fg;
131+
ppa_out_pic_blk_config_t out;
132+
133+
// input data manipulation
134+
bool bg_rgb_swap;
135+
bool bg_byte_swap;
136+
ppa_alpha_update_mode_t bg_alpha_update_mode;
137+
union {
138+
uint32_t bg_alpha_fix_val;
139+
float bg_alpha_scale_ratio;
140+
};
141+
bool fg_rgb_swap;
142+
bool fg_byte_swap;
143+
ppa_alpha_update_mode_t fg_alpha_update_mode;
144+
union {
145+
uint32_t fg_alpha_fix_val;
146+
float fg_alpha_scale_ratio;
147+
};
148+
color_pixel_rgb888_data_t fg_fix_rgb_val;
149+
150+
// color-keying
151+
bool bg_ck_en;
152+
color_pixel_rgb888_data_t bg_ck_rgb_low_thres;
153+
color_pixel_rgb888_data_t bg_ck_rgb_high_thres;
154+
bool fg_ck_en;
155+
color_pixel_rgb888_data_t fg_ck_rgb_low_thres;
156+
color_pixel_rgb888_data_t fg_ck_rgb_high_thres;
157+
color_pixel_rgb888_data_t ck_rgb_default_val;
158+
bool ck_reverse_bg2fg;
159+
160+
ppa_trans_mode_t mode;
161+
void *user_data;
162+
163+
uint32_t bg_alpha_value; // Calculation result for the fix alpha value for BG to be directly written to register
164+
uint32_t fg_alpha_value; // Calculation result for the fix alpha value for FG to be directly written to register
165+
ppa_data_burst_length_t data_burst_length; // Data burst length for the transaction, information passed from the client
166+
} ppa_blend_oper_t;
167+
168+
// The elements in this structure listed first are identical to the elements in structure `ppa_fill_oper_config_t`
169+
// With adding a few extra elements at the end
170+
// This allows memcpy
171+
typedef struct {
172+
ppa_out_pic_blk_config_t out;
173+
174+
uint32_t fill_block_w;
175+
uint32_t fill_block_h;
176+
color_pixel_argb8888_data_t fill_argb_color;
177+
178+
ppa_trans_mode_t mode;
179+
void *user_data;
180+
181+
ppa_data_burst_length_t data_burst_length; // Data burst length for the transaction, information passed from the client
182+
} ppa_fill_oper_t;
183+
184+
/***************************** TRANSACTION ***********************************/
185+
186+
// PPA transaction element
187+
typedef struct ppa_trans_s {
188+
STAILQ_ENTRY(ppa_trans_s) entry; // Link entry
189+
dma2d_trans_config_t *trans_desc; // Pointer to the structure containing the configurations for a 2D-DMA transaction
190+
dma2d_trans_t *dma_trans_placeholder; // Pointer to the memory to store the 2D-DMA transaction context
191+
SemaphoreHandle_t sem; // Semaphore to block when the transaction has not finished
192+
ppa_client_t *client; // Pointer to the client who requested the transaction
193+
void *user_data; // User registered event data (per transaction)
194+
} ppa_trans_t;
195+
196+
typedef struct {
197+
union {
198+
ppa_srm_oper_t *srm_desc; // Pointer to the structure containing the configurations for a PPA SRM operation transaction
199+
ppa_blend_oper_t *blend_desc; // Pointer to the structure containing the configurations for a PPA blend operation transaction
200+
ppa_fill_oper_t *fill_desc; // Pointer to the structure containing the configurations for a PPA fill operation transaction
201+
void *op_desc; // General pointer to the structure containing the configurations for a PPA transaction
202+
};
203+
ppa_engine_t *ppa_engine; // Pointer to the PPA engine
204+
ppa_trans_t *trans_elm; // Pointer to the PPA transaction element
205+
dma2d_trigger_peripheral_t trigger_periph; // The 2D-DMA trigger peripheral
206+
} ppa_dma2d_trans_on_picked_config_t;
207+
208+
bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config);
209+
bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config);
210+
bool ppa_fill_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config);
211+
212+
esp_err_t ppa_do_operation(ppa_client_handle_t ppa_client, ppa_engine_t *ppa_engine_base, ppa_trans_t *trans_elm, ppa_trans_mode_t mode);
213+
214+
bool ppa_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data);
215+
216+
bool ppa_recycle_transaction(ppa_client_handle_t ppa_client, ppa_trans_t *trans_elm);
217+
218+
/****************************** PPA DRIVER ***********************************/
219+
220+
struct ppa_platform_t {
221+
_lock_t mutex; // Platform level mutex lock to protect the ppa_engine_acquire/ppa_engine_release process
222+
portMUX_TYPE spinlock; // Platform level spinlock
223+
ppa_hal_context_t hal; // PPA HAL context
224+
dma2d_pool_handle_t dma2d_pool_handle; // Pointer to the acquired 2D-DMA pool
225+
ppa_srm_engine_t *srm; // Pointer to the PPA SRM engine
226+
ppa_blend_engine_t *blending; // Pointer to the PPA blending engine
227+
uint32_t srm_engine_ref_count; // Reference count used to protect PPA SRM engine acquire and release
228+
uint32_t blend_engine_ref_count; // Reference count used to protect PPA blending engine acquire and release
229+
size_t buf_alignment_size; // Alignment requirement for the outgoing buffer addr and size to satisfy cache line size
230+
uint32_t dma_desc_mem_size; // Alignment requirement for the 2D-DMA descriptor to satisfy cache line size
231+
};
232+
233+
#ifdef __cplusplus
234+
}
235+
#endif

0 commit comments

Comments
 (0)