From a5cf757c9ecbaa562a4f31b58bf133a4b978da8a Mon Sep 17 00:00:00 2001 From: Dat Nguyen Duy Date: Wed, 14 Jun 2023 09:38:41 +0700 Subject: [PATCH] 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 --- drivers/dma/dma_mcux_edma.c | 103 ++++++++++++++-------------- dts/arm/nxp/nxp_rt10xx.dtsi | 1 + dts/arm/nxp/nxp_rt11xx.dtsi | 2 + dts/bindings/dma/nxp,mcux-edma.yaml | 7 ++ 4 files changed, 60 insertions(+), 53 deletions(-) diff --git a/drivers/dma/dma_mcux_edma.c b/drivers/dma/dma_mcux_edma.c index e2f7da80729..10fc71bb6b7 100644 --- a/drivers/dma/dma_mcux_edma.c +++ b/drivers/dma/dma_mcux_edma.c @@ -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); } - -static void dma_mcux_edma_irq_handler(const struct device *dev) +static void dma_mcux_edma_irq_handler(const struct device *dev, uint32_t channel) { - int i = 0; + uint32_t flag = EDMA_GetChannelStatusFlags(DEV_BASE(dev), channel); - LOG_DBG("IRQ CALLED"); - 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"); - EDMA_HandleIRQ(DEV_EDMA_HANDLE(dev, i)); - LOG_DBG("IRQ DONE"); -#if defined __CORTEX_M && (__CORTEX_M == 4U) - barrier_dsync_fence_full(); -#endif - } + if (flag & kEDMA_InterruptFlag) { + LOG_DBG("IRQ OCCURRED"); + /* EDMA interrupt flag is cleared here */ + EDMA_HandleIRQ(DEV_EDMA_HANDLE(dev, channel)); + LOG_DBG("IRQ DONE"); } } @@ -162,18 +154,17 @@ static void dma_mcux_edma_error_irq_handler(const struct device *dev) int i = 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) { 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)); 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(); #endif } @@ -525,40 +516,46 @@ static int dma_mcux_edma_init(const struct device *dev) return 0; } -#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), \ - DT_INST_IRQ_BY_IDX(n, idx, priority), \ - fn, \ - DEVICE_DT_INST_GET(n), 0); \ - irq_enable(DT_INST_IRQ_BY_IDX(n, idx, irq)); \ - )) +/* 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 DMA_MCUX_EDMA_CONFIG_FUNC(n) \ - static void dma_imx_config_func_##n(const struct device *dev) \ - { \ - ARG_UNUSED(dev); \ - \ - IRQ_CONFIG(n, 0, dma_mcux_edma_irq_handler); \ - IRQ_CONFIG(n, 1, dma_mcux_edma_irq_handler); \ - 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); \ - \ - LOG_DBG("install irq done"); \ +#define IRQ_CONFIG(n, idx, fn) \ + { \ + IRQ_CONNECT(DT_INST_IRQ_BY_IDX(n, idx, irq), \ + DT_INST_IRQ_BY_IDX(n, idx, priority), \ + fn, \ + DEVICE_DT_INST_GET(n), 0); \ + 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) \ + LISTIFY(NUM_IRQS_WITHOUT_ERROR_IRQ(n), DMA_MCUX_EDMA_IRQ_DEFINE, (), n) \ + static void dma_imx_config_func_##n(const struct device *dev) \ + { \ + ARG_UNUSED(dev); \ + \ + LISTIFY(NUM_IRQS_WITHOUT_ERROR_IRQ(n), \ + DMA_MCUX_EDMA_IRQ_CONFIG, (;), n) \ + \ + IRQ_CONFIG(n, NUM_IRQS_WITHOUT_ERROR_IRQ(n), \ + dma_mcux_edma_error_irq_handler); \ + \ + LOG_DBG("install irq done"); \ } #define DMA_MCUX_EDMA_MUX(idx, n) \ diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 6e4f6278fae..1f1ff416099 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -856,6 +856,7 @@ <8 0>, <9 0>, <10 0>, <11 0>, <12 0>, <13 0>, <14 0>, <15 0>, <16 0>; + irq-shared-offset = <16>; clocks = <&ccm IMX_CCM_EDMA_CLK 0x7C 0x000000C0>; status = "disabled"; }; diff --git a/dts/arm/nxp/nxp_rt11xx.dtsi b/dts/arm/nxp/nxp_rt11xx.dtsi index b333816a2c8..0deede76c37 100644 --- a/dts/arm/nxp/nxp_rt11xx.dtsi +++ b/dts/arm/nxp/nxp_rt11xx.dtsi @@ -953,6 +953,7 @@ <8 0>, <9 0>, <10 0>, <11 0>, <12 0>, <13 0>, <14 0>, <15 0>, <16 0>; + irq-shared-offset = <16>; }; edma_lpsr0: dma-controller@40c14000 { @@ -971,6 +972,7 @@ <8 0>, <9 0>, <10 0>, <11 0>, <12 0>, <13 0>, <14 0>, <15 0>, <16 0>; + irq-shared-offset = <16>; }; pxp: pxp@40814000 { diff --git a/dts/bindings/dma/nxp,mcux-edma.yaml b/dts/bindings/dma/nxp,mcux-edma.yaml index 7c82982132e..0a0b0a66e2d 100644 --- a/dts/bindings/dma/nxp,mcux-edma.yaml +++ b/dts/bindings/dma/nxp,mcux-edma.yaml @@ -31,6 +31,13 @@ properties: type: boolean 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": type: int required: true