xref: /linux/drivers/mtd/nand/raw/mxc_nand.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1c786bbccSFabio Estevam // SPDX-License-Identifier: GPL-2.0+
293db446aSBoris Brezillon /*
393db446aSBoris Brezillon  * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
493db446aSBoris Brezillon  * Copyright 2008 Sascha Hauer, kernel@pengutronix.de
593db446aSBoris Brezillon  */
693db446aSBoris Brezillon 
793db446aSBoris Brezillon #include <linux/delay.h>
893db446aSBoris Brezillon #include <linux/slab.h>
993db446aSBoris Brezillon #include <linux/init.h>
1093db446aSBoris Brezillon #include <linux/module.h>
1193db446aSBoris Brezillon #include <linux/mtd/mtd.h>
1293db446aSBoris Brezillon #include <linux/mtd/rawnand.h>
1393db446aSBoris Brezillon #include <linux/mtd/partitions.h>
1493db446aSBoris Brezillon #include <linux/interrupt.h>
1593db446aSBoris Brezillon #include <linux/device.h>
1693db446aSBoris Brezillon #include <linux/platform_device.h>
1793db446aSBoris Brezillon #include <linux/clk.h>
1893db446aSBoris Brezillon #include <linux/err.h>
1993db446aSBoris Brezillon #include <linux/io.h>
2093db446aSBoris Brezillon #include <linux/irq.h>
2193db446aSBoris Brezillon #include <linux/completion.h>
2293db446aSBoris Brezillon #include <linux/of.h>
2394beaa25SSascha Hauer #include <linux/bitfield.h>
2493db446aSBoris Brezillon 
2593db446aSBoris Brezillon #define DRIVER_NAME "mxc_nand"
2693db446aSBoris Brezillon 
2793db446aSBoris Brezillon /* Addresses for NFC registers */
2893db446aSBoris Brezillon #define NFC_V1_V2_BUF_SIZE		(host->regs + 0x00)
2993db446aSBoris Brezillon #define NFC_V1_V2_BUF_ADDR		(host->regs + 0x04)
3093db446aSBoris Brezillon #define NFC_V1_V2_FLASH_ADDR		(host->regs + 0x06)
3193db446aSBoris Brezillon #define NFC_V1_V2_FLASH_CMD		(host->regs + 0x08)
3293db446aSBoris Brezillon #define NFC_V1_V2_CONFIG		(host->regs + 0x0a)
3393db446aSBoris Brezillon #define NFC_V1_V2_ECC_STATUS_RESULT	(host->regs + 0x0c)
3493db446aSBoris Brezillon #define NFC_V1_V2_RSLTMAIN_AREA		(host->regs + 0x0e)
353f77f244SMartin Kaiser #define NFC_V21_RSLTSPARE_AREA		(host->regs + 0x10)
3693db446aSBoris Brezillon #define NFC_V1_V2_WRPROT		(host->regs + 0x12)
3793db446aSBoris Brezillon #define NFC_V1_UNLOCKSTART_BLKADDR	(host->regs + 0x14)
3893db446aSBoris Brezillon #define NFC_V1_UNLOCKEND_BLKADDR	(host->regs + 0x16)
3993db446aSBoris Brezillon #define NFC_V21_UNLOCKSTART_BLKADDR0	(host->regs + 0x20)
4093db446aSBoris Brezillon #define NFC_V21_UNLOCKSTART_BLKADDR1	(host->regs + 0x24)
4193db446aSBoris Brezillon #define NFC_V21_UNLOCKSTART_BLKADDR2	(host->regs + 0x28)
4293db446aSBoris Brezillon #define NFC_V21_UNLOCKSTART_BLKADDR3	(host->regs + 0x2c)
4393db446aSBoris Brezillon #define NFC_V21_UNLOCKEND_BLKADDR0	(host->regs + 0x22)
4493db446aSBoris Brezillon #define NFC_V21_UNLOCKEND_BLKADDR1	(host->regs + 0x26)
4593db446aSBoris Brezillon #define NFC_V21_UNLOCKEND_BLKADDR2	(host->regs + 0x2a)
4693db446aSBoris Brezillon #define NFC_V21_UNLOCKEND_BLKADDR3	(host->regs + 0x2e)
4793db446aSBoris Brezillon #define NFC_V1_V2_NF_WRPRST		(host->regs + 0x18)
4893db446aSBoris Brezillon #define NFC_V1_V2_CONFIG1		(host->regs + 0x1a)
4993db446aSBoris Brezillon #define NFC_V1_V2_CONFIG2		(host->regs + 0x1c)
5093db446aSBoris Brezillon 
5194beaa25SSascha Hauer #define NFC_V1_V2_ECC_STATUS_RESULT_ERM GENMASK(3, 2)
5294beaa25SSascha Hauer 
5393db446aSBoris Brezillon #define NFC_V2_CONFIG1_ECC_MODE_4	(1 << 0)
5493db446aSBoris Brezillon #define NFC_V1_V2_CONFIG1_SP_EN		(1 << 2)
5593db446aSBoris Brezillon #define NFC_V1_V2_CONFIG1_ECC_EN	(1 << 3)
5693db446aSBoris Brezillon #define NFC_V1_V2_CONFIG1_INT_MSK	(1 << 4)
5793db446aSBoris Brezillon #define NFC_V1_V2_CONFIG1_BIG		(1 << 5)
5893db446aSBoris Brezillon #define NFC_V1_V2_CONFIG1_RST		(1 << 6)
5993db446aSBoris Brezillon #define NFC_V1_V2_CONFIG1_CE		(1 << 7)
6093db446aSBoris Brezillon #define NFC_V2_CONFIG1_ONE_CYCLE	(1 << 8)
6193db446aSBoris Brezillon #define NFC_V2_CONFIG1_PPB(x)		(((x) & 0x3) << 9)
6293db446aSBoris Brezillon #define NFC_V2_CONFIG1_FP_INT		(1 << 11)
6393db446aSBoris Brezillon 
6493db446aSBoris Brezillon #define NFC_V1_V2_CONFIG2_INT		(1 << 15)
6593db446aSBoris Brezillon 
6693db446aSBoris Brezillon /*
6793db446aSBoris Brezillon  * Operation modes for the NFC. Valid for v1, v2 and v3
6893db446aSBoris Brezillon  * type controllers.
6993db446aSBoris Brezillon  */
7093db446aSBoris Brezillon #define NFC_CMD				(1 << 0)
7193db446aSBoris Brezillon #define NFC_ADDR			(1 << 1)
7293db446aSBoris Brezillon #define NFC_INPUT			(1 << 2)
7393db446aSBoris Brezillon #define NFC_OUTPUT			(1 << 3)
7493db446aSBoris Brezillon #define NFC_ID				(1 << 4)
7593db446aSBoris Brezillon #define NFC_STATUS			(1 << 5)
7693db446aSBoris Brezillon 
7793db446aSBoris Brezillon #define NFC_V3_FLASH_CMD		(host->regs_axi + 0x00)
7893db446aSBoris Brezillon #define NFC_V3_FLASH_ADDR0		(host->regs_axi + 0x04)
7993db446aSBoris Brezillon 
8093db446aSBoris Brezillon #define NFC_V3_CONFIG1			(host->regs_axi + 0x34)
8193db446aSBoris Brezillon #define NFC_V3_CONFIG1_SP_EN		(1 << 0)
8293db446aSBoris Brezillon #define NFC_V3_CONFIG1_RBA(x)		(((x) & 0x7 ) << 4)
8393db446aSBoris Brezillon 
8493db446aSBoris Brezillon #define NFC_V3_ECC_STATUS_RESULT	(host->regs_axi + 0x38)
8593db446aSBoris Brezillon 
8693db446aSBoris Brezillon #define NFC_V3_LAUNCH			(host->regs_axi + 0x40)
8793db446aSBoris Brezillon 
8893db446aSBoris Brezillon #define NFC_V3_WRPROT			(host->regs_ip + 0x0)
8993db446aSBoris Brezillon #define NFC_V3_WRPROT_LOCK_TIGHT	(1 << 0)
9093db446aSBoris Brezillon #define NFC_V3_WRPROT_LOCK		(1 << 1)
9193db446aSBoris Brezillon #define NFC_V3_WRPROT_UNLOCK		(1 << 2)
9293db446aSBoris Brezillon #define NFC_V3_WRPROT_BLS_UNLOCK	(2 << 6)
9393db446aSBoris Brezillon 
9493db446aSBoris Brezillon #define NFC_V3_WRPROT_UNLOCK_BLK_ADD0   (host->regs_ip + 0x04)
9593db446aSBoris Brezillon 
9693db446aSBoris Brezillon #define NFC_V3_CONFIG2			(host->regs_ip + 0x24)
9793db446aSBoris Brezillon #define NFC_V3_CONFIG2_PS_512			(0 << 0)
9893db446aSBoris Brezillon #define NFC_V3_CONFIG2_PS_2048			(1 << 0)
9993db446aSBoris Brezillon #define NFC_V3_CONFIG2_PS_4096			(2 << 0)
10093db446aSBoris Brezillon #define NFC_V3_CONFIG2_ONE_CYCLE		(1 << 2)
10193db446aSBoris Brezillon #define NFC_V3_CONFIG2_ECC_EN			(1 << 3)
10293db446aSBoris Brezillon #define NFC_V3_CONFIG2_2CMD_PHASES		(1 << 4)
10393db446aSBoris Brezillon #define NFC_V3_CONFIG2_NUM_ADDR_PHASE0		(1 << 5)
10493db446aSBoris Brezillon #define NFC_V3_CONFIG2_ECC_MODE_8		(1 << 6)
10593db446aSBoris Brezillon #define NFC_V3_CONFIG2_PPB(x, shift)		(((x) & 0x3) << shift)
10693db446aSBoris Brezillon #define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x)	(((x) & 0x3) << 12)
10793db446aSBoris Brezillon #define NFC_V3_CONFIG2_INT_MSK			(1 << 15)
10893db446aSBoris Brezillon #define NFC_V3_CONFIG2_ST_CMD(x)		(((x) & 0xff) << 24)
10993db446aSBoris Brezillon #define NFC_V3_CONFIG2_SPAS(x)			(((x) & 0xff) << 16)
11093db446aSBoris Brezillon 
11193db446aSBoris Brezillon #define NFC_V3_CONFIG3				(host->regs_ip + 0x28)
11293db446aSBoris Brezillon #define NFC_V3_CONFIG3_ADD_OP(x)		(((x) & 0x3) << 0)
11393db446aSBoris Brezillon #define NFC_V3_CONFIG3_FW8			(1 << 3)
11493db446aSBoris Brezillon #define NFC_V3_CONFIG3_SBB(x)			(((x) & 0x7) << 8)
11593db446aSBoris Brezillon #define NFC_V3_CONFIG3_NUM_OF_DEVICES(x)	(((x) & 0x7) << 12)
11693db446aSBoris Brezillon #define NFC_V3_CONFIG3_RBB_MODE			(1 << 15)
11793db446aSBoris Brezillon #define NFC_V3_CONFIG3_NO_SDMA			(1 << 20)
11893db446aSBoris Brezillon 
11993db446aSBoris Brezillon #define NFC_V3_IPC			(host->regs_ip + 0x2C)
12093db446aSBoris Brezillon #define NFC_V3_IPC_CREQ			(1 << 0)
12193db446aSBoris Brezillon #define NFC_V3_IPC_INT			(1 << 31)
12293db446aSBoris Brezillon 
12393db446aSBoris Brezillon #define NFC_V3_DELAY_LINE		(host->regs_ip + 0x34)
12493db446aSBoris Brezillon 
12593db446aSBoris Brezillon struct mxc_nand_host;
12693db446aSBoris Brezillon 
12793db446aSBoris Brezillon struct mxc_nand_devtype_data {
12893db446aSBoris Brezillon 	void (*preset)(struct mtd_info *);
129d3dfbae6SSascha Hauer 	int (*read_page)(struct nand_chip *chip);
13093db446aSBoris Brezillon 	void (*send_cmd)(struct mxc_nand_host *, uint16_t, int);
13193db446aSBoris Brezillon 	void (*send_addr)(struct mxc_nand_host *, uint16_t, int);
13293db446aSBoris Brezillon 	void (*send_page)(struct mtd_info *, unsigned int);
13393db446aSBoris Brezillon 	void (*send_read_id)(struct mxc_nand_host *);
13493db446aSBoris Brezillon 	uint16_t (*get_dev_status)(struct mxc_nand_host *);
13593db446aSBoris Brezillon 	int (*check_int)(struct mxc_nand_host *);
13693db446aSBoris Brezillon 	void (*irq_control)(struct mxc_nand_host *, int);
13794beaa25SSascha Hauer 	u32 (*get_ecc_status)(struct nand_chip *);
13893db446aSBoris Brezillon 	const struct mtd_ooblayout_ops *ooblayout;
139758b56f5SBoris Brezillon 	void (*select_chip)(struct nand_chip *chip, int cs);
1404c46667bSMiquel Raynal 	int (*setup_interface)(struct nand_chip *chip, int csline,
1414c46667bSMiquel Raynal 			       const struct nand_interface_config *conf);
14293db446aSBoris Brezillon 	void (*enable_hwecc)(struct nand_chip *chip, bool enable);
14393db446aSBoris Brezillon 
14493db446aSBoris Brezillon 	/*
14593db446aSBoris Brezillon 	 * On i.MX21 the CONFIG2:INT bit cannot be read if interrupts are masked
14693db446aSBoris Brezillon 	 * (CONFIG1:INT_MSK is set). To handle this the driver uses
14793db446aSBoris Brezillon 	 * enable_irq/disable_irq_nosync instead of CONFIG1:INT_MSK
14893db446aSBoris Brezillon 	 */
14993db446aSBoris Brezillon 	int irqpending_quirk;
15093db446aSBoris Brezillon 	int needs_ip;
15193db446aSBoris Brezillon 
15293db446aSBoris Brezillon 	size_t regs_offset;
15393db446aSBoris Brezillon 	size_t spare0_offset;
15493db446aSBoris Brezillon 	size_t axi_offset;
15593db446aSBoris Brezillon 
15693db446aSBoris Brezillon 	int spare_len;
15793db446aSBoris Brezillon 	int eccbytes;
15893db446aSBoris Brezillon 	int eccsize;
15993db446aSBoris Brezillon 	int ppb_shift;
16093db446aSBoris Brezillon };
16193db446aSBoris Brezillon 
16293db446aSBoris Brezillon struct mxc_nand_host {
16393db446aSBoris Brezillon 	struct nand_chip	nand;
16493db446aSBoris Brezillon 	struct device		*dev;
16593db446aSBoris Brezillon 
16693db446aSBoris Brezillon 	void __iomem		*spare0;
16793db446aSBoris Brezillon 	void __iomem		*main_area0;
16893db446aSBoris Brezillon 
16993db446aSBoris Brezillon 	void __iomem		*base;
17093db446aSBoris Brezillon 	void __iomem		*regs;
17193db446aSBoris Brezillon 	void __iomem		*regs_axi;
17293db446aSBoris Brezillon 	void __iomem		*regs_ip;
17393db446aSBoris Brezillon 	int			status_request;
17493db446aSBoris Brezillon 	struct clk		*clk;
17593db446aSBoris Brezillon 	int			clk_act;
17693db446aSBoris Brezillon 	int			irq;
17793db446aSBoris Brezillon 	int			eccsize;
17893db446aSBoris Brezillon 	int			used_oobsize;
17993db446aSBoris Brezillon 	int			active_cs;
18094beaa25SSascha Hauer 	unsigned int		ecc_stats_v1;
18193db446aSBoris Brezillon 
18293db446aSBoris Brezillon 	struct completion	op_completion;
18393db446aSBoris Brezillon 
184d3dfbae6SSascha Hauer 	void			*data_buf;
18593db446aSBoris Brezillon 
18693db446aSBoris Brezillon 	const struct mxc_nand_devtype_data *devtype_data;
18793db446aSBoris Brezillon };
18893db446aSBoris Brezillon 
18993db446aSBoris Brezillon static const char * const part_probes[] = {
19093db446aSBoris Brezillon 	"cmdlinepart", "RedBoot", "ofpart", NULL };
19193db446aSBoris Brezillon 
memcpy32_fromio(void * trg,const void __iomem * src,size_t size)19293db446aSBoris Brezillon static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
19393db446aSBoris Brezillon {
19493db446aSBoris Brezillon 	int i;
19593db446aSBoris Brezillon 	u32 *t = trg;
19693db446aSBoris Brezillon 	const __iomem u32 *s = src;
19793db446aSBoris Brezillon 
19893db446aSBoris Brezillon 	for (i = 0; i < (size >> 2); i++)
19993db446aSBoris Brezillon 		*t++ = __raw_readl(s++);
20093db446aSBoris Brezillon }
20193db446aSBoris Brezillon 
memcpy16_fromio(void * trg,const void __iomem * src,size_t size)20293db446aSBoris Brezillon static void memcpy16_fromio(void *trg, const void __iomem  *src, size_t size)
20393db446aSBoris Brezillon {
20493db446aSBoris Brezillon 	int i;
20593db446aSBoris Brezillon 	u16 *t = trg;
20693db446aSBoris Brezillon 	const __iomem u16 *s = src;
20793db446aSBoris Brezillon 
20893db446aSBoris Brezillon 	/* We assume that src (IO) is always 32bit aligned */
20993db446aSBoris Brezillon 	if (PTR_ALIGN(trg, 4) == trg && IS_ALIGNED(size, 4)) {
21093db446aSBoris Brezillon 		memcpy32_fromio(trg, src, size);
21193db446aSBoris Brezillon 		return;
21293db446aSBoris Brezillon 	}
21393db446aSBoris Brezillon 
21493db446aSBoris Brezillon 	for (i = 0; i < (size >> 1); i++)
21593db446aSBoris Brezillon 		*t++ = __raw_readw(s++);
21693db446aSBoris Brezillon }
21793db446aSBoris Brezillon 
memcpy32_toio(void __iomem * trg,const void * src,int size)21893db446aSBoris Brezillon static inline void memcpy32_toio(void __iomem *trg, const void *src, int size)
21993db446aSBoris Brezillon {
22093db446aSBoris Brezillon 	/* __iowrite32_copy use 32bit size values so divide by 4 */
22193db446aSBoris Brezillon 	__iowrite32_copy(trg, src, size / 4);
22293db446aSBoris Brezillon }
22393db446aSBoris Brezillon 
memcpy16_toio(void __iomem * trg,const void * src,int size)22493db446aSBoris Brezillon static void memcpy16_toio(void __iomem *trg, const void *src, int size)
22593db446aSBoris Brezillon {
22693db446aSBoris Brezillon 	int i;
22793db446aSBoris Brezillon 	__iomem u16 *t = trg;
22893db446aSBoris Brezillon 	const u16 *s = src;
22993db446aSBoris Brezillon 
23093db446aSBoris Brezillon 	/* We assume that trg (IO) is always 32bit aligned */
23193db446aSBoris Brezillon 	if (PTR_ALIGN(src, 4) == src && IS_ALIGNED(size, 4)) {
23293db446aSBoris Brezillon 		memcpy32_toio(trg, src, size);
23393db446aSBoris Brezillon 		return;
23493db446aSBoris Brezillon 	}
23593db446aSBoris Brezillon 
23693db446aSBoris Brezillon 	for (i = 0; i < (size >> 1); i++)
23793db446aSBoris Brezillon 		__raw_writew(*s++, t++);
23893db446aSBoris Brezillon }
23993db446aSBoris Brezillon 
24093db446aSBoris Brezillon /*
24193db446aSBoris Brezillon  * The controller splits a page into data chunks of 512 bytes + partial oob.
24293db446aSBoris Brezillon  * There are writesize / 512 such chunks, the size of the partial oob parts is
24393db446aSBoris Brezillon  * oobsize / #chunks rounded down to a multiple of 2. The last oob chunk then
24493db446aSBoris Brezillon  * contains additionally the byte lost by rounding (if any).
24593db446aSBoris Brezillon  * This function handles the needed shuffling between host->data_buf (which
24693db446aSBoris Brezillon  * holds a page in natural order, i.e. writesize bytes data + oobsize bytes
24793db446aSBoris Brezillon  * spare) and the NFC buffer.
24893db446aSBoris Brezillon  */
copy_spare(struct mtd_info * mtd,bool bfrom,void * buf)24993db446aSBoris Brezillon static void copy_spare(struct mtd_info *mtd, bool bfrom, void *buf)
25093db446aSBoris Brezillon {
25193db446aSBoris Brezillon 	struct nand_chip *this = mtd_to_nand(mtd);
25293db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(this);
25393db446aSBoris Brezillon 	u16 i, oob_chunk_size;
25493db446aSBoris Brezillon 	u16 num_chunks = mtd->writesize / 512;
25593db446aSBoris Brezillon 
25693db446aSBoris Brezillon 	u8 *d = buf;
25793db446aSBoris Brezillon 	u8 __iomem *s = host->spare0;
25893db446aSBoris Brezillon 	u16 sparebuf_size = host->devtype_data->spare_len;
25993db446aSBoris Brezillon 
26093db446aSBoris Brezillon 	/* size of oob chunk for all but possibly the last one */
26193db446aSBoris Brezillon 	oob_chunk_size = (host->used_oobsize / num_chunks) & ~1;
26293db446aSBoris Brezillon 
26393db446aSBoris Brezillon 	if (bfrom) {
26493db446aSBoris Brezillon 		for (i = 0; i < num_chunks - 1; i++)
26593db446aSBoris Brezillon 			memcpy16_fromio(d + i * oob_chunk_size,
26693db446aSBoris Brezillon 					s + i * sparebuf_size,
26793db446aSBoris Brezillon 					oob_chunk_size);
26893db446aSBoris Brezillon 
26993db446aSBoris Brezillon 		/* the last chunk */
27093db446aSBoris Brezillon 		memcpy16_fromio(d + i * oob_chunk_size,
27193db446aSBoris Brezillon 				s + i * sparebuf_size,
27293db446aSBoris Brezillon 				host->used_oobsize - i * oob_chunk_size);
27393db446aSBoris Brezillon 	} else {
27493db446aSBoris Brezillon 		for (i = 0; i < num_chunks - 1; i++)
27593db446aSBoris Brezillon 			memcpy16_toio(&s[i * sparebuf_size],
27693db446aSBoris Brezillon 				      &d[i * oob_chunk_size],
27793db446aSBoris Brezillon 				      oob_chunk_size);
27893db446aSBoris Brezillon 
27993db446aSBoris Brezillon 		/* the last chunk */
28093db446aSBoris Brezillon 		memcpy16_toio(&s[i * sparebuf_size],
28193db446aSBoris Brezillon 			      &d[i * oob_chunk_size],
28293db446aSBoris Brezillon 			      host->used_oobsize - i * oob_chunk_size);
28393db446aSBoris Brezillon 	}
28493db446aSBoris Brezillon }
28593db446aSBoris Brezillon 
check_int_v3(struct mxc_nand_host * host)28693db446aSBoris Brezillon static int check_int_v3(struct mxc_nand_host *host)
28793db446aSBoris Brezillon {
28893db446aSBoris Brezillon 	uint32_t tmp;
28993db446aSBoris Brezillon 
29093db446aSBoris Brezillon 	tmp = readl(NFC_V3_IPC);
29193db446aSBoris Brezillon 	if (!(tmp & NFC_V3_IPC_INT))
29293db446aSBoris Brezillon 		return 0;
29393db446aSBoris Brezillon 
29493db446aSBoris Brezillon 	tmp &= ~NFC_V3_IPC_INT;
29593db446aSBoris Brezillon 	writel(tmp, NFC_V3_IPC);
29693db446aSBoris Brezillon 
29793db446aSBoris Brezillon 	return 1;
29893db446aSBoris Brezillon }
29993db446aSBoris Brezillon 
check_int_v1_v2(struct mxc_nand_host * host)30093db446aSBoris Brezillon static int check_int_v1_v2(struct mxc_nand_host *host)
30193db446aSBoris Brezillon {
30293db446aSBoris Brezillon 	uint32_t tmp;
30393db446aSBoris Brezillon 
30493db446aSBoris Brezillon 	tmp = readw(NFC_V1_V2_CONFIG2);
30593db446aSBoris Brezillon 	if (!(tmp & NFC_V1_V2_CONFIG2_INT))
30693db446aSBoris Brezillon 		return 0;
30793db446aSBoris Brezillon 
30893db446aSBoris Brezillon 	if (!host->devtype_data->irqpending_quirk)
30993db446aSBoris Brezillon 		writew(tmp & ~NFC_V1_V2_CONFIG2_INT, NFC_V1_V2_CONFIG2);
31093db446aSBoris Brezillon 
31193db446aSBoris Brezillon 	return 1;
31293db446aSBoris Brezillon }
31393db446aSBoris Brezillon 
irq_control_v1_v2(struct mxc_nand_host * host,int activate)31493db446aSBoris Brezillon static void irq_control_v1_v2(struct mxc_nand_host *host, int activate)
31593db446aSBoris Brezillon {
31693db446aSBoris Brezillon 	uint16_t tmp;
31793db446aSBoris Brezillon 
31893db446aSBoris Brezillon 	tmp = readw(NFC_V1_V2_CONFIG1);
31993db446aSBoris Brezillon 
32093db446aSBoris Brezillon 	if (activate)
32193db446aSBoris Brezillon 		tmp &= ~NFC_V1_V2_CONFIG1_INT_MSK;
32293db446aSBoris Brezillon 	else
32393db446aSBoris Brezillon 		tmp |= NFC_V1_V2_CONFIG1_INT_MSK;
32493db446aSBoris Brezillon 
32593db446aSBoris Brezillon 	writew(tmp, NFC_V1_V2_CONFIG1);
32693db446aSBoris Brezillon }
32793db446aSBoris Brezillon 
irq_control_v3(struct mxc_nand_host * host,int activate)32893db446aSBoris Brezillon static void irq_control_v3(struct mxc_nand_host *host, int activate)
32993db446aSBoris Brezillon {
33093db446aSBoris Brezillon 	uint32_t tmp;
33193db446aSBoris Brezillon 
33293db446aSBoris Brezillon 	tmp = readl(NFC_V3_CONFIG2);
33393db446aSBoris Brezillon 
33493db446aSBoris Brezillon 	if (activate)
33593db446aSBoris Brezillon 		tmp &= ~NFC_V3_CONFIG2_INT_MSK;
33693db446aSBoris Brezillon 	else
33793db446aSBoris Brezillon 		tmp |= NFC_V3_CONFIG2_INT_MSK;
33893db446aSBoris Brezillon 
33993db446aSBoris Brezillon 	writel(tmp, NFC_V3_CONFIG2);
34093db446aSBoris Brezillon }
34193db446aSBoris Brezillon 
irq_control(struct mxc_nand_host * host,int activate)34293db446aSBoris Brezillon static void irq_control(struct mxc_nand_host *host, int activate)
34393db446aSBoris Brezillon {
34493db446aSBoris Brezillon 	if (host->devtype_data->irqpending_quirk) {
34593db446aSBoris Brezillon 		if (activate)
34693db446aSBoris Brezillon 			enable_irq(host->irq);
34793db446aSBoris Brezillon 		else
34893db446aSBoris Brezillon 			disable_irq_nosync(host->irq);
34993db446aSBoris Brezillon 	} else {
35093db446aSBoris Brezillon 		host->devtype_data->irq_control(host, activate);
35193db446aSBoris Brezillon 	}
35293db446aSBoris Brezillon }
35393db446aSBoris Brezillon 
get_ecc_status_v1(struct nand_chip * chip)35494beaa25SSascha Hauer static u32 get_ecc_status_v1(struct nand_chip *chip)
35593db446aSBoris Brezillon {
35694beaa25SSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
35794beaa25SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
35894beaa25SSascha Hauer 	unsigned int ecc_stats, max_bitflips = 0;
35994beaa25SSascha Hauer 	int no_subpages, i;
36094beaa25SSascha Hauer 
36194beaa25SSascha Hauer 	no_subpages = mtd->writesize >> 9;
36294beaa25SSascha Hauer 
36394beaa25SSascha Hauer 	ecc_stats = host->ecc_stats_v1;
36494beaa25SSascha Hauer 
36594beaa25SSascha Hauer 	for (i = 0; i < no_subpages; i++) {
36694beaa25SSascha Hauer 		switch (ecc_stats & 0x3) {
36794beaa25SSascha Hauer 		case 0:
36894beaa25SSascha Hauer 		default:
36994beaa25SSascha Hauer 			break;
37094beaa25SSascha Hauer 		case 1:
37194beaa25SSascha Hauer 			mtd->ecc_stats.corrected++;
37294beaa25SSascha Hauer 			max_bitflips = 1;
37394beaa25SSascha Hauer 			break;
37494beaa25SSascha Hauer 		case 2:
37594beaa25SSascha Hauer 			mtd->ecc_stats.failed++;
37694beaa25SSascha Hauer 			break;
37793db446aSBoris Brezillon 		}
37893db446aSBoris Brezillon 
37994beaa25SSascha Hauer 		ecc_stats >>= 2;
38093db446aSBoris Brezillon 	}
38193db446aSBoris Brezillon 
38294beaa25SSascha Hauer 	return max_bitflips;
38394beaa25SSascha Hauer }
38494beaa25SSascha Hauer 
get_ecc_status_v2_v3(struct nand_chip * chip,unsigned int ecc_stat)38594beaa25SSascha Hauer static u32 get_ecc_status_v2_v3(struct nand_chip *chip, unsigned int ecc_stat)
38693db446aSBoris Brezillon {
38794beaa25SSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
38894beaa25SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
38994beaa25SSascha Hauer 	u8 ecc_bit_mask, err_limit;
39094beaa25SSascha Hauer 	unsigned int max_bitflips = 0;
39194beaa25SSascha Hauer 	int no_subpages, err;
39294beaa25SSascha Hauer 
39394beaa25SSascha Hauer 	ecc_bit_mask = (host->eccsize == 4) ? 0x7 : 0xf;
39494beaa25SSascha Hauer 	err_limit = (host->eccsize == 4) ? 0x4 : 0x8;
39594beaa25SSascha Hauer 
39694beaa25SSascha Hauer 	no_subpages = mtd->writesize >> 9;
39794beaa25SSascha Hauer 
39894beaa25SSascha Hauer 	do {
39994beaa25SSascha Hauer 		err = ecc_stat & ecc_bit_mask;
40094beaa25SSascha Hauer 		if (err > err_limit) {
40194beaa25SSascha Hauer 			mtd->ecc_stats.failed++;
40294beaa25SSascha Hauer 		} else {
40394beaa25SSascha Hauer 			mtd->ecc_stats.corrected += err;
40494beaa25SSascha Hauer 			max_bitflips = max_t(unsigned int, max_bitflips, err);
40594beaa25SSascha Hauer 		}
40694beaa25SSascha Hauer 
40794beaa25SSascha Hauer 		ecc_stat >>= 4;
40894beaa25SSascha Hauer 	} while (--no_subpages);
40994beaa25SSascha Hauer 
41094beaa25SSascha Hauer 	return max_bitflips;
41194beaa25SSascha Hauer }
41294beaa25SSascha Hauer 
get_ecc_status_v2(struct nand_chip * chip)41394beaa25SSascha Hauer static u32 get_ecc_status_v2(struct nand_chip *chip)
41494beaa25SSascha Hauer {
41594beaa25SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
41694beaa25SSascha Hauer 
41794beaa25SSascha Hauer 	u32 ecc_stat = readl(NFC_V1_V2_ECC_STATUS_RESULT);
41894beaa25SSascha Hauer 
41994beaa25SSascha Hauer 	return get_ecc_status_v2_v3(chip, ecc_stat);
42094beaa25SSascha Hauer }
42194beaa25SSascha Hauer 
get_ecc_status_v3(struct nand_chip * chip)42294beaa25SSascha Hauer static u32 get_ecc_status_v3(struct nand_chip *chip)
42394beaa25SSascha Hauer {
42494beaa25SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
42594beaa25SSascha Hauer 
42694beaa25SSascha Hauer 	u32 ecc_stat = readl(NFC_V3_ECC_STATUS_RESULT);
42794beaa25SSascha Hauer 
42894beaa25SSascha Hauer 	return get_ecc_status_v2_v3(chip, ecc_stat);
42993db446aSBoris Brezillon }
43093db446aSBoris Brezillon 
mxc_nfc_irq(int irq,void * dev_id)43193db446aSBoris Brezillon static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
43293db446aSBoris Brezillon {
43393db446aSBoris Brezillon 	struct mxc_nand_host *host = dev_id;
43493db446aSBoris Brezillon 
43593db446aSBoris Brezillon 	if (!host->devtype_data->check_int(host))
43693db446aSBoris Brezillon 		return IRQ_NONE;
43793db446aSBoris Brezillon 
43893db446aSBoris Brezillon 	irq_control(host, 0);
43993db446aSBoris Brezillon 
44093db446aSBoris Brezillon 	complete(&host->op_completion);
44193db446aSBoris Brezillon 
44293db446aSBoris Brezillon 	return IRQ_HANDLED;
44393db446aSBoris Brezillon }
44493db446aSBoris Brezillon 
44593db446aSBoris Brezillon /* This function polls the NANDFC to wait for the basic operation to
44693db446aSBoris Brezillon  * complete by checking the INT bit of config2 register.
44793db446aSBoris Brezillon  */
wait_op_done(struct mxc_nand_host * host,int useirq)44893db446aSBoris Brezillon static int wait_op_done(struct mxc_nand_host *host, int useirq)
44993db446aSBoris Brezillon {
45093db446aSBoris Brezillon 	int ret = 0;
45193db446aSBoris Brezillon 
45293db446aSBoris Brezillon 	/*
45393db446aSBoris Brezillon 	 * If operation is already complete, don't bother to setup an irq or a
45493db446aSBoris Brezillon 	 * loop.
45593db446aSBoris Brezillon 	 */
45693db446aSBoris Brezillon 	if (host->devtype_data->check_int(host))
45793db446aSBoris Brezillon 		return 0;
45893db446aSBoris Brezillon 
45993db446aSBoris Brezillon 	if (useirq) {
460*bf66d819SWolfram Sang 		unsigned long time_left;
46193db446aSBoris Brezillon 
46293db446aSBoris Brezillon 		reinit_completion(&host->op_completion);
46393db446aSBoris Brezillon 
46493db446aSBoris Brezillon 		irq_control(host, 1);
46593db446aSBoris Brezillon 
466*bf66d819SWolfram Sang 		time_left = wait_for_completion_timeout(&host->op_completion, HZ);
467*bf66d819SWolfram Sang 		if (!time_left && !host->devtype_data->check_int(host)) {
46893db446aSBoris Brezillon 			dev_dbg(host->dev, "timeout waiting for irq\n");
46993db446aSBoris Brezillon 			ret = -ETIMEDOUT;
47093db446aSBoris Brezillon 		}
47193db446aSBoris Brezillon 	} else {
47293db446aSBoris Brezillon 		int max_retries = 8000;
47393db446aSBoris Brezillon 		int done;
47493db446aSBoris Brezillon 
47593db446aSBoris Brezillon 		do {
47693db446aSBoris Brezillon 			udelay(1);
47793db446aSBoris Brezillon 
47893db446aSBoris Brezillon 			done = host->devtype_data->check_int(host);
47993db446aSBoris Brezillon 			if (done)
48093db446aSBoris Brezillon 				break;
48193db446aSBoris Brezillon 
48293db446aSBoris Brezillon 		} while (--max_retries);
48393db446aSBoris Brezillon 
48493db446aSBoris Brezillon 		if (!done) {
48593db446aSBoris Brezillon 			dev_dbg(host->dev, "timeout polling for completion\n");
48693db446aSBoris Brezillon 			ret = -ETIMEDOUT;
48793db446aSBoris Brezillon 		}
48893db446aSBoris Brezillon 	}
48993db446aSBoris Brezillon 
49093db446aSBoris Brezillon 	WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq);
49193db446aSBoris Brezillon 
49293db446aSBoris Brezillon 	return ret;
49393db446aSBoris Brezillon }
49493db446aSBoris Brezillon 
send_cmd_v3(struct mxc_nand_host * host,uint16_t cmd,int useirq)49593db446aSBoris Brezillon static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
49693db446aSBoris Brezillon {
49793db446aSBoris Brezillon 	/* fill command */
49893db446aSBoris Brezillon 	writel(cmd, NFC_V3_FLASH_CMD);
49993db446aSBoris Brezillon 
50093db446aSBoris Brezillon 	/* send out command */
50193db446aSBoris Brezillon 	writel(NFC_CMD, NFC_V3_LAUNCH);
50293db446aSBoris Brezillon 
50393db446aSBoris Brezillon 	/* Wait for operation to complete */
50493db446aSBoris Brezillon 	wait_op_done(host, useirq);
50593db446aSBoris Brezillon }
50693db446aSBoris Brezillon 
50793db446aSBoris Brezillon /* This function issues the specified command to the NAND device and
50893db446aSBoris Brezillon  * waits for completion. */
send_cmd_v1_v2(struct mxc_nand_host * host,uint16_t cmd,int useirq)50993db446aSBoris Brezillon static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq)
51093db446aSBoris Brezillon {
51193db446aSBoris Brezillon 	dev_dbg(host->dev, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
51293db446aSBoris Brezillon 
51393db446aSBoris Brezillon 	writew(cmd, NFC_V1_V2_FLASH_CMD);
51493db446aSBoris Brezillon 	writew(NFC_CMD, NFC_V1_V2_CONFIG2);
51593db446aSBoris Brezillon 
51693db446aSBoris Brezillon 	if (host->devtype_data->irqpending_quirk && (cmd == NAND_CMD_RESET)) {
51793db446aSBoris Brezillon 		int max_retries = 100;
51893db446aSBoris Brezillon 		/* Reset completion is indicated by NFC_CONFIG2 */
51993db446aSBoris Brezillon 		/* being set to 0 */
52093db446aSBoris Brezillon 		while (max_retries-- > 0) {
52193db446aSBoris Brezillon 			if (readw(NFC_V1_V2_CONFIG2) == 0) {
52293db446aSBoris Brezillon 				break;
52393db446aSBoris Brezillon 			}
52493db446aSBoris Brezillon 			udelay(1);
52593db446aSBoris Brezillon 		}
52693db446aSBoris Brezillon 		if (max_retries < 0)
52793db446aSBoris Brezillon 			dev_dbg(host->dev, "%s: RESET failed\n", __func__);
52893db446aSBoris Brezillon 	} else {
52993db446aSBoris Brezillon 		/* Wait for operation to complete */
53093db446aSBoris Brezillon 		wait_op_done(host, useirq);
53193db446aSBoris Brezillon 	}
53293db446aSBoris Brezillon }
53393db446aSBoris Brezillon 
send_addr_v3(struct mxc_nand_host * host,uint16_t addr,int islast)53493db446aSBoris Brezillon static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast)
53593db446aSBoris Brezillon {
53693db446aSBoris Brezillon 	/* fill address */
53793db446aSBoris Brezillon 	writel(addr, NFC_V3_FLASH_ADDR0);
53893db446aSBoris Brezillon 
53993db446aSBoris Brezillon 	/* send out address */
54093db446aSBoris Brezillon 	writel(NFC_ADDR, NFC_V3_LAUNCH);
54193db446aSBoris Brezillon 
54293db446aSBoris Brezillon 	wait_op_done(host, 0);
54393db446aSBoris Brezillon }
54493db446aSBoris Brezillon 
54593db446aSBoris Brezillon /* This function sends an address (or partial address) to the
54693db446aSBoris Brezillon  * NAND device. The address is used to select the source/destination for
54793db446aSBoris Brezillon  * a NAND command. */
send_addr_v1_v2(struct mxc_nand_host * host,uint16_t addr,int islast)54893db446aSBoris Brezillon static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast)
54993db446aSBoris Brezillon {
55093db446aSBoris Brezillon 	dev_dbg(host->dev, "send_addr(host, 0x%x %d)\n", addr, islast);
55193db446aSBoris Brezillon 
55293db446aSBoris Brezillon 	writew(addr, NFC_V1_V2_FLASH_ADDR);
55393db446aSBoris Brezillon 	writew(NFC_ADDR, NFC_V1_V2_CONFIG2);
55493db446aSBoris Brezillon 
55593db446aSBoris Brezillon 	/* Wait for operation to complete */
55693db446aSBoris Brezillon 	wait_op_done(host, islast);
55793db446aSBoris Brezillon }
55893db446aSBoris Brezillon 
send_page_v3(struct mtd_info * mtd,unsigned int ops)55993db446aSBoris Brezillon static void send_page_v3(struct mtd_info *mtd, unsigned int ops)
56093db446aSBoris Brezillon {
56193db446aSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
56293db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
56393db446aSBoris Brezillon 	uint32_t tmp;
56493db446aSBoris Brezillon 
56593db446aSBoris Brezillon 	tmp = readl(NFC_V3_CONFIG1);
56693db446aSBoris Brezillon 	tmp &= ~(7 << 4);
56793db446aSBoris Brezillon 	writel(tmp, NFC_V3_CONFIG1);
56893db446aSBoris Brezillon 
56993db446aSBoris Brezillon 	/* transfer data from NFC ram to nand */
57093db446aSBoris Brezillon 	writel(ops, NFC_V3_LAUNCH);
57193db446aSBoris Brezillon 
57293db446aSBoris Brezillon 	wait_op_done(host, false);
57393db446aSBoris Brezillon }
57493db446aSBoris Brezillon 
send_page_v2(struct mtd_info * mtd,unsigned int ops)57593db446aSBoris Brezillon static void send_page_v2(struct mtd_info *mtd, unsigned int ops)
57693db446aSBoris Brezillon {
57793db446aSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
57893db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
57993db446aSBoris Brezillon 
58093db446aSBoris Brezillon 	/* NANDFC buffer 0 is used for page read/write */
58193db446aSBoris Brezillon 	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
58293db446aSBoris Brezillon 
58393db446aSBoris Brezillon 	writew(ops, NFC_V1_V2_CONFIG2);
58493db446aSBoris Brezillon 
58593db446aSBoris Brezillon 	/* Wait for operation to complete */
58693db446aSBoris Brezillon 	wait_op_done(host, true);
58793db446aSBoris Brezillon }
58893db446aSBoris Brezillon 
send_page_v1(struct mtd_info * mtd,unsigned int ops)58993db446aSBoris Brezillon static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
59093db446aSBoris Brezillon {
59193db446aSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
59293db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
59393db446aSBoris Brezillon 	int bufs, i;
59493db446aSBoris Brezillon 
59593db446aSBoris Brezillon 	if (mtd->writesize > 512)
59693db446aSBoris Brezillon 		bufs = 4;
59793db446aSBoris Brezillon 	else
59893db446aSBoris Brezillon 		bufs = 1;
59993db446aSBoris Brezillon 
60093db446aSBoris Brezillon 	for (i = 0; i < bufs; i++) {
60193db446aSBoris Brezillon 
60293db446aSBoris Brezillon 		/* NANDFC buffer 0 is used for page read/write */
60393db446aSBoris Brezillon 		writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
60493db446aSBoris Brezillon 
60593db446aSBoris Brezillon 		writew(ops, NFC_V1_V2_CONFIG2);
60693db446aSBoris Brezillon 
60793db446aSBoris Brezillon 		/* Wait for operation to complete */
60893db446aSBoris Brezillon 		wait_op_done(host, true);
60993db446aSBoris Brezillon 	}
61093db446aSBoris Brezillon }
61193db446aSBoris Brezillon 
send_read_id_v3(struct mxc_nand_host * host)61293db446aSBoris Brezillon static void send_read_id_v3(struct mxc_nand_host *host)
61393db446aSBoris Brezillon {
61493db446aSBoris Brezillon 	/* Read ID into main buffer */
61593db446aSBoris Brezillon 	writel(NFC_ID, NFC_V3_LAUNCH);
61693db446aSBoris Brezillon 
61793db446aSBoris Brezillon 	wait_op_done(host, true);
61893db446aSBoris Brezillon 
61993db446aSBoris Brezillon 	memcpy32_fromio(host->data_buf, host->main_area0, 16);
62093db446aSBoris Brezillon }
62193db446aSBoris Brezillon 
62293db446aSBoris Brezillon /* Request the NANDFC to perform a read of the NAND device ID. */
send_read_id_v1_v2(struct mxc_nand_host * host)62393db446aSBoris Brezillon static void send_read_id_v1_v2(struct mxc_nand_host *host)
62493db446aSBoris Brezillon {
62593db446aSBoris Brezillon 	/* NANDFC buffer 0 is used for device ID output */
62693db446aSBoris Brezillon 	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
62793db446aSBoris Brezillon 
62893db446aSBoris Brezillon 	writew(NFC_ID, NFC_V1_V2_CONFIG2);
62993db446aSBoris Brezillon 
63093db446aSBoris Brezillon 	/* Wait for operation to complete */
63193db446aSBoris Brezillon 	wait_op_done(host, true);
63293db446aSBoris Brezillon 
63393db446aSBoris Brezillon 	memcpy32_fromio(host->data_buf, host->main_area0, 16);
63493db446aSBoris Brezillon }
63593db446aSBoris Brezillon 
get_dev_status_v3(struct mxc_nand_host * host)63693db446aSBoris Brezillon static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
63793db446aSBoris Brezillon {
63893db446aSBoris Brezillon 	writew(NFC_STATUS, NFC_V3_LAUNCH);
63993db446aSBoris Brezillon 	wait_op_done(host, true);
64093db446aSBoris Brezillon 
64193db446aSBoris Brezillon 	return readl(NFC_V3_CONFIG1) >> 16;
64293db446aSBoris Brezillon }
64393db446aSBoris Brezillon 
64493db446aSBoris Brezillon /* This function requests the NANDFC to perform a read of the
64593db446aSBoris Brezillon  * NAND device status and returns the current status. */
get_dev_status_v1_v2(struct mxc_nand_host * host)64693db446aSBoris Brezillon static uint16_t get_dev_status_v1_v2(struct mxc_nand_host *host)
64793db446aSBoris Brezillon {
64893db446aSBoris Brezillon 	void __iomem *main_buf = host->main_area0;
64993db446aSBoris Brezillon 	uint32_t store;
65093db446aSBoris Brezillon 	uint16_t ret;
65193db446aSBoris Brezillon 
65293db446aSBoris Brezillon 	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
65393db446aSBoris Brezillon 
65493db446aSBoris Brezillon 	/*
65593db446aSBoris Brezillon 	 * The device status is stored in main_area0. To
65693db446aSBoris Brezillon 	 * prevent corruption of the buffer save the value
65793db446aSBoris Brezillon 	 * and restore it afterwards.
65893db446aSBoris Brezillon 	 */
65993db446aSBoris Brezillon 	store = readl(main_buf);
66093db446aSBoris Brezillon 
66193db446aSBoris Brezillon 	writew(NFC_STATUS, NFC_V1_V2_CONFIG2);
66293db446aSBoris Brezillon 	wait_op_done(host, true);
66393db446aSBoris Brezillon 
66493db446aSBoris Brezillon 	ret = readw(main_buf);
66593db446aSBoris Brezillon 
66693db446aSBoris Brezillon 	writel(store, main_buf);
66793db446aSBoris Brezillon 
66893db446aSBoris Brezillon 	return ret;
66993db446aSBoris Brezillon }
67093db446aSBoris Brezillon 
mxc_nand_enable_hwecc_v1_v2(struct nand_chip * chip,bool enable)67193db446aSBoris Brezillon static void mxc_nand_enable_hwecc_v1_v2(struct nand_chip *chip, bool enable)
67293db446aSBoris Brezillon {
67393db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
67493db446aSBoris Brezillon 	uint16_t config1;
67593db446aSBoris Brezillon 
676bace41f8SMiquel Raynal 	if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
67793db446aSBoris Brezillon 		return;
67893db446aSBoris Brezillon 
67993db446aSBoris Brezillon 	config1 = readw(NFC_V1_V2_CONFIG1);
68093db446aSBoris Brezillon 
68193db446aSBoris Brezillon 	if (enable)
68293db446aSBoris Brezillon 		config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
68393db446aSBoris Brezillon 	else
68493db446aSBoris Brezillon 		config1 &= ~NFC_V1_V2_CONFIG1_ECC_EN;
68593db446aSBoris Brezillon 
68693db446aSBoris Brezillon 	writew(config1, NFC_V1_V2_CONFIG1);
68793db446aSBoris Brezillon }
68893db446aSBoris Brezillon 
mxc_nand_enable_hwecc_v3(struct nand_chip * chip,bool enable)68993db446aSBoris Brezillon static void mxc_nand_enable_hwecc_v3(struct nand_chip *chip, bool enable)
69093db446aSBoris Brezillon {
69193db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
69293db446aSBoris Brezillon 	uint32_t config2;
69393db446aSBoris Brezillon 
694bace41f8SMiquel Raynal 	if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
69593db446aSBoris Brezillon 		return;
69693db446aSBoris Brezillon 
69793db446aSBoris Brezillon 	config2 = readl(NFC_V3_CONFIG2);
69893db446aSBoris Brezillon 
69993db446aSBoris Brezillon 	if (enable)
70093db446aSBoris Brezillon 		config2 |= NFC_V3_CONFIG2_ECC_EN;
70193db446aSBoris Brezillon 	else
70293db446aSBoris Brezillon 		config2 &= ~NFC_V3_CONFIG2_ECC_EN;
70393db446aSBoris Brezillon 
70493db446aSBoris Brezillon 	writel(config2, NFC_V3_CONFIG2);
70593db446aSBoris Brezillon }
70693db446aSBoris Brezillon 
mxc_nand_read_page_v1(struct nand_chip * chip)707d3dfbae6SSascha Hauer static int mxc_nand_read_page_v1(struct nand_chip *chip)
70893db446aSBoris Brezillon {
70993db446aSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
71093db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
71193db446aSBoris Brezillon 	int no_subpages;
71293db446aSBoris Brezillon 	int i;
71394beaa25SSascha Hauer 	unsigned int ecc_stats = 0;
71493db446aSBoris Brezillon 
715d3dfbae6SSascha Hauer 	if (mtd->writesize)
71693db446aSBoris Brezillon 		no_subpages = mtd->writesize >> 9;
717d3dfbae6SSascha Hauer 	else
718d3dfbae6SSascha Hauer 		/* READ PARAMETER PAGE is called when mtd->writesize is not yet set */
719d3dfbae6SSascha Hauer 		no_subpages = 1;
72093db446aSBoris Brezillon 
72193db446aSBoris Brezillon 	for (i = 0; i < no_subpages; i++) {
72293db446aSBoris Brezillon 		/* NANDFC buffer 0 is used for page read/write */
72393db446aSBoris Brezillon 		writew((host->active_cs << 4) | i, NFC_V1_V2_BUF_ADDR);
72493db446aSBoris Brezillon 
72593db446aSBoris Brezillon 		writew(NFC_OUTPUT, NFC_V1_V2_CONFIG2);
72693db446aSBoris Brezillon 
72793db446aSBoris Brezillon 		/* Wait for operation to complete */
72893db446aSBoris Brezillon 		wait_op_done(host, true);
72993db446aSBoris Brezillon 
73094beaa25SSascha Hauer 		ecc_stats |= FIELD_GET(NFC_V1_V2_ECC_STATUS_RESULT_ERM,
73194beaa25SSascha Hauer 				       readw(NFC_V1_V2_ECC_STATUS_RESULT)) << i * 2;
73294beaa25SSascha Hauer 	}
73393db446aSBoris Brezillon 
73494beaa25SSascha Hauer 	host->ecc_stats_v1 = ecc_stats;
73593db446aSBoris Brezillon 
73694beaa25SSascha Hauer 	return 0;
73793db446aSBoris Brezillon }
73893db446aSBoris Brezillon 
mxc_nand_read_page_v2_v3(struct nand_chip * chip)739d3dfbae6SSascha Hauer static int mxc_nand_read_page_v2_v3(struct nand_chip *chip)
74093db446aSBoris Brezillon {
74193db446aSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
74293db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
74393db446aSBoris Brezillon 
74493db446aSBoris Brezillon 	host->devtype_data->send_page(mtd, NFC_OUTPUT);
74593db446aSBoris Brezillon 
74694beaa25SSascha Hauer 	return 0;
74793db446aSBoris Brezillon }
74893db446aSBoris Brezillon 
mxc_nand_read_page(struct nand_chip * chip,uint8_t * buf,int oob_required,int page)749b9761687SBoris Brezillon static int mxc_nand_read_page(struct nand_chip *chip, uint8_t *buf,
750b9761687SBoris Brezillon 			      int oob_required, int page)
75193db446aSBoris Brezillon {
752d3dfbae6SSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
75393db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
75494beaa25SSascha Hauer 	int ret;
75593db446aSBoris Brezillon 
756d3dfbae6SSascha Hauer 	host->devtype_data->enable_hwecc(chip, true);
75793db446aSBoris Brezillon 
758d3dfbae6SSascha Hauer 	ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize);
759d3dfbae6SSascha Hauer 
760d3dfbae6SSascha Hauer 	host->devtype_data->enable_hwecc(chip, false);
761d3dfbae6SSascha Hauer 
76294beaa25SSascha Hauer 	if (ret)
76394beaa25SSascha Hauer 		return ret;
76494beaa25SSascha Hauer 
765d3dfbae6SSascha Hauer 	if (oob_required)
766d3dfbae6SSascha Hauer 		copy_spare(mtd, true, chip->oob_poi);
767d3dfbae6SSascha Hauer 
76894beaa25SSascha Hauer 	return host->devtype_data->get_ecc_status(chip);
76993db446aSBoris Brezillon }
77093db446aSBoris Brezillon 
mxc_nand_read_page_raw(struct nand_chip * chip,uint8_t * buf,int oob_required,int page)771b9761687SBoris Brezillon static int mxc_nand_read_page_raw(struct nand_chip *chip, uint8_t *buf,
772b9761687SBoris Brezillon 				  int oob_required, int page)
77393db446aSBoris Brezillon {
774d3dfbae6SSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
775d3dfbae6SSascha Hauer 	int ret;
776d3dfbae6SSascha Hauer 
777d3dfbae6SSascha Hauer 	ret = nand_read_page_op(chip, page, 0, buf, mtd->writesize);
778d3dfbae6SSascha Hauer 	if (ret)
779d3dfbae6SSascha Hauer 		return ret;
78093db446aSBoris Brezillon 
78193db446aSBoris Brezillon 	if (oob_required)
782d3dfbae6SSascha Hauer 		copy_spare(mtd, true, chip->oob_poi);
78393db446aSBoris Brezillon 
784d3dfbae6SSascha Hauer 	return 0;
78593db446aSBoris Brezillon }
78693db446aSBoris Brezillon 
mxc_nand_read_oob(struct nand_chip * chip,int page)787b9761687SBoris Brezillon static int mxc_nand_read_oob(struct nand_chip *chip, int page)
78893db446aSBoris Brezillon {
78993db446aSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
79093db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
791d3dfbae6SSascha Hauer 	int ret;
79293db446aSBoris Brezillon 
793d3dfbae6SSascha Hauer 	ret = nand_read_page_op(chip, page, 0, host->data_buf, mtd->writesize);
794d3dfbae6SSascha Hauer 	if (ret)
795d3dfbae6SSascha Hauer 		return ret;
79693db446aSBoris Brezillon 
797d3dfbae6SSascha Hauer 	copy_spare(mtd, true, chip->oob_poi);
79893db446aSBoris Brezillon 
79993db446aSBoris Brezillon 	return 0;
80093db446aSBoris Brezillon }
80193db446aSBoris Brezillon 
mxc_nand_write_page_ecc(struct nand_chip * chip,const uint8_t * buf,int oob_required,int page)802767eb6fbSBoris Brezillon static int mxc_nand_write_page_ecc(struct nand_chip *chip, const uint8_t *buf,
803767eb6fbSBoris Brezillon 				   int oob_required, int page)
80493db446aSBoris Brezillon {
805d3dfbae6SSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
806d3dfbae6SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
807d3dfbae6SSascha Hauer 	int ret;
808d3dfbae6SSascha Hauer 
809d3dfbae6SSascha Hauer 	copy_spare(mtd, false, chip->oob_poi);
810d3dfbae6SSascha Hauer 
811d3dfbae6SSascha Hauer 	host->devtype_data->enable_hwecc(chip, true);
812d3dfbae6SSascha Hauer 
813d3dfbae6SSascha Hauer 	ret = nand_prog_page_op(chip, page, 0, buf, mtd->writesize);
814d3dfbae6SSascha Hauer 
815d3dfbae6SSascha Hauer 	host->devtype_data->enable_hwecc(chip, false);
816d3dfbae6SSascha Hauer 
817d3dfbae6SSascha Hauer 	return ret;
81893db446aSBoris Brezillon }
81993db446aSBoris Brezillon 
mxc_nand_write_page_raw(struct nand_chip * chip,const uint8_t * buf,int oob_required,int page)820767eb6fbSBoris Brezillon static int mxc_nand_write_page_raw(struct nand_chip *chip, const uint8_t *buf,
821767eb6fbSBoris Brezillon 				   int oob_required, int page)
82293db446aSBoris Brezillon {
823d3dfbae6SSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
824d3dfbae6SSascha Hauer 
825d3dfbae6SSascha Hauer 	copy_spare(mtd, false, chip->oob_poi);
826d3dfbae6SSascha Hauer 
827d3dfbae6SSascha Hauer 	return nand_prog_page_op(chip, page, 0, buf, mtd->writesize);
82893db446aSBoris Brezillon }
82993db446aSBoris Brezillon 
mxc_nand_write_oob(struct nand_chip * chip,int page)830767eb6fbSBoris Brezillon static int mxc_nand_write_oob(struct nand_chip *chip, int page)
83193db446aSBoris Brezillon {
832767eb6fbSBoris Brezillon 	struct mtd_info *mtd = nand_to_mtd(chip);
83393db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
83493db446aSBoris Brezillon 
83593db446aSBoris Brezillon 	memset(host->data_buf, 0xff, mtd->writesize);
836d3dfbae6SSascha Hauer 	copy_spare(mtd, false, chip->oob_poi);
83793db446aSBoris Brezillon 
838d3dfbae6SSascha Hauer 	return nand_prog_page_op(chip, page, 0, host->data_buf, mtd->writesize);
83993db446aSBoris Brezillon }
84093db446aSBoris Brezillon 
84193db446aSBoris Brezillon /* This function is used by upper layer for select and
84293db446aSBoris Brezillon  * deselect of the NAND chip */
mxc_nand_select_chip_v1_v3(struct nand_chip * nand_chip,int chip)843758b56f5SBoris Brezillon static void mxc_nand_select_chip_v1_v3(struct nand_chip *nand_chip, int chip)
84493db446aSBoris Brezillon {
84593db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
84693db446aSBoris Brezillon 
84793db446aSBoris Brezillon 	if (chip == -1) {
84893db446aSBoris Brezillon 		/* Disable the NFC clock */
84993db446aSBoris Brezillon 		if (host->clk_act) {
85093db446aSBoris Brezillon 			clk_disable_unprepare(host->clk);
85193db446aSBoris Brezillon 			host->clk_act = 0;
85293db446aSBoris Brezillon 		}
85393db446aSBoris Brezillon 		return;
85493db446aSBoris Brezillon 	}
85593db446aSBoris Brezillon 
85693db446aSBoris Brezillon 	if (!host->clk_act) {
85793db446aSBoris Brezillon 		/* Enable the NFC clock */
85893db446aSBoris Brezillon 		clk_prepare_enable(host->clk);
85993db446aSBoris Brezillon 		host->clk_act = 1;
86093db446aSBoris Brezillon 	}
86193db446aSBoris Brezillon }
86293db446aSBoris Brezillon 
mxc_nand_select_chip_v2(struct nand_chip * nand_chip,int chip)863758b56f5SBoris Brezillon static void mxc_nand_select_chip_v2(struct nand_chip *nand_chip, int chip)
86493db446aSBoris Brezillon {
86593db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
86693db446aSBoris Brezillon 
86793db446aSBoris Brezillon 	if (chip == -1) {
86893db446aSBoris Brezillon 		/* Disable the NFC clock */
86993db446aSBoris Brezillon 		if (host->clk_act) {
87093db446aSBoris Brezillon 			clk_disable_unprepare(host->clk);
87193db446aSBoris Brezillon 			host->clk_act = 0;
87293db446aSBoris Brezillon 		}
87393db446aSBoris Brezillon 		return;
87493db446aSBoris Brezillon 	}
87593db446aSBoris Brezillon 
87693db446aSBoris Brezillon 	if (!host->clk_act) {
87793db446aSBoris Brezillon 		/* Enable the NFC clock */
87893db446aSBoris Brezillon 		clk_prepare_enable(host->clk);
87993db446aSBoris Brezillon 		host->clk_act = 1;
88093db446aSBoris Brezillon 	}
88193db446aSBoris Brezillon 
88293db446aSBoris Brezillon 	host->active_cs = chip;
88393db446aSBoris Brezillon 	writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
88493db446aSBoris Brezillon }
88593db446aSBoris Brezillon 
88693db446aSBoris Brezillon #define MXC_V1_ECCBYTES		5
88793db446aSBoris Brezillon 
mxc_v1_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)88893db446aSBoris Brezillon static int mxc_v1_ooblayout_ecc(struct mtd_info *mtd, int section,
88993db446aSBoris Brezillon 				struct mtd_oob_region *oobregion)
89093db446aSBoris Brezillon {
89193db446aSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
89293db446aSBoris Brezillon 
89393db446aSBoris Brezillon 	if (section >= nand_chip->ecc.steps)
89493db446aSBoris Brezillon 		return -ERANGE;
89593db446aSBoris Brezillon 
89693db446aSBoris Brezillon 	oobregion->offset = (section * 16) + 6;
89793db446aSBoris Brezillon 	oobregion->length = MXC_V1_ECCBYTES;
89893db446aSBoris Brezillon 
89993db446aSBoris Brezillon 	return 0;
90093db446aSBoris Brezillon }
90193db446aSBoris Brezillon 
mxc_v1_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)90293db446aSBoris Brezillon static int mxc_v1_ooblayout_free(struct mtd_info *mtd, int section,
90393db446aSBoris Brezillon 				 struct mtd_oob_region *oobregion)
90493db446aSBoris Brezillon {
90593db446aSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
90693db446aSBoris Brezillon 
90793db446aSBoris Brezillon 	if (section > nand_chip->ecc.steps)
90893db446aSBoris Brezillon 		return -ERANGE;
90993db446aSBoris Brezillon 
91093db446aSBoris Brezillon 	if (!section) {
91193db446aSBoris Brezillon 		if (mtd->writesize <= 512) {
91293db446aSBoris Brezillon 			oobregion->offset = 0;
91393db446aSBoris Brezillon 			oobregion->length = 5;
91493db446aSBoris Brezillon 		} else {
91593db446aSBoris Brezillon 			oobregion->offset = 2;
91693db446aSBoris Brezillon 			oobregion->length = 4;
91793db446aSBoris Brezillon 		}
91893db446aSBoris Brezillon 	} else {
91993db446aSBoris Brezillon 		oobregion->offset = ((section - 1) * 16) + MXC_V1_ECCBYTES + 6;
92093db446aSBoris Brezillon 		if (section < nand_chip->ecc.steps)
92193db446aSBoris Brezillon 			oobregion->length = (section * 16) + 6 -
92293db446aSBoris Brezillon 					    oobregion->offset;
92393db446aSBoris Brezillon 		else
92493db446aSBoris Brezillon 			oobregion->length = mtd->oobsize - oobregion->offset;
92593db446aSBoris Brezillon 	}
92693db446aSBoris Brezillon 
92793db446aSBoris Brezillon 	return 0;
92893db446aSBoris Brezillon }
92993db446aSBoris Brezillon 
93093db446aSBoris Brezillon static const struct mtd_ooblayout_ops mxc_v1_ooblayout_ops = {
93193db446aSBoris Brezillon 	.ecc = mxc_v1_ooblayout_ecc,
93293db446aSBoris Brezillon 	.free = mxc_v1_ooblayout_free,
93393db446aSBoris Brezillon };
93493db446aSBoris Brezillon 
mxc_v2_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)93593db446aSBoris Brezillon static int mxc_v2_ooblayout_ecc(struct mtd_info *mtd, int section,
93693db446aSBoris Brezillon 				struct mtd_oob_region *oobregion)
93793db446aSBoris Brezillon {
93893db446aSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
93993db446aSBoris Brezillon 	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
94093db446aSBoris Brezillon 
94193db446aSBoris Brezillon 	if (section >= nand_chip->ecc.steps)
94293db446aSBoris Brezillon 		return -ERANGE;
94393db446aSBoris Brezillon 
94493db446aSBoris Brezillon 	oobregion->offset = (section * stepsize) + 7;
94593db446aSBoris Brezillon 	oobregion->length = nand_chip->ecc.bytes;
94693db446aSBoris Brezillon 
94793db446aSBoris Brezillon 	return 0;
94893db446aSBoris Brezillon }
94993db446aSBoris Brezillon 
mxc_v2_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * oobregion)95093db446aSBoris Brezillon static int mxc_v2_ooblayout_free(struct mtd_info *mtd, int section,
95193db446aSBoris Brezillon 				 struct mtd_oob_region *oobregion)
95293db446aSBoris Brezillon {
95393db446aSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
95493db446aSBoris Brezillon 	int stepsize = nand_chip->ecc.bytes == 9 ? 16 : 26;
95593db446aSBoris Brezillon 
95693db446aSBoris Brezillon 	if (section >= nand_chip->ecc.steps)
95793db446aSBoris Brezillon 		return -ERANGE;
95893db446aSBoris Brezillon 
95993db446aSBoris Brezillon 	if (!section) {
96093db446aSBoris Brezillon 		if (mtd->writesize <= 512) {
96193db446aSBoris Brezillon 			oobregion->offset = 0;
96293db446aSBoris Brezillon 			oobregion->length = 5;
96393db446aSBoris Brezillon 		} else {
96493db446aSBoris Brezillon 			oobregion->offset = 2;
96593db446aSBoris Brezillon 			oobregion->length = 4;
96693db446aSBoris Brezillon 		}
96793db446aSBoris Brezillon 	} else {
96893db446aSBoris Brezillon 		oobregion->offset = section * stepsize;
96993db446aSBoris Brezillon 		oobregion->length = 7;
97093db446aSBoris Brezillon 	}
97193db446aSBoris Brezillon 
97293db446aSBoris Brezillon 	return 0;
97393db446aSBoris Brezillon }
97493db446aSBoris Brezillon 
97593db446aSBoris Brezillon static const struct mtd_ooblayout_ops mxc_v2_ooblayout_ops = {
97693db446aSBoris Brezillon 	.ecc = mxc_v2_ooblayout_ecc,
97793db446aSBoris Brezillon 	.free = mxc_v2_ooblayout_free,
97893db446aSBoris Brezillon };
97993db446aSBoris Brezillon 
98093db446aSBoris Brezillon /*
98193db446aSBoris Brezillon  * v2 and v3 type controllers can do 4bit or 8bit ecc depending
98293db446aSBoris Brezillon  * on how much oob the nand chip has. For 8bit ecc we need at least
98393db446aSBoris Brezillon  * 26 bytes of oob data per 512 byte block.
98493db446aSBoris Brezillon  */
get_eccsize(struct mtd_info * mtd)98593db446aSBoris Brezillon static int get_eccsize(struct mtd_info *mtd)
98693db446aSBoris Brezillon {
98793db446aSBoris Brezillon 	int oobbytes_per_512 = 0;
98893db446aSBoris Brezillon 
98993db446aSBoris Brezillon 	oobbytes_per_512 = mtd->oobsize * 512 / mtd->writesize;
99093db446aSBoris Brezillon 
99193db446aSBoris Brezillon 	if (oobbytes_per_512 < 26)
99293db446aSBoris Brezillon 		return 4;
99393db446aSBoris Brezillon 	else
99493db446aSBoris Brezillon 		return 8;
99593db446aSBoris Brezillon }
99693db446aSBoris Brezillon 
preset_v1(struct mtd_info * mtd)99793db446aSBoris Brezillon static void preset_v1(struct mtd_info *mtd)
99893db446aSBoris Brezillon {
99993db446aSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
100093db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
100193db446aSBoris Brezillon 	uint16_t config1 = 0;
100293db446aSBoris Brezillon 
1003bace41f8SMiquel Raynal 	if (nand_chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST &&
1004bace41f8SMiquel Raynal 	    mtd->writesize)
100593db446aSBoris Brezillon 		config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
100693db446aSBoris Brezillon 
100793db446aSBoris Brezillon 	if (!host->devtype_data->irqpending_quirk)
100893db446aSBoris Brezillon 		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
100993db446aSBoris Brezillon 
101093db446aSBoris Brezillon 	host->eccsize = 1;
101193db446aSBoris Brezillon 
101293db446aSBoris Brezillon 	writew(config1, NFC_V1_V2_CONFIG1);
101393db446aSBoris Brezillon 	/* preset operation */
101493db446aSBoris Brezillon 
101593db446aSBoris Brezillon 	/* Unlock the internal RAM Buffer */
101693db446aSBoris Brezillon 	writew(0x2, NFC_V1_V2_CONFIG);
101793db446aSBoris Brezillon 
101893db446aSBoris Brezillon 	/* Blocks to be unlocked */
101993db446aSBoris Brezillon 	writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR);
102093db446aSBoris Brezillon 	writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR);
102193db446aSBoris Brezillon 
102293db446aSBoris Brezillon 	/* Unlock Block Command for given address range */
102393db446aSBoris Brezillon 	writew(0x4, NFC_V1_V2_WRPROT);
102493db446aSBoris Brezillon }
102593db446aSBoris Brezillon 
mxc_nand_v2_setup_interface(struct nand_chip * chip,int csline,const struct nand_interface_config * conf)10264c46667bSMiquel Raynal static int mxc_nand_v2_setup_interface(struct nand_chip *chip, int csline,
10274c46667bSMiquel Raynal 				       const struct nand_interface_config *conf)
102893db446aSBoris Brezillon {
1029858838b8SBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
103093db446aSBoris Brezillon 	int tRC_min_ns, tRC_ps, ret;
103193db446aSBoris Brezillon 	unsigned long rate, rate_round;
103293db446aSBoris Brezillon 	const struct nand_sdr_timings *timings;
103393db446aSBoris Brezillon 	u16 config1;
103493db446aSBoris Brezillon 
103593db446aSBoris Brezillon 	timings = nand_get_sdr_timings(conf);
103693db446aSBoris Brezillon 	if (IS_ERR(timings))
103793db446aSBoris Brezillon 		return -ENOTSUPP;
103893db446aSBoris Brezillon 
103993db446aSBoris Brezillon 	config1 = readw(NFC_V1_V2_CONFIG1);
104093db446aSBoris Brezillon 
104193db446aSBoris Brezillon 	tRC_min_ns = timings->tRC_min / 1000;
104293db446aSBoris Brezillon 	rate = 1000000000 / tRC_min_ns;
104393db446aSBoris Brezillon 
104493db446aSBoris Brezillon 	/*
104593db446aSBoris Brezillon 	 * For tRC < 30ns we have to use EDO mode. In this case the controller
104693db446aSBoris Brezillon 	 * does one access per clock cycle. Otherwise the controller does one
104793db446aSBoris Brezillon 	 * access in two clock cycles, thus we have to double the rate to the
104893db446aSBoris Brezillon 	 * controller.
104993db446aSBoris Brezillon 	 */
105093db446aSBoris Brezillon 	if (tRC_min_ns < 30) {
105193db446aSBoris Brezillon 		rate_round = clk_round_rate(host->clk, rate);
105293db446aSBoris Brezillon 		config1 |= NFC_V2_CONFIG1_ONE_CYCLE;
105393db446aSBoris Brezillon 		tRC_ps = 1000000000 / (rate_round / 1000);
105493db446aSBoris Brezillon 	} else {
105593db446aSBoris Brezillon 		rate *= 2;
105693db446aSBoris Brezillon 		rate_round = clk_round_rate(host->clk, rate);
105793db446aSBoris Brezillon 		config1 &= ~NFC_V2_CONFIG1_ONE_CYCLE;
105893db446aSBoris Brezillon 		tRC_ps = 1000000000 / (rate_round / 1000 / 2);
105993db446aSBoris Brezillon 	}
106093db446aSBoris Brezillon 
106193db446aSBoris Brezillon 	/*
106293db446aSBoris Brezillon 	 * The timing values compared against are from the i.MX25 Automotive
106393db446aSBoris Brezillon 	 * datasheet, Table 50. NFC Timing Parameters
106493db446aSBoris Brezillon 	 */
106593db446aSBoris Brezillon 	if (timings->tCLS_min > tRC_ps - 1000 ||
106693db446aSBoris Brezillon 	    timings->tCLH_min > tRC_ps - 2000 ||
106793db446aSBoris Brezillon 	    timings->tCS_min > tRC_ps - 1000 ||
106893db446aSBoris Brezillon 	    timings->tCH_min > tRC_ps - 2000 ||
106993db446aSBoris Brezillon 	    timings->tWP_min > tRC_ps - 1500 ||
107093db446aSBoris Brezillon 	    timings->tALS_min > tRC_ps ||
107193db446aSBoris Brezillon 	    timings->tALH_min > tRC_ps - 3000 ||
107293db446aSBoris Brezillon 	    timings->tDS_min > tRC_ps ||
107393db446aSBoris Brezillon 	    timings->tDH_min > tRC_ps - 5000 ||
107493db446aSBoris Brezillon 	    timings->tWC_min > 2 * tRC_ps ||
107593db446aSBoris Brezillon 	    timings->tWH_min > tRC_ps - 2500 ||
107693db446aSBoris Brezillon 	    timings->tRR_min > 6 * tRC_ps ||
107793db446aSBoris Brezillon 	    timings->tRP_min > 3 * tRC_ps / 2 ||
107893db446aSBoris Brezillon 	    timings->tRC_min > 2 * tRC_ps ||
107993db446aSBoris Brezillon 	    timings->tREH_min > (tRC_ps / 2) - 2500) {
108093db446aSBoris Brezillon 		dev_dbg(host->dev, "Timing out of bounds\n");
108193db446aSBoris Brezillon 		return -EINVAL;
108293db446aSBoris Brezillon 	}
108393db446aSBoris Brezillon 
108493db446aSBoris Brezillon 	if (csline == NAND_DATA_IFACE_CHECK_ONLY)
108593db446aSBoris Brezillon 		return 0;
108693db446aSBoris Brezillon 
108793db446aSBoris Brezillon 	ret = clk_set_rate(host->clk, rate);
108893db446aSBoris Brezillon 	if (ret)
108993db446aSBoris Brezillon 		return ret;
109093db446aSBoris Brezillon 
109193db446aSBoris Brezillon 	writew(config1, NFC_V1_V2_CONFIG1);
109293db446aSBoris Brezillon 
109393db446aSBoris Brezillon 	dev_dbg(host->dev, "Setting rate to %ldHz, %s mode\n", rate_round,
109493db446aSBoris Brezillon 		config1 & NFC_V2_CONFIG1_ONE_CYCLE ? "One cycle (EDO)" :
109593db446aSBoris Brezillon 		"normal");
109693db446aSBoris Brezillon 
109793db446aSBoris Brezillon 	return 0;
109893db446aSBoris Brezillon }
109993db446aSBoris Brezillon 
preset_v2(struct mtd_info * mtd)110093db446aSBoris Brezillon static void preset_v2(struct mtd_info *mtd)
110193db446aSBoris Brezillon {
110293db446aSBoris Brezillon 	struct nand_chip *nand_chip = mtd_to_nand(mtd);
110393db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(nand_chip);
110493db446aSBoris Brezillon 	uint16_t config1 = 0;
110593db446aSBoris Brezillon 
110693db446aSBoris Brezillon 	config1 |= NFC_V2_CONFIG1_FP_INT;
110793db446aSBoris Brezillon 
110893db446aSBoris Brezillon 	if (!host->devtype_data->irqpending_quirk)
110993db446aSBoris Brezillon 		config1 |= NFC_V1_V2_CONFIG1_INT_MSK;
111093db446aSBoris Brezillon 
111193db446aSBoris Brezillon 	if (mtd->writesize) {
111293db446aSBoris Brezillon 		uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
111393db446aSBoris Brezillon 
1114bace41f8SMiquel Raynal 		if (nand_chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
111593db446aSBoris Brezillon 			config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
111693db446aSBoris Brezillon 
111793db446aSBoris Brezillon 		host->eccsize = get_eccsize(mtd);
111893db446aSBoris Brezillon 		if (host->eccsize == 4)
111993db446aSBoris Brezillon 			config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
112093db446aSBoris Brezillon 
112193db446aSBoris Brezillon 		config1 |= NFC_V2_CONFIG1_PPB(ffs(pages_per_block) - 6);
112293db446aSBoris Brezillon 	} else {
112393db446aSBoris Brezillon 		host->eccsize = 1;
112493db446aSBoris Brezillon 	}
112593db446aSBoris Brezillon 
112693db446aSBoris Brezillon 	writew(config1, NFC_V1_V2_CONFIG1);
112793db446aSBoris Brezillon 	/* preset operation */
112893db446aSBoris Brezillon 
11293f77f244SMartin Kaiser 	/* spare area size in 16-bit half-words */
11303f77f244SMartin Kaiser 	writew(mtd->oobsize / 2, NFC_V21_RSLTSPARE_AREA);
11313f77f244SMartin Kaiser 
113293db446aSBoris Brezillon 	/* Unlock the internal RAM Buffer */
113393db446aSBoris Brezillon 	writew(0x2, NFC_V1_V2_CONFIG);
113493db446aSBoris Brezillon 
113593db446aSBoris Brezillon 	/* Blocks to be unlocked */
113693db446aSBoris Brezillon 	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR0);
113793db446aSBoris Brezillon 	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR1);
113893db446aSBoris Brezillon 	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR2);
113993db446aSBoris Brezillon 	writew(0x0, NFC_V21_UNLOCKSTART_BLKADDR3);
114093db446aSBoris Brezillon 	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR0);
114193db446aSBoris Brezillon 	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR1);
114293db446aSBoris Brezillon 	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR2);
114393db446aSBoris Brezillon 	writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3);
114493db446aSBoris Brezillon 
114593db446aSBoris Brezillon 	/* Unlock Block Command for given address range */
114693db446aSBoris Brezillon 	writew(0x4, NFC_V1_V2_WRPROT);
114793db446aSBoris Brezillon }
114893db446aSBoris Brezillon 
preset_v3(struct mtd_info * mtd)114993db446aSBoris Brezillon static void preset_v3(struct mtd_info *mtd)
115093db446aSBoris Brezillon {
115193db446aSBoris Brezillon 	struct nand_chip *chip = mtd_to_nand(mtd);
115293db446aSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
115393db446aSBoris Brezillon 	uint32_t config2, config3;
115493db446aSBoris Brezillon 	int i, addr_phases;
115593db446aSBoris Brezillon 
115693db446aSBoris Brezillon 	writel(NFC_V3_CONFIG1_RBA(0), NFC_V3_CONFIG1);
115793db446aSBoris Brezillon 	writel(NFC_V3_IPC_CREQ, NFC_V3_IPC);
115893db446aSBoris Brezillon 
115993db446aSBoris Brezillon 	/* Unlock the internal RAM Buffer */
116093db446aSBoris Brezillon 	writel(NFC_V3_WRPROT_BLS_UNLOCK | NFC_V3_WRPROT_UNLOCK,
116193db446aSBoris Brezillon 			NFC_V3_WRPROT);
116293db446aSBoris Brezillon 
116393db446aSBoris Brezillon 	/* Blocks to be unlocked */
116493db446aSBoris Brezillon 	for (i = 0; i < NAND_MAX_CHIPS; i++)
116593db446aSBoris Brezillon 		writel(0xffff << 16, NFC_V3_WRPROT_UNLOCK_BLK_ADD0 + (i << 2));
116693db446aSBoris Brezillon 
116793db446aSBoris Brezillon 	writel(0, NFC_V3_IPC);
116893db446aSBoris Brezillon 
116993db446aSBoris Brezillon 	config2 = NFC_V3_CONFIG2_ONE_CYCLE |
117093db446aSBoris Brezillon 		NFC_V3_CONFIG2_2CMD_PHASES |
117193db446aSBoris Brezillon 		NFC_V3_CONFIG2_SPAS(mtd->oobsize >> 1) |
117293db446aSBoris Brezillon 		NFC_V3_CONFIG2_ST_CMD(0x70) |
117393db446aSBoris Brezillon 		NFC_V3_CONFIG2_INT_MSK |
117493db446aSBoris Brezillon 		NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
117593db446aSBoris Brezillon 
117693db446aSBoris Brezillon 	addr_phases = fls(chip->pagemask) >> 3;
117793db446aSBoris Brezillon 
117893db446aSBoris Brezillon 	if (mtd->writesize == 2048) {
117993db446aSBoris Brezillon 		config2 |= NFC_V3_CONFIG2_PS_2048;
118093db446aSBoris Brezillon 		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
118193db446aSBoris Brezillon 	} else if (mtd->writesize == 4096) {
118293db446aSBoris Brezillon 		config2 |= NFC_V3_CONFIG2_PS_4096;
118393db446aSBoris Brezillon 		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases);
118493db446aSBoris Brezillon 	} else {
118593db446aSBoris Brezillon 		config2 |= NFC_V3_CONFIG2_PS_512;
118693db446aSBoris Brezillon 		config2 |= NFC_V3_CONFIG2_NUM_ADDR_PHASE1(addr_phases - 1);
118793db446aSBoris Brezillon 	}
118893db446aSBoris Brezillon 
118993db446aSBoris Brezillon 	if (mtd->writesize) {
1190bace41f8SMiquel Raynal 		if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
119193db446aSBoris Brezillon 			config2 |= NFC_V3_CONFIG2_ECC_EN;
119293db446aSBoris Brezillon 
119393db446aSBoris Brezillon 		config2 |= NFC_V3_CONFIG2_PPB(
119493db446aSBoris Brezillon 				ffs(mtd->erasesize / mtd->writesize) - 6,
119593db446aSBoris Brezillon 				host->devtype_data->ppb_shift);
119693db446aSBoris Brezillon 		host->eccsize = get_eccsize(mtd);
119793db446aSBoris Brezillon 		if (host->eccsize == 8)
119893db446aSBoris Brezillon 			config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
119993db446aSBoris Brezillon 	}
120093db446aSBoris Brezillon 
120193db446aSBoris Brezillon 	writel(config2, NFC_V3_CONFIG2);
120293db446aSBoris Brezillon 
120393db446aSBoris Brezillon 	config3 = NFC_V3_CONFIG3_NUM_OF_DEVICES(0) |
120493db446aSBoris Brezillon 			NFC_V3_CONFIG3_NO_SDMA |
120593db446aSBoris Brezillon 			NFC_V3_CONFIG3_RBB_MODE |
120693db446aSBoris Brezillon 			NFC_V3_CONFIG3_SBB(6) | /* Reset default */
120793db446aSBoris Brezillon 			NFC_V3_CONFIG3_ADD_OP(0);
120893db446aSBoris Brezillon 
120993db446aSBoris Brezillon 	if (!(chip->options & NAND_BUSWIDTH_16))
121093db446aSBoris Brezillon 		config3 |= NFC_V3_CONFIG3_FW8;
121193db446aSBoris Brezillon 
121293db446aSBoris Brezillon 	writel(config3, NFC_V3_CONFIG3);
121393db446aSBoris Brezillon 
121493db446aSBoris Brezillon 	writel(0, NFC_V3_DELAY_LINE);
121593db446aSBoris Brezillon }
121693db446aSBoris Brezillon 
121793db446aSBoris Brezillon /*
1218735bf220SKieran Bingham  * The generic flash bbt descriptors overlap with our ecc
121993db446aSBoris Brezillon  * hardware, so define some i.MX specific ones.
122093db446aSBoris Brezillon  */
122193db446aSBoris Brezillon static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' };
122293db446aSBoris Brezillon static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' };
122393db446aSBoris Brezillon 
122493db446aSBoris Brezillon static struct nand_bbt_descr bbt_main_descr = {
122593db446aSBoris Brezillon 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
122693db446aSBoris Brezillon 	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
122793db446aSBoris Brezillon 	.offs = 0,
122893db446aSBoris Brezillon 	.len = 4,
122993db446aSBoris Brezillon 	.veroffs = 4,
123093db446aSBoris Brezillon 	.maxblocks = 4,
123193db446aSBoris Brezillon 	.pattern = bbt_pattern,
123293db446aSBoris Brezillon };
123393db446aSBoris Brezillon 
123493db446aSBoris Brezillon static struct nand_bbt_descr bbt_mirror_descr = {
123593db446aSBoris Brezillon 	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
123693db446aSBoris Brezillon 	    | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
123793db446aSBoris Brezillon 	.offs = 0,
123893db446aSBoris Brezillon 	.len = 4,
123993db446aSBoris Brezillon 	.veroffs = 4,
124093db446aSBoris Brezillon 	.maxblocks = 4,
124193db446aSBoris Brezillon 	.pattern = mirror_pattern,
124293db446aSBoris Brezillon };
124393db446aSBoris Brezillon 
124493db446aSBoris Brezillon /* v1 + irqpending_quirk: i.MX21 */
124593db446aSBoris Brezillon static const struct mxc_nand_devtype_data imx21_nand_devtype_data = {
124693db446aSBoris Brezillon 	.preset = preset_v1,
124793db446aSBoris Brezillon 	.read_page = mxc_nand_read_page_v1,
124893db446aSBoris Brezillon 	.send_cmd = send_cmd_v1_v2,
124993db446aSBoris Brezillon 	.send_addr = send_addr_v1_v2,
125093db446aSBoris Brezillon 	.send_page = send_page_v1,
125193db446aSBoris Brezillon 	.send_read_id = send_read_id_v1_v2,
125293db446aSBoris Brezillon 	.get_dev_status = get_dev_status_v1_v2,
125393db446aSBoris Brezillon 	.check_int = check_int_v1_v2,
125493db446aSBoris Brezillon 	.irq_control = irq_control_v1_v2,
125593db446aSBoris Brezillon 	.get_ecc_status = get_ecc_status_v1,
125693db446aSBoris Brezillon 	.ooblayout = &mxc_v1_ooblayout_ops,
125793db446aSBoris Brezillon 	.select_chip = mxc_nand_select_chip_v1_v3,
125893db446aSBoris Brezillon 	.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
125993db446aSBoris Brezillon 	.irqpending_quirk = 1,
126093db446aSBoris Brezillon 	.needs_ip = 0,
126193db446aSBoris Brezillon 	.regs_offset = 0xe00,
126293db446aSBoris Brezillon 	.spare0_offset = 0x800,
126393db446aSBoris Brezillon 	.spare_len = 16,
126493db446aSBoris Brezillon 	.eccbytes = 3,
126593db446aSBoris Brezillon 	.eccsize = 1,
126693db446aSBoris Brezillon };
126793db446aSBoris Brezillon 
126893db446aSBoris Brezillon /* v1 + !irqpending_quirk: i.MX27, i.MX31 */
126993db446aSBoris Brezillon static const struct mxc_nand_devtype_data imx27_nand_devtype_data = {
127093db446aSBoris Brezillon 	.preset = preset_v1,
127193db446aSBoris Brezillon 	.read_page = mxc_nand_read_page_v1,
127293db446aSBoris Brezillon 	.send_cmd = send_cmd_v1_v2,
127393db446aSBoris Brezillon 	.send_addr = send_addr_v1_v2,
127493db446aSBoris Brezillon 	.send_page = send_page_v1,
127593db446aSBoris Brezillon 	.send_read_id = send_read_id_v1_v2,
127693db446aSBoris Brezillon 	.get_dev_status = get_dev_status_v1_v2,
127793db446aSBoris Brezillon 	.check_int = check_int_v1_v2,
127893db446aSBoris Brezillon 	.irq_control = irq_control_v1_v2,
127993db446aSBoris Brezillon 	.get_ecc_status = get_ecc_status_v1,
128093db446aSBoris Brezillon 	.ooblayout = &mxc_v1_ooblayout_ops,
128193db446aSBoris Brezillon 	.select_chip = mxc_nand_select_chip_v1_v3,
128293db446aSBoris Brezillon 	.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
128393db446aSBoris Brezillon 	.irqpending_quirk = 0,
128493db446aSBoris Brezillon 	.needs_ip = 0,
128593db446aSBoris Brezillon 	.regs_offset = 0xe00,
128693db446aSBoris Brezillon 	.spare0_offset = 0x800,
128793db446aSBoris Brezillon 	.axi_offset = 0,
128893db446aSBoris Brezillon 	.spare_len = 16,
128993db446aSBoris Brezillon 	.eccbytes = 3,
129093db446aSBoris Brezillon 	.eccsize = 1,
129193db446aSBoris Brezillon };
129293db446aSBoris Brezillon 
129393db446aSBoris Brezillon /* v21: i.MX25, i.MX35 */
129493db446aSBoris Brezillon static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
129593db446aSBoris Brezillon 	.preset = preset_v2,
129693db446aSBoris Brezillon 	.read_page = mxc_nand_read_page_v2_v3,
129793db446aSBoris Brezillon 	.send_cmd = send_cmd_v1_v2,
129893db446aSBoris Brezillon 	.send_addr = send_addr_v1_v2,
129993db446aSBoris Brezillon 	.send_page = send_page_v2,
130093db446aSBoris Brezillon 	.send_read_id = send_read_id_v1_v2,
130193db446aSBoris Brezillon 	.get_dev_status = get_dev_status_v1_v2,
130293db446aSBoris Brezillon 	.check_int = check_int_v1_v2,
130393db446aSBoris Brezillon 	.irq_control = irq_control_v1_v2,
130493db446aSBoris Brezillon 	.get_ecc_status = get_ecc_status_v2,
130593db446aSBoris Brezillon 	.ooblayout = &mxc_v2_ooblayout_ops,
130693db446aSBoris Brezillon 	.select_chip = mxc_nand_select_chip_v2,
13074c46667bSMiquel Raynal 	.setup_interface = mxc_nand_v2_setup_interface,
130893db446aSBoris Brezillon 	.enable_hwecc = mxc_nand_enable_hwecc_v1_v2,
130993db446aSBoris Brezillon 	.irqpending_quirk = 0,
131093db446aSBoris Brezillon 	.needs_ip = 0,
131193db446aSBoris Brezillon 	.regs_offset = 0x1e00,
131293db446aSBoris Brezillon 	.spare0_offset = 0x1000,
131393db446aSBoris Brezillon 	.axi_offset = 0,
131493db446aSBoris Brezillon 	.spare_len = 64,
131593db446aSBoris Brezillon 	.eccbytes = 9,
131693db446aSBoris Brezillon 	.eccsize = 0,
131793db446aSBoris Brezillon };
131893db446aSBoris Brezillon 
131993db446aSBoris Brezillon /* v3.2a: i.MX51 */
132093db446aSBoris Brezillon static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
132193db446aSBoris Brezillon 	.preset = preset_v3,
132293db446aSBoris Brezillon 	.read_page = mxc_nand_read_page_v2_v3,
132393db446aSBoris Brezillon 	.send_cmd = send_cmd_v3,
132493db446aSBoris Brezillon 	.send_addr = send_addr_v3,
132593db446aSBoris Brezillon 	.send_page = send_page_v3,
132693db446aSBoris Brezillon 	.send_read_id = send_read_id_v3,
132793db446aSBoris Brezillon 	.get_dev_status = get_dev_status_v3,
132893db446aSBoris Brezillon 	.check_int = check_int_v3,
132993db446aSBoris Brezillon 	.irq_control = irq_control_v3,
133093db446aSBoris Brezillon 	.get_ecc_status = get_ecc_status_v3,
133193db446aSBoris Brezillon 	.ooblayout = &mxc_v2_ooblayout_ops,
133293db446aSBoris Brezillon 	.select_chip = mxc_nand_select_chip_v1_v3,
133393db446aSBoris Brezillon 	.enable_hwecc = mxc_nand_enable_hwecc_v3,
133493db446aSBoris Brezillon 	.irqpending_quirk = 0,
133593db446aSBoris Brezillon 	.needs_ip = 1,
133693db446aSBoris Brezillon 	.regs_offset = 0,
133793db446aSBoris Brezillon 	.spare0_offset = 0x1000,
133893db446aSBoris Brezillon 	.axi_offset = 0x1e00,
133993db446aSBoris Brezillon 	.spare_len = 64,
134093db446aSBoris Brezillon 	.eccbytes = 0,
134193db446aSBoris Brezillon 	.eccsize = 0,
134293db446aSBoris Brezillon 	.ppb_shift = 7,
134393db446aSBoris Brezillon };
134493db446aSBoris Brezillon 
134593db446aSBoris Brezillon /* v3.2b: i.MX53 */
134693db446aSBoris Brezillon static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
134793db446aSBoris Brezillon 	.preset = preset_v3,
134893db446aSBoris Brezillon 	.read_page = mxc_nand_read_page_v2_v3,
134993db446aSBoris Brezillon 	.send_cmd = send_cmd_v3,
135093db446aSBoris Brezillon 	.send_addr = send_addr_v3,
135193db446aSBoris Brezillon 	.send_page = send_page_v3,
135293db446aSBoris Brezillon 	.send_read_id = send_read_id_v3,
135393db446aSBoris Brezillon 	.get_dev_status = get_dev_status_v3,
135493db446aSBoris Brezillon 	.check_int = check_int_v3,
135593db446aSBoris Brezillon 	.irq_control = irq_control_v3,
135693db446aSBoris Brezillon 	.get_ecc_status = get_ecc_status_v3,
135793db446aSBoris Brezillon 	.ooblayout = &mxc_v2_ooblayout_ops,
135893db446aSBoris Brezillon 	.select_chip = mxc_nand_select_chip_v1_v3,
135993db446aSBoris Brezillon 	.enable_hwecc = mxc_nand_enable_hwecc_v3,
136093db446aSBoris Brezillon 	.irqpending_quirk = 0,
136193db446aSBoris Brezillon 	.needs_ip = 1,
136293db446aSBoris Brezillon 	.regs_offset = 0,
136393db446aSBoris Brezillon 	.spare0_offset = 0x1000,
136493db446aSBoris Brezillon 	.axi_offset = 0x1e00,
136593db446aSBoris Brezillon 	.spare_len = 64,
136693db446aSBoris Brezillon 	.eccbytes = 0,
136793db446aSBoris Brezillon 	.eccsize = 0,
136893db446aSBoris Brezillon 	.ppb_shift = 8,
136993db446aSBoris Brezillon };
137093db446aSBoris Brezillon 
is_imx21_nfc(struct mxc_nand_host * host)137193db446aSBoris Brezillon static inline int is_imx21_nfc(struct mxc_nand_host *host)
137293db446aSBoris Brezillon {
137393db446aSBoris Brezillon 	return host->devtype_data == &imx21_nand_devtype_data;
137493db446aSBoris Brezillon }
137593db446aSBoris Brezillon 
is_imx27_nfc(struct mxc_nand_host * host)137693db446aSBoris Brezillon static inline int is_imx27_nfc(struct mxc_nand_host *host)
137793db446aSBoris Brezillon {
137893db446aSBoris Brezillon 	return host->devtype_data == &imx27_nand_devtype_data;
137993db446aSBoris Brezillon }
138093db446aSBoris Brezillon 
is_imx25_nfc(struct mxc_nand_host * host)138193db446aSBoris Brezillon static inline int is_imx25_nfc(struct mxc_nand_host *host)
138293db446aSBoris Brezillon {
138393db446aSBoris Brezillon 	return host->devtype_data == &imx25_nand_devtype_data;
138493db446aSBoris Brezillon }
138593db446aSBoris Brezillon 
138693db446aSBoris Brezillon static const struct of_device_id mxcnd_dt_ids[] = {
13875e214b25SFabio Estevam 	{ .compatible = "fsl,imx21-nand", .data = &imx21_nand_devtype_data, },
13885e214b25SFabio Estevam 	{ .compatible = "fsl,imx27-nand", .data = &imx27_nand_devtype_data, },
13895e214b25SFabio Estevam 	{ .compatible = "fsl,imx25-nand", .data = &imx25_nand_devtype_data, },
13905e214b25SFabio Estevam 	{ .compatible = "fsl,imx51-nand", .data = &imx51_nand_devtype_data, },
13915e214b25SFabio Estevam 	{ .compatible = "fsl,imx53-nand", .data = &imx53_nand_devtype_data, },
139293db446aSBoris Brezillon 	{ /* sentinel */ }
139393db446aSBoris Brezillon };
139493db446aSBoris Brezillon MODULE_DEVICE_TABLE(of, mxcnd_dt_ids);
139593db446aSBoris Brezillon 
mxcnd_attach_chip(struct nand_chip * chip)139696fa8e6eSMiquel Raynal static int mxcnd_attach_chip(struct nand_chip *chip)
139796fa8e6eSMiquel Raynal {
139896fa8e6eSMiquel Raynal 	struct mtd_info *mtd = nand_to_mtd(chip);
139996fa8e6eSMiquel Raynal 	struct mxc_nand_host *host = nand_get_controller_data(chip);
140096fa8e6eSMiquel Raynal 	struct device *dev = mtd->dev.parent;
140196fa8e6eSMiquel Raynal 
14021b8d1070SFabio Estevam 	chip->ecc.bytes = host->devtype_data->eccbytes;
14031b8d1070SFabio Estevam 	host->eccsize = host->devtype_data->eccsize;
14041b8d1070SFabio Estevam 	chip->ecc.size = 512;
14051b8d1070SFabio Estevam 
1406bace41f8SMiquel Raynal 	switch (chip->ecc.engine_type) {
1407bace41f8SMiquel Raynal 	case NAND_ECC_ENGINE_TYPE_ON_HOST:
140872600505SSascha Hauer 		mtd_set_ooblayout(mtd, host->devtype_data->ooblayout);
140996fa8e6eSMiquel Raynal 		chip->ecc.read_page = mxc_nand_read_page;
141096fa8e6eSMiquel Raynal 		chip->ecc.read_page_raw = mxc_nand_read_page_raw;
141196fa8e6eSMiquel Raynal 		chip->ecc.read_oob = mxc_nand_read_oob;
141296fa8e6eSMiquel Raynal 		chip->ecc.write_page = mxc_nand_write_page_ecc;
141396fa8e6eSMiquel Raynal 		chip->ecc.write_page_raw = mxc_nand_write_page_raw;
141496fa8e6eSMiquel Raynal 		chip->ecc.write_oob = mxc_nand_write_oob;
141596fa8e6eSMiquel Raynal 		break;
141696fa8e6eSMiquel Raynal 
1417bace41f8SMiquel Raynal 	case NAND_ECC_ENGINE_TYPE_SOFT:
141872600505SSascha Hauer 		chip->ecc.write_page_raw = nand_monolithic_write_page_raw;
141972600505SSascha Hauer 		chip->ecc.read_page_raw = nand_monolithic_read_page_raw;
142096fa8e6eSMiquel Raynal 		break;
142196fa8e6eSMiquel Raynal 
142296fa8e6eSMiquel Raynal 	default:
142396fa8e6eSMiquel Raynal 		return -EINVAL;
142496fa8e6eSMiquel Raynal 	}
142596fa8e6eSMiquel Raynal 
142696fa8e6eSMiquel Raynal 	if (chip->bbt_options & NAND_BBT_USE_FLASH) {
142796fa8e6eSMiquel Raynal 		chip->bbt_td = &bbt_main_descr;
142896fa8e6eSMiquel Raynal 		chip->bbt_md = &bbt_mirror_descr;
142996fa8e6eSMiquel Raynal 	}
143096fa8e6eSMiquel Raynal 
143196fa8e6eSMiquel Raynal 	/* Allocate the right size buffer now */
143296fa8e6eSMiquel Raynal 	devm_kfree(dev, (void *)host->data_buf);
143396fa8e6eSMiquel Raynal 	host->data_buf = devm_kzalloc(dev, mtd->writesize + mtd->oobsize,
143496fa8e6eSMiquel Raynal 				      GFP_KERNEL);
143596fa8e6eSMiquel Raynal 	if (!host->data_buf)
143696fa8e6eSMiquel Raynal 		return -ENOMEM;
143796fa8e6eSMiquel Raynal 
143896fa8e6eSMiquel Raynal 	/* Call preset again, with correct writesize chip time */
143996fa8e6eSMiquel Raynal 	host->devtype_data->preset(mtd);
144096fa8e6eSMiquel Raynal 
144196fa8e6eSMiquel Raynal 	if (!chip->ecc.bytes) {
144296fa8e6eSMiquel Raynal 		if (host->eccsize == 8)
144396fa8e6eSMiquel Raynal 			chip->ecc.bytes = 18;
144496fa8e6eSMiquel Raynal 		else if (host->eccsize == 4)
144596fa8e6eSMiquel Raynal 			chip->ecc.bytes = 9;
144696fa8e6eSMiquel Raynal 	}
144796fa8e6eSMiquel Raynal 
144896fa8e6eSMiquel Raynal 	/*
144996fa8e6eSMiquel Raynal 	 * Experimentation shows that i.MX NFC can only handle up to 218 oob
145096fa8e6eSMiquel Raynal 	 * bytes. Limit used_oobsize to 218 so as to not confuse copy_spare()
145196fa8e6eSMiquel Raynal 	 * into copying invalid data to/from the spare IO buffer, as this
145296fa8e6eSMiquel Raynal 	 * might cause ECC data corruption when doing sub-page write to a
145396fa8e6eSMiquel Raynal 	 * partially written page.
145496fa8e6eSMiquel Raynal 	 */
145596fa8e6eSMiquel Raynal 	host->used_oobsize = min(mtd->oobsize, 218U);
145696fa8e6eSMiquel Raynal 
1457bace41f8SMiquel Raynal 	if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) {
145896fa8e6eSMiquel Raynal 		if (is_imx21_nfc(host) || is_imx27_nfc(host))
145996fa8e6eSMiquel Raynal 			chip->ecc.strength = 1;
146096fa8e6eSMiquel Raynal 		else
146196fa8e6eSMiquel Raynal 			chip->ecc.strength = (host->eccsize == 4) ? 4 : 8;
146296fa8e6eSMiquel Raynal 	}
146396fa8e6eSMiquel Raynal 
146496fa8e6eSMiquel Raynal 	return 0;
146596fa8e6eSMiquel Raynal }
146696fa8e6eSMiquel Raynal 
mxcnd_setup_interface(struct nand_chip * chip,int chipnr,const struct nand_interface_config * conf)14674c46667bSMiquel Raynal static int mxcnd_setup_interface(struct nand_chip *chip, int chipnr,
14684c46667bSMiquel Raynal 				 const struct nand_interface_config *conf)
14697a08dbaeSBoris Brezillon {
14707a08dbaeSBoris Brezillon 	struct mxc_nand_host *host = nand_get_controller_data(chip);
14717a08dbaeSBoris Brezillon 
14724c46667bSMiquel Raynal 	return host->devtype_data->setup_interface(chip, chipnr, conf);
14737a08dbaeSBoris Brezillon }
14747a08dbaeSBoris Brezillon 
memff16_toio(void * buf,int n)147572600505SSascha Hauer static void memff16_toio(void *buf, int n)
147672600505SSascha Hauer {
147772600505SSascha Hauer 	__iomem u16 *t = buf;
147872600505SSascha Hauer 	int i;
147972600505SSascha Hauer 
148072600505SSascha Hauer 	for (i = 0; i < (n >> 1); i++)
148172600505SSascha Hauer 		__raw_writew(0xffff, t++);
148272600505SSascha Hauer }
148372600505SSascha Hauer 
copy_page_to_sram(struct mtd_info * mtd,const void * buf,int buf_len)148472600505SSascha Hauer static void copy_page_to_sram(struct mtd_info *mtd, const void *buf, int buf_len)
148572600505SSascha Hauer {
148672600505SSascha Hauer 	struct nand_chip *this = mtd_to_nand(mtd);
148772600505SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(this);
148872600505SSascha Hauer 	unsigned int no_subpages = mtd->writesize / 512;
148972600505SSascha Hauer 	int oob_per_subpage, i;
149072600505SSascha Hauer 
149172600505SSascha Hauer 	oob_per_subpage = (mtd->oobsize / no_subpages) & ~1;
149272600505SSascha Hauer 
149372600505SSascha Hauer 	/*
149472600505SSascha Hauer 	 * During a page write the i.MX NAND controller will read 512b from
149572600505SSascha Hauer 	 * main_area0 SRAM, then oob_per_subpage bytes from spare0 SRAM, then
149672600505SSascha Hauer 	 * 512b from main_area1 SRAM and so on until the full page is written.
149772600505SSascha Hauer 	 * For software ECC we want to have a 1:1 mapping between the raw page
149872600505SSascha Hauer 	 * data on the NAND chip and the view of the NAND core. This is
149972600505SSascha Hauer 	 * necessary to make the NAND_CMD_RNDOUT read the data it expects.
150072600505SSascha Hauer 	 * To accomplish this we have to write the data in the order the controller
150172600505SSascha Hauer 	 * reads it. This is reversed in copy_page_from_sram() below.
150272600505SSascha Hauer 	 *
150372600505SSascha Hauer 	 * buf_len can either be the full page including the OOB or user data only.
150472600505SSascha Hauer 	 * When it's user data only make sure that we fill up the rest of the
150572600505SSascha Hauer 	 * SRAM with 0xff.
150672600505SSascha Hauer 	 */
150772600505SSascha Hauer 	for (i = 0; i < no_subpages; i++) {
150872600505SSascha Hauer 		int now = min(buf_len, 512);
150972600505SSascha Hauer 
151072600505SSascha Hauer 		if (now)
151172600505SSascha Hauer 			memcpy16_toio(host->main_area0 + i * 512, buf, now);
151272600505SSascha Hauer 
151372600505SSascha Hauer 		if (now < 512)
151472600505SSascha Hauer 			memff16_toio(host->main_area0 + i * 512 + now, 512 - now);
151572600505SSascha Hauer 
151672600505SSascha Hauer 		buf += 512;
151772600505SSascha Hauer 		buf_len -= now;
151872600505SSascha Hauer 
151972600505SSascha Hauer 		now = min(buf_len, oob_per_subpage);
152072600505SSascha Hauer 		if (now)
152172600505SSascha Hauer 			memcpy16_toio(host->spare0 + i * host->devtype_data->spare_len,
152272600505SSascha Hauer 				      buf, now);
152372600505SSascha Hauer 
152472600505SSascha Hauer 		if (now < oob_per_subpage)
152572600505SSascha Hauer 			memff16_toio(host->spare0 + i * host->devtype_data->spare_len + now,
152672600505SSascha Hauer 				     oob_per_subpage - now);
152772600505SSascha Hauer 
152872600505SSascha Hauer 		buf += oob_per_subpage;
152972600505SSascha Hauer 		buf_len -= now;
153072600505SSascha Hauer 	}
153172600505SSascha Hauer }
153272600505SSascha Hauer 
copy_page_from_sram(struct mtd_info * mtd)153372600505SSascha Hauer static void copy_page_from_sram(struct mtd_info *mtd)
153472600505SSascha Hauer {
153572600505SSascha Hauer 	struct nand_chip *this = mtd_to_nand(mtd);
153672600505SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(this);
153772600505SSascha Hauer 	void *buf = host->data_buf;
153872600505SSascha Hauer 	unsigned int no_subpages = mtd->writesize / 512;
153972600505SSascha Hauer 	int oob_per_subpage, i;
154072600505SSascha Hauer 
154172600505SSascha Hauer 	/* mtd->writesize is not set during ident scanning */
154272600505SSascha Hauer 	if (!no_subpages)
154372600505SSascha Hauer 		no_subpages = 1;
154472600505SSascha Hauer 
154572600505SSascha Hauer 	oob_per_subpage = (mtd->oobsize / no_subpages) & ~1;
154672600505SSascha Hauer 
154772600505SSascha Hauer 	for (i = 0; i < no_subpages; i++) {
154872600505SSascha Hauer 		memcpy16_fromio(buf, host->main_area0 + i * 512, 512);
154972600505SSascha Hauer 		buf += 512;
155072600505SSascha Hauer 
155172600505SSascha Hauer 		memcpy16_fromio(buf, host->spare0 + i * host->devtype_data->spare_len,
155272600505SSascha Hauer 				oob_per_subpage);
155372600505SSascha Hauer 		buf += oob_per_subpage;
155472600505SSascha Hauer 	}
155572600505SSascha Hauer }
155672600505SSascha Hauer 
mxcnd_do_exec_op(struct nand_chip * chip,const struct nand_subop * op)1557d3dfbae6SSascha Hauer static int mxcnd_do_exec_op(struct nand_chip *chip,
1558d3dfbae6SSascha Hauer 			    const struct nand_subop *op)
1559d3dfbae6SSascha Hauer {
1560d3dfbae6SSascha Hauer 	struct mxc_nand_host *host = nand_get_controller_data(chip);
1561d3dfbae6SSascha Hauer 	struct mtd_info *mtd = nand_to_mtd(chip);
1562d3dfbae6SSascha Hauer 	int i, j, buf_len;
1563d3dfbae6SSascha Hauer 	void *buf_read = NULL;
1564d3dfbae6SSascha Hauer 	const void *buf_write = NULL;
1565d3dfbae6SSascha Hauer 	const struct nand_op_instr *instr;
1566d3dfbae6SSascha Hauer 	bool readid = false;
1567d3dfbae6SSascha Hauer 	bool statusreq = false;
1568d3dfbae6SSascha Hauer 
1569d3dfbae6SSascha Hauer 	for (i = 0; i < op->ninstrs; i++) {
1570d3dfbae6SSascha Hauer 		instr = &op->instrs[i];
1571d3dfbae6SSascha Hauer 
1572d3dfbae6SSascha Hauer 		switch (instr->type) {
1573d3dfbae6SSascha Hauer 		case NAND_OP_WAITRDY_INSTR:
1574d3dfbae6SSascha Hauer 			/* NFC handles R/B internally, nothing to do here */
1575d3dfbae6SSascha Hauer 			break;
1576d3dfbae6SSascha Hauer 		case NAND_OP_CMD_INSTR:
1577d3dfbae6SSascha Hauer 			host->devtype_data->send_cmd(host, instr->ctx.cmd.opcode, true);
1578d3dfbae6SSascha Hauer 
1579d3dfbae6SSascha Hauer 			if (instr->ctx.cmd.opcode == NAND_CMD_READID)
1580d3dfbae6SSascha Hauer 				readid = true;
1581d3dfbae6SSascha Hauer 			if (instr->ctx.cmd.opcode == NAND_CMD_STATUS)
1582d3dfbae6SSascha Hauer 				statusreq = true;
1583d3dfbae6SSascha Hauer 
1584d3dfbae6SSascha Hauer 			break;
1585d3dfbae6SSascha Hauer 		case NAND_OP_ADDR_INSTR:
1586d3dfbae6SSascha Hauer 			for (j = 0; j < instr->ctx.addr.naddrs; j++) {
1587d3dfbae6SSascha Hauer 				bool islast = j == instr->ctx.addr.naddrs - 1;
1588d3dfbae6SSascha Hauer 				host->devtype_data->send_addr(host, instr->ctx.addr.addrs[j], islast);
1589d3dfbae6SSascha Hauer 			}
1590d3dfbae6SSascha Hauer 			break;
1591d3dfbae6SSascha Hauer 		case NAND_OP_DATA_OUT_INSTR:
1592d3dfbae6SSascha Hauer 			buf_write = instr->ctx.data.buf.out;
1593d3dfbae6SSascha Hauer 			buf_len = instr->ctx.data.len;
1594d3dfbae6SSascha Hauer 
159572600505SSascha Hauer 			if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST)
1596d3dfbae6SSascha Hauer 				memcpy32_toio(host->main_area0, buf_write, buf_len);
159772600505SSascha Hauer 			else
159872600505SSascha Hauer 				copy_page_to_sram(mtd, buf_write, buf_len);
1599d3dfbae6SSascha Hauer 
1600d3dfbae6SSascha Hauer 			host->devtype_data->send_page(mtd, NFC_INPUT);
1601d3dfbae6SSascha Hauer 
1602d3dfbae6SSascha Hauer 			break;
1603d3dfbae6SSascha Hauer 		case NAND_OP_DATA_IN_INSTR:
1604d3dfbae6SSascha Hauer 
1605d3dfbae6SSascha Hauer 			buf_read = instr->ctx.data.buf.in;
1606d3dfbae6SSascha Hauer 			buf_len = instr->ctx.data.len;
1607d3dfbae6SSascha Hauer 
1608d3dfbae6SSascha Hauer 			if (readid) {
1609d3dfbae6SSascha Hauer 				host->devtype_data->send_read_id(host);
1610d3dfbae6SSascha Hauer 				readid = false;
1611d3dfbae6SSascha Hauer 
1612d3dfbae6SSascha Hauer 				memcpy32_fromio(host->data_buf, host->main_area0, buf_len * 2);
1613d3dfbae6SSascha Hauer 
1614d3dfbae6SSascha Hauer 				if (chip->options & NAND_BUSWIDTH_16) {
1615d3dfbae6SSascha Hauer 					u8 *bufr = buf_read;
1616d3dfbae6SSascha Hauer 					u16 *bufw = host->data_buf;
1617d3dfbae6SSascha Hauer 					for (j = 0; j < buf_len; j++)
1618d3dfbae6SSascha Hauer 						bufr[j] = bufw[j];
1619d3dfbae6SSascha Hauer 				} else {
1620d3dfbae6SSascha Hauer 					memcpy(buf_read, host->data_buf, buf_len);
1621d3dfbae6SSascha Hauer 				}
1622d3dfbae6SSascha Hauer 				break;
1623d3dfbae6SSascha Hauer 			}
1624d3dfbae6SSascha Hauer 
1625d3dfbae6SSascha Hauer 			if (statusreq) {
1626d3dfbae6SSascha Hauer 				*(u8*)buf_read = host->devtype_data->get_dev_status(host);
1627d3dfbae6SSascha Hauer 				statusreq = false;
1628d3dfbae6SSascha Hauer 				break;
1629d3dfbae6SSascha Hauer 			}
1630d3dfbae6SSascha Hauer 
1631d3dfbae6SSascha Hauer 			host->devtype_data->read_page(chip);
1632d3dfbae6SSascha Hauer 
163372600505SSascha Hauer 			if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_ON_HOST) {
1634d3dfbae6SSascha Hauer 				if (IS_ALIGNED(buf_len, 4)) {
1635d3dfbae6SSascha Hauer 					memcpy32_fromio(buf_read, host->main_area0, buf_len);
1636d3dfbae6SSascha Hauer 				} else {
1637d3dfbae6SSascha Hauer 					memcpy32_fromio(host->data_buf, host->main_area0, mtd->writesize);
1638d3dfbae6SSascha Hauer 					memcpy(buf_read, host->data_buf, buf_len);
1639d3dfbae6SSascha Hauer 				}
164072600505SSascha Hauer 			} else {
164172600505SSascha Hauer 				copy_page_from_sram(mtd);
164272600505SSascha Hauer 				memcpy(buf_read, host->data_buf, buf_len);
164372600505SSascha Hauer 			}
1644d3dfbae6SSascha Hauer 
1645d3dfbae6SSascha Hauer 			break;
1646d3dfbae6SSascha Hauer 		}
1647d3dfbae6SSascha Hauer 	}
1648d3dfbae6SSascha Hauer 
1649d3dfbae6SSascha Hauer 	return 0;
1650d3dfbae6SSascha Hauer }
1651d3dfbae6SSascha Hauer 
1652d3dfbae6SSascha Hauer #define MAX_DATA_SIZE	(4096 + 512)
1653d3dfbae6SSascha Hauer 
1654d3dfbae6SSascha Hauer static const struct nand_op_parser mxcnd_op_parser = NAND_OP_PARSER(
1655d3dfbae6SSascha Hauer 	NAND_OP_PARSER_PATTERN(mxcnd_do_exec_op,
1656d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_CMD_ELEM(false),
1657d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_ADDR_ELEM(true, 7),
1658d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_CMD_ELEM(true),
1659d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_WAITRDY_ELEM(true),
1660d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_DATA_IN_ELEM(true, MAX_DATA_SIZE)),
1661d3dfbae6SSascha Hauer 	NAND_OP_PARSER_PATTERN(mxcnd_do_exec_op,
1662d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_CMD_ELEM(false),
1663d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7),
1664d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_DATA_SIZE),
1665d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_CMD_ELEM(false),
1666d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
1667d3dfbae6SSascha Hauer 	NAND_OP_PARSER_PATTERN(mxcnd_do_exec_op,
1668d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_CMD_ELEM(false),
1669d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_ADDR_ELEM(false, 7),
1670d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_DATA_OUT_ELEM(false, MAX_DATA_SIZE),
1671d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_CMD_ELEM(true),
1672d3dfbae6SSascha Hauer 			       NAND_OP_PARSER_PAT_WAITRDY_ELEM(true)),
1673d3dfbae6SSascha Hauer 	);
1674d3dfbae6SSascha Hauer 
mxcnd_exec_op(struct nand_chip * chip,const struct nand_operation * op,bool check_only)1675d3dfbae6SSascha Hauer static int mxcnd_exec_op(struct nand_chip *chip,
1676d3dfbae6SSascha Hauer 			 const struct nand_operation *op, bool check_only)
1677d3dfbae6SSascha Hauer {
1678d3dfbae6SSascha Hauer 	return nand_op_parser_exec_op(chip, &mxcnd_op_parser,
1679d3dfbae6SSascha Hauer 				      op, check_only);
1680d3dfbae6SSascha Hauer }
1681d3dfbae6SSascha Hauer 
168296fa8e6eSMiquel Raynal static const struct nand_controller_ops mxcnd_controller_ops = {
168396fa8e6eSMiquel Raynal 	.attach_chip = mxcnd_attach_chip,
16844c46667bSMiquel Raynal 	.setup_interface = mxcnd_setup_interface,
1685d3dfbae6SSascha Hauer 	.exec_op = mxcnd_exec_op,
168696fa8e6eSMiquel Raynal };
168796fa8e6eSMiquel Raynal 
mxcnd_probe(struct platform_device * pdev)168893db446aSBoris Brezillon static int mxcnd_probe(struct platform_device *pdev)
168993db446aSBoris Brezillon {
169093db446aSBoris Brezillon 	struct nand_chip *this;
169193db446aSBoris Brezillon 	struct mtd_info *mtd;
169293db446aSBoris Brezillon 	struct mxc_nand_host *host;
169393db446aSBoris Brezillon 	int err = 0;
169493db446aSBoris Brezillon 
169593db446aSBoris Brezillon 	/* Allocate memory for MTD device structure and private data */
169693db446aSBoris Brezillon 	host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
169793db446aSBoris Brezillon 			GFP_KERNEL);
169893db446aSBoris Brezillon 	if (!host)
169993db446aSBoris Brezillon 		return -ENOMEM;
170093db446aSBoris Brezillon 
170193db446aSBoris Brezillon 	/* allocate a temporary buffer for the nand_scan_ident() */
170293db446aSBoris Brezillon 	host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
170393db446aSBoris Brezillon 	if (!host->data_buf)
170493db446aSBoris Brezillon 		return -ENOMEM;
170593db446aSBoris Brezillon 
170693db446aSBoris Brezillon 	host->dev = &pdev->dev;
170793db446aSBoris Brezillon 	/* structures must be linked */
170893db446aSBoris Brezillon 	this = &host->nand;
170993db446aSBoris Brezillon 	mtd = nand_to_mtd(this);
171093db446aSBoris Brezillon 	mtd->dev.parent = &pdev->dev;
171193db446aSBoris Brezillon 	mtd->name = DRIVER_NAME;
171293db446aSBoris Brezillon 
171393db446aSBoris Brezillon 	/* 50 us command delay time */
17143cece3abSBoris Brezillon 	this->legacy.chip_delay = 5;
171593db446aSBoris Brezillon 
171693db446aSBoris Brezillon 	nand_set_controller_data(this, host);
171763f559d3SZheng Yongjun 	nand_set_flash_node(this, pdev->dev.of_node);
171893db446aSBoris Brezillon 
171993db446aSBoris Brezillon 	host->clk = devm_clk_get(&pdev->dev, NULL);
172093db446aSBoris Brezillon 	if (IS_ERR(host->clk))
172193db446aSBoris Brezillon 		return PTR_ERR(host->clk);
172293db446aSBoris Brezillon 
17235876f2d9SFabio Estevam 	host->devtype_data = device_get_match_data(&pdev->dev);
172493db446aSBoris Brezillon 
17254c46667bSMiquel Raynal 	if (!host->devtype_data->setup_interface)
17267a08dbaeSBoris Brezillon 		this->options |= NAND_KEEP_TIMINGS;
172793db446aSBoris Brezillon 
172893db446aSBoris Brezillon 	if (host->devtype_data->needs_ip) {
1729c96b3e09SYangtao Li 		host->regs_ip = devm_platform_ioremap_resource(pdev, 0);
173093db446aSBoris Brezillon 		if (IS_ERR(host->regs_ip))
173193db446aSBoris Brezillon 			return PTR_ERR(host->regs_ip);
173293db446aSBoris Brezillon 
1733c96b3e09SYangtao Li 		host->base = devm_platform_ioremap_resource(pdev, 1);
173493db446aSBoris Brezillon 	} else {
1735c96b3e09SYangtao Li 		host->base = devm_platform_ioremap_resource(pdev, 0);
173693db446aSBoris Brezillon 	}
173793db446aSBoris Brezillon 
173893db446aSBoris Brezillon 	if (IS_ERR(host->base))
173993db446aSBoris Brezillon 		return PTR_ERR(host->base);
174093db446aSBoris Brezillon 
174193db446aSBoris Brezillon 	host->main_area0 = host->base;
174293db446aSBoris Brezillon 
174393db446aSBoris Brezillon 	if (host->devtype_data->regs_offset)
174493db446aSBoris Brezillon 		host->regs = host->base + host->devtype_data->regs_offset;
174593db446aSBoris Brezillon 	host->spare0 = host->base + host->devtype_data->spare0_offset;
174693db446aSBoris Brezillon 	if (host->devtype_data->axi_offset)
174793db446aSBoris Brezillon 		host->regs_axi = host->base + host->devtype_data->axi_offset;
174893db446aSBoris Brezillon 
17497d6c37e9SBoris Brezillon 	this->legacy.select_chip = host->devtype_data->select_chip;
175093db446aSBoris Brezillon 
175193db446aSBoris Brezillon 	init_completion(&host->op_completion);
175293db446aSBoris Brezillon 
175393db446aSBoris Brezillon 	host->irq = platform_get_irq(pdev, 0);
175493db446aSBoris Brezillon 	if (host->irq < 0)
175593db446aSBoris Brezillon 		return host->irq;
175693db446aSBoris Brezillon 
175793db446aSBoris Brezillon 	/*
175893db446aSBoris Brezillon 	 * Use host->devtype_data->irq_control() here instead of irq_control()
175993db446aSBoris Brezillon 	 * because we must not disable_irq_nosync without having requested the
176093db446aSBoris Brezillon 	 * irq.
176193db446aSBoris Brezillon 	 */
176293db446aSBoris Brezillon 	host->devtype_data->irq_control(host, 0);
176393db446aSBoris Brezillon 
176493db446aSBoris Brezillon 	err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
176593db446aSBoris Brezillon 			0, DRIVER_NAME, host);
176693db446aSBoris Brezillon 	if (err)
176793db446aSBoris Brezillon 		return err;
176893db446aSBoris Brezillon 
176993db446aSBoris Brezillon 	err = clk_prepare_enable(host->clk);
177093db446aSBoris Brezillon 	if (err)
177193db446aSBoris Brezillon 		return err;
177293db446aSBoris Brezillon 	host->clk_act = 1;
177393db446aSBoris Brezillon 
177493db446aSBoris Brezillon 	/*
177593db446aSBoris Brezillon 	 * Now that we "own" the interrupt make sure the interrupt mask bit is
177693db446aSBoris Brezillon 	 * cleared on i.MX21. Otherwise we can't read the interrupt status bit
177793db446aSBoris Brezillon 	 * on this machine.
177893db446aSBoris Brezillon 	 */
177993db446aSBoris Brezillon 	if (host->devtype_data->irqpending_quirk) {
178093db446aSBoris Brezillon 		disable_irq_nosync(host->irq);
178193db446aSBoris Brezillon 		host->devtype_data->irq_control(host, 1);
178293db446aSBoris Brezillon 	}
178393db446aSBoris Brezillon 
178496fa8e6eSMiquel Raynal 	/* Scan the NAND device */
17857b6a9b28SBoris Brezillon 	this->legacy.dummy_controller.ops = &mxcnd_controller_ops;
178600ad378fSBoris Brezillon 	err = nand_scan(this, is_imx25_nfc(host) ? 4 : 1);
178793db446aSBoris Brezillon 	if (err)
178893db446aSBoris Brezillon 		goto escan;
178993db446aSBoris Brezillon 
179093db446aSBoris Brezillon 	/* Register the partitions */
17910f6b7919SFabio Estevam 	err = mtd_device_parse_register(mtd, part_probes, NULL, NULL, 0);
1792be051bf2SMiquel Raynal 	if (err)
1793be051bf2SMiquel Raynal 		goto cleanup_nand;
179493db446aSBoris Brezillon 
179593db446aSBoris Brezillon 	platform_set_drvdata(pdev, host);
179693db446aSBoris Brezillon 
179793db446aSBoris Brezillon 	return 0;
179893db446aSBoris Brezillon 
1799be051bf2SMiquel Raynal cleanup_nand:
1800be051bf2SMiquel Raynal 	nand_cleanup(this);
180193db446aSBoris Brezillon escan:
180293db446aSBoris Brezillon 	if (host->clk_act)
180393db446aSBoris Brezillon 		clk_disable_unprepare(host->clk);
180493db446aSBoris Brezillon 
180593db446aSBoris Brezillon 	return err;
180693db446aSBoris Brezillon }
180793db446aSBoris Brezillon 
mxcnd_remove(struct platform_device * pdev)1808ec185b18SUwe Kleine-König static void mxcnd_remove(struct platform_device *pdev)
180993db446aSBoris Brezillon {
181093db446aSBoris Brezillon 	struct mxc_nand_host *host = platform_get_drvdata(pdev);
1811c6dc0827SMiquel Raynal 	struct nand_chip *chip = &host->nand;
1812c6dc0827SMiquel Raynal 	int ret;
181393db446aSBoris Brezillon 
1814c6dc0827SMiquel Raynal 	ret = mtd_device_unregister(nand_to_mtd(chip));
1815c6dc0827SMiquel Raynal 	WARN_ON(ret);
1816c6dc0827SMiquel Raynal 	nand_cleanup(chip);
181793db446aSBoris Brezillon 	if (host->clk_act)
181893db446aSBoris Brezillon 		clk_disable_unprepare(host->clk);
181993db446aSBoris Brezillon }
182093db446aSBoris Brezillon 
182193db446aSBoris Brezillon static struct platform_driver mxcnd_driver = {
182293db446aSBoris Brezillon 	.driver = {
182393db446aSBoris Brezillon 		   .name = DRIVER_NAME,
18241200c7f8SFabio Estevam 		   .of_match_table = mxcnd_dt_ids,
182593db446aSBoris Brezillon 	},
182693db446aSBoris Brezillon 	.probe = mxcnd_probe,
1827ec185b18SUwe Kleine-König 	.remove_new = mxcnd_remove,
182893db446aSBoris Brezillon };
182993db446aSBoris Brezillon module_platform_driver(mxcnd_driver);
183093db446aSBoris Brezillon 
183193db446aSBoris Brezillon MODULE_AUTHOR("Freescale Semiconductor, Inc.");
183293db446aSBoris Brezillon MODULE_DESCRIPTION("MXC NAND MTD driver");
183393db446aSBoris Brezillon MODULE_LICENSE("GPL");
1834