/** * @file dma.c * @author chipsea * @brief * @version 0.1 * @date 2020-11-30 * @copyright Copyright (c) 2020, CHIPSEA Co., Ltd. * @note */ #include #include "clock.h" #include "pwrmgr.h" #include "error.h" #include "log.h" #include "jump_function.h" #include "dma.h" typedef struct{ bool init_flg; DMA_CH_Ctx_t dma_ch_ctx[DMA_CH_NUM]; }dma_ctx_t; dma_ctx_t s_dma_ctx = { .init_flg = FALSE, }; static DMA_CONN_e GetSrcConn(uint32_t addr) { if(addr == (uint32_t)&(AP_SPI0->DataReg)) return DMA_CONN_SPI0_Rx; if(addr == (uint32_t)&(AP_SPI1->DataReg)) return DMA_CONN_SPI1_Rx; if(addr == (uint32_t)&(AP_I2C0->IC_DATA_CMD)) return DMA_CONN_I2C0_Rx; if(addr == (uint32_t)&(AP_I2C1->IC_DATA_CMD)) return DMA_CONN_I2C1_Rx; if(addr == (uint32_t)&(AP_UART0->RBR)) return DMA_CONN_UART0_Rx; if(addr == (uint32_t)&(AP_UART1->RBR)) return DMA_CONN_UART1_Rx; return DMA_CONN_MEM; } static DMA_CONN_e GetDstConn(uint32_t addr) { if(addr == (uint32_t)&(AP_SPI0->DataReg)) return DMA_CONN_SPI0_Tx; if(addr == (uint32_t)&(AP_SPI1->DataReg)) return DMA_CONN_SPI1_Tx; if(addr == (uint32_t)&(AP_I2C0->IC_DATA_CMD)) return DMA_CONN_I2C0_Tx; if(addr == (uint32_t)&(AP_I2C1->IC_DATA_CMD)) return DMA_CONN_I2C1_Tx; if(addr == (uint32_t)&(AP_UART0->THR)) return DMA_CONN_UART0_Tx; if(addr == (uint32_t)&(AP_UART1->THR)) return DMA_CONN_UART1_Tx; return DMA_CONN_MEM; } static void DMAWakeupHandler(void) { hal_clk_gate_enable(MOD_DMA); NVIC_SetPriority((IRQn_Type)DMAC_IRQn, IRQ_PRIO_HAL); NVIC_EnableIRQ((IRQn_Type)DMAC_IRQn); JUMP_FUNCTION(V19_IRQ_HANDLER) = (uint32_t)&HalDMAIRQHandler; AP_DMA_MISC->DmaCfgReg = DMA_DMAC_E; } int HalDMAInitChannel(HAL_DMA_t cfg) { DMA_CH_Ctx_t* pctx; DMA_CH_t ch; if(!s_dma_ctx.init_flg) return ERR_NOT_REGISTED; ch = cfg.dma_channel; if(ch >= DMA_CH_NUM) return ERR_INVALID_PARAM; pctx = &s_dma_ctx.dma_ch_ctx[ch]; if(pctx ->init_ch) return ERR_INVALID_STATE; pctx->evt_handler = cfg.evt_handler; pctx->init_ch = true; return SUCCESS; } int HalDMAConfigChannel(DMA_CH_t ch, DMA_CH_CFG_t* cfg) { DMA_CH_Ctx_t* pctx; DMA_CONN_e src_conn,dst_conn; uint32_t cctrl = 0; uint32_t transf_type = DMA_TRANSFERTYPE_M2M; uint32_t transf_per = 0; uint32_t spif_protect = AP_SPIF->wr_protection; uint32_t cache_bypass = AP_PCR->CACHE_BYPASS; if(!s_dma_ctx.init_flg) { return ERR_NOT_REGISTED; } if(ch >= DMA_CH_NUM) { return ERR_INVALID_PARAM; } if(cfg->sinc >DMA_INC_NCHG || cfg->dinc >DMA_INC_NCHG) { return ERR_INVALID_PARAM; } if(cfg->src_tr_width >DMA_WIDTH_8WORD || cfg->dst_tr_width >DMA_WIDTH_8WORD) { return ERR_INVALID_PARAM; } if(cfg->src_msize >DMA_BSIZE_256 || cfg->dst_msize >DMA_BSIZE_256) { return ERR_INVALID_PARAM; } pctx = &s_dma_ctx.dma_ch_ctx[ch]; if(!pctx->init_ch) return ERR_INVALID_STATE; if ((AP_DMA_MISC->ChEnReg & (DMA_DMACEnbldChns_Ch(ch))) || \ (pctx->xmit_busy)){ // This channel is enabled, return ERROR, need to release this channel first return ERR_BUSY; } // Reset the Interrupt status AP_DMA_INT->ClearTfr = DMA_DMACIntTfrClr_Ch(ch); // UnMask interrupt AP_DMA_INT->MaskTfr = DMA_DMACCxIntMask_E(ch); src_conn = GetSrcConn(cfg->src_addr); dst_conn = GetDstConn(cfg->dst_addr); /* Assign Linker List Item value */ if(src_conn && dst_conn){ transf_type = DMA_TRANSFERTYPE_P2P; transf_per = DMA_DMACCxConfig_SrcPeripheral(src_conn-1)| \ DMA_DMACCxConfig_DestPeripheral(dst_conn-1); } else if(src_conn){ transf_type = DMA_TRANSFERTYPE_P2M; transf_per = DMA_DMACCxConfig_SrcPeripheral(src_conn-1); } else if(dst_conn){ transf_type = DMA_TRANSFERTYPE_M2P; transf_per = DMA_DMACCxConfig_DestPeripheral(dst_conn-1); } if((cfg->dst_addr > 0x11000000) && (cfg->dst_addr <= 0x11080000)) { pctx->xmit_flash = DMA_DST_XIMT_IS_FLASH; if(spif_protect) { AP_SPIF->wr_protection = 0; } if(cache_bypass == 0) { AP_PCR->CACHE_BYPASS = 1; } } else { pctx->xmit_flash = DMA_DST_XIMT_NOT_FLASH; } AP_DMA_CH_CFG(ch)->SAR = cfg->src_addr; AP_DMA_CH_CFG(ch)->DAR = cfg->dst_addr; AP_DMA_CH_CFG(ch)->LLP = 0; if(DMA_GET_MAX_TRANSPORT_SIZE(ch) < cfg->transf_size) { return ERR_INVALID_PARAM; } AP_DMA_CH_CFG(ch)->CTL_H = DMA_DMACCxControl_TransferSize(cfg->transf_size); subWriteReg(&(AP_DMA_CH_CFG(ch)->CFG_H),15,7 ,transf_per); AP_DMA_CH_CFG(ch)->CFG = 0; cctrl = DMA_DMACCxConfig_TransferType(transf_type)| \ DMA_DMACCxControl_SMSize(cfg->src_msize)| \ DMA_DMACCxControl_DMSize(cfg->dst_msize)| \ DMA_DMACCxControl_SWidth(cfg->src_tr_width)| \ DMA_DMACCxControl_DWidth(cfg->dst_tr_width)| \ DMA_DMACCxControl_SInc(cfg->sinc)| \ DMA_DMACCxControl_DInc(cfg->dinc)| \ DMA_DMAC_INT_E; AP_DMA_CH_CFG(ch)->CTL = cctrl; if(cfg->enable_int) { AP_DMA_INT->MaskTfr = DMA_DMACCxConfig_E(ch) | BIT(ch); pctx->interrupt = true; } else { AP_DMA_INT->ClearTfr = DMA_DMACIntTfrClr_Ch(ch); AP_DMA_INT->MaskTfr = DMA_DMACCxIntMask_E(ch); pctx->interrupt = false; } return SUCCESS; } int HalDMAStartChannel(DMA_CH_t ch) { DMA_CH_Ctx_t* pctx; if(!s_dma_ctx.init_flg) return ERR_NOT_REGISTED; if(ch >= DMA_CH_NUM) { return ERR_INVALID_PARAM; } pctx = &s_dma_ctx.dma_ch_ctx[ch]; AP_DMA_MISC->ChEnReg = DMA_DMACCxConfig_E(ch) | BIT(ch); pctx->xmit_busy = TRUE; hal_pwrmgr_lock(MOD_DMA); return SUCCESS; } int HalDMAStopChannel(DMA_CH_t ch) { uint32_t spif_protect = AP_SPIF->wr_protection; uint32_t cache_bypass = AP_PCR->CACHE_BYPASS; DMA_CH_Ctx_t* pctx; if(!s_dma_ctx.init_flg) return ERR_NOT_REGISTED; if(ch >= DMA_CH_NUM) { return ERR_INVALID_PARAM; } pctx = &s_dma_ctx.dma_ch_ctx[ch]; if(pctx->xmit_flash == DMA_DST_XIMT_IS_FLASH) { if(spif_protect) { AP_SPIF->wr_protection = 2; } if(cache_bypass == 0) { AP_PCR->CACHE_BYPASS = 0; AP_CACHE->CTRL0 = 0x01; } } // Reset the Interrupt status AP_DMA_INT->ClearTfr = DMA_DMACIntTfrClr_Ch(ch); // UnMask interrupt // AP_DMA_INT->MaskTfr = DMA_DMACCxIntMask_E(ch); AP_DMA_MISC->ChEnReg = DMA_DMACCxConfig_E(ch); pctx->xmit_busy = FALSE; hal_pwrmgr_unlock(MOD_DMA); return SUCCESS; } int HalDMAStatusControl(DMA_CH_t ch) { DMA_CH_Ctx_t* pctx; if(!s_dma_ctx.init_flg) return ERR_NOT_REGISTED; if(ch >= DMA_CH_NUM) { return ERR_INVALID_PARAM; } pctx = &s_dma_ctx.dma_ch_ctx[ch]; if(pctx->interrupt == false) HalDMAWaitChannelComplete(ch); return SUCCESS; } int HalDMAWaitChannelComplete(DMA_CH_t ch) { uint32_t Temp = 0; if(!s_dma_ctx.init_flg) return ERR_NOT_REGISTED; if(ch >= DMA_CH_NUM) { return ERR_INVALID_PARAM; } while(1){ Temp ++; if(AP_DMA_INT->RawTfr) { break; } } HalDMAStopChannel(ch); // LOG("wait count is %d\n",Temp); return SUCCESS; } int HalDMAInit(void) { uint8_t ret; hal_clk_gate_enable(MOD_DMA); hal_clk_reset(MOD_DMA); NVIC_SetPriority((IRQn_Type)DMAC_IRQn, IRQ_PRIO_HAL); NVIC_EnableIRQ((IRQn_Type)DMAC_IRQn); JUMP_FUNCTION(V19_IRQ_HANDLER) = (uint32_t)&HalDMAIRQHandler; ret = hal_pwrmgr_register(MOD_DMA,NULL, DMAWakeupHandler); if(ret == SUCCESS) { s_dma_ctx.init_flg = TRUE; memset(&(s_dma_ctx.dma_ch_ctx[0]), 0, sizeof(DMA_CH_Ctx_t)*DMA_CH_NUM); //dmac controller enable AP_DMA_MISC->DmaCfgReg = DMA_DMAC_E; } else { return ret; } return SUCCESS; } int HalDMADeinit(void) { //dmac controller disable AP_DMA_MISC->DmaCfgReg = DMA_DMAC_D; s_dma_ctx.init_flg = FALSE; memset(&(s_dma_ctx.dma_ch_ctx[0]), 0, sizeof(DMA_CH_Ctx_t)*DMA_CH_NUM); hal_clk_gate_disable(MOD_DMA); return SUCCESS; } void __attribute__((used)) HalDMAIRQHandler(void) { DMA_CH_t ch; for(ch = DMA_CH_0;ch < DMA_CH_NUM;ch++) { if(AP_DMA_INT->StatusTfr & BIT(ch)) { HalDMAStopChannel(ch); if(s_dma_ctx.dma_ch_ctx[ch].evt_handler != NULL) { s_dma_ctx.dma_ch_ctx[ch].evt_handler(ch); } } } }