2 * (C) Copyright 2004-2008 Texas Instruments, <www.ti.com>
3 * Rohit Choraria <rohitkc@ti.com>
5 * SPDX-License-Identifier: GPL-2.0+
10 #include <asm/errno.h>
11 #include <asm/arch/mem.h>
12 #include <linux/mtd/omap_gpmc.h>
13 #include <linux/mtd/nand_ecc.h>
14 #include <linux/bch.h>
15 #include <linux/compiler.h>
17 #include <linux/mtd/omap_elm.h>
19 #define BADBLOCK_MARKER_LENGTH 2
20 #define SECTOR_BYTES 512
21 #define ECCCLEAR (0x1 << 8)
22 #define ECCRESULTREG1 (0x1 << 0)
23 /* 4 bit padding to make byte aligned, 56 = 52 + 4 */
24 #define BCH4_BIT_PAD 4
27 static u8 bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
28 0x97, 0x79, 0xe5, 0x24, 0xb5};
30 static uint8_t cs_next;
31 static __maybe_unused struct nand_ecclayout omap_ecclayout;
34 * Driver configurations
36 struct omap_nand_info {
37 struct bch_control *control;
38 enum omap_ecc ecc_scheme;
42 /* We are wasting a bit of memory but al least we are safe */
43 static struct omap_nand_info omap_nand_info[GPMC_MAX_CS];
46 * omap_nand_hwcontrol - Set the address pointers corretly for the
47 * following address/data/command operation
49 static void omap_nand_hwcontrol(struct mtd_info *mtd, int32_t cmd,
52 register struct nand_chip *this = mtd->priv;
53 struct omap_nand_info *info = this->priv;
57 * Point the IO_ADDR to DATA and ADDRESS registers instead
61 case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
62 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
64 case NAND_CTRL_CHANGE | NAND_CTRL_ALE:
65 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr;
67 case NAND_CTRL_CHANGE | NAND_NCE:
68 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
72 if (cmd != NAND_CMD_NONE)
73 writeb(cmd, this->IO_ADDR_W);
76 /* Check wait pin as dev ready indicator */
77 static int omap_dev_ready(struct mtd_info *mtd)
79 return gpmc_cfg->status & (1 << 8);
83 * gen_true_ecc - This function will generate true ECC value, which
84 * can be used when correcting data read from NAND flash memory core
86 * @ecc_buf: buffer to store ecc code
88 * @return: re-formatted ECC value
90 static uint32_t gen_true_ecc(uint8_t *ecc_buf)
92 return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
93 ((ecc_buf[2] & 0x0F) << 8);
97 * omap_correct_data - Compares the ecc read from nand spare area with ECC
98 * registers values and corrects one bit error if it has occured
99 * Further details can be had from OMAP TRM and the following selected links:
100 * http://en.wikipedia.org/wiki/Hamming_code
101 * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf
103 * @mtd: MTD device structure
105 * @read_ecc: ecc read from nand flash
106 * @calc_ecc: ecc read from ECC registers
108 * @return 0 if data is OK or corrected, else returns -1
110 static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
111 uint8_t *read_ecc, uint8_t *calc_ecc)
113 uint32_t orig_ecc, new_ecc, res, hm;
114 uint16_t parity_bits, byte;
117 /* Regenerate the orginal ECC */
118 orig_ecc = gen_true_ecc(read_ecc);
119 new_ecc = gen_true_ecc(calc_ecc);
120 /* Get the XOR of real ecc */
121 res = orig_ecc ^ new_ecc;
123 /* Get the hamming width */
125 /* Single bit errors can be corrected! */
127 /* Correctable data! */
128 parity_bits = res >> 16;
129 bit = (parity_bits & 0x7);
130 byte = (parity_bits >> 3) & 0x1FF;
131 /* Flip the bit to correct */
132 dat[byte] ^= (0x1 << bit);
133 } else if (hm == 1) {
134 printf("Error: Ecc is wrong\n");
135 /* ECC itself is corrupted */
139 * hm distance != parity pairs OR one, could mean 2 bit
140 * error OR potentially be on a blank page..
141 * orig_ecc: contains spare area data from nand flash.
142 * new_ecc: generated ecc while reading data area.
143 * Note: if the ecc = 0, all data bits from which it was
144 * generated are 0xFF.
145 * The 3 byte(24 bits) ecc is generated per 512byte
146 * chunk of a page. If orig_ecc(from spare area)
147 * is 0xFF && new_ecc(computed now from data area)=0x0,
148 * this means that data area is 0xFF and spare area is
149 * 0xFF. A sure sign of a erased page!
151 if ((orig_ecc == 0x0FFF0FFF) && (new_ecc == 0x00000000))
153 printf("Error: Bad compare! failed\n");
154 /* detected 2 bit error */
162 * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write
163 * @mtd: MTD device structure
164 * @mode: Read/Write mode
167 static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode)
169 struct nand_chip *nand = mtd->priv;
170 struct omap_nand_info *info = nand->priv;
171 unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0;
172 unsigned int ecc_algo = 0;
173 unsigned int bch_type = 0;
174 unsigned int eccsize1 = 0x00, eccsize0 = 0x00, bch_wrapmode = 0x00;
175 u32 ecc_size_config_val = 0;
176 u32 ecc_config_val = 0;
179 /* configure GPMC for specific ecc-scheme */
180 switch (info->ecc_scheme) {
181 case OMAP_ECC_HAM1_CODE_SW:
183 case OMAP_ECC_HAM1_CODE_HW:
190 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
191 case OMAP_ECC_BCH8_CODE_HW:
194 if (mode == NAND_ECC_WRITE) {
196 eccsize0 = 0; /* extra bits in nibbles per sector */
197 eccsize1 = 28; /* OOB bits in nibbles per sector */
200 eccsize0 = 26; /* ECC bits in nibbles per sector */
201 eccsize1 = 2; /* non-ECC bits in nibbles per sector */
204 case OMAP_ECC_BCH16_CODE_HW:
207 if (mode == NAND_ECC_WRITE) {
209 eccsize0 = 0; /* extra bits in nibbles per sector */
210 eccsize1 = 52; /* OOB bits in nibbles per sector */
213 eccsize0 = 52; /* ECC bits in nibbles per sector */
214 eccsize1 = 0; /* non-ECC bits in nibbles per sector */
220 /* Clear ecc and enable bits */
221 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control);
222 /* Configure ecc size for BCH */
223 ecc_size_config_val = (eccsize1 << 22) | (eccsize0 << 12);
224 writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config);
226 /* Configure device details for BCH engine */
227 ecc_config_val = ((ecc_algo << 16) | /* HAM1 | BCHx */
228 (bch_type << 12) | /* BCH4/BCH8/BCH16 */
229 (bch_wrapmode << 8) | /* wrap mode */
230 (dev_width << 7) | /* bus width */
231 (0x0 << 4) | /* number of sectors */
232 (cs << 1) | /* ECC CS */
233 (0x1)); /* enable ECC */
234 writel(ecc_config_val, &gpmc_cfg->ecc_config);
238 * omap_calculate_ecc - Read ECC result
239 * @mtd: MTD structure
241 * @ecc_code: ecc_code buffer
242 * Using noninverted ECC can be considered ugly since writing a blank
243 * page ie. padding will clear the ECC bytes. This is no problem as
244 * long nobody is trying to write data on the seemingly unused page.
245 * Reading an erased page will produce an ECC mismatch between
246 * generated and read ECC bytes that has to be dealt with separately.
247 * E.g. if page is 0xFF (fresh erased), and if HW ECC engine within GPMC
248 * is used, the result of read will be 0x0 while the ECC offsets of the
249 * spare area will be 0xFF which will result in an ECC mismatch.
251 static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
254 struct nand_chip *chip = mtd->priv;
255 struct omap_nand_info *info = chip->priv;
256 uint32_t *ptr, val = 0;
259 switch (info->ecc_scheme) {
260 case OMAP_ECC_HAM1_CODE_HW:
261 val = readl(&gpmc_cfg->ecc1_result);
262 ecc_code[0] = val & 0xFF;
263 ecc_code[1] = (val >> 16) & 0xFF;
264 ecc_code[2] = ((val >> 8) & 0x0F) | ((val >> 20) & 0xF0);
267 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
269 case OMAP_ECC_BCH8_CODE_HW:
270 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3];
272 ecc_code[i++] = (val >> 0) & 0xFF;
274 for (j = 0; j < 3; j++) {
276 ecc_code[i++] = (val >> 24) & 0xFF;
277 ecc_code[i++] = (val >> 16) & 0xFF;
278 ecc_code[i++] = (val >> 8) & 0xFF;
279 ecc_code[i++] = (val >> 0) & 0xFF;
283 case OMAP_ECC_BCH16_CODE_HW:
284 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]);
285 ecc_code[i++] = (val >> 8) & 0xFF;
286 ecc_code[i++] = (val >> 0) & 0xFF;
287 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]);
288 ecc_code[i++] = (val >> 24) & 0xFF;
289 ecc_code[i++] = (val >> 16) & 0xFF;
290 ecc_code[i++] = (val >> 8) & 0xFF;
291 ecc_code[i++] = (val >> 0) & 0xFF;
292 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]);
293 ecc_code[i++] = (val >> 24) & 0xFF;
294 ecc_code[i++] = (val >> 16) & 0xFF;
295 ecc_code[i++] = (val >> 8) & 0xFF;
296 ecc_code[i++] = (val >> 0) & 0xFF;
297 for (j = 3; j >= 0; j--) {
298 val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j]
300 ecc_code[i++] = (val >> 24) & 0xFF;
301 ecc_code[i++] = (val >> 16) & 0xFF;
302 ecc_code[i++] = (val >> 8) & 0xFF;
303 ecc_code[i++] = (val >> 0) & 0xFF;
309 /* ECC scheme specific syndrome customizations */
310 switch (info->ecc_scheme) {
311 case OMAP_ECC_HAM1_CODE_HW:
314 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
316 for (i = 0; i < chip->ecc.bytes; i++)
317 *(ecc_code + i) = *(ecc_code + i) ^
321 case OMAP_ECC_BCH8_CODE_HW:
322 ecc_code[chip->ecc.bytes - 1] = 0x00;
324 case OMAP_ECC_BCH16_CODE_HW:
332 #ifdef CONFIG_NAND_OMAP_ELM
334 * omap_reverse_list - re-orders list elements in reverse order [internal]
335 * @list: pointer to start of list
336 * @length: length of list
338 static void omap_reverse_list(u8 *list, unsigned int length)
341 unsigned int half_length = length / 2;
343 for (i = 0, j = length - 1; i < half_length; i++, j--) {
351 * omap_correct_data_bch - Compares the ecc read from nand spare area
352 * with ECC registers values and corrects one bit error if it has occured
354 * @mtd: MTD device structure
356 * @read_ecc: ecc read from nand flash (ignored)
357 * @calc_ecc: ecc read from ECC registers
359 * @return 0 if data is OK or corrected, else returns -1
361 static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
362 uint8_t *read_ecc, uint8_t *calc_ecc)
364 struct nand_chip *chip = mtd->priv;
365 struct omap_nand_info *info = chip->priv;
366 struct nand_ecc_ctrl *ecc = &chip->ecc;
367 uint32_t error_count = 0, error_max;
368 uint32_t error_loc[ELM_MAX_ERROR_COUNT];
369 enum bch_level bch_type;
370 uint32_t i, ecc_flag = 0;
372 uint32_t byte_pos, bit_pos;
375 /* check calculated ecc */
376 for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
377 if (calc_ecc[i] != 0x00)
383 /* check for whether its a erased-page */
385 for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
386 if (read_ecc[i] != 0xff)
393 * while reading ECC result we read it in big endian.
394 * Hence while loading to ELM we have rotate to get the right endian.
396 switch (info->ecc_scheme) {
397 case OMAP_ECC_BCH8_CODE_HW:
398 bch_type = BCH_8_BIT;
399 omap_reverse_list(calc_ecc, ecc->bytes - 1);
401 case OMAP_ECC_BCH16_CODE_HW:
402 bch_type = BCH_16_BIT;
403 omap_reverse_list(calc_ecc, ecc->bytes);
408 /* use elm module to check for errors */
409 elm_config(bch_type);
410 err = elm_check_error(calc_ecc, bch_type, &error_count, error_loc);
414 /* correct bch error */
415 for (count = 0; count < error_count; count++) {
416 switch (info->ecc_scheme) {
417 case OMAP_ECC_BCH8_CODE_HW:
418 /* 14th byte in ECC is reserved to match ROM layout */
419 error_max = SECTOR_BYTES + (ecc->bytes - 1);
421 case OMAP_ECC_BCH16_CODE_HW:
422 error_max = SECTOR_BYTES + ecc->bytes;
427 byte_pos = error_max - (error_loc[count] / 8) - 1;
428 bit_pos = error_loc[count] % 8;
429 if (byte_pos < SECTOR_BYTES) {
430 dat[byte_pos] ^= 1 << bit_pos;
431 printf("nand: bit-flip corrected @data=%d\n", byte_pos);
432 } else if (byte_pos < error_max) {
433 read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos;
434 printf("nand: bit-flip corrected @oob=%d\n", byte_pos -
438 printf("nand: error: invalid bit-flip location\n");
441 return (err) ? err : error_count;
445 * omap_read_page_bch - hardware ecc based page read function
446 * @mtd: mtd info structure
447 * @chip: nand chip info structure
448 * @buf: buffer to store read data
449 * @oob_required: caller expects OOB data read to chip->oob_poi
450 * @page: page number to read
453 static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip,
454 uint8_t *buf, int oob_required, int page)
456 int i, eccsize = chip->ecc.size;
457 int eccbytes = chip->ecc.bytes;
458 int eccsteps = chip->ecc.steps;
460 uint8_t *ecc_calc = chip->buffers->ecccalc;
461 uint8_t *ecc_code = chip->buffers->ecccode;
462 uint32_t *eccpos = chip->ecc.layout->eccpos;
463 uint8_t *oob = chip->oob_poi;
469 oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0];
470 oob += chip->ecc.layout->eccpos[0];
472 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize,
474 chip->ecc.hwctl(mtd, NAND_ECC_READ);
476 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1);
477 chip->read_buf(mtd, p, eccsize);
479 /* read respective ecc from oob area */
480 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1);
481 chip->read_buf(mtd, oob, eccbytes);
483 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
489 for (i = 0; i < chip->ecc.total; i++)
490 ecc_code[i] = chip->oob_poi[eccpos[i]];
492 eccsteps = chip->ecc.steps;
495 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
498 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
500 mtd->ecc_stats.failed++;
502 mtd->ecc_stats.corrected += stat;
506 #endif /* CONFIG_NAND_OMAP_ELM */
509 * OMAP3 BCH8 support (with BCH library)
513 * omap_correct_data_bch_sw - Decode received data and correct errors
514 * @mtd: MTD device structure
516 * @read_ecc: ecc read from nand flash
517 * @calc_ecc: ecc read from HW ECC registers
519 static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data,
520 u_char *read_ecc, u_char *calc_ecc)
523 /* cannot correct more than 8 errors */
524 unsigned int errloc[8];
525 struct nand_chip *chip = mtd->priv;
526 struct omap_nand_info *info = chip->priv;
528 count = decode_bch(info->control, NULL, 512, read_ecc, calc_ecc,
532 for (i = 0; i < count; i++) {
533 /* correct data only, not ecc bytes */
534 if (errloc[i] < 8*512)
535 data[errloc[i]/8] ^= 1 << (errloc[i] & 7);
536 printf("corrected bitflip %u\n", errloc[i]);
540 * BCH8 have 13 bytes of ECC; BCH4 needs adoption
543 for (i = 0; i < 13; i++)
544 printf("%02x ", read_ecc[i]);
547 for (i = 0; i < 13; i++)
548 printf("%02x ", calc_ecc[i]);
552 } else if (count < 0) {
553 puts("ecc unrecoverable error\n");
559 * omap_free_bch - Release BCH ecc resources
560 * @mtd: MTD device structure
562 static void __maybe_unused omap_free_bch(struct mtd_info *mtd)
564 struct nand_chip *chip = mtd->priv;
565 struct omap_nand_info *info = chip->priv;
568 free_bch(info->control);
569 info->control = NULL;
572 #endif /* CONFIG_BCH */
575 * omap_select_ecc_scheme - configures driver for particular ecc-scheme
576 * @nand: NAND chip device structure
577 * @ecc_scheme: ecc scheme to configure
578 * @pagesize: number of main-area bytes per page of NAND device
579 * @oobsize: number of OOB/spare bytes per page of NAND device
581 static int omap_select_ecc_scheme(struct nand_chip *nand,
582 enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) {
583 struct omap_nand_info *info = nand->priv;
584 struct nand_ecclayout *ecclayout = &omap_ecclayout;
585 int eccsteps = pagesize / SECTOR_BYTES;
588 switch (ecc_scheme) {
589 case OMAP_ECC_HAM1_CODE_SW:
590 debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n");
591 /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are
592 * initialized in nand_scan_tail(), so just set ecc.mode */
593 info->control = NULL;
594 nand->ecc.mode = NAND_ECC_SOFT;
595 nand->ecc.layout = NULL;
599 case OMAP_ECC_HAM1_CODE_HW:
600 debug("nand: selected OMAP_ECC_HAM1_CODE_HW\n");
601 /* check ecc-scheme requirements before updating ecc info */
602 if ((3 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
603 printf("nand: error: insufficient OOB: require=%d\n", (
604 (3 * eccsteps) + BADBLOCK_MARKER_LENGTH));
607 info->control = NULL;
608 /* populate ecc specific fields */
609 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
610 nand->ecc.mode = NAND_ECC_HW;
611 nand->ecc.strength = 1;
612 nand->ecc.size = SECTOR_BYTES;
614 nand->ecc.hwctl = omap_enable_hwecc;
615 nand->ecc.correct = omap_correct_data;
616 nand->ecc.calculate = omap_calculate_ecc;
617 /* define ecc-layout */
618 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
619 for (i = 0; i < ecclayout->eccbytes; i++) {
620 if (nand->options & NAND_BUSWIDTH_16)
621 ecclayout->eccpos[i] = i + 2;
623 ecclayout->eccpos[i] = i + 1;
625 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
626 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
627 BADBLOCK_MARKER_LENGTH;
630 case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
632 debug("nand: selected OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n");
633 /* check ecc-scheme requirements before updating ecc info */
634 if ((13 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
635 printf("nand: error: insufficient OOB: require=%d\n", (
636 (13 * eccsteps) + BADBLOCK_MARKER_LENGTH));
639 /* check if BCH S/W library can be used for error detection */
640 info->control = init_bch(13, 8, 0x201b);
641 if (!info->control) {
642 printf("nand: error: could not init_bch()\n");
645 /* populate ecc specific fields */
646 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
647 nand->ecc.mode = NAND_ECC_HW;
648 nand->ecc.strength = 8;
649 nand->ecc.size = SECTOR_BYTES;
650 nand->ecc.bytes = 13;
651 nand->ecc.hwctl = omap_enable_hwecc;
652 nand->ecc.correct = omap_correct_data_bch_sw;
653 nand->ecc.calculate = omap_calculate_ecc;
654 /* define ecc-layout */
655 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
656 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH;
657 for (i = 1; i < ecclayout->eccbytes; i++) {
658 if (i % nand->ecc.bytes)
659 ecclayout->eccpos[i] =
660 ecclayout->eccpos[i - 1] + 1;
662 ecclayout->eccpos[i] =
663 ecclayout->eccpos[i - 1] + 2;
665 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
666 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
667 BADBLOCK_MARKER_LENGTH;
670 printf("nand: error: CONFIG_BCH required for ECC\n");
674 case OMAP_ECC_BCH8_CODE_HW:
675 #ifdef CONFIG_NAND_OMAP_ELM
676 debug("nand: selected OMAP_ECC_BCH8_CODE_HW\n");
677 /* check ecc-scheme requirements before updating ecc info */
678 if ((14 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
679 printf("nand: error: insufficient OOB: require=%d\n", (
680 (14 * eccsteps) + BADBLOCK_MARKER_LENGTH));
683 /* intialize ELM for ECC error detection */
685 info->control = NULL;
686 /* populate ecc specific fields */
687 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl));
688 nand->ecc.mode = NAND_ECC_HW;
689 nand->ecc.strength = 8;
690 nand->ecc.size = SECTOR_BYTES;
691 nand->ecc.bytes = 14;
692 nand->ecc.hwctl = omap_enable_hwecc;
693 nand->ecc.correct = omap_correct_data_bch;
694 nand->ecc.calculate = omap_calculate_ecc;
695 nand->ecc.read_page = omap_read_page_bch;
696 /* define ecc-layout */
697 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
698 for (i = 0; i < ecclayout->eccbytes; i++)
699 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
700 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
701 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes -
702 BADBLOCK_MARKER_LENGTH;
705 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
709 case OMAP_ECC_BCH16_CODE_HW:
710 #ifdef CONFIG_NAND_OMAP_ELM
711 debug("nand: using OMAP_ECC_BCH16_CODE_HW\n");
712 /* check ecc-scheme requirements before updating ecc info */
713 if ((26 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) {
714 printf("nand: error: insufficient OOB: require=%d\n", (
715 (26 * eccsteps) + BADBLOCK_MARKER_LENGTH));
718 /* intialize ELM for ECC error detection */
720 /* populate ecc specific fields */
721 nand->ecc.mode = NAND_ECC_HW;
722 nand->ecc.size = SECTOR_BYTES;
723 nand->ecc.bytes = 26;
724 nand->ecc.strength = 16;
725 nand->ecc.hwctl = omap_enable_hwecc;
726 nand->ecc.correct = omap_correct_data_bch;
727 nand->ecc.calculate = omap_calculate_ecc;
728 nand->ecc.read_page = omap_read_page_bch;
729 /* define ecc-layout */
730 ecclayout->eccbytes = nand->ecc.bytes * eccsteps;
731 for (i = 0; i < ecclayout->eccbytes; i++)
732 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH;
733 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH;
734 ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes -
735 BADBLOCK_MARKER_LENGTH;
738 printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n");
742 debug("nand: error: ecc scheme not enabled or supported\n");
746 /* nand_scan_tail() sets ham1 sw ecc; hw ecc layout is set by driver */
747 if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW)
748 nand->ecc.layout = ecclayout;
750 info->ecc_scheme = ecc_scheme;
754 #ifndef CONFIG_SPL_BUILD
756 * omap_nand_switch_ecc - switch the ECC operation between different engines
757 * (h/w and s/w) and different algorithms (hamming and BCHx)
759 * @hardware - true if one of the HW engines should be used
760 * @eccstrength - the number of bits that could be corrected
761 * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16)
763 int __maybe_unused omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength)
765 struct nand_chip *nand;
766 struct mtd_info *mtd;
769 if (nand_curr_device < 0 ||
770 nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
771 !nand_info[nand_curr_device].name) {
772 printf("nand: error: no NAND devices found\n");
776 mtd = &nand_info[nand_curr_device];
778 nand->options |= NAND_OWN_BUFFERS;
779 nand->options &= ~NAND_SUBPAGE_READ;
780 /* Setup the ecc configurations again */
782 if (eccstrength == 1) {
783 err = omap_select_ecc_scheme(nand,
784 OMAP_ECC_HAM1_CODE_HW,
785 mtd->writesize, mtd->oobsize);
786 } else if (eccstrength == 8) {
787 err = omap_select_ecc_scheme(nand,
788 OMAP_ECC_BCH8_CODE_HW,
789 mtd->writesize, mtd->oobsize);
791 printf("nand: error: unsupported ECC scheme\n");
795 err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
796 mtd->writesize, mtd->oobsize);
799 /* Update NAND handling after ECC mode switch */
801 err = nand_scan_tail(mtd);
804 #endif /* CONFIG_SPL_BUILD */
807 * Board-specific NAND initialization. The following members of the
808 * argument are board-specific:
809 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
810 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
811 * - cmd_ctrl: hardwarespecific function for accesing control-lines
812 * - waitfunc: hardwarespecific function for accesing device ready/busy line
813 * - ecc.hwctl: function to enable (reset) hardware ecc generator
814 * - ecc.mode: mode of ecc, see defines
815 * - chip_delay: chip dependent delay for transfering data from array to
817 * - options: various chip options. They can partly be set to inform
818 * nand_scan about special functionality. See the defines for further
821 int board_nand_init(struct nand_chip *nand)
823 int32_t gpmc_config = 0;
827 * xloader/Uboot's gpmc configuration would have configured GPMC for
828 * nand type of memory. The following logic scans and latches on to the
829 * first CS with NAND type memory.
830 * TBD: need to make this logic generic to handle multiple CS NAND
833 while (cs < GPMC_MAX_CS) {
834 /* Check if NAND type is set */
835 if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) {
841 if (cs >= GPMC_MAX_CS) {
842 printf("nand: error: Unable to find NAND settings in "
843 "GPMC Configuration - quitting\n");
847 gpmc_config = readl(&gpmc_cfg->config);
848 /* Disable Write protect */
850 writel(gpmc_config, &gpmc_cfg->config);
852 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat;
853 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd;
854 omap_nand_info[cs].control = NULL;
855 omap_nand_info[cs].cs = cs;
856 nand->priv = &omap_nand_info[cs];
857 nand->cmd_ctrl = omap_nand_hwcontrol;
858 nand->options |= NAND_NO_PADDING | NAND_CACHEPRG;
859 nand->chip_delay = 100;
860 nand->ecc.layout = &omap_ecclayout;
862 /* configure driver and controller based on NAND device bus-width */
863 gpmc_config = readl(&gpmc_cfg->cs[cs].config1);
864 #if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT)
865 nand->options |= NAND_BUSWIDTH_16;
866 writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1);
868 nand->options &= ~NAND_BUSWIDTH_16;
869 writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1);
871 /* select ECC scheme */
872 #if defined(CONFIG_NAND_OMAP_ECCSCHEME)
873 err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME,
874 CONFIG_SYS_NAND_PAGE_SIZE, CONFIG_SYS_NAND_OOBSIZE);
876 /* pagesize and oobsize are not required to configure sw ecc-scheme */
877 err = omap_select_ecc_scheme(nand, OMAP_ECC_HAM1_CODE_SW,
883 #ifdef CONFIG_SPL_BUILD
884 if (nand->options & NAND_BUSWIDTH_16)
885 nand->read_buf = nand_read_buf16;
887 nand->read_buf = nand_read_buf;
890 nand->dev_ready = omap_dev_ready;