Lines Matching +full:nand +full:- +full:ecc +full:- +full:engine
1 // SPDX-License-Identifier: GPL-2.0
3 * Support for Macronix external hardware ECC engine for NAND devices, also
4 * called DPE for Data Processing Engine.
10 #include <linux/dma-mapping.h>
18 #include <linux/mtd/nand.h>
19 #include <linux/mtd/nand-ecc-mxic.h>
53 /* ECC Chunk Size */
63 /* ECC Chunk Count */
98 /* ECC machinery */
124 static struct mxic_ecc_engine *nand_to_mxic(struct nand_device *nand) in nand_to_mxic() argument
126 struct nand_ecc_engine *eng = nand->ecc.engine; in nand_to_mxic()
128 if (eng->integration == NAND_ECC_ENGINE_INTEGRATION_EXTERNAL) in nand_to_mxic()
137 struct nand_device *nand = mtd_to_nanddev(mtd); in mxic_ecc_ooblayout_ecc() local
138 struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand); in mxic_ecc_ooblayout_ecc()
140 if (section < 0 || section >= ctx->steps) in mxic_ecc_ooblayout_ecc()
141 return -ERANGE; in mxic_ecc_ooblayout_ecc()
143 oobregion->offset = (section * ctx->oob_step_sz) + ctx->meta_sz; in mxic_ecc_ooblayout_ecc()
144 oobregion->length = ctx->parity_sz; in mxic_ecc_ooblayout_ecc()
152 struct nand_device *nand = mtd_to_nanddev(mtd); in mxic_ecc_ooblayout_free() local
153 struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand); in mxic_ecc_ooblayout_free()
155 if (section < 0 || section >= ctx->steps) in mxic_ecc_ooblayout_free()
156 return -ERANGE; in mxic_ecc_ooblayout_free()
159 oobregion->offset = 2; in mxic_ecc_ooblayout_free()
160 oobregion->length = ctx->meta_sz - 2; in mxic_ecc_ooblayout_free()
162 oobregion->offset = section * ctx->oob_step_sz; in mxic_ecc_ooblayout_free()
163 oobregion->length = ctx->meta_sz; in mxic_ecc_ooblayout_free()
170 .ecc = mxic_ecc_ooblayout_ecc,
178 reg = readl(mxic->regs + DP_CONFIG); in mxic_ecc_disable_engine()
180 writel(reg, mxic->regs + DP_CONFIG); in mxic_ecc_disable_engine()
187 reg = readl(mxic->regs + DP_CONFIG); in mxic_ecc_enable_engine()
189 writel(reg, mxic->regs + DP_CONFIG); in mxic_ecc_enable_engine()
194 writel(0, mxic->regs + INTRPT_SIG_EN); in mxic_ecc_disable_int()
199 writel(TRANS_CMPLT, mxic->regs + INTRPT_SIG_EN); in mxic_ecc_enable_int()
207 sts = readl(mxic->regs + INTRPT_STS); in mxic_ecc_isr()
212 complete(&mxic->complete); in mxic_ecc_isr()
214 writel(sts, mxic->regs + INTRPT_STS); in mxic_ecc_isr()
219 static int mxic_ecc_init_ctx(struct nand_device *nand, struct device *dev) in mxic_ecc_init_ctx() argument
221 struct mxic_ecc_engine *mxic = nand_to_mxic(nand); in mxic_ecc_init_ctx()
222 struct nand_ecc_props *conf = &nand->ecc.ctx.conf; in mxic_ecc_init_ctx()
223 struct nand_ecc_props *reqs = &nand->ecc.requirements; in mxic_ecc_init_ctx()
224 struct nand_ecc_props *user = &nand->ecc.user_conf; in mxic_ecc_init_ctx()
225 struct mtd_info *mtd = nanddev_to_mtd(nand); in mxic_ecc_init_ctx()
235 return -ENOMEM; in mxic_ecc_init_ctx()
237 nand->ecc.ctx.priv = ctx; in mxic_ecc_init_ctx()
239 /* Only large page NAND chips may use BCH */ in mxic_ecc_init_ctx()
240 if (mtd->oobsize < 64) { in mxic_ecc_init_ctx()
241 pr_err("BCH cannot be used with small page NAND chips\n"); in mxic_ecc_init_ctx()
242 return -EINVAL; in mxic_ecc_init_ctx()
249 TO_SPARE | TO_MAIN, mxic->regs + INTRPT_STS_EN); in mxic_ecc_init_ctx()
251 /* Configure the correction depending on the NAND device topology */ in mxic_ecc_init_ctx()
252 if (user->step_size && user->strength) { in mxic_ecc_init_ctx()
253 step_size = user->step_size; in mxic_ecc_init_ctx()
254 strength = user->strength; in mxic_ecc_init_ctx()
255 } else if (reqs->step_size && reqs->strength) { in mxic_ecc_init_ctx()
256 step_size = reqs->step_size; in mxic_ecc_init_ctx()
257 strength = reqs->strength; in mxic_ecc_init_ctx()
261 steps = mtd->writesize / step_size; in mxic_ecc_init_ctx()
266 conf->step_size = SZ_1K; in mxic_ecc_init_ctx()
267 steps = mtd->writesize / conf->step_size; in mxic_ecc_init_ctx()
269 ctx->status = devm_kzalloc(dev, steps * sizeof(u8), GFP_KERNEL); in mxic_ecc_init_ctx()
270 if (!ctx->status) in mxic_ecc_init_ctx()
271 return -ENOMEM; in mxic_ecc_init_ctx()
281 ARRAY_SIZE(possible_strength) - 1); in mxic_ecc_init_ctx()
284 idx = ARRAY_SIZE(possible_strength) - 1; in mxic_ecc_init_ctx()
288 for (; idx >= 0; idx--) { in mxic_ecc_init_ctx()
289 if (spare_size[idx] * steps <= mtd->oobsize) in mxic_ecc_init_ctx()
293 /* This engine cannot be used with this NAND device */ in mxic_ecc_init_ctx()
295 return -EINVAL; in mxic_ecc_init_ctx()
297 /* Configure the engine for the desired strength */ in mxic_ecc_init_ctx()
298 writel(ECC_TYP(idx), mxic->regs + DP_CONFIG); in mxic_ecc_init_ctx()
299 conf->strength = possible_strength[idx]; in mxic_ecc_init_ctx()
300 spare_reg = readl(mxic->regs + SPARE_SIZE); in mxic_ecc_init_ctx()
302 ctx->steps = steps; in mxic_ecc_init_ctx()
303 ctx->data_step_sz = mtd->writesize / steps; in mxic_ecc_init_ctx()
304 ctx->oob_step_sz = mtd->oobsize / steps; in mxic_ecc_init_ctx()
305 ctx->parity_sz = PARITY_SZ(spare_reg); in mxic_ecc_init_ctx()
306 ctx->meta_sz = META_SZ(spare_reg); in mxic_ecc_init_ctx()
309 ctx->req_ctx.oob_buffer_size = nanddev_per_page_oobsize(nand) + in mxic_ecc_init_ctx()
310 (ctx->steps * STAT_BYTES); in mxic_ecc_init_ctx()
311 ret = nand_ecc_init_req_tweaking(&ctx->req_ctx, nand); in mxic_ecc_init_ctx()
315 ctx->oobwithstat = kmalloc(mtd->oobsize + (ctx->steps * STAT_BYTES), in mxic_ecc_init_ctx()
317 if (!ctx->oobwithstat) { in mxic_ecc_init_ctx()
318 ret = -ENOMEM; in mxic_ecc_init_ctx()
322 sg_init_table(ctx->sg, 2); in mxic_ecc_init_ctx()
326 readl(mxic->regs + DP_VER) >> DP_VER_OFFSET); in mxic_ecc_init_ctx()
327 dev_err(dev, "Chunk size: %d\n", readl(mxic->regs + CHUNK_SIZE)); in mxic_ecc_init_ctx()
328 dev_err(dev, "Main size: %d\n", readl(mxic->regs + MAIN_SIZE)); in mxic_ecc_init_ctx()
331 dev_err(dev, "Parity size: %d\n", ctx->parity_sz); in mxic_ecc_init_ctx()
332 dev_err(dev, "Meta size: %d\n", ctx->meta_sz); in mxic_ecc_init_ctx()
334 if ((ctx->meta_sz + ctx->parity_sz + RSV_SZ(spare_reg)) != in mxic_ecc_init_ctx()
337 ctx->meta_sz, ctx->parity_sz, RSV_SZ(spare_reg), in mxic_ecc_init_ctx()
339 ret = -EINVAL; in mxic_ecc_init_ctx()
343 if (ctx->oob_step_sz != SPARE_SZ(spare_reg)) { in mxic_ecc_init_ctx()
345 ctx->oob_step_sz, SPARE_SZ(spare_reg)); in mxic_ecc_init_ctx()
346 ret = -EINVAL; in mxic_ecc_init_ctx()
353 kfree(ctx->oobwithstat); in mxic_ecc_init_ctx()
355 nand_ecc_cleanup_req_tweaking(&ctx->req_ctx); in mxic_ecc_init_ctx()
360 static int mxic_ecc_init_ctx_external(struct nand_device *nand) in mxic_ecc_init_ctx_external() argument
362 struct mxic_ecc_engine *mxic = nand_to_mxic(nand); in mxic_ecc_init_ctx_external()
363 struct device *dev = nand->ecc.engine->dev; in mxic_ecc_init_ctx_external()
366 dev_info(dev, "Macronix ECC engine in external mode\n"); in mxic_ecc_init_ctx_external()
368 ret = mxic_ecc_init_ctx(nand, dev); in mxic_ecc_init_ctx_external()
373 writel(1, mxic->regs + CHUNK_CNT); in mxic_ecc_init_ctx_external()
375 mxic->regs + HC_CONFIG); in mxic_ecc_init_ctx_external()
380 static int mxic_ecc_init_ctx_pipelined(struct nand_device *nand) in mxic_ecc_init_ctx_pipelined() argument
382 struct mxic_ecc_engine *mxic = nand_to_mxic(nand); in mxic_ecc_init_ctx_pipelined()
387 dev = nand_ecc_get_engine_dev(nand->ecc.engine->dev); in mxic_ecc_init_ctx_pipelined()
389 return -EINVAL; in mxic_ecc_init_ctx_pipelined()
391 dev_info(dev, "Macronix ECC engine in pipelined/mapping mode\n"); in mxic_ecc_init_ctx_pipelined()
393 ret = mxic_ecc_init_ctx(nand, dev); in mxic_ecc_init_ctx_pipelined()
397 ctx = nand_to_ecc_ctx(nand); in mxic_ecc_init_ctx_pipelined()
400 writel(ctx->steps, mxic->regs + CHUNK_CNT); in mxic_ecc_init_ctx_pipelined()
403 * Interleaved ECC scheme cannot be used otherwise factory bad block in mxic_ecc_init_ctx_pipelined()
407 mxic->regs + HC_CONFIG); in mxic_ecc_init_ctx_pipelined()
412 static void mxic_ecc_cleanup_ctx(struct nand_device *nand) in mxic_ecc_cleanup_ctx() argument
414 struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand); in mxic_ecc_cleanup_ctx()
417 nand_ecc_cleanup_req_tweaking(&ctx->req_ctx); in mxic_ecc_cleanup_ctx()
418 kfree(ctx->oobwithstat); in mxic_ecc_cleanup_ctx()
427 if (mxic->irq) { in mxic_ecc_data_xfer_wait_for_completion()
428 reinit_completion(&mxic->complete); in mxic_ecc_data_xfer_wait_for_completion()
430 ret = wait_for_completion_timeout(&mxic->complete, in mxic_ecc_data_xfer_wait_for_completion()
432 ret = ret ? 0 : -ETIMEDOUT; in mxic_ecc_data_xfer_wait_for_completion()
435 ret = readl_poll_timeout(mxic->regs + INTRPT_STS, val, in mxic_ecc_data_xfer_wait_for_completion()
437 writel(val, mxic->regs + INTRPT_STS); in mxic_ecc_data_xfer_wait_for_completion()
441 dev_err(mxic->dev, "Timeout on data xfer completion\n"); in mxic_ecc_data_xfer_wait_for_completion()
442 return -ETIMEDOUT; in mxic_ecc_data_xfer_wait_for_completion()
458 writel(SDMA_STRT | dir, mxic->regs + SDMA_CTRL); in mxic_ecc_process_data()
474 writel(dirmap, mxic->regs + HC_SLV_ADDR); in mxic_ecc_process_data_pipelined()
482 u8 *buf = ctx->oobwithstat; in mxic_ecc_extract_status_bytes()
486 /* Extract the ECC status */ in mxic_ecc_extract_status_bytes()
487 for (step = 0; step < ctx->steps; step++) { in mxic_ecc_extract_status_bytes()
488 next_stat_pos = ctx->oob_step_sz + in mxic_ecc_extract_status_bytes()
489 ((STAT_BYTES + ctx->oob_step_sz) * step); in mxic_ecc_extract_status_bytes()
491 ctx->status[step] = buf[next_stat_pos]; in mxic_ecc_extract_status_bytes()
500 /* Reconstruct the OOB buffer linearly (without the ECC status bytes) */ in mxic_ecc_reconstruct_oobbuf()
501 for (step = 0; step < ctx->steps; step++) in mxic_ecc_reconstruct_oobbuf()
502 memcpy(dst + (step * ctx->oob_step_sz), in mxic_ecc_reconstruct_oobbuf()
503 src + (step * (ctx->oob_step_sz + STAT_BYTES)), in mxic_ecc_reconstruct_oobbuf()
504 ctx->oob_step_sz); in mxic_ecc_reconstruct_oobbuf()
513 for (step = 0; step < ctx->steps; step++) in mxic_ecc_add_room_in_oobbuf()
514 memcpy(dst + (step * (ctx->oob_step_sz + STAT_BYTES)), in mxic_ecc_add_room_in_oobbuf()
515 src + (step * ctx->oob_step_sz), in mxic_ecc_add_room_in_oobbuf()
516 ctx->oob_step_sz); in mxic_ecc_add_room_in_oobbuf()
520 struct nand_device *nand) in mxic_ecc_count_biterrs() argument
522 struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand); in mxic_ecc_count_biterrs()
523 struct mtd_info *mtd = nanddev_to_mtd(nand); in mxic_ecc_count_biterrs()
524 struct device *dev = mxic->dev; in mxic_ecc_count_biterrs()
529 for (step = 0; step < ctx->steps; step++) { in mxic_ecc_count_biterrs()
530 u8 stat = ctx->status[step]; in mxic_ecc_count_biterrs()
533 dev_dbg(dev, "ECC step %d: no error\n", step); in mxic_ecc_count_biterrs()
535 dev_dbg(dev, "ECC step %d: erased\n", step); in mxic_ecc_count_biterrs()
537 dev_dbg(dev, "ECC step %d: uncorrectable\n", step); in mxic_ecc_count_biterrs()
538 mtd->ecc_stats.failed++; in mxic_ecc_count_biterrs()
541 dev_dbg(dev, "ECC step %d: %d bits corrected\n", in mxic_ecc_count_biterrs()
544 mtd->ecc_stats.corrected += stat; in mxic_ecc_count_biterrs()
548 return failure ? -EBADMSG : max_bf; in mxic_ecc_count_biterrs()
551 /* External ECC engine helpers */
552 static int mxic_ecc_prepare_io_req_external(struct nand_device *nand, in mxic_ecc_prepare_io_req_external() argument
555 struct mxic_ecc_engine *mxic = nand_to_mxic(nand); in mxic_ecc_prepare_io_req_external()
556 struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand); in mxic_ecc_prepare_io_req_external()
557 struct mtd_info *mtd = nanddev_to_mtd(nand); in mxic_ecc_prepare_io_req_external()
560 if (req->mode == MTD_OPS_RAW) in mxic_ecc_prepare_io_req_external()
563 nand_ecc_tweak_req(&ctx->req_ctx, req); in mxic_ecc_prepare_io_req_external()
564 ctx->req = req; in mxic_ecc_prepare_io_req_external()
566 if (req->type == NAND_PAGE_READ) in mxic_ecc_prepare_io_req_external()
569 mxic_ecc_add_room_in_oobbuf(ctx, ctx->oobwithstat, in mxic_ecc_prepare_io_req_external()
570 ctx->req->oobbuf.out); in mxic_ecc_prepare_io_req_external()
572 sg_set_buf(&ctx->sg[0], req->databuf.out, req->datalen); in mxic_ecc_prepare_io_req_external()
573 sg_set_buf(&ctx->sg[1], ctx->oobwithstat, in mxic_ecc_prepare_io_req_external()
574 req->ooblen + (ctx->steps * STAT_BYTES)); in mxic_ecc_prepare_io_req_external()
576 nents = dma_map_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL); in mxic_ecc_prepare_io_req_external()
578 return -EINVAL; in mxic_ecc_prepare_io_req_external()
580 mutex_lock(&mxic->lock); in mxic_ecc_prepare_io_req_external()
582 for (step = 0; step < ctx->steps; step++) { in mxic_ecc_prepare_io_req_external()
583 writel(sg_dma_address(&ctx->sg[0]) + (step * ctx->data_step_sz), in mxic_ecc_prepare_io_req_external()
584 mxic->regs + SDMA_MAIN_ADDR); in mxic_ecc_prepare_io_req_external()
585 writel(sg_dma_address(&ctx->sg[1]) + (step * (ctx->oob_step_sz + STAT_BYTES)), in mxic_ecc_prepare_io_req_external()
586 mxic->regs + SDMA_SPARE_ADDR); in mxic_ecc_prepare_io_req_external()
587 ret = mxic_ecc_process_data(mxic, ctx->req->type); in mxic_ecc_prepare_io_req_external()
592 mutex_unlock(&mxic->lock); in mxic_ecc_prepare_io_req_external()
594 dma_unmap_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL); in mxic_ecc_prepare_io_req_external()
599 /* Retrieve the calculated ECC bytes */ in mxic_ecc_prepare_io_req_external()
600 for (step = 0; step < ctx->steps; step++) { in mxic_ecc_prepare_io_req_external()
601 offset = ctx->meta_sz + (step * ctx->oob_step_sz); in mxic_ecc_prepare_io_req_external()
603 (u8 *)ctx->req->oobbuf.out + offset, in mxic_ecc_prepare_io_req_external()
604 ctx->oobwithstat + (step * STAT_BYTES), in mxic_ecc_prepare_io_req_external()
605 step * ctx->parity_sz, in mxic_ecc_prepare_io_req_external()
606 ctx->parity_sz); in mxic_ecc_prepare_io_req_external()
612 static int mxic_ecc_finish_io_req_external(struct nand_device *nand, in mxic_ecc_finish_io_req_external() argument
615 struct mxic_ecc_engine *mxic = nand_to_mxic(nand); in mxic_ecc_finish_io_req_external()
616 struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand); in mxic_ecc_finish_io_req_external()
619 if (req->mode == MTD_OPS_RAW) in mxic_ecc_finish_io_req_external()
622 if (req->type == NAND_PAGE_WRITE) { in mxic_ecc_finish_io_req_external()
623 nand_ecc_restore_req(&ctx->req_ctx, req); in mxic_ecc_finish_io_req_external()
627 /* Copy the OOB buffer and add room for the ECC engine status bytes */ in mxic_ecc_finish_io_req_external()
628 mxic_ecc_add_room_in_oobbuf(ctx, ctx->oobwithstat, ctx->req->oobbuf.in); in mxic_ecc_finish_io_req_external()
630 sg_set_buf(&ctx->sg[0], req->databuf.in, req->datalen); in mxic_ecc_finish_io_req_external()
631 sg_set_buf(&ctx->sg[1], ctx->oobwithstat, in mxic_ecc_finish_io_req_external()
632 req->ooblen + (ctx->steps * STAT_BYTES)); in mxic_ecc_finish_io_req_external()
633 nents = dma_map_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL); in mxic_ecc_finish_io_req_external()
635 return -EINVAL; in mxic_ecc_finish_io_req_external()
637 mutex_lock(&mxic->lock); in mxic_ecc_finish_io_req_external()
639 for (step = 0; step < ctx->steps; step++) { in mxic_ecc_finish_io_req_external()
640 writel(sg_dma_address(&ctx->sg[0]) + (step * ctx->data_step_sz), in mxic_ecc_finish_io_req_external()
641 mxic->regs + SDMA_MAIN_ADDR); in mxic_ecc_finish_io_req_external()
642 writel(sg_dma_address(&ctx->sg[1]) + (step * (ctx->oob_step_sz + STAT_BYTES)), in mxic_ecc_finish_io_req_external()
643 mxic->regs + SDMA_SPARE_ADDR); in mxic_ecc_finish_io_req_external()
644 ret = mxic_ecc_process_data(mxic, ctx->req->type); in mxic_ecc_finish_io_req_external()
649 mutex_unlock(&mxic->lock); in mxic_ecc_finish_io_req_external()
651 dma_unmap_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL); in mxic_ecc_finish_io_req_external()
654 nand_ecc_restore_req(&ctx->req_ctx, req); in mxic_ecc_finish_io_req_external()
660 mxic_ecc_reconstruct_oobbuf(ctx, ctx->req->oobbuf.in, ctx->oobwithstat); in mxic_ecc_finish_io_req_external()
662 nand_ecc_restore_req(&ctx->req_ctx, req); in mxic_ecc_finish_io_req_external()
664 return mxic_ecc_count_biterrs(mxic, nand); in mxic_ecc_finish_io_req_external()
667 /* Pipelined ECC engine helpers */
668 static int mxic_ecc_prepare_io_req_pipelined(struct nand_device *nand, in mxic_ecc_prepare_io_req_pipelined() argument
671 struct mxic_ecc_engine *mxic = nand_to_mxic(nand); in mxic_ecc_prepare_io_req_pipelined()
672 struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand); in mxic_ecc_prepare_io_req_pipelined()
675 if (req->mode == MTD_OPS_RAW) in mxic_ecc_prepare_io_req_pipelined()
678 nand_ecc_tweak_req(&ctx->req_ctx, req); in mxic_ecc_prepare_io_req_pipelined()
679 ctx->req = req; in mxic_ecc_prepare_io_req_pipelined()
681 /* Copy the OOB buffer and add room for the ECC engine status bytes */ in mxic_ecc_prepare_io_req_pipelined()
682 mxic_ecc_add_room_in_oobbuf(ctx, ctx->oobwithstat, ctx->req->oobbuf.in); in mxic_ecc_prepare_io_req_pipelined()
684 sg_set_buf(&ctx->sg[0], req->databuf.in, req->datalen); in mxic_ecc_prepare_io_req_pipelined()
685 sg_set_buf(&ctx->sg[1], ctx->oobwithstat, in mxic_ecc_prepare_io_req_pipelined()
686 req->ooblen + (ctx->steps * STAT_BYTES)); in mxic_ecc_prepare_io_req_pipelined()
688 nents = dma_map_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL); in mxic_ecc_prepare_io_req_pipelined()
690 return -EINVAL; in mxic_ecc_prepare_io_req_pipelined()
692 mutex_lock(&mxic->lock); in mxic_ecc_prepare_io_req_pipelined()
694 writel(sg_dma_address(&ctx->sg[0]), mxic->regs + SDMA_MAIN_ADDR); in mxic_ecc_prepare_io_req_pipelined()
695 writel(sg_dma_address(&ctx->sg[1]), mxic->regs + SDMA_SPARE_ADDR); in mxic_ecc_prepare_io_req_pipelined()
700 static int mxic_ecc_finish_io_req_pipelined(struct nand_device *nand, in mxic_ecc_finish_io_req_pipelined() argument
703 struct mxic_ecc_engine *mxic = nand_to_mxic(nand); in mxic_ecc_finish_io_req_pipelined()
704 struct mxic_ecc_ctx *ctx = nand_to_ecc_ctx(nand); in mxic_ecc_finish_io_req_pipelined()
707 if (req->mode == MTD_OPS_RAW) in mxic_ecc_finish_io_req_pipelined()
710 mutex_unlock(&mxic->lock); in mxic_ecc_finish_io_req_pipelined()
712 dma_unmap_sg(mxic->dev, ctx->sg, 2, DMA_BIDIRECTIONAL); in mxic_ecc_finish_io_req_pipelined()
714 if (req->type == NAND_PAGE_READ) { in mxic_ecc_finish_io_req_pipelined()
716 mxic_ecc_reconstruct_oobbuf(ctx, ctx->req->oobbuf.in, in mxic_ecc_finish_io_req_pipelined()
717 ctx->oobwithstat); in mxic_ecc_finish_io_req_pipelined()
718 ret = mxic_ecc_count_biterrs(mxic, nand); in mxic_ecc_finish_io_req_pipelined()
721 nand_ecc_restore_req(&ctx->req_ctx, req); in mxic_ecc_finish_io_req_pipelined()
752 /* Retrieve the nand-ecc-engine phandle */ in mxic_ecc_get_pdev()
753 np = of_parse_phandle(spi_pdev->dev.of_node, "nand-ecc-engine", 0); in mxic_ecc_get_pdev()
757 /* Jump to the engine's device node */ in mxic_ecc_get_pdev()
768 platform_device_put(to_platform_device(mxic->dev)); in mxic_ecc_put_pipelined_engine()
780 return ERR_PTR(-ENODEV); in mxic_ecc_get_pipelined_engine()
785 return ERR_PTR(-EPROBE_DEFER); in mxic_ecc_get_pipelined_engine()
788 return &mxic->pipelined_engine; in mxic_ecc_get_pipelined_engine()
793 * Only the external ECC engine is exported as the pipelined is SoC specific, so
798 struct device *dev = &pdev->dev; in mxic_ecc_probe()
802 mxic = devm_kzalloc(&pdev->dev, sizeof(*mxic), GFP_KERNEL); in mxic_ecc_probe()
804 return -ENOMEM; in mxic_ecc_probe()
806 mxic->dev = &pdev->dev; in mxic_ecc_probe()
809 * Both memory regions for the ECC engine itself and the AXI slave in mxic_ecc_probe()
812 mxic->regs = devm_platform_ioremap_resource(pdev, 0); in mxic_ecc_probe()
813 if (IS_ERR(mxic->regs)) { in mxic_ecc_probe()
814 dev_err(&pdev->dev, "Missing memory region\n"); in mxic_ecc_probe()
815 return PTR_ERR(mxic->regs); in mxic_ecc_probe()
822 mxic->irq = platform_get_irq_byname_optional(pdev, "ecc-engine"); in mxic_ecc_probe()
823 if (mxic->irq > 0) { in mxic_ecc_probe()
824 ret = devm_request_irq(&pdev->dev, mxic->irq, mxic_ecc_isr, 0, in mxic_ecc_probe()
825 "mxic-ecc", mxic); in mxic_ecc_probe()
830 mxic->irq = 0; in mxic_ecc_probe()
833 mutex_init(&mxic->lock); in mxic_ecc_probe()
836 * In external mode, the device is the ECC engine. In pipelined mode, in mxic_ecc_probe()
838 * right ECC engine based on the DT properties. in mxic_ecc_probe()
840 mxic->external_engine.dev = &pdev->dev; in mxic_ecc_probe()
841 mxic->external_engine.integration = NAND_ECC_ENGINE_INTEGRATION_EXTERNAL; in mxic_ecc_probe()
842 mxic->external_engine.ops = &mxic_ecc_engine_external_ops; in mxic_ecc_probe()
844 nand_ecc_register_on_host_hw_engine(&mxic->external_engine); in mxic_ecc_probe()
855 nand_ecc_unregister_on_host_hw_engine(&mxic->external_engine); in mxic_ecc_remove()
860 .compatible = "mxicy,nand-ecc-engine-rev3",
868 .name = "mxic-nand-ecc-engine",
878 MODULE_DESCRIPTION("Macronix NAND hardware ECC controller");