1072d7532SNicolas Le Bayon /* 2*c7061045SPatrick Delaunay * Copyright (c) 2017-2024, STMicroelectronics - All Rights Reserved 3072d7532SNicolas Le Bayon * 4072d7532SNicolas Le Bayon * SPDX-License-Identifier: BSD-3-Clause 5072d7532SNicolas Le Bayon */ 6072d7532SNicolas Le Bayon 7072d7532SNicolas Le Bayon #include <assert.h> 8072d7532SNicolas Le Bayon #include <limits.h> 9072d7532SNicolas Le Bayon 10072d7532SNicolas Le Bayon #include <arch_helpers.h> 11072d7532SNicolas Le Bayon #include <common/debug.h> 12072d7532SNicolas Le Bayon #include <drivers/st/bsec.h> 13072d7532SNicolas Le Bayon #include <drivers/st/bsec2_reg.h> 14072d7532SNicolas Le Bayon #include <lib/mmio.h> 15072d7532SNicolas Le Bayon #include <lib/spinlock.h> 16072d7532SNicolas Le Bayon #include <libfdt.h> 17072d7532SNicolas Le Bayon 18072d7532SNicolas Le Bayon #include <platform_def.h> 19072d7532SNicolas Le Bayon 20072d7532SNicolas Le Bayon #define BSEC_IP_VERSION_1_1 U(0x11) 21072d7532SNicolas Le Bayon #define BSEC_IP_VERSION_2_0 U(0x20) 22072d7532SNicolas Le Bayon #define BSEC_IP_ID_2 U(0x100032) 23072d7532SNicolas Le Bayon 24*c7061045SPatrick Delaunay /* 25*c7061045SPatrick Delaunay * IP configuration 26*c7061045SPatrick Delaunay */ 27*c7061045SPatrick Delaunay #define BSEC_OTP_MASK GENMASK(4, 0) 28*c7061045SPatrick Delaunay #define BSEC_OTP_BANK_SHIFT 5 29*c7061045SPatrick Delaunay #define BSEC_TIMEOUT_VALUE U(0xFFFF) 30*c7061045SPatrick Delaunay 31072d7532SNicolas Le Bayon #define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT) 32072d7532SNicolas Le Bayon 33*c7061045SPatrick Delaunay static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __maybe_unused; 34072d7532SNicolas Le Bayon 35*c7061045SPatrick Delaunay static uint32_t bsec_shadow_register(uint32_t otp); 36072d7532SNicolas Le Bayon static uint32_t bsec_power_safmem(bool power); 37*c7061045SPatrick Delaunay static uint32_t bsec_get_version(void); 38*c7061045SPatrick Delaunay static uint32_t bsec_get_id(void); 39*c7061045SPatrick Delaunay static uint32_t bsec_get_status(void); 40*c7061045SPatrick Delaunay static uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value); 41072d7532SNicolas Le Bayon 42072d7532SNicolas Le Bayon /* BSEC access protection */ 43072d7532SNicolas Le Bayon static spinlock_t bsec_spinlock; 44072d7532SNicolas Le Bayon 45072d7532SNicolas Le Bayon static void bsec_lock(void) 46072d7532SNicolas Le Bayon { 47072d7532SNicolas Le Bayon if (stm32mp_lock_available()) { 48072d7532SNicolas Le Bayon spin_lock(&bsec_spinlock); 49072d7532SNicolas Le Bayon } 50072d7532SNicolas Le Bayon } 51072d7532SNicolas Le Bayon 52072d7532SNicolas Le Bayon static void bsec_unlock(void) 53072d7532SNicolas Le Bayon { 54072d7532SNicolas Le Bayon if (stm32mp_lock_available()) { 55072d7532SNicolas Le Bayon spin_unlock(&bsec_spinlock); 56072d7532SNicolas Le Bayon } 57072d7532SNicolas Le Bayon } 58072d7532SNicolas Le Bayon 59072d7532SNicolas Le Bayon static bool is_otp_invalid_mode(void) 60072d7532SNicolas Le Bayon { 61*c7061045SPatrick Delaunay bool ret = ((bsec_get_status() & BSEC_OTP_STATUS_INVALID) == BSEC_OTP_STATUS_INVALID); 62072d7532SNicolas Le Bayon 63072d7532SNicolas Le Bayon if (ret) { 64072d7532SNicolas Le Bayon ERROR("OTP mode is OTP-INVALID\n"); 65072d7532SNicolas Le Bayon } 66072d7532SNicolas Le Bayon 67072d7532SNicolas Le Bayon return ret; 68072d7532SNicolas Le Bayon } 69072d7532SNicolas Le Bayon 70072d7532SNicolas Le Bayon #if defined(IMAGE_BL32) 71072d7532SNicolas Le Bayon static int bsec_get_dt_node(struct dt_node_info *info) 72072d7532SNicolas Le Bayon { 73072d7532SNicolas Le Bayon int node; 74072d7532SNicolas Le Bayon 75072d7532SNicolas Le Bayon node = dt_get_node(info, -1, DT_BSEC_COMPAT); 76072d7532SNicolas Le Bayon if (node < 0) { 77072d7532SNicolas Le Bayon return -FDT_ERR_NOTFOUND; 78072d7532SNicolas Le Bayon } 79072d7532SNicolas Le Bayon 80072d7532SNicolas Le Bayon return node; 81072d7532SNicolas Le Bayon } 82072d7532SNicolas Le Bayon 83072d7532SNicolas Le Bayon static void enable_non_secure_access(uint32_t otp) 84072d7532SNicolas Le Bayon { 85072d7532SNicolas Le Bayon otp_nsec_access[otp / __WORD_BIT] |= BIT(otp % __WORD_BIT); 86072d7532SNicolas Le Bayon 87072d7532SNicolas Le Bayon if (bsec_shadow_register(otp) != BSEC_OK) { 88072d7532SNicolas Le Bayon panic(); 89072d7532SNicolas Le Bayon } 90072d7532SNicolas Le Bayon } 91072d7532SNicolas Le Bayon 92072d7532SNicolas Le Bayon static bool non_secure_can_access(uint32_t otp) 93072d7532SNicolas Le Bayon { 94072d7532SNicolas Le Bayon return (otp_nsec_access[otp / __WORD_BIT] & 95072d7532SNicolas Le Bayon BIT(otp % __WORD_BIT)) != 0U; 96072d7532SNicolas Le Bayon } 97072d7532SNicolas Le Bayon 98072d7532SNicolas Le Bayon static void bsec_dt_otp_nsec_access(void *fdt, int bsec_node) 99072d7532SNicolas Le Bayon { 100072d7532SNicolas Le Bayon int bsec_subnode; 101072d7532SNicolas Le Bayon 102072d7532SNicolas Le Bayon fdt_for_each_subnode(bsec_subnode, fdt, bsec_node) { 103072d7532SNicolas Le Bayon const fdt32_t *cuint; 104072d7532SNicolas Le Bayon uint32_t otp; 105072d7532SNicolas Le Bayon uint32_t i; 106072d7532SNicolas Le Bayon uint32_t size; 107072d7532SNicolas Le Bayon uint32_t offset; 108072d7532SNicolas Le Bayon uint32_t length; 109072d7532SNicolas Le Bayon 110072d7532SNicolas Le Bayon cuint = fdt_getprop(fdt, bsec_subnode, "reg", NULL); 111072d7532SNicolas Le Bayon if (cuint == NULL) { 112072d7532SNicolas Le Bayon panic(); 113072d7532SNicolas Le Bayon } 114072d7532SNicolas Le Bayon 115072d7532SNicolas Le Bayon offset = fdt32_to_cpu(*cuint); 116072d7532SNicolas Le Bayon cuint++; 117072d7532SNicolas Le Bayon length = fdt32_to_cpu(*cuint); 118072d7532SNicolas Le Bayon 119072d7532SNicolas Le Bayon otp = offset / sizeof(uint32_t); 120072d7532SNicolas Le Bayon 121072d7532SNicolas Le Bayon if (otp < STM32MP1_UPPER_OTP_START) { 122072d7532SNicolas Le Bayon unsigned int otp_end = round_up(offset + length, 123072d7532SNicolas Le Bayon sizeof(uint32_t)) / 124072d7532SNicolas Le Bayon sizeof(uint32_t); 125072d7532SNicolas Le Bayon 126072d7532SNicolas Le Bayon if (otp_end > STM32MP1_UPPER_OTP_START) { 127072d7532SNicolas Le Bayon /* 128072d7532SNicolas Le Bayon * OTP crosses Lower/Upper boundary, consider 129072d7532SNicolas Le Bayon * only the upper part. 130072d7532SNicolas Le Bayon */ 131072d7532SNicolas Le Bayon otp = STM32MP1_UPPER_OTP_START; 132072d7532SNicolas Le Bayon length -= (STM32MP1_UPPER_OTP_START * 133072d7532SNicolas Le Bayon sizeof(uint32_t)) - offset; 134072d7532SNicolas Le Bayon offset = STM32MP1_UPPER_OTP_START * 135072d7532SNicolas Le Bayon sizeof(uint32_t); 136072d7532SNicolas Le Bayon 137072d7532SNicolas Le Bayon WARN("OTP crosses Lower/Upper boundary\n"); 138072d7532SNicolas Le Bayon } else { 139072d7532SNicolas Le Bayon continue; 140072d7532SNicolas Le Bayon } 141072d7532SNicolas Le Bayon } 142072d7532SNicolas Le Bayon 143072d7532SNicolas Le Bayon if ((fdt_getprop(fdt, bsec_subnode, 144072d7532SNicolas Le Bayon "st,non-secure-otp", NULL)) == NULL) { 145072d7532SNicolas Le Bayon continue; 146072d7532SNicolas Le Bayon } 147072d7532SNicolas Le Bayon 148072d7532SNicolas Le Bayon if (((offset % sizeof(uint32_t)) != 0U) || 149072d7532SNicolas Le Bayon ((length % sizeof(uint32_t)) != 0U)) { 150072d7532SNicolas Le Bayon ERROR("Unaligned non-secure OTP\n"); 151072d7532SNicolas Le Bayon panic(); 152072d7532SNicolas Le Bayon } 153072d7532SNicolas Le Bayon 154072d7532SNicolas Le Bayon size = length / sizeof(uint32_t); 155072d7532SNicolas Le Bayon 156072d7532SNicolas Le Bayon for (i = otp; i < (otp + size); i++) { 157072d7532SNicolas Le Bayon enable_non_secure_access(i); 158072d7532SNicolas Le Bayon } 159072d7532SNicolas Le Bayon } 160072d7532SNicolas Le Bayon } 161072d7532SNicolas Le Bayon 162072d7532SNicolas Le Bayon static void bsec_late_init(void) 163072d7532SNicolas Le Bayon { 164072d7532SNicolas Le Bayon void *fdt; 165072d7532SNicolas Le Bayon int node; 166072d7532SNicolas Le Bayon struct dt_node_info bsec_info; 167072d7532SNicolas Le Bayon 168072d7532SNicolas Le Bayon if (fdt_get_address(&fdt) == 0) { 169072d7532SNicolas Le Bayon panic(); 170072d7532SNicolas Le Bayon } 171072d7532SNicolas Le Bayon 172072d7532SNicolas Le Bayon node = bsec_get_dt_node(&bsec_info); 173072d7532SNicolas Le Bayon if (node < 0) { 174072d7532SNicolas Le Bayon panic(); 175072d7532SNicolas Le Bayon } 176072d7532SNicolas Le Bayon 177*c7061045SPatrick Delaunay assert(bsec_info.base == BSEC_BASE); 178072d7532SNicolas Le Bayon 179072d7532SNicolas Le Bayon bsec_dt_otp_nsec_access(fdt, node); 180072d7532SNicolas Le Bayon } 181072d7532SNicolas Le Bayon #endif 182072d7532SNicolas Le Bayon 183072d7532SNicolas Le Bayon static uint32_t otp_bank_offset(uint32_t otp) 184072d7532SNicolas Le Bayon { 185072d7532SNicolas Le Bayon assert(otp <= STM32MP1_OTP_MAX_ID); 186072d7532SNicolas Le Bayon 187072d7532SNicolas Le Bayon return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) * 188072d7532SNicolas Le Bayon sizeof(uint32_t); 189072d7532SNicolas Le Bayon } 190072d7532SNicolas Le Bayon 191*c7061045SPatrick Delaunay static uint32_t otp_bit_mask(uint32_t otp) 192*c7061045SPatrick Delaunay { 193*c7061045SPatrick Delaunay return BIT(otp & BSEC_OTP_MASK); 194*c7061045SPatrick Delaunay } 195*c7061045SPatrick Delaunay 196072d7532SNicolas Le Bayon /* 197072d7532SNicolas Le Bayon * bsec_check_error: check BSEC error status. 198072d7532SNicolas Le Bayon * otp: OTP number. 199072d7532SNicolas Le Bayon * check_disturbed: check only error (false), 200072d7532SNicolas Le Bayon * or error and disturbed status (true). 201072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 202072d7532SNicolas Le Bayon */ 203072d7532SNicolas Le Bayon static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed) 204072d7532SNicolas Le Bayon { 205*c7061045SPatrick Delaunay uint32_t bit = otp_bit_mask(otp); 206072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 207072d7532SNicolas Le Bayon 208*c7061045SPatrick Delaunay if ((mmio_read_32(BSEC_BASE + BSEC_ERROR_OFF + bank) & bit) != 0U) { 209072d7532SNicolas Le Bayon return BSEC_ERROR; 210072d7532SNicolas Le Bayon } 211072d7532SNicolas Le Bayon 212072d7532SNicolas Le Bayon if (!check_disturbed) { 213072d7532SNicolas Le Bayon return BSEC_OK; 214072d7532SNicolas Le Bayon } 215072d7532SNicolas Le Bayon 216*c7061045SPatrick Delaunay if ((mmio_read_32(BSEC_BASE + BSEC_DISTURBED_OFF + bank) & bit) != 0U) { 217072d7532SNicolas Le Bayon return BSEC_DISTURBED; 218072d7532SNicolas Le Bayon } 219072d7532SNicolas Le Bayon 220072d7532SNicolas Le Bayon return BSEC_OK; 221072d7532SNicolas Le Bayon } 222072d7532SNicolas Le Bayon 223072d7532SNicolas Le Bayon /* 224072d7532SNicolas Le Bayon * bsec_probe: initialize BSEC driver. 225072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 226072d7532SNicolas Le Bayon */ 227072d7532SNicolas Le Bayon uint32_t bsec_probe(void) 228072d7532SNicolas Le Bayon { 229072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 230072d7532SNicolas Le Bayon return BSEC_ERROR; 231072d7532SNicolas Le Bayon } 232072d7532SNicolas Le Bayon 233*c7061045SPatrick Delaunay if (((bsec_get_version() != BSEC_IP_VERSION_1_1) && 234*c7061045SPatrick Delaunay (bsec_get_version() != BSEC_IP_VERSION_2_0)) || 235072d7532SNicolas Le Bayon (bsec_get_id() != BSEC_IP_ID_2)) { 236072d7532SNicolas Le Bayon panic(); 237072d7532SNicolas Le Bayon } 238072d7532SNicolas Le Bayon 239072d7532SNicolas Le Bayon #if defined(IMAGE_BL32) 240072d7532SNicolas Le Bayon bsec_late_init(); 241072d7532SNicolas Le Bayon #endif 242072d7532SNicolas Le Bayon return BSEC_OK; 243072d7532SNicolas Le Bayon } 244072d7532SNicolas Le Bayon 245072d7532SNicolas Le Bayon /* 246072d7532SNicolas Le Bayon * bsec_shadow_register: copy SAFMEM OTP to BSEC data. 247072d7532SNicolas Le Bayon * otp: OTP number. 248072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 249072d7532SNicolas Le Bayon */ 250*c7061045SPatrick Delaunay static uint32_t bsec_shadow_register(uint32_t otp) 251072d7532SNicolas Le Bayon { 252072d7532SNicolas Le Bayon uint32_t result; 253072d7532SNicolas Le Bayon bool value; 254072d7532SNicolas Le Bayon bool power_up = false; 255072d7532SNicolas Le Bayon 256072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 257072d7532SNicolas Le Bayon return BSEC_ERROR; 258072d7532SNicolas Le Bayon } 259072d7532SNicolas Le Bayon 260072d7532SNicolas Le Bayon result = bsec_read_sr_lock(otp, &value); 261072d7532SNicolas Le Bayon if (result != BSEC_OK) { 262072d7532SNicolas Le Bayon ERROR("BSEC: %u Sticky-read bit read Error %u\n", otp, result); 263072d7532SNicolas Le Bayon return result; 264072d7532SNicolas Le Bayon } 265072d7532SNicolas Le Bayon 266072d7532SNicolas Le Bayon if (value) { 267072d7532SNicolas Le Bayon VERBOSE("BSEC: OTP %u is locked and will not be refreshed\n", 268072d7532SNicolas Le Bayon otp); 269072d7532SNicolas Le Bayon } 270072d7532SNicolas Le Bayon 271*c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) { 272072d7532SNicolas Le Bayon result = bsec_power_safmem(true); 273072d7532SNicolas Le Bayon 274072d7532SNicolas Le Bayon if (result != BSEC_OK) { 275072d7532SNicolas Le Bayon return result; 276072d7532SNicolas Le Bayon } 277072d7532SNicolas Le Bayon 278072d7532SNicolas Le Bayon power_up = true; 279072d7532SNicolas Le Bayon } 280072d7532SNicolas Le Bayon 281072d7532SNicolas Le Bayon bsec_lock(); 282072d7532SNicolas Le Bayon 283*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, otp | BSEC_READ); 284072d7532SNicolas Le Bayon 285*c7061045SPatrick Delaunay while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) { 286072d7532SNicolas Le Bayon ; 287072d7532SNicolas Le Bayon } 288072d7532SNicolas Le Bayon 289072d7532SNicolas Le Bayon result = bsec_check_error(otp, true); 290072d7532SNicolas Le Bayon 291072d7532SNicolas Le Bayon bsec_unlock(); 292072d7532SNicolas Le Bayon 293072d7532SNicolas Le Bayon if (power_up) { 294072d7532SNicolas Le Bayon if (bsec_power_safmem(false) != BSEC_OK) { 295072d7532SNicolas Le Bayon panic(); 296072d7532SNicolas Le Bayon } 297072d7532SNicolas Le Bayon } 298072d7532SNicolas Le Bayon 299072d7532SNicolas Le Bayon return result; 300072d7532SNicolas Le Bayon } 301072d7532SNicolas Le Bayon 302072d7532SNicolas Le Bayon /* 303072d7532SNicolas Le Bayon * bsec_read_otp: read an OTP data value. 304072d7532SNicolas Le Bayon * val: read value. 305072d7532SNicolas Le Bayon * otp: OTP number. 306072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 307072d7532SNicolas Le Bayon */ 308072d7532SNicolas Le Bayon uint32_t bsec_read_otp(uint32_t *val, uint32_t otp) 309072d7532SNicolas Le Bayon { 310072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 311072d7532SNicolas Le Bayon return BSEC_ERROR; 312072d7532SNicolas Le Bayon } 313072d7532SNicolas Le Bayon 314072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 315072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 316072d7532SNicolas Le Bayon } 317072d7532SNicolas Le Bayon 318*c7061045SPatrick Delaunay *val = mmio_read_32(BSEC_BASE + BSEC_OTP_DATA_OFF + 319072d7532SNicolas Le Bayon (otp * sizeof(uint32_t))); 320072d7532SNicolas Le Bayon 321072d7532SNicolas Le Bayon return BSEC_OK; 322072d7532SNicolas Le Bayon } 323072d7532SNicolas Le Bayon 324072d7532SNicolas Le Bayon /* 325072d7532SNicolas Le Bayon * bsec_write_otp: write value in BSEC data register. 326072d7532SNicolas Le Bayon * val: value to write. 327072d7532SNicolas Le Bayon * otp: OTP number. 328072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 329072d7532SNicolas Le Bayon */ 330072d7532SNicolas Le Bayon uint32_t bsec_write_otp(uint32_t val, uint32_t otp) 331072d7532SNicolas Le Bayon { 332072d7532SNicolas Le Bayon uint32_t result; 333072d7532SNicolas Le Bayon bool value; 334072d7532SNicolas Le Bayon 335072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 336072d7532SNicolas Le Bayon return BSEC_ERROR; 337072d7532SNicolas Le Bayon } 338072d7532SNicolas Le Bayon 339072d7532SNicolas Le Bayon result = bsec_read_sw_lock(otp, &value); 340072d7532SNicolas Le Bayon if (result != BSEC_OK) { 341072d7532SNicolas Le Bayon ERROR("BSEC: %u Sticky-write bit read Error %u\n", otp, result); 342072d7532SNicolas Le Bayon return result; 343072d7532SNicolas Le Bayon } 344072d7532SNicolas Le Bayon 345072d7532SNicolas Le Bayon if (value) { 346072d7532SNicolas Le Bayon VERBOSE("BSEC: OTP %u is locked and write will be ignored\n", 347072d7532SNicolas Le Bayon otp); 348072d7532SNicolas Le Bayon } 349072d7532SNicolas Le Bayon 350072d7532SNicolas Le Bayon /* Ensure integrity of each register access sequence */ 351072d7532SNicolas Le Bayon bsec_lock(); 352072d7532SNicolas Le Bayon 353*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_DATA_OFF + 354072d7532SNicolas Le Bayon (otp * sizeof(uint32_t)), val); 355072d7532SNicolas Le Bayon 356072d7532SNicolas Le Bayon bsec_unlock(); 357072d7532SNicolas Le Bayon 358072d7532SNicolas Le Bayon return result; 359072d7532SNicolas Le Bayon } 360072d7532SNicolas Le Bayon 361072d7532SNicolas Le Bayon /* 362072d7532SNicolas Le Bayon * bsec_program_otp: program a bit in SAFMEM after the prog. 363072d7532SNicolas Le Bayon * The OTP data is not refreshed. 364072d7532SNicolas Le Bayon * val: value to program. 365072d7532SNicolas Le Bayon * otp: OTP number. 366072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 367072d7532SNicolas Le Bayon */ 368072d7532SNicolas Le Bayon uint32_t bsec_program_otp(uint32_t val, uint32_t otp) 369072d7532SNicolas Le Bayon { 370072d7532SNicolas Le Bayon uint32_t result; 371072d7532SNicolas Le Bayon bool power_up = false; 372072d7532SNicolas Le Bayon bool sp_lock; 373072d7532SNicolas Le Bayon bool perm_lock; 374072d7532SNicolas Le Bayon 375072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 376072d7532SNicolas Le Bayon return BSEC_ERROR; 377072d7532SNicolas Le Bayon } 378072d7532SNicolas Le Bayon 379072d7532SNicolas Le Bayon result = bsec_read_sp_lock(otp, &sp_lock); 380072d7532SNicolas Le Bayon if (result != BSEC_OK) { 381072d7532SNicolas Le Bayon ERROR("BSEC: %u Sticky-prog bit read Error %u\n", otp, result); 382072d7532SNicolas Le Bayon return result; 383072d7532SNicolas Le Bayon } 384072d7532SNicolas Le Bayon 385072d7532SNicolas Le Bayon result = bsec_read_permanent_lock(otp, &perm_lock); 386072d7532SNicolas Le Bayon if (result != BSEC_OK) { 387072d7532SNicolas Le Bayon ERROR("BSEC: %u permanent bit read Error %u\n", otp, result); 388072d7532SNicolas Le Bayon return result; 389072d7532SNicolas Le Bayon } 390072d7532SNicolas Le Bayon 391072d7532SNicolas Le Bayon if (sp_lock || perm_lock) { 392072d7532SNicolas Le Bayon WARN("BSEC: OTP locked, prog will be ignored\n"); 393072d7532SNicolas Le Bayon return BSEC_PROG_FAIL; 394072d7532SNicolas Le Bayon } 395072d7532SNicolas Le Bayon 396*c7061045SPatrick Delaunay if ((mmio_read_32(BSEC_BASE + BSEC_OTP_LOCK_OFF) & GPLOCK_LOCK_MASK) != 0U) { 397072d7532SNicolas Le Bayon WARN("BSEC: GPLOCK activated, prog will be ignored\n"); 398072d7532SNicolas Le Bayon } 399072d7532SNicolas Le Bayon 400*c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) { 401072d7532SNicolas Le Bayon result = bsec_power_safmem(true); 402072d7532SNicolas Le Bayon 403072d7532SNicolas Le Bayon if (result != BSEC_OK) { 404072d7532SNicolas Le Bayon return result; 405072d7532SNicolas Le Bayon } 406072d7532SNicolas Le Bayon 407072d7532SNicolas Le Bayon power_up = true; 408072d7532SNicolas Le Bayon } 409072d7532SNicolas Le Bayon 410072d7532SNicolas Le Bayon bsec_lock(); 411072d7532SNicolas Le Bayon 412*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_WRDATA_OFF, val); 413072d7532SNicolas Le Bayon 414*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE); 415072d7532SNicolas Le Bayon 416*c7061045SPatrick Delaunay while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) { 417072d7532SNicolas Le Bayon ; 418072d7532SNicolas Le Bayon } 419072d7532SNicolas Le Bayon 420*c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 0U) { 421072d7532SNicolas Le Bayon result = BSEC_PROG_FAIL; 422072d7532SNicolas Le Bayon } else { 423072d7532SNicolas Le Bayon result = bsec_check_error(otp, true); 424072d7532SNicolas Le Bayon } 425072d7532SNicolas Le Bayon 426072d7532SNicolas Le Bayon bsec_unlock(); 427072d7532SNicolas Le Bayon 428072d7532SNicolas Le Bayon if (power_up) { 429072d7532SNicolas Le Bayon if (bsec_power_safmem(false) != BSEC_OK) { 430072d7532SNicolas Le Bayon panic(); 431072d7532SNicolas Le Bayon } 432072d7532SNicolas Le Bayon } 433072d7532SNicolas Le Bayon 434072d7532SNicolas Le Bayon return result; 435072d7532SNicolas Le Bayon } 436072d7532SNicolas Le Bayon 437072d7532SNicolas Le Bayon /* 438072d7532SNicolas Le Bayon * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM. 439072d7532SNicolas Le Bayon * otp: OTP number. 440072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 441072d7532SNicolas Le Bayon */ 442*c7061045SPatrick Delaunay #if defined(IMAGE_BL32) 443072d7532SNicolas Le Bayon uint32_t bsec_permanent_lock_otp(uint32_t otp) 444072d7532SNicolas Le Bayon { 445072d7532SNicolas Le Bayon uint32_t result; 446072d7532SNicolas Le Bayon bool power_up = false; 447072d7532SNicolas Le Bayon uint32_t data; 448072d7532SNicolas Le Bayon uint32_t addr; 449072d7532SNicolas Le Bayon 450072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 451072d7532SNicolas Le Bayon return BSEC_ERROR; 452072d7532SNicolas Le Bayon } 453072d7532SNicolas Le Bayon 454072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 455072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 456072d7532SNicolas Le Bayon } 457072d7532SNicolas Le Bayon 458*c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) { 459072d7532SNicolas Le Bayon result = bsec_power_safmem(true); 460072d7532SNicolas Le Bayon 461072d7532SNicolas Le Bayon if (result != BSEC_OK) { 462072d7532SNicolas Le Bayon return result; 463072d7532SNicolas Le Bayon } 464072d7532SNicolas Le Bayon 465072d7532SNicolas Le Bayon power_up = true; 466072d7532SNicolas Le Bayon } 467072d7532SNicolas Le Bayon 468072d7532SNicolas Le Bayon if (otp < STM32MP1_UPPER_OTP_START) { 469072d7532SNicolas Le Bayon addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT; 470072d7532SNicolas Le Bayon data = DATA_LOWER_OTP_PERLOCK_BIT << 471072d7532SNicolas Le Bayon ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U); 472072d7532SNicolas Le Bayon } else { 473072d7532SNicolas Le Bayon addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U; 474072d7532SNicolas Le Bayon data = DATA_UPPER_OTP_PERLOCK_BIT << 475072d7532SNicolas Le Bayon (otp & DATA_UPPER_OTP_PERLOCK_MASK); 476072d7532SNicolas Le Bayon } 477072d7532SNicolas Le Bayon 478072d7532SNicolas Le Bayon bsec_lock(); 479072d7532SNicolas Le Bayon 480*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_WRDATA_OFF, data); 481072d7532SNicolas Le Bayon 482*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, 483072d7532SNicolas Le Bayon addr | BSEC_WRITE | BSEC_LOCK); 484072d7532SNicolas Le Bayon 485*c7061045SPatrick Delaunay while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) { 486072d7532SNicolas Le Bayon ; 487072d7532SNicolas Le Bayon } 488072d7532SNicolas Le Bayon 489*c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 0U) { 490072d7532SNicolas Le Bayon result = BSEC_PROG_FAIL; 491072d7532SNicolas Le Bayon } else { 492072d7532SNicolas Le Bayon result = bsec_check_error(otp, false); 493072d7532SNicolas Le Bayon } 494072d7532SNicolas Le Bayon 495072d7532SNicolas Le Bayon bsec_unlock(); 496072d7532SNicolas Le Bayon 497072d7532SNicolas Le Bayon if (power_up) { 498072d7532SNicolas Le Bayon if (bsec_power_safmem(false) != BSEC_OK) { 499072d7532SNicolas Le Bayon panic(); 500072d7532SNicolas Le Bayon } 501072d7532SNicolas Le Bayon } 502072d7532SNicolas Le Bayon 503072d7532SNicolas Le Bayon return result; 504072d7532SNicolas Le Bayon } 505*c7061045SPatrick Delaunay #endif 506072d7532SNicolas Le Bayon 507072d7532SNicolas Le Bayon /* 508072d7532SNicolas Le Bayon * bsec_read_debug_conf: return debug configuration register value. 509072d7532SNicolas Le Bayon */ 510072d7532SNicolas Le Bayon uint32_t bsec_read_debug_conf(void) 511072d7532SNicolas Le Bayon { 512*c7061045SPatrick Delaunay return mmio_read_32(BSEC_BASE + BSEC_DEN_OFF); 513072d7532SNicolas Le Bayon } 514072d7532SNicolas Le Bayon 515072d7532SNicolas Le Bayon /* 516072d7532SNicolas Le Bayon * bsec_write_scratch: write value in scratch register. 517072d7532SNicolas Le Bayon * val: value to write. 518072d7532SNicolas Le Bayon * return value: none. 519072d7532SNicolas Le Bayon */ 520072d7532SNicolas Le Bayon void bsec_write_scratch(uint32_t val) 521072d7532SNicolas Le Bayon { 522072d7532SNicolas Le Bayon #if defined(IMAGE_BL32) 523072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 524072d7532SNicolas Le Bayon return; 525072d7532SNicolas Le Bayon } 526072d7532SNicolas Le Bayon 527072d7532SNicolas Le Bayon bsec_lock(); 528*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val); 529072d7532SNicolas Le Bayon bsec_unlock(); 530072d7532SNicolas Le Bayon #else 531072d7532SNicolas Le Bayon mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val); 532072d7532SNicolas Le Bayon #endif 533072d7532SNicolas Le Bayon } 534072d7532SNicolas Le Bayon 535072d7532SNicolas Le Bayon /* 536072d7532SNicolas Le Bayon * bsec_get_status: return status register value. 537072d7532SNicolas Le Bayon */ 538*c7061045SPatrick Delaunay static uint32_t bsec_get_status(void) 539072d7532SNicolas Le Bayon { 540*c7061045SPatrick Delaunay return mmio_read_32(BSEC_BASE + BSEC_OTP_STATUS_OFF); 541072d7532SNicolas Le Bayon } 542072d7532SNicolas Le Bayon 543072d7532SNicolas Le Bayon /* 544072d7532SNicolas Le Bayon * bsec_get_version: return BSEC version register value. 545072d7532SNicolas Le Bayon */ 546*c7061045SPatrick Delaunay static uint32_t bsec_get_version(void) 547072d7532SNicolas Le Bayon { 548*c7061045SPatrick Delaunay return mmio_read_32(BSEC_BASE + BSEC_IPVR_OFF) & BSEC_IPVR_MSK; 549072d7532SNicolas Le Bayon } 550072d7532SNicolas Le Bayon 551072d7532SNicolas Le Bayon /* 552072d7532SNicolas Le Bayon * bsec_get_id: return BSEC ID register value. 553072d7532SNicolas Le Bayon */ 554*c7061045SPatrick Delaunay static uint32_t bsec_get_id(void) 555072d7532SNicolas Le Bayon { 556*c7061045SPatrick Delaunay return mmio_read_32(BSEC_BASE + BSEC_IP_ID_OFF); 557072d7532SNicolas Le Bayon } 558072d7532SNicolas Le Bayon 559072d7532SNicolas Le Bayon /* 560072d7532SNicolas Le Bayon * bsec_set_sr_lock: set shadow-read lock. 561072d7532SNicolas Le Bayon * otp: OTP number. 562072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 563072d7532SNicolas Le Bayon */ 564072d7532SNicolas Le Bayon uint32_t bsec_set_sr_lock(uint32_t otp) 565072d7532SNicolas Le Bayon { 566072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 567*c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 568072d7532SNicolas Le Bayon 569072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 570072d7532SNicolas Le Bayon return BSEC_ERROR; 571072d7532SNicolas Le Bayon } 572072d7532SNicolas Le Bayon 573072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 574072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 575072d7532SNicolas Le Bayon } 576072d7532SNicolas Le Bayon 577072d7532SNicolas Le Bayon bsec_lock(); 578*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_SRLOCK_OFF + bank, otp_mask); 579072d7532SNicolas Le Bayon bsec_unlock(); 580072d7532SNicolas Le Bayon 581072d7532SNicolas Le Bayon return BSEC_OK; 582072d7532SNicolas Le Bayon } 583072d7532SNicolas Le Bayon 584072d7532SNicolas Le Bayon /* 585072d7532SNicolas Le Bayon * bsec_read_sr_lock: read shadow-read lock. 586072d7532SNicolas Le Bayon * otp: OTP number. 587072d7532SNicolas Le Bayon * value: read value (true or false). 588072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 589072d7532SNicolas Le Bayon */ 590072d7532SNicolas Le Bayon uint32_t bsec_read_sr_lock(uint32_t otp, bool *value) 591072d7532SNicolas Le Bayon { 592072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 593*c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 594072d7532SNicolas Le Bayon uint32_t bank_value; 595072d7532SNicolas Le Bayon 596072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 597072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 598072d7532SNicolas Le Bayon } 599072d7532SNicolas Le Bayon 600*c7061045SPatrick Delaunay bank_value = mmio_read_32(BSEC_BASE + BSEC_SRLOCK_OFF + bank); 601072d7532SNicolas Le Bayon 602072d7532SNicolas Le Bayon *value = ((bank_value & otp_mask) != 0U); 603072d7532SNicolas Le Bayon 604072d7532SNicolas Le Bayon return BSEC_OK; 605072d7532SNicolas Le Bayon } 606072d7532SNicolas Le Bayon 607072d7532SNicolas Le Bayon /* 608072d7532SNicolas Le Bayon * bsec_set_sw_lock: set shadow-write lock. 609072d7532SNicolas Le Bayon * otp: OTP number. 610072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 611072d7532SNicolas Le Bayon */ 612072d7532SNicolas Le Bayon uint32_t bsec_set_sw_lock(uint32_t otp) 613072d7532SNicolas Le Bayon { 614072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 615*c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 616072d7532SNicolas Le Bayon 617072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 618072d7532SNicolas Le Bayon return BSEC_ERROR; 619072d7532SNicolas Le Bayon } 620072d7532SNicolas Le Bayon 621072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 622072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 623072d7532SNicolas Le Bayon } 624072d7532SNicolas Le Bayon 625072d7532SNicolas Le Bayon bsec_lock(); 626*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_SWLOCK_OFF + bank, otp_mask); 627072d7532SNicolas Le Bayon bsec_unlock(); 628072d7532SNicolas Le Bayon 629072d7532SNicolas Le Bayon return BSEC_OK; 630072d7532SNicolas Le Bayon } 631072d7532SNicolas Le Bayon 632072d7532SNicolas Le Bayon /* 633072d7532SNicolas Le Bayon * bsec_read_sw_lock: read shadow-write lock. 634072d7532SNicolas Le Bayon * otp: OTP number. 635072d7532SNicolas Le Bayon * value: read value (true or false). 636072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 637072d7532SNicolas Le Bayon */ 638072d7532SNicolas Le Bayon uint32_t bsec_read_sw_lock(uint32_t otp, bool *value) 639072d7532SNicolas Le Bayon { 640072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 641072d7532SNicolas Le Bayon uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); 642072d7532SNicolas Le Bayon uint32_t bank_value; 643072d7532SNicolas Le Bayon 644072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 645072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 646072d7532SNicolas Le Bayon } 647072d7532SNicolas Le Bayon 648*c7061045SPatrick Delaunay bank_value = mmio_read_32(BSEC_BASE + BSEC_SWLOCK_OFF + bank); 649072d7532SNicolas Le Bayon 650072d7532SNicolas Le Bayon *value = ((bank_value & otp_mask) != 0U); 651072d7532SNicolas Le Bayon 652072d7532SNicolas Le Bayon return BSEC_OK; 653072d7532SNicolas Le Bayon } 654072d7532SNicolas Le Bayon 655072d7532SNicolas Le Bayon /* 656072d7532SNicolas Le Bayon * bsec_set_sp_lock: set shadow-program lock. 657072d7532SNicolas Le Bayon * otp: OTP number. 658072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 659072d7532SNicolas Le Bayon */ 660072d7532SNicolas Le Bayon uint32_t bsec_set_sp_lock(uint32_t otp) 661072d7532SNicolas Le Bayon { 662072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 663*c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 664072d7532SNicolas Le Bayon 665072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 666072d7532SNicolas Le Bayon return BSEC_ERROR; 667072d7532SNicolas Le Bayon } 668072d7532SNicolas Le Bayon 669072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 670072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 671072d7532SNicolas Le Bayon } 672072d7532SNicolas Le Bayon 673072d7532SNicolas Le Bayon bsec_lock(); 674*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_SPLOCK_OFF + bank, otp_mask); 675072d7532SNicolas Le Bayon bsec_unlock(); 676072d7532SNicolas Le Bayon 677072d7532SNicolas Le Bayon return BSEC_OK; 678072d7532SNicolas Le Bayon } 679072d7532SNicolas Le Bayon 680072d7532SNicolas Le Bayon /* 681072d7532SNicolas Le Bayon * bsec_read_sp_lock: read shadow-program lock. 682072d7532SNicolas Le Bayon * otp: OTP number. 683072d7532SNicolas Le Bayon * value: read value (true or false). 684072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 685072d7532SNicolas Le Bayon */ 686072d7532SNicolas Le Bayon uint32_t bsec_read_sp_lock(uint32_t otp, bool *value) 687072d7532SNicolas Le Bayon { 688072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 689072d7532SNicolas Le Bayon uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); 690072d7532SNicolas Le Bayon uint32_t bank_value; 691072d7532SNicolas Le Bayon 692072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 693072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 694072d7532SNicolas Le Bayon } 695072d7532SNicolas Le Bayon 696*c7061045SPatrick Delaunay bank_value = mmio_read_32(BSEC_BASE + BSEC_SPLOCK_OFF + bank); 697072d7532SNicolas Le Bayon 698072d7532SNicolas Le Bayon *value = ((bank_value & otp_mask) != 0U); 699072d7532SNicolas Le Bayon 700072d7532SNicolas Le Bayon return BSEC_OK; 701072d7532SNicolas Le Bayon } 702072d7532SNicolas Le Bayon 703072d7532SNicolas Le Bayon /* 704072d7532SNicolas Le Bayon * bsec_read_permanent_lock: Read permanent lock status. 705072d7532SNicolas Le Bayon * otp: OTP number. 706072d7532SNicolas Le Bayon * value: read value (true or false). 707072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 708072d7532SNicolas Le Bayon */ 709*c7061045SPatrick Delaunay static uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value) 710072d7532SNicolas Le Bayon { 711072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 712*c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 713072d7532SNicolas Le Bayon uint32_t bank_value; 714072d7532SNicolas Le Bayon 715072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 716072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 717072d7532SNicolas Le Bayon } 718072d7532SNicolas Le Bayon 719*c7061045SPatrick Delaunay bank_value = mmio_read_32(BSEC_BASE + BSEC_WRLOCK_OFF + bank); 720072d7532SNicolas Le Bayon 721072d7532SNicolas Le Bayon *value = ((bank_value & otp_mask) != 0U); 722072d7532SNicolas Le Bayon 723072d7532SNicolas Le Bayon return BSEC_OK; 724072d7532SNicolas Le Bayon } 725072d7532SNicolas Le Bayon 726072d7532SNicolas Le Bayon /* 727072d7532SNicolas Le Bayon * bsec_power_safmem: Activate or deactivate SAFMEM power. 728072d7532SNicolas Le Bayon * power: true to power up, false to power down. 729072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 730072d7532SNicolas Le Bayon */ 731072d7532SNicolas Le Bayon static uint32_t bsec_power_safmem(bool power) 732072d7532SNicolas Le Bayon { 733072d7532SNicolas Le Bayon uint32_t register_val; 734072d7532SNicolas Le Bayon uint32_t timeout = BSEC_TIMEOUT_VALUE; 735072d7532SNicolas Le Bayon 736072d7532SNicolas Le Bayon bsec_lock(); 737072d7532SNicolas Le Bayon 738*c7061045SPatrick Delaunay register_val = mmio_read_32(BSEC_BASE + BSEC_OTP_CONF_OFF); 739072d7532SNicolas Le Bayon 740072d7532SNicolas Le Bayon if (power) { 741072d7532SNicolas Le Bayon register_val |= BSEC_CONF_POWER_UP_MASK; 742072d7532SNicolas Le Bayon } else { 743072d7532SNicolas Le Bayon register_val &= ~BSEC_CONF_POWER_UP_MASK; 744072d7532SNicolas Le Bayon } 745072d7532SNicolas Le Bayon 746*c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_CONF_OFF, register_val); 747072d7532SNicolas Le Bayon 748072d7532SNicolas Le Bayon if (power) { 749*c7061045SPatrick Delaunay while (((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) && 750072d7532SNicolas Le Bayon (timeout != 0U)) { 751072d7532SNicolas Le Bayon timeout--; 752072d7532SNicolas Le Bayon } 753072d7532SNicolas Le Bayon } else { 754*c7061045SPatrick Delaunay while (((bsec_get_status() & BSEC_OTP_STATUS_PWRON) != 0U) && 755072d7532SNicolas Le Bayon (timeout != 0U)) { 756072d7532SNicolas Le Bayon timeout--; 757072d7532SNicolas Le Bayon } 758072d7532SNicolas Le Bayon } 759072d7532SNicolas Le Bayon 760072d7532SNicolas Le Bayon bsec_unlock(); 761072d7532SNicolas Le Bayon 762072d7532SNicolas Le Bayon if (timeout == 0U) { 763072d7532SNicolas Le Bayon return BSEC_TIMEOUT; 764072d7532SNicolas Le Bayon } 765072d7532SNicolas Le Bayon 766072d7532SNicolas Le Bayon return BSEC_OK; 767072d7532SNicolas Le Bayon } 768072d7532SNicolas Le Bayon 769072d7532SNicolas Le Bayon /* 770072d7532SNicolas Le Bayon * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value. 771*c7061045SPatrick Delaunay * val: read value. 772*c7061045SPatrick Delaunay * otp: OTP number. 773072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 774072d7532SNicolas Le Bayon */ 775*c7061045SPatrick Delaunay uint32_t bsec_shadow_read_otp(uint32_t *val, uint32_t otp) 776072d7532SNicolas Le Bayon { 777072d7532SNicolas Le Bayon uint32_t result; 778072d7532SNicolas Le Bayon 779*c7061045SPatrick Delaunay result = bsec_shadow_register(otp); 780072d7532SNicolas Le Bayon if (result != BSEC_OK) { 781*c7061045SPatrick Delaunay ERROR("BSEC: %u Shadowing Error %u\n", otp, result); 782072d7532SNicolas Le Bayon return result; 783072d7532SNicolas Le Bayon } 784072d7532SNicolas Le Bayon 785*c7061045SPatrick Delaunay result = bsec_read_otp(val, otp); 786072d7532SNicolas Le Bayon if (result != BSEC_OK) { 787*c7061045SPatrick Delaunay ERROR("BSEC: %u Read Error %u\n", otp, result); 788072d7532SNicolas Le Bayon } 789072d7532SNicolas Le Bayon 790072d7532SNicolas Le Bayon return result; 791072d7532SNicolas Le Bayon } 792072d7532SNicolas Le Bayon 793*c7061045SPatrick Delaunay #if defined(IMAGE_BL32) 794072d7532SNicolas Le Bayon /* 795072d7532SNicolas Le Bayon * bsec_check_nsec_access_rights: check non-secure access rights to target OTP. 796072d7532SNicolas Le Bayon * otp: OTP number. 797072d7532SNicolas Le Bayon * return value: BSEC_OK if authorized access. 798072d7532SNicolas Le Bayon */ 799072d7532SNicolas Le Bayon uint32_t bsec_check_nsec_access_rights(uint32_t otp) 800072d7532SNicolas Le Bayon { 801072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 802072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 803072d7532SNicolas Le Bayon } 804072d7532SNicolas Le Bayon 805072d7532SNicolas Le Bayon if (otp >= STM32MP1_UPPER_OTP_START) { 806072d7532SNicolas Le Bayon if (!non_secure_can_access(otp)) { 807072d7532SNicolas Le Bayon return BSEC_ERROR; 808072d7532SNicolas Le Bayon } 809072d7532SNicolas Le Bayon } 810072d7532SNicolas Le Bayon 811072d7532SNicolas Le Bayon return BSEC_OK; 812072d7532SNicolas Le Bayon } 813*c7061045SPatrick Delaunay #endif 814072d7532SNicolas Le Bayon 815*c7061045SPatrick Delaunay uint32_t bsec_get_secure_state(void) 816*c7061045SPatrick Delaunay { 817*c7061045SPatrick Delaunay uint32_t status = bsec_get_status(); 818*c7061045SPatrick Delaunay uint32_t result = BSEC_STATE_INVALID; 819*c7061045SPatrick Delaunay uint32_t otp_enc_id __maybe_unused; 820*c7061045SPatrick Delaunay uint32_t otp_bit_len __maybe_unused; 821*c7061045SPatrick Delaunay int res __maybe_unused; 822*c7061045SPatrick Delaunay 823*c7061045SPatrick Delaunay if ((status & BSEC_OTP_STATUS_INVALID) != 0U) { 824*c7061045SPatrick Delaunay result = BSEC_STATE_INVALID; 825*c7061045SPatrick Delaunay } else { 826*c7061045SPatrick Delaunay if ((status & BSEC_OTP_STATUS_SECURE) != 0U) { 827*c7061045SPatrick Delaunay if (stm32mp_is_closed_device()) { 828*c7061045SPatrick Delaunay result = BSEC_STATE_SEC_CLOSED; 829*c7061045SPatrick Delaunay } else { 830*c7061045SPatrick Delaunay result = BSEC_STATE_SEC_OPEN; 831*c7061045SPatrick Delaunay } 832*c7061045SPatrick Delaunay } else { 833*c7061045SPatrick Delaunay /* OTP modes OPEN1 and OPEN2 are not supported */ 834*c7061045SPatrick Delaunay result = BSEC_STATE_INVALID; 835*c7061045SPatrick Delaunay } 836*c7061045SPatrick Delaunay } 837*c7061045SPatrick Delaunay 838*c7061045SPatrick Delaunay return result; 839*c7061045SPatrick Delaunay } 840