2 * QTest testcase for BCM283x DMA engine (on Raspberry Pi 3)
3 * and its interrupts coming to Interrupt Controller.
5 * Copyright (c) 2022 Auriga LLC
7 * SPDX-License-Identifier: GPL-2.0-or-later
10 #include "qemu/osdep.h"
11 #include "libqtest-single.h"
13 /* Offsets in raspi3b platform: */
14 #define RASPI3_DMA_BASE 0x3f007000
15 #define RASPI3_IC_BASE 0x3f00b200
17 /* Used register/fields definitions */
19 /* DMA engine registers: */
20 #define BCM2708_DMA_CS 0
21 #define BCM2708_DMA_ACTIVE (1 << 0)
22 #define BCM2708_DMA_INT (1 << 2)
24 #define BCM2708_DMA_ADDR 0x04
26 #define BCM2708_DMA_INT_STATUS 0xfe0
28 /* DMA Transfer Info fields: */
29 #define BCM2708_DMA_INT_EN (1 << 0)
30 #define BCM2708_DMA_D_INC (1 << 4)
31 #define BCM2708_DMA_S_INC (1 << 8)
33 /* Interrupt controller registers: */
34 #define IRQ_PENDING_BASIC 0x00
35 #define IRQ_GPU_PENDING1_AGGR (1 << 8)
36 #define IRQ_PENDING_1 0x04
37 #define IRQ_ENABLE_1 0x10
39 /* Data for the test: */
44 const uint32_t check_data
= 0x12345678;
46 static void bcm2835_dma_test_interrupt(int dma_c
, int irq_line
)
48 uint64_t dma_base
= RASPI3_DMA_BASE
+ dma_c
* 0x100;
49 int gpu_irq_line
= 16 + irq_line
;
51 /* Check that interrupts are silent by default: */
52 writel(RASPI3_IC_BASE
+ IRQ_ENABLE_1
, 1 << gpu_irq_line
);
53 int isr
= readl(dma_base
+ BCM2708_DMA_INT_STATUS
);
54 g_assert_cmpint(isr
, ==, 0);
55 uint32_t reg0
= readl(dma_base
+ BCM2708_DMA_CS
);
56 g_assert_cmpint(reg0
, ==, 0);
57 uint32_t ic_pending
= readl(RASPI3_IC_BASE
+ IRQ_PENDING_BASIC
);
58 g_assert_cmpint(ic_pending
, ==, 0);
59 uint32_t gpu_pending1
= readl(RASPI3_IC_BASE
+ IRQ_PENDING_1
);
60 g_assert_cmpint(gpu_pending1
, ==, 0);
62 /* Prepare Control Block: */
63 writel(SCB_ADDR
+ 0, BCM2708_DMA_S_INC
| BCM2708_DMA_D_INC
|
64 BCM2708_DMA_INT_EN
); /* transfer info */
65 writel(SCB_ADDR
+ 4, S_ADDR
); /* source address */
66 writel(SCB_ADDR
+ 8, D_ADDR
); /* destination address */
67 writel(SCB_ADDR
+ 12, TXFR_LEN
); /* transfer length */
68 writel(dma_base
+ BCM2708_DMA_ADDR
, SCB_ADDR
);
70 writel(S_ADDR
, check_data
);
71 for (int word
= S_ADDR
+ 4; word
< S_ADDR
+ TXFR_LEN
; word
+= 4) {
72 writel(word
, ~check_data
);
74 /* Perform the transfer: */
75 writel(dma_base
+ BCM2708_DMA_CS
, BCM2708_DMA_ACTIVE
);
77 /* Check that destination == source: */
78 uint32_t data
= readl(D_ADDR
);
79 g_assert_cmpint(data
, ==, check_data
);
80 for (int word
= D_ADDR
+ 4; word
< D_ADDR
+ TXFR_LEN
; word
+= 4) {
82 g_assert_cmpint(data
, ==, ~check_data
);
85 /* Check that interrupt status is set both in DMA and IC controllers: */
86 isr
= readl(RASPI3_DMA_BASE
+ BCM2708_DMA_INT_STATUS
);
87 g_assert_cmpint(isr
, ==, 1 << dma_c
);
89 ic_pending
= readl(RASPI3_IC_BASE
+ IRQ_PENDING_BASIC
);
90 g_assert_cmpint(ic_pending
, ==, IRQ_GPU_PENDING1_AGGR
);
92 gpu_pending1
= readl(RASPI3_IC_BASE
+ IRQ_PENDING_1
);
93 g_assert_cmpint(gpu_pending1
, ==, 1 << gpu_irq_line
);
95 /* Clean up, clear interrupt: */
96 writel(dma_base
+ BCM2708_DMA_CS
, BCM2708_DMA_INT
);
99 static void bcm2835_dma_test_interrupts(void)
101 /* DMA engines 0--10 have separate IRQ lines, 11--14 - only one: */
102 bcm2835_dma_test_interrupt(0, 0);
103 bcm2835_dma_test_interrupt(10, 10);
104 bcm2835_dma_test_interrupt(11, 11);
105 bcm2835_dma_test_interrupt(14, 11);
108 int main(int argc
, char **argv
)
111 g_test_init(&argc
, &argv
, NULL
);
112 qtest_add_func("/bcm2835/dma/test_interrupts",
113 bcm2835_dma_test_interrupts
);
114 qtest_start("-machine raspi3b");