1
2
3
4
5
6
7
8#include <common.h>
9#include <command.h>
10#include <env.h>
11#include <log.h>
12#include <asm/arch/sm.h>
13#include <asm/cache.h>
14#include <asm/global_data.h>
15#include <asm/ptrace.h>
16#include <linux/bitops.h>
17#include <linux/err.h>
18#include <linux/kernel.h>
19#include <dm.h>
20#include <linux/bitfield.h>
21#include <regmap.h>
22#include <syscon.h>
23
24#define FN_GET_SHARE_MEM_INPUT_BASE 0x82000020
25#define FN_GET_SHARE_MEM_OUTPUT_BASE 0x82000021
26#define FN_EFUSE_READ 0x82000030
27#define FN_EFUSE_WRITE 0x82000031
28#define FN_CHIP_ID 0x82000044
29
30static void *shmem_input;
31static void *shmem_output;
32
33static void meson_init_shmem(void)
34{
35 struct pt_regs regs;
36
37 if (shmem_input && shmem_output)
38 return;
39
40 regs.regs[0] = FN_GET_SHARE_MEM_INPUT_BASE;
41 smc_call(®s);
42 shmem_input = (void *)regs.regs[0];
43
44 regs.regs[0] = FN_GET_SHARE_MEM_OUTPUT_BASE;
45 smc_call(®s);
46 shmem_output = (void *)regs.regs[0];
47
48 debug("Secure Monitor shmem: 0x%p 0x%p\n", shmem_input, shmem_output);
49}
50
51ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size)
52{
53 struct pt_regs regs;
54
55 meson_init_shmem();
56
57 regs.regs[0] = FN_EFUSE_READ;
58 regs.regs[1] = offset;
59 regs.regs[2] = size;
60
61 smc_call(®s);
62
63 if (regs.regs[0] == 0)
64 return -1;
65
66 memcpy(buffer, shmem_output, min(size, regs.regs[0]));
67
68 return regs.regs[0];
69}
70
71ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size)
72{
73 struct pt_regs regs;
74
75 meson_init_shmem();
76
77 memcpy(shmem_input, buffer, size);
78
79 regs.regs[0] = FN_EFUSE_WRITE;
80 regs.regs[1] = offset;
81 regs.regs[2] = size;
82
83 smc_call(®s);
84
85 if (regs.regs[0] == 0)
86 return -1;
87
88 return 0;
89}
90
91#define SM_CHIP_ID_LENGTH 119
92#define SM_CHIP_ID_OFFSET 4
93#define SM_CHIP_ID_SIZE 12
94
95int meson_sm_get_serial(void *buffer, size_t size)
96{
97 struct pt_regs regs;
98
99 meson_init_shmem();
100
101 regs.regs[0] = FN_CHIP_ID;
102 regs.regs[1] = 0;
103 regs.regs[2] = 0;
104
105 smc_call(®s);
106
107 memcpy(buffer, shmem_output + SM_CHIP_ID_OFFSET,
108 min_t(size_t, size, SM_CHIP_ID_SIZE));
109
110 return 0;
111}
112
113#define AO_SEC_SD_CFG15 0xfc
114#define REBOOT_REASON_MASK GENMASK(15, 12)
115
116int meson_sm_get_reboot_reason(void)
117{
118 struct regmap *regmap;
119 int nodeoffset;
120 ofnode node;
121 unsigned int reason;
122
123
124 nodeoffset = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
125 "amlogic,meson-gx-ao-secure");
126 if (nodeoffset < 0) {
127 printf("%s: failed to get amlogic,meson-gx-ao-secure\n",
128 __func__);
129 return -ENODEV;
130 }
131
132
133 node = offset_to_ofnode(nodeoffset);
134 regmap = syscon_node_to_regmap(node);
135 if (IS_ERR(regmap)) {
136 printf("%s: failed to get regmap\n", __func__);
137 return -EINVAL;
138 }
139
140 regmap_read(regmap, AO_SEC_SD_CFG15, &reason);
141
142
143 return FIELD_GET(REBOOT_REASON_MASK, reason);
144}
145
146static int do_sm_serial(struct cmd_tbl *cmdtp, int flag, int argc,
147 char *const argv[])
148{
149 ulong address;
150 int ret;
151
152 if (argc < 2)
153 return CMD_RET_USAGE;
154
155 address = simple_strtoul(argv[1], NULL, 0);
156
157 ret = meson_sm_get_serial((void *)address, SM_CHIP_ID_SIZE);
158 if (ret)
159 return CMD_RET_FAILURE;
160
161 return CMD_RET_SUCCESS;
162}
163
164#define MAX_REBOOT_REASONS 14
165
166static const char *reboot_reasons[MAX_REBOOT_REASONS] = {
167 [REBOOT_REASON_COLD] = "cold_boot",
168 [REBOOT_REASON_NORMAL] = "normal",
169 [REBOOT_REASON_RECOVERY] = "recovery",
170 [REBOOT_REASON_UPDATE] = "update",
171 [REBOOT_REASON_FASTBOOT] = "fastboot",
172 [REBOOT_REASON_SUSPEND_OFF] = "suspend_off",
173 [REBOOT_REASON_HIBERNATE] = "hibernate",
174 [REBOOT_REASON_BOOTLOADER] = "bootloader",
175 [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot",
176 [REBOOT_REASON_RPMBP] = "rpmbp",
177 [REBOOT_REASON_CRASH_DUMP] = "crash_dump",
178 [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic",
179 [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot",
180};
181
182static int do_sm_reboot_reason(struct cmd_tbl *cmdtp, int flag, int argc,
183 char *const argv[])
184{
185 const char *reason_str;
186 char *destarg = NULL;
187 int reason;
188
189 if (argc > 1)
190 destarg = argv[1];
191
192 reason = meson_sm_get_reboot_reason();
193 if (reason < 0)
194 return CMD_RET_FAILURE;
195
196 if (reason >= MAX_REBOOT_REASONS ||
197 !reboot_reasons[reason])
198 reason_str = "unknown";
199 else
200 reason_str = reboot_reasons[reason];
201
202 if (destarg)
203 env_set(destarg, reason_str);
204 else
205 printf("reboot reason: %s (%x)\n", reason_str, reason);
206
207 return CMD_RET_SUCCESS;
208}
209
210static int do_efuse_read(struct cmd_tbl *cmdtp, int flag, int argc,
211 char *const argv[])
212{
213 ulong address, offset, size;
214 int ret;
215
216 if (argc < 4)
217 return CMD_RET_USAGE;
218
219 offset = simple_strtoul(argv[1], NULL, 0);
220 size = simple_strtoul(argv[2], NULL, 0);
221
222 address = simple_strtoul(argv[3], NULL, 0);
223
224 ret = meson_sm_read_efuse(offset, (void *)address, size);
225 if (ret)
226 return CMD_RET_FAILURE;
227
228 return CMD_RET_SUCCESS;
229}
230
231static int do_efuse_write(struct cmd_tbl *cmdtp, int flag, int argc,
232 char *const argv[])
233{
234 ulong address, offset, size;
235 int ret;
236
237 if (argc < 4)
238 return CMD_RET_USAGE;
239
240 offset = simple_strtoul(argv[1], NULL, 0);
241 size = simple_strtoul(argv[2], NULL, 0);
242
243 address = simple_strtoul(argv[3], NULL, 0);
244
245 ret = meson_sm_write_efuse(offset, (void *)address, size);
246 if (ret)
247 return CMD_RET_FAILURE;
248
249 return CMD_RET_SUCCESS;
250}
251
252static struct cmd_tbl cmd_sm_sub[] = {
253 U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""),
254 U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""),
255 U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""),
256 U_BOOT_CMD_MKENT(efusewrite, 4, 0, do_efuse_write, "", ""),
257};
258
259static int do_sm(struct cmd_tbl *cmdtp, int flag, int argc,
260 char *const argv[])
261{
262 struct cmd_tbl *c;
263
264 if (argc < 2)
265 return CMD_RET_USAGE;
266
267
268 argc--;
269 argv++;
270
271 c = find_cmd_tbl(argv[0], &cmd_sm_sub[0], ARRAY_SIZE(cmd_sm_sub));
272
273 if (c)
274 return c->cmd(cmdtp, flag, argc, argv);
275 else
276 return CMD_RET_USAGE;
277}
278
279U_BOOT_CMD(
280 sm, 5, 0, do_sm,
281 "Secure Monitor Control",
282 "serial <address> - read chip unique id to memory address\n"
283 "sm reboot_reason [name] - get reboot reason and store to to environment\n"
284 "sm efuseread <offset> <size> <address> - read efuse to memory address\n"
285 "sm efusewrite <offset> <size> <address> - write into efuse from memory address"
286);
287