blob: ec1787f22492d93322a4014c6acc3d3da9ba2d9f [file] [log] [blame]
Dirk Behme778933f2008-12-14 09:47:16 +01001/*
2 * (C) Copyright 2004-2008 Texas Instruments, <www.ti.com>
3 * Rohit Choraria <rohitkc@ti.com>
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
Dirk Behme778933f2008-12-14 09:47:16 +01006 */
7
8#include <common.h>
9#include <asm/io.h>
10#include <asm/errno.h>
11#include <asm/arch/mem.h>
Tom Rini8eb48ff2013-03-14 11:15:25 +000012#include <asm/arch/cpu.h>
Andreas Bießmann9a48c5c2013-04-02 06:05:54 +000013#include <asm/omap_gpmc.h>
Dirk Behme778933f2008-12-14 09:47:16 +010014#include <linux/mtd/nand_ecc.h>
Andreas Bießmann82a65472013-04-05 04:55:21 +000015#include <linux/bch.h>
Stefano Babicaade5792012-03-21 23:56:17 +000016#include <linux/compiler.h>
Dirk Behme778933f2008-12-14 09:47:16 +010017#include <nand.h>
Mansoor Ahamede5612512012-11-06 13:06:33 +000018#ifdef CONFIG_AM33XX
19#include <asm/arch/elm.h>
20#endif
Dirk Behme778933f2008-12-14 09:47:16 +010021
22static uint8_t cs;
Stefano Babicaade5792012-03-21 23:56:17 +000023static __maybe_unused struct nand_ecclayout hw_nand_oob =
24 GPMC_NAND_HW_ECC_LAYOUT;
Andreas Bießmann82a65472013-04-05 04:55:21 +000025static __maybe_unused struct nand_ecclayout hw_bch8_nand_oob =
26 GPMC_NAND_HW_BCH8_ECC_LAYOUT;
Dirk Behme778933f2008-12-14 09:47:16 +010027
28/*
29 * omap_nand_hwcontrol - Set the address pointers corretly for the
30 * following address/data/command operation
31 */
32static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
33 uint32_t ctrl)
34{
35 register struct nand_chip *this = mtd->priv;
36
37 /*
38 * Point the IO_ADDR to DATA and ADDRESS registers instead
39 * of chip address
40 */
41 switch (ctrl) {
42 case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
Dirk Behmea4becd62009-08-08 09:30:22 +020043 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Dirk Behme778933f2008-12-14 09:47:16 +010044 break;
45 case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
Dirk Behmea4becd62009-08-08 09:30:22 +020046 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
Dirk Behme778933f2008-12-14 09:47:16 +010047 break;
48 case NAND_CTRL_CHANGE | NAND_NCE:
Dirk Behmea4becd62009-08-08 09:30:22 +020049 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
Dirk Behme778933f2008-12-14 09:47:16 +010050 break;
51 }
52
53 if (cmd != NAND_CMD_NONE)
54 writeb(cmd, this->IO_ADDR_W);
55}
56
Simon Schwarz4f62e982011-09-14 15:30:16 -040057#ifdef CONFIG_SPL_BUILD
58/* Check wait pin as dev ready indicator */
59int omap_spl_dev_ready(struct mtd_info *mtd)
60{
61 return gpmc_cfg->status & (1 << 8);
62}
63#endif
64
Dirk Behme778933f2008-12-14 09:47:16 +010065/*
66 * omap_hwecc_init - Initialize the Hardware ECC for NAND flash in
67 * GPMC controller
68 * @mtd: MTD device structure
69 *
70 */
Stefano Babicaade5792012-03-21 23:56:17 +000071static void __maybe_unused omap_hwecc_init(struct nand_chip *chip)
Dirk Behme778933f2008-12-14 09:47:16 +010072{
73 /*
74 * Init ECC Control Register
75 * Clear all ECC | Enable Reg1
76 */
Dirk Behmea4becd62009-08-08 09:30:22 +020077 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
78 writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL, &gpmc_cfg->ecc_size_config);
Dirk Behme778933f2008-12-14 09:47:16 +010079}
80
81/*
82 * gen_true_ecc - This function will generate true ECC value, which
83 * can be used when correcting data read from NAND flash memory core
84 *
85 * @ecc_buf: buffer to store ecc code
86 *
87 * @return: re-formatted ECC value
88 */
89static uint32_t gen_true_ecc(uint8_t *ecc_buf)
90{
91 return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
92 ((ecc_buf[2] & 0x0F) << 8);
93}
94
95/*
96 * omap_correct_data - Compares the ecc read from nand spare area with ECC
97 * registers values and corrects one bit error if it has occured
98 * Further details can be had from OMAP TRM and the following selected links:
99 * http://en.wikipedia.org/wiki/Hamming_code
100 * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf
101 *
102 * @mtd: MTD device structure
103 * @dat: page data
104 * @read_ecc: ecc read from nand flash
105 * @calc_ecc: ecc read from ECC registers
106 *
107 * @return 0 if data is OK or corrected, else returns -1
108 */
Stefano Babicaade5792012-03-21 23:56:17 +0000109static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
Dirk Behme778933f2008-12-14 09:47:16 +0100110 uint8_t *read_ecc, uint8_t *calc_ecc)
111{
112 uint32_t orig_ecc, new_ecc, res, hm;
113 uint16_t parity_bits, byte;
114 uint8_t bit;
115
116 /* Regenerate the orginal ECC */
117 orig_ecc = gen_true_ecc(read_ecc);
118 new_ecc = gen_true_ecc(calc_ecc);
119 /* Get the XOR of real ecc */
120 res = orig_ecc ^ new_ecc;
121 if (res) {
122 /* Get the hamming width */
123 hm = hweight32(res);
124 /* Single bit errors can be corrected! */
125 if (hm == 12) {
126 /* Correctable data! */
127 parity_bits = res >> 16;
128 bit = (parity_bits & 0x7);
129 byte = (parity_bits >> 3) & 0x1FF;
130 /* Flip the bit to correct */
131 dat[byte] ^= (0x1 << bit);
132 } else if (hm == 1) {
133 printf("Error: Ecc is wrong\n");
134 /* ECC itself is corrupted */
135 return 2;
136 } else {
137 /*
138 * hm distance != parity pairs OR one, could mean 2 bit
139 * error OR potentially be on a blank page..
140 * orig_ecc: contains spare area data from nand flash.
141 * new_ecc: generated ecc while reading data area.
142 * Note: if the ecc = 0, all data bits from which it was
143 * generated are 0xFF.
144 * The 3 byte(24 bits) ecc is generated per 512byte
145 * chunk of a page. If orig_ecc(from spare area)
146 * is 0xFF && new_ecc(computed now from data area)=0x0,
147 * this means that data area is 0xFF and spare area is
148 * 0xFF. A sure sign of a erased page!
149 */
150 if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000))
151 return 0;
152 printf("Error: Bad compare! failed\n");
153 /* detected 2 bit error */
154 return -1;
155 }
156 }
157 return 0;
158}
159
160/*
161 * omap_calculate_ecc - Generate non-inverted ECC bytes.
162 *
163 * Using noninverted ECC can be considered ugly since writing a blank
164 * page ie. padding will clear the ECC bytes. This is no problem as
165 * long nobody is trying to write data on the seemingly unused page.
166 * Reading an erased page will produce an ECC mismatch between
167 * generated and read ECC bytes that has to be dealt with separately.
168 * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
169 * is used, the result of read will be 0x0 while the ECC offsets of the
170 * spare area will be 0xFF which will result in an ECC mismatch.
171 * @mtd: MTD structure
172 * @dat: unused
173 * @ecc_code: ecc_code buffer
174 */
Stefano Babicaade5792012-03-21 23:56:17 +0000175static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd,
176 const uint8_t *dat, uint8_t *ecc_code)
Dirk Behme778933f2008-12-14 09:47:16 +0100177{
178 u_int32_t val;
179
180 /* Start Reading from HW ECC1_Result = 0x200 */
Dirk Behmea4becd62009-08-08 09:30:22 +0200181 val = readl(&gpmc_cfg->ecc1_result);
Dirk Behme778933f2008-12-14 09:47:16 +0100182
183 ecc_code[0] = val & 0xFF;
184 ecc_code[1] = (val >> 16) & 0xFF;
185 ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
186
187 /*
188 * Stop reading anymore ECC vals and clear old results
189 * enable will be called if more reads are required
190 */
Dirk Behmea4becd62009-08-08 09:30:22 +0200191 writel(0x000, &gpmc_cfg->ecc_config);
Dirk Behme778933f2008-12-14 09:47:16 +0100192
193 return 0;
194}
195
196/*
197 * omap_enable_ecc - This function enables the hardware ecc functionality
198 * @mtd: MTD device structure
199 * @mode: Read/Write mode
200 */
Stefano Babicaade5792012-03-21 23:56:17 +0000201static void __maybe_unused omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
Dirk Behme778933f2008-12-14 09:47:16 +0100202{
203 struct nand_chip *chip = mtd->priv;
204 uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
205
206 switch (mode) {
207 case NAND_ECC_READ:
208 case NAND_ECC_WRITE:
209 /* Clear the ecc result registers, select ecc reg as 1 */
Dirk Behmea4becd62009-08-08 09:30:22 +0200210 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
Dirk Behme778933f2008-12-14 09:47:16 +0100211
212 /*
213 * Size 0 = 0xFF, Size1 is 0xFF - both are 512 bytes
214 * tell all regs to generate size0 sized regs
215 * we just have a single ECC engine for all CS
216 */
217 writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL,
Dirk Behmea4becd62009-08-08 09:30:22 +0200218 &gpmc_cfg->ecc_size_config);
Dirk Behme778933f2008-12-14 09:47:16 +0100219 val = (dev_width << 7) | (cs << 1) | (0x1);
Dirk Behmea4becd62009-08-08 09:30:22 +0200220 writel(val, &gpmc_cfg->ecc_config);
Dirk Behme778933f2008-12-14 09:47:16 +0100221 break;
222 default:
223 printf("Error: Unrecognized Mode[%d]!\n", mode);
224 break;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000225 }
226}
227
228/*
Andreas Bießmann82a65472013-04-05 04:55:21 +0000229 * Generic BCH interface
Mansoor Ahamede5612512012-11-06 13:06:33 +0000230 */
Mansoor Ahamede5612512012-11-06 13:06:33 +0000231struct nand_bch_priv {
232 uint8_t mode;
233 uint8_t type;
234 uint8_t nibbles;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000235 struct bch_control *control;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000236};
237
238/* bch types */
239#define ECC_BCH4 0
240#define ECC_BCH8 1
241#define ECC_BCH16 2
242
Andreas Bießmann82a65472013-04-05 04:55:21 +0000243/* GPMC ecc engine settings */
244#define BCH_WRAPMODE_1 1 /* BCH wrap mode 1 */
245#define BCH_WRAPMODE_6 6 /* BCH wrap mode 6 */
246
Mansoor Ahamede5612512012-11-06 13:06:33 +0000247/* BCH nibbles for diff bch levels */
248#define NAND_ECC_HW_BCH ((uint8_t)(NAND_ECC_HW_OOB_FIRST) + 1)
249#define ECC_BCH4_NIBBLES 13
250#define ECC_BCH8_NIBBLES 26
251#define ECC_BCH16_NIBBLES 52
252
Andreas Bießmann82a65472013-04-05 04:55:21 +0000253/*
254 * This can be a single instance cause all current users have only one NAND
255 * with nearly the same setup (BCH8, some with ELM and others with sw BCH
256 * library).
257 * When some users with other BCH strength will exists this have to change!
258 */
259static __maybe_unused struct nand_bch_priv bch_priv = {
Mansoor Ahamede5612512012-11-06 13:06:33 +0000260 .mode = NAND_ECC_HW_BCH,
261 .type = ECC_BCH8,
Andreas Bießmann82a65472013-04-05 04:55:21 +0000262 .nibbles = ECC_BCH8_NIBBLES,
263 .control = NULL
Mansoor Ahamede5612512012-11-06 13:06:33 +0000264};
265
266/*
Andreas Bießmann82a65472013-04-05 04:55:21 +0000267 * omap_hwecc_init_bch - Initialize the BCH Hardware ECC for NAND flash in
268 * GPMC controller
269 * @mtd: MTD device structure
270 * @mode: Read/Write mode
271 */
272__maybe_unused
273static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
274{
275 uint32_t val;
276 uint32_t dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
277#ifdef CONFIG_AM33XX
278 uint32_t unused_length = 0;
279#endif
280 uint32_t wr_mode = BCH_WRAPMODE_6;
281 struct nand_bch_priv *bch = chip->priv;
282
283 /* Clear the ecc result registers, select ecc reg as 1 */
284 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
285
286#ifdef CONFIG_AM33XX
287 wr_mode = BCH_WRAPMODE_1;
288
289 switch (bch->nibbles) {
290 case ECC_BCH4_NIBBLES:
291 unused_length = 3;
292 break;
293 case ECC_BCH8_NIBBLES:
294 unused_length = 2;
295 break;
296 case ECC_BCH16_NIBBLES:
297 unused_length = 0;
298 break;
299 }
300
301 /*
302 * This is ecc_size_config for ELM mode.
303 * Here we are using different settings for read and write access and
304 * also depending on BCH strength.
305 */
306 switch (mode) {
307 case NAND_ECC_WRITE:
308 /* write access only setup eccsize1 config */
309 val = ((unused_length + bch->nibbles) << 22);
310 break;
311
312 case NAND_ECC_READ:
313 default:
314 /*
315 * by default eccsize0 selected for ecc1resultsize
316 * eccsize0 config.
317 */
318 val = (bch->nibbles << 12);
319 /* eccsize1 config */
320 val |= (unused_length << 22);
321 break;
322 }
323#else
324 /*
325 * This ecc_size_config setting is for BCH sw library.
326 *
327 * Note: we only support BCH8 currently with BCH sw library!
328 * Should be really easy to adobt to BCH4, however some omap3 have
329 * flaws with BCH4.
330 *
331 * Here we are using wrapping mode 6 both for reading and writing, with:
332 * size0 = 0 (no additional protected byte in spare area)
333 * size1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
334 */
335 val = (32 << 22) | (0 << 12);
336#endif
337 /* ecc size configuration */
338 writel(val, &gpmc_cfg->ecc_size_config);
339
340 /*
341 * Configure the ecc engine in gpmc
342 * We assume 512 Byte sector pages for access to NAND.
343 */
344 val = (1 << 16); /* enable BCH mode */
345 val |= (bch->type << 12); /* setup BCH type */
346 val |= (wr_mode << 8); /* setup wrapping mode */
347 val |= (dev_width << 7); /* setup device width (16 or 8 bit) */
348 val |= (cs << 1); /* setup chip select to work on */
349 debug("set ECC_CONFIG=0x%08x\n", val);
350 writel(val, &gpmc_cfg->ecc_config);
351}
352
353/*
354 * omap_enable_ecc_bch - This function enables the bch h/w ecc functionality
355 * @mtd: MTD device structure
356 * @mode: Read/Write mode
357 */
358__maybe_unused
359static void omap_enable_ecc_bch(struct mtd_info *mtd, int32_t mode)
360{
361 struct nand_chip *chip = mtd->priv;
362
363 omap_hwecc_init_bch(chip, mode);
364 /* enable ecc */
365 writel((readl(&gpmc_cfg->ecc_config) | 0x1), &gpmc_cfg->ecc_config);
366}
367
368/*
369 * omap_ecc_disable - Disable H/W ECC calculation
370 *
371 * @mtd: MTD device structure
372 */
373static void __maybe_unused omap_ecc_disable(struct mtd_info *mtd)
374{
375 writel((readl(&gpmc_cfg->ecc_config) & ~0x1), &gpmc_cfg->ecc_config);
376}
377
378/*
379 * BCH8 support (needs ELM and thus AM33xx-only)
380 */
381#ifdef CONFIG_AM33XX
382/*
Mansoor Ahamede5612512012-11-06 13:06:33 +0000383 * omap_read_bch8_result - Read BCH result for BCH8 level
384 *
385 * @mtd: MTD device structure
386 * @big_endian: When set read register 3 first
387 * @ecc_code: Read syndrome from BCH result registers
388 */
389static void omap_read_bch8_result(struct mtd_info *mtd, uint8_t big_endian,
390 uint8_t *ecc_code)
391{
392 uint32_t *ptr;
393 int8_t i = 0, j;
394
395 if (big_endian) {
396 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
397 ecc_code[i++] = readl(ptr) & 0xFF;
398 ptr--;
399 for (j = 0; j < 3; j++) {
400 ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
401 ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
402 ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
403 ecc_code[i++] = readl(ptr) & 0xFF;
404 ptr--;
405 }
406 } else {
407 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[0];
408 for (j = 0; j < 3; j++) {
409 ecc_code[i++] = readl(ptr) & 0xFF;
410 ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
411 ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
412 ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
413 ptr++;
414 }
415 ecc_code[i++] = readl(ptr) & 0xFF;
416 ecc_code[i++] = 0; /* 14th byte is always zero */
417 }
418}
419
420/*
Mansoor Ahamede5612512012-11-06 13:06:33 +0000421 * omap_rotate_ecc_bch - Rotate the syndrome bytes
422 *
423 * @mtd: MTD device structure
424 * @calc_ecc: ECC read from ECC registers
425 * @syndrome: Rotated syndrome will be retuned in this array
426 *
427 */
428static void omap_rotate_ecc_bch(struct mtd_info *mtd, uint8_t *calc_ecc,
429 uint8_t *syndrome)
430{
431 struct nand_chip *chip = mtd->priv;
432 struct nand_bch_priv *bch = chip->priv;
433 uint8_t n_bytes = 0;
434 int8_t i, j;
435
436 switch (bch->type) {
437 case ECC_BCH4:
438 n_bytes = 8;
439 break;
440
441 case ECC_BCH16:
442 n_bytes = 28;
443 break;
444
445 case ECC_BCH8:
446 default:
447 n_bytes = 13;
448 break;
449 }
450
451 for (i = 0, j = (n_bytes-1); i < n_bytes; i++, j--)
452 syndrome[i] = calc_ecc[j];
453}
454
455/*
456 * omap_calculate_ecc_bch - Read BCH ECC result
457 *
458 * @mtd: MTD structure
459 * @dat: unused
460 * @ecc_code: ecc_code buffer
461 */
462static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
463 uint8_t *ecc_code)
464{
465 struct nand_chip *chip = mtd->priv;
466 struct nand_bch_priv *bch = chip->priv;
467 uint8_t big_endian = 1;
468 int8_t ret = 0;
469
470 if (bch->type == ECC_BCH8)
471 omap_read_bch8_result(mtd, big_endian, ecc_code);
472 else /* BCH4 and BCH16 currently not supported */
473 ret = -1;
474
475 /*
476 * Stop reading anymore ECC vals and clear old results
477 * enable will be called if more reads are required
478 */
479 omap_ecc_disable(mtd);
480
481 return ret;
482}
483
484/*
485 * omap_fix_errors_bch - Correct bch error in the data
486 *
487 * @mtd: MTD device structure
488 * @data: Data read from flash
489 * @error_count:Number of errors in data
490 * @error_loc: Locations of errors in the data
491 *
492 */
493static void omap_fix_errors_bch(struct mtd_info *mtd, uint8_t *data,
494 uint32_t error_count, uint32_t *error_loc)
495{
496 struct nand_chip *chip = mtd->priv;
497 struct nand_bch_priv *bch = chip->priv;
498 uint8_t count = 0;
499 uint32_t error_byte_pos;
500 uint32_t error_bit_mask;
501 uint32_t last_bit = (bch->nibbles * 4) - 1;
502
503 /* Flip all bits as specified by the error location array. */
504 /* FOR( each found error location flip the bit ) */
505 for (count = 0; count < error_count; count++) {
506 if (error_loc[count] > last_bit) {
507 /* Remove the ECC spare bits from correction. */
508 error_loc[count] -= (last_bit + 1);
509 /* Offset bit in data region */
510 error_byte_pos = ((512 * 8) -
511 (error_loc[count]) - 1) / 8;
512 /* Error Bit mask */
513 error_bit_mask = 0x1 << (error_loc[count] % 8);
514 /* Toggle the error bit to make the correction. */
515 data[error_byte_pos] ^= error_bit_mask;
516 }
Dirk Behme778933f2008-12-14 09:47:16 +0100517 }
518}
519
Mansoor Ahamede5612512012-11-06 13:06:33 +0000520/*
521 * omap_correct_data_bch - Compares the ecc read from nand spare area
522 * with ECC registers values and corrects one bit error if it has occured
523 *
524 * @mtd: MTD device structure
525 * @dat: page data
526 * @read_ecc: ecc read from nand flash (ignored)
527 * @calc_ecc: ecc read from ECC registers
528 *
529 * @return 0 if data is OK or corrected, else returns -1
530 */
531static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
532 uint8_t *read_ecc, uint8_t *calc_ecc)
533{
534 struct nand_chip *chip = mtd->priv;
535 struct nand_bch_priv *bch = chip->priv;
536 uint8_t syndrome[28];
537 uint32_t error_count = 0;
538 uint32_t error_loc[8];
539 uint32_t i, ecc_flag;
540
541 ecc_flag = 0;
542 for (i = 0; i < chip->ecc.bytes; i++)
543 if (read_ecc[i] != 0xff)
544 ecc_flag = 1;
545
546 if (!ecc_flag)
547 return 0;
548
549 elm_reset();
550 elm_config((enum bch_level)(bch->type));
551
552 /*
553 * while reading ECC result we read it in big endian.
554 * Hence while loading to ELM we have rotate to get the right endian.
555 */
556 omap_rotate_ecc_bch(mtd, calc_ecc, syndrome);
557
558 /* use elm module to check for errors */
559 if (elm_check_error(syndrome, bch->nibbles, &error_count,
560 error_loc) != 0) {
561 printf("ECC: uncorrectable.\n");
562 return -1;
563 }
564
565 /* correct bch error */
566 if (error_count > 0)
567 omap_fix_errors_bch(mtd, dat, error_count, error_loc);
568
569 return 0;
570}
Mansoor Ahamede5612512012-11-06 13:06:33 +0000571
572/**
573 * omap_read_page_bch - hardware ecc based page read function
574 * @mtd: mtd info structure
575 * @chip: nand chip info structure
576 * @buf: buffer to store read data
Sergey Lapin3a38a552013-01-14 03:46:50 +0000577 * @oob_required: caller expects OOB data read to chip->oob_poi
Mansoor Ahamede5612512012-11-06 13:06:33 +0000578 * @page: page number to read
579 *
580 */
581static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
Sergey Lapin3a38a552013-01-14 03:46:50 +0000582 uint8_t *buf, int oob_required, int page)
Mansoor Ahamede5612512012-11-06 13:06:33 +0000583{
584 int i, eccsize = chip->ecc.size;
585 int eccbytes = chip->ecc.bytes;
586 int eccsteps = chip->ecc.steps;
587 uint8_t *p = buf;
588 uint8_t *ecc_calc = chip->buffers->ecccalc;
589 uint8_t *ecc_code = chip->buffers->ecccode;
590 uint32_t *eccpos = chip->ecc.layout->eccpos;
591 uint8_t *oob = chip->oob_poi;
592 uint32_t data_pos;
593 uint32_t oob_pos;
594
595 data_pos = 0;
596 /* oob area start */
597 oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
598 oob += chip->ecc.layout->eccpos[0];
599
600 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
601 oob += eccbytes) {
602 chip->ecc.hwctl(mtd, NAND_ECC_READ);
603 /* read data */
604 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, page);
605 chip->read_buf(mtd, p, eccsize);
606
607 /* read respective ecc from oob area */
608 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, page);
609 chip->read_buf(mtd, oob, eccbytes);
610 /* read syndrome */
611 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
612
613 data_pos += eccsize;
614 oob_pos += eccbytes;
615 }
616
617 for (i = 0; i < chip->ecc.total; i++)
618 ecc_code[i] = chip->oob_poi[eccpos[i]];
619
620 eccsteps = chip->ecc.steps;
621 p = buf;
622
623 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
624 int stat;
625
626 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
627 if (stat < 0)
628 mtd->ecc_stats.failed++;
629 else
630 mtd->ecc_stats.corrected += stat;
631 }
632 return 0;
633}
634#endif /* CONFIG_AM33XX */
635
Andreas Bießmann82a65472013-04-05 04:55:21 +0000636/*
637 * OMAP3 BCH8 support (with BCH library)
638 */
639#ifdef CONFIG_NAND_OMAP_BCH8
640/*
641 * omap_calculate_ecc_bch - Read BCH ECC result
642 *
643 * @mtd: MTD device structure
644 * @dat: The pointer to data on which ecc is computed (unused here)
645 * @ecc: The ECC output buffer
646 */
647static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
648 uint8_t *ecc)
649{
650 int ret = 0;
651 size_t i;
652 unsigned long nsectors, val1, val2, val3, val4;
653
654 nsectors = ((readl(&gpmc_cfg->ecc_config) >> 4) & 0x7) + 1;
655
656 for (i = 0; i < nsectors; i++) {
657 /* Read hw-computed remainder */
658 val1 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[0]);
659 val2 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[1]);
660 val3 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[2]);
661 val4 = readl(&gpmc_cfg->bch_result_0_3[i].bch_result_x[3]);
662
663 /*
664 * Add constant polynomial to remainder, in order to get an ecc
665 * sequence of 0xFFs for a buffer filled with 0xFFs.
666 */
667 *ecc++ = 0xef ^ (val4 & 0xFF);
668 *ecc++ = 0x51 ^ ((val3 >> 24) & 0xFF);
669 *ecc++ = 0x2e ^ ((val3 >> 16) & 0xFF);
670 *ecc++ = 0x09 ^ ((val3 >> 8) & 0xFF);
671 *ecc++ = 0xed ^ (val3 & 0xFF);
672 *ecc++ = 0x93 ^ ((val2 >> 24) & 0xFF);
673 *ecc++ = 0x9a ^ ((val2 >> 16) & 0xFF);
674 *ecc++ = 0xc2 ^ ((val2 >> 8) & 0xFF);
675 *ecc++ = 0x97 ^ (val2 & 0xFF);
676 *ecc++ = 0x79 ^ ((val1 >> 24) & 0xFF);
677 *ecc++ = 0xe5 ^ ((val1 >> 16) & 0xFF);
678 *ecc++ = 0x24 ^ ((val1 >> 8) & 0xFF);
679 *ecc++ = 0xb5 ^ (val1 & 0xFF);
680 }
681
682 /*
683 * Stop reading anymore ECC vals and clear old results
684 * enable will be called if more reads are required
685 */
686 omap_ecc_disable(mtd);
687
688 return ret;
689}
690
691/**
692 * omap_correct_data_bch - Decode received data and correct errors
693 * @mtd: MTD device structure
694 * @data: page data
695 * @read_ecc: ecc read from nand flash
696 * @calc_ecc: ecc read from HW ECC registers
697 */
698static int omap_correct_data_bch(struct mtd_info *mtd, u_char *data,
699 u_char *read_ecc, u_char *calc_ecc)
700{
701 int i, count;
702 /* cannot correct more than 8 errors */
703 unsigned int errloc[8];
704 struct nand_chip *chip = mtd->priv;
705 struct nand_bch_priv *chip_priv = chip->priv;
706 struct bch_control *bch = chip_priv->control;
707
708 count = decode_bch(bch, NULL, 512, read_ecc, calc_ecc, NULL, errloc);
709 if (count > 0) {
710 /* correct errors */
711 for (i = 0; i < count; i++) {
712 /* correct data only, not ecc bytes */
713 if (errloc[i] < 8*512)
714 data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
715 printf("corrected bitflip %u\n", errloc[i]);
716#ifdef DEBUG
717 puts("read_ecc: ");
718 /*
719 * BCH8 have 13 bytes of ECC; BCH4 needs adoption
720 * here!
721 */
722 for (i = 0; i < 13; i++)
723 printf("%02x ", read_ecc[i]);
724 puts("\n");
725 puts("calc_ecc: ");
726 for (i = 0; i < 13; i++)
727 printf("%02x ", calc_ecc[i]);
728 puts("\n");
729#endif
730 }
731 } else if (count < 0) {
732 puts("ecc unrecoverable error\n");
733 }
734 return count;
735}
736
737/**
738 * omap_free_bch - Release BCH ecc resources
739 * @mtd: MTD device structure
740 */
741static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
742{
743 struct nand_chip *chip = mtd->priv;
744 struct nand_bch_priv *chip_priv = chip->priv;
745 struct bch_control *bch = NULL;
746
747 if (chip_priv)
748 bch = chip_priv->control;
749
750 if (bch) {
751 free_bch(bch);
752 chip_priv->control = NULL;
753 }
754}
755#endif /* CONFIG_NAND_OMAP_BCH8 */
756
Simon Schwarz4f62e982011-09-14 15:30:16 -0400757#ifndef CONFIG_SPL_BUILD
Dirk Behme778933f2008-12-14 09:47:16 +0100758/*
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000759 * omap_nand_switch_ecc - switch the ECC operation between different engines
760 * (h/w and s/w) and different algorithms (hamming and BCHx)
Dirk Behme778933f2008-12-14 09:47:16 +0100761 *
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000762 * @hardware - true if one of the HW engines should be used
763 * @eccstrength - the number of bits that could be corrected
764 * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16)
Dirk Behme778933f2008-12-14 09:47:16 +0100765 */
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000766void omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
Dirk Behme778933f2008-12-14 09:47:16 +0100767{
768 struct nand_chip *nand;
769 struct mtd_info *mtd;
770
771 if (nand_curr_device < 0 ||
772 nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
773 !nand_info[nand_curr_device].name) {
774 printf("Error: Can't switch ecc, no devices available\n");
775 return;
776 }
777
778 mtd = &nand_info[nand_curr_device];
779 nand = mtd->priv;
780
781 nand->options |= NAND_OWN_BUFFERS;
782
783 /* Reset ecc interface */
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000784 nand->ecc.mode = NAND_ECC_NONE;
Dirk Behme778933f2008-12-14 09:47:16 +0100785 nand->ecc.read_page = NULL;
786 nand->ecc.write_page = NULL;
787 nand->ecc.read_oob = NULL;
788 nand->ecc.write_oob = NULL;
789 nand->ecc.hwctl = NULL;
790 nand->ecc.correct = NULL;
791 nand->ecc.calculate = NULL;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000792 nand->ecc.strength = eccstrength;
Dirk Behme778933f2008-12-14 09:47:16 +0100793
794 /* Setup the ecc configurations again */
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000795 if (hardware) {
796 if (eccstrength == 1) {
797 nand->ecc.mode = NAND_ECC_HW;
798 nand->ecc.layout = &hw_nand_oob;
799 nand->ecc.size = 512;
800 nand->ecc.bytes = 3;
801 nand->ecc.hwctl = omap_enable_hwecc;
802 nand->ecc.correct = omap_correct_data;
803 nand->ecc.calculate = omap_calculate_ecc;
804 omap_hwecc_init(nand);
805 printf("1-bit hamming HW ECC selected\n");
806 }
Andreas Bießmann82a65472013-04-05 04:55:21 +0000807#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8)
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000808 else if (eccstrength == 8) {
809 nand->ecc.mode = NAND_ECC_HW;
810 nand->ecc.layout = &hw_bch8_nand_oob;
811 nand->ecc.size = 512;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000812#ifdef CONFIG_AM33XX
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000813 nand->ecc.bytes = 14;
814 nand->ecc.read_page = omap_read_page_bch;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000815#else
816 nand->ecc.bytes = 13;
817#endif
Andreas Bießmann1e4eccf2013-04-04 23:52:50 +0000818 nand->ecc.hwctl = omap_enable_ecc_bch;
819 nand->ecc.correct = omap_correct_data_bch;
820 nand->ecc.calculate = omap_calculate_ecc_bch;
821 omap_hwecc_init_bch(nand, NAND_ECC_READ);
822 printf("8-bit BCH HW ECC selected\n");
823 }
Mansoor Ahamede5612512012-11-06 13:06:33 +0000824#endif
Dirk Behme778933f2008-12-14 09:47:16 +0100825 } else {
826 nand->ecc.mode = NAND_ECC_SOFT;
827 /* Use mtd default settings */
828 nand->ecc.layout = NULL;
Jeroen Hofstee3d33d092012-08-14 10:39:29 +0000829 nand->ecc.size = 0;
Dirk Behme778933f2008-12-14 09:47:16 +0100830 printf("SW ECC selected\n");
831 }
832
833 /* Update NAND handling after ECC mode switch */
834 nand_scan_tail(mtd);
835
836 nand->options &= ~NAND_OWN_BUFFERS;
837}
Simon Schwarz4f62e982011-09-14 15:30:16 -0400838#endif /* CONFIG_SPL_BUILD */
Dirk Behme778933f2008-12-14 09:47:16 +0100839
840/*
841 * Board-specific NAND initialization. The following members of the
842 * argument are board-specific:
843 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
844 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
845 * - cmd_ctrl: hardwarespecific function for accesing control-lines
846 * - waitfunc: hardwarespecific function for accesing device ready/busy line
847 * - ecc.hwctl: function to enable (reset) hardware ecc generator
848 * - ecc.mode: mode of ecc, see defines
849 * - chip_delay: chip dependent delay for transfering data from array to
850 * read regs (tR)
851 * - options: various chip options. They can partly be set to inform
852 * nand_scan about special functionality. See the defines for further
853 * explanation
854 */
855int board_nand_init(struct nand_chip *nand)
856{
857 int32_t gpmc_config = 0;
858 cs = 0;
859
860 /*
861 * xloader/Uboot's gpmc configuration would have configured GPMC for
862 * nand type of memory. The following logic scans and latches on to the
863 * first CS with NAND type memory.
864 * TBD: need to make this logic generic to handle multiple CS NAND
865 * devices.
866 */
867 while (cs < GPMC_MAX_CS) {
Dirk Behme778933f2008-12-14 09:47:16 +0100868 /* Check if NAND type is set */
Dirk Behmea4becd62009-08-08 09:30:22 +0200869 if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
Dirk Behme778933f2008-12-14 09:47:16 +0100870 /* Found it!! */
871 break;
872 }
873 cs++;
874 }
875 if (cs >= GPMC_MAX_CS) {
876 printf("NAND: Unable to find NAND settings in "
877 "GPMC Configuration - quitting\n");
878 return -ENODEV;
879 }
880
Dirk Behmea4becd62009-08-08 09:30:22 +0200881 gpmc_config = readl(&gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +0100882 /* Disable Write protect */
883 gpmc_config |= 0x10;
Dirk Behmea4becd62009-08-08 09:30:22 +0200884 writel(gpmc_config, &gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +0100885
Dirk Behmea4becd62009-08-08 09:30:22 +0200886 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
887 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Dirk Behme778933f2008-12-14 09:47:16 +0100888
889 nand->cmd_ctrl = omap_nand_hwcontrol;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000890 nand->options = NAND_NO_PADDING | NAND_CACHEPRG;
Dirk Behme778933f2008-12-14 09:47:16 +0100891 /* If we are 16 bit dev, our gpmc config tells us that */
Dirk Behmea4becd62009-08-08 09:30:22 +0200892 if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
Dirk Behme778933f2008-12-14 09:47:16 +0100893 nand->options |= NAND_BUSWIDTH_16;
894
895 nand->chip_delay = 100;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000896
Andreas Bießmann82a65472013-04-05 04:55:21 +0000897#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8)
Mansoor Ahamede5612512012-11-06 13:06:33 +0000898#ifdef CONFIG_AM33XX
Andreas Bießmann82a65472013-04-05 04:55:21 +0000899 /* AM33xx uses the ELM */
Mansoor Ahamede5612512012-11-06 13:06:33 +0000900 /* required in case of BCH */
901 elm_init();
Andreas Bießmann82a65472013-04-05 04:55:21 +0000902#else
903 /*
904 * Whereas other OMAP based SoC do not have the ELM, they use the BCH
905 * SW library.
906 */
907 bch_priv.control = init_bch(13, 8, 0x201b /* hw polynominal */);
908 if (!bch_priv.control) {
909 puts("Could not init_bch()\n");
910 return -ENODEV;
911 }
912#endif
Mansoor Ahamede5612512012-11-06 13:06:33 +0000913 /* BCH info that will be correct for SPL or overridden otherwise. */
914 nand->priv = &bch_priv;
915#endif
916
Dirk Behme778933f2008-12-14 09:47:16 +0100917 /* Default ECC mode */
Andreas Bießmann82a65472013-04-05 04:55:21 +0000918#if defined(CONFIG_AM33XX) || defined(CONFIG_NAND_OMAP_BCH8)
Mansoor Ahamede5612512012-11-06 13:06:33 +0000919 nand->ecc.mode = NAND_ECC_HW;
920 nand->ecc.layout = &hw_bch8_nand_oob;
921 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
922 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
Sergey Lapin67da22a2013-06-04 11:42:43 -0500923 nand->ecc.strength = 8;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000924 nand->ecc.hwctl = omap_enable_ecc_bch;
925 nand->ecc.correct = omap_correct_data_bch;
926 nand->ecc.calculate = omap_calculate_ecc_bch;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000927#ifdef CONFIG_AM33XX
Mansoor Ahamede5612512012-11-06 13:06:33 +0000928 nand->ecc.read_page = omap_read_page_bch;
Andreas Bießmann82a65472013-04-05 04:55:21 +0000929#endif
Mansoor Ahamede5612512012-11-06 13:06:33 +0000930 omap_hwecc_init_bch(nand, NAND_ECC_READ);
931#else
Ilya Yanokd7bca052011-11-28 06:37:38 +0000932#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC)
Dirk Behme778933f2008-12-14 09:47:16 +0100933 nand->ecc.mode = NAND_ECC_SOFT;
Simon Schwarz4f62e982011-09-14 15:30:16 -0400934#else
935 nand->ecc.mode = NAND_ECC_HW;
936 nand->ecc.layout = &hw_nand_oob;
937 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
938 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
939 nand->ecc.hwctl = omap_enable_hwecc;
940 nand->ecc.correct = omap_correct_data;
941 nand->ecc.calculate = omap_calculate_ecc;
Sergey Lapin67da22a2013-06-04 11:42:43 -0500942 nand->ecc.strength = 1;
Simon Schwarz4f62e982011-09-14 15:30:16 -0400943 omap_hwecc_init(nand);
Ilya Yanokd7bca052011-11-28 06:37:38 +0000944#endif
Mansoor Ahamede5612512012-11-06 13:06:33 +0000945#endif
Simon Schwarz4f62e982011-09-14 15:30:16 -0400946
Ilya Yanokd7bca052011-11-28 06:37:38 +0000947#ifdef CONFIG_SPL_BUILD
Simon Schwarz4f62e982011-09-14 15:30:16 -0400948 if (nand->options & NAND_BUSWIDTH_16)
949 nand->read_buf = nand_read_buf16;
950 else
951 nand->read_buf = nand_read_buf;
952 nand->dev_ready = omap_spl_dev_ready;
953#endif
Dirk Behme778933f2008-12-14 09:47:16 +0100954
955 return 0;
956}