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>
8  * Author: Alexey Romanov <avromanov@sberdevices.ru>
9  */
10 
11 #include <command.h>
12 #include <common.h>
13 #include <env.h>
14 #include <asm/arch/sm.h>
15 #include <stdlib.h>
16 #include <display_options.h>
17 
do_sm_serial(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])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 
do_sm_reboot_reason(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])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 
do_efuse_read(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])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 
do_efuse_write(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])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 
do_efuse_dump(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])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 
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, "", ""),
160 	U_BOOT_CMD_MKENT(efusedump, 3, 1, do_efuse_dump, "", ""),
161 };
162 
do_sm(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])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"
189 	"sm efusewrite <offset> <size> <address> - write into efuse from memory address\n"
190 	"sm efusedump <offset> <size> - dump efuse data range to console"
191 );
192