This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Linux/AM3352: ELM question

Part Number: AM3352

Tool/software: Linux

hi :

sdk version : sdk6

Occasionally found uboot use the following two ways to burn uboot.img:

1,nandecc hw 2

2,nandecc sw

Found that these two ways to read uboot when MLO, it will not even report ecc error.

BCH8 is used in MLO. That means when nandecc sw flashes uboot, there should be ecc error, but no.

So go see the ecc calibration code and find that calibration is related to ELM.

In the calibration code, ecc_code is ecc data stored in oob, and ecc_calc is generated when data in nandflash is read.

Here is just to judge whether the ecc_code is 0xff, and then discarded.

The main operation is to convert the ecc_calc into the ELM_SYNDROME_FRAGMENT_x register, finally through the ELM_ERROR_LOCATION_x register to know the wrong bit and position.

How does ELM know that data has a bit error without requiring ecc data in oob?

Thanks!

  • Hi,

    SDK 6 is obsolete and no longer maintained or supported by TI. Please move to the new Processor SDK: www.ti.com/.../PROCESSOR-SDK-AM335X
  • hi Biser Gatchev-XID :

    I found it in version sdk-src-04.01.00.06, the ecc calibration method is the same as sdk6, ignoring ecc data read from nandflash.

     

    uboot : drivers/mtd/nand/omap_gpmc.c

    /*
     * ti81xx_correct_data_bch - Compares the ecc read from nand spare area
     * with ECC registers values and corrects one bit error if it has occured
     *
     * @mtd:	MTD device structure
     * @dat:	page data
     * @read_ecc:	ecc read from nand flash (ignored)
     * @calc_ecc:	ecc read from ECC registers
     *
     * @return 0 if data is OK or corrected, else returns -1
     */
    static int ti81xx_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
    				uint8_t *read_ecc, uint8_t *calc_ecc)
    {
    	struct nand_chip *chip = mtd->priv;
    	struct nand_bch_priv *bch = chip->priv;
    	uint8_t syndrome[28];
    	uint32_t error_count = 0;
    	uint32_t error_loc[8];
    	uint32_t i, ecc_flag;
    
    	ecc_flag = 0;
    	for (i = 0; i < (chip->ecc.bytes - 1); i++)
    		if (read_ecc[i] != 0xff)
    			ecc_flag = 1;
            ....
    }

    I have not understood how ELM ignores data from the nandflash read ecc data, how to determine the data bit error and positioning bit position.

    Thanks!

  • The code in omap_elm.c uses the ecc read from the NAND to determine BCH errors and locations.

    Steve K.

  • hi Steve Kipisz:
     
    omap_elm.c has five functions:
    elm_load_syndromes
        elm_check_error
    elm_config
    elm_reset
    elm_init
     
    sdk-src-04.01.00.06

    Function call

        omap_correct_data_bch

    -> elm_check_error

    /*
     * omap_correct_data_bch - Compares the ecc read from nand spare area
     * with ECC registers values and corrects one bit error if it has occurred
     *
     * @mtd:    MTD device structure
     * @dat:    page data
     * @read_ecc:   ecc read from nand flash (ignored)
     * @calc_ecc:   ecc read from ECC registers
     *
     * @return 0 if data is OK or corrected, else returns -1
     */
    static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat,
                    uint8_t *read_ecc, uint8_t *calc_ecc)
    {
        struct nand_chip *chip = mtd_to_nand(mtd);
        struct omap_nand_info *info = nand_get_controller_data(chip);
        struct nand_ecc_ctrl *ecc = &chip->ecc;
        uint32_t error_count = 0, error_max;
        uint32_t error_loc[ELM_MAX_ERROR_COUNT];
        enum bch_level bch_type;
        uint32_t i, ecc_flag = 0;
        uint8_t count;
        uint32_t byte_pos, bit_pos;
        int err = 0;
    
        /* check calculated ecc */
        for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
            if (calc_ecc[i] != 0x00)
                ecc_flag = 1;
        }
        if (!ecc_flag)
            return 0;
    
        /* check for whether its a erased-page */
        ecc_flag = 0;
        for (i = 0; i < ecc->bytes && !ecc_flag; i++) {
            if (read_ecc[i] != 0xff)
                ecc_flag = 1;
        }
        if (!ecc_flag)
            return 0;
        /*   
         * while reading ECC result we read it in big endian.
         * Hence while loading to ELM we have rotate to get the right endian.
         */
        switch (info->ecc_scheme) {
        case OMAP_ECC_BCH8_CODE_HW:
            bch_type = BCH_8_BIT;
            omap_reverse_list(calc_ecc, ecc->bytes - 1);
            break;
        case OMAP_ECC_BCH16_CODE_HW:
            bch_type = BCH_16_BIT;
            omap_reverse_list(calc_ecc, ecc->bytes);
            break;
        default:
            return -EINVAL;
        }
        /* use elm module to check for errors */
        elm_config(bch_type);
        err = elm_check_error(calc_ecc, bch_type, &error_count, error_loc);
        if (err)
            return err;
    
        /* correct bch error */
        for (count = 0; count < error_count; count++) {
            switch (info->ecc_scheme) {
            case OMAP_ECC_BCH8_CODE_HW:
                /* 14th byte in ECC is reserved to match ROM layout */
                error_max = SECTOR_BYTES + (ecc->bytes - 1);
                break;
            case OMAP_ECC_BCH16_CODE_HW:
                error_max = SECTOR_BYTES + ecc->bytes;
                break;
            default:
                return -EINVAL;
            }
            byte_pos = error_max - (error_loc[count] / 8) - 1;
            bit_pos  = error_loc[count] % 8;
            if (byte_pos < SECTOR_BYTES) {
                dat[byte_pos] ^= 1 << bit_pos;
                debug("nand: bit-flip corrected @data=%d\n", byte_pos);
            } else if (byte_pos < error_max) {
                read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos;
                debug("nand: bit-flip corrected @oob=%d\n", byte_pos -
                                    SECTOR_BYTES);
            } else {
                err = -EBADMSG;
                printf("nand: error: invalid bit-flip location\n");
            }
        }
        return (err) ? err : error_count;
    }
    

     I found that in the uboot code, the ecc check function ignores ecc data read from flash.

    Thanks!

  • Has your question been answered?

    Steve K.
  • hi Steve Kipisz:

         Thanks for your reply!

         This question still has no answer.

    Thanks!

  • I think the comment about the read ecc is ignored is incorrect. If you look later in the code you'll see
    read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos;

    Steve K.
  • hi Steve Kipisz:

    if (byte_pos < SECTOR_BYTES) {
         dat[byte_pos] ^= 1 << bit_pos;
         debug("nand: bit-flip corrected @data=%d\n", byte_pos);
    } else if (byte_pos < error_max) {
         read_ecc[byte_pos - SECTOR_BYTES] ^= 1 << bit_pos;
         debug("nand: bit-flip corrected @oob=%d\n", byte_pos -SECTOR_BYTES);
    } else {
         err = -EBADMSG;
         printf("nand: error: invalid bit-flip location\n");
    }

          Ecc error correction is for dat, why do you modify read_ecc?
    Thanks!
  • read_ecc is modified to correct a bit-flip in the OOB.

    Steve K.
  • 1. This means that read_ecc is only used for oob regional data calibration, not data area?

    2. After the data in the data area is read, the calc_ecc generated by ELM will be calibrated, instead of read_ecc?

  • Correct.

    Steve K.