bcm2835-dma: Need to keep PROT bits set in CS on 40bit controller

Resetting them to zero puts DMA channel into secure mode
which makes further accesses impossible

Signed-off-by: Dom Cobley <popcornmix@gmail.com>
This commit is contained in:
Dom Cobley
2023-05-05 11:23:50 +01:00
committed by Phil Elwell
parent 4616cdd5b1
commit 654368fe84

View File

@@ -249,6 +249,9 @@ struct bcm2835_desc {
#define BCM2711_DMA40_DISDEBUG BIT(29) #define BCM2711_DMA40_DISDEBUG BIT(29)
#define BCM2711_DMA40_ABORT BIT(30) #define BCM2711_DMA40_ABORT BIT(30)
#define BCM2711_DMA40_HALT BIT(31) #define BCM2711_DMA40_HALT BIT(31)
// we always want to run in supervisor mode
#define BCM2711_DMA40_PROT (BIT(8)|BIT(9))
#define BCM2711_DMA40_CS_FLAGS(x) (x & (BCM2711_DMA40_QOS(15) | \ #define BCM2711_DMA40_CS_FLAGS(x) (x & (BCM2711_DMA40_QOS(15) | \
BCM2711_DMA40_PANIC_QOS(15) | \ BCM2711_DMA40_PANIC_QOS(15) | \
BCM2711_DMA40_WAIT_FOR_WRITES | \ BCM2711_DMA40_WAIT_FOR_WRITES | \
@@ -682,7 +685,7 @@ static void bcm2835_dma_abort(struct bcm2835_chan *c)
dev_err(c->vc.chan.device->dev, dev_err(c->vc.chan.device->dev,
"failed to halt dma\n"); "failed to halt dma\n");
writel(0, chan_base + BCM2711_DMA40_CS); writel(BCM2711_DMA40_PROT, chan_base + BCM2711_DMA40_CS);
writel(0, chan_base + BCM2711_DMA40_CB); writel(0, chan_base + BCM2711_DMA40_CB);
} else { } else {
/* /*
@@ -742,7 +745,7 @@ static void bcm2835_dma_start_desc(struct bcm2835_chan *c)
if (c->is_40bit_channel) { if (c->is_40bit_channel) {
writel(to_bcm2711_cbaddr(d->cb_list[0].paddr), writel(to_bcm2711_cbaddr(d->cb_list[0].paddr),
c->chan_base + BCM2711_DMA40_CB); c->chan_base + BCM2711_DMA40_CB);
writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_CS_FLAGS(c->dreq), writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT | BCM2711_DMA40_CS_FLAGS(c->dreq),
c->chan_base + BCM2711_DMA40_CS); c->chan_base + BCM2711_DMA40_CS);
} else { } else {
writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR); writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
@@ -775,8 +778,13 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data)
* if this IRQ handler is threaded.) If the channel is finished, it * if this IRQ handler is threaded.) If the channel is finished, it
* will remain idle despite the ACTIVE flag being set. * will remain idle despite the ACTIVE flag being set.
*/ */
writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq), if (c->is_40bit_channel)
c->chan_base + BCM2835_DMA_CS); writel(BCM2835_DMA_INT | BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT |
BCM2711_DMA40_CS_FLAGS(c->dreq),
c->chan_base + BCM2711_DMA40_CS);
else
writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
c->chan_base + BCM2835_DMA_CS);
d = c->desc; d = c->desc;
@@ -1230,14 +1238,14 @@ void bcm2711_dma40_memcpy(dma_addr_t dst, dma_addr_t src, size_t size)
scb->next_cb = 0; scb->next_cb = 0;
writel(to_bcm2711_cbaddr(memcpy_scb_dma), memcpy_chan + BCM2711_DMA40_CB); writel(to_bcm2711_cbaddr(memcpy_scb_dma), memcpy_chan + BCM2711_DMA40_CB);
writel(BCM2711_DMA40_MEMCPY_FLAGS + BCM2711_DMA40_ACTIVE, writel(BCM2711_DMA40_MEMCPY_FLAGS | BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT,
memcpy_chan + BCM2711_DMA40_CS); memcpy_chan + BCM2711_DMA40_CS);
/* Poll for completion */ /* Poll for completion */
while (!(readl(memcpy_chan + BCM2711_DMA40_CS) & BCM2711_DMA40_END)) while (!(readl(memcpy_chan + BCM2711_DMA40_CS) & BCM2711_DMA40_END))
cpu_relax(); cpu_relax();
writel(BCM2711_DMA40_END, memcpy_chan + BCM2711_DMA40_CS); writel(BCM2711_DMA40_END | BCM2711_DMA40_PROT, memcpy_chan + BCM2711_DMA40_CS);
spin_unlock_irqrestore(&memcpy_lock, flags); spin_unlock_irqrestore(&memcpy_lock, flags);
} }