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