diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/include/asm/arch-meson/sm.h | 18 | ||||
-rw-r--r-- | arch/arm/mach-meson/sm.c | 87 |
2 files changed, 104 insertions, 1 deletions
diff --git a/arch/arm/include/asm/arch-meson/sm.h b/arch/arm/include/asm/arch-meson/sm.h index 60d04ae2283..f3ae46a6d6b 100644 --- a/arch/arm/include/asm/arch-meson/sm.h +++ b/arch/arm/include/asm/arch-meson/sm.h @@ -12,4 +12,22 @@ ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size); int meson_sm_get_serial(void *buffer, size_t size); +enum { + REBOOT_REASON_COLD = 0, + REBOOT_REASON_NORMAL = 1, + REBOOT_REASON_RECOVERY = 2, + REBOOT_REASON_UPDATE = 3, + REBOOT_REASON_FASTBOOT = 4, + REBOOT_REASON_SUSPEND_OFF = 5, + REBOOT_REASON_HIBERNATE = 6, + REBOOT_REASON_BOOTLOADER = 7, + REBOOT_REASON_SHUTDOWN_REBOOT = 8, + REBOOT_REASON_RPMBP = 9, + REBOOT_REASON_CRASH_DUMP = 11, + REBOOT_REASON_KERNEL_PANIC = 12, + REBOOT_REASON_WATCHDOG_REBOOT = 13, +}; + +int meson_sm_get_reboot_reason(void); + #endif /* __MESON_SM_H__ */ diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index 99fa17d9a8c..fabcb3bfd74 100644 --- a/arch/arm/mach-meson/sm.c +++ b/arch/arm/mach-meson/sm.c @@ -8,6 +8,10 @@ #include <common.h> #include <asm/arch/sm.h> #include <linux/kernel.h> +#include <dm.h> +#include <linux/bitfield.h> +#include <regmap.h> +#include <syscon.h> #define FN_GET_SHARE_MEM_INPUT_BASE 0x82000020 #define FN_GET_SHARE_MEM_OUTPUT_BASE 0x82000021 @@ -78,6 +82,39 @@ int meson_sm_get_serial(void *buffer, size_t size) return 0; } +#define AO_SEC_SD_CFG15 0xfc +#define REBOOT_REASON_MASK GENMASK(15, 12) + +int meson_sm_get_reboot_reason(void) +{ + struct regmap *regmap; + int nodeoffset; + ofnode node; + unsigned int reason; + + /* find the offset of compatible node */ + nodeoffset = fdt_node_offset_by_compatible(gd->fdt_blob, -1, + "amlogic,meson-gx-ao-secure"); + if (nodeoffset < 0) { + printf("%s: failed to get amlogic,meson-gx-ao-secure\n", + __func__); + return -ENODEV; + } + + /* get regmap from the syscon node */ + node = offset_to_ofnode(nodeoffset); + regmap = syscon_node_to_regmap(node); + if (IS_ERR(regmap)) { + printf("%s: failed to get regmap\n", __func__); + return -EINVAL; + } + + regmap_read(regmap, AO_SEC_SD_CFG15, &reason); + + /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */ + return FIELD_GET(REBOOT_REASON_MASK, reason); +} + static int do_sm_serial(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { @@ -96,8 +133,55 @@ static int do_sm_serial(cmd_tbl_t *cmdtp, int flag, int argc, return CMD_RET_SUCCESS; } +#define MAX_REBOOT_REASONS 14 + +static const char *reboot_reasons[MAX_REBOOT_REASONS] = { + [REBOOT_REASON_COLD] = "cold_boot", + [REBOOT_REASON_NORMAL] = "normal", + [REBOOT_REASON_RECOVERY] = "recovery", + [REBOOT_REASON_UPDATE] = "update", + [REBOOT_REASON_FASTBOOT] = "fastboot", + [REBOOT_REASON_SUSPEND_OFF] = "suspend_off", + [REBOOT_REASON_HIBERNATE] = "hibernate", + [REBOOT_REASON_BOOTLOADER] = "bootloader", + [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot", + [REBOOT_REASON_RPMBP] = "rpmbp", + [REBOOT_REASON_CRASH_DUMP] = "crash_dump", + [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic", + [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot", +}; + +static int do_sm_reboot_reason(cmd_tbl_t *cmdtp, int flag, int argc, + char *const argv[]) +{ + const char *reason_str; + char *destarg = NULL; + int reason; + + if (argc > 1) + destarg = argv[1]; + + reason = meson_sm_get_reboot_reason(); + if (reason < 0) + return CMD_RET_FAILURE; + + if (reason >= MAX_REBOOT_REASONS || + !reboot_reasons[reason]) + reason_str = "unknown"; + else + reason_str = reboot_reasons[reason]; + + if (destarg) + env_set(destarg, reason_str); + else + printf("reboot reason: %s (%x)\n", reason_str, reason); + + return CMD_RET_SUCCESS; +} + static cmd_tbl_t cmd_sm_sub[] = { U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""), + U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""), }; static int do_sm(cmd_tbl_t *cmdtp, int flag, int argc, @@ -123,5 +207,6 @@ static int do_sm(cmd_tbl_t *cmdtp, int flag, int argc, U_BOOT_CMD( sm, 5, 0, do_sm, "Secure Monitor Control", - "serial <address> - read chip unique id to memory address" + "serial <address> - read chip unique id to memory address\n" + "sm reboot_reason [name] - get reboot reason and store to to environment" ); |