]> git.ipfire.org Git - thirdparty/u-boot.git/blame - arch/arm/mach-meson/sm.c
common: Drop net.h from common header
[thirdparty/u-boot.git] / arch / arm / mach-meson / sm.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
c7757d46
BG
2/*
3 * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
4 *
c7757d46
BG
5 * Secure monitor calls.
6 */
7
8#include <common.h>
0ef8e406 9#include <asm/arch/sm.h>
90526e9f 10#include <asm/cache.h>
61b29b82 11#include <linux/err.h>
c7757d46 12#include <linux/kernel.h>
b1dd7deb
NA
13#include <dm.h>
14#include <linux/bitfield.h>
15#include <regmap.h>
16#include <syscon.h>
c7757d46
BG
17
18#define FN_GET_SHARE_MEM_INPUT_BASE 0x82000020
19#define FN_GET_SHARE_MEM_OUTPUT_BASE 0x82000021
20#define FN_EFUSE_READ 0x82000030
21#define FN_EFUSE_WRITE 0x82000031
0ef8e406 22#define FN_CHIP_ID 0x82000044
c7757d46
BG
23
24static void *shmem_input;
25static void *shmem_output;
26
27static void meson_init_shmem(void)
28{
29 struct pt_regs regs;
30
31 if (shmem_input && shmem_output)
32 return;
33
34 regs.regs[0] = FN_GET_SHARE_MEM_INPUT_BASE;
35 smc_call(&regs);
36 shmem_input = (void *)regs.regs[0];
37
38 regs.regs[0] = FN_GET_SHARE_MEM_OUTPUT_BASE;
39 smc_call(&regs);
40 shmem_output = (void *)regs.regs[0];
41
42 debug("Secure Monitor shmem: 0x%p 0x%p\n", shmem_input, shmem_output);
43}
44
45ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size)
46{
47 struct pt_regs regs;
48
49 meson_init_shmem();
50
51 regs.regs[0] = FN_EFUSE_READ;
52 regs.regs[1] = offset;
53 regs.regs[2] = size;
54
55 smc_call(&regs);
56
57 if (regs.regs[0] == 0)
58 return -1;
59
60 memcpy(buffer, shmem_output, min(size, regs.regs[0]));
61
62 return regs.regs[0];
63}
0ef8e406
NA
64
65#define SM_CHIP_ID_LENGTH 119
66#define SM_CHIP_ID_OFFSET 4
67#define SM_CHIP_ID_SIZE 12
68
69int meson_sm_get_serial(void *buffer, size_t size)
70{
71 struct pt_regs regs;
72
73 meson_init_shmem();
74
75 regs.regs[0] = FN_CHIP_ID;
76 regs.regs[1] = 0;
77 regs.regs[2] = 0;
78
79 smc_call(&regs);
80
81 memcpy(buffer, shmem_output + SM_CHIP_ID_OFFSET,
82 min_t(size_t, size, SM_CHIP_ID_SIZE));
83
84 return 0;
85}
559e6256 86
b1dd7deb
NA
87#define AO_SEC_SD_CFG15 0xfc
88#define REBOOT_REASON_MASK GENMASK(15, 12)
89
90int meson_sm_get_reboot_reason(void)
91{
92 struct regmap *regmap;
93 int nodeoffset;
94 ofnode node;
95 unsigned int reason;
96
97 /* find the offset of compatible node */
98 nodeoffset = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
99 "amlogic,meson-gx-ao-secure");
100 if (nodeoffset < 0) {
101 printf("%s: failed to get amlogic,meson-gx-ao-secure\n",
102 __func__);
103 return -ENODEV;
104 }
105
106 /* get regmap from the syscon node */
107 node = offset_to_ofnode(nodeoffset);
108 regmap = syscon_node_to_regmap(node);
109 if (IS_ERR(regmap)) {
110 printf("%s: failed to get regmap\n", __func__);
111 return -EINVAL;
112 }
113
114 regmap_read(regmap, AO_SEC_SD_CFG15, &reason);
115
116 /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */
117 return FIELD_GET(REBOOT_REASON_MASK, reason);
118}
119
559e6256
NA
120static int do_sm_serial(cmd_tbl_t *cmdtp, int flag, int argc,
121 char *const argv[])
122{
123 ulong address;
124 int ret;
125
126 if (argc < 2)
127 return CMD_RET_USAGE;
128
129 address = simple_strtoul(argv[1], NULL, 0);
130
131 ret = meson_sm_get_serial((void *)address, SM_CHIP_ID_SIZE);
132 if (ret)
133 return CMD_RET_FAILURE;
134
135 return CMD_RET_SUCCESS;
136}
137
b1dd7deb
NA
138#define MAX_REBOOT_REASONS 14
139
140static const char *reboot_reasons[MAX_REBOOT_REASONS] = {
141 [REBOOT_REASON_COLD] = "cold_boot",
142 [REBOOT_REASON_NORMAL] = "normal",
143 [REBOOT_REASON_RECOVERY] = "recovery",
144 [REBOOT_REASON_UPDATE] = "update",
145 [REBOOT_REASON_FASTBOOT] = "fastboot",
146 [REBOOT_REASON_SUSPEND_OFF] = "suspend_off",
147 [REBOOT_REASON_HIBERNATE] = "hibernate",
148 [REBOOT_REASON_BOOTLOADER] = "bootloader",
149 [REBOOT_REASON_SHUTDOWN_REBOOT] = "shutdown_reboot",
150 [REBOOT_REASON_RPMBP] = "rpmbp",
151 [REBOOT_REASON_CRASH_DUMP] = "crash_dump",
152 [REBOOT_REASON_KERNEL_PANIC] = "kernel_panic",
153 [REBOOT_REASON_WATCHDOG_REBOOT] = "watchdog_reboot",
154};
155
156static int do_sm_reboot_reason(cmd_tbl_t *cmdtp, int flag, int argc,
157 char *const argv[])
158{
159 const char *reason_str;
160 char *destarg = NULL;
161 int reason;
162
163 if (argc > 1)
164 destarg = argv[1];
165
166 reason = meson_sm_get_reboot_reason();
167 if (reason < 0)
168 return CMD_RET_FAILURE;
169
170 if (reason >= MAX_REBOOT_REASONS ||
171 !reboot_reasons[reason])
172 reason_str = "unknown";
173 else
174 reason_str = reboot_reasons[reason];
175
176 if (destarg)
177 env_set(destarg, reason_str);
178 else
179 printf("reboot reason: %s (%x)\n", reason_str, reason);
180
181 return CMD_RET_SUCCESS;
182}
183
559e6256
NA
184static cmd_tbl_t cmd_sm_sub[] = {
185 U_BOOT_CMD_MKENT(serial, 2, 1, do_sm_serial, "", ""),
b1dd7deb 186 U_BOOT_CMD_MKENT(reboot_reason, 1, 1, do_sm_reboot_reason, "", ""),
559e6256
NA
187};
188
189static int do_sm(cmd_tbl_t *cmdtp, int flag, int argc,
190 char *const argv[])
191{
192 cmd_tbl_t *c;
193
194 if (argc < 2)
195 return CMD_RET_USAGE;
196
197 /* Strip off leading 'sm' command argument */
198 argc--;
199 argv++;
200
201 c = find_cmd_tbl(argv[0], &cmd_sm_sub[0], ARRAY_SIZE(cmd_sm_sub));
202
203 if (c)
204 return c->cmd(cmdtp, flag, argc, argv);
205 else
206 return CMD_RET_USAGE;
207}
208
209U_BOOT_CMD(
210 sm, 5, 0, do_sm,
211 "Secure Monitor Control",
b1dd7deb
NA
212 "serial <address> - read chip unique id to memory address\n"
213 "sm reboot_reason [name] - get reboot reason and store to to environment"
559e6256 214);