Lines Matching +full:flip +full:- +full:chip
1 // SPDX-License-Identifier: GPL-2.0+
3 * (C) Copyright 2004-2008 Texas Instruments, <www.ti.com>
54 * omap_nand_hwcontrol - Set the address pointers corretly for the
62 int cs = info->cs; in omap_nand_hwcontrol()
66 * of chip address in omap_nand_hwcontrol()
70 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; in omap_nand_hwcontrol()
73 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_adr; in omap_nand_hwcontrol()
76 this->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; in omap_nand_hwcontrol()
81 writeb(cmd, this->IO_ADDR_W); in omap_nand_hwcontrol()
89 return gpmc_cfg->status & (1 << (8 + info->ws)); in omap_dev_ready()
93 * gen_true_ecc - This function will generate true ECC value, which
98 * @return: re-formatted ECC value
107 * omap_correct_data - Compares the ecc read from nand spare area with ECC
111 * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf
118 * @return 0 if data is OK or corrected, else returns -1
141 /* Flip the bit to correct */ in omap_correct_data()
165 return -EBADMSG; in omap_correct_data()
172 * omap_enable_hwecc - configures GPMC as per ECC scheme before read/write
181 unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0; in omap_enable_hwecc()
187 int cs = info->cs; in omap_enable_hwecc()
189 /* configure GPMC for specific ecc-scheme */ in omap_enable_hwecc()
190 switch (info->ecc_scheme) { in omap_enable_hwecc()
211 eccsize1 = 2; /* non-ECC bits in nibbles per sector */ in omap_enable_hwecc()
224 eccsize1 = 0; /* non-ECC bits in nibbles per sector */ in omap_enable_hwecc()
231 writel(ECCCLEAR | ECCRESULTREG1, &gpmc_cfg->ecc_control); in omap_enable_hwecc()
234 writel(ecc_size_config_val, &gpmc_cfg->ecc_size_config); in omap_enable_hwecc()
244 writel(ecc_config_val, &gpmc_cfg->ecc_config); in omap_enable_hwecc()
248 * omap_calculate_ecc - Read ECC result
264 struct nand_chip *chip = mtd_to_nand(mtd); in omap_calculate_ecc() local
265 struct omap_nand_info *info = nand_get_controller_data(chip); in omap_calculate_ecc()
270 switch (info->ecc_scheme) { in omap_calculate_ecc()
272 val = readl(&gpmc_cfg->ecc1_result); in omap_calculate_ecc()
281 ptr = &gpmc_cfg->bch_result_0_3[0].bch_result_x[3]; in omap_calculate_ecc()
284 ptr--; in omap_calculate_ecc()
291 ptr--; in omap_calculate_ecc()
295 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]); in omap_calculate_ecc()
298 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]); in omap_calculate_ecc()
303 val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]); in omap_calculate_ecc()
308 for (j = 3; j >= 0; j--) { in omap_calculate_ecc()
309 val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j] in omap_calculate_ecc()
318 return -EINVAL; in omap_calculate_ecc()
321 switch (info->ecc_scheme) { in omap_calculate_ecc()
327 for (i = 0; i < chip->ecc.bytes; i++) in omap_calculate_ecc()
333 ecc_code[chip->ecc.bytes - 1] = 0x00; in omap_calculate_ecc()
338 return -EINVAL; in omap_calculate_ecc()
353 * omap_prefetch_enable - configures and starts prefetch transfer
357 * @cs: chip select to use
364 return -EINVAL; in omap_prefetch_enable()
366 if (readl(&gpmc_cfg->prefetch_control)) in omap_prefetch_enable()
367 return -EBUSY; in omap_prefetch_enable()
370 writel(count, &gpmc_cfg->prefetch_config2); in omap_prefetch_enable()
374 writel(val, &gpmc_cfg->prefetch_config1); in omap_prefetch_enable()
377 writel(1, &gpmc_cfg->prefetch_control); in omap_prefetch_enable()
383 * omap_prefetch_reset - disables and stops the prefetch engine
387 writel(0, &gpmc_cfg->prefetch_control); in omap_prefetch_reset()
388 writel(0, &gpmc_cfg->prefetch_config1); in omap_prefetch_reset()
391 static int __read_prefetch_aligned(struct nand_chip *chip, uint32_t *buf, int len) in __read_prefetch_aligned() argument
395 struct omap_nand_info *info = nand_get_controller_data(chip); in __read_prefetch_aligned()
397 ret = omap_prefetch_enable(PREFETCH_FIFOTHRESHOLD_MAX, len, 0, info->cs); in __read_prefetch_aligned()
404 cnt = readl(&gpmc_cfg->prefetch_status); in __read_prefetch_aligned()
409 len -= 4; in __read_prefetch_aligned()
420 struct nand_chip *chip = mtd_to_nand(mtd); in omap_nand_read() local
422 if (chip->options & NAND_BUSWIDTH_16) in omap_nand_read()
432 struct nand_chip *chip = mtd_to_nand(mtd); in omap_nand_read_prefetch() local
436 * the overlap byte-wise. in omap_nand_read_prefetch()
442 len -= head; in omap_nand_read_prefetch()
446 * Only transfer multiples of 4 bytes in a pre-fetched fashion. in omap_nand_read_prefetch()
447 * If there's a residue, care for it byte-wise afterwards. in omap_nand_read_prefetch()
451 ret = __read_prefetch_aligned(chip, (uint32_t *)buf, len - tail); in omap_nand_read_prefetch()
456 buf += len - tail; in omap_nand_read_prefetch()
464 * omap_reverse_list - re-orders list elements in reverse order [internal]
473 for (i = 0, j = length - 1; i < half_length; i++, j--) { in omap_reverse_list()
481 * omap_correct_data_bch - Compares the ecc read from nand spare area
489 * @return 0 if data is OK or corrected, else returns -1
494 struct nand_chip *chip = mtd_to_nand(mtd); in omap_correct_data_bch() local
495 struct omap_nand_info *info = nand_get_controller_data(chip); in omap_correct_data_bch()
496 struct nand_ecc_ctrl *ecc = &chip->ecc; in omap_correct_data_bch()
506 for (i = 0; i < ecc->bytes && !ecc_flag; i++) { in omap_correct_data_bch()
513 /* check for whether its a erased-page */ in omap_correct_data_bch()
515 for (i = 0; i < ecc->bytes && !ecc_flag; i++) { in omap_correct_data_bch()
526 switch (info->ecc_scheme) { in omap_correct_data_bch()
529 omap_reverse_list(calc_ecc, ecc->bytes - 1); in omap_correct_data_bch()
533 omap_reverse_list(calc_ecc, ecc->bytes); in omap_correct_data_bch()
536 return -EINVAL; in omap_correct_data_bch()
546 switch (info->ecc_scheme) { in omap_correct_data_bch()
549 error_max = SECTOR_BYTES + (ecc->bytes - 1); in omap_correct_data_bch()
552 error_max = SECTOR_BYTES + ecc->bytes; in omap_correct_data_bch()
555 return -EINVAL; in omap_correct_data_bch()
557 byte_pos = error_max - (error_loc[count] / 8) - 1; in omap_correct_data_bch()
561 debug("nand: bit-flip corrected @data=%d\n", byte_pos); in omap_correct_data_bch()
563 read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos; in omap_correct_data_bch()
564 debug("nand: bit-flip corrected @oob=%d\n", byte_pos - in omap_correct_data_bch()
567 err = -EBADMSG; in omap_correct_data_bch()
568 printf("nand: error: invalid bit-flip location\n"); in omap_correct_data_bch()
575 * omap_read_page_bch - hardware ecc based page read function
577 * @chip: nand chip info structure
579 * @oob_required: caller expects OOB data read to chip->oob_poi
583 static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, in omap_read_page_bch() argument
586 int i, eccsize = chip->ecc.size; in omap_read_page_bch()
587 int eccbytes = chip->ecc.bytes; in omap_read_page_bch()
588 int eccsteps = chip->ecc.steps; in omap_read_page_bch()
590 uint8_t *ecc_calc = chip->buffers->ecccalc; in omap_read_page_bch()
591 uint8_t *ecc_code = chip->buffers->ecccode; in omap_read_page_bch()
592 uint32_t *eccpos = chip->ecc.layout->eccpos; in omap_read_page_bch()
593 uint8_t *oob = chip->oob_poi; in omap_read_page_bch()
599 oob_pos = (eccsize * eccsteps) + chip->ecc.layout->eccpos[0]; in omap_read_page_bch()
600 oob += chip->ecc.layout->eccpos[0]; in omap_read_page_bch()
602 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize, in omap_read_page_bch()
604 chip->ecc.hwctl(mtd, NAND_ECC_READ); in omap_read_page_bch()
606 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_pos, -1); in omap_read_page_bch()
607 chip->read_buf(mtd, p, eccsize); in omap_read_page_bch()
610 chip->cmdfunc(mtd, NAND_CMD_RNDOUT, oob_pos, -1); in omap_read_page_bch()
611 chip->read_buf(mtd, oob, eccbytes); in omap_read_page_bch()
613 chip->ecc.calculate(mtd, p, &ecc_calc[i]); in omap_read_page_bch()
619 for (i = 0; i < chip->ecc.total; i++) in omap_read_page_bch()
620 ecc_code[i] = chip->oob_poi[eccpos[i]]; in omap_read_page_bch()
622 eccsteps = chip->ecc.steps; in omap_read_page_bch()
625 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { in omap_read_page_bch()
628 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]); in omap_read_page_bch()
630 mtd->ecc_stats.failed++; in omap_read_page_bch()
632 mtd->ecc_stats.corrected += stat; in omap_read_page_bch()
643 * omap_correct_data_bch_sw - Decode received data and correct errors
655 struct nand_chip *chip = mtd_to_nand(mtd); in omap_correct_data_bch_sw() local
656 struct omap_nand_info *info = nand_get_controller_data(chip); in omap_correct_data_bch_sw()
658 count = decode_bch(info->control, NULL, SECTOR_BYTES, in omap_correct_data_bch_sw()
689 * omap_free_bch - Release BCH ecc resources
694 struct nand_chip *chip = mtd_to_nand(mtd); in omap_free_bch() local
695 struct omap_nand_info *info = nand_get_controller_data(chip); in omap_free_bch()
697 if (info->control) { in omap_free_bch()
698 free_bch(info->control); in omap_free_bch()
699 info->control = NULL; in omap_free_bch()
705 * omap_select_ecc_scheme - configures driver for particular ecc-scheme
706 * @nand: NAND chip device structure
708 * @pagesize: number of main-area bytes per page of NAND device
721 /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are in omap_select_ecc_scheme()
723 info->control = NULL; in omap_select_ecc_scheme()
724 nand->ecc.mode = NAND_ECC_SOFT; in omap_select_ecc_scheme()
725 nand->ecc.layout = NULL; in omap_select_ecc_scheme()
726 nand->ecc.size = 0; in omap_select_ecc_scheme()
731 /* check ecc-scheme requirements before updating ecc info */ in omap_select_ecc_scheme()
735 return -EINVAL; in omap_select_ecc_scheme()
737 info->control = NULL; in omap_select_ecc_scheme()
739 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); in omap_select_ecc_scheme()
740 nand->ecc.mode = NAND_ECC_HW; in omap_select_ecc_scheme()
741 nand->ecc.strength = 1; in omap_select_ecc_scheme()
742 nand->ecc.size = SECTOR_BYTES; in omap_select_ecc_scheme()
743 nand->ecc.bytes = 3; in omap_select_ecc_scheme()
744 nand->ecc.hwctl = omap_enable_hwecc; in omap_select_ecc_scheme()
745 nand->ecc.correct = omap_correct_data; in omap_select_ecc_scheme()
746 nand->ecc.calculate = omap_calculate_ecc; in omap_select_ecc_scheme()
747 /* define ecc-layout */ in omap_select_ecc_scheme()
748 ecclayout->eccbytes = nand->ecc.bytes * eccsteps; in omap_select_ecc_scheme()
749 for (i = 0; i < ecclayout->eccbytes; i++) { in omap_select_ecc_scheme()
750 if (nand->options & NAND_BUSWIDTH_16) in omap_select_ecc_scheme()
751 ecclayout->eccpos[i] = i + 2; in omap_select_ecc_scheme()
753 ecclayout->eccpos[i] = i + 1; in omap_select_ecc_scheme()
755 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; in omap_select_ecc_scheme()
756 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - in omap_select_ecc_scheme()
763 /* check ecc-scheme requirements before updating ecc info */ in omap_select_ecc_scheme()
767 return -EINVAL; in omap_select_ecc_scheme()
770 info->control = init_bch(13, 8, 0x201b); in omap_select_ecc_scheme()
771 if (!info->control) { in omap_select_ecc_scheme()
773 return -ENODEV; in omap_select_ecc_scheme()
776 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); in omap_select_ecc_scheme()
777 nand->ecc.mode = NAND_ECC_HW; in omap_select_ecc_scheme()
778 nand->ecc.strength = 8; in omap_select_ecc_scheme()
779 nand->ecc.size = SECTOR_BYTES; in omap_select_ecc_scheme()
780 nand->ecc.bytes = 13; in omap_select_ecc_scheme()
781 nand->ecc.hwctl = omap_enable_hwecc; in omap_select_ecc_scheme()
782 nand->ecc.correct = omap_correct_data_bch_sw; in omap_select_ecc_scheme()
783 nand->ecc.calculate = omap_calculate_ecc; in omap_select_ecc_scheme()
784 /* define ecc-layout */ in omap_select_ecc_scheme()
785 ecclayout->eccbytes = nand->ecc.bytes * eccsteps; in omap_select_ecc_scheme()
786 ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; in omap_select_ecc_scheme()
787 for (i = 1; i < ecclayout->eccbytes; i++) { in omap_select_ecc_scheme()
788 if (i % nand->ecc.bytes) in omap_select_ecc_scheme()
789 ecclayout->eccpos[i] = in omap_select_ecc_scheme()
790 ecclayout->eccpos[i - 1] + 1; in omap_select_ecc_scheme()
792 ecclayout->eccpos[i] = in omap_select_ecc_scheme()
793 ecclayout->eccpos[i - 1] + 2; in omap_select_ecc_scheme()
795 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; in omap_select_ecc_scheme()
796 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - in omap_select_ecc_scheme()
801 return -EINVAL; in omap_select_ecc_scheme()
807 /* check ecc-scheme requirements before updating ecc info */ in omap_select_ecc_scheme()
811 return -EINVAL; in omap_select_ecc_scheme()
815 info->control = NULL; in omap_select_ecc_scheme()
817 memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); in omap_select_ecc_scheme()
818 nand->ecc.mode = NAND_ECC_HW; in omap_select_ecc_scheme()
819 nand->ecc.strength = 8; in omap_select_ecc_scheme()
820 nand->ecc.size = SECTOR_BYTES; in omap_select_ecc_scheme()
821 nand->ecc.bytes = 14; in omap_select_ecc_scheme()
822 nand->ecc.hwctl = omap_enable_hwecc; in omap_select_ecc_scheme()
823 nand->ecc.correct = omap_correct_data_bch; in omap_select_ecc_scheme()
824 nand->ecc.calculate = omap_calculate_ecc; in omap_select_ecc_scheme()
825 nand->ecc.read_page = omap_read_page_bch; in omap_select_ecc_scheme()
826 /* define ecc-layout */ in omap_select_ecc_scheme()
827 ecclayout->eccbytes = nand->ecc.bytes * eccsteps; in omap_select_ecc_scheme()
828 for (i = 0; i < ecclayout->eccbytes; i++) in omap_select_ecc_scheme()
829 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; in omap_select_ecc_scheme()
830 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; in omap_select_ecc_scheme()
831 ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - in omap_select_ecc_scheme()
836 return -EINVAL; in omap_select_ecc_scheme()
842 /* check ecc-scheme requirements before updating ecc info */ in omap_select_ecc_scheme()
846 return -EINVAL; in omap_select_ecc_scheme()
851 nand->ecc.mode = NAND_ECC_HW; in omap_select_ecc_scheme()
852 nand->ecc.size = SECTOR_BYTES; in omap_select_ecc_scheme()
853 nand->ecc.bytes = 26; in omap_select_ecc_scheme()
854 nand->ecc.strength = 16; in omap_select_ecc_scheme()
855 nand->ecc.hwctl = omap_enable_hwecc; in omap_select_ecc_scheme()
856 nand->ecc.correct = omap_correct_data_bch; in omap_select_ecc_scheme()
857 nand->ecc.calculate = omap_calculate_ecc; in omap_select_ecc_scheme()
858 nand->ecc.read_page = omap_read_page_bch; in omap_select_ecc_scheme()
859 /* define ecc-layout */ in omap_select_ecc_scheme()
860 ecclayout->eccbytes = nand->ecc.bytes * eccsteps; in omap_select_ecc_scheme()
861 for (i = 0; i < ecclayout->eccbytes; i++) in omap_select_ecc_scheme()
862 ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; in omap_select_ecc_scheme()
863 ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; in omap_select_ecc_scheme()
864 ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes - in omap_select_ecc_scheme()
869 return -EINVAL; in omap_select_ecc_scheme()
873 return -EINVAL; in omap_select_ecc_scheme()
878 nand->ecc.layout = ecclayout; in omap_select_ecc_scheme()
880 info->ecc_scheme = ecc_scheme; in omap_select_ecc_scheme()
886 * omap_nand_switch_ecc - switch the ECC operation between different engines
889 * @hardware - true if one of the HW engines should be used
890 * @eccstrength - the number of bits that could be corrected
891 * (1 - hamming, 4 - BCH4, 8 - BCH8, 16 - BCH16)
901 return -ENODEV; in omap_nand_switch_ecc()
905 nand->options |= NAND_OWN_BUFFERS; in omap_nand_switch_ecc()
906 nand->options &= ~NAND_SUBPAGE_READ; in omap_nand_switch_ecc()
912 mtd->writesize, mtd->oobsize); in omap_nand_switch_ecc()
916 mtd->writesize, mtd->oobsize); in omap_nand_switch_ecc()
920 mtd->writesize, mtd->oobsize); in omap_nand_switch_ecc()
923 return -EINVAL; in omap_nand_switch_ecc()
929 mtd->writesize, mtd->oobsize); in omap_nand_switch_ecc()
933 mtd->writesize, mtd->oobsize); in omap_nand_switch_ecc()
936 return -EINVAL; in omap_nand_switch_ecc()
948 * Board-specific NAND initialization. The following members of the
949 * argument are board-specific:
950 * - IO_ADDR_R: address to read the 8 I/O lines of the flash device
951 * - IO_ADDR_W: address to write the 8 I/O lines of the flash device
952 * - cmd_ctrl: hardwarespecific function for accesing control-lines
953 * - waitfunc: hardwarespecific function for accesing device ready/busy line
954 * - ecc.hwctl: function to enable (reset) hardware ecc generator
955 * - ecc.mode: mode of ecc, see defines
956 * - chip_delay: chip dependent delay for transfering data from array to
958 * - options: various chip options. They can partly be set to inform
976 if ((readl(&gpmc_cfg->cs[cs].config1) & 0xC00) == 0x800) { in board_nand_init()
984 "GPMC Configuration - quitting\n"); in board_nand_init()
985 return -ENODEV; in board_nand_init()
988 gpmc_config = readl(&gpmc_cfg->config); in board_nand_init()
991 writel(gpmc_config, &gpmc_cfg->config); in board_nand_init()
993 nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; in board_nand_init()
994 nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; in board_nand_init()
999 nand->cmd_ctrl = omap_nand_hwcontrol; in board_nand_init()
1000 nand->options |= NAND_NO_PADDING | NAND_CACHEPRG; in board_nand_init()
1001 nand->chip_delay = 100; in board_nand_init()
1002 nand->ecc.layout = &omap_ecclayout; in board_nand_init()
1004 /* configure driver and controller based on NAND device bus-width */ in board_nand_init()
1005 gpmc_config = readl(&gpmc_cfg->cs[cs].config1); in board_nand_init()
1007 nand->options |= NAND_BUSWIDTH_16; in board_nand_init()
1008 writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1); in board_nand_init()
1010 nand->options &= ~NAND_BUSWIDTH_16; in board_nand_init()
1011 writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1); in board_nand_init()
1018 /* pagesize and oobsize are not required to configure sw ecc-scheme */ in board_nand_init()
1026 nand->read_buf = omap_nand_read_prefetch; in board_nand_init()
1028 if (nand->options & NAND_BUSWIDTH_16) in board_nand_init()
1029 nand->read_buf = nand_read_buf16; in board_nand_init()
1031 nand->read_buf = nand_read_buf; in board_nand_init()
1034 nand->dev_ready = omap_dev_ready; in board_nand_init()