drivers: dma: Update NXP EDMA driver for version 4

1. Update EDMA driver for version 4
2. The DMAMux module is not always present. Use the
   feature define to make this optional.
3. Use the EDMA_SetChannelMux API for SoC's that supports
   this feature.

Signed-off-by: Mahesh Mahadevan <mahesh.mahadevan@nxp.com>
This commit is contained in:
Mahesh Mahadevan 2023-03-14 11:54:16 -05:00 committed by Anas Nashif
commit 55abfcb31e
5 changed files with 91 additions and 27 deletions

View file

@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_DMA_SAM0 dma_sam0.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE dma_handlers.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE dma_handlers.c)
zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_EDMA dma_mcux_edma.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_EDMA dma_mcux_edma.c)
zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_EDMA_V3 dma_mcux_edma.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_EDMA_V3 dma_mcux_edma.c)
zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_EDMA_V4 dma_mcux_edma.c)
zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_LPC dma_mcux_lpc.c) zephyr_library_sources_ifdef(CONFIG_DMA_MCUX_LPC dma_mcux_lpc.c)
zephyr_library_sources_ifdef(CONFIG_DMA_PL330 dma_pl330.c) zephyr_library_sources_ifdef(CONFIG_DMA_PL330 dma_pl330.c)
zephyr_library_sources_ifdef(CONFIG_DMA_IPROC_PAX dma_iproc_pax_v1.c) zephyr_library_sources_ifdef(CONFIG_DMA_IPROC_PAX dma_iproc_pax_v1.c)

View file

@ -18,7 +18,14 @@ config DMA_MCUX_EDMA_V3
help help
DMA version 3 driver for MCUX series SoCs. DMA version 3 driver for MCUX series SoCs.
if DMA_MCUX_EDMA || DMA_MCUX_EDMA_V3 config DMA_MCUX_EDMA_V4
bool "MCUX DMA v4 driver"
default y
depends on DT_HAS_NXP_MCUX_EDMA_V4_ENABLED
help
DMA version 4 driver for MCUX series SoCs.
if DMA_MCUX_EDMA || DMA_MCUX_EDMA_V3 || DMA_MCUX_EDMA_V4
config DMA_TCD_QUEUE_SIZE config DMA_TCD_QUEUE_SIZE
int "number of TCD in a queue for SG mode" int "number of TCD in a queue for SG mode"
@ -41,4 +48,4 @@ config DMA_MCUX_USE_DTCM_FOR_DMA_DESCRIPTORS
When this option is activated, the descriptors for DMA transfer are When this option is activated, the descriptors for DMA transfer are
located in the DTCM (Data Tightly Coupled Memory). located in the DTCM (Data Tightly Coupled Memory).
endif # DMA_MCUX_EDMA || DMA_MCUX_EDMA_V3 endif # DMA_MCUX_EDMA || DMA_MCUX_EDMA_V3 || DMA_MCUX_EDMA_V4

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (c) 2020 NXP Semiconductor INC. * Copyright 2020-23 NXP
* All rights reserved.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -28,6 +27,8 @@
#define DT_DRV_COMPAT nxp_mcux_edma #define DT_DRV_COMPAT nxp_mcux_edma
#elif CONFIG_DMA_MCUX_EDMA_V3 #elif CONFIG_DMA_MCUX_EDMA_V3
#define DT_DRV_COMPAT nxp_mcux_edma_v3 #define DT_DRV_COMPAT nxp_mcux_edma_v3
#elif CONFIG_DMA_MCUX_EDMA_V4
#define DT_DRV_COMPAT nxp_mcux_edma_v4
#endif #endif
LOG_MODULE_REGISTER(dma_mcux_edma, CONFIG_DMA_LOG_LEVEL); LOG_MODULE_REGISTER(dma_mcux_edma, CONFIG_DMA_LOG_LEVEL);
@ -37,7 +38,9 @@ LOG_MODULE_REGISTER(dma_mcux_edma, CONFIG_DMA_LOG_LEVEL);
struct dma_mcux_edma_config { struct dma_mcux_edma_config {
DMA_Type *base; DMA_Type *base;
#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
DMAMUX_Type **dmamux_base; DMAMUX_Type **dmamux_base;
#endif
uint8_t channels_per_mux; uint8_t channels_per_mux;
uint8_t dmamux_reg_offset; uint8_t dmamux_reg_offset;
int dma_channels; /* number of channels */ int dma_channels; /* number of channels */
@ -120,11 +123,13 @@ struct dma_mcux_edma_data {
#define DEV_EDMA_HANDLE(dev, ch) \ #define DEV_EDMA_HANDLE(dev, ch) \
((edma_handle_t *)(&(DEV_CHANNEL_DATA(dev, ch)->edma_handle))) ((edma_handle_t *)(&(DEV_CHANNEL_DATA(dev, ch)->edma_handle)))
#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
#define DEV_DMAMUX_BASE(dev, idx) ((DMAMUX_Type *)DEV_CFG(dev)->dmamux_base[idx]) #define DEV_DMAMUX_BASE(dev, idx) ((DMAMUX_Type *)DEV_CFG(dev)->dmamux_base[idx])
#define DEV_DMAMUX_IDX(dev, ch) (ch / DEV_CFG(dev)->channels_per_mux) #define DEV_DMAMUX_IDX(dev, ch) (ch / DEV_CFG(dev)->channels_per_mux)
#define DEV_DMAMUX_CHANNEL(dev, ch) \ #define DEV_DMAMUX_CHANNEL(dev, ch) \
(ch % DEV_CFG(dev)->channels_per_mux) ^ (DEV_CFG(dev)->dmamux_reg_offset) (ch % DEV_CFG(dev)->channels_per_mux) ^ (DEV_CFG(dev)->dmamux_reg_offset)
#endif
/* /*
* The hardware channel (takes the gap into account) is used when access DMA registers. * The hardware channel (takes the gap into account) is used when access DMA registers.
@ -163,7 +168,7 @@ static bool data_size_valid(const size_t data_size)
return (data_size == 4U || data_size == 2U || return (data_size == 4U || data_size == 2U ||
data_size == 1U || data_size == 8U || data_size == 1U || data_size == 8U ||
data_size == 16U || data_size == 32U data_size == 16U || data_size == 32U
#ifdef CONFIG_DMA_MCUX_EDMA_V3 #if defined(CONFIG_DMA_MCUX_EDMA_V3) || defined(CONFIG_DMA_MCUX_EDMA_V4)
|| data_size == 64U || data_size == 64U
#endif #endif
); );
@ -246,7 +251,6 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
struct call_back *data = DEV_CHANNEL_DATA(dev, channel); struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
struct dma_block_config *block_config = config->head_block; struct dma_block_config *block_config = config->head_block;
uint32_t slot = config->dma_slot; uint32_t slot = config->dma_slot;
uint8_t dmamux_idx, dmamux_channel;
uint32_t hw_channel; uint32_t hw_channel;
edma_transfer_type_t transfer_type; edma_transfer_type_t transfer_type;
unsigned int key; unsigned int key;
@ -263,8 +267,12 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
} }
hw_channel = dma_mcux_edma_add_channel_gap(dev, channel); hw_channel = dma_mcux_edma_add_channel_gap(dev, channel);
#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
uint8_t dmamux_idx, dmamux_channel;
dmamux_idx = DEV_DMAMUX_IDX(dev, channel); dmamux_idx = DEV_DMAMUX_IDX(dev, channel);
dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel); dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel);
#endif
data->transfer_settings.valid = false; data->transfer_settings.valid = false;
switch (config->channel_direction) { switch (config->channel_direction) {
@ -314,6 +322,8 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
/* Lock and page in the channel configuration */ /* Lock and page in the channel configuration */
key = irq_lock(); key = irq_lock();
#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
#if DT_INST_PROP(0, nxp_a_on) #if DT_INST_PROP(0, nxp_a_on)
if (config->source_handshake || config->dest_handshake || if (config->source_handshake || config->dest_handshake ||
transfer_type == kEDMA_MemoryToMemory) { transfer_type == kEDMA_MemoryToMemory) {
@ -330,6 +340,8 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
/* dam_imx_rt_set_channel_priority(dev, channel, config); */ /* dam_imx_rt_set_channel_priority(dev, channel, config); */
DMAMUX_EnableChannel(DEV_DMAMUX_BASE(dev, dmamux_idx), dmamux_channel); DMAMUX_EnableChannel(DEV_DMAMUX_BASE(dev, dmamux_idx), dmamux_channel);
#endif
if (data->busy) { if (data->busy) {
EDMA_AbortTransfer(p_handle); EDMA_AbortTransfer(p_handle);
} }
@ -337,6 +349,12 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
EDMA_CreateHandle(p_handle, DEV_BASE(dev), hw_channel); EDMA_CreateHandle(p_handle, DEV_BASE(dev), hw_channel);
EDMA_SetCallback(p_handle, nxp_edma_callback, (void *)data); EDMA_SetCallback(p_handle, nxp_edma_callback, (void *)data);
#if defined(FSL_FEATURE_EDMA_HAS_CHANNEL_MUX) && FSL_FEATURE_EDMA_HAS_CHANNEL_MUX
/* First release any peripheral previously associated with this channel */
EDMA_SetChannelMux(DEV_BASE(dev), hw_channel, 0);
EDMA_SetChannelMux(DEV_BASE(dev), hw_channel, slot);
#endif
LOG_DBG("channel is %d", channel); LOG_DBG("channel is %d", channel);
EDMA_EnableChannelInterrupts(DEV_BASE(dev), hw_channel, kEDMA_ErrorInterruptEnable); EDMA_EnableChannelInterrupts(DEV_BASE(dev), hw_channel, kEDMA_ErrorInterruptEnable);
@ -377,7 +395,7 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
LOG_ERR("Error submitting EDMA Transfer: 0x%x", submit_status); LOG_ERR("Error submitting EDMA Transfer: 0x%x", submit_status);
ret = -EFAULT; ret = -EFAULT;
} }
#ifdef CONFIG_DMA_MCUX_EDMA_V3 #if defined(CONFIG_DMA_MCUX_EDMA_V3) || defined(CONFIG_DMA_MCUX_EDMA_V4)
LOG_DBG("DMA TCD_CSR 0x%x", DEV_BASE(dev)->CH[hw_channel].TCD_CSR); LOG_DBG("DMA TCD_CSR 0x%x", DEV_BASE(dev)->CH[hw_channel].TCD_CSR);
#else #else
LOG_DBG("data csr is 0x%x", DEV_BASE(dev)->TCD[hw_channel].CSR); LOG_DBG("data csr is 0x%x", DEV_BASE(dev)->TCD[hw_channel].CSR);
@ -411,13 +429,17 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
static int dma_mcux_edma_start(const struct device *dev, uint32_t channel) static int dma_mcux_edma_start(const struct device *dev, uint32_t channel)
{ {
struct call_back *data = DEV_CHANNEL_DATA(dev, channel); struct call_back *data = DEV_CHANNEL_DATA(dev, channel);
LOG_DBG("START TRANSFER");
#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
uint8_t dmamux_idx = DEV_DMAMUX_IDX(dev, channel); uint8_t dmamux_idx = DEV_DMAMUX_IDX(dev, channel);
uint8_t dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel); uint8_t dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel);
LOG_DBG("START TRANSFER");
LOG_DBG("DMAMUX CHCFG 0x%x", DEV_DMAMUX_BASE(dev, dmamux_idx)->CHCFG[dmamux_channel]); LOG_DBG("DMAMUX CHCFG 0x%x", DEV_DMAMUX_BASE(dev, dmamux_idx)->CHCFG[dmamux_channel]);
#endif
#ifndef CONFIG_DMA_MCUX_EDMA_V3 #if !defined(CONFIG_DMA_MCUX_EDMA_V3) && !defined(CONFIG_DMA_MCUX_EDMA_V4)
LOG_DBG("DMA CR 0x%x", DEV_BASE(dev)->CR); LOG_DBG("DMA CR 0x%x", DEV_BASE(dev)->CR);
#endif #endif
data->busy = true; data->busy = true;
@ -518,9 +540,6 @@ cleanup:
static int dma_mcux_edma_get_status(const struct device *dev, uint32_t channel, static int dma_mcux_edma_get_status(const struct device *dev, uint32_t channel,
struct dma_status *status) struct dma_status *status)
{ {
uint8_t dmamux_idx = DEV_DMAMUX_IDX(dev, channel);
uint8_t dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel);
uint32_t hw_channel = dma_mcux_edma_add_channel_gap(dev, channel); uint32_t hw_channel = dma_mcux_edma_add_channel_gap(dev, channel);
if (DEV_CHANNEL_DATA(dev, channel)->busy) { if (DEV_CHANNEL_DATA(dev, channel)->busy) {
@ -532,9 +551,15 @@ static int dma_mcux_edma_get_status(const struct device *dev, uint32_t channel,
status->pending_length = 0; status->pending_length = 0;
} }
status->dir = DEV_CHANNEL_DATA(dev, channel)->transfer_settings.direction; status->dir = DEV_CHANNEL_DATA(dev, channel)->transfer_settings.direction;
LOG_DBG("DMAMUX CHCFG 0x%x", DEV_DMAMUX_BASE(dev, dmamux_idx)->CHCFG[dmamux_channel]);
#ifdef CONFIG_DMA_MCUX_EDMA_V3 #if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
uint8_t dmamux_idx = DEV_DMAMUX_IDX(dev, channel);
uint8_t dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel);
LOG_DBG("DMAMUX CHCFG 0x%x", DEV_DMAMUX_BASE(dev, dmamux_idx)->CHCFG[dmamux_channel]);
#endif
#if defined(CONFIG_DMA_MCUX_EDMA_V3) || defined(CONFIG_DMA_MCUX_EDMA_V4)
LOG_DBG("DMA MP_CSR 0x%x", DEV_BASE(dev)->MP_CSR); LOG_DBG("DMA MP_CSR 0x%x", DEV_BASE(dev)->MP_CSR);
LOG_DBG("DMA MP_ES 0x%x", DEV_BASE(dev)->MP_ES); LOG_DBG("DMA MP_ES 0x%x", DEV_BASE(dev)->MP_ES);
LOG_DBG("DMA CHx_ES 0x%x", DEV_BASE(dev)->CH[hw_channel].CH_ES); LOG_DBG("DMA CHx_ES 0x%x", DEV_BASE(dev)->CH[hw_channel].CH_ES);
@ -584,13 +609,16 @@ static int dma_mcux_edma_init(const struct device *dev)
struct dma_mcux_edma_data *data = dev->data; struct dma_mcux_edma_data *data = dev->data;
edma_config_t userConfig = { 0 }; edma_config_t userConfig = { 0 };
uint8_t i;
LOG_DBG("INIT NXP EDMA"); LOG_DBG("INIT NXP EDMA");
#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
uint8_t i;
for (i = 0; i < config->dma_channels / config->channels_per_mux; i++) { for (i = 0; i < config->dma_channels / config->channels_per_mux; i++) {
DMAMUX_Init(DEV_DMAMUX_BASE(dev, i)); DMAMUX_Init(DEV_DMAMUX_BASE(dev, i));
} }
#endif
EDMA_GetDefaultConfig(&userConfig); EDMA_GetDefaultConfig(&userConfig);
EDMA_Init(DEV_BASE(dev), &userConfig); EDMA_Init(DEV_BASE(dev), &userConfig);
@ -654,9 +682,6 @@ static int dma_mcux_edma_init(const struct device *dev)
LOG_DBG("install irq done"); \ LOG_DBG("install irq done"); \
} }
#define DMA_MCUX_EDMA_MUX(idx, n) \
(DMAMUX_Type *)DT_INST_REG_ADDR_BY_IDX(n, UTIL_INC(idx))
#if DMA_MCUX_HAS_CHANNEL_GAP #if DMA_MCUX_HAS_CHANNEL_GAP
#define DMA_MCUX_EDMA_CHANNEL_GAP(n) \ #define DMA_MCUX_EDMA_CHANNEL_GAP(n) \
.channel_gap = DT_INST_PROP_OR(n, channel_gap, \ .channel_gap = DT_INST_PROP_OR(n, channel_gap, \
@ -665,21 +690,37 @@ static int dma_mcux_edma_init(const struct device *dev)
#define DMA_MCUX_EDMA_CHANNEL_GAP(n) #define DMA_MCUX_EDMA_CHANNEL_GAP(n)
#endif #endif
#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
#define DMA_MCUX_EDMA_MUX(idx, n) \
(DMAMUX_Type *)DT_INST_REG_ADDR_BY_IDX(n, UTIL_INC(idx))
#define DMAMUX_BASE_INIT_DEFINE(n) \
static DMAMUX_Type *dmamux_base_##n[] = { \
LISTIFY(UTIL_DEC(DT_NUM_REGS(DT_DRV_INST(n))), \
DMA_MCUX_EDMA_MUX, (,), n) \
};
#define DMAMUX_BASE_INIT(n) .dmamux_base = &dmamux_base_##n[0],
#define CHANNELS_PER_MUX(n) .channels_per_mux = DT_INST_PROP(n, dma_channels) / \
ARRAY_SIZE(dmamux_base_##n),
#else
#define DMAMUX_BASE_INIT_DEFINE(n)
#define DMAMUX_BASE_INIT(n)
#define CHANNELS_PER_MUX(n)
#endif
/* /*
* define the dma * define the dma
*/ */
#define DMA_INIT(n) \ #define DMA_INIT(n) \
DMAMUX_BASE_INIT_DEFINE(n) \
static void dma_imx_config_func_##n(const struct device *dev); \ static void dma_imx_config_func_##n(const struct device *dev); \
static DMAMUX_Type *dmamux_base_##n[] = { \
LISTIFY(UTIL_DEC(DT_NUM_REGS(DT_DRV_INST(n))), \
DMA_MCUX_EDMA_MUX, (,), n) \
}; \
static const struct dma_mcux_edma_config dma_config_##n = { \ static const struct dma_mcux_edma_config dma_config_##n = { \
.base = (DMA_Type *)DT_INST_REG_ADDR(n), \ .base = (DMA_Type *)DT_INST_REG_ADDR(n), \
.dmamux_base = &dmamux_base_##n[0], \ DMAMUX_BASE_INIT(n) \
.dma_channels = DT_INST_PROP(n, dma_channels), \ .dma_channels = DT_INST_PROP(n, dma_channels), \
.channels_per_mux = DT_INST_PROP(n, dma_channels) / \ CHANNELS_PER_MUX(n) \
ARRAY_SIZE(dmamux_base_##n), \
.irq_config_func = dma_imx_config_func_##n, \ .irq_config_func = dma_imx_config_func_##n, \
.dmamux_reg_offset = DT_INST_PROP(n, dmamux_reg_offset), \ .dmamux_reg_offset = DT_INST_PROP(n, dmamux_reg_offset), \
DMA_MCUX_EDMA_CHANNEL_GAP(n) \ DMA_MCUX_EDMA_CHANNEL_GAP(n) \

View file

@ -1,6 +1,5 @@
/* /*
* Copyright (c) 2020 NXP Semiconductor INC. * Copyright 2020-23 NXP
* All rights reserved.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -15,6 +14,8 @@
#include <fsl_common.h> #include <fsl_common.h>
#include "fsl_edma.h" #include "fsl_edma.h"
#if defined(FSL_FEATURE_SOC_DMAMUX_COUNT) && FSL_FEATURE_SOC_DMAMUX_COUNT
#include "fsl_dmamux.h" #include "fsl_dmamux.h"
#endif
#endif /* DMA_MCUX_EDMA_H_*/ #endif /* DMA_MCUX_EDMA_H_*/

View file

@ -0,0 +1,14 @@
# Copyright 2024 NXP
# SPDX-License-Identifier: Apache-2.0
description: NXP MCUX EDMA version 4 controller
compatible: "nxp,mcux-edma-v4"
include: nxp,mcux-edma.yaml
properties:
no-error-irq:
type: boolean
description: |
If the SoCs don't have a separate interrupt id for error IRQ.