diff options
Diffstat (limited to 'chip/it83xx')
-rw-r--r-- | chip/it83xx/build.mk | 1 | ||||
-rw-r--r-- | chip/it83xx/config_chip.h | 13 | ||||
-rw-r--r-- | chip/it83xx/flash.c | 765 | ||||
-rw-r--r-- | chip/it83xx/registers.h | 26 | ||||
-rw-r--r-- | chip/it83xx/system.c | 27 |
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; +} |