Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 89b7e78f authored by Vinod Koul's avatar Vinod Koul
Browse files

Merge branch 'topic/renesas' into for-linus

parents 35e0db66 218c2104
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ Required Properties:
		- "renesas,dmac-r8a77965" (R-Car M3-N)
		- "renesas,dmac-r8a77965" (R-Car M3-N)
		- "renesas,dmac-r8a77970" (R-Car V3M)
		- "renesas,dmac-r8a77970" (R-Car V3M)
		- "renesas,dmac-r8a77980" (R-Car V3H)
		- "renesas,dmac-r8a77980" (R-Car V3H)
		- "renesas,dmac-r8a77990" (R-Car E3)
		- "renesas,dmac-r8a77995" (R-Car D3)
		- "renesas,dmac-r8a77995" (R-Car D3)


- reg: base address and length of the registers block for the DMAC
- reg: base address and length of the registers block for the DMAC
+46 −66
Original line number Original line Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
/*
 * Renesas R-Car Gen2 DMA Controller Driver
 * Renesas R-Car Gen2 DMA Controller Driver
 *
 *
 * Copyright (C) 2014 Renesas Electronics Inc.
 * Copyright (C) 2014 Renesas Electronics Inc.
 *
 *
 * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 */
 */


#include <linux/delay.h>
#include <linux/delay.h>
@@ -431,7 +428,8 @@ static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan)
		chcr |= RCAR_DMACHCR_DPM_DISABLED | RCAR_DMACHCR_IE;
		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)
static int rcar_dmac_init(struct rcar_dmac *dmac)
@@ -761,21 +759,15 @@ static void rcar_dmac_chcr_de_barrier(struct rcar_dmac_chan *chan)
	dev_err(chan->chan.device->dev, "CHCR DE check error\n");
	dev_err(chan->chan.device->dev, "CHCR DE check error\n");
}
}


static void rcar_dmac_sync_tcr(struct rcar_dmac_chan *chan)
static void rcar_dmac_clear_chcr_de(struct rcar_dmac_chan *chan)
{
{
	u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
	u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);


	if (!(chcr & RCAR_DMACHCR_DE))
		return;

	/* set DE=0 and flush remaining data */
	/* set DE=0 and flush remaining data */
	rcar_dmac_chan_write(chan, RCAR_DMACHCR, (chcr & ~RCAR_DMACHCR_DE));
	rcar_dmac_chan_write(chan, RCAR_DMACHCR, (chcr & ~RCAR_DMACHCR_DE));


	/* make sure all remaining data was flushed */
	/* make sure all remaining data was flushed */
	rcar_dmac_chcr_de_barrier(chan);
	rcar_dmac_chcr_de_barrier(chan);

	/* back DE */
	rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr);
}
}


static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
@@ -783,7 +775,8 @@ static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
	u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
	u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);


	chcr &= ~(RCAR_DMACHCR_DSE | RCAR_DMACHCR_DSIE | RCAR_DMACHCR_IE |
	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_chan_write(chan, RCAR_DMACHCR, chcr);
	rcar_dmac_chcr_de_barrier(chan);
	rcar_dmac_chcr_de_barrier(chan);
}
}
@@ -812,12 +805,7 @@ static void rcar_dmac_chan_reinit(struct rcar_dmac_chan *chan)
	}
	}
}
}


static void rcar_dmac_stop(struct rcar_dmac *dmac)
static void rcar_dmac_stop_all_chan(struct rcar_dmac *dmac)
{
	rcar_dmac_write(dmac, RCAR_DMAOR, 0);
}

static void rcar_dmac_abort(struct rcar_dmac *dmac)
{
{
	unsigned int i;
	unsigned int i;


@@ -826,14 +814,24 @@ static void rcar_dmac_abort(struct rcar_dmac *dmac)
		struct rcar_dmac_chan *chan = &dmac->channels[i];
		struct rcar_dmac_chan *chan = &dmac->channels[i];


		/* Stop and reinitialize the channel. */
		/* Stop and reinitialize the channel. */
		spin_lock(&chan->lock);
		spin_lock_irq(&chan->lock);
		rcar_dmac_chan_halt(chan);
		rcar_dmac_chan_halt(chan);
		spin_unlock(&chan->lock);
		spin_unlock_irq(&chan->lock);

		rcar_dmac_chan_reinit(chan);
	}
	}
}
}


static int rcar_dmac_chan_pause(struct dma_chan *chan)
{
	unsigned long flags;
	struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);

	spin_lock_irqsave(&rchan->lock, flags);
	rcar_dmac_clear_chcr_de(rchan);
	spin_unlock_irqrestore(&rchan->lock, flags);

	return 0;
}

/* -----------------------------------------------------------------------------
/* -----------------------------------------------------------------------------
 * Descriptors preparation
 * Descriptors preparation
 */
 */
@@ -1355,9 +1353,6 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
		residue += chunk->size;
		residue += chunk->size;
	}
	}


	if (desc->direction == DMA_DEV_TO_MEM)
		rcar_dmac_sync_tcr(chan);

	/* Add the residue for the current chunk. */
	/* Add the residue for the current chunk. */
	residue += rcar_dmac_chan_read(chan, RCAR_DMATCRB) << desc->xfer_shift;
	residue += rcar_dmac_chan_read(chan, RCAR_DMATCRB) << desc->xfer_shift;


@@ -1522,11 +1517,26 @@ static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev)
	u32 mask = RCAR_DMACHCR_DSE | RCAR_DMACHCR_TE;
	u32 mask = RCAR_DMACHCR_DSE | RCAR_DMACHCR_TE;
	struct rcar_dmac_chan *chan = dev;
	struct rcar_dmac_chan *chan = dev;
	irqreturn_t ret = IRQ_NONE;
	irqreturn_t ret = IRQ_NONE;
	bool reinit = false;
	u32 chcr;
	u32 chcr;


	spin_lock(&chan->lock);
	spin_lock(&chan->lock);


	chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
	chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
	if (chcr & RCAR_DMACHCR_CAE) {
		struct rcar_dmac *dmac = to_rcar_dmac(chan->chan.device);

		/*
		 * We don't need to call rcar_dmac_chan_halt()
		 * because channel is already stopped in error case.
		 * We need to clear register and check DE bit as recovery.
		 */
		rcar_dmac_write(dmac, RCAR_DMACHCLR, 1 << chan->index);
		rcar_dmac_chcr_de_barrier(chan);
		reinit = true;
		goto spin_lock_end;
	}

	if (chcr & RCAR_DMACHCR_TE)
	if (chcr & RCAR_DMACHCR_TE)
		mask |= RCAR_DMACHCR_DE;
		mask |= RCAR_DMACHCR_DE;
	rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask);
	rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask);
@@ -1539,8 +1549,16 @@ static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev)
	if (chcr & RCAR_DMACHCR_TE)
	if (chcr & RCAR_DMACHCR_TE)
		ret |= rcar_dmac_isr_transfer_end(chan);
		ret |= rcar_dmac_isr_transfer_end(chan);


spin_lock_end:
	spin_unlock(&chan->lock);
	spin_unlock(&chan->lock);


	if (reinit) {
		dev_err(chan->chan.device->dev, "Channel Address Error\n");

		rcar_dmac_chan_reinit(chan);
		ret = IRQ_HANDLED;
	}

	return ret;
	return ret;
}
}


@@ -1597,24 +1615,6 @@ static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev)
	return IRQ_HANDLED;
	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
 * OF xlate and channel filter
 */
 */
@@ -1784,8 +1784,6 @@ static int rcar_dmac_probe(struct platform_device *pdev)
	struct rcar_dmac *dmac;
	struct rcar_dmac *dmac;
	struct resource *mem;
	struct resource *mem;
	unsigned int i;
	unsigned int i;
	char *irqname;
	int irq;
	int ret;
	int ret;


	dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL);
	dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL);
@@ -1824,17 +1822,6 @@ static int rcar_dmac_probe(struct platform_device *pdev)
	if (IS_ERR(dmac->iomem))
	if (IS_ERR(dmac->iomem))
		return PTR_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. */
	/* Enable runtime PM and initialize the device. */
	pm_runtime_enable(&pdev->dev);
	pm_runtime_enable(&pdev->dev);
	ret = pm_runtime_get_sync(&pdev->dev);
	ret = pm_runtime_get_sync(&pdev->dev);
@@ -1871,6 +1858,7 @@ static int rcar_dmac_probe(struct platform_device *pdev)
	engine->device_prep_slave_sg		= rcar_dmac_prep_slave_sg;
	engine->device_prep_slave_sg		= rcar_dmac_prep_slave_sg;
	engine->device_prep_dma_cyclic		= rcar_dmac_prep_dma_cyclic;
	engine->device_prep_dma_cyclic		= rcar_dmac_prep_dma_cyclic;
	engine->device_config			= rcar_dmac_device_config;
	engine->device_config			= rcar_dmac_device_config;
	engine->device_pause			= rcar_dmac_chan_pause;
	engine->device_terminate_all		= rcar_dmac_chan_terminate_all;
	engine->device_terminate_all		= rcar_dmac_chan_terminate_all;
	engine->device_tx_status		= rcar_dmac_tx_status;
	engine->device_tx_status		= rcar_dmac_tx_status;
	engine->device_issue_pending		= rcar_dmac_issue_pending;
	engine->device_issue_pending		= rcar_dmac_issue_pending;
@@ -1885,14 +1873,6 @@ static int rcar_dmac_probe(struct platform_device *pdev)
			goto error;
			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. */
	/* Register the DMAC as a DMA provider for DT. */
	ret = of_dma_controller_register(pdev->dev.of_node, rcar_dmac_of_xlate,
	ret = of_dma_controller_register(pdev->dev.of_node, rcar_dmac_of_xlate,
					 NULL);
					 NULL);
@@ -1932,7 +1912,7 @@ static void rcar_dmac_shutdown(struct platform_device *pdev)
{
{
	struct rcar_dmac *dmac = platform_get_drvdata(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[] = {
static const struct of_device_id rcar_dmac_of_ids[] = {