1 /* 2 * QTest testcase for BCM283x DMA engine (on Raspberry Pi 3) 3 * and its interrupts coming to Interrupt Controller. 4 * 5 * Copyright (c) 2022 Auriga LLC 6 * 7 * SPDX-License-Identifier: GPL-2.0-or-later 8 */ 9 10 #include "qemu/osdep.h" 11 #include "libqtest-single.h" 12 13 /* Offsets in raspi3b platform: */ 14 #define RASPI3_DMA_BASE 0x3f007000 15 #define RASPI3_IC_BASE 0x3f00b200 16 17 /* Used register/fields definitions */ 18 19 /* DMA engine registers: */ 20 #define BCM2708_DMA_CS 0 21 #define BCM2708_DMA_ACTIVE (1 << 0) 22 #define BCM2708_DMA_INT (1 << 2) 23 24 #define BCM2708_DMA_ADDR 0x04 25 26 #define BCM2708_DMA_INT_STATUS 0xfe0 27 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) 32 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 38 39 /* Data for the test: */ 40 #define SCB_ADDR 256 41 #define S_ADDR 32 42 #define D_ADDR 64 43 #define TXFR_LEN 32 44 const uint32_t check_data = 0x12345678; 45 46 static void bcm2835_dma_test_interrupt(int dma_c, int irq_line) 47 { 48 uint64_t dma_base = RASPI3_DMA_BASE + dma_c * 0x100; 49 int gpu_irq_line = 16 + irq_line; 50 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); 61 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); 69 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); 73 } 74 /* Perform the transfer: */ 75 writel(dma_base + BCM2708_DMA_CS, BCM2708_DMA_ACTIVE); 76 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) { 81 data = readl(word); 82 g_assert_cmpint(data, ==, ~check_data); 83 } 84 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); 88 89 ic_pending = readl(RASPI3_IC_BASE + IRQ_PENDING_BASIC); 90 g_assert_cmpint(ic_pending, ==, IRQ_GPU_PENDING1_AGGR); 91 92 gpu_pending1 = readl(RASPI3_IC_BASE + IRQ_PENDING_1); 93 g_assert_cmpint(gpu_pending1, ==, 1 << gpu_irq_line); 94 95 /* Clean up, clear interrupt: */ 96 writel(dma_base + BCM2708_DMA_CS, BCM2708_DMA_INT); 97 } 98 99 static void bcm2835_dma_test_interrupts(void) 100 { 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); 106 } 107 108 int main(int argc, char **argv) 109 { 110 int ret; 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"); 115 ret = g_test_run(); 116 qtest_end(); 117 return ret; 118 } 119