From f9f50936446e8e441238ecfe12ce0fc9e04d491a Mon Sep 17 00:00:00 2001 From: Rizwan Qureshi Date: Mon, 31 Dec 2018 15:19:16 +0530 Subject: [PATCH] drivers/spi: Add controller protection type Some SPI controllers support both READ and WRITE protection add a variable to the protect API for the callers to specify the kind of protection they want (Read/Write/Both). Also, update the callers and protect API implementation. BUG=None BRANCH=None TEST=test that the mrc cache is protected as expected on soraka. Also tried if the read protection is applied correctly. Change-Id: I093884c4768b08a378f21242ac82e430ac013d15 Signed-off-by: Rizwan Qureshi Reviewed-on: https://review.coreboot.org/c/30559 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Rudolph --- src/drivers/mrc_cache/mrc_cache.c | 4 ++- src/drivers/spi/spi_flash.c | 5 ++-- src/include/spi-generic.h | 9 ++++++- src/include/spi_flash.h | 3 ++- src/soc/intel/broadwell/include/soc/spi.h | 1 + src/soc/intel/broadwell/spi.c | 24 ++++++++++++++--- .../common/block/fast_spi/fast_spi_flash.c | 23 +++++++++++++--- src/southbridge/intel/common/spi.c | 27 ++++++++++++++++--- 8 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/drivers/mrc_cache/mrc_cache.c b/src/drivers/mrc_cache/mrc_cache.c index 4dd0dbc434..84bbdb05b3 100644 --- a/src/drivers/mrc_cache/mrc_cache.c +++ b/src/drivers/mrc_cache/mrc_cache.c @@ -456,13 +456,15 @@ static int nvm_is_write_protected(void) /* Apply protection to a range of flash */ static int nvm_protect(const struct region *r) { + const struct spi_flash *flash = boot_device_spi_flash(); + if (!IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT)) return 0; if (!IS_ENABLED(CONFIG_BOOT_DEVICE_SPI_FLASH)) return 0; - return spi_flash_ctrlr_protect_region(boot_device_spi_flash(), r); + return spi_flash_ctrlr_protect_region(flash, r, WRITE_PROTECT); } /* Protect mrc region with a Protected Range Register */ diff --git a/src/drivers/spi/spi_flash.c b/src/drivers/spi/spi_flash.c index f06de2a11a..204f607889 100644 --- a/src/drivers/spi/spi_flash.c +++ b/src/drivers/spi/spi_flash.c @@ -572,7 +572,8 @@ void lb_spi_flash(struct lb_header *header) int spi_flash_ctrlr_protect_region(const struct spi_flash *flash, - const struct region *region) + const struct region *region, + const enum ctrlr_prot_type type) { const struct spi_ctrlr *ctrlr; struct region flash_region = { 0 }; @@ -591,7 +592,7 @@ int spi_flash_ctrlr_protect_region(const struct spi_flash *flash, return -1; if (ctrlr->flash_protect) - return ctrlr->flash_protect(flash, region); + return ctrlr->flash_protect(flash, region, type); return -1; } diff --git a/src/include/spi-generic.h b/src/include/spi-generic.h index e3e7f829f7..c24aadd926 100644 --- a/src/include/spi-generic.h +++ b/src/include/spi-generic.h @@ -97,6 +97,12 @@ struct spi_cfg { struct spi_flash; +enum ctrlr_prot_type { + READ_PROTECT = 1, + WRITE_PROTECT = 2, + READ_WRITE_PROTECT = 3, +}; + enum { /* Deduct the command length from the spi_crop_chunk() calculation for sizing a transaction. */ @@ -144,7 +150,8 @@ struct spi_ctrlr { int (*flash_probe)(const struct spi_slave *slave, struct spi_flash *flash); int (*flash_protect)(const struct spi_flash *flash, - const struct region *region); + const struct region *region, + const enum ctrlr_prot_type type); }; /*----------------------------------------------------------------------- diff --git a/src/include/spi_flash.h b/src/include/spi_flash.h index 09908eb9f8..936b0abe85 100644 --- a/src/include/spi_flash.h +++ b/src/include/spi_flash.h @@ -207,7 +207,8 @@ const struct spi_flash *boot_device_spi_flash(void); /* Protect a region of spi flash using its controller, if available. Returns * < 0 on error, else 0 on success. */ int spi_flash_ctrlr_protect_region(const struct spi_flash *flash, - const struct region *region); + const struct region *region, + const enum ctrlr_prot_type type); /* * This function is provided to support spi flash command-response transactions. diff --git a/src/soc/intel/broadwell/include/soc/spi.h b/src/soc/intel/broadwell/include/soc/spi.h index 588af17609..5ad62fd19d 100644 --- a/src/soc/intel/broadwell/include/soc/spi.h +++ b/src/soc/intel/broadwell/include/soc/spi.h @@ -38,6 +38,7 @@ #define SPI_PRR_BASE_SHIFT 0 #define SPI_PRR_LIMIT_SHIFT 16 #define SPI_PRR_WPE (1 << 31) +#define SPI_PRR_RPE (1 << 15) #define SPIBAR_PREOP 0x94 #define SPIBAR_OPTYPE 0x96 diff --git a/src/soc/intel/broadwell/spi.c b/src/soc/intel/broadwell/spi.c index 2317c9a137..de3d061aea 100644 --- a/src/soc/intel/broadwell/spi.c +++ b/src/soc/intel/broadwell/spi.c @@ -615,11 +615,13 @@ static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout, /* Use first empty Protected Range Register to cover region of flash */ static int spi_flash_protect(const struct spi_flash *flash, - const struct region *region) + const struct region *region, + const enum ctrlr_prot_type type) { u32 start = region_offset(region); u32 end = start + region_sz(region) - 1; u32 reg; + u32 protect_mask = 0; int prr; /* Find first empty PRR */ @@ -637,12 +639,28 @@ static int spi_flash_protect(const struct spi_flash *flash, reg = ((end >> SPI_PRR_SHIFT) & SPI_PRR_MASK); reg <<= SPI_PRR_LIMIT_SHIFT; reg |= ((start >> SPI_PRR_SHIFT) & SPI_PRR_MASK); - reg |= SPI_PRR_WPE; + + switch (type) { + case WRITE_PROTECT: + protect_mask |= SPI_PRR_WPE; + break; + case READ_PROTECT: + protect_mask |= SPI_PRR_RPE; + break; + case READ_WRITE_PROTECT: + protect_mask |= (SPI_PRR_RPE | SPI_PRR_WPE); + break; + default: + printk(BIOS_ERR, "ERROR: Seeking invalid protection!\n"); + return -1; + } + + reg |= protect_mask; /* Set the PRR register and verify it is protected */ SPIBAR32(SPI_PRR(prr)) = reg; reg = SPIBAR32(SPI_PRR(prr)); - if (!(reg & SPI_PRR_WPE)) { + if (!(reg & protect_mask)) { printk(BIOS_ERR, "ERROR: Unable to set SPI PRR %d\n", prr); return -1; } diff --git a/src/soc/intel/common/block/fast_spi/fast_spi_flash.c b/src/soc/intel/common/block/fast_spi/fast_spi_flash.c index 4579b19151..65708a6b19 100644 --- a/src/soc/intel/common/block/fast_spi/fast_spi_flash.c +++ b/src/soc/intel/common/block/fast_spi/fast_spi_flash.c @@ -367,11 +367,13 @@ static int fast_spi_flash_ctrlr_setup(const struct spi_slave *dev) * Protected Range (FPR) register if available. */ static int fast_spi_flash_protect(const struct spi_flash *flash, - const struct region *region) + const struct region *region, + const enum ctrlr_prot_type type) { u32 start = region_offset(region); u32 end = start + region_sz(region) - 1; u32 reg; + u32 protect_mask = 0; int fpr; uintptr_t fpr_base; BOILERPLATE_CREATE_CTX(ctx); @@ -391,13 +393,28 @@ static int fast_spi_flash_protect(const struct spi_flash *flash, return -1; } + switch (type) { + case WRITE_PROTECT: + protect_mask |= SPI_FPR_WPE; + break; + case READ_PROTECT: + protect_mask |= SPI_FPR_RPE; + break; + case READ_WRITE_PROTECT: + protect_mask |= (SPI_FPR_RPE | SPI_FPR_WPE); + break; + default: + printk(BIOS_ERR, "ERROR: Seeking invalid protection!\n"); + return -1; + } + /* Set protected range base and limit */ - reg = SPI_FPR(start, end) | SPI_FPR_WPE; + reg = SPI_FPR(start, end) | protect_mask; /* Set the FPR register and verify it is protected */ write32((void *)fpr_base, reg); reg = read32((void *)fpr_base); - if (!(reg & SPI_FPR_WPE)) { + if (!(reg & protect_mask)) { printk(BIOS_ERR, "ERROR: Unable to set SPI FPR %d\n", fpr); return -1; } diff --git a/src/southbridge/intel/common/spi.c b/src/southbridge/intel/common/spi.c index 9bc34140a9..4c5939963f 100644 --- a/src/southbridge/intel/common/spi.c +++ b/src/southbridge/intel/common/spi.c @@ -1010,12 +1010,14 @@ static u32 spi_fpr(u32 base, u32 limit) * Returns 0 on success, -1 on failure of programming fpr registers. */ static int spi_flash_protect(const struct spi_flash *flash, - const struct region *region) + const struct region *region, + const enum ctrlr_prot_type type) { ich_spi_controller *cntlr = car_get_var_ptr(&g_cntlr); u32 start = region_offset(region); u32 end = start + region_sz(region) - 1; u32 reg; + u32 protect_mask = 0; int fpr; uint32_t *fpr_base; @@ -1033,13 +1035,32 @@ static int spi_flash_protect(const struct spi_flash *flash, return -1; } + switch (type) { + case WRITE_PROTECT: + protect_mask |= SPI_FPR_WPE; + break; + case READ_PROTECT: + if (IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_I82801GX)) + return -1; + protect_mask |= ICH9_SPI_FPR_RPE; + break; + case READ_WRITE_PROTECT: + if (IS_ENABLED(CONFIG_SOUTHBRIDGE_INTEL_I82801GX)) + return -1; + protect_mask |= (ICH9_SPI_FPR_RPE | SPI_FPR_WPE); + break; + default: + printk(BIOS_ERR, "ERROR: Seeking invalid protection!\n"); + return -1; + } + /* Set protected range base and limit */ - reg = spi_fpr(start, end) | SPI_FPR_WPE; + reg = spi_fpr(start, end) | protect_mask; /* Set the FPR register and verify it is protected */ write32(&fpr_base[fpr], reg); reg = read32(&fpr_base[fpr]); - if (!(reg & SPI_FPR_WPE)) { + if (!(reg & protect_mask)) { printk(BIOS_ERR, "ERROR: Unable to set SPI FPR %d\n", fpr); return -1; }