#include "pdma.h"

pdma_mem_channel* get_pdma_dev(int dma_id)
{
	if(dma_id < 0 || dma_id > 7)
	{
		return 0;
	}
	return &(_MemCh[dma_id]);
}

int pdma_configure(int dma_id, void * dst, const void * src, int size)
{
    if(size <= 0) return 0;

    if (dma_id <0 || dma_id >7) return 0;

    pdma_mem_channel* dma_ch = get_pdma_dev(dma_id);
    if (dma_ch == 0) return 0;

    if (ChEnReg & (1<<dma_id)) return 0;

    dma_ch->SAR = (unsigned)src;
    dma_ch->DAR = (unsigned)dst;
    unsigned long long size_shifted = size>>2;
    size_shifted = size_shifted<<32;
    dma_ch->CTL = size_shifted | 0x4824;
    DmaCfgReg = 1;
    return 1;
}

int pdma_run(int dma_id)
{
    ChEnReg |= (1<<dma_id) | (1<<(dma_id+8));
    return 1;
}

int pdma_wait(int dma_id)
{
    while(1)
    {
      int is_run = ChEnReg&(1<<dma_id);
      if (!is_run) break;
    }
    return 1;
}

int pdma_copy(unsigned int dma_id, void * dst, const void * src, unsigned int size)
{
    int n_blocks = 0;
    unsigned int current_shift = 0;
    int i = 0;
    int size_w = size>>2;

    n_blocks = size_w/PDMA_MAX_BLOCK_SIZE;

    unsigned int src_t, dst_t;

    for (i=0;i<n_blocks;i++)
    {
        current_shift = (i*PDMA_MAX_BLOCK_SIZE*4);
        dst_t = (unsigned int)dst + current_shift;
        src_t = (unsigned int)src + current_shift;
        if(pdma_configure(dma_id, (void*)(dst_t), (void*)(src_t), PDMA_MAX_BLOCK_SIZE*4))
        {
            pdma_run(dma_id);
            pdma_wait(dma_id);
        }
        else return 0;
    }

    if ((size_w%PDMA_MAX_BLOCK_SIZE)!=0)
    {
        current_shift = (n_blocks*PDMA_MAX_BLOCK_SIZE*4);
        dst_t = (unsigned int)dst + current_shift;
        src_t = (unsigned int)src + current_shift;
        int wsize =  (size_w%PDMA_MAX_BLOCK_SIZE)<<2;
        if(pdma_configure(dma_id, (void*)(dst_t), (void*)(src_t), wsize))
        {
            pdma_run(dma_id);
            pdma_wait(dma_id);
        }
        else return 0;
    }

    return 1;
}

pdma_mem_chain * pdma_fill_link(pdma_mem_chain *link, void * dst, void * src, unsigned int size, unsigned int llp_en)
{
    link->DAR = (unsigned int)dst;
    link->SAR = (unsigned int)src;
    link->LLP = (unsigned int)(link+1);
    unsigned long long size_shifted = size>>2;
    size_shifted = size_shifted<<32;
    link->CTL = size_shifted | 0x4824;
    if (llp_en == 1) link->CTL |= 0x18000000;
}

int pdma_start_chain(int dma_id, pdma_mem_chain *link)
{
    pdma_mem_channel* dma_ch = get_pdma_dev(dma_id);
    if (dma_ch == 0) return 0;

    if (ChEnReg & (1<<dma_id)) return 0;

    dma_ch->DAR = link->DAR;
    dma_ch->SAR = link->SAR;
    dma_ch->CTL = link->CTL;
    DmaCfgReg = 1;
    pdma_run(dma_id);
}