History

Merge tag 'spi-nor/for-7.2' into mtd/next

SPI NOR changes for 7.2 Notable changes: - Big set of cleanups and improvements to the locking support. This series contains some cleanups and bug fixes for code and documentation around write protection. Then support is added for complement locking, which allows finer grained configuration of what is considered locked and unlocked. Then complement locking is enabled on a bunch of Winbond W25 flashes. - Fix die erase support on Spansion flashes. Die erase is only supported on multi-die flashes, but the die erase opcode was set for all. When the opcode is set, it overrides the default chip erase opcode which should be used for single-die flashes. Only set the opcode on multi-die flashes. Also, the opcode was not set on multi-die s28hx-t flashes. Set it so they can use die-erase correctly.

Miquel Raynal committed 4 months ago

Commit c10f6412 parents cf4ff71 df415c59 files · +672 −92Browse files

Unified · Split

9 files
  1. Documentation/driver-api/mtd/spi-nor.rst +170 −0
  2. drivers/mtd/spi-nor/Kconfig +0 −1
  3. drivers/mtd/spi-nor/core.c +73 −3
  4. drivers/mtd/spi-nor/core.h +22 −3
  5. drivers/mtd/spi-nor/debugfs.c +70 −2
  6. drivers/mtd/spi-nor/spansion.c +6 −1
  7. drivers/mtd/spi-nor/swp.c +291 −74
  8. drivers/mtd/spi-nor/winbond.c +35 −6
  9. include/linux/mtd/spi-nor.h +5 −2
Documentation/driver-api/mtd/spi-nor.rst+170−0
@@ -203,3 +203,173 @@ section, after the ``---`` marker. · 202 unmodified lines
203 mtd.writesize = 1203 mtd.writesize = 1
204 mtd.oobsize = 0204 mtd.oobsize = 0
205 regions = 0205 regions = 0
206
2075) If your flash supports locking, please go through the following test
208 procedure to make sure it correctly behaves. The below example
209 expects the typical situation where eraseblocks and lock sectors have
210 the same size. In case you enabled MTD_SPI_NOR_USE_4K_SECTORS, you
211 must adapt `bs` accordingly.
212
213 Warning: These tests may hard lock your device! Make sure:
214
215 - The device is not hard locked already (#WP strapped to low and
216 SR_SRWD bit set)
217 - If you have a WPn pin, you may want to set `no-wp` in your DT for
218 the time of the test, to only make use of software protection.
219 Otherwise, clearing the locking state depends on the WPn
220 signal and if it is tied to low, the flash will be permanently
221 locked.
222
223 Test full chip locking and make sure expectations, the MEMISLOCKED
224 ioctl output, the debugfs output and experimental results are all
225 aligned::
226
227 root@1:~# alias show_sectors='grep -A4 "locked sectors" /sys/kernel/debug/spi-nor/spi0.0/params'
228 root@1:~# flash_lock -u /dev/mtd0
229 root@1:~# flash_lock -i /dev/mtd0
230 Device: /dev/mtd0
231 Start: 0
232 Len: 0x4000000
233 Lock status: unlocked
234 Return code: 0
235 root@1:~# mtd_debug erase /dev/mtd0 0 2097152
236 Erased 2097152 bytes from address 0x00000000 in flash
237 root@1:~# mtd_debug write /dev/mtd0 0 2097152 spi_test
238 Copied 2097152 bytes from spi_test to address 0x00000000 in flash
239 root@1:~# mtd_debug read /dev/mtd0 0 2097152 spi_read
240 Copied 2097152 bytes from address 0x00000000 in flash to spi_read
241 root@1:~# sha256sum spi*
242 c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_read
243 c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_test
244 root@1:~# show_sectors
245 software locked sectors
246 region (in hex) | status | #sectors
247 ------------------+----------+---------
248 00000000-03ffffff | unlocked | 1024
249
250 root@1:~# flash_lock -l /dev/mtd0
251 root@1:~# flash_lock -i /dev/mtd0
252 Device: /dev/mtd0
253 Start: 0
254 Len: 0x4000000
255 Lock status: locked
256 Return code: 1
257 root@1:~# mtd_debug erase /dev/mtd0 0 2097152
258 Erased 2097152 bytes from address 0x00000000 in flash
259 root@1:~# mtd_debug read /dev/mtd0 0 2097152 spi_read
260 Copied 2097152 bytes from address 0x00000000 in flash to spi_read
261 root@1:~# sha256sum spi*
262 c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_read
263 c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_test
264 root@1:~# dd if=/dev/urandom of=./spi_test2 bs=1M count=2
265 2+0 records in
266 2+0 records out
267 root@1:~# mtd_debug write /dev/mtd0 0 2097152 spi_test2
268 Copied 2097152 bytes from spi_test2 to address 0x00000000 in flash
269 root@1:~# mtd_debug read /dev/mtd0 0 2097152 spi_read2
270 Copied 2097152 bytes from address 0x00000000 in flash to spi_read2
271 root@1:~# sha256sum spi*
272 c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_read
273 c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_read2
274 c444216a6ba2a4a66cccd60a0dd062bce4b865dd52b200ef5e21838c4b899ac8 spi_test
275 bea9334df51c620440f86751cba0799214a016329f1736f9456d40cf40efdc88 spi_test2
276 root@1:~# show_sectors
277 software locked sectors
278 region (in hex) | status | #sectors
279 ------------------+----------+---------
280 00000000-03ffffff | locked | 1024
281 root@1:~# flash_lock -u /dev/mtd0
282
283 Once we trust the debugfs output we can use it to test various
284 situations. Check top locking/unlocking (end of the device)::
285
286 root@1:~# size=$(cat /sys/class/mtd/mtd0/size)
287 root@1:~# bs=$(cat /sys/class/mtd/mtd0/erasesize)
288 root@1:~# nsectors=$(grep unlocked /sys/kernel/debug/spi-nor/spi0.0/params | sed -e 's/.*unlocked | //')
289 root@1:~# ss=$(($size / $nsectors))
290 root@1:~# bps=$(($ss / $bs))
291
292 root@1:~# flash_lock -u /dev/mtd0
293 root@1:~# flash_lock -l /dev/mtd0 $(($size - (2 * $ss))) $((2 * $bps)) # last two
294 root@1:~# show_sectors
295 software locked sectors
296 region (in hex) | status | #sectors
297 ------------------+----------+---------
298 00000000-03fdffff | unlocked | 1022
299 03fe0000-03ffffff | locked | 2
300 root@1:~# flash_lock -u /dev/mtd0 $(($size - (2 * $ss))) $((1 * $bps)) # last one
301 root@1:~# show_sectors
302 software locked sectors
303 region (in hex) | status | #sectors
304 ------------------+----------+---------
305 00000000-03feffff | unlocked | 1023
306 03ff0000-03ffffff | locked | 1
307
308 If the flash features 4 block protection bits (BP), we can protect
309 more than 4MB (typically 128 64kiB-blocks or more), with a finer
310 grain than locking the entire device::
311
312 root@1:~# flash_lock -u /dev/mtd0
313 root@1:~# flash_lock -l /dev/mtd0 $(($size - (2**7 * $ss))) $((2**7 * $bps))
314 root@1:~# show_sectors
315 software locked sectors
316 region (in hex) | status | #sectors
317 ------------------+----------+---------
318 00000000-037fffff | unlocked | 896
319 03800000-03ffffff | locked | 128
320
321 If the flash features a Top/Bottom (TB) bit, we can protect the
322 beginning of the flash::
323
324 root@1:~# flash_lock -u /dev/mtd0
325 root@1:~# flash_lock -l /dev/mtd0 0 $((2 * $bps)) # first two
326 root@1:~# show_sectors
327 software locked sectors
328 region (in hex) | status | #sectors
329 ------------------+----------+---------
330 00000000-0001ffff | locked | 2
331 00020000-03ffffff | unlocked | 1022
332 root@1:~# flash_lock -u /dev/mtd0 $ss $((1 * $bps)) # first one
333 root@1:~# show_sectors
334 software locked sectors
335 region (in hex) | status | #sectors
336 ------------------+----------+---------
337 00000000-0000ffff | locked | 1
338 00010000-03ffffff | unlocked | 1023
339
340 If the flash features a Complement (CMP) bit, we can protect with
341 more granularity above half of the capacity. Let's lock all but one
342 block, then unlock one more block::
343
344 root@1:~# all_but_one=$((($size / $bs) - ($ss / $bs)))
345
346 root@1:~# flash_lock -u /dev/mtd0
347 root@1:~# flash_lock -l /dev/mtd0 $ss $all_but_one # all but the first
348 root@1:~# show_sectors
349 software locked sectors
350 region (in hex) | status | #sectors
351 ------------------+----------+---------
352 00000000-0000ffff | unlocked | 1
353 00010000-03ffffff | locked | 1023
354 root@1:~# flash_lock -u /dev/mtd0 $ss $(($ss / $bs)) # all but the two first
355 root@1:~# show_sectors
356 software locked sectors
357 region (in hex) | status | #sectors
358 ------------------+----------+---------
359 00000000-0001ffff | unlocked | 2
360 00020000-03ffffff | locked | 1022
361 root@1:~# flash_lock -u /dev/mtd0
362 root@1:~# flash_lock -l /dev/mtd0 0 $all_but_one # same from the other side
363 root@1:~# show_sectors
364 software locked sectors
365 region (in hex) | status | #sectors
366 ------------------+----------+---------
367 00000000-03feffff | locked | 1023
368 03ff0000-03ffffff | unlocked | 1
369 root@1:~# flash_lock -u /dev/mtd0 $(($size - (2 * $ss))) $(($ss / $bs)) # all but two
370 root@1:~# show_sectors
371 software locked sectors
372 region (in hex) | status | #sectors
373 ------------------+----------+---------
374 00000000-03fdffff | locked | 1022
375 03fe0000-03ffffff | unlocked | 2
drivers/mtd/spi-nor/Kconfig+0−1
@@ -1,7 +1,6 @@
1# SPDX-License-Identifier: GPL-2.0-only1# SPDX-License-Identifier: GPL-2.0-only
2menuconfig MTD_SPI_NOR2menuconfig MTD_SPI_NOR
3 tristate "SPI NOR device support"3 tristate "SPI NOR device support"
4 depends on MTD
5 depends on MTD && SPI_MASTER4 depends on MTD && SPI_MASTER
6 select SPI_MEM5 select SPI_MEM
7 help6 help
drivers/mtd/spi-nor/core.c+73−3
@@ -869,8 +869,8 @@ static int spi_nor_write_16bit_sr_and_check(struct spi_nor *nor, u8 sr1) · 868 unmodified lines
869 ret = spi_nor_read_cr(nor, &sr_cr[1]);869 ret = spi_nor_read_cr(nor, &sr_cr[1]);
870 if (ret)870 if (ret)
871 return ret;871 return ret;
872 } else if (spi_nor_get_protocol_width(nor->read_proto) == 4 &&872 } else if ((spi_nor_get_protocol_width(nor->read_proto) == 4 ||
873 spi_nor_get_protocol_width(nor->write_proto) == 4 &&873 spi_nor_get_protocol_width(nor->write_proto) == 4) &&
874 nor->params->quad_enable) {874 nor->params->quad_enable) {
875 /*875 /*
876 * If the Status Register 2 Read command (35h) is not876 * If the Status Register 2 Read command (35h) is not
@@ -976,6 +976,54 @@ int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr) · 99 unmodified lines
976 return 0;976 return 0;
977}977}
978 978
979/**
980 * spi_nor_write_16bit_sr_cr_and_check() - Write the Status Register 1 and the
981 * Configuration Register in one shot. Ensure that the bytes written in both
982 * registers match the received value.
983 * @nor: pointer to a 'struct spi_nor'.
984 * @regs: two-byte array with values to be written to the status and
985 * configuration registers.
986 *
987 * Return: 0 on success, -errno otherwise.
988 */
989static int spi_nor_write_16bit_sr_cr_and_check(struct spi_nor *nor, const u8 *regs)
990{
991 u8 written_regs[2];
992 int ret;
993
994 written_regs[0] = regs[0];
995 written_regs[1] = regs[1];
996 nor->bouncebuf[0] = regs[0];
997 nor->bouncebuf[1] = regs[1];
998
999 ret = spi_nor_write_sr(nor, nor->bouncebuf, 2);
1000 if (ret)
1001 return ret;
1002
1003 ret = spi_nor_read_sr(nor, &nor->bouncebuf[0]);
1004 if (ret)
1005 return ret;
1006
1007 if (written_regs[0] != nor->bouncebuf[0]) {
1008 dev_dbg(nor->dev, "SR: Read back test failed\n");
1009 return -EIO;
1010 }
1011
1012 if (nor->flags & SNOR_F_NO_READ_CR)
1013 return 0;
1014
1015 ret = spi_nor_read_cr(nor, &nor->bouncebuf[1]);
1016 if (ret)
1017 return ret;
1018
1019 if (written_regs[1] != nor->bouncebuf[1]) {
1020 dev_dbg(nor->dev, "CR: read back test failed\n");
1021 return -EIO;
1022 }
1023
1024 return 0;
1025}
1026
979/**1027/**
980 * spi_nor_write_sr_and_check() - Write the Status Register 1 and ensure that1028 * spi_nor_write_sr_and_check() - Write the Status Register 1 and ensure that
981 * the byte written match the received value without affecting other bits in the1029 * the byte written match the received value without affecting other bits in the
@@ -993,6 +1041,23 @@ int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1) · 11 unmodified lines
993 return spi_nor_write_sr1_and_check(nor, sr1);1041 return spi_nor_write_sr1_and_check(nor, sr1);
994}1042}
995 1043
1044/**
1045 * spi_nor_write_sr_cr_and_check() - Write the Status Register 1 and ensure that
1046 * the byte written match the received value. Same for the Control Register if
1047 * available.
1048 * @nor: pointer to a 'struct spi_nor'.
1049 * @regs: byte array to be written to the registers.
1050 *
1051 * Return: 0 on success, -errno otherwise.
1052 */
1053int spi_nor_write_sr_cr_and_check(struct spi_nor *nor, const u8 *regs)
1054{
1055 if (nor->flags & SNOR_F_HAS_16BIT_SR)
1056 return spi_nor_write_16bit_sr_cr_and_check(nor, regs);
1057
1058 return spi_nor_write_sr1_and_check(nor, regs[0]);
1059}
1060
996/**1061/**
997 * spi_nor_write_sr2() - Write the Status Register 2 using the1062 * spi_nor_write_sr2() - Write the Status Register 2 using the
998 * SPINOR_OP_WRSR2 (3eh) command.1063 * SPINOR_OP_WRSR2 (3eh) command.
@@ -2909,6 +2974,9 @@ static void spi_nor_init_flags(struct spi_nor *nor) · 1910 unmodified lines
2909 nor->flags |= SNOR_F_HAS_SR_BP3_BIT6;2974 nor->flags |= SNOR_F_HAS_SR_BP3_BIT6;
2910 }2975 }
2911 2976
2977 if (flags & SPI_NOR_HAS_CMP)
2978 nor->flags |= SNOR_F_HAS_SR2_CMP_BIT6;
2979
2912 if (flags & SPI_NOR_RWW && nor->params->n_banks > 1 &&2980 if (flags & SPI_NOR_RWW && nor->params->n_banks > 1 &&
2913 !nor->controller_ops)2981 !nor->controller_ops)
2914 nor->flags |= SNOR_F_RWW;2982 nor->flags |= SNOR_F_RWW;
@@ -3261,10 +3329,12 @@ static int spi_nor_init(struct spi_nor *nor) · 346 unmodified lines
3261 * protection bits are volatile. The latter is indicated by3329 * protection bits are volatile. The latter is indicated by
3262 * SNOR_F_SWP_IS_VOLATILE.3330 * SNOR_F_SWP_IS_VOLATILE.
3263 */3331 */
3332 spi_nor_cache_sr_lock_bits(nor, NULL);
3264 if (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE) ||3333 if (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE) ||
3265 (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE) &&3334 (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE_ON_VOLATILE) &&
3266 nor->flags & SNOR_F_SWP_IS_VOLATILE))3335 nor->flags & SNOR_F_SWP_IS_VOLATILE)) {
3267 spi_nor_try_unlock_all(nor);3336 spi_nor_try_unlock_all(nor);
3337 }
3268 3338
3269 if (nor->addr_nbytes == 4 &&3339 if (nor->addr_nbytes == 4 &&
3270 nor->read_proto != SNOR_PROTO_8_8_8_DTR &&3340 nor->read_proto != SNOR_PROTO_8_8_8_DTR &&
drivers/mtd/spi-nor/core.h+22−3
@@ -141,6 +141,7 @@ enum spi_nor_option_flags { · 140 unmodified lines
141 SNOR_F_ECC = BIT(15),141 SNOR_F_ECC = BIT(15),
142 SNOR_F_NO_WP = BIT(16),142 SNOR_F_NO_WP = BIT(16),
143 SNOR_F_SWAP16 = BIT(17),143 SNOR_F_SWAP16 = BIT(17),
144 SNOR_F_HAS_SR2_CMP_BIT6 = BIT(18),
144};145};
145 146
146struct spi_nor_read_command {147struct spi_nor_read_command {
@@ -279,9 +280,17 @@ struct spi_nor_erase_map { · 132 unmodified lines
279 280
280/**281/**
281 * struct spi_nor_locking_ops - SPI NOR locking methods282 * struct spi_nor_locking_ops - SPI NOR locking methods
282 * @lock: lock a region of the SPI NOR.283 * @lock: lock a region of the SPI NOR, never locks more than what is
283 * @unlock: unlock a region of the SPI NOR.284 * requested, ie. may lock less.
284 * @is_locked: check if a region of the SPI NOR is completely locked285 * @unlock: unlock a region of the SPI NOR, may unlock more than what is
286 * requested.
287 * @is_locked: check if a region of the SPI NOR is completely locked, returns
288 * false otherwise. This feedback may be misleading because users
289 * may get an "unlocked" status even though a subpart of the region
290 * is effectively locked.
291 *
292 * If in doubt during development, check-out the debugfs output which tries to
293 * be more user friendly.
285 */294 */
286struct spi_nor_locking_ops {295struct spi_nor_locking_ops {
287 int (*lock)(struct spi_nor *nor, loff_t ofs, u64 len);296 int (*lock)(struct spi_nor *nor, loff_t ofs, u64 len);
@@ -483,6 +492,8 @@ struct spi_nor_id { · 195 unmodified lines
483 * SPI_NOR_NO_ERASE: no erase command needed.492 * SPI_NOR_NO_ERASE: no erase command needed.
484 * SPI_NOR_QUAD_PP: flash supports Quad Input Page Program.493 * SPI_NOR_QUAD_PP: flash supports Quad Input Page Program.
485 * SPI_NOR_RWW: flash supports reads while write.494 * SPI_NOR_RWW: flash supports reads while write.
495 * SPI_NOR_HAS_CMP: flash SR2 has complement (CMP) protect bit. Must
496 * be used with SPI_NOR_HAS_LOCK.
486 *497 *
487 * @no_sfdp_flags: flags that indicate support that can be discovered via SFDP.498 * @no_sfdp_flags: flags that indicate support that can be discovered via SFDP.
488 * Used when SFDP tables are not defined in the flash. These499 * Used when SFDP tables are not defined in the flash. These
@@ -531,6 +542,7 @@ struct flash_info { · 42 unmodified lines
531#define SPI_NOR_NO_ERASE BIT(6)542#define SPI_NOR_NO_ERASE BIT(6)
532#define SPI_NOR_QUAD_PP BIT(8)543#define SPI_NOR_QUAD_PP BIT(8)
533#define SPI_NOR_RWW BIT(9)544#define SPI_NOR_RWW BIT(9)
545#define SPI_NOR_HAS_CMP BIT(10)
534 546
535 u8 no_sfdp_flags;547 u8 no_sfdp_flags;
536#define SPI_NOR_SKIP_SFDP BIT(0)548#define SPI_NOR_SKIP_SFDP BIT(0)
@@ -632,6 +644,7 @@ int spi_nor_read_cr(struct spi_nor *nor, u8 *cr); · 95 unmodified lines
632int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);644int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);
633int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);645int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
634int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr);646int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr);
647int spi_nor_write_sr_cr_and_check(struct spi_nor *nor, const u8 *regs);
635 648
636ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,649ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
637 u8 *buf);650 u8 *buf);
@@ -672,7 +685,9 @@ int spi_nor_post_bfpt_fixups(struct spi_nor *nor, · 34 unmodified lines
672 const struct sfdp_bfpt *bfpt);685 const struct sfdp_bfpt *bfpt);
673 686
674void spi_nor_init_default_locking_ops(struct spi_nor *nor);687void spi_nor_init_default_locking_ops(struct spi_nor *nor);
688bool spi_nor_has_default_locking_ops(struct spi_nor *nor);
675void spi_nor_try_unlock_all(struct spi_nor *nor);689void spi_nor_try_unlock_all(struct spi_nor *nor);
690void spi_nor_cache_sr_lock_bits(struct spi_nor *nor, u8 *sr);
676void spi_nor_set_mtd_locking_ops(struct spi_nor *nor);691void spi_nor_set_mtd_locking_ops(struct spi_nor *nor);
677void spi_nor_set_mtd_otp_ops(struct spi_nor *nor);692void spi_nor_set_mtd_otp_ops(struct spi_nor *nor);
678 693
@@ -705,6 +720,10 @@ static inline bool spi_nor_needs_sfdp(const struct spi_nor *nor) · 26 unmodified lines
705 return !nor->info->size;720 return !nor->info->size;
706}721}
707 722
723u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor);
724void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_t *ofs, u64 *len);
725bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, u64 len, const u8 *sr);
726
708#ifdef CONFIG_DEBUG_FS727#ifdef CONFIG_DEBUG_FS
709void spi_nor_debugfs_register(struct spi_nor *nor);728void spi_nor_debugfs_register(struct spi_nor *nor);
710void spi_nor_debugfs_shutdown(void);729void spi_nor_debugfs_shutdown(void);
drivers/mtd/spi-nor/debugfs.c+70−2
@@ -1,6 +1,7 @@
1// SPDX-License-Identifier: GPL-2.01// SPDX-License-Identifier: GPL-2.0
2 2
3#include <linux/debugfs.h>3#include <linux/debugfs.h>
4#include <linux/math64.h>
4#include <linux/mtd/spi-nor.h>5#include <linux/mtd/spi-nor.h>
5#include <linux/spi/spi.h>6#include <linux/spi/spi.h>
6#include <linux/spi/spi-mem.h>7#include <linux/spi/spi-mem.h>
@@ -28,6 +29,8 @@ static const char *const snor_f_names[] = { · 21 unmodified lines
28 SNOR_F_NAME(RWW),29 SNOR_F_NAME(RWW),
29 SNOR_F_NAME(ECC),30 SNOR_F_NAME(ECC),
30 SNOR_F_NAME(NO_WP),31 SNOR_F_NAME(NO_WP),
32 SNOR_F_NAME(SWAP16),
33 SNOR_F_NAME(HAS_SR2_CMP_BIT6),
31};34};
32#undef SNOR_F_NAME35#undef SNOR_F_NAME
33 36
@@ -76,11 +79,14 @@ static void spi_nor_print_flags(struct seq_file *s, unsigned long flags, · 42 unmodified lines
76static int spi_nor_params_show(struct seq_file *s, void *data)79static int spi_nor_params_show(struct seq_file *s, void *data)
77{80{
78 struct spi_nor *nor = s->private;81 struct spi_nor *nor = s->private;
82 u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
79 struct spi_nor_flash_parameter *params = nor->params;83 struct spi_nor_flash_parameter *params = nor->params;
80 struct spi_nor_erase_map *erase_map = &params->erase_map;84 struct spi_nor_erase_map *erase_map = &params->erase_map;
81 struct spi_nor_erase_region *region = erase_map->regions;85 struct spi_nor_erase_region *region = erase_map->regions;
82 const struct flash_info *info = nor->info;86 const struct flash_info *info = nor->info;
83 char buf[16], *str;87 char buf[16], *str;
88 loff_t lock_start;
89 u64 lock_length;
84 unsigned int i;90 unsigned int i;
85 91
86 seq_printf(s, "name\t\t%s\n", info->name);92 seq_printf(s, "name\t\t%s\n", info->name);
@@ -138,12 +144,12 @@ static int spi_nor_params_show(struct seq_file *s, void *data) · 51 unmodified lines
138 144
139 if (!(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {145 if (!(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
140 string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));146 string_get_size(params->size, 1, STRING_UNITS_2, buf, sizeof(buf));
141 seq_printf(s, " %02x (%s)\n", nor->params->die_erase_opcode, buf);147 seq_printf(s, " %02x (%s)\n", params->die_erase_opcode, buf);
142 }148 }
143 149
144 seq_puts(s, "\nsector map\n");150 seq_puts(s, "\nsector map\n");
145 seq_puts(s, " region (in hex) | erase mask | overlaid\n");151 seq_puts(s, " region (in hex) | erase mask | overlaid\n");
146 seq_puts(s, " ------------------+------------+----------\n");152 seq_puts(s, " ------------------+------------+---------\n");
147 for (i = 0; i < erase_map->n_regions; i++) {153 for (i = 0; i < erase_map->n_regions; i++) {
148 u64 start = region[i].offset;154 u64 start = region[i].offset;
149 u64 end = start + region[i].size - 1;155 u64 end = start + region[i].size - 1;
@@ -158,10 +164,69 @@ static int spi_nor_params_show(struct seq_file *s, void *data) · 8 unmodified lines
158 region[i].overlaid ? "yes" : "no");164 region[i].overlaid ? "yes" : "no");
159 }165 }
160 166
167 if (!spi_nor_has_default_locking_ops(nor))
168 return 0;
169
170 seq_puts(s, "\nlocked sectors\n");
171 seq_puts(s, " region (in hex) | status | #sectors\n");
172 seq_puts(s, " ------------------+----------+---------\n");
173
174 spi_nor_get_locked_range_sr(nor, nor->dfs_sr_cache, &lock_start, &lock_length);
175 if (!lock_length || lock_length == params->size) {
176 seq_printf(s, " %08llx-%08llx | %s | %llu\n", 0ULL, params->size - 1,
177 lock_length ? " locked" : "unlocked",
178 div_u64(params->size, min_prot_len));
179 } else if (!lock_start) {
180 seq_printf(s, " %08llx-%08llx | %s | %llu\n", 0ULL, lock_length - 1,
181 " locked", div_u64(lock_length, min_prot_len));
182 seq_printf(s, " %08llx-%08llx | %s | %llu\n", lock_length, params->size - 1,
183 "unlocked", div_u64(params->size - lock_length, min_prot_len));
184 } else {
185 seq_printf(s, " %08llx-%08llx | %s | %llu\n", 0ULL, lock_start - 1,
186 "unlocked", div_u64(lock_start, min_prot_len));
187 seq_printf(s, " %08llx-%08llx | %s | %llu\n", lock_start, params->size - 1,
188 " locked", div_u64(lock_length, min_prot_len));
189 }
190
161 return 0;191 return 0;
162}192}
163DEFINE_SHOW_ATTRIBUTE(spi_nor_params);193DEFINE_SHOW_ATTRIBUTE(spi_nor_params);
164 194
195static int spi_nor_locked_sectors_map_show(struct seq_file *s, void *data)
196{
197 struct spi_nor *nor = s->private;
198 struct spi_nor_flash_parameter *params = nor->params;
199 u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
200 unsigned int sector = 0;
201 u64 offset = 0;
202 bool locked;
203 int i;
204
205 seq_printf(s, "Locked sectors map (x: locked, .: unlocked, unit: %lldkiB)\n",
206 min_prot_len / 1024);
207 while (offset < params->size) {
208 seq_printf(s, " 0x%08llx (#%5d): ", offset, sector);
209 for (i = 0; i < 64 && offset < params->size; i++) {
210 locked = spi_nor_is_locked_sr(nor, offset, min_prot_len,
211 nor->dfs_sr_cache);
212 if (locked)
213 seq_puts(s, "x");
214 else
215 seq_puts(s, ".");
216
217 if (((i + 1) % 16) == 0)
218 seq_puts(s, " ");
219
220 offset += min_prot_len;
221 sector++;
222 }
223 seq_puts(s, "\n");
224 }
225
226 return 0;
227}
228DEFINE_SHOW_ATTRIBUTE(spi_nor_locked_sectors_map);
229
165static void spi_nor_print_read_cmd(struct seq_file *s, u32 cap,230static void spi_nor_print_read_cmd(struct seq_file *s, u32 cap,
166 struct spi_nor_read_command *cmd)231 struct spi_nor_read_command *cmd)
167{232{
@@ -247,6 +312,9 @@ void spi_nor_debugfs_register(struct spi_nor *nor) · 79 unmodified lines
247 debugfs_create_file("params", 0444, d, nor, &spi_nor_params_fops);312 debugfs_create_file("params", 0444, d, nor, &spi_nor_params_fops);
248 debugfs_create_file("capabilities", 0444, d, nor,313 debugfs_create_file("capabilities", 0444, d, nor,
249 &spi_nor_capabilities_fops);314 &spi_nor_capabilities_fops);
315 if (spi_nor_has_default_locking_ops(nor))
316 debugfs_create_file("locked-sectors-map", 0444, d, nor,
317 &spi_nor_locked_sectors_map_fops);
250}318}
251 319
252void spi_nor_debugfs_shutdown(void)320void spi_nor_debugfs_shutdown(void)
drivers/mtd/spi-nor/spansion.c+6−1
@@ -674,7 +674,9 @@ static int s25hx_t_late_init(struct spi_nor *nor) · 673 unmodified lines
674 params->ready = cypress_nor_sr_ready_and_clear;674 params->ready = cypress_nor_sr_ready_and_clear;
675 cypress_nor_ecc_init(nor);675 cypress_nor_ecc_init(nor);
676 676
677 params->die_erase_opcode = SPINOR_OP_CYPRESS_DIE_ERASE;677 if (params->n_dice > 1)
678 params->die_erase_opcode = SPINOR_OP_CYPRESS_DIE_ERASE;
679
678 return 0;680 return 0;
679}681}
680 682
@@ -760,6 +762,9 @@ static int s28hx_t_late_init(struct spi_nor *nor) · 79 unmodified lines
760 params->ready = cypress_nor_sr_ready_and_clear;762 params->ready = cypress_nor_sr_ready_and_clear;
761 cypress_nor_ecc_init(nor);763 cypress_nor_ecc_init(nor);
762 764
765 if (params->n_dice > 1)
766 params->die_erase_opcode = SPINOR_OP_CYPRESS_DIE_ERASE;
767
763 return 0;768 return 0;
764}769}
765 770
drivers/mtd/spi-nor/swp.c+291−74
@@ -34,7 +34,16 @@ static u8 spi_nor_get_sr_tb_mask(struct spi_nor *nor) · 33 unmodified lines
34 return 0;34 return 0;
35}35}
36 36
37static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)37static u8 spi_nor_get_sr_cmp_mask(struct spi_nor *nor)
38{
39 if (!(nor->flags & SNOR_F_NO_READ_CR) &&
40 nor->flags & SNOR_F_HAS_SR2_CMP_BIT6)
41 return SR2_CMP_BIT6;
42 else
43 return 0;
44}
45
46u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
38{47{
39 unsigned int bp_slots, bp_slots_needed;48 unsigned int bp_slots, bp_slots_needed;
40 /*49 /*
@@ -55,13 +64,16 @@ static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) · 14 unmodified lines
55 return sector_size;64 return sector_size;
56}65}
57 66
58static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,67void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_t *ofs,
59 u64 *len)68 u64 *len)
60{69{
61 u64 min_prot_len;70 u64 min_prot_len;
62 u8 mask = spi_nor_get_sr_bp_mask(nor);71 u8 bp_mask = spi_nor_get_sr_bp_mask(nor);
63 u8 tb_mask = spi_nor_get_sr_tb_mask(nor);72 u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
64 u8 bp, val = sr & mask;73 u8 cmp_mask = spi_nor_get_sr_cmp_mask(nor);
74 u8 bp, val = sr[0] & bp_mask;
75 bool tb = (nor->flags & SNOR_F_HAS_SR_TB) ? sr[0] & tb_mask : 0;
76 bool cmp = sr[1] & cmp_mask;
65 77
66 if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6)78 if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6)
67 val = (val & ~SR_BP3_BIT6) | SR_BP3;79 val = (val & ~SR_BP3_BIT6) | SR_BP3;
@@ -69,22 +81,37 @@ static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs, · 1 unmodified line
69 bp = val >> SR_BP_SHIFT;81 bp = val >> SR_BP_SHIFT;
70 82
71 if (!bp) {83 if (!bp) {
72 /* No protection */84 if (!cmp) {
73 *ofs = 0;85 /* No protection */
74 *len = 0;86 *ofs = 0;
87 *len = 0;
88 } else {
89 /* Full protection */
90 *ofs = 0;
91 *len = nor->params->size;
92 }
75 return;93 return;
76 }94 }
77 95
78 min_prot_len = spi_nor_get_min_prot_length_sr(nor);96 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
79 *len = min_prot_len << (bp - 1);97 *len = min_prot_len << (bp - 1);
80
81 if (*len > nor->params->size)98 if (*len > nor->params->size)
82 *len = nor->params->size;99 *len = nor->params->size;
83 100
84 if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask)101 if (cmp)
85 *ofs = 0;102 *len = nor->params->size - *len;
86 else103
87 *ofs = nor->params->size - *len;104 if (!cmp) {
105 if (tb)
106 *ofs = 0;
107 else
108 *ofs = nor->params->size - *len;
109 } else {
110 if (tb)
111 *ofs = nor->params->size - *len;
112 else
113 *ofs = 0;
114 }
88}115}
89 116
90/*117/*
@@ -92,7 +119,7 @@ static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs, · 1 unmodified line
92 * (if @locked is false); false otherwise.119 * (if @locked is false); false otherwise.
93 */120 */
94static bool spi_nor_check_lock_status_sr(struct spi_nor *nor, loff_t ofs,121static bool spi_nor_check_lock_status_sr(struct spi_nor *nor, loff_t ofs,
95 u64 len, u8 sr, bool locked)122 u64 len, const u8 *sr, bool locked)
96{123{
97 loff_t lock_offs, lock_offs_max, offs_max;124 loff_t lock_offs, lock_offs_max, offs_max;
98 u64 lock_len;125 u64 lock_len;
@@ -113,27 +140,102 @@ static bool spi_nor_check_lock_status_sr(struct spi_nor *nor, loff_t ofs, · 14 unmodified lines
113 return (ofs >= lock_offs_max) || (offs_max <= lock_offs);140 return (ofs >= lock_offs_max) || (offs_max <= lock_offs);
114}141}
115 142
116static bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, u64 len, u8 sr)143bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, u64 len, const u8 *sr)
117{144{
118 return spi_nor_check_lock_status_sr(nor, ofs, len, sr, true);145 return spi_nor_check_lock_status_sr(nor, ofs, len, sr, true);
119}146}
120 147
121static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len,148static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len,
122 u8 sr)149 const u8 *sr)
123{150{
124 return spi_nor_check_lock_status_sr(nor, ofs, len, sr, false);151 return spi_nor_check_lock_status_sr(nor, ofs, len, sr, false);
125}152}
126 153
154static int spi_nor_sr_set_bp_mask(struct spi_nor *nor, u8 *sr, u8 pow)
155{
156 u8 mask = spi_nor_get_sr_bp_mask(nor);
157 u8 val = pow << SR_BP_SHIFT;
158
159 if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3)
160 val = (val & ~SR_BP3) | SR_BP3_BIT6;
161
162 if (val & ~mask)
163 return -EINVAL;
164
165 sr[0] |= val;
166
167 return 0;
168}
169
170static int spi_nor_build_sr(struct spi_nor *nor, const u8 *old_sr, u8 *new_sr,
171 u8 pow, bool use_top, bool cmp)
172{
173 u8 bp_mask = spi_nor_get_sr_bp_mask(nor);
174 u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
175 u8 cmp_mask = spi_nor_get_sr_cmp_mask(nor);
176 int ret;
177
178 new_sr[0] = old_sr[0] & ~bp_mask & ~tb_mask;
179 new_sr[1] = old_sr[1] & ~cmp_mask;
180
181 /* Build BP field */
182 ret = spi_nor_sr_set_bp_mask(nor, &new_sr[0], pow);
183 if (ret)
184 return ret;
185
186 /* Build TB field */
187 if ((!cmp && !use_top) || (cmp && use_top))
188 new_sr[0] |= tb_mask;
189
190 /* Build CMP field */
191 if (cmp)
192 new_sr[1] |= cmp_mask;
193
194 return 0;
195}
196
197/*
198 * Keep a local cache containing all lock-related bits for debugfs use only.
199 * This way, debugfs never needs to access the flash directly.
200 */
201void spi_nor_cache_sr_lock_bits(struct spi_nor *nor, u8 *sr)
202{
203 u8 bp_mask = spi_nor_get_sr_bp_mask(nor);
204 u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
205 u8 cmp_mask = spi_nor_get_sr_cmp_mask(nor);
206 u8 sr_cr[2] = {};
207
208
209 if (!sr) {
210 if (spi_nor_read_sr(nor, nor->bouncebuf))
211 return;
212
213 sr_cr[0] = nor->bouncebuf[0];
214
215 if (!(nor->flags & SNOR_F_NO_READ_CR)) {
216 if (spi_nor_read_cr(nor, nor->bouncebuf))
217 return;
218 }
219
220 sr_cr[1] = nor->bouncebuf[0];
221 sr = sr_cr;
222 }
223
224 nor->dfs_sr_cache[0] = sr[0] & (bp_mask | tb_mask | SR_SRWD);
225 nor->dfs_sr_cache[1] = sr[1] & cmp_mask;
226}
227
127/*228/*
128 * Lock a region of the flash. Compatible with ST Micro and similar flash.229 * Lock a region of the flash. Compatible with ST Micro and similar flash.
129 * Supports the block protection bits BP{0,1,2}/BP{0,1,2,3} in the status230 * Supports the block protection bits BP{0,1,2}/BP{0,1,2,3} in the status
130 * register231 * register
131 * (SR). Does not support these features found in newer SR bitfields:232 * (SR). Does not support these features found in newer SR bitfields:
132 * - SEC: sector/block protect - only handle SEC=0 (block protect)233 * - SEC: sector/block protect - only handle SEC=0 (block protect)
133 * - CMP: complement protect - only support CMP=0 (range is not complemented)
134 *234 *
135 * Support for the following is provided conditionally for some flash:235 * Support for the following is provided conditionally for some flash:
136 * - TB: top/bottom protect236 * - TB: top/bottom protect
237 * - CMP: complement protect (BP and TP describe the unlocked part, while
238 * the reminder is locked)
137 *239 *
138 * Sample table portion for 8MB flash (Winbond w25q64fw):240 * Sample table portion for 8MB flash (Winbond w25q64fw):
139 *241 *
@@ -159,20 +261,31 @@ static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len, · 19 unmodified lines
159 */261 */
160static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)262static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
161{263{
162 u64 min_prot_len;264 u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
163 int ret, status_old, status_new;265 u8 status_old[2] = {}, status_new[2] = {}, status_new_cmp[2] = {};
164 u8 mask = spi_nor_get_sr_bp_mask(nor);266 u8 *best_status_new = status_new;
165 u8 tb_mask = spi_nor_get_sr_tb_mask(nor);267 loff_t ofs_old, ofs_new, ofs_new_cmp;
166 u8 pow, val;268 u64 len_old, len_new, len_new_cmp;
167 loff_t lock_len;269 loff_t lock_len;
168 bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;270 bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB,
271 can_be_cmp = spi_nor_get_sr_cmp_mask(nor);
169 bool use_top;272 bool use_top;
273 int ret;
274 u8 pow;
170 275
171 ret = spi_nor_read_sr(nor, nor->bouncebuf);276 ret = spi_nor_read_sr(nor, nor->bouncebuf);
172 if (ret)277 if (ret)
173 return ret;278 return ret;
174 279
175 status_old = nor->bouncebuf[0];280 status_old[0] = nor->bouncebuf[0];
281
282 if (!(nor->flags & SNOR_F_NO_READ_CR)) {
283 ret = spi_nor_read_cr(nor, nor->bouncebuf);
284 if (ret)
285 return ret;
286
287 status_old[1] = nor->bouncebuf[0];
288 }
176 289
177 /* If nothing in our range is unlocked, we don't need to do anything */290 /* If nothing in our range is unlocked, we don't need to do anything */
178 if (spi_nor_is_locked_sr(nor, ofs, len, status_old))291 if (spi_nor_is_locked_sr(nor, ofs, len, status_old))
@@ -199,46 +312,82 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len) · 20 unmodified lines
199 else312 else
200 lock_len = ofs + len;313 lock_len = ofs + len;
201 314
202 if (lock_len == nor->params->size) {315 if (lock_len == nor->params->size)
203 val = mask;316 pow = (nor->flags & SNOR_F_HAS_4BIT_BP) ? GENMASK(3, 0) : GENMASK(2, 0);
204 } else {317 else
205 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
206 pow = ilog2(lock_len) - ilog2(min_prot_len) + 1;318 pow = ilog2(lock_len) - ilog2(min_prot_len) + 1;
207 val = pow << SR_BP_SHIFT;
208
209 if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3)
210 val = (val & ~SR_BP3) | SR_BP3_BIT6;
211 319
212 if (val & ~mask)320 ret = spi_nor_build_sr(nor, status_old, status_new, pow, use_top, false);
213 return -EINVAL;321 if (ret)
322 return ret;
214 323
215 /* Don't "lock" with no region! */324 /*
216 if (!(val & mask))325 * In case the region asked is not fully met, maybe we can try with the
217 return -EINVAL;326 * complement feature
327 */
328 spi_nor_get_locked_range_sr(nor, status_new, &ofs_new, &len_new);
329 if (can_be_cmp && len_new != lock_len) {
330 pow = ilog2(nor->params->size - lock_len) - ilog2(min_prot_len) + 1;
331 ret = spi_nor_build_sr(nor, status_old, status_new_cmp, pow, use_top, true);
332 if (ret)
333 return ret;
334
335 /*
336 * ilog2() "floors" the result, which means in some cases we may have to
337 * manually reduce the scope when the complement feature is used.
338 * The uAPI is to never lock more than what is requested, but less is accepted.
339 * Make sure we are not covering a too wide range, reduce it otherwise.
340 */
341 spi_nor_get_locked_range_sr(nor, status_new_cmp, &ofs_new_cmp, &len_new_cmp);
342 if (len_new_cmp > lock_len) {
343 pow++;
344 ret = spi_nor_build_sr(nor, status_old, status_new_cmp, pow, use_top, true);
345 if (ret)
346 return ret;
347 }
348
349 /* Pick the CMP configuration if we cover a closer range */
350 spi_nor_get_locked_range_sr(nor, status_new, &ofs_new, &len_new);
351 spi_nor_get_locked_range_sr(nor, status_new_cmp, &ofs_new_cmp, &len_new_cmp);
352 if (len_new_cmp <= lock_len &&
353 (lock_len - len_new_cmp) < (lock_len - len_new))
354 best_status_new = status_new_cmp;
218 }355 }
219 356
220 status_new = (status_old & ~mask & ~tb_mask) | val;
221
222 /*357 /*
223 * Disallow further writes if WP# pin is neither left floating nor358 * Disallow further writes if WP# pin is neither left floating nor
224 * wrongly tied to GND (that includes internal pull-downs).359 * wrongly tied to GND (that includes internal pull-downs).
225 * WP# pin hard strapped to GND can be a valid use case.360 * WP# pin hard strapped to GND can be a valid use case.
226 */361 */
227 if (!(nor->flags & SNOR_F_NO_WP))362 if (!(nor->flags & SNOR_F_NO_WP))
228 status_new |= SR_SRWD;363 best_status_new[0] |= SR_SRWD;
364
365 spi_nor_get_locked_range_sr(nor, status_old, &ofs_old, &len_old);
366 spi_nor_get_locked_range_sr(nor, best_status_new, &ofs_new, &len_new);
229 367
230 if (!use_top)368 /* Don't "lock" with no region! */
231 status_new |= tb_mask;369 if (!len_new)
370 return -EINVAL;
232 371
233 /* Don't bother if they're the same */372 /* Don't bother if they're the same */
234 if (status_new == status_old)373 if (best_status_new[0] == status_old[0] && best_status_new[1] == status_old[1])
235 return 0;374 return 0;
236 375
237 /* Only modify protection if it will not unlock other areas */376 /* Only modify protection if it will not unlock other areas */
238 if ((status_new & mask) < (status_old & mask))377 if (len_old &&
378 (ofs_old < ofs_new || (ofs_new + len_new) < (ofs_old + len_old)))
239 return -EINVAL;379 return -EINVAL;
240 380
241 return spi_nor_write_sr_and_check(nor, status_new);381 if (nor->flags & SNOR_F_NO_READ_CR)
382 ret = spi_nor_write_sr_and_check(nor, best_status_new[0]);
383 else
384 ret = spi_nor_write_sr_cr_and_check(nor, best_status_new);
385 if (ret)
386 return ret;
387
388 spi_nor_cache_sr_lock_bits(nor, best_status_new);
389
390 return 0;
242}391}
243 392
244/*393/*
@@ -248,20 +397,31 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len) · 3 unmodified lines
248 */397 */
249static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)398static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
250{399{
251 u64 min_prot_len;400 u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
252 int ret, status_old, status_new;401 u8 status_old[2] = {}, status_new[2] = {}, status_new_cmp[2] = {};
253 u8 mask = spi_nor_get_sr_bp_mask(nor);402 u8 *best_status_new = status_new;
254 u8 tb_mask = spi_nor_get_sr_tb_mask(nor);403 loff_t ofs_old, ofs_new, ofs_new_cmp;
255 u8 pow, val;404 u64 len_old, len_new, len_new_cmp;
256 loff_t lock_len;405 loff_t lock_len;
257 bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB;406 bool can_be_top = true, can_be_bottom = nor->flags & SNOR_F_HAS_SR_TB,
407 can_be_cmp = spi_nor_get_sr_cmp_mask(nor);
258 bool use_top;408 bool use_top;
409 int ret;
410 u8 pow;
259 411
260 ret = spi_nor_read_sr(nor, nor->bouncebuf);412 ret = spi_nor_read_sr(nor, nor->bouncebuf);
261 if (ret)413 if (ret)
262 return ret;414 return ret;
263 415
264 status_old = nor->bouncebuf[0];416 status_old[0] = nor->bouncebuf[0];
417
418 if (!(nor->flags & SNOR_F_NO_READ_CR)) {
419 ret = spi_nor_read_cr(nor, nor->bouncebuf);
420 if (ret)
421 return ret;
422
423 status_old[1] = nor->bouncebuf[0];
424 }
265 425
266 /* If nothing in our range is locked, we don't need to do anything */426 /* If nothing in our range is locked, we don't need to do anything */
267 if (spi_nor_is_unlocked_sr(nor, ofs, len, status_old))427 if (spi_nor_is_unlocked_sr(nor, ofs, len, status_old))
@@ -282,45 +442,86 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len) · 14 unmodified lines
282 /* Prefer top, if both are valid */442 /* Prefer top, if both are valid */
283 use_top = can_be_top;443 use_top = can_be_top;
284 444
285 /* lock_len: length of region that should remain locked */445 /*
286 if (use_top)446 * lock_len: length of region that should remain locked.
447 *
448 * When can_be_top and can_be_bottom booleans are true, both adjacent
449 * regions are unlocked, thus the entire flash can be unlocked.
450 */
451 if (can_be_top && can_be_bottom)
452 lock_len = 0;
453 else if (use_top)
287 lock_len = nor->params->size - (ofs + len);454 lock_len = nor->params->size - (ofs + len);
288 else455 else
289 lock_len = ofs;456 lock_len = ofs;
290 457
291 if (lock_len == 0) {458 if (lock_len == 0)
292 val = 0; /* fully unlocked */459 pow = 0; /* fully unlocked */
293 } else {460 else
294 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
295 pow = ilog2(lock_len) - ilog2(min_prot_len) + 1;461 pow = ilog2(lock_len) - ilog2(min_prot_len) + 1;
296 val = pow << SR_BP_SHIFT;
297 462
298 if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3)463 ret = spi_nor_build_sr(nor, status_old, status_new, pow, use_top, false);
299 val = (val & ~SR_BP3) | SR_BP3_BIT6;464 if (ret)
465 return ret;
300 466
301 /* Some power-of-two sizes are not supported */467 /*
302 if (val & ~mask)468 * In case the region asked is not fully met, maybe we can try with the
303 return -EINVAL;469 * complement feature
470 */
471 spi_nor_get_locked_range_sr(nor, status_new, &ofs_new, &len_new);
472 if (can_be_cmp && len_new != lock_len) {
473 pow = ilog2(nor->params->size - lock_len) - ilog2(min_prot_len) + 1;
474 ret = spi_nor_build_sr(nor, status_old, status_new_cmp, pow, use_top, true);
475 if (ret)
476 return ret;
477
478 /*
479 * ilog2() "floors" the result, which means in some cases we may have to
480 * manually reduce the scope when the complement feature is used.
481 * The uAPI is to never unlock more than what is requested, but less is accepted.
482 * Make sure we are not covering a too small range, increase it otherwise.
483 */
484 spi_nor_get_locked_range_sr(nor, status_new_cmp, &ofs_new_cmp, &len_new_cmp);
485 if (len_new_cmp < lock_len) {
486 pow--;
487 ret = spi_nor_build_sr(nor, status_old, status_new_cmp, pow, use_top, true);
488 if (ret)
489 return ret;
490 }
491
492 /* Pick the CMP configuration if we cover a closer range */
493 spi_nor_get_locked_range_sr(nor, status_new, &ofs_new, &len_new);
494 spi_nor_get_locked_range_sr(nor, status_new_cmp, &ofs_new_cmp, &len_new_cmp);
495 if (len_new_cmp <= lock_len &&
496 (lock_len - len_new_cmp) < (lock_len - len_new))
497 best_status_new = status_new_cmp;
304 }498 }
305 499
306 status_new = (status_old & ~mask & ~tb_mask) | val;
307
308 /* Don't protect status register if we're fully unlocked */500 /* Don't protect status register if we're fully unlocked */
309 if (lock_len == 0)501 if (lock_len == 0)
310 status_new &= ~SR_SRWD;502 best_status_new[0] &= ~SR_SRWD;
311
312 if (!use_top)
313 status_new |= tb_mask;
314 503
315 /* Don't bother if they're the same */504 /* Don't bother if they're the same */
316 if (status_new == status_old)505 if (best_status_new[0] == status_old[0] && best_status_new[1] == status_old[1])
317 return 0;506 return 0;
318 507
319 /* Only modify protection if it will not lock other areas */508 /* Only modify protection if it will not lock other areas */
320 if ((status_new & mask) > (status_old & mask))509 spi_nor_get_locked_range_sr(nor, status_old, &ofs_old, &len_old);
510 spi_nor_get_locked_range_sr(nor, best_status_new, &ofs_new, &len_new);
511 if (len_old && len_new &&
512 (ofs_new < ofs_old || (ofs_old + len_old) < (ofs_new + len_new)))
321 return -EINVAL;513 return -EINVAL;
322 514
323 return spi_nor_write_sr_and_check(nor, status_new);515 if (nor->flags & SNOR_F_NO_READ_CR)
516 ret = spi_nor_write_sr_and_check(nor, best_status_new[0]);
517 else
518 ret = spi_nor_write_sr_cr_and_check(nor, best_status_new);
519 if (ret)
520 return ret;
521
522 spi_nor_cache_sr_lock_bits(nor, best_status_new);
523
524 return 0;
324}525}
325 526
326/*527/*
@@ -332,13 +533,24 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len) · 5 unmodified lines
332 */533 */
333static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, u64 len)534static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, u64 len)
334{535{
536 u8 sr_cr[2] = {};
335 int ret;537 int ret;
336 538
337 ret = spi_nor_read_sr(nor, nor->bouncebuf);539 ret = spi_nor_read_sr(nor, nor->bouncebuf);
338 if (ret)540 if (ret)
339 return ret;541 return ret;
340 542
341 return spi_nor_is_locked_sr(nor, ofs, len, nor->bouncebuf[0]);543 sr_cr[0] = nor->bouncebuf[0];
544
545 if (!(nor->flags & SNOR_F_NO_READ_CR)) {
546 ret = spi_nor_read_cr(nor, nor->bouncebuf);
547 if (ret)
548 return ret;
549
550 sr_cr[1] = nor->bouncebuf[0];
551 }
552
553 return spi_nor_is_locked_sr(nor, ofs, len, sr_cr);
342}554}
343 555
344static const struct spi_nor_locking_ops spi_nor_sr_locking_ops = {556static const struct spi_nor_locking_ops spi_nor_sr_locking_ops = {
@@ -352,6 +564,11 @@ void spi_nor_init_default_locking_ops(struct spi_nor *nor) · 7 unmodified lines
352 nor->params->locking_ops = &spi_nor_sr_locking_ops;564 nor->params->locking_ops = &spi_nor_sr_locking_ops;
353}565}
354 566
567bool spi_nor_has_default_locking_ops(struct spi_nor *nor)
568{
569 return nor->params->locking_ops == &spi_nor_sr_locking_ops;
570}
571
355static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, u64 len)572static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, u64 len)
356{573{
357 struct spi_nor *nor = mtd_to_spi_nor(mtd);574 struct spi_nor *nor = mtd_to_spi_nor(mtd);
drivers/mtd/spi-nor/winbond.c+35−6
@@ -73,6 +73,26 @@ static const struct spi_nor_fixups w25q256_fixups = { · 72 unmodified lines
73 .post_bfpt = w25q256_post_bfpt_fixups,73 .post_bfpt = w25q256_post_bfpt_fixups,
74};74};
75 75
76static int
77winbond_rdcr_post_bfpt_fixup(struct spi_nor *nor,
78 const struct sfdp_parameter_header *bfpt_header,
79 const struct sfdp_bfpt *bfpt)
80{
81 /*
82 * W25H02NW, unlike its W25H512NW nor W25H01NW cousins, improperly sets
83 * the QE BFPT configuration bits, indicating a non readable CR. This is
84 * both incorrect and impractical, as the chip features a CMP bit for its
85 * locking scheme that lays in the Control Register, and needs to be read.
86 */
87 nor->flags &= ~SNOR_F_NO_READ_CR;
88
89 return 0;
90}
91
92static const struct spi_nor_fixups winbond_rdcr_fixup = {
93 .post_bfpt = winbond_rdcr_post_bfpt_fixup,
94};
95
76/**96/**
77 * winbond_nor_select_die() - Set active die.97 * winbond_nor_select_die() - Set active die.
78 * @nor: pointer to 'struct spi_nor'.98 * @nor: pointer to 'struct spi_nor'.
@@ -348,27 +368,36 @@ static const struct flash_info winbond_nor_parts[] = { · 269 unmodified lines
348 }, {368 }, {
349 /* W25Q01NWxxIQ */369 /* W25Q01NWxxIQ */
350 .id = SNOR_ID(0xef, 0x60, 0x21),370 .id = SNOR_ID(0xef, 0x60, 0x21),
351 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP,371 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 |
372 SPI_NOR_4BIT_BP | SPI_NOR_HAS_CMP,
373 .fixups = &winbond_rdcr_fixup,
352 }, {374 }, {
353 /* W25Q01NWxxIM */375 /* W25Q01NWxxIM */
354 .id = SNOR_ID(0xef, 0x80, 0x21),376 .id = SNOR_ID(0xef, 0x80, 0x21),
355 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP,377 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 |
378 SPI_NOR_4BIT_BP | SPI_NOR_HAS_CMP,
356 }, {379 }, {
357 /* W25Q02NWxxIM */380 /* W25Q02NWxxIM */
358 .id = SNOR_ID(0xef, 0x80, 0x22),381 .id = SNOR_ID(0xef, 0x80, 0x22),
359 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP,382 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 |
383 SPI_NOR_4BIT_BP | SPI_NOR_HAS_CMP,
384 .fixups = &winbond_rdcr_fixup,
360 }, {385 }, {
361 /* W25H512NWxxAM */386 /* W25H512NWxxAM */
362 .id = SNOR_ID(0xef, 0xa0, 0x20),387 .id = SNOR_ID(0xef, 0xa0, 0x20),
363 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP,388 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 |
389 SPI_NOR_4BIT_BP | SPI_NOR_HAS_CMP,
364 }, {390 }, {
365 /* W25H01NWxxAM */391 /* W25H01NWxxAM */
366 .id = SNOR_ID(0xef, 0xa0, 0x21),392 .id = SNOR_ID(0xef, 0xa0, 0x21),
367 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP,393 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 |
394 SPI_NOR_4BIT_BP | SPI_NOR_HAS_CMP,
368 }, {395 }, {
369 /* W25H02NWxxAM */396 /* W25H02NWxxAM */
370 .id = SNOR_ID(0xef, 0xa0, 0x22),397 .id = SNOR_ID(0xef, 0xa0, 0x22),
371 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 | SPI_NOR_4BIT_BP,398 .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6 |
399 SPI_NOR_4BIT_BP | SPI_NOR_HAS_CMP,
400 .fixups = &winbond_rdcr_fixup,
372 },401 },
373};402};
374 403
include/linux/mtd/spi-nor.h+5−2
@@ -21,8 +21,8 @@ · 20 unmodified lines
21/* Flash opcodes. */21/* Flash opcodes. */
22#define SPINOR_OP_WRDI 0x04 /* Write disable */22#define SPINOR_OP_WRDI 0x04 /* Write disable */
23#define SPINOR_OP_WREN 0x06 /* Write enable */23#define SPINOR_OP_WREN 0x06 /* Write enable */
24#define SPINOR_OP_RDSR 0x05 /* Read status register */24#define SPINOR_OP_RDSR 0x05 /* Read status register 1 */
25#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */25#define SPINOR_OP_WRSR 0x01 /* Write status register 1 */
26#define SPINOR_OP_RDSR2 0x3f /* Read status register 2 */26#define SPINOR_OP_RDSR2 0x3f /* Read status register 2 */
27#define SPINOR_OP_WRSR2 0x3e /* Write status register 2 */27#define SPINOR_OP_WRSR2 0x3e /* Write status register 2 */
28#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */28#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */
@@ -125,6 +125,7 @@ · 96 unmodified lines
125#define SR2_LB1 BIT(3) /* Security Register Lock Bit 1 */125#define SR2_LB1 BIT(3) /* Security Register Lock Bit 1 */
126#define SR2_LB2 BIT(4) /* Security Register Lock Bit 2 */126#define SR2_LB2 BIT(4) /* Security Register Lock Bit 2 */
127#define SR2_LB3 BIT(5) /* Security Register Lock Bit 3 */127#define SR2_LB3 BIT(5) /* Security Register Lock Bit 3 */
128#define SR2_CMP_BIT6 BIT(6)
128#define SR2_QUAD_EN_BIT7 BIT(7)129#define SR2_QUAD_EN_BIT7 BIT(7)
129 130
130/* Supported SPI protocols */131/* Supported SPI protocols */
@@ -371,6 +372,7 @@ struct spi_nor_flash_parameter; · 240 unmodified lines
371 * @reg_proto: the SPI protocol for read_reg/write_reg/erase operations372 * @reg_proto: the SPI protocol for read_reg/write_reg/erase operations
372 * @sfdp: the SFDP data of the flash373 * @sfdp: the SFDP data of the flash
373 * @debugfs_root: pointer to the debugfs directory374 * @debugfs_root: pointer to the debugfs directory
375 * @dfs_sr_cache: Status Register cached value for debugfs use only
374 * @controller_ops: SPI NOR controller driver specific operations.376 * @controller_ops: SPI NOR controller driver specific operations.
375 * @params: [FLASH-SPECIFIC] SPI NOR flash parameters and settings.377 * @params: [FLASH-SPECIFIC] SPI NOR flash parameters and settings.
376 * The structure includes legacy flash parameters and378 * The structure includes legacy flash parameters and
@@ -409,6 +411,7 @@ struct spi_nor { · 32 unmodified lines
409 enum spi_nor_cmd_ext cmd_ext_type;411 enum spi_nor_cmd_ext cmd_ext_type;
410 struct sfdp *sfdp;412 struct sfdp *sfdp;
411 struct dentry *debugfs_root;413 struct dentry *debugfs_root;
414 u8 dfs_sr_cache[2];
412 415
413 const struct spi_nor_controller_ops *controller_ops;416 const struct spi_nor_controller_ops *controller_ops;
414 417

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t