/**
 * @file hv_cal_Dma.c
 * @brief dma driver chip abstract layer file.
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2023-06-15
 * @copyright Copyright(c),2023-6, Hiview Software. All rights reserved.
 * </table>
 */

#include "hv_chip_Config.h"
#include "hv_vos_Comm.h"
#include "hv_comm_DataType.h"
#include "hv_comm_Define.h"
#include "hv_cal_Dma.h"
#include "hv_comm_Assert.h"

static DmaSelf* s_pstDma[DMA_CHANNEL_COUNT] = {NULL,};

static UINT32 g_uiChannelIrqAttachFlag = 0;

static HV_VOS_ISR_RESULT_E  Hv_Cal_Dma_Port0_IrqHandler(UINT32 uiIrqNum, void *pArg);

static HV_VOS_ISR_RESULT_E  Hv_Cal_Dma_Port1_IrqHandler(UINT32 uiIrqNum, void *pArg);

static BOOL Hv_Cal_Dma_GetFlag(DmaSelf *pstSelf, UINT32 uiFlagBit)
{
    UINT32 uiValue = 0;

    uiValue = HV_R32(CPU_SYS_DMAC_STATUSINT + pstSelf->portOffset);
    return (uiValue & uiFlagBit & DMA_FLAG_MASK) == (uiFlagBit & DMA_FLAG_MASK);
}

static Status Hv_Cal_Dma_WaitOnFlagUntilTimeout(DmaSelf * pstSelf, UINT32 uiFlag, UINT32 uiTimeout)
{
    UINT64 tickstart = 0;
    tickstart = Hv_Vos_GetTick();

    /* Wait the flag set*/
    while (Hv_Cal_Dma_GetFlag(pstSelf, uiFlag) != HV_TRUE)
    {
        if (uiTimeout != 0)
        {
            if ((Hv_Vos_GetTick() - tickstart ) > uiTimeout)
            {
                return HV_FAILURE;
            }
        }
    }
    return HV_SUCCESS;
}

static void DMA_CHANNEL_IrqAttach(DmaSelf* pstSelf)
{
    UINT32 uiAttachIrqState   = 0;
    UINT32 uiRegVal           = 0;
    UINT32 uiIntNumOffset     = 0;

    DmaPortChannel enPortChannelNum = pstSelf->InitParam.PortChannelNum;
    DmaPort enDmaPort = (DmaPort)(enPortChannelNum >> DMA_PORT_BITS_MASK);
    UINT32 uiChannelNum = enPortChannelNum & DMA_CHANNEL_MASK;

    if (enDmaPort == DMA_PORT_0)
    {
        uiAttachIrqState = g_uiChannelIrqAttachFlag & (1 << enPortChannelNum);

        if (uiAttachIrqState == 0)
        {
            g_uiChannelIrqAttachFlag |= (1 << enPortChannelNum);
            uiRegVal = HV_R32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1);
            if (enPortChannelNum == DMA_PORT0_CHANNEL0)
            {
                uiIntNumOffset = 0;
                uiRegVal |= (1 << DMA_PORT0_CHANNEL0);
                HV_W32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1, uiRegVal);
            }
            else if (enPortChannelNum == DMA_PORT0_CHANNEL1)
            {
                uiIntNumOffset = 1;
                uiRegVal |= (1 <<(DMA_PORT0_CHANNEL1 + 8));
                HV_W32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1, uiRegVal);
            }
            else if (enPortChannelNum == DMA_PORT0_CHANNEL2)
            {
                uiIntNumOffset = 2;
                uiRegVal |= (1 <<(DMA_PORT0_CHANNEL2 + 16));
                HV_W32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1, uiRegVal);
            }
            else if (enPortChannelNum == DMA_PORT0_CHANNEL3)
            {
                uiIntNumOffset = 3;
                uiRegVal |= (1 <<(DMA_PORT0_CHANNEL3 + 24));
                HV_W32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1, uiRegVal);
            }
            else
            {
                return;
            }
            Hv_Vos_AttachIsr(HV_CHIP_IRQ_PDMAC_CH0 - uiIntNumOffset, Hv_Cal_Dma_Port0_IrqHandler, pstSelf);
            Hv_Vos_UnmaskIrq(HV_CHIP_IRQ_PDMAC_CH0 - uiIntNumOffset);
        }
    }
    else if (enDmaPort == DMA_PORT_1)
    {
        uiAttachIrqState = g_uiChannelIrqAttachFlag & (1 << enPortChannelNum);
        if (uiAttachIrqState == 0)
        {
            g_uiChannelIrqAttachFlag |= (1 << enPortChannelNum);
            Hv_Vos_AttachIsr(HV_CHIP_IRQ_GDMAC_CH0 - uiChannelNum, Hv_Cal_Dma_Port1_IrqHandler, pstSelf);
            Hv_Vos_UnmaskIrq(HV_CHIP_IRQ_GDMAC_CH0 - uiChannelNum);
        }
    }
    else
    {
        return;
    }
}

static void DMA_CHANNEL_IrqUnAttach(DmaSelf* pstSelf)
{
    UINT32 uiRegVal           = 0;
    UINT32 uiIntNumOffset     = 0;
    UINT32 uiAttachedChNum    = 0;

    DmaPortChannel enPortChannelNum = pstSelf->InitParam.PortChannelNum;
    DmaPort enDmaPort = (DmaPort)(enPortChannelNum >> DMA_PORT_BITS_MASK);
    UINT32 uiChannelNum = enPortChannelNum & DMA_CHANNEL_MASK;

    if (enDmaPort == DMA_PORT_0)
    {
        uiAttachedChNum = g_uiChannelIrqAttachFlag & (1 << enPortChannelNum);
        if (uiAttachedChNum > 0)
        {
            g_uiChannelIrqAttachFlag &= ~(1 << enPortChannelNum);
            uiRegVal = HV_R32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1);
            if (enPortChannelNum == DMA_PORT0_CHANNEL0)
            {
                uiIntNumOffset = 0;
                uiRegVal &= ~(1 << DMA_PORT0_CHANNEL0);
                HV_W32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1,uiRegVal);
            }
            else if (enPortChannelNum == DMA_PORT0_CHANNEL1)
            {
                uiIntNumOffset = 1;
                uiRegVal &= ~(1 << (DMA_PORT0_CHANNEL1 + 8));
                HV_W32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1, uiRegVal);
            }
            else if (enPortChannelNum == DMA_PORT0_CHANNEL2)
            {
                uiIntNumOffset = 2;
                uiRegVal &= ~(1 << (DMA_PORT0_CHANNEL2 + 16));
                HV_W32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1, uiRegVal);
            }
            else if (enPortChannelNum == DMA_PORT0_CHANNEL3)
            {
                uiIntNumOffset = 3;
                uiRegVal &= ~(1 << (DMA_PORT0_CHANNEL3 + 24));
                HV_W32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED1, uiRegVal);
            }
            else
            {
                return;
            }
            Hv_Vos_MaskIrq(HV_CHIP_IRQ_PDMAC_CH0 - uiIntNumOffset);
            Hv_Vos_DetachIsr(HV_CHIP_IRQ_PDMAC_CH0 - uiIntNumOffset, Hv_Cal_Dma_Port0_IrqHandler);
        }
    }
    else if (enDmaPort == DMA_PORT_1)
    {
        uiAttachedChNum = g_uiChannelIrqAttachFlag & (1 << enPortChannelNum);
        if (uiAttachedChNum > 0)
        {
            g_uiChannelIrqAttachFlag &= ~(1 << enPortChannelNum);
            Hv_Vos_MaskIrq(HV_CHIP_IRQ_GDMAC_CH0 - uiChannelNum);
            Hv_Vos_DetachIsr(HV_CHIP_IRQ_GDMAC_CH0 - uiChannelNum, Hv_Cal_Dma_Port1_IrqHandler);
        }
    }
    else
    {
        return;
    }

}

void Hv_Cal_Dma_InterfaceAttribute(DmaInitParam* InitParam)
{
    if (InitParam->Application == DMA_APPLI_I2C0_TX)
    {
        InitParam->DstInterface = DMA_CHANNEL_HW_INTERF_8;
    }
    else if (InitParam->Application == DMA_APPLI_I2C0_RX)
    {
        InitParam->SrcInterface = DMA_CHANNEL_HW_INTERF_9;
    }
    else if (InitParam->Application == DMA_APPLI_I2C1_TX)
    {
        InitParam->DstInterface = DMA_CHANNEL_HW_INTERF_10;
    }
    else if (InitParam->Application == DMA_APPLI_I2C1_RX)
    {
        InitParam->SrcInterface = DMA_CHANNEL_HW_INTERF_11;
    }
    else if (InitParam->Application == DMA_APPLI_UART0_TX)
    {
        InitParam->DstInterface = DMA_CHANNEL_HW_INTERF_12;
    }
    else if (InitParam->Application == DMA_APPLI_UART0_RX)
    {
        InitParam->SrcInterface = DMA_CHANNEL_HW_INTERF_13;
    }
    else if (InitParam->Application == DMA_APPLI_UART1_TX)
    {
        InitParam->DstInterface = DMA_CHANNEL_HW_INTERF_14;
    }
    else if (InitParam->Application == DMA_APPLI_UART1_RX)
    {
        InitParam->SrcInterface = DMA_CHANNEL_HW_INTERF_15;
    }
    else if (InitParam->Application == DMA_APPLI_SPI0_TX)
    {
        InitParam->DstInterface = DMA_CHANNEL_HW_INTERF_4;
    }
    else if (InitParam->Application == DMA_APPLI_SPI0_RX)
    {
        InitParam->SrcInterface = DMA_CHANNEL_HW_INTERF_5;
    }
    else if (InitParam->Application == DMA_APPLI_QSPI0_TX)
    {
        InitParam->DstInterface = DMA_CHANNEL_HW_INTERF_0;
    }
    else if (InitParam->Application == DMA_APPLI_QSPI0_RX)
    {
        InitParam->SrcInterface = DMA_CHANNEL_HW_INTERF_1;
    }
    else
    {
        ;
    }
    return;
}

void Hv_Cal_Dma_TransTypeAttribute(DmaInitParam* InitParam)
{

    if (InitParam->transType == DMA_TYPE_SINGLE)
    {
        InitParam->SrcLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->DstLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->SrcAutoReloadEn = DMA_AUTO_RELOAD_DIS;
        InitParam->DstAutoReloadEn = DMA_AUTO_RELOAD_DIS;
    }
    else if (InitParam->transType == DMA_TYPE_LINKEDLIST)
    {
        InitParam->SrcLinkedListEn = DMA_LINKED_LIST_EN;
        InitParam->DstLinkedListEn = DMA_LINKED_LIST_EN;
        InitParam->SrcAutoReloadEn = DMA_AUTO_RELOAD_DIS;
        InitParam->DstAutoReloadEn = DMA_AUTO_RELOAD_DIS;
    }
    else if (InitParam->transType == DMA_TYPE_AUTORELOAD)
    {
        InitParam->SrcLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->DstLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->SrcAutoReloadEn = DMA_AUTO_RELOAD_EN;
        InitParam->DstAutoReloadEn = DMA_AUTO_RELOAD_EN;
    }
    else if (InitParam->transType == DMA_TYPE_LINKEDLIST_AUTORELOAD)
    {
        InitParam->SrcLinkedListEn = DMA_LINKED_LIST_EN;
        InitParam->DstLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->SrcAutoReloadEn = DMA_AUTO_RELOAD_DIS;
        InitParam->DstAutoReloadEn = DMA_AUTO_RELOAD_EN;
    }
    else if (InitParam->transType == DMA_TYPE_AUTORELOAD_LINKEDLIST)
    {
        InitParam->SrcLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->DstLinkedListEn = DMA_LINKED_LIST_EN;
        InitParam->SrcAutoReloadEn = DMA_AUTO_RELOAD_EN;
        InitParam->DstAutoReloadEn = DMA_AUTO_RELOAD_DIS;
    }
    else if (InitParam->transType == DMA_TYPE_LINKEDLIST_CONTIGU)
    {
        InitParam->SrcLinkedListEn = DMA_LINKED_LIST_EN;
        InitParam->DstLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->SrcAutoReloadEn = DMA_AUTO_RELOAD_DIS;
        InitParam->DstAutoReloadEn = DMA_AUTO_RELOAD_DIS;
    }
    else if (InitParam->transType == DMA_TYPE_CONTIGU_LINKEDLIST)
    {
        InitParam->SrcLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->DstLinkedListEn = DMA_LINKED_LIST_EN;
        InitParam->SrcAutoReloadEn = DMA_AUTO_RELOAD_DIS;
        InitParam->DstAutoReloadEn = DMA_AUTO_RELOAD_DIS;
    }
    else if (InitParam->transType == DMA_TYPE_AUTORELOAD_CONTIGU)
    {
        InitParam->SrcLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->DstLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->SrcAutoReloadEn = DMA_AUTO_RELOAD_EN;
        InitParam->DstAutoReloadEn = DMA_AUTO_RELOAD_DIS;
    }
    else if (InitParam->transType == DMA_TYPE_CONTIGU_AUTORELOAD)
    {
        InitParam->SrcLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->DstLinkedListEn = DMA_LINKED_LIST_DIS;
        InitParam->SrcAutoReloadEn = DMA_AUTO_RELOAD_DIS;
        InitParam->DstAutoReloadEn = DMA_AUTO_RELOAD_EN;
    }
    else
    {
        ;
    }
    return;
}

void Hv_Cal_Dma_DirectionAttribute(DmaInitParam* InitParam)
{
    if (InitParam->Application== DMA_APPLI_MEM)
    {
        InitParam->Direction = DMA_M_TO_M_DMAC;
        InitParam->Sink = DMA_SINK_INCREASE;
        InitParam->Dink = DMA_DINK_INCREASE;
    }
    else if ((InitParam->Application & DMA_APPLI_PERIPHERAL_TO_MEM_MASK) != HV_FALSE)
    {
        InitParam->Direction = DMA_P_TO_M_DMAC;
        InitParam->Sink = DMA_SINK_NO_CHANGE;
        InitParam->Dink = DMA_DINK_INCREASE;
    }
    else
    {
        InitParam->Direction = DMA_M_TO_P_DMAC;
        InitParam->Sink = DMA_SINK_INCREASE;
        InitParam->Dink = DMA_DINK_NO_CHANGE;
    }
    return;
}


void Hv_Cal_Dma_DataSizeAttribute(DmaInitParam* InitParam)
{

    if ((InitParam->Application & DMA_APPLI_DATAWIDTH32_MASK) != HV_FALSE)
    {
        InitParam->SrcDataSize = DMA_DATA_SIZE_32Bits;
        InitParam->DstDataSize = DMA_DATA_SIZE_32Bits;
    }
    else
    {
        InitParam->SrcDataSize = DMA_DATA_SIZE_8Bits;
        InitParam->DstDataSize = DMA_DATA_SIZE_8Bits;
    }
    return;
}

void Hv_Cal_Dma_BurstSizeAttribute(DmaInitParam* InitParam)
{
    if ((InitParam->Application & (DMA_APPLI_HIGH_SPEED_MASK | DMA_APPLI_DATAWIDTH32_MASK)) != HV_FALSE)
    {
        InitParam->SrcBurstSize = DMA_DATA_BURST_SIZE_8;
        InitParam->DstBurstSize = DMA_DATA_BURST_SIZE_8;
    }
    else if ((InitParam->Application & DMA_APPLI_MIDDLE_SPEED_MASK) != HV_FALSE)
    {
        InitParam->SrcBurstSize = DMA_DATA_BURST_SIZE_4;
        InitParam->DstBurstSize = DMA_DATA_BURST_SIZE_4;
    }
    else
    {
        InitParam->SrcBurstSize = DMA_DATA_BURST_SIZE_1;
        InitParam->DstBurstSize = DMA_DATA_BURST_SIZE_1;
    }
    return;
}

static void Hv_Cal_Dma_IntMask(DmaSelf * pstSelf, UINT32 uiIntFlag)
{

    rs_cpu_sys_dmac_masktfr       regMaskTfrVal     = {0};
    rs_cpu_sys_dmac_maskblock     regMaskBlockVal   = {0};
    rs_cpu_sys_dmac_masksrctran   regMaskSrctranVal = {0};
    rs_cpu_sys_dmac_maskdsttran   regMaskDsttranVal = {0};
    rs_cpu_sys_dmac_maskerr       regMaskErrVal     = {0};

    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    if ((uiIntFlag & DMA_FLAG_TFR) == DMA_FLAG_TFR)
    {
        regMaskTfrVal.INT_MASK_WE   = 1 << uiChannelNum;
        regMaskTfrVal.INT_MASK      = 0 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKTFR + pstSelf->portOffset, regMaskTfrVal);
    }
    if ((uiIntFlag & DMA_FLAG_BLOCK) == DMA_FLAG_BLOCK)
    {
        regMaskBlockVal.INT_MASK_WE = 1 << uiChannelNum;
        regMaskBlockVal.INT_MASK    = 0 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKBLOCK + pstSelf->portOffset, regMaskBlockVal);
    }
    if ((uiIntFlag & DMA_FLAG_SRCTRAN) == DMA_FLAG_SRCTRAN)
    {
        regMaskSrctranVal.INT_MASK_WE   = 1 << uiChannelNum;
        regMaskSrctranVal.INT_MASK      = 0 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKSRCTRAN + pstSelf->portOffset, regMaskSrctranVal);
    }
    if ((uiIntFlag & DMA_FLAG_DESTTRAN) == DMA_FLAG_DESTTRAN)
    {
        regMaskDsttranVal.INT_MASK_WE   = 1 << uiChannelNum;
        regMaskDsttranVal.INT_MASK      = 0 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKDSTTRAN + pstSelf->portOffset, regMaskDsttranVal);
    }
    if ((uiIntFlag & DMA_FLAG_ERR) == DMA_FLAG_ERR)
    {
        regMaskErrVal.INT_MASK_WE   = 1 << uiChannelNum;
        regMaskErrVal.INT_MASK      = 0 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKERR + pstSelf->portOffset, regMaskErrVal);
    }
    return;
}


static void Hv_Cal_Dma_IntEn(DmaSelf * pstSelf, UINT32 uiIntFlag)
{
    rs_cpu_sys_dmac_masktfr       regMaskTfrVal     = {0};
    rs_cpu_sys_dmac_maskblock     regMaskBlockVal   = {0};
    rs_cpu_sys_dmac_masksrctran   regMaskSrctranVal = {0};
    rs_cpu_sys_dmac_maskdsttran   regMaskDsttranVal = {0};
    rs_cpu_sys_dmac_maskerr       regMaskErrVal     = {0};

    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    if ((uiIntFlag & DMA_FLAG_TFR) == DMA_FLAG_TFR)
    {
        regMaskTfrVal.INT_MASK_WE   = 1 << uiChannelNum;
        regMaskTfrVal.INT_MASK      = 1 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKTFR + pstSelf->portOffset, regMaskTfrVal);
    }
    if ((uiIntFlag & DMA_FLAG_BLOCK) == DMA_FLAG_BLOCK)
    {
        regMaskBlockVal.INT_MASK_WE = 1 << uiChannelNum;
        regMaskBlockVal.INT_MASK    = 1 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKBLOCK + pstSelf->portOffset, regMaskBlockVal);
    }
    if ((uiIntFlag & DMA_FLAG_SRCTRAN) == DMA_FLAG_SRCTRAN)
    {
        regMaskSrctranVal.INT_MASK_WE   = 1 << uiChannelNum;
        regMaskSrctranVal.INT_MASK      = 1 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKSRCTRAN + pstSelf->portOffset, regMaskSrctranVal);
    }
    if ((uiIntFlag & DMA_FLAG_DESTTRAN) == DMA_FLAG_DESTTRAN)
    {
        regMaskDsttranVal.INT_MASK_WE   = 1 << uiChannelNum;
        regMaskDsttranVal.INT_MASK      = 1 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKDSTTRAN + pstSelf->portOffset, regMaskDsttranVal);
    }
    if ((uiIntFlag & DMA_FLAG_ERR) == DMA_FLAG_ERR)
    {
        regMaskErrVal.INT_MASK_WE   = 1 << uiChannelNum;
        regMaskErrVal.INT_MASK      = 1 << uiChannelNum;
        HV_W32_REG(CPU_SYS_DMAC_MASKERR + pstSelf->portOffset, regMaskErrVal);
    }
    return;
}


static void Hv_Cal_Dma_IntClear(DmaSelf * pstSelf, UINT32 uiIntFlag)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    if ((uiIntFlag & DMA_FLAG_TFR) == DMA_FLAG_TFR)
    {
        HV_W32(CPU_SYS_DMAC_CLEARTFR + pstSelf->portOffset, 1 << uiChannelNum);
    }
    if ((uiIntFlag & DMA_FLAG_BLOCK) == DMA_FLAG_BLOCK)
    {
        HV_W32(CPU_SYS_DMAC_CLEARBLOCK + pstSelf->portOffset, 1 << uiChannelNum);
    }
    if ((uiIntFlag & DMA_FLAG_SRCTRAN) == DMA_FLAG_SRCTRAN)
    {
        HV_W32(CPU_SYS_DMAC_CLEARSRCTRAN + pstSelf->portOffset, 1 << uiChannelNum);
    }
    if ((uiIntFlag & DMA_FLAG_DESTTRAN) == DMA_FLAG_DESTTRAN)
    {
        HV_W32(CPU_SYS_DMAC_CLEARDSTTRAN + pstSelf->portOffset, 1 << uiChannelNum);
    }
    if ((uiIntFlag & DMA_FLAG_ERR) == DMA_FLAG_ERR)
    {
        HV_W32(CPU_SYS_DMAC_CLEARERR + pstSelf->portOffset, 1 << uiChannelNum);
    }
    return;
}


static void Hv_Cal_Dma_TransCompleteCallback(DmaPort enDmaPort, UINT32 uiIntStatus)
{
    DmaInitParam* pstInitParam = NULL;
    DmaSelf * pstSelf = NULL;

    UINT32 uiIndex = enDmaPort * DMA_ONE_PORT_CHANNEL_COUNT;
    UINT32 uiChannel = 0;

    for (uiChannel = 0; uiChannel < 8; uiChannel++)
    {
        if (((uiIntStatus >> uiChannel) & 1) == 1)
        {
            pstSelf = s_pstDma[uiIndex + uiChannel];
            pstInitParam = &pstSelf->InitParam;
            if (pstInitParam->XferCpltCallback != NULL)
            {
                if ((pstInitParam->transType & DMA_TYPE_AUTORELOAD_MASK) == DMA_TYPE_AUTORELOAD_MASK)
                {
                    if (pstInitParam->BlockNum != DMA_WORK_LOOP)
                    {
                        Hv_Cal_Dma_IntMask(pstSelf,DMA_FLAG_BLOCK);
                    }
                }
                pstInitParam->XferCpltCallback(pstSelf);
            }
            pstSelf->TransCompleteFlag = DMA_TRANS_END;
        }
    }
    return;
}


static void Hv_Cal_Dma_BlockProcess(DmaSelf * pstSelf, UINT32 uiBlockIntFlag)
{
    DmaPortChannel enPortChannelNum = pstSelf->InitParam.PortChannelNum;
    UINT32 uiChannelOffset = (enPortChannelNum & DMA_CHANNEL_MASK) * DMA_CHANNEL_REG_LENGTH;

    if (pstSelf->InitParam.BlockNum == 2)
    {
        if ((pstSelf->InitParam.transType == DMA_TYPE_AUTORELOAD_LINKEDLIST)
            || (pstSelf->InitParam.transType == DMA_TYPE_AUTORELOAD_CONTIGU))
        {
            HV_W32_FIELD_EX(CPU_SYS_DMAC_CFG0_L, pstSelf->portOffset + uiChannelOffset, RELOAD_SRC, 0);
        }
        else if ((pstSelf->InitParam.transType == DMA_TYPE_LINKEDLIST_AUTORELOAD)
                || (pstSelf->InitParam.transType == DMA_TYPE_CONTIGU_AUTORELOAD))
        {
            HV_W32_FIELD_EX(CPU_SYS_DMAC_CFG0_L, pstSelf->portOffset + uiChannelOffset, RELOAD_DST, 0);
        }
        else if (pstSelf->InitParam.transType == DMA_TYPE_AUTORELOAD)
        {
            HV_W32_FIELD_EX(CPU_SYS_DMAC_CFG0_L, pstSelf->portOffset + uiChannelOffset, RELOAD_SRC, 0);
            HV_W32_FIELD_EX(CPU_SYS_DMAC_CFG0_L, pstSelf->portOffset + uiChannelOffset, RELOAD_DST, 0);
        }
    }
    if (pstSelf->InitParam.BlockNum != DMA_WORK_LOOP)
    {
        pstSelf->InitParam.BlockNum--;
    }
    else
    {
        DmaPort enDmaPort = (DmaPort)(enPortChannelNum >> DMA_PORT_BITS_MASK);
        Hv_Cal_Dma_TransCompleteCallback(enDmaPort, uiBlockIntFlag);
    }
    return;
}

static void Hv_Cal_Dma_IntBlockHandler(DmaPort enDmaPort, UINT32 uiPortOffset)
{
    UINT32 uiReadVal    = 0;
    UINT32 uiChannel    = 0;
    UINT32 uiIndex      = 0;

    DmaSelf * pstSelf  = NULL;

    uiIndex     = enDmaPort * DMA_ONE_PORT_CHANNEL_COUNT;
    uiReadVal   = HV_R32(CPU_SYS_DMAC_STATUSBLOCK + uiPortOffset);

    for (uiChannel = 0; uiChannel < 8; uiChannel++)
    {
        if (((uiReadVal >> uiChannel) & 1) == 1)
        {
            pstSelf = s_pstDma[uiIndex + uiChannel];
            Hv_Cal_Dma_BlockProcess(pstSelf, DMA_STATUS_CHANNEL0);
            HV_W32(CPU_SYS_DMAC_CLEARBLOCK + pstSelf->portOffset, (1 << uiChannel));
        }
    }
    return;
}

static HV_VOS_ISR_RESULT_E  Hv_Cal_Dma_Port0_IrqHandler(UINT32 uiIrqNum, void *pArg)
{
    HV_UNUSED(uiIrqNum);
    UINT32 uiIntStaVal = 0;
    UINT32 portOffset = 0;
    DmaSelf* pstSelf = (DmaSelf*)pArg;
    DmaPortChannel enPortChannelNum = pstSelf->InitParam.PortChannelNum;
    uiIntStaVal = HV_R32(CPU_SYS_DMAC_STATUSINT);

    if ((uiIntStaVal & DMA_FLAG_BLOCK) == DMA_FLAG_BLOCK)
    {
        Hv_Cal_Dma_IntBlockHandler(DMA_PORT_0,portOffset);
    }
    if ((uiIntStaVal & DMA_FLAG_TFR) == DMA_FLAG_TFR)
    {
        UINT32 uiReadVal = HV_R32(CPU_SYS_DMAC_STATUSTFR + portOffset);
        /* Fix multi CPU dma interrupts bug*/
        uiReadVal &= (1 << enPortChannelNum);
        HV_W32(CPU_SYS_DMAC_CLEARTFR + portOffset, uiReadVal);
        Hv_Cal_Dma_TransCompleteCallback(DMA_PORT_0,uiReadVal);
    }
    //if ((uiIntStaVal & DMA_FLAG_SRCTRAN) == DMA_FLAG_SRCTRAN)
    //{
    //}
    //if ((uiIntStaVal & DMA_FLAG_DESTTRAN) == DMA_FLAG_DESTTRAN)
    //{
    //}
    //if ((uiIntStaVal & DMA_FLAG_ERR) == DMA_FLAG_ERR)
    //{
        //HV_LOGW("Dma erro int.\n");
    //}
    return  HV_VOS_ISR_HANDLED;
}

static HV_VOS_ISR_RESULT_E  Hv_Cal_Dma_Port1_IrqHandler(UINT32 uiIrqNum, void *pArg)
{
    HV_UNUSED(uiIrqNum);
    UINT32 uiIntStaVal = 0;
    UINT32 uiReadVal = 0;
    UINT32 uiPortOffset = HV_DMAC1_BASE_ADDRESS - HV_DMAC_BASE_ADDRESS;
    DmaSelf* pstSelf = (DmaSelf*)pArg;
    DmaPortChannel enPortChannelNum = pstSelf->InitParam.PortChannelNum;

    uiIntStaVal = HV_R32(CPU_SYS_DMAC_STATUSINT + uiPortOffset);

    if ((uiIntStaVal & DMA_FLAG_BLOCK) == DMA_FLAG_BLOCK)
    {
        Hv_Cal_Dma_IntBlockHandler(DMA_PORT_1, uiPortOffset);
    }
    if ((uiIntStaVal & DMA_FLAG_TFR) == DMA_FLAG_TFR)
    {
        uiReadVal = HV_R32(CPU_SYS_DMAC_STATUSTFR + uiPortOffset);
        /* Fix multi CPU dma interrupts bug*/
        uiReadVal &= (1 << (enPortChannelNum - 8));
        HV_W32(CPU_SYS_DMAC_CLEARTFR + uiPortOffset, uiReadVal);
        Hv_Cal_Dma_TransCompleteCallback(DMA_PORT_1, uiReadVal);
    }
    //if ((uiIntStaVal & DMA_FLAG_SRCTRAN) == DMA_FLAG_SRCTRAN)
    //{
    //    ;
    //}
    //if ((uiIntStaVal & DMA_FLAG_DESTTRAN) == DMA_FLAG_DESTTRAN)
    //{
    //    ;
    //}
    //if ((uiIntStaVal & DMA_FLAG_ERR) == DMA_FLAG_ERR)
    //{
    //    ;//HV_LOGW("Dma erro int.\n");
    //}
    return  HV_VOS_ISR_HANDLED;
}


static BOOL Hv_Cal_Dma_ChannelBusyCheck(DmaSelf*  pstSelf)
{
    UINT32 uiReadVal = 0;
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    uiReadVal =  HV_R32(CPU_SYS_DMAC_CHENREG + pstSelf->portOffset);

    if ((uiReadVal & (1 << uiChannelNum)) == 1)
    {
        return (BOOL)DMA_CHANNEL_BUSY;
    }
    return DMA_CHANNEL_IDLE;
}

static UCHAR8 Hv_Cal_Dma_IdleChannelGet(DmaSelf* pstSelf)
{
    UINT32 uiReadVal  = 0;
    UCHAR8 ucLoop    = 0;
    uiReadVal =  HV_R32(CPU_SYS_DMAC_CHENREG + pstSelf->portOffset);
    for (ucLoop = 0; ucLoop < 8; ucLoop++)
    {
        if (((uiReadVal >> ucLoop) & 0x1) != 0x1)
        {
            return ucLoop;
        }
    }
    return DMA_ALL_CHANNEL_BUSY;
}

static void  Hv_Cal_Dma_ChannelRegConfig(DmaSelf*  pstSelf)
{
    DmaInitParam* InitParam = &pstSelf->InitParam;
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = DMA_CHANNEL_REG_LENGTH * uiChannelNum;

    rs_cpu_sys_dmac_ctl0_l  regCtlVal_L = {0};
    rs_cpu_sys_dmac_cfg0_l  regCfgVal_L = {0};
    rs_cpu_sys_dmac_cfg0_h  regCfgVal_H = {0};
    rs_cpu_sys_dmac_sar0    regSarVal   = {0};
    rs_cpu_sys_dmac_dar0    regDarVal   = {0};

    Hv_Cal_Dma_ChannelDis(pstSelf);
    /*Clear channel (Num) all interrupt flag*/
    Hv_Cal_Dma_IntClear(pstSelf, DMA_FLAG_TFR | DMA_FLAG_BLOCK | DMA_FLAG_SRCTRAN | DMA_FLAG_DESTTRAN | DMA_FLAG_ERR);

    regCtlVal_L.INT_EN          = DMA_INT_ENABLE;
    regCtlVal_L.SRC_TR_WIDTH    = InitParam->SrcDataSize;
    regCtlVal_L.DST_TR_WIDTH    = InitParam->DstDataSize;
    regCtlVal_L.SINC            = InitParam->Sink;
    regCtlVal_L.DINC            = InitParam->Dink;
    regCtlVal_L.SRC_GATHER_EN   = DMA_SRC_GATHER_DIS;
    regCtlVal_L.DST_SCATTER_EN  = DMA_DST_SCATTER_DIS;
    regCtlVal_L.SRC_MSIZE       = InitParam->SrcBurstSize;
    regCtlVal_L.DEST_MSIZE      = InitParam->DstBurstSize;
    regCtlVal_L.TT_FC           = InitParam->Direction;
    regCtlVal_L.SMS             = DMA_AHB_MASTER_1;         //tag_0802
    if (InitParam->masterMode == DMA_MASTER_MODE_SINGLE)
    {
        regCtlVal_L.DMS            = DMA_AHB_MASTER_1;
    }
    else
    {
        regCtlVal_L.DMS            = DMA_AHB_MASTER_2;
    }
    if (InitParam->masterMode == DMA_MASTER_MODE_ISPRAM_READ)
    {
        regCtlVal_L.SMS             = DMA_AHB_MASTER_4;
        regCtlVal_L.DMS             = DMA_AHB_MASTER_1;
    }
    if (InitParam->masterMode == DMA_MASTER_MODE_ISPRAM_WRITE)
    {
        regCtlVal_L.SMS             = DMA_AHB_MASTER_1;
        regCtlVal_L.DMS             = DMA_AHB_MASTER_4;
    }
    if (InitParam->masterMode == DMA_MASTER_MODE_DSPRAM_READ)
    {
        regCtlVal_L.SMS             = DMA_AHB_MASTER_3;
        regCtlVal_L.DMS             = DMA_AHB_MASTER_1;
    }
    if (InitParam->masterMode == DMA_MASTER_MODE_DSPRAM_WRITE)
    {
        regCtlVal_L.SMS             = DMA_AHB_MASTER_1;
        regCtlVal_L.DMS             = DMA_AHB_MASTER_3;
    }
    regCtlVal_L.LLP_DST_EN  = InitParam->DstLinkedListEn;
    regCtlVal_L.LLP_SRC_EN  = InitParam->SrcLinkedListEn;
    HV_W32_REG(CPU_SYS_DMAC_CTL0_L + pstSelf->portOffset + uiChannelOffset, regCtlVal_L);

    regCfgVal_L.CH_PRIOR    = InitParam->ChPriority;
    regCfgVal_L.RELOAD_SRC  = InitParam->SrcAutoReloadEn;
    regCfgVal_L.RELOAD_DST  = InitParam->DstAutoReloadEn;
    if ((InitParam->masterMode >= DMA_MASTER_MODE_ISPRAM_READ) && (InitParam->masterMode <= DMA_MASTER_MODE_DSPRAM_WRITE))
    {
        regCfgVal_L.MAX_ABRST   = 1;
    }
    else
    {
        regCfgVal_L.MAX_ABRST   = 0;
    }
    HV_W32_REG(CPU_SYS_DMAC_CFG0_L + pstSelf->portOffset + uiChannelOffset, regCfgVal_L);

    regCfgVal_H.SRC_PER     = InitParam->SrcInterface;
    regCfgVal_H.DEST_PER    = InitParam->DstInterface;
    regCfgVal_H.FIFO_MODE   = 1;
    if (pstSelf->InitParam.PortChannelNum>>DMA_PORT_BITS_MASK)
    {
        regCfgVal_H.FIFO_MODE = 1;
    }
    if ((InitParam->masterMode >= DMA_MASTER_MODE_ISPRAM_READ) && (InitParam->masterMode <= DMA_MASTER_MODE_DSPRAM_WRITE))
    {
        regCfgVal_H.FIFO_MODE   = 0;
    }
    HV_W32_REG(CPU_SYS_DMAC_CFG0_H + pstSelf->portOffset + uiChannelOffset, regCfgVal_H);

    regSarVal.SAR = InitParam->SrcAddr;
    HV_W32_REG(CPU_SYS_DMAC_SAR0 + pstSelf->portOffset + uiChannelOffset, regSarVal);

    regDarVal.DAR = InitParam->DstAddr;
    HV_W32_REG(CPU_SYS_DMAC_DAR0 + pstSelf->portOffset + uiChannelOffset, regDarVal);
    return;
}



DmaSelf* Hv_Cal_Dma_MallocDma(DmaInitParam* InitParam)
{
    DmaPort enDmaPort = (DmaPort)(InitParam->PortChannelNum >> DMA_PORT_BITS_MASK);
    DmaPortChannel index = InitParam->PortChannelNum;
    static BOOL bDma0IsOpen = HV_FALSE;
    static BOOL bDma1IsOpen = HV_FALSE;

    if (s_pstDma[index] == NULL)
    {
        s_pstDma[index] = HV_MALLOC_OBJECT(DmaSelf);
    }

    if (enDmaPort == DMA_PORT_0)
    {
        s_pstDma[index]->portOffset = 0;
        if (bDma0IsOpen == HV_FALSE)
        {
            HV_W32_FIELD_EX(CPU_SYS_DMACFGREG, s_pstDma[index]->portOffset, DMA_EN, 1);
            bDma0IsOpen = HV_TRUE;
        }
    }
    else
    {
        s_pstDma[index]->portOffset = HV_DMAC1_BASE_ADDRESS - HV_DMAC_BASE_ADDRESS;
        if (bDma1IsOpen == HV_FALSE)
        {
            HV_W32_FIELD_EX(CPU_SYS_DMACFGREG, s_pstDma[index]->portOffset, DMA_EN, 1);
            bDma1IsOpen = HV_TRUE;
        }
    }

    return s_pstDma[index];
}

static DmaSelf* Hv_Cal_Dma_ChannelConfig(DmaInitParam* InitParam)
{
    BOOL bRet = 0;
    static BOOL dmaIsOpen = HV_FALSE;
    DmaSelf* pstSelf = Hv_Cal_Dma_MallocDma(InitParam);

    HV_MEMCPY(&pstSelf->InitParam, InitParam, sizeof(*InitParam));
    bRet = Hv_Cal_Dma_ChannelBusyCheck(pstSelf);
    if (bRet == (BOOL)DMA_CHANNEL_BUSY)
    {
        UCHAR8 idleChannel = Hv_Cal_Dma_IdleChannelGet(pstSelf);
        if(idleChannel == DMA_ALL_CHANNEL_BUSY)
        {
            return NULL;
        }
        else
        {
            InitParam->PortChannelNum = (DmaPortChannel)idleChannel;
            pstSelf = Hv_Cal_Dma_MallocDma(InitParam);
            HV_MEMCPY(&pstSelf->InitParam, InitParam, sizeof(*InitParam));
        }
    }
    DMA_CHANNEL_IrqAttach(pstSelf);
    Hv_Cal_Dma_ChannelRegConfig(pstSelf);
    return pstSelf;
}

void Hv_Cal_Dma_SetParent(DmaSelf* pstSelf, void* pParent)
{
    pstSelf->parent = pParent;
    return;
}

void* Hv_Cal_Dma_GetParent(DmaSelf* pstSelf)
{
    return pstSelf->parent;
}

DmaPortChannel Hv_Cal_Dma_GetPortChannelNum(DmaSelf* pstSelf)
{
    return pstSelf->InitParam.PortChannelNum;
}

Status Hv_Cal_Dma_WaitTfrFlag(DmaSelf* pstSelf)
{

    UINT32 uiRet = Hv_Cal_Dma_WaitOnFlagUntilTimeout(pstSelf, DMA_FLAG_TFR, DMA_TIMEOUT);
    if (uiRet == HV_SUCCESS)
    {
        Hv_Cal_Dma_IntClear(pstSelf,DMA_FLAG_TFR);
        return HV_SUCCESS;
    }
    else
    {
        HV_LOGW("Dma Wait Tfr uiFlag uiTimeout.\n");
        return HV_FAILURE;
    }
}

/** @brief 当多个src拼接到一个dst时，每个src和dst均是连续的。创建到一个LLC，启动一次dma传输。最后一个src的最后一个block结束传输。
 *  @param linkedListStem linklist to setup.
 *  @param SrcAddr srcaddr to move
 *  @param DstAddr DstAddr to move
 *  @param SrcSize total size to move
 *  @param uiLast whether the last src to transfer
 */
Status Hv_Cal_Dma_LLIbuild_BothContinous(DmaLinkedList* pstLinkedListStem, UINT32 uiSrcAddr, UINT32 uiDstAddr, UINT32 uiSrcSize, UINT32 uiLast)
{
    UINT32 uiLoop = 0;
    UINT32 StemSrcAddrOffset = 0;
    UINT32 StemDstAddrOffset = 0;
    DmaLinkedList* pstLinkedList = NULL;
    UINT32 uiBlockNum = 0;
    UINT32 uiLastSize = 0;
    UINT32 uiBlockSize = DMA_MEM_BLOCK_SIZE ;
    UINT32 uiDmaCtrl0 = 0;
    rs_cpu_sys_dmac_ctl0_l rCtrlValue = {0};

    uiBlockNum = uiSrcSize / uiBlockSize;
    uiLastSize = uiSrcSize % uiBlockSize;
    pstLinkedList = pstLinkedListStem;

    if (uiLastSize)
    {
        uiBlockNum++;
    }
    HV_LOGV("Hv_Cal_Dma_LLIbuild_BothContinous address %x, size %x, num %d!\n", uiSrcAddr, uiSrcSize, uiBlockNum);
    for (uiLoop = 0; uiLoop < uiBlockNum; uiLoop++)
    {
        StemSrcAddrOffset = uiBlockSize * uiLoop;
        pstLinkedList[uiLoop].SrcAddr = VIRT_TO_PHY(uiSrcAddr + StemSrcAddrOffset);
        pstLinkedList[uiLoop].DstAddr = VIRT_TO_PHY(uiDstAddr);


        /* 4837: 64bit 4825: 32bit 4813: 16bit 4801: 8bit */
        if (uiLoop == uiBlockNum -1)
        {
            if (uiLastSize)
            {
                uiBlockSize = uiLastSize;
            }
        }
        /* set BLOCK_TS */
        pstLinkedList[uiLoop].CtrlVal_H = uiBlockSize >> 2;

        rCtrlValue.INT_EN       = 1;
        /* dest width 32bits */
        rCtrlValue.DST_TR_WIDTH = 2;
        /* src width 32bits */
        rCtrlValue.SRC_TR_WIDTH = 2;
        /* dest burst 4 */
        rCtrlValue.DEST_MSIZE   = 1;
        /* src burst 4 */
        rCtrlValue.SRC_MSIZE    = 1;
        /* the last transfer */
        if ((uiLoop == uiBlockNum -1) && (uiLast))
        {
            pstLinkedList[uiLoop].NextLinkedListAddr = 0;
        }
        else
        {
            /* src llp enable */
            rCtrlValue.LLP_SRC_EN  = 1;
            pstLinkedList[uiLoop].NextLinkedListAddr = VIRT_TO_PHY((UINT32)&pstLinkedList[uiLoop+1]);
        }
        pstLinkedList[uiLoop].CtrlVal_L = HV_REG_VAL(rCtrlValue);
    }

    for (uiLoop = 0; uiLoop < uiBlockNum; uiLoop++)
    {

        HV_LOGV(" %x, %x, %x, %x, %x\n",
        pstLinkedList[uiLoop].SrcAddr, pstLinkedList[uiLoop].DstAddr,
        pstLinkedList[uiLoop].CtrlVal_H, pstLinkedList[uiLoop].CtrlVal_L,
        pstLinkedList[uiLoop].NextLinkedListAddr);
    }
    return HV_SUCCESS;
}

/** @brief Set the frame data transfer size of source
 *  @pstSelf channelparam no.
 *  @param enFrameVal transfer data size
 */
void Hv_Cal_Dma_SetSrcFrameSize(DmaSelf* pstSelf, DmaDataSize enFrameVal)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    pstSelf->InitParam.SrcDataSize = enFrameVal;
    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L , pstSelf->portOffset + uiChannelOffset, SRC_TR_WIDTH, enFrameVal);
    return;
}

/** @brief Set the frame data transfer size of destination
 *  @pstSelf channelparam no.
 *  @param enFrameVal transfer data size
 */
void Hv_Cal_Dma_SetDstFrameSize(DmaSelf* pstSelf, DmaDataSize enFrameVal)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    pstSelf->InitParam.DstDataSize = enFrameVal;
    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L, pstSelf->portOffset + uiChannelOffset, DST_TR_WIDTH, enFrameVal);
    return;
}

/** @brief Set the dma source address
 *  @pstSelf channelparam no.
 *  @param SrcAddr source address
 */
void Hv_Cal_Dma_SetSrcAddr(DmaSelf* pstSelf, UINT32 uiSrcAddr)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    UINT32 SrcPhyAddr;
    Hv_Cal_Dma_ChannelDis(pstSelf);
    SrcPhyAddr = VIRT_TO_PHY(uiSrcAddr);
    HV_W32_FIELD_EX(CPU_SYS_DMAC_SAR0, pstSelf->portOffset + uiChannelOffset, SAR, SrcPhyAddr);
    pstSelf->InitParam.SrcAddr = uiSrcAddr;
    return;
}

/** @brief Set the dma destination address
 *  @pstSelf channelparam no.
 *  @param DstAddr destination address
 */
void Hv_Cal_Dma_SetDstAddr(DmaSelf* pstSelf, UINT32 uiDstAddr)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    UINT32 DstPhyAddr = VIRT_TO_PHY(uiDstAddr);
    Hv_Cal_Dma_ChannelDis(pstSelf);
    HV_W32_FIELD_EX(CPU_SYS_DMAC_DAR0, pstSelf->portOffset + uiChannelOffset, DAR, DstPhyAddr);
    pstSelf->InitParam.DstAddr = uiDstAddr;
    return;
}

/** @brief Set the dma block transfer size
 *  @pstSelf channelparam no.
 *  @param BlockSize size of block
 */
void Hv_Cal_Dma_SetBlockSize(DmaSelf* pstSelf,UINT32 uiBlockSize)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_H, pstSelf->portOffset + uiChannelOffset, BLOCK_TS, uiBlockSize);
    return;
}

/** @brief Set the source address increment mode
 *  @pstSelf channelparam no.
 *  @param enAddrChangeMode increment mode
 */
void Hv_Cal_Dma_SetSrcAddrMode(DmaSelf* pstSelf,DmaSink enAddrChangeMode)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    pstSelf->InitParam.Sink = enAddrChangeMode;
    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L, pstSelf->portOffset + uiChannelOffset, SINC, enAddrChangeMode);
    return;
}

/** @brief Set the destination address increment mode
 *  @pstSelf channelparam no.
 *  @param enAddrChangeMode increment mode
 */
void Hv_Cal_Dma_SetDstAddrMode(DmaSelf* pstSelf,DmaDink enAddrChangeMode)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    pstSelf->InitParam.Dink = enAddrChangeMode;
    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L, pstSelf->portOffset + uiChannelOffset, DINC, enAddrChangeMode);
    return;
}

/** @brief Set the source burst transaction length
 *  @pstSelf channelparam no.
 *  @param uiBurstSize burst size
 */
void Hv_Cal_Dma_SetSrcBurstSize(DmaSelf* pstSelf, DmaBurstSize uiBurstSize)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    pstSelf->InitParam.SrcBurstSize = uiBurstSize;
    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L, pstSelf->portOffset + uiChannelOffset, SRC_MSIZE, uiBurstSize);
    return;
}

/** @brief Set the destination burst transaction length
 *  @pstSelf channelparam no.
 *  @param uiBurstSize burst size
 */
void Hv_Cal_Dma_SetDstBurstSize(DmaSelf* pstSelf, DmaBurstSize uiBurstSize)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

     pstSelf->InitParam.DstBurstSize = uiBurstSize;
    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L, pstSelf->portOffset + uiChannelOffset, DEST_MSIZE, uiBurstSize);
    return;
}

/** @brief Set the source master select
 *  @pstSelf channelparam no.
 *  @param AHBLayer sms selection, such as AHB master 1/2/3/4
 */
void Hv_Cal_Dma_SetSrcLayer(DmaSelf* pstSelf, DmaAhbSelect AHBLayer)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L, pstSelf->portOffset + uiChannelOffset, SMS, AHBLayer);
    return;
}

/** @brief Set the destination master select
 *  @pstSelf channelparam no.
 *  @param AHBLayer sms selection, such as AHB master 1/2/3/4
 */
void Hv_Cal_Dma_SetDstLayer(DmaSelf* pstSelf,DmaAhbSelect AHBLayer)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L, pstSelf->portOffset + uiChannelOffset, DMS, AHBLayer);
    return;
}

/** @brief Set the FIFO mode select
 *  @pstSelf channelparam no.
 *  @param enFifoMode 0x0(FIFO_MODE_0), 0x1(FIFO_MODE_1)
 */
void Hv_Cal_Dma_SetFifoMode(DmaSelf* pstSelf, DmaFifoMode enFifoMode)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    HV_W32_FIELD_EX(CPU_SYS_DMAC_CFG0_H, pstSelf->portOffset + uiChannelOffset, FIFO_MODE, enFifoMode);
    return;
}

/** @brief Set the address of next linked list item
 *  @pstSelf channelparam no.
 *  @param pstLinkedListStemAddr starting address in memory of next Link List Item if block chaining is enabled
 */
void Hv_Cal_Dma_SetLinkedListAddr(DmaSelf* pstSelf, DmaLinkedList* pstLinkedListStemAddr)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    rs_cpu_sys_dmac_llp0  regLlpVal = {0};
    UINT32 linkedListPhyAddr = 0;

    Hv_Cal_Dma_ChannelDis(pstSelf);
    linkedListPhyAddr = VIRT_TO_PHY((UINT32)pstLinkedListStemAddr);
    regLlpVal.LMS = DMA_AHB_MASTER_1;
    regLlpVal.LOC = (UINT32)linkedListPhyAddr >> 2;
    HV_W32_REG(CPU_SYS_DMAC_LLP0 + pstSelf->portOffset + uiChannelOffset, regLlpVal);

    if (pstSelf->InitParam.SrcLinkedListEn == DMA_LINKED_LIST_EN)
    {
        HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L , pstSelf->portOffset + uiChannelOffset, LLP_SRC_EN, 1);
    }
    if (pstSelf->InitParam.DstLinkedListEn == DMA_LINKED_LIST_EN)
    {
        HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L , pstSelf->portOffset + uiChannelOffset, LLP_DST_EN, 1);
    }
    return;
}

/** @brief Set the source gather parameters, includes en, interval, count
 *  @pstSelf channelparam no.
 *  @param pstGather pointer to source gather structure
 */
void Hv_Cal_Dma_SetSrcGatherParam(DmaSelf* pstSelf, DmaSrcGather* pstGather)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    UINT32 valSrc = 1 << pstSelf->InitParam.SrcDataSize;
    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L, pstSelf->portOffset + uiChannelOffset, SRC_GATHER_EN, pstGather->SrcGatherEn);
    HV_W32_FIELD_EX(CPU_SYS_DMAC_SGR0, pstSelf->portOffset + uiChannelOffset, SGI, pstGather->SrcGatherInterval/valSrc);
    HV_W32_FIELD_EX(CPU_SYS_DMAC_SGR0, pstSelf->portOffset + uiChannelOffset, SGC, pstGather->SrcGatherCount/valSrc);
    return;
}

/** @brief Set the destination scatter parameters, includes en, interval, count
 *  @pstSelf channelparam no.
 *  @param pstScatter pointer to destination scatter structure
 */
void Hv_Cal_Dma_SetDstScatterParam(DmaSelf* pstSelf, DmaDstScatter* pstScatter)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChannelOffset = uiChannelNum * DMA_CHANNEL_REG_LENGTH;
    Hv_Cal_Dma_ChannelDis(pstSelf);

    UINT32 valDst = 1 << pstSelf->InitParam.DstDataSize;
    HV_W32_FIELD_EX(CPU_SYS_DMAC_CTL0_L, pstSelf->portOffset + uiChannelOffset, DST_SCATTER_EN, pstScatter->DstScatterEn);
    HV_W32_FIELD_EX(CPU_SYS_DMAC_DSR0, pstSelf->portOffset + uiChannelOffset, DGI, pstScatter->DstScatterInterval/valDst);
    HV_W32_FIELD_EX(CPU_SYS_DMAC_DSR0, pstSelf->portOffset + uiChannelOffset, DGC, pstScatter->DstScatterCount/valDst);
    return;
}

/** @brief Bond the memory move complete callback
 *  @pstSelf channelparam no.
 *  @param CallbackFunc user defined callback fn.
 */
void Hv_Cal_Dma_XferCallbackBond(DmaSelf* pstSelf, void* CallbackFunc)
{
    pstSelf->InitParam.XferCpltCallback = (XferCpltCallbackType)CallbackFunc;
    return;
}

/** @brief Unbond the transfer complete callback
 *  @pstSelf channelparam no.
 *  @param CallbackFunc user defined callback fn.
 */
void Hv_Cal_Dma_XferCallbackUnBond(DmaSelf* pstSelf)
{
    pstSelf->InitParam.XferCpltCallback = NULL;
    return;
}

/** Enable the designated DMA channel
 *  @param  PortChannelNum channel number
 */
void Hv_Cal_Dma_ChannelEn(DmaSelf*  pstSelf)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChEnVal = 0;

    Hv_Vos_InvalidAllDCache();
    uiChEnVal = HV_R32(CPU_SYS_DMAC_CHENREG + pstSelf->portOffset);
    uiChEnVal |= (1 << (uiChannelNum + 8));
    uiChEnVal |= (1 <<  uiChannelNum);
    HV_W32(CPU_SYS_DMAC_CHENREG + pstSelf->portOffset, uiChEnVal);
    return;
}

/** Disable the designated DMA channel
 *  @param  PortChannelNum channel number
 */
void Hv_Cal_Dma_ChannelDis(DmaSelf*  pstSelf)
{
    UINT32 uiChannelNum = pstSelf->InitParam.PortChannelNum & DMA_CHANNEL_MASK;
    UINT32 uiChEnVal = 0;

    uiChEnVal = HV_R32(CPU_SYS_DMAC_CHENREG + pstSelf->portOffset);
    uiChEnVal &= (0 << uiChannelNum);
    uiChEnVal |= (1 << (uiChannelNum + 8));
    HV_W32(CPU_SYS_DMAC_CHENREG + pstSelf->portOffset, uiChEnVal);
    return;
}

/** Configure the designated DMA channel
 *  @param  chCfgParam pointer to channel configuration parameters
 *  @param  isMemToMem is or not mem to mem
 *  @retval worked channel number
 */
DmaSelf* Hv_Cal_Dma_ChannelInit(DmaInitParam* InitParam)
{
    DmaSelf* pstSelf = NULL;
    DmaPort enDmaPort = (DmaPort)(InitParam->PortChannelNum >> DMA_PORT_BITS_MASK);

    if (enDmaPort == DMA_PORT_0)
    {
        Hv_Cal_Dma_InterfaceAttribute(InitParam);
        Hv_Cal_Dma_TransTypeAttribute(InitParam);
        Hv_Cal_Dma_DirectionAttribute(InitParam);
        Hv_Cal_Dma_DataSizeAttribute(InitParam);
        Hv_Cal_Dma_BurstSizeAttribute(InitParam);
    }
    else if (enDmaPort == DMA_PORT_1)
    {
        InitParam->Sink = DMA_SINK_INCREASE;
        InitParam->Dink = DMA_DINK_INCREASE;
        InitParam->SrcDataSize = DMA_DATA_SIZE_64Bits;
        InitParam->DstDataSize = DMA_DATA_SIZE_64Bits;

        Hv_Cal_Dma_TransTypeAttribute(InitParam);
    }
    pstSelf = Hv_Cal_Dma_ChannelConfig(InitParam);
    if (pstSelf == NULL)
    {
        return NULL;
    }
    Hv_Cal_Dma_IntEn(pstSelf, DMA_FLAG_TFR);
    if ((InitParam->transType & DMA_TYPE_AUTORELOAD_MASK) == DMA_TYPE_AUTORELOAD_MASK)
    {
        Hv_Cal_Dma_IntEn(pstSelf,DMA_FLAG_BLOCK);
    }
    return pstSelf;
}

BOOL Hv_Cal_Dma_Port1LinkedListStemBuild(DmaLinkedList* linkedListStem,UINT32 SrcAddr,UINT32 DstAddr, UINT32 SrcAddrOffset, UINT32 DstAddrOffset, UINT32 ConfigType, UINT32 BlockNum, UINT32 OneBlockSize,UINT32 LastBlockSize) {

    UINT32  i = 0;
    UINT32 StemSrcAddrOffset = 0;
    UINT32 StemDstAddrOffset = 0;
    DmaLinkedList* linkedList;
    UCHAR8 linkedListStructSize = 0;
    linkedList = linkedListStem;

    for(i = 0; i < BlockNum ; i++) 
    {
        StemSrcAddrOffset = SrcAddrOffset * i;
        StemDstAddrOffset = DstAddrOffset * i;

        if(ConfigType == DMA_SRC_CONFIF) 
        {
            linkedList[i].SrcAddr = VIRT_TO_PHY(SrcAddr + StemSrcAddrOffset);
            linkedList[i].DstAddr = VIRT_TO_PHY(DstAddr);
        } 
        else if(ConfigType == DMA_DST_CONFIF) 
        {
            linkedList[i].SrcAddr = VIRT_TO_PHY(SrcAddr);
            linkedList[i].DstAddr = VIRT_TO_PHY(DstAddr + StemDstAddrOffset);
        } 
        else if(ConfigType == DMA_BOTH_CONFIF) 
        {
            linkedList[i].SrcAddr = VIRT_TO_PHY(SrcAddr + StemSrcAddrOffset);
            linkedList[i].DstAddr = VIRT_TO_PHY(DstAddr + StemDstAddrOffset);
        }

        // 4837: 64bit
        // 4825: 32bit
        // 4813: 16bit
        // 4801: 8bit
        if(i != (BlockNum - 1)) 
        {
            if(ConfigType == DMA_SRC_CONFIF) 
            {
                linkedList[i].CtrlVal_L = 0x10004825;
            } 
            else if(ConfigType == DMA_DST_CONFIF) 
            {
                linkedList[i].CtrlVal_L = 0x8004825;
            } 
            else if(ConfigType == DMA_BOTH_CONFIF) 
            {
                linkedList[i].CtrlVal_L = 0x18004825;
            }
            linkedList[i].CtrlVal_H = OneBlockSize>>2;
            linkedList[i].NextLinkedListAddr = VIRT_TO_PHY((UINT32)&linkedListStem[i+1]);
        } 
        else 
        {
            linkedList[i].CtrlVal_L = 0x4825;
            linkedList[i].CtrlVal_H = LastBlockSize>>2;
            linkedList[i].NextLinkedListAddr = 0;
        }
    }
    return HV_TRUE;
}

/** Start the dma memory move
 *  @pstSelf channelparam number
 *  @param  SrcAddr source address
 *  @param  DstAddr destination address
 *  @param  uiBlockSize block size
 */
void Hv_Cal_Dma_MemMove(DmaSelf* pstSelf, UINT32 uiSrcAddr, UINT32 uiDstAddr, UINT32 uiDataSize)
{
    DmaPort enDmaPort = (DmaPort)(pstSelf->InitParam.PortChannelNum >> DMA_PORT_BITS_MASK);
    UINT32 uiBlockSize = 0;

    Hv_Cal_Dma_SetSrcAddr(pstSelf, uiSrcAddr);
    Hv_Cal_Dma_SetDstAddr(pstSelf, uiDstAddr);
    if (enDmaPort == DMA_PORT_0)
    {
        HV_ASSERT((uiDataSize & 0x03)== 0);
        uiBlockSize = uiDataSize >> pstSelf->InitParam.SrcDataSize;;
    }
    else if (enDmaPort == DMA_PORT_1)
    {
        HV_ASSERT((uiDataSize & 0x07)== 0);
        uiBlockSize = uiDataSize >> pstSelf->InitParam.SrcDataSize;;
    }
    Hv_Cal_Dma_SetBlockSize(pstSelf, uiBlockSize);
    pstSelf->TransCompleteFlag = DMA_TRANS_IN_PROCESS;
    Hv_Cal_Dma_ChannelEn(pstSelf);
    return;
}

/** dma is complete or not
 *  @pstSelf channelparam number
 */
BOOL Hv_Cal_Dma_TransferIsComplete(DmaSelf *pstSelf)
{
    if (pstSelf->TransCompleteFlag == DMA_TRANS_IN_PROCESS)
    {
        return HV_FALSE;
    }
    else if (pstSelf->TransCompleteFlag == DMA_TRANS_END)
    {
        return HV_TRUE;
    }
    return HV_FALSE;
}

/** De-initializes the DMA module.
 *  @param  pstSelf dma handler
 */
void Hv_Cal_Dma_CleanUp(DmaSelf* pstSelf)
{
    DMA_CHANNEL_IrqUnAttach(pstSelf);
    return;
}


