637f4562dd83b7b954e38a7c8e2f5a107c78691e
[openwrt/staging/xback.git] /
1 From 132f5d41c2da9f7292f1495fd30cf04a3de8d196 Mon Sep 17 00:00:00 2001
2 From: Dom Cobley <popcornmix@gmail.com>
3 Date: Fri, 5 May 2023 11:23:50 +0100
4 Subject: [PATCH] bcm2835-dma: Need to keep PROT bits set in CS on
5 40bit controller
6
7 Resetting them to zero puts DMA channel into secure mode
8 which makes further accesses impossible
9
10 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
11 ---
12 drivers/dma/bcm2835-dma.c | 20 ++++++++++++++------
13 1 file changed, 14 insertions(+), 6 deletions(-)
14
15 --- a/drivers/dma/bcm2835-dma.c
16 +++ b/drivers/dma/bcm2835-dma.c
17 @@ -249,6 +249,9 @@ struct bcm2835_desc {
18 #define BCM2711_DMA40_DISDEBUG BIT(29)
19 #define BCM2711_DMA40_ABORT BIT(30)
20 #define BCM2711_DMA40_HALT BIT(31)
21 +// we always want to run in supervisor mode
22 +#define BCM2711_DMA40_PROT (BIT(8)|BIT(9))
23 +
24 #define BCM2711_DMA40_CS_FLAGS(x) (x & (BCM2711_DMA40_QOS(15) | \
25 BCM2711_DMA40_PANIC_QOS(15) | \
26 BCM2711_DMA40_WAIT_FOR_WRITES | \
27 @@ -682,7 +685,7 @@ static void bcm2835_dma_abort(struct bcm
28 dev_err(c->vc.chan.device->dev,
29 "failed to halt dma\n");
30
31 - writel(0, chan_base + BCM2711_DMA40_CS);
32 + writel(BCM2711_DMA40_PROT, chan_base + BCM2711_DMA40_CS);
33 writel(0, chan_base + BCM2711_DMA40_CB);
34 } else {
35 /*
36 @@ -742,7 +745,7 @@ static void bcm2835_dma_start_desc(struc
37 if (c->is_40bit_channel) {
38 writel(to_bcm2711_cbaddr(d->cb_list[0].paddr),
39 c->chan_base + BCM2711_DMA40_CB);
40 - writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_CS_FLAGS(c->dreq),
41 + writel(BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT | BCM2711_DMA40_CS_FLAGS(c->dreq),
42 c->chan_base + BCM2711_DMA40_CS);
43 } else {
44 writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
45 @@ -775,8 +778,13 @@ static irqreturn_t bcm2835_dma_callback(
46 * if this IRQ handler is threaded.) If the channel is finished, it
47 * will remain idle despite the ACTIVE flag being set.
48 */
49 - writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
50 - c->chan_base + BCM2835_DMA_CS);
51 + if (c->is_40bit_channel)
52 + writel(BCM2835_DMA_INT | BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT |
53 + BCM2711_DMA40_CS_FLAGS(c->dreq),
54 + c->chan_base + BCM2711_DMA40_CS);
55 + else
56 + writel(BCM2835_DMA_INT | BCM2835_DMA_ACTIVE | BCM2835_DMA_CS_FLAGS(c->dreq),
57 + c->chan_base + BCM2835_DMA_CS);
58
59 d = c->desc;
60
61 @@ -1230,14 +1238,14 @@ void bcm2711_dma40_memcpy(dma_addr_t dst
62 scb->next_cb = 0;
63
64 writel(to_bcm2711_cbaddr(memcpy_scb_dma), memcpy_chan + BCM2711_DMA40_CB);
65 - writel(BCM2711_DMA40_MEMCPY_FLAGS + BCM2711_DMA40_ACTIVE,
66 + writel(BCM2711_DMA40_MEMCPY_FLAGS | BCM2711_DMA40_ACTIVE | BCM2711_DMA40_PROT,
67 memcpy_chan + BCM2711_DMA40_CS);
68
69 /* Poll for completion */
70 while (!(readl(memcpy_chan + BCM2711_DMA40_CS) & BCM2711_DMA40_END))
71 cpu_relax();
72
73 - writel(BCM2711_DMA40_END, memcpy_chan + BCM2711_DMA40_CS);
74 + writel(BCM2711_DMA40_END | BCM2711_DMA40_PROT, memcpy_chan + BCM2711_DMA40_CS);
75
76 spin_unlock_irqrestore(&memcpy_lock, flags);
77 }