diff options
-rw-r--r-- | board/zinger/hardware.c | 2 | ||||
-rw-r--r-- | chip/stm32/flash-f.c | 148 | ||||
-rw-r--r-- | chip/stm32/registers.h | 50 | ||||
-rw-r--r-- | chip/stm32/system.c | 2 |
4 files changed, 122 insertions, 80 deletions
diff --git a/board/zinger/hardware.c b/board/zinger/hardware.c index d6a8d1d4c3..c3cf2b5f4a 100644 --- a/board/zinger/hardware.c +++ b/board/zinger/hardware.c @@ -465,7 +465,7 @@ void flash_physical_permanent_protect(void) write_optb(0, 0x11); /* Reset by using OBL_LAUNCH to take changes into account */ asm volatile("cpsid i"); - STM32_FLASH_CR |= STM32_FLASH_CR_OBL_LAUNCH; + STM32_FLASH_CR |= FLASH_CR_OBL_LAUNCH; /* Spin and wait for reboot; should never return */ while (1) ; diff --git a/chip/stm32/flash-f.c b/chip/stm32/flash-f.c index 8421ca61b1..15be87beeb 100644 --- a/chip/stm32/flash-f.c +++ b/chip/stm32/flash-f.c @@ -27,22 +27,6 @@ /* Flash page programming timeout. This is 2x the datasheet max. */ #define FLASH_TIMEOUT_US 16000 -/* Flash unlocking keys */ -#define KEY1 0x45670123 -#define KEY2 0xCDEF89AB - -/* Lock bits for FLASH_CR register */ -#define PG (1<<0) -#define PER (1<<1) -#define OPTPG (1<<4) -#define OPTER (1<<5) -#define STRT (1<<6) -#define CR_LOCK (1<<7) -#define PRG_LOCK 0 -#define OPT_LOCK (1<<9) - -static int write_optb(int byte, uint8_t value); - static inline int calculate_flash_timeout(void) { return (FLASH_TIMEOUT_US * @@ -52,11 +36,21 @@ static inline int calculate_flash_timeout(void) static int wait_busy(void) { int timeout = calculate_flash_timeout(); - while (STM32_FLASH_SR & (1 << 0) && timeout-- > 0) + while ((STM32_FLASH_SR & FLASH_SR_BUSY) && timeout-- > 0) udelay(CYCLE_PER_FLASH_LOOP); return (timeout > 0) ? EC_SUCCESS : EC_ERROR_TIMEOUT; } + +/* + * We at least unlock the control register lock. + * We may also unlock other locks. + */ +enum extra_lock_type { + NO_EXTRA_LOCK = 0, + OPT_LOCK = 1, +}; + static int unlock(int locks) { /* @@ -65,27 +59,30 @@ static int unlock(int locks) */ ignore_bus_fault(1); - /* unlock CR if needed */ - if (STM32_FLASH_CR & CR_LOCK) { - STM32_FLASH_KEYR = KEY1; - STM32_FLASH_KEYR = KEY2; + /* Always unlock CR if needed */ + if (STM32_FLASH_CR & FLASH_CR_LOCK) { + STM32_FLASH_KEYR = FLASH_KEYR_KEY1; + STM32_FLASH_KEYR = FLASH_KEYR_KEY2; } /* unlock option memory if required */ - if ((locks & OPT_LOCK) && !(STM32_FLASH_CR & OPT_LOCK)) { - STM32_FLASH_OPTKEYR = KEY1; - STM32_FLASH_OPTKEYR = KEY2; + if ((locks & OPT_LOCK) && STM32_FLASH_OPT_LOCKED) { + STM32_FLASH_OPTKEYR = FLASH_OPTKEYR_KEY1; + STM32_FLASH_OPTKEYR = FLASH_OPTKEYR_KEY2; } /* Re-enable bus fault handler */ ignore_bus_fault(0); - return ((STM32_FLASH_CR ^ OPT_LOCK) & (locks | CR_LOCK)) ? - EC_ERROR_UNKNOWN : EC_SUCCESS; + if ((locks & OPT_LOCK) && STM32_FLASH_OPT_LOCKED) + return EC_ERROR_UNKNOWN; + if (STM32_FLASH_CR & FLASH_CR_LOCK) + return EC_ERROR_UNKNOWN; + return EC_SUCCESS; } static void lock(void) { - STM32_FLASH_CR = CR_LOCK; + STM32_FLASH_CR |= FLASH_CR_LOCK; } /* @@ -121,8 +118,8 @@ static int erase_optb(void) return rv; /* Must be set in 2 separate lines. */ - STM32_FLASH_CR |= OPTER; - STM32_FLASH_CR |= STRT; + STM32_FLASH_CR |= FLASH_CR_OPTSTRT; + STM32_FLASH_CR |= FLASH_CR_STRT; rv = wait_busy(); if (rv) @@ -132,6 +129,7 @@ static int erase_optb(void) return EC_SUCCESS; } +static int write_optb(int byte, uint8_t value); /* * Since the option byte erase is WHOLE erase, this function is to keep * rest of bytes, but make this byte 0xff. @@ -190,12 +188,12 @@ static int write_optb(int byte, uint8_t value) return rv; /* set OPTPG bit */ - STM32_FLASH_CR |= OPTPG; + STM32_FLASH_CR |= FLASH_CR_OPTPG; *hword = ((~value) << STM32_OPTB_COMPL_SHIFT) | value; /* reset OPTPG bit */ - STM32_FLASH_CR &= ~OPTPG; + STM32_FLASH_CR &= ~FLASH_CR_OPTPG; rv = wait_busy(); if (rv) @@ -210,23 +208,38 @@ static int write_optb(int byte, uint8_t value) int flash_physical_write(int offset, int size, const char *data) { +#if CONFIG_FLASH_WRITE_SIZE == 1 + uint8_t *address = (uint8_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset); + uint8_t quantum = 0; +#elif CONFIG_FLASH_WRITE_SIZE == 2 uint16_t *address = (uint16_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset); + uint16_t quantum = 0; +#elif CONFIG_FLASH_WRITE_SIZE == 4 + uint32_t *address = (uint32_t *)(CONFIG_PROGRAM_MEMORY_BASE + offset); + uint32_t quantum = 0; +#else +#error "CONFIG_FLASH_WRITE_SIZE not supported." +#endif int res = EC_SUCCESS; int timeout = calculate_flash_timeout(); - int i; - if (unlock(PRG_LOCK) != EC_SUCCESS) { + if (unlock(NO_EXTRA_LOCK) != EC_SUCCESS) { res = EC_ERROR_UNKNOWN; goto exit_wr; } /* Clear previous error status */ - STM32_FLASH_SR = 0x34; + STM32_FLASH_SR = FLASH_SR_ALL_ERR | FLASH_SR_EOP; /* set PG bit */ - STM32_FLASH_CR |= PG; + STM32_FLASH_CR |= FLASH_CR_PG; + + for (; size > 0; size -= CONFIG_FLASH_WRITE_SIZE) { + int i; - for (; size > 0; size -= sizeof(uint16_t)) { + for (i = CONFIG_FLASH_WRITE_SIZE - 1, quantum = 0; i >= 0; i--) + quantum = (quantum << 8) + data[i]; + data += CONFIG_FLASH_WRITE_SIZE; /* * Reload the watchdog timer to avoid watchdog reset when doing * long writing with interrupt disabled. @@ -234,27 +247,30 @@ int flash_physical_write(int offset, int size, const char *data) watchdog_reload(); /* wait to be ready */ - for (i = 0; (STM32_FLASH_SR & 1) && (i < timeout); + for (i = 0; + (STM32_FLASH_SR & FLASH_SR_BUSY) && + (i < timeout); i++) ; - /* write the half word */ - *address++ = data[0] + (data[1] << 8); - data += 2; + /* write the data */ + *address++ = quantum; /* Wait for writes to complete */ - for (i = 0; (STM32_FLASH_SR & 1) && (i < timeout); + for (i = 0; + (STM32_FLASH_SR & FLASH_SR_BUSY) && + (i < timeout); i++) ; - if (STM32_FLASH_SR & 1) { + if (STM32_FLASH_SR & FLASH_SR_BUSY) { res = EC_ERROR_TIMEOUT; goto exit_wr; } /* Check for error conditions - erase failed, voltage error, * protection error */ - if (STM32_FLASH_SR & 0x14) { + if (STM32_FLASH_SR & FLASH_SR_ALL_ERR) { res = EC_ERROR_UNKNOWN; goto exit_wr; } @@ -262,7 +278,7 @@ int flash_physical_write(int offset, int size, const char *data) exit_wr: /* Disable PG bit */ - STM32_FLASH_CR &= ~PG; + STM32_FLASH_CR &= ~FLASH_CR_PG; lock(); @@ -272,29 +288,30 @@ exit_wr: int flash_physical_erase(int offset, int size) { int res = EC_SUCCESS; + int sector_size; + int timeout_us; - if (unlock(PRG_LOCK) != EC_SUCCESS) + if (unlock(NO_EXTRA_LOCK) != EC_SUCCESS) return EC_ERROR_UNKNOWN; /* Clear previous error status */ - STM32_FLASH_SR = 0x34; + STM32_FLASH_SR = FLASH_SR_ALL_ERR | FLASH_SR_EOP; - /* set PER bit */ - STM32_FLASH_CR |= PER; + /* set SER/PER bit */ + STM32_FLASH_CR |= FLASH_CR_PER; - for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, - offset += CONFIG_FLASH_ERASE_SIZE) { + while (size > 0) { timestamp_t deadline; - + sector_size = CONFIG_FLASH_ERASE_SIZE; + timeout_us = FLASH_TIMEOUT_US; /* Do nothing if already erased */ - if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE)) - continue; - + if (flash_is_erased(offset, sector_size)) + goto next_sector; /* select page to erase */ STM32_FLASH_AR = CONFIG_PROGRAM_MEMORY_BASE + offset; /* set STRT bit : start erase */ - STM32_FLASH_CR |= STRT; + STM32_FLASH_CR |= FLASH_CR_STRT; /* * Reload the watchdog timer to avoid watchdog reset during a @@ -302,13 +319,14 @@ int flash_physical_erase(int offset, int size) */ watchdog_reload(); - deadline.val = get_time().val + FLASH_TIMEOUT_US; + deadline.val = get_time().val + timeout_us; /* Wait for erase to complete */ - while ((STM32_FLASH_SR & 1) && + watchdog_reload(); + while ((STM32_FLASH_SR & FLASH_SR_BUSY) && (get_time().val < deadline.val)) { - usleep(300); + usleep(timeout_us/100); } - if (STM32_FLASH_SR & 1) { + if (STM32_FLASH_SR & FLASH_SR_BUSY) { res = EC_ERROR_TIMEOUT; goto exit_er; } @@ -317,15 +335,18 @@ int flash_physical_erase(int offset, int size) * Check for error conditions - erase failed, voltage error, * protection error */ - if (STM32_FLASH_SR & 0x14) { + if (STM32_FLASH_SR & FLASH_SR_ALL_ERR) { res = EC_ERROR_UNKNOWN; goto exit_er; } +next_sector: + size -= sector_size; + offset += sector_size; } exit_er: - /* reset PER bit */ - STM32_FLASH_CR &= ~PER; + /* reset SER/PER bit */ + STM32_FLASH_CR &= ~FLASH_CR_PER; lock(); @@ -400,6 +421,9 @@ static int registers_need_reset(void) int ro_at_boot = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? 1 : 0; int ro_wp_region_start = WP_BANK_OFFSET; int ro_wp_region_end = WP_BANK_OFFSET + WP_BANK_COUNT; +#ifdef CONFIG_FLASH_PSTATE + ro_wp_region_end += PSTATE_BANK_COUNT; +#endif for (i = ro_wp_region_start; i < ro_wp_region_end; i++) if (flash_physical_get_protect_at_boot(i) != ro_at_boot) diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index 72623745f5..b885c8fcca 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -1298,14 +1298,14 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_FLASH_WRPR REG32(STM32_FLASH_REGS_BASE + 0x20) #define STM32_OPTB_BASE 0x1ff80000 -#define STM32_OPTB_RDP 0x00 -#define STM32_OPTB_USER 0x04 -#define STM32_OPTB_WRP1L 0x08 -#define STM32_OPTB_WRP1H 0x0c -#define STM32_OPTB_WRP2L 0x10 -#define STM32_OPTB_WRP2H 0x14 -#define STM32_OPTB_WRP3L 0x18 -#define STM32_OPTB_WRP3H 0x1c +#define STM32_OPTB_RDP 0x00 +#define STM32_OPTB_USER 0x04 +#define STM32_OPTB_WRP1L 0x08 +#define STM32_OPTB_WRP1H 0x0c +#define STM32_OPTB_WRP2L 0x10 +#define STM32_OPTB_WRP2H 0x14 +#define STM32_OPTB_WRP3L 0x18 +#define STM32_OPTB_WRP3H 0x1c #elif defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3) #define STM32_FLASH_REGS_BASE 0x40022000 @@ -1316,22 +1316,40 @@ typedef volatile struct stm32_spi_regs stm32_spi_regs_t; #define STM32_FLASH_ACR_LATENCY (1 << 0) #define STM32_FLASH_ACR_PRFTEN (1 << 4) #define STM32_FLASH_KEYR REG32(STM32_FLASH_REGS_BASE + 0x04) +#define FLASH_KEYR_KEY1 0x45670123 +#define FLASH_KEYR_KEY2 0xCDEF89AB + #define STM32_FLASH_OPTKEYR REG32(STM32_FLASH_REGS_BASE + 0x08) +#define FLASH_OPTKEYR_KEY1 FLASH_KEYR_KEY1 +#define FLASH_OPTKEYR_KEY2 FLASH_KEYR_KEY2 #define STM32_FLASH_SR REG32(STM32_FLASH_REGS_BASE + 0x0c) +#define FLASH_SR_BUSY (1 << 0) +#define FLASH_SR_PGERR (1 << 2) +#define FLASH_SR_WRPRTERR (1 << 4) +#define FLASH_SR_ALL_ERR \ + (FLASH_SR_PGERR | FLASH_SR_WRPRTERR) +#define FLASH_SR_EOP (1 << 5) #define STM32_FLASH_CR REG32(STM32_FLASH_REGS_BASE + 0x10) -#define STM32_FLASH_CR_OBL_LAUNCH (1 << 13) +#define FLASH_CR_PG (1 << 0) +#define FLASH_CR_PER (1 << 1) +#define FLASH_CR_OPTPG (1 << 4) +#define FLASH_CR_OPTSTRT (1 << 5) +#define FLASH_CR_STRT (1 << 6) +#define FLASH_CR_LOCK (1 << 7) +#define FLASH_CR_OPTWRE (1 << 9) +#define FLASH_CR_OBL_LAUNCH (1 << 13) +#define STM32_FLASH_OPT_LOCKED (STM32_FLASH_CR & FLASH_CR_OPTWRE) #define STM32_FLASH_AR REG32(STM32_FLASH_REGS_BASE + 0x14) #define STM32_FLASH_OBR REG32(STM32_FLASH_REGS_BASE + 0x1c) -#define STM32_FLASH_OBR_RDP_MASK (3 << 1) +#define STM32_FLASH_OBR_RDP_MASK (3 << 1) #define STM32_FLASH_WRPR REG32(STM32_FLASH_REGS_BASE + 0x20) #define STM32_OPTB_BASE 0x1FFFF800 - -#define STM32_OPTB_RDP_OFF 0x00 -#define STM32_OPTB_USER_OFF 0x02 -#define STM32_OPTB_WRP_OFF(n) (0x08 + (n&3) * 2) -#define STM32_OPTB_WRP01 0x08 -#define STM32_OPTB_WRP23 0x0c +#define STM32_OPTB_RDP_OFF 0x00 +#define STM32_OPTB_USER_OFF 0x02 +#define STM32_OPTB_WRP_OFF(n) (0x08 + (n&3) * 2) +#define STM32_OPTB_WRP01 0x08 +#define STM32_OPTB_WRP23 0x0c #define STM32_OPTB_COMPL_SHIFT 8 diff --git a/chip/stm32/system.c b/chip/stm32/system.c index b81dc0055c..9f90d2db41 100644 --- a/chip/stm32/system.c +++ b/chip/stm32/system.c @@ -291,7 +291,7 @@ void system_reset(int flags) * The reload request triggers a chip reset, so let's just * use this for hard reset. */ - STM32_FLASH_CR |= STM32_FLASH_CR_OBL_LAUNCH; + STM32_FLASH_CR |= FLASH_CR_OBL_LAUNCH; #elif defined(CHIP_FAMILY_STM32L4) STM32_FLASH_KEYR = FLASH_KEYR_KEY1; STM32_FLASH_KEYR = FLASH_KEYR_KEY2; |