Message ID | 20190527085118.40423-7-yibin.gong@nxp.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | add edma2 for i.mx7ulp | expand |
On Mon, May 27, 2019 at 04:51:17PM +0800, yibin.gong@nxp.com wrote: > From: Robin Gong <yibin.gong@nxp.com> > > +static const struct of_device_id fsl_edma_dt_ids[] = { > + { .compatible = "fsl,vf610-edma", .data = (void *)v1 }, > + { .compatible = "fsl,imx7ulp-edma", .data = (void *)v3 }, > + { /* sentinel */ } Please put a struct type behind the .data pointer so that you can configure... > +}; > +MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); > + > @@ -218,6 +272,22 @@ static int fsl_edma_probe(struct platform_device *pdev) > fsl_edma_setup_regs(fsl_edma); > regs = &fsl_edma->regs; > > + if (fsl_edma->version == v3) { > + fsl_edma->dmamux_nr = 1; ...things like this... > @@ -264,7 +334,11 @@ static int fsl_edma_probe(struct platform_device *pdev) > } > > edma_writel(fsl_edma, ~0, regs->intl); > - ret = fsl_edma_irq_init(pdev, fsl_edma); > + > + if (fsl_edma->version == v3) > + ret = fsl_edma2_irq_init(pdev, fsl_edma); > + else > + ret = fsl_edma_irq_init(pdev, fsl_edma); ...and this one in that struct rather than littering the code more and more with such version tests. Sascha
On 2019-05-27 at 11:05 +0200, Sascha Hauer wrote: > On Mon, May 27, 2019 at 04:51:17PM +0800, yibin.gong@nxp.com wrote: > > > > From: Robin Gong <yibin.gong@nxp.com> > > > > +static const struct of_device_id fsl_edma_dt_ids[] = { > > + { .compatible = "fsl,vf610-edma", .data = (void *)v1 }, > > + { .compatible = "fsl,imx7ulp-edma", .data = (void *)v3 }, > > + { /* sentinel */ } > Please put a struct type behind the .data pointer so that you can > configure... But current only version needed, so I give up struct define.... > > > > > +}; > > +MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); > > + > > @@ -218,6 +272,22 @@ static int fsl_edma_probe(struct > > platform_device *pdev) > > fsl_edma_setup_regs(fsl_edma); > > regs = &fsl_edma->regs; > > > > + if (fsl_edma->version == v3) { > > + fsl_edma->dmamux_nr = 1; > ...things like this... Yes, dmamux_nr could be moved to struct at least. > > > > > @@ -264,7 +334,11 @@ static int fsl_edma_probe(struct > > platform_device *pdev) > > } > > > > edma_writel(fsl_edma, ~0, regs->intl); > > - ret = fsl_edma_irq_init(pdev, fsl_edma); > > + > > + if (fsl_edma->version == v3) > > + ret = fsl_edma2_irq_init(pdev, fsl_edma); > > + else > > + ret = fsl_edma_irq_init(pdev, fsl_edma); > ...and this one in that struct rather than littering the code more > and > more with such version tests. Yes, such irq setup function could be moved to struct, thus, no version test in this file. Will refine it in v3. > > Sascha >
On 27-05-19, 11:05, Sascha Hauer wrote: > On Mon, May 27, 2019 at 04:51:17PM +0800, yibin.gong@nxp.com wrote: > > From: Robin Gong <yibin.gong@nxp.com> > > > > +static const struct of_device_id fsl_edma_dt_ids[] = { > > + { .compatible = "fsl,vf610-edma", .data = (void *)v1 }, > > + { .compatible = "fsl,imx7ulp-edma", .data = (void *)v3 }, > > + { /* sentinel */ } > > Please put a struct type behind the .data pointer so that you can > configure... Yeah that was the idea behind the suggestion in previous version. Something like struct fsl_edma_driver_data { unsigned int channels; ... }; and then you have const struct fsl_edma_driver_data v1_data { .channels = 1; ... }; > > > +}; > > +MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); > > + > > @@ -218,6 +272,22 @@ static int fsl_edma_probe(struct platform_device *pdev) > > fsl_edma_setup_regs(fsl_edma); > > regs = &fsl_edma->regs; > > > > + if (fsl_edma->version == v3) { > > + fsl_edma->dmamux_nr = 1; You can store the struct in driver context or store the values, so here it becomes driver->data->channel; and so on for other data, you can also point function pointers (hint edma/2_irq_init) > > ...things like this... > > > @@ -264,7 +334,11 @@ static int fsl_edma_probe(struct platform_device *pdev) > > } > > > > edma_writel(fsl_edma, ~0, regs->intl); > > - ret = fsl_edma_irq_init(pdev, fsl_edma); > > + > > + if (fsl_edma->version == v3) > > + ret = fsl_edma2_irq_init(pdev, fsl_edma); > > + else > > + ret = fsl_edma_irq_init(pdev, fsl_edma); > > ...and this one in that struct rather than littering the code more and > more with such version tests. > > Sascha > > -- > Pengutronix e.K. | | > Industrial Linux Solutions | http://www.pengutronix.de/ | > Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | > Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
diff --git a/drivers/dma/fsl-edma-common.c b/drivers/dma/fsl-edma-common.c index 45d70d3..0d9915c 100644 --- a/drivers/dma/fsl-edma-common.c +++ b/drivers/dma/fsl-edma-common.c @@ -90,6 +90,19 @@ static void mux_configure8(struct fsl_edma_chan *fsl_chan, void __iomem *addr, iowrite8(val8, addr + off); } +void mux_configure32(struct fsl_edma_chan *fsl_chan, void __iomem *addr, + u32 off, u32 slot, bool enable) +{ + u32 val; + + if (enable) + val = EDMAMUX_CHCFG_ENBL << 24 | slot; + else + val = EDMAMUX_CHCFG_DIS; + + iowrite32(val, addr + off * 4); +} + void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, unsigned int slot, bool enable) { @@ -102,7 +115,10 @@ void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan, muxaddr = fsl_chan->edma->muxbase[ch / chans_per_mux]; slot = EDMAMUX_CHCFG_SOURCE(slot); - mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable); + if (fsl_chan->edma->version == v3) + mux_configure32(fsl_chan, muxaddr, ch_off, slot, enable); + else + mux_configure8(fsl_chan, muxaddr, ch_off, slot, enable); } EXPORT_SYMBOL_GPL(fsl_edma_chan_mux); diff --git a/drivers/dma/fsl-edma-common.h b/drivers/dma/fsl-edma-common.h index 21a9cfd..2b0cc8e 100644 --- a/drivers/dma/fsl-edma-common.h +++ b/drivers/dma/fsl-edma-common.h @@ -124,6 +124,7 @@ struct fsl_edma_chan { dma_addr_t dma_dev_addr; u32 dma_dev_size; enum dma_data_direction dma_dir; + char chan_name[16]; }; struct fsl_edma_desc { @@ -138,6 +139,7 @@ struct fsl_edma_desc { enum edma_version { v1, /* 32ch, Vybrid, mpc57x, etc */ v2, /* 64ch Coldfire */ + v3, /* 32ch, i.mx7ulp */ }; struct fsl_edma_engine { @@ -145,6 +147,7 @@ struct fsl_edma_engine { void __iomem *membase; void __iomem *muxbase[DMAMUX_NR]; struct clk *muxclk[DMAMUX_NR]; + struct clk *dmaclk; u32 dmamux_nr; struct mutex fsl_edma_mutex; u32 n_chans; diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index 7b65ef4..055f430 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -165,6 +165,51 @@ fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma return 0; } +static int +fsl_edma2_irq_init(struct platform_device *pdev, + struct fsl_edma_engine *fsl_edma) +{ + struct device_node *np = pdev->dev.of_node; + int i, ret, irq; + int count = 0; + + count = of_irq_count(np); + dev_info(&pdev->dev, "%s Found %d interrupts\r\n", __func__, count); + if (count <= 2) { + dev_err(&pdev->dev, "Interrupts in DTS not correct.\n"); + return -EINVAL; + } + /* + * 16 channel independent interrupts + 1 error interrupt on i.mx7ulp. + * 2 channel share one interrupt, for example, ch0/ch16, ch1/ch17... + * For now, just simply request irq without IRQF_SHARED flag, since 16 + * channels are enough on i.mx7ulp whose M4 domain own some peripherals. + */ + for (i = 0; i < count; i++) { + irq = platform_get_irq(pdev, i); + if (irq < 0) + return -ENXIO; + + sprintf(fsl_edma->chans[i].chan_name, "eDMA2-CH%02d", i); + + /* The last IRQ is for eDMA err */ + if (i == count - 1) + ret = devm_request_irq(&pdev->dev, irq, + fsl_edma_err_handler, + 0, "eDMA2-ERR", fsl_edma); + else + + ret = devm_request_irq(&pdev->dev, irq, + fsl_edma_tx_handler, 0, + fsl_edma->chans[i].chan_name, + fsl_edma); + if (ret) + return ret; + } + + return 0; +} + static void fsl_edma_irq_exit( struct platform_device *pdev, struct fsl_edma_engine *fsl_edma) { @@ -184,8 +229,17 @@ static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma, int nr_clocks) clk_disable_unprepare(fsl_edma->muxclk[i]); } +static const struct of_device_id fsl_edma_dt_ids[] = { + { .compatible = "fsl,vf610-edma", .data = (void *)v1 }, + { .compatible = "fsl,imx7ulp-edma", .data = (void *)v3 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); + static int fsl_edma_probe(struct platform_device *pdev) { + const struct of_device_id *of_id = + of_match_device(fsl_edma_dt_ids, &pdev->dev); struct device_node *np = pdev->dev.of_node; struct fsl_edma_engine *fsl_edma; struct fsl_edma_chan *fsl_chan; @@ -205,7 +259,7 @@ static int fsl_edma_probe(struct platform_device *pdev) if (!fsl_edma) return -ENOMEM; - fsl_edma->version = v1; + fsl_edma->version = (enum edma_version)of_id->data; fsl_edma->dmamux_nr = DMAMUX_NR; fsl_edma->n_chans = chans; mutex_init(&fsl_edma->fsl_edma_mutex); @@ -218,6 +272,22 @@ static int fsl_edma_probe(struct platform_device *pdev) fsl_edma_setup_regs(fsl_edma); regs = &fsl_edma->regs; + if (fsl_edma->version == v3) { + fsl_edma->dmamux_nr = 1; + + fsl_edma->dmaclk = devm_clk_get(&pdev->dev, "dma"); + if (IS_ERR(fsl_edma->dmaclk)) { + dev_err(&pdev->dev, "Missing DMA block clock.\n"); + return PTR_ERR(fsl_edma->dmaclk); + } + + ret = clk_prepare_enable(fsl_edma->dmaclk); + if (ret) { + dev_err(&pdev->dev, "DMA clk block failed.\n"); + return ret; + } + } + for (i = 0; i < fsl_edma->dmamux_nr; i++) { char clkname[32]; @@ -264,7 +334,11 @@ static int fsl_edma_probe(struct platform_device *pdev) } edma_writel(fsl_edma, ~0, regs->intl); - ret = fsl_edma_irq_init(pdev, fsl_edma); + + if (fsl_edma->version == v3) + ret = fsl_edma2_irq_init(pdev, fsl_edma); + else + ret = fsl_edma_irq_init(pdev, fsl_edma); if (ret) return ret; @@ -383,12 +457,6 @@ static const struct dev_pm_ops fsl_edma_pm_ops = { .resume_early = fsl_edma_resume_early, }; -static const struct of_device_id fsl_edma_dt_ids[] = { - { .compatible = "fsl,vf610-edma", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids); - static struct platform_driver fsl_edma_driver = { .driver = { .name = "fsl-edma",