qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

bcm2835-dma-test.c (3803B)


      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 Trasfer 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 }