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.

Nand write one page out of two

Other Parts Discussed in Thread: OMAP-L138, OMAPL138, DA8XX

Hi,

I'm experiencing a very strange problem with NAND on a custom board I'm working on, based on DA850/OMAP-L138 LCDK. When I'm erasing the NAND with flash_erase or reading it with nanddump in a file, no problem, everything works fine. The problem is when I'm writing on it with nandwrite tool, only one page out of two is written. As a test, I'm writing a file containing only 0xAA. Of course, I erase the flash memory before. When I read the memory with nanddump in a file, I got : 

AA AA AA AA AA .... (2048 bytes)

FF FF FF FF FF .... (2048 bytes)

AA AA AA AA AA .... (2048 bytes)

FF FF FF FF FF .... (2048 bytes)

....

The NAND I'm using is : Micron NAND 512MiB 3,3V 16-bit #MT29F4G08ABADAH4.

I can send you my code if you need it.

Thank you

Sylvain.

  • Hi Sylvain,


    The problem is when I'm writing on it with nandwrite tool, only one page out of two is written.


    Is that nandwrite tool is your own code or any open source ?

    Did you test the same on LCDK board and if yes, results ?

    Could you share the code and steps that you followed.
  • Hi sylvain,

    Welcome to the TI E2E forum. I hope you will find many good answers here and in the TI.com documents and in the TI Wiki Pages. Be sure to search those for helpful information and to browse for the questions others may have asked on similar topics.

    OMAPL138 LCDK board already have a tested and working NAND driver example code. You will find it as a part of Starterware package.

    www.ti.com/.../starterware-dsparm

    I would recommend you to download the starterware package ans use the NAND sample code given in it. It is always good to start with something which already works. You can run the example and browse through the source code of read and write functionalities. Compare the source code of it with yours. You may find out what you are missing!!

     

    Regards,

    Shankari

     

    -------------------------------------------------------------------------------------------------------

    Please click the Verify Answer button on this post if it answers your question.
    --------------------------------------------------------------------------------------------------------

  • Hi Titus,

    The nandwrite tool is part of the linux 3.3 kernel provided with the DA850/OMAP-L138 LCDK :

    www.ti.com/.../bioslinuxmcsdk

    I use this tool once linux is booted. I tested the nandwrite tool on the LCDK and it worked perfectly. I can send you the content of my board file in arch/arm/mach-davinci concerning the NAND so you can see what my configuration looks like. The nand used is the same as the LCDK.

    struct mtd_partition rtm9431_nandflash_partition[] =

    {

    {

    .name           = "filesystem",

    .offset         = 0,

    .size           = MTDPART_SIZ_FULL,

    .mask_flags     = 0,

    },

    };

    static struct davinci_aemif_timing rtm9431_nandflash_timing = {

    .wsetup = 15,

    .wstrobe = 63,

    .whold = 7,

    .rsetup = 15,

    .rstrobe = 63,

    .rhold = 7,

    .ta = 3,

    };

    static struct davinci_nand_pdata rtm9431_nandflash_data =

    {

    .parts          = rtm9431_nandflash_partition,

    .nr_parts       = ARRAY_SIZE(rtm9431_nandflash_partition),

    .ecc_mode       = NAND_ECC_HW,

    .options        = NAND_BUSWIDTH_16,//NAND_BUSWIDTH_AUTO,

    .ecc_bits       = 1, // 4 bit mode is not supported with 16 bit NAND

    .bbt_options    = NAND_BBT_USE_FLASH,

    .timing = &rtm9431_nandflash_timing,

    };

    static const short rtm9431_nand_pins[] =

    {

    DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,

    DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,

    DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11,

    DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15,

    DA850_EMA_A_1, DA850_EMA_A_2, DA850_NEMA_CS_3,

    DA850_NEMA_WE,DA850_NEMA_OE,

    -1

    };

    /*static const short rtm9431_lcd_pins[] =

    {

    DA850_EMA_D_0, DA850_EMA_D_1, DA850_EMA_D_2, DA850_EMA_D_3,

    DA850_EMA_D_4, DA850_EMA_D_5, DA850_EMA_D_6, DA850_EMA_D_7,

    DA850_EMA_D_8, DA850_EMA_D_9, DA850_EMA_D_10, DA850_EMA_D_11,

    DA850_EMA_D_12, DA850_EMA_D_13, DA850_EMA_D_14, DA850_EMA_D_15,

    DA850_EMA_A_0, DA850_NEMA_CS_5, RTM_LCD_RESET,

    DA850_NEMA_WE,DA850_NEMA_OE,

    -1

    };*/

    static struct resource rtm9431_nandflash_resource[] =

    {

    {

    .start  = DA8XX_AEMIF_CS3_BASE,

    .end    = DA8XX_AEMIF_CS3_BASE + SZ_512K + 2 * SZ_1K - 1,

    .flags  = IORESOURCE_MEM,

    },

    {

    .start  = DA8XX_AEMIF_CTL_BASE,

    .end    = DA8XX_AEMIF_CTL_BASE + SZ_32K - 1,

    .flags  = IORESOURCE_MEM,

    },

    };

    static struct platform_device rtm9431_emif_devices[] __initdata = {

    {

    .name = "davinci_nand",

    .id = 1,

    .resource = rtm9431_nandflash_resource,

    .num_resources = ARRAY_SIZE(rtm9431_nandflash_resource),

    .dev =

    {

    .platform_data = &rtm9431_nandflash_data,

    },

    },

    };

    static struct davinci_aemif_devices davinci_emif_devices = {

    .devices = rtm9431_emif_devices,

    .num_devices = ARRAY_SIZE(rtm9431_emif_devices),

    };

    static struct platform_device davinci_emif_device = {

    .name = "davinci_aemif",

    .id = -1,

    .dev = {

    .platform_data = &davinci_emif_devices,

    },

    };

    static struct platform_device *rtm9431_devices[] __initdata =

    {

    &davinci_emif_device,

    };

    static void __init rtm9431_setup_nand(void)

    {

    int ret;

    ret = davinci_cfg_reg_list(rtm9431_nand_pins);

    if (ret) {

    pr_warn("RTM9431-20_init:"

    "nand mux setup failed: %d\n", ret);

    return;

    }

    platform_add_devices(rtm9431_devices, ARRAY_SIZE(rtm9431_devices));

    }

    I finally call the rtm9431_setup_nand function in the board init funtion. I hope it will help you to find what I'm doing wrong.

    Thank you

    Sylvain

  • Hi Shankari,

    I will try Starterware package. As you said, maybe I will find what I'm missing!

    Thank you!

    Sylvain
  • Hi Sylvain,

    Okay, this configuration is seems good.

    Able to load kernel from NAND to RAM & execute ?
    Have you tried to write and read back in u-boot prompt ?

    Also, you can validate (CCS's memory browser) your NAND hw using starterware code or NAND writer code (CCS) with your custom board .
  • Hi,

    I finally found the problem inside nand_davinci_writebuf function in /drivers/mtd/nand/davinci_nand.c

    static void nand_davinci_write_buf(struct mtd_info *mtd,
    const uint8_t *buf, int len)
    {
    struct nand_chip *chip = mtd->priv;

    if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
    {
    iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
    }
    else if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
    {
    iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
    }
    else
    {
    iowrite8_rep(chip->IO_ADDR_R, buf, len);
    }
    }

    I put some printk to realize that iowrite32_rep function is called, so the condition : ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0) is true.
    I commented the first part of the IF with the iowrite32_rep function and it worked. I just don't know how the conditions work and why it's true. I know that "len" value is 512, and it comes from nand_write_page_hwecc function in nand_base.c file. The len value comes from
    chip->ecc.size. I will try to find the answer, but if you can help me, that will be very appreciated!

    Regards,
    Sylvain
  • Hi Titus and Shankari,

    After commenting the section about writing in 32 bits, to be sure to write in 16 bits like this :

    /* if ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)
    {
    iowrite32_rep(chip->IO_ADDR_R, buf, len >> 2);
    }
    else*/

     if ((0x01 & ((unsigned)buf)) == 0 && (0x01 & len) == 0)
    {
    iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);
    }
    else
    {
    iowrite8_rep(chip->IO_ADDR_R, buf, len);
    }

    I have another problem, when I write my test file to NAND using nandwrite tool. My test file looks like this : 

    The file contain only 0xAA, except at the beginning of each page, I changed 20 bytes of 0xAA to 20 bytes of 0xBB.  I use nanddump tool to read NAND into file and I obtain this :

    Result, I have an extra FF FF FF FF    FF FF FF FF     FF FF FF FF    FF FF FF FF    FF FF FF FF. And at the and of the page, the data is not shifted, it is truncated to fit the beginning of the other page. The next page is not beginning at 0x1014, it's still begining at 0x1000, so there is data lost. I still can't figure out what's the problem. For your information, I have the same problems with U-Boot. 

    My questions are how to be sure to enter in the good section of the nand_davinci_write_buf function to write in 16 bits (I don't understant the if statement) and why is an extra 20 bytes 0xFF written at the beginning of any page?

    Thank you for your help!

    Sylvain

  • Here is the Internal ECC and Spare Area Mapping for ECC section from page 109 of the Micron datasheet m60a_4gb_8gb_16gb_ecc_nand.pdf - Rev. O 08/13 EN:

    Internal ECC enables 5-bit detection and 4-bit error correction in 512 bytes (x8) or 256 words (x16) of the main area and 4 bytes (x8) or 2 words (x16) of metadata I in the spare area. The metadata II area, which consists of two bytes (x8) and one word (x16), is not ECC protected. During the busy time for PROGRAM operations, internal ECC generates parity bits when error detection is complete.

    As Sylvain point out, the the condition : ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0) is true.

    The variable len is determined by info->chip.ecc.size = 512 in the following code from davinci_nand.c:

    switch (ecc_mode) {
    case NAND_ECC_NONE:

    case NAND_ECC_SOFT:

    pdata->ecc_bits = 0;

    break;

    case NAND_ECC_HW:

    if (pdata->ecc_bits == 4) {

    /* No sanity checks: CPUs must support this,

    * and the chips may not use NAND_BUSWIDTH_16.

    */



    /* No sharing 4-bit hardware between chipselects yet */

    spin_lock_irq(&davinci_nand_lock);

    if (ecc4_busy)

    ret = -EBUSY;

    else

    ecc4_busy = true;

    spin_unlock_irq(&davinci_nand_lock);



    if (ret == -EBUSY)

    goto err_ecc;



    info->chip.ecc.calculate = nand_davinci_calculate_4bit;

    info->chip.ecc.correct = nand_davinci_correct_4bit;

    info->chip.ecc.hwctl = nand_davinci_hwctl_4bit;

    info->chip.ecc.bytes = 10;

    } else {

    info->chip.ecc.calculate = nand_davinci_calculate_1bit;

    info->chip.ecc.correct = nand_davinci_correct_1bit;

    info->chip.ecc.hwctl = nand_davinci_hwctl_1bit;

    info->chip.ecc.bytes = 3;

    }

    info->chip.ecc.size = 512;
    //!Considering unit as bytes and not words
    break;

    default:

    ret = -EINVAL;

    goto err_ecc;

    }

    info->chip.ecc.mode = ecc_mode;

    My question is: Do we have to modify the condition ((0x03 & ((unsigned)buf)) == 0 && (0x03 & len) == 0)?
    Because changing len = info->chip.ecc.size = 514; is a bit awkward to be able to call the 16 bits writes function (iowrite16_rep(chip->IO_ADDR_R, buf, len >> 1);) as stated by Sylvain.

    Best Regards,

    Jason
  • Finaly I found the problem. It was a hardware problem, the EMIFA_WAIT1 and EMIFA_WAIT0 pins was reversed. This way, there was no wait signals received on ARM side. I changed temporarily the nand_davinci_dev_ready function, so it read the second bit of the NANDFSR registry entry, corresponding to the EMIFA_WAIT1 pin. When the hardware correction would be done, I will be able to reverse this change. I suggest a possible switch, so the nand_davinci_dev_ready function could use EMIFA_WAIT1 and EMIFA_WAIT0 pins, not only EMIFA_WAIT0.

    Thank you everyone for your help!
    Sylvain