Message ID | 20241216075819.2066772-7-larisa.grigore@oss.nxp.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Add eDMAv3 support for S32G2/S32G3 SoCs | expand |
On Mon, Dec 16, 2024 at 09:58:16AM +0200, Larisa Grigore wrote: > S32G2/S32G3 includes two system eDMA instances based on v3 version, each of > them integrated with two DMAMUX blocks. Nit: empty line here > Another particularity of these SoCs is that the interrupts are shared > between channels as follows: > - DMA Channels 0-15 share the 'tx-0-15' interrupt > - DMA Channels 16-31 share the 'tx-16-31' interrupt > - all channels share the 'err' interrupt > > Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com> > Co-developed-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com> > Signed-off-by: Ciprian Marian Costea <ciprianmarian.costea@nxp.com> > --- Reviewed-by: Frank Li <Frank.Li@nxp.com> > drivers/dma/fsl-edma-common.h | 3 + > drivers/dma/fsl-edma-main.c | 109 +++++++++++++++++++++++++++++++++- > 2 files changed, 111 insertions(+), 1 deletion(-) > > diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h > index 52901623d6fc..63e908fc3575 100644 > --- a/drivers/dma/fsl-edma-common.h > +++ b/drivers/dma/fsl-edma-common.h > @@ -68,6 +68,8 @@ > #define EDMA_V3_CH_CSR_EEI BIT(2) > #define EDMA_V3_CH_CSR_DONE BIT(30) > #define EDMA_V3_CH_CSR_ACTIVE BIT(31) > +#define EDMA_V3_CH_ES_ERR BIT(31) > +#define EDMA_V3_MP_ES_VLD BIT(31) > > enum fsl_edma_pm_state { > RUNNING = 0, > @@ -252,6 +254,7 @@ struct fsl_edma_engine { > const struct fsl_edma_drvdata *drvdata; > u32 n_chans; > int txirq; > + int txirq_16_31; > int errirq; > bool big_endian; > struct edma_regs regs; > diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c > index cc1787698b56..27bae3649026 100644 > --- a/drivers/dma/fsl-edma-main.c > +++ b/drivers/dma/fsl-edma-main.c > @@ -3,10 +3,11 @@ > * drivers/dma/fsl-edma.c > * > * Copyright 2013-2014 Freescale Semiconductor, Inc. > + * Copyright 2024 NXP > * > * Driver for the Freescale eDMA engine with flexible channel multiplexing > * capability for DMA request sources. The eDMA block can be found on some > - * Vybrid and Layerscape SoCs. > + * Vybrid, Layerscape and S32G SoCs. > */ > > #include <dt-bindings/dma/fsl-edma.h> > @@ -73,6 +74,60 @@ static irqreturn_t fsl_edma2_tx_handler(int irq, void *devi_id) > return fsl_edma_tx_handler(irq, fsl_chan->edma); > } > > +static irqreturn_t fsl_edma3_or_tx_handler(int irq, void *dev_id, > + u8 start, u8 end) > +{ > + struct fsl_edma_engine *fsl_edma = dev_id; > + struct fsl_edma_chan *chan; > + int i; > + > + end = min(end, fsl_edma->n_chans); > + > + for (i = start; i < end; i++) { > + chan = &fsl_edma->chans[i]; > + > + fsl_edma3_tx_handler(irq, chan); > + } > + > + return IRQ_HANDLED; > +} > + > +static irqreturn_t fsl_edma3_tx_0_15_handler(int irq, void *dev_id) > +{ > + return fsl_edma3_or_tx_handler(irq, dev_id, 0, 16); > +} > + > +static irqreturn_t fsl_edma3_tx_16_31_handler(int irq, void *dev_id) > +{ > + return fsl_edma3_or_tx_handler(irq, dev_id, 16, 32); > +} > + > +static irqreturn_t fsl_edma3_or_err_handler(int irq, void *dev_id) > +{ > + struct fsl_edma_engine *fsl_edma = dev_id; > + struct edma_regs *regs = &fsl_edma->regs; > + unsigned int err, ch, ch_es; > + struct fsl_edma_chan *chan; > + > + err = edma_readl(fsl_edma, regs->es); > + if (!(err & EDMA_V3_MP_ES_VLD)) > + return IRQ_NONE; > + > + for (ch = 0; ch < fsl_edma->n_chans; ch++) { > + chan = &fsl_edma->chans[ch]; > + > + ch_es = edma_readl_chreg(chan, ch_es); > + if (!(ch_es & EDMA_V3_CH_ES_ERR)) > + continue; > + > + edma_writel_chreg(chan, EDMA_V3_CH_ES_ERR, ch_es); > + fsl_edma_disable_request(chan); > + fsl_edma->chans[ch].status = DMA_ERROR; > + } > + > + return IRQ_HANDLED; > +} > + > static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id) > { > struct fsl_edma_engine *fsl_edma = dev_id; > @@ -276,6 +331,49 @@ static int fsl_edma3_irq_init(struct platform_device *pdev, struct fsl_edma_engi > return 0; > } > > +static int fsl_edma3_or_irq_init(struct platform_device *pdev, > + struct fsl_edma_engine *fsl_edma) > +{ > + int ret; > + > + fsl_edma->txirq = platform_get_irq_byname(pdev, "tx-0-15"); > + if (fsl_edma->txirq < 0) > + return fsl_edma->txirq; > + > + fsl_edma->txirq_16_31 = platform_get_irq_byname(pdev, "tx-16-31"); > + if (fsl_edma->txirq_16_31 < 0) > + return fsl_edma->txirq_16_31; > + > + fsl_edma->errirq = platform_get_irq_byname(pdev, "err"); > + if (fsl_edma->errirq < 0) > + return fsl_edma->errirq; > + > + ret = devm_request_irq(&pdev->dev, fsl_edma->txirq, > + fsl_edma3_tx_0_15_handler, 0, "eDMA tx0_15", > + fsl_edma); > + if (ret) > + return dev_err_probe(&pdev->dev, ret, > + "Can't register eDMA tx0_15 IRQ.\n"); > + > + if (fsl_edma->n_chans > 16) { > + ret = devm_request_irq(&pdev->dev, fsl_edma->txirq_16_31, > + fsl_edma3_tx_16_31_handler, 0, > + "eDMA tx16_31", fsl_edma); > + if (ret) > + return dev_err_probe(&pdev->dev, ret, > + "Can't register eDMA tx16_31 IRQ.\n"); > + } > + > + ret = devm_request_irq(&pdev->dev, fsl_edma->errirq, > + fsl_edma3_or_err_handler, 0, "eDMA err", > + fsl_edma); > + if (ret) > + return dev_err_probe(&pdev->dev, ret, > + "Can't register eDMA err IRQ.\n"); > + > + return 0; > +} > + > static int > fsl_edma2_irq_init(struct platform_device *pdev, > struct fsl_edma_engine *fsl_edma) > @@ -406,6 +504,14 @@ static struct fsl_edma_drvdata imx95_data5 = { > .setup_irq = fsl_edma3_irq_init, > }; > > +static const struct fsl_edma_drvdata s32g2_data = { > + .dmamuxs = DMAMUX_NR, > + .chreg_space_sz = EDMA_TCD, > + .chreg_off = 0x4000, > + .flags = FSL_EDMA_DRV_EDMA3 | FSL_EDMA_DRV_MUX_SWAP, > + .setup_irq = fsl_edma3_or_irq_init, > +}; > + > static const struct of_device_id fsl_edma_dt_ids[] = { > { .compatible = "fsl,vf610-edma", .data = &vf610_data}, > { .compatible = "fsl,ls1028a-edma", .data = &ls1028a_data}, > @@ -415,6 +521,7 @@ static const struct of_device_id fsl_edma_dt_ids[] = { > { .compatible = "fsl,imx93-edma3", .data = &imx93_data3}, > { .compatible = "fsl,imx93-edma4", .data = &imx93_data4}, > { .compatible = "fsl,imx95-edma5", .data = &imx95_data5}, > + { .compatible = "nxp,s32g2-edma", .data = &s32g2_data}, > { /* sentinel */ } > }; > MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); > -- > 2.47.0 >
diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 52901623d6fc..63e908fc3575 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -68,6 +68,8 @@ #define EDMA_V3_CH_CSR_EEI BIT(2) #define EDMA_V3_CH_CSR_DONE BIT(30) #define EDMA_V3_CH_CSR_ACTIVE BIT(31) +#define EDMA_V3_CH_ES_ERR BIT(31) +#define EDMA_V3_MP_ES_VLD BIT(31) enum fsl_edma_pm_state { RUNNING = 0, @@ -252,6 +254,7 @@ struct fsl_edma_engine { const struct fsl_edma_drvdata *drvdata; u32 n_chans; int txirq; + int txirq_16_31; int errirq; bool big_endian; struct edma_regs regs; diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index cc1787698b56..27bae3649026 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -3,10 +3,11 @@ * drivers/dma/fsl-edma.c * * Copyright 2013-2014 Freescale Semiconductor, Inc. + * Copyright 2024 NXP * * Driver for the Freescale eDMA engine with flexible channel multiplexing * capability for DMA request sources. The eDMA block can be found on some - * Vybrid and Layerscape SoCs. + * Vybrid, Layerscape and S32G SoCs. */ #include <dt-bindings/dma/fsl-edma.h> @@ -73,6 +74,60 @@ static irqreturn_t fsl_edma2_tx_handler(int irq, void *devi_id) return fsl_edma_tx_handler(irq, fsl_chan->edma); } +static irqreturn_t fsl_edma3_or_tx_handler(int irq, void *dev_id, + u8 start, u8 end) +{ + struct fsl_edma_engine *fsl_edma = dev_id; + struct fsl_edma_chan *chan; + int i; + + end = min(end, fsl_edma->n_chans); + + for (i = start; i < end; i++) { + chan = &fsl_edma->chans[i]; + + fsl_edma3_tx_handler(irq, chan); + } + + return IRQ_HANDLED; +} + +static irqreturn_t fsl_edma3_tx_0_15_handler(int irq, void *dev_id) +{ + return fsl_edma3_or_tx_handler(irq, dev_id, 0, 16); +} + +static irqreturn_t fsl_edma3_tx_16_31_handler(int irq, void *dev_id) +{ + return fsl_edma3_or_tx_handler(irq, dev_id, 16, 32); +} + +static irqreturn_t fsl_edma3_or_err_handler(int irq, void *dev_id) +{ + struct fsl_edma_engine *fsl_edma = dev_id; + struct edma_regs *regs = &fsl_edma->regs; + unsigned int err, ch, ch_es; + struct fsl_edma_chan *chan; + + err = edma_readl(fsl_edma, regs->es); + if (!(err & EDMA_V3_MP_ES_VLD)) + return IRQ_NONE; + + for (ch = 0; ch < fsl_edma->n_chans; ch++) { + chan = &fsl_edma->chans[ch]; + + ch_es = edma_readl_chreg(chan, ch_es); + if (!(ch_es & EDMA_V3_CH_ES_ERR)) + continue; + + edma_writel_chreg(chan, EDMA_V3_CH_ES_ERR, ch_es); + fsl_edma_disable_request(chan); + fsl_edma->chans[ch].status = DMA_ERROR; + } + + return IRQ_HANDLED; +} + static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id) { struct fsl_edma_engine *fsl_edma = dev_id; @@ -276,6 +331,49 @@ static int fsl_edma3_irq_init(struct platform_device *pdev, struct fsl_edma_engi return 0; } +static int fsl_edma3_or_irq_init(struct platform_device *pdev, + struct fsl_edma_engine *fsl_edma) +{ + int ret; + + fsl_edma->txirq = platform_get_irq_byname(pdev, "tx-0-15"); + if (fsl_edma->txirq < 0) + return fsl_edma->txirq; + + fsl_edma->txirq_16_31 = platform_get_irq_byname(pdev, "tx-16-31"); + if (fsl_edma->txirq_16_31 < 0) + return fsl_edma->txirq_16_31; + + fsl_edma->errirq = platform_get_irq_byname(pdev, "err"); + if (fsl_edma->errirq < 0) + return fsl_edma->errirq; + + ret = devm_request_irq(&pdev->dev, fsl_edma->txirq, + fsl_edma3_tx_0_15_handler, 0, "eDMA tx0_15", + fsl_edma); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Can't register eDMA tx0_15 IRQ.\n"); + + if (fsl_edma->n_chans > 16) { + ret = devm_request_irq(&pdev->dev, fsl_edma->txirq_16_31, + fsl_edma3_tx_16_31_handler, 0, + "eDMA tx16_31", fsl_edma); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Can't register eDMA tx16_31 IRQ.\n"); + } + + ret = devm_request_irq(&pdev->dev, fsl_edma->errirq, + fsl_edma3_or_err_handler, 0, "eDMA err", + fsl_edma); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Can't register eDMA err IRQ.\n"); + + return 0; +} + static int fsl_edma2_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma) @@ -406,6 +504,14 @@ static struct fsl_edma_drvdata imx95_data5 = { .setup_irq = fsl_edma3_irq_init, }; +static const struct fsl_edma_drvdata s32g2_data = { + .dmamuxs = DMAMUX_NR, + .chreg_space_sz = EDMA_TCD, + .chreg_off = 0x4000, + .flags = FSL_EDMA_DRV_EDMA3 | FSL_EDMA_DRV_MUX_SWAP, + .setup_irq = fsl_edma3_or_irq_init, +}; + static const struct of_device_id fsl_edma_dt_ids[] = { { .compatible = "fsl,vf610-edma", .data = &vf610_data}, { .compatible = "fsl,ls1028a-edma", .data = &ls1028a_data}, @@ -415,6 +521,7 @@ static const struct of_device_id fsl_edma_dt_ids[] = { { .compatible = "fsl,imx93-edma3", .data = &imx93_data3}, { .compatible = "fsl,imx93-edma4", .data = &imx93_data4}, { .compatible = "fsl,imx95-edma5", .data = &imx95_data5}, + { .compatible = "nxp,s32g2-edma", .data = &s32g2_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);