From 07a5cb9d3b9bf9bca9ca207b82f92eac73cbdda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Beh=C3=BAn?= Date: Tue, 23 Jul 2019 16:49:32 +0200 Subject: spi: mvebu_a3700_spi: Fix clock prescale computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prescaler value computation can yield wrong result if given 0x1f at the beginning: the value is computed to be 0x20, but the maximum value the register can hold 0x1f, so the actual stored value in this case is 0, which is obviously wrong. Set the upper bound of the value to 0x1f with the min macro. Signed-off-by: Marek BehĂșn Reviewed-by: Stefan Roese Reviewed-by: Jagan Teki --- drivers/spi/mvebu_a3700_spi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/mvebu_a3700_spi.c b/drivers/spi/mvebu_a3700_spi.c index feeafdceaa..99ad505f24 100644 --- a/drivers/spi/mvebu_a3700_spi.c +++ b/drivers/spi/mvebu_a3700_spi.c @@ -181,10 +181,9 @@ static int mvebu_spi_set_speed(struct udevice *bus, uint hz) data = readl(®->cfg); prescale = DIV_ROUND_UP(clk_get_rate(&plat->clk), hz); - if (prescale > 0x1f) - prescale = 0x1f; - else if (prescale > 0xf) + if (prescale > 0xf) prescale = 0x10 + (prescale + 1) / 2; + prescale = min(prescale, 0x1fu); data &= ~MVEBU_SPI_A3700_CLK_PRESCALE_MASK; data |= prescale & MVEBU_SPI_A3700_CLK_PRESCALE_MASK; -- cgit v1.2.1 From dfe72d081d4eda0c0788dc5db69de3abbec1b857 Mon Sep 17 00:00:00 2001 From: Christophe Kerello Date: Fri, 2 Aug 2019 15:46:29 +0200 Subject: spi: soft_spi: Fix data abort if slave is not probed In case spi_get_bus_and_cs callback is used, spi bus is first probed then slave devices are probed. To avoid a data abort in soft_spi probe function, we need to check that (slave != NULL). If slave is NULL, cs_flags and clk_flags will be initialized with respectively GPIOD_ACTIVE_LOW and 0. Signed-off-by: Christophe Kerello Signed-off-by: Patrice Chotard Reviewed-by: Jagan Teki --- drivers/spi/soft_spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c index b06883f9d0..b80f810bd1 100644 --- a/drivers/spi/soft_spi.c +++ b/drivers/spi/soft_spi.c @@ -215,8 +215,8 @@ static int soft_spi_probe(struct udevice *dev) int cs_flags, clk_flags; int ret; - cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW; - clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0; + cs_flags = (slave && slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW; + clk_flags = (slave && slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0; if (gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs, GPIOD_IS_OUT | cs_flags) || -- cgit v1.2.1 From 6bd6c21693547f1887b516bee11481e95e239ecb Mon Sep 17 00:00:00 2001 From: Lukasz Majewski Date: Thu, 1 Aug 2019 17:56:44 +0200 Subject: spi: Kconfig: Unmark DEPRECATED for MXS_SPI MXS_SPI driver now partially converted into driver-model, so unmark the DEPRECATED option for the same. Signed-off-by: Lukasz Majewski [jagan: update the commit message] Signed-off-by: Jagan Teki Reviewed-by: Jagan Teki --- drivers/spi/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f459c0a411..8dd3213d48 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -419,7 +419,6 @@ config MXC_SPI config MXS_SPI bool "MXS SPI Driver" - depends on DEPRECATED help Enable the MXS SPI controller driver. This driver can be used on the i.MX23 and i.MX28 SoCs. -- cgit v1.2.1 From 8473b32127232d8b602d905a2ed26ed48d352f6e Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 22 Jul 2019 17:22:56 +0530 Subject: spi: Add spi_write_then_read Add support for SPI synchronous write followed by read, this is common interface call from spi-nor to spi drivers. Reviewed-by: Simon Glass Signed-off-by: Jagan Teki Tested-by: Adam Ford #da850-evm --- drivers/spi/spi-uclass.c | 24 ++++++++++++++++++++++++ include/spi.h | 20 ++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 88cb2a1262..76c4b53c16 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -108,6 +108,30 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, return dm_spi_xfer(slave->dev, bitlen, dout, din, flags); } +int spi_write_then_read(struct spi_slave *slave, const u8 *opcode, + size_t n_opcode, const u8 *txbuf, u8 *rxbuf, + size_t n_buf) +{ + unsigned long flags = SPI_XFER_BEGIN; + int ret; + + if (n_buf == 0) + flags |= SPI_XFER_END; + + ret = spi_xfer(slave, n_opcode * 8, opcode, NULL, flags); + if (ret) { + debug("spi: failed to send command (%zu bytes): %d\n", + n_opcode, ret); + } else if (n_buf != 0) { + ret = spi_xfer(slave, n_buf * 8, txbuf, rxbuf, SPI_XFER_END); + if (ret) + debug("spi: failed to transfer %zu bytes of data: %d\n", + n_buf, ret); + } + + return ret; +} + #if !CONFIG_IS_ENABLED(OF_PLATDATA) static int spi_child_post_bind(struct udevice *dev) { diff --git a/include/spi.h b/include/spi.h index 378594163b..5eec0c4775 100644 --- a/include/spi.h +++ b/include/spi.h @@ -248,6 +248,26 @@ int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen); int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags); +/** + * spi_write_then_read - SPI synchronous write followed by read + * + * This performs a half duplex transaction in which the first transaction + * is to send the opcode and if the length of buf is non-zero then it start + * the second transaction as tx or rx based on the need from respective slave. + * + * @slave: The SPI slave device with which opcode/data will be exchanged + * @opcode: opcode used for specific transfer + * @n_opcode: size of opcode, in bytes + * @txbuf: buffer into which data to be written + * @rxbuf: buffer into which data will be read + * @n_buf: size of buf (whether it's [tx|rx]buf), in bytes + * + * Returns: 0 on success, not 0 on failure + */ +int spi_write_then_read(struct spi_slave *slave, const u8 *opcode, + size_t n_opcode, const u8 *txbuf, u8 *rxbuf, + size_t n_buf); + /* Copy memory mapped data */ void spi_flash_copy_mmap(void *data, void *offset, size_t len); -- cgit v1.2.1 From 43084a56b08b34a4daef36697dd715659a17caf9 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 22 Jul 2019 17:22:57 +0530 Subject: mtd: spi_dataflash: Use spi read then write Now, we have spi_write_then_read routine that would handle spi_xfer handling based on the tx_buf and rx_buf parameters. So, replace individual flash read/write/cmd transfer call with spi_write_then_read. Cc: Egnite GmbH Cc: Daniel Gorsulowski Cc: Ilko Iliev Cc: Marek Vasut Cc: Mateusz Kulikowski Cc: Alison Wang Tested-by: Adam Ford #da850-evm Signed-off-by: Jagan Teki --- drivers/mtd/spi/sf_dataflash.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/spi/sf_dataflash.c b/drivers/mtd/spi/sf_dataflash.c index b6a2631747..55fb4bd31a 100644 --- a/drivers/mtd/spi/sf_dataflash.c +++ b/drivers/mtd/spi/sf_dataflash.c @@ -76,12 +76,14 @@ struct dataflash { static inline int dataflash_status(struct spi_slave *spi) { int ret; + u8 opcode = OP_READ_STATUS; u8 status; + /* * 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_write_then_read(spi, &opcode, 1, NULL, &status, 1); return ret ? -EIO : status; } @@ -173,7 +175,7 @@ static int spi_dataflash_erase(struct udevice *dev, u32 offset, size_t len) command[0], command[1], command[2], command[3], pageaddr); - status = spi_flash_cmd_write(spi, command, 4, NULL, 0); + status = spi_write_then_read(spi, command, 4, NULL, NULL, 0); if (status < 0) { debug("%s: erase send command error!\n", dev->name); return -EIO; @@ -248,7 +250,7 @@ static int spi_dataflash_read(struct udevice *dev, u32 offset, size_t len, command[3] = (uint8_t)(addr >> 0); /* 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_write_then_read(spi, command, 8, NULL, buf, len); spi_release_bus(spi); @@ -327,7 +329,8 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len, debug("TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); - status = spi_flash_cmd_write(spi, command, 4, NULL, 0); + status = spi_write_then_read(spi, command, 4, + NULL, NULL, 0); if (status < 0) { debug("%s: write(name); @@ -352,8 +355,8 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len, debug("PROGRAM: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); - status = spi_flash_cmd_write(spi, command, - 4, writebuf, writelen); + status = spi_write_then_read(spi, command, 4, + writebuf, NULL, writelen); if (status < 0) { debug("%s: write send command error!\n", dev->name); return -EIO; @@ -376,8 +379,8 @@ int spi_dataflash_write(struct udevice *dev, u32 offset, size_t len, debug("COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); - status = spi_flash_cmd_write(spi, command, - 4, writebuf, writelen); + status = spi_write_then_read(spi, command, 4, + writebuf, NULL, writelen); if (status < 0) { debug("%s: write(compare) send command error!\n", dev->name); @@ -508,6 +511,7 @@ static struct data_flash_info *jedec_probe(struct spi_slave *spi) uint8_t id[5]; uint32_t jedec; struct data_flash_info *info; + u8 opcode = CMD_READ_ID; int status; /* @@ -519,7 +523,7 @@ static struct data_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_write_then_read(spi, &opcode, 1, NULL, id, sizeof(id)); if (tmp < 0) { printf("dataflash: error %d reading JEDEC ID\n", tmp); return ERR_PTR(tmp); -- cgit v1.2.1 From 210d8ad0fa6c63e5775662b840b8eb095a69db19 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Mon, 22 Jul 2019 17:22:58 +0530 Subject: mtd: spi: Drop sf.c spi_write_then_read, will manage to do the respective spi_xfer based on the tx_buf, rx_buf so drop the legacy spi_flash_read/write/cm code. Tested-by: Adam Ford #da850-evm Signed-off-by: Jagan Teki --- drivers/mtd/spi/Makefile | 2 +- drivers/mtd/spi/sf.c | 53 ------------------------------------------- drivers/mtd/spi/sf_internal.h | 18 --------------- 3 files changed, 1 insertion(+), 72 deletions(-) delete mode 100644 drivers/mtd/spi/sf.c diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index f99f6cb16e..20db1015d9 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -18,6 +18,6 @@ spi-nor-y += spi-nor-core.o endif obj-$(CONFIG_SPI_FLASH) += spi-nor.o -obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o sf.o +obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o diff --git a/drivers/mtd/spi/sf.c b/drivers/mtd/spi/sf.c deleted file mode 100644 index ee3cf8b759..0000000000 --- a/drivers/mtd/spi/sf.c +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * SPI flash interface - * - * Copyright (C) 2008 Atmel Corporation - * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik - */ - -#include -#include - -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) -{ - unsigned long flags = SPI_XFER_BEGIN; - int ret; - - if (data_len == 0) - flags |= SPI_XFER_END; - - ret = spi_xfer(spi, cmd_len * 8, cmd, 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); - if (ret) - debug("SF: Failed to transfer %zu bytes of data: %d\n", - 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) -{ - return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len); -} - -int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len) -{ - return spi_flash_cmd_read(spi, &cmd, 1, response, len); -} - -int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, - const void *data, size_t data_len) -{ - return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); -} diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index a6bf734830..ece6fbc258 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -72,24 +72,6 @@ extern const struct flash_info spi_nor_ids[]; #define JEDEC_MFR(info) ((info)->id[0]) #define JEDEC_ID(info) (((info)->id[1]) << 8 | ((info)->id[2])) -/* 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); - -/* - * 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); - -/* - * 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); - - /* Get software write-protect value (BP bits) */ int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash); -- cgit v1.2.1 From e0cacdcc0a479dc70d3048ee40705478dce2655e Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Mon, 9 Sep 2019 22:33:14 +0300 Subject: mtd: spi-nor: add missing SST26* flash IC protection ops Commit c4e8862308d4 (mtd: spi: Switch to new SPI NOR framework) performs switch from previous 'spi_flash' infrastructure without proper testing/investigations which results in a regressions for SST26 flash series. Add missing SST26* flash IC protection ops which were introduced previously by Commit 3d4fed87a5fa (mtd: sf: Add support of sst26wf* flash ICs protection ops) Signed-off-by: Eugeniy Paltsev Reviewed-by: Jagan Teki --- drivers/mtd/spi/sf_internal.h | 1 + drivers/mtd/spi/spi-nor-core.c | 181 +++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/spi-nor.h | 4 + 3 files changed, 186 insertions(+) diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index ece6fbc258..bb8c19a31c 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -65,6 +65,7 @@ struct flash_info { #define NO_CHIP_ERASE BIT(12) /* Chip does not support chip erase */ #define SPI_NOR_SKIP_SFDP BIT(13) /* Skip parsing of SFDP tables */ #define USE_CLSR BIT(14) /* use CLSR command */ +#define SPI_NOR_HAS_SST26LOCK BIT(15) /* Flash supports lock/unlock via BPR */ }; extern const struct flash_info spi_nor_ids[]; diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index 1acff745d1..990e39d7c2 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -945,6 +945,177 @@ read_err: } #ifdef CONFIG_SPI_FLASH_SST +/* + * sst26 flash series has its own block protection implementation: + * 4x - 8 KByte blocks - read & write protection bits - upper addresses + * 1x - 32 KByte blocks - write protection bits + * rest - 64 KByte blocks - write protection bits + * 1x - 32 KByte blocks - write protection bits + * 4x - 8 KByte blocks - read & write protection bits - lower addresses + * + * We'll support only per 64k lock/unlock so lower and upper 64 KByte region + * will be treated as single block. + */ +#define SST26_BPR_8K_NUM 4 +#define SST26_MAX_BPR_REG_LEN (18 + 1) +#define SST26_BOUND_REG_SIZE ((32 + SST26_BPR_8K_NUM * 8) * SZ_1K) + +enum lock_ctl { + SST26_CTL_LOCK, + SST26_CTL_UNLOCK, + SST26_CTL_CHECK +}; + +static bool sst26_process_bpr(u32 bpr_size, u8 *cmd, u32 bit, enum lock_ctl ctl) +{ + switch (ctl) { + case SST26_CTL_LOCK: + cmd[bpr_size - (bit / 8) - 1] |= BIT(bit % 8); + break; + case SST26_CTL_UNLOCK: + cmd[bpr_size - (bit / 8) - 1] &= ~BIT(bit % 8); + break; + case SST26_CTL_CHECK: + return !!(cmd[bpr_size - (bit / 8) - 1] & BIT(bit % 8)); + } + + return false; +} + +/* + * Lock, unlock or check lock status of the flash region of the flash (depending + * on the lock_ctl value) + */ +static int sst26_lock_ctl(struct spi_nor *nor, loff_t ofs, uint64_t len, enum lock_ctl ctl) +{ + struct mtd_info *mtd = &nor->mtd; + u32 i, bpr_ptr, rptr_64k, lptr_64k, bpr_size; + bool lower_64k = false, upper_64k = false; + u8 bpr_buff[SST26_MAX_BPR_REG_LEN] = {}; + int ret; + + /* Check length and offset for 64k alignment */ + if ((ofs & (SZ_64K - 1)) || (len & (SZ_64K - 1))) { + dev_err(nor->dev, "length or offset is not 64KiB allighned\n"); + return -EINVAL; + } + + if (ofs + len > mtd->size) { + dev_err(nor->dev, "range is more than device size: %#llx + %#llx > %#llx\n", + ofs, len, mtd->size); + return -EINVAL; + } + + /* SST26 family has only 16 Mbit, 32 Mbit and 64 Mbit IC */ + if (mtd->size != SZ_2M && + mtd->size != SZ_4M && + mtd->size != SZ_8M) + return -EINVAL; + + bpr_size = 2 + (mtd->size / SZ_64K / 8); + + ret = nor->read_reg(nor, SPINOR_OP_READ_BPR, bpr_buff, bpr_size); + if (ret < 0) { + dev_err(nor->dev, "fail to read block-protection register\n"); + return ret; + } + + rptr_64k = min_t(u32, ofs + len, mtd->size - SST26_BOUND_REG_SIZE); + lptr_64k = max_t(u32, ofs, SST26_BOUND_REG_SIZE); + + upper_64k = ((ofs + len) > (mtd->size - SST26_BOUND_REG_SIZE)); + lower_64k = (ofs < SST26_BOUND_REG_SIZE); + + /* Lower bits in block-protection register are about 64k region */ + bpr_ptr = lptr_64k / SZ_64K - 1; + + /* Process 64K blocks region */ + while (lptr_64k < rptr_64k) { + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl)) + return EACCES; + + bpr_ptr++; + lptr_64k += SZ_64K; + } + + /* 32K and 8K region bits in BPR are after 64k region bits */ + bpr_ptr = (mtd->size - 2 * SST26_BOUND_REG_SIZE) / SZ_64K; + + /* Process lower 32K block region */ + if (lower_64k) + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl)) + return EACCES; + + bpr_ptr++; + + /* Process upper 32K block region */ + if (upper_64k) + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl)) + return EACCES; + + bpr_ptr++; + + /* Process lower 8K block regions */ + for (i = 0; i < SST26_BPR_8K_NUM; i++) { + if (lower_64k) + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl)) + return EACCES; + + /* In 8K area BPR has both read and write protection bits */ + bpr_ptr += 2; + } + + /* Process upper 8K block regions */ + for (i = 0; i < SST26_BPR_8K_NUM; i++) { + if (upper_64k) + if (sst26_process_bpr(bpr_size, bpr_buff, bpr_ptr, ctl)) + return EACCES; + + /* In 8K area BPR has both read and write protection bits */ + bpr_ptr += 2; + } + + /* If we check region status we don't need to write BPR back */ + if (ctl == SST26_CTL_CHECK) + return 0; + + ret = nor->write_reg(nor, SPINOR_OP_WRITE_BPR, bpr_buff, bpr_size); + if (ret < 0) { + dev_err(nor->dev, "fail to write block-protection register\n"); + return ret; + } + + return 0; +} + +static int sst26_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + return sst26_lock_ctl(nor, ofs, len, SST26_CTL_UNLOCK); +} + +static int sst26_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + return sst26_lock_ctl(nor, ofs, len, SST26_CTL_LOCK); +} + +/* + * Returns EACCES (positive value) if region is locked, 0 if region is unlocked, + * and negative on errors. + */ +static int sst26_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len) +{ + /* + * is_locked function is used for check before reading or erasing flash + * region, so offset and length might be not 64k allighned, so adjust + * them to be 64k allighned as sst26_lock_ctl works only with 64k + * allighned regions. + */ + ofs -= ofs & (SZ_64K - 1); + len = len & (SZ_64K - 1) ? (len & ~(SZ_64K - 1)) + SZ_64K : len; + + return sst26_lock_ctl(nor, ofs, len, SST26_CTL_CHECK); +} + static int sst_write_byteprogram(struct spi_nor *nor, loff_t to, size_t len, size_t *retlen, const u_char *buf) { @@ -2302,6 +2473,16 @@ int spi_nor_scan(struct spi_nor *nor) #endif #ifdef CONFIG_SPI_FLASH_SST + /* + * sst26 series block protection implementation differs from other + * series. + */ + if (info->flags & SPI_NOR_HAS_SST26LOCK) { + nor->flash_lock = sst26_lock; + nor->flash_unlock = sst26_unlock; + nor->flash_is_locked = sst26_is_locked; + } + /* sst nor chips use AAI word program */ if (info->flags & SST_WRITE) mtd->_write = sst_write; diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 88e80af579..709b49d393 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -91,6 +91,10 @@ #define SPINOR_OP_WRDI 0x04 /* Write disable */ #define SPINOR_OP_AAI_WP 0xad /* Auto address increment word program */ +/* Used for SST26* flashes only. */ +#define SPINOR_OP_READ_BPR 0x72 /* Read block protection register */ +#define SPINOR_OP_WRITE_BPR 0x42 /* Write block protection register */ + /* Used for S3AN flashes only */ #define SPINOR_OP_XSE 0x50 /* Sector erase */ #define SPINOR_OP_XPP 0x82 /* Page program */ -- cgit v1.2.1 From 718fd834c0d0972d61714c266a1115d2ca425ec2 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Mon, 9 Sep 2019 22:33:15 +0300 Subject: mtd: spi-nor: enable protection ops for SST26 flash series Commit c4e8862308d4 (mtd: spi: Switch to new SPI NOR framework) performs switch from previous 'spi_flash' infrastructure without proper testing/investigations which results in a regressions for SST26 flash series. Enable protection ops for SST26 flash series which were previously enabled by Commit 3d4fed87a5fa (mtd: sf: Add support of sst26wf* flash ICs protection ops) Signed-off-by: Eugeniy Paltsev Reviewed-by: Jagan Teki --- drivers/mtd/spi/spi-nor-ids.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index a3920ba520..6996c0a286 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -214,10 +214,10 @@ const struct flash_info spi_nor_ids[] = { { INFO("sst25wf040b", 0x621613, 0, 64 * 1024, 8, SECT_4K) }, { INFO("sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, { INFO("sst25wf080", 0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, - { INFO("sst26vf064b", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { INFO("sst26wf016", 0xbf2651, 0, 64 * 1024, 32, SECT_4K) }, - { INFO("sst26wf032", 0xbf2622, 0, 64 * 1024, 64, SECT_4K) }, - { INFO("sst26wf064", 0xbf2643, 0, 64 * 1024, 128, SECT_4K) }, + { INFO("sst26vf064b", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("sst26wf016", 0xbf2651, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, + { INFO("sst26wf032", 0xbf2622, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, + { INFO("sst26wf064", 0xbf2643, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_HAS_SST26LOCK) }, #endif #ifdef CONFIG_SPI_FLASH_STMICRO /* STMICRO */ /* ST Microelectronics -- newer production may have feature updates */ -- cgit v1.2.1 From ce704ea11f29b0ee8c195f17370a4048b6be29a9 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Fri, 13 Sep 2019 07:55:42 +0530 Subject: doc: driver-model: Update SPI migration status Update SPI drivers, driver model conversion status for v2019.10 release. Signed-off-by: Jagan Teki --- doc/driver-model/migration.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/driver-model/migration.rst b/doc/driver-model/migration.rst index 75b85235ef..fd499fb74a 100644 --- a/doc/driver-model/migration.rst +++ b/doc/driver-model/migration.rst @@ -58,10 +58,8 @@ to move the migration with in the deadline. No dm conversion yet:: - drivers/spi/cf_spi.c drivers/spi/fsl_espi.c drivers/spi/lpc32xx_ssp.c - drivers/spi/mxs_spi.c drivers/spi/sh_spi.c drivers/spi/soft_spi_legacy.c @@ -74,6 +72,7 @@ Partially converted:: drivers/spi/fsl_dspi.c drivers/spi/kirkwood_spi.c drivers/spi/mxc_spi.c + drivers/spi/mxs_spi.c drivers/spi/omap3_spi.c drivers/spi/sh_qspi.c -- cgit v1.2.1