mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
refactor(parlio_tx): use gdma link list driver to mount buffer
This commit is contained in:
parent
c8de3754df
commit
35c6e44181
@ -17,4 +17,5 @@ endif()
|
|||||||
idf_component_register(SRCS ${srcs}
|
idf_component_register(SRCS ${srcs}
|
||||||
INCLUDE_DIRS ${public_include}
|
INCLUDE_DIRS ${public_include}
|
||||||
PRIV_REQUIRES "${priv_requires}"
|
PRIV_REQUIRES "${priv_requires}"
|
||||||
|
LDFRAGMENTS "linker.lf"
|
||||||
)
|
)
|
||||||
|
6
components/esp_driver_parlio/linker.lf
Normal file
6
components/esp_driver_parlio/linker.lf
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[mapping:parlio_driver_gdma]
|
||||||
|
archive: libesp_hw_support.a
|
||||||
|
entries:
|
||||||
|
if PARLIO_ISR_IRAM_SAFE:
|
||||||
|
gdma_link: gdma_link_mount_buffers (noflash)
|
||||||
|
gdma_link: gdma_link_get_head_addr (noflash)
|
@ -34,6 +34,7 @@
|
|||||||
#include "esp_memory_utils.h"
|
#include "esp_memory_utils.h"
|
||||||
#include "esp_clk_tree.h"
|
#include "esp_clk_tree.h"
|
||||||
#include "esp_private/gdma.h"
|
#include "esp_private/gdma.h"
|
||||||
|
#include "esp_private/gdma_link.h"
|
||||||
|
|
||||||
static const char *TAG = "parlio-tx";
|
static const char *TAG = "parlio-tx";
|
||||||
|
|
||||||
@ -49,8 +50,7 @@ typedef struct parlio_tx_unit_t {
|
|||||||
intr_handle_t intr; // allocated interrupt handle
|
intr_handle_t intr; // allocated interrupt handle
|
||||||
esp_pm_lock_handle_t pm_lock; // power management lock
|
esp_pm_lock_handle_t pm_lock; // power management lock
|
||||||
gdma_channel_handle_t dma_chan; // DMA channel
|
gdma_channel_handle_t dma_chan; // DMA channel
|
||||||
parlio_dma_desc_t *dma_nodes; // DMA descriptor nodes
|
gdma_link_list_handle_t dma_link; // DMA link list handle
|
||||||
parlio_dma_desc_t *dma_nodes_nc;// non-cached DMA descriptor nodes
|
|
||||||
size_t dma_nodes_num; // number of DMA descriptor nodes
|
size_t dma_nodes_num; // number of DMA descriptor nodes
|
||||||
#if CONFIG_PM_ENABLE
|
#if CONFIG_PM_ENABLE
|
||||||
char pm_lock_name[PARLIO_PM_LOCK_NAME_LEN_MAX]; // pm lock name
|
char pm_lock_name[PARLIO_PM_LOCK_NAME_LEN_MAX]; // pm lock name
|
||||||
@ -123,8 +123,8 @@ static esp_err_t parlio_destroy_tx_unit(parlio_tx_unit_t *tx_unit)
|
|||||||
// de-register from group
|
// de-register from group
|
||||||
parlio_unregister_unit_from_group(&tx_unit->base);
|
parlio_unregister_unit_from_group(&tx_unit->base);
|
||||||
}
|
}
|
||||||
if (tx_unit->dma_nodes) {
|
if (tx_unit->dma_link) {
|
||||||
free(tx_unit->dma_nodes);
|
ESP_RETURN_ON_ERROR(gdma_del_link_list(tx_unit->dma_link), TAG, "delete dma link list failed");
|
||||||
}
|
}
|
||||||
free(tx_unit);
|
free(tx_unit);
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
@ -191,11 +191,19 @@ static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit)
|
|||||||
};
|
};
|
||||||
gdma_apply_strategy(tx_unit->dma_chan, &gdma_strategy_conf);
|
gdma_apply_strategy(tx_unit->dma_chan, &gdma_strategy_conf);
|
||||||
|
|
||||||
// Link the descriptors
|
// create DMA link list
|
||||||
size_t dma_nodes_num = tx_unit->dma_nodes_num;
|
size_t dma_nodes_num = tx_unit->dma_nodes_num;
|
||||||
for (int i = 0; i < dma_nodes_num; i++) {
|
gdma_link_list_config_t dma_link_config = {
|
||||||
tx_unit->dma_nodes_nc[i].next = (i == dma_nodes_num - 1) ? NULL : &(tx_unit->dma_nodes[i + 1]);
|
.buffer_alignment = 1,
|
||||||
}
|
.item_alignment = PARLIO_DMA_DESC_ALIGNMENT,
|
||||||
|
.num_items = dma_nodes_num,
|
||||||
|
.flags = {
|
||||||
|
.check_owner = true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// throw the error to the caller
|
||||||
|
ESP_RETURN_ON_ERROR(gdma_new_link_list(&dma_link_config, &tx_unit->dma_link), TAG, "create DMA link list failed");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,26 +288,9 @@ esp_err_t parlio_new_tx_unit(const parlio_tx_unit_config_t *config, parlio_tx_un
|
|||||||
|
|
||||||
// create DMA descriptors
|
// create DMA descriptors
|
||||||
// DMA descriptors must be placed in internal SRAM
|
// 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;
|
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;
|
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->max_transfer_bits = config->max_transfer_size * 8;
|
||||||
unit->base.dir = PARLIO_DIR_TX;
|
unit->base.dir = PARLIO_DIR_TX;
|
||||||
unit->data_width = data_width;
|
unit->data_width = data_width;
|
||||||
@ -385,27 +376,6 @@ esp_err_t parlio_del_tx_unit(parlio_tx_unit_handle_t unit)
|
|||||||
return parlio_destroy_tx_unit(unit);
|
return parlio_destroy_tx_unit(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
uint32_t mount_bytes = 0;
|
|
||||||
parlio_dma_desc_t *desc_nc = tx_unit->dma_nodes_nc;
|
|
||||||
|
|
||||||
while (len) {
|
|
||||||
assert(desc_nc);
|
|
||||||
mount_bytes = len > PARLIO_MAX_ALIGNED_DMA_BUF_SIZE ? PARLIO_MAX_ALIGNED_DMA_BUF_SIZE : len;
|
|
||||||
len -= mount_bytes;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t parlio_tx_unit_wait_all_done(parlio_tx_unit_handle_t tx_unit, int timeout_ms)
|
esp_err_t parlio_tx_unit_wait_all_done(parlio_tx_unit_handle_t tx_unit, int timeout_ms)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(tx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(tx_unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
@ -448,7 +418,15 @@ static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio
|
|||||||
tx_unit->cur_trans = t;
|
tx_unit->cur_trans = t;
|
||||||
|
|
||||||
// DMA transfer data based on bytes not bits, so convert the bit length to bytes, round up
|
// DMA transfer data based on bytes not bits, so convert the bit length to bytes, round up
|
||||||
parlio_tx_mount_dma_data(tx_unit, t->payload, (t->payload_bits + 7) / 8);
|
gdma_buffer_mount_config_t mount_config = {
|
||||||
|
.buffer = (void *)t->payload,
|
||||||
|
.length = (t->payload_bits + 7) / 8,
|
||||||
|
.flags = {
|
||||||
|
.mark_eof = true,
|
||||||
|
.mark_final = true, // singly link list, mark final descriptor
|
||||||
|
}
|
||||||
|
};
|
||||||
|
gdma_link_mount_buffers(tx_unit->dma_link, 0, &mount_config, 1, NULL);
|
||||||
|
|
||||||
parlio_ll_tx_reset_fifo(hal->regs);
|
parlio_ll_tx_reset_fifo(hal->regs);
|
||||||
PARLIO_RCC_ATOMIC() {
|
PARLIO_RCC_ATOMIC() {
|
||||||
@ -457,7 +435,7 @@ static void IRAM_ATTR parlio_tx_do_transaction(parlio_tx_unit_t *tx_unit, parlio
|
|||||||
parlio_ll_tx_set_idle_data_value(hal->regs, t->idle_value);
|
parlio_ll_tx_set_idle_data_value(hal->regs, t->idle_value);
|
||||||
parlio_ll_tx_set_trans_bit_len(hal->regs, t->payload_bits);
|
parlio_ll_tx_set_trans_bit_len(hal->regs, t->payload_bits);
|
||||||
|
|
||||||
gdma_start(tx_unit->dma_chan, (intptr_t)tx_unit->dma_nodes);
|
gdma_start(tx_unit->dma_chan, gdma_link_get_head_addr(tx_unit->dma_link));
|
||||||
// wait until the data goes from the DMA to TX unit's FIFO
|
// wait until the data goes from the DMA to TX unit's FIFO
|
||||||
while (parlio_ll_tx_is_ready(hal->regs) == false);
|
while (parlio_ll_tx_is_ready(hal->regs) == false);
|
||||||
// turn on the core clock after we start the TX unit
|
// turn on the core clock after we start the TX unit
|
||||||
|
Loading…
Reference in New Issue
Block a user