xref: /openbmc/linux/drivers/mtd/nand/raw/diskonchip.c (revision ed4543328f7108e1047b83b96ca7f7208747d930)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
293db446aSBoris Brezillon /*
393db446aSBoris Brezillon  * (C) 2003 Red Hat, Inc.
493db446aSBoris Brezillon  * (C) 2004 Dan Brown <dan_brown@ieee.org>
593db446aSBoris Brezillon  * (C) 2004 Kalev Lember <kalev@smartlink.ee>
693db446aSBoris Brezillon  *
793db446aSBoris Brezillon  * Author: David Woodhouse <dwmw2@infradead.org>
893db446aSBoris Brezillon  * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
993db446aSBoris Brezillon  * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
1093db446aSBoris Brezillon  *
1193db446aSBoris Brezillon  * Error correction code lifted from the old docecc code
1293db446aSBoris Brezillon  * Author: Fabrice Bellard (fabrice.bellard@netgem.com)
1393db446aSBoris Brezillon  * Copyright (C) 2000 Netgem S.A.
1493db446aSBoris Brezillon  * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
1593db446aSBoris Brezillon  *
1693db446aSBoris Brezillon  * Interface to generic NAND code for M-Systems DiskOnChip devices
1793db446aSBoris Brezillon  */
1893db446aSBoris Brezillon 
1993db446aSBoris Brezillon #include <linux/kernel.h>
2093db446aSBoris Brezillon #include <linux/init.h>
2193db446aSBoris Brezillon #include <linux/sched.h>
2293db446aSBoris Brezillon #include <linux/delay.h>
2393db446aSBoris Brezillon #include <linux/rslib.h>
2493db446aSBoris Brezillon #include <linux/moduleparam.h>
2593db446aSBoris Brezillon #include <linux/slab.h>
2693db446aSBoris Brezillon #include <linux/io.h>
2793db446aSBoris Brezillon 
2893db446aSBoris Brezillon #include <linux/mtd/mtd.h>
2993db446aSBoris Brezillon #include <linux/mtd/rawnand.h>
3093db446aSBoris Brezillon #include <linux/mtd/doc2000.h>
3193db446aSBoris Brezillon #include <linux/mtd/partitions.h>
3293db446aSBoris Brezillon #include <linux/mtd/inftl.h>
3393db446aSBoris Brezillon #include <linux/module.h>
3493db446aSBoris Brezillon 
3593db446aSBoris Brezillon /* Where to look for the devices? */
3693db446aSBoris Brezillon #ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
3793db446aSBoris Brezillon #define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
3893db446aSBoris Brezillon #endif
3993db446aSBoris Brezillon 
4093db446aSBoris Brezillon static unsigned long doc_locations[] __initdata = {
4193db446aSBoris Brezillon #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
4293db446aSBoris Brezillon #ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
4393db446aSBoris Brezillon 	0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
4493db446aSBoris Brezillon 	0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
4593db446aSBoris Brezillon 	0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
4693db446aSBoris Brezillon 	0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
4793db446aSBoris Brezillon 	0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
4893db446aSBoris Brezillon #else
4993db446aSBoris Brezillon 	0xc8000, 0xca000, 0xcc000, 0xce000,
5093db446aSBoris Brezillon 	0xd0000, 0xd2000, 0xd4000, 0xd6000,
5193db446aSBoris Brezillon 	0xd8000, 0xda000, 0xdc000, 0xde000,
5293db446aSBoris Brezillon 	0xe0000, 0xe2000, 0xe4000, 0xe6000,
5393db446aSBoris Brezillon 	0xe8000, 0xea000, 0xec000, 0xee000,
5493db446aSBoris Brezillon #endif
5593db446aSBoris Brezillon #endif
56db4ecbf8SArnd Bergmann };
5793db446aSBoris Brezillon 
5893db446aSBoris Brezillon static struct mtd_info *doclist = NULL;
5993db446aSBoris Brezillon 
6093db446aSBoris Brezillon struct doc_priv {
61f37b1d3cSBoris Brezillon 	struct nand_controller base;
6293db446aSBoris Brezillon 	void __iomem *virtadr;
6393db446aSBoris Brezillon 	unsigned long physadr;
6493db446aSBoris Brezillon 	u_char ChipID;
6593db446aSBoris Brezillon 	u_char CDSNControl;
6693db446aSBoris Brezillon 	int chips_per_floor;	/* The number of chips detected on each floor */
6793db446aSBoris Brezillon 	int curfloor;
6893db446aSBoris Brezillon 	int curchip;
6993db446aSBoris Brezillon 	int mh0_page;
7093db446aSBoris Brezillon 	int mh1_page;
71964dfce9SThomas Gleixner 	struct rs_control *rs_decoder;
7293db446aSBoris Brezillon 	struct mtd_info *nextdoc;
73fddf5cecSBoris Brezillon 	bool supports_32b_reads;
7493db446aSBoris Brezillon 
7593db446aSBoris Brezillon 	/* Handle the last stage of initialization (BBT scan, partitioning) */
7693db446aSBoris Brezillon 	int (*late_init)(struct mtd_info *mtd);
7793db446aSBoris Brezillon };
7893db446aSBoris Brezillon 
7993db446aSBoris Brezillon /* This is the ecc value computed by the HW ecc generator upon writing an empty
8093db446aSBoris Brezillon    page, one with all 0xff for data. */
8193db446aSBoris Brezillon static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 };
8293db446aSBoris Brezillon 
8393db446aSBoris Brezillon #define INFTL_BBT_RESERVED_BLOCKS 4
8493db446aSBoris Brezillon 
8593db446aSBoris Brezillon #define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32)
8693db446aSBoris Brezillon #define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil)
8793db446aSBoris Brezillon #define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k)
8893db446aSBoris Brezillon 
8993db446aSBoris Brezillon static int debug = 0;
9093db446aSBoris Brezillon module_param(debug, int, 0);
9193db446aSBoris Brezillon 
9293db446aSBoris Brezillon static int try_dword = 1;
9393db446aSBoris Brezillon module_param(try_dword, int, 0);
9493db446aSBoris Brezillon 
9593db446aSBoris Brezillon static int no_ecc_failures = 0;
9693db446aSBoris Brezillon module_param(no_ecc_failures, int, 0);
9793db446aSBoris Brezillon 
9893db446aSBoris Brezillon static int no_autopart = 0;
9993db446aSBoris Brezillon module_param(no_autopart, int, 0);
10093db446aSBoris Brezillon 
10193db446aSBoris Brezillon static int show_firmware_partition = 0;
10293db446aSBoris Brezillon module_param(show_firmware_partition, int, 0);
10393db446aSBoris Brezillon 
10493db446aSBoris Brezillon #ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE
10593db446aSBoris Brezillon static int inftl_bbt_write = 1;
10693db446aSBoris Brezillon #else
10793db446aSBoris Brezillon static int inftl_bbt_write = 0;
10893db446aSBoris Brezillon #endif
10993db446aSBoris Brezillon module_param(inftl_bbt_write, int, 0);
11093db446aSBoris Brezillon 
11193db446aSBoris Brezillon static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
11293db446aSBoris Brezillon module_param(doc_config_location, ulong, 0);
11393db446aSBoris Brezillon MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
11493db446aSBoris Brezillon 
11593db446aSBoris Brezillon /* Sector size for HW ECC */
11693db446aSBoris Brezillon #define SECTOR_SIZE 512
11793db446aSBoris Brezillon /* The sector bytes are packed into NB_DATA 10 bit words */
11893db446aSBoris Brezillon #define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
11993db446aSBoris Brezillon /* Number of roots */
12093db446aSBoris Brezillon #define NROOTS 4
12193db446aSBoris Brezillon /* First consective root */
12293db446aSBoris Brezillon #define FCR 510
12393db446aSBoris Brezillon /* Number of symbols */
12493db446aSBoris Brezillon #define NN 1023
12593db446aSBoris Brezillon 
12693db446aSBoris Brezillon /*
12793db446aSBoris Brezillon  * The HW decoder in the DoC ASIC's provides us a error syndrome,
12893db446aSBoris Brezillon  * which we must convert to a standard syndrome usable by the generic
12993db446aSBoris Brezillon  * Reed-Solomon library code.
13093db446aSBoris Brezillon  *
13193db446aSBoris Brezillon  * Fabrice Bellard figured this out in the old docecc code. I added
13293db446aSBoris Brezillon  * some comments, improved a minor bit and converted it to make use
13393db446aSBoris Brezillon  * of the generic Reed-Solomon library. tglx
13493db446aSBoris Brezillon  */
doc_ecc_decode(struct rs_control * rs,uint8_t * data,uint8_t * ecc)13593db446aSBoris Brezillon static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
13693db446aSBoris Brezillon {
13793db446aSBoris Brezillon 	int i, j, nerr, errpos[8];
13893db446aSBoris Brezillon 	uint8_t parity;
13993db446aSBoris Brezillon 	uint16_t ds[4], s[5], tmp, errval[8], syn[4];
14021633981SThomas Gleixner 	struct rs_codec *cd = rs->codec;
14193db446aSBoris Brezillon 
14293db446aSBoris Brezillon 	memset(syn, 0, sizeof(syn));
14393db446aSBoris Brezillon 	/* Convert the ecc bytes into words */
14493db446aSBoris Brezillon 	ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
14593db446aSBoris Brezillon 	ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
14693db446aSBoris Brezillon 	ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
14793db446aSBoris Brezillon 	ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
14893db446aSBoris Brezillon 	parity = ecc[1];
14993db446aSBoris Brezillon 
15093db446aSBoris Brezillon 	/* Initialize the syndrome buffer */
15193db446aSBoris Brezillon 	for (i = 0; i < NROOTS; i++)
15293db446aSBoris Brezillon 		s[i] = ds[0];
15393db446aSBoris Brezillon 	/*
15493db446aSBoris Brezillon 	 *  Evaluate
15593db446aSBoris Brezillon 	 *  s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
15693db446aSBoris Brezillon 	 *  where x = alpha^(FCR + i)
15793db446aSBoris Brezillon 	 */
15893db446aSBoris Brezillon 	for (j = 1; j < NROOTS; j++) {
15993db446aSBoris Brezillon 		if (ds[j] == 0)
16093db446aSBoris Brezillon 			continue;
16121633981SThomas Gleixner 		tmp = cd->index_of[ds[j]];
16293db446aSBoris Brezillon 		for (i = 0; i < NROOTS; i++)
16321633981SThomas Gleixner 			s[i] ^= cd->alpha_to[rs_modnn(cd, tmp + (FCR + i) * j)];
16493db446aSBoris Brezillon 	}
16593db446aSBoris Brezillon 
16693db446aSBoris Brezillon 	/* Calc syn[i] = s[i] / alpha^(v + i) */
16793db446aSBoris Brezillon 	for (i = 0; i < NROOTS; i++) {
16893db446aSBoris Brezillon 		if (s[i])
16921633981SThomas Gleixner 			syn[i] = rs_modnn(cd, cd->index_of[s[i]] + (NN - FCR - i));
17093db446aSBoris Brezillon 	}
17193db446aSBoris Brezillon 	/* Call the decoder library */
17293db446aSBoris Brezillon 	nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
17393db446aSBoris Brezillon 
17493db446aSBoris Brezillon 	/* Incorrectable errors ? */
17593db446aSBoris Brezillon 	if (nerr < 0)
17693db446aSBoris Brezillon 		return nerr;
17793db446aSBoris Brezillon 
17893db446aSBoris Brezillon 	/*
17993db446aSBoris Brezillon 	 * Correct the errors. The bitpositions are a bit of magic,
18093db446aSBoris Brezillon 	 * but they are given by the design of the de/encoder circuit
18193db446aSBoris Brezillon 	 * in the DoC ASIC's.
18293db446aSBoris Brezillon 	 */
18393db446aSBoris Brezillon 	for (i = 0; i < nerr; i++) {
18493db446aSBoris Brezillon 		int index, bitpos, pos = 1015 - errpos[i];
18593db446aSBoris Brezillon 		uint8_t val;
18693db446aSBoris Brezillon 		if (pos >= NB_DATA && pos < 1019)
18793db446aSBoris Brezillon 			continue;
18893db446aSBoris Brezillon 		if (pos < NB_DATA) {
18993db446aSBoris Brezillon 			/* extract bit position (MSB first) */
19093db446aSBoris Brezillon 			pos = 10 * (NB_DATA - 1 - pos) - 6;
19193db446aSBoris Brezillon 			/* now correct the following 10 bits. At most two bytes
19293db446aSBoris Brezillon 			   can be modified since pos is even */
19393db446aSBoris Brezillon 			index = (pos >> 3) ^ 1;
19493db446aSBoris Brezillon 			bitpos = pos & 7;
19593db446aSBoris Brezillon 			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
19693db446aSBoris Brezillon 				val = (uint8_t) (errval[i] >> (2 + bitpos));
19793db446aSBoris Brezillon 				parity ^= val;
19893db446aSBoris Brezillon 				if (index < SECTOR_SIZE)
19993db446aSBoris Brezillon 					data[index] ^= val;
20093db446aSBoris Brezillon 			}
20193db446aSBoris Brezillon 			index = ((pos >> 3) + 1) ^ 1;
20293db446aSBoris Brezillon 			bitpos = (bitpos + 10) & 7;
20393db446aSBoris Brezillon 			if (bitpos == 0)
20493db446aSBoris Brezillon 				bitpos = 8;
20593db446aSBoris Brezillon 			if ((index >= 0 && index < SECTOR_SIZE) || index == (SECTOR_SIZE + 1)) {
20693db446aSBoris Brezillon 				val = (uint8_t) (errval[i] << (8 - bitpos));
20793db446aSBoris Brezillon 				parity ^= val;
20893db446aSBoris Brezillon 				if (index < SECTOR_SIZE)
20993db446aSBoris Brezillon 					data[index] ^= val;
21093db446aSBoris Brezillon 			}
21193db446aSBoris Brezillon 		}
21293db446aSBoris Brezillon 	}
21393db446aSBoris Brezillon 	/* If the parity is wrong, no rescue possible */
21493db446aSBoris Brezillon 	return parity ? -EBADMSG : nerr;
21593db446aSBoris Brezillon }
21693db446aSBoris Brezillon 
DoC_Delay(struct doc_priv * doc,unsigned short cycles)21793db446aSBoris Brezillon static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
21893db446aSBoris Brezillon {
21963c34f21SLee Jones 	volatile char __always_unused dummy;
22093db446aSBoris Brezillon 	int i;
22193db446aSBoris Brezillon 
22293db446aSBoris Brezillon 	for (i = 0; i < cycles; i++) {
22393db446aSBoris Brezillon 		if (DoC_is_Millennium(doc))
22493db446aSBoris Brezillon 			dummy = ReadDOC(doc->virtadr, NOP);
22593db446aSBoris Brezillon 		else if (DoC_is_MillenniumPlus(doc))
22693db446aSBoris Brezillon 			dummy = ReadDOC(doc->virtadr, Mplus_NOP);
22793db446aSBoris Brezillon 		else
22893db446aSBoris Brezillon 			dummy = ReadDOC(doc->virtadr, DOCStatus);
22993db446aSBoris Brezillon 	}
23093db446aSBoris Brezillon 
23193db446aSBoris Brezillon }
23293db446aSBoris Brezillon 
23393db446aSBoris Brezillon #define CDSN_CTRL_FR_B_MASK	(CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1)
23493db446aSBoris Brezillon 
23593db446aSBoris Brezillon /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
_DoC_WaitReady(struct doc_priv * doc)23693db446aSBoris Brezillon static int _DoC_WaitReady(struct doc_priv *doc)
23793db446aSBoris Brezillon {
23893db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
23993db446aSBoris Brezillon 	unsigned long timeo = jiffies + (HZ * 10);
24093db446aSBoris Brezillon 
24193db446aSBoris Brezillon 	if (debug)
24293db446aSBoris Brezillon 		printk("_DoC_WaitReady...\n");
24393db446aSBoris Brezillon 	/* Out-of-line routine to wait for chip response */
24493db446aSBoris Brezillon 	if (DoC_is_MillenniumPlus(doc)) {
24593db446aSBoris Brezillon 		while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) {
24693db446aSBoris Brezillon 			if (time_after(jiffies, timeo)) {
24793db446aSBoris Brezillon 				printk("_DoC_WaitReady timed out.\n");
24893db446aSBoris Brezillon 				return -EIO;
24993db446aSBoris Brezillon 			}
25093db446aSBoris Brezillon 			udelay(1);
25193db446aSBoris Brezillon 			cond_resched();
25293db446aSBoris Brezillon 		}
25393db446aSBoris Brezillon 	} else {
25493db446aSBoris Brezillon 		while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
25593db446aSBoris Brezillon 			if (time_after(jiffies, timeo)) {
25693db446aSBoris Brezillon 				printk("_DoC_WaitReady timed out.\n");
25793db446aSBoris Brezillon 				return -EIO;
25893db446aSBoris Brezillon 			}
25993db446aSBoris Brezillon 			udelay(1);
26093db446aSBoris Brezillon 			cond_resched();
26193db446aSBoris Brezillon 		}
26293db446aSBoris Brezillon 	}
26393db446aSBoris Brezillon 
26493db446aSBoris Brezillon 	return 0;
26593db446aSBoris Brezillon }
26693db446aSBoris Brezillon 
DoC_WaitReady(struct doc_priv * doc)26793db446aSBoris Brezillon static inline int DoC_WaitReady(struct doc_priv *doc)
26893db446aSBoris Brezillon {
26993db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
27093db446aSBoris Brezillon 	int ret = 0;
27193db446aSBoris Brezillon 
27293db446aSBoris Brezillon 	if (DoC_is_MillenniumPlus(doc)) {
27393db446aSBoris Brezillon 		DoC_Delay(doc, 4);
27493db446aSBoris Brezillon 
27593db446aSBoris Brezillon 		if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK)
27693db446aSBoris Brezillon 			/* Call the out-of-line routine to wait */
27793db446aSBoris Brezillon 			ret = _DoC_WaitReady(doc);
27893db446aSBoris Brezillon 	} else {
27993db446aSBoris Brezillon 		DoC_Delay(doc, 4);
28093db446aSBoris Brezillon 
28193db446aSBoris Brezillon 		if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B))
28293db446aSBoris Brezillon 			/* Call the out-of-line routine to wait */
28393db446aSBoris Brezillon 			ret = _DoC_WaitReady(doc);
28493db446aSBoris Brezillon 		DoC_Delay(doc, 2);
28593db446aSBoris Brezillon 	}
28693db446aSBoris Brezillon 
28793db446aSBoris Brezillon 	if (debug)
28893db446aSBoris Brezillon 		printk("DoC_WaitReady OK\n");
28993db446aSBoris Brezillon 	return ret;
29093db446aSBoris Brezillon }
29193db446aSBoris Brezillon 
doc2000_write_byte(struct nand_chip * this,u_char datum)292c0739d85SBoris Brezillon static void doc2000_write_byte(struct nand_chip *this, u_char datum)
29393db446aSBoris Brezillon {
29493db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
29593db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
29693db446aSBoris Brezillon 
29793db446aSBoris Brezillon 	if (debug)
29893db446aSBoris Brezillon 		printk("write_byte %02x\n", datum);
29993db446aSBoris Brezillon 	WriteDOC(datum, docptr, CDSNSlowIO);
30093db446aSBoris Brezillon 	WriteDOC(datum, docptr, 2k_CDSN_IO);
30193db446aSBoris Brezillon }
30293db446aSBoris Brezillon 
doc2000_writebuf(struct nand_chip * this,const u_char * buf,int len)303c0739d85SBoris Brezillon static void doc2000_writebuf(struct nand_chip *this, const u_char *buf,
304c0739d85SBoris Brezillon 			     int len)
30593db446aSBoris Brezillon {
30693db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
30793db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
30893db446aSBoris Brezillon 	int i;
30993db446aSBoris Brezillon 	if (debug)
31093db446aSBoris Brezillon 		printk("writebuf of %d bytes: ", len);
31193db446aSBoris Brezillon 	for (i = 0; i < len; i++) {
31293db446aSBoris Brezillon 		WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i);
31393db446aSBoris Brezillon 		if (debug && i < 16)
31493db446aSBoris Brezillon 			printk("%02x ", buf[i]);
31593db446aSBoris Brezillon 	}
31693db446aSBoris Brezillon 	if (debug)
31793db446aSBoris Brezillon 		printk("\n");
31893db446aSBoris Brezillon }
31993db446aSBoris Brezillon 
doc2000_readbuf(struct nand_chip * this,u_char * buf,int len)3207e534323SBoris Brezillon static void doc2000_readbuf(struct nand_chip *this, u_char *buf, int len)
32193db446aSBoris Brezillon {
32293db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
32393db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
324fddf5cecSBoris Brezillon 	u32 *buf32 = (u32 *)buf;
32593db446aSBoris Brezillon 	int i;
32693db446aSBoris Brezillon 
32793db446aSBoris Brezillon 	if (debug)
32893db446aSBoris Brezillon 		printk("readbuf of %d bytes: ", len);
32993db446aSBoris Brezillon 
330fddf5cecSBoris Brezillon 	if (!doc->supports_32b_reads ||
331fddf5cecSBoris Brezillon 	    ((((unsigned long)buf) | len) & 3)) {
3327e534323SBoris Brezillon 		for (i = 0; i < len; i++)
33393db446aSBoris Brezillon 			buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i);
33493db446aSBoris Brezillon 	} else {
335fddf5cecSBoris Brezillon 		for (i = 0; i < len / 4; i++)
336fddf5cecSBoris Brezillon 			buf32[i] = readl(docptr + DoC_2k_CDSN_IO + i);
33793db446aSBoris Brezillon 	}
33893db446aSBoris Brezillon }
33993db446aSBoris Brezillon 
340f46eb7afSBoris Brezillon /*
341f46eb7afSBoris Brezillon  * We need our own readid() here because it's called before the NAND chip
342f46eb7afSBoris Brezillon  * has been initialized, and calling nand_op_readid() would lead to a NULL
343f46eb7afSBoris Brezillon  * pointer exception when dereferencing the NAND timings.
344f46eb7afSBoris Brezillon  */
doc200x_readid(struct nand_chip * this,unsigned int cs,u8 * id)345f46eb7afSBoris Brezillon static void doc200x_readid(struct nand_chip *this, unsigned int cs, u8 *id)
346f46eb7afSBoris Brezillon {
347f46eb7afSBoris Brezillon 	u8 addr = 0;
348f46eb7afSBoris Brezillon 	struct nand_op_instr instrs[] = {
349f46eb7afSBoris Brezillon 		NAND_OP_CMD(NAND_CMD_READID, 0),
350f46eb7afSBoris Brezillon 		NAND_OP_ADDR(1, &addr, 50),
351f46eb7afSBoris Brezillon 		NAND_OP_8BIT_DATA_IN(2, id, 0),
352f46eb7afSBoris Brezillon 	};
353f46eb7afSBoris Brezillon 
354f46eb7afSBoris Brezillon 	struct nand_operation op = NAND_OPERATION(cs, instrs);
355f46eb7afSBoris Brezillon 
356f46eb7afSBoris Brezillon 	if (!id)
357f46eb7afSBoris Brezillon 		op.ninstrs--;
358f46eb7afSBoris Brezillon 
359f46eb7afSBoris Brezillon 	this->controller->ops->exec_op(this, &op, false);
360f46eb7afSBoris Brezillon }
361f46eb7afSBoris Brezillon 
doc200x_ident_chip(struct mtd_info * mtd,int nr)36293db446aSBoris Brezillon static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
36393db446aSBoris Brezillon {
36493db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
36593db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
36693db446aSBoris Brezillon 	uint16_t ret;
367f46eb7afSBoris Brezillon 	u8 id[2];
36893db446aSBoris Brezillon 
369f46eb7afSBoris Brezillon 	doc200x_readid(this, nr, id);
37093db446aSBoris Brezillon 
371f46eb7afSBoris Brezillon 	ret = ((u16)id[0] << 8) | id[1];
37293db446aSBoris Brezillon 
37393db446aSBoris Brezillon 	if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) {
37493db446aSBoris Brezillon 		/* First chip probe. See if we get same results by 32-bit access */
37593db446aSBoris Brezillon 		union {
37693db446aSBoris Brezillon 			uint32_t dword;
37793db446aSBoris Brezillon 			uint8_t byte[4];
37893db446aSBoris Brezillon 		} ident;
37993db446aSBoris Brezillon 		void __iomem *docptr = doc->virtadr;
38093db446aSBoris Brezillon 
381f46eb7afSBoris Brezillon 		doc200x_readid(this, nr, NULL);
38293db446aSBoris Brezillon 
38393db446aSBoris Brezillon 		ident.dword = readl(docptr + DoC_2k_CDSN_IO);
38493db446aSBoris Brezillon 		if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
38563fa37f0SShreeya Patel 			pr_info("DiskOnChip 2000 responds to DWORD access\n");
386fddf5cecSBoris Brezillon 			doc->supports_32b_reads = true;
38793db446aSBoris Brezillon 		}
38893db446aSBoris Brezillon 	}
38993db446aSBoris Brezillon 
39093db446aSBoris Brezillon 	return ret;
39193db446aSBoris Brezillon }
39293db446aSBoris Brezillon 
doc2000_count_chips(struct mtd_info * mtd)39393db446aSBoris Brezillon static void __init doc2000_count_chips(struct mtd_info *mtd)
39493db446aSBoris Brezillon {
39593db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
39693db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
39793db446aSBoris Brezillon 	uint16_t mfrid;
39893db446aSBoris Brezillon 	int i;
39993db446aSBoris Brezillon 
40093db446aSBoris Brezillon 	/* Max 4 chips per floor on DiskOnChip 2000 */
40193db446aSBoris Brezillon 	doc->chips_per_floor = 4;
40293db446aSBoris Brezillon 
40393db446aSBoris Brezillon 	/* Find out what the first chip is */
40493db446aSBoris Brezillon 	mfrid = doc200x_ident_chip(mtd, 0);
40593db446aSBoris Brezillon 
40693db446aSBoris Brezillon 	/* Find how many chips in each floor. */
40793db446aSBoris Brezillon 	for (i = 1; i < 4; i++) {
40893db446aSBoris Brezillon 		if (doc200x_ident_chip(mtd, i) != mfrid)
40993db446aSBoris Brezillon 			break;
41093db446aSBoris Brezillon 	}
41193db446aSBoris Brezillon 	doc->chips_per_floor = i;
41263fa37f0SShreeya Patel 	pr_debug("Detected %d chips per floor.\n", i);
41393db446aSBoris Brezillon }
41493db446aSBoris Brezillon 
doc2001_write_byte(struct nand_chip * this,u_char datum)415c0739d85SBoris Brezillon static void doc2001_write_byte(struct nand_chip *this, u_char datum)
41693db446aSBoris Brezillon {
41793db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
41893db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
41993db446aSBoris Brezillon 
42093db446aSBoris Brezillon 	WriteDOC(datum, docptr, CDSNSlowIO);
42193db446aSBoris Brezillon 	WriteDOC(datum, docptr, Mil_CDSN_IO);
42293db446aSBoris Brezillon 	WriteDOC(datum, docptr, WritePipeTerm);
42393db446aSBoris Brezillon }
42493db446aSBoris Brezillon 
doc2001_writebuf(struct nand_chip * this,const u_char * buf,int len)425c0739d85SBoris Brezillon static void doc2001_writebuf(struct nand_chip *this, const u_char *buf, int len)
42693db446aSBoris Brezillon {
42793db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
42893db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
42993db446aSBoris Brezillon 	int i;
43093db446aSBoris Brezillon 
43193db446aSBoris Brezillon 	for (i = 0; i < len; i++)
43293db446aSBoris Brezillon 		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
43393db446aSBoris Brezillon 	/* Terminate write pipeline */
43493db446aSBoris Brezillon 	WriteDOC(0x00, docptr, WritePipeTerm);
43593db446aSBoris Brezillon }
43693db446aSBoris Brezillon 
doc2001_readbuf(struct nand_chip * this,u_char * buf,int len)4377e534323SBoris Brezillon static void doc2001_readbuf(struct nand_chip *this, u_char *buf, int len)
43893db446aSBoris Brezillon {
43993db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
44093db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
44193db446aSBoris Brezillon 	int i;
44293db446aSBoris Brezillon 
44393db446aSBoris Brezillon 	/* Start read pipeline */
44493db446aSBoris Brezillon 	ReadDOC(docptr, ReadPipeInit);
44593db446aSBoris Brezillon 
44693db446aSBoris Brezillon 	for (i = 0; i < len - 1; i++)
44793db446aSBoris Brezillon 		buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff));
44893db446aSBoris Brezillon 
44993db446aSBoris Brezillon 	/* Terminate read pipeline */
45093db446aSBoris Brezillon 	buf[i] = ReadDOC(docptr, LastDataRead);
45193db446aSBoris Brezillon }
45293db446aSBoris Brezillon 
doc2001plus_writebuf(struct nand_chip * this,const u_char * buf,int len)453c0739d85SBoris Brezillon static void doc2001plus_writebuf(struct nand_chip *this, const u_char *buf, int len)
45493db446aSBoris Brezillon {
45593db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
45693db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
45793db446aSBoris Brezillon 	int i;
45893db446aSBoris Brezillon 
45993db446aSBoris Brezillon 	if (debug)
46093db446aSBoris Brezillon 		printk("writebuf of %d bytes: ", len);
46193db446aSBoris Brezillon 	for (i = 0; i < len; i++) {
46293db446aSBoris Brezillon 		WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i);
46393db446aSBoris Brezillon 		if (debug && i < 16)
46493db446aSBoris Brezillon 			printk("%02x ", buf[i]);
46593db446aSBoris Brezillon 	}
46693db446aSBoris Brezillon 	if (debug)
46793db446aSBoris Brezillon 		printk("\n");
46893db446aSBoris Brezillon }
46993db446aSBoris Brezillon 
doc2001plus_readbuf(struct nand_chip * this,u_char * buf,int len)4707e534323SBoris Brezillon static void doc2001plus_readbuf(struct nand_chip *this, u_char *buf, int len)
47193db446aSBoris Brezillon {
47293db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
47393db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
47493db446aSBoris Brezillon 	int i;
47593db446aSBoris Brezillon 
47693db446aSBoris Brezillon 	if (debug)
47793db446aSBoris Brezillon 		printk("readbuf of %d bytes: ", len);
47893db446aSBoris Brezillon 
47993db446aSBoris Brezillon 	/* Start read pipeline */
48093db446aSBoris Brezillon 	ReadDOC(docptr, Mplus_ReadPipeInit);
48193db446aSBoris Brezillon 	ReadDOC(docptr, Mplus_ReadPipeInit);
48293db446aSBoris Brezillon 
48393db446aSBoris Brezillon 	for (i = 0; i < len - 2; i++) {
48493db446aSBoris Brezillon 		buf[i] = ReadDOC(docptr, Mil_CDSN_IO);
48593db446aSBoris Brezillon 		if (debug && i < 16)
48693db446aSBoris Brezillon 			printk("%02x ", buf[i]);
48793db446aSBoris Brezillon 	}
48893db446aSBoris Brezillon 
48993db446aSBoris Brezillon 	/* Terminate read pipeline */
490a50b0c20SBoris Brezillon 	if (len >= 2) {
49193db446aSBoris Brezillon 		buf[len - 2] = ReadDOC(docptr, Mplus_LastDataRead);
49293db446aSBoris Brezillon 		if (debug && i < 16)
49393db446aSBoris Brezillon 			printk("%02x ", buf[len - 2]);
494a50b0c20SBoris Brezillon 	}
495a50b0c20SBoris Brezillon 
49693db446aSBoris Brezillon 	buf[len - 1] = ReadDOC(docptr, Mplus_LastDataRead);
49793db446aSBoris Brezillon 	if (debug && i < 16)
49893db446aSBoris Brezillon 		printk("%02x ", buf[len - 1]);
49993db446aSBoris Brezillon 	if (debug)
50093db446aSBoris Brezillon 		printk("\n");
50193db446aSBoris Brezillon }
50293db446aSBoris Brezillon 
doc200x_write_control(struct doc_priv * doc,u8 value)503f46eb7afSBoris Brezillon static void doc200x_write_control(struct doc_priv *doc, u8 value)
504f46eb7afSBoris Brezillon {
505f46eb7afSBoris Brezillon 	WriteDOC(value, doc->virtadr, CDSNControl);
506f46eb7afSBoris Brezillon 	/* 11.4.3 -- 4 NOPs after CSDNControl write */
507f46eb7afSBoris Brezillon 	DoC_Delay(doc, 4);
508f46eb7afSBoris Brezillon }
509f46eb7afSBoris Brezillon 
doc200x_exec_instr(struct nand_chip * this,const struct nand_op_instr * instr)510f46eb7afSBoris Brezillon static void doc200x_exec_instr(struct nand_chip *this,
511f46eb7afSBoris Brezillon 			       const struct nand_op_instr *instr)
512f46eb7afSBoris Brezillon {
513f46eb7afSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
514f46eb7afSBoris Brezillon 	unsigned int i;
515f46eb7afSBoris Brezillon 
516f46eb7afSBoris Brezillon 	switch (instr->type) {
517f46eb7afSBoris Brezillon 	case NAND_OP_CMD_INSTR:
518f46eb7afSBoris Brezillon 		doc200x_write_control(doc, CDSN_CTRL_CE | CDSN_CTRL_CLE);
519f46eb7afSBoris Brezillon 		doc2000_write_byte(this, instr->ctx.cmd.opcode);
520f46eb7afSBoris Brezillon 		break;
521f46eb7afSBoris Brezillon 
522f46eb7afSBoris Brezillon 	case NAND_OP_ADDR_INSTR:
523f46eb7afSBoris Brezillon 		doc200x_write_control(doc, CDSN_CTRL_CE | CDSN_CTRL_ALE);
524f46eb7afSBoris Brezillon 		for (i = 0; i < instr->ctx.addr.naddrs; i++) {
525f46eb7afSBoris Brezillon 			u8 addr = instr->ctx.addr.addrs[i];
526f46eb7afSBoris Brezillon 
527f46eb7afSBoris Brezillon 			if (DoC_is_2000(doc))
528f46eb7afSBoris Brezillon 				doc2000_write_byte(this, addr);
529f46eb7afSBoris Brezillon 			else
530f46eb7afSBoris Brezillon 				doc2001_write_byte(this, addr);
531f46eb7afSBoris Brezillon 		}
532f46eb7afSBoris Brezillon 		break;
533f46eb7afSBoris Brezillon 
534f46eb7afSBoris Brezillon 	case NAND_OP_DATA_IN_INSTR:
535f46eb7afSBoris Brezillon 		doc200x_write_control(doc, CDSN_CTRL_CE);
536f46eb7afSBoris Brezillon 		if (DoC_is_2000(doc))
537f46eb7afSBoris Brezillon 			doc2000_readbuf(this, instr->ctx.data.buf.in,
538f46eb7afSBoris Brezillon 					instr->ctx.data.len);
539f46eb7afSBoris Brezillon 		else
540f46eb7afSBoris Brezillon 			doc2001_readbuf(this, instr->ctx.data.buf.in,
541f46eb7afSBoris Brezillon 					instr->ctx.data.len);
542f46eb7afSBoris Brezillon 		break;
543f46eb7afSBoris Brezillon 
544f46eb7afSBoris Brezillon 	case NAND_OP_DATA_OUT_INSTR:
545f46eb7afSBoris Brezillon 		doc200x_write_control(doc, CDSN_CTRL_CE);
546f46eb7afSBoris Brezillon 		if (DoC_is_2000(doc))
547f46eb7afSBoris Brezillon 			doc2000_writebuf(this, instr->ctx.data.buf.out,
548f46eb7afSBoris Brezillon 					 instr->ctx.data.len);
549f46eb7afSBoris Brezillon 		else
550f46eb7afSBoris Brezillon 			doc2001_writebuf(this, instr->ctx.data.buf.out,
551f46eb7afSBoris Brezillon 					 instr->ctx.data.len);
552f46eb7afSBoris Brezillon 		break;
553f46eb7afSBoris Brezillon 
554f46eb7afSBoris Brezillon 	case NAND_OP_WAITRDY_INSTR:
555f46eb7afSBoris Brezillon 		DoC_WaitReady(doc);
556f46eb7afSBoris Brezillon 		break;
557f46eb7afSBoris Brezillon 	}
558f46eb7afSBoris Brezillon 
559f46eb7afSBoris Brezillon 	if (instr->delay_ns)
560f46eb7afSBoris Brezillon 		ndelay(instr->delay_ns);
561f46eb7afSBoris Brezillon }
562f46eb7afSBoris Brezillon 
doc200x_exec_op(struct nand_chip * this,const struct nand_operation * op,bool check_only)563f46eb7afSBoris Brezillon static int doc200x_exec_op(struct nand_chip *this,
564f46eb7afSBoris Brezillon 			   const struct nand_operation *op,
565f46eb7afSBoris Brezillon 			   bool check_only)
566f46eb7afSBoris Brezillon {
567f46eb7afSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
568f46eb7afSBoris Brezillon 	unsigned int i;
569f46eb7afSBoris Brezillon 
570f46eb7afSBoris Brezillon 	if (check_only)
571f46eb7afSBoris Brezillon 		return true;
572f46eb7afSBoris Brezillon 
573f46eb7afSBoris Brezillon 	doc->curchip = op->cs % doc->chips_per_floor;
574f46eb7afSBoris Brezillon 	doc->curfloor = op->cs / doc->chips_per_floor;
575f46eb7afSBoris Brezillon 
576f46eb7afSBoris Brezillon 	WriteDOC(doc->curfloor, doc->virtadr, FloorSelect);
577f46eb7afSBoris Brezillon 	WriteDOC(doc->curchip, doc->virtadr, CDSNDeviceSelect);
578f46eb7afSBoris Brezillon 
579f46eb7afSBoris Brezillon 	/* Assert CE pin */
580f46eb7afSBoris Brezillon 	doc200x_write_control(doc, CDSN_CTRL_CE);
581f46eb7afSBoris Brezillon 
582f46eb7afSBoris Brezillon 	for (i = 0; i < op->ninstrs; i++)
583f46eb7afSBoris Brezillon 		doc200x_exec_instr(this, &op->instrs[i]);
584f46eb7afSBoris Brezillon 
585f46eb7afSBoris Brezillon 	/* De-assert CE pin */
586f46eb7afSBoris Brezillon 	doc200x_write_control(doc, 0);
587f46eb7afSBoris Brezillon 
588f46eb7afSBoris Brezillon 	return 0;
589f46eb7afSBoris Brezillon }
590f46eb7afSBoris Brezillon 
doc2001plus_write_pipe_term(struct doc_priv * doc)591f46eb7afSBoris Brezillon static void doc2001plus_write_pipe_term(struct doc_priv *doc)
592f46eb7afSBoris Brezillon {
593f46eb7afSBoris Brezillon 	WriteDOC(0x00, doc->virtadr, Mplus_WritePipeTerm);
594f46eb7afSBoris Brezillon 	WriteDOC(0x00, doc->virtadr, Mplus_WritePipeTerm);
595f46eb7afSBoris Brezillon }
596f46eb7afSBoris Brezillon 
doc2001plus_exec_instr(struct nand_chip * this,const struct nand_op_instr * instr)597f46eb7afSBoris Brezillon static void doc2001plus_exec_instr(struct nand_chip *this,
598f46eb7afSBoris Brezillon 				   const struct nand_op_instr *instr)
599f46eb7afSBoris Brezillon {
600f46eb7afSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
601f46eb7afSBoris Brezillon 	unsigned int i;
602f46eb7afSBoris Brezillon 
603f46eb7afSBoris Brezillon 	switch (instr->type) {
604f46eb7afSBoris Brezillon 	case NAND_OP_CMD_INSTR:
605f46eb7afSBoris Brezillon 		WriteDOC(instr->ctx.cmd.opcode, doc->virtadr, Mplus_FlashCmd);
606f46eb7afSBoris Brezillon 		doc2001plus_write_pipe_term(doc);
607f46eb7afSBoris Brezillon 		break;
608f46eb7afSBoris Brezillon 
609f46eb7afSBoris Brezillon 	case NAND_OP_ADDR_INSTR:
610f46eb7afSBoris Brezillon 		for (i = 0; i < instr->ctx.addr.naddrs; i++) {
611f46eb7afSBoris Brezillon 			u8 addr = instr->ctx.addr.addrs[i];
612f46eb7afSBoris Brezillon 
613f46eb7afSBoris Brezillon 			WriteDOC(addr, doc->virtadr, Mplus_FlashAddress);
614f46eb7afSBoris Brezillon 		}
615f46eb7afSBoris Brezillon 		doc2001plus_write_pipe_term(doc);
616f46eb7afSBoris Brezillon 		/* deassert ALE */
617f46eb7afSBoris Brezillon 		WriteDOC(0, doc->virtadr, Mplus_FlashControl);
618f46eb7afSBoris Brezillon 		break;
619f46eb7afSBoris Brezillon 
620f46eb7afSBoris Brezillon 	case NAND_OP_DATA_IN_INSTR:
621f46eb7afSBoris Brezillon 		doc2001plus_readbuf(this, instr->ctx.data.buf.in,
622f46eb7afSBoris Brezillon 				    instr->ctx.data.len);
623f46eb7afSBoris Brezillon 		break;
624f46eb7afSBoris Brezillon 	case NAND_OP_DATA_OUT_INSTR:
625f46eb7afSBoris Brezillon 		doc2001plus_writebuf(this, instr->ctx.data.buf.out,
626f46eb7afSBoris Brezillon 				     instr->ctx.data.len);
627f46eb7afSBoris Brezillon 		doc2001plus_write_pipe_term(doc);
628f46eb7afSBoris Brezillon 		break;
629f46eb7afSBoris Brezillon 	case NAND_OP_WAITRDY_INSTR:
630f46eb7afSBoris Brezillon 		DoC_WaitReady(doc);
631f46eb7afSBoris Brezillon 		break;
632f46eb7afSBoris Brezillon 	}
633f46eb7afSBoris Brezillon 
634f46eb7afSBoris Brezillon 	if (instr->delay_ns)
635f46eb7afSBoris Brezillon 		ndelay(instr->delay_ns);
636f46eb7afSBoris Brezillon }
637f46eb7afSBoris Brezillon 
doc2001plus_exec_op(struct nand_chip * this,const struct nand_operation * op,bool check_only)638f46eb7afSBoris Brezillon static int doc2001plus_exec_op(struct nand_chip *this,
639f46eb7afSBoris Brezillon 			       const struct nand_operation *op,
640f46eb7afSBoris Brezillon 			       bool check_only)
641f46eb7afSBoris Brezillon {
642f46eb7afSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
643f46eb7afSBoris Brezillon 	unsigned int i;
644f46eb7afSBoris Brezillon 
645f46eb7afSBoris Brezillon 	if (check_only)
646f46eb7afSBoris Brezillon 		return true;
647f46eb7afSBoris Brezillon 
648f46eb7afSBoris Brezillon 	doc->curchip = op->cs % doc->chips_per_floor;
649f46eb7afSBoris Brezillon 	doc->curfloor = op->cs / doc->chips_per_floor;
650f46eb7afSBoris Brezillon 
651f46eb7afSBoris Brezillon 	/* Assert ChipEnable and deassert WriteProtect */
652f46eb7afSBoris Brezillon 	WriteDOC(DOC_FLASH_CE, doc->virtadr, Mplus_FlashSelect);
653f46eb7afSBoris Brezillon 
654f46eb7afSBoris Brezillon 	for (i = 0; i < op->ninstrs; i++)
655f46eb7afSBoris Brezillon 		doc2001plus_exec_instr(this, &op->instrs[i]);
656f46eb7afSBoris Brezillon 
657f46eb7afSBoris Brezillon 	/* De-assert ChipEnable */
658f46eb7afSBoris Brezillon 	WriteDOC(0, doc->virtadr, Mplus_FlashSelect);
659f46eb7afSBoris Brezillon 
660f46eb7afSBoris Brezillon 	return 0;
661f46eb7afSBoris Brezillon }
662f46eb7afSBoris Brezillon 
doc200x_enable_hwecc(struct nand_chip * this,int mode)663ec47636cSBoris Brezillon static void doc200x_enable_hwecc(struct nand_chip *this, int mode)
66493db446aSBoris Brezillon {
66593db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
66693db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
66793db446aSBoris Brezillon 
66893db446aSBoris Brezillon 	/* Prime the ECC engine */
66993db446aSBoris Brezillon 	switch (mode) {
67093db446aSBoris Brezillon 	case NAND_ECC_READ:
67193db446aSBoris Brezillon 		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
67293db446aSBoris Brezillon 		WriteDOC(DOC_ECC_EN, docptr, ECCConf);
67393db446aSBoris Brezillon 		break;
67493db446aSBoris Brezillon 	case NAND_ECC_WRITE:
67593db446aSBoris Brezillon 		WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
67693db446aSBoris Brezillon 		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
67793db446aSBoris Brezillon 		break;
67893db446aSBoris Brezillon 	}
67993db446aSBoris Brezillon }
68093db446aSBoris Brezillon 
doc2001plus_enable_hwecc(struct nand_chip * this,int mode)681ec47636cSBoris Brezillon static void doc2001plus_enable_hwecc(struct nand_chip *this, int mode)
68293db446aSBoris Brezillon {
68393db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
68493db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
68593db446aSBoris Brezillon 
68693db446aSBoris Brezillon 	/* Prime the ECC engine */
68793db446aSBoris Brezillon 	switch (mode) {
68893db446aSBoris Brezillon 	case NAND_ECC_READ:
68993db446aSBoris Brezillon 		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
69093db446aSBoris Brezillon 		WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
69193db446aSBoris Brezillon 		break;
69293db446aSBoris Brezillon 	case NAND_ECC_WRITE:
69393db446aSBoris Brezillon 		WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
69493db446aSBoris Brezillon 		WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
69593db446aSBoris Brezillon 		break;
69693db446aSBoris Brezillon 	}
69793db446aSBoris Brezillon }
69893db446aSBoris Brezillon 
69993db446aSBoris Brezillon /* This code is only called on write */
doc200x_calculate_ecc(struct nand_chip * this,const u_char * dat,unsigned char * ecc_code)700af37d2c3SBoris Brezillon static int doc200x_calculate_ecc(struct nand_chip *this, const u_char *dat,
701af37d2c3SBoris Brezillon 				 unsigned char *ecc_code)
70293db446aSBoris Brezillon {
70393db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
70493db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
70593db446aSBoris Brezillon 	int i;
70663c34f21SLee Jones 	int __always_unused emptymatch = 1;
70793db446aSBoris Brezillon 
70893db446aSBoris Brezillon 	/* flush the pipeline */
70993db446aSBoris Brezillon 	if (DoC_is_2000(doc)) {
71093db446aSBoris Brezillon 		WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl);
71193db446aSBoris Brezillon 		WriteDOC(0, docptr, 2k_CDSN_IO);
71293db446aSBoris Brezillon 		WriteDOC(0, docptr, 2k_CDSN_IO);
71393db446aSBoris Brezillon 		WriteDOC(0, docptr, 2k_CDSN_IO);
71493db446aSBoris Brezillon 		WriteDOC(doc->CDSNControl, docptr, CDSNControl);
71593db446aSBoris Brezillon 	} else if (DoC_is_MillenniumPlus(doc)) {
71693db446aSBoris Brezillon 		WriteDOC(0, docptr, Mplus_NOP);
71793db446aSBoris Brezillon 		WriteDOC(0, docptr, Mplus_NOP);
71893db446aSBoris Brezillon 		WriteDOC(0, docptr, Mplus_NOP);
71993db446aSBoris Brezillon 	} else {
72093db446aSBoris Brezillon 		WriteDOC(0, docptr, NOP);
72193db446aSBoris Brezillon 		WriteDOC(0, docptr, NOP);
72293db446aSBoris Brezillon 		WriteDOC(0, docptr, NOP);
72393db446aSBoris Brezillon 	}
72493db446aSBoris Brezillon 
72593db446aSBoris Brezillon 	for (i = 0; i < 6; i++) {
72693db446aSBoris Brezillon 		if (DoC_is_MillenniumPlus(doc))
72793db446aSBoris Brezillon 			ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
72893db446aSBoris Brezillon 		else
72993db446aSBoris Brezillon 			ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
73093db446aSBoris Brezillon 		if (ecc_code[i] != empty_write_ecc[i])
73193db446aSBoris Brezillon 			emptymatch = 0;
73293db446aSBoris Brezillon 	}
73393db446aSBoris Brezillon 	if (DoC_is_MillenniumPlus(doc))
73493db446aSBoris Brezillon 		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
73593db446aSBoris Brezillon 	else
73693db446aSBoris Brezillon 		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
73793db446aSBoris Brezillon #if 0
73893db446aSBoris Brezillon 	/* If emptymatch=1, we might have an all-0xff data buffer.  Check. */
73993db446aSBoris Brezillon 	if (emptymatch) {
74093db446aSBoris Brezillon 		/* Note: this somewhat expensive test should not be triggered
74193db446aSBoris Brezillon 		   often.  It could be optimized away by examining the data in
74293db446aSBoris Brezillon 		   the writebuf routine, and remembering the result. */
74393db446aSBoris Brezillon 		for (i = 0; i < 512; i++) {
74493db446aSBoris Brezillon 			if (dat[i] == 0xff)
74593db446aSBoris Brezillon 				continue;
74693db446aSBoris Brezillon 			emptymatch = 0;
74793db446aSBoris Brezillon 			break;
74893db446aSBoris Brezillon 		}
74993db446aSBoris Brezillon 	}
75093db446aSBoris Brezillon 	/* If emptymatch still =1, we do have an all-0xff data buffer.
75193db446aSBoris Brezillon 	   Return all-0xff ecc value instead of the computed one, so
75293db446aSBoris Brezillon 	   it'll look just like a freshly-erased page. */
75393db446aSBoris Brezillon 	if (emptymatch)
75493db446aSBoris Brezillon 		memset(ecc_code, 0xff, 6);
75593db446aSBoris Brezillon #endif
75693db446aSBoris Brezillon 	return 0;
75793db446aSBoris Brezillon }
75893db446aSBoris Brezillon 
doc200x_correct_data(struct nand_chip * this,u_char * dat,u_char * read_ecc,u_char * isnull)75900da2ea9SBoris Brezillon static int doc200x_correct_data(struct nand_chip *this, u_char *dat,
76093db446aSBoris Brezillon 				u_char *read_ecc, u_char *isnull)
76193db446aSBoris Brezillon {
76293db446aSBoris Brezillon 	int i, ret = 0;
76393db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
76493db446aSBoris Brezillon 	void __iomem *docptr = doc->virtadr;
76593db446aSBoris Brezillon 	uint8_t calc_ecc[6];
76693db446aSBoris Brezillon 	volatile u_char dummy;
76793db446aSBoris Brezillon 
76893db446aSBoris Brezillon 	/* flush the pipeline */
76993db446aSBoris Brezillon 	if (DoC_is_2000(doc)) {
77093db446aSBoris Brezillon 		dummy = ReadDOC(docptr, 2k_ECCStatus);
77193db446aSBoris Brezillon 		dummy = ReadDOC(docptr, 2k_ECCStatus);
77293db446aSBoris Brezillon 		dummy = ReadDOC(docptr, 2k_ECCStatus);
77393db446aSBoris Brezillon 	} else if (DoC_is_MillenniumPlus(doc)) {
77493db446aSBoris Brezillon 		dummy = ReadDOC(docptr, Mplus_ECCConf);
77593db446aSBoris Brezillon 		dummy = ReadDOC(docptr, Mplus_ECCConf);
77693db446aSBoris Brezillon 		dummy = ReadDOC(docptr, Mplus_ECCConf);
77793db446aSBoris Brezillon 	} else {
77893db446aSBoris Brezillon 		dummy = ReadDOC(docptr, ECCConf);
77993db446aSBoris Brezillon 		dummy = ReadDOC(docptr, ECCConf);
78093db446aSBoris Brezillon 		dummy = ReadDOC(docptr, ECCConf);
78193db446aSBoris Brezillon 	}
78293db446aSBoris Brezillon 
78393db446aSBoris Brezillon 	/* Error occurred ? */
78493db446aSBoris Brezillon 	if (dummy & 0x80) {
78593db446aSBoris Brezillon 		for (i = 0; i < 6; i++) {
78693db446aSBoris Brezillon 			if (DoC_is_MillenniumPlus(doc))
78793db446aSBoris Brezillon 				calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i);
78893db446aSBoris Brezillon 			else
78993db446aSBoris Brezillon 				calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
79093db446aSBoris Brezillon 		}
79193db446aSBoris Brezillon 
792964dfce9SThomas Gleixner 		ret = doc_ecc_decode(doc->rs_decoder, dat, calc_ecc);
79393db446aSBoris Brezillon 		if (ret > 0)
79463fa37f0SShreeya Patel 			pr_err("doc200x_correct_data corrected %d errors\n",
79563fa37f0SShreeya Patel 			       ret);
79693db446aSBoris Brezillon 	}
79793db446aSBoris Brezillon 	if (DoC_is_MillenniumPlus(doc))
79893db446aSBoris Brezillon 		WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
79993db446aSBoris Brezillon 	else
80093db446aSBoris Brezillon 		WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
80193db446aSBoris Brezillon 	if (no_ecc_failures && mtd_is_eccerr(ret)) {
80263fa37f0SShreeya Patel 		pr_err("suppressing ECC failure\n");
80393db446aSBoris Brezillon 		ret = 0;
80493db446aSBoris Brezillon 	}
80593db446aSBoris Brezillon 	return ret;
80693db446aSBoris Brezillon }
80793db446aSBoris Brezillon 
80893db446aSBoris Brezillon //u_char mydatabuf[528];
80993db446aSBoris Brezillon 
doc200x_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)81093db446aSBoris Brezillon static int doc200x_ooblayout_ecc(struct mtd_info *mtd, int section,
81193db446aSBoris Brezillon 				 struct mtd_oob_region *oobregion)
81293db446aSBoris Brezillon {
81393db446aSBoris Brezillon 	if (section)
81493db446aSBoris Brezillon 		return -ERANGE;
81593db446aSBoris Brezillon 
81693db446aSBoris Brezillon 	oobregion->offset = 0;
81793db446aSBoris Brezillon 	oobregion->length = 6;
81893db446aSBoris Brezillon 
81993db446aSBoris Brezillon 	return 0;
82093db446aSBoris Brezillon }
82193db446aSBoris Brezillon 
doc200x_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)82293db446aSBoris Brezillon static int doc200x_ooblayout_free(struct mtd_info *mtd, int section,
82393db446aSBoris Brezillon 				  struct mtd_oob_region *oobregion)
82493db446aSBoris Brezillon {
82593db446aSBoris Brezillon 	if (section > 1)
82693db446aSBoris Brezillon 		return -ERANGE;
82793db446aSBoris Brezillon 
82893db446aSBoris Brezillon 	/*
82993db446aSBoris Brezillon 	 * The strange out-of-order free bytes definition is a (possibly
83093db446aSBoris Brezillon 	 * unneeded) attempt to retain compatibility.  It used to read:
83193db446aSBoris Brezillon 	 *	.oobfree = { {8, 8} }
83293db446aSBoris Brezillon 	 * Since that leaves two bytes unusable, it was changed.  But the
83393db446aSBoris Brezillon 	 * following scheme might affect existing jffs2 installs by moving the
83493db446aSBoris Brezillon 	 * cleanmarker:
83593db446aSBoris Brezillon 	 *	.oobfree = { {6, 10} }
83693db446aSBoris Brezillon 	 * jffs2 seems to handle the above gracefully, but the current scheme
83793db446aSBoris Brezillon 	 * seems safer. The only problem with it is that any code retrieving
83893db446aSBoris Brezillon 	 * free bytes position must be able to handle out-of-order segments.
83993db446aSBoris Brezillon 	 */
84093db446aSBoris Brezillon 	if (!section) {
84193db446aSBoris Brezillon 		oobregion->offset = 8;
84293db446aSBoris Brezillon 		oobregion->length = 8;
84393db446aSBoris Brezillon 	} else {
84493db446aSBoris Brezillon 		oobregion->offset = 6;
84593db446aSBoris Brezillon 		oobregion->length = 2;
84693db446aSBoris Brezillon 	}
84793db446aSBoris Brezillon 
84893db446aSBoris Brezillon 	return 0;
84993db446aSBoris Brezillon }
85093db446aSBoris Brezillon 
85193db446aSBoris Brezillon static const struct mtd_ooblayout_ops doc200x_ooblayout_ops = {
85293db446aSBoris Brezillon 	.ecc = doc200x_ooblayout_ecc,
85393db446aSBoris Brezillon 	.free = doc200x_ooblayout_free,
85493db446aSBoris Brezillon };
85593db446aSBoris Brezillon 
85693db446aSBoris Brezillon /* Find the (I)NFTL Media Header, and optionally also the mirror media header.
85793db446aSBoris Brezillon    On successful return, buf will contain a copy of the media header for
85893db446aSBoris Brezillon    further processing.  id is the string to scan for, and will presumably be
85993db446aSBoris Brezillon    either "ANAND" or "BNAND".  If findmirror=1, also look for the mirror media
86093db446aSBoris Brezillon    header.  The page #s of the found media headers are placed in mh0_page and
86193db446aSBoris Brezillon    mh1_page in the DOC private structure. */
find_media_headers(struct mtd_info * mtd,u_char * buf,const char * id,int findmirror)86293db446aSBoris Brezillon static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const char *id, int findmirror)
86393db446aSBoris Brezillon {
86493db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
86593db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
86693db446aSBoris Brezillon 	unsigned offs;
86793db446aSBoris Brezillon 	int ret;
86893db446aSBoris Brezillon 	size_t retlen;
86993db446aSBoris Brezillon 
87093db446aSBoris Brezillon 	for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
87193db446aSBoris Brezillon 		ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
87293db446aSBoris Brezillon 		if (retlen != mtd->writesize)
87393db446aSBoris Brezillon 			continue;
87493db446aSBoris Brezillon 		if (ret) {
87563fa37f0SShreeya Patel 			pr_warn("ECC error scanning DOC at 0x%x\n", offs);
87693db446aSBoris Brezillon 		}
87793db446aSBoris Brezillon 		if (memcmp(buf, id, 6))
87893db446aSBoris Brezillon 			continue;
87963fa37f0SShreeya Patel 		pr_info("Found DiskOnChip %s Media Header at 0x%x\n", id, offs);
88093db446aSBoris Brezillon 		if (doc->mh0_page == -1) {
88193db446aSBoris Brezillon 			doc->mh0_page = offs >> this->page_shift;
88293db446aSBoris Brezillon 			if (!findmirror)
88393db446aSBoris Brezillon 				return 1;
88493db446aSBoris Brezillon 			continue;
88593db446aSBoris Brezillon 		}
88693db446aSBoris Brezillon 		doc->mh1_page = offs >> this->page_shift;
88793db446aSBoris Brezillon 		return 2;
88893db446aSBoris Brezillon 	}
88993db446aSBoris Brezillon 	if (doc->mh0_page == -1) {
89063fa37f0SShreeya Patel 		pr_warn("DiskOnChip %s Media Header not found.\n", id);
89193db446aSBoris Brezillon 		return 0;
89293db446aSBoris Brezillon 	}
89393db446aSBoris Brezillon 	/* Only one mediaheader was found.  We want buf to contain a
89493db446aSBoris Brezillon 	   mediaheader on return, so we'll have to re-read the one we found. */
89593db446aSBoris Brezillon 	offs = doc->mh0_page << this->page_shift;
89693db446aSBoris Brezillon 	ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf);
89793db446aSBoris Brezillon 	if (retlen != mtd->writesize) {
89893db446aSBoris Brezillon 		/* Insanity.  Give up. */
89963fa37f0SShreeya Patel 		pr_err("Read DiskOnChip Media Header once, but can't reread it???\n");
90093db446aSBoris Brezillon 		return 0;
90193db446aSBoris Brezillon 	}
90293db446aSBoris Brezillon 	return 1;
90393db446aSBoris Brezillon }
90493db446aSBoris Brezillon 
nftl_partscan(struct mtd_info * mtd,struct mtd_partition * parts)90593db446aSBoris Brezillon static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
90693db446aSBoris Brezillon {
90793db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
90893db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
909629a442cSBoris Brezillon 	struct nand_memory_organization *memorg;
91093db446aSBoris Brezillon 	int ret = 0;
91193db446aSBoris Brezillon 	u_char *buf;
91293db446aSBoris Brezillon 	struct NFTLMediaHeader *mh;
91393db446aSBoris Brezillon 	const unsigned psize = 1 << this->page_shift;
91493db446aSBoris Brezillon 	int numparts = 0;
91593db446aSBoris Brezillon 	unsigned blocks, maxblocks;
91693db446aSBoris Brezillon 	int offs, numheaders;
91793db446aSBoris Brezillon 
918629a442cSBoris Brezillon 	memorg = nanddev_get_memorg(&this->base);
919629a442cSBoris Brezillon 
92093db446aSBoris Brezillon 	buf = kmalloc(mtd->writesize, GFP_KERNEL);
92193db446aSBoris Brezillon 	if (!buf) {
92293db446aSBoris Brezillon 		return 0;
92393db446aSBoris Brezillon 	}
92493db446aSBoris Brezillon 	if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
92593db446aSBoris Brezillon 		goto out;
92693db446aSBoris Brezillon 	mh = (struct NFTLMediaHeader *)buf;
92793db446aSBoris Brezillon 
92893db446aSBoris Brezillon 	le16_to_cpus(&mh->NumEraseUnits);
92993db446aSBoris Brezillon 	le16_to_cpus(&mh->FirstPhysicalEUN);
93093db446aSBoris Brezillon 	le32_to_cpus(&mh->FormattedSize);
93193db446aSBoris Brezillon 
93263fa37f0SShreeya Patel 	pr_info("    DataOrgID        = %s\n"
93393db446aSBoris Brezillon 		"    NumEraseUnits    = %d\n"
93493db446aSBoris Brezillon 		"    FirstPhysicalEUN = %d\n"
93593db446aSBoris Brezillon 		"    FormattedSize    = %d\n"
93693db446aSBoris Brezillon 		"    UnitSizeFactor   = %d\n",
93793db446aSBoris Brezillon 		mh->DataOrgID, mh->NumEraseUnits,
93893db446aSBoris Brezillon 		mh->FirstPhysicalEUN, mh->FormattedSize,
93993db446aSBoris Brezillon 		mh->UnitSizeFactor);
94093db446aSBoris Brezillon 
94193db446aSBoris Brezillon 	blocks = mtd->size >> this->phys_erase_shift;
94293db446aSBoris Brezillon 	maxblocks = min(32768U, mtd->erasesize - psize);
94393db446aSBoris Brezillon 
94493db446aSBoris Brezillon 	if (mh->UnitSizeFactor == 0x00) {
94593db446aSBoris Brezillon 		/* Auto-determine UnitSizeFactor.  The constraints are:
94693db446aSBoris Brezillon 		   - There can be at most 32768 virtual blocks.
94793db446aSBoris Brezillon 		   - There can be at most (virtual block size - page size)
94893db446aSBoris Brezillon 		   virtual blocks (because MediaHeader+BBT must fit in 1).
94993db446aSBoris Brezillon 		 */
95093db446aSBoris Brezillon 		mh->UnitSizeFactor = 0xff;
95193db446aSBoris Brezillon 		while (blocks > maxblocks) {
95293db446aSBoris Brezillon 			blocks >>= 1;
95393db446aSBoris Brezillon 			maxblocks = min(32768U, (maxblocks << 1) + psize);
95493db446aSBoris Brezillon 			mh->UnitSizeFactor--;
95593db446aSBoris Brezillon 		}
95663fa37f0SShreeya Patel 		pr_warn("UnitSizeFactor=0x00 detected.  Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor);
95793db446aSBoris Brezillon 	}
95893db446aSBoris Brezillon 
95993db446aSBoris Brezillon 	/* NOTE: The lines below modify internal variables of the NAND and MTD
96093db446aSBoris Brezillon 	   layers; variables with have already been configured by nand_scan.
96193db446aSBoris Brezillon 	   Unfortunately, we didn't know before this point what these values
96293db446aSBoris Brezillon 	   should be.  Thus, this code is somewhat dependent on the exact
96393db446aSBoris Brezillon 	   implementation of the NAND layer.  */
96493db446aSBoris Brezillon 	if (mh->UnitSizeFactor != 0xff) {
96593db446aSBoris Brezillon 		this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
966629a442cSBoris Brezillon 		memorg->pages_per_eraseblock <<= (0xff - mh->UnitSizeFactor);
96793db446aSBoris Brezillon 		mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
96863fa37f0SShreeya Patel 		pr_info("Setting virtual erase size to %d\n", mtd->erasesize);
96993db446aSBoris Brezillon 		blocks = mtd->size >> this->bbt_erase_shift;
97093db446aSBoris Brezillon 		maxblocks = min(32768U, mtd->erasesize - psize);
97193db446aSBoris Brezillon 	}
97293db446aSBoris Brezillon 
97393db446aSBoris Brezillon 	if (blocks > maxblocks) {
97463fa37f0SShreeya Patel 		pr_err("UnitSizeFactor of 0x%02x is inconsistent with device size.  Aborting.\n", mh->UnitSizeFactor);
97593db446aSBoris Brezillon 		goto out;
97693db446aSBoris Brezillon 	}
97793db446aSBoris Brezillon 
97893db446aSBoris Brezillon 	/* Skip past the media headers. */
97993db446aSBoris Brezillon 	offs = max(doc->mh0_page, doc->mh1_page);
98093db446aSBoris Brezillon 	offs <<= this->page_shift;
98193db446aSBoris Brezillon 	offs += mtd->erasesize;
98293db446aSBoris Brezillon 
98393db446aSBoris Brezillon 	if (show_firmware_partition == 1) {
98493db446aSBoris Brezillon 		parts[0].name = " DiskOnChip Firmware / Media Header partition";
98593db446aSBoris Brezillon 		parts[0].offset = 0;
98693db446aSBoris Brezillon 		parts[0].size = offs;
98793db446aSBoris Brezillon 		numparts = 1;
98893db446aSBoris Brezillon 	}
98993db446aSBoris Brezillon 
99093db446aSBoris Brezillon 	parts[numparts].name = " DiskOnChip BDTL partition";
99193db446aSBoris Brezillon 	parts[numparts].offset = offs;
99293db446aSBoris Brezillon 	parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
99393db446aSBoris Brezillon 
99493db446aSBoris Brezillon 	offs += parts[numparts].size;
99593db446aSBoris Brezillon 	numparts++;
99693db446aSBoris Brezillon 
99793db446aSBoris Brezillon 	if (offs < mtd->size) {
99893db446aSBoris Brezillon 		parts[numparts].name = " DiskOnChip Remainder partition";
99993db446aSBoris Brezillon 		parts[numparts].offset = offs;
100093db446aSBoris Brezillon 		parts[numparts].size = mtd->size - offs;
100193db446aSBoris Brezillon 		numparts++;
100293db446aSBoris Brezillon 	}
100393db446aSBoris Brezillon 
100493db446aSBoris Brezillon 	ret = numparts;
100593db446aSBoris Brezillon  out:
100693db446aSBoris Brezillon 	kfree(buf);
100793db446aSBoris Brezillon 	return ret;
100893db446aSBoris Brezillon }
100993db446aSBoris Brezillon 
101093db446aSBoris Brezillon /* This is a stripped-down copy of the code in inftlmount.c */
inftl_partscan(struct mtd_info * mtd,struct mtd_partition * parts)101193db446aSBoris Brezillon static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partition *parts)
101293db446aSBoris Brezillon {
101393db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
101493db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
101593db446aSBoris Brezillon 	int ret = 0;
101693db446aSBoris Brezillon 	u_char *buf;
101793db446aSBoris Brezillon 	struct INFTLMediaHeader *mh;
101893db446aSBoris Brezillon 	struct INFTLPartition *ip;
101993db446aSBoris Brezillon 	int numparts = 0;
102093db446aSBoris Brezillon 	int blocks;
102193db446aSBoris Brezillon 	int vshift, lastvunit = 0;
102293db446aSBoris Brezillon 	int i;
102393db446aSBoris Brezillon 	int end = mtd->size;
102493db446aSBoris Brezillon 
102593db446aSBoris Brezillon 	if (inftl_bbt_write)
102693db446aSBoris Brezillon 		end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift);
102793db446aSBoris Brezillon 
102893db446aSBoris Brezillon 	buf = kmalloc(mtd->writesize, GFP_KERNEL);
102993db446aSBoris Brezillon 	if (!buf) {
103093db446aSBoris Brezillon 		return 0;
103193db446aSBoris Brezillon 	}
103293db446aSBoris Brezillon 
103393db446aSBoris Brezillon 	if (!find_media_headers(mtd, buf, "BNAND", 0))
103493db446aSBoris Brezillon 		goto out;
103593db446aSBoris Brezillon 	doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift);
103693db446aSBoris Brezillon 	mh = (struct INFTLMediaHeader *)buf;
103793db446aSBoris Brezillon 
103893db446aSBoris Brezillon 	le32_to_cpus(&mh->NoOfBootImageBlocks);
103993db446aSBoris Brezillon 	le32_to_cpus(&mh->NoOfBinaryPartitions);
104093db446aSBoris Brezillon 	le32_to_cpus(&mh->NoOfBDTLPartitions);
104193db446aSBoris Brezillon 	le32_to_cpus(&mh->BlockMultiplierBits);
104293db446aSBoris Brezillon 	le32_to_cpus(&mh->FormatFlags);
104393db446aSBoris Brezillon 	le32_to_cpus(&mh->PercentUsed);
104493db446aSBoris Brezillon 
104563fa37f0SShreeya Patel 	pr_info("    bootRecordID          = %s\n"
104693db446aSBoris Brezillon 		"    NoOfBootImageBlocks   = %d\n"
104793db446aSBoris Brezillon 		"    NoOfBinaryPartitions  = %d\n"
104893db446aSBoris Brezillon 		"    NoOfBDTLPartitions    = %d\n"
104913a96466SColin Ian King 		"    BlockMultiplierBits   = %d\n"
105093db446aSBoris Brezillon 		"    FormatFlgs            = %d\n"
105193db446aSBoris Brezillon 		"    OsakVersion           = %d.%d.%d.%d\n"
105293db446aSBoris Brezillon 		"    PercentUsed           = %d\n",
105393db446aSBoris Brezillon 		mh->bootRecordID, mh->NoOfBootImageBlocks,
105493db446aSBoris Brezillon 		mh->NoOfBinaryPartitions,
105593db446aSBoris Brezillon 		mh->NoOfBDTLPartitions,
105693db446aSBoris Brezillon 		mh->BlockMultiplierBits, mh->FormatFlags,
105793db446aSBoris Brezillon 		((unsigned char *) &mh->OsakVersion)[0] & 0xf,
105893db446aSBoris Brezillon 		((unsigned char *) &mh->OsakVersion)[1] & 0xf,
105993db446aSBoris Brezillon 		((unsigned char *) &mh->OsakVersion)[2] & 0xf,
106093db446aSBoris Brezillon 		((unsigned char *) &mh->OsakVersion)[3] & 0xf,
106193db446aSBoris Brezillon 		mh->PercentUsed);
106293db446aSBoris Brezillon 
106393db446aSBoris Brezillon 	vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
106493db446aSBoris Brezillon 
106593db446aSBoris Brezillon 	blocks = mtd->size >> vshift;
106693db446aSBoris Brezillon 	if (blocks > 32768) {
106763fa37f0SShreeya Patel 		pr_err("BlockMultiplierBits=%d is inconsistent with device size.  Aborting.\n", mh->BlockMultiplierBits);
106893db446aSBoris Brezillon 		goto out;
106993db446aSBoris Brezillon 	}
107093db446aSBoris Brezillon 
107193db446aSBoris Brezillon 	blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift);
107293db446aSBoris Brezillon 	if (inftl_bbt_write && (blocks > mtd->erasesize)) {
107363fa37f0SShreeya Patel 		pr_err("Writeable BBTs spanning more than one erase block are not yet supported.  FIX ME!\n");
107493db446aSBoris Brezillon 		goto out;
107593db446aSBoris Brezillon 	}
107693db446aSBoris Brezillon 
107793db446aSBoris Brezillon 	/* Scan the partitions */
107893db446aSBoris Brezillon 	for (i = 0; (i < 4); i++) {
107993db446aSBoris Brezillon 		ip = &(mh->Partitions[i]);
108093db446aSBoris Brezillon 		le32_to_cpus(&ip->virtualUnits);
108193db446aSBoris Brezillon 		le32_to_cpus(&ip->firstUnit);
108293db446aSBoris Brezillon 		le32_to_cpus(&ip->lastUnit);
108393db446aSBoris Brezillon 		le32_to_cpus(&ip->flags);
108493db446aSBoris Brezillon 		le32_to_cpus(&ip->spareUnits);
108593db446aSBoris Brezillon 		le32_to_cpus(&ip->Reserved0);
108693db446aSBoris Brezillon 
108763fa37f0SShreeya Patel 		pr_info("    PARTITION[%d] ->\n"
108893db446aSBoris Brezillon 			"        virtualUnits    = %d\n"
108993db446aSBoris Brezillon 			"        firstUnit       = %d\n"
109093db446aSBoris Brezillon 			"        lastUnit        = %d\n"
109193db446aSBoris Brezillon 			"        flags           = 0x%x\n"
109293db446aSBoris Brezillon 			"        spareUnits      = %d\n",
109393db446aSBoris Brezillon 			i, ip->virtualUnits, ip->firstUnit,
109493db446aSBoris Brezillon 			ip->lastUnit, ip->flags,
109593db446aSBoris Brezillon 			ip->spareUnits);
109693db446aSBoris Brezillon 
109793db446aSBoris Brezillon 		if ((show_firmware_partition == 1) &&
109893db446aSBoris Brezillon 		    (i == 0) && (ip->firstUnit > 0)) {
109993db446aSBoris Brezillon 			parts[0].name = " DiskOnChip IPL / Media Header partition";
110093db446aSBoris Brezillon 			parts[0].offset = 0;
1101*3970d6b3SZichen Xie 			parts[0].size = (uint64_t)mtd->erasesize * ip->firstUnit;
110293db446aSBoris Brezillon 			numparts = 1;
110393db446aSBoris Brezillon 		}
110493db446aSBoris Brezillon 
110593db446aSBoris Brezillon 		if (ip->flags & INFTL_BINARY)
110693db446aSBoris Brezillon 			parts[numparts].name = " DiskOnChip BDK partition";
110793db446aSBoris Brezillon 		else
110893db446aSBoris Brezillon 			parts[numparts].name = " DiskOnChip BDTL partition";
110993db446aSBoris Brezillon 		parts[numparts].offset = ip->firstUnit << vshift;
111093db446aSBoris Brezillon 		parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift;
111193db446aSBoris Brezillon 		numparts++;
111293db446aSBoris Brezillon 		if (ip->lastUnit > lastvunit)
111393db446aSBoris Brezillon 			lastvunit = ip->lastUnit;
111493db446aSBoris Brezillon 		if (ip->flags & INFTL_LAST)
111593db446aSBoris Brezillon 			break;
111693db446aSBoris Brezillon 	}
111793db446aSBoris Brezillon 	lastvunit++;
111893db446aSBoris Brezillon 	if ((lastvunit << vshift) < end) {
111993db446aSBoris Brezillon 		parts[numparts].name = " DiskOnChip Remainder partition";
112093db446aSBoris Brezillon 		parts[numparts].offset = lastvunit << vshift;
112193db446aSBoris Brezillon 		parts[numparts].size = end - parts[numparts].offset;
112293db446aSBoris Brezillon 		numparts++;
112393db446aSBoris Brezillon 	}
112493db446aSBoris Brezillon 	ret = numparts;
112593db446aSBoris Brezillon  out:
112693db446aSBoris Brezillon 	kfree(buf);
112793db446aSBoris Brezillon 	return ret;
112893db446aSBoris Brezillon }
112993db446aSBoris Brezillon 
nftl_scan_bbt(struct mtd_info * mtd)113093db446aSBoris Brezillon static int __init nftl_scan_bbt(struct mtd_info *mtd)
113193db446aSBoris Brezillon {
113293db446aSBoris Brezillon 	int ret, numparts;
113393db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
113493db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
113593db446aSBoris Brezillon 	struct mtd_partition parts[2];
113693db446aSBoris Brezillon 
113793db446aSBoris Brezillon 	memset((char *)parts, 0, sizeof(parts));
113893db446aSBoris Brezillon 	/* On NFTL, we have to find the media headers before we can read the
113993db446aSBoris Brezillon 	   BBTs, since they're stored in the media header eraseblocks. */
114093db446aSBoris Brezillon 	numparts = nftl_partscan(mtd, parts);
114193db446aSBoris Brezillon 	if (!numparts)
114293db446aSBoris Brezillon 		return -EIO;
114393db446aSBoris Brezillon 	this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
114493db446aSBoris Brezillon 				NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
114593db446aSBoris Brezillon 				NAND_BBT_VERSION;
114693db446aSBoris Brezillon 	this->bbt_td->veroffs = 7;
114793db446aSBoris Brezillon 	this->bbt_td->pages[0] = doc->mh0_page + 1;
114893db446aSBoris Brezillon 	if (doc->mh1_page != -1) {
114993db446aSBoris Brezillon 		this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT |
115093db446aSBoris Brezillon 					NAND_BBT_SAVECONTENT | NAND_BBT_WRITE |
115193db446aSBoris Brezillon 					NAND_BBT_VERSION;
115293db446aSBoris Brezillon 		this->bbt_md->veroffs = 7;
115393db446aSBoris Brezillon 		this->bbt_md->pages[0] = doc->mh1_page + 1;
115493db446aSBoris Brezillon 	} else {
115593db446aSBoris Brezillon 		this->bbt_md = NULL;
115693db446aSBoris Brezillon 	}
115793db446aSBoris Brezillon 
1158e80eba75SBoris Brezillon 	ret = nand_create_bbt(this);
115993db446aSBoris Brezillon 	if (ret)
116093db446aSBoris Brezillon 		return ret;
116193db446aSBoris Brezillon 
116293db446aSBoris Brezillon 	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
116393db446aSBoris Brezillon }
116493db446aSBoris Brezillon 
inftl_scan_bbt(struct mtd_info * mtd)116593db446aSBoris Brezillon static int __init inftl_scan_bbt(struct mtd_info *mtd)
116693db446aSBoris Brezillon {
116793db446aSBoris Brezillon 	int ret, numparts;
116893db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
116993db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
117093db446aSBoris Brezillon 	struct mtd_partition parts[5];
117193db446aSBoris Brezillon 
117232813e28SBoris Brezillon 	if (nanddev_ntargets(&this->base) > doc->chips_per_floor) {
117363fa37f0SShreeya Patel 		pr_err("Multi-floor INFTL devices not yet supported.\n");
117493db446aSBoris Brezillon 		return -EIO;
117593db446aSBoris Brezillon 	}
117693db446aSBoris Brezillon 
117793db446aSBoris Brezillon 	if (DoC_is_MillenniumPlus(doc)) {
117893db446aSBoris Brezillon 		this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE;
117993db446aSBoris Brezillon 		if (inftl_bbt_write)
118093db446aSBoris Brezillon 			this->bbt_td->options |= NAND_BBT_WRITE;
118193db446aSBoris Brezillon 		this->bbt_td->pages[0] = 2;
118293db446aSBoris Brezillon 		this->bbt_md = NULL;
118393db446aSBoris Brezillon 	} else {
118493db446aSBoris Brezillon 		this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
118593db446aSBoris Brezillon 		if (inftl_bbt_write)
118693db446aSBoris Brezillon 			this->bbt_td->options |= NAND_BBT_WRITE;
118793db446aSBoris Brezillon 		this->bbt_td->offs = 8;
118893db446aSBoris Brezillon 		this->bbt_td->len = 8;
118993db446aSBoris Brezillon 		this->bbt_td->veroffs = 7;
119093db446aSBoris Brezillon 		this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
119193db446aSBoris Brezillon 		this->bbt_td->reserved_block_code = 0x01;
119293db446aSBoris Brezillon 		this->bbt_td->pattern = "MSYS_BBT";
119393db446aSBoris Brezillon 
119493db446aSBoris Brezillon 		this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | NAND_BBT_VERSION;
119593db446aSBoris Brezillon 		if (inftl_bbt_write)
119693db446aSBoris Brezillon 			this->bbt_md->options |= NAND_BBT_WRITE;
119793db446aSBoris Brezillon 		this->bbt_md->offs = 8;
119893db446aSBoris Brezillon 		this->bbt_md->len = 8;
119993db446aSBoris Brezillon 		this->bbt_md->veroffs = 7;
120093db446aSBoris Brezillon 		this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS;
120193db446aSBoris Brezillon 		this->bbt_md->reserved_block_code = 0x01;
120293db446aSBoris Brezillon 		this->bbt_md->pattern = "TBB_SYSM";
120393db446aSBoris Brezillon 	}
120493db446aSBoris Brezillon 
1205e80eba75SBoris Brezillon 	ret = nand_create_bbt(this);
120693db446aSBoris Brezillon 	if (ret)
120793db446aSBoris Brezillon 		return ret;
120893db446aSBoris Brezillon 
120993db446aSBoris Brezillon 	memset((char *)parts, 0, sizeof(parts));
121093db446aSBoris Brezillon 	numparts = inftl_partscan(mtd, parts);
121193db446aSBoris Brezillon 	/* At least for now, require the INFTL Media Header.  We could probably
121293db446aSBoris Brezillon 	   do without it for non-INFTL use, since all it gives us is
121393db446aSBoris Brezillon 	   autopartitioning, but I want to give it more thought. */
121493db446aSBoris Brezillon 	if (!numparts)
121593db446aSBoris Brezillon 		return -EIO;
121693db446aSBoris Brezillon 	return mtd_device_register(mtd, parts, no_autopart ? 0 : numparts);
121793db446aSBoris Brezillon }
121893db446aSBoris Brezillon 
doc2000_init(struct mtd_info * mtd)121993db446aSBoris Brezillon static inline int __init doc2000_init(struct mtd_info *mtd)
122093db446aSBoris Brezillon {
122193db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
122293db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
122393db446aSBoris Brezillon 
122493db446aSBoris Brezillon 	doc->late_init = nftl_scan_bbt;
122593db446aSBoris Brezillon 
122693db446aSBoris Brezillon 	doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO;
122793db446aSBoris Brezillon 	doc2000_count_chips(mtd);
122893db446aSBoris Brezillon 	mtd->name = "DiskOnChip 2000 (NFTL Model)";
122993db446aSBoris Brezillon 	return (4 * doc->chips_per_floor);
123093db446aSBoris Brezillon }
123193db446aSBoris Brezillon 
doc2001_init(struct mtd_info * mtd)123293db446aSBoris Brezillon static inline int __init doc2001_init(struct mtd_info *mtd)
123393db446aSBoris Brezillon {
123493db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
123593db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
123693db446aSBoris Brezillon 
123793db446aSBoris Brezillon 	ReadDOC(doc->virtadr, ChipID);
123893db446aSBoris Brezillon 	ReadDOC(doc->virtadr, ChipID);
123993db446aSBoris Brezillon 	ReadDOC(doc->virtadr, ChipID);
124093db446aSBoris Brezillon 	if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) {
124193db446aSBoris Brezillon 		/* It's not a Millennium; it's one of the newer
124293db446aSBoris Brezillon 		   DiskOnChip 2000 units with a similar ASIC.
124393db446aSBoris Brezillon 		   Treat it like a Millennium, except that it
124493db446aSBoris Brezillon 		   can have multiple chips. */
124593db446aSBoris Brezillon 		doc2000_count_chips(mtd);
124693db446aSBoris Brezillon 		mtd->name = "DiskOnChip 2000 (INFTL Model)";
124793db446aSBoris Brezillon 		doc->late_init = inftl_scan_bbt;
124893db446aSBoris Brezillon 		return (4 * doc->chips_per_floor);
124993db446aSBoris Brezillon 	} else {
125093db446aSBoris Brezillon 		/* Bog-standard Millennium */
125193db446aSBoris Brezillon 		doc->chips_per_floor = 1;
125293db446aSBoris Brezillon 		mtd->name = "DiskOnChip Millennium";
125393db446aSBoris Brezillon 		doc->late_init = nftl_scan_bbt;
125493db446aSBoris Brezillon 		return 1;
125593db446aSBoris Brezillon 	}
125693db446aSBoris Brezillon }
125793db446aSBoris Brezillon 
doc2001plus_init(struct mtd_info * mtd)125893db446aSBoris Brezillon static inline int __init doc2001plus_init(struct mtd_info *mtd)
125993db446aSBoris Brezillon {
126093db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
126193db446aSBoris Brezillon 	struct doc_priv *doc = nand_get_controller_data(this);
126293db446aSBoris Brezillon 
126393db446aSBoris Brezillon 	doc->late_init = inftl_scan_bbt;
126493db446aSBoris Brezillon 	this->ecc.hwctl = doc2001plus_enable_hwecc;
126593db446aSBoris Brezillon 
126693db446aSBoris Brezillon 	doc->chips_per_floor = 1;
126793db446aSBoris Brezillon 	mtd->name = "DiskOnChip Millennium Plus";
126893db446aSBoris Brezillon 
126993db446aSBoris Brezillon 	return 1;
127093db446aSBoris Brezillon }
127193db446aSBoris Brezillon 
doc200x_attach_chip(struct nand_chip * chip)12727f4ea034SMiquel Raynal static int doc200x_attach_chip(struct nand_chip *chip)
12737f4ea034SMiquel Raynal {
12747f4ea034SMiquel Raynal 	if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
12757f4ea034SMiquel Raynal 		return 0;
12767f4ea034SMiquel Raynal 
12777f4ea034SMiquel Raynal 	chip->ecc.placement = NAND_ECC_PLACEMENT_INTERLEAVED;
12787f4ea034SMiquel Raynal 	chip->ecc.size = 512;
12797f4ea034SMiquel Raynal 	chip->ecc.bytes = 6;
12807f4ea034SMiquel Raynal 	chip->ecc.strength = 2;
12817f4ea034SMiquel Raynal 	chip->ecc.options = NAND_ECC_GENERIC_ERASED_CHECK;
12827f4ea034SMiquel Raynal 	chip->ecc.hwctl = doc200x_enable_hwecc;
12837f4ea034SMiquel Raynal 	chip->ecc.calculate = doc200x_calculate_ecc;
12847f4ea034SMiquel Raynal 	chip->ecc.correct = doc200x_correct_data;
12857f4ea034SMiquel Raynal 
12867f4ea034SMiquel Raynal 	return 0;
12877f4ea034SMiquel Raynal }
12887f4ea034SMiquel Raynal 
1289f46eb7afSBoris Brezillon static const struct nand_controller_ops doc200x_ops = {
1290f46eb7afSBoris Brezillon 	.exec_op = doc200x_exec_op,
12917f4ea034SMiquel Raynal 	.attach_chip = doc200x_attach_chip,
1292f46eb7afSBoris Brezillon };
1293f46eb7afSBoris Brezillon 
1294f46eb7afSBoris Brezillon static const struct nand_controller_ops doc2001plus_ops = {
1295f46eb7afSBoris Brezillon 	.exec_op = doc2001plus_exec_op,
12967f4ea034SMiquel Raynal 	.attach_chip = doc200x_attach_chip,
1297f46eb7afSBoris Brezillon };
1298f46eb7afSBoris Brezillon 
doc_probe(unsigned long physadr)129993db446aSBoris Brezillon static int __init doc_probe(unsigned long physadr)
130093db446aSBoris Brezillon {
1301964dfce9SThomas Gleixner 	struct nand_chip *nand = NULL;
1302964dfce9SThomas Gleixner 	struct doc_priv *doc = NULL;
130393db446aSBoris Brezillon 	unsigned char ChipID;
130493db446aSBoris Brezillon 	struct mtd_info *mtd;
130593db446aSBoris Brezillon 	void __iomem *virtadr;
130693db446aSBoris Brezillon 	unsigned char save_control;
130793db446aSBoris Brezillon 	unsigned char tmp, tmpb, tmpc;
130893db446aSBoris Brezillon 	int reg, len, numchips;
130993db446aSBoris Brezillon 	int ret = 0;
131093db446aSBoris Brezillon 
131193db446aSBoris Brezillon 	if (!request_mem_region(physadr, DOC_IOREMAP_LEN, "DiskOnChip"))
131293db446aSBoris Brezillon 		return -EBUSY;
131393db446aSBoris Brezillon 	virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
131493db446aSBoris Brezillon 	if (!virtadr) {
131563fa37f0SShreeya Patel 		pr_err("Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n",
131663fa37f0SShreeya Patel 		       DOC_IOREMAP_LEN, physadr);
131793db446aSBoris Brezillon 		ret = -EIO;
131893db446aSBoris Brezillon 		goto error_ioremap;
131993db446aSBoris Brezillon 	}
132093db446aSBoris Brezillon 
132193db446aSBoris Brezillon 	/* It's not possible to cleanly detect the DiskOnChip - the
132293db446aSBoris Brezillon 	 * bootup procedure will put the device into reset mode, and
132393db446aSBoris Brezillon 	 * it's not possible to talk to it without actually writing
132493db446aSBoris Brezillon 	 * to the DOCControl register. So we store the current contents
132593db446aSBoris Brezillon 	 * of the DOCControl register's location, in case we later decide
132693db446aSBoris Brezillon 	 * that it's not a DiskOnChip, and want to put it back how we
132793db446aSBoris Brezillon 	 * found it.
132893db446aSBoris Brezillon 	 */
132993db446aSBoris Brezillon 	save_control = ReadDOC(virtadr, DOCControl);
133093db446aSBoris Brezillon 
133193db446aSBoris Brezillon 	/* Reset the DiskOnChip ASIC */
133293db446aSBoris Brezillon 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
133393db446aSBoris Brezillon 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, virtadr, DOCControl);
133493db446aSBoris Brezillon 
133593db446aSBoris Brezillon 	/* Enable the DiskOnChip ASIC */
133693db446aSBoris Brezillon 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
133793db446aSBoris Brezillon 	WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, virtadr, DOCControl);
133893db446aSBoris Brezillon 
133993db446aSBoris Brezillon 	ChipID = ReadDOC(virtadr, ChipID);
134093db446aSBoris Brezillon 
134193db446aSBoris Brezillon 	switch (ChipID) {
134293db446aSBoris Brezillon 	case DOC_ChipID_Doc2k:
134393db446aSBoris Brezillon 		reg = DoC_2k_ECCStatus;
134493db446aSBoris Brezillon 		break;
134593db446aSBoris Brezillon 	case DOC_ChipID_DocMil:
134693db446aSBoris Brezillon 		reg = DoC_ECCConf;
134793db446aSBoris Brezillon 		break;
134893db446aSBoris Brezillon 	case DOC_ChipID_DocMilPlus16:
134993db446aSBoris Brezillon 	case DOC_ChipID_DocMilPlus32:
135093db446aSBoris Brezillon 	case 0:
135193db446aSBoris Brezillon 		/* Possible Millennium Plus, need to do more checks */
135293db446aSBoris Brezillon 		/* Possibly release from power down mode */
135393db446aSBoris Brezillon 		for (tmp = 0; (tmp < 4); tmp++)
135493db446aSBoris Brezillon 			ReadDOC(virtadr, Mplus_Power);
135593db446aSBoris Brezillon 
135693db446aSBoris Brezillon 		/* Reset the Millennium Plus ASIC */
135793db446aSBoris Brezillon 		tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
135893db446aSBoris Brezillon 		WriteDOC(tmp, virtadr, Mplus_DOCControl);
135993db446aSBoris Brezillon 		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
136093db446aSBoris Brezillon 
13617b4b1994SJia-Ju Bai 		usleep_range(1000, 2000);
136293db446aSBoris Brezillon 		/* Enable the Millennium Plus ASIC */
136393db446aSBoris Brezillon 		tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | DOC_MODE_BDECT;
136493db446aSBoris Brezillon 		WriteDOC(tmp, virtadr, Mplus_DOCControl);
136593db446aSBoris Brezillon 		WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm);
13667b4b1994SJia-Ju Bai 		usleep_range(1000, 2000);
136793db446aSBoris Brezillon 
136893db446aSBoris Brezillon 		ChipID = ReadDOC(virtadr, ChipID);
136993db446aSBoris Brezillon 
137093db446aSBoris Brezillon 		switch (ChipID) {
137193db446aSBoris Brezillon 		case DOC_ChipID_DocMilPlus16:
137293db446aSBoris Brezillon 			reg = DoC_Mplus_Toggle;
137393db446aSBoris Brezillon 			break;
137493db446aSBoris Brezillon 		case DOC_ChipID_DocMilPlus32:
137563fa37f0SShreeya Patel 			pr_err("DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n");
1376025a06c1SMiquel Raynal 			fallthrough;
137793db446aSBoris Brezillon 		default:
137893db446aSBoris Brezillon 			ret = -ENODEV;
137993db446aSBoris Brezillon 			goto notfound;
138093db446aSBoris Brezillon 		}
138193db446aSBoris Brezillon 		break;
138293db446aSBoris Brezillon 
138393db446aSBoris Brezillon 	default:
138493db446aSBoris Brezillon 		ret = -ENODEV;
138593db446aSBoris Brezillon 		goto notfound;
138693db446aSBoris Brezillon 	}
138793db446aSBoris Brezillon 	/* Check the TOGGLE bit in the ECC register */
138893db446aSBoris Brezillon 	tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
138993db446aSBoris Brezillon 	tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
139093db446aSBoris Brezillon 	tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT;
139193db446aSBoris Brezillon 	if ((tmp == tmpb) || (tmp != tmpc)) {
139263fa37f0SShreeya Patel 		pr_warn("Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr);
139393db446aSBoris Brezillon 		ret = -ENODEV;
139493db446aSBoris Brezillon 		goto notfound;
139593db446aSBoris Brezillon 	}
139693db446aSBoris Brezillon 
139793db446aSBoris Brezillon 	for (mtd = doclist; mtd; mtd = doc->nextdoc) {
139893db446aSBoris Brezillon 		unsigned char oldval;
139993db446aSBoris Brezillon 		unsigned char newval;
140093db446aSBoris Brezillon 		nand = mtd_to_nand(mtd);
140193db446aSBoris Brezillon 		doc = nand_get_controller_data(nand);
140293db446aSBoris Brezillon 		/* Use the alias resolution register to determine if this is
140393db446aSBoris Brezillon 		   in fact the same DOC aliased to a new address.  If writes
140493db446aSBoris Brezillon 		   to one chip's alias resolution register change the value on
140593db446aSBoris Brezillon 		   the other chip, they're the same chip. */
140693db446aSBoris Brezillon 		if (ChipID == DOC_ChipID_DocMilPlus16) {
140793db446aSBoris Brezillon 			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
140893db446aSBoris Brezillon 			newval = ReadDOC(virtadr, Mplus_AliasResolution);
140993db446aSBoris Brezillon 		} else {
141093db446aSBoris Brezillon 			oldval = ReadDOC(doc->virtadr, AliasResolution);
141193db446aSBoris Brezillon 			newval = ReadDOC(virtadr, AliasResolution);
141293db446aSBoris Brezillon 		}
141393db446aSBoris Brezillon 		if (oldval != newval)
141493db446aSBoris Brezillon 			continue;
141593db446aSBoris Brezillon 		if (ChipID == DOC_ChipID_DocMilPlus16) {
141693db446aSBoris Brezillon 			WriteDOC(~newval, virtadr, Mplus_AliasResolution);
141793db446aSBoris Brezillon 			oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution);
141893db446aSBoris Brezillon 			WriteDOC(newval, virtadr, Mplus_AliasResolution);	// restore it
141993db446aSBoris Brezillon 		} else {
142093db446aSBoris Brezillon 			WriteDOC(~newval, virtadr, AliasResolution);
142193db446aSBoris Brezillon 			oldval = ReadDOC(doc->virtadr, AliasResolution);
142293db446aSBoris Brezillon 			WriteDOC(newval, virtadr, AliasResolution);	// restore it
142393db446aSBoris Brezillon 		}
142493db446aSBoris Brezillon 		newval = ~newval;
142593db446aSBoris Brezillon 		if (oldval == newval) {
142663fa37f0SShreeya Patel 			pr_debug("Found alias of DOC at 0x%lx to 0x%lx\n",
142763fa37f0SShreeya Patel 				 doc->physadr, physadr);
142893db446aSBoris Brezillon 			goto notfound;
142993db446aSBoris Brezillon 		}
143093db446aSBoris Brezillon 	}
143193db446aSBoris Brezillon 
143263fa37f0SShreeya Patel 	pr_notice("DiskOnChip found at 0x%lx\n", physadr);
143393db446aSBoris Brezillon 
143493db446aSBoris Brezillon 	len = sizeof(struct nand_chip) + sizeof(struct doc_priv) +
143593db446aSBoris Brezillon 	      (2 * sizeof(struct nand_bbt_descr));
143693db446aSBoris Brezillon 	nand = kzalloc(len, GFP_KERNEL);
143793db446aSBoris Brezillon 	if (!nand) {
143893db446aSBoris Brezillon 		ret = -ENOMEM;
143993db446aSBoris Brezillon 		goto fail;
144093db446aSBoris Brezillon 	}
144193db446aSBoris Brezillon 
1442964dfce9SThomas Gleixner 	/*
1443964dfce9SThomas Gleixner 	 * Allocate a RS codec instance
1444964dfce9SThomas Gleixner 	 *
1445964dfce9SThomas Gleixner 	 * Symbolsize is 10 (bits)
1446964dfce9SThomas Gleixner 	 * Primitve polynomial is x^10+x^3+1
1447964dfce9SThomas Gleixner 	 * First consecutive root is 510
1448964dfce9SThomas Gleixner 	 * Primitve element to generate roots = 1
1449964dfce9SThomas Gleixner 	 * Generator polinomial degree = 4
1450964dfce9SThomas Gleixner 	 */
145193db446aSBoris Brezillon 	doc = (struct doc_priv *) (nand + 1);
1452964dfce9SThomas Gleixner 	doc->rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
1453964dfce9SThomas Gleixner 	if (!doc->rs_decoder) {
1454964dfce9SThomas Gleixner 		pr_err("DiskOnChip: Could not create a RS codec\n");
1455964dfce9SThomas Gleixner 		ret = -ENOMEM;
1456964dfce9SThomas Gleixner 		goto fail;
1457964dfce9SThomas Gleixner 	}
1458964dfce9SThomas Gleixner 
1459f37b1d3cSBoris Brezillon 	nand_controller_init(&doc->base);
1460f46eb7afSBoris Brezillon 	if (ChipID == DOC_ChipID_DocMilPlus16)
1461f46eb7afSBoris Brezillon 		doc->base.ops = &doc2001plus_ops;
1462f46eb7afSBoris Brezillon 	else
1463f46eb7afSBoris Brezillon 		doc->base.ops = &doc200x_ops;
1464f46eb7afSBoris Brezillon 
1465964dfce9SThomas Gleixner 	mtd			= nand_to_mtd(nand);
146693db446aSBoris Brezillon 	nand->bbt_td		= (struct nand_bbt_descr *) (doc + 1);
146793db446aSBoris Brezillon 	nand->bbt_md		= nand->bbt_td + 1;
146893db446aSBoris Brezillon 
146993db446aSBoris Brezillon 	mtd->owner		= THIS_MODULE;
147093db446aSBoris Brezillon 	mtd_set_ooblayout(mtd, &doc200x_ooblayout_ops);
147193db446aSBoris Brezillon 
1472f37b1d3cSBoris Brezillon 	nand->controller	= &doc->base;
147393db446aSBoris Brezillon 	nand_set_controller_data(nand, doc);
147493db446aSBoris Brezillon 	nand->bbt_options	= NAND_BBT_USE_FLASH;
147593db446aSBoris Brezillon 	/* Skip the automatic BBT scan so we can run it manually */
1476dace12ccSBoris Brezillon 	nand->options		|= NAND_SKIP_BBTSCAN | NAND_NO_BBM_QUIRK;
147793db446aSBoris Brezillon 
147893db446aSBoris Brezillon 	doc->physadr		= physadr;
147993db446aSBoris Brezillon 	doc->virtadr		= virtadr;
148093db446aSBoris Brezillon 	doc->ChipID		= ChipID;
148193db446aSBoris Brezillon 	doc->curfloor		= -1;
148293db446aSBoris Brezillon 	doc->curchip		= -1;
148393db446aSBoris Brezillon 	doc->mh0_page		= -1;
148493db446aSBoris Brezillon 	doc->mh1_page		= -1;
148593db446aSBoris Brezillon 	doc->nextdoc		= doclist;
148693db446aSBoris Brezillon 
148793db446aSBoris Brezillon 	if (ChipID == DOC_ChipID_Doc2k)
148893db446aSBoris Brezillon 		numchips = doc2000_init(mtd);
148993db446aSBoris Brezillon 	else if (ChipID == DOC_ChipID_DocMilPlus16)
149093db446aSBoris Brezillon 		numchips = doc2001plus_init(mtd);
149193db446aSBoris Brezillon 	else
149293db446aSBoris Brezillon 		numchips = doc2001_init(mtd);
149393db446aSBoris Brezillon 
149400ad378fSBoris Brezillon 	if ((ret = nand_scan(nand, numchips)) || (ret = doc->late_init(mtd))) {
1495c5be12e4SMiquel Raynal 		/* DBB note: i believe nand_cleanup is necessary here, as
149693db446aSBoris Brezillon 		   buffers may have been allocated in nand_base.  Check with
149793db446aSBoris Brezillon 		   Thomas. FIX ME! */
1498c5be12e4SMiquel Raynal 		nand_cleanup(nand);
149993db446aSBoris Brezillon 		goto fail;
150093db446aSBoris Brezillon 	}
150193db446aSBoris Brezillon 
150293db446aSBoris Brezillon 	/* Success! */
150393db446aSBoris Brezillon 	doclist = mtd;
150493db446aSBoris Brezillon 	return 0;
150593db446aSBoris Brezillon 
150693db446aSBoris Brezillon  notfound:
150793db446aSBoris Brezillon 	/* Put back the contents of the DOCControl register, in case it's not
150893db446aSBoris Brezillon 	   actually a DiskOnChip.  */
150993db446aSBoris Brezillon 	WriteDOC(save_control, virtadr, DOCControl);
151093db446aSBoris Brezillon  fail:
1511964dfce9SThomas Gleixner 	if (doc)
1512964dfce9SThomas Gleixner 		free_rs(doc->rs_decoder);
1513964dfce9SThomas Gleixner 	kfree(nand);
151493db446aSBoris Brezillon 	iounmap(virtadr);
151593db446aSBoris Brezillon 
151693db446aSBoris Brezillon error_ioremap:
151793db446aSBoris Brezillon 	release_mem_region(physadr, DOC_IOREMAP_LEN);
151893db446aSBoris Brezillon 
151993db446aSBoris Brezillon 	return ret;
152093db446aSBoris Brezillon }
152193db446aSBoris Brezillon 
release_nanddoc(void)152293db446aSBoris Brezillon static void release_nanddoc(void)
152393db446aSBoris Brezillon {
152493db446aSBoris Brezillon 	struct mtd_info *mtd, *nextmtd;
152593db446aSBoris Brezillon 	struct nand_chip *nand;
152693db446aSBoris Brezillon 	struct doc_priv *doc;
152763a14607SMiquel Raynal 	int ret;
152893db446aSBoris Brezillon 
152993db446aSBoris Brezillon 	for (mtd = doclist; mtd; mtd = nextmtd) {
153093db446aSBoris Brezillon 		nand = mtd_to_nand(mtd);
153193db446aSBoris Brezillon 		doc = nand_get_controller_data(nand);
153293db446aSBoris Brezillon 
153393db446aSBoris Brezillon 		nextmtd = doc->nextdoc;
153463a14607SMiquel Raynal 		ret = mtd_device_unregister(mtd);
153563a14607SMiquel Raynal 		WARN_ON(ret);
153663a14607SMiquel Raynal 		nand_cleanup(nand);
153793db446aSBoris Brezillon 		iounmap(doc->virtadr);
153893db446aSBoris Brezillon 		release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
1539964dfce9SThomas Gleixner 		free_rs(doc->rs_decoder);
154093db446aSBoris Brezillon 		kfree(nand);
154193db446aSBoris Brezillon 	}
154293db446aSBoris Brezillon }
154393db446aSBoris Brezillon 
init_nanddoc(void)154493db446aSBoris Brezillon static int __init init_nanddoc(void)
154593db446aSBoris Brezillon {
154693db446aSBoris Brezillon 	int i, ret = 0;
154793db446aSBoris Brezillon 
154893db446aSBoris Brezillon 	if (doc_config_location) {
154963fa37f0SShreeya Patel 		pr_info("Using configured DiskOnChip probe address 0x%lx\n",
155063fa37f0SShreeya Patel 			doc_config_location);
155193db446aSBoris Brezillon 		ret = doc_probe(doc_config_location);
155293db446aSBoris Brezillon 		if (ret < 0)
1553964dfce9SThomas Gleixner 			return ret;
155493db446aSBoris Brezillon 	} else {
1555db4ecbf8SArnd Bergmann 		for (i = 0; i < ARRAY_SIZE(doc_locations); i++) {
155693db446aSBoris Brezillon 			doc_probe(doc_locations[i]);
155793db446aSBoris Brezillon 		}
155893db446aSBoris Brezillon 	}
155993db446aSBoris Brezillon 	/* No banner message any more. Print a message if no DiskOnChip
156093db446aSBoris Brezillon 	   found, so the user knows we at least tried. */
156193db446aSBoris Brezillon 	if (!doclist) {
156263fa37f0SShreeya Patel 		pr_info("No valid DiskOnChip devices found\n");
156393db446aSBoris Brezillon 		ret = -ENODEV;
156493db446aSBoris Brezillon 	}
156593db446aSBoris Brezillon 	return ret;
156693db446aSBoris Brezillon }
156793db446aSBoris Brezillon 
cleanup_nanddoc(void)156893db446aSBoris Brezillon static void __exit cleanup_nanddoc(void)
156993db446aSBoris Brezillon {
157093db446aSBoris Brezillon 	/* Cleanup the nand/DoC resources */
157193db446aSBoris Brezillon 	release_nanddoc();
157293db446aSBoris Brezillon }
157393db446aSBoris Brezillon 
157493db446aSBoris Brezillon module_init(init_nanddoc);
157593db446aSBoris Brezillon module_exit(cleanup_nanddoc);
157693db446aSBoris Brezillon 
157793db446aSBoris Brezillon MODULE_LICENSE("GPL");
157893db446aSBoris Brezillon MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
157993db446aSBoris Brezillon MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver");
1580