xref: /openbmc/qemu/tests/qtest/bcm2835-dma-test.c (revision c5ea91da443b458352c1b629b490ee6631775cb4)
1004c8a8bSAndrey Makarov /*
2004c8a8bSAndrey Makarov  * QTest testcase for BCM283x DMA engine (on Raspberry Pi 3)
3004c8a8bSAndrey Makarov  * and its interrupts coming to Interrupt Controller.
4004c8a8bSAndrey Makarov  *
5004c8a8bSAndrey Makarov  * Copyright (c) 2022 Auriga LLC
6004c8a8bSAndrey Makarov  *
7004c8a8bSAndrey Makarov  * SPDX-License-Identifier: GPL-2.0-or-later
8004c8a8bSAndrey Makarov  */
9004c8a8bSAndrey Makarov 
10004c8a8bSAndrey Makarov #include "qemu/osdep.h"
11004c8a8bSAndrey Makarov #include "libqtest-single.h"
12004c8a8bSAndrey Makarov 
13004c8a8bSAndrey Makarov /* Offsets in raspi3b platform: */
14004c8a8bSAndrey Makarov #define RASPI3_DMA_BASE 0x3f007000
15004c8a8bSAndrey Makarov #define RASPI3_IC_BASE  0x3f00b200
16004c8a8bSAndrey Makarov 
17004c8a8bSAndrey Makarov /* Used register/fields definitions */
18004c8a8bSAndrey Makarov 
19004c8a8bSAndrey Makarov /* DMA engine registers: */
20004c8a8bSAndrey Makarov #define BCM2708_DMA_CS         0
21004c8a8bSAndrey Makarov #define BCM2708_DMA_ACTIVE     (1 << 0)
22004c8a8bSAndrey Makarov #define BCM2708_DMA_INT        (1 << 2)
23004c8a8bSAndrey Makarov 
24004c8a8bSAndrey Makarov #define BCM2708_DMA_ADDR       0x04
25004c8a8bSAndrey Makarov 
26004c8a8bSAndrey Makarov #define BCM2708_DMA_INT_STATUS 0xfe0
27004c8a8bSAndrey Makarov 
28*96420a30SMichael Tokarev /* DMA Transfer Info fields: */
29004c8a8bSAndrey Makarov #define BCM2708_DMA_INT_EN     (1 << 0)
30004c8a8bSAndrey Makarov #define BCM2708_DMA_D_INC      (1 << 4)
31004c8a8bSAndrey Makarov #define BCM2708_DMA_S_INC      (1 << 8)
32004c8a8bSAndrey Makarov 
33004c8a8bSAndrey Makarov /* Interrupt controller registers: */
34004c8a8bSAndrey Makarov #define IRQ_PENDING_BASIC      0x00
35004c8a8bSAndrey Makarov #define IRQ_GPU_PENDING1_AGGR  (1 << 8)
36004c8a8bSAndrey Makarov #define IRQ_PENDING_1          0x04
37004c8a8bSAndrey Makarov #define IRQ_ENABLE_1           0x10
38004c8a8bSAndrey Makarov 
39004c8a8bSAndrey Makarov /* Data for the test: */
40004c8a8bSAndrey Makarov #define SCB_ADDR   256
41004c8a8bSAndrey Makarov #define S_ADDR     32
42004c8a8bSAndrey Makarov #define D_ADDR     64
43004c8a8bSAndrey Makarov #define TXFR_LEN   32
44004c8a8bSAndrey Makarov const uint32_t check_data = 0x12345678;
45004c8a8bSAndrey Makarov 
bcm2835_dma_test_interrupt(int dma_c,int irq_line)46004c8a8bSAndrey Makarov static void bcm2835_dma_test_interrupt(int dma_c, int irq_line)
47004c8a8bSAndrey Makarov {
48004c8a8bSAndrey Makarov     uint64_t dma_base = RASPI3_DMA_BASE + dma_c * 0x100;
49004c8a8bSAndrey Makarov     int gpu_irq_line = 16 + irq_line;
50004c8a8bSAndrey Makarov 
51004c8a8bSAndrey Makarov     /* Check that interrupts are silent by default: */
52004c8a8bSAndrey Makarov     writel(RASPI3_IC_BASE + IRQ_ENABLE_1, 1 << gpu_irq_line);
53004c8a8bSAndrey Makarov     int isr = readl(dma_base + BCM2708_DMA_INT_STATUS);
54004c8a8bSAndrey Makarov     g_assert_cmpint(isr, ==, 0);
55004c8a8bSAndrey Makarov     uint32_t reg0 = readl(dma_base + BCM2708_DMA_CS);
56004c8a8bSAndrey Makarov     g_assert_cmpint(reg0, ==, 0);
57004c8a8bSAndrey Makarov     uint32_t ic_pending = readl(RASPI3_IC_BASE + IRQ_PENDING_BASIC);
58004c8a8bSAndrey Makarov     g_assert_cmpint(ic_pending, ==, 0);
59004c8a8bSAndrey Makarov     uint32_t gpu_pending1 = readl(RASPI3_IC_BASE + IRQ_PENDING_1);
60004c8a8bSAndrey Makarov     g_assert_cmpint(gpu_pending1, ==, 0);
61004c8a8bSAndrey Makarov 
62004c8a8bSAndrey Makarov     /* Prepare Control Block: */
63004c8a8bSAndrey Makarov     writel(SCB_ADDR + 0, BCM2708_DMA_S_INC | BCM2708_DMA_D_INC |
64004c8a8bSAndrey Makarov                          BCM2708_DMA_INT_EN); /* transfer info */
65004c8a8bSAndrey Makarov     writel(SCB_ADDR + 4, S_ADDR);             /* source address */
66004c8a8bSAndrey Makarov     writel(SCB_ADDR + 8, D_ADDR);             /* destination address */
67004c8a8bSAndrey Makarov     writel(SCB_ADDR + 12, TXFR_LEN);          /* transfer length */
68004c8a8bSAndrey Makarov     writel(dma_base + BCM2708_DMA_ADDR, SCB_ADDR);
69004c8a8bSAndrey Makarov 
70004c8a8bSAndrey Makarov     writel(S_ADDR, check_data);
71004c8a8bSAndrey Makarov     for (int word = S_ADDR + 4; word < S_ADDR + TXFR_LEN; word += 4) {
72004c8a8bSAndrey Makarov         writel(word, ~check_data);
73004c8a8bSAndrey Makarov     }
74004c8a8bSAndrey Makarov     /* Perform the transfer: */
75004c8a8bSAndrey Makarov     writel(dma_base + BCM2708_DMA_CS, BCM2708_DMA_ACTIVE);
76004c8a8bSAndrey Makarov 
77004c8a8bSAndrey Makarov     /* Check that destination == source: */
78004c8a8bSAndrey Makarov     uint32_t data = readl(D_ADDR);
79004c8a8bSAndrey Makarov     g_assert_cmpint(data, ==, check_data);
80004c8a8bSAndrey Makarov     for (int word = D_ADDR + 4; word < D_ADDR + TXFR_LEN; word += 4) {
81004c8a8bSAndrey Makarov         data = readl(word);
82004c8a8bSAndrey Makarov         g_assert_cmpint(data, ==, ~check_data);
83004c8a8bSAndrey Makarov     }
84004c8a8bSAndrey Makarov 
85004c8a8bSAndrey Makarov     /* Check that interrupt status is set both in DMA and IC controllers: */
86004c8a8bSAndrey Makarov     isr = readl(RASPI3_DMA_BASE + BCM2708_DMA_INT_STATUS);
87004c8a8bSAndrey Makarov     g_assert_cmpint(isr, ==, 1 << dma_c);
88004c8a8bSAndrey Makarov 
89004c8a8bSAndrey Makarov     ic_pending = readl(RASPI3_IC_BASE + IRQ_PENDING_BASIC);
90004c8a8bSAndrey Makarov     g_assert_cmpint(ic_pending, ==, IRQ_GPU_PENDING1_AGGR);
91004c8a8bSAndrey Makarov 
92004c8a8bSAndrey Makarov     gpu_pending1 = readl(RASPI3_IC_BASE + IRQ_PENDING_1);
93004c8a8bSAndrey Makarov     g_assert_cmpint(gpu_pending1, ==, 1 << gpu_irq_line);
94004c8a8bSAndrey Makarov 
95004c8a8bSAndrey Makarov     /* Clean up, clear interrupt: */
96004c8a8bSAndrey Makarov     writel(dma_base + BCM2708_DMA_CS, BCM2708_DMA_INT);
97004c8a8bSAndrey Makarov }
98004c8a8bSAndrey Makarov 
bcm2835_dma_test_interrupts(void)99004c8a8bSAndrey Makarov static void bcm2835_dma_test_interrupts(void)
100004c8a8bSAndrey Makarov {
101004c8a8bSAndrey Makarov     /* DMA engines 0--10 have separate IRQ lines, 11--14 - only one: */
102004c8a8bSAndrey Makarov     bcm2835_dma_test_interrupt(0,  0);
103004c8a8bSAndrey Makarov     bcm2835_dma_test_interrupt(10, 10);
104004c8a8bSAndrey Makarov     bcm2835_dma_test_interrupt(11, 11);
105004c8a8bSAndrey Makarov     bcm2835_dma_test_interrupt(14, 11);
106004c8a8bSAndrey Makarov }
107004c8a8bSAndrey Makarov 
main(int argc,char ** argv)108004c8a8bSAndrey Makarov int main(int argc, char **argv)
109004c8a8bSAndrey Makarov {
110004c8a8bSAndrey Makarov     int ret;
111004c8a8bSAndrey Makarov     g_test_init(&argc, &argv, NULL);
112004c8a8bSAndrey Makarov     qtest_add_func("/bcm2835/dma/test_interrupts",
113004c8a8bSAndrey Makarov                    bcm2835_dma_test_interrupts);
114004c8a8bSAndrey Makarov     qtest_start("-machine raspi3b");
115004c8a8bSAndrey Makarov     ret = g_test_run();
116004c8a8bSAndrey Makarov     qtest_end();
117004c8a8bSAndrey Makarov     return ret;
118004c8a8bSAndrey Makarov }
119