mtd: spinand: Instantiate a SPI-NAND on-die ECC engine
[linux-2.6-microblaze.git] / drivers / mtd / nand / spi / core.c
index b2830e1..069ebf8 100644 (file)
@@ -246,6 +246,73 @@ static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
        .free = spinand_noecc_ooblayout_free,
 };
 
+static int spinand_ondie_ecc_init_ctx(struct nand_device *nand)
+{
+       struct spinand_device *spinand = nand_to_spinand(nand);
+       struct mtd_info *mtd = nanddev_to_mtd(nand);
+       struct spinand_ondie_ecc_conf *engine_conf;
+
+       nand->ecc.ctx.conf.engine_type = NAND_ECC_ENGINE_TYPE_ON_DIE;
+       nand->ecc.ctx.conf.step_size = nand->ecc.requirements.step_size;
+       nand->ecc.ctx.conf.strength = nand->ecc.requirements.strength;
+
+       engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
+       if (!engine_conf)
+               return -ENOMEM;
+
+       nand->ecc.ctx.priv = engine_conf;
+
+       if (spinand->eccinfo.ooblayout)
+               mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
+       else
+               mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout);
+
+       return 0;
+}
+
+static void spinand_ondie_ecc_cleanup_ctx(struct nand_device *nand)
+{
+       kfree(nand->ecc.ctx.priv);
+}
+
+static int spinand_ondie_ecc_prepare_io_req(struct nand_device *nand,
+                                           struct nand_page_io_req *req)
+{
+       struct spinand_device *spinand = nand_to_spinand(nand);
+       bool enable = (req->mode != MTD_OPS_RAW);
+
+       /* Only enable or disable the engine */
+       return spinand_ecc_enable(spinand, enable);
+}
+
+static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand,
+                                          struct nand_page_io_req *req)
+{
+       struct spinand_ondie_ecc_conf *engine_conf = nand->ecc.ctx.priv;
+       struct spinand_device *spinand = nand_to_spinand(nand);
+
+       if (req->mode == MTD_OPS_RAW)
+               return 0;
+
+       /* Nothing to do when finishing a page write */
+       if (req->type == NAND_PAGE_WRITE)
+               return 0;
+
+       /* Finish a page write: check the status, report errors/bitflips */
+       return spinand_check_ecc_status(spinand, engine_conf->status);
+}
+
+static struct nand_ecc_engine_ops spinand_ondie_ecc_engine_ops = {
+       .init_ctx = spinand_ondie_ecc_init_ctx,
+       .cleanup_ctx = spinand_ondie_ecc_cleanup_ctx,
+       .prepare_io_req = spinand_ondie_ecc_prepare_io_req,
+       .finish_io_req = spinand_ondie_ecc_finish_io_req,
+};
+
+static __maybe_unused struct nand_ecc_engine spinand_ondie_ecc_engine = {
+       .ops = &spinand_ondie_ecc_engine_ops,
+};
+
 static int spinand_write_enable_op(struct spinand_device *spinand)
 {
        struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true);