diff options
author | Kevin | 2014-11-15 10:00:36 +0800 |
---|---|---|
committer | Kevin | 2014-11-15 10:00:36 +0800 |
commit | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (patch) | |
tree | de942df665fac4bac0d9cb7ae86910fe937b0c1a /ANDROID_3.4.5/drivers/mtd/nand | |
parent | 392e8802486cb573b916e746010e141a75f507e6 (diff) | |
download | FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.gz FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.tar.bz2 FOSSEE-netbook-kernel-source-9d40ac5867b9aefe0722bc1f110b965ff294d30d.zip |
add via modify part source code for wm8880 4.4 kitkat
Diffstat (limited to 'ANDROID_3.4.5/drivers/mtd/nand')
-rw-r--r-- | ANDROID_3.4.5/drivers/mtd/nand/Kconfig | 63 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mtd/nand/Makefile | 3 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mtd/nand/nand_base.c | 916 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mtd/nand/nand_bbt.c | 1496 | ||||
-rw-r--r-- | ANDROID_3.4.5/drivers/mtd/nand/nand_ids.c | 372 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mtd/nand/wmt_nand.c | 8285 | ||||
-rwxr-xr-x | ANDROID_3.4.5/drivers/mtd/nand/wmt_nand.h | 365 |
7 files changed, 11324 insertions, 176 deletions
diff --git a/ANDROID_3.4.5/drivers/mtd/nand/Kconfig b/ANDROID_3.4.5/drivers/mtd/nand/Kconfig index 884f99ca..8a13c2f3 100644 --- a/ANDROID_3.4.5/drivers/mtd/nand/Kconfig +++ b/ANDROID_3.4.5/drivers/mtd/nand/Kconfig @@ -343,12 +343,12 @@ config MTD_NAND_SHARPSL depends on ARCH_PXA config MTD_NAND_CAFE - tristate "NAND support for OLPC CAFÉ chip" + tristate "NAND support for OLPC CAF? chip" depends on PCI select REED_SOLOMON select REED_SOLOMON_DEC16 help - Use NAND flash attached to the CAFÉ chip designed for the OLPC + Use NAND flash attached to the CAF? chip designed for the OLPC laptop. config MTD_NAND_CS553X @@ -571,4 +571,63 @@ config MTD_NAND_FSMC Enables support for NAND Flash chips on the ST Microelectronics Flexible Static Memory Controller (FSMC) +config MTD_NAND_WMT + tristate "NAND Flash support for WMT SoC" +# depends on ARCH_VT8500 + help + This enables the NAND flash controller on the WMT + SoCs + + No board specific support is done by this driver, each board + must advertise a platform_device for the driver to attach. + +config MTD_NAND_CHIP_NUM + int "NAND Flash numbers select verbosity (1 = CE0, 2 = CE0,CE1)" + depends on MTD_NAND_WMT + default "2" + help + Determines the verbosity numbers of nand chip supported by WMT. + +config MTD_NAND_WMT_HWECC + bool "WMT NAND Hardware ECC" + depends on MTD_NAND_WMT + default y + help + Enable the use of the WMT's internal ECC generator when + using NAND. + +config MTD_NAND_HM_ECC + int "WMT NAND Hardware ECC Algorithm select verbosity(Harming ECC: =1, BCH ECC: =2)" + depends on MTD_NAND_WMT + default "2" + help + Enable the use of the WMT's internal ECC generator when + using NAND. + +choice + prompt "WMT NAND Partition for System" + default MTD_NAND_WMT_ANDROID + depends on MTD_NAND_WMT + help + Partition Nand Flash for Android, Ubuntu or Android/Ubuntu Dual system + +config MTD_NAND_WMT_ANDROID + bool "Android" + depends on MTD_NAND_WMT + help + Partition Nand Flash for WMT Android System + +config MTD_NAND_WMT_UBUNTU + bool "Ubuntu" + depends on MTD_NAND_WMT + help + Partition Nand Flash for WMT Ubuntu System + +config MTD_NAND_WMT_ANDROID_UBUNTU_DUALOS + bool "Android + Ubuntu" + depends on MTD_NAND_WMT + help + Partition Nand Flash for WMT Android/Ubuntu Dual System +endchoice + endif # MTD_NAND diff --git a/ANDROID_3.4.5/drivers/mtd/nand/Makefile b/ANDROID_3.4.5/drivers/mtd/nand/Makefile index d4b4d873..41fb98f5 100644 --- a/ANDROID_3.4.5/drivers/mtd/nand/Makefile +++ b/ANDROID_3.4.5/drivers/mtd/nand/Makefile @@ -51,5 +51,6 @@ obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o obj-$(CONFIG_MTD_NAND_RICOH) += r852.o obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ +obj-$(CONFIG_MTD_NAND_WMT) += wmt_nand.o -nand-objs := nand_base.o nand_bbt.o +nand-$(CONFIG_MTD_NAND) := nand_base.o nand_bbt.o diff --git a/ANDROID_3.4.5/drivers/mtd/nand/nand_base.c b/ANDROID_3.4.5/drivers/mtd/nand/nand_base.c index 47b19c0b..00be451a 100644 --- a/ANDROID_3.4.5/drivers/mtd/nand/nand_base.c +++ b/ANDROID_3.4.5/drivers/mtd/nand/nand_base.c @@ -47,8 +47,74 @@ #include <linux/bitops.h> #include <linux/leds.h> #include <linux/io.h> +#include <mach/hardware.h> #include <linux/mtd/partitions.h> +#include "../../../arch/arm/mach-wmt/wmt_clk.h" +#include "wmt_nand.h" +#define myDEBUG +//#undef myDEBUG +#ifdef myDEBUG +#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +#define DPRINTK(fmt, args...) +#endif + +//#define DBG_60BIT_ECC + +#ifdef NAND_BBT_BCH_ECC + +#if(CONFIG_MTD_NAND_PAGE_SIZE == 2048) +static struct nand_ecclayout wmt_oobinfo_2048_backup = { + /* nand flash new structure and BCH ECC oob info */ + .eccbytes = 40, + .eccpos = { 0, 1, 2, 3, 4, 5, 6, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 61, 62, 63}, + .oobavail = 16, + .oobfree = {{9, 4},{25, 4},{41, 4},{57, 4}} +}; + +static struct nand_ecclayout wmt_hm_oobinfo_2048_backup = { + /* nand flash old structure and Harming ECC oob info */ + .eccbytes = 14, + .eccpos = { 32, 33, 34, 36, 37, 38, 40, 41, 42, 44, 45, 46, 48, 49}, + .oobavail = 32, + .oobfree = {{0, 32}} +}; +#else + +static struct nand_ecclayout wmt_hm_oobinfo_4096_backup = { + /* nand flash old structure and Harming ECC oob info */ + .eccbytes = 27, + .eccpos = { 64, 65, 66, 68, 69, 70, 72, 73, 74, 76, 77, 78, + 80, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 94, + 96, 97, 98}, + .oobavail = 64, + .oobfree = {{0, 32}} +}; + +static struct nand_ecclayout wmt_oobinfo_4096_backup = { + /* nand flash old structure and Harming ECC oob info */ + .eccbytes = 80, + .eccpos = { 0, 1, 2, 3, 4, 5, 6, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 61, 62, 63}, + // 64, 65, 66, 67, 68, 69, 70, 77, 78, 79, + // 80, 81, 82, 83, 84, 85, 86, 93, 94, 95, + // 96, 97, 98, 99, 100,101,102,109,110,111, + // 112,113,114,115,116,117,118,125,126,127}, + .oobavail = 16, + .oobfree = {{9, 4},{25, 4},{41, 4},{57, 4}} + // .oobfree = {{9, 4},{25, 4},{41, 4},{57, 4},{73,4},{89,4},{105,4},{121,4}} +}; +#endif + +#endif +extern struct nand_bbt_descr largepage_flashbased; +extern int second_chip; /* Define default oob placement schemes for large and small page devices */ static struct nand_ecclayout nand_oob_8 = { .eccbytes = 3, @@ -103,7 +169,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, * For devices which display every fart in the system on a separate LED. Is * compiled away when LED support is disabled. */ -DEFINE_LED_TRIGGER(nand_led_trigger); +//DEFINE_LED_TRIGGER(nand_led_trigger); static int check_offs_len(struct mtd_info *mtd, loff_t ofs, uint64_t len) @@ -145,6 +211,7 @@ static void nand_release_device(struct mtd_info *mtd) chip->state = FL_READY; wake_up(&chip->controller->wq); spin_unlock(&chip->controller->lock); + auto_pll_divisor(DEV_NAND, CLK_DISABLE, 0, 0); } /** @@ -159,6 +226,28 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) return readb(chip->IO_ADDR_R); } +int wmt_recovery_call(struct notifier_block *nb, unsigned long code, void *_cmd) +{ + struct mtd_info *mtd = NULL; + struct nand_chip *chip = NULL; + mtd = container_of(nb, struct mtd_info, reboot_notifier); + chip = (struct nand_chip *)mtd->priv; + + if(chip->cur_chip && (((mtd->id >>24)&0xff) == NAND_MFR_HYNIX)) { + nand_get_device(chip, mtd, FL_WRITING); + #ifdef RETRY_DEBUG + printk("current try times: %d\n", chip->cur_chip->cur_try_times); + #endif + chip->select_chip(mtd, 0); + chip->cur_chip->set_parameter(mtd, READ_RETRY_MODE, DEFAULT_VALUE); + //chip->cur_chip->get_parameter(mtd,READ_RETRY_MODE); + chip->select_chip(mtd, -1); + nand_release_device(mtd); + } + return NOTIFY_DONE; +} +EXPORT_SYMBOL(wmt_recovery_call); + /** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip @@ -335,14 +424,22 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) int page, chipnr, res = 0, i = 0; struct nand_chip *chip = mtd->priv; u16 bad; + int page1 = 0, pagecnt = mtd->pagecnt; if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ofs += mtd->erasesize - mtd->writesize; - page = (int)(ofs >> chip->page_shift) & chip->pagemask; + if (mtd->planenum > 1) {//dan_multi + page = ((int)(ofs >> chip->page_shift) * mtd->planenum); + page1 = page + pagecnt; + page &= chip->pagemask; + page1 &= chip->pagemask; + } else + page = (int)(ofs >> chip->page_shift) & chip->pagemask; if (getchip) { - chipnr = (int)(ofs >> chip->chip_shift); + //chipnr = (int)(ofs >> chip->chip_shift); + chipnr = ((int)(ofs >> (10+chip->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); nand_get_device(chip, mtd, FL_READING); @@ -357,18 +454,27 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) bad = cpu_to_le16(chip->read_word(mtd)); if (chip->badblockpos & 0x1) bad >>= 8; - else - bad &= 0xFF; + /*else + bad &= 0xFF;*/ //masked dan_multi + if ((bad & 0xFF) != 0xff)//dan_multi + res = 1; } else { - chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, - page); - bad = chip->read_byte(mtd); + chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page); + //bad = chip->read_byte(mtd); + if (chip->read_byte(mtd) != 0xff) + res = 1; + if (mtd->planenum > 1) { + //printk("\n multiplane block bad check! \n"); + chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page1); + if (chip->read_byte(mtd) != 0xff) + res = 1; + } } - if (likely(chip->badblockbits == 8)) + /*if (likely(chip->badblockbits == 8)) res = bad != 0xFF; else - res = hweight8(bad) < chip->badblockbits; + res = hweight8(bad) < chip->badblockbits;*/ //masked dan_multi ofs += mtd->writesize; page = (int)(ofs >> chip->page_shift) & chip->pagemask; i++; @@ -395,11 +501,11 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) * Note that we retain the first error encountered in (3) or (4), finish the * procedures, and dump the error in the end. */ -static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) +static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs, int type) { struct nand_chip *chip = mtd->priv; uint8_t buf[2] = { 0, 0 }; - int block, res, ret = 0, i = 0; + int block, res = 0, ret = 0, i = 0, bits; int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); if (write_oob) { @@ -409,15 +515,39 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) memset(&einfo, 0, sizeof(einfo)); einfo.mtd = mtd; einfo.addr = ofs; - einfo.len = 1 << chip->phys_erase_shift; + //einfo.len = 1 << chip->phys_erase_shift; + einfo.len = mtd->erasesize; nand_erase_nand(mtd, &einfo, 0); } /* Get block number */ - block = (int)(ofs >> chip->bbt_erase_shift); + //block = (int)(ofs >> chip->bbt_erase_shift); + block = (((int)(ofs >> 10))/mtd->pageSizek) >> chip->pagecnt_shift; /* Mark block bad in memory-based BBT */ - if (chip->bbt) - chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + if (chip->bbt) { + if (chip->realplanenum) { + if (block == (chip->status_plane[0]/mtd->pagecnt && (chip->status_plane[1]&7))) { + if ((0xFF&(mtd->id>>24)) == NAND_MFR_TOSHIBA) + bits = ((chip->status_plane[1]&2) ? 1 : 0) + ((chip->status_plane[1]&4) ? 4 : 0);//toshiba + else + bits = ((chip->status_plane[1]&1) ? 1 : 0) + ((chip->status_plane[1]&2) ? 4 : 0);//others + chip->bbt[block >> 1] &= (~(0xF << ((block & 0x01) << 2)));//prevent from mark read fail then mark wort out! + chip->bbt[block >> 1] |= bits << ((block & 0x01) << 2); + } else { + //printk("markbad block=%d diff last err block=%d\n", block, (chip->status_plane[0]/mtd->pagecnt)); + bits = 5; + if (type == 1) + bits = 0xa; + chip->bbt[block >> 1] |= bits << ((block & 0x01) << 2); + } + } else { + bits = 1; + if (type == 1) + bits = 0x2; + chip->bbt[block >> 2] &= (~(3 << ((block & 0x03) << 1)));//prevent from mark read fail then mark wort out! + chip->bbt[block >> 2] |= bits << ((block & 0x03) << 1); + } + } /* Write bad block marker to OOB */ if (write_oob) { @@ -458,7 +588,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) if (!ret) ret = res; } - +//printk("markbad blk fin res=%d\n",res); if (!ret) mtd->ecc_stats.badblocks++; @@ -496,7 +626,7 @@ static int nand_check_wp(struct mtd_info *mtd) * calling of the scan function. */ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, - int allowbbt) + int allowbbt, int allow_readfail) { struct nand_chip *chip = mtd->priv; @@ -504,7 +634,10 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, return chip->block_bad(mtd, ofs, getchip); /* Return info from the table */ - return nand_isbad_bbt(mtd, ofs, allowbbt); + if (chip->realplanenum) + return nand_isbad_bbt_multi(mtd, ofs, allowbbt, allow_readfail); + else + return nand_isbad_bbt(mtd, ofs, allowbbt, allow_readfail); } /** @@ -539,14 +672,14 @@ void nand_wait_ready(struct mtd_info *mtd) if (in_interrupt() || oops_in_progress) return panic_nand_wait_ready(mtd, 400); - led_trigger_event(nand_led_trigger, LED_FULL); +// led_trigger_event(nand_led_trigger, LED_FULL); /* Wait until command is processed or timeout occurs */ do { if (chip->dev_ready(mtd)) break; - touch_softlockup_watchdog(); +// touch_softlockup_watchdog(); } while (time_before(jiffies, timeo)); - led_trigger_event(nand_led_trigger, LED_OFF); +// led_trigger_event(nand_led_trigger, LED_OFF); } EXPORT_SYMBOL_GPL(nand_wait_ready); @@ -803,6 +936,7 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) spinlock_t *lock = &chip->controller->lock; wait_queue_head_t *wq = &chip->controller->wq; DECLARE_WAITQUEUE(wait, current); + auto_pll_divisor(DEV_NAND, CLK_ENABLE, 0, 0); retry: spin_lock(lock); @@ -876,7 +1010,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) else timeo += (HZ * 20) / 1000; - led_trigger_event(nand_led_trigger, LED_FULL); +// led_trigger_event(nand_led_trigger, LED_FULL); /* * Apply this short delay always to ensure that we do wait tWB in any @@ -884,9 +1018,18 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) */ ndelay(100); - if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) - chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); - else + if ((state == FL_ERASING || state == FL_WRITING) && + ((chip->options & NAND_IS_AND) || chip->realplanenum)) { + /*if (state == FL_ERASING) + printk("read status multi erase\n"); + if (state == FL_WRITING) + printk("read status multi write\n");*/ + //printk("read status multi write id=0x%x\n", 0xFF&(mtd->id>>24)); + if ((0xFF&(mtd->id>>24)) == NAND_MFR_HYNIX || (0xFF&(mtd->id>>24)) == NAND_MFR_MICRON || (0xFF&(mtd->id>>24)) == NAND_MFR_INTEL) { + chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + } else + chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); + } else chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); if (in_interrupt() || oops_in_progress) @@ -903,9 +1046,17 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) cond_resched(); } } - led_trigger_event(nand_led_trigger, LED_OFF); +// led_trigger_event(nand_led_trigger, LED_OFF); status = (int)chip->read_byte(mtd); + /*if ((0xFF&(mtd->id>>24)) == 0xAD && chip->realplanenum) + while (status&0x1 || !(status&0x40)) { + chip->cmdfunc(mtd, 0x75, -1, -1); + status = (int)chip->read_byte(mtd); + printk("read status 75 multi=%x\n", status); + if (status&0x40) + break; + }*/ return status; } @@ -976,7 +1127,8 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) nand_get_device(chip, mtd, FL_UNLOCKING); /* Shift to get chip number */ - chipnr = ofs >> chip->chip_shift; + //chipnr = ofs >> chip->chip_shift; + chipnr = ((int)(ofs >> (10+chip->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); chip->select_chip(mtd, chipnr); @@ -1025,7 +1177,8 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) nand_get_device(chip, mtd, FL_LOCKING); /* Shift to get chip number */ - chipnr = ofs >> chip->chip_shift; + //chipnr = ofs >> chip->chip_shift; + chipnr = ((int)(ofs >> (10+chip->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); chip->select_chip(mtd, chipnr); @@ -1180,7 +1333,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, int datafrag_len, eccfrag_len, aligned_len, aligned_pos; int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; int index = 0; - +printk(KERN_NOTICE "r nand_read_subpage -------------------------\n"); /* Column address within the page aligned to ECC size (256bytes) */ start_step = data_offs / chip->ecc.size; end_step = (data_offs + readlen - 1) / chip->ecc.size; @@ -1462,9 +1615,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, int chipnr, page, realpage, col, bytes, aligned; struct nand_chip *chip = mtd->priv; struct mtd_ecc_stats stats; - int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + //int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + int blkcheck = mtd->pagecnt -1; int sndcmd = 1; - int ret = 0; + int ret = 0, nocache = 1; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ? @@ -1473,38 +1627,64 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, uint8_t *bufpoi, *oob, *buf; stats = mtd->ecc_stats; + mtd->ecc_err_cnt = 0; - chipnr = (int)(from >> chip->chip_shift); + //chipnr = (int)(from >> chip->chip_shift); + chipnr = ((int)(from >> (10+chip->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); chip->select_chip(mtd, chipnr); - - realpage = (int)(from >> chip->page_shift); + if(chipnr > 0) { + second_chip = 1; + } else { + second_chip = 0; + } + //realpage = (int)(from >> chip->page_shift); + realpage = ((int)(from >> 10))/mtd->pageSizek; page = realpage & chip->pagemask; - col = (int)(from & (mtd->writesize - 1)); + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) == 1) { + col = (int)(from & (mtd->writesize - 1)); + } else { + col = ((int)(from>>10)) % mtd->pageSizek; + col = col << 10; + } + //printk("chip=%d realpage=0x%x page=0x%x mask=0x%x col=0x%x \n",chipnr, realpage, page, chip->pagemask, col); buf = ops->datbuf; oob = ops->oobbuf; while (1) { + nocache = 1; bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); - + //if (!aligned || col) +//printk("readlen=%d byte=%d align=%d col=%d\n", readlen, bytes, aligned, col); /* Is the current page in the buffer? */ if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; if (likely(sndcmd)) { - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + if (!chip->realplanenum) {//dan_multi + /*page = (page / pagecnt) * pagecnt + page;//dan_multi 65->129, 129->257 + else*/ + if (aligned) + nocache = cache_read_data(mtd, chip, page, buf); + if (nocache) + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + } sndcmd = 0; } /* Now read the page into the buffer */ - if (unlikely(ops->mode == MTD_OPS_RAW)) + /*if (unlikely(ops->mode == MTD_OPS_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, page); else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); + else*/ + /* dannier comment: copy data + oob to bufpoi */ + if (!chip->realplanenum && nocache == 0) + ret = 0; else ret = chip->ecc.read_page(mtd, chip, bufpoi, page); @@ -1594,9 +1774,16 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; + if (mtd->ecc_err_cnt > mtd->ecc_err_level) { + return -NEED_REPLACEMENT; + } + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } +static int nand_block_markbad_wmt(struct mtd_info *mtd, loff_t ofs, int type); + + /** * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc * @mtd: MTD device structure @@ -1622,6 +1809,11 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, ret = nand_do_read_ops(mtd, from, &ops); *retlen = ops.retlen; nand_release_device(mtd); + + if (ret == -EBADMSG) { + nand_block_markbad_wmt(mtd, from, 1); + } + return ret; } @@ -1764,6 +1956,108 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, return status & NAND_STATUS_FAIL ? -EIO : 0; } + +/** + * nand_do_read_bb_oob - [Intern] NAND read out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operations description structure + * + * NAND read out-of-band data from the spare area + */ +static int nand_do_read_bb_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + int page, realpage, chipnr, sndcmd = 1; + struct nand_chip *chip = mtd->priv; + struct mtd_ecc_stats stats; + int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + int readlen = ops->ooblen; + int len; + uint8_t *buf = ops->oobbuf; + + pr_debug("%s: from = 0x%08Lx, len = %i\n", + __func__, (unsigned long long)from, readlen); + + stats = mtd->ecc_stats; + len = mtd->oobsize; + + if (unlikely(ops->ooboffs >= len)) { + pr_debug("%s: attempt to start read outside oob\n", + __func__); + return -EINVAL; + } + + /* Do not allow reads past end of device */ + if (unlikely(from >= mtd->size || + ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - + (from >> chip->page_shift)) * len)) { + pr_debug("%s: attempt to read beyond end of device\n", + __func__); + return -EINVAL; + } + + //chipnr = (int)(from >> chip->chip_shift); + chipnr = ((int)(from >> (10+chip->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); + chip->select_chip(mtd, chipnr); + + /* Shift to get page */ + //realpage = (int)(from >> chip->page_shift); + realpage = ((int)(from >> 10))/mtd->pageSizek; + page = realpage & chip->pagemask; + + while(1) { + sndcmd = chip->ecc.read_bb_oob(mtd, chip, page, sndcmd); + + len = min(len, readlen); + if (((mtd->id>>24)&0xff) == 0x45) { + memcpy(buf, chip->oob_poi - mtd->writesize, 1024); + len = min((int)mtd->oobsize, readlen); + } else + buf = nand_transfer_oob(chip, buf, ops, len); + + if (!(chip->options & NAND_NO_READRDY)) { + /* + * Apply delay or wait for ready/busy pin. Do this + * before the AUTOINCR check, so no problems arise if a + * chip which does auto increment is marked as + * NOAUTOINCR by the board driver. + */ + if (!chip->dev_ready) + udelay(chip->chip_delay); + else + nand_wait_ready(mtd); + } + + readlen -= len; + if (!readlen) + break; + + /* Increment page address */ + realpage++; + + page = realpage & chip->pagemask; + /* Check, if we cross a chip boundary */ + if (!page) { + chipnr++; + chip->select_chip(mtd, -1); + chip->select_chip(mtd, chipnr); + } + + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ + if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) + sndcmd = 1; + } + + ops->oobretlen = ops->ooblen; + + if (mtd->ecc_stats.failed - stats.failed) + return -EBADMSG; + + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +} /** * nand_do_read_oob - [INTERN] NAND read out-of-band * @mtd: MTD device structure @@ -1781,7 +2075,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; int readlen = ops->ooblen; int len; - uint8_t *buf = ops->oobbuf; + uint8_t *buf = ops->oobbuf, *buf1; + + mtd->ecc_err_cnt = 0; pr_debug("%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); @@ -1808,13 +2104,20 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, return -EINVAL; } - chipnr = (int)(from >> chip->chip_shift); + //chipnr = (int)(from >> chip->chip_shift); + chipnr = ((int)(from >> (10+chip->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); chip->select_chip(mtd, chipnr); /* Shift to get page */ - realpage = (int)(from >> chip->page_shift); + //realpage = (int)(from >> chip->page_shift); + realpage = ((int)(from >> 10))/mtd->pageSizek; page = realpage & chip->pagemask; - + if(chipnr > 0) { + second_chip = 1; + } else { + second_chip = 0; + } + buf1 = buf; while (1) { if (ops->mode == MTD_OPS_RAW) sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd); @@ -1865,6 +2168,9 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; + if (mtd->ecc_err_cnt > mtd->ecc_err_level) { + return -NEED_REPLACEMENT; + } return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } @@ -1903,10 +2209,78 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, goto out; } - if (!ops->datbuf) - ret = nand_do_read_oob(mtd, from, ops); - else + if (!ops->datbuf) { + /* DannierChen20101022 : Patch for avoiding yaffs2 read checkpoint signature from a bad block*/ + if (chip->bbt && nand_block_checkbad(mtd, from, 1, 0xFF, 1)) { + memset(ops->oobbuf, 0xff, ops->ooblen); + //printk("nand_do_read_oob: memset ops->ooblen=%d Byte\n", ops->ooblen); + /* DannierChen20101022 : Patch end */ + } else { + ret = nand_do_read_oob(mtd, from, ops); + if (ret == -EBADMSG) { + nand_release_device(mtd); + nand_block_markbad_wmt(mtd, from, 1); + return ret; + } + } + } else { + //printk("In nand_read_oob() call nand_do_read_ops():and ops->len is %d\n", ops->len); ret = nand_do_read_ops(mtd, from, ops); + if (ret == -EBADMSG) { + nand_release_device(mtd); + nand_block_markbad_wmt(mtd, from, 1); + return ret; + } + } + + out: + nand_release_device(mtd); + return ret; +} + + +/** + * nand_read_bbt_facmk - [MTD Interface] NAND read data and/or out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure + * + * NAND read factory-marked bad block information + */ +static int nand_read_bbt_facmk(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct nand_chip *chip = mtd->priv; + int ret = -ENOTSUPP; + //printk("enter nand_read_bbt_facmk\n"); + ops->retlen = 0; + + /* Do not allow reads past end of device */ + if (ops->datbuf && (from + ops->len) > mtd->size) { + pr_debug("%s: attempt to read beyond end of device\n", + __func__); + return -EINVAL; + } + + nand_get_device(chip, mtd, FL_READING); + + switch (ops->mode) { + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: + break; + + default: + goto out; + } + + if (!ops->datbuf) { + ret = nand_do_read_bb_oob(mtd, from, ops); + //printk("enter nand_read_bbt_facmk nand_do_read_bb_oob yes\n"); + } else { + //printk("enter nand_read_bbt_facmk nand_do_read_ops no\n"); + ret = nand_do_read_ops(mtd, from, ops); + } out: nand_release_device(mtd); @@ -2214,23 +2588,34 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, return -EINVAL; } - column = to & (mtd->writesize - 1); - subpage = column || (writelen & (mtd->writesize - 1)); - + //column = to & (mtd->writesize - 1); + column = ((int)(to>>10)) % mtd->pageSizek; + column = column << 10; + //subpage = column || (writelen & (mtd->writesize - 1)); + subpage = column || (writelen < mtd->writesize); +//printk("column=%d subpage=%d writelen=%d\n", column, subpage, writelen); if (subpage && oob) return -EINVAL; - chipnr = (int)(to >> chip->chip_shift); + //chipnr = (int)(to >> chip->chip_shift); + chipnr = ((int)(to >> (10+chip->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); chip->select_chip(mtd, chipnr); /* Check, if it is write protected */ if (nand_check_wp(mtd)) return -EIO; - realpage = (int)(to >> chip->page_shift); + //realpage = (int)(to >> chip->page_shift); + realpage = ((int)(to >> 10))/mtd->pageSizek; page = realpage & chip->pagemask; - blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + //blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + blockmask = (1 << (chip->pagecnt_shift)) - 1; + if(chipnr > 0) { + second_chip = 1; + } else { + second_chip = 0; + } /* Invalidate the page cache, when we write to the cached page */ if (to <= (chip->pagebuf << chip->page_shift) && (chip->pagebuf << chip->page_shift) < (to + ops->len)) @@ -2257,6 +2642,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (unlikely(oob)) { size_t len = min(oobwritelen, oobmaxlen); + memset(chip->oob_poi, 0xff, mtd->oobsize); /* edward wan add 20080606 */ oob = nand_fill_oob(mtd, oob, len, ops); oobwritelen -= len; } else { @@ -2264,8 +2650,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, memset(chip->oob_poi, 0xff, mtd->oobsize); } - ret = chip->write_page(mtd, chip, wbuf, page, cached, - (ops->mode == MTD_OPS_RAW)); + // ret = chip->write_page(mtd, chip, wbuf, page, cached, + // (ops->mode == MTD_OOB_RAW)); + ret = chip->write_page(mtd, chip, wbuf, page, cached, ops->mode); if (ret) break; @@ -2400,7 +2787,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, return -EINVAL; } - chipnr = (int)(to >> chip->chip_shift); + //chipnr = (int)(to >> chip->chip_shift); + chipnr = ((int)(to >> (10+chip->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); chip->select_chip(mtd, chipnr); /* Shift to get page */ @@ -2481,16 +2869,41 @@ out: } /** + * get_para - [MTD Interface] NAND get retry and eslc information + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure + */ +static int get_para(struct mtd_info *mtd, int chipnr) +{ + struct nand_chip *chip = mtd->priv; + int ret = -ENOTSUPP; + + nand_get_device(chip, mtd, FL_READING); + + + chip->select_chip(mtd, chipnr); + + chip->get_para(mtd, chip); + + chip->select_chip(mtd, -1); + + + nand_release_device(mtd); + return ret; +} +/* * single_erase_cmd - [GENERIC] NAND standard block erase command function * @mtd: MTD device structure * @page: the page address of the block which will be erased * * Standard erase command for NAND chips. */ +extern unsigned int par4_ofs; +extern unsigned int prob_end; static void single_erase_cmd(struct mtd_info *mtd, int page) { struct nand_chip *chip = mtd->priv; - /* Send commands to erase a block */ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); } @@ -2554,11 +2967,29 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, nand_get_device(chip, mtd, FL_ERASING); /* Shift to get first page */ - page = (int)(instr->addr >> chip->page_shift); - chipnr = (int)(instr->addr >> chip->chip_shift); + //page = (int)(instr->addr >> chip->page_shift); + page = ((int)(instr->addr >> 10))/mtd->pageSizek; + //chipnr = (int)(instr->addr >> chip->chip_shift); + chipnr = ((int)(instr->addr >> (10+chip->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); + + if(chipnr > 0) + second_chip = 1; + else + second_chip = 0; + + if (chip->cur_chip && (chip->cur_chip->nand_id>>24) == NAND_MFR_HYNIX && prob_end == 1) { + if (page < par4_ofs && second_chip == 0) { + //printk("SKIP Multi erase page 0x%x, par4_ofs 0x%x\n", page, par4_ofs); + instr->state = MTD_ERASE_DONE; + ret = 0; + nand_release_device(mtd); + return ret; + } + } /* Calculate pages in each block */ - pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); + //pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift); + pages_per_block = 1 << chip->pagecnt_shift; /* Select the NAND device */ chip->select_chip(mtd, chipnr); @@ -2587,13 +3018,17 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, while (len) { /* Check if we have a bad block, we do not erase bad blocks! */ - if (nand_block_checkbad(mtd, ((loff_t) page) << - chip->page_shift, 0, allowbbt)) { + if(allowbbt != 0xFF) { /* normal flow */ + //if (nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, 0, allowbbt)) { + if (nand_block_checkbad(mtd, ((loff_t) (page*mtd->pageSizek)) << 10, 0, allowbbt, 1)) { pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", __func__, page); + printk("nand_erase: attempt to erase a " + "bad block at page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; goto erase_exit; } + } /* * Invalidate the page cache, if we erase the block which @@ -2607,6 +3042,18 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, status = chip->waitfunc(mtd, chip); + if (chip->realplanenum && (status & NAND_STATUS_FAIL)) { + /*if (abv != 13479) { + status = 0xe3;//0xe5; + abv = 13479; + printk("erase page=%x error abv=%d\n", page, abv); + }*/ + chip->status_plane[0] = page; + chip->status_plane[1] = status; + printk("erase blk=%x error status=0x%x\n", page/mtd->pagecnt, status); + //while(1); + } + /* * See if operation failed and additional status checks are * available @@ -2619,9 +3066,22 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, if (status & NAND_STATUS_FAIL) { pr_debug("%s: failed erase, page 0x%08x\n", __func__, page); + printk( "nand_erase: " + "Failed erase, page 0x%08x ", page); + if(allowbbt == 0xFF) { + //len -= (1 << chip->phys_erase_shift); + len -= mtd->erasesize; + page += pages_per_block; + printk( "continue next\n"); + continue; + } else + printk( "\n"); + instr->state = MTD_ERASE_FAILED; instr->fail_addr = - ((loff_t)page << chip->page_shift); + //((loff_t)page << chip->page_shift); + ((loff_t)(page*mtd->pageSizek)) << 10; + printk("nand_erase: goto erase_exit\n"); goto erase_exit; } @@ -2632,12 +3092,15 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, if (bbt_masked_page != 0xffffffff && (page & BBT_PAGE_MASK) == bbt_masked_page) rewrite_bbt[chipnr] = - ((loff_t)page << chip->page_shift); + //((loff_t)page << chip->page_shift); + ((loff_t)(page*mtd->pageSizek)) << 10; /* Increment page address and decrement length */ - len -= (1 << chip->phys_erase_shift); + //len -= (1 << chip->phys_erase_shift); + len -= mtd->erasesize; page += pages_per_block; - + if (len) +printk("-----------------------------------er%d=blk=%d len=%llu\n",page,page/256, (unsigned long long)len); /* Check, if we cross a chip boundary */ if (len && !(page & chip->pagemask)) { chipnr++; @@ -2681,6 +3144,9 @@ erase_exit: pr_debug("%s: nand_update_bbt (%d:0x%0llx 0x%0x)\n", __func__, chipnr, rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); + printk( "nand_erase_nand: nand_update_bbt " + "(%d:0x%0llx 0x%0x) page=%x\n", chipnr, rewrite_bbt[chipnr], + chip->bbt_td->pages[chipnr], page); nand_update_bbt(mtd, rewrite_bbt[chipnr]); } @@ -2713,9 +3179,37 @@ static void nand_sync(struct mtd_info *mtd) */ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) { - return nand_block_checkbad(mtd, offs, 1, 0); + return nand_block_checkbad(mtd, offs, 1, 0, 1); +} + +static int nand_block_isbad_wmt(struct mtd_info *mtd, loff_t offs) +{ + return nand_block_checkbad(mtd, offs, 1, 0, 0); +} + +/** + * nand_block_markbad_wmt - [MTD Interface] Mark block at the given offset as bad + * @mtd: MTD device structure + * @ofs: offset relative to mtd start + * @type: worn out or reserved(unrecoveryable error occurs). + */ +static int nand_block_markbad_wmt(struct mtd_info *mtd, loff_t ofs, int type) +{ + struct nand_chip *chip = mtd->priv; + int ret; + + ret = nand_block_isbad_wmt(mtd, ofs); + if (ret) { + /* If it was bad already, return success and do nothing */ + if (ret > 0) + return 0; + return ret; + } + + return chip->block_markbad(mtd, ofs, type); } + /** * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad * @mtd: MTD device structure @@ -2734,7 +3228,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) return ret; } - return chip->block_markbad(mtd, ofs); + return chip->block_markbad(mtd, ofs, 0); } /** @@ -2759,8 +3253,7 @@ static void nand_resume(struct mtd_info *mtd) if (chip->state == FL_PM_SUSPENDED) nand_release_device(mtd); else - pr_err("%s called for a chip which is not in suspended state\n", - __func__); + pr_err("called for a chip which is not in suspended state\n"); } /* Set default functions */ @@ -2804,6 +3297,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) } } +#if 0 /* Sanitize ONFI strings so we can safely print them */ static void sanitize_string(uint8_t *s, size_t len) @@ -2834,7 +3328,20 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) return crc; } - +#endif +static int shift_bit(uint64_t value) +{ + int i = 0; + while (!(value & 1)) { + value >>= 1; + i++; + if (i == 63) + break; + } + /* return the number count of "zero" bit */ + return i; +} +#if 0 /* * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ @@ -3161,6 +3668,233 @@ ident_done: return type; } +#endif +/* + * Get the flash and manufacturer id and lookup if the type is supported + */ +static struct WMT_nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, + struct nand_chip *chip, + int busw, int *maf_id) +{ + struct WMT_nand_flash_dev *type = NULL, type_env; + int i, dev_id, maf_idx, ret = 0, varlen = 10; + unsigned int id = 0, id_5th = 0, id1, flash_bank; + char varval[10]; + + /* Select the device */ + chip->select_chip(mtd, 0); + + /* reset test: edwardwan add for debug 20071229 start*/ + chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + /* reset test: edwardwan add for debug 20071229 end*/ + + /* Send the command for reading device ID */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + *maf_id = chip->read_byte(mtd); + for (i = 0; i < 3; i++) { + dev_id = chip->read_byte(mtd); + id += ((unsigned char)dev_id) <<((2-i)*8); + } + for (i = 0; i < 4; i++) { + dev_id = chip->read_byte(mtd); + id_5th += ((unsigned char)dev_id) <<((3-i)*8); + } + printk("nand chip device id = 0x%x 0x%x\n", id, id_5th); + #ifdef NAND_DEBUG + printk("nand chip device maf_id is %x, and dev_id is %x\n",*maf_id,dev_id); + #endif + id1 = (unsigned int)id + ((*maf_id)<<24); + + + /* Lookup the flash id */ + /*for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (dev_id == nand_flash_ids[i].id) {*/ + for (i = 0; WMT_nand_flash_ids[i].dwFlashID != 0; i++) { + if (((unsigned int)id + ((*maf_id)<<24)) == WMT_nand_flash_ids[i].dwFlashID) { + if (WMT_nand_flash_ids[i].dwFlashID == 0x98D79432) + if (id_5th != WMT_nand_flash_ids[i].dwFlashID2) + continue; + if (WMT_nand_flash_ids[i].dwFlashID == 0x98DE8493) + if (id_5th != WMT_nand_flash_ids[i].dwFlashID2) + continue; + type = &WMT_nand_flash_ids[i]; + //printk("find nand chip device id\n"); + break; + } + } + #ifdef CONFIG_MTD_NAND_WMT + ret = get_flash_info_from_env(id1, id_5th, &type_env); + + if (!ret) { + if (type) + printk(KERN_WARNING "Both table and env have flash id info, use env info first\n"); + type = &type_env; + } + #endif + + if (!type) { + return ERR_PTR(-ENODEV); + } + if (!mtd->name) + /*mtd->name = type->name;*/ + mtd->name = "WMT.nand"; + + if (wmt_getsyspara("wmt.nand.ecc", varval, &varlen) == 0) { + varlen = simple_strtoul(varval, NULL, 10); + #ifdef DBG_60BIT_ECC + printk("wmt_nand_ecc=%s len=%d\n", varval, varlen); + printk("val=%s len=%d\n", varval, varlen); + #endif + flash_bank = type->dwPageSize >> 10; + if ((type->dwFlashID == 0x2C64444B && type->dwFlashID2 == 0xA9000000) + || (type->dwFlashID == 0xADDE94EB && type->dwFlashID2 == 0x74440000)) { + if (varlen > type->dwECCBitNum) { + type->dwPageSize = type->dwPageSize - 2048; + type->dwBlockSize = (type->dwBlockSize/flash_bank)*(flash_bank-2); + type->dwECCBitNum = varlen; + } + } + #ifdef DBG_60BIT_ECC + printk("blksize=0x%x pagesize=0x%x ecc=%d\n", type->dwBlockSize, type->dwPageSize, type->dwECCBitNum); + #endif + } + + /*chip->chipsize = type->chipsize << 20;*/ + chip->chipsize = (uint64_t)type->dwBlockCount * (uint64_t)type->dwBlockSize; + if (((PLANE2_READ|PLANE2_PROG|PLANE2_ERASE) & type->dwSpeedUpCmd) + == (PLANE2_READ|PLANE2_PROG|PLANE2_ERASE)) { + chip->realplanenum = 1; + printk("\n ****realplanenum**** is %d",chip->realplanenum); + } else + chip->realplanenum = 0; + + /* get all information from table */ + mtd->blkcnt = type->dwBlockCount; + chip->cellinfo = type->dwNandType << 2; + mtd->realwritesize = mtd->writesize = type->dwPageSize; + mtd->realoobsize = mtd->oobsize = type->dwSpareSize; + mtd->realerasesize = mtd->erasesize = type->dwBlockSize; + if (chip->realplanenum) {//dan_multi + mtd->planenum = 2; + mtd->writesize *= 2; + mtd->erasesize *= 2; + mtd->oobsize *= 2; + mtd->blkcnt >>= 1; + } else + mtd->planenum = 1; + mtd->dwECCBitNum = type->dwECCBitNum; + mtd->ecc_err_level = 20; + if (mtd->dwECCBitNum >= 40) + mtd->ecc_err_level = mtd->dwECCBitNum - 10; + + mtd->dwRetry = type->dwRetry; + mtd->dwRdmz = type->dwRdmz; + mtd->id = type->dwFlashID; + mtd->id2 = type->dwFlashID2; + if (((mtd->id>>24)&0xFF) == NAND_MFR_TOSHIBA && type->dwDDR == 2) + mtd->dwDDR = type->dwDDR; + else + mtd->dwDDR = 0; + mtd->pageSizek = mtd->writesize >> 10; + mtd->pagecnt = mtd->erasesize/mtd->writesize; + mtd->spec_clk = type->dwRWTimming; + mtd->spec_tadl = type->dwTadl; + + busw = type->dwDataWidth ? NAND_BUSWIDTH_16 : 0; + chip->page_offset[0] = type->dwBI0Position; + chip->page_offset[1] = type->dwBI1Position; + + /* Try to identify manufacturer */ + for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { + if (nand_manuf_ids[maf_idx].id == *maf_id) + break; + } + + /* + * Check, if buswidth is correct. Hardware drivers should set + * chip correct ! + */ + if (busw != (chip->options & NAND_BUSWIDTH_16)) { + printk(KERN_INFO "NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, + /*dev_id, nand_manuf_ids[maf_idx].name, mtd->name);*/ + id, nand_manuf_ids[maf_idx].name, mtd->name); + printk(KERN_WARNING "NAND bus width %d instead %d bit\n", + (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, + busw ? 16 : 8); + return ERR_PTR(-EINVAL); + } + + /* Calculate the address shift from the page size */ + chip->page_shift = ffs(mtd->writesize) - 1; + chip->pagecnt_shift = ffs(mtd->pagecnt) - 1; + //printk("------------------page_shift=%d pgcnt_shift=%d\n", chip->page_shift, chip->pagecnt_shift); + /* Convert chipsize to number of pages per chip -1. */ + //chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + chip->pagemask = (mtd->blkcnt*mtd->pagecnt) - 1; + + chip->bbt_erase_shift = chip->phys_erase_shift = + ffs(mtd->erasesize) - 1; + if (chip->chipsize > 0x80000000) + chip->chip_shift = shift_bit(chip->chipsize); + else + chip->chip_shift = ffs(chip->chipsize) - 1; + //chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; + + chip->badblockbits = 8; + /* Set the bad block position */ + chip->badblockpos = mtd->writesize > 512 ? + NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; + + /* Get chip options, preserve non chip based options */ + chip->options &= ~NAND_CHIPOPTIONS_MSK; + chip->options |= type->options & NAND_CHIPOPTIONS_MSK; + + /* + * Set chip as a default. Board drivers can override it, if necessary + */ + chip->options |= NAND_NO_AUTOINCR; + + /* Check if chip is a not a samsung device. Do not clear the + * options for chips which are not having an extended id. + */ + /*if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)*//* Dannier:to support new table*/ + if (*maf_id != NAND_MFR_SAMSUNG && type->dwPageSize > 512) + chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; + + chip->options |= NAND_BBT_SCAN2NDPAGE; + /* Check for AND chips with 4 page planes */ + if (!chip->realplanenum) {//dan_multi + if (chip->options & NAND_4PAGE_ARRAY) + chip->erase_cmd = multi_erase_cmd; + else + chip->erase_cmd = single_erase_cmd; + } + + /* Do not replace user supplied command function ! */ + if (mtd->writesize > 512 && chip->cmdfunc == nand_command) + chip->cmdfunc = nand_command_lp; + + printk(KERN_INFO "NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, id, + nand_manuf_ids[maf_idx].name, type->ProductName); + +#ifdef CONFIG_MTD_NAND_WMT + set_partition_size(mtd); + wmt_init_nfc(mtd, mtd->spec_clk, mtd->spec_tadl, busw); + set_ecc_info(mtd); + ret = alloc_write_cache(mtd); + if (ret) + return 0; + ret = alloc_rdmz_buffer(mtd); + if (ret) + return 0; +#endif + + return type; +} /** * nand_scan_ident - [NAND Interface] Scan for the NAND device @@ -3176,9 +3910,9 @@ ident_done: int nand_scan_ident(struct mtd_info *mtd, int maxchips, struct nand_flash_dev *table) { - int i, busw, nand_maf_id, nand_dev_id; + int i = 1, busw, nand_maf_id/*, nand_dev_id*/; struct nand_chip *chip = mtd->priv; - struct nand_flash_dev *type; + struct WMT_nand_flash_dev *type; /* Get buswidth to select the correct functions */ busw = chip->options & NAND_BUSWIDTH_16; @@ -3186,8 +3920,9 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, nand_set_defaults(chip, busw); /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, busw, - &nand_maf_id, &nand_dev_id, table); + type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id); + //type = nand_get_flash_type(mtd, chip, busw, + //&nand_maf_id, &nand_dev_id, table); if (IS_ERR(type)) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) @@ -3205,7 +3940,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ if (nand_maf_id != chip->read_byte(mtd) || - nand_dev_id != chip->read_byte(mtd)) + /*nand_dev_id != chip->read_byte(mtd))*/ + ((type->dwFlashID>>16)&0xFF) != chip->read_byte(mtd)) break; } if (i > 1) @@ -3449,7 +4185,11 @@ int nand_scan_tail(struct mtd_info *mtd) break; } } - chip->subpagesize = mtd->writesize >> mtd->subpage_sft; + //chip->subpagesize = mtd->writesize >> mtd->subpage_sft; + if (mtd->dwECCBitNum >= 24) + chip->subpagesize = 1024; + else + chip->subpagesize = 512; /* Initialize state */ chip->state = FL_READY; @@ -3480,11 +4220,14 @@ int nand_scan_tail(struct mtd_info *mtd) mtd->_block_isbad = nand_block_isbad; mtd->_block_markbad = nand_block_markbad; mtd->writebufsize = mtd->writesize; + mtd->get_para = get_para; /* propagate ecc info to mtd_info */ mtd->ecclayout = chip->ecc.layout; mtd->ecc_strength = chip->ecc.strength * chip->ecc.steps; + /* edwardwan add support 4 bits BCH ECC */ + mtd->read_bbinfo_facmk = nand_read_bbt_facmk; /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) return 0; @@ -3519,16 +4262,27 @@ EXPORT_SYMBOL(nand_scan_tail); int nand_scan(struct mtd_info *mtd, int maxchips) { int ret; + unsigned int ret1; /* Many callers got this wrong, so check for it for a while... */ - if (!mtd->owner && caller_is_module()) { + /*if (!mtd->owner && caller_is_module()) { pr_crit("%s called with NULL mtd->owner!\n", __func__); BUG(); - } - + }*/ + ret1 = *(volatile unsigned long *)PMCEU_ADDR; + if (!(ret1&0x0010000)) + printk(KERN_NOTICE "1 pmc_nand: 0x%x\n", ret1); + auto_pll_divisor(DEV_NAND, CLK_ENABLE, 0, 0); + ret1 = *(volatile unsigned long *)PMCEU_ADDR; + if (!(ret1&0x0010000)) + printk(KERN_NOTICE "2 pmc_nand: 0x%x\n", ret1); ret = nand_scan_ident(mtd, maxchips, NULL); if (!ret) ret = nand_scan_tail(mtd); + auto_pll_divisor(DEV_NAND, CLK_DISABLE, 0, 0); + ret1 = *(volatile unsigned long *)PMCEU_ADDR; + if (ret1&0x0010000) + printk(KERN_NOTICE "3 pmc_nand: 0x%x\n", ret1); return ret; } EXPORT_SYMBOL(nand_scan); @@ -3560,13 +4314,13 @@ EXPORT_SYMBOL_GPL(nand_release); static int __init nand_base_init(void) { - led_trigger_register_simple("nand-disk", &nand_led_trigger); +// led_trigger_register_simple("nand-disk", &nand_led_trigger); return 0; } static void __exit nand_base_exit(void) { - led_trigger_unregister_simple(nand_led_trigger); +// led_trigger_unregister_simple(nand_led_trigger); } module_init(nand_base_init); diff --git a/ANDROID_3.4.5/drivers/mtd/nand/nand_bbt.c b/ANDROID_3.4.5/drivers/mtd/nand/nand_bbt.c index 30d1319f..a6a9e661 100644 --- a/ANDROID_3.4.5/drivers/mtd/nand/nand_bbt.c +++ b/ANDROID_3.4.5/drivers/mtd/nand/nand_bbt.c @@ -68,7 +68,8 @@ #include <linux/delay.h> #include <linux/vmalloc.h> #include <linux/export.h> - +#include <mach/hardware.h> +//#define RETRY_DEBUG static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) { int ret; @@ -131,7 +132,7 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc * good / bad block identifiers. Same as check_pattern, but no optional empty * check. */ -static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) +static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td, int ano_bytes) { int i; uint8_t *p = buf; @@ -141,6 +142,16 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) if (p[td->offs + i] != td->pattern[i]) return -1; } + if (ano_bytes) { + //printk("sandisk flash"); + for (i = 0; i < ano_bytes; i++) { + //printk("of=0x%x da=0x%x len=%x\n", td->offs + i, p[td->offs + i], td->len); + if (p[i] != td->pattern[0]) { + printk("p[%d]=0x%x of=0x%x da=0x%x len=%x\n", i, p[i], td->offs + i, p[td->offs + i], td->len); + return -1; + } + } + } return 0; } @@ -188,10 +199,12 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, totlen = (num * bits) >> 3; marker_len = add_marker_len(td); - from = ((loff_t)page) << this->page_shift; + //from = ((loff_t)page) << this->page_shift; + from = ((loff_t)page*mtd->pageSizek) << 10; while (totlen) { - len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); + //len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); + len = min(totlen, (size_t)(mtd->erasesize)); if (marker_len) { /* * In case the BBT marker is not in the OOB area it @@ -225,8 +238,9 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, if (tmp == msk) continue; if (reserved_block_code && (tmp == reserved_block_code)) { - pr_info("nand_read_bbt: reserved block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + pr_info("nand_read_bbt: (read fail)reserved block at 0x%012llx\n", + //(loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + (loff_t)(((offs << 2) + (act >> 1))*mtd->pageSizek) << (10+this->pagecnt_shift)); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); mtd->ecc_stats.bbtblocks++; continue; @@ -235,8 +249,10 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, * Leave it for now, if it's matured we can * move this message to pr_debug. */ - pr_info("nand_read_bbt: bad block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + pr_info("nand_read_bbt: bad block at 0x%012llx (block%d)\n", + //(loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift, + (loff_t)(((offs << 2) + (act >> 1))*mtd->pageSizek) << (10+this->pagecnt_shift), + (offs << 2) + (act >> 1)); /* Factory marked bad or worn out? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); @@ -250,6 +266,111 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, } return ret; } +extern void print_nand_buffer(char *value, unsigned int length); +/** + * read_bbt_multi - [GENERIC] Read the bad block table starting from page + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @td: the bbt describtion table + * @offs: offset in the memory table + * + * Read the bad block table starting from page. + */ +static int read_bbt_multi(struct mtd_info *mtd, uint8_t *buf, int page, int num, + struct nand_bbt_descr *td, int offs) +{ + int res, ret = 0, i, j, act = 0; + struct nand_chip *this = mtd->priv; + size_t retlen, len, totlen; + loff_t from; + int bits = (td->options & NAND_BBT_NRBITS_MSK)<<1; + uint8_t msk = (uint8_t)((1 << bits) - 1); + u32 marker_len; + int reserved_block_code = td->reserved_block_code;//=0 +//printk("--------bit=%d, msk=%d, code=%d\n",bits, msk, reserved_block_code); + totlen = (num * bits) >> 3; + marker_len = add_marker_len(td); + //from = ((loff_t)page) << this->page_shift; + from = ((loff_t)page*mtd->pageSizek) << 10; +//printk("----totlen=%d, marker_len=%d, page=%d\n", totlen, marker_len, page); + while (totlen) { + //len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); + len = min(totlen, (size_t)(mtd->erasesize)); + if (marker_len) { + /* + * In case the BBT marker is not in the OOB area it + * will be just in the first page. + */ + len -= marker_len; + from += marker_len; + marker_len = 0; + } + res = mtd_read(mtd, from, len, &retlen, buf); + if (res < 0) { + if (mtd_is_eccerr(res)) { + pr_info("nand_bbt: ECC error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + return res; + } else if (mtd_is_bitflip(res)) { + pr_info("nand_bbt: corrected error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + ret = res; + } else { + pr_info("nand_bbt: error reading BBT\n"); + return res; + } + } +//printk("+++++++++++++++++len=%d, offs=%d\n", len, offs); +//print_nand_buffer(buf, 8192+64); +//print_nand_buffer(buf+8192, 8192+64); + /* Analyse data */ + for (i = 0; i < len; i++) { + uint8_t dat = buf[i]; + if (this->bbt_plane[0] == page || this->bbt_plane[1] == page) + dat = buf[i+mtd->realwritesize]; + for (j = 0; j < 8; j += bits, act += 4) { + uint8_t tmp = (dat >> j) & msk; + if (tmp == msk) + continue; + if (reserved_block_code && (tmp == reserved_block_code)) { + pr_info("nand_read_bbt: (read fail)reserved block at 0x%012llx\n", + //(loff_t)((offs << 1) + (act >> 2)) << this->bbt_erase_shift); + (loff_t)(((offs << 1) + (act >> 2))*mtd->pageSizek) << (10+this->pagecnt_shift)); + this->bbt[offs + (act >> 3)] |= 0xa << (act & 0x04); + mtd->ecc_stats.bbtblocks++; + continue; + } + /* + * Leave it for now, if it's matured we can + * move this message to pr_debug. + */ + pr_info("nand_read_bbt: bad block at 0x%012llx (block%d)\n", + //(loff_t)((offs << 1) + (act >> 2)) << this->bbt_erase_shift, + ((loff_t)(((offs << 1) + (act >> 2))*mtd->pageSizek)) << (10+this->pagecnt_shift), + (offs << 1) + (act >> 2)); + + /* Factory marked bad or worn out? */ + if (tmp == 0) { + this->bbt[offs + (act >> 3)] |= 0xf << (act & 0x04); + //printk("bbt[%d]=0x%x", offs + (act >> 3), this->bbt[offs + (act >> 3)] |= 0xf << (act & 0x04)); + } else if (tmp == 0x3) { + this->bbt[offs + (act >> 3)] |= 0xc << (act & 0x04); + //printk("bbt[%d]=0x%x", offs + (act >> 3), this->bbt[offs + (act >> 3)] |= 0xc << (act & 0x04)); + } else if (tmp == 0xc) { + this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x04); + //printk("bbt[%d]=0x%x", offs + (act >> 3), this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x04)); + } else + this->bbt[offs + (act >> 3)] |= 0x5 << (act & 0x04); + mtd->ecc_stats.badblocks++; + } + } + totlen -= len; + from += len; + } + return ret; +} /** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page @@ -270,17 +391,155 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc if (td->options & NAND_BBT_PERCHIP) { int offs = 0; for (i = 0; i < this->numchips; i++) { - if (chip == -1 || chip == i) - res = read_bbt(mtd, buf, td->pages[i], - this->chipsize >> this->bbt_erase_shift, - td, offs); + if (chip == -1 || chip == i) { + if (this->realplanenum) { + /* multi plane mode use 4-bit as an block instead of 2-bit */ + res = read_bbt_multi(mtd, buf, td->pages[i], + //this->chipsize >> this->bbt_erase_shift, + (int)(this->chipsize >> (10+this->pagecnt_shift))/mtd->pageSizek, + td, offs); + } else { + res = read_bbt(mtd, buf, td->pages[i], + //this->chipsize >> this->bbt_erase_shift, + (int)(this->chipsize >> (10+this->pagecnt_shift))/mtd->pageSizek, + td, offs); + } + } if (res) return res; - offs += this->chipsize >> (this->bbt_erase_shift + 2); + if (this->realplanenum) { + //offs += this->chipsize >> (this->bbt_erase_shift + 1); + offs += ((int)(this->chipsize >> (10+this->pagecnt_shift+1))/mtd->pageSizek); + } else { + //offs += this->chipsize >> (this->bbt_erase_shift + 2); + offs += ((int)(this->chipsize >> (10+this->pagecnt_shift+2))/mtd->pageSizek); + } } } else { - res = read_bbt(mtd, buf, td->pages[0], - mtd->size >> this->bbt_erase_shift, td, 0); + if (this->realplanenum) { + /* multi plane mode use 4-bit as an block instead of 2-bit */ + res = read_bbt_multi(mtd, buf, td->pages[0], + //mtd->size >> this->bbt_erase_shift, td, 0); + (int)(mtd->size >> (10+this->pagecnt_shift))/mtd->pageSizek, td, 0); + } else { + res = read_bbt(mtd, buf, td->pages[0], + //mtd->size >> this->bbt_erase_shift, td, 0); + (int)(mtd->size >> (10+this->pagecnt_shift))/mtd->pageSizek, td, 0); + if (res) + return res; + } + } + return 0; +} + + +/** + * read_retry_table - [GENERIC] Read the retry table starting from page + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @td: the bbt describtion table + * @offs: offset in the memory table + * + * Read the read retry table starting from page. + * + */ +static int read_retry_table(struct mtd_info *mtd, uint8_t *buf, int page, int chip) +{ + int res; + struct nand_chip *this = mtd->priv; + struct nand_read_retry_param *rdtry; + size_t retlen; + loff_t from; + + //from = ((loff_t) page) << this->page_shift; + from = ((loff_t) (page*mtd->pageSizek)) << 10; + + res = mtd->_read(mtd, from, mtd->writesize, &retlen, buf); + if (res < 0) { + if (retlen != mtd->writesize) { + printk(KERN_INFO "nand_bbt: Error reading retry table\n"); + return res; + } + printk(KERN_WARNING "nand_bbt: ECC error while reading retry table\n"); + } + + /* Analyse data */ + rdtry = (struct nand_read_retry_param *)buf; + #ifdef RETRY_DEBUG + print_nand_buffer((uint8_t *)this->cur_chip, sizeof(chip_table[0])); + #endif + if (strcmp("readretry", rdtry->magic) /*|| info->data_ecc_uncor_err == 2*/) { + printk(KERN_WARNING "nand_bbt: retry table magic number wrong%s\n", rdtry->magic); + return -1; + } + #ifdef RETRY_DEBUG + printk(KERN_WARNING "nand_bbt: copy from buf\n"); + #endif + memcpy(/*(uint8_t *)*/this->cur_chip, buf, sizeof(chip_table[0])-16); + this->cur_chip->retry_def_value[this->cur_chip->retry_reg_num] = 0xff; + this->cur_chip->retry_def_value[this->cur_chip->retry_reg_num+1] = 0xff; + #ifdef RETRY_DEBUG + print_nand_buffer((uint8_t *)this->cur_chip, sizeof(chip_table[0])); + #endif + + /*if (rdtry->eslc_reg_num) { + if (rdtry->eslc_reg_num > 5) + printk(KERN_WARNING "nand_bbt: eslc reg size=%d is too big\n", rdtry->eslc_reg_num); + this->eslc_reg_num = rdtry->eslc_reg_num; + this->eslc_cmd = kzalloc(this->eslc_reg_num, GFP_KERNEL); + if (!this->eslc_cmd) { + printk(KERN_ERR "nand_scan_bbt: create eslc_cmd Out of memory\n"); + return -ENOMEM; + } + } + memcpy(this->eslc_cmd, ((uint8_t *)&rdtry->retry_reg_num)+4, this->eslc_reg_num); + print_nand_buffer(this->eslc_cmd, this->eslc_reg_num); + + if (rdtry->total_retry_cnt && rdtry->retry_reg_num) { + if ((rdtry->total_retry_cnt * rdtry->retry_reg_num) > 64) + printk(KERN_WARNING "nand_bbt: eslc reg size=%d is too big\n", + (rdtry->total_retry_cnt * rdtry->retry_reg_num)); + this->total_retry_cnt = rdtry->total_retry_cnt; + this->retry_reg_num = rdtry->retry_reg_num; + this->retry_cmd = kzalloc((this->retry_reg_num*this->total_retry_cnt), GFP_KERNEL); + if (!this->retry_cmd) { + printk(KERN_ERR "nand_scan_bbt: create retry_cmd Out of memory\n"); + return -ENOMEM; + } + } + memcpy(this->retry_cmd, ((uint8_t *)&rdtry->retry_reg_num)+4+this->eslc_reg_num, + (this->retry_reg_num*this->total_retry_cnt)); + + + for (i = 0; i < this->total_retry_cnt; i++) { + print_nand_buffer(&this->retry_cmd[i*this->retry_reg_num], this->retry_reg_num); + }*/ + + return 0; +} + +/** + * read_abs_retry_table - [GENERIC] Read the retry table starting at a given page + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @chip: read the table for a specific chip, -1 read all chips. + * + * Read the retry table for all chips starting at a given page +*/ +static int read_abs_retry_table(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) +{ + //struct nand_chip *this = mtd->priv; + int res = 0, i, chips; + + //chips = this->numchips + chips = 1; + + for (i = 0; i < chips; i++) { + if (chip == -1 || chip == i) + res = read_retry_table(mtd, buf, td->pages[i], chip); if (res) return res; } @@ -351,7 +610,7 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, ops.oobbuf = oob; ops.len = len; - return mtd_write_oob(mtd, offs, &ops); + return mtd_write_oob(mtd, offs, &ops); /* call mtd->_write_oob*/ } static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) @@ -376,11 +635,12 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { - struct nand_chip *this = mtd->priv; + //struct nand_chip *this = mtd->priv; /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, + //scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, + scan_read_raw(mtd, buf, (loff_t)(td->pages[0]*mtd->pageSizek) << 10, mtd->writesize, td); td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; pr_info("Bad block table at page %d, version 0x%02X\n", @@ -389,7 +649,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, + //scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, + scan_read_raw(mtd, buf, (loff_t)(md->pages[0]*mtd->pageSizek) << 10, mtd->writesize, td); md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; pr_info("Bad block table at page %d, version 0x%02X\n", @@ -422,7 +683,7 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, int len) { struct mtd_oob_ops ops; - int j, ret; + int j, ret, more_bytes = 0, flag = 0; ops.ooblen = mtd->oobsize; ops.oobbuf = buf; @@ -430,20 +691,54 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, ops.datbuf = NULL; ops.mode = MTD_OPS_PLACE_OOB; + if ((mtd->id>>24) == 0x45) { + more_bytes = 6; + } for (j = 0; j < len; j++) { /* * Read the full oob until read_oob is fixed to handle single * byte reads for 16 bit buswidth. */ - ret = mtd_read_oob(mtd, offs, &ops); + /* Dannier Chen patch 2010.04.20: start + check invalid bad block on which page of blocks + should be based on flash spec, for example flash type:HY27UT088G2M-T(P) bad block + is marked at page 125 and 127 of each block. + NOT always page 0 and 1. + */ + //printk("scan_block_fast: j=%d len=%d bd->page_offset[0]=%d offset[1]=%d\n ", j, len, bd->page_offset[0], bd->page_offset[1]); +#ifdef CONFIG_MTD_NAND_WMT_HWECC + ret = mtd->read_bbinfo_facmk(mtd, offs + bd->page_offset[j]*mtd->writesize, &ops); +#else + ret = mtd->read_oob(mtd, offs + bd->page_offset[j]*mtd->writesize, &ops); +#endif /* Ignore ECC errors when checking for BBM */ if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; - if (check_short_pattern(buf, bd)) - return 1; - - offs += mtd->writesize; + if (check_short_pattern(buf, bd, more_bytes)) + flag |= 1;//return 1; + + if ((flag&1) == 0) + if (mtd->id == 0xECDED57E && mtd->id2 == 0x68440000) + if (check_short_pattern(buf+1, bd, 0)) + flag |= 1;//return 1; + + if (mtd->planenum > 1) { + if (check_short_pattern(buf+more_bytes, bd, more_bytes)) + flag |= 2;//return 1; + + if (check_short_pattern(buf+32, bd, 0)) + flag |= 2;//return 1; + + if ((flag&2) == 0) + if (mtd->id == 0xECDED57E && mtd->id2 == 0x68440000) + if (check_short_pattern(buf+33, bd, 0)) + flag |= 2;//return 1; + } + if (flag) + return flag; + /*offs += mtd->writesize;*/ + /* Dannier Chen patch 2010.04.20: end */ } return 0; } @@ -471,7 +766,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, pr_info("Scanning device for bad blocks\n"); if (bd->options & NAND_BBT_SCANALLPAGES) - len = 1 << (this->bbt_erase_shift - this->page_shift); + //len = 1 << (this->bbt_erase_shift - this->page_shift); + len = 1 << (this->pagecnt_shift); else if (bd->options & NAND_BBT_SCAN2NDPAGE) len = 2; else @@ -492,7 +788,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, * Note that numblocks is 2 * (real numblocks) here, see i+=2 * below as it makes shifting and masking less painful */ - numblocks = mtd->size >> (this->bbt_erase_shift - 1); + //numblocks = mtd->size >> (this->bbt_erase_shift - 1); + numblocks = ((int)(mtd->size >> (10+this->pagecnt_shift-1)))/mtd->pageSizek; startblock = 0; from = 0; } else { @@ -501,10 +798,12 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, chip + 1, this->numchips); return -EINVAL; } - numblocks = this->chipsize >> (this->bbt_erase_shift - 1); + //numblocks = this->chipsize >> (this->bbt_erase_shift - 1); + numblocks = ((int)(this->chipsize >> (10+this->pagecnt_shift-1)))/mtd->pageSizek; startblock = chip * numblocks; numblocks += startblock; - from = (loff_t)startblock << (this->bbt_erase_shift - 1); + //from = (loff_t)startblock << (this->bbt_erase_shift - 1); + from = (loff_t)(startblock*mtd->pageSizek) << (10+this->pagecnt_shift-1); } if (this->bbt_options & NAND_BBT_SCANLASTPAGE) @@ -512,6 +811,19 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, for (i = startblock; i < numblocks;) { int ret; + + if (((mtd->id>>24)&0xFF) == 0x45) { + /* dannierchen add to erase sandisk all blocks before check bad block 20121217 */ + /*printk(KERN_INFO "create_bbt: erase all blocks for sandisk\n");*/ + struct erase_info einfo; + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = from; + //einfo.len = 1 << this->bbt_erase_shift; + einfo.len = mtd->erasesize; + /*printk("einfo.addr is %llx einfo.len is %llx\n", einfo.addr, einfo.len);*/ + nand_erase_nand(mtd, &einfo, 0xFF); + } /* end of dannierchen erase 20121217 */ BUG_ON(bd->options & NAND_BBT_NO_OOB); @@ -529,14 +841,251 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, pr_warn("Bad eraseblock %d at 0x%012llx\n", i >> 1, (unsigned long long)from); mtd->ecc_stats.badblocks++; - } + + /* edwardwan add for debug 20071229 start */ +#if 0 + if(mtd->ecc_stats.badblocks > 10){ + printk("\rnand flash bad block number is greater than 10\n"); + return 0; + } + /* edwardwan add for debug 20071229 end */ +#endif + } else if (((mtd->id>>24)&0xFF) != 0x45) { /* dannierchen add to erase good block when first creat table 20091014 */ + /*printk(KERN_INFO "create_bbt: erase good blocks\n");*/ + struct erase_info einfo; + int res = 0; + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = from; + //einfo.len = 1 << this->bbt_erase_shift; + einfo.len = mtd->erasesize; + /*printk("einfo.addr is %llx\n",einfo.addr); + printk("einfo.len is %llx\n",einfo.len);*/ + res = nand_erase_nand(mtd, &einfo, 0xFF); + if (res < 0) + printk("enand_erase_nand addr 0x%llx result is %x\n", einfo.addr, res); + } /* end of dannierchen erase 20091014 */ i += 2; - from += (1 << this->bbt_erase_shift); + //from += (1 << this->bbt_erase_shift); + from += (mtd->erasesize); + } + return 0; +} + +/** + * create_bbt_multi - [GENERIC] Create a bad block table by scanning the device + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * @chip: create the table for a specific chip, -1 read all chips; applies only + * if NAND_BBT_PERCHIP option is set + * + * Create a bad block table by scanning the device for the given good/bad block + * identify pattern. + */ +static int create_bbt_multi(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *bd, int chip) +{ + struct nand_chip *this = mtd->priv; + int i, numblocks, len, scanlen; + int startblock; + loff_t from; + size_t readlen; + + pr_info("Scanning device for bad blocks\n"); + + if (bd->options & NAND_BBT_SCANALLPAGES) + //len = 1 << (this->bbt_erase_shift - this->page_shift); + len = 1 << this->pagecnt_shift; + else if (bd->options & NAND_BBT_SCAN2NDPAGE) + len = 2; + else + len = 1; + + if (!(bd->options & NAND_BBT_SCANEMPTY)) { + /* We need only read few bytes from the OOB area */ + scanlen = 0; + readlen = bd->len; + } else { + /* Full page content should be read */ + scanlen = mtd->writesize + mtd->oobsize; + readlen = len * mtd->writesize; + } + + if (chip == -1) { + /* + * Note that numblocks is 2 * (real numblocks) here, see i+=2 + * below as it makes shifting and masking less painful + */ + //numblocks = mtd->size >> (this->bbt_erase_shift - 2); + numblocks = ((int)(mtd->size >> (10+this->pagecnt_shift-2)))/mtd->pageSizek; + startblock = 0; + from = 0; + } else { + if (chip >= this->numchips) { + pr_warn("create_bbt_multi(): chipnr (%d) > available chips (%d)\n", + chip + 1, this->numchips); + return -EINVAL; + } + //numblocks = this->chipsize >> (this->bbt_erase_shift - 2); + numblocks = ((int)(this->chipsize >> (10+this->pagecnt_shift-2)))/mtd->pageSizek; + startblock = chip * numblocks; + numblocks += startblock; + //from = (loff_t)startblock << (this->bbt_erase_shift - 2); + from = (loff_t)(startblock*mtd->pageSizek) << (10+this->pagecnt_shift-2); + } + + if (this->bbt_options & NAND_BBT_SCANLASTPAGE) + from += mtd->erasesize - (mtd->writesize * len); + + for (i = startblock; i < numblocks;) { + int ret; + + if ((mtd->id>>24) == 0x45) { + /* dannierchen add to erase sandisk all blocks before check bad block 20121217 */ + /*printk(KERN_INFO "create_bbt_multi: erase all blocks for sandisk\n");*/ + struct erase_info einfo; + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = from; + //einfo.len = 1 << this->bbt_erase_shift; + einfo.len = mtd->erasesize; + /*printk("einfo.addr is %llx einfo.len is %llx\n", einfo.addr, einfo.len);*/ + nand_erase_nand(mtd, &einfo, 0xFF); + } /* end of dannierchen erase 20121217 */ + + BUG_ON(bd->options & NAND_BBT_NO_OOB); + + if (bd->options & NAND_BBT_SCANALLPAGES) + ret = scan_block_full(mtd, bd, from, buf, readlen, + scanlen, len); + else + ret = scan_block_fast(mtd, bd, from, buf, len); + + if (ret < 0) + return ret; + + if (ret) { + this->bbt[i >> 3] |= 0x0F << (i & 0x4); + pr_warn("Bad eraseblock %d at 0x%012llx\n", + i >> 2, (unsigned long long)from); + mtd->ecc_stats.badblocks++; + + /* edwardwan add for debug 20071229 start */ +#if 0 + if(mtd->ecc_stats.badblocks > 10){ + printk("\rnand flash bad block number is greater than 10\n"); + return 0; + } + /* edwardwan add for debug 20071229 end */ +#endif + } else if ((mtd->id>>24) != 0x45) { /* dannierchen add to erase good block when first creat table 20091014 */ + /*printk(KERN_INFO "create_bbt_multi: erase good blocks\n");*/ + struct erase_info einfo; + int res = 0; + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = from; + //einfo.len = 1 << this->bbt_erase_shift; + einfo.len = mtd->erasesize; + /*printk("einfo.addr is %llx\n",einfo.addr); + printk("einfo.len is %llx\n",einfo.len);*/ + res = nand_erase_nand(mtd, &einfo, 0xFF); + if (res < 0) + printk("enand_erase_nand addr 0x%llx result is %x\n", einfo.addr, res); + } /* end of dannierchen erase 20091014 */ + + i += 4; + //from += (1 << this->bbt_erase_shift); + from += (mtd->erasesize); + } + return 0; +} + +int create_hynix_table(struct mtd_info *mtd, int chip) +{ + int res; + res = mtd->get_para(mtd, chip); + + return res; +} + +static int check_retry_pattern(uint8_t *buf, int paglen, struct nand_bbt_descr *td) +{ + int i; + uint8_t *p = buf+paglen; + + for (i = 0; i < 10; i++) { + if (p[i] != td->pattern[i]) + return -1; + } + return 0; +} +/* +* +* read oob to search retry table +* +*/ + +static int search_hynix_retry_table(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) +{ + struct nand_chip *this = mtd->priv; + int i, chips; + int startblock, block, dir; + int bbtblocks; + //int blocktopage = this->bbt_erase_shift - this->page_shift; + int blocktopage = this->pagecnt_shift; + + /* Search direction top -> down ? */ + //if (td->options & NAND_BBT_LASTBLOCK) { + //startblock = (mtd->size >> this->bbt_erase_shift) - 1; + startblock = ((int)(mtd->size >> (10+this->pagecnt_shift)))/mtd->pageSizek - 1; + dir = -1; + /*} else { + startblock = 0; + dir = 1; + }*/ + + //so far use first chip parameter for read retry on 2-die chip + //chips = this->numchips; + chips = 1; + + //bbtblocks = this->chipsize >> this->bbt_erase_shift; + bbtblocks = ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; + startblock &= bbtblocks - 5; + + for (i = 0; i < chips; i++) { + td->pages[i] = -1; + /* Scan the maximum number of blocks */ + for (block = 0; block < td->maxblocks; block++) { + + int actblock = startblock + dir * block; + //loff_t offs = (loff_t)actblock << this->bbt_erase_shift; + loff_t offs = (loff_t)(actblock*mtd->pageSizek) << (10+this->pagecnt_shift); + + /* Read first page */ + scan_read_raw(mtd, buf, offs, mtd->writesize, td); + + if (!check_retry_pattern(buf, mtd->writesize, this->retry_pattern)) { + td->pages[i] = actblock << blocktopage; + break; + } + } + //startblock += this->chipsize >> this->bbt_erase_shift; + startblock += ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; + } + /* Check, if we found a bbt for each requested chip */ + for (i = 0; i < chips; i++) { + if (td->pages[i] == -1) + printk(KERN_WARNING "Retry block table not found for chip %d\n", i); + else + printk(KERN_WARNING "Retry block table is found for chip %d\n", i); } return 0; } + /** * search_bbt - [GENERIC] scan the device for a specific bad block table * @mtd: MTD device structure @@ -559,11 +1108,13 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr int bits, startblock, block, dir; int scanlen = mtd->writesize + mtd->oobsize; int bbtblocks; - int blocktopage = this->bbt_erase_shift - this->page_shift; + //int blocktopage = this->bbt_erase_shift - this->page_shift; + int blocktopage = this->pagecnt_shift; /* Search direction top -> down? */ if (td->options & NAND_BBT_LASTBLOCK) { - startblock = (mtd->size >> this->bbt_erase_shift) - 1; + //startblock = (mtd->size >> this->bbt_erase_shift) - 1; + startblock = ((int)(mtd->size >> (10+this->pagecnt_shift)))/mtd->pageSizek - 1; dir = -1; } else { startblock = 0; @@ -573,15 +1124,19 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; - bbtblocks = this->chipsize >> this->bbt_erase_shift; + //bbtblocks = this->chipsize >> this->bbt_erase_shift; + bbtblocks = ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; startblock &= bbtblocks - 1; } else { chips = 1; - bbtblocks = mtd->size >> this->bbt_erase_shift; + //bbtblocks = mtd->size >> this->bbt_erase_shift; + bbtblocks = ((int)(mtd->size >> (10+this->pagecnt_shift)))/mtd->pageSizek; } /* Number of bits for each erase block in the bbt */ bits = td->options & NAND_BBT_NRBITS_MSK; + if (this->realplanenum) + bits<<=1; for (i = 0; i < chips; i++) { /* Reset version information */ @@ -591,20 +1146,39 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr for (block = 0; block < td->maxblocks; block++) { int actblock = startblock + dir * block; - loff_t offs = (loff_t)actblock << this->bbt_erase_shift; + //loff_t offs = (loff_t)actblock << this->bbt_erase_shift; + loff_t offs = (loff_t)(actblock*mtd->pageSizek) << (10+this->pagecnt_shift); /* Read first page */ scan_read_raw(mtd, buf, offs, mtd->writesize, td); + //print_nand_buffer(buf+mtd->writesize, 64); if (!check_pattern(buf, scanlen, mtd->writesize, td)) { td->pages[i] = actblock << blocktopage; + printk("get bbt0 from %x\n",td->pages[i]); + this->bbt_plane[i] = 0; if (td->options & NAND_BBT_VERSION) { - offs = bbt_get_ver_offs(mtd, td); - td->version[i] = buf[offs]; + u32 offs_ver; + offs_ver = bbt_get_ver_offs(mtd, td); + td->version[i] = buf[offs_ver]; } break; } + if (this->realplanenum) + if (!check_pattern(buf, scanlen, mtd->writesize+20, td)) { + td->pages[i] = actblock << blocktopage; + //printk("get bbt1 from %x\n",td->pages[i]); + this->bbt_plane[i] = td->pages[i]; + //printk("get bbt plane[%d] from %x\n",i, this->bbt_plane[i]); + if (td->options & NAND_BBT_VERSION) { + u32 offs_ver; + offs_ver = bbt_get_ver_offs(mtd, td); + td->version[i] = buf[20+offs_ver]; + } + break; + } } - startblock += this->chipsize >> this->bbt_erase_shift; + //startblock += this->chipsize >> this->bbt_erase_shift; + startblock += ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; } /* Check, if we found a bbt for each requested chip */ for (i = 0; i < chips; i++) { @@ -617,6 +1191,9 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr return 0; } +extern int reset_nfc(struct mtd_info *mtd, unsigned int *buf, int step); +extern void nfc_hw_rdmz(struct mtd_info *mtd, int on); +extern void print_nand_register(struct mtd_info *mtd); /** * search_read_bbts - [GENERIC] scan the device for bad block table(s) * @mtd: MTD device structure @@ -673,7 +1250,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, rcode = 0xff; /* Write bad block table per chip rather than per device? */ if (td->options & NAND_BBT_PERCHIP) { - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + //numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + numblocks = ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; /* Full device write or specific chip? */ if (chipsel == -1) { nrchips = this->numchips; @@ -682,7 +1260,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, chip = chipsel; } } else { - numblocks = (int)(mtd->size >> this->bbt_erase_shift); + //numblocks = (int)(mtd->size >> this->bbt_erase_shift); + numblocks = ((int)(mtd->size >> (10+this->pagecnt_shift)))/mtd->pageSizek; nrchips = 1; } @@ -720,7 +1299,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, continue; } page = block << - (this->bbt_erase_shift - this->page_shift); + //(this->bbt_erase_shift - this->page_shift); + this->pagecnt_shift; /* Check, if the block is used by the mirror table */ if (!md || md->pages[chip] != page) goto write; @@ -731,7 +1311,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /* Set up shift count and masks for the flash table */ bits = td->options & NAND_BBT_NRBITS_MSK; - msk[2] = ~rcode; + msk[2] = 2;//~rcode; switch (bits) { case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; msk[3] = 0x01; @@ -749,14 +1329,20 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, } bbtoffs = chip * (numblocks >> 2); + if (this->realplanenum) + bbtoffs = chip * (numblocks >> 1); - to = ((loff_t)page) << this->page_shift; + //to = ((loff_t)page) << this->page_shift; + to = ((loff_t) (page*mtd->pageSizek)) << 10; /* Must we save the block contents? */ if (td->options & NAND_BBT_SAVECONTENT) { + printk("inlegal------not go-----------\n"); /* Make it block aligned */ - to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); - len = 1 << this->bbt_erase_shift; + //to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); + to &= ~((loff_t)((mtd->erasesize) - 1));//danbbg + //len = 1 << this->bbt_erase_shift; + len = mtd->erasesize; res = mtd_read(mtd, to, len, &retlen, buf); if (res < 0) { if (retlen != len) { @@ -768,15 +1354,18 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, "block for writing bad block table\n"); } /* Read oob data */ - ops.ooblen = (len >> this->page_shift) * mtd->oobsize; + //ops.ooblen = (len >> this->page_shift) * mtd->oobsize; + ops.ooblen = (mtd->pagecnt) * mtd->oobsize; ops.oobbuf = &buf[len]; res = mtd_read_oob(mtd, to + mtd->writesize, &ops); if (res < 0 || ops.oobretlen != ops.ooblen) goto outerr; /* Calc the byte offset in the buffer */ - pageoffs = page - (int)(to >> this->page_shift); - offs = pageoffs << this->page_shift; + //pageoffs = page - (int)(to >> this->page_shift); + pageoffs = page - ((int)(to >> 10))/mtd->pageSizek; + //offs = pageoffs << this->page_shift; + offs = (pageoffs*mtd->pageSizek) << 10; /* Preset the bbt area with 0xff */ memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); ooboffs = len + (pageoffs * mtd->oobsize); @@ -801,9 +1390,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, len = (size_t)(numblocks >> sft); /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); + if (len < mtd->writesize) + len = mtd->writesize; /* Preset the buffer with 0xff */ memset(buf, 0xff, len + - (len >> this->page_shift)* mtd->oobsize); + //(len >> this->page_shift)* mtd->oobsize); + mtd->pagecnt* mtd->oobsize); offs = 0; ooboffs = len; /* Pattern is located in oob area of first page */ @@ -820,17 +1412,276 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, for (j = 0; j < 4; j++, i++) { int sftcnt = (i << (3 - sft)) & sftmsk; /* Do not store the reserved bbt blocks! */ - buf[offs + (i >> sft)] &= - ~(msk[dat & 0x03] << sftcnt); + + /* dannier 2014/03/01 add a condition only retry and bbt blocks are not store + read retry command fail blocks are marked as reserved blk and need to be stored to flash */ + if (i >= (numblocks - td->maxblocks - 4) && (dat&0x3) == 0x2) { + //buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); + //printk("offs + (i >> sft)=%d data=0x%x, dat=0x%x sft=%d\n",offs + (i >> sft), ~(msk[dat & 0x03] << sftcnt), dat, sft); + } else + buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); dat >>= 2; } } + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = to; + //einfo.len = 1 << this->bbt_erase_shift; + einfo.len = mtd->erasesize; + res = nand_erase_nand(mtd, &einfo, 1); + if (res < 0) + goto outerr; + + res = scan_write_bbt(mtd, to, len, buf, + td->options & NAND_BBT_NO_OOB ? NULL : + &buf[len]); + if (res < 0) + goto outerr; + pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", + (unsigned long long)to, td->version[chip]); +//while(1); + /* Mark it as used */ + td->pages[chip] = page; + } + return 0; + + outerr: + pr_warn("nand_bbt: error while writing bad block table %d\n", res); + return res; +} + +/** + * write_bbt - [GENERIC] (Re)write the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all + * + * (Re)write the bad block table. + */ +static int write_bbt_multi(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, struct nand_bbt_descr *md, + int chipsel) +{ + struct nand_chip *this = mtd->priv; + struct erase_info einfo; + int i, j, res, chip = 0; + int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; + int nrchips, bbtoffs, pageoffs, ooboffs; + uint8_t msk[16]; + uint8_t rcode = td->reserved_block_code; + size_t retlen, len = 0; + loff_t to; + struct mtd_oob_ops ops; + + ops.ooblen = mtd->oobsize; + ops.ooboffs = 0; + ops.datbuf = NULL; + ops.mode = MTD_OPS_PLACE_OOB; + + if (!rcode) + rcode = 0xff; + /* Write bad block table per chip rather than per device? */ + if (td->options & NAND_BBT_PERCHIP) { + //numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + numblocks = ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; + /* Full device write or specific chip? */ + if (chipsel == -1) { + nrchips = this->numchips; + } else { + nrchips = chipsel + 1; + chip = chipsel; + } + } else { + //numblocks = (int)(mtd->size >> this->bbt_erase_shift); + numblocks = ((int)(mtd->size >> (10+this->pagecnt_shift)))/mtd->pageSizek; + nrchips = 1; + } + + /* Loop through the chips */ + for (; chip < nrchips; chip++) { + /* + * There was already a version of the table, reuse the page + * This applies for absolute placement too, as we have the + * page nr. in td->pages. + */ + if (td->pages[chip] != -1) { + page = td->pages[chip]; + goto write; + } + + /* + * Automatic placement of the bad block table. Search direction + * top -> down? + */ + if (td->options & NAND_BBT_LASTBLOCK) { + startblock = numblocks * (chip + 1) - 1; + dir = -1; + } else { + startblock = chip * numblocks; + dir = 1; + } + + for (i = 0; i < td->maxblocks; i++) { + int block = startblock + dir * i; + //printk("blockstatus=%x\n",((this->bbt[block >> 1] >> (2 * (block & 0x01))) & 0x0F)); + //printk("block=%x, sht=%d\n",block,(4 * (block & 0x01)) & 0x0F); + /* Check, if the block is bad */ + switch ((this->bbt[block >> 1] >> + (4 * (block & 0x01))) & 0x0F) { + case 0x01: + case 0x04: + case 0x05://case 0x07: case 0x0D: not exist for bad_fact+bad_wort + case 0x03://case 0x0B: case 0x0E: not exist for bad_fact+reserved + case 0x0C://case 0x02: case 0x08: not exist for good + reserved + case 0x0F://case 0x06: case 0x09: not exist for bad_wort+reserved + continue; + //case 0x00: case 0x0A: only good or reserved is used (so far no reserved) + } + page = block << + //(this->bbt_erase_shift - this->page_shift); + this->pagecnt_shift; + /* Check, if the block is used by the mirror table */ + if (!md || md->pages[chip] != page) + goto write; + } + pr_err("No space left to write bad block table\n"); + return -ENOSPC; + write: + + /* Set up shift count and masks for the flash table */ + bits = td->options & NAND_BBT_NRBITS_MSK; + if (this->realplanenum) + bits<<=1; + msk[2] = ~rcode; + switch (bits) { + case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; + msk[3] = 0x01; + break; + case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; + msk[3] = 0x03; + break; + case 4: sft = 1; sftmsk = 0x04; + msk[0] = 0x00; msk[1] = 0x01; msk[2] = 0x2; msk[3] = 0x03; + msk[4] = 0x04; msk[5] = 0x05; msk[6] = 0x06; msk[7] = 0x07; + msk[8] = 0x08; msk[9] = 0x09; msk[10] = /*~rcode*/0x0a; msk[11] = 0x0b; + msk[12] = 0x0c; msk[13] = 0x0d; msk[14] = 0x0e; msk[15] = 0x0f; + break; + case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; + msk[3] = 0xff; + break; + default: return -EINVAL; + } + + bbtoffs = chip * (numblocks >> 2); + if (this->realplanenum) + bbtoffs = chip * (numblocks >> 1); + + //to = ((loff_t)page) << this->page_shift; + to = ((loff_t) (page*mtd->pageSizek)) << 10; + + /* Must we save the block contents? */ + if (td->options & NAND_BBT_SAVECONTENT) { + /* Make it block aligned */printk("write bbt multi inlegal-----------------\n"); + //to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); + to &= ~((loff_t)((mtd->erasesize) - 1));//danbbg + //len = 1 << this->bbt_erase_shift; + len = mtd->erasesize; + res = mtd_read(mtd, to, len, &retlen, buf); + if (res < 0) { + if (retlen != len) { + pr_info("nand_bbt: error reading block " + "for writing the bad block table\n"); + return res; + } + pr_warn("nand_bbt: ECC error while reading " + "block for writing bad block table\n"); + } + /* Read oob data */ + //ops.ooblen = (len >> this->page_shift) * mtd->oobsize; + ops.ooblen = (mtd->pagecnt) * mtd->oobsize; + ops.oobbuf = &buf[len]; + res = mtd_read_oob(mtd, to + mtd->writesize, &ops); + if (res < 0 || ops.oobretlen != ops.ooblen) + goto outerr; + + /* Calc the byte offset in the buffer */ + //pageoffs = page - (int)(to >> this->page_shift); + pageoffs = page - ((int)(to >> 10))/mtd->pageSizek; + //offs = pageoffs << this->page_shift; + offs = (pageoffs*mtd->pageSizek) << 10; + /* Preset the bbt area with 0xff */ + memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); + ooboffs = len + (pageoffs * mtd->oobsize); + + } else if (td->options & NAND_BBT_NO_OOB) { + ooboffs = 0; + offs = td->len; + /* The version byte */ + if (td->options & NAND_BBT_VERSION) + offs++; + /* Calc length */ + len = (size_t)(numblocks >> sft); + len += offs; + /* Make it page aligned! */ + len = ALIGN(len, mtd->writesize); + /* Preset the buffer with 0xff */ + memset(buf, 0xff, len); + /* Pattern is located at the begin of first page */ + memcpy(buf, td->pattern, td->len); + } else { + /* Calc length */ + len = (size_t)(numblocks >> sft); + /* Make it page aligned! */ + len = ALIGN(len, mtd->writesize); + if (len < mtd->writesize) + len = mtd->writesize; + /* Preset the buffer with 0xff */ + memset(buf, 0xff, len + + //(len >> this->page_shift)* mtd->oobsize); + mtd->pagecnt* mtd->oobsize); + offs = 0; + ooboffs = len; + /* Pattern is located in oob area of first page */ + memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); + //printk("td->len=%d ooboffs=%d td->offs=%d\n", td->len, ooboffs, td->offs); + } + + if (td->options & NAND_BBT_VERSION) + buf[ooboffs + td->veroffs] = td->version[chip]; + + /* Walk through the memory table */ + for (i = 0; i < numblocks;) { + uint8_t dat; + dat = this->bbt[bbtoffs + (i >> 1)]; + for (j = 0; j < 2; j++, i++) { + int sftcnt = (i << (3 - sft)) & sftmsk; + /* Do not store the reserved bbt blocks! */ + /* dannier 2014/03/01 add a condition only retry and bbt blocks are not store + read retry command fail blocks are marked as reserved blk and need to be stored to flash */ + if (i >= (numblocks - td->maxblocks - 4) && (dat&0xF)==0xa) { + //buf[offs + (i >> sft)] &= ~(msk[dat & 0x0F] << sftcnt); + //printk("offs + (i >> sft)=%d data=0x%x, dat=0x%x sft=%d\n",offs + (i >> sft), ~(msk[dat & 0x0F] << sftcnt), dat, sft); + } else + buf[offs + (i >> sft)] &= ~(msk[dat & 0x0F] << sftcnt); + + dat >>= 4; + } + } + memcpy(&buf[mtd->realwritesize], buf, (numblocks>>1)); +//printk("print bbt write info ");print_nand_buffer(buf, 1536); +/*printk("Bad block table written to 0x%012llx, version 0x%02X\n", + (unsigned long long)to, td->version[chip]);dump_stack();while(1);*/ +//printk("erase blk=%d, page=0x%x len=%d copy=%d\n", (unsigned int)(to>>this->bbt_erase_shift), page, len, (numblocks>>1)); memset(&einfo, 0, sizeof(einfo)); einfo.mtd = mtd; einfo.addr = to; - einfo.len = 1 << this->bbt_erase_shift; + //einfo.len = 1 << this->bbt_erase_shift; + einfo.len = mtd->erasesize; res = nand_erase_nand(mtd, &einfo, 1); + //printk("erase ret=%d\n",res); if (res < 0) goto outerr; @@ -849,7 +1700,154 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, return 0; outerr: - pr_warn("nand_bbt: error while writing bad block table %d\n", res); + pr_warn("nand_bbt: multi error while writing bad block table %d\n", res); + return res; +} + +void copy_retry_info_to_buf(struct mtd_info *mtd, uint8_t *buf) +{ + /*uint8_t *bf; + struct nand_read_retry_param *rdtry = (struct nand_read_retry_param *)buf;*/ + struct nand_chip *this = mtd->priv; + + memcpy(buf, /*(uint8_t *)*/this->cur_chip, sizeof(chip_table[0])-16); + #ifdef RETRY_DEBUG + print_nand_buffer((uint8_t *)this->cur_chip, sizeof(chip_table[0])); + #endif + + /* + memcpy(buf, "ANDROID!", 8); + rdtry->nand_id = FlashId;//this->nand_id; + //rdtry->nand_id_5th = this->nand_id_5th; + rdtry->eslc_reg_num = this->eslc_reg_num; + rdtry->total_retry_cnt = this->total_retry_cnt; + rdtry->retry_reg_num = this->retry_reg_num; + bf = buf + 28; + if (this->eslc_reg_num) + memcpy(bf, this->eslc_cmd, this->eslc_reg_num); + bf = buf + this->eslc_reg_num; + if (this->retry_reg_num) + memcpy(bf, this->retry_cmd, this->retry_reg_num * this->total_retry_cnt); + else + printk("no retry param is writen to retry table block\n"); + + printk("save rdtry to block\n"); + print_nand_buffer(buf, 128); + */ +} + +/** + * write_hynix_table - [GENERIC] (Re)write the hynix table + * + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the retry table block + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all + * + * (Re)write the bad block table + * +*/ +static int write_hynix_table(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, int chipsel) +{ + struct nand_chip *this = mtd->priv; + struct erase_info einfo; + int i, res, chip = 0; + int startblock, dir, page, numblocks, nrchips; + uint8_t rcode = td->reserved_block_code; + size_t len = 0; + loff_t to; + struct mtd_oob_ops ops; + + ops.ooblen = mtd->oobsize; + ops.ooboffs = 0; + ops.datbuf = NULL; + ops.mode = MTD_OPS_PLACE_OOB; + + if (!rcode) + rcode = 0xff; + + //numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + numblocks = ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; + nrchips = chipsel + 1; + chip = chipsel; + + /* Loop through the chips */ + for (; chip < nrchips; chip++) { + + /* Search direction top -> down ? */ + startblock = numblocks * (chip + 1) - 5; + dir = -1; + + for (i = 0; i < td->maxblocks; i++) { + int block = startblock + dir * i; + /* Check, if the block is bad */ + if (this->realplanenum) { + switch ((this->bbt[block >> 1] >> + (4 * (block & 0x01))) & 0x0F) { + case 0x01: + case 0x04: + case 0x05://case 0x07: case 0x0D: not exist for bad_fact+bad_wort + case 0x03://case 0x0B: case 0x0E: not exist for bad_fact+reserved + case 0x0C://case 0x02: case 0x08: not exist for good + reserved + case 0x0F://case 0x06: case 0x09: not exist for bad_wort+reserved + continue; + //case 0x00: case 0x0A: only good or reserved is used (so far no reserved) + } + } else { + switch ((this->bbt[block >> 2] >> + (2 * (block & 0x03))) & 0x03) { + case 0x01: + case 0x03: + continue; + } + } + //page = block << (this->bbt_erase_shift - this->page_shift); + page = block << this->pagecnt_shift; + goto write; + } + printk(KERN_ERR "No space left to write read retry table\n"); + return -ENOSPC; + write: + + //to = ((loff_t) page) << this->page_shift; + to = ((loff_t) (page*mtd->pageSizek)) << 10; + len = mtd->writesize; + /* Preset the buffer with 0xff */ + //memset(buf, 0xff, len + (len >> this->page_shift)* mtd->oobsize); + memset(buf, 0xff, len + mtd->pagecnt* mtd->oobsize); + /* Pattern is located in oob area of first page */ + memcpy(&buf[len], td->pattern, 10); + + //------write signature into buf retry into--/ + #ifdef RETRY_DEBUG + printk("save rdtry to page=0x%x\n", page); + #endif + copy_retry_info_to_buf(mtd, buf); + + //------erase block-----------/ + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = to; + //einfo.len = 1 << this->bbt_erase_shift; + einfo.len = mtd->erasesize; + res = nand_erase_nand(mtd, &einfo, 1); + if (res < 0) + goto outerr; + printk("writing rdtry to nand flash and page addr is 0x%x, len=0x%x\n", page, len); + res = scan_write_bbt(mtd, to, len, buf, &buf[len]); + if (res < 0) + goto outerr; + + /* Mark it as used */ + td->pages[chip] = page; + } + return 0; + + outerr: + printk(KERN_WARNING + "nand_bbt: Error while writing read retry table %d\n", res); return res; } @@ -866,7 +1864,10 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b struct nand_chip *this = mtd->priv; bd->options &= ~NAND_BBT_SCANEMPTY; - return create_bbt(mtd, this->buffers->databuf, bd, -1); + if (this->realplanenum) + return create_bbt_multi(mtd, this->buffers->databuf, bd, -1); + else + return create_bbt(mtd, this->buffers->databuf, bd, -1); } /** @@ -939,8 +1940,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc continue; /* Create the table in memory by scanning the chip(s) */ - if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) - create_bbt(mtd, buf, bd, chipsel); + if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) { + //print_nand_register(mtd); + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + //print_nand_register(mtd); + + if (this->realplanenum) + create_bbt_multi(mtd, buf, bd, chipsel); + else + create_bbt(mtd, buf, bd, chipsel); + + + } td->version[i] = 1; if (md) @@ -982,14 +1994,20 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, td, md, chipsel); + if (this->realplanenum) + res = write_bbt_multi(mtd, buf, td, md, chipsel); + else + res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) return res; } /* Write the mirror bad block table to the device? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); + if (this->realplanenum) + res = write_bbt_multi(mtd, buf, md, td, chipsel); + else + res = write_bbt(mtd, buf, md, td, chipsel); if (res < 0) return res; } @@ -997,6 +2015,53 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc return 0; } +static int check_retry_table(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *rd) +{ + int i, chips, chipsel, res = 0, need_save = 0; + struct nand_chip *this = mtd->priv; + + /* Do we have a retry table per chip ? */ + /* so far, use chip 0 retry param on chip 0 and chip 1 */ + //chips = this->numchips; + chips = 1; + for (i = 0; i < chips; i++) { + /* Per chip */ + chipsel = i; + if (rd->pages[i] == -1) { + goto create; + } + #ifdef RETRY_DEBUG + printk("read_abs_retry_table\n"); + #endif + /* Read the retry table starting at a given page */ + res = read_abs_retry_table(mtd, buf, rd, chipsel); + if (res == 0) { + if(this->cur_chip != NULL) { + this->select_chip(mtd, 0); + this->cur_chip->get_parameter(mtd, READ_RETRY_MODE); + this->select_chip(mtd, -1); + } + break; + } + + create: + #ifdef RETRY_DEBUG + printk("create_hynix_table\n"); + #endif + /* Create the table in memory by get feature or get otp cmd */ + create_hynix_table(mtd, chipsel); + + need_save = 1; + + //printk("dannier write_hynix_table\n"); + /* Write the retry block table to the device ? => leave it saved after bbt searched*/ + /*res = write_hynix_table(mtd, buf, rd, chipsel); + if (res < 0) + return res;*/ + } + + return need_save; +} /** * mark_bbt_regions - [GENERIC] mark the bad block table regions * @mtd: MTD device structure @@ -1014,10 +2079,12 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; - nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); + //nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); + nrblocks = ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; } else { chips = 1; - nrblocks = (int)(mtd->size >> this->bbt_erase_shift); + //nrblocks = (int)(mtd->size >> this->bbt_erase_shift); + nrblocks = ((int)(mtd->size >> (10+this->pagecnt_shift)))/mtd->pageSizek; } for (i = 0; i < chips; i++) { @@ -1025,19 +2092,25 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) !(td->options & NAND_BBT_WRITE)) { if (td->pages[i] == -1) continue; - block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); + //block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); + block = td->pages[i] >> (this->pagecnt_shift); block <<= 1; oldval = this->bbt[(block >> 3)]; newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; - if ((oldval != newval) && td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1)); + if ((oldval != newval) && 0/*td->reserved_block_code*/) + //nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1)); + nand_update_bbt(mtd, (loff_t)(block*mtd->pageSizek) << (10+this->pagecnt_shift-1)); continue; } update = 0; - if (td->options & NAND_BBT_LASTBLOCK) + if (td->options & NAND_BBT_LASTBLOCK) { block = ((i + 1) * nrblocks) - td->maxblocks; - else + if (td->pattern[0] == 'r' && td->pattern[1] == 'e') { + block = ((i + 1) * nrblocks) - td->maxblocks - 4; + //printk("mark_bbt_region set blocks =%d ~ %d\n", block, block+3); + } + } else block = i * nrblocks; block <<= 1; for (j = 0; j < td->maxblocks; j++) { @@ -1053,12 +2126,83 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) * new ones have been marked, then we need to update the stored * bbts. This should only happen once. */ - if (update && td->reserved_block_code) - nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); + if (update && 0/*td->reserved_block_code*/) + //nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); + nand_update_bbt(mtd, (loff_t)((block - 2)*mtd->pageSizek) << (10+this->pagecnt_shift-1)); } } /** + * mark_bbt_regions_multi - [GENERIC] mark the bad block table regions + * @mtd: MTD device structure + * @td: bad block table descriptor + * + * The bad block table regions are marked as "bad" to prevent accidental + * erasures / writes. The regions are identified by the mark 0x02. + */ +static void mark_bbt_region_multi(struct mtd_info *mtd, struct nand_bbt_descr *td) +{ + struct nand_chip *this = mtd->priv; + int i, j, chips, block, nrblocks, update; + uint8_t oldval, newval; + + /* Do we have a bbt per chip? */ + if (td->options & NAND_BBT_PERCHIP) { + chips = this->numchips; + //nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); + nrblocks = ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; + } else { + chips = 1; + //nrblocks = (int)(mtd->size >> this->bbt_erase_shift); + nrblocks = ((int)(mtd->size >> (10+this->pagecnt_shift)))/mtd->pageSizek; + } + + for (i = 0; i < chips; i++) { + if ((td->options & NAND_BBT_ABSPAGE) || + !(td->options & NAND_BBT_WRITE)) { + if (td->pages[i] == -1) + continue; + //block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); + block = td->pages[i] >> (this->pagecnt_shift); + block <<= 2; + oldval = this->bbt[(block >> 3)]; + newval = oldval | (0xA << (block & 0x04)); + this->bbt[(block >> 3)] = newval; + if ((oldval != newval) && 0/*td->reserved_block_code*/) + //nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 2)); + nand_update_bbt(mtd, (loff_t)(block*mtd->pageSizek) << (10+this->pagecnt_shift-2)); + continue; + } + update = 0; + if (td->options & NAND_BBT_LASTBLOCK) { + block = ((i + 1) * nrblocks) - td->maxblocks; + if (td->pattern[0] == 'r' && td->pattern[1] == 'e') { + block = ((i + 1) * nrblocks) - td->maxblocks - 4; + //printk("mark_bbt_region set blocks =%d ~ %d\n", block, block+3); + } + } else + block = i * nrblocks; + block <<= 2; + for (j = 0; j < td->maxblocks; j++) { + oldval = this->bbt[(block >> 3)]; + newval = oldval | (0xA << (block & 0x04)); + this->bbt[(block >> 3)] = newval; + if (oldval != newval) + update = 1; + block += 4; + } + /* + * If we want reserved blocks to be recorded to flash, and some + * new ones have been marked, then we need to update the stored + * bbts. This should only happen once. + */ + if (update && 0/*td->reserved_block_code*/) + //nand_update_bbt(mtd, (loff_t)(block - 4) << (this->bbt_erase_shift - 2)); + nand_update_bbt(mtd, (loff_t)((block - 4)*mtd->pageSizek) << (10+this->pagecnt_shift-2)); + }//print_nand_buffer(this->bbt, 2048); +} + +/** * verify_bbt_descr - verify the bad block description * @mtd: MTD device structure * @bd: the table to verify @@ -1078,6 +2222,8 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) pattern_len = bd->len; bits = bd->options & NAND_BBT_NRBITS_MSK; + if (this->realplanenum) + bits<<=1; BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && !(this->bbt_options & NAND_BBT_USE_FLASH)); @@ -1096,14 +2242,17 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) } if (bd->options & NAND_BBT_PERCHIP) - table_size = this->chipsize >> this->bbt_erase_shift; + //table_size = this->chipsize >> this->bbt_erase_shift; + table_size = ((int)(this->chipsize >> (10+this->pagecnt_shift)))/mtd->pageSizek; else - table_size = mtd->size >> this->bbt_erase_shift; + //table_size = mtd->size >> this->bbt_erase_shift; + table_size = ((int)(mtd->size >> (10+this->pagecnt_shift)))/mtd->pageSizek; table_size >>= 3; table_size *= bits; if (bd->options & NAND_BBT_NO_OOB) table_size += pattern_len; - BUG_ON(table_size > (1 << this->bbt_erase_shift)); + //BUG_ON(table_size > (1 << this->bbt_erase_shift)); + BUG_ON(table_size > mtd->erasesize); } /** @@ -1118,15 +2267,21 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) * The bad block table memory is allocated here. It must be freed by calling * the nand_free_bbt function. */ +extern struct nand_read_retry_param chip_table[]; int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; - int len, res = 0; + int len, res = 0, i, need_save = 0; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; + + this->bbt_plane[1] = this->bbt_plane[0] = 0; - len = mtd->size >> (this->bbt_erase_shift + 2); + //len = mtd->size >> (this->bbt_erase_shift + 2); + len = ((int)(mtd->size >> (10+this->pagecnt_shift+2)))/mtd->pageSizek; + if (this->realplanenum) + len <<=1; /* * Allocate memory (2bit per block) and clear the memory bad block * table. @@ -1135,6 +2290,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) if (!this->bbt) return -ENOMEM; + /* Clear the memory bad block table */ + memset (this->bbt, 0x00, len); /* * If no primary table decriptor is given, scan the device to build a * memory based bad block table. @@ -1151,14 +2308,40 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) verify_bbt_descr(mtd, md); /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; + //len = (1 << this->bbt_erase_shift); + len = mtd->erasesize; + //len += (len >> this->page_shift) * mtd->oobsize; + len += (mtd->pagecnt) * mtd->oobsize; buf = vmalloc(len); if (!buf) { kfree(this->bbt); this->bbt = NULL; return -ENOMEM; } + + if (mtd->dwRetry /*&& (mtd->id>>24) == NAND_MFR_HYNIX*/) { + for (i = 0; /*i < READ_RETRY_CHIP_NUM*/; i++) { + if (chip_table[i].nand_id == 0 && chip_table[i].nand_id_5th == 0) + break; + if (mtd->id == chip_table[i].nand_id && mtd->id2 == chip_table[i].nand_id_5th) { + #ifdef RETRY_DEBUG + printk("get retry table id 0x%x, 0x%x\n", chip_table[i].nand_id, chip_table[i].nand_id_5th); + #endif + this->cur_chip = &chip_table[i]; + break; + } + } + if(this->cur_chip != NULL && chip_table[i].nand_id != 0) { + #ifdef RETRY_DEBUG + printk("search_hynix_retry_table\n"); + #endif + search_hynix_retry_table(mtd, buf, this->retry_pattern); + #ifdef RETRY_DEBUG + printk("check_retry_table\n"); + #endif + need_save = check_retry_table(mtd, buf, this->retry_pattern); + } + } /* Is the bbt at a given page? */ if (td->options & NAND_BBT_ABSPAGE) { @@ -1171,10 +2354,34 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) if (res) res = check_create(mtd, buf, bd); + + if (mtd->dwRetry && this->cur_chip != NULL && need_save) { + //printk("dannier write_hynix_table\n"); + /* Write the retry block table to the device ? */ + res = write_hynix_table(mtd, buf, this->retry_pattern, 0); + + //testing + //this->cur_chip->cur_try_times = 5; + } + + /* Prevent the rdtry block regions from erasing / writing */ + if (this->realplanenum) + mark_bbt_region_multi(mtd, this->retry_pattern); + else + mark_bbt_region(mtd, this->retry_pattern); + /* Prevent the bbt regions from erasing / writing */ - mark_bbt_region(mtd, td); - if (md) - mark_bbt_region(mtd, md); + if (this->realplanenum) + mark_bbt_region_multi(mtd, td); + else + mark_bbt_region(mtd, td); + if (md) { + if (this->realplanenum) + mark_bbt_region_multi(mtd, md); + else + mark_bbt_region(mtd, md); + } + vfree(buf); return res; @@ -1200,15 +2407,20 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) return -EINVAL; /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) + //len = (1 << this->bbt_erase_shift); + len = mtd->erasesize; + //len += (len >> this->page_shift) * mtd->oobsize; + len += (mtd->pagecnt) * mtd->oobsize; + //buf = kmalloc(len, GFP_KERNEL); + buf = vmalloc(len); + if (!buf) { + printk(KERN_ERR "nand_update_bbt: Out of memory\n"); return -ENOMEM; - + } /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { - chip = (int)(offs >> this->chip_shift); + //chip = (int)(offs >> this->chip_shift); + chip = ((int)(offs >> (10+this->pagecnt_shift)))/(mtd->pageSizek*mtd->blkcnt); chipsel = chip; } else { chip = 0; @@ -1221,17 +2433,24 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) /* Write the bad block table to the device? */ if (td->options & NAND_BBT_WRITE) { - res = write_bbt(mtd, buf, td, md, chipsel); + if (this->realplanenum) + res = write_bbt_multi(mtd, buf, td, md, chipsel); + else + res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) goto out; } /* Write the mirror bad block table to the device? */ if (md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); + if (this->realplanenum) + res = write_bbt_multi(mtd, buf, md, td, chipsel); + else + res = write_bbt(mtd, buf, md, td, chipsel); } out: - kfree(buf); + vfree(buf); + //printk("nand_update_bbt free mem res=%d\n", res); return res; } @@ -1307,6 +2526,7 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { static int nand_create_badblock_pattern(struct nand_chip *this) { struct nand_bbt_descr *bd; + //struct mtd_info *mtd = this->priv; if (this->badblock_pattern) { pr_warn("Bad block pattern already allocated; not replacing\n"); return -EINVAL; @@ -1319,6 +2539,10 @@ static int nand_create_badblock_pattern(struct nand_chip *this) bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; bd->pattern = scan_ff_pattern; bd->options |= NAND_BBT_DYNAMICSTRUCT; + //if ((0xFF&(mtd->id>>24)) == 0x45 || (0xFF&(mtd->id>>24)) == NAND_MFR_HYNIX) + bd->options |= NAND_BBT_SCAN2NDPAGE;//All type of flash need to scan 2 page per block. + bd->page_offset[0] = this->page_offset[0]; + bd->page_offset[1] = this->page_offset[1]; this->badblock_pattern = bd; return 0; } @@ -1366,6 +2590,11 @@ int nand_default_bbt(struct mtd_info *mtd) this->bbt_td = NULL; this->bbt_md = NULL; } + + if (this->bbt_td->reserved_block_code && this->realplanenum) { + this->bbt_td->reserved_block_code = 0x5; + this->bbt_md->reserved_block_code = 0x5; + } if (!this->badblock_pattern) nand_create_badblock_pattern(this); @@ -1379,30 +2608,113 @@ int nand_default_bbt(struct mtd_info *mtd) * @offs: offset in the device * @allowbbt: allow access to bad block table region */ -int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) +int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt, int allow_readfail) { struct nand_chip *this = mtd->priv; int block; uint8_t res; /* Get block number * 2 */ - block = (int)(offs >> (this->bbt_erase_shift - 1)); + //block = (int)(offs >> (this->bbt_erase_shift - 1)); + block = ((int)(offs >> (10+this->pagecnt_shift - 1)))/mtd->pageSizek; res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: " + pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08llx: " "(block %d) 0x%02x\n", - (unsigned int)offs, block >> 1, res); + offs, block >> 1, res); switch ((int)res) { case 0x00: return 0; case 0x01: + #if 0 + if (allowbbt != 0xFF && this->state == FL_READY) { + struct erase_info einfo; + int res1 = 0; + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = offs; + //einfo.len = (1 << this->bbt_erase_shift); + einfo.len = mtd->erasesize; + printk("einfo.addr is 0x%llx\n",einfo.addr); + printk("einfo.len is 0x%llx\n", einfo.len); + res1 = nand_erase_nand(mtd, &einfo, 0xFF); + if (res1 < 0) + printk("nand_erase_nand addr 0x%llx result is %d\n", einfo.addr, res1); + } + #endif return 1; case 0x02: - return allowbbt ? 0 : 1; + if ((block>>1) < (mtd->blkcnt - 8)) { + if (allow_readfail) + return 0; + else + return 1; + } else + return allowbbt ? 0 : 1; } return 1; } +/** + * nand_isbad_bbt_multi - [NAND Interface] Check if a block is bad + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + */ +int nand_isbad_bbt_multi(struct mtd_info *mtd, loff_t offs, int allowbbt, int allow_readfail) +{ + struct nand_chip *this = mtd->priv; + int block; + uint8_t res; + + /* Get block number * 4 */ + //block = (int)(offs >> (this->bbt_erase_shift - 2)); + block = ((int)(offs >> (10+this->pagecnt_shift - 2)))/mtd->pageSizek; + res = (this->bbt[block >> 3] >> (block & 0x4)) & 0x0F; + + pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08llx: " + "(block %d) 0x%02x\n", + offs, block >> 2, res); + /*printk("nand_isbad_bbt(): bbt info for offs 0x%08llx: " + "(block %d) 0x%02x\n", + offs, block >> 2, res);*/ + + switch ((int)res) { + case 0x00: + return 0; + case 0x01: + case 0x04: + case 0x05://1 or both 2 blocks worn out! + #if 0 + if (allowbbt != 0xFF && this->state == FL_READY) { + struct erase_info einfo; + int res1 = 0; + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = offs; + //einfo.len = (1 << this->bbt_erase_shift); + einfo.len = mtd->erasesize; + printk("einfo.addr is 0x%llx\n",einfo.addr); + printk("einfo.len is 0x%llx\n", einfo.len); + res1 = nand_erase_nand(mtd, &einfo, 0xFF); + if (res1 < 0) + printk("nand_erase_nand addr 0x%llx result is %d\n", einfo.addr, res1); + } + #endif + return 1; + case 0x0A://usually two block are reserved + if ((block>>2) < (mtd->blkcnt - 8)) { + if (allow_readfail) + return 0; + else + return 1; + } else + return allowbbt ? 0 : 1; + } + return 1; +} + + EXPORT_SYMBOL(nand_scan_bbt); EXPORT_SYMBOL(nand_default_bbt); diff --git a/ANDROID_3.4.5/drivers/mtd/nand/nand_ids.c b/ANDROID_3.4.5/drivers/mtd/nand/nand_ids.c index af4fe8ca..723379af 100644 --- a/ANDROID_3.4.5/drivers/mtd/nand/nand_ids.c +++ b/ANDROID_3.4.5/drivers/mtd/nand/nand_ids.c @@ -164,6 +164,373 @@ struct nand_flash_dev nand_flash_ids[] = { {NULL,} }; +#define MLC 1 +#define SLC 0 +#define WD8 0 +struct WMT_nand_flash_dev WMT_nand_flash_ids[] = { + + + {0xADD314A5, 4096, 2048, 64, 0x40000, 5, 125, 127, 0, WD8, 1, 0, 1, MLC, 4, 0x140A0C12, 0x64780046, 0, 0, 0, 0x00000000, 0x00000000, "HY27UT088G2M-T(P)", LP_OPTIONS}, + {0xADF1801D, 1024, 2048, 64, 0x20000, 4, 0, 1, 0, WD8, 4, 0, 1, SLC, 4, 0x140A0F12, 0x64780064, 0, 0, 0, 0x00000000, 0x00000000, "HY27UF081G2A", LP_OPTIONS}, + {0xADF1001D, 1024, 2048, 64, 0x20000, 4, 0, 1, 0, WD8, 4, 0, 1, SLC, 4, 0x140A0C12, 0x64780046, 0, 0, 0, 0x00000000, 0x00000000, "H27U1G8F2BFR", LP_OPTIONS}, + {0xADD59425, 4096, 4096, 218, 0x80000, 5, 125, 127, 0, WD8, 1, 0, 1, MLC, 12, 0x140A0F12, 0x64780064, 0, 0, 0, 0x00000000, 0x00000000, "HY27UAG8T2A", LP_OPTIONS}, + {0xADD7949A, 2048, 8192, 448,0x200000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 24, 0x140A0C12, 0x64500064, 0, 0, 0, 0x74420000, 0x00000000, "H27UBG8T2ATR", LP_OPTIONS}, + {0xADD5949A, 1024, 8192, 448,0x200000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 24, 0x140A0C12, 0x64640064, 0, 0, 0, 0x74420000, 0x00000000, "H27UAG8T2BTR-BC", LP_OPTIONS}, + {0xADD794DA, 2048, 8192, 640,0x200000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 24, 0x10080A12, 0x645000C8, 0, 1, 1, 0x74C30000, 0x00000000, "H27UBG8T2BTR", LP_OPTIONS}, + {0xADD79491, 2048, 8192, 640,0x200000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 40, 0x10060812, 0x647800C8, 0, 1, 1, 0x00000000, 0x00003FFF, "H27UBG8T2CTR-F20", LP_OPTIONS}, + {0xADDE94DA, 4096, 8192, 640,0x200000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 40, 0x10060812, 0x647800C8, 1, 1, 1, 0x00000000, 0x00003FFF, "H27UCG8T2ATR-F20", LP_OPTIONS}, + {0xADDE94EB, 2048,16384,1280,0x400000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 40, 0x10060812, 0x647800C8, 0, 1, 1, 0x74440000, 0x00003FFF, "H27UCG8T2BTR-F20", LP_OPTIONS}, + + {0xECD314A5, 4096, 2048, 64, 0x40000, 5, 127, 0, 0, WD8, 1, 0, 1, MLC, 4, 0x140A0C12, 0x64400064, 0, 0, 0, 0x00000000, 0x00000000, "K9G8G08X0A", LP_OPTIONS}, + {0xECD59429, 4096, 4096, 218, 0x80000, 5, 127, 0, 0, WD8, 1, 0, 1, MLC, 12, 0x140A0F12, 0x64400064, 0, 0, 0, 0x00000000, 0x00000000, "K9GAG08UXD", LP_OPTIONS}, + {0xECF10095, 1024, 2048, 64, 0x20000, 4, 0, 1, 0, WD8, 4, 0, 1, SLC, 4, 0x140a1412, 0x64400064, 0, 0, 0, 0x00000000, 0x00000000, "K9F1G08U0B", LP_OPTIONS}, + {0xECD514B6, 4096, 4096, 128, 0x80000, 5, 127, 0, 0, WD8, 1, 0, 1, MLC, 4, 0x140A0C12, 0x64400064, 0, 0, 0, 0x00000000, 0x00000000, "K9GAG08U0M", LP_OPTIONS}, + {0xECD755B6, 8192, 4096, 128, 0x80000, 5, 127, 0, 0, WD8, 1, 0, 1, MLC, 4, 0x140A0C12, 0x64400064, 0, 0, 0, 0x00000000, 0x00000000, "K9LBG08U0M", LP_OPTIONS}, + {0xECD58472, 2048, 8192, 436,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 24, 0x140A0F12, 0x6440012C, 0, 0, 0, 0x00000000, 0x00000000, "K9GAG08U0E", LP_OPTIONS}, + {0xECD7947A, 4096, 8192, 448,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 24, 0x140A0F12, 0x6478012C, 0, 0, 1, 0x54430000, 0x00003FFF, "K9GBG08U0A", LP_OPTIONS}, + {0xECD59476, 2048, 8192, 448,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 24, 0x140A0C12, 0x6478012C, 0, 0, 0, 0x00000000, 0x00000000, "K9GAG08U0F", LP_OPTIONS}, + {0xECD7947E, 4096, 8192,1024,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 40, 0x140B0B12, 0x6478012C, 0, 1, 1, 0x64440000, 0x00000000, "K9GBG08U0B", LP_OPTIONS}, + {0xECDED57A, 8192, 8192, 640,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 24, 0x140A0C12, 0x6478012C, 0, 0, 1, 0x58430000, 0x00000000, "K9LCG08U0A", LP_OPTIONS}, + {0xECDED57E, 8192, 8192,1024,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 40, 0x140B0C12, 0x6478012C, 0, 1, 1, 0x68440000, 0x00000000, "K9LCG08U0B", LP_OPTIONS}, + + {0x98D594BA, 4096, 4096, 218, 0x80000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 12, 0x190F0F12, 0x64b40070, 0, 0, 0, 0x00000000, 0x00000000, "TC58NVG4D1DTG0", LP_OPTIONS}, + {0x98D19015, 1024, 2048, 64, 0x20000, 4, 0, 1, 0, WD8, 4, 0, 1, SLC, 4, 0x140A0C12, 0x64B40011, 0, 0, 0, 0x00000000, 0x00000000, "TC58NVG0S3ETA00", LP_OPTIONS}, + {0x98D59432, 2048, 8192, 448,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 24, 0x100A0C12, 0x64B40084, 0, 0, 0, 0x00000000, 0x00000000, "TC58NVG4D2FTA00", LP_OPTIONS}, + {0x98D58432, 2048, 8192, 640,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 40, 0x100A0F12, 0x64B4012C, 0, 1, 1, 0x72560000, 0x00000000, "TC58NVG4D2HTA00", LP_OPTIONS}, + {0x98DE8493, 2048,16384,1280,0x400000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 40, 0x10070A12, 0x64B4012C, 0, 1, 1, 0x72570000, 0x00000000, "TC58NVG6DCJTA00", LP_OPTIONS}, + {0x98DE8493, 2048,16384,1280,0x400000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 40, 0x10070A12, 0x64B4012C, 2, 1, 1, 0x72D70000, 0x00000000, "TC58TEG6DCJTA00-DDR", LP_OPTIONS}, + {0x98D79432, 4096, 8192, 448,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 24, 0x100A0C12, 0x64FF0078, 0, 0, 0, 0x76550000, 0x00000000, "TC58NVG5D2FTAI0", LP_OPTIONS}, + {0x98D79432, 4096, 8192, 640,0x100000, 5, 0, 127, 0, WD8, 1, 0, 1, MLC, 40, 0x10070A12, 0x64B4012C, 0, 1, 1, 0x76560000, 0x00000000, "TC58NVG5D2HTA00", LP_OPTIONS}, + {0x98D78493, 1024,16384,1280,0x400000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 40, 0x10070A12, 0x6478012C, 1, 1, 1, 0x72570000, 0x00000000, "TC58TEG5DCJTA00", LP_OPTIONS}, + {0x98DE9493, 2048,16384,1280,0x400000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 40, 0x10070A12, 0x6478012C, 1, 1, 1, 0x76570000, 0x00000000, "TC58TEG6DDKTA00", LP_OPTIONS}, + {0x98D78493, 1024,16384,1280,0x400000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 40, 0x10070A12, 0x6478012C, 1, 1, 1, 0x72500000, 0x00000000, "TC58TEG5DCKTA00", LP_OPTIONS}, + + {0x2C88044B, 4096, 8192, 448,0x200000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 24, 0x100B1210/*0x321E32C8*/, 0x647800C8, 0, 0, 0, 0x00000000, 0x00000000, "MT29F64G08CBAAA", LP_OPTIONS}, + {0x2C88044B, 4096, 8192, 448,0x200000, 5, 0, 255, 0, WD8, 1, 0, 1, MLC, 24, 0x100B1210/*0x321E32C8*/, 0x647800C8, 0, 0, 0, 0x00000000, 0x00000000, "MT29F128G08CFAAA", LP_OPTIONS}, + {0x2C48044A, 2048, 4096, 224,0x100000, 5, 0, 1, 0, WD8, 1, 0, 1, MLC, 12, 0x100B1210/*0x321E32C8*/, 0x647800C8, 0, 0, 0, 0xA5000000, 0x00003FFF, "MT29F16G08CBACA", LP_OPTIONS}, + {0x2C68044A, 4096, 4096, 224,0x100000, 5, 0, 1, 0, WD8, 1, 0, 1, MLC, 12, 0x100B1210/*0x321E32C8*/, 0x647800C8, 0, 0, 0, 0xA9000000, 0x00003FFF, "MT29F32G08CBACA", LP_OPTIONS}, + {0x2C64444B, 4096, 8192, 744,0x200000, 5, 0, 1, 0, WD8, 1, 0, 1, MLC, 40, 0x100B1210/*0x321E32C8*/, 0x647800C8, 0, 1, 0, 0xA9000000, 0x00000000, "MT29F64G08CBABA", LP_OPTIONS}, + {0x2C44444B, 2048, 8192, 744,0x200000, 5, 0, 1, 0, WD8, 1, 0, 1, MLC, 40, 0x100B1210/*0x321E32C8*/, 0x647800C8, 0, 1, 0, 0xA9000000, 0x00000000, "MT29F32G08CBADA", LP_OPTIONS}, + + {0x45DE9493, 2048,16384,1280,0x400000, 5, 0, 1, 0, WD8, 1, 0, 1, MLC, 40, 0x10070A12, 0x64B40140, 1, 1, 1, 0x76570000, 0x00003FFF, "SDTNQGAMA-008G", LP_OPTIONS}, + {0x45D78493, 1024,16384,1280,0x400000, 5, 0, 1, 0, WD8, 1, 0, 1, MLC, 40, 0x10070A12, 0x64B40140, 1, 1, 1, 0x72570000, 0x00000000, "SDTNQFAMA-004G", LP_OPTIONS}, + + {0x8968044A, 4096, 4096, 224,0x100000, 5, 0, 1, 0, WD8, 1, 0, 1, MLC, 12, 0x100B1210, 0x647800C8, 0, 0, 0, 0xA9000000, 0x00003FFF, "JS29F32G08AAME1", LP_OPTIONS}, + {0x8988244B, 4096, 8192, 448,0x200000, 5, 0, 1, 0, WD8, 1, 0, 1, MLC, 24, 0x10070A12, 0x64400046, 0, 0, 0, 0xA9000000, 0x00000000, "JS29F64G08AAME1", LP_OPTIONS}, + {0x8988244B, 4096, 8192, 744,0x200000, 5, 0, 1, 0, WD8, 1, 0, 1, MLC, 40, 0x10070A12, 0x64B40046, 0, 0, 0, 0xA9840000, 0x00000000, "JS29F64G08AAMF1", LP_OPTIONS}, + + + {0xC2F1801D, 1024, 2048, 64, 0x20000, 4, 0, 1, 0, WD8, 4, 0, 1, SLC, 4, 0x140A0F12, 0x64400064, 0, 0, 0, 0x00000000, 0x00000000, "MX30LF1G08AA", LP_OPTIONS}, + + {0x92F18095, 1024, 2048, 64, 0x20000, 4, 0, 1, 0, WD8, 4, 0, 1, SLC, 4, 0x140A0C12, 0x64400064, 0, 0, 0, 0x40000000, 0x00000000, "PSU1GA(3/4)0HT", LP_OPTIONS}, + {0,} + /*add new product item here.*/ +}; + +struct nand_read_retry_param chip_table[] = { +#ifdef CONFIG_MTD_NAND_WMT + //Hynix + { + .magic = "readretry", + .nand_id = 0xADD794DA, + .nand_id_5th = 0x74C30000, + .eslc_reg_num = 5, + .eslc_offset = {0xa0, 0xa1, 0xb0, 0xb1, 0xc9}, + .eslc_set_value = {0x26, 0x26, 0x26, 0x26, 0x1}, + .retry_reg_num = 4, + .retry_offset = {0xa7, 0xad, 0xae, 0xaf}, + .retry_value = {0, 0x6,0xa, 0x6, 0x0, 0x3, 0x7, 0x8, 0, 0x6, 0xd, 0xf, 0x0, 0x9, 0x14, 0x17, 0x0, 0x0, 0x1a, 0x1e, 0x0, 0x0, 0x20, 0x25}, + .total_try_times = 6, + .cur_try_times = -1, + .set_parameter = hynix_set_parameter, + .get_parameter = hynix_get_parameter, + .get_otp_table = NULL, + .retry = 0 + }, + { + .magic = "readretry", + .nand_id = 0xADDE94DA, + .nand_id_5th = 0, + .eslc_reg_num = 4, + .eslc_offset = {0xb0, 0xb1, 0xa0, 0xa1}, + .eslc_set_value = {0xa, 0xa, 0xa, 0xa}, + .retry_reg_num = 8, + .retry_offset = {0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf}, + .otp_len = 2, + .otp_offset = {0xff, 0xcc}, + .otp_data = {0x40, 0x4d}, + .total_try_times = 7, + .cur_try_times = -1, + .set_parameter = hynix_set_parameter, + .get_parameter = hynix_get_parameter, + .get_otp_table = hynix_get_otp, + .retry = 0 + }, + { + .magic = "readretry", + .nand_id = 0xADDE94EB, + .nand_id_5th = 0x74440000, + .eslc_reg_num = 4, + .eslc_offset = {0xa0, 0xa1, 0xa7, 0xa8}, + .eslc_set_value = {0xa, 0xa, 0xa, 0xa}, + .retry_reg_num = 8, + .retry_offset = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7}, + .otp_len = 2, + .otp_offset = {0xae, 0xb0}, + .otp_data = {0x00, 0x4d}, + .total_try_times = 7, + .cur_try_times = -1, + .set_parameter = hynix_set_parameter, + .get_parameter = hynix_get_parameter, + .get_otp_table = hynix_get_otp, + .retry = 0 + }, + { + .magic = "readretry", + .nand_id = 0xADD79491, + .nand_id_5th = 0x0, + .eslc_reg_num = 4, + .eslc_offset = {0xa0, 0xa1, 0xa7, 0xa8}, + .eslc_set_value = {0xa, 0xa, 0xa, 0xa}, + .retry_reg_num = 8, + .retry_offset = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7}, + .otp_len = 2, + .otp_offset = {0xae, 0xb0}, + .otp_data = {0x00, 0x4d}, + .total_try_times = 7, + .cur_try_times = -1, + .set_parameter = hynix_set_parameter, + .get_parameter = hynix_get_parameter, + .get_otp_table = hynix_get_otp, + .retry = 0 + }, + //Toshiba + { + .magic = "readretry", + .nand_id = 0x98D58432, + .nand_id_5th = 0x72560000, + .retry_reg_num = 4, + .retry_offset = {4, 5, 6, 7}, + .retry_value = {0, 0, 0, 0, 4, 4, 4, 4, 0x7c, 0x7c, 0x7c, 0x7c, 0x78, 0x78, 0x78, 0x78, 0x74, 0x74, 0x74, 0x74, 0x8, 0x8, 0x8, 0x8}, + .total_try_times = 6, + .cur_try_times = 0, + .set_parameter = toshiba_set_parameter, + .get_parameter = toshiba_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0x98DE8493, + .nand_id_5th = 0x72570000, + .retry_reg_num = 4, + .retry_offset = {4, 5, 6, 7}, + .retry_value = {0, 0, 0, 0, 4, 4, 4, 4, 0x7c, 0x7c, 0x7c, 0x7c, 0x78, 0x78, 0x78, 0x78, 0x74, 0x74, 0x74, 0x74, 0x8, 0x8, 0x8, 0x8}, + .total_try_times = 6, + .cur_try_times = 0, + .set_parameter = toshiba_set_parameter, + .get_parameter = toshiba_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0x98DE8493, + .nand_id_5th = 0x72D70000, + .retry_reg_num = 4, + .retry_offset = {4, 5, 6, 7}, + .retry_value = {0, 0, 0, 0, 4, 4, 4, 4, 0x7c, 0x7c, 0x7c, 0x7c, 0x78, 0x78, 0x78, 0x78, 0x74, 0x74, 0x74, 0x74, 0x8, 0x8, 0x8, 0x8}, + .total_try_times = 6, + .cur_try_times = 0, + .set_parameter = toshiba_set_parameter, + .get_parameter = toshiba_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0x98DE9482, + .nand_id_5th = 0x72570000, + .retry_reg_num = 4, + .retry_offset = {4, 5, 6, 7}, + .retry_value = {0, 0, 0, 0, 4, 4, 4, 4, 0x7c, 0x7c, 0x7c, 0x7c, 0x78, 0x78, 0x78, 0x78, 0x74, 0x74, 0x74, 0x74, 0x8, 0x8, 0x8, 0x8}, + .total_try_times = 6, + .cur_try_times = 0, + .set_parameter = toshiba_set_parameter, + .get_parameter = toshiba_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0x98D79432, + .nand_id_5th = 0x76560000, + .retry_reg_num = 4, + .retry_offset = {4, 5, 6, 7}, + .retry_value = {0, 0, 0, 0, 4, 4, 4, 4, 0x7c, 0x7c, 0x7c, 0x7c, 0x78, 0x78, 0x78, 0x78, 0x74, 0x74, 0x74, 0x74, 0x8, 0x8, 0x8, 0x8}, + .total_try_times = 6, + .cur_try_times = 0, + .set_parameter = toshiba_set_parameter, + .get_parameter = toshiba_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0x98D78493, + .nand_id_5th = 0x72570000, + .retry_reg_num = 4, + .retry_offset = {4, 5, 6, 7}, + .retry_value = {0, 0, 0, 0, 4, 4, 4, 4, 0x7c, 0x7c, 0x7c, 0x7c, 0x78, 0x78, 0x78, 0x78, 0x74, 0x74, 0x74, 0x74, 0x8, 0x8, 0x8, 0x8}, + .total_try_times = 6, + .cur_try_times = 0, + .set_parameter = toshiba_set_parameter, + .get_parameter = toshiba_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0x98D78493, + .nand_id_5th = 0x72500000, + .retry_reg_num = 4, + .retry_offset = {4, 5, 6, 7}, + .retry_value = {0, 0, 0, 0, 4, 4, 4, 4, 0x7c, 0x7c, 0x7c, 0x7c, 0x78, 0x78, 0x78, 0x78, 0x74, 0x74, 0x74, 0x74, 0x8, 0x8, 0x8, 0x8}, + .total_try_times = 6, + .cur_try_times = 0, + .set_parameter = toshiba_set_parameter, + .get_parameter = toshiba_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0x98DE9493, + .nand_id_5th = 0x76570000, + .retry_reg_num = 4, + .retry_offset = {4, 5, 6, 7}, + .retry_value = {0, 0, 0, 0, 4, 4, 4, 4, 0x7c, 0x7c, 0x7c, 0x7c, 0x78, 0x78, 0x78, 0x78, 0x74, 0x74, 0x74, 0x74, 0x8, 0x8, 0x8, 0x8}, + .total_try_times = 6, + .cur_try_times = 0, + .set_parameter = toshiba_set_parameter, + .get_parameter = toshiba_get_parameter, + .retry = 0, + }, + + //samsung + { + .magic = "readretry", + .nand_id = 0xECD7947E, + .nand_id_5th = 0x64440000, + .retry_reg_num = 4, + .retry_offset = {0xA7, 0xA4, 0xA5, 0xA6}, + .retry_def_value = {0, 0, 0, 0}, + .retry_value = {5, 0xA, 0, 0, 0x28, 0, 0xEC, 0xD8, 0xED, 0xF5, 0xED, 0xE6, 0xA, 0xF, 5, 0, + 0xF, 0xA, 0xFB, 0xEC, 0xE8, 0xEF, 0xE8, 0xDC, 0xF1, 0xFB, 0xFE, 0xF0, 0xA, 0x0, 0xFB, 0xEC, + 0xD0, 0xE2, 0xD0, 0xC2, 0x14, 0xF, 0xFB, 0xEC, 0xE8, 0xFB, 0xE8, 0xDC, 0x1E, 0x14, 0xFB, 0xEC, + 0xFB, 0xFF, 0xFB, 0xF8, 0x7, 0xC, 0x2, 0}, + .total_try_times = 14, + .cur_try_times = 0, + .set_parameter = samsung_set_parameter, + .get_parameter = samsung_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0xECDED57E, + .nand_id_5th = 0x68440000, + .retry_reg_num = 4, + .retry_offset = {0xA7, 0xA4, 0xA5, 0xA6}, + .retry_def_value = {0, 0, 0, 0}, + .retry_value = {5, 0xA, 0, 0, 0x28, 0, 0xEC, 0xD8, 0xED, 0xF5, 0xED, 0xE6, 0xA, 0xF, 5, 0, + 0xF, 0xA, 0xFB, 0xEC, 0xE8, 0xEF, 0xE8, 0xDC, 0xF1, 0xFB, 0xFE, 0xF0, 0xA, 0x0, 0xFB, 0xEC, + 0xD0, 0xE2, 0xD0, 0xC2, 0x14, 0xF, 0xFB, 0xEC, 0xE8, 0xFB, 0xE8, 0xDC, 0x1E, 0x14, 0xFB, 0xEC, + 0xFB, 0xFF, 0xFB, 0xF8, 0x7, 0xC, 0x2, 0}, + .total_try_times = 14, + .cur_try_times = 0, + .set_parameter = samsung_set_parameter, + .get_parameter = samsung_get_parameter, + .retry = 0, + }, + //Sandisk + { + .magic = "readretry", + .nand_id = 0x45DE9493, + .nand_id_5th = 0x76570000, + .retry_reg_num = 3, + .retry_offset = {4, 5, 7}, + .retry_def_value = {0, 0, 0, 0xFF, 0xFF}, + .retry_value = {0xF0, 0, 0xF0, 0xE0, 0, 0xE0, 0xD0, 0, 0xD0, 0x10, 0, 0x10, 0x20, 0, 0x20, 0x30, 0, 0x30, + 0xC0, 0, 0xD0, 0x00, 0, 0x10, 0x00, 0, 0x20, 0x10, 0, 0x20, 0xB0, 0, 0xD0, 0xA0, 0, 0xD0, + 0x90, 0, 0xD0, 0xB0, 0, 0xC0, 0xA0, 0, 0xC0, 0x90, 0, 0xC0,//lower page retry parameter + 0x00, 0xF0, 0, 0x0F, 0xE0, 0, 0x0F, 0xD0, 0, 0x0E, 0xE0, 0, 0x0E, 0xD0, 0, 0x0D, 0xF0, 0, + 0x0D, 0xE0, 0, 0x0D, 0xD0, 0, 0x01, 0x10, 0, 0x02, 0x20, 0, 0x02, 0x10, 0, 0x03, 0x20, 0, + 0x0F, 0x00, 0, 0x0E, 0xF0, 0, 0x0D, 0xC0, 0, 0x0F, 0xF0, 0, 0x01, 0x00, 0, 0x02, 0x00, 0, + 0x0D, 0xB0, 0, 0x0C, 0xA0, 0},//upper page retry parameter + .otp_len = 9, + .otp_offset = {0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC}, + .otp_data = {0, 0, 0, 0, 0, 0, 0, 0, 0}, + .total_try_times = 0x1410,//bit15~8 for upper page, bit7~0 for lower page + .cur_try_times = -1, + .set_parameter = sandisk_set_parameter, + .get_parameter = sandisk_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0x45D78493, + .nand_id_5th = 0x72570000, + .retry_reg_num = 3, + .retry_offset = {4, 5, 7}, + .retry_def_value = {0, 0, 0, 0xFF, 0xFF}, + .retry_value = {0xF0, 0, 0xF0, 0xE0, 0, 0xE0, 0xD0, 0, 0xD0, 0x10, 0, 0x10, 0x20, 0, 0x20, 0x30, 0, 0x30, + 0xC0, 0, 0xD0, 0x00, 0, 0x10, 0x00, 0, 0x20, 0x10, 0, 0x20, 0xB0, 0, 0xD0, 0xA0, 0, 0xD0, + 0x90, 0, 0xD0, 0xB0, 0, 0xC0, 0xA0, 0, 0xC0, 0x90, 0, 0xC0,//lower page retry parameter + 0x00, 0xF0, 0, 0x0F, 0xE0, 0, 0x0F, 0xD0, 0, 0x0E, 0xE0, 0, 0x0E, 0xD0, 0, 0x0D, 0xF0, 0, + 0x0D, 0xE0, 0, 0x0D, 0xD0, 0, 0x01, 0x10, 0, 0x02, 0x20, 0, 0x02, 0x10, 0, 0x03, 0x20, 0, + 0x0F, 0x00, 0, 0x0E, 0xF0, 0, 0x0D, 0xC0, 0, 0x0F, 0xF0, 0, 0x01, 0x00, 0, 0x02, 0x00, 0, + 0x0D, 0xB0, 0, 0x0C, 0xA0, 0},//upper page retry parameter + .otp_len = 9, + .otp_offset = {0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC}, + .otp_data = {0, 0, 0, 0, 0, 0, 0, 0, 0}, + .total_try_times = 0x1410,//bit15~8 for upper page, bit7~0 for lower page + .cur_try_times = -1, + .set_parameter = sandisk_set_parameter, + .get_parameter = sandisk_get_parameter, + .retry = 0, + }, + + //Micron + { + .magic = "readretry", + .nand_id = 0x2C64444B, + .nand_id_5th = 0xA9000000, + .retry_reg_num = 1, + .retry_offset = {0x89}, + .retry_def_value = {0}, + .retry_value = {1, 2, 3, 4, 5, 6, 7}, + .total_try_times = 7, + .cur_try_times = 0, + .set_parameter = micron_set_parameter, + .get_parameter = micron_get_parameter, + .retry = 0, + }, + { + .magic = "readretry", + .nand_id = 0x2C44444B, + .nand_id_5th = 0xA9000000, + .retry_reg_num = 1, + .retry_offset = {0x89}, + .retry_def_value = {0}, + .retry_value = {1, 2, 3, 4, 5, 6, 7}, + .total_try_times = 7, + .cur_try_times = 0, + .set_parameter = micron_set_parameter, + .get_parameter = micron_get_parameter, + .retry = 0, + }, +#endif + { + .nand_id = 0, + .nand_id_5th = 0, + } +}; + + + /* * Manufacturer ID list */ @@ -176,13 +543,18 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix"}, {NAND_MFR_MICRON, "Micron"}, + {NAND_MFR_SANDISK, "Sandisk"}, {NAND_MFR_AMD, "AMD"}, + {NAND_MFR_INTEL, "Intel"}, {NAND_MFR_MACRONIX, "Macronix"}, + {NAND_MFR_MXIC, "Mxic"}, + {NAND_MFR_MIRA, "Mira"}, {0x0, "Unknown"} }; EXPORT_SYMBOL(nand_manuf_ids); EXPORT_SYMBOL(nand_flash_ids); +EXPORT_SYMBOL(WMT_nand_flash_ids); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); diff --git a/ANDROID_3.4.5/drivers/mtd/nand/wmt_nand.c b/ANDROID_3.4.5/drivers/mtd/nand/wmt_nand.c new file mode 100755 index 00000000..0fa2bde0 --- /dev/null +++ b/ANDROID_3.4.5/drivers/mtd/nand/wmt_nand.c @@ -0,0 +1,8285 @@ +/*++ +linux/drivers/mtd/nand/wmt_nand.c + +Copyright (c) 2008 WonderMedia Technologies, Inc. + +This program is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software Foundation, +either version 2 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. + +WonderMedia Technologies, Inc. +10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C. +--*/ + +//#include <linux/config.h> +#include <linux/module.h> +/*#include <linux/types.h>*/ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <linux/ioport.h> +/*#include <linux/platform_device.h>*/ +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/dma-mapping.h> +/*#include <linux/clk.h>*/ + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +/*#include <linux/mtd/partitions.h>*/ +#include <linux/interrupt.h> +#include <linux/completion.h> +#include <linux/reboot.h> //Lch +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/sizes.h> +#include <mach/irqs.h> +#include <mach/hardware.h> +#include <linux/vmalloc.h> +#include <linux/proc_fs.h> +#include "wmt_nand.h" + + +#ifndef memzero +#define memzero(s, n) memset ((s), 0, (n)) +#endif +//#define RETRY_DEBUG +#define WMT_HW_RDMZ +//#ifdef WMT_SW_RDMZ +unsigned int rdmz[BYTE_SEED]= { + 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, +}; +//#endif + +#define WR_BUF_CNT 16 +#define NANDINFO "nandinfo" +static struct proc_dir_entry *nandinfo_proc = NULL; +static struct mtd_info *mtd_nandinfo = NULL; +uint8_t *buf_rdmz, *wr_cache; +/*#define NAND_DEBUG*/ +unsigned int wmt_version; +uint32_t par1_ofs, par2_ofs, par3_ofs, par4_ofs, eslc_write, prob_end; +#include <linux/mtd/partitions.h> +#define NUM_NAND_PARTITIONS ARRAY_SIZE(nand_partitions) + +#ifndef CONFIG_MTD_NAND_WMT_UBUNTU + +struct mtd_partition nand_partitions[] = { + { + .name = "logo", + .offset = MTDPART_OFS_APPEND, + .size = 0x1000000, + }, + { + .name = "boot", + .offset = MTDPART_OFS_APPEND, + .size = 0x1000000, + }, + { + .name = "recovery", + .offset = MTDPART_OFS_APPEND, + .size = 0x1000000, + }, + { + .name = "misc", + .offset = MTDPART_OFS_APPEND, + .size = 0x1000000, + }, + { + .name = "keydata", + .offset = MTDPART_OFS_APPEND, + .size = 0x4000000, + }, + { + .name = "system", + .offset = MTDPART_OFS_APPEND, + .size = 0x40000000, + }, + { + .name = "cache", + .offset = MTDPART_OFS_APPEND, + .size = 0x20000000, + }, + { + .name = "swap", + .offset = MTDPART_OFS_APPEND, + .size = 0x10000000, + }, +#ifndef CONFIG_MTD_NAND_WMT_ANDROID_UBUNTU_DUALOS + { + .name = "data", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + } +#else // #ifdef CONFIG_MTD_NAND_WMT_ANDROID_UBUNTU_DUALOS + { + .name = "data", + .offset = MTDPART_OFS_APPEND, + .size = 0x88000000, + }, + { .name = "ubuntu-boot", + .offset = MTDPART_OFS_APPEND, + .size = 0x1000000, + }, + { + .name = "ubuntu-rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + } +#endif +}; + +#else // #ifdef CONFIG_MTD_NAND_WMT_UBUNTU + +struct mtd_partition nand_partitions[] = { + { + .name = "ubuntu-logo", + .offset = MTDPART_OFS_APPEND, + .size = 0x1000000, + }, + { + .name = "ubuntu-boot", + .offset = MTDPART_OFS_APPEND, + .size = 0x1000000, + }, + { + .name = "ubuntu-rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + } +}; + +#endif + +EXPORT_SYMBOL(nand_partitions); + +int second_chip = 0; +EXPORT_SYMBOL(second_chip); + +#ifdef CONFIG_MTD_NAND_WMT_HWECC + static int MAX_CHIP = CONFIG_MTD_NAND_CHIP_NUM; + static int hardware_ecc = 1; +#else + #define MAX_CHIP 1 + static int hardware_ecc = 0; +#endif + +#define HW_ENCODE_OOB +//#define SW_ENCODE_OOB + +#ifdef SW_ENCODE_OOB +static unsigned char parity[MAX_PARITY_SIZE]; +#endif +static unsigned int bch_err_pos[MAX_ECC_BIT_ERROR]; +static unsigned int bch_err_pos[MAX_ECC_BIT_ERROR]; + +/* used for software de-randomizer of read id and read status command */ +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 +}; + +/* + * check the page is erased or not + * each row is oob byte 16~23 of randomizer seed(page) 0 ~ 15 + * +*/ +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} +}; + +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 +}; + +/* + * hardware specific Out Of Band information +*/ + +/* +* new oob placement block for use with hardware ecc generation +*/ +/* +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_12bit_oobinfo_4096 = { + .eccbytes = 20, + .eccpos = { 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43}, + .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} } +}; + + +/* Ick. The BBT code really ought to be able to work this bit out + for itself from the above, at least for the 2KiB case +*/ +static uint8_t wmt_bbt_pattern_2048[] = { 'B', 'b', 't', '0' }; +static uint8_t wmt_mirror_pattern_2048[] = { '1', 't', 'b', 'B' }; + +static uint8_t wmt_rdmz[] = { 'z', 'm', 'd', 'r' }; +static uint8_t retry_table[] = {'r','e','t','r','y','t','a','b','l','e'}; + +static struct nand_bbt_descr wmt_rdtry_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 10, + .veroffs = 0, + .maxblocks = 4, + .pattern = retry_table, + .reserved_block_code = 1 +}; + +static struct nand_bbt_descr wmt_bbt_main_descr_2048 = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 0, + .maxblocks = 4, + .pattern = wmt_bbt_pattern_2048, + .reserved_block_code = 1 +}; + +static struct nand_bbt_descr wmt_bbt_mirror_descr_2048 = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 0, + .maxblocks = 4, + .pattern = wmt_mirror_pattern_2048, +}; + + +/* controller and mtd information */ +extern unsigned int wmt_read_oscr(void); +/*static*/ void print_nand_register(struct mtd_info *mtd); +void print_nand_buffer(char *value, unsigned int length); +#ifdef NAND_DEBUG +static void print_nand_buffer_int(unsigned int *value, unsigned int length); +#endif + +struct wmt_nand_set { + int nr_chips; + int nr_partitions; + char *name; + int *nr_map; + struct mtd_partition *partitions; +}; + +struct wmt_nand_platform_data { + const char * name; + int id; + struct device dev; + u32 num_resources; + struct resource * resource; + + const struct platform_device_id *id_entry; + + /* MFD cell pointer */ + struct mfd_cell *mfd_cell; + + /* arch specific additions */ + struct pdev_archdata archdata; + struct mtd_partition *partitions; +}; + +#if 0 + struct wmt_platform_nand { + /* timing information for controller, all times in nanoseconds */ + + int tacls; /* time for active CLE/ALE to nWE/nOE */ + int twrph0; /* active time for nWE/nOE */ + int twrph1; /* time for release CLE/ALE from nWE/nOE inactive */ + + int nr_sets; + struct wmt_nand_set *sets; + void (*select_chip)(struct s3c2410_nand_set *, int chip); + } +#endif + +struct wmt_nand_info; + +struct wmt_nand_mtd { + struct mtd_info mtd; + struct nand_chip chip; + /*struct wmt_nand_set* set;*/ + struct wmt_nand_info *info; + int scan_res; +}; + +/* overview of the wmt nand state */ + +struct wmt_nand_info { + /* mtd info */ + struct nand_hw_control controller; + struct wmt_nand_mtd *mtds; + struct wmt_platform_nand *platform; + int oper_step; + /* device info */ + struct device *device; + struct resource *area; + void __iomem *reg; + int cpu_type; + int datalen; + int nr_data; + int data_pos; + int page_addr; + dma_addr_t dmaaddr; + dma_addr_t last_bank_dmaaddr; + int dma_finish; + int phase; + void *done_data; /* completion data */ + unsigned int isr_state; + unsigned int isr_cmd; + unsigned int cur_lpage; + unsigned int cur_page; + unsigned int last_bank_col; + unsigned int oob_col; + //void (*done)(void *data);/* completion function */ + unsigned char *dmabuf; + +#ifdef CONFIG_MTD_NAND_DIRECT_WRITE + + int vmalloc_flag; + int sglen; + struct scatterlist *sglist; + dma_addr_t data_address0; + dma_addr_t data_address1; + dma_addr_t tempaddr; + unsigned char *tempbuf; + +#endif + + int ECC_bytes; + int oob_ECC_bytes; + int oob_ecc_error; + int data_ecc_uncor_err; /* use read retry for data area has uncorrectable error*/ + int unc_bank; + int unc_allFF; + int bank_size; + int ECC_mode; + int oob_ECC_mode; + unsigned int lst_wpage; + int wr_page[WR_BUF_CNT]; + char banks; + char oob_max_bit_error; +}; + +/* conversion functions */ + +static struct wmt_nand_mtd *wmt_nand_mtd_toours(struct mtd_info *mtd) +{ + return container_of(mtd, struct wmt_nand_mtd, mtd); +} + +static struct wmt_nand_info *wmt_nand_mtd_toinfo(struct mtd_info *mtd) +{ + return wmt_nand_mtd_toours(mtd)->info; +} + +/* +static struct wmt_nand_info *to_nand_info(struct platform_device *dev) +{ + return platform_get_drvdata(dev); +} +*/ +/* +static struct platform_device *to_platform(struct device *dev) +{ + return container_of(dev, struct platform_device, dev); +} +*/ +#if 0 +static struct wmt_platform_nand *to_nand_plat(struct platform_device *dev) +{ + return dev->dev.platform_data; +} +#endif + +void copy_filename (char *dst, char *src, int size) +{ + if (*src && (*src == '"')) { + ++src; + --size; + } + + while ((--size > 0) && *src && (*src != '"')) { + *dst++ = *src++; + } + *dst = '\0'; +} + +int set_ECC_mode(struct mtd_info *mtd) +{ + unsigned int ECCbit = mtd->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: + printk("ecc mode input not support ECCbit=%d\n", ECCbit); + return -1; + } + return ECC_mode; +} +void calculate_ECC_info(struct mtd_info *mtd, struct ECC_size_info *ECC_size) +{ + switch (ECC_size->ecc_engine) { + case ECC4bit: + 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 = mtd->realwritesize/512; + ECC_size->bank_size = 512; + ECC_size->bank_offset = mtd->realwritesize/ECC_size->banks + ECC4bit_byte_count; + ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC4bit_byte_count; + ECC_size->oob_ECC_mode = ECC4bit; + ECC_size->unprotect = mtd->realoobsize - ECC4bit_byte_count*(ECC_size->banks+1) - 24; + break; + case ECC8bit: + 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 = mtd->realwritesize/512; + ECC_size->bank_size = 512; + ECC_size->bank_offset = mtd->realwritesize/ECC_size->banks + ECC8bit_byte_count; + ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC8bit_byte_count; + ECC_size->oob_ECC_mode = ECC8bit; + ECC_size->unprotect = mtd->realoobsize - ECC8bit_byte_count*(ECC_size->banks+1) - 24; + break; + case ECC12bit: + 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 = mtd->realwritesize/512; + ECC_size->bank_size = 512; + ECC_size->bank_offset = mtd->realwritesize/ECC_size->banks + ECC12bit_byte_count; + ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC12bit_byte_count; + ECC_size->oob_ECC_mode = ECC12bit; + ECC_size->unprotect = mtd->realoobsize - ECC12bit_byte_count*(ECC_size->banks+1) - 24; + break; + case ECC16bit: + 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 = mtd->realwritesize/512; + ECC_size->bank_size = 512; + ECC_size->bank_offset = mtd->realwritesize/ECC_size->banks + ECC16bit_byte_count; + ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC16bit_byte_count; + ECC_size->oob_ECC_mode = ECC16bit; + ECC_size->unprotect = mtd->realoobsize - ECC16bit_byte_count*(ECC_size->banks+1) - 24; + break; + case ECC24bitPer1K: + 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 = mtd->realwritesize/1024; + ECC_size->bank_size = 1024; + ECC_size->bank_offset = mtd->realwritesize/ECC_size->banks + ECC24bitPer1K_byte_count; + ECC_size->oob_ECC_bytes = ECC_size->ECC_bytes = ECC24bitPer1K_byte_count; + ECC_size->oob_ECC_mode = ECC24bitPer1K; + ECC_size->unprotect = mtd->realoobsize - ECC24bitPer1K_byte_count*(ECC_size->banks+1) - 24; + break; + case ECC40bitPer1K: + 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 = mtd->realwritesize/1024; + ECC_size->bank_size = 1024; + ECC_size->bank_offset = mtd->realwritesize/ECC_size->banks + ECC40bitPer1K_byte_count; + ECC_size->ECC_bytes = ECC40bitPer1K_byte_count; + ECC_size->oob_ECC_bytes = ECC24bitPer1K_byte_count; + ECC_size->oob_ECC_mode = ECC24bitPer1K; + ECC_size->unprotect = mtd->realoobsize - ECC40bitPer1K_byte_count*ECC_size->banks - ECC24bitPer1K_byte_count - 24; + break; + case ECC60bitPer1K: + 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 = mtd->realwritesize/1024; + ECC_size->bank_size = 1024; + ECC_size->bank_offset = mtd->realwritesize/ECC_size->banks + ECC60bitPer1K_byte_count; + ECC_size->ECC_bytes = ECC60bitPer1K_byte_count; + ECC_size->oob_ECC_bytes = ECC24bitPer1K_byte_count; + ECC_size->oob_ECC_mode = ECC24bitPer1K; + ECC_size->unprotect = mtd->realoobsize - ECC60bitPer1K_byte_count*ECC_size->banks - ECC24bitPer1K_byte_count - 24; + break; + default: + printk("%d-bit ECC engine is not support:\r\n", ECC_size->ecc_engine); + break;; + } + return; +} + +int get_partition_name(const char *src, char** endpp, char* buffer) +{ + int i = 0; + if(NULL == src || NULL == buffer) + { + return -1; + } + + while(*src != ':') + { + *buffer++ = *src++; + i++; + } + *endpp = (char *)src; + buffer[i] = '\0'; + return i; +} + +int search_mtd_table(char *string, int *ret) +{ + int i, err = 0; + for (i = 0; i < NUM_NAND_PARTITIONS; i++) { + // printk(KERN_DEBUG "MTD dev%d size: %8.8llx \"%s\"\n", + //i, nand_partitions[i].size, nand_partitions[i].name); + if (strcmp(string, nand_partitions[i].name) == 0) { + *ret = i; + break; + } + } + return err; +} + +/* + * Get the flash and manufacturer id and lookup if the type is supported + */ +int get_flash_info_from_env(unsigned int id, unsigned int id2, struct WMT_nand_flash_dev *type) +{ + int ret, sf_boot_nand_en = 0x4000; + char varval[200], *s = NULL, *tmp, varname[] = "wmt.io.nand"; + unsigned int varlen = 200, value; + + value = STRAP_STATUS_VAL; + if ((value&0x4008) != sf_boot_nand_en) + return 1; + ret = wmt_getsyspara(varname, varval, &varlen); + if (!ret) { + s = varval; + value = simple_strtoul(s, &tmp, 16); type->dwFlashID = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwBlockCount = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwPageSize = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwSpareSize = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwBlockSize = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwAddressCycle = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwBI0Position = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwBI1Position = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwBIOffset = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwDataWidth = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwPageProgramLimit = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwSeqRowReadSupport = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwSeqPageProgram = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwNandType = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwECCBitNum = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwRWTimming = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwTadl = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwDDR = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwRetry = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwRdmz = value; s = tmp+1; + value = simple_strtoul(s, &tmp, 16); type->dwFlashID2 = value; s = tmp+1; + copy_filename(type->ProductName, s, MAX_PRODUCT_NAME_LENGTH); + + if (type->dwBlockCount < 1024 || type->dwBlockCount > 16384) { + printk(KERN_INFO "dwBlockCount = 0x%x is abnormal\n", type->dwBlockCount); + return 2; + } + if (type->dwPageSize < 512 || type->dwPageSize > 16384) { + printk(KERN_INFO "dwPageSize = 0x%x is abnormal\n", type->dwPageSize); + return 2; + } + if (type->dwPageSize > 512) + type->options = NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR; + if (type->dwBlockSize < (1024*64) || type->dwBlockSize > (16384*256)) { + printk(KERN_INFO "dwBlockSize = 0x%x is abnormal\n", type->dwBlockSize); + return 2; + } + if (type->dwAddressCycle < 3 || type->dwAddressCycle > 5) { + printk(KERN_INFO "dwAddressCycle = 0x%x is abnoraml\n", type->dwAddressCycle); + return 2; + } + if (type->dwBI0Position != 0 && + type->dwBI0Position > ((type->dwBlockSize/type->dwPageSize)-1)) { + printk(KERN_INFO "dwBI0Position = 0x%x is abnoraml\n", type->dwBI0Position); + return 2; + } + if (type->dwBI1Position != 0 && + type->dwBI1Position > ((type->dwBlockSize/type->dwPageSize)-1)) { + printk(KERN_INFO "dwBI1Position = 0x%x is abnoraml\n", type->dwBI1Position); + return 2; + } + if (type->dwBIOffset != 0 && type->dwBIOffset != 5) { + printk(KERN_INFO "dwBIOffset = 0x%x is abnoraml\n", type->dwBIOffset); + return 2; + } + if (type->dwDataWidth != 0/* && type->dwDataWidth != 1*/) { + printk(KERN_INFO "dwDataWidth = 0x%x is abnoraml\n", type->dwDataWidth); + return 2; + } + printk(KERN_DEBUG "dwFlashID = 0x%x\n", type->dwFlashID); + printk(KERN_DEBUG "dwBlockCount = 0x%x\n", type->dwBlockCount); + printk(KERN_DEBUG "dwPageSize = 0x%x\n", type->dwPageSize); + printk(KERN_DEBUG "dwSpareSize = 0x%x\n", type->dwSpareSize); + printk(KERN_DEBUG "dwBlockSize = 0x%x\n", type->dwBlockSize); + printk(KERN_DEBUG "dwAddressCycle = 0x%x\n", type->dwAddressCycle); + printk(KERN_DEBUG "dwBI0Position = 0x%x\n", type->dwBI0Position); + printk(KERN_DEBUG "dwBI1Position = 0x%x\n", type->dwBI1Position); + printk(KERN_DEBUG "dwBIOffset = 0x%x\n", type->dwBIOffset); + printk(KERN_DEBUG "dwDataWidth = 0x%x\n", type->dwDataWidth); + printk(KERN_DEBUG "dwPageProgramLimit = 0x%x\n", type->dwPageProgramLimit); + printk(KERN_DEBUG "dwSeqRowReadSupport = 0x%x\n", type->dwSeqRowReadSupport); + printk(KERN_DEBUG "dwSeqPageProgram = 0x%x\n", type->dwSeqPageProgram); + printk(KERN_DEBUG "dwNandType = 0x%x\n", type->dwNandType); + printk(KERN_DEBUG "dwECCBitNum = 0x%x\n", type->dwECCBitNum); + printk(KERN_DEBUG "dwRWTimming = 0x%x\n", type->dwRWTimming); + printk(KERN_DEBUG "dwTadl = 0x%x\n", type->dwTadl); + printk(KERN_DEBUG "dwDDR = 0x%x\n", type->dwDDR); + printk(KERN_DEBUG "dwRetry = 0x%x\n", type->dwRetry); + printk(KERN_DEBUG "dwRdmz = 0x%x\n", type->dwRdmz); + printk(KERN_DEBUG "dwFlashID2 = 0x%x\n", type->dwFlashID2); + printk(KERN_DEBUG "cProductName = %s\n", type->ProductName); + if (id != type->dwFlashID || id2 != type->dwFlashID2) { + printk(KERN_ERR "env flash id is different from real id = 0x%x 0x%x\n", + type->dwFlashID, type->dwFlashID2); + return 3; + } + } + return ret; +} + +static int wmt_calc_clock(struct mtd_info *mtd, 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, margin; + + /*print_nand_register(mtd);*/ + PLLB = *(volatile unsigned int *)PMPMB_ADDR; + PLLB = (2*(((PLLB>>16)&0x7F)+1))/((((PLLB>>8)&0x1F)+1)*(1<<(PLLB&3))); + printk(KERN_DEBUG "PLLB=0x%x, spec_clk=0x%x\n", PLLB, spec_clk); + 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; + } + } + + margin = (tREA+10)*10+15; + if (mtd->id == 0x98D78493 && mtd->id2 == 0x72570000) + margin = (tREA+6)*10; + else if (mtd->id == 0x45D78493 && mtd->id2 == 0x72570000) + margin = (tREA+6)*10; + + for (i = div1; i < 32; i++) { + clk1 = (10000 * i)/(PLLB*SOURCE_CLOCK); + if ((2*clk1) >= margin) { + 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; + + return 0; +} +#if 0 +static int old_wmt_calc_clock(struct mtd_info *mtd, unsigned int spec_clk, unsigned int spec_tadl, 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, divisor, 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))); + printk(KERN_DEBUG "PLLB=0x%x, spec_clk=0x%x\n", PLLB, spec_clk); + 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; + } + } + + clk1 = (1000 * div1)/(PLLB*SOURCE_CLOCK); + //printk("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; + printk(KERN_DEBUG "T1=%d, clk1=%d, div1=%d, Thold=%d, tREA=%d+delay(%d)\n", T1, clk1, div1, Thold, tREA, MAX_READ_DELAY); + 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; + printk(KERN_DEBUG "T2=%d, clk2=%d, div2=%d, Thold2=%d, comp=1\n", T2, clk2, div2, Thold2); + break; + } + } + if (comp == 1) { + clk1 = clk * (T_setup+Thold) * mtd->realwritesize; + div1 = clk2 * (T2+Thold2) * mtd->realwritesize; + printk(KERN_DEBUG "Tim1=%d , Tim2=%d\n", clk1, div1); + if ((clk * (T_setup+Thold) * mtd->realwritesize) > (clk2 * (T2+Thold2) * mtd->realwritesize)) { + T_setup = T2; + clk = clk2; + divisor = div2; + Thold = Thold2; + } else { + printk(KERN_DEBUG "T2 is greater and not use\n"); + } + } + } /* 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/hold time */ + while ((i*clk) <= (tWP+MAX_WRITE_DELAY)) { + nfc_rw->T_W_setup += 1; + i++; + } + nfc_rw->T_W_hold = 1; + + if ((nfc_rw->T_W_hold * 2) == 2) + Thold = 4; + else if ((nfc_rw->T_W_hold * 2) == 4) + Thold = 6; + i = 0; + while (((i/*+Thold*/)*clk) < tADL && i < 50) + i++; + nfc_rw->T_TADL = i; + //printk("Tad i=%d\n", 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_hold&0xF) << 4) + + ((nfc_rw->T_W_setup + nfc_rw->T_W_hold)&0xF); + + if ((MAX_SPEED_MHZ < (PLLB*SOURCE_CLOCK)/(divisor)) || clk == 0 || T_setup == 0 || clk > 45) + return 1; + + return 0; +} +#endif + +static void wmt_nfc_init(struct wmt_nand_info *info, struct mtd_info *mtd) +{ + writeb((PAGE_2K|WP_DISABLE|DIRECT_MAP), info->reg + NFCR12_NAND_TYPE_SEL); + + writel(0x2424, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + writeb(B2R, info->reg + NFCRb_NFC_INT_STAT); + writeb(0x0, info->reg + NFCRd_OOB_CTRL); + +} + +void wmt_init_nfc(struct mtd_info *mtd, unsigned int spec_clk, unsigned int spec_tadl, int busw) +{ + unsigned int status = 0, page_size, divisor, NFC_RWTimming; + struct nand_chip *chip = mtd->priv; + struct NFC_RW_T nfc_rw; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned short cfg = 0; + + writeb(B2R, info->reg + NFCRb_NFC_INT_STAT); + writel(0x0, info->reg + NFCRd_OOB_CTRL); + + if (mtd->realwritesize == 2048) { + page_size = PAGE_2K; + } else if (mtd->realwritesize == 4096) { + page_size = PAGE_4K; + } else if (mtd->realwritesize == 6144) { + page_size = PAGE_8K; + } else if (mtd->realwritesize == 8192) { + page_size = PAGE_8K; + } else if (mtd->realwritesize == 16384 || mtd->realwritesize == 15360) { + page_size = PAGE_16K; + } else + page_size = PAGE_32K; + + cfg = WP_DISABLE|DIRECT_MAP|page_size; + if (prob_end == 1 && !mtd->dwDDR) + cfg |= RD_DLY; + + if (busw) { + cfg |= WIDTH_16; + printk(KERN_WARNING "nand flash use 16-bit witdth mode\n"); + } + writeb(cfg, info->reg + NFCR12_NAND_TYPE_SEL); + + status = wmt_calc_clock(mtd, spec_clk, spec_tadl, &nfc_rw); + if (status) { + printk(KERN_ERR "timming calculate fail\n"); + nfc_rw.T_RHC_THC = 0x2424; + nfc_rw.T_TADL = 0x3c; + nfc_rw.T_TWHR = 0x12; + nfc_rw.T_TWB = 0xa; + nfc_rw.divisor = 10; + } + NFC_RWTimming = nfc_rw.T_RHC_THC; + divisor = nfc_rw.divisor; + if (prob_end == 0 && mtd->dwDDR) + divisor = divisor + 5; + + switch(mtd->id) + { + case 0x2C88044B: + case 0x2C68044A: + case 0x2C64444B: + case 0x2C44444B: + case 0x2C48044A: + case 0x8968044A: + //NFC_RWTimming = 0x2424; + //divisor = 9; + //nand_get_feature(mtd, 1); + nand_set_feature(mtd, NAND_SET_FEATURE, 01, 05); + nand_get_feature(mtd, 1); + break; + } + //chip->select_chip(mtd, -1); + if (!status) { + while ((*(volatile unsigned long *)(PMCS_ADDR+0x18))&0x7F0038) + ; + *(volatile unsigned long *)PMNAND_ADDR = divisor; + while ((*(volatile unsigned long *)(PMCS_ADDR+0x18))&0x7F0038) + ; + } + divisor = *(volatile unsigned long *)PMNAND_ADDR; + if (((mtd->id>>24)&0xFF) == NAND_MFR_HYNIX) { + if (prob_end == 1) + NFC_RWTimming = 0x1312;//0x2424; + else + NFC_RWTimming = 0x2424; + } + + if (prob_end == 1) + NFC_RWTimming = 0x1212; + else + NFC_RWTimming = 0x2424; + + printk(KERN_NOTICE "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_RWTimming); + writel((nfc_rw.T_TWB<<16) + (nfc_rw.T_TWHR<<8) + nfc_rw.T_TADL, info->reg + NFCRe_CALC_TADL); + writel(NFC_RWTimming, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + + if (mtd->dwDDR) { + if (mtd->dwDDR == 1) { + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + nand_get_feature(mtd, 0x80); + nand_set_feature(mtd, NAND_SET_FEATURE, 0x80, 0); + nand_get_feature(mtd, 0x80); + } + writel(0x0101, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + writeb(0x7F, info->reg + NFCR7_DLYCOMP); + writeb(readb(info->reg + NFCR12_NAND_TYPE_SEL)|0x80, info->reg + NFCR12_NAND_TYPE_SEL); + } + printk("DDR=%d\n", mtd->dwDDR); + /*print_nand_register(mtd);*/ + chip->select_chip(mtd, -1); +} + +#if 0 +static void disable_redunt_out_bch_ctrl(struct wmt_nand_info *info, int flag) +{ + if (flag == 1) + writeb(readb(info->reg + NFCRd_OOB_CTRL)|RED_DIS, info->reg + NFCRd_OOB_CTRL); + else + writeb(readb(info->reg + NFCRd_OOB_CTRL)&(~RED_DIS), info->reg + NFCRd_OOB_CTRL); +} +static void redunt_read_hm_ecc_ctrl(struct wmt_nand_info *info, int flag) +{ + if (flag == 1) + writeb(readb(info->reg + NFCRd_OOB_CTRL) | OOB_READ, info->reg + NFCRd_OOB_CTRL); + else + writeb(readb(info->reg + NFCRd_OOB_CTRL) & (~OOB_READ), info->reg + NFCRd_OOB_CTRL); +} +#endif + +static void set_ecc_engine(struct wmt_nand_info *info, int type) +{ + /*struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd);*/ + writel((readl(info->reg + NFCR9_ECC_BCH_CTRL) & (~ECC_MODE)) | type, + info->reg + NFCR9_ECC_BCH_CTRL); + + if (type > ECC1bit) { /* enable BCH ecc interrupt */ + writel(readl(info->reg + NFCR9_ECC_BCH_CTRL) | BCH_INT_EN, info->reg + NFCR9_ECC_BCH_CTRL); + } else + writel(readl(info->reg + NFCR9_ECC_BCH_CTRL) & (~BCH_INT_EN), info->reg + NFCR9_ECC_BCH_CTRL); + + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); +} + + +static int wmt_nand_ready(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + //unsigned int b2r_stat; + int i = 0; + + while (1) { + if (readb(info->reg + NFCRb_NFC_INT_STAT) & B2R) + break; + if ((++i>>20)) { + printk(KERN_ERR "nand flash is not ready\n"); + /*print_nand_register(mtd);*/ + /* while (1);*/ + return -1; + } + } + //b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R, info->reg + NFCRb_NFC_INT_STAT); + wmb(); + if (readb(info->reg + NFCRb_NFC_INT_STAT) & B2R) { + printk(KERN_ERR "NFC err : B2R status not clean\n"); + return -2; + } + return 0; +} + + +static int wmt_nfc_transfer_ready(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i = 0; + + while (1) { + if (!(readb(info->reg + NFCRa_NFC_STAT) & NFC_BUSY)) + break; + + if (++i>>20) + return -3; + } + return 0; +} +/* Vincent 2008.11.3*/ +static int wmt_wait_chip_ready(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i = 0; + + while (1) { + if ((readb(info->reg + NFCRa_NFC_STAT) & FLASH_RDY)) + break; + if (++i>>20) + return -3; + } + return 0; +} +static int wmt_wait_cmd_ready(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i = 0; + + while (1) { + if (!(readb(info->reg + NFCRa_NFC_STAT) & NFC_CMD_RDY)) + break; + if (++i>>20) + return -3; + } + return 0; +} + +/* #if (NAND_PAGE_SIZE == 512) Vincent 2008.11.4 +static int wmt_wait_dma_ready(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i = 0; + + while (1) { + if (!(readb(info->reg + NFC_IDLE) & 0x02)) + break; + if (++i>>20) { + printk(KERN_ERR"\r DMA NOT Ready!\n"); + print_nand_register(mtd); + return -3; + } + } + return 0; +} +#endif Vincent 2008.11.4*/ + +static void wmt_wait_nfc_ready(struct wmt_nand_info *info) +{ + unsigned int bank_stat1, i = 0; + while (1) { + bank_stat1 = readw(info->reg + NFCRb_NFC_INT_STAT); + if (!(readb(info->reg + NFCRa_NFC_STAT) & NFC_BUSY)) + break; + else if ((bank_stat1 & (ERR_CORRECT | BCH_ERR)) == (ERR_CORRECT | BCH_ERR)) + break; + + if (i>>20) + return; + i++; + } +} + +static void bit_correct(uint8_t *c, uint8_t pos) +{ + c[0] = (((c[0] ^ (0x01<<pos)) & (0x01<<pos)) | (c[0] & (~(0x01<<pos)))); + #if 0 + temp = info->dmabuf[bch_err_idx[0] >> 3]; + temp >>= ((bch_err_idx[0] & 0x07) - 1); + #endif +} + +/* + * flag = 0, need check BCH ECC + * flag = 1, don't check ECC + * flag = 2, need check Harming ECC + * +*/ + +static int NFC_WAIT_IDLE(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i = 0; + + while (1) { + if (readb(info->reg + NFCR15_IDLE_STAT) & NFC_IDLE) + break; + if (i>>20) { + printk(KERN_NOTICE "nfc_wait_idle() time out\n"); + print_nand_register(mtd); + //while(i); + return -1; + } + i++; + } + return 0; + +} + +static int wmt_nfc_wait_idle(struct mtd_info *mtd, unsigned int flag, int command, +int column, unsigned int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i = 0; + + while (1) { + if (readb(info->reg + NFCR15_IDLE_STAT) & NFC_IDLE) + break; + if (i>>20) { + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + printk(KERN_NOTICE "nfc_wait_idle time out\n"); + print_nand_register(mtd); + //while(i); + return -1; + } + i++; + } + /* continue read next bank and calc BCH ECC */ + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + + return 0; +} + +int check_rdmz_mark(unsigned int *buf, int size, int oob, struct mtd_info *mtd) +{ + /*struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd);*/ + int i = 0, k = 0; + uint8_t *bm = (uint8_t *) &buf[1]; + for (i = 0; i < 4; i++) { + if (bm[i] == wmt_rdmz[i]) + k++; + } + if (k > 0 && k < 4) { + printk("buf=0x%x 0x%x mark=0x%x\n", buf[0], *(unsigned int *)(buf-1), *(unsigned int *)wmt_rdmz); + //printk("nfcrf=%x oob=%d page=0x%x\n", readl(info->reg + NFCRf_CALC_RDMZ), oob, info->cur_page); + } + if (k >= 2) + return 0; + else + return 1; +} +void set_FIFO_FF(unsigned int *buf, int size) +{ + int i; + for (i = 0; i < size; i++) + buf[i] = 0xFFFFFFFF; +} +int check_all_FF(unsigned int *buf, int size, struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i = 0, j = 0, k = 0; + unsigned int *bf = (unsigned int *)&rdmz_FF[info->cur_page%16][0]; + //unsigned int *bf = (unsigned int *)&info->dmabuf[24]; + unsigned int *bf1 = &rdmz_badblk[info->cur_page%2][0]; + + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) { + for (i = 0; i < size; i++) { + if (buf[i] != bf[i] && buf[i] != bf1[i]) { + k++; + /*if (info->cur_page < ((mtd->blkcnt - 4) * mtd->pagecnt)) + printk("need retry %d=[%x][%x] \n",i, buf[i],bf[i]);*/ + } else + j++; + } + if (j > (size/2)) + return 1; + } else { + if (info->ECC_mode <= 3) + size--; + for (i = 0; i < size; i++) { + if (buf[i] != 0xFFFFFFFF && buf[i] != 0) { + k++; + /*printk("unc %d=[%x]\n",i, buf[i]);*/ + } else + j++; + } + if (j > (size/2)) + return 1; + } + /*if (info->cur_lpage < ((mtd->blkcnt - 4) * mtd->pagecnt)) { + print_nand_register(mtd); + printk("cur page 0x%x\n",info->cur_page); + }*/ + return 0; +} + +#if 1 +int check_all_FF_sw(unsigned int *buf, int size, struct mtd_info *mtd) +{ + /*struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd);*/ + int i = 0, j = 0, k = 0; + for (i = 0; i < size; i++) { + if (buf[i] != 0xFFFFFFFF) { + k++;//return -i; + /*if (oob) + printk("%d=[%x] \n",i, buf[i]);*/ + } else + j++; + } + //if (k && oob) { + //printk("k=%d total%d, oob=%d\n", k, size, oob); + /*print_nand_register(mtd); + rdmzier_oob((uint8_t *)(info->reg+ECC_FIFO_0), (uint8_t *)(info->reg+ECC_FIFO_0), 6, info->cur_page, mtd->realwritesize/4); + print_nand_register(mtd); + rdmzier_oob((uint8_t *)(info->reg+ECC_FIFO_0), (uint8_t *)(info->reg+ECC_FIFO_0), 6, info->cur_page, mtd->realwritesize/4); + while(k);*/ + //} + /*if (k && !oob) + printk("k=%d j%d, total=%d\n", k, j, size);*/ + if (j > (size/2)) + return 1; + else + return 0; +} +#endif + +void clear_ecc_resume_dma(struct wmt_nand_info *info) +{ + writeb((ERR_CORRECT | BCH_ERR), info->reg + NFCRb_NFC_INT_STAT); + wmb(); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + wmb(); +} + + + +void bch_data_ecc_correct(struct mtd_info *mtd) +{ + int i, all_FF = 0; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *this = mtd->priv; + unsigned int bank_stat2, bch_ecc_idx, bank; + unsigned int bank_size; + + /* BCH ECC err process */ + bank_stat2 = readw(info->reg + NFCR17_ECC_BCH_ERR_STAT); + bch_ecc_idx = bank_stat2 & BCH_ERR_CNT; + bank = (bank_stat2 & BANK_NUM) >> 8; + /* for data area */ + /*if (bch_ecc_idx > 15) + printk(KERN_NOTICE "pg=0x%x bk%d=%d\n",info->cur_page, bank, bch_ecc_idx);*/ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "Read data \n"); + #endif + bank_size = info->bank_size; + /*if (this->cur_chip && (info->cur_page%4) == 0) + if ((info->cur_lpage < 0x7FB00) && this->cur_chip->cur_try_times < 5 && this->cur_chip != 0 && info->isr_cmd == 0x0) { + printk("----------------------------------set unc error by dannier info->cur_page0x%x\n", info->cur_page); + bch_ecc_idx = BCH_ERR_CNT; + }*/ + if (bch_ecc_idx >= BCH_ERR_CNT) { + //unsigned int oob_parity_size = readb(info->reg + NFCR10_OOB_ECC_SIZE+1); + if (bank == 0) + info->unc_bank = 1; + else + info->unc_bank |= (1<<bank); + /*if (oob_parity_size >= 40) + oob_parity_size = 40;*/ + + clear_ecc_resume_dma(info); + + if (bank >= (info->banks-1)) { + //all_FF = check_rdmz_mark((uint32_t *)(info->reg+ECC_FIFO_4), 1, 0, mtd); + all_FF = check_all_FF((uint32_t *)(info->reg+ECC_FIFO_6), 6, mtd); + + if (all_FF) { + info->data_ecc_uncor_err = 0; + info->unc_allFF = 1; + /*set_FIFO_FF((uint32_t *)(info->reg+ECC_FIFO_0), 5); + set_FIFO_FF((uint32_t *)info->dmabuf, mtd->realwritesize/4);*/ + return; + } /*else + printk("**********lost check all FF case *********af%x, bk%x\n", + info->unc_bank,((1<<info->banks)-1));*/ + } + + if (info->isr_cmd == 0x0 && mtd->dwRetry && this->cur_chip) { + info->data_ecc_uncor_err = 1; + if ((info->cur_lpage >= ((mtd->blkcnt-8)*mtd->pagecnt) && + info->cur_lpage < ((mtd->blkcnt-4)*mtd->pagecnt)) && + ((this->cur_chip->nand_id>>24)&0xFF) == NAND_MFR_HYNIX) { + /* read retry table not allowed to use read retry */ + info->data_ecc_uncor_err = 2; + if (bank >= (info->banks-1)) + printk(KERN_ERR "data area bank %d uncor err page=0x%x no retry\n", bank, info->cur_page); + } + #ifdef RETRY_DEBUG + else { + if (bank >= (info->banks-1)) + printk(KERN_ERR "data area bank %d uncor err page=0x%x use retry\n", bank, info->cur_page); + } + #endif + + return; + } else { + if (bank >= (info->banks-1)) { + printk("reda lpage=%x bbt_sw_rdmz=%d hold=%x blkcnt=%d\n", info->cur_lpage, mtd->bbt_sw_rdmz, ((mtd->blkcnt - 8)*mtd->pagecnt), mtd->blkcnt); + printk(KERN_ERR "data area uncor err page=0x%x,blk=%d no retry\n", info->cur_page, info->cur_page/mtd->pagecnt); + /*print_nand_buffer(info->dmabuf, 32);printk("isrcmd 0x=%x\n", info->isr_cmd); + print_nand_buffer((uint8_t *)(info->reg+ECC_FIFO_0), 48); + print_nand_register(mtd); + while(1);*/ + } else + return; + } + printk(KERN_ERR "data area unc++ page=0x%x no retry\n", info->cur_page); + mtd->ecc_stats.failed++; + return; /* uncorrected err */ + } + if (mtd->ecc_err_cnt < bch_ecc_idx) + mtd->ecc_err_cnt = bch_ecc_idx; + /* mtd->ecc_stats.corrected += (bank_stat2 & BCH_ERR_CNT);*/ + /* BCH ECC correct */ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "data area %d bit corrected err on bank %d \n", bch_ecc_idx, bank); + #endif + /*if (bank >= (info->banks-1)) { + print_nand_register(mtd); + }*/ + + for (i = 0; i < bch_ecc_idx; i++) + bch_err_pos[i] = (readw(info->reg + NFCR18_ECC_BCH_ERR_POS + 2*i) & BCH_ERRPOS0); + + /* continue read next bank and calc BCH ECC */ + clear_ecc_resume_dma(info); + + for (i = 0; i < bch_ecc_idx; i++) { + //bch_err_pos[i] = (readw(info->reg + NFCR18_ECC_BCH_ERR_POS + 2*i) & BCH_ERRPOS0); + //if (bank >= (info->banks-1)) + //printk(KERN_NOTICE "data area byte=%d corrected err on bank %d bs=%d, banks=%d\n", bch_err_pos[i]>>3, bank, bank_size,info->banks); + //printk(KERN_NOTICE "data page=0x%x byte=%d corrected err on bank %d bs=%d, banks=%d\n", + //info->cur_page, bch_err_pos[i]>>3, bank, bank_size,info->banks); + if((bch_err_pos[i] >> 3) < bank_size) { + //if (bank >= (info->banks-1)) + //printk(KERN_NOTICE "bank%d area value=%x ", bank, info->dmabuf[bank_size* bank + (bch_err_pos[i] >> 3)]); + bit_correct(&info->dmabuf[bank_size* bank + (bch_err_pos[i] >> 3)], bch_err_pos[i] & 0x07); + //if (bank >= (info->banks-1)) + //printk(KERN_NOTICE "bank%d area c-value=%x \n", bank, info->dmabuf[bank_size* bank + (bch_err_pos[i] >> 3)]); + } else if ((bch_err_pos[i] >> 3) < (bank_size + 24) && bank >= (info->banks-1)) {//oob area + //if (bank >= (info->banks-1)) + //printk(KERN_NOTICE "red area value=%x ", *((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size)); + bit_correct((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size, (bch_err_pos[i] & 0x07)); + //if (bank >= (info->banks-1)) + //printk(KERN_NOTICE "red area c-value=%x \n", *((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size)); + } + #ifdef NAND_DEBUG + printk(KERN_NOTICE "data area %xth ecc error position is byte%d bit%d\n", + i, bank_size * bank + (bch_err_pos[i] >> 3), (bch_err_pos[i] & 0x07)); + #endif + } +} + +void bch_redunt_ecc_correct(struct mtd_info *mtd) +{ + int i, all_FF = 1; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *this = mtd->priv; + unsigned int bank_stat2, bch_ecc_idx, bank; + unsigned int bank_size; + + /* BCH ECC err process */ + bank_stat2 = readw(info->reg + NFCR17_ECC_BCH_ERR_STAT); + bch_ecc_idx = bank_stat2 & BCH_ERR_CNT; + bank = (bank_stat2 & BANK_NUM) >> 8; + /* for data area */ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "Read oob \n"); + #endif + + if (info->isr_cmd != 0x50) { + printk("bch_redunt_ecc_correct cmd not read oob \n"); + print_nand_register(mtd); + while(1) + ; + } + /*oob_parity_size = readb(info->reg + NFCR10_OOB_ECC_SIZE+1); + if (oob_parity_size >= 40) + oob_parity_size = 40;*/ + if (bch_ecc_idx >= BCH_ERR_CNT) { + info->unc_bank = 1; + all_FF = check_all_FF((uint32_t *)(info->reg+ECC_FIFO_6), 6, mtd); + + clear_ecc_resume_dma(info); + + if (all_FF > 0) { + info->unc_allFF = 1; + return; + } + /*printk("red unc err\n"); + print_nand_register(mtd); + rdmzier_oob((uint8_t *)(info->reg+ECC_FIFO_0), (uint8_t *)(info->reg+ECC_FIFO_0), 6, info->cur_page, mtd->realwritesize/4); + print_nand_register(mtd); + rdmzier_oob((uint8_t *)(info->reg+ECC_FIFO_0), (uint8_t *)(info->reg+ECC_FIFO_0), 6, info->cur_page, mtd->realwritesize/4); + while(1);*/ + if (mtd->dwRetry && this->cur_chip) { + info->data_ecc_uncor_err = 1; + info->oob_ecc_error = 0x50; + if ((info->cur_lpage >= ((mtd->blkcnt-8)*mtd->pagecnt) && + info->cur_lpage < ((mtd->blkcnt-4)*mtd->pagecnt)) && + ((this->cur_chip->nand_id>>24)&0xFF) == NAND_MFR_HYNIX) { + /* read retry table not allowed to use read retry */ + info->data_ecc_uncor_err = 2; + printk(KERN_ERR "red area bank %d uncor err page=0x%x no retry\n", bank, info->cur_page); + } + #ifdef RETRY_DEBUG + else + printk(KERN_ERR "red area bank %d uncor err page=0x%x use retry\n", bank, info->cur_page); + #endif + + return; + } else { + printk(KERN_ERR "red area uncor err page=0x%x no retry\n", info->cur_page); + } + mtd->ecc_stats.failed++; + printk(KERN_ERR "red area unc++ page=0x%x no retry\n", info->cur_page); + return; /* uncorrected err */ + } + bank_size = info->bank_size; + /* mtd->ecc_stats.corrected += (bank_stat2 & BCH_ERR_CNT);*/ + /* BCH ECC correct */ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "redunt area %d bit corrected err on bank %d \n", bch_ecc_idx, bank); + #endif + for (i = 0; i < bch_ecc_idx; i++) { + bch_err_pos[i] = (readw(info->reg + NFCR18_ECC_BCH_ERR_POS + 2*i) & BCH_ERRPOS0); + //printk(KERN_NOTICE "data area byte=%d corrected err on bank %d bs=%d, banks=%d\n", bch_err_pos[i]>>3, bank, bank_size,info->banks); + if((bch_err_pos[i] >> 3) < 24) { + //printk(KERN_NOTICE "area value=%d ", *((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3))); + bit_correct((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3), (bch_err_pos[i] & 0x07)); + } + #ifdef NAND_DEBUG + printk(KERN_NOTICE "redunt area %xth ecc error position is byte%d bit%d\n", + i, bank_size * bank + (bch_err_pos[i] >> 3), (bch_err_pos[i] & 0x07)); + #endif + } + /* continue read next bank and calc BCH ECC */ + clear_ecc_resume_dma(info); +} + +void bch_data_last_bk_ecc_correct(struct mtd_info *mtd) +{ + int i, all_FF; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *this = mtd->priv; + unsigned int bank_stat2, bch_ecc_idx, bank, bank_size; + + /* BCH ECC err process */ + bank_stat2 = readw(info->reg + NFCR17_ECC_BCH_ERR_STAT); + bch_ecc_idx = bank_stat2 & BCH_ERR_CNT; + bank = (bank_stat2 & BANK_NUM) >> 8; + /* mtd->ecc_stats.corrected += (bank_stat2 & BCH_ERR_CNT);*/ + /* BCH ECC correct */ + bank_size = info->bank_size; + if (bch_ecc_idx >= BCH_ERR_CNT) { + info->unc_bank = 1; + //unsigned int oob_parity_size = readb(info->reg + NFCR10_OOB_ECC_SIZE+1); + all_FF = check_all_FF((uint32_t *)(info->reg+ECC_FIFO_6), 6/*oob_parity_size/4*/, mtd); + clear_ecc_resume_dma(info); + if (all_FF > 0) { + info->unc_allFF = 1; + return; + } + if (mtd->dwRetry && this->cur_chip) { + info->data_ecc_uncor_err = 1; + printk(KERN_ERR + "last bank data area uncorrected err cur_page=%d use retry\n",info->cur_page); + return; + } else + printk(KERN_ERR + "last bank data area uncorrected err cur_page=%d no retry\n",info->cur_page); + mtd->ecc_stats.failed++; + printk(KERN_ERR "lst area unc++ page=0x%x no retry\n", info->cur_page); + //while(bank_stat1); + return; + } + if (mtd->ecc_err_cnt < bch_ecc_idx) + mtd->ecc_err_cnt = bch_ecc_idx; + /* mtd->ecc_stats.corrected += (bank_stat2 & BCH_ERR_CNT);*/ + /* BCH ECC correct */ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "last bank %d bit corrected error\n", bch_ecc_idx); + #endif + for (i = 0; i < bch_ecc_idx; i++) { + bch_err_pos[i] = (readw(info->reg + NFCR18_ECC_BCH_ERR_POS + 2*i) & BCH_ERRPOS0); + //printk(KERN_NOTICE "data area byte=%d corrected err on bank %d bs=%d, banks=%d\n", bch_err_pos[i]>>3, bank, bank_size,info->banks); + if((bch_err_pos[i] >> 3) < bank_size) { + bit_correct(&info->dmabuf[bank_size * (info->banks-1) + (bch_err_pos[i] >> 3)], bch_err_pos[i] & 0x07); + } else if ((bch_err_pos[i] >> 3) < (bank_size + 24)) {//oob area of last bank + //printk(KERN_NOTICE "redundant area value=%d ", *((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size)); + bit_correct((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size, (bch_err_pos[i] & 0x07)); + //printk(KERN_NOTICE "redundant area value=%d \n", *((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size)); + } + + #ifdef NAND_DEBUG + printk(KERN_NOTICE "data area last bank %xth ecc error position is byte%d bit%d\n", + i, bank_size * bank + (bch_err_pos[i] >> 3), (bch_err_pos[i] & 0x07)); + #endif + } + /* continue read next bank and calc BCH ECC */ + clear_ecc_resume_dma(info); +} + +void bch_data_ecc_correct_noalign(struct mtd_info *mtd) +{ + int i, all_FF = 0; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *this = mtd->priv; + unsigned int bank_stat2, bch_ecc_idx, bank, dmabank = info->banks; + unsigned int bank_size; + + dmabank = info->banks + 1; + + /* BCH ECC err process */ + bank_stat2 = readw(info->reg + NFCR17_ECC_BCH_ERR_STAT); + bch_ecc_idx = bank_stat2 & BCH_ERR_CNT; + bank = (bank_stat2 & BANK_NUM) >> 8; + bank_size = info->bank_size; + /* for data area */ + /*if (bch_ecc_idx >= 50) + printk(KERN_NOTICE "pg=0x%x=blk%d bk%d=%d\n",info->cur_page, info->cur_page/mtd->pagecnt, bank, bch_ecc_idx);*/ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "Read data \n");//print_nand_register(mtd); + #endif + + if (bch_ecc_idx >= BCH_ERR_CNT) { + /*if (bank >= (dmabank-1)) + print_nand_buffer((uint8_t *)info->dmabuf+bank_size * (dmabank-1), 32);*/ + //unsigned int oob_parity_size = readb(info->reg + NFCR10_OOB_ECC_SIZE+1); + if (bank == 0) + info->unc_bank = 1; + else + info->unc_bank |= (1<<bank); + + clear_ecc_resume_dma(info); + + if (bank >= (dmabank-1)) { + if (dmabank == (info->banks + 1)) + all_FF = check_all_FF((uint32_t *)(info->dmabuf+mtd->realwritesize+24), 6, mtd); + else + all_FF = check_all_FF((uint32_t *)(info->reg+ECC_FIFO_6), 6, mtd); + if (all_FF) { + info->data_ecc_uncor_err = 0; + info->unc_allFF = 1; + return; + } /*else + printk("**********lost check all FF case *********af%x, bk%x\n", + info->unc_bank,((1<<dmabank)-1));*/ + } + + if (info->isr_cmd == 0x0 && mtd->dwRetry && this->cur_chip) { + info->data_ecc_uncor_err = 1; + if ((info->cur_lpage >= ((mtd->blkcnt-8)*mtd->pagecnt) && + info->cur_lpage < ((mtd->blkcnt-4)*mtd->pagecnt)) && + ((this->cur_chip->nand_id>>24)&0xFF) == NAND_MFR_HYNIX) { + /* read retry table not allowed to use read retry */ + info->data_ecc_uncor_err = 2; + if (bank >= (dmabank-1)) + printk(KERN_ERR "data area bank %d uncor err at eslc page=0x%x no retry\n", bank, info->cur_page); + } + #ifdef RETRY_DEBUG + else { + if (bank >= (dmabank-1)) + printk(KERN_ERR "data area bank %d uncor err page=0x%x use retry\n", bank, info->cur_page); + } + #endif + + return; + } else { + if (bank >= (dmabank-1)) { + printk("reda lpage=%x bbt_sw_rdmz=%d hold=%x blkcnt=%d\n", info->cur_lpage, mtd->bbt_sw_rdmz, ((mtd->blkcnt - 8)*mtd->pagecnt), mtd->blkcnt); + printk(KERN_ERR "data area uncor err page=0x%x,blk=%d no retry\n", info->cur_page, info->cur_page/mtd->pagecnt); + /*print_nand_buffer(info->dmabuf, 32);printk("isrcmd 0x=%x\n", info->isr_cmd); + print_nand_buffer((uint8_t *)(info->reg+ECC_FIFO_0), 48); + print_nand_register(mtd); + while(1);*/ + } else + return; + } + printk(KERN_ERR "data area unc++ page=0x%x no retry\n", info->cur_page); + mtd->ecc_stats.failed++; + return; /* uncorrected err */ + } + if (mtd->ecc_err_cnt < bch_ecc_idx) + mtd->ecc_err_cnt = bch_ecc_idx; + /* mtd->ecc_stats.corrected += (bank_stat2 & BCH_ERR_CNT);*/ + /* BCH ECC correct */ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "data area %d bit corrected err on bank %d \n", bch_ecc_idx, bank); + #endif + /*if (bank >= (dmabank-1)) { + print_nand_register(mtd); + }*/ + + for (i = 0; i < bch_ecc_idx; i++) + bch_err_pos[i] = (readw(info->reg + NFCR18_ECC_BCH_ERR_POS + 2*i) & BCH_ERRPOS0); + + /* continue read next bank and calc BCH ECC */ + clear_ecc_resume_dma(info); + + for (i = 0; i < bch_ecc_idx; i++) { + //if (bank >= (dmabank-1)) + //printk(KERN_NOTICE "data area byte=%d corrected err on bank %d bs=%d, banks=%d\n", bch_err_pos[i]>>3, bank, bank_size,dmabank); + //printk(KERN_NOTICE "data page=0x%x byte=%d corrected err on bank %d bs=%d, banks=%d\n", + //info->cur_page, bch_err_pos[i]>>3, bank, bank_size,dmabank); + if((bch_err_pos[i] >> 3) < bank_size) { + //printk(KERN_NOTICE "bank%d area value=%x ", bank, info->dmabuf[bank_size* bank + (bch_err_pos[i] >> 3)]); + bit_correct(&info->dmabuf[bank_size* bank + (bch_err_pos[i] >> 3)], bch_err_pos[i] & 0x07); + //printk(KERN_NOTICE "bank%d area c-value=%x \n", bank, info->dmabuf[bank_size* bank + (bch_err_pos[i] >> 3)]); + } else if ((bch_err_pos[i] >> 3) < (bank_size + 24) && bank >= (dmabank-1)) {//oob area + //printk(KERN_NOTICE "red area value=%x ", *((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size)); + bit_correct((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size, (bch_err_pos[i] & 0x07)); + //printk(KERN_NOTICE "red area c-value=%x \n", *((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size)); + } + #ifdef NAND_DEBUG + printk(KERN_NOTICE "data area %xth ecc error position is byte%d bit%d\n", + i, bank_size * bank + (bch_err_pos[i] >> 3), (bch_err_pos[i] & 0x07)); + #endif + } +} + +void bch_data_last_bk_ecc_correct_noalign(struct mtd_info *mtd) +{ + int i, all_FF; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *this = mtd->priv; + unsigned int bank_stat2, bch_ecc_idx, bank, bank_size, bank_oob = info->banks; + + bank_stat2 = readw(info->reg + NFCR17_ECC_BCH_ERR_STAT); + bch_ecc_idx = bank_stat2 & BCH_ERR_CNT; + bank = (bank_stat2 & BANK_NUM) >> 8; + /* mtd->ecc_stats.corrected += (bank_stat2 & BCH_ERR_CNT);*/ + /* BCH ECC correct */ + + #ifdef NAND_DEBUG + printk(KERN_NOTICE "Read lst bk data \n"); + #endif + + bank_size = info->bank_size; + if (bch_ecc_idx >= BCH_ERR_CNT) { + //print_nand_buffer((uint8_t *)info->dmabuf+bank_size * bank_oob, 32); + //unsigned int oob_parity_size = readb(info->reg + NFCR10_OOB_ECC_SIZE+1); + all_FF = check_all_FF((uint32_t *)(info->dmabuf+bank_size * bank_oob + 24), 6, mtd);//print_nand_buffer(info->dmabuf+bank_size * bank_oob + 24, 24); + clear_ecc_resume_dma(info); + //printk(KERN_ERR "lstbk err cur_page=0x%x %d all_FF=%d\n",info->cur_page, info->cur_page, all_FF); + if (all_FF > 0) { + info->unc_allFF = 1; + return; + } + if (mtd->dwRetry && this->cur_chip) { + info->data_ecc_uncor_err = 1; + printk(KERN_ERR + "last bank data area uncorrected err cur_page=%d use retry\n",info->cur_page); + //print_nand_buffer(info->dmabuf+bank_size * bank_oob/* + 24*/, 48); + return; + } else + printk(KERN_ERR + "last bank data area uncorrected err cur_page=%d no retry\n",info->cur_page); + mtd->ecc_stats.failed++; + //while(bank_stat1); + return; + } + if (mtd->ecc_err_cnt < bch_ecc_idx) + mtd->ecc_err_cnt = bch_ecc_idx; + /* mtd->ecc_stats.corrected += (bank_stat2 & BCH_ERR_CNT);*/ + /* BCH ECC correct */ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "last bank %d bit corrected error\n", bch_ecc_idx); + #endif + for (i = 0; i < bch_ecc_idx; i++) { + bch_err_pos[i] = (readw(info->reg + NFCR18_ECC_BCH_ERR_POS + 2*i) & BCH_ERRPOS0); + //printk(KERN_NOTICE "data area byte=%d corrected err on bank %d bs=%d, banks=%d\n", bch_err_pos[i]>>3, bank, bank_size,bank_oob+1); + if((bch_err_pos[i] >> 3) < bank_size) { + bit_correct(&info->dmabuf[bank_size * bank_oob + (bch_err_pos[i] >> 3)], bch_err_pos[i] & 0x07); + } /*else if ((bch_err_pos[i] >> 3) < (bank_size + 24)) {//oob area of last bank + //printk(KERN_NOTICE "redundant area value=%d ", *((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size)); + bit_correct((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size, (bch_err_pos[i] & 0x07)); + //printk(KERN_NOTICE "redundant area value=%d \n", *((uint8_t *)(info->reg+ECC_FIFO_0)+(bch_err_pos[i] >> 3) - bank_size)); + }*/ + + #ifdef NAND_DEBUG + printk(KERN_NOTICE "data area last bank %xth ecc error position is byte%d bit%d\n", + i, bank_size * bank + (bch_err_pos[i] >> 3), (bch_err_pos[i] & 0x07)); + #endif + } + /* continue read next bank and calc BCH ECC */ + clear_ecc_resume_dma(info); +} + +/* +* [Routine Description] +* read status +* [Arguments] +* cmd : nand read status command +* [Return] +* the result of command +*/ +static int wmt_read_nand_status(struct mtd_info *mtd, unsigned char cmd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int cfg = 0, status = -1; + unsigned int b2r_stat; + + #ifdef WMT_HW_RDMZ + unsigned int rdmz; + rdmz = readb(info->reg + NFCRf_CALC_RDMZ+2); + if (mtd->dwRdmz && rdmz) { + //dump_stack(); + nfc_hw_rdmz(mtd, 1); + writeb(0, info->reg + NFCR4_COMPORT3_4); + } + #endif + + writeb(cmd, info->reg + NFCR2_COMPORT0); + cfg = TWHR|DPAHSE_DISABLE|(1<<1); + + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); +//print_nand_register(mtd); + writew(cfg|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_wait_cmd_ready(mtd); + if (status) { + printk(KERN_ERR "NFC command transfer1 is not ready\n"); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + return status; + } + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + cfg = SING_RW|NAND2NFC; + writew(cfg|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); +//print_nand_register(mtd); + status = wmt_wait_cmd_ready(mtd); + if (status) { + printk(KERN_ERR "NFC command transfer2 is not ready\n"); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + return status; + } + status = wmt_nfc_transfer_ready(mtd); + /* status = wmt_nand_wait_idle(mtd);*/ + if (status) { + printk(KERN_ERR "NFC IO transfer is not ready\n"); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + /*print_nand_register(mtd);*/ + return status; + } + info->datalen = 0; + info->dmabuf[0] = readb(info->reg + NFCR0_DATAPORT) & 0xff; + #ifdef WMT_HW_RDMZ + if (mtd->dwRdmz && rdmz) { + //printk(KERN_ERR "sts=%x\n", info->dmabuf[0]); + info->dmabuf[0] = info->dmabuf[0]^rdmz_tb[0]; + if ((info->dmabuf[0]&0xFF) != 0xe0) { + printk(KERN_ERR "de-rdmz sts=%x page=%x\n", info->dmabuf[0],info->cur_page); + //if (info->cur_page != 0x7ff00) { + print_nand_register(mtd); + dump_stack(); + //while(1); + //} + } + } + #endif + + status = info->dmabuf[0]; + //printk( "read status=0x%x\n", status); + return status; +} + +void fill_desc(unsigned int *Desc, unsigned int len, unsigned char *buf, unsigned int bank_size) +{ + unsigned int CurDes_off = 0, i; + unsigned char *desc = (unsigned char *)Desc; + + for (i = 0; i < (len/bank_size); i++) { + nand_init_short_desc((unsigned int *)(desc+CurDes_off), bank_size, + (unsigned int *)(buf+i*bank_size), + ((i == ((len/bank_size)-1)) && (!(len%bank_size))) ? 1 : 0); + CurDes_off += sizeof(struct _NAND_PDMA_DESC_S); + } + if (len%bank_size) + nand_init_short_desc((unsigned int *)(desc+CurDes_off), + (len%bank_size), (unsigned int *)(buf+i*bank_size), 1); +} + +/* data_flag = 0: set data ecc fifo */ +static int wmt_nfc_dma_cfg(struct mtd_info *mtd, unsigned int len, unsigned int wr, +int data_flag, int Nbank) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int status; + unsigned int *ReadDesc, *WriteDesc, ofs; + ofs = mtd->writesize + mtd->oobsize + 0x1000 - (mtd->oobsize%0x1000); + ReadDesc = (unsigned int *)(info->dmabuf + ofs + 0x100); + WriteDesc = (unsigned int *)(info->dmabuf + ofs + 0x200); + /* + printk(KERN_ERR "info->dmabuf = 0x%x\r\n", (unsigned int) info->dmabuf); + printk(KERN_ERR "info->dmaaddr = 0x%x\r\n", (unsigned int) info->dmaaddr); + printk(KERN_ERR "ReadDesc addr = 0x%x\r\n", (unsigned int) ReadDesc); + printk(KERN_ERR "WriteDesc addr = 0x%x\r\n", (unsigned int) WriteDesc); + */ + if (len == 0) { + printk(KERN_ERR "DMA transfer length = 0\r\n"); + return 1; + } + if (len > 1024 && readb(info->reg + NFCR9_ECC_BCH_CTRL)&DIS_BCH_ECC) { + len = 512; + if (mtd->realwritesize > 8192) + len = 1024; + } + + if (data_flag == 0) { + writeb(readb(info->reg + NFCRd_OOB_CTRL) & 0xF7, info->reg + NFCRd_OOB_CTRL); + } + writew(len - 1, info->reg + NFCR8_DMA_CNT); + status = nand_init_pdma(mtd); + if (status) + printk(KERN_ERR "nand_init_pdma fail status = 0x%x", status); + + if (readl(info->reg + NFC_DMA_ISR) & NAND_PDMA_IER_INT_STS) + writel(NAND_PDMA_IER_INT_STS, info->reg + NFC_DMA_ISR); + + if (readl(info->reg + NFC_DMA_ISR) & NAND_PDMA_IER_INT_STS) { + printk(KERN_ERR "PDMA interrupt status can't be clear "); + printk(KERN_ERR "NFC_DMA_ISR = 0x%8.8x \n", (unsigned int)readl(info->reg + NFC_DMA_ISR)); + } + + nand_alloc_desc_pool((wr) ? WriteDesc : ReadDesc); + /*nand_init_short_desc((wr)?WriteDesc : ReadDesc, len, (unsigned long *)buf);*/ + if (info->oob_ecc_error == 0x50 && len != 1 && len != 3) { + fill_desc((wr)?WriteDesc : ReadDesc, len, (unsigned char *)info->last_bank_dmaaddr, 1024); + if (len != 1024 && len != 512) + printk("oob_ecc_error len!=1024, len=%d \n", len); + } else if (Nbank == 2) {//for multi-plane 2nd plane wr dma cfg + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + fill_desc((wr)?WriteDesc : ReadDesc, len, (unsigned char *)info->dmaaddr, 1024); + else + fill_desc((wr)?WriteDesc : ReadDesc, len, (unsigned char *)info->dmaaddr + mtd->realwritesize, 1024); + } else + fill_desc((wr)?WriteDesc : ReadDesc, len, (unsigned char *)info->dmaaddr, 1024); + /*printk(KERN_ERR "dma wr=%d, len=0x%x\n", wr, len);*/ + + nand_config_pdma(mtd, + (wr) ? (unsigned long *)(info->dmaaddr + ofs + 0x200) + : (unsigned long *)(info->dmaaddr + ofs + 0x100), wr); + + return 0; +} + +int nand_init_pdma(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + + writel(NAND_PDMA_GCR_SOFTRESET, info->reg + NFC_DMA_GCR); + writel(NAND_PDMA_GCR_DMA_EN, info->reg + NFC_DMA_GCR); + if (readl(info->reg + NFC_DMA_GCR) & NAND_PDMA_GCR_DMA_EN) + return 0; + else + return 1; +} + + +int nand_free_pdma(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + writel(0, info->reg + NFC_DMA_DESPR); + writel(0, info->reg + NFC_DMA_GCR); + return 0; +} + + +int nand_alloc_desc_pool(unsigned int *DescAddr) +{ + memset(DescAddr, 0x00, 0x80); + return 0; +} + +int nand_init_short_desc(unsigned int *DescAddr, unsigned int ReqCount, unsigned int *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_desc(unsigned long *DescAddr, unsigned long *BufferAddr, int Blk_Cnt) +{ + int i = 0 ; + unsigned long *CurDes = DescAddr; + + nand_alloc_desc_pool(CurDes); + + + for (i = 0 ; i < 3 ; i++) { + nand_init_short_desc(CurDes, 0x80, BufferAddr); + BufferAddr += (i * 0x80); + CurDes += (i * sizeof(NAND_PDMA_DESC_S)); + } + if (Blk_Cnt > 1) { + nand_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + sizeof(NAND_PDMA_DESC_L), 0); + BufferAddr += (i * 0x80); + CurDes += (i * sizeof(NAND_PDMA_DESC_L)); + + nand_init_long_desc(CurDes, (Blk_Cnt - 1) * 512, BufferAddr, + CurDes + sizeof(NAND_PDMA_DESC_L), 1); + } else { + nand_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + sizeof(NAND_PDMA_DESC_L), 1); + } + + return 0; +} +*/ + +int nand_config_pdma(struct mtd_info *mtd, unsigned long *DescAddr, unsigned int dir) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + if (info->isr_cmd != NAND_SET_FEATURE && info->isr_cmd != 0x37 && info->isr_cmd != 0x36) + writel(NAND_PDMA_IER_INT_EN, info->reg + NFC_DMA_IER); + writel((unsigned long)DescAddr, info->reg + NFC_DMA_DESPR); + if (dir == NAND_PDMA_READ) + writel(readl(info->reg + NFC_DMA_CCR)|NAND_PDMA_CCR_peripheral_to_IF, + info->reg + NFC_DMA_CCR); + else + writel(readl(info->reg + NFC_DMA_CCR)&(~NAND_PDMA_CCR_peripheral_to_IF), + info->reg + NFC_DMA_CCR); + wmb(); + /*mask_interrupt(IRQ_NFC_DMA);*/ + writel(readl(info->reg + NFC_DMA_CCR)|NAND_PDMA_CCR_RUN, info->reg + NFC_DMA_CCR); + /*printk(KERN_ERR "NFC_DMA_CCR = 0x%8.8x\r\n", readl(info->reg + NFC_DMA_CCR));*/ + /*print_nand_register(mtd);*/ + wmb(); + return 0; +} + +int nand_pdma_handler(struct mtd_info *mtd) +{ + unsigned long status = 0; + unsigned long count = 0; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + + count = 0x100000; +#if 0 + /* polling CSR TC status */ + if (!(readl(info->reg + NFC_DMA_CCR)|NAND_PDMA_CCR_peripheral_to_IF)) { + do { + count--; + if (readl(info->reg + NFC_DMA_ISR) & NAND_PDMA_IER_INT_STS) { + status = readl(info->reg + NFC_DMA_CCR) & NAND_PDMA_CCR_EvtCode; + writel(readl(info->reg + NFC_DMA_ISR)&NAND_PDMA_IER_INT_STS, info->reg + NFC_DMA_ISR); + printk(KERN_ERR "NFC_DMA_ISR = 0x%8.8x\r\n", + (unsigned int)readl(info->reg + NFC_DMA_ISR)); + break; + } + if (count == 0) { + printk(KERN_ERR "PDMA Time Out!\n"); + printk(KERN_ERR "NFC_DMA_CCR = 0x%8.8x\r\n", + (unsigned int)readl(info->reg + NFC_DMA_CCR)); + /*print_nand_register(mtd);*/ + count = 0x100000; + /*break;*/ + } + } while (1); +} else +#endif + status = readl(info->reg + NFC_DMA_CCR) & NAND_PDMA_CCR_EvtCode; + writel(readl(info->reg + NFC_DMA_ISR)&NAND_PDMA_IER_INT_STS, info->reg + NFC_DMA_ISR); + if (status == NAND_PDMA_CCR_Evt_ff_underrun) + printk(KERN_ERR "PDMA Buffer under run!\n"); + + if (status == NAND_PDMA_CCR_Evt_ff_overrun) + printk(KERN_ERR "PDMA Buffer over run!\n"); + + if (status == NAND_PDMA_CCR_Evt_desp_read) + printk(KERN_ERR "PDMA read Descriptor error!\n"); + + if (status == NAND_PDMA_CCR_Evt_data_rw) + printk(KERN_ERR "PDMA read/write memory descriptor error!\n"); + + if (status == NAND_PDMA_CCR_Evt_early_end) + printk(KERN_ERR "PDMA read early end!\n"); + + if (count == 0) { + printk(KERN_ERR "PDMA TimeOut!\n"); + while (1) + ; + } + return 0; +} + +int nand_get_feature(struct mtd_info *mtd, int addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int cfg = 0, i = 0; + int status = -1; + + writeb(0xEE, info->reg + NFCR2_COMPORT0); + writeb(addr, info->reg + NFCR3_COMPORT1_2); + cfg = DPAHSE_DISABLE|(0x02<<1); + writew(cfg|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + + status = wmt_wait_cmd_ready(mtd); + + if (status) { + printk(KERN_ERR "nand_get_feature(): wait cmd is not ready\n"); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + return status; + } + status = wmt_wait_chip_ready(mtd); + if (status) + printk(KERN_ERR "flash is not ready\n"); + + status = wmt_nand_ready(mtd); + if (status) + printk(KERN_ERR "get feature wait B2R fail\n"); + + cfg = NAND2NFC|SING_RW; + for (i = 0; i < 4; i++) { + writew(cfg|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_wait_cmd_ready(mtd); + if (status) + return status; + status = wmt_nfc_transfer_ready(mtd); + if (status) { + printk(KERN_ERR "in nand_get_feature(): wait transfer cmd is not ready\n"); + return status; + } + info->dmabuf[i] = readb(info->reg + NFCR0_DATAPORT) & 0xff; + } + //#ifdef NAND_DEBUG + printk(KERN_NOTICE "nand get feature %x %x %x %x\n", + info->dmabuf[0], info->dmabuf[1], info->dmabuf[2], info->dmabuf[3]); + //#endif + info->datalen = 0; + return 0; +} + +int nand_set_feature(struct mtd_info *mtd, int cmd, int addrss, int value) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int cfg = 0, len = 4; + int status = -1; + DECLARE_COMPLETION(complete); + //unsigned char id[4] = {value, 0, 0, 0}; + info->dmabuf[0] = value; + info->dmabuf[1] = 0; + info->dmabuf[2] = 0; + info->dmabuf[3] = 0; + info->isr_cmd = cmd; + info->done_data = &complete; + writel(readl(info->reg + NFCR9_ECC_BCH_CTRL) | DIS_BCH_ECC, info->reg + NFCR9_ECC_BCH_CTRL); + //printk("set feature cycle1\n"); + + writeb(0x1F, info->reg + NFCR13_INT_MASK); + writel(B2R, info->reg + NFCRb_NFC_INT_STAT); + if (readb(info->reg + NFCRb_NFC_INT_STAT) & B2R) + printk("nand get feature B2R can't clear\n"); + writeb(0x1B, info->reg + NFCR13_INT_MASK); + + //printk("set feature cycle2\n"); + + wmt_nfc_dma_cfg(mtd, len, 1, 0, -1); + //print_nand_register(nfc); + + writeb(cmd, info->reg + NFCR2_COMPORT0); + writeb(addrss, info->reg + NFCR3_COMPORT1_2); + cfg = (0x02<<1); + //print_nand_register(mtd); + //printk("set feature cycle trigg = 0x%x\n", cfg|NFC_TRIGGER|OLD_CMD); + writew(cfg|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + //print_nand_register(mtd); + //printk("set feature cycle3\n"); + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + status = NFC_WAIT_IDLE(mtd); + if (status) { + printk("get feature nand flash idle time out\n"); + return status; + } + + writeb(0x80, info->reg + NFCR13_INT_MASK); + //printk("set feature cycle5\n"); + status = wmt_nfc_transfer_ready(mtd); + /* status = wmt_nand_wait_idle(mtd);*/ + if (status) { + printk(KERN_ERR "NFC IO transfer is not ready\n"); + /*print_nand_register(mtd);*/ + return status; + } + + status = NFC_WAIT_IDLE(mtd); + if (status) { + printk("set feature nand flash idle time out\n"); + return status; + } + + status = nand_pdma_handler(mtd); + nand_free_pdma(mtd); + if (status) + printk(KERN_ERR "check write pdma handler status= %x \n", status); + writel(readl(info->reg + NFCR9_ECC_BCH_CTRL) & ~DIS_BCH_ECC, info->reg + NFCR9_ECC_BCH_CTRL); + printk(KERN_DEBUG " MICRON flash set feature timing mode %d\n", value); + return status; +} + +int get_parameter(struct mtd_info *mtd, uint8_t *buf, uint8_t *addr, int size) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int cfg = 0, len = 1; + int i, status = -1, regc = size; + unsigned char *FIFO = (unsigned char *) (info->reg+ECC_FIFO_c); + + //print_nand_register(mtd); + + for (i = 0; i < regc;i++) { + //DECLARE_COMPLETION(complete); + info->isr_cmd = 0x37; + //info->done_data = &complete; + //printk("hynix retry get c1\n"); + //nfc->reg->NFCR13 = 0x0F; + writeb(0x1F, info->reg + NFCR13_INT_MASK); + //nfc->reg->NFCRb |= B2R; /* write to clear */ + writel(B2R, info->reg + NFCRb_NFC_INT_STAT); + if (readb(info->reg + NFCRb_NFC_INT_STAT) & B2R) + printk("B2R can't clear\n"); + + //printk("hynix retry get c2\n"); + wmt_nfc_dma_cfg(mtd, len, 0, 0, -1); + //print_nand_register(nfc); + writeb(readb(info->reg + NFCRd_OOB_CTRL) | HIGH64FIFO, info->reg + NFCRd_OOB_CTRL); + if (i == 0) { + FIFO[0] = 0x37; + FIFO[1] = addr[0]; + //nfc->reg->NFCRc = 0x00020001; + writel(0x00020001, info->reg + NFCRc_CMD_ADDR); + cfg = (0x02<<1); + } else { + FIFO[0] = addr[i]; + // set address latch ALE(high) and CLE(lower) + //nfc->reg->NFCRc = 0x00010000; + writel(0x00010000, info->reg + NFCRc_CMD_ADDR); + cfg = (0x01<<1); + } + //print_nand_register(mtd); + //printk("hynix get retry param trigg = 0x%x\n", NAND2NFC|cfg|NFC_TRIGGER); + //nfc->reg->NFCR1 = NAND2NFC|cfg|NFC_TRIGGER; /* cfg & start*/ + writew(NAND2NFC|cfg|NFC_TRIGGER, info->reg + NFCR1_COMCTRL); + //print_nand_register(mtd); + //wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + //j = 0; + while (!readl(info->reg + NFC_DMA_ISR)&NAND_PDMA_IER_INT_STS); + status = NFC_WAIT_IDLE(mtd); + if (status) { + printk("get feature nand flash idle time out\n"); + return status; + } + writeb(0x80, info->reg + NFCR13_INT_MASK); + //printk("set feature cycle5\n"); + status = wmt_nfc_transfer_ready(mtd); + /* status = wmt_nand_wait_idle(mtd);*/ + if (status) { + printk(KERN_ERR "NFC IO transfer is not ready\n"); + /*print_nand_register(mtd);*/ + return status; + } + + status = NFC_WAIT_IDLE(mtd); + if (status) { + printk("set feature nand flash idle time out\n"); + return status; + } + + status = nand_pdma_handler(mtd); + nand_free_pdma(mtd); + if (status) + printk(KERN_ERR "check write pdma handler status= %x \n", status); + + buf[i] = info->dmabuf[0]; + } + + #ifdef RETRY_DEBUG + printk("retry param buf ="); + for (i = 0; i < regc;i++) + printk(" 0x%x", buf[i]); + printk("\n"); + #endif + + //writel(readl(info->reg + NFCR9_ECC_BCH_CTRL) & ~DIS_BCH_ECC, info->reg + NFCR9_ECC_BCH_CTRL); + writeb(readb(info->reg + NFCRd_OOB_CTRL) & ~HIGH64FIFO, info->reg + NFCRd_OOB_CTRL); + return status; +} + +int hynix_get_parameter(struct mtd_info *mtd, int mode) +{ + struct nand_chip *this = mtd->priv; + struct nand_read_retry_param *cur_chip = this->cur_chip; + 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 { + printk("Not support this mode %d\n", mode); + return rc; + } + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + rc = get_parameter(mtd, buf, offset, reg_num); + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1);//enable rdmz + if (rc != 0) + 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; + //printk("ESLC: "); + print_nand_buffer(buf, reg_num); + } else { + //printk("ESLC Current: "); + //print_nand_buffer(buf, reg_num); + } + } 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; + //printk("Retry : "); + //print_nand_buffer(buf, reg_num); + } else { + //printk("Retry Current: "); + //print_nand_buffer(buf, reg_num); + //printk("\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; + } + if(i == reg_num) { + cur_chip->cur_try_times = j; + printk("Get current try times %d from current register.\n", j); + break; + } + } + + } + } + return rc; +} + +int write_bytes_cmd(struct mtd_info *mtd, int cmd_cnt, int addr_cnt, int data_cnt, uint8_t *cmd, uint8_t *addr, uint8_t *data) +{ + int i, status = 0; + unsigned int cmd_addr_cycle = 0, cfg = 0, cfg_bit8 = 0, counter = 10000; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned char *FIFO = (unsigned char *) (info->reg+ECC_FIFO_c); + + + writeb(0x1F, info->reg + NFCR13_INT_MASK); + + status = NFC_WAIT_IDLE(mtd); + if (status) { + printk("nand flash idle time out\n"); + return status; + } + + if (data_cnt > 0) { + info->isr_cmd = 0x36; + memcpy(info->dmabuf, data, data_cnt); + wmt_nfc_dma_cfg(mtd, data_cnt, 1, 0, -1); + } + writeb(readb(info->reg + NFCRd_OOB_CTRL) | HIGH64FIFO, info->reg + NFCRd_OOB_CTRL); + 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)); + } + writel(cmd_addr_cycle, info->reg + NFCRc_CMD_ADDR); + + #ifdef RETRY_DEBUG + //printk("NFCRc=0x%x ", cmd_addr_cycle); + printk("FIFO = "); + for (i = 0; i < (addr_cnt+cmd_cnt); i++) + printk("0x%x ", FIFO[i]); + if (data_cnt > 0) { + printk("data = "); + for (i = 0; i < data_cnt; i++) { + printk("0x%x ", data[i]); + } + printk("\n"); + } else + printk("\n"); + #endif + + cfg = ((cmd_cnt + addr_cnt)&0x7)<<1; + cfg_bit8 = (((cmd_cnt + addr_cnt)&0x18)>>3)<<8; + + if (data_cnt == 0) + cfg |= DPAHSE_DISABLE; + + writew(cfg_bit8|cfg|NFC_TRIGGER, info->reg + NFCR1_COMCTRL); + +//print_nand_register(mtd); + status = wmt_nfc_transfer_ready(mtd); + if (status) { + writeb(readb(info->reg + NFCRd_OOB_CTRL) & ~HIGH64FIFO, info->reg + NFCRd_OOB_CTRL); + printk(KERN_ERR "NFC IO transfer is not ready\n"); + /*print_nand_register(mtd);*/ + goto go_fail; + } + status = NFC_WAIT_IDLE(mtd); + if (status) { + printk("retry c1 wait idle time out\n"); + goto go_fail; + } + if (cmd_cnt > 0 && cmd) + if (cmd[0] == NAND_CMD_RESET) { + status = wmt_nand_ready(mtd); + if (status) { + printk(KERN_ERR "Reset err, nand device is not ready\n"); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + } + } + if (data_cnt > 0) + while (!readl(info->reg + NFC_DMA_ISR)&NAND_PDMA_IER_INT_STS) { + if (counter <= 0) { + break; + } + counter--; + } + if (data_cnt > 0) { + status = nand_pdma_handler(mtd); + nand_free_pdma(mtd); + if (status) { + printk(KERN_ERR "check write pdma handler status= %x \n", status); + goto go_fail; + } + } + +go_fail: + writeb(0x80, info->reg + NFCR13_INT_MASK); + writeb(readb(info->reg + NFCRd_OOB_CTRL) & ~HIGH64FIFO, info->reg + NFCRd_OOB_CTRL); + + return status; +} + +int set_parameter(struct mtd_info *mtd, unsigned char *buf, unsigned char *offset, int regn) +{ + int i, status = -1, regc = regn; + unsigned char cmd[2] = {0x36, 0x16}; +//print_nand_register(mtd); + status = write_bytes_cmd(mtd, 1, 1, 1, (uint8_t *)&cmd[0], offset, buf); + if (status) + printk("hynix_set read retry reg: phase 0 fail"); + for (i = 1; i < regc; i++) { + status = write_bytes_cmd(mtd, 0, 1, 1, NULL, &offset[i], &buf[i]); + if (status) + printk("hynix_set read retry reg: phase %d fail", i); + } + status = write_bytes_cmd(mtd, 1, 0, 0, (uint8_t *)&cmd[1], NULL, NULL); + if (status) + printk("load_hynix_opt_reg: phase 3 fail"); + + return status; +} + +void dummy_read(struct mtd_info *mtd) +{ + int status = -1; + uint8_t cmd[2] = {0x00, 0x30}, addr[5] = {0, 0, 0, 0, 0}; + + status = write_bytes_cmd(mtd, 1, 5, 0, &cmd[0], addr, NULL); + if (status) + printk("dummy read cmd(00) + addr fail\n"); + status = write_bytes_cmd(mtd, 1, 0, 0, &cmd[1], NULL, NULL); + if (status) + printk("dummy read cmd(0x30) fail\n"); +/*print_nand_register(mtd); +dump_stack();*/ + /* check busy to ready status*/ + status = wmt_nand_ready(mtd); + if (status) { + printk(KERN_ERR "NFC check B2R time out\n"); + } +} + +int hynix_set_parameter(struct mtd_info *mtd, int mode, int def_value) +{struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *this = mtd->priv; + struct nand_read_retry_param *cur_chip = this->cur_chip; + 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 (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; + } + } +#ifdef RETRY_DEBUG + printk("hynix set value: cur_try_times=%d\n", cur_chip->cur_try_times); + for(rc = 0; rc < reg_num; rc++) + printk(" 0x%x:0x%x ", offset[rc], set_value[rc]); + printk("reg_num = %d\n", reg_num); +#endif + + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + + rc = set_parameter(mtd, set_value, offset, reg_num); + + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1);//enable rdmz + + if(rc) { + printk("set_parameter fail.\n"); + return rc; + } + + if (def_value == DEFAULT_VALUE && mode == ESLC_MODE) { + printk("dummy read: rpage=%x wpage%x\n", info->cur_page, info->lst_wpage); + dummy_read(mtd); + } + + return rc; +} + +int toshiba_pre_condition(struct mtd_info *mtd) +{ + int status = 0; + unsigned char cmd1[2] = {0x5c, 0xc5}; + + status = write_bytes_cmd(mtd, 2, 0, 0, cmd1, NULL, NULL); + if(status) + printk("toshiba pre condition cmd1 time out.\n"); + else + printk("toshiba pre condition OK.\n"); + + return status; +} + +int toshiba_get_parameter(struct mtd_info *mtd, int mode) +{ + return 0; +} + +int toshiba_set_parameter(struct mtd_info *mtd, int mode, int def_mode) +{ + int i, status = -1; + struct nand_chip *this = mtd->priv; + struct nand_read_retry_param *cur_chip = this->cur_chip; + unsigned char cmd2[1] = {0x55}; + unsigned char cmd3[2] = {0x26, 0x5d}; + unsigned char *set_value = NULL; + unsigned char *offset = NULL; + + + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + + + if (cur_chip->cur_try_times >= cur_chip->total_try_times) + cur_chip->cur_try_times = 0; + 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++; + #ifdef RETRY_DEBUG + printk("toshiba set cur_try_times=%d\n", cur_chip->cur_try_times); + #endif + for (i = 0; i < 4; i++) { + status = write_bytes_cmd(mtd, 1, 1, 1, cmd2, &offset[i], &set_value[i]); + if (status) + printk("toshiba set read retry reg: phase %d fail", i); + } + + status = write_bytes_cmd(mtd, 2, 0, 0, cmd3, NULL, NULL); + if (status) { + printk("pre condition cmd2 time out\n"); + } + + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1);//enable rdmz + + return status; +} + +int samsung_get_parameter(struct mtd_info *mtd, int mode) +{ + return 0; +} + +int samsung_set_parameter(struct mtd_info *mtd, int mode, int def_mode) +{ + struct nand_chip *this = mtd->priv; + struct nand_read_retry_param *cur_chip = this->cur_chip; + 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}; + + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + + 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 + printk("samsung set value: cur_try_times=%d\n", cur_chip->cur_try_times); + for(i = 0; i < reg_num; i++) + printk(" 0x%x:0x%x ", offset[i], set_value[i]); + printk("reg_num = %d\n", reg_num); + #endif + + for (i = 0; i < reg_num; i++) { + data[1] = offset[i]; + data[2] = set_value[i]; + rc = write_bytes_cmd(mtd, 1, 0, 3, cmd, NULL, data); + if (rc) + printk("samsung read retry reg: phase %d fail\n", i); + } + + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1);//enable rdmz + + return rc; +} + +int sandisk_get_parameter(struct mtd_info *mtd, int mode) +{ + return 0; +} + +int sandisk_set_parameter(struct mtd_info *mtd, int total_try_times, int def_value) +{ + struct nand_chip *this = mtd->priv; + struct nand_read_retry_param *cur_chip = this->cur_chip; + 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; + + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + + 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 + printk("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++) + printk(" 0x%x:0x%x ", offset[i], set_value[i]); + printk("reg_num = %d\n", reg_num); +#endif + rc = write_bytes_cmd(mtd, 2, 0, 0, cmd, NULL, NULL); + if (rc) + printk("sandisk read retry reg: set cmd fail\n"); + for (i = 0; i < reg_num; i++) { + rc = write_bytes_cmd(mtd, 1, 1, 1, &cmd[2], &offset[i], &set_value[i]); + if (rc) + printk("sandisk set retry reg: phase %d fail\n", i); + } + + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1);//enable rdmz + + return rc; +} + +int sandisk_init_retry_register(struct mtd_info *mtd, struct nand_read_retry_param *cur_chip) +{ + int i,status = -1; + unsigned char cmd[4] = {0x3B, 0xB9, 0x53, 0x54}; + unsigned char *offset = cur_chip->otp_offset; + unsigned char *data = cur_chip->otp_data; + unsigned int regc = cur_chip->otp_len; + + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + + #ifdef RETRY_DEBUG + printk("set sandisk init retry register offset addr: 0x%x, 0x%x\n", offset[0], offset[1]); + #endif + status = write_bytes_cmd(mtd, 2, 0, 0, cmd, NULL, NULL); + if (status) { + printk("send sandisk_init_retry_register cmd fail\n"); + } + for (i = 0; i < regc; i++) { + status = write_bytes_cmd(mtd, 1, 1, 1, &cmd[2], &offset[i], &data[i]); + if (status) + printk("sandisk_init_retry_register : phase %d fail", i); + } + + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1);//enable rdmz + + return status; +} + +int micron_get_parameter(struct mtd_info *mtd, int mode) +{ + return 0; +} + +int micron_set_parameter(struct mtd_info *mtd, int mode, int def_mode) +{ + struct nand_chip *this = mtd->priv; + struct nand_read_retry_param *cur_chip = this->cur_chip; + unsigned char *offset = NULL; + unsigned char *set_value = NULL; + unsigned int reg_num; + int rc = -1, i; + uint8_t cmd[1] = {NAND_SET_FEATURE}; + + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + + 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 + printk("micron set value: cur_try_times=%d\n", cur_chip->cur_try_times); + for(i = 0; i < reg_num; i++) + printk(" 0x%x:0x%x ", offset[i], set_value[i]); + printk("reg_num = %d\n", reg_num); + #endif + + for (i = 0; i < reg_num; i++) { + rc = write_bytes_cmd(mtd, 1, 1, 1, cmd, offset, set_value); + if (rc) + printk("micron read retry reg: phase %d fail\n", i); + } + + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1);//enable rdmz + + return rc; +} + +static int wmt_nand_read_raw_page(struct mtd_info *mtd, struct nand_chip *chip, int page); +int hynix_get_otp(struct mtd_info *mtd, struct nand_chip *chip) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_read_retry_param *cur_chip = chip->cur_chip; + int i, j, status = -1; + //unsigned char data[2] = {0x00, 0x4D}; + unsigned char cmd[5] = {0x36, 0x16, 0x17, 0x04, 0x19}; + //unsigned char addr[2] = {0xAE , 0xB0}; + unsigned int page = 0x200; + unsigned char *buff, reset = NAND_CMD_RESET, retry_end = NAND_CMD_HYNIX_RETRY_END; + unsigned char *offset = cur_chip->otp_offset; + unsigned char *data = cur_chip->otp_data; + unsigned int retry_times, retry_regs, chk = 0; + unsigned char *bf, *bf2; + + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + + printk("get otp offset addr: 0x%x, 0x%x\n", offset[0], offset[1]); + //chip->cmdfunc(mtd, NAND_CMD_RESET_NO_STATUS_READ, -1, -1); + + status = write_bytes_cmd(mtd, 1, 0, 0, (uint8_t *)&reset, NULL, NULL); + if (status) { + printk("load_hynix_opt_reg: reset fail"); + } + status = write_bytes_cmd(mtd, 1, 1, 1, (uint8_t *)&cmd[0], (uint8_t *)&offset[0], (uint8_t *)&data[0]); + if (status) + printk("load_hynix_opt_reg: phase 1 fail"); + status = write_bytes_cmd(mtd, 0, 1, 1, NULL, (uint8_t *)&offset[1], (uint8_t *)&data[1]); + if (status) + printk("load_hynix_opt_reg: phase 2 fail"); + status = write_bytes_cmd(mtd, 4, 0, 0, (uint8_t *)&cmd[1], NULL, NULL); + if (status) + printk("load_hynix_opt_reg: phase 3 fail"); + //status = HY_nand_read(0, page, buf, 1026, ecc_code, nfc, 0); + wmt_nand_read_raw_page(mtd, chip, page); + /*if (status != 0) { + printk("load_hynix_opt_reg: phase 3 fail status = %d\n", status); + //return -1; + }*/ + status = write_bytes_cmd(mtd, 1, 0, 0, (uint8_t *)&reset, NULL, NULL); + if (status) { + printk("load_hynix_opt_reg: reset fail"); + } + status = write_bytes_cmd(mtd, 1, 0, 0, (uint8_t *)&retry_end, NULL, NULL); + if (status) { + printk("load_hynix_opt_reg: OTP end 0x38 fail"); + } + + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1);//enable rdmz + + print_nand_buffer((uint8_t *)info->dmabuf, 1040); + buff = info->dmabuf; + if (buff[0] > 8 || buff[1] > 8) { + printk("retry_cmd buff is not big enough for size %d\n", buff[0]*buff[1]); + return -1; + } + + retry_times = buff[0]; + retry_regs = buff[1]; + + cur_chip->total_try_times = buff[0] - 1; + cur_chip->retry_reg_num = 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) { + printk("inverse check fail %x %x\n", bf[j], bf2[j]); + break; + } + } + if (j >= (retry_times*retry_regs)) { + chk = 1; + break; + } + } + + if (chk == 0) { + printk("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->retry_def_value[buff[1]] = 0xff; + cur_chip->retry_def_value[buff[1]+1] = 0xff; + + + return 0; +} + +int nand_get_para(struct mtd_info *mtd, struct nand_chip *chip) +{ + int ret = 0; + struct nand_read_retry_param *cur_chip = chip->cur_chip; + + if (cur_chip->get_otp_table) { + ret = cur_chip->get_otp_table(mtd, chip); + if (ret) { + printk("get otp para error\n"); + chip->cur_chip = NULL; + return ret; + } else + printk("get otp retry para end\n"); + } else if (cur_chip->get_parameter) { + ret = cur_chip->get_parameter(mtd, READ_RETRY_MODE); + if (ret) { + printk("get default retry para error\n"); + chip->cur_chip = NULL; + return ret; + } else + printk("get default retry para end\n"); + } + + if (cur_chip->eslc_reg_num) { + ret = cur_chip->get_parameter(mtd, ESLC_MODE); + if (ret) { + printk("get default eslc error\n"); + chip->cur_chip = NULL; + } else + printk("get eslc param end\n"); + } + + print_nand_buffer((uint8_t *)cur_chip, sizeof(chip_table[0])); + + return ret; +} + +static int wmt_nand_readID(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int cfg = 0, i = 0; + int status = -1; + + writeb(NAND_CMD_READID, info->reg + NFCR2_COMPORT0); + writeb(0x00, info->reg + NFCR3_COMPORT1_2); + cfg = DPAHSE_DISABLE|(0x02<<1); + writew(cfg|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + + status = wmt_wait_cmd_ready(mtd); + /* status = wmt_nfc_ready(mtd);*/ + + if (status) { + printk(KERN_ERR "in wmt_nand_readID(): wait cmd is not ready\n"); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + return status; + } + cfg = NAND2NFC|SING_RW; + for (i = 0; i < 6; i++) { + writew(cfg|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_wait_cmd_ready(mtd); + /* status = wmt_nfc_ready(mtd);*/ + if (status) + return status; + status = wmt_nfc_transfer_ready(mtd); + /* status = wmt_nand_wait_idle(mtd);*/ + if (status) { + printk(KERN_ERR "in wmt_nand_readID(): wait transfer cmd is not ready\n"); + return status; + } + info->dmabuf[i] = readb(info->reg + NFCR0_DATAPORT) & 0xff; + + #ifdef NAND_DEBUG + printk(KERN_NOTICE "readID is %x\n", readb(info->reg + NFCR0_DATAPORT)); + #endif + } + info->datalen = 0; + return 0; +} + +/* check flash busy pin is ready => return 1 else return 0 */ +static int wmt_device_ready(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + return readb(info->reg + NFCRa_NFC_STAT) & 0x01; +} + + +static void wmt_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + if (mode == hardware_ecc) + writeb(readb(info->reg + NFCR9_ECC_BCH_CTRL) & (~DIS_BCH_ECC), info->reg + NFCR9_ECC_BCH_CTRL); + else + writeb(readb(info->reg + NFCR9_ECC_BCH_CTRL) | DIS_BCH_ECC, info->reg + NFCR9_ECC_BCH_CTRL); +} + +/*static*/ void print_nand_register(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int j; + + for (j = 0; j < 0x200; j += 16) + printk(KERN_NOTICE "NFCR%x ~ NFCR%x = 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\r\n", + j/4, (j+12)/4, + readl(info->reg + j + 0), + readl(info->reg + j + 4), + readl(info->reg + j + 8), + readl(info->reg + j + 12)); +} + +void print_nand_buffer(char *value, unsigned int length) +{ + int j; + for (j = 0; j < length; j += 16) + printk(KERN_NOTICE "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, value[j+0], value[j+1], value[j+2], value[j+3], value[j+4], + value[j+5], value[j+6], value[j+7], value[j+8], value[j+9], + value[j+10], value[j+11], value[j+12], value[j+13], value[j+14], value[j+15]); +} +void print_nand_buffer_int(unsigned int *value, unsigned int length) +{ + int j; + for (j = 0; j < length; j += 8) + printk(KERN_NOTICE"Row%3.3x:%8.2x-%8.2x-%8.2x-%8.2x-%8.2x-%8.2x-%8.2x-%8.2x\n", + j, value[j+0], value[j+1], value[j+2], value[j+3], value[j+4], value[j+5], value[j+6], value[j+7]); +} + +static void set_read_addr(struct mtd_info *mtd, unsigned int *address_cycle, int column, int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *chip = mtd->priv; + unsigned int addr_cycle = 0; + + if (column != -1) { + writeb(column, info->reg + NFCR3_COMPORT1_2); + addr_cycle++; + if (mtd->realwritesize != 512) { + writeb(column >> 8, (unsigned char *)(info->reg + NFCR3_COMPORT1_2) + 1); + addr_cycle++; + } + if (page_addr != -1) { + if (mtd->realwritesize != 512) { + writeb(page_addr, info->reg + NFCR4_COMPORT3_4); + page_addr >>= 8; + writeb(page_addr, (unsigned char *)(info->reg + NFCR4_COMPORT3_4) + 1); + addr_cycle += 2; + } else { + writeb(page_addr, (unsigned char *)(info->reg + NFCR3_COMPORT1_2) + 1); + page_addr >>= 8; + writeb(page_addr, info->reg + NFCR4_COMPORT3_4); + addr_cycle += 2; + } + + if (mtd->realwritesize == 2048) { + /* One more address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) { + page_addr >>= 8; + if (mtd->realwritesize != 512) + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + else + writeb(page_addr, + (unsigned char *)(info->reg + NFCR4_COMPORT3_4) + 1); + addr_cycle++; + } + } else if (mtd->realwritesize == 4096) { + /* One more address cycle for devices > 256MiB */ + if (chip->chipsize > (256 << 20)) { + page_addr >>= 8; + if (mtd->realwritesize != 512) + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + else + writeb(page_addr, + (unsigned char *)(info->reg + NFCR4_COMPORT3_4) + 1); + addr_cycle++; + } + } else if (mtd->realwritesize == 8192) { + /* One more address cycle for devices > 512MiB */ + if (chip->chipsize > (512 << 20)) { + page_addr >>= 8; + if (mtd->realwritesize != 512) + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + else + writeb(page_addr, + (unsigned char *)(info->reg + NFCR4_COMPORT3_4) + 1); + addr_cycle++; + } + } else if (mtd->realwritesize == 16384) { + /* One more address cycle for devices > 1024MiB */ + if (chip->chipsize > (1024 << 20)) { + page_addr >>= 8; + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + addr_cycle++; + } + } else {/*page size 512*/ + /* One more address cycle for devices > 32MiB */ + if (chip->chipsize > (32 << 20)) { + page_addr >>= 8; + if (mtd->realwritesize != 512) + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + else + writeb(page_addr, + (unsigned char *)(info->reg + NFCR4_COMPORT3_4) + 1); + addr_cycle++; + } + } + } + /* } else if (page_addr != -1) {*/ + } else if ((page_addr != -1) && (column == -1)) { + writeb(page_addr & 0xff, info->reg + NFCR3_COMPORT1_2); + page_addr >>= 8; + writeb(page_addr & 0xff, (unsigned char *)(info->reg + NFCR3_COMPORT1_2) + 1); + addr_cycle += 2; + + if (mtd->realwritesize == 2048) { + /* One more address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) { + page_addr >>= 8; + writeb(page_addr & 0xff, + info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } else if (mtd->realwritesize == 4096) { + /* One more address cycle for devices > 256MiB */ + if (chip->chipsize > (256 << 20)) { + page_addr >>= 8; + writeb(page_addr & 0xff, + info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } else if (mtd->realwritesize == 8192) { + /* One more address cycle for devices > 512MiB */ + if (chip->chipsize > (512 << 20)) { + page_addr >>= 8; + writeb(page_addr & 0xff, + info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } else if (mtd->realwritesize == 16384) { + /* One more address cycle for devices > 1024MiB */ + if (chip->chipsize > (1024 << 20)) { + page_addr >>= 8; + writeb(page_addr & 0xff, + info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } else {/*page size = 512 bytes */ + /* One more address cycle for devices > 32MiB */ + if (chip->chipsize > (32 << 20)) { + + /* One more address cycle for devices > 128MiB */ + /* if (chip->chipsize > (128 << 20)) {*/ + page_addr >>= 8; + /* writeb(page_addr, + info->reg + NFCR4_COMPORT3_4 + 1); */ + /* before, may be a little error */ + writeb(page_addr & 0xff, + info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } + } + *address_cycle = addr_cycle; +} + +static int wmt_multi_page_start_micron(struct mtd_info *mtd, unsigned command, int colum, int page) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + //struct nand_chip *chip = mtd->priv; + unsigned int pagecnt = mtd->pagecnt; + unsigned int b2r_stat; + int status = 0, i; + DECLARE_COMPLETION(complete); + + uint8_t cmd[2] = {0x00, 0x32}, addr[5] = {0, 0, 0, 0, 0}; + + for (i = 0; i < 3; i++) { + addr[2+i] = 0xFF&(page>>(8*i)); + } + + status = write_bytes_cmd(mtd, 1, 5, 0, &cmd[0], addr, NULL); + if (status) + printk("micron multi read cmd(00) + addr fail\n"); + status = write_bytes_cmd(mtd, 1, 0, 0, &cmd[1], NULL, NULL); + if (status) + printk("micron multi read cmd(32) + addr fail\n"); + + /* check busy to ready status*/ + status = wmt_nand_ready(mtd); + + for (i = 0; i < 3; i++) { + addr[2+i] = 0xFF&((page + pagecnt)>>(8*i)); + } + + status = write_bytes_cmd(mtd, 1, 5, 0, &cmd[0], addr, NULL); + if (status) + printk("micron multi read cmd(00) + addr fail\n"); + + writeb(0x30, info->reg + NFCR2_COMPORT0); + + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + if (B2R&b2r_stat) { + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + status = wmt_wait_chip_ready(mtd); + if (status) + printk(KERN_NOTICE"The chip is not ready\n"); + } + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + writeb(0x1B, info->reg + NFCR13_INT_MASK); + + info->done_data = &complete; + info->isr_cmd = 0x60; + + writew(DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + info->datalen = 0; + + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + //writeb(0x80, info->reg + NFCR13_INT_MASK); + + status = wmt_nfc_wait_idle(mtd, 1, 1, -1, -1); /* write page, don't check ecc */ + //b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + //writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + status = wmt_wait_cmd_ready(mtd); + if (status) { + printk(KERN_ERR "Multi_read_start err: nfc command is not ready\n"); + } + writeb(0x80, info->reg + NFCR13_INT_MASK); + return 0; +} + +static int wmt_multi_page_start(struct mtd_info *mtd, unsigned command, int colum, int page) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *chip = mtd->priv; + unsigned int pagecnt = mtd->pagecnt; + unsigned int b2r_stat; + int status = 0; + DECLARE_COMPLETION(complete); + + chip->cmdfunc(mtd, 0x60, -1, page); + chip->cmdfunc(mtd, 0x60, -1, page + pagecnt); + + writeb(0x30, info->reg + NFCR2_COMPORT0); + + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + if (B2R&b2r_stat) { + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + status = wmt_wait_chip_ready(mtd); + if (status) + printk(KERN_NOTICE"The chip is not ready\n"); + } + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + writeb(0x1B, info->reg + NFCR13_INT_MASK); + + info->done_data = &complete; + info->isr_cmd = 0x60; + + writew(DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + info->datalen = 0; + + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + //writeb(0x80, info->reg + NFCR13_INT_MASK); + + status = wmt_nfc_wait_idle(mtd, 1, 1, -1, -1); /* write page, don't check ecc */ + //b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + //writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + status = wmt_wait_cmd_ready(mtd); + if (status) { + printk(KERN_ERR "Multi_read_start err: nfc command is not ready\n"); + } + writeb(0x80, info->reg + NFCR13_INT_MASK); + return 0; +} +//unsigned int r1,r2,r3,r4,r5,r6,r7,r8,r9,r10; +static int wmt_multi_page_read(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + //struct nand_chip *chip = mtd->priv; + DECLARE_COMPLETION(complete); + unsigned int addr_cycle = 0 /*b2r_stat, bank_stat1, bank_stat2=0*/; + int status = -1; + unsigned char *FIFO = (unsigned char *) (info->reg+ECC_FIFO_c); + + info->isr_cmd = command; + info->data_ecc_uncor_err = 0; + info->dma_finish = 0; + info->done_data = &complete; + + set_read_addr(mtd, &addr_cycle, column, page_addr); + + writeb(NAND_CMD_READ0, info->reg + NFCR2_COMPORT0); + //printk("multi read page=%x blk=%d, addr_cycle=%d trig=%x\n",page_addr, page_addr/128, addr_cycle, DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD); + //print_nand_register(mtd); + writew(DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + wmb(); + status = wmt_wait_cmd_ready(mtd); + if (status) { + printk(KERN_ERR "Multi_read_s2 err: nfc command is not ready\n"); + } + + addr_cycle = 0; + if (column != -1) { + writeb(column, info->reg + NFCR3_COMPORT1_2); + writeb(column, info->reg + NFCR3_COMPORT1_2 + 1); + addr_cycle += 2; + } + + writeb(NAND_CMD_RNDOUT, info->reg + NFCR2_COMPORT0); + writew(DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + wmb(); + status = wmt_wait_cmd_ready(mtd); + if (status) { + printk(KERN_ERR "Multi_read_s2 err: nfc command is not ready\n"); + } + + writeb(0x1C, info->reg + NFCR13_INT_MASK); + writeb(readb(info->reg + NFCRd_OOB_CTRL) | HIGH64FIFO, info->reg + NFCRd_OOB_CTRL); + FIFO[0] = NAND_CMD_RNDOUTSTART; + FIFO[3] = 0xFF&page_addr; + writeb(readb(info->reg + NFCRd_OOB_CTRL) & ~HIGH64FIFO, info->reg + NFCRd_OOB_CTRL); + writel(0x80001, info->reg + NFCRc_CMD_ADDR); + + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + wmt_nfc_dma_cfg(mtd, mtd->realwritesize + 1024, 0, -1, -1); + else + wmt_nfc_dma_cfg(mtd, mtd->realwritesize, 0, -1, -1);//r3 = wmt_read_oscr(); + + info->datalen = 0; + + //printk("2page=%x blk=%d, addr_cycle=%d trig=%x\n",page_addr, page_addr/256, addr_cycle, NAND2NFC|MUL_CMDS|((addr_cycle + 2)<<1)|NFC_TRIGGER|OLD_CMD); +//print_nand_register(mtd); + //writew(NAND2NFC|MUL_CMDS|((addr_cycle + 2)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + //writew(NAND2NFC|(1<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + writew(NAND2NFC|(1<<1)|NFC_TRIGGER, info->reg + NFCR1_COMCTRL); + wmb(); + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + if (info->dma_finish != 1) { + printk("read page wait dma time out info->dma_finish=%d\n",info->dma_finish); + print_nand_register(mtd); + dump_stack(); + while(info->dma_finish == 0) { + if (readl(info->reg + NFC_DMA_ISR)&1) { + writel(0, info->reg + NFC_DMA_IER); + info->dma_finish++; + if (info->done_data != NULL) { + //complete(info->done_data); + info->done_data = NULL; + } + } + } + } + + status = nand_pdma_handler(mtd); + nand_free_pdma(mtd); + if (status) + printk(KERN_ERR "dma transfer data time out: %x\n", + readb(info->reg + NFCRa_NFC_STAT)); + + wmt_nfc_transfer_ready(mtd); + writeb(0x80, info->reg + NFCR13_INT_MASK); + status = wmt_nfc_wait_idle(mtd, 0, command, column, page_addr); + if (status) { + printk(KERN_NOTICE"multi-read page wait idle status =%d\n", status); + } + return 0; +} + +static int wmt_dma_ready(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i = 0; + + while (1) { + if ((readb(info->reg + NFC_DMA_ISR) & NAND_PDMA_IER_INT_STS)) + break; + + if (++i>>20) + return -3; + } + return 0; +} + +//#define RE_PORFO +static int wmt_nand_page_read(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *chip = mtd->priv; + struct nand_read_retry_param *cur_chip = chip->cur_chip; + unsigned int addr_cycle = 0, b2r_stat; + int status = -1; + unsigned int bank_stat, id = 0, pageInBlk = 0; + int i, total_times = 1, total_try_times = 0, tmp = 0; + unsigned char reset = NAND_CMD_RESET, retry_enable =0xB6, retry_disable = 0xD6; + DECLARE_COMPLETION(complete); + + #ifdef NAND_DEBUG + printk(KERN_NOTICE "read data cmd: 0x%x col:0x%x, page:0x%x\n", command, column, page_addr); + #endif + /*info->phase = 0; + if (readl(info->reg + NFCR9_ECC_BCH_CTRL) & DIS_BCH_ECC) + info->phase = 2;*/ + + if (cur_chip != NULL) { + total_times = cur_chip->total_try_times + 1; + id = (cur_chip->nand_id>>24)&0xFF; + if (id == NAND_MFR_SANDISK) { + pageInBlk = page_addr%mtd->pagecnt; + if (((pageInBlk%2) == 1 || pageInBlk == 0) && pageInBlk != (mtd->pagecnt - 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; + //printk("read page--cur_times = %d, totoal_times = %d \n", cur_chip->cur_try_times, total_times); + } + //cur_chip->cur_try_times = 4; + for (i = 0; i < total_times; i++) { + info->unc_bank = 0; + info->unc_allFF = 0; + if (i > 0) + info->isr_cmd = command; + + info->data_ecc_uncor_err = 0; + info->dma_finish = 0; + writeb(0x1C, info->reg + NFCR13_INT_MASK); + info->done_data = &complete; + /* 1: read, 0:data, -1: */ + if (info->phase == 2) {//disable bch read + tmp = (mtd->realoobsize > 512) ? mtd->realoobsize : 512; + wmt_nfc_dma_cfg(mtd, tmp, 0, -1, -1); + } else { + if (info->oob_ecc_error == 0x50) {//read last bank for oob in DDR mode + wmt_nfc_dma_cfg(mtd, chip->ecc.size, 0, -1, -1); + } else {//read whole page + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + wmt_nfc_dma_cfg(mtd, mtd->realwritesize + 1024, 0, -1, -1); + else + wmt_nfc_dma_cfg(mtd, mtd->realwritesize, 0, -1, -1); + } + } + /*print_nand_register(mtd);*/ + wmb(); + info->datalen = 0; + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + /* printk(KERN_NOTICE "RB is %d\n", b2r_stat & 0x02);*/ + + set_read_addr(mtd, &addr_cycle, column, page_addr); + + bank_stat = readw(info->reg + NFCRb_NFC_INT_STAT); + writew(bank_stat|0x101, info->reg + NFCRb_NFC_INT_STAT); + + status = wmt_wait_chip_ready(mtd); /*Vincent 2008.11.3*/ + if (status) + printk(KERN_ERR "The chip is not ready\n"); + writeb(NAND_CMD_READ0, info->reg + NFCR2_COMPORT0); + if (addr_cycle == 4) + writeb(NAND_CMD_READSTART, info->reg + NFCR5_COMPORT5_6); + else if (addr_cycle == 5) + writeb(NAND_CMD_READSTART, (unsigned char *)(info->reg + NFCR5_COMPORT5_6) + 1); + wmb(); + writew(NAND2NFC|MUL_CMDS|((addr_cycle + 2)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + wmb(); + //printk("read page wait for completion\n"); + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + if (info->dma_finish != 1) { + printk("read page wait dma time out info->dma_finish=%d\n",info->dma_finish); + print_nand_register(mtd); + dump_stack(); + while(info->dma_finish == 0) { + if (readl(info->reg + NFC_DMA_ISR)&1) { + writel(0, info->reg + NFC_DMA_IER); + info->dma_finish++; + if (info->done_data != NULL) { + //complete(info->done_data); + info->done_data = NULL; + } + } + } + } + status = nand_pdma_handler(mtd); + //printk(KERN_ERR "check status pdma handler status= %x \n", status); + nand_free_pdma(mtd); + if (status) + printk(KERN_ERR "dma transfer data time out: %x\n", + readb(info->reg + NFCRa_NFC_STAT)); +//printk("read page 3\n"); + wmt_nfc_transfer_ready(mtd); + /*status = wmt_nand_ready(mtd); + if (status) + printk(KERN_NOTICE"B2R not clear status=0x%x\n", status);*/ + writeb(0x80, info->reg + NFCR13_INT_MASK); +//printk("read page 4\n"); + status = wmt_nfc_wait_idle(mtd, 0, command, column, page_addr); +//printk("read page 5\n"); + if (status) { + printk(KERN_NOTICE"read page wait idle status =%d\n", status); + /*print_nand_register(mtd);*/ + /*while(1);*/ + } + if (info->unc_allFF == 0 && info->unc_bank && mtd->dwRetry == 0) { + mtd->ecc_stats.failed++; + printk("no retry flash occur uncoverable ecc error uncor_err=%d\n", info->data_ecc_uncor_err); + } + + if(info->data_ecc_uncor_err == 1) { + if((cur_chip != NULL)) { + mtd->ecc_err_cnt = 0; + if (prob_end == 1 && page_addr < ((mtd->blkcnt - 8) * mtd->pagecnt)){ + if((id != NAND_MFR_HYNIX) ||((id == NAND_MFR_HYNIX) && (cur_chip->cur_try_times >=5))) + printk("Unc_Err %d_th pg=0x%x cur_retry=%d\n", i, page_addr, cur_chip->cur_try_times); + } + + if (id == NAND_MFR_HYNIX) { + //printk("set retry mode cur_try_times=%d\n", cur_chip->cur_try_times); + cur_chip->set_parameter(mtd, READ_RETRY_MODE, ECC_ERROR_VALUE); + cur_chip->retry = 1; + + if (i == total_try_times) { + cur_chip->retry = 0; + /* read retry many times still ecc uncorrectable error */ + cur_chip->set_parameter(mtd, READ_RETRY_MODE, DEFAULT_VALUE); + if (prob_end == 1 && page_addr < ((mtd->blkcnt - 8) * mtd->pagecnt)) + printk("read page after retry still uncor err\n"); + mtd->ecc_stats.failed++; + //dump_stack(); + //while(cur_chip); + return status; + } + } else if (id == NAND_MFR_TOSHIBA) { + if (cur_chip->cur_try_times >= total_try_times) { + /* send reset cmd after read retry finish(fail) for toshiba */ + write_bytes_cmd(mtd, 1, 0, 0, (uint8_t *)&reset, NULL, NULL); + cur_chip->cur_try_times = 0; + cur_chip->retry = 0; + if (prob_end == 1 && page_addr < ((mtd->blkcnt - 8) * mtd->pagecnt)) + printk("read page after retry still uncor err\n"); + mtd->ecc_stats.failed++; + //while(cur_chip); + return status; + } + if (cur_chip->cur_try_times == 0 && cur_chip->retry != 1) + toshiba_pre_condition(mtd); + cur_chip->set_parameter(mtd, 0, 0); + cur_chip->retry = 1; + } else if (id == NAND_MFR_SAMSUNG || id == NAND_MFR_MICRON) { + if (cur_chip->cur_try_times >= total_try_times) { + /* send default cmd after read retry finish(fail) for samsung */ + cur_chip->set_parameter(mtd, READ_RETRY_MODE, DEFAULT_VALUE); + cur_chip->cur_try_times = 0; + cur_chip->retry = 0; + if (prob_end == 1 && page_addr < ((mtd->blkcnt - 8) * mtd->pagecnt)) + printk("read page after retry still uncor err\n"); + mtd->ecc_stats.failed++; + //while(cur_chip); + return status; + } + cur_chip->set_parameter(mtd, READ_RETRY_MODE, ECC_ERROR_VALUE); + cur_chip->retry = 1; + } else if (id == NAND_MFR_SANDISK) { + //printk("set retry mode cur_try_times=%d\n", cur_chip->cur_try_times); + cur_chip->set_parameter(mtd, total_try_times, ECC_ERROR_VALUE); + if (i == 0 && cur_chip->retry != 1) + write_bytes_cmd(mtd, 1, 0, 0, &retry_enable, NULL, NULL); + cur_chip->retry = 1; + + if (i == total_try_times) { + write_bytes_cmd(mtd, 1, 0, 0, &retry_disable, NULL, NULL); + cur_chip->retry = 0; + /* read retry many times still ecc uncorrectable error */ + if (prob_end == 1 && page_addr < ((mtd->blkcnt - 8) * mtd->pagecnt)) + printk("read page after retry still uncor err\n"); + mtd->ecc_stats.failed++; + //while(cur_chip); + return status; + } + } + } else { + printk("read page uncor err but cur_chip = NULL!\n"); + break; + } + } else { + if (cur_chip) { + unsigned int bakeup; + if (cur_chip->retry == 1) { + if((id != NAND_MFR_HYNIX) || ((id == NAND_MFR_HYNIX)&&(cur_chip->cur_try_times >= 5))) + printk("read retry PASS cur_try_times=%d\n", cur_chip->cur_try_times); + bakeup = *(uint32_t *)info->dmabuf; + } else + break; + /* send reset cmd after read retry finish(pass) for toshiba */ + if (id == NAND_MFR_TOSHIBA) { + write_bytes_cmd(mtd, 1, 0, 0, (uint8_t *)&reset, NULL, NULL); + printk("reset cmd to finish retry\n"); + cur_chip->cur_try_times = 0; + } else if (id == NAND_MFR_SAMSUNG || id == NAND_MFR_MICRON) { + cur_chip->set_parameter(mtd, READ_RETRY_MODE, DEFAULT_VALUE); + cur_chip->cur_try_times = 0; + } else if (id == NAND_MFR_SANDISK) { + write_bytes_cmd(mtd, 1, 0, 0, &retry_disable, NULL, NULL); + //set retry default value need before page program + cur_chip->set_parameter(mtd, total_try_times, DEFAULT_VALUE); + //should we reset cur_try_times to zero? + cur_chip->cur_try_times = -1; + } if (id == NAND_MFR_HYNIX) { + cur_chip->set_parameter(mtd, READ_RETRY_MODE, DEFAULT_VALUE); + cur_chip->cur_try_times = -1; + } + cur_chip->retry = 0; + *(uint32_t *)info->dmabuf = bakeup; + } + break; + } + } //end of retry for loop + + return 0; +} +#if 0 +static int wmt_multi_copy_start(struct mtd_info *mtd, unsigned command, int column, int page) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *chip = mtd->priv; + + unsigned int div = mtd->erasesize / mtd->writesize; + + unsigned int b2r_stat; + + int status = 0; + + chip->cmdfunc(mtd, 0x60, -1, page); + + chip->cmdfunc(mtd, 0x60, -1, page + div); + + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + writeb(0x35, info->reg + NFCR2_COMPORT0); + + writew(NAND2NFC|DPAHSE_DISABLE|1<<1|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL);// cost lots of time + + status = wmt_wait_cmd_ready(mtd); + + if (status) { + + printk(KERN_ERR "Multi_read err: nfc command is not ready\n"); + } + + return 0; +} +static int wmt_multi_copy_read(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + //struct nand_chip *chip = mtd->priv; + + unsigned int addr_cycle = 0;//, b2r_stat, bank_stat1, bank_stat2=0; + int status = -1; + //unsigned int bank_stat, id = 0, pageInBlk = 0; + + set_read_addr(mtd, &addr_cycle, column, page_addr); + // bank_stat = readw(info->reg + NFCRb_NFC_INT_STAT); + // writew(bank_stat|0x101, info->reg + NFCRb_NFC_INT_STAT); + + //status = wmt_wait_chip_ready(mtd); /*Vincent 2008.11.3*/ //problem + + // if (status) + // printk(KERN_ERR "The chip is not ready\n"); + writeb(NAND_CMD_READ0, info->reg + NFCR2_COMPORT0); + + writew(DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_wait_cmd_ready(mtd); + if (status) { + printk(KERN_ERR "Multi_read err: nfc command is not ready\n"); + } + + addr_cycle = 0; + if (column != -1) { + writeb(column, info->reg + NFCR3_COMPORT1_2); + writeb(column, info->reg + NFCR3_COMPORT1_2 + 1); + addr_cycle += 2; + } + + // writeb(0x07, info->reg + WMT_NFC_REDUNT_ECC_STAT); + // writel(0xffffffff, info->reg + WMT_NFC_BANK18_ECC_STAT); + // b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + // writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + writeb(NAND_CMD_RNDOUT, info->reg + NFCR2_COMPORT0); + + writeb(NAND_CMD_RNDOUTSTART, info->reg + NFCR4_COMPORT3_4); + + writew(DPAHSE_DISABLE|MUL_CMDS|((addr_cycle + 2)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_nfc_wait_idle(mtd, 0, command, column, page_addr); + if(status) { + printk(KERN_NOTICE"WaitIdle is not ready=%d\n", status); + } + return status; +} + +static int wmt_multi_copy_write(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int div = mtd->erasesize / mtd->writesize; + unsigned int addr_cycle = 0; + int status = -1; + int b2r_stat = 0; + + set_read_addr(mtd, &addr_cycle, column, page_addr); + writeb(0x85, info->reg + NFCR2_COMPORT0); + writew(DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_wait_cmd_ready(mtd); + if (status) + printk(KERN_ERR "erase command is not ready\n"); + + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + writeb(0x11, info->reg + NFCR2_COMPORT0); + writew(DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + + status = wmt_nand_ready(mtd); + if (status) + printk(KERN_NOTICE"B2R not clear status=0x%x\n", status); + status = wmt_nfc_wait_idle(mtd, 0, command, column, page_addr); + + if (status) { + printk(KERN_NOTICE"read page wait idle status =%d\n", status); + } + set_read_addr(mtd, &addr_cycle, column, page_addr+div); + writeb(0x81, info->reg + NFCR2_COMPORT0); + writew(DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_wait_cmd_ready(mtd); + if (status) + printk(KERN_ERR "command is not ready\n"); + + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + writeb(0x10, info->reg + NFCR2_COMPORT0); + writew(DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + + status = wmt_nand_ready(mtd); + if (status) + printk(KERN_NOTICE"B2R not clear status=0x%x\n", status); + status = wmt_nfc_wait_idle(mtd, 0, command, column, page_addr); + + if (status) { + printk(KERN_NOTICE"read page wait idle status =%d\n", status); + } + //printk("\n wmt_copy_back_write is OK!"); + return status; +} + +static int wmt_copy_back_read(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int addr_cycle = 0, b2r_stat; + int status = -1; + + set_read_addr(mtd, &addr_cycle, column, page_addr); + + writeb(NAND_CMD_READ0, info->reg + NFCR2_COMPORT0); + + writew(NAND2NFC|DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD,info->reg + NFCR1_COMCTRL); + + status = wmt_wait_cmd_ready(mtd); + if (status) + printk(KERN_ERR "Read 0x00 cmd is not ready\n"); + + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + writeb(0x35, info->reg + NFCR2_COMPORT0); + + writew(DPAHSE_DISABLE|1<<1|NFC_TRIGGER|OLD_CMD,info->reg + NFCR1_COMCTRL); + + status = wmt_nand_ready(mtd); + if (status) + printk(KERN_NOTICE"B2R not clear status=0x%x\n", status); + status = wmt_nfc_wait_idle(mtd, 0, command, column, page_addr); + + if (status) { + printk(KERN_NOTICE"read page wait idle status =%d\n", status); + } + //printk("\n wmt_copy_back_read is OK! "); + return status; +} + +static int wmt_copy_back_write(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int addr_cycle = 0; + int status = -1; + int b2r_stat = 0; + set_read_addr(mtd, &addr_cycle, column, page_addr); + writeb(0x85, info->reg + NFCR2_COMPORT0); + writew(DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_wait_cmd_ready(mtd); + if (status) + printk(KERN_ERR "erase command is not ready\n"); + + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + writeb(0x10, info->reg + NFCR2_COMPORT0); + writew(DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + + status = wmt_nand_ready(mtd); + if (status) + printk(KERN_NOTICE"B2R not clear status=0x%x\n", status); + status = wmt_nfc_wait_idle(mtd, 0, command, column, page_addr); + + if (status) { + printk(KERN_NOTICE"read page wait idle status =%d\n", status); + } + //printk("\n wmt_copy_back_write is OK!"); + return status; +} +#endif + + +static void wmt_nand_oob_read(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + //struct nand_chip *chip = mtd->priv; + unsigned int addr_cycle = 0, b2r_stat; + int status = -1; + unsigned int bank_stat; + int mycolumn = column, mypage_addr = page_addr; + DECLARE_COMPLETION(complete); + + info->data_ecc_uncor_err = 0; + + #ifdef NAND_DEBUG + printk(KERN_NOTICE "wmt_nand_oob_read: readoob col=0x%x, page=0x%x\n", column, page_addr); + #endif + + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + writeb(0x18, info->reg + NFCR13_INT_MASK); + info->done_data = &complete; + + info->datalen = 0; + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + /* printk(KERN_NOTICE "RB is %d\n", b2r_stat & 0x02);*/ + + set_read_addr(mtd, &addr_cycle, column, page_addr); + + bank_stat = readw(info->reg + NFCRb_NFC_INT_STAT); + if (bank_stat) + writew(B2R|(ERR_CORRECT | BCH_ERR), info->reg + NFCRb_NFC_INT_STAT); + + status = wmt_wait_chip_ready(mtd); /*Vincent 2008.11.3*/ + if (status) + printk(KERN_ERR "The chip is not ready\n"); + writeb(NAND_CMD_READ0, info->reg + NFCR2_COMPORT0); + if (addr_cycle == 4) + writeb(NAND_CMD_READSTART, info->reg + NFCR5_COMPORT5_6); + else if (addr_cycle == 5) + writeb(NAND_CMD_READSTART, (unsigned char *)(info->reg + NFCR5_COMPORT5_6) + 1); + + writew(NAND2NFC|MUL_CMDS|((addr_cycle + 2)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + + + /* read oob has no dma but assert B2R status */ + //printk("read oob wait for completion"); + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + status = wmt_nfc_transfer_ready(mtd); + if (status) + printk(KERN_NOTICE"oob read wait NFC_BUSY time out\n"); + //wmt_nand_ready(mtd); + writeb(0x80, info->reg + NFCR13_INT_MASK); + + status = wmt_nfc_wait_idle(mtd, 0, command, mycolumn, mypage_addr); + + if (status) { + if (status == -4) + return; + printk(KERN_ERR "wmt_nfc_wait_idle status =%d\n", status); + printk(KERN_ERR "command =0x%x\n", command); + printk(KERN_ERR "Read ERR ,NFC is not idle\n"); + /*print_nand_register(mtd);*/ + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + /*while(1);*/ + } +//printk(KERN_NOTICE "rbe|"); + return; +} + +/** + * wmt_isbad_bbt - [NAND Interface] Check if a block is bad + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + * +*/ +int wmt_isbad_bbt(struct mtd_info *mtd, struct nand_chip *chip, int block) +{ + uint8_t res; + + if (!mtd || !chip) { + printk(KERN_ERR "nand not init, check bad block fail.\n"); + return 1; + } + if (!chip->bbt) { + printk(KERN_ERR "nand bbt not init, check bad block fail.\n"); + return 1; + } + /* dannier test nandwrite tool */ + #if 0 + if (block == 339 || block == 342 || block == 344) { + //if (block == 338 || block == 340 || block == 341 || block == 343) { + printk("blk%d --->bad\n", block); + return 1; + } + #endif + + /* Get block number * 2 */ + block <<= 1; + res = (chip->bbt[block >> 3] >> (block & 0x06)) & 0x03; + + switch ((int)res) { + case 0x00: + return 0; + case 0x01: + return 1; + case 0x02: + return 1; + } + return 1; +} + +/** + * wmt_isbad_bbt_multi - [NAND Interface] Check if a block is bad + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + * +*/ +int wmt_isbad_bbt_multi(struct mtd_info *mtd, struct nand_chip *chip, int block) +{ + uint8_t res; + + if (!mtd || !chip) { + printk(KERN_ERR "nand not init, check bad block fail.\n"); + return 1; + } + if (!chip->bbt) { + printk(KERN_ERR "nand bbt not init, check bad block fail.\n"); + return 1; + } + /* dannier test nandwrite tool */ + #if 0 + if (block == 339 || block == 342 || block == 344) { + //if (block == 338 || block == 340 || block == 341 || block == 343) { + printk("blk%d --->bad\n", block); + return 1; + } + #endif + + /* Get block number * 4 */ + block <<= 2; + res = (chip->bbt[block >> 3] >> (block & 0x4)) & 0x0F; + + switch ((int)res) { + case 0x00: + return 0; + case 0x01: + case 0x04: + case 0x05: + return 1; + } + return 1; +} + +//#define ESLC_DEBUG +#define ESLC_READ_WRITE +#ifdef ESLC_READ_WRITE +static int hynix_eslc_page_address_calculate(struct mtd_info *mtd, struct nand_chip *chip, int page) +{ + int status = -1, page_in_blk, par_page_start = 0, par_page_end, block; + int good_blk = 0, bad_blk = 0, par_blk_start, par_blk_end, i, j, blk_page_shift; + unsigned int par_blk_ofs = 0, real_need_blk, real_page; + + blk_page_shift = chip->phys_erase_shift - chip->page_shift; + block = page >> blk_page_shift; + page_in_blk = page%mtd->pagecnt; + + if (page < par1_ofs/4) { + par_page_start = 0; + par_page_end = par1_ofs/4; + } else if (page < par1_ofs) { + par_page_start = par1_ofs/4; + par_page_end = par1_ofs; + } else if (page < par2_ofs) { + par_page_start = par1_ofs; + par_page_end = par2_ofs; + } else if (page < par3_ofs) { + par_page_start = par2_ofs; + par_page_end = par3_ofs; + } else { + par_page_start = par3_ofs; + par_page_end = par4_ofs; + } + par_blk_start = par_page_start >> blk_page_shift; + par_blk_end = par_page_end >> blk_page_shift; + par_blk_ofs = block - par_blk_start; + + for (j = par_blk_start; j < block; j++) { + if (chip->realplanenum) + status = wmt_isbad_bbt_multi(mtd, chip, j); + else + status = wmt_isbad_bbt(mtd, chip, j); + if (status) { + #ifdef ESLC_DEBUG + if (page_in_blk == 0 || page_in_blk == (mtd->pagecnt/2)) + printk("skip blk%d bad\n", j); + #endif + bad_blk++; + } + } + par_blk_ofs = par_blk_ofs - bad_blk; + real_need_blk = par_blk_ofs*2 + ((page_in_blk >= (mtd->pagecnt/2)) ? 1 : 0); + + for (i = par_blk_start; i < par_blk_end; i++) { + //printk("i=%d, par_blk_start=0x%x, par_blk_end=0x%x real_need_blk=0x%x\n", i, par_blk_start, par_blk_end, real_need_blk); + if (chip->realplanenum) + status = wmt_isbad_bbt_multi(mtd, chip, i); + else + status = wmt_isbad_bbt(mtd, chip, i); + if (status == 0) { + #ifdef ESLC_DEBUG + if (page_in_blk == 0 || page_in_blk == (mtd->pagecnt/2)) + printk("blk%d good\n",i); + #endif + good_blk++; + } + if (good_blk >= (real_need_blk + 1)) { + #ifdef ESLC_DEBUG + if (page_in_blk == 0 || page_in_blk == (mtd->pagecnt/2)) + printk("wr blk%d \n",i); + #endif + break; + } + } + if (i >= par_blk_end) { + if (page_in_blk == 0 || page_in_blk == (mtd->pagecnt/2)) + printk(KERN_ERR "eslc addr is out of partition size, skip page=0x%x" + ", par_page_end=0x%x, end_blk=%d\n", page, par_page_end, i); + return -1; + } + real_page = (i << blk_page_shift) + eslc_map_table[(page_in_blk%(mtd->pagecnt/2))]; + if (page_in_blk == 0 || page_in_blk == (mtd->pagecnt/2)) + printk(KERN_NOTICE "page = 0x%x ======> eslc page = 0x%x\n", page, real_page); + + return real_page; +} +#endif + +/* + * wmt_nand_cmdfunc - Send command to NAND large page device + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + * + * Send command to NAND device. This is the version for the new large page + * devices We dont have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + */ +static void wmt_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + struct nand_chip *chip = mtd->priv; + unsigned int addr_cycle = 0, b2r_stat, pmc_nand, chip_en, tmp; + int status = -1, i; + int mycolumn, mypage_addr; + DECLARE_COMPLETION(complete); + + if (!chip->realplanenum && (command == NAND_CMD_READ0)) { + info->cur_lpage = page_addr; + if (page_addr >= ((mtd->blkcnt - 8)*mtd->pagecnt)) + mtd->bbt_sw_rdmz = 1; + else + mtd->bbt_sw_rdmz = 0; + } +//printk(KERN_DEBUG "cmd %x col:%x, page:0x%x hold=0x%x \n", command, column, page_addr, ((mtd->blkcnt - 8)*mtd->pagecnt)); + if (mtd->id == 0xECDED57A) { + if (page_addr >= (4096*128)) { + page_addr = page_addr + 0x80000; + //printk(KERN_NOTICE "cmd %x col:%x, page:0x%x\n", command, column, page_addr); + } + } else if (command == NAND_CMD_READ0 && chip->cur_chip && prob_end == 1 && + (chip->cur_chip->nand_id>>24) == NAND_MFR_HYNIX) { + #ifdef ESLC_READ_WRITE + if (!chip->realplanenum) + if (command == NAND_CMD_READ0) { + if ((page_addr < par4_ofs && second_chip == 0)) { + #ifdef ESLC_DEBUG + if (page_addr%mtd->pagecnt == 0 || page_addr%mtd->pagecnt == (mtd->pagecnt/2)) + printk("\ncmdfunc: \n"); + #endif + page_addr = hynix_eslc_page_address_calculate(mtd, chip, page_addr); + if (page_addr < 0) + return; + } + #endif + } + } + mycolumn = column; + mypage_addr = page_addr; + #ifdef NAND_DEBUG + printk(KERN_NOTICE "enter in wmt_nand_cmdfunc() command: %x column:%x, page_addr:%x\n", + command, column, page_addr); + //if (command == 0x70) + //dump_stack(); + #endif + info->isr_cmd = command; + if (page_addr != 0xFFFFFFFF && page_addr != -1) + info->cur_page = page_addr; + info->phase = 0; + if (readl(info->reg + NFCR9_ECC_BCH_CTRL) & DIS_BCH_ECC) + info->phase = 2; + pmc_nand = *(volatile unsigned long *)PMCEU_ADDR;// |= (0x0010000);//add by vincent + if (!(pmc_nand&0x0010000)) + printk(KERN_NOTICE "pmc_nand=0x%x\n", pmc_nand); + + chip_en = readb(info->reg + NFCR12_NAND_TYPE_SEL+1); + if ((chip_en&7) == 7) { + printk(KERN_NOTICE "chip 0, or 1, is not select chip_sel=%x\n", chip_en); + writeb(0xfe, info->reg + NFCR12_NAND_TYPE_SEL+1); + } + + switch (command) { + case NAND_CMD_READ0: + #ifdef WMT_HW_RDMZ + tmp = DIS_BCH_ECC & readb(info->reg + NFCR9_ECC_BCH_CTRL); + if (mtd->dwRdmz) { + if (mtd->bbt_sw_rdmz || tmp) { + if ((RDMZ & readl(info->reg + NFCRf_CALC_RDMZ)) == RDMZ) + reset_nfc(mtd, NULL, 3); + } else + nfc_hw_rdmz(mtd, 1); + } + #endif + wmt_nand_page_read(mtd, command, column, page_addr); + /*#ifdef WMT_HW_RDMZ + if (mtd->dwRdmz) + nfc_hw_rdmz(mtd, 1); + #endif*/ + return; + case NAND_CMD_READOOB: + #ifdef WMT_HW_RDMZ + if (mtd->dwRdmz) { + if (mtd->bbt_sw_rdmz) { + if ((RDMZ & readl(info->reg + NFCRf_CALC_RDMZ)) == RDMZ) + reset_nfc(mtd, NULL, 3); + } else + nfc_hw_rdmz(mtd, 1); + } + #endif + //printk("oobRe=%x mtd->bbt_sw_rdmz=%d dwRdmz=%d\n", page_addr, mtd->bbt_sw_rdmz, mtd->dwRdmz); + wmt_nand_oob_read(mtd, command, column, page_addr); + /*#ifdef WMT_HW_RDMZ + if (mtd->dwRdmz) + nfc_hw_rdmz(mtd, 1); + #endif*/ + return; + + case MULTI_READ_1CYCLE: + if ((0xFF&(mtd->id>>24)) == NAND_MFR_MICRON || (0xFF&(mtd->id>>24)) == NAND_MFR_INTEL) + wmt_multi_page_start_micron(mtd, command, column, page_addr); + else + wmt_multi_page_start(mtd, command, column, page_addr); + return; + case MULTI_READ_2CYCLE: + info->isr_cmd = 0x00; + command = 0x00; + wmt_multi_page_read(mtd, command, column, page_addr); + return; + /*case MULTI_COPY_1CYCLE: + info->isr_cmd = 0x60; + command = 0x60; + wmt_multi_copy_start(mtd, command, column, page_addr); + return; + case MULTI_COPY_2CYCLE: + info->isr_cmd = 0x00; + command = 0x00; + wmt_multi_copy_read(mtd, command, column, page_addr); + return; + case MULTI_COPY_3CYCLE: + info->isr_cmd = 0x85; + command = 0x85; + wmt_multi_copy_write(mtd, command, column, page_addr); + return; + case COPY_BACK_1CYCLE: + info->isr_cmd = 0x00; + command = 0x00; + wmt_copy_back_read(mtd, command, column, page_addr); + return; + case COPY_BACK_2CYCLE: + info->isr_cmd = 0x85; + command = 0x85; + wmt_copy_back_write(mtd, command, column, page_addr); + return;*/ + + case 0x81: + case NAND_CMD_SEQIN: + case NAND_CMD_ERASE1: + /* printk(KERN_NOTICE "command is %x\n", command);*/ + if (column != -1) { + writeb(column, info->reg + NFCR3_COMPORT1_2); + addr_cycle++; + /*#ifndef PAGE_ADDR*/ + if (mtd->realwritesize != 512) { + writeb(column >> 8, (unsigned char *)(info->reg + NFCR3_COMPORT1_2) + 1); + addr_cycle++; + }/*#endif*/ + if (page_addr != -1) { + /*#ifndef PAGE_ADDR*/ + if (mtd->realwritesize != 512) { + writeb(page_addr, info->reg + NFCR4_COMPORT3_4); + page_addr >>= 8; + writeb(page_addr, (unsigned char *)(info->reg + NFCR4_COMPORT3_4) + 1); + addr_cycle += 2; + /*#else*/ + } else { + writeb(page_addr, (unsigned char *)(info->reg + NFCR3_COMPORT1_2) + 1); + page_addr >>= 8; + writeb(page_addr, info->reg + NFCR4_COMPORT3_4); + addr_cycle += 2; + } /*#endif*/ + + if (mtd->realwritesize == 2048) { + /* One more address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) { + page_addr >>= 8; + /*#ifndef PAGE_ADDR*/ + if (mtd->realwritesize != 512) + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + else /*#else*/ + writeb(page_addr, (unsigned char *)(info->reg + NFCR4_COMPORT3_4) + 1); + /*#endif*/ + addr_cycle++; + } + } else if (mtd->realwritesize == 4096) { + /* One more address cycle for devices > 256MiB */ + if (chip->chipsize > (256 << 20)) { + page_addr >>= 8; + /*#ifndef PAGE_ADDR*/ + if (mtd->realwritesize != 512) + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + else /*#else*/ + writeb(page_addr, (unsigned char *)(info->reg + NFCR4_COMPORT3_4) + 1); + /*#endif*/ + addr_cycle++; + } + } else if (mtd->realwritesize == 8192) { + /* One more address cycle for devices > 512MiB */ + if (chip->chipsize > (512 << 20)) { + page_addr >>= 8; + if (mtd->realwritesize != 512) + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + addr_cycle++; + } + } else if (mtd->realwritesize == 16384) { + /* One more address cycle for devices > 1024MiB */ + if (chip->chipsize > (1024 << 20)) { + page_addr >>= 8; + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + addr_cycle++; + } + } else { + /* One more address cycle for devices > 32MiB */ + if (chip->chipsize > (32 << 20)) { + page_addr >>= 8; + /*#ifndef PAGE_ADDR*/ + if (mtd->realwritesize != 512) + writeb(page_addr, info->reg + NFCR5_COMPORT5_6); + else /*#else*/ + writeb(page_addr, (unsigned char *)(info->reg + NFCR4_COMPORT3_4) + 1); + /*#endif*/ + addr_cycle++; + } + } + } + /*} else if (page_addr != -1) {*/ + } else if ((page_addr != -1) && (column == -1)) { + writeb(page_addr & 0xff, info->reg + NFCR3_COMPORT1_2); + page_addr >>= 8; + writeb(page_addr & 0xff, (unsigned char *)(info->reg + NFCR3_COMPORT1_2) + 1); + addr_cycle += 2; + + if (mtd->realwritesize == 2048) { + /* One more address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) { + page_addr >>= 8; + writeb(page_addr, info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } else if (mtd->realwritesize == 4096) { + /* One more address cycle for devices > 256MiB */ + if (chip->chipsize > (256 << 20)) { + page_addr >>= 8; + writeb(page_addr, info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } else if (mtd->realwritesize == 8192) { + /* One more address cycle for devices > 512MiB */ + if (chip->chipsize > (512 << 20)) { + page_addr >>= 8; + writeb(page_addr, info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } else if (mtd->realwritesize == 16384) { + /* One more address cycle for devices > 1024MiB */ + if (chip->chipsize > (1024 << 20)) { + page_addr >>= 8; + writeb(page_addr, info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } else { + /* One more address cycle for devices > 32MiB */ + if (chip->chipsize > (32 << 20)) { + page_addr >>= 8; + writeb(page_addr, info->reg + NFCR4_COMPORT3_4); + addr_cycle++; + } + } + } + + /* set command 1 cycle */ + writeb(command, info->reg + NFCR2_COMPORT0); + if (command == NAND_CMD_SEQIN || command == 0x81) { + wmb(); + info->done_data = &complete; + writew(((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + } else { + /* writeb(read(info->reg + NFCR12_NAND_TYPE_SEL) | WP_DISABLE , + info->reg + NFCR12_NAND_TYPE_SEL);*/ + writew(DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, + info->reg + NFCR1_COMCTRL); + } + wmb(); + + if (command == NAND_CMD_ERASE1) {//printk("erpg=0x%x\n", page_addr); + status = wmt_wait_cmd_ready(mtd); + /* status = wmt_nfc_ready(mtd); */ + if (status) + printk(KERN_ERR "command is not ready\n"); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + } else { + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + status = wmt_nfc_transfer_ready(mtd); + /*status = wmt_wait_dma_ready(mtd);*/ /*dannier mask*/ + wmt_wait_nfc_ready(info); + if (status) { + printk(KERN_ERR "dma transfer data is not ready: %x\n", + readb(info->reg + NFCRa_NFC_STAT)); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + /*printk(KERN_NOTICE "\rwait transfer data is not ready: %x\n", + readb(info->reg + NFCRa_NFC_STAT));*/ + /*print_nand_register(mtd);*/ + /* while (1);*/ + /* return;*/ + } + } + return; + + + case 0x11: + //printk("\n0x11 is here \n"); + writeb(command, info->reg + NFCR2_COMPORT0); + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + //writeb(0x1B, info->reg + NFCR13_INT_MASK); + info->done_data = &complete; + writew(DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|0x400, info->reg + NFCR1_COMCTRL); + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + //print_nand_register(mtd); + writeb(0x80, info->reg + NFCR13_INT_MASK); + status = wmt_wait_chip_ready(mtd); + if (status) + printk(KERN_NOTICE"The chip is not ready\n"); + status = wmt_nfc_wait_idle(mtd, 1, 1, -1, -1); /* write page, don't check ecc */ + if (status < 0) + printk(KERN_ERR "page multi plane err, nand controller is not idle\n"); + return; + + + case NAND_CMD_PAGEPROG: + /* case NAND_CMD_READSTART:*/ + case NAND_CMD_ERASE2: + case NAND_CMD_ERASE3: + /*printk(KERN_NOTICE "command is %x\n", command);*/ + writeb(command, info->reg + NFCR2_COMPORT0); + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + if (B2R&b2r_stat) { + printk(KERN_NOTICE"flash B2R status assert command=0x%x statu%x\n",command, b2r_stat); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + status = wmt_wait_chip_ready(mtd); /*Vincent 2008.11.3*/ + if (status) + printk(KERN_NOTICE"The chip is not ready\n"); + } + + if (NAND_CMD_ERASE2 == command || NAND_CMD_ERASE3 == command) { + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + writeb(0x1B, info->reg + NFCR13_INT_MASK); + } + info->done_data = &complete; + writew(DPAHSE_DISABLE|(1<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + + info->datalen = 0; + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + writeb(0x80, info->reg + NFCR13_INT_MASK); + #if 0 /* for debug */ + if (command == NAND_CMD_ERASE2 || NAND_CMD_ERASE3 == command) { + wmt_read_nand_status(mtd, NAND_CMD_STATUS); + if ((readb(info->reg + NFCR0_DATAPORT) & 0xff) == 0xc0) { + printk(KERN_NOTICE "wmt_func: erase block OK\n"); + printk(KERN_NOTICE "read nand status is %x\n", + readb(info->reg + NFCR0_DATAPORT) & 0xff); + } else + printk(KERN_NOTICE "wmt_func: erase block failed\n"); + } + #endif + + status = wmt_nfc_wait_idle(mtd, 1, 1, -1, -1); /* write page, don't check ecc */ + if (status < 0) { + printk(KERN_ERR "page program or erase err, nand controller is not idle\n"); + /*print_nand_register(mtd);*/ + /* while (1);*/ + #if 0 + status = wmt_read_nand_status(mtd, NAND_CMD_STATUS); + if (status < 0) + printk(KERN_NOTICE "\rNFC or NAND is not ready\n"); + else if (status & NAND_STATUS_FAIL) + printk(KERN_NOTICE "\r status : fail\n"); + else if (!(status & NAND_STATUS_READY)) + printk(KERN_NOTICE "\r status : busy\n"); + else if (!(status & NAND_STATUS_WP)) + printk(KERN_NOTICE "\r status : protect\n"); + #endif + return; + } + + return; + + case NAND_CMD_RESET_NO_STATUS_READ: + case NAND_CMD_HYNIX_RETRY_END: + + if (!chip->dev_ready) + break; + udelay(chip->chip_delay); + writeb(command, info->reg + NFCR2_COMPORT0); + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + writew(DPAHSE_DISABLE|(0x01<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_nand_ready(mtd); + if (status) { + printk(KERN_ERR "Reset err, nand device is not ready\n"); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + } + + return; + + case NAND_CMD_RESET: + + if (!chip->dev_ready) + break; + udelay(chip->chip_delay); + writeb(command, info->reg + NFCR2_COMPORT0); + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + writew(DPAHSE_DISABLE|(0x01<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + status = wmt_nand_ready(mtd); + if (status) { + b2r_stat = readb(info->reg + NFCR12_NAND_TYPE_SEL+1); + printk(KERN_ERR "Reset err, nand device chip %d is not ready\n", ((~b2r_stat)&0xFF)>>1); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + } + + wmt_read_nand_status(mtd, NAND_CMD_STATUS); + /* while (!(chip->read_byte(mtd) & NAND_STATUS_READY));*/ + i = 0; + while (!((readb(info->reg + NFCR0_DATAPORT) & 0xff) & NAND_STATUS_READY)) { + if (i>>12) { + printk("reset flash chip%d time out\n", ~readb(info->reg + NFCR12_NAND_TYPE_SEL+1)); + break; + } + i++; + } + + #ifdef NAND_DEBUG + printk(KERN_NOTICE "Reset status is ok\n"); + #endif + return; + + case NAND_CMD_READID: + + status = wmt_nand_readID(mtd); + #ifdef NAND_DEBUG + printk(KERN_NOTICE "readID status is %d\n", status); + #endif + return; + + case NAND_GET_FEATURE: + if (mtd->dwRdmz) + reset_nfc(mtd, NULL, 3); + status = nand_get_feature(mtd, 0x1); + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1);//enable rdmz + return; + + case NAND_CMD_STATUS: + + wmt_read_nand_status(mtd, command); + return; + + case NAND_CMD_STATUS_MULTI: + + wmt_read_nand_status(mtd, command); + return; + + case NAND_CMD_RNDIN: + if (column != -1) { + writeb(column, info->reg + NFCR3_COMPORT1_2); + addr_cycle++; + if (mtd->realwritesize != 512) { + writeb(column >> 8, (unsigned char *)(info->reg + NFCR3_COMPORT1_2) + 1); + addr_cycle++; + } + } + info->done_data = &complete; + /* set command 1 cycle */ + writeb(command, info->reg + NFCR2_COMPORT0); + + writew(((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + wait_for_completion_timeout(&complete, NFC_TIMEOUT_TIME); + status = wmt_nfc_wait_idle(mtd, 1, -1, -1, -1); /* don't check ecc, wait nfc idle */ + /* status = wmt_wait_cmd_ready(mtd);*/ + /* status = wmt_nfc_ready(mtd);*/ + if (status) + printk(KERN_ERR "Ramdom input err: nfc is not idle\n"); + + return; + + case NAND_CMD_RNDOUT: + + if (column != -1) { + writeb(column, info->reg + NFCR3_COMPORT1_2); + writeb(column, info->reg + NFCR3_COMPORT1_2 + 1); + addr_cycle += 2; + } + + /* CLEAR ECC BIT */ + //writeb(0x1B, info->reg + NFCR13_INT_MASK); + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + /* set command 1 cycle */ + writeb(command, info->reg + NFCR2_COMPORT0); + + writew(DPAHSE_DISABLE|((addr_cycle + 1)<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + + status = wmt_wait_cmd_ready(mtd); + /* status = wmt_nfc_ready(mtd);*/ + if (status) { + printk(KERN_ERR "Ramdom output err: nfc command is not ready\n"); + /* return;*/ + } + + writeb(NAND_CMD_RNDOUTSTART, info->reg + NFCR2_COMPORT0); + /* write to clear B2R */ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + writew(NAND2NFC|(1<<1)|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + + status = wmt_wait_cmd_ready(mtd); + /* status = wmt_nand_ready(mtd);*/ + if (status) { + printk(KERN_ERR "Ramdom output err: nfc io transfer is not finished\n"); + /* return;*/ + } + /* reduntant aera check ecc, wait nfc idle */ + status = wmt_nfc_wait_idle(mtd, 0, -1, -1, -1); + /* status = wmt_nand_wait_idle(mtd);*/ + if (status) + printk(KERN_ERR "Ramdom output err: nfc is not idle\n"); + return; + + + case NAND_CMD_STATUS_ERROR: + case NAND_CMD_STATUS_ERROR0: + udelay(chip->chip_delay); + return; + + + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + + /* trigger command and addrress cycle */ + + if (!chip->dev_ready) { + udelay(chip->chip_delay); + return; + } + } + /* Apply this short delay always to ensure that we do wait tWB in */ + /* any case on any machine.*/ + /* ndelay(100);*/ + wmt_device_ready(mtd); +} + + +static void wmt_nand_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int b2r_stat; + #ifdef NAND_DEBUG + printk(KERN_NOTICE "\r enter in wmt_nand_select_chip()\n"); + #endif + if (!((*(volatile unsigned long *)PMCEU_ADDR)&0x0010000)) + auto_pll_divisor(DEV_NAND, CLK_ENABLE, 0, 0); + if (chipnr > 1) + printk(KERN_WARNING "There are only support two chip sets\n"); + + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + if (chipnr == 1) + chipnr++; + else if (chipnr == 2) + chipnr--; + + if (chipnr >= 0 && chipnr < 4) + writeb(~(1<<chipnr), info->reg + NFCR12_NAND_TYPE_SEL+1); + else if (chipnr < 0) + writeb(~0, info->reg + NFCR12_NAND_TYPE_SEL+1); + else + printk(KERN_WARNING "There are only support two chip sets. chipnr = %d\n", chipnr); +} + +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 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; + } +} + + +static void wmt_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + #ifdef NAND_DEBUG + printk(KERN_NOTICE "enter in wmt_nand_write_buf()\n"); + #endif + //printk("info->dmabuf=%x datalen=%x \n", (unsigned int)info->dmabuf, info->datalen); + memcpy(info->dmabuf + info->datalen, buf, len); +//print_nand_buffer((uint8_t *)info->dmabuf, mtd->writesize); + info->datalen += len; +} + +static void wmt_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + #ifdef NAND_DEBUG + printk(KERN_NOTICE "enter in wmt_nand_read_buf() len: %x infoDatalen :%x\n", len, info->datalen); + #endif + + memcpy(buf, info->dmabuf + info->datalen, len); + info->datalen += len; +} + +static uint8_t wmt_read_byte(struct mtd_info *mtd) +{ + /* struct wmt_nand_mtd *nmtd = mtd->priv;*/ + /* struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd);*/ + uint8_t d; + #ifdef NAND_DEBUG + printk(KERN_NOTICE "enter in wmt_nand_read_byte()\n"); + #endif + + /* d = readb(info->reg + NFCR0_DATAPORT) & 0xff;*/ + wmt_nand_read_buf(mtd, &d, 1); + /* via_dev_dbg(&nmtd->info->platform->dev, "Read %02x\n", d);*/ + /* via_dev_dbg(info->platform->dev, "Read %02x\n", d);*/ + + return d; +} + +static int wmt_nand_read_oob_noalign(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + uint8_t *buf = chip->oob_poi; + uint8_t *bufpoi = buf; + + info->unc_bank = 0; + info->unc_allFF = 0; + + // read redundant area cmd + //printk(KERN_NOTICE "scan oob page=0x%x\n", page);dannier + info->oob_ecc_error = 0x0; + #if 0 + if (!mtd->dwDDR) { + writeb(readb(info->reg + NFCRd_OOB_CTRL) | OOB_READ, + info->reg + NFCRd_OOB_CTRL); + //writeb((info->oob_ECC_bytes+1), info->reg + NFCR10_OOB_ECC_SIZE+1); + if (info->ECC_mode != info->oob_ECC_mode) + set_ecc_engine(info, info->oob_ECC_mode); + //pos = info->oob_col/*+ i * (eccsize + chunk);*/ + //print_nand_register(mtd); + chip->cmdfunc(mtd, NAND_CMD_READOOB, info->oob_col, page); + if (info->ECC_mode != info->oob_ECC_mode) + set_ecc_engine(info, info->ECC_mode); + //writeb(info->oob_ECC_bytes, info->reg + NFCR10_OOB_ECC_SIZE+1); + writeb(readb(info->reg + NFCRd_OOB_CTRL) & (~OOB_READ), + info->reg + NFCRd_OOB_CTRL); + } else + #endif + { + info->data_ecc_uncor_err = 0; + info->oob_ecc_error = 0x50; + } + + if (mtd->dwRdmz) { + if (mtd->bbt_sw_rdmz) { + if ((RDMZ & readl(info->reg + NFCRf_CALC_RDMZ)) == RDMZ) + reset_nfc(mtd, NULL, 3); + } else + nfc_hw_rdmz(mtd, 1); + } + + if (info->data_ecc_uncor_err == 1 || info->oob_ecc_error == 0x50) { + if (info->data_ecc_uncor_err == 1) + printk(KERN_WARNING "**************page0x%x, read oob unc err goto read page\n", page); + info->isr_cmd = 0; + wmt_nand_page_read(mtd, 0, info->last_bank_col, page); + info->oob_ecc_error = 0; + } + + if (info->unc_allFF) { + set_FIFO_FF((uint32_t *)(chip->oob_poi), 6);//set_FIFO_FF((uint32_t *)(info->reg+ECC_FIFO_0), 4); + /*printk("oobRe=%x \n", page); + print_nand_buffer((char *)(info->reg+ECC_FIFO_0), 32); + print_nand_buffer((char *)(chip->oob_poi), 32); + printk("\n");*/ + } else { + memcpy(bufpoi, info->dmabuf + mtd->realwritesize, 24); + //print_nand_buffer((char *)(chip->oob_poi), 32); + //print_nand_buffer((char *)(info->dmabuf + mtd->realwritesize), 32); + /*if (!(*(uint32_t *)(info->reg+ECC_FIFO_0) == 0xFFFFFFFF && *(uint32_t *)(info->reg+ECC_FIFO_1) == 0xFFFFFFFF + && *(uint32_t *)(info->reg+ECC_FIFO_2) == 0xFFFFFFFF && *(uint32_t *)(info->reg+ECC_FIFO_3) == 0xFFFFFFFF + && *(uint32_t *)(info->reg+ECC_FIFO_4) == 0xFFFFFFFF && *(uint32_t *)(info->reg+ECC_FIFO_5) == 0xFFFFFFFF)) { + printk("fail to derdmz oob roob page= 0x%x e\n", page); + print_nand_buffer((char *)(info->reg+ECC_FIFO_0), 32); + //rdmzier_oob((uint8_t *)(info->reg+ECC_FIFO_0), (uint8_t *)(info->reg+ECC_FIFO_0), 5, page, mtd->realwritesize/4); + //print_nand_buffer((char *)(info->reg+ECC_FIFO_0), 32); + //while(1); + }*/ + } + + return 1; +} + +static int wmt_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + uint8_t *buf = chip->oob_poi; + /* int length = mtd->realoobsize; */ /* prepad = chip->ecc.prepad, bytes = chip->ecc.bytes;*/ + /* int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;*/ + /* int eccsize = chip->ecc.size;*/ + uint8_t *bufpoi = buf; + /* struct nand_oobfree *free = chip->ecc.layout->oobfree;*/ + /* uint32_t boffs;*/ + /* int pos; */ /* toread, sndrnd = 1;*/ + #ifdef WMT_SW_RDMZ + unsigned int rdmz_mark = 0; + #endif + + #ifdef NAND_DEBUG + printk(KERN_NOTICE "\r enter in wmt_nand_read_oob() page =0x%x cur_page=0x%x\n", page, info->cur_page); + #endif + + info->unc_bank = 0; + info->unc_allFF = 0; + + // read redundant area cmd + //printk(KERN_NOTICE "scan oob page=%d\n", page); + info->oob_ecc_error = 0x0; + #if 1 + if (!mtd->dwDDR) { + writeb(readb(info->reg + NFCRd_OOB_CTRL) | OOB_READ, + info->reg + NFCRd_OOB_CTRL); + //writeb((info->oob_ECC_bytes+1), info->reg + NFCR10_OOB_ECC_SIZE+1); + if (info->ECC_mode != info->oob_ECC_mode) + set_ecc_engine(info, info->oob_ECC_mode); + //pos = info->oob_col/*+ i * (eccsize + chunk);*/ + //print_nand_register(mtd); + chip->cmdfunc(mtd, NAND_CMD_READOOB, info->oob_col, page); + if (info->ECC_mode != info->oob_ECC_mode) + set_ecc_engine(info, info->ECC_mode); + //writeb(info->oob_ECC_bytes, info->reg + NFCR10_OOB_ECC_SIZE+1); + writeb(readb(info->reg + NFCRd_OOB_CTRL) & (~OOB_READ), + info->reg + NFCRd_OOB_CTRL); + } else + #endif + { + info->data_ecc_uncor_err = 0; + info->oob_ecc_error = 0x50; + } + + if (mtd->dwRdmz) { + if (mtd->bbt_sw_rdmz) { + if ((RDMZ & readl(info->reg + NFCRf_CALC_RDMZ)) == RDMZ) + reset_nfc(mtd, NULL, 3); + } else + nfc_hw_rdmz(mtd, 1); + } + + if (info->data_ecc_uncor_err == 1 || info->oob_ecc_error == 0x50) { + if (info->data_ecc_uncor_err == 1) + printk(KERN_WARNING "**************page0x%x, read oob unc err goto read page\n", page); + info->isr_cmd = 0; + writeb(readb(info->reg + NFCR9_ECC_BCH_CTRL) | 0x10, info->reg + NFCR9_ECC_BCH_CTRL); + wmt_nand_page_read(mtd, 0, info->last_bank_col, page); + writeb(readb(info->reg + NFCR9_ECC_BCH_CTRL) & 0xEF, info->reg + NFCR9_ECC_BCH_CTRL); + info->oob_ecc_error = 0; + } +//print_nand_buffer((char *)(info->reg+ECC_FIFO_0), 16); + #ifdef WMT_SW_RDMZ + rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)(info->reg+ECC_FIFO_5), 1, page, (mtd->realwritesize+20)/4); + //printk("re oob page=0x%x rdmz_mark=0x%x wmt_rdmz=0x%x fifo5=0x%x\n",page , rdmz_mark, *(unsigned int *)wmt_rdmz, *(unsigned int *)(info->reg+ECC_FIFO_5)); + if (mtd->dwRdmz == 1 && rdmz_mark == *(unsigned int *)wmt_rdmz) { + rdmzier_oob(bufpoi, (uint8_t *)(info->reg+ECC_FIFO_0), 5, page, mtd->realwritesize/4); + //print_nand_buffer(info->reg+ECC_FIFO_0, 24); + } else + #endif + if (info->unc_allFF) { + set_FIFO_FF((uint32_t *)(chip->oob_poi), 5);//set_FIFO_FF((uint32_t *)(info->reg+ECC_FIFO_0), 4); + /*printk("oobRe=%x \n", page); + print_nand_buffer((char *)(info->reg+ECC_FIFO_0), 32); + print_nand_buffer((char *)(chip->oob_poi), 32); + printk("\n");*/ + } else { + memcpy(bufpoi, info->reg+ECC_FIFO_0, 20); + /*if (!(*(uint32_t *)(info->reg+ECC_FIFO_0) == 0xFFFFFFFF && *(uint32_t *)(info->reg+ECC_FIFO_1) == 0xFFFFFFFF + && *(uint32_t *)(info->reg+ECC_FIFO_2) == 0xFFFFFFFF && *(uint32_t *)(info->reg+ECC_FIFO_3) == 0xFFFFFFFF + && *(uint32_t *)(info->reg+ECC_FIFO_4) == 0xFFFFFFFF && *(uint32_t *)(info->reg+ECC_FIFO_5) == 0xFFFFFFFF)) { + printk("fail to derdmz oob roob page= 0x%x e\n", page); + print_nand_buffer((char *)(info->reg+ECC_FIFO_0), 32); + //rdmzier_oob((uint8_t *)(info->reg+ECC_FIFO_0), (uint8_t *)(info->reg+ECC_FIFO_0), 5, page, mtd->realwritesize/4); + //print_nand_buffer((char *)(info->reg+ECC_FIFO_0), 32); + //while(1); + }*/ + } + /*chip->read_buf(mtd, bufpoi, 32);*/ + /*chip->read_buf(mtd, bufpoi + i * 16, 16);*/ + + return 1; +} + +static int wmt_nand_read_oob_single(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int ret = 0; + + info->cur_lpage = page; + info->cur_page = page; + + ret = cache_read_data(mtd, chip, page, NULL); + if (!ret) { + //printk("re oob lpg=0x%x from cache\n", page); + return 0; + } + ret = 0; + + if (page >= ((mtd->blkcnt - 8)*mtd->pagecnt)) + mtd->bbt_sw_rdmz = 1; + else + mtd->bbt_sw_rdmz = 0; +//printk("11oobRe=0x%x mtd->bbt_sw_rdmz=%d cur_page=0x%x\n", page, mtd->bbt_sw_rdmz, info->cur_page); + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) { + if (wmt_nand_read_oob_noalign(mtd, chip, page, sndcmd)) + ret = 1; + } else { + if (wmt_nand_read_oob(mtd, chip, page, sndcmd)) + ret = 1; + } + + return ret; +} + + +static int wmt_nand_read_oob_plane(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) +{ + //printk("\n wmt_nand_read_oob_plane \n"); + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + + int pagecnt = mtd->pagecnt; + int ret = 0; //printk("\n wmt_nand_read_oob_plane page=%x =>page=%x\n",page,(page / pagecnt) * pagecnt + page); + + info->cur_lpage = page; + ret = cache_read_data(mtd, chip, page, NULL); + if (!ret) { + //printk("re oob lpg=0x%x from cache\n", page); + return 0; + } + ret = 0; + + if (page >= ((mtd->blkcnt - 8)*mtd->pagecnt)) + mtd->bbt_sw_rdmz = 1; + else + mtd->bbt_sw_rdmz = 0; + + page = (page / pagecnt) * pagecnt + page; + + info->cur_page = page; + //printk("22oobRe=0x%x mtd->bbt_sw_rdmz=%d hold=%x blkcnt=%d\n", page, mtd->bbt_sw_rdmz, ((mtd->blkcnt - 8)*mtd->pagecnt), mtd->blkcnt); + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) { + if (wmt_nand_read_oob_noalign(mtd, chip, page, 1)) + ret = 1; + } else { + if (wmt_nand_read_oob(mtd, chip, page, 1)) + ret = 1; + } +/* info->oper_step = 1; + if(wmt_nand_read_oob(mtd, chip, page+div, 1))ret = 1; + //if(ret)printk("ret is 1! \n"); +*/ + return ret; +} + + + +/* + * wmt_nand_read_raw_page + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not + */ +static int wmt_nand_read_raw_page(struct mtd_info *mtd, struct nand_chip *chip, int page) +{ + unsigned int bch; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + + /*print_nand_register(mtd); + dump_stack();*/ + + bch = readb(info->reg + NFCR9_ECC_BCH_CTRL); + writeb((bch & (~BCH_INT_EN))| DIS_BCH_ECC, info->reg + NFCR9_ECC_BCH_CTRL); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + writeb(bch, info->reg + NFCR9_ECC_BCH_CTRL); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + + set_ecc_engine(info, info->ECC_mode); + + return 0; +} + + +/* - SCAN DEFAULT INVALID BAD BLOCK - + * wmt_nand_read_bb_oob - OOB data read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not + */ +static int wmt_nand_read_bb_oob(struct mtd_info *mtd, struct nand_chip *chip, +int page, int sndcmd) +{ + unsigned int bch, bak_time; + int i, size = 1024, ofs = mtd->realwritesize; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + #ifdef NAND_DEBUG + printk(KERN_NOTICE "enter in wmt_nand_read_bb_oob() page=0x%x\n", page); + #endif + bch = readb(info->reg + NFCR9_ECC_BCH_CTRL); + writeb((bch & (~BCH_INT_EN))| DIS_BCH_ECC, info->reg + NFCR9_ECC_BCH_CTRL); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + bak_time = readl(info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + if (!mtd->dwDDR) + writel(0x2424, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) { + ofs = ofs + 2048; + } + + if (sndcmd) { + if ((0xFF&(mtd->id>>24)) == 0x45) { + for (i = 0; i < ((ofs/1024)+1); i++) { + chip->cmdfunc(mtd, NAND_CMD_READ0, i*1024, page); + info->datalen = 0; + if (i == (ofs/1024)) + size = (mtd->realoobsize >= 1024) ? 1024 : mtd->realoobsize; + chip->read_buf(mtd, chip->oob_poi - ofs + (i*1024), size); + } + } else if (mtd->id == 0xECDED57E && mtd->id2 == 0x68440000) { + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + info->datalen = 0; + chip->read_buf(mtd, chip->oob_poi, 1); + chip->cmdfunc(mtd, NAND_CMD_READ0, ofs, page); + info->datalen = 0; + chip->read_buf(mtd, chip->oob_poi+1, 63); + } else { + chip->cmdfunc(mtd, NAND_CMD_READ0, ofs, page); + info->datalen = 0; + chip->read_buf(mtd, chip->oob_poi, 64); + } + sndcmd = 0; + } + if (!mtd->dwDDR) + writel(bak_time, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + writeb(bch, info->reg + NFCR9_ECC_BCH_CTRL); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + + set_ecc_engine(info, info->ECC_mode); + + return sndcmd; +} + +/* - SCAN DEFAULT INVALID BAD BLOCK - + * wmt_nand_read_bb_oob_multi - OOB data read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not + */ +static int wmt_nand_read_bb_oob_multi(struct mtd_info *mtd, struct nand_chip *chip, +int page, int sndcmd) +{ + unsigned int bch, bak_time; + int i, size = 1024, plane, ofs = mtd->realwritesize; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + #ifdef NAND_DEBUG + printk(KERN_NOTICE "enter in wmt_nand_read_bb_oob() page=0x%x\n", page); + #endif + bch = readb(info->reg + NFCR9_ECC_BCH_CTRL); + writeb((bch & (~BCH_INT_EN))| DIS_BCH_ECC, info->reg + NFCR9_ECC_BCH_CTRL); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + bak_time = readl(info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + if (!mtd->dwDDR) + writel(0x2424, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) { + ofs = ofs + 2048; + } + + if (sndcmd) { + if ((0xFF&(mtd->id>>24)) == 0x45) { + plane = (info->oper_step ? (ofs-1024) : mtd->writesize); + for (i = 0; i < ((ofs/1024)+1); i++) { + chip->cmdfunc(mtd, NAND_CMD_READ0, i*1024, page); + info->datalen = 0; + if (i == (ofs/1024)) + size = (mtd->realoobsize >= 1024) ? 1024 : mtd->realoobsize; + chip->read_buf(mtd, chip->oob_poi - plane + (i*1024), size); + } + } else if (mtd->id == 0xECDED57E && mtd->id2 == 0x68440000) { + plane = (info->oper_step ? 32 : 0); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + info->datalen = 0; + chip->read_buf(mtd, chip->oob_poi+plane, 1); + chip->cmdfunc(mtd, NAND_CMD_READ0, ofs, page); + info->datalen = 0; + chip->read_buf(mtd, chip->oob_poi+1+plane, 31); + } else { + chip->cmdfunc(mtd, NAND_CMD_READ0, ofs, page); + info->datalen = 0; + plane = (info->oper_step ? 32 : 0); + chip->read_buf(mtd, chip->oob_poi+plane, 32); + } + sndcmd = 0; + } + if (!mtd->dwDDR) + writel(bak_time, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + writeb(bch, info->reg + NFCR9_ECC_BCH_CTRL); + writeb(READ_RESUME, info->reg + NFCR9_ECC_BCH_CTRL + 1); + + set_ecc_engine(info, info->ECC_mode); + + return sndcmd; +} + +static int wmt_nand_read_bb_oob_plane(struct mtd_info *mtd, struct nand_chip *chip, +int page, int sndcmd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int div = mtd->erasesize / mtd->writesize; + int ret = 0; + page = (page / div) * div + page; + info->oper_step = 0; + if (wmt_nand_read_bb_oob_multi(mtd, chip, page,sndcmd)) + ret = 1; + info->oper_step = 1; + if(wmt_nand_read_bb_oob_multi(mtd, chip, page+div,sndcmd)) + ret = 1; + info->oper_step = 0; + return ret; +} + + +/* write oob is no longer support */ +static int wmt_nand_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + /*int i;*/ + unsigned int b2r_stat; + /*int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;*/ + int eccsize = chip->ecc.size; /* length = mtd->realoobsize; */ + /* prepad = chip->ecc.prepad, bytes = chip->ecc.bytes;*/ + + int pos, status = 0; + /*int steps = chip->ecc.steps;*/ /* Vincent 2008.11.4*/ + const uint8_t *bufpoi = chip->oob_poi; + /* struct nand_oobfree *free = chip->ecc.layout->oobfree;*/ + /* uint32_t boffs;*/ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "\r enter in wmt_nand_write_oob()\n"); + #endif + + + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + info->datalen = 0; + /*chip->write_buf(mtd, bufpoi, 32);*/ + memcpy(info->reg+ECC_FIFO_0, bufpoi, 32); + pos = eccsize * chip->ecc.steps + 8*4; + /*pos = eccsize + i * (eccsize + chunk);*/ + /*wmt_nfc_dma_cfg(mtd, 32, 1, 1, i);*/ + chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + /* printk(KERN_NOTICE "\r in wmt_nand_write_oob_new(): waitfunc_1\n");*/ + status = chip->waitfunc(mtd, chip); + /* printk(KERN_NOTICE "\r in wmt_nand_write_oob_new(): waitfunc_2\n");*/ + if (status & NAND_STATUS_FAIL) + return -EIO; + /* } */ + return 0; + +} + +static int wmt_nand_write_oob_plane(struct mtd_info *mtd, struct nand_chip *chip, int page) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + uint8_t *bufpoi = chip->oob_poi; + /*int i;*/ + unsigned int b2r_stat; + /*int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;*/ + int eccsize = chip->ecc.size; /* length = mtd->realoobsize; */ + /* prepad = chip->ecc.prepad, bytes = chip->ecc.bytes;*/ + + int pos, status = 0; + /*int steps = chip->ecc.steps;*/ /* Vincent 2008.11.4*/ + + int div = mtd->erasesize / mtd->writesize; + + page = (page / div) *div + page; + + // if(info->oper_step) bufpoi = chip->oob_poi + mtd->realoobsize; + /* struct nand_oobfree *free = chip->ecc.layout->oobfree;*/ + /* uint32_t boffs;*/ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "\r enter in wmt_nand_write_oob()\n"); + #endif + /* + * data-ecc-data-ecc ... ecc-oob + * or + * 512 7 1 5 0 3 + * data-ecc-prepad-data-pad-oobecc .... + */ + + /* for (i = 0; i < steps; i++) {*/ + /*for (i = 0; i < 4; i++) {*/ + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + + info->datalen = 0; + memcpy(info->reg+ECC_FIFO_0, bufpoi, 32); + pos = eccsize * chip->ecc.steps + 8*4; + /*pos = eccsize + i * (eccsize + chunk);*/ + /*wmt_nfc_dma_cfg(mtd, 32, 1, 1, i);*/ + chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); + + chip->cmdfunc(mtd, 0x11, -1, -1); + + memcpy(info->reg+ECC_FIFO_0, bufpoi + mtd->realoobsize, 32); + + chip->cmdfunc(mtd, 0x81, pos, page + div); + + chip->cmdfunc(mtd, 0x10, -1, -1); + /* printk(KERN_NOTICE "\r in wmt_nand_write_oob_new(): waitfunc_1\n");*/ + status = chip->waitfunc(mtd, chip); + /* printk(KERN_NOTICE "\r in wmt_nand_write_oob_new(): waitfunc_2\n");*/ + if (status & NAND_STATUS_FAIL) + return -EIO; + /* } */ + + return 0; +} + +static void wmt_single_plane_erase(struct mtd_info *mtd, int page) +{ + struct nand_chip *chip = mtd->priv; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i; +#if 0 + /* Send commands to erase a block */ + if (chip->cur_chip && (chip->cur_chip->nand_id>>24) == NAND_MFR_HYNIX && prob_end == 1) { + if (page < par3_ofs || (page >= par6_ofs && page < par7_ofs)) { + //printk("SKIP erase page 0x%x, par4_ofs 0x%x\n", page, par4_ofs); + return; + } + } // nand_base.c nand_erase_nand +#endif + for (i = 0; i < WR_BUF_CNT; i++) + if (page <= info->wr_page[i] && (page+mtd->pagecnt) > info->wr_page[i]) + info->wr_page[i] = -1; + info->cur_page = page; + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); +} + +static void wmt_multi_plane_erase(struct mtd_info *mtd, int page) +{ + struct nand_chip *chip = mtd->priv; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i, pagecnt = mtd->pagecnt, page_plane1; + //if (((page/pagecnt) * pagecnt + page) != (page<<1) - (page%pagecnt)) + //printk("erase page %d => page1=%d page2=%d\n", page, (page/pagecnt) * pagecnt + page, (page<<1) - (page%pagecnt)); + + for (i = 0; i < WR_BUF_CNT; i++) + if (page <= info->wr_page[i] && (page+mtd->pagecnt) > info->wr_page[i]) + info->wr_page[i] = -1; + + /*if (chip->cur_chip && (chip->cur_chip->nand_id>>24) == NAND_MFR_HYNIX && prob_end == 1) { + if (page < par3_ofs || (page >= par5_ofs && page < par7_ofs)) { + printk("SKIP erase page 0x%x, par4_ofs 0x%x\n", page, par3_ofs); + //while(1); + return; + } + }*/ + page = (page / pagecnt) * pagecnt + page; + page_plane1 = page + pagecnt; + //printk("multi erase page %x => page1=%x page2=%x, pagepl1=%x\n", page, (page/pagecnt) * pagecnt + page, (page<<1) - (page%pagecnt), page_plane1); + //printk("blk=%d, blk1=%d\n", page/mtd->pagecnt, page_plane1/mtd->pagecnt); + + info->cur_page = page; +// chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);//simulate +// chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); //simulate +// chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page+div); //simulate +// chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); //simulate +/*******************************************************************************/ + if ((0xFF&(mtd->id>>24)) == NAND_MFR_MICRON || (0xFF&(mtd->id>>24)) == NAND_MFR_INTEL) { + //printk(KERN_NOTICE"multi erase0 command=0x%x \n",NAND_CMD_ERASE1); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + //printk(KERN_NOTICE"multi erase1 command=0x%x \n",NAND_CMD_ERASE3); + chip->cmdfunc(mtd, NAND_CMD_ERASE3, -1, -1); /* send cmd 0xd0 */ + //printk(KERN_NOTICE"multi erase1 command=0x%x \n",NAND_CMD_ERASE1); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page_plane1); + //printk(KERN_NOTICE"multi erase2 command=0x%x \n",NAND_CMD_ERASE2); + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ + } else { + //printk(KERN_NOTICE"multi erase0 command=0x%x \n",NAND_CMD_ERASE1); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + //printk(KERN_NOTICE"multi erase1 command=0x%x \n",NAND_CMD_ERASE1); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page_plane1); + //printk(KERN_NOTICE"multi erase2 command=0x%x \n",NAND_CMD_ERASE2); + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); /* send cmd 0xd0 */ + } +/*******************************************************************************/ +} + + +#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 *)kmalloc((parity_len) * sizeof(unsigned int), GFP_KERNEL); + if (p == NULL) { + printk("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]); + kfree(p); //release malloc + } + return 0; +} +#endif //faster encode function + +#if 0 //old fast encode function + +unsigned int reverse32 (unsigned int n) +{ + int i=0; + unsigned int tmp = n, y=0; + for(;i<31;i++) { + 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--) printk("%8x",pariA[i]);printk("\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 *)kmalloc((pari_len+2) * sizeof(unsigned int), GFP_KERNEL); + if (p == NULL) { + printk("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; + } + } + //printk("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; + //printk("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 = p3; + */ + //printk("p2=0x%x p3=0x%x\n", (unsigned int)p2, (unsigned int)p3); + for(i=0;i<=pari_len;i++) { + p_parity[pari_len-i] = reverse32(p1[i]); + } + /*reverse oder of parity end*/ + //printk("reverse finiah!\n"); + kfree(p); //release malloc + } + //printk("leave encode\n"); + return 0; +} +#endif //old fast encode function + +#if 0 //slow encode function +int encode_ecc(unsigned char *src_data, unsigned char *parity, unsigned int ecc_bit, unsigned char *c_len, unsigned int encode_len) +{ + //unsigned char src_data[512];//24 + //unsigned char parity[26];//42 + //unsigned char ecc_bit; + unsigned char c_len1 = *c_len; + unsigned int fail; + + //char in_char; + int i; + //int j,in_v; + + + + //for (i=0; i<encode_len; i++) src_data[i] = 0x00; + // for (i = 0; i < encode_len; i += 2) { + // src_data[i] = 0xFF&(jj>>8); + // src_data[i+1] = 0xFF&jj; + // jj++; + // jj %= 0x10000; + // src_data[i] = 0x12; + // src_data[i+1] = 0x12; + // } +/* + i = 0; j = 0; + in_char = getchar(); + while (in_char != EOF) { + in_v = hextoint(in_char); + if (in_v != -1) { + if (j==0) { + src_data[i] = 0; + src_data[i] += in_v * 16; + j++; + } else { + src_data[i] += in_v; + i++; + j = 0; + } + } + in_char = getchar(); + }*/ + //printk("start encode\n"); + fail = wmt_bchencoder(src_data,parity,ecc_bit,&c_len1, encode_len); + if (fail) + printk("----------------Encode Error Detected! code=%d-----------------\n",fail); + else + *c_len = c_len1; + /*printk("\nCodeLengh=%d %d Parity=",*c_len, c_len1); + for (i=(c_len1-1); i>=0; i--) + printk("%02x ",parity[i]); + printk("\n");*/ + + return 0; +} + +int hextoint(char hex) +// Convert HEX number to Integer +{ + int r, h; + r = -1; + h = (int)hex; + if ((h >= 97) && (h <= 102)) + r = h - 87; + else if ((h >= 65) && (h <= 70)) + r = h - 55; + else if ((h >= 48) && (h <= 57)) + r = h - 48; + else if ((h != 10) && (h != 13)) + printk("Error detected!!! hex=%c",hex); + return r; +} + + +// This function is used to encode the BCH code for the input data +// data : [IN] The information data to be encoded by BCH. The lendth of this buffer is fixed at 512Bytes. +// bch_code : [OUT] Buffer pointer to keep the BCH code. +// bits : [IN] The number of bits for the BCH error correcting capability. +// bch_codelen : [IN/OUT] This parameter is used to specify the length of the buffer bch_code in unit of byte for input for the +// encoder. And will specify the length of encoded bch for the data with error correcting capability bits as output. +// RETURN : 0 indicates success. Nonzero indicates failure. +unsigned int wmt_bchencoder (unsigned char *data, unsigned char *bch_code, unsigned char bits, unsigned char *bch_codelen, unsigned int encode_len) +{ + unsigned char bch_codelen_in; + unsigned char bch_i; + /*unsigned char b_data[MAX_BANK_SIZE*8]; + unsigned char bch_sera[MAX_PARITY_SIZE*8]; + unsigned char bch_sera_tmp[MAX_PARITY_SIZE*8];*/ + unsigned char bch_sera_back; + unsigned int width; + unsigned int i,j,k; + unsigned long retval; + unsigned char offset; + + unsigned char *bch_GF2; + /*unsigned char bch_GF_4becc[MAX_PARITY_SIZE*8] = {0,1,0,0,0,1,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,1,1,1,0,1,0,1,0,1,1,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char bch_GF_8becc[MAX_PARITY_SIZE*8] = {0,0,0,1,0,1,0,1,1,1,1,1,1,0,0,1,0,0,0,1,0,1,0,0,1,1,1,0,0,0,0,0,0,1,1,1,1,0,1,1,0,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,1,1,1,0,1,0,0,0,0,0,1,1,1,0,0,0,1,0,1,1,1,0,0,0,1,0,0,1,1,1,1,1,0,1,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char bch_GF_12becc[MAX_PARITY_SIZE*8] = {1,1,1,0,0,1,0,0,1,0,0,0,0,1,1,1,0,0,1,1,0,0,1,0,0,1,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,1,1,0,1,0,0,1,0,1,0,1,1,0,0,1,1,1,1,0,0,0,0,1,0,0,1,0,1,0,0,1,1,0,1,0,0,1,0,1,0,0,0,0,0,0,1,0,1,0,0,1,0,0,1,1,0,0,0,1,1,0,1,1,1,0,0,1,1,0,1,1,0,1,0,1,1,1,1,1,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,1,1,1,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char bch_GF_16becc[MAX_PARITY_SIZE*8] = {1,1,0,0,1,0,1,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,1,0,0,0,0,1,1,0,1,1,0,1,1,1,1,1,0,1,1,0,0,0,1,0,1,0,1,1,0,0,0,1,1,1,0,1,1,0,1,0,1,1,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,0,1,0,1,0,0,1,0,0,0,1,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,0,0,0,1,0,1,0,0,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,1,1,0,1,1,1,0,1,0,0,0,0,1,1,1,1,1,1,0,1,1,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char bch_GF_24becc[MAX_PARITY_SIZE*8] = {1,0,0,0,1,1,1,0,1,0,0,1,0,1,0,0,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,1,0,1,1,0,0,1,0,0,0,0,1,0,0,1,1,1,0,1,0,0,1,0,1,0,1,1,0,1,0,0,0,1,0,1,0,0,1,0,0,1,0,1,0,1,1,1,0,0,1,0,1,1,0,1,0,0,0,1,1,1,1,0,1,1,0,1,1,1,0,1,1,0,0,1,1,1,0,1,0,0,0,0,1,0,0,1,1,0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,1,0,0,0,0,1,1,1,0,1,0,0,0,1,1,1,0,1,0,0,0,1,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,1,0,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,1,1,1,0,1,0,0,0,1,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,1,1,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,0,1,1,0,1,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,1,0,0,1,1,0,0,1,0,0,1,0,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + unsigned char bch_GF_40becc[MAX_PARITY_SIZE*8] = {1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,1,0,0,1,1,0,1,1,0,0,0,1,1,0,1,0,0,0,0,0,1,1,0,1,1,1,0,0,0,1,0,1,1,1,0,1,1,0,0,1,0,1,1,0,0,1,1,0,0,0,0,1,1,0,0,1,1,1,1,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,0,0,0,1,0,0,1,0,0,1,0,1,1,0,0,1,1,1,0,1,0,1,0,1,0,0,1,1,1,1,0,1,1,0,1,1,0,1,1,1,1,0,1,0,0,1,1,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,0,0,1,1,1,1,1,1,0,1,0,1,0,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,0,0,0,1,0,1,0,0,1,1,1,0,1,1,1,1,1,0,1,1,0,0,0,0,1,1,1,1,1,1,0,1,0,1,0,1,0,0,1,1,1,0,0,1,1,0,0,1,0,0,0,1,0,1,0,1,1,0,1,0,1,0,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,1,0,0,1,0,1,0,1,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,0,0,1,1,0,0,1,1,1,0,0,0,1,0,1,0,0,1,0,1,1,0,0,1,1,1,1,0,1,1,0,0,0,1,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,1,0,1,1,1,1,1,1,1,0,0,0,1,0,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,0,1,1,1,0,1,1,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,1,0,1,1,1,1,1,0,0,1,1,0,0,0,1,0,1,0,0,1,1,0,1,1,0,1,0,0,1,0,1,0,0,0,0,0,1,1,1,0,1,1,0,0,0,1,0,1,0,1,1,0,1,1,1,0,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,1,1,1,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,1,1,1,0,0,0,0,0,1};*/ + + // initialization + retval = 0; + for(i=0; i<MAX_PARITY_SIZE*8; i++) { + bch_sera[i] = 0; + bch_sera_tmp[i] = 0; + } + + for (i=0; i <=(encode_len*8); i++) { + if ((unsigned char)((unsigned int)(1<<(i%8))) & data[i/8]) + b_data[i] = 1; + else + b_data[i] = 0; + } + + // select width and poly-nominal + switch (bits) { + case 4 : width = 51; bch_GF2 = bch_GF_4becc; break; + case 8 : width = 103; bch_GF2 = bch_GF_8becc; break; + case 12 : width = 155; bch_GF2 = bch_GF_12becc; break; + case 16 : width = 207; bch_GF2 = bch_GF_16becc; break; + case 24 : width = 335; bch_GF2 = bch_GF_24becc; break; + case 40 : width = 559; bch_GF2 = bch_GF_40becc; break; + default : width = 51; bch_GF2 = bch_GF_4becc; retval += 1; break; + } + + // calculate the parity + for (k=0; k<(encode_len*8); k++) { + bch_i = b_data[k]; + bch_sera_back = bch_sera[width] ^ bch_i; + bch_sera_tmp[0] = bch_sera_back; + for (i=0; i<width; i++) { + bch_sera_tmp[i+1] = bch_sera[i] ^ (bch_sera_back * bch_GF2[width-(i+1)]); + } + for (i=0; i<=width; i++) + bch_sera[i] = bch_sera_tmp[i]; + } + + i = 0; + bch_code[0] = 0; + bch_codelen_in = *bch_codelen; + if(bits == 4 || bits == 12) + offset = 4; + else + offset = 0; + for (j = 0; j <= width; j++) { + *bch_codelen = i+1; + bch_code[i] += bch_sera[j] * (unsigned char)((unsigned int)(1<<(7-((j+offset)%8)))); + if (i>=bch_codelen_in) { + retval += 2; + break; + } + if((j+offset)%8==7) { + i++; + bch_code[i] = 0; + } + } + + return(retval); +} +#endif //end of #if 0 : slow encode function + +/** + * wmt_nand_read_page - hardware ecc syndrom based page read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * + * The hw generator calculates the error syndrome automatically. Therefor + * we need a special oob layout and handling. + */ +static int wmt_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + uint8_t *bufpoi = chip->oob_poi; + + //#ifdef WMT_SW_RDMZ + unsigned int rdmz_mark = 0;//,g1=0,g2=0,g3=0; + //#endif + #ifdef NAND_DEBUG + printk(KERN_NOTICE "\r enter in wmt_nand_read_page()page=0x%x\n", page); + #endif + if (info->oper_step) + bufpoi = chip->oob_poi+20;//bufpoi = chip->oob_poi+mtd->realoobsize; +//g1 = wmt_read_oscr(); + info->datalen = 0; + if (info->unc_allFF && !mtd->bbt_sw_rdmz) { + set_FIFO_FF((uint32_t *)buf, mtd->realwritesize/4); + } else + chip->read_buf(mtd, buf, mtd->realwritesize); +//g2 = wmt_read_oscr(); + if (chip->cur_chip && prob_end == 1 && + (chip->cur_chip->nand_id>>24) == NAND_MFR_HYNIX) { + if (!chip->realplanenum) + if (page < par4_ofs && second_chip == 0) { + #ifdef ESLC_DEBUG + if (page%mtd->pagecnt == 0 || page%mtd->pagecnt == (mtd->pagecnt/2)) + printk("\nread: \n"); + #endif + page = hynix_eslc_page_address_calculate(mtd, chip, page); + if (page < 0) + return 0; + } + } + /*if (page == 0xaa00) { + print_nand_buffer((uint8_t *)(info->reg+ECC_FIFO_0), 24); + rdmzier_oob((uint8_t *)bufpoi, (uint8_t *)(info->reg+ECC_FIFO_0), 6, info->cur_page, mtd->realwritesize/4); + print_nand_buffer((uint8_t *)bufpoi, 24); + }*/ + /*if (info->cur_page != page) { + printk("cur_page=%x, page=%x\n", info->cur_page, page); + while(1); + }*/ + //#ifdef WMT_SW_RDMZ + if (mtd->dwRdmz == 1 && mtd->bbt_sw_rdmz) { + //printk("check read page derdmz page= 0x%x\n", page); + rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)(info->reg+ECC_FIFO_5), 1, page, (mtd->realwritesize+20)/4); + if ((*(unsigned int *)(info->reg+ECC_FIFO_5)) == (*(unsigned int *)wmt_rdmz) || + rdmz_mark == (*(unsigned int *)wmt_rdmz)) { + //printk("read page derdmz page= 0x%x\n", page); + rdmzier(buf, mtd->realwritesize/4, page); + } + } + //#endif + + writeb(readb(info->reg + NFCRd_OOB_CTRL) & 0xF7, info->reg + NFCRd_OOB_CTRL); + + //printk("re page=0x%x rdmz_mark=0x%x wmt_rdmz=0x%x fifo5=0x%x\n",page , rdmz_mark, *(unsigned int *)wmt_rdmz, *(unsigned int *)(info->reg+ECC_FIFO_5)); + if (mtd->dwRdmz == 1 && rdmz_mark == *(unsigned int *)wmt_rdmz && mtd->bbt_sw_rdmz) { + //print_nand_buffer((uint8_t *)(info->reg+ECC_FIFO_0), 24); + rdmzier_oob((uint8_t *)bufpoi, (uint8_t *)(info->reg+ECC_FIFO_0), 5/*20/4*/, page, mtd->realwritesize/4); + //print_nand_buffer((uint8_t *)bufpoi, 24); + } else if (info->unc_allFF) { + set_FIFO_FF((uint32_t *)(bufpoi), 4); + } else + memcpy(bufpoi, info->reg+ECC_FIFO_0, 20); + /*print_nand_buffer((char *)(chip->oob_poi), 32); + print_nand_buffer((char *)(buf), 16); + printk("info->unc_bank=%x golden=%x\n", info->unc_bank, ((1<<info->banks)-1));*/ + /*if (*(uint32_t *)(info->reg+ECC_FIFO_0) != 0xFFFFFFFF) { + printk(KERN_NOTICE "rd PID:%d Comm:%s sqNum=0x%x, objId=0x%x, lgcAdr=0x%x Byte=0x%x page=0x%x\n", + current->pid, current->comm, *(uint32_t *)(info->reg+ECC_FIFO_0), + *(uint32_t *)(info->reg+ECC_FIFO_1), *(uint32_t *)(info->reg+ECC_FIFO_2), + *(uint32_t *)(info->reg+ECC_FIFO_3), info->cur_page); + printk("info->unc_bank=%x golden=%x\n", info->unc_bank, ((1<<info->banks)-1)); + }*/ +//g3 = wmt_read_oscr(); + //printk(KERN_DEBUG"g12=%d,g23=%d\n",(g2-g1)/3,(g3-g1)/3); + return 0; +} + +/** + * wmt_nand_read_page - hardware ecc syndrom based page read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * + * The hw generator calculates the error syndrome automatically. Therefor + * we need a special oob layout and handling. + */ +static int wmt_nand_read_page_noalign(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + uint8_t *bufpoi = chip->oob_poi; + + unsigned int rdmz_mark = 0; + + if (info->oper_step) + bufpoi = chip->oob_poi+20; + + info->datalen = 0; + if (info->unc_allFF && !mtd->bbt_sw_rdmz) { + set_FIFO_FF((uint32_t *)buf, mtd->realwritesize/4); + } else + chip->read_buf(mtd, buf, mtd->realwritesize); + + if (chip->cur_chip && prob_end == 1 && + (chip->cur_chip->nand_id>>24) == NAND_MFR_HYNIX) { + if (!chip->realplanenum) + if (page < par4_ofs && second_chip == 0) { + #ifdef ESLC_DEBUG + if (page%mtd->pagecnt == 0 || page%mtd->pagecnt == (mtd->pagecnt/2)) + printk("\nread: \n"); + #endif + page = hynix_eslc_page_address_calculate(mtd, chip, page); + if (page < 0) + return 0; + } + } + + if (mtd->dwRdmz == 1 && mtd->bbt_sw_rdmz) { + //printk("check read page derdmz page= 0x%x\n", page); + rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)(info->dmabuf + mtd->realwritesize + 20), 1, page, (mtd->realwritesize+20)/4); + if ((*(unsigned int *)(info->dmabuf + mtd->realwritesize + 20)) == (*(unsigned int *)wmt_rdmz) || + rdmz_mark == (*(unsigned int *)wmt_rdmz)) { + //printk("read page derdmz page= 0x%x\n", page); + rdmzier(buf, mtd->realwritesize/4, page); + } + } + + + writeb(readb(info->reg + NFCRd_OOB_CTRL) & 0xF7, info->reg + NFCRd_OOB_CTRL); + + if (mtd->dwRdmz == 1 && rdmz_mark == *(unsigned int *)wmt_rdmz && mtd->bbt_sw_rdmz) { + //print_nand_buffer((uint8_t *)(info->dmabuf + mtd->realwritesize), 24); + rdmzier_oob((uint8_t *)bufpoi, (uint8_t *)(info->dmabuf + mtd->realwritesize /*+ 20*/), 5, page, mtd->realwritesize/4); + //print_nand_buffer((uint8_t *)bufpoi, 24); + } else if (info->unc_allFF) { + set_FIFO_FF((uint32_t *)(bufpoi), 6); + } else + memcpy(bufpoi, info->dmabuf + mtd->realwritesize, 20); + //print_nand_buffer((char *)(chip->oob_poi), 32); + /*print_nand_buffer((char *)(buf), 16); + printk("info->unc_bank=%x golden=%x\n", info->unc_bank, ((1<<info->banks)-1));*/ + + /*if (*(uint32_t *)(info->reg+ECC_FIFO_0) != 0xFFFFFFFF) { + printk(KERN_NOTICE "rd PID:%d Comm:%s sqNum=0x%x, objId=0x%x, lgcAdr=0x%x Byte=0x%x page=0x%x\n", + current->pid, current->comm, *(uint32_t *)(info->reg+ECC_FIFO_0), + *(uint32_t *)(info->reg+ECC_FIFO_1), *(uint32_t *)(info->reg+ECC_FIFO_2), + *(uint32_t *)(info->reg+ECC_FIFO_3), info->cur_page); + printk("info->unc_bank=%x golden=%x\n", info->unc_bank, ((1<<info->banks)-1)); + }*/ + /*if (info->dmabuf[0] == 1) + printk( "R%x:%x ", page, *(uint32_t *)info->dmabuf);*/ +/*printk(KERN_DEBUG "RPG=0x%x : 0x%x 0x%x 0x%x 0x%x\n", page, *(uint32_t *)info->dmabuf, +*((uint32_t *)info->dmabuf+1), *((uint32_t *)info->dmabuf+2), *((uint32_t *)info->dmabuf+3));*/ + return 0; +} + +#if 0 +static int wmt_nand_cp_data(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int rdmz_mark = 0; + + info->datalen = 0; + if (info->unc_allFF && !mtd->bbt_sw_rdmz) { + set_FIFO_FF((uint32_t *)buf, mtd->realwritesize/4); + } else + chip->read_buf(mtd, buf, mtd->realwritesize); + + if (mtd->dwRdmz == 1 && mtd->bbt_sw_rdmz) { + rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)(info->reg+ECC_FIFO_5), 1, page, (mtd->realwritesize+20)/4); + if ((*(unsigned int *)(info->reg+ECC_FIFO_5)) == (*(unsigned int *)wmt_rdmz) || + rdmz_mark == (*(unsigned int *)wmt_rdmz)) { + rdmzier(buf, mtd->realwritesize/4, page); + } + } + return 0; +} + +static int wmt_nand_cp_oob(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + uint8_t *bufpoi = chip->oob_poi; + unsigned int rdmz_mark = 0; + + if (mtd->dwRdmz == 1 && mtd->bbt_sw_rdmz) + rdmzier_oob((uint8_t *)&rdmz_mark, (uint8_t *)(info->reg+ECC_FIFO_5), 1, page, (mtd->realwritesize+20)/4); + + if (mtd->dwRdmz == 1 && rdmz_mark == *(unsigned int *)wmt_rdmz && mtd->bbt_sw_rdmz) { + rdmzier_oob((uint8_t *)bufpoi, (uint8_t *)(info->reg+ECC_FIFO_0), 5, page, mtd->realwritesize/4); + } else if (info->unc_allFF) { + set_FIFO_FF((uint32_t *)(bufpoi), 4); + } else + memcpy(bufpoi, info->reg+ECC_FIFO_0, 20); + + return 0; +} +#endif + +int reset_nfc(struct mtd_info *mtd, unsigned int *buf, int step) +{ + int ret = 0; + unsigned int backup1[7], *backup; + //unsigned int t1, t2; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + + + backup = backup1; + if (step != 3 && buf != NULL) + backup = buf; + + if (step&1) { + backup[0] = readl(info->reg + NFCR9_ECC_BCH_CTRL); + backup[1] = readl(info->reg + NFCRe_CALC_TADL); + backup[2] = readl(info->reg + NFCR10_OOB_ECC_SIZE); + backup[3] = readl(info->reg + NFCR12_NAND_TYPE_SEL); + backup[4] = readl(info->reg + NFCR13_INT_MASK); + backup[5] = readl(info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + backup[6] = readl(info->reg + NFCR7_DLYCOMP); + writeb(0x80, info->reg + NFCR13_INT_MASK); + writew(1, info->reg + NFCR12_NAND_TYPE_SEL); + writeb(0x2, info->reg + NFCR11_SOFT_RST); + } + if (step&2) { + ret = NFC_WAIT_IDLE(mtd); + if (ret) + printk("reset nfc, wait idle time out\n"); + writeb(0x0, info->reg + NFCR11_SOFT_RST); + + ret = wmt_wait_chip_ready(mtd); + if (ret) { + printk(KERN_ERR "reset nfc, The chip is not ready\n"); + print_nand_register(mtd); + while(1); + } + writeb(B2R, info->reg + NFCRb_NFC_INT_STAT); + writeb(0, info->reg + NFCRd_OOB_CTRL); + writel(backup[0], info->reg + NFCR9_ECC_BCH_CTRL); + writel(backup[1], info->reg + NFCRe_CALC_TADL); + writel(backup[2], info->reg + NFCR10_OOB_ECC_SIZE); + writel(backup[3], info->reg + NFCR12_NAND_TYPE_SEL); + writel(backup[4], info->reg + NFCR13_INT_MASK); + writel(backup[5], info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + writel(backup[6], info->reg + NFCR7_DLYCOMP); + } + + return ret; +} +void nfc_hw_rdmz(struct mtd_info *mtd, int on) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + if (on) + writel(RDMZ/*|(page%RDMZ)*/, info->reg + NFCRf_CALC_RDMZ); + else + writel(0, info->reg + NFCRf_CALC_RDMZ); +} + +int hw_encode_oob(struct mtd_info *mtd) +{ + int ret = 0; + unsigned int ecc_mode, oob_ecc_mode, tmp; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + + tmp = readb(info->reg + NFCR9_ECC_BCH_CTRL); + ecc_mode = tmp & ECC_MODE; + oob_ecc_mode = ecc_mode; + if (ecc_mode > 5) + oob_ecc_mode = 5; + + if (oob_ecc_mode != ecc_mode) + writeb((tmp & (~ECC_MODE)) | oob_ecc_mode, info->reg + NFCR9_ECC_BCH_CTRL); + + writeb(readb(info->reg + NFCRd_OOB_CTRL) | OOB_READ, info->reg + NFCRd_OOB_CTRL); + writew(DPAHSE_DISABLE|NFC_TRIGGER|OLD_CMD, info->reg + NFCR1_COMCTRL); + ret = NFC_WAIT_IDLE(mtd); + if (ret) + printk("hw encode oob idle time out\n"); + + writeb(readb(info->reg + NFCRd_OOB_CTRL) & (~OOB_READ), info->reg + NFCRd_OOB_CTRL); + + if (oob_ecc_mode != ecc_mode) + writeb(tmp, info->reg + NFCR9_ECC_BCH_CTRL); + + return ret; +} + +/************************Johnny Liu****************************************************/ +static int wmt_multi_plane_read(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ +/* + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + + int div = mtd->erasesize / mtd->writesize; + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + + wmt_nand_read_page(mtd, chip, buf, page); + + info->oper_step = 1; + + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page+div); + + wmt_nand_read_page(mtd, chip, buf+mtd->realwritesize, page+div); + + info->oper_step = 0; + + return 0; +*/ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int tmp, ret = 0, plane_0_uncor_err = 0, plane_1_uncor_err = 0; + + info->cur_lpage = page; + + tmp = cache_read_data(mtd, chip, page, buf); + if (!tmp) { + //printk("re lpg=0x%x from cache\n", page); + return 0; + } + + if (page >= ((mtd->blkcnt - 8)*mtd->pagecnt)) + mtd->bbt_sw_rdmz = 1; + else + mtd->bbt_sw_rdmz = 0; + + //printk("re pg=%x bbt_sw_rdmz=%d hold=%x blkcnt=%d\n", page, mtd->bbt_sw_rdmz, ((mtd->blkcnt - 8)*mtd->pagecnt), mtd->blkcnt); + + if (chip->cur_chip && prob_end == 1 && (chip->cur_chip->nand_id>>24) == NAND_MFR_HYNIX) { + #ifdef ESLC_READ_WRITE + if (page < par4_ofs && second_chip == 0) { + //printk("multi read page=%x ",page); + page = hynix_eslc_page_address_calculate(mtd, chip, page); + //printk("eslc cal page0=%x page1=0x%x \n", (page / mtd->pagecnt) * mtd->pagecnt + page, + //(page / mtd->pagecnt) * mtd->pagecnt + page + mtd->pagecnt); + if (page < 0) + return 0; + } + #endif + } + + page = (page / mtd->pagecnt) * mtd->pagecnt + page;//dan_multi 65->129, 129->257 + info->unc_bank = 0; + info->unc_allFF = 0; + if (/*(0xFF&(mtd->id>>24)) != NAND_MFR_MICRON && (0xFF&(mtd->id>>24)) != NAND_MFR_INTEL &&*/ (0xFF&(mtd->id>>24)) != NAND_MFR_TOSHIBA) { + + #ifdef WMT_HW_RDMZ + tmp = DIS_BCH_ECC & readb(info->reg + NFCR9_ECC_BCH_CTRL); + if (mtd->dwRdmz) { + if (mtd->bbt_sw_rdmz || tmp) { + if ((RDMZ & readl(info->reg + NFCRf_CALC_RDMZ)) == RDMZ) + reset_nfc(mtd, NULL, 3); + } else + nfc_hw_rdmz(mtd, 1); + } + #endif + + chip->cmdfunc(mtd, MULTI_READ_1CYCLE, -1, page); + chip->cmdfunc(mtd, MULTI_READ_2CYCLE, 0x00, page); + + if (info->data_ecc_uncor_err == 0) { + //printk("multi read plane0page=%x\n",page); + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + ret = wmt_nand_read_page_noalign(mtd, chip, buf, page); + else + ret = wmt_nand_read_page(mtd, chip, buf, page); + if (ret) { + printk("multi read plane0 data fail\n"); + ret = 1; + } else + ret = 0; + } else + plane_0_uncor_err = 1; + info->oper_step = 1; + info->unc_bank = 0; + info->unc_allFF = 0; + chip->cmdfunc(mtd, MULTI_READ_2CYCLE, 0x00, page + mtd->pagecnt); + + if (info->data_ecc_uncor_err == 0) { + //printk("multi read plane1 page=%x\n", page+mtd->pagecnt); + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + ret = wmt_nand_read_page_noalign(mtd, chip, buf+mtd->realwritesize, page + mtd->pagecnt); + else + ret = wmt_nand_read_page(mtd, chip, buf+mtd->realwritesize, page + mtd->pagecnt); + if (ret) { + printk("multi read plane1 data fail\n"); + ret = 1; + } else + ret = 0; + } else + plane_1_uncor_err = 1; + } else { + plane_0_uncor_err = 1; + plane_1_uncor_err = 1; + } + //print_nand_buffer((uint8_t *)buf, mtd->writesize); + + info->oper_step = 0; + if (plane_0_uncor_err == 1) { + //printk("multi read plane_0_uncor_err\n"); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + ret = wmt_nand_read_page_noalign(mtd, chip, buf, page); + else + ret = wmt_nand_read_page(mtd, chip, buf, page); + if (ret) + ret = 1; + else + ret = 0; + } + info->oper_step = 1; + if (plane_1_uncor_err == 1) { + //printk("multi read plane_1_uncor_err\n"); + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page + mtd->pagecnt); + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + ret = wmt_nand_read_page_noalign(mtd, chip, buf+mtd->realwritesize, page + mtd->pagecnt); + else + ret = wmt_nand_read_page(mtd, chip, buf+mtd->realwritesize, page + mtd->pagecnt); + if (ret) + ret = 1; + else + ret = 0; + } + info->oper_step = 0; + //printk("mrp=%d=0x%x\n", page, page); + //print_nand_buffer((uint8_t *)chip->oob_poi, 48); + /*printk(KERN_NOTICE "re sqNum=0x%x, objId=0x%x, lgcAdr=0x%x Byte=0x%x page=0x%x PID:%d Comm:%s\n", + *(uint32_t *)(chip->oob_poi+ECC_FIFO_0), + *(uint32_t *)(chip->oob_poi+4), *(uint32_t *)(chip->oob_poi+8), + *(uint32_t *)(chip->oob_poi+12), page,current->pid, current->comm);*/ + if (ret) + printk("----------multi read ret=%d\n", ret); + return ret; +} + +static void wmt_nand_write_page_lowlevel_noalign(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int b2r_stat, backup[6];//, w1, w2, w3; + uint8_t *bufpoi = chip->oob_poi; + #ifdef NAND_DEBUG + printk(KERN_NOTICE "enter in wmt_nand_page_write_lowlevel() writesize %x\n", mtd->realwritesize); + #endif + + info->dma_finish = 0; + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + writeb(0x1B, info->reg + NFCR13_INT_MASK); + + if (mtd->dwRdmz == 1) { + *(unsigned int *)(bufpoi+20) = *(unsigned int *)wmt_rdmz; + } + + writeb(readb(info->reg + NFCRd_OOB_CTRL) & 0xF7, info->reg + NFCRd_OOB_CTRL); + //memcpy(info->reg+ECC_FIFO_0, bufpoi, 24); + + //print_nand_buffer((uint8_t *)(info->reg+ECC_FIFO_0), 32); + if(!chip->realplanenum) { + info->datalen = 0; + reset_nfc(mtd, backup, 1); + chip->write_buf(mtd, buf, mtd->writesize); + memcpy(info->dmabuf + mtd->realwritesize, bufpoi, 24); + memset(info->dmabuf + mtd->realwritesize+24, 0x55, 24); + reset_nfc(mtd, backup, 2); + //hw_encode_oob(mtd); + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1); + wmt_nfc_dma_cfg(mtd, mtd->realwritesize+1024, 1, 0, -1); + //print_nand_buffer((uint8_t *)(info->dmabuf+6144), 32);print_nand_register(mtd); + } else if (chip->realplanenum && info->datalen == 0) { + //printk("copybuf 1\n"); + //w1 = wmt_read_oscr(); + reset_nfc(mtd, backup, 1); + chip->write_buf(mtd, buf, mtd->realwritesize); + memcpy(info->dmabuf + mtd->realwritesize, bufpoi, 24); + memset(info->dmabuf + mtd->realwritesize+24, 0x55, 24); + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 1) + rdmzier_oob((info->dmabuf + mtd->realwritesize), (info->dmabuf + mtd->realwritesize), 1024/4, info->cur_page, mtd->realwritesize/4); + //w2 = wmt_read_oscr(); + reset_nfc(mtd, backup, 2); + //hw_encode_oob(mtd); + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1); + //w3 = wmt_read_oscr(); + //printk(KERN_DEBUG "w2-w1=%d w3-w1=%d---------------\n",w2-w1, w3-w1); + wmt_nfc_dma_cfg(mtd, mtd->realwritesize+1024, 1, 0, -1); + //print_nand_register(mtd); + } else if (info->datalen == mtd->writesize) { + //printk("copybuf 2\n"); + //info->datalen = mtd->realwritesize; + //chip->write_buf(mtd, buf, mtd->writesize); + memcpy(info->dmabuf, buf+mtd->realwritesize, mtd->realwritesize); + wmt_nfc_dma_cfg(mtd, mtd->realwritesize+1024, 1, 0, 2); + //print_nand_register(mtd); + } +/*printk(KERN_DEBUG "WPG=0x%x : 0x%x 0x%x 0x%x 0x%x\n", info->cur_page, *(uint32_t *)info->dmabuf, +*((uint32_t *)info->dmabuf+1), *((uint32_t *)info->dmabuf+2), *((uint32_t *)info->dmabuf+3));*/ + /*if ((info->cur_page%256) == 0)dannier + printk(KERN_NOTICE "wr PID:%d Comm:%s sqNum=0x%x, objId=0x%x, lgcAdr=0x%x Byte=0x%x page=0x%x\n", + current->pid, current->comm, *(uint32_t *)(info->reg+ECC_FIFO_0), + *(uint32_t *)(info->reg+ECC_FIFO_1), *(uint32_t *)(info->reg+ECC_FIFO_2), + *(uint32_t *)(info->reg+ECC_FIFO_3), info->cur_page);*/ +} +//extern unsigned int wmt_read_oscr(void); +/** + * wmt_nand_write_page_lowlevel - hardware ecc syndrom based page write + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * + * The hw generator calculates the error syndrome automatically. Therefor + * we need a special oob layout and handling. + * + */ +static void wmt_nand_write_page_lowlevel(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + unsigned int b2r_stat, backup[6];//, w1, w2, w3; + uint8_t *bufpoi = chip->oob_poi; + #ifdef NAND_DEBUG + printk(KERN_NOTICE "enter in wmt_nand_page_write_lowlevel() writesize %x\n", mtd->realwritesize); + #endif + + info->dma_finish = 0; + b2r_stat = readb(info->reg + NFCRb_NFC_INT_STAT); + writeb(B2R|b2r_stat, info->reg + NFCRb_NFC_INT_STAT); + writeb(0x1B, info->reg + NFCR13_INT_MASK); + + if (mtd->dwRdmz == 1) { + *(unsigned int *)(bufpoi+20) = *(unsigned int *)wmt_rdmz; + } + + writeb(readb(info->reg + NFCRd_OOB_CTRL) & 0xF7, info->reg + NFCRd_OOB_CTRL); + if (mtd->dwRdmz == 1 && mtd->bbt_sw_rdmz) { + //print_nand_buffer((uint8_t *)bufpoi, 24); + printk(KERN_NOTICE "wr sqNum=0x%x, objId=0x%x, lgcAdr=0x%x Byte=0x%x page=0x%x PID:%d Comm:%s\n", + *(uint32_t *)(chip->oob_poi+0), + *(uint32_t *)(chip->oob_poi+4), *(uint32_t *)(chip->oob_poi+8), + *(uint32_t *)(chip->oob_poi+12), info->cur_page, + current->pid, current->comm); + + rdmzier_oob((uint8_t *)(info->reg+ECC_FIFO_0), (uint8_t *)bufpoi, 6, info->cur_page, mtd->realwritesize/4); + //print_nand_buffer((uint8_t *)(info->reg+ECC_FIFO_0), 64); + } else + memcpy(info->reg+ECC_FIFO_0, bufpoi, 24); + + + //print_nand_buffer((uint8_t *)(info->reg+ECC_FIFO_0), 32); + if(!chip->realplanenum) { + info->datalen = 0; + reset_nfc(mtd, backup, 1); + chip->write_buf(mtd, buf, mtd->writesize); + reset_nfc(mtd, backup, 2); + hw_encode_oob(mtd); + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1); + wmt_nfc_dma_cfg(mtd, mtd->realwritesize, 1, 0, -1); + } else if (chip->realplanenum && info->datalen == 0) { + //printk("copybuf 1\n"); + //w1 = wmt_read_oscr(); + reset_nfc(mtd, backup, 1); + chip->write_buf(mtd, buf, mtd->writesize); + //w2 = wmt_read_oscr(); + reset_nfc(mtd, backup, 2); + hw_encode_oob(mtd); + if (mtd->dwRdmz && mtd->bbt_sw_rdmz == 0) + nfc_hw_rdmz(mtd, 1); + //w3 = wmt_read_oscr(); + //printk(KERN_DEBUG "w2-w1=%d w3-w1=%d---------------\n",w2-w1, w3-w1); + wmt_nfc_dma_cfg(mtd, mtd->realwritesize, 1, 0, -1); + //print_nand_register(mtd); + } else if (info->datalen == mtd->writesize) { + //printk("copybuf 2\n"); + //info->datalen = mtd->realwritesize; + //chip->write_buf(mtd, buf, mtd->writesize); + wmt_nfc_dma_cfg(mtd, mtd->realwritesize, 1, 0, 2); + //print_nand_register(mtd); + } +//while(info->datalen); + + #if 0 + if (info->cur_lpage >= 19456/*992768*/) { + if (strcmp(current->comm, "yaffs-bg-1") == 0) { + printk(KERN_NOTICE "wr PID:%d Comm:%s sqNum=0x%x, objId=0x%x, lgcAdr=0x%x Byte=0x%x page=0x%x\n", + current->pid, current->comm, *(uint32_t *)(info->reg+ECC_FIFO_0), + *(uint32_t *)(info->reg+ECC_FIFO_1), *(uint32_t *)(info->reg+ECC_FIFO_2), + *(uint32_t *)(info->reg+ECC_FIFO_3), info->cur_page); + #if 0 + } else if (strcmp(current->comm, "cp") == 0 /*&& *(uint32_t *)(info->reg+ECC_FIFO_2) > 0x1f90*/ + && lst_chunkid == 0 /*&& *(uint32_t *)(info->reg+ECC_FIFO_2) != (lst_chunkid+1)*/) { + printk(KERN_NOTICE "wr PID:%d Comm:%s sqNum=0x%x, objId=0x%x, lgcAdr=0x%x Byte=0x%x page=0x%x\n", + current->pid, current->comm, *(uint32_t *)(info->reg+ECC_FIFO_0), + *(uint32_t *)(info->reg+ECC_FIFO_1), *(uint32_t *)(info->reg+ECC_FIFO_2), + *(uint32_t *)(info->reg+ECC_FIFO_3), info->cur_page); + lst_chunkid = 11; + //#endif + } else if (strcmp(current->comm, "cp") == 0 && *(uint32_t *)(info->reg+ECC_FIFO_2) > 0x1f60) { + chunk[idx] = *(uint32_t *)(info->reg+ECC_FIFO_2); + cpg[idx] = info->cur_page; + idx++; + } else if (strcmp(current->comm, "sync") == 0) { + printk(KERN_NOTICE "wr PID:%d Comm:%s sqNum=0x%x, objId=0x%x, lgcAdr=0x%x Byte=0x%x page=0x%x\n", + current->pid, current->comm, *(uint32_t *)(info->reg+ECC_FIFO_0), + *(uint32_t *)(info->reg+ECC_FIFO_1), *(uint32_t *)(info->reg+ECC_FIFO_2), + *(uint32_t *)(info->reg+ECC_FIFO_3), info->cur_page); + if (*(uint32_t *)(info->reg+ECC_FIFO_0) == 0x21 && *(uint32_t *)(info->reg+ECC_FIFO_2) == 0x4) + print_nand_buffer((char *)info->dmabuf, mtd->realwritesize); + #endif + } + } + #endif +} + +static int hynix_eslc_mode_change(struct mtd_info *mtd, struct nand_chip *chip, int page) +{ + if (chip->cur_chip && (chip->cur_chip->nand_id>>24) == NAND_MFR_HYNIX /*&& mtd->dwRetry*/) { + #ifdef ESLC_READ_WRITE + #ifdef ESLC_DEBUG + int ori_page = page; + #endif + if ((page < par4_ofs && second_chip == 0) || (page >= (mtd->blkcnt-8)*mtd->pagecnt)) { + //printk("page=0x%x\n", page); + //dump_stack(); + //while(1); + if (page < (mtd->blkcnt-8)*mtd->pagecnt) { + page = hynix_eslc_page_address_calculate(mtd, chip, page); + if (page < 0) + return -1; + if (page%(mtd->pagecnt/2) == 0) { + if(chip->realplanenum == 0) { + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); + } else if(chip->realplanenum == 1) { + wmt_multi_plane_erase(mtd, page); + } + #ifdef ESLC_DEBUG + printk("eslc erase page=0x%x => eslc page = 0x%x when write.\n", ori_page, page); + #endif + } + } + if (eslc_write != 2) { + eslc_write = 2; + chip->cur_chip->set_parameter(mtd, ESLC_MODE, ECC_ERROR_VALUE); + #ifdef ESLC_DEBUG + printk(KERN_WARNING "page=0x%x----ENABLE ESLC", ori_page); + if (page >= (mtd->blkcnt-8)*mtd->pagecnt) { + printk(KERN_WARNING "(BBT) page%x,bbtpage=%x pagecnt=%d, blkcnt=%d\n", page, (mtd->blkcnt-8)*mtd->pagecnt,mtd->pagecnt, mtd->blkcnt); + dump_stack(); + } else + printk(KERN_WARNING "\n"); + #endif + } + } else if (eslc_write == 2) { + chip->cur_chip->set_parameter(mtd, ESLC_MODE, DEFAULT_VALUE); + eslc_write = 0; + #ifdef ESLC_DEBUG + printk(KERN_NOTICE "page=0x%x****DIS ESLC\n", page); + #endif + } + #endif + } + return page; +} + +int cache_read_data(struct mtd_info *mtd, struct nand_chip *chip, int page, const uint8_t *buf) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int cache_index; + + if (prob_end == 0) + return 1; + + if (wr_cache == NULL) + return 1; + + cache_index = page%mtd->pagecnt; + cache_index %= WR_BUF_CNT; + + if (info->wr_page[cache_index] == page && page >= 0) { + if (buf) + memcpy((char *)buf, wr_cache+(cache_index*(mtd->writesize+32)), mtd->writesize); + memcpy(chip->oob_poi, wr_cache+(cache_index*(mtd->writesize+32)) + mtd->writesize, 32); + return 0; + } + return 1; +} + +void cache_write_data(struct mtd_info *mtd, struct nand_chip *chip, int page, const uint8_t *buf) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int cache_index; + + cache_index = page%mtd->pagecnt; + cache_index %= WR_BUF_CNT; + + if (wr_cache == NULL) + return; + + if ((page%mtd->pagecnt) == 0 && prob_end == 1) + init_wr_cache(mtd); + + if (prob_end == 1) { + info->wr_page[cache_index] = page;//printk("wr-cache lpage[%d]=0x%x\n", cache_index, page); + memcpy(wr_cache+(cache_index*(mtd->writesize+32)), buf, mtd->writesize); + memcpy(wr_cache+(cache_index*(mtd->writesize+32)) + mtd->writesize, chip->oob_poi, 32); + } +} + +static int wmt_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, +const uint8_t *buf, int page, int cached, int raw) +{ + int status; + uint8_t *tmp_buf = (uint8_t *)buf; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + #ifdef NAND_DEBUG + printk(KERN_NOTICE "enter in wmt_nand_write_page() raw = %d\n", raw); + #endif + + cache_write_data(mtd, chip, page, buf); + info->cur_lpage = page; + + if (page > ((mtd->blkcnt - 8)*mtd->pagecnt)) + mtd->bbt_sw_rdmz = 1; + else + mtd->bbt_sw_rdmz = 0; + + page = hynix_eslc_mode_change(mtd, chip, page); + + if (page < 0) + return 0; + + info->cur_page = page; + wmb(); + + if (mtd->dwRdmz) { + if (mtd->bbt_sw_rdmz) { + if ((RDMZ & readl(info->reg + NFCRf_CALC_RDMZ)) == RDMZ) + reset_nfc(mtd, NULL, 3); + tmp_buf = buf_rdmz; + memcpy(tmp_buf, buf, mtd->realwritesize);//print_nand_buffer(tmp_buf, 64); + rdmzier(tmp_buf, mtd->realwritesize/4, page);//print_nand_buffer(tmp_buf, 64); + } else + nfc_hw_rdmz(mtd, 1); + } + + info->datalen = 0; + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + wmt_nand_write_page_lowlevel_noalign(mtd, chip, tmp_buf); + else + chip->ecc.write_page(mtd, chip, tmp_buf); + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + status = nand_pdma_handler(mtd); + nand_free_pdma(mtd); + if (status) + printk(KERN_ERR "check write pdma handler status= %x \n", status); + + /* + * * * Cached progamming disabled for now, Not sure if its worth the + * * * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) + * * */ + cached = 0; + + if (!cached || !(chip->options & NAND_CACHEPRG)) { + + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + #ifdef WMT_HW_RDMZ + if (mtd->dwRdmz) { + //nfc_hw_rdmz(mtd, 1); + writeb(0, info->reg + NFCR4_COMPORT3_4); + } + #endif + + status = chip->waitfunc(mtd, chip); + writeb(0x80, info->reg + NFCR13_INT_MASK); + /* + * * See if operation failed and additional status checks are + * * available + * * + */ + if ((status & NAND_STATUS_FAIL) && (chip->errstat)) + status = chip->errstat(mtd, chip, FL_WRITING, status, page); + + if (status & NAND_STATUS_FAIL) + goto GO_EIO;//return -EIO; + } else { + chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1); + + #ifdef WMT_HW_RDMZ + if (mtd->dwRdmz) { + if (mtd->bbt_sw_rdmz) { + if ((RDMZ & readl(info->reg + NFCRf_CALC_RDMZ)) == RDMZ) + reset_nfc(mtd, NULL, 3); + tmp_buf = buf_rdmz; + memcpy(tmp_buf, buf, mtd->realwritesize); + rdmzier(tmp_buf, mtd->realwritesize/4, page); + } else + nfc_hw_rdmz(mtd, 1); + writeb(0, info->reg + NFCR4_COMPORT3_4); + } + #endif + + status = chip->waitfunc(mtd, chip); + } + + #ifdef CONFIG_MTD_NAND_VERIFY_WRITE + /* Send command to read back the data */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + + if (chip->verify_buf(mtd, buf, mtd->realwritesize)) + goto GO_EIO;//return -EIO; + #endif + return 0; + +GO_EIO: + return -EIO; +} +int abcc; +static int wmt_multi_plane_program(struct mtd_info *mtd, struct nand_chip *chip, +const uint8_t *buf, int page, int cached, int raw) +{ + int status, page_plane1; + + uint8_t *tmp_buf = (uint8_t *)buf; + int pagecnt = mtd->pagecnt, p1; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + #ifdef ESLC_DEBUG + int p0 = page; + #endif + + cache_write_data(mtd, chip, page, buf);//logical address + info->cur_lpage = page; + + if (page > ((mtd->blkcnt-8)*mtd->pagecnt)) + mtd->bbt_sw_rdmz = 1; + else + mtd->bbt_sw_rdmz = 0; + + //printk("multi program page %d => page1=%d page2=%d\n", page, (page/pagecnt) * pagecnt + page, (page<<1) - (page%pagecnt)); + p1 = page = hynix_eslc_mode_change(mtd, chip, page); + + if (page < 0) + return 0; + + page = (page /pagecnt) * pagecnt + page;//1->1, 128 -> 256, 256->512 + page_plane1 = page + pagecnt; + #ifdef ESLC_DEBUG + if (p0 != p1) + printk("multi program page 0x%x eslc 0x%x => page1=0x%x page2=0x%x \n", p0, p1, page, page_plane1); + #endif + + info->lst_wpage = page; + //page_plane1 = hynix_eslc_mode_change(mtd, chip, page_plane1); + //printk("mw p1=%x page %x => page plane1=%x\n", p1, page, page_plane1); + + info->cur_page = page; + wmb(); + if (mtd->dwRdmz) { + if (mtd->bbt_sw_rdmz) { + if ((RDMZ & readl(info->reg + NFCRf_CALC_RDMZ)) == RDMZ) + reset_nfc(mtd, NULL, 3); + tmp_buf = buf_rdmz; + memcpy(tmp_buf, buf, mtd->writesize); + rdmzier(tmp_buf, mtd->realwritesize/4, page); + //memcpy(tmp_buf, buf+mtd->realwritesize, mtd->realwritesize); + rdmzier(tmp_buf+mtd->realwritesize, mtd->realwritesize/4, page_plane1); + } else + nfc_hw_rdmz(mtd, 1); + } + + info->datalen = 0; + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + wmt_nand_write_page_lowlevel_noalign(mtd, chip, tmp_buf); + else + chip->ecc.write_page(mtd, chip, tmp_buf); + chip->cmdfunc(mtd, 0x80, 0x00, page); + status = nand_pdma_handler(mtd); + nand_free_pdma(mtd); + if (status) + printk(KERN_ERR "check write pdma handler status= %x \n", status); + /***********************Johnny Liu start**************************************/ + chip->cmdfunc(mtd, 0x11,-1,-1); + + info->datalen = mtd->writesize;//need + info->cur_page = page_plane1; + + /*#ifdef WMT_SW_RDMZ + if (mtd->dwRdmz == 1) { + tmp_buf = buf_rdmz; + //memcpy(tmp_buf, buf+mtd->realwritesize, mtd->realwritesize); + //rdmzier(tmp_buf, mtd->realwritesize/4, page_plane1); + } + #endif + #ifdef WMT_HW_RDMZ + if (mtd->dwRdmz) + nfc_hw_rdmz(mtd, 1); + #endif*/ + + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + wmt_nand_write_page_lowlevel_noalign(mtd, chip, tmp_buf); + else + chip->ecc.write_page(mtd, chip, tmp_buf); + if ((0xFF&(mtd->id>>24)) == NAND_MFR_MICRON) + chip->cmdfunc(mtd, 0x80, 0x00, page_plane1); + else + chip->cmdfunc(mtd, 0x81, 0x00, page_plane1); + + status = nand_pdma_handler(mtd); + nand_free_pdma(mtd); + if (status) + printk(KERN_ERR "check write pdma handler status= %x \n", status); + /************************Johnny Liu end*************************************/ + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + #ifdef WMT_HW_RDMZ + if (mtd->dwRdmz) { + //nfc_hw_rdmz(mtd, 1); + writeb(0, info->reg + NFCR4_COMPORT3_4); + } + #endif + status = chip->waitfunc(mtd, chip); + writeb(0x80, info->reg + NFCR13_INT_MASK); + + if (chip->realplanenum && (status & NAND_STATUS_FAIL)) { + printk(KERN_ERR "multi write page=0x%x fail status= %x\n", page, status); + //dump_stack(); + /*if (abcc != 13479) { + status = 0xe3;//0xe5; + abcc = 13479; + printk("write page=%x error abv=%d\n", page, abcc); + dump_stack(); + }*/ + chip->status_plane[0] = page; + chip->status_plane[1] = status; + } + if ((status & NAND_STATUS_FAIL) && (chip->errstat)) { + printk(KERN_ERR "write fail status= %x\n", status); + status = chip->errstat(mtd, chip, FL_WRITING, status, page); + } + + if (status & NAND_STATUS_FAIL) + return -EIO; + + return 0; +} + +#if 0 +static int wmt_multi_plane_copy(struct mtd_info *mtd, struct nand_chip *chip, +int source, int des) +{ +// printk("\n copy data from %d to %d",source, des); + unsigned int page = 0; + + int div = mtd->erasesize / mtd->writesize; + page = (source / div) * div + source; + chip->cmdfunc(mtd, MULTI_COPY_1CYCLE, 0x00, page); + + chip->cmdfunc(mtd, MULTI_COPY_2CYCLE, 0x00, page); + chip->cmdfunc(mtd, MULTI_COPY_2CYCLE, 0x00, page + div); + + page = (des / div) * div + des; + chip->cmdfunc(mtd, MULTI_COPY_3CYCLE, 0x00, page); + + return 0; +} +static int wmt_nand_copy_page(struct mtd_info *mtd, struct nand_chip *chip, +int source, int des) +{ + unsigned int page = 0; + //int status = -1; + //printk("\n copy data from %d to %d", source, des); + //First, we calculate the source page + page = source; + //Copy back read cycle + chip->cmdfunc(mtd, COPY_BACK_1CYCLE, 0x00, page); + + //Second, we calculate the des page + page = des; + //Copy back program cycle + chip->cmdfunc(mtd, COPY_BACK_2CYCLE, 0x00, page); + return 0; +} +#endif + +#if 0 +/** + * wmt_errstat - perform additional error status checks + * @mtd: MTD device structure + * @this: NAND chip structure + * @state: state or the operation + * @status: status code returned from read status + * @page: startpage inside the chip, must be called with (page & this->pagemask) + * + * Perform additional error status checks on erase and write failures + * to determine if errors are correctable. For this device, correctable + * 1-bit errors on erase and write are considered acceptable. + * + * + */ +static int wmt_errstat(struct mtd_info *mtd, struct nand_chip *this, + int state, int status, int page) +{ + int er_stat = 0; + int rtn, retlen; + size_t len; + uint8_t *buf; + int i; + + this->cmdfunc(mtd, NAND_CMD_STATUS_CLEAR, -1, -1); + + if (state == FL_ERASING) { + + for (i = 0; i < 4; i++) { + if (!(status & 1 << (i + 1))) + continue; + this->cmdfunc(mtd, (NAND_CMD_STATUS_ERROR + i + 1), + -1, -1); + rtn = this->read_byte(mtd); + this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1); + + /* err_ecc_not_avail */ + //if (!(rtn & ERR_STAT_ECC_AVAILABLE)) + //er_stat |= 1 << (i + 1); + } + + } else if (state == FL_WRITING) { + + unsigned long corrected = mtd->ecc_stats.corrected; + + /* single bank write logic */ + this->cmdfunc(mtd, NAND_CMD_STATUS_ERROR, -1, -1); + rtn = this->read_byte(mtd); + this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1); + + if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { + /* err_ecc_not_avail */ + er_stat |= 1 << 1; + goto out; + } + + len = mtd->writesize; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) { + er_stat = 1; + goto out; + } + + /* recovery read */ + rtn = nand_do_read(mtd, page, len, &retlen, buf); + + /* if read failed or > 1-bit error corrected */ + if (rtn || (mtd->ecc_stats.corrected - corrected) > 1) + er_stat |= 1 << 1; + kfree(buf); + } +out: + rtn = status; + if (er_stat == 0) { /* if ECC is available */ + rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */ + } + + return rtn; +} +#endif + +/* wmt_nand_init_chip + * + * init a single instance of an chip + */ + +static void wmt_nand_init_chip(struct mtd_info *mtd, +struct ECC_size_info *ECC_size) +{ + //struct nand_chip *chip = &nmtd->chip; + //struct mtd_info *mtd = &nmtd->mtd; + struct nand_chip *chip = mtd->priv; + + /* chip->cmd_ctrl = wmt_nand_hwcontrol;*/ + #if 0 + switch (info->cpu_type) { + case TYPE_wmt: + break; + + case TYPE_vt8620: + break; + + case TYPE_vt8610: + break; + } + #endif + + /* nmtd->set = set;*/ + if (hardware_ecc) { + /* chip->ecc.calculate = wmt_nand_calculate_ecc;*/ + /* chip->ecc.correct = wmt_nand_correct_data;*/ + + /*if (mtd->realwritesize == 2048) { + chip->ecc.size = 512; + chip->ecc.bytes = 8; + chip->ecc.steps = 4; + chip->ecc.layout = &wmt_oobinfo_2048; + chip->ecc.prepad = 1; + chip->ecc.postpad = 8; + } else if (mtd->realwritesize == 4096) { + chip->ecc.size = 512; + chip->ecc.bytes = 20; + chip->ecc.steps = 8; + chip->ecc.layout = &wmt_oobinfo_4096; + chip->ecc.prepad = 1; + chip->ecc.postpad = 8; + } else if (mtd->realwritesize == 8192) { + chip->ecc.size = 1024; + chip->ecc.bytes = 42; + chip->ecc.steps = 8; + chip->ecc.layout = &wmt_oobinfo_8192; + chip->ecc.prepad = 1; + chip->ecc.postpad = 8; + } else if (mtd->realwritesize == 16384) { + chip->ecc.size = 1024; + chip->ecc.bytes = 70; + chip->ecc.steps = 16; + chip->ecc.layout = &wmt_oobinfo_16k; + chip->ecc.prepad = 1; + chip->ecc.postpad = 8; + } else { // 512 page + chip->ecc.size = 512; + chip->ecc.bytes = 3; + chip->ecc.steps = 1; + chip->ecc.layout = &wmt_oobinfo_512; + chip->ecc.prepad = 4; + chip->ecc.postpad = 9; + }*/ + chip->ecc.size = (mtd->realwritesize/ECC_size->banks); + chip->ecc.bytes = ECC_size->ECC_bytes; + chip->ecc.steps = ECC_size->banks; + + chip->write_page = wmt_nand_write_page; + //chip->copy_page = wmt_nand_copy_page; + + chip->ecc.write_page = wmt_nand_write_page_lowlevel; + chip->ecc.write_oob = wmt_nand_write_oob; + chip->ecc.read_page = wmt_nand_read_page; + chip->ecc.read_oob = wmt_nand_read_oob_single; + + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + chip->ecc.read_page = wmt_nand_read_page_noalign; + + chip->ecc.read_bb_oob = wmt_nand_read_bb_oob; + chip->erase_cmd = wmt_single_plane_erase; + if (chip->realplanenum) { + chip->write_page = wmt_multi_plane_program; + //chip->copy_page = wmt_multi_plane_copy; + chip->ecc.read_page = wmt_multi_plane_read; + chip->erase_cmd = wmt_multi_plane_erase; + chip->ecc.write_oob = wmt_nand_write_oob_plane; + chip->ecc.read_oob = wmt_nand_read_oob_plane; + chip->ecc.read_bb_oob = wmt_nand_read_bb_oob_plane; + } + + + /* switch (info->cpu_type) {*/ + /* case TYPE_wmt:*/ + chip->ecc.hwctl = wmt_nand_enable_hwecc; + /* chip->ecc.calculate = wmt_nand_calculate_ecc;*/ + /* break;*/ + #if 0 + case TYPE_vt8620: + chip->ecc.hwctl = vt8620_nand_enable_hwecc; + chip->ecc.calculate = vt86203_nand_calculate_ecc; + break; + + case TYPE_vt8610: + chip->ecc.hwctl = vt8610_nand_enable_hwecc; + chip->ecc.calculate = vt8610_nand_calculate_ecc; + break; + #endif + } else + chip->ecc.mode = NAND_ECC_SOFT; +} + + +static int wmt_nand_remove(struct platform_device *pdev) +{ + struct wmt_nand_info *info = dev_get_drvdata(&pdev->dev); + + /* struct mtd_info *mtd = dev_get_drvdata(pdev);*/ + dev_set_drvdata(&pdev->dev, NULL); + /* platform_set_drvdata(pdev, NULL);*/ + /* dev_set_drvdata(pdev, NULL);*/ + if (info == NULL) + return 0; + + /* first thing we need to do is release all our mtds + * and their partitions, then go through freeing the + * resources used + */ + + if (info->mtds != NULL) { + struct wmt_nand_mtd *ptr = info->mtds; + /* int mtdno;*/ + + /* for (mtdno = 0; mtdno < info->mtd_count; mtdno++, ptr++) {*/ + /* pr_debug("releasing mtd %d (%p)\n", mtdno, ptr);*/ + nand_release(&ptr->mtd); + /* }*/ + kfree(info->mtds); + } + + /* free the common resources */ + + if (info->reg != NULL) { + //iounmap(info->reg); + info->reg = NULL; + } + + if (info->area != NULL) { + release_resource(info->area); + kfree(info->area); + info->area = NULL; + } + kfree(info); + if (buf_rdmz) + vfree(buf_rdmz); + remove_proc_entry(NANDINFO, NULL); + return 0; +} + +#if 0 +/*Lch */ +static int wmt_recovery_call(struct notifier_block *nb, unsigned long code, void *_cmd) +{ + struct mtd_info *mtd; + struct nand_chip *chip; + + mtd = container_of(nb, struct mtd_info, reboot_notifier); + chip = (struct nand_chip *)mtd->priv; + if(chip->cur_chip && (((mtd->id >>24)&0xff) == NAND_MFR_HYNIX)) { + auto_pll_divisor(DEV_NAND, CLK_ENABLE, 0, 0); + #ifdef RETRY_DEBUG + printk("current try times: %d\n", chip->cur_chip->cur_try_times); + #endif + chip->select_chip(mtd, 0); + chip->cur_chip->set_parameter(mtd, READ_RETRY_MODE, DEFAULT_VALUE); + //chip->cur_chip->get_parameter(mtd,READ_RETRY_MODE); + chip->select_chip(mtd, -1); + } + return NOTIFY_DONE; + + mtd = container_of(nb, struct mtd_info, reboot_notifier); + + if((code == SYS_RESTART) && _cmd) { + char *cmd = _cmd; + if (!strcmp(cmd, "recovery")) { + err = search_mtd_table("android-data", &ret1); + ret = (int)ret1; + if (!err) { + // printk(KERN_EMERG "Lch jump2 android-data wmt_recovery_call.ret =%d\n",ret); + struct erase_info einfo; + loff_t to; + memset(&einfo, 0, sizeof(einfo)); + to = nand_partitions[ret].offset; + einfo.mtd = mtd; + einfo.addr = (unsigned long)to; + einfo.len = nand_partitions[ret].size; + + // printk("android-data einfo.addr is %8.8x\n",einfo.addr); + // printk("android-data einfo.len is %8.8x\n",einfo.len); + // printk("android-data nand_partitions[%d].offset is %8.8x\n",ret,nand_partitions[ret].offset); + // printk("android-data nand_partitions[%d].size is %8.8x\n",ret,nand_partitions[ret].size); + ret = nand_erase_nand(mtd, &einfo, 0xFF); + if (ret < 0) + printk("enand_erase_nand result is %x\n",ret); + } + + err = search_mtd_table("android-cache", &ret1); + ret = (int)ret1; + if (!err) { + // printk(KERN_EMERG "Lch jump3 wmt_recovery_call.android-cache ret=%d\n",ret); + struct erase_info einfo; + loff_t to; + memset(&einfo, 0, sizeof(einfo)); + to = nand_partitions[ret].offset; + einfo.mtd = mtd; + einfo.addr = (unsigned long)to; + einfo.len = nand_partitions[ret].size; + + // printk("android-cache einfo.addr is %8.8x\n",einfo.addr); + // printk("android-cache einfo.len is %8.8x\n",einfo.len); + // printk("android-data nand_partitions[%d].offset is %8.8x\n",ret,nand_partitions[ret].offset); + // printk("android-data nand_partitions[%d].size is %8.8x\n",ret,nand_partitions[ret].size); + ret = nand_erase_nand(mtd, &einfo, 0xFF); + if (ret < 0) + printk("enand_erase_nand result is %x\n",ret); + } + } + } + return NOTIFY_DONE; +} +#endif + +/********************************************************************** +Name : nfc_pdma_isr +Function :. +Calls : +Called by : +Parameter : +Author : Dannier Chen +History : +***********************************************************************/ +static irqreturn_t nfc_pdma_isr(int irq, void *dev_id) +{ + struct wmt_nand_info *info = (struct wmt_nand_info *)dev_id; + struct mtd_info *mtd = &info->mtds->mtd; + disable_irq_nosync(irq); + //spin_lock(&host->lock); + writel(0, info->reg + NFC_DMA_IER); + wmb(); + //writel(/*readl(info->reg + NFC_DMA_ISR)&*/NAND_PDMA_IER_INT_STS, info->reg + NFC_DMA_ISR); + //printk(" pdmaisr finish NFC_DMA_ISR=0x%x\n", readl(info->reg + NFC_DMA_ISR)); + //print_nand_register(mtd); + info->dma_finish++; + WARN_ON(info->done_data == NULL); + if (info->done_data == NULL) { + printk(" pdmaisr finish pointer is null info->dma_finish=%d\n", info->dma_finish); + print_nand_register(mtd); + dump_stack(); + //while(1); + } + if (info->done_data != NULL) { + complete(info->done_data); + info->done_data = NULL; + } + //info->done = NULL; + //spin_unlock(&host->lock); + enable_irq(irq); + + return IRQ_HANDLED; +} + +/********************************************************************** +Name : nfc_regular_isr +Function :. +Calls : +Called by : +Parameter : +Author : Dannier Chen +History : +***********************************************************************/ +//static irqreturn_t nfc_regular_isr(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t nfc_regular_isr(int irq, void *dev_id) +{ + + struct wmt_nand_info *info = dev_id; + struct mtd_info *mtd = &info->mtds->mtd; + unsigned int bank_stat1, bank_stat2=0,status = 0, intsts; + + disable_irq_nosync(irq); + //spin_lock(&host->lock); + //printk("isrCMD=0x%x\n", info->isr_cmd); + if (info->isr_cmd == 0) { + //print_nand_register(mtd); + bank_stat1 = readb(info->reg + NFCRb_NFC_INT_STAT); + if (bank_stat1&(ERR_CORRECT | BCH_ERR)) { + while ((bank_stat1&(ERR_CORRECT|BCH_ERR)) != (ERR_CORRECT|BCH_ERR)) { + bank_stat1 = readb(info->reg + NFCRb_NFC_INT_STAT); + bank_stat2++; + if (bank_stat2 >= 0x10000) { + printk("ecc error, but ecc correct not assert ecc status=0x%x\n",bank_stat1); + print_nand_register(mtd); + //while(1); + break; + } + } + writeb((B2R | ERR_CORRECT | BCH_ERR), info->reg + NFCRb_NFC_INT_STAT); + bank_stat2 = readw(info->reg + NFCR9_ECC_BCH_CTRL); + #ifdef NAND_DEBUG + printk(KERN_NOTICE" BCH Read data ecc eror page_addr:%x cmd=%d\n", info->cur_page, info->isr_cmd); + #endif + if ((bank_stat2 & BANK_DR) || info->oob_ecc_error == 0x50) { + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + bch_data_last_bk_ecc_correct_noalign(mtd); + else + bch_data_last_bk_ecc_correct(mtd); + } else { + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) + bch_data_ecc_correct_noalign(mtd); + else + bch_data_ecc_correct(mtd); + } + } else { + printk("read page error but not ecc error sts=0x%x\n",bank_stat1); + print_nand_register(mtd); + //while(1); + } + } else if (info->isr_cmd == 0x50) { + //print_nand_register(mtd); + wmt_wait_nfc_ready(info); + bank_stat1 = readb(info->reg + NFCRb_NFC_INT_STAT); + if (bank_stat1&(ERR_CORRECT | BCH_ERR)) { + while ((bank_stat1&(ERR_CORRECT|BCH_ERR)) != (ERR_CORRECT|BCH_ERR)) { + bank_stat2++; + bank_stat1 = readb(info->reg + NFCRb_NFC_INT_STAT); + if (bank_stat2 >= 0x10000) { + printk("oob ecc error, but ecc correct not assert ecc status=0x%x\n",bank_stat1); + print_nand_register(mtd); + //while(1); + break; + } + } + bank_stat2 = readb(info->reg + NFCRd_OOB_CTRL)&OOB_READ; + if (!bank_stat2) + printk("oob cmd error, but oob flag is not set\n"); + bch_redunt_ecc_correct(mtd); + } + writeb((B2R | ERR_CORRECT | BCH_ERR), info->reg + NFCRb_NFC_INT_STAT); + status = NFC_WAIT_IDLE(mtd); + if (status) + printk("B2R isr not ecc error occurs, but idle fail\n"); + WARN_ON(info->done_data == NULL); + complete(info->done_data); + info->done_data = NULL; + } else /*if (info->isr_cmd != 0 && info->isr_cmd != 0x50) */{ + /* only erase/write operation enter for B2R interrupt */ + intsts = readb(info->reg + NFCRb_NFC_INT_STAT); + if (intsts&B2R) { + writeb(B2R, info->reg + NFCRb_NFC_INT_STAT); + if (readb(info->reg + NFCRb_NFC_INT_STAT) & B2R) + printk("[nfc_isr] erase/write cmd B2R staus can't clear\n"); + } else + printk("[nfc_isr] erase/write cmd B2R staus not assert\n"); + + status = (readb(info->reg + NFCR13_INT_MASK)&0xFF); + if ((status&0x1C) != 0x18) { + printk("[nfc_isr] isr is not check busy interrup =0x%x\n", status); + dump_stack(); + print_nand_register(mtd); + //while(info->isr_cmd); + } + + WARN_ON(info->done_data == NULL); + complete(info->done_data); + info->done_data = NULL; + } + //spin_unlock(&host->lock); + enable_irq(irq); + + return IRQ_HANDLED; +} + +static void wmt_set_logo_offset(void) +{ + int ret1; + int err = 0, ret = 0, status = 0, i; + unsigned char varval[100], tmp[100]; + unsigned int varlen; + unsigned long long offs_data = 0; + + err = search_mtd_table("u-boot-logo", &ret1); + ret = (int) ret1; + varlen = 100; + status = wmt_getsyspara("wmt.nfc.mtd.u-boot-logo", tmp, &varlen); + for (i = 0; i < ret; i++) + offs_data += nand_partitions[i].size; + sprintf(varval, "0x%llx", offs_data); + if (!status && (strcmp(varval, tmp) == 0)) + status = 0; + else + status = 1; + if (!err && status) { + ret = wmt_setsyspara("wmt.nfc.mtd.u-boot-logo", varval); + if (ret) + printk(KERN_NOTICE "write u-boot-logo offset to env fail\n"); + } else if (err) + printk(KERN_NOTICE "search u-boot-logo partition fail\n"); + + err = search_mtd_table("kernel-logo", &ret1); + ret = (int) ret1; + varlen = 100; + status = wmt_getsyspara("wmt.nfc.mtd.kernel-logo", tmp, &varlen); + offs_data = 0; + for (i = 0; i < ret; i++) + offs_data += nand_partitions[i].size; + sprintf(varval, "0x%llx", offs_data); + if (!status && (strcmp(varval, tmp) == 0)) + status = 0; + else + status = 1; + if (!err && status) { + ret = wmt_setsyspara("wmt.nfc.mtd.kernel-logo", varval); + if (ret) + printk(KERN_NOTICE "write kernel-logo offset to env fail\n"); + } else if (err) + printk(KERN_NOTICE "search kernel-logo partition fail\n"); + +} + +#if 0 +static void wmt_set_partition_info(struct nand_chip *chip) +{ + int ret = 0, status = 0, i, j; + unsigned char varval[256], tmp[256]; + unsigned int varlen = 256; + unsigned int offs_data, size; + + varval[0] = '\0'; + for (i = 0; i < NUM_NAND_PARTITIONS; i++) { + if (&nand_partitions[i]) { + offs_data = 0; + for (j = 0; j < i; j++) + offs_data += (unsigned int)(nand_partitions[j].size>>20); + if (i < (NUM_NAND_PARTITIONS - 1)) + size = (unsigned int)(nand_partitions[i].size>>20); + else + size = (unsigned int)(chip->chipsize>>20) - offs_data; + + if (i == 0) + sprintf(tmp, "%dm@%dm(%s)", size, offs_data, nand_partitions[i].name); + else + sprintf(tmp, ",%dm@%dm(%s)", size, offs_data, nand_partitions[i].name); + strcat(varval, tmp); + } else + break; + } + printk(KERN_DEBUG "fbparts=%s\n", varval); + status = wmt_getsyspara("fbparts", tmp, &varlen); + if (status) { + printk(KERN_DEBUG "fbparts not found varlen=256=>%d\n", varlen); + ret = wmt_setsyspara("fbparts", varval); + } else { + if (strcmp(tmp, varval) != 0) { + printk(KERN_DEBUG "tmp=%s\n", tmp); + printk(KERN_WARNING "fbparts not sync => update\n"); + ret = wmt_setsyspara("fbparts", varval); + } else + printk(KERN_DEBUG "fbparts env compare pass\n"); + } + if (ret) + printk(KERN_ERR "set fbparts env fail\n"); +} +#endif + +void set_ecc_info(struct mtd_info *mtd) +{ + unsigned int ecc_bit_mode; + struct ECC_size_info ECC_size, *ECC_size_pt; + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + + ecc_bit_mode = mtd->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); + + info->ECC_mode = ECC_size.ecc_engine = ecc_bit_mode; + calculate_ECC_info(mtd, &ECC_size); + writew((ECC_size.oob_ECC_bytes<<8) /*+ (ECC_size.unprotect&0xFF)*/, info->reg + NFCR10_OOB_ECC_SIZE); + info->oob_ECC_bytes = ECC_size.oob_ECC_bytes; + if ((mtd->pageSizek >> (ffs(mtd->pageSizek)-1)) != 1) { + info->last_bank_dmaaddr = info->dmaaddr + mtd->realwritesize; + info->oob_col = mtd->realwritesize + (ECC_size.ECC_bytes * ECC_size.banks); + info->last_bank_col = info->oob_col; + } else { + info->last_bank_dmaaddr = info->dmaaddr + mtd->realwritesize - ECC_size.bank_size; + info->oob_col = mtd->realwritesize + (ECC_size.ECC_bytes * (ECC_size.banks-1)); + info->last_bank_col = info->oob_col - ECC_size.bank_size; + } + info->oob_ECC_mode = ECC_size.oob_ECC_mode; + info->oob_ecc_error = 0; + info->banks = ECC_size.banks; + info->bank_size = ECC_size.bank_size; + info->oob_max_bit_error = ECC_size.oob_max_bit_error; + + ECC_size_pt = &ECC_size; + wmt_nand_init_chip(mtd, ECC_size_pt); + + printk(KERN_DEBUG "last_bank_dmaaddr=0x%x banks=%d\n", info->last_bank_dmaaddr, info->banks); + printk(KERN_DEBUG "oob_col=%d\n", info->oob_col); + printk(KERN_DEBUG "last_bank_col=%d\n", info->last_bank_col); + + printk(KERN_NOTICE "BCH ECC %d BIT mode\n", mtd->dwECCBitNum); + set_ecc_engine(info, ecc_bit_mode); /* BCH ECC new structure */ +} + +void set_partition_size(struct mtd_info *mtd) +{ + int ret, index; + char varval[256], partition_name[32]; + int varlen = 256; + char *s = NULL, *tmp = NULL; + uint64_t part_size = 0; + struct nand_chip *chip = mtd->priv; + + if(((mtd->id>>24)&0xff) == NAND_MFR_HYNIX) { + if(chip->realplanenum == 1) { + nand_partitions[0].size = 0x4000000; + nand_partitions[1].size = 0x4000000; + nand_partitions[2].size = 0x4000000; + } else { + nand_partitions[0].size = 0x2000000; + nand_partitions[1].size = 0x2000000; + nand_partitions[2].size = 0x2000000; + } + } + + if ((mtd->pageSizek >> (ffs(mtd->pageSizek) - 1)) != 1) { + if (mtd->pageSizek == 12) { + nand_partitions[0].size = 0x1080000; + nand_partitions[1].size = 0x1080000; + nand_partitions[2].size = 0x1080000; + nand_partitions[3].size = 0x1080000; + nand_partitions[4].size = 0x4200000; + nand_partitions[5].size = 0x30000000; + nand_partitions[6].size = 0x20100000; + nand_partitions[7].size = MTDPART_SIZ_FULL; + } else if (mtd->pageSizek == 28) { + nand_partitions[0].size = 0x3800000; + nand_partitions[1].size = 0x3800000; + nand_partitions[2].size = 0x3800000; + nand_partitions[3].size = 0x1c00000; + nand_partitions[4].size = 0x7000000; + nand_partitions[5].size = 0x31000000; + nand_partitions[6].size = 0x21400000; + nand_partitions[7].size = 0x1c000000; + nand_partitions[8].size = MTDPART_SIZ_FULL; + } + //printk("(pageSizek>>(ffs(pageSizek)-1)=%d\n", mtd->pageSizek >> (ffs(mtd->pageSizek)-1)); + } + + ret = wmt_getsyspara("wmt.nand.partition", varval, &varlen); + if(ret == 0) { + printk("wmt.nand.partition: %s\n", varval); + s = varval; + while(*s != '\0') + { + index = NUM_NAND_PARTITIONS; + memset(partition_name, 0, 32); + get_partition_name(s, &tmp, partition_name); + search_mtd_table(partition_name, &index); + s = tmp + 1; + part_size = simple_strtoul(s, &tmp, 16); + s = tmp; + if(*s == ':') + s++; + + //data can't be resized by uboot env, its size is left whole nand. + if((index >= 0) && (index < (NUM_NAND_PARTITIONS-1)) && (part_size < chip->chipsize)) { + nand_partitions[index].size = part_size; + } else { + printk("Invalid parameter \"wmt.nand.partition\". Use default partition size for \"%s\" partition.\n", partition_name); + } + } + } + + + + if(((mtd->id>>24)&0xff) == NAND_MFR_HYNIX) { + par1_ofs = nand_partitions[0].size; + par2_ofs = par1_ofs + nand_partitions[1].size; + par3_ofs = par2_ofs + nand_partitions[2].size; + par4_ofs = par3_ofs + nand_partitions[3].size; + + par1_ofs = ((unsigned int )(par1_ofs >> 10))/mtd->pageSizek; + par2_ofs = ((unsigned int )(par2_ofs >> 10))/mtd->pageSizek; + par3_ofs = ((unsigned int )(par3_ofs >> 10))/mtd->pageSizek; + par4_ofs = ((unsigned int )(par4_ofs >> 10))/mtd->pageSizek; + } + + + + /*min_partition_size = 0; + for (i = 0; i < 11; i++) + min_partition_size += nand_partitions[i].size; + nand_partitions[11].size = chip->chipsize - min_partition_size - (mtd->erasesize * 8);*/ +} + +void init_wr_cache(struct mtd_info *mtd) +{ + struct wmt_nand_info *info = wmt_nand_mtd_toinfo(mtd); + int i; + + for (i = 0; i < WR_BUF_CNT; i++) + info->wr_page[i] = -1; +} + +int alloc_write_cache(struct mtd_info *mtd) +{ + wr_cache = vmalloc((mtd->writesize+32)*WR_BUF_CNT); + if (!wr_cache) { + printk(KERN_ERR"wr_cache=0x%x alloc fail\n", (mtd->writesize+32)*WR_BUF_CNT); + return 1; + } + + return 0; +} + +int alloc_rdmz_buffer(struct mtd_info *mtd) +{ + if (mtd->dwRdmz == 1) { + buf_rdmz = vmalloc(mtd->writesize); + if (!buf_rdmz) { + printk(KERN_ERR"buf_rdmz alloc fail\n"); + return 1; + } + } + return 0; +} + +static int nandinfo_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) { + char mfr_name[32]; + int len = 0; + int mfr =(mtd_nandinfo->id>>24)&0xff; + + switch(mfr) { + case NAND_MFR_SANDISK: + strcpy(mfr_name, "Sandisk"); + break; + case NAND_MFR_HYNIX: + strcpy(mfr_name, "Hynix"); + break; + case NAND_MFR_TOSHIBA: + strcpy(mfr_name, "Toshiba"); + break; + case NAND_MFR_SAMSUNG: + strcpy(mfr_name, "Samsung"); + break; + case NAND_MFR_MICRON: + strcpy(mfr_name, "Micron"); + break; + case NAND_MFR_INTEL: + strcpy(mfr_name, "Intel"); + break; + default: + strcpy(mfr_name, "Unknown"); + break; + } + + len = sprintf(page, "Manufacturer : %s\n" + "nand id1 : %lu\n" + "nand id2 : %lu\n" , mfr_name, mtd_nandinfo->id, mtd_nandinfo->id2); + return len; +} + +extern int wmt_recovery_call(struct notifier_block *nb, unsigned long code, void *_cmd); +static int wmt_nand_probe(struct platform_device *pdev) +{ + /* struct wmt_platform_nand *plat = to_nand_plat(pdev);*/ + /*struct device *dev = &pdev->dev;*/ + struct wmt_nand_platform_data *pdata = pdev->dev.platform_data; + struct wmt_nand_info *info; + struct wmt_nand_mtd *nmtd; + struct mtd_info *mtd; + static const char *part_parsers[] = {"cmdlinepart", NULL}; + /*struct mtd_part_parser_data ppdata;*/ + /* struct wmt_nand_set *sets; */ /* extend more chips and partitions structure*/ + struct resource *res; + int err = 0, ret = 0; + int size; + /* ------------------------*/ + unsigned char sd_buf[80]; + int sd_varlen = 80; + char *varname = "wmt.sd1.param"; + int sd_enable = 0, SD1_function = 0; /*0 :disable 1:enable*/ + /* ------------------------*/ + buf_rdmz = NULL; + wr_cache = NULL; + prob_end = 0; + eslc_write = 0; + /* int nr_sets;*/ + /* int setno;*/ + pr_debug("wmt_nand_probe(%p)\n", pdev); + ret = wmt_getsyspara("wmt.boot.dev", sd_buf, &sd_varlen); + printk("wmt.boot.dev ret = %d\n", ret); + if(!ret && (!strncmp(sd_buf, "TF", 2) || (!strncmp(sd_buf, "UDISK", 5)))) + { + printk("Boot from SD card or udisk card.\n"); + return -1; + } + + /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/ + ret = wmt_getsyspara(varname, sd_buf, &sd_varlen); + if (ret == 0) { + sscanf(sd_buf,"%d:%d", &sd_enable,&SD1_function); + if (sd_enable == 1) { + printk(KERN_NOTICE "SD1 enabled => NAND probe disabled\n"); + return -EINVAL; + } + } + /*err = -EINVAL; + return err;*/ + *(volatile unsigned int *)(GPIO_BASE_ADDR + 0x200) &= ~(1<<11); /*PIN_SHARE_SDMMC1_NAND*/ + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + dev_err(&pdev->dev, "no memory for flash info\n"); + err = -ENOMEM; + goto exit_error; + } + + memzero(info, sizeof(*info)); + dev_set_drvdata(&pdev->dev, info); + platform_get_resource(pdev, IORESOURCE_MEM, 0); + + ret = request_irq(IRQ_NFC, + nfc_regular_isr, + IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED? + "NFC", + (void *)info); + if (ret) { + printk(KERN_ALERT "[NFC driver] Failed to register regular ISR!\n"); + goto unmap; + } + + ret = request_irq(IRQ_NFC_DMA, + nfc_pdma_isr, + IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian + "NFC", + (void *)info); + if (ret) { + printk(KERN_ALERT "[NFC driver] Failed to register DMA ISR!\n"); + goto fr_regular_isr; + } + spin_lock_init(&info->controller.lock); + init_waitqueue_head(&info->controller.wq); + + /* allocate and map the resource */ + + /* currently we assume we have the one resource */ + res = pdev->resource; + size = res->end - res->start + 1; + + info->area = request_mem_region(res->start, size, pdev->name); + info->oper_step = 0; + + + if (info->area == NULL) { + dev_err(&pdev->dev, "cannot reserve register region\n"); + err = -ENOENT; + goto exit_error; + } + + info->device = &pdev->dev; + /* info->platform = plat;*/ + info->reg = (void __iomem *)NF_CTRL_CFG_BASE_ADDR;/*ioremap(res->start, size);*/ + /* info->cpu_type = cpu_type;*/ + + if (info->reg == NULL) { + dev_err(&pdev->dev, "cannot reserve register region\n"); + err = -EIO; + goto exit_error; + } + +/* + * * extend more partitions + * + err = wmt_nand_inithw(info, pdev); + if (err != 0) + goto exit_error; + + sets = (plat != NULL) ? plat->sets : NULL; + nr_sets = (plat != NULL) ? plat->nr_sets : 1; + + info->mtd_count = nr_sets; +*/ + /* allocate our information */ + +/* size = nr_sets * sizeof(*info->mtds);*/ + size = sizeof(*info->mtds); + info->mtds = kmalloc(size, GFP_KERNEL); + if (info->mtds == NULL) { + dev_err(&pdev->dev, "failed to allocate mtd storage\n"); + err = -ENOMEM; + goto exit_error; + } + + memzero(info->mtds, size); + + /* initialise all possible chips */ + + nmtd = info->mtds; + + mtd = &nmtd->mtd; + info->dmabuf = dma_alloc_coherent(&pdev->dev, 40960, &info->dmaaddr, GFP_KERNEL); + + if (!info->dmabuf && (info->dmaaddr & 0x0f)) { + err = -ENOMEM; + goto out_free_dma; + } + /* nmtd->chip.buffers = (void *)info->dmabuf + 2112;*/ + + nmtd->chip.cmdfunc = wmt_nand_cmdfunc; + nmtd->chip.dev_ready = wmt_device_ready; + nmtd->chip.read_byte = wmt_read_byte; + nmtd->chip.write_buf = wmt_nand_write_buf; + nmtd->chip.read_buf = wmt_nand_read_buf; + nmtd->chip.select_chip = wmt_nand_select_chip; + nmtd->chip.get_para = nand_get_para; + nmtd->chip.chip_delay = 20; + nmtd->chip.priv = nmtd; + nmtd->chip.bbt_options = NAND_BBT_LASTBLOCK | NAND_BBT_USE_FLASH | NAND_BBT_PERCHIP | NAND_BBT_NO_OOB_BBM; + /* nmtd->chip.controller = &info->controller;*/ + + /*nmtd->chip.ecc.steps = 1; + nmtd->chip.ecc.prepad = 1; + nmtd->chip.ecc.postpad = 8;*/ + + nmtd->chip.ecc.mode = NAND_ECC_HW; + /*nmtd->chip.ecc.mode = 0;*/ + + + /* for (setno = 0; setno < nr_sets; setno++, nmtd++)*/ + #ifdef NAND_DEBUG + printk(KERN_NOTICE "initialising (%p, info %p)\n", nmtd, info); + #endif + + /* Set up DMA address */ + /*writel(info->dmaaddr & 0xffffffff, info->reg + NFC_DMA_DAR);*/ + + /*info->dmabuf = readl(info->reg + WMT_NFC_DMA_TRANS_CONFIG);*/ + + /* nmtd->nand.chip_delay = 0;*/ + + /* Enable the following for a flash based bad block table */ + /* nmtd->nand.options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR | NAND_OWN_BUFFERS;*/ + + nmtd->chip.bbt_td = &wmt_bbt_main_descr_2048; + nmtd->chip.bbt_md = &wmt_bbt_mirror_descr_2048; + nmtd->chip.retry_pattern = &wmt_rdtry_descr; + nmtd->chip.cur_chip = NULL; + + nmtd->info = info; + nmtd->mtd.priv = &nmtd->chip; + nmtd->mtd.owner = THIS_MODULE; + nmtd->mtd.reboot_notifier.notifier_call = wmt_recovery_call;//Lch + {/*unsigned int s1, s2; + s1 = wmt_read_oscr();*/ + ret = reset_nfc(mtd, NULL, 3); + //s2 = wmt_read_oscr();printk("s2-s1=%d------------\n", (s2-s1)/3); + } + set_ecc_engine(info, 1); + + info->datalen = 0; + /* initialise the hardware */ + wmt_nfc_init(info, &nmtd->mtd); + writeb(0xff, info->reg + NFCR12_NAND_TYPE_SEL+1); //chip disable + + /*rc = set_ECC_mode(mtd); + if (rc) + goto out_free_dma;*/ + + nmtd->chip.ecc.layout = &wmt_oobinfo_16k; + writeb(0x0, info->reg + NFCR11_SOFT_RST); + + nmtd->scan_res = nand_scan(&nmtd->mtd, MAX_CHIP); + /*nmtd->scan_res = nand_scan(&nmtd->mtd, (sets) ? sets->nr_chips : 1);*/ + + if (nmtd->chip.cur_chip && mtd->dwRetry && ((mtd->id>>24)&0xFF) == NAND_MFR_SANDISK) { + /* Activating and initializing Dynamic Read Register */ + auto_pll_divisor(DEV_NAND, CLK_ENABLE, 0, 0); + sandisk_init_retry_register(mtd, nmtd->chip.cur_chip); + auto_pll_divisor(DEV_NAND, CLK_DISABLE, 0, 0); + } + + if (nmtd->scan_res == 0) { + if (pdata) + pdata->partitions = nand_partitions; + + ret = mtd_device_parse_register(mtd, part_parsers, NULL/*&ppdata*/, + pdata ? pdata->partitions : nand_partitions, + pdata ? NUM_NAND_PARTITIONS : NUM_NAND_PARTITIONS); + + if (ret) { + dev_err(&pdev->dev, "Failed to add mtd device\n"); + goto out_free_dma; + } + } + + //wmt_set_logo_offset(); + + /* write back mtd partition to env */ + /* wmt_set_partition_info(&nmtd->chip); */ + + nandinfo_proc = create_proc_entry(NANDINFO, 0666, NULL); + if(nandinfo_proc == NULL) { + printk("Failed to create nandinfo proccess device\n"); + goto out_free_dma; + } else { + mtd_nandinfo = mtd; + } + nandinfo_proc->read_proc = nandinfo_proc_read; + + register_reboot_notifier(&mtd->reboot_notifier);//Lch + + /*if (((mtd->id>>24)&0xFF) == NAND_MFR_HYNIX) { + auto_pll_divisor(DEV_NAND, CLK_ENABLE, 0, 0); + writel(0x1312, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + printk("prob_end timing=%x\n",readl(info->reg + NFCR14_READ_CYCLE_PULE_CTRL)); + auto_pll_divisor(DEV_NAND, CLK_DISABLE, 0, 0); + }*/ + + auto_pll_divisor(DEV_NAND, CLK_ENABLE, 0, 0); + if (!mtd->dwDDR) { + writeb(RD_DLY|readb(info->reg + NFCR12_NAND_TYPE_SEL), info->reg + NFCR12_NAND_TYPE_SEL); + writel(0x1212, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + } else { + //writel(0x0101, info->reg + NFCR14_READ_CYCLE_PULE_CTRL); + while ((*(volatile unsigned long *)(PMCS_ADDR+0x18))&0x7F0038) + ; + *(volatile unsigned long *)PMNAND_ADDR = (*(volatile unsigned long *)PMNAND_ADDR) - 5; + } + printk("prob_end timing=%x nfcr12%x divisor=0x%x\n",readl(info->reg + NFCR14_READ_CYCLE_PULE_CTRL), + readb(info->reg + NFCR12_NAND_TYPE_SEL), *(volatile unsigned long *)PMNAND_ADDR); + auto_pll_divisor(DEV_NAND, CLK_DISABLE, 0, 0); + + init_wr_cache(mtd); + + printk(KERN_NOTICE "nand initialised ok\n"); + prob_end = 1; + second_chip = 0; + return 0; + +out_free_dma: + dma_free_coherent(&pdev->dev, 32000/*17664 + 0x300*/, info->dmabuf, info->dmaaddr); + +fr_regular_isr: +unmap: +exit_error: + wmt_nand_remove(pdev); + + if (err == 0) + err = -EINVAL; + return err; +} + +/* PM Support */ +#ifdef CONFIG_PM +int wmt_nand_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct wmt_nand_info *info = dev_get_drvdata(&pdev->dev); + struct mtd_info *mtd = &info->mtds->mtd; + + /*nand_suspend->nand_get_device*/ + mtd_suspend(mtd); + + if ((STRAP_STATUS_VAL&0x400E) == 0x4008) { + auto_pll_divisor(DEV_NAND, CLK_ENABLE, 0, 0); + *(volatile unsigned long *)(NF_CTRL_CFG_BASE_ADDR + 0x44) |= (1<<1); + printk(KERN_NOTICE "reset nand boot register NF_CTRL_CFG_BASE_ADDR + 0x44\n"); + *(volatile unsigned long *)(NF_CTRL_CFG_BASE_ADDR + 0x44) &= ~(1<<1); + } + printk(KERN_NOTICE "wmt_nand_suspend\n"); + return 0; +} + +int wmt_nand_resume(struct platform_device *pdev) +{ + struct wmt_nand_info *info = dev_get_drvdata(&pdev->dev); + struct mtd_info *mtd = &info->mtds->mtd; + struct wmt_nand_mtd *nmtd; + struct nand_chip *chip; + unsigned char reset = NAND_CMD_RESET; + int i; + auto_pll_divisor(DEV_NAND, CLK_ENABLE, 0, 0); + if (info) { + nmtd = info->mtds; + chip = nmtd->mtd.priv; + //if ((STRAP_STATUS_VAL&0x400E) == 0x4008) + writeb(0x0, info->reg + NFCR11_SOFT_RST); + /* initialise the hardware */ + wmt_nfc_init(info, &nmtd->mtd); + set_ecc_engine(info, info->ECC_mode); /* BCH ECC */ + writew((info->oob_ECC_bytes<<8) /*+ (ECC_size.unprotect&0xFF)*/, info->reg + NFCR10_OOB_ECC_SIZE); + + if ((&nmtd->mtd)->dwDDR) + writeb(0x7F, info->reg + NFCR7_DLYCOMP); + wmt_nand_select_chip(&nmtd->mtd, 0); + write_bytes_cmd(&nmtd->mtd, 1, 0, 0, (uint8_t *)&reset, NULL, NULL); + for (i = 1; i < chip->numchips; i++) { + wmt_nand_select_chip(&nmtd->mtd, i); + write_bytes_cmd(&nmtd->mtd, 1, 0, 0, (uint8_t *)&reset, NULL, NULL); + } + wmt_init_nfc(&nmtd->mtd, nmtd->mtd.spec_clk, nmtd->mtd.spec_tadl, 0); + wmt_nand_select_chip(&nmtd->mtd, -1); + + if ((&nmtd->mtd)->dwRdmz) { + nfc_hw_rdmz(&nmtd->mtd, 1); + writeb(0, info->reg + NFCR4_COMPORT3_4); + } + printk(KERN_NOTICE "wmt_nand_resume OK\n"); + } else + printk(KERN_NOTICE "wmt_nand_resume error\n"); + + auto_pll_divisor(DEV_NAND, CLK_DISABLE, 0, 0); + + /*nand_resume->nand_release_device*/ + mtd_resume(mtd); + + return 0; +} + +#else /* else of #define PM */ +#define wmt_nand_suspend NULL +#define wmt_nand_resume NULL +#endif + +/*struct platform_driver wmt_nand_driver = {*/ +struct platform_driver wmt_nand_driver = { + .driver.name = "nand", + .probe = wmt_nand_probe, + .remove = wmt_nand_remove, + .suspend = wmt_nand_suspend, + .resume = wmt_nand_resume + /* + .driiver = { + .name = "wmt-nand", + .owner = THIS_MODULE, + }, + */ +}; + +static int __init wmt_nand_init(void) +{ + //printk(KERN_NOTICE "NAND Driver, WonderMedia Technologies, Inc\n"); + return platform_driver_register(&wmt_nand_driver); +} + +static void __exit wmt_nand_exit(void) +{ + platform_driver_unregister(&wmt_nand_driver); +} + +module_init(wmt_nand_init); +module_exit(wmt_nand_exit); + +MODULE_AUTHOR("WonderMedia Technologies, Inc."); +MODULE_DESCRIPTION("WMT [Nand Flash Interface] driver"); +MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/mtd/nand/wmt_nand.h b/ANDROID_3.4.5/drivers/mtd/nand/wmt_nand.h new file mode 100755 index 00000000..e5692ac7 --- /dev/null +++ b/ANDROID_3.4.5/drivers/mtd/nand/wmt_nand.h @@ -0,0 +1,365 @@ +/*++ + Copyright (c) 2008 WonderMedia Technologies, Inc. All Rights Reserved. + + This PROPRIETARY SOFTWARE is the property of WonderMedia Technologies, Inc. + and may contain trade secrets and/or other confidential information of + WonderMedia Technologies, Inc. This file shall not be disclosed to any third + party, in whole or in part, without prior written consent of WonderMedia. + + THIS PROPRIETARY SOFTWARE AND ANY RELATED DOCUMENTATION ARE PROVIDED AS IS, + WITH ALL FAULTS, AND WITHOUT WARRANTY OF ANY KIND EITHER EXPRESS OR IMPLIED, + AND WonderMedia TECHNOLOGIES, INC. DISCLAIMS ALL EXPRESS OR IMPLIED WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR + NON-INFRINGEMENT. + + Module Name: + + $Workfile: post_nand.c $ + + Abstract: + + POST functions, called by main(). + + Revision History: + + Dec.04.2008 First created + Dec.19.2008 Dannier change coding style and support spi flash boot with nor accessible. + $JustDate: 2008/12/19 $ +--*/ + +#ifndef __NFC_H__ +#define __NFC_H__ + +/* include/asm-arm/arch-vt8630.h or arch-vt8620.h or include/asm-zac/arch-vt8620.h or arch-vt8630.h */ +/* #define NFC_BASE_ADDR 0xd8009000 */ + +#define NFCR0_DATAPORT 0x00 +#define NFCR1_COMCTRL 0x04 +#define NFCR2_COMPORT0 0x08 +#define NFCR3_COMPORT1_2 0x0c +#define NFCR4_COMPORT3_4 0x10 +#define NFCR5_COMPORT5_6 0x14 +#define NFCR6_COMPORT7 0x18 +#define NFCR7_DLYCOMP 0x1c +#define NFCR8_DMA_CNT 0x20 +#define NFCR9_ECC_BCH_CTRL 0x24 +#define NFCRa_NFC_STAT 0x28 +#define NFCRb_NFC_INT_STAT 0x2c +#define NFCRc_CMD_ADDR 0x30 +#define NFCRd_OOB_CTRL 0x34 +#define NFCRe_CALC_TADL 0x38 +#define NFCRf_CALC_RDMZ 0x3c +#define NFCR10_OOB_ECC_SIZE 0x40 +#define NFCR11_SOFT_RST 0x44 +#define NFCR12_NAND_TYPE_SEL 0x48 +#define NFCR13_INT_MASK 0x4c +#define NFCR14_READ_CYCLE_PULE_CTRL 0x50 +#define NFCR15_IDLE_STAT 0x54 +#define NFCR16_TIMER_CNT_CFG 0x58 +#define NFCR17_ECC_BCH_ERR_STAT 0x5c +#define NFCR18_ECC_BCH_ERR_POS 0x60 + +#define ECC_FIFO_0 0x1c0 +#define ECC_FIFO_1 0x1c4 +#define ECC_FIFO_2 0x1c8 +#define ECC_FIFO_3 0x1cc +#define ECC_FIFO_4 0x1d0 +#define ECC_FIFO_5 0x1d4 +#define ECC_FIFO_6 0x1d8 +#define ECC_FIFO_7 0x1dc +#define ECC_FIFO_8 0x1e0 +#define ECC_FIFO_9 0x1e4 +#define ECC_FIFO_a 0x1e8 +#define ECC_FIFO_b 0x1ec +#define ECC_FIFO_c 0x1f0 +#define ECC_FIFO_d 0x1f4 +#define ECC_FIFO_e 0x1f8 +#define ECC_FIFO_f 0x1fc + +struct ECC_size_info{ + int ecc_engine; + int oob_ECC_mode; + int banks; + int bank_size; + int max_bit_error; + int oob_max_bit_error; + int ecc_bits_count; + int oob_ecc_bits_count; + int bank_offset; /* add data + data ecc ex: 512+8 4-bit engine */ + int ECC_bytes; + int oob_ECC_bytes; + int unprotect; +}; +#define ECC1bit 0 +#define ECC4bit 1 +#define ECC8bit 2 +#define ECC12bit 3 +#define ECC16bit 4 +#define ECC24bitPer1K 5 +#define ECC40bitPer1K 6 +#define ECC60bitPer1K 7 +#define ECC44bitPer1K 7 +#define ECC44bit 8 +#define ECC1bit_bit_count 32 +#define ECC4bit_bit_count 52 +#define ECC8bit_bit_count 104 +#define ECC12bit_bit_count 156 +#define ECC16bit_bit_count 208 +#define ECC24bitPer1K_bit_count 336 +#define ECC40bitPer1K_bit_count 560 +#define ECC60bitPer1K_bit_count 830 +#define ECC44bitPer1K_bit_count 616 +#define ECC44bit_bit_count 576 +#define ECC1bit_byte_count 4 +#define ECC4bit_byte_count 8 +#define ECC8bit_byte_count 16 +#define ECC12bit_byte_count 20 +#define ECC16bit_byte_count 26 +#define ECC24bitPer1K_byte_count 42 +#define ECC40bitPer1K_byte_count 70 +#define ECC60bitPer1K_byte_count 106 +#define ECC44bitPer1K_byte_count 77 +#define ECC44bit_byte_count 72 +#define ECC1bit_unprotect 0 +#define ECC4bit_unprotect 0 +#define ECC8bit_unprotect 50 +#define ECC12bit_unprotect 14 +#define ECC16bit_unprotect 26 +#define ECC24bitPer1K_unprotect 34 +#define ECC40bitPer1K_unprotect 14 +#define ECC60bitPer1K_unprotect 46 //8k+960 +#define ECC44bitPer1K_unprotect 14 +#define ECC44bit_unprotect 72 +#define MAX_BANK_SIZE 1024 +#define MAX_PARITY_SIZE 106 +#define MAX_ECC_BIT_ERROR 60 +/* + * NAND PDMA + */ +#define NAND_DESC_BASE_ADDR 0x00D00000 + +#define NFC_DMA_GCR 0x100 +#define NFC_DMA_IER 0x104 +#define NFC_DMA_ISR 0x108 +#define NFC_DMA_DESPR 0x10C +#define NFC_DMA_RBR 0x110 +#define NFC_DMA_DAR 0x114 +#define NFC_DMA_BAR 0x118 +#define NFC_DMA_CPR 0x11C +#define NFC_DMA_CCR 0X120 + +#define NAND_GET_FEATURE 0xEE +#define NAND_SET_FEATURE 0xEF +/* + * NAND PDMA - DMA_GCR : DMA Global Control Register + */ +#define NAND_PDMA_GCR_DMA_EN 0x00000001 /* [0] -- DMA controller enable */ +#define NAND_PDMA_GCR_SOFTRESET 0x00000100 /* [8] -- Software rest */ + +/* + * NAND PDMA - DMA_IER : DMA Interrupt Enable Register + */ +#define NAND_PDMA_IER_INT_EN 0x00000001 /* [0] -- DMA interrupt enable */ +/* + * NAND PDMA - DMA_ISR : DMA Interrupt Status Register + */ +#define NAND_PDMA_IER_INT_STS 0x00000001 /* [0] -- DMA interrupt status */ +/* + * NAND PDMA - DMA_DESPR : DMA Descriptor base address Pointer Register + */ + +/* + * NAND PDMA - DMA_RBR : DMA Residual Bytes Register + */ +#define NAND_PDMA_RBR_End 0x80000000 /* [31] -- DMA descriptor end flag */ +#define NAND_PDMA_RBR_Format 0x40000000 /* [30] -- DMA descriptor format */ +/* + * NAND PDMA - DMA_DAR : DMA Data Address Register + */ + +/* + * NAND PDMA - DMA_BAR : DMA Rbanch Address Register + */ + +/* + * NAND PDMA - DMA_CPR : DMA Command Pointer Register + */ + +/* + * NAND PDMA - DMA_CCR : DMAContext Control Register for Channel 0 + */ +#define NAND_PDMA_READ 0x00 +#define NAND_PDMA_WRITE 0x01 +#define NAND_PDMA_CCR_RUN 0x00000080 +#define NAND_PDMA_CCR_IF_to_peripheral 0x00000000 +#define NAND_PDMA_CCR_peripheral_to_IF 0x00400000 +#define NAND_PDMA_CCR_EvtCode 0x0000000f +#define NAND_PDMA_CCR_Evt_no_status 0x00000000 +#define NAND_PDMA_CCR_Evt_ff_underrun 0x00000001 +#define NAND_PDMA_CCR_Evt_ff_overrun 0x00000002 +#define NAND_PDMA_CCR_Evt_desp_read 0x00000003 +#define NAND_PDMA_CCR_Evt_data_rw 0x00000004 +#define NAND_PDMA_CCR_Evt_early_end 0x00000005 +#define NAND_PDMA_CCR_Evt_success 0x0000000f + +/* + * PDMA Descriptor short + */ +struct _NAND_PDMA_DESC_S{ + unsigned int volatile ReqCount : 16; /* bit 0 -15 -Request count */ + unsigned int volatile i : 1; /* bit 16 -interrupt */ + unsigned int volatile reserve : 13; /* bit 17-29 -reserved */ + unsigned int volatile format : 1; /* bit 30 -The descriptor format */ + unsigned int volatile end : 1; /* bit 31 -End flag of descriptor list*/ + unsigned int volatile DataBufferAddr : 32;/* bit 31 -Data Buffer address */ +}; + +/* + * PDMA Descriptor long + */ +struct _NAND_PDMA_DESC_L{ + unsigned long volatile ReqCount : 16; /* bit 0 -15 -Request count */ + unsigned long volatile i : 1; /* bit 16 -interrupt */ + unsigned long volatile reserve : 13; /* bit 17-29 -reserved */ + unsigned long volatile format : 1; /* bit 30 -The descriptor format */ + unsigned long volatile end : 1; /* bit 31 -End flag of descriptor list*/ + unsigned long volatile DataBufferAddr : 32;/* bit 31-0 -Data Buffer address */ + unsigned long volatile BranchAddr : 32; /* bit 31-2 -Descriptor Branch address */ + unsigned long volatile reserve0 : 32; /* bit 31-0 -reserved */ +}; + +struct NFC_RW_T { + unsigned int T_R_setup; + unsigned int T_R_hold; + unsigned int T_W_setup; + unsigned int T_W_hold; + unsigned int divisor; + unsigned int T_TADL; + unsigned int T_TWHR; + unsigned int T_TWB; + unsigned int T_RHC_THC; +}; + +/* cfg_1 */ +#define TWHR 0x800 +#define OLD_CMD 0x400 /* enable old command trigger mode */ +#define DPAHSE_DISABLE 0x80 /*disable data phase */ +#define NAND2NFC 0x40 /* direction : nand to controller */ +#define SING_RW 0x20 /* enable signal read/ write command */ +#define MUL_CMDS 0x10 /* support cmd+addr+cmd */ +#define NFC_TRIGGER 0x01 /* start cmd&addr sequence */ +/*cfg_9 */ +#define READ_RESUME 1 //0x100 +#define BCH_INT_EN 0x60 +#define BANK_DR 0x10 +#define DIS_BCH_ECC 0x08 +#define USE_HW_ECC 0 +#define ECC_MODE 7 + +/*cfg_a */ +#define NFC_CMD_RDY 0x04 +#define NFC_BUSY 0x02 /* command and data is being transfer in flash I/O */ +#define FLASH_RDY 0x01 /* flash is ready */ +/*cfg_b */ +#define B2R 0x08 /* status form busy to ready */ +#define ERR_CORRECT 0x2 +#define BCH_ERR 0x1 +/*cfg_d */ +#define HIGH64FIFO 8 /* read high 64 bytes fifo */ +#define OOB_READ 0x4 /* calculate the side info BCH decoder */ +#define RED_DIS 0x2 /* do not read out oob area data to FIFO */ +/*cfg_f */ +#define RDMZ 0x10000 /* enable randomizer */ +#define RDMZH 1 /* enable randomizer */ +/*cfg_12 */ +#define PAGE_512 0 +#define PAGE_2K 1 +#define PAGE_4K 2 +#define PAGE_8K 3 +#define PAGE_16K 4 +#define PAGE_32K 5 +#define WD8 0 +#define WIDTH_16 (1<<3) +#define WP_DISABLE (1<<4) /*disable write protection */ +#define DIRECT_MAP (1<<5) +#define RD_DLY (1<<6) +#define TOGGLE (1<<7) + +/*cfg_13*/ /* Dannier Add */ +#define B2RMEN 0x08 /* interrupt mask enable of nand flash form busy to ready */ +/*cfg_15 */ +#define NFC_IDLE 0x01 +/*cfg_17 status */ +#define BANK_NUM 0x1F00 +#define BCH_ERR_CNT 0x3F +/*cfg_18 */ +#define BCH_ERRPOS0 0x3fff +#define BCH_ERRPOS1 (BCH_ERRPOS0<<16) + +#define ADDR_COLUMN 1 +#define ADDR_PAGE 2 +#define ADDR_COLUMN_PAGE 3 +#define WRITE_NAND_COMMAND(d, adr) do { *(volatile unsigned char *)(adr) = (unsigned char)(d); } while (0) +#define WRITE_NAND_ADDRESS(d, adr) do { *(volatile unsigned char *)(adr) = (unsigned char)(d); } while (0) + + +#define SOURCE_CLOCK 24 +#define MAX_SPEED_MHZ 96 +#define MAX_READ_DELAY 9 /* 8.182 = tSKEW 3.606 + tDLY 4.176 + tSETUP 0.4 */ +#define MAX_WRITE_DELAY 9 /* 8.72 = tDLY 10.24 - tSKEW 1.52*/ + +#define DMA_SINGNAL 0 +#define DMA_INC4 0x10 +#define DMA_INC8 0x20 +/*#define first4k218 0 +#define second4k218 4314 *//* 4096 + 218 */ +#define NFC_TIMEOUT_TIME (HZ*2) + +int nand_init_pdma(struct mtd_info *mtd); +int nand_free_pdma(struct mtd_info *mtd); +int nand_alloc_desc_pool(unsigned int *DescAddr); +int nand_init_short_desc(unsigned int *DescAddr, unsigned int ReqCount, unsigned int *BufferAddr, int End); +int nand_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, +unsigned long *BranchAddr, int End); +int nand_config_pdma(struct mtd_info *mtd, unsigned long *DescAddr, unsigned int dir); +int nand_pdma_handler(struct mtd_info *mtd); +void nand_hamming_ecc_1bit_correct(struct mtd_info *mtd); +void bch_data_ecc_correct(struct mtd_info *mtd); +void bch_redunt_ecc_correct(struct mtd_info *mtd); +void bch_data_last_bk_ecc_correct(struct mtd_info *mtd); +void copy_filename (char *dst, char *src, int size); +int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); +int wmt_setsyspara(char *varname, char *varval); +void calculate_ECC_info(struct mtd_info *mtd, struct ECC_size_info *ECC_size); +/*unsigned int wmt_bchencoder (unsigned char *data, unsigned char *bch_code, unsigned char bits, unsigned char *bch_codelen, unsigned int encode_len);*/ +int bch_encoder(unsigned int *p_parity, u32 *p_data, u8 bits, u32 datacnt); +unsigned int Caculat_1b_bch( unsigned int *pariA, unsigned int *bch_GF2, unsigned int din, u8 pari_len, u8 pari_lb); +int Gen_GF2(u8 bits, unsigned int *buf); +int nand_get_feature(struct mtd_info *mtd, int addr); +int nand_set_feature(struct mtd_info *mtd, int cmd, int addrss, int value); +void rdmzier(uint8_t *buf, int size, int page); +void rdmzier_oob(uint8_t *buf, uint8_t *src, int size, int page, int ofs); +int nand_hynix_get_retry_reg(struct mtd_info *mtd, uint8_t *addr, uint8_t *para, int size); +int nand_hynix_set_retry_reg(struct mtd_info *mtd, int reg); +int write_bytes_cmd(struct mtd_info *mtd, int cmd_cnt, int addr_cnt, int data_cnt, uint8_t *cmd, uint8_t *addr, uint8_t *data); +int hynix_read_retry_set_para(struct mtd_info *mtd, int reg); +int load_hynix_opt_reg(struct mtd_info *mtd, struct nand_chip *chip); +void wmt_init_nfc(struct mtd_info *mtd, unsigned int spec_clk, unsigned int spec_tadl, int busw); +void set_ecc_info(struct mtd_info *mtd); +int alloc_rdmz_buffer(struct mtd_info *mtd); +int alloc_write_cache(struct mtd_info *mtd); +void init_wr_cache(struct mtd_info *mtd); +int cache_read_data(struct mtd_info *mtd, struct nand_chip *chip, int page, const uint8_t *buf); +void cache_write_data(struct mtd_info *mtd, struct nand_chip *chip, int page, const uint8_t *buf); +void set_partition_size(struct mtd_info *mtd); +int get_flash_info_from_env(unsigned int id, unsigned int id2, struct WMT_nand_flash_dev *type); +int reset_nfc(struct mtd_info *mtd, unsigned int *buf, int step); +void nfc_hw_rdmz(struct mtd_info *mtd, int on); + + +#define REG_SEED 1 +#define BYTE_SEED 2112 + + + +#endif |