mtd: spi-nor: sst: Add support for Global Unlock on sst26vf
Even if sst26vf shares the SPINOR_OP_GBULK opcode with Macronix (ex. MX25U12835F) and Winbound (ex. W25Q128FV), it has its own Individual Block Protection scheme, which is also capable to read-lock individual parameter blocks. Thus the sst26vf's Individual Block Protection scheme will reside in the sst.c manufacturer driver. Add support to unlock the entire flash memory. The device is write-protected by default after a power-on reset cycle (volatile software protection), in order to avoid inadvertent writes during power-up. Could do an erase, write, read back, and compare when MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE=y. Signed-off-by: Tudor Ambarus <tudor.ambarus@microchip.com> Reviewed-by: Michael Walle <michael@walle.cc> Link: https://lore.kernel.org/r/20210121110546.382633-2-tudor.ambarus@microchip.com
This commit is contained in:
parent
a7a5acba0e
commit
75386810d3
@ -465,7 +465,7 @@ static int spi_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
|
||||
*
|
||||
* Return: 0 on success, -errno otherwise.
|
||||
*/
|
||||
static int spi_nor_read_cr(struct spi_nor *nor, u8 *cr)
|
||||
int spi_nor_read_cr(struct spi_nor *nor, u8 *cr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -441,6 +441,7 @@ int spi_nor_sr1_bit6_quad_enable(struct spi_nor *nor);
|
||||
int spi_nor_sr2_bit1_quad_enable(struct spi_nor *nor);
|
||||
int spi_nor_sr2_bit7_quad_enable(struct spi_nor *nor);
|
||||
int spi_nor_read_sr(struct spi_nor *nor, u8 *sr);
|
||||
int spi_nor_read_cr(struct spi_nor *nor, u8 *cr);
|
||||
int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);
|
||||
int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
|
||||
|
||||
|
@ -8,6 +8,53 @@
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define SST26VF_CR_BPNV BIT(3)
|
||||
|
||||
static int sst26vf_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static int sst26vf_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* We only support unlocking the entire flash array. */
|
||||
if (ofs != 0 || len != nor->params->size)
|
||||
return -EINVAL;
|
||||
|
||||
ret = spi_nor_read_cr(nor, nor->bouncebuf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(nor->bouncebuf[0] & SST26VF_CR_BPNV)) {
|
||||
dev_dbg(nor->dev, "Any block has been permanently locked\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return spi_nor_global_block_unlock(nor);
|
||||
}
|
||||
|
||||
static int sst26vf_is_locked(struct spi_nor *nor, loff_t ofs, uint64_t len)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const struct spi_nor_locking_ops sst26vf_locking_ops = {
|
||||
.lock = sst26vf_lock,
|
||||
.unlock = sst26vf_unlock,
|
||||
.is_locked = sst26vf_is_locked,
|
||||
};
|
||||
|
||||
static void sst26vf_default_init(struct spi_nor *nor)
|
||||
{
|
||||
nor->params->locking_ops = &sst26vf_locking_ops;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups sst26vf_fixups = {
|
||||
.default_init = sst26vf_default_init,
|
||||
};
|
||||
|
||||
static const struct flash_info sst_parts[] = {
|
||||
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
|
||||
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8,
|
||||
@ -39,8 +86,9 @@ static const struct flash_info sst_parts[] = {
|
||||
{ "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32,
|
||||
SECT_4K | SPI_NOR_DUAL_READ) },
|
||||
{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128,
|
||||
SECT_4K | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ) },
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
|
||||
.fixups = &sst26vf_fixups },
|
||||
};
|
||||
|
||||
static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
|
Loading…
Reference in New Issue
Block a user