drivers: dma_mcux_edma: add support for multiple DMAMuxes

This adds support for platforms that have multiple DMAMUXes
per DMA instance

Signed-off-by: Dat Nguyen Duy <dat.nguyenduy@nxp.com>
This commit is contained in:
Dat Nguyen Duy 2023-06-13 17:21:37 +07:00 committed by David Leach
commit 03b5ba5990

View file

@ -30,7 +30,8 @@ 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;
DMAMUX_Type *dmamux_base; DMAMUX_Type **dmamux_base;
uint8_t channels_per_mux;
int dma_channels; /* number of channels */ int dma_channels; /* number of channels */
void (*irq_config_func)(const struct device *dev); void (*irq_config_func)(const struct device *dev);
}; };
@ -102,14 +103,16 @@ struct dma_mcux_edma_data {
#define DEV_DATA(dev) ((struct dma_mcux_edma_data *)dev->data) #define DEV_DATA(dev) ((struct dma_mcux_edma_data *)dev->data)
#define DEV_BASE(dev) ((DMA_Type *)DEV_CFG(dev)->base) #define DEV_BASE(dev) ((DMA_Type *)DEV_CFG(dev)->base)
#define DEV_DMAMUX_BASE(dev) ((DMAMUX_Type *)DEV_CFG(dev)->dmamux_base)
#define DEV_CHANNEL_DATA(dev, ch) \ #define DEV_CHANNEL_DATA(dev, ch) \
((struct call_back *)(&(DEV_DATA(dev)->data_cb[ch]))) ((struct call_back *)(&(DEV_DATA(dev)->data_cb[ch])))
#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)))
#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_CHANNEL(dev, ch) (ch % DEV_CFG(dev)->channels_per_mux)
static bool data_size_valid(const size_t data_size) static bool data_size_valid(const size_t data_size)
{ {
return (data_size == 4U || data_size == 2U || return (data_size == 4U || data_size == 2U ||
@ -188,6 +191,7 @@ 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;
edma_transfer_type_t transfer_type; edma_transfer_type_t transfer_type;
unsigned int key; unsigned int key;
int ret = 0; int ret = 0;
@ -202,6 +206,8 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
return -EINVAL; return -EINVAL;
} }
dmamux_idx = DEV_DMAMUX_IDX(dev, channel);
dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel);
data->transfer_settings.valid = false; data->transfer_settings.valid = false;
switch (config->channel_direction) { switch (config->channel_direction) {
@ -256,16 +262,16 @@ static int dma_mcux_edma_configure(const struct device *dev, uint32_t channel,
transfer_type == kEDMA_MemoryToMemory) { transfer_type == kEDMA_MemoryToMemory) {
/*software trigger make the channel always on*/ /*software trigger make the channel always on*/
LOG_DBG("ALWAYS ON"); LOG_DBG("ALWAYS ON");
DMAMUX_EnableAlwaysOn(DEV_DMAMUX_BASE(dev), channel, true); DMAMUX_EnableAlwaysOn(DEV_DMAMUX_BASE(dev, dmamux_idx), dmamux_channel, true);
} else { } else {
DMAMUX_SetSource(DEV_DMAMUX_BASE(dev), channel, slot); DMAMUX_SetSource(DEV_DMAMUX_BASE(dev, dmamux_idx), dmamux_channel, slot);
} }
#else #else
DMAMUX_SetSource(DEV_DMAMUX_BASE(dev), channel, slot); DMAMUX_SetSource(DEV_DMAMUX_BASE(dev, dmamux_idx), dmamux_channel, slot);
#endif #endif
/* dam_imx_rt_set_channel_priority(dev, channel, config); */ /* dam_imx_rt_set_channel_priority(dev, channel, config); */
DMAMUX_EnableChannel(DEV_DMAMUX_BASE(dev), channel); DMAMUX_EnableChannel(DEV_DMAMUX_BASE(dev, dmamux_idx), dmamux_channel);
if (data->busy) { if (data->busy) {
EDMA_AbortTransfer(p_handle); EDMA_AbortTransfer(p_handle);
@ -345,9 +351,11 @@ 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);
uint8_t dmamux_idx = DEV_DMAMUX_IDX(dev, channel);
uint8_t dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel);
LOG_DBG("START TRANSFER"); LOG_DBG("START TRANSFER");
LOG_DBG("DMAMUX CHCFG 0x%x", DEV_DMAMUX_BASE(dev)->CHCFG[channel]); LOG_DBG("DMAMUX CHCFG 0x%x", DEV_DMAMUX_BASE(dev, dmamux_idx)->CHCFG[dmamux_channel]);
LOG_DBG("DMA CR 0x%x", DEV_BASE(dev)->CR); LOG_DBG("DMA CR 0x%x", DEV_BASE(dev)->CR);
data->busy = true; data->busy = true;
EDMA_StartTransfer(DEV_EDMA_HANDLE(dev, channel)); EDMA_StartTransfer(DEV_EDMA_HANDLE(dev, channel));
@ -444,6 +452,8 @@ static int dma_mcux_edma_get_status(const struct device *dev, uint32_t channel,
struct dma_status *status) struct dma_status *status)
{ {
edma_tcd_t *tcdRegs; edma_tcd_t *tcdRegs;
uint8_t dmamux_idx = DEV_DMAMUX_IDX(dev, channel);
uint8_t dmamux_channel = DEV_DMAMUX_CHANNEL(dev, channel);
if (DEV_CHANNEL_DATA(dev, channel)->busy) { if (DEV_CHANNEL_DATA(dev, channel)->busy) {
status->busy = true; status->busy = true;
@ -454,7 +464,7 @@ 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)->CHCFG[channel]); LOG_DBG("DMAMUX CHCFG 0x%x", DEV_DMAMUX_BASE(dev, dmamux_idx)->CHCFG[dmamux_channel]);
LOG_DBG("DMA CR 0x%x", DEV_BASE(dev)->CR); LOG_DBG("DMA CR 0x%x", DEV_BASE(dev)->CR);
LOG_DBG("DMA INT 0x%x", DEV_BASE(dev)->INT); LOG_DBG("DMA INT 0x%x", DEV_BASE(dev)->INT);
LOG_DBG("DMA ERQ 0x%x", DEV_BASE(dev)->ERQ); LOG_DBG("DMA ERQ 0x%x", DEV_BASE(dev)->ERQ);
@ -496,9 +506,14 @@ 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");
DMAMUX_Init(DEV_DMAMUX_BASE(dev));
for (i = 0; i < config->dma_channels / config->channels_per_mux; i++) {
DMAMUX_Init(DEV_DMAMUX_BASE(dev, i));
}
EDMA_GetDefaultConfig(&userConfig); EDMA_GetDefaultConfig(&userConfig);
EDMA_Init(DEV_BASE(dev), &userConfig); EDMA_Init(DEV_BASE(dev), &userConfig);
config->irq_config_func(dev); config->irq_config_func(dev);
@ -546,27 +561,35 @@ 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))
/* /*
* define the dma * define the dma
*/ */
#define DMA_INIT(n) \ #define DMA_INIT(n) \
static void dma_imx_config_func_##n(const struct device *dev); \ static void dma_imx_config_func_##n(const struct device *dev); \
static const struct dma_mcux_edma_config dma_config_##n = { \ static DMAMUX_Type *dmamux_base_##n[] = { \
.base = (DMA_Type *)DT_INST_REG_ADDR(n), \ LISTIFY(UTIL_DEC(DT_NUM_REGS(DT_DRV_INST(n))), \
.dmamux_base = \ DMA_MCUX_EDMA_MUX, (,), n) \
(DMAMUX_Type *)DT_INST_REG_ADDR_BY_IDX(n, 1), \ }; \
.dma_channels = DT_INST_PROP(n, dma_channels), \ static const struct dma_mcux_edma_config dma_config_##n = { \
.irq_config_func = dma_imx_config_func_##n, \ .base = (DMA_Type *)DT_INST_REG_ADDR(n), \
}; \ .dmamux_base = &dmamux_base_##n[0], \
\ .dma_channels = DT_INST_PROP(n, dma_channels), \
struct dma_mcux_edma_data dma_data_##n; \ .channels_per_mux = DT_INST_PROP(n, dma_channels) / \
\ ARRAY_SIZE(dmamux_base_##n), \
DEVICE_DT_INST_DEFINE(n, \ .irq_config_func = dma_imx_config_func_##n, \
&dma_mcux_edma_init, NULL, \ }; \
&dma_data_##n, &dma_config_##n, \ \
PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, \ struct dma_mcux_edma_data dma_data_##n; \
&dma_mcux_edma_api); \ \
\ DEVICE_DT_INST_DEFINE(n, \
&dma_mcux_edma_init, NULL, \
&dma_data_##n, &dma_config_##n, \
PRE_KERNEL_1, CONFIG_DMA_INIT_PRIORITY, \
&dma_mcux_edma_api); \
\
DMA_MCUX_EDMA_CONFIG_FUNC(n); DMA_MCUX_EDMA_CONFIG_FUNC(n);
DT_INST_FOREACH_STATUS_OKAY(DMA_INIT) DT_INST_FOREACH_STATUS_OKAY(DMA_INIT)