| /* Copyright (c) 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 "common.h" |
| #include "console.h" |
| #include "cpu.h" |
| #include "host_command.h" |
| #include "registers.h" |
| #include "system.h" |
| #include "hooks.h" |
| #include "task.h" |
| #include "timer.h" |
| #include "util.h" |
| #include "hwtimer_chip.h" |
| #include "system_chip.h" |
| |
| #ifdef CONFIG_CODERAM_ARCH |
| /* base address for jumping */ |
| uint32_t base_addr; |
| #endif |
| |
| /* Flags for BBRM_DATA_INDEX_WAKE */ |
| #define HIBERNATE_WAKE_MTC (1 << 0) /* MTC alarm */ |
| #define HIBERNATE_WAKE_PIN (1 << 1) /* Wake pin */ |
| |
| /* Super-IO index and register definitions */ |
| #define SIO_OFFSET 0x4E |
| #define INDEX_SID 0x20 |
| #define INDEX_CHPREV 0x24 |
| #define INDEX_SRID 0x27 |
| |
| /* equivalent to 250us according to 48MHz core clock */ |
| #define MTC_TTC_LOAD_DELAY 1500 |
| #define MTC_ALARM_MASK ((1 << 25) - 1) |
| #define MTC_WUI_GROUP MIWU_GROUP_4 |
| #define MTC_WUI_MASK MASK_PIN7 |
| |
| /* ROM address of chip revision */ |
| #define CHIP_REV_ADDR 0x00007FFC |
| |
| /* Begin address for the .lpram section; defined in linker script */ |
| uintptr_t __lpram_fw_start = CONFIG_LPRAM_BASE; |
| |
| /*****************************************************************************/ |
| /* Internal functions */ |
| |
| /* Super-IO read/write function */ |
| void system_sib_write_reg(uint8_t io_offset, uint8_t index_value, |
| uint8_t io_data) |
| { |
| /* Disable interrupts */ |
| interrupt_disable(); |
| |
| /* Lock host CFG module */ |
| SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); |
| /* Enable Core-to-Host Modules Access */ |
| SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE); |
| /* Enable Core access to CFG module */ |
| SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); |
| /* Verify Core read/write to host modules is not in progress */ |
| while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD)) |
| ; |
| while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR)) |
| ; |
| |
| /* Specify the io_offset A0 = 0. the index register is accessed */ |
| NPCX_IHIOA = io_offset; |
| /* Write the data. This starts the write access to the host module */ |
| NPCX_IHD = index_value; |
| /* Wait while Core write operation is in progress */ |
| while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR)) |
| ; |
| |
| /* Specify the io_offset A0 = 1. the data register is accessed */ |
| NPCX_IHIOA = io_offset+1; |
| /* Write the data. This starts the write access to the host module */ |
| NPCX_IHD = io_data; |
| /* Wait while Core write operation is in progress */ |
| while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR)) |
| ; |
| |
| /* Disable Core access to CFG module */ |
| CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); |
| /* Disable Core-to-Host Modules Access */ |
| CLEAR_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE); |
| /* unlock host CFG module */ |
| CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); |
| |
| /* Enable interrupts */ |
| interrupt_enable(); |
| } |
| |
| uint8_t system_sib_read_reg(uint8_t io_offset, uint8_t index_value) |
| { |
| uint8_t data_value; |
| |
| /* Disable interrupts */ |
| interrupt_disable(); |
| |
| /* Lock host CFG module */ |
| SET_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); |
| /* Enable Core-to-Host Modules Access */ |
| SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE); |
| /* Enable Core access to CFG module */ |
| SET_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); |
| /* Verify Core read/write to host modules is not in progress */ |
| while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD)) |
| ; |
| while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR)) |
| ; |
| |
| |
| /* Specify the io_offset A0 = 0. the index register is accessed */ |
| NPCX_IHIOA = io_offset; |
| /* Write the data. This starts the write access to the host module */ |
| NPCX_IHD = index_value; |
| /* Wait while Core write operation is in progress */ |
| while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR)) |
| ; |
| |
| /* Specify the io_offset A0 = 1. the data register is accessed */ |
| NPCX_IHIOA = io_offset+1; |
| /* Start a Core read from host module */ |
| SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD); |
| /* Wait while Core read operation is in progress */ |
| while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD)) |
| ; |
| /* Read the data */ |
| data_value = NPCX_IHD; |
| |
| /* Disable Core access to CFG module */ |
| CLEAR_BIT(NPCX_CRSMAE, NPCX_CRSMAE_CFGAE); |
| /* Disable Core-to-Host Modules Access */ |
| CLEAR_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE); |
| /* unlock host CFG module */ |
| CLEAR_BIT(NPCX_LKSIOHA, NPCX_LKSIOHA_LKCFG); |
| |
| /* Enable interrupts */ |
| interrupt_enable(); |
| |
| return data_value; |
| } |
| |
| void system_watchdog_reset(void) |
| { |
| /* Unlock & stop watchdog registers */ |
| NPCX_WDSDM = 0x87; |
| NPCX_WDSDM = 0x61; |
| NPCX_WDSDM = 0x63; |
| |
| /* 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(); |
| } |
| |
| /** |
| * 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; |
| /* Check index */ |
| if (index < 0 || index >= NPCX_BBRAM_SIZE) |
| return 0; |
| |
| /* BBRAM is valid */ |
| if (IS_BIT_SET(NPCX_BKUP_STS, NPCX_BKUP_STS_IBBR)) |
| return 0; |
| |
| /* Read BBRAM */ |
| 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) |
| { |
| /* Check index */ |
| if (index < 0 || index >= NPCX_BBRAM_SIZE) |
| return EC_ERROR_INVAL; |
| |
| /* BBRAM is valid */ |
| if (IS_BIT_SET(NPCX_BKUP_STS, NPCX_BKUP_STS_IBBR)) |
| return EC_ERROR_INVAL; |
| |
| /* Write BBRAM */ |
| NPCX_BBRAM(index) = value & 0xFF; |
| 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; |
| } |
| |
| /* 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) |
| { |
| volatile uint16_t __i; |
| |
| /* Set MTC counter unit:seconds */ |
| NPCX_TTC = seconds; |
| |
| /* Wait till clock is readable */ |
| for (__i = 0; __i < MTC_TTC_LOAD_DELAY; ++__i) |
| ; |
| } |
| |
| /* Check reset cause */ |
| void system_check_reset_cause(void) |
| { |
| uint32_t hib_wake_flags = bbram_data_read(BBRM_DATA_INDEX_WAKE); |
| uint32_t flags = 0; |
| |
| /* Use scratch bit to check power on reset or VCC1_RST reset */ |
| if (!IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_SCRATCH)) { |
| /* Check for VCC1 reset */ |
| if (IS_BIT_SET(NPCX_RSTCTL, NPCX_RSTCTL_VCC1_RST_STS)) |
| flags |= RESET_FLAG_RESET_PIN; |
| else |
| flags |= RESET_FLAG_POWER_ON; |
| } |
| |
| /* |
| * 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 |= RESET_FLAG_SOFT; |
| /* Clear debugger reset status initially*/ |
| SET_BIT(NPCX_RSTCTL, NPCX_RSTCTL_DBGRST_STS); |
| } |
| |
| /* Watchdog Reset */ |
| #ifndef CHIP_NPCX5M5G |
| if (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS)) { |
| flags |= RESET_FLAG_WATCHDOG; |
| /* Clear watchdog reset status initially*/ |
| SET_BIT(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS); |
| } |
| #else |
| /* Workaround method to check watchdog reset */ |
| if (NPCX_BBRAM(BBRM_DATA_INDEX_RAMLOG) & 0x04) |
| flags |= RESET_FLAG_WATCHDOG; |
| #endif |
| |
| if ((hib_wake_flags & HIBERNATE_WAKE_PIN)) |
| flags |= RESET_FLAG_WAKE_PIN; |
| else if ((hib_wake_flags & HIBERNATE_WAKE_MTC)) |
| flags |= RESET_FLAG_RTC_ALARM; |
| |
| /* Restore then clear saved reset flags */ |
| flags |= bbram_data_read(BBRM_DATA_INDEX_SAVED_RESET_FLAGS); |
| bbram_data_write(BBRM_DATA_INDEX_SAVED_RESET_FLAGS, 0); |
| /* Clear saved hibernate wake flag, too */ |
| bbram_data_write(BBRM_DATA_INDEX_WAKE, 0); |
| |
| system_set_reset_flags(flags); |
| } |
| |
| /** |
| * Configure address 0x40001600 in the the MPU |
| * (Memory Protection Unit) as a "regular" memory |
| */ |
| void system_mpu_config(void) |
| { |
| /* Enable MPU */ |
| CPU_MPU_CTRL = 0x7; |
| |
| /* Create a new MPU Region for low-power ram */ |
| CPU_MPU_RNR = 0; /* Select region number 0 */ |
| CPU_MPU_RASR = CPU_MPU_RASR & 0xFFFFFFFE; /* Disable region */ |
| CPU_MPU_RBAR = CONFIG_LPRAM_BASE; /* Set region base address */ |
| /* |
| * Set region size & attribute and enable region |
| * [31:29] - Reserved. |
| * [28] - XN (Execute Never) = 0 |
| * [27] - Reserved. |
| * [26:24] - AP = 011 (Full access) |
| * [23:22] - Reserved. |
| * [21:19,18,17,16] - TEX,S,C,B = 001000 (Normal memory) |
| * [15:8] - SRD = 0 (Subregions enabled) |
| * [7:6] - Reserved. |
| * [5:1] - SIZE = 01001 (1K) |
| * [0] - ENABLE = 1 (enabled) |
| */ |
| CPU_MPU_RASR = 0x03080013; |
| |
| /* Create a new MPU Region for data ram */ |
| CPU_MPU_RNR = 1; /* Select region number 1 */ |
| CPU_MPU_RASR = CPU_MPU_RASR & 0xFFFFFFFE; /* Disable region */ |
| CPU_MPU_RBAR = CONFIG_RAM_BASE; /* Set region base address */ |
| /* |
| * Set region size & attribute and enable region |
| * [31:29] - Reserved. |
| * [28] - XN (Execute Never) = 1 |
| * [27] - Reserved. |
| * [26:24] - AP = 011 (Full access) |
| * [23:22] - Reserved. |
| * [21:19,18,17,16] - TEX,S,C,B = 001000 (Normal memory) |
| * [15:8] - SRD = 0 (Subregions enabled) |
| * [7:6] - Reserved. |
| * [5:1] - SIZE = 01110 (32K) |
| * [0] - ENABLE = 1 (enabled) |
| */ |
| CPU_MPU_RASR = 0x1308001D; |
| } |
| |
| void __attribute__ ((section(".lowpower_ram"))) |
| __enter_hibernate_in_lpram(void) |
| { |
| |
| /* Disable Code RAM first */ |
| SET_BIT(NPCX_PWDWN_CTL(5), NPCX_PWDWN_CTL5_MRFSH_DIS); |
| SET_BIT(NPCX_DISIDL_CTL, NPCX_DISIDL_CTL_RAM_DID); |
| |
| while (1) { |
| /* Set deep idle - instant wake-up mode*/ |
| NPCX_PMCSR = 0x7; |
| /* Enter deep idle, wake-up by GPIOxx or RTC */ |
| asm("wfi"); |
| |
| /* POWER_BUTTON_L wake-up */ |
| if (NPCX_WKPND(NPCX_BBRAM(BBRM_DATA_INDEX_PBUTTON), |
| NPCX_BBRAM(BBRM_DATA_INDEX_PBUTTON + 1)) |
| & NPCX_BBRAM(BBRM_DATA_INDEX_PBUTTON + 2)) { |
| /* Clear WUI pending bit of POWER_BUTTON_L */ |
| NPCX_WKPCL(NPCX_BBRAM(BBRM_DATA_INDEX_PBUTTON), |
| NPCX_BBRAM(BBRM_DATA_INDEX_PBUTTON + 1)) |
| = NPCX_BBRAM(BBRM_DATA_INDEX_PBUTTON + 2); |
| /* |
| * Mark wake-up reason for hibernate |
| * Do not call bbram_data_write directly cause of |
| * excuting in low-power ram |
| */ |
| NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_PIN; |
| break; |
| } |
| /* RTC wake-up */ |
| else if (IS_BIT_SET(NPCX_WTC, NPCX_WTC_PTO)) { |
| /* Clear WUI pending bit of MTC */ |
| NPCX_WKPCL(MIWU_TABLE_0, MTC_WUI_GROUP) = MTC_WUI_MASK; |
| /* Clear interrupt & Disable alarm interrupt */ |
| CLEAR_BIT(NPCX_WTC, NPCX_WTC_WIE); |
| SET_BIT(NPCX_WTC, NPCX_WTC_PTO); |
| |
| /* Mark wake-up reason for hibernate */ |
| NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_MTC; |
| break; |
| } |
| } |
| |
| /* Start a watchdog reset */ |
| NPCX_WDCNT = 0x01; |
| /* 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)) |
| ; |
| |
| /* Spin and wait for reboot; should never return */ |
| while (1) |
| ; |
| } |
| /** |
| * Internal hibernate function. |
| * |
| * @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; |
| void (*__hibernate_in_lpram)(void) = |
| (void(*)(void))(__lpram_fw_start | 0x01); |
| |
| /* Set instant wake up mode */ |
| SET_BIT(NPCX_ENIDL_CTL, NPCX_ENIDL_CTL_LP_WK_CTL); |
| interrupt_disable(); |
| |
| /* ITIM event module disable */ |
| CLEAR_BIT(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITIM16_ITEN); |
| /* ITIM time module disable */ |
| CLEAR_BIT(NPCX_ITCTS(ITIM_TIME_NO), NPCX_ITIM16_ITEN); |
| /* ITIM watchdog warn module disable */ |
| CLEAR_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITIM16_ITEN); |
| |
| /* |
| * Set RTC interrupt in time to wake up before |
| * next event. |
| */ |
| if (seconds || microseconds) |
| system_set_rtc_alarm(seconds, microseconds); |
| |
| /* Unlock & stop watchdog */ |
| NPCX_WDSDM = 0x87; |
| NPCX_WDSDM = 0x61; |
| NPCX_WDSDM = 0x63; |
| |
| /* Enable Low Power RAM */ |
| NPCX_LPRAM_CTRL = 1; |
| |
| /* 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 */ |
| |
| /* Copy the __enter_hibernate_in_lpram instructions to LPRAM */ |
| for (i = 0; i < &__flash_lpfw_end - &__flash_lpfw_start; i++) |
| *((uint32_t *)__lpram_fw_start + i) = |
| *(&__flash_lpfw_start + i); |
| |
| /* Disable interrupt */ |
| interrupt_disable(); |
| |
| /* execute hibernate func in LPRAM */ |
| __hibernate_in_lpram(); |
| |
| } |
| |
| static char system_to_hex(uint8_t x) |
| { |
| if (x >= 0 && x <= 9) |
| return '0' + x; |
| return 'a' + x - 10; |
| } |
| |
| /*****************************************************************************/ |
| /* IC specific low-level driver */ |
| |
| /* Microsecond will be ignore for hardware limitation */ |
| void system_set_rtc_alarm(uint32_t seconds, uint32_t microseconds) |
| { |
| uint32_t cur_secs, alarm_secs; |
| |
| if (seconds == 0) |
| 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; |
| |
| /* Reset alarm first */ |
| system_reset_rtc_alarm(); |
| |
| /* Set alarm, use first 25 bits of clock value */ |
| NPCX_WTC = alarm_secs; |
| |
| /* Enable interrupt mode alarm */ |
| SET_BIT(NPCX_WTC, NPCX_WTC_WIE); |
| |
| /* Enable MTC interrupt */ |
| task_enable_irq(NPCX_IRQ_MTC_WKINTAD_0); |
| |
| /* Enable wake-up input sources */ |
| 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_WKINTAD_0); |
| } |
| |
| /** |
| * Enable hibernate interrupt |
| */ |
| void system_enable_hib_interrupt(void) |
| { |
| task_enable_irq(NPCX_IRQ_MTC_WKINTAD_0); |
| } |
| |
| void system_hibernate(uint32_t seconds, uint32_t microseconds) |
| { |
| /* Flush console before hibernating */ |
| cflush(); |
| |
| #if SUPPORT_HIB |
| /* Add additional hibernate operations here */ |
| __enter_hibernate(seconds, microseconds); |
| #endif |
| } |
| |
| void system_pre_init(void) |
| { |
| /* |
| * Add additional initialization here |
| * EC should be initialized in Booter |
| */ |
| |
| /* Power-down the modules we don't need */ |
| NPCX_PWDWN_CTL(0) = 0xF9; /* Skip SDP_PD FIU_PD */ |
| NPCX_PWDWN_CTL(1) = 0xFF; |
| NPCX_PWDWN_CTL(2) = 0x8F; |
| NPCX_PWDWN_CTL(3) = 0xF4; /* Skip ITIM2/1_PD */ |
| NPCX_PWDWN_CTL(4) = 0xF8; |
| NPCX_PWDWN_CTL(5) = 0x85; /* Skip ITIM5_PD */ |
| |
| /* |
| * Configure LPRAM in the MPU as a regular memory |
| * and DATA RAM to prevent code execution |
| */ |
| system_mpu_config(); |
| } |
| |
| void system_reset(int flags) |
| { |
| uint32_t save_flags = 0; |
| |
| /* Disable interrupts to avoid task swaps during reboot */ |
| interrupt_disable(); |
| |
| /* Save current reset reasons if necessary */ |
| if (flags & SYSTEM_RESET_PRESERVE_FLAGS) |
| save_flags = system_get_reset_flags() | RESET_FLAG_PRESERVED; |
| |
| /* Add in AP off flag into saved flags. */ |
| if (flags & SYSTEM_RESET_LEAVE_AP_OFF) |
| save_flags |= RESET_FLAG_AP_OFF; |
| |
| /* Save reset flag */ |
| if (flags & SYSTEM_RESET_HARD) |
| save_flags |= RESET_FLAG_HARD; |
| else { |
| save_flags |= RESET_FLAG_SOFT; |
| /* Use SYSRESETREQ to trigger a soft reboot */ |
| CPU_NVIC_APINT = 0x05fa0004; |
| } |
| /* Store flags to battery backed RAM. */ |
| bbram_data_write(BBRM_DATA_INDEX_SAVED_RESET_FLAGS, save_flags); |
| |
| /* 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 & 0xF0) >> 4); |
| *(p + 1) = system_to_hex(fam_id & 0x0F); |
| *(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) { |
| case 0x12: |
| return "NPCX585G"; |
| case 0x13: |
| return "NPCX575G"; |
| default: |
| *p = system_to_hex((chip_id & 0xF0) >> 4); |
| *(p + 1) = system_to_hex(chip_id & 0x0F); |
| *(p + 2) = '\0'; |
| return str; |
| } |
| } |
| |
| const char *system_get_chip_revision(void) |
| { |
| static char rev[4]; |
| #ifndef CHIP_NPCX5M5G |
| uint8_t rev_num = system_sib_read_reg(SIO_OFFSET, INDEX_CHPREV); |
| #else |
| /* Read ROM data for chip revision directly */ |
| uint8_t rev_num = *((uint8_t *)CHIP_REV_ADDR); |
| #endif |
| *(rev) = 'A'; |
| *(rev + 1) = '.'; |
| *(rev + 2) = system_to_hex((rev_num & 0xF0) >> 4); |
| *(rev + 3) = system_to_hex(rev_num & 0x0F); |
| |
| return rev; |
| } |
| |
| /** |
| * Get/Set VbNvContext in non-volatile storage. The block should be 16 bytes |
| * long, which is the current size of VbNvContext block. |
| * |
| * @param block Pointer to a buffer holding VbNvContext. |
| * @return 0 on success, !0 on error. |
| */ |
| int system_get_vbnvcontext(uint8_t *block) |
| { |
| int i; |
| uint32_t *pblock = (uint32_t *) block; |
| for (i = 0; i < 4; i++) |
| pblock[i] = bbram_data_read(BBRM_DATA_INDEX_VBNVCNTXT + i*4); |
| |
| return EC_SUCCESS; |
| } |
| |
| int system_set_vbnvcontext(const uint8_t *block) |
| { |
| int i, result; |
| uint32_t *pblock = (uint32_t *) block; |
| for (i = 0; i < 4; i++) { |
| result = bbram_data_write(BBRM_DATA_INDEX_VBNVCNTXT + i*4, |
| pblock[i]); |
| if (result != EC_SUCCESS) |
| return result; |
| } |
| return EC_SUCCESS; |
| } |
| |
| /** |
| * 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); |
| } |
| |
| uint32_t system_get_scratchpad(void) |
| { |
| return bbram_data_read(BBRM_DATA_INDEX_SCRATCHPAD); |
| } |
| |
| /*****************************************************************************/ |
| /* Console commands */ |
| |
| static int command_system_rtc(int argc, char **argv) |
| { |
| uint32_t sec; |
| 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; |
| } |
| |
| sec = system_get_rtc_sec(); |
| ccprintf("RTC: 0x%08x (%d.00 s)\n", sec, sec); |
| |
| return EC_SUCCESS; |
| } |
| DECLARE_CONSOLE_COMMAND(rtc, command_system_rtc, |
| "[set <seconds>]", |
| "Get/set real-time clock", |
| NULL); |
| |
| #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", |
| NULL); |
| #endif /* CONFIG_CMD_RTC_ALARM */ |
| |
| /*****************************************************************************/ |
| /* Host commands */ |
| |
| static int 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 int 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)); |
| |
| /* For LPC host register initial via SIB module */ |
| void system_lpc_host_register_init(void){ |
| /* Setting PMC2 */ |
| /* LDN register = 0x12(PMC2) */ |
| system_sib_write_reg(SIO_OFFSET, 0x07, 0x12); |
| /* CMD port is 0x200 */ |
| system_sib_write_reg(SIO_OFFSET, 0x60, 0x02); |
| system_sib_write_reg(SIO_OFFSET, 0x61, 0x00); |
| /* Data port is 0x204 */ |
| system_sib_write_reg(SIO_OFFSET, 0x62, 0x02); |
| system_sib_write_reg(SIO_OFFSET, 0x63, 0x04); |
| /* enable PMC2 */ |
| system_sib_write_reg(SIO_OFFSET, 0x30, 0x01); |
| |
| /* Setting SHM */ |
| /* LDN register = 0x0F(SHM) */ |
| system_sib_write_reg(SIO_OFFSET, 0x07, 0x0F); |
| /* WIN1&2 mapping to IO */ |
| system_sib_write_reg(SIO_OFFSET, 0xF1, |
| system_sib_read_reg(SIO_OFFSET, 0xF1) | 0x30); |
| /* Host Command on the IO:0x0800 */ |
| system_sib_write_reg(SIO_OFFSET, 0xF7, 0x00); |
| system_sib_write_reg(SIO_OFFSET, 0xF6, 0x00); |
| system_sib_write_reg(SIO_OFFSET, 0xF5, 0x08); |
| system_sib_write_reg(SIO_OFFSET, 0xF4, 0x00); |
| /* WIN1 as Host Command on the IO:0x0800 */ |
| system_sib_write_reg(SIO_OFFSET, 0xFB, 0x00); |
| system_sib_write_reg(SIO_OFFSET, 0xFA, 0x00); |
| /* WIN2 as MEMMAP on the IO:0x900 */ |
| system_sib_write_reg(SIO_OFFSET, 0xF9, 0x09); |
| system_sib_write_reg(SIO_OFFSET, 0xF8, 0x00); |
| /* enable SHM */ |
| system_sib_write_reg(SIO_OFFSET, 0x30, 0x01); |
| } |
| #ifdef CONFIG_CODERAM_ARCH |
| uint32_t system_get_lfw_address(uint32_t flash_addr) |
| { |
| /* Little FW located on top of flash - 4K */ |
| uint32_t jump_addr = (CONFIG_FLASH_BASE + CONFIG_SPI_FLASH_SIZE |
| - CONFIG_LFW_OFFSET + 1); |
| /* restore base address for jumping*/ |
| base_addr = flash_addr; |
| return jump_addr; |
| } |
| |
| enum system_image_copy_t system_get_shrspi_image_copy(void) |
| { |
| /* RO region FW */ |
| if (IS_BIT_SET(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION)) |
| return SYSTEM_IMAGE_RO; |
| else/* RW region FW */ |
| return SYSTEM_IMAGE_RW; |
| } |
| |
| /** |
| * Set flag for jumping across a sysjump. |
| */ |
| static void system_sysjump(void) |
| { |
| /* Jump to RO region -- set flag */ |
| if (base_addr == CONFIG_FLASH_BASE + CONFIG_RO_MEM_OFF) |
| SET_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION); |
| else /* Jump to RW region -- clear flag */ |
| CLEAR_BIT(NPCX_FWCTRL, NPCX_FWCTRL_RO_REGION); |
| } |
| DECLARE_HOOK(HOOK_SYSJUMP, system_sysjump, HOOK_PRIO_DEFAULT); |
| #endif |