diff mbox series

[U-Boot,v10,04/27] mtd: spi-nor: sync/modify sst write operations

Message ID 1514441553-27543-5-git-send-email-jagan@amarulasolutions.com
State Rejected
Delegated to: Tom Rini
Headers show
Series dm: Generic MTD Subsystem, with SPI-NOR interface | expand

Commit Message

Jagan Teki Dec. 28, 2017, 6:12 a.m. UTC
sst write operations can be changed based on the mode
set from the controller with byte program or word program,
so sync the similar code from legacy spi_flash.c and
update accordingly with mtd operations.

Signed-off-by: Suneel Garapati <suneelglinux@gmail.com>
Signed-off-by: Jagan Teki <jagan@amarulasolutions.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 115 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)
diff mbox series

Patch

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 09fb8ca..cfd21fb 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -316,6 +316,113 @@  int spi_nor_mread(struct udevice *dev, loff_t from, size_t len,
 	return ret;
 }
 
+#ifdef CONFIG_SPI_NOR_SST
+static int sst_byte_write(struct spi_nor *nor, u32 addr, const void *buf,
+			  size_t *retlen)
+{
+	const struct spi_nor_ops *ops = spi_nor_get_ops(nor->dev);
+	int ret;
+
+	ret = write_enable(nor->dev);
+	if (ret)
+		return ret;
+
+	nor->program_opcode = SNOR_OP_BP;
+
+	ret = ops->write(nor->dev, addr, 1, buf);
+	if (ret)
+		return ret;
+
+	*retlen += 1;
+
+	return spi_nor_wait_till_ready(nor->dev, SNOR_READY_WAIT_PROG);
+}
+
+static int sst_mwrite_wp(struct udevice *dev, loff_t to, size_t len,
+			 size_t *retlen, const u_char *buf)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	int devnum = mtd->devnum;
+	const struct spi_nor_ops *ops;
+	struct spi_nor *nor;
+	size_t actual;
+	int ret;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+	ops = spi_nor_get_ops(nor->dev);
+
+	/* If the data is not word aligned, write out leading single byte */
+	actual = to % 2;
+	if (actual) {
+		ret = sst_byte_write(nor, to, buf, retlen);
+		if (ret)
+			goto done;
+	}
+	to += actual;
+
+	ret = write_enable(nor->dev);
+	if (ret)
+		goto done;
+
+	for (; actual < len - 1; actual += 2) {
+		nor->program_opcode = SNOR_OP_AAI_WP;
+
+		ret = ops->write(nor->dev, to, 2, buf + actual);
+		if (ret) {
+			debug("spi-nor: sst word program failed\n");
+			break;
+		}
+
+		ret = spi_nor_wait_till_ready(nor->dev, SNOR_READY_WAIT_PROG);
+		if (ret)
+			break;
+
+		to += 2;
+		*retlen += 2;
+	}
+
+	if (!ret)
+		ret = write_disable(nor->dev);
+
+	/* If there is a single trailing byte, write it out */
+	if (!ret && actual != len)
+		ret = sst_byte_write(nor, to, buf + actual, retlen);
+
+ done:
+	return ret;
+}
+
+static int sst_mwrite_bp(struct udevice *dev, loff_t to, size_t len,
+			 size_t *retlen, const u_char *buf)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	int devnum = mtd->devnum;
+	struct spi_nor *nor;
+	size_t actual;
+	int ret;
+
+	nor = find_spi_nor_device(devnum);
+	if (!nor)
+		return -ENODEV;
+
+	for (actual = 0; actual < len; actual++) {
+		ret = sst_byte_write(nor, to, buf + actual, retlen);
+		if (ret) {
+			debug("spi-nor: sst byte program failed\n");
+			break;
+		}
+		to++;
+	}
+
+	if (!ret)
+		ret = write_disable(nor->dev);
+
+	return ret;
+}
+#endif
+
 #ifdef CONFIG_SPI_NOR_MACRONIX
 static int macronix_quad_enable(struct udevice *dev)
 {
@@ -482,6 +589,14 @@  int spi_nor_scan(struct spi_nor *nor)
 		nor->flags |= SNOR_F_SST_WRITE;
 
 	ops->write = spi_nor_mwrite;
+#if defined(CONFIG_SPI_NOR_SST)
+	if (nor->flags & SNOR_F_SST_WRITE) {
+		if (nor->mode & SNOR_WRITE_1_1_BYTE)
+			ops->write = sst_mwrite_bp;
+		else
+			ops->write = sst_mwrite_wp;
+	}
+#endif
 
 	/* compute the flash size */
 	nor->page_size = info->page_size;