/**
* @file         dev_dmac.c
* @brief        XXX
* @details      XXX
* @author       Ϳ��
* @date         2021-07-07 11:14
* @version      V0.0
* @copyright    Copyright (c) 2017-2021  SpaceTouch Inc.
*/

//channel: 0-7

#include "platform.h"

void DMA_Config(uint32_t channelx, dma_config_parameter_t *dma_config_struct)
{
    uint32_t src_addr_HSB, dst_addr_HSB;
    src_addr_HSB = dma_config_struct->src_start_addr >> 24;
    dst_addr_HSB = dma_config_struct->dst_start_addr >> 24;
    DEV_DMAC->DMA_CHN[channelx].SSA = dma_config_struct->src_start_addr;//ַ
    DEV_DMAC->DMA_CHN[channelx].SOA = DEV_DMAC_DMA_CHNn_SOA_SRC_SLOT_OFFSET(dma_config_struct->src_slot_offset)
                                      | DEV_DMAC_DMA_CHNn_SOA_SRC_WORD_OFFSET(dma_config_struct->src_word_offset);
    DEV_DMAC->DMA_CHN[channelx].DSA = dma_config_struct->dst_start_addr;//ַ
    DEV_DMAC->DMA_CHN[channelx].DOA = DEV_DMAC_DMA_CHNn_DOA_DST_SLOT_OFFSET(dma_config_struct->dst_slot_offset)
                                      | DEV_DMAC_DMA_CHNn_DOA_DST_WORD_OFFSET(dma_config_struct->dst_word_offset);
    DEV_DMAC->DMA_CHN[channelx].CFG = dma_config_struct->src_width << 10
                                      | dma_config_struct->src_dls << 9
                                      | (dma_config_struct->src_ifs << 4)
                                      | dma_config_struct->src_burst_len << 2
                                      | dma_config_struct->src_addr_type << 1
                                      | dma_config_struct->src_slave
                                      | dma_config_struct->reload_en << 15
                                      | dma_config_struct->priority << 12
                                      | dma_config_struct->dst_width << 26
                                      | dma_config_struct->dst_dls << 25
                                      | (dma_config_struct->dst_ifs << 20)
                                      | dma_config_struct->dst_burst_len << 18
                                      | dma_config_struct->dst_addr_type << 17
                                      | dma_config_struct->dst_slave << 16;
    DEV_DMAC->DMA_CHN[channelx].LEN =  DEV_DMAC_DMA_CHNn_LEN_SLOT_NUM(dma_config_struct->slot_num) //
                                       | DEV_DMAC_DMA_CHNn_LEN_BYTE_NUM(dma_config_struct->byte_num) ; //

    //CCTL
    if ((src_addr_HSB == 0x40UL) || (src_addr_HSB == 0x50UL))
    {
        //write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_WB_ALL);
        write_csr(NDS_MCCTLCOMMAND, 7UL);
    }

    if ((dst_addr_HSB == 0x40UL) || (dst_addr_HSB == 0x50UL))
    {
        //write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_INVAL_ALL);
        write_csr(NDS_MCCTLCOMMAND, 23UL);
    }
}




void DMA_Cmd(uint32_t channelx, uint32_t state)
{
    if (state != DISABLE)
    {
        DEV_DMAC->DMA_EN = (1UL << (channelx)) | (1UL << (channelx + 16));
    }
    else
    {
        DEV_DMAC->DMA_EN = (1UL << (channelx + 16));
    }
}

uint32_t DMA_GetCmdStatus(uint32_t channelx)
{
    return (DEV_DMAC->DMA_EN & (1UL << (channelx))) >> channelx;
}


void DMA_ITConfig(uint32_t channelx, uint32_t it_type, uint32_t state)
{
    if (state != DISABLE)
    {
        DEV_DMAC->DMA_IE |= it_type << channelx;
    }
    else
    {
        DEV_DMAC->DMA_IE &= ~(it_type << channelx);
    }
}

uint32_t DMA_GetITStatus(uint32_t channelx, uint32_t it_type)
{
    return (DEV_DMAC->DMA_PD & (it_type << (channelx))) ? SET : RESET;
}
void DMA_ClearITPendingBit(uint32_t channelx, uint32_t it_type)
{
    DEV_DMAC->DMA_PD = it_type << channelx;
}

void DMA_DMAPause(uint32_t channelx, uint32_t state)
{
    if (state != DISABLE)
    {
        DEV_DMAC->DMA_CHN[channelx].CFG |= DEV_DMAC_DMA_CHNn_CFG_PAUSE_MASK;
    }
    else
    {
        DEV_DMAC->DMA_CHN[channelx].CFG &= ~DEV_DMAC_DMA_CHNn_CFG_PAUSE_MASK;
    }
}

void DMA_SetSourceAddr(uint32_t channelx, uint32_t addr)
{
    uint32_t addr_HSB;
    addr_HSB = addr >> 24;
    DEV_DMAC->DMA_CHN[channelx].SSA = addr;

    if ((addr_HSB == 0x40UL) || (addr_HSB == 0x50UL))
    {
        //write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_WB_ALL);
        write_csr(NDS_MCCTLCOMMAND, 7UL);
    }
}
uint32_t DMA_GetSourceAddr(uint32_t channelx)
{
    return DEV_DMAC->DMA_CHN[channelx].SSA;
}

void DMA_SetDestinationAddr(uint32_t channelx, uint32_t addr)
{
    uint32_t addr_HSB;
    addr_HSB = addr >> 24;
    DEV_DMAC->DMA_CHN[channelx].DSA = addr;

    if ((addr_HSB == 0x40UL) || (addr_HSB == 0x50UL))
    {
        //write_csr(NDS_MCCTLCOMMAND, CCTL_L1D_INVAL_ALL);
        write_csr(NDS_MCCTLCOMMAND, 23UL);
    }
}
uint32_t DMA_GetDestinationAddr(uint32_t channelx)
{
    return DEV_DMAC->DMA_CHN[channelx].DSA;
}

void DMA_SetSourceBurstLength(uint32_t channelx, uint32_t BurstLength)
{
    DEV_DMAC->DMA_CHN[channelx].CFG &= ~DEV_DMAC_DMA_CHNn_CFG_SRC_BURST_LEN_MASK;
    DEV_DMAC->DMA_CHN[channelx].CFG |= BurstLength << 2;
}

void DMA_SetDestinationBurstLength(uint32_t channelx, uint32_t BurstLength)
{
    DEV_DMAC->DMA_CHN[channelx].CFG &= ~DEV_DMAC_DMA_CHNn_CFG_DST_BURST_LEN_MASK;
    DEV_DMAC->DMA_CHN[channelx].CFG |= BurstLength << 18;
}

void DMA_SetSourceDataWidth(uint32_t channelx, uint32_t DataWidth)
{
    DEV_DMAC->DMA_CHN[channelx].CFG &= ~DEV_DMAC_DMA_CHNn_CFG_SRC_WIDTH_MASK;
    DEV_DMAC->DMA_CHN[channelx].CFG |= DataWidth << 10;
}

void DMA_SetDestinationDataWidth(uint32_t channelx, uint32_t DataWidth)
{
    DEV_DMAC->DMA_CHN[channelx].CFG &= ~DEV_DMAC_DMA_CHNn_CFG_DST_WIDTH_MASK;
    DEV_DMAC->DMA_CHN[channelx].CFG |= DataWidth << 26;
}

void DMA_SetSourceSlotOffset(uint32_t channelx, uint32_t SlotOffset)
{
    DEV_DMAC->DMA_CHN[channelx].SOA &= ~DEV_DMAC_DMA_CHNn_SOA_SRC_SLOT_OFFSET_MASK;
    DEV_DMAC->DMA_CHN[channelx].SOA |= DEV_DMAC_DMA_CHNn_SOA_SRC_SLOT_OFFSET(SlotOffset);
}

void DMA_SetSourceWordOffset(uint32_t channelx, uint32_t WordOffset)
{
    DEV_DMAC->DMA_CHN[channelx].SOA &= ~DEV_DMAC_DMA_CHNn_SOA_SRC_WORD_OFFSET_MASK;
    DEV_DMAC->DMA_CHN[channelx].SOA |= DEV_DMAC_DMA_CHNn_SOA_SRC_WORD_OFFSET(WordOffset);
}

void DMA_SetDestinationSlotOffset(uint32_t channelx, uint32_t SlotOffset)
{
    DEV_DMAC->DMA_CHN[channelx].DOA &= ~DEV_DMAC_DMA_CHNn_DOA_DST_SLOT_OFFSET_MASK;
    DEV_DMAC->DMA_CHN[channelx].DOA |= DEV_DMAC_DMA_CHNn_DOA_DST_SLOT_OFFSET(SlotOffset);
}

void DMA_SetDestinationWordOffset(uint32_t channelx, uint32_t WordOffset)
{
    DEV_DMAC->DMA_CHN[channelx].DOA &= ~DEV_DMAC_DMA_CHNn_DOA_DST_WORD_OFFSET_MASK;
    DEV_DMAC->DMA_CHN[channelx].DOA |= DEV_DMAC_DMA_CHNn_DOA_DST_WORD_OFFSET(WordOffset);
}

void DMA_SetSlotNum(uint32_t channelx, uint32_t SlotNum)
{
    DEV_DMAC->DMA_CHN[channelx].LEN &= ~DEV_DMAC_DMA_CHNn_LEN_SLOT_NUM_MASK;
    DEV_DMAC->DMA_CHN[channelx].LEN |= DEV_DMAC_DMA_CHNn_LEN_SLOT_NUM(SlotNum);
}

uint16_t DMA_GetSlotNum(uint32_t channelx)
{
    return DEV_DMAC->DMA_CHN[channelx].STA >> 16;
}

void DMA_SetByteNum(uint32_t channelx, uint32_t ByteNum)
{
    DEV_DMAC->DMA_CHN[channelx].LEN &= ~DEV_DMAC_DMA_CHNn_LEN_BYTE_NUM_MASK;
    DEV_DMAC->DMA_CHN[channelx].LEN |= DEV_DMAC_DMA_CHNn_LEN_BYTE_NUM(ByteNum);
}

uint16_t DMA_GetByteNum(uint32_t channelx)
{
    return DEV_DMAC->DMA_CHN[channelx].STA & DEV_DMAC_DMA_CHNn_STA_RMN_BYTE_CNT_MASK;
}
