
On Tue, Jul 25, 2017 at 12:30 PM, Wenyou Yang wenyou.yang@microchip.com wrote:
From: Cyrille Pitchen cyrille.pitchen@atmel.com
Now that the SPI sub-system API has been extended with 'struct spi_flash_command' and spi_is_flash_command_supported() / spi_exec_flash_command() functions, we update the SPI FLASH sub-system to use this new API.
Signed-off-by: Cyrille Pitchen cyrille.pitchen@atmel.com Signed-off-by: Wenyou Yang wenyou.yang@microchip.com
Changes in v3: None Changes in v2: None
drivers/mtd/spi/sf.c | 78 +++++++++++++---- drivers/mtd/spi/sf_dataflash.c | 119 +++++++++++++------------- drivers/mtd/spi/sf_internal.h | 24 +++--- drivers/mtd/spi/spi_flash.c | 184 +++++++++++++++++++++++------------------ 4 files changed, 236 insertions(+), 169 deletions(-)
diff --git a/drivers/mtd/spi/sf.c b/drivers/mtd/spi/sf.c index d5e175ca00..6178b0aa98 100644 --- a/drivers/mtd/spi/sf.c +++ b/drivers/mtd/spi/sf.c @@ -9,46 +9,88 @@
#include <common.h> #include <spi.h> +#include <spi_flash.h>
-static int spi_flash_read_write(struct spi_slave *spi,
const u8 *cmd, size_t cmd_len,
const u8 *data_out, u8 *data_in,
size_t data_len)
+#include "sf_internal.h"
+static void spi_flash_addr(u32 addr, u8 addr_len, u8 *cmd_buf) {
u8 i;
for (i = 0; i < addr_len; i++)
cmd_buf[i] = addr >> ((addr_len - 1 - i) * 8);
+}
+static u8 spi_compute_num_dummy_bytes(enum spi_flash_protocol proto,
u8 num_dummy_clock_cycles)
+{
int shift = fls(spi_flash_protocol_get_addr_nbits(proto)) - 1;
if (shift < 0)
shift = 0;
return (num_dummy_clock_cycles << shift) >> 3;
+}
+static int spi_flash_exec(struct spi_flash *flash,
const struct spi_flash_command *cmd)
+{
struct spi_slave *spi = flash->spi;
u8 cmd_buf[SPI_FLASH_CMD_LEN];
size_t cmd_len, num_dummy_bytes; unsigned long flags = SPI_XFER_BEGIN; int ret;
if (data_len == 0)
if (spi_is_flash_command_supported(spi, cmd))
return spi_exec_flash_command(spi, cmd);
if (cmd->data_len == 0) flags |= SPI_XFER_END;
ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
cmd_buf[0] = cmd->inst;
spi_flash_addr(cmd->addr, cmd->addr_len, cmd_buf + 1);
cmd_len = 1 + cmd->addr_len;
num_dummy_bytes = spi_compute_num_dummy_bytes(cmd->proto,
cmd->num_mode_cycles +
cmd->num_wait_states);
memset(cmd_buf + cmd_len, 0xff, num_dummy_bytes);
cmd_len += num_dummy_bytes;
ret = spi_xfer(spi, cmd_len * 8, cmd_buf, NULL, flags); if (ret) { debug("SF: Failed to send command (%zu bytes): %d\n", cmd_len, ret);
} else if (data_len != 0) {
ret = spi_xfer(spi, data_len * 8, data_out, data_in,
SPI_XFER_END);
} else if (cmd->data_len != 0) {
ret = spi_xfer(spi, cmd->data_len * 8,
cmd->tx_data, cmd->rx_data,
SPI_XFER_END); if (ret) debug("SF: Failed to transfer %zu bytes of data: %d\n",
data_len, ret);
cmd->data_len, ret); } return ret;
}
-int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
size_t cmd_len, void *data, size_t data_len)
+int spi_flash_cmd_read(struct spi_flash *flash,
const struct spi_flash_command *cmd)
{
return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len);
return spi_flash_exec(flash, cmd);
}
-int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) +int spi_flash_cmd(struct spi_flash *flash, u8 instr, void *response, size_t len) {
return spi_flash_cmd_read(spi, &cmd, 1, response, len);
struct spi_flash_command cmd;
u8 flags = (response && len) ? SPI_FCMD_READ_REG : SPI_FCMD_WRITE_REG;
spi_flash_command_init(&cmd, instr, 0, flags);
cmd.data_len = len;
cmd.rx_data = response;
return spi_flash_exec(flash, &cmd);
}
-int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
const void *data, size_t data_len)
+int spi_flash_cmd_write(struct spi_flash *flash,
const struct spi_flash_command *cmd)
{
return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len);
return spi_flash_exec(flash, cmd);
} diff --git a/drivers/mtd/spi/sf_dataflash.c b/drivers/mtd/spi/sf_dataflash.c index bcddfa0755..b2166ad4e5 100644 --- a/drivers/mtd/spi/sf_dataflash.c +++ b/drivers/mtd/spi/sf_dataflash.c @@ -73,7 +73,7 @@ struct dataflash { };
/* Return the status of the DataFlash device */ -static inline int dataflash_status(struct spi_slave *spi) +static inline int dataflash_status(struct spi_flash *spi_flash) { int ret; u8 status; @@ -81,7 +81,7 @@ static inline int dataflash_status(struct spi_slave *spi) * NOTE: at45db321c over 25 MHz wants to write * a dummy byte after the opcode... */
ret = spi_flash_cmd(spi, OP_READ_STATUS, &status, 1);
ret = spi_flash_cmd(spi_flash, OP_READ_STATUS, &status, 1); return ret ? -EIO : status;
}
@@ -90,7 +90,7 @@ static inline int dataflash_status(struct spi_slave *spi)
- This usually takes 5-20 msec or so; more for sector erase.
- ready: return > 0
*/ -static int dataflash_waitready(struct spi_slave *spi) +static int dataflash_waitready(struct spi_flash *spi_flash) { int status; int timeout = 2 * CONFIG_SYS_HZ; @@ -98,7 +98,7 @@ static int dataflash_waitready(struct spi_slave *spi)
timebase = get_timer(0); do {
status = dataflash_status(spi);
status = dataflash_status(spi_flash); if (status < 0) status = 0;
@@ -114,11 +114,11 @@ static int dataflash_waitready(struct spi_slave *spi) /* Erase pages of flash */ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len) {
struct spi_flash_command cmd; struct dataflash *dataflash; struct spi_flash *spi_flash; struct spi_slave *spi; unsigned blocksize;
uint8_t *command; uint32_t rem; int status;
@@ -128,9 +128,6 @@ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len)
blocksize = spi_flash->page_size << 3;
memset(dataflash->command, 0 , sizeof(dataflash->command));
command = dataflash->command;
debug("%s: erase addr=0x%x len 0x%x\n", dev->name, offset, len); div_u64_rem(len, spi_flash->page_size, &rem);
@@ -146,6 +143,8 @@ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len) return status; }
spi_flash_command_init(&cmd, OP_ERASE_BLOCK, SPI_FLASH_3B_ADDR_LEN,
SPI_FCMD_ERASE); while (len > 0) { unsigned int pageaddr; int do_block;
@@ -157,23 +156,24 @@ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len) do_block = (pageaddr & 0x7) == 0 && len >= blocksize; pageaddr = pageaddr << dataflash->page_offset;
command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE;
command[1] = (uint8_t)(pageaddr >> 16);
command[2] = (uint8_t)(pageaddr >> 8);
command[3] = 0;
cmd.inst = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE;
cmd.addr = pageaddr & 0x00FFFF00; debug("%s ERASE %s: (%x) %x %x %x [%d]\n", dev->name, do_block ? "block" : "page",
command[0], command[1], command[2], command[3],
cmd.inst,
(cmd.addr >> 16) & 0xff,
(cmd.addr >> 8) & 0xff,
(cmd.addr >> 0) & 0xff, pageaddr);
status = spi_flash_cmd_write(spi, command, 4, NULL, 0);
status = spi_flash_cmd_write(spi_flash, &cmd); if (status < 0) { debug("%s: erase send command error!\n", dev->name); return -EIO; }
status = dataflash_waitready(spi);
status = dataflash_waitready(spi_flash); if (status < 0) { debug("%s: erase waitready error!\n", dev->name); return status;
@@ -202,23 +202,18 @@ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len) static int spi_dataflash_read(struct udevice *dev, u32 offset, size_t len, void *buf) {
struct spi_flash_command cmd; struct dataflash *dataflash; struct spi_flash *spi_flash; struct spi_slave *spi; unsigned int addr;
uint8_t *command; int status; dataflash = dev_get_priv(dev); spi_flash = dev_get_uclass_priv(dev); spi = spi_flash->spi;
memset(dataflash->command, 0 , sizeof(dataflash->command));
command = dataflash->command;
debug("%s: erase addr=0x%x len 0x%x\n", dev->name, offset, len);
debug("READ: (%x) %x %x %x\n",
command[0], command[1], command[2], command[3]);
debug("%s: read addr=0x%x len 0x%x\n", dev->name, offset, len); /* Calculate flash page/byte address */ addr = (((unsigned)offset / spi_flash->page_size)
@@ -236,13 +231,15 @@ static int spi_dataflash_read(struct udevice *dev, u32 offset, size_t len, * the peak rate available. Some chips support commands with * fewer "don't care" bytes. Both buffers stay unchanged. */
command[0] = OP_READ_CONTINUOUS;
command[1] = (uint8_t)(addr >> 16);
command[2] = (uint8_t)(addr >> 8);
command[3] = (uint8_t)(addr >> 0);
spi_flash_command_init(&cmd, OP_READ_CONTINUOUS, SPI_FLASH_3B_ADDR_LEN,
SPI_FCMD_READ);
cmd.addr = addr;
cmd.num_wait_states = 4 * 8; /* 4 "don't care" bytes */
cmd.data_len = len;
cmd.rx_data = buf; /* plus 4 "don't care" bytes, command len: 4 + 4 "don't care" bytes */
status = spi_flash_cmd_read(spi, command, 8, buf, len);
status = spi_flash_cmd_read(spi_flash, &cmd); spi_release_bus(spi);
@@ -258,10 +255,10 @@ static int spi_dataflash_read(struct udevice *dev, u32 offset, size_t len, int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len, const void *buf) {
struct spi_flash_command cmd; struct dataflash *dataflash; struct spi_flash *spi_flash; struct spi_slave *spi;
uint8_t *command; unsigned int pageaddr, addr, to, writelen; size_t remaining = len; u_char *writebuf = (u_char *)buf;
@@ -271,9 +268,6 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len, spi_flash = dev_get_uclass_priv(dev); spi = spi_flash->spi;
memset(dataflash->command, 0 , sizeof(dataflash->command));
command = dataflash->command;
debug("%s: write 0x%x..0x%x\n", dev->name, offset, (offset + len)); pageaddr = ((unsigned)offset / spi_flash->page_size);
@@ -289,6 +283,8 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len, return status; }
spi_flash_command_init(&cmd, OP_TRANSFER_BUF1, SPI_FLASH_3B_ADDR_LEN,
SPI_FCMD_WRITE); while (remaining > 0) { debug("write @ %d:%d len=%d\n", pageaddr, to, writelen);
@@ -313,22 +309,25 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len,
/* (1) Maybe transfer partial page to Buffer1 */ if (writelen != spi_flash->page_size) {
command[0] = OP_TRANSFER_BUF1;
command[1] = (addr & 0x00FF0000) >> 16;
command[2] = (addr & 0x0000FF00) >> 8;
command[3] = 0;
cmd.inst = OP_TRANSFER_BUF1;
cmd.addr = (addr & 0x00FFFF00);
cmd.data_len = 0;
cmd.tx_data = NULL; debug("TRANSFER: (%x) %x %x %x\n",
command[0], command[1], command[2], command[3]);
cmd.inst,
(cmd.addr >> 16) & 0xff,
(cmd.addr >> 8) & 0xff,
(cmd.addr >> 0) & 0xff);
status = spi_flash_cmd_write(spi, command, 4, NULL, 0);
status = spi_flash_cmd_write(spi_flash, &cmd); if (status < 0) { debug("%s: write(<pagesize) command error!\n", dev->name); return -EIO; }
status = dataflash_waitready(spi);
status = dataflash_waitready(spi_flash); if (status < 0) { debug("%s: write(<pagesize) waitready error!\n", dev->name);
@@ -338,22 +337,24 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len,
/* (2) Program full page via Buffer1 */ addr += to;
command[0] = OP_PROGRAM_VIA_BUF1;
command[1] = (addr & 0x00FF0000) >> 16;
command[2] = (addr & 0x0000FF00) >> 8;
command[3] = (addr & 0x000000FF);
cmd.inst = OP_PROGRAM_VIA_BUF1;
cmd.addr = addr;
cmd.data_len = writelen;
cmd.tx_data = writebuf; debug("PROGRAM: (%x) %x %x %x\n",
command[0], command[1], command[2], command[3]);
cmd.inst,
(cmd.addr >> 16) & 0xff,
(cmd.addr >> 8) & 0xff,
(cmd.addr >> 0) & 0xff);
status = spi_flash_cmd_write(spi, command,
4, writebuf, writelen);
status = spi_flash_cmd_write(spi_flash, &cmd); if (status < 0) { debug("%s: write send command error!\n", dev->name); return -EIO; }
status = dataflash_waitready(spi);
status = dataflash_waitready(spi_flash); if (status < 0) { debug("%s: write waitready error!\n", dev->name); return status;
@@ -362,16 +363,18 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len, #ifdef CONFIG_SPI_DATAFLASH_WRITE_VERIFY /* (3) Compare to Buffer1 */ addr = pageaddr << dataflash->page_offset;
command[0] = OP_COMPARE_BUF1;
command[1] = (addr & 0x00FF0000) >> 16;
command[2] = (addr & 0x0000FF00) >> 8;
command[3] = 0;
cmd.inst = OP_COMPARE_BUF1;
cmd.addr = addr & 0x00FFFF00;
cmd.data_len = writelen;
cmd.tx_data = writebuf; debug("COMPARE: (%x) %x %x %x\n",
command[0], command[1], command[2], command[3]);
cmd.inst,
(cmd.addr >> 16) & 0xff,
(cmd.addr >> 8) & 0xff,
(cmd.addr >> 0) & 0xff);
status = spi_flash_cmd_write(spi, command,
4, writebuf, writelen);
status = spi_flash_cmd_write(spi, &cmd); if (status < 0) { debug("%s: write(compare) send command error!\n", dev->name);
@@ -496,7 +499,7 @@ static struct flash_info dataflash_data[] = { { "at45db642d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS}, };
-static struct flash_info *jedec_probe(struct spi_slave *spi) +static struct flash_info *jedec_probe(struct spi_flash *spi_flash) { int tmp; uint8_t id[5]; @@ -513,7 +516,7 @@ static struct flash_info *jedec_probe(struct spi_slave *spi) * That's not an error; only rev C and newer chips handle it, and * only Atmel sells these chips. */
tmp = spi_flash_cmd(spi, CMD_READ_ID, id, sizeof(id));
tmp = spi_flash_cmd(spi_flash, CMD_READ_ID, id, sizeof(id)); if (tmp < 0) { printf("dataflash: error %d reading JEDEC ID\n", tmp); return ERR_PTR(tmp);
@@ -532,7 +535,7 @@ static struct flash_info *jedec_probe(struct spi_slave *spi) tmp++, info++) { if (info->jedec_id == jedec) { if (info->flags & SUP_POW2PS) {
status = dataflash_status(spi);
status = dataflash_status(spi_flash); if (status < 0) { debug("dataflash: status error %d\n", status);
@@ -596,7 +599,7 @@ static int spi_dataflash_probe(struct udevice *dev) * Both support the security register, though with different * write procedures. */
info = jedec_probe(spi);
info = jedec_probe(spi_flash); if (IS_ERR(info)) goto err_jedec_probe; if (info != NULL) {
@@ -611,7 +614,7 @@ static int spi_dataflash_probe(struct udevice *dev) * Older chips support only legacy commands, identifing * capacity using bits in the status byte. */
status = dataflash_status(spi);
status = dataflash_status(spi_flash); if (status <= 0 || status == 0xff) { printf("dataflash: read status error %d\n", status); if (status == 0 || status == 0xff)
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 839cdbe1b0..5c551089d6 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -27,7 +27,7 @@ enum spi_nor_option_flags { };
#define SPI_FLASH_3B_ADDR_LEN 3 -#define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN) +#define SPI_FLASH_CMD_LEN (1 + SPI_FLASH_3B_ADDR_LEN + 16) #define SPI_FLASH_16MB_BOUN 0x1000000
/* CFI Manufacture ID's */ @@ -137,21 +137,21 @@ struct spi_flash_info { extern const struct spi_flash_info spi_flash_ids[];
/* Send a single-byte command to the device and read the response */ -int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); +int spi_flash_cmd(struct spi_flash *flash, u8 instr, void *response, size_t len);
/*
- Send a multi-byte command to the device and read the response. Used
- for flash array reads, etc.
*/ -int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
size_t cmd_len, void *data, size_t data_len);
+int spi_flash_cmd_read(struct spi_flash *flash,
const struct spi_flash_command *cmd);
/*
- Send a multi-byte command to the device followed by (optional)
- data. Used for programming the flash array, etc.
*/ -int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
const void *data, size_t data_len);
+int spi_flash_cmd_write(struct spi_flash *flash,
const struct spi_flash_command *cmd);
/* Flash erase(sectors) operation, support all possible erase commands */ @@ -169,13 +169,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_cmd(flash, CMD_WRITE_ENABLE, NULL, 0);
}
/* 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_cmd(flash, CMD_WRITE_DISABLE, NULL, 0);
}
/* @@ -186,8 +186,8 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash)
- spi_flash_wait_till_ready
- SPI release
*/ -int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd,
size_t cmd_len, const void *buf, size_t buf_len);
+int spi_flash_write_common(struct spi_flash *flash,
const struct spi_flash_command *cmd);
/*
- Flash write operation, support all possible write commands.
@@ -201,8 +201,8 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset,
- Same as spi_flash_cmd_read() except it also claims/releases the SPI
- bus. Used as common part of the ->read() operation.
*/ -int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
size_t cmd_len, void *data, size_t data_len);
+int spi_flash_read_common(struct spi_flash *flash,
const struct spi_flash_command *cmd);
/* Flash read operation, support all possible read commands */ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 0034a28d5f..80541d0ab4 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -22,21 +22,15 @@
DECLARE_GLOBAL_DATA_PTR;
-static void spi_flash_addr(u32 addr, u8 *cmd) -{
/* cmd[0] is actual command */
cmd[1] = addr >> 16;
cmd[2] = addr >> 8;
cmd[3] = addr >> 0;
-}
static int read_sr(struct spi_flash *flash, u8 *rs) {
struct spi_flash_command cmd; int ret;
u8 cmd;
cmd = CMD_READ_STATUS;
ret = spi_flash_read_common(flash, &cmd, 1, rs, 1);
spi_flash_command_init(&cmd, CMD_READ_STATUS, 0, SPI_FCMD_READ_REG);
cmd.data_len = 1;
cmd.rx_data = rs;
Better to do these command initialization in sf.c just before the transfer initiate instead of doing it for each I/O operation.
thanks!