Message ID | 1443636231-17173-3-git-send-email-festevam@gmail.com |
---|---|
State | Superseded |
Delegated to: | Jagannadha Sutradharudu Teki |
Headers | show |
On 30 September 2015 at 23:33, Fabio Estevam <festevam@gmail.com> wrote: > From: Fabio Estevam <fabio.estevam@freescale.com> > > Many SPI flashes have protection bits (BP2, BP1 and BP0) in the > status register that can protect selected regions of the SPI NOR. > > Take these bits into account when performing erase operations, > making sure that the protected areas are skipped. > > Introduce the CONFIG_SPI_FLASH_STM_PROTECT option that can be > selectedby systems that want to protect regions of SPI NOR flash > using the same programming model as in the ST Micro SPI NOR flashes, > like for example the M25P32. > > Tested on a mx6qsabresd: > > => sf probe > SF: Detected M25P32 with page size 256 Bytes, erase size 64 KiB, total 4 MiB > => sf protect on 0x3f0000 0x10000 > => sf erase 0x3f0000 0x10000 > offset 0x3f0000 is protected and cannot be erased > SF: 65536 bytes @ 0x3f0000 Erased: ERROR > => sf protect off 0x3f0000 0x10000 > => sf erase 0x3f0000 0x10000 > SF: 65536 bytes @ 0x3f0000 Erased: OK > > Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com> > --- > Changes since v3: > - Split this patch in two parts (Jagan) > > common/cmd_sf.c | 35 +++++++++++++++++++++++++++++++++++ > drivers/mtd/spi/Kconfig | 15 +++++++++++++++ > drivers/mtd/spi/sf_internal.h | 10 ++++------ > drivers/mtd/spi/sf_ops.c | 33 +++++++++++++++++++++++++++++++++ > drivers/mtd/spi/sf_probe.c | 27 +++++++++++++++++++++++++++ > include/spi_flash.h | 18 ++++++++++++++++++ > 6 files changed, 132 insertions(+), 6 deletions(-) > > diff --git a/common/cmd_sf.c b/common/cmd_sf.c > index ac7f5df..bb39cb7 100644 > --- a/common/cmd_sf.c > +++ b/common/cmd_sf.c > @@ -348,6 +348,37 @@ static int do_spi_flash_erase(int argc, char * const argv[]) > return ret == 0 ? 0 : 1; > } > > +static int do_spi_protect(int argc, char * const argv[]) > +{ > + int ret = 0; > + loff_t start, len; > + bool prot = false; > + > + if (argc != 4) > + return -1; > + > + if (!str2off(argv[2], &start)) { > + puts("start sector is not a valid number\n"); > + return 1; > + } > + > + if (!str2off(argv[3], &len)) { > + puts("len is not a valid number\n"); > + return 1; > + } > + > + if (strcmp(argv[1], "on") == 0) > + prot = true; > + else if (strcmp(argv[1], "off") == 0) > + prot = false; > + else > + return -1; /* Unknown parameter */ > + > + ret = spi_flash_protect(flash, start, len, prot); > + > + return ret == 0 ? 0 : 1; > +} > + > #ifdef CONFIG_CMD_SF_TEST > enum { > STAGE_ERASE, > @@ -540,6 +571,8 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, > ret = do_spi_flash_read_write(argc, argv); > else if (strcmp(cmd, "erase") == 0) > ret = do_spi_flash_erase(argc, argv); > + else if (strcmp(cmd, "protect") == 0) > + ret = do_spi_protect(argc, argv); > #ifdef CONFIG_CMD_SF_TEST > else if (!strcmp(cmd, "test")) > ret = do_spi_flash_test(argc, argv); > @@ -579,5 +612,7 @@ U_BOOT_CMD( > "sf update addr offset|partition len - erase and write `len' bytes from memory\n" > " at `addr' to flash at `offset'\n" > " or to start of mtd `partition'\n" > + "sf protect on/off sector len - protect/unprotect 'len' bytes starting\n" > + " at address 'sector'\n" To be in-line with mtd lock utils, how about this notation sf protect lock sf protect unlock sf protect islocked > SF_TEST_HELP > ); > diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig > index 3f7433c..2ee1089 100644 > --- a/drivers/mtd/spi/Kconfig > +++ b/drivers/mtd/spi/Kconfig > @@ -101,6 +101,21 @@ config SPI_FLASH_USE_4K_SECTORS > Please note that some tools/drivers/filesystems may not work with > 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). > > +config SPI_FLASH_STM_PROTECT Remove this macro, just use existing CONFIG_SPI_FLASH_STMICRO as all these code is specific to these parts. > + bool "Use STM flash protection mechanism" > + depends on SPI_FLASH > + help > + Enable the built-in protection mechanism provided by the > + BP2, BP1 and BP0 bits from the status register present > + on ST-Micro flashes such as M25P32. Please refer to the > + M25P32 datasheet to understand how to program these bits > + in order to protect a selected region of the SPI NOR flash. > + > + This same bit protection programming model applies to SPI > + NOR flashes from other manufacturers such as: > + - Micron M25P32 > + - SST SST25V32B > + > config SPI_FLASH_DATAFLASH > bool "AT45xxx DataFlash support" > depends on SPI_FLASH && DM_SPI_FLASH > diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h > index 9c95d56..8fb1b18 100644 > --- a/drivers/mtd/spi/sf_internal.h > +++ b/drivers/mtd/spi/sf_internal.h > @@ -162,12 +162,6 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, > /* Flash erase(sectors) operation, support all possible erase commands */ > int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); > > -/* Read the status register */ > -int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); > - > -/* Program the status register */ > -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); Please don't remove this stuff - this is mtd/spi > - > /* Read the config register */ > int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc); > > @@ -222,6 +216,10 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, > int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, > size_t len, void *data); > > +int spi_flash_cmd_lock_ops(struct spi_flash *flash, u32 offset, size_t len); > +int spi_flash_cmd_unlock_ops(struct spi_flash *flash, u32 offset, size_t len); > +int spi_flash_cmd_is_locked_ops(struct spi_flash *flash, u32 offset, size_t len); > + > #ifdef CONFIG_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_ops.c b/drivers/mtd/spi/sf_ops.c > index e12f8ee..281b06d 100644 > --- a/drivers/mtd/spi/sf_ops.c > +++ b/drivers/mtd/spi/sf_ops.c > @@ -276,6 +276,11 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) > return -1; > } > > + if (flash->is_locked(flash, offset, len) > 0) { > + printf("offset 0x%x is protected and cannot be erased\n", offset); > + return -EINVAL; > + } Can we handle - if the part of the sectors were protected and remaining were not, so it will erase only unprotected sectors and show "these many sectors were locked and unable to erase"? > + > cmd[0] = flash->erase_cmd; > while (len) { > erase_addr = offset; > @@ -318,6 +323,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, > > page_size = flash->page_size; > > + if (flash->is_locked(flash, offset, len) > 0) { > + printf("offset 0x%x is protected and cannot be written\n", offset); > + return -EINVAL; > + } > + > cmd[0] = flash->write_cmd; > for (actual = 0; actual < len; actual += chunk_len) { > write_addr = offset; > @@ -356,6 +366,21 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, > return ret; > } > > +int spi_flash_cmd_lock_ops(struct spi_flash *flash, u32 offset, size_t len) > +{ > + return stm_lock(flash, offset, len); > +} > + > +int spi_flash_cmd_unlock_ops(struct spi_flash *flash, u32 offset, size_t len) > +{ > + return stm_unlock(flash, offset, len); > +} > + > +int spi_flash_cmd_is_locked_ops(struct spi_flash *flash, u32 offset, size_t len) > +{ > + return stm_is_locked(flash, offset, len); > +} > + > int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, > size_t cmd_len, void *data, size_t data_len) > { > @@ -761,3 +786,11 @@ int stm_unlock(struct spi_flash *nor, u32 ofs, u32 len) > return 0; > } > #endif /* CONFIG_SPI_FLASH_STM_PROTECT */ > + > +int spi_flash_protect(struct spi_flash *nor, loff_t ofs, u32 len, bool prot) > +{ > + if (prot) > + return nor->lock(nor, ofs, len); > + else > + return nor->unlock(nor, ofs, len); %s/nor/flash/g Define this spi_flash_protect in include/spi_flash not in ops. > +} > diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c > index 954376d..6da9d6c 100644 > --- a/drivers/mtd/spi/sf_probe.c > +++ b/drivers/mtd/spi/sf_probe.c > @@ -149,6 +149,9 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, > #endif > flash->erase = spi_flash_cmd_erase_ops; > flash->read = spi_flash_cmd_read_ops; > + flash->lock = spi_flash_cmd_lock_ops; > + flash->unlock = spi_flash_cmd_unlock_ops; > + flash->is_locked = spi_flash_cmd_is_locked_ops; > #endif > > /* Compute the flash size */ > @@ -469,6 +472,27 @@ int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) > return spi_flash_cmd_erase_ops(flash, offset, len); > } > > +int spi_flash_std_lock(struct udevice *dev, u32 offset, size_t len) > +{ > + struct spi_flash *flash = dev_get_uclass_priv(dev); > + > + return spi_flash_cmd_lock_ops(flash, offset, len); > +} > + > +int spi_flash_std_unlock(struct udevice *dev, u32 offset, size_t len) > +{ > + struct spi_flash *flash = dev_get_uclass_priv(dev); > + > + return spi_flash_cmd_unlock_ops(flash, offset, len); > +} > + > +int spi_flash_std_is_locked(struct udevice *dev, u32 offset, size_t len) > +{ > + struct spi_flash *flash = dev_get_uclass_priv(dev); > + > + return spi_flash_cmd_is_locked_ops(flash, offset, len); > +} > + > int spi_flash_std_probe(struct udevice *dev) > { > struct spi_slave *slave = dev_get_parentdata(dev); > @@ -485,6 +509,9 @@ 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, > + .lock = spi_flash_std_lock, > + .unlock = spi_flash_std_unlock, > + .is_locked = spi_flash_std_is_locked, > }; > > static const struct udevice_id spi_flash_std_ids[] = { > diff --git a/include/spi_flash.h b/include/spi_flash.h > index 3b2d555..28ec357 100644 > --- a/include/spi_flash.h > +++ b/include/spi_flash.h > @@ -105,6 +105,9 @@ struct spi_flash { > int (*write)(struct spi_flash *flash, u32 offset, size_t len, > const void *buf); > int (*erase)(struct spi_flash *flash, u32 offset, size_t len); > + int (*lock)(struct spi_flash *flash, u32 offset, size_t len); > + int (*unlock)(struct spi_flash *flash, u32 offset, size_t len); > + int (*is_locked)(struct spi_flash *flash, u32 offset, size_t len); > #endif > }; > > @@ -113,8 +116,23 @@ 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); > + int (*lock)(struct udevice *dev, u32 offset, size_t len); > + int (*unlock)(struct udevice *dev, u32 offset, size_t len); > + int (*is_locked)(struct udevice *dev, u32 offset, size_t len); > }; > > + > +/* Read the status register */ > +int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); > + > +/* Program the status register */ > +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); > + > +int stm_is_locked(struct spi_flash *nor, loff_t ofs, u32 len); > +int stm_lock(struct spi_flash *nor, u32 ofs, u32 len); > +int stm_unlock(struct spi_flash *nor, u32 ofs, u32 len); > +int spi_flash_protect(struct spi_flash *nor, loff_t ofs, u32 len, bool prot); Move these into mtd/spi > + > /* Access the serial operations for a device */ > #define sf_get_ops(dev) ((struct dm_spi_flash_ops *)(dev)->driver->ops) >
On Thu, Oct 1, 2015 at 10:48 AM, Jagan Teki <jteki@openedev.com> wrote: > To be in-line with mtd lock utils, how about this notation > sf protect lock > sf protect unlock > sf protect islocked Ok. >> diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig >> index 3f7433c..2ee1089 100644 >> --- a/drivers/mtd/spi/Kconfig >> +++ b/drivers/mtd/spi/Kconfig >> @@ -101,6 +101,21 @@ config SPI_FLASH_USE_4K_SECTORS >> Please note that some tools/drivers/filesystems may not work with >> 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). >> >> +config SPI_FLASH_STM_PROTECT > > Remove this macro, just use existing CONFIG_SPI_FLASH_STMICRO as all > these code is specific to these parts. Ok. >> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h >> index 9c95d56..8fb1b18 100644 >> --- a/drivers/mtd/spi/sf_internal.h >> +++ b/drivers/mtd/spi/sf_internal.h >> @@ -162,12 +162,6 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, >> /* Flash erase(sectors) operation, support all possible erase commands */ >> int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); >> >> -/* Read the status register */ >> -int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); >> - >> -/* Program the status register */ >> -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); > > Please don't remove this stuff - this is mtd/spi Ok. >> --- a/drivers/mtd/spi/sf_ops.c >> +++ b/drivers/mtd/spi/sf_ops.c >> @@ -276,6 +276,11 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) >> return -1; >> } >> >> + if (flash->is_locked(flash, offset, len) > 0) { >> + printf("offset 0x%x is protected and cannot be erased\n", offset); >> + return -EINVAL; >> + } > > Can we handle - if the part of the sectors were protected and > remaining were not, so it will erase only unprotected sectors and show > "these many sectors were locked and unable to erase"? We can add this feature in subsequent patches. >> +int spi_flash_protect(struct spi_flash *nor, loff_t ofs, u32 len, bool prot) >> +{ >> + if (prot) >> + return nor->lock(nor, ofs, len); >> + else >> + return nor->unlock(nor, ofs, len); > > %s/nor/flash/g Ok. > Define this spi_flash_protect in include/spi_flash not in ops. Cannot do this as include/spi_flash.h is included by several files, and then we would get errors about funcion being redefined. >> +/* Read the status register */ >> +int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); >> + >> +/* Program the status register */ >> +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); >> + >> +int stm_is_locked(struct spi_flash *nor, loff_t ofs, u32 len); >> +int stm_lock(struct spi_flash *nor, u32 ofs, u32 len); >> +int stm_unlock(struct spi_flash *nor, u32 ofs, u32 len); >> +int spi_flash_protect(struct spi_flash *nor, loff_t ofs, u32 len, bool prot); > > Move these into mtd/spi Ok.
On 2 October 2015 at 00:06, Fabio Estevam <festevam@gmail.com> wrote: > On Thu, Oct 1, 2015 at 10:48 AM, Jagan Teki <jteki@openedev.com> wrote: > >> To be in-line with mtd lock utils, how about this notation >> sf protect lock >> sf protect unlock >> sf protect islocked > > Ok. > >>> diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig >>> index 3f7433c..2ee1089 100644 >>> --- a/drivers/mtd/spi/Kconfig >>> +++ b/drivers/mtd/spi/Kconfig >>> @@ -101,6 +101,21 @@ config SPI_FLASH_USE_4K_SECTORS >>> Please note that some tools/drivers/filesystems may not work with >>> 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). >>> >>> +config SPI_FLASH_STM_PROTECT >> >> Remove this macro, just use existing CONFIG_SPI_FLASH_STMICRO as all >> these code is specific to these parts. > > Ok. > >>> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h >>> index 9c95d56..8fb1b18 100644 >>> --- a/drivers/mtd/spi/sf_internal.h >>> +++ b/drivers/mtd/spi/sf_internal.h >>> @@ -162,12 +162,6 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, >>> /* Flash erase(sectors) operation, support all possible erase commands */ >>> int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); >>> >>> -/* Read the status register */ >>> -int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); >>> - >>> -/* Program the status register */ >>> -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); >> >> Please don't remove this stuff - this is mtd/spi > > Ok. > >>> --- a/drivers/mtd/spi/sf_ops.c >>> +++ b/drivers/mtd/spi/sf_ops.c >>> @@ -276,6 +276,11 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) >>> return -1; >>> } >>> >>> + if (flash->is_locked(flash, offset, len) > 0) { >>> + printf("offset 0x%x is protected and cannot be erased\n", offset); >>> + return -EINVAL; >>> + } >> >> Can we handle - if the part of the sectors were protected and >> remaining were not, so it will erase only unprotected sectors and show >> "these many sectors were locked and unable to erase"? Couldn't understand why would we get an errors for define this in spi_flash.h Like spi_flash_erase/_read/_write spi_flash_protect is a command ops which would intern call mtd/spi operations as function pointers. > > We can add this feature in subsequent patches. > >>> +int spi_flash_protect(struct spi_flash *nor, loff_t ofs, u32 len, bool prot) >>> +{ >>> + if (prot) >>> + return nor->lock(nor, ofs, len); >>> + else >>> + return nor->unlock(nor, ofs, len); >> >> %s/nor/flash/g > > Ok. > >> Define this spi_flash_protect in include/spi_flash not in ops. > > Cannot do this as include/spi_flash.h is included by several files, > and then we would get errors about funcion being redefined. > >>> +/* Read the status register */ >>> +int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); >>> + >>> +/* Program the status register */ >>> +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); >>> + >>> +int stm_is_locked(struct spi_flash *nor, loff_t ofs, u32 len); >>> +int stm_lock(struct spi_flash *nor, u32 ofs, u32 len); >>> +int stm_unlock(struct spi_flash *nor, u32 ofs, u32 len); >>> +int spi_flash_protect(struct spi_flash *nor, loff_t ofs, u32 len, bool prot); >> >> Move these into mtd/spi > > Ok. > _______________________________________________ > U-Boot mailing list > U-Boot@lists.denx.de > http://lists.denx.de/mailman/listinfo/u-boot
On Mon, Oct 5, 2015 at 6:05 AM, Jagan Teki <jteki@openedev.com> wrote: > Couldn't understand why would we get an errors for define this in > spi_flash.h Like spi_flash_erase/_read/_write spi_flash_protect is a > command ops which would intern call mtd/spi operations as function > pointers. Ok, got your point. Fixed it in v6.
diff --git a/common/cmd_sf.c b/common/cmd_sf.c index ac7f5df..bb39cb7 100644 --- a/common/cmd_sf.c +++ b/common/cmd_sf.c @@ -348,6 +348,37 @@ static int do_spi_flash_erase(int argc, char * const argv[]) return ret == 0 ? 0 : 1; } +static int do_spi_protect(int argc, char * const argv[]) +{ + int ret = 0; + loff_t start, len; + bool prot = false; + + if (argc != 4) + return -1; + + if (!str2off(argv[2], &start)) { + puts("start sector is not a valid number\n"); + return 1; + } + + if (!str2off(argv[3], &len)) { + puts("len is not a valid number\n"); + return 1; + } + + if (strcmp(argv[1], "on") == 0) + prot = true; + else if (strcmp(argv[1], "off") == 0) + prot = false; + else + return -1; /* Unknown parameter */ + + ret = spi_flash_protect(flash, start, len, prot); + + return ret == 0 ? 0 : 1; +} + #ifdef CONFIG_CMD_SF_TEST enum { STAGE_ERASE, @@ -540,6 +571,8 @@ static int do_spi_flash(cmd_tbl_t *cmdtp, int flag, int argc, ret = do_spi_flash_read_write(argc, argv); else if (strcmp(cmd, "erase") == 0) ret = do_spi_flash_erase(argc, argv); + else if (strcmp(cmd, "protect") == 0) + ret = do_spi_protect(argc, argv); #ifdef CONFIG_CMD_SF_TEST else if (!strcmp(cmd, "test")) ret = do_spi_flash_test(argc, argv); @@ -579,5 +612,7 @@ U_BOOT_CMD( "sf update addr offset|partition len - erase and write `len' bytes from memory\n" " at `addr' to flash at `offset'\n" " or to start of mtd `partition'\n" + "sf protect on/off sector len - protect/unprotect 'len' bytes starting\n" + " at address 'sector'\n" SF_TEST_HELP ); diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index 3f7433c..2ee1089 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -101,6 +101,21 @@ config SPI_FLASH_USE_4K_SECTORS Please note that some tools/drivers/filesystems may not work with 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). +config SPI_FLASH_STM_PROTECT + bool "Use STM flash protection mechanism" + depends on SPI_FLASH + help + Enable the built-in protection mechanism provided by the + BP2, BP1 and BP0 bits from the status register present + on ST-Micro flashes such as M25P32. Please refer to the + M25P32 datasheet to understand how to program these bits + in order to protect a selected region of the SPI NOR flash. + + This same bit protection programming model applies to SPI + NOR flashes from other manufacturers such as: + - Micron M25P32 + - SST SST25V32B + config SPI_FLASH_DATAFLASH bool "AT45xxx DataFlash support" depends on SPI_FLASH && DM_SPI_FLASH diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h index 9c95d56..8fb1b18 100644 --- a/drivers/mtd/spi/sf_internal.h +++ b/drivers/mtd/spi/sf_internal.h @@ -162,12 +162,6 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, /* Flash erase(sectors) operation, support all possible erase commands */ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len); -/* Read the status register */ -int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); - -/* Program the status register */ -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); - /* Read the config register */ int spi_flash_cmd_read_config(struct spi_flash *flash, u8 *rc); @@ -222,6 +216,10 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, size_t len, void *data); +int spi_flash_cmd_lock_ops(struct spi_flash *flash, u32 offset, size_t len); +int spi_flash_cmd_unlock_ops(struct spi_flash *flash, u32 offset, size_t len); +int spi_flash_cmd_is_locked_ops(struct spi_flash *flash, u32 offset, size_t len); + #ifdef CONFIG_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_ops.c b/drivers/mtd/spi/sf_ops.c index e12f8ee..281b06d 100644 --- a/drivers/mtd/spi/sf_ops.c +++ b/drivers/mtd/spi/sf_ops.c @@ -276,6 +276,11 @@ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) return -1; } + if (flash->is_locked(flash, offset, len) > 0) { + printf("offset 0x%x is protected and cannot be erased\n", offset); + return -EINVAL; + } + cmd[0] = flash->erase_cmd; while (len) { erase_addr = offset; @@ -318,6 +323,11 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, page_size = flash->page_size; + if (flash->is_locked(flash, offset, len) > 0) { + printf("offset 0x%x is protected and cannot be written\n", offset); + return -EINVAL; + } + cmd[0] = flash->write_cmd; for (actual = 0; actual < len; actual += chunk_len) { write_addr = offset; @@ -356,6 +366,21 @@ int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, return ret; } +int spi_flash_cmd_lock_ops(struct spi_flash *flash, u32 offset, size_t len) +{ + return stm_lock(flash, offset, len); +} + +int spi_flash_cmd_unlock_ops(struct spi_flash *flash, u32 offset, size_t len) +{ + return stm_unlock(flash, offset, len); +} + +int spi_flash_cmd_is_locked_ops(struct spi_flash *flash, u32 offset, size_t len) +{ + return stm_is_locked(flash, offset, len); +} + int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, size_t cmd_len, void *data, size_t data_len) { @@ -761,3 +786,11 @@ int stm_unlock(struct spi_flash *nor, u32 ofs, u32 len) return 0; } #endif /* CONFIG_SPI_FLASH_STM_PROTECT */ + +int spi_flash_protect(struct spi_flash *nor, loff_t ofs, u32 len, bool prot) +{ + if (prot) + return nor->lock(nor, ofs, len); + else + return nor->unlock(nor, ofs, len); +} diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c index 954376d..6da9d6c 100644 --- a/drivers/mtd/spi/sf_probe.c +++ b/drivers/mtd/spi/sf_probe.c @@ -149,6 +149,9 @@ static int spi_flash_validate_params(struct spi_slave *spi, u8 *idcode, #endif flash->erase = spi_flash_cmd_erase_ops; flash->read = spi_flash_cmd_read_ops; + flash->lock = spi_flash_cmd_lock_ops; + flash->unlock = spi_flash_cmd_unlock_ops; + flash->is_locked = spi_flash_cmd_is_locked_ops; #endif /* Compute the flash size */ @@ -469,6 +472,27 @@ int spi_flash_std_erase(struct udevice *dev, u32 offset, size_t len) return spi_flash_cmd_erase_ops(flash, offset, len); } +int spi_flash_std_lock(struct udevice *dev, u32 offset, size_t len) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + + return spi_flash_cmd_lock_ops(flash, offset, len); +} + +int spi_flash_std_unlock(struct udevice *dev, u32 offset, size_t len) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + + return spi_flash_cmd_unlock_ops(flash, offset, len); +} + +int spi_flash_std_is_locked(struct udevice *dev, u32 offset, size_t len) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + + return spi_flash_cmd_is_locked_ops(flash, offset, len); +} + int spi_flash_std_probe(struct udevice *dev) { struct spi_slave *slave = dev_get_parentdata(dev); @@ -485,6 +509,9 @@ 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, + .lock = spi_flash_std_lock, + .unlock = spi_flash_std_unlock, + .is_locked = spi_flash_std_is_locked, }; static const struct udevice_id spi_flash_std_ids[] = { diff --git a/include/spi_flash.h b/include/spi_flash.h index 3b2d555..28ec357 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -105,6 +105,9 @@ struct spi_flash { int (*write)(struct spi_flash *flash, u32 offset, size_t len, const void *buf); int (*erase)(struct spi_flash *flash, u32 offset, size_t len); + int (*lock)(struct spi_flash *flash, u32 offset, size_t len); + int (*unlock)(struct spi_flash *flash, u32 offset, size_t len); + int (*is_locked)(struct spi_flash *flash, u32 offset, size_t len); #endif }; @@ -113,8 +116,23 @@ 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); + int (*lock)(struct udevice *dev, u32 offset, size_t len); + int (*unlock)(struct udevice *dev, u32 offset, size_t len); + int (*is_locked)(struct udevice *dev, u32 offset, size_t len); }; + +/* Read the status register */ +int spi_flash_cmd_read_status(struct spi_flash *flash, u8 *rs); + +/* Program the status register */ +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 ws); + +int stm_is_locked(struct spi_flash *nor, loff_t ofs, u32 len); +int stm_lock(struct spi_flash *nor, u32 ofs, u32 len); +int stm_unlock(struct spi_flash *nor, u32 ofs, u32 len); +int spi_flash_protect(struct spi_flash *nor, loff_t ofs, u32 len, bool prot); + /* Access the serial operations for a device */ #define sf_get_ops(dev) ((struct dm_spi_flash_ops *)(dev)->driver->ops)