/* dwdma linked list struct */
struct llp_t {
    uint32_t sar;
    uint32_t dar;
    struct llp_t *llp;
    uint32_t ctl_l;
    uint32_t ctl_h;
    uint32_t dstat;
};

uint16_t dst_buff[240][400];
uint16_t src_buff[240][400];

/* structs which describe full screen update */
struct llp_t scr_llp[LCD_HEIGHT];


static void llp_setup(void *src, void *dst, struct llp_t *llp, uint32_t size)
{
    llp->sar = (uint32_t)src;
    llp->dar = (uint32_t)dst;
    llp->llp = llp + 1;
    llp->ctl_h = size;
    llp->ctl_l = (1<<20) |
                 (1<<23) |
                 (1<<17) |
                 (2<<1)  |
                 (2<<4)  |
                 (3<<11) |
                 (3<<14) |
                 (1<<27) |
                 (1<<28);
}

static void llp_end(struct llp_t *llp)
{
    llp->ctl_l &= ~((1<<27)|(1<<28));
}


static void dwdma_start(uint8_t ch, struct llp_t *llp, uint8_t handshake)
{
    DWDMA_SAR(ch) = 0;
    DWDMA_DAR(ch) = 0;
    DWDMA_LLP(ch) = (uint32_t)llp;
    DWDMA_CTL_L(ch) = (1<<20) |
                      (1<<23) |
                      (1<<17) |
                      (2<<1)  |
                      (2<<4)  |
                      (3<<11) |
                      (3<<14) |
                      (1<<27) |
                      (1<<28);

   DWDMA_CTL_H(ch) = 1;
   DWDMA_CFG_L(ch) = (7<<5);
   DWDMA_CFG_H(ch) = (handshake<<11)|(1<<2);
   DWDMA_SGR(ch) = (13<<20);
   DWDMA_DMA_CHEN = (0x101<<ch);

}

static void dwdma_init(void)
{
    DWDMA_DMA_CHEN = 0xf00;
    DWDMA_CLEAR_BLOCK = 0x0f;
    DWDMA_DMA_CFG = 1; /* global enable */
}

bool dbg_ports(void)
{
    int i,j = 0;
    int fd;

    /* build src array */
    for (i=0; i<240; i++)
        for(j=0; j<400; j++)
            src_buff[i][j] = ((i*400 + j) & 0xffff);

    /* build LLPs */
    for (i=0; i<240; i++)
        llp_setup(&src_buff[i], &dst_buff[i], &scr_llp[i], LCD_WIDTH/2);
    llp_end(&scr_llp[LCD_HEIGHT-1]);

    dwdma_init();

    LCDC_CTRL = ALPHA(7) | LCDC_STOP | LCDC_MCU;
    MCU_CTRL = ALPHA_BASE(0x3f) | MCU_CTRL_BYPASS;
    HOR_BP = LCD_WIDTH + 3;
    VERT_BP = LCD_HEIGHT;

    LINE0_YADDR = 0;
    LINE1_YADDR = (1 * LCD_WIDTH/2);
    LINE2_YADDR = (2 * LCD_WIDTH/2);
    LINE3_YADDR = (3 * LCD_WIDTH/2);

    LINE0_UVADDR = 1;
    LINE1_UVADDR = (1 * LCD_WIDTH/2) + 1;
    LINE2_UVADDR = (2 * LCD_WIDTH/2) + 1;
    LINE3_UVADDR = (3 * LCD_WIDTH/2) + 1;

    lcdctrl_bypass(0);

    //memset((void *)&LCD_BUFF, 0x00, 2048*4);

    dwdma_start(0, scr_llp, 6);

    MCU_CTRL=(1<<1)|(1<<2)|(1<<5);
    while (!(LCDC_STA & LCDC_MCU_IDLE));

    fd = open("/src_buff.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
    if (fd > 0)
    {
        _backlight_off();
        sleep(HZ);
        _backlight_on();
    }
    write(fd, src_buff, sizeof(src_buff));
    close(fd);

    fd = open("/dst_buff.txt", O_RDWR|O_CREAT|O_TRUNC, 0666);
    if (fd > 0)
    {
        _backlight_off();
        sleep(HZ);
        _backlight_on();
    }
    write(fd, dst_buff, sizeof(dst_buff));
    close(fd);

    _backlight_off();
    sleep(2*HZ);
    _backlight_on();
    while(1);
}