diff --git a/drivers/mtd/nand/ecc-sw-bch.c b/drivers/mtd/nand/ecc-sw-bch.c
index 405552d014a8..bda31ef8f0b8 100644
--- a/drivers/mtd/nand/ecc-sw-bch.c
+++ b/drivers/mtd/nand/ecc-sw-bch.c
@@ -238,7 +238,9 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand)
 	engine_conf->code_size = code_size;
 	engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
 	engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
-	if (!engine_conf->calc_buf || !engine_conf->code_buf) {
+	engine_conf->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
+	if (!engine_conf->calc_buf || !engine_conf->code_buf ||
+	    !engine_conf->oob_buf) {
 		ret = -ENOMEM;
 		goto free_bufs;
 	}
@@ -267,6 +269,7 @@ int nand_ecc_sw_bch_init_ctx(struct nand_device *nand)
 	nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx);
 	kfree(engine_conf->calc_buf);
 	kfree(engine_conf->code_buf);
+	kfree(engine_conf->oob_buf);
 free_engine_conf:
 	kfree(engine_conf);
 
@@ -283,6 +286,7 @@ void nand_ecc_sw_bch_cleanup_ctx(struct nand_device *nand)
 		nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx);
 		kfree(engine_conf->calc_buf);
 		kfree(engine_conf->code_buf);
+		kfree(engine_conf->oob_buf);
 		kfree(engine_conf);
 	}
 }
@@ -299,22 +303,42 @@ static int nand_ecc_sw_bch_prepare_io_req(struct nand_device *nand,
 	int total = nand->ecc.ctx.total;
 	u8 *ecccalc = engine_conf->calc_buf;
 	const u8 *data;
-	int i;
+	int i, ret = 0;
 
 	/* Nothing to do for a raw operation */
 	if (req->mode == MTD_OPS_RAW)
 		return 0;
 
-	/* This engine does not provide BBM/free OOB bytes protection */
-	if (!req->datalen)
-		return 0;
-
 	nand_ecc_tweak_req(&engine_conf->req_ctx, req);
 
 	/* No more preparation for page read */
 	if (req->type == NAND_PAGE_READ)
 		return 0;
 
+	if (req->ooblen) {
+		memset(engine_conf->oob_buf, 0xff,
+		       nanddev_per_page_oobsize(nand));
+
+		if (req->mode == MTD_OPS_AUTO_OOB) {
+			ret = mtd_ooblayout_set_databytes(mtd, req->oobbuf.out,
+							  engine_conf->oob_buf,
+							  req->ooboffs,
+							  mtd->oobavail);
+			if (ret)
+				return ret;
+		} else {
+			memcpy(engine_conf->oob_buf + req->ooboffs,
+			       req->oobbuf.out, req->ooblen);
+		}
+
+		engine_conf->src_oob_buf = (void *)req->oobbuf.out;
+		req->oobbuf.out = engine_conf->oob_buf;
+	}
+
+	/* This engine does not provide BBM/free OOB bytes protection */
+	if (!req->datalen)
+		return 0;
+
 	/* Preparation for page write: derive the ECC bytes and place them */
 	for (i = 0, data = req->databuf.out;
 	     eccsteps;
@@ -344,12 +368,36 @@ static int nand_ecc_sw_bch_finish_io_req(struct nand_device *nand,
 	if (req->mode == MTD_OPS_RAW)
 		return 0;
 
-	/* This engine does not provide BBM/free OOB bytes protection */
-	if (!req->datalen)
-		return 0;
-
 	/* No more preparation for page write */
 	if (req->type == NAND_PAGE_WRITE) {
+		if (req->ooblen)
+			req->oobbuf.out = engine_conf->src_oob_buf;
+
+		nand_ecc_restore_req(&engine_conf->req_ctx, req);
+		return 0;
+	}
+
+	if (req->ooblen) {
+		memset(engine_conf->oob_buf, 0xff,
+		       nanddev_per_page_oobsize(nand));
+
+		if (req->mode == MTD_OPS_AUTO_OOB) {
+			ret = mtd_ooblayout_get_databytes(mtd,
+							  engine_conf->oob_buf,
+							  req->oobbuf.in,
+							  req->ooboffs,
+							  mtd->oobavail);
+			if (ret)
+				return ret;
+		} else {
+			memcpy(engine_conf->oob_buf,
+			       req->oobbuf.in + req->ooboffs, req->ooblen);
+		}
+	}
+
+	/* This engine does not provide BBM/free OOB bytes protection */
+	if (!req->datalen) {
+		req->oobbuf.in = engine_conf->oob_buf;
 		nand_ecc_restore_req(&engine_conf->req_ctx, req);
 		return 0;
 	}
@@ -379,6 +427,9 @@ static int nand_ecc_sw_bch_finish_io_req(struct nand_device *nand,
 		}
 	}
 
+	if (req->ooblen)
+		req->oobbuf.in = engine_conf->oob_buf;
+
 	nand_ecc_restore_req(&engine_conf->req_ctx, req);
 
 	return max_bitflips;
diff --git a/drivers/mtd/nand/ecc-sw-hamming.c b/drivers/mtd/nand/ecc-sw-hamming.c
index 254db2e7f8bb..c90ff31e9656 100644
--- a/drivers/mtd/nand/ecc-sw-hamming.c
+++ b/drivers/mtd/nand/ecc-sw-hamming.c
@@ -507,7 +507,9 @@ int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand)
 	engine_conf->code_size = 3;
 	engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
 	engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
-	if (!engine_conf->calc_buf || !engine_conf->code_buf) {
+	engine_conf->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
+	if (!engine_conf->calc_buf || !engine_conf->code_buf ||
+	    !engine_conf->oob_buf) {
 		ret = -ENOMEM;
 		goto free_bufs;
 	}
@@ -522,6 +524,7 @@ int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand)
 	nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx);
 	kfree(engine_conf->calc_buf);
 	kfree(engine_conf->code_buf);
+	kfree(engine_conf->oob_buf);
 free_engine_conf:
 	kfree(engine_conf);
 
@@ -537,6 +540,7 @@ void nand_ecc_sw_hamming_cleanup_ctx(struct nand_device *nand)
 		nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx);
 		kfree(engine_conf->calc_buf);
 		kfree(engine_conf->code_buf);
+		kfree(engine_conf->oob_buf);
 		kfree(engine_conf);
 	}
 }
@@ -553,22 +557,42 @@ static int nand_ecc_sw_hamming_prepare_io_req(struct nand_device *nand,
 	int total = nand->ecc.ctx.total;
 	u8 *ecccalc = engine_conf->calc_buf;
 	const u8 *data;
-	int i;
+	int i, ret;
 
 	/* Nothing to do for a raw operation */
 	if (req->mode == MTD_OPS_RAW)
 		return 0;
 
-	/* This engine does not provide BBM/free OOB bytes protection */
-	if (!req->datalen)
-		return 0;
-
 	nand_ecc_tweak_req(&engine_conf->req_ctx, req);
 
 	/* No more preparation for page read */
 	if (req->type == NAND_PAGE_READ)
 		return 0;
 
+	if (req->ooblen) {
+		memset(engine_conf->oob_buf, 0xff,
+		       nanddev_per_page_oobsize(nand));
+
+		if (req->mode == MTD_OPS_AUTO_OOB) {
+			ret = mtd_ooblayout_set_databytes(mtd, req->oobbuf.out,
+							  engine_conf->oob_buf,
+							  req->ooboffs,
+							  mtd->oobavail);
+			if (ret)
+				return ret;
+		} else {
+			memcpy(engine_conf->oob_buf + req->ooboffs,
+			       req->oobbuf.out, req->ooblen);
+		}
+
+		engine_conf->src_oob_buf = (void *)req->oobbuf.out;
+		req->oobbuf.out = engine_conf->oob_buf;
+	}
+
+	/* This engine does not provide BBM/free OOB bytes protection */
+	if (!req->datalen)
+		return 0;
+
 	/* Preparation for page write: derive the ECC bytes and place them */
 	for (i = 0, data = req->databuf.out;
 	     eccsteps;
@@ -598,12 +622,36 @@ static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand,
 	if (req->mode == MTD_OPS_RAW)
 		return 0;
 
-	/* This engine does not provide BBM/free OOB bytes protection */
-	if (!req->datalen)
-		return 0;
-
 	/* No more preparation for page write */
 	if (req->type == NAND_PAGE_WRITE) {
+		if (req->ooblen)
+			req->oobbuf.out = engine_conf->src_oob_buf;
+
+		nand_ecc_restore_req(&engine_conf->req_ctx, req);
+		return 0;
+	}
+
+	if (req->ooblen) {
+		memset(engine_conf->oob_buf, 0xff,
+		       nanddev_per_page_oobsize(nand));
+
+		if (req->mode == MTD_OPS_AUTO_OOB) {
+			ret = mtd_ooblayout_get_databytes(mtd,
+							  engine_conf->oob_buf,
+							  req->oobbuf.in,
+							  req->ooboffs,
+							  mtd->oobavail);
+			if (ret)
+				return ret;
+		} else {
+			memcpy(engine_conf->oob_buf,
+			       req->oobbuf.in + req->ooboffs, req->ooblen);
+		}
+	}
+
+	/* This engine does not provide BBM/free OOB bytes protection */
+	if (!req->datalen) {
+		req->oobbuf.in = engine_conf->oob_buf;
 		nand_ecc_restore_req(&engine_conf->req_ctx, req);
 		return 0;
 	}
@@ -633,6 +681,9 @@ static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand,
 		}
 	}
 
+	if (req->ooblen)
+		req->oobbuf.in = engine_conf->oob_buf;
+
 	nand_ecc_restore_req(&engine_conf->req_ctx, req);
 
 	return max_bitflips;
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index c58f558302c4..9033036086f2 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -267,6 +267,12 @@ static int spinand_ondie_ecc_init_ctx(struct nand_device *nand)
 	if (!engine_conf)
 		return -ENOMEM;
 
+	engine_conf->oob_buf = kzalloc(nand->memorg.oobsize, GFP_KERNEL);
+	if (!engine_conf->oob_buf) {
+		kfree(engine_conf);
+		return -ENOMEM;
+	}
+
 	nand->ecc.ctx.priv = engine_conf;
 
 	if (spinand->eccinfo.ooblayout)
@@ -279,16 +285,40 @@ static int spinand_ondie_ecc_init_ctx(struct nand_device *nand)
 
 static void spinand_ondie_ecc_cleanup_ctx(struct nand_device *nand)
 {
-	kfree(nand->ecc.ctx.priv);
+	struct spinand_ondie_ecc_conf *engine_conf = nand->ecc.ctx.priv;
+
+	kfree(engine_conf->oob_buf);
+	kfree(engine_conf);
 }
 
 static int spinand_ondie_ecc_prepare_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);
+	struct mtd_info *mtd = spinand_to_mtd(spinand);
 	bool enable = (req->mode != MTD_OPS_RAW);
+	int ret;
 
-	memset(spinand->oobbuf, 0xff, nanddev_per_page_oobsize(nand));
+	if (req->ooblen && req->type == NAND_PAGE_WRITE) {
+		memset(engine_conf->oob_buf, 0xff,
+		       nanddev_per_page_oobsize(nand));
+
+		if (req->mode == MTD_OPS_AUTO_OOB) {
+			ret = mtd_ooblayout_set_databytes(mtd, req->oobbuf.out,
+							  engine_conf->oob_buf,
+							  req->ooboffs,
+							  mtd->oobavail);
+			if (ret)
+				return ret;
+		} else {
+			memcpy(engine_conf->oob_buf + req->ooboffs,
+			       req->oobbuf.out, req->ooblen);
+		}
+
+		engine_conf->src_oob_buf = (void *)req->oobbuf.out;
+		req->oobbuf.out = engine_conf->oob_buf;
+	}
 
 	/* Only enable or disable the engine */
 	return spinand_ecc_enable(spinand, enable);
@@ -306,8 +336,32 @@ static int spinand_ondie_ecc_finish_io_req(struct nand_device *nand,
 		return 0;
 
 	/* Nothing to do when finishing a page write */
-	if (req->type == NAND_PAGE_WRITE)
+	if (req->type == NAND_PAGE_WRITE) {
+		if (req->ooblen)
+			req->oobbuf.out = engine_conf->src_oob_buf;
+
 		return 0;
+	}
+
+	if (req->ooblen) {
+		memset(engine_conf->oob_buf, 0xff,
+		       nanddev_per_page_oobsize(nand));
+
+		if (req->mode == MTD_OPS_AUTO_OOB) {
+			ret = mtd_ooblayout_get_databytes(mtd,
+							  engine_conf->oob_buf,
+							  req->oobbuf.in,
+							  req->ooboffs,
+							  mtd->oobavail);
+			if (ret)
+				return ret;
+		} else {
+			memcpy(engine_conf->oob_buf,
+			       req->oobbuf.in + req->ooboffs, req->ooblen);
+		}
+
+		req->oobbuf.in = engine_conf->oob_buf;
+	}
 
 	/* Finish a page read: check the status, report errors/bitflips */
 	ret = spinand_check_ecc_status(spinand, engine_conf->status);
@@ -360,7 +414,6 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
 				      const struct nand_page_io_req *req)
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
-	struct mtd_info *mtd = spinand_to_mtd(spinand);
 	struct spi_mem_dirmap_desc *rdesc;
 	unsigned int nbytes = 0;
 	void *buf = NULL;
@@ -403,16 +456,9 @@ static int spinand_read_from_cache_op(struct spinand_device *spinand,
 		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);
-	}
+	if (req->ooblen)
+		memcpy(req->oobbuf.in, spinand->oobbuf + req->ooboffs,
+		       req->ooblen);
 
 	return 0;
 }
@@ -421,7 +467,6 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
 				     const struct nand_page_io_req *req)
 {
 	struct nand_device *nand = spinand_to_nand(spinand);
-	struct mtd_info *mtd = spinand_to_mtd(spinand);
 	struct spi_mem_dirmap_desc *wdesc;
 	unsigned int nbytes, column = 0;
 	void *buf = spinand->databuf;
@@ -433,27 +478,17 @@ static int spinand_write_to_cache_op(struct spinand_device *spinand,
 	 * 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, nanddev_page_size(nand));
+	memset(spinand->databuf, 0xff, nbytes);
 
 	if (req->datalen)
 		memcpy(spinand->databuf + req->dataoffs, req->databuf.out,
 		       req->datalen);
 
-	if (req->ooblen) {
-		if (req->mode == MTD_OPS_AUTO_OOB)
-			mtd_ooblayout_set_databytes(mtd, req->oobbuf.out,
-						    spinand->oobbuf,
-						    req->ooboffs,
-						    req->ooblen);
-		else
-			memcpy(spinand->oobbuf + req->ooboffs, req->oobbuf.out,
-			       req->ooblen);
-	}
+	if (req->ooblen)
+		memcpy(spinand->oobbuf + req->ooboffs, req->oobbuf.out,
+		       req->ooblen);
 
 	if (req->mode == MTD_OPS_RAW)
 		wdesc = spinand->dirmaps[req->pos.plane].wdesc;
diff --git a/include/linux/mtd/nand-ecc-sw-bch.h b/include/linux/mtd/nand-ecc-sw-bch.h
index 9da9969505a8..c4730badb77b 100644
--- a/include/linux/mtd/nand-ecc-sw-bch.h
+++ b/include/linux/mtd/nand-ecc-sw-bch.h
@@ -18,6 +18,8 @@
  * @code_size: Number of bytes needed to store a code (one code per step)
  * @calc_buf: Buffer to use when calculating ECC bytes
  * @code_buf: Buffer to use when reading (raw) ECC bytes from the chip
+ * @oob_buf: Buffer to use when handle the data in OOB area.
+ * @src_oob_buf: Pointer be used to store source OOB buffer pointer when write
  * @bch: BCH control structure
  * @errloc: error location array
  * @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
@@ -27,6 +29,8 @@ struct nand_ecc_sw_bch_conf {
 	unsigned int code_size;
 	u8 *calc_buf;
 	u8 *code_buf;
+	u8 *oob_buf;
+	void *src_oob_buf;
 	struct bch_control *bch;
 	unsigned int *errloc;
 	unsigned char *eccmask;
diff --git a/include/linux/mtd/nand-ecc-sw-hamming.h b/include/linux/mtd/nand-ecc-sw-hamming.h
index c6c71894c575..88788d53b911 100644
--- a/include/linux/mtd/nand-ecc-sw-hamming.h
+++ b/include/linux/mtd/nand-ecc-sw-hamming.h
@@ -19,6 +19,8 @@
  * @code_size: Number of bytes needed to store a code (one code per step)
  * @calc_buf: Buffer to use when calculating ECC bytes
  * @code_buf: Buffer to use when reading (raw) ECC bytes from the chip
+ * @oob_buf: Buffer to use when handle the data in OOB area.
+ * @src_oob_buf: Pointer be used to store source OOB buffer pointer when write
  * @sm_order: Smart Media special ordering
  */
 struct nand_ecc_sw_hamming_conf {
@@ -26,6 +28,8 @@ struct nand_ecc_sw_hamming_conf {
 	unsigned int code_size;
 	u8 *calc_buf;
 	u8 *code_buf;
+	u8 *oob_buf;
+	void *src_oob_buf;
 	unsigned int sm_order;
 };
 
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 3aa28240a77f..23b86941fbf6 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -312,9 +312,13 @@ struct spinand_ecc_info {
  * struct spinand_ondie_ecc_conf - private SPI-NAND on-die ECC engine structure
  * @status: status of the last wait operation that will be used in case
  *          ->get_status() is not populated by the spinand device.
+ * @oob_buf: Buffer to use when handle the data in OOB area.
+ * @src_oob_buf: Pointer be used to store source OOB buffer pointer when write
  */
 struct spinand_ondie_ecc_conf {
 	u8 status;
+	u8 *oob_buf;
+	void *src_oob_buf;
 };
 
 /**
