summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/wmt_nand.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/nand/wmt_nand.c')
-rwxr-xr-xdrivers/mtd/nand/wmt_nand.c8285
1 files changed, 8285 insertions, 0 deletions
diff --git a/drivers/mtd/nand/wmt_nand.c b/drivers/mtd/nand/wmt_nand.c
new file mode 100755
index 00000000..0fa2bde0
--- /dev/null
+++ b/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");