mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-03 21:49:32 +00:00
Nothing has used this config option since Spring and Skate, back in early 2014. There's nothing in ToT that uses it at all. I want to add something similar for other purposes, and having two similar-sounding options will just cause confusion. NOTE: Although the comments in include/system.h said that the two functions system_get_console_force_enabled() system_set_console_force_enabled() were only useful when CONFIG_CONSOLE_RESTRICTED_INPUT is defined, they were being used in chip/stm32/system.c. But since the bkpdata registers are only accessible to the EC, there was no way to initialize or modify the one relevant bit that those functions cared about, so they almost certainly had no effect. BUG=chrome-os-partner:55322 BRANCH=none TEST=make buildall Change-Id: Id41541193d4559f5c507bdd0268b049166af4497 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/374525
386 lines
9.9 KiB
C
386 lines
9.9 KiB
C
/* Copyright (c) 2012 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 "clock.h"
|
|
#include "console.h"
|
|
#include "cpu.h"
|
|
#include "flash.h"
|
|
#include "host_command.h"
|
|
#include "registers.h"
|
|
#include "panic.h"
|
|
#include "system.h"
|
|
#include "task.h"
|
|
#include "util.h"
|
|
#include "version.h"
|
|
#include "watchdog.h"
|
|
|
|
enum bkpdata_index {
|
|
BKPDATA_INDEX_SCRATCHPAD, /* General-purpose scratchpad */
|
|
BKPDATA_INDEX_SAVED_RESET_FLAGS, /* Saved reset flags */
|
|
BKPDATA_INDEX_VBNV_CONTEXT0,
|
|
BKPDATA_INDEX_VBNV_CONTEXT1,
|
|
BKPDATA_INDEX_VBNV_CONTEXT2,
|
|
BKPDATA_INDEX_VBNV_CONTEXT3,
|
|
BKPDATA_INDEX_VBNV_CONTEXT4,
|
|
BKPDATA_INDEX_VBNV_CONTEXT5,
|
|
BKPDATA_INDEX_VBNV_CONTEXT6,
|
|
BKPDATA_INDEX_VBNV_CONTEXT7,
|
|
#ifdef CONFIG_SOFTWARE_PANIC
|
|
BKPDATA_INDEX_SAVED_PANIC_REASON, /* Saved panic reason */
|
|
BKPDATA_INDEX_SAVED_PANIC_INFO, /* Saved panic data */
|
|
BKPDATA_INDEX_SAVED_PANIC_EXCEPTION, /* Saved panic exception code */
|
|
#endif
|
|
};
|
|
|
|
/**
|
|
* Read backup register at specified index.
|
|
*
|
|
* @return The value of the register or 0 if invalid index.
|
|
*/
|
|
static uint16_t bkpdata_read(enum bkpdata_index index)
|
|
{
|
|
if (index < 0 || index >= STM32_BKP_ENTRIES)
|
|
return 0;
|
|
|
|
#if defined(CHIP_FAMILY_STM32L) || defined(CHIP_FAMILY_STM32F0) || \
|
|
defined(CHIP_FAMILY_STM32F3)
|
|
if (index & 1)
|
|
return STM32_BKP_DATA(index >> 1) >> 16;
|
|
else
|
|
return STM32_BKP_DATA(index >> 1) & 0xFFFF;
|
|
#else
|
|
return STM32_BKP_DATA(index);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Write hibernate register at specified index.
|
|
*
|
|
* @return nonzero if error.
|
|
*/
|
|
static int bkpdata_write(enum bkpdata_index index, uint16_t value)
|
|
{
|
|
if (index < 0 || index >= STM32_BKP_ENTRIES)
|
|
return EC_ERROR_INVAL;
|
|
|
|
#if defined(CHIP_FAMILY_STM32L) || defined(CHIP_FAMILY_STM32F0) || \
|
|
defined(CHIP_FAMILY_STM32F3)
|
|
if (index & 1) {
|
|
uint32_t val = STM32_BKP_DATA(index >> 1);
|
|
val = (val & 0x0000FFFF) | (value << 16);
|
|
STM32_BKP_DATA(index >> 1) = val;
|
|
} else {
|
|
uint32_t val = STM32_BKP_DATA(index >> 1);
|
|
val = (val & 0xFFFF0000) | value;
|
|
STM32_BKP_DATA(index >> 1) = val;
|
|
}
|
|
#else
|
|
STM32_BKP_DATA(index) = value;
|
|
#endif
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
void __no_hibernate(uint32_t seconds, uint32_t microseconds)
|
|
{
|
|
#ifdef CONFIG_COMMON_RUNTIME
|
|
/*
|
|
* Hibernate not implemented on this platform.
|
|
*
|
|
* Until then, treat this as a request to hard-reboot.
|
|
*/
|
|
cprints(CC_SYSTEM, "hibernate not supported, so rebooting");
|
|
cflush();
|
|
system_reset(SYSTEM_RESET_HARD);
|
|
#endif
|
|
}
|
|
|
|
void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
|
|
__attribute__((weak, alias("__no_hibernate")));
|
|
|
|
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 = bkpdata_read(BKPDATA_INDEX_SAVED_RESET_FLAGS);
|
|
uint32_t raw_cause = STM32_RCC_CSR;
|
|
uint32_t pwr_status = STM32_PWR_CSR;
|
|
|
|
/* Clear the hardware reset cause by setting the RMVF bit */
|
|
STM32_RCC_CSR |= 1 << 24;
|
|
/* Clear SBF in PWR_CSR */
|
|
STM32_PWR_CR |= 1 << 3;
|
|
/* Clear saved reset flags */
|
|
bkpdata_write(BKPDATA_INDEX_SAVED_RESET_FLAGS, 0);
|
|
|
|
if (raw_cause & 0x60000000) {
|
|
/*
|
|
* IWDG or WWDG, if the watchdog was not used as an hard reset
|
|
* mechanism
|
|
*/
|
|
if (!(flags & RESET_FLAG_HARD))
|
|
flags |= RESET_FLAG_WATCHDOG;
|
|
}
|
|
|
|
if (raw_cause & 0x10000000)
|
|
flags |= RESET_FLAG_SOFT;
|
|
|
|
if (raw_cause & 0x08000000)
|
|
flags |= RESET_FLAG_POWER_ON;
|
|
|
|
if (raw_cause & 0x04000000)
|
|
flags |= RESET_FLAG_RESET_PIN;
|
|
|
|
if (pwr_status & 0x00000002)
|
|
/* Hibernated and subsequently awakened */
|
|
flags |= RESET_FLAG_HIBERNATE;
|
|
|
|
if (!flags && (raw_cause & 0xfe000000))
|
|
flags |= RESET_FLAG_OTHER;
|
|
|
|
/*
|
|
* WORKAROUND: as we cannot de-activate the watchdog during
|
|
* long hibernation, we are woken-up once by the watchdog and
|
|
* go back to hibernate if we detect that condition, without
|
|
* watchdog initialized this time.
|
|
* The RTC deadline (if any) is already set.
|
|
*/
|
|
if ((flags & (RESET_FLAG_HIBERNATE | RESET_FLAG_WATCHDOG)) ==
|
|
(RESET_FLAG_HIBERNATE | RESET_FLAG_WATCHDOG)) {
|
|
__enter_hibernate(0, 0);
|
|
}
|
|
|
|
system_set_reset_flags(flags);
|
|
}
|
|
|
|
void system_pre_init(void)
|
|
{
|
|
#ifdef CONFIG_SOFTWARE_PANIC
|
|
uint16_t reason, info;
|
|
uint8_t exception;
|
|
#endif
|
|
|
|
/* enable clock on Power module */
|
|
STM32_RCC_APB1ENR |= STM32_RCC_PWREN;
|
|
#if defined(CHIP_FAMILY_STM32F4)
|
|
/* enable backup registers */
|
|
STM32_RCC_AHB1ENR |= STM32_RCC_AHB1ENR_BKPSRAMEN;
|
|
#else
|
|
/* enable backup registers */
|
|
STM32_RCC_APB1ENR |= 1 << 27;
|
|
#endif
|
|
/* Delay 1 APB clock cycle after the clock is enabled */
|
|
clock_wait_bus_cycles(BUS_APB, 1);
|
|
/* Enable access to RCC CSR register and RTC backup registers */
|
|
STM32_PWR_CR |= 1 << 8;
|
|
#ifdef CHIP_FAMILY_STM32L4
|
|
/* Enable Vddio2 */
|
|
STM32_PWR_CR2 |= 1 << 9;
|
|
#endif
|
|
|
|
/* switch on LSI */
|
|
STM32_RCC_CSR |= 1 << 0;
|
|
/* Wait for LSI to be ready */
|
|
while (!(STM32_RCC_CSR & (1 << 1)))
|
|
;
|
|
/* re-configure RTC if needed */
|
|
#ifdef CHIP_FAMILY_STM32L
|
|
if ((STM32_RCC_CSR & 0x00C30000) != 0x00420000) {
|
|
/* the RTC settings are bad, we need to reset it */
|
|
STM32_RCC_CSR |= 0x00800000;
|
|
/* Enable RTC and use LSI as clock source */
|
|
STM32_RCC_CSR = (STM32_RCC_CSR & ~0x00C30000) | 0x00420000;
|
|
}
|
|
#elif defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3) || \
|
|
defined(CHIP_FAMILY_STM32L4) || defined(CHIP_FAMILY_STM32F4)
|
|
if ((STM32_RCC_BDCR & 0x00018300) != 0x00008200) {
|
|
/* the RTC settings are bad, we need to reset it */
|
|
STM32_RCC_BDCR |= 0x00010000;
|
|
/* Enable RTC and use LSI as clock source */
|
|
STM32_RCC_BDCR = (STM32_RCC_BDCR & ~0x00018300) | 0x00008200;
|
|
}
|
|
#else
|
|
#error "Unsupported chip family"
|
|
#endif
|
|
|
|
check_reset_cause();
|
|
|
|
#ifdef CONFIG_SOFTWARE_PANIC
|
|
/* Restore then clear saved panic reason */
|
|
reason = bkpdata_read(BKPDATA_INDEX_SAVED_PANIC_REASON);
|
|
info = bkpdata_read(BKPDATA_INDEX_SAVED_PANIC_INFO);
|
|
exception = bkpdata_read(BKPDATA_INDEX_SAVED_PANIC_EXCEPTION);
|
|
if (reason || info || exception) {
|
|
panic_set_reason(reason, info, exception);
|
|
bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_REASON, 0);
|
|
bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_INFO, 0);
|
|
bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_EXCEPTION, 0);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
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;
|
|
|
|
if (flags & SYSTEM_RESET_LEAVE_AP_OFF)
|
|
save_flags |= RESET_FLAG_AP_OFF;
|
|
|
|
/* Remember that the software asked us to hard reboot */
|
|
if (flags & SYSTEM_RESET_HARD)
|
|
save_flags |= RESET_FLAG_HARD;
|
|
|
|
bkpdata_write(BKPDATA_INDEX_SAVED_RESET_FLAGS, save_flags);
|
|
|
|
if (flags & SYSTEM_RESET_HARD) {
|
|
#ifdef CONFIG_SOFTWARE_PANIC
|
|
uint32_t reason, info;
|
|
uint8_t exception;
|
|
|
|
/* Panic data will be wiped by hard reset, so save it */
|
|
panic_get_reason(&reason, &info, &exception);
|
|
/* 16 bits stored - upper 16 bits of reason / info are lost */
|
|
bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_REASON, reason);
|
|
bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_INFO, info);
|
|
bkpdata_write(BKPDATA_INDEX_SAVED_PANIC_EXCEPTION, exception);
|
|
#endif
|
|
|
|
#ifdef CHIP_FAMILY_STM32L
|
|
/*
|
|
* Ask the flash module to reboot, so that we reload the
|
|
* option bytes.
|
|
*/
|
|
flash_physical_force_reload();
|
|
|
|
/* Fall through to watchdog if that fails */
|
|
#endif
|
|
|
|
#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3)
|
|
/*
|
|
* On some chips, a reboot doesn't always reload the option
|
|
* bytes, and we need to explicitly request for a reload.
|
|
* The reload request triggers a chip reset, so let's just
|
|
* use this for hard reset.
|
|
*/
|
|
STM32_FLASH_CR |= STM32_FLASH_CR_OBL_LAUNCH;
|
|
#else
|
|
/* Ask the watchdog to trigger a hard reboot */
|
|
STM32_IWDG_KR = 0x5555;
|
|
STM32_IWDG_RLR = 0x1;
|
|
STM32_IWDG_KR = 0xcccc;
|
|
#endif
|
|
/* wait for the chip to reboot */
|
|
while (1)
|
|
;
|
|
} else {
|
|
CPU_NVIC_APINT = 0x05fa0004;
|
|
}
|
|
|
|
/* Spin and wait for reboot; should never return */
|
|
while (1)
|
|
;
|
|
}
|
|
|
|
int system_set_scratchpad(uint32_t value)
|
|
{
|
|
/* Check if value fits in 16 bits */
|
|
if (value & 0xffff0000)
|
|
return EC_ERROR_INVAL;
|
|
return bkpdata_write(BKPDATA_INDEX_SCRATCHPAD, (uint16_t)value);
|
|
}
|
|
|
|
uint32_t system_get_scratchpad(void)
|
|
{
|
|
return (uint32_t)bkpdata_read(BKPDATA_INDEX_SCRATCHPAD);
|
|
}
|
|
|
|
const char *system_get_chip_vendor(void)
|
|
{
|
|
return "stm";
|
|
}
|
|
|
|
const char *system_get_chip_name(void)
|
|
{
|
|
return STRINGIFY(CHIP_VARIANT);
|
|
}
|
|
|
|
const char *system_get_chip_revision(void)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
int system_get_vbnvcontext(uint8_t *block)
|
|
{
|
|
enum bkpdata_index i;
|
|
uint16_t value;
|
|
|
|
for (i = BKPDATA_INDEX_VBNV_CONTEXT0;
|
|
i <= BKPDATA_INDEX_VBNV_CONTEXT7; i++) {
|
|
value = bkpdata_read(i);
|
|
*block++ = (uint8_t)(value & 0xff);
|
|
*block++ = (uint8_t)(value >> 8);
|
|
}
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
int system_set_vbnvcontext(const uint8_t *block)
|
|
{
|
|
enum bkpdata_index i;
|
|
uint16_t value;
|
|
int err;
|
|
|
|
for (i = BKPDATA_INDEX_VBNV_CONTEXT0;
|
|
i <= BKPDATA_INDEX_VBNV_CONTEXT7; i++) {
|
|
value = *block++;
|
|
value |= ((uint16_t)*block++) << 8;
|
|
err = bkpdata_write(i, value);
|
|
if (err)
|
|
return err;
|
|
}
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
int system_is_reboot_warm(void)
|
|
{
|
|
#if defined(CHIP_FAMILY_STM32F0) || defined(CHIP_FAMILY_STM32F3)
|
|
return ((STM32_RCC_AHBENR & 0x7e0000) == 0x7e0000);
|
|
#elif defined(CHIP_FAMILY_STM32L)
|
|
return ((STM32_RCC_AHBENR & 0x3f) == 0x3f);
|
|
#elif defined(CHIP_FAMILY_STM32L4)
|
|
return ((STM32_RCC_AHB2ENR & STM32_RCC_AHB2ENR_GPIOMASK)
|
|
== STM32_RCC_AHB2ENR_GPIOMASK);
|
|
#elif defined(CHIP_FAMILY_STM32F4)
|
|
return ((STM32_RCC_AHB1ENR & STM32_RCC_AHB1ENR_GPIOMASK)
|
|
== STM32_RCC_AHB1ENR_GPIOMASK);
|
|
#endif
|
|
}
|