mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/parlio_coverity_issue' into 'master'
feat(parlio_tx): minor clean up and fix Closes IDF-9420 See merge request espressif/esp-idf!29663
This commit is contained in:
commit
3a9d082523
@ -8,5 +8,5 @@ endif()
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
INCLUDE_DIRS ${public_include}
|
||||
PRIV_REQUIRES "esp_pm" "esp_driver_gpio"
|
||||
PRIV_REQUIRES "esp_pm" "esp_driver_gpio" "esp_mm"
|
||||
)
|
||||
|
@ -150,6 +150,9 @@ esp_err_t parlio_tx_unit_register_event_callbacks(parlio_tx_unit_handle_t tx_uni
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t idle_value; /*!< The value on the data line when the parallel IO is in idle state */
|
||||
struct {
|
||||
uint32_t queue_nonblocking : 1; /*!< If set, when the transaction queue is full, driver will not block the thread but return directly */
|
||||
} flags; /*!< Transmit specific config flags */
|
||||
} parlio_transmit_config_t;
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
*/
|
||||
@ -42,8 +42,6 @@ parlio_group_t *parlio_acquire_group_handle(int group_id)
|
||||
if (group) {
|
||||
new_group = true;
|
||||
s_platform.groups[group_id] = group;
|
||||
group->group_id = group_id;
|
||||
group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED;
|
||||
PARLIO_RCC_ATOMIC() {
|
||||
parlio_ll_enable_bus_clock(group_id, true);
|
||||
parlio_ll_reset_register(group_id);
|
||||
@ -61,6 +59,8 @@ parlio_group_t *parlio_acquire_group_handle(int group_id)
|
||||
_lock_release(&s_platform.mutex);
|
||||
|
||||
if (new_group) {
|
||||
portMUX_INITIALIZE(&group->spinlock);
|
||||
group->group_id = group_id;
|
||||
ESP_LOGD(TAG, "new group(%d) at %p", group_id, group);
|
||||
}
|
||||
return group;
|
||||
@ -81,11 +81,11 @@ void parlio_release_group_handle(parlio_group_t *group)
|
||||
PARLIO_RCC_ATOMIC() {
|
||||
parlio_ll_enable_bus_clock(group_id, false);
|
||||
}
|
||||
free(group);
|
||||
}
|
||||
_lock_release(&s_platform.mutex);
|
||||
|
||||
if (do_deinitialize) {
|
||||
free(group);
|
||||
ESP_LOGD(TAG, "del group(%d)", group_id);
|
||||
}
|
||||
}
|
||||
@ -96,23 +96,20 @@ esp_err_t parlio_register_unit_to_group(parlio_unit_base_handle_t unit)
|
||||
int unit_id = -1;
|
||||
for (int i = 0; i < SOC_PARLIO_GROUPS; i++) {
|
||||
group = parlio_acquire_group_handle(i);
|
||||
parlio_unit_base_handle_t *group_unit = NULL;
|
||||
ESP_RETURN_ON_FALSE(group, ESP_ERR_NO_MEM, TAG, "no memory for group (%d)", i);
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
if (unit->dir == PARLIO_DIR_TX) {
|
||||
for (int j = 0; j < SOC_PARLIO_TX_UNITS_PER_GROUP; j++) {
|
||||
group_unit = &group->tx_units[j];
|
||||
if (*group_unit == NULL) {
|
||||
*group_unit = unit;
|
||||
if (!group->tx_units[j]) {
|
||||
group->tx_units[j] = unit;
|
||||
unit_id = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < SOC_PARLIO_RX_UNITS_PER_GROUP; j++) {
|
||||
group_unit = &group->rx_units[j];
|
||||
if (*group_unit == NULL) {
|
||||
*group_unit = unit;
|
||||
if (!group->rx_units[j]) {
|
||||
group->rx_units[j] = unit;
|
||||
unit_id = j;
|
||||
break;
|
||||
}
|
||||
@ -122,7 +119,6 @@ esp_err_t parlio_register_unit_to_group(parlio_unit_base_handle_t unit)
|
||||
if (unit_id < 0) {
|
||||
/* didn't find a free unit slot in the group */
|
||||
parlio_release_group_handle(group);
|
||||
group = NULL;
|
||||
} else {
|
||||
unit->unit_id = unit_id;
|
||||
unit->group = group;
|
||||
@ -138,11 +134,12 @@ void parlio_unregister_unit_from_group(parlio_unit_base_handle_t unit)
|
||||
{
|
||||
assert(unit);
|
||||
parlio_group_t *group = unit->group;
|
||||
int unit_id = unit->unit_id;
|
||||
portENTER_CRITICAL(&group->spinlock);
|
||||
if (unit->dir == PARLIO_DIR_TX) {
|
||||
group->tx_units[unit->unit_id] = NULL;
|
||||
group->tx_units[unit_id] = NULL;
|
||||
} else {
|
||||
group->rx_units[unit->unit_id] = NULL;
|
||||
group->rx_units[unit_id] = NULL;
|
||||
}
|
||||
portEXIT_CRITICAL(&group->spinlock);
|
||||
/* the parlio unit has a reference of the group, release it now */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -10,6 +10,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/gdma_channel.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "hal/parlio_types.h"
|
||||
#include "hal/parlio_hal.h"
|
||||
#include "hal/parlio_ll.h"
|
||||
@ -19,7 +20,10 @@
|
||||
#include "rom/cache.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "driver/parlio_types.h"
|
||||
#include "esp_cache.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/esp_gpio_reserve.h"
|
||||
#include "esp_private/gpio.h"
|
||||
|
||||
#if CONFIG_PARLIO_ISR_IRAM_SAFE
|
||||
#define PARLIO_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
|
||||
@ -51,6 +55,8 @@ typedef dma_descriptor_align8_t parlio_dma_desc_t;
|
||||
#endif
|
||||
#endif // defined(SOC_GDMA_TRIG_PERIPH_PARLIO0_BUS)
|
||||
|
||||
#define ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
#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)
|
||||
@ -77,12 +83,12 @@ typedef dma_descriptor_align8_t parlio_dma_desc_t;
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
typedef enum {
|
||||
PARLIO_TX_QUEUE_READY,
|
||||
PARLIO_TX_QUEUE_PROGRESS,
|
||||
PARLIO_TX_QUEUE_COMPLETE,
|
||||
PARLIO_TX_QUEUE_MAX,
|
||||
};
|
||||
} parlio_tx_queue_status_t;
|
||||
|
||||
typedef enum {
|
||||
PARLIO_DIR_TX,
|
||||
@ -101,21 +107,20 @@ 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 for each group
|
||||
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
|
||||
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;
|
||||
|
||||
/**
|
||||
* @brief The common field of rx and tx unit structure
|
||||
*
|
||||
*/
|
||||
struct parlio_unit_t {
|
||||
int unit_id; // unit id
|
||||
parlio_dir_t dir;
|
||||
parlio_group_t *group; // group handle
|
||||
int unit_id; // unit id
|
||||
parlio_dir_t dir; // direction
|
||||
parlio_group_t *group; // group handle
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
*/
|
||||
@ -28,7 +28,6 @@
|
||||
#include "esp_pm.h"
|
||||
#include "soc/parlio_periph.h"
|
||||
#include "hal/parlio_ll.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/parlio_tx.h"
|
||||
#include "parlio_private.h"
|
||||
@ -50,6 +49,9 @@ typedef struct parlio_tx_unit_t {
|
||||
intr_handle_t intr; // allocated interrupt handle
|
||||
esp_pm_lock_handle_t pm_lock; // power management lock
|
||||
gdma_channel_handle_t dma_chan; // DMA channel
|
||||
parlio_dma_desc_t *dma_nodes; // DMA descriptor nodes
|
||||
parlio_dma_desc_t *dma_nodes_nc;// non-cached DMA descriptor nodes
|
||||
size_t dma_nodes_num; // number of DMA descriptor nodes
|
||||
#if CONFIG_PM_ENABLE
|
||||
char pm_lock_name[PARLIO_PM_LOCK_NAME_LEN_MAX]; // pm lock name
|
||||
#endif
|
||||
@ -64,7 +66,6 @@ typedef struct parlio_tx_unit_t {
|
||||
_Atomic parlio_tx_fsm_t fsm; // Driver FSM state
|
||||
parlio_tx_done_callback_t on_trans_done; // callback function when the transmission is done
|
||||
void *user_data; // user data passed to the callback function
|
||||
parlio_dma_desc_t *dma_nodes; // DMA descriptor nodes
|
||||
parlio_tx_trans_desc_t trans_desc_pool[]; // transaction descriptor pool
|
||||
} parlio_tx_unit_t;
|
||||
|
||||
@ -122,7 +123,9 @@ static esp_err_t parlio_destroy_tx_unit(parlio_tx_unit_t *tx_unit)
|
||||
// de-register from group
|
||||
parlio_unregister_unit_from_group(&tx_unit->base);
|
||||
}
|
||||
free(tx_unit->dma_nodes);
|
||||
if (tx_unit->dma_nodes) {
|
||||
free(tx_unit->dma_nodes);
|
||||
}
|
||||
free(tx_unit);
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -145,8 +148,7 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const
|
||||
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config data GPIO failed");
|
||||
esp_rom_gpio_connect_out_signal(config->data_gpio_nums[i],
|
||||
parlio_periph_signals.groups[group_id].tx_units[unit_id].data_sigs[i], false, false);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->data_gpio_nums[i]], PIN_FUNC_GPIO);
|
||||
|
||||
gpio_func_sel(config->data_gpio_nums[i], PIN_FUNC_GPIO);
|
||||
}
|
||||
}
|
||||
// Note: the valid signal will override TXD[PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG]
|
||||
@ -156,14 +158,14 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const
|
||||
esp_rom_gpio_connect_out_signal(config->valid_gpio_num,
|
||||
parlio_periph_signals.groups[group_id].tx_units[unit_id].data_sigs[PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG],
|
||||
false, false);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->valid_gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_func_sel(config->valid_gpio_num, PIN_FUNC_GPIO);
|
||||
}
|
||||
if (config->clk_out_gpio_num >= 0) {
|
||||
gpio_conf.pin_bit_mask = BIT64(config->clk_out_gpio_num);
|
||||
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config clk out GPIO failed");
|
||||
esp_rom_gpio_connect_out_signal(config->clk_out_gpio_num,
|
||||
parlio_periph_signals.groups[group_id].tx_units[unit_id].clk_out_sig, false, false);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->clk_out_gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_func_sel(config->clk_out_gpio_num, PIN_FUNC_GPIO);
|
||||
}
|
||||
if (config->clk_in_gpio_num >= 0) {
|
||||
gpio_conf.mode = config->flags.io_loop_back ? GPIO_MODE_INPUT_OUTPUT : GPIO_MODE_INPUT;
|
||||
@ -171,7 +173,7 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const
|
||||
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config clk in GPIO failed");
|
||||
esp_rom_gpio_connect_in_signal(config->clk_in_gpio_num,
|
||||
parlio_periph_signals.groups[group_id].tx_units[unit_id].clk_in_sig, false);
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[config->clk_in_gpio_num], PIN_FUNC_GPIO);
|
||||
gpio_func_sel(config->clk_in_gpio_num, PIN_FUNC_GPIO);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -188,6 +190,12 @@ static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit)
|
||||
.owner_check = true,
|
||||
};
|
||||
gdma_apply_strategy(tx_unit->dma_chan, &gdma_strategy_conf);
|
||||
|
||||
// Link the descriptors
|
||||
size_t dma_nodes_num = tx_unit->dma_nodes_num;
|
||||
for (int i = 0; i < dma_nodes_num; i++) {
|
||||
tx_unit->dma_nodes_nc[i].next = (i == dma_nodes_num - 1) ? NULL : &(tx_unit->dma_nodes[i + 1]);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -247,36 +255,51 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
|
||||
#endif
|
||||
esp_err_t ret = ESP_OK;
|
||||
parlio_tx_unit_t *unit = NULL;
|
||||
ESP_GOTO_ON_FALSE(config && ret_unit, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(config && ret_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
size_t data_width = config->data_width;
|
||||
// data_width must be power of 2 and less than or equal to SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH
|
||||
ESP_GOTO_ON_FALSE(data_width && (data_width <= SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH) && ((data_width & (data_width - 1)) == 0),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "invalid data width");
|
||||
ESP_RETURN_ON_FALSE(data_width && (data_width <= SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH) && ((data_width & (data_width - 1)) == 0),
|
||||
ESP_ERR_INVALID_ARG, TAG, "invalid data width");
|
||||
// data_width must not conflict with the valid signal
|
||||
ESP_GOTO_ON_FALSE(!(config->valid_gpio_num >= 0 && data_width > PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "valid signal conflicts with data signal");
|
||||
ESP_GOTO_ON_FALSE(config->max_transfer_size && config->max_transfer_size <= PARLIO_LL_TX_MAX_BITS_PER_FRAME / 8,
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "invalid max transfer size");
|
||||
ESP_RETURN_ON_FALSE(!(config->valid_gpio_num >= 0 && data_width > PARLIO_LL_TX_DATA_LINE_AS_VALID_SIG),
|
||||
ESP_ERR_INVALID_ARG, TAG, "valid signal conflicts with data signal");
|
||||
ESP_RETURN_ON_FALSE(config->max_transfer_size && config->max_transfer_size <= PARLIO_LL_TX_MAX_BITS_PER_FRAME / 8,
|
||||
ESP_ERR_INVALID_ARG, TAG, "invalid max transfer size");
|
||||
#if SOC_PARLIO_TX_CLK_SUPPORT_GATING
|
||||
// clock gating is controlled by either the MSB bit of data bus or the valid signal
|
||||
ESP_GOTO_ON_FALSE(!(config->flags.clk_gate_en && config->valid_gpio_num < 0 && config->data_width <= PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE),
|
||||
ESP_ERR_INVALID_ARG, err, TAG, "no gpio can control the clock gating");
|
||||
ESP_RETURN_ON_FALSE(!(config->flags.clk_gate_en && config->valid_gpio_num < 0 && config->data_width <= PARLIO_LL_TX_DATA_LINE_AS_CLK_GATE),
|
||||
ESP_ERR_INVALID_ARG, TAG, "no gpio can control the clock gating");
|
||||
#else
|
||||
ESP_GOTO_ON_FALSE(config->flags.clk_gate_en == 0, ESP_ERR_NOT_SUPPORTED, err, TAG, "clock gating is not supported");
|
||||
ESP_RETURN_ON_FALSE(config->flags.clk_gate_en == 0, ESP_ERR_NOT_SUPPORTED, TAG, "clock gating is not supported");
|
||||
#endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING
|
||||
|
||||
// malloc unit memory
|
||||
unit = heap_caps_calloc(1, sizeof(parlio_tx_unit_t) + sizeof(parlio_tx_trans_desc_t) * config->trans_queue_depth, PARLIO_MEM_ALLOC_CAPS);
|
||||
uint32_t mem_caps = PARLIO_MEM_ALLOC_CAPS;
|
||||
unit = heap_caps_calloc(1, sizeof(parlio_tx_unit_t) + sizeof(parlio_tx_trans_desc_t) * config->trans_queue_depth, mem_caps);
|
||||
ESP_GOTO_ON_FALSE(unit, ESP_ERR_NO_MEM, err, TAG, "no memory for tx unit");
|
||||
size_t dma_nodes_num = config->max_transfer_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE + 1;
|
||||
// DMA descriptors must be placed in internal SRAM
|
||||
|
||||
unit->dma_nodes = heap_caps_aligned_calloc(PARLIO_DMA_DESC_ALIGNMENT, dma_nodes_num, sizeof(parlio_dma_desc_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA);
|
||||
ESP_GOTO_ON_FALSE(unit->dma_nodes, ESP_ERR_NO_MEM, err, TAG, "no memory for DMA nodes");
|
||||
// Link the descriptors
|
||||
for (int i = 0; i < dma_nodes_num; i++) {
|
||||
unit->dma_nodes[i].next = (i == dma_nodes_num - 1) ? NULL : &(unit->dma_nodes[i + 1]);
|
||||
// create DMA descriptors
|
||||
// DMA descriptors must be placed in internal SRAM
|
||||
mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
|
||||
size_t dma_nodes_num = config->max_transfer_size / DMA_DESCRIPTOR_BUFFER_MAX_SIZE + 1;
|
||||
uint32_t data_cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
|
||||
// the alignment should meet both the DMA and cache requirement
|
||||
size_t alignment = MAX(data_cache_line_size, PARLIO_DMA_DESC_ALIGNMENT);
|
||||
size_t dma_nodes_mem_size = ALIGN_UP(dma_nodes_num * sizeof(parlio_dma_desc_t), alignment);
|
||||
parlio_dma_desc_t *dma_nodes = heap_caps_aligned_calloc(alignment, 1, dma_nodes_mem_size, mem_caps);
|
||||
ESP_GOTO_ON_FALSE(dma_nodes, ESP_ERR_NO_MEM, err, TAG, "no memory for DMA nodes");
|
||||
unit->dma_nodes = dma_nodes;
|
||||
unit->dma_nodes_num = dma_nodes_num;
|
||||
|
||||
// write back and then invalidate the cached dma_nodes, we will skip the cache (by non-cacheable address) when access the dma_nodes
|
||||
if (data_cache_line_size) {
|
||||
ESP_GOTO_ON_ERROR(esp_cache_msync(dma_nodes, dma_nodes_mem_size,
|
||||
ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE),
|
||||
err, TAG, "cache sync failed");
|
||||
}
|
||||
// we will use the non-cached address to manipulate the DMA descriptor, for simplicity
|
||||
unit->dma_nodes_nc = PARLIO_GET_NON_CACHED_DESC_ADDR(dma_nodes);
|
||||
|
||||
unit->max_transfer_bits = config->max_transfer_size * 8;
|
||||
unit->base.dir = PARLIO_DIR_TX;
|
||||
unit->data_width = data_width;
|
||||
@ -362,27 +385,27 @@ esp_err_t parlio_del_tx_unit(parlio_tx_unit_handle_t unit)
|
||||
return parlio_destroy_tx_unit(unit);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR parlio_tx_mount_dma_data(parlio_dma_desc_t *desc_head, const void *buffer, size_t len)
|
||||
static void IRAM_ATTR parlio_tx_mount_dma_data(parlio_tx_unit_t *tx_unit, const void *buffer, size_t len)
|
||||
{
|
||||
size_t prepared_length = 0;
|
||||
uint8_t *data = (uint8_t *)buffer;
|
||||
parlio_dma_desc_t *desc = desc_head;
|
||||
parlio_dma_desc_t *desc_nc = tx_unit->dma_nodes_nc;
|
||||
|
||||
while (len) {
|
||||
parlio_dma_desc_t *non_cache_desc = PARLIO_GET_NON_CACHED_DESC_ADDR(desc);
|
||||
uint32_t mount_bytes = len > DMA_DESCRIPTOR_BUFFER_MAX_SIZE ? DMA_DESCRIPTOR_BUFFER_MAX_SIZE : len;
|
||||
len -= mount_bytes;
|
||||
non_cache_desc->dw0.suc_eof = len == 0; // whether the last frame
|
||||
non_cache_desc->dw0.size = mount_bytes;
|
||||
non_cache_desc->dw0.length = mount_bytes;
|
||||
non_cache_desc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
|
||||
non_cache_desc->buffer = &data[prepared_length];
|
||||
desc = desc->next; // move to next descriptor
|
||||
desc_nc->dw0.suc_eof = (len == 0); // whether the last frame
|
||||
desc_nc->dw0.size = mount_bytes;
|
||||
desc_nc->dw0.length = mount_bytes;
|
||||
desc_nc->dw0.owner = DMA_DESCRIPTOR_BUFFER_OWNER_DMA;
|
||||
desc_nc->buffer = &data[prepared_length];
|
||||
desc_nc = PARLIO_GET_NON_CACHED_DESC_ADDR(desc_nc->next);
|
||||
prepared_length += mount_bytes;
|
||||
}
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32P4
|
||||
// Write back to cache to synchronize the cache before DMA start
|
||||
Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)buffer, len);
|
||||
esp_cache_msync(buffer, len, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
|
||||
#endif // CONFIG_IDF_TARGET_ESP32P4
|
||||
}
|
||||
|
||||
@ -428,7 +451,7 @@ static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio
|
||||
tx_unit->cur_trans = t;
|
||||
|
||||
// DMA transfer data based on bytes not bits, so convert the bit length to bytes, round up
|
||||
parlio_tx_mount_dma_data(tx_unit->dma_nodes, t->payload, (t->payload_bits + 7) / 8);
|
||||
parlio_tx_mount_dma_data(tx_unit, t->payload, (t->payload_bits + 7) / 8);
|
||||
|
||||
parlio_ll_tx_reset_fifo(hal->regs);
|
||||
PARLIO_RCC_ATOMIC() {
|
||||
@ -529,10 +552,14 @@ esp_err_t parlio_tx_unit_transmit(parlio_tx_unit_handle_t tx_unit, const void *p
|
||||
ESP_RETURN_ON_FALSE((payload_bits % 8) == 0, ESP_ERR_INVALID_ARG, TAG, "payload bit length must be multiple of 8");
|
||||
#endif // !SOC_PARLIO_TRANS_BIT_ALIGN
|
||||
|
||||
// acquire one transaction description from ready queue or complete queue
|
||||
TickType_t queue_wait_ticks = portMAX_DELAY;
|
||||
if (config->flags.queue_nonblocking) {
|
||||
queue_wait_ticks = 0;
|
||||
}
|
||||
parlio_tx_trans_desc_t *t = NULL;
|
||||
// acquire one transaction description from ready queue or complete queue
|
||||
if (xQueueReceive(tx_unit->trans_queues[PARLIO_TX_QUEUE_READY], &t, 0) != pdTRUE) {
|
||||
if (xQueueReceive(tx_unit->trans_queues[PARLIO_TX_QUEUE_COMPLETE], &t, 0) == pdTRUE) {
|
||||
if (xQueueReceive(tx_unit->trans_queues[PARLIO_TX_QUEUE_COMPLETE], &t, queue_wait_ticks) == pdTRUE) {
|
||||
tx_unit->num_trans_inflight--;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
@ -16,7 +16,6 @@
|
||||
#include "hal/hal_utils.h"
|
||||
#include "soc/hp_sys_clkrst_struct.h"
|
||||
#include "soc/parl_io_struct.h"
|
||||
#include "soc/hp_sys_clkrst_struct.h"
|
||||
|
||||
#define PARLIO_LL_RX_MAX_BYTES_PER_FRAME 0xFFFF
|
||||
#define PARLIO_LL_RX_MAX_CLK_INT_DIV 0x100
|
||||
@ -40,13 +39,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
PARLIO_LL_CLK_SRC_XTAL = PARLIO_CLK_SRC_XTAL,
|
||||
PARLIO_LL_CLK_SRC_PLL_F160M = PARLIO_CLK_SRC_PLL_F160M,
|
||||
PARLIO_LL_CLK_SRC_RC_FAST = PARLIO_CLK_SRC_RC_FAST,
|
||||
PARLIO_LL_CLK_SRC_PAD = PARLIO_CLK_SRC_EXTERNAL, // clock source from GPIO pad
|
||||
} parlio_ll_clock_source_t;
|
||||
|
||||
typedef enum {
|
||||
PARLIO_LL_RX_EOF_COND_RX_FULL, /*!< RX unit generates EOF event when it receives enough data */
|
||||
PARLIO_LL_RX_EOF_COND_EN_INACTIVE, /*!< RX unit generates EOF event when the external enable signal becomes inactive */
|
||||
@ -63,22 +55,23 @@ typedef enum {
|
||||
* @param group_id The group id of the parlio module
|
||||
* @param enable Set true to enable, false to disable
|
||||
*/
|
||||
static inline void parlio_ll_enable_bus_clock(int group_id, bool enable)
|
||||
static inline void _parlio_ll_enable_bus_clock(int group_id, bool enable)
|
||||
{
|
||||
(void)group_id;
|
||||
HP_SYS_CLKRST.soc_clk_ctrl1.reg_parlio_sys_clk_en = enable;
|
||||
HP_SYS_CLKRST.soc_clk_ctrl2.reg_parlio_apb_clk_en = enable;
|
||||
}
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_enable_bus_clock(__VA_ARGS__)
|
||||
#define parlio_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_enable_bus_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Reset the parlio module
|
||||
*
|
||||
* @param group_id The group id of the parlio module
|
||||
*/
|
||||
static inline void parlio_ll_reset_register(int group_id)
|
||||
static inline void _parlio_ll_reset_register(int group_id)
|
||||
{
|
||||
(void)group_id;
|
||||
HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_parlio = 1;
|
||||
@ -87,7 +80,7 @@ static inline void parlio_ll_reset_register(int group_id)
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_reset_register(__VA_ARGS__)
|
||||
#define parlio_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_reset_register(__VA_ARGS__)
|
||||
|
||||
///////////////////////////////////////RX Unit///////////////////////////////////////
|
||||
|
||||
@ -97,21 +90,21 @@ static inline void parlio_ll_reset_register(int group_id)
|
||||
* @param dev Parallel IO register base address
|
||||
* @param src Clock source
|
||||
*/
|
||||
static inline void parlio_ll_rx_set_clock_source(parl_io_dev_t *dev, parlio_ll_clock_source_t src)
|
||||
static inline void _parlio_ll_rx_set_clock_source(parl_io_dev_t *dev, parlio_clock_source_t src)
|
||||
{
|
||||
(void)dev;
|
||||
uint32_t clk_sel = 0;
|
||||
switch (src) {
|
||||
case PARLIO_LL_CLK_SRC_XTAL:
|
||||
case PARLIO_CLK_SRC_XTAL:
|
||||
clk_sel = 0;
|
||||
break;
|
||||
case PARLIO_LL_CLK_SRC_RC_FAST:
|
||||
case PARLIO_CLK_SRC_RC_FAST:
|
||||
clk_sel = 1;
|
||||
break;
|
||||
case PARLIO_LL_CLK_SRC_PLL_F160M:
|
||||
case PARLIO_CLK_SRC_PLL_F160M:
|
||||
clk_sel = 2;
|
||||
break;
|
||||
case PARLIO_LL_CLK_SRC_PAD:
|
||||
case PARLIO_CLK_SRC_EXTERNAL:
|
||||
clk_sel = 3;
|
||||
break;
|
||||
|
||||
@ -124,7 +117,7 @@ static inline void parlio_ll_rx_set_clock_source(parl_io_dev_t *dev, parlio_ll_c
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_rx_set_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_rx_set_clock_source(__VA_ARGS__)
|
||||
#define parlio_ll_rx_set_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_rx_set_clock_source(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Set the clock divider for the RX unit
|
||||
@ -132,7 +125,7 @@ static inline void parlio_ll_rx_set_clock_source(parl_io_dev_t *dev, parlio_ll_c
|
||||
* @param dev Parallel IO register base address
|
||||
* @param clk_div Clock division with integral and decimal part
|
||||
*/
|
||||
static inline void parlio_ll_rx_set_clock_div(parl_io_dev_t *dev, const hal_utils_clk_div_t *clk_div)
|
||||
static inline void _parlio_ll_rx_set_clock_div(parl_io_dev_t *dev, const hal_utils_clk_div_t *clk_div)
|
||||
{
|
||||
(void)dev;
|
||||
HAL_ASSERT(clk_div->integer > 0 && clk_div->integer <= PARLIO_LL_RX_MAX_CLK_INT_DIV);
|
||||
@ -143,14 +136,14 @@ static inline void parlio_ll_rx_set_clock_div(parl_io_dev_t *dev, const hal_util
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_rx_set_clock_div(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_rx_set_clock_div(__VA_ARGS__)
|
||||
#define parlio_ll_rx_set_clock_div(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_rx_set_clock_div(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Reset the RX unit Core clock domain
|
||||
*
|
||||
* @param dev Parallel IO register base address
|
||||
*/
|
||||
static inline void parlio_ll_rx_reset_clock(parl_io_dev_t *dev)
|
||||
static inline void _parlio_ll_rx_reset_clock(parl_io_dev_t *dev)
|
||||
{
|
||||
(void)dev;
|
||||
HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_parlio_rx = 1;
|
||||
@ -159,7 +152,7 @@ static inline void parlio_ll_rx_reset_clock(parl_io_dev_t *dev)
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_rx_reset_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_rx_reset_clock(__VA_ARGS__)
|
||||
#define parlio_ll_rx_reset_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_rx_reset_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Enable the RX unit Core clock domain
|
||||
@ -168,7 +161,7 @@ static inline void parlio_ll_rx_reset_clock(parl_io_dev_t *dev)
|
||||
* @param en True to enable, False to disable
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void parlio_ll_rx_enable_clock(parl_io_dev_t *dev, bool en)
|
||||
static inline void _parlio_ll_rx_enable_clock(parl_io_dev_t *dev, bool en)
|
||||
{
|
||||
(void)dev;
|
||||
HP_SYS_CLKRST.peri_clk_ctrl117.reg_parlio_rx_clk_en = en;
|
||||
@ -176,7 +169,7 @@ static inline void parlio_ll_rx_enable_clock(parl_io_dev_t *dev, bool en)
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_rx_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_rx_enable_clock(__VA_ARGS__)
|
||||
#define parlio_ll_rx_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_rx_enable_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Set the condition to generate the RX EOF event
|
||||
@ -420,21 +413,21 @@ static inline void parlio_ll_rx_update_config(parl_io_dev_t *dev)
|
||||
* @param dev Parallel IO register base address
|
||||
* @param src Clock source
|
||||
*/
|
||||
static inline void parlio_ll_tx_set_clock_source(parl_io_dev_t *dev, parlio_ll_clock_source_t src)
|
||||
static inline void _parlio_ll_tx_set_clock_source(parl_io_dev_t *dev, parlio_clock_source_t src)
|
||||
{
|
||||
(void)dev;
|
||||
uint32_t clk_sel = 0;
|
||||
switch (src) {
|
||||
case PARLIO_LL_CLK_SRC_XTAL:
|
||||
case PARLIO_CLK_SRC_XTAL:
|
||||
clk_sel = 0;
|
||||
break;
|
||||
case PARLIO_LL_CLK_SRC_RC_FAST:
|
||||
case PARLIO_CLK_SRC_RC_FAST:
|
||||
clk_sel = 1;
|
||||
break;
|
||||
case PARLIO_LL_CLK_SRC_PLL_F160M:
|
||||
case PARLIO_CLK_SRC_PLL_F160M:
|
||||
clk_sel = 2;
|
||||
break;
|
||||
case PARLIO_LL_CLK_SRC_PAD:
|
||||
case PARLIO_CLK_SRC_EXTERNAL:
|
||||
clk_sel = 3;
|
||||
break;
|
||||
|
||||
@ -447,7 +440,7 @@ static inline void parlio_ll_tx_set_clock_source(parl_io_dev_t *dev, parlio_ll_c
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_tx_set_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_tx_set_clock_source(__VA_ARGS__)
|
||||
#define parlio_ll_tx_set_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_tx_set_clock_source(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Set the clock divider for the TX unit
|
||||
@ -455,7 +448,7 @@ static inline void parlio_ll_tx_set_clock_source(parl_io_dev_t *dev, parlio_ll_c
|
||||
* @param dev Parallel IO register base address
|
||||
* @param clk_div Clock division with integral and decimal part
|
||||
*/
|
||||
static inline void parlio_ll_tx_set_clock_div(parl_io_dev_t *dev, const hal_utils_clk_div_t *clk_div)
|
||||
static inline void _parlio_ll_tx_set_clock_div(parl_io_dev_t *dev, const hal_utils_clk_div_t *clk_div)
|
||||
{
|
||||
(void)dev;
|
||||
HAL_ASSERT(clk_div->integer > 0 && clk_div->integer <= PARLIO_LL_RX_MAX_CLK_INT_DIV);
|
||||
@ -466,7 +459,7 @@ static inline void parlio_ll_tx_set_clock_div(parl_io_dev_t *dev, const hal_util
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_tx_set_clock_source(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_tx_set_clock_source(__VA_ARGS__)
|
||||
#define parlio_ll_tx_set_clock_div(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_tx_set_clock_div(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Reset the TX unit Core clock domain
|
||||
@ -474,7 +467,7 @@ static inline void parlio_ll_tx_set_clock_div(parl_io_dev_t *dev, const hal_util
|
||||
* @param dev Parallel IO register base address
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void parlio_ll_tx_reset_clock(parl_io_dev_t *dev)
|
||||
static inline void _parlio_ll_tx_reset_clock(parl_io_dev_t *dev)
|
||||
{
|
||||
(void)dev;
|
||||
HP_SYS_CLKRST.hp_rst_en2.reg_rst_en_parlio_tx = 1;
|
||||
@ -483,7 +476,7 @@ static inline void parlio_ll_tx_reset_clock(parl_io_dev_t *dev)
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_tx_reset_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_tx_reset_clock(__VA_ARGS__)
|
||||
#define parlio_ll_tx_reset_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_tx_reset_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Enable the TX unit Core clock domain
|
||||
@ -492,7 +485,7 @@ static inline void parlio_ll_tx_reset_clock(parl_io_dev_t *dev)
|
||||
* @param en True to enable, False to disable
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void parlio_ll_tx_enable_clock(parl_io_dev_t *dev, bool en)
|
||||
static inline void _parlio_ll_tx_enable_clock(parl_io_dev_t *dev, bool en)
|
||||
{
|
||||
(void)dev;
|
||||
HP_SYS_CLKRST.peri_clk_ctrl118.reg_parlio_tx_clk_en = en;
|
||||
@ -500,7 +493,7 @@ static inline void parlio_ll_tx_enable_clock(parl_io_dev_t *dev, bool en)
|
||||
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define parlio_ll_tx_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; parlio_ll_tx_enable_clock(__VA_ARGS__)
|
||||
#define parlio_ll_tx_enable_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _parlio_ll_tx_enable_clock(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Set the data length to be transmitted
|
||||
|
@ -593,11 +593,7 @@ typedef enum {
|
||||
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_EXTERNAL = -1, /*!< Select EXTERNAL clock as the source clock */
|
||||
#if SOC_CLK_TREE_SUPPORTED
|
||||
PARLIO_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default clock choice */
|
||||
#else
|
||||
PARLIO_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default clock choice */
|
||||
#endif
|
||||
} soc_periph_parlio_clk_src_t;
|
||||
|
||||
//////////////////////////////////////////////////SDMMC///////////////////////////////////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user