1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * (C) 2003 Red Hat, Inc.
4*4882a593Smuzhiyun * (C) 2004 Dan Brown <dan_brown@ieee.org>
5*4882a593Smuzhiyun * (C) 2004 Kalev Lember <kalev@smartlink.ee>
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: David Woodhouse <dwmw2@infradead.org>
8*4882a593Smuzhiyun * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
9*4882a593Smuzhiyun * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Error correction code lifted from the old docecc code
12*4882a593Smuzhiyun * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
13*4882a593Smuzhiyun * Copyright (C) 2000 Netgem S.A.
14*4882a593Smuzhiyun * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * Interface to generic NAND code for M-Systems DiskOnChip devices
17*4882a593Smuzhiyun */
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <linux/kernel.h>
20*4882a593Smuzhiyun #include <linux/init.h>
21*4882a593Smuzhiyun #include <linux/sched.h>
22*4882a593Smuzhiyun #include <linux/delay.h>
23*4882a593Smuzhiyun #include <linux/rslib.h>
24*4882a593Smuzhiyun #include <linux/moduleparam.h>
25*4882a593Smuzhiyun #include <linux/slab.h>
26*4882a593Smuzhiyun #include <linux/io.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
29*4882a593Smuzhiyun #include <linux/mtd/rawnand.h>
30*4882a593Smuzhiyun #include <linux/mtd/doc2000.h>
31*4882a593Smuzhiyun #include <linux/mtd/partitions.h>
32*4882a593Smuzhiyun #include <linux/mtd/inftl.h>
33*4882a593Smuzhiyun #include <linux/module.h>
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* Where to look for the devices? */
36*4882a593Smuzhiyun #ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
37*4882a593Smuzhiyun #define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
38*4882a593Smuzhiyun #endif
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static unsigned long doc_locations[] __initdata = {
41*4882a593Smuzhiyun #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
42*4882a593Smuzhiyun #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
43*4882a593Smuzhiyun 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
44*4882a593Smuzhiyun 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
45*4882a593Smuzhiyun 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
46*4882a593Smuzhiyun 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
47*4882a593Smuzhiyun 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
48*4882a593Smuzhiyun #else
49*4882a593Smuzhiyun 0xc8000, 0xca000, 0xcc000, 0xce000,
50*4882a593Smuzhiyun 0xd0000, 0xd2000, 0xd4000, 0xd6000,
51*4882a593Smuzhiyun 0xd8000, 0xda000, 0xdc000, 0xde000,
52*4882a593Smuzhiyun 0xe0000, 0xe2000, 0xe4000, 0xe6000,
53*4882a593Smuzhiyun 0xe8000, 0xea000, 0xec000, 0xee000,
54*4882a593Smuzhiyun #endif
55*4882a593Smuzhiyun #endif
56*4882a593Smuzhiyun 0xffffffff };
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun static struct mtd_info *doclist = NULL;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun struct doc_priv {
61*4882a593Smuzhiyun struct nand_controller base;
62*4882a593Smuzhiyun void __iomem *virtadr;
63*4882a593Smuzhiyun unsigned long physadr;
64*4882a593Smuzhiyun u_char ChipID;
65*4882a593Smuzhiyun u_char CDSNControl;
66*4882a593Smuzhiyun int chips_per_floor; /* The number of chips detected on each floor */
67*4882a593Smuzhiyun int curfloor;
68*4882a593Smuzhiyun int curchip;
69*4882a593Smuzhiyun int mh0_page;
70*4882a593Smuzhiyun int mh1_page;
71*4882a593Smuzhiyun struct rs_control *rs_decoder;
72*4882a593Smuzhiyun struct mtd_info *nextdoc;
73*4882a593Smuzhiyun bool supports_32b_reads;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun /* Handle the last stage of initialization (BBT scan, partitioning) */
76*4882a593Smuzhiyun int (*late_init)(struct mtd_info *mtd);
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* This is the ecc value computed by the HW ecc generator upon writing an empty
80*4882a593Smuzhiyun page, one with all 0xff for data. */
81*4882a593Smuzhiyun static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun #define INFTL_BBT_RESERVED_BLOCKS 4
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun #define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
86*4882a593Smuzhiyun #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
87*4882a593Smuzhiyun #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun static int debug = 0;
90*4882a593Smuzhiyun module_param(debug, int, 0);
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun static int try_dword = 1;
93*4882a593Smuzhiyun module_param(try_dword, int, 0);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun static int no_ecc_failures = 0;
96*4882a593Smuzhiyun module_param(no_ecc_failures, int, 0);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun static int no_autopart = 0;
99*4882a593Smuzhiyun module_param(no_autopart, int, 0);
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun static int show_firmware_partition = 0;
102*4882a593Smuzhiyun module_param(show_firmware_partition, int, 0);
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun #ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
105*4882a593Smuzhiyun static int inftl_bbt_write = 1;
106*4882a593Smuzhiyun #else
107*4882a593Smuzhiyun static int inftl_bbt_write = 0;
108*4882a593Smuzhiyun #endif
109*4882a593Smuzhiyun module_param(inftl_bbt_write, int, 0);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
112*4882a593Smuzhiyun module_param(doc_config_location, ulong, 0);
113*4882a593Smuzhiyun MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /* Sector size for HW ECC */
116*4882a593Smuzhiyun #define SECTOR_SIZE 512
117*4882a593Smuzhiyun /* The sector bytes are packed into NB_DATA 10 bit words */
118*4882a593Smuzhiyun #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
119*4882a593Smuzhiyun /* Number of roots */
120*4882a593Smuzhiyun #define NROOTS 4
121*4882a593Smuzhiyun /* First consective root */
122*4882a593Smuzhiyun #define FCR 510
123*4882a593Smuzhiyun /* Number of symbols */
124*4882a593Smuzhiyun #define NN 1023
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /*
127*4882a593Smuzhiyun * The HW decoder in the DoC ASIC's provides us a error syndrome,
128*4882a593Smuzhiyun * which we must convert to a standard syndrome usable by the generic
129*4882a593Smuzhiyun * Reed-Solomon library code.
130*4882a593Smuzhiyun *
131*4882a593Smuzhiyun * Fabrice Bellard figured this out in the old docecc code. I added
132*4882a593Smuzhiyun * some comments, improved a minor bit and converted it to make use
133*4882a593Smuzhiyun * of the generic Reed-Solomon library. tglx
134*4882a593Smuzhiyun */
doc_ecc_decode(struct rs_control * rs,uint8_t * data,uint8_t * ecc)135*4882a593Smuzhiyun static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun int i, j, nerr, errpos[8];
138*4882a593Smuzhiyun uint8_t parity;
139*4882a593Smuzhiyun uint16_t ds[4], s[5], tmp, errval[8], syn[4];
140*4882a593Smuzhiyun struct rs_codec *cd = rs->codec;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun memset(syn, 0, sizeof(syn));
143*4882a593Smuzhiyun /* Convert the ecc bytes into words */
144*4882a593Smuzhiyun ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
145*4882a593Smuzhiyun ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
146*4882a593Smuzhiyun ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
147*4882a593Smuzhiyun ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
148*4882a593Smuzhiyun parity = ecc[1];
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /* Initialize the syndrome buffer */
151*4882a593Smuzhiyun for (i = 0; i < NROOTS; i++)
152*4882a593Smuzhiyun s[i] = ds[0];
153*4882a593Smuzhiyun /*
154*4882a593Smuzhiyun * Evaluate
155*4882a593Smuzhiyun * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
156*4882a593Smuzhiyun * where x = alpha^(FCR + i)
157*4882a593Smuzhiyun */
158*4882a593Smuzhiyun for (j = 1; j < NROOTS; j++) {
159*4882a593Smuzhiyun if (ds[j] == 0)
160*4882a593Smuzhiyun continue;
161*4882a593Smuzhiyun tmp = cd->index_of[ds[j]];
162*4882a593Smuzhiyun for (i = 0; i < NROOTS; i++)
163*4882a593Smuzhiyun s[i] ^= cd->alpha_to[rs_modnn(cd, tmp + (FCR + i) * j)];
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /* Calc syn[i] = s[i] / alpha^(v + i) */
167*4882a593Smuzhiyun for (i = 0; i < NROOTS; i++) {
168*4882a593Smuzhiyun if (s[i])
169*4882a593Smuzhiyun syn[i] = rs_modnn(cd, cd->index_of[s[i]] + (NN - FCR - i));
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun /* Call the decoder library */
172*4882a593Smuzhiyun nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun /* Incorrectable errors ? */
175*4882a593Smuzhiyun if (nerr < 0)
176*4882a593Smuzhiyun return nerr;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /*
179*4882a593Smuzhiyun * Correct the errors. The bitpositions are a bit of magic,
180*4882a593Smuzhiyun * but they are given by the design of the de/encoder circuit
181*4882a593Smuzhiyun * in the DoC ASIC's.
182*4882a593Smuzhiyun */
183*4882a593Smuzhiyun for (i = 0; i < nerr; i++) {
184*4882a593Smuzhiyun int index, bitpos, pos = 1015 - errpos[i];
185*4882a593Smuzhiyun uint8_t val;
186*4882a593Smuzhiyun if (pos >= NB_DATA && pos < 1019)
187*4882a593Smuzhiyun continue;
188*4882a593Smuzhiyun if (pos < NB_DATA) {
189*4882a593Smuzhiyun /* extract bit position (MSB first) */
190*4882a593Smuzhiyun pos = 10 * (NB_DATA - 1 - pos) - 6;
191*4882a593Smuzhiyun /* now correct the following 10 bits. At most two bytes
192*4882a593Smuzhiyun can be modified since pos is even */
193*4882a593Smuzhiyun index = (pos >> 3) ^ 1;
194*4882a593Smuzhiyun bitpos = pos & 7;
195*4882a593Smuzhiyun if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
196*4882a593Smuzhiyun val = (uint8_t) (errval[i] >> (2 + bitpos));
197*4882a593Smuzhiyun parity ^= val;
198*4882a593Smuzhiyun if (index < SECTOR_SIZE)
199*4882a593Smuzhiyun data[index] ^= val;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun index = ((pos >> 3) + 1) ^ 1;
202*4882a593Smuzhiyun bitpos = (bitpos + 10) & 7;
203*4882a593Smuzhiyun if (bitpos == 0)
204*4882a593Smuzhiyun bitpos = 8;
205*4882a593Smuzhiyun if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
206*4882a593Smuzhiyun val = (uint8_t) (errval[i] << (8 - bitpos));
207*4882a593Smuzhiyun parity ^= val;
208*4882a593Smuzhiyun if (index < SECTOR_SIZE)
209*4882a593Smuzhiyun data[index] ^= val;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun /* If the parity is wrong, no rescue possible */
214*4882a593Smuzhiyun return parity ? -EBADMSG : nerr;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
DoC_Delay(struct doc_priv * doc,unsigned short cycles)217*4882a593Smuzhiyun static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun volatile char dummy;
220*4882a593Smuzhiyun int i;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun for (i = 0; i < cycles; i++) {
223*4882a593Smuzhiyun if (DoC_is_Millennium(doc))
224*4882a593Smuzhiyun dummy = ReadDOC(doc->virtadr, NOP);
225*4882a593Smuzhiyun else if (DoC_is_MillenniumPlus(doc))
226*4882a593Smuzhiyun dummy = ReadDOC(doc->virtadr, Mplus_NOP);
227*4882a593Smuzhiyun else
228*4882a593Smuzhiyun dummy = ReadDOC(doc->virtadr, DOCStatus);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun #define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
_DoC_WaitReady(struct doc_priv * doc)236*4882a593Smuzhiyun static int _DoC_WaitReady(struct doc_priv *doc)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
239*4882a593Smuzhiyun unsigned long timeo = jiffies + (HZ * 10);
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun if (debug)
242*4882a593Smuzhiyun printk("_DoC_WaitReady...\n");
243*4882a593Smuzhiyun /* Out-of-line routine to wait for chip response */
244*4882a593Smuzhiyun if (DoC_is_MillenniumPlus(doc)) {
245*4882a593Smuzhiyun while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
246*4882a593Smuzhiyun if (time_after(jiffies, timeo)) {
247*4882a593Smuzhiyun printk("_DoC_WaitReady timed out.\n");
248*4882a593Smuzhiyun return -EIO;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun udelay(1);
251*4882a593Smuzhiyun cond_resched();
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun } else {
254*4882a593Smuzhiyun while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
255*4882a593Smuzhiyun if (time_after(jiffies, timeo)) {
256*4882a593Smuzhiyun printk("_DoC_WaitReady timed out.\n");
257*4882a593Smuzhiyun return -EIO;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun udelay(1);
260*4882a593Smuzhiyun cond_resched();
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun return 0;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
DoC_WaitReady(struct doc_priv * doc)267*4882a593Smuzhiyun static inline int DoC_WaitReady(struct doc_priv *doc)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
270*4882a593Smuzhiyun int ret = 0;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if (DoC_is_MillenniumPlus(doc)) {
273*4882a593Smuzhiyun DoC_Delay(doc, 4);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
276*4882a593Smuzhiyun /* Call the out-of-line routine to wait */
277*4882a593Smuzhiyun ret = _DoC_WaitReady(doc);
278*4882a593Smuzhiyun } else {
279*4882a593Smuzhiyun DoC_Delay(doc, 4);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
282*4882a593Smuzhiyun /* Call the out-of-line routine to wait */
283*4882a593Smuzhiyun ret = _DoC_WaitReady(doc);
284*4882a593Smuzhiyun DoC_Delay(doc, 2);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun if (debug)
288*4882a593Smuzhiyun printk("DoC_WaitReady OK\n");
289*4882a593Smuzhiyun return ret;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
doc2000_write_byte(struct nand_chip * this,u_char datum)292*4882a593Smuzhiyun static void doc2000_write_byte(struct nand_chip *this, u_char datum)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
295*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun if (debug)
298*4882a593Smuzhiyun printk("write_byte %02x\n", datum);
299*4882a593Smuzhiyun WriteDOC(datum, docptr, CDSNSlowIO);
300*4882a593Smuzhiyun WriteDOC(datum, docptr, 2k_CDSN_IO);
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
doc2000_writebuf(struct nand_chip * this,const u_char * buf,int len)303*4882a593Smuzhiyun static void doc2000_writebuf(struct nand_chip *this, const u_char *buf,
304*4882a593Smuzhiyun int len)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
307*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
308*4882a593Smuzhiyun int i;
309*4882a593Smuzhiyun if (debug)
310*4882a593Smuzhiyun printk("writebuf of %d bytes: ", len);
311*4882a593Smuzhiyun for (i = 0; i < len; i++) {
312*4882a593Smuzhiyun WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
313*4882a593Smuzhiyun if (debug && i < 16)
314*4882a593Smuzhiyun printk("%02x ", buf[i]);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun if (debug)
317*4882a593Smuzhiyun printk("\n");
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
doc2000_readbuf(struct nand_chip * this,u_char * buf,int len)320*4882a593Smuzhiyun static void doc2000_readbuf(struct nand_chip *this, u_char *buf, int len)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
323*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
324*4882a593Smuzhiyun u32 *buf32 = (u32 *)buf;
325*4882a593Smuzhiyun int i;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun if (debug)
328*4882a593Smuzhiyun printk("readbuf of %d bytes: ", len);
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun if (!doc->supports_32b_reads ||
331*4882a593Smuzhiyun ((((unsigned long)buf) | len) & 3)) {
332*4882a593Smuzhiyun for (i = 0; i < len; i++)
333*4882a593Smuzhiyun buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
334*4882a593Smuzhiyun } else {
335*4882a593Smuzhiyun for (i = 0; i < len / 4; i++)
336*4882a593Smuzhiyun buf32[i] = readl(docptr + DoC_2k_CDSN_IO + i);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /*
341*4882a593Smuzhiyun * We need our own readid() here because it's called before the NAND chip
342*4882a593Smuzhiyun * has been initialized, and calling nand_op_readid() would lead to a NULL
343*4882a593Smuzhiyun * pointer exception when dereferencing the NAND timings.
344*4882a593Smuzhiyun */
doc200x_readid(struct nand_chip * this,unsigned int cs,u8 * id)345*4882a593Smuzhiyun static void doc200x_readid(struct nand_chip *this, unsigned int cs, u8 *id)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun u8 addr = 0;
348*4882a593Smuzhiyun struct nand_op_instr instrs[] = {
349*4882a593Smuzhiyun NAND_OP_CMD(NAND_CMD_READID, 0),
350*4882a593Smuzhiyun NAND_OP_ADDR(1, &addr, 50),
351*4882a593Smuzhiyun NAND_OP_8BIT_DATA_IN(2, id, 0),
352*4882a593Smuzhiyun };
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun struct nand_operation op = NAND_OPERATION(cs, instrs);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun if (!id)
357*4882a593Smuzhiyun op.ninstrs--;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun this->controller->ops->exec_op(this, &op, false);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
doc200x_ident_chip(struct mtd_info * mtd,int nr)362*4882a593Smuzhiyun static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
365*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
366*4882a593Smuzhiyun uint16_t ret;
367*4882a593Smuzhiyun u8 id[2];
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun doc200x_readid(this, nr, id);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun ret = ((u16)id[0] << 8) | id[1];
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
374*4882a593Smuzhiyun /* First chip probe. See if we get same results by 32-bit access */
375*4882a593Smuzhiyun union {
376*4882a593Smuzhiyun uint32_t dword;
377*4882a593Smuzhiyun uint8_t byte[4];
378*4882a593Smuzhiyun } ident;
379*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun doc200x_readid(this, nr, NULL);
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun ident.dword = readl(docptr + DoC_2k_CDSN_IO);
384*4882a593Smuzhiyun if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
385*4882a593Smuzhiyun pr_info("DiskOnChip 2000 responds to DWORD access\n");
386*4882a593Smuzhiyun doc->supports_32b_reads = true;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun return ret;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
doc2000_count_chips(struct mtd_info * mtd)393*4882a593Smuzhiyun static void __init doc2000_count_chips(struct mtd_info *mtd)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
396*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
397*4882a593Smuzhiyun uint16_t mfrid;
398*4882a593Smuzhiyun int i;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* Max 4 chips per floor on DiskOnChip 2000 */
401*4882a593Smuzhiyun doc->chips_per_floor = 4;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun /* Find out what the first chip is */
404*4882a593Smuzhiyun mfrid = doc200x_ident_chip(mtd, 0);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun /* Find how many chips in each floor. */
407*4882a593Smuzhiyun for (i = 1; i < 4; i++) {
408*4882a593Smuzhiyun if (doc200x_ident_chip(mtd, i) != mfrid)
409*4882a593Smuzhiyun break;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun doc->chips_per_floor = i;
412*4882a593Smuzhiyun pr_debug("Detected %d chips per floor.\n", i);
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
doc2001_write_byte(struct nand_chip * this,u_char datum)415*4882a593Smuzhiyun static void doc2001_write_byte(struct nand_chip *this, u_char datum)
416*4882a593Smuzhiyun {
417*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
418*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun WriteDOC(datum, docptr, CDSNSlowIO);
421*4882a593Smuzhiyun WriteDOC(datum, docptr, Mil_CDSN_IO);
422*4882a593Smuzhiyun WriteDOC(datum, docptr, WritePipeTerm);
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
doc2001_writebuf(struct nand_chip * this,const u_char * buf,int len)425*4882a593Smuzhiyun static void doc2001_writebuf(struct nand_chip *this, const u_char *buf, int len)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
428*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
429*4882a593Smuzhiyun int i;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun for (i = 0; i < len; i++)
432*4882a593Smuzhiyun WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
433*4882a593Smuzhiyun /* Terminate write pipeline */
434*4882a593Smuzhiyun WriteDOC(0x00, docptr, WritePipeTerm);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
doc2001_readbuf(struct nand_chip * this,u_char * buf,int len)437*4882a593Smuzhiyun static void doc2001_readbuf(struct nand_chip *this, u_char *buf, int len)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
440*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
441*4882a593Smuzhiyun int i;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun /* Start read pipeline */
444*4882a593Smuzhiyun ReadDOC(docptr, ReadPipeInit);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun for (i = 0; i < len - 1; i++)
447*4882a593Smuzhiyun buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun /* Terminate read pipeline */
450*4882a593Smuzhiyun buf[i] = ReadDOC(docptr, LastDataRead);
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
doc2001plus_writebuf(struct nand_chip * this,const u_char * buf,int len)453*4882a593Smuzhiyun static void doc2001plus_writebuf(struct nand_chip *this, const u_char *buf, int len)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
456*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
457*4882a593Smuzhiyun int i;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun if (debug)
460*4882a593Smuzhiyun printk("writebuf of %d bytes: ", len);
461*4882a593Smuzhiyun for (i = 0; i < len; i++) {
462*4882a593Smuzhiyun WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
463*4882a593Smuzhiyun if (debug && i < 16)
464*4882a593Smuzhiyun printk("%02x ", buf[i]);
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun if (debug)
467*4882a593Smuzhiyun printk("\n");
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
doc2001plus_readbuf(struct nand_chip * this,u_char * buf,int len)470*4882a593Smuzhiyun static void doc2001plus_readbuf(struct nand_chip *this, u_char *buf, int len)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
473*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
474*4882a593Smuzhiyun int i;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun if (debug)
477*4882a593Smuzhiyun printk("readbuf of %d bytes: ", len);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun /* Start read pipeline */
480*4882a593Smuzhiyun ReadDOC(docptr, Mplus_ReadPipeInit);
481*4882a593Smuzhiyun ReadDOC(docptr, Mplus_ReadPipeInit);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun for (i = 0; i < len - 2; i++) {
484*4882a593Smuzhiyun buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
485*4882a593Smuzhiyun if (debug && i < 16)
486*4882a593Smuzhiyun printk("%02x ", buf[i]);
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun /* Terminate read pipeline */
490*4882a593Smuzhiyun if (len >= 2) {
491*4882a593Smuzhiyun buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead);
492*4882a593Smuzhiyun if (debug && i < 16)
493*4882a593Smuzhiyun printk("%02x ", buf[len - 2]);
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);
497*4882a593Smuzhiyun if (debug && i < 16)
498*4882a593Smuzhiyun printk("%02x ", buf[len - 1]);
499*4882a593Smuzhiyun if (debug)
500*4882a593Smuzhiyun printk("\n");
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun
doc200x_write_control(struct doc_priv * doc,u8 value)503*4882a593Smuzhiyun static void doc200x_write_control(struct doc_priv *doc, u8 value)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun WriteDOC(value, doc->virtadr, CDSNControl);
506*4882a593Smuzhiyun /* 11.4.3 -- 4 NOPs after CSDNControl write */
507*4882a593Smuzhiyun DoC_Delay(doc, 4);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
doc200x_exec_instr(struct nand_chip * this,const struct nand_op_instr * instr)510*4882a593Smuzhiyun static void doc200x_exec_instr(struct nand_chip *this,
511*4882a593Smuzhiyun const struct nand_op_instr *instr)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
514*4882a593Smuzhiyun unsigned int i;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun switch (instr->type) {
517*4882a593Smuzhiyun case NAND_OP_CMD_INSTR:
518*4882a593Smuzhiyun doc200x_write_control(doc, CDSN_CTRL_CE | CDSN_CTRL_CLE);
519*4882a593Smuzhiyun doc2000_write_byte(this, instr->ctx.cmd.opcode);
520*4882a593Smuzhiyun break;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun case NAND_OP_ADDR_INSTR:
523*4882a593Smuzhiyun doc200x_write_control(doc, CDSN_CTRL_CE | CDSN_CTRL_ALE);
524*4882a593Smuzhiyun for (i = 0; i < instr->ctx.addr.naddrs; i++) {
525*4882a593Smuzhiyun u8 addr = instr->ctx.addr.addrs[i];
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun if (DoC_is_2000(doc))
528*4882a593Smuzhiyun doc2000_write_byte(this, addr);
529*4882a593Smuzhiyun else
530*4882a593Smuzhiyun doc2001_write_byte(this, addr);
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun break;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun case NAND_OP_DATA_IN_INSTR:
535*4882a593Smuzhiyun doc200x_write_control(doc, CDSN_CTRL_CE);
536*4882a593Smuzhiyun if (DoC_is_2000(doc))
537*4882a593Smuzhiyun doc2000_readbuf(this, instr->ctx.data.buf.in,
538*4882a593Smuzhiyun instr->ctx.data.len);
539*4882a593Smuzhiyun else
540*4882a593Smuzhiyun doc2001_readbuf(this, instr->ctx.data.buf.in,
541*4882a593Smuzhiyun instr->ctx.data.len);
542*4882a593Smuzhiyun break;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun case NAND_OP_DATA_OUT_INSTR:
545*4882a593Smuzhiyun doc200x_write_control(doc, CDSN_CTRL_CE);
546*4882a593Smuzhiyun if (DoC_is_2000(doc))
547*4882a593Smuzhiyun doc2000_writebuf(this, instr->ctx.data.buf.out,
548*4882a593Smuzhiyun instr->ctx.data.len);
549*4882a593Smuzhiyun else
550*4882a593Smuzhiyun doc2001_writebuf(this, instr->ctx.data.buf.out,
551*4882a593Smuzhiyun instr->ctx.data.len);
552*4882a593Smuzhiyun break;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun case NAND_OP_WAITRDY_INSTR:
555*4882a593Smuzhiyun DoC_WaitReady(doc);
556*4882a593Smuzhiyun break;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun if (instr->delay_ns)
560*4882a593Smuzhiyun ndelay(instr->delay_ns);
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
doc200x_exec_op(struct nand_chip * this,const struct nand_operation * op,bool check_only)563*4882a593Smuzhiyun static int doc200x_exec_op(struct nand_chip *this,
564*4882a593Smuzhiyun const struct nand_operation *op,
565*4882a593Smuzhiyun bool check_only)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
568*4882a593Smuzhiyun unsigned int i;
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun if (check_only)
571*4882a593Smuzhiyun return true;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun doc->curchip = op->cs % doc->chips_per_floor;
574*4882a593Smuzhiyun doc->curfloor = op->cs / doc->chips_per_floor;
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun WriteDOC(doc->curfloor, doc->virtadr, FloorSelect);
577*4882a593Smuzhiyun WriteDOC(doc->curchip, doc->virtadr, CDSNDeviceSelect);
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun /* Assert CE pin */
580*4882a593Smuzhiyun doc200x_write_control(doc, CDSN_CTRL_CE);
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun for (i = 0; i < op->ninstrs; i++)
583*4882a593Smuzhiyun doc200x_exec_instr(this, &op->instrs[i]);
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun /* De-assert CE pin */
586*4882a593Smuzhiyun doc200x_write_control(doc, 0);
587*4882a593Smuzhiyun
588*4882a593Smuzhiyun return 0;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun
doc2001plus_write_pipe_term(struct doc_priv * doc)591*4882a593Smuzhiyun static void doc2001plus_write_pipe_term(struct doc_priv *doc)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun WriteDOC(0x00, doc->virtadr, Mplus_WritePipeTerm);
594*4882a593Smuzhiyun WriteDOC(0x00, doc->virtadr, Mplus_WritePipeTerm);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
doc2001plus_exec_instr(struct nand_chip * this,const struct nand_op_instr * instr)597*4882a593Smuzhiyun static void doc2001plus_exec_instr(struct nand_chip *this,
598*4882a593Smuzhiyun const struct nand_op_instr *instr)
599*4882a593Smuzhiyun {
600*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
601*4882a593Smuzhiyun unsigned int i;
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun switch (instr->type) {
604*4882a593Smuzhiyun case NAND_OP_CMD_INSTR:
605*4882a593Smuzhiyun WriteDOC(instr->ctx.cmd.opcode, doc->virtadr, Mplus_FlashCmd);
606*4882a593Smuzhiyun doc2001plus_write_pipe_term(doc);
607*4882a593Smuzhiyun break;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun case NAND_OP_ADDR_INSTR:
610*4882a593Smuzhiyun for (i = 0; i < instr->ctx.addr.naddrs; i++) {
611*4882a593Smuzhiyun u8 addr = instr->ctx.addr.addrs[i];
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun WriteDOC(addr, doc->virtadr, Mplus_FlashAddress);
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun doc2001plus_write_pipe_term(doc);
616*4882a593Smuzhiyun /* deassert ALE */
617*4882a593Smuzhiyun WriteDOC(0, doc->virtadr, Mplus_FlashControl);
618*4882a593Smuzhiyun break;
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun case NAND_OP_DATA_IN_INSTR:
621*4882a593Smuzhiyun doc2001plus_readbuf(this, instr->ctx.data.buf.in,
622*4882a593Smuzhiyun instr->ctx.data.len);
623*4882a593Smuzhiyun break;
624*4882a593Smuzhiyun case NAND_OP_DATA_OUT_INSTR:
625*4882a593Smuzhiyun doc2001plus_writebuf(this, instr->ctx.data.buf.out,
626*4882a593Smuzhiyun instr->ctx.data.len);
627*4882a593Smuzhiyun doc2001plus_write_pipe_term(doc);
628*4882a593Smuzhiyun break;
629*4882a593Smuzhiyun case NAND_OP_WAITRDY_INSTR:
630*4882a593Smuzhiyun DoC_WaitReady(doc);
631*4882a593Smuzhiyun break;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun if (instr->delay_ns)
635*4882a593Smuzhiyun ndelay(instr->delay_ns);
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun
doc2001plus_exec_op(struct nand_chip * this,const struct nand_operation * op,bool check_only)638*4882a593Smuzhiyun static int doc2001plus_exec_op(struct nand_chip *this,
639*4882a593Smuzhiyun const struct nand_operation *op,
640*4882a593Smuzhiyun bool check_only)
641*4882a593Smuzhiyun {
642*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
643*4882a593Smuzhiyun unsigned int i;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun if (check_only)
646*4882a593Smuzhiyun return true;
647*4882a593Smuzhiyun
648*4882a593Smuzhiyun doc->curchip = op->cs % doc->chips_per_floor;
649*4882a593Smuzhiyun doc->curfloor = op->cs / doc->chips_per_floor;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun /* Assert ChipEnable and deassert WriteProtect */
652*4882a593Smuzhiyun WriteDOC(DOC_FLASH_CE, doc->virtadr, Mplus_FlashSelect);
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun for (i = 0; i < op->ninstrs; i++)
655*4882a593Smuzhiyun doc2001plus_exec_instr(this, &op->instrs[i]);
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun /* De-assert ChipEnable */
658*4882a593Smuzhiyun WriteDOC(0, doc->virtadr, Mplus_FlashSelect);
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun return 0;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun
doc200x_enable_hwecc(struct nand_chip * this,int mode)663*4882a593Smuzhiyun static void doc200x_enable_hwecc(struct nand_chip *this, int mode)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
666*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
667*4882a593Smuzhiyun
668*4882a593Smuzhiyun /* Prime the ECC engine */
669*4882a593Smuzhiyun switch (mode) {
670*4882a593Smuzhiyun case NAND_ECC_READ:
671*4882a593Smuzhiyun WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
672*4882a593Smuzhiyun WriteDOC(DOC_ECC_EN, docptr, ECCConf);
673*4882a593Smuzhiyun break;
674*4882a593Smuzhiyun case NAND_ECC_WRITE:
675*4882a593Smuzhiyun WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
676*4882a593Smuzhiyun WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
677*4882a593Smuzhiyun break;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
doc2001plus_enable_hwecc(struct nand_chip * this,int mode)681*4882a593Smuzhiyun static void doc2001plus_enable_hwecc(struct nand_chip *this, int mode)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
684*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun /* Prime the ECC engine */
687*4882a593Smuzhiyun switch (mode) {
688*4882a593Smuzhiyun case NAND_ECC_READ:
689*4882a593Smuzhiyun WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
690*4882a593Smuzhiyun WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
691*4882a593Smuzhiyun break;
692*4882a593Smuzhiyun case NAND_ECC_WRITE:
693*4882a593Smuzhiyun WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
694*4882a593Smuzhiyun WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
695*4882a593Smuzhiyun break;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun /* This code is only called on write */
doc200x_calculate_ecc(struct nand_chip * this,const u_char * dat,unsigned char * ecc_code)700*4882a593Smuzhiyun static int doc200x_calculate_ecc(struct nand_chip *this, const u_char *dat,
701*4882a593Smuzhiyun unsigned char *ecc_code)
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
704*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
705*4882a593Smuzhiyun int i;
706*4882a593Smuzhiyun int emptymatch = 1;
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun /* flush the pipeline */
709*4882a593Smuzhiyun if (DoC_is_2000(doc)) {
710*4882a593Smuzhiyun WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);
711*4882a593Smuzhiyun WriteDOC(0, docptr, 2k_CDSN_IO);
712*4882a593Smuzhiyun WriteDOC(0, docptr, 2k_CDSN_IO);
713*4882a593Smuzhiyun WriteDOC(0, docptr, 2k_CDSN_IO);
714*4882a593Smuzhiyun WriteDOC(doc->CDSNControl, docptr, CDSNControl);
715*4882a593Smuzhiyun } else if (DoC_is_MillenniumPlus(doc)) {
716*4882a593Smuzhiyun WriteDOC(0, docptr, Mplus_NOP);
717*4882a593Smuzhiyun WriteDOC(0, docptr, Mplus_NOP);
718*4882a593Smuzhiyun WriteDOC(0, docptr, Mplus_NOP);
719*4882a593Smuzhiyun } else {
720*4882a593Smuzhiyun WriteDOC(0, docptr, NOP);
721*4882a593Smuzhiyun WriteDOC(0, docptr, NOP);
722*4882a593Smuzhiyun WriteDOC(0, docptr, NOP);
723*4882a593Smuzhiyun }
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun for (i = 0; i < 6; i++) {
726*4882a593Smuzhiyun if (DoC_is_MillenniumPlus(doc))
727*4882a593Smuzhiyun ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
728*4882a593Smuzhiyun else
729*4882a593Smuzhiyun ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
730*4882a593Smuzhiyun if (ecc_code[i] != empty_write_ecc[i])
731*4882a593Smuzhiyun emptymatch = 0;
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun if (DoC_is_MillenniumPlus(doc))
734*4882a593Smuzhiyun WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
735*4882a593Smuzhiyun else
736*4882a593Smuzhiyun WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
737*4882a593Smuzhiyun #if 0
738*4882a593Smuzhiyun /* If emptymatch=1, we might have an all-0xff data buffer. Check. */
739*4882a593Smuzhiyun if (emptymatch) {
740*4882a593Smuzhiyun /* Note: this somewhat expensive test should not be triggered
741*4882a593Smuzhiyun often. It could be optimized away by examining the data in
742*4882a593Smuzhiyun the writebuf routine, and remembering the result. */
743*4882a593Smuzhiyun for (i = 0; i < 512; i++) {
744*4882a593Smuzhiyun if (dat[i] == 0xff)
745*4882a593Smuzhiyun continue;
746*4882a593Smuzhiyun emptymatch = 0;
747*4882a593Smuzhiyun break;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun /* If emptymatch still =1, we do have an all-0xff data buffer.
751*4882a593Smuzhiyun Return all-0xff ecc value instead of the computed one, so
752*4882a593Smuzhiyun it'll look just like a freshly-erased page. */
753*4882a593Smuzhiyun if (emptymatch)
754*4882a593Smuzhiyun memset(ecc_code, 0xff, 6);
755*4882a593Smuzhiyun #endif
756*4882a593Smuzhiyun return 0;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun
doc200x_correct_data(struct nand_chip * this,u_char * dat,u_char * read_ecc,u_char * isnull)759*4882a593Smuzhiyun static int doc200x_correct_data(struct nand_chip *this, u_char *dat,
760*4882a593Smuzhiyun u_char *read_ecc, u_char *isnull)
761*4882a593Smuzhiyun {
762*4882a593Smuzhiyun int i, ret = 0;
763*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
764*4882a593Smuzhiyun void __iomem *docptr = doc->virtadr;
765*4882a593Smuzhiyun uint8_t calc_ecc[6];
766*4882a593Smuzhiyun volatile u_char dummy;
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun /* flush the pipeline */
769*4882a593Smuzhiyun if (DoC_is_2000(doc)) {
770*4882a593Smuzhiyun dummy = ReadDOC(docptr, 2k_ECCStatus);
771*4882a593Smuzhiyun dummy = ReadDOC(docptr, 2k_ECCStatus);
772*4882a593Smuzhiyun dummy = ReadDOC(docptr, 2k_ECCStatus);
773*4882a593Smuzhiyun } else if (DoC_is_MillenniumPlus(doc)) {
774*4882a593Smuzhiyun dummy = ReadDOC(docptr, Mplus_ECCConf);
775*4882a593Smuzhiyun dummy = ReadDOC(docptr, Mplus_ECCConf);
776*4882a593Smuzhiyun dummy = ReadDOC(docptr, Mplus_ECCConf);
777*4882a593Smuzhiyun } else {
778*4882a593Smuzhiyun dummy = ReadDOC(docptr, ECCConf);
779*4882a593Smuzhiyun dummy = ReadDOC(docptr, ECCConf);
780*4882a593Smuzhiyun dummy = ReadDOC(docptr, ECCConf);
781*4882a593Smuzhiyun }
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun /* Error occurred ? */
784*4882a593Smuzhiyun if (dummy & 0x80) {
785*4882a593Smuzhiyun for (i = 0; i < 6; i++) {
786*4882a593Smuzhiyun if (DoC_is_MillenniumPlus(doc))
787*4882a593Smuzhiyun calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
788*4882a593Smuzhiyun else
789*4882a593Smuzhiyun calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun ret = doc_ecc_decode(doc->rs_decoder, dat, calc_ecc);
793*4882a593Smuzhiyun if (ret > 0)
794*4882a593Smuzhiyun pr_err("doc200x_correct_data corrected %d errors\n",
795*4882a593Smuzhiyun ret);
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun if (DoC_is_MillenniumPlus(doc))
798*4882a593Smuzhiyun WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
799*4882a593Smuzhiyun else
800*4882a593Smuzhiyun WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
801*4882a593Smuzhiyun if (no_ecc_failures && mtd_is_eccerr(ret)) {
802*4882a593Smuzhiyun pr_err("suppressing ECC failure\n");
803*4882a593Smuzhiyun ret = 0;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun return ret;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun //u_char mydatabuf[528];
809*4882a593Smuzhiyun
doc200x_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)810*4882a593Smuzhiyun static int doc200x_ooblayout_ecc(struct mtd_info *mtd, int section,
811*4882a593Smuzhiyun struct mtd_oob_region *oobregion)
812*4882a593Smuzhiyun {
813*4882a593Smuzhiyun if (section)
814*4882a593Smuzhiyun return -ERANGE;
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun oobregion->offset = 0;
817*4882a593Smuzhiyun oobregion->length = 6;
818*4882a593Smuzhiyun
819*4882a593Smuzhiyun return 0;
820*4882a593Smuzhiyun }
821*4882a593Smuzhiyun
doc200x_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)822*4882a593Smuzhiyun static int doc200x_ooblayout_free(struct mtd_info *mtd, int section,
823*4882a593Smuzhiyun struct mtd_oob_region *oobregion)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun if (section > 1)
826*4882a593Smuzhiyun return -ERANGE;
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun /*
829*4882a593Smuzhiyun * The strange out-of-order free bytes definition is a (possibly
830*4882a593Smuzhiyun * unneeded) attempt to retain compatibility. It used to read:
831*4882a593Smuzhiyun * .oobfree = { {8, 8} }
832*4882a593Smuzhiyun * Since that leaves two bytes unusable, it was changed. But the
833*4882a593Smuzhiyun * following scheme might affect existing jffs2 installs by moving the
834*4882a593Smuzhiyun * cleanmarker:
835*4882a593Smuzhiyun * .oobfree = { {6, 10} }
836*4882a593Smuzhiyun * jffs2 seems to handle the above gracefully, but the current scheme
837*4882a593Smuzhiyun * seems safer. The only problem with it is that any code retrieving
838*4882a593Smuzhiyun * free bytes position must be able to handle out-of-order segments.
839*4882a593Smuzhiyun */
840*4882a593Smuzhiyun if (!section) {
841*4882a593Smuzhiyun oobregion->offset = 8;
842*4882a593Smuzhiyun oobregion->length = 8;
843*4882a593Smuzhiyun } else {
844*4882a593Smuzhiyun oobregion->offset = 6;
845*4882a593Smuzhiyun oobregion->length = 2;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun return 0;
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
852*4882a593Smuzhiyun .ecc = doc200x_ooblayout_ecc,
853*4882a593Smuzhiyun .free = doc200x_ooblayout_free,
854*4882a593Smuzhiyun };
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun /* Find the (I)NFTL Media Header, and optionally also the mirror media header.
857*4882a593Smuzhiyun On successful return, buf will contain a copy of the media header for
858*4882a593Smuzhiyun further processing. id is the string to scan for, and will presumably be
859*4882a593Smuzhiyun either "ANAND" or "BNAND". If findmirror=1, also look for the mirror media
860*4882a593Smuzhiyun header. The page #s of the found media headers are placed in mh0_page and
861*4882a593Smuzhiyun mh1_page in the DOC private structure. */
find_media_headers(struct mtd_info * mtd,u_char * buf,const char * id,int findmirror)862*4882a593Smuzhiyun static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
863*4882a593Smuzhiyun {
864*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
865*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
866*4882a593Smuzhiyun unsigned offs;
867*4882a593Smuzhiyun int ret;
868*4882a593Smuzhiyun size_t retlen;
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
871*4882a593Smuzhiyun ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
872*4882a593Smuzhiyun if (retlen != mtd->writesize)
873*4882a593Smuzhiyun continue;
874*4882a593Smuzhiyun if (ret) {
875*4882a593Smuzhiyun pr_warn("ECC error scanning DOC at 0x%x\n", offs);
876*4882a593Smuzhiyun }
877*4882a593Smuzhiyun if (memcmp(buf, id, 6))
878*4882a593Smuzhiyun continue;
879*4882a593Smuzhiyun pr_info("Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
880*4882a593Smuzhiyun if (doc->mh0_page == -1) {
881*4882a593Smuzhiyun doc->mh0_page = offs >> this->page_shift;
882*4882a593Smuzhiyun if (!findmirror)
883*4882a593Smuzhiyun return 1;
884*4882a593Smuzhiyun continue;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun doc->mh1_page = offs >> this->page_shift;
887*4882a593Smuzhiyun return 2;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun if (doc->mh0_page == -1) {
890*4882a593Smuzhiyun pr_warn("DiskOnChip %s Media Header not found.\n", id);
891*4882a593Smuzhiyun return 0;
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun /* Only one mediaheader was found. We want buf to contain a
894*4882a593Smuzhiyun mediaheader on return, so we'll have to re-read the one we found. */
895*4882a593Smuzhiyun offs = doc->mh0_page << this->page_shift;
896*4882a593Smuzhiyun ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
897*4882a593Smuzhiyun if (retlen != mtd->writesize) {
898*4882a593Smuzhiyun /* Insanity. Give up. */
899*4882a593Smuzhiyun pr_err("Read DiskOnChip Media Header once, but can't reread it???\n");
900*4882a593Smuzhiyun return 0;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun return 1;
903*4882a593Smuzhiyun }
904*4882a593Smuzhiyun
nftl_partscan(struct mtd_info * mtd,struct mtd_partition * parts)905*4882a593Smuzhiyun static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
906*4882a593Smuzhiyun {
907*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
908*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
909*4882a593Smuzhiyun struct nand_memory_organization *memorg;
910*4882a593Smuzhiyun int ret = 0;
911*4882a593Smuzhiyun u_char *buf;
912*4882a593Smuzhiyun struct NFTLMediaHeader *mh;
913*4882a593Smuzhiyun const unsigned psize = 1 << this->page_shift;
914*4882a593Smuzhiyun int numparts = 0;
915*4882a593Smuzhiyun unsigned blocks, maxblocks;
916*4882a593Smuzhiyun int offs, numheaders;
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun memorg = nanddev_get_memorg(&this->base);
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun buf = kmalloc(mtd->writesize, GFP_KERNEL);
921*4882a593Smuzhiyun if (!buf) {
922*4882a593Smuzhiyun return 0;
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
925*4882a593Smuzhiyun goto out;
926*4882a593Smuzhiyun mh = (struct NFTLMediaHeader *)buf;
927*4882a593Smuzhiyun
928*4882a593Smuzhiyun le16_to_cpus(&mh->NumEraseUnits);
929*4882a593Smuzhiyun le16_to_cpus(&mh->FirstPhysicalEUN);
930*4882a593Smuzhiyun le32_to_cpus(&mh->FormattedSize);
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun pr_info(" DataOrgID = %s\n"
933*4882a593Smuzhiyun " NumEraseUnits = %d\n"
934*4882a593Smuzhiyun " FirstPhysicalEUN = %d\n"
935*4882a593Smuzhiyun " FormattedSize = %d\n"
936*4882a593Smuzhiyun " UnitSizeFactor = %d\n",
937*4882a593Smuzhiyun mh->DataOrgID, mh->NumEraseUnits,
938*4882a593Smuzhiyun mh->FirstPhysicalEUN, mh->FormattedSize,
939*4882a593Smuzhiyun mh->UnitSizeFactor);
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun blocks = mtd->size >> this->phys_erase_shift;
942*4882a593Smuzhiyun maxblocks = min(32768U, mtd->erasesize - psize);
943*4882a593Smuzhiyun
944*4882a593Smuzhiyun if (mh->UnitSizeFactor == 0x00) {
945*4882a593Smuzhiyun /* Auto-determine UnitSizeFactor. The constraints are:
946*4882a593Smuzhiyun - There can be at most 32768 virtual blocks.
947*4882a593Smuzhiyun - There can be at most (virtual block size - page size)
948*4882a593Smuzhiyun virtual blocks (because MediaHeader+BBT must fit in 1).
949*4882a593Smuzhiyun */
950*4882a593Smuzhiyun mh->UnitSizeFactor = 0xff;
951*4882a593Smuzhiyun while (blocks > maxblocks) {
952*4882a593Smuzhiyun blocks >>= 1;
953*4882a593Smuzhiyun maxblocks = min(32768U, (maxblocks << 1) + psize);
954*4882a593Smuzhiyun mh->UnitSizeFactor--;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun pr_warn("UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun /* NOTE: The lines below modify internal variables of the NAND and MTD
960*4882a593Smuzhiyun layers; variables with have already been configured by nand_scan.
961*4882a593Smuzhiyun Unfortunately, we didn't know before this point what these values
962*4882a593Smuzhiyun should be. Thus, this code is somewhat dependent on the exact
963*4882a593Smuzhiyun implementation of the NAND layer. */
964*4882a593Smuzhiyun if (mh->UnitSizeFactor != 0xff) {
965*4882a593Smuzhiyun this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
966*4882a593Smuzhiyun memorg->pages_per_eraseblock <<= (0xff - mh->UnitSizeFactor);
967*4882a593Smuzhiyun mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
968*4882a593Smuzhiyun pr_info("Setting virtual erase size to %d\n", mtd->erasesize);
969*4882a593Smuzhiyun blocks = mtd->size >> this->bbt_erase_shift;
970*4882a593Smuzhiyun maxblocks = min(32768U, mtd->erasesize - psize);
971*4882a593Smuzhiyun }
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun if (blocks > maxblocks) {
974*4882a593Smuzhiyun pr_err("UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor);
975*4882a593Smuzhiyun goto out;
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun
978*4882a593Smuzhiyun /* Skip past the media headers. */
979*4882a593Smuzhiyun offs = max(doc->mh0_page, doc->mh1_page);
980*4882a593Smuzhiyun offs <<= this->page_shift;
981*4882a593Smuzhiyun offs += mtd->erasesize;
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun if (show_firmware_partition == 1) {
984*4882a593Smuzhiyun parts[0].name = " DiskOnChip Firmware / Media Header partition";
985*4882a593Smuzhiyun parts[0].offset = 0;
986*4882a593Smuzhiyun parts[0].size = offs;
987*4882a593Smuzhiyun numparts = 1;
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun
990*4882a593Smuzhiyun parts[numparts].name = " DiskOnChip BDTL partition";
991*4882a593Smuzhiyun parts[numparts].offset = offs;
992*4882a593Smuzhiyun parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun offs += parts[numparts].size;
995*4882a593Smuzhiyun numparts++;
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun if (offs < mtd->size) {
998*4882a593Smuzhiyun parts[numparts].name = " DiskOnChip Remainder partition";
999*4882a593Smuzhiyun parts[numparts].offset = offs;
1000*4882a593Smuzhiyun parts[numparts].size = mtd->size - offs;
1001*4882a593Smuzhiyun numparts++;
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun ret = numparts;
1005*4882a593Smuzhiyun out:
1006*4882a593Smuzhiyun kfree(buf);
1007*4882a593Smuzhiyun return ret;
1008*4882a593Smuzhiyun }
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun /* This is a stripped-down copy of the code in inftlmount.c */
inftl_partscan(struct mtd_info * mtd,struct mtd_partition * parts)1011*4882a593Smuzhiyun static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
1012*4882a593Smuzhiyun {
1013*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
1014*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
1015*4882a593Smuzhiyun int ret = 0;
1016*4882a593Smuzhiyun u_char *buf;
1017*4882a593Smuzhiyun struct INFTLMediaHeader *mh;
1018*4882a593Smuzhiyun struct INFTLPartition *ip;
1019*4882a593Smuzhiyun int numparts = 0;
1020*4882a593Smuzhiyun int blocks;
1021*4882a593Smuzhiyun int vshift, lastvunit = 0;
1022*4882a593Smuzhiyun int i;
1023*4882a593Smuzhiyun int end = mtd->size;
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun if (inftl_bbt_write)
1026*4882a593Smuzhiyun end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun buf = kmalloc(mtd->writesize, GFP_KERNEL);
1029*4882a593Smuzhiyun if (!buf) {
1030*4882a593Smuzhiyun return 0;
1031*4882a593Smuzhiyun }
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun if (!find_media_headers(mtd, buf, "BNAND", 0))
1034*4882a593Smuzhiyun goto out;
1035*4882a593Smuzhiyun doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
1036*4882a593Smuzhiyun mh = (struct INFTLMediaHeader *)buf;
1037*4882a593Smuzhiyun
1038*4882a593Smuzhiyun le32_to_cpus(&mh->NoOfBootImageBlocks);
1039*4882a593Smuzhiyun le32_to_cpus(&mh->NoOfBinaryPartitions);
1040*4882a593Smuzhiyun le32_to_cpus(&mh->NoOfBDTLPartitions);
1041*4882a593Smuzhiyun le32_to_cpus(&mh->BlockMultiplierBits);
1042*4882a593Smuzhiyun le32_to_cpus(&mh->FormatFlags);
1043*4882a593Smuzhiyun le32_to_cpus(&mh->PercentUsed);
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun pr_info(" bootRecordID = %s\n"
1046*4882a593Smuzhiyun " NoOfBootImageBlocks = %d\n"
1047*4882a593Smuzhiyun " NoOfBinaryPartitions = %d\n"
1048*4882a593Smuzhiyun " NoOfBDTLPartitions = %d\n"
1049*4882a593Smuzhiyun " BlockMultiplierBits = %d\n"
1050*4882a593Smuzhiyun " FormatFlgs = %d\n"
1051*4882a593Smuzhiyun " OsakVersion = %d.%d.%d.%d\n"
1052*4882a593Smuzhiyun " PercentUsed = %d\n",
1053*4882a593Smuzhiyun mh->bootRecordID, mh->NoOfBootImageBlocks,
1054*4882a593Smuzhiyun mh->NoOfBinaryPartitions,
1055*4882a593Smuzhiyun mh->NoOfBDTLPartitions,
1056*4882a593Smuzhiyun mh->BlockMultiplierBits, mh->FormatFlags,
1057*4882a593Smuzhiyun ((unsigned char *) &mh->OsakVersion)[0] & 0xf,
1058*4882a593Smuzhiyun ((unsigned char *) &mh->OsakVersion)[1] & 0xf,
1059*4882a593Smuzhiyun ((unsigned char *) &mh->OsakVersion)[2] & 0xf,
1060*4882a593Smuzhiyun ((unsigned char *) &mh->OsakVersion)[3] & 0xf,
1061*4882a593Smuzhiyun mh->PercentUsed);
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
1064*4882a593Smuzhiyun
1065*4882a593Smuzhiyun blocks = mtd->size >> vshift;
1066*4882a593Smuzhiyun if (blocks > 32768) {
1067*4882a593Smuzhiyun pr_err("BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits);
1068*4882a593Smuzhiyun goto out;
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun
1071*4882a593Smuzhiyun blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
1072*4882a593Smuzhiyun if (inftl_bbt_write && (blocks > mtd->erasesize)) {
1073*4882a593Smuzhiyun pr_err("Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n");
1074*4882a593Smuzhiyun goto out;
1075*4882a593Smuzhiyun }
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun /* Scan the partitions */
1078*4882a593Smuzhiyun for (i = 0; (i < 4); i++) {
1079*4882a593Smuzhiyun ip = &(mh->Partitions[i]);
1080*4882a593Smuzhiyun le32_to_cpus(&ip->virtualUnits);
1081*4882a593Smuzhiyun le32_to_cpus(&ip->firstUnit);
1082*4882a593Smuzhiyun le32_to_cpus(&ip->lastUnit);
1083*4882a593Smuzhiyun le32_to_cpus(&ip->flags);
1084*4882a593Smuzhiyun le32_to_cpus(&ip->spareUnits);
1085*4882a593Smuzhiyun le32_to_cpus(&ip->Reserved0);
1086*4882a593Smuzhiyun
1087*4882a593Smuzhiyun pr_info(" PARTITION[%d] ->\n"
1088*4882a593Smuzhiyun " virtualUnits = %d\n"
1089*4882a593Smuzhiyun " firstUnit = %d\n"
1090*4882a593Smuzhiyun " lastUnit = %d\n"
1091*4882a593Smuzhiyun " flags = 0x%x\n"
1092*4882a593Smuzhiyun " spareUnits = %d\n",
1093*4882a593Smuzhiyun i, ip->virtualUnits, ip->firstUnit,
1094*4882a593Smuzhiyun ip->lastUnit, ip->flags,
1095*4882a593Smuzhiyun ip->spareUnits);
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun if ((show_firmware_partition == 1) &&
1098*4882a593Smuzhiyun (i == 0) && (ip->firstUnit > 0)) {
1099*4882a593Smuzhiyun parts[0].name = " DiskOnChip IPL / Media Header partition";
1100*4882a593Smuzhiyun parts[0].offset = 0;
1101*4882a593Smuzhiyun parts[0].size = mtd->erasesize * ip->firstUnit;
1102*4882a593Smuzhiyun numparts = 1;
1103*4882a593Smuzhiyun }
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun if (ip->flags & INFTL_BINARY)
1106*4882a593Smuzhiyun parts[numparts].name = " DiskOnChip BDK partition";
1107*4882a593Smuzhiyun else
1108*4882a593Smuzhiyun parts[numparts].name = " DiskOnChip BDTL partition";
1109*4882a593Smuzhiyun parts[numparts].offset = ip->firstUnit << vshift;
1110*4882a593Smuzhiyun parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
1111*4882a593Smuzhiyun numparts++;
1112*4882a593Smuzhiyun if (ip->lastUnit > lastvunit)
1113*4882a593Smuzhiyun lastvunit = ip->lastUnit;
1114*4882a593Smuzhiyun if (ip->flags & INFTL_LAST)
1115*4882a593Smuzhiyun break;
1116*4882a593Smuzhiyun }
1117*4882a593Smuzhiyun lastvunit++;
1118*4882a593Smuzhiyun if ((lastvunit << vshift) < end) {
1119*4882a593Smuzhiyun parts[numparts].name = " DiskOnChip Remainder partition";
1120*4882a593Smuzhiyun parts[numparts].offset = lastvunit << vshift;
1121*4882a593Smuzhiyun parts[numparts].size = end - parts[numparts].offset;
1122*4882a593Smuzhiyun numparts++;
1123*4882a593Smuzhiyun }
1124*4882a593Smuzhiyun ret = numparts;
1125*4882a593Smuzhiyun out:
1126*4882a593Smuzhiyun kfree(buf);
1127*4882a593Smuzhiyun return ret;
1128*4882a593Smuzhiyun }
1129*4882a593Smuzhiyun
nftl_scan_bbt(struct mtd_info * mtd)1130*4882a593Smuzhiyun static int __init nftl_scan_bbt(struct mtd_info *mtd)
1131*4882a593Smuzhiyun {
1132*4882a593Smuzhiyun int ret, numparts;
1133*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
1134*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
1135*4882a593Smuzhiyun struct mtd_partition parts[2];
1136*4882a593Smuzhiyun
1137*4882a593Smuzhiyun memset((char *)parts, 0, sizeof(parts));
1138*4882a593Smuzhiyun /* On NFTL, we have to find the media headers before we can read the
1139*4882a593Smuzhiyun BBTs, since they're stored in the media header eraseblocks. */
1140*4882a593Smuzhiyun numparts = nftl_partscan(mtd, parts);
1141*4882a593Smuzhiyun if (!numparts)
1142*4882a593Smuzhiyun return -EIO;
1143*4882a593Smuzhiyun this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
1144*4882a593Smuzhiyun NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
1145*4882a593Smuzhiyun NAND_BBT_VERSION;
1146*4882a593Smuzhiyun this->bbt_td->veroffs = 7;
1147*4882a593Smuzhiyun this->bbt_td->pages[0] = doc->mh0_page + 1;
1148*4882a593Smuzhiyun if (doc->mh1_page != -1) {
1149*4882a593Smuzhiyun this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
1150*4882a593Smuzhiyun NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
1151*4882a593Smuzhiyun NAND_BBT_VERSION;
1152*4882a593Smuzhiyun this->bbt_md->veroffs = 7;
1153*4882a593Smuzhiyun this->bbt_md->pages[0] = doc->mh1_page + 1;
1154*4882a593Smuzhiyun } else {
1155*4882a593Smuzhiyun this->bbt_md = NULL;
1156*4882a593Smuzhiyun }
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun ret = nand_create_bbt(this);
1159*4882a593Smuzhiyun if (ret)
1160*4882a593Smuzhiyun return ret;
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun
inftl_scan_bbt(struct mtd_info * mtd)1165*4882a593Smuzhiyun static int __init inftl_scan_bbt(struct mtd_info *mtd)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun int ret, numparts;
1168*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
1169*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
1170*4882a593Smuzhiyun struct mtd_partition parts[5];
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun if (nanddev_ntargets(&this->base) > doc->chips_per_floor) {
1173*4882a593Smuzhiyun pr_err("Multi-floor INFTL devices not yet supported.\n");
1174*4882a593Smuzhiyun return -EIO;
1175*4882a593Smuzhiyun }
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun if (DoC_is_MillenniumPlus(doc)) {
1178*4882a593Smuzhiyun this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
1179*4882a593Smuzhiyun if (inftl_bbt_write)
1180*4882a593Smuzhiyun this->bbt_td->options |= NAND_BBT_WRITE;
1181*4882a593Smuzhiyun this->bbt_td->pages[0] = 2;
1182*4882a593Smuzhiyun this->bbt_md = NULL;
1183*4882a593Smuzhiyun } else {
1184*4882a593Smuzhiyun this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
1185*4882a593Smuzhiyun if (inftl_bbt_write)
1186*4882a593Smuzhiyun this->bbt_td->options |= NAND_BBT_WRITE;
1187*4882a593Smuzhiyun this->bbt_td->offs = 8;
1188*4882a593Smuzhiyun this->bbt_td->len = 8;
1189*4882a593Smuzhiyun this->bbt_td->veroffs = 7;
1190*4882a593Smuzhiyun this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
1191*4882a593Smuzhiyun this->bbt_td->reserved_block_code = 0x01;
1192*4882a593Smuzhiyun this->bbt_td->pattern = "MSYS_BBT";
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
1195*4882a593Smuzhiyun if (inftl_bbt_write)
1196*4882a593Smuzhiyun this->bbt_md->options |= NAND_BBT_WRITE;
1197*4882a593Smuzhiyun this->bbt_md->offs = 8;
1198*4882a593Smuzhiyun this->bbt_md->len = 8;
1199*4882a593Smuzhiyun this->bbt_md->veroffs = 7;
1200*4882a593Smuzhiyun this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
1201*4882a593Smuzhiyun this->bbt_md->reserved_block_code = 0x01;
1202*4882a593Smuzhiyun this->bbt_md->pattern = "TBB_SYSM";
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun
1205*4882a593Smuzhiyun ret = nand_create_bbt(this);
1206*4882a593Smuzhiyun if (ret)
1207*4882a593Smuzhiyun return ret;
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun memset((char *)parts, 0, sizeof(parts));
1210*4882a593Smuzhiyun numparts = inftl_partscan(mtd, parts);
1211*4882a593Smuzhiyun /* At least for now, require the INFTL Media Header. We could probably
1212*4882a593Smuzhiyun do without it for non-INFTL use, since all it gives us is
1213*4882a593Smuzhiyun autopartitioning, but I want to give it more thought. */
1214*4882a593Smuzhiyun if (!numparts)
1215*4882a593Smuzhiyun return -EIO;
1216*4882a593Smuzhiyun return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
1217*4882a593Smuzhiyun }
1218*4882a593Smuzhiyun
doc2000_init(struct mtd_info * mtd)1219*4882a593Smuzhiyun static inline int __init doc2000_init(struct mtd_info *mtd)
1220*4882a593Smuzhiyun {
1221*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
1222*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun doc->late_init = nftl_scan_bbt;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
1227*4882a593Smuzhiyun doc2000_count_chips(mtd);
1228*4882a593Smuzhiyun mtd->name = "DiskOnChip 2000 (NFTL Model)";
1229*4882a593Smuzhiyun return (4 * doc->chips_per_floor);
1230*4882a593Smuzhiyun }
1231*4882a593Smuzhiyun
doc2001_init(struct mtd_info * mtd)1232*4882a593Smuzhiyun static inline int __init doc2001_init(struct mtd_info *mtd)
1233*4882a593Smuzhiyun {
1234*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
1235*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun ReadDOC(doc->virtadr, ChipID);
1238*4882a593Smuzhiyun ReadDOC(doc->virtadr, ChipID);
1239*4882a593Smuzhiyun ReadDOC(doc->virtadr, ChipID);
1240*4882a593Smuzhiyun if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
1241*4882a593Smuzhiyun /* It's not a Millennium; it's one of the newer
1242*4882a593Smuzhiyun DiskOnChip 2000 units with a similar ASIC.
1243*4882a593Smuzhiyun Treat it like a Millennium, except that it
1244*4882a593Smuzhiyun can have multiple chips. */
1245*4882a593Smuzhiyun doc2000_count_chips(mtd);
1246*4882a593Smuzhiyun mtd->name = "DiskOnChip 2000 (INFTL Model)";
1247*4882a593Smuzhiyun doc->late_init = inftl_scan_bbt;
1248*4882a593Smuzhiyun return (4 * doc->chips_per_floor);
1249*4882a593Smuzhiyun } else {
1250*4882a593Smuzhiyun /* Bog-standard Millennium */
1251*4882a593Smuzhiyun doc->chips_per_floor = 1;
1252*4882a593Smuzhiyun mtd->name = "DiskOnChip Millennium";
1253*4882a593Smuzhiyun doc->late_init = nftl_scan_bbt;
1254*4882a593Smuzhiyun return 1;
1255*4882a593Smuzhiyun }
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun
doc2001plus_init(struct mtd_info * mtd)1258*4882a593Smuzhiyun static inline int __init doc2001plus_init(struct mtd_info *mtd)
1259*4882a593Smuzhiyun {
1260*4882a593Smuzhiyun struct nand_chip *this = mtd_to_nand(mtd);
1261*4882a593Smuzhiyun struct doc_priv *doc = nand_get_controller_data(this);
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun doc->late_init = inftl_scan_bbt;
1264*4882a593Smuzhiyun this->ecc.hwctl = doc2001plus_enable_hwecc;
1265*4882a593Smuzhiyun
1266*4882a593Smuzhiyun doc->chips_per_floor = 1;
1267*4882a593Smuzhiyun mtd->name = "DiskOnChip Millennium Plus";
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun return 1;
1270*4882a593Smuzhiyun }
1271*4882a593Smuzhiyun
doc200x_attach_chip(struct nand_chip * chip)1272*4882a593Smuzhiyun static int doc200x_attach_chip(struct nand_chip *chip)
1273*4882a593Smuzhiyun {
1274*4882a593Smuzhiyun if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
1275*4882a593Smuzhiyun return 0;
1276*4882a593Smuzhiyun
1277*4882a593Smuzhiyun chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
1278*4882a593Smuzhiyun chip->ecc.size = 512;
1279*4882a593Smuzhiyun chip->ecc.bytes = 6;
1280*4882a593Smuzhiyun chip->ecc.strength = 2;
1281*4882a593Smuzhiyun chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
1282*4882a593Smuzhiyun chip->ecc.hwctl = doc200x_enable_hwecc;
1283*4882a593Smuzhiyun chip->ecc.calculate = doc200x_calculate_ecc;
1284*4882a593Smuzhiyun chip->ecc.correct = doc200x_correct_data;
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun return 0;
1287*4882a593Smuzhiyun }
1288*4882a593Smuzhiyun
1289*4882a593Smuzhiyun static const struct nand_controller_ops doc200x_ops = {
1290*4882a593Smuzhiyun .exec_op = doc200x_exec_op,
1291*4882a593Smuzhiyun .attach_chip = doc200x_attach_chip,
1292*4882a593Smuzhiyun };
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun static const struct nand_controller_ops doc2001plus_ops = {
1295*4882a593Smuzhiyun .exec_op = doc2001plus_exec_op,
1296*4882a593Smuzhiyun .attach_chip = doc200x_attach_chip,
1297*4882a593Smuzhiyun };
1298*4882a593Smuzhiyun
doc_probe(unsigned long physadr)1299*4882a593Smuzhiyun static int __init doc_probe(unsigned long physadr)
1300*4882a593Smuzhiyun {
1301*4882a593Smuzhiyun struct nand_chip *nand = NULL;
1302*4882a593Smuzhiyun struct doc_priv *doc = NULL;
1303*4882a593Smuzhiyun unsigned char ChipID;
1304*4882a593Smuzhiyun struct mtd_info *mtd;
1305*4882a593Smuzhiyun void __iomem *virtadr;
1306*4882a593Smuzhiyun unsigned char save_control;
1307*4882a593Smuzhiyun unsigned char tmp, tmpb, tmpc;
1308*4882a593Smuzhiyun int reg, len, numchips;
1309*4882a593Smuzhiyun int ret = 0;
1310*4882a593Smuzhiyun
1311*4882a593Smuzhiyun if (!request_mem_region(physadr, DOC_IOREMAP_LEN, "DiskOnChip"))
1312*4882a593Smuzhiyun return -EBUSY;
1313*4882a593Smuzhiyun virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
1314*4882a593Smuzhiyun if (!virtadr) {
1315*4882a593Smuzhiyun pr_err("Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n",
1316*4882a593Smuzhiyun DOC_IOREMAP_LEN, physadr);
1317*4882a593Smuzhiyun ret = -EIO;
1318*4882a593Smuzhiyun goto error_ioremap;
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun
1321*4882a593Smuzhiyun /* It's not possible to cleanly detect the DiskOnChip - the
1322*4882a593Smuzhiyun * bootup procedure will put the device into reset mode, and
1323*4882a593Smuzhiyun * it's not possible to talk to it without actually writing
1324*4882a593Smuzhiyun * to the DOCControl register. So we store the current contents
1325*4882a593Smuzhiyun * of the DOCControl register's location, in case we later decide
1326*4882a593Smuzhiyun * that it's not a DiskOnChip, and want to put it back how we
1327*4882a593Smuzhiyun * found it.
1328*4882a593Smuzhiyun */
1329*4882a593Smuzhiyun save_control = ReadDOC(virtadr, DOCControl);
1330*4882a593Smuzhiyun
1331*4882a593Smuzhiyun /* Reset the DiskOnChip ASIC */
1332*4882a593Smuzhiyun WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
1333*4882a593Smuzhiyun WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
1334*4882a593Smuzhiyun
1335*4882a593Smuzhiyun /* Enable the DiskOnChip ASIC */
1336*4882a593Smuzhiyun WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
1337*4882a593Smuzhiyun WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun ChipID = ReadDOC(virtadr, ChipID);
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun switch (ChipID) {
1342*4882a593Smuzhiyun case DOC_ChipID_Doc2k:
1343*4882a593Smuzhiyun reg = DoC_2k_ECCStatus;
1344*4882a593Smuzhiyun break;
1345*4882a593Smuzhiyun case DOC_ChipID_DocMil:
1346*4882a593Smuzhiyun reg = DoC_ECCConf;
1347*4882a593Smuzhiyun break;
1348*4882a593Smuzhiyun case DOC_ChipID_DocMilPlus16:
1349*4882a593Smuzhiyun case DOC_ChipID_DocMilPlus32:
1350*4882a593Smuzhiyun case 0:
1351*4882a593Smuzhiyun /* Possible Millennium Plus, need to do more checks */
1352*4882a593Smuzhiyun /* Possibly release from power down mode */
1353*4882a593Smuzhiyun for (tmp = 0; (tmp < 4); tmp++)
1354*4882a593Smuzhiyun ReadDOC(virtadr, Mplus_Power);
1355*4882a593Smuzhiyun
1356*4882a593Smuzhiyun /* Reset the Millennium Plus ASIC */
1357*4882a593Smuzhiyun tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
1358*4882a593Smuzhiyun WriteDOC(tmp, virtadr, Mplus_DOCControl);
1359*4882a593Smuzhiyun WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
1360*4882a593Smuzhiyun
1361*4882a593Smuzhiyun usleep_range(1000, 2000);
1362*4882a593Smuzhiyun /* Enable the Millennium Plus ASIC */
1363*4882a593Smuzhiyun tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
1364*4882a593Smuzhiyun WriteDOC(tmp, virtadr, Mplus_DOCControl);
1365*4882a593Smuzhiyun WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
1366*4882a593Smuzhiyun usleep_range(1000, 2000);
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun ChipID = ReadDOC(virtadr, ChipID);
1369*4882a593Smuzhiyun
1370*4882a593Smuzhiyun switch (ChipID) {
1371*4882a593Smuzhiyun case DOC_ChipID_DocMilPlus16:
1372*4882a593Smuzhiyun reg = DoC_Mplus_Toggle;
1373*4882a593Smuzhiyun break;
1374*4882a593Smuzhiyun case DOC_ChipID_DocMilPlus32:
1375*4882a593Smuzhiyun pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
1376*4882a593Smuzhiyun fallthrough;
1377*4882a593Smuzhiyun default:
1378*4882a593Smuzhiyun ret = -ENODEV;
1379*4882a593Smuzhiyun goto notfound;
1380*4882a593Smuzhiyun }
1381*4882a593Smuzhiyun break;
1382*4882a593Smuzhiyun
1383*4882a593Smuzhiyun default:
1384*4882a593Smuzhiyun ret = -ENODEV;
1385*4882a593Smuzhiyun goto notfound;
1386*4882a593Smuzhiyun }
1387*4882a593Smuzhiyun /* Check the TOGGLE bit in the ECC register */
1388*4882a593Smuzhiyun tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
1389*4882a593Smuzhiyun tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
1390*4882a593Smuzhiyun tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
1391*4882a593Smuzhiyun if ((tmp == tmpb) || (tmp != tmpc)) {
1392*4882a593Smuzhiyun pr_warn("Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
1393*4882a593Smuzhiyun ret = -ENODEV;
1394*4882a593Smuzhiyun goto notfound;
1395*4882a593Smuzhiyun }
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun for (mtd = doclist; mtd; mtd = doc->nextdoc) {
1398*4882a593Smuzhiyun unsigned char oldval;
1399*4882a593Smuzhiyun unsigned char newval;
1400*4882a593Smuzhiyun nand = mtd_to_nand(mtd);
1401*4882a593Smuzhiyun doc = nand_get_controller_data(nand);
1402*4882a593Smuzhiyun /* Use the alias resolution register to determine if this is
1403*4882a593Smuzhiyun in fact the same DOC aliased to a new address. If writes
1404*4882a593Smuzhiyun to one chip's alias resolution register change the value on
1405*4882a593Smuzhiyun the other chip, they're the same chip. */
1406*4882a593Smuzhiyun if (ChipID == DOC_ChipID_DocMilPlus16) {
1407*4882a593Smuzhiyun oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
1408*4882a593Smuzhiyun newval = ReadDOC(virtadr, Mplus_AliasResolution);
1409*4882a593Smuzhiyun } else {
1410*4882a593Smuzhiyun oldval = ReadDOC(doc->virtadr, AliasResolution);
1411*4882a593Smuzhiyun newval = ReadDOC(virtadr, AliasResolution);
1412*4882a593Smuzhiyun }
1413*4882a593Smuzhiyun if (oldval != newval)
1414*4882a593Smuzhiyun continue;
1415*4882a593Smuzhiyun if (ChipID == DOC_ChipID_DocMilPlus16) {
1416*4882a593Smuzhiyun WriteDOC(~newval, virtadr, Mplus_AliasResolution);
1417*4882a593Smuzhiyun oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
1418*4882a593Smuzhiyun WriteDOC(newval, virtadr, Mplus_AliasResolution); // restore it
1419*4882a593Smuzhiyun } else {
1420*4882a593Smuzhiyun WriteDOC(~newval, virtadr, AliasResolution);
1421*4882a593Smuzhiyun oldval = ReadDOC(doc->virtadr, AliasResolution);
1422*4882a593Smuzhiyun WriteDOC(newval, virtadr, AliasResolution); // restore it
1423*4882a593Smuzhiyun }
1424*4882a593Smuzhiyun newval = ~newval;
1425*4882a593Smuzhiyun if (oldval == newval) {
1426*4882a593Smuzhiyun pr_debug("Found alias of DOC at 0x%lx to 0x%lx\n",
1427*4882a593Smuzhiyun doc->physadr, physadr);
1428*4882a593Smuzhiyun goto notfound;
1429*4882a593Smuzhiyun }
1430*4882a593Smuzhiyun }
1431*4882a593Smuzhiyun
1432*4882a593Smuzhiyun pr_notice("DiskOnChip found at 0x%lx\n", physadr);
1433*4882a593Smuzhiyun
1434*4882a593Smuzhiyun len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
1435*4882a593Smuzhiyun (2 * sizeof(struct nand_bbt_descr));
1436*4882a593Smuzhiyun nand = kzalloc(len, GFP_KERNEL);
1437*4882a593Smuzhiyun if (!nand) {
1438*4882a593Smuzhiyun ret = -ENOMEM;
1439*4882a593Smuzhiyun goto fail;
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun
1442*4882a593Smuzhiyun /*
1443*4882a593Smuzhiyun * Allocate a RS codec instance
1444*4882a593Smuzhiyun *
1445*4882a593Smuzhiyun * Symbolsize is 10 (bits)
1446*4882a593Smuzhiyun * Primitve polynomial is x^10+x^3+1
1447*4882a593Smuzhiyun * First consecutive root is 510
1448*4882a593Smuzhiyun * Primitve element to generate roots = 1
1449*4882a593Smuzhiyun * Generator polinomial degree = 4
1450*4882a593Smuzhiyun */
1451*4882a593Smuzhiyun doc = (struct doc_priv *) (nand + 1);
1452*4882a593Smuzhiyun doc->rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
1453*4882a593Smuzhiyun if (!doc->rs_decoder) {
1454*4882a593Smuzhiyun pr_err("DiskOnChip: Could not create a RS codec\n");
1455*4882a593Smuzhiyun ret = -ENOMEM;
1456*4882a593Smuzhiyun goto fail;
1457*4882a593Smuzhiyun }
1458*4882a593Smuzhiyun
1459*4882a593Smuzhiyun nand_controller_init(&doc->base);
1460*4882a593Smuzhiyun if (ChipID == DOC_ChipID_DocMilPlus16)
1461*4882a593Smuzhiyun doc->base.ops = &doc2001plus_ops;
1462*4882a593Smuzhiyun else
1463*4882a593Smuzhiyun doc->base.ops = &doc200x_ops;
1464*4882a593Smuzhiyun
1465*4882a593Smuzhiyun mtd = nand_to_mtd(nand);
1466*4882a593Smuzhiyun nand->bbt_td = (struct nand_bbt_descr *) (doc + 1);
1467*4882a593Smuzhiyun nand->bbt_md = nand->bbt_td + 1;
1468*4882a593Smuzhiyun
1469*4882a593Smuzhiyun mtd->owner = THIS_MODULE;
1470*4882a593Smuzhiyun mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
1471*4882a593Smuzhiyun
1472*4882a593Smuzhiyun nand->controller = &doc->base;
1473*4882a593Smuzhiyun nand_set_controller_data(nand, doc);
1474*4882a593Smuzhiyun nand->bbt_options = NAND_BBT_USE_FLASH;
1475*4882a593Smuzhiyun /* Skip the automatic BBT scan so we can run it manually */
1476*4882a593Smuzhiyun nand->options |= NAND_SKIP_BBTSCAN | NAND_NO_BBM_QUIRK;
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun doc->physadr = physadr;
1479*4882a593Smuzhiyun doc->virtadr = virtadr;
1480*4882a593Smuzhiyun doc->ChipID = ChipID;
1481*4882a593Smuzhiyun doc->curfloor = -1;
1482*4882a593Smuzhiyun doc->curchip = -1;
1483*4882a593Smuzhiyun doc->mh0_page = -1;
1484*4882a593Smuzhiyun doc->mh1_page = -1;
1485*4882a593Smuzhiyun doc->nextdoc = doclist;
1486*4882a593Smuzhiyun
1487*4882a593Smuzhiyun if (ChipID == DOC_ChipID_Doc2k)
1488*4882a593Smuzhiyun numchips = doc2000_init(mtd);
1489*4882a593Smuzhiyun else if (ChipID == DOC_ChipID_DocMilPlus16)
1490*4882a593Smuzhiyun numchips = doc2001plus_init(mtd);
1491*4882a593Smuzhiyun else
1492*4882a593Smuzhiyun numchips = doc2001_init(mtd);
1493*4882a593Smuzhiyun
1494*4882a593Smuzhiyun if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) {
1495*4882a593Smuzhiyun /* DBB note: i believe nand_cleanup is necessary here, as
1496*4882a593Smuzhiyun buffers may have been allocated in nand_base. Check with
1497*4882a593Smuzhiyun Thomas. FIX ME! */
1498*4882a593Smuzhiyun nand_cleanup(nand);
1499*4882a593Smuzhiyun goto fail;
1500*4882a593Smuzhiyun }
1501*4882a593Smuzhiyun
1502*4882a593Smuzhiyun /* Success! */
1503*4882a593Smuzhiyun doclist = mtd;
1504*4882a593Smuzhiyun return 0;
1505*4882a593Smuzhiyun
1506*4882a593Smuzhiyun notfound:
1507*4882a593Smuzhiyun /* Put back the contents of the DOCControl register, in case it's not
1508*4882a593Smuzhiyun actually a DiskOnChip. */
1509*4882a593Smuzhiyun WriteDOC(save_control, virtadr, DOCControl);
1510*4882a593Smuzhiyun fail:
1511*4882a593Smuzhiyun if (doc)
1512*4882a593Smuzhiyun free_rs(doc->rs_decoder);
1513*4882a593Smuzhiyun kfree(nand);
1514*4882a593Smuzhiyun iounmap(virtadr);
1515*4882a593Smuzhiyun
1516*4882a593Smuzhiyun error_ioremap:
1517*4882a593Smuzhiyun release_mem_region(physadr, DOC_IOREMAP_LEN);
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun return ret;
1520*4882a593Smuzhiyun }
1521*4882a593Smuzhiyun
release_nanddoc(void)1522*4882a593Smuzhiyun static void release_nanddoc(void)
1523*4882a593Smuzhiyun {
1524*4882a593Smuzhiyun struct mtd_info *mtd, *nextmtd;
1525*4882a593Smuzhiyun struct nand_chip *nand;
1526*4882a593Smuzhiyun struct doc_priv *doc;
1527*4882a593Smuzhiyun int ret;
1528*4882a593Smuzhiyun
1529*4882a593Smuzhiyun for (mtd = doclist; mtd; mtd = nextmtd) {
1530*4882a593Smuzhiyun nand = mtd_to_nand(mtd);
1531*4882a593Smuzhiyun doc = nand_get_controller_data(nand);
1532*4882a593Smuzhiyun
1533*4882a593Smuzhiyun nextmtd = doc->nextdoc;
1534*4882a593Smuzhiyun ret = mtd_device_unregister(mtd);
1535*4882a593Smuzhiyun WARN_ON(ret);
1536*4882a593Smuzhiyun nand_cleanup(nand);
1537*4882a593Smuzhiyun iounmap(doc->virtadr);
1538*4882a593Smuzhiyun release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
1539*4882a593Smuzhiyun free_rs(doc->rs_decoder);
1540*4882a593Smuzhiyun kfree(nand);
1541*4882a593Smuzhiyun }
1542*4882a593Smuzhiyun }
1543*4882a593Smuzhiyun
init_nanddoc(void)1544*4882a593Smuzhiyun static int __init init_nanddoc(void)
1545*4882a593Smuzhiyun {
1546*4882a593Smuzhiyun int i, ret = 0;
1547*4882a593Smuzhiyun
1548*4882a593Smuzhiyun if (doc_config_location) {
1549*4882a593Smuzhiyun pr_info("Using configured DiskOnChip probe address 0x%lx\n",
1550*4882a593Smuzhiyun doc_config_location);
1551*4882a593Smuzhiyun ret = doc_probe(doc_config_location);
1552*4882a593Smuzhiyun if (ret < 0)
1553*4882a593Smuzhiyun return ret;
1554*4882a593Smuzhiyun } else {
1555*4882a593Smuzhiyun for (i = 0; (doc_locations[i] != 0xffffffff); i++) {
1556*4882a593Smuzhiyun doc_probe(doc_locations[i]);
1557*4882a593Smuzhiyun }
1558*4882a593Smuzhiyun }
1559*4882a593Smuzhiyun /* No banner message any more. Print a message if no DiskOnChip
1560*4882a593Smuzhiyun found, so the user knows we at least tried. */
1561*4882a593Smuzhiyun if (!doclist) {
1562*4882a593Smuzhiyun pr_info("No valid DiskOnChip devices found\n");
1563*4882a593Smuzhiyun ret = -ENODEV;
1564*4882a593Smuzhiyun }
1565*4882a593Smuzhiyun return ret;
1566*4882a593Smuzhiyun }
1567*4882a593Smuzhiyun
cleanup_nanddoc(void)1568*4882a593Smuzhiyun static void __exit cleanup_nanddoc(void)
1569*4882a593Smuzhiyun {
1570*4882a593Smuzhiyun /* Cleanup the nand/DoC resources */
1571*4882a593Smuzhiyun release_nanddoc();
1572*4882a593Smuzhiyun }
1573*4882a593Smuzhiyun
1574*4882a593Smuzhiyun module_init(init_nanddoc);
1575*4882a593Smuzhiyun module_exit(cleanup_nanddoc);
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1578*4882a593Smuzhiyun MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1579*4882a593Smuzhiyun MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver");
1580