[PATCH RFC v3 3/4] nand: pl353: Add ONDIE ECC support
Added ONDIE ECC support. Currently this ecc mode is supported for specific micron parts with oob size 64 bytes. Signed-off-by: Punnaiah Choudary Kalluri --- drivers/mtd/nand/pl353_nand.c | 131 +++- 1 files changed, 127 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index eca205f..4f56c7f 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -140,6 +140,48 @@ static struct nand_ecclayout nand_oob_64 = { .length = 50} } }; +static struct nand_ecclayout ondie_nand_oob_64 = { + .eccbytes = 32, + + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 24, 25, 26, 27, 28, 29, 30, 31, + 40, 41, 42, 43, 44, 45, 46, 47, + 56, 57, 58, 59, 60, 61, 62, 63 + }, + + .oobfree = { + { .offset = 4, .length = 4 }, + { .offset = 20, .length = 4 }, + { .offset = 36, .length = 4 }, + { .offset = 52, .length = 4 } + } +}; + +/* Generic flash bbt decriptors */ +static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = mirror_pattern +}; + /** * pl353_nand_calculate_hwecc - Calculate Hardware ECC * @mtd: Pointer to the mtd_info structure @@ -816,15 +858,74 @@ static int pl353_nand_device_ready(struct mtd_info *mtd) } /** + * pl353_nand_detect_ondie_ecc - Get the flash ondie ecc state + * @mtd: Pointer to the mtd_info structure + * + * This function enables the ondie ecc for the Micron ondie ecc capable devices + * + * Return: 1 on detect, 0 if fail to detect + */ +static int pl353_nand_detect_ondie_ecc(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + u8 maf_id, dev_id, i, get_feature; + u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 }; + + /* Check if On-Die ECC flash */ + nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + maf_id = readb(nand_chip->IO_ADDR_R); + dev_id = readb(nand_chip->IO_ADDR_R); + + if ((maf_id == NAND_MFR_MICRON) && + ((dev_id == 0xf1) || (dev_id == 0xa1) || +(dev_id == 0xb1) || (dev_id == 0xaa) || +(dev_id == 0xba) || (dev_id == 0xda) || +(dev_id == 0xca) || (dev_id == 0xac) || +(dev_id == 0xbc) || (dev_id == 0xdc) || +(dev_id == 0xcc) || (dev_id == 0xa3) || +(dev_id == 0xb3) || +(dev_id == 0xd3) || (dev_id == 0xc3))) { + + nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + get_feature = readb(nand_chip->IO_ADDR_R); + + if (get_feature & 0x08) { + return 1; + } else { + nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + for (i = 0; i < 4; i++) + writeb(set_feature[i], nand_chip->IO_ADDR_W); + + ndelay(1000); + + nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + get_feature = readb(nand_chip->IO_ADDR_R); + + if (get_feature & 0x08) + return 1; + } + } + + return 0; +} + +/** * pl353_nand_ecc_init - Initialize the ecc information as per the ecc mode * @mtd: Pointer to the mtd_info structure + * @ondie_ecc_state: ondie ecc status * * This function initializes the ecc block and functional pointers as per the * ecc mode * * Return: Zero on success and error on failure. */ -static int pl353_nand_ecc_init(struct mtd_info *mtd) +static int pl353_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) { struct nand_chip *nand_chip = mtd->priv; struct pl353_nand_info *xnand = @@ -838,12 +939,28 @@ static int pl353_nand_ecc_init(struct mtd_info *mtd) switch (xnand->ecc_mode) { case NAND_ECC_HW: - if (mtd->writesize > 2048) { +
[PATCH RFC v3 3/4] nand: pl353: Add ONDIE ECC support
Added ONDIE ECC support. Currently this ecc mode is supported for specific micron parts with oob size 64 bytes. Signed-off-by: Punnaiah Choudary Kalluri punn...@xilinx.com --- drivers/mtd/nand/pl353_nand.c | 131 +++- 1 files changed, 127 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/pl353_nand.c b/drivers/mtd/nand/pl353_nand.c index eca205f..4f56c7f 100644 --- a/drivers/mtd/nand/pl353_nand.c +++ b/drivers/mtd/nand/pl353_nand.c @@ -140,6 +140,48 @@ static struct nand_ecclayout nand_oob_64 = { .length = 50} } }; +static struct nand_ecclayout ondie_nand_oob_64 = { + .eccbytes = 32, + + .eccpos = { + 8, 9, 10, 11, 12, 13, 14, 15, + 24, 25, 26, 27, 28, 29, 30, 31, + 40, 41, 42, 43, 44, 45, 46, 47, + 56, 57, 58, 59, 60, 61, 62, 63 + }, + + .oobfree = { + { .offset = 4, .length = 4 }, + { .offset = 20, .length = 4 }, + { .offset = 36, .length = 4 }, + { .offset = 52, .length = 4 } + } +}; + +/* Generic flash bbt decriptors */ +static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 4, + .len = 4, + .veroffs = 20, + .maxblocks = 4, + .pattern = mirror_pattern +}; + /** * pl353_nand_calculate_hwecc - Calculate Hardware ECC * @mtd: Pointer to the mtd_info structure @@ -816,15 +858,74 @@ static int pl353_nand_device_ready(struct mtd_info *mtd) } /** + * pl353_nand_detect_ondie_ecc - Get the flash ondie ecc state + * @mtd: Pointer to the mtd_info structure + * + * This function enables the ondie ecc for the Micron ondie ecc capable devices + * + * Return: 1 on detect, 0 if fail to detect + */ +static int pl353_nand_detect_ondie_ecc(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd-priv; + u8 maf_id, dev_id, i, get_feature; + u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 }; + + /* Check if On-Die ECC flash */ + nand_chip-cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + nand_chip-cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + maf_id = readb(nand_chip-IO_ADDR_R); + dev_id = readb(nand_chip-IO_ADDR_R); + + if ((maf_id == NAND_MFR_MICRON) + ((dev_id == 0xf1) || (dev_id == 0xa1) || +(dev_id == 0xb1) || (dev_id == 0xaa) || +(dev_id == 0xba) || (dev_id == 0xda) || +(dev_id == 0xca) || (dev_id == 0xac) || +(dev_id == 0xbc) || (dev_id == 0xdc) || +(dev_id == 0xcc) || (dev_id == 0xa3) || +(dev_id == 0xb3) || +(dev_id == 0xd3) || (dev_id == 0xc3))) { + + nand_chip-cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + get_feature = readb(nand_chip-IO_ADDR_R); + + if (get_feature 0x08) { + return 1; + } else { + nand_chip-cmdfunc(mtd, NAND_CMD_SET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + for (i = 0; i 4; i++) + writeb(set_feature[i], nand_chip-IO_ADDR_W); + + ndelay(1000); + + nand_chip-cmdfunc(mtd, NAND_CMD_GET_FEATURES, + ONDIE_ECC_FEATURE_ADDR, -1); + get_feature = readb(nand_chip-IO_ADDR_R); + + if (get_feature 0x08) + return 1; + } + } + + return 0; +} + +/** * pl353_nand_ecc_init - Initialize the ecc information as per the ecc mode * @mtd: Pointer to the mtd_info structure + * @ondie_ecc_state: ondie ecc status * * This function initializes the ecc block and functional pointers as per the * ecc mode * * Return: Zero on success and error on failure. */ -static int pl353_nand_ecc_init(struct mtd_info *mtd) +static int pl353_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) { struct nand_chip *nand_chip = mtd-priv; struct pl353_nand_info *xnand = @@ -838,12 +939,28 @@ static int pl353_nand_ecc_init(struct mtd_info *mtd) switch (xnand-ecc_mode) { case NAND_ECC_HW: - if (mtd-writesize 2048) { +