@@ -35,9 +35,8 @@ Required Properties:
- interrupts: interrupt specifiers for the DMAC, one for each entry in
interrupt-names.
-- interrupt-names: one entry for the error interrupt, named "error", plus one
- entry per channel, named "ch%u", where %u is the channel number ranging from
- zero to the number of channels minus one.
+- interrupt-names: one entry per channel, named "ch%u", where %u is the
+ channel number ranging from zero to the number of channels minus one.
- clock-names: "fck" for the functional clock
- clocks: a list of phandle + clock-specifier pairs, one for each entry
@@ -53,8 +52,7 @@ Example: R8A7790 (R-Car H2) SYS-DMACs
dmac0: dma-controller@e6700000 {
compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
reg = <0 0xe6700000 0 0x20000>;
- interrupts = <0 197 IRQ_TYPE_LEVEL_HIGH
- 0 200 IRQ_TYPE_LEVEL_HIGH
+ interrupts = <0 200 IRQ_TYPE_LEVEL_HIGH
0 201 IRQ_TYPE_LEVEL_HIGH
0 202 IRQ_TYPE_LEVEL_HIGH
0 203 IRQ_TYPE_LEVEL_HIGH
@@ -69,8 +67,7 @@ Example: R8A7790 (R-Car H2) SYS-DMACs
0 212 IRQ_TYPE_LEVEL_HIGH
0 213 IRQ_TYPE_LEVEL_HIGH
0 214 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "error",
- "ch0", "ch1", "ch2", "ch3",
+ interrupt-names = "ch0", "ch1", "ch2", "ch3",
"ch4", "ch5", "ch6", "ch7",
"ch8", "ch9", "ch10", "ch11",
"ch12", "ch13", "ch14";
@@ -83,8 +80,7 @@ Example: R8A7790 (R-Car H2) SYS-DMACs
dmac1: dma-controller@e6720000 {
compatible = "renesas,dmac-r8a7790", "renesas,rcar-dmac";
reg = <0 0xe6720000 0 0x20000>;
- interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH
- 0 216 IRQ_TYPE_LEVEL_HIGH
+ interrupts = <0 216 IRQ_TYPE_LEVEL_HIGH
0 217 IRQ_TYPE_LEVEL_HIGH
0 218 IRQ_TYPE_LEVEL_HIGH
0 219 IRQ_TYPE_LEVEL_HIGH
@@ -99,8 +95,7 @@ Example: R8A7790 (R-Car H2) SYS-DMACs
0 316 IRQ_TYPE_LEVEL_HIGH
0 317 IRQ_TYPE_LEVEL_HIGH
0 318 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "error",
- "ch0", "ch1", "ch2", "ch3",
+ interrupt-names = "ch0", "ch1", "ch2", "ch3",
"ch4", "ch5", "ch6", "ch7",
"ch8", "ch9", "ch10", "ch11",
"ch12", "ch13", "ch14";
@@ -431,7 +431,8 @@ static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan)
chcr |= RCAR_DMACHCR_DPM_DISABLED | RCAR_DMACHCR_IE;
}
- rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr | RCAR_DMACHCR_DE);
+ rcar_dmac_chan_write(chan, RCAR_DMACHCR,
+ chcr | RCAR_DMACHCR_DE | RCAR_DMACHCR_CAIE);
}
static int rcar_dmac_init(struct rcar_dmac *dmac)
@@ -783,7 +784,8 @@ static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
chcr &= ~(RCAR_DMACHCR_DSE | RCAR_DMACHCR_DSIE | RCAR_DMACHCR_IE |
- RCAR_DMACHCR_TE | RCAR_DMACHCR_DE);
+ RCAR_DMACHCR_TE | RCAR_DMACHCR_DE |
+ RCAR_DMACHCR_CAE | RCAR_DMACHCR_CAIE);
rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr);
rcar_dmac_chcr_de_barrier(chan);
}
@@ -812,12 +814,7 @@ static void rcar_dmac_chan_reinit(struct rcar_dmac_chan *chan)
}
}
-static void rcar_dmac_stop(struct rcar_dmac *dmac)
-{
- rcar_dmac_write(dmac, RCAR_DMAOR, 0);
-}
-
-static void rcar_dmac_abort(struct rcar_dmac *dmac)
+static void rcar_dmac_stop_all_chan(struct rcar_dmac *dmac)
{
unsigned int i;
@@ -829,11 +826,10 @@ static void rcar_dmac_abort(struct rcar_dmac *dmac)
spin_lock(&chan->lock);
rcar_dmac_chan_halt(chan);
spin_unlock(&chan->lock);
-
- rcar_dmac_chan_reinit(chan);
}
}
+
/* -----------------------------------------------------------------------------
* Descriptors preparation
*/
@@ -1522,25 +1518,37 @@ static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev)
u32 mask = RCAR_DMACHCR_DSE | RCAR_DMACHCR_TE;
struct rcar_dmac_chan *chan = dev;
irqreturn_t ret = IRQ_NONE;
+ bool reinit = false;
u32 chcr;
spin_lock(&chan->lock);
chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
- if (chcr & RCAR_DMACHCR_TE)
- mask |= RCAR_DMACHCR_DE;
- rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask);
- if (mask & RCAR_DMACHCR_DE)
- rcar_dmac_chcr_de_barrier(chan);
-
- if (chcr & RCAR_DMACHCR_DSE)
- ret |= rcar_dmac_isr_desc_stage_end(chan);
+ if (chcr & RCAR_DMACHCR_CAE) {
+ rcar_dmac_chan_halt(chan);
+ reinit = true;
+ } else {
+ if (chcr & RCAR_DMACHCR_TE)
+ mask |= RCAR_DMACHCR_DE;
+ rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask);
+ if (mask & RCAR_DMACHCR_DE)
+ rcar_dmac_chcr_de_barrier(chan);
- if (chcr & RCAR_DMACHCR_TE)
- ret |= rcar_dmac_isr_transfer_end(chan);
+ if (chcr & RCAR_DMACHCR_DSE)
+ ret |= rcar_dmac_isr_desc_stage_end(chan);
+ if (chcr & RCAR_DMACHCR_TE)
+ ret |= rcar_dmac_isr_transfer_end(chan);
+ }
spin_unlock(&chan->lock);
+ if (reinit) {
+ dev_err(chan->chan.device->dev, "Channel Address Error happen\n");
+
+ rcar_dmac_chan_reinit(chan);
+ ret = IRQ_HANDLED;
+ }
+
return ret;
}
@@ -1597,24 +1605,6 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev)
return IRQ_HANDLED;
}
-static irqreturn_t rcar_dmac_isr_error(int irq, void *data)
-{
- struct rcar_dmac *dmac = data;
-
- if (!(rcar_dmac_read(dmac, RCAR_DMAOR) & RCAR_DMAOR_AE))
- return IRQ_NONE;
-
- /*
- * An unrecoverable error occurred on an unknown channel. Halt the DMAC,
- * abort transfers on all channels, and reinitialize the DMAC.
- */
- rcar_dmac_stop(dmac);
- rcar_dmac_abort(dmac);
- rcar_dmac_init(dmac);
-
- return IRQ_HANDLED;
-}
-
/* -----------------------------------------------------------------------------
* OF xlate and channel filter
*/
@@ -1784,8 +1774,6 @@ static int rcar_dmac_probe(struct platform_device *pdev)
struct rcar_dmac *dmac;
struct resource *mem;
unsigned int i;
- char *irqname;
- int irq;
int ret;
dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL);
@@ -1824,17 +1812,6 @@ static int rcar_dmac_probe(struct platform_device *pdev)
if (IS_ERR(dmac->iomem))
return PTR_ERR(dmac->iomem);
- irq = platform_get_irq_byname(pdev, "error");
- if (irq < 0) {
- dev_err(&pdev->dev, "no error IRQ specified\n");
- return -ENODEV;
- }
-
- irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:error",
- dev_name(dmac->dev));
- if (!irqname)
- return -ENOMEM;
-
/* Enable runtime PM and initialize the device. */
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
@@ -1885,14 +1862,6 @@ static int rcar_dmac_probe(struct platform_device *pdev)
goto error;
}
- ret = devm_request_irq(&pdev->dev, irq, rcar_dmac_isr_error, 0,
- irqname, dmac);
- if (ret) {
- dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n",
- irq, ret);
- return ret;
- }
-
/* Register the DMAC as a DMA provider for DT. */
ret = of_dma_controller_register(pdev->dev.of_node, rcar_dmac_of_xlate,
NULL);
@@ -1932,7 +1901,7 @@ static void rcar_dmac_shutdown(struct platform_device *pdev)
{
struct rcar_dmac *dmac = platform_get_drvdata(pdev);
- rcar_dmac_stop(dmac);
+ rcar_dmac_stop_all_chan(dmac);
}
static const struct of_device_id rcar_dmac_of_ids[] = {