diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index fd1bec80d6..cfce00ef54 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -31,6 +31,15 @@ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len) return log_ret(sf_get_ops(dev)->erase(dev, offset, len)); } +int spl_flash_get_sw_write_prot(struct udevice *dev) +{ + struct dm_spi_flash_ops *ops = sf_get_ops(dev); + + if (!ops->get_sw_write_prot) + return -ENOSYS; + return log_ret(ops->get_sw_write_prot(dev)); +} + /* * TODO(sjg@chromium.org): This is an old-style function. We should remove * it when all SPI flash drivers use dm diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 9ceff0e7c1..786301ba4a 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -75,6 +75,10 @@ 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])) +/* Get software write-protect value (BP bits) */ +int spi_flash_cmd_get_sw_write_prot(struct spi_flash *flash); + + #if CONFIG_IS_ENABLED(SPI_FLASH_MTD) int spi_flash_mtd_register(struct spi_flash *flash); void spi_flash_mtd_unregister(void); diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 6c87434867..3befbe91ca 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -130,6 +130,13 @@ static int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) return mtd->_erase(mtd, &instr); } +static int spi_flash_std_get_sw_write_prot(struct udevice *dev) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + + return spi_flash_cmd_get_sw_write_prot(flash); +} + int spi_flash_std_probe(struct udevice *dev) { struct spi_slave *slave = dev_get_parent_priv(dev); @@ -153,6 +160,7 @@ static const struct dm_spi_flash_ops spi_flash_std_ops = { .read = spi_flash_std_read, .write = spi_flash_std_write, .erase = spi_flash_std_erase, + .get_sw_write_prot = spi_flash_std_get_sw_write_prot, }; static const struct udevice_id spi_flash_std_ids[] = { diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c index e0efebc355..a6625535a7 100644 --- a/drivers/mtd/spi/spi-nor-core.c +++ b/drivers/mtd/spi/spi-nor-core.c @@ -2647,3 +2647,14 @@ int spi_nor_scan(struct spi_nor *nor) return 0; } + +/* U-Boot specific functions, need to extend MTD to support these */ +int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor) +{ + int sr = read_sr(nor); + + if (sr < 0) + return sr; + + return (sr >> 2) & 7; +} diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c index 07c8c7b82b..1d5861d55c 100644 --- a/drivers/mtd/spi/spi-nor-tiny.c +++ b/drivers/mtd/spi/spi-nor-tiny.c @@ -809,3 +809,9 @@ int spi_nor_scan(struct spi_nor *nor) return 0; } + +/* U-Boot specific functions, need to extend MTD to support these */ +int spi_flash_cmd_get_sw_write_prot(struct spi_nor *nor) +{ + return -ENOTSUPP; +} diff --git a/include/spi_flash.h b/include/spi_flash.h index 478c543b06..3d747c925b 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -35,6 +35,19 @@ struct dm_spi_flash_ops { int (*write)(struct udevice *dev, u32 offset, size_t len, const void *buf); int (*erase)(struct udevice *dev, u32 offset, size_t len); + /** + * get_sw_write_prot() - Check state of software write-protect feature + * + * SPI flash chips can lock a region of the flash defined by a + * 'protected area'. This function checks if this protected area is + * defined. + * + * @dev: SPI flash device + * @return 0 if no region is write-protected, 1 if a region is + * write-protected, -ENOSYS if the driver does not implement this, + * other -ve value on error + */ + int (*get_sw_write_prot)(struct udevice *dev); }; /* Access the serial operations for a device */ @@ -76,6 +89,20 @@ int spi_flash_write_dm(struct udevice *dev, u32 offset, size_t len, */ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len); +/** + * spl_flash_get_sw_write_prot() - Check state of software write-protect feature + * + * SPI flash chips can lock a region of the flash defined by a + * 'protected area'. This function checks if this protected area is + * defined. + * + * @dev: SPI flash device + * @return 0 if no region is write-protected, 1 if a region is + * write-protected, -ENOSYS if the driver does not implement this, + * other -ve value on error + */ +int spl_flash_get_sw_write_prot(struct udevice *dev); + /** * spi_flash_std_probe() - Probe a SPI flash device * diff --git a/test/dm/sf.c b/test/dm/sf.c index cc1fc4d69a..17d43fef3b 100644 --- a/test/dm/sf.c +++ b/test/dm/sf.c @@ -21,7 +21,7 @@ /* Simple test of sandbox SPI flash */ static int dm_test_spi_flash(struct unit_test_state *uts) { - struct udevice *dev; + struct udevice *dev, *emul; int full_size = 0x200000; int size = 0x10000; u8 *src, *dst; @@ -51,6 +51,14 @@ static int dm_test_spi_flash(struct unit_test_state *uts) ut_assertok(spi_flash_read_dm(dev, 0, size, dst)); ut_asserteq_mem(src, dst, size); + /* Try the write-protect stuff */ + ut_assertok(uclass_first_device_err(UCLASS_SPI_EMUL, &emul)); + ut_asserteq(0, spl_flash_get_sw_write_prot(dev)); + sandbox_sf_set_block_protect(emul, 1); + ut_asserteq(1, spl_flash_get_sw_write_prot(dev)); + sandbox_sf_set_block_protect(emul, 0); + ut_asserteq(0, spl_flash_get_sw_write_prot(dev)); + /* Check mapping */ ut_assertok(dm_spi_get_mmap(dev, &map_base, &map_size, &offset)); ut_asserteq(0x1000, map_base);