Loading src/drivers/mtd/nand/pl35x_nand.c +165 −101 Original line number Original line Diff line number Diff line Loading @@ -83,8 +83,6 @@ struct pl35x_nand_command_format { /** /** * struct pl35x_nand_info - Defines the NAND flash driver instance * struct pl35x_nand_info - Defines the NAND flash driver instance * @chip: NAND chip information structure * @chip: NAND chip information structure * @mtd: MTD information structure * @parts: Pointer to the mtd_partition structure * @nand_base: Virtual address of the NAND flash device * @nand_base: Virtual address of the NAND flash device * @end_cmd_pending: End command is pending * @end_cmd_pending: End command is pending * @end_cmd: End command * @end_cmd: End command Loading @@ -93,8 +91,6 @@ struct pl35x_nand_command_format { */ */ struct pl35x_nand_info { struct pl35x_nand_info { struct nand_chip chip; struct nand_chip chip; struct mtd_info mtd; struct mtd_partition *parts; void __iomem *nand_base; void __iomem *nand_base; unsigned long end_cmd_pending; unsigned long end_cmd_pending; unsigned long end_cmd; unsigned long end_cmd; Loading Loading @@ -133,43 +129,110 @@ static const struct pl35x_nand_command_format pl35x_nand_commands[] = { */ */ }; }; /* Define default oob placement schemes for large and small page devices */ static int pl35x_ecc_ooblayout16_ecc(struct mtd_info *mtd, int section, static struct nand_ecclayout nand_oob_16 = { struct mtd_oob_region *oobregion) .eccbytes = 3, { .eccpos = {0, 1, 2}, struct nand_chip *chip = mtd_to_nand(mtd); .oobfree = { {.offset = 8, if (section >= chip->ecc.steps) . length = 8} } return -ERANGE; oobregion->offset = (section * 16) + 0; oobregion->length = chip->ecc.bytes; return 0; } static int pl35x_ecc_ooblayout16_free(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); if (section >= chip->ecc.steps) return -ERANGE; oobregion->offset = (section * 16) + 8; oobregion->length = 8; return 0; } static const struct mtd_ooblayout_ops fsmc_ecc_ooblayout16_ops = { .ecc = pl35x_ecc_ooblayout16_ecc, .free = pl35x_ecc_ooblayout16_free, }; }; static int pl35x_ecc_ooblayout64_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); if (section >= chip->ecc.steps) return -ERANGE; oobregion->offset = (section * 16) + 52; oobregion->length = chip->ecc.bytes; return 0; } static struct nand_ecclayout nand_oob_64 = { static int pl35x_ecc_ooblayout64_free(struct mtd_info *mtd, int section, .eccbytes = 12, struct mtd_oob_region *oobregion) .eccpos = { { 52, 53, 54, 55, 56, 57, struct nand_chip *chip = mtd_to_nand(mtd); 58, 59, 60, 61, 62, 63}, .oobfree = { if (section >= chip->ecc.steps) {.offset = 2, return -ERANGE; .length = 50} } oobregion->offset = (section * 16) + 2; oobregion->length = 50; return 0; } static const struct mtd_ooblayout_ops fsmc_ecc_ooblayout64_ops = { .ecc = pl35x_ecc_ooblayout64_ecc, .free = pl35x_ecc_ooblayout64_free, }; }; static int pl35x_ecc_ooblayout_ondie64_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); static struct nand_ecclayout ondie_nand_oob_64 = { if (section >= chip->ecc.steps) .eccbytes = 32, return -ERANGE; .eccpos = { oobregion->offset = (section * 16) + 8; 8, 9, 10, 11, 12, 13, 14, 15, oobregion->length = chip->ecc.bytes; 24, 25, 26, 27, 28, 29, 30, 31, 40, 41, 42, 43, 44, 45, 46, 47, return 0; 56, 57, 58, 59, 60, 61, 62, 63 } }, static int pl35x_ecc_ooblayout_ondie64_free(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); if (section >= chip->ecc.steps) return -ERANGE; .oobfree = { { .offset = 4, .length = 4 }, oobregion->length = 4; { .offset = 20, .length = 4 }, if (!section) { .offset = 36, .length = 4 }, oobregion->offset = 4; { .offset = 52, .length = 4 } else oobregion->offset = (section * 16) + 4; return 0; } } static const struct mtd_ooblayout_ops fsmc_ecc_ooblayout_ondie64_ops = { .ecc = pl35x_ecc_ooblayout_ondie64_ecc, .free = pl35x_ecc_ooblayout_ondie64_free, }; }; /* Generic flash bbt decriptors */ /* Generic flash bbt decriptors */ static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; Loading Loading @@ -211,7 +274,6 @@ static int pl35x_nand_calculate_hwecc(struct mtd_info *mtd, u32 ecc_value, ecc_status; u32 ecc_value, ecc_status; u8 ecc_reg, ecc_byte; u8 ecc_reg, ecc_byte; unsigned long timeout = jiffies + PL35X_NAND_ECC_BUSY_TIMEOUT; unsigned long timeout = jiffies + PL35X_NAND_ECC_BUSY_TIMEOUT; /* Wait till the ECC operation is complete or timeout */ /* Wait till the ECC operation is complete or timeout */ do { do { if (pl35x_smc_ecc_is_busy()) if (pl35x_smc_ecc_is_busy()) Loading Loading @@ -415,7 +477,8 @@ static int pl35x_nand_read_page_raw(struct mtd_info *mtd, */ */ static int pl35x_nand_write_page_raw(struct mtd_info *mtd, static int pl35x_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, struct nand_chip *chip, const uint8_t *buf, int oob_required) const uint8_t *buf, int oob_required, int page) { { unsigned long data_phase_addr; unsigned long data_phase_addr; uint8_t *p; uint8_t *p; Loading Loading @@ -450,15 +513,15 @@ static int pl35x_nand_write_page_raw(struct mtd_info *mtd, */ */ static int pl35x_nand_write_page_hwecc(struct mtd_info *mtd, static int pl35x_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, struct nand_chip *chip, const uint8_t *buf, int oob_required) int oob_required, int page) { { int i, eccsize = chip->ecc.size; int eccsize = chip->ecc.size; int eccsteps = chip->ecc.steps; int eccsteps = chip->ecc.steps; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; unsigned long data_phase_addr; unsigned long data_phase_addr; uint8_t *oob_ptr; uint8_t *oob_ptr; u32 ret; for ( ; (eccsteps - 1); eccsteps--) { for ( ; (eccsteps - 1); eccsteps--) { chip->write_buf(mtd, p, eccsize); chip->write_buf(mtd, p, eccsize); Loading @@ -473,13 +536,14 @@ static int pl35x_nand_write_page_hwecc(struct mtd_info *mtd, chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; chip->write_buf(mtd, p, PL35X_NAND_LAST_TRANSFER_LENGTH); chip->write_buf(mtd, p, PL35X_NAND_LAST_TRANSFER_LENGTH); /* Wait for ECC to be calculated and read the error values */ p = buf; p = buf; chip->ecc.calculate(mtd, p, &ecc_calc[0]); chip->ecc.calculate(mtd, p, &ecc_calc[0]); for (i = 0; i < chip->ecc.total; i++) /* Wait for ECC to be calculated and read the error values */ chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]); ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, chip->ecc.total); if (ret) return ret; /* Clear ECC last bit */ /* Clear ECC last bit */ data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; data_phase_addr &= ~PL35X_NAND_ECC_LAST; data_phase_addr &= ~PL35X_NAND_ECC_LAST; Loading Loading @@ -511,23 +575,23 @@ static int pl35x_nand_write_page_hwecc(struct mtd_info *mtd, */ */ static int pl35x_nand_write_page_swecc(struct mtd_info *mtd, static int pl35x_nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, struct nand_chip *chip, const uint8_t *buf, int oob_required) int oob_required, int page) { { int i, eccsize = chip->ecc.size; int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; int eccsteps = chip->ecc.steps; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; u32 ret; /* Software ecc calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); chip->ecc.calculate(mtd, p, &ecc_calc[0]); for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; chip->ecc.write_page_raw(mtd, chip, buf, 1); ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, chip->ecc.total); if (ret) return ret; chip->ecc.write_page_raw(mtd, chip, buf, 1, page); return 0; return 0; } } Loading Loading @@ -555,9 +619,9 @@ static int pl35x_nand_read_page_hwecc(struct mtd_info *mtd, uint8_t *p = buf; uint8_t *p = buf; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_code = chip->buffers->ecccode; uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; unsigned long data_phase_addr; unsigned long data_phase_addr; uint8_t *oob_ptr; uint8_t *oob_ptr; u32 ret; for ( ; (eccsteps - 1); eccsteps--) { for ( ; (eccsteps - 1); eccsteps--) { chip->read_buf(mtd, p, eccsize); chip->read_buf(mtd, p, eccsize); Loading Loading @@ -594,8 +658,10 @@ static int pl35x_nand_read_page_hwecc(struct mtd_info *mtd, oob_ptr += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH); oob_ptr += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH); chip->read_buf(mtd, oob_ptr, PL35X_NAND_LAST_TRANSFER_LENGTH); chip->read_buf(mtd, oob_ptr, PL35X_NAND_LAST_TRANSFER_LENGTH); for (i = 0; i < chip->ecc.total; i++) ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, ecc_code[i] = ~(chip->oob_poi[eccpos[i]]); chip->ecc.total); if (ret) return ret; eccsteps = chip->ecc.steps; eccsteps = chip->ecc.steps; p = buf; p = buf; Loading Loading @@ -631,15 +697,15 @@ static int pl35x_nand_read_page_swecc(struct mtd_info *mtd, uint8_t *p = buf; uint8_t *p = buf; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_code = chip->buffers->ecccode; uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; u32 ret; chip->ecc.read_page_raw(mtd, chip, buf, page, 1); chip->ecc.read_page_raw(mtd, chip, buf, page, 1); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); chip->ecc.calculate(mtd, p, &ecc_calc[i]); for (i = 0; i < chip->ecc.total; i++) ret = mtd_ooblayout_get_eccbytes(mtd, ecc_calc, chip->oob_poi, ecc_code[i] = chip->oob_poi[eccpos[i]]; 0, chip->ecc.total); eccsteps = chip->ecc.steps; eccsteps = chip->ecc.steps; p = buf; p = buf; Loading Loading @@ -684,10 +750,10 @@ static void pl35x_nand_cmd_function(struct mtd_info *mtd, unsigned int command, if (command == NAND_CMD_UNLOCK1) pr_debug("NAND UNLOCK1\n"); if (command == NAND_CMD_UNLOCK1) pr_debug("NAND UNLOCK1\n"); if (command == NAND_CMD_SET_FEATURES) pr_debug("NAND NAND_CMD_SET_FEATURES\n"); if (command == NAND_CMD_SET_FEATURES) pr_debug("NAND NAND_CMD_SET_FEATURES\n"); struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd_to_nand(mtd); const struct pl35x_nand_command_format *curr_cmd = NULL; const struct pl35x_nand_command_format *curr_cmd = NULL; struct pl35x_nand_info *xnand = struct pl35x_nand_info *xnand = container_of(mtd, struct pl35x_nand_info, mtd); container_of(chip, struct pl35x_nand_info, chip); void __iomem *cmd_addr; void __iomem *cmd_addr; unsigned long cmd_data = 0, end_cmd_valid = 0; unsigned long cmd_data = 0, end_cmd_valid = 0; unsigned long cmd_phase_addr, data_phase_addr, end_cmd, i; unsigned long cmd_phase_addr, data_phase_addr, end_cmd, i; Loading Loading @@ -834,7 +900,7 @@ static void pl35x_nand_cmd_function(struct mtd_info *mtd, unsigned int command, static void pl35x_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) static void pl35x_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { { int i; int i; struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd_to_nand(mtd); unsigned long *ptr = (unsigned long *)buf; unsigned long *ptr = (unsigned long *)buf; len >>= 2; len >>= 2; Loading @@ -852,18 +918,17 @@ static void pl35x_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) int len) { { int i; int i; struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd_to_nand(mtd); unsigned long *ptr = (unsigned long *)buf; unsigned long *ptr = (unsigned long *)buf; pr_debug("pl35x_nand_write_buf: datasize=%d len=%d len>>2=%d\n",sizeof(ptr[0]),len,len>>2); pr_debug("pl35x_nand_write_buf: datasize=%d len=%d len>>2=%d\n",sizeof(ptr[0]),len,len>>2); len >>= 2; len >>= 2; for (i = 0; i < len; i++) for (i = 0; i < len; i++) writel(ptr[i], chip->IO_ADDR_W); writel(ptr[i], chip->IO_ADDR_W); //writeb(byte, chip->IO_ADDR_W); } } /** /** * pl35x_nand_device_ready - Check device ready/busy line * pl35x_nand_device_ready - Check device ready/busy line * @mtd: Pointer to the mtd_info structure * @mtd: Pointer to the mtd_info structure Loading @@ -879,6 +944,7 @@ static int pl35x_nand_device_ready(struct mtd_info *mtd) return 0; return 0; } } // Elphel: whole function /** /** * pl35x_nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand * pl35x_nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand * @mtd: MTD device structure * @mtd: MTD device structure Loading Loading @@ -916,6 +982,7 @@ static int pl35x_nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip * return 0; return 0; } } // Elphel: whole function /** /** * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand * @mtd: MTD device structure * @mtd: MTD device structure Loading Loading @@ -952,7 +1019,7 @@ static int pl35x_nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip * */ */ static int pl35x_nand_detect_ondie_ecc(struct mtd_info *mtd) static int pl35x_nand_detect_ondie_ecc(struct mtd_info *mtd) { { struct nand_chip *nand_chip = mtd->priv; struct nand_chip *nand_chip = mtd_to_nand(mtd); u8 maf_id, dev_id, i, get_feature; u8 maf_id, dev_id, i, get_feature; u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 }; u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 }; Loading Loading @@ -1009,16 +1076,17 @@ static int pl35x_nand_detect_ondie_ecc(struct mtd_info *mtd) * This function initializes the ecc block and functional pointers as per the * This function initializes the ecc block and functional pointers as per the * ecc mode * ecc mode */ */ static void pl35x_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) static void pl35x_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc, int ondie_ecc_state) { { struct nand_chip *nand_chip = mtd->priv; struct nand_chip *nand_chip = mtd_to_nand(mtd); nand_chip->ecc.mode = NAND_ECC_HW; ecc->mode = NAND_ECC_HW; nand_chip->ecc.read_oob = pl35x_nand_read_oob; ecc->read_oob = pl35x_nand_read_oob; nand_chip->ecc.read_page_raw = pl35x_nand_read_page_raw; ecc->read_page_raw = pl35x_nand_read_page_raw; nand_chip->ecc.strength = 1; ecc->strength = 1; nand_chip->ecc.write_oob = pl35x_nand_write_oob; ecc->write_oob = pl35x_nand_write_oob; nand_chip->ecc.write_page_raw = pl35x_nand_write_page_raw; ecc->write_page_raw = pl35x_nand_write_page_raw; if (ondie_ecc_state) { if (ondie_ecc_state) { /* bypass the controller ECC block */ /* bypass the controller ECC block */ Loading @@ -1028,11 +1096,11 @@ static void pl35x_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) * The software ECC routines won't work with the * The software ECC routines won't work with the * SMC controller * SMC controller */ */ nand_chip->ecc.bytes = 0; ecc->bytes = 0; nand_chip->ecc.layout = &ondie_nand_oob_64; mtd_set_ooblayout(mtd, &fsmc_ecc_ooblayout_ondie64_ops); nand_chip->ecc.read_page = pl35x_nand_read_page_raw; ecc->read_page = pl35x_nand_read_page_raw; nand_chip->ecc.write_page = pl35x_nand_write_page_raw; ecc->write_page = pl35x_nand_write_page_raw; nand_chip->ecc.size = mtd->writesize; ecc->size = mtd->writesize; /* /* * On-Die ECC spare bytes offset 8 is used for ECC codes * On-Die ECC spare bytes offset 8 is used for ECC codes * Use the BBT pattern descriptors * Use the BBT pattern descriptors Loading @@ -1041,13 +1109,13 @@ static void pl35x_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) nand_chip->bbt_md = &bbt_mirror_descr; nand_chip->bbt_md = &bbt_mirror_descr; } else { } else { /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ nand_chip->ecc.bytes = 3; ecc->bytes = 3; nand_chip->ecc.calculate = pl35x_nand_calculate_hwecc; ecc->calculate = pl35x_nand_calculate_hwecc; nand_chip->ecc.correct = pl35x_nand_correct_data; ecc->correct = pl35x_nand_correct_data; nand_chip->ecc.hwctl = NULL; ecc->hwctl = NULL; nand_chip->ecc.read_page = pl35x_nand_read_page_hwecc; ecc->read_page = pl35x_nand_read_page_hwecc; nand_chip->ecc.size = PL35X_NAND_ECC_SIZE; ecc->size = PL35X_NAND_ECC_SIZE; nand_chip->ecc.write_page = pl35x_nand_write_page_hwecc; ecc->write_page = pl35x_nand_write_page_hwecc; pl35x_smc_set_ecc_pg_size(mtd->writesize); pl35x_smc_set_ecc_pg_size(mtd->writesize); switch (mtd->writesize) { switch (mtd->writesize) { Loading @@ -1061,18 +1129,18 @@ static void pl35x_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) * The software ECC routines won't work with the * The software ECC routines won't work with the * SMC controller * SMC controller */ */ nand_chip->ecc.calculate = nand_calculate_ecc; ecc->calculate = nand_calculate_ecc; nand_chip->ecc.correct = nand_correct_data; ecc->correct = nand_correct_data; nand_chip->ecc.read_page = pl35x_nand_read_page_swecc; ecc->read_page = pl35x_nand_read_page_swecc; nand_chip->ecc.write_page = pl35x_nand_write_page_swecc; ecc->write_page = pl35x_nand_write_page_swecc; nand_chip->ecc.size = 256; ecc->size = 256; break; break; } } if (mtd->oobsize == 16) if (mtd->oobsize == 16) nand_chip->ecc.layout = &nand_oob_16; mtd_set_ooblayout(mtd, &fsmc_ecc_ooblayout16_ops); else if (mtd->oobsize == 64) else if (mtd->oobsize == 64) nand_chip->ecc.layout = &nand_oob_64; mtd_set_ooblayout(mtd, &fsmc_ecc_ooblayout64_ops); } } } } Loading @@ -1090,7 +1158,6 @@ static int pl35x_nand_probe(struct platform_device *pdev) struct mtd_info *mtd; struct mtd_info *mtd; struct nand_chip *nand_chip; struct nand_chip *nand_chip; struct resource *res; struct resource *res; struct mtd_part_parser_data ppdata; int ondie_ecc_state; int ondie_ecc_state; xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL); xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL); Loading @@ -1103,14 +1170,14 @@ static int pl35x_nand_probe(struct platform_device *pdev) if (IS_ERR(xnand->nand_base)) if (IS_ERR(xnand->nand_base)) return PTR_ERR(xnand->nand_base); return PTR_ERR(xnand->nand_base); /* Link the private data with the MTD structure */ mtd = &xnand->mtd; nand_chip = &xnand->chip; nand_chip = &xnand->chip; mtd = nand_to_mtd(nand_chip); nand_chip->priv = xnand; nand_set_controller_data(nand_chip, xnand); mtd->priv = nand_chip; mtd->priv = nand_chip; mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE; mtd->name = PL35X_NAND_DRIVER_NAME; mtd->name = PL35X_NAND_DRIVER_NAME; nand_set_flash_node(nand_chip, pdev->dev.of_node); /* Set address of NAND IO lines */ /* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = xnand->nand_base; nand_chip->IO_ADDR_R = xnand->nand_base; Loading Loading @@ -1149,7 +1216,7 @@ static int pl35x_nand_probe(struct platform_device *pdev) xnand->col_addr_cycles = xnand->col_addr_cycles = (nand_chip->onfi_params.addr_cycles >> 4) & 0xF; (nand_chip->onfi_params.addr_cycles >> 4) & 0xF; pl35x_nand_ecc_init(mtd, ondie_ecc_state); pl35x_nand_ecc_init(mtd, &nand_chip->ecc, ondie_ecc_state); if (nand_chip->options & NAND_BUSWIDTH_16) if (nand_chip->options & NAND_BUSWIDTH_16) pl35x_smc_set_buswidth(PL35X_SMC_MEM_WIDTH_16); pl35x_smc_set_buswidth(PL35X_SMC_MEM_WIDTH_16); Loading @@ -1165,9 +1232,7 @@ static int pl35x_nand_probe(struct platform_device *pdev) mtd->_unlock = nand_unlock; mtd->_unlock = nand_unlock; mtd->_lock = nand_lock; mtd->_lock = nand_lock; ppdata.of_node = pdev->dev.of_node; mtd_device_register(mtd, NULL, 0); mtd_device_parse_register(&xnand->mtd, NULL, &ppdata, NULL, 0); return 0; return 0; } } Loading @@ -1184,11 +1249,10 @@ static int pl35x_nand_probe(struct platform_device *pdev) static int pl35x_nand_remove(struct platform_device *pdev) static int pl35x_nand_remove(struct platform_device *pdev) { { struct pl35x_nand_info *xnand = platform_get_drvdata(pdev); struct pl35x_nand_info *xnand = platform_get_drvdata(pdev); struct mtd_info *mtd = nand_to_mtd(&xnand->chip); /* Release resources, unregister device */ /* Release resources, unregister device */ nand_release(&xnand->mtd); nand_release(mtd); /* kfree(NULL) is safe */ kfree(xnand->parts); return 0; return 0; } } Loading Loading
src/drivers/mtd/nand/pl35x_nand.c +165 −101 Original line number Original line Diff line number Diff line Loading @@ -83,8 +83,6 @@ struct pl35x_nand_command_format { /** /** * struct pl35x_nand_info - Defines the NAND flash driver instance * struct pl35x_nand_info - Defines the NAND flash driver instance * @chip: NAND chip information structure * @chip: NAND chip information structure * @mtd: MTD information structure * @parts: Pointer to the mtd_partition structure * @nand_base: Virtual address of the NAND flash device * @nand_base: Virtual address of the NAND flash device * @end_cmd_pending: End command is pending * @end_cmd_pending: End command is pending * @end_cmd: End command * @end_cmd: End command Loading @@ -93,8 +91,6 @@ struct pl35x_nand_command_format { */ */ struct pl35x_nand_info { struct pl35x_nand_info { struct nand_chip chip; struct nand_chip chip; struct mtd_info mtd; struct mtd_partition *parts; void __iomem *nand_base; void __iomem *nand_base; unsigned long end_cmd_pending; unsigned long end_cmd_pending; unsigned long end_cmd; unsigned long end_cmd; Loading Loading @@ -133,43 +129,110 @@ static const struct pl35x_nand_command_format pl35x_nand_commands[] = { */ */ }; }; /* Define default oob placement schemes for large and small page devices */ static int pl35x_ecc_ooblayout16_ecc(struct mtd_info *mtd, int section, static struct nand_ecclayout nand_oob_16 = { struct mtd_oob_region *oobregion) .eccbytes = 3, { .eccpos = {0, 1, 2}, struct nand_chip *chip = mtd_to_nand(mtd); .oobfree = { {.offset = 8, if (section >= chip->ecc.steps) . length = 8} } return -ERANGE; oobregion->offset = (section * 16) + 0; oobregion->length = chip->ecc.bytes; return 0; } static int pl35x_ecc_ooblayout16_free(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); if (section >= chip->ecc.steps) return -ERANGE; oobregion->offset = (section * 16) + 8; oobregion->length = 8; return 0; } static const struct mtd_ooblayout_ops fsmc_ecc_ooblayout16_ops = { .ecc = pl35x_ecc_ooblayout16_ecc, .free = pl35x_ecc_ooblayout16_free, }; }; static int pl35x_ecc_ooblayout64_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); if (section >= chip->ecc.steps) return -ERANGE; oobregion->offset = (section * 16) + 52; oobregion->length = chip->ecc.bytes; return 0; } static struct nand_ecclayout nand_oob_64 = { static int pl35x_ecc_ooblayout64_free(struct mtd_info *mtd, int section, .eccbytes = 12, struct mtd_oob_region *oobregion) .eccpos = { { 52, 53, 54, 55, 56, 57, struct nand_chip *chip = mtd_to_nand(mtd); 58, 59, 60, 61, 62, 63}, .oobfree = { if (section >= chip->ecc.steps) {.offset = 2, return -ERANGE; .length = 50} } oobregion->offset = (section * 16) + 2; oobregion->length = 50; return 0; } static const struct mtd_ooblayout_ops fsmc_ecc_ooblayout64_ops = { .ecc = pl35x_ecc_ooblayout64_ecc, .free = pl35x_ecc_ooblayout64_free, }; }; static int pl35x_ecc_ooblayout_ondie64_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); static struct nand_ecclayout ondie_nand_oob_64 = { if (section >= chip->ecc.steps) .eccbytes = 32, return -ERANGE; .eccpos = { oobregion->offset = (section * 16) + 8; 8, 9, 10, 11, 12, 13, 14, 15, oobregion->length = chip->ecc.bytes; 24, 25, 26, 27, 28, 29, 30, 31, 40, 41, 42, 43, 44, 45, 46, 47, return 0; 56, 57, 58, 59, 60, 61, 62, 63 } }, static int pl35x_ecc_ooblayout_ondie64_free(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { struct nand_chip *chip = mtd_to_nand(mtd); if (section >= chip->ecc.steps) return -ERANGE; .oobfree = { { .offset = 4, .length = 4 }, oobregion->length = 4; { .offset = 20, .length = 4 }, if (!section) { .offset = 36, .length = 4 }, oobregion->offset = 4; { .offset = 52, .length = 4 } else oobregion->offset = (section * 16) + 4; return 0; } } static const struct mtd_ooblayout_ops fsmc_ecc_ooblayout_ondie64_ops = { .ecc = pl35x_ecc_ooblayout_ondie64_ecc, .free = pl35x_ecc_ooblayout_ondie64_free, }; }; /* Generic flash bbt decriptors */ /* Generic flash bbt decriptors */ static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; Loading Loading @@ -211,7 +274,6 @@ static int pl35x_nand_calculate_hwecc(struct mtd_info *mtd, u32 ecc_value, ecc_status; u32 ecc_value, ecc_status; u8 ecc_reg, ecc_byte; u8 ecc_reg, ecc_byte; unsigned long timeout = jiffies + PL35X_NAND_ECC_BUSY_TIMEOUT; unsigned long timeout = jiffies + PL35X_NAND_ECC_BUSY_TIMEOUT; /* Wait till the ECC operation is complete or timeout */ /* Wait till the ECC operation is complete or timeout */ do { do { if (pl35x_smc_ecc_is_busy()) if (pl35x_smc_ecc_is_busy()) Loading Loading @@ -415,7 +477,8 @@ static int pl35x_nand_read_page_raw(struct mtd_info *mtd, */ */ static int pl35x_nand_write_page_raw(struct mtd_info *mtd, static int pl35x_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, struct nand_chip *chip, const uint8_t *buf, int oob_required) const uint8_t *buf, int oob_required, int page) { { unsigned long data_phase_addr; unsigned long data_phase_addr; uint8_t *p; uint8_t *p; Loading Loading @@ -450,15 +513,15 @@ static int pl35x_nand_write_page_raw(struct mtd_info *mtd, */ */ static int pl35x_nand_write_page_hwecc(struct mtd_info *mtd, static int pl35x_nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, struct nand_chip *chip, const uint8_t *buf, int oob_required) int oob_required, int page) { { int i, eccsize = chip->ecc.size; int eccsize = chip->ecc.size; int eccsteps = chip->ecc.steps; int eccsteps = chip->ecc.steps; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; unsigned long data_phase_addr; unsigned long data_phase_addr; uint8_t *oob_ptr; uint8_t *oob_ptr; u32 ret; for ( ; (eccsteps - 1); eccsteps--) { for ( ; (eccsteps - 1); eccsteps--) { chip->write_buf(mtd, p, eccsize); chip->write_buf(mtd, p, eccsize); Loading @@ -473,13 +536,14 @@ static int pl35x_nand_write_page_hwecc(struct mtd_info *mtd, chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; chip->IO_ADDR_W = (void __iomem * __force)data_phase_addr; chip->write_buf(mtd, p, PL35X_NAND_LAST_TRANSFER_LENGTH); chip->write_buf(mtd, p, PL35X_NAND_LAST_TRANSFER_LENGTH); /* Wait for ECC to be calculated and read the error values */ p = buf; p = buf; chip->ecc.calculate(mtd, p, &ecc_calc[0]); chip->ecc.calculate(mtd, p, &ecc_calc[0]); for (i = 0; i < chip->ecc.total; i++) /* Wait for ECC to be calculated and read the error values */ chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]); ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, chip->ecc.total); if (ret) return ret; /* Clear ECC last bit */ /* Clear ECC last bit */ data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; data_phase_addr = (unsigned long __force)chip->IO_ADDR_W; data_phase_addr &= ~PL35X_NAND_ECC_LAST; data_phase_addr &= ~PL35X_NAND_ECC_LAST; Loading Loading @@ -511,23 +575,23 @@ static int pl35x_nand_write_page_hwecc(struct mtd_info *mtd, */ */ static int pl35x_nand_write_page_swecc(struct mtd_info *mtd, static int pl35x_nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, struct nand_chip *chip, const uint8_t *buf, int oob_required) int oob_required, int page) { { int i, eccsize = chip->ecc.size; int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; int eccbytes = chip->ecc.bytes; int eccsteps = chip->ecc.steps; int eccsteps = chip->ecc.steps; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->buffers->ecccalc; const uint8_t *p = buf; const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; u32 ret; /* Software ecc calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); chip->ecc.calculate(mtd, p, &ecc_calc[0]); for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; chip->ecc.write_page_raw(mtd, chip, buf, 1); ret = mtd_ooblayout_set_eccbytes(mtd, ecc_calc, chip->oob_poi, 0, chip->ecc.total); if (ret) return ret; chip->ecc.write_page_raw(mtd, chip, buf, 1, page); return 0; return 0; } } Loading Loading @@ -555,9 +619,9 @@ static int pl35x_nand_read_page_hwecc(struct mtd_info *mtd, uint8_t *p = buf; uint8_t *p = buf; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_code = chip->buffers->ecccode; uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; unsigned long data_phase_addr; unsigned long data_phase_addr; uint8_t *oob_ptr; uint8_t *oob_ptr; u32 ret; for ( ; (eccsteps - 1); eccsteps--) { for ( ; (eccsteps - 1); eccsteps--) { chip->read_buf(mtd, p, eccsize); chip->read_buf(mtd, p, eccsize); Loading Loading @@ -594,8 +658,10 @@ static int pl35x_nand_read_page_hwecc(struct mtd_info *mtd, oob_ptr += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH); oob_ptr += (mtd->oobsize - PL35X_NAND_LAST_TRANSFER_LENGTH); chip->read_buf(mtd, oob_ptr, PL35X_NAND_LAST_TRANSFER_LENGTH); chip->read_buf(mtd, oob_ptr, PL35X_NAND_LAST_TRANSFER_LENGTH); for (i = 0; i < chip->ecc.total; i++) ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0, ecc_code[i] = ~(chip->oob_poi[eccpos[i]]); chip->ecc.total); if (ret) return ret; eccsteps = chip->ecc.steps; eccsteps = chip->ecc.steps; p = buf; p = buf; Loading Loading @@ -631,15 +697,15 @@ static int pl35x_nand_read_page_swecc(struct mtd_info *mtd, uint8_t *p = buf; uint8_t *p = buf; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_calc = chip->buffers->ecccalc; uint8_t *ecc_code = chip->buffers->ecccode; uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; u32 ret; chip->ecc.read_page_raw(mtd, chip, buf, page, 1); chip->ecc.read_page_raw(mtd, chip, buf, page, 1); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); chip->ecc.calculate(mtd, p, &ecc_calc[i]); for (i = 0; i < chip->ecc.total; i++) ret = mtd_ooblayout_get_eccbytes(mtd, ecc_calc, chip->oob_poi, ecc_code[i] = chip->oob_poi[eccpos[i]]; 0, chip->ecc.total); eccsteps = chip->ecc.steps; eccsteps = chip->ecc.steps; p = buf; p = buf; Loading Loading @@ -684,10 +750,10 @@ static void pl35x_nand_cmd_function(struct mtd_info *mtd, unsigned int command, if (command == NAND_CMD_UNLOCK1) pr_debug("NAND UNLOCK1\n"); if (command == NAND_CMD_UNLOCK1) pr_debug("NAND UNLOCK1\n"); if (command == NAND_CMD_SET_FEATURES) pr_debug("NAND NAND_CMD_SET_FEATURES\n"); if (command == NAND_CMD_SET_FEATURES) pr_debug("NAND NAND_CMD_SET_FEATURES\n"); struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd_to_nand(mtd); const struct pl35x_nand_command_format *curr_cmd = NULL; const struct pl35x_nand_command_format *curr_cmd = NULL; struct pl35x_nand_info *xnand = struct pl35x_nand_info *xnand = container_of(mtd, struct pl35x_nand_info, mtd); container_of(chip, struct pl35x_nand_info, chip); void __iomem *cmd_addr; void __iomem *cmd_addr; unsigned long cmd_data = 0, end_cmd_valid = 0; unsigned long cmd_data = 0, end_cmd_valid = 0; unsigned long cmd_phase_addr, data_phase_addr, end_cmd, i; unsigned long cmd_phase_addr, data_phase_addr, end_cmd, i; Loading Loading @@ -834,7 +900,7 @@ static void pl35x_nand_cmd_function(struct mtd_info *mtd, unsigned int command, static void pl35x_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) static void pl35x_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { { int i; int i; struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd_to_nand(mtd); unsigned long *ptr = (unsigned long *)buf; unsigned long *ptr = (unsigned long *)buf; len >>= 2; len >>= 2; Loading @@ -852,18 +918,17 @@ static void pl35x_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) int len) { { int i; int i; struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd_to_nand(mtd); unsigned long *ptr = (unsigned long *)buf; unsigned long *ptr = (unsigned long *)buf; pr_debug("pl35x_nand_write_buf: datasize=%d len=%d len>>2=%d\n",sizeof(ptr[0]),len,len>>2); pr_debug("pl35x_nand_write_buf: datasize=%d len=%d len>>2=%d\n",sizeof(ptr[0]),len,len>>2); len >>= 2; len >>= 2; for (i = 0; i < len; i++) for (i = 0; i < len; i++) writel(ptr[i], chip->IO_ADDR_W); writel(ptr[i], chip->IO_ADDR_W); //writeb(byte, chip->IO_ADDR_W); } } /** /** * pl35x_nand_device_ready - Check device ready/busy line * pl35x_nand_device_ready - Check device ready/busy line * @mtd: Pointer to the mtd_info structure * @mtd: Pointer to the mtd_info structure Loading @@ -879,6 +944,7 @@ static int pl35x_nand_device_ready(struct mtd_info *mtd) return 0; return 0; } } // Elphel: whole function /** /** * pl35x_nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand * pl35x_nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand * @mtd: MTD device structure * @mtd: MTD device structure Loading Loading @@ -916,6 +982,7 @@ static int pl35x_nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip * return 0; return 0; } } // Elphel: whole function /** /** * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand * @mtd: MTD device structure * @mtd: MTD device structure Loading Loading @@ -952,7 +1019,7 @@ static int pl35x_nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip * */ */ static int pl35x_nand_detect_ondie_ecc(struct mtd_info *mtd) static int pl35x_nand_detect_ondie_ecc(struct mtd_info *mtd) { { struct nand_chip *nand_chip = mtd->priv; struct nand_chip *nand_chip = mtd_to_nand(mtd); u8 maf_id, dev_id, i, get_feature; u8 maf_id, dev_id, i, get_feature; u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 }; u8 set_feature[4] = { 0x08, 0x00, 0x00, 0x00 }; Loading Loading @@ -1009,16 +1076,17 @@ static int pl35x_nand_detect_ondie_ecc(struct mtd_info *mtd) * This function initializes the ecc block and functional pointers as per the * This function initializes the ecc block and functional pointers as per the * ecc mode * ecc mode */ */ static void pl35x_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) static void pl35x_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc, int ondie_ecc_state) { { struct nand_chip *nand_chip = mtd->priv; struct nand_chip *nand_chip = mtd_to_nand(mtd); nand_chip->ecc.mode = NAND_ECC_HW; ecc->mode = NAND_ECC_HW; nand_chip->ecc.read_oob = pl35x_nand_read_oob; ecc->read_oob = pl35x_nand_read_oob; nand_chip->ecc.read_page_raw = pl35x_nand_read_page_raw; ecc->read_page_raw = pl35x_nand_read_page_raw; nand_chip->ecc.strength = 1; ecc->strength = 1; nand_chip->ecc.write_oob = pl35x_nand_write_oob; ecc->write_oob = pl35x_nand_write_oob; nand_chip->ecc.write_page_raw = pl35x_nand_write_page_raw; ecc->write_page_raw = pl35x_nand_write_page_raw; if (ondie_ecc_state) { if (ondie_ecc_state) { /* bypass the controller ECC block */ /* bypass the controller ECC block */ Loading @@ -1028,11 +1096,11 @@ static void pl35x_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) * The software ECC routines won't work with the * The software ECC routines won't work with the * SMC controller * SMC controller */ */ nand_chip->ecc.bytes = 0; ecc->bytes = 0; nand_chip->ecc.layout = &ondie_nand_oob_64; mtd_set_ooblayout(mtd, &fsmc_ecc_ooblayout_ondie64_ops); nand_chip->ecc.read_page = pl35x_nand_read_page_raw; ecc->read_page = pl35x_nand_read_page_raw; nand_chip->ecc.write_page = pl35x_nand_write_page_raw; ecc->write_page = pl35x_nand_write_page_raw; nand_chip->ecc.size = mtd->writesize; ecc->size = mtd->writesize; /* /* * On-Die ECC spare bytes offset 8 is used for ECC codes * On-Die ECC spare bytes offset 8 is used for ECC codes * Use the BBT pattern descriptors * Use the BBT pattern descriptors Loading @@ -1041,13 +1109,13 @@ static void pl35x_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) nand_chip->bbt_md = &bbt_mirror_descr; nand_chip->bbt_md = &bbt_mirror_descr; } else { } else { /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */ nand_chip->ecc.bytes = 3; ecc->bytes = 3; nand_chip->ecc.calculate = pl35x_nand_calculate_hwecc; ecc->calculate = pl35x_nand_calculate_hwecc; nand_chip->ecc.correct = pl35x_nand_correct_data; ecc->correct = pl35x_nand_correct_data; nand_chip->ecc.hwctl = NULL; ecc->hwctl = NULL; nand_chip->ecc.read_page = pl35x_nand_read_page_hwecc; ecc->read_page = pl35x_nand_read_page_hwecc; nand_chip->ecc.size = PL35X_NAND_ECC_SIZE; ecc->size = PL35X_NAND_ECC_SIZE; nand_chip->ecc.write_page = pl35x_nand_write_page_hwecc; ecc->write_page = pl35x_nand_write_page_hwecc; pl35x_smc_set_ecc_pg_size(mtd->writesize); pl35x_smc_set_ecc_pg_size(mtd->writesize); switch (mtd->writesize) { switch (mtd->writesize) { Loading @@ -1061,18 +1129,18 @@ static void pl35x_nand_ecc_init(struct mtd_info *mtd, int ondie_ecc_state) * The software ECC routines won't work with the * The software ECC routines won't work with the * SMC controller * SMC controller */ */ nand_chip->ecc.calculate = nand_calculate_ecc; ecc->calculate = nand_calculate_ecc; nand_chip->ecc.correct = nand_correct_data; ecc->correct = nand_correct_data; nand_chip->ecc.read_page = pl35x_nand_read_page_swecc; ecc->read_page = pl35x_nand_read_page_swecc; nand_chip->ecc.write_page = pl35x_nand_write_page_swecc; ecc->write_page = pl35x_nand_write_page_swecc; nand_chip->ecc.size = 256; ecc->size = 256; break; break; } } if (mtd->oobsize == 16) if (mtd->oobsize == 16) nand_chip->ecc.layout = &nand_oob_16; mtd_set_ooblayout(mtd, &fsmc_ecc_ooblayout16_ops); else if (mtd->oobsize == 64) else if (mtd->oobsize == 64) nand_chip->ecc.layout = &nand_oob_64; mtd_set_ooblayout(mtd, &fsmc_ecc_ooblayout64_ops); } } } } Loading @@ -1090,7 +1158,6 @@ static int pl35x_nand_probe(struct platform_device *pdev) struct mtd_info *mtd; struct mtd_info *mtd; struct nand_chip *nand_chip; struct nand_chip *nand_chip; struct resource *res; struct resource *res; struct mtd_part_parser_data ppdata; int ondie_ecc_state; int ondie_ecc_state; xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL); xnand = devm_kzalloc(&pdev->dev, sizeof(*xnand), GFP_KERNEL); Loading @@ -1103,14 +1170,14 @@ static int pl35x_nand_probe(struct platform_device *pdev) if (IS_ERR(xnand->nand_base)) if (IS_ERR(xnand->nand_base)) return PTR_ERR(xnand->nand_base); return PTR_ERR(xnand->nand_base); /* Link the private data with the MTD structure */ mtd = &xnand->mtd; nand_chip = &xnand->chip; nand_chip = &xnand->chip; mtd = nand_to_mtd(nand_chip); nand_chip->priv = xnand; nand_set_controller_data(nand_chip, xnand); mtd->priv = nand_chip; mtd->priv = nand_chip; mtd->owner = THIS_MODULE; mtd->owner = THIS_MODULE; mtd->name = PL35X_NAND_DRIVER_NAME; mtd->name = PL35X_NAND_DRIVER_NAME; nand_set_flash_node(nand_chip, pdev->dev.of_node); /* Set address of NAND IO lines */ /* Set address of NAND IO lines */ nand_chip->IO_ADDR_R = xnand->nand_base; nand_chip->IO_ADDR_R = xnand->nand_base; Loading Loading @@ -1149,7 +1216,7 @@ static int pl35x_nand_probe(struct platform_device *pdev) xnand->col_addr_cycles = xnand->col_addr_cycles = (nand_chip->onfi_params.addr_cycles >> 4) & 0xF; (nand_chip->onfi_params.addr_cycles >> 4) & 0xF; pl35x_nand_ecc_init(mtd, ondie_ecc_state); pl35x_nand_ecc_init(mtd, &nand_chip->ecc, ondie_ecc_state); if (nand_chip->options & NAND_BUSWIDTH_16) if (nand_chip->options & NAND_BUSWIDTH_16) pl35x_smc_set_buswidth(PL35X_SMC_MEM_WIDTH_16); pl35x_smc_set_buswidth(PL35X_SMC_MEM_WIDTH_16); Loading @@ -1165,9 +1232,7 @@ static int pl35x_nand_probe(struct platform_device *pdev) mtd->_unlock = nand_unlock; mtd->_unlock = nand_unlock; mtd->_lock = nand_lock; mtd->_lock = nand_lock; ppdata.of_node = pdev->dev.of_node; mtd_device_register(mtd, NULL, 0); mtd_device_parse_register(&xnand->mtd, NULL, &ppdata, NULL, 0); return 0; return 0; } } Loading @@ -1184,11 +1249,10 @@ static int pl35x_nand_probe(struct platform_device *pdev) static int pl35x_nand_remove(struct platform_device *pdev) static int pl35x_nand_remove(struct platform_device *pdev) { { struct pl35x_nand_info *xnand = platform_get_drvdata(pdev); struct pl35x_nand_info *xnand = platform_get_drvdata(pdev); struct mtd_info *mtd = nand_to_mtd(&xnand->chip); /* Release resources, unregister device */ /* Release resources, unregister device */ nand_release(&xnand->mtd); nand_release(mtd); /* kfree(NULL) is safe */ kfree(xnand->parts); return 0; return 0; } } Loading