embox

Форк
0
/
pl330_dma.c 
218 строк · 6.5 Кб
1
/**
2
 * @file
3
 * @brief
4
 *
5
 * @date    07.06.2021
6
 * @author  kpishere
7
 */
8

9
#include <assert.h>
10
#include <util/log.h>
11
#include <kernel/irq.h>
12
#include <embox/unit.h>
13
#include <framework/mod/options.h>
14
#include <module/embox/mem/bitmask.h>
15

16
#include <asm/cp15.h>
17

18
#include <drivers/dma/dma.h>
19
#include <drivers/dma/pl330_dma.h>
20
#include <drivers/mailbox/bcm2835_mailbox_property.h>
21

22
#define DMA_0_BASE OPTION_GET(NUMBER, dma0_base)
23
#define DMA_F_BASE OPTION_GET(NUMBER, dmaF_base)
24

25
#define DMA330_IRQ OPTION_GET(NUMBER,dma_interrupt_irq)
26

27
#define REGS_DMA(c) (( Dma *)( DMA_0_BASE + 0x100 * (c) ) )
28
#define REGS_DMA_F  (( Dma *)( DMA_F_BASE ))
29
#define REGS_DMA_CHAN(r) ( (((uint32_t)(r))-DMA_0_BASE) / 0x100)
30

31
#define REGS_DMA_STATUS ((volatile uint32_t *)( DMA_0_BASE + 0x0fe0))
32
#define REGS_DMA_ENABLE ((volatile uint32_t *)( DMA_0_BASE + 0x0ff0))
33

34
static volatile struct dma_ctrl_blk shared_conbk;
35

36
// Returns a handle to the allocated memory
37
//
38
static uint32_t pl330_vc_malloc(size_t bytes, uint32_t align, uint32_t flags) {
39
    bcm2835_mailbox_property_t *resp;
40
    
41
    bcm2835_property_init();
42
    bcm2835_property_add_tag( TAG_ALLOCATE_MEMORY,  bytes, align, flags );
43
    bcm2835_property_process();
44
    resp = bcm2835_property_get( TAG_ALLOCATE_MEMORY );
45
    uint32_t handle = (uint32_t)resp->data.value_32;
46

47
    return handle;
48
}
49

50
// Lock memory to physical address mapping, returns a bus address 
51
// accessable only by GPU and DMA (but corresponding physical address
52
// can now be accessed by ARM CPU)
53
//
54
static uint32_t pl330_vc_mem_lock(uint32_t handle) {
55
    bcm2835_mailbox_property_t *resp;
56

57
    bcm2835_property_init();
58
    bcm2835_property_add_tag( TAG_LOCK_MEMORY,  handle );
59
    bcm2835_property_process();
60
    resp = bcm2835_property_get( TAG_LOCK_MEMORY );
61

62
    return resp->data.value_32;
63
}
64

65
// Unlock but don't de-allocate memory
66
// (can't be accessed by ARM CPU but still can by GPU and DMA)
67
//
68
static int pl330_vc_mem_unlock(uint32_t handle) {
69
    bcm2835_mailbox_property_t *resp;
70

71
    bcm2835_property_init();
72
    bcm2835_property_add_tag( TAG_UNLOCK_MEMORY,  handle );
73
    bcm2835_property_process();
74
    resp = bcm2835_property_get( TAG_UNLOCK_MEMORY );
75

76
    return resp->data.value_32;
77
}
78

79
// Release the allocated memory
80
//
81
static int pl330_vc_mem_free(uint32_t handle) {
82
    bcm2835_mailbox_property_t *resp;
83

84
    bcm2835_property_init();
85
    bcm2835_property_add_tag( TAG_RELEASE_MEMORY,  handle );
86
    bcm2835_property_process();
87
    resp = bcm2835_property_get( TAG_RELEASE_MEMORY );
88

89
    return resp->data.value_32;
90
}
91

92
/* IRQ 16 / DMA 0, 17/1, 18/2, 19/3, 20/4, 21/5
93
 *   22/6, 23/7, 24/8, 25/9, 26/A
94
 * - IRQ number 27 is shared by channels B thru E 
95
 */
96
static uint8_t get_irq_from_channel(uint8_t ch) {
97
    uint8_t irq = ch + 16;
98

99
    if(ch > 0x0A) irq = 27;
100
    return irq;
101
}
102

103
// Allocate and lock memory for use by DMA
104
//
105
struct dma_mem_handle *pl330_dma_malloc(size_t size)
106
{
107
    // Make `size` a multiple of PAGE_SIZE
108
    size = ((size + PAGE_SIZE() - 1) / PAGE_SIZE()) * PAGE_SIZE();
109

110
    Dma_mem_handle *mem = (struct dma_mem_handle  *)malloc(sizeof(struct dma_mem_handle ));
111
    mem->mb_handle = (uint32_t)pl330_vc_malloc(size, PAGE_SIZE(), BCM2835_MEM_FLAG_DIRECT);
112
    mem->bus_addr = pl330_vc_mem_lock(mem->mb_handle);
113
    mem->physical_addr = DMA_BUS_TO_PHYS(mem->bus_addr);
114
    mem->size = size;
115

116
    assert(mem->bus_addr != 0);
117
    return mem;
118
}
119

120
// Unlock and deallocate memory
121
//
122
void pl330_dma_free(struct dma_mem_handle  *mem)
123
{
124
    if (mem->physical_addr == NULL)
125
        return;
126

127
    pl330_vc_mem_unlock(mem->mb_handle);
128
    pl330_vc_mem_free(mem->mb_handle);
129
    mem->physical_addr = NULL;
130
    free(mem);
131
}
132

133
// Enable and reset DMA
134
int pl330_dma_config(int dma_chan, irq_handler_t irqhandler, uint32_t cs_panic_opts) {
135
    assert(dma_chan <= DMA_CHANNELS);
136
    int res = 0, irq = get_irq_from_channel(dma_chan);
137
    Dma *dev = REGS_DMA(dma_chan);
138

139
    if ( irqhandler == NULL && irq_nr_valid(irq) == 0 ) {
140
        res = irq_detach(irq, REGS_DMA(dma_chan));
141
        dev->ti &= ~DMA_TI_INTEN;
142
    }
143

144
    *(REGS_DMA_ENABLE) |= ( 1 << dma_chan );
145
    dev->cs = DMA_CS_RESET | (cs_panic_opts & ( DMA_CS_DISDEBUG 
146
        | DMA_CS_WAIT_FOR_OUTSTANDING_WRITES | DMA_CS_PANIC_PRIORITY(0xff) 
147
        | DMA_CS_PRIORITY(0xff) | DMA_CS_INT | DMA_CS_END | DMA_CS_ACTIVE ) ) ;
148

149
    if ( irqhandler != NULL ) {
150
        res = irq_attach(get_irq_from_channel(dma_chan), irqhandler, 0x00, dev, "DMA IRQ");
151
    }
152

153
    return res;
154
}
155

156
// Start DMA
157
// dma_chan - integer 0-15
158
// conbk - pointer to data type in physical memory
159
int pl330_dma_transfer_conbk(int dma_chan, volatile struct dma_ctrl_blk *conbk) {
160
    assert(dma_chan <= DMA_CHANNELS);
161

162
    REGS_DMA(dma_chan)->conblk_ad = (uint32_t)DMA_PHYS_TO_BUS(conbk);  
163
    REGS_DMA(dma_chan)->cs = DMA_CS_END | DMA_CS_INT; // Clear 'end' flag and interrupt
164
    REGS_DMA(dma_chan)->debug = DMA_DEBUG_READ_ERROR 
165
        | DMA_DEBUG_FIFO_ERROR 
166
        | DMA_DEBUG_READ_LAST_NOT_SET_ERROR; // clear error bits
167
    REGS_DMA(dma_chan)->cs |= DMA_CS_ACTIVE; // Start DMA
168
    return 0;
169
}
170

171
// Start DMA - basic memory copy
172
// dma_chan - integer 0-15
173
// dst, src - are destination and source memory locations in bus address space
174
// words - 4-byte aligned memory length
175
int pl330_dma_transfer(int dma_chan, uint32_t dst, uint32_t src, int words) {   
176
    assert(dma_chan <= DMA_CHANNELS);
177

178
    // A standard copy block to support basic implementation
179
    shared_conbk.source_ad = (uint32_t)DMA_PHYS_TO_BUS(src);
180
    shared_conbk.dest_ad = (uint32_t)DMA_PHYS_TO_BUS(dst);
181
    shared_conbk.txfr_len = words * sizeof(uint32_t);
182
    shared_conbk.ti = DMA_TI_SRC_INC | DMA_TI_DEST_INC;
183
    shared_conbk.nextconbk = 0;
184
    shared_conbk.stride = 0;
185
    shared_conbk.debug[1] = shared_conbk.debug[0] = 0;
186

187
    return pl330_dma_transfer_conbk(dma_chan, &shared_conbk);
188
}
189

190
int pl330_dma_in_progress(int dma_chan, uint32_t *error_flags) {
191
    assert(dma_chan <= DMA_CHANNELS);
192

193
    *error_flags = REGS_DMA(dma_chan)->debug;
194

195
    return (REGS_DMA(dma_chan)->cs & DMA_CS_ACTIVE);
196
}
197

198
uint32_t pl330_dma_channels_free(void) {
199
    bcm2835_mailbox_tag_t queries[] = {TAG_GET_DMA_CHANNELS, 0x0};
200
    uint32_t answers[] = {0x0, 0x0};
201

202
    bcm2835_property_value32(queries, answers);
203

204
    return answers[0];
205
}
206

207
static int pl330_dma_init(void) {
208
    dma_dev.config_extended = pl330_dma_config;
209
    dma_dev.transfer = pl330_dma_transfer;
210
    dma_dev.transfer_conbk = pl330_dma_transfer_conbk;
211
    dma_dev.in_progress_status = pl330_dma_in_progress;
212
    dma_dev.malloc = pl330_dma_malloc;
213
    dma_dev.free = pl330_dma_free;
214
    dma_dev.channels_free = pl330_dma_channels_free;
215
    return 0;
216
}
217

218
EMBOX_UNIT_INIT(pl330_dma_init);
219

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.