summaryrefslogtreecommitdiff
path: root/chip/it83xx
diff options
context:
space:
mode:
Diffstat (limited to 'chip/it83xx')
-rw-r--r--chip/it83xx/build.mk1
-rw-r--r--chip/it83xx/config_chip.h13
-rw-r--r--chip/it83xx/flash.c765
-rw-r--r--chip/it83xx/registers.h26
-rw-r--r--chip/it83xx/system.c27
5 files changed, 820 insertions, 12 deletions
diff --git a/chip/it83xx/build.mk b/chip/it83xx/build.mk
index d8e75f0726..9d4191aad4 100644
--- a/chip/it83xx/build.mk
+++ b/chip/it83xx/build.mk
@@ -17,6 +17,7 @@ chip-y=hwtimer.o uart.o gpio.o system.o jtag.o clock.o irq.o intc.o
# Optional chip modules
chip-$(CONFIG_WATCHDOG)+=watchdog.o
chip-$(CONFIG_FANS)+=fan.o pwm.o
+chip-$(CONFIG_FLASH)+=flash.o
chip-$(CONFIG_PWM)+=pwm.o
chip-$(CONFIG_ADC)+=adc.o
chip-$(CONFIG_EC2I)+=ec2i.o
diff --git a/chip/it83xx/config_chip.h b/chip/it83xx/config_chip.h
index b38decefdc..01676a9171 100644
--- a/chip/it83xx/config_chip.h
+++ b/chip/it83xx/config_chip.h
@@ -47,14 +47,19 @@
#define CONFIG_FLASH_ERASE_SIZE 0x00000400 /* erase bank size */
#define CONFIG_FLASH_WRITE_SIZE 0x00000004 /* minimum write size */
-/* Ideal flash write size fills the 32-entry flash write buffer */
-#define CONFIG_FLASH_WRITE_IDEAL_SIZE (32 * 4)
+#define CONFIG_IT83XX_ILM_BLOCK_SIZE 0x00001000
+
+/*
+ * The AAI program instruction allows continue write flash
+ * until write disable instruction.
+ */
+#define CONFIG_FLASH_WRITE_IDEAL_SIZE CONFIG_FLASH_ERASE_SIZE
/* This is the physical size of the flash on the chip. We'll reserve one bank
* in order to emulate per-bank write-protection UNTIL REBOOT. The hardware
* doesn't support a write-protect pin, and if we make the write-protection
* permanent, it can't be undone easily enough to support RMA. */
-#define CONFIG_FLASH_PHYSICAL_SIZE 0x00020000
+#define CONFIG_FLASH_PHYSICAL_SIZE 0x00040000
/****************************************************************************/
/* Define our flash layout. */
@@ -77,11 +82,11 @@
/* Use hardware specific udelay() for this chip */
#define CONFIG_HW_SPECIFIC_UDELAY
+#define CONFIG_FW_RESET_VECTOR
/* Optional features present on this chip */
#define CONFIG_ADC
#define CONFIG_EC2I
-#undef CONFIG_FLASH
#define CONFIG_I2C
#define CONFIG_LPC
#define CONFIG_PECI
diff --git a/chip/it83xx/flash.c b/chip/it83xx/flash.c
new file mode 100644
index 0000000000..579aea3fce
--- /dev/null
+++ b/chip/it83xx/flash.c
@@ -0,0 +1,765 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "console.h"
+#include "flash.h"
+#include "host_command.h"
+#include "system.h"
+#include "util.h"
+#include "watchdog.h"
+#include "registers.h"
+#include "task.h"
+#include "shared_mem.h"
+#include "uart.h"
+
+const char __flash_dma_start;
+#define FLASH_DMA_START ((uint32_t) &__flash_dma_start)
+#define FLASH_DMA_CODE __attribute__((section(".flash_direct_map")))
+
+#define FLASH_SECTOR_ERASE_SIZE 0x00000400
+#define FLASH_STATUS_CHECK_TIMEOUT_US (20 * MSEC)
+
+/* Flash sector erase (1K bytes) command */
+#define FLASH_CMD_SECTOR_ERASE 0xD7
+/* Write status register */
+#define FLASH_CMD_WRSR 0x01
+/* Write disable */
+#define FLASH_CMD_WRDI 0x04
+/* Write enable */
+#define FLASH_CMD_WREN 0x06
+/* Read status register */
+#define FLASH_CMD_RS 0x05
+/* Auto address increment programming */
+#define FLASH_CMD_AAI_WORD 0xAD
+
+static int stuck_locked;
+static int all_protected;
+static int flash_dma_code_enabled;
+
+#define FWP_REG(bank) (bank / 8)
+#define FWP_MASK(bank) (1 << (bank % 8))
+
+enum flash_wp_interface {
+ FLASH_WP_HOST = 0x01,
+ FLASH_WP_DBGR = 0x02,
+ FLASH_WP_EC = 0x04,
+};
+
+enum flash_wp_status {
+ FLASH_WP_STATUS_PROTECT_RO = EC_FLASH_PROTECT_RO_NOW,
+ FLASH_WP_STATUS_PROTECT_ALL = EC_FLASH_PROTECT_ALL_NOW,
+};
+
+enum flash_status_mask {
+ FLASH_SR_NO_BUSY = 0,
+ /* Internal write operation is in progress */
+ FLASH_SR_BUSY = 0x01,
+ /* Device is memory Write enabled */
+ FLASH_SR_WEL = 0x02,
+
+ FLASH_SR_ALL = (FLASH_SR_BUSY | FLASH_SR_WEL),
+};
+
+enum dlm_address_view {
+ SCAR0_ILM0_DLM13 = 0x8D000, /* DLM ~ 0x8DFFF H2RAM map LPC I/O */
+ SCAR1_ILM1_DLM11 = 0x8B000, /* DLM ~ 0x8BFFF reserved */
+ SCAR2_ILM2_DLM14 = 0x8E000, /* DLM ~ 0x8EFFF RO/RW flash code DMA */
+ SCAR3_ILM3_DLM6 = 0x86000, /* DLM ~ 0x86FFF reserved */
+ SCAR4_ILM4_DLM7 = 0x87000, /* DLM ~ 0x87FFF reserved */
+ SCAR5_ILM5_DLM8 = 0x88000, /* DLM ~ 0x88FFF reserved */
+ SCAR6_ILM6_DLM9 = 0x89000, /* DLM ~ 0x89FFF reserved */
+ SCAR7_ILM7_DLM10 = 0x8A000, /* DLM ~ 0x8AFFF reserved */
+ SCAR8_ILM8_DLM4 = 0x84000, /* DLM ~ 0x84FFF reserved */
+ SCAR9_ILM9_DLM5 = 0x85000, /* DLM ~ 0x85FFF reserved */
+ SCAR10_ILM10_DLM2 = 0x82000, /* DLM ~ 0x82FFF ram 8K ~ 12K */
+ SCAR11_ILM11_DLM3 = 0x83000, /* DLM ~ 0x83FFF ram 12K ~ 16K */
+ SCAR12_ILM12_DLM12 = 0x8C000, /* DLM ~ 0x8CFFF reserved */
+};
+
+void FLASH_DMA_CODE dma_reset_immu(void)
+{
+ /* Immu tag sram reset */
+ IT83XX_GCTRL_MCCR |= 0x10;
+ IT83XX_GCTRL_MCCR &= ~0x10;
+}
+
+void FLASH_DMA_CODE dma_flash_follow_mode(void)
+{
+ /* Enter follow mode and FSCE# high level */
+ IT83XX_SMFI_ECINDAR3 = 0x4F;
+ IT83XX_SMFI_ECINDAR2 = 0xFF;
+ IT83XX_SMFI_ECINDAR1 = 0xFE;
+ IT83XX_SMFI_ECINDAR0 = 0x00;
+ IT83XX_SMFI_ECINDDR = 0x00;
+}
+
+void FLASH_DMA_CODE dma_flash_follow_mode_exit(void)
+{
+ /* Exit follow mode */
+ IT83XX_SMFI_ECINDAR3 = 0x00;
+ IT83XX_SMFI_ECINDAR2 = 0x00;
+}
+
+void FLASH_DMA_CODE dma_flash_fsce_high(void)
+{
+ /* FSCE# high level */
+ IT83XX_SMFI_ECINDAR1 = 0xFE;
+ IT83XX_SMFI_ECINDDR = 0x00;
+}
+
+uint8_t FLASH_DMA_CODE dma_flash_read_dat(void)
+{
+ /* Read data from FMISO */
+ return IT83XX_SMFI_ECINDDR;
+}
+
+void FLASH_DMA_CODE dma_flash_write_dat(uint8_t wdata)
+{
+ /* Write data to FMOSI */
+ IT83XX_SMFI_ECINDDR = wdata;
+}
+
+void FLASH_DMA_CODE dma_flash_transaction(int wlen, uint8_t *wbuf,
+ int rlen, uint8_t *rbuf, int cmd_end)
+{
+ int i;
+
+ /* FSCE# with low level */
+ IT83XX_SMFI_ECINDAR1 = 0xFD;
+ /* Write data to FMOSI */
+ for (i = 0; i < wlen; i++)
+ IT83XX_SMFI_ECINDDR = wbuf[i];
+ /* Read data from FMISO */
+ for (i = 0; i < rlen; i++)
+ rbuf[i] = IT83XX_SMFI_ECINDDR;
+
+ /* FSCE# high level if transaction done */
+ if (cmd_end)
+ dma_flash_fsce_high();
+}
+
+void FLASH_DMA_CODE dma_flash_cmd_read_status(enum flash_status_mask mask,
+ enum flash_status_mask target)
+{
+ uint8_t status[1];
+ uint8_t cmd_rs[] = {FLASH_CMD_RS};
+ int timeout = 0;
+
+ while (1) {
+ /* read status */
+ dma_flash_transaction(sizeof(cmd_rs), cmd_rs, 1, status, 1);
+ /* only bit[1:0] valid */
+ if ((status[0] & mask) == target) {
+ break;
+ } else {
+ /* delay ~15.25us */
+ IT83XX_GCTRL_WNCKR = 0;
+ timeout += 15;
+ if (timeout > FLASH_STATUS_CHECK_TIMEOUT_US)
+ break;
+ }
+ }
+}
+
+void FLASH_DMA_CODE dma_flash_cmd_write_enable(void)
+{
+ uint8_t cmd_we[] = {FLASH_CMD_WREN};
+
+ /* enter EC-indirect follow mode */
+ dma_flash_follow_mode();
+ /* send write enable command */
+ dma_flash_transaction(sizeof(cmd_we), cmd_we, 0, NULL, 1);
+ /* read status and make sure busy bit cleared and write enabled. */
+ dma_flash_cmd_read_status(FLASH_SR_ALL, FLASH_SR_WEL);
+ /* exit EC-indirect follow mode */
+ dma_flash_follow_mode_exit();
+}
+
+void FLASH_DMA_CODE dma_flash_cmd_write_disable(void)
+{
+ uint8_t cmd_wd[] = {FLASH_CMD_WRDI};
+
+ /* enter EC-indirect follow mode */
+ dma_flash_follow_mode();
+ /* send write disable command */
+ dma_flash_transaction(sizeof(cmd_wd), cmd_wd, 0, NULL, 1);
+ /* make sure busy bit cleared. */
+ dma_flash_cmd_read_status(FLASH_SR_ALL, FLASH_SR_NO_BUSY);
+ /* exit EC-indirect follow mode */
+ dma_flash_follow_mode_exit();
+}
+
+void FLASH_DMA_CODE dma_flash_cmd_erase(int addr, int cmd)
+{
+ uint8_t cmd_erase[] = {cmd, ((addr >> 16) & 0xFF),
+ ((addr >> 8) & 0xFF), (addr & 0xFF)};
+
+ /* enter EC-indirect follow mode */
+ dma_flash_follow_mode();
+ /* send erase command */
+ dma_flash_transaction(sizeof(cmd_erase), cmd_erase, 0, NULL, 1);
+ /* make sure busy bit cleared. */
+ dma_flash_cmd_read_status(FLASH_SR_BUSY, FLASH_SR_NO_BUSY);
+ /* exit EC-indirect follow mode */
+ dma_flash_follow_mode_exit();
+}
+
+void FLASH_DMA_CODE dma_flash_cmd_aai_write(int addr, int wlen, uint8_t *wbuf)
+{
+ int i;
+ uint8_t aai_write[] = {FLASH_CMD_AAI_WORD, ((addr >> 16) & 0xFF),
+ ((addr >> 8) & 0xFF), (addr & 0xFF)};
+
+ /* enter EC-indirect follow mode */
+ dma_flash_follow_mode();
+ /* send aai word command */
+ dma_flash_transaction(sizeof(aai_write), aai_write, 0, NULL, 0);
+ for (i = 0; i < wlen; i += 2) {
+ dma_flash_write_dat(wbuf[i]);
+ dma_flash_write_dat(wbuf[i + 1]);
+ dma_flash_fsce_high();
+ /* make sure busy bit cleared. */
+ dma_flash_cmd_read_status(FLASH_SR_BUSY, FLASH_SR_NO_BUSY);
+ /* resend aai word command without address field */
+ if ((i + 2) < wlen)
+ dma_flash_transaction(1, aai_write, 0, NULL, 0);
+ }
+ /* exit EC-indirect follow mode */
+ dma_flash_follow_mode_exit();
+}
+
+uint8_t FLASH_DMA_CODE dma_flash_indirect_fast_read(int addr)
+{
+ IT83XX_SMFI_ECINDAR3 = 0x40;
+ IT83XX_SMFI_ECINDAR2 = (addr >> 16) & 0xFF;
+ IT83XX_SMFI_ECINDAR1 = (addr >> 8) & 0xFF;
+ IT83XX_SMFI_ECINDAR0 = (addr & 0xFF);
+
+ return IT83XX_SMFI_ECINDDR;
+}
+
+int FLASH_DMA_CODE dma_flash_verify(int addr, int size, const char *data)
+{
+ int i;
+ uint8_t *wbuf = (uint8_t *)data;
+
+ /* verify for erase */
+ if (data == NULL) {
+ for (i = 0; i < size; i++) {
+ if (dma_flash_indirect_fast_read(addr + i) != 0xFF)
+ return EC_ERROR_UNKNOWN;
+ }
+ /* verify for write */
+ } else {
+ for (i = 0; i < size; i++) {
+ if (dma_flash_indirect_fast_read(addr + i) != wbuf[i])
+ return EC_ERROR_UNKNOWN;
+ }
+ }
+
+ return EC_SUCCESS;
+}
+
+void FLASH_DMA_CODE dma_flash_aai_write(int addr, int wlen, const char *wbuf)
+{
+ dma_flash_cmd_write_enable();
+ dma_flash_cmd_aai_write(addr, wlen, (uint8_t *)wbuf);
+ dma_flash_cmd_write_disable();
+}
+
+void FLASH_DMA_CODE dma_flash_erase(int addr, int cmd)
+{
+ dma_flash_cmd_write_enable();
+ dma_flash_cmd_erase(addr, cmd);
+ dma_flash_cmd_write_disable();
+}
+
+static enum flash_wp_status flash_check_wp(void)
+{
+ enum flash_wp_status wp_status;
+ int all_bank_count, bank;
+
+ all_bank_count = CONFIG_FLASH_PHYSICAL_SIZE / CONFIG_FLASH_BANK_SIZE;
+
+ for (bank = 0; bank < all_bank_count; bank++) {
+ if (!(IT83XX_GCTRL_EWPR0PFEC(FWP_REG(bank)) & FWP_MASK(bank)))
+ break;
+ }
+
+ if (bank == WP_BANK_COUNT)
+ wp_status = FLASH_WP_STATUS_PROTECT_RO;
+ else if (bank == (WP_BANK_COUNT + PSTATE_BANK_COUNT))
+ wp_status = FLASH_WP_STATUS_PROTECT_RO;
+ else if (bank == all_bank_count)
+ wp_status = FLASH_WP_STATUS_PROTECT_ALL;
+ else
+ wp_status = 0;
+
+ return wp_status;
+}
+
+/**
+ * Protect flash banks until reboot.
+ *
+ * @param start_bank Start bank to protect
+ * @param bank_count Number of banks to protect
+ */
+static void flash_protect_banks(int start_bank,
+ int bank_count,
+ enum flash_wp_interface wp_if)
+{
+ int bank;
+
+ for (bank = start_bank; bank < start_bank + bank_count; bank++) {
+ if (wp_if & FLASH_WP_EC)
+ IT83XX_GCTRL_EWPR0PFEC(FWP_REG(bank)) |= FWP_MASK(bank);
+ if (wp_if & FLASH_WP_HOST)
+ IT83XX_GCTRL_EWPR0PFH(FWP_REG(bank)) |= FWP_MASK(bank);
+ if (wp_if & FLASH_WP_DBGR)
+ IT83XX_GCTRL_EWPR0PFD(FWP_REG(bank)) |= FWP_MASK(bank);
+ }
+}
+
+int FLASH_DMA_CODE flash_physical_read(int offset, int size, char *data)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ data[i] = dma_flash_indirect_fast_read(offset);
+ offset++;
+ }
+
+ return EC_SUCCESS;
+}
+
+/**
+ * Write to physical flash.
+ *
+ * Offset and size must be a multiple of CONFIG_FLASH_WRITE_SIZE.
+ *
+ * @param offset Flash offset to write.
+ * @param size Number of bytes to write.
+ * @param data Data to write to flash. Must be 32-bit aligned.
+ */
+int FLASH_DMA_CODE flash_physical_write(int offset, int size, const char *data)
+{
+ uint32_t psw = get_psw();
+
+ if (flash_dma_code_enabled == 0)
+ return EC_ERROR_ACCESS_DENIED;
+
+ if (all_protected)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /*
+ * CPU can't fetch instruction from flash while use
+ * EC-indirect follow mode to access flash, interrupts need to be
+ * disabled.
+ */
+ interrupt_disable();
+
+ dma_flash_aai_write(offset, size, data);
+ dma_reset_immu();
+
+ if (psw & PSW_GIE)
+ interrupt_enable();
+
+ return dma_flash_verify(offset, size, data);
+}
+
+/**
+ * Erase physical flash.
+ *
+ * Offset and size must be a multiple of CONFIG_FLASH_ERASE_SIZE.
+ *
+ * @param offset Flash offset to erase.
+ * @param size Number of bytes to erase.
+ */
+int FLASH_DMA_CODE flash_physical_erase(int offset, int size)
+{
+ int v_size = size, v_addr = offset;
+ uint32_t psw = get_psw();
+
+ if (flash_dma_code_enabled == 0)
+ return EC_ERROR_ACCESS_DENIED;
+
+ if (all_protected)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /*
+ * CPU can't fetch instruction from flash while use
+ * EC-indirect follow mode to access flash, interrupts need to be
+ * disabled.
+ */
+ interrupt_disable();
+
+ /* Always use sector erase command (1K bytes) */
+ for (; size > 0; size -= FLASH_SECTOR_ERASE_SIZE) {
+ dma_flash_erase(offset, FLASH_CMD_SECTOR_ERASE);
+ offset += FLASH_SECTOR_ERASE_SIZE;
+ }
+ dma_reset_immu();
+
+ if (psw & PSW_GIE)
+ interrupt_enable();
+
+ return dma_flash_verify(v_addr, v_size, NULL);
+}
+
+/**
+ * Read physical write protect setting for a flash bank.
+ *
+ * @param bank Bank index to check.
+ * @return non-zero if bank is protected until reboot.
+ */
+int flash_physical_get_protect(int bank)
+{
+ return IT83XX_GCTRL_EWPR0PFEC(FWP_REG(bank)) & FWP_MASK(bank);
+}
+
+/**
+ * Protect flash now.
+ *
+ * @param all Protect all (=1) or just read-only and pstate (=0).
+ * @return non-zero if error.
+ */
+int flash_physical_protect_now(int all)
+{
+ if (all) {
+ /* Protect the entire flash */
+ flash_protect_banks(0,
+ CONFIG_FLASH_PHYSICAL_SIZE / CONFIG_FLASH_BANK_SIZE,
+ FLASH_WP_EC);
+ all_protected = 1;
+ } else {
+ /* Protect the read-only section and persistent state */
+ flash_protect_banks(WP_BANK_OFFSET,
+ WP_BANK_COUNT, FLASH_WP_EC);
+#ifdef PSTATE_BANK
+ flash_protect_banks(PSTATE_BANK,
+ PSTATE_BANK_COUNT, FLASH_WP_EC);
+#endif
+ }
+
+ /*
+ * bit[0], eflash protect lock register which can only be write 1 and
+ * only be cleared by power-on reset.
+ */
+ IT83XX_GCTRL_EPLR |= 0x01;
+
+ return EC_SUCCESS;
+}
+
+/**
+ * Return flash protect state flags from the physical layer.
+ *
+ * This should only be called by flash_get_protect().
+ *
+ * Uses the EC_FLASH_PROTECT_* flags from ec_commands.h
+ */
+uint32_t flash_physical_get_protect_flags(void)
+{
+ uint32_t flags = 0;
+
+ flags |= flash_check_wp();
+
+ if (all_protected)
+ flags |= EC_FLASH_PROTECT_ALL_NOW;
+
+ /* Check if blocks were stuck locked at pre-init */
+ if (stuck_locked)
+ flags |= EC_FLASH_PROTECT_ERROR_STUCK;
+
+ return flags;
+}
+
+/**
+ * Return the valid flash protect flags.
+ *
+ * @return A combination of EC_FLASH_PROTECT_* flags from ec_commands.h
+ */
+uint32_t flash_physical_get_valid_flags(void)
+{
+ return EC_FLASH_PROTECT_RO_AT_BOOT |
+ EC_FLASH_PROTECT_RO_NOW |
+ EC_FLASH_PROTECT_ALL_NOW;
+}
+
+/**
+ * Return the writable flash protect flags.
+ *
+ * @param cur_flags The current flash protect flags.
+ * @return A combination of EC_FLASH_PROTECT_* flags from ec_commands.h
+ */
+uint32_t flash_physical_get_writable_flags(uint32_t cur_flags)
+{
+ uint32_t ret = 0;
+
+ /* If RO protection isn't enabled, its at-boot state can be changed. */
+ if (!(cur_flags & EC_FLASH_PROTECT_RO_NOW))
+ ret |= EC_FLASH_PROTECT_RO_AT_BOOT;
+
+ /*
+ * If entire flash isn't protected at this boot, it can be enabled if
+ * the WP GPIO is asserted.
+ */
+ if (!(cur_flags & EC_FLASH_PROTECT_ALL_NOW) &&
+ (cur_flags & EC_FLASH_PROTECT_GPIO_ASSERTED))
+ ret |= EC_FLASH_PROTECT_ALL_NOW;
+
+ return ret;
+}
+
+static void flash_code_static_dma(void)
+{
+ uint32_t psw = get_psw();
+
+ /* Make sure no interrupt while enable static DMA */
+ interrupt_disable();
+
+ /* invalid static DMA first */
+ IT83XX_SMFI_SCAR2H = 0x08;
+
+ /* Copy to DLM */
+ IT83XX_GCTRL_MCCR2 |= 0x20;
+ memcpy((void *)SCAR2_ILM2_DLM14, (const void *)FLASH_DMA_START,
+ CONFIG_IT83XX_ILM_BLOCK_SIZE);
+ IT83XX_GCTRL_MCCR2 &= ~0x20;
+
+ /*
+ * Enable ILM
+ * Set the logic memory address(flash code of RO/RW) in eflash
+ * by programing the register SCARx bit19-bit0.
+ */
+ IT83XX_SMFI_SCAR2L = FLASH_DMA_START & 0xFF;
+ IT83XX_SMFI_SCAR2M = (FLASH_DMA_START >> 8) & 0xFF;
+ IT83XX_SMFI_SCAR2H = (FLASH_DMA_START >> 16) & 0x0F;
+ /*
+ * Validate Direct-map SRAM function by programing
+ * register SCARx bit20=0
+ */
+ IT83XX_SMFI_SCAR2H &= ~0x10;
+
+ flash_dma_code_enabled = 0x01;
+
+ if (psw & PSW_GIE)
+ interrupt_enable();
+}
+
+/**
+ * Initialize the module.
+ *
+ * Applies at-boot protection settings if necessary.
+ */
+int flash_pre_init(void)
+{
+ int32_t reset_flags, prot_flags, unwanted_prot_flags;
+
+ flash_code_static_dma();
+
+ reset_flags = system_get_reset_flags();
+ prot_flags = flash_get_protect();
+ unwanted_prot_flags = EC_FLASH_PROTECT_ALL_NOW |
+ EC_FLASH_PROTECT_ERROR_INCONSISTENT;
+
+ /*
+ * If we have already jumped between images, an earlier image could
+ * have applied write protection. Nothing additional needs to be done.
+ */
+ if (reset_flags & RESET_FLAG_SYSJUMP)
+ return EC_SUCCESS;
+
+ if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) {
+ /* Protect the entire flash of host interface */
+ flash_protect_banks(0,
+ CONFIG_FLASH_PHYSICAL_SIZE / CONFIG_FLASH_BANK_SIZE,
+ FLASH_WP_HOST);
+ /* Protect the entire flash of DBGR interface */
+ flash_protect_banks(0,
+ CONFIG_FLASH_PHYSICAL_SIZE / CONFIG_FLASH_BANK_SIZE,
+ FLASH_WP_DBGR);
+ /*
+ * Write protect is asserted. If we want RO flash protected,
+ * protect it now.
+ */
+ if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) &&
+ !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) {
+ int rv = flash_set_protect(EC_FLASH_PROTECT_RO_NOW,
+ EC_FLASH_PROTECT_RO_NOW);
+ if (rv)
+ return rv;
+
+ /* Re-read flags */
+ prot_flags = flash_get_protect();
+ }
+ } else {
+ /* Don't want RO flash protected */
+ unwanted_prot_flags |= EC_FLASH_PROTECT_RO_NOW;
+ }
+
+ /* If there are no unwanted flags, done */
+ if (!(prot_flags & unwanted_prot_flags))
+ return EC_SUCCESS;
+
+ /*
+ * If the last reboot was a power-on reset, it should have cleared
+ * write-protect. If it didn't, then the flash write protect registers
+ * have been permanently committed and we can't fix that.
+ */
+ if (reset_flags & RESET_FLAG_POWER_ON) {
+ stuck_locked = 1;
+ return EC_ERROR_ACCESS_DENIED;
+ }
+
+ /* Otherwise, do a hard boot to clear the flash protection registers */
+ system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS);
+
+ /* That doesn't return, so if we're still here that's an error */
+ return EC_ERROR_UNKNOWN;
+}
+
+static int eflash_test_erase(int addr, int size)
+{
+ int rv, i, rvr;
+ uint8_t *rdata;
+
+ /* Acquire the shared memory buffer */
+ rv = shared_mem_acquire(FLASH_SECTOR_ERASE_SIZE, (char **)&rdata);
+ if (rv) {
+ ccputs("Can't get shared mem\n");
+ return rv;
+ }
+
+ for (; size > 0; size -= FLASH_SECTOR_ERASE_SIZE) {
+
+ rv = flash_physical_erase(addr, FLASH_SECTOR_ERASE_SIZE);
+
+ if (rv) {
+ /* Free the buffer */
+ shared_mem_release(rdata);
+ ccputs("Flash erase error\n");
+ return rv;
+ }
+
+ rvr = flash_read(addr, FLASH_SECTOR_ERASE_SIZE, rdata);
+
+ if (rvr) {
+ /* Free the buffer */
+ shared_mem_release(rdata);
+ ccputs("Flash read error\n");
+ return rvr;
+ }
+
+ for (i = 0; i < FLASH_SECTOR_ERASE_SIZE; i++) {
+ if (rdata[i] != 0xff) {
+ ccprintf("Addr %Xh should be FFh but %Xh\n",
+ (addr+i), rdata[i]);
+ ccprintf("Erase %Xh ~ %Xh fail\n", addr,
+ (addr + FLASH_SECTOR_ERASE_SIZE - 1));
+
+ /* Free the buffer */
+ shared_mem_release(rdata);
+ return rv;
+ }
+ }
+
+ ccprintf("Verify %Xh ~ %Xh OK\n", addr,
+ (addr + FLASH_SECTOR_ERASE_SIZE - 1));
+ addr += FLASH_SECTOR_ERASE_SIZE;
+ }
+ /* Free the buffer */
+ shared_mem_release(rdata);
+ return rv;
+}
+
+static int eflash_test_write(int addr, int size)
+{
+ int rv, i, rvr;
+ uint8_t *rwdata;
+
+ /* Acquire the shared memory buffer */
+ rv = shared_mem_acquire((size * 2), (char **)&rwdata);
+ if (rv) {
+ ccputs("Can't get shared mem\n");
+ return rv;
+ }
+
+ for (i = 0; i < size; i++)
+ rwdata[i] = i;
+
+ rv = flash_physical_write(addr, size, rwdata);
+ if (rv) {
+ /* Free the buffer */
+ shared_mem_release(rwdata);
+ ccputs("Flash write error\n");
+ return rv;
+ }
+
+ rvr = flash_read(addr, size, &rwdata[size]);
+ if (rvr) {
+ /* Free the buffer */
+ shared_mem_release(rwdata);
+ ccputs("Flash read error\n");
+ return rvr;
+ }
+
+ rvr = 0;
+ for (i = 0; i < size; i++) {
+ if (rwdata[i] != rwdata[i+size]) {
+ ccprintf("%Xh should be %Xh but %Xh\n",
+ (addr+i), rwdata[i], rwdata[i+size]);
+ rvr++;
+ }
+ }
+
+ if (rvr)
+ ccprintf("Verify %d bytes fail\n", rvr);
+ else
+ ccprintf("Verify %Xh ~ %Xh OK\n", addr, (addr + size - 1));
+
+ /* Free the buffer */
+ shared_mem_release(rwdata);
+ return rv;
+}
+
+static int eflash_test(int argc, char **argv)
+{
+ char *e;
+ int addr, size;
+ int rv;
+
+ if (argc != 4)
+ return EC_ERROR_PARAM_COUNT;
+
+ addr = strtoi(argv[2], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ size = strtoi(argv[3], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM3;
+
+ /* erase */
+ if (strcasecmp(argv[1], "e") == 0) {
+ rv = eflash_test_erase(addr, size);
+ /* write */
+ } else if (strcasecmp(argv[1], "w") == 0) {
+ if (size > CONFIG_FLASH_WRITE_IDEAL_SIZE) {
+ ccprintf("size need <=%d\n",
+ CONFIG_FLASH_WRITE_IDEAL_SIZE);
+ return EC_ERROR_PARAM3;
+ }
+ rv = eflash_test_write(addr, size);
+ } else {
+ return EC_ERROR_PARAM1;
+ }
+
+ return rv;
+}
+DECLARE_CONSOLE_COMMAND(eflash, eflash_test,
+ "e/w addr size",
+ "erase/write internal eflash",
+ NULL);
diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h
index c918d3eb5b..3cfeede2cf 100644
--- a/chip/it83xx/registers.h
+++ b/chip/it83xx/registers.h
@@ -639,11 +639,18 @@ enum clock_gate_offsets {
/* --- General Control (GCTRL) --- */
#define IT83XX_GCTRL_BASE 0x00F02000
-#define IT83XX_GCTRL_WNCKR REG8(IT83XX_GCTRL_BASE+0x0B)
-#define IT83XX_GCTRL_RSTS REG8(IT83XX_GCTRL_BASE+0x06)
-#define IT83XX_GCTRL_BADRSEL REG8(IT83XX_GCTRL_BASE+0x0A)
-#define IT83XX_GCTRL_RSTC4 REG8(IT83XX_GCTRL_BASE+0x11)
-#define IT83XX_GCTRL_MCCR2 REG8(IT83XX_GCTRL_BASE+0x44)
+#define IT83XX_GCTRL_WNCKR REG8(IT83XX_GCTRL_BASE+0x0B)
+#define IT83XX_GCTRL_RSTS REG8(IT83XX_GCTRL_BASE+0x06)
+#define IT83XX_GCTRL_BADRSEL REG8(IT83XX_GCTRL_BASE+0x0A)
+#define IT83XX_GCTRL_RSTC4 REG8(IT83XX_GCTRL_BASE+0x11)
+#define IT83XX_GCTRL_SPCTRL4 REG8(IT83XX_GCTRL_BASE+0x1C)
+#define IT83XX_GCTRL_MCCR REG8(IT83XX_GCTRL_BASE+0x30)
+#define IT83XX_GCTRL_EPLR REG8(IT83XX_GCTRL_BASE+0x37)
+#define IT83XX_GCTRL_IVTBAR REG8(IT83XX_GCTRL_BASE+0x41)
+#define IT83XX_GCTRL_MCCR2 REG8(IT83XX_GCTRL_BASE+0x44)
+#define IT83XX_GCTRL_EWPR0PFH(i) REG8(IT83XX_GCTRL_BASE+0x60+i)
+#define IT83XX_GCTRL_EWPR0PFD(i) REG8(IT83XX_GCTRL_BASE+0xA0+i)
+#define IT83XX_GCTRL_EWPR0PFEC(i) REG8(IT83XX_GCTRL_BASE+0xC0+i)
/* --- Pulse Width Modulation (PWM) --- */
#define IT83XX_PWM_BASE 0x00F01800
@@ -868,6 +875,15 @@ REG8(IT83XX_PMC_BASE + (ch > LPC_PM2 ? 3 : 6) + (ch << 4))
#define IT83XX_SMFI_H2RAMECSIE REG8(IT83XX_SMFI_BASE+0x7A)
#define IT83XX_SMFI_H2RAMECSA REG8(IT83XX_SMFI_BASE+0x7B)
#define IT83XX_SMFI_H2RAMHSS REG8(IT83XX_SMFI_BASE+0x7C)
+#define IT83XX_SMFI_ECINDAR0 REG8(IT83XX_SMFI_BASE+0x3B)
+#define IT83XX_SMFI_ECINDAR1 REG8(IT83XX_SMFI_BASE+0x3C)
+#define IT83XX_SMFI_ECINDAR2 REG8(IT83XX_SMFI_BASE+0x3D)
+#define IT83XX_SMFI_ECINDAR3 REG8(IT83XX_SMFI_BASE+0x3E)
+#define IT83XX_SMFI_ECINDDR REG8(IT83XX_SMFI_BASE+0x3F)
+#define IT83XX_SMFI_SCAR2L REG8(IT83XX_SMFI_BASE+0x46)
+#define IT83XX_SMFI_SCAR2M REG8(IT83XX_SMFI_BASE+0x47)
+#define IT83XX_SMFI_SCAR2H REG8(IT83XX_SMFI_BASE+0x48)
+#define IT83XX_SMFI_STCDMACR REG8(IT83XX_SMFI_BASE+0x80)
/* Serial Peripheral Interface (SSPI) */
#define IT83XX_SSPI_BASE 0x00F02600
diff --git a/chip/it83xx/system.c b/chip/it83xx/system.c
index ffeae356fe..8d434c9c5c 100644
--- a/chip/it83xx/system.c
+++ b/chip/it83xx/system.c
@@ -31,14 +31,23 @@ static void check_reset_cause(void)
{
uint32_t flags = 0;
uint8_t raw_reset_cause = IT83XX_GCTRL_RSTS & 0x03;
+ uint8_t raw_reset_cause2 = IT83XX_GCTRL_SPCTRL4 & 0x07;
/* Clear reset cause. */
- IT83XX_GCTRL_RSTS |= 0x01;
+ IT83XX_GCTRL_RSTS |= 0x03;
+ IT83XX_GCTRL_SPCTRL4 |= 0x07;
/* Determine if watchdog reset or power on reset. */
- if (raw_reset_cause & 0x02)
+ if (raw_reset_cause & 0x02) {
flags |= RESET_FLAG_WATCHDOG;
- else
+ } else if (raw_reset_cause & 0x01) {
+ flags |= RESET_FLAG_POWER_ON;
+ } else {
+ if ((IT83XX_GCTRL_RSTS & 0xC0) == 0x80)
+ flags |= RESET_FLAG_POWER_ON;
+ }
+
+ if (raw_reset_cause2 & 0x04)
flags |= RESET_FLAG_POWER_ON;
/* Restore then clear saved reset flags. */
@@ -167,3 +176,15 @@ int system_get_console_force_enabled(void)
/* TODO(crosbug.com/p/23575): IMPLEMENT ME ! */
return 0;
}
+
+uintptr_t system_get_fw_reset_vector(uintptr_t base)
+{
+ uintptr_t reset_vector, num;
+
+ num = *(uintptr_t *)base;
+ reset_vector = ((num>>24)&0xff) | ((num<<8)&0xff0000) |
+ ((num>>8)&0xff00) | ((num<<24)&0xff000000);
+ reset_vector = ((reset_vector & 0xffffff) << 1) + base;
+
+ return reset_vector;
+}