diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index 5041d1b..263a2db 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -191,6 +191,75 @@ static int ts78xx_ts_nand_dev_ready(struct mtd_info *mtd)
 	return readb(TS_NAND_CTRL) & 0x20;
 }
 
+/*
+ * FPGA will handle 8/16/32bit reads and writes
+ */
+static void ts78xx_ts_nand_read_buf(struct mtd_info *mtd,
+			uint8_t *buf, int len)
+{
+	struct nand_chip *this = mtd->priv;
+
+	if (len % 2) {
+		*buf++ = readb(this->IO_ADDR_R);
+		len--;
+	}
+	if (len % 4 == 2) {
+		uint16_t *t = (uint16_t *) buf;
+		*t = readw(this->IO_ADDR_R);
+		buf += 2;
+		len -= 2;
+	}
+
+	while (len > 3) {
+		uint32_t *t = (uint32_t *) buf;
+		*t = readl(this->IO_ADDR_R);
+		buf += 4;
+		len -= 4;
+	}
+
+	if (len % 4 == 2) {
+		uint16_t *t = (uint16_t *) buf;
+		*t = readw(this->IO_ADDR_R);
+		buf += 2;
+		len -= 2;
+	}
+	if (len)
+		*buf = readb(this->IO_ADDR_R);
+}
+
+static void ts78xx_ts_nand_write_buf(struct mtd_info *mtd,
+			const uint8_t *buf, int len)
+{
+	struct nand_chip *this = mtd->priv;
+
+	if (len % 2) {
+		writeb(*buf++, this->IO_ADDR_W);
+		len--;
+	}
+	if (len % 4 == 2) {
+		uint16_t *t = (uint16_t *) buf;
+		writew(*t, this->IO_ADDR_W);
+		buf += 2;
+		len -= 2;
+	}
+
+	while (len > 3) {
+		uint32_t *t = (uint32_t *) buf;
+		writel(*t, this->IO_ADDR_W);
+		buf += 4;
+		len -= 4;
+	}
+
+	if (len % 4 == 2) {
+		uint16_t *t = (uint16_t *) buf;
+		writew(*t, this->IO_ADDR_W);
+		buf += 2;
+		len -= 2;
+	}
+	if (len)
+		writeb(*buf, this->IO_ADDR_W);
+}
+
 const char *ts_nand_part_probes[] = { "cmdlinepart", NULL };
 
 static struct mtd_partition ts78xx_ts_nand_parts[] = {
@@ -230,8 +299,10 @@ static struct platform_nand_data ts78xx_ts_nand_data = {
 		 * e6cf5df1838c28bb060ac45b5585e48e71bbc740 so now there is
 		 * no performance advantage to be had so we no longer bother
 		 */
-		.cmd_ctrl		= ts78xx_ts_nand_cmd_ctrl,
 		.dev_ready		= ts78xx_ts_nand_dev_ready,
+		.cmd_ctrl		= ts78xx_ts_nand_cmd_ctrl,
+		.read_buf		= ts78xx_ts_nand_read_buf,
+		.write_buf		= ts78xx_ts_nand_write_buf,
 	},
 };
 
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
index 86e1d08..4cdec46 100644
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -61,6 +61,8 @@ static int __devinit plat_nand_probe(struct platform_device *pdev)
 	data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
 	data->chip.dev_ready = pdata->ctrl.dev_ready;
 	data->chip.select_chip = pdata->ctrl.select_chip;
+	data->chip.write_buf = pdata->ctrl.write_buf;
+	data->chip.read_buf = pdata->ctrl.read_buf;
 	data->chip.chip_delay = pdata->chip.chip_delay;
 	data->chip.options |= pdata->chip.options;
 
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 7efb9be..0e35375 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -584,6 +584,8 @@ struct platform_nand_chip {
  * @select_chip:	platform specific chip select function
  * @cmd_ctrl:		platform specific function for controlling
  *			ALE/CLE/nCE. Also used to write command and address
+ * @write_buf:		platform specific function for write buffer
+ * @read_buf:		platform specific function for read buffer
  * @priv:		private data to transport driver specific settings
  *
  * All fields are optional and depend on the hardware driver requirements
@@ -594,6 +596,10 @@ struct platform_nand_ctrl {
 	void		(*select_chip)(struct mtd_info *mtd, int chip);
 	void		(*cmd_ctrl)(struct mtd_info *mtd, int dat,
 				    unsigned int ctrl);
+	void		(*write_buf)(struct mtd_info *mtd,
+				    const uint8_t *buf, int len);
+	void		(*read_buf)(struct mtd_info *mtd,
+				    uint8_t *buf, int len);
 	void		*priv;
 };

