| /* Copyright 2016 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 "clock.h" |
| #include "common.h" |
| #include "console.h" |
| #include "cpu.h" |
| #include "gpio.h" |
| #include "hooks.h" |
| #include "host_command.h" |
| #include "interrupts.h" |
| #include "ish_fwst.h" |
| #include "ish_persistent_data.h" |
| #include "power_mgt.h" |
| #include "registers.h" |
| #include "shared_mem.h" |
| #include "spi.h" |
| #include "system.h" |
| #include "task.h" |
| #include "timer.h" |
| #include "util.h" |
| |
| #define CPUTS(outstr) cputs(CC_SYSTEM, outstr) |
| #define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args) |
| #define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args) |
| |
| int system_is_reboot_warm(void) |
| { |
| return !(system_get_reset_flags() & |
| (EC_RESET_FLAG_POWER_ON | EC_RESET_FLAG_HARD)); |
| } |
| |
| void system_pre_init(void) |
| { |
| ish_fwst_set_fw_status(FWSTS_FW_IS_RUNNING); |
| if (IS_ENABLED(CONFIG_ISH_CLEAR_FABRIC_ERRORS)) |
| task_enable_irq(ISH_FABRIC_IRQ); |
| ish_pm_init(); |
| ish_persistent_data_init(); |
| } |
| |
| void chip_save_reset_flags(uint32_t flags) |
| { |
| ish_persistent_data.reset_flags = flags; |
| } |
| |
| uint32_t chip_read_reset_flags(void) |
| { |
| return ish_persistent_data.reset_flags; |
| } |
| |
| /* |
| * Kill the Minute-IA core and don't come back alive. |
| * |
| * Used when the watchdog timer exceeds max retries and we want to |
| * disable ISH completely. |
| */ |
| noreturn |
| static void system_halt(void) |
| { |
| cflush(); |
| |
| while (1) { |
| disable_all_interrupts(); |
| WDT_CONTROL = 0; |
| CCU_TCG_EN = 1; |
| __asm__ volatile ( |
| "cli\n" |
| "hlt\n"); |
| } |
| } |
| |
| void system_reset(int flags) |
| { |
| uint32_t save_flags; |
| |
| /* |
| * We can't save any data when we do an ish_mia_reset(). Take |
| * the quick path out. |
| */ |
| if (!IS_ENABLED(CONFIG_ISH_PM_AONTASK) || flags & SYSTEM_RESET_HARD) { |
| ish_mia_reset(); |
| __builtin_unreachable(); |
| } |
| |
| system_encode_save_flags(flags, &save_flags); |
| |
| if (flags & SYSTEM_RESET_AP_WATCHDOG) { |
| save_flags |= EC_RESET_FLAG_WATCHDOG; |
| ish_persistent_data.watchdog_counter += 1; |
| if (ish_persistent_data.watchdog_counter |
| >= CONFIG_WATCHDOG_MAX_RETRIES) { |
| CPRINTS("Halting ISH due to max watchdog resets"); |
| system_halt(); |
| } |
| } |
| |
| chip_save_reset_flags(save_flags); |
| |
| ish_persistent_data_commit(); |
| ish_pm_reset(ISH_PM_STATE_RESET); |
| __builtin_unreachable(); |
| } |
| |
| const char *system_get_chip_vendor(void) |
| { |
| return "intel"; |
| } |
| |
| const char *system_get_chip_name(void) |
| { |
| return "intel"; |
| } |
| |
| static char to_hex(int x) |
| { |
| if (x >= 0 && x <= 9) |
| return '0' + x; |
| return 'a' + x - 10; |
| } |
| |
| const char *system_get_chip_revision(void) |
| { |
| static char buf[3]; |
| uint8_t rev = 0x86; |
| |
| buf[0] = to_hex(rev / 16); |
| buf[1] = to_hex(rev & 0xf); |
| buf[2] = '\0'; |
| return buf; |
| } |
| |
| int system_get_bbram(enum system_bbram_idx idx, uint8_t *value) |
| { |
| return EC_ERROR_UNIMPLEMENTED; |
| } |
| |
| int system_set_bbram(enum system_bbram_idx idx, uint8_t value) |
| { |
| return EC_ERROR_UNIMPLEMENTED; |
| } |
| |
| int system_set_scratchpad(uint32_t value) |
| { |
| return EC_SUCCESS; |
| } |
| |
| uint32_t system_get_scratchpad(void) |
| { |
| return 0; |
| } |
| |
| void system_hibernate(uint32_t seconds, uint32_t microseconds) |
| { |
| } |
| |
| void htimer_interrupt(void) |
| { |
| /* Time to wake up */ |
| } |
| |
| enum ec_image system_get_shrspi_image_copy(void) |
| { |
| return 0; |
| } |
| |
| uint32_t system_get_lfw_address(void) |
| { |
| return 0; |
| } |
| |
| void system_set_image_copy(enum ec_image copy) |
| { |
| } |
| |
| #define HBW_FABRIC_BASE 0x10000000 |
| #define PER0_FABRIC_BASE 0x04000000 |
| #define AGENT_STS 0x28 |
| #define ERROR_LOG 0x58 |
| |
| static uint16_t hbw_ia_offset[] = { |
| 0x1000, |
| 0x3400, |
| 0x3800, |
| 0x5000, |
| 0x5800, |
| 0x6000 |
| }; |
| |
| static inline void clear_register(uint32_t reg) |
| { |
| REG32(reg) = REG32(reg); |
| } |
| |
| void clear_fabric_error(void) |
| { |
| unsigned int i; |
| |
| for (i = 0; i < ARRAY_SIZE(hbw_ia_offset); i++) { |
| clear_register(HBW_FABRIC_BASE + hbw_ia_offset[i] + AGENT_STS); |
| clear_register(HBW_FABRIC_BASE + hbw_ia_offset[i] + ERROR_LOG); |
| } |
| clear_register(PER0_FABRIC_BASE + 0x1000 + AGENT_STS); |
| clear_register(PER0_FABRIC_BASE + 0x1000 + ERROR_LOG); |
| } |
| |
| static __maybe_unused void fabric_isr(void) |
| { |
| /** |
| * clear fabric error status, otherwise it will wakeup ISH immediately |
| * when entered low power mode. |
| * TODO(b:130740646): figure out why this issue happens. |
| */ |
| if (FABRIC_AGENT_STATUS & FABRIC_MIA_STATUS_BIT_ERR) |
| FABRIC_AGENT_STATUS = FABRIC_AGENT_STATUS; |
| } |
| #ifdef CONFIG_ISH_CLEAR_FABRIC_ERRORS |
| DECLARE_IRQ(ISH_FABRIC_IRQ, fabric_isr); |
| #endif |