.ops = &spinand_ondie_ecc_engine_ops,
 };
 
+static void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
+{
+       struct spinand_ondie_ecc_conf *engine_conf = nand->ecc.ctx.priv;
+
+       if (nand->ecc.ctx.conf.engine_type == NAND_ECC_ENGINE_TYPE_ON_DIE &&
+           engine_conf)
+               engine_conf->status = status;
+}
+
 static int spinand_write_enable_op(struct spinand_device *spinand)
 {
        struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true);
                                      const struct nand_page_io_req *req)
 {
        struct nand_device *nand = spinand_to_nand(spinand);
-       struct mtd_info *mtd = nanddev_to_mtd(nand);
        struct spi_mem_dirmap_desc *rdesc;
        unsigned int nbytes = 0;
        void *buf = NULL;
                memcpy(req->databuf.in, spinand->databuf + req->dataoffs,
                       req->datalen);
 
-       if (req->ooblen) {
-               if (req->mode == MTD_OPS_AUTO_OOB)
-                       mtd_ooblayout_get_databytes(mtd, req->oobbuf.in,
-                                                   spinand->oobbuf,
-                                                   req->ooboffs,
-                                                   req->ooblen);
-               else
-                       memcpy(req->oobbuf.in, spinand->oobbuf + req->ooboffs,
-                              req->ooblen);
-       }
-
        return 0;
 }
 
                                     const struct nand_page_io_req *req)
 {
        struct nand_device *nand = spinand_to_nand(spinand);
-       struct mtd_info *mtd = nanddev_to_mtd(nand);
+       struct mtd_info *mtd = spinand_to_mtd(spinand);
        struct spi_mem_dirmap_desc *wdesc;
        unsigned int nbytes, column = 0;
        void *buf = spinand->databuf;
         * must fill the page cache entirely even if we only want to program
         * the data portion of the page, otherwise we might corrupt the BBM or
         * user data previously programmed in OOB area.
+        *
+        * Only reset the data buffer manually, the OOB buffer is prepared by
+        * ECC engines ->prepare_io_req() callback.
         */
        nbytes = nanddev_page_size(nand) + nanddev_per_page_oobsize(nand);
-       memset(spinand->databuf, 0xff, nbytes);
+       memset(spinand->databuf, 0xff, nanddev_page_size(nand));
 
        if (req->datalen)
                memcpy(spinand->databuf + req->dataoffs, req->databuf.out,
 }
 
 static int spinand_read_page(struct spinand_device *spinand,
-                            const struct nand_page_io_req *req,
-                            bool ecc_enabled)
+                            const struct nand_page_io_req *req)
 {
+       struct nand_device *nand = spinand_to_nand(spinand);
        u8 status;
        int ret;
 
+       ret = nand_ecc_prepare_io_req(nand, (struct nand_page_io_req *)req);
+       if (ret)
+               return ret;
+
        ret = spinand_load_page_op(spinand, req);
        if (ret)
                return ret;
        if (ret < 0)
                return ret;
 
+       spinand_ondie_ecc_save_status(nand, status);
+
        ret = spinand_read_from_cache_op(spinand, req);
        if (ret)
                return ret;
 
-       if (!ecc_enabled)
-               return 0;
-
-       return spinand_check_ecc_status(spinand, status);
+       return nand_ecc_finish_io_req(nand, (struct nand_page_io_req *)req);
 }
 
 static int spinand_write_page(struct spinand_device *spinand,
                              const struct nand_page_io_req *req)
 {
+       struct nand_device *nand = spinand_to_nand(spinand);
        u8 status;
        int ret;
 
+       ret = nand_ecc_prepare_io_req(nand, (struct nand_page_io_req *)req);
+       if (ret)
+               return ret;
+
        ret = spinand_write_enable_op(spinand);
        if (ret)
                return ret;
 
        ret = spinand_wait(spinand, &status);
        if (!ret && (status & STATUS_PROG_FAILED))
-               ret = -EIO;
+               return -EIO;
 
-       return ret;
+       return nand_ecc_finish_io_req(nand, (struct nand_page_io_req *)req);
 }
 
 static int spinand_mtd_read(struct mtd_info *mtd, loff_t from,
        struct nand_device *nand = mtd_to_nanddev(mtd);
        unsigned int max_bitflips = 0;
        struct nand_io_iter iter;
-       bool enable_ecc = false;
+       bool disable_ecc = false;
        bool ecc_failed = false;
        int ret = 0;
 
-       if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout)
-               enable_ecc = true;
+       if (ops->mode == MTD_OPS_RAW || !spinand->eccinfo.ooblayout)
+               disable_ecc = true;
 
        mutex_lock(&spinand->lock);
 
        nanddev_io_for_each_page(nand, NAND_PAGE_READ, from, ops, &iter) {
-               ret = spinand_select_target(spinand, iter.req.pos.target);
-               if (ret)
-                       break;
+               if (disable_ecc)
+                       iter.req.mode = MTD_OPS_RAW;
 
-               ret = spinand_ecc_enable(spinand, enable_ecc);
+               ret = spinand_select_target(spinand, iter.req.pos.target);
                if (ret)
                        break;
 
-               ret = spinand_read_page(spinand, &iter.req, enable_ecc);
+               ret = spinand_read_page(spinand, &iter.req);
                if (ret < 0 && ret != -EBADMSG)
                        break;
 
        struct spinand_device *spinand = mtd_to_spinand(mtd);
        struct nand_device *nand = mtd_to_nanddev(mtd);
        struct nand_io_iter iter;
-       bool enable_ecc = false;
+       bool disable_ecc = false;
        int ret = 0;
 
-       if (ops->mode != MTD_OPS_RAW && mtd->ooblayout)
-               enable_ecc = true;
+       if (ops->mode == MTD_OPS_RAW || !mtd->ooblayout)
+               disable_ecc = true;
 
        mutex_lock(&spinand->lock);
 
        nanddev_io_for_each_page(nand, NAND_PAGE_WRITE, to, ops, &iter) {
-               ret = spinand_select_target(spinand, iter.req.pos.target);
-               if (ret)
-                       break;
+               if (disable_ecc)
+                       iter.req.mode = MTD_OPS_RAW;
 
-               ret = spinand_ecc_enable(spinand, enable_ecc);
+               ret = spinand_select_target(spinand, iter.req.pos.target);
                if (ret)
                        break;
 
        };
 
        spinand_select_target(spinand, pos->target);
-       spinand_read_page(spinand, &req, false);
+       spinand_read_page(spinand, &req);
        if (marker[0] != 0xff || marker[1] != 0xff)
                return true;
 
        nand->ecc.defaults.engine_type = NAND_ECC_ENGINE_TYPE_ON_DIE;
        nand->ecc.ondie_engine = &spinand_ondie_ecc_engine;
 
+       spinand_ecc_enable(spinand, false);
+       ret = nanddev_ecc_engine_init(nand);
+       if (ret)
+               goto err_cleanup_nanddev;
+
        /*
         * Right now, we don't support ECC, so let the whole oob
         * area available for the user.
        mtd->_erase = spinand_mtd_erase;
        mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks;
 
-       if (spinand->eccinfo.ooblayout)
-               mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
-       else
-               mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout);
-
        ret = mtd_ooblayout_count_freebytes(mtd);
        if (ret < 0)
-               goto err_cleanup_nanddev;
+               goto err_cleanup_ecc_engine;
 
        mtd->oobavail = ret;
 
 
        return 0;
 
+err_cleanup_ecc_engine:
+       nanddev_ecc_engine_cleanup(nand);
+
 err_cleanup_nanddev:
        nanddev_cleanup(nand);