2019-05-27 08:51:46

by Robin Gong

[permalink] [raw]
Subject: [PATCH v2 6/7] dmaengine: fsl-edma: add i.mx7ulp edma2 version support

From: Robin Gong <[email protected]>

Add edma2 for i.mx7ulp by version v3, since v2 has already
been used by mcf-edma.
The big changes based on v1 are belows:
1. only one dmamux.
2. another clock dma_clk except dmamux clk.
3. 16 independent interrupts instead of only one interrupt for
all channels.

Signed-off-by: Robin Gong <[email protected]>
---
drivers/dma/fsl-edma-common.c | 18 +++++++++-
drivers/dma/fsl-edma-common.h | 3 ++
drivers/dma/fsl-edma.c | 84 ++++++++++++++++++++++++++++++++++++++-----
3 files changed, 96 insertions(+), 9 deletions(-)

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",
--
2.7.4


2019-05-27 09:08:18

by Sascha Hauer

[permalink] [raw]
Subject: Re: [PATCH v2 6/7] dmaengine: fsl-edma: add i.mx7ulp edma2 version support

On Mon, May 27, 2019 at 04:51:17PM +0800, [email protected] wrote:
> From: Robin Gong <[email protected]>
>
> +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

--
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 |

2019-05-27 10:07:17

by Robin Gong

[permalink] [raw]
Subject: Re: [PATCH v2 6/7] dmaengine: fsl-edma: add i.mx7ulp edma2 version support

On 2019-05-27 at 11:05 +0200, Sascha Hauer wrote:
> On Mon, May 27, 2019 at 04:51:17PM +0800, [email protected] wrote:
> >
> > From: Robin Gong <[email protected]>
> >
> > +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
>

2019-05-27 10:11:39

by Vinod Koul

[permalink] [raw]
Subject: Re: [PATCH v2 6/7] dmaengine: fsl-edma: add i.mx7ulp edma2 version support

On 27-05-19, 11:05, Sascha Hauer wrote:
> On Mon, May 27, 2019 at 04:51:17PM +0800, [email protected] wrote:
> > From: Robin Gong <[email protected]>
> >
> > +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 |

--
~Vinod