diff options
Diffstat (limited to 'chip/npcx/system.c')
-rw-r--r-- | chip/npcx/system.c | 1437 |
1 files changed, 0 insertions, 1437 deletions
diff --git a/chip/npcx/system.c b/chip/npcx/system.c deleted file mode 100644 index ac7056330f..0000000000 --- a/chip/npcx/system.c +++ /dev/null @@ -1,1437 +0,0 @@ -/* Copyright 2014 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. - */ - -/* System module for Chrome EC : NPCX hardware specific implementation */ - -#include "clock.h" -#include "clock_chip.h" -#include "common.h" -#include "console.h" -#include "cpu.h" -#include "gpio.h" -#include "hooks.h" -#include "host_command.h" -#include "hwtimer_chip.h" -#include "lct_chip.h" -#include "registers.h" -#include "rom_chip.h" -#include "sib_chip.h" -#include "system.h" -#include "system_chip.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "watchdog.h" - -/* Delay after writing TTC for value to latch */ -#define MTC_TTC_LOAD_DELAY_US 250 -#define MTC_ALARM_MASK (BIT(25) - 1) -#define MTC_WUI_GROUP MIWU_GROUP_4 -#define MTC_WUI_MASK MASK_PIN7 - -/* ROM address of chip revision */ -#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX9 -#define CHIP_REV_ADDR 0x0000FFFC -#define CHIP_REV_STR_SIZE 12 -#else -#define CHIP_REV_ADDR 0x00007FFC -#define CHIP_REV_STR_SIZE 6 -#endif - -/* Legacy SuperI/O Configuration D register offset */ -#define SIOCFD_REG_OFFSET 0x2D - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_SYSTEM, outstr) -#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) - -#if defined(NPCX_LCT_SUPPORT) -/* A flag for waking up from hibernate mode by RTC overflow event */ -static int is_rtc_overflow_event; -#endif - -/*****************************************************************************/ -/* Internal functions */ - -void system_watchdog_reset(void) -{ - /* Unlock & stop watchdog registers */ - watchdog_stop_and_unlock(); - - /* Reset TWCFG */ - NPCX_TWCFG = 0; - /* Select T0IN clock as watchdog prescaler clock */ - SET_BIT(NPCX_TWCFG, NPCX_TWCFG_WDCT0I); - - /* Clear watchdog reset status initially*/ - SET_BIT(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS); - - /* Keep prescaler ratio timer0 clock to 1:1 */ - NPCX_TWCP = 0x00; - - /* Set internal counter and prescaler */ - NPCX_TWDT0 = 0x00; - NPCX_WDCNT = 0x01; - - /* Disable interrupt */ - interrupt_disable(); - /* Reload and restart Timer 0*/ - SET_BIT(NPCX_T0CSR, NPCX_T0CSR_RST); - /* Wait for timer is loaded and restart */ - while (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_RST)) - ; - /* Enable interrupt */ - interrupt_enable(); -} - -/* Return true if index is stored as a single byte in bbram */ -static int bbram_is_byte_access(enum bbram_data_index index) -{ - return index == BBRM_DATA_INDEX_PD0 || - index == BBRM_DATA_INDEX_PD1 || - index == BBRM_DATA_INDEX_PD2 || - index == BBRM_DATA_INDEX_PANIC_FLAGS; -} - -/* Check and clear BBRAM status on any reset */ -void system_check_bbram_on_reset(void) -{ - if (IS_BIT_SET(NPCX_BKUP_STS, NPCX_BKUP_STS_IBBR)) { - /* - * If the reset cause is not power-on reset and VBAT has ever - * dropped, print a warning message. - */ - if (IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_SCRATCH) || - IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_STS)) - CPRINTF("VBAT drop!\n"); - - /* - * npcx5/npcx7m6g/npcx7m6f: - * Clear IBBR bit - * npcx7m6fb/npcx7m6fc/npcx7m7fc/npcx7m7wb/npcx7m7wc: - * Clear IBBR/VSBY_STS/VCC1_STS bit - */ - NPCX_BKUP_STS = NPCX_BKUP_STS_ALL_MASK; - } -} - -/* Check index is within valid BBRAM range and IBBR is not set */ -static int bbram_valid(enum bbram_data_index index, int bytes) -{ - /* Check index */ - if (index < 0 || index + bytes > NPCX_BBRAM_SIZE) - return 0; - - /* Check BBRAM is valid */ - if (IS_BIT_SET(NPCX_BKUP_STS, NPCX_BKUP_STS_IBBR)) { - NPCX_BKUP_STS = BIT(NPCX_BKUP_STS_IBBR); - panic_printf("IBBR set: BBRAM corrupted!\n"); - return 0; - } - return 1; -} - -/** - * Read battery-backed ram (BBRAM) at specified index. - * - * @return The value of the register or 0 if invalid index. - */ -static uint32_t bbram_data_read(enum bbram_data_index index) -{ - uint32_t value = 0; - int bytes = bbram_is_byte_access(index) ? 1 : 4; - - if (!bbram_valid(index, bytes)) - return 0; - - /* Read BBRAM */ - if (bytes == 4) { - value += NPCX_BBRAM(index + 3); - value = value << 8; - value += NPCX_BBRAM(index + 2); - value = value << 8; - value += NPCX_BBRAM(index + 1); - value = value << 8; - } - value += NPCX_BBRAM(index); - - return value; -} - -/** - * Write battery-backed ram (BBRAM) at specified index. - * - * @return nonzero if error. - */ -static int bbram_data_write(enum bbram_data_index index, uint32_t value) -{ - int bytes = bbram_is_byte_access(index) ? 1 : 4; - - if (!bbram_valid(index, bytes)) - return EC_ERROR_INVAL; - - /* Write BBRAM */ - NPCX_BBRAM(index) = value & 0xFF; - if (bytes == 4) { - NPCX_BBRAM(index + 1) = (value >> 8) & 0xFF; - NPCX_BBRAM(index + 2) = (value >> 16) & 0xFF; - NPCX_BBRAM(index + 3) = (value >> 24) & 0xFF; - } - - /* Wait for write-complete */ - return EC_SUCCESS; -} - -/* Map idx to a returned BBRM_DATA_INDEX_*, or return -1 on invalid idx */ -static int bbram_idx_lookup(enum system_bbram_idx idx) -{ - if (idx == SYSTEM_BBRAM_IDX_PD0) - return BBRM_DATA_INDEX_PD0; - if (idx == SYSTEM_BBRAM_IDX_PD1) - return BBRM_DATA_INDEX_PD1; - if (idx == SYSTEM_BBRAM_IDX_PD2) - return BBRM_DATA_INDEX_PD2; - if (idx == SYSTEM_BBRAM_IDX_TRY_SLOT) - return BBRM_DATA_INDEX_TRY_SLOT; - return -1; -} - -int system_get_bbram(enum system_bbram_idx idx, uint8_t *value) -{ - int bbram_idx = bbram_idx_lookup(idx); - - if (bbram_idx < 0) - return EC_ERROR_INVAL; - - *value = bbram_data_read(bbram_idx); - return EC_SUCCESS; -} - -int system_set_bbram(enum system_bbram_idx idx, uint8_t value) -{ - int bbram_idx = bbram_idx_lookup(idx); - - if (bbram_idx < 0) - return EC_ERROR_INVAL; - - return bbram_data_write(bbram_idx, value); -} - -/* MTC functions */ -uint32_t system_get_rtc_sec(void) -{ - /* Get MTC counter unit:seconds */ - uint32_t sec = NPCX_TTC; - return sec; -} - -void system_set_rtc(uint32_t seconds) -{ - /* - * Set MTC counter unit:seconds, write twice to ensure values - * latch to NVMem. - */ - NPCX_TTC = seconds; - udelay(MTC_TTC_LOAD_DELAY_US); - NPCX_TTC = seconds; - udelay(MTC_TTC_LOAD_DELAY_US); -} - -#ifdef CONFIG_CHIP_PANIC_BACKUP -/* - * Following information from panic data is stored in BBRAM: - * - * index | data - * ==========|============= - * 36 | CFSR - * 40 | HFSR - * 44 | BFAR - * 48 | LREG1 - * 52 | LREG3 - * 56 | LREG4 - * 60 | reserved - * - * Above registers are chosen to be saved in case of panic because: - * 1. CFSR, HFSR and BFAR seem to provide more information about the fault. - * 2. LREG1, LREG3 and LREG4 store exception, reason and info in case of - * software panic. - */ -#define BKUP_CFSR (BBRM_DATA_INDEX_PANIC_BKUP + 0) -#define BKUP_HFSR (BBRM_DATA_INDEX_PANIC_BKUP + 4) -#define BKUP_BFAR (BBRM_DATA_INDEX_PANIC_BKUP + 8) -#define BKUP_LREG1 (BBRM_DATA_INDEX_PANIC_BKUP + 12) -#define BKUP_LREG3 (BBRM_DATA_INDEX_PANIC_BKUP + 16) -#define BKUP_LREG4 (BBRM_DATA_INDEX_PANIC_BKUP + 20) - -#define BKUP_PANIC_DATA_VALID BIT(0) - -void chip_panic_data_backup(void) -{ - struct panic_data *d = panic_get_data(); - - if (!d) - return; - - bbram_data_write(BKUP_CFSR, d->cm.cfsr); - bbram_data_write(BKUP_HFSR, d->cm.hfsr); - bbram_data_write(BKUP_BFAR, d->cm.dfsr); - bbram_data_write(BKUP_LREG1, d->cm.regs[1]); - bbram_data_write(BKUP_LREG3, d->cm.regs[3]); - bbram_data_write(BKUP_LREG4, d->cm.regs[4]); - bbram_data_write(BBRM_DATA_INDEX_PANIC_FLAGS, BKUP_PANIC_DATA_VALID); -} - -static void chip_panic_data_restore(void) -{ - struct panic_data *d; - - /* Ensure BBRAM is valid. */ - if (!bbram_valid(BKUP_CFSR, 4)) - return; - - /* Ensure Panic data in BBRAM is valid. */ - if (!(bbram_data_read(BBRM_DATA_INDEX_PANIC_FLAGS) & - BKUP_PANIC_DATA_VALID)) - return; - - d = get_panic_data_write(); - - memset(d, 0, CONFIG_PANIC_DATA_SIZE); - d->magic = PANIC_DATA_MAGIC; - d->struct_size = CONFIG_PANIC_DATA_SIZE; - d->struct_version = 2; - d->arch = PANIC_ARCH_CORTEX_M; - - d->cm.cfsr = bbram_data_read(BKUP_CFSR); - d->cm.hfsr = bbram_data_read(BKUP_HFSR); - d->cm.dfsr = bbram_data_read(BKUP_BFAR); - - d->cm.regs[1] = bbram_data_read(BKUP_LREG1); - d->cm.regs[3] = bbram_data_read(BKUP_LREG3); - d->cm.regs[4] = bbram_data_read(BKUP_LREG4); - - /* Reset panic data in BBRAM. */ - bbram_data_write(BBRM_DATA_INDEX_PANIC_FLAGS, 0); -} -#endif /* CONFIG_CHIP_PANIC_BACKUP */ - -void chip_save_reset_flags(uint32_t flags) -{ - bbram_data_write(BBRM_DATA_INDEX_SAVED_RESET_FLAGS, flags); -} - -uint32_t chip_read_reset_flags(void) -{ - return bbram_data_read(BBRM_DATA_INDEX_SAVED_RESET_FLAGS); -} - -static void chip_set_hib_flag(uint32_t *flags, uint32_t hib_wake_flags) -{ - /* Hibernate via PSL */ - if (hib_wake_flags & HIBERNATE_WAKE_PSL) { -#ifdef NPCX_LCT_SUPPORT - if (npcx_lct_is_event_set()) { - *flags |= EC_RESET_FLAG_RTC_ALARM | - EC_RESET_FLAG_HIBERNATE; - /* Is RTC overflow event? */ - if (bbram_data_read(BBRM_DATA_INDEX_LCT_TIME) == - NPCX_LCT_MAX) { - /* - * Mark it as RTC overflow event and handle it - * in hook init function later for logging info. - */ - is_rtc_overflow_event = 1; - } - npcx_lct_clear_event(); - return; - } -#endif - *flags |= EC_RESET_FLAG_WAKE_PIN | - EC_RESET_FLAG_HIBERNATE; - } else { /* Hibernate via non-PSL */ -#ifdef NPCX_LCT_SUPPORT - if (hib_wake_flags & HIBERNATE_WAKE_LCT) { - *flags |= EC_RESET_FLAG_RTC_ALARM | - EC_RESET_FLAG_HIBERNATE; - return; - } -#endif - if (hib_wake_flags & HIBERNATE_WAKE_PIN) { - *flags |= EC_RESET_FLAG_WAKE_PIN | - EC_RESET_FLAG_HIBERNATE; - } else if (hib_wake_flags & HIBERNATE_WAKE_MTC) { - *flags |= EC_RESET_FLAG_RTC_ALARM | - EC_RESET_FLAG_HIBERNATE; - } - } -} - -static void check_reset_cause(void) -{ - uint32_t hib_wake_flags = bbram_data_read(BBRM_DATA_INDEX_WAKE); - uint32_t chip_flags = chip_read_reset_flags(); - uint32_t flags = chip_flags; - - /* Clear saved reset flags in bbram */ -#ifdef CONFIG_POWER_BUTTON_INIT_IDLE - /* - * We're not sure whether we're booting or not. AP_IDLE will be cleared - * on S5->S3 transition. - */ - chip_flags &= EC_RESET_FLAG_AP_IDLE; -#else - chip_flags = 0; -#endif - /* Clear saved hibernate wake flag in bbram , too */ - bbram_data_write(BBRM_DATA_INDEX_WAKE, 0); - - chip_set_hib_flag(&flags, hib_wake_flags); - - /* Use scratch bit to check power on reset or VCC1_RST reset */ - if (!IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_SCRATCH)) { -#ifdef CONFIG_BOARD_FORCE_RESET_PIN - /* Treat all resets as RESET_PIN */ - flags |= EC_RESET_FLAG_RESET_PIN; -#else - /* Check for VCC1 reset */ - int reset = IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_STS); - - /* - * If configured, check the saved flags to see whether - * the previous restart was a power-on, in which case - * treat this restart as a power-on as well. - * This is to workaround the fact that the H1 will - * reset the EC at power up. - */ - if (IS_ENABLED(CONFIG_BOARD_RESET_AFTER_POWER_ON)) { - /* - * Reset pin restart rather than power-on, so check - * for any flag set from a previous power-on. - */ - if (reset) { - if (flags & EC_RESET_FLAG_INITIAL_PWR) - /* - * The previous restart was a power-on - * so treat this restart as that, and - * clear the flag so later code will - * not wait for the second reset. - */ - flags = - (flags & ~EC_RESET_FLAG_INITIAL_PWR) - | EC_RESET_FLAG_POWER_ON; - else - /* - * No previous power-on flag, - * so this is a subsequent restart - * i.e any restarts after the - * second restart caused by the H1. - */ - flags |= EC_RESET_FLAG_RESET_PIN; - } else { - flags |= EC_RESET_FLAG_POWER_ON; - - /* - * Power-on restart, so set a flag and save it - * for the next imminent reset. Later code - * will check for this flag and wait for the - * second reset. Waking from PSL hibernate is - * power-on for EC but not for H1, so do not - * wait for the second reset. - */ - if (!(flags & EC_RESET_FLAG_HIBERNATE)) { - flags |= EC_RESET_FLAG_INITIAL_PWR; - chip_flags |= EC_RESET_FLAG_INITIAL_PWR; - } - } - } else - /* - * No second reset after power-on, so - * set the flags according to the restart reason. - */ - flags |= reset ? EC_RESET_FLAG_RESET_PIN - : EC_RESET_FLAG_POWER_ON; -#endif - } - chip_save_reset_flags(chip_flags); - - /* - * Set scratch bit to distinguish VCC1RST# is asserted again - * or not. This bit will be clear automatically when VCC1RST# - * is asserted or power-on reset occurs - */ - SET_BIT(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_SCRATCH); - - /* Software debugger reset */ - if (IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_DBGRST_STS)) { - flags |= EC_RESET_FLAG_SOFT; - /* Clear debugger reset status initially*/ - SET_BIT(NPCX_RSTCTL, NPCX_RSTCTL_DBGRST_STS); - } - - /* Watchdog Reset */ - if (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS)) { - /* - * Don't set EC_RESET_FLAG_WATCHDOG flag if watchdog is issued - * by system_reset or hibernate in order to distinguish reset - * cause is panic reason or not. - */ - if (!(flags & (EC_RESET_FLAG_SOFT | EC_RESET_FLAG_HARD | - EC_RESET_FLAG_HIBERNATE))) - flags |= EC_RESET_FLAG_WATCHDOG; - - /* Clear watchdog reset status initially*/ - SET_BIT(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS); - } - - system_set_reset_flags(flags); -} - -/** - * Chip-level function to set GPIOs and wake-up inputs for hibernate. - */ -#ifdef CONFIG_SUPPORT_CHIP_HIBERNATION -static void system_set_gpios_and_wakeup_inputs_hibernate(void) -{ - int table, i; - - /* Disable all MIWU inputs before entering hibernate */ - for (table = MIWU_TABLE_0 ; table < MIWU_TABLE_2 ; table++) { - for (i = 0 ; i < 8 ; i++) { - /* Disable all wake-ups */ - NPCX_WKEN(table, i) = 0x00; - /* Clear all pending bits of wake-ups */ - NPCX_WKPCL(table, i) = 0xFF; - /* - * Disable all inputs of wake-ups to prevent leakage - * caused by input floating. - */ - NPCX_WKINEN(table, i) = 0x00; - } - } - -#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7 - /* Disable MIWU 2 group 6 inputs which used for the additional GPIOs */ - NPCX_WKEN(MIWU_TABLE_2, MIWU_GROUP_6) = 0x00; - NPCX_WKPCL(MIWU_TABLE_2, MIWU_GROUP_6) = 0xFF; - NPCX_WKINEN(MIWU_TABLE_2, MIWU_GROUP_6) = 0x00; -#endif - - /* Enable wake-up inputs of hibernate_wake_pins array */ - for (i = 0; i < hibernate_wake_pins_used; i++) { - gpio_reset(hibernate_wake_pins[i]); - /* Re-enable interrupt for wake-up inputs */ - gpio_enable_interrupt(hibernate_wake_pins[i]); -#if defined(CONFIG_HIBERNATE_PSL) - /* Config PSL pins setting for wake-up inputs */ - if (!system_config_psl_mode(hibernate_wake_pins[i])) - ccprintf("Invalid PSL setting in wake-up pin %d\n", i); -#endif - } -} - -#ifdef NPCX_LCT_SUPPORT -static void system_set_lct_alarm(uint32_t seconds, uint32_t microseconds) -{ - /* The min resolution of LCT is 1 seconds */ - if ((seconds == 0) && (microseconds != 0)) - seconds = 1; - - npcx_lct_enable(0); - npcx_lct_sel_power_src(NPCX_LCT_PWR_SRC_VSBY); -#ifdef CONFIG_HIBERNATE_PSL - /* Enable LCT event to PSL */ - npcx_lct_config(seconds, 1, 0); - /* save the start time of LCT */ - if (IS_ENABLED(CONFIG_HOSTCMD_RTC) || IS_ENABLED(CONFIG_CMD_RTC)) - bbram_data_write(BBRM_DATA_INDEX_LCT_TIME, seconds); -#else - /* Enable LCT event interrupt and MIWU */ - npcx_lct_config(seconds, 0, 1); - task_disable_irq(NPCX_IRQ_LCT_WKINTF_2); - /* Enable wake-up input sources & clear pending bit */ - NPCX_WKPCL(MIWU_TABLE_2, LCT_WUI_GROUP) |= LCT_WUI_MASK; - NPCX_WKINEN(MIWU_TABLE_2, LCT_WUI_GROUP) |= LCT_WUI_MASK; - NPCX_WKEN(MIWU_TABLE_2, LCT_WUI_GROUP) |= LCT_WUI_MASK; - task_enable_irq(NPCX_IRQ_LCT_WKINTF_2); -#endif - npcx_lct_enable(1); -} -#endif - -/** - * hibernate function for npcx ec. - * - * @param seconds Number of seconds to sleep before LCT alarm - * @param microseconds Number of microseconds to sleep before LCT alarm - */ -void __enter_hibernate(uint32_t seconds, uint32_t microseconds) -{ - int i; - - /* Disable ADC */ - NPCX_ADCCNF = 0; - usleep(1000); - -#ifdef NPCX_LCT_SUPPORT - /* - * This function must be called before the ITIM (system tick) - * is disabled because it calls udelay inside this function - */ - npcx_lct_enable_clk(1); -#endif - - /* Set SPI pins to be in Tri-State */ - SET_BIT(NPCX_DEVCNT, NPCX_DEVCNT_F_SPI_TRIS); - - /* Disable instant wake up mode for better power consumption */ - CLEAR_BIT(NPCX_ENIDL_CTL, NPCX_ENIDL_CTL_LP_WK_CTL); - - /* Disable interrupt */ - interrupt_disable(); - - /* Unlock & stop watchdog */ - watchdog_stop_and_unlock(); - - /* ITIM event module disable */ - CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITCTS_ITEN); - /* ITIM time module disable */ - CLEAR_BIT(NPCX_ITCTS(ITIM_SYSTEM_NO), NPCX_ITCTS_ITEN); - /* ITIM watchdog warn module disable */ - CLEAR_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITCTS_ITEN); - - /* Initialize watchdog */ - NPCX_TWCFG = 0; /* Select T0IN clock as watchdog prescaler clock */ - SET_BIT(NPCX_TWCFG, NPCX_TWCFG_WDCT0I); - NPCX_TWCP = 0x00; /* Keep prescaler ratio timer0 clock to 1:1 */ - NPCX_TWDT0 = 0x00; /* Set internal counter and prescaler */ - - /* Disable interrupt */ - interrupt_disable(); - - /* - * Set gpios and wake-up input for better power consumption before - * entering hibernate. - */ - system_set_gpios_and_wakeup_inputs_hibernate(); - - /* - * Give the board a chance to do any late stage hibernation work. This - * is likely going to configure GPIOs for hibernation. On some boards, - * it's possible that this may not return at all. On those boards, - * power to the EC is likely being turn off entirely. - */ - if (board_hibernate_late) - board_hibernate_late(); - - /* Clear all pending IRQ otherwise wfi will have no affect */ - for (i = NPCX_IRQ_0 ; i < NPCX_IRQ_COUNT ; i++) - task_clear_pending_irq(i); - - /* Set the timer interrupt for wake up. */ -#ifdef NPCX_LCT_SUPPORT - if (seconds || microseconds) { - system_set_lct_alarm(seconds, microseconds); - } else if (IS_ENABLED(CONFIG_HIBERNATE_PSL_COMPENSATE_RTC)) { - system_set_lct_alarm(NPCX_LCT_MAX, 0); - } -#else - if (seconds || microseconds) - system_set_rtc_alarm(seconds, microseconds); -#endif - - /* execute hibernate func depend on chip series */ - __hibernate_npcx_series(); -} - -#ifdef CONFIG_HIBERNATE_PSL_COMPENSATE_RTC -#ifndef NPCX_LCT_SUPPORT -#error "Do not enable CONFIG_HIBERNATE_PSL_COMPENSATE_RTC if npcx ec doesn't \ -support LCT!" -#endif -/* - * The function uses the LCT counter value to compensate for RTC after hibernate - * wake-up. Because system_set_rtc() will invoke udelay(), the function should - * execute after timer_init(). The function also should execute before - * npcx_lct_init() which will clear all LCT register. - */ -void system_compensate_rtc(void) -{ - uint32_t rtc_time, ltc_start_time; - - ltc_start_time = bbram_data_read(BBRM_DATA_INDEX_LCT_TIME); - if (ltc_start_time == 0) - return; - - rtc_time = system_get_rtc_sec(); - rtc_time += ltc_start_time - npcx_lct_get_time(); - system_set_rtc(rtc_time); - /* Clear BBRAM data to avoid compensating again. */ - bbram_data_write(BBRM_DATA_INDEX_LCT_TIME, 0); -} -#endif -#endif /* CONFIG_SUPPORT_CHIP_HIBERNATION */ - -static char system_to_hex(uint8_t val) -{ - uint8_t x = val & 0x0F; - - if (x <= 9) - return '0' + x; - return 'a' + x - 10; -} - -/*****************************************************************************/ -/* IC specific low-level driver */ - -/* - * Microseconds will be ignored. The WTC register only - * stores wakeup time in seconds. - * Set seconds = 0 to disable the alarm - */ -void system_set_rtc_alarm(uint32_t seconds, uint32_t microseconds) -{ - uint32_t cur_secs, alarm_secs; - - if (seconds == EC_RTC_ALARM_CLEAR && !microseconds) { - CLEAR_BIT(NPCX_WTC, NPCX_WTC_WIE); - SET_BIT(NPCX_WTC, NPCX_WTC_PTO); - - return; - } - - /* Get current clock */ - cur_secs = NPCX_TTC; - - /* If alarm clock is not sequential or not in range */ - alarm_secs = cur_secs + seconds; - alarm_secs = alarm_secs & MTC_ALARM_MASK; - - /* - * We should set new alarm (first 25 bits of clock value) first before - * clearing PTO in case issue rtc interrupt immediately. - */ - NPCX_WTC = alarm_secs; - - /* Reset alarm first */ - system_reset_rtc_alarm(); - - /* Enable interrupt mode alarm */ - SET_BIT(NPCX_WTC, NPCX_WTC_WIE); - - /* Enable MTC interrupt */ - task_enable_irq(NPCX_IRQ_MTC); - - /* Enable wake-up input sources & clear pending bit */ - NPCX_WKPCL(MIWU_TABLE_0, MTC_WUI_GROUP) |= MTC_WUI_MASK; - NPCX_WKINEN(MIWU_TABLE_0, MTC_WUI_GROUP) |= MTC_WUI_MASK; - NPCX_WKEN(MIWU_TABLE_0, MTC_WUI_GROUP) |= MTC_WUI_MASK; -} - -void system_reset_rtc_alarm(void) -{ - /* - * Clear interrupt & Disable alarm interrupt - * Update alarm value to zero - */ - CLEAR_BIT(NPCX_WTC, NPCX_WTC_WIE); - SET_BIT(NPCX_WTC, NPCX_WTC_PTO); - - /* Disable MTC interrupt */ - task_disable_irq(NPCX_IRQ_MTC); -} - -/* - * Return the seconds remaining before the RTC alarm goes off. - * Returns 0 if alarm is not set. - */ -uint32_t system_get_rtc_alarm(void) -{ - /* - * Return 0: - * 1. If alarm is not set to go off, OR - * 2. If alarm is set and has already gone off - */ - if (!IS_BIT_SET(NPCX_WTC, NPCX_WTC_WIE) || - IS_BIT_SET(NPCX_WTC, NPCX_WTC_PTO)) { - return 0; - } - /* Get seconds before alarm goes off */ - return (NPCX_WTC - NPCX_TTC) & MTC_ALARM_MASK; -} - -/** - * Enable hibernate interrupt - */ -void system_enable_hib_interrupt(void) -{ - task_enable_irq(NPCX_IRQ_MTC); -} - -void system_hibernate(uint32_t seconds, uint32_t microseconds) -{ - /* Flush console before hibernating */ - cflush(); - - if (board_hibernate) - board_hibernate(); - -#ifdef CONFIG_SUPPORT_CHIP_HIBERNATION - /* Add additional hibernate operations here */ - __enter_hibernate(seconds, microseconds); -#endif -} - -#ifndef CONFIG_ENABLE_JTAG_SELECTION -static void system_disable_host_sel_jtag(void) -{ - int data; - - /* Enable Core-to-Host Modules Access */ - SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE); - /* Clear SIOCFD.JEN0_HSL to disable JTAG0 */ - data = sib_read_reg(SIO_OFFSET, SIOCFD_REG_OFFSET); - data &= ~0x80; - sib_write_reg(SIO_OFFSET, SIOCFD_REG_OFFSET, data); - /* Disable Core-to-Host Modules Access */ - CLEAR_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE); -} -#endif - -void chip_pre_init(void) -{ - /* Setting for fixing JTAG issue */ - NPCX_DBGCTRL = 0x04; - /* Enable automatic freeze mode */ - CLEAR_BIT(NPCX_DBGFRZEN3, NPCX_DBGFRZEN3_GLBL_FRZ_DIS); - - /* - * Enable JTAG functionality by SW without pulling down strap-pin - * nJEN0 or nJEN1 during ec POWERON or VCCRST reset occurs. - * Please notice it will change pinmux to JTAG directly. - */ -#ifdef NPCX_ENABLE_JTAG -#if NPCX_JTAG_MODULE2 - CLEAR_BIT(NPCX_DEVALT(ALT_GROUP_5), NPCX_DEVALT5_NJEN1_EN); -#else - CLEAR_BIT(NPCX_DEVALT(ALT_GROUP_5), NPCX_DEVALT5_NJEN0_EN); -#endif -#endif - -#ifndef CONFIG_ENABLE_JTAG_SELECTION - /* - * (b/129908668) - * This is the workaround to disable the JTAG0 which is enabled - * accidentally by a special key combination. - */ -#if NPCX_FAMILY_VERSION < NPCX_FAMILY_NPCX9 - if (!IS_BIT_SET(NPCX_DEVALT(5), NPCX_DEVALT5_NJEN0_EN)) { - /* Set DEVALT5.nJEN0_EN to disable JTAG0 */ - SET_BIT(NPCX_DEVALT(5), NPCX_DEVALT5_NJEN0_EN); - system_disable_host_sel_jtag(); - } -#else - if (GET_FIELD(NPCX_JEN_CTL1, NPCX_JEN_CTL1_JEN_EN_FIELD) == - NPCX_JEN_CTL1_JEN_EN_ENA) { - SET_FIELD(NPCX_JEN_CTL1, NPCX_JEN_CTL1_JEN_EN_FIELD, - NPCX_JEN_CTL1_JEN_EN_DIS); - system_disable_host_sel_jtag(); - } -#endif -#endif -} - -void system_pre_init(void) -{ - uint8_t pwdwn6; - - /* - * Add additional initialization here - * EC should be initialized in Booter - */ - - /* Power-down the modules we don't need */ - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_1) = 0xF9; /* Skip SDP_PD FIU_PD */ - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_2) = 0xFF; -#if defined(CHIP_FAMILY_NPCX5) - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_3) = 0x0F; /* Skip GDMA */ -#elif NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7 - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_3) = 0x3F; /* Skip GDMA */ -#endif - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_4) = 0xF4; /* Skip ITIM2/1_PD */ - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_5) = 0xF8; - - pwdwn6 = 0x70 | -#if NPCX_FAMILY_VERSION <= NPCX_FAMILY_NPCX7 - /* - * Don't set PD of ITIM6 for NPCX9 and later chips because - * they use it as the system timer. - */ - BIT(NPCX_PWDWN_CTL6_ITIM6_PD) | -#endif - BIT(NPCX_PWDWN_CTL6_ITIM4_PD); /* Skip ITIM5_PD */ -#if !defined(CONFIG_HOSTCMD_ESPI) - pwdwn6 |= 1 << NPCX_PWDWN_CTL6_ESPI_PD; -#endif - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_6) = pwdwn6; - -#if defined(CHIP_FAMILY_NPCX7) -#if defined(CHIP_VARIANT_NPCX7M6FB) || defined(CHIP_VARIANT_NPCX7M6FC) || \ - defined(CHIP_VARIANT_NPCX7M7FC) || defined(CHIP_VARIANT_NPCX7M7WB) || \ - defined(CHIP_VARIANT_NPCX7M7WC) - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_7) = 0xE7; -#else - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_7) = 0x07; -#endif -#endif -#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX9 - NPCX_PWDWN_CTL(NPCX_PMC_PWDWN_7) = 0xFF; -#endif - - /* Following modules can be powered down automatically in npcx7 */ -#if defined(CHIP_FAMILY_NPCX5) - /* Power down the modules of npcx5 used internally */ - NPCX_INTERNAL_CTRL1 = 0x03; - NPCX_INTERNAL_CTRL2 = 0x03; - NPCX_INTERNAL_CTRL3 = 0x03; - - /* Enable low-power regulator */ - CLEAR_BIT(NPCX_LFCGCALCNT, NPCX_LFCGCALCNT_LPREG_CTL_EN); - SET_BIT(NPCX_LFCGCALCNT, NPCX_LFCGCALCNT_LPREG_CTL_EN); -#endif - - /* - * Configure LPRAM in the MPU as a regular memory - * and DATA RAM to prevent code execution - */ - system_mpu_config(); - - /* - * Change FMUL_WIN_DLY from 0x8A to 0x81 for better WoV - * audio quality. - */ -#ifdef CHIP_FAMILY_NPCX7 - NPCX_FMUL_WIN_DLY = 0x81; -#endif - -#ifdef CONFIG_CHIP_PANIC_BACKUP - chip_panic_data_restore(); -#endif - -#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX9 - if (IS_ENABLED(CONFIG_HIBERNATE_PSL)) { - uint8_t opt_flag = CONFIG_HIBERNATE_PSL_OUT_FLAGS; - - /* PSL Glitch Protection */ - SET_BIT(NPCX_GLUE_PSL_MCTL2, NPCX_GLUE_PSL_MCTL2_PSL_GP_EN); - - /* - * TODO: Remove this when NPCX9 A2 chip is available because A2 - * chip will enable VCC1_RST to PSL wakeup source and lock it in - * the booter. - */ - if (IS_ENABLED(CONFIG_HIBERNATE_PSL_VCC1_RST_WAKEUP)) { - /* - * Enable VCC1_RST as the wake-up source from - * hibernation. - */ - SET_BIT(NPCX_GLUE_PSL_MCTL1, - NPCX_GLUE_PSL_MCTL1_VCC1_RST_PSL); - /* Disable VCC_RST Pull-Up */ - SET_BIT(NPCX_DEVALT(ALT_GROUP_G), - NPCX_DEVALTG_VCC1_RST_PUD); - /* - * Lock this bit itself and VCC1_RST_PSL in the - * PSL_MCTL1 register to read-only. - */ - SET_BIT(NPCX_GLUE_PSL_MCTL2, - NPCX_GLUE_PSL_MCTL2_VCC1_RST_PSL_LK); - } - - /* Don't set PSL_OUT to open-drain if it is the level mode */ - ASSERT((opt_flag & NPCX_PSL_CFG_PSL_OUT_PULSE) || - !(opt_flag & NPCX_PSL_CFG_PSL_OUT_OD)); - - if (opt_flag & NPCX_PSL_CFG_PSL_OUT_OD) - SET_BIT(NPCX_GLUE_PSL_MCTL1, NPCX_GLUE_PSL_MCTL1_OD_EN); - else - CLEAR_BIT(NPCX_GLUE_PSL_MCTL1, - NPCX_GLUE_PSL_MCTL1_OD_EN); - - if (opt_flag & NPCX_PSL_CFG_PSL_OUT_PULSE) - SET_BIT(NPCX_GLUE_PSL_MCTL1, - NPCX_GLUE_PSL_MCTL1_PLS_EN); - else - CLEAR_BIT(NPCX_GLUE_PSL_MCTL1, - NPCX_GLUE_PSL_MCTL1_PLS_EN); - } -#endif -} - -void system_reset(int flags) -{ - uint32_t save_flags; - - /* Disable interrupts to avoid task swaps during reboot */ - interrupt_disable(); - - /* Get flags to be saved in BBRAM */ - system_encode_save_flags(flags, &save_flags); - - /* Store flags to battery backed RAM. */ - chip_save_reset_flags(save_flags); - - /* If WAIT_EXT is set, then allow 10 seconds for external reset */ - if (flags & SYSTEM_RESET_WAIT_EXT) { - int i; - - /* Wait 10 seconds for external reset */ - for (i = 0; i < 1000; i++) { - watchdog_reload(); - udelay(10000); - } - } - - /* Ask the watchdog to trigger a hard reboot */ - system_watchdog_reset(); - - /* Spin and wait for reboot; should never return */ - while (1) - ; -} - -/** - * Return the chip vendor/name/revision string. - */ -const char *system_get_chip_vendor(void) -{ - static char str[15] = "Unknown-"; - char *p = str + 8; - - /* Read Vendor ID in core register */ - uint8_t fam_id = NPCX_SID_CR; - switch (fam_id) { - case 0x20: - return "Nuvoton"; - default: - *p = system_to_hex(fam_id >> 4); - *(p + 1) = system_to_hex(fam_id); - *(p + 2) = '\0'; - return str; - } -} - -const char *system_get_chip_name(void) -{ - static char str[15] = "Unknown-"; - char *p = str + 8; - - /* Read Chip ID in core register */ - uint8_t chip_id = NPCX_DEVICE_ID_CR; - - switch (chip_id) { -#if defined(CHIP_FAMILY_NPCX5) - case NPCX585G_CHIP_ID: - return "NPCX585G"; - case NPCX575G_CHIP_ID: - return "NPCX575G"; - case NPCX586G_CHIP_ID: - return "NPCX586G"; - case NPCX576G_CHIP_ID: - return "NPCX576G"; -#elif defined(CHIP_FAMILY_NPCX7) - case NPCX787G_CHIP_ID: - return "NPCX787G"; - case NPCX797F_C_CHIP_ID: - return "NPCX797F"; - case NPCX796F_A_B_CHIP_ID: - case NPCX796F_C_CHIP_ID: - return "NPCX796F"; - case NPCX797W_B_CHIP_ID: - case NPCX797W_C_CHIP_ID: - return "NPCX797W"; -#elif defined(CHIP_FAMILY_NPCX9) - case NPCX996F_CHIP_ID: - return "NPCX996F"; - case NPCX993F_CHIP_ID: - return "NPCX993F"; -#endif - default: - *p = system_to_hex(chip_id >> 4); - *(p + 1) = system_to_hex(chip_id); - *(p + 2) = '\0'; - return str; - } -} - -const char *system_get_chip_revision(void) -{ - static char rev[CHIP_REV_STR_SIZE]; - char *p = rev; - /* Read chip generation from SRID_CR */ - uint8_t chip_gen = NPCX_SRID_CR; - /* Read ROM data for chip revision directly */ -#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX9 - uint32_t rev_num = *((uint32_t *)CHIP_REV_ADDR); -#else - uint8_t rev_num = *((uint8_t *)CHIP_REV_ADDR); -#endif - -#ifdef CHIP_FAMILY_NPCX7 - uint8_t chip_id = NPCX_DEVICE_ID_CR; -#endif - int s; - - switch (chip_gen) { -#if defined(CHIP_FAMILY_NPCX5) - case 0x05: - *p++ = 'A'; - break; -#elif defined(CHIP_FAMILY_NPCX7) - case 0x06: - *p++ = 'A'; - break; - case 0x07: - if (chip_id == NPCX796F_A_B_CHIP_ID || - chip_id == NPCX797W_B_CHIP_ID) - *p++ = 'B'; - else - *p++ = 'C'; - break; -#elif defined(CHIP_FAMILY_NPCX9) - case 0x09: - *p++ = 'A'; - break; -#endif - default: - *p++ = system_to_hex(chip_gen >> 4); - *p++ = system_to_hex(chip_gen); - break; - } - - *p++ = '.'; - /* - * For npcx5/npcx7, the revision number is 1 byte. - * For NPCX9 and later chips, the revision number is 4 bytes. - */ - for (s = sizeof(rev_num) - 1; s >= 0; s--) { - uint8_t r = rev_num >> (s * 8); - - *p++ = system_to_hex(r >> 4); - *p++ = system_to_hex(r); - } - *p++ = '\0'; - - return rev; -} - -/** - * Set a scratchpad register to the specified value. - * - * The scratchpad register must maintain its contents across a - * software-requested warm reset. - * - * @param value Value to store. - * @return EC_SUCCESS, or non-zero if error. - */ -int system_set_scratchpad(uint32_t value) -{ - return bbram_data_write(BBRM_DATA_INDEX_SCRATCHPAD, value); -} - -int system_get_scratchpad(uint32_t *value) -{ - *value = bbram_data_read(BBRM_DATA_INDEX_SCRATCHPAD); - return EC_SUCCESS; -} - -int system_is_reboot_warm(void) -{ - uint32_t reset_flags; - - /* - * Check reset cause here, - * gpio_pre_init is executed faster than system_pre_init - */ - check_reset_cause(); - reset_flags = system_get_reset_flags(); - - if ((reset_flags & EC_RESET_FLAG_RESET_PIN) || - (reset_flags & EC_RESET_FLAG_POWER_ON) || - (reset_flags & EC_RESET_FLAG_WATCHDOG) || - (reset_flags & EC_RESET_FLAG_HARD) || - (reset_flags & EC_RESET_FLAG_SOFT) || - (reset_flags & EC_RESET_FLAG_HIBERNATE)) - return 0; - else - return 1; -} - -#if defined(CONFIG_HIBERNATE_PSL) && defined(NPCX_LCT_SUPPORT) -static void system_init_check_rtc_wakeup_event(void) -{ - /* - * If platform uses PSL (Power Switch Logic) for hibernating and RTC is - * also supported, determine whether ec is woken up by RTC with overflow - * event (16 weeks). If so, let it go to hibernate mode immediately. - */ - if (is_rtc_overflow_event){ - CPRINTS("Hibernate due to RTC overflow event"); - system_hibernate(0, 0); - } -} -DECLARE_HOOK(HOOK_INIT, system_init_check_rtc_wakeup_event, - HOOK_PRIO_DEFAULT - 1); -#endif - -/*****************************************************************************/ -/* Console commands */ -void print_system_rtc(enum console_channel ch) -{ - uint32_t sec = system_get_rtc_sec(); - - cprintf(ch, "RTC: 0x%08x (%d.00 s)\n", sec, sec); -} - -#ifdef CONFIG_CMD_RTC -static int command_system_rtc(int argc, char **argv) -{ - if (argc == 3 && !strcasecmp(argv[1], "set")) { - char *e; - uint32_t t = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - - system_set_rtc(t); - } else if (argc > 1) { - return EC_ERROR_INVAL; - } - - print_system_rtc(CC_COMMAND); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(rtc, command_system_rtc, - "[set <seconds>]", - "Get/set real-time clock"); - -#ifdef CONFIG_CMD_RTC_ALARM -/** - * Test the RTC alarm by setting an interrupt on RTC match. - */ -static int command_rtc_alarm_test(int argc, char **argv) -{ - int s = 1, us = 0; - char *e; - - ccprintf("Setting RTC alarm\n"); - system_enable_hib_interrupt(); - - if (argc > 1) { - s = strtoi(argv[1], &e, 10); - if (*e) - return EC_ERROR_PARAM1; - - } - if (argc > 2) { - us = strtoi(argv[2], &e, 10); - if (*e) - return EC_ERROR_PARAM2; - - } - - system_set_rtc_alarm(s, us); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(rtc_alarm, command_rtc_alarm_test, - "[seconds [microseconds]]", - "Test alarm"); -#endif /* CONFIG_CMD_RTC_ALARM */ -#endif /* CONFIG_CMD_RTC */ - -/*****************************************************************************/ -/* Host commands */ - -#ifdef CONFIG_HOSTCMD_RTC -static enum ec_status system_rtc_get_value(struct host_cmd_handler_args *args) -{ - struct ec_response_rtc *r = args->response; - - r->time = system_get_rtc_sec(); - args->response_size = sizeof(*r); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_RTC_GET_VALUE, - system_rtc_get_value, - EC_VER_MASK(0)); - -static enum ec_status system_rtc_set_value(struct host_cmd_handler_args *args) -{ - const struct ec_params_rtc *p = args->params; - - system_set_rtc(p->time); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_RTC_SET_VALUE, - system_rtc_set_value, - EC_VER_MASK(0)); - -static enum ec_status system_rtc_set_alarm(struct host_cmd_handler_args *args) -{ - const struct ec_params_rtc *p = args->params; - - system_set_rtc_alarm(p->time, 0); - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_RTC_SET_ALARM, - system_rtc_set_alarm, - EC_VER_MASK(0)); - -static enum ec_status system_rtc_get_alarm(struct host_cmd_handler_args *args) -{ - struct ec_response_rtc *r = args->response; - - r->time = system_get_rtc_alarm(); - args->response_size = sizeof(*r); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_RTC_GET_ALARM, - system_rtc_get_alarm, - EC_VER_MASK(0)); - -#endif /* CONFIG_HOSTCMD_RTC */ -#ifdef CONFIG_EXTERNAL_STORAGE -void system_jump_to_booter(void) -{ - enum API_RETURN_STATUS_T status __attribute__((unused)); - static uint32_t flash_offset; - static uint32_t flash_used; - static uint32_t addr_entry; - - /* - * Get memory offset and size for RO/RW regions. - * Both of them need 16-bytes alignment since GDMA burst mode. - */ - switch (system_get_shrspi_image_copy()) { - case EC_IMAGE_RW: - flash_offset = CONFIG_EC_WRITABLE_STORAGE_OFF + - CONFIG_RW_STORAGE_OFF; - flash_used = CONFIG_RW_SIZE; - break; -#ifdef CONFIG_RW_B - case EC_IMAGE_RW_B: - flash_offset = CONFIG_EC_WRITABLE_STORAGE_OFF + - CONFIG_RW_B_STORAGE_OFF; - flash_used = CONFIG_RW_SIZE; - break; -#endif - case EC_IMAGE_RO: - default: /* Jump to RO by default */ - flash_offset = CONFIG_EC_PROTECTED_STORAGE_OFF + - CONFIG_RO_STORAGE_OFF; - flash_used = CONFIG_RO_SIZE; - break; - } - - /* Make sure the reset vector is inside the destination image */ - addr_entry = *(uintptr_t *)(flash_offset + - CONFIG_MAPPED_STORAGE_BASE + 4); - - /* - * Speed up FW download time by increasing clock freq of EC. It will - * restore to default in clock_init() later. - */ - clock_turbo(); - -/* - * npcx9 Rev.1 has the problem for download_from_flash API. - * Workwaroud it by executing the system_download_from_flash function - * in the suspend RAM like npcx5. - * TODO: Removing npcx9 when Rev.2 is available. - */ - /* Bypass for GMDA issue of ROM api utilities */ -#if defined(CHIP_FAMILY_NPCX5) || defined(CONFIG_WORKAROUND_FLASH_DOWNLOAD_API) - system_download_from_flash( - flash_offset, /* The offset of the data in spi flash */ - CONFIG_PROGRAM_MEMORY_BASE, /* RAM Addr of downloaded data */ - flash_used, /* Number of bytes to download */ - addr_entry /* jump to this address after download */ - ); -#else - download_from_flash( - flash_offset, /* The offset of the data in spi flash */ - CONFIG_PROGRAM_MEMORY_BASE, /* RAM Addr of downloaded data */ - flash_used, /* Number of bytes to download */ - SIGN_NO_CHECK, /* Need CRC check or not */ - addr_entry, /* jump to this address after download */ - &status /* Status fo download */ - ); -#endif -} - -uint32_t system_get_lfw_address() -{ - /* - * In A3 version, we don't use little FW anymore - * We provide the alternative function in ROM - */ - uint32_t jump_addr = (uint32_t)system_jump_to_booter; - return jump_addr; -} - -/* - * Set and clear image copy flags in MDC register. - * - * NPCX_FWCTRL_RO_REGION: 1 - RO, 0 - RW - * NPCX_FWCTRL_FW_SLOT: 1 - SLOT_A, 0 - SLOT_B - */ -void system_set_image_copy(enum ec_image copy) -{ - switch (copy) { - case EC_IMAGE_RW: - CLEAR_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION); - SET_BIT(NPCX_FWCTRL, NPCX_FWCTRL_FW_SLOT); - break; -#ifdef CONFIG_RW_B - case EC_IMAGE_RW_B: - CLEAR_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION); - CLEAR_BIT(NPCX_FWCTRL, NPCX_FWCTRL_FW_SLOT); - break; -#endif - default: - CPRINTS("Invalid copy (%d) is requested as a jump destination. " - "Change it to %d.", copy, EC_IMAGE_RO); - /* Fall through to EC_IMAGE_RO */ - case EC_IMAGE_RO: - SET_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION); - SET_BIT(NPCX_FWCTRL, NPCX_FWCTRL_FW_SLOT); - break; - } -} - -enum ec_image system_get_shrspi_image_copy(void) -{ - if (IS_BIT_SET(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION)) { - /* RO image */ -#ifdef CHIP_HAS_RO_B - if (!IS_BIT_SET(NPCX_FWCTRL, NPCX_FWCTRL_FW_SLOT)) - return EC_IMAGE_RO_B; -#endif - return EC_IMAGE_RO; - } else { -#ifdef CONFIG_RW_B - /* RW image */ - if (!IS_BIT_SET(NPCX_FWCTRL, NPCX_FWCTRL_FW_SLOT)) - /* Slot A */ - return EC_IMAGE_RW_B; -#endif - return EC_IMAGE_RW; - } -} - -#endif |