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:
parent
f27815d645
commit
03b5ba5990
1 changed files with 51 additions and 28 deletions
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue