1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 #include <console/console.h>
4 #include <commonlib/helpers.h>
6 #include <spi-generic.h>
10 #include "spi_flash_internal.h"
11 #include "spi_winbond.h"
22 } bp3
; /* for example: W25Q128FW */
29 } bp4
; /* for example: W25Q256J */
47 #if defined(__BIG_ENDIAN)
48 union status_reg2 reg2
;
49 union status_reg1 reg1
;
51 union status_reg1 reg1
;
52 union status_reg2 reg2
;
59 static const struct spi_flash_part_id flash_table
[] = {
63 .nr_sectors_shift
= 8,
68 .nr_sectors_shift
= 9,
73 .nr_sectors_shift
= 10,
78 .nr_sectors_shift
= 8,
79 .fast_read_dual_output_support
= 1,
84 .nr_sectors_shift
= 9,
85 .fast_read_dual_output_support
= 1,
90 .nr_sectors_shift
= 10,
91 .fast_read_dual_output_support
= 1,
96 .nr_sectors_shift
= 11,
97 .fast_read_dual_output_support
= 1,
102 .nr_sectors_shift
= 8,
103 .fast_read_dual_output_support
= 1,
104 .fast_read_dual_io_support
= 1,
109 .nr_sectors_shift
= 9,
110 .fast_read_dual_output_support
= 1,
111 .fast_read_dual_io_support
= 1,
112 .protection_granularity_shift
= 16,
118 .nr_sectors_shift
= 9,
119 .fast_read_dual_output_support
= 1,
120 .fast_read_dual_io_support
= 1,
121 .protection_granularity_shift
= 16,
127 .nr_sectors_shift
= 10,
128 .fast_read_dual_output_support
= 1,
129 .fast_read_dual_io_support
= 1,
130 .protection_granularity_shift
= 16,
136 .nr_sectors_shift
= 10,
137 .fast_read_dual_output_support
= 1,
138 .fast_read_dual_io_support
= 1,
139 .protection_granularity_shift
= 16,
145 .nr_sectors_shift
= 11,
146 .fast_read_dual_output_support
= 1,
147 .fast_read_dual_io_support
= 1,
148 .protection_granularity_shift
= 17,
154 .nr_sectors_shift
= 11,
155 .fast_read_dual_output_support
= 1,
156 .fast_read_dual_io_support
= 1,
157 .protection_granularity_shift
= 17,
163 .nr_sectors_shift
= 11,
164 .fast_read_dual_output_support
= 1,
165 .fast_read_dual_io_support
= 1,
166 .protection_granularity_shift
= 17,
172 .nr_sectors_shift
= 12,
173 .fast_read_dual_output_support
= 1,
174 .fast_read_dual_io_support
= 1,
175 .protection_granularity_shift
= 18,
181 .nr_sectors_shift
= 12,
182 .fast_read_dual_output_support
= 1,
183 .fast_read_dual_io_support
= 1,
184 .protection_granularity_shift
= 18,
190 .nr_sectors_shift
= 12,
191 .fast_read_dual_output_support
= 1,
192 .fast_read_dual_io_support
= 1,
193 .protection_granularity_shift
= 18,
199 .nr_sectors_shift
= 12,
200 .fast_read_dual_output_support
= 1,
201 .fast_read_dual_io_support
= 1,
202 .protection_granularity_shift
= 18,
208 .nr_sectors_shift
= 14,
209 .fast_read_dual_output_support
= 1,
210 .fast_read_dual_io_support
= 1,
211 .protection_granularity_shift
= 16,
217 .nr_sectors_shift
= 13,
218 .fast_read_dual_output_support
= 1,
219 .fast_read_dual_io_support
= 1,
220 .protection_granularity_shift
= 16,
226 .nr_sectors_shift
= 13,
227 .fast_read_dual_output_support
= 1,
228 .fast_read_dual_io_support
= 1,
229 .protection_granularity_shift
= 16,
235 .nr_sectors_shift
= 13,
236 .fast_read_dual_output_support
= 1,
237 .fast_read_dual_io_support
= 1,
238 .protection_granularity_shift
= 16,
244 .nr_sectors_shift
= 13,
245 .fast_read_dual_output_support
= 1,
246 .fast_read_dual_io_support
= 1,
247 .protection_granularity_shift
= 16,
253 * Convert BPx, TB and CMP to a region.
254 * SEC (if available) must be zero.
256 static void winbond_bpbits_to_region(const size_t granularity
,
257 const struct spi_flash_bpbits
*bits
,
258 const size_t flash_size
,
261 size_t protected_size
=
262 MIN(bits
->bp
? granularity
<< (bits
->bp
- 1) : 0, flash_size
);
266 protected_size
= flash_size
- protected_size
;
270 *out
= region_create(tb
? 0 : flash_size
- protected_size
, protected_size
);
274 * Available on all devices.
275 * Read block protect bits from Status/Status2 Reg.
276 * Converts block protection bits to a region.
280 * 1 if region is covered by write protection
281 * 0 if a part of region isn't covered by write protection
283 static int winbond_get_write_protection(const struct spi_flash
*flash
,
284 const struct region
*region
)
286 const struct spi_flash_part_id
*params
;
287 struct region wp_region
;
288 struct spi_flash_bpbits bpbits
;
291 params
= flash
->part
;
296 const size_t granularity
= (1 << params
->protection_granularity_shift
);
298 union status_reg1 reg1
= { .u
= 0 };
299 union status_reg2 reg2
= { .u
= 0 };
301 ret
= spi_flash_cmd(&flash
->spi
, flash
->status_cmd
, ®1
.u
,
306 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR2
, ®2
.u
,
311 if (params
->bp_bits
== 3) {
313 // FIXME: not supported
317 bpbits
= (struct spi_flash_bpbits
){
322 * For W25Q*{,F}* parts:
324 * 0 0 | writable if WEL==1
325 * 0 1 | writable if WEL==1 && #WP==Vcc
326 * 1 0 | not writable until next power-down
327 * 1 1 | not writable, permanently
329 * checked datasheets: W25Q128FV, (W25Q80, W25Q16,
333 .srp0
= reg1
.bp3
.srp0
,
337 } else if (params
->bp_bits
== 4) {
338 bpbits
= (struct spi_flash_bpbits
){
343 * For W25Q*{J,D}* parts:
346 * 0 0 | writable if WEL==1
347 * 0 1 | writable if WEL==1 && #WP==Vcc
348 * 1 x | not writable until next power-down
350 * checked datasheets: W25Q132JW, W25Q128JW, W25Q256JV.
353 * The srp0/srp1 bits got renamed to srp/srl in the
354 * datasheets, we retain the prior naming
355 * convention for the structs though.
358 .srp0
= reg1
.bp4
.srp0
,
363 // FIXME: not supported
367 winbond_bpbits_to_region(granularity
, &bpbits
, flash
->size
,
370 if (!region_sz(&wp_region
)) {
371 printk(BIOS_DEBUG
, "WINBOND: flash isn't protected\n");
376 printk(BIOS_DEBUG
, "WINBOND: flash protected range 0x%08zx-0x%08zx\n",
377 region_offset(&wp_region
), region_last(&wp_region
));
379 return region_is_subregion(&wp_region
, region
);
383 * Common method to write some bit of the status register 1 & 2 at the same
384 * time. Only change bits that are one in @mask.
385 * Compare the final result to make sure that the register isn't locked.
387 * @param mask: The bits that are affected by @val
388 * @param val: The bits to write
389 * @param non_volatile: Make setting permanent
391 * @return 0 on success
393 static int winbond_flash_cmd_status(const struct spi_flash
*flash
,
396 const bool non_volatile
)
408 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR
, ®8
, sizeof(reg8
));
414 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR2
, ®8
, sizeof(reg8
));
418 cmdbuf
.sreg
|= reg8
<< 8;
420 if ((val
& mask
) == (cmdbuf
.sreg
& mask
))
424 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_WREN
, NULL
, 0);
426 ret
= spi_flash_cmd(&flash
->spi
, CMD_VOLATILE_SREG_WREN
, NULL
,
432 cmdbuf
.sreg
&= ~mask
;
433 cmdbuf
.sreg
|= val
& mask
;
434 cmdbuf
.cmd
= CMD_W25_WRSR
;
436 /* Legacy method of writing status register 1 & 2 */
437 ret
= spi_flash_cmd_write(&flash
->spi
, (u8
*)&cmdbuf
, sizeof(cmdbuf
),
444 ret
= spi_flash_cmd_wait_ready(flash
, WINBOND_FLASH_TIMEOUT
);
452 /* Now read the status register to make sure it's not locked */
453 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR
, ®8
, sizeof(reg8
));
459 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR2
, ®8
, sizeof(reg8
));
463 cmdbuf
.sreg
|= reg8
<< 8;
465 printk(BIOS_DEBUG
, "WINBOND: SREG=%02x SREG2=%02x\n",
469 /* Compare against expected result */
470 if ((val
& mask
) != (cmdbuf
.sreg
& mask
)) {
471 printk(BIOS_ERR
, "WINBOND: SREG is locked!\n");
479 * Available on all devices.
480 * Protect a region starting from start of flash or end of flash.
481 * The caller must provide a supported protected region size.
482 * SEC isn't supported and set to zero.
483 * Write block protect bits to Status/Status2 Reg.
484 * Optionally lock the status register if lock_sreg is set with the provided
487 * @param flash: The flash to operate on
488 * @param region: The region to write protect
489 * @param mode: Optional status register lock-down mode
491 * @return 0 on success
494 winbond_set_write_protection(const struct spi_flash
*flash
,
495 const struct region
*region
,
496 const enum spi_flash_status_reg_lockdown mode
)
498 const struct spi_flash_part_id
*params
;
499 struct status_regs mask
, val
;
500 struct region wp_region
;
504 /* Need to touch TOP or BOTTOM */
505 if (region_offset(region
) != 0 && region_last(region
) != flash
->size
- 1)
508 params
= flash
->part
;
513 if (params
->bp_bits
!= 3 && params
->bp_bits
!= 4) {
514 /* FIXME: not implemented */
520 if (region_offset(&wp_region
) == 0)
525 if (region_sz(&wp_region
) > flash
->size
/ 2) {
527 wp_region
= region_create(tb
? 0 : region_sz(&wp_region
),
528 flash
->size
- region_sz(&wp_region
));
534 if (region_sz(&wp_region
) == 0) {
536 } else if (IS_POWER_OF_2(region_sz(&wp_region
)) &&
537 (region_sz(&wp_region
) >=
538 (1 << params
->protection_granularity_shift
))) {
539 bp
= log2(region_sz(&wp_region
)) -
540 params
->protection_granularity_shift
+ 1;
542 printk(BIOS_ERR
, "WINBOND: ERROR: unsupported region size\n");
546 /* Write block protection bits */
548 if (params
->bp_bits
== 3) {
549 val
.reg1
= (union status_reg1
) {
550 .bp3
= { .bp
= bp
, .tb
= tb
, .sec
= 0 }
552 mask
.reg1
= (union status_reg1
) {
553 .bp3
= { .bp
= ~0, .tb
= 1, .sec
= 1 }
556 val
.reg1
= (union status_reg1
) {
557 .bp4
= { .bp
= bp
, .tb
= tb
}
559 mask
.reg1
= (union status_reg1
) {
560 .bp4
= { .bp
= ~0, .tb
= 1 }
564 val
.reg2
= (union status_reg2
) { .cmp
= cmp
};
565 mask
.reg2
= (union status_reg2
) { .cmp
= 1 };
567 if (mode
!= SPI_WRITE_PROTECTION_PRESERVE
) {
570 case SPI_WRITE_PROTECTION_NONE
:
573 case SPI_WRITE_PROTECTION_PIN
:
576 case SPI_WRITE_PROTECTION_REBOOT
:
579 case SPI_WRITE_PROTECTION_PERMANENT
:
586 if (params
->bp_bits
== 3) {
587 val
.reg1
.bp3
.srp0
= !!(srp
& 1);
588 mask
.reg1
.bp3
.srp0
= 1;
590 val
.reg1
.bp4
.srp0
= !!(srp
& 1);
591 mask
.reg1
.bp4
.srp0
= 1;
594 val
.reg2
.srp1
= !!(srp
& 2);
598 ret
= winbond_flash_cmd_status(flash
, mask
.u
, val
.u
, true);
602 printk(BIOS_DEBUG
, "WINBOND: write-protection set to range "
603 "0x%08zx-0x%08zx\n", region_offset(region
), region_last(region
));
608 static const struct spi_flash_protection_ops spi_flash_protection_ops
= {
609 .get_write
= winbond_get_write_protection
,
610 .set_write
= winbond_set_write_protection
,
613 const struct spi_flash_vendor_info spi_flash_winbond_vi
= {
614 .id
= VENDOR_ID_WINBOND
,
615 .page_size_shift
= 8,
616 .sector_size_kib_shift
= 2,
617 .match_id_mask
[0] = 0xffff,
619 .nr_part_ids
= ARRAY_SIZE(flash_table
),
620 .desc
= &spi_flash_pp_0x20_sector_desc
,
621 .prot_ops
= &spi_flash_protection_ops
,