Merge branch 'feature/parlio_rx_driver_p4_v5.3' into 'release/v5.3'

feat(parlio_rx): supported parlio rx on p4 (v5.3)

See merge request espressif/esp-idf!31096
This commit is contained in:
morris 2024-06-07 22:54:08 +08:00
commit 41515a9086
19 changed files with 238 additions and 91 deletions

View File

@ -48,6 +48,8 @@ parlio_group_t *parlio_acquire_group_handle(int group_id)
}
// hal layer initialize
parlio_hal_init(&group->hal);
group->dma_align = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
group->dma_align = group->dma_align < 4 ? 4 : group->dma_align;
}
} else { // group already install
group = s_platform.groups[group_id];

View File

@ -30,6 +30,7 @@
#else
#define PARLIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif
#define PARLIO_DMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
#if SOC_PARLIO_TX_RX_SHARE_INTERRUPT
#define PARLIO_INTR_ALLOC_FLAG_SHARED ESP_INTR_FLAG_SHARED
@ -57,6 +58,12 @@ typedef dma_descriptor_align8_t parlio_dma_desc_t;
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#define PARLIO_MAX_ALIGNED_DMA_BUF_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED
#else
#define PARLIO_MAX_ALIGNED_DMA_BUF_SIZE DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED
#endif
#ifdef CACHE_LL_L2MEM_NON_CACHE_ADDR
/* The descriptor address can be mapped by a fixed offset */
#define PARLIO_GET_NON_CACHED_DESC_ADDR(desc) (desc ? (parlio_dma_desc_t *)(CACHE_LL_L2MEM_NON_CACHE_ADDR(desc)) : NULL)
@ -107,11 +114,12 @@ typedef enum {
typedef struct parlio_unit_t *parlio_unit_base_handle_t;
typedef struct parlio_group_t {
int group_id; // group ID, index from 0
portMUX_TYPE spinlock; // to protect per-group register level concurrent access
parlio_hal_context_t hal; // hal layer context
parlio_unit_base_handle_t tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP]; // tx unit handles
parlio_unit_base_handle_t rx_units[SOC_PARLIO_RX_UNITS_PER_GROUP]; // rx unit handles
int group_id; // group ID, index from 0
portMUX_TYPE spinlock; // to protect per-group register level concurrent access
parlio_hal_context_t hal; // hal layer context
uint32_t dma_align; // DMA buffer alignment
parlio_unit_base_handle_t tx_units[SOC_PARLIO_TX_UNITS_PER_GROUP]; // tx unit handles
parlio_unit_base_handle_t rx_units[SOC_PARLIO_RX_UNITS_PER_GROUP]; // rx unit handles
} parlio_group_t;
/**

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -33,7 +33,9 @@
#include "esp_memory_utils.h"
#include "esp_clk_tree.h"
#include "esp_attr.h"
#include "esp_dma_utils.h"
#include "esp_private/gdma.h"
#include "esp_cache.h"
static const char *TAG = "parlio-rx";
@ -81,8 +83,9 @@ typedef struct parlio_rx_unit_t {
gdma_channel_handle_t dma_chan; /*!< DMA channel */
size_t max_recv_size; /*!< Maximum receive size for a normal transaction */
size_t desc_num; /*!< DMA descriptor number */
dma_descriptor_t *dma_descs; /*!< DMA descriptor array pointer */
dma_descriptor_t *curr_desc; /*!< The pointer of the current descriptor */
size_t desc_size; /*!< DMA descriptors total size */
parlio_dma_desc_t **dma_descs; /*!< DMA descriptor array pointer */
parlio_dma_desc_t *curr_desc; /*!< The pointer of the current descriptor */
void *usr_recv_buf; /*!< The pointe to the user's receiving buffer */
/* Infinite transaction specific */
void *dma_buf; /*!< Additional internal DMA buffer only for infinite transactions */
@ -125,19 +128,21 @@ typedef struct parlio_rx_delimiter_t {
} flags;
} parlio_rx_delimiter_t;
#define PRALIO_RX_MOUNT_SIZE_CALC(total_size, div, align) ((((total_size) / (align)) / (div)) * (align))
static portMUX_TYPE s_rx_spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
static IRAM_ATTR size_t s_parlio_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parlio_rx_transaction_t *trans)
{
dma_descriptor_t *p_desc = rx_unit->dma_descs;
parlio_dma_desc_t **p_desc = rx_unit->dma_descs;
/* Update the current transaction to the next one, and declare the delimiter is under using of the rx unit */
memcpy(&rx_unit->curr_trans, trans, sizeof(parlio_rx_transaction_t));
portENTER_CRITICAL_SAFE(&s_rx_spinlock);
trans->delimiter->under_using = true;
portEXIT_CRITICAL_SAFE(&s_rx_spinlock);
uint32_t desc_num = trans->size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
uint32_t remain_num = trans->size % DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED;
uint32_t desc_num = trans->size / PARLIO_MAX_ALIGNED_DMA_BUF_SIZE;
uint32_t remain_num = trans->size % PARLIO_MAX_ALIGNED_DMA_BUF_SIZE;
/* If there are still data remained, need one more descriptor */
desc_num += remain_num ? 1 : 0;
if (trans->flags.infinite && desc_num < 2) {
@ -146,30 +151,40 @@ static IRAM_ATTR size_t s_parlio_mount_transaction_buffer(parlio_rx_unit_handle_
}
size_t mount_size = 0;
size_t offset = 0;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
uint32_t alignment = rx_unit->base.group->dma_align;
#else
uint32_t alignment = 4;
#endif
/* Loop the descriptors to assign the data */
for (int i = 0; i < desc_num; i++) {
size_t rest_size = trans->size - offset;
if (rest_size >= 2 * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
mount_size = trans->size / desc_num;
} else if (rest_size <= DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED) {
mount_size = (desc_num == 2) && (i == 0) ? rest_size / 2 : rest_size;
if (rest_size >= 2 * PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) {
mount_size = PRALIO_RX_MOUNT_SIZE_CALC(trans->size, desc_num, alignment);
} else if (rest_size <= PARLIO_MAX_ALIGNED_DMA_BUF_SIZE) {
mount_size = (desc_num == 2) && (i == 0) ? PRALIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment) : rest_size;
} else {
mount_size = rest_size / 2;
mount_size = PRALIO_RX_MOUNT_SIZE_CALC(rest_size, 2, alignment);
}
p_desc[i].buffer = (void *)((uint8_t *)trans->payload + offset);
p_desc[i].dw0.size = mount_size;
p_desc[i].dw0.length = mount_size;
p_desc[i].dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
p_desc[i]->buffer = (void *)((uint8_t *)trans->payload + offset);
p_desc[i]->dw0.size = mount_size;
p_desc[i]->dw0.length = mount_size;
p_desc[i]->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
// Link the descriptor
if (i > 0) {
p_desc[i - 1].next = &p_desc[i];
if (i < desc_num - 1) {
p_desc[i]->next = p_desc[i + 1];
} else {
/* For infinite transaction, link the descriptor as a ring */
p_desc[i]->next = trans->flags.infinite ? p_desc[0] : NULL;
}
offset += mount_size;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(p_desc[i], rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif
}
/* For infinite transaction, link the descriptor as a ring */
p_desc[desc_num - 1].next = trans->flags.infinite ? &p_desc[0] : NULL;
/* Reset the current DMA node */
rx_unit->curr_desc = p_desc;
rx_unit->curr_desc = p_desc[0];
return offset;
}
@ -251,6 +266,8 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons
gpio_conf.mode = config->flags.io_loop_back ? GPIO_MODE_INPUT_OUTPUT : GPIO_MODE_INPUT;
gpio_conf.pin_bit_mask = BIT64(config->clk_in_gpio_num);
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config clk in GPIO failed");
} else {
gpio_ll_input_enable(&GPIO, config->clk_in_gpio_num);
}
esp_rom_gpio_connect_in_signal(config->clk_in_gpio_num,
parlio_periph_signals.groups[group_id].rx_units[unit_id].clk_in_sig, false);
@ -275,6 +292,8 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons
if (!config->flags.io_no_init) {
gpio_conf.pin_bit_mask = BIT64(config->valid_gpio_num);
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config data GPIO failed");
} else {
gpio_ll_input_enable(&GPIO, config->valid_gpio_num);
}
/* Not connect the signal here, the signal is lazy connected until the delimiter takes effect */
}
@ -286,7 +305,8 @@ static esp_err_t s_parlio_rx_unit_set_gpio(parlio_rx_unit_handle_t rx_unit, cons
if (!config->flags.io_no_init) {
gpio_conf.pin_bit_mask = BIT64(config->data_gpio_nums[i]);
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config data GPIO failed");
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->data_gpio_nums[i]], PIN_FUNC_GPIO);
} else {
gpio_ll_input_enable(&GPIO, config->data_gpio_nums[i]);
}
esp_rom_gpio_connect_in_signal(config->data_gpio_nums[i],
parlio_periph_signals.groups[group_id].rx_units[unit_id].data_sigs[i], false);
@ -330,18 +350,22 @@ static IRAM_ATTR bool s_parlio_rx_default_eof_callback(gdma_channel_handle_t dma
/* The current transaction finished, try to get the next transaction from the transaction queue */
if (xQueueReceiveFromISR(rx_unit->trans_que, &next_trans, &high_task_woken) == pdTRUE) {
if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false);
}
}
/* If the delimiter of the next transaction is not same as the current one, need to re-config the hardware */
if (next_trans.delimiter != rx_unit->curr_trans.delimiter) {
if ((next_trans.delimiter != NULL) && (next_trans.delimiter != rx_unit->curr_trans.delimiter)) {
s_parlio_set_delimiter_config(rx_unit, next_trans.delimiter);
}
/* Mount the new transaction buffer and start the new transaction */
s_parlio_mount_transaction_buffer(rx_unit, &next_trans);
gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->dma_descs);
gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->dma_descs[0]);
if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_start(rx_unit->base.group->hal.regs, true);
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true);
}
}
} else if (rx_unit->curr_trans.delimiter) { // Add condition in case the curr_trans has been cleared in the last timeout isr
/* No more transaction pending to receive, clear the current transaction */
@ -368,7 +392,15 @@ static IRAM_ATTR bool s_parlio_rx_default_desc_done_callback(gdma_channel_handle
}
/* Get the finished descriptor from the current descriptor */
dma_descriptor_t *finished_desc = rx_unit->curr_desc;
parlio_dma_desc_t *finished_desc = rx_unit->curr_desc;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_err_t ret = ESP_OK;
ret |= esp_cache_msync((void *)finished_desc, rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
ret |= esp_cache_msync((void *)(finished_desc->buffer), finished_desc->dw0.size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
if (ret != ESP_OK) {
ESP_EARLY_LOGW(TAG, "failed to sync dma buffer from memory to cache");
}
#endif
parlio_rx_event_data_t evt_data = {
.delimiter = rx_unit->curr_trans.delimiter,
.data = finished_desc->buffer,
@ -399,21 +431,41 @@ static IRAM_ATTR bool s_parlio_rx_default_desc_done_callback(gdma_channel_handle
static esp_err_t s_parlio_rx_create_dma_descriptors(parlio_rx_unit_handle_t rx_unit, uint32_t max_recv_size)
{
ESP_RETURN_ON_FALSE(rx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid param");
esp_err_t ret = ESP_OK;
uint32_t desc_num = max_recv_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED + 1;
/* set at least 2 descriptors */
if (desc_num < 2) {
desc_num = 4;
desc_num = 2;
}
rx_unit->desc_num = desc_num;
/* Allocated and link the descriptor nodes */
rx_unit->dma_descs = (dma_descriptor_t *)heap_caps_calloc(desc_num, sizeof(dma_descriptor_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
ESP_RETURN_ON_FALSE(rx_unit->dma_descs, ESP_ERR_NO_MEM, TAG, "no memory for DMA descriptors");
rx_unit->dma_descs = heap_caps_calloc(desc_num, sizeof(parlio_dma_desc_t *), MALLOC_CAP_DMA);
ESP_RETURN_ON_FALSE(rx_unit->dma_descs, ESP_ERR_NO_MEM, TAG, "no memory for DMA descriptor array");
uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
size_t alignment = MAX(cache_line_size, PARLIO_DMA_DESC_ALIGNMENT);
rx_unit->desc_size = ALIGN_UP(sizeof(parlio_dma_desc_t), alignment);
for (int i = 0; i < desc_num; i++) {
rx_unit->dma_descs[i] = heap_caps_aligned_calloc(alignment, 1, rx_unit->desc_size, PARLIO_DMA_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(rx_unit->dma_descs[i], ESP_ERR_NO_MEM, err, TAG, "no memory for DMA descriptors");
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(rx_unit->dma_descs[i], rx_unit->desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif
}
rx_unit->max_recv_size = max_recv_size;
return ESP_OK;
return ret;
err:
for (int i = 0; i < desc_num; i++) {
if (rx_unit->dma_descs[i]) {
free(rx_unit->dma_descs[i]);
rx_unit->dma_descs[i] = NULL;
}
}
free(rx_unit->dma_descs);
rx_unit->dma_descs = NULL;
return ret;
}
static esp_err_t s_parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit)
@ -422,7 +474,7 @@ static esp_err_t s_parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit)
gdma_channel_alloc_config_t dma_chan_config = {
.direction = GDMA_CHANNEL_DIRECTION_RX,
};
ESP_RETURN_ON_ERROR(gdma_new_channel(&dma_chan_config, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed");
ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed");
gdma_connect(rx_unit->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_PARLIO, 0));
/* Set GDMA strategy */
@ -487,8 +539,10 @@ static esp_err_t s_parlio_select_periph_clock(parlio_rx_unit_handle_t rx_unit, c
#endif
/* Set clock configuration */
parlio_ll_rx_set_clock_source(hal->regs, clk_src);
parlio_ll_rx_set_clock_div(hal->regs, &clk_div);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_set_clock_source(hal->regs, clk_src);
parlio_ll_rx_set_clock_div(hal->regs, &clk_div);
}
rx_unit->clk_src = clk_src;
/* warning if precision lost due to division */
@ -525,7 +579,14 @@ static esp_err_t s_parlio_destroy_rx_unit(parlio_rx_unit_handle_t rx_unit)
}
/* Free the DMA descriptors */
if (rx_unit->dma_descs) {
for (int i = 0; i < rx_unit->desc_num; i++) {
if (rx_unit->dma_descs[i]) {
free(rx_unit->dma_descs[i]);
rx_unit->dma_descs[i] = NULL;
}
}
free(rx_unit->dma_descs);
rx_unit->dma_descs = NULL;
}
/* Free the internal DMA buffer */
if (rx_unit->dma_buf) {
@ -591,9 +652,13 @@ esp_err_t parlio_new_rx_unit(const parlio_rx_unit_config_t *config, parlio_rx_un
/* Install DMA service */
ESP_GOTO_ON_ERROR(s_parlio_rx_unit_init_dma(unit), err, TAG, "install rx DMA failed");
/* Reset RX module */
parlio_ll_rx_reset_clock(hal->regs);
PARLIO_RCC_ATOMIC() {
parlio_ll_rx_reset_clock(hal->regs);
}
parlio_ll_rx_reset_fifo(hal->regs);
parlio_ll_rx_enable_clock(hal->regs, false);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, false);
}
parlio_ll_rx_start(hal->regs, false);
/* parlio_ll_clock_source_t and parlio_clock_source_t are binary compatible if the clock source is from internal */
ESP_GOTO_ON_ERROR(s_parlio_select_periph_clock(unit, config), err, TAG, "set clock source failed");
@ -651,7 +716,9 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu
if (!rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_reset_fifo(hal->regs);
parlio_ll_rx_start(hal->regs, true);
parlio_ll_rx_enable_clock(hal->regs, true);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, true);
}
}
/* Check if we need to start a pending transaction */
@ -663,14 +730,18 @@ esp_err_t parlio_rx_unit_enable(parlio_rx_unit_handle_t rx_unit, bool reset_queu
// The semaphore always supposed to be taken successfully
assert(xSemaphoreTake(rx_unit->trans_sem, 0) == pdTRUE);
if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_enable_clock(hal->regs, false);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, false);
}
}
s_parlio_set_delimiter_config(rx_unit, trans.delimiter);
s_parlio_mount_transaction_buffer(rx_unit, &trans);
gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc);
if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_start(hal->regs, true);
parlio_ll_rx_enable_clock(hal->regs, true);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, true);
}
}
}
err:
@ -691,7 +762,9 @@ esp_err_t parlio_rx_unit_disable(parlio_rx_unit_handle_t rx_unit)
rx_unit->is_enabled = false;
/* stop the RX engine */
gdma_stop(rx_unit->dma_chan);
parlio_ll_rx_enable_clock(hal->regs, false);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(hal->regs, false);
}
parlio_ll_rx_start(hal->regs, false);
if (rx_unit->curr_trans.delimiter) {
portENTER_CRITICAL(&s_rx_spinlock);
@ -842,7 +915,9 @@ static esp_err_t s_parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit
portEXIT_CRITICAL_ISR(&s_rx_spinlock);
if (is_stopped) {
if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, false);
}
}
if (trans->delimiter != rx_unit->curr_trans.delimiter) {
s_parlio_set_delimiter_config(rx_unit, trans->delimiter);
@ -853,7 +928,9 @@ static esp_err_t s_parlio_rx_unit_do_transaction(parlio_rx_unit_handle_t rx_unit
gdma_start(rx_unit->dma_chan, (intptr_t)rx_unit->curr_desc);
if (rx_unit->cfg.flags.free_clk) {
parlio_ll_rx_start(rx_unit->base.group->hal.regs, true);
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true);
PARLIO_CLOCK_SRC_ATOMIC() {
parlio_ll_rx_enable_clock(rx_unit->base.group->hal.regs, true);
}
}
} else { // Otherwise send to the queue
/* Send the transaction to the queue */
@ -871,8 +948,17 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit,
ESP_RETURN_ON_FALSE(rx_unit && payload && recv_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
ESP_RETURN_ON_FALSE(recv_cfg->delimiter, ESP_ERR_INVALID_ARG, TAG, "no delimiter specified");
ESP_RETURN_ON_FALSE(payload_size <= rx_unit->max_recv_size, ESP_ERR_INVALID_ARG, TAG, "trans length too large");
uint32_t alignment = rx_unit->base.group->dma_align;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
ESP_RETURN_ON_FALSE(payload_size % alignment == 0, ESP_ERR_INVALID_ARG, TAG, "The payload size should align with %"PRIu32, alignment);
if (recv_cfg->flags.partial_rx_en) {
ESP_RETURN_ON_FALSE(payload_size >= 2 * alignment, ESP_ERR_INVALID_ARG, TAG, "The payload size should greater than %"PRIu32, 2 * alignment);
}
#endif
#if CONFIG_GDMA_ISR_IRAM_SAFE
ESP_RETURN_ON_FALSE(esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM");
#else
ESP_RETURN_ON_FALSE(recv_cfg->flags.indirect_mount || esp_ptr_internal(payload), ESP_ERR_INVALID_ARG, TAG, "payload not in internal RAM");
#endif
if (recv_cfg->delimiter->eof_data_len) {
ESP_RETURN_ON_FALSE(payload_size >= recv_cfg->delimiter->eof_data_len, ESP_ERR_INVALID_ARG,
@ -895,7 +981,7 @@ esp_err_t parlio_rx_unit_receive(parlio_rx_unit_handle_t rx_unit,
if (recv_cfg->flags.partial_rx_en && recv_cfg->flags.indirect_mount) {
ESP_RETURN_ON_FALSE(!rx_unit->dma_buf, ESP_ERR_INVALID_STATE, TAG, "infinite transaction is using the internal DMA buffer");
/* Allocate the internal DMA buffer to store the data temporary */
rx_unit->dma_buf = heap_caps_calloc(1, payload_size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
rx_unit->dma_buf = heap_caps_aligned_calloc(alignment, 1, payload_size, PARLIO_DMA_MEM_ALLOC_CAPS);
ESP_RETURN_ON_FALSE(rx_unit->dma_buf, ESP_ERR_NO_MEM, TAG, "No memory for the internal DMA buffer");
/* Use the internal DMA buffer so that the user buffer can always be available */
p_buffer = rx_unit->dma_buf;

View File

@ -405,7 +405,7 @@ static void IRAM_ATTR parlio_tx_mount_dma_data(parlio_tx_unit_t *tx_unit, const
#if CONFIG_IDF_TARGET_ESP32P4
// Write back to cache to synchronize the cache before DMA start
esp_cache_msync(buffer, len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
esp_cache_msync((void *)buffer, len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif // CONFIG_IDF_TARGET_ESP32P4
}

View File

@ -4,8 +4,8 @@ components/esp_driver_parlio/test_apps/parlio:
disable:
- if: SOC_PARLIO_SUPPORTED != 1
disable_test:
- if: IDF_TARGET == "esp32p4"
- if: IDF_TARGET in ["esp32h2", "esp32p4"]
temporary: true
reason: lack of runner
reason: IDF-9806 waiting for the fix of the bit shift issue after reset
depends_components:
- esp_driver_parlio

View File

@ -1,2 +1,2 @@
| Supported Targets | ESP32-C6 | ESP32-H2 |
| ----------------- | -------- | -------- |
| Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 |
| ----------------- | -------- | -------- | -------- |

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -18,6 +18,7 @@ extern "C" {
#define TEST_PARLIO_CALLBACK_ATTR
#define TEST_PARLIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif
#define TEST_PARLIO_DMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
#if CONFIG_IDF_TARGET_ESP32C6
#define TEST_CLK_GPIO 10
@ -42,15 +43,16 @@ extern "C" {
#define TEST_DATA6_GPIO 8
#define TEST_DATA7_GPIO 9
#elif CONFIG_IDF_TARGET_ESP32P4
#define TEST_CLK_GPIO 20
#define TEST_DATA0_GPIO 21
#define TEST_DATA1_GPIO 22
#define TEST_DATA2_GPIO 34
#define TEST_DATA3_GPIO 35
#define TEST_DATA4_GPIO 48
#define TEST_DATA5_GPIO 49
#define TEST_DATA6_GPIO 10
#define TEST_DATA7_GPIO 11
#define TEST_CLK_GPIO 32
#define TEST_VALID_GPIO 36
#define TEST_DATA0_GPIO 20
#define TEST_DATA1_GPIO 21
#define TEST_DATA2_GPIO 22
#define TEST_DATA3_GPIO 23
#define TEST_DATA4_GPIO 45
#define TEST_DATA5_GPIO 46
#define TEST_DATA6_GPIO 47
#define TEST_DATA7_GPIO 48
#else
#error "Unsupported target"
#endif

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -17,16 +17,26 @@
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "soc/soc_caps.h"
#include "soc/i2s_periph.h"
#include "soc/spi_periph.h"
#include "soc/parlio_periph.h"
#include "esp_dma_utils.h"
#include "esp_attr.h"
#include "test_board.h"
#define TEST_SPI_HOST SPI2_HOST
#define TEST_I2S_PORT I2S_NUM_0
#define TEST_VALID_SIG (PARLIO_RX_UNIT_MAX_DATA_WIDTH - 1)
#if SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT
#define TEST_OUTPUT_CLK_PIN TEST_CLK_GPIO
#else
#define TEST_OUTPUT_CLK_PIN -1
#endif
#define TEST_DEFAULT_UNIT_CONFIG(_clk_src, _clk_freq) { \
.trans_queue_depth = 10, \
.max_recv_size = 10 * 1024, \
@ -35,7 +45,7 @@
.ext_clk_freq_hz = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? _clk_freq : 0, \
.clk_in_gpio_num = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? TEST_CLK_GPIO : -1, \
.exp_clk_freq_hz = _clk_freq, \
.clk_out_gpio_num = -1, \
.clk_out_gpio_num = _clk_src == PARLIO_CLK_SRC_EXTERNAL ? -1 : TEST_OUTPUT_CLK_PIN, \
.valid_gpio_num = TEST_VALID_GPIO, \
.data_gpio_nums = { \
[0] = TEST_DATA0_GPIO, \
@ -56,6 +66,10 @@ typedef struct {
uint32_t timeout_cnt;
} test_data_t;
#ifndef ALIGN_UP
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
#endif
TEST_PARLIO_CALLBACK_ATTR
static bool test_parlio_rx_partial_recv_callback(parlio_rx_unit_handle_t rx_unit, const parlio_rx_event_data_t *edata, void *user_data)
{
@ -285,11 +299,15 @@ static bool test_delimiter(parlio_rx_delimiter_handle_t deli, bool free_running_
.delimiter = deli,
.flags.partial_rx_en = false,
};
uint8_t recv_buff[TEST_EOF_DATA_LEN];
uint8_t *recv_buff = NULL;
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
alignment = alignment < 4 ? 4 : alignment;
size_t buff_size = ALIGN_UP(TEST_EOF_DATA_LEN, alignment);
recv_buff = heap_caps_aligned_calloc(alignment, 1, buff_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS);
bool is_success = false;
// sample 5 times
for (int i = 0; i < 5 && !is_success; i++) {
TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, recv_buff, TEST_EOF_DATA_LEN, &recv_config));
TEST_ESP_OK(parlio_rx_unit_receive(rx_unit, recv_buff, buff_size, &recv_config));
TEST_ESP_OK(parlio_rx_unit_wait_all_done(rx_unit, 5000));
for (int k = 0; k < TEST_EOF_DATA_LEN; k++) {
printf("%x ", recv_buff[k]);
@ -315,6 +333,7 @@ static bool test_delimiter(parlio_rx_delimiter_handle_t deli, bool free_running_
}
// Delete the sender task
vTaskDelete(sender_task);
free(recv_buff);
TEST_ESP_OK(parlio_rx_unit_disable(rx_unit));
TEST_ESP_OK(parlio_del_rx_unit(rx_unit));
@ -409,8 +428,7 @@ TEST_CASE("parallel_rx_unit_install_uninstall", "[parlio_rx]")
TEST_ESP_OK(parlio_rx_unit_disable(units[0]));
TEST_ESP_OK(parlio_del_rx_unit(units[0]));
}
#define TEST_PAYLOAD_SIZE 5000
#define TEST_PAYLOAD_SIZE 5120
// This test case uses soft delimiter
TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]")
@ -444,7 +462,11 @@ TEST_CASE("parallel_rx_unit_receive_transaction_test", "[parlio_rx]")
.delimiter = deli,
.flags.partial_rx_en = false,
};
uint8_t *payload = heap_caps_calloc(1, TEST_PAYLOAD_SIZE, TEST_PARLIO_MEM_ALLOC_CAPS);
uint8_t *payload = NULL;
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
alignment = alignment < 4 ? 4 : alignment;
size_t payload_size = ALIGN_UP(TEST_PAYLOAD_SIZE, alignment);
payload = heap_caps_aligned_calloc(alignment, 1, payload_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS);
TEST_ASSERT(payload);
printf("Testing one normal transaction...\n");
@ -535,7 +557,11 @@ TEST_CASE("parallel_rx_unit_receive_timeout_test", "[parlio_rx]")
.delimiter = timeout_deli,
.flags.partial_rx_en = false,
};
uint8_t *payload = heap_caps_calloc(1, TEST_PAYLOAD_SIZE, TEST_PARLIO_MEM_ALLOC_CAPS);
uint8_t *payload = NULL;
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
alignment = alignment < 4 ? 4 : alignment;
size_t payload_size = ALIGN_UP(TEST_PAYLOAD_SIZE, alignment);
payload = heap_caps_aligned_calloc(alignment, 1, payload_size, TEST_PARLIO_DMA_MEM_ALLOC_CAPS);
TEST_ASSERT(payload);
printf("Testing the timeout callback...\n");

View File

@ -1,12 +1,10 @@
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32c6
@pytest.mark.esp32h2
@pytest.mark.generic
@pytest.mark.parametrize(
'config',

View File

@ -213,13 +213,13 @@ static inline void parlio_ll_rx_set_recv_bit_len(parl_io_dev_t *dev, uint32_t bi
* @brief Set the sub mode of the level controlled receive mode
*
* @param dev Parallel IO register base address
* @param active_level Level of the external enable signal, true for active high, false for active low
* @param active_low_en Level of the external enable signal, true for active low, false for active high
*/
__attribute__((always_inline))
static inline void parlio_ll_rx_set_level_recv_mode(parl_io_dev_t *dev, bool active_level)
static inline void parlio_ll_rx_set_level_recv_mode(parl_io_dev_t *dev, bool active_low_en)
{
dev->rx_mode_cfg.rx_smp_mode_sel = 0;
dev->rx_mode_cfg.rx_ext_en_inv = !active_level; // 0: active low, 1: active high
dev->rx_mode_cfg.rx_ext_en_inv = active_low_en;
}
/**
@ -359,7 +359,7 @@ static inline void parlio_ll_rx_treat_data_line_as_en(parl_io_dev_t *dev, uint32
}
/**
* @brief Wether to enable the RX clock gating
* @brief whether to enable the RX clock gating
*
* @param dev Parallel IO register base address
* @param en True to enable, False to disable
@ -519,7 +519,7 @@ static inline void parlio_ll_tx_set_eof_condition(parl_io_dev_t *dev, parlio_ll_
}
/**
* @brief Wether to enable the TX clock gating
* @brief whether to enable the TX clock gating
*
* @note The MSB of TXD will be taken as the gating enable signal
*
@ -589,7 +589,6 @@ static inline void parlio_ll_tx_set_bus_width(parl_io_dev_t *dev, uint32_t width
{
uint32_t width_sel = 0;
switch (width) {
// TODO: check this field (IDF-8284)
case 16:
width_sel = 4;
break;

View File

@ -58,6 +58,7 @@ ESP_STATIC_ASSERT(sizeof(dma_descriptor_align8_t) == 16, "dma_descriptor_align8_
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE (4095) /*!< Maximum size of the buffer that can be attached to descriptor */
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED (4095-3) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 4B */
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_16B_ALIGNED (4095-15) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 16B */
#define DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED (4095-63) /*!< Maximum size of the buffer that can be attached to descriptor, and aligned to 64B */
/**
* Get the number of DMA descriptors required for a given buffer size.

View File

@ -63,6 +63,10 @@ config SOC_ETM_SUPPORTED
bool
default y
config SOC_PARLIO_SUPPORTED
bool
default y
config SOC_ASYNC_MEMCPY_SUPPORTED
bool
default y
@ -1011,6 +1015,10 @@ config SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH
int
default 16
config SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT
bool
default y
config SOC_PARLIO_TX_SIZE_BY_DMA
bool
default y

View File

@ -635,8 +635,8 @@ typedef enum {
*/
typedef enum {
PARLIO_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
PARLIO_CLK_SRC_PLL_F160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
PARLIO_CLK_SRC_RC_FAST = SOC_MOD_CLK_RC_FAST, /*!< Select RC_FAST as the source clock */
PARLIO_CLK_SRC_PLL_F160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
PARLIO_CLK_SRC_EXTERNAL = -1, /*!< Select EXTERNAL clock as the source clock */
PARLIO_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */
} soc_periph_parlio_clk_src_t;

View File

@ -34,7 +34,7 @@
#define SOC_MCPWM_SUPPORTED 1
#define SOC_TWAI_SUPPORTED 1
#define SOC_ETM_SUPPORTED 1
// #define SOC_PARLIO_SUPPORTED 1 //TODO: IDF-7471
#define SOC_PARLIO_SUPPORTED 1
#define SOC_ASYNC_MEMCPY_SUPPORTED 1
#define SOC_EMAC_SUPPORTED 1
#define SOC_USB_OTG_SUPPORTED 1
@ -398,6 +398,7 @@
#define SOC_PARLIO_RX_UNITS_PER_GROUP 1U /*!< number of RX units in each group */
#define SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the TX unit */
#define SOC_PARLIO_RX_UNIT_MAX_DATA_WIDTH 16 /*!< Number of data lines of the RX unit */
#define SOC_PARLIO_RX_CLK_SUPPORT_OUTPUT 1 /*!< Support output RX clock to a GPIO */
#define SOC_PARLIO_TX_SIZE_BY_DMA 1 /*!< Transaction length is controlled by DMA instead of indicated by register */
/*--------------------------- MPI CAPS ---------------------------------------*/

View File

@ -261,9 +261,11 @@ examples/peripherals/parlio:
examples/peripherals/parlio/parlio_rx:
disable:
- if: SOC_PARLIO_SUPPORTED != 1 or IDF_TARGET == "esp32p4"
- if: SOC_PARLIO_SUPPORTED != 1
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: not support esp32p4 yet (IDF-7471)
reason: lack of runner
depends_components:
- esp_driver_parlio

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32-C6 | ESP32-H2 |
| ----------------- | -------- | -------- |
| Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 |
| ----------------- | -------- | -------- | -------- |
# Logic Analyzer Example

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -11,6 +11,8 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "soc/soc_caps.h"
#include "hal/dma_types.h"
#include "esp_heap_caps.h"
#include "esp_probe.h"
@ -19,12 +21,17 @@ extern "C" {
#endif
#define ESP_PROBE_DEFAULT_Q_DEPTH 8
#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * 4092)
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_64B_ALIGNED)
#else
#define ESP_PROBE_DEFAULT_MAX_RECV_SIZE (ESP_PROBE_DEFAULT_Q_DEPTH * DMA_DESCRIPTOR_BUFFER_MAX_SIZE_4B_ALIGNED)
#endif
#if CONFIG_PARLIO_ISR_IRAM_SAFE
#define ESP_PROBE_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else
#define ESP_PROBE_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif
#define ESP_PROBE_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
struct esp_probe_t {
uint32_t sample_width; /*!< sample width, i.e., enabled probe channel nums */

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -8,8 +8,11 @@
#include <string.h>
#include "sdkconfig.h"
#include "driver/parlio_rx.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_clk_tree.h"
#include "esp_heap_caps.h"
#include "esp_dma_utils.h"
#include "esp_check.h"
#include "esp_probe_private.h"
@ -43,7 +46,11 @@ esp_err_t esp_probe_priv_init_hardware(esp_probe_handle_t handle, esp_probe_conf
esp_err_t ret = ESP_OK;
s_ephi = calloc(1, sizeof(esp_probe_impl_pralio_t));
ESP_RETURN_ON_FALSE(s_ephi, ESP_ERR_NO_MEM, TAG, "no memory for the esp probe hardware implementation");
s_ephi->payload = heap_caps_calloc(1, ESP_PROBE_DEFAULT_MAX_RECV_SIZE, ESP_PROBE_ALLOC_CAPS);
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
alignment = alignment < 4 ? 4 : alignment;
size_t payload_aligned_size = ESP_PROBE_DEFAULT_MAX_RECV_SIZE & ~(alignment - 1);
s_ephi->payload = heap_caps_aligned_calloc(alignment, 1, payload_aligned_size, ESP_PROBE_DMA_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(s_ephi->payload, ESP_ERR_NO_MEM, err, TAG, "no memory for payload");
// Get the channel number, the channel number can only be the power of 2

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32-C6 | ESP32-H2 |
| ----------------- | -------- | -------- |
| Supported Targets | ESP32-C6 | ESP32-H2 | ESP32-P4 |
| ----------------- | -------- | -------- | -------- |
# Parallel IO TX Example: Simple RGB LED Matrix