kendryte-standalone-sdk/lib/drivers/dmac.c

717 lines
22 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 <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include "dmac.h"
#include "sysctl.h"
#include "fpioa.h"
#include "common.h"
#include "plic.h"
#include "stdlib.h"
volatile struct dmac_t *const dmac = (struct dmac_t *)DMAC_BASE_ADDR;
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);
}
uint64_t dmac_read_id(void)
{
return dmac->id;
}
uint64_t dmac_read_version(void)
{
return dmac->compver;
}
uint64_t dmac_read_channel_id(dmac_channel_number channel_num)
{
return dmac->channel[channel_num].axi_id;
}
void dmac_enable(void)
{
union dmac_cfg_u dmac_cfg;
dmac_cfg.data = readq(&dmac->cfg);
dmac_cfg.cfg.dmac_en = 1;
dmac_cfg.cfg.int_en = 1;
writeq(dmac_cfg.data, &dmac->cfg);
}
void dmac_disable(void)
{
union dmac_cfg_u dmac_cfg;
dmac_cfg.data = readq(&dmac->cfg);
dmac_cfg.cfg.dmac_en = 0;
dmac_cfg.cfg.int_en = 0;
writeq(dmac_cfg.data, &dmac->cfg);
}
void src_transaction_complete_int_enable(dmac_channel_number channel_num)
{
union dmac_ch_intstatus_enable_u ch_intstat;
ch_intstat.data = readq(&dmac->channel[channel_num].intstatus_en);
ch_intstat.ch_intstatus_enable.enable_src_transcomp_intstat = 1;
writeq(ch_intstat.data, &dmac->channel[channel_num].intstatus_en);
}
void dmac_channel_enable(dmac_channel_number channel_num)
{
union dmac_chen_u chen;
chen.data = readq(&dmac->chen);
switch (channel_num) {
case DMAC_CHANNEL0:
chen.dmac_chen.ch1_en = 1;
chen.dmac_chen.ch1_en_we = 1;
break;
case DMAC_CHANNEL1:
chen.dmac_chen.ch2_en = 1;
chen.dmac_chen.ch2_en_we = 1;
break;
case DMAC_CHANNEL2:
chen.dmac_chen.ch3_en = 1;
chen.dmac_chen.ch3_en_we = 1;
break;
case DMAC_CHANNEL3:
chen.dmac_chen.ch4_en = 1;
chen.dmac_chen.ch4_en_we = 1;
break;
case DMAC_CHANNEL4:
chen.dmac_chen.ch5_en = 1;
chen.dmac_chen.ch5_en_we = 1;
break;
case DMAC_CHANNEL5:
chen.dmac_chen.ch6_en = 1;
chen.dmac_chen.ch6_en_we = 1;
break;
default:
break;
}
writeq(chen.data, &dmac->chen);
}
void dmac_channel_disable(dmac_channel_number channel_num)
{
union dmac_chen_u chen;
chen.data = readq(&dmac->chen);
switch (channel_num) {
case DMAC_CHANNEL0:
chen.dmac_chen.ch1_en = 0;
chen.dmac_chen.ch1_en_we = 0;
break;
case DMAC_CHANNEL1:
chen.dmac_chen.ch2_en = 0;
chen.dmac_chen.ch2_en_we = 0;
break;
case DMAC_CHANNEL2:
chen.dmac_chen.ch3_en = 0;
chen.dmac_chen.ch3_en_we = 0;
break;
case DMAC_CHANNEL3:
chen.dmac_chen.ch4_en = 0;
chen.dmac_chen.ch4_en_we = 0;
break;
case DMAC_CHANNEL4:
chen.dmac_chen.ch5_en = 0;
chen.dmac_chen.ch5_en_we = 0;
break;
case DMAC_CHANNEL5:
chen.dmac_chen.ch6_en = 0;
chen.dmac_chen.ch6_en_we = 0;
break;
default:
break;
}
writeq(chen.data, &dmac->chen);
}
int32_t dmac_check_channel_busy(dmac_channel_number channel_num)
{
int32_t ret = 0;
union dmac_chen_u chen_u;
chen_u.data = readq(&dmac->chen);
switch (channel_num) {
case DMAC_CHANNEL0:
if (chen_u.dmac_chen.ch1_en == 1)
ret = 1;
break;
case DMAC_CHANNEL1:
if (chen_u.dmac_chen.ch2_en == 1)
ret = 1;
break;
case DMAC_CHANNEL2:
if (chen_u.dmac_chen.ch3_en == 1)
ret = 1;
break;
case DMAC_CHANNEL3:
if (chen_u.dmac_chen.ch4_en == 1)
ret = 1;
break;
case DMAC_CHANNEL4:
if (chen_u.dmac_chen.ch5_en == 1)
ret = 1;
break;
case DMAC_CHANNEL5:
if (chen_u.dmac_chen.ch6_en == 1)
ret = 1;
break;
default:
break;
}
writeq(chen_u.data, &dmac->chen);
return ret;
}
int32_t dmac_set_list_master_select(dmac_channel_number channel_num,
dmac_src_dst_select sd_sel, enum dmac_master_number mst_num)
{
int32_t ret = 0;
uint64_t tmp = 0;
union dmac_ch_ctl_u ctl;
ctl.data = readq(&dmac->channel[channel_num].ctl);
ret = dmac_check_channel_busy(channel_num);
if (ret == 0) {
if (sd_sel == DMAC_SRC || sd_sel == DMAC_SRC_DST)
ctl.ch_ctl.sms = mst_num;
if (sd_sel == DMAC_DST || sd_sel == DMAC_SRC_DST)
ctl.ch_ctl.dms = mst_num;
tmp |= *(uint64_t *)&dmac->channel[channel_num].ctl;
writeq(ctl.data, &dmac->channel[channel_num].ctl);
}
return ret;
}
void dmac_enable_common_interrupt_status(void)
{
union dmac_commonreg_intstatus_enable_u intstatus;
intstatus.data = readq(&dmac->com_intstatus_en);
intstatus.intstatus_enable.enable_slvif_dec_err_intstat = 1;
intstatus.intstatus_enable.enable_slvif_wr2ro_err_intstat = 1;
intstatus.intstatus_enable.enable_slvif_rd2wo_err_intstat = 1;
intstatus.intstatus_enable.enable_slvif_wronhold_err_intstat = 1;
intstatus.intstatus_enable.enable_slvif_undefinedreg_dec_err_intstat = 1;
writeq(intstatus.data, &dmac->com_intstatus_en);
}
void dmac_enable_common_interrupt_signal(void)
{
union dmac_commonreg_intsignal_enable_u intsignal;
intsignal.data = readq(&dmac->com_intsignal_en);
intsignal.intsignal_enable.enable_slvif_dec_err_intsignal = 1;
intsignal.intsignal_enable.enable_slvif_wr2ro_err_intsignal = 1;
intsignal.intsignal_enable.enable_slvif_rd2wo_err_intsignal = 1;
intsignal.intsignal_enable.enable_slvif_wronhold_err_intsignal = 1;
intsignal.intsignal_enable.enable_slvif_undefinedreg_dec_err_intsignal = 1;
writeq(intsignal.data, &dmac->com_intsignal_en);
}
void dmac_enable_channel_interrupt_status(dmac_channel_number channel_num)
{
writeq(0xffffffff, &dmac->channel[channel_num].intclear);
writeq(0xffffffff, &dmac->channel[channel_num].intstatus_en);
}
void dmac_disable_channel_interrupt_status(dmac_channel_number channel_num)
{
writeq(0, &dmac->channel[channel_num].intstatus_en);
}
void dmac_enable_channel_interrupt_signal(dmac_channel_number channel_num,
enum dmca_common_int which_interrupt)
{
}
void dmac_chanel_interrupt_clear(dmac_channel_number channel_num)
{
writeq(0xffffffff, &dmac->channel[channel_num].intclear);
}
int dmac_set_channel_config(dmac_channel_number channel_num,
struct dmac_channel_config_t *cfg_param)
{
union dmac_ch_ctl_u ctl;
union dmac_ch_cfg_u cfg;
union dmac_ch_llp_u ch_llp;
if (cfg_param->ctl_sms > DMAC_MASTER2)
return -1;
if (cfg_param->ctl_dms > DMAC_MASTER2)
return -1;
if (cfg_param->ctl_src_msize > DMAC_MSIZE_256)
return -1;
if (cfg_param->ctl_drc_msize > DMAC_MSIZE_256)
return -1;
/**
* cfg register must configure before ts_block and
* sar dar register
*/
cfg.data = readq(&dmac->channel[channel_num].cfg);
cfg.ch_cfg.hs_sel_src = cfg_param->cfg_hs_sel_src;
cfg.ch_cfg.hs_sel_dst = cfg_param->cfg_hs_sel_dst;
cfg.ch_cfg.src_hwhs_pol = cfg_param->cfg_src_hs_pol;
cfg.ch_cfg.dst_hwhs_pol = cfg_param->cfg_dst_hs_pol;
cfg.ch_cfg.src_per = cfg_param->cfg_src_per;
cfg.ch_cfg.dst_per = cfg_param->cfg_dst_per;
cfg.ch_cfg.ch_prior = cfg_param->cfg_ch_prior;
cfg.ch_cfg.tt_fc = cfg_param->ctl_tt_fc;
cfg.ch_cfg.src_multblk_type = cfg_param->cfg_src_multblk_type;
cfg.ch_cfg.dst_multblk_type = cfg_param->cfg_dst_multblk_type;
writeq(cfg.data, &dmac->channel[channel_num].cfg);
ctl.data = readq(&dmac->channel[channel_num].ctl);
ctl.ch_ctl.sms = cfg_param->ctl_sms;
ctl.ch_ctl.dms = cfg_param->ctl_dms;
/* master select */
ctl.ch_ctl.sinc = cfg_param->ctl_sinc;
ctl.ch_ctl.dinc = cfg_param->ctl_dinc;
/* address incrememt */
ctl.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width;
ctl.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width;
/* transfer width */
ctl.ch_ctl.src_msize = cfg_param->ctl_src_msize;
ctl.ch_ctl.dst_msize = cfg_param->ctl_drc_msize;
/* Burst transaction length */
ctl.ch_ctl.ioc_blktfr = cfg_param->ctl_ioc_blktfr;
/* interrupt on completion of block transfer */
/* 0x1 enable BLOCK_TFR_DONE_IntStat field */
writeq(cfg_param->ctl_block_ts, &dmac->channel[channel_num].block_ts);
/* the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */
/* transferred in a dma block transfer */
dmac->channel[channel_num].sar = cfg_param->sar;
dmac->channel[channel_num].dar = cfg_param->dar;
ch_llp.data = readq(&dmac->channel[channel_num].llp);
ch_llp.llp.loc = cfg_param->llp_loc;
ch_llp.llp.lms = cfg_param->llp_lms;
writeq(ch_llp.data, &dmac->channel[channel_num].llp);
writeq(ctl.data, &dmac->channel[channel_num].ctl);
readq(&dmac->channel[channel_num].swhssrc);
return 0;
}
int dmac_set_channel_param(dmac_channel_number channel_num,
void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc,
enum dmac_burst_trans_length dmac_msize,
enum dmac_transfer_width dmac_trans_width,
uint32_t blockSize)
{
union dmac_ch_ctl_u ctl;
union dmac_ch_cfg_u cfg_u;
int mem_type_src = is_memory((uintptr_t)src), mem_type_dest = is_memory((uintptr_t)dest);
enum dmac_transfer_flow flow_control;
if (mem_type_src == 0 && mem_type_dest == 0)
{
flow_control = DMAC_PRF2PRF_DMA;
}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;
/**
* cfg register must configure before ts_block and
* sar dar register
*/
cfg_u.data = readq(&dmac->channel[channel_num].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 = channel_num;
cfg_u.ch_cfg.dst_per = channel_num;
cfg_u.ch_cfg.src_multblk_type = 0;
cfg_u.ch_cfg.dst_multblk_type = 0;
writeq(cfg_u.data, &dmac->channel[channel_num].cfg);
dmac->channel[channel_num].sar = (uint64_t)src;
dmac->channel[channel_num].dar = (uint64_t)dest;
ctl.data = readq(&dmac->channel[channel_num].ctl);
ctl.ch_ctl.sms = DMAC_MASTER1;
ctl.ch_ctl.dms = DMAC_MASTER2;
/* master select */
ctl.ch_ctl.sinc = src_inc;
ctl.ch_ctl.dinc = dest_inc;
/* address incrememt */
ctl.ch_ctl.src_tr_width = dmac_trans_width;
ctl.ch_ctl.dst_tr_width = dmac_trans_width;
/* transfer width */
ctl.ch_ctl.src_msize = dmac_msize;
ctl.ch_ctl.dst_msize = dmac_msize;
writeq(ctl.data, &dmac->channel[channel_num].ctl);
writeq(blockSize - 1, &dmac->channel[channel_num].block_ts);
/*the number of (blcok_ts +1) data of width SRC_TR_WIDTF to be */
/* transferred in a dma block transfer */
return 0;
}
int dmac_get_channel_config(dmac_channel_number channel_num,
struct dmac_channel_config_t *cfg_param)
{
union dmac_ch_ctl_u ctl;
union dmac_ch_cfg_u cfg;
union dmac_ch_llp_u ch_llp;
if (cfg_param == 0)
return -1;
if (channel_num < DMAC_CHANNEL0 ||
channel_num > DMAC_CHANNEL3)
return -1;
ctl.data = readq(&dmac->channel[channel_num].ctl);
cfg_param->ctl_sms = ctl.ch_ctl.sms;
cfg_param->ctl_dms = ctl.ch_ctl.dms;
cfg_param->ctl_sinc = ctl.ch_ctl.sinc;
cfg_param->ctl_dinc = ctl.ch_ctl.dinc;
cfg_param->ctl_src_tr_width = ctl.ch_ctl.src_tr_width;
cfg_param->ctl_dst_tr_width = ctl.ch_ctl.dst_tr_width;
cfg_param->ctl_src_msize = ctl.ch_ctl.src_msize;
cfg_param->ctl_drc_msize = ctl.ch_ctl.dst_msize;
cfg_param->ctl_ioc_blktfr = ctl.ch_ctl.ioc_blktfr;
cfg.data = readq(&dmac->channel[channel_num].cfg);
cfg_param->cfg_hs_sel_src = cfg.ch_cfg.hs_sel_src;
cfg_param->cfg_hs_sel_dst = cfg.ch_cfg.hs_sel_dst;
cfg_param->cfg_src_hs_pol = cfg.ch_cfg.src_hwhs_pol;
cfg_param->cfg_dst_hs_pol = cfg.ch_cfg.dst_hwhs_pol;
cfg_param->cfg_src_per = cfg.ch_cfg.src_per;
cfg_param->cfg_dst_per = cfg.ch_cfg.dst_per;
cfg_param->cfg_ch_prior = cfg.ch_cfg.ch_prior;
cfg_param->cfg_src_multblk_type = cfg.ch_cfg.src_multblk_type;
cfg_param->cfg_dst_multblk_type = cfg.ch_cfg.dst_multblk_type;
cfg_param->sar = dmac->channel[channel_num].sar;
cfg_param->dar = dmac->channel[channel_num].dar;
ch_llp.data = readq(&dmac->channel[channel_num].llp);
cfg_param->llp_loc = ch_llp.llp.loc;
cfg_param->llp_lms = ch_llp.llp.lms;
cfg_param->ctl_block_ts = readq(&dmac->channel[channel_num].block_ts);
return 0;
}
void dmac_set_address(dmac_channel_number channel_num, uint64_t src_addr,
uint64_t dst_addr)
{
writeq(src_addr, &dmac->channel[channel_num].sar);
writeq(dst_addr, &dmac->channel[channel_num].dar);
}
void dmac_set_block_ts(dmac_channel_number channel_num,
uint32_t block_size)
{
uint32_t block_ts;
block_ts = block_size & 0x3fffff;
writeq(block_ts, &dmac->channel[channel_num].block_ts);
}
void dmac_source_control(dmac_channel_number channel_num,
enum dmac_master_number master_select,
enum dmac_address_increment address_mode,
enum dmac_transfer_width tr_width,
enum dmac_burst_trans_length burst_length)
{
union dmac_ch_ctl_u ctl_u;
ctl_u.data = readq(&dmac->channel[channel_num].ctl);
ctl_u.ch_ctl.sms = master_select;
ctl_u.ch_ctl.sinc = address_mode;
ctl_u.ch_ctl.src_tr_width = tr_width;
ctl_u.ch_ctl.src_msize = burst_length;
writeq(ctl_u.data, &dmac->channel[channel_num].ctl);
}
void dmac_master_control(dmac_channel_number channel_num,
enum dmac_master_number master_select,
enum dmac_address_increment address_mode,
enum dmac_transfer_width tr_width,
enum dmac_burst_trans_length burst_length)
{
union dmac_ch_ctl_u ctl_u;
ctl_u.data = readq(&dmac->channel[channel_num].ctl);
ctl_u.ch_ctl.dms = master_select;
ctl_u.ch_ctl.dinc = address_mode;
ctl_u.ch_ctl.dst_tr_width = tr_width;
ctl_u.ch_ctl.dst_msize = burst_length;
writeq(ctl_u.data, &dmac->channel[channel_num].ctl);
}
void dmac_set_source_transfer_control(dmac_channel_number channel_num,
enum dmac_multiblk_transfer_type transfer_type,
enum dmac_sw_hw_hs_select handshak_select)
{
union dmac_ch_cfg_u cfg_u;
cfg_u.data = readq(&dmac->channel[channel_num].cfg);
cfg_u.ch_cfg.src_multblk_type = transfer_type;
cfg_u.ch_cfg.hs_sel_src = handshak_select;
writeq(cfg_u.data, &dmac->channel[channel_num].cfg);
}
void dmac_set_destination_transfer_control(dmac_channel_number channel_num,
enum dmac_multiblk_transfer_type transfer_type,
enum dmac_sw_hw_hs_select handshak_select)
{
union dmac_ch_cfg_u cfg_u;
cfg_u.data = readq(&dmac->channel[channel_num].cfg);
cfg_u.ch_cfg.dst_multblk_type = transfer_type;
cfg_u.ch_cfg.hs_sel_dst = handshak_select;
writeq(cfg_u.data, &dmac->channel[channel_num].cfg);
}
void dmac_set_flow_control(dmac_channel_number channel_num,
enum dmac_transfer_flow flow_control)
{
union dmac_ch_cfg_u cfg_u;
cfg_u.data = readq(&dmac->channel[channel_num].cfg);
cfg_u.ch_cfg.tt_fc = flow_control;
writeq(cfg_u.data, &dmac->channel[channel_num].cfg);
}
void dmac_set_linked_list_addr_point(dmac_channel_number channel_num,
uint64_t *addr)
{
union dmac_ch_llp_u llp_u;
llp_u.data = readq(&dmac->channel[channel_num].llp);
/* Cast pointer to uint64_t */
llp_u.llp.loc = (uint64_t)addr;
writeq(llp_u.data, &dmac->channel[channel_num].llp);
}
void dmac_init(void)
{
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);
/*reset dmac */
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);
/* clear common register interrupt */
dmac_cfg.data = readq(&dmac->cfg);
dmac_cfg.cfg.dmac_en = 0;
dmac_cfg.cfg.int_en = 0;
writeq(dmac_cfg.data, &dmac->cfg);
/* disable dmac and disable interrupt */
while (readq(&dmac->cfg))
;
tmp = readq(&dmac->chen);
tmp &= ~0xf;
writeq(tmp, &dmac->chen);
/* disable all channel before configure */
}
void list_add(struct list_head_t *new, struct list_head_t *prev,
struct list_head_t *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
void list_add_tail(struct list_head_t *new, struct list_head_t *head)
{
list_add(new, head->prev, head);
}
void INIT_LIST_HEAD(struct list_head_t *list)
{
list->next = list;
list->prev = list;
}
void dmac_link_list_item(dmac_channel_number channel_num,
uint8_t LLI_row_num, int8_t LLI_last_row,
struct dmac_lli_item_t *lli_item,
struct dmac_channel_config_t *cfg_param)
{
union dmac_ch_ctl_u ctl;
union dmac_ch_llp_u llp_u;
lli_item[LLI_row_num].sar = cfg_param->sar;
lli_item[LLI_row_num].dar = cfg_param->dar;
ctl.data = readq(&dmac->channel[channel_num].ctl);
ctl.ch_ctl.sms = cfg_param->ctl_sms;
ctl.ch_ctl.dms = cfg_param->ctl_dms;
ctl.ch_ctl.sinc = cfg_param->ctl_sinc;
ctl.ch_ctl.dinc = cfg_param->ctl_dinc;
ctl.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width;
ctl.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width;
ctl.ch_ctl.src_msize = cfg_param->ctl_src_msize;
ctl.ch_ctl.dst_msize = cfg_param->ctl_drc_msize;
ctl.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en;
ctl.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en;
if (LLI_last_row != LAST_ROW) {
ctl.ch_ctl.shadowreg_or_lli_valid = 1;
ctl.ch_ctl.shadowreg_or_lli_last = 0;
} else {
ctl.ch_ctl.shadowreg_or_lli_valid = 1;
ctl.ch_ctl.shadowreg_or_lli_last = 1;
}
lli_item[LLI_row_num].ctl = ctl.data;
lli_item[LLI_row_num].ch_block_ts = cfg_param->ctl_block_ts;
lli_item[LLI_row_num].sstat = 0;
lli_item[LLI_row_num].dstat = 0;
llp_u.data = readq(&dmac->channel[channel_num].llp);
if (LLI_last_row != LAST_ROW)
llp_u.llp.loc = ((uint64_t)&lli_item[LLI_row_num + 1]) >> 6;
else
llp_u.llp.loc = 0;
lli_item[LLI_row_num].llp = llp_u.data;
}
void dmac_update_shandow_register(dmac_channel_number channel_num,
int8_t last_block, struct dmac_channel_config_t *cfg_param)
{
union dmac_ch_ctl_u ctl_u;
do {
ctl_u.data = readq(&dmac->channel[channel_num].ctl);
} while (ctl_u.ch_ctl.shadowreg_or_lli_valid);
writeq(cfg_param->sar, &dmac->channel[channel_num].sar);
writeq(cfg_param->dar, &dmac->channel[channel_num].dar);
writeq(cfg_param->ctl_block_ts, &dmac->channel[channel_num].block_ts);
ctl_u.ch_ctl.sms = cfg_param->ctl_sms;
ctl_u.ch_ctl.dms = cfg_param->ctl_dms;
ctl_u.ch_ctl.sinc = cfg_param->ctl_sinc;
ctl_u.ch_ctl.dinc = cfg_param->ctl_dinc;
ctl_u.ch_ctl.src_tr_width = cfg_param->ctl_src_tr_width;
ctl_u.ch_ctl.dst_tr_width = cfg_param->ctl_dst_tr_width;
ctl_u.ch_ctl.src_msize = cfg_param->ctl_src_msize;
ctl_u.ch_ctl.dst_msize = cfg_param->ctl_drc_msize;
ctl_u.ch_ctl.src_stat_en = cfg_param->ctl_src_stat_en;
ctl_u.ch_ctl.dst_stat_en = cfg_param->ctl_dst_stat_en;
if (last_block != LAST_ROW)
{
ctl_u.ch_ctl.shadowreg_or_lli_valid = 1;
ctl_u.ch_ctl.shadowreg_or_lli_last = 0;
} else {
ctl_u.ch_ctl.shadowreg_or_lli_valid = 1;
ctl_u.ch_ctl.shadowreg_or_lli_last = 1;
}
writeq(ctl_u.data, &dmac->channel[channel_num].ctl);
writeq(0, &dmac->channel[channel_num].blk_tfr);
}
void dmac_set_shadow_invalid_flag(dmac_channel_number channel_num)
{
union dmac_ch_ctl_u ctl_u;
ctl_u.data = readq(&dmac->channel[channel_num].ctl);
ctl_u.ch_ctl.shadowreg_or_lli_valid = 1;
ctl_u.ch_ctl.shadowreg_or_lli_last = 0;
writeq(ctl_u.data, &dmac->channel[channel_num].ctl);
}
void dmac_set_single_mode(dmac_channel_number channel_num,
void *src, void *dest, enum dmac_address_increment src_inc, enum dmac_address_increment dest_inc,
enum dmac_burst_trans_length dmac_msize,
enum dmac_transfer_width dmac_trans_width,
uint32_t blockSize)
{
dmac_channel_disable(channel_num);
dmac_set_channel_param(channel_num, src, dest, src_inc,dest_inc,
dmac_msize,dmac_trans_width,blockSize);
dmac_enable();
dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */
dmac_enable_channel_interrupt_status(channel_num);
dmac_channel_enable(channel_num);
}
void dmac_wait_done(dmac_channel_number channel_num)
{
while (!(readq(&dmac->channel[channel_num].intstatus) & 0x2))
;
dmac_chanel_interrupt_clear(channel_num); /* clear interrupt */
}