blob: 68f9b1a9a59130dc71305ce9f48ee17d53f9ab5f [file] [log] [blame]
Patrick Delaunay109d13f2019-07-05 17:20:17 +02001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
4 */
5
6#include <common.h>
7#include <command.h>
8#include <console.h>
Patrick Delaunayba779402020-11-06 19:01:29 +01009#include <log.h>
Patrick Delaunay109d13f2019-07-05 17:20:17 +020010#include <misc.h>
11#include <dm/device.h>
12#include <dm/uclass.h>
13
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020014/* Closed device : bit 6 of OPT0*/
15#define STM32_OTP_CLOSE_ID 0
16#define STM32_OTP_CLOSE_MASK BIT(6)
17
18/* HASH of key: 8 OTPs, starting with OTP24) */
19#define STM32_OTP_HASH_KEY_START 24
20#define STM32_OTP_HASH_KEY_SIZE 8
Patrick Delaunay109d13f2019-07-05 17:20:17 +020021
Patrick Delaunay212eafc2022-09-15 18:11:38 +020022#define BSEC_LOCK_ERROR (-1)
23#define BSEC_LOCK_PERM BIT(0)
24
Patrick Delaunaybd0233a2021-06-28 14:56:01 +020025static int get_misc_dev(struct udevice **dev)
26{
27 int ret;
28
29 ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(stm32mp_bsec), dev);
30 if (ret)
31 log_err("Can't find stm32mp_bsec driver\n");
32
33 return ret;
34}
35
Patrick Delaunay109d13f2019-07-05 17:20:17 +020036static void read_hash_value(u32 addr)
37{
38 int i;
39
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020040 printf("Read KEY at 0x%x\n", addr);
Patrick Delaunay109d13f2019-07-05 17:20:17 +020041 for (i = 0; i < STM32_OTP_HASH_KEY_SIZE; i++) {
42 printf("OTP value %i: %x\n", STM32_OTP_HASH_KEY_START + i,
43 __be32_to_cpu(*(u32 *)addr));
44 addr += 4;
45 }
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020046}
47
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +020048static int read_hash_otp(struct udevice *dev, bool print, bool *locked)
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020049{
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020050 int i, word, ret;
51 int nb_invalid = 0, nb_zero = 0, nb_lock = 0;
52 u32 val, lock;
53 bool status;
54
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020055 for (i = 0, word = STM32_OTP_HASH_KEY_START; i < STM32_OTP_HASH_KEY_SIZE; i++, word++) {
56 ret = misc_read(dev, STM32_BSEC_OTP(word), &val, 4);
57 if (ret != 4)
58 val = ~0x0;
59 ret = misc_read(dev, STM32_BSEC_LOCK(word), &lock, 4);
60 if (ret != 4)
Patrick Delaunay212eafc2022-09-15 18:11:38 +020061 lock = BSEC_LOCK_ERROR;
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020062 if (print)
Patrick Delaunay212eafc2022-09-15 18:11:38 +020063 printf("OTP HASH %i: %x lock : %x\n", word, val, lock);
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020064 if (val == ~0x0)
65 nb_invalid++;
66 else if (val == 0x0)
67 nb_zero++;
Patrick Delaunay212eafc2022-09-15 18:11:38 +020068 if (lock & BSEC_LOCK_PERM)
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020069 nb_lock++;
70 }
71
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020072 status = (nb_lock == STM32_OTP_HASH_KEY_SIZE);
73 if (locked)
74 *locked = status;
75 if (!status && print)
76 printf("Hash of key is not locked!\n");
77
78 if (nb_invalid == STM32_OTP_HASH_KEY_SIZE) {
79 if (print)
80 printf("Hash of key is invalid!\n");
81 return -EINVAL;
82 }
83 if (nb_zero == STM32_OTP_HASH_KEY_SIZE) {
84 if (print)
85 printf("Hash of key is free!\n");
86 return -ENOENT;
87 }
88
89 return 0;
Patrick Delaunay109d13f2019-07-05 17:20:17 +020090}
91
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +020092static int read_close_status(struct udevice *dev, bool print, bool *closed)
Patrick Delaunay109d13f2019-07-05 17:20:17 +020093{
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +020094 int word, ret, result;
95 u32 val, lock;
96 bool status;
97
98 result = 0;
99 word = STM32_OTP_CLOSE_ID;
100 ret = misc_read(dev, STM32_BSEC_OTP(word), &val, 4);
101 if (ret < 0)
102 result = ret;
103 if (ret != 4)
104 val = 0x0;
105
106 ret = misc_read(dev, STM32_BSEC_LOCK(word), &lock, 4);
107 if (ret < 0)
108 result = ret;
109 if (ret != 4)
110 lock = BSEC_LOCK_ERROR;
111
112 status = (val & STM32_OTP_CLOSE_MASK) == STM32_OTP_CLOSE_MASK;
113 if (closed)
114 *closed = status;
115 if (print)
116 printf("OTP %d: closed status: %d lock : %x\n", word, status, lock);
117
118 return result;
119}
120
121static int fuse_hash_value(struct udevice *dev, u32 addr, bool print)
122{
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200123 u32 word, val;
124 int i, ret;
125
Patrick Delaunaycd8bfb32021-06-28 14:56:00 +0200126 for (i = 0, word = STM32_OTP_HASH_KEY_START;
127 i < STM32_OTP_HASH_KEY_SIZE;
128 i++, word++, addr += 4) {
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200129 val = __be32_to_cpu(*(u32 *)addr);
Patrick Delaunayc80a0e42021-06-28 14:55:59 +0200130 if (print)
131 printf("Fuse OTP %i : %x\n", word, val);
132
133 ret = misc_write(dev, STM32_BSEC_OTP(word), &val, 4);
134 if (ret != 4) {
135 log_err("Fuse OTP %i failed\n", word);
136 return ret;
137 }
Patrick Delaunaycd8bfb32021-06-28 14:56:00 +0200138 /* on success, lock the OTP for HASH key */
Patrick Delaunay212eafc2022-09-15 18:11:38 +0200139 val = BSEC_LOCK_PERM;
Patrick Delaunaycd8bfb32021-06-28 14:56:00 +0200140 ret = misc_write(dev, STM32_BSEC_LOCK(word), &val, 4);
141 if (ret != 4) {
142 log_err("Lock OTP %i failed\n", word);
143 return ret;
144 }
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200145 }
Patrick Delaunayc80a0e42021-06-28 14:55:59 +0200146
147 return 0;
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200148}
149
150static int confirm_prog(void)
151{
152 puts("Warning: Programming fuses is an irreversible operation!\n"
153 " This may brick your system.\n"
154 " Use this command only if you are sure of what you are doing!\n"
155 "\nReally perform this fuse programming? <y/N>\n");
156
157 if (confirm_yesno())
158 return 1;
159
160 puts("Fuse programming aborted\n");
161 return 0;
162}
163
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200164static int do_stm32key_read(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200165{
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200166 struct udevice *dev;
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200167 u32 addr;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200168 int ret;
169
170 ret = get_misc_dev(&dev);
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200171
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200172 if (argc == 1) {
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200173 if (ret)
174 return CMD_RET_FAILURE;
175 read_hash_otp(dev, true, NULL);
176 ret = read_close_status(dev, true, NULL);
177 if (ret)
178 return CMD_RET_FAILURE;
179
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200180 return CMD_RET_SUCCESS;
181 }
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200182
Simon Glass3ff49ec2021-07-24 09:03:29 -0600183 addr = hextoul(argv[1], NULL);
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200184 if (!addr)
185 return CMD_RET_USAGE;
186
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200187 read_hash_value(addr);
188
189 return CMD_RET_SUCCESS;
190}
191
192static int do_stm32key_fuse(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
193{
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200194 struct udevice *dev;
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200195 u32 addr;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200196 int ret;
197 bool yes = false, lock;
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200198
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200199 if (argc < 2)
200 return CMD_RET_USAGE;
201
202 if (argc == 3) {
203 if (strcmp(argv[1], "-y"))
204 return CMD_RET_USAGE;
205 yes = true;
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200206 }
207
Simon Glass3ff49ec2021-07-24 09:03:29 -0600208 addr = hextoul(argv[argc - 1], NULL);
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200209 if (!addr)
210 return CMD_RET_USAGE;
211
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200212 ret = get_misc_dev(&dev);
213 if (ret)
214 return CMD_RET_FAILURE;
215
216 if (read_hash_otp(dev, !yes, &lock) != -ENOENT) {
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200217 printf("Error: can't fuse again the OTP\n");
218 return CMD_RET_FAILURE;
219 }
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200220 if (lock) {
221 printf("Error: PKH is locked\n");
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200222 return CMD_RET_FAILURE;
223 }
224
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200225 if (!yes && !confirm_prog())
226 return CMD_RET_FAILURE;
227
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200228 if (fuse_hash_value(dev, addr, !yes))
Patrick Delaunayc80a0e42021-06-28 14:55:59 +0200229 return CMD_RET_FAILURE;
230
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200231 printf("Hash key updated !\n");
232
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200233 return CMD_RET_SUCCESS;
234}
235
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200236static int do_stm32key_close(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
237{
238 bool yes, lock, closed;
239 struct udevice *dev;
240 u32 val;
241 int ret;
242
243 yes = false;
244 if (argc == 2) {
245 if (strcmp(argv[1], "-y"))
246 return CMD_RET_USAGE;
247 yes = true;
248 }
249
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200250 ret = get_misc_dev(&dev);
251 if (ret)
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200252 return CMD_RET_FAILURE;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200253
254 if (read_close_status(dev, !yes, &closed))
255 return CMD_RET_FAILURE;
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200256
257 if (closed) {
258 printf("Error: already closed!\n");
259 return CMD_RET_FAILURE;
260 }
261
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200262 /* check PKH status before to close */
263 ret = read_hash_otp(dev, !yes, &lock);
264 if (ret) {
265 if (ret == -ENOENT)
266 printf("Error: OTP not programmed!\n");
267 return CMD_RET_FAILURE;
268 }
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200269 if (!lock)
270 printf("Warning: OTP not locked!\n");
271
272 if (!yes && !confirm_prog())
273 return CMD_RET_FAILURE;
274
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200275 val = STM32_OTP_CLOSE_MASK;
276 ret = misc_write(dev, STM32_BSEC_OTP(STM32_OTP_CLOSE_ID), &val, 4);
277 if (ret != 4) {
278 printf("Error: can't update OTP\n");
279 return CMD_RET_FAILURE;
280 }
281
282 printf("Device is closed !\n");
283
284 return CMD_RET_SUCCESS;
285}
286
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200287static char stm32key_help_text[] =
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200288 "read [<addr>]: Read the hash stored at addr in memory or in OTP\n"
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200289 "stm32key fuse [-y] <addr> : Fuse hash stored at addr in OTP\n"
290 "stm32key close [-y] : Close the device, the hash stored in OTP\n";
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200291
292U_BOOT_CMD_WITH_SUBCMDS(stm32key, "Fuse ST Hash key", stm32key_help_text,
293 U_BOOT_SUBCMD_MKENT(read, 2, 0, do_stm32key_read),
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200294 U_BOOT_SUBCMD_MKENT(fuse, 3, 0, do_stm32key_fuse),
295 U_BOOT_SUBCMD_MKENT(close, 2, 0, do_stm32key_close));