xref: /linux/drivers/mtd/nand/raw/mxc_nand.c (revision 95d002e0a34cb0f238abb39987f9980f325d8332)
1c786bbccSFabio Estevam // SPDX-License-Identifier: GPL-2.0+
234f6e157SSascha Hauer /*
334f6e157SSascha Hauer  * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
434f6e157SSascha Hauer  * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
534f6e157SSascha Hauer  */
634f6e157SSascha Hauer 
734f6e157SSascha Hauer #include <linux/delay.h>
834f6e157SSascha Hauer #include <linux/slab.h>
934f6e157SSascha Hauer #include <linux/init.h>
1034f6e157SSascha Hauer #include <linux/module.h>
1134f6e157SSascha Hauer #include <linux/mtd/mtd.h>
12d4092d76SBoris Brezillon #include <linux/mtd/rawnand.h>
1334f6e157SSascha Hauer #include <linux/mtd/partitions.h>
1434f6e157SSascha Hauer #include <linux/interrupt.h>
1534f6e157SSascha Hauer #include <linux/device.h>
1634f6e157SSascha Hauer #include <linux/platform_device.h>
1734f6e157SSascha Hauer #include <linux/clk.h>
1834f6e157SSascha Hauer #include <linux/err.h>
1934f6e157SSascha Hauer #include <linux/io.h>
2063f1474cSSascha Hauer #include <linux/irq.h>
2163f1474cSSascha Hauer #include <linux/completion.h>
22d367e37eSSachin Kamat #include <linux/of.h>
236436356bSUwe Kleine-König #include <linux/of_device.h>
2482906b13SArnd Bergmann #include <linux/platform_data/mtd-mxc_nand.h>
2534f6e157SSascha Hauer 
2634f6e157SSascha Hauer #define DRIVER_NAME "mxc_nand"
2734f6e157SSascha Hauer 
2834f6e157SSascha Hauer /* Addresses for NFC registers */
291bc99180SSascha Hauer #define NFC_V1_V2_BUF_SIZE		(host->regs + 0x00)
301bc99180SSascha Hauer #define NFC_V1_V2_BUF_ADDR		(host->regs + 0x04)
311bc99180SSascha Hauer #define NFC_V1_V2_FLASH_ADDR		(host->regs + 0x06)
321bc99180SSascha Hauer #define NFC_V1_V2_FLASH_CMD		(host->regs + 0x08)
331bc99180SSascha Hauer #define NFC_V1_V2_CONFIG		(host->regs + 0x0a)
341bc99180SSascha Hauer #define NFC_V1_V2_ECC_STATUS_RESULT	(host->regs + 0x0c)
351bc99180SSascha Hauer #define NFC_V1_V2_RSLTMAIN_AREA		(host->regs + 0x0e)
363f77f244SMartin Kaiser #define NFC_V21_RSLTSPARE_AREA		(host->regs + 0x10)
371bc99180SSascha Hauer #define NFC_V1_V2_WRPROT		(host->regs + 0x12)
381bc99180SSascha Hauer #define NFC_V1_UNLOCKSTART_BLKADDR	(host->regs + 0x14)
391bc99180SSascha Hauer #define NFC_V1_UNLOCKEND_BLKADDR	(host->regs + 0x16)
40d178e3e8SBaruch Siach #define NFC_V21_UNLOCKSTART_BLKADDR0	(host->regs + 0x20)
41d178e3e8SBaruch Siach #define NFC_V21_UNLOCKSTART_BLKADDR1	(host->regs + 0x24)
42d178e3e8SBaruch Siach #define NFC_V21_UNLOCKSTART_BLKADDR2	(host->regs + 0x28)
43d178e3e8SBaruch Siach #define NFC_V21_UNLOCKSTART_BLKADDR3	(host->regs + 0x2c)
44d178e3e8SBaruch Siach #define NFC_V21_UNLOCKEND_BLKADDR0	(host->regs + 0x22)
45d178e3e8SBaruch Siach #define NFC_V21_UNLOCKEND_BLKADDR1	(host->regs + 0x26)
46d178e3e8SBaruch Siach #define NFC_V21_UNLOCKEND_BLKADDR2	(host->regs + 0x2a)
47d178e3e8SBaruch Siach #define NFC_V21_UNLOCKEND_BLKADDR3	(host->regs + 0x2e)
481bc99180SSascha Hauer #define NFC_V1_V2_NF_WRPRST		(host->regs + 0x18)
491bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1		(host->regs + 0x1a)
501bc99180SSascha Hauer #define NFC_V1_V2_CONFIG2		(host->regs + 0x1c)
5134f6e157SSascha Hauer 
526e85dfdcSSascha Hauer #define NFC_V2_CONFIG1_ECC_MODE_4	(1 << 0)
531bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_SP_EN		(1 << 2)
541bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_ECC_EN	(1 << 3)
551bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_INT_MSK	(1 << 4)
561bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_BIG		(1 << 5)
571bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_RST		(1 << 6)
581bc99180SSascha Hauer #define NFC_V1_V2_CONFIG1_CE		(1 << 7)
59b8db2f51SSascha Hauer #define NFC_V2_CONFIG1_ONE_CYCLE	(1 << 8)
60b8db2f51SSascha Hauer #define NFC_V2_CONFIG1_PPB(x)		(((x) & 0x3) << 9)
61b8db2f51SSascha Hauer #define NFC_V2_CONFIG1_FP_INT		(1 << 11)
6234f6e157SSascha Hauer 
631bc99180SSascha Hauer #define NFC_V1_V2_CONFIG2_INT		(1 << 15)
6434f6e157SSascha Hauer 
651bc99180SSascha Hauer /*
661bc99180SSascha Hauer  * Operation modes for the NFC. Valid for v1, v2 and v3
671bc99180SSascha Hauer  * type controllers.
681bc99180SSascha Hauer  */
691bc99180SSascha Hauer #define NFC_CMD				(1 << 0)
701bc99180SSascha Hauer #define NFC_ADDR			(1 << 1)
711bc99180SSascha Hauer #define NFC_INPUT			(1 << 2)
721bc99180SSascha Hauer #define NFC_OUTPUT			(1 << 3)
731bc99180SSascha Hauer #define NFC_ID				(1 << 4)
741bc99180SSascha Hauer #define NFC_STATUS			(1 << 5)
7534f6e157SSascha Hauer 
7671ec5155SSascha Hauer #define NFC_V3_FLASH_CMD		(host->regs_axi + 0x00)
7771ec5155SSascha Hauer #define NFC_V3_FLASH_ADDR0		(host->regs_axi + 0x04)
7834f6e157SSascha Hauer 
7971ec5155SSascha Hauer #define NFC_V3_CONFIG1			(host->regs_axi + 0x34)
8071ec5155SSascha Hauer #define NFC_V3_CONFIG1_SP_EN		(1 << 0)
8171ec5155SSascha Hauer #define NFC_V3_CONFIG1_RBA(x)		(((x) & 0x7 ) << 4)
8234f6e157SSascha Hauer 
8371ec5155SSascha Hauer #define NFC_V3_ECC_STATUS_RESULT	(host->regs_axi + 0x38)
8434f6e157SSascha Hauer 
8571ec5155SSascha Hauer #define NFC_V3_LAUNCH			(host->regs_axi + 0x40)
8634f6e157SSascha Hauer 
8771ec5155SSascha Hauer #define NFC_V3_WRPROT			(host->regs_ip + 0x0)
8871ec5155SSascha Hauer #define NFC_V3_WRPROT_LOCK_TIGHT	(1 << 0)
8971ec5155SSascha Hauer #define NFC_V3_WRPROT_LOCK		(1 << 1)
9071ec5155SSascha Hauer #define NFC_V3_WRPROT_UNLOCK		(1 << 2)
9171ec5155SSascha Hauer #define NFC_V3_WRPROT_BLS_UNLOCK	(2 << 6)
9271ec5155SSascha Hauer 
9371ec5155SSascha Hauer #define NFC_V3_WRPROT_UNLOCK_BLK_ADD0   (host->regs_ip + 0x04)
9471ec5155SSascha Hauer 
9571ec5155SSascha Hauer #define NFC_V3_CONFIG2			(host->regs_ip + 0x24)
9671ec5155SSascha Hauer #define NFC_V3_CONFIG2_PS_512			(0 << 0)
9771ec5155SSascha Hauer #define NFC_V3_CONFIG2_PS_2048			(1 << 0)
9871ec5155SSascha Hauer #define NFC_V3_CONFIG2_PS_4096			(2 << 0)
9971ec5155SSascha Hauer #define NFC_V3_CONFIG2_ONE_CYCLE		(1 << 2)
10071ec5155SSascha Hauer #define NFC_V3_CONFIG2_ECC_EN			(1 << 3)
10171ec5155SSascha Hauer #define NFC_V3_CONFIG2_2CMD_PHASES		(1 << 4)
10271ec5155SSascha Hauer #define NFC_V3_CONFIG2_NUM_ADDR_PHASE0		(1 << 5)
10371ec5155SSascha Hauer #define NFC_V3_CONFIG2_ECC_MODE_8		(1 << 6)
10471718a8eSSascha Hauer #define NFC_V3_CONFIG2_PPB(x, shift)		(((x) & 0x3) << shift)
10571ec5155SSascha Hauer #define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x)	(((x) & 0x3) << 12)
10671ec5155SSascha Hauer #define NFC_V3_CONFIG2_INT_MSK			(1 << 15)
10771ec5155SSascha Hauer #define NFC_V3_CONFIG2_ST_CMD(x)		(((x) & 0xff) << 24)
10871ec5155SSascha Hauer #define NFC_V3_CONFIG2_SPAS(x)			(((x) & 0xff) << 16)
10971ec5155SSascha Hauer 
11071ec5155SSascha Hauer #define NFC_V3_CONFIG3				(host->regs_ip + 0x28)
11171ec5155SSascha Hauer #define NFC_V3_CONFIG3_ADD_OP(x)		(((x) & 0x3) << 0)
11271ec5155SSascha Hauer #define NFC_V3_CONFIG3_FW8			(1 << 3)
11371ec5155SSascha Hauer #define NFC_V3_CONFIG3_SBB(x)			(((x) & 0x7) << 8)
11471ec5155SSascha Hauer #define NFC_V3_CONFIG3_NUM_OF_DEVICES(x)	(((x) & 0x7) << 12)
11571ec5155SSascha Hauer #define NFC_V3_CONFIG3_RBB_MODE			(1 << 15)
11671ec5155SSascha Hauer #define NFC_V3_CONFIG3_NO_SDMA			(1 << 20)
11771ec5155SSascha Hauer 
11871ec5155SSascha Hauer #define NFC_V3_IPC			(host->regs_ip + 0x2C)
11971ec5155SSascha Hauer #define NFC_V3_IPC_CREQ			(1 << 0)
12071ec5155SSascha Hauer #define NFC_V3_IPC_INT			(1 << 31)
12171ec5155SSascha Hauer 
12271ec5155SSascha Hauer #define NFC_V3_DELAY_LINE		(host->regs_ip + 0x34)
12334f6e157SSascha Hauer 
124e4303b25SUwe Kleine-König struct mxc_nand_host;
125e4303b25SUwe Kleine-König 
126e4303b25SUwe Kleine-König struct mxc_nand_devtype_data {
127e4303b25SUwe Kleine-König 	void (*preset)(struct mtd_info *);
12867b87f66SSascha Hauer 	int (*read_page)(struct nand_chip *chip, void *buf, void *oob, bool ecc,
12967b87f66SSascha Hauer 			 int page);
130e4303b25SUwe Kleine-König 	void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
131e4303b25SUwe Kleine-König 	void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
132e4303b25SUwe Kleine-König 	void (*send_page)(struct mtd_info *, unsigned int);
133e4303b25SUwe Kleine-König 	void (*send_read_id)(struct mxc_nand_host *);
134e4303b25SUwe Kleine-König 	uint16_t (*get_dev_status)(struct mxc_nand_host *);
135e4303b25SUwe Kleine-König 	int (*check_int)(struct mxc_nand_host *);
136e4303b25SUwe Kleine-König 	void (*irq_control)(struct mxc_nand_host *, int);
1376d38af25SUwe Kleine-König 	u32 (*get_ecc_status)(struct mxc_nand_host *);
138a894cf6cSBoris Brezillon 	const struct mtd_ooblayout_ops *ooblayout;
139758b56f5SBoris Brezillon 	void (*select_chip)(struct nand_chip *chip, int cs);
140858838b8SBoris Brezillon 	int (*setup_data_interface)(struct nand_chip *chip, int csline,
141104e442aSBoris Brezillon 				    const struct nand_data_interface *conf);
142040bd3f6SSascha Hauer 	void (*enable_hwecc)(struct nand_chip *chip, bool enable);
143f48d0f9aSUwe Kleine-König 
144f48d0f9aSUwe Kleine-König 	/*
145f48d0f9aSUwe Kleine-König 	 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
146f48d0f9aSUwe Kleine-König 	 * (CONFIG1:INT_MSK is set). To handle this the driver uses
147f48d0f9aSUwe Kleine-König 	 * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
148f48d0f9aSUwe Kleine-König 	 */
149f48d0f9aSUwe Kleine-König 	int irqpending_quirk;
150f48d0f9aSUwe Kleine-König 	int needs_ip;
151f48d0f9aSUwe Kleine-König 
152f48d0f9aSUwe Kleine-König 	size_t regs_offset;
153f48d0f9aSUwe Kleine-König 	size_t spare0_offset;
154f48d0f9aSUwe Kleine-König 	size_t axi_offset;
155f48d0f9aSUwe Kleine-König 
156f48d0f9aSUwe Kleine-König 	int spare_len;
157f48d0f9aSUwe Kleine-König 	int eccbytes;
158f48d0f9aSUwe Kleine-König 	int eccsize;
15971718a8eSSascha Hauer 	int ppb_shift;
160e4303b25SUwe Kleine-König };
161e4303b25SUwe Kleine-König 
16234f6e157SSascha Hauer struct mxc_nand_host {
16334f6e157SSascha Hauer 	struct nand_chip	nand;
16434f6e157SSascha Hauer 	struct device		*dev;
16534f6e157SSascha Hauer 
1664b6f05e1SUwe Kleine-König 	void __iomem		*spare0;
1674b6f05e1SUwe Kleine-König 	void __iomem		*main_area0;
168c6de7e1bSSascha Hauer 
169c6de7e1bSSascha Hauer 	void __iomem		*base;
17034f6e157SSascha Hauer 	void __iomem		*regs;
17171ec5155SSascha Hauer 	void __iomem		*regs_axi;
17271ec5155SSascha Hauer 	void __iomem		*regs_ip;
17334f6e157SSascha Hauer 	int			status_request;
17434f6e157SSascha Hauer 	struct clk		*clk;
17534f6e157SSascha Hauer 	int			clk_act;
17634f6e157SSascha Hauer 	int			irq;
17794f77e50SSascha Hauer 	int			eccsize;
1787e7e4730SBaruch Siach 	int			used_oobsize;
179d178e3e8SBaruch Siach 	int			active_cs;
18034f6e157SSascha Hauer 
18163f1474cSSascha Hauer 	struct completion	op_completion;
182f8f9608dSSascha Hauer 
183f8f9608dSSascha Hauer 	uint8_t			*data_buf;
184f8f9608dSSascha Hauer 	unsigned int		buf_start;
1855f97304eSSascha Hauer 
186e4303b25SUwe Kleine-König 	const struct mxc_nand_devtype_data *devtype_data;
1876436356bSUwe Kleine-König 	struct mxc_nand_platform_data pdata;
18834f6e157SSascha Hauer };
18934f6e157SSascha Hauer 
190b2ac0376SJingoo Han static const char * const part_probes[] = {
191740bb0c4SLothar Waßmann 	"cmdlinepart", "RedBoot", "ofpart", NULL };
19234f6e157SSascha Hauer 
193096bcc23SSascha Hauer static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
194096bcc23SSascha Hauer {
195096bcc23SSascha Hauer 	int i;
196096bcc23SSascha Hauer 	u32 *t = trg;
197096bcc23SSascha Hauer 	const __iomem u32 *s = src;
198096bcc23SSascha Hauer 
199096bcc23SSascha Hauer 	for (i = 0; i < (size >> 2); i++)
200096bcc23SSascha Hauer 		*t++ = __raw_readl(s++);
201096bcc23SSascha Hauer }
202096bcc23SSascha Hauer 
2030d17fc3eSBaruch Siach static void memcpy16_fromio(void *trg, const void __iomem  *src, size_t size)
2040d17fc3eSBaruch Siach {
2050d17fc3eSBaruch Siach 	int i;
2060d17fc3eSBaruch Siach 	u16 *t = trg;
2070d17fc3eSBaruch Siach 	const __iomem u16 *s = src;
2080d17fc3eSBaruch Siach 
2090d17fc3eSBaruch Siach 	/* We assume that src (IO) is always 32bit aligned */
2100d17fc3eSBaruch Siach 	if (PTR_ALIGN(trg, 4) == trg && IS_ALIGNED(size, 4)) {
2110d17fc3eSBaruch Siach 		memcpy32_fromio(trg, src, size);
2120d17fc3eSBaruch Siach 		return;
2130d17fc3eSBaruch Siach 	}
2140d17fc3eSBaruch Siach 
2150d17fc3eSBaruch Siach 	for (i = 0; i < (size >> 1); i++)
2160d17fc3eSBaruch Siach 		*t++ = __raw_readw(s++);
2170d17fc3eSBaruch Siach }
2180d17fc3eSBaruch Siach 
21933a87a15SKoul, Vinod static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
220096bcc23SSascha Hauer {
22133a87a15SKoul, Vinod 	/* __iowrite32_copy use 32bit size values so divide by 4 */
22233a87a15SKoul, Vinod 	__iowrite32_copy(trg, src, size / 4);
223096bcc23SSascha Hauer }
224096bcc23SSascha Hauer 
2250d17fc3eSBaruch Siach static void memcpy16_toio(void __iomem *trg, const void *src, int size)
2260d17fc3eSBaruch Siach {
2270d17fc3eSBaruch Siach 	int i;
2280d17fc3eSBaruch Siach 	__iomem u16 *t = trg;
2290d17fc3eSBaruch Siach 	const u16 *s = src;
2300d17fc3eSBaruch Siach 
2310d17fc3eSBaruch Siach 	/* We assume that trg (IO) is always 32bit aligned */
2320d17fc3eSBaruch Siach 	if (PTR_ALIGN(src, 4) == src && IS_ALIGNED(size, 4)) {
2330d17fc3eSBaruch Siach 		memcpy32_toio(trg, src, size);
2340d17fc3eSBaruch Siach 		return;
2350d17fc3eSBaruch Siach 	}
2360d17fc3eSBaruch Siach 
2370d17fc3eSBaruch Siach 	for (i = 0; i < (size >> 1); i++)
2380d17fc3eSBaruch Siach 		__raw_writew(*s++, t++);
2390d17fc3eSBaruch Siach }
2400d17fc3eSBaruch Siach 
24115493331SSascha Hauer /*
24215493331SSascha Hauer  * The controller splits a page into data chunks of 512 bytes + partial oob.
24315493331SSascha Hauer  * There are writesize / 512 such chunks, the size of the partial oob parts is
24415493331SSascha Hauer  * oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then
24515493331SSascha Hauer  * contains additionally the byte lost by rounding (if any).
24615493331SSascha Hauer  * This function handles the needed shuffling between host->data_buf (which
24715493331SSascha Hauer  * holds a page in natural order, i.e. writesize bytes data + oobsize bytes
24815493331SSascha Hauer  * spare) and the NFC buffer.
24915493331SSascha Hauer  */
2501af0b314SSascha Hauer static void copy_spare(struct mtd_info *mtd, bool bfrom, void *buf)
25115493331SSascha Hauer {
25215493331SSascha Hauer 	struct nand_chip *this = mtd_to_nand(mtd);
25315493331SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(this);
25415493331SSascha Hauer 	u16 i, oob_chunk_size;
25515493331SSascha Hauer 	u16 num_chunks = mtd->writesize / 512;
25615493331SSascha Hauer 
2571af0b314SSascha Hauer 	u8 *d = buf;
25815493331SSascha Hauer 	u8 __iomem *s = host->spare0;
25915493331SSascha Hauer 	u16 sparebuf_size = host->devtype_data->spare_len;
26015493331SSascha Hauer 
26115493331SSascha Hauer 	/* size of oob chunk for all but possibly the last one */
26215493331SSascha Hauer 	oob_chunk_size = (host->used_oobsize / num_chunks) & ~1;
26315493331SSascha Hauer 
26415493331SSascha Hauer 	if (bfrom) {
26515493331SSascha Hauer 		for (i = 0; i < num_chunks - 1; i++)
26615493331SSascha Hauer 			memcpy16_fromio(d + i * oob_chunk_size,
26715493331SSascha Hauer 					s + i * sparebuf_size,
26815493331SSascha Hauer 					oob_chunk_size);
26915493331SSascha Hauer 
27015493331SSascha Hauer 		/* the last chunk */
27115493331SSascha Hauer 		memcpy16_fromio(d + i * oob_chunk_size,
27215493331SSascha Hauer 				s + i * sparebuf_size,
27315493331SSascha Hauer 				host->used_oobsize - i * oob_chunk_size);
27415493331SSascha Hauer 	} else {
27515493331SSascha Hauer 		for (i = 0; i < num_chunks - 1; i++)
27615493331SSascha Hauer 			memcpy16_toio(&s[i * sparebuf_size],
27715493331SSascha Hauer 				      &d[i * oob_chunk_size],
27815493331SSascha Hauer 				      oob_chunk_size);
27915493331SSascha Hauer 
28015493331SSascha Hauer 		/* the last chunk */
28115493331SSascha Hauer 		memcpy16_toio(&s[i * sparebuf_size],
28215493331SSascha Hauer 			      &d[i * oob_chunk_size],
28315493331SSascha Hauer 			      host->used_oobsize - i * oob_chunk_size);
28415493331SSascha Hauer 	}
28515493331SSascha Hauer }
28615493331SSascha Hauer 
28715493331SSascha Hauer /*
28815493331SSascha Hauer  * MXC NANDFC can only perform full page+spare or spare-only read/write.  When
28915493331SSascha Hauer  * the upper layers perform a read/write buf operation, the saved column address
29015493331SSascha Hauer  * is used to index into the full page. So usually this function is called with
29115493331SSascha Hauer  * column == 0 (unless no column cycle is needed indicated by column == -1)
29215493331SSascha Hauer  */
29315493331SSascha Hauer static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
29415493331SSascha Hauer {
29515493331SSascha Hauer 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
29615493331SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
29715493331SSascha Hauer 
29815493331SSascha Hauer 	/* Write out column address, if necessary */
29915493331SSascha Hauer 	if (column != -1) {
30015493331SSascha Hauer 		host->devtype_data->send_addr(host, column & 0xff,
30115493331SSascha Hauer 					      page_addr == -1);
30215493331SSascha Hauer 		if (mtd->writesize > 512)
30315493331SSascha Hauer 			/* another col addr cycle for 2k page */
30415493331SSascha Hauer 			host->devtype_data->send_addr(host,
30515493331SSascha Hauer 						      (column >> 8) & 0xff,
30615493331SSascha Hauer 						      false);
30715493331SSascha Hauer 	}
30815493331SSascha Hauer 
30915493331SSascha Hauer 	/* Write out page address, if necessary */
31015493331SSascha Hauer 	if (page_addr != -1) {
31115493331SSascha Hauer 		/* paddr_0 - p_addr_7 */
31215493331SSascha Hauer 		host->devtype_data->send_addr(host, (page_addr & 0xff), false);
31315493331SSascha Hauer 
31415493331SSascha Hauer 		if (mtd->writesize > 512) {
31515493331SSascha Hauer 			if (mtd->size >= 0x10000000) {
31615493331SSascha Hauer 				/* paddr_8 - paddr_15 */
31715493331SSascha Hauer 				host->devtype_data->send_addr(host,
31815493331SSascha Hauer 						(page_addr >> 8) & 0xff,
31915493331SSascha Hauer 						false);
32015493331SSascha Hauer 				host->devtype_data->send_addr(host,
32115493331SSascha Hauer 						(page_addr >> 16) & 0xff,
32215493331SSascha Hauer 						true);
32315493331SSascha Hauer 			} else
32415493331SSascha Hauer 				/* paddr_8 - paddr_15 */
32515493331SSascha Hauer 				host->devtype_data->send_addr(host,
32615493331SSascha Hauer 						(page_addr >> 8) & 0xff, true);
32715493331SSascha Hauer 		} else {
32815493331SSascha Hauer 			if (nand_chip->options & NAND_ROW_ADDR_3) {
32915493331SSascha Hauer 				/* paddr_8 - paddr_15 */
33015493331SSascha Hauer 				host->devtype_data->send_addr(host,
33115493331SSascha Hauer 						(page_addr >> 8) & 0xff,
33215493331SSascha Hauer 						false);
33315493331SSascha Hauer 				host->devtype_data->send_addr(host,
33415493331SSascha Hauer 						(page_addr >> 16) & 0xff,
33515493331SSascha Hauer 						true);
33615493331SSascha Hauer 			} else
33715493331SSascha Hauer 				/* paddr_8 - paddr_15 */
33815493331SSascha Hauer 				host->devtype_data->send_addr(host,
33915493331SSascha Hauer 						(page_addr >> 8) & 0xff, true);
34015493331SSascha Hauer 		}
34115493331SSascha Hauer 	}
34215493331SSascha Hauer }
34315493331SSascha Hauer 
34471ec5155SSascha Hauer static int check_int_v3(struct mxc_nand_host *host)
34571ec5155SSascha Hauer {
34671ec5155SSascha Hauer 	uint32_t tmp;
34771ec5155SSascha Hauer 
34871ec5155SSascha Hauer 	tmp = readl(NFC_V3_IPC);
34971ec5155SSascha Hauer 	if (!(tmp & NFC_V3_IPC_INT))
35071ec5155SSascha Hauer 		return 0;
35171ec5155SSascha Hauer 
35271ec5155SSascha Hauer 	tmp &= ~NFC_V3_IPC_INT;
35371ec5155SSascha Hauer 	writel(tmp, NFC_V3_IPC);
35471ec5155SSascha Hauer 
35571ec5155SSascha Hauer 	return 1;
35671ec5155SSascha Hauer }
35771ec5155SSascha Hauer 
3587aaf28acSSascha Hauer static int check_int_v1_v2(struct mxc_nand_host *host)
3597aaf28acSSascha Hauer {
3607aaf28acSSascha Hauer 	uint32_t tmp;
3617aaf28acSSascha Hauer 
3621bc99180SSascha Hauer 	tmp = readw(NFC_V1_V2_CONFIG2);
3631bc99180SSascha Hauer 	if (!(tmp & NFC_V1_V2_CONFIG2_INT))
3647aaf28acSSascha Hauer 		return 0;
3657aaf28acSSascha Hauer 
366f48d0f9aSUwe Kleine-König 	if (!host->devtype_data->irqpending_quirk)
3671bc99180SSascha Hauer 		writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
3687aaf28acSSascha Hauer 
3697aaf28acSSascha Hauer 	return 1;
3707aaf28acSSascha Hauer }
3717aaf28acSSascha Hauer 
37263f1474cSSascha Hauer static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
37363f1474cSSascha Hauer {
37463f1474cSSascha Hauer 	uint16_t tmp;
37563f1474cSSascha Hauer 
37663f1474cSSascha Hauer 	tmp = readw(NFC_V1_V2_CONFIG1);
37763f1474cSSascha Hauer 
37863f1474cSSascha Hauer 	if (activate)
37963f1474cSSascha Hauer 		tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
38063f1474cSSascha Hauer 	else
38163f1474cSSascha Hauer 		tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
38263f1474cSSascha Hauer 
38363f1474cSSascha Hauer 	writew(tmp, NFC_V1_V2_CONFIG1);
38463f1474cSSascha Hauer }
38563f1474cSSascha Hauer 
38663f1474cSSascha Hauer static void irq_control_v3(struct mxc_nand_host *host, int activate)
38763f1474cSSascha Hauer {
38863f1474cSSascha Hauer 	uint32_t tmp;
38963f1474cSSascha Hauer 
39063f1474cSSascha Hauer 	tmp = readl(NFC_V3_CONFIG2);
39163f1474cSSascha Hauer 
39263f1474cSSascha Hauer 	if (activate)
39363f1474cSSascha Hauer 		tmp &= ~NFC_V3_CONFIG2_INT_MSK;
39463f1474cSSascha Hauer 	else
39563f1474cSSascha Hauer 		tmp |= NFC_V3_CONFIG2_INT_MSK;
39663f1474cSSascha Hauer 
39763f1474cSSascha Hauer 	writel(tmp, NFC_V3_CONFIG2);
39863f1474cSSascha Hauer }
39963f1474cSSascha Hauer 
4008556958aSUwe Kleine-König static void irq_control(struct mxc_nand_host *host, int activate)
4018556958aSUwe Kleine-König {
402f48d0f9aSUwe Kleine-König 	if (host->devtype_data->irqpending_quirk) {
4038556958aSUwe Kleine-König 		if (activate)
4048556958aSUwe Kleine-König 			enable_irq(host->irq);
4058556958aSUwe Kleine-König 		else
4068556958aSUwe Kleine-König 			disable_irq_nosync(host->irq);
4078556958aSUwe Kleine-König 	} else {
408e4303b25SUwe Kleine-König 		host->devtype_data->irq_control(host, activate);
4098556958aSUwe Kleine-König 	}
4108556958aSUwe Kleine-König }
4118556958aSUwe Kleine-König 
4126d38af25SUwe Kleine-König static u32 get_ecc_status_v1(struct mxc_nand_host *host)
4136d38af25SUwe Kleine-König {
4146d38af25SUwe Kleine-König 	return readw(NFC_V1_V2_ECC_STATUS_RESULT);
4156d38af25SUwe Kleine-König }
4166d38af25SUwe Kleine-König 
4176d38af25SUwe Kleine-König static u32 get_ecc_status_v2(struct mxc_nand_host *host)
4186d38af25SUwe Kleine-König {
4196d38af25SUwe Kleine-König 	return readl(NFC_V1_V2_ECC_STATUS_RESULT);
4206d38af25SUwe Kleine-König }
4216d38af25SUwe Kleine-König 
4226d38af25SUwe Kleine-König static u32 get_ecc_status_v3(struct mxc_nand_host *host)
4236d38af25SUwe Kleine-König {
4246d38af25SUwe Kleine-König 	return readl(NFC_V3_ECC_STATUS_RESULT);
4256d38af25SUwe Kleine-König }
4266d38af25SUwe Kleine-König 
4278556958aSUwe Kleine-König static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
4288556958aSUwe Kleine-König {
4298556958aSUwe Kleine-König 	struct mxc_nand_host *host = dev_id;
4308556958aSUwe Kleine-König 
431e4303b25SUwe Kleine-König 	if (!host->devtype_data->check_int(host))
4328556958aSUwe Kleine-König 		return IRQ_NONE;
4338556958aSUwe Kleine-König 
4348556958aSUwe Kleine-König 	irq_control(host, 0);
4358556958aSUwe Kleine-König 
4368556958aSUwe Kleine-König 	complete(&host->op_completion);
4378556958aSUwe Kleine-König 
4388556958aSUwe Kleine-König 	return IRQ_HANDLED;
4398556958aSUwe Kleine-König }
4408556958aSUwe Kleine-König 
44134f6e157SSascha Hauer /* This function polls the NANDFC to wait for the basic operation to
44234f6e157SSascha Hauer  * complete by checking the INT bit of config2 register.
44334f6e157SSascha Hauer  */
444e35d1d8aSUwe Kleine-König static int wait_op_done(struct mxc_nand_host *host, int useirq)
44534f6e157SSascha Hauer {
446e35d1d8aSUwe Kleine-König 	int ret = 0;
447e35d1d8aSUwe Kleine-König 
448e35d1d8aSUwe Kleine-König 	/*
449e35d1d8aSUwe Kleine-König 	 * If operation is already complete, don't bother to setup an irq or a
450e35d1d8aSUwe Kleine-König 	 * loop.
451e35d1d8aSUwe Kleine-König 	 */
452e35d1d8aSUwe Kleine-König 	if (host->devtype_data->check_int(host))
453e35d1d8aSUwe Kleine-König 		return 0;
45434f6e157SSascha Hauer 
45534f6e157SSascha Hauer 	if (useirq) {
456e35d1d8aSUwe Kleine-König 		unsigned long timeout;
457e35d1d8aSUwe Kleine-König 
45816735d02SWolfram Sang 		reinit_completion(&host->op_completion);
459e35d1d8aSUwe Kleine-König 
4608556958aSUwe Kleine-König 		irq_control(host, 1);
461e35d1d8aSUwe Kleine-König 
462e35d1d8aSUwe Kleine-König 		timeout = wait_for_completion_timeout(&host->op_completion, HZ);
463e35d1d8aSUwe Kleine-König 		if (!timeout && !host->devtype_data->check_int(host)) {
464e35d1d8aSUwe Kleine-König 			dev_dbg(host->dev, "timeout waiting for irq\n");
465e35d1d8aSUwe Kleine-König 			ret = -ETIMEDOUT;
46634f6e157SSascha Hauer 		}
46734f6e157SSascha Hauer 	} else {
468e35d1d8aSUwe Kleine-König 		int max_retries = 8000;
469e35d1d8aSUwe Kleine-König 		int done;
470e35d1d8aSUwe Kleine-König 
471e35d1d8aSUwe Kleine-König 		do {
472e35d1d8aSUwe Kleine-König 			udelay(1);
473e35d1d8aSUwe Kleine-König 
474e35d1d8aSUwe Kleine-König 			done = host->devtype_data->check_int(host);
475e35d1d8aSUwe Kleine-König 			if (done)
47634f6e157SSascha Hauer 				break;
4777aaf28acSSascha Hauer 
478e35d1d8aSUwe Kleine-König 		} while (--max_retries);
479e35d1d8aSUwe Kleine-König 
480e35d1d8aSUwe Kleine-König 		if (!done) {
481e35d1d8aSUwe Kleine-König 			dev_dbg(host->dev, "timeout polling for completion\n");
482e35d1d8aSUwe Kleine-König 			ret = -ETIMEDOUT;
48334f6e157SSascha Hauer 		}
48434f6e157SSascha Hauer 	}
485e35d1d8aSUwe Kleine-König 
486e35d1d8aSUwe Kleine-König 	WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq);
487e35d1d8aSUwe Kleine-König 
488e35d1d8aSUwe Kleine-König 	return ret;
48934f6e157SSascha Hauer }
49034f6e157SSascha Hauer 
49171ec5155SSascha Hauer static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
49271ec5155SSascha Hauer {
49371ec5155SSascha Hauer 	/* fill command */
49471ec5155SSascha Hauer 	writel(cmd, NFC_V3_FLASH_CMD);
49571ec5155SSascha Hauer 
49671ec5155SSascha Hauer 	/* send out command */
49771ec5155SSascha Hauer 	writel(NFC_CMD, NFC_V3_LAUNCH);
49871ec5155SSascha Hauer 
49971ec5155SSascha Hauer 	/* Wait for operation to complete */
50071ec5155SSascha Hauer 	wait_op_done(host, useirq);
50171ec5155SSascha Hauer }
50271ec5155SSascha Hauer 
50334f6e157SSascha Hauer /* This function issues the specified command to the NAND device and
50434f6e157SSascha Hauer  * waits for completion. */
5055f97304eSSascha Hauer static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
50634f6e157SSascha Hauer {
5071f3df4dcSSascha Hauer 	dev_dbg(host->dev, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
50834f6e157SSascha Hauer 
5091bc99180SSascha Hauer 	writew(cmd, NFC_V1_V2_FLASH_CMD);
5101bc99180SSascha Hauer 	writew(NFC_CMD, NFC_V1_V2_CONFIG2);
51134f6e157SSascha Hauer 
512f48d0f9aSUwe Kleine-König 	if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
513a47bfd2eSIvo Clarysse 		int max_retries = 100;
514a47bfd2eSIvo Clarysse 		/* Reset completion is indicated by NFC_CONFIG2 */
515a47bfd2eSIvo Clarysse 		/* being set to 0 */
516a47bfd2eSIvo Clarysse 		while (max_retries-- > 0) {
5171bc99180SSascha Hauer 			if (readw(NFC_V1_V2_CONFIG2) == 0) {
518a47bfd2eSIvo Clarysse 				break;
519a47bfd2eSIvo Clarysse 			}
520a47bfd2eSIvo Clarysse 			udelay(1);
521a47bfd2eSIvo Clarysse 		}
522a47bfd2eSIvo Clarysse 		if (max_retries < 0)
5231f3df4dcSSascha Hauer 			dev_dbg(host->dev, "%s: RESET failed\n", __func__);
524a47bfd2eSIvo Clarysse 	} else {
52534f6e157SSascha Hauer 		/* Wait for operation to complete */
526c110eaf4SSascha Hauer 		wait_op_done(host, useirq);
52734f6e157SSascha Hauer 	}
528a47bfd2eSIvo Clarysse }
52934f6e157SSascha Hauer 
53071ec5155SSascha Hauer static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
53171ec5155SSascha Hauer {
53271ec5155SSascha Hauer 	/* fill address */
53371ec5155SSascha Hauer 	writel(addr, NFC_V3_FLASH_ADDR0);
53471ec5155SSascha Hauer 
53571ec5155SSascha Hauer 	/* send out address */
53671ec5155SSascha Hauer 	writel(NFC_ADDR, NFC_V3_LAUNCH);
53771ec5155SSascha Hauer 
53871ec5155SSascha Hauer 	wait_op_done(host, 0);
53971ec5155SSascha Hauer }
54071ec5155SSascha Hauer 
54134f6e157SSascha Hauer /* This function sends an address (or partial address) to the
54234f6e157SSascha Hauer  * NAND device. The address is used to select the source/destination for
54334f6e157SSascha Hauer  * a NAND command. */
5445f97304eSSascha Hauer static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
54534f6e157SSascha Hauer {
5461f3df4dcSSascha Hauer 	dev_dbg(host->dev, "send_addr(host, 0x%x %d)\n", addr, islast);
54734f6e157SSascha Hauer 
5481bc99180SSascha Hauer 	writew(addr, NFC_V1_V2_FLASH_ADDR);
5491bc99180SSascha Hauer 	writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
55034f6e157SSascha Hauer 
55134f6e157SSascha Hauer 	/* Wait for operation to complete */
552c110eaf4SSascha Hauer 	wait_op_done(host, islast);
55334f6e157SSascha Hauer }
55434f6e157SSascha Hauer 
55571ec5155SSascha Hauer static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
55671ec5155SSascha Hauer {
5574bd4ebccSBoris BREZILLON 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
558d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
55971ec5155SSascha Hauer 	uint32_t tmp;
56071ec5155SSascha Hauer 
56171ec5155SSascha Hauer 	tmp = readl(NFC_V3_CONFIG1);
56271ec5155SSascha Hauer 	tmp &= ~(7 << 4);
56371ec5155SSascha Hauer 	writel(tmp, NFC_V3_CONFIG1);
56471ec5155SSascha Hauer 
56571ec5155SSascha Hauer 	/* transfer data from NFC ram to nand */
56671ec5155SSascha Hauer 	writel(ops, NFC_V3_LAUNCH);
56771ec5155SSascha Hauer 
56871ec5155SSascha Hauer 	wait_op_done(host, false);
56971ec5155SSascha Hauer }
57071ec5155SSascha Hauer 
5716d38af25SUwe Kleine-König static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
5726d38af25SUwe Kleine-König {
5734bd4ebccSBoris BREZILLON 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
574d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
5756d38af25SUwe Kleine-König 
5766d38af25SUwe Kleine-König 	/* NANDFC buffer 0 is used for page read/write */
5776d38af25SUwe Kleine-König 	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
5786d38af25SUwe Kleine-König 
5796d38af25SUwe Kleine-König 	writew(ops, NFC_V1_V2_CONFIG2);
5806d38af25SUwe Kleine-König 
5816d38af25SUwe Kleine-König 	/* Wait for operation to complete */
5826d38af25SUwe Kleine-König 	wait_op_done(host, true);
5836d38af25SUwe Kleine-König }
5846d38af25SUwe Kleine-König 
5856d38af25SUwe Kleine-König static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
58634f6e157SSascha Hauer {
5874bd4ebccSBoris BREZILLON 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
588d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
589c5d23f1bSSascha Hauer 	int bufs, i;
590c5d23f1bSSascha Hauer 
5916d38af25SUwe Kleine-König 	if (mtd->writesize > 512)
592c5d23f1bSSascha Hauer 		bufs = 4;
593c5d23f1bSSascha Hauer 	else
594c5d23f1bSSascha Hauer 		bufs = 1;
595c5d23f1bSSascha Hauer 
596c5d23f1bSSascha Hauer 	for (i = 0; i < bufs; i++) {
59734f6e157SSascha Hauer 
59834f6e157SSascha Hauer 		/* NANDFC buffer 0 is used for page read/write */
599d178e3e8SBaruch Siach 		writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
60034f6e157SSascha Hauer 
6011bc99180SSascha Hauer 		writew(ops, NFC_V1_V2_CONFIG2);
60234f6e157SSascha Hauer 
60334f6e157SSascha Hauer 		/* Wait for operation to complete */
604c110eaf4SSascha Hauer 		wait_op_done(host, true);
60534f6e157SSascha Hauer 	}
60634f6e157SSascha Hauer }
60734f6e157SSascha Hauer 
60871ec5155SSascha Hauer static void send_read_id_v3(struct mxc_nand_host *host)
60971ec5155SSascha Hauer {
61071ec5155SSascha Hauer 	/* Read ID into main buffer */
61171ec5155SSascha Hauer 	writel(NFC_ID, NFC_V3_LAUNCH);
61271ec5155SSascha Hauer 
61371ec5155SSascha Hauer 	wait_op_done(host, true);
61471ec5155SSascha Hauer 
615096bcc23SSascha Hauer 	memcpy32_fromio(host->data_buf, host->main_area0, 16);
61671ec5155SSascha Hauer }
61771ec5155SSascha Hauer 
61834f6e157SSascha Hauer /* Request the NANDFC to perform a read of the NAND device ID. */
6195f97304eSSascha Hauer static void send_read_id_v1_v2(struct mxc_nand_host *host)
62034f6e157SSascha Hauer {
62134f6e157SSascha Hauer 	/* NANDFC buffer 0 is used for device ID output */
622d178e3e8SBaruch Siach 	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
62334f6e157SSascha Hauer 
6241bc99180SSascha Hauer 	writew(NFC_ID, NFC_V1_V2_CONFIG2);
62534f6e157SSascha Hauer 
62634f6e157SSascha Hauer 	/* Wait for operation to complete */
627c110eaf4SSascha Hauer 	wait_op_done(host, true);
62834f6e157SSascha Hauer 
629096bcc23SSascha Hauer 	memcpy32_fromio(host->data_buf, host->main_area0, 16);
63034f6e157SSascha Hauer }
63134f6e157SSascha Hauer 
63271ec5155SSascha Hauer static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
63334f6e157SSascha Hauer {
63471ec5155SSascha Hauer 	writew(NFC_STATUS, NFC_V3_LAUNCH);
635c110eaf4SSascha Hauer 	wait_op_done(host, true);
63634f6e157SSascha Hauer 
63771ec5155SSascha Hauer 	return readl(NFC_V3_CONFIG1) >> 16;
63871ec5155SSascha Hauer }
63971ec5155SSascha Hauer 
64034f6e157SSascha Hauer /* This function requests the NANDFC to perform a read of the
64134f6e157SSascha Hauer  * NAND device status and returns the current status. */
6425f97304eSSascha Hauer static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
64334f6e157SSascha Hauer {
644c29c607aSSascha Hauer 	void __iomem *main_buf = host->main_area0;
64534f6e157SSascha Hauer 	uint32_t store;
64634f6e157SSascha Hauer 	uint16_t ret;
64734f6e157SSascha Hauer 
648d178e3e8SBaruch Siach 	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
649c29c607aSSascha Hauer 
650c29c607aSSascha Hauer 	/*
651c29c607aSSascha Hauer 	 * The device status is stored in main_area0. To
652c29c607aSSascha Hauer 	 * prevent corruption of the buffer save the value
653c29c607aSSascha Hauer 	 * and restore it afterwards.
654c29c607aSSascha Hauer 	 */
65534f6e157SSascha Hauer 	store = readl(main_buf);
65634f6e157SSascha Hauer 
6571bc99180SSascha Hauer 	writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
65834f6e157SSascha Hauer 	wait_op_done(host, true);
65934f6e157SSascha Hauer 
66034f6e157SSascha Hauer 	ret = readw(main_buf);
661c29c607aSSascha Hauer 
66234f6e157SSascha Hauer 	writel(store, main_buf);
66334f6e157SSascha Hauer 
66434f6e157SSascha Hauer 	return ret;
66534f6e157SSascha Hauer }
66634f6e157SSascha Hauer 
667040bd3f6SSascha Hauer static void mxc_nand_enable_hwecc_v1_v2(struct nand_chip *chip, bool enable)
668040bd3f6SSascha Hauer {
669040bd3f6SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
670040bd3f6SSascha Hauer 	uint16_t config1;
671040bd3f6SSascha Hauer 
672040bd3f6SSascha Hauer 	if (chip->ecc.mode != NAND_ECC_HW)
673040bd3f6SSascha Hauer 		return;
674040bd3f6SSascha Hauer 
675040bd3f6SSascha Hauer 	config1 = readw(NFC_V1_V2_CONFIG1);
676040bd3f6SSascha Hauer 
677040bd3f6SSascha Hauer 	if (enable)
678040bd3f6SSascha Hauer 		config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
679040bd3f6SSascha Hauer 	else
680040bd3f6SSascha Hauer 		config1 &= ~NFC_V1_V2_CONFIG1_ECC_EN;
681040bd3f6SSascha Hauer 
682040bd3f6SSascha Hauer 	writew(config1, NFC_V1_V2_CONFIG1);
683040bd3f6SSascha Hauer }
684040bd3f6SSascha Hauer 
685040bd3f6SSascha Hauer static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable)
686040bd3f6SSascha Hauer {
687040bd3f6SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
688040bd3f6SSascha Hauer 	uint32_t config2;
689040bd3f6SSascha Hauer 
690040bd3f6SSascha Hauer 	if (chip->ecc.mode != NAND_ECC_HW)
691040bd3f6SSascha Hauer 		return;
692040bd3f6SSascha Hauer 
693040bd3f6SSascha Hauer 	config2 = readl(NFC_V3_CONFIG2);
694040bd3f6SSascha Hauer 
695040bd3f6SSascha Hauer 	if (enable)
696040bd3f6SSascha Hauer 		config2 |= NFC_V3_CONFIG2_ECC_EN;
697040bd3f6SSascha Hauer 	else
698040bd3f6SSascha Hauer 		config2 &= ~NFC_V3_CONFIG2_ECC_EN;
699040bd3f6SSascha Hauer 
700040bd3f6SSascha Hauer 	writel(config2, NFC_V3_CONFIG2);
701040bd3f6SSascha Hauer }
702040bd3f6SSascha Hauer 
70334f6e157SSascha Hauer /* This functions is used by upper layer to checks if device is ready */
70450a487e7SBoris Brezillon static int mxc_nand_dev_ready(struct nand_chip *chip)
70534f6e157SSascha Hauer {
70634f6e157SSascha Hauer 	/*
70734f6e157SSascha Hauer 	 * NFC handles R/B internally. Therefore, this function
70834f6e157SSascha Hauer 	 * always returns status as ready.
70934f6e157SSascha Hauer 	 */
71034f6e157SSascha Hauer 	return 1;
71134f6e157SSascha Hauer }
71234f6e157SSascha Hauer 
7135039fc9fSSascha Hauer static int mxc_nand_read_page_v1(struct nand_chip *chip, void *buf, void *oob,
7145039fc9fSSascha Hauer 				 bool ecc, int page)
7155039fc9fSSascha Hauer {
7165039fc9fSSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
7175039fc9fSSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
7185039fc9fSSascha Hauer 	unsigned int bitflips_corrected = 0;
7195039fc9fSSascha Hauer 	int no_subpages;
7205039fc9fSSascha Hauer 	int i;
7215039fc9fSSascha Hauer 
7225039fc9fSSascha Hauer 	host->devtype_data->enable_hwecc(chip, ecc);
7235039fc9fSSascha Hauer 
7245039fc9fSSascha Hauer 	host->devtype_data->send_cmd(host, NAND_CMD_READ0, false);
7255039fc9fSSascha Hauer 	mxc_do_addr_cycle(mtd, 0, page);
7265039fc9fSSascha Hauer 
7275039fc9fSSascha Hauer 	if (mtd->writesize > 512)
7285039fc9fSSascha Hauer 		host->devtype_data->send_cmd(host, NAND_CMD_READSTART, true);
7295039fc9fSSascha Hauer 
7305039fc9fSSascha Hauer 	no_subpages = mtd->writesize >> 9;
7315039fc9fSSascha Hauer 
7325039fc9fSSascha Hauer 	for (i = 0; i < no_subpages; i++) {
7335039fc9fSSascha Hauer 		uint16_t ecc_stats;
7345039fc9fSSascha Hauer 
7355039fc9fSSascha Hauer 		/* NANDFC buffer 0 is used for page read/write */
7365039fc9fSSascha Hauer 		writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
7375039fc9fSSascha Hauer 
7385039fc9fSSascha Hauer 		writew(NFC_OUTPUT, NFC_V1_V2_CONFIG2);
7395039fc9fSSascha Hauer 
7405039fc9fSSascha Hauer 		/* Wait for operation to complete */
7415039fc9fSSascha Hauer 		wait_op_done(host, true);
7425039fc9fSSascha Hauer 
7435039fc9fSSascha Hauer 		ecc_stats = get_ecc_status_v1(host);
7445039fc9fSSascha Hauer 
7455039fc9fSSascha Hauer 		ecc_stats >>= 2;
7465039fc9fSSascha Hauer 
7475039fc9fSSascha Hauer 		if (buf && ecc) {
7485039fc9fSSascha Hauer 			switch (ecc_stats & 0x3) {
7495039fc9fSSascha Hauer 			case 0:
7505039fc9fSSascha Hauer 			default:
7515039fc9fSSascha Hauer 				break;
7525039fc9fSSascha Hauer 			case 1:
7535039fc9fSSascha Hauer 				mtd->ecc_stats.corrected++;
7545039fc9fSSascha Hauer 				bitflips_corrected = 1;
7555039fc9fSSascha Hauer 				break;
7565039fc9fSSascha Hauer 			case 2:
7575039fc9fSSascha Hauer 				mtd->ecc_stats.failed++;
7585039fc9fSSascha Hauer 				break;
7595039fc9fSSascha Hauer 			}
7605039fc9fSSascha Hauer 		}
7615039fc9fSSascha Hauer 	}
7625039fc9fSSascha Hauer 
7635039fc9fSSascha Hauer 	if (buf)
7645039fc9fSSascha Hauer 		memcpy32_fromio(buf, host->main_area0, mtd->writesize);
7655039fc9fSSascha Hauer 	if (oob)
7665039fc9fSSascha Hauer 		copy_spare(mtd, true, oob);
7675039fc9fSSascha Hauer 
7685039fc9fSSascha Hauer 	return bitflips_corrected;
76934f6e157SSascha Hauer }
77034f6e157SSascha Hauer 
77167b87f66SSascha Hauer static int mxc_nand_read_page_v2_v3(struct nand_chip *chip, void *buf,
77267b87f66SSascha Hauer 				    void *oob, bool ecc, int page)
77367b87f66SSascha Hauer {
77467b87f66SSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
77567b87f66SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
77667b87f66SSascha Hauer 	unsigned int max_bitflips = 0;
77794f77e50SSascha Hauer 	u32 ecc_stat, err;
77867b87f66SSascha Hauer 	int no_subpages;
77994f77e50SSascha Hauer 	u8 ecc_bit_mask, err_limit;
78094f77e50SSascha Hauer 
78167b87f66SSascha Hauer 	host->devtype_data->enable_hwecc(chip, ecc);
78267b87f66SSascha Hauer 
78367b87f66SSascha Hauer 	host->devtype_data->send_cmd(host, NAND_CMD_READ0, false);
78467b87f66SSascha Hauer 	mxc_do_addr_cycle(mtd, 0, page);
78567b87f66SSascha Hauer 
78667b87f66SSascha Hauer 	if (mtd->writesize > 512)
78767b87f66SSascha Hauer 		host->devtype_data->send_cmd(host,
78867b87f66SSascha Hauer 				NAND_CMD_READSTART, true);
78967b87f66SSascha Hauer 
79067b87f66SSascha Hauer 	host->devtype_data->send_page(mtd, NFC_OUTPUT);
79167b87f66SSascha Hauer 
79267b87f66SSascha Hauer 	if (buf)
79367b87f66SSascha Hauer 		memcpy32_fromio(buf, host->main_area0, mtd->writesize);
79467b87f66SSascha Hauer 	if (oob)
79567b87f66SSascha Hauer 		copy_spare(mtd, true, oob);
79667b87f66SSascha Hauer 
79794f77e50SSascha Hauer 	ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
79894f77e50SSascha Hauer 	err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
79994f77e50SSascha Hauer 
80094f77e50SSascha Hauer 	no_subpages = mtd->writesize >> 9;
80194f77e50SSascha Hauer 
8026d38af25SUwe Kleine-König 	ecc_stat = host->devtype_data->get_ecc_status(host);
80394f77e50SSascha Hauer 
80494f77e50SSascha Hauer 	do {
80594f77e50SSascha Hauer 		err = ecc_stat & ecc_bit_mask;
80694f77e50SSascha Hauer 		if (err > err_limit) {
80767b87f66SSascha Hauer 			mtd->ecc_stats.failed++;
80894f77e50SSascha Hauer 		} else {
80967b87f66SSascha Hauer 			mtd->ecc_stats.corrected += err;
81067b87f66SSascha Hauer 			max_bitflips = max_t(unsigned int, max_bitflips, err);
81194f77e50SSascha Hauer 		}
81267b87f66SSascha Hauer 
81394f77e50SSascha Hauer 		ecc_stat >>= 4;
81494f77e50SSascha Hauer 	} while (--no_subpages);
81594f77e50SSascha Hauer 
81667b87f66SSascha Hauer 	return max_bitflips;
81767b87f66SSascha Hauer }
81894f77e50SSascha Hauer 
819b9761687SBoris Brezillon static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf,
820b9761687SBoris Brezillon 			      int oob_required, int page)
82167b87f66SSascha Hauer {
82267b87f66SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
82367b87f66SSascha Hauer 	void *oob_buf;
82467b87f66SSascha Hauer 
82567b87f66SSascha Hauer 	if (oob_required)
82667b87f66SSascha Hauer 		oob_buf = chip->oob_poi;
82767b87f66SSascha Hauer 	else
82867b87f66SSascha Hauer 		oob_buf = NULL;
82967b87f66SSascha Hauer 
83067b87f66SSascha Hauer 	return host->devtype_data->read_page(chip, buf, oob_buf, 1, page);
83167b87f66SSascha Hauer }
83267b87f66SSascha Hauer 
833b9761687SBoris Brezillon static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
834b9761687SBoris Brezillon 				  int oob_required, int page)
83567b87f66SSascha Hauer {
83667b87f66SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
83767b87f66SSascha Hauer 	void *oob_buf;
83867b87f66SSascha Hauer 
83967b87f66SSascha Hauer 	if (oob_required)
84067b87f66SSascha Hauer 		oob_buf = chip->oob_poi;
84167b87f66SSascha Hauer 	else
84267b87f66SSascha Hauer 		oob_buf = NULL;
84367b87f66SSascha Hauer 
84467b87f66SSascha Hauer 	return host->devtype_data->read_page(chip, buf, oob_buf, 0, page);
84567b87f66SSascha Hauer }
84667b87f66SSascha Hauer 
847b9761687SBoris Brezillon static int mxc_nand_read_oob(struct nand_chip *chip, int page)
84867b87f66SSascha Hauer {
84967b87f66SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
85067b87f66SSascha Hauer 
85167b87f66SSascha Hauer 	return host->devtype_data->read_page(chip, NULL, chip->oob_poi, 0,
85267b87f66SSascha Hauer 					     page);
85394f77e50SSascha Hauer }
85494f77e50SSascha Hauer 
8556811c464SSascha Hauer static int mxc_nand_write_page(struct nand_chip *chip, const uint8_t *buf,
8566811c464SSascha Hauer 			       bool ecc, int page)
8576811c464SSascha Hauer {
8586811c464SSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
8596811c464SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
8606811c464SSascha Hauer 
8616811c464SSascha Hauer 	host->devtype_data->enable_hwecc(chip, ecc);
8626811c464SSascha Hauer 
8636811c464SSascha Hauer 	host->devtype_data->send_cmd(host, NAND_CMD_SEQIN, false);
8646811c464SSascha Hauer 	mxc_do_addr_cycle(mtd, 0, page);
8656811c464SSascha Hauer 
8666811c464SSascha Hauer 	memcpy32_toio(host->main_area0, buf, mtd->writesize);
8676811c464SSascha Hauer 	copy_spare(mtd, false, chip->oob_poi);
8686811c464SSascha Hauer 
8696811c464SSascha Hauer 	host->devtype_data->send_page(mtd, NFC_INPUT);
8706811c464SSascha Hauer 	host->devtype_data->send_cmd(host, NAND_CMD_PAGEPROG, true);
8716811c464SSascha Hauer 	mxc_do_addr_cycle(mtd, 0, page);
8726811c464SSascha Hauer 
8736811c464SSascha Hauer 	return 0;
8746811c464SSascha Hauer }
8756811c464SSascha Hauer 
876767eb6fbSBoris Brezillon static int mxc_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf,
877767eb6fbSBoris Brezillon 				   int oob_required, int page)
8786811c464SSascha Hauer {
8796811c464SSascha Hauer 	return mxc_nand_write_page(chip, buf, true, page);
8806811c464SSascha Hauer }
8816811c464SSascha Hauer 
882767eb6fbSBoris Brezillon static int mxc_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
883767eb6fbSBoris Brezillon 				   int oob_required, int page)
8846811c464SSascha Hauer {
8856811c464SSascha Hauer 	return mxc_nand_write_page(chip, buf, false, page);
8866811c464SSascha Hauer }
8876811c464SSascha Hauer 
888767eb6fbSBoris Brezillon static int mxc_nand_write_oob(struct nand_chip *chip, int page)
8896811c464SSascha Hauer {
890767eb6fbSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
8916811c464SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
8926811c464SSascha Hauer 
8936811c464SSascha Hauer 	memset(host->data_buf, 0xff, mtd->writesize);
8946811c464SSascha Hauer 
8956811c464SSascha Hauer 	return mxc_nand_write_page(chip, host->data_buf, false, page);
8966811c464SSascha Hauer }
8976811c464SSascha Hauer 
8987e534323SBoris Brezillon static u_char mxc_nand_read_byte(struct nand_chip *nand_chip)
89934f6e157SSascha Hauer {
900d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
901f8f9608dSSascha Hauer 	uint8_t ret;
90234f6e157SSascha Hauer 
90334f6e157SSascha Hauer 	/* Check for status request */
90434f6e157SSascha Hauer 	if (host->status_request)
905e4303b25SUwe Kleine-König 		return host->devtype_data->get_dev_status(host) & 0xFF;
90634f6e157SSascha Hauer 
9073f410690SUwe Kleine-König 	if (nand_chip->options & NAND_BUSWIDTH_16) {
9083f410690SUwe Kleine-König 		/* only take the lower byte of each word */
9093f410690SUwe Kleine-König 		ret = *(uint16_t *)(host->data_buf + host->buf_start);
9103f410690SUwe Kleine-König 
9113f410690SUwe Kleine-König 		host->buf_start += 2;
9123f410690SUwe Kleine-König 	} else {
913f8f9608dSSascha Hauer 		ret = *(uint8_t *)(host->data_buf + host->buf_start);
914f8f9608dSSascha Hauer 		host->buf_start++;
9153f410690SUwe Kleine-König 	}
91634f6e157SSascha Hauer 
9171f3df4dcSSascha Hauer 	dev_dbg(host->dev, "%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start);
91834f6e157SSascha Hauer 	return ret;
91934f6e157SSascha Hauer }
92034f6e157SSascha Hauer 
92134f6e157SSascha Hauer /* Write data of length len to buffer buf. The data to be
92234f6e157SSascha Hauer  * written on NAND Flash is first copied to RAMbuffer. After the Data Input
92334f6e157SSascha Hauer  * Operation by the NFC, the data is written to NAND Flash */
924c0739d85SBoris Brezillon static void mxc_nand_write_buf(struct nand_chip *nand_chip, const u_char *buf,
925c0739d85SBoris Brezillon 			       int len)
92634f6e157SSascha Hauer {
927c0739d85SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(nand_chip);
928d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
929f8f9608dSSascha Hauer 	u16 col = host->buf_start;
930f8f9608dSSascha Hauer 	int n = mtd->oobsize + mtd->writesize - col;
93134f6e157SSascha Hauer 
932f8f9608dSSascha Hauer 	n = min(n, len);
93334f6e157SSascha Hauer 
934f8f9608dSSascha Hauer 	memcpy(host->data_buf + col, buf, n);
93534f6e157SSascha Hauer 
936f8f9608dSSascha Hauer 	host->buf_start += n;
93734f6e157SSascha Hauer }
93834f6e157SSascha Hauer 
93934f6e157SSascha Hauer /* Read the data buffer from the NAND Flash. To read the data from NAND
94034f6e157SSascha Hauer  * Flash first the data output cycle is initiated by the NFC, which copies
94134f6e157SSascha Hauer  * the data to RAMbuffer. This data of length len is then copied to buffer buf.
94234f6e157SSascha Hauer  */
9437e534323SBoris Brezillon static void mxc_nand_read_buf(struct nand_chip *nand_chip, u_char *buf,
9447e534323SBoris Brezillon 			      int len)
94534f6e157SSascha Hauer {
9467e534323SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(nand_chip);
947d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
948f8f9608dSSascha Hauer 	u16 col = host->buf_start;
949f8f9608dSSascha Hauer 	int n = mtd->oobsize + mtd->writesize - col;
95034f6e157SSascha Hauer 
951f8f9608dSSascha Hauer 	n = min(n, len);
95234f6e157SSascha Hauer 
9535d9d9936SBaruch Siach 	memcpy(buf, host->data_buf + col, n);
95434f6e157SSascha Hauer 
9555d9d9936SBaruch Siach 	host->buf_start += n;
95634f6e157SSascha Hauer }
95734f6e157SSascha Hauer 
95834f6e157SSascha Hauer /* This function is used by upper layer for select and
95934f6e157SSascha Hauer  * deselect of the NAND chip */
960758b56f5SBoris Brezillon static void mxc_nand_select_chip_v1_v3(struct nand_chip *nand_chip, int chip)
96134f6e157SSascha Hauer {
962d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
96334f6e157SSascha Hauer 
964d178e3e8SBaruch Siach 	if (chip == -1) {
96534f6e157SSascha Hauer 		/* Disable the NFC clock */
96634f6e157SSascha Hauer 		if (host->clk_act) {
96797c3213fSSascha Hauer 			clk_disable_unprepare(host->clk);
96834f6e157SSascha Hauer 			host->clk_act = 0;
96934f6e157SSascha Hauer 		}
970d178e3e8SBaruch Siach 		return;
971d178e3e8SBaruch Siach 	}
972d178e3e8SBaruch Siach 
97334f6e157SSascha Hauer 	if (!host->clk_act) {
974d178e3e8SBaruch Siach 		/* Enable the NFC clock */
97597c3213fSSascha Hauer 		clk_prepare_enable(host->clk);
97634f6e157SSascha Hauer 		host->clk_act = 1;
97734f6e157SSascha Hauer 	}
9785e05a2d6SUwe Kleine-König }
97934f6e157SSascha Hauer 
980758b56f5SBoris Brezillon static void mxc_nand_select_chip_v2(struct nand_chip *nand_chip, int chip)
98134f6e157SSascha Hauer {
982d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
98334f6e157SSascha Hauer 
98434f6e157SSascha Hauer 	if (chip == -1) {
98534f6e157SSascha Hauer 		/* Disable the NFC clock */
98634f6e157SSascha Hauer 		if (host->clk_act) {
9873d059693SFabio Estevam 			clk_disable_unprepare(host->clk);
98834f6e157SSascha Hauer 			host->clk_act = 0;
98934f6e157SSascha Hauer 		}
99034f6e157SSascha Hauer 		return;
99134f6e157SSascha Hauer 	}
99234f6e157SSascha Hauer 
99334f6e157SSascha Hauer 	if (!host->clk_act) {
99434f6e157SSascha Hauer 		/* Enable the NFC clock */
9953d059693SFabio Estevam 		clk_prepare_enable(host->clk);
99634f6e157SSascha Hauer 		host->clk_act = 1;
99734f6e157SSascha Hauer 	}
99834f6e157SSascha Hauer 
999d178e3e8SBaruch Siach 	host->active_cs = chip;
1000d178e3e8SBaruch Siach 	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
100134f6e157SSascha Hauer }
100234f6e157SSascha Hauer 
10033bff08dfSBoris Brezillon #define MXC_V1_ECCBYTES		5
10043bff08dfSBoris Brezillon 
1005a894cf6cSBoris Brezillon static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
1006a894cf6cSBoris Brezillon 				struct mtd_oob_region *oobregion)
1007a894cf6cSBoris Brezillon {
1008a894cf6cSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
1009a894cf6cSBoris Brezillon 
1010a894cf6cSBoris Brezillon 	if (section >= nand_chip->ecc.steps)
1011a894cf6cSBoris Brezillon 		return -ERANGE;
1012a894cf6cSBoris Brezillon 
1013a894cf6cSBoris Brezillon 	oobregion->offset = (section * 16) + 6;
10143bff08dfSBoris Brezillon 	oobregion->length = MXC_V1_ECCBYTES;
1015a894cf6cSBoris Brezillon 
1016a894cf6cSBoris Brezillon 	return 0;
1017a894cf6cSBoris Brezillon }
1018a894cf6cSBoris Brezillon 
1019a894cf6cSBoris Brezillon static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section,
1020a894cf6cSBoris Brezillon 				 struct mtd_oob_region *oobregion)
1021a894cf6cSBoris Brezillon {
1022a894cf6cSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
1023a894cf6cSBoris Brezillon 
1024a894cf6cSBoris Brezillon 	if (section > nand_chip->ecc.steps)
1025a894cf6cSBoris Brezillon 		return -ERANGE;
1026a894cf6cSBoris Brezillon 
1027a894cf6cSBoris Brezillon 	if (!section) {
1028a894cf6cSBoris Brezillon 		if (mtd->writesize <= 512) {
1029a894cf6cSBoris Brezillon 			oobregion->offset = 0;
1030a894cf6cSBoris Brezillon 			oobregion->length = 5;
1031a894cf6cSBoris Brezillon 		} else {
1032a894cf6cSBoris Brezillon 			oobregion->offset = 2;
1033a894cf6cSBoris Brezillon 			oobregion->length = 4;
1034a894cf6cSBoris Brezillon 		}
1035a894cf6cSBoris Brezillon 	} else {
10363bff08dfSBoris Brezillon 		oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6;
1037a894cf6cSBoris Brezillon 		if (section < nand_chip->ecc.steps)
1038a894cf6cSBoris Brezillon 			oobregion->length = (section * 16) + 6 -
1039a894cf6cSBoris Brezillon 					    oobregion->offset;
1040a894cf6cSBoris Brezillon 		else
1041a894cf6cSBoris Brezillon 			oobregion->length = mtd->oobsize - oobregion->offset;
1042a894cf6cSBoris Brezillon 	}
1043a894cf6cSBoris Brezillon 
1044a894cf6cSBoris Brezillon 	return 0;
1045a894cf6cSBoris Brezillon }
1046a894cf6cSBoris Brezillon 
1047a894cf6cSBoris Brezillon static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
1048a894cf6cSBoris Brezillon 	.ecc = mxc_v1_ooblayout_ecc,
1049a894cf6cSBoris Brezillon 	.free = mxc_v1_ooblayout_free,
1050a894cf6cSBoris Brezillon };
1051a894cf6cSBoris Brezillon 
1052a894cf6cSBoris Brezillon static int mxc_v2_ooblayout_ecc(struct mtd_info *mtd, int section,
1053a894cf6cSBoris Brezillon 				struct mtd_oob_region *oobregion)
1054a894cf6cSBoris Brezillon {
1055a894cf6cSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
1056a894cf6cSBoris Brezillon 	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
1057a894cf6cSBoris Brezillon 
1058a894cf6cSBoris Brezillon 	if (section >= nand_chip->ecc.steps)
1059a894cf6cSBoris Brezillon 		return -ERANGE;
1060a894cf6cSBoris Brezillon 
1061a894cf6cSBoris Brezillon 	oobregion->offset = (section * stepsize) + 7;
1062a894cf6cSBoris Brezillon 	oobregion->length = nand_chip->ecc.bytes;
1063a894cf6cSBoris Brezillon 
1064a894cf6cSBoris Brezillon 	return 0;
1065a894cf6cSBoris Brezillon }
1066a894cf6cSBoris Brezillon 
1067a894cf6cSBoris Brezillon static int mxc_v2_ooblayout_free(struct mtd_info *mtd, int section,
1068a894cf6cSBoris Brezillon 				 struct mtd_oob_region *oobregion)
1069a894cf6cSBoris Brezillon {
1070a894cf6cSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
1071a894cf6cSBoris Brezillon 	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
1072a894cf6cSBoris Brezillon 
107338178e7bSLothar Waßmann 	if (section >= nand_chip->ecc.steps)
1074a894cf6cSBoris Brezillon 		return -ERANGE;
1075a894cf6cSBoris Brezillon 
1076a894cf6cSBoris Brezillon 	if (!section) {
1077a894cf6cSBoris Brezillon 		if (mtd->writesize <= 512) {
1078a894cf6cSBoris Brezillon 			oobregion->offset = 0;
1079a894cf6cSBoris Brezillon 			oobregion->length = 5;
1080a894cf6cSBoris Brezillon 		} else {
1081a894cf6cSBoris Brezillon 			oobregion->offset = 2;
1082a894cf6cSBoris Brezillon 			oobregion->length = 4;
1083a894cf6cSBoris Brezillon 		}
1084a894cf6cSBoris Brezillon 	} else {
1085a894cf6cSBoris Brezillon 		oobregion->offset = section * stepsize;
1086a894cf6cSBoris Brezillon 		oobregion->length = 7;
1087a894cf6cSBoris Brezillon 	}
1088a894cf6cSBoris Brezillon 
1089a894cf6cSBoris Brezillon 	return 0;
1090a894cf6cSBoris Brezillon }
1091a894cf6cSBoris Brezillon 
1092a894cf6cSBoris Brezillon static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = {
1093a894cf6cSBoris Brezillon 	.ecc = mxc_v2_ooblayout_ecc,
1094a894cf6cSBoris Brezillon 	.free = mxc_v2_ooblayout_free,
1095a894cf6cSBoris Brezillon };
1096a894cf6cSBoris Brezillon 
10976e85dfdcSSascha Hauer /*
10986e85dfdcSSascha Hauer  * v2 and v3 type controllers can do 4bit or 8bit ecc depending
10996e85dfdcSSascha Hauer  * on how much oob the nand chip has. For 8bit ecc we need at least
11006e85dfdcSSascha Hauer  * 26 bytes of oob data per 512 byte block.
11016e85dfdcSSascha Hauer  */
11026e85dfdcSSascha Hauer static int get_eccsize(struct mtd_info *mtd)
11036e85dfdcSSascha Hauer {
11046e85dfdcSSascha Hauer 	int oobbytes_per_512 = 0;
11056e85dfdcSSascha Hauer 
11066e85dfdcSSascha Hauer 	oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
11076e85dfdcSSascha Hauer 
11086e85dfdcSSascha Hauer 	if (oobbytes_per_512 < 26)
11096e85dfdcSSascha Hauer 		return 4;
11106e85dfdcSSascha Hauer 	else
11116e85dfdcSSascha Hauer 		return 8;
11126e85dfdcSSascha Hauer }
11136e85dfdcSSascha Hauer 
11146d38af25SUwe Kleine-König static void preset_v1(struct mtd_info *mtd)
1115d4840180SIvo Clarysse {
11164bd4ebccSBoris BREZILLON 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
1117d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
1118b8db2f51SSascha Hauer 	uint16_t config1 = 0;
1119d4840180SIvo Clarysse 
11201f42adc8SUwe Kleine-König 	if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize)
1121b8db2f51SSascha Hauer 		config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
1122b8db2f51SSascha Hauer 
1123f48d0f9aSUwe Kleine-König 	if (!host->devtype_data->irqpending_quirk)
1124b8db2f51SSascha Hauer 		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
11256e85dfdcSSascha Hauer 
11266d38af25SUwe Kleine-König 	host->eccsize = 1;
11276d38af25SUwe Kleine-König 
11286d38af25SUwe Kleine-König 	writew(config1, NFC_V1_V2_CONFIG1);
11296d38af25SUwe Kleine-König 	/* preset operation */
11306d38af25SUwe Kleine-König 
11316d38af25SUwe Kleine-König 	/* Unlock the internal RAM Buffer */
11326d38af25SUwe Kleine-König 	writew(0x2, NFC_V1_V2_CONFIG);
11336d38af25SUwe Kleine-König 
11346d38af25SUwe Kleine-König 	/* Blocks to be unlocked */
11356d38af25SUwe Kleine-König 	writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
11366d38af25SUwe Kleine-König 	writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
11376d38af25SUwe Kleine-König 
11386d38af25SUwe Kleine-König 	/* Unlock Block Command for given address range */
11396d38af25SUwe Kleine-König 	writew(0x4, NFC_V1_V2_WRPROT);
11406d38af25SUwe Kleine-König }
11416d38af25SUwe Kleine-König 
1142858838b8SBoris Brezillon static int mxc_nand_v2_setup_data_interface(struct nand_chip *chip, int csline,
1143104e442aSBoris Brezillon 					const struct nand_data_interface *conf)
114482830796SSascha Hauer {
1145858838b8SBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
114682830796SSascha Hauer 	int tRC_min_ns, tRC_ps, ret;
114782830796SSascha Hauer 	unsigned long rate, rate_round;
114882830796SSascha Hauer 	const struct nand_sdr_timings *timings;
114982830796SSascha Hauer 	u16 config1;
115082830796SSascha Hauer 
115182830796SSascha Hauer 	timings = nand_get_sdr_timings(conf);
115282830796SSascha Hauer 	if (IS_ERR(timings))
115382830796SSascha Hauer 		return -ENOTSUPP;
115482830796SSascha Hauer 
115582830796SSascha Hauer 	config1 = readw(NFC_V1_V2_CONFIG1);
115682830796SSascha Hauer 
115782830796SSascha Hauer 	tRC_min_ns = timings->tRC_min / 1000;
115882830796SSascha Hauer 	rate = 1000000000 / tRC_min_ns;
115982830796SSascha Hauer 
116082830796SSascha Hauer 	/*
116182830796SSascha Hauer 	 * For tRC < 30ns we have to use EDO mode. In this case the controller
116282830796SSascha Hauer 	 * does one access per clock cycle. Otherwise the controller does one
116382830796SSascha Hauer 	 * access in two clock cycles, thus we have to double the rate to the
116482830796SSascha Hauer 	 * controller.
116582830796SSascha Hauer 	 */
116682830796SSascha Hauer 	if (tRC_min_ns < 30) {
116782830796SSascha Hauer 		rate_round = clk_round_rate(host->clk, rate);
116882830796SSascha Hauer 		config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
116982830796SSascha Hauer 		tRC_ps = 1000000000 / (rate_round / 1000);
117082830796SSascha Hauer 	} else {
117182830796SSascha Hauer 		rate *= 2;
117282830796SSascha Hauer 		rate_round = clk_round_rate(host->clk, rate);
117382830796SSascha Hauer 		config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
117482830796SSascha Hauer 		tRC_ps = 1000000000 / (rate_round / 1000 / 2);
117582830796SSascha Hauer 	}
117682830796SSascha Hauer 
117782830796SSascha Hauer 	/*
117882830796SSascha Hauer 	 * The timing values compared against are from the i.MX25 Automotive
117982830796SSascha Hauer 	 * datasheet, Table 50. NFC Timing Parameters
118082830796SSascha Hauer 	 */
118182830796SSascha Hauer 	if (timings->tCLS_min > tRC_ps - 1000 ||
118282830796SSascha Hauer 	    timings->tCLH_min > tRC_ps - 2000 ||
118382830796SSascha Hauer 	    timings->tCS_min > tRC_ps - 1000 ||
118482830796SSascha Hauer 	    timings->tCH_min > tRC_ps - 2000 ||
118582830796SSascha Hauer 	    timings->tWP_min > tRC_ps - 1500 ||
118682830796SSascha Hauer 	    timings->tALS_min > tRC_ps ||
118782830796SSascha Hauer 	    timings->tALH_min > tRC_ps - 3000 ||
118882830796SSascha Hauer 	    timings->tDS_min > tRC_ps ||
118982830796SSascha Hauer 	    timings->tDH_min > tRC_ps - 5000 ||
119082830796SSascha Hauer 	    timings->tWC_min > 2 * tRC_ps ||
119182830796SSascha Hauer 	    timings->tWH_min > tRC_ps - 2500 ||
119282830796SSascha Hauer 	    timings->tRR_min > 6 * tRC_ps ||
119382830796SSascha Hauer 	    timings->tRP_min > 3 * tRC_ps / 2 ||
119482830796SSascha Hauer 	    timings->tRC_min > 2 * tRC_ps ||
119582830796SSascha Hauer 	    timings->tREH_min > (tRC_ps / 2) - 2500) {
119682830796SSascha Hauer 		dev_dbg(host->dev, "Timing out of bounds\n");
119782830796SSascha Hauer 		return -EINVAL;
119882830796SSascha Hauer 	}
119982830796SSascha Hauer 
1200104e442aSBoris Brezillon 	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
120182830796SSascha Hauer 		return 0;
120282830796SSascha Hauer 
120382830796SSascha Hauer 	ret = clk_set_rate(host->clk, rate);
120482830796SSascha Hauer 	if (ret)
120582830796SSascha Hauer 		return ret;
120682830796SSascha Hauer 
120782830796SSascha Hauer 	writew(config1, NFC_V1_V2_CONFIG1);
120882830796SSascha Hauer 
120982830796SSascha Hauer 	dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
121082830796SSascha Hauer 		config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
121182830796SSascha Hauer 		"normal");
121282830796SSascha Hauer 
121382830796SSascha Hauer 	return 0;
121482830796SSascha Hauer }
121582830796SSascha Hauer 
12166d38af25SUwe Kleine-König static void preset_v2(struct mtd_info *mtd)
12176d38af25SUwe Kleine-König {
12184bd4ebccSBoris BREZILLON 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
1219d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
12206d38af25SUwe Kleine-König 	uint16_t config1 = 0;
12216d38af25SUwe Kleine-König 
1222d4840180SIvo Clarysse 	config1 |= NFC_V2_CONFIG1_FP_INT;
1223d4840180SIvo Clarysse 
1224f48d0f9aSUwe Kleine-König 	if (!host->devtype_data->irqpending_quirk)
1225d4840180SIvo Clarysse 		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
12266e85dfdcSSascha Hauer 
12276d38af25SUwe Kleine-König 	if (mtd->writesize) {
1228b8db2f51SSascha Hauer 		uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
1229b8db2f51SSascha Hauer 
12301f42adc8SUwe Kleine-König 		if (nand_chip->ecc.mode == NAND_ECC_HW)
12311f42adc8SUwe Kleine-König 			config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
12321f42adc8SUwe Kleine-König 
12336e85dfdcSSascha Hauer 		host->eccsize = get_eccsize(mtd);
12346e85dfdcSSascha Hauer 		if (host->eccsize == 4)
1235b8db2f51SSascha Hauer 			config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
1236b8db2f51SSascha Hauer 
1237b8db2f51SSascha Hauer 		config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
12386e85dfdcSSascha Hauer 	} else {
12396e85dfdcSSascha Hauer 		host->eccsize = 1;
12406e85dfdcSSascha Hauer 	}
12416e85dfdcSSascha Hauer 
1242b8db2f51SSascha Hauer 	writew(config1, NFC_V1_V2_CONFIG1);
1243d4840180SIvo Clarysse 	/* preset operation */
1244d4840180SIvo Clarysse 
12453f77f244SMartin Kaiser 	/* spare area size in 16-bit half-words */
12463f77f244SMartin Kaiser 	writew(mtd->oobsize / 2, NFC_V21_RSLTSPARE_AREA);
12473f77f244SMartin Kaiser 
1248d4840180SIvo Clarysse 	/* Unlock the internal RAM Buffer */
12491bc99180SSascha Hauer 	writew(0x2, NFC_V1_V2_CONFIG);
1250d4840180SIvo Clarysse 
1251d4840180SIvo Clarysse 	/* Blocks to be unlocked */
1252d178e3e8SBaruch Siach 	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
1253d178e3e8SBaruch Siach 	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
1254d178e3e8SBaruch Siach 	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
1255d178e3e8SBaruch Siach 	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
1256d178e3e8SBaruch Siach 	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
1257d178e3e8SBaruch Siach 	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
1258d178e3e8SBaruch Siach 	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
1259d178e3e8SBaruch Siach 	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
1260d4840180SIvo Clarysse 
1261d4840180SIvo Clarysse 	/* Unlock Block Command for given address range */
12621bc99180SSascha Hauer 	writew(0x4, NFC_V1_V2_WRPROT);
1263d4840180SIvo Clarysse }
1264d4840180SIvo Clarysse 
126571ec5155SSascha Hauer static void preset_v3(struct mtd_info *mtd)
126671ec5155SSascha Hauer {
12674bd4ebccSBoris BREZILLON 	struct nand_chip *chip = mtd_to_nand(mtd);
1268d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(chip);
126971ec5155SSascha Hauer 	uint32_t config2, config3;
127071ec5155SSascha Hauer 	int i, addr_phases;
127171ec5155SSascha Hauer 
127271ec5155SSascha Hauer 	writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
127371ec5155SSascha Hauer 	writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
127471ec5155SSascha Hauer 
127571ec5155SSascha Hauer 	/* Unlock the internal RAM Buffer */
127671ec5155SSascha Hauer 	writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
127771ec5155SSascha Hauer 			NFC_V3_WRPROT);
127871ec5155SSascha Hauer 
127971ec5155SSascha Hauer 	/* Blocks to be unlocked */
128071ec5155SSascha Hauer 	for (i = 0; i < NAND_MAX_CHIPS; i++)
12811b15b1f5SFabio Estevam 		writel(0xffff << 16, NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
128271ec5155SSascha Hauer 
128371ec5155SSascha Hauer 	writel(0, NFC_V3_IPC);
128471ec5155SSascha Hauer 
128571ec5155SSascha Hauer 	config2 = NFC_V3_CONFIG2_ONE_CYCLE |
128671ec5155SSascha Hauer 		NFC_V3_CONFIG2_2CMD_PHASES |
128771ec5155SSascha Hauer 		NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
128871ec5155SSascha Hauer 		NFC_V3_CONFIG2_ST_CMD(0x70) |
128963f1474cSSascha Hauer 		NFC_V3_CONFIG2_INT_MSK |
129071ec5155SSascha Hauer 		NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
129171ec5155SSascha Hauer 
129271ec5155SSascha Hauer 	addr_phases = fls(chip->pagemask) >> 3;
129371ec5155SSascha Hauer 
129471ec5155SSascha Hauer 	if (mtd->writesize == 2048) {
129571ec5155SSascha Hauer 		config2 |= NFC_V3_CONFIG2_PS_2048;
129671ec5155SSascha Hauer 		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
129771ec5155SSascha Hauer 	} else if (mtd->writesize == 4096) {
129871ec5155SSascha Hauer 		config2 |= NFC_V3_CONFIG2_PS_4096;
129971ec5155SSascha Hauer 		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
130071ec5155SSascha Hauer 	} else {
130171ec5155SSascha Hauer 		config2 |= NFC_V3_CONFIG2_PS_512;
130271ec5155SSascha Hauer 		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
130371ec5155SSascha Hauer 	}
130471ec5155SSascha Hauer 
130571ec5155SSascha Hauer 	if (mtd->writesize) {
13061f42adc8SUwe Kleine-König 		if (chip->ecc.mode == NAND_ECC_HW)
13071f42adc8SUwe Kleine-König 			config2 |= NFC_V3_CONFIG2_ECC_EN;
13081f42adc8SUwe Kleine-König 
130971718a8eSSascha Hauer 		config2 |= NFC_V3_CONFIG2_PPB(
131071718a8eSSascha Hauer 				ffs(mtd->erasesize / mtd->writesize) - 6,
131171718a8eSSascha Hauer 				host->devtype_data->ppb_shift);
131271ec5155SSascha Hauer 		host->eccsize = get_eccsize(mtd);
131371ec5155SSascha Hauer 		if (host->eccsize == 8)
131471ec5155SSascha Hauer 			config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
131571ec5155SSascha Hauer 	}
131671ec5155SSascha Hauer 
131771ec5155SSascha Hauer 	writel(config2, NFC_V3_CONFIG2);
131871ec5155SSascha Hauer 
131971ec5155SSascha Hauer 	config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
132071ec5155SSascha Hauer 			NFC_V3_CONFIG3_NO_SDMA |
132171ec5155SSascha Hauer 			NFC_V3_CONFIG3_RBB_MODE |
132271ec5155SSascha Hauer 			NFC_V3_CONFIG3_SBB(6) | /* Reset default */
132371ec5155SSascha Hauer 			NFC_V3_CONFIG3_ADD_OP(0);
132471ec5155SSascha Hauer 
132571ec5155SSascha Hauer 	if (!(chip->options & NAND_BUSWIDTH_16))
132671ec5155SSascha Hauer 		config3 |= NFC_V3_CONFIG3_FW8;
132771ec5155SSascha Hauer 
132871ec5155SSascha Hauer 	writel(config3, NFC_V3_CONFIG3);
132971ec5155SSascha Hauer 
133071ec5155SSascha Hauer 	writel(0, NFC_V3_DELAY_LINE);
1331a3e65b64SSascha Hauer }
133234f6e157SSascha Hauer 
133334f6e157SSascha Hauer /* Used by the upper layer to write command to NAND Flash for
133434f6e157SSascha Hauer  * different operations to be carried out on NAND Flash */
13355295cf2eSBoris Brezillon static void mxc_nand_command(struct nand_chip *nand_chip, unsigned command,
133634f6e157SSascha Hauer 			     int column, int page_addr)
133734f6e157SSascha Hauer {
13385295cf2eSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(nand_chip);
1339d699ed25SBoris BREZILLON 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
134034f6e157SSascha Hauer 
13411f3df4dcSSascha Hauer 	dev_dbg(host->dev, "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
134234f6e157SSascha Hauer 	      command, column, page_addr);
134334f6e157SSascha Hauer 
134434f6e157SSascha Hauer 	/* Reset command state information */
134534f6e157SSascha Hauer 	host->status_request = false;
134634f6e157SSascha Hauer 
134734f6e157SSascha Hauer 	/* Command pre-processing step */
134834f6e157SSascha Hauer 	switch (command) {
1349d4840180SIvo Clarysse 	case NAND_CMD_RESET:
1350e4303b25SUwe Kleine-König 		host->devtype_data->preset(mtd);
1351e4303b25SUwe Kleine-König 		host->devtype_data->send_cmd(host, command, false);
1352d4840180SIvo Clarysse 		break;
135334f6e157SSascha Hauer 
135434f6e157SSascha Hauer 	case NAND_CMD_STATUS:
1355f8f9608dSSascha Hauer 		host->buf_start = 0;
135634f6e157SSascha Hauer 		host->status_request = true;
135789121a6bSSascha Hauer 
1358e4303b25SUwe Kleine-König 		host->devtype_data->send_cmd(host, command, true);
1359c4ca3997SUwe Kleine-König 		WARN_ONCE(column != -1 || page_addr != -1,
1360c4ca3997SUwe Kleine-König 			  "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
1361c4ca3997SUwe Kleine-König 			  command, column, page_addr);
136289121a6bSSascha Hauer 		mxc_do_addr_cycle(mtd, column, page_addr);
136334f6e157SSascha Hauer 		break;
136434f6e157SSascha Hauer 
136534f6e157SSascha Hauer 	case NAND_CMD_READID:
1366e4303b25SUwe Kleine-König 		host->devtype_data->send_cmd(host, command, true);
136789121a6bSSascha Hauer 		mxc_do_addr_cycle(mtd, column, page_addr);
1368e4303b25SUwe Kleine-König 		host->devtype_data->send_read_id(host);
1369c4ca3997SUwe Kleine-König 		host->buf_start = 0;
137034f6e157SSascha Hauer 		break;
137134f6e157SSascha Hauer 
137289121a6bSSascha Hauer 	case NAND_CMD_ERASE1:
137334f6e157SSascha Hauer 	case NAND_CMD_ERASE2:
1374e4303b25SUwe Kleine-König 		host->devtype_data->send_cmd(host, command, false);
1375c4ca3997SUwe Kleine-König 		WARN_ONCE(column != -1,
1376c4ca3997SUwe Kleine-König 			  "Unexpected column value (cmd=%u, col=%d)\n",
1377c4ca3997SUwe Kleine-König 			  command, column);
137889121a6bSSascha Hauer 		mxc_do_addr_cycle(mtd, column, page_addr);
137989121a6bSSascha Hauer 
138034f6e157SSascha Hauer 		break;
13813d6e81c0SUwe Kleine-König 	case NAND_CMD_PARAM:
13823d6e81c0SUwe Kleine-König 		host->devtype_data->send_cmd(host, command, false);
13833d6e81c0SUwe Kleine-König 		mxc_do_addr_cycle(mtd, column, page_addr);
13843d6e81c0SUwe Kleine-König 		host->devtype_data->send_page(mtd, NFC_OUTPUT);
13853d6e81c0SUwe Kleine-König 		memcpy32_fromio(host->data_buf, host->main_area0, 512);
13863d6e81c0SUwe Kleine-König 		host->buf_start = 0;
13873d6e81c0SUwe Kleine-König 		break;
138898ebb521SUwe Kleine-König 	default:
138998ebb521SUwe Kleine-König 		WARN_ONCE(1, "Unimplemented command (cmd=%u)\n",
139098ebb521SUwe Kleine-König 			  command);
139198ebb521SUwe Kleine-König 		break;
139234f6e157SSascha Hauer 	}
139334f6e157SSascha Hauer }
139434f6e157SSascha Hauer 
1395aa36ff25SBoris Brezillon static int mxc_nand_set_features(struct nand_chip *chip, int addr,
1396aa36ff25SBoris Brezillon 				 u8 *subfeature_param)
13974123ea34SSascha Hauer {
1398aa36ff25SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
1399aa36ff25SBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
14004123ea34SSascha Hauer 	int i;
14014123ea34SSascha Hauer 
14024123ea34SSascha Hauer 	host->buf_start = 0;
14034123ea34SSascha Hauer 
14044123ea34SSascha Hauer 	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
1405716bbbabSBoris Brezillon 		chip->legacy.write_byte(chip, subfeature_param[i]);
14064123ea34SSascha Hauer 
14074123ea34SSascha Hauer 	memcpy32_toio(host->main_area0, host->data_buf, mtd->writesize);
14084123ea34SSascha Hauer 	host->devtype_data->send_cmd(host, NAND_CMD_SET_FEATURES, false);
14094123ea34SSascha Hauer 	mxc_do_addr_cycle(mtd, addr, -1);
14104123ea34SSascha Hauer 	host->devtype_data->send_page(mtd, NFC_INPUT);
14114123ea34SSascha Hauer 
14124123ea34SSascha Hauer 	return 0;
14134123ea34SSascha Hauer }
14144123ea34SSascha Hauer 
1415aa36ff25SBoris Brezillon static int mxc_nand_get_features(struct nand_chip *chip, int addr,
1416aa36ff25SBoris Brezillon 				 u8 *subfeature_param)
14174123ea34SSascha Hauer {
1418aa36ff25SBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
1419aa36ff25SBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
14204123ea34SSascha Hauer 	int i;
14214123ea34SSascha Hauer 
14224123ea34SSascha Hauer 	host->devtype_data->send_cmd(host, NAND_CMD_GET_FEATURES, false);
14234123ea34SSascha Hauer 	mxc_do_addr_cycle(mtd, addr, -1);
14244123ea34SSascha Hauer 	host->devtype_data->send_page(mtd, NFC_OUTPUT);
14254123ea34SSascha Hauer 	memcpy32_fromio(host->data_buf, host->main_area0, 512);
14264123ea34SSascha Hauer 	host->buf_start = 0;
14274123ea34SSascha Hauer 
14284123ea34SSascha Hauer 	for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
1429716bbbabSBoris Brezillon 		*subfeature_param++ = chip->legacy.read_byte(chip);
14304123ea34SSascha Hauer 
14314123ea34SSascha Hauer 	return 0;
14324123ea34SSascha Hauer }
14334123ea34SSascha Hauer 
1434f1372055SSascha Hauer /*
1435f1372055SSascha Hauer  * The generic flash bbt decriptors overlap with our ecc
1436f1372055SSascha Hauer  * hardware, so define some i.MX specific ones.
1437f1372055SSascha Hauer  */
1438f1372055SSascha Hauer static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
1439f1372055SSascha Hauer static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
1440f1372055SSascha Hauer 
1441f1372055SSascha Hauer static struct nand_bbt_descr bbt_main_descr = {
1442f1372055SSascha Hauer 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1443f1372055SSascha Hauer 	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1444f1372055SSascha Hauer 	.offs = 0,
1445f1372055SSascha Hauer 	.len = 4,
1446f1372055SSascha Hauer 	.veroffs = 4,
1447f1372055SSascha Hauer 	.maxblocks = 4,
1448f1372055SSascha Hauer 	.pattern = bbt_pattern,
1449f1372055SSascha Hauer };
1450f1372055SSascha Hauer 
1451f1372055SSascha Hauer static struct nand_bbt_descr bbt_mirror_descr = {
1452f1372055SSascha Hauer 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
1453f1372055SSascha Hauer 	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
1454f1372055SSascha Hauer 	.offs = 0,
1455f1372055SSascha Hauer 	.len = 4,
1456f1372055SSascha Hauer 	.veroffs = 4,
1457f1372055SSascha Hauer 	.maxblocks = 4,
1458f1372055SSascha Hauer 	.pattern = mirror_pattern,
1459f1372055SSascha Hauer };
1460f1372055SSascha Hauer 
1461f48d0f9aSUwe Kleine-König /* v1 + irqpending_quirk: i.MX21 */
1462e4303b25SUwe Kleine-König static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
14636d38af25SUwe Kleine-König 	.preset = preset_v1,
14645039fc9fSSascha Hauer 	.read_page = mxc_nand_read_page_v1,
1465e4303b25SUwe Kleine-König 	.send_cmd = send_cmd_v1_v2,
1466e4303b25SUwe Kleine-König 	.send_addr = send_addr_v1_v2,
14676d38af25SUwe Kleine-König 	.send_page = send_page_v1,
1468e4303b25SUwe Kleine-König 	.send_read_id = send_read_id_v1_v2,
1469e4303b25SUwe Kleine-König 	.get_dev_status = get_dev_status_v1_v2,
1470e4303b25SUwe Kleine-König 	.check_int = check_int_v1_v2,
1471e4303b25SUwe Kleine-König 	.irq_control = irq_control_v1_v2,
14726d38af25SUwe Kleine-König 	.get_ecc_status = get_ecc_status_v1,
1473a894cf6cSBoris Brezillon 	.ooblayout = &mxc_v1_ooblayout_ops,
14745e05a2d6SUwe Kleine-König 	.select_chip = mxc_nand_select_chip_v1_v3,
1475040bd3f6SSascha Hauer 	.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
1476f48d0f9aSUwe Kleine-König 	.irqpending_quirk = 1,
1477f48d0f9aSUwe Kleine-König 	.needs_ip = 0,
1478f48d0f9aSUwe Kleine-König 	.regs_offset = 0xe00,
1479f48d0f9aSUwe Kleine-König 	.spare0_offset = 0x800,
1480f48d0f9aSUwe Kleine-König 	.spare_len = 16,
1481f48d0f9aSUwe Kleine-König 	.eccbytes = 3,
1482f48d0f9aSUwe Kleine-König 	.eccsize = 1,
1483f48d0f9aSUwe Kleine-König };
1484f48d0f9aSUwe Kleine-König 
1485f48d0f9aSUwe Kleine-König /* v1 + !irqpending_quirk: i.MX27, i.MX31 */
1486f48d0f9aSUwe Kleine-König static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
1487f48d0f9aSUwe Kleine-König 	.preset = preset_v1,
14885039fc9fSSascha Hauer 	.read_page = mxc_nand_read_page_v1,
1489f48d0f9aSUwe Kleine-König 	.send_cmd = send_cmd_v1_v2,
1490f48d0f9aSUwe Kleine-König 	.send_addr = send_addr_v1_v2,
1491f48d0f9aSUwe Kleine-König 	.send_page = send_page_v1,
1492f48d0f9aSUwe Kleine-König 	.send_read_id = send_read_id_v1_v2,
1493f48d0f9aSUwe Kleine-König 	.get_dev_status = get_dev_status_v1_v2,
1494f48d0f9aSUwe Kleine-König 	.check_int = check_int_v1_v2,
1495f48d0f9aSUwe Kleine-König 	.irq_control = irq_control_v1_v2,
1496f48d0f9aSUwe Kleine-König 	.get_ecc_status = get_ecc_status_v1,
1497a894cf6cSBoris Brezillon 	.ooblayout = &mxc_v1_ooblayout_ops,
1498f48d0f9aSUwe Kleine-König 	.select_chip = mxc_nand_select_chip_v1_v3,
1499040bd3f6SSascha Hauer 	.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
1500f48d0f9aSUwe Kleine-König 	.irqpending_quirk = 0,
1501f48d0f9aSUwe Kleine-König 	.needs_ip = 0,
1502f48d0f9aSUwe Kleine-König 	.regs_offset = 0xe00,
1503f48d0f9aSUwe Kleine-König 	.spare0_offset = 0x800,
1504f48d0f9aSUwe Kleine-König 	.axi_offset = 0,
1505f48d0f9aSUwe Kleine-König 	.spare_len = 16,
1506f48d0f9aSUwe Kleine-König 	.eccbytes = 3,
1507f48d0f9aSUwe Kleine-König 	.eccsize = 1,
1508e4303b25SUwe Kleine-König };
1509e4303b25SUwe Kleine-König 
1510e4303b25SUwe Kleine-König /* v21: i.MX25, i.MX35 */
1511e4303b25SUwe Kleine-König static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
15126d38af25SUwe Kleine-König 	.preset = preset_v2,
151367b87f66SSascha Hauer 	.read_page = mxc_nand_read_page_v2_v3,
1514e4303b25SUwe Kleine-König 	.send_cmd = send_cmd_v1_v2,
1515e4303b25SUwe Kleine-König 	.send_addr = send_addr_v1_v2,
15166d38af25SUwe Kleine-König 	.send_page = send_page_v2,
1517e4303b25SUwe Kleine-König 	.send_read_id = send_read_id_v1_v2,
1518e4303b25SUwe Kleine-König 	.get_dev_status = get_dev_status_v1_v2,
1519e4303b25SUwe Kleine-König 	.check_int = check_int_v1_v2,
1520e4303b25SUwe Kleine-König 	.irq_control = irq_control_v1_v2,
15216d38af25SUwe Kleine-König 	.get_ecc_status = get_ecc_status_v2,
1522a894cf6cSBoris Brezillon 	.ooblayout = &mxc_v2_ooblayout_ops,
15235e05a2d6SUwe Kleine-König 	.select_chip = mxc_nand_select_chip_v2,
152482830796SSascha Hauer 	.setup_data_interface = mxc_nand_v2_setup_data_interface,
1525040bd3f6SSascha Hauer 	.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
1526f48d0f9aSUwe Kleine-König 	.irqpending_quirk = 0,
1527f48d0f9aSUwe Kleine-König 	.needs_ip = 0,
1528f48d0f9aSUwe Kleine-König 	.regs_offset = 0x1e00,
1529f48d0f9aSUwe Kleine-König 	.spare0_offset = 0x1000,
1530f48d0f9aSUwe Kleine-König 	.axi_offset = 0,
1531f48d0f9aSUwe Kleine-König 	.spare_len = 64,
1532f48d0f9aSUwe Kleine-König 	.eccbytes = 9,
1533f48d0f9aSUwe Kleine-König 	.eccsize = 0,
1534e4303b25SUwe Kleine-König };
1535e4303b25SUwe Kleine-König 
153671718a8eSSascha Hauer /* v3.2a: i.MX51 */
1537e4303b25SUwe Kleine-König static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
1538e4303b25SUwe Kleine-König 	.preset = preset_v3,
153967b87f66SSascha Hauer 	.read_page = mxc_nand_read_page_v2_v3,
1540e4303b25SUwe Kleine-König 	.send_cmd = send_cmd_v3,
1541e4303b25SUwe Kleine-König 	.send_addr = send_addr_v3,
1542e4303b25SUwe Kleine-König 	.send_page = send_page_v3,
1543e4303b25SUwe Kleine-König 	.send_read_id = send_read_id_v3,
1544e4303b25SUwe Kleine-König 	.get_dev_status = get_dev_status_v3,
1545e4303b25SUwe Kleine-König 	.check_int = check_int_v3,
1546e4303b25SUwe Kleine-König 	.irq_control = irq_control_v3,
15476d38af25SUwe Kleine-König 	.get_ecc_status = get_ecc_status_v3,
1548a894cf6cSBoris Brezillon 	.ooblayout = &mxc_v2_ooblayout_ops,
15495e05a2d6SUwe Kleine-König 	.select_chip = mxc_nand_select_chip_v1_v3,
1550040bd3f6SSascha Hauer 	.enable_hwecc = mxc_nand_enable_hwecc_v3,
1551f48d0f9aSUwe Kleine-König 	.irqpending_quirk = 0,
1552f48d0f9aSUwe Kleine-König 	.needs_ip = 1,
1553f48d0f9aSUwe Kleine-König 	.regs_offset = 0,
1554f48d0f9aSUwe Kleine-König 	.spare0_offset = 0x1000,
1555f48d0f9aSUwe Kleine-König 	.axi_offset = 0x1e00,
1556f48d0f9aSUwe Kleine-König 	.spare_len = 64,
1557f48d0f9aSUwe Kleine-König 	.eccbytes = 0,
1558f48d0f9aSUwe Kleine-König 	.eccsize = 0,
155971718a8eSSascha Hauer 	.ppb_shift = 7,
156071718a8eSSascha Hauer };
156171718a8eSSascha Hauer 
156271718a8eSSascha Hauer /* v3.2b: i.MX53 */
156371718a8eSSascha Hauer static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
156471718a8eSSascha Hauer 	.preset = preset_v3,
156567b87f66SSascha Hauer 	.read_page = mxc_nand_read_page_v2_v3,
156671718a8eSSascha Hauer 	.send_cmd = send_cmd_v3,
156771718a8eSSascha Hauer 	.send_addr = send_addr_v3,
156871718a8eSSascha Hauer 	.send_page = send_page_v3,
156971718a8eSSascha Hauer 	.send_read_id = send_read_id_v3,
157071718a8eSSascha Hauer 	.get_dev_status = get_dev_status_v3,
157171718a8eSSascha Hauer 	.check_int = check_int_v3,
157271718a8eSSascha Hauer 	.irq_control = irq_control_v3,
157371718a8eSSascha Hauer 	.get_ecc_status = get_ecc_status_v3,
1574a894cf6cSBoris Brezillon 	.ooblayout = &mxc_v2_ooblayout_ops,
157571718a8eSSascha Hauer 	.select_chip = mxc_nand_select_chip_v1_v3,
1576040bd3f6SSascha Hauer 	.enable_hwecc = mxc_nand_enable_hwecc_v3,
157771718a8eSSascha Hauer 	.irqpending_quirk = 0,
157871718a8eSSascha Hauer 	.needs_ip = 1,
157971718a8eSSascha Hauer 	.regs_offset = 0,
158071718a8eSSascha Hauer 	.spare0_offset = 0x1000,
158171718a8eSSascha Hauer 	.axi_offset = 0x1e00,
158271718a8eSSascha Hauer 	.spare_len = 64,
158371718a8eSSascha Hauer 	.eccbytes = 0,
158471718a8eSSascha Hauer 	.eccsize = 0,
158571718a8eSSascha Hauer 	.ppb_shift = 8,
1586e4303b25SUwe Kleine-König };
1587e4303b25SUwe Kleine-König 
15884d62435fSShawn Guo static inline int is_imx21_nfc(struct mxc_nand_host *host)
15894d62435fSShawn Guo {
15904d62435fSShawn Guo 	return host->devtype_data == &imx21_nand_devtype_data;
15914d62435fSShawn Guo }
15924d62435fSShawn Guo 
15934d62435fSShawn Guo static inline int is_imx27_nfc(struct mxc_nand_host *host)
15944d62435fSShawn Guo {
15954d62435fSShawn Guo 	return host->devtype_data == &imx27_nand_devtype_data;
15964d62435fSShawn Guo }
15974d62435fSShawn Guo 
15984d62435fSShawn Guo static inline int is_imx25_nfc(struct mxc_nand_host *host)
15994d62435fSShawn Guo {
16004d62435fSShawn Guo 	return host->devtype_data == &imx25_nand_devtype_data;
16014d62435fSShawn Guo }
16024d62435fSShawn Guo 
16034d62435fSShawn Guo static inline int is_imx51_nfc(struct mxc_nand_host *host)
16044d62435fSShawn Guo {
16054d62435fSShawn Guo 	return host->devtype_data == &imx51_nand_devtype_data;
16064d62435fSShawn Guo }
16074d62435fSShawn Guo 
16084d62435fSShawn Guo static inline int is_imx53_nfc(struct mxc_nand_host *host)
16094d62435fSShawn Guo {
16104d62435fSShawn Guo 	return host->devtype_data == &imx53_nand_devtype_data;
16114d62435fSShawn Guo }
16124d62435fSShawn Guo 
16138d1e568dSKrzysztof Kozlowski static const struct platform_device_id mxcnd_devtype[] = {
16144d62435fSShawn Guo 	{
16154d62435fSShawn Guo 		.name = "imx21-nand",
16164d62435fSShawn Guo 		.driver_data = (kernel_ulong_t) &imx21_nand_devtype_data,
16174d62435fSShawn Guo 	}, {
16184d62435fSShawn Guo 		.name = "imx27-nand",
16194d62435fSShawn Guo 		.driver_data = (kernel_ulong_t) &imx27_nand_devtype_data,
16204d62435fSShawn Guo 	}, {
16214d62435fSShawn Guo 		.name = "imx25-nand",
16224d62435fSShawn Guo 		.driver_data = (kernel_ulong_t) &imx25_nand_devtype_data,
16234d62435fSShawn Guo 	}, {
16244d62435fSShawn Guo 		.name = "imx51-nand",
16254d62435fSShawn Guo 		.driver_data = (kernel_ulong_t) &imx51_nand_devtype_data,
16264d62435fSShawn Guo 	}, {
16274d62435fSShawn Guo 		.name = "imx53-nand",
16284d62435fSShawn Guo 		.driver_data = (kernel_ulong_t) &imx53_nand_devtype_data,
16294d62435fSShawn Guo 	}, {
16304d62435fSShawn Guo 		/* sentinel */
16314d62435fSShawn Guo 	}
16324d62435fSShawn Guo };
16334d62435fSShawn Guo MODULE_DEVICE_TABLE(platform, mxcnd_devtype);
16344d62435fSShawn Guo 
1635ba52b4ddSBoris Brezillon #ifdef CONFIG_OF
16366436356bSUwe Kleine-König static const struct of_device_id mxcnd_dt_ids[] = {
16376436356bSUwe Kleine-König 	{
16386436356bSUwe Kleine-König 		.compatible = "fsl,imx21-nand",
16396436356bSUwe Kleine-König 		.data = &imx21_nand_devtype_data,
16406436356bSUwe Kleine-König 	}, {
16416436356bSUwe Kleine-König 		.compatible = "fsl,imx27-nand",
16426436356bSUwe Kleine-König 		.data = &imx27_nand_devtype_data,
16436436356bSUwe Kleine-König 	}, {
16446436356bSUwe Kleine-König 		.compatible = "fsl,imx25-nand",
16456436356bSUwe Kleine-König 		.data = &imx25_nand_devtype_data,
16466436356bSUwe Kleine-König 	}, {
16476436356bSUwe Kleine-König 		.compatible = "fsl,imx51-nand",
16486436356bSUwe Kleine-König 		.data = &imx51_nand_devtype_data,
164971718a8eSSascha Hauer 	}, {
165071718a8eSSascha Hauer 		.compatible = "fsl,imx53-nand",
165171718a8eSSascha Hauer 		.data = &imx53_nand_devtype_data,
16526436356bSUwe Kleine-König 	},
16536436356bSUwe Kleine-König 	{ /* sentinel */ }
16546436356bSUwe Kleine-König };
1655b33c35b1SLuis de Bethencourt MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
16566436356bSUwe Kleine-König 
165724f0ae99SMartin Kaiser static int mxcnd_probe_dt(struct mxc_nand_host *host)
16586436356bSUwe Kleine-König {
16596436356bSUwe Kleine-König 	struct device_node *np = host->dev->of_node;
16606436356bSUwe Kleine-König 	const struct of_device_id *of_id =
16616436356bSUwe Kleine-König 		of_match_device(mxcnd_dt_ids, host->dev);
16626436356bSUwe Kleine-König 
16636436356bSUwe Kleine-König 	if (!np)
16646436356bSUwe Kleine-König 		return 1;
16656436356bSUwe Kleine-König 
16666436356bSUwe Kleine-König 	host->devtype_data = of_id->data;
16676436356bSUwe Kleine-König 
16686436356bSUwe Kleine-König 	return 0;
16696436356bSUwe Kleine-König }
16706436356bSUwe Kleine-König #else
167124f0ae99SMartin Kaiser static int mxcnd_probe_dt(struct mxc_nand_host *host)
16726436356bSUwe Kleine-König {
16736436356bSUwe Kleine-König 	return 1;
16746436356bSUwe Kleine-König }
16756436356bSUwe Kleine-König #endif
16766436356bSUwe Kleine-König 
167796fa8e6eSMiquel Raynal static int mxcnd_attach_chip(struct nand_chip *chip)
167896fa8e6eSMiquel Raynal {
167996fa8e6eSMiquel Raynal 	struct mtd_info *mtd = nand_to_mtd(chip);
168096fa8e6eSMiquel Raynal 	struct mxc_nand_host *host = nand_get_controller_data(chip);
168196fa8e6eSMiquel Raynal 	struct device *dev = mtd->dev.parent;
168296fa8e6eSMiquel Raynal 
168396fa8e6eSMiquel Raynal 	switch (chip->ecc.mode) {
168496fa8e6eSMiquel Raynal 	case NAND_ECC_HW:
168596fa8e6eSMiquel Raynal 		chip->ecc.read_page = mxc_nand_read_page;
168696fa8e6eSMiquel Raynal 		chip->ecc.read_page_raw = mxc_nand_read_page_raw;
168796fa8e6eSMiquel Raynal 		chip->ecc.read_oob = mxc_nand_read_oob;
168896fa8e6eSMiquel Raynal 		chip->ecc.write_page = mxc_nand_write_page_ecc;
168996fa8e6eSMiquel Raynal 		chip->ecc.write_page_raw = mxc_nand_write_page_raw;
169096fa8e6eSMiquel Raynal 		chip->ecc.write_oob = mxc_nand_write_oob;
169196fa8e6eSMiquel Raynal 		break;
169296fa8e6eSMiquel Raynal 
169396fa8e6eSMiquel Raynal 	case NAND_ECC_SOFT:
169496fa8e6eSMiquel Raynal 		break;
169596fa8e6eSMiquel Raynal 
169696fa8e6eSMiquel Raynal 	default:
169796fa8e6eSMiquel Raynal 		return -EINVAL;
169896fa8e6eSMiquel Raynal 	}
169996fa8e6eSMiquel Raynal 
170096fa8e6eSMiquel Raynal 	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
170196fa8e6eSMiquel Raynal 		chip->bbt_td = &bbt_main_descr;
170296fa8e6eSMiquel Raynal 		chip->bbt_md = &bbt_mirror_descr;
170396fa8e6eSMiquel Raynal 	}
170496fa8e6eSMiquel Raynal 
170596fa8e6eSMiquel Raynal 	/* Allocate the right size buffer now */
170696fa8e6eSMiquel Raynal 	devm_kfree(dev, (void *)host->data_buf);
170796fa8e6eSMiquel Raynal 	host->data_buf = devm_kzalloc(dev, mtd->writesize + mtd->oobsize,
170896fa8e6eSMiquel Raynal 				      GFP_KERNEL);
170996fa8e6eSMiquel Raynal 	if (!host->data_buf)
171096fa8e6eSMiquel Raynal 		return -ENOMEM;
171196fa8e6eSMiquel Raynal 
171296fa8e6eSMiquel Raynal 	/* Call preset again, with correct writesize chip time */
171396fa8e6eSMiquel Raynal 	host->devtype_data->preset(mtd);
171496fa8e6eSMiquel Raynal 
171596fa8e6eSMiquel Raynal 	if (!chip->ecc.bytes) {
171696fa8e6eSMiquel Raynal 		if (host->eccsize == 8)
171796fa8e6eSMiquel Raynal 			chip->ecc.bytes = 18;
171896fa8e6eSMiquel Raynal 		else if (host->eccsize == 4)
171996fa8e6eSMiquel Raynal 			chip->ecc.bytes = 9;
172096fa8e6eSMiquel Raynal 	}
172196fa8e6eSMiquel Raynal 
172296fa8e6eSMiquel Raynal 	/*
172396fa8e6eSMiquel Raynal 	 * Experimentation shows that i.MX NFC can only handle up to 218 oob
172496fa8e6eSMiquel Raynal 	 * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
172596fa8e6eSMiquel Raynal 	 * into copying invalid data to/from the spare IO buffer, as this
172696fa8e6eSMiquel Raynal 	 * might cause ECC data corruption when doing sub-page write to a
172796fa8e6eSMiquel Raynal 	 * partially written page.
172896fa8e6eSMiquel Raynal 	 */
172996fa8e6eSMiquel Raynal 	host->used_oobsize = min(mtd->oobsize, 218U);
173096fa8e6eSMiquel Raynal 
173196fa8e6eSMiquel Raynal 	if (chip->ecc.mode == NAND_ECC_HW) {
173296fa8e6eSMiquel Raynal 		if (is_imx21_nfc(host) || is_imx27_nfc(host))
173396fa8e6eSMiquel Raynal 			chip->ecc.strength = 1;
173496fa8e6eSMiquel Raynal 		else
173596fa8e6eSMiquel Raynal 			chip->ecc.strength = (host->eccsize == 4) ? 4 : 8;
173696fa8e6eSMiquel Raynal 	}
173796fa8e6eSMiquel Raynal 
173896fa8e6eSMiquel Raynal 	return 0;
173996fa8e6eSMiquel Raynal }
174096fa8e6eSMiquel Raynal 
17417a08dbaeSBoris Brezillon static int mxcnd_setup_data_interface(struct nand_chip *chip, int chipnr,
17427a08dbaeSBoris Brezillon 				      const struct nand_data_interface *conf)
17437a08dbaeSBoris Brezillon {
17447a08dbaeSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
17457a08dbaeSBoris Brezillon 
17467a08dbaeSBoris Brezillon 	return host->devtype_data->setup_data_interface(chip, chipnr, conf);
17477a08dbaeSBoris Brezillon }
17487a08dbaeSBoris Brezillon 
174996fa8e6eSMiquel Raynal static const struct nand_controller_ops mxcnd_controller_ops = {
175096fa8e6eSMiquel Raynal 	.attach_chip = mxcnd_attach_chip,
17517a08dbaeSBoris Brezillon 	.setup_data_interface = mxcnd_setup_data_interface,
175296fa8e6eSMiquel Raynal };
175396fa8e6eSMiquel Raynal 
175406f25510SBill Pemberton static int mxcnd_probe(struct platform_device *pdev)
175534f6e157SSascha Hauer {
175634f6e157SSascha Hauer 	struct nand_chip *this;
175734f6e157SSascha Hauer 	struct mtd_info *mtd;
175834f6e157SSascha Hauer 	struct mxc_nand_host *host;
175934f6e157SSascha Hauer 	struct resource *res;
1760d4ed8f12SDmitry Eremin-Solenikov 	int err = 0;
176134f6e157SSascha Hauer 
176234f6e157SSascha Hauer 	/* Allocate memory for MTD device structure and private data */
1763a5900554SHuang Shijie 	host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
1764a5900554SHuang Shijie 			GFP_KERNEL);
176534f6e157SSascha Hauer 	if (!host)
176634f6e157SSascha Hauer 		return -ENOMEM;
176734f6e157SSascha Hauer 
1768a5900554SHuang Shijie 	/* allocate a temporary buffer for the nand_scan_ident() */
1769a5900554SHuang Shijie 	host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
1770a5900554SHuang Shijie 	if (!host->data_buf)
1771a5900554SHuang Shijie 		return -ENOMEM;
1772f8f9608dSSascha Hauer 
177334f6e157SSascha Hauer 	host->dev = &pdev->dev;
177434f6e157SSascha Hauer 	/* structures must be linked */
177534f6e157SSascha Hauer 	this = &host->nand;
1776a008deb1SBoris BREZILLON 	mtd = nand_to_mtd(this);
177787f39f04SDavid Brownell 	mtd->dev.parent = &pdev->dev;
17781fbff0a6SSascha Hauer 	mtd->name = DRIVER_NAME;
177934f6e157SSascha Hauer 
178034f6e157SSascha Hauer 	/* 50 us command delay time */
17813cece3abSBoris Brezillon 	this->legacy.chip_delay = 5;
178234f6e157SSascha Hauer 
1783d699ed25SBoris BREZILLON 	nand_set_controller_data(this, host);
1784a61ae81aSBrian Norris 	nand_set_flash_node(this, pdev->dev.of_node),
17858395b753SBoris Brezillon 	this->legacy.dev_ready = mxc_nand_dev_ready;
1786bf6065c6SBoris Brezillon 	this->legacy.cmdfunc = mxc_nand_command;
1787716bbbabSBoris Brezillon 	this->legacy.read_byte = mxc_nand_read_byte;
1788716bbbabSBoris Brezillon 	this->legacy.write_buf = mxc_nand_write_buf;
1789716bbbabSBoris Brezillon 	this->legacy.read_buf = mxc_nand_read_buf;
179045240367SBoris Brezillon 	this->legacy.set_features = mxc_nand_set_features;
179145240367SBoris Brezillon 	this->legacy.get_features = mxc_nand_get_features;
179234f6e157SSascha Hauer 
179324b82d3cSFabio Estevam 	host->clk = devm_clk_get(&pdev->dev, NULL);
1794e4a09cbfSSascha Hauer 	if (IS_ERR(host->clk))
1795e4a09cbfSSascha Hauer 		return PTR_ERR(host->clk);
179634f6e157SSascha Hauer 
179771885b65SSascha Hauer 	err = mxcnd_probe_dt(host);
17984d62435fSShawn Guo 	if (err > 0) {
1799453810b7SJingoo Han 		struct mxc_nand_platform_data *pdata =
1800453810b7SJingoo Han 					dev_get_platdata(&pdev->dev);
18014d62435fSShawn Guo 		if (pdata) {
18024d62435fSShawn Guo 			host->pdata = *pdata;
18034d62435fSShawn Guo 			host->devtype_data = (struct mxc_nand_devtype_data *)
18044d62435fSShawn Guo 						pdev->id_entry->driver_data;
18054d62435fSShawn Guo 		} else {
18064d62435fSShawn Guo 			err = -ENODEV;
18074d62435fSShawn Guo 		}
18084d62435fSShawn Guo 	}
180971885b65SSascha Hauer 	if (err < 0)
181071885b65SSascha Hauer 		return err;
181171885b65SSascha Hauer 
18127a08dbaeSBoris Brezillon 	if (!host->devtype_data->setup_data_interface)
18137a08dbaeSBoris Brezillon 		this->options |= NAND_KEEP_TIMINGS;
181482830796SSascha Hauer 
181571885b65SSascha Hauer 	if (host->devtype_data->needs_ip) {
181634f6e157SSascha Hauer 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1817b0de774cSThierry Reding 		host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
1818b0de774cSThierry Reding 		if (IS_ERR(host->regs_ip))
1819b0de774cSThierry Reding 			return PTR_ERR(host->regs_ip);
182071885b65SSascha Hauer 
182171885b65SSascha Hauer 		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
182271885b65SSascha Hauer 	} else {
182371885b65SSascha Hauer 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
182471885b65SSascha Hauer 	}
182571885b65SSascha Hauer 
1826b0de774cSThierry Reding 	host->base = devm_ioremap_resource(&pdev->dev, res);
1827b0de774cSThierry Reding 	if (IS_ERR(host->base))
1828b0de774cSThierry Reding 		return PTR_ERR(host->base);
182934f6e157SSascha Hauer 
1830c6de7e1bSSascha Hauer 	host->main_area0 = host->base;
18319467114eSSascha Hauer 
1832f48d0f9aSUwe Kleine-König 	if (host->devtype_data->regs_offset)
1833f48d0f9aSUwe Kleine-König 		host->regs = host->base + host->devtype_data->regs_offset;
1834f48d0f9aSUwe Kleine-König 	host->spare0 = host->base + host->devtype_data->spare0_offset;
1835f48d0f9aSUwe Kleine-König 	if (host->devtype_data->axi_offset)
1836f48d0f9aSUwe Kleine-König 		host->regs_axi = host->base + host->devtype_data->axi_offset;
1837f48d0f9aSUwe Kleine-König 
1838f48d0f9aSUwe Kleine-König 	this->ecc.bytes = host->devtype_data->eccbytes;
1839f48d0f9aSUwe Kleine-König 	host->eccsize = host->devtype_data->eccsize;
1840f48d0f9aSUwe Kleine-König 
18417d6c37e9SBoris Brezillon 	this->legacy.select_chip = host->devtype_data->select_chip;
1842f48d0f9aSUwe Kleine-König 	this->ecc.size = 512;
1843a894cf6cSBoris Brezillon 	mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
1844f48d0f9aSUwe Kleine-König 
18456436356bSUwe Kleine-König 	if (host->pdata.hw_ecc) {
184613e1add1SSascha Hauer 		this->ecc.mode = NAND_ECC_HW;
184713e1add1SSascha Hauer 	} else {
184813e1add1SSascha Hauer 		this->ecc.mode = NAND_ECC_SOFT;
1849c1c7040eSRafał Miłecki 		this->ecc.algo = NAND_ECC_HAMMING;
185034f6e157SSascha Hauer 	}
185134f6e157SSascha Hauer 
18526436356bSUwe Kleine-König 	/* NAND bus width determines access functions used by upper layer */
18536436356bSUwe Kleine-König 	if (host->pdata.width == 2)
185434f6e157SSascha Hauer 		this->options |= NAND_BUSWIDTH_16;
185513e1add1SSascha Hauer 
1856f1372055SSascha Hauer 	/* update flash based bbt */
1857609468f9SBoris Brezillon 	if (host->pdata.flash_bbt)
1858bb9ebd4eSBrian Norris 		this->bbt_options |= NAND_BBT_USE_FLASH;
185934f6e157SSascha Hauer 
186063f1474cSSascha Hauer 	init_completion(&host->op_completion);
1861d4840180SIvo Clarysse 
1862d4840180SIvo Clarysse 	host->irq = platform_get_irq(pdev, 0);
186326fbf48bSFabio Estevam 	if (host->irq < 0)
186426fbf48bSFabio Estevam 		return host->irq;
1865d4840180SIvo Clarysse 
186663f1474cSSascha Hauer 	/*
1867e4303b25SUwe Kleine-König 	 * Use host->devtype_data->irq_control() here instead of irq_control()
1868e4303b25SUwe Kleine-König 	 * because we must not disable_irq_nosync without having requested the
1869e4303b25SUwe Kleine-König 	 * irq.
187063f1474cSSascha Hauer 	 */
1871e4303b25SUwe Kleine-König 	host->devtype_data->irq_control(host, 0);
187263f1474cSSascha Hauer 
1873e4a09cbfSSascha Hauer 	err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
1874b1eb234fSMichael Opdenacker 			0, DRIVER_NAME, host);
1875d4840180SIvo Clarysse 	if (err)
1876e4a09cbfSSascha Hauer 		return err;
1877e4a09cbfSSascha Hauer 
1878dcedf628SFabio Estevam 	err = clk_prepare_enable(host->clk);
1879dcedf628SFabio Estevam 	if (err)
1880dcedf628SFabio Estevam 		return err;
1881e4a09cbfSSascha Hauer 	host->clk_act = 1;
1882d4840180SIvo Clarysse 
188363f1474cSSascha Hauer 	/*
18848556958aSUwe Kleine-König 	 * Now that we "own" the interrupt make sure the interrupt mask bit is
18858556958aSUwe Kleine-König 	 * cleared on i.MX21. Otherwise we can't read the interrupt status bit
18868556958aSUwe Kleine-König 	 * on this machine.
188763f1474cSSascha Hauer 	 */
1888f48d0f9aSUwe Kleine-König 	if (host->devtype_data->irqpending_quirk) {
18898556958aSUwe Kleine-König 		disable_irq_nosync(host->irq);
1890e4303b25SUwe Kleine-König 		host->devtype_data->irq_control(host, 1);
18918556958aSUwe Kleine-König 	}
189263f1474cSSascha Hauer 
189396fa8e6eSMiquel Raynal 	/* Scan the NAND device */
1894*7b6a9b28SBoris Brezillon 	this->legacy.dummy_controller.ops = &mxcnd_controller_ops;
189500ad378fSBoris Brezillon 	err = nand_scan(this, is_imx25_nfc(host) ? 4 : 1);
1896bc83c788SMasahiro Yamada 	if (err)
18974a43faf5SSascha Hauer 		goto escan;
18984a43faf5SSascha Hauer 
189934f6e157SSascha Hauer 	/* Register the partitions */
1900be051bf2SMiquel Raynal 	err = mtd_device_parse_register(mtd, part_probes, NULL,
19016436356bSUwe Kleine-König 					host->pdata.parts,
19026436356bSUwe Kleine-König 					host->pdata.nr_parts);
1903be051bf2SMiquel Raynal 	if (err)
1904be051bf2SMiquel Raynal 		goto cleanup_nand;
190534f6e157SSascha Hauer 
190634f6e157SSascha Hauer 	platform_set_drvdata(pdev, host);
190734f6e157SSascha Hauer 
190834f6e157SSascha Hauer 	return 0;
190934f6e157SSascha Hauer 
1910be051bf2SMiquel Raynal cleanup_nand:
1911be051bf2SMiquel Raynal 	nand_cleanup(this);
191234f6e157SSascha Hauer escan:
1913c10d8ee3SLothar Waßmann 	if (host->clk_act)
1914e4a09cbfSSascha Hauer 		clk_disable_unprepare(host->clk);
191534f6e157SSascha Hauer 
191634f6e157SSascha Hauer 	return err;
191734f6e157SSascha Hauer }
191834f6e157SSascha Hauer 
1919810b7e06SBill Pemberton static int mxcnd_remove(struct platform_device *pdev)
192034f6e157SSascha Hauer {
192134f6e157SSascha Hauer 	struct mxc_nand_host *host = platform_get_drvdata(pdev);
192234f6e157SSascha Hauer 
192359ac276fSBoris Brezillon 	nand_release(&host->nand);
19248bfd4f7fSWei Yongjun 	if (host->clk_act)
19258bfd4f7fSWei Yongjun 		clk_disable_unprepare(host->clk);
192634f6e157SSascha Hauer 
192734f6e157SSascha Hauer 	return 0;
192834f6e157SSascha Hauer }
192934f6e157SSascha Hauer 
193034f6e157SSascha Hauer static struct platform_driver mxcnd_driver = {
193134f6e157SSascha Hauer 	.driver = {
193234f6e157SSascha Hauer 		   .name = DRIVER_NAME,
19336436356bSUwe Kleine-König 		   .of_match_table = of_match_ptr(mxcnd_dt_ids),
193434f6e157SSascha Hauer 	},
19354d62435fSShawn Guo 	.id_table = mxcnd_devtype,
1936ddf16d62SFabio Estevam 	.probe = mxcnd_probe,
19375153b88cSBill Pemberton 	.remove = mxcnd_remove,
193834f6e157SSascha Hauer };
1939ddf16d62SFabio Estevam module_platform_driver(mxcnd_driver);
194034f6e157SSascha Hauer 
194134f6e157SSascha Hauer MODULE_AUTHOR("Freescale Semiconductor, Inc.");
194234f6e157SSascha Hauer MODULE_DESCRIPTION("MXC NAND MTD driver");
194334f6e157SSascha Hauer MODULE_LICENSE("GPL");
1944