summaryrefslogtreecommitdiff
path: root/common/cmd_nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/cmd_nand.c')
-rwxr-xr-xcommon/cmd_nand.c11544
1 files changed, 11544 insertions, 0 deletions
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
new file mode 100755
index 0000000..408dafb
--- /dev/null
+++ b/common/cmd_nand.c
@@ -0,0 +1,11544 @@
+/*
+ * Driver for NAND support, Rick Bronson
+ * borrowed heavily from:
+ * (c) 1999 Machine Vision Holdings, Inc.
+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
+ *
+ * Added 16-bit nand support
+ * (C) 2004 Texas Instruments
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <asm/io.h>
+//#include <watchdog.h>
+#include <nand.h>
+#include "wmt_display/hw/wmt_mmap.h"
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+//#if (CONFIG_COMMANDS & CFG_CMD_NAND)
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ids.h>
+#include <jffs2/jffs2.h>
+
+struct sig_header {
+ unsigned int img_size; //kernel signature size in bytes
+ unsigned int reserved[3]; //reserved.
+};
+#ifdef CONFIG_OMAP1510
+void archflashwp(void *archdata, int wp);
+#endif
+
+#define ROUND_DOWN(value,boundary) ((value) & (~((boundary)-1)))
+
+extern unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
+/*
+ * Definition of the out of band configuration structure
+ */
+struct nand_oob_config {
+ int ecc_pos[6]; /* position of ECC bytes inside oob */
+ int badblock_pos; /* position of bad block flag inside oob -1 = inactive */
+ int eccvalid_pos; /* position of ECC valid flag inside oob -1 = inactive */
+} oob_config = { {0}, 0, 0};
+
+#undef NAND_DEBUG
+#undef PSYCHO_DEBUG
+
+/* ****************** WARNING *********************
+ * When ALLOW_ERASE_BAD_DEBUG is non-zero the erase command will
+ * erase (or at least attempt to erase) blocks that are marked
+ * bad. This can be very handy if you are _sure_ that the block
+ * is OK, say because you marked a good block bad to test bad
+ * block handling and you are done testing, or if you have
+ * accidentally marked blocks bad.
+ *
+ * Erasing factory marked bad blocks is a _bad_ idea. If the
+ * erase succeeds there is no reliable way to find them again,
+ * and attempting to program or erase bad blocks can affect
+ * the data in _other_ (good) blocks.
+ */
+#define ALLOW_ERASE_BAD_DEBUG 0
+
+#define CONFIG_MTD_NAND_ECC /* enable ECC */
+#define CONFIG_MTD_NAND_ECC_JFFS2
+
+/* bits for nand_rw() `cmd'; or together as needed */
+#define NANDRW_READ 0x01
+#define NANDRW_WRITE 0x00
+#define NANDRW_JFFS2 0x02
+#define NANDRW_JFFS2_SKIP 0x04
+
+/*------move from cmd_nandrw.c---start--*/
+#define HW_ENCODE_OOB
+//#define WMT_SW_RDMZ
+#define WMT_HW_RDMZ
+#define USE_BBT
+#define PMPMB_ADDR 0xd8130204
+#define PMNAND_ADDR 0xd8130318
+#define PMCS_ADDR 0xd8130000
+#define WMT_PLL_CLOCK 25
+#define NFC_MAX_CLOCK 60
+#define NFC_SETUPTIME 15
+
+WMT_NFC_CFG *pNFCRegs;
+struct _NAND_PDMA_REG_ *pNand_PDma_Reg;
+unsigned long *ReadDesc, *WriteDesc;
+unsigned int g_WMTNFCBASE;
+static unsigned char *rdmz_buf = NULL;
+static unsigned char *data_buf = NULL;
+
+/*static unsigned char *rdmz_buf0 = NULL;
+static unsigned char *rdmz_buf1 = NULL;
+static unsigned char *rdmz_buf_rd = NULL;//for the read pipeline*/
+
+//static unsigned char parity[70];
+
+#define WRITE_NAND16(d, addr) (*(volatile unsigned short *)(addr) = (unsigned short)d)
+#define READ_NAND16(d, addr) (d = *(volatile unsigned short *)(addr))
+#define READ_NAND8(d, addr) (d = *(volatile unsigned char *)(addr))
+#define WRITE_NAND8(d, addr) (*(volatile unsigned char *)(addr) = (unsigned char)d)
+#define READ_NAND(adr) ((volatile unsigned char)(*(volatile __u8 *)(unsigned long)adr))
+
+static unsigned char bbt_pattern[] = {'B', 'b', 't', '0' };
+static unsigned char mirror_pattern[] = {'1', 't', 'b', 'B' };
+static unsigned int *bbt;
+static unsigned int bbt_version;
+#define BBT_MAX_BLOCK 4
+#define RETRY_MAX_BLOCK 4
+#define BBT_BITMAP 2
+unsigned int bad_block_pos[CFG_MAX_NAND_DEVICE][30];
+static uint32_t wmt_rdmz = 0x72646d7a;//{ 'z', 'm', 'd', 'r' };
+static unsigned int logo_base, boot_base, recovery_base, misc_base, misc_end,keydata_base;
+
+int r_w_check_ecc_robust = 0;
+int max_ecc_bits = 0;
+int force_set_rr_value = -1;
+int do_page_rw = 0;
+int erase_all_read_fail = 0;
+
+
+/*------move from cmd_nandrw.c---end--*/
+/*
+ * Function Prototypes
+ */
+extern void *memcpy_itp(void *d, const void *s, size_t n);
+int hw_encode_oob(struct nand_chip *nand);
+int nand_read_block(struct nand_chip *nand, unsigned int maddr, unsigned int page, unsigned int page_count);
+static void nand_print(struct nand_chip *nand);
+int nand_rw (struct nand_chip* nand, int cmd,
+ size_t start, size_t len,
+ size_t * retlen, u_char * buf, u_char * oob, size_t ooblen);
+int wmt_nand_erase(struct nand_chip *nand, unsigned int block);
+int get_pattern_small(struct nand_chip *nand, unsigned int block, unsigned int *tag, unsigned int *version);
+int get_pattern_large(struct nand_chip *nand, unsigned int block, unsigned int *tag, unsigned int *version);
+int nand_page_program(struct nand_chip *nand, unsigned int page, unsigned int maddr, unsigned int len);
+int nand_page_program_random(struct nand_chip *nand, unsigned int start, unsigned int maddr, unsigned int len);
+
+int nand_read_page(struct nand_chip *nand, unsigned int start, unsigned int maddr, unsigned int len);
+void nfc_ecc_set(unsigned int type, unsigned int ecc, struct nand_chip *nand);
+int WMTLoadImageFormNAND(struct nand_chip *nand, unsigned long long naddr, unsigned int maddr, unsigned int size);
+int WMTAccessNandEarier(unsigned long long naddr, unsigned int maddr, unsigned int size, int write);
+int WMTSaveImageToNAND(struct nand_chip *nand, unsigned long long naddr, unsigned int dwImageStart,
+ unsigned int dwImageLength, int oob_offs, int need_erase);
+int nfc_BCH_read_page(struct nand_chip *nand, unsigned int page, unsigned int maddr, unsigned int len);
+int nfc_BCH_read_page2(struct nand_chip *nand, unsigned int page, unsigned int maddr, unsigned int len, int pipeline,int lastpage);
+int NFC_CHECK_ECC(void);
+int nfc_1bit_ecc_correct(struct nand_chip *nand, unsigned int start, unsigned int maddr, unsigned int len);
+int nfc_1bit_read_page(struct nand_chip *nand, unsigned int start, unsigned int maddr, unsigned int len);
+int creat_bbt(struct nand_chip *nand, int chip);
+int find_bbt(struct nand_chip *nand, int chip);
+int update_bbt_inram(struct nand_chip *nand, unsigned int block, int chip);
+int update_bbt_inflash(struct nand_chip *nand, unsigned int last, int chip);
+int isbbtbadblock(struct nand_chip *nand, unsigned int block, int chip);
+int tellme_badblock(struct nand_chip *nand);
+int WMTEraseNAND(struct nand_chip *nand, unsigned int block, unsigned int block_nums, unsigned int all);
+int tellme_whereistable(struct nand_chip *nand);
+int nand_write_block(struct nand_chip *nand, unsigned int start, unsigned int page, unsigned int page_count, unsigned char *oob, int oob_offs);
+int tellme_nandinfo(struct nand_chip *nand);
+int nand_readID(unsigned char *id);
+int WMTEraseNANDALL(struct nand_chip *nand, unsigned int all);
+int check_block_table(struct nand_chip *nand, unsigned int scan);
+int nfc_BCH_ecc_check(struct nand_chip *nand, unsigned int maddr);
+void nfc_BCH_ecc_correct(struct nand_chip *nand, unsigned int bitcnt, unsigned int maddr);
+int wmt_calc_clock(struct nand_chip *nand, unsigned int spec_clk,unsigned int spec_clk1,struct NFC_RW_T *nfc_rw);
+int wmt_get_timing(struct nand_chip *nand, unsigned int spec_clk, unsigned int spec_clk1);
+int set_ECC_mode(struct nand_chip *nand);
+void calculate_ECC_info(struct nand_chip *nand, struct ECC_size_info *ECC_size);
+int reset_nfc(void);
+int write_read_blk(struct nand_chip *nand,unsigned long *bbcheck_value);//for check dangerous ecc bit number
+int eslc_save_image_tpi(struct nand_chip *nand, unsigned long long naddr, unsigned int dwImageStart, unsigned int dwImageLength);
+int WMTSaveImageToNAND2(struct nand_chip *nand, unsigned long long naddr, unsigned int dwImageStart, unsigned int dwImageLength, int oob_offs, unsigned int need_erase, unsigned long long *eaddr);
+
+int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean);
+static int nand_do_read_oob(struct nand_chip *nand, size_t start, size_t ooblen,
+ size_t *retooblen, u_char *oob);
+
+static int nand_do_read_ops(struct nand_chip *nand, size_t start, size_t len,
+ size_t *retlen, u_char *buf, size_t ooblen, size_t *retooblen, u_char *oob);
+
+static int nand_do_write_oob(struct nand_chip *nand, size_t start, size_t ooblen,
+ size_t *retooblen, u_char *oob);
+
+static int nand_do_write_ops(struct nand_chip *nand, size_t start, size_t len,
+ size_t *retlen, u_char *buf, size_t ooblen, size_t *retooblen, u_char *oob);
+
+int update_bbt_inram_set_goodblk(struct nand_chip *nand, unsigned int block, int chip);
+int update_bbt_inram_set_w_e_badblk(struct nand_chip *nand, unsigned int block, int chip);
+int update_bbt_inram_set_r_badblk(struct nand_chip *nand, unsigned int block, int chip);
+int getbbtbadblock_detail(struct nand_chip *nand, unsigned int block, int chip);
+int parse_fbparts(char * env_str, char *str, int *ofs);
+
+/*
+static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,
+ size_t * retlen, u_char *buf, u_char *ecc_code);
+static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
+ size_t * retlen, const u_char * buf, u_char * ecc_code);
+static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
+ size_t * retlen, u_char * buf);
+*/
+static void nand_print_bad(struct nand_chip *nand);
+/*static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
+ size_t * retlen, u_char * buf);*/
+int nand_boot(struct nand_chip* nand, unsigned long long off, unsigned int mem_kernel, unsigned int mem_ramdisk, char *ramdiskSize);
+void rdmzier(uint8_t *buf, int size, int page);
+void rdmzier2(uint8_t *buf, int size, int page);
+void rdmzier_oob(uint8_t *buf, uint8_t *src, int size, int page, int ofs);
+int get_read_retry_para(struct nand_chip *nand);
+int set_read_retry_para(struct nand_chip *nand, int reg);
+/*static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
+ size_t * retlen, const u_char * buf);
+static int NanD_WaitReady(struct nand_chip *nand, int ale_wait);*/
+#ifdef CONFIG_MTD_NAND_ECC
+/*static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);*/
+#endif
+#define BYTE_SEED 2112
+unsigned int rdmz[BYTE_SEED]= {/*need to modify rdmzier2() if rdmz,BYTE_SEED are changed!!*/
+ 0xC5F7B49E, 0x85AD42B6, 0x1888A48B, 0xFBA90A42, 0xE20E7129, 0x37E8086E, 0x6F1C1918, 0x31510E20,
+ 0x382771CB, 0x6107F49D, 0x901B6D0B, 0x3CD489E1, 0xA9B9CE07, 0x6B41AC61, 0x749F181D, 0xA7DDA658,
+ 0x405276C0, 0xB67EFB43, 0xC5EE35A6, 0xF8406534, 0x73D8093A, 0xD98028A3, 0x084CE1AF, 0xB4744210,
+ 0x951E02A0, 0xF657482D, 0x6C64F9D0, 0x68DB8651, 0xD1E64A45, 0x3A0FCB39, 0x9C9BB663, 0x05322DAE,
+ 0xA4F40077, 0x801BA102, 0xB73BE0DD, 0xA2E34B6A, 0x5A50E576, 0x83CD0C99, 0x63C1440B, 0x2F82661D,
+ 0x6846C973, 0xA74C29E6, 0x880E86A2, 0xB1D7E000, 0xF9B6F2B5, 0x71E5F26C, 0xE707DE1E, 0x439D5A63,
+ 0x1F697817, 0x23DFB560, 0xE87F6BD0, 0xBD1BBCC3, 0xB1D3A074, 0x6C1B7C0A, 0xE2823FDB, 0x17F45131,
+ 0x9082625D, 0xDFD364FD, 0x88DF4E2B, 0xB6FE752D, 0x5B04FF38, 0xB27648A9, 0x8C4EF297, 0x1C595F00,
+ 0x9E7B4520, 0x826ADDFF, 0xF83FE0EE, 0xF981B0B0, 0x1F9233D7, 0xA2C148CB, 0xF73C908E, 0x18F36125,
+ 0xE45D3D77, 0xB77BA7EA, 0x6D962E25, 0xFF4BF3B8, 0x7C06714F, 0x812DFFDA, 0xE499B45A, 0x73498684,
+ 0x11DCD8C1, 0x0FE5FAEC, 0x882C8503, 0x1CBB95F8, 0x62889F09, 0xF6798B10, 0x7FFE1FE9, 0x464DBD35,
+ 0x476EA249, 0xD7D7428D, 0xD885740A, 0xA034FA2C, 0xB37FD49C, 0x9AC07AD5, 0xAEFA9F54, 0x80B1AC25,
+ 0xAFE642C5, 0x55249024, 0xC3BD79F8, 0x78D3CAB0, 0x71523E07, 0x179AD53B, 0x4C6DE12B, 0x545E4957,
+ 0xE19CDBF1, 0xB9CA4748, 0xD401EF16, 0x0C7FD0DC, 0x2D55D75B, 0x8169F899, 0xBE415FAA, 0x45355DFD,
+ 0x1EE42A38, 0x3E167903, 0x838D4BAE, 0xACB42144, 0x8A9970D3, 0x978DB4A5, 0x45A09237, 0x431554E5,
+ 0xAAD8AFF7, 0x4F260392, 0xF60E8E22, 0xDEFCBB1D, 0xA6903D2E, 0x0C041572, 0x32A1E06E, 0xD41C2E5A,
+ 0xE43F79E1, 0xD562B75D, 0x53B35557, 0x871CF712, 0x06130B69, 0x4FE6CACB, 0xA79121F3, 0x31D1804E,
+ 0xA6CDBB55, 0x2B31D900, 0x6F8D96A6, 0xF90DFE42, 0x3F8E6A88, 0x5D5F338E, 0x19BEFA53, 0xA80B5EC5,
+ 0x33A4BCC7, 0x7C6435D9, 0xE334EF6D, 0xDABCCF28, 0x0B1E822E, 0x6BC9A2E7, 0xC12ECFFD, 0xCB2410AA,
+ 0x5E239332, 0xD599FC9D, 0xD2ADA8FC, 0x985F0C4C, 0xA3FBD68F, 0x1A6857C8, 0x7CF1FA13, 0xBEC591B0,
+ 0x4E7219DC, 0xC7B5CA12, 0x31730D81, 0x954B0433, 0xFA399921, 0x17871477, 0xA42D4816, 0xAC692951,
+ 0x3346763F, 0x8097EFF0, 0x9727B982, 0x5D7D302F, 0xB4D28FAB, 0x33353379, 0xB438C5BB, 0xE49DF42E,
+ 0xE6E4083B, 0x82BB1576, 0xFF1675C3, 0x5B33BD3D, 0xDC018912, 0xC9886442, 0xA8F895ED, 0x99E15C12,
+ 0x45E855E8, 0xA73B2CD4, 0x290C2256, 0x510A601B, 0xB2DC458E, 0x9493508F, 0xEB9E844E, 0x0796D9AE,
+ 0x79741BD6, 0xEAAC9AE2, 0xC1990396, 0x3BB91B8F, 0x51D3287A, 0x9EAECDDD, 0x10EEC66D, 0xC9EA20D4,
+ 0xCAE1855A, 0xA7C42760, 0x3DBF5142, 0xDD2E56F2, 0xE7C71747, 0x1202F5B2, 0xF0444344, 0x2382331B,
+ 0xCF4AA7A2, 0xE037CA0B, 0x9CC2706C, 0xB7AA6F63, 0x6ABFBB08, 0x5DF9FE35, 0xBF95CB8A, 0xEA64D353,
+ 0xBB5DB139, 0xF25BBBB3, 0xB069B05E, 0x1FA571D2, 0xCCB68970, 0xB2FA065B, 0xAC52ABC8, 0xE3C72445,
+ 0x70F92FFD, 0x3292E21F, 0x2FC6615E, 0x329E2283, 0x9130F29F, 0x8736745B, 0x802463EF, 0xF2173C18,
+ 0xC1EA46D0, 0x0F1631C4, 0x226965D6, 0x2537F5C9, 0x26875CB0, 0x05C9666E, 0x25EAFDDC, 0x9F585A5C,
+ 0x12D33D3B, 0xF76DD669, 0x81303E96, 0x0CD91D67, 0x8B7EE682, 0xC306750F, 0x36B85254, 0xCB0AD397,
+ 0x4DB9750B, 0xFB0FC7F9, 0x442540F0, 0x758785F8, 0xE7E514E6, 0xBF6E804A, 0x6B7A2EF8, 0xA41E4A67,
+ 0x57B36655, 0xE5E72D5D, 0xC4C5AA32, 0x43A2988E, 0x5A45A4D2, 0x40D6B8DA, 0xBD39BF62, 0x1CBFD58C,
+ 0xF72511B6, 0x651E46A7, 0x8F0D90C6, 0x9552850B, 0x87D4BEA3, 0x7CD7B9C6, 0x86046AF7, 0x462BB9D7,
+ 0xB0DA3C41, 0x7A95F448, 0x5021FF8F, 0x093EB834, 0xBD0EFD67, 0x72C81437, 0xB2E38763, 0xD1BF8C4A,
+ 0x889789F4, 0x52D00D1C, 0xD8D07299, 0xAC5A2B20, 0xC89C393B, 0x5636B492, 0xD375FC40, 0x89F81123,
+ 0xB3EA1B56, 0xC7310408, 0x3A3449A0, 0x4C1AE419, 0xF55CEDA3, 0x01415BEA, 0xF2A0F073, 0x31774DF5,
+ 0x00E68A8C, 0x695E5496, 0xE7749B58, 0x77327028, 0x6CD335BB, 0x98468D74, 0xDE16F10D, 0x7138FA79,
+ 0x5ED8D8F2, 0x54870136, 0xCDEE53A2, 0x3DB7D1AA, 0xF6754B8C, 0xC1088C28, 0xF3E5EBED, 0x567A3339,
+ 0xA2F60ACE, 0x994B5135, 0x5D35F7F0, 0x50FCF79A, 0xB0E1BED8, 0xAA14A632, 0xA04F3F82, 0xAC8BE3A9,
+ 0xCFB5AC16, 0xF484B91F, 0x10E64685, 0xE2B13DAA, 0xEC2E1E35, 0x4623393F, 0x9B81213F, 0x5C5A6F27,
+ 0xB1C6E1D0, 0xAF00C849, 0x3C7AC4B2, 0x24C9E2A0, 0x0FE1BA98, 0x1D810BBC, 0x8FDC584F, 0x927B1026,
+ 0x2566B32E, 0xBF440303, 0xED4D467E, 0x19EFBCB4, 0x31C80176, 0xDB209CD7, 0x406174B1, 0x4DA4B447,
+ 0x134F6EC4, 0xBC1220F6, 0xA75D2836, 0xDEB8BC5E, 0xFC48D6DE, 0x3A78CE0B, 0x3D991297, 0xE5EFADB5,
+ 0xEF9EB74C, 0x656D03E1, 0xBBA2BA8D, 0xE6E8C8A7, 0x3C4D86B7, 0x4ABE231B, 0x4A272C4D, 0xA920C151,
+ 0x8846417D, 0x55F99831, 0x7A627F14, 0x6FC991E5, 0xA3D515B2, 0x09F2B1F1, 0x5267C177, 0x284D79BC,
+ 0xA3AA9068, 0x83AB087B, 0x9475DA03, 0x82C0D0D8, 0xE0E242F6, 0x0E466BFE, 0x867FAF59, 0x59DF8EE2,
+ 0xE5AFEA82, 0x20EBD203, 0xC076152F, 0x4469C75B, 0x04047376, 0xF75654F0, 0x51B16CEC, 0xFCB7DD6A,
+ 0x2ECBBD1F, 0xB1BD247E, 0xB0F4FF7C, 0x690F1271, 0x7EB7C4EB, 0x9FB65038, 0x50D674D3, 0x36D6D65E,
+ 0x17E550E1, 0xC63458A1, 0x924C5223, 0x4B117295, 0xFA8295D6, 0x59EC8C93, 0x1E75A586, 0xF64A8961,
+ 0x842450ED, 0x90ECE657, 0x033CE78B, 0x03526381, 0xDFBDE0F7, 0x5430CD5D, 0x3D735887, 0x32476AE2,
+ 0xBD427ACC, 0x034BE2B9, 0xA250C775, 0x3F6060EC, 0x1F5A7A66, 0xD805FA64, 0x3EDE30B2, 0xF949F901,
+ 0x65568178, 0x6B23E8F7, 0x168608AA, 0x99F8DD2A, 0x3805726A, 0xCC6B8165, 0x0B2500B7, 0xBB48F09D,
+ 0x31400FF0, 0x6E914B37, 0x2C98C243, 0x53D551B5, 0x70A8691A, 0xAB51BDAC, 0xC742414E, 0x0E9B63EB,
+ 0x3FA0A9B5, 0x4EC5D5B7, 0x3728C137, 0x3E83B6C9, 0xDE7C3573, 0x387AF7B0, 0x463238EF, 0xCD371BC3,
+ 0x11C559F9, 0x7208DD6E, 0xE37C28B2, 0x3E92B719, 0x88CA0F8F, 0x75E5C16E, 0x85FC0451, 0x814BFB38,
+ 0x132D2A52, 0xDE0B3041, 0x99785344, 0xA6EFB8F4, 0x865DACF8, 0xF4B3FB1A, 0x7E91873E, 0xA777AB7F,
+ 0x588FD4D8, 0x41B9200D, 0x5C03A928, 0x035EA31D, 0x614B7336, 0xE1989B85, 0x2C67C9F7, 0x476622A1,
+ 0xFC8C5FF3, 0xFE4AEF65, 0x41D3E473, 0x1541A4E1, 0x1BB44300, 0xF8FB69C3, 0x3DB391DE, 0x63D8C533,
+ 0x526F419F, 0x031664C2, 0x85650B07, 0x624C1624, 0x324BAA7E, 0x03B4E90D, 0xB6E3B461, 0xB3445605,
+ 0x4A4128AF, 0x5E945F59, 0x2504F7B8, 0xDD5D13B4, 0xD3683D0C, 0x61B8B81E, 0x4BDD7B50, 0x15EBA9C6,
+ 0x0369E118, 0x0F3CB28D, 0xA45E0D50, 0x98C6031A, 0x40FC3B93, 0x3B0ED7E4, 0xA14E235F, 0x915E7695,
+ 0x5BD9F72D, 0x0BA94E45, 0x9B54A9C2, 0xCEDE74B5, 0x801321EA, 0x9C60FDA3, 0x842CD005, 0xBBB7FB29,
+ 0x25F37CE4, 0xE2B57DDE, 0x7983908A, 0xD544F488, 0x6B72AE10, 0x8F455719, 0x717CFD3A, 0x04003302,
+ 0x62FBDA4F, 0xC2D6A15B, 0x0C445245, 0xFDD48521, 0x71073894, 0x1BF40437, 0x378E0C8C, 0x98A88710,
+ 0x9C13B8E5, 0xB083FA4E, 0xC80DB685, 0x9E6A44F0, 0xD4DCE703, 0xB5A0D630, 0x3A4F8C0E, 0x53EED32C,
+ 0xA0293B60, 0x5B3F7DA1, 0x62F71AD3, 0x7C20329A, 0xB9EC049D, 0xECC01451, 0x042670D7, 0x5A3A2108,
+ 0xCA8F0150, 0x7B2BA416, 0xB6327CE8, 0xB46DC328, 0xE8F32522, 0x9D07E59C, 0x4E4DDB31, 0x829916D7,
+ 0x527A003B, 0xC00DD081, 0x5B9DF06E, 0x5171A5B5, 0xAD2872BB, 0xC1E6864C, 0xB1E0A205, 0x97C1330E,
+ 0x342364B9, 0x53A614F3, 0x44074351, 0xD8EBF000, 0x7CDB795A, 0x38F2F936, 0xF383EF0F, 0xA1CEAD31,
+ 0x0FB4BC0B, 0x11EFDAB0, 0xF43FB5E8, 0x5E8DDE61, 0x58E9D03A, 0xB60DBE05, 0xF1411FED, 0x8BFA2898,
+ 0xC841312E, 0xEFE9B27E, 0xC46FA715, 0x5B7F3A96, 0xAD827F9C, 0xD93B2454, 0x4627794B, 0x0E2CAF80,
+ 0xCF3DA290, 0x41356EFF, 0x7C1FF077, 0xFCC0D858, 0x8FC919EB, 0x5160A465, 0xFB9E4847, 0x8C79B092,
+ 0x722E9EBB, 0xDBBDD3F5, 0x36CB1712, 0xFFA5F9DC, 0x3E0338A7, 0x4096FFED, 0x724CDA2D, 0xB9A4C342,
+ 0x08EE6C60, 0x87F2FD76, 0x44164281, 0x8E5DCAFC, 0x31444F84, 0xFB3CC588, 0xBFFF0FF4, 0xA326DE9A,
+ 0xA3B75124, 0x6BEBA146, 0x6C42BA05, 0x501A7D16, 0xD9BFEA4E, 0x4D603D6A, 0xD77D4FAA, 0xC058D612,
+ 0x57F32162, 0x2A924812, 0x61DEBCFC, 0xBC69E558, 0xB8A91F03, 0x8BCD6A9D, 0xA636F095, 0xAA2F24AB,
+ 0x70CE6DF8, 0x5CE523A4, 0x6A00F78B, 0x863FE86E, 0x96AAEBAD, 0x40B4FC4C, 0xDF20AFD5, 0x229AAEFE,
+ 0x8F72151C, 0x1F0B3C81, 0x41C6A5D7, 0xD65A10A2, 0xC54CB869, 0xCBC6DA52, 0xA2D0491B, 0xA18AAA72,
+ 0x556C57FB, 0x279301C9, 0xFB074711, 0x6F7E5D8E, 0x53481E97, 0x06020AB9, 0x1950F037, 0xEA0E172D,
+ 0xF21FBCF0, 0xEAB15BAE, 0x29D9AAAB, 0xC38E7B89, 0x830985B4, 0xA7F36565, 0x53C890F9, 0x98E8C027,
+ 0x5366DDAA, 0x1598EC80, 0x37C6CB53, 0x7C86FF21, 0x1FC73544, 0xAEAF99C7, 0x8CDF7D29, 0xD405AF62,
+ 0x99D25E63, 0xBE321AEC, 0x719A77B6, 0x6D5E6794, 0x858F4117, 0xB5E4D173, 0x609767FE, 0x65920855,
+ 0xAF11C999, 0x6ACCFE4E, 0x6956D47E, 0xCC2F8626, 0x51FDEB47, 0x8D342BE4, 0x3E78FD09, 0x5F62C8D8,
+ 0x27390CEE, 0xE3DAE509, 0x98B986C0, 0xCAA58219, 0xFD1CCC90, 0x0BC38A3B, 0xD216A40B, 0xD63494A8,
+ 0x19A33B1F, 0x404BF7F8, 0xCB93DCC1, 0xAEBE9817, 0xDA6947D5, 0x999A99BC, 0x5A1C62DD, 0xF24EFA17,
+ 0x7372041D, 0xC15D8ABB, 0xFF8B3AE1, 0x2D99DE9E, 0x6E00C489, 0xE4C43221, 0x547C4AF6, 0x4CF0AE09,
+ 0x22F42AF4, 0x539D966A, 0x9486112B, 0x2885300D, 0xD96E22C7, 0x4A49A847, 0x75CF4227, 0x03CB6CD7,
+ 0x3CBA0DEB, 0x75564D71, 0xE0CC81CB, 0x1DDC8DC7, 0xA8E9943D, 0xCF5766EE, 0x08776336, 0x64F5106A,
+ 0x6570C2AD, 0x53E213B0, 0x1EDFA8A1, 0xEE972B79, 0x73E38BA3, 0x09017AD9, 0xF82221A2, 0x11C1198D,
+ 0xE7A553D1, 0x701BE505, 0xCE613836, 0x5BD537B1, 0xB55FDD84, 0x2EFCFF1A, 0xDFCAE5C5, 0xF53269A9,
+ 0xDDAED89C, 0x792DDDD9, 0x5834D82F, 0x0FD2B8E9, 0xE65B44B8, 0x597D032D, 0xD62955E4, 0xF1E39222,
+ 0xB87C97FE, 0x1949710F, 0x97E330AF, 0x994F1141, 0xC898794F, 0xC39B3A2D, 0x401231F7, 0x790B9E0C,
+ 0x60F52368, 0x078B18E2, 0x9134B2EB, 0x129BFAE4, 0x1343AE58, 0x02E4B337, 0x12F57EEE, 0xCFAC2D2E,
+ 0x89699E9D, 0x7BB6EB34, 0xC0981F4B, 0x066C8EB3, 0xC5BF7341, 0x61833A87, 0x9B5C292A, 0xE58569CB,
+ 0xA6DCBA85, 0x7D87E3FC, 0x2212A078, 0x3AC3C2FC, 0x73F28A73, 0x5FB74025, 0xB5BD177C, 0xD20F2533,
+ 0xABD9B32A, 0x72F396AE, 0x6262D519, 0x21D14C47, 0x2D22D269, 0x206B5C6D, 0x5E9CDFB1, 0x0E5FEAC6,
+ 0xFB9288DB, 0x328F2353, 0xC786C863, 0xCAA94285, 0x43EA5F51, 0xBE6BDCE3, 0xC302357B, 0xA315DCEB,
+ 0x586D1E20, 0xBD4AFA24, 0x2810FFC7, 0x849F5C1A, 0xDE877EB3, 0xB9640A1B, 0x5971C3B1, 0x68DFC625,
+ 0x444BC4FA, 0xA968068E, 0x6C68394C, 0xD62D1590, 0x644E1C9D, 0x2B1B5A49, 0xE9BAFE20, 0x44FC0891,
+ 0x59F50DAB, 0x63988204, 0x9D1A24D0, 0xA60D720C, 0x7AAE76D1, 0x80A0ADF5, 0xF9507839, 0x18BBA6FA,
+ 0x00734546, 0x34AF2A4B, 0x73BA4DAC, 0xBB993814, 0x36699ADD, 0xCC2346BA, 0xEF0B7886, 0x389C7D3C,
+ 0x2F6C6C79, 0x2A43809B, 0x66F729D1, 0x1EDBE8D5, 0x7B3AA5C6, 0xE0844614, 0xF9F2F5F6, 0x2B3D199C,
+ 0xD17B0567, 0x4CA5A89A, 0x2E9AFBF8, 0x287E7BCD, 0x5870DF6C, 0x550A5319, 0xD0279FC1, 0x5645F1D4,
+ 0xE7DAD60B, 0xFA425C8F, 0x08732342, 0xF1589ED5, 0xF6170F1A, 0xA3119C9F, 0xCDC0909F, 0x2E2D3793,
+ 0xD8E370E8, 0x57806424, 0x1E3D6259, 0x1264F150, 0x07F0DD4C, 0x8EC085DE, 0x47EE2C27, 0x493D8813,
+ 0x92B35997, 0x5FA20181, 0x76A6A33F, 0x0CF7DE5A, 0x98E400BB, 0xED904E6B, 0xA030BA58, 0x26D25A23,
+ 0x09A7B762, 0x5E09107B, 0x53AE941B, 0x6F5C5E2F, 0xFE246B6F, 0x9D3C6705, 0x9ECC894B, 0x72F7D6DA,
+ 0xF7CF5BA6, 0xB2B681F0, 0xDDD15D46, 0xF3746453, 0x9E26C35B, 0xA55F118D, 0xA5139626, 0xD49060A8,
+ 0xC42320BE, 0x2AFCCC18, 0xBD313F8A, 0x37E4C8F2, 0xD1EA8AD9, 0x84F958F8, 0x2933E0BB, 0x1426BCDE,
+ 0xD1D54834, 0xC1D5843D, 0x4A3AED01, 0x4160686C, 0x7071217B, 0x872335FF, 0x433FD7AC, 0x2CEFC771,
+ 0xF2D7F541, 0x9075E901, 0xE03B0A97, 0x2234E3AD, 0x020239BB, 0x7BAB2A78, 0x28D8B676, 0xFE5BEEB5,
+ 0x1765DE8F, 0x58DE923F, 0xD87A7FBE, 0xB4878938, 0x3F5BE275, 0xCFDB281C, 0x286B3A69, 0x9B6B6B2F,
+ 0x8BF2A870, 0xE31A2C50, 0xC9262911, 0x2588B94A, 0xFD414AEB, 0x2CF64649, 0x8F3AD2C3, 0xFB2544B0,
+ 0xC2122876, 0xC876732B, 0x819E73C5, 0x81A931C0, 0xEFDEF07B, 0xAA1866AE, 0x1EB9AC43, 0x1923B571,
+ 0xDEA13D66, 0x81A5F15C, 0x512863BA, 0x1FB03076, 0x0FAD3D33, 0x6C02FD32, 0x9F6F1859, 0x7CA4FC80,
+ 0xB2AB40BC, 0x3591F47B, 0x0B430455, 0x4CFC6E95, 0x9C02B935, 0xE635C0B2, 0x8592805B, 0x5DA4784E,
+ 0x98A007F8, 0xB748A59B, 0x964C6121, 0x29EAA8DA, 0x3854348D, 0x55A8DED6, 0xE3A120A7, 0x874DB1F5,
+ 0x9FD054DA, 0xA762EADB, 0x9B94609B, 0x9F41DB64, 0x6F3E1AB9, 0x9C3D7BD8, 0xA3191C77, 0xE69B8DE1,
+ 0x08E2ACFC, 0x39046EB7, 0xF1BE1459, 0x9F495B8C, 0x446507C7, 0xBAF2E0B7, 0x42FE0228, 0x40A5FD9C,
+ 0x89969529, 0x6F059820, 0x4CBC29A2, 0x5377DC7A, 0x432ED67C, 0x7A59FD8D, 0xBF48C39F, 0x53BBD5BF,
+ 0xAC47EA6C, 0x20DC9006, 0xAE01D494, 0x01AF518E, 0xB0A5B99B, 0xF0CC4DC2, 0x9633E4FB, 0xA3B31150,
+ 0xFE462FF9, 0xFF2577B2, 0xA0E9F239, 0x0AA0D270, 0x8DDA2180, 0x7C7DB4E1, 0x9ED9C8EF, 0xB1EC6299,
+ 0x2937A0CF, 0x818B3261, 0x42B28583, 0x31260B12, 0x9925D53F, 0x81DA7486, 0xDB71DA30, 0xD9A22B02,
+ 0xA5209457, 0x2F4A2FAC, 0x12827BDC, 0x6EAE89DA, 0x69B41E86, 0x30DC5C0F, 0x25EEBDA8, 0x0AF5D4E3,
+ 0x81B4F08C, 0x079E5946, 0x522F06A8, 0xCC63018D, 0x207E1DC9, 0x9D876BF2, 0xD0A711AF, 0xC8AF3B4A,
+ 0xADECFB96, 0x05D4A722, 0xCDAA54E1, 0x676F3A5A, 0xC00990F5, 0xCE307ED1, 0xC2166802, 0x5DDBFD94,
+ 0x12F9BE72, 0x715ABEEF, 0x3CC1C845, 0x6AA27A44, 0xB5B95708, 0x47A2AB8C, 0x38BE7E9D, 0x82001981,
+ 0xB17DED27, 0xE16B50AD, 0x86222922, 0x7EEA4290, 0xB8839C4A, 0x0DFA021B, 0x1BC70646, 0xCC544388,
+ 0x4E09DC72, 0xD841FD27, 0x6406DB42, 0xCF352278, 0x6A6E7381, 0x5AD06B18, 0x1D27C607, 0x29F76996,
+ 0xD0149DB0, 0xAD9FBED0, 0x317B8D69, 0xBE10194D, 0xDCF6024E, 0xF6600A28, 0x0213386B, 0x2D1D1084,
+ 0x654780A8, 0x3D95D20B, 0x5B193E74, 0x5A36E194, 0x74799291, 0xCE83F2CE, 0xA726ED98, 0xC14C8B6B,
+ 0xA93D001D, 0x6006E840, 0xADCEF837, 0xA8B8D2DA, 0x5694395D, 0xE0F34326, 0x58F05102, 0xCBE09987,
+ 0x9A11B25C, 0xA9D30A79, 0x2203A1A8, 0x6C75F800, 0x3E6DBCAD, 0x9C797C9B, 0xF9C1F787, 0xD0E75698,
+ 0x07DA5E05, 0x08F7ED58, 0xFA1FDAF4, 0x2F46EF30, 0xAC74E81D, 0xDB06DF02, 0x78A08FF6, 0x45FD144C,
+ 0x64209897, 0xF7F4D93F, 0x6237D38A, 0x2DBF9D4B, 0x56C13FCE, 0xEC9D922A, 0x2313BCA5, 0x071657C0,
+ 0xE79ED148, 0xA09AB77F, 0x3E0FF83B, 0xFE606C2C, 0xC7E48CF5, 0xA8B05232, 0x7DCF2423, 0xC63CD849,
+ 0xB9174F5D, 0x6DDEE9FA, 0x1B658B89, 0xFFD2FCEE, 0x9F019C53, 0xA04B7FF6, 0x39266D16, 0x5CD261A1,
+ 0x04773630, 0xC3F97EBB, 0x220B2140, 0x472EE57E, 0x18A227C2, 0x7D9E62C4, 0x5FFF87FA, 0x51936F4D,
+ 0x51DBA892, 0xB5F5D0A3, 0x36215D02, 0x280D3E8B, 0x6CDFF527, 0x26B01EB5, 0x6BBEA7D5, 0x602C6B09,
+ 0x2BF990B1, 0x15492409, 0x30EF5E7E, 0xDE34F2AC, 0xDC548F81, 0xC5E6B54E, 0xD31B784A, 0x55179255,
+ 0x386736FC, 0xAE7291D2, 0x35007BC5, 0xC31FF437, 0x4B5575D6, 0xA05A7E26, 0x6F9057EA, 0x114D577F,
+ 0xC7B90A8E, 0x8F859E40, 0x20E352EB, 0xEB2D0851, 0x62A65C34, 0xE5E36D29, 0x5168248D, 0xD0C55539,
+ 0xAAB62BFD, 0x93C980E4, 0x7D83A388, 0xB7BF2EC7, 0xA9A40F4B, 0x8301055C, 0x8CA8781B, 0x75070B96,
+ 0x790FDE78, 0xF558ADD7, 0x94ECD555, 0x61C73DC4, 0xC184C2DA, 0xD3F9B2B2, 0xA9E4487C, 0x4C746013,
+ 0x29B36ED5, 0x8ACC7640, 0x9BE365A9, 0x3E437F90, 0x8FE39AA2, 0xD757CCE3, 0x466FBE94, 0xEA02D7B1,
+ 0x4CE92F31, 0x5F190D76, 0x38CD3BDB, 0xB6AF33CA, 0xC2C7A08B, 0x5AF268B9, 0xB04BB3FF, 0xB2C9042A,
+ 0x5788E4CC, 0x35667F27, 0x34AB6A3F, 0xE617C313, 0x28FEF5A3, 0xC69A15F2, 0x1F3C7E84, 0x2FB1646C,
+ 0x939C8677, 0x71ED7284, 0xCC5CC360, 0x6552C10C, 0xFE8E6648, 0x85E1C51D, 0x690B5205, 0xEB1A4A54,
+ 0x0CD19D8F, 0xA025FBFC, 0xE5C9EE60, 0xD75F4C0B, 0x6D34A3EA, 0xCCCD4CDE, 0xAD0E316E, 0xF9277D0B,
+ 0xB9B9020E, 0xE0AEC55D, 0x7FC59D70, 0x96CCEF4F, 0xB7006244, 0x72621910, 0xAA3E257B, 0x26785704,
+ 0x117A157A, 0xA9CECB35, 0xCA430895, 0x94429806, 0xECB71163, 0xA524D423, 0xBAE7A113, 0x81E5B66B,
+ 0x9E5D06F5, 0xBAAB26B8, 0xF06640E5, 0x8EEE46E3, 0x5474CA1E, 0x67ABB377, 0x043BB19B, 0xB27A8835,
+ 0x32B86156, 0xA9F109D8, 0x8F6FD450, 0xF74B95BC, 0xB9F1C5D1, 0x0480BD6C, 0xFC1110D1, 0x88E08CC6,
+ 0xF3D2A9E8, 0x380DF282, 0xE7309C1B, 0x2DEA9BD8, 0x5AAFEEC2, 0x977E7F8D, 0xEFE572E2, 0x7A9934D4,
+ 0xEED76C4E, 0xBC96EEEC, 0xAC1A6C17, 0x07E95C74, 0xF32DA25C, 0x2CBE8196, 0x6B14AAF2, 0x78F1C911,
+ 0xDC3E4BFF, 0x8CA4B887, 0xCBF19857, 0xCCA788A0, 0xE44C3CA7, 0xE1CD9D16, 0x200918FB, 0x3C85CF06,
+ 0x307A91B4, 0x83C58C71, 0x489A5975, 0x094DFD72, 0x89A1D72C, 0x0172599B, 0x097ABF77, 0xE7D61697,
+ 0x44B4CF4E, 0xBDDB759A, 0xE04C0FA5, 0x83364759, 0xE2DFB9A0, 0x30C19D43, 0xCDAE1495, 0xF2C2B4E5,
+ 0x536E5D42, 0x3EC3F1FE, 0x1109503C, 0x9D61E17E, 0xB9F94539, 0x2FDBA012, 0xDADE8BBE, 0x69079299,
+ 0x55ECD995, 0xB979CB57, 0xB1316A8C, 0x90E8A623, 0x96916934, 0x9035AE36, 0x2F4E6FD8, 0x872FF563,
+ 0xFDC9446D, 0x994791A9, 0xE3C36431, 0xE554A142, 0xA1F52FA8, 0xDF35EE71, 0xE1811ABD, 0x518AEE75,
+ 0x2C368F10, 0xDEA57D12, 0x14087FE3, 0xC24FAE0D, 0xEF43BF59, 0xDCB2050D, 0xACB8E1D8, 0x346FE312,
+ 0x2225E27D, 0x54B40347, 0x36341CA6, 0xEB168AC8, 0xB2270E4E, 0x158DAD24, 0xF4DD7F10, 0xA27E0448,
+ 0x2CFA86D5, 0x31CC4102, 0x4E8D1268, 0xD306B906, 0xBD573B68, 0xC05056FA, 0x7CA83C1C, 0x0C5DD37D,
+ 0x8039A2A3, 0x1A579525, 0x39DD26D6, 0xDDCC9C0A, 0x1B34CD6E, 0x6611A35D, 0x7785BC43, 0x9C4E3E9E,
+ 0x97B6363C, 0x9521C04D, 0xB37B94E8, 0x0F6DF46A, 0x3D9D52E3, 0x7042230A, 0x7CF97AFB, 0x959E8CCE,
+ 0x68BD82B3, 0x2652D44D, 0x974D7DFC, 0x143F3DE6, 0xAC386FB6, 0xAA85298C, 0x6813CFE0, 0xAB22F8EA,
+ 0xF3ED6B05, 0x7D212E47, 0x843991A1, 0x78AC4F6A, 0xFB0B878D, 0xD188CE4F, 0xE6E0484F, 0x17169BC9,
+ 0x6C71B874, 0xABC03212, 0x0F1EB12C, 0x093278A8, 0x03F86EA6, 0xC76042EF, 0xA3F71613, 0xA49EC409,
+ 0xC959ACCB, 0xAFD100C0, 0x3B53519F, 0x867BEF2D, 0xCC72005D, 0x76C82735, 0xD0185D2C, 0x13692D11,
+ 0x84D3DBB1, 0xAF04883D, 0xA9D74A0D, 0xB7AE2F17, 0xFF1235B7, 0xCE9E3382, 0x4F6644A5, 0x397BEB6D,
+ 0x7BE7ADD3, 0x595B40F8, 0xEEE8AEA3, 0xF9BA3229, 0xCF1361AD, 0x52AF88C6, 0x5289CB13, 0x6A483054,
+ 0x6211905F, 0x157E660C, 0x5E989FC5, 0x9BF26479, 0x68F5456C, 0xC27CAC7C, 0x1499F05D, 0x0A135E6F,
+ 0xE8EAA41A, 0xE0EAC21E, 0x251D7680, 0xA0B03436, 0xB83890BD, 0x43919AFF, 0xA19FEBD6, 0x9677E3B8,
+ 0xF96BFAA0, 0xC83AF480, 0xF01D854B, 0x911A71D6, 0x01011CDD, 0x3DD5953C, 0x946C5B3B, 0xFF2DF75A,
+ 0x8BB2EF47, 0x2C6F491F, 0x6C3D3FDF, 0xDA43C49C, 0x1FADF13A, 0xE7ED940E, 0x94359D34, 0x4DB5B597,
+ 0x45F95438, 0xF18D1628, 0x64931488, 0x92C45CA5, 0xFEA0A575, 0x967B2324, 0x479D6961, 0x7D92A258,
+ 0xE109143B, 0xE43B3995, 0x40CF39E2, 0xC0D498E0, 0x77EF783D, 0xD50C3357, 0x8F5CD621, 0x0C91DAB8,
+ 0x6F509EB3, 0x40D2F8AE, 0x289431DD, 0x8FD8183B, 0x07D69E99, 0xB6017E99, 0x4FB78C2C, 0x3E527E40,
+ 0xD955A05E, 0x9AC8FA3D, 0x85A1822A, 0xA67E374A, 0x4E015C9A, 0xF31AE059, 0x42C9402D, 0x2ED23C27,
+ 0xCC5003FC, 0xDBA452CD, 0x4B263090, 0x94F5546D, 0x1C2A1A46, 0xAAD46F6B, 0xF1D09053, 0x43A6D8FA,
+ 0xCFE82A6D, 0xD3B1756D, 0x4DCA304D, 0xCFA0EDB2, 0x379F0D5C, 0xCE1EBDEC, 0xD18C8E3B, 0x734DC6F0,
+ 0x8471567E, 0x9C82375B, 0x78DF0A2C, 0xCFA4ADC6, 0xA23283E3, 0x5D79705B, 0x217F0114, 0xA052FECE,
+ 0x44CB4A94, 0x3782CC10, 0x265E14D1, 0x29BBEE3D, 0xA1976B3E, 0xBD2CFEC6, 0xDFA461CF, 0x29DDEADF,
+ 0x5623F536, 0x106E4803, 0x5700EA4A, 0x80D7A8C7, 0x5852DCCD, 0xF86626E1, 0x4B19F27D, 0xD1D988A8,
+ 0x7F2317FC, 0xFF92BBD9, 0x5074F91C, 0x05506938, 0xC6ED10C0, 0xBE3EDA70, 0xCF6CE477, 0xD8F6314C,
+ 0x949BD067, 0xC0C59930, 0x215942C1, 0x98930589, 0x4C92EA9F, 0x40ED3A43, 0x6DB8ED18, 0xECD11581,
+ 0x52904A2B, 0x17A517D6, 0x09413DEE, 0x375744ED, 0xB4DA0F43, 0x186E2E07, 0x92F75ED4, 0x057AEA71,
+ 0x40DA7846, 0x03CF2CA3, 0xA9178354, 0xE63180C6, 0x103F0EE4, 0xCEC3B5F9, 0x685388D7, 0x64579DA5,
+ 0x56F67DCB, 0x82EA5391, 0x66D52A70, 0xB3B79D2D, 0xE004C87A, 0x67183F68, 0x610B3401, 0x2EEDFECA,
+ 0x897CDF39, 0xB8AD5F77, 0x1E60E422, 0x35513D22, 0x5ADCAB84, 0xA3D155C6, 0x9C5F3F4E, 0xC1000CC0,
+ 0xD8BEF693, 0x70B5A856, 0x43111491, 0x3F752148, 0xDC41CE25, 0x06FD010D, 0x0DE38323, 0x662A21C4,
+ 0xA704EE39, 0x6C20FE93, 0x32036DA1, 0xE79A913C, 0x353739C0, 0xAD68358C, 0x0E93E303, 0x14FBB4CB,
+ 0x680A4ED8, 0xD6CFDF68, 0x98BDC6B4, 0x5F080CA6, 0x6E7B0127, 0xFB300514, 0x01099C35, 0x168E8842,
+ 0xB2A3C054, 0x1ECAE905, 0x2D8C9F3A, 0xAD1B70CA, 0x3A3CC948, 0x6741F967, 0xD39376CC, 0xE0A645B5,
+ 0x549E800E, 0xB0037420, 0x56E77C1B, 0xD45C696D, 0x2B4A1CAE, 0x7079A193, 0xAC782881, 0x65F04CC3,
+ 0xCD08D92E, 0x54E9853C, 0x1101D0D4, 0xB63AFC00, 0x9F36DE56, 0xCE3CBE4D, 0x7CE0FBC3, 0xE873AB4C,
+ 0x03ED2F02, 0x047BF6AC, 0x7D0FED7A, 0x97A37798, 0x563A740E, 0x6D836F81, 0x3C5047FB, 0xA2FE8A26,
+ 0xB2104C4B, 0x7BFA6C9F, 0xB11BE9C5, 0x16DFCEA5, 0x2B609FE7, 0xF64EC915, 0x1189DE52, 0x038B2BE0,
+ 0xF3CF68A4, 0xD04D5BBF, 0x1F07FC1D, 0xFF303616, 0x63F2467A, 0xD4582919, 0xBEE79211, 0xE31E6C24,
+ 0x5C8BA7AE, 0xB6EF74FD, 0x0DB2C5C4, 0xFFE97E77, 0x4F80CE29, 0x5025BFFB, 0x9C93368B, 0x2E6930D0,
+ 0x823B9B18, 0x61FCBF5D, 0x110590A0, 0x239772BF, 0x0C5113E1, 0x3ECF3162, 0xAFFFC3FD, 0x28C9B7A6,
+ 0xA8EDD449, 0x5AFAE851, 0x9B10AE81, 0x94069F45, 0xB66FFA93, 0x93580F5A, 0xB5DF53EA, 0xB0163584,
+ 0x95FCC858, 0x0AA49204, 0x1877AF3F, 0xEF1A7956, 0x6E2A47C0, 0x62F35AA7, 0xE98DBC25, 0x2A8BC92A,
+ 0x1C339B7E, 0xD73948E9, 0x9A803DE2, 0x618FFA1B, 0x25AABAEB, 0x502D3F13, 0xB7C82BF5, 0x08A6ABBF,
+ 0x63DC8547, 0xC7C2CF20, 0x9071A975, 0x75968428, 0xB1532E1A, 0xF2F1B694, 0xA8B41246, 0xE862AA9C,
+ 0x555B15FE, 0x49E4C072, 0xBEC1D1C4, 0xDBDF9763, 0x54D207A5, 0xC18082AE, 0x46543C0D, 0x3A8385CB,
+ 0xBC87EF3C, 0xFAAC56EB, 0x4A766AAA, 0x30E39EE2, 0x60C2616D, 0x69FCD959, 0xD4F2243E, 0xA63A3009,
+ 0x14D9B76A, 0xC5663B20, 0x4DF1B2D4, 0x1F21BFC8, 0xC7F1CD51, 0x6BABE671, 0xA337DF4A, 0xF5016BD8,
+ 0x26749798, 0xAF8C86BB, 0x1C669DED, 0xDB5799E5, 0xE163D045, 0xAD79345C, 0x5825D9FF, 0x59648215,
+ 0xABC47266, 0x9AB33F93, 0x9A55B51F, 0xF30BE189, 0x147F7AD1, 0x634D0AF9, 0x0F9E3F42, 0x97D8B236,
+ 0x49CE433B, 0x38F6B942, 0x662E61B0, 0x32A96086, 0xFF473324, 0xC2F0E28E, 0x3485A902, 0xF58D252A,
+ 0x0668CEC7, 0x5012FDFE, 0xF2E4F730, 0x6BAFA605, 0x369A51F5, 0x6666A66F, 0xD68718B7, 0x7C93BE85,
+ 0xDCDC8107, 0x705762AE, 0xBFE2CEB8, 0x4B6677A7, 0x5B803122, 0xB9310C88, 0x551F12BD, 0x133C2B82,
+ 0x88BD0ABD, 0xD4E7659A, 0x6521844A, 0xCA214C03, 0xF65B88B1, 0xD2926A11, 0xDD73D089, 0xC0F2DB35,
+ 0x4F2E837A, 0xDD55935C, 0xF8332072, 0x47772371, 0xAA3A650F, 0xB3D5D9BB, 0x821DD8CD, 0x593D441A,
+ 0x195C30AB, 0x54F884EC, 0x47B7EA28, 0xFBA5CADE, 0x5CF8E2E8, 0x82405EB6, 0x7E088868, 0x44704663,
+ 0x79E954F4, 0x9C06F941, 0x73984E0D, 0x16F54DEC, 0xAD57F761, 0x4BBF3FC6, 0x77F2B971, 0x3D4C9A6A,
+ 0x776BB627, 0xDE4B7776, 0x560D360B, 0x03F4AE3A, 0x7996D12E, 0x165F40CB, 0xB58A5579, 0xBC78E488,
+ 0xEE1F25FF, 0xC6525C43, 0x65F8CC2B, 0xE653C450, 0x72261E53, 0xF0E6CE8B, 0x10048C7D, 0x1E42E783,
+ 0x983D48DA, 0xC1E2C638, 0x244D2CBA, 0x04A6FEB9, 0xC4D0EB96, 0x80B92CCD, 0x84BD5FBB, 0x73EB0B4B,
+ 0x225A67A7, 0xDEEDBACD, 0xF02607D2, 0x419B23AC, 0xF16FDCD0, 0x9860CEA1, 0xE6D70A4A, 0x79615A72,
+ 0x29B72EA1, 0x1F61F8FF, 0x0884A81E, 0xCEB0F0BF, 0x5CFCA29C, 0x17EDD009, 0xED6F45DF, 0xB483C94C,
+ 0xAAF66CCA, 0x5CBCE5AB, 0xD898B546, 0x48745311, 0x4B48B49A, 0x481AD71B, 0x97A737EC, 0xC397FAB1,
+ 0xFEE4A236, 0xCCA3C8D4, 0x71E1B218, 0x72AA50A1, 0xD0FA97D4, 0xEF9AF738, 0xF0C08D5E, 0x28C5773A,
+ 0x161B4788, 0xEF52BE89, 0x8A043FF1, 0xE127D706, 0xF7A1DFAC, 0x6E590286, 0x565C70EC, 0x9A37F189,
+ 0x9112F13E, 0x2A5A01A3, 0x1B1A0E53, 0x758B4564, 0x59138727, 0x0AC6D692, 0x7A6EBF88, 0xD13F0224,
+ 0x167D436A, 0x18E62081, 0x27468934, 0x69835C83, 0x5EAB9DB4, 0x60282B7D, 0xBE541E0E, 0x862EE9BE,
+ 0xC01CD151, 0x0D2BCA92, 0x1CEE936B, 0x6EE64E05, 0x8D9A66B7, 0xB308D1AE, 0x3BC2DE21, 0x4E271F4F,
+ 0xCBDB1B1E, 0x4A90E026, 0x59BDCA74, 0x87B6FA35, 0x1ECEA971, 0xB8211185, 0x3E7CBD7D, 0xCACF4667,
+ 0xB45EC159, 0x13296A26, 0x4BA6BEFE, 0x0A1F9EF3, 0x561C37DB, 0x554294C6, 0x3409E7F0, 0xD5917C75,
+ 0xF9F6B582, 0xBE909723, 0x421CC8D0, 0xBC5627B5, 0xFD85C3C6, 0xE8C46727, 0xF3702427, 0x0B8B4DE4,
+ 0x3638DC3A, 0x55E01909, 0x078F5896, 0x04993C54, 0x81FC3753, 0xE3B02177, 0xD1FB8B09, 0xD24F6204,
+ 0x64ACD665, 0xD7E88060, 0x9DA9A8CF, 0xC33DF796, 0xE639002E, 0x3B64139A, 0xE80C2E96, 0x89B49688,
+ 0xC269EDD8, 0xD782441E, 0xD4EBA506, 0xDBD7178B, 0x7F891ADB, 0xE74F19C1, 0xA7B32252, 0x9CBDF5B6,
+ 0x3DF3D6E9, 0xACADA07C, 0xF7745751, 0xFCDD1914, 0x6789B0D6, 0xA957C463, 0x2944E589, 0xB524182A,
+ 0x3108C82F, 0x8ABF3306, 0xAF4C4FE2, 0x4DF9323C, 0x347AA2B6, 0xE13E563E, 0x8A4CF82E, 0x0509AF37,
+ 0x7475520D, 0x7075610F, 0x128EBB40, 0xD0581A1B, 0xDC1C485E, 0x21C8CD7F, 0x50CFF5EB, 0x4B3BF1DC,
+ 0x7CB5FD50, 0xE41D7A40, 0x780EC2A5, 0xC88D38EB, 0x00808E6E, 0x9EEACA9E, 0x4A362D9D, 0xFF96FBAD,
+ 0xC5D977A3, 0x9637A48F, 0x361E9FEF, 0x6D21E24E, 0x0FD6F89D, 0x73F6CA07, 0xCA1ACE9A, 0x26DADACB,
+ 0x22FCAA1C, 0x78C68B14, 0xB2498A44, 0xC9622E52, 0x7F5052BA, 0xCB3D9192, 0x23CEB4B0, 0xBEC9512C,
+ 0xF0848A1D, 0x721D9CCA, 0x20679CF1, 0xE06A4C70, 0xBBF7BC1E, 0xEA8619AB, 0x47AE6B10, 0x8648ED5C,
+ 0x37A84F59, 0xA0697C57, 0x944A18EE, 0xC7EC0C1D, 0x83EB4F4C, 0x5B00BF4C, 0x27DBC616, 0x1F293F20,
+ 0xECAAD02F, 0x4D647D1E, 0x42D0C115, 0x533F1BA5, 0xA700AE4D, 0xF98D702C, 0xA164A016, 0x17691E13,
+ 0xE62801FE, 0x6DD22966, 0xA5931848, 0x4A7AAA36, 0x8E150D23, 0xD56A37B5, 0x78E84829, 0xA1D36C7D,
+ 0xE7F41536, 0xE9D8BAB6, 0x26E51826, 0x67D076D9, 0x1BCF86AE, 0xE70F5EF6, 0x68C6471D, 0x39A6E378,
+ 0xC238AB3F, 0x4E411BAD, 0x3C6F8516, 0xE7D256E3, 0xD11941F1, 0x2EBCB82D, 0x10BF808A, 0x50297F67,
+ 0x2265A54A, 0x9BC16608, 0x932F0A68, 0x14DDF71E, 0x50CBB59F, 0xDE967F63, 0xEFD230E7, 0x14EEF56F,
+ 0xAB11FA9B, 0x08372401, 0xAB807525, 0xC06BD463, 0xAC296E66, 0xFC331370, 0x258CF93E, 0x68ECC454,
+ 0xBF918BFE, 0x7FC95DEC, 0x283A7C8E, 0x02A8349C, 0x63768860, 0xDF1F6D38, 0x67B6723B, 0xEC7B18A6,
+ 0x4A4DE833, 0xE062CC98, 0x90ACA160, 0xCC4982C4, 0xA649754F, 0x20769D21, 0xB6DC768C, 0xF6688AC0,
+ 0x29482515, 0x0BD28BEB, 0x84A09EF7, 0x9BABA276, 0xDA6D07A1, 0x0C371703, 0xC97BAF6A, 0x02BD7538,
+ 0xA06D3C23, 0x01E79651, 0x548BC1AA, 0x7318C063, 0x881F8772, 0xE761DAFC, 0xB429C46B, 0xB22BCED2,
+ 0xAB7B3EE5, 0x417529C8, 0xB36A9538, 0x59DBCE96, 0x7002643D, 0xB38C1FB4, 0x30859A00, 0x9776FF65,
+ 0xC4BE6F9C, 0x5C56AFBB, 0x0F307211, 0x1AA89E91, 0x2D6E55C2, 0x51E8AAE3, 0x4E2F9FA7, 0xE0800660,
+ 0x6C5F7B49, 0xB85AD42B, 0x21888A48, 0x9FBA90A4, 0xEE20E712, 0x837E8086, 0x06F1C191, 0xB31510E2,
+ 0xD382771C, 0xB6107F49, 0x1901B6D0, 0x73CD489E, 0x1A9B9CE0, 0xD6B41AC6, 0x8749F181, 0x0A7DDA65,
+ 0x3405276C, 0x6B67EFB4, 0x4C5EE35A, 0xAF840653, 0x373D8093, 0xFD98028A, 0x0084CE1A, 0x0B474421,
+ 0xD951E02A, 0x0F657482, 0x16C64F9D, 0x568DB865, 0x9D1E64A4, 0x33A0FCB3, 0xE9C9BB66, 0x705322DA,
+ 0x2A4F4007, 0xD801BA10, 0xAB73BE0D, 0x6A2E34B6, 0x95A50E57, 0xB83CD0C9, 0xD63C1440, 0x32F82661,
+ 0x66846C97, 0x2A74C29E, 0x0880E86A, 0x5B1D7E00, 0xCF9B6F2B, 0xE71E5F26, 0x3E707DE1, 0x7439D5A6,
+ 0x01F69781, 0x023DFB56, 0x3E87F6BD, 0x4BD1BBCC, 0xAB1D3A07, 0xB6C1B7C0, 0x1E2823FD, 0xD17F4513,
+ 0xD9082625, 0xBDFD364F, 0xD88DF4E2, 0x8B6FE752, 0x95B04FF3, 0x7B27648A, 0x08C4EF29, 0x01C595F0,
+};
+
+unsigned char rdmz_tb[128] = {
+ 0x84, 0x4a, 0x37, 0xbe, 0xd7, 0xd2, 0x39, 0x03, 0x8e, 0x77, 0xb9, 0x41, 0x99, 0xa7, 0x78, 0x62,
+ 0x53, 0x88, 0x12, 0xf4, 0x75, 0x21, 0xf0, 0x27, 0xc2, 0x0f, 0x04, 0x80, 0xd7, 0x5a, 0xce, 0x37,
+ 0x56, 0xb1, 0x1c, 0xdc, 0x61, 0x9a, 0x86, 0x10, 0xae, 0xec, 0x73, 0x54, 0xa1, 0x5a, 0x56, 0xdc,
+ 0x2b, 0x45, 0x5e, 0x09, 0x99, 0xb7, 0x64, 0x2b, 0x7f, 0x0c, 0x62, 0x91, 0xa0, 0xfe, 0x35, 0x84,
+ 0xdf, 0x7a, 0xa0, 0x21, 0xa7, 0x42, 0x30, 0x38, 0x80, 0x05, 0x6e, 0x6b, 0xda, 0x23, 0x3f, 0xf3,
+ 0x8e, 0x5d, 0xf7, 0x63, 0xbd, 0x34, 0x92, 0x19, 0x7d, 0x84, 0xcf, 0x66, 0xe9, 0x0d, 0x23, 0x32,
+ 0x55, 0xed, 0x5f, 0xc0, 0xcd, 0x76, 0xaf, 0x87, 0x9e, 0x83, 0x96, 0xa3, 0xf8, 0xb5, 0x09, 0x46,
+ 0x25, 0xa2, 0xc4, 0x3d, 0x2c, 0x46, 0x58, 0x89, 0x14, 0x2e, 0x3b, 0x29, 0x9a, 0x96, 0x0c, 0xe7
+};
+
+unsigned char eslc_map_table[128] = {
+ 0x0, 0x1,
+ 0x2, 0x3,
+ 0x6, 0x7,
+ 0xa, 0xb,
+ 0xe, 0xf,
+ 0x12, 0x13,
+ 0x16, 0x17,
+ 0x1a, 0x1b,
+ 0x1e, 0x1f,
+ 0x22, 0x23,
+ 0x26, 0x27,
+ 0x2a, 0x2b,
+ 0x2e, 0x2f,
+ 0x32, 0x33,
+ 0x36, 0x37,
+ 0x3a, 0x3b,
+ 0x3e, 0x3f,
+ 0x42, 0x43,
+ 0x46, 0x47,
+ 0x4a, 0x4b,
+ 0x4e, 0x4f,
+ 0x52, 0x53,
+ 0x56, 0x57,
+ 0x5a, 0x5b,
+ 0x5e, 0x5f,
+ 0x62, 0x63,
+ 0x66, 0x67,
+ 0x6a, 0x6b,
+ 0x6e, 0x6f,
+ 0x72, 0x73,
+ 0x76, 0x77,
+ 0x7a, 0x7b,
+ 0x7e, 0x7f,
+ 0x82, 0x83,
+ 0x86, 0x87,
+ 0x8a, 0x8b,
+ 0x8e, 0x8f,
+ 0x92, 0x93,
+ 0x96, 0x97,
+ 0x9a, 0x9b,
+ 0x9e, 0x9f,
+ 0xa2, 0xa3,
+ 0xa6, 0xa7,
+ 0xaa, 0xab,
+ 0xae, 0xaf,
+ 0xb2, 0xb3,
+ 0xb6, 0xb7,
+ 0xba, 0xbb,
+ 0xbe, 0xbf,
+ 0xc2, 0xc3,
+ 0xc6, 0xc7,
+ 0xca, 0xcb,
+ 0xce, 0xcf,
+ 0xd2, 0xd3,
+ 0xd6, 0xd7,
+ 0xda, 0xdb,
+ 0xde, 0xdf,
+ 0xe2, 0xe3,
+ 0xe6, 0xe7,
+ 0xea, 0xeb,
+ 0xee, 0xef,
+ 0xf2, 0xf3,
+ 0xf6, 0xf7,
+ 0xfa, 0xfb
+};
+
+void rdmzier(uint8_t *buf, int size, int page)
+{
+ int i, j;
+ unsigned int *bi = (unsigned int *)buf;
+ j = page%256;
+
+ for (i = 0; i < size; i++) {
+ bi[i] = rdmz[j] ^ bi[i];
+ j++;
+ if (j >= BYTE_SEED)
+ j = 0;
+ }
+}
+
+void rdmzier2(uint8_t *buf, int size, int page) //@20130731 Henry (speed up rdmzier by using assembly)
+{
+ int j;
+ unsigned int *bi = (unsigned int *)buf;
+
+ j = page%256; //0~255
+
+ unsigned int *rd = rdmz+j; //use int pointer (use "rdmz+j" down below "r" (rdmz+j) will fail... )
+
+ asm volatile (
+ ".ST: \n\t"
+ "mov r1, #2112 \n\t"//move #2112 to r1 to implement (#2112-j)
+ "sub r0, r1, %3 \n\t"//implement (#2112-j) to decide load 4,3,2 or 1 reg(s) this time
+ "cmp r0, #3 \n\t"// (#2112-j)==3,load 3 reags first ,then load 1reg
+ "beq .LV3 \n\t"//branch to Label ".LV3"
+ "cmp r0, #2 \n\t"//(#2112-j)==2,load 2 reags first ,then load 2regs
+ "beq .LV2 \n\t"//branch to Label ".LV2"
+ "cmp r0, #1 \n\t"//(#2112-j)==1,load 1 reag first ,then load 3regs
+ "beq .LV1 \n\t"//branch to Label ".LV1"
+ //(#2112-j)==others
+ "ldmia %0!, {r0-r3} \n\t" //load 16Bytes rdmz to reg r0~r3
+ "ldmia %1!, {r4-r7} \n\t" //load 16Bytes rdmz to reg r4~r7
+ "eor r4, r0, r4 \n\t" //do xor...
+ "eor r5, r1, r5 \n\t"
+ "eor r6, r2, r6 \n\t"
+ "eor r7, r3, r7 \n\t"
+ "sub %1, %1, #16 \n\t" //using ldmia with "!" will change pointer , need restore
+ "stmia %1!, {r4-r7} \n\t" //store 16Bytes reg r4~r7 to buf
+ "add %3, %3, #4 \n\t" //j need +1 every 4B finished ,j need +4 here
+ "cmp %3, #2112 \n\t" //check if j equal 2112
+ "moveq %3, #0 \n\t" //give j 0 if it reach 2112
+ "subeq %0, %0, #8448\n\t" //change rdmz pointer to the first entry of array
+ "subs %2, %2, #4 \n\t" //calculate the size we have finished
+ "bne .ST \n\t" //leave if size is 0 (all data are finished),or jump to Label ".S" and continue loop
+ "b .ED \n\t" //exit
+ //(#2112-j)==3
+ ".LV3: \n\t"
+ "ldmia %0!, {r0-r2} \n\t" //load 12Bytes rdmz to reg r0~r2
+ "ldmia %1!, {r4-r6} \n\t" //load 12Bytes rdmz to reg r4~r6
+ "eor r4, r0, r4 \n\t" //do xor...
+ "eor r5, r1, r5 \n\t"
+ "eor r6, r2, r6 \n\t"
+ "sub %1, %1, #12 \n\t" //using ldmia with "!" will change pointer , need restore
+ "stmia %1!, {r4-r6} \n\t" //store 12Bytes reg r4~r6 to buf
+ "mov %3, #0 \n\t" //give j 0 because it reach 2112
+ "subeq %0, %0, #8448\n\t" //change rdmz pointer to the first entry of array
+ "ldmia %0!, {r0} \n\t" //load 4Bytes rdmz to reg r0
+ "ldmia %1!, {r4} \n\t" //load 4Bytes rdmz to reg r4
+ "eor r4, r0, r4 \n\t" //do xor...
+ "sub %1, %1, #4 \n\t" //using ldmia with "!" will change pointer , need restore
+ "stmia %1!, {r4} \n\t" //store 4Bytes reg r4 to buf
+ "add %3, %3, #1 \n\t" //j need +1 every 4B finished ,j need +1 here
+ "subs %2, %2, #4 \n\t" //calculate the size we have finished
+ "bne .ST \n\t" //leave if size is 0 (all data are finished),or jump to Label ".S" and continue loop
+ "b .ED \n\t" //exit
+ //(#2112-j)==2
+ ".LV2: \n\t"
+ "ldmia %0!, {r0-r1} \n\t" //load 8Bytes rdmz to reg r0~r1
+ "ldmia %1!, {r4-r5} \n\t" //load 8Bytes rdmz to reg r4~r5
+ "eor r4, r0, r4 \n\t" //do xor...
+ "eor r5, r1, r5 \n\t"
+ "sub %1, %1, #8 \n\t" //using ldmia with "!" will change pointer , need restore
+ "stmia %1!, {r4-r5} \n\t" //store 8Bytes reg r4~r5 to buf
+ "mov %3, #0 \n\t" //give j 0 because it reach 2112
+ "subeq %0, %0, #8448\n\t" //change rdmz pointer to the first entry of array
+ "ldmia %0!, {r0-r1} \n\t" //load 8Bytes rdmz to reg r0~r1
+ "ldmia %1!, {r4-r5} \n\t" //load 8Bytes rdmz to reg r4~r5
+ "eor r4, r0, r4 \n\t" //do xor...
+ "eor r5, r1, r5 \n\t"
+ "sub %1, %1, #8 \n\t" //using ldmia with "!" will change pointer , need restore
+ "stmia %1!, {r4-r5} \n\t" //store 8Bytes reg r4~r5 to buf
+ "add %3, %3, #2 \n\t" //j need +1 every 4B finished ,j need +2 here
+ "subs %2, %2, #4 \n\t" //calculate the size we have finished
+ "bne .ST \n\t" //leave if size is 0 (all data are finished),or jump to Label ".S" and continue loop
+ "b .ED \n\t" //exit
+ //(#2112-j)==1
+ ".LV1: \n\t"
+ "ldmia %0!, {r0} \n\t" //load 4Bytes rdmz to reg r0
+ "ldmia %1!, {r4} \n\t" //load 4Bytes rdmz to reg r4
+ "eor r4, r0, r4 \n\t" //do xor...
+ "sub %1, %1, #4 \n\t" //using ldmia with "!" will change pointer , need restore
+ "stmia %1!, {r4} \n\t" //store 4Bytes reg r4 to buf
+ "mov %3, #0 \n\t" //give j 0 because it reach 2112
+ "subeq %0, %0, #8448\n\t" //change rdmz pointer to the first entry of array
+ "ldmia %0!, {r0-r2} \n\t" //load 12Bytes rdmz to reg r0~r2
+ "ldmia %1!, {r4-r6} \n\t" //load 12Bytes rdmz to reg r4~r6
+ "eor r4, r0, r4 \n\t" //do xor...
+ "eor r5, r1, r5 \n\t"
+ "eor r6, r2, r6 \n\t"
+ "sub %1, %1, #12 \n\t" //using ldmia with "!" will change pointer , need restore
+ "stmia %1!, {r4-r6} \n\t" //store 12Bytes reg r4~r6 to buf
+ "add %3, %3, #3 \n\t" //j need +1 every 4B finished ,j need +3 here
+ "subs %2, %2, #4 \n\t" //calculate the size we have finished
+ "bne .ST \n\t" //leave if size is 0 (all data are finished),or jump to Label ".S" and continue loop
+ "b .ED \n\t" //exit
+ ".ED: "
+ :
+ : "r" (rd), "r" (bi), "r" (size), "r" (j) //%0=rd, %1=bi, %2=size, %3=j
+ : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" //arm regs that will be used
+ );
+
+ //original C code
+ /*for (i = 0; i < size; i++) {
+ bi[i] = rdmz[j] ^ bi[i];
+ j++;
+ if (j >= BYTE_SEED)
+ j = 0;
+ }*/
+
+}
+
+
+void rdmzier_oob(uint8_t *buf, uint8_t *src, int size, int page, int ofs)
+{
+ int i, j;
+ unsigned int *bi = (unsigned int *)buf;
+ unsigned int *bs = (unsigned int *)src;
+ j = page%256;
+ j = (j+ofs)%BYTE_SEED;
+
+ for (i = 0; i < size; i++) {
+ bi[i] = rdmz[j] ^ bs[i];
+ j++;
+ if (j >= BYTE_SEED)
+ j = 0;
+ }
+}
+
+/* ecc_layout
+*
+* Johnny Liu 2013.1.18
+*
+*/
+static struct nand_ecclayout wmt_oobinfo_2048 = {
+ .eccbytes = 7,
+ .eccpos = { 24, 25, 26, 27, 28, 29, 30},
+ .oobavail = 24,
+ .oobfree = {{0, 24} }
+};
+
+static struct nand_ecclayout wmt_oobinfo_8192 = {
+ .eccbytes = 42,
+ .eccpos = { 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65},
+ .oobavail = 24,
+ .oobfree = {{0, 24} }
+};
+
+static struct nand_ecclayout wmt_oobinfo_16k = {
+ .eccbytes = 70,
+ .eccpos = { 24, 25, 26, 27, 28, 29, 30,
+ 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65,
+ 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86,
+ 87, 88, 89, 90, 91, 92, 93},
+ .oobavail = 24,
+ .oobfree = {{0, 24} }
+};
+
+static struct nand_ecclayout wmt_oobinfo_4096 = {
+ .eccbytes = 7,
+ .eccpos = { 24, 25, 26, 27, 28, 29, 30},
+ .oobavail = 24,
+ .oobfree = {{0, 24} }
+};
+static struct nand_ecclayout wmt_oobinfo_512 = {
+ .eccbytes = 8,
+ .eccpos = { 4, 5, 6, 8, 9, 10, 12, 13},
+ .oobfree = {{0, 4},{7, 1},{11,1},{14,2}}
+};
+struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE] = {{0}};
+int eslc_load_image(struct nand_chip *nand, unsigned long long naddr, unsigned int maddr, unsigned int size);
+int eslc_load_image_tpi(struct nand_chip *nand, unsigned long long naddr, unsigned int maddr, unsigned int size);
+int eslc_save_image(struct nand_chip *nand, unsigned long long naddr, unsigned int dwImageStart, unsigned int dwImageLength);
+int eslc_nand_write_block(struct nand_chip *nand, unsigned int start, unsigned int page, unsigned int page_count, unsigned char *oob);
+int sandisk_init_retry_register(struct nand_chip *nand, int chip);
+int read_retry_param_from_nand(struct nand_chip *nand, int chip);
+int write_retry_param_to_nand(struct nand_chip *nand, int chip);
+int toshiba_pre_condition(void);
+int write_bytes_param(int cmd_cnt, int addr_cnt, int data_cnt, uchar *cmd, uchar *addr, uchar *data);
+int shift_bit(unsigned int value);
+/* Current NAND Device */
+static int curr_device = -1;
+
+//FIXME: move Wmt*Nand* Functions to sepereate file?
+struct nand_chip* get_current_nand_chip(void){
+ if(curr_device >= 0 && curr_device < CFG_MAX_NAND_DEVICE)
+ return nand_dev_desc + curr_device;
+ return NULL;
+}
+
+struct nand_read_retry_param *cur_chip = NULL;
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+#define READ_RETRY_CHIP_NUM ARRAY_SIZE(chip_table)
+
+void NAND_ENABLE_CE(struct nand_chip *nand, int chip)
+{
+ if (chip == 1)
+ chip++;
+ else if (chip == 2)
+ chip--;
+ *(((volatile __u8 *)(nand->IO_ADDR)) + 0x49) = ~(1<<chip);
+}
+
+#define NAND_DISABLE_CE(nand) do \
+{ \
+ *(((volatile __u8 *)(nand->IO_ADDR)) + 0x49) = 0xFF; \
+} while(0)
+
+/* ------------------------------------------------------------------------- */
+
+/*--For fastboot partial write image , fastboot need to know the valid write size about the flash--*/
+unsigned long get_nand_valid_partial_write_size(unsigned long buffer_bound_MB)
+{
+ unsigned long rt;
+ unsigned long buf_MB;
+ struct nand_chip* nand = &nand_dev_desc[curr_device];
+
+ if (curr_device < 0) {
+ printf("nand flash not initial yet.(get_nand_valid_partial_write_size)\n");
+ return 0;
+ }
+
+ buf_MB = buffer_bound_MB<<20;
+
+ if (nand->realplanenum) {
+ rt = buf_MB/(nand->erasesize_valid*2 + nand->dwPageCount*64);
+ //printf("multi:buf_MB=%d,rt=%lu\n",buf_MB,rt);
+ rt = rt*(nand->erasesize_valid*2 + nand->dwPageCount*64);
+ //printf("multi:rt=%lu\n",rt);
+ } else {
+ rt = buf_MB/(nand->erasesize_valid + nand->dwPageCount*64);
+ //printf("single:buf_MB=%d,rt=%lu\n",buf_MB,rt);
+ rt = rt*(nand->erasesize_valid + nand->dwPageCount*64);
+ //printf("single:rt=%lu\n",rt);
+ }
+
+ return rt;
+
+}
+
+unsigned long get_nand_data_tol_size(void)
+{
+ if (curr_device < 0) {
+ printf("nand flash not initial yet.\n");
+ return 0;
+ }
+ return ((nand_dev_desc[curr_device].erasesize_valid/1024)*nand_dev_desc[curr_device].dwBlockCount);
+}
+
+unsigned int get_nand_blk_KB_size(void)
+{
+ if (curr_device < 0) {
+ printf("nand flash not initial yet.\n");
+ return 0;
+ }
+ return (nand_dev_desc[curr_device].erasesize_valid/1024);
+
+}
+
+void disable_hw_rdmz(struct nand_chip *nand)
+{
+ #ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz && (pNFCRegs->NFCRf&RDMZ))
+ reset_nfc();
+ #endif
+}
+void enable_hw_rdmz(struct nand_chip *nand)
+{
+ #ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz && !(pNFCRegs->NFCRf&RDMZ))
+ pNFCRegs->NFCRf = RDMZ;
+ #endif
+}
+
+int do_nand (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int rcode = 0;
+
+ *(volatile unsigned int *)(GPIO_BASE_ADDR + 0x200) &= ~(1<<11); /*PIN_SHARE_SDMMC1_NAND*/
+
+ enable_hw_rdmz( nand_dev_desc + curr_device );//enable hw rdmz when start doing nand stuff
+
+ switch (argc) {
+ case 0:
+ case 1:
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ case 2:
+ if (strcmp(argv[1],"info") == 0) {
+ int i;
+
+ putc ('\n');
+
+ for (i=0; i<CFG_MAX_NAND_DEVICE; ++i) {
+ if(nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN)
+ continue; /* list only known devices */
+ printf ("Device %d: ", i);
+ nand_print(&nand_dev_desc[i]);
+ }
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+
+ } else if (strcmp(argv[1],"device") == 0) {
+ if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
+ puts ("\nno devices available\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ printf ("\nDevice %d: ", curr_device);
+ nand_print(&nand_dev_desc[curr_device]);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+
+ } else if (strcmp(argv[1],"bad") == 0) {
+ if ((curr_device < 0) || (curr_device >= CFG_MAX_NAND_DEVICE)) {
+ puts ("\nno devices available\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ printf ("\nDevice %d bad blocks:\n", curr_device);
+ nand_print_bad(&nand_dev_desc[curr_device]);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ }
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ case 3:
+ if (strcmp(argv[1],"device") == 0) {
+ int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+ printf ("\nDevice %d: ", dev);
+ if (dev >= CFG_MAX_NAND_DEVICE) {
+ puts ("unknown device\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ nand_print(&nand_dev_desc[dev]);
+ /*nand_print (dev);*/
+
+ if (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN) {
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+
+ curr_device = dev;
+
+ puts ("... is now current device\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ } else if (strncmp(argv[1], "erase", 4) == 0 || strncmp(argv[1], "erase", 3) == 0) {
+ struct nand_chip* nand = &nand_dev_desc[curr_device];
+ if (strcmp(argv[2], "all") == 0) {
+ printf("Erase all\n");
+ WMTEraseNAND(nand, 0, 0, 1);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ } else if (strcmp(argv[2], "allrf") == 0) { //erase all good blocks & read fail block
+ printf("Erase all good blocks & read fail block\n");
+ erase_all_read_fail = 1;
+ WMTEraseNAND(nand, 0, 0, 1);
+ erase_all_read_fail = 0;
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ } else if (strcmp(argv[2], "force") == 0) {
+ printf("Erase force all include bbt and bad block\n");
+ WMTEraseNANDALL(nand, 1);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ } else if (strcmp(argv[2], "table") == 0) { //erase retry & bbt (skip bad block)
+ printf("Erase bbt & retry Table (skip bad block)\n");
+ WMTEraseNANDALL(nand, 0);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ } else if (strcmp(argv[2], "fretry") == 0) { //force erase retry blocks (no skip bad block)
+ printf("Erase retry Table (no skip bad block)\n");
+ WMTEraseNANDALL(nand, 2);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ } else if (strcmp(argv[2], "ftable") == 0) { //force erase bbt blocks (no skip bad block)
+ printf("Erase bbt Table (no skip bad block)\n");
+ WMTEraseNANDALL(nand, 3);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ }
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ } else if (strncmp(argv[1], "tellme", 3) == 0) {
+ struct nand_chip* nand = &nand_dev_desc[curr_device];
+ if (strcmp(argv[2], "bad") == 0)
+ tellme_badblock(nand);
+ if (strcmp(argv[2], "table") == 0)
+ tellme_whereistable(nand);
+ if (strcmp(argv[2], "nand") == 0)
+ tellme_nandinfo(nand);
+ else if (strcmp(argv[2], "retry") == 0)
+ get_read_retry_para(nand);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 0;
+ }
+
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ default:
+ /* at least 4 args */
+#if 0
+ if (strncmp(argv[1], "read", 4) == 0 ||
+ strncmp(argv[1], "write", 5) == 0) {
+ ulong addr = simple_strtoul(argv[2], NULL, 16);
+ ulong off = simple_strtoul(argv[3], NULL, 16);
+ ulong size = simple_strtoul(argv[4], NULL, 16);
+ int cmd = (strncmp(argv[1], "read", 4) == 0) ?
+ NANDRW_READ : NANDRW_WRITE;
+ int ret, total;
+ char* cmdtail = strchr(argv[1], '.');
+
+ if (cmdtail && !strncmp(cmdtail, ".oob", 2)) {
+ /* read out-of-band data */
+ if (cmd & NANDRW_READ) {
+ ret = nand_read_oob(nand_dev_desc + curr_device,
+ off, size, (size_t *)&total,
+ (u_char*)addr);
+ }
+ else {
+ ret = 0;
+ /*ret = nand_write_oob(nand_dev_desc + curr_device,
+ off, size, (size_t *)&total,
+ (u_char*)addr);*/
+ }
+ return ret;
+ }
+ else if (cmdtail && !strncmp(cmdtail, ".jffs2s", 7)) {
+ cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */
+ if (cmd & NANDRW_READ)
+ cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */
+ }
+ else if (cmdtail && !strncmp(cmdtail, ".jffs2", 2))
+ cmd |= NANDRW_JFFS2; /* skip bad blocks (fill with 0xFF)*/
+#ifdef SXNI855T
+ /* need ".e" same as ".j" for compatibility with older units */
+ else if (cmdtail && !strcmp(cmdtail, ".e"))
+ cmd |= NANDRW_JFFS2; /* skip bad blocks */
+#endif
+#ifdef CFG_NAND_SKIP_BAD_DOT_I
+ /* need ".i" same as ".jffs2s" for compatibility with older units (esd) */
+ /* ".i" for image -> read skips bad block (no 0xff) */
+ else if (cmdtail && !strcmp(cmdtail, ".i")) {
+ cmd |= NANDRW_JFFS2; /* skip bad blocks (on read too) */
+ if (cmd & NANDRW_READ)
+ cmd |= NANDRW_JFFS2_SKIP; /* skip bad blocks (on read too) */
+ }
+#endif /* CFG_NAND_SKIP_BAD_DOT_I */
+ else if (cmdtail) {
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
+
+ printf ("\nNAND %s: device %d offset %ld, size %ld ... ",
+ (cmd & NANDRW_READ) ? "read" : "write",
+ curr_device, off, size);
+
+ ret = nand_rw(nand_dev_desc + curr_device, cmd, off, size,
+ (size_t *)&total, (u_char*)addr);
+
+ printf (" %d bytes %s: %s\n", total,
+ (cmd & NANDRW_READ) ? "read" : "written",
+ ret ? "ERROR" : "OK");
+
+ return ret;
+ } else
+#endif
+ if (strncmp(argv[1], "setbbt", 6) == 0 && argc == 4) {
+ int ret = 0;
+ struct nand_chip* nand = &nand_dev_desc[curr_device];
+
+ unsigned int block = simple_strtoull(argv[2], NULL, 16);
+ unsigned int value = simple_strtoul(argv[3], NULL, 16);
+
+ if (value!=0 && value!=1 && value!=2 && value!=3) {
+ printf("wrong value! set value should be :\n");
+ printf("0(default bad blk)\n1(read fail bad blk)\n2(write/erase fail bad blk)\n3(good blk)\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ }
+
+ if( block > (nand->dwBlockCount-(nand->realplanenum?8:4)) ) {
+ printf("wrong block number %d(0x%x)\n",block,block);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ }
+
+ if (value == 0) {
+ printf("Set default bad block%d(0x%x) to bbt \n",block,block);
+ update_bbt_inram(nand , block, 0);
+ } else if (value == 1) {
+ printf("Set read fail bad block%d(0x%x) to bbt \n",block,block);
+ update_bbt_inram_set_r_badblk(nand , block, 0);
+ } else if (value == 2) {
+ printf("Set write & erase fail bad block%d(0x%x) to bbt \n",block,block);
+ update_bbt_inram_set_w_e_badblk(nand , block, 0);
+ } else {/* value == 3 */
+ printf("Set good block%d(0x%x) to bbt \n",block,block);
+ update_bbt_inram_set_goodblk(nand , block, 0);
+ }
+
+ update_bbt_inflash(nand,0,0);
+
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if (strncmp(argv[1], "pw", 2) == 0 && argc == 5) {
+ int ret;
+ ulong need_erase = 1;//must enable when test (not using fastboot to write img)
+ struct nand_chip* nand = &nand_dev_desc[curr_device];
+ ulong maddr = simple_strtoul(argv[2], NULL, 16);
+ ulong page_num = simple_strtoul(argv[3], NULL, 16);
+ ulong page_cnt = simple_strtoul(argv[4], NULL, 16);
+
+ unsigned long long off = (unsigned long long)( (page_num*nand->oobblock_K)<<nand->page_shift );
+ ulong size = page_cnt*nand->dwPageSize;
+
+
+ /*printf("page_cnt 0x%lx\n", page_cnt);
+ printf("off print to memory 0 (because can't print unsigned long long!)");
+ memcpy(0,(unsigned char*)&off , 8);
+ printf("nand->dwPageSize 0x%lx\n", nand->dwPageSize);
+ printf("page_num 0x%lx\n", page_num);
+ printf("off 0x%lx\n", off);*/
+
+
+ if (!page_cnt) {
+ printf("page_cnt=0!\n");
+ disable_hw_rdmz( nand );
+ return 1;
+ }
+ printf("Write 0x%lx pages from page0x%lx ,mem(0x%lx), size(0x%lx)\n", page_cnt,page_num,maddr,size);
+ printf("(No skip bad block,force single plane,no eslc mode)\n");
+ do_page_rw = 1;
+ ret = WMTSaveImageToNAND(nand, off, maddr, size, 0, need_erase);
+ disable_hw_rdmz( nand );
+ do_page_rw = 0;
+ return ret;
+ } else if (strncmp(argv[1], "pr", 2) == 0 && argc == 5) {
+ int ret;
+ struct nand_chip* nand = &nand_dev_desc[curr_device];
+ ulong page_num = simple_strtoul(argv[2], NULL, 16);
+ ulong maddr = simple_strtoul(argv[3], NULL, 16);
+ ulong page_cnt = simple_strtoul(argv[4], NULL, 16);
+
+ unsigned long long off = (unsigned long long)( (page_num*nand->oobblock_K)<<nand->page_shift );
+ ulong size = page_cnt*nand->dwPageSize;
+
+ /*printf("page_cnt 0x%lx\n", page_cnt);
+ printf("off print to memory 0 (because can't print unsigned long long!)");
+ memcpy(0,(unsigned char*)&off , 8);
+ printf("nand->dwPageSize 0x%lx\n", nand->dwPageSize);
+ printf("page_num 0x%lx\n", page_num);
+ printf("off 0x%lx\n", off);*/
+
+ if (!page_cnt) {
+ printf("page_cnt=0!\n");
+ disable_hw_rdmz( nand );
+ return 1;
+ }
+ printf("Read 0x%x pages from page0x%x to mem(0x%lx), size(0x%lx)\n", page_cnt,page_num,maddr,size);
+ printf("(No skip bad block,force single plane,no eslc mode)\n");
+ do_page_rw = 1;
+ ret = WMTLoadImageFormNAND(nand, off, maddr, size);
+ disable_hw_rdmz( nand );
+ do_page_rw = 0;
+ return ret;
+ } else if (strncmp(argv[1], "r", 1) == 0 && argc == 5) {
+ int ret;
+ //ulong off = simple_strtoul(argv[2], NULL, 16);
+ unsigned long long off = simple_strtoull(argv[2], NULL, 16);
+ ulong maddr = simple_strtoul(argv[3], NULL, 16);
+ ulong size = simple_strtoul(argv[4], NULL, 16);
+ if (!size) {
+ printf("size=0\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ /*printf("Load Image Form NAND Flash off=0x%lx\r\n", off);*/
+ ret = WMTLoadImageFormNAND(nand_dev_desc + curr_device, off, maddr, size);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if (strncmp(argv[1], "wb", 2) == 0 && argc == 5) {
+ int ret;
+ ulong need_erase = 3;
+ ulong maddr = simple_strtoul(argv[2], NULL, 16);
+ //ulong off = simple_strtoul(argv[3], NULL, 16);
+ unsigned long long off = simple_strtoull(argv[3], NULL, 16);
+ ulong size = simple_strtoul(argv[4], NULL, 16);
+ if (!size) {
+ printf("size=0\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ ret = WMTSaveImageToNAND(nand_dev_desc + curr_device, off, maddr, size, 0, need_erase);
+ pNFCRegs->NFCRd &= ~RED_DIS;
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if (strncmp(argv[1], "w", 1) == 0 && argc == 5) {
+ int ret;
+ ulong need_erase = 1;
+ ulong maddr = simple_strtoul(argv[2], NULL, 16);
+ //ulong off = simple_strtoul(argv[3], NULL, 16);
+ unsigned long long off = simple_strtoull(argv[3], NULL, 16);
+ ulong size = simple_strtoul(argv[4], NULL, 16);
+ if (!size) {
+ printf("size=0\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ ret = WMTSaveImageToNAND(nand_dev_desc + curr_device, off, maddr, size, 0, need_erase);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if (strncmp(argv[1], "wo", 2) == 0 && argc == 6) {
+ int ret;
+ ulong need_erase = 0;//must enable when test (not using fastboot to write img)
+ ulong maddr = simple_strtoul(argv[2], NULL, 16);
+ unsigned long long off = simple_strtoull(argv[3], NULL, 16);
+ ulong size = simple_strtoul(argv[4], NULL, 16);
+ ulong oob_offs = simple_strtoul(argv[5], NULL, 16);
+ if (!size) {
+ printf("size=0\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ ret = WMTSaveImageToNAND(nand_dev_desc + curr_device, off, maddr, size, oob_offs, need_erase);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if (strncmp(argv[1], "woe", 3) == 0 && argc == 7) {
+ int ret;
+ ulong maddr = simple_strtoul(argv[2], NULL, 16);
+ unsigned long long off = simple_strtoull(argv[3], NULL, 16);
+ ulong size = simple_strtoul(argv[4], NULL, 16);
+ ulong oob_offs = simple_strtoul(argv[5], NULL, 16);
+ unsigned int need_erase = simple_strtoul(argv[6], NULL, 16);
+ if (!size) {
+ printf("size=0\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ ret = WMTSaveImageToNAND(nand_dev_desc + curr_device, off, maddr, size, oob_offs, need_erase);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if (strncmp(argv[1], "er", 2) == 0 && argc == 5) {
+ int ret;
+ //ulong off = simple_strtoul(argv[2], NULL, 16);
+ unsigned long long off = simple_strtoull(argv[2], NULL, 16);
+ ulong maddr = simple_strtoul(argv[3], NULL, 16);
+ ulong size = simple_strtoul(argv[4], NULL, 16);
+ if (!size) {
+ printf("size=0\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ if(!cur_chip) {
+ printf("Warning: This chip not need eslc and read retry.\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ /*printf("Load Image Form NAND Flash off=0x%lx\r\n", off);*/
+ ret = eslc_load_image(nand_dev_desc + curr_device, off, maddr, size);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if (strncmp(argv[1], "ew", 2) == 0 && argc == 5) {
+ int ret;
+ ulong maddr = simple_strtoul(argv[2], NULL, 16);
+ //ulong off = simple_strtoul(argv[3], NULL, 16);
+ unsigned long long off = simple_strtoull(argv[3], NULL, 16);
+ ulong size = simple_strtoul(argv[4], NULL, 16);
+ if (!size) {
+ printf("size=0\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+ if(!cur_chip) {
+ printf("Warning: This chip not need eslc and read retry.\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+
+ ret = eslc_save_image_tpi(nand_dev_desc + curr_device, off, maddr, size);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if (strncmp(argv[1], "boot", 4) == 0 && argc == 6) {
+ int ret;
+ unsigned long long off = simple_strtoull(argv[2], NULL, 16);
+ ulong maddr_kernel = simple_strtoul(argv[3], NULL, 16);
+ ulong maddr_ramdisk = simple_strtoul(argv[4], NULL, 16);
+
+ printf("nand partition offset=0x%lx%x\r\n", (ulong)(off>>32), (ulong)off);
+ ret = nand_boot(nand_dev_desc + curr_device, off, maddr_kernel, maddr_ramdisk, argv[5]);
+ disable_hw_rdmz(nand_dev_desc + curr_device );
+ if (ret)
+ return 0;
+ return ret;
+ } else if (strncmp(argv[1], "exboot", 6) == 0 && argc == 7) {
+ int ret;
+ unsigned long long off;
+ ulong maddr_kernel = simple_strtoul(argv[4], NULL, 16);
+ ulong maddr_ramdisk = simple_strtoul(argv[5], NULL, 16);
+
+ if (parse_fbparts(argv[2], argv[3], &ret)) {
+ printf("%s find %s failed\n", argv[2], argv[3]);
+ return 0;
+ }
+
+ off = (unsigned long long)(ret<<20);
+ ret = nand_boot(nand_dev_desc + curr_device, off, maddr_kernel, maddr_ramdisk, argv[6]);
+ if (ret)
+ return 0;
+ return ret;
+ } else if (strncmp(argv[1], "load", 4) == 0 && argc == 6) {
+ int ret;
+ unsigned long long off;
+ ulong maddr = simple_strtoul(argv[4], NULL, 16);
+ ulong size = simple_strtoul(argv[5], NULL, 16);
+ if (!size) {
+ printf("size=0\n");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return 1;
+ }
+
+ if (parse_fbparts(argv[2], argv[3], &ret)) {
+ printf("%s find %s failed\n", argv[2], argv[3]);
+ return 0;
+ }
+
+ off = (unsigned long long)(ret<<20);
+ ret = WMTLoadImageFormNAND(nand_dev_desc + curr_device, off, maddr, size);
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ if (ret)
+ return 0;
+ return ret;
+ } else if ((strcmp(argv[1],"erase") == 0 && strncmp(argv[2], "address", 4) == 0)
+ && strcmp(argv[3], "clean") == 0) {
+ struct nand_chip* nand = &nand_dev_desc[curr_device];
+ ulong off = 0;
+ ulong size = nand->totlen;
+ int ret;
+
+ printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
+ curr_device, off, size);
+
+ ret = nand_erase(nand, off, size, 1);
+
+ printf("%s\n", ret ? "ERROR" : "OK");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if ((strcmp(argv[1],"erase") == 0 && (strcmp("address", argv[2]) == 0))
+ && (argc == 5 || strcmp("clean", argv[3]) == 0)) {
+ int clean = argc == 6;
+ ulong off = simple_strtoul(argv[3 + clean], NULL, 16);
+ ulong size = simple_strtoul(argv[4 + clean], NULL, 16);
+ int ret;
+
+ printf ("\nNAND erase: device %d offset %ld, size %ld ... ",
+ curr_device, off, size);
+
+ ret = nand_erase(nand_dev_desc + curr_device, off, size, clean);
+
+ printf("%s\n", ret ? "ERROR" : "OK");
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return ret;
+ } else if (strcmp(argv[1],"erase") == 0 &&
+ (argc == 4)) {
+ ulong start_blk = simple_strtoul(argv[2], NULL, 16);
+ ulong blk_num = simple_strtoul(argv[3], NULL, 16);
+ printf("\nNAND erase: device %d, start blk %d, blk num %d\n", curr_device, start_blk, blk_num);
+ WMTEraseNAND(nand_dev_desc + curr_device, start_blk, blk_num, 0);
+ } else if (strcmp(argv[1],"eraseb") == 0 && (argc == 4)) {
+ unsigned long long start_ofs = simple_strtoull(argv[2], NULL, 16);
+ unsigned long long blk_ofs = simple_strtoull(argv[3], NULL, 16);
+ ulong start_blk, blk_num, blk_shift;
+ blk_shift = shift_bit(nand_dev_desc[curr_device].dwBlockSize);
+ start_blk = start_ofs >> blk_shift;
+ blk_num = blk_ofs >> blk_shift;
+ blk_num += ((blk_ofs&(blk_shift-1)) ? 1 : 0);
+ printf("start_blk0x%x, blk_num=0x%x, bloksize=0x%x\n", start_blk, blk_num, nand_dev_desc[0].dwBlockSize);
+ WMTEraseNAND(nand_dev_desc + curr_device, start_blk, blk_num, 0);
+ } else if (strncmp(argv[1], "set", 3) == 0 && (argc == 4)) {
+ struct nand_chip* nand = &nand_dev_desc[curr_device];
+ int reg = simple_strtoul(argv[3], NULL, 16);
+ if (strcmp(argv[2], "retry") == 0)
+ set_read_retry_para(nand, reg);
+ } else {
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ rcode = 1;
+ }
+ disable_hw_rdmz( nand_dev_desc + curr_device );
+ return rcode;
+ }
+}
+
+U_BOOT_CMD(
+ nandrw, 7, 1, do_nand,
+ "nandrw - NAND sub-system\n",
+ "nandrw info - show available NAND devices\n"
+ /*"nandrw device [dev] - show or set current device\n"
+ "nandrw read[.jffs2[s]] addr off size\n"
+ "nandrw write[.jffs2] addr off size - read/write `size' bytes starting\n"
+ " at offset `off' to/from memory address `addr'\n"
+ "nandrw erase address [clean] [off size] - erase `size' bytes from\n"
+ " offset `off' (entire device if not specified)\n"
+ "nandrw bad - show bad blocks by checking initial defective marker\n"
+ " \r\n"*/
+ "nandrw erase start_block block_numbers - erase blocks skip bad block\n"
+ "nandrw erase all - erase full blocks except table blocks (last 4 blocks)\n"
+ /*"nandrw erase table - erase table blocks (last 4 blocks)\n"*/
+ /*"nandrw erase force - erase entire device including table blocks\n"*/
+ "nandrw tellme nand - show nand flash info\n"
+ "nandrw tellme bad - show bad blocks from bad block table\n"
+ "nandrw tellme table - show bad block table\n"
+ /*"nandrw read.oob addr off size - read out-of-band data\n"*/
+ "nandrw r off addr size - read nand flash from offset 'off' to memory\n"
+ " address `addr' with skip bad blocks\n"
+ "nandrw w addr off size - write nand flash from memory address 'addr' to nand\n"
+ " flash offset `off' with skip bad blocks\n"
+ /*"nandrw write.oob addr off size - read out-of-band data\n"*/
+
+);
+
+#if 0
+int do_nandboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ char *boot_device = NULL;
+ char *ep;
+ int dev;
+ ulong cnt;
+ ulong addr;
+ ulong offset = 0;
+ image_header_t *hdr;
+ int rcode = 0;
+ switch (argc) {
+ case 1:
+ addr = CFG_LOAD_ADDR;
+ boot_device = getenv ("bootdevice");
+ break;
+ case 2:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = getenv ("bootdevice");
+ break;
+ case 3:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ break;
+ case 4:
+ addr = simple_strtoul(argv[1], NULL, 16);
+ boot_device = argv[2];
+ offset = simple_strtoul(argv[3], NULL, 16);
+ break;
+ default:
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ if (!boot_device) {
+ puts ("\n** No boot device **\n");
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ dev = simple_strtoul(boot_device, &ep, 16);
+
+ if ((dev >= CFG_MAX_NAND_DEVICE) ||
+ (nand_dev_desc[dev].ChipID == NAND_ChipID_UNKNOWN)) {
+ printf ("\n** Device %d not available\n", dev);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ printf ("\nLoading from device %d: %s at 0x%lx (offset 0x%lx)\n",
+ dev, nand_dev_desc[dev].name, nand_dev_desc[dev].IO_ADDR,
+ offset);
+
+ if (nand_rw(nand_dev_desc + dev, NANDRW_READ, offset,
+ SECTORSIZE, NULL, (u_char *)addr)) {
+ printf ("** Read error on %d\n", dev);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ hdr = (image_header_t *)addr;
+
+ if (ntohl(hdr->ih_magic) == IH_MAGIC) {
+
+ print_image_hdr (hdr);
+
+ cnt = (ntohl(hdr->ih_size) + sizeof(image_header_t));
+ cnt -= SECTORSIZE;
+ } else {
+ printf ("\n** Bad Magic Number 0x%x **\n", hdr->ih_magic);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ if (nand_rw(nand_dev_desc + dev, NANDRW_READ, offset + SECTORSIZE, cnt,
+ NULL, (u_char *)(addr+SECTORSIZE))) {
+ printf ("** Read error on %d\n", dev);
+ SHOW_BOOT_PROGRESS (-1);
+ return 1;
+ }
+
+ /* Loading ok, update default load address */
+
+ load_addr = addr;
+
+ /* Check if we should attempt an auto-start */
+ if (((ep = getenv("autostart")) != NULL) && (strcmp(ep,"yes") == 0)) {
+ char *local_args[2];
+ extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
+
+ local_args[0] = argv[0];
+ local_args[1] = NULL;
+
+ printf ("Automatic boot of image at addr 0x%08lx ...\n", addr);
+
+ do_bootm (cmdtp, 0, 1, local_args);
+ rcode = 1;
+ }
+ return rcode;
+}
+
+U_BOOT_CMD(
+ nboot, 4, 1, do_nandboot,
+ "nboot - boot from NAND device\n",
+ "loadAddr dev\n"
+);
+#endif
+
+void WRITE_NAND_COMMAND(unsigned int cmd)
+{
+ pNFCRegs->NFCR2 = (unsigned char)cmd;
+}
+
+
+
+//FIXME: this command has nothing to do with nand, move this to another file?
+int do_parseimg (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
+
+ char buf[10];
+ ulong imgAddr, kernelAddr, ramdiskAddr;
+ unsigned int kernelSize, ramdiskSize, pageSize, ramOff;
+ struct boot_img_hdr *imgHdr = NULL;
+
+
+ if(argc < 5){
+ printf("Invalid argument , type 'help parseimg' to view the help msg\n");
+ return 1;
+ }
+
+ imgAddr = simple_strtoul(argv[1], NULL, 16);
+ imgHdr = (struct boot_img_hdr *)imgAddr;
+
+ if (strncmp((char *)imgHdr->magic, "ANDROID!", 8) != 0) {
+ printf("fail: image header (0x%x) signature is not \"ANDROID!\" \n", imgAddr);
+ return 0;
+ }
+
+ kernelAddr = simple_strtoul(argv[2], NULL, 16);
+ ramdiskAddr = simple_strtoul(argv[3], NULL, 16);
+
+ kernelSize = imgHdr->kernel_size;
+ ramdiskSize = imgHdr->ramdisk_size;
+ pageSize = imgHdr->page_size;
+
+ memcpy((void*)kernelAddr, (void*)(imgAddr+pageSize), kernelSize);
+
+ ramOff = pageSize + kernelSize + ((kernelSize%pageSize) ? (pageSize - (kernelSize%pageSize)) : 0);
+ memcpy((void*)ramdiskAddr, (void*)(imgAddr+ramOff), ramdiskSize);
+
+ sprintf(buf, "%lx", ramdiskSize);
+ setenv(argv[4], buf);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ parseimg, 5, 1, do_parseimg,
+ "parseimg - parse android img\n",
+ "imgMemAddr kernelMemAddr ramdiskMemAddr sizeVar\n"
+);
+
+extern int image_rsa_check(unsigned int image_mem_addr, unsigned int image_size, unsigned int sig_addr, unsigned int sig_size);
+
+int nand_boot(
+struct nand_chip* nand,
+unsigned long long off,
+unsigned int mem_kernel,
+unsigned int mem_ramdisk,
+char * ramdiskSize)
+{
+ int ret = 0;
+ struct boot_img_hdr *img_hdr;
+ struct sig_header *sig_hdr;
+ char *s = NULL, *p = NULL, *key = NULL, buf[10];
+ unsigned int maddr, page_size, kernel_size, ramdisk_size, total_size;
+ unsigned int load_kernel, copy_start = 0, sig_start, sig_size, boot_size;
+
+ key = getenv("wmt.rsa.pem");
+ s = getenv("boot-method");
+ if (strncmp(s, "boot-nand-normal", 16) == 0) {
+ p = getenv("nand-normal-offs");
+ }
+ load_kernel = mem_kernel;
+ maddr = mem_ramdisk;
+ printf("load_kernel = 0x%x load_ramdisk=0x%x, nand offset = 0x%lx \n", load_kernel, maddr, (ulong)off);
+
+ //read header 608 Bytes
+ ret = WMTLoadImageFormNAND(nand_dev_desc /*+ curr_device*/, off, maddr, nand->oobblock_valid);
+ if (ret) {
+ printf("read nand img header fail\n");
+ return 0;
+ }
+
+ img_hdr = (struct boot_img_hdr *)maddr;
+ if (strncmp((char *)img_hdr->magic, "ANDROID!", 8) != 0) {
+ printf("fail: image header signature is not \"ANDROID!\" \n");
+ return 0;
+ }
+ kernel_size = img_hdr->kernel_size;
+ ramdisk_size = img_hdr->ramdisk_size;
+ page_size = img_hdr->page_size;
+
+ printf("kernel_size = 0x%x ramdisk_size = 0x%x, page_size=0x%x\n",
+ kernel_size, ramdisk_size, page_size);
+
+ if (kernel_size == 0) {
+ printf("kernel size is zero\n");
+ return 0;
+ }
+
+ total_size = (page_size<<2) + kernel_size + ramdisk_size;
+ printf("read kernel from offset = 0x%x to mem = 0x%x, size=0x%x\n", (ulong)off, maddr,total_size);
+ ret = WMTLoadImageFormNAND(nand_dev_desc /*+ curr_device*/, off, maddr, total_size);
+ if (ret) {
+ printf("read nand kernel fail\n");
+ return 0;
+ }
+
+ copy_start = page_size + kernel_size + ((kernel_size%page_size) ? (page_size - (kernel_size%page_size)) : 0);
+ boot_size = copy_start + ramdisk_size + ((ramdisk_size%page_size) ? (page_size - (ramdisk_size%page_size)) : 0);
+ sig_start = copy_start + ramdisk_size + (((copy_start+ramdisk_size)%4096) ? (4096 - ((copy_start+ramdisk_size)%4096)) : 0);
+
+
+ printf("copy_start %x,boot_size%x sig_start%x,maddr%x\n",copy_start,boot_size,sig_start);
+ sig_hdr = (struct sig_header *)(maddr+sig_start);
+
+ if (key) {
+ if (sig_hdr->img_size == 0 || sig_hdr->img_size == 0xFFFFFFFF) {
+ printf("sig=%x not exist!\n", sig_hdr->img_size);
+ // memset((void *)maddr, 0, kernel_size);
+ // return 0;
+ } else {
+ sig_size = sig_hdr->img_size;
+ ret = image_rsa_check(maddr, boot_size, (maddr+sig_start+16), sig_size);
+ if (ret) {
+ printf("boot_addr(0x%x)=0x%x 0x%x bootsize(0x%x) sig_size=0x%x\n", maddr, *(unsigned int *)(maddr), boot_size, sig_size);
+ printf("sig check fail!! sig_hdr(0x%x)=0x%x 0x%x ramdisk(0x%x)\n",
+ (maddr+sig_start), *(unsigned int *)(maddr+sig_start), *(unsigned int *)(maddr+sig_start+4), (maddr+copy_start));
+ memset((void *)maddr, 0, kernel_size);
+ return 0;
+ }
+ }
+ }
+
+ memcpy_itp((void *)load_kernel, (void *)(maddr+page_size), kernel_size);
+
+ if (ramdisk_size != 0) {
+ memcpy_itp((void *)maddr, (void *)(maddr+copy_start), ramdisk_size);
+ sprintf(buf, "%lx", ramdisk_size);
+ setenv(ramdiskSize, buf);
+ } else
+ printf("ramdisk size is zero!\n");
+
+ if (key == NULL)
+ return ramdisk_size;
+
+
+ return sig_size;
+}
+int parse_fbparts(char * env_str, char *str, int *ofs)
+{
+ char *p = NULL;
+ int i = 0, j = 0;
+ int tmp = 0, total = 0, tmp1 = 0;
+ int mach = 1;
+
+
+ p = getenv(env_str);
+ if (p == NULL) {
+ printf("get %s error !!!!!!!!!!!!!!!!!!!\n", env_str);
+ return -1;
+ }
+
+ while(p[i]) {
+ if (p[i] == ':')
+ break;
+ i++;
+ }
+ i = i+1;
+
+ while(p[i]) {
+ if (p[i] < '0' || p[i] > '9') {
+ return -1;
+ } else
+ tmp = (int)simple_strtoul(&p[i], NULL, 10);
+ while(1) {
+ if (p[i] < '0' || p[i] > '9')
+ break;
+ i++;
+ }
+ if (p[i] != 'm') {
+ printf("wrong type for %s : %s\n", env_str, p);
+ return -1;
+ }
+ if (p[i+1] == '@') {
+ if (p[i+2] < '0' || p[i+2] > '9')
+ return -1;
+ tmp1 = (int)simple_strtoul(&p[i+2], NULL, 10);
+ }
+
+ while(p[i] != '(')
+ i++;
+
+ i++;
+ j = 0;
+ while(p[i] != ')') {
+ if (str[j] != p[i])
+ mach = 0;
+ i++;
+ j++;
+ }
+ if (mach) {
+ if (strlen(str) == j)
+ break;
+ }
+ i+=2;
+ mach = 1;
+ total += tmp;
+ }
+ if (total > tmp1)
+ *ofs = total;
+ else
+ *ofs = tmp1;
+ return 0;
+}
+
+void print_nfc_register(void){
+ int j;
+ for (j = 0; j < 0x80; j += 4)
+ printf("XDCR%x ~ XDCR%x = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\r\n",
+ j, j+3,
+ *(unsigned int *)(&pNFCRegs->NFCR0+j+0),
+ *(unsigned int *)(&pNFCRegs->NFCR0+j+1),
+ *(unsigned int *)(&pNFCRegs->NFCR0+j+2),
+ *(unsigned int *)(&pNFCRegs->NFCR0+j+3));
+}
+
+void print_nand_buf(unsigned char * rvalue, int length)
+{
+ int j;
+ for (j = 0; j < length; j += 16)
+ /*printf("Row%x:%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x\n",
+ j, rvalue[j+0], rvalue[j+1], rvalue[j+2], rvalue[j+3], rvalue[j+4],
+ rvalue[j+5], rvalue[j+6], rvalue[j+7], rvalue[j+8], rvalue[j+9],
+ rvalue[j+10], rvalue[j+11], rvalue[j+12], rvalue[j+13], rvalue[j+14], rvalue[j+15]);*/
+ printf("Row%3.3x:%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x\n",
+ j, rvalue[j+0], rvalue[j+1], rvalue[j+2], rvalue[j+3], rvalue[j+4], rvalue[j+5], rvalue[j+6],
+ rvalue[j+7], rvalue[j+8], rvalue[j+9], rvalue[j+10], rvalue[j+11], rvalue[j+12],
+ rvalue[j+13], rvalue[j+14], rvalue[j+15]);
+}
+
+void nfc_ecc_set(unsigned int type, unsigned int ecc, struct nand_chip *nand)
+{
+ pNFCRegs->NFCR13 |= (ERR_CORRECT|BCH_ERR);
+
+ if (type == USE_HW_ECC) {
+ /*
+ printf("USE_HW_ECC \n");
+ if (ecc == ECC60bitPer1K)
+ printf("ECC60bitPer1K\n");
+ else if (ecc == ECC40bitPer1K)
+ printf("ECC40bitPer1K\n");
+ else if (ecc == ECC24bitPer1K)
+ printf("ECC24bitPer1K\n");
+ else if (ecc == ECC12bit)
+ printf("ECC12bit\n");
+ else if(ecc == ECC4bit)
+ printf("ECC4bit\n");
+ */
+ pNFCRegs->NFCR9 = (pNFCRegs->NFCR9&(~(DIS_BCH_ECC|ECC_MOD_SEL)))|(ecc|ECC_INT_EN);
+ pNFCRegs->NFCR9 |= READ_RESUME;/* do for safty */
+ } else {
+ printf("USE_SW_ECC\n");
+ pNFCRegs->NFCR9 |= (DIS_BCH_ECC|ecc|ECC_INT_EN);
+ }
+}
+
+int shift_bit(unsigned int value)
+{
+ int i = 0;
+ while (!(value & 1)) {
+ value >>= 1;
+ i++;
+ if (i == 32)
+ break;
+ }
+ /* return the number count of "zero" bit */
+ return i;
+}
+
+int NFC_WAIT_READY(void)
+{
+ int i = 0;
+
+ while (1) {
+ if (!(pNFCRegs->NFCRa & NFC_BUSY))
+ break;
+ if (i>>21)
+ return -3;
+ i++;
+ }
+ return 0;
+}
+
+int NAND_WAIT_FLASH_READY(void)
+{
+ int i = 0;
+
+ while (1) {
+ if ((pNFCRegs->NFCRa & FLASH_RDY))
+ break;
+ if (i>>21)
+ return -3;
+ i++;
+ }
+ return 0;
+}
+
+int NAND_WAIT_READY(void)
+{
+ int i = 0;
+
+ while (1) {
+ if (pNFCRegs->NFCRb & B2R)
+ break;
+ if ((i>>15))
+ return -1;
+ i++;
+ }
+ pNFCRegs->NFCRb &= B2R;
+ return 0;
+}
+
+int NFC_WAIT_CMD_READY(void)
+{
+ int i = 0;
+
+ while (1) {
+ if (!(pNFCRegs->NFCRa & NFC_CMD_RDY))
+ break;
+ if (i>>21)
+ return -4;
+ i++;
+ }
+ return 0;
+}
+
+int NAND_WAIT_IDLE(void)
+{
+ int i = 0;
+
+ while (1) {
+ if (pNFCRegs->NFCR15 & NFC_IDLE)
+ break;
+ if (i>>21)
+ return -2;
+ i++;
+ }
+ return 0;
+}
+/* returns 0 if block containing pos is OK:
+ * valid erase block and
+ * not marked bad, or no bad mark position is specified
+ * returns 1 if marked bad or otherwise invalid
+ */
+int check_block(struct nand_chip *nand, unsigned long block)
+{
+ /*size_t retlen;
+ uint8_t oob_data;
+ uint16_t oob_data16[6];*/
+ int j, rc = -1;
+ int page[2];
+ page[1] = page[0] = block * nand->dwPageCount;
+ int badpos = (nand->dwBIOffset&0xffff);/*oob_config.badblock_pos;*/
+ page[0] += (nand->dwBI0Position&0xffff);
+ page[1] += (nand->dwBI1Position&0xffff);
+
+ if (block >= nand->dwBlockCount)
+ return 1;
+
+ if (badpos < 0)
+ return 0; /* no way to check, assume OK */
+
+ for (j = 0; j < 2; j++) {
+ rc = nand->nfc_read_page(nand, page[j], (unsigned int)nand->data_buf, nand->oobblock+nand->oobsize);
+ if (rc) {
+ printf("scan bbt err at addr %d, rc=%d\n", page[j], rc);
+ if (rc != -ERR_ECC_UNCORRECT)
+ return rc;
+ printf("read page fail at block%d\n", block);
+ return 1;
+ } else {
+ if (*(((unsigned char *)nand->data_buf)+nand->oobblock+badpos) != 0xFF ||
+ *((unsigned char *)nand->data_buf) != 0xFF) {
+ printf("find bad block : block%d ", block);
+ return 1;
+ }
+ }
+ }
+ #if 0
+ if (nand->bus16) {
+ if (nand_read_oob(nand, (page0 + 0), 12, &retlen, (uint8_t *)oob_data16)
+ || (oob_data16[2] & 0xff00) != 0xff00)
+ return 1;
+ if (nand_read_oob(nand, (page1 + 0), 12, &retlen, (uint8_t *)oob_data16)
+ || (oob_data16[2] & 0xff00) != 0xff00)
+ return 1;
+ } else {
+ /* Note - bad block marker can be on first or second page */
+ if (nand_read_oob(nand, page0 + badpos, 1, &retlen, (unsigned char *)&oob_data)
+ || oob_data != 0xff
+ || nand_read_oob (nand, page1 + badpos, 1, &retlen, (unsigned char *)&oob_data)
+ || oob_data != 0xff)
+ return 1;
+ }
+ #endif
+
+
+ return 0;
+}
+
+/* print bad blocks in NAND flash */
+static void nand_print_bad(struct nand_chip* nand)
+{
+ unsigned long block, chip;
+
+ nfc_ecc_set(USE_SW_ECC, ECC1bit, nand);
+ for (chip = 0; chip < nand->numchips; chip++) {
+ NAND_ENABLE_CE(nand, chip);
+ for (block = 0; block < nand->dwBlockCount; block++) {
+ if (check_block(nand, block))
+ printf(" 0x%8.8lx\n", block);
+ }
+ }
+
+ NAND_DISABLE_CE(nand);
+ set_ECC_mode(nand);
+ puts("\n");
+}
+/*
+*cmd 0 NANDRW_WRITE write, fail on bad block
+* 1 NANDRW_READ read, fail on bad block
+* 2 NAND_WRITE | NANDRW_JFFS2 write, skip bad blocks
+* 3 NAND_READ | NANDRW_JFFS2 read, data all oxff for bad blocks
+* 7 NAND_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks
+*/
+int nand_rw (struct nand_chip* nand, int cmd,
+ size_t start, size_t len,
+ size_t * retlen, u_char * buf, u_char * oob, size_t ooblen)
+{
+
+ int ret = 0, tmplen, tmpooblen, total = 0;
+ unsigned long eblk = ~0;
+ unsigned int erasesize = nand->erasesize;
+ if(!buf && oob) len = ooblen;
+// if(start >= nand->totlen || (start + len) >= nand->totlen) {
+// printf("\nnand address %d is out of size \r\n", start);
+// return -2;
+// }
+ NAND_ENABLE_CE(nand, 0);
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand); /* set pin high */
+ return -1;
+ }
+ while (len) {
+ if((start & (~erasesize)) != eblk) {
+
+ eblk = start & (~erasesize);
+ ret = nand->isbadblock(nand, eblk/nand->erasesize, 0);
+ if(ret < 0) {
+ printf("bbt is not exist\n");
+ NAND_DISABLE_CE(nand);
+ return ret;
+ } else if (ret > 0) {
+ printf("\n bad block is here!");
+ if(cmd == (NANDRW_READ | NANDRW_JFFS2)) {
+ while (len > 0 &&
+ start - eblk < erasesize) {
+ *(buf++) = 0xff;
+ ++start;
+ ++total;
+ --len;
+ }
+ continue;
+ } else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) {
+ start += erasesize;
+ continue;
+ } else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) {
+ start += erasesize;
+ continue;
+ } else {
+ ret = 1;
+ break;
+ }
+ }
+ }
+//END:
+ // end bad block
+ if( cmd & NANDRW_READ) {
+ if(!buf && oob) nand_do_read_oob(nand, start, ooblen, (size_t *)&tmpooblen, oob);
+ else nand_do_read_ops(nand, start, len, (size_t *)&tmplen,
+ buf, ooblen, (size_t *)&tmpooblen, oob);
+ }
+ else {
+ if(!buf && oob) nand_do_write_oob(nand, start, ooblen, (size_t *)&tmpooblen, oob);
+ else nand_do_write_ops(nand, start, len, (size_t *)&tmplen,
+ buf, ooblen, (size_t *)&tmpooblen, oob);
+ }
+ if(ret & 1) break;
+
+ start += tmplen;
+ if(buf) {
+ buf += tmplen;
+ total += tmplen;
+ len -= tmplen;
+ }
+ if(oob) {
+ oob += tmpooblen;
+ ooblen -= tmpooblen;
+ if(!buf) {
+ total += tmpooblen;
+ len -= tmpooblen;
+ }
+ }
+ }
+ if(retlen) *retlen = total;
+#if 0
+ page = (unsigned long)(start >> nand->page_shift);
+ len_in_page = len/nand->oobblock + ((len%nand->oobblock) ? 1 :0);
+ set_ECC_mode(nand);
+
+ while(1) {
+ chip = page / (nand->dwBlockCount * nand->dwPageCount);
+ page_in_chip = page % (nand->dwBlockCount * nand->dwPageCount);
+
+ left_page_in_blk = nand->dwPageCount - page_in_chip%nand->dwPageCount;
+ if (len_in_page >= nand->dwPageCount)
+ page_count = (page%nand->dwPageCount) ? left_page_in_blk : nand->dwPageCount;
+ else
+ page_count = (len_in_page < left_page_in_blk) ? len_in_page : left_page_in_blk;
+ if (cmd & NANDRW_READ) {
+ ret = nand_read_block(nand, (unsigned int)buf, page_in_chip, page_count);
+ if (ret) return ret;
+ } else {
+ ret = nand_write_block(nand, (unsigned int)buf, page_in_chip, page_count, oob);
+ if(ret) return ret;
+ }
+ buf = buf + page_count * nand->oobblock;
+ page = page + page_count;
+ len_in_page -= page_count;
+
+ if(!len_in_page) {
+ NAND_DISABLE_CE(nand);
+ return 0;
+ }
+ }
+#endif
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+
+#if 0
+backup
+/* cmd: 0: NANDRW_WRITE write, fail on bad block
+ * 1: NANDRW_READ read, fail on bad block
+ * 2: NANDRW_WRITE | NANDRW_JFFS2 write, skip bad blocks
+ * 3: NANDRW_READ | NANDRW_JFFS2 read, data all 0xff for bad blocks
+ * 7: NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP read, skip bad blocks
+ */
+int nand_rw (struct nand_chip* nand, int cmd,
+ size_t start, size_t len,
+ size_t * retlen, u_char * buf)
+{
+ int ret = 0, n, total = 0;
+ char eccbuf[6];
+ /* eblk (once set) is the start of the erase block containing the
+ * data being processed.
+ */
+ unsigned long eblk = ~0; /* force mismatch on first pass */
+ unsigned long erasesize = nand->erasesize;
+ NAND_ENABLE_CE(nand, 0); /* set pin low */
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand); /* set pin high */
+ return -1;
+ }
+
+ while (len) {
+ if ((start & (-erasesize)) != eblk) {
+ /* have crossed into new erase block, deal with
+ * it if it is sure marked bad.
+ */
+ eblk = start & (-erasesize); /* start of block */
+ /*printf("check bad block in eblk = 0x%x\n", eblk);*/
+ ret = nand->isbadblock(nand, eblk/nand->erasesize, 0);
+ /*printf("check bad block out ret= %d\n", ret);*/
+ if (ret < 0) {
+ printf("bbt is not exist\n");
+ NAND_DISABLE_CE(nand); /* set pin high */
+ return ret;
+ } else if (ret > 0) {
+ if (cmd == (NANDRW_READ | NANDRW_JFFS2)) {
+ while (len > 0 &&
+ start - eblk < erasesize) {
+ *(buf++) = 0xff;
+ ++start;
+ ++total;
+ --len;
+ }
+ continue;
+ } else if (cmd == (NANDRW_READ | NANDRW_JFFS2 | NANDRW_JFFS2_SKIP)) {
+ start += erasesize;
+ continue;
+ } else if (cmd == (NANDRW_WRITE | NANDRW_JFFS2)) {
+ /* skip bad block */
+ start += erasesize;
+ continue;
+ } else {
+ ret = 1;
+ break;
+ }
+ }
+ }
+ /* The ECC will not be calculated correctly if
+ less than 512 is written or read */
+ /* Is request at least 512 bytes AND it starts on a proper boundry */
+ if((start != ROUND_DOWN(start, 0x200)) || (len < 0x200))
+ printf("Warning block writes should be at least 512 bytes and start on a 512 byte boundry\n");
+
+ if (cmd & NANDRW_READ) {
+ ret = nand_read_ecc(nand, start,
+ min(len, eblk + erasesize - start),
+ (size_t *)&n, (u_char*)buf, (u_char *)eccbuf);
+ } else {
+ ret = nand_write_ecc(nand, start,
+ min(len, eblk + erasesize - start),
+ (size_t *)&n, (u_char*)buf, (u_char *)eccbuf);
+ }
+
+ if (ret&1)
+ break;
+
+ start += n;
+ buf += n;
+ total += n;
+ len -= n;
+ }
+ if (retlen)
+ *retlen = total;
+
+ NAND_DISABLE_CE(nand); /* set pin high */
+ return (ret&1);
+}
+#endif
+
+static void nand_print(struct nand_chip *nand)
+{
+ if (nand->numchips > 1) {
+ printf("%s at 0x%lx,\n"
+ "\t %d chips %s, size %d MB, \n"
+ "\t total size %ld MB, sector size %ld kB\n",
+ nand->name, nand->IO_ADDR, nand->numchips,
+ nand->chips_name, 1 << (nand->chipshift - 20),
+ nand->totlen >> 20, nand->erasesize >> 10);
+ } else {
+ printf("%s at 0x%lx (", nand->chips_name, nand->IO_ADDR);
+ print_size(nand->totlen, ", ");
+ print_size(nand->erasesize, " sector)\n");
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+#if 0
+static int NanD_WaitReady(struct nand_chip *nand, int ale_wait)
+{
+ /* This is inline, to optimise the common case, where it's ready instantly */
+ int ret = 0;
+
+#ifdef NAND_NO_RB /* in config file, shorter delays currently wrap accesses */
+ if(ale_wait)
+ NAND_WAIT_READY(); /* do the worst case 25us wait */
+ else
+ udelay(10);
+#else /* has functional r/b signal */
+ NAND_WAIT_READY();
+#endif
+ return ret;
+}
+
+/* NanD_Command: Send a flash command to the flash chip */
+#if 0
+static inline int NanD_Command(struct nand_chip *nand, unsigned char command)
+{
+ unsigned long nandptr = nand->IO_ADDR;
+
+ /* Assert the CLE (Command Latch Enable) line to the flash chip */
+ NAND_CTL_SETCLE(nandptr);
+
+ /* Send the command */
+ WRITE_NAND_COMMAND(command, nandptr);
+
+ /* Lower the CLE line */
+ NAND_CTL_CLRCLE(nandptr);
+
+#ifdef NAND_NO_RB
+ if(command == NAND_CMD_RESET){
+ u_char ret_val;
+ NanD_Command(nand, NAND_CMD_STATUS);
+ do {
+ ret_val = READ_NAND(nandptr);/* wait till ready */
+ } while((ret_val & 0x40) != 0x40);
+ }
+#endif
+ return NanD_WaitReady(nand, 0);
+}
+#endif
+#endif
+/* NanD_Address: Set the current address for the flash chip */
+void NanD_Address(struct nand_chip *nand, int numbytes, unsigned int col, unsigned int row)
+{
+ unsigned char addr[10];
+ unsigned int i = 0, tmp;
+ unsigned int nandptr = 0;
+
+ if (nand->id == 0xECDED57A)
+ if (row >= (4096*128)) {
+ row = row + 0x80000;
+ }
+
+ memset(addr, 0, 10);
+ nandptr = g_WMTNFCBASE + 0x0c;
+ if (numbytes == ADDR_COLUMN_PAGE) {
+ for (i = 0; i < nand->col; i++)
+ addr[i] = (col>>(i*8));
+ for (i = nand->col; i < (nand->row + nand->col); i++)
+ addr[i] = (row>>((i-nand->col)*8));
+ for (i = 0; i <= (nand->col+nand->row); i += 2, nandptr += 4) {
+ tmp = (addr[i+1]<<8)+addr[i];
+ WRITE_NAND16(tmp, nandptr);
+ /*printf("write %x to %8.8x\n",tmp,nandptr);*/
+ }
+ }
+ if (numbytes == ADDR_COLUMN) {
+ for (i = 0; i < nand->col; i++)
+ addr[i] = (col>>(i*8));
+ for (i = 0; i < nand->col; i += 2, nandptr += 4) {
+ tmp = (addr[i+1]<<8)+addr[i];
+ WRITE_NAND16(tmp, nandptr);
+ }
+ }
+ if (numbytes == ADDR_PAGE) {
+ for (i = 0; i < nand->row; i++)
+ addr[i] = (row>>(i*8));
+
+ for (i = 0; i < nand->row; i += 2, nandptr += 4) {
+ tmp = (addr[i+1]<<8)+addr[i];
+ WRITE_NAND16(tmp, nandptr);
+ }
+ }
+}
+#if 0
+static int NanD_Address(struct nand_chip *nand, int numbytes, unsigned long ofs)
+{
+ unsigned long nandptr;
+ int i;
+
+ nandptr = nand->IO_ADDR;
+
+ /* Assert the ALE (Address Latch Enable) line to the flash chip */
+ NAND_CTL_SETALE(nandptr);
+
+ /* Send the address */
+ /* Devices with 256-byte page are addressed as:
+ * Column (bits 0-7), Page (bits 8-15, 16-23, 24-31)
+ * there is no device on the market with page256
+ * and more than 24 bits.
+ * Devices with 512-byte page are addressed as:
+ * Column (bits 0-7), Page (bits 9-16, 17-24, 25-31)
+ * 25-31 is sent only if the chip support it.
+ * bit 8 changes the read command to be sent
+ * (NAND_CMD_READ0 or NAND_CMD_READ1).
+ */
+
+ if (numbytes == ADDR_COLUMN || numbytes == ADDR_COLUMN_PAGE)
+ WRITE_NAND_ADDRESS(ofs, nandptr);
+
+ ofs = ofs >> nand->page_shift;
+
+ if (numbytes == ADDR_PAGE || numbytes == ADDR_COLUMN_PAGE) {
+ for (i = 0; i < nand->pageadrlen; i++, ofs = ofs >> 8) {
+ WRITE_NAND_ADDRESS(ofs, nandptr);
+ }
+ }
+
+ /* Lower the ALE line */
+ NAND_CTL_CLRALE(nandptr);
+
+ /* Wait for the chip to respond */
+ return NanD_WaitReady(nand, 1);
+}
+#endif
+
+int nfc_dma_cfg(unsigned int buf, unsigned int len, unsigned int wr)
+{
+ unsigned int status, CurDes_off = 0, i, dma_unit;
+
+ //if (!len || buf & 0x03) {
+ if (!len) {
+ printf("Error : length = %x , address = %x\r\n", len, buf);
+ return -1;
+ }
+
+ if (!ReadDesc) {
+ printf("alloc ReadDesc failed\n");
+ return -1;
+ }
+ if (len > 512 && pNFCRegs->NFCR9&DIS_BCH_ECC) {
+ len = 512;
+ if ((pNFCRegs->NFCR9&ECC_MOD_SEL) >= ECC24bitPer1K)
+ len = 1024;
+ }
+ pNFCRegs->NFCR8 = len-1;
+ /* Interrupt setting */
+ /*disable_irq();
+ set_irq_handlers(IRQ_NFC_DMA, nand_dma_isr);
+ set_int_route(IRQ_NFC_DMA, 0);
+ unmask_interrupt(IRQ_NFC_DMA);
+ enable_irq();*/
+
+ if (pNand_PDma_Reg->DMA_ISR & NAND_PDMA_IER_INT_STS)
+ pNand_PDma_Reg->DMA_ISR = NAND_PDMA_IER_INT_STS;
+
+ if (pNand_PDma_Reg->DMA_ISR & NAND_PDMA_IER_INT_STS) {
+ printf("PDMA interrupt status can't be clear ");
+ printf("pNand_PDma_Reg->DMA_ISR = 0x%8.8x \n", (unsigned int)pNand_PDma_Reg->DMA_ISR);
+ }
+ if ((pNFCRegs->NFCR9&ECC_MOD_SEL) >= ECC24bitPer1K)
+ dma_unit = 1024;
+ else
+ dma_unit = 512;
+ status = nand_init_pdma();
+ if (status)
+ printf("nand_init_pdma fail status = 0x%x", status);
+ nand_alloc_desc_pool(ReadDesc);
+ /*printf(" ReadDesc = 0x%x\r\n", (unsigned int ) ReadDesc);*/
+ /*printf(" buf = 0x%x\r\n", (unsigned int ) buf);*/
+ for (i = 0; i < (len/dma_unit); i++) {
+ nand_init_short_desc(ReadDesc+CurDes_off, dma_unit, (unsigned long *)(buf+i*dma_unit),
+ ((i == ((len/dma_unit)-1)) && !(len%dma_unit)) ? 1 : 0);
+ CurDes_off += sizeof(NAND_PDMA_DESC_S)/4;
+ }
+ if (len%dma_unit)
+ nand_init_short_desc(ReadDesc+CurDes_off, (len%dma_unit),
+ (unsigned long *)(buf+i*dma_unit), 1);
+
+ nand_config_pdma(ReadDesc, wr);
+ return 0;
+}
+
+int nand_init_pdma(void)
+{
+ pNand_PDma_Reg->DMA_GCR = NAND_PDMA_GCR_SOFTRESET;
+ pNand_PDma_Reg->DMA_GCR = NAND_PDMA_GCR_DMA_EN;
+ if (pNand_PDma_Reg->DMA_GCR & NAND_PDMA_GCR_DMA_EN)
+ return 0;
+ else
+ return 1;
+}
+
+
+int nand_free_pdma(void)
+{
+ pNand_PDma_Reg->DMA_DESPR = 0;
+ pNand_PDma_Reg->DMA_GCR = 0;
+ return 0;
+}
+
+
+int nand_alloc_desc_pool(unsigned long *DescAddr)
+{
+ int i;
+ for (i = 0; i < 40; i++)
+ *(DescAddr+i) = 0;
+ return 0;
+}
+
+int nand_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End)
+{
+ struct _NAND_PDMA_DESC_S *CurDes_S;
+ CurDes_S = (struct _NAND_PDMA_DESC_S *) DescAddr;
+ CurDes_S->ReqCount = ReqCount;
+ CurDes_S->i = End;
+ CurDes_S->end = End;
+ CurDes_S->format = 0;
+ CurDes_S->DataBufferAddr = (unsigned long)BufferAddr;
+ return 0;
+}
+
+int nand_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr,
+unsigned long *BranchAddr, int End)
+{
+ struct _NAND_PDMA_DESC_L *CurDes_L;
+ CurDes_L = (struct _NAND_PDMA_DESC_L *) DescAddr;
+ CurDes_L->ReqCount = ReqCount;
+ CurDes_L->i = 0;
+ CurDes_L->format = 1;
+ CurDes_L->DataBufferAddr = (unsigned long)BufferAddr;
+ CurDes_L->BranchAddr = (unsigned long)BranchAddr;
+ if (End) {
+ CurDes_L->end = 1;
+ CurDes_L->i = 1;
+ }
+
+ return 0;
+}
+
+
+int nand_config_pdma(unsigned long *DescAddr, unsigned int dir)
+{
+ /*pNand_PDma_Reg->DMA_IER = NAND_PDMA_IER_INT_EN;*/
+ pNand_PDma_Reg->DMA_DESPR = (unsigned long)DescAddr;
+ if (dir == NAND_PDMA_READ)
+ pNand_PDma_Reg->DMA_CCR |= NAND_PDMA_CCR_peripheral_to_IF;
+ else
+ pNand_PDma_Reg->DMA_CCR &= ~NAND_PDMA_CCR_peripheral_to_IF;
+
+ pNand_PDma_Reg->DMA_CCR |= NAND_PDMA_CCR_RUN;
+
+ return 0;
+}
+
+int nand_pdma_handler(void)
+{
+ unsigned long status = 0;
+ unsigned long count = 0;
+
+ count = 0x100000;
+ /* polling CSR TC status */
+ do {
+ count--;
+ if (pNand_PDma_Reg->DMA_ISR & NAND_PDMA_IER_INT_STS) {
+ status = pNand_PDma_Reg->DMA_CCR & NAND_PDMA_CCR_EvtCode;
+ pNand_PDma_Reg->DMA_ISR &= NAND_PDMA_IER_INT_STS;
+ break ;
+ }
+ if (count == 0) {
+ printf("PDMA Time Out!\n");
+ printf("pNand_PDma_Reg->DMA_CCR = 0x%8.8x\r\n",
+ (unsigned int)pNand_PDma_Reg->DMA_CCR);
+
+ break;
+ }
+ } while (1);
+ if (status == NAND_PDMA_CCR_Evt_ff_underrun)
+ printf("PDMA Buffer under run!\n");
+
+ if (status == NAND_PDMA_CCR_Evt_ff_overrun)
+ printf("PDMA Buffer over run!\n");
+
+ if (status == NAND_PDMA_CCR_Evt_desp_read)
+ printf("PDMA read Descriptor error!\n");
+
+ if (status == NAND_PDMA_CCR_Evt_data_rw)
+ printf("PDMA read/write memory descriptor error!\n");
+
+ if (status == NAND_PDMA_CCR_Evt_early_end)
+ printf("PDMA read early end!\n");
+
+ if (count == 0) {
+ printf("PDMA TimeOut!\n");
+ // while (1)
+ ;
+ }
+
+ return 0;
+}
+
+int hynix_read_retry_get_para(struct nand_chip *nand)
+{
+ int i, status = -1, index = 0, regc = 4;
+ unsigned int cfg, para[4], IdList[4] = {0xADD794DA, 0xADD79491, 0xADDE94DA, 0x11111111};
+ unsigned char *FIFO = (unsigned char *) &pNFCRegs->FIFO[48];
+ unsigned char reg[4] = {4, 8, 8 , 8};
+ unsigned char addr[6][8] = {{0xA7, 0xAD, 0xAE, 0xAF, 0x00, 0x00, 0x00, 0x00},
+ {0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
+ {0xA7, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3},
+ {0xA7, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3},
+ {0xA7, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3},
+ {0xA7, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3}};
+ for (i = 0; i < 4; i++)
+ para[i] = 0;
+ for (i = 0; i < 4; i++) {
+ if (nand->id == IdList[i]) {
+ index = i;
+ regc = reg[i];
+ break;
+ }
+ }
+
+ status = NAND_WAIT_IDLE();
+ if (status)
+ return status;
+
+ for (i = 0; i < regc;i++) {
+ if (nfc_dma_cfg((unsigned int)&para[i], 1, 0))
+ return -4;
+ pNFCRegs->NFCRd |= HIGH64FIFO;
+ //print_nfc_register();
+ if (i == 0) {
+ FIFO[0] = 0x37;
+ FIFO[1] = addr[index][0];
+ //printf("FIFO:");
+ //for (k=0;k<2;k++)
+ //printf("[%d]=0x%x ", k, FIFO[k]);
+ //printf("\n");
+ // set address latch ALE(high) and CLE(lower)
+ pNFCRegs->NFCRc = 0x00020001;
+ cfg = (0x02<<1);
+ } else {
+ FIFO[0] = addr[index][i];
+ // set address latch ALE(high) and CLE(lower)
+ pNFCRegs->NFCRc = 0x00010000;
+ cfg = (0x01<<1);
+ }
+ pNFCRegs->NFCR1 = NAND2NFC|cfg|NFC_TRIGGER; /* cfg & start*/
+
+ /* wait command/address to finished */
+ status = NFC_WAIT_CMD_READY();
+ if (status) {
+ printf("[hynix_read_retry_get_para]retry c1 wait cmd/addr ready time out\n");
+ return status;
+ }
+
+ status = NFC_WAIT_READY();
+ if (status) {
+ printf("retry wait NFC ready time out\n");
+ return status;
+ }
+
+ status = nand_pdma_handler();
+ nand_free_pdma();
+ if (status)
+ return status;
+
+ printf("para[%d]=0x%x\n", i, para[i]);
+ }
+ status = NAND_WAIT_IDLE();
+ if (status) {
+ printf("retry wait idle time out\n");
+ return status;
+ }
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+
+ //printf("retry start cmd end para = 0x%x %x %x %x\n", para[0], para[1], para[2], para[3]);
+ return 0;
+}
+
+int get_read_retry_para(struct nand_chip *nand)
+{
+ NAND_ENABLE_CE(nand, 0);
+ if (nand->id == 0xADD794DA)
+ hynix_read_retry_get_para(nand);
+ /*else
+ toshiba_read_retry_get_para(struct nand_chip *nand)*/
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+
+int hynix_read_retry_set_para(struct nand_chip *nand, int reg)
+{
+ int i, status = -1, index, regc = 4;
+ unsigned int cfg, IdList[4] = {0xADD794DA, 0xADD79491, 0xADDE94DA, 0x11111111};
+ unsigned char *FIFO = (unsigned char *) &pNFCRegs->FIFO[48];
+ unsigned char reg_cnt[4] = {4, 8, 8 , 8};
+ unsigned char addr[6][8] = {{0xA7, 0xAD, 0xAE, 0xAF, 0x00, 0x00, 0x00, 0x00},
+ {0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
+ {0xA7, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3},
+ {0xA7, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3},
+ {0xA7, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3},
+ {0xA7, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3}};
+ unsigned int cmd[7][4] = {{0x20, 0x20, 0x74, 0xC1},
+ {0, 0x6, 0xA, 0x6},
+ {0, 0x3, 0x7, 0x8},
+ {0, 0x6, 0xD, 0xF},
+ {0, 0x9, 0x14, 0x17},
+ {0, 0x0, 0x1A, 0x1E},
+ {0, 0x0, 0x20, 0x25}};
+
+ for (i = 0; i < 4; i++) {
+ if (nand->id == IdList[i]) {
+ index = i;
+ regc = reg_cnt[i];
+ break;
+ }
+ }
+ status = NAND_WAIT_IDLE();
+ if (status)
+ return status;
+
+ for (i = 0; i < (regc+1);i++) {
+ if (i < regc) {
+ if (nfc_dma_cfg((unsigned int)&cmd[reg][i], 1, 1))
+ return -4;
+ }
+ pNFCRegs->NFCRd |= HIGH64FIFO;
+ if (i == 0) {
+ FIFO[0] = 0x36;
+ FIFO[1] = addr[0][0];
+ //printf("FIFO:");
+ //for (k=0;k<2;k++)
+ //printf("[%d]=0x%x ", k, FIFO[k]);
+ //printf("\n");
+ // set address latch ALE(high) and CLE(lower)
+ pNFCRegs->NFCRc = 0x00020001;
+ cfg = (0x02<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER; /* cfg & start*/
+ } else if (i < regc) {
+ FIFO[0] = addr[0][i];
+ // set address latch ALE(high) and CLE(lower)
+ pNFCRegs->NFCRc = 0x00010000;
+ cfg = (0x01<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER; /* cfg & start*/
+ } else {
+ FIFO[0] = 0x16;
+ pNFCRegs->NFCRc = 0x00000001;
+ cfg = (0x01<<1);
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|cfg|NFC_TRIGGER; /* cfg & start*/
+ }
+
+ /* wait command/address to finished */
+ status = NFC_WAIT_CMD_READY();
+ if (status) {
+ printf("[hynix_read_retry_set_para]retry c1 wait cmd/addr ready time out\n");
+ return status;
+ }
+
+ status = NFC_WAIT_READY();
+ if (status) {
+ printf("retry wait NFC ready time out\n");
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ return status;
+ }
+ if (i < regc) {
+ status = nand_pdma_handler();
+ nand_free_pdma();
+ if (status) {
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ return status;
+ }
+ }
+ }
+ status = NAND_WAIT_IDLE();
+ if (status) {
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ printf("retry c1 wait idle time out\n");
+ return status;
+ }
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+
+ return 0;
+}
+
+int set_read_retry_para(struct nand_chip *nand, int reg)
+{
+ NAND_ENABLE_CE(nand, 0);
+ if (nand->id == 0xADD794DA)
+ hynix_read_retry_set_para(nand, reg);
+ if (nand->id == 0xADDE94EB) {
+ force_set_rr_value = reg;
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, ECC_ERROR_VALUE);
+ force_set_rr_value = -1;
+ }
+
+ /*else
+ toshiba_read_retry_get_para(struct nand_chip *nand)*/
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+
+int NFC_CHECK_ECC(void)
+{
+ int i = 0;
+
+ while (1) {
+ if (!(pNFCRegs->NFCRa & NFC_BUSY))
+ break;
+ if ((pNFCRegs->NFCRb&(ERR_CORRECT|BCH_ERR)) == (ERR_CORRECT|BCH_ERR))
+ return 1;
+ if (i>>21)
+ return -3;
+ i++;
+ }
+ if (pNFCRegs->NFCRb&BCH_ERR) {
+ while(1) {
+ if (pNFCRegs->NFCRb&ERR_CORRECT)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void nfc_BCH_ecc_correct(struct nand_chip *nand, unsigned int bitcnt, unsigned int maddr)
+{
+ unsigned int ofs, i = 0, type, bank;
+ unsigned int posptr, dma_unit;
+ unsigned short err_ofs;
+ unsigned int byte_ofs, bit_ofs;
+ unsigned char err_data;
+ unsigned int ofs1 = 0;
+ struct ECC_size_info ECC_size;
+
+ ECC_size.ecc_engine = pNFCRegs->NFCR9&ECC_MOD_SEL;
+ calculate_ECC_info(nand, &ECC_size);
+ dma_unit = nand->oobblock/ECC_size.banks;
+
+#ifdef SHOWME_ECC
+ printf("error happen at 0x%x", maddr);
+#endif
+ posptr = g_WMTNFCBASE + 0x60;
+ type = pNFCRegs->NFCRd & OOB_READ;
+ bank = (pNFCRegs->NFCR17 & BANK_NUM)>>8;
+ if (type) {
+ #ifdef SHOWME_ECC
+ printf("bank%d red area\n",bank);
+ #endif
+ ofs = g_WMTNFCBASE + 0x1C0;
+ } else {
+ #ifdef SHOWME_ECC
+ printf("bank%d data area \n",bank);
+ #endif
+ ofs1 = (bank*dma_unit);
+ ofs = maddr + (bank*dma_unit);
+ }
+
+ for (i = 0; i < bitcnt; i++, posptr+=2) {
+ READ_NAND16(err_ofs, posptr);
+ byte_ofs = (unsigned int)(err_ofs>>3);
+ bit_ofs = (unsigned int)(err_ofs & 0x07);
+#ifdef POST_TEST_FUNS
+ if(type) {
+ g_ecc_result.pred[g_ecc_rcnt] = (byte_ofs*8)+bit_ofs;
+ g_ecc_rcnt++;
+ if (g_ecc_rcnt >= MAX_ECC_BIT)
+ g_ecc_rcnt = 0;
+ } else {
+ g_ecc_result.pos[g_ecc_dcnt] = ((ofs1+byte_ofs)*8)+bit_ofs;
+ g_ecc_dcnt++;
+ if (g_ecc_dcnt >= MAX_ECC_BIT)
+ g_ecc_dcnt = 0;
+ }
+#endif
+ #ifdef SHOWME_ECC
+ printf(" byte%d, bit%d ",byte_ofs,bit_ofs);
+ #endif
+ if (byte_ofs >= ((bank < (ECC_size.banks-1))?dma_unit:(dma_unit+24))) {
+ #ifdef SHOWME_ECC
+ printf("\n");
+ #endif
+ continue;
+ }
+
+ if (byte_ofs >= dma_unit) {
+ ofs = g_WMTNFCBASE + 0x1C0;
+ READ_NAND8(err_data, (ofs+byte_ofs-dma_unit));
+ } else
+ READ_NAND8(err_data, (ofs+byte_ofs));
+ #ifdef SHOWME_ECC
+ printf("org (0x%x) 0x%x => ",(ofs+byte_ofs),err_data);
+ #endif
+ if (err_data & (1<<bit_ofs))
+ err_data &= ~(1<<bit_ofs);
+ else
+ err_data |= (1<<bit_ofs);
+ #ifdef SHOWME_ECC
+ printf("0x%x\n",err_data);
+ #endif
+ if (byte_ofs >= dma_unit)
+ WRITE_NAND8(err_data, (ofs+byte_ofs-dma_unit));
+ else
+ WRITE_NAND8(err_data, (ofs+byte_ofs));
+ }
+}
+
+unsigned char rdmz_FF[18][24] = {
+/*{0xac,0x77,0xed,0x0b,0x8a,0xde,0x0f,0xd8},
+{0xd6,0xbb,0xf6,0x85,0x45,0xef,0x07,0x6c},
+{0xeb,0xdd,0xfb,0x42,0x22,0x77,0x03,0xb6},
+{0x75,0xee,0xfd,0xa1,0x11,0xbb,0x81,0x5b},
+{0x3a,0x77,0x7e,0xd0,0x88,0x5d,0x40,0xad},
+{0x1d,0xbb,0xbf,0x68,0x44,0xae,0x20,0x56},
+{0x8e,0xdd,0x5f,0xb4,0xa2,0xd7,0x90,0x2b},
+{0x47,0xee,0xaf,0x5a,0xd1,0x6b,0xc8,0x95},
+{0xa3,0x77,0x57,0xad,0x68,0xb5,0xe4,0x4a},
+{0x51,0xbb,0xab,0xd6,0x34,0x5a,0xf2,0x25},
+{0x28,0xdd,0x55,0xeb,0x9a,0xad,0xf9,0x12},
+{0x94,0xee,0xaa,0x75,0x4d,0xd6,0xfc,0x09},
+{0xca,0x77,0xd5,0xba,0xa6,0xeb,0xfe,0x84},
+{0x65,0xbb,0x6a,0x5d,0x53,0xf5,0x7f,0xc2},
+{0xb2,0xdd,0xb5,0x2e,0x29,0x7a,0x3f,0x61},
+{0x59,0xee,0xda,0x17,0x14,0xbd,0x1f,0xb0}*//* byte 24 ~ byte 48 */
+{0x3d,0xf0,0xfb,0x7f,0x28,0xa5,0x31,0xc8,0xa9,0x4e,0xe3,0x23,0x9e,0x65,0x79,0xef,0x51,0x13,0x8c,0xab,0x5e,0xa5,0xa9,0x23},
+{0x1e,0xf8,0xfd,0xbf,0x94,0x52,0x18,0x64,0x54,0x27,0xf1,0x91,0xcf,0x32,0x3c,0xf7,0xa8,0x09,0xc6,0x55,0xaf,0xd2,0xd4,0x91},
+{0x8f,0xfc,0xfe,0xdf,0xca,0xa9,0x8c,0x32,0x2a,0x93,0xf8,0x48,0xe7,0x99,0x9e,0xfb,0x54,0x84,0x63,0x2a,0x57,0xe9,0xea,0x48},
+{0xc7,0x7e,0x7f,0xef,0x65,0xd4,0x46,0x99,0x95,0xc9,0x7c,0x24,0xf3,0xcc,0x4f,0xfd,0xaa,0x42,0x31,0x95,0xab,0x74,0x75,0x24},
+{0xe3,0x3f,0x3f,0xf7,0xb2,0xea,0x23,0x4c,0x4a,0x64,0x3e,0x12,0x79,0x66,0xa7,0xfe,0xd5,0xa1,0x18,0xca,0xd5,0xba,0xba,0x12},
+{0x71,0x9f,0x1f,0xfb,0xd9,0x75,0x11,0xa6,0xa5,0x32,0x9f,0x09,0x3c,0x33,0xd3,0x7f,0x6a,0x50,0x0c,0xe5,0x6a,0x5d,0x5d,0x89},
+{0xb8,0x4f,0x8f,0xfd,0x6c,0xba,0x08,0x53,0x52,0x19,0x4f,0x84,0x1e,0x99,0xe9,0x3f,0x35,0x28,0x06,0xf2,0x35,0x2e,0x2e,0x44},
+{0xdc,0xa7,0x47,0xfe,0x36,0xdd,0x04,0xa9,0x29,0x0c,0x27,0x42,0x0f,0x4c,0xf4,0x9f,0x9a,0x94,0x03,0x79,0x1a,0x97,0x97,0x22},
+{0x6e,0x53,0x23,0x7f,0x1b,0xee,0x02,0x54,0x94,0x06,0x93,0x21,0x87,0xa6,0x7a,0x4f,0xcd,0xca,0x81,0x3c,0x8d,0xcb,0x4b,0x91},
+{0xb7,0x29,0x91,0xbf,0x0d,0xf7,0x81,0x2a,0xca,0x03,0xc9,0x90,0x43,0xd3,0xbd,0xa7,0xe6,0xe5,0x40,0x9e,0x46,0xe5,0xa5,0xc8},
+{0x5b,0x14,0xc8,0xdf,0x06,0x7b,0x40,0x15,0x65,0x81,0xe4,0xc8,0xa1,0x69,0x5e,0xd3,0x73,0xf2,0x20,0xcf,0xa3,0x72,0x52,0xe4},
+{0xad,0x0a,0x64,0xef,0x03,0xbd,0x20,0x0a,0x32,0xc0,0x72,0x64,0xd0,0xb4,0x2f,0xe9,0x39,0x79,0x90,0x67,0xd1,0xb9,0x29,0x72},
+{0xd6,0x05,0xb2,0xf7,0x81,0x5e,0x10,0x85,0x99,0xe0,0x39,0x32,0xe8,0x5a,0x97,0xf4,0x1c,0x3c,0xc8,0xb3,0xe8,0x5c,0x94,0x39},
+{0xeb,0x82,0xd9,0xfb,0x40,0x2f,0x88,0x42,0x4c,0x70,0x1c,0x19,0xf4,0x2d,0xcb,0x7a,0x8e,0x9e,0x64,0x59,0xf4,0x2e,0x4a,0x1c},
+{0xf5,0xc1,0xec,0xfd,0xa0,0x97,0xc4,0x21,0xa6,0x38,0x8e,0x8c,0x7a,0x96,0xe5,0xbd,0x47,0x4f,0x32,0xac,0x7a,0x97,0xa5,0x8e},
+{0x7a,0xe0,0xf6,0xfe,0x50,0x4b,0x62,0x90,0x53,0x9c,0xc7,0x46,0x3d,0xcb,0xf2,0xde,0xa3,0x27,0x19,0x56,0xbd,0x4b,0x52,0x47}
+};
+unsigned int rdmz_badblk[2][6] = {
+{0x80040fc2,0x37ce5ad7,0xdc1cb156,0x10869a61,0x5473ecae,0xdc565aa1},
+{0x400207e1,0x9be7ad6b,0x6e0ed8ab,0x8c3cd30,0xaa39f657,0x6e2b2d50}
+};
+
+
+int check_all_FF_sw(unsigned int *buf, int size, struct nand_chip *nand)
+{
+ int i = 0, j = 0;
+
+ //for <=12-bit mode oob parity only has 20 bytes --> check all-FF size need to be adjusted.
+ if ((pNFCRegs->NFCR9&ECC_MOD_SEL) < 5)
+ size--;
+
+ for (i = 0; i < size; i++) {
+ if (buf[i] != 0xFFFFFFFF && buf[i] != 0) {
+ printf("[check_all_FF_sw]unc %d=[%x]\n",i, buf[i]);
+ } else
+ j++;
+ }
+ if (j > (size/2))
+ return 1;
+
+ return 0;
+}
+
+int check_all_FF(unsigned int *buf, int size, struct nand_chip *nand)
+{
+ int i = 0, j = 0, k = 0;
+ unsigned int *bf = (unsigned int *)&rdmz_FF[nand->cur_page%16][0];
+ unsigned int *bf1 = &rdmz_badblk[nand->cur_page%2][0];
+
+ //for <=12-bit mode oob parity only has 20 bytes --> check all-FF size need to be adjusted.
+ if ((pNFCRegs->NFCR9&ECC_MOD_SEL) < 5)
+ size--;
+
+ if (nand->dwRdmz) {
+ for (i = 0; i < size; i++) {
+ if (buf[i] != bf[i] && buf[i] != bf1[i]) {
+ k++;
+ /*if (nand->cur_page < ((nand->dwBlockCount - 8) * nand->dwPageCount))
+ printf("need retry %d=[%x][%x] \n",i, buf[i],bf[i]);*/
+ } else
+ j++;
+ }
+ if (j > (size/2))
+ return 1;
+ } else {
+ for (i = 0; i < size; i++) {
+ if (buf[i] != 0xFFFFFFFF && buf[i] != 0) {
+ k++;
+ printf("[check_all_FF]unc %d=[%x]\n",i, buf[i]);
+ } else
+ j++;
+ }
+ if (j > (size/2))
+ return 1;
+ }
+ /*if (nand->cur_page < ((nand->dwBlockCount - 8) * nand->dwPageCount)) {
+ print_nfc_register();
+ printf("cur page 0x%x\n", nand->cur_page);
+ }*/
+ return 0;
+}
+
+int nfc_BCH_ecc_check_sw(struct nand_chip *nand, unsigned int maddr)
+{
+ unsigned int cnt = 0, count = 0x100;
+ int rc = 0, all_FF = 0;
+
+ if ((pNFCRegs->NFCRb&(ERR_CORRECT|BCH_ERR)) == (ERR_CORRECT|BCH_ERR)) {
+ cnt = pNFCRegs->NFCR17 & BCH_ERR_CNT;
+ if (cnt == BCH_ERR_CNT) {
+ all_FF = check_all_FF_sw((unsigned int *)&pNFCRegs->FIFO[24], 6, nand);
+ /*if (!all_FF)
+ printf("UncorErr\n");*/
+ //print_nfc_register();
+ rc = -ERR_ECC_UNCORRECT;
+ } else {
+ if (!cnt) {
+ printf("report ecc error : count =%d\n", cnt);
+ pNFCRegs->NFCR9 |= READ_RESUME;
+ rc = -ERR_UNKNOW;
+ }
+ }
+ if (rc) {
+ pNFCRegs->NFCRb &= (ERR_CORRECT|BCH_ERR);
+ pNFCRegs->NFCR9 |= READ_RESUME;
+ if (all_FF)
+ return 0;
+ return rc;
+ }
+
+ while ((0 != (pNand_PDma_Reg->DMA_RBR%0x200)) && (count--))
+ printf("dma is not finish please wait");
+
+ nfc_BCH_ecc_correct(nand, cnt, maddr);
+ }
+ pNFCRegs->NFCRb &= (ERR_CORRECT|BCH_ERR);
+ pNFCRegs->NFCR9 |= READ_RESUME;
+
+ return 0;
+}
+
+int nfc_BCH_ecc_check(struct nand_chip *nand, unsigned int maddr)
+{
+ unsigned int cnt = 0, count = 0x100;
+ int rc = 0, all_FF = 0;
+
+ if ((pNFCRegs->NFCRb&(ERR_CORRECT|BCH_ERR)) == (ERR_CORRECT|BCH_ERR)) {
+ cnt = pNFCRegs->NFCR17 & BCH_ERR_CNT;
+
+ if (r_w_check_ecc_robust) {
+ //printf("cnt=%d ",cnt);
+ if(cnt >= max_ecc_bits)
+ max_ecc_bits = cnt;
+ //printf("max_ecc_bits=%d \n",max_ecc_bits);
+ }
+
+ if (cnt == BCH_ERR_CNT) {
+ unsigned int bank, oob, dma_unit = 1024, tot_bank;
+ oob = pNFCRegs->NFCRd & OOB_READ;
+ bank = (pNFCRegs->NFCR17 & BANK_NUM)>>8;
+ if ((pNFCRegs->NFCR9&ECC_MOD_SEL) < 5) {
+ dma_unit = 512;
+ printf("warning : bank size=512\n");
+ }
+ if (nand->dwECCBitNum == 60)
+ tot_bank = (nand->oobblock_valid/dma_unit)+1;
+ else
+ tot_bank = (nand->oobblock/dma_unit);
+
+ nand->unc_banks |= (1 << bank);
+
+ rc = -ERR_ECC_UNCORRECT;
+
+ if (oob || bank == (tot_bank-1)) {
+ if (nand->dwECCBitNum == 60) {
+ if (nand->bbt_sw_rdmz)
+ all_FF = check_all_FF_sw((unsigned int *)(maddr+nand->oobblock_valid+24), 6, nand);
+ else
+ all_FF = check_all_FF((unsigned int *)(maddr+nand->oobblock_valid+24), 6, nand);
+ } else {
+ if (nand->bbt_sw_rdmz)
+ all_FF = check_all_FF_sw((unsigned int *)&pNFCRegs->FIFO[24], 6, nand);
+ else
+ all_FF = check_all_FF((unsigned int *)&pNFCRegs->FIFO[24], 6, nand);
+ }
+
+ if (oob && (!all_FF)) {
+ printf("oob uncor Error unc_banks=0x%x allff=%d tot=0x%x\n",nand->unc_banks, all_FF,((1<<tot_bank)-1));
+ }
+ if (all_FF) {
+ memset((void *)maddr, 0xff, nand->oobblock);
+ //printf("uncor Error unc_banks=0x%x allff=%d tot=0x%x\n",nand->unc_banks, all_FF,((1<<tot_bank)-1));
+ //printf("all FF \n");
+ }
+ }
+ //print_nfc_register();
+ } else {
+ if (!cnt) {
+ printf("report ecc error : count =%d\n", cnt);
+ pNFCRegs->NFCR9 |= READ_RESUME;
+ rc = -ERR_UNKNOW;
+ }
+ }
+ if (rc) {
+ pNFCRegs->NFCRb &= (ERR_CORRECT|BCH_ERR);
+ pNFCRegs->NFCR9 |= READ_RESUME;
+ if (all_FF)
+ return 1;
+ return rc;
+ }
+
+ while ((0 != (pNand_PDma_Reg->DMA_RBR%0x200)) && (count--))
+ printf("dma is not finish please wait");
+
+ nfc_BCH_ecc_correct(nand, cnt, maddr);
+ }
+ pNFCRegs->NFCRb &= (ERR_CORRECT|BCH_ERR);
+ pNFCRegs->NFCR9 |= READ_RESUME;
+
+ return 0;
+}
+
+static int wmt_nand_read_oob_60bit(struct nand_chip *nand, unsigned int maddr)
+{
+ int i;
+ unsigned int *FIFO = (unsigned int *)pNFCRegs->FIFO;
+
+ unsigned int *buf = (unsigned int *)(maddr + nand->oobblock_valid);
+
+ for (i = 0; i < 6; i++) {
+ FIFO[i] = buf[i];
+ //printf("buf[%d]=0x%x \n",i,buf[i]);
+ }
+ //printf("\n");
+
+ return 0;
+}
+
+
+int nfc_BCH_read_page_60bit(
+struct nand_chip *nand,
+unsigned int page,
+unsigned int maddr,
+unsigned int len)
+{
+ //printf("nfc_BCH_read_page_60bit page=0x%x maddr=0x%x\n",page,maddr);
+
+ unsigned int row = 0, col = 0, dma_unit = 512, pageInBlk = 0;
+ int rc = -1, err = 0, i;
+ int total_times = 1;
+ int retry_pass = 0;
+ int retry = 0, total_try_times = 0;
+ unsigned char *cmd2 = (unsigned char *)&pNFCRegs->NFCR5;
+ unsigned char cmd[1] = {0xff}, retry_enable =0xB6, retry_disable = 0xD6;
+ unsigned int rdmz_mark = 0;
+
+ nand->cur_page = page;
+ if ((pNFCRegs->NFCR9&ECC_MOD_SEL) >= 5)
+ dma_unit = 1024;
+
+
+ if(NULL != cur_chip) {
+ total_times = cur_chip->total_try_times + 1;
+ if (nand->mfr == NAND_SANDISK) {//sandisk
+ pageInBlk = page%nand->dwPageCount;
+ if (((pageInBlk%2) == 1 || pageInBlk == 0) && pageInBlk != (nand->dwPageCount - 1))
+ total_try_times = cur_chip->total_try_times&0xFF;//Lower page
+ else
+ total_try_times = (cur_chip->total_try_times>>8)&0xFF;//Upper page
+ } else
+ total_try_times = cur_chip->total_try_times&0xFF;
+ }
+
+ for(i = 0; i < total_times; i++) {
+ nand->unc_banks = 0;
+ row = page;
+ col = nand->col_offset;
+ if (nfc_dma_cfg(maddr, len + dma_unit, 0))
+ return -ERR_DMA_CFG;
+
+ /* addr */
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, row);
+ WRITE_NAND_COMMAND(NAND_READ0); /* set command cycle 1 */
+
+ /*print_nfc_register();*/
+ cmd2[1] = NAND_READ_CONFIRM;
+ pNFCRegs->NFCRb &= (B2R|ERR_CORRECT|BCH_ERR); /* write to clear */
+ pNFCRegs->NFCR1 = NAND2NFC|MUL_CMDS|((nand->row+nand->col+2)<<1)|NFC_TRIGGER|OLD_CMD;
+
+ if (pNFCRegs->NFCR9 & DIS_BCH_ECC) {
+ if (NFC_WAIT_READY())
+ return -ERR_NFC_READY;
+ } else {
+ row = ((nand->oobblock_valid + dma_unit)/dma_unit);
+ for (col = 0; col < row; col++) {
+ rc = NFC_CHECK_ECC();
+ if (rc < 0)
+ return -ERR_NFC_READY;
+ else {
+ if (rc) {
+ /*if (nand->bbt_sw_rdmz)
+ err = nfc_BCH_ecc_check_sw(nand, maddr);
+ else*/
+ err = nfc_BCH_ecc_check(nand, maddr);
+ if(err) {
+ // printf("The %d bank need retry.\n", col);
+ retry = 1;
+ }
+ }
+ }
+ }
+ if (err == 1) {
+ //printf("all ff detect!\n");
+ retry = 0;
+ }
+ }
+ rc = nand_pdma_handler();
+ nand_free_pdma();
+
+ if (NAND_WAIT_READY())
+ return -ERR_NAND_IDLE;
+
+ if(cur_chip != NULL) {
+// printf("p4 retry = %d\n", retry);
+ if(retry == 1) {
+ printf("Ecc Err %d_th, page=%x cur_try:%d fail.\n", i, page, cur_chip->cur_try_times);
+ if(cur_chip->read_table == 1) {
+ break;
+ }
+ if(i == (total_try_times)) {
+ if(nand->mfr == NAND_TOSHIBA) {
+ write_bytes_param(1, 0, 0, cmd, NULL, NULL);
+ cur_chip->cur_try_times = 0;
+ } else if (nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) {
+ /* send default cmd after read retry finish(fail) for samsung */
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, DEFAULT_VALUE);
+ cur_chip->cur_try_times = 0;
+ } else if (nand->mfr == NAND_SANDISK) {
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ write_bytes_param(1, 0, 0, &retry_disable, NULL, NULL);
+ } else if (nand->mfr == NAND_HYNIX) {
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ cur_chip->cur_try_times = -1;
+ }
+ printf("retry %d FAIL.\n", cur_chip->cur_try_times);
+ retry = -1;
+ break;
+ }
+ if(nand->mfr == NAND_HYNIX) {//hynix
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, ECC_ERROR_VALUE);
+ retry_pass = 1;
+ } else if(nand->mfr == NAND_TOSHIBA) {//toshiba
+ if(cur_chip->cur_try_times == 0)
+ toshiba_pre_condition();
+ cur_chip->set_parameter(nand, 0, 0);
+ retry_pass = 1;
+ } else if (nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) {//samsung and micron
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, ECC_ERROR_VALUE);
+ retry_pass = 1;
+ } else if (nand->mfr == NAND_SANDISK) {//sandisk
+ //printf("set retry mode cur_try_times=%d\n", cur_chip->cur_try_times);
+ cur_chip->set_parameter(nand, total_try_times, ECC_ERROR_VALUE);
+ if (i == 0)
+ write_bytes_param(1, 0, 0, &retry_enable, NULL, NULL);
+ retry_pass = 1;
+ }
+ retry = 0;
+ continue;
+ } else {
+ if (cur_chip->read_table == 1) {
+ break;
+ }
+
+ if(retry_pass == 1) {
+ printf("retry %d PASS.\n", cur_chip->cur_try_times);
+ }
+
+ if ((nand->mfr == NAND_TOSHIBA) && (retry_pass == 1)) {
+ write_bytes_param(1, 0, 0, cmd, NULL, NULL);
+ cur_chip->cur_try_times = 0;
+ retry = 0;
+ } else if ((nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) && (retry_pass == 1)) {
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, DEFAULT_VALUE);
+ cur_chip->cur_try_times = 0;
+ retry = 0;
+ } else if (nand->mfr == NAND_SANDISK && (retry_pass == 1)) {
+ write_bytes_param(1, 0, 0, &retry_disable, NULL, NULL);
+ /* set retry default value need before page program */
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ /* should we reset cur_try_times to zero? */
+ cur_chip->cur_try_times = -1;
+ retry = 0;
+ } else if (nand->mfr == NAND_HYNIX && (retry_pass == 1)) {
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ cur_chip->cur_try_times = -1;
+ retry = 0;
+ }
+
+ break;
+ }
+ }
+ }
+
+ wmt_nand_read_oob_60bit(nand,maddr);
+
+ /* Fix : add support 60bit */
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC) && nand->bbt_sw_rdmz) {
+ //printf("sw r page=0x%x ", page);
+ rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)&pNFCRegs->FIFO[20], 1, page, (nand->oobblock_valid+20)/4);
+ //printf("rdmz_mark=0x%x pNFCRegs->FIFO[20]=0x%x.page=0x%x...\n", rdmz_mark, *(uint32_t *)&pNFCRegs->FIFO[20], page);
+ if (nand->dwRdmz == 1) {
+ if (rdmz_mark == wmt_rdmz || *(unsigned int *)&pNFCRegs->FIFO[20] == wmt_rdmz) {
+ //printf("1with rdmz mark fifo5=0x%x\n", *(unsigned int *)&pNFCRegs->FIFO[20]);
+ rdmzier2((uint8_t *)maddr, nand->oobblock_valid/4, page);
+ }
+ if (rdmz_mark == wmt_rdmz) {
+ rdmzier_oob((uint8_t *)pNFCRegs->FIFO, (uint8_t *)pNFCRegs->FIFO, 6, page, nand->oobblock_valid/4);
+ //printf("2with rdmz mark fifo5=0x%x\n", *(unsigned int *)&pNFCRegs->FIFO[20]);
+ }
+ }
+ }
+
+
+
+ if(retry)
+ return -1;
+ return 0;
+}
+
+
+int nfc_BCH_read_page(
+struct nand_chip *nand,
+unsigned int page,
+unsigned int maddr,
+unsigned int len)
+{
+ unsigned int row = 0, col = 0, dma_unit = 512, pageInBlk = 0;
+ int rc = -1, err = 0, i;
+ int total_times = 1;
+ int retry_pass = 0;
+ int retry = 0, total_try_times = 0;
+ unsigned char *cmd2 = (unsigned char *)&pNFCRegs->NFCR5;
+ unsigned char cmd[1] = {0xff}, retry_enable =0xB6, retry_disable = 0xD6;
+ //#ifdef WMT_SW_RDMZ
+ unsigned int rdmz_mark = 0;
+ //#endif
+ nand->cur_page = page;
+ if ((pNFCRegs->NFCR9&ECC_MOD_SEL) >= 5)
+ dma_unit = 1024;
+
+
+ if(NULL != cur_chip) {
+ total_times = cur_chip->total_try_times + 1;
+ if (nand->mfr == NAND_SANDISK) {//sandisk
+ pageInBlk = page%nand->dwPageCount;
+ if (((pageInBlk%2) == 1 || pageInBlk == 0) && pageInBlk != (nand->dwPageCount - 1))
+ total_try_times = cur_chip->total_try_times&0xFF;//Lower page
+ else
+ total_try_times = (cur_chip->total_try_times>>8)&0xFF;//Upper page
+ } else
+ total_try_times = cur_chip->total_try_times&0xFF;
+ }
+//#ifdef WMT_HW_RDMZ
+ //pNFCRegs->NFCRf &= ~RDMZ;
+ //if (nand->dwRdmz == 1 && !(pNFCRegs->NFCR9 & DIS_BCH_ECC) && !nand->bbt_sw_rdmz)
+ //pNFCRegs->NFCRf = RDMZ/*|(page%RDMZ)*/;
+//#endif
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC) && !nand->bbt_sw_rdmz){
+ //printf("HW RDMZ ON ( nfc_BCH_read_page )\n");
+ enable_hw_rdmz(nand);
+ }
+
+ for(i = 0; i < total_times; i++) {
+ nand->unc_banks = 0;
+ row = page;
+ col = nand->col_offset;
+ if (nfc_dma_cfg(maddr, len, 0))
+ return -ERR_DMA_CFG;
+
+ /* addr */
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, row);
+ WRITE_NAND_COMMAND(NAND_READ0); /* set command cycle 1 */
+
+ /*print_nfc_register();*/
+ cmd2[1] = NAND_READ_CONFIRM;
+ pNFCRegs->NFCRb &= (B2R|ERR_CORRECT|BCH_ERR); /* write to clear */
+ pNFCRegs->NFCR1 = NAND2NFC|MUL_CMDS|((nand->row+nand->col+2)<<1)|NFC_TRIGGER|OLD_CMD;
+
+ if (pNFCRegs->NFCR9 & DIS_BCH_ECC) {
+ if (NFC_WAIT_READY())
+ return -ERR_NFC_READY;
+ } else {
+ row = (nand->oobblock/dma_unit);
+ for (col = 0; col < row; col++) {
+ rc = NFC_CHECK_ECC();
+ if (rc < 0)
+ return -ERR_NFC_READY;
+ else {
+ if (rc) {
+ /*if (nand->bbt_sw_rdmz)
+ err = nfc_BCH_ecc_check_sw(nand, maddr);
+ else*/
+ err = nfc_BCH_ecc_check(nand, maddr);
+ if(err) {
+ // printf("The %d bank need retry.\n", col);
+ retry = 1;
+ }
+ }
+ }
+ }
+ //If all 0xFF , don't do retry.
+ if (err == 1) {
+ //printf("all ff detect!\n");
+ retry = 0;
+ }
+ }
+ rc = nand_pdma_handler();
+ nand_free_pdma();
+
+ if (NAND_WAIT_READY())
+ return -ERR_NAND_IDLE;
+
+ if(cur_chip != NULL) {
+// printf("p4 retry = %d\n", retry);
+ if(retry == 1) {
+ printf("Ecc Err %d_th, page=%x cur_try:%d fail.\n", i, page, cur_chip->cur_try_times);
+ if(cur_chip->read_table == 1) {
+ break;
+ }
+ if(i == (total_try_times)) {
+ if(nand->mfr == NAND_TOSHIBA) {
+ write_bytes_param(1, 0, 0, cmd, NULL, NULL);
+ cur_chip->cur_try_times = 0;
+ } else if (nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) {
+ /* send default cmd after read retry finish(fail) for samsung */
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, DEFAULT_VALUE);
+ cur_chip->cur_try_times = 0;
+ } else if (nand->mfr == NAND_SANDISK) {
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ write_bytes_param(1, 0, 0, &retry_disable, NULL, NULL);
+ } else if (nand->mfr == NAND_HYNIX) {
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ cur_chip->cur_try_times = -1;
+ }
+
+ printf("retry %d FAIL.\n", cur_chip->cur_try_times);
+ retry = -1;
+ break;
+ }
+ if(nand->mfr == NAND_HYNIX) {//hynix
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, ECC_ERROR_VALUE);
+ retry_pass = 1;
+ } else if(nand->mfr == NAND_TOSHIBA) {//toshiba
+ if(cur_chip->cur_try_times == 0)
+ toshiba_pre_condition();
+ cur_chip->set_parameter(nand, 0, 0);
+ retry_pass = 1;
+ } else if (nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) {//samsung and micron
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, ECC_ERROR_VALUE);
+ retry_pass = 1;
+ } else if (nand->mfr == NAND_SANDISK) {//sandisk
+ //printf("set retry mode cur_try_times=%d\n", cur_chip->cur_try_times);
+ cur_chip->set_parameter(nand, total_try_times, ECC_ERROR_VALUE);
+ if (i == 0)
+ write_bytes_param(1, 0, 0, &retry_enable, NULL, NULL);
+ retry_pass = 1;
+ }
+ retry = 0;
+ continue;
+ } else {
+ if (cur_chip->read_table == 1) {
+ break;
+ }
+
+ if(retry_pass == 1) {
+ printf("retry %d PASS.\n", cur_chip->cur_try_times);
+ }
+
+ if ((nand->mfr == NAND_TOSHIBA) && (retry_pass == 1)) {
+ write_bytes_param(1, 0, 0, cmd, NULL, NULL);
+ cur_chip->cur_try_times = 0;
+ retry = 0;
+ } else if ((nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) && (retry_pass == 1)) {
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, DEFAULT_VALUE);
+ cur_chip->cur_try_times = 0;
+ retry = 0;
+ } else if (nand->mfr == NAND_SANDISK && (retry_pass == 1)) {
+ write_bytes_param(1, 0, 0, &retry_disable, NULL, NULL);
+ /* set retry default value need before page program */
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ /* should we reset cur_try_times to zero? */
+ cur_chip->cur_try_times = -1;
+ retry = 0;
+ } else if (nand->mfr == NAND_HYNIX && (retry_pass == 1)) {
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ cur_chip->cur_try_times = -1;
+ retry = 0;
+ }
+
+ break;
+ }
+ }
+ }
+ //#ifdef WMT_SW_RDMZ
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC) && nand->bbt_sw_rdmz) {
+ //printf("sw r page=0x%x ", page);
+ rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)&pNFCRegs->FIFO[20], 1, page, (nand->oobblock+20)/4);
+ //printf("rdmz_mark=0x%x pNFCRegs->FIFO[20]=0x%x.page=0x%x...\n", rdmz_mark, *(uint32_t *)&pNFCRegs->FIFO[20], page);
+ if (nand->dwRdmz == 1) {
+ if (rdmz_mark == wmt_rdmz || *(unsigned int *)&pNFCRegs->FIFO[20] == wmt_rdmz) {
+ //printf("1with rdmz mark fifo5=0x%x\n", *(unsigned int *)&pNFCRegs->FIFO[20]);
+ rdmzier2((uint8_t *)maddr, nand->oobblock/4, page);
+ }
+ if (rdmz_mark == wmt_rdmz) {
+ rdmzier_oob((uint8_t *)pNFCRegs->FIFO, (uint8_t *)pNFCRegs->FIFO, 6, page, nand->oobblock/4);
+ //printf("2with rdmz mark fifo5=0x%x\n", *(unsigned int *)&pNFCRegs->FIFO[20]);
+ }
+ } /*else
+ printf(" dwRdmz=0x%x\n", nand->dwRdmz);*/
+ } /*else
+ printf("sw r nordmz page=0x%x\n", page);*/
+ //#endif
+ /*#ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz == 1)
+ pNFCRegs->NFCRf &= ~RDMZ;
+ #endif*/
+
+ if(retry)
+ return -1;
+ return 0;
+}
+
+int nfc_BCH_read_page2(
+struct nand_chip *nand,
+unsigned int page,
+unsigned int maddr,
+unsigned int len,
+int pipeline,
+int lastpage)
+{
+ unsigned int row = 0, col = 0, dma_unit = 512, pageInBlk = 0;
+ int rc = -1, err = 0, i;
+ int total_times = 1;
+ int retry_pass = 0;
+ int retry = 0, total_try_times = 0;
+ unsigned char cmd[1] = {0xff}, retry_enable =0xB6, retry_disable = 0xD6;
+ #ifdef WMT_SW_RDMZ
+ unsigned int rdmz_mark = 0;
+ #endif
+
+ nand->cur_page = page;
+ if ((pNFCRegs->NFCR9&ECC_MOD_SEL) >= 5)
+ dma_unit = 1024;
+
+
+ if(NULL != cur_chip) {
+ total_times = cur_chip->total_try_times + 1;
+ if (nand->mfr == NAND_SANDISK) {//sandisk
+ pageInBlk = page%nand->dwPageCount;
+ if (((pageInBlk%2) == 1 || pageInBlk == 0) && pageInBlk != (nand->dwPageCount - 1))
+ total_try_times = cur_chip->total_try_times&0xFF;//Lower page
+ else
+ total_try_times = (cur_chip->total_try_times>>8)&0xFF;//Upper page
+ } else
+ total_try_times = cur_chip->total_try_times&0xFF;
+ }
+//#ifdef WMT_HW_RDMZ
+ //pNFCRegs->NFCRf &= ~RDMZ;
+ //if (nand->dwRdmz == 1 && !(pNFCRegs->NFCR9 & DIS_BCH_ECC))
+ //pNFCRegs->NFCRf = RDMZ/*|(page%RDMZ)*/;
+//#endif
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ //printf("HW RDMZ ON ( nfc_BCH_read_page2 )\n");
+ enable_hw_rdmz(nand);
+ }
+
+
+ for(i = 0; i < total_times; i++) {
+ row = page;
+ col = nand->col_offset;
+ if (nfc_dma_cfg(maddr, len, 0))
+ return -ERR_DMA_CFG;
+
+ /* addr */
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, row);
+ WRITE_NAND_COMMAND(NAND_READ0); /* set command cycle 1 */
+
+ /*print_nfc_register();*/
+
+ pNFCRegs->NFCRb &= (B2R|ERR_CORRECT|BCH_ERR); /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|((nand->row+nand->col+1)<<1)|NFC_TRIGGER|OLD_CMD;
+ if (nand->oobblock > 512) {
+ if (NFC_WAIT_CMD_READY())
+ return -ERR_NFC_CMD;
+ WRITE_NAND_COMMAND(NAND_READ_CONFIRM);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = NAND2NFC|1<<1|NFC_TRIGGER|OLD_CMD;
+ }
+
+
+
+ if (pNFCRegs->NFCR9 & DIS_BCH_ECC) {
+ if (NFC_WAIT_READY())
+ return -ERR_NFC_READY;
+ } else {
+
+ if (pipeline != 0){//do the rdmzier() for the previous page except the first page in a block! pipeline!
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ if (nand->dwRdmz == 1) {
+ #ifdef WMT_SW_RDMZ
+ rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)&pNFCRegs->FIFO[20], 1, page-1, (nand->oobblock+20)/4);
+ if (rdmz_mark == wmt_rdmz || *(unsigned int *)&pNFCRegs->FIFO[20] == wmt_rdmz) {
+ rdmzier2(rdmz_buf_rd, nand->oobblock/4, page-1);
+ }
+ #endif
+ }
+ }
+ }
+
+ row = (nand->oobblock/dma_unit)+1;
+ for (col = 0; col < row; col++) {
+ rc = NFC_CHECK_ECC();
+ if (rc < 0)
+ return -ERR_NFC_READY;
+ else {
+ if (rc) {
+ err = nfc_BCH_ecc_check(nand, maddr);
+ if(err) {
+ // printf("The %d bank need retry.\n", col);
+ retry = 1;
+ }
+ }
+ }
+ }
+ }
+ rc = nand_pdma_handler();
+ nand_free_pdma();
+
+ if (NAND_WAIT_READY())
+ return -ERR_NAND_IDLE;
+
+ if(cur_chip != NULL) {
+// printf("p4 retry = %d\n", retry);
+ if(retry == 1) {
+ printf("Ecc Err %d_th, on page %d cur_try_times:%d fail.\n", i, page, cur_chip->cur_try_times);
+ if(cur_chip->read_table == 1) {
+ break;
+ }
+ if(i == (total_try_times)) {
+ if(nand->mfr == NAND_TOSHIBA) {
+ write_bytes_param(1, 0, 0, cmd, NULL, NULL);
+ cur_chip->cur_try_times = 0;
+ } else if (nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) {
+ /* send default cmd after read retry finish(fail) for samsung */
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, DEFAULT_VALUE);
+ cur_chip->cur_try_times = 0;
+ } else if (nand->mfr == NAND_SANDISK) {
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ write_bytes_param(1, 0, 0, &retry_disable, NULL, NULL);
+ }
+ printf("retry %d FAIL.\n", cur_chip->cur_try_times);
+ retry = -1;
+ break;
+ }
+ if(nand->mfr == NAND_HYNIX) {//hynix
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, ECC_ERROR_VALUE);
+ retry_pass = 1;
+ } else if(nand->mfr == NAND_TOSHIBA) {//toshiba
+ if(cur_chip->cur_try_times == 0)
+ toshiba_pre_condition();
+ cur_chip->set_parameter(nand, 0, 0);
+ retry_pass = 1;
+ } else if (nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) {//samsung and micron
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, ECC_ERROR_VALUE);
+ retry_pass = 1;
+ } else if (nand->mfr == NAND_SANDISK) {//sandisk
+ //printf("set retry mode cur_try_times=%d\n", cur_chip->cur_try_times);
+ cur_chip->set_parameter(nand, total_try_times, ECC_ERROR_VALUE);
+ if (i == 0)
+ write_bytes_param(1, 0, 0, &retry_enable, NULL, NULL);
+ retry_pass = 1;
+ }
+ retry = 0;
+ continue;
+ } else {
+ if (cur_chip->read_table == 1) {
+ break;
+ }
+
+ if ((nand->mfr == NAND_TOSHIBA) && (retry_pass == 1)) {
+ write_bytes_param(1, 0, 0, cmd, NULL, NULL);
+ cur_chip->cur_try_times = 0;
+ retry = 0;
+ } else if ((nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) && (retry_pass == 1)) {
+ cur_chip->set_parameter(nand, READ_RETRY_MODE, DEFAULT_VALUE);
+ cur_chip->cur_try_times = 0;
+ retry = 0;
+ } else if (nand->mfr == NAND_SANDISK && (retry_pass == 1)) {
+ write_bytes_param(1, 0, 0, &retry_disable, NULL, NULL);
+ /* set retry default value need before page program */
+ cur_chip->set_parameter(nand, total_try_times, DEFAULT_VALUE);
+ /* should we reset cur_try_times to zero? */
+ cur_chip->cur_try_times = -1;
+ retry = 0;
+ }
+ if(retry_pass == 1) {
+ printf("retry %d PASS.\n", cur_chip->cur_try_times);
+ }
+ break;
+ }
+ }
+ }
+ #ifdef WMT_SW_RDMZ
+
+ if (lastpage){//need to do rdmzier() for the last page in a block
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)&pNFCRegs->FIFO[20], 1, page, (nand->oobblock+20)/4);
+ if (nand->dwRdmz == 1) {
+ if (rdmz_mark == wmt_rdmz || *(unsigned int *)&pNFCRegs->FIFO[20] == wmt_rdmz) {
+ rdmzier2((uint8_t *)maddr, nand->oobblock/4, page);
+ }
+ }
+ }
+ }
+ else {
+ //save the final read data address and do the rdmzier() during next page ,not now
+ rdmz_buf_rd = (unsigned char *)maddr;
+ }
+
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ //printf("hw r page=0x%x ", page);
+ rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)&pNFCRegs->FIFO[20], 1, page, (nand->oobblock+20)/4);
+ if (nand->dwRdmz == 1) {
+ if (rdmz_mark == wmt_rdmz) {
+ rdmzier_oob((uint8_t *)pNFCRegs->FIFO, (uint8_t *)pNFCRegs->FIFO, 6, page, nand->oobblock/4);
+ }
+ }
+ }
+
+ #endif
+ /*#ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz == 1)
+ pNFCRegs->NFCRf &= ~RDMZ;
+ #endif*/
+
+ if(retry)
+ return -1;
+ return 0;
+}
+
+static int wmt_multi_page_start_micron(struct nand_chip *nand, int page)
+{
+ int i, status = 0;
+ unsigned char cmd[3];
+ uint8_t addr[5] = {0, 0, 0, 0, 0};
+ cmd[0] = 0x00;cmd[1] = 0x32;cmd[2] = 0x30;
+
+ for (i = 0; i < 3; i++) {
+ addr[2+i] = 0xFF&(page>>(8*i));
+ }
+
+ status = write_bytes_param(1, 5, 0, cmd, addr, NULL);
+ if (status)
+ printf("micron multi read cmd(00) + addr1 fail\n");
+ status = write_bytes_param(1, 0, 0, &cmd[1], NULL, NULL);
+ if (status)
+ printf("micron multi read cmd(32) + addr fail\n");
+
+ if (NAND_WAIT_READY()) {
+ printf("multi read wait B2R fail\n");
+ return -ERR_NAND_IDLE;
+ }
+
+ for (i = 0; i < 3; i++) {
+ addr[2+i] = 0xFF&((page + nand->dwPageCount)>>(8*i));
+ }
+
+ status = write_bytes_param(1, 5, 0, cmd, addr, NULL);
+ if (status)
+ printf("micron multi read cmd(00) + addr2 fail\n");
+ status = write_bytes_param(1, 0, 0, &cmd[2], NULL, NULL);
+ if (status)
+ printf("micron multi read cmd(30) + addr fail\n");
+
+ if (NAND_WAIT_READY()) {
+ printf("micron multi read wait B2R fail \n");
+ return -ERR_NAND_IDLE;
+ }
+ pNFCRegs->NFCRb = (B2R|ERR_CORRECT|BCH_ERR); /* write to clear */
+
+ return status;
+}
+
+
+static int wmt_multi_page_start(struct nand_chip *nand, int page)
+{
+ int status = 0;
+ unsigned char cmd[3];
+ unsigned char *addr = (uchar *)&page;
+ cmd[0] = 0x60; cmd[1] = 0x60; cmd[2] = 0x30;
+
+ status = write_bytes_param(1, 3, 0, (uchar *)&cmd[0], addr, NULL);
+ if (status)
+ printf("wmt_multi_page_start step1 fail\n");
+ page = page + nand->dwPageCount;
+ status = write_bytes_param(1, 3, 0, (uchar *)&cmd[1], addr, NULL);
+ if (status)
+ printf("wmt_multi_page_start step2 fail\n");
+ status = write_bytes_param(1, 0, 0, (uchar *)&cmd[2], NULL, NULL);
+ if (status)
+ printf("wmt_multi_page_start step3 fail\n");
+
+ if (NAND_WAIT_READY()) {
+ printf("multi read wait B2R fail\n");
+ return -ERR_NAND_IDLE;
+ }
+ pNFCRegs->NFCRb = (B2R|ERR_CORRECT|BCH_ERR); /* write to clear */
+
+ return status;
+}
+
+static int wmt_multi_page_read_60bit(struct nand_chip *nand, unsigned int page,
+unsigned int maddr, unsigned int len, int pipeline, int lastpage)
+{
+ int status = -1, retry = 0, row, col, i, rc, err=0;
+ unsigned char cmd[3];// = {0x00, 0x05, 0xE0};
+ unsigned char addr[5] = {0, 0, 0, 0, 0};
+ unsigned char *FIFO = (unsigned char *)&pNFCRegs->FIFO[48];
+ unsigned int dma_unit = ((pNFCRegs->NFCR9&ECC_MOD_SEL) < 5)?512:1024;
+ #ifdef WMT_SW_RDMZ
+ unsigned int rdmz_mark = 0;
+ #endif
+
+ cmd[0] = 0;cmd[1] = 5;cmd[2] = 0xE0; // micron : 0x06 0xE0
+ for (i = 0; i < 3; i++)
+ addr[i+2] = 0xFF&(page >> (i*8));
+
+ status = write_bytes_param(1, 5, 0, (uchar *)&cmd[0], addr, NULL);
+ if (status) {
+ printf("wmt_multi_page_read_60bit step1 fail\n");
+ }
+
+ /*pNFCRegs->NFCRd |= HIGH64FIFO;//Henry test
+ print_nfc_register();//Henry test
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;//Henry test*/
+
+ status = write_bytes_param(1, 2, 0, (uchar *)&cmd[1], addr, NULL);
+ if (status)
+ printf("wmt_multi_page_read_60bit step2 fail\n");
+
+ /*status = write_bytes_param(1, 0, 0, (uchar *)&cmd[2], NULL, NULL);
+ if (status)
+ printf("wmt_multi_page_read step3 fail\n");*/
+
+ if (nfc_dma_cfg(maddr, len + dma_unit, 0))
+ return -ERR_DMA_CFG;
+
+ pNFCRegs->NFCRb = (B2R|ERR_CORRECT|BCH_ERR); /* write to clear */
+ if (NFC_WAIT_CMD_READY())
+ return -ERR_NFC_CMD;
+ //WRITE_NAND_COMMAND(0xE0);
+ //pNFCRegs->NFCR1 = TWHR|NAND2NFC|1<<1|NFC_TRIGGER|OLD_CMD;
+ pNFCRegs->NFCRd |= HIGH64FIFO;
+ FIFO[0] = 0xE0;
+ FIFO[3] = 0xFF&page;
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ pNFCRegs->NFCRc = 0x80001;
+ /*print_nfc_register();*/
+ pNFCRegs->NFCR1 = TWHR|NAND2NFC|1<<1|NFC_TRIGGER;
+
+ if (pNFCRegs->NFCR9 & DIS_BCH_ECC) {
+ if (NFC_WAIT_READY())
+ return -ERR_NFC_READY;
+ } else {
+ //do the rdmzier() for the previous page except the first page in a block! pipeline!
+ /*if (pipeline != 0) {
+ if (nand->dwRdmz == 1) {
+ rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)&pNFCRegs->FIFO[20], 1, page-1, (nand->oobblock+20)/4);
+ if (rdmz_mark == wmt_rdmz || *(unsigned int *)&pNFCRegs->FIFO[20] == wmt_rdmz) {
+ rdmzier2(rdmz_buf_rd, nand->oobblock/4, page-1);
+ }
+ }
+ }*/
+
+ row = (nand->oobblock_valid/dma_unit + 1);
+ for (col = 0; col < row; col++) {
+ rc = NFC_CHECK_ECC();
+ if (rc < 0)
+ return -ERR_NFC_READY;
+ else {
+ if (rc) {
+ err = nfc_BCH_ecc_check(nand, maddr);
+ if(err) {
+ //printf("The %d bank need retry.\n", col);
+ retry = 1;
+ }
+ }
+ }
+ }
+ if (err == 1) {
+ //printf("all ff detect!\n");
+ retry = 0;
+ }
+ }
+ /*print_nfc_register();*/
+ rc = nand_pdma_handler();
+ nand_free_pdma();
+
+ wmt_nand_read_oob_60bit(nand,maddr);
+
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC) && !retry) {
+ #ifdef WMT_SW_RDMZ
+ rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)&pNFCRegs->FIFO[20], 1, page, (nand->oobblock+20)/4);
+ //printf("rdmz_mark=0x%x pNFCRegs->FIFO[20]=0x%x.page=0x%x...\n", rdmz_mark, *(uint32_t *)&pNFCRegs->FIFO[20], page);
+ if (nand->dwRdmz == 1) {
+ if (rdmz_mark == wmt_rdmz || *(unsigned int *)&pNFCRegs->FIFO[20] == wmt_rdmz) {
+ rdmzier2((uint8_t *)maddr, nand->oobblock/4, page);
+ rdmzier_oob((uint8_t *)pNFCRegs->FIFO, (uint8_t *)pNFCRegs->FIFO, 6, page, nand->oobblock/4);
+ }
+ }
+ #endif
+ }
+
+ return retry;
+}
+
+static int wmt_multi_page_read(struct nand_chip *nand, unsigned int page,
+unsigned int maddr, unsigned int len, int pipeline, int lastpage)
+{
+ int status = -1, retry = 0, row, col, i, rc, err=0;
+ unsigned char cmd[3];// = {0x00, 0x05, 0xE0};
+ unsigned char addr[5] = {0, 0, 0, 0, 0};
+ unsigned char *FIFO = (unsigned char *)&pNFCRegs->FIFO[48];
+ unsigned int dma_unit = ((pNFCRegs->NFCR9&ECC_MOD_SEL) < 5)?512:1024;
+ #ifdef WMT_SW_RDMZ
+ unsigned int rdmz_mark = 0;
+ #endif
+
+ cmd[0] = 0;cmd[1] = 5;cmd[2] = 0xE0;
+ for (i = 0; i < 3; i++)
+ addr[i+2] = 0xFF&(page >> (i*8));
+
+ status = write_bytes_param(1, 5, 0, (uchar *)&cmd[0], addr, NULL);
+ if (status)
+ printf("wmt_multi_page_read step1 fail\n");
+
+
+ status = write_bytes_param(1, 2, 0, (uchar *)&cmd[1], addr, NULL);
+ if (status)
+ printf("wmt_multi_page_read step2 fail\n");
+ /*status = write_bytes_param(1, 0, 0, (uchar *)&cmd[2], NULL, NULL);
+ if (status)
+ printf("wmt_multi_page_read step3 fail\n");*/
+
+ if (nfc_dma_cfg(maddr, len, 0))
+ return -ERR_DMA_CFG;
+
+ pNFCRegs->NFCRb = (B2R|ERR_CORRECT|BCH_ERR); /* write to clear */
+ if (NFC_WAIT_CMD_READY())
+ return -ERR_NFC_CMD;
+ //WRITE_NAND_COMMAND(0xE0);
+ //pNFCRegs->NFCR1 = TWHR|NAND2NFC|1<<1|NFC_TRIGGER|OLD_CMD;
+ pNFCRegs->NFCRd |= HIGH64FIFO;
+ FIFO[0] = 0xE0;
+ FIFO[3] = 0xFF&page;
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ pNFCRegs->NFCRc = 0x80001;
+ /*print_nfc_register();*/
+ pNFCRegs->NFCR1 = TWHR|NAND2NFC|1<<1|NFC_TRIGGER;
+
+ if (pNFCRegs->NFCR9 & DIS_BCH_ECC) {
+ if (NFC_WAIT_READY())
+ return -ERR_NFC_READY;
+ } else {
+ //do the rdmzier() for the previous page except the first page in a block! pipeline!
+ /*if (pipeline != 0) {
+ if (nand->dwRdmz == 1) {
+ rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)&pNFCRegs->FIFO[20], 1, page-1, (nand->oobblock+20)/4);
+ if (rdmz_mark == wmt_rdmz || *(unsigned int *)&pNFCRegs->FIFO[20] == wmt_rdmz) {
+ rdmzier2(rdmz_buf_rd, nand->oobblock/4, page-1);
+ }
+ }
+ }*/
+
+ row = (nand->oobblock/dma_unit);
+ for (col = 0; col < row; col++) {
+ rc = NFC_CHECK_ECC();
+ if (rc < 0)
+ return -ERR_NFC_READY;
+ else {
+ if (rc) {
+ err = nfc_BCH_ecc_check(nand, maddr);
+ if(err) {
+ //printf("The %d bank need retry.\n", col);
+ retry = 1;
+ }
+ }
+ }
+ }
+ if (err == 1) {
+ //printf("all ff detect!\n");
+ retry = 0;
+ }
+ }
+ /*print_nfc_register();*/
+ rc = nand_pdma_handler();
+ nand_free_pdma();
+
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC) && !retry) {
+ #ifdef WMT_SW_RDMZ
+ rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)&pNFCRegs->FIFO[20], 1, page, (nand->oobblock+20)/4);
+ //printf("rdmz_mark=0x%x pNFCRegs->FIFO[20]=0x%x.page=0x%x...\n", rdmz_mark, *(uint32_t *)&pNFCRegs->FIFO[20], page);
+ if (nand->dwRdmz == 1) {
+ if (rdmz_mark == wmt_rdmz || *(unsigned int *)&pNFCRegs->FIFO[20] == wmt_rdmz) {
+ rdmzier2((uint8_t *)maddr, nand->oobblock/4, page);
+ rdmzier_oob((uint8_t *)pNFCRegs->FIFO, (uint8_t *)pNFCRegs->FIFO, 6, page, nand->oobblock/4);
+ }
+ }
+ #endif
+ }
+
+ return retry;
+}
+
+static int wmt_multi_plane_read(struct nand_chip *nand, unsigned int page,
+unsigned int maddr, unsigned int len, int pipeline, int lastpage)
+{
+ int rc0, rc1;
+ int page0 = page, page1 = page + nand->dwPageCount;
+ //printf("p0=%x p1=%x ",page0, page1);
+
+ if ((0xFF&(nand->id>>24)) == NAND_MICRON)
+ wmt_multi_page_start_micron(nand, page);
+ else
+ wmt_multi_page_start(nand, page);
+
+ nand->cur_page = page0;
+
+ if(nand->dwECCBitNum ==60)
+ rc0 = wmt_multi_page_read_60bit(nand, page0, maddr, len, pipeline, lastpage);
+ else
+ rc0 = wmt_multi_page_read(nand, page0, maddr, len, pipeline, lastpage);
+
+ nand->cur_page = page1;
+
+ if(nand->dwECCBitNum ==60)
+ rc1 = wmt_multi_page_read_60bit(nand, page1, maddr+len, len, pipeline, lastpage);
+ else
+ rc1 = wmt_multi_page_read(nand, page1, maddr+len, len, pipeline, lastpage);
+
+ if (rc0) {
+ printf("m-re p0_uncor rc0=%d\n",rc0);
+ nand->cur_page = page0;
+ if (nand->dwECCBitNum ==60) {
+ //printf("nfc_BCH_read_page_60bit! page=%d\n",page0);
+ rc0 = nfc_BCH_read_page_60bit(nand, page0, maddr, len);
+ } else {
+ //printf("read page=0x%x\n", page0);
+ rc0 = nand->nfc_read_page(nand, page0, maddr, len);//@original
+ }
+ }
+ if (rc0) {
+ printf("retry page0=%d fail\n", page0);
+ return rc0;
+ }
+ if (rc1) {
+ printf("m-re p1_uncor rc1=%d\n",rc1);
+ nand->cur_page = page1;
+ if (nand->dwECCBitNum ==60) {
+ //printf("nfc_BCH_read_page_60bit! page=%d\n",page1);
+ rc1 = nfc_BCH_read_page_60bit(nand, page1, maddr+len, len);
+ } else {
+ //printf("read page=0x%x\n", page1);
+ rc1 = nand->nfc_read_page(nand, page1, maddr+len, len);//@original
+ }
+ }
+ if (rc1) {
+ printf("retry page1=%d fail\n", page1);
+ return rc1;
+ }
+ return 0;
+}
+
+
+int nand_read_status(struct nand_chip *nand, unsigned char cmd)
+{
+ int cfg = 0, status = -1;
+ #ifdef WMT_HW_RDMZ
+ unsigned int rdmz;
+ rdmz = pNFCRegs->NFCRf&RDMZ;
+
+ if (nand->dwRdmz && rdmz) {
+ //printf("HW RDMZ ON ( nand_read_status )\n");
+ //pNFCRegs->NFCRf = RDMZ;
+ enable_hw_rdmz(nand);
+ pNFCRegs->NFCR4 = 0;
+ }
+ #endif
+
+ pNFCRegs->NFCR2 = cmd;
+ cfg = DPAHSE_DISABLE|(1<<1);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = TWHR|cfg|NFC_TRIGGER|OLD_CMD;
+ if (NFC_WAIT_READY()) {
+ return -ERR_NFC_READY;
+ }
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ cfg = SING_RW|NAND2NFC;
+ pNFCRegs->NFCR1 = cfg | NFC_TRIGGER|OLD_CMD;
+ if (NFC_WAIT_READY()) {
+ return -ERR_NFC_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+ status = pNFCRegs->NFCR0 & 0xff;
+
+ #ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz && rdmz) {
+ status = status^rdmz_tb[0];
+ if (status != 0xe0)
+ printf("de-rdmz sts=%x\n", status);
+ }
+ #endif
+
+ return status;
+}
+
+int tellme_badblock(struct nand_chip *nand)
+{
+ unsigned int block, count = 0, chip;
+ NAND_ENABLE_CE(nand, 0);
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+ if (nand->isbadblock == isbbtbadblock)
+ printf("Using BBT to search bad blocks\n");
+ else {
+ printf("Unknow Table tpye\n");
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+ for (chip = 0; chip < nand->numchips; chip++) {
+ for (block = 0; block < nand->dwBlockCount; block++) {
+ if (nand->isbadblock(nand, block, chip)) {
+ printf("block%x is bad. ", block);
+ count++;
+
+ /* Add for get bad block detail */
+ switch (getbbtbadblock_detail(nand, block, chip)) {
+ case 0:
+ printf("(default)\n");
+ break;
+ case 1:
+ printf("(read fail)\n");
+ break;
+ case 2:
+ printf("(write/erase fail)\n");
+ break;
+ default:/* returned value < 0 */
+ printf("bbt not exist!\n");
+ break;
+ }
+ }
+ }
+ printf("chip%d Total %d Bad Block\n", chip, count);
+ }
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+
+int tellme_whereistable(struct nand_chip *nand)
+{
+ unsigned int i, cnt = 0, chip;
+
+ NAND_ENABLE_CE(nand, 0);
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+ for (chip = 0; chip < nand->numchips; chip++) {
+ for (i = 0; i < 6; i++) {
+ if (bad_block_pos[chip][i]) {
+ cnt++;
+ if ((bad_block_pos[chip][i] & 0xffff) == 1)
+ printf("Find Major BBT Table ");
+ else
+ printf("Find Minor BBT Table ");
+ printf("at block%d\n", (bad_block_pos[chip][i]>>16)&0xffff);
+ }
+ }
+ printf("Chip%d Total %d Tables\n", chip, cnt);
+ }
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+
+int tellme_nandinfo(struct nand_chip *nand)
+{
+ int rc = -1;
+
+ if (g_WMTNFCBASE != __NFC_BASE) {
+ rc = nand_probe(__NFC_BASE);
+ if (!rc) {
+ printf("Init Flash Failed rc=%d\r\n", rc);
+ return rc;
+ }
+ }
+
+ printf("NAND information : ");
+ switch (nand->mfr) {
+ case NAND_HYNIX:
+ //case NAND_HYNIX_new:
+ printf("current CHIP structure addr 0x%x NAND_HYNIX\n", (int)nand);
+ break;
+ case NAND_SAMSUNG:
+ printf("current CHIP structure addr 0x%x NAND_SAMSUNG\n", (int)nand);
+ break;
+ case NAND_TOSHIBA:
+ printf("current CHIP structure addr 0x%x NAND_TOSHIBA\n", (int)nand);
+ break;
+ case NAND_SANDISK:
+ printf("current CHIP structure addr 0x%x NAND_SANDISK\n", (int)nand);
+ break;
+ case NAND_MICRON:
+ printf("current CHIP structure addr 0x%x NAND_MICRON\n", (int)nand);
+ break;
+ case NAND_INTEL:
+ printf("current CHIP structure addr 0x%x NAND_INTEL\n", (int)nand);
+ break;
+ case NAND_MXIC:
+ printf("current CHIP structure addr 0x%x NAND_MXIC\n", (int)nand);
+ break;
+ case NAND_MIRA:
+ printf("current CHIP structure addr 0x%x NAND_MIRA\n", (int)nand);
+ break;
+ default:
+ printf(" UNKNOW ( id = %x )\n", nand->mfr);
+ return -1;
+ }
+ printf("page size = %d , Spare size = %d, %d pages per block\n",
+ nand->oobblock_valid, nand->oobsize, nand->dwPageCount);
+ printf("logical page size = %d, logical erase size = %d\n",nand->l_oobblock,nand->l_erasesize);
+ printf("column cycle = %d, row cycle = %d\n", nand->col, nand->row);
+ printf("Erase size = 0x%x, Total Blocks = %d\n", nand->erasesize_valid, nand->dwBlockCount);
+ printf("page_shift = %d, chips_name = %s\n", nand->page_shift, nand->chips_name);
+ printf("bus16 = %d, IO_ADDR = 0x%x\n", nand->bus16, nand->IO_ADDR);
+ printf("numchips = %d\n", nand->numchips);
+ return 0;
+}
+
+int nand_read_page(struct nand_chip *nand, unsigned int start, unsigned int maddr, unsigned int len)
+{
+ unsigned int page = 0, col = 0;
+ int rc = -1;
+
+ /* First we calculate the starting page */
+ page = start >> nand->page_shift;
+ /* Get raw starting column */
+ col = start & (nand->oobblock - 1);
+
+ if (pNFCRegs->NFCR9&2) {
+ col = nand->oobblock;
+ printf("1 bit ecc col=0x%x, row = 0x%x\r\n", col, page);
+ } else {
+ if (nfc_dma_cfg(maddr, len, 0))
+ return -ERR_DMA_CFG;
+ }
+ /* addr */
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, page);
+ /* set command 1 cycle */
+ WRITE_NAND_COMMAND(NAND_READ0);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ if (nand->oobblock > 512)
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|((nand->row+nand->col+1)<<1)|NFC_TRIGGER|0x400;
+ else
+ pNFCRegs->NFCR1 = NAND2NFC|((nand->row+nand->col+1)<<1)|NFC_TRIGGER|0x400;
+ if (nand->oobblock > 512) {
+ if (NFC_WAIT_CMD_READY())
+ return -ERR_NFC_CMD;
+ WRITE_NAND_COMMAND(NAND_READ_CONFIRM);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = NAND2NFC|1<<1|NFC_TRIGGER|0x400;
+ }
+ if (NFC_WAIT_READY())
+ return -ERR_NFC_READY;
+
+ if (!(pNFCRegs->NFCR9&2)) {
+ rc = nand_pdma_handler();
+ nand_free_pdma();
+ if (rc)
+ return -rc;
+ }
+
+ if (NAND_WAIT_READY())
+ return -ERR_NAND_IDLE;
+
+ if (pNFCRegs->NFCR9&2)
+ memcpy_itp((unsigned char *)maddr, (unsigned char *)&pNFCRegs->FIFO[0], 64);
+
+ return 0;
+}
+int wmt_nand_erase(struct nand_chip *nand, unsigned int block)
+{
+ unsigned int row, col = 0;
+
+ /* First we calculate the starting page */
+ row = block * nand->dwPageCount;
+ /* addr */
+ NanD_Address(nand, ADDR_PAGE, col, row);
+
+ WRITE_NAND_COMMAND(NAND_ERASE_SET);
+ /* trigger */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|((nand->row+1)<<1)|NFC_TRIGGER|OLD_CMD;
+
+ //print_nfc_register();
+
+ if (NFC_WAIT_CMD_READY())/* kevin:wait cmd ready excluding data phase */
+ return -ERR_NFC_CMD;
+ if (NAND_WAIT_IDLE())
+ return -ERR_NAND_IDLE;
+ WRITE_NAND_COMMAND(NAND_ERASE_CONFIRM);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;
+ if (NAND_WAIT_READY())
+ return -ERR_NAND_READY;
+ if (NAND_WAIT_IDLE())
+ return -ERR_NAND_IDLE;
+ /* status */
+ return nand_read_status(nand, NAND_STATUS);
+
+}
+int wmt_nand_erase_multi(struct nand_chip *nand, unsigned int block)
+{
+
+
+ //printf("wmt_nand_erase_multi\n");
+
+ unsigned int row, col = 0;
+ unsigned int plane_cnt = 2;
+ unsigned int plane_page[2];
+ int i;
+
+ /*first stage********************************************************/
+ for (i = 0; i < plane_cnt; i++) {
+
+ /* First we calculate the starting page */
+ plane_page[i] = block * nand->dwPageCount + i*nand->dwPageCount;
+
+ row = plane_page[i];
+
+ NanD_Address(nand, ADDR_PAGE, col, row);
+
+ WRITE_NAND_COMMAND(NAND_ERASE_SET);
+
+ /* trigger */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|((nand->row+1)<<1)|NFC_TRIGGER|OLD_CMD;
+
+ if (NFC_WAIT_CMD_READY())
+ return -ERR_NFC_CMD;
+ if (NAND_WAIT_IDLE())
+ return -ERR_NAND_IDLE;
+ }
+ /*final stage************************************************************/
+
+ WRITE_NAND_COMMAND(NAND_ERASE_CONFIRM);
+
+ pNFCRegs->NFCRb |= B2R;
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;
+
+ if (NAND_WAIT_READY())
+ return -ERR_NAND_READY;
+ if (NAND_WAIT_IDLE())
+ return -ERR_NAND_IDLE;
+
+ return nand_read_status(nand, 0x70/*NAND_CMD_STATUS*/);
+}
+
+
+#if 0
+unsigned int reverse32 (unsigned int n)
+{
+ int i=0;
+ unsigned int tmp = n, y=0;
+ for(;i<31;i++) {//31
+ y += tmp&0x00000001;
+ tmp >>= 1;
+ y <<= 1;
+ }
+ y += tmp&0x00000001;
+ return y;
+}
+
+int Gen_GF2(u8 bits, unsigned int *buf)
+{
+// assign bch_GF_40becc = 560'hC07F_89B1_A0DC_5D96_619F_32D0_4967_54F6_DE9D_4F93_F527_EF14_EFB0_FD53_9915_A82C_CD92_5528_8030_477D_EE3F_338A_59EC_5FA2_10AF_E2EF_DFAE_D244_DF31_4DA5_0762_B724_A002_9CEF_2DC1;
+// assign bch_GF_24becc = 560'h8E94_E024_8D90_9D2B_4525_72D1_EDD9_D098_FE73_0E8E_8D26_C2D2_2893_A3A0_485B_D0AB_6E0B_4992_9A35_6BD4_30EF;
+// assign bch_GF_12becc = 560'hE48_7325_6115_A567_84A6_940A_4C6E_6D7E_1205_E051;
+// assign bch_GF_8becc = 560'h15_F914_E07B_0C13_8741_C5C4_FB23;
+// assign bch_GF_4becc = 560'h4_5230_43AB_86AB;
+ unsigned int bch_GF_40becc[] = { 0xC07F, 0x89B1A0DC, 0x5D96619F, 0x32D04967, 0x54F6DE9D, 0x4F93F527, 0xEF14EFB0, 0xFD539915, 0xA82CCD92, 0x55288030, 0x477DEE3F, 0x338A59EC, 0x5FA210AF, 0xE2EFDFAE, 0xD244DF31, 0x4DA50762, 0xB724A002, 0x9CEF2DC1};
+ unsigned int bch_GF_24becc[] = { 0x8E94, 0xE0248D90, 0x9D2B4525, 0x72D1EDD9, 0xD098FE73, 0x0E8E8D26, 0xC2D22893, 0xA3A0485B, 0xD0AB6E0B, 0x49929A35, 0x6BD430EF};
+ unsigned int bch_GF_12becc[] = { 0xE487325, 0x6115A567, 0x84A6940A, 0x4C6E6D7E, 0x1205E051};
+ unsigned int bch_GF_8becc[] = { 0x15, 0xF914E07B, 0x0C138741, 0xC5C4FB23};
+ unsigned int bch_GF_4becc[] = { 0x45230, 0x43AB86AB};
+ unsigned int *p;
+ int i,len,width;
+
+ switch (bits) {
+ case 4 : width = 51; p = bch_GF_4becc; break;
+ case 8 : width = 103; p = bch_GF_8becc; break;
+ case 12 : width = 155; p = bch_GF_12becc; break;
+ case 24 : width = 335; p = bch_GF_24becc; break;
+ case 40 : width = 559; p = bch_GF_40becc; break;
+ default : width = 51; p = bch_GF_4becc; break;
+ }
+ len = width/32 +1;
+ for(i=0;i<len;i++)
+ buf[i] = *(p+len-1-i);
+
+ return (width);
+}
+
+unsigned int Caculat_1b_bch( unsigned int *pariA, unsigned int *bch_GF2, unsigned int din, u8 pari_len, u8 pari_lb)
+{
+ //din: bit31-1 should be 0, only bit0 is valid
+ //pari_len: the index of last DW of the parity
+ //pari_lb: the MSB of the last DW
+ u8 i;
+ unsigned int mask = ~(0xffffffff <<(pari_lb+1));
+ unsigned int lstdw = mask & pariA[pari_len];
+ unsigned int ldwMSB = lstdw >> pari_lb ;
+ // for(i=pari_len;i>=0;i--) printk("%8x",pariA[i]);printk("\n---before\n");
+ for(i=pari_len;i>0;i--) {
+ pariA[i]= (pariA[i]<<1) +(pariA[i-1]>>31);
+ if(din ^ ldwMSB) pariA[i] = pariA[i] ^ bch_GF2[i];
+ }
+ pariA[0]= (pariA[0]<<1);
+ if(din ^ ldwMSB) pariA[i] = pariA[i]^ bch_GF2[i];
+// for(i=pari_len;i>=0;i--) printf("%8x",pariA[i]);printf("\n---after\n");
+ return (ldwMSB );
+}
+
+int bch_encoder(unsigned int *p_parity, unsigned int *p_data, u8 bits, unsigned int datacnt)
+{
+ int i,j;
+ int bchGF_msb;
+ u8 pari_len,pari_lb;
+ unsigned int bch_GF2[18];
+ unsigned int tmp;
+ unsigned int *p, *p1;
+ u8 *p2, p3[50];
+
+ bchGF_msb = Gen_GF2( bits, bch_GF2);
+ pari_len = (u8)(bchGF_msb /32);
+ pari_lb = (u8)(bchGF_msb %32);
+ //p = (unsigned int *)malloc((pari_len+2) * sizeof(unsigned int));
+ p = (unsigned int *)malloc((pari_len+2) * sizeof(unsigned int));
+ if (p == NULL) {
+ printf("malloc Error!");
+ return -1;
+ } else {
+ /*gen parity[ bchGF_msb:0] begin*/
+ //Init
+ for(i=pari_len+1;i>=0;i--)
+ *(p+i) = 0;
+ //Caculate
+ p1 = &p[1];
+ for (i=0;i<datacnt;i++) {
+ tmp = p_data[i];
+ for (j=0;j<32;j++) {
+ Caculat_1b_bch( p1, bch_GF2, tmp&0x00000001, pari_len, pari_lb);
+ tmp >>= 1;
+ }
+ }
+
+ //printf("encode finiah!pari_len=%d p_parity=0x%x\n",pari_len, (unsigned int)p_parity);
+ /*gen parity[ bchGF_msb:0] end*/
+
+ /*reverse oder of parity begin*/
+ p2 = (u8 *)p;
+ //printf("pari_lb=%d p2=0x%x\n", pari_lb, (unsigned int)p2);
+ //p1 = (unsigned int *)(p2+3-(pari_lb/8));
+ p2 = (p2+3-(pari_lb/8));
+ for(i=0;i<((pari_len+1)*4);i++)
+ p3[i] = p2[i];
+ p1 = (unsigned int *)p3;
+
+
+ //printf("p1=0x%x p2=0x%x\n", (unsigned int)p1, (unsigned int)p2);
+ for(i=0;i<=pari_len;i++) {
+ p_parity[pari_len-i] = (unsigned int)reverse32(p1[i]);
+ }
+ /*reverse oder of parity end*/
+ //printf("reverse finiah!\n");
+ free(p); //release malloc
+ }
+ //printf("leave encode\n");
+ return 0;
+}
+#endif
+#if 1 //faster encode function
+u32 reverse32 (u32 n)
+{
+ int i;
+ u32 tmp, y;
+
+ y=0;
+ tmp = n;
+
+ for(i=0;i<31;i++)
+ {
+ y = y + (tmp & 0x01);
+ //printf("y=%08x\n",y);
+ tmp >>= 1;
+ y <<= 1;
+ }
+ y = y + (tmp & 0x01);
+
+ return y;
+}
+
+int gen_gf2(u8 ecc_mod_bits, u32 *p_bch_gf2)
+{
+// assign bch_GF_60becc = 840'h9A_5FB0C03C_2D3F4F2F_F106E7D9_ED397A28_479724D7_F259A1CD_DB6C78DA_62668B7F_D9D13742_80F0C37C_06664C92_86CCB2D9_DD1A2B4B_3BC4895C_F7212F8C_D75FB017_7FBFE2B9_66646AAA_CEB7855F_6996F036_3D096201_F62357BD_EB9AD670_03F47DD9_73D6AE65_E5A30A27;
+// assign bch_GF_40becc = 560'hC07F_89B1_A0DC_5D96_619F_32D0_4967_54F6_DE9D_4F93_F527_EF14_EFB0_FD53_9915_A82C_CD92_5528_8030_477D_EE3F_338A_59EC_5FA2_10AF_E2EF_DFAE_D244_DF31_4DA5_0762_B724_A002_9CEF_2DC1;
+// assign bch_GF_24becc = 560'h8E94_E024_8D90_9D2B_4525_72D1_EDD9_D098_FE73_0E8E_8D26_C2D2_2893_A3A0_485B_D0AB_6E0B_4992_9A35_6BD4_30EF;
+// assign bch_GF_12becc = 560'hE48_7325_6115_A567_84A6_940A_4C6E_6D7E_1205_E051;
+// assign bch_GF_8becc = 560'h15_F914_E07B_0C13_8741_C5C4_FB23;
+// assign bch_GF_4becc = 560'h4_5230_43AB_86AB;
+ u32 bch_GF_60becc[] = { 0x9A, 0x5FB0C03C, 0x2D3F4F2F, 0xF106E7D9, 0xED397A28, 0x479724D7, 0xF259A1CD, 0xDB6C78DA, 0x62668B7F, 0xD9D13742, 0x80F0C37C, 0x06664C92, 0x86CCB2D9, 0xDD1A2B4B, 0x3BC4895C, 0xF7212F8C, 0xD75FB017, 0x7FBFE2B9, 0x66646AAA, 0xCEB7855F, 0x6996F036, 0x3D096201, 0xF62357BD, 0xEB9AD670, 0x03F47DD9, 0x73D6AE65, 0xE5A30A27};
+ u32 bch_GF_40becc[] = { 0xC07F, 0x89B1A0DC, 0x5D96619F, 0x32D04967, 0x54F6DE9D, 0x4F93F527, 0xEF14EFB0, 0xFD539915, 0xA82CCD92, 0x55288030, 0x477DEE3F, 0x338A59EC, 0x5FA210AF, 0xE2EFDFAE, 0xD244DF31, 0x4DA50762, 0xB724A002, 0x9CEF2DC1};
+ u32 bch_GF_24becc[] = { 0x8E94, 0xE0248D90, 0x9D2B4525, 0x72D1EDD9, 0xD098FE73, 0x0E8E8D26, 0xC2D22893, 0xA3A0485B, 0xD0AB6E0B, 0x49929A35, 0x6BD430EF};
+ u32 bch_GF_12becc[] = { 0xE487325, 0x6115A567, 0x84A6940A, 0x4C6E6D7E, 0x1205E051};
+ u32 bch_GF_8becc[] = { 0x15, 0xF914E07B, 0x0C138741, 0xC5C4FB23};
+ u32 bch_GF_4becc[] = { 0x45230, 0x43AB86AB};
+ u32 *p_tmp;
+ int i,len,width;
+
+ switch (ecc_mod_bits)
+ {
+ case 4 : width = 52; p_tmp = bch_GF_4becc; break;
+ case 8 : width = 104; p_tmp = bch_GF_8becc; break;
+ case 12 : width = 156; p_tmp = bch_GF_12becc; break;
+ case 24 : width = 336; p_tmp = bch_GF_24becc; break;
+ case 40 : width = 560; p_tmp = bch_GF_40becc; break;
+ case 60 : width = 840; p_tmp = bch_GF_60becc; break;
+ default : width = 52; p_tmp = bch_GF_4becc; break;
+ }
+len = width/32 +1;
+for(i=0;i<len;i++)
+ *(p_bch_gf2+i) = *(p_tmp+len-1-i);
+
+return (width);
+}
+//calculate ecc with 1bit data
+u32 calc_1b_bch( u32 *parity_buf, u32 *bch_GF2, u32 din, u8 parity_len, u8 parity_msb_pos)
+{
+ //parity_buf: pointer to parity buffer
+ //bch_GF2: pointer to generation polynomial
+ //din: input data, bit31-1 should be 0, only bit0 is valid
+ //parity_len: parity length in DW
+ //parity_msb_pos: the msb position of parity
+ u8 i;
+ u32 mask = ~(0xffffffff << (parity_msb_pos));
+ u32 msb_word = mask & parity_buf[parity_len-1];
+ u32 parity_msb = msb_word >> (parity_msb_pos-1) ;
+
+ for(i=parity_len-1;i>0;i--)
+ {
+ parity_buf[i]= (parity_buf[i]<<1) +(parity_buf[i-1]>>31);
+ if(din ^ parity_msb) parity_buf[i]= parity_buf[i]^ bch_GF2[i];
+ }
+
+ parity_buf[0]= (parity_buf[0]<<1);
+ if(din ^ parity_msb) parity_buf[i]= parity_buf[i]^ bch_GF2[i];
+
+ return (parity_msb );
+}
+
+int bch_encoder(u32 *p_parity, u32 *p_data, u8 ecc_mod_bits, u32 datacnt)
+{
+ //p_parity: pointer to parity buffer
+ //p_data: pointer to input data
+ //ecc_mod_bits: ecc mode select, options are 4,8,12,24,40,60
+ //datacnt: data length in DW
+ int i,j;
+ int bchGF_width;
+ u8 parity_len,parity_msb_pos;
+ u32 bch_GF2[27]; //support 60becc, 105bytes 27DW
+ u32 tmp;
+ u32 *p;
+ u8 align_offset;
+
+ bchGF_width = gen_gf2( ecc_mod_bits, bch_GF2);
+ parity_len = (u8)(bchGF_width /32 + 1);
+ parity_msb_pos = (u8)(bchGF_width %32);
+ align_offset = 32 - parity_msb_pos;
+
+ //p = (u32 *)malloc((parity_len) * sizeof(u32));
+ p = (unsigned int *)malloc((parity_len) * sizeof(unsigned int));
+ if (p == NULL) {
+ printf("malloc Error!");
+ return -1;
+ } else {
+ //initialize parity buffer
+ for(i=parity_len-1;i>=0;i--)
+ *(p+i) = 0;
+
+ //Caculate bit by bit
+ for (i=0;i<datacnt;i++) {
+ tmp = p_data[i];
+ for (j=0;j<32;j++) {
+ calc_1b_bch( p, bch_GF2, tmp&0x00000001, parity_len, parity_msb_pos);
+ tmp >>= 1;
+ }
+ }
+ //adjust parity align offset
+ for (i=parity_len -1 ; i >0; i--)
+ p[i] = (p[i] << align_offset) + (p[i-1] >> (32-align_offset));
+
+ p[0] = p[0] << align_offset;
+
+ //reverse parity order
+ for(i=0;i<parity_len;i++)
+ p_parity[parity_len-1-i] =reverse32(p[i]);
+ free(p); //release malloc
+ }
+ return 0;
+}
+
+int hw_encode_oob(struct nand_chip *nand)
+{
+ int ret = 0;
+ unsigned int ecc_mode, oob_ecc_mode, tmp;
+ ret = reset_nfc();
+ tmp = pNFCRegs->NFCR9;
+ ecc_mode = tmp & ECC_MOD_SEL;
+ oob_ecc_mode = ecc_mode;
+ if (ecc_mode > 5)
+ oob_ecc_mode = 5;
+
+ if (oob_ecc_mode != ecc_mode)
+ pNFCRegs->NFCR9 = (tmp&(~ECC_MOD_SEL)) | oob_ecc_mode;
+
+ pNFCRegs->NFCRd |= OOB_READ;
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|NFC_TRIGGER|OLD_CMD;
+
+ ret = NAND_WAIT_IDLE();
+ if (ret)
+ printf("hw encode oob idle time out\n");
+
+ pNFCRegs->NFCRd = 0;
+
+ if (oob_ecc_mode != ecc_mode)
+ pNFCRegs->NFCR9 = tmp;
+
+ return ret;
+}
+
+
+static int wmt_nand_write_oob(struct nand_chip *nand)
+{
+ //struct ECC_size_info ECC_size;
+ //unsigned int ecc_bit_mode, i, data_len = 24;
+ //unsigned char ecc_bit = 24, c_len = 42;
+ //unsigned char *FIFO6 = (unsigned char *)&pNFCRegs->FIFO[24];
+ //unsigned char *FIFO0 = (unsigned char *)&pNFCRegs->FIFO[0];
+ //FIFO0 = FIFO0 + 18;
+ /*ecc_bit_mode = nand->dwECCBitNum;
+ if (ecc_bit_mode > 24)
+ ecc_bit_mode = (ecc_bit_mode == 40) ? 6 : (-1);
+ else
+ ecc_bit_mode = (ecc_bit_mode > 16) ? ((ecc_bit_mode/4) - 1) : (ecc_bit_mode/4);
+ ECC_size.ecc_engine = ecc_bit_mode;
+ calculate_ECC_info(nand, &ECC_size);*/
+// printf("\n ecc_bit_mode is %d\n", ecc_bit_mode);
+
+ //pNFCRegs->NFCR10 = (ECC_size.oob_ECC_bytes<<8);//+ ECC_size.unprotect&0xFF;
+
+ //print_nfc_register();
+ //printf("\n ");
+ //ecc_bit = ECC_size.oob_max_bit_error;
+ //c_len = ECC_size.oob_ECC_bytes;
+ if(nand->oobblock == 2048) {
+ //memcpy(FIFO0, oob_poi, 24);
+ #ifdef SW_ENCODE_OOB
+ bch_encoder((unsigned int *)parity, (unsigned int *)FIFO0, ecc_bit, data_len/4);
+ for (i = 0; i < c_len; i++) {
+ if (i >= 40) {
+ pNFCRegs->NFCRd |= 0x08;
+ FIFO0[i-40] = parity[i];
+ } else FIFO6[i] = parity[i];
+ }
+ pNFCRegs->NFCRd &= 0xF7;
+ #endif
+
+ #ifdef HW_ENCODE_OOB
+ hw_encode_oob(nand);
+ #endif
+
+ } else if (nand->oobblock >= 4096) {
+ //memcpy(FIFO0, oob_poi, 24);
+ #ifdef SW_ENCODE_OOB
+ bch_encoder((unsigned int *)parity, (unsigned int *)FIFO0, ecc_bit, data_len/4);
+ pNFCRegs->NFCRd &= 0xF7;
+// for (i = 0; i < 6; i++)
+// pNFCRegs->FIFO[i] = oob_poi[i];
+// printf("\n After bch encoder is :\n");
+// print_nand_buf(parity, 32);
+ // for (i = 0; i< 24; i++)
+ //memcpy(FIFO0, oob_poi, 24);
+ for (i = 0; i < c_len; i++) {
+ if (i >= 40) {
+ pNFCRegs->NFCRd |= 0x08;
+ FIFO0[i-40] = parity[i];
+ } else FIFO6[i] = parity[i];
+ }
+ pNFCRegs->NFCRd &= 0xF7;
+ #endif
+ #ifdef HW_ENCODE_OOB
+ hw_encode_oob(nand);
+ #endif
+ }
+// printf("\n FIFO is \n");
+// print_nand_buf(FIFO0, 32);
+// printf("\n");
+// print_nfc_register();
+ return 0;
+}
+#endif
+
+int nand_page_program(struct nand_chip *nand, unsigned int page, unsigned int maddr, unsigned int len)
+{
+ unsigned int row = 0, col = 0;
+
+ row = page;
+
+ /* reset nand */
+ WRITE_NAND_COMMAND(NAND_READ0);
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;
+ if (NFC_WAIT_READY()) {
+ return -ERR_NFC_READY;
+ }
+ //if(nand->oob_flag) wmt_nand_write_oob(nand); Johnny
+ //if ((page/nand->dwPageCount) >= (nand->dwBlockCount - 8))
+ wmt_nand_write_oob(nand);
+
+ if (nfc_dma_cfg(maddr, len, 1)) {
+ return -ERR_DMA_CFG;
+ }
+
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, row);
+ WRITE_NAND_COMMAND(NAND_SEQIN);
+
+//#ifdef WMT_HW_RDMZ
+ //pNFCRegs->NFCRf &= ~RDMZ;
+ //if (nand->dwRdmz == 1 && !(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ //*(unsigned int *)&pNFCRegs->FIFO[20] = wmt_rdmz;
+ //pNFCRegs->NFCRf = RDMZ/*|(page%RDMZ)*/;
+ //}
+//#endif
+ #ifdef WMT_HW_RDMZ
+ pNFCRegs->NFCRf &= ~RDMZ;
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC) && !nand->bbt_sw_rdmz) {//henry add " nand->bbt_sw_rdmz"
+ enable_hw_rdmz(nand);
+ //printf("HW RDMZ ON ( nand_page_program )\n");
+ }
+ #endif
+
+ /* trigger */
+ pNFCRegs->NFCR1 = ((nand->row+nand->col+1)<<1)|NFC_TRIGGER|OLD_CMD;/* command 1 cycle */
+ if (NFC_WAIT_READY())/* wait command &data completed */ {
+ return -ERR_NFC_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+ WRITE_NAND_COMMAND(NAND_PAGEPROG);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;/* command 2 cycle */
+ if (NAND_WAIT_READY()) {
+ return -ERR_NAND_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+/*#ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz == 1)
+ pNFCRegs->NFCRf &= ~RDMZ;
+#endif*/
+ /* status */
+ return nand_read_status(nand, NAND_STATUS);
+}
+
+
+static int wmt_nand_write_oob_60bit(struct nand_chip *nand, unsigned int maddr)
+{
+ int i;
+ unsigned int *FIFO = (unsigned int *)pNFCRegs->FIFO;
+
+ //printf("w:data start 0x%x\n",maddr);
+ //printf("w:oob start 0x%x\n",maddr + nand->oobblock_valid);
+
+ unsigned int *buf = (unsigned int *)(maddr + nand->oobblock_valid);
+
+ for (i = 0; i < 12; i++) {
+ if (i<6) {
+ buf[i] = FIFO[i];
+ //printf("buf[%d]=0x%x ",i,buf[i]);
+ } else {
+ buf[i] = 0x55555555; //fill 24byte zeros after 24byte oob
+ }
+ }
+ //printf("\n");
+
+ return 0;
+}
+
+int nand_page_program_60bit(struct nand_chip *nand, unsigned int page, unsigned int maddr, unsigned int len)
+{
+ //printf("nand_page_program_60bit page=0x%x maddr=0x%x\n",page,maddr);
+
+ unsigned int row = 0, col = 0;
+
+ row = page;
+
+ /* just use a buffer to config the data we're going to write */
+ memcpy_itp(data_buf, (unsigned char *)maddr, nand->oobblock_valid);
+ wmt_nand_write_oob_60bit(nand,(unsigned int)data_buf);
+
+
+ /* reset nand */
+ WRITE_NAND_COMMAND(NAND_READ0);
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;
+ if (NFC_WAIT_READY()) {
+ return -ERR_NFC_READY;
+ }
+
+ //printf("write data buf: 0x%x,page=0x%x\n",maddr,page);
+ //print_nand_buf((unsigned char *)maddr,100);
+
+ if (nfc_dma_cfg((unsigned int)data_buf, len+1024, 1)) { //len + 1024 --> 1024=oob's bank
+ return -ERR_DMA_CFG;
+ }
+
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, row);
+ WRITE_NAND_COMMAND(NAND_SEQIN);
+
+ /* trigger */
+ pNFCRegs->NFCR1 = ((nand->row+nand->col+1)<<1)|NFC_TRIGGER|OLD_CMD;/* command 1 cycle */
+ if (NFC_WAIT_READY())/* wait command &data completed */ {
+ return -ERR_NFC_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+ WRITE_NAND_COMMAND(NAND_PAGEPROG);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;/* command 2 cycle */
+ if (NAND_WAIT_READY()) {
+ return -ERR_NAND_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+
+ /* status */
+ return nand_read_status(nand, NAND_STATUS);
+}
+#if 0
+int nand_page_program2(struct nand_chip *nand, unsigned int page,
+unsigned int maddr, unsigned int len,int oob_offs,int pipeline,int lastpage)
+{
+ unsigned int row = 0, col = 0;
+ int rdmz0or1 = pipeline % 2;
+
+ row = page;
+
+ if(pipeline == 0) {
+ if (nfc_dma_cfg((unsigned int)rdmz_buf0, len, 1)) {
+ return -ERR_DMA_CFG;
+ }
+ }
+ else {//According to the page number , assign the proper buf to dma (for pipeline)
+ if (nfc_dma_cfg((rdmz0or1==1)?(unsigned int)rdmz_buf1 : (unsigned int)rdmz_buf0, len, 1)) {
+ return -ERR_DMA_CFG;
+ }
+ }
+
+ /* reset nand */
+ WRITE_NAND_COMMAND(NAND_READ0);
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;
+ if (NFC_WAIT_READY()) {
+ return -ERR_NFC_READY;
+ }
+ //if(nand->oob_flag) wmt_nand_write_oob(nand); Johnny
+// if ((page/nand->dwPageCount) >= (nand->dwBlockCount - 8)){
+ wmt_nand_write_oob(nand);
+// printf("page=%d ",page);
+// }
+
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, row);
+ WRITE_NAND_COMMAND(NAND_SEQIN);
+
+#ifdef WMT_HW_RDMZ
+ //pNFCRegs->NFCRf &= ~RDMZ;
+ if (nand->dwRdmz == 1 && !(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ *(unsigned int *)&pNFCRegs->FIFO[20] = wmt_rdmz;
+ pNFCRegs->NFCRf = RDMZ/*|(page%RDMZ)*/;
+ }
+#endif
+ /* trigger */
+ pNFCRegs->NFCR1 = ((nand->row+nand->col+1)<<1)|NFC_TRIGGER|OLD_CMD;/* command 1 cycle */
+
+ if(!lastpage){//do the pipeline if this is not the first page in a block
+ memcpy_itp((rdmz0or1==1)? rdmz_buf0 : rdmz_buf1, (unsigned char *)maddr+nand->oobblock+oob_offs, nand->oobblock);//mem copy next (oob_offs=0)
+ }
+
+ if (NFC_WAIT_READY())/* wait command &data completed */ {
+ return -ERR_NFC_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+ WRITE_NAND_COMMAND(NAND_PAGEPROG);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;/* command 2 cycle */
+
+ if(!lastpage){//do the pipeline if this is not the first page in a block
+ rdmzier2((uint8_t *)((rdmz0or1==1)? rdmz_buf0 : rdmz_buf1), nand->oobblock/4, page + 1);//page+1 for pipeline
+ }
+
+ if (NAND_WAIT_READY()) {
+ return -ERR_NAND_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+/*#ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz == 1)
+ pNFCRegs->NFCRf &= ~RDMZ;
+#endif*/
+ /* status */
+ return nand_read_status(nand, NAND_STATUS);
+}
+#endif
+int nand_page_program_multi(struct nand_chip *nand, unsigned int page, unsigned int maddr, unsigned int len, int oob_offs)
+{
+ unsigned int row = 0, col = 0, page1;
+
+ row = page;
+ page1 = page + nand->dwPageCount;
+//----------------------plane 0---------------------------------
+
+ wmt_nand_write_oob(nand);
+
+ if (nfc_dma_cfg(maddr, len, 1)) {
+ return -ERR_DMA_CFG;
+ }
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, row);
+ WRITE_NAND_COMMAND(NAND_SEQIN);
+
+ #ifdef WMT_HW_RDMZ
+ pNFCRegs->NFCRf &= ~RDMZ;
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ enable_hw_rdmz(nand);
+ //printf("HW RDMZ ON ( nand_page_program_multi )\n");
+ }
+ #endif
+
+ /* trigger */
+ pNFCRegs->NFCR1 = ((nand->row+nand->col+1)<<1)|NFC_TRIGGER|OLD_CMD;/* command 1 cycle */
+ if (NFC_WAIT_READY())/* wait command &data completed */ {
+ return -ERR_NFC_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+ WRITE_NAND_COMMAND(0x11);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;/* command 2 cycle */
+ if (NAND_WAIT_READY()) {
+ return -ERR_NAND_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+
+//------------------plane 1--------------------------------------------------
+
+ if (nfc_dma_cfg(maddr+nand->oobblock/*+oob_offs*/, len, 1)) {
+ return -ERR_DMA_CFG;
+ }
+
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, page1);
+ WRITE_NAND_COMMAND(0x81);
+
+//#ifdef WMT_HW_RDMZ
+ //pNFCRegs->NFCRf &= ~RDMZ;
+ //if (nand->dwRdmz == 1 && !(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ //*(unsigned int *)&pNFCRegs->FIFO[20] = wmt_rdmz;
+ //pNFCRegs->NFCRf = RDMZ/*|(page%RDMZ)*/;
+// }
+//#endif
+ #ifdef WMT_HW_RDMZ
+ pNFCRegs->NFCRf &= ~RDMZ;
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ enable_hw_rdmz(nand);
+ //printf("HW RDMZ ON ( nand_page_program_multi )\n");
+ }
+ #endif
+
+ /* trigger */
+ pNFCRegs->NFCR1 = ((nand->row+nand->col+1)<<1)|NFC_TRIGGER|OLD_CMD;/* command 1 cycle */
+ if (NFC_WAIT_READY())/* wait command &data completed */ {
+ return -ERR_NFC_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+ WRITE_NAND_COMMAND(NAND_PAGEPROG);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;/* command 2 cycle */
+ if (NAND_WAIT_READY()) {
+ return -ERR_NAND_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+
+/*#ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz == 1)
+ pNFCRegs->NFCRf &= ~RDMZ;
+#endif*/
+
+ /* status */
+ return nand_read_status(nand, NAND_STATUS);//fix use multi read status
+}
+
+int nand_page_program_multi_60bit(struct nand_chip *nand, unsigned int page, unsigned int maddr, unsigned int len, int oob_offs)
+{
+ unsigned int row = 0, col = 0, page1;
+
+ row = page;
+ page1 = page + nand->dwPageCount;
+
+ /* just use a buffer to config the data we're going to write */
+ memcpy_itp(data_buf, (unsigned char *)maddr, nand->oobblock_valid);
+ wmt_nand_write_oob_60bit(nand,(unsigned int)data_buf);
+
+//----------------------plane 0---------------------------------
+
+ //wmt_nand_write_oob(nand);
+
+ if (nfc_dma_cfg((unsigned int)data_buf, len+1024, 1)) {
+ return -ERR_DMA_CFG;
+ }
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, row);
+ WRITE_NAND_COMMAND(NAND_SEQIN);
+
+ #ifdef WMT_HW_RDMZ
+ pNFCRegs->NFCRf &= ~RDMZ;
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ enable_hw_rdmz(nand);
+ //printf("HW RDMZ ON ( nand_page_program_multi )\n");
+ }
+ #endif
+
+ /* trigger */
+ pNFCRegs->NFCR1 = ((nand->row+nand->col+1)<<1)|NFC_TRIGGER|OLD_CMD;/* command 1 cycle */
+ if (NFC_WAIT_READY())/* wait command &data completed */ {
+ return -ERR_NFC_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+ WRITE_NAND_COMMAND(0x11);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;/* command 2 cycle */
+ if (NAND_WAIT_READY()) {
+ return -ERR_NAND_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+
+//------------------plane 1--------------------------------------------------
+
+ /* just use a buffer to config the data we're going to write */
+ memcpy_itp(data_buf, (unsigned char *)maddr + nand->oobblock_valid, nand->oobblock_valid);
+ wmt_nand_write_oob_60bit(nand,(unsigned int)data_buf);
+
+ if (nfc_dma_cfg((unsigned int)data_buf, len+1024, 1)) {
+ return -ERR_DMA_CFG;
+ }
+
+ NanD_Address(nand, ADDR_COLUMN_PAGE, col, page1);
+ WRITE_NAND_COMMAND(0x81);
+
+//#ifdef WMT_HW_RDMZ
+ //pNFCRegs->NFCRf &= ~RDMZ;
+ //if (nand->dwRdmz == 1 && !(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ //*(unsigned int *)&pNFCRegs->FIFO[20] = wmt_rdmz;
+ //pNFCRegs->NFCRf = RDMZ/*|(page%RDMZ)*/;
+// }
+//#endif
+ #ifdef WMT_HW_RDMZ
+ pNFCRegs->NFCRf &= ~RDMZ;
+ if (!(pNFCRegs->NFCR9 & DIS_BCH_ECC)) {
+ enable_hw_rdmz(nand);
+ //printf("HW RDMZ ON ( nand_page_program_multi )\n");
+ }
+ #endif
+
+ /* trigger */
+ pNFCRegs->NFCR1 = ((nand->row+nand->col+1)<<1)|NFC_TRIGGER|OLD_CMD;/* command 1 cycle */
+ if (NFC_WAIT_READY())/* wait command &data completed */ {
+ return -ERR_NFC_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+ WRITE_NAND_COMMAND(NAND_PAGEPROG);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;/* command 2 cycle */
+ if (NAND_WAIT_READY()) {
+ return -ERR_NAND_READY;
+ }
+ if (NAND_WAIT_IDLE()) {
+ return -ERR_NAND_IDLE;
+ }
+
+/*#ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz == 1)
+ pNFCRegs->NFCRf &= ~RDMZ;
+#endif*/
+
+ /* status */
+ return nand_read_status(nand, NAND_STATUS);//fix use multi read status
+}
+
+int WMTEraseNANDALL(struct nand_chip *nand, unsigned int all)
+{
+ unsigned int i, block = 0, start, blk_cnt;
+ int rc = -1, bbt_blk = BBT_MAX_BLOCK, retry_blk = 4;
+
+ if (g_WMTNFCBASE != __NFC_BASE) {
+ rc = nand_probe(__NFC_BASE);
+ if (!rc) {
+ printf("Init Flash Failed rc=%d\r\n", rc);
+ return -1;
+ }
+ }
+ if (nand->realplanenum) {
+ bbt_blk = BBT_MAX_BLOCK*2;
+ retry_blk *= 2;
+ }
+ blk_cnt = nand->dwBlockCount;
+ for (i = 0; i < nand->numchips; i++) {
+ NAND_ENABLE_CE(nand, i);
+ if (all == 1) //force erase all
+ start = 0;
+ else if (all == 2) { //force erase retry
+ start = nand->dwBlockCount - bbt_blk - retry_blk;
+ blk_cnt -= (nand->realplanenum ? 8 : 4);
+ } else if (all == 3) { //force erase bbt
+ start = nand->dwBlockCount - bbt_blk;
+ } else { //erase bbt & retry (skip bad blocks)
+ start = nand->dwBlockCount - bbt_blk - retry_blk;
+ }
+
+ for (block = start; block < blk_cnt; block++) {
+ if(all==0 && nand->isbadblock(nand, block, 0)) {//skip bad block only when all=0
+ printf("skip erasing bad block %d\n",block);
+ continue;
+ }
+ rc = wmt_nand_erase(nand, block);
+ }
+ }
+ if (all != 2) {
+ free(bbt);
+ bbt = NULL;
+ }
+ NAND_DISABLE_CE(nand);
+
+ return 0;
+}
+
+
+int WMTEraseNAND(struct nand_chip *nand, unsigned int block, unsigned int block_nums, unsigned int all)
+{
+ unsigned int i, cnt1 = 0, cnt = 0;
+ int rc = -1, bbt_blk = BBT_MAX_BLOCK, retry_blk = RETRY_MAX_BLOCK;
+ unsigned int chip = 0, need[CFG_MAX_NAND_DEVICE];
+ unsigned int blk_start[CFG_MAX_NAND_DEVICE], blk_nobbt_inchip, blk_in_chip;
+ unsigned int blk_len[CFG_MAX_NAND_DEVICE], len_in_blk = block_nums;
+
+ if ((block + block_nums) > (nand->numchips*nand->dwBlockCount)) {
+// printf(" erase block length is out of flash size");
+ return -1;
+ }
+
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+
+ for (i = 0; i < CFG_MAX_NAND_DEVICE; i++)
+ blk_len[i] = blk_start[i] = need[i] = 0;
+
+ if (nand->realplanenum) {
+ bbt_blk *= 2;
+ retry_blk *= 2;
+ }
+
+ if(cur_chip != NULL && nand->mfr == NAND_HYNIX)
+ blk_nobbt_inchip = nand->dwBlockCount - bbt_blk - retry_blk;
+ else
+ blk_nobbt_inchip = nand->dwBlockCount - bbt_blk;
+
+ while ((len_in_blk && chip < nand->numchips) && !all) {
+ //printf("len_in_blk= 0x%x", len_in_blk);
+ chip = block/nand->dwBlockCount;
+ blk_in_chip = block%nand->dwBlockCount;
+ blk_start[chip] = blk_in_chip;
+ if ((len_in_blk + blk_in_chip) > nand->dwBlockCount) {
+ len_in_blk -= (nand->dwBlockCount - blk_in_chip);
+ block += (nand->dwBlockCount - blk_in_chip);
+ blk_len[chip] = (blk_nobbt_inchip > blk_in_chip)
+ ? (blk_nobbt_inchip - blk_in_chip) : 0;
+ } else {
+ blk_len[chip] =
+ ((len_in_blk + blk_in_chip) >= blk_nobbt_inchip)
+ ? ((blk_nobbt_inchip > blk_in_chip) ? (blk_nobbt_inchip - blk_in_chip) : 0)
+ : len_in_blk;
+ block += len_in_blk;
+ len_in_blk = 0;
+ break;
+ }
+ chip++;
+ }
+
+ if (all)
+ for (chip = 0; chip < nand->numchips; chip++) {
+ blk_start[chip] = 0;
+ blk_len[chip] = blk_nobbt_inchip;
+ }
+
+// for (i = 0; i < CFG_MAX_NAND_DEVICE; i++)
+// if (blk_len[i])
+// printf("Erase start at chip%d block %d len=%d\n", i, blk_start[i], blk_len[i]);
+
+ for (chip = 0; chip < nand->numchips; chip++) {
+ for (i = blk_start[chip]; i < blk_start[chip] + blk_len[chip]; i++) {
+ NAND_ENABLE_CE(nand, chip);
+
+ //if read fail
+ if (!nand->isbadblock(nand, i, chip) || (erase_all_read_fail && getbbtbadblock_detail(nand, i, chip)==1)) {
+
+ if (erase_all_read_fail && getbbtbadblock_detail(nand, i, chip)==1) {
+ //set good block
+ update_bbt_inram_set_goodblk(nand , i, chip);
+ printf("block %d is read fail but still erase \n",i);
+ }
+
+ /*printf("Erase start at chip%d block %d \n", chip, i);*/
+ rc = wmt_nand_erase(nand, i);
+ if (rc < 0 || rc & 0x01) {
+ cnt1++;
+ nand->update_table_inram(nand, i, chip);
+ printf("erase fail uddate table chip%d block%d\n", chip, i);
+ need[chip] = 1;
+ } else
+ cnt++;
+ }
+ }
+
+ if(erase_all_read_fail)//update bbt in nand when erase all include read fail blocks
+ update_bbt_inflash(nand,0,chip);
+ }
+ for (chip = 0; chip < nand->numchips; chip++) {
+ if (need[chip]) {
+ printf("update bbt to nand chip%d..... \n", chip);
+ rc = nand->update_table_inflash(nand, 0, chip);
+ if (rc) {
+ printf("failed\n");
+ NAND_DISABLE_CE(nand);
+ return rc;
+ }
+ printf("success\n");
+ }
+ }
+// printf("Erase success %d failed %d\n", cnt, cnt1);
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+
+int eslc_nand_write_block(struct nand_chip *nand, unsigned int start, unsigned int page, unsigned int page_count, unsigned char *oob)
+{
+ unsigned int i = 0;
+ unsigned int addr = start;
+ int rc = -1;
+ int page1;
+ unsigned int page_mod = page%(nand->dwPageCount/2);
+
+ page = page - page_mod;
+ //printf("start = %x page = %d, page_count = %d\n", start, page, page_count);
+ if (oob) {
+ if (nand->oobsize == 128) {
+ pNFCRegs->NFCRd |= HIGH64FIFO;
+ for (i = 0; i < 64; i++)
+ pNFCRegs->FIFO[i] = oob[64+i];
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ for (i = 0; i < 64; i++)
+ pNFCRegs->FIFO[i] = oob[i];
+ } else if (nand->oobsize > 64) {
+ for (i = 0; i < 64; i++)
+ pNFCRegs->FIFO[i] = oob[i];
+ } else {
+ for (i = 0; i < nand->oobsize; i++)
+ pNFCRegs->FIFO[i] = oob[i];
+ }
+ } else {
+ for (i = 0; i < 64; i++)
+ pNFCRegs->FIFO[i] = 0xff;
+ }
+
+ i = 0;
+ while(i < page_count){
+#ifdef WMT_SW_RDMZ
+ if(nand->dwRdmz) {
+ memcpy((void*)rdmz_buf, (void*)addr, nand->oobblock);
+ *(unsigned int *)&pNFCRegs->FIFO[20] = wmt_rdmz;
+ rdmzier(rdmz_buf, nand->oobblock/4, page+eslc_map_table[page_mod]);
+ rdmzier_oob((uint8_t *)pNFCRegs->FIFO, (uint8_t *)pNFCRegs->FIFO, 6, page + eslc_map_table[page_mod], nand->oobblock/4);
+ //printf("write page: %d\n", page + eslc_map_table[i]);
+ rc = nand_page_program(nand, page+ eslc_map_table[page_mod], (unsigned int)rdmz_buf, nand->oobblock);
+ }
+#else
+ if (nand->realplanenum) {//Henry add
+ page1 = page + eslc_map_table[page_mod];
+ page1 = (page1 / nand->dwPageCount) * nand->dwPageCount + page1;
+ //printf("i=%d,page1=%d\n",i,page1);//Henry test
+ if (nand->dwECCBitNum == 60)
+ rc = nand_page_program_multi_60bit(nand, page1, addr, nand->oobblock_valid, 0/*oob_offs*/);
+ else
+ rc = nand_page_program_multi(nand, page1, addr, nand->oobblock, 0/*oob_offs*/);
+ } else
+ rc = nand_page_program(nand, page+ eslc_map_table[page_mod], (unsigned int)addr, nand->oobblock);
+
+#endif
+ if (rc < 0 || rc & 0x01)
+ return rc;
+ i++;
+ page_mod++;
+ addr = addr + (nand->oobblock_valid << (nand->realplanenum ? 1 : 0));
+ }
+
+ return 0;
+}
+
+int nand_write_block(
+struct nand_chip *nand,
+unsigned int start,
+unsigned int page,
+unsigned int page_count,
+unsigned char *oob,
+int oob_offs)
+{
+ unsigned int i = 0, j;
+ unsigned int addr = start;
+ int rc = -1;
+ unsigned int *FIFO = (unsigned int *)pNFCRegs->FIFO;
+ unsigned int *OOB = (unsigned int *)oob;
+
+ if (oob) {
+ for (i = 0; i < 6; i++)
+ FIFO[i] = OOB[i];
+ } else {
+ if (!oob_offs)
+ for (i = 0; i < 6; i++)
+ FIFO[i] = 0xFFFFFFFF;
+ }
+
+ //printf("write data buf: 0x%x page=0x%x\n",addr,page);
+ //print_nand_buf((unsigned char *)addr,100);
+
+ /* printf("need %d pages\r\n",size); */
+ for (i = 0; i < page_count; i++) {
+ if (oob_offs) {
+ unsigned int *oob_addr = (unsigned int *)(addr + nand->oobblock_valid);
+ for (j = 0; j < 6; j++)
+ FIFO[j] = oob_addr[j];
+ }
+#ifdef WMT_SW_RDMZ
+ if (nand->dwRdmz == 1) {
+
+ if(i == 0){//do the pipeline when first page
+ memcpy_itp(rdmz_buf0, (unsigned char *)addr, nand->oobblock);
+ rdmzier2((uint8_t *)rdmz_buf0, nand->oobblock/4, page+i);
+ }
+
+ *(unsigned int *)&pNFCRegs->FIFO[20] = wmt_rdmz;
+ rdmzier_oob((uint8_t *)pNFCRegs->FIFO, (uint8_t *)pNFCRegs->FIFO, 6, page+i, nand->oobblock/4);
+
+ if(i == (page_count - 1) && i ==0) {//only one page
+ lastpage = 1;
+ }
+ else if(i == (page_count - 1)){ //last page
+ lastpage = 1;
+ }
+ else{ //not last page
+ lastpage = 0;
+ }
+
+ //printf("wr rdmz page=0x%x\n", page+i);
+ rc = nand_page_program2(nand, page+i, addr, nand->oobblock,oob_offs,i,lastpage);
+ } else
+#endif
+ /*write bbt use sw rdmz*/
+
+ if (nand->bbt_sw_rdmz && nand->dwRdmz) {
+ memcpy_itp(rdmz_buf, (unsigned char *)addr, nand->oobblock_valid);
+ rdmzier2((uint8_t *)rdmz_buf, nand->oobblock_valid/4, page+i);
+
+ *(unsigned int *)&pNFCRegs->FIFO[20] = wmt_rdmz;
+ rdmzier_oob((uint8_t *)pNFCRegs->FIFO, (uint8_t *)pNFCRegs->FIFO, 6, page+i, nand->oobblock_valid/4);
+
+ if (nand->dwECCBitNum == 60) {
+ //printf("nand_page_program_60bit! page=%d\n",page+i);
+ rc = nand_page_program_60bit(nand, page+i, (unsigned int)rdmz_buf, nand->oobblock_valid);
+ } else {
+ rc = nand_page_program(nand, page+i, (unsigned int)rdmz_buf, nand->oobblock);
+ }
+ } else {
+ if (nand->dwECCBitNum == 60) {
+ //printf("nand_page_program_60bit! page=%d\n",page+i);
+ rc = nand_page_program_60bit(nand, page+i, addr, nand->oobblock_valid);
+ } else {
+ rc = nand_page_program(nand, page+i, addr, nand->oobblock);
+ }
+ }
+
+ if (rc < 0 || rc & 0x01)
+ return rc;
+ /* printf("write to %x page%d\n",naddr,(naddr>>nand->page_shift)&0x3f); */
+ if (!r_w_check_ecc_robust)
+ addr = addr + nand->oobblock_valid+ oob_offs;
+ }
+
+ return 0;
+}
+
+int nand_write_block_multi(
+struct nand_chip *nand,
+unsigned int start,
+unsigned int page,
+unsigned int page_count,
+unsigned char *oob,
+int oob_offs)
+{
+ unsigned int i = 0, j,k;
+ unsigned int addr = start;
+ int rc = -1;
+ unsigned int *FIFO = (unsigned int *)pNFCRegs->FIFO;
+ unsigned int *OOB = (unsigned int *)oob;
+
+ if (oob) {
+ for (i = 0; i < 6; i++)
+ FIFO[i] = OOB[i];
+ } else {
+ if (!oob_offs)
+ for (i = 0; i < 6; i++)
+ FIFO[i] = 0xFFFFFFFF;
+ }
+
+ /* printf("need %d pages\r\n",size); */
+ for (i = 0, j = 0; i < page_count; i+=2,j++) {
+ if (oob_offs) {
+ unsigned int *oob_addr = (unsigned int *)(addr + nand->oobblock_valid*2);
+ for (k = 0; k < 6; k++)
+ FIFO[k] = oob_addr[k];
+ }
+#ifdef WMT_SW_RDMZ
+ if (nand->dwRdmz == 1) {
+
+ //memcpy_itp(rdmz_buf0, (unsigned char *)addr, nand->oobblock);
+ //memcpy_itp(rdmz_buf0 + nand->oobblock, (unsigned char *)addr + oob_offs + nand->oobblock, nand->oobblock);
+ rdmzier2((uint8_t *)addr, nand->oobblock/4, page+j);
+ rdmzier2((uint8_t *)addr + nand->oobblock + oob_offs, nand->oobblock/4, page+j + nand->dwPageCount);//2nd oobblock
+
+ //*(unsigned int *)&pNFCRegs->FIFO[20] = wmt_rdmz;
+ //rdmzier_oob((uint8_t *)pNFCRegs->FIFO, (uint8_t *)pNFCRegs->FIFO, 6, page+j, nand->oobblock/4);
+
+ //printf("wr rdmz page=0x%x\n", page+i);
+ //rc = nand_page_program2(nand, page+i, addr, nand->oobblock,oob_offs,i,lastpage);
+ rc = nand_page_program_multi(nand, page+j, addr, nand->oobblock, oob_offs);
+ } else
+#endif
+ if (nand->dwECCBitNum == 60)
+ rc = nand_page_program_multi_60bit(nand, page+j, addr, nand->oobblock_valid, oob_offs);
+ else
+ rc = nand_page_program_multi(nand, page+j, addr, nand->oobblock, oob_offs);
+
+ if (rc < 0 || rc & 0x01)
+ return rc;
+ /* printf("write to %x page%d\n",naddr,(naddr>>nand->page_shift)&0x3f); */
+ addr = addr + nand->oobblock_valid*2 + oob_offs;
+ }
+
+ return 0;
+}
+
+// Just read the half of one block for Hynix ESLC mode
+int eslc_nand_read_block(struct nand_chip *nand, unsigned int maddr, unsigned int page, unsigned int page_count)
+{
+ unsigned int i = 0;
+ unsigned int addr = maddr, page1;
+ int rc = -1;
+ int page_mod = page%(nand->dwPageCount/2);
+
+ page = page-page_mod;
+
+ while(i < page_count) {
+ if (nand->realplanenum) {
+ page1 = page + eslc_map_table[page_mod];
+ page1 = (page1 / nand->dwPageCount) * nand->dwPageCount + page1;
+ rc = wmt_multi_plane_read(nand, page1, addr, nand->oobblock_valid, 0, 0);
+ } else
+ rc = nand->nfc_read_page(nand, page + eslc_map_table[page_mod], addr, nand->oobblock);
+ if (rc) {
+ printf("Err1 at page 0x%x\n", page + eslc_map_table[page_mod]);
+ return rc;
+ }
+ i++;
+ page_mod++;
+ addr = addr + (nand->oobblock_valid << (nand->realplanenum ? 1 : 0));
+ }
+
+ return 0;
+}
+
+int nand_read_block(struct nand_chip *nand, unsigned int maddr, unsigned int page, unsigned int page_count)
+{
+ unsigned int i = 0;
+ unsigned int addr = maddr;
+ int rc = -1;
+
+ for (i = 0; i < page_count; i++) {
+
+ if (nand->dwECCBitNum ==60) {
+ //printf("nfc_BCH_read_page_60bit! page=%d\n",page+i);
+ rc = nfc_BCH_read_page_60bit(nand, page+i, addr, nand->oobblock_valid);
+ } else {
+ rc = nand->nfc_read_page(nand, page+i, addr, nand->oobblock);//@original
+ }
+
+ if (rc) {
+ printf("Read Err at page 0x%d\n", page+i);
+ return rc;
+ }
+ if (!r_w_check_ecc_robust)
+ addr = addr + nand->oobblock_valid;
+ }
+
+ //printf("read data buf: 0x%x page=0x%x\n",maddr,page);
+ //print_nand_buf((unsigned char *)maddr,100);
+
+ return 0;
+}
+
+int nand_read_block_multi(struct nand_chip *nand, unsigned int maddr, unsigned int page, unsigned int page_count)
+{
+ unsigned int i, j;
+ unsigned int addr = maddr;
+ int rc = -1, multi = (nand->realplanenum ? 2 : 1);
+
+ for (i = 0, j = 0; i < page_count; i+=2, j++) {
+ rc = wmt_multi_plane_read(nand, page+j, addr, nand->oobblock_valid, 0/*i*/, 0);
+ if (rc) {
+ printf("Read Err at page 0x%d\n", page+i);
+ return rc;
+ }
+ addr = addr + nand->oobblock_valid* multi;
+ }
+ return 0;
+}
+
+//eslc_save_image_tpi ---Henry add
+int eslc_save_image_tpi(struct nand_chip *nand, unsigned long long naddr, unsigned int dwImageStart, unsigned int dwImageLength)
+{
+ unsigned int maddr = dwImageStart;
+ unsigned int ret = dwImageLength;
+ unsigned int naddr_page;
+ unsigned int need[CFG_MAX_NAND_DEVICE], i = 0;
+ unsigned long chip, page_in_chip, len_in_page, page_count, left_page_in_blk, block_in_chip;
+ unsigned char fifo[64];
+ int rc = -1;
+
+ if (naddr >= nand->totlen || (naddr + ret) >= nand->totlen) {
+ printf("naddr=0x%llx is out of size\r\n", naddr);
+ return -2;
+ }
+
+ if (check_block_table(nand, 1)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+
+ naddr_page = naddr >> nand->page_shift;
+ len_in_page = ret/nand->oobblock + ((ret%nand->oobblock) ? 1 : 0);
+
+ printf("ESLC Save Image From NAND Flash page=0x%lx len 0x%x\r\n", naddr_page, len_in_page);
+
+ rc = set_ECC_mode(nand);
+ if (rc)
+ return -1;
+
+ for (i = 0; i < CFG_MAX_NAND_DEVICE; i++)
+ need[i] = 0;
+
+ while (1) {
+ chip = naddr_page / (nand->dwBlockCount * nand->dwPageCount);
+ page_in_chip = naddr_page % (nand->dwBlockCount * nand->dwPageCount);
+ block_in_chip = page_in_chip/(nand->dwPageCount);
+
+ if (chip >= nand->numchips) {
+ printf("no space for write chip%d, left pages=%d\n", chip, len_in_page);
+ break;
+ }
+
+ if (nand->isbadblock(nand, page_in_chip/nand->dwPageCount, chip)) {
+ naddr_page = naddr_page + nand->dwPageCount;
+ continue;
+ }
+ NAND_ENABLE_CE(nand, chip);
+ cur_chip->set_parameter(nand, ESLC_MODE, ECC_ERROR_VALUE);
+
+ rc = wmt_nand_erase(nand, block_in_chip);
+ if (rc < 0 || rc & 0x01) {
+ printf("Erase failed at chip%d block%d\n", block_in_chip);
+ //nand->update_table_inram(nand, block_in_chip, chip);
+ update_bbt_inram_set_w_e_badblk(nand , block_in_chip, chip);
+ naddr_page = naddr_page + nand->dwPageCount;// - (naddr_page%nand->dwPageCount);
+ need[chip] = 1;
+ continue;
+ }
+
+ left_page_in_blk = nand->dwPageCount/2 - page_in_chip%(nand->dwPageCount/2);
+ if (len_in_page >= (nand->dwPageCount/2))
+ page_count = (naddr_page%(nand->dwPageCount/2)) ? left_page_in_blk : nand->dwPageCount/2;
+ else
+ page_count = (len_in_page < left_page_in_blk) ? len_in_page : left_page_in_blk;
+
+ printf("left_page_in_blk:%d, len_in_page = %d, page_count = %d, chip:%d, page_in_chip:%d, block_chip:%d\n", left_page_in_blk, len_in_page, page_count, chip, page_in_chip, block_in_chip);
+ memset(fifo, 0xff, 64);
+ rc = eslc_nand_write_block(nand, maddr, page_in_chip, page_count, fifo);
+ if (rc) {
+ printf("Write block failed at chip%d page%d\n", chip, page_in_chip);
+ //nand->update_table_inram(nand, block_in_chip, chip);
+ update_bbt_inram_set_w_e_badblk(nand , block_in_chip, chip);
+ naddr_page = naddr_page + nand->dwPageCount;
+ need[chip] = 1;
+ continue;
+ }
+
+ maddr = maddr + page_count * nand->oobblock;
+ if(page_count == (nand->dwPageCount/2))
+ naddr_page = naddr_page + nand->dwPageCount;
+ else
+ naddr_page = naddr_page + page_count + nand->dwPageCount/2;
+ len_in_page -= page_count;
+
+ if (!len_in_page) {
+ printf("\r\n write NAND Flash OK\r\n");
+ break;
+ }
+ }
+ for (i = 0; i < nand->numchips; i++) {
+ if (need[i]) {
+ printf("update bbt to nand chip%d ...", i);
+ NAND_ENABLE_CE(nand, chip);
+ rc = nand->update_table_inflash(nand, 0, chip);
+ if (rc) {
+ printf("failed\n");
+ NAND_DISABLE_CE(nand);
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+ return rc;
+ }
+ printf("success\n");
+ }
+ }
+ printf("\r\nWrite To NAND Flash OK\r\n");
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+// cur_chip->get_parameter(nand, ESLC_MODE);
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+
+
+// Just use the half of one block to save the data for Hynix ESLC mode
+int eslc_save_image(struct nand_chip *nand, unsigned long long naddr, unsigned int dwImageStart, unsigned int dwImageLength)
+{
+ unsigned int maddr = dwImageStart;
+ unsigned int ret = dwImageLength;
+ unsigned int need[CFG_MAX_NAND_DEVICE], i = 0;
+ unsigned long chip, page_in_chip, len_in_page, page_count, left_page_in_blk, block_in_chip;
+ unsigned char fifo[64];
+ int rc = -1;
+ unsigned int eslcpage_mod, eslcpage_base, block_ofs, base_page = 0, base_page_end = 0, good_blk = 0, page_eslc;
+ unsigned int naddr_page = naddr >> nand->page_shift;
+ unsigned int size_page = ret >nand->dwPageSize ? ret >> nand->page_shift:1;
+ unsigned int base_blk, base_blk_end;
+
+
+ if(naddr_page < boot_base/4) {
+ if((naddr_page + size_page) >= (boot_base/8)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than logo0 partition end 0x%x\n", naddr_page + size_page, boot_base/8);
+ //ret = (boot_base/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = logo_base;
+ base_page_end = boot_base/4;
+ } else if(naddr_page < boot_base) {
+ if((naddr_page + size_page) >= (boot_base*3/8)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than logo1 partition end 0x%x\n", naddr_page + size_page, boot_base*3/8);
+ //ret = (boot_base/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = boot_base/4;
+ base_page_end = boot_base;
+ } else if(naddr_page < recovery_base) {
+ if((naddr_page + size_page) >= ((recovery_base+boot_base)/2)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than boot partition end 0x%x\n", naddr_page + size_page, (recovery_base+boot_base)/2);
+ //ret = ((recovery_base+boot_base)/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = boot_base;
+ base_page_end = recovery_base;
+ } else if(naddr_page < misc_base) {
+ if((naddr_page + size_page) >= ((misc_base + recovery_base)/2)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than recovery partition end 0x%x\n", naddr_page + size_page, (misc_base + recovery_base)/2);
+ //ret = ((misc_base + recovery_base)/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = recovery_base;
+ base_page_end = misc_base;
+ } else if(naddr_page < misc_end) {
+ if((naddr_page + size_page) >= ((misc_end+misc_base)/2)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than misc partition end 0x%x\n", naddr_page + size_page, (misc_end+misc_base)/2);
+ //ret = ((misc_end+misc_base)/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = misc_base;
+ base_page_end = misc_end;
+ }
+
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+
+ eslcpage_mod = naddr_page % nand->dwPageCount;
+ eslcpage_base = naddr_page - eslcpage_mod;
+ base_blk = base_page/nand->dwPageCount;
+ base_blk_end = base_page_end/nand->dwPageCount;
+ block_ofs = (eslcpage_base - base_page)/nand->dwPageCount;
+ if(eslcpage_mod >= (nand->dwPageCount/2))
+ block_ofs = block_ofs*2 + 1;
+ else
+ block_ofs = block_ofs*2;
+
+ for (i = base_blk; i < base_blk_end; i++) {
+ rc = nand->isbadblock(nand, i, 0);
+ //printf("rc = %d, i = %d data_size=0x%x\n", rc, i, ret);
+ if (rc) {
+ printf("write skip bad blk %d", i);
+ continue;
+ } else {
+ if (eslcpage_mod == 0 || eslcpage_mod == (nand->dwPageCount/2))
+ good_blk++;
+ }
+ if (good_blk >= (block_ofs + 1)) {
+ break;
+ }
+ }
+ if (i >= base_blk_end) {
+ printf("So many bad block and out of partition size, base_blk_end:0x%x, i = %d\n", base_blk_end, i);
+ return -1;
+ }
+ block_ofs = i * nand->dwPageCount;
+
+ page_eslc = block_ofs + eslc_map_table[(eslcpage_mod%(nand->dwPageCount/2))];
+
+ len_in_page = ret/nand->oobblock + ((ret%nand->oobblock) ? 1 : 0);
+
+ printf("ESLC Save Image From NAND Flash base=0x%x page=0x%lx, eslc page 0x%x len 0x%x\r\n", base_page, naddr_page, page_eslc, len_in_page);
+
+ set_ECC_mode(nand);
+
+ for (i = 0; i < CFG_MAX_NAND_DEVICE; i++)
+ need[i] = 0;
+
+ while (1) {
+ chip = page_eslc / (nand->dwBlockCount * nand->dwPageCount);
+ page_in_chip = page_eslc % (nand->dwBlockCount * nand->dwPageCount);
+ block_in_chip = page_in_chip/(nand->dwPageCount);
+
+ if (chip >= nand->numchips) {
+ printf("no space for write chip%d, left pages=%d\n", chip, len_in_page);
+ break;
+ }
+
+ if (nand->isbadblock(nand, page_in_chip/nand->dwPageCount, chip)) {
+ page_eslc = page_eslc + nand->dwPageCount;
+ continue;
+ }
+ NAND_ENABLE_CE(nand, chip);
+ cur_chip->set_parameter(nand, ESLC_MODE, ECC_ERROR_VALUE);
+
+ rc = wmt_nand_erase(nand, block_in_chip);
+ if (rc < 0 || rc & 0x01) {
+ printf("Erase failed at chip%d block%d\n", block_in_chip);
+ nand->update_table_inram(nand, block_in_chip, chip);
+ page_eslc = page_eslc + nand->dwPageCount;// - (page_eslc%nand->dwPageCount);
+ need[chip] = 1;
+ continue;
+ }
+
+ left_page_in_blk = nand->dwPageCount/2 - page_in_chip%(nand->dwPageCount/2);
+ if (len_in_page >= (nand->dwPageCount/2))
+ page_count = (page_eslc%(nand->dwPageCount/2)) ? left_page_in_blk : nand->dwPageCount/2;
+ else
+ page_count = (len_in_page < left_page_in_blk) ? len_in_page : left_page_in_blk;
+
+ printf("left_page_in_blk:%d, len_in_page = %d, page_count = %d, chip:%d, page_in_chip:%d, block_chip:%d\n", left_page_in_blk, len_in_page, page_count, chip, page_in_chip, block_in_chip);
+ memset(fifo, 0xff, 64);
+ rc = eslc_nand_write_block(nand, maddr, page_in_chip, page_count, fifo);
+ if (rc) {
+ printf("Write block failed at chip%d page%d\n", chip, page_in_chip);
+ nand->update_table_inram(nand, block_in_chip, chip);
+ page_eslc = page_eslc + nand->dwPageCount;
+ need[chip] = 1;
+ continue;
+ }
+
+ maddr = maddr + page_count * nand->oobblock;
+ if(page_count == (nand->dwPageCount/2))
+ page_eslc = page_eslc + nand->dwPageCount;
+ else
+ page_eslc = page_eslc + page_count + nand->dwPageCount/2;
+ len_in_page -= page_count;
+
+ if (!len_in_page) {
+ printf("\r\n write NAND Flash OK\r\n");
+ break;
+ }
+ }
+ for (i = 0; i < nand->numchips; i++) {
+ if (need[i]) {
+ printf("update bbt to nand chip%d ...", i);
+ NAND_ENABLE_CE(nand, chip);
+ rc = nand->update_table_inflash(nand, 0, chip);
+ if (rc) {
+ printf("failed\n");
+ NAND_DISABLE_CE(nand);
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+ return rc;
+ }
+ printf("success\n");
+ }
+ }
+ printf("\r\nWrite To NAND Flash OK\r\n");
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+// cur_chip->get_parameter(nand, ESLC_MODE);
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+#if 0
+// Just use the half of one block to save the data for Hynix ESLC mode
+int eslc_save_image_multi(struct nand_chip *nand, unsigned long long naddr, unsigned int dwImageStart, unsigned int dwImageLength)
+{
+ unsigned int maddr = dwImageStart;
+ unsigned int ret = dwImageLength;
+ unsigned int need[CFG_MAX_NAND_DEVICE], i = 0;
+ unsigned long chip, page_in_chip, len_in_page, page_count, left_page_in_blk, block_in_chip;
+ unsigned char fifo[64];
+ int rc = -1;
+ unsigned int eslcpage_mod, eslcpage_base, block_ofs, base_page = 0, base_page_end = 0, good_blk = 0, page_eslc;
+ unsigned int naddr_page, page = naddr >> nand->page_shift;
+ unsigned int size_page = ret >nand->dwPageSize ? ret >> nand->page_shift:1;
+ unsigned int base_blk, base_blk_end;
+ unsigned int logic_oobblock, logic_blkCnt;//, logic_page_in_chip, logic_page_count;
+
+ if(naddr_page < boot_base/4) {
+ if((naddr_page + size_page) >= (boot_base/8)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than logo0 partition end 0x%x\n", naddr_page + size_page, boot_base/8);
+ //ret = (boot_base/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = logo_base;
+ base_page_end = boot_base/4;
+ } else if(naddr_page < boot_base) {
+ if((naddr_page + size_page) >= (boot_base*3/8)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than logo1 partition end 0x%x\n", naddr_page + size_page, boot_base*3/8);
+ //ret = (boot_base/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = boot_base/4;
+ base_page_end = boot_base;
+ } else if(naddr_page < recovery_base) {
+ if((naddr_page + size_page) >= ((recovery_base+boot_base)/2)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than boot partition end 0x%x\n", naddr_page + size_page, (recovery_base+boot_base)/2);
+ //ret = ((recovery_base+boot_base)/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = boot_base;
+ base_page_end = recovery_base;
+ } else if(naddr_page < misc_base) {
+ if((naddr_page + size_page) >= ((misc_base + recovery_base)/2)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than recovery partition end 0x%x\n", naddr_page + size_page, (misc_base + recovery_base)/2);
+ //ret = ((misc_base + recovery_base)/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = recovery_base;
+ base_page_end = misc_base;
+ } else if(naddr_page < misc_end) {
+ if((naddr_page + size_page) >= ((misc_end+misc_base)/2)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than misc partition end 0x%x\n", naddr_page + size_page, (misc_end+misc_base)/2);
+ //ret = ((misc_end+misc_base)/2 - naddr_page) << nand->page_shift;
+ return -1;
+ }
+ base_page = misc_base;
+ base_page_end = misc_end;
+ }
+
+ logic_oobblock = nand->oobblock*2;
+ logic_blkCnt = nand->dwBlockCount/2;
+
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+
+ if ((naddr_page/nand->dwPageCount)%2) {
+ naddr_page -= nand->dwPageCount;
+ printf("address is directed to plane 0 page=0x%x\n", naddr_page);
+ }
+
+ naddr_page = page >> 1; // naddr_page is logical address.
+ if ((naddr_page % nand->dwPageCount)) {
+ printf("Error: wrong parameter, Just support 0 page start.\n");
+ return -1;
+ }
+ base_page = naddr_page;
+ base_page_end = (nand->dwBlockCount - 8) * nand->dwPageCount;
+
+ eslcpage_mod = naddr_page % nand->dwPageCount;
+ eslcpage_base = naddr_page - eslcpage_mod;
+ base_blk = base_page/nand->dwPageCount;
+ base_blk_end = base_page_end/nand->dwPageCount;
+ block_ofs = (eslcpage_base - base_page)/nand->dwPageCount;
+ if (eslcpage_mod >= (nand->dwPageCount/2))
+ block_ofs = block_ofs*2 + 1;
+ else
+ block_ofs = block_ofs*2;
+
+ for (i = base_blk; i < base_blk_end; i++) {
+ rc = nand->isbadblock(nand, 2*i, 0);
+ //printf("rc = %d, i = %d data_size=0x%x\n", rc, i, ret);
+ if (rc) {
+ printf("write skip bad blk %d", 2*i);
+ continue;
+ }
+ rc = nand->isbadblock(nand, (2*i)+1, 0);
+ //printf("rc = %d, i = %d data_size=0x%x\n", rc, i, ret);
+ if (rc) {
+ printf("write skip bad blk %d", (2*i)+1);
+ continue;
+ }
+ if (eslcpage_mod == 0 || eslcpage_mod == (nand->dwPageCount/2))
+ good_blk++;
+
+ if (good_blk >= (block_ofs + 1)) {
+ break;
+ }
+ }
+ if (i >= base_blk_end) {
+ printf("So many bad block and out of partition size, base_blk_end:0x%x, i = %d\n", base_blk_end, i);
+ return -1;
+ }
+ block_ofs = i * nand->dwPageCount;
+
+ page_eslc = block_ofs + eslc_map_table[(eslcpage_mod%(nand->dwPageCount/2))];
+ len_in_page = ret/nand->oobblock + ((ret%nand->oobblock) ? 1 : 0);
+ printf("ESLC Save Image From NAND Flash base=0x%x page=0x%lx, eslc page 0x%x len 0x%x\r\n", base_page, naddr_page, page_eslc, len_in_page);
+
+ set_ECC_mode(nand);
+
+ for (i = 0; i < CFG_MAX_NAND_DEVICE; i++)
+ need[i] = 0;
+
+ while (1) {
+ chip = page_eslc / (nand->dwBlockCount * nand->dwPageCount);
+ page_in_chip = page_eslc % (nand->dwBlockCount * nand->dwPageCount);
+ block_in_chip = page_in_chip/(nand->dwPageCount);
+
+ if (chip >= nand->numchips) {
+ printf("no space for write chip%d, left pages=%d\n", chip, len_in_page);
+ break;
+ }
+
+ if (nand->isbadblock(nand, page_in_chip/nand->dwPageCount, chip)) {
+ page_eslc = page_eslc + nand->dwPageCount;
+ continue;
+ }
+ NAND_ENABLE_CE(nand, chip);
+ cur_chip->set_parameter(nand, ESLC_MODE, ECC_ERROR_VALUE);
+
+ rc = wmt_nand_erase(nand, block_in_chip);
+ if (rc < 0 || rc & 0x01) {
+ printf("Erase failed at chip%d block%d\n", block_in_chip);
+ nand->update_table_inram(nand, block_in_chip, chip);
+ page_eslc = page_eslc + nand->dwPageCount;// - (page_eslc%nand->dwPageCount);
+ need[chip] = 1;
+ continue;
+ }
+
+ left_page_in_blk = nand->dwPageCount/2 - page_in_chip%(nand->dwPageCount/2);
+ if (len_in_page >= (nand->dwPageCount/2))
+ page_count = (page_eslc%(nand->dwPageCount/2)) ? left_page_in_blk : nand->dwPageCount/2;
+ else
+ page_count = (len_in_page < left_page_in_blk) ? len_in_page : left_page_in_blk;
+
+ printf("left_page_in_blk:%d, len_in_page = %d, page_count = %d, chip:%d, page_in_chip:%d, block_chip:%d\n", left_page_in_blk, len_in_page, page_count, chip, page_in_chip, block_in_chip);
+ memset(fifo, 0xff, 64);
+ rc = eslc_nand_write_block(nand, maddr, page_in_chip, page_count, fifo);
+ if (rc) {
+ printf("Write block failed at chip%d page%d\n", chip, page_in_chip);
+ nand->update_table_inram(nand, block_in_chip, chip);
+ page_eslc = page_eslc + nand->dwPageCount;
+ need[chip] = 1;
+ continue;
+ }
+
+ maddr = maddr + page_count * nand->oobblock;
+ if(page_count == (nand->dwPageCount/2))
+ page_eslc = page_eslc + nand->dwPageCount;
+ else
+ page_eslc = page_eslc + page_count + nand->dwPageCount/2;
+ len_in_page -= page_count;
+
+ if (!len_in_page) {
+ printf("\r\n write NAND Flash OK\r\n");
+ break;
+ }
+ }
+ for (i = 0; i < nand->numchips; i++) {
+ if (need[i]) {
+ printf("update bbt to nand chip%d ...", i);
+ NAND_ENABLE_CE(nand, chip);
+ rc = nand->update_table_inflash(nand, 0, chip);
+ if (rc) {
+ printf("failed\n");
+ NAND_DISABLE_CE(nand);
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+ return rc;
+ }
+ printf("success\n");
+ }
+ }
+ printf("\r\nWrite To NAND Flash OK\r\n");
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+// cur_chip->get_parameter(nand, ESLC_MODE);
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+#endif
+// Just use the half of one block to save the data for Hynix ESLC mode
+int eslc_save_image_tpi_multi(struct nand_chip *nand, unsigned long long naddr, unsigned int dwImageStart, unsigned int dwImageLength)
+{
+ unsigned int maddr = dwImageStart;
+ unsigned int size = dwImageLength;
+ int rc = -1, len_in_logic_page;
+ unsigned int need[CFG_MAX_NAND_DEVICE], i = 0;
+ unsigned long page, chip, left_page_in_blk;
+ unsigned int logic_page, logic_page_in_chip, logic_page_count, logic_oobblock, logic_blkCnt;
+ int need_erase;
+ unsigned char fifo[64];
+
+ logic_oobblock = nand->oobblock_valid*2;
+ logic_blkCnt = nand->dwBlockCount/2;
+
+ if (naddr >= nand->totlen || (naddr + size) >= nand->totlen) {
+ printf("naddr=0x%llx is out of size\r\n", naddr);
+ return -2;
+ }
+
+ if (check_block_table(nand, 1)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+
+ //page = (unsigned long)(naddr>>nand->page_shift);
+ page = (unsigned long)((naddr>>nand->page_shift)/nand->oobblock_K);//For 60bit edit: "/nand->oobblock_K "
+
+ if ((page/nand->dwPageCount)%2) {
+ page -= nand->dwPageCount;
+ printf("address is directed to plane 0 page=0x%x\n", page);
+ }
+
+ logic_page = (page>>1) + (page%nand->dwPageCount);
+/* if((logic_page % nand->dwPageCount)) {
+ printf("Error: wrong parameter, Just support 0 page start.\n");
+ return -1;
+ }*/
+ len_in_logic_page = size/logic_oobblock + ((size%logic_oobblock) ? 1 : 0);
+ printf("ESLC Save Image From NAND Flash page=0x%lx\r\n", logic_page);
+
+ rc = set_ECC_mode(nand);
+ if (rc)
+ return -1;
+
+
+ while (1) {
+ chip = logic_page / (logic_blkCnt * nand->dwPageCount);
+ logic_page_in_chip = logic_page % (logic_blkCnt * nand->dwPageCount);
+
+ if (chip >= nand->numchips) {
+ printf("no space for write chip%d\n", chip);
+ break;
+ }
+
+ if (nand->isbadblock(nand, (logic_page_in_chip/nand->dwPageCount)*2, chip)) {
+ logic_page = logic_page + nand->dwPageCount - (logic_page_in_chip%nand->dwPageCount);
+ continue;
+ }
+ if (nand->isbadblock(nand, (logic_page_in_chip/nand->dwPageCount)*2+1, chip)) {
+ logic_page = logic_page + nand->dwPageCount - (logic_page_in_chip%nand->dwPageCount);
+ continue;
+ }
+
+ left_page_in_blk = (nand->dwPageCount/2) - logic_page_in_chip%((nand->dwPageCount/2));
+
+ if (len_in_logic_page >= (nand->dwPageCount/2))
+ logic_page_count = (logic_page%(nand->dwPageCount/2)) ? left_page_in_blk : ((nand->dwPageCount/2));
+ else
+ logic_page_count = (len_in_logic_page < left_page_in_blk) ? len_in_logic_page : left_page_in_blk;
+
+ /*printf("left_page_in_blk:%d, len_in_logic_page = %d, logic_page_count = %d, chip:%d, logic_page_in_chip:%d\n",
+ left_page_in_blk, len_in_logic_page, logic_page_count, chip, logic_page_in_chip);*/
+
+ NAND_ENABLE_CE(nand, chip);
+
+ cur_chip->set_parameter(nand, ESLC_MODE, ECC_ERROR_VALUE);
+
+ need_erase=1;
+ if (need_erase) {
+
+ rc = wmt_nand_erase_multi(nand, (logic_page_in_chip/nand->dwPageCount)*2);//fix : add return status which block really fail.
+
+ if (rc < 0 || rc & 0x01) {
+ printf("Erase failed at chip%d block%d\n", (logic_page_in_chip/nand->dwPageCount)*2);
+
+ //nand->update_table_inram(nand, (logic_page_in_chip/nand->dwPageCount)*2, chip);
+ //nand->update_table_inram(nand, (logic_page_in_chip/nand->dwPageCount)*2+1, chip);//fix : mark for really fail block.
+ update_bbt_inram_set_w_e_badblk(nand , (logic_page_in_chip/nand->dwPageCount)*2, chip);
+ update_bbt_inram_set_w_e_badblk(nand , (logic_page_in_chip/nand->dwPageCount)*2+1, chip);
+
+ logic_page = logic_page + nand->dwPageCount - (logic_page_in_chip%nand->dwPageCount);
+ need[chip] = 1;
+ continue;
+ }
+ }
+
+ left_page_in_blk = (nand->dwPageCount/2) - logic_page_in_chip%((nand->dwPageCount/2));
+
+ if (len_in_logic_page >= (nand->dwPageCount/2))
+ logic_page_count = (logic_page%(nand->dwPageCount/2)) ? left_page_in_blk : ((nand->dwPageCount/2));
+ else
+ logic_page_count = (len_in_logic_page < left_page_in_blk) ? len_in_logic_page : left_page_in_blk;
+
+ /*printf("left_page_in_blk:%d, len_in_logic_page = %d, logic_page_count = %d, chip:%d, logic_page_in_chip:%d\n",
+ left_page_in_blk, len_in_logic_page, logic_page_count, chip, logic_page_in_chip);*/
+
+
+ memset(fifo, 0xff, 64);
+
+
+ rc = eslc_nand_write_block(nand, maddr, logic_page_in_chip, logic_page_count, fifo);
+
+
+ if (rc) {
+ printf("Write block failed at chip%d logic page%d\n", chip, logic_page_in_chip);
+ //nand->update_table_inram(nand, (logic_page_in_chip/nand->dwPageCount)*2, chip);
+ //nand->update_table_inram(nand, (logic_page_in_chip/nand->dwPageCount)*2+1, chip);
+ update_bbt_inram_set_w_e_badblk(nand , (logic_page_in_chip/nand->dwPageCount)*2, chip);
+ update_bbt_inram_set_w_e_badblk(nand , (logic_page_in_chip/nand->dwPageCount)*2+1, chip);
+
+ logic_page = logic_page + nand->dwPageCount - (logic_page_in_chip%nand->dwPageCount);
+ need[chip] = 1;
+ continue;
+ }
+
+ maddr = maddr + logic_page_count * logic_oobblock;
+ if (logic_page_count == (nand->dwPageCount/2))
+ logic_page = logic_page + nand->dwPageCount;
+ else
+ logic_page = logic_page + logic_page_count;
+ len_in_logic_page -= logic_page_count;
+
+ if (len_in_logic_page <= 0) {
+ printf("\r\nwrite NAND Flash OK\r\n");
+ return 0;
+ }
+
+ }
+
+ for (i = 0; i < nand->numchips; i++) {
+ if (need[i]) {
+ printf("update bbt to nand chip%d ...", i);
+ NAND_ENABLE_CE(nand, chip);
+ rc = nand->update_table_inflash(nand, 0, chip);
+ if (rc) {
+ printf("failed\n");
+ NAND_DISABLE_CE(nand);
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+ return rc;
+ }
+ printf("success\n");
+ }
+ }
+
+ printf("\r\nWrite To NAND Flash OK\r\n");
+
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+
+// cur_chip->get_parameter(nand, ESLC_MODE);
+ NAND_DISABLE_CE(nand);
+ return 0;
+}
+int WMTAccessNandEarier(unsigned long long naddr, unsigned int maddr, unsigned int size, int write)
+{
+ int mode = !!write;
+ if(nand_dev_desc[0].ChipID == NAND_ChipID_UNKNOWN) {
+ nand_probe(0xd8009000);
+ }
+
+ if(mode == NAND_WRITE) {
+ return WMTSaveImageToNAND(nand_dev_desc + curr_device, naddr, maddr, size, 0, 1);
+ } else {
+ return WMTLoadImageFormNAND(nand_dev_desc + curr_device, naddr, maddr, size);
+ }
+}
+
+int WMTSaveImageToNAND(
+ struct nand_chip *nand,
+ unsigned long long naddr,
+ unsigned int dwImageStart,
+ unsigned int dwImageLength,
+ int oob_offs,
+ int need_erase
+ )
+{
+ return WMTSaveImageToNAND2(nand, naddr, dwImageStart, dwImageLength, oob_offs, need_erase, NULL);
+}
+
+int WMTSaveImageToNAND2(
+ struct nand_chip *nand,
+ unsigned long long naddr,
+ unsigned int dwImageStart,
+ unsigned int dwImageLength,
+ int oob_offs,
+ unsigned int need_erase, unsigned long long *eaddr
+ )
+{
+ unsigned int maddr = dwImageStart;
+ unsigned int ret = dwImageLength;
+ unsigned int need[CFG_MAX_NAND_DEVICE], i;
+ unsigned long page, chip, page_in_chip,
+ page_count, left_page_in_blk, block_in_chip;
+ //unsigned char fifo[64];
+ int rc = -1, multi = 1, len_in_page;
+ unsigned int naddr_page;
+ //unsigned int naddr_page = naddr >> nand->page_shift;
+ //unsigned int size_page = ret > nand->dwPageSize? ret >> nand->page_shift : 1;
+
+
+ if(nand->dwECCBitNum == 60)
+ naddr_page = naddr/nand->oobblock_K>>10;
+ else
+ naddr_page = naddr >> nand->page_shift;
+ if(!cur_chip)
+ printf("cur_chip not exist!\n");
+ if (cur_chip && nand->mfr == NAND_HYNIX && !do_page_rw && naddr_page < misc_end) { //Henry mark cur_chip
+ if (nand->realplanenum)
+ ret = eslc_save_image_tpi_multi(nand, naddr, maddr, ret);
+ else
+ ret = eslc_save_image_tpi(nand, naddr, maddr, ret);
+ disable_hw_rdmz(nand);
+ return ret;
+ }
+
+ if(eaddr != NULL) *eaddr = naddr;
+
+ if (naddr >= nand->totlen || (naddr + ret) >= nand->totlen) {
+ printf("naddr=0x%llx is out of size\r\n", naddr);
+ disable_hw_rdmz(nand);
+ return -2;
+ }
+
+ if (check_block_table(nand, 1)) {
+ NAND_DISABLE_CE(nand);
+ disable_hw_rdmz(nand);
+ return -1;
+ }
+
+ enable_hw_rdmz(nand);
+
+ page = (unsigned long)((naddr>>nand->page_shift)/nand->oobblock_K);//For 60bit edit: "/nand->oobblock_K "
+
+ if (nand->realplanenum && !do_page_rw) {
+ len_in_page = ret/(nand->oobblock_valid*2 + oob_offs) + ((ret%(nand->oobblock_valid*2 + oob_offs)) ? 1 : 0);
+ len_in_page = len_in_page<<1;
+ } else {
+ len_in_page = ret/(nand->oobblock_valid + oob_offs) + ((ret%(nand->oobblock_valid+ oob_offs)) ? 1 : 0);//For 60bit edit: "oobblock_valid"
+ }
+
+ set_ECC_mode(nand);
+ if (need_erase == 3) {
+ pNFCRegs->NFCRd |= RED_DIS;
+ printf("nfcrd=%x\n", pNFCRegs->NFCRd);
+ }
+ for (i = 0; i < CFG_MAX_NAND_DEVICE; i++)
+ need[i] = 0;
+
+ if (nand->realplanenum && !do_page_rw) {
+ multi = 2;
+ //page -= page%(nand->dwPageCount*multi);
+ if ((page/nand->dwPageCount)%2) {
+ page -= nand->dwPageCount;
+ printf("address is directed to plane 0 page=0x%x\n", page);
+ }
+ }
+
+ while (1) {
+ chip = page / (nand->dwBlockCount * nand->dwPageCount);
+ page_in_chip = page % (nand->dwBlockCount * nand->dwPageCount);
+ block_in_chip = page_in_chip/nand->dwPageCount;
+
+ if (chip >= nand->numchips) {
+ printf("no space for write chip%d, left pages=%d\n", chip, len_in_page);
+ break;
+ }
+
+ if (nand->isbadblock(nand, block_in_chip, chip) && !do_page_rw) {
+ page = page + nand->dwPageCount * multi - (page%nand->dwPageCount);
+ printf("*");
+ continue;
+ }
+ if (multi == 2 && nand->isbadblock(nand, block_in_chip + 1, chip)) {
+ page = page + nand->dwPageCount * multi - (page%nand->dwPageCount);
+ continue;
+ }
+
+ NAND_ENABLE_CE(nand, chip);
+ if (need_erase) {
+ if (multi == 2)
+ rc = wmt_nand_erase_multi(nand, block_in_chip);//fix : add return status which block really fail.
+ else
+ rc = wmt_nand_erase(nand, block_in_chip);
+ if (rc < 0 || rc & 0x01) {
+ printf("Erase failed at chip%d block%d\n", chip, block_in_chip);
+ //nand->update_table_inram(nand, block_in_chip, chip);
+ update_bbt_inram_set_w_e_badblk(nand , block_in_chip, chip);
+
+ if (multi == 2)
+ //nand->update_table_inram(nand, block_in_chip+1, chip);//fix : mark for really fail block.
+ update_bbt_inram_set_w_e_badblk(nand , block_in_chip+1, chip);
+ page = page + nand->dwPageCount * multi - (page%nand->dwPageCount);
+ need[chip] = 1;
+ continue;
+ }
+ }
+ left_page_in_blk = nand->dwPageCount * multi - page_in_chip%(nand->dwPageCount * multi);
+ if (len_in_page >= (nand->dwPageCount*multi))
+ page_count = (page%(nand->dwPageCount * multi)) ? left_page_in_blk : (nand->dwPageCount * multi);
+ else
+ page_count = (len_in_page < left_page_in_blk) ? len_in_page : left_page_in_blk;
+
+
+ // memset(fifo, 0xff, 64);
+
+ if (multi == 2) {
+ pNFCRegs->NFCR14 = 0x1212;
+ pNFCRegs->NFCR12 |= RD_DLY;
+ rc = nand_write_block_multi(nand, maddr, page_in_chip, page_count, NULL, oob_offs);
+ pNFCRegs->NFCR14 = 0x2424;
+ pNFCRegs->NFCR12 &= ~RD_DLY;
+ }else
+ rc = nand_write_block(nand, maddr, page_in_chip, page_count, NULL, oob_offs);
+
+ if (rc) {
+ printf("Write block failed at chip%d page%d\n", chip, page_in_chip);
+ //nand->update_table_inram(nand, block_in_chip, chip);
+ update_bbt_inram_set_w_e_badblk(nand , block_in_chip, chip);
+ if (multi == 2)
+ //nand->update_table_inram(nand, block_in_chip+1, chip);//fix : mark for really fail block.
+ update_bbt_inram_set_w_e_badblk(nand , block_in_chip+1, chip);
+ page = page + page_count;
+ need[chip] = 1;//Henry mark tmp
+ continue;
+ }
+ printf(".");
+ /*printf("write data from memory 0x%x to chip%d, page=0x%x, page count=0x%x\r\n",
+ maddr, chip, page_in_chip, page_count);
+ printf("len_in_page%d left_page_in_blk%d\n", len_in_page, left_page_in_blk);*/
+
+ if (multi == 2)
+ maddr = maddr + page_count * nand->oobblock_valid + (page_count*oob_offs)/2;
+ else
+ maddr = maddr + page_count * (nand->oobblock_valid+ oob_offs);//For 60bit edit: "oobblock_valid"
+
+ page = page + page_count;
+ len_in_page -= page_count;
+
+ if (len_in_page <= 0) {
+ printf("\r\n write NAND Flash OK\r\n");
+ break;
+ }
+ }
+ if(eaddr != NULL) {
+ if(nand->dwECCBitNum == 60)
+ *eaddr = ((unsigned long long)page)*nand->oobblock_K<<10;
+ else
+ *eaddr = ((unsigned long long)page)<<nand->page_shift;
+ }
+
+ for (i = 0; i < nand->numchips; i++) {
+ if (need[i]) {
+ printf("update bbt to nand chip%d ...", i);
+ NAND_ENABLE_CE(nand, chip);
+ rc = nand->update_table_inflash(nand, 0, chip);
+ if (rc) {
+ printf("failed\n");
+ NAND_DISABLE_CE(nand);
+ disable_hw_rdmz(nand);
+ pNFCRegs->NFCRd &= ~RED_DIS;
+ return rc;
+ }
+ printf("success\n");
+ }
+ }
+ pNFCRegs->NFCRd &= ~RED_DIS;
+ printf("\r\nWrite To NAND Flash OK\r\n");
+ NAND_DISABLE_CE(nand);
+ disable_hw_rdmz(nand);
+ return 0;
+}
+
+int eslc_load_image(struct nand_chip *nand, unsigned long long naddr, unsigned int maddr, unsigned int size)
+{
+ int rc = -1, len_in_page;
+ unsigned long chip, page_in_chip, page_count, left_page_in_blk;
+ unsigned long base_page = 0, base_page_end = 0, eslcpage_base, eslcpage_mod, page_eslc, block_ofs, base_blk, base_blk_end;
+ unsigned int naddr_page =naddr >> nand->page_shift;
+ unsigned int size_page = size >> nand->page_shift;
+ unsigned int i, good_blk = 0;
+
+ if(naddr_page < boot_base/4) {
+ if((naddr_page + size_page) >= (boot_base/8)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than logo0 partition end 0x%x\n", naddr_page + size_page, boot_base/8);
+ }
+ base_page = 0;
+ base_page_end = boot_base/4;
+ } else if(naddr_page < boot_base) {
+ if((naddr_page + size_page) >= (boot_base*3/8)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than logo1 partition end 0x%x\n", naddr_page + size_page, boot_base*3/8);
+ }
+ base_page = boot_base/4;
+ base_page_end = boot_base;
+ } else if(naddr_page < recovery_base) {
+ if((naddr_page + size_page) >= ((boot_base + recovery_base)/2)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than boot partition end 0x%x\n", naddr_page + size_page, (boot_base + recovery_base)/2);
+ }
+ base_page = boot_base;
+ base_page_end = recovery_base;
+ } else if(naddr_page < misc_base) {
+ if((naddr_page + size_page) >= ((recovery_base + misc_base)/2)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than recovery partition end 0x%x\n", naddr_page + size_page, (recovery_base + misc_base)/2);
+ }
+ base_page = recovery_base;
+ base_page_end = misc_base;
+ } else if(naddr_page < misc_end) {
+ if((naddr_page + size_page) >= ((misc_end+misc_base)/2)) {
+ printf("In ESLC MODE: nand address 0x%x is bigger than misc partition end 0x%x\n", naddr_page + size_page, (misc_end+misc_base)/2);
+ }
+ base_page = misc_base;
+ base_page_end = misc_end;
+ } else {
+ printf("In ESLC MODE: wrong nand parameter.\n");
+ return -1;
+ }
+
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+
+ eslcpage_mod = naddr_page % nand->dwPageCount;
+ eslcpage_base = naddr_page - eslcpage_mod;
+ base_blk = base_page/nand->dwPageCount;
+ base_blk_end = base_page_end/nand->dwPageCount;
+ block_ofs = (eslcpage_base - base_page)/nand->dwPageCount;
+ if(eslcpage_mod >= (nand->dwPageCount/2))
+ block_ofs = block_ofs*2 + 1;
+ else
+ block_ofs = block_ofs*2;
+
+ for (i = base_blk; i < base_blk_end; i++) {
+ rc = nand->isbadblock(nand, i, 0);
+ if (rc) {
+ printf("read skip bad blk %d\n", i);
+ continue;
+ } else {
+ good_blk++;
+ }
+ if (good_blk >= (block_ofs + 1)) {
+ break;
+ }
+ }
+ if (i >= base_blk_end) {
+ printf("out of partition size, skip page=0x%x read, base_page_end=%x\n", naddr_page, base_page_end);
+ return -1;
+ }
+ block_ofs = i * nand->dwPageCount;
+
+ page_eslc = block_ofs + eslc_map_table[(eslcpage_mod%(nand->dwPageCount/2))];
+ len_in_page = size/nand->oobblock + ((size%nand->oobblock) ? 1 : 0);
+ printf("ESLC Load Image From NAND Flash base=0x%x page=0x%lx, eslc page 0x%x len 0x%x\n", base_page, naddr_page, page_eslc, len_in_page);
+
+ rc = set_ECC_mode(nand);
+ if (rc)
+ return -1;
+
+ while (1) {
+ chip = page_eslc / (nand->dwBlockCount * nand->dwPageCount);
+ page_in_chip = page_eslc % (nand->dwBlockCount * nand->dwPageCount);
+
+ if (nand->isbadblock(nand, page_in_chip/nand->dwPageCount, chip)) {
+ page_eslc = page_eslc + nand->dwPageCount;// - (page_in_chip%nand->dwPageCount);
+ continue;
+ }
+
+ left_page_in_blk = nand->dwPageCount/2 - page_in_chip%(nand->dwPageCount/2);
+ if (len_in_page >= (nand->dwPageCount/2))
+ page_count = (page_eslc%(nand->dwPageCount/2)) ? left_page_in_blk : nand->dwPageCount/2;
+ else
+ page_count = (len_in_page < left_page_in_blk) ? len_in_page : left_page_in_blk;
+
+ //printf("left_page_in_blk:%d, len_in_page = %d, page_count = %d, chip:%d, page_in_chip:%d\n", left_page_in_blk, len_in_page, page_count, chip, page_in_chip);
+ printf(".");
+ NAND_ENABLE_CE(nand, chip);
+ rc = eslc_nand_read_block(nand, maddr, page_in_chip, page_count);
+ if (rc)
+ return rc;
+
+ maddr = maddr + page_count*nand->oobblock;
+ if(page_count == (nand->dwPageCount/2))
+ page_eslc = page_eslc + nand->dwPageCount;
+ else
+ page_eslc = page_eslc + page_count + nand->dwPageCount/2;
+ len_in_page -= page_count;
+
+ if (len_in_page <= 0) {
+ printf("\r\nRead NAND Flash OK\r\n");
+ NAND_DISABLE_CE(nand);
+ return 0;
+ }
+ }
+ NAND_DISABLE_CE(nand);
+ return -1;
+}
+
+int eslc_load_image_tpi(struct nand_chip *nand, unsigned long long naddr, unsigned int maddr, unsigned int size)
+{
+ int rc = -1, len_in_page;
+ unsigned long page, chip, page_in_chip,
+ page_count, left_page_in_blk;
+
+ if (naddr >= nand->totlen || (naddr + size) >= nand->totlen) {
+ printf("naddr=0x%llx is out of size\r\n", naddr);
+ return -2;
+ }
+ if (check_block_table(nand, 1)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+ page = (unsigned long)(naddr>>nand->page_shift);
+ if((page % nand->dwPageCount)) {
+ printf("Error: wrong parameter, Just support 0 page start.\n");
+ return -1;
+ }
+ len_in_page = size/nand->oobblock + ((size%nand->oobblock) ? 1 : 0);
+ printf("ESLC Load Image From NAND Flash page=0x%lx\r\n", page);
+
+ rc = set_ECC_mode(nand);
+ if (rc)
+ return -1;
+
+
+ while (1) {
+ chip = page / (nand->dwBlockCount * nand->dwPageCount);
+ page_in_chip = page % (nand->dwBlockCount * nand->dwPageCount);
+
+ if (nand->isbadblock(nand, page_in_chip/nand->dwPageCount, chip)) {
+ page = page + nand->dwPageCount - (page_in_chip%nand->dwPageCount);
+ continue;
+ }
+
+ left_page_in_blk = (nand->dwPageCount/2) - page_in_chip%((nand->dwPageCount/2));
+ if (len_in_page >= (nand->dwPageCount/2))
+ page_count = (page%(nand->dwPageCount/2)) ? left_page_in_blk : ((nand->dwPageCount/2));
+ else
+ page_count = (len_in_page < left_page_in_blk) ? len_in_page : left_page_in_blk;
+
+ /*printf("left_page_in_blk:%d, len_in_page = %d, page_count = %d, chip:%d, page_in_chip:%d\n", left_page_in_blk, len_in_page, page_count, chip, page_in_chip);*/
+ NAND_ENABLE_CE(nand, chip);
+ rc = eslc_nand_read_block(nand, maddr, page_in_chip, page_count);
+ if (rc) {
+ printf("Read Fail! Add block%d to bbt.\n",page_in_chip/nand->dwPageCount);
+
+ update_bbt_inram_set_r_badblk(nand , page_in_chip/nand->dwPageCount, chip);
+
+ update_bbt_inflash(nand,0,chip);
+
+ return rc;
+ }
+
+ maddr = maddr + page_count*nand->oobblock;
+ if(page_count == (nand->dwPageCount/2))
+ page = page + nand->dwPageCount;
+ else
+ page = page + page_count;
+ len_in_page -= page_count;
+
+ if (len_in_page <= 0) {
+ printf("\r\nRead NAND Flash OK\r\n");
+ NAND_DISABLE_CE(nand);
+ return 0;
+ }
+ }
+ NAND_DISABLE_CE(nand);
+ return -1;
+}
+
+
+int eslc_load_image_tpi_multi(struct nand_chip *nand, unsigned long long naddr, unsigned int maddr, unsigned int size)
+{
+ int rc = -1, len_in_logic_page;
+ unsigned long page, chip, left_page_in_blk;
+ unsigned int logic_page, logic_page_in_chip, logic_page_count, logic_oobblock, logic_blkCnt;
+
+ logic_oobblock = nand->oobblock_valid*2;//For 60bit edit: "/nand->oobblock_valid "
+ logic_blkCnt = nand->dwBlockCount/2;
+
+ if (naddr >= nand->totlen || (naddr + size) >= nand->totlen) {
+ printf("naddr=0x%llx is out of size\r\n", naddr);
+ return -2;
+ }
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand);
+ return -1;
+ }
+
+ enable_hw_rdmz(nand);
+
+ //page = (unsigned long)(naddr>>nand->page_shift);
+ page = (unsigned long)((naddr>>nand->page_shift)/nand->oobblock_K);//For 60bit edit: "/nand->oobblock_K "
+
+ if ((page/nand->dwPageCount)%2) {
+ page -= nand->dwPageCount;
+ printf("address is directed to plane 0 page=0x%x\n", page);
+ }
+
+ logic_page = (page>>1)+(page%nand->dwPageCount);
+/* if((logic_page % nand->dwPageCount)) {
+ printf("Error: wrong parameter, Just support 0 page start.\n");
+ return -1;
+ }*/
+ len_in_logic_page = size/logic_oobblock + ((size%logic_oobblock) ? 1 : 0);
+ printf("ESLC Load Image From NAND Flash page=0x%lx\r\n", logic_page);
+
+ rc = set_ECC_mode(nand);
+ if (rc)
+ return -1;
+
+ while (1) {
+
+ chip = logic_page / (logic_blkCnt * nand->dwPageCount);
+ logic_page_in_chip = logic_page % (logic_blkCnt * nand->dwPageCount);
+
+ if (nand->isbadblock(nand, (logic_page_in_chip/nand->dwPageCount)*2, chip)) {
+ logic_page = logic_page + nand->dwPageCount - (logic_page_in_chip%nand->dwPageCount);
+ continue;
+ }
+ if (nand->isbadblock(nand, (logic_page_in_chip/nand->dwPageCount)*2+1, chip)) {
+ logic_page = logic_page + nand->dwPageCount - (logic_page_in_chip%nand->dwPageCount);
+ continue;
+ }
+
+ left_page_in_blk = (nand->dwPageCount/2) - logic_page_in_chip%((nand->dwPageCount/2));
+ if (len_in_logic_page >= (nand->dwPageCount/2))
+ logic_page_count = (logic_page%(nand->dwPageCount/2)) ? left_page_in_blk : ((nand->dwPageCount/2));
+ else
+ logic_page_count = (len_in_logic_page < left_page_in_blk) ? len_in_logic_page : left_page_in_blk;
+
+ printf("left_page_in_blk:%d, len_in_logic_page = %d, logic_page_count = %d, chip:%d, logic_page_in_chip:%d\n",
+ left_page_in_blk, len_in_logic_page, logic_page_count, chip, logic_page_in_chip);
+ NAND_ENABLE_CE(nand, chip);
+ rc = eslc_nand_read_block(nand, maddr, logic_page_in_chip, logic_page_count);
+ if (rc) {
+ printf("Read Fail! Add block%d to bbt.\n",(logic_page_in_chip/nand->dwPageCount)*2);
+
+ //add real read fail bad block
+ update_bbt_inram_set_r_badblk(nand , (logic_page_in_chip/nand->dwPageCount)*2, chip);
+
+ update_bbt_inflash(nand,0,chip);
+
+ return rc;
+ }
+
+ maddr = maddr + logic_page_count * logic_oobblock;
+ if (logic_page_count == (nand->dwPageCount/2))
+ logic_page = logic_page + nand->dwPageCount;
+ else
+ logic_page = logic_page + logic_page_count;
+ len_in_logic_page -= logic_page_count;
+
+ if (len_in_logic_page <= 0) {
+ printf("\r\nRead NAND Flash OK\r\n");
+ NAND_DISABLE_CE(nand);
+ return 0;
+ }
+ }
+ NAND_DISABLE_CE(nand);
+ return -1;
+}
+
+
+int WMTLoadImageFormNAND(
+struct nand_chip *nand,
+unsigned long long naddr,
+unsigned int maddr,
+unsigned int size)
+{
+
+ int rc = -1, multi = 1, len_in_page;
+ unsigned long page, chip, page_in_chip, page_count, left_page_in_blk;
+ unsigned int naddr_page, size_page;
+
+ if(nand->dwECCBitNum == 60)
+ naddr_page = naddr/nand->oobblock_K>>10;
+ else
+ naddr_page = naddr >> nand->page_shift;
+
+ if((nand->mfr == NAND_HYNIX)&& keydata_base!=0){
+ misc_end = keydata_base;
+ }
+ if(cur_chip && nand->mfr == NAND_HYNIX && !do_page_rw && naddr_page < misc_end) {
+
+ if (nand->realplanenum) {
+ rc = eslc_load_image_tpi_multi(nand, naddr, maddr, size);
+ } else {
+ rc = eslc_load_image_tpi(nand, naddr, maddr, size);
+ }
+ disable_hw_rdmz(nand);
+ return rc;
+ }
+
+ if (naddr >= nand->totlen || (naddr + size) >= nand->totlen) {
+ printf("naddr=0x%llx is out of size\r\n", naddr);
+ disable_hw_rdmz(nand);
+ return -2;
+ }
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand);
+ disable_hw_rdmz(nand);
+ return -1;
+ }
+
+ enable_hw_rdmz(nand);
+
+ page = (unsigned long)((naddr>>nand->page_shift)/nand->oobblock_K);//For 60bit edit: "/nand->oobblock_K "
+
+ len_in_page = size/nand->oobblock_valid + ((size%nand->oobblock_valid) ? 1 : 0);
+ printf("Load Image From NAND Flash naddr 0x%x, page=0x%x, len = 0x%x\n", (ulong)(naddr>>10), (ulong)page, len_in_page);
+
+ rc = set_ECC_mode(nand);
+ if (rc){
+ disable_hw_rdmz(nand);
+ return -1;
+ }
+
+ if (nand->realplanenum && !do_page_rw) {
+ multi = 2;
+ //page -= page%(nand->dwPageCount*multi);
+ if ((page/nand->dwPageCount)%2) {
+ page -= nand->dwPageCount;
+ printf("address is directed to plane 0 page=0x%x\n", page);
+ }
+ }
+
+
+ while (1) {
+ chip = page / (nand->dwBlockCount * nand->dwPageCount);
+ page_in_chip = page % (nand->dwBlockCount * nand->dwPageCount);
+
+ if (nand->isbadblock(nand, page_in_chip/nand->dwPageCount, chip) && !do_page_rw) {
+ page = page + nand->dwPageCount * multi - (page_in_chip%nand->dwPageCount);
+ continue;
+ }
+ if (multi == 2 && nand->isbadblock(nand, (page_in_chip/nand->dwPageCount)+1, chip)) {
+ page = page + nand->dwPageCount * multi - (page_in_chip%nand->dwPageCount);
+ continue;
+ }
+
+ left_page_in_blk = nand->dwPageCount * multi - page_in_chip%(nand->dwPageCount * multi);
+ if (len_in_page >= (nand->dwPageCount*multi))
+ page_count = (page%(nand->dwPageCount * multi)) ? left_page_in_blk : (nand->dwPageCount * multi);
+ else
+ page_count = (len_in_page < left_page_in_blk) ? len_in_page : left_page_in_blk;
+
+ /*printf("\n read start chip%d,page=0x%x, page count=0x%x\r\n",
+ chip, page_in_chip, page_count);
+ printf("\n read left_page_in_blk=%d,len_in_page=0x%x, page count=0x%x\r\n",
+ left_page_in_blk, len_in_page, page_count);*/
+
+ NAND_ENABLE_CE(nand, chip);
+
+ if (nand->realplanenum && !do_page_rw) {
+ pNFCRegs->NFCR14 = 0x1212;
+ pNFCRegs->NFCR12 |= RD_DLY;
+ rc = nand_read_block_multi(nand, maddr, page_in_chip, page_count);
+ pNFCRegs->NFCR14 = 0x2424;
+ pNFCRegs->NFCR12 &= ~RD_DLY;
+ }
+ else
+ rc = nand_read_block(nand, maddr, page_in_chip, page_count);
+ if (rc){
+ disable_hw_rdmz(nand);
+
+ printf("Read Fail! Add block%d to bbt.\n",page_in_chip/nand->dwPageCount);
+
+ update_bbt_inram_set_r_badblk(nand , page_in_chip/nand->dwPageCount, chip);
+
+ update_bbt_inflash(nand,0,chip);
+
+ return rc;
+ }
+
+ maddr = maddr + page_count*nand->oobblock_valid;//For 60bit edit: "oobblock_valid"
+
+ page = page + page_count;
+ len_in_page -= page_count;
+
+ if (len_in_page <= 0) {
+ printf("\r\nRead NAND Flash OK\r\n");
+ NAND_DISABLE_CE(nand);
+ disable_hw_rdmz(nand);
+ return 0;
+ }
+ }
+ NAND_DISABLE_CE(nand);
+ disable_hw_rdmz(nand);
+ return -1;
+}
+
+int getbbtbadblock_detail(struct nand_chip *nand, unsigned int block, int chip)
+{
+
+ unsigned int ffword = 0x03;
+
+ if (!bbt)
+ return -1;
+
+ /* read fail bad block (1) */
+ if ((bbt[(nand->oobblock*chip)/4 + (block>>4)] & (ffword<<((block&0x0f)*2)))
+ == (0x01<<((block&0x0f)*2))) {
+ return 1;
+ }
+ /* write/erase fail bad block (2) */
+ else if ((bbt[(nand->oobblock*chip)/4 + (block>>4)] & (ffword<<((block&0x0f)*2)))
+ == (0x02<<((block&0x0f)*2))) {
+ return 2;
+ }
+ /* default bad block (0) */
+ else {
+ return 0;
+ }
+
+}
+
+
+int isbbtbadblock(struct nand_chip *nand, unsigned int block, int chip)
+{
+#ifdef USE_BBT
+ unsigned int ffword = 0x03;
+
+ if (!bbt) {
+ printf("return -1!\n");
+ return -1;
+ }
+
+ /* consider the read fail block as normal block to read or write @20140618 */
+ if ((bbt[(nand->oobblock*chip)/4 + (block>>4)] & (ffword<<((block&0x0f)*2)))
+ == (0x01<<((block&0x0f)*2))) {
+ printf("bbt : block%d is read fail bad block\n", block);
+ return 0;
+ }
+
+ if ((bbt[(nand->oobblock*chip)/4 + (block>>4)] & (ffword<<((block&0x0f)*2)))
+ != (ffword<<((block&0x0f)*2))) {
+ /*printf("bbt : block%d is bad\n", block);*/
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+int update_bbt_inflash(struct nand_chip *nand, unsigned int last, int chip)
+{
+ unsigned int i, j, block = 0, page_count;
+ int rc = -1, bbt_blk = nand->dwBlockCount - BBT_MAX_BLOCK;
+ unsigned char *pattern;
+ unsigned int need;
+ unsigned char fifo[64];
+ unsigned int ofs, ofs1;
+
+ if (!bbt) {
+ printf("bbt = NULL\n");
+ return -1;
+ }
+
+ NAND_ENABLE_CE(nand, chip);
+
+ rc = set_ECC_mode(nand);
+ if (rc) {
+ return -1;
+ }
+
+ if(cur_chip && nand->mfr == NAND_HYNIX) { //use eslc mode to create bbt
+ cur_chip->set_parameter(nand, ESLC_MODE, ECC_ERROR_VALUE);
+ }
+ ofs = NAND_LARGE_DWRESERVED1_OFS;
+ ofs1 = NAND_LARGE_DWRESERVED2_OFS;
+ if (nand->oobblock <= 0x200) {
+ ofs = NAND_SMALL_DWRESERVED1_OFS;
+ ofs1 = NAND_SMALL_DWRESERVED2_OFS;
+ }
+ page_count = 1 + (((nand->dwBlockCount>>2)>nand->oobblock) ? 1 : 0);
+
+ nand->bbt_sw_rdmz = 1;//Henry add
+
+ /* first update to last block */
+ if (last)
+ block = last & 0xffff;
+ else {
+ bbt_version++;
+ pattern = bbt_pattern;
+ if (nand->realplanenum)
+ bbt_blk = nand->dwBlockCount - (BBT_MAX_BLOCK*2);
+ else
+ bbt_blk = nand->dwBlockCount - BBT_MAX_BLOCK;
+ for (i = nand->dwBlockCount-1; i >= bbt_blk; i--) {
+ if (isbbtbadblock(nand, i, chip))
+ continue;
+ rc = wmt_nand_erase(nand, i);
+ if (rc < 0 || rc & 0x01) {
+ printf("Erase failed at chip%d, block%d\n", chip, i);
+ update_bbt_inram(nand, i, chip);
+ continue;
+ }
+ memset(fifo, 0xff, 64);
+ for (j = 0; j < 4; j++) {
+ fifo[ofs+j] = pattern[j];
+ fifo[ofs1+j] = (unsigned char)((bbt_version>>(8*j))&0xff);
+ }
+
+ rc = nand_write_block(
+ nand,
+ (unsigned int)&bbt[(chip*nand->oobblock)/4],
+ (i*nand->dwPageCount),
+ page_count,
+ fifo,
+ 0
+ );
+ if (rc)
+ update_bbt_inram(nand, i, chip);
+ else {
+ printf("write bbt_pattern to chip%d, block%d , bbt 0x%8.8x\n",
+ chip, i, (unsigned int)&bbt[0]);
+ bad_block_pos[chip][nand->dwBlockCount -i -1] = i << 16;
+ break;
+ }
+ }
+ block = i;
+ }
+ if (block <= bbt_blk) {
+ printf("err : we have only %d table blocks (block=%d)\n", bbt_blk, block);
+ if(cur_chip && nand->mfr == NAND_HYNIX) {
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+ }
+ nand->bbt_sw_rdmz = 0;//Henry add
+ return -1;
+ }
+ need = 0;
+ for (i = bbt_blk; i < block; i++) {
+ if (isbbtbadblock(nand, i, chip))
+ continue;
+ rc = wmt_nand_erase(nand, i);
+ if (rc < 0 || rc & 0x01) {
+ update_bbt_inram(nand, i, chip);
+ printf("Erase failed at chip%d, block%x\n", chip, i);
+ if (!need)
+ bbt_version++;
+ need = 1;
+ }
+ }
+ pattern = mirror_pattern;
+ if (last) {
+ if ((last>>16) - 1)
+ pattern = bbt_pattern;
+ }
+ for (i = block-1; i >= bbt_blk; i--) {
+ if (isbbtbadblock(nand, i, chip))
+ continue;
+ memset(fifo, 0xff, 64);
+ for (j = 0; j < 4; j++) {
+ fifo[ofs+j] = pattern[j];
+ fifo[ofs1+j] = (unsigned char)((bbt_version>>(8*j))&0xff);
+ }
+ rc = nand_write_block(
+ nand,
+ (unsigned int)&bbt[(chip*nand->oobblock)/4],
+ (i*nand->dwPageCount),
+ page_count,
+ fifo,
+ 0
+ );
+ if (rc) {
+ update_bbt_inram(nand, i, chip);
+ if (!need)
+ bbt_version++;
+ need = 1;
+ } else {
+ printf("write mirror_pattern to chip%d, block%d bbt = 0x%8.8x\n",
+ chip, i, (unsigned int)&bbt[0]);
+ bad_block_pos[chip][nand->dwBlockCount -i -1] = (i << 16);
+ break;
+ }
+ }
+ if(cur_chip && nand->mfr == NAND_HYNIX) {
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+ }
+ nand->bbt_sw_rdmz = 0;//Henry add
+ return 0;
+}
+
+
+/*Set default bad block to bbt (0) */
+int update_bbt_inram(struct nand_chip *nand, unsigned int block, int chip)
+{
+ unsigned int ffword = 0x03;
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] &= ~(ffword<<((block&0x0f)*2));
+
+ //set another pair block as the same type of bad block when using muiltplane mode
+ if (nand->realplanenum) {
+ if (block%2)
+ block--;
+ else
+ block++;
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] &= ~(ffword<<((block&0x0f)*2));
+ }
+
+ return 0;
+}
+
+/*Set read fail bad block to bbt (1) */
+int update_bbt_inram_set_r_badblk(struct nand_chip *nand, unsigned int block, int chip)
+{
+ unsigned int ffword = 0x03;
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] &= ~(ffword<<((block&0x0f)*2));//clean to 0x00
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] |= (0x1<<((block&0x0f)*2));
+
+ //set another pair block as the same type of bad block when using muiltplane mode
+ if (nand->realplanenum) {
+ if (block%2)
+ block--;
+ else
+ block++;
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] &= ~(ffword<<((block&0x0f)*2));//clean to 0x00
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] |= (0x1<<((block&0x0f)*2));
+ }
+
+ return 0;
+}
+
+/*Set write & erase fail bad block to bbt (2) */
+int update_bbt_inram_set_w_e_badblk(struct nand_chip *nand, unsigned int block, int chip)
+{
+ unsigned int ffword = 0x03;
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] &= ~(ffword<<((block&0x0f)*2));//clean to 0x00
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] |= (0x2<<((block&0x0f)*2));
+
+ //set another pair block as the same type of bad block when using muiltplane mode
+ if (nand->realplanenum) {
+ if (block%2)
+ block--;
+ else
+ block++;
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] &= ~(ffword<<((block&0x0f)*2));//clean to 0x00
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] |= (0x2<<((block&0x0f)*2));
+ }
+
+
+ return 0;
+}
+
+/*Set good block to bbt (3) */
+int update_bbt_inram_set_goodblk(struct nand_chip *nand, unsigned int block, int chip)
+{
+ unsigned int ffword = 0x03;
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] |= (ffword<<((block&0x0f)*2));
+
+ //set another pair block as good block when using muiltplane mode
+ if (nand->realplanenum) {
+ if (block%2)
+ block--;
+ else
+ block++;
+ bbt[(chip*nand->oobblock)/4 + (block>>4)] |= (ffword<<((block&0x0f)*2));
+ }
+
+ return 0;
+}
+
+
+int write_read_blk(struct nand_chip *nand,unsigned long *bbcheck_value)
+{
+ printf("WARNING: now check the ecc error bits distribution to create bbt! Might take some time...\n");
+ printf("WARNING: Please make sure you did \"nandrw erase all\" then \"nandrw erase table\" first.\n");
+ unsigned int page_in_chip=0,block_in_chip=0;
+ int i,rc,block=4;
+ //unsigned int need[CFG_MAX_NAND_DEVICE];
+
+ int thredhold = *bbcheck_value;
+ unsigned int value = 0x55AA55AA;
+ unsigned int *garbade_buf = malloc(nand->oobblock);
+ unsigned int *read_buf = malloc(nand->oobblock);
+ if (nand->realplanenum)
+ block = 8;
+
+ r_w_check_ecc_robust = 1;
+
+ for (i = 0; i < nand->oobblock/4; i++) {
+ garbade_buf[i] = value;//initial garbage buffer
+ }
+
+
+ while (1) {
+
+ block_in_chip = page_in_chip/nand->dwPageCount;
+
+ if (block_in_chip == nand->dwBlockCount-block) {
+ break;
+ }
+
+ if (nand->isbadblock(nand, block_in_chip, 0)) {
+ printf("Meet bad block %d, try next...\n",block_in_chip);
+ page_in_chip = page_in_chip + nand->dwPageCount - (page_in_chip%nand->dwPageCount);
+ continue;
+ }
+ /* ERASE BLOCK */
+ rc = wmt_nand_erase(nand, block_in_chip);
+
+ if (rc < 0 || rc & 0x01) {
+ printf("Erase failed at chip%d block%d\n", block_in_chip);
+ nand->update_table_inram(nand, block_in_chip, 0);
+ page_in_chip = page_in_chip + nand->dwPageCount - (page_in_chip%nand->dwPageCount);
+ continue;
+ }
+ /* WRITE BLOCK */
+ rc = nand_write_block(nand, (unsigned int)garbade_buf, page_in_chip, nand->dwPageCount, NULL, 0);
+
+ if (rc) {
+ printf("Write block failed at chip%d page%d\n", 0, page_in_chip);
+ nand->update_table_inram(nand, block_in_chip, 0);
+
+ page_in_chip = page_in_chip + nand->dwPageCount - (page_in_chip%nand->dwPageCount);
+ continue;
+ }
+
+ /* READ BLOCK */
+ max_ecc_bits = 0;
+ rc = nand_read_block(nand, (unsigned int)read_buf, page_in_chip, nand->dwPageCount);// tmp read to read_buf
+
+ printf("Finish checked page=%d,block=%d,max_err_bit=%d\n",page_in_chip,block_in_chip,max_ecc_bits);
+
+ if ( max_ecc_bits > thredhold ) {
+ printf("-> block%d has %d error bits (> %d),update to bbt!\n",block_in_chip,max_ecc_bits, thredhold );
+ nand->update_table_inram(nand, block_in_chip, 0);
+ }
+
+ //tmp test
+ /*if (block_in_chip == 50) {
+ printf("write_read_blk OK %d \r\n",block_in_chip);
+ break;
+ }*/
+
+ page_in_chip = page_in_chip + nand->dwPageCount - (page_in_chip%nand->dwPageCount);
+
+ }
+ printf("write_read_blk OK B0~B%d \r\n",block_in_chip-1);
+ printf("WARNING: recommend doing \"nandrw erase all\" once after bbt created.\n");
+
+ r_w_check_ecc_robust = 0;
+ free(garbade_buf);
+ free(read_buf);
+
+ return 0;
+}
+
+/*
+purpose : enable/disable check bab block by ecc error bits count base on env parameter "wmt_nand_bbcheck"
+env parameter format : 1:15 (1=enable ;15=check bab block by ecc error bits > 15)
+add by Henry @2013/11/29
+*/
+int parsing_wmt_bbcheck(char* s,unsigned long *bbcheck_on,unsigned long *bbcheck_value)
+{
+ char *tmp_s = NULL;
+ int i=0,j=0,len=0;
+
+ while (s[i]!=':') {
+ if (s[i]>'9' || s[i]<'0' || s[i]=='\0') {
+ printf("format error.\n");
+ return -1;
+ }
+ i++;
+ len++;
+ }
+ if (len==0) {
+ printf("value error\n");
+ return -1;
+ }
+ while (j!=len) {
+ tmp_s[j]=s[i-len+j];
+ j++;
+ }
+ *bbcheck_on = simple_strtoul(tmp_s, NULL, 10);//get value of enable check bab block by ecc error bits count
+ i++;
+ j=0; len=0;
+ while (s[i]!='\0') {
+ if (s[i]>'9' || s[i]<'0') {
+ printf("format error.\n");
+ return -1;
+ }
+ i++;
+ len++;
+ }
+ if (len==0) {
+ printf("value error\n");
+ return -1;
+ }
+ while (j!=len) {
+ tmp_s[j]=s[i-len+j];
+ j++;
+ }
+ *bbcheck_value = simple_strtoul(tmp_s, NULL, 10);//get value of ecc error bits count
+
+ //printf("bbcheck_on=%d,bbcheck_value=%d\n",*bbcheck_on,*bbcheck_value);
+
+ return 0;
+}
+
+int creat_bbt(struct nand_chip *nand, int chip)
+{
+ unsigned int i, j, k, count = 0;
+ unsigned int page[2];
+ unsigned int bpos[2];
+ unsigned int ffword = 0x03;
+ int rc = -1, block = 4;
+
+ if (nand->realplanenum)
+ block = 8;
+
+ NAND_ENABLE_CE(nand, chip);
+
+ /*#ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz && (pNFCRegs->NFCRf&RDMZ))
+ reset_nfc();
+ #endif*/
+ disable_hw_rdmz(nand);
+
+ //printf("HW RDMZ OFF ( creat_bbt )\n");
+
+ printf("creat_bbt at chip=%d\n", chip);
+ nfc_ecc_set(USE_SW_ECC, ECC1bit, nand);
+ /* scan bbt first */
+ bpos[0] = (nand->dwBIOffset&0xffff);
+ page[0] = (nand->dwBI0Position&0xffff);
+ bpos[1] = (nand->dwBIOffset&0xffff);
+ page[1] = (nand->dwBI1Position&0xffff);
+ if (!bbt) {
+ bbt = malloc(nand->oobblock * nand->numchips);
+ if (!bbt) {
+ printf("alloc bbt failed\n");
+ return -1;
+ }
+ }
+ memset((unsigned char *)bbt+nand->oobblock*chip, 0xff, nand->oobblock);
+
+ nand->bbt_sw_rdmz = 1;//Henry add
+
+ for (i = 0; i < nand->dwBlockCount; i++) {
+ for (j = 0; j < block; j++) {
+
+ nand->col_offset = (j%2) ? 0 : nand->oobblock;
+
+ rc = nand->nfc_read_page(nand,
+ (i*nand->dwPageCount)+page[j%2],
+ (unsigned int)nand->data_buf,
+ 128/*nand->oobblock+nand->oobsize*/
+ );
+
+ if (rc) {
+ printf("scan bbt err at block%d rc=%d\n", i+page[j%2], rc);
+ if (rc != -ERR_ECC_UNCORRECT){
+ nand->bbt_sw_rdmz = 0;//Henry add
+ return rc;
+ }
+ bbt[i>>4] &= ~(ffword<<((i&0x0f)*2));
+ count++;
+ printf("find bad block : block%d\n", i);
+ break;
+ } else {
+ if (((nand->id>>24)%0xFF) == NAND_SANDISK) {
+ int badblk = 0;
+ for (k = 0; k < 128/*(nand->oobblock+nand->oobsize)*/; k++) {
+ if (*(((unsigned char *)nand->data_buf) + k) != 0xFF) {
+ badblk = 1;
+ break;
+ }
+ }
+ if (badblk) {
+ bbt[(nand->oobblock*chip)/4 +(i>>4)] &= ~(ffword<<((i&0x0f)*2));
+ count++;
+ printf("find bad block : block%d\n", i);
+ break;
+ }
+ } else {
+ if (/**(((unsigned char *)nand->data_buf)+nand->oobblock+bpos[j]) != 0xFF ||*/
+ *((unsigned char *)nand->data_buf) != 0xFF) {
+ /*printf("find bad block : data_buf%x\n", *((unsigned char *)nand->data_buf));
+ printf("find bad block : data_buf+oobblock%x\n", *(((unsigned char *)nand->data_buf)+nand->oobblock+bpos[j]));*/
+ bbt[(nand->oobblock*chip)/4 +(i>>4)] &= ~(ffword<<((i&0x0f)*2));
+ //printf("find bad block : block%d bbt[%d]=0x%x\n", i, (nand->oobblock*chip)/4 +(i>>4), bbt[(nand->oobblock*chip)/4 +(i>>4)]);
+ count++;
+ printf("find bad block : block%d\n", i);
+ break;
+ }
+ }
+ }
+ }
+ }
+ nand->col_offset = 0;
+ nand->bbt_sw_rdmz = 0;//Henry add
+ printf("Total find %d bad blocks\n", count);
+
+ /*#ifdef WMT_HW_RDMZ
+ if (nand->dwRdmz == 1)
+ pNFCRegs->NFCRf = RDMZ;
+ #endif*/
+ //enable_hw_rdmz(nand);
+ //printf("HW RDMZ ON ( creat_bbt )\n");
+
+ rc = set_ECC_mode(nand);
+ if (rc)
+ return -1;
+ bbt_version = 0;
+ nand->update_table_inflash = update_bbt_inflash;
+ nand->update_table_inram = update_bbt_inram;
+ nand->isbadblock = isbbtbadblock;
+
+
+ unsigned long bbcheck_on = 0;
+ unsigned long bbcheck_value = 0;
+ char *s = NULL;
+
+ s = getenv("wmt_nand_bbcheck");
+ if (s != NULL) {
+ if (parsing_wmt_bbcheck(s,&bbcheck_on,&bbcheck_value)) {
+ printf("parsing_wmt_bbcheck fail\n");
+ bbcheck_on = 0;
+ }
+ else
+ printf("bbcheck_on=%d,bbcheck_value=%d\n",bbcheck_on,bbcheck_value);
+ }
+ if(bbcheck_on)
+ write_read_blk(nand,&bbcheck_value);//Fix: After doing this,do we need to erase programed block??
+
+ return update_bbt_inflash(nand, 0, chip);
+}
+
+/* NanD_SelectChip: Select a given flash chip within the current floor */
+#if 0
+static inline int NanD_SelectChip(struct nand_chip *nand, int chip)
+{
+ /* Wait for it to be ready */
+ return NanD_WaitReady(nand, 0);
+}
+#endif
+
+void calculate_ECC_info(struct nand_chip *nand, struct ECC_size_info *ECC_size)
+{
+ switch (ECC_size->ecc_engine) {
+ case 1:
+ ECC_size->oob_ecc_bits_count = ECC_size->ecc_bits_count = ECC4bit_bit_count;
+ ECC_size->oob_max_bit_error = ECC_size->max_bit_error = 4;
+ ECC_size->banks = nand->oobblock/512;
+ ECC_size->bank_offset = nand->oobblock/ECC_size->banks + ECC4bit_byte_count;
+ ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC4bit_byte_count;
+ ECC_size->unprotect = nand->oobsize - ECC4bit_byte_count*(ECC_size->banks+1) - 24;
+ break;
+ case 2:
+ ECC_size->oob_ecc_bits_count = ECC_size->ecc_bits_count = ECC8bit_bit_count;
+ ECC_size->oob_max_bit_error = ECC_size->max_bit_error = 8;
+ ECC_size->banks = nand->oobblock/512;
+ ECC_size->bank_offset = nand->oobblock/ECC_size->banks + ECC8bit_byte_count;
+ ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC8bit_byte_count;
+ ECC_size->unprotect = nand->oobsize - ECC8bit_byte_count*(ECC_size->banks+1) - 24;
+ break;
+ case 3:
+ ECC_size->oob_ecc_bits_count = ECC_size->ecc_bits_count = ECC12bit_bit_count;
+ ECC_size->oob_max_bit_error = ECC_size->max_bit_error = 12;
+ ECC_size->banks = nand->oobblock/512;
+ ECC_size->bank_offset = nand->oobblock/ECC_size->banks + ECC12bit_byte_count;
+ ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC12bit_byte_count;
+ ECC_size->unprotect = nand->oobsize - ECC12bit_byte_count*(ECC_size->banks+1) - 24;
+ break;
+ case 4:
+ ECC_size->oob_ecc_bits_count = ECC_size->ecc_bits_count = ECC16bit_bit_count;
+ ECC_size->oob_max_bit_error = ECC_size->max_bit_error = 16;
+ ECC_size->banks = nand->oobblock/512;
+ ECC_size->bank_offset = nand->oobblock/ECC_size->banks + ECC16bit_byte_count;
+ ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC16bit_byte_count;
+ ECC_size->unprotect = nand->oobsize - ECC16bit_byte_count*(ECC_size->banks+1) - 24;
+ break;
+ case 5:
+ ECC_size->oob_ecc_bits_count = ECC_size->ecc_bits_count = ECC24bitPer1K_bit_count;
+ ECC_size->oob_max_bit_error = ECC_size->max_bit_error = 24;
+ ECC_size->banks = nand->oobblock/1024;
+ ECC_size->bank_offset = nand->oobblock/ECC_size->banks + ECC24bitPer1K_byte_count;
+ ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC24bitPer1K_byte_count;
+ ECC_size->unprotect = nand->oobsize - ECC24bitPer1K_byte_count*(ECC_size->banks+1) - 24;
+ break;
+ case 6:
+ ECC_size->ecc_bits_count = ECC40bitPer1K_bit_count;
+ ECC_size->oob_ecc_bits_count = ECC24bitPer1K_bit_count;
+ ECC_size->max_bit_error = 40;
+ ECC_size->oob_max_bit_error = 24;
+ ECC_size->banks = nand->oobblock/1024;
+ ECC_size->bank_offset = nand->oobblock/ECC_size->banks + ECC40bitPer1K_byte_count;
+ ECC_size->ECC_bytes = ECC40bitPer1K_byte_count;
+ ECC_size->oob_ECC_bytes = ECC24bitPer1K_byte_count;
+ ECC_size->unprotect = nand->oobsize - ECC40bitPer1K_byte_count*ECC_size->banks - ECC24bitPer1K_byte_count - 24;
+ break;
+ case 7:
+ ECC_size->ecc_bits_count = ECC60bitPer1K_bit_count;
+ ECC_size->oob_ecc_bits_count = ECC24bitPer1K_bit_count;
+ ECC_size->max_bit_error = 60;
+ ECC_size->oob_max_bit_error = 24;
+ ECC_size->banks = nand->oobblock/1024;
+ ECC_size->bank_offset = nand->oobblock/ECC_size->banks + ECC60bitPer1K_byte_count;
+ ECC_size->ECC_bytes = ECC60bitPer1K_byte_count;
+ ECC_size->oob_ECC_bytes = ECC24bitPer1K_byte_count;
+ ECC_size->unprotect = nand->oobsize - ECC60bitPer1K_byte_count*ECC_size->banks - ECC24bitPer1K_byte_count - 24;
+ break;
+ default:
+ printf("%d-bit ECC engine is not support:\r\n", ECC_size->ecc_engine);
+ break;;
+ }
+ return;
+}
+
+int wmt_nand_reset(void)
+{
+ int status = -1;
+ unsigned int chip = ((~pNFCRegs->NFCR12)&0xFF00)>>9;
+
+ pNFCRegs->NFCR2 = 0xff; /* set command */
+ pNFCRegs->NFCRb &= B2R; /* write to clear*/
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;
+ status = NAND_WAIT_READY();
+ if (status) {
+ printf("reset real chip=%x wait busy status = 0x%x time out\r\n", chip, status);
+ return status;
+ }
+ return status;
+}
+
+int set_ECC_mode(struct nand_chip *nand)
+{
+ unsigned int ECCbit = nand->dwECCBitNum;
+ unsigned int ECC_mode;
+ switch (ECCbit) {
+ case 1:
+ ECC_mode = ECC1bit;
+ break;
+ case 4:
+ ECC_mode = ECC4bit;
+ break;
+ case 8:
+ ECC_mode = ECC8bit;
+ break;
+ case 12:
+ ECC_mode = ECC12bit;
+ break;
+ case 16:
+ ECC_mode = ECC16bit;
+ break;
+ case 24:
+ ECC_mode = ECC24bitPer1K;
+ break;
+ case 40:
+ ECC_mode = ECC40bitPer1K;
+ break;
+ case 60:
+ ECC_mode = ECC60bitPer1K;
+ break;
+ default:
+ printf("ecc mode input not support ECCbit=%d\n", ECCbit);
+ return -1;
+ }
+ nfc_ecc_set(USE_HW_ECC, ECC_mode, nand);
+ return 0;
+}
+
+int nand_readID(unsigned char *id)
+{
+ unsigned int cfg = 0, i = 0;
+ int status = -1;
+
+ #ifdef WMT_HW_RDMZ
+ unsigned int rdmz;
+ rdmz = pNFCRegs->NFCRf&RDMZ;
+
+
+ if (rdmz) {
+ //printf("HW RDMZ ON ( nand_readID )\n");
+ //pNFCRegs->NFCRf = RDMZ;
+ enable_hw_rdmz(nand_dev_desc + curr_device);
+ pNFCRegs->NFCR4 = 0;
+ }
+ #endif
+
+ pNFCRegs->NFCR2 = NAND_READID;
+ pNFCRegs->NFCR3 = 0xff00;
+ cfg = DPAHSE_DISABLE|(0x02<<1);
+ pNFCRegs->NFCR1 = TWHR|cfg|NFC_TRIGGER|OLD_CMD; /* cfg & start */
+ status = NFC_WAIT_READY();
+ if (status)
+ return status;
+ cfg = NAND2NFC|SING_RW;
+ for (i = 0; i < 6; i++) {
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER|OLD_CMD;
+ status = NFC_WAIT_READY();
+ if (status)
+ return status;
+ status = NAND_WAIT_IDLE();
+ if (status)
+ return status;
+ id[i] = (unsigned char)pNFCRegs->NFCR0;
+
+ #ifdef WMT_HW_RDMZ
+ if (rdmz)
+ id[i] = id[i]^rdmz_tb[0];
+ #endif
+ }
+
+ return 0;
+}
+
+int nand_get_feature(void)
+{
+ unsigned char id[4]={0};
+
+ unsigned int cfg = 0, i = 0;
+ int status = -1;
+
+ #ifdef WMT_HW_RDMZ
+ unsigned int rdmz;
+ rdmz = pNFCRegs->NFCRf&RDMZ;
+ if (rdmz) {
+ //printf("HW RDMZ ON ( nand_get_feature )\n");
+ //pNFCRegs->NFCRf = RDMZ;
+ enable_hw_rdmz(nand_dev_desc + curr_device);
+ pNFCRegs->NFCR4 = 0;
+ }
+ #endif
+
+ pNFCRegs->NFCR2 = 0xEE;
+ pNFCRegs->NFCR3 = 0xff01;
+ cfg = DPAHSE_DISABLE|(0x02<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER|OLD_CMD; /* cfg & start */
+ status = NFC_WAIT_READY();
+
+ if (status){
+ /*#ifdef WMT_HW_RDMZ
+ if (pNFCRegs->NFCRf&RDMZ)
+ reset_nfc();
+ #endif*/
+ disable_hw_rdmz(nand_dev_desc + curr_device);
+ //printf("HW RDMZ OFF ( nand_get_feature )\n");
+ return status;
+ }
+ cfg = NAND2NFC|SING_RW;
+ for (i = 0; i < 4; i++) {
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER|OLD_CMD;
+ status = NFC_WAIT_READY();
+ if (status){
+ /*#ifdef WMT_HW_RDMZ
+ if (pNFCRegs->NFCRf&RDMZ)
+ reset_nfc();
+ #endif*/
+ disable_hw_rdmz(nand_dev_desc + curr_device);
+ //printf("HW RDMZ OFF ( nand_get_feature )\n");
+ return status;
+ }
+ status = NAND_WAIT_IDLE();
+ if (status){
+ /*#ifdef WMT_HW_RDMZ
+ if (pNFCRegs->NFCRf&RDMZ)
+ reset_nfc();
+ #endif*/
+ disable_hw_rdmz(nand_dev_desc + curr_device);
+ //printf("HW RDMZ OFF ( nand_get_feature )\n");
+ return status;
+ }
+ id[i] = (unsigned char)pNFCRegs->NFCR0;
+
+ #ifdef WMT_HW_RDMZ
+ if (rdmz)
+ id[i] = id[i]^rdmz_tb[0];
+ #endif
+ }
+
+ printf("Micron nand flash feature is: 0x%02X%02X%02X%02X\n", id[0], id[1], id[2], id[3]);
+ /*#ifdef WMT_HW_RDMZ
+ if (pNFCRegs->NFCRf&RDMZ)
+ reset_nfc();
+ #endif*/
+ disable_hw_rdmz(nand_dev_desc + curr_device);
+ //printf("HW RDMZ OFF ( nand_get_feature )\n");
+ return 0;
+}
+
+int nand_set_feature(int value)
+{
+ unsigned char id[5]= {0};
+ unsigned int cfg = 0;
+
+ id[0] = value;
+ /* reset nand */
+ WRITE_NAND_COMMAND(NAND_READ0);
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;
+ if (NFC_WAIT_READY())
+ return -ERR_NFC_READY;
+
+ if (nfc_dma_cfg((unsigned int)id, 4, 1))
+ {
+ printf("nand_set_feature() fail\n");
+ return -ERR_DMA_CFG;
+ }
+
+ pNFCRegs->NFCR2 = 0xEF;
+ pNFCRegs->NFCR3 = 0xff01;
+ cfg = 0x02<<1;
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER|OLD_CMD; /* cfg & start */
+
+ if (NFC_WAIT_READY())/* wait command &data completed */
+ return -ERR_NFC_READY;
+
+ if (NAND_WAIT_IDLE())
+ return -ERR_NAND_IDLE;
+
+ return 0;
+}
+#ifdef CFG_CMD_NET
+void copy_filename (char *dst, char *src, int size);
+#else
+void copy_filename (char *dst, char *src, int size)
+{
+ if (*src && (*src == '"')) {
+ ++src;
+ --size;
+ }
+
+ while ((--size > 0) && *src && (*src != '"')) {
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+}
+#endif
+int set_ecc_info(struct nand_chip *nand)
+{
+ struct ECC_size_info ECC_size;
+ int rc;
+ unsigned int ecc_bit_mode = nand->dwECCBitNum;
+ if (ecc_bit_mode > 40)
+ ecc_bit_mode = (ecc_bit_mode == 60) ? 7 : (-1);
+ else if (ecc_bit_mode > 24)
+ ecc_bit_mode = (ecc_bit_mode == 40) ? 6 : (-1);
+ else
+ ecc_bit_mode = (ecc_bit_mode > 16) ? ((ecc_bit_mode/4) - 1) : (ecc_bit_mode/4);
+ ECC_size.ecc_engine = ecc_bit_mode;
+ calculate_ECC_info(nand, &ECC_size);
+ pNFCRegs->NFCR10 = (ECC_size.oob_ECC_bytes<<8)/* + (ECC_size.unprotect&0xFF)*/;
+ rc = set_ECC_mode(nand);
+ if (rc)
+ return 1;
+
+ return 0;
+}
+
+int get_nand_info_from_env(struct nand_chip *nand, char *s, unsigned int id, unsigned int id2)
+{
+ char *tmp;
+ unsigned int value;
+ int rc;
+
+ value = simple_strtoul(s, &tmp, 16);
+ if (id != value) {
+ printf(" env flash id not match, env_id = 0x%x, chip_id = 0x%x\n", value, id);
+ return 1;
+ }
+ nand->dwFlashID = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwBlockCount = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwPageSize = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwSpareSize = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwBlockSize = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwAddressCycle = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwBI0Position = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwBI1Position = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwBIOffset = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwDataWidth = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwPageProgramLimit = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwSeqRowReadSupport = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwSeqPageProgram = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwNandType = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwECCBitNum = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwRWTimming = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ nand->dwTwbTwhrTadl = value;
+ s = tmp+1;
+ value = simple_strtoul(s, &tmp, 16);
+ if (id2 != value) {
+ printf(" env flash id not match, env_id2 = 0x%x, chip_id2 = 0x%x\n", value, id2);
+ return 1;
+ }
+ nand->dwFlashID2 = value;
+ s = tmp+1;
+ copy_filename(nand->cProductName, s, MAX_PRODUCT_NAME_LENGTH);
+
+ if (nand->dwBlockCount < 1024 || nand->dwBlockCount > 16384) {
+ printf("dwBlockCount = 0x%x is abnormal\n", nand->dwBlockCount);
+ return 1;
+ }
+ if (nand->dwPageSize < 512 || nand->dwPageSize > 16384) {
+ printf("dwPageSize = 0x%x is abnormal\n", nand->dwPageSize);
+ return 1;
+ }
+ if (nand->dwBlockSize < (1024*64) || nand->dwBlockSize > (16384*64)) {
+ printf("dwBlockSize = 0x%x is abnormal\n", nand->dwBlockSize);
+ return 1;
+ }
+ if (nand->dwAddressCycle < 3 || nand->dwAddressCycle > 5) {
+ printf("dwAddressCycle = 0x%x is abnoraml\n", nand->dwAddressCycle);
+ return 1;
+ }
+ if (nand->dwBI0Position != 0 &&
+ nand->dwBI0Position > ((nand->dwBlockSize/nand->dwPageSize)-1)) {
+ printf("dwBI0Position = 0x%x is abnoraml\n", nand->dwBI0Position);
+ return 1;
+ }
+ if (nand->dwBI1Position != 0 &&
+ nand->dwBI1Position > ((nand->dwBlockSize/nand->dwPageSize)-1)) {
+ printf("dwBI1Position = 0x%x is abnoraml\n", nand->dwBI1Position);
+ return 1;
+ }
+ if (nand->dwBIOffset != 0 && nand->dwBIOffset != 5) {
+ printf("dwBIOffset = 0x%x is abnoraml\n", nand->dwBIOffset);
+ return 1;
+ }
+ if (nand->dwDataWidth != 0/* && nand->dwDataWidth != 1*/) {
+ printf("dwDataWidth = 0x%x is abnoraml\n", nand->dwDataWidth);
+ return 1;
+ }
+ /*printf("dwFlashID = 0x%x\n", nand->dwFlashID);
+ printf("dwBlockCount = 0x%x\n", nand->dwBlockCount);
+ printf("dwPageSize = 0x%x\n", nand->dwPageSize);
+ printf("dwSpareSize = 0x%x\n", nand->dwSpareSize);
+ printf("dwBlockSize = 0x%x\n", nand->dwBlockSize);
+ printf("dwAddressCycle = 0x%x\n", nand->dwAddressCycle);
+ printf("dwBI0Position = 0x%x\n", nand->dwBI0Position);
+ printf("dwBI1Position = 0x%x\n", nand->dwBI1Position);
+ printf("dwBIOffset = 0x%x\n", nand->dwBIOffset);
+ printf("dwDataWidth = 0x%x\n", nand->dwDataWidth);
+ printf("dwPageProgramLimit = 0x%x\n", nand->dwPageProgramLimit);
+ printf("dwSeqRowReadSupport = 0x%x\n", nand->dwSeqRowReadSupport);
+ printf("dwSeqPageProgram = 0x%x\n", nand->dwSeqPageProgram);
+ printf("dwNandType = 0x%x\n", nand->dwNandType);
+ printf("dwECCBitNum = 0x%x\n", nand->dwECCBitNum);
+ printf("dwRWTimming = 0x%x\n", nand->dwRWTimming);
+ printf("dwTwbTwhrTadl = 0x%x\n", nand->dwTwbTwhrTadl);
+ printf("cProductName = %s\n", nand->cProductName);*/
+
+ nand->mfr = id>>24;
+ nand->id = id;
+ nand->chipshift = shift_bit(nand->dwBlockCount) + shift_bit(nand->dwBlockSize);
+ nand->page256 = 0;/*nand_flash_ids[i].page256;*/
+ nand->eccsize = 512;//256;
+ nand->oobblock = nand->dwPageSize;//512;
+ nand->oobsize = nand->dwSpareSize;//16;
+ nand->page_shift = shift_bit(nand->dwPageSize);//9;
+ nand->erasesize = nand->dwBlockSize;//nand_flash_ids[i].erasesize;
+ nand->chips_name = nand->cProductName;
+ nand->bus16 = nand->dwDataWidth;
+ nand->dwPageCount = nand->dwBlockSize/nand->dwPageSize;
+ nand->IO_ADDR = __NFC_BASE;
+ wmt_get_timing(nand, (unsigned int)nand->dwRWTimming, nand->dwTwbTwhrTadl);
+ /*-------------move from cmd_nandrw.c below-----------------*/
+ pNFCRegs->NFCR12 = 0xFF00 | WP_DISABLE | DIRECT_MAP;
+ switch (nand->oobblock) {
+ case 512:
+ pNFCRegs->NFCR12 |= PAGE_512;
+ nand->col = 1;
+ break;
+ case 2048:
+ pNFCRegs->NFCR12 |= PAGE_2K;
+ nand->col = 2;
+ break;
+ case 4096:
+ pNFCRegs->NFCR12 |= PAGE_4K;
+ nand->col = 2;
+ break;
+ case 8192:
+ pNFCRegs->NFCR12 |= PAGE_8K;
+ nand->col = 2;
+ break;
+ case 16384:
+ pNFCRegs->NFCR12 |= PAGE_16K;
+ nand->col = 2;
+ break;
+ case 32768:
+ pNFCRegs->NFCR12 |= PAGE_32K;
+ nand->col = 2;
+ break;
+ default:
+ return 0;
+ }
+ nand->col = (nand->oobblock > 512) ? 2 : 1;
+ nand->pageadrlen = nand->row = nand->dwAddressCycle - nand->col;
+ if (nand->bus16)
+ pNFCRegs->NFCR12 |= WIDTH_16;
+
+ rc = set_ecc_info(nand);
+ if (rc)
+ return 1;
+
+ return 0;
+}
+
+/* Nand_IdentChip: Identify a given NAND chip given {floor,chip} */
+static int Nand_IdentChip(struct nand_chip *nand, int floor, int chip)
+{
+ unsigned int mfr, id, i, found = 0, id_5th = 0;
+ unsigned char ids[8], chip_off = chip;
+ unsigned int id0;
+ int rc = -1;
+ char *s = NULL;
+ unsigned int varlen = 0;
+
+ pNFCRegs->NFCR11 = 0; /* reset nfc*/
+ pNFCRegs->NFCRd = 0;
+ if (chip_off == 0) {
+ pNFCRegs->NFCR12 = 0xFF00|PAGE_2K|WP_DISABLE|DIRECT_MAP;
+ pNFCRegs->NFCR14 = 0x3636;/* in case of margine short */
+ }
+ NAND_ENABLE_CE(nand, chip_off); /* set pin low */
+ /* Reset the chip */
+ rc = wmt_nand_reset();
+ if (rc)
+ return 0;
+
+#if 0 /* dannier mark open source start */
+/*************************************************************************/
+ if (NanD_Command(nand, NAND_CMD_RESET)) {
+#ifdef NAND_DEBUG
+ printf("NanD_Command (reset) for %d,%d returned true\n",
+ floor, chip);
+#endif
+ NAND_DISABLE_CE(nand); /* set pin high */
+ return 0;
+ }
+
+ /* Read the NAND chip ID: 1. Send ReadID command */
+ if (NanD_Command(nand, NAND_CMD_READID)) {
+#ifdef NAND_DEBUG
+ printf("NanD_Command (ReadID) for %d,%d returned true\n",
+ floor, chip);
+#endif
+ NAND_DISABLE_CE(nand); /* set pin high */
+ return 0;
+ }
+
+ /* Read the NAND chip ID: 2. Send address byte zero */
+ NanD_Address(nand, ADDR_COLUMN, 0);
+
+ /* Read the manufacturer and device id codes from the device */
+
+ mfr = READ_NAND(nand->IO_ADDR);
+
+ id = READ_NAND(nand->IO_ADDR);
+/*************************************************************************/
+#endif /* dannier mark open source end */
+
+ rc = nand_readID(ids);
+ if (rc) {
+ printf("get id failed\n");
+ return 0;
+ }
+ mfr = ids[0];
+ id0 = (ids[0]<<24) + (ids[1]<<16) + (ids[2]<<8) + (ids[3]);
+ id = (ids[1]<<16) + (ids[2]<<8) + ids[3];
+ id_5th = (ids[4]<<24) + (ids[5]<<16) /*+ (ids[6]<<8) + ids[7]*/;
+
+ NAND_DISABLE_CE(nand); /* set pin high */
+//#ifdef NAND_DEBUG
+ printf("NanD_Command (ReadID) got %x %x %x %x\n", mfr,id0, id, id_5th);
+//#endif
+ if (mfr == 0xff || mfr == 0) {
+ /* No response - return failure */
+ return 0;
+ }
+
+ /* Check it's the same as the first chip we identified.
+ * M-Systems say that any given nand_chip device should only
+ * contain _one_ type of flash part, although that's not a
+ * hardware restriction. */
+ if (nand->mfr) {
+ if (((mfr << 24) + id) == nand->id) {
+ return 1; /* This is another the same the first */
+ } else {
+ printf("Flash chip at floor %d, chip %d is different:\n",
+ floor, chip);
+ }
+ }
+ /*-------identify by env start-----------*/
+ for (i = 0; WMT_nand_flash_ids[i].dwFlashID != 0; i++)
+ if (id0 == WMT_nand_flash_ids[i].dwFlashID) {
+ if (WMT_nand_flash_ids[i].dwFlashID == 0x98D79432)
+ if (id_5th != WMT_nand_flash_ids[i].dwFlashID2)
+ continue;
+ found = 1;
+ printf("got nand id from id list\n");
+ break;
+ }
+
+ if ((*((volatile unsigned int *)(0xd8110100))&0x4008) == 0x4000)/* sf boot,nand active */
+ s = getenv("wmt.io.nand");
+ if (s != NULL) {
+ rc = get_nand_info_from_env(nand, s, id, id_5th);
+ if (rc && found == 0)
+ return 0;
+ else if (rc == 0) {
+ printf("use env [nand id] info\n");
+ return 1;
+ }
+ }
+
+ if (found == 0) {
+ /* We haven't fully identified the chip. Print as much as we know. */
+ printf("Unknown flash chip found: %2.2X %2.2X\n", id0, id_5th);
+ return 0;
+ }
+ /*-------identify by env end----------*/
+
+ /* Print and store the manufacturer and ID codes. */
+ for (i = 0; WMT_nand_flash_ids[i].dwFlashID != 0; i++) {
+ if ((id0 == WMT_nand_flash_ids[i].dwFlashID)){
+
+ if((WMT_nand_flash_ids[i].dwFlashID != 0x98DE9493) ){
+ if ((id_5th != WMT_nand_flash_ids[i].dwFlashID2)) {
+ continue;
+ }
+ }
+
+#ifdef NAND_DEBUG
+ printf("Flash chip found:\n\t Manufacturer ID: 0x%2.2X, "
+ "Chip ID: 0x%2.2X (%s)\n", mfr, id,
+ WMT_nand_flash_ids[i].ProductName);
+#endif
+ if (!nand->mfr) {
+ if ( (WMT_nand_flash_ids[i].dwFlashID == 0x2C64444B && WMT_nand_flash_ids[i].dwFlashID2 == 0xA9000000)||//MT29F64G08CBABA
+ (WMT_nand_flash_ids[i].dwFlashID == 0xADDE94EB && WMT_nand_flash_ids[i].dwFlashID2 == 0x74440000)//H27UCG8T2BTR-F20
+ ){
+ s = getenv("wmt.nand.ecc");
+ if (s != NULL) {
+ varlen = simple_strtoul(s, NULL, 10);
+ if (varlen > WMT_nand_flash_ids[i].dwECCBitNum) {
+ if (varlen > 60)
+ varlen = 60;
+ WMT_nand_flash_ids[i].dwECCBitNum = varlen;
+ printf("wmt.nand.ecc=%d\n", varlen);
+ }
+ }
+ }
+
+ if (WMT_nand_flash_ids[i].dwECCBitNum == 60) {//implement 6K/14K page with 60bit ecc
+ if (WMT_nand_flash_ids[i].dwPageSize == 8192) {
+ nand->oobblock_valid = (WMT_nand_flash_ids[i].dwPageSize*3)/4; // ==> (X*6)/8
+ nand->erasesize_valid = (WMT_nand_flash_ids[i].dwBlockSize*3)/4; // ==> (X*6)/8
+ nand->page_shift = 10;
+ nand->oobblock_K = nand->oobblock_valid/1024;
+ } else if (WMT_nand_flash_ids[i].dwPageSize == 16384) {
+ nand->oobblock_valid = (WMT_nand_flash_ids[i].dwPageSize*7)/8; // ==> (X*14)/16
+ nand->erasesize_valid = (WMT_nand_flash_ids[i].dwBlockSize*7)/8; // ==> (X*14)/16
+ nand->page_shift = 10;
+ nand->oobblock_K = nand->oobblock_valid/1024;
+ } else {
+ printf("(page size not support 60 bit!)\n");
+ }
+ } else {
+ nand->oobblock_valid = WMT_nand_flash_ids[i].dwPageSize;
+ nand->erasesize_valid = WMT_nand_flash_ids[i].dwBlockSize;
+ nand->page_shift = shift_bit(WMT_nand_flash_ids[i].dwPageSize);
+ nand->oobblock_K = 1;
+ }
+
+ memcpy(nand, &WMT_nand_flash_ids[i], sizeof(struct WMT_nand_flash_dev));
+
+ nand->mfr = mfr;
+ nand->id = id0;
+ nand->id2 = WMT_nand_flash_ids[i].dwFlashID2;
+ nand->chipshift = shift_bit(WMT_nand_flash_ids[i].dwBlockCount) +
+ shift_bit(WMT_nand_flash_ids[i].dwBlockSize); // no use when use 60ecc with 6K !!!!!!
+ nand->page256 = 0;//nand_flash_ids[i].page256;
+ nand->eccsize = 512;//256;
+
+ nand->oobblock = WMT_nand_flash_ids[i].dwPageSize;
+ nand->erasesize = WMT_nand_flash_ids[i].dwBlockSize;//nand_flash_ids[i].erasesize;
+
+ nand->oobsize = WMT_nand_flash_ids[i].dwSpareSize;
+ nand->chips_name = WMT_nand_flash_ids[i].ProductName;
+ nand->bus16 = WMT_nand_flash_ids[i].dwDataWidth;
+ nand->dwPageCount = WMT_nand_flash_ids[i].dwBlockSize/WMT_nand_flash_ids[i].dwPageSize;
+
+ /* support TOSHIBA DDR mode "TC58NVG6DCJTA00" */
+ if (nand->mfr==NAND_TOSHIBA && nand->dwDDR==2) {
+ printf("@@DDR=2!\n");
+ nand->dwDDR = 2; // 2: means default support ddr( no need to set feature again)
+ } else {
+ printf("@@DDR=0!\n");
+ nand->dwDDR = 0; // u-boot tmp only support TOSHIBA's DDR mode
+ }
+
+ nand->IO_ADDR = __NFC_BASE;
+ nand->nfc_read_page = nfc_BCH_read_page;
+ if (((PLANE2_READ|PLANE2_PROG|PLANE2_ERASE) & nand->dwSpeedUpCmd)
+ == (PLANE2_READ|PLANE2_PROG|PLANE2_ERASE)) {
+ nand->realplanenum = 1;
+ printf("\n ****realplanenum**** is %d",nand->realplanenum);
+ } else
+ nand->realplanenum = 0;
+ nand->l_oobblock = nand->oobblock_valid*(nand->realplanenum?2:1);
+ nand->l_erasesize = nand->erasesize_valid*(nand->realplanenum?2:1);
+ printf("@@ WMT_nand_flash_ids[i].dwPageSize=%d,WMT_nand_flash_ids[i].dwBlockSize=0x%x\n",WMT_nand_flash_ids[i].dwPageSize,WMT_nand_flash_ids[i].dwBlockSize);
+ printf("@@ nand->oobblock=%d,nand->erasesize=0x%x,nand->oobblock_K=%d,nand->page_shift=%d\n",nand->oobblock,nand->erasesize,nand->oobblock_K,nand->page_shift);
+ printf("@@ nand->oobblock_valid=%d !,nand->erasesize_valid=0x%x !\n",nand->oobblock_valid,nand->erasesize_valid);
+ printf("@@ nand->dwPageCount=%d\n",nand->dwPageCount);
+ printf("@@ nand->dwECCBitNum=%d\n",nand->dwECCBitNum);
+ printf("@@ nand->l_oobblock=%d\n",nand->l_oobblock);
+ printf("@@ nand->l_erasesize=%d\n",nand->l_erasesize);
+ wmt_get_timing(nand, (unsigned int)WMT_nand_flash_ids[i].dwRWTimming,
+ (unsigned int)WMT_nand_flash_ids[i].dwTwbTwhrTadl);
+ /*-------------move from cmd_nandrw.c below-----------------*/
+ pNFCRegs->NFCR12 = 0xFF00 | WP_DISABLE | DIRECT_MAP;
+
+ switch (nand->oobblock) {
+ case 512:
+ pNFCRegs->NFCR12 |= PAGE_512;
+ nand->col = 1;
+ break;
+ case 2048:
+ pNFCRegs->NFCR12 |= PAGE_2K;
+ nand->col = 2;
+ break;
+ case 4096:
+ if (nand->dwECCBitNum == 60)
+ pNFCRegs->NFCR12 |= PAGE_2K;
+ else
+ pNFCRegs->NFCR12 |= PAGE_4K;
+ nand->col = 2;
+ break;
+ case 8192:
+ pNFCRegs->NFCR12 |= PAGE_8K;
+ nand->col = 2;
+ break;
+ case 16384:
+ pNFCRegs->NFCR12 |= PAGE_16K;
+ nand->col = 2;
+ break;
+ case 32768:
+ pNFCRegs->NFCR12 |= PAGE_32K;
+ nand->col = 2;
+ break;
+ default:
+ return 0;
+ }
+ nand->pageadrlen = nand->row = WMT_nand_flash_ids[i].dwAddressCycle - nand->col;
+ if (nand->bus16)
+ pNFCRegs->NFCR12 |= WIDTH_16;
+
+ /* set DDR feature */
+ if(nand->dwDDR) {
+ /* no set feature code because we only support TOSHIBA TC58NVG6DCJTA00(default DDR mode) */
+ printf("@@DDR setting!!\n");
+ //disable_hw_rdmz(nand);
+ pNFCRegs->NFCR14 = 0x0101;
+ pNFCRegs->NFCR7 = 0x7f;
+ pNFCRegs->NFCR12 |= TOGGLE;
+ }
+
+ rc = set_ecc_info(nand);
+ if (rc)
+ return 0;
+
+ return 1;
+ }
+ return 0;
+ }
+ }
+ /* We haven't fully identified the chip. Print as much as we know. */
+ printf("Unknown flash chip found: %2.2X %2.2X\n", id0, id_5th);
+ return 0;
+}
+
+int wmt_calc_clock(struct nand_chip *nand, unsigned int spec_clk, unsigned int spec_tadl, struct NFC_RW_T *nfc_rw)
+{
+ unsigned int i, div1=0, clk1, clk = 0, PLLB;
+ unsigned int tREA, tREH, tADL, tWP, divisor = 11, tWH, tWB, tWHR;
+
+ /*print_nand_register(mtd);*/
+ PLLB = *(volatile unsigned int *)PMPMB_ADDR;
+ PLLB = (2*(((PLLB>>16)&0x7F)+1))/((((PLLB>>8)&0x1F)+1)*(1<<(PLLB&3)));
+ #ifdef CONFIG_EMU
+ printf("PLLB=0x%x, spec_clk=0x%x\n", PLLB, spec_clk);
+ #endif
+ tREA = (spec_clk>>24)&0xFF;
+ tREH = (spec_clk>>16)&0xFF;
+ tWP = (spec_clk>>8)&0xFF;
+ tWH = spec_clk&0xFF;
+ tWB = (spec_tadl>>24)&0xFF;
+ tWHR = (spec_tadl>>16)&0xFF;
+ tADL = spec_tadl&0xFFFF;
+ for (i = 1; i < 16; i++) {
+ if (MAX_SPEED_MHZ >= (PLLB*SOURCE_CLOCK)/i) {
+ div1 = i;
+ break;
+ }
+ }
+
+ for (i = div1; i < 32; i++) {
+ clk1 = (10000 * i)/(PLLB*SOURCE_CLOCK);
+ if ((2*clk1) >= ((tREA+10)*10+15)) {
+ divisor = i;
+ clk = clk1/10;
+ //printk("div=%d tREA=%d 2*clk=%d\n", i, (tREA+10)*10+15, clk*2);
+ break;
+ }
+ }
+ nfc_rw->T_R_hold = 1;
+ nfc_rw->T_R_setup = 1;
+ nfc_rw->divisor = divisor;
+ nfc_rw->T_W_hold = 1;
+ nfc_rw->T_W_setup = 1;
+
+ i = 0;
+ while ((i*clk) < tADL && i < 50)
+ i++;
+ nfc_rw->T_TADL = i;
+ i = 0;
+ while ((i*clk) < tWHR && i < 50)
+ i++;
+ nfc_rw->T_TWHR = i;
+ i = 0;
+ while ((i*clk) < tWB && i < 50)
+ i++;
+ nfc_rw->T_TWB = i;
+
+ nfc_rw->T_RHC_THC =
+ ((nfc_rw->T_R_hold&0xFF) << 12) +
+ (((nfc_rw->T_R_setup&0xFF) + (nfc_rw->T_R_hold&0xFF)) << 8) +
+ ((nfc_rw->T_W_setup&0xF) << 4) +
+ ((nfc_rw->T_W_setup + nfc_rw->T_W_hold)&0xF);
+
+ if ((MAX_SPEED_MHZ < (PLLB*SOURCE_CLOCK)/(divisor)) || clk == 0 || clk > 45)
+ return 1;
+
+ *(volatile unsigned long *)PMNAND_ADDR = (nfc_rw->divisor);
+ while ((*(volatile unsigned long *)PMCS_ADDR)&(0x7F0038))
+ ;
+
+ return 0;
+}
+
+#if 0
+int old_wmt_calc_clock(struct nand_chip *nand,
+unsigned int spec_clk,
+unsigned int spec_clk1,
+struct NFC_RW_T *nfc_rw)
+{
+ unsigned int i, div1=0, div2, clk1, clk2=0, comp, T_setup, T1=0, T2=0, clk, PLLB;
+ unsigned int tREA, tREH, Thold, Thold2, Ttmp, tADL, tWP, tWB, tWHR, tWH, divisor;
+
+ PLLB = *(volatile unsigned int *)PMPMB_ADDR;
+ PLLB = (2*(((PLLB>>16)&0x7F)+1))/((((PLLB>>8)&0x1F)+1)*(1<<(PLLB&3)));
+ #ifdef CONFIG_EMU
+ printf("PLLB=0x%x, spec_clk=0x%x\n", PLLB, spec_clk);
+ #endif
+ tREA = (spec_clk>>24)&0xFF;
+ tREH = (spec_clk>>16)&0xFF;
+ tWP = (spec_clk>>8)&0xFF;
+ tWH = spec_clk&0xFF;
+
+ tWB = (spec_clk1>>24)&0xFF;
+ tWHR = (spec_clk1>>16)&0xFF;
+ tADL = spec_clk1&0xFFFF;
+ for (i = 1; i < 16; i++) {
+ if (MAX_SPEED_MHZ >= (PLLB*SOURCE_CLOCK)/i) {
+ div1 = i;
+ break;
+ }
+ }
+
+ clk1 = (1000 * div1)/(PLLB*SOURCE_CLOCK);
+ //printf("clk1=%d, div1=%d, spec_clk=%d\n", clk1, div1, spec_clk);
+ for (T1 = 1; T1 < 10; T1++) {
+ if ((T1*clk1) >= (tREA + MAX_READ_DELAY))
+ break;
+ }
+ i = 1;
+ while (i*clk1 <= tREH) {
+ i++;
+ }
+ Thold = i;
+ #ifdef CONFIG_EMU
+ printf("T1=%d, clk1=%d, div1=%d, Thold=%d, tREA=%d+delay(15)\n", T1, clk1, div1, Thold, tREA);
+ #endif
+ Ttmp = T_setup = T1;
+ clk = clk1;
+ divisor = div1;
+ div2 = div1;
+ while (Ttmp > 1 && clk != 0) {
+ div2++;
+ clk2 = (1000 * div2)/(PLLB*SOURCE_CLOCK);
+ comp = 0;
+ for (T2 = 1; T2 < Ttmp; T2++) {
+ if ((T2*clk2) >= (tREA + MAX_READ_DELAY)) {
+ Ttmp = T2;
+ comp = 1;
+ i = 1;
+ while (i*clk2 <= tREH) {
+ i++;
+ }
+ Thold2 = i;
+ #ifdef CONFIG_EMU
+ printf("T2=%d, clk2=%d, div2=%d, Thold2=%d, comp=1\n", T2, clk2, div2, Thold2);
+ #endif
+ break;
+ }
+ }
+ if (comp == 1) {
+ clk1 = clk * (T_setup+Thold) * nand->oobblock;
+ div1 = clk2 * (T2+Thold2) * nand->oobblock;
+ #ifdef CONFIG_EMU
+ printf("Tim1=%d , Tim2=%d\n", clk1, div1);
+ #endif
+ if ((clk * (T_setup+Thold) * nand->oobblock) > (clk2 * (T2+Thold2) * nand->oobblock)) {
+ T_setup = T2;
+ clk = clk2;
+ divisor = div2;
+ Thold = Thold2;
+ } else {
+ #ifdef CONFIG_EMU
+ printf("T2 is greater and not use\n");
+ #endif
+ }
+ }
+ } /* end of while */
+ nfc_rw->T_R_hold = Thold;
+ nfc_rw->T_R_setup = T_setup;
+ nfc_rw->divisor = divisor;
+
+ i = 1;
+ nfc_rw->T_W_setup = 0x1; /* set write setup time */
+ while ((i*clk) <= (tWP+MAX_WRITE_DELAY)) {
+ nfc_rw->T_W_setup += 1;
+ i++;
+ }
+
+ i = 1;
+ nfc_rw->T_W_hold = 0x1; /* set write hold time */
+ while ((i*clk) <= tWH) {
+ nfc_rw->T_W_hold += 1;
+ i++;
+ }
+
+ i = 1;
+ while ((i*clk) < tADL && i < 60) {
+ i++;
+ }
+ nfc_rw->T_TADL = i;
+
+ i = 1;
+ while ((i*clk) < tWHR && i < 18) {
+ i++;
+ }
+ nfc_rw->T_TWHR = i;
+
+ i = 1;
+ while ((i*clk) < tWB && i < 10) {
+ i++;
+ }
+ nfc_rw->T_TWB = i;
+
+ nfc_rw->T_RHC_THC =
+ ((nfc_rw->T_R_hold&0xFF) << 12) +
+ (((nfc_rw->T_R_setup&0xFF) + (nfc_rw->T_R_hold&0xFF)) << 8) +
+ ((nfc_rw->T_W_hold&0xFF) << 4) +
+ (nfc_rw->T_W_hold&0xFF)*2;
+
+ #ifdef CONFIG_EMU
+ printf("T=0x%x, clk=%d ns, divisor=%d\n", nfc_rw->T_RHC_THC, clk, divisor);
+ #endif
+ if ((MAX_SPEED_MHZ < (PLLB*SOURCE_CLOCK)/(divisor)) || clk == 0 || T_setup == 0 || clk > 45)
+ return 1;
+
+ *(volatile unsigned long *)PMNAND_ADDR = (nfc_rw->divisor);
+ while ((*(volatile unsigned long *)PMCS_ADDR)&(0x7F0038))
+ ;
+
+ return 0;
+}
+#endif
+
+int wmt_get_timing(struct nand_chip *nand, unsigned int spec_clk, unsigned int spec_clk1)
+{
+ unsigned int divisor;
+ struct NFC_RW_T nfc_rw;
+ int status;
+
+ status = wmt_calc_clock(nand, spec_clk, spec_clk1, &nfc_rw);
+ if (status) {
+ printf("timming setting fail");
+ return 1;
+ }
+ divisor = *(volatile unsigned long *)PMNAND_ADDR;
+ printf("TWB=%dT, tWHR=%dT, tadl=%dT, div=0x%x, (RH/RC/WH/WC)=0x%x\n",
+ nfc_rw.T_TWB, nfc_rw.T_TWHR, nfc_rw.T_TADL, divisor, nfc_rw.T_RHC_THC);
+
+ pNFCRegs->NFCRe = (nfc_rw.T_TWB<<16) + (nfc_rw.T_TWHR<<8) + nfc_rw.T_TADL;
+ pNFCRegs->NFCR14 = 0x2424;//nfc_rw.T_RHC_THC; /* set r/w cycle */
+
+ switch(nand->dwFlashID) {
+ case 0x2C88044B:
+ case 0x2C68044A:
+ case 0x2C64444B:
+ case 0x2C48044A:
+ divisor = 9;
+ break;
+ }
+
+ *(volatile unsigned long *)PMNAND_ADDR = (divisor&0x1FF);
+ while ((*(volatile unsigned long *)PMCS_ADDR)&(0x7F0038))
+ ;
+
+ return 0;
+}
+
+/* NanD_ScanChips: Find all NAND chips present in a nand_chip, and identify them */
+
+static void Nand_ScanChips(struct nand_chip *nand)
+{
+ int floor, chip;
+ int numchips[NAND_MAX_FLOORS];
+ int maxchips = NAND_MAX_CHIPS;
+ int ret = 1;
+
+ nand->numchips = 0;
+ nand->mfr = 0;
+ nand->id = 0;
+
+
+ /* For each floor, find the number of valid chips it contains */
+ for (floor = 0; floor < NAND_MAX_FLOORS; floor++) {
+ ret = 1;
+ numchips[floor] = 0;
+ for (chip = 0; chip < maxchips && ret != 0; chip++) {
+
+ ret = Nand_IdentChip(nand, floor, chip);
+ if (ret) {
+ numchips[floor]++;
+ nand->numchips++;
+ } else
+ break;
+ }
+ }
+
+ /* If there are none at all that we recognise, bail */
+ if (!nand->numchips) {
+//#ifdef NAND_DEBUG
+ puts ("No NAND flash chips recognised.\n");
+//#endif
+ return;
+ }
+
+ /* Allocate an array to hold the information for each chip */
+ nand->chips = malloc(sizeof(struct Nand) * nand->numchips);
+ if (!nand->chips) {
+ puts ("No memory for allocating chip info structures\n");
+ return;
+ }
+
+ ret = 0;
+
+ /* Fill out the chip array with {floor, chipno} for each
+ * detected chip in the device. */
+ for (floor = 0; floor < NAND_MAX_FLOORS; floor++) {
+ for (chip = 0; chip < numchips[floor]; chip++) {
+ nand->chips[ret].floor = floor;
+ nand->chips[ret].chip = chip;
+ nand->chips[ret].curadr = 0;
+ nand->chips[ret].curmode = 0x50;
+ ret++;
+ }
+ }
+
+ /* Calculate and print the total size of the device */
+
+ //nand->totlen = nand->numchips * ((long long)1 << nand->chipshift); //Henry mark
+
+ if (nand->dwECCBitNum==60)
+ nand->totlen = nand->numchips * (long long)(((nand->oobblock_K<<10)<<shift_bit(nand->dwPageCount))<<shift_bit(nand->dwBlockCount));
+ else
+ nand->totlen = nand->numchips * ((long long)1 << nand->chipshift); //Henry mark
+
+ printf("@@ nand->numchips=%d,nand->oobblock_K<<10=%d,shift_bit(nand->dwPageCount)=%d,shift_bit(nand->dwBlockCount)=%d\n",nand->numchips,nand->oobblock_K<<10,shift_bit(nand->dwPageCount),shift_bit(nand->dwBlockCount));
+
+ //nand->totlen = (long long)nand->dwBlockCount * (long long)nand->dwBlockSize;
+
+#ifdef WMT_SW_RDMZ
+ if(nand->dwRdmz) {
+ rdmz_buf = malloc(nand->oobblock);
+ rdmz_buf0= malloc(nand->oobblock);
+ rdmz_buf1= malloc(nand->oobblock);
+ if(rdmz_buf == NULL || rdmz_buf0 == NULL || rdmz_buf1 == NULL)
+ printf("randomizer buffer malloc fail.\n");
+ }
+#endif
+
+ rdmz_buf = malloc(nand->oobblock);
+ if (rdmz_buf == NULL)
+ printf("randomizer buffer malloc fail.\n");
+
+ data_buf = malloc(nand->oobblock);
+ if (data_buf == NULL)
+ printf("data buffer malloc fail.\n");
+
+ if (nand->dwSpeedUpCmd)
+ printf("nand support speed up cmd=0x%x\n", nand->dwSpeedUpCmd);
+
+ printf("%d flash chips found. Total nand size: %ld MB\n",
+ nand->numchips, nand->totlen >> 20);
+}
+#if 0 /* original code not support start */
+/* we need to be fast here, 1 us per read translates to 1 second per meg */
+static void NanD_ReadBuf (struct nand_chip *nand, u_char * data_buf, int cntr)
+{
+ unsigned long nandptr = nand->IO_ADDR;
+
+ //NanD_Command (nand, NAND_CMD_READ0);
+
+ if (nand->bus16) {
+ u16 val;
+
+ while (cntr >= 16) {
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ cntr -= 16;
+ }
+
+ while (cntr > 0) {
+ val = READ_NAND (nandptr);
+ *data_buf++ = val & 0xff;
+ *data_buf++ = val >> 8;
+ cntr -= 2;
+ }
+ } else {
+ while (cntr >= 16) {
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ *data_buf++ = READ_NAND (nandptr);
+ cntr -= 16;
+ }
+
+ while (cntr > 0) {
+ *data_buf++ = READ_NAND (nandptr);
+ cntr--;
+ }
+ }
+}
+#endif
+/*
+* nand_transfer_oob(nand, oob, toread)
+*/
+static unsigned char *nand_fill_oob(struct nand_chip *nand, unsigned char *oob, size_t len)
+{
+ struct nand_oobfree *free = nand->ecc.layout->oobfree;
+ unsigned int boffs = 0, woffs = 0;
+ size_t bytes = 0;
+
+ for (; free->length && len; free++, len -= bytes) {
+ /* Write request not from offset 0 ? */
+ if (woffs) {
+ if (woffs >= free->length) {
+ woffs -= free->length;
+ continue;
+ }
+ boffs = free->offset + woffs;
+ bytes = min(len,(free->length - woffs));
+ woffs = 0;
+ } else {
+ bytes = min(len, free->length);
+ boffs = free->offset;
+ }
+ memcpy(nand->oob_poi + boffs, oob, bytes);
+ oob += bytes;
+ }
+
+ return oob;
+}
+static unsigned char *nand_transfer_oob(struct nand_chip *nand, unsigned char *oob, size_t len)
+{
+ struct nand_oobfree *free = nand->ecc.layout->oobfree;
+ unsigned int boffs = 0, roffs = 0;
+ size_t bytes = 0;
+
+ for(; free->length && len; free++, len -= bytes) {
+
+ if (roffs) {
+ if (roffs >= free->length) {
+ roffs -= free->length;
+ continue;
+ }
+ boffs = free->offset + roffs;
+ bytes = min(len,(free->length - roffs));
+ roffs = 0;
+ } else {
+ bytes = min(len, free->length);
+ boffs = free->offset;
+ }
+ memcpy(oob, nand->oob_poi + boffs, bytes);
+ if (boffs!= 0)
+ printf("boffs=%d, byte=%d \n", boffs, bytes);
+ oob += bytes;
+ }
+ return oob;
+
+}
+
+static int wmt_nand_read_oob(struct nand_chip *nand, size_t ofs)
+{
+ int ret = 0;
+ int pos = 0;
+ struct ECC_size_info ECC_size;
+
+ ECC_size.ecc_engine = pNFCRegs->NFCR9&ECC_MOD_SEL;
+ // ECC_size.ecc_engine = 1;
+ calculate_ECC_info(nand, &ECC_size);
+
+ if (nand->oobblock >= 2048) {
+// printf("\n ECC_bytes is %d, oob_max_bit_error is %d, oob_ECC_bytes is %d",
+// ECC_size.ECC_bytes, ECC_size.oob_max_bit_error, ECC_size.oob_ECC_bytes);
+// pNFCRegs->NFCR8|= nand->oobsize-1;
+// pNFCRegs->NFCR9 |= 0x2;
+ pos = nand->oobblock + (ECC_size.ECC_bytes * (ECC_size.banks-1));
+// pos = nand->ecc.size * nand->ecc.steps + 8*4;
+ nand->col_offset = pos;
+ ret = nand->nfc_read_page(nand, ofs,
+ (unsigned int)nand->oob_poi, 32);
+ nand->col_offset = 0;
+// memcpy(nand->oob_poi, nand->data_buf, 32);
+// ret = nand->nfc_read_page(nand, ofs,
+ // (unsigned int)nand->data_buf, nand->oobblock);
+
+// memcpy(nand->oob_poi, (unsigned char *)&pNFCRegs->FIFO[0], 32);
+
+ } else {
+ ret = nand->nfc_read_page(nand, ofs,
+ (unsigned int)nand->data_buf, nand->oobblock);
+
+ memcpy(nand->oob_poi, (unsigned char *)&pNFCRegs->FIFO[0], 16);
+ }
+
+ if (ret) {
+ printf("Read oob failed ret=%d at addr %x\n", ret, ofs);
+ return ret;
+ }
+ if (nand->oobblock >= 2048)
+ pNFCRegs->NFCR9 &= 0xFFFFFFFD;
+
+ return ret;
+}
+/*
+*nand_do_read_oob
+*/
+static int nand_do_read_oob(struct nand_chip *nand, size_t start, size_t ooblen,
+ size_t *retooblen, u_char *oob)
+{
+ int page, ret;
+ int readlen = ooblen;
+ int len;
+ u_char *buf = oob;
+
+ len = nand->ecc.layout->oobavail;
+ page = start >> nand->page_shift;
+
+// printf("\n nand do read oob");
+
+ while(1) {
+
+ ret = wmt_nand_read_oob(nand, page);
+ len = min (len, readlen);
+ buf = nand_transfer_oob(nand, buf, len);
+
+ readlen -= len;
+
+ if(!readlen) break;
+
+ page++;
+ }
+ *retooblen = ooblen;
+ return ret;
+}
+/*
+* wmt_nand_write_oob
+*/
+static int wmt_write_oob(struct nand_chip *nand, size_t ofs)
+{
+ int pos;
+ u_char *bufpoi = nand->oob_poi;
+ unsigned long nandptr = nand->IO_ADDR;
+
+ pNFCRegs->NFCRb &= 0x08; /* write to clear*/
+
+ memcpy((unsigned char *)&pNFCRegs->FIFO[0], bufpoi, 32);
+ pos = nand->ecc.size * nand->ecc.steps + 8*4;
+
+ NanD_Address(nand, ADDR_COLUMN_PAGE, pos, ofs);
+
+ WRITE_NAND_COMMAND(NAND_CMD_SEQIN);
+ WRITE_NAND_COMMAND(NAND_CMD_PAGEPROG);
+
+ if (READ_NAND(nandptr) & 1) {
+ puts ("Error programming oob data\n");
+ /* There was an error */
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+* nand_do_write_oob
+*/
+static int nand_do_write_oob(struct nand_chip *nand, size_t start, size_t ooblen,
+ size_t *retooblen, u_char *oob)
+{
+ int page, ret;
+ int len = nand->ecc.layout->oobavail;
+ page = start >> nand->page_shift;
+
+ *retooblen = 0;
+
+
+ if (!(nand_read_status(nand, NAND_STATUS) & 0x80)) {
+ printf ("%s: Device is write protected!!!\n", __FUNCTION__);
+ ret = -1;
+ }
+
+ if (page == nand->pagebuf) nand->pagebuf = -1;
+
+ memset(nand->oob_poi, 0xff, nand->oobsize);
+ len = min(len, ooblen);
+ nand_fill_oob(nand, oob, len);
+ ret = wmt_write_oob(nand, page);
+ memset(nand->oob_poi, 0xff, nand->oobsize);
+
+ if(ret) {
+ return ret;
+ }
+
+ *retooblen = ooblen;
+
+
+ return 0;
+
+}
+/*
+* nand_do_write_ops
+*/
+
+static int nand_do_write_ops(struct nand_chip *nand, size_t start, size_t len,
+ size_t *retlen, u_char *buf, size_t ooblen, size_t *retooblen, u_char *oob)
+{
+ int page, col;
+ int writelen = len;
+ int oobwritelen = ooblen;
+ int ret = 0;
+
+ if(!writelen) return 0;
+
+// printf("\n nand_do_write_ops!");
+ page = start >> nand->page_shift;
+ col = start & (nand->oobblock - 1);
+
+ *retlen = 0;
+ *retooblen = 0;
+
+// printf("\n page is %d", page);
+ if (!(nand_read_status(nand, NAND_STATUS) & 0x80)) {
+ printf ("%s: Device is write protected!!!\n", __FUNCTION__);
+ ret = -1;
+ goto out;
+ }
+
+ if(!oob) memset(nand->oob_poi, 0xff, nand->oobsize);
+
+ while(1) {
+
+ int bytes = nand->oobblock;
+ unsigned char * wbuf = buf;
+
+ if(col || writelen < (nand->oobblock -1)) {
+ bytes = min(bytes - col, writelen);
+ memset(nand->buffers, 0xff, nand->oobblock);
+ memcpy(nand->buffers+col, buf, bytes);
+ wbuf = nand->buffers;
+ }
+
+
+ if(oob) {
+ int towrite = min(oobwritelen, nand->ecc.layout->oobavail);
+ memset(nand->oob_poi, 0xff, nand->oobsize);
+ oob = nand_fill_oob(nand, oob, towrite);
+ oobwritelen -= towrite;
+ }
+
+ memcpy(nand->data_buf, wbuf, nand->oobblock);
+ nand->oob_flag = 1;
+ nand_page_program(nand, page, (unsigned int)nand->data_buf, nand->oobblock);
+ nand->oob_flag = 0;
+ // oob
+
+ if (ret < 0 || ret & 0x01)
+ goto out;
+
+ writelen -= bytes;
+ if(!writelen) break;
+
+ /* Next data start at page boundary */
+ col = 0;
+ buf += bytes;
+ page++;
+
+ }//end while
+ *retlen = len - writelen;
+ if(oob)*retooblen = ooblen;
+out:
+ /* De-select the NAND device */
+
+#ifdef CONFIG_OMAP1510
+ archflashwp(0,1);
+#endif
+#ifdef CFG_NAND_WP
+ NAND_WP_ON();
+#endif
+
+ return ret;
+}
+/*
+*nand_do_read_ops
+*/
+
+static int nand_do_read_ops(struct nand_chip *nand, size_t start, size_t len,
+ size_t *retlen, u_char *buf, size_t ooblen, size_t *retooblen, u_char *oob)
+{
+ int col, page, bytes, aligned;
+ int readlen = len;
+ int oobreadlen = ooblen;
+ int ecc_error;
+ unsigned int ecc_failed = 0;
+
+ u_char *bufpoi;
+
+ page = start >> nand->page_shift;
+ col = start & (nand->oobblock -1);
+// printf("\n nand do read ops");
+ *retlen = 0;
+ *retooblen = 0;
+
+
+ while (1) {
+ bytes = min(nand->oobblock - col, readlen);
+ aligned = (bytes == nand->oobblock);
+
+ if( page != nand->pagebuf || oob) {
+
+ bufpoi = aligned ? buf : nand->buffers;
+
+ ecc_error = nand->nfc_read_page(nand, page, (unsigned int)nand->data_buf, nand->oobblock);
+
+ if(ecc_error) {
+ ecc_failed++;
+ }
+ memcpy(bufpoi, nand->data_buf, nand->oobblock);
+ memcpy(nand->oob_poi, (unsigned char *)&pNFCRegs->FIFO[0], 32);
+ //nand->nfc_read_page(nand, page, (unsigned int)nand->data_buf, nand->oobblock);
+ //memcpy(nand->oob_poi, (unsigned char *)&pNFCRegs->FIFO[0], 32);
+ if(!aligned) {
+ if(!oob && !ecc_failed)
+ nand->pagebuf = page;
+ memcpy(buf, nand->buffers + col, bytes);
+ }
+
+ buf += bytes;
+ if(oob) {
+ int toread = min(oobreadlen, nand->ecc.layout->oobavail);
+ if (toread) {
+ oob = nand_transfer_oob(nand, oob, toread);
+ oobreadlen -= toread;
+ }
+ }
+
+ } else {
+ memcpy(buf, nand->buffers + col, bytes);
+ buf += bytes;
+ }
+ readlen -= bytes;
+
+ if(!readlen) break;
+
+ col = 0;
+
+ page++;
+
+
+ }
+
+
+ *retlen = len - (size_t)readlen;
+
+ if(oob) *retooblen = ooblen - oobreadlen;
+
+
+ if(ecc_failed) return -67;
+
+ return 0;
+}//look like there is something wrong
+
+
+#if 0
+/*
+ * NAND read with ECC
+ */
+static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len,
+ size_t * retlen, u_char *buf, u_char *ecc_code)
+{
+ int col, page;
+ int ecc_status = 0;
+#ifdef CONFIG_MTD_NAND_ECC
+ int j;
+ int ecc_failed = 0;
+ u_char *data_poi;
+ /*u_char ecc_calc[6];*/
+#endif
+
+ /* Do not allow reads past end of device */
+ if ((start + len) > nand->totlen) {
+ printf ("%s: Attempt read beyond end of device %x %x %x\n",
+ __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen);
+ *retlen = 0;
+ return -1;
+ }
+
+ /* First we calculate the starting page */
+ /*page = shr(start, nand->page_shift);*/
+ page = start >> nand->page_shift;
+
+ /* Get raw starting column */
+ col = start & (nand->oobblock - 1);
+
+ /* Initialize return value */
+ *retlen = 0;
+
+ /* Select the NAND device */
+ NAND_ENABLE_CE(nand, 0); /* set pin low */
+
+ /* Loop until all data read */
+ while (*retlen < len) {
+
+#ifdef CONFIG_MTD_NAND_ECC
+ /* Do we have this page in cache ? */
+ if (nand->cache_page == page)
+ goto readdata;
+ /* Send the read command */
+ //NanD_Command(nand, NAND_CMD_READ0);
+ /*if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }*/
+
+ /* Read in a page + oob data */
+ /*NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize);*/
+ j = nand->nfc_read_page(nand, (page<<nand->page_shift), (unsigned int)nand->data_buf, nand->oobblock);
+ if (j)
+ ecc_failed++;
+ /* copy data into cache, for read out of cache and if ecc fails */
+ if (nand->data_cache) {
+ memcpy (nand->data_cache, nand->data_buf,
+ nand->oobblock + nand->oobsize);
+ }
+
+ /* Pick the ECC bytes out of the oob data */
+ for (j = 0; j < 6; j++) {
+ ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])];
+ }
+
+ /* Calculate the ECC and verify it */
+ /* If block was not written with ECC, skip ECC */
+ #if 0
+ if (oob_config.eccvalid_pos != -1 &&
+ (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0x0f) != 0x0f) {
+
+ nand_calculate_ecc (&nand->data_buf[0], &ecc_calc[0]);
+ switch (nand_correct_data (&nand->data_buf[0], &ecc_code[0], &ecc_calc[0])) {
+ case -1:
+ printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);
+ ecc_failed++;
+ break;
+ case 1:
+ case 2: /* transfer ECC corrected data to cache */
+ if (nand->data_cache)
+ memcpy (nand->data_cache, nand->data_buf, 256);
+ break;
+ }
+ }
+
+ if (oob_config.eccvalid_pos != -1 &&
+ nand->oobblock == 512 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) {
+
+ nand_calculate_ecc (&nand->data_buf[256], &ecc_calc[3]);
+ switch (nand_correct_data (&nand->data_buf[256], &ecc_code[3], &ecc_calc[3])) {
+ case -1:
+ printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);
+ ecc_failed++;
+ break;
+ case 1:
+ case 2: /* transfer ECC corrected data to cache */
+ if (nand->data_cache)
+ memcpy (&nand->data_cache[256], &nand->data_buf[256], 256);
+ break;
+ }
+ }
+ #endif
+readdata:
+ /* Read the data from ECC data buffer into return buffer */
+ data_poi = (nand->data_cache) ? nand->data_cache : nand->data_buf;
+ data_poi += col;
+ if ((*retlen + (nand->oobblock - col)) >= len) {
+ memcpy (buf + *retlen, data_poi, len - *retlen);
+ *retlen = len;
+ } else {
+ memcpy (buf + *retlen, data_poi, nand->oobblock - col);
+ *retlen += nand->oobblock - col;
+ }
+ /* Set cache page address, invalidate, if ecc_failed */
+ nand->cache_page = (nand->data_cache && !ecc_failed) ? page : -1;
+
+ ecc_status += ecc_failed;
+ ecc_failed = 0;
+/*#else*/
+#if 0
+ /* Send the read command */
+ //NanD_Command(nand, NAND_CMD_READ0);
+ if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+
+ /* Read the data directly into the return buffer */
+ if ((*retlen + (nand->oobblock - col)) >= len) {
+ NanD_ReadBuf(nand, buf + *retlen, len - *retlen);
+ *retlen = len;
+ /* We're done */
+ continue;
+ } else {
+ NanD_ReadBuf(nand, buf + *retlen, nand->oobblock - col);
+ *retlen += nand->oobblock - col;
+ }
+#endif
+#endif
+ /* For subsequent reads align to page boundary. */
+ col = 0;
+ /* Increment page address */
+ page++;
+ }
+
+ /* De-select the NAND device */
+ NAND_DISABLE_CE(nand); /* set pin high */
+
+ /*
+ * Return success, if no ECC failures, else -EIO
+ * fs driver will take care of that, because
+ * retlen == desired len and result == -EIO
+ */
+ return ecc_status ? -1 : 0;
+}
+
+/*
+ * Nand_page_program function is used for write and writev !
+ */
+static int nand_write_page (struct nand_chip *nand,
+ int page, int col, int last, u_char * ecc_code)
+{
+
+ int i;
+ unsigned long nandptr = nand->IO_ADDR;
+
+#ifdef CONFIG_MTD_NAND_ECC
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+ int ecc_bytes = (nand->oobblock == 512) ? 6 : 3;
+#endif
+#endif
+ /* pad oob area */
+ for (i = nand->oobblock; i < nand->oobblock + nand->oobsize; i++)
+ nand->data_buf[i] = 0xff;
+
+#ifdef CONFIG_MTD_NAND_ECC
+ /* Zero out the ECC array */
+ for (i = 0; i < 6; i++)
+ ecc_code[i] = 0x00;
+
+ /* Read back previous written data, if col > 0 */
+ if (col) {
+ NanD_Command (nand, NAND_CMD_READ0);
+ if (nand->bus16) {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+
+ if (nand->bus16) {
+ u16 val;
+
+ for (i = 0; i < col; i += 2) {
+ val = READ_NAND (nandptr);
+ nand->data_buf[i] = val & 0xff;
+ nand->data_buf[i + 1] = val >> 8;
+ }
+ } else {
+ for (i = 0; i < col; i++)
+ nand->data_buf[i] = READ_NAND (nandptr);
+ }
+ }
+
+ /* Calculate and write the ECC if we have enough data */
+ if ((col < nand->eccsize) && (last >= nand->eccsize)) {
+ nand_calculate_ecc (&nand->data_buf[0], &(ecc_code[0]));
+ for (i = 0; i < 3; i++) {
+ nand->data_buf[(nand->oobblock +
+ oob_config.ecc_pos[i])] = ecc_code[i];
+ }
+ if (oob_config.eccvalid_pos != -1) {
+ nand->data_buf[nand->oobblock +
+ oob_config.eccvalid_pos] = 0xf0;
+ }
+ }
+
+ /* Calculate and write the second ECC if we have enough data */
+ if ((nand->oobblock == 512) && (last == nand->oobblock)) {
+ nand_calculate_ecc (&nand->data_buf[256], &(ecc_code[3]));
+ for (i = 3; i < 6; i++) {
+ nand->data_buf[(nand->oobblock +
+ oob_config.ecc_pos[i])] = ecc_code[i];
+ }
+ if (oob_config.eccvalid_pos != -1) {
+ nand->data_buf[nand->oobblock +
+ oob_config.eccvalid_pos] &= 0x0f;
+ }
+ }
+#endif
+ /* Prepad for partial page programming !!! */
+ for (i = 0; i < col; i++)
+ nand->data_buf[i] = 0xff;
+
+ /* Postpad for partial page programming !!! oob is already padded */
+ for (i = last; i < nand->oobblock; i++)
+ nand->data_buf[i] = 0xff;
+
+ /* Send command to begin auto page programming */
+ //NanD_Command (nand, NAND_CMD_READ0);
+ //NanD_Command (nand, NAND_CMD_SEQIN);
+ if (nand->bus16) {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+
+ /* Write out complete page of data */
+ if (nand->bus16) {
+ for (i = 0; i < (nand->oobblock + nand->oobsize); i += 2) {
+ WRITE_NAND (nand->data_buf[i] +
+ (nand->data_buf[i + 1] << 8),
+ nand->IO_ADDR);
+ }
+ } else {
+ for (i = 0; i < (nand->oobblock + nand->oobsize); i++)
+ WRITE_NAND (nand->data_buf[i], nand->IO_ADDR);
+ }
+
+ /* Send command to actually program the data */
+ //NanD_Command (nand, NAND_CMD_PAGEPROG);
+ //NanD_Command (nand, NAND_CMD_STATUS);
+#ifdef NAND_NO_RB
+ {
+ u_char ret_val;
+
+ do {
+ ret_val = READ_NAND (nandptr); /* wait till ready */
+ } while ((ret_val & 0x40) != 0x40);
+ }
+#endif
+ /* See if device thinks it succeeded */
+ if (READ_NAND (nand->IO_ADDR) & 0x01) {
+ printf ("%s: Failed write, page 0x%08x, ", __FUNCTION__,
+ page);
+ return -1;
+ }
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+ /*
+ * The NAND device assumes that it is always writing to
+ * a cleanly erased page. Hence, it performs its internal
+ * write verification only on bits that transitioned from
+ * 1 to 0. The device does NOT verify the whole page on a
+ * byte by byte basis. It is possible that the page was
+ * not completely erased or the page is becoming unusable
+ * due to wear. The read with ECC would catch the error
+ * later when the ECC page check fails, but we would rather
+ * catch it early in the page write stage. Better to write
+ * no data than invalid data.
+ */
+
+ /* Send command to read back the page */
+ if (col < nand->eccsize)
+ NanD_Command (nand, NAND_CMD_READ0);
+ else
+ NanD_Command (nand, NAND_CMD_READ1);
+ if (nand->bus16) {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+
+ /* Loop through and verify the data */
+ if (nand->bus16) {
+ for (i = col; i < last; i = +2) {
+ if ((nand->data_buf[i] +
+ (nand->data_buf[i + 1] << 8)) != READ_NAND (nand->IO_ADDR)) {
+ printf ("%s: Failed write verify, page 0x%08x ",
+ __FUNCTION__, page);
+ return -1;
+ }
+ }
+ } else {
+ for (i = col; i < last; i++) {
+ if (nand->data_buf[i] != READ_NAND (nand->IO_ADDR)) {
+ printf ("%s: Failed write verify, page 0x%08x ",
+ __FUNCTION__, page);
+ return -1;
+ }
+ }
+ }
+
+#ifdef CONFIG_MTD_NAND_ECC
+ /*
+ * We also want to check that the ECC bytes wrote
+ * correctly for the same reasons stated above.
+ */
+ NanD_Command (nand, NAND_CMD_READOOB);
+ if (nand->bus16) {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + (col >> 1));
+ } else {
+ NanD_Address (nand, ADDR_COLUMN_PAGE,
+ (page << nand->page_shift) + col);
+ }
+ if (nand->bus16) {
+ for (i = 0; i < nand->oobsize; i += 2) {
+ u16 val;
+
+ val = READ_NAND (nand->IO_ADDR);
+ nand->data_buf[i] = val & 0xff;
+ nand->data_buf[i + 1] = val >> 8;
+ }
+ } else {
+ for (i = 0; i < nand->oobsize; i++) {
+ nand->data_buf[i] = READ_NAND (nand->IO_ADDR);
+ }
+ }
+ for (i = 0; i < ecc_bytes; i++) {
+ if ((nand->data_buf[(oob_config.ecc_pos[i])] != ecc_code[i]) && ecc_code[i]) {
+ printf ("%s: Failed ECC write "
+ "verify, page 0x%08x, "
+ "%6i bytes were succesful\n",
+ __FUNCTION__, page, i);
+ return -1;
+ }
+ }
+#endif /* CONFIG_MTD_NAND_ECC */
+#endif /* CONFIG_MTD_NAND_VERIFY_WRITE */
+ return 0;
+}
+#endif /* original code not support end*/
+#if 0
+static int nand_write_ecc (struct nand_chip* nand, size_t to, size_t len,
+ size_t * retlen, const u_char * buf, u_char * ecc_code)
+{
+ int i, page, col, cnt, ret = 0;
+
+ /* Do not allow write past end of device */
+ if ((to + len) > nand->totlen) {
+ printf ("%s: Attempt to write past end of page\n", __FUNCTION__);
+ return -1;
+ }
+
+ /* Shift to get page */
+ page = ((int) to) >> nand->page_shift;
+
+ /* Get the starting column */
+ col = to & (nand->oobblock - 1);
+
+ /* Initialize return length value */
+ *retlen = 0;
+
+ /* Select the NAND device */
+#ifdef CONFIG_OMAP1510
+ archflashwp(0,0);
+#endif
+#ifdef CFG_NAND_WP
+ NAND_WP_OFF();
+#endif
+
+ NAND_ENABLE_CE(nand, 0); /* set pin low */
+
+ /* Check the WP bit */
+ /*NanD_Command(nand, NAND_CMD_STATUS);*/
+ if (!(nand_read_status(nand, NAND_STATUS) & 0x80)) {
+ printf ("%s: Device is write protected!!!\n", __FUNCTION__);
+ ret = -1;
+ goto out;
+ }
+
+ /* Loop until all data is written */
+ while (*retlen < len) {
+ /* Invalidate cache, if we write to this page */
+ if (nand->cache_page == page)
+ nand->cache_page = -1;
+
+ /* Write data into buffer */
+ if ((col + len) >= nand->oobblock) {
+ for (i = col, cnt = 0; i < nand->oobblock; i++, cnt++) {
+ nand->data_buf[i] = buf[(*retlen + cnt)];
+ }
+ } else {
+ for (i = col, cnt = 0; cnt < (len - *retlen); i++, cnt++) {
+ nand->data_buf[i] = buf[(*retlen + cnt)];
+ }
+ }
+ /* We use the same function for write and writev !) */
+ /*ret = nand_write_page (nand, page, col, i, ecc_code);*/
+ ret = nand_page_program(nand, page, (unsigned int)nand->data_buf, i);
+ if (ret < 0 || ret & 0x01)
+ goto out;
+
+ /* Next data start at page boundary */
+ col = 0;
+
+ /* Update written bytes count */
+ *retlen += cnt;
+
+ /* Increment page address */
+ page++;
+ }
+
+ /* Return happy */
+ *retlen = len;
+
+out:
+ /* De-select the NAND device */
+ NAND_DISABLE_CE(nand); /* set pin high */
+#ifdef CONFIG_OMAP1510
+ archflashwp(0,1);
+#endif
+#ifdef CFG_NAND_WP
+ NAND_WP_ON();
+#endif
+
+ return ret;
+}
+
+/* read from the 16 bytes of oob data that correspond to a 512 byte
+ * page or 2 256-byte pages.
+ */
+static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len,
+ size_t * retlen, u_char * buf)
+{
+ /*int len256 = 0;*/
+ struct Nand *mychip;
+ int ret = 0;
+
+ mychip = &nand->chips[ofs >> nand->chipshift];
+
+ /* update address for 2M x 8bit devices. OOB starts on the second */
+ /* page to maintain compatibility with nand_read_ecc. */
+ /*if (nand->page256) {
+ if (!(ofs & 0x8))
+ ofs += 0x100;
+ else
+ ofs -= 0x8;
+ }*/
+
+ NAND_ENABLE_CE(nand, 0); /* set pin low */
+ /*NanD_Command(nand, NAND_CMD_READOOB);
+ if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ ((ofs >> nand->page_shift) << nand->page_shift) +
+ ((ofs & (nand->oobblock - 1)) >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+ }*/
+ if (nand->oobblock >= 2048) {
+ pNFCRegs->NFCRd |= OOB_READ;/* read sidinfo */
+ ret = nand->nfc_read_page(nand,
+ ofs + (pNFCRegs->NFCRd&OOB_READ),
+ (unsigned int)&buf[0], 32);
+ } else {
+ ret = nand->nfc_read_page(nand, ofs,
+ (unsigned int)nand->data_buf, nand->oobblock);
+
+ memcpy(buf, (unsigned char *)&pNFCRegs->FIFO[0], 16);
+ }
+
+ if (ret) {
+ printf("Read oob failed ret=%d at addr %x\n", ret, ofs);
+ return ret;
+ }
+ if (nand->oobblock >= 2048)
+ pNFCRegs->NFCRd &= ~OOB_READ; /* return to default value */
+
+
+ /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+ /* Note: datasheet says it should automaticaly wrap to the */
+ /* next OOB block, but it didn't work here. mf. */
+ /*if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
+ len256 = (ofs | 0x7) + 1 - ofs;
+ NanD_ReadBuf(nand, buf, len256);
+
+ NanD_Command(nand, NAND_CMD_READOOB);
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
+ }*/
+
+ /*NanD_ReadBuf(nand, &buf[len256], len - len256);*/
+
+ *retlen = len;
+ /* Reading the full OOB data drops us off of the end of the page,
+ * causing the flash device to go into busy mode, so we need
+ * to wait until ready 11.4.1 and Toshiba TC58256FT nands */
+
+ /*ret = NanD_WaitReady(nand, 1);*/
+ NAND_DISABLE_CE(nand); /* set pin high */
+
+ return ret;
+}
+
+/* write to the 16 bytes of oob data that correspond to a 512 byte
+ * page or 2 256-byte pages.
+ */
+static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,
+ size_t * retlen, const u_char * buf)
+{
+ int len256 = 0;
+ int i;
+ unsigned long nandptr = nand->IO_ADDR;
+
+#ifdef PSYCHO_DEBUG
+ printf("nand_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",
+ (long)ofs, len, buf[0], buf[1], buf[2], buf[3],
+ buf[8], buf[9], buf[14],buf[15]);
+#endif
+
+ NAND_ENABLE_CE(nand, 0); /* set pin low to enable chip */
+
+ /* Reset the chip */
+ /*NanD_Command(nand, NAND_CMD_RESET);*/
+
+ /* issue the Read2 command to set the pointer to the Spare Data Area. */
+ /*NanD_Command(nand, NAND_CMD_READOOB);
+ if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ ((ofs >> nand->page_shift) << nand->page_shift) +
+ ((ofs & (nand->oobblock - 1)) >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+ }*/
+
+ /* update address for 2M x 8bit devices. OOB starts on the second */
+ /* page to maintain compatibility with nand_read_ecc. */
+ /*if (nand->page256) {
+ if (!(ofs & 0x8))
+ ofs += 0x100;
+ else
+ ofs -= 0x8;
+ }*/
+
+ /* issue the Serial Data In command to initial the Page Program process */
+ /*NanD_Command(nand, NAND_CMD_SEQIN);
+ if (nand->bus16) {
+ NanD_Address(nand, ADDR_COLUMN_PAGE,
+ ((ofs >> nand->page_shift) << nand->page_shift) +
+ ((ofs & (nand->oobblock - 1)) >> 1));
+ } else {
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs);
+ }*/
+
+ /* treat crossing 8-byte OOB data for 2M x 8bit devices */
+ /* Note: datasheet says it should automaticaly wrap to the */
+ /* next OOB block, but it didn't work here. mf. */
+ if (nand->page256 && ofs + len > (ofs | 0x7) + 1) {
+ len256 = (ofs | 0x7) + 1 - ofs;
+ for (i = 0; i < len256; i++)
+ WRITE_NAND(buf[i], nandptr);
+
+ NanD_Command(nand, NAND_CMD_PAGEPROG);
+ NanD_Command(nand, NAND_CMD_STATUS);
+#ifdef NAND_NO_RB
+ { u_char ret_val;
+ do {
+ ret_val = READ_NAND(nandptr); /* wait till ready */
+ } while ((ret_val & 0x40) != 0x40);
+ }
+#endif
+ if (READ_NAND(nandptr) & 1) {
+ puts ("Error programming oob data\n");
+ /* There was an error */
+ NAND_DISABLE_CE(nand); /* set pin high */
+ *retlen = 0;
+ return -1;
+ }
+ NanD_Command(nand, NAND_CMD_SEQIN);
+ NanD_Address(nand, ADDR_COLUMN_PAGE, ofs & (~0x1ff));
+ }
+
+ if (nand->bus16) {
+ for (i = len256; i < len; i += 2) {
+ WRITE_NAND(buf[i] + (buf[i+1] << 8), nandptr);
+ }
+ } else {
+ for (i = len256; i < len; i++)
+ WRITE_NAND(buf[i], nandptr);
+ }
+
+ NanD_Command(nand, NAND_CMD_PAGEPROG);
+ NanD_Command(nand, NAND_CMD_STATUS);
+#ifdef NAND_NO_RB
+ { u_char ret_val;
+ do {
+ ret_val = READ_NAND(nandptr); /* wait till ready */
+ } while ((ret_val & 0x40) != 0x40);
+ }
+#endif
+ if (READ_NAND(nandptr) & 1) {
+ puts ("Error programming oob data\n");
+ /* There was an error */
+ NAND_DISABLE_CE(nand); /* set pin high */
+ *retlen = 0;
+ return -1;
+ }
+
+ NAND_DISABLE_CE(nand); /* set pin high */
+ *retlen = len;
+ return 0;
+
+}
+#endif
+int nand_erase(struct nand_chip* nand, size_t ofs, size_t len, int clean)
+{
+ /* This is defined as a structure so it will work on any system
+ * using native endian jffs2 (the default).
+ */
+/* static struct jffs2_unknown_node clean_marker = {
+ JFFS2_MAGIC_BITMASK,
+ JFFS2_NODETYPE_CLEANMARKER,
+ 8 *//* 8 bytes in this node */
+/* };*/
+ unsigned long nandptr;
+ struct Nand *mychip;
+ int ret = 0;
+ if ((ofs & (nand->erasesize-1)) || (len & (nand->erasesize-1))) {
+ printf ("Offset and size must be sector aligned, ofs = 0x%x, erasesize = %d len=0x%x\n",
+ (int)ofs, (int) nand->erasesize, (int) len);
+ return -1;
+ }
+
+ nandptr = nand->IO_ADDR;
+
+ /* Select the NAND device */
+#ifdef CONFIG_OMAP1510
+ archflashwp(0,0);
+#endif
+#ifdef CFG_NAND_WP
+ NAND_WP_OFF();
+#endif
+ NAND_ENABLE_CE(nand, 0); /* set pin low */
+
+ /* Check the WP bit */
+ /*NanD_Command(nand, NAND_CMD_STATUS);*/
+ if (!(nand_read_status(nand, NAND_STATUS) & 0x80)) {
+ printf ("nand_write_ecc: Device is write protected!!!\n");
+ ret = -1;
+ goto out;
+ }
+
+ /* Check the WP bit */
+ /*NanD_Command(nand, NAND_CMD_STATUS);*/
+ if (!(nand_read_status(nand, NAND_STATUS) & 0x80)) {
+ printf ("%s: Device is write protected!!!\n", __FUNCTION__);
+ ret = -1;
+ goto out;
+ }
+ if (check_block_table(nand, 0)) {
+ NAND_DISABLE_CE(nand); /* set pin high */
+ return -1;
+ }
+ /* FIXME: Do nand in the background. Use timers or schedule_task() */
+ while(len) {
+ /*mychip = &nand->chips[shr(ofs, nand->chipshift)];*/
+ mychip = &nand->chips[ofs >> nand->chipshift];
+
+ /* always check for bad block first, genuine bad blocks
+ * should _never_ be erased.
+ */
+ /*if (ALLOW_ERASE_BAD_DEBUG || !check_block(nand, ofs)) {*/
+ if (ALLOW_ERASE_BAD_DEBUG || !nand->isbadblock(nand, ofs/nand->erasesize, 0)) {
+ /* Select the NAND device */
+ NAND_ENABLE_CE(nand, 0); /* set pin low */
+
+ //WMTEraseNAND(ofs/nand->erasesize, len/nand->erasesize, 0);
+ ret = wmt_nand_erase(nand, ofs/nand->erasesize);
+ /*printf ("erase finish ofs = 0x%x, ret = 0x%x len=0x%x\n",
+ (int)ofs, (int) ret, (int) len);*/
+/* NanD_Command(nand, NAND_CMD_ERASE1);
+ NanD_Address(nand, ADDR_PAGE, ofs);
+ NanD_Command(nand, NAND_CMD_ERASE2);
+
+ NanD_Command(nand, NAND_CMD_STATUS);
+*/
+#ifdef NAND_NO_RB
+ { u_char ret_val;
+ do {
+ ret_val = READ_NAND(nandptr); /* wait till ready */
+ } while ((ret_val & 0x40) != 0x40);
+ }
+#endif
+ if (ret < 0 || (ret&1)) {
+ printf ("%s: Error erasing at 0x%lx\n",
+ __FUNCTION__, (long)ofs);
+ /* There was an error */
+ ret = -1;
+ goto out;
+ } else
+ ret = 0;
+ if (clean) {
+ /*int n;*/ /* return value not used */
+ int p, l;
+
+ /* clean marker position and size depend
+ * on the page size, since 256 byte pages
+ * only have 8 bytes of oob data
+ */
+ if (nand->page256) {
+ p = NAND_JFFS2_OOB8_FSDAPOS;
+ l = NAND_JFFS2_OOB8_FSDALEN;
+ } else {
+ p = NAND_JFFS2_OOB16_FSDAPOS;
+ l = NAND_JFFS2_OOB16_FSDALEN;
+ }
+
+ /*ret = nand_write_oob(nand, ofs + p, l, (size_t *)&n,
+ (u_char *)&clean_marker);*/
+ /* quit here if write failed */
+ /*if (ret)
+ goto out;*/
+ }
+ }
+ ofs += nand->erasesize;
+ len -= nand->erasesize;
+ }
+
+out:
+ /* De-select the NAND device */
+ NAND_DISABLE_CE(nand); /* set pin high */
+#ifdef CONFIG_OMAP1510
+ archflashwp(0,1);
+#endif
+#ifdef CFG_NAND_WP
+ NAND_WP_ON();
+#endif
+
+ return ret;
+}
+
+//get eslc and retry value
+int get_parameter(struct nand_chip *nand, unsigned char *buf, unsigned char * offset, int num)
+{
+ int i, /*k,*/ status = -1;
+ unsigned int cfg, reg_num = num;
+ unsigned char *FIFO = (unsigned char *) &pNFCRegs->FIFO[48];
+ unsigned char para[16] = {0};
+
+ for (i = 0; i < reg_num; i++) {
+ if (nfc_dma_cfg((unsigned int)&para[i], 1, 0))
+ return -1;
+ pNFCRegs->NFCRd |= HIGH64FIFO;
+ if (i == 0) {
+ FIFO[0] = NAND_GET_PARAM;
+ FIFO[1] = offset[i];
+ /*printf("FIFO:");
+ for (k=0;k<2;k++)
+ printf("[%d]=0x%x ", k, FIFO[k]);
+ printf("\n");*/
+ // set address latch ALE(high) and CLE(lower)
+ pNFCRegs->NFCRc = 0x00020001;
+ cfg = (0x02<<1);
+ } else {
+ FIFO[0] = offset[i];
+ // set address latch ALE(high) and CLE(lower)
+ pNFCRegs->NFCRc = 0x00010000;
+ cfg = (0x01<<1);
+ }
+ pNFCRegs->NFCR1 = NAND2NFC|cfg|NFC_TRIGGER; /* cfg & start*/
+
+ /* wait command/address to finished */
+ status = NFC_WAIT_CMD_READY();
+ if (status) {
+ printf("[Hynix get_parameter]retry c1 wait cmd/addr ready time out\n");
+ return status;
+ }
+
+ status = NFC_WAIT_READY();
+ if (status) {
+ printf("retry wait NFC ready time out\n");
+ return status;
+ }
+
+ status = nand_pdma_handler();
+ nand_free_pdma();
+ if (status)
+ return status;
+ }
+ status = NAND_WAIT_IDLE();
+ if (status) {
+ printf("retry c1 wait idle time out\n");
+ return status;
+ }
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+
+// printf("retry start cmd end para = 0x%x %x %x %x %x\n", para[0], para[1], para[2], para[3], para[4]);
+ for(i = 0; i < reg_num; i++) {
+ buf[i] = para[i];
+ }
+
+ return 0;
+}
+
+/*
+int my_get_parameter(struct nand_chip *nand)
+{
+ unsigned char offset[5] = {0xa0, 0xa1, 0xb2, 0xb1, 0xc9};
+ unsigned char buf[16] = {0};
+ NAND_ENABLE_CE(nand, 0);
+ get_parameter(nand, buf, offset, 5);
+ NAND_DISABLE_CE(nand);
+ printf("%x %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3], buf[4]);
+
+}
+*/
+
+int hynix_get_parameter(struct nand_chip *nand, int mode)
+{
+ unsigned char buf[16] = {0};
+ unsigned char *offset = NULL;
+ unsigned char *set_value = NULL;
+ unsigned char *def_value = NULL;
+ unsigned int reg_num;
+ int i = 0, j = 0;
+ int rc = -1;
+
+ if(mode == ESLC_MODE) {
+ reg_num = cur_chip->eslc_reg_num;
+ offset = cur_chip->eslc_offset;
+ def_value = cur_chip->eslc_def_value;
+ set_value = cur_chip->eslc_set_value;
+ } else if(mode == READ_RETRY_MODE){
+ reg_num = cur_chip->retry_reg_num;
+ offset = cur_chip->retry_offset;
+ def_value = cur_chip->retry_def_value;
+ } else {
+ printf("Not support this mode %d\n", mode);
+ return rc;
+ }
+
+ //if (nand->dwRdmz)
+ // reset_nfc();
+ disable_hw_rdmz(nand);
+
+ rc = get_parameter(nand, buf, offset, reg_num);
+
+ /*if (nand->dwRdmz && nand->bbt_sw_rdmz == 0)
+ pNFCRegs->NFCRf = RDMZ;*/
+
+ if (nand->bbt_sw_rdmz == 0) {
+ enable_hw_rdmz(nand);
+ //printf("HW RDMZ ON ( hynix_get_parameter )\n");
+ }
+
+
+ if(rc != 0) {
+ disable_hw_rdmz(nand);
+ return rc;
+ }
+
+ if(mode == ESLC_MODE) {
+ if((def_value[reg_num] != 0xff) && (def_value[reg_num + 1] != 0xff)) {
+ for(i = 0; i < reg_num; i++) {
+ def_value[i] = buf[i];
+ set_value[i] += buf[i];
+ }
+ def_value[reg_num] = 0xff;
+ def_value[reg_num + 1] = 0xff;
+ } else {
+ printf("ESLC Current: ");
+ for(i = 0; i < reg_num; i++)
+ printf("0x%x ", buf[i]);
+ printf("\n");
+ }
+ } else if(mode == READ_RETRY_MODE) {
+ if((def_value[reg_num] != 0xff) && (def_value[reg_num + 1] != 0xff)) {
+ for(i = 0; i < reg_num; i++)
+ def_value[i] = buf[i];
+ def_value[reg_num] = 0xff;
+ def_value[reg_num + 1] = 0xff;
+ } else {
+ /*printf("Retry Current: ");
+ for(i = 0; i < reg_num; i++)
+ printf("0x%x ", buf[i]);
+ printf("\n");*/
+ for (j = 0; j < cur_chip->total_try_times; j++) {
+ for (i = 0; i < reg_num; i++) {
+ if (buf[i] != cur_chip->retry_value[j*reg_num+i])
+ break;
+ }
+ //printf("i = %d\n", i);
+ if (i == reg_num) {
+ cur_chip->cur_try_times = j;
+ printf("Get current try times %d from kernel.\n", j);
+ break;
+ }
+ }
+ }
+ }
+ disable_hw_rdmz(nand);
+ return rc;
+}
+
+
+/*This is for Hynix set read retry parameter!*/
+int set_parameter(struct nand_chip *nand, unsigned char *buf, unsigned char *offset, int regn)
+{
+
+ int i, status = -1/*, k*/;
+ unsigned int cfg;
+ unsigned char *FIFO = (unsigned char *) &pNFCRegs->FIFO[48];
+ unsigned int reg_num = regn;
+
+ for (i = 0; i < (reg_num+1);i++) {
+ if (i < reg_num) {
+ if (nfc_dma_cfg((unsigned int)&buf[i], 1, 1))
+ return -1;
+ }
+
+// printf("retry c1 p2 i=%d mode = %d\n", i, mode);
+ pNFCRegs->NFCRd |= HIGH64FIFO;
+ if (i == 0) {
+ FIFO[0] = 0x36;
+ FIFO[1] = offset[i];
+ /*printf("FIFO:");
+ for (k=0;k<2;k++)
+ printf("[%d]=0x%x ", k, FIFO[k]);
+ printf("\n");*/
+ // set address latch ALE(high) and CLE(lower)
+ pNFCRegs->NFCRc = 0x00020001;
+ cfg = (0x02<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER; /* cfg & start*/
+ } else if (i < reg_num) {
+ FIFO[0] = offset[i];
+ // set address latch ALE(high) and CLE(lower)
+ pNFCRegs->NFCRc = 0x00010000;
+ cfg = (0x01<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER; /* cfg & start*/
+ } else {
+ FIFO[0] = 0x16;
+ pNFCRegs->NFCRc = 0x00000001;
+ cfg = (0x01<<1);
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|cfg|NFC_TRIGGER; /* cfg & start*/
+ }
+
+ /* wait command/address to finished */
+ status = NFC_WAIT_CMD_READY();
+ if (status) {
+ printf("[Hynix set_parameter]retry c1 wait cmd/addr ready time out\n");
+ return status;
+ }
+
+ status = NFC_WAIT_READY();
+ if (status) {
+ printf("retry wait NFC ready time out\n");
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ return status;
+ }
+
+ if (i < reg_num) {
+ status = nand_pdma_handler();
+ nand_free_pdma();
+ if (status) {
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ return status;
+ }
+ }
+ }
+// printf("\n retry c1 p5\n");
+ status = NAND_WAIT_IDLE();
+ if (status) {
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ printf("retry c1 wait idle time out\n");
+ return status;
+ }
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+// printf("retry start cmd p1\n");
+ return 0;
+}
+
+int dummy_read(struct nand_chip *nand)
+{
+ int status = -1;
+ unsigned char buf[4];
+
+ nfc_ecc_set(USE_SW_ECC, 0, nand);
+ if (nfc_dma_cfg((unsigned int)buf, 4, 0))
+ return -ERR_DMA_CFG;
+ NanD_Address(nand, ADDR_COLUMN_PAGE, 0, 0);
+ WRITE_NAND_COMMAND(NAND_READ0); /* set command cycle 1 */
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|((nand->row+nand->col+1)<<1)|NFC_TRIGGER|OLD_CMD;
+ if (NFC_WAIT_CMD_READY()) {
+ set_ECC_mode(nand);
+ return -ERR_NFC_CMD;
+ }
+ WRITE_NAND_COMMAND(NAND_READ_CONFIRM);
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+ pNFCRegs->NFCR1 = NAND2NFC|1<<1|NFC_TRIGGER|OLD_CMD;
+
+ status = nand_pdma_handler();
+ nand_free_pdma();
+ if (status) {
+ set_ECC_mode(nand);
+ return status;
+ }
+ status = NAND_WAIT_IDLE();
+ set_ECC_mode(nand);
+ if (status) {
+ printf("dummy read wait idle time out\n");
+ return status;
+ }
+ return 0;
+}
+
+
+int hynix_set_parameter(struct nand_chip *nand, int mode, int def_value)
+{
+ unsigned char *offset = NULL;
+ unsigned char *set_value = NULL;
+ unsigned int reg_num;
+ int rc = -1;
+
+
+ if(mode == ESLC_MODE) {
+ reg_num = cur_chip->eslc_reg_num;
+ offset = cur_chip->eslc_offset;
+ if(def_value == ECC_ERROR_VALUE) {
+ set_value = cur_chip->eslc_set_value;
+ } else {
+ set_value = cur_chip->eslc_def_value;
+ }
+ } else {
+ reg_num = cur_chip->retry_reg_num;
+ offset = cur_chip->retry_offset;
+ if(def_value == ECC_ERROR_VALUE) {
+ cur_chip->cur_try_times++;
+
+ if(force_set_rr_value != -1) {
+ printf("set read retry value to %d.\n",force_set_rr_value);
+ cur_chip->cur_try_times = force_set_rr_value;
+ }
+
+ if(cur_chip->cur_try_times >= cur_chip->total_try_times)
+ cur_chip->cur_try_times = -1;
+ if((cur_chip->cur_try_times >= 0) && (cur_chip->cur_try_times < cur_chip->total_try_times))
+ set_value = cur_chip->retry_value + cur_chip->cur_try_times* cur_chip->retry_reg_num;
+ else
+ set_value = cur_chip->retry_def_value;
+ } else {
+ set_value = cur_chip->retry_def_value;
+ cur_chip->cur_try_times = -1;
+ }
+ }
+
+#if 0
+ printf("set value:\n");
+ for(rc = 0; rc < reg_num; rc++)
+ printf(" 0x%x:0x%x ", offset[rc], set_value[rc]);
+ printf("reg_num = %d\n", reg_num);
+#endif
+
+ //if (nand->dwRdmz)
+ // reset_nfc();
+ disable_hw_rdmz(nand);
+
+ rc = set_parameter(nand, set_value, offset, reg_num);
+
+ /*if (nand->dwRdmz && nand->bbt_sw_rdmz == 0)
+ pNFCRegs->NFCRf = RDMZ;*/
+ if (nand->bbt_sw_rdmz == 0) {
+ enable_hw_rdmz(nand);
+ //printf("HW RDMZ ON ( hynix_set_parameter )\n");
+ }
+
+ if(rc) {
+ printf("set_parameter fail.\n");
+ disable_hw_rdmz(nand);
+ return rc;
+ }
+
+ //if(def_value == DEFAULT_VALUE && mode == ESLC_MODE)
+ dummy_read(nand);
+
+ disable_hw_rdmz(nand);
+
+ return rc;
+}
+
+int nand_reset_no_read_status(unsigned int cmd)
+{
+ int status = 0;
+
+ pNFCRegs->NFCR2 = cmd; /* set command */
+ pNFCRegs->NFCRb &= B2R; /* write to clear*/
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD;
+ status = NAND_WAIT_READY();
+ if (status) {
+ printf("NFCR12 chip enable 0x%x\r\n", pNFCRegs->NFCR12>>8);
+ printf("\r\n reset wait busy status = 0x%x\r\n", status);
+ return status;
+ }
+ return status;
+}
+
+int write_bytes_param(int cmd_cnt, int addr_cnt, int data_cnt, uchar *cmd, uchar *addr, uchar *data)
+{
+ int i, status = 0;
+ unsigned int cmd_addr_cycle = 0, cfg = 0, cfg_bit8 = 0;
+ unsigned char *FIFO = (unsigned char *)&pNFCRegs->FIFO[48];
+
+ if (data_cnt > 0) {
+ if (nfc_dma_cfg((unsigned int)data, data_cnt, 1))
+ return -4;
+ }
+ pNFCRegs->NFCRd |= HIGH64FIFO;
+ for (i = 0; i < cmd_cnt; i++) {
+ FIFO[i] = cmd[i];
+ cmd_addr_cycle |= (1<<i);
+ }
+
+ for (i = cmd_cnt; i < (addr_cnt+cmd_cnt); i++) {
+ FIFO[i] = addr[i-cmd_cnt];
+ cmd_addr_cycle |= (1<<(i+16));
+ }
+ pNFCRegs->NFCRc = cmd_addr_cycle;
+ /*if (FIFO[0] == 0) {
+ printf("FIFO = ");
+ for (i = 0; i < (addr_cnt+cmd_cnt); i++)
+ printf("0x%x ", FIFO[i]);
+ printf("\n");
+ }*/
+
+ /*if (data_cnt > 0) {
+ printf("data = ");
+ for (i = 0; i < data_cnt; i++) {
+ printf("0x%x ", data[i]);
+ //printf("\n");
+ }
+ }*/
+ //printf(" NFCRc=0x%x\n", cmd_addr_cycle);
+ cfg = ((cmd_cnt + addr_cnt)&0x7)<<1;
+ cfg_bit8 = (((cmd_cnt + addr_cnt)&0x18)>>3)<<8;
+
+ pNFCRegs->NFCRb &= B2R; /* write to clear */
+
+ if (data_cnt > 0)
+ pNFCRegs->NFCR1 = cfg_bit8|cfg|NFC_TRIGGER; /* cfg & start*/
+ else
+ pNFCRegs->NFCR1 = DPAHSE_DISABLE|cfg_bit8|cfg|NFC_TRIGGER; /* cfg & start*/
+
+ /* wait command/address to finished */
+ status = NFC_WAIT_CMD_READY();
+ if (status) {
+ printf("[write_bytes_param]retry c1 wait cmd/addr ready time out\n");
+ goto go_fail;
+ }
+
+ status = NAND_WAIT_FLASH_READY();//Henry add @20140512
+ if (status) {
+ printf("retry wait FLASH ready time out\n");
+ goto go_fail;
+ }
+
+ status = NFC_WAIT_READY();
+ if (status) {
+ printf("retry wait NFC ready time out\n");
+ goto go_fail;
+ }
+
+ status = NAND_WAIT_IDLE();
+ if (status) {
+ printf("retry c1 wait idle time out\n");
+ goto go_fail;
+ }
+
+ if (data_cnt > 0) {
+ status = nand_pdma_handler();
+ nand_free_pdma();
+ if (status) {
+ goto go_fail;
+ }
+ }
+
+go_fail:
+ pNFCRegs->NFCRd &= ~HIGH64FIFO;
+ return status;
+}
+
+
+int toshiba_send_data(void)
+{
+ unsigned int i = 0, j,/*k,*/ cfg;
+ int status = -1;
+ unsigned char *FIFO = (unsigned char *)&pNFCRegs->FIFO[48];
+ unsigned char *set_value = NULL;
+ unsigned char *offset = NULL;
+
+// printf("FIFO#0x%x, cur_try_times = %d, reg_num = %d\n", &pNFCRegs->FIFO[48], cur_chip->cur_try_times, cur_chip->retry_reg_num);
+ set_value = cur_chip->retry_value + cur_chip->cur_try_times*cur_chip->retry_reg_num;
+ offset = cur_chip->retry_offset;
+
+ cur_chip->cur_try_times++;
+ if(cur_chip->cur_try_times >= cur_chip->total_try_times)
+ cur_chip->cur_try_times = 0;
+
+ //printf("Set parameter: retry c1 p1\n");
+ for (i=0,j=4;i<4;i++,j++) {
+ if (nfc_dma_cfg((unsigned int)&set_value[i], 1, 1))
+ return -4;
+ pNFCRegs->NFCRd |= HIGH64FIFO;
+ FIFO[0] = 0x55;
+ FIFO[1] = offset[i];
+ /*printf("FIFO:");
+ for (k=0;k<2;k++)
+ printf("[%d]=0x%x ", k, FIFO[k]);
+ printf("\n");*/
+ // set address latch ALE(high) and CLE(lower)
+ pNFCRegs->NFCRc = 0x00020001;
+ cfg = (0x02<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER; /* cfg & start*/
+
+ /* wait command/address to finished */
+ status = NFC_WAIT_CMD_READY();
+ if (status) {
+ printf("retry c1 wait cmd/addr ready time out\n");
+ return status;
+ }
+
+ status = NFC_WAIT_READY();
+ if (status) {
+ printf("retry wait NFC ready time out\n");
+ return status;
+ }
+
+ status = nand_pdma_handler();
+ nand_free_pdma();
+ if (status)
+ return status;
+ }
+ printf("retry c1 p5\n");
+ status = NAND_WAIT_IDLE();
+ if (status) {
+ printf("retry c1 wait idle time out\n");
+ return status;
+ }
+ //printf("set parameter end.\n");
+ return status;
+}
+
+int toshiba_pre_condition(void)
+{
+ int cfg;
+ int status = 0;
+ unsigned char cmd1[2] = {0x5c, 0xc5};
+
+ pNFCRegs->NFCR2 = cmd1[0];
+ pNFCRegs->NFCR3 = 0xff00;
+ cfg = DPAHSE_DISABLE|(0x02<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER|OLD_CMD; /* cfg & start */
+ status = NFC_WAIT_READY();
+ if (status)
+ return status;
+ pNFCRegs->NFCR2 = cmd1[1];
+ pNFCRegs->NFCR3 = 0xff00;
+ cfg = DPAHSE_DISABLE|(0x02<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER|OLD_CMD; /* cfg & start */
+ status = NFC_WAIT_READY();
+ if (status)
+ return status;
+ //printf("toshiba_pre_condition OK.\n");
+ return status;
+}
+
+int toshiba_set_parameter(struct nand_chip *nand, int mode, int def_mode)
+{
+ int cfg;
+ int status = 0;
+ unsigned char cmd2[2] = {0x26, 0x5d};
+
+ status = toshiba_send_data();
+ if (status) {
+ printf("pre condition cmd2 time out\n");
+ return status;
+ }
+ pNFCRegs->NFCR2 = cmd2[0];
+ pNFCRegs->NFCR3 = 0xff00;
+ cfg = DPAHSE_DISABLE|(0x02<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER|OLD_CMD; /* cfg & start */
+ status = NFC_WAIT_READY();
+ if (status)
+ return status;
+ pNFCRegs->NFCR2 = cmd2[1];
+ pNFCRegs->NFCR3 = 0xff00;
+ cfg = DPAHSE_DISABLE|(0x02<<1);
+ pNFCRegs->NFCR1 = cfg|NFC_TRIGGER|OLD_CMD; /* cfg & start */
+ status = NFC_WAIT_READY();
+ if (status)
+ return status;
+
+ return status;
+}
+
+int hynix_get_otp(struct nand_chip *nand)
+{
+ int i, j, status = -1;
+ unsigned char cmd[5] = {0x36, 0x16, 0x17, 0x04, 0x19};
+ unsigned char *offset = cur_chip->otp_offset;
+ unsigned char *data = cur_chip->otp_data;
+ unsigned int page = 0x200;
+ unsigned char reset = 0xFF, *buff, *buf;
+ unsigned int retry_times, retry_regs, chk = 0;
+ unsigned char *bf, *bf2;
+
+ disable_hw_rdmz(nand);
+
+ buf = nand->data_buf;
+ //printf("p0 offset: 0x%x, 0x%x\n", offset[0], offset[1]);
+ status = nand_reset_no_read_status(reset);
+ if (status) {
+ printf("load_hynix_opt_reg: reset fail");
+ }
+
+ status = write_bytes_param(1, 1, 1, (uchar *)&cmd[0], (uchar *)&offset[0], (uchar *)&data[0]);
+ if (status)
+ printf("load_hynix_opt_reg: phase 1 fail");
+ status = write_bytes_param(0, 1, 1, NULL, (uchar *)&offset[1], (uchar *)&data[1]);
+ if (status)
+ printf("load_hynix_opt_reg: phase 2 fail");
+ status = write_bytes_param(4, 0, 0, (uchar *)&cmd[1], NULL, NULL);
+ if (status)
+ printf("load_hynix_opt_reg: phase 3 fail");
+ nfc_ecc_set(USE_SW_ECC, ECC1bit, nand);
+ status = nand->nfc_read_page(nand, page, (unsigned int)buf, 1024);
+
+ set_ECC_mode(nand);
+
+ if (status != 0) {
+ printf("load_hynix_opt_reg: phase 4 fail status = %d\n", status);
+ return -1;
+ }
+ status = nand_reset_no_read_status(reset);
+ if (status) {
+ printf("load_hynix_opt_reg: reset fail");
+ }
+ status = nand_reset_no_read_status(0x38);
+ if (status) {
+ printf("load_hynix_opt_reg: OTP end 0x38 fail");
+ }
+ //print_nand_buf((uchar *)buf, 1040);
+ buff = (unsigned char *)buf;
+ if (buff[0] > 8 || buff[1] > 8) {
+ printf("retry_cmd buff is not big enough for size %d\n", buff[0]*buff[1]);
+ return -1;
+ }
+
+ cur_chip->total_try_times = buff[0];
+ cur_chip->retry_reg_num = buff[1];
+
+ retry_times = buff[0];
+ retry_regs = buff[1];
+
+ for (i = 0; i < 16; i+=2) {
+ bf = &buff[i * retry_times * retry_regs + 2];
+ bf2 = &buff[(i+1) * retry_times * retry_regs + 2];
+ for (j = 0; j < (retry_times*retry_regs); j++) {
+ if ((bf[j] ^ bf2[j]) != 0xFF) {
+ printf("inverse check fail %x %x\n", bf[j], bf2[j]);
+ break;
+ }
+ }
+ if (j >= (retry_times*retry_regs)) {
+ chk = 1;
+ break;
+ }
+ }
+
+ if (chk == 0) {
+ printf("hynix : no valid otp data checked\n");
+ }
+
+ for (j = 0; j < retry_regs; j++)
+ cur_chip->retry_def_value[j] = bf[j];
+
+ /*print_nand_buffer(cur_chip->retry_def_value, retry_regs);*/
+
+ for (i = 0; i < (retry_times-1); i++) {
+ for (j = 0; j < retry_regs; j++) {
+ cur_chip->retry_value[i*retry_regs + j] = bf[(i+1)*retry_regs + j];
+ }
+ /*print_nand_buffer(&cur_chip->retry_value[i*retry_regs], retry_regs);*/
+ }
+
+ cur_chip->total_try_times--;
+
+ //page read for Hardware Issue. //Henry mark
+ //nand->nfc_read_page(nand, page, (unsigned int)buf, nand->oobblock);
+
+ return 0;
+}
+
+
+int toshiba_get_parameter(struct nand_chip *nand, int mode)
+{
+ return 0;
+}
+
+int samsung_get_parameter(struct nand_chip *nand, int mode)
+{
+ return 0;
+}
+
+int sandisk_get_parameter(struct nand_chip *nand, int mode)
+{
+ return 0;
+}
+
+int micron_get_parameter(struct nand_chip *nand, int mode)
+{
+ return 0;
+}
+
+int samsung_set_parameter(struct nand_chip *nand, int mode, int def_mode)
+{
+ unsigned char *offset = NULL;
+ unsigned char *set_value = NULL;
+ unsigned int reg_num;
+ int rc = -1, i;
+ uint8_t cmd[1] = {0xA1};
+ uint8_t data[3] = {0, 0, 0};
+
+ reg_num = cur_chip->retry_reg_num;
+ offset = cur_chip->retry_offset;
+ if (def_mode == ECC_ERROR_VALUE) {
+ set_value = cur_chip->retry_value + cur_chip->cur_try_times * reg_num;
+ cur_chip->cur_try_times++;
+ } else {
+ set_value = cur_chip->retry_def_value;
+ cur_chip->cur_try_times = 0;
+ }
+
+ #ifdef RETRY_DEBUG
+ printf("samsung set value: cur_try_times=%d\n", cur_chip->cur_try_times);
+ for(i = 0; i < reg_num; i++)
+ printf(" 0x%x:0x%x ", offset[i], set_value[i]);
+ printf("reg_num = %d\n", reg_num);
+ #endif
+
+ //if (nand->dwRdmz)
+ // reset_nfc();
+ disable_hw_rdmz(nand);
+
+ for (i = 0; i < reg_num; i++) {
+ data[1] = offset[i];
+ data[2] = set_value[i];
+ rc = write_bytes_param(1, 0, 3, cmd, NULL, data);
+ if (rc)
+ printf("samsung read retry reg: phase %d fail\n", i);
+ }
+
+ //if (nand->dwRdmz && nand->bbt_sw_rdmz == 0)
+ // pNFCRegs->NFCRf = RDMZ;
+
+ /*print_nfc_register();
+ printf("\n");*/
+ return rc;
+}
+
+int micron_set_parameter(struct nand_chip *nand, int mode, int def_mode)
+{
+ unsigned char *offset = NULL;
+ unsigned char *set_value = NULL;
+ unsigned int reg_num;
+ int rc = -1, i;
+ uint8_t cmd[1] = {0xEF};
+
+ reg_num = cur_chip->retry_reg_num;
+ offset = cur_chip->retry_offset;
+ if (def_mode == ECC_ERROR_VALUE) {
+ set_value = cur_chip->retry_value + cur_chip->cur_try_times * reg_num;
+ cur_chip->cur_try_times++;
+ } else {
+ set_value = cur_chip->retry_def_value;
+ cur_chip->cur_try_times = 0;
+ }
+
+ #ifdef RETRY_DEBUG
+ printf("micron set value: cur_try_times=%d\n", cur_chip->cur_try_times);
+ for(i = 0; i < reg_num; i++)
+ printf(" 0x%x:0x%x ", offset[i], set_value[i]);
+ printf("reg_num = %d\n", reg_num);
+ #endif
+
+ //if (nand->dwRdmz)
+ // reset_nfc();
+ disable_hw_rdmz(nand);
+
+ for (i = 0; i < reg_num; i++) {
+ rc = write_bytes_param(1, 1, 1, cmd, offset, set_value);
+ if (rc)
+ printf("micron read retry reg: phase %d fail\n", i);
+ }
+
+ //if (nand->dwRdmz && nand->bbt_sw_rdmz == 0)
+ // pNFCRegs->NFCRf = RDMZ;
+
+ return rc;
+}
+
+int sandisk_init_retry_register(struct nand_chip *nand, int chip)
+{
+ int i, status = -1;
+ unsigned int cmd0 = 0xB93B;//, 0xB9};
+ unsigned int cmd2 = 0x5453;//, 0x54};
+ unsigned char *offset = cur_chip->otp_offset;
+ unsigned char *data = cur_chip->otp_data;
+ unsigned int regc = cur_chip->otp_len;
+
+ NAND_ENABLE_CE(nand, chip);
+
+ //printf("set sandisk init retry register offset addr: 0x%x, 0x%x\n", offset[0], offset[1]);
+ //if (nand->dwRdmz)
+ // reset_nfc();
+ disable_hw_rdmz(nand);
+
+ status = write_bytes_param(2, 0, 0, (unsigned char *)&cmd0, NULL, NULL);
+ if (status) {
+ printf("send sandisk_init_retry_register cmd fail\n");
+ goto sdk_init_out;
+ }
+ for (i = 0; i < regc; i++) {
+ status = write_bytes_param(1, 1, 1, (unsigned char *)&cmd2, &offset[i], &data[i]);
+ if (status) {
+ printf("sandisk_init_retry_register : phase %d fail", i);
+ goto sdk_init_out;
+ }
+ }
+
+sdk_init_out:
+
+ //if (nand->dwRdmz && nand->bbt_sw_rdmz == 0)
+ // pNFCRegs->NFCRf = RDMZ;
+
+ NAND_DISABLE_CE(nand);
+
+ return status;
+}
+
+
+int sandisk_set_parameter(struct nand_chip *nand, int total_try_times, int def_value)
+{
+ unsigned char *offset = NULL;
+ unsigned char *set_value = NULL;
+ unsigned int reg_num, upper_page = 0;
+ int i, rc = -1;
+ uint8_t cmd[4] = {0x3B, 0xB9, 0x53, 0x54};
+
+ if (total_try_times != (cur_chip->total_try_times&0xFF))
+ upper_page = 1;
+
+ reg_num = cur_chip->retry_reg_num;
+ offset = cur_chip->retry_offset;
+ if (def_value == ECC_ERROR_VALUE) {
+ cur_chip->cur_try_times++;
+ if (cur_chip->cur_try_times >= total_try_times)
+ cur_chip->cur_try_times = -1;
+ if ((cur_chip->cur_try_times >= 0) && (cur_chip->cur_try_times < total_try_times)) {
+ if (upper_page)
+ set_value = cur_chip->retry_value +
+ (cur_chip->cur_try_times + (cur_chip->total_try_times&0xFF))* reg_num;
+ else
+ set_value = cur_chip->retry_value + cur_chip->cur_try_times * reg_num;
+ } else
+ set_value = cur_chip->retry_def_value;
+
+ } else {
+ set_value = cur_chip->retry_def_value;
+ cur_chip->cur_try_times = -1;
+ }
+#ifdef RETRY_DEBUG
+ printf("sandisk set value: upper_page=%d, cur_try_times=%d\n", upper_page, cur_chip->cur_try_times);
+ for(i = 0; i < reg_num; i++)
+ printf(" 0x%x:0x%x ", offset[i], set_value[i]);
+ printf("reg_num = %d\n", reg_num);
+#endif
+
+ //if (nand->dwRdmz)
+ // reset_nfc();
+ disable_hw_rdmz(nand);
+
+ rc = write_bytes_param(2, 0, 0, cmd, NULL, NULL);
+ if (rc)
+ printf("sandisk read retry reg: set cmd fail\n");
+ for (i = 0; i < reg_num; i++) {
+ rc = write_bytes_param(1, 1, 1, &cmd[2], &offset[i], &set_value[i]);
+ if (rc)
+ printf("sandisk set retry reg: phase %d fail\n", i);
+ }
+
+ //if (nand->dwRdmz && nand->bbt_sw_rdmz == 0)
+ // pNFCRegs->NFCRf = RDMZ;
+
+ return rc;
+}
+
+
+int read_retry_param_from_nand(struct nand_chip *nand, int chip)
+{
+ unsigned char *pbuf = nand->data_buf;
+ int i = 0;
+ int index = 0;
+ int rc = -1;
+ int find = 0;
+ struct nand_read_retry_param *p = NULL;
+ int end_block = nand->dwBlockCount - 2*BBT_MAX_BLOCK;
+ int start_block = nand->dwBlockCount - BBT_MAX_BLOCK -1;
+
+ if (nand->realplanenum) {
+ end_block = nand->dwBlockCount - 4*BBT_MAX_BLOCK;
+ start_block = nand->dwBlockCount - 2*BBT_MAX_BLOCK -1;
+ }
+
+ NAND_ENABLE_CE(nand, chip);
+
+ nand->bbt_sw_rdmz = 1;//retry table is the same as bbt (use sw rdmz to read!)
+
+ cur_chip->read_table = 1;
+ for(i = start_block; i >= end_block; i--) {
+ //printf("readretry block = %d\n", i);
+
+ if (nand->dwECCBitNum == 60)
+ rc = nfc_BCH_read_page_60bit(nand, i*nand->dwPageCount, (unsigned int)pbuf, nand->oobblock_valid);
+ else
+ rc = nand->nfc_read_page(nand, i*nand->dwPageCount, (unsigned int)pbuf, nand->oobblock);
+
+ if(rc) {
+ printf("can't read nand default parameter from nand block %d page 0.\n", i);
+ continue;
+ }
+
+ p = (struct nand_read_retry_param *)pbuf;
+ if(!strncmp(p->magic, "readretry", 9) && (p->nand_id == nand->id) && (p->nand_id_5th == nand->id2)) {
+ for(index = 0; index < cur_chip->eslc_reg_num; index++) {
+ //printf("0x%x 0x%x 0x%x", p->eslc_offset[index], p->eslc_def_value[index], p->eslc_set_value[index]);
+ cur_chip->eslc_def_value[index] = p->eslc_def_value[index];
+ cur_chip->eslc_set_value[index] = p->eslc_set_value[index];
+ }
+ for(index = 0; index < cur_chip->retry_reg_num; index++) {
+ //printf("0x%x 0x%x, 0x%x", p->retry_offset[index], p->retry_def_value[index], p->retry_value[index]);
+ //printf("\n");
+ cur_chip->retry_def_value[index] = p->retry_def_value[index];
+ }
+
+ for(index = 0; index < cur_chip->retry_reg_num * cur_chip->total_try_times; index++) {
+ //printf("0x%x ", p->retry_value[index]);
+ cur_chip->retry_value[index] = p->retry_value[index];
+ }
+
+ cur_chip->eslc_def_value[cur_chip->eslc_reg_num] = 0xff;
+ cur_chip->eslc_def_value[cur_chip->eslc_reg_num+1] = 0xff;
+ cur_chip->retry_def_value[cur_chip->retry_reg_num] = 0xff;
+ cur_chip->retry_def_value[cur_chip->retry_reg_num+1] = 0xff;
+ find = 1;
+ } else {
+ //uboot can't write default parameter, rc = -1, or rc = 1.
+ rc = 1;
+ }
+
+ if(find == 1) {
+ printf("sucess to read the nand default param.\n");
+ rc = 0;
+ break;
+ }
+ }
+
+ cur_chip->read_table = 0;
+ nand->bbt_sw_rdmz = 0;//recover (retry table is the same as bbt)
+ NAND_DISABLE_CE(nand);
+ return rc;
+}
+
+int write_retry_param_to_nand(struct nand_chip *nand, int chip)
+{
+ unsigned char *pbuf = nand->data_buf;
+ int i = 0;
+ int rc = -1;
+ unsigned char fifo[64];
+ int end_block = nand->dwBlockCount - 2*BBT_MAX_BLOCK;
+ int start_block = nand->dwBlockCount - BBT_MAX_BLOCK -1;
+
+/* if(check_block_table(nand, 0))
+ return rc;*/
+
+ memset(fifo, 0xff, 64);
+ strcpy((char *)fifo, "retrytable");
+ NAND_ENABLE_CE(nand, chip);
+
+ //write default parameter in ESLC mode
+ cur_chip->set_parameter(nand, ESLC_MODE, ECC_ERROR_VALUE);
+ for(i = start_block; i >= end_block; i--) {
+ /* if(nand->isbadblock(nand, i, chip))
+ continue;*/
+ rc = nand_write_block(nand, (unsigned int)pbuf, i*nand->dwPageCount, 1, fifo, 0);
+ if(rc) {
+ printf("can't write nand default parameter on block %d page 0.\n", i);
+ continue;
+ } else {
+ printf("sucess to write nand default parameter on block %d page 0.\n", i);
+ break;
+ }
+ }
+ if(i == (end_block -1)) {
+ printf("There is no good block for readretry parameter and readrety is disabled.\n");
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+ cur_chip = NULL;
+ }
+ if(cur_chip)
+ cur_chip->set_parameter(nand, ESLC_MODE, DEFAULT_VALUE);
+ NAND_DISABLE_CE(nand);
+ return rc;
+}
+
+static inline int nandcheck(unsigned long potential, unsigned long physadr)
+{
+ return 0;
+}
+
+int get_pattern_small(struct nand_chip *nand, unsigned int block, unsigned int *tag, unsigned int *version)
+{
+ unsigned int pos, pos1;
+ unsigned char *buf;
+ int rc = -1;
+ buf = nand->data_buf;
+
+ rc = nand->nfc_read_page(nand, (block*nand->dwPageCount), (unsigned int)buf, nand->oobblock);
+ if (rc) {
+ printf("Read Tag failed rc=%d at page0x%x\n", rc, (block*nand->dwPageCount));
+ return rc;
+ }
+ pos = NAND_SMALL_DWRESERVED1_OFS;
+ pos1 = NAND_SMALL_DWRESERVED2_OFS;
+ *tag = (pNFCRegs->FIFO[pos] << 24)|
+ (pNFCRegs->FIFO[pos+1] << 16)|
+ (pNFCRegs->FIFO[pos+2] << 8)|
+ pNFCRegs->FIFO[pos+3];
+ *version = pNFCRegs->FIFO[pos1]/*|
+ (pNFCRegs->FIFO[pos1+1] << 8)|
+ (pNFCRegs->FIFO[pos1+2] << 16)|
+ (pNFCRegs->FIFO[pos1+3] << 24)*/;
+
+ return 0;
+}
+
+int get_pattern_large(struct nand_chip *nand, unsigned int block, unsigned int *tag, unsigned int *version)
+{
+ unsigned int pos;
+ unsigned char *buf;
+ int rc = -1;
+
+ pos = NAND_LARGE_DWRESERVED1_OFS;
+ buf = nand->data_buf;
+
+ if (nand->dwECCBitNum == 60)
+ rc = nfc_BCH_read_page_60bit(nand, (block*nand->dwPageCount), (unsigned int)buf, nand->oobblock_valid);
+ else
+ rc = nand->nfc_read_page(nand, (block*nand->dwPageCount), (unsigned int)buf, nand->oobblock);
+
+ if (rc) {
+ printf("Read Tag failed rc=%d at page0x%x\n", rc, (block*nand->dwPageCount));
+ return rc;
+ }
+ *tag = (pNFCRegs->FIFO[pos] << 24)|
+ (pNFCRegs->FIFO[pos+1] << 16)|
+ (pNFCRegs->FIFO[pos+2] << 8)|
+ pNFCRegs->FIFO[pos+3];
+ pos = NAND_LARGE_DWRESERVED2_OFS;
+
+ *version = pNFCRegs->FIFO[pos];
+ return 0;
+}
+
+int WMT_check_pattern(struct nand_chip *nand, unsigned int block, unsigned int *type, unsigned int *version)
+{
+ unsigned int tag = 0;
+
+ *type = 0;
+ get_pattern_large(nand, block, &tag, version);
+ printf("block%d tag=%x ", block, tag);
+ switch (tag) {
+ case 0x42627430:
+ *type = 1;
+ printf(" version =%x\n", *version);
+ return 0;
+ case 0x31746242:
+ *type = 2;
+ printf(" version =%x\n", *version);
+ return 0;
+ default:
+ break;
+ }
+ printf(" no version\n");
+ return 0;
+}
+
+int find_bbt(struct nand_chip *nand, int chip)
+{
+ int rc = -1, bbt_blk = nand->dwBlockCount-BBT_MAX_BLOCK;
+ unsigned int i, type, page_count = 0;
+ unsigned int count = 2, first = 0;
+ unsigned int version = 0xff;
+
+ NAND_ENABLE_CE(nand, chip);
+
+ if (nand->realplanenum)
+ bbt_blk = nand->dwBlockCount - BBT_MAX_BLOCK*2;
+
+ for (i = 0; i < 30; i++)
+ bad_block_pos[chip][i] = 0;
+
+ nand->update_table_inflash = NULL;
+ nand->update_table_inram = NULL;
+ nand->isbadblock = NULL;
+
+//-----start----
+#if 0
+ enable_hw_rdmz(nand);
+
+ for (i = nand->dwBlockCount-1; i > (bbt_blk-1); i--) {
+ WMT_check_pattern(nand, i, &type, &version);
+ if (type) {
+ bad_block_pos[chip][nand->dwBlockCount-i-1] = (type|(i<<16));
+ count--;
+ } else
+ continue;
+ if (!page_count) {
+ if (i == bbt_blk) {
+ printf("find first table at block%d , failed\n", i);
+ rc = -1;
+ goto EXIT;
+ }
+ nand->update_table_inflash = update_bbt_inflash;
+ nand->update_table_inram = update_bbt_inram;
+ nand->isbadblock = isbbtbadblock;
+ count = 1;
+ first = (i|1<<16);
+ page_count = 1 + ((nand->dwBlockCount>>2) > nand->oobblock) ? 1 : 0;
+ bbt_version = version;
+
+ if (!bbt) {
+ bbt = malloc(page_count * nand->oobblock * nand->numchips);
+ if (!bbt) {
+ printf("alloc bbt failed\n");
+ rc = -1;
+ goto EXIT;
+ }
+ /*printf("alloc bbt addr=0x%x\n", (unsigned int)bbt);*/
+ }
+ rc = nand_read_block(nand, (unsigned int)&bbt[(nand->oobblock*chip)/4],
+ i*nand->dwPageCount, page_count);
+ if (rc) {
+ goto EXIT;
+ }
+ } else if (version > bbt_version) {
+ bbt_version = version;
+ rc = nand_read_block(nand, (unsigned int)&bbt[(nand->oobblock*chip)/4],
+ i*nand->dwPageCount, page_count);
+ if (rc) {
+ goto EXIT;
+ }
+ }
+ //fixme: bbt1 replace bbt0 without merge.
+ if (!count)
+ break;
+ }
+
+#endif
+//-----end----
+
+ //#ifdef WMT_HW_RDMZ /* support hw rdmz search sw rdmz bbt */
+
+ //printf("RDMZ=0x%x\n",pNFCRegs->NFCRf&RDMZ);
+ disable_hw_rdmz(nand);
+
+ nand->bbt_sw_rdmz = 1;
+ for (i = nand->dwBlockCount-1; i > (bbt_blk-1); i--) {
+ WMT_check_pattern(nand, i, &type, &version);
+ if (type) {
+ bad_block_pos[chip][nand->dwBlockCount-i-1] = (type|(i<<16));
+ count--;
+ } else
+ continue;
+ if (!page_count) {
+ if (i == bbt_blk) {
+ printf("find first table at block%d , failed\n", i);
+ rc = -1;
+ goto EXIT;
+ }
+ nand->update_table_inflash = update_bbt_inflash;
+ nand->update_table_inram = update_bbt_inram;
+ nand->isbadblock = isbbtbadblock;
+ count = 1;
+ first = (i|1<<16);
+ page_count = 1 + ((nand->dwBlockCount>>2) > nand->oobblock) ? 1 : 0;
+ bbt_version = version;
+
+ if (!bbt) {
+ bbt = malloc(page_count * nand->oobblock * nand->numchips);
+ if (!bbt) {
+ printf("alloc bbt failed\n");
+ rc = -1;
+ goto EXIT;
+ }
+ /*printf("alloc bbt addr=0x%x\n", (unsigned int)bbt);*/
+ }
+ rc = nand_read_block(nand, (unsigned int)&bbt[(nand->oobblock*chip)/4],
+ i*nand->dwPageCount, page_count);
+ if (rc) {
+ goto EXIT;
+ }
+ } else if (version > bbt_version) {
+ bbt_version = version;
+ rc = nand_read_block(nand, (unsigned int)&bbt[(nand->oobblock*chip)/4],
+ i*nand->dwPageCount, page_count);
+ if (rc) {
+ goto EXIT;
+ }
+ }
+ //fixme: bbt1 replace bbt0 without merge.
+ if (!count)
+ break;
+ }
+
+ //pNFCRegs->NFCRf = RDMZ;
+ //enable_hw_rdmz(nand);
+ //printf("HW RDMZ ON ( find_bbt )\n");
+
+ //#endif
+
+ if (!first) {
+ printf("bbt table is not found\n");
+ rc = 1;
+ goto EXIT;
+ }
+
+ printf("bbt table is found.\n");
+EXIT:
+
+ nand->bbt_sw_rdmz = 0;
+ return rc;
+}
+
+int check_block_table(struct nand_chip *nand, unsigned int scan)
+{
+ int rc = -1, i;
+
+ if ((g_WMTNFCBASE != __NFC_BASE) || !bbt) {
+ if (bbt) {
+ printf("free bbt\n");
+ free(bbt);
+ bbt = NULL;
+ }
+ if (g_WMTNFCBASE != __NFC_BASE)
+ rc = nand_probe(__NFC_BASE);
+ /*if (!rc) {
+ printf("Init Flash Failed rc=%d\r\n", rc);
+ return -1;
+ }*/
+#ifdef USE_BBT
+ for (i = 0; i < nand->numchips; i++) {
+ rc = find_bbt(nand, i);
+// printf("return of find_bbt failed rc = %d , numchips=%d, scan = %d\n", rc, nand->numchips, scan);
+ if (rc < 0) {
+ printf("find_bbt of chip%d failed\n", i);
+ return -1;
+ }
+ if (rc > 0 && scan) {
+ if (creat_bbt(nand, i)) {
+ printf("creat_bbt of chip%d failed\n", i);
+ return -1;
+ }
+ } else if (rc > 0) {
+ return -2;
+ }
+ }
+#endif
+ }
+ return 0;
+}
+
+int get_base_addr_for_eslc(struct nand_chip *nand)
+{
+ char *boot_base_name = "boot-NAND_ofs";
+ char *recovery_base_name = "recov-NAND_ofs";
+ char *misc_base_name = "misc-NAND_ofs";
+ char *misc_end_name = "filesystem-NAND_ofs";
+ char *wince = "wmt.wince.os";
+ char *keydata_base_name = "otz-NAND_ofs";
+ //char buf[32];
+ char *s = NULL;
+ unsigned int page_shift = nand->page_shift;
+
+ logo_base = 0;
+ boot_base = 0;
+ recovery_base = 0;
+ misc_base = 0;
+ misc_end = 0;
+ keydata_base=0;
+ s = getenv(boot_base_name);
+ if(s != NULL) {
+ boot_base = simple_strtoul(s, NULL, 16);
+ if(nand->dwECCBitNum == 60)
+ boot_base = boot_base / nand->oobblock_K >> 10;
+ else
+ boot_base = boot_base >> page_shift;
+ printf("boot_base: 0x%x\n", boot_base);
+ } else {
+ if(nand->dwECCBitNum == 60)
+ boot_base = 0x1c00000 / nand->oobblock_K >> 10;
+ else
+ boot_base = 0x1000000>>page_shift;
+ }
+
+ s = getenv(recovery_base_name);
+ if(s != NULL) {
+ recovery_base = simple_strtoul(s, NULL, 16);
+ if(nand->dwECCBitNum == 60)
+ recovery_base = recovery_base / nand->oobblock_K >> 10;
+ else
+ recovery_base = recovery_base >> page_shift;
+ printf("recovery_base: 0x%x\n", recovery_base);
+ }else {
+ if(nand->dwECCBitNum == 60)
+ recovery_base = 0x3800000 / nand->oobblock_K >> 10;
+ else
+ recovery_base = 0x2000000>>page_shift;
+ }
+
+ s = getenv(misc_base_name);
+ if(s != NULL) {
+ misc_base = simple_strtoul(s, NULL, 16);
+ if(nand->dwECCBitNum == 60)
+ misc_base = misc_base / nand->oobblock_K >> 10;
+ else
+ misc_base = misc_base >> page_shift;
+ printf("misc_base: 0x%x\n", misc_base);
+ } else {
+ if(nand->dwECCBitNum == 60)
+ misc_base = 0x5400000 / nand->oobblock_K >> 10;
+ else
+ misc_base = 0x3000000>>page_shift;
+ }
+
+ s = getenv(misc_end_name);
+ if(s != NULL) {
+ misc_end = simple_strtoul(s, NULL, 16);
+ if(nand->dwECCBitNum == 60)
+ misc_end = misc_end / nand->oobblock_K >> 10;
+ else
+ misc_end = misc_end >> page_shift;
+ printf("misc_end: 0x%x\n", misc_end);
+ }else {
+ if(nand->dwECCBitNum == 60)
+ misc_end = 0x7000000 / nand->oobblock_K >> 10;
+ else
+ misc_end = 0x4000000>>page_shift;
+ }
+
+ s = getenv(wince);
+ if(s != NULL && !strcmp(s, "1")) {
+ boot_base *= 2;
+ recovery_base *= 2;
+ misc_base *= 2;
+ misc_end *= 2;
+ printf("wince os.boot_base: 0x%x, recovery_base:0x%x, misc_base:0x%x, misc_end:0x%x\n", boot_base, recovery_base, misc_base, misc_end);
+ }
+
+ s = getenv(keydata_base_name);
+ if(s != NULL) {
+ keydata_base = simple_strtoul(s, NULL, 16);
+ if(nand->dwECCBitNum == 60)
+ keydata_base = keydata_base / nand->oobblock_K >> 10;
+ else
+ keydata_base = keydata_base >> page_shift;
+ printf("keydata_base: 0x%x\n", keydata_base);
+ }else {
+ keydata_base = 0;
+ }
+
+ return 0;
+}
+
+int reset_nfc(void)
+{
+ int ret = 0;
+ unsigned int backup[7];
+
+ backup[0] = pNFCRegs->NFCR9;
+ backup[1] = pNFCRegs->NFCRe;
+ backup[2] = pNFCRegs->NFCR10;
+ backup[3] = pNFCRegs->NFCR12;
+ backup[4] = pNFCRegs->NFCR13;
+ backup[5] = pNFCRegs->NFCR14;
+ backup[6] = pNFCRegs->NFCR7;
+ pNFCRegs->NFCR12 = 1;//writew(1, info->reg + NFCR12_NAND_TYPE_SEL);
+ pNFCRegs->NFCR11 = 2;
+ ret = NAND_WAIT_IDLE();
+ if (ret)
+ printf("reset nfc, wait idle time out\n");
+ pNFCRegs->NFCR11 = 0;
+
+ ret = NAND_WAIT_FLASH_READY();
+ if (ret) {
+ printf("reset nfc, The flash is not ready\n");
+ }
+ pNFCRegs->NFCRd = 0;
+ pNFCRegs->NFCR9 = backup[0];
+ pNFCRegs->NFCRe = backup[1];
+ pNFCRegs->NFCR10 = backup[2];
+ pNFCRegs->NFCR12 = backup[3];
+ pNFCRegs->NFCR13 = backup[4];
+ pNFCRegs->NFCR14 = backup[5];
+ pNFCRegs->NFCR7 = backup[6];
+
+ return ret;
+}
+
+unsigned long nand_probe(unsigned long physadr)
+{
+ struct nand_chip *nand = NULL;
+ unsigned char *dataBuf;
+ int i = 0, ChipID = 1;
+ int rc = -1;
+
+ *(volatile unsigned int *)(GPIO_BASE_ADDR + 0x200) &= ~(1<<11); /*PIN_SHARE_SDMMC1_NAND*/
+
+ pNFCRegs = (WMT_NFC_CFG *) __NFC_BASE;
+ pNand_PDma_Reg = (struct _NAND_PDMA_REG_ *) (__NFC_BASE + 0x100);
+ g_WMTNFCBASE = __NFC_BASE;
+#ifdef CONFIG_MTD_NAND_ECC_JFFS2
+ oob_config.ecc_pos[0] = NAND_JFFS2_OOB_ECCPOS0;
+ oob_config.ecc_pos[1] = NAND_JFFS2_OOB_ECCPOS1;
+ oob_config.ecc_pos[2] = NAND_JFFS2_OOB_ECCPOS2;
+ oob_config.ecc_pos[3] = NAND_JFFS2_OOB_ECCPOS3;
+ oob_config.ecc_pos[4] = NAND_JFFS2_OOB_ECCPOS4;
+ oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5;
+ oob_config.eccvalid_pos = 4;
+#else
+ oob_config.ecc_pos[0] = NAND_NOOB_ECCPOS0;
+ oob_config.ecc_pos[1] = NAND_NOOB_ECCPOS1;
+ oob_config.ecc_pos[2] = NAND_NOOB_ECCPOS2;
+ oob_config.ecc_pos[3] = NAND_NOOB_ECCPOS3;
+ oob_config.ecc_pos[4] = NAND_NOOB_ECCPOS4;
+ oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5;
+ oob_config.eccvalid_pos = NAND_NOOB_ECCVPOS;
+#endif
+ oob_config.badblock_pos = 5;
+
+ #ifdef WMT_HW_RDMZ
+ nand->bbt_sw_rdmz = 0;
+ //if (pNFCRegs->NFCRf&RDMZ)
+ // reset_nfc();
+ disable_hw_rdmz(nand);
+ //printf("HW RDMZ OFF ( probe )\n");
+ #endif
+
+ for (i=0; i<CFG_MAX_NAND_DEVICE; i++) {
+ if (nand_dev_desc[i].ChipID == NAND_ChipID_UNKNOWN) {
+ nand = &nand_dev_desc[i];
+ break;
+ }
+ }
+ if (!nand)
+ return (0);
+
+ memset((char *)nand, 0, sizeof(struct nand_chip));
+ nand->IO_ADDR = physadr;
+ nand->cache_page = -1; /* init the cache page */
+ nand->pagebuf = -1;
+ Nand_ScanChips(nand);
+
+ if (nand->totlen == 0) {
+ /* no chips found, clean up and quit */
+ memset((char *)nand, 0, sizeof(struct nand_chip));
+ nand->ChipID = NAND_ChipID_UNKNOWN;
+ printf("nand->totlen = 0 return\n");
+ return 0;
+ }
+
+ if(nand->dwRdmz)
+ printf("nand->id: 0x%x dwRdmz = %d\n", nand->id, nand->dwRdmz);
+
+ nand->ChipID = ChipID;
+ if (curr_device == -1)
+ curr_device = i;
+ if (nand->oobblock == 2048) {
+ nand->ecc.layout = &wmt_oobinfo_2048;
+ nand->ecc.size = 512;
+ nand->ecc.bytes = 8;
+ nand->ecc.steps = 4;
+ } else if (nand->oobblock == 4096) {
+ nand->ecc.layout = &wmt_oobinfo_4096;
+ nand->ecc.size = 512;
+ nand->ecc.bytes = 8;
+ nand->ecc.steps = 8;
+ } else if (nand->oobblock == 8192) {
+ nand->ecc.layout = &wmt_oobinfo_8192;
+ nand->ecc.size = 1024;
+ nand->ecc.bytes = 42;
+ nand->ecc.steps = 8;
+ } else if (nand->oobblock == 16384) {
+ nand->ecc.layout = &wmt_oobinfo_16k;
+ nand->ecc.size = 1024;
+ nand->ecc.bytes = 70;
+ nand->ecc.steps = 16;
+ } else {
+ nand->ecc.layout = &wmt_oobinfo_512;
+ nand->ecc.size = 512;
+ nand->ecc.bytes = 3;
+ nand->ecc.steps = 1;
+ }
+
+ dataBuf = malloc (nand->oobblock + nand->oobsize + 0x2300);
+ if (!dataBuf) {
+ puts ("Cannot allocate memory for data structures.\n");
+ return (0);
+ }
+ ReadDesc = (unsigned long *)((((unsigned int)dataBuf)&(~0xfff)) + 0x1000);
+ nand->data_buf = (unsigned char *)((unsigned int)ReadDesc) + 0x1000;
+ nand->buffers = malloc(nand->oobblock + nand->oobsize);
+ nand->oob_poi = nand->buffers + nand->oobblock;
+ /*printf(" dataBuf = 0x%x\r\n", (unsigned int)dataBuf);
+ printf(" ReadDesc = 0x%x\r\n", (unsigned int)ReadDesc);
+ printf(" nand->data_buf = 0x%x\r\n", (unsigned int)nand->data_buf);*/
+
+ switch(nand->dwFlashID)
+ {
+ case 0x2C88044B:
+ case 0x2C68044A:
+ case 0x2C64444B:
+ NAND_ENABLE_CE(nand, i);
+ if(nand->dwFlashID == 0x2C88044B)
+ nand_set_feature(0x04); //set to mode 4
+ //else if(nand->dwFlashID == 0x2C68044A)
+ // nand_set_feature(0x05); //set to mode 5
+ nand_get_feature();
+ NAND_DISABLE_CE(nand);
+ break;
+ }
+
+ /*scan currenct read retry chip*/
+ for(i = 0; i < READ_RETRY_CHIP_NUM; i++) {
+
+ if((nand->id == chip_table[i].nand_id)) {
+ if((nand->id2 == chip_table[i].nand_id_5th)||(chip_table[i].nand_id == 0x98DE9493)){
+ cur_chip = &chip_table[i];
+ printf("Retry nand.\n");
+ break;
+ }
+ }
+ }
+
+ if (cur_chip != NULL) {
+ if (nand->mfr == NAND_TOSHIBA) {
+ return (nand->totlen);
+ } else if (nand->mfr == NAND_SANDISK) {
+ rc = sandisk_init_retry_register(nand, 0);
+ if(rc < 0)
+ cur_chip = NULL;
+ return (nand->totlen);
+ } else if (nand->mfr == NAND_SAMSUNG || nand->mfr == NAND_MICRON) {
+ return (nand->totlen);
+ }
+ rc = read_retry_param_from_nand(nand, 0);
+
+ if(rc < 0) {
+ printf("Find retry table from nand fail!\n");
+ //cur_chip = NULL;
+ //return (nand->totlen); //Henry mark
+ }
+
+ //Get base Address
+ if(nand->mfr == NAND_HYNIX)
+ get_base_addr_for_eslc(nand);
+
+ NAND_ENABLE_CE(nand, 0);
+ if(rc == 0) { // get the cur try times of reboot when read retry.
+ cur_chip->get_parameter(nand, READ_RETRY_MODE);
+ }
+ NAND_DISABLE_CE(nand);
+ if(rc) {
+ NAND_ENABLE_CE(nand, 0);
+ if(cur_chip->get_otp_table) {
+ rc = cur_chip->get_otp_table(nand);
+ if(rc) {
+ printf("fail to get default nand otp parameter.\n");
+ cur_chip = NULL;
+ return (nand->totlen);
+ }
+ printf("Get otp param!\n");
+ rc = cur_chip->get_parameter(nand, ESLC_MODE);
+ if(rc) {
+ printf("fail to get default nand parameter.\n");
+ cur_chip = NULL;
+ return (nand->totlen);
+ }
+ printf("Get eslc param!\n");
+ } else {
+ rc = cur_chip->get_parameter(nand, READ_RETRY_MODE);
+ if(rc) {
+ printf("fail to get default nand parameter.\n");
+ cur_chip = NULL;
+ return (nand->totlen);
+ }
+ rc = cur_chip->get_parameter(nand, ESLC_MODE);
+ if(rc) {
+ printf("fail to get default nand parameter.\n");
+ cur_chip = NULL;
+ return (nand->totlen);
+ }
+ }
+ NAND_DISABLE_CE(nand);
+#if 0
+ memset(nand->data_buf, 0xff, sizeof(*cur_chip));
+ memcpy(nand->data_buf, cur_chip, sizeof(*cur_chip));
+ for(i = 0; i < sizeof(*cur_chip); i++)
+ printf("0x%x ", nand->data_buf[i]);
+ printf("\n");
+ rc = write_retry_param_to_nand(nand, 0);
+ if(rc) {
+ cur_chip = NULL;
+ printf("fail to write parameter.\n");
+ }
+#endif
+ }
+ } else {
+ printf("This chip 0x%x 0x%x not need read retry.\n", nand->id, nand->id2);
+ }
+
+ /*#ifdef WMT_HW_RDMZ //Henry mark
+ if (nand->dwRdmz == 1)
+ pNFCRegs->NFCRf = RDMZ;
+ #endif*/
+
+ return (nand->totlen);
+}
+
+#ifdef CONFIG_MTD_NAND_ECC
+#if 0
+
+/*
+ * Pre-calculated 256-way 1 byte column parity
+ */
+static const u_char nand_ecc_precalc_table[] = {
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+ 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+ 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+ 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+ 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+ 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+ 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+ 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+ 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+ 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+ 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+ 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+ 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+ 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+ 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+ 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00
+};
+
+
+/*
+ * Creates non-inverted ECC code from line parity
+ */
+#if 0
+static void nand_trans_result(u_char reg2, u_char reg3,
+ u_char *ecc_code)
+{
+ u_char a, b, i, tmp1, tmp2;
+
+ /* Initialize variables */
+ a = b = 0x80;
+ tmp1 = tmp2 = 0;
+
+ /* Calculate first ECC byte */
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP15,13,11,9 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP14,12,10,8 --> ecc_code[0] */
+ tmp1 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Calculate second ECC byte */
+ b = 0x80;
+ for (i = 0; i < 4; i++) {
+ if (reg3 & a) /* LP7,5,3,1 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ if (reg2 & a) /* LP6,4,2,0 --> ecc_code[1] */
+ tmp2 |= b;
+ b >>= 1;
+ a >>= 1;
+ }
+
+ /* Store two of the ECC bytes */
+ ecc_code[0] = tmp1;
+ ecc_code[1] = tmp2;
+}
+#endif
+/*
+ * Calculate 3 byte ECC code for 256 byte block
+ */
+
+static void nand_calculate_ecc (const u_char *dat, u_char *ecc_code)
+{
+ u_char idx, reg1, reg3;
+ int j;
+
+ /* Initialize variables */
+ reg1 = reg3 = 0;
+ ecc_code[0] = ecc_code[1] = ecc_code[2] = 0;
+
+ /* Build up column parity */
+ for(j = 0; j < 256; j++) {
+
+ /* Get CP0 - CP5 from table */
+ idx = nand_ecc_precalc_table[dat[j]];
+ reg1 ^= idx;
+
+ /* All bit XOR = 1 ? */
+ if (idx & 0x40) {
+ reg3 ^= (u_char) j;
+ }
+ }
+
+ /* Create non-inverted ECC code from line parity */
+ nand_trans_result((reg1 & 0x40) ? ~reg3 : reg3, reg3, ecc_code);
+
+ /* Calculate final ECC code */
+ ecc_code[0] = ~ecc_code[0];
+ ecc_code[1] = ~ecc_code[1];
+ ecc_code[2] = ((~reg1) << 2) | 0x03;
+}
+
+/*
+ * Detect and correct a 1 bit error for 256 byte block
+ */
+static int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+ u_char a, b, c, d1, d2, d3, add, bit, i;
+
+ /* Do error detection */
+ d1 = calc_ecc[0] ^ read_ecc[0];
+ d2 = calc_ecc[1] ^ read_ecc[1];
+ d3 = calc_ecc[2] ^ read_ecc[2];
+
+ if ((d1 | d2 | d3) == 0) {
+ /* No errors */
+ return 0;
+ } else {
+ a = (d1 ^ (d1 >> 1)) & 0x55;
+ b = (d2 ^ (d2 >> 1)) & 0x55;
+ c = (d3 ^ (d3 >> 1)) & 0x54;
+
+ /* Found and will correct single bit error in the data */
+ if ((a == 0x55) && (b == 0x55) && (c == 0x54)) {
+ c = 0x80;
+ add = 0;
+ a = 0x80;
+ for (i=0; i<4; i++) {
+ if (d1 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ c = 0x80;
+ for (i=0; i<4; i++) {
+ if (d2 & c)
+ add |= a;
+ c >>= 2;
+ a >>= 1;
+ }
+ bit = 0;
+ b = 0x04;
+ c = 0x80;
+ for (i=0; i<3; i++) {
+ if (d3 & c)
+ bit |= b;
+ c >>= 2;
+ b >>= 1;
+ }
+ b = 0x01;
+ a = dat[add];
+ a ^= (b << bit);
+ dat[add] = a;
+ return 1;
+ }
+ else {
+ i = 0;
+ while (d1) {
+ if (d1 & 0x01)
+ ++i;
+ d1 >>= 1;
+ }
+ while (d2) {
+ if (d2 & 0x01)
+ ++i;
+ d2 >>= 1;
+ }
+ while (d3) {
+ if (d3 & 0x01)
+ ++i;
+ d3 >>= 1;
+ }
+ if (i == 1) {
+ /* ECC Code Error Correction */
+ read_ecc[0] = calc_ecc[0];
+ read_ecc[1] = calc_ecc[1];
+ read_ecc[2] = calc_ecc[2];
+ return 2;
+ }
+ else {
+ /* Uncorrectable Error */
+ return -1;
+ }
+ }
+ }
+
+ /* Should never happen */
+ return -1;
+}
+#endif /* end of #if 0 by dannier*/
+#endif
+
+#ifdef CONFIG_JFFS2_NAND
+
+int read_jffs2_nand(size_t start, size_t len,
+ size_t * retlen, u_char * buf, int nanddev)
+{
+ return nand_rw(nand_dev_desc + nanddev, NANDRW_READ | NANDRW_JFFS2,
+ start, len, retlen, buf);
+}
+
+#endif /* CONFIG_JFFS2_NAND */
+int read_ubi_nand(unsigned int addr, unsigned int len, size_t * retlen, u_char * buf)
+{
+ return nand_rw(nand_dev_desc + 0, NANDRW_READ, addr, len, retlen, buf, NULL, 0);
+}
+
+int write_ubi_nand(unsigned int addr, unsigned int len, size_t * retlen, u_char * buf)
+{
+ return nand_rw(nand_dev_desc + 0, NANDRW_WRITE, addr, len, retlen, buf, NULL, 0);
+}
+
+int erase_ubi_nand(unsigned int block)
+{
+ return WMTEraseNAND(nand_dev_desc + 0, block, 1, 0);
+}
+int erase_yaffs2_nand(unsigned int block, int nanddev)
+{
+ return WMTEraseNAND(nand_dev_desc + nanddev, block, 1, 0);
+}
+int write_yaffs2_nand(unsigned int addr, __u8 * data)
+{
+ size_t retlen = 0;
+ return nand_rw(nand_dev_desc + 0, NANDRW_WRITE, addr, nand_dev_desc[0].oobblock, &retlen, data, NULL, 0);
+}
+
+int write_oob_yaffs2_nand(unsigned int addr, __u8 * data, __u8 * oob, unsigned int ooblen)
+{
+ size_t retlen = 0;
+ return nand_rw(nand_dev_desc + 0, NANDRW_WRITE, addr, nand_dev_desc[0].oobblock, &retlen, data, oob, ooblen);
+}
+int read_yaffs2_nand(unsigned int addr, __u8 * data)
+{
+ size_t retlen = 0;
+ return nand_rw(nand_dev_desc + 0, NANDRW_READ, addr, nand_dev_desc[0].oobblock, &retlen, data, NULL, 0);
+}
+int read_oob_yaffs2_nand(unsigned int addr, __u8 * data, __u8 * oob, unsigned int ooblen)
+{
+ size_t retlen = 0;
+ return nand_rw(nand_dev_desc + 0, NANDRW_READ, addr, nand_dev_desc[0].oobblock, &retlen, data, oob, ooblen);
+}
+
+int nand_block_isbad(unsigned int block)
+{
+ return isbbtbadblock(nand_dev_desc + 0, block, 0);
+}
+
+int nand_block_markbad(unsigned int block)
+{
+ int ret;
+
+ ret = nand_block_isbad(block);
+ if(ret) {
+ if(ret > 0) return 0 ;// It has been marked already.
+ return ret;
+ }
+ ret = update_bbt_inflash(nand_dev_desc + 0, 0, 0);
+ return ret;
+}
+//#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */
+int read_first_logo_page(unsigned long naddr,unsigned int maddr)
+{
+ int ret;
+ struct nand_chip *nand = nand_dev_desc + curr_device;
+ ret = WMTLoadImageFormNAND(nand, naddr,
+ maddr, nand->oobblock/*1<<nand->page_shift*/);
+
+ return ret;
+}
+
+int read_logo_file(unsigned long naddr,unsigned int maddr,int size)
+{
+ int ret;
+ struct nand_chip *nand = nand_dev_desc + curr_device;
+ ret = WMTLoadImageFormNAND(nand, naddr,
+ maddr, size);
+ return ret;
+}
+
+int wmt_nand_read(int dev, unsigned int addr, char *filename, int bytes)
+{
+ return 0;
+}
+
+int wmt_nand_write(int dev, unsigned int addr, char *filename, int bytes)
+{
+ return 0;
+}