drivers: dma_mcux_edma: improve interrupt handling

The current implementation iterates over all channels
even if only several channels share the same irq. This
introduces one more dt property to describe an offset
between two channels share the same interrupt id.

Beside that, the error interrupt must be put as last
element of "interrupt" dt property.

Signed-off-by: Dat Nguyen Duy <dat.nguyenduy@nxp.com>
This commit is contained in:
Dat Nguyen Duy 2023-06-14 09:38:41 +07:00 committed by David Leach
commit a5cf757c9e
4 changed files with 60 additions and 53 deletions

View file

@ -137,23 +137,15 @@ static void nxp_edma_callback(edma_handle_t *handle, void *param, bool transferD
data->dma_callback(data->dev, data->user_data, channel, ret); data->dma_callback(data->dev, data->user_data, channel, ret);
} }
static void dma_mcux_edma_irq_handler(const struct device *dev, uint32_t channel)
static void dma_mcux_edma_irq_handler(const struct device *dev)
{ {
int i = 0; uint32_t flag = EDMA_GetChannelStatusFlags(DEV_BASE(dev), channel);
LOG_DBG("IRQ CALLED"); if (flag & kEDMA_InterruptFlag) {
for (i = 0; i < DT_INST_PROP(0, dma_channels); i++) {
uint32_t flag = EDMA_GetChannelStatusFlags(DEV_BASE(dev), i);
if ((flag & (uint32_t)kEDMA_InterruptFlag) != 0U) {
LOG_DBG("IRQ OCCURRED"); LOG_DBG("IRQ OCCURRED");
EDMA_HandleIRQ(DEV_EDMA_HANDLE(dev, i)); /* EDMA interrupt flag is cleared here */
EDMA_HandleIRQ(DEV_EDMA_HANDLE(dev, channel));
LOG_DBG("IRQ DONE"); LOG_DBG("IRQ DONE");
#if defined __CORTEX_M && (__CORTEX_M == 4U)
barrier_dsync_fence_full();
#endif
}
} }
} }
@ -162,18 +154,17 @@ static void dma_mcux_edma_error_irq_handler(const struct device *dev)
int i = 0; int i = 0;
uint32_t flag = 0; uint32_t flag = 0;
for (i = 0; i < DT_INST_PROP(0, dma_channels); i++) { for (i = 0; i < DEV_CFG(dev)->dma_channels; i++) {
if (DEV_CHANNEL_DATA(dev, i)->busy) { if (DEV_CHANNEL_DATA(dev, i)->busy) {
flag = EDMA_GetChannelStatusFlags(DEV_BASE(dev), i); flag = EDMA_GetChannelStatusFlags(DEV_BASE(dev), i);
LOG_INF("channel %d error status is 0x%x", i, flag); EDMA_ClearChannelStatusFlags(DEV_BASE(dev), i, 0xFFFFFFFF);
EDMA_ClearChannelStatusFlags(DEV_BASE(dev), i,
0xFFFFFFFF);
EDMA_AbortTransfer(DEV_EDMA_HANDLE(dev, i)); EDMA_AbortTransfer(DEV_EDMA_HANDLE(dev, i));
DEV_CHANNEL_DATA(dev, i)->busy = false; DEV_CHANNEL_DATA(dev, i)->busy = false;
LOG_INF("channel %d error status is 0x%x", i, flag);
} }
} }
#if defined __CORTEX_M && (__CORTEX_M == 4U) #if defined(CONFIG_CPU_CORTEX_M4)
barrier_dsync_fence_full(); barrier_dsync_fence_full();
#endif #endif
} }
@ -525,38 +516,44 @@ static int dma_mcux_edma_init(const struct device *dev)
return 0; return 0;
} }
/* The shared error interrupt (if have) must be declared as the last element in devicetree */
#define NUM_IRQS_WITHOUT_ERROR_IRQ(n) UTIL_DEC(DT_NUM_IRQS(DT_DRV_INST(n)))
#define IRQ_CONFIG(n, idx, fn) \ #define IRQ_CONFIG(n, idx, fn) \
IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, idx), ( \ { \
IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, idx, irq), \ IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, idx, irq), \
DT_INST_IRQ_BY_IDX(n, idx, priority), \ DT_INST_IRQ_BY_IDX(n, idx, priority), \
fn, \ fn, \
DEVICE_DT_INST_GET(n), 0); \ DEVICE_DT_INST_GET(n), 0); \
irq_enable(DT_INST_IRQ_BY_IDX(n, idx, irq)); \ irq_enable(DT_INST_IRQ_BY_IDX(n, idx, irq)); \
)) }
#define DMA_MCUX_EDMA_IRQ_DEFINE(idx, n) \
static void dma_mcux_edma_##n##_irq_##idx(const struct device *dev) \
{ \
dma_mcux_edma_irq_handler(dev, idx); \
\
IF_ENABLED(UTIL_BOOL(DT_INST_PROP(n, irq_shared_offset)), \
(dma_mcux_edma_irq_handler(dev, \
idx + DT_INST_PROP(n, irq_shared_offset));)) \
\
IF_ENABLED(CONFIG_CPU_CORTEX_M4, (barrier_dsync_fence_full();)) \
}
#define DMA_MCUX_EDMA_IRQ_CONFIG(idx, n) \
IRQ_CONFIG(n, idx, dma_mcux_edma_##n##_irq_##idx)
#define DMA_MCUX_EDMA_CONFIG_FUNC(n) \ #define DMA_MCUX_EDMA_CONFIG_FUNC(n) \
LISTIFY(NUM_IRQS_WITHOUT_ERROR_IRQ(n), DMA_MCUX_EDMA_IRQ_DEFINE, (), n) \
static void dma_imx_config_func_##n(const struct device *dev) \ static void dma_imx_config_func_##n(const struct device *dev) \
{ \ { \
ARG_UNUSED(dev); \ ARG_UNUSED(dev); \
\ \
IRQ_CONFIG(n, 0, dma_mcux_edma_irq_handler); \ LISTIFY(NUM_IRQS_WITHOUT_ERROR_IRQ(n), \
IRQ_CONFIG(n, 1, dma_mcux_edma_irq_handler); \ DMA_MCUX_EDMA_IRQ_CONFIG, (;), n) \
IRQ_CONFIG(n, 2, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 3, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 4, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 5, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 6, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 7, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 8, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 9, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 10, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 11, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 12, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 13, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 14, dma_mcux_edma_irq_handler); \
IRQ_CONFIG(n, 15, dma_mcux_edma_irq_handler); \
\ \
IRQ_CONFIG(n, 16, dma_mcux_edma_error_irq_handler); \ IRQ_CONFIG(n, NUM_IRQS_WITHOUT_ERROR_IRQ(n), \
dma_mcux_edma_error_irq_handler); \
\ \
LOG_DBG("install irq done"); \ LOG_DBG("install irq done"); \
} }

View file

@ -856,6 +856,7 @@
<8 0>, <9 0>, <10 0>, <11 0>, <8 0>, <9 0>, <10 0>, <11 0>,
<12 0>, <13 0>, <14 0>, <15 0>, <12 0>, <13 0>, <14 0>, <15 0>,
<16 0>; <16 0>;
irq-shared-offset = <16>;
clocks = <&ccm IMX_CCM_EDMA_CLK 0x7C 0x000000C0>; clocks = <&ccm IMX_CCM_EDMA_CLK 0x7C 0x000000C0>;
status = "disabled"; status = "disabled";
}; };

View file

@ -953,6 +953,7 @@
<8 0>, <9 0>, <10 0>, <11 0>, <8 0>, <9 0>, <10 0>, <11 0>,
<12 0>, <13 0>, <14 0>, <15 0>, <12 0>, <13 0>, <14 0>, <15 0>,
<16 0>; <16 0>;
irq-shared-offset = <16>;
}; };
edma_lpsr0: dma-controller@40c14000 { edma_lpsr0: dma-controller@40c14000 {
@ -971,6 +972,7 @@
<8 0>, <9 0>, <10 0>, <11 0>, <8 0>, <9 0>, <10 0>, <11 0>,
<12 0>, <13 0>, <14 0>, <15 0>, <12 0>, <13 0>, <14 0>, <15 0>,
<16 0>; <16 0>;
irq-shared-offset = <16>;
}; };
pxp: pxp@40814000 { pxp: pxp@40814000 {

View file

@ -31,6 +31,13 @@ properties:
type: boolean type: boolean
description: If the DMA controller supports always on description: If the DMA controller supports always on
irq-shared-offset:
type: int
default: 0
description: |
Describes an offset between two channels share the same interrupt entry.
Default value means each channel has separate interrupt entry.
"#dma-cells": "#dma-cells":
type: int type: int
required: true required: true