On Tue, Jul 25, 2017 at 12:30 PM, Wenyou Yang <wenyou.y...@microchip.com> wrote: > From: Cyrille Pitchen <cyrille.pitc...@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.pitc...@atmel.com> > Signed-off-by: Wenyou Yang <wenyou.y...@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! -- Jagan Teki Free Software Engineer | www.openedev.com U-Boot, Linux | Upstream Maintainer Hyderabad, India. _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot