blob: cee394ece4b7699bc3932c367f436aeb2debc885 [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 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25#include <asm/io.h>
26#include <asm/errno.h>
27#include <asm/arch/mem.h>
28#include <asm/arch/omap_gpmc.h>
29#include <linux/mtd/nand_ecc.h>
Stefano Babicaade5792012-03-21 23:56:17 +000030#include <linux/compiler.h>
Dirk Behme778933f2008-12-14 09:47:16 +010031#include <nand.h>
Mansoor Ahamede5612512012-11-06 13:06:33 +000032#ifdef CONFIG_AM33XX
33#include <asm/arch/elm.h>
34#endif
Dirk Behme778933f2008-12-14 09:47:16 +010035
36static uint8_t cs;
Stefano Babicaade5792012-03-21 23:56:17 +000037static __maybe_unused struct nand_ecclayout hw_nand_oob =
38 GPMC_NAND_HW_ECC_LAYOUT;
Dirk Behme778933f2008-12-14 09:47:16 +010039
40/*
41 * omap_nand_hwcontrol - Set the address pointers corretly for the
42 * following address/data/command operation
43 */
44static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
45 uint32_t ctrl)
46{
47 register struct nand_chip *this = mtd->priv;
48
49 /*
50 * Point the IO_ADDR to DATA and ADDRESS registers instead
51 * of chip address
52 */
53 switch (ctrl) {
54 case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
Dirk Behmea4becd62009-08-08 09:30:22 +020055 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Dirk Behme778933f2008-12-14 09:47:16 +010056 break;
57 case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
Dirk Behmea4becd62009-08-08 09:30:22 +020058 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
Dirk Behme778933f2008-12-14 09:47:16 +010059 break;
60 case NAND_CTRL_CHANGE | NAND_NCE:
Dirk Behmea4becd62009-08-08 09:30:22 +020061 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
Dirk Behme778933f2008-12-14 09:47:16 +010062 break;
63 }
64
65 if (cmd != NAND_CMD_NONE)
66 writeb(cmd, this->IO_ADDR_W);
67}
68
Simon Schwarz4f62e982011-09-14 15:30:16 -040069#ifdef CONFIG_SPL_BUILD
70/* Check wait pin as dev ready indicator */
71int omap_spl_dev_ready(struct mtd_info *mtd)
72{
73 return gpmc_cfg->status & (1 << 8);
74}
75#endif
76
Dirk Behme778933f2008-12-14 09:47:16 +010077/*
78 * omap_hwecc_init - Initialize the Hardware ECC for NAND flash in
79 * GPMC controller
80 * @mtd: MTD device structure
81 *
82 */
Stefano Babicaade5792012-03-21 23:56:17 +000083static void __maybe_unused omap_hwecc_init(struct nand_chip *chip)
Dirk Behme778933f2008-12-14 09:47:16 +010084{
85 /*
86 * Init ECC Control Register
87 * Clear all ECC | Enable Reg1
88 */
Dirk Behmea4becd62009-08-08 09:30:22 +020089 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
90 writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL, &gpmc_cfg->ecc_size_config);
Dirk Behme778933f2008-12-14 09:47:16 +010091}
92
93/*
94 * gen_true_ecc - This function will generate true ECC value, which
95 * can be used when correcting data read from NAND flash memory core
96 *
97 * @ecc_buf: buffer to store ecc code
98 *
99 * @return: re-formatted ECC value
100 */
101static uint32_t gen_true_ecc(uint8_t *ecc_buf)
102{
103 return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
104 ((ecc_buf[2] & 0x0F) << 8);
105}
106
107/*
108 * omap_correct_data - Compares the ecc read from nand spare area with ECC
109 * registers values and corrects one bit error if it has occured
110 * Further details can be had from OMAP TRM and the following selected links:
111 * http://en.wikipedia.org/wiki/Hamming_code
112 * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf
113 *
114 * @mtd: MTD device structure
115 * @dat: page data
116 * @read_ecc: ecc read from nand flash
117 * @calc_ecc: ecc read from ECC registers
118 *
119 * @return 0 if data is OK or corrected, else returns -1
120 */
Stefano Babicaade5792012-03-21 23:56:17 +0000121static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
Dirk Behme778933f2008-12-14 09:47:16 +0100122 uint8_t *read_ecc, uint8_t *calc_ecc)
123{
124 uint32_t orig_ecc, new_ecc, res, hm;
125 uint16_t parity_bits, byte;
126 uint8_t bit;
127
128 /* Regenerate the orginal ECC */
129 orig_ecc = gen_true_ecc(read_ecc);
130 new_ecc = gen_true_ecc(calc_ecc);
131 /* Get the XOR of real ecc */
132 res = orig_ecc ^ new_ecc;
133 if (res) {
134 /* Get the hamming width */
135 hm = hweight32(res);
136 /* Single bit errors can be corrected! */
137 if (hm == 12) {
138 /* Correctable data! */
139 parity_bits = res >> 16;
140 bit = (parity_bits & 0x7);
141 byte = (parity_bits >> 3) & 0x1FF;
142 /* Flip the bit to correct */
143 dat[byte] ^= (0x1 << bit);
144 } else if (hm == 1) {
145 printf("Error: Ecc is wrong\n");
146 /* ECC itself is corrupted */
147 return 2;
148 } else {
149 /*
150 * hm distance != parity pairs OR one, could mean 2 bit
151 * error OR potentially be on a blank page..
152 * orig_ecc: contains spare area data from nand flash.
153 * new_ecc: generated ecc while reading data area.
154 * Note: if the ecc = 0, all data bits from which it was
155 * generated are 0xFF.
156 * The 3 byte(24 bits) ecc is generated per 512byte
157 * chunk of a page. If orig_ecc(from spare area)
158 * is 0xFF && new_ecc(computed now from data area)=0x0,
159 * this means that data area is 0xFF and spare area is
160 * 0xFF. A sure sign of a erased page!
161 */
162 if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000))
163 return 0;
164 printf("Error: Bad compare! failed\n");
165 /* detected 2 bit error */
166 return -1;
167 }
168 }
169 return 0;
170}
171
172/*
173 * omap_calculate_ecc - Generate non-inverted ECC bytes.
174 *
175 * Using noninverted ECC can be considered ugly since writing a blank
176 * page ie. padding will clear the ECC bytes. This is no problem as
177 * long nobody is trying to write data on the seemingly unused page.
178 * Reading an erased page will produce an ECC mismatch between
179 * generated and read ECC bytes that has to be dealt with separately.
180 * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
181 * is used, the result of read will be 0x0 while the ECC offsets of the
182 * spare area will be 0xFF which will result in an ECC mismatch.
183 * @mtd: MTD structure
184 * @dat: unused
185 * @ecc_code: ecc_code buffer
186 */
Stefano Babicaade5792012-03-21 23:56:17 +0000187static int __maybe_unused omap_calculate_ecc(struct mtd_info *mtd,
188 const uint8_t *dat, uint8_t *ecc_code)
Dirk Behme778933f2008-12-14 09:47:16 +0100189{
190 u_int32_t val;
191
192 /* Start Reading from HW ECC1_Result = 0x200 */
Dirk Behmea4becd62009-08-08 09:30:22 +0200193 val = readl(&gpmc_cfg->ecc1_result);
Dirk Behme778933f2008-12-14 09:47:16 +0100194
195 ecc_code[0] = val & 0xFF;
196 ecc_code[1] = (val >> 16) & 0xFF;
197 ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
198
199 /*
200 * Stop reading anymore ECC vals and clear old results
201 * enable will be called if more reads are required
202 */
Dirk Behmea4becd62009-08-08 09:30:22 +0200203 writel(0x000, &gpmc_cfg->ecc_config);
Dirk Behme778933f2008-12-14 09:47:16 +0100204
205 return 0;
206}
207
208/*
209 * omap_enable_ecc - This function enables the hardware ecc functionality
210 * @mtd: MTD device structure
211 * @mode: Read/Write mode
212 */
Stefano Babicaade5792012-03-21 23:56:17 +0000213static void __maybe_unused omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
Dirk Behme778933f2008-12-14 09:47:16 +0100214{
215 struct nand_chip *chip = mtd->priv;
216 uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
217
218 switch (mode) {
219 case NAND_ECC_READ:
220 case NAND_ECC_WRITE:
221 /* Clear the ecc result registers, select ecc reg as 1 */
Dirk Behmea4becd62009-08-08 09:30:22 +0200222 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
Dirk Behme778933f2008-12-14 09:47:16 +0100223
224 /*
225 * Size 0 = 0xFF, Size1 is 0xFF - both are 512 bytes
226 * tell all regs to generate size0 sized regs
227 * we just have a single ECC engine for all CS
228 */
229 writel(ECCSIZE1 | ECCSIZE0 | ECCSIZE0SEL,
Dirk Behmea4becd62009-08-08 09:30:22 +0200230 &gpmc_cfg->ecc_size_config);
Dirk Behme778933f2008-12-14 09:47:16 +0100231 val = (dev_width << 7) | (cs << 1) | (0x1);
Dirk Behmea4becd62009-08-08 09:30:22 +0200232 writel(val, &gpmc_cfg->ecc_config);
Dirk Behme778933f2008-12-14 09:47:16 +0100233 break;
234 default:
235 printf("Error: Unrecognized Mode[%d]!\n", mode);
236 break;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000237 }
238}
239
240/*
241 * BCH8 support (needs ELM and thus AM33xx-only)
242 */
243#ifdef CONFIG_AM33XX
244struct nand_bch_priv {
245 uint8_t mode;
246 uint8_t type;
247 uint8_t nibbles;
248};
249
250/* bch types */
251#define ECC_BCH4 0
252#define ECC_BCH8 1
253#define ECC_BCH16 2
254
255/* BCH nibbles for diff bch levels */
256#define NAND_ECC_HW_BCH ((uint8_t)(NAND_ECC_HW_OOB_FIRST) + 1)
257#define ECC_BCH4_NIBBLES 13
258#define ECC_BCH8_NIBBLES 26
259#define ECC_BCH16_NIBBLES 52
260
261static struct nand_ecclayout hw_bch8_nand_oob = GPMC_NAND_HW_BCH8_ECC_LAYOUT;
262
263static struct nand_bch_priv bch_priv = {
264 .mode = NAND_ECC_HW_BCH,
265 .type = ECC_BCH8,
266 .nibbles = ECC_BCH8_NIBBLES
267};
268
269/*
270 * omap_read_bch8_result - Read BCH result for BCH8 level
271 *
272 * @mtd: MTD device structure
273 * @big_endian: When set read register 3 first
274 * @ecc_code: Read syndrome from BCH result registers
275 */
276static void omap_read_bch8_result(struct mtd_info *mtd, uint8_t big_endian,
277 uint8_t *ecc_code)
278{
279 uint32_t *ptr;
280 int8_t i = 0, j;
281
282 if (big_endian) {
283 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
284 ecc_code[i++] = readl(ptr) & 0xFF;
285 ptr--;
286 for (j = 0; j < 3; j++) {
287 ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
288 ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
289 ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
290 ecc_code[i++] = readl(ptr) & 0xFF;
291 ptr--;
292 }
293 } else {
294 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[0];
295 for (j = 0; j < 3; j++) {
296 ecc_code[i++] = readl(ptr) & 0xFF;
297 ecc_code[i++] = (readl(ptr) >> 8) & 0xFF;
298 ecc_code[i++] = (readl(ptr) >> 16) & 0xFF;
299 ecc_code[i++] = (readl(ptr) >> 24) & 0xFF;
300 ptr++;
301 }
302 ecc_code[i++] = readl(ptr) & 0xFF;
303 ecc_code[i++] = 0; /* 14th byte is always zero */
304 }
305}
306
307/*
308 * omap_ecc_disable - Disable H/W ECC calculation
309 *
310 * @mtd: MTD device structure
311 *
312 */
313static void omap_ecc_disable(struct mtd_info *mtd)
314{
315 writel((readl(&gpmc_cfg->ecc_config) & ~0x1),
316 &gpmc_cfg->ecc_config);
317}
318
319/*
320 * omap_rotate_ecc_bch - Rotate the syndrome bytes
321 *
322 * @mtd: MTD device structure
323 * @calc_ecc: ECC read from ECC registers
324 * @syndrome: Rotated syndrome will be retuned in this array
325 *
326 */
327static void omap_rotate_ecc_bch(struct mtd_info *mtd, uint8_t *calc_ecc,
328 uint8_t *syndrome)
329{
330 struct nand_chip *chip = mtd->priv;
331 struct nand_bch_priv *bch = chip->priv;
332 uint8_t n_bytes = 0;
333 int8_t i, j;
334
335 switch (bch->type) {
336 case ECC_BCH4:
337 n_bytes = 8;
338 break;
339
340 case ECC_BCH16:
341 n_bytes = 28;
342 break;
343
344 case ECC_BCH8:
345 default:
346 n_bytes = 13;
347 break;
348 }
349
350 for (i = 0, j = (n_bytes-1); i < n_bytes; i++, j--)
351 syndrome[i] = calc_ecc[j];
352}
353
354/*
355 * omap_calculate_ecc_bch - Read BCH ECC result
356 *
357 * @mtd: MTD structure
358 * @dat: unused
359 * @ecc_code: ecc_code buffer
360 */
361static int omap_calculate_ecc_bch(struct mtd_info *mtd, const uint8_t *dat,
362 uint8_t *ecc_code)
363{
364 struct nand_chip *chip = mtd->priv;
365 struct nand_bch_priv *bch = chip->priv;
366 uint8_t big_endian = 1;
367 int8_t ret = 0;
368
369 if (bch->type == ECC_BCH8)
370 omap_read_bch8_result(mtd, big_endian, ecc_code);
371 else /* BCH4 and BCH16 currently not supported */
372 ret = -1;
373
374 /*
375 * Stop reading anymore ECC vals and clear old results
376 * enable will be called if more reads are required
377 */
378 omap_ecc_disable(mtd);
379
380 return ret;
381}
382
383/*
384 * omap_fix_errors_bch - Correct bch error in the data
385 *
386 * @mtd: MTD device structure
387 * @data: Data read from flash
388 * @error_count:Number of errors in data
389 * @error_loc: Locations of errors in the data
390 *
391 */
392static void omap_fix_errors_bch(struct mtd_info *mtd, uint8_t *data,
393 uint32_t error_count, uint32_t *error_loc)
394{
395 struct nand_chip *chip = mtd->priv;
396 struct nand_bch_priv *bch = chip->priv;
397 uint8_t count = 0;
398 uint32_t error_byte_pos;
399 uint32_t error_bit_mask;
400 uint32_t last_bit = (bch->nibbles * 4) - 1;
401
402 /* Flip all bits as specified by the error location array. */
403 /* FOR( each found error location flip the bit ) */
404 for (count = 0; count < error_count; count++) {
405 if (error_loc[count] > last_bit) {
406 /* Remove the ECC spare bits from correction. */
407 error_loc[count] -= (last_bit + 1);
408 /* Offset bit in data region */
409 error_byte_pos = ((512 * 8) -
410 (error_loc[count]) - 1) / 8;
411 /* Error Bit mask */
412 error_bit_mask = 0x1 << (error_loc[count] % 8);
413 /* Toggle the error bit to make the correction. */
414 data[error_byte_pos] ^= error_bit_mask;
415 }
Dirk Behme778933f2008-12-14 09:47:16 +0100416 }
417}
418
Mansoor Ahamede5612512012-11-06 13:06:33 +0000419/*
420 * omap_correct_data_bch - Compares the ecc read from nand spare area
421 * with ECC registers values and corrects one bit error if it has occured
422 *
423 * @mtd: MTD device structure
424 * @dat: page data
425 * @read_ecc: ecc read from nand flash (ignored)
426 * @calc_ecc: ecc read from ECC registers
427 *
428 * @return 0 if data is OK or corrected, else returns -1
429 */
430static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
431 uint8_t *read_ecc, uint8_t *calc_ecc)
432{
433 struct nand_chip *chip = mtd->priv;
434 struct nand_bch_priv *bch = chip->priv;
435 uint8_t syndrome[28];
436 uint32_t error_count = 0;
437 uint32_t error_loc[8];
438 uint32_t i, ecc_flag;
439
440 ecc_flag = 0;
441 for (i = 0; i < chip->ecc.bytes; i++)
442 if (read_ecc[i] != 0xff)
443 ecc_flag = 1;
444
445 if (!ecc_flag)
446 return 0;
447
448 elm_reset();
449 elm_config((enum bch_level)(bch->type));
450
451 /*
452 * while reading ECC result we read it in big endian.
453 * Hence while loading to ELM we have rotate to get the right endian.
454 */
455 omap_rotate_ecc_bch(mtd, calc_ecc, syndrome);
456
457 /* use elm module to check for errors */
458 if (elm_check_error(syndrome, bch->nibbles, &error_count,
459 error_loc) != 0) {
460 printf("ECC: uncorrectable.\n");
461 return -1;
462 }
463
464 /* correct bch error */
465 if (error_count > 0)
466 omap_fix_errors_bch(mtd, dat, error_count, error_loc);
467
468 return 0;
469}
470/*
471 * omap_hwecc_init_bch - Initialize the BCH Hardware ECC for NAND flash in
472 * GPMC controller
473 * @mtd: MTD device structure
474 * @mode: Read/Write mode
475 */
476static void omap_hwecc_init_bch(struct nand_chip *chip, int32_t mode)
477{
478 uint32_t val, dev_width = (chip->options & NAND_BUSWIDTH_16) >> 1;
479 uint32_t unused_length = 0;
480 struct nand_bch_priv *bch = chip->priv;
481
482 switch (bch->nibbles) {
483 case ECC_BCH4_NIBBLES:
484 unused_length = 3;
485 break;
486 case ECC_BCH8_NIBBLES:
487 unused_length = 2;
488 break;
489 case ECC_BCH16_NIBBLES:
490 unused_length = 0;
491 break;
492 }
493
494 /* Clear the ecc result registers, select ecc reg as 1 */
495 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
496
497 switch (mode) {
498 case NAND_ECC_WRITE:
499 /* eccsize1 config */
500 val = ((unused_length + bch->nibbles) << 22);
501 break;
502
503 case NAND_ECC_READ:
504 default:
505 /* by default eccsize0 selected for ecc1resultsize */
506 /* eccsize0 config */
507 val = (bch->nibbles << 12);
508 /* eccsize1 config */
509 val |= (unused_length << 22);
510 break;
511 }
512 /* ecc size configuration */
513 writel(val, &gpmc_cfg->ecc_size_config);
514 /* by default 512bytes sector page is selected */
515 /* set bch mode */
516 val = (1 << 16);
517 /* bch4 / bch8 / bch16 */
518 val |= (bch->type << 12);
519 /* set wrap mode to 1 */
520 val |= (1 << 8);
521 val |= (dev_width << 7);
522 val |= (cs << 1);
523 writel(val, &gpmc_cfg->ecc_config);
524}
525
526/*
527 * omap_enable_ecc_bch- This function enables the bch h/w ecc functionality
528 * @mtd: MTD device structure
529 * @mode: Read/Write mode
530 *
531 */
532static void omap_enable_ecc_bch(struct mtd_info *mtd, int32_t mode)
533{
534 struct nand_chip *chip = mtd->priv;
535
536 omap_hwecc_init_bch(chip, mode);
537 /* enable ecc */
538 writel((readl(&gpmc_cfg->ecc_config) | 0x1), &gpmc_cfg->ecc_config);
539}
540
541/**
542 * omap_read_page_bch - hardware ecc based page read function
543 * @mtd: mtd info structure
544 * @chip: nand chip info structure
545 * @buf: buffer to store read data
546 * @page: page number to read
547 *
548 */
549static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
550 uint8_t *buf, int page)
551{
552 int i, eccsize = chip->ecc.size;
553 int eccbytes = chip->ecc.bytes;
554 int eccsteps = chip->ecc.steps;
555 uint8_t *p = buf;
556 uint8_t *ecc_calc = chip->buffers->ecccalc;
557 uint8_t *ecc_code = chip->buffers->ecccode;
558 uint32_t *eccpos = chip->ecc.layout->eccpos;
559 uint8_t *oob = chip->oob_poi;
560 uint32_t data_pos;
561 uint32_t oob_pos;
562
563 data_pos = 0;
564 /* oob area start */
565 oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
566 oob += chip->ecc.layout->eccpos[0];
567
568 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
569 oob += eccbytes) {
570 chip->ecc.hwctl(mtd, NAND_ECC_READ);
571 /* read data */
572 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, page);
573 chip->read_buf(mtd, p, eccsize);
574
575 /* read respective ecc from oob area */
576 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, page);
577 chip->read_buf(mtd, oob, eccbytes);
578 /* read syndrome */
579 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
580
581 data_pos += eccsize;
582 oob_pos += eccbytes;
583 }
584
585 for (i = 0; i < chip->ecc.total; i++)
586 ecc_code[i] = chip->oob_poi[eccpos[i]];
587
588 eccsteps = chip->ecc.steps;
589 p = buf;
590
591 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
592 int stat;
593
594 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
595 if (stat < 0)
596 mtd->ecc_stats.failed++;
597 else
598 mtd->ecc_stats.corrected += stat;
599 }
600 return 0;
601}
602#endif /* CONFIG_AM33XX */
603
Simon Schwarz4f62e982011-09-14 15:30:16 -0400604#ifndef CONFIG_SPL_BUILD
Dirk Behme778933f2008-12-14 09:47:16 +0100605/*
606 * omap_nand_switch_ecc - switch the ECC operation b/w h/w ecc and s/w ecc.
607 * The default is to come up on s/w ecc
608 *
609 * @hardware - 1 -switch to h/w ecc, 0 - s/w ecc
610 *
611 */
612void omap_nand_switch_ecc(int32_t hardware)
613{
614 struct nand_chip *nand;
615 struct mtd_info *mtd;
616
617 if (nand_curr_device < 0 ||
618 nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
619 !nand_info[nand_curr_device].name) {
620 printf("Error: Can't switch ecc, no devices available\n");
621 return;
622 }
623
624 mtd = &nand_info[nand_curr_device];
625 nand = mtd->priv;
626
627 nand->options |= NAND_OWN_BUFFERS;
628
629 /* Reset ecc interface */
630 nand->ecc.read_page = NULL;
631 nand->ecc.write_page = NULL;
632 nand->ecc.read_oob = NULL;
633 nand->ecc.write_oob = NULL;
634 nand->ecc.hwctl = NULL;
635 nand->ecc.correct = NULL;
636 nand->ecc.calculate = NULL;
637
638 /* Setup the ecc configurations again */
Mansoor Ahamede5612512012-11-06 13:06:33 +0000639 if (hardware == 1) {
Dirk Behme778933f2008-12-14 09:47:16 +0100640 nand->ecc.mode = NAND_ECC_HW;
641 nand->ecc.layout = &hw_nand_oob;
642 nand->ecc.size = 512;
643 nand->ecc.bytes = 3;
644 nand->ecc.hwctl = omap_enable_hwecc;
645 nand->ecc.correct = omap_correct_data;
646 nand->ecc.calculate = omap_calculate_ecc;
647 omap_hwecc_init(nand);
648 printf("HW ECC selected\n");
Mansoor Ahamede5612512012-11-06 13:06:33 +0000649#ifdef CONFIG_AM33XX
650 } else if (hardware == 2) {
651 nand->ecc.mode = NAND_ECC_HW;
652 nand->ecc.layout = &hw_bch8_nand_oob;
653 nand->ecc.size = 512;
654 nand->ecc.bytes = 14;
655 nand->ecc.read_page = omap_read_page_bch;
656 nand->ecc.hwctl = omap_enable_ecc_bch;
657 nand->ecc.correct = omap_correct_data_bch;
658 nand->ecc.calculate = omap_calculate_ecc_bch;
659 omap_hwecc_init_bch(nand, NAND_ECC_READ);
660 printf("HW BCH8 selected\n");
661#endif
Dirk Behme778933f2008-12-14 09:47:16 +0100662 } else {
663 nand->ecc.mode = NAND_ECC_SOFT;
664 /* Use mtd default settings */
665 nand->ecc.layout = NULL;
Jeroen Hofstee3d33d092012-08-14 10:39:29 +0000666 nand->ecc.size = 0;
Dirk Behme778933f2008-12-14 09:47:16 +0100667 printf("SW ECC selected\n");
668 }
669
670 /* Update NAND handling after ECC mode switch */
671 nand_scan_tail(mtd);
672
673 nand->options &= ~NAND_OWN_BUFFERS;
674}
Simon Schwarz4f62e982011-09-14 15:30:16 -0400675#endif /* CONFIG_SPL_BUILD */
Dirk Behme778933f2008-12-14 09:47:16 +0100676
677/*
678 * Board-specific NAND initialization. The following members of the
679 * argument are board-specific:
680 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
681 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
682 * - cmd_ctrl: hardwarespecific function for accesing control-lines
683 * - waitfunc: hardwarespecific function for accesing device ready/busy line
684 * - ecc.hwctl: function to enable (reset) hardware ecc generator
685 * - ecc.mode: mode of ecc, see defines
686 * - chip_delay: chip dependent delay for transfering data from array to
687 * read regs (tR)
688 * - options: various chip options. They can partly be set to inform
689 * nand_scan about special functionality. See the defines for further
690 * explanation
691 */
692int board_nand_init(struct nand_chip *nand)
693{
694 int32_t gpmc_config = 0;
695 cs = 0;
696
697 /*
698 * xloader/Uboot's gpmc configuration would have configured GPMC for
699 * nand type of memory. The following logic scans and latches on to the
700 * first CS with NAND type memory.
701 * TBD: need to make this logic generic to handle multiple CS NAND
702 * devices.
703 */
704 while (cs < GPMC_MAX_CS) {
Dirk Behme778933f2008-12-14 09:47:16 +0100705 /* Check if NAND type is set */
Dirk Behmea4becd62009-08-08 09:30:22 +0200706 if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
Dirk Behme778933f2008-12-14 09:47:16 +0100707 /* Found it!! */
708 break;
709 }
710 cs++;
711 }
712 if (cs >= GPMC_MAX_CS) {
713 printf("NAND: Unable to find NAND settings in "
714 "GPMC Configuration - quitting\n");
715 return -ENODEV;
716 }
717
Dirk Behmea4becd62009-08-08 09:30:22 +0200718 gpmc_config = readl(&gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +0100719 /* Disable Write protect */
720 gpmc_config |= 0x10;
Dirk Behmea4becd62009-08-08 09:30:22 +0200721 writel(gpmc_config, &gpmc_cfg->config);
Dirk Behme778933f2008-12-14 09:47:16 +0100722
Dirk Behmea4becd62009-08-08 09:30:22 +0200723 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
724 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
Dirk Behme778933f2008-12-14 09:47:16 +0100725
726 nand->cmd_ctrl = omap_nand_hwcontrol;
727 nand->options = NAND_NO_PADDING | NAND_CACHEPRG | NAND_NO_AUTOINCR;
728 /* If we are 16 bit dev, our gpmc config tells us that */
Dirk Behmea4becd62009-08-08 09:30:22 +0200729 if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000)
Dirk Behme778933f2008-12-14 09:47:16 +0100730 nand->options |= NAND_BUSWIDTH_16;
731
732 nand->chip_delay = 100;
Mansoor Ahamede5612512012-11-06 13:06:33 +0000733
734#ifdef CONFIG_AM33XX
735 /* required in case of BCH */
736 elm_init();
737
738 /* BCH info that will be correct for SPL or overridden otherwise. */
739 nand->priv = &bch_priv;
740#endif
741
Dirk Behme778933f2008-12-14 09:47:16 +0100742 /* Default ECC mode */
Mansoor Ahamede5612512012-11-06 13:06:33 +0000743#ifdef CONFIG_AM33XX
744 nand->ecc.mode = NAND_ECC_HW;
745 nand->ecc.layout = &hw_bch8_nand_oob;
746 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
747 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
748 nand->ecc.hwctl = omap_enable_ecc_bch;
749 nand->ecc.correct = omap_correct_data_bch;
750 nand->ecc.calculate = omap_calculate_ecc_bch;
751 nand->ecc.read_page = omap_read_page_bch;
752 omap_hwecc_init_bch(nand, NAND_ECC_READ);
753#else
Ilya Yanokd7bca052011-11-28 06:37:38 +0000754#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_NAND_SOFTECC)
Dirk Behme778933f2008-12-14 09:47:16 +0100755 nand->ecc.mode = NAND_ECC_SOFT;
Simon Schwarz4f62e982011-09-14 15:30:16 -0400756#else
757 nand->ecc.mode = NAND_ECC_HW;
758 nand->ecc.layout = &hw_nand_oob;
759 nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
760 nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
761 nand->ecc.hwctl = omap_enable_hwecc;
762 nand->ecc.correct = omap_correct_data;
763 nand->ecc.calculate = omap_calculate_ecc;
764 omap_hwecc_init(nand);
Ilya Yanokd7bca052011-11-28 06:37:38 +0000765#endif
Mansoor Ahamede5612512012-11-06 13:06:33 +0000766#endif
Simon Schwarz4f62e982011-09-14 15:30:16 -0400767
Ilya Yanokd7bca052011-11-28 06:37:38 +0000768#ifdef CONFIG_SPL_BUILD
Simon Schwarz4f62e982011-09-14 15:30:16 -0400769 if (nand->options & NAND_BUSWIDTH_16)
770 nand->read_buf = nand_read_buf16;
771 else
772 nand->read_buf = nand_read_buf;
773 nand->dev_ready = omap_spl_dev_ready;
774#endif
Dirk Behme778933f2008-12-14 09:47:16 +0100775
776 return 0;
777}