Alexey Romanov | 311106a | 2023-01-10 13:56:47 +0300 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Copyright (c) 2016 Beniamino Galvani |
| 4 | * |
| 5 | * Author: Beniamino Galvani <b.galvani@gmail.com> |
| 6 | * Author: Vyacheslav Bocharov <adeep@lexina.in> |
| 7 | * Author: Neil Armstrong <narmstrong@baylibre.com> |
Alexey Romanov | ac7fdbc | 2023-01-10 13:56:49 +0300 | [diff] [blame] | 8 | * Author: Alexey Romanov <avromanov@sberdevices.ru> |
Alexey Romanov | 311106a | 2023-01-10 13:56:47 +0300 | [diff] [blame] | 9 | */ |
| 10 | |
| 11 | #include <command.h> |
Alexey Romanov | 311106a | 2023-01-10 13:56:47 +0300 | [diff] [blame] | 12 | #include <env.h> |
| 13 | #include <asm/arch/sm.h> |
| 14 | #include <stdlib.h> |
Alexey Romanov | ac7fdbc | 2023-01-10 13:56:49 +0300 | [diff] [blame] | 15 | #include <display_options.h> |
Tom Rini | 03de305 | 2024-05-20 13:35:03 -0600 | [diff] [blame] | 16 | #include <vsprintf.h> |
Alexey Romanov | 311106a | 2023-01-10 13:56:47 +0300 | [diff] [blame] | 17 | |
| 18 | static int do_sm_serial(struct cmd_tbl *cmdtp, int flag, int argc, |
| 19 | char *const argv[]) |
| 20 | { |
| 21 | ulong address; |
| 22 | int ret; |
| 23 | |
| 24 | if (argc < 2) |
| 25 | return CMD_RET_USAGE; |
| 26 | |
| 27 | address = simple_strtoul(argv[1], NULL, 0); |
| 28 | |
| 29 | ret = meson_sm_get_serial((void *)address, SM_SERIAL_SIZE); |
| 30 | if (ret) |
| 31 | return CMD_RET_FAILURE; |
| 32 | |
| 33 | return CMD_RET_SUCCESS; |
| 34 | } |
| 35 | |
| 36 | #define MAX_REBOOT_REASONS 14 |
| 37 | |
| 38 | static const char *reboot_reasons[MAX_REBOOT_REASONS] = { |
| 39 | [REBOOT_REASON_COLD] = "cold_boot", |
| 40 | [REBOOT_REASON_NORMAL] = "normal", |
| 41 | [REBOOT_REASON_RECOVERY] = "recovery", |
| 42 | [REBOOT_REASON_UPDATE] = "update", |
| 43 | [REBOOT_REASON_FASTBOOT] = "fastboot", |
| 44 | [REBOOT_REASON_SUSPEND_OFF] = "suspend_off", |
| 45 | [REBOOT_REASON_HIBERNATE] = "hibernate", |
| 46 | [REBOOT_REASON_BOOTLOADER] = "bootloader", |
| 47 | [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot", |
| 48 | [REBOOT_REASON_RPMBP] = "rpmbp", |
| 49 | [REBOOT_REASON_CRASH_DUMP] = "crash_dump", |
| 50 | [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic", |
| 51 | [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot", |
| 52 | }; |
| 53 | |
| 54 | static int do_sm_reboot_reason(struct cmd_tbl *cmdtp, int flag, int argc, |
| 55 | char *const argv[]) |
| 56 | { |
| 57 | const char *reason_str; |
| 58 | char *destarg = NULL; |
| 59 | int reason; |
| 60 | |
| 61 | if (argc > 1) |
| 62 | destarg = argv[1]; |
| 63 | |
| 64 | reason = meson_sm_get_reboot_reason(); |
| 65 | if (reason < 0) |
| 66 | return CMD_RET_FAILURE; |
| 67 | |
| 68 | if (reason >= MAX_REBOOT_REASONS || |
| 69 | !reboot_reasons[reason]) |
| 70 | reason_str = "unknown"; |
| 71 | else |
| 72 | reason_str = reboot_reasons[reason]; |
| 73 | |
| 74 | if (destarg) |
| 75 | env_set(destarg, reason_str); |
| 76 | else |
| 77 | printf("reboot reason: %s (%x)\n", reason_str, reason); |
| 78 | |
| 79 | return CMD_RET_SUCCESS; |
| 80 | } |
| 81 | |
| 82 | static int do_efuse_read(struct cmd_tbl *cmdtp, int flag, int argc, |
| 83 | char *const argv[]) |
| 84 | { |
| 85 | ulong address, offset, size; |
| 86 | int ret; |
| 87 | |
| 88 | if (argc < 4) |
| 89 | return CMD_RET_USAGE; |
| 90 | |
| 91 | offset = simple_strtoul(argv[1], NULL, 0); |
| 92 | size = simple_strtoul(argv[2], NULL, 0); |
| 93 | |
| 94 | address = simple_strtoul(argv[3], NULL, 0); |
| 95 | |
| 96 | ret = meson_sm_read_efuse(offset, (void *)address, size); |
| 97 | if (ret != size) |
| 98 | return CMD_RET_FAILURE; |
| 99 | |
| 100 | return CMD_RET_SUCCESS; |
| 101 | } |
| 102 | |
| 103 | static int do_efuse_write(struct cmd_tbl *cmdtp, int flag, int argc, |
| 104 | char *const argv[]) |
| 105 | { |
| 106 | ulong address, offset, size; |
| 107 | int ret; |
| 108 | |
| 109 | if (argc < 4) |
| 110 | return CMD_RET_USAGE; |
| 111 | |
| 112 | offset = simple_strtoul(argv[1], NULL, 0); |
| 113 | size = simple_strtoul(argv[2], NULL, 0); |
| 114 | |
| 115 | address = simple_strtoul(argv[3], NULL, 0); |
| 116 | |
| 117 | ret = meson_sm_write_efuse(offset, (void *)address, size); |
| 118 | if (ret != size) |
| 119 | return CMD_RET_FAILURE; |
| 120 | |
| 121 | return CMD_RET_SUCCESS; |
| 122 | } |
| 123 | |
Alexey Romanov | ac7fdbc | 2023-01-10 13:56:49 +0300 | [diff] [blame] | 124 | static int do_efuse_dump(struct cmd_tbl *cmdtp, int flag, int argc, |
| 125 | char *const argv[]) |
| 126 | { |
| 127 | ulong offset, size; |
| 128 | u8 *buffer; |
| 129 | int ret; |
| 130 | |
| 131 | if (argc != 3) |
| 132 | return CMD_RET_USAGE; |
| 133 | |
| 134 | offset = simple_strtoul(argv[1], NULL, 0); |
| 135 | size = simple_strtoul(argv[2], NULL, 0); |
| 136 | buffer = malloc(size); |
| 137 | if (!buffer) { |
| 138 | pr_err("Failed to allocate %lu bytes\n", size); |
| 139 | return CMD_RET_FAILURE; |
| 140 | } |
| 141 | |
| 142 | ret = meson_sm_read_efuse(offset, (void *)buffer, size); |
| 143 | if (ret != size) { |
| 144 | ret = CMD_RET_FAILURE; |
| 145 | goto free_buffer; |
| 146 | } |
| 147 | |
| 148 | print_buffer(0, buffer, 1, size, 0); |
| 149 | |
| 150 | free_buffer: |
| 151 | free(buffer); |
| 152 | return ret; |
| 153 | } |
| 154 | |
Alexey Romanov | 311106a | 2023-01-10 13:56:47 +0300 | [diff] [blame] | 155 | static struct cmd_tbl cmd_sm_sub[] = { |
| 156 | U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""), |
| 157 | U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""), |
| 158 | U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""), |
| 159 | U_BOOT_CMD_MKENT(efusewrite, 4, 0, do_efuse_write, "", ""), |
Alexey Romanov | ac7fdbc | 2023-01-10 13:56:49 +0300 | [diff] [blame] | 160 | U_BOOT_CMD_MKENT(efusedump, 3, 1, do_efuse_dump, "", ""), |
Alexey Romanov | 311106a | 2023-01-10 13:56:47 +0300 | [diff] [blame] | 161 | }; |
| 162 | |
| 163 | static int do_sm(struct cmd_tbl *cmdtp, int flag, int argc, |
| 164 | char *const argv[]) |
| 165 | { |
| 166 | struct cmd_tbl *c; |
| 167 | |
| 168 | if (argc < 2) |
| 169 | return CMD_RET_USAGE; |
| 170 | |
| 171 | /* Strip off leading 'sm' command argument */ |
| 172 | argc--; |
| 173 | argv++; |
| 174 | |
| 175 | c = find_cmd_tbl(argv[0], &cmd_sm_sub[0], ARRAY_SIZE(cmd_sm_sub)); |
| 176 | |
| 177 | if (c) |
| 178 | return c->cmd(cmdtp, flag, argc, argv); |
| 179 | else |
| 180 | return CMD_RET_USAGE; |
| 181 | } |
| 182 | |
| 183 | U_BOOT_CMD( |
| 184 | sm, 5, 0, do_sm, |
| 185 | "Secure Monitor Control", |
| 186 | "serial <address> - read chip unique id to memory address\n" |
| 187 | "sm reboot_reason [name] - get reboot reason and store to environment\n" |
| 188 | "sm efuseread <offset> <size> <address> - read efuse to memory address\n" |
Alexey Romanov | ac7fdbc | 2023-01-10 13:56:49 +0300 | [diff] [blame] | 189 | "sm efusewrite <offset> <size> <address> - write into efuse from memory address\n" |
| 190 | "sm efusedump <offset> <size> - dump efuse data range to console" |
Alexey Romanov | 311106a | 2023-01-10 13:56:47 +0300 | [diff] [blame] | 191 | ); |