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