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