Hello Daniel Gröber,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/42115
to review the following change.
Change subject: spi/winbond: Pull out winbond_region_to_bpbits function ......................................................................
spi/winbond: Pull out winbond_region_to_bpbits function
Split region>bpbits conversion related logic out from winbond_set_write_protection into a new function: winbond_region_to_bpbits.
Change-Id: I2c7b08cb56772aa620e690077bbbb1fde3d7aae7 Signed-off-by: Daniel Gröber dxld@darkboxed.org --- M src/drivers/spi/winbond.c 1 file changed, 94 insertions(+), 59 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/15/42115/1
diff --git a/src/drivers/spi/winbond.c b/src/drivers/spi/winbond.c index 77191e4..51d43a8 100644 --- a/src/drivers/spi/winbond.c +++ b/src/drivers/spi/winbond.c @@ -211,6 +211,13 @@ static int winbond_get_bpbits(const struct spi_flash *flash, struct spi_flash_bpbits *bpbits);
+static int winbond_region_to_bpbits( + const struct spi_flash *flash, + const struct spi_flash_part_id *params, + const struct region *region, + const enum spi_flash_status_reg_lockdown mode, + struct spi_flash_bpbits *bits); + /* * Convert BPx, TB and CMP to a region. * SEC (if available) must be zero. @@ -449,19 +456,77 @@ { const struct spi_flash_part_id *params; struct status_regs mask, val; - struct region wp_region; - u8 cmp, bp, tb; + struct spi_flash_bpbits bpbits; int ret;
- /* Need to touch TOP or BOTTOM */ - if (region_offset(region) != 0 && region_end(region) != flash->size) - return -1; - params = flash->part;
if (!params) return -1;
+ ret = winbond_get_bpbits(flash, &bpbits); + if (!ret) + return ret; + + ret = winbond_region_to_bpbits(flash, params, region, mode, &bpbits); + if (!ret) + return ret; + + /* Write block protection bits */ + + if (params->bp_bits == 3) { + val.reg1 = (union status_reg1) { + .bp3 = { .bp = bpbits.bp, .tb = bpbits.tb, .sec = 0 } + }; + mask.reg1 = (union status_reg1) { + .bp3 = { .bp = ~0, .tb = 1, .sec = 1 } + }; + } else { + val.reg1 = (union status_reg1) { + .bp4 = { .bp = bpbits.bp, .tb = bpbits.tb } + }; + mask.reg1 = (union status_reg1) { + .bp4 = { .bp = ~0, .tb = 1 } + }; + } + + val.reg2 = (union status_reg2) { .cmp = bpbits.cmp }; + mask.reg2 = (union status_reg2) { .cmp = 1 }; + + if (params->bp_bits == 3) { + val.reg1.bp3.srp0 = bpbits.winbond.srp0; + mask.reg1.bp3.srp0 = 1; + } else { + val.reg1.bp4.srp0 = bpbits.winbond.srp0; + mask.reg1.bp4.srp0 = 1; + } + + val.reg2.srp1 = bpbits.winbond.srp1; + mask.reg2.srp1 = 1; + + ret = winbond_flash_cmd_status(flash, mask.u, val.u, true); + if (ret) + return ret; + + printk(BIOS_DEBUG, "WINBOND: write-protection set to range " + "0x%08zx-0x%08zx\n", region_offset(region), region_end(region)); + + return ret; +} + +static int winbond_region_to_bpbits( + const struct spi_flash *flash, + const struct spi_flash_part_id *params, + const struct region *region, + const enum spi_flash_status_reg_lockdown mode, + struct spi_flash_bpbits *bits) +{ + struct region wp_region; + + /* Need to touch TOP or BOTTOM */ + if (region_offset(region) != 0 && region_end(region) != flash->size) + return -1; + if (params->bp_bits != 3 && params->bp_bits != 4) { /* FIXME: not implemented */ return -1; @@ -470,91 +535,61 @@ wp_region = *region;
if (region_offset(&wp_region) == 0) - tb = 1; + bits->tb = 1; else - tb = 0; + bits->tb = 0;
if (region_sz(&wp_region) > flash->size / 2) { - cmp = 1; - wp_region.offset = tb ? 0 : region_sz(&wp_region); + bits->cmp = 1; + wp_region.offset = bits->tb ? 0 : region_sz(&wp_region); wp_region.size = flash->size - region_sz(&wp_region); - tb = !tb; + bits->tb = !bits->tb; } else { - cmp = 0; + bits->cmp = 0; }
if (region_sz(&wp_region) == 0) { - bp = 0; + bits->bp = 0; } else if (IS_POWER_OF_2(region_sz(&wp_region)) && (region_sz(&wp_region) >= (1 << params->protection_granularity_shift))) { - bp = log2(region_sz(&wp_region)) - + bits->bp = log2(region_sz(&wp_region)) - params->protection_granularity_shift + 1; } else { printk(BIOS_ERR, "WINBOND: ERROR: unsupported region size\n"); return -1; }
- /* Write block protection bits */ - - if (params->bp_bits == 3) { - val.reg1 = (union status_reg1) { - .bp3 = { .bp = bp, .tb = tb, .sec = 0 } - }; - mask.reg1 = (union status_reg1) { - .bp3 = { .bp = ~0, .tb = 1, .sec = 1 } - }; - } else { - val.reg1 = (union status_reg1) { - .bp4 = { .bp = bp, .tb = tb } - }; - mask.reg1 = (union status_reg1) { - .bp4 = { .bp = ~0, .tb = 1 } - }; - } - - val.reg2 = (union status_reg2) { .cmp = cmp }; - mask.reg2 = (union status_reg2) { .cmp = 1 }; - if (mode != SPI_WRITE_PROTECTION_PRESERVE) { - u8 srp; switch (mode) { case SPI_WRITE_PROTECTION_NONE: - srp = 0; + bits->winbond.srp1 = 0; + bits->winbond.srp0 = 0; break; case SPI_WRITE_PROTECTION_PIN: - srp = 1; + bits->winbond.srp1 = 0; + bits->winbond.srp0 = 1; break; case SPI_WRITE_PROTECTION_REBOOT: - srp = 2; + bits->winbond.srp1 = 1; + bits->winbond.srp0 = 0; break; case SPI_WRITE_PROTECTION_PERMANENT: - srp = 3; + if (params->bp_bits == 3) { + bits->winbond.srp1 = 1; + bits->winbond.srp0 = 1; + } else { + /* FIXME: special permanent protect write + * sequence not implemented. */ + return -1; + } break; default: return -1; } - - if (params->bp_bits == 3) { - val.reg1.bp3.srp0 = !!(srp & 1); - mask.reg1.bp3.srp0 = 1; - } else { - val.reg1.bp4.srp0 = !!(srp & 1); - mask.reg1.bp4.srp0 = 1; - } - - val.reg2.srp1 = !!(srp & 2); - mask.reg2.srp1 = 1; }
- ret = winbond_flash_cmd_status(flash, mask.u, val.u, true); - if (ret) - return ret; - - printk(BIOS_DEBUG, "WINBOND: write-protection set to range " - "0x%08zx-0x%08zx\n", region_offset(region), region_end(region)); - - return ret; + return 0; }
static const struct spi_flash_protection_ops spi_flash_protection_ops = {