forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'topic/brcm' into for-linus
- Loading branch information
Showing
1 changed file
with
31 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,9 +2,6 @@ | |
/* | ||
* BCM2835 DMA engine support | ||
* | ||
* This driver only supports cyclic DMA transfers | ||
* as needed for the I2S module. | ||
* | ||
* Author: Florian Meier <[email protected]> | ||
* Copyright 2013 | ||
* | ||
|
@@ -42,7 +39,6 @@ | |
|
||
struct bcm2835_dmadev { | ||
struct dma_device ddev; | ||
spinlock_t lock; | ||
void __iomem *base; | ||
struct device_dma_parameters dma_parms; | ||
}; | ||
|
@@ -64,7 +60,6 @@ struct bcm2835_cb_entry { | |
|
||
struct bcm2835_chan { | ||
struct virt_dma_chan vc; | ||
struct list_head node; | ||
|
||
struct dma_slave_config cfg; | ||
unsigned int dreq; | ||
|
@@ -405,39 +400,32 @@ static void bcm2835_dma_fill_cb_chain_with_sg( | |
} | ||
} | ||
|
||
static int bcm2835_dma_abort(void __iomem *chan_base) | ||
static void bcm2835_dma_abort(struct bcm2835_chan *c) | ||
{ | ||
unsigned long cs; | ||
void __iomem *chan_base = c->chan_base; | ||
long int timeout = 10000; | ||
|
||
cs = readl(chan_base + BCM2835_DMA_CS); | ||
if (!(cs & BCM2835_DMA_ACTIVE)) | ||
return 0; | ||
/* | ||
* A zero control block address means the channel is idle. | ||
* (The ACTIVE flag in the CS register is not a reliable indicator.) | ||
*/ | ||
if (!readl(chan_base + BCM2835_DMA_ADDR)) | ||
return; | ||
|
||
/* Write 0 to the active bit - Pause the DMA */ | ||
writel(0, chan_base + BCM2835_DMA_CS); | ||
|
||
/* Wait for any current AXI transfer to complete */ | ||
while ((cs & BCM2835_DMA_ISPAUSED) && --timeout) { | ||
while ((readl(chan_base + BCM2835_DMA_CS) & | ||
BCM2835_DMA_WAITING_FOR_WRITES) && --timeout) | ||
cpu_relax(); | ||
cs = readl(chan_base + BCM2835_DMA_CS); | ||
} | ||
|
||
/* We'll un-pause when we set of our next DMA */ | ||
/* Peripheral might be stuck and fail to signal AXI write responses */ | ||
if (!timeout) | ||
return -ETIMEDOUT; | ||
|
||
if (!(cs & BCM2835_DMA_ACTIVE)) | ||
return 0; | ||
dev_err(c->vc.chan.device->dev, | ||
"failed to complete outstanding writes\n"); | ||
|
||
/* Terminate the control block chain */ | ||
writel(0, chan_base + BCM2835_DMA_NEXTCB); | ||
|
||
/* Abort the whole DMA */ | ||
writel(BCM2835_DMA_ABORT | BCM2835_DMA_ACTIVE, | ||
chan_base + BCM2835_DMA_CS); | ||
|
||
return 0; | ||
writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS); | ||
} | ||
|
||
static void bcm2835_dma_start_desc(struct bcm2835_chan *c) | ||
|
@@ -475,20 +463,23 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data) | |
|
||
spin_lock_irqsave(&c->vc.lock, flags); | ||
|
||
/* Acknowledge interrupt */ | ||
writel(BCM2835_DMA_INT, c->chan_base + BCM2835_DMA_CS); | ||
/* | ||
* Clear the INT flag to receive further interrupts. Keep the channel | ||
* active in case the descriptor is cyclic or in case the client has | ||
* already terminated the descriptor and issued a new one. (May happen | ||
* if this IRQ handler is threaded.) If the channel is finished, it | ||
* will remain idle despite the ACTIVE flag being set. | ||
*/ | ||
writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE, | ||
c->chan_base + BCM2835_DMA_CS); | ||
|
||
d = c->desc; | ||
|
||
if (d) { | ||
if (d->cyclic) { | ||
/* call the cyclic callback */ | ||
vchan_cyclic_callback(&d->vd); | ||
|
||
/* Keep the DMA engine running */ | ||
writel(BCM2835_DMA_ACTIVE, | ||
c->chan_base + BCM2835_DMA_CS); | ||
} else { | ||
} else if (!readl(c->chan_base + BCM2835_DMA_ADDR)) { | ||
vchan_cookie_complete(&c->desc->vd); | ||
bcm2835_dma_start_desc(c); | ||
} | ||
|
@@ -506,8 +497,12 @@ static int bcm2835_dma_alloc_chan_resources(struct dma_chan *chan) | |
|
||
dev_dbg(dev, "Allocating DMA channel %d\n", c->ch); | ||
|
||
/* | ||
* Control blocks are 256 bit in length and must start at a 256 bit | ||
* (32 byte) aligned address (BCM2835 ARM Peripherals, sec. 4.2.1.1). | ||
*/ | ||
c->cb_pool = dma_pool_create(dev_name(dev), dev, | ||
sizeof(struct bcm2835_dma_cb), 0, 0); | ||
sizeof(struct bcm2835_dma_cb), 32, 0); | ||
if (!c->cb_pool) { | ||
dev_err(dev, "unable to allocate descriptor pool\n"); | ||
return -ENOMEM; | ||
|
@@ -776,39 +771,16 @@ static int bcm2835_dma_slave_config(struct dma_chan *chan, | |
static int bcm2835_dma_terminate_all(struct dma_chan *chan) | ||
{ | ||
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan); | ||
struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device); | ||
unsigned long flags; | ||
int timeout = 10000; | ||
LIST_HEAD(head); | ||
|
||
spin_lock_irqsave(&c->vc.lock, flags); | ||
|
||
/* Prevent this channel being scheduled */ | ||
spin_lock(&d->lock); | ||
list_del_init(&c->node); | ||
spin_unlock(&d->lock); | ||
|
||
/* | ||
* Stop DMA activity: we assume the callback will not be called | ||
* after bcm_dma_abort() returns (even if it does, it will see | ||
* c->desc is NULL and exit.) | ||
*/ | ||
/* stop DMA activity */ | ||
if (c->desc) { | ||
vchan_terminate_vdesc(&c->desc->vd); | ||
c->desc = NULL; | ||
bcm2835_dma_abort(c->chan_base); | ||
|
||
/* Wait for stopping */ | ||
while (--timeout) { | ||
if (!(readl(c->chan_base + BCM2835_DMA_CS) & | ||
BCM2835_DMA_ACTIVE)) | ||
break; | ||
|
||
cpu_relax(); | ||
} | ||
|
||
if (!timeout) | ||
dev_err(d->ddev.dev, "DMA transfer could not be terminated\n"); | ||
bcm2835_dma_abort(c); | ||
} | ||
|
||
vchan_get_all_descriptors(&c->vc, &head); | ||
|
@@ -836,7 +808,6 @@ static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, | |
|
||
c->vc.desc_free = bcm2835_dma_desc_free; | ||
vchan_init(&c->vc, &d->ddev); | ||
INIT_LIST_HEAD(&c->node); | ||
|
||
c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id); | ||
c->ch = chan_id; | ||
|
@@ -939,7 +910,6 @@ static int bcm2835_dma_probe(struct platform_device *pdev) | |
od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; | ||
od->ddev.dev = &pdev->dev; | ||
INIT_LIST_HEAD(&od->ddev.channels); | ||
spin_lock_init(&od->lock); | ||
|
||
platform_set_drvdata(pdev, od); | ||
|
||
|