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