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
203203 mtd.writesize = 1
204204 mtd.oobsize = 0
205205 regions = 0
206+
207+5) 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 @@
11 # SPDX-License-Identifier: GPL-2.0-only
22 menuconfig MTD_SPI_NOR
33 tristate "SPI NOR device support"
4− depends on MTD
54 depends on MTD && SPI_MASTER
65 select SPI_MEM
76 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
869869 ret = spi_nor_read_cr(nor, &sr_cr[1]);
870870 if (ret)
871871 return ret;
872− } else if (spi_nor_get_protocol_width(nor->read_proto) == 4 &&
873− spi_nor_get_protocol_width(nor->write_proto) == 4 &&
872+ } else if ((spi_nor_get_protocol_width(nor->read_proto) == 4 ||
873+ spi_nor_get_protocol_width(nor->write_proto) == 4) &&
874874 nor->params->quad_enable) {
875875 /*
876876 * 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
976976 return 0;
977977 }
978978
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+ */
989+static 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+
9791027 /**
9801028 * spi_nor_write_sr_and_check() - Write the Status Register 1 and ensure that
9811029 * 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
9931041 return spi_nor_write_sr1_and_check(nor, sr1);
9941042 }
9951043
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+ */
1053+int 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+
9961061 /**
9971062 * spi_nor_write_sr2() - Write the Status Register 2 using the
9981063 * SPINOR_OP_WRSR2 (3eh) command.
@@ -2909,6 +2974,9 @@ static void spi_nor_init_flags(struct spi_nor *nor) · 1910 unmodified lines
29092974 nor->flags |= SNOR_F_HAS_SR_BP3_BIT6;
29102975 }
29112976
2977+ if (flags & SPI_NOR_HAS_CMP)
2978+ nor->flags |= SNOR_F_HAS_SR2_CMP_BIT6;
2979+
29122980 if (flags & SPI_NOR_RWW && nor->params->n_banks > 1 &&
29132981 !nor->controller_ops)
29142982 nor->flags |= SNOR_F_RWW;
@@ -3261,10 +3329,12 @@ static int spi_nor_init(struct spi_nor *nor) · 346 unmodified lines
32613329 * protection bits are volatile. The latter is indicated by
32623330 * SNOR_F_SWP_IS_VOLATILE.
32633331 */
3332+ spi_nor_cache_sr_lock_bits(nor, NULL);
32643333 if (IS_ENABLED(CONFIG_MTD_SPI_NOR_SWP_DISABLE) ||
32653334 (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)) {
32673336 spi_nor_try_unlock_all(nor);
3337+ }
32683338
32693339 if (nor->addr_nbytes == 4 &&
32703340 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
141141 SNOR_F_ECC = BIT(15),
142142 SNOR_F_NO_WP = BIT(16),
143143 SNOR_F_SWAP16 = BIT(17),
144+ SNOR_F_HAS_SR2_CMP_BIT6 = BIT(18),
144145 };
145146
146147 struct spi_nor_read_command {
@@ -279,9 +280,17 @@ struct spi_nor_erase_map { · 132 unmodified lines
279280
280281 /**
281282 * struct spi_nor_locking_ops - SPI NOR locking methods
282− * @lock: lock a region of the SPI NOR.
283− * @unlock: unlock a region of the SPI NOR.
284− * @is_locked: check if a region of the SPI NOR is completely locked
283+ * @lock: lock a region of the SPI NOR, never locks more than what is
284+ * requested, ie. may lock less.
285+ * @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.
285294 */
286295 struct spi_nor_locking_ops {
287296 int (*lock)(struct spi_nor *nor, loff_t ofs, u64 len);
@@ -483,6 +492,8 @@ struct spi_nor_id { · 195 unmodified lines
483492 * SPI_NOR_NO_ERASE: no erase command needed.
484493 * SPI_NOR_QUAD_PP: flash supports Quad Input Page Program.
485494 * 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.
486497 *
487498 * @no_sfdp_flags: flags that indicate support that can be discovered via SFDP.
488499 * Used when SFDP tables are not defined in the flash. These
@@ -531,6 +542,7 @@ struct flash_info { · 42 unmodified lines
531542 #define SPI_NOR_NO_ERASE BIT(6)
532543 #define SPI_NOR_QUAD_PP BIT(8)
533544 #define SPI_NOR_RWW BIT(9)
545+#define SPI_NOR_HAS_CMP BIT(10)
534546
535547 u8 no_sfdp_flags;
536548 #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
632644 int spi_nor_write_sr(struct spi_nor *nor, const u8 *sr, size_t len);
633645 int spi_nor_write_sr_and_check(struct spi_nor *nor, u8 sr1);
634646 int spi_nor_write_16bit_cr_and_check(struct spi_nor *nor, u8 cr);
647+int spi_nor_write_sr_cr_and_check(struct spi_nor *nor, const u8 *regs);
635648
636649 ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
637650 u8 *buf);
@@ -672,7 +685,9 @@ int spi_nor_post_bfpt_fixups(struct spi_nor *nor, · 34 unmodified lines
672685 const struct sfdp_bfpt *bfpt);
673686
674687 void spi_nor_init_default_locking_ops(struct spi_nor *nor);
688+bool spi_nor_has_default_locking_ops(struct spi_nor *nor);
675689 void spi_nor_try_unlock_all(struct spi_nor *nor);
690+void spi_nor_cache_sr_lock_bits(struct spi_nor *nor, u8 *sr);
676691 void spi_nor_set_mtd_locking_ops(struct spi_nor *nor);
677692 void spi_nor_set_mtd_otp_ops(struct spi_nor *nor);
678693
@@ -705,6 +720,10 @@ static inline bool spi_nor_needs_sfdp(const struct spi_nor *nor) · 26 unmodified lines
705720 return !nor->info->size;
706721 }
707722
723+u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor);
724+void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_t *ofs, u64 *len);
725+bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, u64 len, const u8 *sr);
726+
708727 #ifdef CONFIG_DEBUG_FS
709728 void spi_nor_debugfs_register(struct spi_nor *nor);
710729 void spi_nor_debugfs_shutdown(void);
drivers/mtd/spi-nor/debugfs.c+70−2
@@ -1,6 +1,7 @@
11 // SPDX-License-Identifier: GPL-2.0
22
33 #include <linux/debugfs.h>
4+#include <linux/math64.h>
45 #include <linux/mtd/spi-nor.h>
56 #include <linux/spi/spi.h>
67 #include <linux/spi/spi-mem.h>
@@ -28,6 +29,8 @@ static const char *const snor_f_names[] = { · 21 unmodified lines
2829 SNOR_F_NAME(RWW),
2930 SNOR_F_NAME(ECC),
3031 SNOR_F_NAME(NO_WP),
32+ SNOR_F_NAME(SWAP16),
33+ SNOR_F_NAME(HAS_SR2_CMP_BIT6),
3134 };
3235 #undef SNOR_F_NAME
3336
@@ -76,11 +79,14 @@ static void spi_nor_print_flags(struct seq_file *s, unsigned long flags, · 42 unmodified lines
7679 static int spi_nor_params_show(struct seq_file *s, void *data)
7780 {
7881 struct spi_nor *nor = s->private;
82+ u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
7983 struct spi_nor_flash_parameter *params = nor->params;
8084 struct spi_nor_erase_map *erase_map = &params->erase_map;
8185 struct spi_nor_erase_region *region = erase_map->regions;
8286 const struct flash_info *info = nor->info;
8387 char buf[16], *str;
88+ loff_t lock_start;
89+ u64 lock_length;
8490 unsigned int i;
8591
8692 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
138144
139145 if (!(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
140146 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);
142148 }
143149
144150 seq_puts(s, "\nsector map\n");
145151 seq_puts(s, " region (in hex) | erase mask | overlaid\n");
146− seq_puts(s, " ------------------+------------+----------\n");
152+ seq_puts(s, " ------------------+------------+---------\n");
147153 for (i = 0; i < erase_map->n_regions; i++) {
148154 u64 start = region[i].offset;
149155 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
158164 region[i].overlaid ? "yes" : "no");
159165 }
160166
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+
161191 return 0;
162192 }
163193 DEFINE_SHOW_ATTRIBUTE(spi_nor_params);
164194
195+static 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+}
228+DEFINE_SHOW_ATTRIBUTE(spi_nor_locked_sectors_map);
229+
165230 static void spi_nor_print_read_cmd(struct seq_file *s, u32 cap,
166231 struct spi_nor_read_command *cmd)
167232 {
@@ -247,6 +312,9 @@ void spi_nor_debugfs_register(struct spi_nor *nor) · 79 unmodified lines
247312 debugfs_create_file("params", 0444, d, nor, &spi_nor_params_fops);
248313 debugfs_create_file("capabilities", 0444, d, nor,
249314 &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);
250318 }
251319
252320 void 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
674674 params->ready = cypress_nor_sr_ready_and_clear;
675675 cypress_nor_ecc_init(nor);
676676
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+
678680 return 0;
679681 }
680682
@@ -760,6 +762,9 @@ static int s28hx_t_late_init(struct spi_nor *nor) · 79 unmodified lines
760762 params->ready = cypress_nor_sr_ready_and_clear;
761763 cypress_nor_ecc_init(nor);
762764
765+ if (params->n_dice > 1)
766+ params->die_erase_opcode = SPINOR_OP_CYPRESS_DIE_ERASE;
767+
763768 return 0;
764769 }
765770
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
3434 return 0;
3535 }
3636
37−static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
37+static 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+
46+u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor)
3847 {
3948 unsigned int bp_slots, bp_slots_needed;
4049 /*
@@ -55,13 +64,16 @@ static u64 spi_nor_get_min_prot_length_sr(struct spi_nor *nor) · 14 unmodified lines
5564 return sector_size;
5665 }
5766
58−static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs,
59− u64 *len)
67+void spi_nor_get_locked_range_sr(struct spi_nor *nor, const u8 *sr, loff_t *ofs,
68+ u64 *len)
6069 {
6170 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);
6372 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;
6577
6678 if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3_BIT6)
6779 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
6981 bp = val >> SR_BP_SHIFT;
7082
7183 if (!bp) {
72− /* No protection */
73− *ofs = 0;
74− *len = 0;
84+ if (!cmp) {
85+ /* No protection */
86+ *ofs = 0;
87+ *len = 0;
88+ } else {
89+ /* Full protection */
90+ *ofs = 0;
91+ *len = nor->params->size;
92+ }
7593 return;
7694 }
7795
7896 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
7997 *len = min_prot_len << (bp - 1);
80−
8198 if (*len > nor->params->size)
8299 *len = nor->params->size;
83100
84− if (nor->flags & SNOR_F_HAS_SR_TB && sr & tb_mask)
85− *ofs = 0;
86− else
87− *ofs = nor->params->size - *len;
101+ if (cmp)
102+ *len = nor->params->size - *len;
103+
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+ }
88115 }
89116
90117 /*
@@ -92,7 +119,7 @@ static void spi_nor_get_locked_range_sr(struct spi_nor *nor, u8 sr, loff_t *ofs, · 1 unmodified line
92119 * (if @locked is false); false otherwise.
93120 */
94121 static 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)
96123 {
97124 loff_t lock_offs, lock_offs_max, offs_max;
98125 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
113140 return (ofs >= lock_offs_max) || (offs_max <= lock_offs);
114141 }
115142
116−static bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, u64 len, u8 sr)
143+bool spi_nor_is_locked_sr(struct spi_nor *nor, loff_t ofs, u64 len, const u8 *sr)
117144 {
118145 return spi_nor_check_lock_status_sr(nor, ofs, len, sr, true);
119146 }
120147
121148 static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len,
122− u8 sr)
149+ const u8 *sr)
123150 {
124151 return spi_nor_check_lock_status_sr(nor, ofs, len, sr, false);
125152 }
126153
154+static 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+
170+static 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+ */
201+void 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+
127228 /*
128229 * Lock a region of the flash. Compatible with ST Micro and similar flash.
129230 * Supports the block protection bits BP{0,1,2}/BP{0,1,2,3} in the status
130231 * register
131232 * (SR). Does not support these features found in newer SR bitfields:
132233 * - SEC: sector/block protect - only handle SEC=0 (block protect)
133− * - CMP: complement protect - only support CMP=0 (range is not complemented)
134234 *
135235 * Support for the following is provided conditionally for some flash:
136236 * - TB: top/bottom protect
237+ * - CMP: complement protect (BP and TP describe the unlocked part, while
238+ * the reminder is locked)
137239 *
138240 * Sample table portion for 8MB flash (Winbond w25q64fw):
139241 *
@@ -159,20 +261,31 @@ static bool spi_nor_is_unlocked_sr(struct spi_nor *nor, loff_t ofs, u64 len, · 19 unmodified lines
159261 */
160262 static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len)
161263 {
162− u64 min_prot_len;
163− int ret, status_old, status_new;
164− u8 mask = spi_nor_get_sr_bp_mask(nor);
165− u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
166− u8 pow, val;
264+ u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
265+ u8 status_old[2] = {}, status_new[2] = {}, status_new_cmp[2] = {};
266+ u8 *best_status_new = status_new;
267+ loff_t ofs_old, ofs_new, ofs_new_cmp;
268+ u64 len_old, len_new, len_new_cmp;
167269 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);
169272 bool use_top;
273+ int ret;
274+ u8 pow;
170275
171276 ret = spi_nor_read_sr(nor, nor->bouncebuf);
172277 if (ret)
173278 return ret;
174279
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+ }
176289
177290 /* If nothing in our range is unlocked, we don't need to do anything */
178291 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
199312 else
200313 lock_len = ofs + len;
201314
202− if (lock_len == nor->params->size) {
203− val = mask;
204− } else {
205− min_prot_len = spi_nor_get_min_prot_length_sr(nor);
315+ if (lock_len == nor->params->size)
316+ pow = (nor->flags & SNOR_F_HAS_4BIT_BP) ? GENMASK(3, 0) : GENMASK(2, 0);
317+ else
206318 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;
211319
212− if (val & ~mask)
213− return -EINVAL;
320+ ret = spi_nor_build_sr(nor, status_old, status_new, pow, use_top, false);
321+ if (ret)
322+ return ret;
214323
215− /* Don't "lock" with no region! */
216− if (!(val & mask))
217− return -EINVAL;
324+ /*
325+ * In case the region asked is not fully met, maybe we can try with the
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;
218355 }
219356
220− status_new = (status_old & ~mask & ~tb_mask) | val;
221−
222357 /*
223358 * Disallow further writes if WP# pin is neither left floating nor
224359 * wrongly tied to GND (that includes internal pull-downs).
225360 * WP# pin hard strapped to GND can be a valid use case.
226361 */
227362 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);
229367
230− if (!use_top)
231− status_new |= tb_mask;
368+ /* Don't "lock" with no region! */
369+ if (!len_new)
370+ return -EINVAL;
232371
233372 /* 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])
235374 return 0;
236375
237376 /* 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)))
239379 return -EINVAL;
240380
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;
242391 }
243392
244393 /*
@@ -248,20 +397,31 @@ static int spi_nor_sr_lock(struct spi_nor *nor, loff_t ofs, u64 len) · 3 unmodified lines
248397 */
249398 static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len)
250399 {
251− u64 min_prot_len;
252− int ret, status_old, status_new;
253− u8 mask = spi_nor_get_sr_bp_mask(nor);
254− u8 tb_mask = spi_nor_get_sr_tb_mask(nor);
255− u8 pow, val;
400+ u64 min_prot_len = spi_nor_get_min_prot_length_sr(nor);
401+ u8 status_old[2] = {}, status_new[2] = {}, status_new_cmp[2] = {};
402+ u8 *best_status_new = status_new;
403+ loff_t ofs_old, ofs_new, ofs_new_cmp;
404+ u64 len_old, len_new, len_new_cmp;
256405 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);
258408 bool use_top;
409+ int ret;
410+ u8 pow;
259411
260412 ret = spi_nor_read_sr(nor, nor->bouncebuf);
261413 if (ret)
262414 return ret;
263415
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+ }
265425
266426 /* If nothing in our range is locked, we don't need to do anything */
267427 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
282442 /* Prefer top, if both are valid */
283443 use_top = can_be_top;
284444
285− /* lock_len: length of region that should remain locked */
286− if (use_top)
445+ /*
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)
287454 lock_len = nor->params->size - (ofs + len);
288455 else
289456 lock_len = ofs;
290457
291− if (lock_len == 0) {
292− val = 0; /* fully unlocked */
293− } else {
294− min_prot_len = spi_nor_get_min_prot_length_sr(nor);
458+ if (lock_len == 0)
459+ pow = 0; /* fully unlocked */
460+ else
295461 pow = ilog2(lock_len) - ilog2(min_prot_len) + 1;
296− val = pow << SR_BP_SHIFT;
297462
298− if (nor->flags & SNOR_F_HAS_SR_BP3_BIT6 && val & SR_BP3)
299− val = (val & ~SR_BP3) | SR_BP3_BIT6;
463+ ret = spi_nor_build_sr(nor, status_old, status_new, pow, use_top, false);
464+ if (ret)
465+ return ret;
300466
301− /* Some power-of-two sizes are not supported */
302− if (val & ~mask)
303− return -EINVAL;
467+ /*
468+ * In case the region asked is not fully met, maybe we can try with the
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;
304498 }
305499
306− status_new = (status_old & ~mask & ~tb_mask) | val;
307−
308500 /* Don't protect status register if we're fully unlocked */
309501 if (lock_len == 0)
310− status_new &= ~SR_SRWD;
311−
312− if (!use_top)
313− status_new |= tb_mask;
502+ best_status_new[0] &= ~SR_SRWD;
314503
315504 /* 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])
317506 return 0;
318507
319508 /* 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)))
321513 return -EINVAL;
322514
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;
324525 }
325526
326527 /*
@@ -332,13 +533,24 @@ static int spi_nor_sr_unlock(struct spi_nor *nor, loff_t ofs, u64 len) · 5 unmodified lines
332533 */
333534 static int spi_nor_sr_is_locked(struct spi_nor *nor, loff_t ofs, u64 len)
334535 {
536+ u8 sr_cr[2] = {};
335537 int ret;
336538
337539 ret = spi_nor_read_sr(nor, nor->bouncebuf);
338540 if (ret)
339541 return ret;
340542
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);
342554 }
343555
344556 static 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
352564 nor->params->locking_ops = &spi_nor_sr_locking_ops;
353565 }
354566
567+bool spi_nor_has_default_locking_ops(struct spi_nor *nor)
568+{
569+ return nor->params->locking_ops == &spi_nor_sr_locking_ops;
570+}
571+
355572 static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, u64 len)
356573 {
357574 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
7373 .post_bfpt = w25q256_post_bfpt_fixups,
7474 };
7575
76+static int
77+winbond_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+
92+static const struct spi_nor_fixups winbond_rdcr_fixup = {
93+ .post_bfpt = winbond_rdcr_post_bfpt_fixup,
94+};
95+
7696 /**
7797 * winbond_nor_select_die() - Set active die.
7898 * @nor: pointer to 'struct spi_nor'.
@@ -348,27 +368,36 @@ static const struct flash_info winbond_nor_parts[] = { · 269 unmodified lines
348368 }, {
349369 /* W25Q01NWxxIQ */
350370 .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,
352374 }, {
353375 /* W25Q01NWxxIM */
354376 .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,
356379 }, {
357380 /* W25Q02NWxxIM */
358381 .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,
360385 }, {
361386 /* W25H512NWxxAM */
362387 .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,
364390 }, {
365391 /* W25H01NWxxAM */
366392 .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,
368395 }, {
369396 /* W25H02NWxxAM */
370397 .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,
372401 },
373402 };
374403
include/linux/mtd/spi-nor.h+5−2
@@ -21,8 +21,8 @@ · 20 unmodified lines
2121 /* Flash opcodes. */
2222 #define SPINOR_OP_WRDI 0x04 /* Write disable */
2323 #define SPINOR_OP_WREN 0x06 /* Write enable */
24−#define SPINOR_OP_RDSR 0x05 /* Read status register */
25−#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */
24+#define SPINOR_OP_RDSR 0x05 /* Read status register 1 */
25+#define SPINOR_OP_WRSR 0x01 /* Write status register 1 */
2626 #define SPINOR_OP_RDSR2 0x3f /* Read status register 2 */
2727 #define SPINOR_OP_WRSR2 0x3e /* Write status register 2 */
2828 #define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */
@@ -125,6 +125,7 @@ · 96 unmodified lines
125125 #define SR2_LB1 BIT(3) /* Security Register Lock Bit 1 */
126126 #define SR2_LB2 BIT(4) /* Security Register Lock Bit 2 */
127127 #define SR2_LB3 BIT(5) /* Security Register Lock Bit 3 */
128+#define SR2_CMP_BIT6 BIT(6)
128129 #define SR2_QUAD_EN_BIT7 BIT(7)
129130
130131 /* Supported SPI protocols */
@@ -371,6 +372,7 @@ struct spi_nor_flash_parameter; · 240 unmodified lines
371372 * @reg_proto: the SPI protocol for read_reg/write_reg/erase operations
372373 * @sfdp: the SFDP data of the flash
373374 * @debugfs_root: pointer to the debugfs directory
375+ * @dfs_sr_cache: Status Register cached value for debugfs use only
374376 * @controller_ops: SPI NOR controller driver specific operations.
375377 * @params: [FLASH-SPECIFIC] SPI NOR flash parameters and settings.
376378 * The structure includes legacy flash parameters and
@@ -409,6 +411,7 @@ struct spi_nor { · 32 unmodified lines
409411 enum spi_nor_cmd_ext cmd_ext_type;
410412 struct sfdp *sfdp;
411413 struct dentry *debugfs_root;
414+ u8 dfs_sr_cache[2];
412415
413416 const struct spi_nor_controller_ops *controller_ops;
414417

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