blob: 6c28c0f5e445f36c5dbe6543071ce3fe6798a39c [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
85 if (regs.regs[0] == 0)
86 return -1;
87
88 return 0;
89}
90
Neil Armstrong63f475c2019-06-12 11:49:06 +020091#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(&regs);
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}
Neil Armstrong69800ec2019-08-06 17:21:02 +0200112
Neil Armstrong385309c2019-08-06 17:28:36 +0200113#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 /* find the offset of compatible node */
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 /* get regmap from the syscon node */
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 /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */
143 return FIELD_GET(REBOOT_REASON_MASK, reason);
144}
145
Simon Glassed38aef2020-05-10 11:40:03 -0600146static int do_sm_serial(struct cmd_tbl *cmdtp, int flag, int argc,
Neil Armstrong69800ec2019-08-06 17:21:02 +0200147 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
Neil Armstrong385309c2019-08-06 17:28:36 +0200161 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
Simon Glassed38aef2020-05-10 11:40:03 -0600182static int do_sm_reboot_reason(struct cmd_tbl *cmdtp, int flag, int argc,
183 char *const argv[])
Neil Armstrong385309c2019-08-06 17:28:36 +0200184{
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
Neil Armstrong69800ec2019-08-06 17:21:02 +0200207 return CMD_RET_SUCCESS;
208}
209
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +0300210static 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
Simon Glassed38aef2020-05-10 11:40:03 -0600252static struct cmd_tbl cmd_sm_sub[] = {
Neil Armstrong69800ec2019-08-06 17:21:02 +0200253 U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""),
Neil Armstrong385309c2019-08-06 17:28:36 +0200254 U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""),
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +0300255 U_BOOT_CMD_MKENT(efuseread, 4, 1, do_efuse_read, "", ""),
256 U_BOOT_CMD_MKENT(efusewrite, 4, 0, do_efuse_write, "", ""),
Neil Armstrong69800ec2019-08-06 17:21:02 +0200257};
258
Simon Glassed38aef2020-05-10 11:40:03 -0600259static int do_sm(struct cmd_tbl *cmdtp, int flag, int argc,
Neil Armstrong69800ec2019-08-06 17:21:02 +0200260 char *const argv[])
261{
Simon Glassed38aef2020-05-10 11:40:03 -0600262 struct cmd_tbl *c;
Neil Armstrong69800ec2019-08-06 17:21:02 +0200263
264 if (argc < 2)
265 return CMD_RET_USAGE;
266
267 /* Strip off leading 'sm' command argument */
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",
Neil Armstrong385309c2019-08-06 17:28:36 +0200282 "serial <address> - read chip unique id to memory address\n"
Vyacheslav Bocharov14eb82c2021-10-05 15:00:03 +0300283 "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"
Neil Armstrong69800ec2019-08-06 17:21:02 +0200286);