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 <rizwan.qureshi@intel.com> Reviewed-on: https://review.coreboot.org/c/30559 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Patrick Rudolph <siro@das-labor.org>
This commit is contained in:
parent
afe15f0a34
commit
f9f5093644
|
@ -456,13 +456,15 @@ static int nvm_is_write_protected(void)
|
||||||
/* Apply protection to a range of flash */
|
/* Apply protection to a range of flash */
|
||||||
static int nvm_protect(const struct region *r)
|
static int nvm_protect(const struct region *r)
|
||||||
{
|
{
|
||||||
|
const struct spi_flash *flash = boot_device_spi_flash();
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT))
|
if (!IS_ENABLED(CONFIG_MRC_SETTINGS_PROTECT))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_BOOT_DEVICE_SPI_FLASH))
|
if (!IS_ENABLED(CONFIG_BOOT_DEVICE_SPI_FLASH))
|
||||||
return 0;
|
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 */
|
/* Protect mrc region with a Protected Range Register */
|
||||||
|
|
|
@ -572,7 +572,8 @@ void lb_spi_flash(struct lb_header *header)
|
||||||
|
|
||||||
|
|
||||||
int spi_flash_ctrlr_protect_region(const struct spi_flash *flash,
|
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;
|
const struct spi_ctrlr *ctrlr;
|
||||||
struct region flash_region = { 0 };
|
struct region flash_region = { 0 };
|
||||||
|
@ -591,7 +592,7 @@ int spi_flash_ctrlr_protect_region(const struct spi_flash *flash,
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (ctrlr->flash_protect)
|
if (ctrlr->flash_protect)
|
||||||
return ctrlr->flash_protect(flash, region);
|
return ctrlr->flash_protect(flash, region, type);
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,12 @@ struct spi_cfg {
|
||||||
|
|
||||||
struct spi_flash;
|
struct spi_flash;
|
||||||
|
|
||||||
|
enum ctrlr_prot_type {
|
||||||
|
READ_PROTECT = 1,
|
||||||
|
WRITE_PROTECT = 2,
|
||||||
|
READ_WRITE_PROTECT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* Deduct the command length from the spi_crop_chunk() calculation for
|
/* Deduct the command length from the spi_crop_chunk() calculation for
|
||||||
sizing a transaction. */
|
sizing a transaction. */
|
||||||
|
@ -144,7 +150,8 @@ struct spi_ctrlr {
|
||||||
int (*flash_probe)(const struct spi_slave *slave,
|
int (*flash_probe)(const struct spi_slave *slave,
|
||||||
struct spi_flash *flash);
|
struct spi_flash *flash);
|
||||||
int (*flash_protect)(const 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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------
|
/*-----------------------------------------------------------------------
|
||||||
|
|
|
@ -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
|
/* Protect a region of spi flash using its controller, if available. Returns
|
||||||
* < 0 on error, else 0 on success. */
|
* < 0 on error, else 0 on success. */
|
||||||
int spi_flash_ctrlr_protect_region(const struct spi_flash *flash,
|
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.
|
* This function is provided to support spi flash command-response transactions.
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#define SPI_PRR_BASE_SHIFT 0
|
#define SPI_PRR_BASE_SHIFT 0
|
||||||
#define SPI_PRR_LIMIT_SHIFT 16
|
#define SPI_PRR_LIMIT_SHIFT 16
|
||||||
#define SPI_PRR_WPE (1 << 31)
|
#define SPI_PRR_WPE (1 << 31)
|
||||||
|
#define SPI_PRR_RPE (1 << 15)
|
||||||
|
|
||||||
#define SPIBAR_PREOP 0x94
|
#define SPIBAR_PREOP 0x94
|
||||||
#define SPIBAR_OPTYPE 0x96
|
#define SPIBAR_OPTYPE 0x96
|
||||||
|
|
|
@ -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 */
|
/* Use first empty Protected Range Register to cover region of flash */
|
||||||
static int spi_flash_protect(const struct spi_flash *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 start = region_offset(region);
|
||||||
u32 end = start + region_sz(region) - 1;
|
u32 end = start + region_sz(region) - 1;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
u32 protect_mask = 0;
|
||||||
int prr;
|
int prr;
|
||||||
|
|
||||||
/* Find first empty 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 = ((end >> SPI_PRR_SHIFT) & SPI_PRR_MASK);
|
||||||
reg <<= SPI_PRR_LIMIT_SHIFT;
|
reg <<= SPI_PRR_LIMIT_SHIFT;
|
||||||
reg |= ((start >> SPI_PRR_SHIFT) & SPI_PRR_MASK);
|
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 */
|
/* Set the PRR register and verify it is protected */
|
||||||
SPIBAR32(SPI_PRR(prr)) = reg;
|
SPIBAR32(SPI_PRR(prr)) = reg;
|
||||||
reg = SPIBAR32(SPI_PRR(prr));
|
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);
|
printk(BIOS_ERR, "ERROR: Unable to set SPI PRR %d\n", prr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,11 +367,13 @@ static int fast_spi_flash_ctrlr_setup(const struct spi_slave *dev)
|
||||||
* Protected Range (FPR) register if available.
|
* Protected Range (FPR) register if available.
|
||||||
*/
|
*/
|
||||||
static int fast_spi_flash_protect(const struct spi_flash *flash,
|
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 start = region_offset(region);
|
||||||
u32 end = start + region_sz(region) - 1;
|
u32 end = start + region_sz(region) - 1;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
u32 protect_mask = 0;
|
||||||
int fpr;
|
int fpr;
|
||||||
uintptr_t fpr_base;
|
uintptr_t fpr_base;
|
||||||
BOILERPLATE_CREATE_CTX(ctx);
|
BOILERPLATE_CREATE_CTX(ctx);
|
||||||
|
@ -391,13 +393,28 @@ static int fast_spi_flash_protect(const struct spi_flash *flash,
|
||||||
return -1;
|
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 */
|
/* 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 */
|
/* Set the FPR register and verify it is protected */
|
||||||
write32((void *)fpr_base, reg);
|
write32((void *)fpr_base, reg);
|
||||||
reg = read32((void *)fpr_base);
|
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);
|
printk(BIOS_ERR, "ERROR: Unable to set SPI FPR %d\n", fpr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1010,12 +1010,14 @@ static u32 spi_fpr(u32 base, u32 limit)
|
||||||
* Returns 0 on success, -1 on failure of programming fpr registers.
|
* Returns 0 on success, -1 on failure of programming fpr registers.
|
||||||
*/
|
*/
|
||||||
static int spi_flash_protect(const struct spi_flash *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)
|
||||||
{
|
{
|
||||||
ich_spi_controller *cntlr = car_get_var_ptr(&g_cntlr);
|
ich_spi_controller *cntlr = car_get_var_ptr(&g_cntlr);
|
||||||
u32 start = region_offset(region);
|
u32 start = region_offset(region);
|
||||||
u32 end = start + region_sz(region) - 1;
|
u32 end = start + region_sz(region) - 1;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
u32 protect_mask = 0;
|
||||||
int fpr;
|
int fpr;
|
||||||
uint32_t *fpr_base;
|
uint32_t *fpr_base;
|
||||||
|
|
||||||
|
@ -1033,13 +1035,32 @@ static int spi_flash_protect(const struct spi_flash *flash,
|
||||||
return -1;
|
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 */
|
/* 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 */
|
/* Set the FPR register and verify it is protected */
|
||||||
write32(&fpr_base[fpr], reg);
|
write32(&fpr_base[fpr], reg);
|
||||||
reg = read32(&fpr_base[fpr]);
|
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);
|
printk(BIOS_ERR, "ERROR: Unable to set SPI FPR %d\n", fpr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue