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