From 84dc68283e8e6d7ed655101f09357f71bae6a202 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Thu, 26 Jan 2012 22:25:38 +0000 Subject: [PATCH] Split reset cause and image copy code. Preparatory work to introduce a second SoC : 3rd series 2/2 All the RO/A/B firmware copy code could be generic to all our platforms. The console commands are a 'standard' API. Signed-off-by: Vincent Palatin BUG=None TEST=on BDS EC console, check the reset cause with the 'sysinfo' command. Change-Id: Ieeb84571085d88b5747a09da4c33d3852bb0da96 --- chip/lm4/system.c | 203 ++------------------------------------------- common/build.mk | 2 +- common/system.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++ include/system.h | 3 + 4 files changed, 216 insertions(+), 199 deletions(-) create mode 100644 common/system.c diff --git a/chip/lm4/system.c b/chip/lm4/system.c index 30e2f87b8f..fa17eccbaf 100644 --- a/chip/lm4/system.c +++ b/chip/lm4/system.c @@ -1,32 +1,13 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* 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 */ +/* System module for Chrome EC : hardware specific implementation */ -#include "console.h" #include "cpu.h" #include "registers.h" #include "system.h" -#include "uart.h" -#include "util.h" -#include "version.h" - -struct version_struct { - uint32_t cookie1; - char version[32]; - uint32_t cookie2; -} __attribute__ ((packed)); - -static const struct version_struct version_data = { - 0xce112233, - CROS_EC_VERSION_STRING, - 0xce445566 -}; - -static uint32_t raw_reset_cause = 0; -static enum system_reset_cause_t reset_cause = SYSTEM_RESET_UNKNOWN; static int wait_for_hibctl_wc(void) @@ -45,6 +26,8 @@ static void check_reset_cause(void) { enum system_image_copy_t copy = system_get_image_copy(); uint32_t hib_status = LM4_HIBERNATE_HIBRIS; + enum system_reset_cause_t reset_cause = SYSTEM_RESET_UNKNOWN; + uint32_t raw_reset_cause; /* Read the raw reset cause */ raw_reset_cause = LM4_SYSTEM_RESC; @@ -80,6 +63,7 @@ static void check_reset_cause(void) } else { reset_cause = SYSTEM_RESET_UNKNOWN; } + system_set_reset_cause(reset_cause); } @@ -152,85 +136,6 @@ int system_init(void) } -enum system_reset_cause_t system_get_reset_cause(void) -{ - return reset_cause; -} - - -const char *system_get_reset_cause_string(void) -{ - static const char * const cause_descs[] = { - "unknown", "other", "brownout", "power-on", "reset pin", - "soft cold", "soft warm", "watchdog", "rtc alarm", "wake pin", - "low battery"}; - - return reset_cause < ARRAY_SIZE(cause_descs) ? - cause_descs[reset_cause] : "?"; -} - - -enum system_image_copy_t system_get_image_copy(void) -{ - int copy = (uint32_t)system_get_image_copy / CONFIG_FW_IMAGE_SIZE; - switch (copy) { - case 0: - return SYSTEM_IMAGE_RO; - case 1: - return SYSTEM_IMAGE_RW_A; - case 2: - return SYSTEM_IMAGE_RW_B; - default: - return SYSTEM_IMAGE_UNKNOWN; - } -} - - -const char *system_get_image_copy_string(void) -{ - static const char * const copy_descs[] = {"unknown", "RO", "A", "B"}; - int copy = system_get_image_copy(); - return copy < ARRAY_SIZE(copy_descs) ? copy_descs[copy] : "?"; -} - - -int system_run_image_copy(enum system_image_copy_t copy) -{ - uint32_t init_addr; - void (*resetvec)(void); - - /* Fail if we're not in RO firmware */ - if (system_get_image_copy() != SYSTEM_IMAGE_RO) - return EC_ERROR_UNKNOWN; - - /* Load the appropriate reset vector */ - if (copy == SYSTEM_IMAGE_RW_A) - init_addr = *(uint32_t *)(CONFIG_FW_A_OFF + 4); - else if (copy == SYSTEM_IMAGE_RW_B) - init_addr = *(uint32_t *)(CONFIG_FW_B_OFF + 4); - else - return EC_ERROR_UNKNOWN; - - /* TODO: sanity checks (crosbug.com/p/7468) - * - * Fail if called outside of pre-init. - * - * Fail if reboot reason is not soft reboot. Power-on - * reset cause must run RO firmware; if it wants to move to RW - * firmware, it must go through a soft reboot first - * - * Sanity check reset vector; must be inside the appropriate - * image. */ - - /* Jump to the reset vector */ - resetvec = (void(*)(void))init_addr; - resetvec(); - - /* Should never get here */ - return EC_ERROR_UNIMPLEMENTED; -} - - int system_reset(int is_cold) { /* TODO: (crosbug.com/p/7470) support cold boot; this is a @@ -271,101 +176,3 @@ uint32_t system_get_scratchpad(void) { return LM4_HIBERNATE_HIBDATA; } - - -const char *system_get_version(enum system_image_copy_t copy) -{ - int imoffset; - const uint32_t *p, *pend; - const struct version_struct *v; - - /* Handle version of current image */ - if (copy == system_get_image_copy() || copy == SYSTEM_IMAGE_UNKNOWN) - return version_data.version; - - switch (copy) { - case SYSTEM_IMAGE_RO: - imoffset = CONFIG_FW_RO_OFF; - break; - case SYSTEM_IMAGE_RW_A: - imoffset = CONFIG_FW_A_OFF; - break; - case SYSTEM_IMAGE_RW_B: - imoffset = CONFIG_FW_B_OFF; - break; - default: - return ""; - } - - /* Search for version cookies in target image */ - /* TODO: (crosbug.com/p/7469) could be smarter about where to - * search if we stuffed the version data into a predefined - * area of the image - for example, immediately following the - * reset vectors. */ - pend = (uint32_t *)(imoffset + CONFIG_FW_IMAGE_SIZE - - sizeof(version_data)); - for (p = (uint32_t *)imoffset; p <= pend; p++) { - v = (const struct version_struct *)p; - if (v->cookie1 == version_data.cookie1 && - v->cookie2 == version_data.cookie2) - return v->version; - } - - return ""; -} - - -static int command_sysinfo(int argc, char **argv) -{ - uart_printf("Reset cause: %d (%s)\n", - system_get_reset_cause(), - system_get_reset_cause_string()); - uart_printf("Raw reset cause: 0x%x\n", raw_reset_cause); - uart_printf("Scratchpad: 0x%08x\n", system_get_scratchpad()); - uart_printf("Firmware copy: %s\n", system_get_image_copy_string()); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(sysinfo, command_sysinfo); - - -static int command_set_scratchpad(int argc, char **argv) -{ - int s; - char *e; - - if (argc < 2) { - uart_puts("Usage: scratchpad \n"); - return EC_ERROR_UNKNOWN; - } - - s = strtoi(argv[1], &e, 0); - if (*e) { - uart_puts("Invalid scratchpad value\n"); - return EC_ERROR_UNKNOWN; - } - uart_printf("Setting scratchpad to 0x%08x\n", s); - return system_set_scratchpad(s); -} -DECLARE_CONSOLE_COMMAND(setscratchpad, command_set_scratchpad); - -static int command_hibernate(int argc, char **argv) -{ - int seconds; - int microseconds = 0; - - if (argc < 2) { - uart_puts("Usage: hibernate []\n"); - return EC_ERROR_UNKNOWN; - } - seconds = strtoi(argv[1], NULL, 0); - if (argc >= 3) - microseconds = strtoi(argv[2], NULL, 0); - - uart_printf("Hibernating for %d.%06d s ...\n", seconds, microseconds); - uart_flush_output(); - - system_hibernate(seconds, microseconds); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(hibernate, command_hibernate); diff --git a/common/build.mk b/common/build.mk index c220cd54f5..2956407689 100644 --- a/common/build.mk +++ b/common/build.mk @@ -6,7 +6,7 @@ # common-y=main.o util.o console.o vboot.o uart_buffering.o -common-y+=memory_commands.o shared_mem.o usb_charge.o +common-y+=memory_commands.o shared_mem.o system.o usb_charge.o common-$(CONFIG_LPC)+=port80.o common-$(CONFIG_TASK_HOSTCMD)+=host_command.o common-$(CONFIG_TASK_I8042CMD)+=i8042.o keyboard.o diff --git a/common/system.c b/common/system.c new file mode 100644 index 0000000000..53254b092c --- /dev/null +++ b/common/system.c @@ -0,0 +1,207 @@ +/* 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 : common functions */ + +#include "console.h" +#include "system.h" +#include "uart.h" +#include "util.h" +#include "version.h" + +struct version_struct { + uint32_t cookie1; + char version[32]; + uint32_t cookie2; +} __attribute__ ((packed)); + +static const struct version_struct version_data = { + 0xce112233, + CROS_EC_VERSION_STRING, + 0xce445566 +}; + +static enum system_reset_cause_t reset_cause = SYSTEM_RESET_UNKNOWN; + +enum system_reset_cause_t system_get_reset_cause(void) +{ + return reset_cause; +} + + +void system_set_reset_cause(enum system_reset_cause_t cause) +{ + reset_cause = cause; +} + + +const char *system_get_reset_cause_string(void) +{ + static const char * const cause_descs[] = { + "unknown", "other", "brownout", "power-on", "reset pin", + "soft cold", "soft warm", "watchdog", "rtc alarm", "wake pin", + "low battery"}; + + return reset_cause < ARRAY_SIZE(cause_descs) ? + cause_descs[reset_cause] : "?"; +} + + +enum system_image_copy_t system_get_image_copy(void) +{ + int copy = (uint32_t)system_get_image_copy / CONFIG_FW_IMAGE_SIZE; + switch (copy) { + case 0: + return SYSTEM_IMAGE_RO; + case 1: + return SYSTEM_IMAGE_RW_A; + case 2: + return SYSTEM_IMAGE_RW_B; + default: + return SYSTEM_IMAGE_UNKNOWN; + } +} + + +const char *system_get_image_copy_string(void) +{ + static const char * const copy_descs[] = {"unknown", "RO", "A", "B"}; + int copy = system_get_image_copy(); + return copy < ARRAY_SIZE(copy_descs) ? copy_descs[copy] : "?"; +} + + +int system_run_image_copy(enum system_image_copy_t copy) +{ + uint32_t init_addr; + void (*resetvec)(void); + + /* Fail if we're not in RO firmware */ + if (system_get_image_copy() != SYSTEM_IMAGE_RO) + return EC_ERROR_UNKNOWN; + + /* Load the appropriate reset vector */ + if (copy == SYSTEM_IMAGE_RW_A) + init_addr = *(uint32_t *)(CONFIG_FW_A_OFF + 4); + else if (copy == SYSTEM_IMAGE_RW_B) + init_addr = *(uint32_t *)(CONFIG_FW_B_OFF + 4); + else + return EC_ERROR_UNKNOWN; + + /* TODO: sanity checks (crosbug.com/p/7468) + * + * Fail if called outside of pre-init. + * + * Fail if reboot reason is not soft reboot. Power-on + * reset cause must run RO firmware; if it wants to move to RW + * firmware, it must go through a soft reboot first + * + * Sanity check reset vector; must be inside the appropriate + * image. */ + + /* Jump to the reset vector */ + resetvec = (void(*)(void))init_addr; + resetvec(); + + /* Should never get here */ + return EC_ERROR_UNIMPLEMENTED; +} + + +const char *system_get_version(enum system_image_copy_t copy) +{ + int imoffset; + const uint32_t *p, *pend; + const struct version_struct *v; + + /* Handle version of current image */ + if (copy == system_get_image_copy() || copy == SYSTEM_IMAGE_UNKNOWN) + return version_data.version; + + switch (copy) { + case SYSTEM_IMAGE_RO: + imoffset = CONFIG_FW_RO_OFF; + break; + case SYSTEM_IMAGE_RW_A: + imoffset = CONFIG_FW_A_OFF; + break; + case SYSTEM_IMAGE_RW_B: + imoffset = CONFIG_FW_B_OFF; + break; + default: + return ""; + } + + /* Search for version cookies in target image */ + /* TODO: (crosbug.com/p/7469) could be smarter about where to + * search if we stuffed the version data into a predefined + * area of the image - for example, immediately following the + * reset vectors. */ + pend = (uint32_t *)(imoffset + CONFIG_FW_IMAGE_SIZE + - sizeof(version_data)); + for (p = (uint32_t *)imoffset; p <= pend; p++) { + v = (const struct version_struct *)p; + if (v->cookie1 == version_data.cookie1 && + v->cookie2 == version_data.cookie2) + return v->version; + } + + return ""; +} + + +static int command_sysinfo(int argc, char **argv) +{ + uart_printf("Reset cause: %d (%s)\n", + system_get_reset_cause(), + system_get_reset_cause_string()); + uart_printf("Scratchpad: 0x%08x\n", system_get_scratchpad()); + uart_printf("Firmware copy: %s\n", system_get_image_copy_string()); + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(sysinfo, command_sysinfo); + + +static int command_set_scratchpad(int argc, char **argv) +{ + int s; + char *e; + + if (argc < 2) { + uart_puts("Usage: scratchpad \n"); + return EC_ERROR_UNKNOWN; + } + + s = strtoi(argv[1], &e, 0); + if (*e) { + uart_puts("Invalid scratchpad value\n"); + return EC_ERROR_UNKNOWN; + } + uart_printf("Setting scratchpad to 0x%08x\n", s); + return system_set_scratchpad(s); +} +DECLARE_CONSOLE_COMMAND(setscratchpad, command_set_scratchpad); + +static int command_hibernate(int argc, char **argv) +{ + int seconds; + int microseconds = 0; + + if (argc < 2) { + uart_puts("Usage: hibernate []\n"); + return EC_ERROR_UNKNOWN; + } + seconds = strtoi(argv[1], NULL, 0); + if (argc >= 3) + microseconds = strtoi(argv[2], NULL, 0); + + uart_printf("Hibernating for %d.%06d s ...\n", seconds, microseconds); + uart_flush_output(); + + system_hibernate(seconds, microseconds); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(hibernate, command_hibernate); diff --git a/include/system.h b/include/system.h index 46cb5bf730..23607cfcaa 100644 --- a/include/system.h +++ b/include/system.h @@ -56,6 +56,9 @@ int system_init(void); * the cause is not known. */ enum system_reset_cause_t system_get_reset_cause(void); +/* Record the cause of the last reset. */ +void system_set_reset_cause(enum system_reset_cause_t cause); + /* Returns a text description of the last reset cause. */ const char *system_get_reset_cause_string(void);