blob: d6eb910689f41ff39783e2476f6c39986a0c88a3 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Beniamino Galvani38e1a602016-05-08 08:30:17 +02002/*
3 * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
4 *
Beniamino Galvani38e1a602016-05-08 08:30:17 +02005 * Secure monitor calls.
6 */
7
8#include <common.h>
Simon Glassed38aef2020-05-10 11:40:03 -06009#include <command.h>
10#include <env.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Neil Armstrong63f475c2019-06-12 11:49:06 +020012#include <asm/arch/sm.h>
Simon Glass274e0b02020-05-10 11:39:56 -060013#include <asm/cache.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060014#include <asm/global_data.h>
Simon Glass6b9f0102020-05-10 11:40:06 -060015#include <asm/ptrace.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060016#include <linux/bitops.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070017#include <linux/err.h>
Beniamino Galvani38e1a602016-05-08 08:30:17 +020018#include <linux/kernel.h>
Neil Armstrong385309c2019-08-06 17:28:36 +020019#include <dm.h>
20#include <linux/bitfield.h>
21#include <regmap.h>
22#include <syscon.h>
Beniamino Galvani38e1a602016-05-08 08:30:17 +020023
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
Neil Armstrong63f475c2019-06-12 11:49:06 +020028#define FN_CHIP_ID 0x82000044
Beniamino Galvani38e1a602016-05-08 08:30:17 +020029
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(&regs);
42 shmem_input = (void *)regs.regs[0];
43
44 regs.regs[0] = FN_GET_SHARE_MEM_OUTPUT_BASE;
45 smc_call(&regs);
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(&regs);
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}
Neil Armstrong63f475c2019-06-12 11:49:06 +020070
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +030071ssize_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(&regs);
84
Jerome Brunet25759f12022-08-04 16:41:38 +020085 return regs.regs[0];
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +030086}
87
Neil Armstrong63f475c2019-06-12 11:49:06 +020088#define SM_CHIP_ID_LENGTH 119
89#define SM_CHIP_ID_OFFSET 4
90#define SM_CHIP_ID_SIZE 12
91
92int meson_sm_get_serial(void *buffer, size_t size)
93{
94 struct pt_regs regs;
95
96 meson_init_shmem();
97
98 regs.regs[0] = FN_CHIP_ID;
99 regs.regs[1] = 0;
100 regs.regs[2] = 0;
101
102 smc_call(&regs);
103
104 memcpy(buffer, shmem_output + SM_CHIP_ID_OFFSET,
105 min_t(size_t, size, SM_CHIP_ID_SIZE));
106
107 return 0;
108}
Neil Armstrong69800ec2019-08-06 17:21:02 +0200109
Neil Armstrong385309c2019-08-06 17:28:36 +0200110#define AO_SEC_SD_CFG15 0xfc
111#define REBOOT_REASON_MASK GENMASK(15, 12)
112
113int meson_sm_get_reboot_reason(void)
114{
115 struct regmap *regmap;
116 int nodeoffset;
117 ofnode node;
118 unsigned int reason;
119
120 /* find the offset of compatible node */
121 nodeoffset = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
122 "amlogic,meson-gx-ao-secure");
123 if (nodeoffset < 0) {
124 printf("%s: failed to get amlogic,meson-gx-ao-secure\n",
125 __func__);
126 return -ENODEV;
127 }
128
129 /* get regmap from the syscon node */
130 node = offset_to_ofnode(nodeoffset);
131 regmap = syscon_node_to_regmap(node);
132 if (IS_ERR(regmap)) {
133 printf("%s: failed to get regmap\n", __func__);
134 return -EINVAL;
135 }
136
137 regmap_read(regmap, AO_SEC_SD_CFG15, &reason);
138
139 /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */
140 return FIELD_GET(REBOOT_REASON_MASK, reason);
141}
142
Simon Glassed38aef2020-05-10 11:40:03 -0600143static int do_sm_serial(struct cmd_tbl *cmdtp, int flag, int argc,
Neil Armstrong69800ec2019-08-06 17:21:02 +0200144 char *const argv[])
145{
146 ulong address;
147 int ret;
148
149 if (argc < 2)
150 return CMD_RET_USAGE;
151
152 address = simple_strtoul(argv[1], NULL, 0);
153
154 ret = meson_sm_get_serial((void *)address, SM_CHIP_ID_SIZE);
155 if (ret)
156 return CMD_RET_FAILURE;
157
Neil Armstrong385309c2019-08-06 17:28:36 +0200158 return CMD_RET_SUCCESS;
159}
160
161#define MAX_REBOOT_REASONS 14
162
163static const char *reboot_reasons[MAX_REBOOT_REASONS] = {
164 [REBOOT_REASON_COLD] = "cold_boot",
165 [REBOOT_REASON_NORMAL] = "normal",
166 [REBOOT_REASON_RECOVERY] = "recovery",
167 [REBOOT_REASON_UPDATE] = "update",
168 [REBOOT_REASON_FASTBOOT] = "fastboot",
169 [REBOOT_REASON_SUSPEND_OFF] = "suspend_off",
170 [REBOOT_REASON_HIBERNATE] = "hibernate",
171 [REBOOT_REASON_BOOTLOADER] = "bootloader",
172 [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot",
173 [REBOOT_REASON_RPMBP] = "rpmbp",
174 [REBOOT_REASON_CRASH_DUMP] = "crash_dump",
175 [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic",
176 [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot",
177};
178
Simon Glassed38aef2020-05-10 11:40:03 -0600179static int do_sm_reboot_reason(struct cmd_tbl *cmdtp, int flag, int argc,
180 char *const argv[])
Neil Armstrong385309c2019-08-06 17:28:36 +0200181{
182 const char *reason_str;
183 char *destarg = NULL;
184 int reason;
185
186 if (argc > 1)
187 destarg = argv[1];
188
189 reason = meson_sm_get_reboot_reason();
190 if (reason < 0)
191 return CMD_RET_FAILURE;
192
193 if (reason >= MAX_REBOOT_REASONS ||
194 !reboot_reasons[reason])
195 reason_str = "unknown";
196 else
197 reason_str = reboot_reasons[reason];
198
199 if (destarg)
200 env_set(destarg, reason_str);
201 else
202 printf("reboot reason: %s (%x)\n", reason_str, reason);
203
Neil Armstrong69800ec2019-08-06 17:21:02 +0200204 return CMD_RET_SUCCESS;
205}
206
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +0300207static int do_efuse_read(struct cmd_tbl *cmdtp, int flag, int argc,
208 char *const argv[])
209{
210 ulong address, offset, size;
211 int ret;
212
213 if (argc < 4)
214 return CMD_RET_USAGE;
215
216 offset = simple_strtoul(argv[1], NULL, 0);
217 size = simple_strtoul(argv[2], NULL, 0);
218
219 address = simple_strtoul(argv[3], NULL, 0);
220
221 ret = meson_sm_read_efuse(offset, (void *)address, size);
Jerome Brunet25759f12022-08-04 16:41:38 +0200222 if (ret != size)
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +0300223 return CMD_RET_FAILURE;
224
225 return CMD_RET_SUCCESS;
226}
227
228static int do_efuse_write(struct cmd_tbl *cmdtp, int flag, int argc,
229 char *const argv[])
230{
231 ulong address, offset, size;
232 int ret;
233
234 if (argc < 4)
235 return CMD_RET_USAGE;
236
237 offset = simple_strtoul(argv[1], NULL, 0);
238 size = simple_strtoul(argv[2], NULL, 0);
239
240 address = simple_strtoul(argv[3], NULL, 0);
241
242 ret = meson_sm_write_efuse(offset, (void *)address, size);
Jerome Brunet25759f12022-08-04 16:41:38 +0200243 if (ret != size)
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +0300244 return CMD_RET_FAILURE;
245
246 return CMD_RET_SUCCESS;
247}
248
Simon Glassed38aef2020-05-10 11:40:03 -0600249static struct cmd_tbl cmd_sm_sub[] = {
Neil Armstrong69800ec2019-08-06 17:21:02 +0200250 U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""),
Neil Armstrong385309c2019-08-06 17:28:36 +0200251 U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""),
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +0300252 U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""),
253 U_BOOT_CMD_MKENT(efusewrite, 4, 0, do_efuse_write, "", ""),
Neil Armstrong69800ec2019-08-06 17:21:02 +0200254};
255
Simon Glassed38aef2020-05-10 11:40:03 -0600256static int do_sm(struct cmd_tbl *cmdtp, int flag, int argc,
Neil Armstrong69800ec2019-08-06 17:21:02 +0200257 char *const argv[])
258{
Simon Glassed38aef2020-05-10 11:40:03 -0600259 struct cmd_tbl *c;
Neil Armstrong69800ec2019-08-06 17:21:02 +0200260
261 if (argc < 2)
262 return CMD_RET_USAGE;
263
264 /* Strip off leading 'sm' command argument */
265 argc--;
266 argv++;
267
268 c = find_cmd_tbl(argv[0], &cmd_sm_sub[0], ARRAY_SIZE(cmd_sm_sub));
269
270 if (c)
271 return c->cmd(cmdtp, flag, argc, argv);
272 else
273 return CMD_RET_USAGE;
274}
275
276U_BOOT_CMD(
277 sm, 5, 0, do_sm,
278 "Secure Monitor Control",
Neil Armstrong385309c2019-08-06 17:28:36 +0200279 "serial <address> - read chip unique id to memory address\n"
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +0300280 "sm reboot_reason [name] - get reboot reason and store to to environment\n"
281 "sm efuseread <offset> <size> <address> - read efuse to memory address\n"
282 "sm efusewrite <offset> <size> <address> - write into efuse from memory address"
Neil Armstrong69800ec2019-08-06 17:21:02 +0200283);