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