Merge branch 'bugfix/dma2d_various_small_fixes' into 'master'

fix(dma2d): correct a few 2D-DMA driver issues

See merge request espressif/esp-idf!29705
This commit is contained in:
Song Ruo Jing
2024-03-19 21:36:45 +08:00
8 changed files with 100 additions and 94 deletions

View File

@@ -98,8 +98,6 @@ static bool acquire_free_channels_for_trans(dma2d_group_t *dma2d_group, const dm
dma2d_group->tx_chans[channel_id]->base.status.periph_sel_id = -1; dma2d_group->tx_chans[channel_id]->base.status.periph_sel_id = -1;
if (trans_desc->channel_flags & DMA2D_CHANNEL_FUNCTION_FLAG_TX_REORDER) { if (trans_desc->channel_flags & DMA2D_CHANNEL_FUNCTION_FLAG_TX_REORDER) {
dma2d_group->tx_chans[channel_id]->base.status.reorder_en = true; dma2d_group->tx_chans[channel_id]->base.status.reorder_en = true;
} else if (trans_desc->channel_flags & DMA2D_CHANNEL_FUNCTION_FLAG_SIBLING) {
dma2d_group->tx_chans[channel_id]->base.status.has_sibling = true;
} }
channel_handle_array[idx].chan = &dma2d_group->tx_chans[channel_id]->base; channel_handle_array[idx].chan = &dma2d_group->tx_chans[channel_id]->base;
channel_handle_array[idx].dir = DMA2D_CHANNEL_DIRECTION_TX; channel_handle_array[idx].dir = DMA2D_CHANNEL_DIRECTION_TX;
@@ -137,8 +135,6 @@ static bool acquire_free_channels_for_trans(dma2d_group_t *dma2d_group, const dm
dma2d_group->rx_chans[channel_id]->base.status.periph_sel_id = -1; dma2d_group->rx_chans[channel_id]->base.status.periph_sel_id = -1;
if (trans_desc->channel_flags & DMA2D_CHANNEL_FUNCTION_FLAG_RX_REORDER) { if (trans_desc->channel_flags & DMA2D_CHANNEL_FUNCTION_FLAG_RX_REORDER) {
dma2d_group->rx_chans[channel_id]->base.status.reorder_en = true; dma2d_group->rx_chans[channel_id]->base.status.reorder_en = true;
} else if (trans_desc->channel_flags & DMA2D_CHANNEL_FUNCTION_FLAG_SIBLING) {
dma2d_group->rx_chans[channel_id]->base.status.has_sibling = true;
} }
channel_handle_array[idx].chan = &dma2d_group->rx_chans[channel_id]->base; channel_handle_array[idx].chan = &dma2d_group->rx_chans[channel_id]->base;
channel_handle_array[idx].dir = DMA2D_CHANNEL_DIRECTION_RX; channel_handle_array[idx].dir = DMA2D_CHANNEL_DIRECTION_RX;
@@ -176,6 +172,8 @@ static bool free_up_channels(dma2d_group_t *group, dma2d_rx_channel_t *rx_chan)
uint32_t channel_id = rx_chan->base.channel_id; uint32_t channel_id = rx_chan->base.channel_id;
// 1. Clean up channels // 1. Clean up channels
uint32_t bundled_tx_channel_mask = rx_chan->bundled_tx_channel_mask; uint32_t bundled_tx_channel_mask = rx_chan->bundled_tx_channel_mask;
uint32_t tx_periph_sel_id_mask = 0;
uint32_t rx_periph_sel_id_mask = 0;
// Disable RX channel interrupt // Disable RX channel interrupt
portENTER_CRITICAL_SAFE(&rx_chan->base.spinlock); portENTER_CRITICAL_SAFE(&rx_chan->base.spinlock);
dma2d_ll_rx_enable_interrupt(group->hal.dev, channel_id, UINT32_MAX, false); dma2d_ll_rx_enable_interrupt(group->hal.dev, channel_id, UINT32_MAX, false);
@@ -186,6 +184,9 @@ static bool free_up_channels(dma2d_group_t *group, dma2d_rx_channel_t *rx_chan)
dma2d_ll_rx_disconnect_from_periph(group->hal.dev, channel_id); dma2d_ll_rx_disconnect_from_periph(group->hal.dev, channel_id);
// Clear the pointer that points to the finished transaction // Clear the pointer that points to the finished transaction
rx_chan->base.status.transaction = NULL; rx_chan->base.status.transaction = NULL;
// Record its periph_sel_id
assert(rx_chan->base.status.periph_sel_id != -1);
rx_periph_sel_id_mask |= (1 << rx_chan->base.status.periph_sel_id);
portEXIT_CRITICAL_SAFE(&rx_chan->base.spinlock); portEXIT_CRITICAL_SAFE(&rx_chan->base.spinlock);
// For every bundled TX channels: // For every bundled TX channels:
while (rx_chan->bundled_tx_channel_mask) { while (rx_chan->bundled_tx_channel_mask) {
@@ -201,6 +202,9 @@ static bool free_up_channels(dma2d_group_t *group, dma2d_rx_channel_t *rx_chan)
dma2d_ll_tx_disconnect_from_periph(group->hal.dev, nbit); dma2d_ll_tx_disconnect_from_periph(group->hal.dev, nbit);
// Clear the pointer that points to the finished transaction // Clear the pointer that points to the finished transaction
tx_chan->base.status.transaction = NULL; tx_chan->base.status.transaction = NULL;
// Record its periph_sel_id
assert(tx_chan->base.status.periph_sel_id != -1);
tx_periph_sel_id_mask |= (1 << tx_chan->base.status.periph_sel_id);
portEXIT_CRITICAL_SAFE(&tx_chan->base.spinlock); portEXIT_CRITICAL_SAFE(&tx_chan->base.spinlock);
} }
// Channel functionality flags will be reset and assigned new values inside `acquire_free_channels_for_trans` // Channel functionality flags will be reset and assigned new values inside `acquire_free_channels_for_trans`
@@ -212,12 +216,12 @@ static bool free_up_channels(dma2d_group_t *group, dma2d_rx_channel_t *rx_chan)
dma2d_trans_channel_info_t channel_handle_array[DMA2D_MAX_CHANNEL_NUM_PER_TRANSACTION]; dma2d_trans_channel_info_t channel_handle_array[DMA2D_MAX_CHANNEL_NUM_PER_TRANSACTION];
portENTER_CRITICAL_SAFE(&group->spinlock); portENTER_CRITICAL_SAFE(&group->spinlock);
// Release channels
group->tx_channel_free_mask |= bundled_tx_channel_mask; group->tx_channel_free_mask |= bundled_tx_channel_mask;
group->rx_channel_free_mask |= (1 << channel_id); group->rx_channel_free_mask |= (1 << channel_id);
int rx_periph_sel_id = group->rx_chans[channel_id]->base.status.periph_sel_id; // Release M2M periph_sel_id
if (rx_periph_sel_id != -1 && ((1 << rx_periph_sel_id) & DMA2D_LL_CHANNEL_PERIPH_M2M_FREE_ID_MASK)) { group->tx_periph_m2m_free_id_mask |= (tx_periph_sel_id_mask & DMA2D_LL_TX_CHANNEL_PERIPH_M2M_AVAILABLE_ID_MASK);
group->periph_m2m_free_id_mask |= (1 << rx_periph_sel_id); // release m2m periph_sel_id group->rx_periph_m2m_free_id_mask |= (rx_periph_sel_id_mask & DMA2D_LL_RX_CHANNEL_PERIPH_M2M_AVAILABLE_ID_MASK);
}
dma2d_trans_t *next_trans_elm = TAILQ_FIRST(&group->pending_trans_tailq); dma2d_trans_t *next_trans_elm = TAILQ_FIRST(&group->pending_trans_tailq);
if (next_trans_elm) { if (next_trans_elm) {
@@ -295,10 +299,10 @@ static NOINLINE_ATTR bool _dma2d_default_rx_isr(dma2d_group_t *group, int channe
} }
// If last transcation completes (regardless success or not), free the channels // If last transcation completes (regardless success or not), free the channels
if ((intr_status & DMA2D_LL_EVENT_RX_SUC_EOF) || if (intr_status & (DMA2D_LL_EVENT_RX_SUC_EOF | DMA2D_LL_EVENT_RX_ERR_EOF | DMA2D_LL_EVENT_RX_DESC_ERROR)) {
(intr_status & DMA2D_LL_EVENT_RX_ERR_EOF) || if (!(intr_status & DMA2D_LL_EVENT_RX_ERR_EOF)) {
(intr_status & DMA2D_LL_EVENT_RX_DESC_ERROR)) {
assert(dma2d_ll_rx_is_fsm_idle(group->hal.dev, channel_id)); assert(dma2d_ll_rx_is_fsm_idle(group->hal.dev, channel_id));
}
need_yield |= free_up_channels(group, rx_chan); need_yield |= free_up_channels(group, rx_chan);
} }
@@ -365,7 +369,8 @@ esp_err_t dma2d_acquire_pool(const dma2d_pool_config_t *config, dma2d_pool_handl
pre_alloc_group->rx_channel_free_mask = (1 << SOC_DMA2D_RX_CHANNELS_PER_GROUP) - 1; pre_alloc_group->rx_channel_free_mask = (1 << SOC_DMA2D_RX_CHANNELS_PER_GROUP) - 1;
pre_alloc_group->tx_channel_reserved_mask = dma2d_tx_channel_reserved_mask[group_id]; pre_alloc_group->tx_channel_reserved_mask = dma2d_tx_channel_reserved_mask[group_id];
pre_alloc_group->rx_channel_reserved_mask = dma2d_rx_channel_reserved_mask[group_id]; pre_alloc_group->rx_channel_reserved_mask = dma2d_rx_channel_reserved_mask[group_id];
pre_alloc_group->periph_m2m_free_id_mask = DMA2D_LL_CHANNEL_PERIPH_M2M_FREE_ID_MASK; pre_alloc_group->tx_periph_m2m_free_id_mask = DMA2D_LL_TX_CHANNEL_PERIPH_M2M_AVAILABLE_ID_MASK;
pre_alloc_group->rx_periph_m2m_free_id_mask = DMA2D_LL_RX_CHANNEL_PERIPH_M2M_AVAILABLE_ID_MASK;
pre_alloc_group->intr_priority = -1; pre_alloc_group->intr_priority = -1;
for (int i = 0; i < SOC_DMA2D_TX_CHANNELS_PER_GROUP; i++) { for (int i = 0; i < SOC_DMA2D_TX_CHANNELS_PER_GROUP; i++) {
pre_alloc_group->tx_chans[i] = &pre_alloc_tx_channels[i]; pre_alloc_group->tx_chans[i] = &pre_alloc_tx_channels[i];
@@ -393,8 +398,6 @@ esp_err_t dma2d_acquire_pool(const dma2d_pool_config_t *config, dma2d_pool_handl
dma2d_hal_init(&pre_alloc_group->hal, group_id); // initialize HAL context dma2d_hal_init(&pre_alloc_group->hal, group_id); // initialize HAL context
// Enable 2D-DMA module clock // Enable 2D-DMA module clock
dma2d_ll_hw_enable(s_platform.groups[group_id]->hal.dev, true); dma2d_ll_hw_enable(s_platform.groups[group_id]->hal.dev, true);
// Configure 2D-DMA accessible memory range
dma2d_ll_set_accessible_mem_range(s_platform.groups[group_id]->hal.dev);
} else { } else {
ret = ESP_ERR_NO_MEM; ret = ESP_ERR_NO_MEM;
free(pre_alloc_tx_channels); free(pre_alloc_tx_channels);
@@ -531,41 +534,30 @@ esp_err_t dma2d_connect(dma2d_channel_handle_t dma2d_chan, const dma2d_trigger_t
// Find periph_sel_id for the channel // Find periph_sel_id for the channel
int peri_sel_id = trig_periph->periph_sel_id; int peri_sel_id = trig_periph->periph_sel_id;
uint32_t *periph_m2m_free_id_mask = NULL;
uint32_t periph_m2m_available_id_mask = 0;
if (dma2d_chan->direction == DMA2D_CHANNEL_DIRECTION_TX) {
periph_m2m_free_id_mask = &group->tx_periph_m2m_free_id_mask;
periph_m2m_available_id_mask = DMA2D_LL_TX_CHANNEL_PERIPH_M2M_AVAILABLE_ID_MASK;
} else {
periph_m2m_free_id_mask = &group->rx_periph_m2m_free_id_mask;
periph_m2m_available_id_mask = DMA2D_LL_RX_CHANNEL_PERIPH_M2M_AVAILABLE_ID_MASK;
}
portENTER_CRITICAL_SAFE(&group->spinlock); portENTER_CRITICAL_SAFE(&group->spinlock);
if (trig_periph->periph == DMA2D_TRIG_PERIPH_M2M) { if (trig_periph->periph == DMA2D_TRIG_PERIPH_M2M) {
// Assign peri_sel_id to one of {4, 5, 6, 7}
assert(dma2d_chan->status.has_sibling);
// First find out the peri_sel_id of its sibling channel
int sibling_periph_sel_id = -1;
if (dma2d_chan->direction == DMA2D_CHANNEL_DIRECTION_TX) {
sibling_periph_sel_id = group->rx_chans[channel_id]->base.status.periph_sel_id;
} else {
sibling_periph_sel_id = group->tx_chans[channel_id]->base.status.periph_sel_id;
}
if (peri_sel_id == -1) { if (peri_sel_id == -1) {
// Unspecified periph_sel_id, decide by the driver // Unspecified periph_sel_id, decide by the driver
if (sibling_periph_sel_id != -1 && ((1 << sibling_periph_sel_id) & DMA2D_LL_CHANNEL_PERIPH_M2M_FREE_ID_MASK)) { peri_sel_id = __builtin_ctz(*periph_m2m_free_id_mask);
peri_sel_id = sibling_periph_sel_id;
} else {
peri_sel_id = __builtin_ctz(group->periph_m2m_free_id_mask);
}
} else { } else {
// Check whether specified periph_sel_id is valid // Check whether specified periph_sel_id is valid
if (sibling_periph_sel_id != -1) { if (!((1 << peri_sel_id) & *periph_m2m_free_id_mask & periph_m2m_available_id_mask)) {
if (sibling_periph_sel_id != peri_sel_id) {
peri_sel_id = -1; // Conflict id with its sibling channel
}
} else {
if (!((1 << peri_sel_id) & group->periph_m2m_free_id_mask & DMA2D_LL_CHANNEL_PERIPH_M2M_FREE_ID_MASK)) {
peri_sel_id = -1; // Occupied or invalid m2m peri_sel_id peri_sel_id = -1; // Occupied or invalid m2m peri_sel_id
} }
} }
} }
}
if (peri_sel_id >= 0) { if (peri_sel_id >= 0) {
dma2d_chan->status.periph_sel_id = peri_sel_id; dma2d_chan->status.periph_sel_id = peri_sel_id;
group->periph_m2m_free_id_mask &= ~(1 << peri_sel_id); // acquire m2m periph_sel_id *periph_m2m_free_id_mask &= ~(1 << peri_sel_id); // acquire m2m periph_sel_id
} }
portEXIT_CRITICAL_SAFE(&group->spinlock); portEXIT_CRITICAL_SAFE(&group->spinlock);
ESP_GOTO_ON_FALSE_ISR(peri_sel_id >= 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid periph_sel_id"); ESP_GOTO_ON_FALSE_ISR(peri_sel_id >= 0, ESP_ERR_INVALID_ARG, err, TAG, "invalid periph_sel_id");
@@ -608,6 +600,7 @@ esp_err_t dma2d_connect(dma2d_channel_handle_t dma2d_chan, const dma2d_trigger_t
// Reset to certain settings // Reset to certain settings
dma2d_ll_rx_enable_owner_check(group->hal.dev, channel_id, false); dma2d_ll_rx_enable_owner_check(group->hal.dev, channel_id, false);
dma2d_ll_rx_set_auto_return_owner(group->hal.dev, channel_id, DMA2D_DESCRIPTOR_BUFFER_OWNER_CPU); // After auto write back, the owner field will be cleared
dma2d_ll_rx_enable_descriptor_burst(group->hal.dev, channel_id, false); dma2d_ll_rx_enable_descriptor_burst(group->hal.dev, channel_id, false);
dma2d_ll_rx_set_data_burst_length(group->hal.dev, channel_id, DMA2D_DATA_BURST_LENGTH_128); dma2d_ll_rx_set_data_burst_length(group->hal.dev, channel_id, DMA2D_DATA_BURST_LENGTH_128);
dma2d_ll_rx_enable_page_bound_wrap(group->hal.dev, channel_id, true); dma2d_ll_rx_enable_page_bound_wrap(group->hal.dev, channel_id, true);
@@ -834,12 +827,10 @@ esp_err_t dma2d_set_transfer_ability(dma2d_channel_handle_t dma2d_chan, const dm
if (dma2d_chan->direction == DMA2D_CHANNEL_DIRECTION_TX) { if (dma2d_chan->direction == DMA2D_CHANNEL_DIRECTION_TX) {
dma2d_ll_tx_enable_descriptor_burst(group->hal.dev, channel_id, ability->desc_burst_en); dma2d_ll_tx_enable_descriptor_burst(group->hal.dev, channel_id, ability->desc_burst_en);
dma2d_ll_tx_set_data_burst_length(group->hal.dev, channel_id, ability->data_burst_length); dma2d_ll_tx_set_data_burst_length(group->hal.dev, channel_id, ability->data_burst_length);
dma2d_ll_tx_enable_page_bound_wrap(group->hal.dev, channel_id, ability->data_burst_length != 1);
dma2d_ll_tx_set_macro_block_size(group->hal.dev, channel_id, ability->mb_size); dma2d_ll_tx_set_macro_block_size(group->hal.dev, channel_id, ability->mb_size);
} else { } else {
dma2d_ll_rx_enable_descriptor_burst(group->hal.dev, channel_id, ability->desc_burst_en); dma2d_ll_rx_enable_descriptor_burst(group->hal.dev, channel_id, ability->desc_burst_en);
dma2d_ll_rx_set_data_burst_length(group->hal.dev, channel_id, ability->data_burst_length); dma2d_ll_rx_set_data_burst_length(group->hal.dev, channel_id, ability->data_burst_length);
dma2d_ll_rx_enable_page_bound_wrap(group->hal.dev, channel_id, ability->data_burst_length != 1);
dma2d_ll_rx_set_macro_block_size(group->hal.dev, channel_id, ability->mb_size); dma2d_ll_rx_set_macro_block_size(group->hal.dev, channel_id, ability->mb_size);
} }
@@ -942,7 +933,7 @@ err:
esp_err_t dma2d_force_end(dma2d_trans_t *trans, bool *need_yield) esp_err_t dma2d_force_end(dma2d_trans_t *trans, bool *need_yield)
{ {
ESP_RETURN_ON_FALSE_ISR(trans && trans->rx_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); ESP_RETURN_ON_FALSE_ISR(trans && trans->rx_chan && need_yield, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
assert(trans->rx_chan->direction == DMA2D_CHANNEL_DIRECTION_RX); assert(trans->rx_chan->direction == DMA2D_CHANNEL_DIRECTION_RX);
dma2d_group_t *group = trans->rx_chan->group; dma2d_group_t *group = trans->rx_chan->group;

View File

@@ -55,7 +55,8 @@ struct dma2d_group_t {
uint8_t rx_channel_free_mask; // Bit mask indicating the free RX channels at the moment uint8_t rx_channel_free_mask; // Bit mask indicating the free RX channels at the moment
uint8_t tx_channel_reserved_mask; // Bit mask indicating the being reserved TX channels uint8_t tx_channel_reserved_mask; // Bit mask indicating the being reserved TX channels
uint8_t rx_channel_reserved_mask; // Bit mask indicating the being reserved RX channels uint8_t rx_channel_reserved_mask; // Bit mask indicating the being reserved RX channels
uint32_t periph_m2m_free_id_mask; // Bit mask indicating the available M2M peripheral selelction IDs at the moment uint32_t tx_periph_m2m_free_id_mask; // Bit mask indicating the available TX M2M peripheral selelction IDs at the moment
uint32_t rx_periph_m2m_free_id_mask; // Bit mask indicating the available RX M2M peripheral selelction IDs at the moment
dma2d_tx_channel_t *tx_chans[SOC_DMA2D_TX_CHANNELS_PER_GROUP]; // Handles of 2D-DMA TX channels dma2d_tx_channel_t *tx_chans[SOC_DMA2D_TX_CHANNELS_PER_GROUP]; // Handles of 2D-DMA TX channels
dma2d_rx_channel_t *rx_chans[SOC_DMA2D_RX_CHANNELS_PER_GROUP]; // Handles of 2D-DMA RX channels dma2d_rx_channel_t *rx_chans[SOC_DMA2D_RX_CHANNELS_PER_GROUP]; // Handles of 2D-DMA RX channels
int intr_priority; // All channels in the same group should share the same interrupt priority int intr_priority; // All channels in the same group should share the same interrupt priority
@@ -70,7 +71,6 @@ struct dma2d_channel_t {
struct { struct {
dma2d_trans_t *transaction; // Pointer to the 2D-DMA transaction context that is currently being processed on the channel dma2d_trans_t *transaction; // Pointer to the 2D-DMA transaction context that is currently being processed on the channel
uint32_t reorder_en : 1; // This flag indicates the channel will enable reorder functionality uint32_t reorder_en : 1; // This flag indicates the channel will enable reorder functionality
uint32_t has_sibling : 1; // This flag indicates its sibling channel is also in-use
int periph_sel_id : (DMA2D_LL_CHANNEL_PERIPH_SEL_BIT_WIDTH + 1); // This is used to record the periph_sel_id of each channel int periph_sel_id : (DMA2D_LL_CHANNEL_PERIPH_SEL_BIT_WIDTH + 1); // This is used to record the periph_sel_id of each channel
} status; } status;
}; };

View File

@@ -104,9 +104,9 @@ TEST_CASE("DMA2D_M2M_1D_basic", "[DMA2D]")
prtx[idx] = (i + idx + 0x45) & 0xFF; prtx[idx] = (i + idx + 0x45) & 0xFF;
prrx[idx] = 0; prrx[idx] = 0;
} }
// Writeback and invalidate the TX and RX buffers // Writeback TX and RX buffers
esp_cache_msync((void *)prtx, data_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prtx, data_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
esp_cache_msync((void *)prrx, data_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prrx, data_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
// DMA description preparation // DMA description preparation
dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx, dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx,
@@ -146,6 +146,11 @@ TEST_CASE("DMA2D_M2M_1D_basic", "[DMA2D]")
for (int i = 0; i < M2M_TRANS_TIMES; i++) { for (int i = 0; i < M2M_TRANS_TIMES; i++) {
prtx = tx_buf + i * data_size; prtx = tx_buf + i * data_size;
prrx = rx_buf + i * data_size; prrx = rx_buf + i * data_size;
// Invalidate TX and RX buffers
esp_cache_msync((void *)prtx, data_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
esp_cache_msync((void *)prrx, data_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
for (int idx = 0; idx < data_size; idx++) { for (int idx = 0; idx < data_size; idx++) {
TEST_ASSERT_EQUAL(prtx[idx], prrx[idx]); TEST_ASSERT_EQUAL(prtx[idx], prrx[idx]);
TEST_ASSERT_EQUAL(prtx[idx], (i + idx + 0x45) & 0xFF); TEST_ASSERT_EQUAL(prtx[idx], (i + idx + 0x45) & 0xFF);
@@ -249,9 +254,9 @@ TEST_CASE("DMA2D_M2M_1D_RGB565_to_RGB888", "[DMA2D]")
prrx[idx * 3 + 1] = 0; prrx[idx * 3 + 1] = 0;
prrx[idx * 3 + 2] = 0; prrx[idx * 3 + 2] = 0;
} }
// Writeback and invalidate the TX and RX buffers // Writeback TX and RX buffers
esp_cache_msync((void *)prtx, item_size * 2, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prtx, item_size * 2, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
esp_cache_msync((void *)prrx, item_size * 3, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prrx, item_size * 3, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
// DMA description preparation // DMA description preparation
dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx, dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx,
@@ -292,6 +297,11 @@ TEST_CASE("DMA2D_M2M_1D_RGB565_to_RGB888", "[DMA2D]")
for (int i = 0; i < M2M_TRANS_TIMES; i++) { for (int i = 0; i < M2M_TRANS_TIMES; i++) {
prtx = tx_buf + i * item_size * 2; prtx = tx_buf + i * item_size * 2;
prrx = rx_buf + i * item_size * 3; prrx = rx_buf + i * item_size * 3;
// Invalidate TX and RX buffers
esp_cache_msync((void *)prtx, item_size * 2, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
esp_cache_msync((void *)prrx, item_size * 3, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
TEST_ASSERT_EQUAL(0, rgb565_to_rgb888_and_cmp(prtx, prrx, item_size)); TEST_ASSERT_EQUAL(0, rgb565_to_rgb888_and_cmp(prtx, prrx, item_size));
} }
@@ -349,9 +359,9 @@ TEST_CASE("DMA2D_M2M_2D_basic", "[DMA2D]")
prtx[idx] = (i + idx + 0x45) & 0xFF; prtx[idx] = (i + idx + 0x45) & 0xFF;
prrx[idx] = 0; prrx[idx] = 0;
} }
// Writeback and invalidate the TX and RX buffers // Writeback TX and RX buffers
esp_cache_msync((void *)prtx, stripe_size * stripe_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prtx, stripe_size * stripe_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
esp_cache_msync((void *)prrx, stripe_size * stripe_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prrx, stripe_size * stripe_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
// DMA description preparation // DMA description preparation
dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx, dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx,
@@ -391,6 +401,11 @@ TEST_CASE("DMA2D_M2M_2D_basic", "[DMA2D]")
for (int i = 0; i < M2M_TRANS_TIMES; i++) { for (int i = 0; i < M2M_TRANS_TIMES; i++) {
prtx = tx_buf + i * stripe_size * stripe_size; prtx = tx_buf + i * stripe_size * stripe_size;
prrx = rx_buf + i * stripe_size * stripe_size; prrx = rx_buf + i * stripe_size * stripe_size;
// Invalidate TX and RX buffers
esp_cache_msync((void *)prtx, stripe_size * stripe_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
esp_cache_msync((void *)prrx, stripe_size * stripe_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
for (int idx = 0; idx < stripe_size * stripe_size; idx++) { for (int idx = 0; idx < stripe_size * stripe_size; idx++) {
TEST_ASSERT_EQUAL(prtx[idx], prrx[idx]); TEST_ASSERT_EQUAL(prtx[idx], prrx[idx]);
TEST_ASSERT_EQUAL(prtx[idx], (i + idx + 0x45) & 0xFF); TEST_ASSERT_EQUAL(prtx[idx], (i + idx + 0x45) & 0xFF);
@@ -494,9 +509,9 @@ TEST_CASE("DMA2D_M2M_2D_RGB888_to_RGB565", "[DMA2D]")
prrx[idx * 2] = 0; prrx[idx * 2] = 0;
prrx[idx * 2 + 1] = 0; prrx[idx * 2 + 1] = 0;
} }
// Writeback and invalidate the TX and RX buffers // Writeback TX and RX buffers
esp_cache_msync((void *)prtx, stripe_pixel_size * stripe_pixel_size * 3, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prtx, stripe_pixel_size * stripe_pixel_size * 3, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
esp_cache_msync((void *)prrx, stripe_pixel_size * stripe_pixel_size * 2, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prrx, stripe_pixel_size * stripe_pixel_size * 2, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
// DMA description preparation // DMA description preparation
dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx, dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx,
@@ -537,6 +552,11 @@ TEST_CASE("DMA2D_M2M_2D_RGB888_to_RGB565", "[DMA2D]")
for (int i = 0; i < M2M_TRANS_TIMES; i++) { for (int i = 0; i < M2M_TRANS_TIMES; i++) {
prtx = tx_buf + i * stripe_pixel_size * stripe_pixel_size * 3; prtx = tx_buf + i * stripe_pixel_size * stripe_pixel_size * 3;
prrx = rx_buf + i * stripe_pixel_size * stripe_pixel_size * 2; prrx = rx_buf + i * stripe_pixel_size * stripe_pixel_size * 2;
// Invalidate TX and RX buffers
esp_cache_msync((void *)prtx, stripe_pixel_size * stripe_pixel_size * 3, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
esp_cache_msync((void *)prrx, stripe_pixel_size * stripe_pixel_size * 2, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
TEST_ASSERT_EQUAL(0, rgb888_to_rgb565_and_cmp(prtx, prrx, stripe_pixel_size * stripe_pixel_size)); TEST_ASSERT_EQUAL(0, rgb888_to_rgb565_and_cmp(prtx, prrx, stripe_pixel_size * stripe_pixel_size));
} }
@@ -601,9 +621,9 @@ TEST_CASE("DMA2D_M2M_2D_window", "[DMA2D]")
prrx[idx * 2 + 1] = 0xFF; prrx[idx * 2 + 1] = 0xFF;
} }
// Writeback and invalidate the TX and RX buffers // Writeback TX and RX buffers
esp_cache_msync((void *)prtx, 64, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prtx, 64, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
esp_cache_msync((void *)prrx, va * ha * 2, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_INVALIDATE); esp_cache_msync((void *)prrx, va * ha * 2, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
// DMA description preparation // DMA description preparation
dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx, dma2d_link_dscr_init((uint32_t *)tx_dsc[i], NULL, (void *)prtx,
@@ -643,6 +663,11 @@ TEST_CASE("DMA2D_M2M_2D_window", "[DMA2D]")
for (int i = 0; i < M2M_TRANS_TIMES; i++) { for (int i = 0; i < M2M_TRANS_TIMES; i++) {
prtx = tx_buf + i * 64; prtx = tx_buf + i * 64;
prrx = rx_buf + i * va * ha * 2; prrx = rx_buf + i * va * ha * 2;
// Invalidate TX and RX buffers
esp_cache_msync((void *)prtx, 64, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
esp_cache_msync((void *)prrx, va * ha * 2, ESP_CACHE_MSYNC_FLAG_DIR_M2C);
printf("pic:\n"); printf("pic:\n");
for (int idx = 0; idx < va * ha; idx++) { for (int idx = 0; idx < va * ha; idx++) {
printf("%02X%02X ", prrx[idx * 2], prrx[idx * 2 + 1]); printf("%02X%02X ", prrx[idx * 2], prrx[idx * 2 + 1]);

View File

@@ -62,8 +62,9 @@ extern "C" {
#define DMA2D_LL_RX_CHANNEL_SUPPORT_RO_MASK (0U | BIT0) // RX channels that support reorder feature #define DMA2D_LL_RX_CHANNEL_SUPPORT_RO_MASK (0U | BIT0) // RX channels that support reorder feature
#define DMA2D_LL_RX_CHANNEL_SUPPORT_CSC_MASK (0U | BIT0) // RX channels that support color space conversion feature #define DMA2D_LL_RX_CHANNEL_SUPPORT_CSC_MASK (0U | BIT0) // RX channels that support color space conversion feature
// Any "dummy" peripheral selection ID can be used for M2M mode {4, 5, 6, 7} // Any "dummy" peripheral selection ID can be used for M2M mode
#define DMA2D_LL_CHANNEL_PERIPH_M2M_FREE_ID_MASK (0xF0) #define DMA2D_LL_TX_CHANNEL_PERIPH_M2M_AVAILABLE_ID_MASK (0xF0)
#define DMA2D_LL_RX_CHANNEL_PERIPH_M2M_AVAILABLE_ID_MASK (0xF8)
// Peripheral selection ID that disconnects 2D-DMA channel from any peripherals // Peripheral selection ID that disconnects 2D-DMA channel from any peripherals
#define DMA2D_LL_CHANNEL_PERIPH_NO_CHOICE (7) #define DMA2D_LL_CHANNEL_PERIPH_NO_CHOICE (7)
// Peripheral selection ID register field width // Peripheral selection ID register field width
@@ -104,17 +105,6 @@ static inline void dma2d_ll_reset_register(int group_id)
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define dma2d_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; dma2d_ll_reset_register(__VA_ARGS__) #define dma2d_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; dma2d_ll_reset_register(__VA_ARGS__)
/**
* @brief Configure 2D-DMA accessible internal and external memory start/end address (for both buffer and descriptor)
*/
static inline void dma2d_ll_set_accessible_mem_range(dma2d_dev_t *dev)
{
dev->intr_mem_start_addr.access_intr_mem_start_addr = SOC_DIRAM_DRAM_LOW; // L2MEM region (2D-DMA indeed is able to access TCM/LP_MEM regions, but will be restricted in IDF)
dev->intr_mem_end_addr.access_intr_mem_end_addr = SOC_DIRAM_DRAM_HIGH;
dev->extr_mem_start_addr.access_extr_mem_start_addr = SOC_EXTRAM_LOW;
dev->extr_mem_end_addr.access_extr_mem_end_addr = SOC_EXTRAM_HIGH;
}
/** /**
* @brief Enable 2D-DMA module * @brief Enable 2D-DMA module
*/ */
@@ -230,7 +220,7 @@ static inline void dma2d_ll_rx_set_data_burst_length(dma2d_dev_t *dev, uint32_t
{ {
uint32_t sel; uint32_t sel;
switch (length) { switch (length) {
case DMA2D_DATA_BURST_LENGTH_1: case DMA2D_DATA_BURST_LENGTH_8:
sel = 0; sel = 0;
break; break;
case DMA2D_DATA_BURST_LENGTH_16: case DMA2D_DATA_BURST_LENGTH_16:
@@ -384,13 +374,13 @@ static inline void dma2d_ll_rx_restart(dma2d_dev_t *dev, uint32_t channel)
} }
/** /**
* @brief Enable 2D-DMA RX to return the address of current descriptor when receives error * @brief Configure the value of the owner field written back to the 2D-DMA RX descriptor
*/ */
__attribute__((always_inline)) __attribute__((always_inline))
static inline void dma2d_ll_rx_enable_auto_return(dma2d_dev_t *dev, uint32_t channel, bool enable) static inline void dma2d_ll_rx_set_auto_return_owner(dma2d_dev_t *dev, uint32_t channel, int owner)
{ {
volatile dma2d_in_link_conf_chn_reg_t *reg = (volatile dma2d_in_link_conf_chn_reg_t *)DMA2D_LL_IN_CHANNEL_GET_REG_ADDR(dev, channel, in_link_conf); volatile dma2d_in_link_conf_chn_reg_t *reg = (volatile dma2d_in_link_conf_chn_reg_t *)DMA2D_LL_IN_CHANNEL_GET_REG_ADDR(dev, channel, in_link_conf);
reg->inlink_auto_ret_chn = enable; reg->inlink_auto_ret_chn = owner;
} }
/** /**
@@ -767,7 +757,7 @@ static inline void dma2d_ll_tx_set_data_burst_length(dma2d_dev_t *dev, uint32_t
{ {
uint32_t sel; uint32_t sel;
switch (length) { switch (length) {
case DMA2D_DATA_BURST_LENGTH_1: case DMA2D_DATA_BURST_LENGTH_8:
sel = 0; sel = 0;
break; break;
case DMA2D_DATA_BURST_LENGTH_16: case DMA2D_DATA_BURST_LENGTH_16:

View File

@@ -120,7 +120,7 @@ typedef enum {
* @brief Enumeration of 2D-DMA data burst length options * @brief Enumeration of 2D-DMA data burst length options
*/ */
typedef enum { typedef enum {
DMA2D_DATA_BURST_LENGTH_1, /*!< 2D-DMA block size: single byte */ DMA2D_DATA_BURST_LENGTH_8, /*!< 2D-DMA block size: 8 bytes */
DMA2D_DATA_BURST_LENGTH_16, /*!< 2D-DMA block size: 16 bytes */ DMA2D_DATA_BURST_LENGTH_16, /*!< 2D-DMA block size: 16 bytes */
DMA2D_DATA_BURST_LENGTH_32, /*!< 2D-DMA block size: 32 bytes */ DMA2D_DATA_BURST_LENGTH_32, /*!< 2D-DMA block size: 32 bytes */
DMA2D_DATA_BURST_LENGTH_64, /*!< 2D-DMA block size: 64 bytes */ DMA2D_DATA_BURST_LENGTH_64, /*!< 2D-DMA block size: 64 bytes */

View File

@@ -10,10 +10,10 @@
#define SOC_DMA2D_TRIG_PERIPH_JPEG_RX (0) #define SOC_DMA2D_TRIG_PERIPH_JPEG_RX (0)
#define SOC_DMA2D_TRIG_PERIPH_PPA_SR_RX (1) #define SOC_DMA2D_TRIG_PERIPH_PPA_SR_RX (1)
#define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_RX (2) #define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_RX (2)
#define SOC_DMA2D_TRIG_PERIPH_M2M_RX (-1) // Any value of 3 ~ 7, but TX and RX needs the same ID for M2M #define SOC_DMA2D_TRIG_PERIPH_M2M_RX (-1) // Any value of 3 ~ 7, TX and RX do not have to use same ID value for M2M
#define SOC_DMA2D_TRIG_PERIPH_JPEG_TX (0) #define SOC_DMA2D_TRIG_PERIPH_JPEG_TX (0)
#define SOC_DMA2D_TRIG_PERIPH_PPA_SR_TX (1) #define SOC_DMA2D_TRIG_PERIPH_PPA_SR_TX (1)
#define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_FG_TX (2) #define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_FG_TX (2)
#define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_BG_TX (3) #define SOC_DMA2D_TRIG_PERIPH_PPA_BLEND_BG_TX (3)
#define SOC_DMA2D_TRIG_PERIPH_M2M_TX (-1) // Any value of 4 ~ 7, but TX and RX needs the same ID for M2M #define SOC_DMA2D_TRIG_PERIPH_M2M_TX (-1) // Any value of 4 ~ 7, TX and RX do not have to use same ID value for M2M

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 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -63,7 +63,7 @@ extern "C" {
#define DMA2D_OUT_LOOP_TEST_CH0_V 0x00000001U #define DMA2D_OUT_LOOP_TEST_CH0_V 0x00000001U
#define DMA2D_OUT_LOOP_TEST_CH0_S 5 #define DMA2D_OUT_LOOP_TEST_CH0_S 5
/** DMA2D_OUT_MEM_BURST_LENGTH_CH0 : R/W; bitpos: [8:6]; default: 0; /** DMA2D_OUT_MEM_BURST_LENGTH_CH0 : R/W; bitpos: [8:6]; default: 0;
* Block size of Tx channel 0. 0: single 1: 16 bytes 2: 32 bytes 3: 64 * Block size of Tx channel 0. 0: 8 bytes 1: 16 bytes 2: 32 bytes 3: 64
* bytes 4: 128 bytes * bytes 4: 128 bytes
*/ */
#define DMA2D_OUT_MEM_BURST_LENGTH_CH0 0x00000007U #define DMA2D_OUT_MEM_BURST_LENGTH_CH0 0x00000007U
@@ -1098,7 +1098,7 @@ extern "C" {
#define DMA2D_OUT_LOOP_TEST_CH1_V 0x00000001U #define DMA2D_OUT_LOOP_TEST_CH1_V 0x00000001U
#define DMA2D_OUT_LOOP_TEST_CH1_S 5 #define DMA2D_OUT_LOOP_TEST_CH1_S 5
/** DMA2D_OUT_MEM_BURST_LENGTH_CH1 : R/W; bitpos: [8:6]; default: 0; /** DMA2D_OUT_MEM_BURST_LENGTH_CH1 : R/W; bitpos: [8:6]; default: 0;
* Block size of Tx channel 0. 0: single 1: 16 bytes 2: 32 bytes 3: 64 * Block size of Tx channel 0. 0: 8 bytes 1: 16 bytes 2: 32 bytes 3: 64
* bytes 4: 128 bytes * bytes 4: 128 bytes
*/ */
#define DMA2D_OUT_MEM_BURST_LENGTH_CH1 0x00000007U #define DMA2D_OUT_MEM_BURST_LENGTH_CH1 0x00000007U
@@ -2106,7 +2106,7 @@ extern "C" {
#define DMA2D_OUT_LOOP_TEST_CH2_V 0x00000001U #define DMA2D_OUT_LOOP_TEST_CH2_V 0x00000001U
#define DMA2D_OUT_LOOP_TEST_CH2_S 5 #define DMA2D_OUT_LOOP_TEST_CH2_S 5
/** DMA2D_OUT_MEM_BURST_LENGTH_CH2 : R/W; bitpos: [8:6]; default: 0; /** DMA2D_OUT_MEM_BURST_LENGTH_CH2 : R/W; bitpos: [8:6]; default: 0;
* Block size of Tx channel 0. 0: single 1: 16 bytes 2: 32 bytes 3: 64 * Block size of Tx channel 0. 0: 8 bytes 1: 16 bytes 2: 32 bytes 3: 64
* bytes 4: 128 bytes * bytes 4: 128 bytes
*/ */
#define DMA2D_OUT_MEM_BURST_LENGTH_CH2 0x00000007U #define DMA2D_OUT_MEM_BURST_LENGTH_CH2 0x00000007U
@@ -3105,7 +3105,7 @@ extern "C" {
#define DMA2D_IN_LOOP_TEST_CH0_V 0x00000001U #define DMA2D_IN_LOOP_TEST_CH0_V 0x00000001U
#define DMA2D_IN_LOOP_TEST_CH0_S 5 #define DMA2D_IN_LOOP_TEST_CH0_S 5
/** DMA2D_IN_MEM_BURST_LENGTH_CH0 : R/W; bitpos: [8:6]; default: 0; /** DMA2D_IN_MEM_BURST_LENGTH_CH0 : R/W; bitpos: [8:6]; default: 0;
* Block size of Rx channel 0. 0: single 1: 16 bytes 2: 32 bytes 3: 64 * Block size of Rx channel 0. 0: 8 bytes 1: 16 bytes 2: 32 bytes 3: 64
* bytes 4: 128 bytes * bytes 4: 128 bytes
*/ */
#define DMA2D_IN_MEM_BURST_LENGTH_CH0 0x00000007U #define DMA2D_IN_MEM_BURST_LENGTH_CH0 0x00000007U
@@ -3732,8 +3732,8 @@ extern "C" {
*/ */
#define DMA2D_IN_LINK_CONF_CH0_REG (DR_REG_DMA2D_BASE + 0x51c) #define DMA2D_IN_LINK_CONF_CH0_REG (DR_REG_DMA2D_BASE + 0x51c)
/** DMA2D_INLINK_AUTO_RET_CH0 : R/W; bitpos: [20]; default: 1; /** DMA2D_INLINK_AUTO_RET_CH0 : R/W; bitpos: [20]; default: 1;
* Set this bit to return to current inlink descriptor's address, when there are some * Configure the value of the owner field written back to the inlink descriptor.
* errors in current receiving data. * 1: Write back 1. 0: Write back 0.
*/ */
#define DMA2D_INLINK_AUTO_RET_CH0 (BIT(20)) #define DMA2D_INLINK_AUTO_RET_CH0 (BIT(20))
#define DMA2D_INLINK_AUTO_RET_CH0_M (DMA2D_INLINK_AUTO_RET_CH0_V << DMA2D_INLINK_AUTO_RET_CH0_S) #define DMA2D_INLINK_AUTO_RET_CH0_M (DMA2D_INLINK_AUTO_RET_CH0_V << DMA2D_INLINK_AUTO_RET_CH0_S)
@@ -4168,7 +4168,7 @@ extern "C" {
#define DMA2D_IN_LOOP_TEST_CH1_V 0x00000001U #define DMA2D_IN_LOOP_TEST_CH1_V 0x00000001U
#define DMA2D_IN_LOOP_TEST_CH1_S 5 #define DMA2D_IN_LOOP_TEST_CH1_S 5
/** DMA2D_IN_MEM_BURST_LENGTH_CH1 : R/W; bitpos: [8:6]; default: 0; /** DMA2D_IN_MEM_BURST_LENGTH_CH1 : R/W; bitpos: [8:6]; default: 0;
* Block size of Rx channel 0. 0: single 1: 16 bytes 2: 32 bytes 3: 64 * Block size of Rx channel 0. 0: 8 bytes 1: 16 bytes 2: 32 bytes 3: 64
* bytes 4: 128 bytes * bytes 4: 128 bytes
*/ */
#define DMA2D_IN_MEM_BURST_LENGTH_CH1 0x00000007U #define DMA2D_IN_MEM_BURST_LENGTH_CH1 0x00000007U
@@ -4795,8 +4795,8 @@ extern "C" {
*/ */
#define DMA2D_IN_LINK_CONF_CH1_REG (DR_REG_DMA2D_BASE + 0x61c) #define DMA2D_IN_LINK_CONF_CH1_REG (DR_REG_DMA2D_BASE + 0x61c)
/** DMA2D_INLINK_AUTO_RET_CH1 : R/W; bitpos: [20]; default: 1; /** DMA2D_INLINK_AUTO_RET_CH1 : R/W; bitpos: [20]; default: 1;
* Set this bit to return to current inlink descriptor's address, when there are some * Configure the value of the owner field written back to the inlink descriptor.
* errors in current receiving data. * 1: Write back 1. 0: Write back 0.
*/ */
#define DMA2D_INLINK_AUTO_RET_CH1 (BIT(20)) #define DMA2D_INLINK_AUTO_RET_CH1 (BIT(20))
#define DMA2D_INLINK_AUTO_RET_CH1_M (DMA2D_INLINK_AUTO_RET_CH1_V << DMA2D_INLINK_AUTO_RET_CH1_S) #define DMA2D_INLINK_AUTO_RET_CH1_M (DMA2D_INLINK_AUTO_RET_CH1_V << DMA2D_INLINK_AUTO_RET_CH1_S)

View File

@@ -46,7 +46,7 @@ typedef union {
*/ */
uint32_t out_loop_test_chn:1; uint32_t out_loop_test_chn:1;
/** out_mem_burst_length_chn : R/W; bitpos: [8:6]; default: 0; /** out_mem_burst_length_chn : R/W; bitpos: [8:6]; default: 0;
* Block size of Tx channel 0. 0: single 1: 16 bytes 2: 32 bytes 3: 64 * Block size of Tx channel 0. 0: 8 bytes 1: 16 bytes 2: 32 bytes 3: 64
* bytes 4: 128 bytes * bytes 4: 128 bytes
*/ */
uint32_t out_mem_burst_length_chn:3; uint32_t out_mem_burst_length_chn:3;
@@ -762,7 +762,7 @@ typedef union {
*/ */
uint32_t in_loop_test_chn:1; uint32_t in_loop_test_chn:1;
/** in_mem_burst_length_chn : R/W; bitpos: [8:6]; default: 0; /** in_mem_burst_length_chn : R/W; bitpos: [8:6]; default: 0;
* Block size of Rx channel 0. 0: single 1: 16 bytes 2: 32 bytes 3: 64 * Block size of Rx channel 0. 0: 8 bytes 1: 16 bytes 2: 32 bytes 3: 64
* bytes 4: 128 bytes * bytes 4: 128 bytes
*/ */
uint32_t in_mem_burst_length_chn:3; uint32_t in_mem_burst_length_chn:3;
@@ -1179,8 +1179,8 @@ typedef union {
struct { struct {
uint32_t reserved_0:20; uint32_t reserved_0:20;
/** inlink_auto_ret_chn : R/W; bitpos: [20]; default: 1; /** inlink_auto_ret_chn : R/W; bitpos: [20]; default: 1;
* Set this bit to return to current inlink descriptor's address, when there are some * Configure the value of the owner field written back to the inlink descriptor.
* errors in current receiving data. * 1: Write back 1. 0: Write back 0.
*/ */
uint32_t inlink_auto_ret_chn:1; uint32_t inlink_auto_ret_chn:1;
/** inlink_stop_chn : R/W/SC; bitpos: [21]; default: 0; /** inlink_stop_chn : R/W/SC; bitpos: [21]; default: 0;