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