#include <windows.h>
#include <pehdr.h>
#include <romldr.h>
#include <bsp_cfg.h>
#include "image_cfg.h"
#include "utils.h"

#ifdef SDMMC_BOOT
#define CopySDMMCtoMem(z,a,b,c,e)	(((int(*)(unsigned int, unsigned int, unsigned short, unsigned int, unsigned int))(*((unsigned int *)0xD0037F98)))(z,a,b,c,e))
typedef BOOL (*CopySDMMCtoMem)(unsigned int, unsigned int, unsigned short, unsigned int, unsigned int);  
#else
#define NAND_SB_PAGE_SIZE_BYTES     (0x200)        // 1 Page = 0x200 (512 Bytes)
#define NAND_SB_BLOCK_SIZE_BYTES    (0x4000)        // 1 Block = 16 KB
#define NAND_SB_PAGES_PER_BLOCK     (NAND_SB_BLOCK_SIZE_BYTES / NAND_SB_PAGE_SIZE_BYTES)    // 32-pages

#define NAND_LB_PAGE_SIZE_BYTES     (0x800)        // 1 Page = 0x800 (2048 Bytes)
#define NAND_LB_BLOCK_SIZE_BYTES    (0x20000)    // 1 Block = 128 KB
#define NAND_LB_PAGES_PER_BLOCK     (NAND_LB_BLOCK_SIZE_BYTES / NAND_LB_PAGE_SIZE_BYTES)    // 64-pages

//#define NAND_BYTES_PER_PAGE         ((g_bLargeBlock==TRUE)?NAND_LB_PAGE_SIZE_BYTES:NAND_SB_PAGE_SIZE_BYTES)
//#define NAND_PAGES_PER_BLOCK        ((g_bLargeBlock==TRUE)?NAND_LB_PAGES_PER_BLOCK:NAND_SB_PAGES_PER_BLOCK)
#define NAND_BYTES_PER_PAGE         (2048)
#define NAND_PAGES_PER_BLOCK        (64)

#endif

    // NOTE: we assume that this Steppingstone loader occupies *part* the first (good) NAND flash block.  More
    // specifically, the loader takes up 4096 bytes (or 8 NAND pages) of the first block.  We'll start our image
    // copy on the very next page.

#define LOAD_ADDRESS_PHYSICAL       (IMAGE_EBOOT_PA_START)
#define LOAD_IMAGE_BYTE_COUNT       (IMAGE_EBOOT_SIZE)
//#define LOAD_ADDRESS_PHYSICAL       (0x47700000)
//#define LOAD_IMAGE_BYTE_COUNT       (0x00080000)
#define LOAD_IMAGE_PAGE_COUNT       (LOAD_IMAGE_BYTE_COUNT / NAND_BYTES_PER_PAGE)
#define LOAD_IMAGE_PAGE_OFFSET      (NAND_PAGES_PER_BLOCK)    // StpeLoader uses 2 Block
//#define LOAD_IMAGE_PAGE_OFFSET      (64 * 2)    // StpeLoader uses 2 Block

// Globals variables.
ROMHDR * volatile const pTOC = (ROMHDR *)-1;
// For Large Block Check
extern BOOL g_bLargeBlock;

#ifndef SDMMC_BOOT
// Function in "Nand.c"
extern void NAND_Init(void);
extern BOOL NAND_ReadPage(UINT32 block, UINT32 sector, volatile BYTE *buffer);

BOOL NAND_ReadSector(DWORD dwSector, LPBYTE pSectorBuff);

#endif
typedef void (*PFN_IMAGE_LAUNCH)();

static BOOLEAN SetupCopySection(ROMHDR *const pTOC)
{
    // This code doesn't make use of global variables so there are no copy sections.
    // To reduce code size, this is a stub function...
    return(TRUE);
}

/*
 * sdmmc base, current boot channel.
 */
#define irom_v210_sdmmc_base								\
		(*((volatile UINT*)(0xd0037488)))


void main(void)
{
#ifdef SDMMC_BOOT
    // Set up all GPIO ports for LED.
    Port_Init();
    Led_Display(0xf);
	//modifed by terry 2012.6.15
	if(irom_v210_sdmmc_base == 0xeb000000)
	{
		//g_oSD_CHANNEL0 = 1;
		CopySDMMCtoMem(0, EBOOTSTARTSECTOR, (unsigned short)SECTOROFEBOOT, (unsigned int *)LOAD_ADDRESS_PHYSICAL, 0);

	}
	else if(irom_v210_sdmmc_base == 0xeb200000)
	{
		//g_oSD_CHANNEL0 = 0;
		CopySDMMCtoMem(2, EBOOTSTARTSECTOR, (unsigned short)SECTOROFEBOOT, (unsigned int *)LOAD_ADDRESS_PHYSICAL, 0);

	}

#else
    register nBlock;
    register nPage;
    register nBadBlocks;
    volatile unsigned char *pBuf;

    // Set up copy section (initialized globals).
    //
    // NOTE: after this call, globals become valid.
    //
    SetupCopySection(pTOC);

    // Set up all GPIO ports for LED.
    //Port_Init();		//lqm masked
    //Led_Display(0xf);	//lqm masked

    // UART Initialize
    //Uart_Init();

    //Uart_SendString("WinCE 6.0 Steploader for SMDKV210\r\n");

    // Initialize the NAND flash interface.
    //Uart_SendString("NAND Initialize\n\r");
    //while(1);
    
    NAND_Init();


    // Copy image from NAND flash to RAM.
    pBuf = (unsigned char *)LOAD_ADDRESS_PHYSICAL;
    nBadBlocks = 0;

    //Led_Display(0x8);

    for (nPage = LOAD_IMAGE_PAGE_OFFSET; nPage < (LOAD_IMAGE_PAGE_OFFSET + LOAD_IMAGE_PAGE_COUNT) ; nPage++)
    {
        //Led_Display(0x1);
        nBlock = ((nPage / NAND_PAGES_PER_BLOCK) + nBadBlocks);

		if(NAND_ReadSector(nPage, pBuf) == FALSE)
		{
			// Bad block
			nBadBlocks++;
			nPage--;

			continue;
		}
		
        pBuf += NAND_BYTES_PER_PAGE;
    }

	//Led_Display(0x0);

    //Uart_SendString("Launch Eboot...\n\r");
#endif
    ((PFN_IMAGE_LAUNCH)(LOAD_ADDRESS_PHYSICAL))();
}

