mirror of https://gitee.com/openkylin/linux.git
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.
|
* 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;
|
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_bit1_quad_enable(struct spi_nor *nor);
|
||||||
int spi_nor_sr2_bit7_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_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(struct spi_nor *nor, const u8 *sr, size_t len);
|
||||||
int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
|
int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,53 @@
|
||||||
|
|
||||||
#include "core.h"
|
#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[] = {
|
static const struct flash_info sst_parts[] = {
|
||||||
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
|
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
|
||||||
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8,
|
{ "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,
|
{ "sst26vf016b", INFO(0xbf2641, 0, 64 * 1024, 32,
|
||||||
SECT_4K | SPI_NOR_DUAL_READ) },
|
SECT_4K | SPI_NOR_DUAL_READ) },
|
||||||
{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128,
|
{ "sst26vf064b", INFO(0xbf2643, 0, 64 * 1024, 128,
|
||||||
SECT_4K | SPI_NOR_DUAL_READ |
|
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_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,
|
static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||||
|
|
Loading…
Reference in New Issue