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