summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDino Li <dino.li@ite.com.tw>2015-07-02 17:05:51 +0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-07-08 09:25:48 +0000
commita69c63bae5223b6a0070ee2ab48b6c9db65dc6c7 (patch)
tree45adb050cb7fc959f672a1413eec5677c394c3c1
parentd6a6c927248ce16c9467dfa3f170349520cc5bc9 (diff)
downloadchrome-ec-a69c63bae5223b6a0070ee2ab48b6c9db65dc6c7.tar.gz
it8380dev: add flash module and fix system jump
1. Add flash control module for emulation board. 2. Fix system jump for Andes core. 3. Change the physical size of the flash on the chip to 256KB. note: 1. Only IT839x series supports flash write protect by registers. 2. Static DMA method of flash code only for IT839x series and IT838x Dx. Signed-off-by: Dino Li <dino.li@ite.com.tw> BRANCH=none BUG=none TEST=1. console command flashwp and flashinfo 1-a. flashwp enable 1-b. WP asserted and reboot 1-c. flashinfo RO protected now 1-d. WP deasserted and reboot 1-e. No protected 1-f. flashwp disable 1-g. WP asserted and reboot 1-h. No protected 2. console sysjump and sysinfo 2-a. sysjump rw 2-b. jumping to image RW 2-c. sysinfo, Copy : RW, Jumped : yes 2-d. sysjump ro 2-e. jumping to image RO 2-f. sysinfo, Copy : RO, Jumped : yes 3. RO/RW firmware image test 3-a. sysjump rw 3-b. use console command "eflash" to erase RO region, erase OK and system still work. 3-c. reflash firmware 3-d. sysjump rw, sysjump ro 3-e. use console command "eflash" to erase RW region, erase OK and system still work. Change-Id: I7666a095e73026a02fb812e5143bc5172ab713e8 Reviewed-on: https://chromium-review.googlesource.com/271390 Reviewed-by: Randall Spangler <rspangler@chromium.org> Commit-Queue: Dino Li <dino.li@ite.com.tw> Tested-by: Dino Li <dino.li@ite.com.tw>
-rw-r--r--board/it8380dev/board.c27
-rw-r--r--board/it8380dev/gpio.inc1
-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
-rw-r--r--common/system.c5
-rw-r--r--core/nds32/cpu.c8
-rw-r--r--core/nds32/ec.lds.S5
-rw-r--r--include/config.h13
-rw-r--r--include/system.h9
12 files changed, 875 insertions, 25 deletions
diff --git a/board/it8380dev/board.c b/board/it8380dev/board.c
index 56fe4d4bcc..130d4ef47f 100644
--- a/board/it8380dev/board.c
+++ b/board/it8380dev/board.c
@@ -4,26 +4,27 @@
*/
/* IT8380 development board configuration */
+#include "adc.h"
+#include "adc_chip.h"
#include "common.h"
#include "console.h"
+#include "ec2i_chip.h"
+#include "fan.h"
#include "gpio.h"
#include "hooks.h"
-#include "registers.h"
-#include "task.h"
-#include "util.h"
+#include "i2c.h"
+#include "intc.h"
+#include "keyboard_scan.h"
+#include "lid_switch.h"
+#include "lpc.h"
+#include "power_button.h"
#include "pwm.h"
#include "pwm_chip.h"
-#include "adc.h"
-#include "adc_chip.h"
-#include "ec2i_chip.h"
-#include "power_button.h"
-#include "lid_switch.h"
-#include "keyboard_scan.h"
+#include "registers.h"
+#include "switch.h"
+#include "task.h"
#include "timer.h"
-#include "lpc.h"
-#include "intc.h"
-#include "fan.h"
-#include "i2c.h"
+#include "util.h"
/* Test GPIO interrupt function that toggles one LED. */
void test_interrupt(enum gpio_signal signal)
diff --git a/board/it8380dev/gpio.inc b/board/it8380dev/gpio.inc
index 0e4be968ec..61ab6dd45a 100644
--- a/board/it8380dev/gpio.inc
+++ b/board/it8380dev/gpio.inc
@@ -8,6 +8,7 @@
GPIO_INT(POWER_BUTTON_L, PIN(E, 4), GPIO_INT_BOTH | GPIO_PULL_UP, power_button_interrupt)
GPIO_INT(PCH_PLTRST_L, PIN(E, 3), GPIO_INT_BOTH | GPIO_PULL_UP, lpcrst_interrupt)
GPIO_INT(LID_OPEN, PIN(E, 2), GPIO_INT_BOTH | GPIO_PULL_DOWN, lid_interrupt)
+GPIO_INT(WP_L, PIN(E, 1), GPIO_INT_BOTH, switch_interrupt) /* Write protect input */
GPIO(H_LED0, PIN(A, 0), GPIO_ODR_HIGH)
GPIO(H_LED1, PIN(A, 1), GPIO_ODR_HIGH)
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;
+}
diff --git a/common/system.c b/common/system.c
index e3c72855a0..de15f62aa3 100644
--- a/common/system.c
+++ b/common/system.c
@@ -516,8 +516,13 @@ int system_run_image_copy(enum system_image_copy_t copy)
system_set_image_copy(copy);
#else
+#ifdef CONFIG_FW_RESET_VECTOR
+ /* Get reset vector */
+ init_addr = system_get_fw_reset_vector(base);
+#else
/* Make sure the reset vector is inside the destination image */
init_addr = *(uintptr_t *)(base + 4);
+#endif
#ifndef EMU_BUILD
if (init_addr < base || init_addr >= base + get_size(copy))
return EC_ERROR_UNKNOWN;
diff --git a/core/nds32/cpu.c b/core/nds32/cpu.c
index 545e930eca..bf49a58b2e 100644
--- a/core/nds32/cpu.c
+++ b/core/nds32/cpu.c
@@ -6,8 +6,16 @@
*/
#include "cpu.h"
+#include "registers.h"
void cpu_init(void)
{
/* DLM initialization is done in init.S */
+
+ uint32_t image_type = (uint32_t)cpu_init;
+
+ /* To change interrupt vector base if at RW image */
+ if (image_type > CONFIG_RW_MEM_OFF)
+ /* Interrupt Vector Table Base Address, in 64k Byte unit */
+ IT83XX_GCTRL_IVTBAR = (CONFIG_RW_MEM_OFF >> 16) & 0xFF;
}
diff --git a/core/nds32/ec.lds.S b/core/nds32/ec.lds.S
index 57cf6512d3..a936e72d62 100644
--- a/core/nds32/ec.lds.S
+++ b/core/nds32/ec.lds.S
@@ -37,6 +37,11 @@ SECTIONS
KEEP(OUTDIR/core/CORE/init.o (.text.vectirq))
KEEP(OUTDIR/core/CORE/init.o (.text))
*(.text*)
+
+ . = ALIGN(CONFIG_IT83XX_ILM_BLOCK_SIZE);
+ __flash_dma_start = .;
+ KEEP(*(.flash_direct_map))
+ . = ALIGN(CONFIG_IT83XX_ILM_BLOCK_SIZE);
#ifdef COMPILE_FOR_RAM
} > IRAM
#else
diff --git a/include/config.h b/include/config.h
index d628e5d5d7..3bff029e2f 100644
--- a/include/config.h
+++ b/include/config.h
@@ -731,6 +731,12 @@
/* If defined, another image (RW) exists with more features */
#undef CONFIG_FW_LIMITED_IMAGE
+/*
+ * If defined, we can use system_get_fw_reset_vector function to decide
+ * reset vector of RO/RW firmware for sysjump.
+ */
+#undef CONFIG_FW_RESET_VECTOR
+
/*****************************************************************************/
/* Motion sensor based gesture recognition information */
/* These all require HAS_TASK_MOTIONSENSE to work */
@@ -938,6 +944,13 @@
/* Number of IRQs supported on the EC chip */
#undef CONFIG_IRQ_COUNT
+/*
+ * This is the block size of the ILM on the it839x chip.
+ * The ILM for static code cache, CPU fetch instruction from
+ * ILM(ILM -> CPU)instead of flash(flash -> IMMU -> CPU) if enabled.
+ */
+#undef CONFIG_IT83XX_ILM_BLOCK_SIZE
+
/* Enable Wake-up control interrupt from KSI */
#undef CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT
diff --git a/include/system.h b/include/system.h
index c55e4a0f2e..320410b160 100644
--- a/include/system.h
+++ b/include/system.h
@@ -399,4 +399,13 @@ void system_set_image_copy(enum system_image_copy_t copy);
enum system_image_copy_t system_get_shrspi_image_copy(void);
#endif
+
+#ifdef CONFIG_FW_RESET_VECTOR
+/**
+ * Determine reset vector will be jumped to the assigned address.
+ *
+ * @return The address of the reset vector for RO/RW firmware image jump.
+ */
+uintptr_t system_get_fw_reset_vector(uintptr_t base);
+#endif
#endif /* __CROS_EC_SYSTEM_H */