blob: 6bfa67859e1bbf044866cbbe612e4be7812a0a15 [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
Patrick Delaunay109d13f2019-07-05 17:20:17 +02006#include <command.h>
7#include <console.h>
Patrick Delaunayba779402020-11-06 19:01:29 +01008#include <log.h>
Patrick Delaunay109d13f2019-07-05 17:20:17 +02009#include <misc.h>
Patrick Delaunayd5388292023-01-06 13:20:15 +010010#include <asm/arch/bsec.h>
Patrick Delaunay109d13f2019-07-05 17:20:17 +020011#include <dm/device.h>
12#include <dm/uclass.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060013#include <linux/printk.h>
Patrick Delaunay109d13f2019-07-05 17:20:17 +020014
Patrick Delaunayba1013c2022-09-15 18:11:41 +020015/*
16 * Closed device: OTP0
Patrice Chotard47f02212021-12-10 11:05:16 +010017 * STM32MP15x: bit 6 of OTP0
Patrick Delaunayba1013c2022-09-15 18:11:41 +020018 * STM32MP13x: 0b111111 = 0x3F for OTP_SECURED closed device
Patrice Chotard47f02212021-12-10 11:05:16 +010019 * STM32MP25x: bit 0 of OTP18
Patrick Delaunayba1013c2022-09-15 18:11:41 +020020 */
Patrice Chotard47f02212021-12-10 11:05:16 +010021#define STM32MP1_OTP_CLOSE_ID 0
22#define STM32_OTP_STM32MP13X_CLOSE_MASK GENMASK(5, 0)
23#define STM32_OTP_STM32MP15X_CLOSE_MASK BIT(6)
24#define STM32MP25_OTP_WORD8 8
25#define STM32_OTP_STM32MP25X_BOOTROM_CLOSE_MASK GENMASK(7, 0)
26#define STM32MP25_OTP_CLOSE_ID 18
27#define STM32_OTP_STM32MP25X_CLOSE_MASK GENMASK(3, 0)
28#define STM32_OTP_STM32MP25X_PROVISIONING_DONE_MASK GENMASK(7, 4)
29#define STM32MP25_OTP_HWCONFIG 124
30#define STM32_OTP_STM32MP25X_DISABLE_SCAN_MASK BIT(20)
31
32#define STM32MP25_OTP_BOOTROM_CONF8 17
33#define STM32_OTP_STM32MP25X_OEM_KEY2_EN BIT(8)
Patrick Delaunay7b094ea2021-06-28 14:56:02 +020034
Patrick Delaunay424876f2022-09-15 18:11:40 +020035/* PKH is the first element of the key list */
36#define STM32KEY_PKH 0
37
38struct stm32key {
39 char *name;
40 char *desc;
Patrice Chotard47f02212021-12-10 11:05:16 +010041 u16 start;
Patrick Delaunay424876f2022-09-15 18:11:40 +020042 u8 size;
Patrice Chotard47f02212021-12-10 11:05:16 +010043 int (*post_process)(struct udevice *dev);
Patrick Delaunay424876f2022-09-15 18:11:40 +020044};
45
Patrick Delaunayba1013c2022-09-15 18:11:41 +020046const struct stm32key stm32mp13_list[] = {
47 [STM32KEY_PKH] = {
48 .name = "PKHTH",
49 .desc = "Hash of the 8 ECC Public Keys Hashes Table (ECDSA is the authentication algorithm)",
50 .start = 24,
51 .size = 8,
52 },
53 {
54 .name = "EDMK",
55 .desc = "Encryption/Decryption Master Key",
56 .start = 92,
57 .size = 4,
58 }
59};
60
Patrick Delaunay424876f2022-09-15 18:11:40 +020061const struct stm32key stm32mp15_list[] = {
62 [STM32KEY_PKH] = {
63 .name = "PKH",
64 .desc = "Hash of the ECC Public Key (ECDSA is the authentication algorithm)",
65 .start = 24,
66 .size = 8,
Patrice Chotard47f02212021-12-10 11:05:16 +010067 }
68};
69
70static int post_process_oem_key2(struct udevice *dev);
71
72const struct stm32key stm32mp25_list[] = {
73 [STM32KEY_PKH] = {
74 .name = "OEM-KEY1",
75 .desc = "Hash of the 8 ECC Public Keys Hashes Table (ECDSA is the authentication algorithm) for FSBLA or M",
76 .start = 144,
77 .size = 8,
78 },
79 {
80 .name = "OEM-KEY2",
81 .desc = "Hash of the 8 ECC Public Keys Hashes Table (ECDSA is the authentication algorithm) for FSBLM",
82 .start = 152,
83 .size = 8,
84 .post_process = post_process_oem_key2,
85 },
86 {
87 .name = "FIP-EDMK",
88 .desc = "Encryption/Decryption Master Key for FIP",
89 .start = 260,
90 .size = 8,
91 },
92 {
93 .name = "EDMK1",
94 .desc = "Encryption/Decryption Master Key for FSBLA or M",
95 .start = 364,
96 .size = 4,
97 },
98 {
99 .name = "EDMK2",
100 .desc = "Encryption/Decryption Master Key for FSBLM",
101 .start = 360,
102 .size = 4,
103 }
104};
105
106struct otp_close {
107 u32 word;
108 u32 mask_wr;
109 u32 mask_rd;
110 bool (*close_status_ops)(u32 value, u32 mask);
111};
112
113static bool compare_mask_exact(u32 value, u32 mask)
114{
115 return ((value & mask) == mask);
116}
117
118static bool compare_any_bits(u32 value, u32 mask)
119{
120 return ((value & mask) != 0);
121}
122
123const struct otp_close stm32mp13_close_state_otp[] = {
124 {
125 .word = STM32MP1_OTP_CLOSE_ID,
126 .mask_wr = STM32_OTP_STM32MP13X_CLOSE_MASK,
127 .mask_rd = STM32_OTP_STM32MP13X_CLOSE_MASK,
128 .close_status_ops = compare_mask_exact,
129 }
130};
131
132const struct otp_close stm32mp15_close_state_otp[] = {
133 {
134 .word = STM32MP1_OTP_CLOSE_ID,
135 .mask_wr = STM32_OTP_STM32MP15X_CLOSE_MASK,
136 .mask_rd = STM32_OTP_STM32MP15X_CLOSE_MASK,
137 .close_status_ops = compare_mask_exact,
Patrick Delaunay424876f2022-09-15 18:11:40 +0200138 }
139};
140
Patrice Chotard47f02212021-12-10 11:05:16 +0100141const struct otp_close stm32mp25_close_state_otp[] = {
142 {
143 .word = STM32MP25_OTP_WORD8,
144 .mask_wr = STM32_OTP_STM32MP25X_BOOTROM_CLOSE_MASK,
145 .mask_rd = 0,
146 .close_status_ops = NULL
147 },
148 {
149 .word = STM32MP25_OTP_CLOSE_ID,
150 .mask_wr = STM32_OTP_STM32MP25X_CLOSE_MASK |
151 STM32_OTP_STM32MP25X_PROVISIONING_DONE_MASK,
152 .mask_rd = STM32_OTP_STM32MP25X_CLOSE_MASK,
153 .close_status_ops = compare_any_bits
154 },
155 {
156 .word = STM32MP25_OTP_HWCONFIG,
157 .mask_wr = STM32_OTP_STM32MP25X_DISABLE_SCAN_MASK,
158 .mask_rd = 0,
159 .close_status_ops = NULL
160 },
161};
162
Patrick Delaunay424876f2022-09-15 18:11:40 +0200163/* index of current selected key in stm32key list, 0 = PKH by default */
164static u8 stm32key_index;
165
166static u8 get_key_nb(void)
167{
Patrick Delaunay990e0572024-01-15 15:05:56 +0100168 if (IS_ENABLED(CONFIG_STM32MP13X))
Patrick Delaunayba1013c2022-09-15 18:11:41 +0200169 return ARRAY_SIZE(stm32mp13_list);
170
Patrick Delaunay4c6fcbc2024-01-15 15:05:57 +0100171 if (IS_ENABLED(CONFIG_STM32MP15X))
Patrick Delaunayba1013c2022-09-15 18:11:41 +0200172 return ARRAY_SIZE(stm32mp15_list);
Patrice Chotard47f02212021-12-10 11:05:16 +0100173
174 if (IS_ENABLED(CONFIG_STM32MP25X))
175 return ARRAY_SIZE(stm32mp25_list);
Patrick Delaunay424876f2022-09-15 18:11:40 +0200176}
177
178static const struct stm32key *get_key(u8 index)
179{
Patrick Delaunay990e0572024-01-15 15:05:56 +0100180 if (IS_ENABLED(CONFIG_STM32MP13X))
Patrick Delaunayba1013c2022-09-15 18:11:41 +0200181 return &stm32mp13_list[index];
182
Patrick Delaunay4c6fcbc2024-01-15 15:05:57 +0100183 if (IS_ENABLED(CONFIG_STM32MP15X))
Patrick Delaunayba1013c2022-09-15 18:11:41 +0200184 return &stm32mp15_list[index];
Patrice Chotard47f02212021-12-10 11:05:16 +0100185
186 if (IS_ENABLED(CONFIG_STM32MP25X))
187 return &stm32mp25_list[index];
188}
189
190static u8 get_otp_close_state_nb(void)
191{
192 if (IS_ENABLED(CONFIG_STM32MP13X))
193 return ARRAY_SIZE(stm32mp13_close_state_otp);
194
195 if (IS_ENABLED(CONFIG_STM32MP15X))
196 return ARRAY_SIZE(stm32mp15_close_state_otp);
197
198 if (IS_ENABLED(CONFIG_STM32MP25X))
199 return ARRAY_SIZE(stm32mp25_close_state_otp);
Patrick Delaunayba1013c2022-09-15 18:11:41 +0200200}
201
Patrice Chotard47f02212021-12-10 11:05:16 +0100202static const struct otp_close *get_otp_close_state(u8 index)
Patrick Delaunayba1013c2022-09-15 18:11:41 +0200203{
Patrick Delaunay990e0572024-01-15 15:05:56 +0100204 if (IS_ENABLED(CONFIG_STM32MP13X))
Patrice Chotard47f02212021-12-10 11:05:16 +0100205 return &stm32mp13_close_state_otp[index];
Patrick Delaunayba1013c2022-09-15 18:11:41 +0200206
Patrick Delaunay4c6fcbc2024-01-15 15:05:57 +0100207 if (IS_ENABLED(CONFIG_STM32MP15X))
Patrice Chotard47f02212021-12-10 11:05:16 +0100208 return &stm32mp15_close_state_otp[index];
209
210 if (IS_ENABLED(CONFIG_STM32MP25X))
211 return &stm32mp25_close_state_otp[index];
Patrick Delaunay424876f2022-09-15 18:11:40 +0200212}
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200213
Patrick Delaunaybd0233a2021-06-28 14:56:01 +0200214static int get_misc_dev(struct udevice **dev)
215{
216 int ret;
217
218 ret = uclass_get_device_by_driver(UCLASS_MISC, DM_DRIVER_GET(stm32mp_bsec), dev);
219 if (ret)
220 log_err("Can't find stm32mp_bsec driver\n");
221
222 return ret;
223}
224
Patrice Chotard47f02212021-12-10 11:05:16 +0100225static void read_key_value(const struct stm32key *key, unsigned long addr)
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200226{
227 int i;
228
Patrick Delaunay424876f2022-09-15 18:11:40 +0200229 for (i = 0; i < key->size; i++) {
230 printf("%s OTP %i: [%08x] %08x\n", key->name, key->start + i,
Patrice Chotard47f02212021-12-10 11:05:16 +0100231 (u32)addr, __be32_to_cpu(*(u32 *)addr));
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200232 addr += 4;
233 }
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200234}
235
Patrick Delaunay424876f2022-09-15 18:11:40 +0200236static int read_key_otp(struct udevice *dev, const struct stm32key *key, bool print, bool *locked)
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200237{
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200238 int i, word, ret;
Patrick Delaunay424876f2022-09-15 18:11:40 +0200239 int nb_invalid = 0, nb_zero = 0, nb_lock = 0, nb_lock_err = 0;
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200240 u32 val, lock;
241 bool status;
242
Patrick Delaunay424876f2022-09-15 18:11:40 +0200243 for (i = 0, word = key->start; i < key->size; i++, word++) {
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200244 ret = misc_read(dev, STM32_BSEC_OTP(word), &val, 4);
245 if (ret != 4)
246 val = ~0x0;
247 ret = misc_read(dev, STM32_BSEC_LOCK(word), &lock, 4);
248 if (ret != 4)
Patrick Delaunay212eafc2022-09-15 18:11:38 +0200249 lock = BSEC_LOCK_ERROR;
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200250 if (print)
Patrick Delaunay424876f2022-09-15 18:11:40 +0200251 printf("%s OTP %i: %08x lock : %08x\n", key->name, word, val, lock);
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200252 if (val == ~0x0)
253 nb_invalid++;
254 else if (val == 0x0)
255 nb_zero++;
Patrick Delaunay212eafc2022-09-15 18:11:38 +0200256 if (lock & BSEC_LOCK_PERM)
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200257 nb_lock++;
Patrick Delaunay424876f2022-09-15 18:11:40 +0200258 if (lock & BSEC_LOCK_ERROR)
259 nb_lock_err++;
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200260 }
261
Patrick Delaunay424876f2022-09-15 18:11:40 +0200262 status = nb_lock_err || (nb_lock == key->size);
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200263 if (locked)
264 *locked = status;
Patrick Delaunay424876f2022-09-15 18:11:40 +0200265 if (nb_lock_err && print)
266 printf("%s lock is invalid!\n", key->name);
267 else if (!status && print)
268 printf("%s is not locked!\n", key->name);
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200269
Patrick Delaunay424876f2022-09-15 18:11:40 +0200270 if (nb_invalid == key->size) {
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200271 if (print)
Patrick Delaunay424876f2022-09-15 18:11:40 +0200272 printf("%s is invalid!\n", key->name);
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200273 return -EINVAL;
274 }
Patrick Delaunay424876f2022-09-15 18:11:40 +0200275 if (nb_zero == key->size) {
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200276 if (print)
Patrick Delaunay424876f2022-09-15 18:11:40 +0200277 printf("%s is free!\n", key->name);
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200278 return -ENOENT;
279 }
280
281 return 0;
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200282}
283
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200284static int read_close_status(struct udevice *dev, bool print, bool *closed)
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200285{
Patrice Chotard47f02212021-12-10 11:05:16 +0100286 int ret, result, i;
287 const struct otp_close *otp_close = NULL;
288 u32 otp_close_nb = get_otp_close_state_nb();
289 u32 val, lock, mask, word = 0;
290 bool status = true;
291 bool tested_once = false;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200292
293 result = 0;
Patrice Chotard47f02212021-12-10 11:05:16 +0100294 for (i = 0; status && (i < otp_close_nb); i++) {
295 otp_close = get_otp_close_state(i);
296
297 if (!otp_close->close_status_ops)
298 continue;
299
300 mask = otp_close->mask_rd;
301 word = otp_close->word;
302
303 ret = misc_read(dev, STM32_BSEC_OTP(word), &val, 4);
304 if (ret < 0)
305 result = ret;
306 if (ret != 4)
307 val = 0x0;
308
309 ret = misc_read(dev, STM32_BSEC_LOCK(word), &lock, 4);
310 if (ret < 0)
311 result = ret;
312 if (ret != 4)
313 lock = BSEC_LOCK_ERROR;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200314
Patrice Chotard47f02212021-12-10 11:05:16 +0100315 status = otp_close->close_status_ops(val, mask);
316 tested_once = true;
317 }
318
319 if (!tested_once)
320 status = false;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200321
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200322 if (closed)
323 *closed = status;
324 if (print)
Patrick Delaunay424876f2022-09-15 18:11:40 +0200325 printf("OTP %d: closed status: %d lock : %08x\n", word, status, lock);
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200326
327 return result;
328}
329
Patrice Chotard47f02212021-12-10 11:05:16 +0100330static int write_close_status(struct udevice *dev)
331{
332 int i;
333 u32 val, word, ret;
334 const struct otp_close *otp_close = NULL;
335 u32 otp_num = get_otp_close_state_nb();
336
337 for (i = 0; i < otp_num; i++) {
338 otp_close = get_otp_close_state(i);
339 val = otp_close->mask_wr;
340 word = otp_close->word;
341 ret = misc_write(dev, STM32_BSEC_OTP(word), &val, 4);
342 if (ret != 4) {
343 log_err("Error: can't update OTP %d\n", word);
344 return ret;
345 }
346 }
347 return 0;
348}
349
350static int post_process_oem_key2(struct udevice *dev)
351{
352 int ret;
353 u32 val;
354
355 ret = misc_read(dev, STM32_BSEC_OTP(STM32MP25_OTP_BOOTROM_CONF8), &val, 4);
356 if (ret != 4) {
357 log_err("Error %d failed to read STM32MP25_OTP_BOOTROM_CONF8\n", ret);
358 return -EIO;
359 }
360
361 val |= STM32_OTP_STM32MP25X_OEM_KEY2_EN;
362 ret = misc_write(dev, STM32_BSEC_OTP(STM32MP25_OTP_BOOTROM_CONF8), &val, 4);
363 if (ret != 4) {
364 log_err("Error %d failed to write OEM_KEY2_ENABLE\n", ret);
365 return -EIO;
366 }
367
368 return 0;
369}
370
371static int fuse_key_value(struct udevice *dev, const struct stm32key *key, unsigned long addr,
372 bool print)
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200373{
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200374 u32 word, val;
375 int i, ret;
376
Patrick Delaunay424876f2022-09-15 18:11:40 +0200377 for (i = 0, word = key->start; i < key->size; i++, word++, addr += 4) {
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200378 val = __be32_to_cpu(*(u32 *)addr);
Patrick Delaunayc80a0e42021-06-28 14:55:59 +0200379 if (print)
Patrick Delaunay424876f2022-09-15 18:11:40 +0200380 printf("Fuse %s OTP %i : %08x\n", key->name, word, val);
Patrick Delaunayc80a0e42021-06-28 14:55:59 +0200381
382 ret = misc_write(dev, STM32_BSEC_OTP(word), &val, 4);
383 if (ret != 4) {
Patrick Delaunay424876f2022-09-15 18:11:40 +0200384 log_err("Fuse %s OTP %i failed\n", key->name, word);
Patrick Delaunayc80a0e42021-06-28 14:55:59 +0200385 return ret;
386 }
Patrick Delaunay424876f2022-09-15 18:11:40 +0200387 /* on success, lock the OTP for the key */
Patrick Delaunay212eafc2022-09-15 18:11:38 +0200388 val = BSEC_LOCK_PERM;
Patrick Delaunaycd8bfb32021-06-28 14:56:00 +0200389 ret = misc_write(dev, STM32_BSEC_LOCK(word), &val, 4);
390 if (ret != 4) {
Patrick Delaunay424876f2022-09-15 18:11:40 +0200391 log_err("Lock %s OTP %i failed\n", key->name, word);
Patrick Delaunaycd8bfb32021-06-28 14:56:00 +0200392 return ret;
393 }
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200394 }
Patrick Delaunayc80a0e42021-06-28 14:55:59 +0200395
396 return 0;
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200397}
398
399static int confirm_prog(void)
400{
401 puts("Warning: Programming fuses is an irreversible operation!\n"
402 " This may brick your system.\n"
403 " Use this command only if you are sure of what you are doing!\n"
404 "\nReally perform this fuse programming? <y/N>\n");
405
406 if (confirm_yesno())
407 return 1;
408
409 puts("Fuse programming aborted\n");
410 return 0;
411}
412
Patrick Delaunay424876f2022-09-15 18:11:40 +0200413static void display_key_info(const struct stm32key *key)
414{
415 printf("%s : %s\n", key->name, key->desc);
Patrice Chotard47f02212021-12-10 11:05:16 +0100416 printf("\tOTP%d..%d\n", key->start, key->start + key->size - 1);
Patrick Delaunay424876f2022-09-15 18:11:40 +0200417}
418
419static int do_stm32key_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
420{
421 int i;
422
423 for (i = 0; i < get_key_nb(); i++)
424 display_key_info(get_key(i));
425
426 return CMD_RET_SUCCESS;
427}
428
429static int do_stm32key_select(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
430{
431 const struct stm32key *key;
432 int i;
433
434 if (argc == 1) {
435 printf("Selected key:\n");
436 key = get_key(stm32key_index);
437 display_key_info(key);
438 return CMD_RET_SUCCESS;
439 }
440
441 for (i = 0; i < get_key_nb(); i++) {
442 key = get_key(i);
443 if (!strcmp(key->name, argv[1])) {
444 printf("%s selected\n", key->name);
445 stm32key_index = i;
446 return CMD_RET_SUCCESS;
447 }
448 }
449
450 printf("Unknown key %s\n", argv[1]);
451
452 return CMD_RET_FAILURE;
453}
454
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200455static int do_stm32key_read(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200456{
Patrick Delaunay424876f2022-09-15 18:11:40 +0200457 const struct stm32key *key;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200458 struct udevice *dev;
Patrice Chotard47f02212021-12-10 11:05:16 +0100459 unsigned long addr;
Patrick Delaunay424876f2022-09-15 18:11:40 +0200460 int ret, i;
461 int result;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200462
463 ret = get_misc_dev(&dev);
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200464
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200465 if (argc == 1) {
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200466 if (ret)
467 return CMD_RET_FAILURE;
Patrick Delaunay424876f2022-09-15 18:11:40 +0200468 key = get_key(stm32key_index);
469 ret = read_key_otp(dev, key, true, NULL);
470 if (ret != -ENOENT)
471 return CMD_RET_FAILURE;
472 return CMD_RET_SUCCESS;
473 }
474
475 if (!strcmp("-a", argv[1])) {
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200476 if (ret)
477 return CMD_RET_FAILURE;
Patrick Delaunay424876f2022-09-15 18:11:40 +0200478 result = CMD_RET_SUCCESS;
479 for (i = 0; i < get_key_nb(); i++) {
480 key = get_key(i);
481 ret = read_key_otp(dev, key, true, NULL);
482 if (ret != -ENOENT)
483 result = CMD_RET_FAILURE;
484 }
485 ret = read_close_status(dev, true, NULL);
486 if (ret)
487 result = CMD_RET_FAILURE;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200488
Patrick Delaunay424876f2022-09-15 18:11:40 +0200489 return result;
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200490 }
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200491
Simon Glass3ff49ec2021-07-24 09:03:29 -0600492 addr = hextoul(argv[1], NULL);
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200493 if (!addr)
494 return CMD_RET_USAGE;
495
Patrick Delaunay424876f2022-09-15 18:11:40 +0200496 key = get_key(stm32key_index);
Patrice Chotard47f02212021-12-10 11:05:16 +0100497 printf("Read %s at 0x%08x\n", key->name, (u32)addr);
Patrick Delaunay424876f2022-09-15 18:11:40 +0200498 read_key_value(key, addr);
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200499
500 return CMD_RET_SUCCESS;
501}
502
503static int do_stm32key_fuse(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
504{
Patrick Delaunay424876f2022-09-15 18:11:40 +0200505 const struct stm32key *key = get_key(stm32key_index);
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200506 struct udevice *dev;
Patrice Chotard47f02212021-12-10 11:05:16 +0100507 unsigned long addr;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200508 int ret;
509 bool yes = false, lock;
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200510
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200511 if (argc < 2)
512 return CMD_RET_USAGE;
513
514 if (argc == 3) {
515 if (strcmp(argv[1], "-y"))
516 return CMD_RET_USAGE;
517 yes = true;
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200518 }
519
Simon Glass3ff49ec2021-07-24 09:03:29 -0600520 addr = hextoul(argv[argc - 1], NULL);
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200521 if (!addr)
522 return CMD_RET_USAGE;
523
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200524 ret = get_misc_dev(&dev);
525 if (ret)
526 return CMD_RET_FAILURE;
527
Patrick Delaunay424876f2022-09-15 18:11:40 +0200528 if (read_key_otp(dev, key, !yes, &lock) != -ENOENT) {
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200529 printf("Error: can't fuse again the OTP\n");
530 return CMD_RET_FAILURE;
531 }
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200532 if (lock) {
Patrick Delaunay424876f2022-09-15 18:11:40 +0200533 printf("Error: %s is locked\n", key->name);
Patrick Delaunay7b094ea2021-06-28 14:56:02 +0200534 return CMD_RET_FAILURE;
535 }
536
Patrick Delaunay424876f2022-09-15 18:11:40 +0200537 if (!yes) {
538 printf("Writing %s with\n", key->name);
539 read_key_value(key, addr);
540 }
541
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200542 if (!yes && !confirm_prog())
543 return CMD_RET_FAILURE;
544
Patrick Delaunay424876f2022-09-15 18:11:40 +0200545 if (fuse_key_value(dev, key, addr, !yes))
Patrick Delaunayc80a0e42021-06-28 14:55:59 +0200546 return CMD_RET_FAILURE;
547
Patrice Chotard47f02212021-12-10 11:05:16 +0100548 if (key->post_process) {
549 if (key->post_process(dev)) {
550 printf("Error: %s for post process\n", key->name);
551 return CMD_RET_FAILURE;
552 }
553 }
554
Patrick Delaunay424876f2022-09-15 18:11:40 +0200555 printf("%s updated !\n", key->name);
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200556
Patrick Delaunay109d13f2019-07-05 17:20:17 +0200557 return CMD_RET_SUCCESS;
558}
559
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200560static int do_stm32key_close(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
561{
Patrick Delaunay424876f2022-09-15 18:11:40 +0200562 const struct stm32key *key;
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200563 bool yes, lock, closed;
564 struct udevice *dev;
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200565 int ret;
566
567 yes = false;
568 if (argc == 2) {
569 if (strcmp(argv[1], "-y"))
570 return CMD_RET_USAGE;
571 yes = true;
572 }
573
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200574 ret = get_misc_dev(&dev);
575 if (ret)
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200576 return CMD_RET_FAILURE;
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200577
578 if (read_close_status(dev, !yes, &closed))
579 return CMD_RET_FAILURE;
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200580
581 if (closed) {
582 printf("Error: already closed!\n");
583 return CMD_RET_FAILURE;
584 }
585
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200586 /* check PKH status before to close */
Patrick Delaunay424876f2022-09-15 18:11:40 +0200587 key = get_key(STM32KEY_PKH);
588 ret = read_key_otp(dev, key, !yes, &lock);
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200589 if (ret) {
590 if (ret == -ENOENT)
Patrick Delaunay424876f2022-09-15 18:11:40 +0200591 printf("Error: %s not programmed!\n", key->name);
Patrick Delaunay9b7c4d32022-09-15 18:11:39 +0200592 return CMD_RET_FAILURE;
593 }
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200594 if (!lock)
Patrick Delaunay424876f2022-09-15 18:11:40 +0200595 printf("Warning: %s not locked!\n", key->name);
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200596
597 if (!yes && !confirm_prog())
598 return CMD_RET_FAILURE;
599
Patrice Chotard47f02212021-12-10 11:05:16 +0100600 if (write_close_status(dev))
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200601 return CMD_RET_FAILURE;
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200602
603 printf("Device is closed !\n");
604
605 return CMD_RET_SUCCESS;
606}
607
Tom Rini4c1ca0d2024-06-19 10:09:44 -0600608U_BOOT_LONGHELP(stm32key,
Patrick Delaunay424876f2022-09-15 18:11:40 +0200609 "list : list the supported key with description\n"
610 "stm32key select [<key>] : Select the key identified by <key> or display the key used for read/fuse command\n"
611 "stm32key read [<addr> | -a ] : Read the curent key at <addr> or current / all (-a) key in OTP\n"
612 "stm32key fuse [-y] <addr> : Fuse the current key at addr in OTP\n"
Tom Rini4c1ca0d2024-06-19 10:09:44 -0600613 "stm32key close [-y] : Close the device\n");
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200614
Patrick Delaunay424876f2022-09-15 18:11:40 +0200615U_BOOT_CMD_WITH_SUBCMDS(stm32key, "Manage key on STM32", stm32key_help_text,
616 U_BOOT_SUBCMD_MKENT(list, 1, 0, do_stm32key_list),
617 U_BOOT_SUBCMD_MKENT(select, 2, 0, do_stm32key_select),
Patrick Delaunay8b5fe512021-06-28 14:55:58 +0200618 U_BOOT_SUBCMD_MKENT(read, 2, 0, do_stm32key_read),
Patrick Delaunayf4a9b4b2021-06-28 14:56:03 +0200619 U_BOOT_SUBCMD_MKENT(fuse, 3, 0, do_stm32key_fuse),
620 U_BOOT_SUBCMD_MKENT(close, 2, 0, do_stm32key_close));
Patrick Delaunayf2de19d2024-03-20 15:51:08 +0100621
622/*
623 * Check the "closed" state in product life cycle, when product secrets have
624 * been provisioned into the device, by SSP tools for example.
625 * On closed devices, authentication is mandatory.
626 */
627bool stm32mp_is_closed(void)
628{
629 struct udevice *dev;
630 bool closed;
631 int ret;
632
633 ret = get_misc_dev(&dev);
634 if (ret)
635 return false;
636
637 ret = read_close_status(dev, false, &closed);
638 if (ret)
639 return false;
640
641 return closed;
642}