[U-Boot] [PATCH 09/18] sf: add hooks to handle register read and write operations
Cyrille Pitchen
cyrille.pitchen at atmel.com
Tue Mar 15 19:12:31 CET 2016
This patch finalizes the split of internal register and memory data SPI
commands. Indeed some (Q)SPI controllers such as the Atmel QSPI controller
need to make the difference between register read/write SPI commands and
data read/write/erase SPI commands.
It follows an interface close to the one used by the spi-nor.c driver in
Linux:
- read_reg: read out the register
- write_reg: write data to the register
- read: read data from the SPI flash
- write: write data into the SPI flash
- erase: erase sectors of the SPI flash
Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
drivers/mtd/spi/sf-uclass.c | 11 +++++++
drivers/mtd/spi/sf_internal.h | 13 ++++++--
drivers/mtd/spi/sf_probe.c | 18 +++++++++++
drivers/mtd/spi/spi_flash.c | 70 ++++++++++++++++++++++++-------------------
include/spi_flash.h | 58 +++++++++++++++++++++++++++++++++++
5 files changed, 137 insertions(+), 33 deletions(-)
diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c
index 19de964e6121..ebae9b1edb15 100644
--- a/drivers/mtd/spi/sf-uclass.c
+++ b/drivers/mtd/spi/sf-uclass.c
@@ -13,6 +13,17 @@
DECLARE_GLOBAL_DATA_PTR;
+int spi_flash_read_reg_dm(struct udevice *dev, u8 opcode, size_t len, void *buf)
+{
+ return sf_get_ops(dev)->read_reg(dev, opcode, len, buf);
+}
+
+int spi_flash_write_reg_dm(struct udevice *dev, u8 opcode, size_t len,
+ const void *buf)
+{
+ return sf_get_ops(dev)->write_reg(dev, opcode, len, buf);
+}
+
int spi_flash_read_dm(struct udevice *dev, u32 offset, size_t len, void *buf)
{
return sf_get_ops(dev)->read(dev, offset, len, buf);
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 569863a31684..15a5fa9c2afd 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/compiler.h>
+#include <spi_flash.h>
/* Dual SPI flash memories - see SPI_COMM_DUAL_... */
enum spi_dual_flash {
@@ -185,13 +186,13 @@ int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len);
/* Enable writing on the SPI flash */
static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)
{
- return spi_flash_cmd(flash->spi, CMD_WRITE_ENABLE, NULL, 0);
+ return spi_flash_write_reg(flash, CMD_WRITE_ENABLE, 0, NULL);
}
/* Disable writing on the SPI flash */
static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
{
- return spi_flash_cmd(flash->spi, CMD_WRITE_DISABLE, NULL, 0);
+ return spi_flash_write_reg(flash, CMD_WRITE_DISABLE, 0, NULL);
}
/* Wait for Busy/Write in Progress flag to be cleared */
@@ -206,6 +207,10 @@ int spi_flash_wait_ready(struct spi_flash *flash);
int spi_flash_update_reg(struct spi_flash *flash, u8 opcode, size_t len,
const void *buf);
+/* Flash write register operation */
+int spi_flash_cmd_write_reg_ops(struct spi_flash *flash, u8 opcode, size_t len,
+ const void *buf);
+
/*
* Flash write operation, support all possible write commands.
* Write the requested data out breaking it up into multiple write
@@ -219,6 +224,10 @@ typedef int (*spi_flash_write_fn)(struct spi_flash *, u32, size_t,
int spi_flash_write_alg(struct spi_flash *flash, u32 offset, size_t len,
const void *buf, spi_flash_write_fn write_fn);
+/* Flash read register operation */
+int spi_flash_cmd_read_reg_ops(struct spi_flash *flash, u8 opcode, size_t len,
+ void *buf);
+
/* Flash read operation, support all possible read commands */
int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
size_t len, void *data);
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 7b296378d2be..fbd7d4740b51 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -111,6 +111,22 @@ void spi_flash_free(struct spi_flash *flash)
#else /* defined CONFIG_DM_SPI_FLASH */
+static int spi_flash_std_read_reg(struct udevice *dev, u8 opcode, size_t len,
+ void *buf)
+{
+ struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+ return spi_flash_cmd_read_reg_ops(flash, opcode, len, buf);
+}
+
+static int spi_flash_std_write_reg(struct udevice *dev, u8 opcode, size_t len,
+ const void *buf)
+{
+ struct spi_flash *flash = dev_get_uclass_priv(dev);
+
+ return spi_flash_cmd_write_reg_ops(flash, opcode, len, buf);
+}
+
static int spi_flash_std_read(struct udevice *dev, u32 offset, size_t len,
void *buf)
{
@@ -157,6 +173,8 @@ static int spi_flash_std_probe(struct udevice *dev)
}
static const struct dm_spi_flash_ops spi_flash_std_ops = {
+ .read_reg = spi_flash_std_read_reg,
+ .write_reg = spi_flash_std_write_reg,
.read = spi_flash_std_read,
.write = spi_flash_std_write,
.erase = spi_flash_std_erase,
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 4be99ea0b424..4f269eacc591 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -32,12 +32,9 @@ static void spi_flash_addr(u32 addr, u8 *cmd)
static int read_sr(struct spi_flash *flash, u8 *rs)
{
- struct spi_slave *spi = flash->spi;
int ret;
- u8 cmd;
- cmd = CMD_READ_STATUS;
- ret = spi_flash_cmd_read(spi, &cmd, 1, rs, 1);
+ ret = spi_flash_read_reg(flash, CMD_READ_STATUS, 1, rs);
if (ret < 0) {
debug("SF: fail to read status register\n");
return ret;
@@ -48,11 +45,9 @@ static int read_sr(struct spi_flash *flash, u8 *rs)
static int read_fsr(struct spi_flash *flash, u8 *fsr)
{
- struct spi_slave *spi = flash->spi;
int ret;
- const u8 cmd = CMD_FLAG_STATUS;
- ret = spi_flash_cmd_read(spi, &cmd, 1, fsr, 1);
+ ret = spi_flash_read_reg(flash, CMD_FLAG_STATUS, 1, fsr);
if (ret < 0) {
debug("SF: fail to read flag status register\n");
return ret;
@@ -77,12 +72,9 @@ static int write_sr(struct spi_flash *flash, u8 ws)
#if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND)
static int read_cr(struct spi_flash *flash, u8 *rc)
{
- struct spi_slave *spi = flash->spi;
int ret;
- u8 cmd;
- cmd = CMD_READ_CONFIG;
- ret = spi_flash_cmd_read(spi, &cmd, 1, rc, 1);
+ ret = spi_flash_read_reg(flash, CMD_READ_CONFIG, 1, rc);
if (ret < 0) {
debug("SF: fail to read config register\n");
return ret;
@@ -134,7 +126,6 @@ bar_end:
static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0)
{
- struct spi_slave *spi = flash->spi;
u8 curr_bank = 0;
int ret;
@@ -151,7 +142,7 @@ static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0)
flash->bank_write_cmd = CMD_EXTNADDR_WREAR;
}
- ret = spi_flash_cmd_read(spi, &flash->bank_read_cmd, 1, &curr_bank, 1);
+ ret = spi_flash_read_reg(flash, flash->bank_read_cmd, &curr_bank, 1);
if (ret) {
debug("SF: fail to read bank addr register\n");
return ret;
@@ -257,7 +248,6 @@ int spi_flash_wait_ready(struct spi_flash *flash)
int spi_flash_update_reg(struct spi_flash *flash, u8 opcode,
size_t len, const void *buf)
{
- struct spi_slave *spi = flash->spi;
int ret;
ret = spi_flash_cmd_write_enable(flash);
@@ -266,7 +256,7 @@ int spi_flash_update_reg(struct spi_flash *flash, u8 opcode,
return ret;
}
- ret = spi_flash_cmd_write(spi, &opcode, 1, buf, len);
+ ret = spi_flash_write_reg(flash, opcode, len, buf);
if (ret < 0) {
debug("SF: write cmd failed\n");
return ret;
@@ -281,6 +271,14 @@ int spi_flash_update_reg(struct spi_flash *flash, u8 opcode,
return 0;
}
+int spi_flash_cmd_write_reg_ops(struct spi_flash *flash, u8 opcode, size_t len,
+ const void *buf)
+{
+ struct spi_slave *spi = flash->spi;
+
+ return spi_flash_cmd_write(spi, &opcode, 1, buf, len);
+}
+
int spi_flash_erase_alg(struct spi_flash *flash, u32 offset, size_t len,
spi_flash_erase_fn erase_fn)
{
@@ -460,6 +458,14 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
spi_flash_write_impl);
}
+int spi_flash_cmd_read_reg_ops(struct spi_flash *flash, u8 opcode,
+ size_t len, void *buf)
+{
+ struct spi_slave *spi = flash->spi;
+
+ return spi_flash_cmd_read(spi, &opcode, 1, buf, len);
+}
+
/*
* TODO: remove the weak after all the other spi_flash_copy_mmap
* implementations removed from drivers
@@ -982,8 +988,25 @@ int spi_flash_scan(struct spi_flash *flash)
CMD_READ_DUAL_IO_FAST,
CMD_READ_QUAD_IO_FAST };
+ /* Assign spi_flash ops */
+#ifndef CONFIG_DM_SPI_FLASH
+ flash->read_reg = spi_flash_cmd_read_reg_ops;
+ flash->write_reg = spi_flash_cmd_write_reg_ops;
+ flash->write = spi_flash_cmd_write_ops;
+#if defined(CONFIG_SPI_FLASH_SST)
+ if (flash->flags & SNOR_F_SST_WR) {
+ if (spi->mode & SPI_TX_BYTE)
+ flash->write = sst_write_bp;
+ else
+ flash->write = sst_write_wp;
+ }
+#endif
+ flash->erase = spi_flash_cmd_erase_ops;
+ flash->read = spi_flash_cmd_read_ops;
+#endif
+
/* Read the ID codes */
- ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
+ ret = spi_flash_read_reg(flash, CMD_READ_ID, sizeof(idcode), idcode);
if (ret) {
printf("SF: Failed to get idcodes\n");
return ret;
@@ -1032,21 +1055,6 @@ int spi_flash_scan(struct spi_flash *flash)
if (params->flags & SST_WR)
flash->flags |= SNOR_F_SST_WR;
- /* Assign spi_flash ops */
-#ifndef CONFIG_DM_SPI_FLASH
- flash->write = spi_flash_cmd_write_ops;
-#if defined(CONFIG_SPI_FLASH_SST)
- if (flash->flags & SNOR_F_SST_WR) {
- if (spi->mode & SPI_TX_BYTE)
- flash->write = sst_write_bp;
- else
- flash->write = sst_write_wp;
- }
-#endif
- flash->erase = spi_flash_cmd_erase_ops;
- flash->read = spi_flash_cmd_read_ops;
-#endif
-
/* lock hooks are flash specific - assign them based on idcode0 */
switch (idcode[0]) {
#if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST)
diff --git a/include/spi_flash.h b/include/spi_flash.h
index d0ce9e721ad0..31d11e55571d 100644
--- a/include/spi_flash.h
+++ b/include/spi_flash.h
@@ -52,6 +52,9 @@ struct spi_slave;
* @flash_lock: lock a region of the SPI Flash
* @flash_unlock: unlock a region of the SPI Flash
* @flash_is_locked: check if a region of the SPI Flash is completely locked
+ * @read_reg: Flash read_reg ops: Send cmd to read len bytes into buf
+ * @write_reg: Flash write_reg ops: Send cmd to write len bytes from
+ * buf
* @read: Flash read ops: Read len bytes at offset into buf
* Supported cmds: Fast Array Read
* @write: Flash write ops: Write len bytes from buf into offset
@@ -101,6 +104,10 @@ struct spi_flash {
* if required, perhaps with a way of scanning through the list to
* find the driver that matches the device.
*/
+ int (*read_reg)(struct spi_flash *flash, u8 opcode, size_t len,
+ void *buf);
+ int (*write_reg)(struct spi_flash *flash, u8 opcode, size_t len,
+ const void *buf);
int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);
int (*write)(struct spi_flash *flash, u32 offset, size_t len,
const void *buf);
@@ -109,6 +116,9 @@ struct spi_flash {
};
struct dm_spi_flash_ops {
+ int (*read_reg)(struct udevice *dev, u8 opcode, size_t len, void *buf);
+ int (*write_reg)(struct udevice *dev, u8 opcode, size_t len,
+ const void *buf);
int (*read)(struct udevice *dev, u32 offset, size_t len, void *buf);
int (*write)(struct udevice *dev, u32 offset, size_t len,
const void *buf);
@@ -120,6 +130,30 @@ struct dm_spi_flash_ops {
#ifdef CONFIG_DM_SPI_FLASH
/**
+ * spi_flash_read_reg_dm() - Send register command and read data result
+ *
+ * @dev: SPI flash device
+ * @opcode: Register command op code
+ * @len: Number of bytes to read as register command output
+ * @buf: Buffer to fill with the register command output
+ * @return 0 if OK, -ve on error
+ */
+int spi_flash_read_reg_dm(struct udevice *dev, u8 opcode, size_t len,
+ void *buf);
+
+/**
+ * spi_flash_write_reg_dm() - Send register command with data
+ *
+ * @dev: SPI flash device
+ * @opcode: Register command op code
+ * @len: Number of bytes to write as register command input
+ * @buf: Buffer filled with the register command input
+ * @return 0 if OK, -ve on error
+ */
+int spi_flash_write_reg_dm(struct udevice *dev, u8 opcode, size_t len,
+ const void *buf);
+
+/**
* spi_flash_read_dm() - Read data from SPI flash
*
* @dev: SPI flash device
@@ -165,6 +199,18 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
/* Compatibility function - this is the old U-Boot API */
void spi_flash_free(struct spi_flash *flash);
+static inline int spi_flash_read_reg(struct spi_flash *flash, u8 opcode,
+ size_t len, void *buf)
+{
+ return spi_flash_read_reg_dm(flash->dev, opcode, len, buf);
+}
+
+static inline int spi_flash_write_reg(struct spi_flash *flash, u8 opcode,
+ size_t len, const void *buf)
+{
+ return spi_flash_write_reg_dm(flash->dev, opcode, len, buf);
+}
+
static inline int spi_flash_read(struct spi_flash *flash, u32 offset,
size_t len, void *buf)
{
@@ -208,6 +254,18 @@ struct spi_flash *spi_flash_probe_fdt(const void *blob, int slave_node,
void spi_flash_free(struct spi_flash *flash);
+static inline int spi_flash_read_reg(struct spi_flash *flash, u8 opcode,
+ size_t len, void *buf)
+{
+ return flash->read_reg(flash, opcode, len, buf);
+}
+
+static inline int spi_flash_write_reg(struct spi_flash *flash, u8 opcode,
+ size_t len, const void *buf)
+{
+ return flash->write_reg(flash, opcode, len, buf);
+}
+
static inline int spi_flash_read(struct spi_flash *flash, u32 offset,
size_t len, void *buf)
{
--
1.8.2.2
More information about the U-Boot
mailing list