blob: db07d1c5cd15112bd3b99064a4f8f0cefac30c1b [file] [log] [blame]
Yann Gautier36a1e4b2019-01-17 14:52:47 +01001/*
Patrick Delaunaye720b5b2022-12-14 13:45:04 +01002 * Copyright (c) 2017-2024, STMicroelectronics - All Rights Reserved
Yann Gautier36a1e4b2019-01-17 14:52:47 +01003 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <limits.h>
9
Yann Gautier36a1e4b2019-01-17 14:52:47 +010010#include <arch_helpers.h>
11#include <common/debug.h>
12#include <drivers/st/bsec.h>
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +020013#include <drivers/st/bsec2_reg.h>
Yann Gautier36a1e4b2019-01-17 14:52:47 +010014#include <lib/mmio.h>
15#include <lib/spinlock.h>
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +020016#include <libfdt.h>
17
18#include <platform_def.h>
Yann Gautier36a1e4b2019-01-17 14:52:47 +010019
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +020020#define BSEC_IP_VERSION_1_1 U(0x11)
21#define BSEC_IP_VERSION_2_0 U(0x20)
22#define BSEC_IP_ID_2 U(0x100032)
Yann Gautier36a1e4b2019-01-17 14:52:47 +010023
Patrick Delaunaye720b5b2022-12-14 13:45:04 +010024/*
25 * IP configuration
26 */
27#define BSEC_OTP_MASK GENMASK(4, 0)
28#define BSEC_OTP_BANK_SHIFT 5
29#define BSEC_TIMEOUT_VALUE U(0xFFFF)
30
Yann Gautier36a1e4b2019-01-17 14:52:47 +010031#define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT)
32
Patrick Delaunaye720b5b2022-12-14 13:45:04 +010033static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __maybe_unused;
Yann Gautier36a1e4b2019-01-17 14:52:47 +010034
Patrick Delaunaye720b5b2022-12-14 13:45:04 +010035static uint32_t bsec_shadow_register(uint32_t otp);
Yann Gautier36a1e4b2019-01-17 14:52:47 +010036static uint32_t bsec_power_safmem(bool power);
Patrick Delaunaye720b5b2022-12-14 13:45:04 +010037static uint32_t bsec_get_version(void);
38static uint32_t bsec_get_id(void);
39static uint32_t bsec_get_status(void);
40static uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value);
Yann Gautier36a1e4b2019-01-17 14:52:47 +010041
42/* BSEC access protection */
43static spinlock_t bsec_spinlock;
Yann Gautier36a1e4b2019-01-17 14:52:47 +010044
45static void bsec_lock(void)
46{
Yann Gautierf540a592019-05-22 19:13:51 +020047 if (stm32mp_lock_available()) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +010048 spin_lock(&bsec_spinlock);
49 }
50}
51
52static void bsec_unlock(void)
53{
Yann Gautierf540a592019-05-22 19:13:51 +020054 if (stm32mp_lock_available()) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +010055 spin_unlock(&bsec_spinlock);
56 }
57}
58
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +020059static bool is_otp_invalid_mode(void)
60{
Patrick Delaunaye720b5b2022-12-14 13:45:04 +010061 bool ret = ((bsec_get_status() & BSEC_OTP_STATUS_INVALID) == BSEC_OTP_STATUS_INVALID);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +020062
63 if (ret) {
64 ERROR("OTP mode is OTP-INVALID\n");
65 }
66
67 return ret;
68}
69
70#if defined(IMAGE_BL32)
Yann Gautier36a1e4b2019-01-17 14:52:47 +010071static int bsec_get_dt_node(struct dt_node_info *info)
72{
73 int node;
74
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +020075 node = dt_get_node(info, -1, DT_BSEC_COMPAT);
Yann Gautier36a1e4b2019-01-17 14:52:47 +010076 if (node < 0) {
77 return -FDT_ERR_NOTFOUND;
78 }
79
80 return node;
81}
82
Yann Gautier36a1e4b2019-01-17 14:52:47 +010083static void enable_non_secure_access(uint32_t otp)
84{
85 otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT);
86
87 if (bsec_shadow_register(otp) != BSEC_OK) {
88 panic();
89 }
90}
91
92static bool non_secure_can_access(uint32_t otp)
93{
94 return (otp_nsec_access[otp / __WORD_BIT] &
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +020095 BIT(otp % __WORD_BIT)) != 0U;
Yann Gautier36a1e4b2019-01-17 14:52:47 +010096}
97
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +020098static void bsec_dt_otp_nsec_access(void *fdt, int bsec_node)
Yann Gautier36a1e4b2019-01-17 14:52:47 +010099{
100 int bsec_subnode;
101
102 fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) {
103 const fdt32_t *cuint;
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200104 uint32_t otp;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100105 uint32_t i;
106 uint32_t size;
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200107 uint32_t offset;
108 uint32_t length;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100109
110 cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL);
111 if (cuint == NULL) {
112 panic();
113 }
114
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200115 offset = fdt32_to_cpu(*cuint);
116 cuint++;
117 length = fdt32_to_cpu(*cuint);
118
119 otp = offset / sizeof(uint32_t);
120
121 if (otp < STM32MP1_UPPER_OTP_START) {
122 unsigned int otp_end = round_up(offset + length,
123 sizeof(uint32_t)) /
124 sizeof(uint32_t);
125
126 if (otp_end > STM32MP1_UPPER_OTP_START) {
127 /*
128 * OTP crosses Lower/Upper boundary, consider
129 * only the upper part.
130 */
131 otp = STM32MP1_UPPER_OTP_START;
132 length -= (STM32MP1_UPPER_OTP_START *
133 sizeof(uint32_t)) - offset;
134 offset = STM32MP1_UPPER_OTP_START *
135 sizeof(uint32_t);
136
137 WARN("OTP crosses Lower/Upper boundary\n");
138 } else {
139 continue;
140 }
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100141 }
142
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200143 if ((fdt_getprop(fdt, bsec_subnode,
144 "st,non-secure-otp", NULL)) == NULL) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100145 continue;
146 }
147
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200148 if (((offset % sizeof(uint32_t)) != 0U) ||
149 ((length % sizeof(uint32_t)) != 0U)) {
150 ERROR("Unaligned non-secure OTP\n");
151 panic();
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100152 }
153
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200154 size = length / sizeof(uint32_t);
155
156 for (i = otp; i < (otp + size); i++) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100157 enable_non_secure_access(i);
158 }
159 }
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200160}
161
162static void bsec_late_init(void)
163{
164 void *fdt;
165 int node;
166 struct dt_node_info bsec_info;
167
168 if (fdt_get_address(&fdt) == 0) {
Yann Gautier0f2bc612023-11-02 15:36:12 +0100169 EARLY_ERROR("%s: DT not found\n", __func__);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200170 panic();
171 }
172
173 node = bsec_get_dt_node(&bsec_info);
174 if (node < 0) {
Yann Gautier0f2bc612023-11-02 15:36:12 +0100175 EARLY_ERROR("%s: BSEC node not found\n", __func__);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200176 panic();
177 }
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100178
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100179 assert(bsec_info.base == BSEC_BASE);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200180
181 bsec_dt_otp_nsec_access(fdt, node);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100182}
183#endif
184
185static uint32_t otp_bank_offset(uint32_t otp)
186{
187 assert(otp <= STM32MP1_OTP_MAX_ID);
188
189 return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) *
190 sizeof(uint32_t);
191}
192
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100193static uint32_t otp_bit_mask(uint32_t otp)
194{
195 return BIT(otp & BSEC_OTP_MASK);
196}
197
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200198/*
199 * bsec_check_error: check BSEC error status.
200 * otp: OTP number.
201 * check_disturbed: check only error (false),
202 * or error and disturbed status (true).
203 * return value: BSEC_OK if no error.
204 */
205static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100206{
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100207 uint32_t bit = otp_bit_mask(otp);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100208 uint32_t bank = otp_bank_offset(otp);
209
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100210 if ((mmio_read_32(BSEC_BASE + BSEC_ERROR_OFF + bank) & bit) != 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100211 return BSEC_ERROR;
212 }
213
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200214 if (!check_disturbed) {
215 return BSEC_OK;
216 }
217
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100218 if ((mmio_read_32(BSEC_BASE + BSEC_DISTURBED_OFF + bank) & bit) != 0U) {
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200219 return BSEC_DISTURBED;
220 }
221
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100222 return BSEC_OK;
223}
224
225/*
226 * bsec_probe: initialize BSEC driver.
227 * return value: BSEC_OK if no error.
228 */
229uint32_t bsec_probe(void)
230{
Yann Gautier0f2bc612023-11-02 15:36:12 +0100231 uint32_t version;
232 uint32_t id;
233
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200234 if (is_otp_invalid_mode()) {
Yann Gautier0f2bc612023-11-02 15:36:12 +0100235 EARLY_ERROR("%s: otp_invalid_mod\n", __func__);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200236 return BSEC_ERROR;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100237 }
238
Yann Gautier0f2bc612023-11-02 15:36:12 +0100239 version = bsec_get_version();
240 id = bsec_get_id();
241
242 if (((version != BSEC_IP_VERSION_1_1) &&
243 (version != BSEC_IP_VERSION_2_0)) ||
244 (id != BSEC_IP_ID_2)) {
245 EARLY_ERROR("%s: version = 0x%x, id = 0x%x\n", __func__, version, id);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100246 panic();
247 }
248
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100249#if defined(IMAGE_BL32)
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200250 bsec_late_init();
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100251#endif
252 return BSEC_OK;
253}
254
255/*
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100256 * bsec_shadow_register: copy SAFMEM OTP to BSEC data.
257 * otp: OTP number.
258 * return value: BSEC_OK if no error.
259 */
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100260static uint32_t bsec_shadow_register(uint32_t otp)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100261{
262 uint32_t result;
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200263 bool value;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100264 bool power_up = false;
265
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200266 if (is_otp_invalid_mode()) {
267 return BSEC_ERROR;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100268 }
269
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200270 result = bsec_read_sr_lock(otp, &value);
271 if (result != BSEC_OK) {
272 ERROR("BSEC: %u Sticky-read bit read Error %u\n", otp, result);
273 return result;
274 }
275
276 if (value) {
277 VERBOSE("BSEC: OTP %u is locked and will not be refreshed\n",
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100278 otp);
279 }
280
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100281 if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100282 result = bsec_power_safmem(true);
283
284 if (result != BSEC_OK) {
285 return result;
286 }
287
288 power_up = true;
289 }
290
291 bsec_lock();
292
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100293 mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, otp | BSEC_READ);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100294
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100295 while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100296 ;
297 }
298
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200299 result = bsec_check_error(otp, true);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100300
301 bsec_unlock();
302
303 if (power_up) {
304 if (bsec_power_safmem(false) != BSEC_OK) {
305 panic();
306 }
307 }
308
309 return result;
310}
311
312/*
313 * bsec_read_otp: read an OTP data value.
314 * val: read value.
315 * otp: OTP number.
316 * return value: BSEC_OK if no error.
317 */
318uint32_t bsec_read_otp(uint32_t *val, uint32_t otp)
319{
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200320 if (is_otp_invalid_mode()) {
321 return BSEC_ERROR;
322 }
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100323
324 if (otp > STM32MP1_OTP_MAX_ID) {
325 return BSEC_INVALID_PARAM;
326 }
327
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100328 *val = mmio_read_32(BSEC_BASE + BSEC_OTP_DATA_OFF +
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100329 (otp * sizeof(uint32_t)));
330
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200331 return BSEC_OK;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100332}
333
334/*
335 * bsec_write_otp: write value in BSEC data register.
336 * val: value to write.
337 * otp: OTP number.
338 * return value: BSEC_OK if no error.
339 */
340uint32_t bsec_write_otp(uint32_t val, uint32_t otp)
341{
342 uint32_t result;
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200343 bool value;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100344
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200345 if (is_otp_invalid_mode()) {
346 return BSEC_ERROR;
347 }
348
349 result = bsec_read_sw_lock(otp, &value);
350 if (result != BSEC_OK) {
351 ERROR("BSEC: %u Sticky-write bit read Error %u\n", otp, result);
352 return result;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100353 }
354
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200355 if (value) {
356 VERBOSE("BSEC: OTP %u is locked and write will be ignored\n",
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100357 otp);
358 }
359
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200360 /* Ensure integrity of each register access sequence */
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100361 bsec_lock();
362
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100363 mmio_write_32(BSEC_BASE + BSEC_OTP_DATA_OFF +
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100364 (otp * sizeof(uint32_t)), val);
365
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100366 bsec_unlock();
367
368 return result;
369}
370
371/*
372 * bsec_program_otp: program a bit in SAFMEM after the prog.
373 * The OTP data is not refreshed.
374 * val: value to program.
375 * otp: OTP number.
376 * return value: BSEC_OK if no error.
377 */
378uint32_t bsec_program_otp(uint32_t val, uint32_t otp)
379{
380 uint32_t result;
381 bool power_up = false;
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200382 bool sp_lock;
383 bool perm_lock;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100384
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200385 if (is_otp_invalid_mode()) {
386 return BSEC_ERROR;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100387 }
388
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200389 result = bsec_read_sp_lock(otp, &sp_lock);
390 if (result != BSEC_OK) {
391 ERROR("BSEC: %u Sticky-prog bit read Error %u\n", otp, result);
392 return result;
393 }
394
395 result = bsec_read_permanent_lock(otp, &perm_lock);
396 if (result != BSEC_OK) {
397 ERROR("BSEC: %u permanent bit read Error %u\n", otp, result);
398 return result;
399 }
400
401 if (sp_lock || perm_lock) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100402 WARN("BSEC: OTP locked, prog will be ignored\n");
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200403 return BSEC_PROG_FAIL;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100404 }
405
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100406 if ((mmio_read_32(BSEC_BASE + BSEC_OTP_LOCK_OFF) & GPLOCK_LOCK_MASK) != 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100407 WARN("BSEC: GPLOCK activated, prog will be ignored\n");
408 }
409
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100410 if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100411 result = bsec_power_safmem(true);
412
413 if (result != BSEC_OK) {
414 return result;
415 }
416
417 power_up = true;
418 }
419
420 bsec_lock();
421
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100422 mmio_write_32(BSEC_BASE + BSEC_OTP_WRDATA_OFF, val);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100423
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100424 mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100425
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100426 while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100427 ;
428 }
429
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100430 if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100431 result = BSEC_PROG_FAIL;
432 } else {
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200433 result = bsec_check_error(otp, true);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100434 }
435
436 bsec_unlock();
437
438 if (power_up) {
439 if (bsec_power_safmem(false) != BSEC_OK) {
440 panic();
441 }
442 }
443
444 return result;
445}
446
447/*
448 * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM.
449 * otp: OTP number.
450 * return value: BSEC_OK if no error.
451 */
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100452#if defined(IMAGE_BL32)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100453uint32_t bsec_permanent_lock_otp(uint32_t otp)
454{
455 uint32_t result;
456 bool power_up = false;
457 uint32_t data;
458 uint32_t addr;
459
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200460 if (is_otp_invalid_mode()) {
461 return BSEC_ERROR;
462 }
463
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100464 if (otp > STM32MP1_OTP_MAX_ID) {
465 return BSEC_INVALID_PARAM;
466 }
467
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100468 if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100469 result = bsec_power_safmem(true);
470
471 if (result != BSEC_OK) {
472 return result;
473 }
474
475 power_up = true;
476 }
477
478 if (otp < STM32MP1_UPPER_OTP_START) {
479 addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT;
480 data = DATA_LOWER_OTP_PERLOCK_BIT <<
481 ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U);
482 } else {
483 addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U;
484 data = DATA_UPPER_OTP_PERLOCK_BIT <<
485 (otp & DATA_UPPER_OTP_PERLOCK_MASK);
486 }
487
488 bsec_lock();
489
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100490 mmio_write_32(BSEC_BASE + BSEC_OTP_WRDATA_OFF, data);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100491
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100492 mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF,
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100493 addr | BSEC_WRITE | BSEC_LOCK);
494
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100495 while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100496 ;
497 }
498
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100499 if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 0U) {
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100500 result = BSEC_PROG_FAIL;
501 } else {
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200502 result = bsec_check_error(otp, false);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100503 }
504
505 bsec_unlock();
506
507 if (power_up) {
508 if (bsec_power_safmem(false) != BSEC_OK) {
509 panic();
510 }
511 }
512
513 return result;
514}
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100515#endif
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100516
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200517/*
518 * bsec_read_debug_conf: return debug configuration register value.
519 */
520uint32_t bsec_read_debug_conf(void)
521{
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100522 return mmio_read_32(BSEC_BASE + BSEC_DEN_OFF);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200523}
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100524
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200525/*
526 * bsec_write_scratch: write value in scratch register.
527 * val: value to write.
528 * return value: none.
529 */
530void bsec_write_scratch(uint32_t val)
531{
532#if defined(IMAGE_BL32)
533 if (is_otp_invalid_mode()) {
534 return;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100535 }
536
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200537 bsec_lock();
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100538 mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100539 bsec_unlock();
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200540#else
541 mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val);
542#endif
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100543}
544
545/*
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100546 * bsec_get_status: return status register value.
547 */
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100548static uint32_t bsec_get_status(void)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100549{
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100550 return mmio_read_32(BSEC_BASE + BSEC_OTP_STATUS_OFF);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100551}
552
553/*
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200554 * bsec_get_version: return BSEC version register value.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100555 */
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100556static uint32_t bsec_get_version(void)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100557{
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100558 return mmio_read_32(BSEC_BASE + BSEC_IPVR_OFF) & BSEC_IPVR_MSK;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100559}
560
561/*
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200562 * bsec_get_id: return BSEC ID register value.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100563 */
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100564static uint32_t bsec_get_id(void)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100565{
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100566 return mmio_read_32(BSEC_BASE + BSEC_IP_ID_OFF);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100567}
568
569/*
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200570 * bsec_set_sr_lock: set shadow-read lock.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100571 * otp: OTP number.
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200572 * return value: BSEC_OK if no error.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100573 */
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200574uint32_t bsec_set_sr_lock(uint32_t otp)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100575{
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100576 uint32_t bank = otp_bank_offset(otp);
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100577 uint32_t otp_mask = otp_bit_mask(otp);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100578
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200579 if (is_otp_invalid_mode()) {
580 return BSEC_ERROR;
581 }
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100582
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200583 if (otp > STM32MP1_OTP_MAX_ID) {
584 return BSEC_INVALID_PARAM;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100585 }
586
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200587 bsec_lock();
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100588 mmio_write_32(BSEC_BASE + BSEC_SRLOCK_OFF + bank, otp_mask);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100589 bsec_unlock();
590
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200591 return BSEC_OK;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100592}
593
594/*
595 * bsec_read_sr_lock: read shadow-read lock.
596 * otp: OTP number.
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200597 * value: read value (true or false).
598 * return value: BSEC_OK if no error.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100599 */
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200600uint32_t bsec_read_sr_lock(uint32_t otp, bool *value)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100601{
602 uint32_t bank = otp_bank_offset(otp);
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100603 uint32_t otp_mask = otp_bit_mask(otp);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200604 uint32_t bank_value;
605
606 if (otp > STM32MP1_OTP_MAX_ID) {
607 return BSEC_INVALID_PARAM;
608 }
609
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100610 bank_value = mmio_read_32(BSEC_BASE + BSEC_SRLOCK_OFF + bank);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100611
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200612 *value = ((bank_value & otp_mask) != 0U);
613
614 return BSEC_OK;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100615}
616
617/*
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200618 * bsec_set_sw_lock: set shadow-write lock.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100619 * otp: OTP number.
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200620 * return value: BSEC_OK if no error.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100621 */
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200622uint32_t bsec_set_sw_lock(uint32_t otp)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100623{
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100624 uint32_t bank = otp_bank_offset(otp);
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100625 uint32_t otp_mask = otp_bit_mask(otp);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100626
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200627 if (is_otp_invalid_mode()) {
628 return BSEC_ERROR;
629 }
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100630
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200631 if (otp > STM32MP1_OTP_MAX_ID) {
632 return BSEC_INVALID_PARAM;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100633 }
634
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200635 bsec_lock();
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100636 mmio_write_32(BSEC_BASE + BSEC_SWLOCK_OFF + bank, otp_mask);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100637 bsec_unlock();
638
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200639 return BSEC_OK;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100640}
641
642/*
643 * bsec_read_sw_lock: read shadow-write lock.
644 * otp: OTP number.
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200645 * value: read value (true or false).
646 * return value: BSEC_OK if no error.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100647 */
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200648uint32_t bsec_read_sw_lock(uint32_t otp, bool *value)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100649{
650 uint32_t bank = otp_bank_offset(otp);
651 uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200652 uint32_t bank_value;
653
654 if (otp > STM32MP1_OTP_MAX_ID) {
655 return BSEC_INVALID_PARAM;
656 }
657
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100658 bank_value = mmio_read_32(BSEC_BASE + BSEC_SWLOCK_OFF + bank);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200659
660 *value = ((bank_value & otp_mask) != 0U);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100661
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200662 return BSEC_OK;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100663}
664
665/*
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200666 * bsec_set_sp_lock: set shadow-program lock.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100667 * otp: OTP number.
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200668 * return value: BSEC_OK if no error.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100669 */
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200670uint32_t bsec_set_sp_lock(uint32_t otp)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100671{
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100672 uint32_t bank = otp_bank_offset(otp);
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100673 uint32_t otp_mask = otp_bit_mask(otp);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100674
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200675 if (is_otp_invalid_mode()) {
676 return BSEC_ERROR;
677 }
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100678
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200679 if (otp > STM32MP1_OTP_MAX_ID) {
680 return BSEC_INVALID_PARAM;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100681 }
682
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200683 bsec_lock();
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100684 mmio_write_32(BSEC_BASE + BSEC_SPLOCK_OFF + bank, otp_mask);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100685 bsec_unlock();
686
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200687 return BSEC_OK;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100688}
689
690/*
691 * bsec_read_sp_lock: read shadow-program lock.
692 * otp: OTP number.
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200693 * value: read value (true or false).
694 * return value: BSEC_OK if no error.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100695 */
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200696uint32_t bsec_read_sp_lock(uint32_t otp, bool *value)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100697{
698 uint32_t bank = otp_bank_offset(otp);
699 uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200700 uint32_t bank_value;
701
702 if (otp > STM32MP1_OTP_MAX_ID) {
703 return BSEC_INVALID_PARAM;
704 }
705
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100706 bank_value = mmio_read_32(BSEC_BASE + BSEC_SPLOCK_OFF + bank);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100707
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200708 *value = ((bank_value & otp_mask) != 0U);
709
710 return BSEC_OK;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100711}
712
713/*
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200714 * bsec_read_permanent_lock: Read permanent lock status.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100715 * otp: OTP number.
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200716 * value: read value (true or false).
717 * return value: BSEC_OK if no error.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100718 */
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100719static uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100720{
721 uint32_t bank = otp_bank_offset(otp);
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100722 uint32_t otp_mask = otp_bit_mask(otp);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200723 uint32_t bank_value;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100724
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200725 if (otp > STM32MP1_OTP_MAX_ID) {
726 return BSEC_INVALID_PARAM;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100727 }
728
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100729 bank_value = mmio_read_32(BSEC_BASE + BSEC_WRLOCK_OFF + bank);
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200730
731 *value = ((bank_value & otp_mask) != 0U);
732
733 return BSEC_OK;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100734}
735
736/*
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100737 * bsec_power_safmem: Activate or deactivate SAFMEM power.
738 * power: true to power up, false to power down.
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200739 * return value: BSEC_OK if no error.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100740 */
741static uint32_t bsec_power_safmem(bool power)
742{
743 uint32_t register_val;
744 uint32_t timeout = BSEC_TIMEOUT_VALUE;
745
746 bsec_lock();
747
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100748 register_val = mmio_read_32(BSEC_BASE + BSEC_OTP_CONF_OFF);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100749
750 if (power) {
751 register_val |= BSEC_CONF_POWER_UP_MASK;
752 } else {
753 register_val &= ~BSEC_CONF_POWER_UP_MASK;
754 }
755
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100756 mmio_write_32(BSEC_BASE + BSEC_OTP_CONF_OFF, register_val);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100757
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100758 if (power) {
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100759 while (((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) &&
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100760 (timeout != 0U)) {
761 timeout--;
762 }
763 } else {
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100764 while (((bsec_get_status() & BSEC_OTP_STATUS_PWRON) != 0U) &&
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100765 (timeout != 0U)) {
766 timeout--;
767 }
768 }
769
770 bsec_unlock();
771
772 if (timeout == 0U) {
773 return BSEC_TIMEOUT;
774 }
775
776 return BSEC_OK;
777}
778
779/*
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200780 * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value.
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100781 * val: read value.
782 * otp: OTP number.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100783 * return value: BSEC_OK if no error.
784 */
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100785uint32_t bsec_shadow_read_otp(uint32_t *val, uint32_t otp)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100786{
787 uint32_t result;
788
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100789 result = bsec_shadow_register(otp);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100790 if (result != BSEC_OK) {
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100791 ERROR("BSEC: %u Shadowing Error %u\n", otp, result);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100792 return result;
793 }
794
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100795 result = bsec_read_otp(val, otp);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100796 if (result != BSEC_OK) {
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100797 ERROR("BSEC: %u Read Error %u\n", otp, result);
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100798 }
799
800 return result;
801}
802
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100803#if defined(IMAGE_BL32)
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100804/*
805 * bsec_check_nsec_access_rights: check non-secure access rights to target OTP.
806 * otp: OTP number.
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200807 * return value: BSEC_OK if authorized access.
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100808 */
809uint32_t bsec_check_nsec_access_rights(uint32_t otp)
810{
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100811 if (otp > STM32MP1_OTP_MAX_ID) {
812 return BSEC_INVALID_PARAM;
813 }
814
815 if (otp >= STM32MP1_UPPER_OTP_START) {
Nicolas Le Bayon97287cd2019-05-20 18:35:02 +0200816 if (!non_secure_can_access(otp)) {
817 return BSEC_ERROR;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100818 }
819 }
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100820
821 return BSEC_OK;
822}
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100823#endif
824
825uint32_t bsec_get_secure_state(void)
826{
827 uint32_t status = bsec_get_status();
828 uint32_t result = BSEC_STATE_INVALID;
829 uint32_t otp_enc_id __maybe_unused;
830 uint32_t otp_bit_len __maybe_unused;
831 int res __maybe_unused;
Yann Gautier36a1e4b2019-01-17 14:52:47 +0100832
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100833 if ((status & BSEC_OTP_STATUS_INVALID) != 0U) {
834 result = BSEC_STATE_INVALID;
835 } else {
836 if ((status & BSEC_OTP_STATUS_SECURE) != 0U) {
Yann Gautier3e334752023-02-01 15:04:30 +0100837 if (stm32mp_check_closed_device() == STM32MP_CHIP_SEC_CLOSED) {
Patrick Delaunaye720b5b2022-12-14 13:45:04 +0100838 result = BSEC_STATE_SEC_CLOSED;
839 } else {
840 result = BSEC_STATE_SEC_OPEN;
841 }
842 } else {
843 /* OTP modes OPEN1 and OPEN2 are not supported */
844 result = BSEC_STATE_INVALID;
845 }
846 }
847
848 return result;
849}