summaryrefslogtreecommitdiff
path: root/board/zinger/hardware.c
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2014-05-13 13:02:26 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-05-17 20:14:23 +0000
commit5fd33410770fbc9b29432fe6ca81a763e6b47ec4 (patch)
treeed81c35caa3cf5f5dd39f9c5eb245dbbd8b9c8d6 /board/zinger/hardware.c
parent00cf95783210c5b94565b0e0d480271dcef490ca (diff)
downloadchrome-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.c150
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);
+}