11
#include <kernel/irq.h>
12
#include <embox/unit.h>
13
#include <framework/mod/options.h>
14
#include <module/embox/mem/bitmask.h>
18
#include <drivers/dma/dma.h>
19
#include <drivers/dma/pl330_dma.h>
20
#include <drivers/mailbox/bcm2835_mailbox_property.h>
22
#define DMA_0_BASE OPTION_GET(NUMBER, dma0_base)
23
#define DMA_F_BASE OPTION_GET(NUMBER, dmaF_base)
25
#define DMA330_IRQ OPTION_GET(NUMBER,dma_interrupt_irq)
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)
31
#define REGS_DMA_STATUS ((volatile uint32_t *)( DMA_0_BASE + 0x0fe0))
32
#define REGS_DMA_ENABLE ((volatile uint32_t *)( DMA_0_BASE + 0x0ff0))
34
static volatile struct dma_ctrl_blk shared_conbk;
38
static uint32_t pl330_vc_malloc(size_t bytes, uint32_t align, uint32_t flags) {
39
bcm2835_mailbox_property_t *resp;
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;
54
static uint32_t pl330_vc_mem_lock(uint32_t handle) {
55
bcm2835_mailbox_property_t *resp;
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 );
62
return resp->data.value_32;
68
static int pl330_vc_mem_unlock(uint32_t handle) {
69
bcm2835_mailbox_property_t *resp;
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 );
76
return resp->data.value_32;
81
static int pl330_vc_mem_free(uint32_t handle) {
82
bcm2835_mailbox_property_t *resp;
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 );
89
return resp->data.value_32;
96
static uint8_t get_irq_from_channel(uint8_t ch) {
97
uint8_t irq = ch + 16;
99
if(ch > 0x0A) irq = 27;
105
struct dma_mem_handle *pl330_dma_malloc(size_t size)
108
size = ((size + PAGE_SIZE() - 1) / PAGE_SIZE()) * PAGE_SIZE();
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);
116
assert(mem->bus_addr != 0);
122
void pl330_dma_free(struct dma_mem_handle *mem)
124
if (mem->physical_addr == NULL)
127
pl330_vc_mem_unlock(mem->mb_handle);
128
pl330_vc_mem_free(mem->mb_handle);
129
mem->physical_addr = NULL;
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);
139
if ( irqhandler == NULL && irq_nr_valid(irq) == 0 ) {
140
res = irq_detach(irq, REGS_DMA(dma_chan));
141
dev->ti &= ~DMA_TI_INTEN;
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 ) ) ;
149
if ( irqhandler != NULL ) {
150
res = irq_attach(get_irq_from_channel(dma_chan), irqhandler, 0x00, dev, "DMA IRQ");
159
int pl330_dma_transfer_conbk(int dma_chan, volatile struct dma_ctrl_blk *conbk) {
160
assert(dma_chan <= DMA_CHANNELS);
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;
164
REGS_DMA(dma_chan)->debug = DMA_DEBUG_READ_ERROR
165
| DMA_DEBUG_FIFO_ERROR
166
| DMA_DEBUG_READ_LAST_NOT_SET_ERROR;
167
REGS_DMA(dma_chan)->cs |= DMA_CS_ACTIVE;
175
int pl330_dma_transfer(int dma_chan, uint32_t dst, uint32_t src, int words) {
176
assert(dma_chan <= DMA_CHANNELS);
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;
187
return pl330_dma_transfer_conbk(dma_chan, &shared_conbk);
190
int pl330_dma_in_progress(int dma_chan, uint32_t *error_flags) {
191
assert(dma_chan <= DMA_CHANNELS);
193
*error_flags = REGS_DMA(dma_chan)->debug;
195
return (REGS_DMA(dma_chan)->cs & DMA_CS_ACTIVE);
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};
202
bcm2835_property_value32(queries, answers);
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;
218
EMBOX_UNIT_INIT(pl330_dma_init);