coreboot-libre-fam15h-rdimm/3rdparty/chromeec/chip/it83xx/system.c

333 lines
8.0 KiB
C

/* Copyright 2013 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 : hardware specific implementation */
#include "console.h"
#include "cpu.h"
#include "ec2i_chip.h"
#include "flash.h"
#include "hooks.h"
#include "host_command.h"
#include "intc.h"
#include "registers.h"
#include "system.h"
#include "task.h"
#include "util.h"
#include "version.h"
#include "watchdog.h"
void system_hibernate(uint32_t seconds, uint32_t microseconds)
{
#ifdef CONFIG_HOSTCMD_PD
/* Inform the PD MCU that we are going to hibernate. */
host_command_pd_request_hibernate();
/* Wait to ensure exchange with PD before hibernating. */
msleep(100);
#endif
/* Flush console before hibernating */
cflush();
if (board_hibernate)
board_hibernate();
/* chip specific standby mode */
__enter_hibernate(seconds, microseconds);
}
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;
/* Restore saved reset flags. */
flags |= BRAM_RESET_FLAGS0 << 24;
flags |= BRAM_RESET_FLAGS1 << 16;
flags |= BRAM_RESET_FLAGS2 << 8;
flags |= BRAM_RESET_FLAGS3;
/* Clear reset cause. */
IT83XX_GCTRL_RSTS |= 0x03;
IT83XX_GCTRL_SPCTRL4 |= 0x07;
/* Determine if watchdog reset or power on reset. */
if (raw_reset_cause & 0x02) {
flags |= EC_RESET_FLAG_WATCHDOG;
} else if (raw_reset_cause & 0x01) {
flags |= EC_RESET_FLAG_POWER_ON;
} else {
if ((IT83XX_GCTRL_RSTS & 0xC0) == 0x80)
flags |= EC_RESET_FLAG_POWER_ON;
}
if (raw_reset_cause2 & 0x04)
flags |= EC_RESET_FLAG_RESET_PIN;
/* watchdog module triggers these reset */
if (flags & (EC_RESET_FLAG_HARD | EC_RESET_FLAG_SOFT))
flags &= ~EC_RESET_FLAG_WATCHDOG;
/* Clear saved reset flags. */
BRAM_RESET_FLAGS0 = 0;
BRAM_RESET_FLAGS1 = 0;
BRAM_RESET_FLAGS2 = 0;
BRAM_RESET_FLAGS3 = 0;
system_set_reset_flags(flags);
}
static void system_reset_cause_is_unknown(void)
{
/* No reset cause and not sysjump. */
if (!system_get_reset_flags() && !system_jumped_to_this_image())
/*
* We decrease 4 or 2 for "ec_reset_lp" here, that depend on
* which jump and link instruction has executed.
* eg: Andes core (jral5: LP=PC+2, jal: LP=PC+4)
*/
ccprintf("===Unknown reset! jump from %x or %x===\n",
ec_reset_lp - 4, ec_reset_lp - 2);
}
DECLARE_HOOK(HOOK_INIT, system_reset_cause_is_unknown, HOOK_PRIO_FIRST);
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;
}
void chip_pre_init(void)
{
/* bit4, enable debug mode through SMBus */
IT83XX_SMB_SLVISELR &= ~BIT(4);
}
#define BRAM_VALID_MAGIC 0x4252414D /* "BRAM" */
#define BRAM_VALID_MAGIC_FIELD0 (BRAM_VALID_MAGIC & 0xff)
#define BRAM_VALID_MAGIC_FIELD1 ((BRAM_VALID_MAGIC >> 8) & 0xff)
#define BRAM_VALID_MAGIC_FIELD2 ((BRAM_VALID_MAGIC >> 16) & 0xff)
#define BRAM_VALID_MAGIC_FIELD3 ((BRAM_VALID_MAGIC >> 24) & 0xff)
void chip_bram_valid(void)
{
int i;
if ((BRAM_VALID_FLAGS0 != BRAM_VALID_MAGIC_FIELD0) ||
(BRAM_VALID_FLAGS1 != BRAM_VALID_MAGIC_FIELD1) ||
(BRAM_VALID_FLAGS2 != BRAM_VALID_MAGIC_FIELD2) ||
(BRAM_VALID_FLAGS3 != BRAM_VALID_MAGIC_FIELD3)) {
/*
* Magic does not match, so BRAM must be uninitialized. Clear
* entire Bank0 BRAM, and set magic value.
*/
for (i = 0; i < BRAM_IDX_VALID_FLAGS0; i++)
IT83XX_BRAM_BANK0(i) = 0;
BRAM_VALID_FLAGS0 = BRAM_VALID_MAGIC_FIELD0;
BRAM_VALID_FLAGS1 = BRAM_VALID_MAGIC_FIELD1;
BRAM_VALID_FLAGS2 = BRAM_VALID_MAGIC_FIELD2;
BRAM_VALID_FLAGS3 = BRAM_VALID_MAGIC_FIELD3;
}
}
void system_pre_init(void)
{
/* No initialization required */
}
void system_reset(int flags)
{
uint32_t save_flags = 0;
/* Disable interrupts to avoid task swaps during reboot. */
interrupt_disable();
/* Handle saving common reset flags. */
system_encode_save_flags(flags, &save_flags);
if (clock_ec_wake_from_sleep())
save_flags |= EC_RESET_FLAG_HIBERNATE;
/* Store flags to battery backed RAM. */
BRAM_RESET_FLAGS0 = save_flags >> 24;
BRAM_RESET_FLAGS1 = (save_flags >> 16) & 0xff;
BRAM_RESET_FLAGS2 = (save_flags >> 8) & 0xff;
BRAM_RESET_FLAGS3 = save_flags & 0xff;
/* 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);
}
}
/*
* bit4, disable debug mode through SMBus.
* If we are in debug mode, we need disable it before triggering
* a soft reset or reset will fail.
*/
IT83XX_SMB_SLVISELR |= BIT(4);
/* bit0: enable watchdog hardware reset. */
#ifdef IT83XX_ETWD_HW_RESET_SUPPORT
if (flags & SYSTEM_RESET_HARD)
IT83XX_GCTRL_ETWDUARTCR |= BIT(0);
#endif
/*
* Writing invalid key to watchdog module triggers a soft or hardware
* reset. It depends on the setting of bit0 at ETWDUARTCR register.
*/
IT83XX_ETWD_ETWCFG |= 0x20;
IT83XX_ETWD_EWDKEYR = 0x00;
/* Spin and wait for reboot; should never return */
while (1)
;
}
int system_set_scratchpad(uint32_t value)
{
BRAM_SCRATCHPAD3 = (value >> 24) & 0xff;
BRAM_SCRATCHPAD2 = (value >> 16) & 0xff;
BRAM_SCRATCHPAD1 = (value >> 8) & 0xff;
BRAM_SCRATCHPAD0 = value & 0xff;
return EC_SUCCESS;
}
uint32_t system_get_scratchpad(void)
{
uint32_t value = 0;
value |= BRAM_SCRATCHPAD3 << 24;
value |= BRAM_SCRATCHPAD2 << 16;
value |= BRAM_SCRATCHPAD1 << 8;
value |= BRAM_SCRATCHPAD0;
return value;
}
static uint32_t system_get_chip_id(void)
{
#ifdef IT83XX_CHIP_ID_3BYTES
return (IT83XX_GCTRL_CHIPID1 << 16) | (IT83XX_GCTRL_CHIPID2 << 8) |
IT83XX_GCTRL_CHIPID3;
#else
return (IT83XX_GCTRL_CHIPID1 << 8) | IT83XX_GCTRL_CHIPID2;
#endif
}
static uint8_t system_get_chip_version(void)
{
/* bit[3-0], chip version */
return IT83XX_GCTRL_CHIPVER & 0x0F;
}
static char to_hex(int x)
{
if (x >= 0 && x <= 9)
return '0' + x;
return 'a' + x - 10;
}
const char *system_get_chip_vendor(void)
{
return "ite";
}
const char *system_get_chip_name(void)
{
static char buf[8] = {'i', 't'};
int num = (IS_ENABLED(IT83XX_CHIP_ID_3BYTES) ? 4 : 3);
uint32_t chip_id = system_get_chip_id();
for (int n = 2; num >= 0; n++, num--)
buf[n] = to_hex(chip_id >> (num * 4) & 0xF);
return buf;
}
const char *system_get_chip_revision(void)
{
static char buf[3];
uint8_t rev = system_get_chip_version();
buf[0] = to_hex(rev + 0xa);
buf[1] = 'x';
buf[2] = '\0';
return buf;
}
static int bram_idx_lookup(enum system_bbram_idx idx)
{
if (idx >= SYSTEM_BBRAM_IDX_VBNVBLOCK0 &&
idx <= SYSTEM_BBRAM_IDX_VBNVBLOCK15)
return BRAM_IDX_NVCONTEXT +
idx - SYSTEM_BBRAM_IDX_VBNVBLOCK0;
if (idx == SYSTEM_BBRAM_IDX_PD0)
return BRAM_IDX_PD0;
if (idx == SYSTEM_BBRAM_IDX_PD1)
return BRAM_IDX_PD1;
if (idx == SYSTEM_BBRAM_IDX_PD2)
return BRAM_IDX_PD2;
return -1;
}
int system_get_bbram(enum system_bbram_idx idx, uint8_t *value)
{
int bram_idx = bram_idx_lookup(idx);
if (bram_idx < 0)
return EC_ERROR_INVAL;
*value = IT83XX_BRAM_BANK0(bram_idx);
return EC_SUCCESS;
}
int system_set_bbram(enum system_bbram_idx idx, uint8_t value)
{
int bram_idx = bram_idx_lookup(idx);
if (bram_idx < 0)
return EC_ERROR_INVAL;
IT83XX_BRAM_BANK0(bram_idx) = value;
return EC_SUCCESS;
}
#define BRAM_NVCONTEXT_SIZE (BRAM_IDX_NVCONTEXT_END - BRAM_IDX_NVCONTEXT + 1)
BUILD_ASSERT(EC_VBNV_BLOCK_SIZE <= BRAM_NVCONTEXT_SIZE);
uintptr_t system_get_fw_reset_vector(uintptr_t base)
{
/*
* Because our reset vector is at the beginning of image copy
* (see init.S). So I just need to return 'base' here and EC will jump
* to the reset vector.
*/
return base;
}