#ifndef NAND_H_
/**
 * nand chip header
 *
 * nand port state machine -
 * ssd_thread begins with "empty" state
 * when request is pending change to "cmd" state
 * nand_thread then takes over and finishes at "done state"
 *
 */
#define NAND_H_

#include <system.h>


/************************ chip charactersitics *****************************************/
//
#define POWER_NAND_PAGES_PER_ERASE_UNIT (7)   /* 128 */
#define NAND_EU_MASK	                  (0xffffff80) /* 11111111 11111111 11111111 10000000 */
#define POWER_NAND_PAGE_SIZE		    (12)  /* 4096 */

//#define POWER_NAND_PAGES_PER_ERASE_UNIT (5)   /* 32 */
//#define NAND_EU_MASK	                  (0xffffffe0) /* 11111111 11111111 11111111 11100000 */
//#define POWER_NAND_PAGE_SIZE		    (10)  /* 1024 */

//#define POWER_NAND_PAGES_PER_ERASE_UNIT (2)   /* 4 */
//#define NAND_EU_MASK	                  (0xfffffffc) /* 11111111 11111111 11111111 11111100 */
//#define POWER_NAND_PAGE_SIZE		    (4)  /* 16 */

#define POWER_NAND_SPARE_SIZE		    (7)   /* 128 */
#define SIM_FILE_NAME   "flash_sim_4096B_page"
//

#define NAND_PAGE_SIZE				  (1 << POWER_NAND_PAGE_SIZE)
#define NAND_PAGES_PER_ERASE_UNIT     (1 << POWER_NAND_PAGES_PER_ERASE_UNIT)
#define NAND_SPARE_SIZE               (1 << POWER_NAND_SPARE_SIZE)
#define NAND_TOTAL_SIZE				  (NAND_PAGE_SIZE+NAND_SPARE_SIZE)
#define NAND_MAX_EU_OFFSET			  (NAND_PAGES_PER_ERASE_UNIT-1)
#define NAND_ADDRESS_PAGE_BITS_COUNT  POWER_NAND_PAGES_PER_ERASE_UNIT // actually: log(NAND_PAGES_PER_ERASE_UNIT)
//#define POWER_NAND_PAGE_COUNT		  (POWER_NAND_PAGES_PER_ERASE_UNIT+NAND_ADDRESS_EU_BITS_COUNT)

//#define NAND_PAGE_COUNT  (512) /* */
//#define NAND_PAGE_COUNT  (1024) /* */
//#define NAND_PAGE_COUNT  (4096) /* 16MB*/
#define NAND_PAGE_COUNT  (8192) /* 32MB*/
//#define NAND_PAGE_COUNT				  (262144) /* 1G*/
//#define NAND_PAGE_COUNT				  (1048576) /* 4G*/
//#define NAND_PAGE_COUNT                                 (131072) /* 500MB*/
//#define NAND_PAGE_COUNT                                 (5242880) /* 20G*/

#define NAND_BLOCK_COUNT			  (NAND_PAGE_COUNT / NAND_PAGES_PER_ERASE_UNIT)
#define NAND_DEVICE_ID				  0x00000f0f
#define NAND_PAGE_EMPTY 0xffffffff
#define NAND_CHIPS_PER_BUS   (2)
#define NAND_BUSES           (1)

#define NAND_CHIP_COUNT      (NAND_CHIPS_PER_BUS * NAND_BUSES)
#define NAND_PAGES_PER_BUS   (NAND_PAGE_COUNT / NAND_BUSES)
#define NAND_PAGES_PER_CHIP  (NAND_PAGE_COUNT / NAND_CHIP_COUNT)
#define NAND_BLOCKS_PER_CHIP (NAND_PAGES_PER_CHIP / NAND_PAGES_PER_ERASE_UNIT)

#define NAND_SPARE_LBA_OFFSET 					(12)
#define NAND_SPARE_CHUNK_OFFSET_START_OFFSET   (NAND_SPARE_LBA_OFFSET + 4)

#define NAND_SPARE_AREA_START				    (NAND_PAGE_SIZE)
#define NAND_SPARE_LBA									(NAND_SPARE_AREA_START+NAND_SPARE_LBA_OFFSET)
#define NAND_SPARE_CHUNK_OFFSET_START   (NAND_SPARE_AREA_START + NAND_SPARE_CHUNK_OFFSET_START_OFFSET)

#define NAND_CMD_READ    (0)
#define NAND_CMD_WRITE   (1)
#define NAND_CMD_ERASE   (2)

/******************************************************
    									timing
 ******************************************************/
#define NAND_TIME_PAGE_TX 106
#define NAND_TIME_READ    60
#define NAND_TIME_WRITE   200
#define NAND_TIME_ERASE   1500

/******************************************************/
/*  									simulator defines								*/
/******************************************************/
#define POWER_PAGES_PER_GIGA   (30-POWER_NAND_PAGE_SIZE ) /* 1G */
#define PAGES_PER_GIGA         (1 << POWER_PAGES_PER_GIGA)
#define GIGA_SIZE              (PAGES_PER_GIGA * NAND_TOTAL_SIZE)
#define NUM_SIM_FILES          ((NAND_PAGE_COUNT > PAGES_PER_GIGA)?(((int)(NAND_PAGE_COUNT / PAGES_PER_GIGA))+1):1)
#define SIM_FILE_PAGE_COUNT    ((NAND_PAGE_COUNT > PAGES_PER_GIGA)?PAGES_PER_GIGA:NAND_PAGE_COUNT)

/******************************************************/
///* spare area flags and pointers */
//typedef struct __spare{
//	uint8_t bytes[NAND_SPARE_SIZE];
//} spare_area_flags;

/* spare area flags and pointers */
typedef struct __frag{
	uint32_t offset;
	uint32_t len;
} offset_len;


#define CAST_TO_UINT8(PTR)   ((uint8_t*)(PTR))

/* macros */
error_t nandInit(void);


error_t nandErase(uint32_t page_in_erase_unit);

void nandTerminate(void);

/**
 * Simple read page
 */
error_t
nandReadPage(uint8_t *buf, uint32_t page, uint32_t offset, uint32_t len);

error_t
nandProgramPage(uint8_t *buf, uint32_t page, uint32_t offset, uint32_t len);

#endif /*NAND_H_*/
