summaryrefslogtreecommitdiff
path: root/bsp/raspberry-pi/raspi4-32/driver/drv_dma.c
blob: 9dbfee14d68a2b4fa6706aaf1d526231cbbc40a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author         Notes
 * 2020-12-02     bigmagic       first version
 */
#include "drv_dma.h"
#include "raspi4.h"
#include <rtthread.h>

volatile unsigned int __attribute__((aligned(256))) dma_disc[32];
//https://www.raspberrypi.org/forums/viewtopic.php?f=72&t=10276
static struct rt_semaphore dma_sem;

//DMA 0 1 2 3 4 5 6
typedef struct _dma_ctrl_block
{
    unsigned int TI;                   // Transfer information
    unsigned int SOURCE_AD;            // source address
    unsigned int DEST_AD;              // destination address
    unsigned int TXFR_LEN;             // transfer length
    unsigned int STRIDE;               // 2D mode stride
    struct _dma_ctrl_block *NEXTCONBK; // Next control block address
    unsigned int DEBUG;
    unsigned int reserved1;

} dma_ctrl_block_t;

//DMA 7 8 9 10
typedef struct _dma_lite_ctrl_block
{
    unsigned int TI;                        // Transfer information
    unsigned int SOURCE_AD;                 // source address
    unsigned int DEST_AD;                   // destination address
    unsigned int TXFR_LEN;                  // transfer length
    struct _dma_lite_ctrl_block *NEXTCONBK; // Next control block address
    unsigned int DEBUG;
    unsigned int reserved1;
    unsigned int reserved2;

} dma_lite_ctrl_block_t;

//DMA 11 12 13 14 15
typedef struct _dma4_ctrl_block
{
    unsigned int TI;                    // Transfer information
    unsigned int SOURCE_AD0;            // source address0
    unsigned int SOURCE_AD1;            // source address1
    unsigned int DEST_AD0;              // destination address0
    unsigned int DEST_AD1;              // destination address1
    unsigned int TXFR_LEN;              // transfer length
    unsigned int STRIDE;                // 2D mode stride
    struct _dma4_ctrl_block *NEXTCONBK; // Next control block address
} dma4_ctrl_block_t;

static dma_lite_ctrl_block_t *ctr_blocks;

static void dma_irq(int irq, void *param)
{
    if (DMA_INT_STATUS_REG & DMA_INT7)
    {
        DMA_CS(7) = DMA_CS_INT;
        rt_sem_release(&dma_sem);
    }
}

//dma 7 8 9 10:XLENGTH
rt_err_t dma_memcpy(void *src, void *dst, unsigned int size, unsigned int dch, unsigned int timeout)
{
    rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, dst, size);

    /* Stop DMA, if it was already started */
    DMA_CS(dch) = DMA_CS_RESET;

    /* Clear DMA status flags */
    DMA_CS(dch) = DMA_CS_INT | DMA_CS_END; /* Interrupted flag & Transmission ended flag*/
    //cb info
    ctr_blocks->TI = DMA_TI_SRC_INC | DMA_TI_DEST_INC | DMA_TI_INTEN;
    ctr_blocks->SOURCE_AD = (unsigned int)src;
    ctr_blocks->DEST_AD = (unsigned int)dst;
    ctr_blocks->TXFR_LEN = size;
    ctr_blocks->NEXTCONBK = 0;
    ctr_blocks->reserved1 = 0;
    ctr_blocks->reserved2 = 0;

    rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, ctr_blocks, sizeof(dma_lite_ctrl_block_t) * 8);

    DMA_CONBLK_AD(dch) = (rt_uint32_t)ctr_blocks;
    DMA_CS(dch) = DMA_CS_INT | DMA_CS_END | DMA_CS_ACTIVE;

    if(rt_sem_take(&dma_sem, timeout) != RT_EOK)
    {
        rt_kprintf("dma transfer timeout!\n");
        return -RT_ERROR;
    }

    return RT_EOK;
}

void dma_init(unsigned char dch)
{
    rt_sem_init(&dma_sem, "dma_sem", 0, RT_IPC_FLAG_FIFO);

    ctr_blocks = (dma_lite_ctrl_block_t *)&dma_disc[0]; //rt_malloc(sizeof(DMA_Lite_Control_Block));
    //Make sure DMA channel is enabled by
    //writing the corresponding bit in DMA_ENABLE in the DMA register to 1
    DMA_ENABLE_REG = (1 << dch);

    rt_hw_interrupt_install(IRQ_DMA7_DMA8, dma_irq, RT_NULL, "dma_irq");
    rt_hw_interrupt_umask(IRQ_DMA7_DMA8);
}