667 lines
20 KiB
C
667 lines
20 KiB
C
/* Copyright 2018 Canaan Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
#include <FreeRTOS.h>
|
|
#include <atomic.h>
|
|
#include <dmac.h>
|
|
#include <driver.h>
|
|
#include <hal.h>
|
|
#include <plic.h>
|
|
#include <semphr.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sysctl.h>
|
|
#include <task.h>
|
|
|
|
/* DMAC */
|
|
|
|
#define COMMON_ENTRY \
|
|
dmac_data* data = (dmac_data*)userdata; \
|
|
volatile struct dmac_t* dmac = (volatile struct dmac_t*)data->base_addr;
|
|
|
|
typedef struct
|
|
{
|
|
uintptr_t base_addr;
|
|
int32_t axi_master1_use;
|
|
int32_t axi_master2_use;
|
|
} dmac_data;
|
|
|
|
static void dmac_install(void* userdata)
|
|
{
|
|
COMMON_ENTRY;
|
|
|
|
uint64_t tmp;
|
|
union dmac_commonreg_intclear_u intclear;
|
|
union dmac_cfg_u dmac_cfg;
|
|
union dmac_reset_u dmac_reset;
|
|
|
|
sysctl_clock_enable(SYSCTL_CLOCK_DMA);
|
|
|
|
dmac_reset.data = readq(&dmac->reset);
|
|
dmac_reset.reset.rst = 1;
|
|
writeq(dmac_reset.data, &dmac->reset);
|
|
while (dmac_reset.reset.rst)
|
|
dmac_reset.data = readq(&dmac->reset);
|
|
|
|
intclear.data = readq(&dmac->com_intclear);
|
|
intclear.com_intclear.cear_slvif_dec_err_intstat = 1;
|
|
intclear.com_intclear.clear_slvif_wr2ro_err_intstat = 1;
|
|
intclear.com_intclear.clear_slvif_rd2wo_err_intstat = 1;
|
|
intclear.com_intclear.clear_slvif_wronhold_err_intstat = 1;
|
|
intclear.com_intclear.clear_slvif_undefinedreg_dec_err_intstat = 1;
|
|
writeq(intclear.data, &dmac->com_intclear);
|
|
|
|
dmac_cfg.data = readq(&dmac->cfg);
|
|
dmac_cfg.cfg.dmac_en = 0;
|
|
dmac_cfg.cfg.int_en = 0;
|
|
writeq(dmac_cfg.data, &dmac->cfg);
|
|
|
|
while (readq(&dmac->cfg))
|
|
;
|
|
|
|
tmp = readq(&dmac->chen);
|
|
tmp &= ~0xf;
|
|
writeq(tmp, &dmac->chen);
|
|
|
|
dmac_cfg.data = readq(&dmac->cfg);
|
|
dmac_cfg.cfg.dmac_en = 1;
|
|
dmac_cfg.cfg.int_en = 1;
|
|
writeq(dmac_cfg.data, &dmac->cfg);
|
|
}
|
|
|
|
static int dmac_open(void* userdata)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static void dmac_close(void* userdata)
|
|
{
|
|
}
|
|
|
|
static uint32_t add_lru_axi_master(dmac_data* data)
|
|
{
|
|
uint32_t axi1 = atomic_read(&data->axi_master1_use);
|
|
uint32_t axi2 = atomic_read(&data->axi_master2_use);
|
|
|
|
if (axi1 < axi2)
|
|
{
|
|
atomic_add(&data->axi_master1_use, 1);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
atomic_add(&data->axi_master2_use, 1);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static void release_axi_master(dmac_data* data, uint32_t axi)
|
|
{
|
|
if (axi == 0)
|
|
atomic_add(&data->axi_master1_use, -1);
|
|
else
|
|
atomic_add(&data->axi_master2_use, -1);
|
|
}
|
|
|
|
static dmac_data dev0_data = {DMAC_BASE_ADDR, 0, 0};
|
|
|
|
const dmac_driver_t g_dmac_driver_dmac0 = {{&dev0_data, dmac_install, dmac_open, dmac_close}};
|
|
|
|
/* DMA Channel */
|
|
|
|
#define MAX_PING_PONG_SRCS 4
|
|
#define C_COMMON_ENTRY \
|
|
dma_data* data = (dma_data*)userdata; \
|
|
dmac_data* dmacdata = data->dmac_data; \
|
|
volatile struct dmac_t* dmac = (volatile struct dmac_t*)dmacdata->base_addr; \
|
|
(void)dmac; \
|
|
volatile struct dmac_channel_t* dma = (volatile struct dmac_channel_t*)dmac->channel + data->channel; \
|
|
(void)dma;
|
|
|
|
typedef struct
|
|
{
|
|
dmac_data* dmac_data;
|
|
size_t channel;
|
|
int used;
|
|
|
|
struct
|
|
{
|
|
SemaphoreHandle_t completion_event;
|
|
uint32_t axi_master;
|
|
int is_ping_pong;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
enum dmac_transfer_flow flow_control;
|
|
size_t element_size;
|
|
size_t count;
|
|
void* alloc_mem;
|
|
volatile void* dest;
|
|
};
|
|
|
|
struct
|
|
{
|
|
const volatile void* srcs[MAX_PING_PONG_SRCS];
|
|
size_t src_num;
|
|
volatile void* dests[MAX_PING_PONG_SRCS];
|
|
size_t dest_num;
|
|
size_t next_src_id;
|
|
size_t next_dest_id;
|
|
dma_stage_completion_handler stage_completion_handler;
|
|
void* stage_completion_handler_data;
|
|
int* stop_signal;
|
|
};
|
|
};
|
|
} session;
|
|
} dma_data;
|
|
|
|
static void dma_completion_isr(void* userdata)
|
|
{
|
|
C_COMMON_ENTRY;
|
|
|
|
configASSERT(dma->intstatus & 0x2);
|
|
dma->intclear = 0xFFFFFFFF;
|
|
|
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
|
|
if (data->session.is_ping_pong)
|
|
{
|
|
if (atomic_read(data->session.stop_signal))
|
|
{
|
|
release_axi_master(dmacdata, data->session.axi_master);
|
|
if (data->session.stage_completion_handler)
|
|
data->session.stage_completion_handler(data->session.stage_completion_handler_data);
|
|
xSemaphoreGiveFromISR(data->session.completion_event, &xHigherPriorityTaskWoken);
|
|
}
|
|
else
|
|
{
|
|
size_t cnt_src_id = data->session.next_src_id;
|
|
dma->sar = (uint64_t)data->session.srcs[cnt_src_id++];
|
|
if (cnt_src_id < data->session.src_num)
|
|
data->session.next_src_id++;
|
|
else
|
|
data->session.next_src_id = 0;
|
|
|
|
size_t cnt_dest_id = data->session.next_dest_id;
|
|
dma->dar = (uint64_t)data->session.dests[cnt_dest_id++];
|
|
if (cnt_dest_id < data->session.dest_num)
|
|
data->session.next_dest_id++;
|
|
else
|
|
data->session.next_dest_id = 0;
|
|
|
|
if (data->session.stage_completion_handler)
|
|
data->session.stage_completion_handler(data->session.stage_completion_handler_data);
|
|
dmac->chen |= 0x101 << data->channel;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
release_axi_master(dmacdata, data->session.axi_master);
|
|
|
|
if (data->session.flow_control != DMAC_MEM2MEM_DMA && data->session.element_size < 4)
|
|
{
|
|
if (data->session.flow_control == DMAC_PRF2MEM_DMA)
|
|
{
|
|
if (data->session.element_size == 1)
|
|
{
|
|
size_t i;
|
|
uint32_t* p_src = data->session.alloc_mem;
|
|
uint8_t* p_dst = (uint8_t*)data->session.dest;
|
|
for (i = 0; i < data->session.count; i++)
|
|
p_dst[i] = p_src[i];
|
|
}
|
|
else if (data->session.element_size == 2)
|
|
{
|
|
size_t i;
|
|
uint32_t* p_src = data->session.alloc_mem;
|
|
uint16_t* p_dst = (uint16_t*)data->session.dest;
|
|
for (i = 0; i < data->session.count; i++)
|
|
p_dst[i] = p_src[i];
|
|
}
|
|
else
|
|
{
|
|
configASSERT(!"invalid element size");
|
|
}
|
|
}
|
|
else if (data->session.flow_control == DMAC_MEM2PRF_DMA)
|
|
;
|
|
else
|
|
{
|
|
configASSERT(!"Impossible");
|
|
}
|
|
|
|
free(data->session.alloc_mem);
|
|
}
|
|
|
|
xSemaphoreGiveFromISR(data->session.completion_event, &xHigherPriorityTaskWoken);
|
|
}
|
|
}
|
|
|
|
static void dma_install(void* userdata)
|
|
{
|
|
C_COMMON_ENTRY;
|
|
|
|
pic_set_irq_handler(IRQN_DMA0_INTERRUPT + data->channel, dma_completion_isr, userdata);
|
|
pic_set_irq_priority(IRQN_DMA0_INTERRUPT + data->channel, 1);
|
|
pic_set_irq_enable(IRQN_DMA0_INTERRUPT + data->channel, 1);
|
|
}
|
|
|
|
static int dma_open(void* userdata)
|
|
{
|
|
C_COMMON_ENTRY;
|
|
return atomic_cas(&data->used, 0, 1) == 0;
|
|
}
|
|
|
|
static void dma_close_imp(void* userdata)
|
|
{
|
|
C_COMMON_ENTRY;
|
|
atomic_set(&data->used, 0);
|
|
}
|
|
|
|
static void dma_set_select_request_imp(uint32_t request, void* userdata)
|
|
{
|
|
C_COMMON_ENTRY;
|
|
|
|
if (data->channel == SYSCTL_DMA_CHANNEL_5)
|
|
{
|
|
sysctl->dma_sel1.dma_sel5 = request;
|
|
}
|
|
else
|
|
{
|
|
struct sysctl_dma_sel0_t dma_sel;
|
|
dma_sel = sysctl->dma_sel0;
|
|
|
|
switch (data->channel)
|
|
{
|
|
case SYSCTL_DMA_CHANNEL_0:
|
|
dma_sel.dma_sel0 = request;
|
|
break;
|
|
|
|
case SYSCTL_DMA_CHANNEL_1:
|
|
dma_sel.dma_sel1 = request;
|
|
break;
|
|
|
|
case SYSCTL_DMA_CHANNEL_2:
|
|
dma_sel.dma_sel2 = request;
|
|
break;
|
|
|
|
case SYSCTL_DMA_CHANNEL_3:
|
|
dma_sel.dma_sel3 = request;
|
|
break;
|
|
|
|
case SYSCTL_DMA_CHANNEL_4:
|
|
dma_sel.dma_sel4 = request;
|
|
break;
|
|
|
|
default:
|
|
configASSERT(!"Invalid dma channel");
|
|
}
|
|
|
|
/* Write register back to bus */
|
|
sysctl->dma_sel0 = dma_sel;
|
|
}
|
|
}
|
|
|
|
static void dma_config_imp(uint32_t priority, void* userdata)
|
|
{
|
|
C_COMMON_ENTRY;
|
|
configASSERT((dmac->chen & (1 << data->channel)) == 0);
|
|
configASSERT(priority <= 7);
|
|
|
|
union dmac_ch_cfg_u cfg_u;
|
|
|
|
cfg_u.data = readq(&dma->cfg);
|
|
cfg_u.ch_cfg.ch_prior = priority;
|
|
writeq(cfg_u.data, &dma->cfg);
|
|
}
|
|
|
|
static int is_memory(uintptr_t address)
|
|
{
|
|
enum
|
|
{
|
|
mem_len = 6 * 1024 * 1024
|
|
};
|
|
|
|
return ((address >= 0x80000000) && (address < 0x80000000 + mem_len)) || ((address >= 0x40000000) && (address < 0x40000000 + mem_len)) || (address == 0x50450040);
|
|
}
|
|
|
|
static void dma_loop_async_imp(const volatile void** srcs, size_t src_num, volatile void** dests, size_t dest_num, int src_inc, int dest_inc, size_t element_size, size_t count, size_t burst_size, dma_stage_completion_handler stage_completion_handler, void* stage_completion_handler_data, SemaphoreHandle_t completion_event, int* stop_signal, void* userdata)
|
|
{
|
|
C_COMMON_ENTRY;
|
|
|
|
if (count == 0)
|
|
{
|
|
xSemaphoreGive(completion_event);
|
|
return;
|
|
}
|
|
|
|
src_inc = !src_inc;
|
|
dest_inc = !dest_inc;
|
|
configASSERT(count > 0 && count <= 0x3fffff);
|
|
configASSERT((dmac->chen & (1 << data->channel)) == 0);
|
|
configASSERT(element_size >= 4);
|
|
configASSERT(src_num > 0 && src_num <= MAX_PING_PONG_SRCS);
|
|
configASSERT(dest_num > 0 && dest_num <= MAX_PING_PONG_SRCS);
|
|
|
|
int mem_type_src = is_memory((uintptr_t)srcs[0]), mem_type_dest = is_memory((uintptr_t)dests[0]);
|
|
|
|
union dmac_ch_cfg_u cfg_u;
|
|
|
|
enum dmac_transfer_flow flow_control = DMAC_MEM2MEM_DMA;
|
|
if (mem_type_src == 0 && mem_type_dest == 0)
|
|
{
|
|
configASSERT(!"Periph to periph dma is not supported.");
|
|
}
|
|
else if (mem_type_src == 1 && mem_type_dest == 0)
|
|
flow_control = DMAC_MEM2PRF_DMA;
|
|
else if (mem_type_src == 0 && mem_type_dest == 1)
|
|
flow_control = DMAC_PRF2MEM_DMA;
|
|
else if (mem_type_src == 1 && mem_type_dest == 1)
|
|
flow_control = DMAC_MEM2MEM_DMA;
|
|
|
|
configASSERT(flow_control == DMAC_MEM2MEM_DMA || element_size <= 8);
|
|
|
|
cfg_u.data = readq(&dma->cfg);
|
|
cfg_u.ch_cfg.tt_fc = flow_control;
|
|
cfg_u.ch_cfg.hs_sel_src = mem_type_src ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE;
|
|
cfg_u.ch_cfg.hs_sel_dst = mem_type_dest ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE;
|
|
cfg_u.ch_cfg.src_per = data->channel;
|
|
cfg_u.ch_cfg.dst_per = data->channel;
|
|
cfg_u.ch_cfg.src_multblk_type = 0;
|
|
cfg_u.ch_cfg.dst_multblk_type = 0;
|
|
|
|
writeq(cfg_u.data, &dma->cfg);
|
|
|
|
data->session.is_ping_pong = 1;
|
|
data->session.flow_control = flow_control;
|
|
|
|
dma->sar = (uint64_t)srcs[0];
|
|
dma->dar = (uint64_t)dests[0];
|
|
|
|
dma->block_ts = count - 1;
|
|
|
|
uint32_t tr_width = 0;
|
|
switch (element_size)
|
|
{
|
|
case 1:
|
|
tr_width = 0;
|
|
break;
|
|
case 2:
|
|
tr_width = 1;
|
|
break;
|
|
case 4:
|
|
tr_width = 2;
|
|
break;
|
|
case 8:
|
|
tr_width = 3;
|
|
break;
|
|
case 16:
|
|
tr_width = 4;
|
|
break;
|
|
default:
|
|
configASSERT(!"Invalid element size.");
|
|
break;
|
|
}
|
|
|
|
uint32_t msize = 0;
|
|
switch (burst_size)
|
|
{
|
|
case 1:
|
|
msize = 0;
|
|
break;
|
|
case 4:
|
|
msize = 1;
|
|
break;
|
|
case 8:
|
|
msize = 2;
|
|
break;
|
|
case 16:
|
|
msize = 3;
|
|
break;
|
|
case 32:
|
|
msize = 4;
|
|
break;
|
|
default:
|
|
configASSERT(!"Invalid busrt size.");
|
|
break;
|
|
}
|
|
|
|
dma->intstatus_en = 0xFFFFFFE2;
|
|
dma->intclear = 0xFFFFFFFF;
|
|
|
|
union dmac_ch_ctl_u ctl_u;
|
|
|
|
ctl_u.data = readq(&dma->ctl);
|
|
ctl_u.ch_ctl.sinc = src_inc;
|
|
ctl_u.ch_ctl.src_tr_width = tr_width;
|
|
ctl_u.ch_ctl.src_msize = msize;
|
|
ctl_u.ch_ctl.dinc = dest_inc;
|
|
ctl_u.ch_ctl.dst_tr_width = tr_width;
|
|
ctl_u.ch_ctl.dst_msize = msize;
|
|
|
|
uint32_t axi_master = add_lru_axi_master(dmacdata);
|
|
data->session.axi_master = axi_master;
|
|
|
|
ctl_u.ch_ctl.sms = axi_master;
|
|
ctl_u.ch_ctl.dms = axi_master;
|
|
|
|
writeq(ctl_u.data, &dma->ctl);
|
|
|
|
data->session.completion_event = completion_event;
|
|
data->session.stage_completion_handler_data = stage_completion_handler_data;
|
|
data->session.stage_completion_handler = stage_completion_handler;
|
|
data->session.stop_signal = stop_signal;
|
|
data->session.src_num = src_num;
|
|
data->session.dest_num = dest_num;
|
|
data->session.next_src_id = 0;
|
|
data->session.next_dest_id = 0;
|
|
size_t i = 0;
|
|
for (i = 0; i < src_num; i++)
|
|
data->session.srcs[i] = srcs[i];
|
|
for (i = 0; i < dest_num; i++)
|
|
data->session.dests[i] = dests[i];
|
|
|
|
dmac->chen |= 0x101 << data->channel;
|
|
}
|
|
|
|
static void dma_transmit_async_imp(const volatile void* src, volatile void* dest, int src_inc, int dest_inc, size_t element_size, size_t count, size_t burst_size, SemaphoreHandle_t completion_event, void* userdata)
|
|
{
|
|
C_COMMON_ENTRY;
|
|
|
|
if (count == 0)
|
|
{
|
|
xSemaphoreGive(completion_event);
|
|
return;
|
|
}
|
|
|
|
src_inc = !src_inc;
|
|
dest_inc = !dest_inc;
|
|
configASSERT(count > 0 && count <= 0x3fffff);
|
|
configASSERT((dmac->chen & (1 << data->channel)) == 0);
|
|
|
|
int mem_type_src = is_memory((uintptr_t)src), mem_type_dest = is_memory((uintptr_t)dest);
|
|
|
|
union dmac_ch_cfg_u cfg_u;
|
|
|
|
enum dmac_transfer_flow flow_control = DMAC_MEM2MEM_DMA;
|
|
if (mem_type_src == 0 && mem_type_dest == 0)
|
|
{
|
|
configASSERT(!"Periph to periph dma is not supported.");
|
|
}
|
|
else if (mem_type_src == 1 && mem_type_dest == 0)
|
|
flow_control = DMAC_MEM2PRF_DMA;
|
|
else if (mem_type_src == 0 && mem_type_dest == 1)
|
|
flow_control = DMAC_PRF2MEM_DMA;
|
|
else if (mem_type_src == 1 && mem_type_dest == 1)
|
|
flow_control = DMAC_MEM2MEM_DMA;
|
|
|
|
configASSERT(flow_control == DMAC_MEM2MEM_DMA || element_size <= 8);
|
|
|
|
cfg_u.data = readq(&dma->cfg);
|
|
cfg_u.ch_cfg.tt_fc = flow_control;
|
|
cfg_u.ch_cfg.hs_sel_src = mem_type_src ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE;
|
|
cfg_u.ch_cfg.hs_sel_dst = mem_type_dest ? DMAC_HS_SOFTWARE : DMAC_HS_HARDWARE;
|
|
cfg_u.ch_cfg.src_per = data->channel;
|
|
cfg_u.ch_cfg.dst_per = data->channel;
|
|
cfg_u.ch_cfg.src_multblk_type = 0;
|
|
cfg_u.ch_cfg.dst_multblk_type = 0;
|
|
|
|
writeq(cfg_u.data, &dma->cfg);
|
|
|
|
data->session.is_ping_pong = 0;
|
|
data->session.flow_control = flow_control;
|
|
|
|
size_t old_elm_size = element_size;
|
|
data->session.element_size = old_elm_size;
|
|
data->session.count = count;
|
|
data->session.dest = dest;
|
|
data->session.alloc_mem = NULL;
|
|
|
|
if (flow_control != DMAC_MEM2MEM_DMA && old_elm_size < 4)
|
|
{
|
|
void* alloc_mem = malloc(sizeof(uint32_t) * count);
|
|
data->session.alloc_mem = alloc_mem;
|
|
element_size = sizeof(uint32_t);
|
|
|
|
if (!mem_type_src)
|
|
{
|
|
dma->sar = (uint64_t)src;
|
|
dma->dar = (uint64_t)alloc_mem;
|
|
}
|
|
else if (!mem_type_dest)
|
|
{
|
|
if (old_elm_size == 1)
|
|
{
|
|
size_t i;
|
|
const uint8_t* p_src = (const uint8_t*)src;
|
|
uint32_t* p_dst = alloc_mem;
|
|
for (i = 0; i < count; i++)
|
|
p_dst[i] = p_src[i];
|
|
}
|
|
else if (old_elm_size == 2)
|
|
{
|
|
size_t i;
|
|
const uint16_t* p_src = (const uint16_t*)src;
|
|
uint32_t* p_dst = alloc_mem;
|
|
for (i = 0; i < count; i++)
|
|
p_dst[i] = p_src[i];
|
|
}
|
|
else
|
|
{
|
|
configASSERT(!"invalid element size");
|
|
}
|
|
|
|
dma->sar = (uint64_t)alloc_mem;
|
|
dma->dar = (uint64_t)dest;
|
|
}
|
|
else
|
|
{
|
|
configASSERT(!"Impossible");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dma->sar = (uint64_t)src;
|
|
dma->dar = (uint64_t)dest;
|
|
}
|
|
|
|
dma->block_ts = count - 1;
|
|
|
|
uint32_t tr_width = 0;
|
|
switch (element_size)
|
|
{
|
|
case 1:
|
|
tr_width = 0;
|
|
break;
|
|
case 2:
|
|
tr_width = 1;
|
|
break;
|
|
case 4:
|
|
tr_width = 2;
|
|
break;
|
|
case 8:
|
|
tr_width = 3;
|
|
break;
|
|
case 16:
|
|
tr_width = 4;
|
|
break;
|
|
default:
|
|
configASSERT(!"Invalid element size.");
|
|
break;
|
|
}
|
|
|
|
uint32_t msize = 0;
|
|
switch (burst_size)
|
|
{
|
|
case 1:
|
|
msize = 0;
|
|
break;
|
|
case 4:
|
|
msize = 1;
|
|
break;
|
|
case 8:
|
|
msize = 2;
|
|
break;
|
|
case 16:
|
|
msize = 3;
|
|
break;
|
|
case 32:
|
|
msize = 4;
|
|
break;
|
|
default:
|
|
configASSERT(!"Invalid busrt size.");
|
|
break;
|
|
}
|
|
|
|
dma->intstatus_en = 0xFFFFFFE2;
|
|
dma->intclear = 0xFFFFFFFF;
|
|
|
|
union dmac_ch_ctl_u ctl_u;
|
|
|
|
ctl_u.data = readq(&dma->ctl);
|
|
ctl_u.ch_ctl.sinc = src_inc;
|
|
ctl_u.ch_ctl.src_tr_width = tr_width;
|
|
ctl_u.ch_ctl.src_msize = msize;
|
|
ctl_u.ch_ctl.dinc = dest_inc;
|
|
ctl_u.ch_ctl.dst_tr_width = tr_width;
|
|
ctl_u.ch_ctl.dst_msize = msize;
|
|
|
|
uint32_t axi_master = add_lru_axi_master(dmacdata);
|
|
data->session.axi_master = axi_master;
|
|
|
|
ctl_u.ch_ctl.sms = axi_master;
|
|
ctl_u.ch_ctl.dms = axi_master;
|
|
|
|
writeq(ctl_u.data, &dma->ctl);
|
|
|
|
data->session.completion_event = completion_event;
|
|
dmac->chen |= 0x101 << data->channel;
|
|
}
|
|
|
|
static dma_data dev0_c0_data = {&dev0_data, 0, 0, {0}};
|
|
static dma_data dev0_c1_data = {&dev0_data, 1, 0, {0}};
|
|
static dma_data dev0_c2_data = {&dev0_data, 2, 0, {0}};
|
|
static dma_data dev0_c3_data = {&dev0_data, 3, 0, {0}};
|
|
static dma_data dev0_c4_data = {&dev0_data, 4, 0, {0}};
|
|
static dma_data dev0_c5_data = {&dev0_data, 5, 0, {0}};
|
|
|
|
const dma_driver_t g_dma_driver_dma0 = {{&dev0_c0_data, dma_install, dma_open, dma_close_imp}, dma_set_select_request_imp, dma_config_imp, dma_transmit_async_imp, dma_loop_async_imp};
|
|
const dma_driver_t g_dma_driver_dma1 = {{&dev0_c1_data, dma_install, dma_open, dma_close_imp}, dma_set_select_request_imp, dma_config_imp, dma_transmit_async_imp, dma_loop_async_imp};
|
|
const dma_driver_t g_dma_driver_dma2 = {{&dev0_c2_data, dma_install, dma_open, dma_close_imp}, dma_set_select_request_imp, dma_config_imp, dma_transmit_async_imp, dma_loop_async_imp};
|
|
const dma_driver_t g_dma_driver_dma3 = {{&dev0_c3_data, dma_install, dma_open, dma_close_imp}, dma_set_select_request_imp, dma_config_imp, dma_transmit_async_imp, dma_loop_async_imp};
|
|
const dma_driver_t g_dma_driver_dma4 = {{&dev0_c4_data, dma_install, dma_open, dma_close_imp}, dma_set_select_request_imp, dma_config_imp, dma_transmit_async_imp, dma_loop_async_imp};
|
|
const dma_driver_t g_dma_driver_dma5 = {{&dev0_c5_data, dma_install, dma_open, dma_close_imp}, dma_set_select_request_imp, dma_config_imp, dma_transmit_async_imp, dma_loop_async_imp};
|