| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887 |
- /* 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 <stddef.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #include "dmac.h"
- #include "fpioa.h"
- #include "plic.h"
- #include "stdlib.h"
- #include "sysctl.h"
- #include "utils.h"
- #include "iomem.h"
- volatile dmac_t *const dmac = (dmac_t *)DMAC_BASE_ADDR;
- typedef struct _dmac_context
- {
- dmac_channel_number_t dmac_channel;
- #if FIX_CACHE
- uint8_t *dest_buffer;
- uint8_t *src_malloc;
- uint8_t *dest_malloc;
- size_t buf_len;
- #endif
- plic_irq_callback_t callback;
- void *ctx;
- } dmac_context_t;
- dmac_context_t dmac_context[6];
- static int is_memory(uintptr_t address)
- {
- enum
- {
- mem_len = 6 * 1024 * 1024,
- mem_no_cache_len = 8 * 1024 * 1024,
- };
- return ((address >= 0x80000000) && (address < 0x80000000 + mem_len)) || ((address >= 0x40000000) && (address < 0x40000000 + mem_no_cache_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_t channel_num)
- {
- return dmac->channel[channel_num].axi_id;
- }
- static void dmac_enable(void)
- {
- dmac_cfg_u_t 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)
- {
- dmac_cfg_u_t 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_t channel_num)
- {
- dmac_ch_intstatus_enable_u_t 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_t channel_num)
- {
- dmac_chen_u_t 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_t channel_num)
- {
- dmac_chen_u_t chen;
- chen.data = readq(&dmac->chen);
- switch(channel_num)
- {
- case DMAC_CHANNEL0:
- chen.dmac_chen.ch1_en = 0;
- chen.dmac_chen.ch1_en_we = 1;
- break;
- case DMAC_CHANNEL1:
- chen.dmac_chen.ch2_en = 0;
- chen.dmac_chen.ch2_en_we = 1;
- break;
- case DMAC_CHANNEL2:
- chen.dmac_chen.ch3_en = 0;
- chen.dmac_chen.ch3_en_we = 1;
- break;
- case DMAC_CHANNEL3:
- chen.dmac_chen.ch4_en = 0;
- chen.dmac_chen.ch4_en_we = 1;
- break;
- case DMAC_CHANNEL4:
- chen.dmac_chen.ch5_en = 0;
- chen.dmac_chen.ch5_en_we = 1;
- break;
- case DMAC_CHANNEL5:
- chen.dmac_chen.ch6_en = 0;
- chen.dmac_chen.ch6_en_we = 1;
- break;
- default:
- break;
- }
- writeq(chen.data, &dmac->chen);
- }
- int32_t dmac_check_channel_busy(dmac_channel_number_t channel_num)
- {
- int32_t ret = 0;
- dmac_chen_u_t 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_t channel_num,
- dmac_src_dst_select_t sd_sel, dmac_master_number_t mst_num)
- {
- int32_t ret = 0;
- uint64_t tmp = 0;
- dmac_ch_ctl_u_t 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)
- {
- dmac_commonreg_intstatus_enable_u_t 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)
- {
- dmac_commonreg_intsignal_enable_u_t 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);
- }
- static void dmac_enable_channel_interrupt(dmac_channel_number_t channel_num)
- {
- writeq(0xffffffff, &dmac->channel[channel_num].intclear);
- writeq(0x2, &dmac->channel[channel_num].intstatus_en);
- }
- void dmac_disable_channel_interrupt(dmac_channel_number_t channel_num)
- {
- writeq(0, &dmac->channel[channel_num].intstatus_en);
- }
- static void dmac_channel_interrupt_clear(dmac_channel_number_t channel_num)
- {
- writeq(0xffffffff, &dmac->channel[channel_num].intclear);
- }
- int dmac_set_channel_config(dmac_channel_number_t channel_num,
- dmac_channel_config_t *cfg_param)
- {
- dmac_ch_ctl_u_t ctl;
- dmac_ch_cfg_u_t cfg;
- dmac_ch_llp_u_t 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_t channel_num,
- const void *src, void *dest, dmac_address_increment_t src_inc, dmac_address_increment_t dest_inc,
- dmac_burst_trans_length_t dmac_burst_size,
- dmac_transfer_width_t dmac_trans_width,
- uint32_t blockSize)
- {
- dmac_ch_ctl_u_t ctl;
- dmac_ch_cfg_u_t cfg_u;
- #if FIX_CACHE
- uint8_t *src_io = (uint8_t *)src;
- uint8_t *dest_io = (uint8_t *)dest;
- if(is_memory_cache((uintptr_t)src))
- {
- if(src_inc == DMAC_ADDR_NOCHANGE)
- {
- src_io = (uint8_t *)iomem_malloc(1<<dmac_trans_width);
- memcpy(src_io, src, 1<<dmac_trans_width);
- }
- else
- {
- src_io = (uint8_t *)iomem_malloc(blockSize * (1<<dmac_trans_width));
- memcpy(src_io, src, blockSize * (1<<dmac_trans_width));
- }
- dmac_context[channel_num].src_malloc = src_io;
- }
- if(is_memory_cache((uintptr_t)dest))
- {
- if(dest_inc == DMAC_ADDR_NOCHANGE)
- {
- dest_io = (uint8_t *)iomem_malloc(1<<dmac_trans_width);
- dmac_context[channel_num].buf_len = 1<<dmac_trans_width;
- }
- else
- {
- dest_io = (uint8_t *)iomem_malloc(blockSize * (1<<dmac_trans_width));
- dmac_context[channel_num].buf_len = blockSize * (1<<dmac_trans_width);
- }
- dmac_context[channel_num].dest_malloc = dest_io;
- dmac_context[channel_num].dest_buffer = dest;
- }
- #endif
- int mem_type_src = is_memory((uintptr_t)src), mem_type_dest = is_memory((uintptr_t)dest);
- dmac_transfer_flow_t 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
- 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);
- #if FIX_CACHE
- dmac->channel[channel_num].sar = (uint64_t)src_io;
- dmac->channel[channel_num].dar = (uint64_t)dest_io;
- #else
- dmac->channel[channel_num].sar = (uint64_t)src;
- dmac->channel[channel_num].dar = (uint64_t)dest;
- #endif
- 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_burst_size;
- ctl.ch_ctl.dst_msize = dmac_burst_size;
- 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_t channel_num,
- dmac_channel_config_t *cfg_param)
- {
- dmac_ch_ctl_u_t ctl;
- dmac_ch_cfg_u_t cfg;
- dmac_ch_llp_u_t 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_t 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_t 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_t channel_num,
- dmac_master_number_t master_select,
- dmac_address_increment_t address_mode,
- dmac_transfer_width_t tr_width,
- dmac_burst_trans_length_t burst_length)
- {
- dmac_ch_ctl_u_t 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_t channel_num,
- dmac_master_number_t master_select,
- dmac_address_increment_t address_mode,
- dmac_transfer_width_t tr_width,
- dmac_burst_trans_length_t burst_length)
- {
- dmac_ch_ctl_u_t 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_t channel_num,
- dmac_multiblk_transfer_type_t transfer_type,
- dmac_sw_hw_hs_select_t handshak_select)
- {
- dmac_ch_cfg_u_t 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_t channel_num,
- dmac_multiblk_transfer_type_t transfer_type,
- dmac_sw_hw_hs_select_t handshak_select)
- {
- dmac_ch_cfg_u_t 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_t channel_num,
- dmac_transfer_flow_t flow_control)
- {
- dmac_ch_cfg_u_t 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_t channel_num,
- uint64_t *addr)
- {
- dmac_ch_llp_u_t 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;
- dmac_commonreg_intclear_u_t intclear;
- dmac_cfg_u_t dmac_cfg;
- dmac_reset_u_t 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);
- for(dmac_channel_number_t channel=DMAC_CHANNEL0; channel<DMAC_CHANNEL_MAX; channel++)
- {
- dmac_disable_channel_interrupt(channel);
- }
- /* disable all channel before configure */
- dmac_enable();
- }
- static 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_t channel_num,
- uint8_t LLI_row_num, int8_t LLI_last_row,
- dmac_lli_item_t *lli_item,
- dmac_channel_config_t *cfg_param)
- {
- dmac_ch_ctl_u_t ctl;
- dmac_ch_llp_u_t 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_t channel_num,
- int8_t last_block, dmac_channel_config_t *cfg_param)
- {
- dmac_ch_ctl_u_t 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_t channel_num)
- {
- dmac_ch_ctl_u_t 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_t channel_num,
- const void *src, void *dest, dmac_address_increment_t src_inc,
- dmac_address_increment_t dest_inc,
- dmac_burst_trans_length_t dmac_burst_size,
- dmac_transfer_width_t dmac_trans_width,
- size_t block_size)
- {
- dmac_channel_interrupt_clear(channel_num);
- dmac_channel_disable(channel_num);
- dmac_wait_idle(channel_num);
- dmac_set_channel_param(channel_num, src, dest, src_inc, dest_inc,
- dmac_burst_size, dmac_trans_width, block_size);
- dmac_enable();
- dmac_channel_enable(channel_num);
- }
- int dmac_is_done(dmac_channel_number_t channel_num)
- {
- if(readq(&dmac->channel[channel_num].intstatus) & 0x2)
- return 1;
- else
- return 0;
- }
- void dmac_wait_done(dmac_channel_number_t channel_num)
- {
- dmac_wait_idle(channel_num);
- #if FIX_CACHE
- if(dmac_context[channel_num].dest_buffer)
- {
- memcpy(dmac_context[channel_num].dest_buffer, dmac_context[channel_num].dest_malloc, dmac_context[channel_num].buf_len);
- iomem_free(dmac_context[channel_num].dest_malloc);
- dmac_context[channel_num].dest_malloc = NULL;
- dmac_context[channel_num].dest_buffer = NULL;
- dmac_context[channel_num].buf_len = 0;
- }
- if(dmac_context[channel_num].src_malloc)
- {
- iomem_free(dmac_context[channel_num].src_malloc);
- dmac_context[channel_num].src_malloc = NULL;
- }
- #endif
- }
- int dmac_is_idle(dmac_channel_number_t channel_num)
- {
- dmac_chen_u_t chen;
- chen.data = readq(&dmac->chen);
- if((chen.data >> channel_num) & 0x1UL)
- return 0;
- else
- return 1;
- }
- void dmac_wait_idle(dmac_channel_number_t channel_num)
- {
- while(!dmac_is_idle(channel_num))
- ;
- dmac_channel_interrupt_clear(channel_num); /* clear interrupt */
- }
- void dmac_set_src_dest_length(dmac_channel_number_t channel_num, const void *src, void *dest, size_t len)
- {
- if(src != NULL)
- dmac->channel[channel_num].sar = (uint64_t)src;
- if(dest != NULL)
- dmac->channel[channel_num].dar = (uint64_t)dest;
- if(len > 0)
- dmac_set_block_ts(channel_num, len - 1);
- dmac_channel_enable(channel_num);
- }
- static int dmac_irq_callback(void *ctx)
- {
- dmac_context_t *v_dmac_context = (dmac_context_t *)(ctx);
- dmac_channel_number_t v_dmac_channel = v_dmac_context->dmac_channel;
- dmac_channel_interrupt_clear(v_dmac_channel);
- #if FIX_CACHE
- if(v_dmac_context->dest_buffer)
- {
- memcpy(v_dmac_context->dest_buffer, v_dmac_context->dest_malloc, v_dmac_context->buf_len);
- iomem_free(v_dmac_context->dest_malloc);
- v_dmac_context->dest_malloc = NULL;
- v_dmac_context->dest_buffer = NULL;
- v_dmac_context->buf_len = 0;
- }
- if(v_dmac_context->src_malloc)
- {
- iomem_free(v_dmac_context->src_malloc);
- v_dmac_context->src_malloc = NULL;
- }
- #endif
- if(v_dmac_context->callback != NULL)
- v_dmac_context->callback(v_dmac_context->ctx);
- return 0;
- }
- void dmac_irq_register(dmac_channel_number_t channel_num, plic_irq_callback_t dmac_callback, void *ctx, uint32_t priority)
- {
- dmac_context[channel_num].dmac_channel = channel_num;
- dmac_context[channel_num].callback = dmac_callback;
- dmac_context[channel_num].ctx = ctx;
- dmac_enable_channel_interrupt(channel_num);
- plic_set_priority(IRQN_DMA0_INTERRUPT + channel_num, priority);
- plic_irq_register(IRQN_DMA0_INTERRUPT + channel_num, dmac_irq_callback, &dmac_context[channel_num]);
- plic_irq_enable(IRQN_DMA0_INTERRUPT + channel_num);
- }
- void __attribute__((weak, alias("dmac_irq_register"))) dmac_set_irq(dmac_channel_number_t channel_num, plic_irq_callback_t dmac_callback, void *ctx, uint32_t priority);
- void dmac_irq_unregister(dmac_channel_number_t channel_num)
- {
- dmac_context[channel_num].callback = NULL;
- dmac_context[channel_num].ctx = NULL;
- dmac_disable_channel_interrupt(channel_num);
- plic_irq_unregister(IRQN_DMA0_INTERRUPT + channel_num);
- }
- void __attribute__((weak, alias("dmac_irq_unregister"))) dmac_free_irq(dmac_channel_number_t channel_num);
|