diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2014-05-13 13:02:26 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-05-17 20:14:23 +0000 |
commit | 5fd33410770fbc9b29432fe6ca81a763e6b47ec4 (patch) | |
tree | ed81c35caa3cf5f5dd39f9c5eb245dbbd8b9c8d6 /board/zinger/hardware.c | |
parent | 00cf95783210c5b94565b0e0d480271dcef490ca (diff) | |
download | chrome-ec-5fd33410770fbc9b29432fe6ca81a763e6b47ec4.tar.gz |
zinger: add support to flash RW firmware
Allow flashing the RW firmware by sending Vendor-Defined Messages over
the USB-PD link.
This is not the secure update whose design is still under discussion,
it's a simple update with integrity check.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BRANCH=none
BUG=chrome-os-partner:28330
TEST=using the following CLs,
./util/flash_pd.py ./build/zinger/ec.RW.flat
and see Zinger booting on RW, repeat the operations with different
builds of the RW firmware.
Change-Id: Icd90eb92f7321ccd66341a50b9dabd73c59c68c1
Reviewed-on: https://chromium-review.googlesource.com/197948
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'board/zinger/hardware.c')
-rw-r--r-- | board/zinger/hardware.c | 150 |
1 files changed, 145 insertions, 5 deletions
diff --git a/board/zinger/hardware.c b/board/zinger/hardware.c index 1f9851c707..cf71c3ffad 100644 --- a/board/zinger/hardware.c +++ b/board/zinger/hardware.c @@ -9,6 +9,7 @@ #include "common.h" #include "cpu.h" #include "registers.h" +#include "sha1.h" #include "task.h" #include "timer.h" #include "util.h" @@ -99,11 +100,14 @@ static void pins_init(void) static void adc_init(void) { - /* ADC calibration (done with ADEN = 0) */ - STM32_ADC_CR = 1 << 31; /* set ADCAL = 1, ADC off */ - /* wait for the end of calibration */ - while (STM32_ADC_CR & (1 << 31)) - ; + /* Only do the calibration if the ADC is off */ + if (!(STM32_ADC_CR & 1)) { + /* ADC calibration */ + STM32_ADC_CR = 1 << 31; /* set ADCAL = 1, ADC off */ + /* wait for the end of calibration */ + while (STM32_ADC_CR & (1 << 31)) + ; + } /* ADC enabled */ STM32_ADC_CR = 1 << 0; /* Single conversion, right aligned, 12-bit */ @@ -178,3 +182,139 @@ int adc_read_channel(enum adc_channel ch) return value; } + +/* ---- flash handling ---- */ + +/* + * Approximate number of CPU cycles per iteration of the loop when polling + * the flash status + */ +#define CYCLE_PER_FLASH_LOOP 10 + +/* Flash page programming timeout. This is 2x the datasheet max. */ +#define FLASH_TIMEOUT_US 16000 +#define FLASH_TIMEOUT_LOOP \ + (FLASH_TIMEOUT_US * (CPU_CLOCK / SECOND) / CYCLE_PER_FLASH_LOOP) + +/* Flash unlocking keys */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +/* Lock bits for FLASH_CR register */ +#define PG (1<<0) +#define PER (1<<1) +#define STRT (1<<6) +#define CR_LOCK (1<<7) + +int flash_write_rw(int offset, int size, const char *data) +{ + uint16_t *address = (uint16_t *) + (CONFIG_FLASH_BASE + CONFIG_FW_RW_OFF + offset); + int res = EC_SUCCESS; + int i; + + if ((uint32_t)address > CONFIG_FLASH_BASE + CONFIG_FLASH_SIZE) + return EC_ERROR_INVAL; + + /* unlock CR if needed */ + if (STM32_FLASH_CR & CR_LOCK) { + STM32_FLASH_KEYR = KEY1; + STM32_FLASH_KEYR = KEY2; + } + + /* Clear previous error status */ + STM32_FLASH_SR = 0x34; + /* set the ProGram bit */ + STM32_FLASH_CR |= PG; + + for (; size > 0; size -= sizeof(uint16_t)) { + /* wait to be ready */ + for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); + i++) + ; + /* write the half word */ + *address++ = data[0] + (data[1] << 8); + data += 2; + /* Wait for writes to complete */ + for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); + i++) + ; + if (i == FLASH_TIMEOUT_LOOP) { + res = EC_ERROR_TIMEOUT; + goto exit_wr; + } + /* Check for error conditions - erase failed, voltage error, + * protection error */ + if (STM32_FLASH_SR & 0x14) { + res = EC_ERROR_UNKNOWN; + goto exit_wr; + } + } + +exit_wr: + STM32_FLASH_CR &= ~PG; + STM32_FLASH_CR = CR_LOCK; + + return res; +} + +int flash_erase_rw(void) +{ + int res = EC_SUCCESS; + int offset = CONFIG_FW_RW_OFF; + int size = CONFIG_FW_RW_SIZE; + + /* unlock CR if needed */ + if (STM32_FLASH_CR & CR_LOCK) { + STM32_FLASH_KEYR = KEY1; + STM32_FLASH_KEYR = KEY2; + } + + /* Clear previous error status */ + STM32_FLASH_SR = 0x34; + /* set PER bit */ + STM32_FLASH_CR |= PER; + + for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, + offset += CONFIG_FLASH_ERASE_SIZE) { + int i; + /* select page to erase */ + STM32_FLASH_AR = CONFIG_FLASH_BASE + offset; + /* set STRT bit : start erase */ + STM32_FLASH_CR |= STRT; + + + /* Wait for erase to complete */ + for (i = 0; (STM32_FLASH_SR & 1) && (i < FLASH_TIMEOUT_LOOP); + i++) + ; + if (i == FLASH_TIMEOUT_LOOP) { + res = EC_ERROR_TIMEOUT; + goto exit_er; + } + + /* + * Check for error conditions - erase failed, voltage error, + * protection error + */ + if (STM32_FLASH_SR & 0x14) { + res = EC_ERROR_UNKNOWN; + goto exit_er; + } + } + +exit_er: + STM32_FLASH_CR &= ~PER; + STM32_FLASH_CR = CR_LOCK; + + return res; +} + +static struct sha1_ctx ctx; +uint8_t *flash_hash_rw(void) +{ + sha1_init(&ctx); + sha1_update(&ctx, (void *)CONFIG_FLASH_BASE + CONFIG_FW_RW_OFF, + CONFIG_FW_RW_SIZE - 32); + return sha1_final(&ctx); +} |