xref: /rk3399_rockchip-uboot/drivers/mtd/nand/raw/vf610_nfc.c (revision 251a3b836012a99dea07f6687715d916d760f550)
1cfcc706cSMiquel Raynal /*
2cfcc706cSMiquel Raynal  * Copyright 2009-2015 Freescale Semiconductor, Inc. and others
3cfcc706cSMiquel Raynal  *
4cfcc706cSMiquel Raynal  * Description: MPC5125, VF610, MCF54418 and Kinetis K70 Nand driver.
5cfcc706cSMiquel Raynal  * Ported to U-Boot by Stefan Agner
6cfcc706cSMiquel Raynal  * Based on RFC driver posted on Kernel Mailing list by Bill Pringlemeir
7cfcc706cSMiquel Raynal  * Jason ported to M54418TWR and MVFA5.
8cfcc706cSMiquel Raynal  * Authors: Stefan Agner <stefan.agner@toradex.com>
9cfcc706cSMiquel Raynal  *          Bill Pringlemeir <bpringlemeir@nbsps.com>
10cfcc706cSMiquel Raynal  *          Shaohui Xie <b21989@freescale.com>
11cfcc706cSMiquel Raynal  *          Jason Jin <Jason.jin@freescale.com>
12cfcc706cSMiquel Raynal  *
13cfcc706cSMiquel Raynal  * Based on original driver mpc5121_nfc.c.
14cfcc706cSMiquel Raynal  *
15cfcc706cSMiquel Raynal  * SPDX-License-Identifier:	GPL-2.0+
16cfcc706cSMiquel Raynal  *
17cfcc706cSMiquel Raynal  * Limitations:
18cfcc706cSMiquel Raynal  * - Untested on MPC5125 and M54418.
19cfcc706cSMiquel Raynal  * - DMA and pipelining not used.
20cfcc706cSMiquel Raynal  * - 2K pages or less.
21cfcc706cSMiquel Raynal  * - HW ECC: Only 2K page with 64+ OOB.
22cfcc706cSMiquel Raynal  * - HW ECC: Only 24 and 32-bit error correction implemented.
23cfcc706cSMiquel Raynal  */
24cfcc706cSMiquel Raynal 
25cfcc706cSMiquel Raynal #include <common.h>
26cfcc706cSMiquel Raynal #include <malloc.h>
27cfcc706cSMiquel Raynal 
28cfcc706cSMiquel Raynal #include <linux/mtd/mtd.h>
29cfcc706cSMiquel Raynal #include <linux/mtd/rawnand.h>
30cfcc706cSMiquel Raynal #include <linux/mtd/partitions.h>
31cfcc706cSMiquel Raynal 
32cfcc706cSMiquel Raynal #include <nand.h>
33cfcc706cSMiquel Raynal #include <errno.h>
34cfcc706cSMiquel Raynal #include <asm/io.h>
35*251a3b83SLukasz Majewski #if CONFIG_NAND_VF610_NFC_DT
36*251a3b83SLukasz Majewski #include <dm.h>
37*251a3b83SLukasz Majewski #include <linux/io.h>
38*251a3b83SLukasz Majewski #include <linux/ioport.h>
39*251a3b83SLukasz Majewski #endif
40cfcc706cSMiquel Raynal 
41cfcc706cSMiquel Raynal /* Register Offsets */
42cfcc706cSMiquel Raynal #define NFC_FLASH_CMD1			0x3F00
43cfcc706cSMiquel Raynal #define NFC_FLASH_CMD2			0x3F04
44cfcc706cSMiquel Raynal #define NFC_COL_ADDR			0x3F08
45cfcc706cSMiquel Raynal #define NFC_ROW_ADDR			0x3F0c
46cfcc706cSMiquel Raynal #define NFC_ROW_ADDR_INC		0x3F14
47cfcc706cSMiquel Raynal #define NFC_FLASH_STATUS1		0x3F18
48cfcc706cSMiquel Raynal #define NFC_FLASH_STATUS2		0x3F1c
49cfcc706cSMiquel Raynal #define NFC_CACHE_SWAP			0x3F28
50cfcc706cSMiquel Raynal #define NFC_SECTOR_SIZE			0x3F2c
51cfcc706cSMiquel Raynal #define NFC_FLASH_CONFIG		0x3F30
52cfcc706cSMiquel Raynal #define NFC_IRQ_STATUS			0x3F38
53cfcc706cSMiquel Raynal 
54cfcc706cSMiquel Raynal /* Addresses for NFC MAIN RAM BUFFER areas */
55cfcc706cSMiquel Raynal #define NFC_MAIN_AREA(n)		((n) *  0x1000)
56cfcc706cSMiquel Raynal 
57cfcc706cSMiquel Raynal #define PAGE_2K				0x0800
58cfcc706cSMiquel Raynal #define OOB_64				0x0040
59cfcc706cSMiquel Raynal #define OOB_MAX				0x0100
60cfcc706cSMiquel Raynal 
61cfcc706cSMiquel Raynal /*
62cfcc706cSMiquel Raynal  * NFC_CMD2[CODE] values. See section:
63cfcc706cSMiquel Raynal  *  - 31.4.7 Flash Command Code Description, Vybrid manual
64cfcc706cSMiquel Raynal  *  - 23.8.6 Flash Command Sequencer, MPC5125 manual
65cfcc706cSMiquel Raynal  *
66cfcc706cSMiquel Raynal  * Briefly these are bitmasks of controller cycles.
67cfcc706cSMiquel Raynal  */
68cfcc706cSMiquel Raynal #define READ_PAGE_CMD_CODE		0x7EE0
69cfcc706cSMiquel Raynal #define READ_ONFI_PARAM_CMD_CODE	0x4860
70cfcc706cSMiquel Raynal #define PROGRAM_PAGE_CMD_CODE		0x7FC0
71cfcc706cSMiquel Raynal #define ERASE_CMD_CODE			0x4EC0
72cfcc706cSMiquel Raynal #define READ_ID_CMD_CODE		0x4804
73cfcc706cSMiquel Raynal #define RESET_CMD_CODE			0x4040
74cfcc706cSMiquel Raynal #define STATUS_READ_CMD_CODE		0x4068
75cfcc706cSMiquel Raynal 
76cfcc706cSMiquel Raynal /* NFC ECC mode define */
77cfcc706cSMiquel Raynal #define ECC_BYPASS			0
78cfcc706cSMiquel Raynal #define ECC_45_BYTE			6
79cfcc706cSMiquel Raynal #define ECC_60_BYTE			7
80cfcc706cSMiquel Raynal 
81cfcc706cSMiquel Raynal /*** Register Mask and bit definitions */
82cfcc706cSMiquel Raynal 
83cfcc706cSMiquel Raynal /* NFC_FLASH_CMD1 Field */
84cfcc706cSMiquel Raynal #define CMD_BYTE2_MASK				0xFF000000
85cfcc706cSMiquel Raynal #define CMD_BYTE2_SHIFT				24
86cfcc706cSMiquel Raynal 
87cfcc706cSMiquel Raynal /* NFC_FLASH_CM2 Field */
88cfcc706cSMiquel Raynal #define CMD_BYTE1_MASK				0xFF000000
89cfcc706cSMiquel Raynal #define CMD_BYTE1_SHIFT				24
90cfcc706cSMiquel Raynal #define CMD_CODE_MASK				0x00FFFF00
91cfcc706cSMiquel Raynal #define CMD_CODE_SHIFT				8
92cfcc706cSMiquel Raynal #define BUFNO_MASK				0x00000006
93cfcc706cSMiquel Raynal #define BUFNO_SHIFT				1
94cfcc706cSMiquel Raynal #define START_BIT				(1<<0)
95cfcc706cSMiquel Raynal 
96cfcc706cSMiquel Raynal /* NFC_COL_ADDR Field */
97cfcc706cSMiquel Raynal #define COL_ADDR_MASK				0x0000FFFF
98cfcc706cSMiquel Raynal #define COL_ADDR_SHIFT				0
99cfcc706cSMiquel Raynal 
100cfcc706cSMiquel Raynal /* NFC_ROW_ADDR Field */
101cfcc706cSMiquel Raynal #define ROW_ADDR_MASK				0x00FFFFFF
102cfcc706cSMiquel Raynal #define ROW_ADDR_SHIFT				0
103cfcc706cSMiquel Raynal #define ROW_ADDR_CHIP_SEL_RB_MASK		0xF0000000
104cfcc706cSMiquel Raynal #define ROW_ADDR_CHIP_SEL_RB_SHIFT		28
105cfcc706cSMiquel Raynal #define ROW_ADDR_CHIP_SEL_MASK			0x0F000000
106cfcc706cSMiquel Raynal #define ROW_ADDR_CHIP_SEL_SHIFT			24
107cfcc706cSMiquel Raynal 
108cfcc706cSMiquel Raynal /* NFC_FLASH_STATUS2 Field */
109cfcc706cSMiquel Raynal #define STATUS_BYTE1_MASK			0x000000FF
110cfcc706cSMiquel Raynal 
111cfcc706cSMiquel Raynal /* NFC_FLASH_CONFIG Field */
112cfcc706cSMiquel Raynal #define CONFIG_ECC_SRAM_ADDR_MASK		0x7FC00000
113cfcc706cSMiquel Raynal #define CONFIG_ECC_SRAM_ADDR_SHIFT		22
114cfcc706cSMiquel Raynal #define CONFIG_ECC_SRAM_REQ_BIT			(1<<21)
115cfcc706cSMiquel Raynal #define CONFIG_DMA_REQ_BIT			(1<<20)
116cfcc706cSMiquel Raynal #define CONFIG_ECC_MODE_MASK			0x000E0000
117cfcc706cSMiquel Raynal #define CONFIG_ECC_MODE_SHIFT			17
118cfcc706cSMiquel Raynal #define CONFIG_FAST_FLASH_BIT			(1<<16)
119cfcc706cSMiquel Raynal #define CONFIG_16BIT				(1<<7)
120cfcc706cSMiquel Raynal #define CONFIG_BOOT_MODE_BIT			(1<<6)
121cfcc706cSMiquel Raynal #define CONFIG_ADDR_AUTO_INCR_BIT		(1<<5)
122cfcc706cSMiquel Raynal #define CONFIG_BUFNO_AUTO_INCR_BIT		(1<<4)
123cfcc706cSMiquel Raynal #define CONFIG_PAGE_CNT_MASK			0xF
124cfcc706cSMiquel Raynal #define CONFIG_PAGE_CNT_SHIFT			0
125cfcc706cSMiquel Raynal 
126cfcc706cSMiquel Raynal /* NFC_IRQ_STATUS Field */
127cfcc706cSMiquel Raynal #define IDLE_IRQ_BIT				(1<<29)
128cfcc706cSMiquel Raynal #define IDLE_EN_BIT				(1<<20)
129cfcc706cSMiquel Raynal #define CMD_DONE_CLEAR_BIT			(1<<18)
130cfcc706cSMiquel Raynal #define IDLE_CLEAR_BIT				(1<<17)
131cfcc706cSMiquel Raynal 
132cfcc706cSMiquel Raynal #define NFC_TIMEOUT	(1000)
133cfcc706cSMiquel Raynal 
134cfcc706cSMiquel Raynal /*
135cfcc706cSMiquel Raynal  * ECC status - seems to consume 8 bytes (double word). The documented
136cfcc706cSMiquel Raynal  * status byte is located in the lowest byte of the second word (which is
137cfcc706cSMiquel Raynal  * the 4th or 7th byte depending on endianness).
138cfcc706cSMiquel Raynal  * Calculate an offset to store the ECC status at the end of the buffer.
139cfcc706cSMiquel Raynal  */
140cfcc706cSMiquel Raynal #define ECC_SRAM_ADDR		(PAGE_2K + OOB_MAX - 8)
141cfcc706cSMiquel Raynal 
142cfcc706cSMiquel Raynal #define ECC_STATUS		0x4
143cfcc706cSMiquel Raynal #define ECC_STATUS_MASK		0x80
144cfcc706cSMiquel Raynal #define ECC_STATUS_ERR_COUNT	0x3F
145cfcc706cSMiquel Raynal 
146cfcc706cSMiquel Raynal enum vf610_nfc_alt_buf {
147cfcc706cSMiquel Raynal 	ALT_BUF_DATA = 0,
148cfcc706cSMiquel Raynal 	ALT_BUF_ID = 1,
149cfcc706cSMiquel Raynal 	ALT_BUF_STAT = 2,
150cfcc706cSMiquel Raynal 	ALT_BUF_ONFI = 3,
151cfcc706cSMiquel Raynal };
152cfcc706cSMiquel Raynal 
153cfcc706cSMiquel Raynal struct vf610_nfc {
154cfcc706cSMiquel Raynal 	struct nand_chip chip;
155cfcc706cSMiquel Raynal 	void __iomem *regs;
156cfcc706cSMiquel Raynal 	uint buf_offset;
157cfcc706cSMiquel Raynal 	int write_sz;
158cfcc706cSMiquel Raynal 	/* Status and ID are in alternate locations. */
159cfcc706cSMiquel Raynal 	enum vf610_nfc_alt_buf alt_buf;
160cfcc706cSMiquel Raynal };
161cfcc706cSMiquel Raynal 
162cfcc706cSMiquel Raynal #define mtd_to_nfc(_mtd) nand_get_controller_data(mtd_to_nand(_mtd))
163cfcc706cSMiquel Raynal 
164cfcc706cSMiquel Raynal #if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES)
165cfcc706cSMiquel Raynal #define ECC_HW_MODE ECC_45_BYTE
166cfcc706cSMiquel Raynal 
167cfcc706cSMiquel Raynal static struct nand_ecclayout vf610_nfc_ecc = {
168cfcc706cSMiquel Raynal 	.eccbytes = 45,
169cfcc706cSMiquel Raynal 	.eccpos = {19, 20, 21, 22, 23,
170cfcc706cSMiquel Raynal 		   24, 25, 26, 27, 28, 29, 30, 31,
171cfcc706cSMiquel Raynal 		   32, 33, 34, 35, 36, 37, 38, 39,
172cfcc706cSMiquel Raynal 		   40, 41, 42, 43, 44, 45, 46, 47,
173cfcc706cSMiquel Raynal 		   48, 49, 50, 51, 52, 53, 54, 55,
174cfcc706cSMiquel Raynal 		   56, 57, 58, 59, 60, 61, 62, 63},
175cfcc706cSMiquel Raynal 	.oobfree = {
176cfcc706cSMiquel Raynal 		{.offset = 2,
177cfcc706cSMiquel Raynal 		 .length = 17} }
178cfcc706cSMiquel Raynal };
179cfcc706cSMiquel Raynal #elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES)
180cfcc706cSMiquel Raynal #define ECC_HW_MODE ECC_60_BYTE
181cfcc706cSMiquel Raynal 
182cfcc706cSMiquel Raynal static struct nand_ecclayout vf610_nfc_ecc = {
183cfcc706cSMiquel Raynal 	.eccbytes = 60,
184cfcc706cSMiquel Raynal 	.eccpos = { 4,  5,  6,  7,  8,  9, 10, 11,
185cfcc706cSMiquel Raynal 		   12, 13, 14, 15, 16, 17, 18, 19,
186cfcc706cSMiquel Raynal 		   20, 21, 22, 23, 24, 25, 26, 27,
187cfcc706cSMiquel Raynal 		   28, 29, 30, 31, 32, 33, 34, 35,
188cfcc706cSMiquel Raynal 		   36, 37, 38, 39, 40, 41, 42, 43,
189cfcc706cSMiquel Raynal 		   44, 45, 46, 47, 48, 49, 50, 51,
190cfcc706cSMiquel Raynal 		   52, 53, 54, 55, 56, 57, 58, 59,
191cfcc706cSMiquel Raynal 		   60, 61, 62, 63 },
192cfcc706cSMiquel Raynal 	.oobfree = {
193cfcc706cSMiquel Raynal 		{.offset = 2,
194cfcc706cSMiquel Raynal 		 .length = 2} }
195cfcc706cSMiquel Raynal };
196cfcc706cSMiquel Raynal #endif
197cfcc706cSMiquel Raynal 
vf610_nfc_read(struct mtd_info * mtd,uint reg)198cfcc706cSMiquel Raynal static inline u32 vf610_nfc_read(struct mtd_info *mtd, uint reg)
199cfcc706cSMiquel Raynal {
200cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
201cfcc706cSMiquel Raynal 
202cfcc706cSMiquel Raynal 	return readl(nfc->regs + reg);
203cfcc706cSMiquel Raynal }
204cfcc706cSMiquel Raynal 
vf610_nfc_write(struct mtd_info * mtd,uint reg,u32 val)205cfcc706cSMiquel Raynal static inline void vf610_nfc_write(struct mtd_info *mtd, uint reg, u32 val)
206cfcc706cSMiquel Raynal {
207cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
208cfcc706cSMiquel Raynal 
209cfcc706cSMiquel Raynal 	writel(val, nfc->regs + reg);
210cfcc706cSMiquel Raynal }
211cfcc706cSMiquel Raynal 
vf610_nfc_set(struct mtd_info * mtd,uint reg,u32 bits)212cfcc706cSMiquel Raynal static inline void vf610_nfc_set(struct mtd_info *mtd, uint reg, u32 bits)
213cfcc706cSMiquel Raynal {
214cfcc706cSMiquel Raynal 	vf610_nfc_write(mtd, reg, vf610_nfc_read(mtd, reg) | bits);
215cfcc706cSMiquel Raynal }
216cfcc706cSMiquel Raynal 
vf610_nfc_clear(struct mtd_info * mtd,uint reg,u32 bits)217cfcc706cSMiquel Raynal static inline void vf610_nfc_clear(struct mtd_info *mtd, uint reg, u32 bits)
218cfcc706cSMiquel Raynal {
219cfcc706cSMiquel Raynal 	vf610_nfc_write(mtd, reg, vf610_nfc_read(mtd, reg) & ~bits);
220cfcc706cSMiquel Raynal }
221cfcc706cSMiquel Raynal 
vf610_nfc_set_field(struct mtd_info * mtd,u32 reg,u32 mask,u32 shift,u32 val)222cfcc706cSMiquel Raynal static inline void vf610_nfc_set_field(struct mtd_info *mtd, u32 reg,
223cfcc706cSMiquel Raynal 				       u32 mask, u32 shift, u32 val)
224cfcc706cSMiquel Raynal {
225cfcc706cSMiquel Raynal 	vf610_nfc_write(mtd, reg,
226cfcc706cSMiquel Raynal 			(vf610_nfc_read(mtd, reg) & (~mask)) | val << shift);
227cfcc706cSMiquel Raynal }
228cfcc706cSMiquel Raynal 
vf610_nfc_memcpy(void * dst,const void * src,size_t n)229cfcc706cSMiquel Raynal static inline void vf610_nfc_memcpy(void *dst, const void *src, size_t n)
230cfcc706cSMiquel Raynal {
231cfcc706cSMiquel Raynal 	/*
232cfcc706cSMiquel Raynal 	 * Use this accessor for the internal SRAM buffers. On the ARM
233cfcc706cSMiquel Raynal 	 * Freescale Vybrid SoC it's known that the driver can treat
234cfcc706cSMiquel Raynal 	 * the SRAM buffer as if it's memory. Other platform might need
235cfcc706cSMiquel Raynal 	 * to treat the buffers differently.
236cfcc706cSMiquel Raynal 	 *
237cfcc706cSMiquel Raynal 	 * For the time being, use memcpy
238cfcc706cSMiquel Raynal 	 */
239cfcc706cSMiquel Raynal 	memcpy(dst, src, n);
240cfcc706cSMiquel Raynal }
241cfcc706cSMiquel Raynal 
242cfcc706cSMiquel Raynal /* Clear flags for upcoming command */
vf610_nfc_clear_status(void __iomem * regbase)243cfcc706cSMiquel Raynal static inline void vf610_nfc_clear_status(void __iomem *regbase)
244cfcc706cSMiquel Raynal {
245cfcc706cSMiquel Raynal 	void __iomem *reg = regbase + NFC_IRQ_STATUS;
246cfcc706cSMiquel Raynal 	u32 tmp = __raw_readl(reg);
247cfcc706cSMiquel Raynal 	tmp |= CMD_DONE_CLEAR_BIT | IDLE_CLEAR_BIT;
248cfcc706cSMiquel Raynal 	__raw_writel(tmp, reg);
249cfcc706cSMiquel Raynal }
250cfcc706cSMiquel Raynal 
251cfcc706cSMiquel Raynal /* Wait for complete operation */
vf610_nfc_done(struct mtd_info * mtd)252cfcc706cSMiquel Raynal static void vf610_nfc_done(struct mtd_info *mtd)
253cfcc706cSMiquel Raynal {
254cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
255cfcc706cSMiquel Raynal 	uint start;
256cfcc706cSMiquel Raynal 
257cfcc706cSMiquel Raynal 	/*
258cfcc706cSMiquel Raynal 	 * Barrier is needed after this write. This write need
259cfcc706cSMiquel Raynal 	 * to be done before reading the next register the first
260cfcc706cSMiquel Raynal 	 * time.
261cfcc706cSMiquel Raynal 	 * vf610_nfc_set implicates such a barrier by using writel
262cfcc706cSMiquel Raynal 	 * to write to the register.
263cfcc706cSMiquel Raynal 	 */
264cfcc706cSMiquel Raynal 	vf610_nfc_set(mtd, NFC_FLASH_CMD2, START_BIT);
265cfcc706cSMiquel Raynal 
266cfcc706cSMiquel Raynal 	start = get_timer(0);
267cfcc706cSMiquel Raynal 
268cfcc706cSMiquel Raynal 	while (!(vf610_nfc_read(mtd, NFC_IRQ_STATUS) & IDLE_IRQ_BIT)) {
269cfcc706cSMiquel Raynal 		if (get_timer(start) > NFC_TIMEOUT) {
270cfcc706cSMiquel Raynal 			printf("Timeout while waiting for IDLE.\n");
271cfcc706cSMiquel Raynal 			return;
272cfcc706cSMiquel Raynal 		}
273cfcc706cSMiquel Raynal 	}
274cfcc706cSMiquel Raynal 	vf610_nfc_clear_status(nfc->regs);
275cfcc706cSMiquel Raynal }
276cfcc706cSMiquel Raynal 
vf610_nfc_get_id(struct mtd_info * mtd,int col)277cfcc706cSMiquel Raynal static u8 vf610_nfc_get_id(struct mtd_info *mtd, int col)
278cfcc706cSMiquel Raynal {
279cfcc706cSMiquel Raynal 	u32 flash_id;
280cfcc706cSMiquel Raynal 
281cfcc706cSMiquel Raynal 	if (col < 4) {
282cfcc706cSMiquel Raynal 		flash_id = vf610_nfc_read(mtd, NFC_FLASH_STATUS1);
283cfcc706cSMiquel Raynal 		flash_id >>= (3 - col) * 8;
284cfcc706cSMiquel Raynal 	} else {
285cfcc706cSMiquel Raynal 		flash_id = vf610_nfc_read(mtd, NFC_FLASH_STATUS2);
286cfcc706cSMiquel Raynal 		flash_id >>= 24;
287cfcc706cSMiquel Raynal 	}
288cfcc706cSMiquel Raynal 
289cfcc706cSMiquel Raynal 	return flash_id & 0xff;
290cfcc706cSMiquel Raynal }
291cfcc706cSMiquel Raynal 
vf610_nfc_get_status(struct mtd_info * mtd)292cfcc706cSMiquel Raynal static u8 vf610_nfc_get_status(struct mtd_info *mtd)
293cfcc706cSMiquel Raynal {
294cfcc706cSMiquel Raynal 	return vf610_nfc_read(mtd, NFC_FLASH_STATUS2) & STATUS_BYTE1_MASK;
295cfcc706cSMiquel Raynal }
296cfcc706cSMiquel Raynal 
297cfcc706cSMiquel Raynal /* Single command */
vf610_nfc_send_command(void __iomem * regbase,u32 cmd_byte1,u32 cmd_code)298cfcc706cSMiquel Raynal static void vf610_nfc_send_command(void __iomem *regbase, u32 cmd_byte1,
299cfcc706cSMiquel Raynal 				   u32 cmd_code)
300cfcc706cSMiquel Raynal {
301cfcc706cSMiquel Raynal 	void __iomem *reg = regbase + NFC_FLASH_CMD2;
302cfcc706cSMiquel Raynal 	u32 tmp;
303cfcc706cSMiquel Raynal 	vf610_nfc_clear_status(regbase);
304cfcc706cSMiquel Raynal 
305cfcc706cSMiquel Raynal 	tmp = __raw_readl(reg);
306cfcc706cSMiquel Raynal 	tmp &= ~(CMD_BYTE1_MASK | CMD_CODE_MASK | BUFNO_MASK);
307cfcc706cSMiquel Raynal 	tmp |= cmd_byte1 << CMD_BYTE1_SHIFT;
308cfcc706cSMiquel Raynal 	tmp |= cmd_code << CMD_CODE_SHIFT;
309cfcc706cSMiquel Raynal 	__raw_writel(tmp, reg);
310cfcc706cSMiquel Raynal }
311cfcc706cSMiquel Raynal 
312cfcc706cSMiquel Raynal /* Two commands */
vf610_nfc_send_commands(void __iomem * regbase,u32 cmd_byte1,u32 cmd_byte2,u32 cmd_code)313cfcc706cSMiquel Raynal static void vf610_nfc_send_commands(void __iomem *regbase, u32 cmd_byte1,
314cfcc706cSMiquel Raynal 			      u32 cmd_byte2, u32 cmd_code)
315cfcc706cSMiquel Raynal {
316cfcc706cSMiquel Raynal 	void __iomem *reg = regbase + NFC_FLASH_CMD1;
317cfcc706cSMiquel Raynal 	u32 tmp;
318cfcc706cSMiquel Raynal 	vf610_nfc_send_command(regbase, cmd_byte1, cmd_code);
319cfcc706cSMiquel Raynal 
320cfcc706cSMiquel Raynal 	tmp = __raw_readl(reg);
321cfcc706cSMiquel Raynal 	tmp &= ~CMD_BYTE2_MASK;
322cfcc706cSMiquel Raynal 	tmp |= cmd_byte2 << CMD_BYTE2_SHIFT;
323cfcc706cSMiquel Raynal 	__raw_writel(tmp, reg);
324cfcc706cSMiquel Raynal }
325cfcc706cSMiquel Raynal 
vf610_nfc_addr_cycle(struct mtd_info * mtd,int column,int page)326cfcc706cSMiquel Raynal static void vf610_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
327cfcc706cSMiquel Raynal {
328cfcc706cSMiquel Raynal 	if (column != -1) {
329cfcc706cSMiquel Raynal 		struct vf610_nfc *nfc = mtd_to_nfc(mtd);
330cfcc706cSMiquel Raynal 		if (nfc->chip.options & NAND_BUSWIDTH_16)
331cfcc706cSMiquel Raynal 			column = column / 2;
332cfcc706cSMiquel Raynal 		vf610_nfc_set_field(mtd, NFC_COL_ADDR, COL_ADDR_MASK,
333cfcc706cSMiquel Raynal 				    COL_ADDR_SHIFT, column);
334cfcc706cSMiquel Raynal 	}
335cfcc706cSMiquel Raynal 	if (page != -1)
336cfcc706cSMiquel Raynal 		vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK,
337cfcc706cSMiquel Raynal 				    ROW_ADDR_SHIFT, page);
338cfcc706cSMiquel Raynal }
339cfcc706cSMiquel Raynal 
vf610_nfc_ecc_mode(struct mtd_info * mtd,int ecc_mode)340cfcc706cSMiquel Raynal static inline void vf610_nfc_ecc_mode(struct mtd_info *mtd, int ecc_mode)
341cfcc706cSMiquel Raynal {
342cfcc706cSMiquel Raynal 	vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG,
343cfcc706cSMiquel Raynal 			    CONFIG_ECC_MODE_MASK,
344cfcc706cSMiquel Raynal 			    CONFIG_ECC_MODE_SHIFT, ecc_mode);
345cfcc706cSMiquel Raynal }
346cfcc706cSMiquel Raynal 
vf610_nfc_transfer_size(void __iomem * regbase,int size)347cfcc706cSMiquel Raynal static inline void vf610_nfc_transfer_size(void __iomem *regbase, int size)
348cfcc706cSMiquel Raynal {
349cfcc706cSMiquel Raynal 	__raw_writel(size, regbase + NFC_SECTOR_SIZE);
350cfcc706cSMiquel Raynal }
351cfcc706cSMiquel Raynal 
352cfcc706cSMiquel Raynal /* Send command to NAND chip */
vf610_nfc_command(struct mtd_info * mtd,unsigned command,int column,int page)353cfcc706cSMiquel Raynal static void vf610_nfc_command(struct mtd_info *mtd, unsigned command,
354cfcc706cSMiquel Raynal 			      int column, int page)
355cfcc706cSMiquel Raynal {
356cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
357cfcc706cSMiquel Raynal 	int trfr_sz = nfc->chip.options & NAND_BUSWIDTH_16 ? 1 : 0;
358cfcc706cSMiquel Raynal 
359cfcc706cSMiquel Raynal 	nfc->buf_offset = max(column, 0);
360cfcc706cSMiquel Raynal 	nfc->alt_buf = ALT_BUF_DATA;
361cfcc706cSMiquel Raynal 
362cfcc706cSMiquel Raynal 	switch (command) {
363cfcc706cSMiquel Raynal 	case NAND_CMD_SEQIN:
364cfcc706cSMiquel Raynal 		/* Use valid column/page from preread... */
365cfcc706cSMiquel Raynal 		vf610_nfc_addr_cycle(mtd, column, page);
366cfcc706cSMiquel Raynal 		nfc->buf_offset = 0;
367cfcc706cSMiquel Raynal 
368cfcc706cSMiquel Raynal 		/*
369cfcc706cSMiquel Raynal 		 * SEQIN => data => PAGEPROG sequence is done by the controller
370cfcc706cSMiquel Raynal 		 * hence we do not need to issue the command here...
371cfcc706cSMiquel Raynal 		 */
372cfcc706cSMiquel Raynal 		return;
373cfcc706cSMiquel Raynal 	case NAND_CMD_PAGEPROG:
374cfcc706cSMiquel Raynal 		trfr_sz += nfc->write_sz;
375cfcc706cSMiquel Raynal 		vf610_nfc_ecc_mode(mtd, ECC_HW_MODE);
376cfcc706cSMiquel Raynal 		vf610_nfc_transfer_size(nfc->regs, trfr_sz);
377cfcc706cSMiquel Raynal 		vf610_nfc_send_commands(nfc->regs, NAND_CMD_SEQIN,
378cfcc706cSMiquel Raynal 					command, PROGRAM_PAGE_CMD_CODE);
379cfcc706cSMiquel Raynal 		break;
380cfcc706cSMiquel Raynal 
381cfcc706cSMiquel Raynal 	case NAND_CMD_RESET:
382cfcc706cSMiquel Raynal 		vf610_nfc_transfer_size(nfc->regs, 0);
383cfcc706cSMiquel Raynal 		vf610_nfc_send_command(nfc->regs, command, RESET_CMD_CODE);
384cfcc706cSMiquel Raynal 		break;
385cfcc706cSMiquel Raynal 
386cfcc706cSMiquel Raynal 	case NAND_CMD_READOOB:
387cfcc706cSMiquel Raynal 		trfr_sz += mtd->oobsize;
388cfcc706cSMiquel Raynal 		column = mtd->writesize;
389cfcc706cSMiquel Raynal 		vf610_nfc_transfer_size(nfc->regs, trfr_sz);
390cfcc706cSMiquel Raynal 		vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0,
391cfcc706cSMiquel Raynal 					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
392cfcc706cSMiquel Raynal 		vf610_nfc_addr_cycle(mtd, column, page);
393cfcc706cSMiquel Raynal 		vf610_nfc_ecc_mode(mtd, ECC_BYPASS);
394cfcc706cSMiquel Raynal 		break;
395cfcc706cSMiquel Raynal 
396cfcc706cSMiquel Raynal 	case NAND_CMD_READ0:
397cfcc706cSMiquel Raynal 		trfr_sz += mtd->writesize + mtd->oobsize;
398cfcc706cSMiquel Raynal 		vf610_nfc_transfer_size(nfc->regs, trfr_sz);
399cfcc706cSMiquel Raynal 		vf610_nfc_ecc_mode(mtd, ECC_HW_MODE);
400cfcc706cSMiquel Raynal 		vf610_nfc_send_commands(nfc->regs, NAND_CMD_READ0,
401cfcc706cSMiquel Raynal 					NAND_CMD_READSTART, READ_PAGE_CMD_CODE);
402cfcc706cSMiquel Raynal 		vf610_nfc_addr_cycle(mtd, column, page);
403cfcc706cSMiquel Raynal 		break;
404cfcc706cSMiquel Raynal 
405cfcc706cSMiquel Raynal 	case NAND_CMD_PARAM:
406cfcc706cSMiquel Raynal 		nfc->alt_buf = ALT_BUF_ONFI;
407cfcc706cSMiquel Raynal 		trfr_sz = 3 * sizeof(struct nand_onfi_params);
408cfcc706cSMiquel Raynal 		vf610_nfc_transfer_size(nfc->regs, trfr_sz);
409cfcc706cSMiquel Raynal 		vf610_nfc_send_command(nfc->regs, NAND_CMD_PARAM,
410cfcc706cSMiquel Raynal 				       READ_ONFI_PARAM_CMD_CODE);
411cfcc706cSMiquel Raynal 		vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK,
412cfcc706cSMiquel Raynal 				    ROW_ADDR_SHIFT, column);
413cfcc706cSMiquel Raynal 		vf610_nfc_ecc_mode(mtd, ECC_BYPASS);
414cfcc706cSMiquel Raynal 		break;
415cfcc706cSMiquel Raynal 
416cfcc706cSMiquel Raynal 	case NAND_CMD_ERASE1:
417cfcc706cSMiquel Raynal 		vf610_nfc_transfer_size(nfc->regs, 0);
418cfcc706cSMiquel Raynal 		vf610_nfc_send_commands(nfc->regs, command,
419cfcc706cSMiquel Raynal 					NAND_CMD_ERASE2, ERASE_CMD_CODE);
420cfcc706cSMiquel Raynal 		vf610_nfc_addr_cycle(mtd, column, page);
421cfcc706cSMiquel Raynal 		break;
422cfcc706cSMiquel Raynal 
423cfcc706cSMiquel Raynal 	case NAND_CMD_READID:
424cfcc706cSMiquel Raynal 		nfc->alt_buf = ALT_BUF_ID;
425cfcc706cSMiquel Raynal 		nfc->buf_offset = 0;
426cfcc706cSMiquel Raynal 		vf610_nfc_transfer_size(nfc->regs, 0);
427cfcc706cSMiquel Raynal 		vf610_nfc_send_command(nfc->regs, command, READ_ID_CMD_CODE);
428cfcc706cSMiquel Raynal 		vf610_nfc_set_field(mtd, NFC_ROW_ADDR, ROW_ADDR_MASK,
429cfcc706cSMiquel Raynal 				    ROW_ADDR_SHIFT, column);
430cfcc706cSMiquel Raynal 		break;
431cfcc706cSMiquel Raynal 
432cfcc706cSMiquel Raynal 	case NAND_CMD_STATUS:
433cfcc706cSMiquel Raynal 		nfc->alt_buf = ALT_BUF_STAT;
434cfcc706cSMiquel Raynal 		vf610_nfc_transfer_size(nfc->regs, 0);
435cfcc706cSMiquel Raynal 		vf610_nfc_send_command(nfc->regs, command, STATUS_READ_CMD_CODE);
436cfcc706cSMiquel Raynal 		break;
437cfcc706cSMiquel Raynal 	default:
438cfcc706cSMiquel Raynal 		return;
439cfcc706cSMiquel Raynal 	}
440cfcc706cSMiquel Raynal 
441cfcc706cSMiquel Raynal 	vf610_nfc_done(mtd);
442cfcc706cSMiquel Raynal 
443cfcc706cSMiquel Raynal 	nfc->write_sz = 0;
444cfcc706cSMiquel Raynal }
445cfcc706cSMiquel Raynal 
446cfcc706cSMiquel Raynal /* Read data from NFC buffers */
vf610_nfc_read_buf(struct mtd_info * mtd,u_char * buf,int len)447cfcc706cSMiquel Raynal static void vf610_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
448cfcc706cSMiquel Raynal {
449cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
450cfcc706cSMiquel Raynal 	uint c = nfc->buf_offset;
451cfcc706cSMiquel Raynal 
452cfcc706cSMiquel Raynal 	/* Alternate buffers are only supported through read_byte */
453cfcc706cSMiquel Raynal 	if (nfc->alt_buf)
454cfcc706cSMiquel Raynal 		return;
455cfcc706cSMiquel Raynal 
456cfcc706cSMiquel Raynal 	vf610_nfc_memcpy(buf, nfc->regs + NFC_MAIN_AREA(0) + c, len);
457cfcc706cSMiquel Raynal 
458cfcc706cSMiquel Raynal 	nfc->buf_offset += len;
459cfcc706cSMiquel Raynal }
460cfcc706cSMiquel Raynal 
461cfcc706cSMiquel Raynal /* Write data to NFC buffers */
vf610_nfc_write_buf(struct mtd_info * mtd,const uint8_t * buf,int len)462cfcc706cSMiquel Raynal static void vf610_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
463cfcc706cSMiquel Raynal 				int len)
464cfcc706cSMiquel Raynal {
465cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
466cfcc706cSMiquel Raynal 	uint c = nfc->buf_offset;
467cfcc706cSMiquel Raynal 	uint l;
468cfcc706cSMiquel Raynal 
469cfcc706cSMiquel Raynal 	l = min_t(uint, len, mtd->writesize + mtd->oobsize - c);
470cfcc706cSMiquel Raynal 	vf610_nfc_memcpy(nfc->regs + NFC_MAIN_AREA(0) + c, buf, l);
471cfcc706cSMiquel Raynal 
472cfcc706cSMiquel Raynal 	nfc->write_sz += l;
473cfcc706cSMiquel Raynal 	nfc->buf_offset += l;
474cfcc706cSMiquel Raynal }
475cfcc706cSMiquel Raynal 
476cfcc706cSMiquel Raynal /* Read byte from NFC buffers */
vf610_nfc_read_byte(struct mtd_info * mtd)477cfcc706cSMiquel Raynal static uint8_t vf610_nfc_read_byte(struct mtd_info *mtd)
478cfcc706cSMiquel Raynal {
479cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
480cfcc706cSMiquel Raynal 	u8 tmp;
481cfcc706cSMiquel Raynal 	uint c = nfc->buf_offset;
482cfcc706cSMiquel Raynal 
483cfcc706cSMiquel Raynal 	switch (nfc->alt_buf) {
484cfcc706cSMiquel Raynal 	case ALT_BUF_ID:
485cfcc706cSMiquel Raynal 		tmp = vf610_nfc_get_id(mtd, c);
486cfcc706cSMiquel Raynal 		break;
487cfcc706cSMiquel Raynal 	case ALT_BUF_STAT:
488cfcc706cSMiquel Raynal 		tmp = vf610_nfc_get_status(mtd);
489cfcc706cSMiquel Raynal 		break;
490cfcc706cSMiquel Raynal #ifdef __LITTLE_ENDIAN
491cfcc706cSMiquel Raynal 	case ALT_BUF_ONFI:
492cfcc706cSMiquel Raynal 		/* Reverse byte since the controller uses big endianness */
493cfcc706cSMiquel Raynal 		c = nfc->buf_offset ^ 0x3;
494cfcc706cSMiquel Raynal 		/* fall-through */
495cfcc706cSMiquel Raynal #endif
496cfcc706cSMiquel Raynal 	default:
497cfcc706cSMiquel Raynal 		tmp = *((u8 *)(nfc->regs + NFC_MAIN_AREA(0) + c));
498cfcc706cSMiquel Raynal 		break;
499cfcc706cSMiquel Raynal 	}
500cfcc706cSMiquel Raynal 	nfc->buf_offset++;
501cfcc706cSMiquel Raynal 	return tmp;
502cfcc706cSMiquel Raynal }
503cfcc706cSMiquel Raynal 
504cfcc706cSMiquel Raynal /* Read word from NFC buffers */
vf610_nfc_read_word(struct mtd_info * mtd)505cfcc706cSMiquel Raynal static u16 vf610_nfc_read_word(struct mtd_info *mtd)
506cfcc706cSMiquel Raynal {
507cfcc706cSMiquel Raynal 	u16 tmp;
508cfcc706cSMiquel Raynal 
509cfcc706cSMiquel Raynal 	vf610_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
510cfcc706cSMiquel Raynal 	return tmp;
511cfcc706cSMiquel Raynal }
512cfcc706cSMiquel Raynal 
513cfcc706cSMiquel Raynal /* If not provided, upper layers apply a fixed delay. */
vf610_nfc_dev_ready(struct mtd_info * mtd)514cfcc706cSMiquel Raynal static int vf610_nfc_dev_ready(struct mtd_info *mtd)
515cfcc706cSMiquel Raynal {
516cfcc706cSMiquel Raynal 	/* NFC handles R/B internally; always ready.  */
517cfcc706cSMiquel Raynal 	return 1;
518cfcc706cSMiquel Raynal }
519cfcc706cSMiquel Raynal 
520cfcc706cSMiquel Raynal /*
521cfcc706cSMiquel Raynal  * This function supports Vybrid only (MPC5125 would have full RB and four CS)
522cfcc706cSMiquel Raynal  */
vf610_nfc_select_chip(struct mtd_info * mtd,int chip)523cfcc706cSMiquel Raynal static void vf610_nfc_select_chip(struct mtd_info *mtd, int chip)
524cfcc706cSMiquel Raynal {
525cfcc706cSMiquel Raynal #ifdef CONFIG_VF610
526cfcc706cSMiquel Raynal 	u32 tmp = vf610_nfc_read(mtd, NFC_ROW_ADDR);
527cfcc706cSMiquel Raynal 	tmp &= ~(ROW_ADDR_CHIP_SEL_RB_MASK | ROW_ADDR_CHIP_SEL_MASK);
528cfcc706cSMiquel Raynal 
529cfcc706cSMiquel Raynal 	if (chip >= 0) {
530cfcc706cSMiquel Raynal 		tmp |= 1 << ROW_ADDR_CHIP_SEL_RB_SHIFT;
531cfcc706cSMiquel Raynal 		tmp |= (1 << chip) << ROW_ADDR_CHIP_SEL_SHIFT;
532cfcc706cSMiquel Raynal 	}
533cfcc706cSMiquel Raynal 
534cfcc706cSMiquel Raynal 	vf610_nfc_write(mtd, NFC_ROW_ADDR, tmp);
535cfcc706cSMiquel Raynal #endif
536cfcc706cSMiquel Raynal }
537cfcc706cSMiquel Raynal 
538cfcc706cSMiquel Raynal /* Count the number of 0's in buff upto max_bits */
count_written_bits(uint8_t * buff,int size,int max_bits)539cfcc706cSMiquel Raynal static inline int count_written_bits(uint8_t *buff, int size, int max_bits)
540cfcc706cSMiquel Raynal {
541cfcc706cSMiquel Raynal 	uint32_t *buff32 = (uint32_t *)buff;
542cfcc706cSMiquel Raynal 	int k, written_bits = 0;
543cfcc706cSMiquel Raynal 
544cfcc706cSMiquel Raynal 	for (k = 0; k < (size / 4); k++) {
545cfcc706cSMiquel Raynal 		written_bits += hweight32(~buff32[k]);
546cfcc706cSMiquel Raynal 		if (written_bits > max_bits)
547cfcc706cSMiquel Raynal 			break;
548cfcc706cSMiquel Raynal 	}
549cfcc706cSMiquel Raynal 
550cfcc706cSMiquel Raynal 	return written_bits;
551cfcc706cSMiquel Raynal }
552cfcc706cSMiquel Raynal 
vf610_nfc_correct_data(struct mtd_info * mtd,uint8_t * dat,uint8_t * oob,int page)553cfcc706cSMiquel Raynal static inline int vf610_nfc_correct_data(struct mtd_info *mtd, uint8_t *dat,
554cfcc706cSMiquel Raynal 					 uint8_t *oob, int page)
555cfcc706cSMiquel Raynal {
556cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
557cfcc706cSMiquel Raynal 	u32 ecc_status_off = NFC_MAIN_AREA(0) + ECC_SRAM_ADDR + ECC_STATUS;
558cfcc706cSMiquel Raynal 	u8 ecc_status;
559cfcc706cSMiquel Raynal 	u8 ecc_count;
560cfcc706cSMiquel Raynal 	int flips;
561cfcc706cSMiquel Raynal 	int flips_threshold = nfc->chip.ecc.strength / 2;
562cfcc706cSMiquel Raynal 
563cfcc706cSMiquel Raynal 	ecc_status = vf610_nfc_read(mtd, ecc_status_off) & 0xff;
564cfcc706cSMiquel Raynal 	ecc_count = ecc_status & ECC_STATUS_ERR_COUNT;
565cfcc706cSMiquel Raynal 
566cfcc706cSMiquel Raynal 	if (!(ecc_status & ECC_STATUS_MASK))
567cfcc706cSMiquel Raynal 		return ecc_count;
568cfcc706cSMiquel Raynal 
569cfcc706cSMiquel Raynal 	/* Read OOB without ECC unit enabled */
570cfcc706cSMiquel Raynal 	vf610_nfc_command(mtd, NAND_CMD_READOOB, 0, page);
571cfcc706cSMiquel Raynal 	vf610_nfc_read_buf(mtd, oob, mtd->oobsize);
572cfcc706cSMiquel Raynal 
573cfcc706cSMiquel Raynal 	/*
574cfcc706cSMiquel Raynal 	 * On an erased page, bit count (including OOB) should be zero or
575cfcc706cSMiquel Raynal 	 * at least less then half of the ECC strength.
576cfcc706cSMiquel Raynal 	 */
577cfcc706cSMiquel Raynal 	flips = count_written_bits(dat, nfc->chip.ecc.size, flips_threshold);
578cfcc706cSMiquel Raynal 	flips += count_written_bits(oob, mtd->oobsize, flips_threshold);
579cfcc706cSMiquel Raynal 
580cfcc706cSMiquel Raynal 	if (unlikely(flips > flips_threshold))
581cfcc706cSMiquel Raynal 		return -EINVAL;
582cfcc706cSMiquel Raynal 
583cfcc706cSMiquel Raynal 	/* Erased page. */
584cfcc706cSMiquel Raynal 	memset(dat, 0xff, nfc->chip.ecc.size);
585cfcc706cSMiquel Raynal 	memset(oob, 0xff, mtd->oobsize);
586cfcc706cSMiquel Raynal 	return flips;
587cfcc706cSMiquel Raynal }
588cfcc706cSMiquel Raynal 
vf610_nfc_read_page(struct mtd_info * mtd,struct nand_chip * chip,uint8_t * buf,int oob_required,int page)589cfcc706cSMiquel Raynal static int vf610_nfc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
590cfcc706cSMiquel Raynal 				uint8_t *buf, int oob_required, int page)
591cfcc706cSMiquel Raynal {
592cfcc706cSMiquel Raynal 	int eccsize = chip->ecc.size;
593cfcc706cSMiquel Raynal 	int stat;
594cfcc706cSMiquel Raynal 
595cfcc706cSMiquel Raynal 	vf610_nfc_read_buf(mtd, buf, eccsize);
596cfcc706cSMiquel Raynal 	if (oob_required)
597cfcc706cSMiquel Raynal 		vf610_nfc_read_buf(mtd, chip->oob_poi, mtd->oobsize);
598cfcc706cSMiquel Raynal 
599cfcc706cSMiquel Raynal 	stat = vf610_nfc_correct_data(mtd, buf, chip->oob_poi, page);
600cfcc706cSMiquel Raynal 
601cfcc706cSMiquel Raynal 	if (stat < 0) {
602cfcc706cSMiquel Raynal 		mtd->ecc_stats.failed++;
603cfcc706cSMiquel Raynal 		return 0;
604cfcc706cSMiquel Raynal 	} else {
605cfcc706cSMiquel Raynal 		mtd->ecc_stats.corrected += stat;
606cfcc706cSMiquel Raynal 		return stat;
607cfcc706cSMiquel Raynal 	}
608cfcc706cSMiquel Raynal }
609cfcc706cSMiquel Raynal 
610cfcc706cSMiquel Raynal /*
611cfcc706cSMiquel Raynal  * ECC will be calculated automatically
612cfcc706cSMiquel Raynal  */
vf610_nfc_write_page(struct mtd_info * mtd,struct nand_chip * chip,const uint8_t * buf,int oob_required,int page)613cfcc706cSMiquel Raynal static int vf610_nfc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
614cfcc706cSMiquel Raynal 			       const uint8_t *buf, int oob_required, int page)
615cfcc706cSMiquel Raynal {
616cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc = mtd_to_nfc(mtd);
617cfcc706cSMiquel Raynal 
618cfcc706cSMiquel Raynal 	vf610_nfc_write_buf(mtd, buf, mtd->writesize);
619cfcc706cSMiquel Raynal 	if (oob_required)
620cfcc706cSMiquel Raynal 		vf610_nfc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
621cfcc706cSMiquel Raynal 
622cfcc706cSMiquel Raynal 	/* Always write whole page including OOB due to HW ECC */
623cfcc706cSMiquel Raynal 	nfc->write_sz = mtd->writesize + mtd->oobsize;
624cfcc706cSMiquel Raynal 
625cfcc706cSMiquel Raynal 	return 0;
626cfcc706cSMiquel Raynal }
627cfcc706cSMiquel Raynal 
628cfcc706cSMiquel Raynal struct vf610_nfc_config {
629cfcc706cSMiquel Raynal 	int hardware_ecc;
630cfcc706cSMiquel Raynal 	int width;
631cfcc706cSMiquel Raynal 	int flash_bbt;
632cfcc706cSMiquel Raynal };
633cfcc706cSMiquel Raynal 
vf610_nfc_nand_init(int devnum,void __iomem * addr)634cfcc706cSMiquel Raynal static int vf610_nfc_nand_init(int devnum, void __iomem *addr)
635cfcc706cSMiquel Raynal {
636cfcc706cSMiquel Raynal 	struct mtd_info *mtd;
637cfcc706cSMiquel Raynal 	struct nand_chip *chip;
638cfcc706cSMiquel Raynal 	struct vf610_nfc *nfc;
639cfcc706cSMiquel Raynal 	int err = 0;
640cfcc706cSMiquel Raynal 	struct vf610_nfc_config cfg = {
641cfcc706cSMiquel Raynal 		.hardware_ecc = 1,
642cfcc706cSMiquel Raynal #ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT
643cfcc706cSMiquel Raynal 		.width = 16,
644cfcc706cSMiquel Raynal #else
645cfcc706cSMiquel Raynal 		.width = 8,
646cfcc706cSMiquel Raynal #endif
647cfcc706cSMiquel Raynal 		.flash_bbt = 1,
648cfcc706cSMiquel Raynal 	};
649cfcc706cSMiquel Raynal 
6502c92be16SLukasz Majewski 	nfc = calloc(1, sizeof(*nfc));
651cfcc706cSMiquel Raynal 	if (!nfc) {
652cfcc706cSMiquel Raynal 		printf(KERN_ERR "%s: Memory exhausted!\n", __func__);
653cfcc706cSMiquel Raynal 		return -ENOMEM;
654cfcc706cSMiquel Raynal 	}
655cfcc706cSMiquel Raynal 
656cfcc706cSMiquel Raynal 	chip = &nfc->chip;
657cfcc706cSMiquel Raynal 	nfc->regs = addr;
658cfcc706cSMiquel Raynal 
659cfcc706cSMiquel Raynal 	mtd = nand_to_mtd(chip);
660cfcc706cSMiquel Raynal 	nand_set_controller_data(chip, nfc);
661cfcc706cSMiquel Raynal 
662cfcc706cSMiquel Raynal 	if (cfg.width == 16)
663cfcc706cSMiquel Raynal 		chip->options |= NAND_BUSWIDTH_16;
664cfcc706cSMiquel Raynal 
665cfcc706cSMiquel Raynal 	chip->dev_ready = vf610_nfc_dev_ready;
666cfcc706cSMiquel Raynal 	chip->cmdfunc = vf610_nfc_command;
667cfcc706cSMiquel Raynal 	chip->read_byte = vf610_nfc_read_byte;
668cfcc706cSMiquel Raynal 	chip->read_word = vf610_nfc_read_word;
669cfcc706cSMiquel Raynal 	chip->read_buf = vf610_nfc_read_buf;
670cfcc706cSMiquel Raynal 	chip->write_buf = vf610_nfc_write_buf;
671cfcc706cSMiquel Raynal 	chip->select_chip = vf610_nfc_select_chip;
672cfcc706cSMiquel Raynal 
673cfcc706cSMiquel Raynal 	chip->options |= NAND_NO_SUBPAGE_WRITE;
674cfcc706cSMiquel Raynal 
675cfcc706cSMiquel Raynal 	chip->ecc.size = PAGE_2K;
676cfcc706cSMiquel Raynal 
677cfcc706cSMiquel Raynal 	/* Set configuration register. */
678cfcc706cSMiquel Raynal 	vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
679cfcc706cSMiquel Raynal 	vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_ADDR_AUTO_INCR_BIT);
680cfcc706cSMiquel Raynal 	vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_BUFNO_AUTO_INCR_BIT);
681cfcc706cSMiquel Raynal 	vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_BOOT_MODE_BIT);
682cfcc706cSMiquel Raynal 	vf610_nfc_clear(mtd, NFC_FLASH_CONFIG, CONFIG_DMA_REQ_BIT);
683cfcc706cSMiquel Raynal 	vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_FAST_FLASH_BIT);
684cfcc706cSMiquel Raynal 
685cfcc706cSMiquel Raynal 	/* Disable virtual pages, only one elementary transfer unit */
686cfcc706cSMiquel Raynal 	vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG, CONFIG_PAGE_CNT_MASK,
687cfcc706cSMiquel Raynal 			    CONFIG_PAGE_CNT_SHIFT, 1);
688cfcc706cSMiquel Raynal 
689cfcc706cSMiquel Raynal 	/* first scan to find the device and get the page size */
690cfcc706cSMiquel Raynal 	if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL)) {
691cfcc706cSMiquel Raynal 		err = -ENXIO;
692cfcc706cSMiquel Raynal 		goto error;
693cfcc706cSMiquel Raynal 	}
694cfcc706cSMiquel Raynal 
695cfcc706cSMiquel Raynal 	if (cfg.width == 16)
696cfcc706cSMiquel Raynal 		vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_16BIT);
697cfcc706cSMiquel Raynal 
698cfcc706cSMiquel Raynal 	/* Bad block options. */
699cfcc706cSMiquel Raynal 	if (cfg.flash_bbt)
700cfcc706cSMiquel Raynal 		chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB |
701cfcc706cSMiquel Raynal 				    NAND_BBT_CREATE;
702cfcc706cSMiquel Raynal 
703cfcc706cSMiquel Raynal 	/* Single buffer only, max 256 OOB minus ECC status */
704cfcc706cSMiquel Raynal 	if (mtd->writesize + mtd->oobsize > PAGE_2K + OOB_MAX - 8) {
705cfcc706cSMiquel Raynal 		dev_err(nfc->dev, "Unsupported flash page size\n");
706cfcc706cSMiquel Raynal 		err = -ENXIO;
707cfcc706cSMiquel Raynal 		goto error;
708cfcc706cSMiquel Raynal 	}
709cfcc706cSMiquel Raynal 
710cfcc706cSMiquel Raynal 	if (cfg.hardware_ecc) {
711cfcc706cSMiquel Raynal 		if (mtd->writesize != PAGE_2K && mtd->oobsize < 64) {
712cfcc706cSMiquel Raynal 			dev_err(nfc->dev, "Unsupported flash with hwecc\n");
713cfcc706cSMiquel Raynal 			err = -ENXIO;
714cfcc706cSMiquel Raynal 			goto error;
715cfcc706cSMiquel Raynal 		}
716cfcc706cSMiquel Raynal 
717cfcc706cSMiquel Raynal 		if (chip->ecc.size != mtd->writesize) {
718cfcc706cSMiquel Raynal 			dev_err(nfc->dev, "ecc size: %d\n", chip->ecc.size);
719cfcc706cSMiquel Raynal 			dev_err(nfc->dev, "Step size needs to be page size\n");
720cfcc706cSMiquel Raynal 			err = -ENXIO;
721cfcc706cSMiquel Raynal 			goto error;
722cfcc706cSMiquel Raynal 		}
723cfcc706cSMiquel Raynal 
724cfcc706cSMiquel Raynal 		/* Current HW ECC layouts only use 64 bytes of OOB */
725cfcc706cSMiquel Raynal 		if (mtd->oobsize > 64)
726cfcc706cSMiquel Raynal 			mtd->oobsize = 64;
727cfcc706cSMiquel Raynal 
728cfcc706cSMiquel Raynal 		/* propagate ecc.layout to mtd_info */
729cfcc706cSMiquel Raynal 		mtd->ecclayout = chip->ecc.layout;
730cfcc706cSMiquel Raynal 		chip->ecc.read_page = vf610_nfc_read_page;
731cfcc706cSMiquel Raynal 		chip->ecc.write_page = vf610_nfc_write_page;
732cfcc706cSMiquel Raynal 		chip->ecc.mode = NAND_ECC_HW;
733cfcc706cSMiquel Raynal 
734cfcc706cSMiquel Raynal 		chip->ecc.size = PAGE_2K;
735cfcc706cSMiquel Raynal 		chip->ecc.layout = &vf610_nfc_ecc;
736cfcc706cSMiquel Raynal #if defined(CONFIG_SYS_NAND_VF610_NFC_45_ECC_BYTES)
737cfcc706cSMiquel Raynal 		chip->ecc.strength = 24;
738cfcc706cSMiquel Raynal 		chip->ecc.bytes = 45;
739cfcc706cSMiquel Raynal #elif defined(CONFIG_SYS_NAND_VF610_NFC_60_ECC_BYTES)
740cfcc706cSMiquel Raynal 		chip->ecc.strength = 32;
741cfcc706cSMiquel Raynal 		chip->ecc.bytes = 60;
742cfcc706cSMiquel Raynal #endif
743cfcc706cSMiquel Raynal 
744cfcc706cSMiquel Raynal 		/* Set ECC_STATUS offset */
745cfcc706cSMiquel Raynal 		vf610_nfc_set_field(mtd, NFC_FLASH_CONFIG,
746cfcc706cSMiquel Raynal 				    CONFIG_ECC_SRAM_ADDR_MASK,
747cfcc706cSMiquel Raynal 				    CONFIG_ECC_SRAM_ADDR_SHIFT,
748cfcc706cSMiquel Raynal 				    ECC_SRAM_ADDR >> 3);
749cfcc706cSMiquel Raynal 
750cfcc706cSMiquel Raynal 		/* Enable ECC status in SRAM */
751cfcc706cSMiquel Raynal 		vf610_nfc_set(mtd, NFC_FLASH_CONFIG, CONFIG_ECC_SRAM_REQ_BIT);
752cfcc706cSMiquel Raynal 	}
753cfcc706cSMiquel Raynal 
754cfcc706cSMiquel Raynal 	/* second phase scan */
755cfcc706cSMiquel Raynal 	err = nand_scan_tail(mtd);
756cfcc706cSMiquel Raynal 	if (err)
757cfcc706cSMiquel Raynal 		return err;
758cfcc706cSMiquel Raynal 
759cfcc706cSMiquel Raynal 	err = nand_register(devnum, mtd);
760cfcc706cSMiquel Raynal 	if (err)
761cfcc706cSMiquel Raynal 		return err;
762cfcc706cSMiquel Raynal 
763cfcc706cSMiquel Raynal 	return 0;
764cfcc706cSMiquel Raynal 
765cfcc706cSMiquel Raynal error:
766cfcc706cSMiquel Raynal 	return err;
767cfcc706cSMiquel Raynal }
768cfcc706cSMiquel Raynal 
769*251a3b83SLukasz Majewski #if CONFIG_NAND_VF610_NFC_DT
770*251a3b83SLukasz Majewski static const struct udevice_id vf610_nfc_dt_ids[] = {
771*251a3b83SLukasz Majewski 	{
772*251a3b83SLukasz Majewski 		.compatible = "fsl,vf610-nfc",
773*251a3b83SLukasz Majewski 	},
774*251a3b83SLukasz Majewski 	{ /* sentinel */ }
775*251a3b83SLukasz Majewski };
776*251a3b83SLukasz Majewski 
vf610_nfc_dt_probe(struct udevice * dev)777*251a3b83SLukasz Majewski static int vf610_nfc_dt_probe(struct udevice *dev)
778*251a3b83SLukasz Majewski {
779*251a3b83SLukasz Majewski 	struct resource res;
780*251a3b83SLukasz Majewski 	int ret;
781*251a3b83SLukasz Majewski 
782*251a3b83SLukasz Majewski 	ret = dev_read_resource(dev, 0, &res);
783*251a3b83SLukasz Majewski 	if (ret)
784*251a3b83SLukasz Majewski 		return ret;
785*251a3b83SLukasz Majewski 
786*251a3b83SLukasz Majewski 	return vf610_nfc_nand_init(0, devm_ioremap(dev, res.start,
787*251a3b83SLukasz Majewski 						   resource_size(&res)));
788*251a3b83SLukasz Majewski }
789*251a3b83SLukasz Majewski 
790*251a3b83SLukasz Majewski U_BOOT_DRIVER(vf610_nfc_dt) = {
791*251a3b83SLukasz Majewski 	.name = "vf610-nfc-dt",
792*251a3b83SLukasz Majewski 	.id = UCLASS_MTD,
793*251a3b83SLukasz Majewski 	.of_match = vf610_nfc_dt_ids,
794*251a3b83SLukasz Majewski 	.probe = vf610_nfc_dt_probe,
795*251a3b83SLukasz Majewski };
796*251a3b83SLukasz Majewski 
board_nand_init(void)797*251a3b83SLukasz Majewski void board_nand_init(void)
798*251a3b83SLukasz Majewski {
799*251a3b83SLukasz Majewski 	struct udevice *dev;
800*251a3b83SLukasz Majewski 	int ret;
801*251a3b83SLukasz Majewski 
802*251a3b83SLukasz Majewski 	ret = uclass_get_device_by_driver(UCLASS_MTD,
803*251a3b83SLukasz Majewski 					  DM_GET_DRIVER(vf610_nfc_dt),
804*251a3b83SLukasz Majewski 					  &dev);
805*251a3b83SLukasz Majewski 	if (ret && ret != -ENODEV)
806*251a3b83SLukasz Majewski 		pr_err("Failed to initialize NAND controller. (error %d)\n",
807*251a3b83SLukasz Majewski 		       ret);
808*251a3b83SLukasz Majewski }
809*251a3b83SLukasz Majewski #else
board_nand_init(void)810cfcc706cSMiquel Raynal void board_nand_init(void)
811cfcc706cSMiquel Raynal {
812cfcc706cSMiquel Raynal 	int err = vf610_nfc_nand_init(0, (void __iomem *)CONFIG_SYS_NAND_BASE);
813cfcc706cSMiquel Raynal 	if (err)
814cfcc706cSMiquel Raynal 		printf("VF610 NAND init failed (err %d)\n", err);
815cfcc706cSMiquel Raynal }
816*251a3b83SLukasz Majewski #endif /* CONFIG_NAND_VF610_NFC_DT */
817