370 lines
8.5 KiB
C
370 lines
8.5 KiB
C
/*************
|
|
dma.c
|
|
SDK_LICENSE
|
|
***************/
|
|
|
|
#include <string.h>
|
|
|
|
#include "clock.h"
|
|
#include "pwrmgr.h"
|
|
#include "error.h"
|
|
#include "log.h"
|
|
#include "jump_function.h"
|
|
|
|
#include "dma.h"
|
|
#include "spi.h"
|
|
#include "uart.h"
|
|
#include "i2c.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 get_src_conn(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 get_dst_conn(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 dma_wakeup_handler(void)
|
|
{
|
|
hal_clk_gate_enable(MOD_DMA);
|
|
NVIC_SetPriority((IRQn_Type)DMAC_IRQn, IRQ_PRIO_HAL);
|
|
NVIC_EnableIRQ((IRQn_Type)DMAC_IRQn);
|
|
JUMP_FUNCTION(DMAC_IRQ_HANDLER) = (uint32_t)&hal_DMA_IRQHandler;
|
|
AP_DMA_MISC->DmaCfgReg = DMA_DMAC_E;
|
|
}
|
|
|
|
|
|
int hal_dma_init_channel(HAL_DMA_t cfg)
|
|
{
|
|
DMA_CH_Ctx_t* pctx;
|
|
DMA_CH_t ch;
|
|
|
|
if(!s_dma_ctx.init_flg)
|
|
return PPlus_ERR_NOT_REGISTED;
|
|
|
|
ch = cfg.dma_channel;
|
|
|
|
if(ch >= DMA_CH_NUM)
|
|
return PPlus_ERR_INVALID_PARAM;
|
|
|
|
pctx = &s_dma_ctx.dma_ch_ctx[ch];
|
|
|
|
if(pctx ->init_ch)
|
|
return PPlus_ERR_INVALID_STATE;
|
|
|
|
pctx->evt_handler = cfg.evt_handler;
|
|
pctx->init_ch = true;
|
|
return PPlus_SUCCESS;
|
|
}
|
|
|
|
|
|
int hal_dma_config_channel(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 PPlus_ERR_NOT_REGISTED;
|
|
|
|
if(ch >= DMA_CH_NUM)
|
|
{
|
|
return PPlus_ERR_INVALID_PARAM;
|
|
}
|
|
|
|
pctx = &s_dma_ctx.dma_ch_ctx[ch];
|
|
|
|
if(!pctx->init_ch)
|
|
return PPlus_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 PPlus_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 = get_src_conn(cfg->src_addr);
|
|
dst_conn = get_dst_conn(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 PPlus_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 PPlus_SUCCESS;
|
|
}
|
|
|
|
int hal_dma_start_channel(DMA_CH_t ch)
|
|
{
|
|
DMA_CH_Ctx_t* pctx;
|
|
|
|
if(!s_dma_ctx.init_flg)
|
|
return PPlus_ERR_NOT_REGISTED;
|
|
|
|
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 PPlus_SUCCESS;
|
|
}
|
|
|
|
int hal_dma_stop_channel(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 PPlus_ERR_NOT_REGISTED;
|
|
|
|
if(ch >= DMA_CH_NUM)
|
|
{
|
|
return PPlus_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 PPlus_SUCCESS;
|
|
}
|
|
|
|
int hal_dma_status_control(DMA_CH_t ch)
|
|
{
|
|
DMA_CH_Ctx_t* pctx;
|
|
|
|
if(!s_dma_ctx.init_flg)
|
|
return PPlus_ERR_NOT_REGISTED;
|
|
|
|
if(ch >= DMA_CH_NUM)
|
|
{
|
|
return PPlus_ERR_INVALID_PARAM;
|
|
}
|
|
|
|
pctx = &s_dma_ctx.dma_ch_ctx[ch];
|
|
|
|
if(pctx->interrupt == false)
|
|
hal_dma_wait_channel_complete(ch);
|
|
|
|
return PPlus_SUCCESS;
|
|
}
|
|
|
|
int hal_dma_wait_channel_complete(DMA_CH_t ch)
|
|
{
|
|
uint32_t Temp = 0;
|
|
|
|
if(!s_dma_ctx.init_flg)
|
|
return PPlus_ERR_NOT_REGISTED;
|
|
|
|
while(1)
|
|
{
|
|
Temp ++;
|
|
|
|
if(AP_DMA_INT->RawTfr)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
hal_dma_stop_channel(ch);
|
|
// LOG("wait count is %d\n",Temp);
|
|
return PPlus_SUCCESS;
|
|
}
|
|
|
|
int hal_dma_init(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(DMAC_IRQ_HANDLER) = (uint32_t)&hal_DMA_IRQHandler;
|
|
ret = hal_pwrmgr_register(MOD_DMA,NULL, dma_wakeup_handler);
|
|
|
|
if(ret == PPlus_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;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int hal_dma_deinit(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_pwrmgr_unregister(MOD_DMA);
|
|
hal_clk_gate_disable(MOD_DMA);
|
|
return PPlus_SUCCESS;
|
|
}
|
|
|
|
void __attribute__((used)) hal_DMA_IRQHandler(void)
|
|
{
|
|
DMA_CH_t ch;
|
|
|
|
for(ch = DMA_CH_0; ch < DMA_CH_NUM; ch++)
|
|
{
|
|
if(AP_DMA_INT->StatusTfr & BIT(ch))
|
|
{
|
|
hal_dma_stop_channel(ch);
|
|
|
|
if(s_dma_ctx.dma_ch_ctx[ch].evt_handler != NULL)
|
|
{
|
|
s_dma_ctx.dma_ch_ctx[ch].evt_handler(ch);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|