Skip to content

Commit 1b1005a

Browse files
committed
feat(ppa): add PPA driver support for ESP32P4
1 parent 3f632df commit 1b1005a

File tree

41 files changed

+2926
-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

+2926
-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: 284 additions & 0 deletions
Large diffs are not rendered by default.

components/esp_driver_ppa/src/ppa_core.c

Lines changed: 517 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
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 buffer extended window (alignment not necessary on C2M 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 *)out_ext_window, out_ext_window_len, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED);
112+
// Invalidate out_buffer entire picture (alignment strict on M2C direction)
113+
esp_cache_msync((void *)config->out.buffer, config->out.buffer_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
114+
115+
esp_err_t ret = ESP_OK;
116+
ppa_trans_t *trans_elm = NULL;
117+
if (xQueueReceive(ppa_client->trans_elm_ptr_queue, (void *)&trans_elm, 0)) {
118+
dma2d_trans_config_t *dma_trans_desc = trans_elm->trans_desc;
119+
120+
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = dma_trans_desc->user_config;
121+
122+
ppa_fill_oper_t *fill_trans_desc = (ppa_fill_oper_t *)trans_on_picked_desc->fill_desc;
123+
memcpy(fill_trans_desc, config, sizeof(ppa_fill_oper_config_t));
124+
fill_trans_desc->data_burst_length = ppa_client->data_burst_length;
125+
126+
trans_on_picked_desc->ppa_engine = ppa_client->engine;
127+
trans_on_picked_desc->trigger_periph = DMA2D_TRIG_PERIPH_PPA_BLEND;
128+
129+
dma_trans_desc->tx_channel_num = 0;
130+
dma_trans_desc->rx_channel_num = 1;
131+
dma_trans_desc->channel_flags = 0;
132+
dma_trans_desc->specified_tx_channel_mask = 0;
133+
dma_trans_desc->specified_rx_channel_mask = 0;
134+
135+
trans_elm->client = ppa_client;
136+
trans_elm->user_data = config->user_data;
137+
xSemaphoreTake(trans_elm->sem, 0); // Ensure no transaction semaphore before transaction starts
138+
139+
ret = ppa_do_operation(ppa_client, ppa_client->engine, trans_elm, config->mode);
140+
if (ret != ESP_OK) {
141+
ppa_recycle_transaction(ppa_client, trans_elm);
142+
}
143+
} else {
144+
ret = ESP_FAIL;
145+
ESP_LOGE(TAG, "exceed maximum pending transactions for the client, consider increase max_pending_trans_num");
146+
}
147+
return ret;
148+
}
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
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+
typedef struct ppa_platform_t ppa_platform_t;
38+
39+
/******************************** ENGINE *************************************/
40+
// PPA module contains SRM engine and Blending engine
41+
42+
typedef struct ppa_engine_t ppa_engine_t;
43+
44+
struct ppa_engine_t {
45+
ppa_platform_t *platform; // PPA driver platform
46+
ppa_engine_type_t type; // Type of the PPA engine
47+
portMUX_TYPE spinlock; // Engine level spinlock
48+
SemaphoreHandle_t sem; // Semaphore for whether the engine is processing a transaction
49+
STAILQ_HEAD(trans, ppa_trans_s) trans_stailq; // link head of pending transactions for the PPA engine
50+
#if CONFIG_PM_ENABLE
51+
esp_pm_lock_handle_t pm_lock; // Power management lock
52+
#endif
53+
};
54+
55+
typedef struct ppa_srm_engine_t {
56+
ppa_engine_t base; // PPA engine base structure
57+
dma2d_descriptor_t *dma_tx_desc; // Into PPA SRM engine direction 2D-DMA descriptor
58+
dma2d_descriptor_t *dma_rx_desc; // Out from PPA SRM engine direction 2D-DMA descriptor
59+
} ppa_srm_engine_t;
60+
61+
typedef struct ppa_blend_engine_t {
62+
ppa_engine_t base; // PPA engine base structure
63+
dma2d_descriptor_t *dma_tx_bg_desc; // Into PPA Blending engine direction background channel 2D-DMA descriptor
64+
dma2d_descriptor_t *dma_tx_fg_desc; // Into PPA Blending engine direction foreground channel 2D-DMA descriptor
65+
dma2d_descriptor_t *dma_rx_desc; // Out from PPA blending engine direction 2D-DMA descriptor
66+
} ppa_blend_engine_t;
67+
68+
typedef struct {
69+
ppa_engine_type_t engine; // Engine type
70+
} ppa_engine_config_t;
71+
72+
/******************************** CLIENT *************************************/
73+
74+
typedef struct ppa_client_t ppa_client_t;
75+
76+
struct ppa_client_t {
77+
ppa_operation_t oper_type; // The PPA operation type that the client wants to do in speciality
78+
ppa_engine_t *engine; // Pointer to the PPA engine that in charge of performing the PPA operation
79+
uint32_t trans_cnt; // Number of pending PPA transactions
80+
portMUX_TYPE spinlock; // Client level spinlock
81+
ppa_event_callback_t done_cb; // Transaction done callback
82+
QueueHandle_t trans_elm_ptr_queue; // Queue that contains the pointers to the allocated memory to save the transaction contexts
83+
ppa_data_burst_length_t data_burst_length; // The desired data burst length for all the transactions of the client
84+
};
85+
86+
/****************************** OPERATION ************************************/
87+
88+
// The elements in this structure listed first are identical to the elements in structure `ppa_srm_oper_config_t`
89+
// With adding a few extra elements at the end
90+
// This allows memcpy
91+
typedef struct {
92+
ppa_in_pic_blk_config_t in;
93+
ppa_out_pic_blk_config_t out;
94+
95+
// scale-rotate-mirror manipulation
96+
ppa_srm_rotation_angle_t rotation_angle;
97+
float scale_x;
98+
float scale_y;
99+
bool mirror_x;
100+
bool mirror_y;
101+
102+
// input data manipulation
103+
bool rgb_swap;
104+
bool byte_swap;
105+
ppa_alpha_update_mode_t alpha_update_mode;
106+
union {
107+
uint32_t alpha_fix_val;
108+
float alpha_scale_ratio;
109+
};
110+
111+
ppa_trans_mode_t mode;
112+
void *user_data;
113+
114+
uint32_t scale_x_int; // Calculation result for the integral part of the scale_x to be directly written to register
115+
uint32_t scale_x_frag; // Calculation result for the fractional part of the scale_x to be directly written to register
116+
uint32_t scale_y_int; // Calculation result for the integral part of the scale_y to be directly written to register
117+
uint32_t scale_y_frag; // Calculation result for the fractional part of the scale_y to be directly written to register
118+
uint32_t alpha_value; // Calculation result for the fix alpha value to be directly written to register
119+
ppa_data_burst_length_t data_burst_length; // Data burst length for the transaction, information passed from the client
120+
} ppa_srm_oper_t;
121+
122+
// The elements in this structure listed first are identical to the elements in structure `ppa_blend_oper_config_t`
123+
// With adding a few extra elements at the end
124+
// This allows memcpy
125+
typedef struct {
126+
ppa_in_pic_blk_config_t in_bg;
127+
ppa_in_pic_blk_config_t in_fg;
128+
ppa_out_pic_blk_config_t out;
129+
130+
// input data manipulation
131+
bool bg_rgb_swap;
132+
bool bg_byte_swap;
133+
ppa_alpha_update_mode_t bg_alpha_update_mode;
134+
union {
135+
uint32_t bg_alpha_fix_val;
136+
float bg_alpha_scale_ratio;
137+
};
138+
bool fg_rgb_swap;
139+
bool fg_byte_swap;
140+
ppa_alpha_update_mode_t fg_alpha_update_mode;
141+
union {
142+
uint32_t fg_alpha_fix_val;
143+
float fg_alpha_scale_ratio;
144+
};
145+
color_pixel_rgb888_data_t fg_fix_rgb_val;
146+
147+
// color-keying
148+
bool bg_ck_en;
149+
color_pixel_rgb888_data_t bg_ck_rgb_low_thres;
150+
color_pixel_rgb888_data_t bg_ck_rgb_high_thres;
151+
bool fg_ck_en;
152+
color_pixel_rgb888_data_t fg_ck_rgb_low_thres;
153+
color_pixel_rgb888_data_t fg_ck_rgb_high_thres;
154+
color_pixel_rgb888_data_t ck_rgb_default_val;
155+
bool ck_reverse_bg2fg;
156+
157+
ppa_trans_mode_t mode;
158+
void *user_data;
159+
160+
uint32_t bg_alpha_value; // Calculation result for the fix alpha value for BG to be directly written to register
161+
uint32_t fg_alpha_value; // Calculation result for the fix alpha value for FG to be directly written to register
162+
ppa_data_burst_length_t data_burst_length; // Data burst length for the transaction, information passed from the client
163+
} ppa_blend_oper_t;
164+
165+
// The elements in this structure listed first are identical to the elements in structure `ppa_fill_oper_config_t`
166+
// With adding a few extra elements at the end
167+
// This allows memcpy
168+
typedef struct {
169+
ppa_out_pic_blk_config_t out;
170+
171+
uint32_t fill_block_w;
172+
uint32_t fill_block_h;
173+
color_pixel_argb8888_data_t fill_argb_color;
174+
175+
ppa_trans_mode_t mode;
176+
void *user_data;
177+
178+
ppa_data_burst_length_t data_burst_length; // Data burst length for the transaction, information passed from the client
179+
} ppa_fill_oper_t;
180+
181+
/***************************** TRANSACTION ***********************************/
182+
183+
// PPA transaction element
184+
typedef struct ppa_trans_s {
185+
STAILQ_ENTRY(ppa_trans_s) entry; // Link entry
186+
dma2d_trans_config_t *trans_desc; // Pointer to the structure containing the configurations for a 2D-DMA transaction
187+
dma2d_trans_t *dma_trans_placeholder; // Pointer to the memory to store the 2D-DMA transaction context
188+
SemaphoreHandle_t sem; // Semaphore to block when the transaction has not finished
189+
ppa_client_t *client; // Pointer to the client who requested the transaction
190+
void *user_data; // User registered event data (per transaction)
191+
} ppa_trans_t;
192+
193+
typedef struct {
194+
union {
195+
ppa_srm_oper_t *srm_desc; // Pointer to the structure containing the configurations for a PPA SRM operation transaction
196+
ppa_blend_oper_t *blend_desc; // Pointer to the structure containing the configurations for a PPA blend operation transaction
197+
ppa_fill_oper_t *fill_desc; // Pointer to the structure containing the configurations for a PPA fill operation transaction
198+
void *op_desc; // General pointer to the structure containing the configurations for a PPA transaction
199+
};
200+
ppa_engine_t *ppa_engine; // Pointer to the PPA engine
201+
ppa_trans_t *trans_elm; // Pointer to the PPA transaction element
202+
dma2d_trigger_peripheral_t trigger_periph; // The 2D-DMA trigger peripheral
203+
} ppa_dma2d_trans_on_picked_config_t;
204+
205+
bool ppa_srm_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config);
206+
bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config);
207+
bool ppa_fill_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config);
208+
209+
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);
210+
211+
bool ppa_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data);
212+
213+
bool ppa_recycle_transaction(ppa_client_handle_t ppa_client, ppa_trans_t *trans_elm);
214+
215+
/****************************** PPA DRIVER ***********************************/
216+
217+
struct ppa_platform_t {
218+
_lock_t mutex; // Platform level mutex lock to protect the ppa_engine_acquire/ppa_engine_release process
219+
portMUX_TYPE spinlock; // Platform level spinlock
220+
ppa_hal_context_t hal; // PPA HAL context
221+
dma2d_pool_handle_t dma2d_pool_handle; // Pointer to the acquired 2D-DMA pool
222+
ppa_srm_engine_t *srm; // Pointer to the PPA SRM engine
223+
ppa_blend_engine_t *blending; // Pointer to the PPA blending engine
224+
uint32_t srm_engine_ref_count; // Reference count used to protect PPA SRM engine acquire and release
225+
uint32_t blend_engine_ref_count; // Reference count used to protect PPA blending engine acquire and release
226+
size_t buf_alignment_size; // Alignment requirement for the outgoing buffer addr and size to satisfy cache line size
227+
uint32_t dma_desc_mem_size; // Alignment requirement for the 2D-DMA descriptor to satisfy cache line size
228+
};
229+
230+
#ifdef __cplusplus
231+
}
232+
#endif

0 commit comments

Comments
 (0)