diff --git a/src/soc/intel/common/Kconfig b/src/soc/intel/common/Kconfig index 8eae23b6e7..affec55718 100644 --- a/src/soc/intel/common/Kconfig +++ b/src/soc/intel/common/Kconfig @@ -9,6 +9,10 @@ config CACHE_MRC_SETTINGS bool "Save cached MRC settings" default n +config SOC_INTEL_COMMON_SPI_PROTECT + bool + default n + if CACHE_MRC_SETTINGS config MRC_SETTINGS_CACHE_BASE diff --git a/src/soc/intel/common/Makefile.inc b/src/soc/intel/common/Makefile.inc index 13ba21bcbe..888c657f3e 100644 --- a/src/soc/intel/common/Makefile.inc +++ b/src/soc/intel/common/Makefile.inc @@ -19,6 +19,7 @@ postcar-y += util.c ramstage-y += hda_verb.c ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += mrc_cache.c ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += nvm.c +ramstage-$(CONFIG_SOC_INTEL_COMMON_SPI_PROTECT) += spi.c ramstage-$(CONFIG_SOC_INTEL_COMMON_LPSS_I2C) += lpss_i2c.c ramstage-$(CONFIG_SOC_INTEL_COMMON_RESET) += reset.c ramstage-y += util.c diff --git a/src/soc/intel/common/nvm.c b/src/soc/intel/common/nvm.c index 99dcaac39e..6b86faf2e8 100644 --- a/src/soc/intel/common/nvm.c +++ b/src/soc/intel/common/nvm.c @@ -20,9 +20,9 @@ #include #include #include -#include #include #include "nvm.h" +#include "spi.h" /* This module assumes the flash is memory mapped just below 4GiB in the * address space for reading. Also this module assumes an area it erased diff --git a/src/soc/intel/common/spi.c b/src/soc/intel/common/spi.c new file mode 100644 index 0000000000..e73a55e125 --- /dev/null +++ b/src/soc/intel/common/spi.c @@ -0,0 +1,66 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "spi.h" + +/* + * Protect range of SPI flash defined by [start, start+size-1] using Flash + * Protected Range (FPR) register if available. + */ +int spi_flash_protect(u32 start, u32 size) +{ + struct fpr_info fpr_info; + u32 end = start + size - 1; + u32 reg; + int fpr; + uintptr_t fpr_base; + + if (spi_get_fpr_info(&fpr_info) == -1) { + printk(BIOS_ERR, "ERROR: FPR Info not found!\n"); + return -1; + } + + fpr_base = fpr_info.base; + + /* Find first empty FPR */ + for (fpr = 0; fpr < fpr_info.max; fpr++) { + reg = read32((void *)fpr_base); + if (reg == 0) + break; + fpr_base += sizeof(uint32_t); + } + + if (fpr >= fpr_info.max) { + printk(BIOS_ERR, "ERROR: No SPI FPR free!\n"); + return -1; + } + + /* Set protected range base and limit */ + reg = SPI_FPR(start, end) | SPI_FPR_WPE; + + /* Set the FPR register and verify it is protected */ + write32((void *)fpr_base, reg); + reg = read32((void *)fpr_base); + if (!(reg & SPI_FPR_WPE)) { + printk(BIOS_ERR, "ERROR: Unable to set SPI FPR %d\n", fpr); + return -1; + } + + printk(BIOS_INFO, "%s: FPR %d is enabled for range 0x%08x-0x%08x\n", + __func__, fpr, start, end); + return 0; +} diff --git a/src/soc/intel/common/spi.h b/src/soc/intel/common/spi.h new file mode 100644 index 0000000000..a89f7925aa --- /dev/null +++ b/src/soc/intel/common/spi.h @@ -0,0 +1,45 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define SPI_FPR_SHIFT 12 +#define SPI_FPR_MASK 0x7fff +#define SPI_FPR_BASE_SHIFT 0 +#define SPI_FPR_LIMIT_SHIFT 16 +#define SPI_FPR_RPE (1 << 15) /* Read Protect */ +#define SPI_FPR_WPE (1 << 31) /* Write Protect */ +#define SPI_FPR(base, limit) \ + (((((limit) >> SPI_FPR_SHIFT) & SPI_FPR_MASK) << SPI_FPR_LIMIT_SHIFT) |\ + ((((base) >> SPI_FPR_SHIFT) & SPI_FPR_MASK) << SPI_FPR_BASE_SHIFT)) + +struct fpr_info { + /* Offset of first FPR register */ + uintptr_t base; + /* Maximum number of FPR registers */ + uint8_t max; +}; + +/* + * SoC is expected to implement this function to provide address of first FPR + * register and max count of FPR registers. + * + * On success return 0 else -1. + */ +int spi_get_fpr_info(struct fpr_info *info); + +/* + * Protect range of SPI flash defined by [start, start+size-1] using Flash + * Protected Range (FPR) register if available. + */ +int spi_flash_protect(u32 start, u32 size);