forked from espressif/esp-idf
feat(ppa): add PPA driver support for ESP32P4
cleaned up a bit, unify to some static functions
This commit is contained in:
@ -100,6 +100,10 @@ typedef struct {
|
|||||||
color_conv_std_rgb_yuv_t yuv_std;
|
color_conv_std_rgb_yuv_t yuv_std;
|
||||||
bool rgb_swap;
|
bool rgb_swap;
|
||||||
bool byte_swap;
|
bool byte_swap;
|
||||||
|
ppa_alpha_mode_t alpha_mode;
|
||||||
|
uint32_t alpha_value; /*!< When PPA_ALPHA_FIX_VALUE mode is selected, alpha_value is the alpha value to be replaced with (output_alpha = alpha_value)
|
||||||
|
When PPA_ALPHA_SCALE mode is selected, alpha_value/256 is the multiplier to the input alpha value (output_alpha = input_alpha * alpha_value / 256)
|
||||||
|
When other alpha modes are selected, this field is not used */
|
||||||
} in_color;
|
} in_color;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@ -107,11 +111,6 @@ typedef struct {
|
|||||||
color_range_t yuv_range;
|
color_range_t yuv_range;
|
||||||
color_conv_std_rgb_yuv_t yuv_std;
|
color_conv_std_rgb_yuv_t yuv_std;
|
||||||
} out_color;
|
} out_color;
|
||||||
|
|
||||||
ppa_alpha_mode_t alpha_mode;
|
|
||||||
uint32_t alpha_value; /*!< When PPA_ALPHA_FIX_VALUE mode is selected, alpha_value is the alpha value to be replaced with (output_alpha = alpha_value)
|
|
||||||
When PPA_ALPHA_SCALE mode is selected, alpha_value/256 is the multiplier to the input alpha value (output_alpha = input_alpha * alpha_value / 256)
|
|
||||||
When other alpha modes are selected, this field is not used*/
|
|
||||||
} ppa_sr_trans_config_t;
|
} ppa_sr_trans_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -192,6 +191,7 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
esp_err_t ppa_do_blend(ppa_invoker_handle_t ppa_invoker, const ppa_blend_trans_config_t *config, ppa_trans_mode_t mode);
|
esp_err_t ppa_do_blend(ppa_invoker_handle_t ppa_invoker, const ppa_blend_trans_config_t *config, ppa_trans_mode_t mode);
|
||||||
|
|
||||||
|
// TODO: FILL
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *out_buffer;
|
void *out_buffer;
|
||||||
} ppa_fill_trans_config_t;
|
} ppa_fill_trans_config_t;
|
||||||
@ -219,8 +219,6 @@ esp_err_t ppa_do_fill(ppa_invoker_handle_t ppa_invoker, const ppa_fill_trans_con
|
|||||||
// Consider blocking and non-blocking options
|
// Consider blocking and non-blocking options
|
||||||
// Non-blocking may require notification of process done event
|
// Non-blocking may require notification of process done event
|
||||||
|
|
||||||
// dma2d done/eof callback, when/how to free dma2d transaction content
|
|
||||||
|
|
||||||
// cache writeback/invalidate
|
// cache writeback/invalidate
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
|
#include "freertos/idf_additions.h"
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "esp_cache.h"
|
#include "esp_cache.h"
|
||||||
#include "hal/cache_hal.h"
|
#include "hal/cache_hal.h"
|
||||||
@ -60,10 +61,6 @@ typedef ppa_blend_trans_config_t ppa_blend_transaction_t;
|
|||||||
|
|
||||||
typedef struct ppa_trans_s {
|
typedef struct ppa_trans_s {
|
||||||
STAILQ_ENTRY(ppa_trans_s) entry; // link entry
|
STAILQ_ENTRY(ppa_trans_s) entry; // link entry
|
||||||
// union {
|
|
||||||
// const ppa_sr_transaction_t *sr_desc;
|
|
||||||
// const ppa_blending_transaction_t *blending_desc;
|
|
||||||
// };
|
|
||||||
dma2d_trans_config_t *trans_desc;
|
dma2d_trans_config_t *trans_desc;
|
||||||
dma2d_trans_t *dma_trans_placeholder;
|
dma2d_trans_t *dma_trans_placeholder;
|
||||||
SemaphoreHandle_t sem;
|
SemaphoreHandle_t sem;
|
||||||
@ -79,10 +76,6 @@ typedef struct {
|
|||||||
ppa_engine_t *ppa_engine;
|
ppa_engine_t *ppa_engine;
|
||||||
ppa_trans_t *trans_elm;
|
ppa_trans_t *trans_elm;
|
||||||
dma2d_trigger_peripheral_t trigger_periph;
|
dma2d_trigger_peripheral_t trigger_periph;
|
||||||
// dma2d_csc_config_t
|
|
||||||
// dma2d_strategy_config_t *dma_strategy;
|
|
||||||
// dma2d_transfer_ability_t *dma_transfer_ability;
|
|
||||||
// dma2d_rx_event_callbacks_t *event_cbs;
|
|
||||||
} ppa_dma2d_trans_on_picked_config_t;
|
} ppa_dma2d_trans_on_picked_config_t;
|
||||||
|
|
||||||
struct ppa_engine_t {
|
struct ppa_engine_t {
|
||||||
@ -120,8 +113,11 @@ struct ppa_invoker_t {
|
|||||||
// user_data
|
// user_data
|
||||||
};
|
};
|
||||||
|
|
||||||
// how to free and how to push next trans into dma2d queue after engine is free (callback triggered)
|
typedef enum {
|
||||||
//
|
PPA_OPERATION_SR,
|
||||||
|
PPA_OPERATION_BLEND,
|
||||||
|
PPA_OPERATION_FILL,
|
||||||
|
} ppa_operation_t;
|
||||||
|
|
||||||
typedef struct ppa_platform_t {
|
typedef struct ppa_platform_t {
|
||||||
_lock_t mutex; // platform level mutex lock to protect the ppa_module_acquire/ppa_module_release process
|
_lock_t mutex; // platform level mutex lock to protect the ppa_module_acquire/ppa_module_release process
|
||||||
@ -148,6 +144,20 @@ typedef struct {
|
|||||||
|
|
||||||
static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engine_t **ret_engine);
|
static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engine_t **ret_engine);
|
||||||
static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine);
|
static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine);
|
||||||
|
static bool ppa_sr_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config);
|
||||||
|
static bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config);
|
||||||
|
|
||||||
|
extern uint32_t dma2d_tx_channel_reserved_mask[SOC_DMA2D_GROUPS];
|
||||||
|
extern uint32_t dma2d_rx_channel_reserved_mask[SOC_DMA2D_GROUPS];
|
||||||
|
static uint32_t ppa_specified_tx_channel_mask = 0;
|
||||||
|
static uint32_t ppa_specified_rx_channel_mask = 0;
|
||||||
|
static __attribute__((constructor)) void ppa_reserve_dma2d_channels(void)
|
||||||
|
{
|
||||||
|
// ppa_specified_tx_channel_mask = 1 << 0;
|
||||||
|
// ppa_specified_rx_channel_mask = 1 << 0;
|
||||||
|
dma2d_tx_channel_reserved_mask[0] |= ppa_specified_tx_channel_mask;
|
||||||
|
dma2d_rx_channel_reserved_mask[0] |= ppa_specified_rx_channel_mask;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: acquire pm_lock?
|
// TODO: acquire pm_lock?
|
||||||
static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engine_t **ret_engine)
|
static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engine_t **ret_engine)
|
||||||
@ -169,7 +179,7 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin
|
|||||||
if (config->engine == PPA_ENGINE_TYPE_SR) {
|
if (config->engine == PPA_ENGINE_TYPE_SR) {
|
||||||
if (!s_platform.sr) {
|
if (!s_platform.sr) {
|
||||||
ppa_sr_engine_t *sr_engine = heap_caps_calloc(1, sizeof(ppa_sr_engine_t), PPA_MEM_ALLOC_CAPS);
|
ppa_sr_engine_t *sr_engine = heap_caps_calloc(1, sizeof(ppa_sr_engine_t), PPA_MEM_ALLOC_CAPS);
|
||||||
SemaphoreHandle_t sr_sem = xSemaphoreCreateBinary();
|
SemaphoreHandle_t sr_sem = xSemaphoreCreateBinaryWithCaps(PPA_MEM_ALLOC_CAPS);
|
||||||
dma2d_descriptor_t *sr_tx_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
dma2d_descriptor_t *sr_tx_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
||||||
dma2d_descriptor_t *sr_rx_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
dma2d_descriptor_t *sr_rx_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
||||||
if (sr_engine && sr_sem && sr_tx_dma_desc && sr_rx_dma_desc) {
|
if (sr_engine && sr_sem && sr_tx_dma_desc && sr_rx_dma_desc) {
|
||||||
@ -190,7 +200,7 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin
|
|||||||
ESP_LOGE(TAG, "no mem to register PPA SR engine");
|
ESP_LOGE(TAG, "no mem to register PPA SR engine");
|
||||||
free(sr_engine);
|
free(sr_engine);
|
||||||
if (sr_sem) {
|
if (sr_sem) {
|
||||||
vSemaphoreDelete(sr_sem);
|
vSemaphoreDeleteWithCaps(sr_sem);
|
||||||
}
|
}
|
||||||
free(sr_tx_dma_desc);
|
free(sr_tx_dma_desc);
|
||||||
free(sr_rx_dma_desc);
|
free(sr_rx_dma_desc);
|
||||||
@ -203,7 +213,7 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin
|
|||||||
} else if (config->engine == PPA_ENGINE_TYPE_BLEND) {
|
} else if (config->engine == PPA_ENGINE_TYPE_BLEND) {
|
||||||
if (!s_platform.blending) {
|
if (!s_platform.blending) {
|
||||||
ppa_blend_engine_t *blending_engine = heap_caps_calloc(1, sizeof(ppa_blend_engine_t), PPA_MEM_ALLOC_CAPS);
|
ppa_blend_engine_t *blending_engine = heap_caps_calloc(1, sizeof(ppa_blend_engine_t), PPA_MEM_ALLOC_CAPS);
|
||||||
SemaphoreHandle_t blending_sem = xSemaphoreCreateBinary();
|
SemaphoreHandle_t blending_sem = xSemaphoreCreateBinaryWithCaps(PPA_MEM_ALLOC_CAPS);
|
||||||
dma2d_descriptor_t *blending_tx_bg_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
dma2d_descriptor_t *blending_tx_bg_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
||||||
dma2d_descriptor_t *blending_tx_fg_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
dma2d_descriptor_t *blending_tx_fg_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
||||||
dma2d_descriptor_t *blending_rx_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
dma2d_descriptor_t *blending_rx_dma_desc = (dma2d_descriptor_t *)heap_caps_aligned_calloc(alignment, 1, s_platform.dma_desc_mem_size, MALLOC_CAP_DMA | PPA_MEM_ALLOC_CAPS);
|
||||||
@ -226,7 +236,7 @@ static esp_err_t ppa_engine_acquire(const ppa_engine_config_t *config, ppa_engin
|
|||||||
ESP_LOGE(TAG, "no mem to register PPA Blending engine");
|
ESP_LOGE(TAG, "no mem to register PPA Blending engine");
|
||||||
free(blending_engine);
|
free(blending_engine);
|
||||||
if (blending_sem) {
|
if (blending_sem) {
|
||||||
vSemaphoreDelete(blending_sem);
|
vSemaphoreDeleteWithCaps(blending_sem);
|
||||||
}
|
}
|
||||||
free(blending_tx_bg_dma_desc);
|
free(blending_tx_bg_dma_desc);
|
||||||
free(blending_tx_fg_dma_desc);
|
free(blending_tx_fg_dma_desc);
|
||||||
@ -291,7 +301,7 @@ static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine)
|
|||||||
s_platform.sr = NULL;
|
s_platform.sr = NULL;
|
||||||
free(sr_engine->dma_tx_desc);
|
free(sr_engine->dma_tx_desc);
|
||||||
free(sr_engine->dma_rx_desc);
|
free(sr_engine->dma_rx_desc);
|
||||||
vSemaphoreDelete(sr_engine->base.sem);
|
vSemaphoreDeleteWithCaps(sr_engine->base.sem);
|
||||||
free(sr_engine);
|
free(sr_engine);
|
||||||
}
|
}
|
||||||
} else if (ppa_engine->type == PPA_ENGINE_TYPE_BLEND) {
|
} else if (ppa_engine->type == PPA_ENGINE_TYPE_BLEND) {
|
||||||
@ -310,7 +320,7 @@ static esp_err_t ppa_engine_release(ppa_engine_t *ppa_engine)
|
|||||||
free(blending_engine->dma_tx_bg_desc);
|
free(blending_engine->dma_tx_bg_desc);
|
||||||
free(blending_engine->dma_tx_fg_desc);
|
free(blending_engine->dma_tx_fg_desc);
|
||||||
free(blending_engine->dma_rx_desc);
|
free(blending_engine->dma_rx_desc);
|
||||||
vSemaphoreDelete(blending_engine->base.sem);
|
vSemaphoreDeleteWithCaps(blending_engine->base.sem);
|
||||||
free(blending_engine);
|
free(blending_engine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -694,38 +704,139 @@ static void ppa_recycle_transaction(ppa_trans_t *trans_elm)
|
|||||||
free(trans_elm->trans_desc);
|
free(trans_elm->trans_desc);
|
||||||
}
|
}
|
||||||
if (trans_elm->sem) {
|
if (trans_elm->sem) {
|
||||||
vSemaphoreDelete(trans_elm->sem);
|
vSemaphoreDeleteWithCaps(trans_elm->sem);
|
||||||
}
|
}
|
||||||
free(trans_elm);
|
free(trans_elm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ppa_sr_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data)
|
static esp_err_t ppa_do_operation(ppa_invoker_handle_t ppa_invoker, ppa_engine_t *ppa_engine_base, ppa_operation_t ppa_operation, const void *config, ppa_trans_mode_t mode)
|
||||||
|
{
|
||||||
|
esp_err_t ret = ESP_OK;
|
||||||
|
ppa_engine_type_t engine_type = ppa_engine_base->type;
|
||||||
|
|
||||||
|
ppa_trans_t *new_trans_elm = (ppa_trans_t *)heap_caps_calloc(1, sizeof(ppa_trans_t), PPA_MEM_ALLOC_CAPS);
|
||||||
|
dma2d_trans_t *dma_trans_elm = (dma2d_trans_t *)heap_caps_calloc(1, SIZEOF_DMA2D_TRANS_T, PPA_MEM_ALLOC_CAPS);
|
||||||
|
dma2d_trans_config_t *dma_trans_desc = (dma2d_trans_config_t *)heap_caps_calloc(1, sizeof(dma2d_trans_config_t), PPA_MEM_ALLOC_CAPS);
|
||||||
|
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)heap_caps_calloc(1, sizeof(ppa_dma2d_trans_on_picked_config_t), PPA_MEM_ALLOC_CAPS);
|
||||||
|
size_t ppa_trans_desc_size = (ppa_operation == PPA_OPERATION_SR) ? sizeof(ppa_sr_transaction_t) :
|
||||||
|
(ppa_operation == PPA_OPERATION_BLEND) ? sizeof(ppa_blend_transaction_t) : 0;
|
||||||
|
assert(ppa_trans_desc_size != 0);
|
||||||
|
void *ppa_trans_desc = heap_caps_calloc(1, ppa_trans_desc_size, PPA_MEM_ALLOC_CAPS);
|
||||||
|
ESP_GOTO_ON_FALSE(new_trans_elm && dma_trans_elm && dma_trans_desc && trans_on_picked_desc && ppa_trans_desc, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction storage");
|
||||||
|
if (mode == PPA_TRANS_MODE_BLOCKING) {
|
||||||
|
new_trans_elm->sem = xSemaphoreCreateBinaryWithCaps(PPA_MEM_ALLOC_CAPS);
|
||||||
|
ESP_GOTO_ON_FALSE(new_trans_elm->sem, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction storage");
|
||||||
|
}
|
||||||
|
memcpy(ppa_trans_desc, config, ppa_trans_desc_size);
|
||||||
|
|
||||||
|
trans_on_picked_desc->blend_desc = ppa_trans_desc;
|
||||||
|
trans_on_picked_desc->ppa_engine = ppa_engine_base;
|
||||||
|
trans_on_picked_desc->trans_elm = new_trans_elm;
|
||||||
|
trans_on_picked_desc->trigger_periph = (engine_type == PPA_ENGINE_TYPE_SR) ? DMA2D_TRIG_PERIPH_PPA_SR : DMA2D_TRIG_PERIPH_PPA_BLEND;
|
||||||
|
|
||||||
|
dma_trans_desc->tx_channel_num = (ppa_operation == PPA_OPERATION_SR) ? 1 :
|
||||||
|
(ppa_operation == PPA_OPERATION_BLEND) ? 2 : 0;
|
||||||
|
dma_trans_desc->rx_channel_num = 1;
|
||||||
|
if (ppa_operation == PPA_OPERATION_SR) {
|
||||||
|
dma_trans_desc->specified_tx_channel_mask = ppa_specified_tx_channel_mask;
|
||||||
|
dma_trans_desc->specified_rx_channel_mask = ppa_specified_rx_channel_mask;
|
||||||
|
}
|
||||||
|
dma_trans_desc->user_config = (void *)trans_on_picked_desc;
|
||||||
|
dma_trans_desc->on_job_picked = (ppa_operation == PPA_OPERATION_SR) ? ppa_sr_transaction_on_picked :
|
||||||
|
(ppa_operation == PPA_OPERATION_BLEND) ? ppa_blend_transaction_on_picked : NULL;
|
||||||
|
|
||||||
|
new_trans_elm->trans_desc = dma_trans_desc;
|
||||||
|
new_trans_elm->dma_trans_placeholder = dma_trans_elm;
|
||||||
|
new_trans_elm->invoker = ppa_invoker;
|
||||||
|
|
||||||
|
portENTER_CRITICAL(&ppa_invoker->spinlock);
|
||||||
|
if (ppa_invoker->in_accepting_trans_state) {
|
||||||
|
// Send transaction into PPA engine queue
|
||||||
|
STAILQ_INSERT_TAIL(&ppa_engine_base->trans_stailq, new_trans_elm, entry);
|
||||||
|
if (engine_type == PPA_ENGINE_TYPE_SR) {
|
||||||
|
ppa_invoker->sr_trans_cnt++;
|
||||||
|
} else {
|
||||||
|
ppa_invoker->blending_trans_cnt++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = ESP_FAIL;
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&ppa_invoker->spinlock);
|
||||||
|
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "The invoker cannot accept transaction now");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
TickType_t ticks_to_wait = (mode == PPA_TRANS_MODE_NON_BLOCKING) ? 0 : portMAX_DELAY;
|
||||||
|
if (xSemaphoreTake(ppa_engine_base->sem, ticks_to_wait) == pdTRUE) {
|
||||||
|
// Check if the transaction has already been started from the ISR
|
||||||
|
// If so, then the transaction should have been removed from queue at this moment (transaction completed)
|
||||||
|
bool found = false;
|
||||||
|
ppa_trans_t *temp = NULL;
|
||||||
|
portENTER_CRITICAL(&ppa_engine_base->spinlock);
|
||||||
|
STAILQ_FOREACH(temp, &ppa_engine_base->trans_stailq, entry) {
|
||||||
|
if (temp == new_trans_elm) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
portEXIT_CRITICAL(&ppa_engine_base->spinlock);
|
||||||
|
if (found) {
|
||||||
|
ret = ppa_dma2d_enqueue(new_trans_elm);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
portENTER_CRITICAL(&ppa_engine_base->spinlock);
|
||||||
|
STAILQ_REMOVE(&ppa_engine_base->trans_stailq, new_trans_elm, ppa_trans_s, entry);
|
||||||
|
portEXIT_CRITICAL(&ppa_engine_base->spinlock);
|
||||||
|
xSemaphoreGive(ppa_engine_base->sem);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
xSemaphoreGive(ppa_engine_base->sem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == PPA_TRANS_MODE_BLOCKING) {
|
||||||
|
// while (1) {
|
||||||
|
// printf("ppa intr: %ld\n", PPA.int_raw.val);
|
||||||
|
// }
|
||||||
|
xSemaphoreTake(new_trans_elm->sem, portMAX_DELAY); // Given in the ISR
|
||||||
|
// Sanity check new_trans_elm not in trans_stailq anymore? (loop takes time tho)
|
||||||
|
ppa_recycle_transaction(new_trans_elm);
|
||||||
|
}
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ppa_recycle_transaction(new_trans_elm);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ppa_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data)
|
||||||
{
|
{
|
||||||
bool need_yield = false;
|
bool need_yield = false;
|
||||||
BaseType_t HPTaskAwoken;
|
BaseType_t HPTaskAwoken;
|
||||||
ppa_trans_t *trans_elm = (ppa_trans_t *)user_data;
|
ppa_trans_t *trans_elm = (ppa_trans_t *)user_data;
|
||||||
ppa_invoker_t *invoker = trans_elm->invoker;
|
ppa_invoker_t *invoker = trans_elm->invoker;
|
||||||
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)trans_elm->trans_desc->user_config;
|
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)trans_elm->trans_desc->user_config;
|
||||||
assert(trans_on_picked_desc->trigger_periph == DMA2D_TRIG_PERIPH_PPA_SR);
|
ppa_engine_t *engine_base = trans_on_picked_desc->ppa_engine;
|
||||||
ppa_sr_engine_t *sr_engine = __containerof(trans_on_picked_desc->ppa_engine, ppa_sr_engine_t, base);
|
ppa_engine_type_t engine_type = engine_base->type;
|
||||||
|
|
||||||
ppa_trans_t *next_start_trans = NULL;
|
ppa_trans_t *next_start_trans = NULL;
|
||||||
portENTER_CRITICAL_ISR(&sr_engine->base.spinlock);
|
portENTER_CRITICAL_ISR(&engine_base->spinlock);
|
||||||
// Remove this transaction from transaction queue
|
// Remove this transaction from transaction queue
|
||||||
STAILQ_REMOVE(&sr_engine->base.trans_stailq, trans_elm, ppa_trans_s, entry);
|
STAILQ_REMOVE(&engine_base->trans_stailq, trans_elm, ppa_trans_s, entry);
|
||||||
next_start_trans = STAILQ_FIRST(&sr_engine->base.trans_stailq);
|
next_start_trans = STAILQ_FIRST(&engine_base->trans_stailq);
|
||||||
portEXIT_CRITICAL_ISR(&sr_engine->base.spinlock);
|
portEXIT_CRITICAL_ISR(&engine_base->spinlock);
|
||||||
|
|
||||||
// If there is next trans in PPA engine queue, send it to DMA queue; otherwise, release the engine semaphore
|
// If there is next trans in PPA engine queue, send it to DMA queue; otherwise, release the engine semaphore
|
||||||
if (next_start_trans) {
|
if (next_start_trans) {
|
||||||
esp_rom_printf("from ISR -");
|
|
||||||
ppa_dma2d_enqueue(next_start_trans);
|
ppa_dma2d_enqueue(next_start_trans);
|
||||||
} else {
|
} else {
|
||||||
xSemaphoreGiveFromISR(sr_engine->base.sem, &HPTaskAwoken);
|
xSemaphoreGiveFromISR(engine_base->sem, &HPTaskAwoken);
|
||||||
need_yield |= (HPTaskAwoken == pdTRUE);
|
need_yield |= (HPTaskAwoken == pdTRUE);
|
||||||
}
|
}
|
||||||
esp_rom_printf("trans addr: 0x%x\n", trans_elm);
|
|
||||||
// Recycle transaction or give transaction semaphore
|
// Recycle transaction or give transaction semaphore
|
||||||
if (trans_elm->sem != NULL) {
|
if (trans_elm->sem != NULL) {
|
||||||
xSemaphoreGiveFromISR(trans_elm->sem, &HPTaskAwoken);
|
xSemaphoreGiveFromISR(trans_elm->sem, &HPTaskAwoken);
|
||||||
@ -735,7 +846,11 @@ static bool ppa_sr_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_
|
|||||||
}
|
}
|
||||||
|
|
||||||
portENTER_CRITICAL_ISR(&invoker->spinlock);
|
portENTER_CRITICAL_ISR(&invoker->spinlock);
|
||||||
invoker->sr_trans_cnt--;
|
if (engine_type == PPA_ENGINE_TYPE_SR) {
|
||||||
|
invoker->sr_trans_cnt--;
|
||||||
|
} else {
|
||||||
|
invoker->blending_trans_cnt--;
|
||||||
|
}
|
||||||
portEXIT_CRITICAL_ISR(&invoker->spinlock);
|
portEXIT_CRITICAL_ISR(&invoker->spinlock);
|
||||||
|
|
||||||
// TODO: how to notify non-blocking transaction
|
// TODO: how to notify non-blocking transaction
|
||||||
@ -862,11 +977,11 @@ static bool ppa_sr_transaction_on_picked(uint32_t num_chans, const dma2d_trans_c
|
|||||||
dma2d_csc_config_t dma_rx_csc = {
|
dma2d_csc_config_t dma_rx_csc = {
|
||||||
.rx_csc_option = DMA2D_CSC_RX_YUV420_TO_YUV444,
|
.rx_csc_option = DMA2D_CSC_RX_YUV420_TO_YUV444,
|
||||||
};
|
};
|
||||||
dma2d_configure_color_space_conversion(dma2d_rx_chan, &dma_rx_csc);
|
dma2d_configure_color_space_conversion(dma2d_rx_chan, &dma_rx_csc); // TODO: RX CSC only on channel 0
|
||||||
}
|
}
|
||||||
|
|
||||||
dma2d_rx_event_callbacks_t dma_event_cbs = {
|
dma2d_rx_event_callbacks_t dma_event_cbs = {
|
||||||
.on_recv_eof = ppa_sr_transaction_done_cb,
|
.on_recv_eof = ppa_transaction_done_cb,
|
||||||
};
|
};
|
||||||
dma2d_register_rx_event_callbacks(dma2d_rx_chan, &dma_event_cbs, (void *)trans_on_picked_desc->trans_elm);
|
dma2d_register_rx_event_callbacks(dma2d_rx_chan, &dma_event_cbs, (void *)trans_on_picked_desc->trans_elm);
|
||||||
|
|
||||||
@ -885,6 +1000,7 @@ static bool ppa_sr_transaction_on_picked(uint32_t num_chans, const dma2d_trans_c
|
|||||||
}
|
}
|
||||||
ppa_ll_sr_enable_rx_byte_swap(s_platform.hal.dev, sr_trans_desc->in_color.byte_swap);
|
ppa_ll_sr_enable_rx_byte_swap(s_platform.hal.dev, sr_trans_desc->in_color.byte_swap);
|
||||||
ppa_ll_sr_enable_rx_rgb_swap(s_platform.hal.dev, sr_trans_desc->in_color.rgb_swap);
|
ppa_ll_sr_enable_rx_rgb_swap(s_platform.hal.dev, sr_trans_desc->in_color.rgb_swap);
|
||||||
|
ppa_ll_sr_configure_rx_alpha(s_platform.hal.dev, sr_trans_desc->in_color.alpha_mode, sr_trans_desc->in_color.alpha_value);
|
||||||
|
|
||||||
ppa_ll_sr_set_tx_color_mode(s_platform.hal.dev, ppa_out_color_mode);
|
ppa_ll_sr_set_tx_color_mode(s_platform.hal.dev, ppa_out_color_mode);
|
||||||
if (COLOR_SPACE_TYPE(ppa_out_color_mode) == COLOR_SPACE_YUV) {
|
if (COLOR_SPACE_TYPE(ppa_out_color_mode) == COLOR_SPACE_YUV) {
|
||||||
@ -892,8 +1008,6 @@ static bool ppa_sr_transaction_on_picked(uint32_t num_chans, const dma2d_trans_c
|
|||||||
ppa_ll_sr_set_yuv2rgb_std(s_platform.hal.dev, sr_trans_desc->out_color.yuv_std);
|
ppa_ll_sr_set_yuv2rgb_std(s_platform.hal.dev, sr_trans_desc->out_color.yuv_std);
|
||||||
}
|
}
|
||||||
|
|
||||||
ppa_ll_sr_configure_rx_alpha(s_platform.hal.dev, sr_trans_desc->alpha_mode, sr_trans_desc->alpha_value);
|
|
||||||
|
|
||||||
// TODO: sr_macro_bk_ro_bypass
|
// TODO: sr_macro_bk_ro_bypass
|
||||||
// PPA.sr_byte_order.sr_macro_bk_ro_bypass = 1;
|
// PPA.sr_byte_order.sr_macro_bk_ro_bypass = 1;
|
||||||
ppa_ll_sr_set_rotation_angle(s_platform.hal.dev, sr_trans_desc->rotation_angle);
|
ppa_ll_sr_set_rotation_angle(s_platform.hal.dev, sr_trans_desc->rotation_angle);
|
||||||
@ -910,7 +1024,6 @@ static bool ppa_sr_transaction_on_picked(uint32_t num_chans, const dma2d_trans_c
|
|||||||
|
|
||||||
esp_err_t ppa_do_scale_and_rotate(ppa_invoker_handle_t ppa_invoker, const ppa_sr_trans_config_t *config, ppa_trans_mode_t mode)
|
esp_err_t ppa_do_scale_and_rotate(ppa_invoker_handle_t ppa_invoker, const ppa_sr_trans_config_t *config, ppa_trans_mode_t mode)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
|
||||||
ESP_RETURN_ON_FALSE(ppa_invoker && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(ppa_invoker && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_RETURN_ON_FALSE(ppa_invoker->sr_engine, ESP_ERR_INVALID_ARG, TAG, "invoker did not register to SR engine");
|
ESP_RETURN_ON_FALSE(ppa_invoker->sr_engine, ESP_ERR_INVALID_ARG, TAG, "invoker did not register to SR engine");
|
||||||
ESP_RETURN_ON_FALSE(mode <= PPA_TRANS_MODE_NON_BLOCKING, ESP_ERR_INVALID_ARG, TAG, "invalid mode");
|
ESP_RETURN_ON_FALSE(mode <= PPA_TRANS_MODE_NON_BLOCKING, ESP_ERR_INVALID_ARG, TAG, "invalid mode");
|
||||||
@ -924,135 +1037,9 @@ esp_err_t ppa_do_scale_and_rotate(ppa_invoker_handle_t ppa_invoker, const ppa_sr
|
|||||||
ESP_ERR_INVALID_ARG, TAG, "invalid scale");
|
ESP_ERR_INVALID_ARG, TAG, "invalid scale");
|
||||||
// byte/rgb swap with color mode only to (A)RGB color space?
|
// byte/rgb swap with color mode only to (A)RGB color space?
|
||||||
|
|
||||||
ppa_sr_engine_t *sr_engine = __containerof(ppa_invoker->sr_engine, ppa_sr_engine_t, base);
|
// TODO: Maybe do buffer writeback and invalidation here, instead of in on_picked?
|
||||||
// ESP_RETURN_ON_FALSE(sr_engine, ESP_FAIL, TAG, "SR engine not registered, please register through ppa_module_acquire first");
|
|
||||||
|
|
||||||
ppa_trans_t *new_trans_elm = (ppa_trans_t *)heap_caps_calloc(1, sizeof(ppa_trans_t), PPA_MEM_ALLOC_CAPS);
|
return ppa_do_operation(ppa_invoker, ppa_invoker->sr_engine, PPA_OPERATION_SR, (void *)config, mode);
|
||||||
dma2d_trans_t *dma_trans_elm = (dma2d_trans_t *)heap_caps_calloc(1, SIZEOF_DMA2D_TRANS_T, PPA_MEM_ALLOC_CAPS);
|
|
||||||
dma2d_trans_config_t *dma_trans_desc = (dma2d_trans_config_t *)heap_caps_calloc(1, sizeof(dma2d_trans_config_t), PPA_MEM_ALLOC_CAPS);
|
|
||||||
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)heap_caps_calloc(1, sizeof(ppa_dma2d_trans_on_picked_config_t), PPA_MEM_ALLOC_CAPS);
|
|
||||||
ppa_sr_transaction_t *ppa_trans_desc = (ppa_sr_transaction_t *)heap_caps_calloc(1, sizeof(ppa_sr_transaction_t), PPA_MEM_ALLOC_CAPS);
|
|
||||||
ESP_GOTO_ON_FALSE(new_trans_elm && dma_trans_elm && dma_trans_desc && trans_on_picked_desc && ppa_trans_desc, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction storage");
|
|
||||||
if (mode == PPA_TRANS_MODE_BLOCKING) {
|
|
||||||
new_trans_elm->sem = xSemaphoreCreateBinary();
|
|
||||||
ESP_GOTO_ON_FALSE(new_trans_elm->sem, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction storage");
|
|
||||||
}
|
|
||||||
esp_rom_printf("new trans addr: 0x%x\n", new_trans_elm);
|
|
||||||
memcpy(ppa_trans_desc, config, sizeof(ppa_sr_trans_config_t));
|
|
||||||
|
|
||||||
trans_on_picked_desc->sr_desc = ppa_trans_desc;
|
|
||||||
trans_on_picked_desc->ppa_engine = &sr_engine->base;
|
|
||||||
trans_on_picked_desc->trans_elm = new_trans_elm;
|
|
||||||
trans_on_picked_desc->trigger_periph = DMA2D_TRIG_PERIPH_PPA_SR;
|
|
||||||
|
|
||||||
dma_trans_desc->tx_channel_num = 1;
|
|
||||||
dma_trans_desc->rx_channel_num = 1;
|
|
||||||
// TODO: reserved channels
|
|
||||||
dma_trans_desc->user_config = (void *)trans_on_picked_desc;
|
|
||||||
dma_trans_desc->on_job_picked = ppa_sr_transaction_on_picked;
|
|
||||||
|
|
||||||
new_trans_elm->trans_desc = dma_trans_desc;
|
|
||||||
new_trans_elm->dma_trans_placeholder = dma_trans_elm;
|
|
||||||
new_trans_elm->invoker = ppa_invoker;
|
|
||||||
|
|
||||||
portENTER_CRITICAL(&ppa_invoker->spinlock);
|
|
||||||
if (ppa_invoker->in_accepting_trans_state) {
|
|
||||||
// Send transaction into PPA SR engine queue
|
|
||||||
STAILQ_INSERT_TAIL(&sr_engine->base.trans_stailq, new_trans_elm, entry);
|
|
||||||
ppa_invoker->sr_trans_cnt++;
|
|
||||||
} else {
|
|
||||||
ret = ESP_FAIL;
|
|
||||||
}
|
|
||||||
portEXIT_CRITICAL(&ppa_invoker->spinlock);
|
|
||||||
|
|
||||||
if (ret != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "The invoker cannot accept transaction now");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
TickType_t ticks_to_wait = (mode == PPA_TRANS_MODE_NON_BLOCKING) ? 0 : portMAX_DELAY;
|
|
||||||
if (xSemaphoreTake(sr_engine->base.sem, ticks_to_wait) == pdTRUE) {
|
|
||||||
// Check if the transaction has already been started from the ISR
|
|
||||||
// If so, then the transaction should have been removed from queue at this moment (transaction completed)
|
|
||||||
bool found = false;
|
|
||||||
ppa_trans_t *temp = NULL;
|
|
||||||
portENTER_CRITICAL(&sr_engine->base.spinlock);
|
|
||||||
STAILQ_FOREACH(temp, &sr_engine->base.trans_stailq, entry) {
|
|
||||||
if (temp == new_trans_elm) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
portEXIT_CRITICAL(&sr_engine->base.spinlock);
|
|
||||||
if (found) {
|
|
||||||
ret = ppa_dma2d_enqueue(new_trans_elm);
|
|
||||||
if (ret != ESP_OK) {
|
|
||||||
portENTER_CRITICAL(&sr_engine->base.spinlock);
|
|
||||||
STAILQ_REMOVE(&sr_engine->base.trans_stailq, new_trans_elm, ppa_trans_s, entry);
|
|
||||||
portEXIT_CRITICAL(&sr_engine->base.spinlock);
|
|
||||||
xSemaphoreGive(sr_engine->base.sem);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
xSemaphoreGive(sr_engine->base.sem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == PPA_TRANS_MODE_BLOCKING) {
|
|
||||||
// while (1) {
|
|
||||||
// printf("ppa intr: %ld\n", PPA.int_raw.val);
|
|
||||||
// }
|
|
||||||
xSemaphoreTake(new_trans_elm->sem, portMAX_DELAY); // Given in the ISR
|
|
||||||
// Sanity check new_trans_elm not in trans_stailq anymore? (loop takes time tho)
|
|
||||||
ppa_recycle_transaction(new_trans_elm);
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (ret != ESP_OK) {
|
|
||||||
ppa_recycle_transaction(new_trans_elm);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ppa_blend_transaction_done_cb(dma2d_channel_handle_t dma2d_chan, dma2d_event_data_t *event_data, void *user_data)
|
|
||||||
{
|
|
||||||
bool need_yield = false;
|
|
||||||
BaseType_t HPTaskAwoken;
|
|
||||||
ppa_trans_t *trans_elm = (ppa_trans_t *)user_data;
|
|
||||||
ppa_invoker_t *invoker = trans_elm->invoker;
|
|
||||||
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)trans_elm->trans_desc->user_config;
|
|
||||||
assert(trans_on_picked_desc->trigger_periph == DMA2D_TRIG_PERIPH_PPA_BLEND);
|
|
||||||
ppa_blend_engine_t *blend_engine = __containerof(trans_on_picked_desc->ppa_engine, ppa_blend_engine_t, base);
|
|
||||||
|
|
||||||
ppa_trans_t *next_start_trans = NULL;
|
|
||||||
portENTER_CRITICAL_ISR(&blend_engine->base.spinlock);
|
|
||||||
// Remove this transaction from transaction queue
|
|
||||||
STAILQ_REMOVE(&blend_engine->base.trans_stailq, trans_elm, ppa_trans_s, entry);
|
|
||||||
next_start_trans = STAILQ_FIRST(&blend_engine->base.trans_stailq);
|
|
||||||
portEXIT_CRITICAL_ISR(&blend_engine->base.spinlock);
|
|
||||||
|
|
||||||
// If there is next trans in PPA engine queue, send it to DMA queue; otherwise, release the engine semaphore
|
|
||||||
if (next_start_trans) {
|
|
||||||
ppa_dma2d_enqueue(next_start_trans);
|
|
||||||
} else {
|
|
||||||
xSemaphoreGiveFromISR(blend_engine->base.sem, &HPTaskAwoken);
|
|
||||||
need_yield |= (HPTaskAwoken == pdTRUE);
|
|
||||||
}
|
|
||||||
// Recycle transaction or give transaction semaphore
|
|
||||||
if (trans_elm->sem != NULL) {
|
|
||||||
xSemaphoreGiveFromISR(trans_elm->sem, &HPTaskAwoken);
|
|
||||||
need_yield |= (HPTaskAwoken == pdTRUE);
|
|
||||||
} else {
|
|
||||||
ppa_recycle_transaction(trans_elm);
|
|
||||||
}
|
|
||||||
|
|
||||||
portENTER_CRITICAL_ISR(&invoker->spinlock);
|
|
||||||
invoker->blending_trans_cnt--;
|
|
||||||
portEXIT_CRITICAL_ISR(&invoker->spinlock);
|
|
||||||
|
|
||||||
// TODO: how to notify non-blocking transaction
|
|
||||||
|
|
||||||
return need_yield;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config)
|
static bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_trans_channel_info_t *dma2d_chans, void *user_config)
|
||||||
@ -1179,7 +1166,7 @@ static bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_tran
|
|||||||
dma2d_set_transfer_ability(dma2d_rx_chan, &dma_transfer_ability);
|
dma2d_set_transfer_ability(dma2d_rx_chan, &dma_transfer_ability);
|
||||||
|
|
||||||
dma2d_rx_event_callbacks_t dma_event_cbs = {
|
dma2d_rx_event_callbacks_t dma_event_cbs = {
|
||||||
.on_recv_eof = ppa_blend_transaction_done_cb,
|
.on_recv_eof = ppa_transaction_done_cb,
|
||||||
};
|
};
|
||||||
dma2d_register_rx_event_callbacks(dma2d_rx_chan, &dma_event_cbs, (void *)trans_on_picked_desc->trans_elm);
|
dma2d_register_rx_event_callbacks(dma2d_rx_chan, &dma_event_cbs, (void *)trans_on_picked_desc->trans_elm);
|
||||||
|
|
||||||
@ -1216,96 +1203,14 @@ static bool ppa_blend_transaction_on_picked(uint32_t num_chans, const dma2d_tran
|
|||||||
|
|
||||||
esp_err_t ppa_do_blend(ppa_invoker_handle_t ppa_invoker, const ppa_blend_trans_config_t *config, ppa_trans_mode_t mode)
|
esp_err_t ppa_do_blend(ppa_invoker_handle_t ppa_invoker, const ppa_blend_trans_config_t *config, ppa_trans_mode_t mode)
|
||||||
{
|
{
|
||||||
esp_err_t ret = ESP_OK;
|
|
||||||
ESP_RETURN_ON_FALSE(ppa_invoker && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(ppa_invoker && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_RETURN_ON_FALSE(ppa_invoker->blending_engine, ESP_ERR_INVALID_ARG, TAG, "invoker did not register to Blending engine");
|
ESP_RETURN_ON_FALSE(ppa_invoker->blending_engine, ESP_ERR_INVALID_ARG, TAG, "invoker did not register to Blending engine");
|
||||||
ESP_RETURN_ON_FALSE(mode <= PPA_TRANS_MODE_NON_BLOCKING, ESP_ERR_INVALID_ARG, TAG, "invalid mode");
|
ESP_RETURN_ON_FALSE(mode <= PPA_TRANS_MODE_NON_BLOCKING, ESP_ERR_INVALID_ARG, TAG, "invalid mode");
|
||||||
|
// TODO: ARG CHECK
|
||||||
|
|
||||||
ppa_blend_engine_t *blend_engine = __containerof(ppa_invoker->blending_engine, ppa_blend_engine_t, base);
|
// TODO: Maybe do buffer writeback and invalidation here, instead of in on_picked?
|
||||||
|
|
||||||
ppa_trans_t *new_trans_elm = (ppa_trans_t *)heap_caps_calloc(1, sizeof(ppa_trans_t), PPA_MEM_ALLOC_CAPS);
|
return ppa_do_operation(ppa_invoker, ppa_invoker->blending_engine, PPA_OPERATION_BLEND, (void *)config, mode);
|
||||||
dma2d_trans_t *dma_trans_elm = (dma2d_trans_t *)heap_caps_calloc(1, SIZEOF_DMA2D_TRANS_T, PPA_MEM_ALLOC_CAPS);
|
|
||||||
dma2d_trans_config_t *dma_trans_desc = (dma2d_trans_config_t *)heap_caps_calloc(1, sizeof(dma2d_trans_config_t), PPA_MEM_ALLOC_CAPS);
|
|
||||||
ppa_dma2d_trans_on_picked_config_t *trans_on_picked_desc = (ppa_dma2d_trans_on_picked_config_t *)heap_caps_calloc(1, sizeof(ppa_dma2d_trans_on_picked_config_t), PPA_MEM_ALLOC_CAPS);
|
|
||||||
ppa_blend_transaction_t *ppa_trans_desc = (ppa_blend_transaction_t *)heap_caps_calloc(1, sizeof(ppa_blend_transaction_t), PPA_MEM_ALLOC_CAPS);
|
|
||||||
ESP_GOTO_ON_FALSE(new_trans_elm && dma_trans_elm && dma_trans_desc && trans_on_picked_desc && ppa_trans_desc, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction storage");
|
|
||||||
if (mode == PPA_TRANS_MODE_BLOCKING) {
|
|
||||||
new_trans_elm->sem = xSemaphoreCreateBinary();
|
|
||||||
ESP_GOTO_ON_FALSE(new_trans_elm->sem, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction storage");
|
|
||||||
}
|
|
||||||
memcpy(ppa_trans_desc, config, sizeof(ppa_blend_trans_config_t));
|
|
||||||
|
|
||||||
trans_on_picked_desc->blend_desc = ppa_trans_desc;
|
|
||||||
trans_on_picked_desc->ppa_engine = &blend_engine->base;
|
|
||||||
trans_on_picked_desc->trans_elm = new_trans_elm;
|
|
||||||
trans_on_picked_desc->trigger_periph = DMA2D_TRIG_PERIPH_PPA_BLEND;
|
|
||||||
|
|
||||||
dma_trans_desc->tx_channel_num = 2;
|
|
||||||
dma_trans_desc->rx_channel_num = 1;
|
|
||||||
dma_trans_desc->user_config = (void *)trans_on_picked_desc;
|
|
||||||
dma_trans_desc->on_job_picked = ppa_blend_transaction_on_picked;
|
|
||||||
|
|
||||||
new_trans_elm->trans_desc = dma_trans_desc;
|
|
||||||
new_trans_elm->dma_trans_placeholder = dma_trans_elm;
|
|
||||||
new_trans_elm->invoker = ppa_invoker;
|
|
||||||
|
|
||||||
portENTER_CRITICAL(&ppa_invoker->spinlock);
|
|
||||||
if (ppa_invoker->in_accepting_trans_state) {
|
|
||||||
// Send transaction into PPA blending engine queue
|
|
||||||
STAILQ_INSERT_TAIL(&blend_engine->base.trans_stailq, new_trans_elm, entry);
|
|
||||||
ppa_invoker->blending_trans_cnt++;
|
|
||||||
} else {
|
|
||||||
ret = ESP_FAIL;
|
|
||||||
}
|
|
||||||
portEXIT_CRITICAL(&ppa_invoker->spinlock);
|
|
||||||
|
|
||||||
if (ret != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "The invoker cannot accept transaction now");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
TickType_t ticks_to_wait = (mode == PPA_TRANS_MODE_NON_BLOCKING) ? 0 : portMAX_DELAY;
|
|
||||||
if (xSemaphoreTake(blend_engine->base.sem, ticks_to_wait) == pdTRUE) {
|
|
||||||
// Check if the transaction has already been started from the ISR
|
|
||||||
// If so, then the transaction should have been removed from queue at this moment (transaction completed)
|
|
||||||
bool found = false;
|
|
||||||
ppa_trans_t *temp = NULL;
|
|
||||||
portENTER_CRITICAL(&blend_engine->base.spinlock);
|
|
||||||
STAILQ_FOREACH(temp, &blend_engine->base.trans_stailq, entry) {
|
|
||||||
if (temp == new_trans_elm) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
portEXIT_CRITICAL(&blend_engine->base.spinlock);
|
|
||||||
if (found) {
|
|
||||||
ret = ppa_dma2d_enqueue(new_trans_elm);
|
|
||||||
if (ret != ESP_OK) {
|
|
||||||
portENTER_CRITICAL(&blend_engine->base.spinlock);
|
|
||||||
STAILQ_REMOVE(&blend_engine->base.trans_stailq, new_trans_elm, ppa_trans_s, entry);
|
|
||||||
portEXIT_CRITICAL(&blend_engine->base.spinlock);
|
|
||||||
xSemaphoreGive(blend_engine->base.sem);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
xSemaphoreGive(blend_engine->base.sem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == PPA_TRANS_MODE_BLOCKING) {
|
|
||||||
// while (1) {
|
|
||||||
// printf("ppa intr: %ld\n", PPA.int_raw.val);
|
|
||||||
// }
|
|
||||||
xSemaphoreTake(new_trans_elm->sem, portMAX_DELAY); // Given in the ISR
|
|
||||||
// Sanity check new_trans_elm not in trans_stailq anymore? (loop takes time tho)
|
|
||||||
ppa_recycle_transaction(new_trans_elm);
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (ret != ESP_OK) {
|
|
||||||
ppa_recycle_transaction(new_trans_elm);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t ppa_do_fill(ppa_invoker_handle_t ppa_invoker, const ppa_fill_trans_config_t *config, ppa_trans_mode_t mode)
|
esp_err_t ppa_do_fill(ppa_invoker_handle_t ppa_invoker, const ppa_fill_trans_config_t *config, ppa_trans_mode_t mode)
|
||||||
|
Reference in New Issue
Block a user