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"
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 * Convert BPx, TB and CMP to a region.
245 * SEC (if available) must be zero.
247 static void winbond_bpbits_to_region(const size_t granularity
,
251 const size_t flash_size
,
254 size_t protected_size
=
255 MIN(bp
? granularity
<< (bp
- 1) : 0, flash_size
);
258 protected_size
= flash_size
- protected_size
;
262 out
->offset
= tb
? 0 : flash_size
- protected_size
;
263 out
->size
= protected_size
;
267 * Available on all devices.
268 * Read block protect bits from Status/Status2 Reg.
269 * Converts block protection bits to a region.
273 * 1 if region is covered by write protection
274 * 0 if a part of region isn't covered by write protection
276 static int winbond_get_write_protection(const struct spi_flash
*flash
,
277 const struct region
*region
)
279 const struct spi_flash_part_id
*params
;
280 struct region wp_region
;
281 union status_reg2 reg2
;
285 params
= flash
->part
;
290 const size_t granularity
= (1 << params
->protection_granularity_shift
);
292 union status_reg1 reg1
= { .u
= 0 };
294 ret
= spi_flash_cmd(&flash
->spi
, flash
->status_cmd
, ®1
.u
,
299 if (params
->bp_bits
== 3) {
301 // FIXME: not supported
307 } else if (params
->bp_bits
== 4) {
311 // FIXME: not supported
315 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR2
, ®2
.u
,
320 winbond_bpbits_to_region(granularity
, bp
, tb
, reg2
.cmp
, flash
->size
,
323 if (!region_sz(&wp_region
)) {
324 printk(BIOS_DEBUG
, "WINBOND: flash isn't protected\n");
329 printk(BIOS_DEBUG
, "WINBOND: flash protected range 0x%08zx-0x%08zx\n",
330 region_offset(&wp_region
), region_end(&wp_region
));
332 return region_is_subregion(&wp_region
, region
);
336 * Common method to write some bit of the status register 1 & 2 at the same
337 * time. Only change bits that are one in @mask.
338 * Compare the final result to make sure that the register isn't locked.
340 * @param mask: The bits that are affected by @val
341 * @param val: The bits to write
342 * @param non_volatile: Make setting permanent
344 * @return 0 on success
346 static int winbond_flash_cmd_status(const struct spi_flash
*flash
,
349 const bool non_volatile
)
361 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR
, ®8
, sizeof(reg8
));
367 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR2
, ®8
, sizeof(reg8
));
371 cmdbuf
.sreg
|= reg8
<< 8;
373 if ((val
& mask
) == (cmdbuf
.sreg
& mask
))
377 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_WREN
, NULL
, 0);
379 ret
= spi_flash_cmd(&flash
->spi
, CMD_VOLATILE_SREG_WREN
, NULL
,
385 cmdbuf
.sreg
&= ~mask
;
386 cmdbuf
.sreg
|= val
& mask
;
387 cmdbuf
.cmd
= CMD_W25_WRSR
;
389 /* Legacy method of writing status register 1 & 2 */
390 ret
= spi_flash_cmd_write(&flash
->spi
, (u8
*)&cmdbuf
, sizeof(cmdbuf
),
397 ret
= spi_flash_cmd_wait_ready(flash
, WINBOND_FLASH_TIMEOUT
);
405 /* Now read the status register to make sure it's not locked */
406 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR
, ®8
, sizeof(reg8
));
412 ret
= spi_flash_cmd(&flash
->spi
, CMD_W25_RDSR2
, ®8
, sizeof(reg8
));
416 cmdbuf
.sreg
|= reg8
<< 8;
418 printk(BIOS_DEBUG
, "WINBOND: SREG=%02x SREG2=%02x\n",
422 /* Compare against expected result */
423 if ((val
& mask
) != (cmdbuf
.sreg
& mask
)) {
424 printk(BIOS_ERR
, "WINBOND: SREG is locked!\n");
432 * Available on all devices.
433 * Protect a region starting from start of flash or end of flash.
434 * The caller must provide a supported protected region size.
435 * SEC isn't supported and set to zero.
436 * Write block protect bits to Status/Status2 Reg.
437 * Optionally lock the status register if lock_sreg is set with the provided
440 * @param flash: The flash to operate on
441 * @param region: The region to write protect
442 * @param mode: Optional status register lock-down mode
444 * @return 0 on success
447 winbond_set_write_protection(const struct spi_flash
*flash
,
448 const struct region
*region
,
449 const enum spi_flash_status_reg_lockdown mode
)
451 const struct spi_flash_part_id
*params
;
452 struct status_regs mask
, val
;
453 struct region wp_region
;
457 /* Need to touch TOP or BOTTOM */
458 if (region_offset(region
) != 0 && region_end(region
) != flash
->size
)
461 params
= flash
->part
;
466 if (params
->bp_bits
!= 3 && params
->bp_bits
!= 4) {
467 /* FIXME: not implemented */
473 if (region_offset(&wp_region
) == 0)
478 if (region_sz(&wp_region
) > flash
->size
/ 2) {
480 wp_region
.offset
= tb
? 0 : region_sz(&wp_region
);
481 wp_region
.size
= flash
->size
- region_sz(&wp_region
);
487 if (region_sz(&wp_region
) == 0) {
489 } else if (IS_POWER_OF_2(region_sz(&wp_region
)) &&
490 (region_sz(&wp_region
) >=
491 (1 << params
->protection_granularity_shift
))) {
492 bp
= log2(region_sz(&wp_region
)) -
493 params
->protection_granularity_shift
+ 1;
495 printk(BIOS_ERR
, "WINBOND: ERROR: unsupported region size\n");
499 /* Write block protection bits */
501 if (params
->bp_bits
== 3) {
502 val
.reg1
= (union status_reg1
) {
503 .bp3
= { .bp
= bp
, .tb
= tb
, .sec
= 0 }
505 mask
.reg1
= (union status_reg1
) {
506 .bp3
= { .bp
= ~0, .tb
= 1, .sec
= 1 }
509 val
.reg1
= (union status_reg1
) {
510 .bp4
= { .bp
= bp
, .tb
= tb
}
512 mask
.reg1
= (union status_reg1
) {
513 .bp4
= { .bp
= ~0, .tb
= 1 }
517 val
.reg2
= (union status_reg2
) { .cmp
= cmp
};
518 mask
.reg2
= (union status_reg2
) { .cmp
= 1 };
520 if (mode
!= SPI_WRITE_PROTECTION_PRESERVE
) {
523 case SPI_WRITE_PROTECTION_NONE
:
526 case SPI_WRITE_PROTECTION_PIN
:
529 case SPI_WRITE_PROTECTION_REBOOT
:
532 case SPI_WRITE_PROTECTION_PERMANENT
:
539 if (params
->bp_bits
== 3) {
540 val
.reg1
.bp3
.srp0
= !!(srp
& 1);
541 mask
.reg1
.bp3
.srp0
= 1;
543 val
.reg1
.bp4
.srp0
= !!(srp
& 1);
544 mask
.reg1
.bp4
.srp0
= 1;
547 val
.reg2
.srp1
= !!(srp
& 2);
551 ret
= winbond_flash_cmd_status(flash
, mask
.u
, val
.u
, true);
555 printk(BIOS_DEBUG
, "WINBOND: write-protection set to range "
556 "0x%08zx-0x%08zx\n", region_offset(region
), region_end(region
));
561 static const struct spi_flash_protection_ops spi_flash_protection_ops
= {
562 .get_write
= winbond_get_write_protection
,
563 .set_write
= winbond_set_write_protection
,
566 const struct spi_flash_vendor_info spi_flash_winbond_vi
= {
567 .id
= VENDOR_ID_WINBOND
,
568 .page_size_shift
= 8,
569 .sector_size_kib_shift
= 2,
570 .match_id_mask
[0] = 0xffff,
572 .nr_part_ids
= ARRAY_SIZE(flash_table
),
573 .desc
= &spi_flash_pp_0x20_sector_desc
,
574 .prot_ops
= &spi_flash_protection_ops
,