ONFI SET FEATURES / GET FEATURES FCM implementation

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

ONFI SET FEATURES / GET FEATURES FCM implementation

1,302 Views
nilsmagnusnilss
Contributor I

I need to implement ONFI commands SET FEATURES / GET FEATURES in order to enable on-die ECC for a Micron NAND (MT29F4G08ABADA) and custom P2020 board running linux.

However, I'm having a hard time implementing that using the FCM.

I'm hoping that I simply haven't understood some feature of FCM programming, and that you will be able to spot my mistake.

The sequence to enable internal ECC with SET FEATURES is EFh(cmd)-90h(addr)-08h(data)-00h(data)-00h(data)-00h(data)-wait(tFEAT).

The GET FEATURES command is EEh.

Does the following implementation look reasonable?:

fsl_elbc_nand.c, fsl_elbc_cmdfunc():

...

        case NAND_CMD_SET_FEATURES: // 0xEF

                out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |

                                    (FIR_OP_UA  << FIR_OP1_SHIFT) |

                                    (FIR_OP_WB << FIR_OP2_SHIFT));

                out_be32(&lbc->fcr, NAND_CMD_SET_FEATURES << FCR_CMD0_SHIFT);

                out_be32(&lbc->fbcr, 4);

                ctrl->read_bytes = 0;

                ctrl->use_mdr = 1;

                ctrl->mdr = column; // 0x90

                set_addr(mtd, 0, 0, 0);

                fsl_elbc_run_command(mtd);

                //after this, 4 bytes [0x08,0x00,0x00,0x00] are written with fsl_elbc_write_buf()

                break;

  case NAND_CMD_GET_FEATURES: // 0xEE

                out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |

                                    (FIR_OP_UA  << FIR_OP1_SHIFT) |

                                    (FIR_OP_RBW << FIR_OP2_SHIFT));

                out_be32(&lbc->fcr, NAND_CMD_GET_FEATURES << FCR_CMD0_SHIFT);

                out_be32(&lbc->fbcr, 4);

                ctrl->read_bytes = 4;

                ctrl->use_mdr = 1;

                ctrl->mdr = column; // 0x90

                set_addr(mtd, 0, 0, 0);

                fsl_elbc_run_command(mtd);

                 //after this, 4 bytes are read with fsl_elbc_read_buf()

                break;

...

Labels (1)
Tags (3)
0 Kudos
3 Replies

826 Views
lunminliang
NXP Employee
NXP Employee

Hello Magnus Nilsson,

The code looks OK.

Regards

Lunmin

0 Kudos

826 Views
nilsmagnusnilss
Contributor I

I can't get SET_FEATURES to work properly.

I believe GET_FEATURES is working - out of reset i read [0,0,0,0] as expected ( http://datasheet.octopart.com/MT29F4G08ABBDAH4%3AD-Micron-datasheet-11758868.pdf page 50). I can also replace it with another operation e.g. READ_ID and read the expected data.

However, when I try to write [8,0,0,0] with SET_FEATURES (address 0x90), I end up writing [F,0,0,0].

With different delays (unfortunately I don't have specifics - I'm experimenting with that right now) I have also read back [A,0,0,0].

Code:

static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,

                        int addr, uint8_t *subfeature_param)

{

        int status;

        if (!chip->onfi_version)

                return -EINVAL;

        chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);

        printk(KERN_ERR "nand_onfi_set_features addr: %x subfeature_param: %x %x %x %x\n",addr,subfeature_param[0],subfeature_param[1],subfeature_param[2],subfeature_param[3]);

        ndelay(100); //tADL=min 70ns

        chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);

        ndelay(1000); //tFEAT=max 1us=1000ns

        status = chip->waitfunc(mtd, chip);

        if (status & NAND_STATUS_FAIL)

                return -EIO;

        return 0;

}

static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,

                        int addr, uint8_t *subfeature_param)

{

        if (!chip->onfi_version)

                return -EINVAL;

        chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);

        //chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); //reads 2c dc 90 95 (correct, this is MT29F4G08ABADA)

        //chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); //reads 'O' 'N' 'F' 'I' (correct)

        ndelay(1000); //tFEAT=max 1us=1000ns

        chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);

        printk(KERN_ERR "nand_onfi_get_features addr: %x subfeature_param: %x %x %x %x\n",addr,subfeature_param[0],subfeature_param[1],subfeature_param[2],subfeature_param[3]);

        return 0;

}

Debug output:

nand_onfi_set_features addr: 90 subfeature_param: 8 0 0 0

nand_onfi_get_features addr: 90 subfeature_param: f 0 0 0

0 Kudos

826 Views
nilsmagnusnilss
Contributor I

Well, I found a workaround - using MDR to write the 4 byte array (the last byte is thankfully is 0x00, since MDR only contains 4 bytes and the address 0x90 already uses one).

I still don't understand quite how fsl_elbc_write_buf() works - when I use it and then try to write with FIR_OP_WB, it just writes garbage.

In any case, if someone else is stuck with the same problem, here's how I solved it for now:

case NAND_CMD_SET_FEATURES:

                out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |

                                    (FIR_OP_UA  << FIR_OP1_SHIFT) |

                                    (FIR_OP_WS << FIR_OP2_SHIFT) |

                                    (FIR_OP_WS << FIR_OP3_SHIFT) |

                                    (FIR_OP_WS << FIR_OP4_SHIFT) |

                                    (FIR_OP_WS << FIR_OP5_SHIFT));

                out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT);

                out_be32(&lbc->fbcr, 0);

                ctrl->use_mdr = 1;

                //page_addr=0x00 or 0x08, so MDR = 0x00000090 or 0x00000890 to enable/disable on-die ECC

                ctrl->mdr = (page_addr<<8) + column;

                set_addr(mtd, 0, 0, 0);

                fsl_elbc_run_command(mtd);

                break;

0 Kudos