#include <nds.h>
#include <nds/card.h>
#include <stdio.h>
#include "iointerface.h"
#include <game_define.h>
#include "strpcm.h"
#include "fpga_mm.h"
#include <string.h>

int	sdmode_sdhc	;//	(*(vu32*)0x023FEE04)	//FIXME: DLDI could not alloc global memory ??
/*
40001A4h - NDS7/NDS9 - ROMCTRL - Gamecard Bus ROMCTRL (R/W)
  Bit   Expl.
  0-12  KEY1 length part1 (0-1FFFh) (forced min 08F8h by BIOS)
  13    KEY2 encrypt data (0=Disable, 1=Enable KEY2 Encryption for Data)
  14     "SE" Unknown? (usually same as Bit13)
  15    KEY2 Apply Seed   (0=No change, 1=Apply Encryption Seed) (Write only)
  16-21 KEY1 length part2 (0-3Fh)   (forced min 18h by BIOS)
  22    KEY2 encrypt cmd  (0=Disable, 1=Enable KEY2 Encryption for Commands)
  23    Data-Word Status  (0=Busy, 1=Ready/DRQ) (Read-only)
  24-26 Data Block size   (0=None, 1..6=100h SHL (1..6) bytes, 7=4 bytes)
  27    Transfer CLK rate (0=6.7MHz=33.51MHz/5, 1=4.2MHz=33.51MHz/8)
  28    Secure Area Mode  (0=Normal, 1=Other)
  29     "RESB" Unknown (always 1 ?) (not read/write-able)
  30     "WR"   Unknown (always 0 ?) (read/write-able)
  31    Block Start/Status (0=Ready, 1=Start/Busy) (IRQ See 40001A0h/Bit14)

 
*/
//int nds_card_isrun;
u32 tempbuf_1[2048/4];
u32 r4_delay,w4_delay,r512_delay,w512_delay;
extern int delay_times_0;
extern int delay_times_1;
extern int CARD_LINE_iqe_w;
extern int CARD_LINE_iqe_r;

#define fifo_over_time 20
#define CARD_CR2_FLAG 0xA0180010

u32 cardexitemode(void) 
{
  //while (CARD_CR2&CARD_BUSY);
    //nds_card_isrun = true;
    u32 returndata=0;
	CARD_CR1H = CARD_CR1_ENABLE | CARD_CR1_IRQ;
	CARD_COMMAND[0] = 0x66;
	CARD_COMMAND[1] = 0;
	CARD_COMMAND[2] = 0;
	CARD_COMMAND[3] = 0;
	CARD_COMMAND[4] = 0;
	CARD_COMMAND[5] = 0;
	CARD_COMMAND[6] = 0;
	CARD_COMMAND[7] = 0;
	CARD_CR2 = CARD_CR2_FLAG | 0x07000000;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);

	return returndata;
}


u32 cardcommand_r4_nowait(u8 cmd,u32 address,u32 data) 
{
 // while (CARD_CR2&CARD_BUSY);
        //nds_card_isrun = true;
    u32 returndata = 0;
	CARD_CR1H = CARD_CR1_ENABLE | CARD_CR1_IRQ;
	CARD_COMMAND[0] = cmd;
	CARD_COMMAND[1] = (address >> 24) & 0xff;
	CARD_COMMAND[2] = (address >> 16) & 0xff;
	CARD_COMMAND[3] = (address >> 8) & 0xff;
	CARD_COMMAND[4] = address & 0xff;
	CARD_COMMAND[5] = (data>>16) & 0xff;
	CARD_COMMAND[6] = (data>>8) & 0xff;
	CARD_COMMAND[7] = data & 0xff;
	CARD_CR2 = CARD_CR2_FLAG | 0x07000000;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);
	return returndata;
}
u32 cardcommand_r0_nowait(u8 cmd,u32 address,u32 data) 
{
 // while (CARD_CR2&CARD_BUSY);
        //nds_card_isrun = true;
    u32 returndata = 0;
	CARD_CR1H = CARD_CR1_ENABLE | CARD_CR1_IRQ;
	CARD_COMMAND[0] = cmd;
	CARD_COMMAND[1] = (address >> 24) & 0xff;
	CARD_COMMAND[2] = (address >> 16) & 0xff;
	CARD_COMMAND[3] = (address >> 8) & 0xff;
	CARD_COMMAND[4] = address & 0xff;
	CARD_COMMAND[5] = (data>>16) & 0xff;
	CARD_COMMAND[6] = (data>>8) & 0xff;
	CARD_COMMAND[7] = data & 0xff;
	CARD_CR2 = CARD_CR2_FLAG;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);
	return returndata;
}
#define EepromWaitBusy()		while (CARD_CR1 & 0x80)

int waitfifo_full_half(int len)
{
    u32 temp;
    delay_times_0 = fifo_over_time ;
    while(1)
    {
        temp=cardcommand_r4_nowait(nds_fifo_cmd_read_state,0,0);
        if (delay_times_0 == 0)
        {
#ifdef ENABLE_DEBUG  
            CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40;
            CARD_EEPDATA = 0x06;
            EepromWaitBusy();
            CARD_CR1 = /*MODE*/0x40;
            printf("delay error,%x\n",temp);
#endif
            return 1;
        }
        if (((temp>>nds_fifo_read_error_bit)&3) !=0)
        {
#ifdef ENABLE_DEBUG  
            CARD_CR1 = /*E*/0x8000 | /*SEL*/0x2000 | /*MODE*/0x40;
            CARD_EEPDATA = 0x06;
            EepromWaitBusy();
            CARD_CR1 = /*MODE*/0x40;
            printf("error,%x\n",temp);
#endif
            return 1;
        }else if (((temp>>nds_fifo_read_full_bit)&1) ==1)
        {
            break;
        }
        else if (((temp>>nds_fifo_len_bit)&nds_fifo_len_mask)  >=(len/2))
        {
            break;
        }

    }
    return 0;
}
int waitfifo_full_len(int len)
{
    u32 temp;
    delay_times_0 = fifo_over_time ;
    while(1)
    {
        temp=cardcommand_r4_nowait(nds_fifo_cmd_read_state,0,0);
        if (((temp>>nds_fifo_read_full_bit)&1) ==1)
        {
            break;
        }
        else if (((temp>>nds_fifo_len_bit)&nds_fifo_len_mask)  >=len)
        {
            break;
        }

        if (delay_times_0 == 0)
        {
            return 1;
        }
    }
    return 0;
}

int waitfifo_empty()
{
    u32 temp;
    delay_times_0 = fifo_over_time ;
    while(1)
    {
        temp=cardcommand_r4_nowait(nds_fifo_cmd_read_state,0,0);
        if (((temp>>nds_fifo_read_empty_bit)&1)  ==1)
        {
            break;
        }
        if (delay_times_0 == 0)
        {
            return 1;
        }
    }
    return 0;


}
int reset_fifo()
{
    cardcommand_r4_nowait(nds_fifo_cmd_reset,0,0);
}


u32 cardcommand_r4_rtc(u8 cmd,u32 address) 
{
  //while (CARD_CR2&CARD_BUSY);
        //nds_card_isrun = true;
    u32 returndata;
    reset_fifo();
	CARD_COMMAND[0] = cmd;
	CARD_COMMAND[1] = (*(vu8*)address++) & 0xff;
	CARD_COMMAND[2] = (*(vu8*)address++) & 0xff;
	CARD_COMMAND[3] = (*(vu8*)address++) & 0xff;
	CARD_COMMAND[4] = (*(vu8*)address++) & 0xff;
	CARD_COMMAND[5] = (*(vu8*)address++) & 0xff;
	CARD_COMMAND[6] = (*(vu8*)address++) & 0xff;
	CARD_COMMAND[7] = (*(vu8*)address++) & 0xff;
	CARD_CR2 = CARD_CR2_FLAG;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);
    returndata=waitfifo_full_len(4);
    return 0;
}
u32 cardcommand_r4_cmdend(u8 cmd,u32 address,u32 data) 
{
 // while (CARD_CR2&CARD_BUSY);
        //nds_card_isrun = true;
    u32 returndata;
    reset_fifo();

	CARD_COMMAND[0] = cmd;
	CARD_COMMAND[1] = (address >> 24) & 0xff;
	CARD_COMMAND[2] = (address >> 16) & 0xff;
	CARD_COMMAND[3] = (address >> 8) & 0xff;
	CARD_COMMAND[4] = address & 0xff;
	CARD_COMMAND[5] = (data>>16) & 0xff;
	CARD_COMMAND[6] = (data>>8) & 0xff;
	CARD_COMMAND[7] = data & 0xff;
	CARD_CR2 = CARD_CR2_FLAG;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);
    returndata=waitfifo_full_len(4);
	return 0;
}

extern int zj_list;
//extern int zj_list_w;
//extern int zj_list_r;
//extern int zj_list_sub;
u32 cardcommand_r4_num(u8 cmd,u32 w_num,u32 r_num,u8 flag) 
{
  //while (CARD_CR2&CARD_BUSY);
        //nds_card_isrun = true;
    u32 returndata;
    reset_fifo();

	CARD_COMMAND[0] = cmd;
	CARD_COMMAND[1] = (w_num >> 16) & 0xff;
	CARD_COMMAND[2] = (w_num >> 8) & 0xff;
	CARD_COMMAND[3] = (w_num >> 0) & 0xff;
	CARD_COMMAND[4] = (r_num >> 16) & 0xff; 
	CARD_COMMAND[5] = (r_num >> 8) & 0xff;  
	CARD_COMMAND[6] = (r_num >> 0) & 0xff;  
	CARD_COMMAND[7] = flag & 0xff;
	CARD_CR2 = CARD_CR2_FLAG;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);
    returndata=waitfifo_full_len(4);
    if (returndata == 0)
    {
        returndata=cardcommand_r4_nowait(nds_fifo_cmd_read,0,0);
         if (((returndata>>16)&0xffff) ==0xa5a5)
         {
            zj_list=returndata&0xffff;
            return 0;
         }
    }
    //while (CARD_CR2&CARD_BUSY);
    CARD_COMMAND[0] = cmd;
    CARD_COMMAND[1] = (w_num >> 16) & 0xff;
    CARD_COMMAND[2] = (w_num >> 8) & 0xff;
    CARD_COMMAND[3] = (w_num >> 0) & 0xff;
    CARD_COMMAND[4] = (r_num >> 16) & 0xff; 
    CARD_COMMAND[5] = (r_num >> 8) & 0xff;  
    CARD_COMMAND[6] = (r_num >> 0) & 0xff;  
    CARD_COMMAND[7] = flag & 0xff;
    CARD_CR2 = CARD_CR2_FLAG | 0x07000000 | r4_delay;
    do{
        if (CARD_CR2&CARD_DATA_READY) 
            returndata=CARD_DATA_RD;
    }while (CARD_CR2&CARD_BUSY);
     if ((cmd == 0xc4) && (((returndata>>16)&0xffff) ==0xa5a5))
     {
        zj_list=returndata&0xffff;
     }
     else
    {
        //printf("enter wait iqe=%x,%x\n",CARD_LINE_iqe_w,CARD_LINE_iqe_r);
         //while(CARD_LINE_iqe_w == CARD_LINE_iqe_r)
        //{
        //     swiWaitForVBlank();
        //     //swiDelay(2000);
        //
        //}
        //printf("exit wait iqe\n");
    }

	return 0;
}

u32 cardcommand_r4_key(u8 cmd,u16 x,u16 y,u16 key,u8 br ) 
{
  //while (CARD_CR2&CARD_BUSY);
    u32 returndata;
    reset_fifo();
	CARD_COMMAND[0] = cmd;
	CARD_COMMAND[1] = (x >> 8) & 0xff;//x
	CARD_COMMAND[2] = (x >> 0) & 0xff;//px
	CARD_COMMAND[3] = (y >> 8) & 0xff;//y
	CARD_COMMAND[4] = (y >> 0) & 0xff;//py
	CARD_COMMAND[5] = (key>>8) & 0xff;
	CARD_COMMAND[6] = (key>>0) & 0xff;
	CARD_COMMAND[7] = br;
	CARD_CR2 = CARD_CR2_FLAG;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);
    returndata=waitfifo_full_len(4);

	return 0;
}

void cardcommand_r512(u8 cmd,u32 address,u32 buf) 
{
    u32 returndata;
    if ((buf >= 0x2000000)&&(buf < 0x2400000))
    {
        DC_FlushRange( (u32*)buf, 512);
    }
    reset_fifo();
//while (CARD_CR2&CARD_BUSY);
	CARD_COMMAND[0] = cmd;
	CARD_COMMAND[1] = (address >> 24) & 0xff;
	CARD_COMMAND[2] = (address >> 16) & 0xff;
	CARD_COMMAND[3] = (address >> 8) & 0xff;
	CARD_COMMAND[4] = address & 0xff;
	CARD_COMMAND[5] = 0;
	CARD_COMMAND[6] = 2;
	CARD_COMMAND[7] = 0;
	CARD_CR2 = CARD_CR2_FLAG;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);
    waitfifo_full_len(512);
    //waitfifo_full_half(512);
//while (CARD_CR2&CARD_BUSY);
	CARD_COMMAND[0] = nds_fifo_cmd_read;
	CARD_COMMAND[1] = 0;
	CARD_COMMAND[2] = 0;
	CARD_COMMAND[3] = 0;
	CARD_COMMAND[4] = 0;
	CARD_COMMAND[5] = 0;
	CARD_COMMAND[6] = 0;
	CARD_COMMAND[7] = 0;

	// Set up a DMA channel to transfer a word every time the card makes one
	DMA_SRC(0) = (u32)&CARD_DATA_RD;
	DMA_DEST(0) = (u32)buf;
	DMA_CR(0) = 0xAF000001;// DMA_ENABLE | DMA_START_CARD | DMA_32_BIT | DMA_REPEAT | DMA_SRC_FIX | 0x0001;

    CARD_CR2 =CARD_CR2_FLAG | 0x01000000;

    while (CARD_CR2 & CARD_BUSY);
    DMA_CR(0) =0;


/*
	do{
		if (CARD_CR2&CARD_DATA_READY) 
        {
			*(u32*)buf=CARD_DATA_RD;buf+=4;
        }
	}while (CARD_CR2&CARD_BUSY);
*/



}
int errmum=0;
void cardcommand_r512n(u8 cmd,u32 address,u32 buf,int len,u32 cpu_callback,int retdata) 
{
        //nds_card_isrun = true;

    u32 regflag;
    int size;
    int returndata;

    len += 0x1ff;
    len &= ~(u32)(0x1ff);
    if ((buf >= 0x2000000)&&(buf < 0x2400000))
    {
        DC_FlushRange( (u32*)buf, len);
    }
    int old_addr=0;
    int err_num=0;
    reset_fifo();
    if (len > 0)
    {
      //while (CARD_CR2&CARD_BUSY);
        CARD_COMMAND[0] = cmd;
        CARD_COMMAND[1] = (address >> 24) & 0xff;
        CARD_COMMAND[2] = (address >> 16) & 0xff;
        CARD_COMMAND[3] = (address >> 8) & 0xff;
        CARD_COMMAND[4] = address & 0xff;
        CARD_COMMAND[5] = (len >>16) & 0xff;
        CARD_COMMAND[6] = (len >>8) & 0xff;
        CARD_COMMAND[7] = (retdata >> 8 &0xff );//(len >>0) & 0xff;
        CARD_CR2 = CARD_CR2_FLAG;
        do{
            if (CARD_CR2&CARD_DATA_READY) 
                returndata=CARD_DATA_RD;
        }while (CARD_CR2&CARD_BUSY);
    }

    while (len>0)
    {
        if (len>512)
        {
            size=1024;
            regflag = 2<<24;
        }
        else
        {
            size=512;
            regflag = 1<<24;
        }
        //waitfifo_full_len(size);
        //waitfifo_full_half(size);
        //if(waitfifo_full_half(size) == 1) break;
        if(waitfifo_full_len(size) == 1)         
        //if(waitfifo_full_half(size) == 1) 
        {
            reset_fifo();
            //len -= size;
            //buf += size;
            //address += size;
            //continue;
            break;
        }
//while (CARD_CR2&CARD_BUSY);
        CARD_COMMAND[0] = nds_fifo_cmd_read;
        CARD_COMMAND[1] = 0;
        CARD_COMMAND[2] = 0;
        CARD_COMMAND[3] = 0;
        CARD_COMMAND[4] = 0;
        CARD_COMMAND[5] = 0;
        CARD_COMMAND[6] = 0;
        CARD_COMMAND[7] = 0;

        DMA_SRC(0) = (u32)&CARD_DATA_RD;
        DMA_DEST(0) = (u32)buf;
        DMA_CR(0) = DMA_ENABLE | DMA_START_CARD | DMA_32_BIT | DMA_REPEAT | DMA_SRC_FIX | 0x0001;

        //CARD_CR2 = 0xA03f0000 | r512_delay | regflag;
        //CARD_CR2 = 0xA00f0000 | r512_delay | regflag;
        CARD_CR2 = CARD_CR2_FLAG | regflag;

        while (CARD_CR2 & CARD_BUSY);
        DMA_CR(0)=0;


        len -= size;
        buf += size;
        address += size;
/*

	do{
		if (CARD_CR2&CARD_DATA_READY) 
        {
			*(u32*)buf=CARD_DATA_RD;buf+=4;
            //len-=4;
            //address+=4;
        }
	}while (CARD_CR2&CARD_BUSY);
    len -= size;
    address += size;

*/


    }
    cardcommand_r4_cmdend(cmd,cpu_callback,retdata | 0x800000);
}



int check_fpga_1(void)
{
//while (CARD_CR2&CARD_BUSY);
    u32 returndata=0;
    reset_fifo();
	CARD_COMMAND[0] = 0x5d;
	CARD_COMMAND[1] = 0;
	CARD_COMMAND[2] = 0;
	CARD_COMMAND[3] = 0;
	CARD_COMMAND[4] = 0;
	CARD_COMMAND[5] = 0;
	CARD_COMMAND[6] = 0;
	CARD_COMMAND[7] = 0;
	CARD_CR2 = CARD_CR2_FLAG;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);
    waitfifo_full_len(512);

    DC_FlushRange( (u32*)tempbuf_1, 1024);
//while (CARD_CR2&CARD_BUSY);
	CARD_COMMAND[0] = nds_fifo_cmd_read;
	CARD_COMMAND[1] = 0;
	CARD_COMMAND[2] = 0;
	CARD_COMMAND[3] = 0;
	CARD_COMMAND[4] = 0;
	CARD_COMMAND[5] = 0;
	CARD_COMMAND[6] = 0;
	CARD_COMMAND[7] = 0;

	// Set up a DMA channel to transfer a word every time the card makes one
	DMA_SRC(0) = (u32)&CARD_DATA_RD;
	DMA_DEST(0) = (u32)tempbuf_1;
	DMA_CR(0) = 0xAF000001;// DMA_ENABLE | DMA_START_CARD | DMA_32_BIT | DMA_REPEAT | DMA_SRC_FIX | 0x0001;

    CARD_CR2 =CARD_CR2_FLAG | 0x02000000;

    while (CARD_CR2 & CARD_BUSY);
    DMA_CR(0) =0;
    return memcmp(tempbuf_1,fpga_mm,1024);


}
int check_fpga_2(void)
{
 // while (CARD_CR2&CARD_BUSY);
    u32 returndata=0;
    reset_fifo();

	CARD_COMMAND[0] = 0x5e;
	CARD_COMMAND[1] = 0;
	CARD_COMMAND[2] = 0;
	CARD_COMMAND[3] = 0;
	CARD_COMMAND[4] = 0;
	CARD_COMMAND[5] = 0;
	CARD_COMMAND[6] = 0;
	CARD_COMMAND[7] = 0;
	CARD_CR2 = CARD_CR2_FLAG;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);

    waitfifo_full_len(4);

//while (CARD_CR2&CARD_BUSY);
	CARD_COMMAND[0] = nds_fifo_cmd_read;
	CARD_COMMAND[1] = 0;
	CARD_COMMAND[2] = 0;
	CARD_COMMAND[3] = 0;
	CARD_COMMAND[4] = 0;
	CARD_COMMAND[5] = 0;
	CARD_COMMAND[6] = 0;
	CARD_COMMAND[7] = 0;
	CARD_CR2 = CARD_CR2_FLAG | 0x07000000;
	do{
		if (CARD_CR2&CARD_DATA_READY) 
			returndata=CARD_DATA_RD;
	}while (CARD_CR2&CARD_BUSY);



  #define RGB15_T(r,g,b)  (((r)|((g)<<5)|((b)<<10)))
            
  u32 i =((RGB15_T(0x4,0,0x7))<<16) | RGB15_T(0xc,0,0x5);
  i=i | 0x80008000;

    if (returndata == i )
    {
        return 0;
    }
    return -1;


    

}






int read_set_512(u32 buf)
{
    cardcommand_r512(0x5c,0,buf);
}



