//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#ifndef __NAND_H__
#define __NAND_H__

#include <fmd.h>

#define MAGNETO 0

typedef struct
{
    UINT16 nNumOfBlks;
    UINT16 nPagesPerBlk;
    UINT16 nSctsPerPage;
} NANDDeviceInfo;

NANDDeviceInfo stDeviceInfo;
    
#ifdef __cplusplus
extern "C"  {
#endif
NANDDeviceInfo GetNandInfo(void);
BOOL FMD_WriteSector_Stepldr(SECTOR_ADDR startSectorAddr, LPBYTE pSectorBuff, PSectorInfo pSectorInfoBuff, DWORD dwNumSectors);
#ifdef __cplusplus
}
#endif

#define NAND_LB_PAGE_SIZE       (2048)  // Each Page has 512 Bytes
#define SPARE_DATA_ECC_SIZE     (6)     // bad block + reserved1 + OEMreserved
#define SPARE_MECC_ECC_SIZE     (16)    // MECC(4B) x 4

#define ALL_FF                  (0xFFFFFFFF)

//#define NUM_OF_BLOCKS           (stDeviceInfo.nNumOfBlks)
//#define PAGES_PER_BLOCK         (stDeviceInfo.nPagesPerBlk)
//#define SECTORS_PER_PAGE        (stDeviceInfo.nSctsPerPage)


#define SECTORS_PER_BLOCK		(g_pNANDSpec->usPagesPerBlock)
#define NUM_OF_BLOCKS			(g_pNANDSpec->usNumberOfBlocks)
#define BYTES_PER_SECTOR		(g_pNANDSpec->usMainBytesPerPage)


#define USE_NFCE				0
#define USE_GPIO				0

#define CMD_READID              (0x90)  //  ReadID
#define CMD_READ                (0x00)  //  Read
#define CMD_READ2               (0x50)  //  Read2
#define CMD_READ3               (0x30)  //  Read3
#define CMD_RESET               (0xff)  //  Reset
#define CMD_ERASE               (0x60)  //  Erase phase 1
#define CMD_ERASE2              (0xd0)  //  Erase phase 2
#define CMD_WRITE               (0x80)  //  Write phase 1
#define CMD_WRITE2              (0x10)  //  Write phase 2
#define CMD_STATUS              (0x70)  //  STATUS
#define CMD_RDI                 (0x85)  //  Random Data Input
#define CMD_RDO                 (0x05)  //  Random Data Output
#define CMD_RDO2                (0xE0)  //  Random Data Output

#define BADBLOCKMARK            (0x00)

//  Status bit pattern
#define STATUS_READY            (0x40)  //  Ready
#define STATUS_ERROR            (0x01)  //  Error
#define	STATUS_ILLACC           (1<<5)  //	Illigar Access

/* !!! Maximum Delay Setting, Please Adjust these value to Optimize */
/*
#if 0
// 266Mhz: 1,6,1.
//#define TACLS            1     // 1
//#define TWRPH0            4//6 
//#define TWRPH1            1//2     // 2 

// 133Mhz: 1,6,1.
#define TACLS            0    // 1
#define TWRPH0            4    // 6
#define TWRPH1            2    // 2
#endif

#if 1
#define TACLS            7
#define TWRPH0            7
#define TWRPH1            7
#endif
*/


// NFCONF
#define ECC_1BIT				(0 << 23)
#define ECC_4BIT				(2 << 23)
#define ECC_DISABLE				(1 << 23)

#define SLC_NAND				(0 << 3)
#define MLC_NAND				(1 << 3)

#define LARGE_BLOCK				(0 << 2)
#define SMALL_BLOCK				(1 << 2)

#define EXT_ADDR				(1 << 1)		// additional address cycle (5 addres cycles for 2K/4K page NAND)




#define NF_CMD(cmd)				{v_pNFCONregs->NFCMD   =  (unsigned char)(cmd);}
#define NF_ADDR(addr)			{v_pNFCONregs->NFADDR  =  (unsigned char)(addr);}    

#define NF_nFCE_L()				{v_pNFCONregs->NFCONT &= ~(1<<1);}
#define NF_nFCE_H()				{v_pNFCONregs->NFCONT |=  (1<<1);}
#define NF_RDESTST				(v_pNFCONregs->NFECCERR1)

//-----------------------------------------

#define NF_RSTECC()				{v_pNFCONregs->NFCONT |=  ((1<<5) | (1<<4));}

#define NF_MECC_UnLock()		{v_pNFCONregs->NFCONT &= ~(1<<7);}
#define NF_MECC_Lock()			{v_pNFCONregs->NFCONT |= (1<<7);}
#define NF_SECC_UnLock()		{v_pNFCONregs->NFCONT &= ~(1<<6);}
#define NF_SECC_Lock()			{v_pNFCONregs->NFCONT |= (1<<6);}

#define NF_CLEAR_RB()			{v_pNFCONregs->NFSTAT = (1<<4);}    // Have write '1' to clear this bit.

#define NF_DETECT_RB()			{while((v_pNFCONregs->NFSTAT & 0x11) != 0x11);} // RnB_Transdetect & RnB
#define NF_WAITRB()				{while(!(v_pNFCONregs->NFSTAT & (1<<0)));} 


#define NF_RDDATA_BYTE()		(v_pNFCONregs->NFDATA)
#define NF_RDDATA_WORD()		(*(volatile UINT32 *)(&(v_pNFCONregs->NFDATA)))

#define NF_WRDATA_BYTE(data)	{v_pNFCONregs->NFDATA  =  (UINT8)(data);}
#define NF_WRDATA_WORD(data)    {*(volatile UINT32 *)(&(v_pNFCONregs->NFDATA)) = (UINT32)(data);}

#define NF_RDMECC0()			(v_pNFCONregs->NFMECC0)
#define NF_RDMECC1()			(v_pNFCONregs->NFMECC1)
#define NF_RDSECC()				(v_pNFCONregs->NFSECC)

#define NF_RDMECCD0()			(v_pNFCONregs->NFMECCD0)
#define NF_RDMECCD1()			(v_pNFCONregs->NFMECCD1)
#define NF_RDSECCD()			(v_pNFCONregs->NFSECCD)

#define NF_ECC_ERR0				(v_pNFCONregs->NFECCERR0)
#define NF_ECC_ERR1				(v_pNFCONregs->NFECCERR1)

#define NF_WRMECCD0(data)		{v_pNFCONregs->NFMECCD0 = (data);}
#define NF_WRMECCD1(data)		{v_pNFCONregs->NFMECCD1 = (data);}
#define NF_WRSECCD(data)		{v_pNFCONregs->NFSECCD = (data);}

#define NF_8MECC0()				(v_pNFCONregs->NF8MECC0)
#define NF_8MECC1()				(v_pNFCONregs->NF8MECC1)
#define NF_8MECC2()				(v_pNFCONregs->NF8MECC2)
#define NF_8MECC3()				(v_pNFCONregs->NF8MECC3)

#define NF_RDSTAT				(v_pNFCONregs->NFSTAT)


#define NF_ECC8_DECODE()			(v_pECCregs->NFECCCONT = (0 << 16) | (1 << 2))
#define NF_ECC8_ENCODE()			(v_pECCregs->NFECCCONT = (1 << 16) | (1 << 2))

#define NF_ECC8_SETUP(MsgLength)	{v_pNFCONregs->NFCONF |= (0x3 << 23); (v_pECCregs->NFECCCONF = ((MsgLength - 1) << 16) | 0x3);}
#define NF_ECC1_SETUP()				{v_pECCregs->NFECCCONF &= ~(0x7); v_pNFCONregs->NFCONF &= ~(0x3 << 23);}


#define NF_ECC8_WAIT_DECODE_DONE()	{while((v_pECCregs->NFECCSTAT & (1 << 24)) == 0);}
#define NF_ECC8_WAIT_ENCODE_DONE()	{while((v_pECCregs->NFECCSTAT & (1 << 25)) == 0);}
#define NF_ECC8_CLEAR_DECODE_DONE()	{v_pECCregs->NFECCSTAT = (1 << 24);}
#define NF_ECC8_CLEAR_ENCODE_DONE()	{v_pECCregs->NFECCSTAT = (1 << 25);}
#define NF_ECC8_CLEAR_DONE()		{v_pECCregs->NFECCSTAT = (1 << 25) | (1 << 24);}

#define NF_ECC8_ERROR()				(v_pECCregs->NFECCSECSTAT & 0x1F)

#define NF_ECC8_ERROR_BYTE0			((v_pECCregs->NFECCERL0 >> 0) & 0x3FF)
#define NF_ECC8_ERROR_BYTE1			((v_pECCregs->NFECCERL0 >> 16) & 0x3FF)
#define NF_ECC8_ERROR_BYTE2			((v_pECCregs->NFECCERL1 >> 0) & 0x3FF)
#define NF_ECC8_ERROR_BYTE3			((v_pECCregs->NFECCERL1 >> 16) & 0x3FF)
#define NF_ECC8_ERROR_BYTE4			((v_pECCregs->NFECCERL2 >> 0) & 0x3FF)
#define NF_ECC8_ERROR_BYTE5			((v_pECCregs->NFECCERL2 >> 16) & 0x3FF)
#define NF_ECC8_ERROR_BYTE6			((v_pECCregs->NFECCERL3 >> 0) & 0x3FF)
#define NF_ECC8_ERROR_BYTE7			((v_pECCregs->NFECCERL3 >> 16) & 0x3FF)

#define NF_ECC8_ERROR_PATTERN0		((v_pECCregs->NFECCERP0 >> 0) & 0xFF)
#define NF_ECC8_ERROR_PATTERN1		((v_pECCregs->NFECCERP0 >> 8) & 0xFF)
#define NF_ECC8_ERROR_PATTERN2		((v_pECCregs->NFECCERP0 >> 16) & 0xFF)
#define NF_ECC8_ERROR_PATTERN3		((v_pECCregs->NFECCERP0 >> 24) & 0xFF)
#define NF_ECC8_ERROR_PATTERN4		((v_pECCregs->NFECCERP1 >> 0) & 0xFF)
#define NF_ECC8_ERROR_PATTERN5		((v_pECCregs->NFECCERP1 >> 8) & 0xFF)
#define NF_ECC8_ERROR_PATTERN6		((v_pECCregs->NFECCERP1 >> 16) & 0xFF)
#define NF_ECC8_ERROR_PATTERN7		((v_pECCregs->NFECCERP1 >> 24) & 0xFF)

//-----------------------------------------------------------------------------

typedef enum
{
    ECC_CORRECT_MAIN = 0,    // correct Main ECC
    ECC_CORRECT_SPARE = 1    // correct Main ECC
} ECC_CORRECT_TYPE;

//-----------------------------------------------------------------------------

#endif    // __NAND_H_.

