diff options
Diffstat (limited to 'arch/arm/mach-meson')
-rw-r--r-- | arch/arm/mach-meson/board-common.c | 33 | ||||
-rw-r--r-- | arch/arm/mach-meson/sm.c | 133 |
2 files changed, 166 insertions, 0 deletions
diff --git a/arch/arm/mach-meson/board-common.c b/arch/arm/mach-meson/board-common.c index 0843dca..d261b4e 100644 --- a/arch/arm/mach-meson/board-common.c +++ b/arch/arm/mach-meson/board-common.c @@ -14,6 +14,11 @@ #include <asm/unaligned.h> #include <efi_loader.h> +#if CONFIG_IS_ENABLED(FASTBOOT) +#include <asm/psci.h> +#include <fastboot.h> +#endif + DECLARE_GLOBAL_DATA_PTR; __weak int board_init(void) @@ -142,7 +147,35 @@ int board_late_init(void) return meson_board_late_init(); } +#if CONFIG_IS_ENABLED(FASTBOOT) +static unsigned int reboot_reason = REBOOT_REASON_NORMAL; + +int fastboot_set_reboot_flag() +{ + reboot_reason = REBOOT_REASON_BOOTLOADER; + + printf("Using reboot reason: 0x%x\n", reboot_reason); + + return 0; +} + +void reset_cpu(ulong addr) +{ + struct pt_regs regs; + + regs.regs[0] = ARM_PSCI_0_2_FN_SYSTEM_RESET; + regs.regs[1] = reboot_reason; + + printf("Rebooting with reason: 0x%lx\n", regs.regs[1]); + + smc_call(®s); + + while (1) + ; +} +#else void reset_cpu(ulong addr) { psci_system_reset(); } +#endif diff --git a/arch/arm/mach-meson/sm.c b/arch/arm/mach-meson/sm.c index 05b7f0b..fabcb3b 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 @@ -77,3 +81,132 @@ 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[]) +{ + ulong address; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + address = simple_strtoul(argv[1], NULL, 0); + + ret = meson_sm_get_serial((void *)address, SM_CHIP_ID_SIZE); + if (ret) + return CMD_RET_FAILURE; + + 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, + char *const argv[]) +{ + cmd_tbl_t *c; + + if (argc < 2) + return CMD_RET_USAGE; + + /* Strip off leading 'sm' command argument */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], &cmd_sm_sub[0], ARRAY_SIZE(cmd_sm_sub)); + + if (c) + return c->cmd(cmdtp, flag, argc, argv); + else + return CMD_RET_USAGE; +} + +U_BOOT_CMD( + sm, 5, 0, do_sm, + "Secure Monitor Control", + "serial <address> - read chip unique id to memory address\n" + "sm reboot_reason [name] - get reboot reason and store to to environment" +); |