summaryrefslogtreecommitdiff
path: root/common/flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/flash.c')
-rw-r--r--common/flash.c77
1 files changed, 62 insertions, 15 deletions
diff --git a/common/flash.c b/common/flash.c
index 275e4692e8..673c962295 100644
--- a/common/flash.c
+++ b/common/flash.c
@@ -523,8 +523,12 @@ int flash_protect_at_boot(uint32_t new_flags)
uint32_t flash_get_protect(void)
{
uint32_t flags = 0;
- int not_protected[2] = {0};
int i;
+ /* Region protection status */
+ int not_protected[FLASH_REGION_COUNT] = {0};
+ /* Flags that must be set to set ALL_NOW flag. */
+ const uint32_t all_flags = EC_FLASH_PROTECT_RO_NOW |
+ EC_FLASH_PROTECT_RW_NOW;
/* Read write protect GPIO */
#ifdef CONFIG_WP_ALWAYS
@@ -544,26 +548,29 @@ uint32_t flash_get_protect(void)
/* Scan flash protection */
for (i = 0; i < PHYSICAL_BANKS; i++) {
- /* Is this bank part of RO */
int is_ro = (i >= WP_BANK_OFFSET &&
- i < WP_BANK_OFFSET + WP_BANK_COUNT) ? 1 : 0;
-
- int bank_flag = (is_ro ? EC_FLASH_PROTECT_RO_NOW :
- EC_FLASH_PROTECT_ALL_NOW);
+ i < WP_BANK_OFFSET + WP_BANK_COUNT);
+ enum flash_region region = is_ro ? FLASH_REGION_RO :
+ FLASH_REGION_RW;
+ int bank_flag = is_ro ? EC_FLASH_PROTECT_RO_NOW :
+ EC_FLASH_PROTECT_RW_NOW;
if (flash_physical_get_protect(i)) {
/* At least one bank in the region is protected */
flags |= bank_flag;
- if (not_protected[is_ro])
+ if (not_protected[region])
flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
} else {
/* At least one bank in the region is NOT protected */
- not_protected[is_ro] = 1;
+ not_protected[region] = 1;
if (flags & bank_flag)
flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
}
}
+ if ((flags & all_flags) == all_flags)
+ flags |= EC_FLASH_PROTECT_ALL_NOW;
+
/*
* If the RW banks are protected but the RO banks aren't, that's
* inconsistent.
@@ -572,10 +579,14 @@ uint32_t flash_get_protect(void)
* since some chips can also protect ALL_NOW for the current boot by
* locking up the flash program-erase registers.
*/
- if ((flags & EC_FLASH_PROTECT_ALL_NOW) &&
- !(flags & EC_FLASH_PROTECT_RO_NOW))
+ if ((flags & all_flags) && !(flags & EC_FLASH_PROTECT_RO_NOW))
flags |= EC_FLASH_PROTECT_ERROR_INCONSISTENT;
+#ifndef CONFIG_FLASH_PROTECT_RW
+ /* RW flag was used for intermediate computations, clear it now. */
+ flags &= ~EC_FLASH_PROTECT_RW_NOW;
+#endif
+
/* Add in flags from physical layer */
return flags | flash_physical_get_protect_flags();
}
@@ -585,7 +596,8 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
int retval = EC_SUCCESS;
int rv;
int old_flags_at_boot = flash_get_protect() &
- (EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_ALL_AT_BOOT);
+ (EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RW_AT_BOOT |
+ EC_FLASH_PROTECT_ALL_AT_BOOT);
int new_flags_at_boot = old_flags_at_boot;
/* Sanitize input flags */
@@ -618,9 +630,23 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
new_flags_at_boot &= ~(mask & EC_FLASH_PROTECT_RO_AT_BOOT);
new_flags_at_boot |= flags & EC_FLASH_PROTECT_RO_AT_BOOT;
+ /* Removing ALL must also remove RW */
if ((mask & EC_FLASH_PROTECT_ALL_AT_BOOT) &&
- !(flags & EC_FLASH_PROTECT_ALL_AT_BOOT))
+ !(flags & EC_FLASH_PROTECT_ALL_AT_BOOT)) {
new_flags_at_boot &= ~EC_FLASH_PROTECT_ALL_AT_BOOT;
+#ifdef CONFIG_FLASH_PROTECT_RW
+ new_flags_at_boot &= ~EC_FLASH_PROTECT_RW_AT_BOOT;
+#endif
+ }
+
+#ifdef CONFIG_FLASH_PROTECT_RW
+ /* Removing RW must also remove ALL (otherwise nothing will happen). */
+ if ((mask & EC_FLASH_PROTECT_RW_AT_BOOT) &&
+ !(flags & EC_FLASH_PROTECT_RW_AT_BOOT)) {
+ new_flags_at_boot &= ~EC_FLASH_PROTECT_ALL_AT_BOOT;
+ new_flags_at_boot &= ~EC_FLASH_PROTECT_RW_AT_BOOT;
+ }
+#endif
if (new_flags_at_boot != old_flags_at_boot) {
rv = flash_protect_at_boot(new_flags_at_boot);
@@ -638,11 +664,15 @@ int flash_set_protect(uint32_t mask, uint32_t flags)
return retval;
/*
- * The case where ALL_AT_BOOT is unset is already covered above,
+ * The case where ALL/RW_AT_BOOT is unset is already covered above,
* so we do not need to mask it out.
*/
new_flags_at_boot |= flags & EC_FLASH_PROTECT_ALL_AT_BOOT;
+#ifdef CONFIG_FLASH_PROTECT_RW
+ new_flags_at_boot |= flags & EC_FLASH_PROTECT_RW_AT_BOOT;
+#endif
+
if (new_flags_at_boot != old_flags_at_boot) {
rv = flash_protect_at_boot(new_flags_at_boot);
if (rv)
@@ -689,6 +719,12 @@ static int command_flash_info(int argc, char **argv)
ccputs(" ro_now");
if (i & EC_FLASH_PROTECT_ALL_NOW)
ccputs(" all_now");
+#ifdef CONFIG_FLASH_PROTECT_RW
+ if (i & EC_FLASH_PROTECT_RW_AT_BOOT)
+ ccputs(" rw_at_boot");
+ if (i & EC_FLASH_PROTECT_RW_NOW)
+ ccputs(" rw_now");
+#endif
if (i & EC_FLASH_PROTECT_ERROR_STUCK)
ccputs(" STUCK");
if (i & EC_FLASH_PROTECT_ERROR_INCONSISTENT)
@@ -838,6 +874,14 @@ static int command_flash_wp(int argc, char **argv)
if (!strcasecmp(argv[1], "noall"))
return flash_set_protect(EC_FLASH_PROTECT_ALL_AT_BOOT, 0);
+#ifdef CONFIG_FLASH_PROTECT_RW
+ if (!strcasecmp(argv[1], "rw"))
+ return flash_set_protect(EC_FLASH_PROTECT_RW_AT_BOOT, -1);
+
+ if (!strcasecmp(argv[1], "norw"))
+ return flash_set_protect(EC_FLASH_PROTECT_RW_AT_BOOT, 0);
+#endif
+
/* Do this last, since anything starting with 'n' means "no" */
if (parse_bool(argv[1], &val))
return flash_set_protect(EC_FLASH_PROTECT_RO_AT_BOOT,
@@ -846,8 +890,11 @@ static int command_flash_wp(int argc, char **argv)
return EC_ERROR_PARAM1;
}
DECLARE_CONSOLE_COMMAND(flashwp, command_flash_wp,
- "<BOOLEAN> | now | all | noall",
- "Modify flash write protect");
+ "<BOOLEAN> | now | all | noall"
+#ifdef CONFIG_FLASH_PROTECT_RW
+ " | rw | norw"
+#endif
+ , "Modify flash write protect");
/*****************************************************************************/
/* Host commands */