1072d7532SNicolas Le Bayon /* 2c7061045SPatrick 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 24c7061045SPatrick Delaunay /* 25c7061045SPatrick Delaunay * IP configuration 26c7061045SPatrick Delaunay */ 27c7061045SPatrick Delaunay #define BSEC_OTP_MASK GENMASK(4, 0) 28c7061045SPatrick Delaunay #define BSEC_OTP_BANK_SHIFT 5 29c7061045SPatrick Delaunay #define BSEC_TIMEOUT_VALUE U(0xFFFF) 30c7061045SPatrick Delaunay 31072d7532SNicolas Le Bayon #define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT) 32072d7532SNicolas Le Bayon 33c7061045SPatrick Delaunay static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __maybe_unused; 34072d7532SNicolas Le Bayon 35c7061045SPatrick Delaunay static uint32_t bsec_shadow_register(uint32_t otp); 36072d7532SNicolas Le Bayon static uint32_t bsec_power_safmem(bool power); 37c7061045SPatrick Delaunay static uint32_t bsec_get_version(void); 38c7061045SPatrick Delaunay static uint32_t bsec_get_id(void); 39c7061045SPatrick Delaunay static uint32_t bsec_get_status(void); 40c7061045SPatrick 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 { 61c7061045SPatrick 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) { 169*cf237f8dSYann Gautier EARLY_ERROR("%s: DT not found\n", __func__); 170072d7532SNicolas Le Bayon panic(); 171072d7532SNicolas Le Bayon } 172072d7532SNicolas Le Bayon 173072d7532SNicolas Le Bayon node = bsec_get_dt_node(&bsec_info); 174072d7532SNicolas Le Bayon if (node < 0) { 175*cf237f8dSYann Gautier EARLY_ERROR("%s: BSEC node not found\n", __func__); 176072d7532SNicolas Le Bayon panic(); 177072d7532SNicolas Le Bayon } 178072d7532SNicolas Le Bayon 179c7061045SPatrick Delaunay assert(bsec_info.base == BSEC_BASE); 180072d7532SNicolas Le Bayon 181072d7532SNicolas Le Bayon bsec_dt_otp_nsec_access(fdt, node); 182072d7532SNicolas Le Bayon } 183072d7532SNicolas Le Bayon #endif 184072d7532SNicolas Le Bayon 185072d7532SNicolas Le Bayon static uint32_t otp_bank_offset(uint32_t otp) 186072d7532SNicolas Le Bayon { 187072d7532SNicolas Le Bayon assert(otp <= STM32MP1_OTP_MAX_ID); 188072d7532SNicolas Le Bayon 189072d7532SNicolas Le Bayon return ((otp & ~BSEC_OTP_MASK) >> BSEC_OTP_BANK_SHIFT) * 190072d7532SNicolas Le Bayon sizeof(uint32_t); 191072d7532SNicolas Le Bayon } 192072d7532SNicolas Le Bayon 193c7061045SPatrick Delaunay static uint32_t otp_bit_mask(uint32_t otp) 194c7061045SPatrick Delaunay { 195c7061045SPatrick Delaunay return BIT(otp & BSEC_OTP_MASK); 196c7061045SPatrick Delaunay } 197c7061045SPatrick Delaunay 198072d7532SNicolas Le Bayon /* 199072d7532SNicolas Le Bayon * bsec_check_error: check BSEC error status. 200072d7532SNicolas Le Bayon * otp: OTP number. 201072d7532SNicolas Le Bayon * check_disturbed: check only error (false), 202072d7532SNicolas Le Bayon * or error and disturbed status (true). 203072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 204072d7532SNicolas Le Bayon */ 205072d7532SNicolas Le Bayon static uint32_t bsec_check_error(uint32_t otp, bool check_disturbed) 206072d7532SNicolas Le Bayon { 207c7061045SPatrick Delaunay uint32_t bit = otp_bit_mask(otp); 208072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 209072d7532SNicolas Le Bayon 210c7061045SPatrick Delaunay if ((mmio_read_32(BSEC_BASE + BSEC_ERROR_OFF + bank) & bit) != 0U) { 211072d7532SNicolas Le Bayon return BSEC_ERROR; 212072d7532SNicolas Le Bayon } 213072d7532SNicolas Le Bayon 214072d7532SNicolas Le Bayon if (!check_disturbed) { 215072d7532SNicolas Le Bayon return BSEC_OK; 216072d7532SNicolas Le Bayon } 217072d7532SNicolas Le Bayon 218c7061045SPatrick Delaunay if ((mmio_read_32(BSEC_BASE + BSEC_DISTURBED_OFF + bank) & bit) != 0U) { 219072d7532SNicolas Le Bayon return BSEC_DISTURBED; 220072d7532SNicolas Le Bayon } 221072d7532SNicolas Le Bayon 222072d7532SNicolas Le Bayon return BSEC_OK; 223072d7532SNicolas Le Bayon } 224072d7532SNicolas Le Bayon 225072d7532SNicolas Le Bayon /* 226072d7532SNicolas Le Bayon * bsec_probe: initialize BSEC driver. 227072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 228072d7532SNicolas Le Bayon */ 229072d7532SNicolas Le Bayon uint32_t bsec_probe(void) 230072d7532SNicolas Le Bayon { 231*cf237f8dSYann Gautier uint32_t version; 232*cf237f8dSYann Gautier uint32_t id; 233*cf237f8dSYann Gautier 234072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 235*cf237f8dSYann Gautier EARLY_ERROR("%s: otp_invalid_mod\n", __func__); 236072d7532SNicolas Le Bayon return BSEC_ERROR; 237072d7532SNicolas Le Bayon } 238072d7532SNicolas Le Bayon 239*cf237f8dSYann Gautier version = bsec_get_version(); 240*cf237f8dSYann Gautier id = bsec_get_id(); 241*cf237f8dSYann Gautier 242*cf237f8dSYann Gautier if (((version != BSEC_IP_VERSION_1_1) && 243*cf237f8dSYann Gautier (version != BSEC_IP_VERSION_2_0)) || 244*cf237f8dSYann Gautier (id != BSEC_IP_ID_2)) { 245*cf237f8dSYann Gautier EARLY_ERROR("%s: version = 0x%x, id = 0x%x\n", __func__, version, id); 246072d7532SNicolas Le Bayon panic(); 247072d7532SNicolas Le Bayon } 248072d7532SNicolas Le Bayon 249072d7532SNicolas Le Bayon #if defined(IMAGE_BL32) 250072d7532SNicolas Le Bayon bsec_late_init(); 251072d7532SNicolas Le Bayon #endif 252072d7532SNicolas Le Bayon return BSEC_OK; 253072d7532SNicolas Le Bayon } 254072d7532SNicolas Le Bayon 255072d7532SNicolas Le Bayon /* 256072d7532SNicolas Le Bayon * bsec_shadow_register: copy SAFMEM OTP to BSEC data. 257072d7532SNicolas Le Bayon * otp: OTP number. 258072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 259072d7532SNicolas Le Bayon */ 260c7061045SPatrick Delaunay static uint32_t bsec_shadow_register(uint32_t otp) 261072d7532SNicolas Le Bayon { 262072d7532SNicolas Le Bayon uint32_t result; 263072d7532SNicolas Le Bayon bool value; 264072d7532SNicolas Le Bayon bool power_up = false; 265072d7532SNicolas Le Bayon 266072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 267072d7532SNicolas Le Bayon return BSEC_ERROR; 268072d7532SNicolas Le Bayon } 269072d7532SNicolas Le Bayon 270072d7532SNicolas Le Bayon result = bsec_read_sr_lock(otp, &value); 271072d7532SNicolas Le Bayon if (result != BSEC_OK) { 272072d7532SNicolas Le Bayon ERROR("BSEC: %u Sticky-read bit read Error %u\n", otp, result); 273072d7532SNicolas Le Bayon return result; 274072d7532SNicolas Le Bayon } 275072d7532SNicolas Le Bayon 276072d7532SNicolas Le Bayon if (value) { 277072d7532SNicolas Le Bayon VERBOSE("BSEC: OTP %u is locked and will not be refreshed\n", 278072d7532SNicolas Le Bayon otp); 279072d7532SNicolas Le Bayon } 280072d7532SNicolas Le Bayon 281c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) { 282072d7532SNicolas Le Bayon result = bsec_power_safmem(true); 283072d7532SNicolas Le Bayon 284072d7532SNicolas Le Bayon if (result != BSEC_OK) { 285072d7532SNicolas Le Bayon return result; 286072d7532SNicolas Le Bayon } 287072d7532SNicolas Le Bayon 288072d7532SNicolas Le Bayon power_up = true; 289072d7532SNicolas Le Bayon } 290072d7532SNicolas Le Bayon 291072d7532SNicolas Le Bayon bsec_lock(); 292072d7532SNicolas Le Bayon 293c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, otp | BSEC_READ); 294072d7532SNicolas Le Bayon 295c7061045SPatrick Delaunay while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) { 296072d7532SNicolas Le Bayon ; 297072d7532SNicolas Le Bayon } 298072d7532SNicolas Le Bayon 299072d7532SNicolas Le Bayon result = bsec_check_error(otp, true); 300072d7532SNicolas Le Bayon 301072d7532SNicolas Le Bayon bsec_unlock(); 302072d7532SNicolas Le Bayon 303072d7532SNicolas Le Bayon if (power_up) { 304072d7532SNicolas Le Bayon if (bsec_power_safmem(false) != BSEC_OK) { 305072d7532SNicolas Le Bayon panic(); 306072d7532SNicolas Le Bayon } 307072d7532SNicolas Le Bayon } 308072d7532SNicolas Le Bayon 309072d7532SNicolas Le Bayon return result; 310072d7532SNicolas Le Bayon } 311072d7532SNicolas Le Bayon 312072d7532SNicolas Le Bayon /* 313072d7532SNicolas Le Bayon * bsec_read_otp: read an OTP data value. 314072d7532SNicolas Le Bayon * val: read value. 315072d7532SNicolas Le Bayon * otp: OTP number. 316072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 317072d7532SNicolas Le Bayon */ 318072d7532SNicolas Le Bayon uint32_t bsec_read_otp(uint32_t *val, uint32_t otp) 319072d7532SNicolas Le Bayon { 320072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 321072d7532SNicolas Le Bayon return BSEC_ERROR; 322072d7532SNicolas Le Bayon } 323072d7532SNicolas Le Bayon 324072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 325072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 326072d7532SNicolas Le Bayon } 327072d7532SNicolas Le Bayon 328c7061045SPatrick Delaunay *val = mmio_read_32(BSEC_BASE + BSEC_OTP_DATA_OFF + 329072d7532SNicolas Le Bayon (otp * sizeof(uint32_t))); 330072d7532SNicolas Le Bayon 331072d7532SNicolas Le Bayon return BSEC_OK; 332072d7532SNicolas Le Bayon } 333072d7532SNicolas Le Bayon 334072d7532SNicolas Le Bayon /* 335072d7532SNicolas Le Bayon * bsec_write_otp: write value in BSEC data register. 336072d7532SNicolas Le Bayon * val: value to write. 337072d7532SNicolas Le Bayon * otp: OTP number. 338072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 339072d7532SNicolas Le Bayon */ 340072d7532SNicolas Le Bayon uint32_t bsec_write_otp(uint32_t val, uint32_t otp) 341072d7532SNicolas Le Bayon { 342072d7532SNicolas Le Bayon uint32_t result; 343072d7532SNicolas Le Bayon bool value; 344072d7532SNicolas Le Bayon 345072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 346072d7532SNicolas Le Bayon return BSEC_ERROR; 347072d7532SNicolas Le Bayon } 348072d7532SNicolas Le Bayon 349072d7532SNicolas Le Bayon result = bsec_read_sw_lock(otp, &value); 350072d7532SNicolas Le Bayon if (result != BSEC_OK) { 351072d7532SNicolas Le Bayon ERROR("BSEC: %u Sticky-write bit read Error %u\n", otp, result); 352072d7532SNicolas Le Bayon return result; 353072d7532SNicolas Le Bayon } 354072d7532SNicolas Le Bayon 355072d7532SNicolas Le Bayon if (value) { 356072d7532SNicolas Le Bayon VERBOSE("BSEC: OTP %u is locked and write will be ignored\n", 357072d7532SNicolas Le Bayon otp); 358072d7532SNicolas Le Bayon } 359072d7532SNicolas Le Bayon 360072d7532SNicolas Le Bayon /* Ensure integrity of each register access sequence */ 361072d7532SNicolas Le Bayon bsec_lock(); 362072d7532SNicolas Le Bayon 363c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_DATA_OFF + 364072d7532SNicolas Le Bayon (otp * sizeof(uint32_t)), val); 365072d7532SNicolas Le Bayon 366072d7532SNicolas Le Bayon bsec_unlock(); 367072d7532SNicolas Le Bayon 368072d7532SNicolas Le Bayon return result; 369072d7532SNicolas Le Bayon } 370072d7532SNicolas Le Bayon 371072d7532SNicolas Le Bayon /* 372072d7532SNicolas Le Bayon * bsec_program_otp: program a bit in SAFMEM after the prog. 373072d7532SNicolas Le Bayon * The OTP data is not refreshed. 374072d7532SNicolas Le Bayon * val: value to program. 375072d7532SNicolas Le Bayon * otp: OTP number. 376072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 377072d7532SNicolas Le Bayon */ 378072d7532SNicolas Le Bayon uint32_t bsec_program_otp(uint32_t val, uint32_t otp) 379072d7532SNicolas Le Bayon { 380072d7532SNicolas Le Bayon uint32_t result; 381072d7532SNicolas Le Bayon bool power_up = false; 382072d7532SNicolas Le Bayon bool sp_lock; 383072d7532SNicolas Le Bayon bool perm_lock; 384072d7532SNicolas Le Bayon 385072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 386072d7532SNicolas Le Bayon return BSEC_ERROR; 387072d7532SNicolas Le Bayon } 388072d7532SNicolas Le Bayon 389072d7532SNicolas Le Bayon result = bsec_read_sp_lock(otp, &sp_lock); 390072d7532SNicolas Le Bayon if (result != BSEC_OK) { 391072d7532SNicolas Le Bayon ERROR("BSEC: %u Sticky-prog bit read Error %u\n", otp, result); 392072d7532SNicolas Le Bayon return result; 393072d7532SNicolas Le Bayon } 394072d7532SNicolas Le Bayon 395072d7532SNicolas Le Bayon result = bsec_read_permanent_lock(otp, &perm_lock); 396072d7532SNicolas Le Bayon if (result != BSEC_OK) { 397072d7532SNicolas Le Bayon ERROR("BSEC: %u permanent bit read Error %u\n", otp, result); 398072d7532SNicolas Le Bayon return result; 399072d7532SNicolas Le Bayon } 400072d7532SNicolas Le Bayon 401072d7532SNicolas Le Bayon if (sp_lock || perm_lock) { 402072d7532SNicolas Le Bayon WARN("BSEC: OTP locked, prog will be ignored\n"); 403072d7532SNicolas Le Bayon return BSEC_PROG_FAIL; 404072d7532SNicolas Le Bayon } 405072d7532SNicolas Le Bayon 406c7061045SPatrick Delaunay if ((mmio_read_32(BSEC_BASE + BSEC_OTP_LOCK_OFF) & GPLOCK_LOCK_MASK) != 0U) { 407072d7532SNicolas Le Bayon WARN("BSEC: GPLOCK activated, prog will be ignored\n"); 408072d7532SNicolas Le Bayon } 409072d7532SNicolas Le Bayon 410c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) { 411072d7532SNicolas Le Bayon result = bsec_power_safmem(true); 412072d7532SNicolas Le Bayon 413072d7532SNicolas Le Bayon if (result != BSEC_OK) { 414072d7532SNicolas Le Bayon return result; 415072d7532SNicolas Le Bayon } 416072d7532SNicolas Le Bayon 417072d7532SNicolas Le Bayon power_up = true; 418072d7532SNicolas Le Bayon } 419072d7532SNicolas Le Bayon 420072d7532SNicolas Le Bayon bsec_lock(); 421072d7532SNicolas Le Bayon 422c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_WRDATA_OFF, val); 423072d7532SNicolas Le Bayon 424c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, otp | BSEC_WRITE); 425072d7532SNicolas Le Bayon 426c7061045SPatrick Delaunay while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) { 427072d7532SNicolas Le Bayon ; 428072d7532SNicolas Le Bayon } 429072d7532SNicolas Le Bayon 430c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 0U) { 431072d7532SNicolas Le Bayon result = BSEC_PROG_FAIL; 432072d7532SNicolas Le Bayon } else { 433072d7532SNicolas Le Bayon result = bsec_check_error(otp, true); 434072d7532SNicolas Le Bayon } 435072d7532SNicolas Le Bayon 436072d7532SNicolas Le Bayon bsec_unlock(); 437072d7532SNicolas Le Bayon 438072d7532SNicolas Le Bayon if (power_up) { 439072d7532SNicolas Le Bayon if (bsec_power_safmem(false) != BSEC_OK) { 440072d7532SNicolas Le Bayon panic(); 441072d7532SNicolas Le Bayon } 442072d7532SNicolas Le Bayon } 443072d7532SNicolas Le Bayon 444072d7532SNicolas Le Bayon return result; 445072d7532SNicolas Le Bayon } 446072d7532SNicolas Le Bayon 447072d7532SNicolas Le Bayon /* 448072d7532SNicolas Le Bayon * bsec_permanent_lock_otp: permanent lock of OTP in SAFMEM. 449072d7532SNicolas Le Bayon * otp: OTP number. 450072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 451072d7532SNicolas Le Bayon */ 452c7061045SPatrick Delaunay #if defined(IMAGE_BL32) 453072d7532SNicolas Le Bayon uint32_t bsec_permanent_lock_otp(uint32_t otp) 454072d7532SNicolas Le Bayon { 455072d7532SNicolas Le Bayon uint32_t result; 456072d7532SNicolas Le Bayon bool power_up = false; 457072d7532SNicolas Le Bayon uint32_t data; 458072d7532SNicolas Le Bayon uint32_t addr; 459072d7532SNicolas Le Bayon 460072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 461072d7532SNicolas Le Bayon return BSEC_ERROR; 462072d7532SNicolas Le Bayon } 463072d7532SNicolas Le Bayon 464072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 465072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 466072d7532SNicolas Le Bayon } 467072d7532SNicolas Le Bayon 468c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) { 469072d7532SNicolas Le Bayon result = bsec_power_safmem(true); 470072d7532SNicolas Le Bayon 471072d7532SNicolas Le Bayon if (result != BSEC_OK) { 472072d7532SNicolas Le Bayon return result; 473072d7532SNicolas Le Bayon } 474072d7532SNicolas Le Bayon 475072d7532SNicolas Le Bayon power_up = true; 476072d7532SNicolas Le Bayon } 477072d7532SNicolas Le Bayon 478072d7532SNicolas Le Bayon if (otp < STM32MP1_UPPER_OTP_START) { 479072d7532SNicolas Le Bayon addr = otp >> ADDR_LOWER_OTP_PERLOCK_SHIFT; 480072d7532SNicolas Le Bayon data = DATA_LOWER_OTP_PERLOCK_BIT << 481072d7532SNicolas Le Bayon ((otp & DATA_LOWER_OTP_PERLOCK_MASK) << 1U); 482072d7532SNicolas Le Bayon } else { 483072d7532SNicolas Le Bayon addr = (otp >> ADDR_UPPER_OTP_PERLOCK_SHIFT) + 2U; 484072d7532SNicolas Le Bayon data = DATA_UPPER_OTP_PERLOCK_BIT << 485072d7532SNicolas Le Bayon (otp & DATA_UPPER_OTP_PERLOCK_MASK); 486072d7532SNicolas Le Bayon } 487072d7532SNicolas Le Bayon 488072d7532SNicolas Le Bayon bsec_lock(); 489072d7532SNicolas Le Bayon 490c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_WRDATA_OFF, data); 491072d7532SNicolas Le Bayon 492c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_CTRL_OFF, 493072d7532SNicolas Le Bayon addr | BSEC_WRITE | BSEC_LOCK); 494072d7532SNicolas Le Bayon 495c7061045SPatrick Delaunay while ((bsec_get_status() & BSEC_OTP_STATUS_BUSY) != 0U) { 496072d7532SNicolas Le Bayon ; 497072d7532SNicolas Le Bayon } 498072d7532SNicolas Le Bayon 499c7061045SPatrick Delaunay if ((bsec_get_status() & BSEC_OTP_STATUS_PROGFAIL) != 0U) { 500072d7532SNicolas Le Bayon result = BSEC_PROG_FAIL; 501072d7532SNicolas Le Bayon } else { 502072d7532SNicolas Le Bayon result = bsec_check_error(otp, false); 503072d7532SNicolas Le Bayon } 504072d7532SNicolas Le Bayon 505072d7532SNicolas Le Bayon bsec_unlock(); 506072d7532SNicolas Le Bayon 507072d7532SNicolas Le Bayon if (power_up) { 508072d7532SNicolas Le Bayon if (bsec_power_safmem(false) != BSEC_OK) { 509072d7532SNicolas Le Bayon panic(); 510072d7532SNicolas Le Bayon } 511072d7532SNicolas Le Bayon } 512072d7532SNicolas Le Bayon 513072d7532SNicolas Le Bayon return result; 514072d7532SNicolas Le Bayon } 515c7061045SPatrick Delaunay #endif 516072d7532SNicolas Le Bayon 517072d7532SNicolas Le Bayon /* 518072d7532SNicolas Le Bayon * bsec_read_debug_conf: return debug configuration register value. 519072d7532SNicolas Le Bayon */ 520072d7532SNicolas Le Bayon uint32_t bsec_read_debug_conf(void) 521072d7532SNicolas Le Bayon { 522c7061045SPatrick Delaunay return mmio_read_32(BSEC_BASE + BSEC_DEN_OFF); 523072d7532SNicolas Le Bayon } 524072d7532SNicolas Le Bayon 525072d7532SNicolas Le Bayon /* 526072d7532SNicolas Le Bayon * bsec_write_scratch: write value in scratch register. 527072d7532SNicolas Le Bayon * val: value to write. 528072d7532SNicolas Le Bayon * return value: none. 529072d7532SNicolas Le Bayon */ 530072d7532SNicolas Le Bayon void bsec_write_scratch(uint32_t val) 531072d7532SNicolas Le Bayon { 532072d7532SNicolas Le Bayon #if defined(IMAGE_BL32) 533072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 534072d7532SNicolas Le Bayon return; 535072d7532SNicolas Le Bayon } 536072d7532SNicolas Le Bayon 537072d7532SNicolas Le Bayon bsec_lock(); 538c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val); 539072d7532SNicolas Le Bayon bsec_unlock(); 540072d7532SNicolas Le Bayon #else 541072d7532SNicolas Le Bayon mmio_write_32(BSEC_BASE + BSEC_SCRATCH_OFF, val); 542072d7532SNicolas Le Bayon #endif 543072d7532SNicolas Le Bayon } 544072d7532SNicolas Le Bayon 545072d7532SNicolas Le Bayon /* 546072d7532SNicolas Le Bayon * bsec_get_status: return status register value. 547072d7532SNicolas Le Bayon */ 548c7061045SPatrick Delaunay static uint32_t bsec_get_status(void) 549072d7532SNicolas Le Bayon { 550c7061045SPatrick Delaunay return mmio_read_32(BSEC_BASE + BSEC_OTP_STATUS_OFF); 551072d7532SNicolas Le Bayon } 552072d7532SNicolas Le Bayon 553072d7532SNicolas Le Bayon /* 554072d7532SNicolas Le Bayon * bsec_get_version: return BSEC version register value. 555072d7532SNicolas Le Bayon */ 556c7061045SPatrick Delaunay static uint32_t bsec_get_version(void) 557072d7532SNicolas Le Bayon { 558c7061045SPatrick Delaunay return mmio_read_32(BSEC_BASE + BSEC_IPVR_OFF) & BSEC_IPVR_MSK; 559072d7532SNicolas Le Bayon } 560072d7532SNicolas Le Bayon 561072d7532SNicolas Le Bayon /* 562072d7532SNicolas Le Bayon * bsec_get_id: return BSEC ID register value. 563072d7532SNicolas Le Bayon */ 564c7061045SPatrick Delaunay static uint32_t bsec_get_id(void) 565072d7532SNicolas Le Bayon { 566c7061045SPatrick Delaunay return mmio_read_32(BSEC_BASE + BSEC_IP_ID_OFF); 567072d7532SNicolas Le Bayon } 568072d7532SNicolas Le Bayon 569072d7532SNicolas Le Bayon /* 570072d7532SNicolas Le Bayon * bsec_set_sr_lock: set shadow-read lock. 571072d7532SNicolas Le Bayon * otp: OTP number. 572072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 573072d7532SNicolas Le Bayon */ 574072d7532SNicolas Le Bayon uint32_t bsec_set_sr_lock(uint32_t otp) 575072d7532SNicolas Le Bayon { 576072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 577c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 578072d7532SNicolas Le Bayon 579072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 580072d7532SNicolas Le Bayon return BSEC_ERROR; 581072d7532SNicolas Le Bayon } 582072d7532SNicolas Le Bayon 583072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 584072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 585072d7532SNicolas Le Bayon } 586072d7532SNicolas Le Bayon 587072d7532SNicolas Le Bayon bsec_lock(); 588c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_SRLOCK_OFF + bank, otp_mask); 589072d7532SNicolas Le Bayon bsec_unlock(); 590072d7532SNicolas Le Bayon 591072d7532SNicolas Le Bayon return BSEC_OK; 592072d7532SNicolas Le Bayon } 593072d7532SNicolas Le Bayon 594072d7532SNicolas Le Bayon /* 595072d7532SNicolas Le Bayon * bsec_read_sr_lock: read shadow-read lock. 596072d7532SNicolas Le Bayon * otp: OTP number. 597072d7532SNicolas Le Bayon * value: read value (true or false). 598072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 599072d7532SNicolas Le Bayon */ 600072d7532SNicolas Le Bayon uint32_t bsec_read_sr_lock(uint32_t otp, bool *value) 601072d7532SNicolas Le Bayon { 602072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 603c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 604072d7532SNicolas Le Bayon uint32_t bank_value; 605072d7532SNicolas Le Bayon 606072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 607072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 608072d7532SNicolas Le Bayon } 609072d7532SNicolas Le Bayon 610c7061045SPatrick Delaunay bank_value = mmio_read_32(BSEC_BASE + BSEC_SRLOCK_OFF + bank); 611072d7532SNicolas Le Bayon 612072d7532SNicolas Le Bayon *value = ((bank_value & otp_mask) != 0U); 613072d7532SNicolas Le Bayon 614072d7532SNicolas Le Bayon return BSEC_OK; 615072d7532SNicolas Le Bayon } 616072d7532SNicolas Le Bayon 617072d7532SNicolas Le Bayon /* 618072d7532SNicolas Le Bayon * bsec_set_sw_lock: set shadow-write lock. 619072d7532SNicolas Le Bayon * otp: OTP number. 620072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 621072d7532SNicolas Le Bayon */ 622072d7532SNicolas Le Bayon uint32_t bsec_set_sw_lock(uint32_t otp) 623072d7532SNicolas Le Bayon { 624072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 625c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 626072d7532SNicolas Le Bayon 627072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 628072d7532SNicolas Le Bayon return BSEC_ERROR; 629072d7532SNicolas Le Bayon } 630072d7532SNicolas Le Bayon 631072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 632072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 633072d7532SNicolas Le Bayon } 634072d7532SNicolas Le Bayon 635072d7532SNicolas Le Bayon bsec_lock(); 636c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_SWLOCK_OFF + bank, otp_mask); 637072d7532SNicolas Le Bayon bsec_unlock(); 638072d7532SNicolas Le Bayon 639072d7532SNicolas Le Bayon return BSEC_OK; 640072d7532SNicolas Le Bayon } 641072d7532SNicolas Le Bayon 642072d7532SNicolas Le Bayon /* 643072d7532SNicolas Le Bayon * bsec_read_sw_lock: read shadow-write lock. 644072d7532SNicolas Le Bayon * otp: OTP number. 645072d7532SNicolas Le Bayon * value: read value (true or false). 646072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 647072d7532SNicolas Le Bayon */ 648072d7532SNicolas Le Bayon uint32_t bsec_read_sw_lock(uint32_t otp, bool *value) 649072d7532SNicolas Le Bayon { 650072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 651072d7532SNicolas Le Bayon uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); 652072d7532SNicolas Le Bayon uint32_t bank_value; 653072d7532SNicolas Le Bayon 654072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 655072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 656072d7532SNicolas Le Bayon } 657072d7532SNicolas Le Bayon 658c7061045SPatrick Delaunay bank_value = mmio_read_32(BSEC_BASE + BSEC_SWLOCK_OFF + bank); 659072d7532SNicolas Le Bayon 660072d7532SNicolas Le Bayon *value = ((bank_value & otp_mask) != 0U); 661072d7532SNicolas Le Bayon 662072d7532SNicolas Le Bayon return BSEC_OK; 663072d7532SNicolas Le Bayon } 664072d7532SNicolas Le Bayon 665072d7532SNicolas Le Bayon /* 666072d7532SNicolas Le Bayon * bsec_set_sp_lock: set shadow-program lock. 667072d7532SNicolas Le Bayon * otp: OTP number. 668072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 669072d7532SNicolas Le Bayon */ 670072d7532SNicolas Le Bayon uint32_t bsec_set_sp_lock(uint32_t otp) 671072d7532SNicolas Le Bayon { 672072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 673c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 674072d7532SNicolas Le Bayon 675072d7532SNicolas Le Bayon if (is_otp_invalid_mode()) { 676072d7532SNicolas Le Bayon return BSEC_ERROR; 677072d7532SNicolas Le Bayon } 678072d7532SNicolas Le Bayon 679072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 680072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 681072d7532SNicolas Le Bayon } 682072d7532SNicolas Le Bayon 683072d7532SNicolas Le Bayon bsec_lock(); 684c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_SPLOCK_OFF + bank, otp_mask); 685072d7532SNicolas Le Bayon bsec_unlock(); 686072d7532SNicolas Le Bayon 687072d7532SNicolas Le Bayon return BSEC_OK; 688072d7532SNicolas Le Bayon } 689072d7532SNicolas Le Bayon 690072d7532SNicolas Le Bayon /* 691072d7532SNicolas Le Bayon * bsec_read_sp_lock: read shadow-program lock. 692072d7532SNicolas Le Bayon * otp: OTP number. 693072d7532SNicolas Le Bayon * value: read value (true or false). 694072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 695072d7532SNicolas Le Bayon */ 696072d7532SNicolas Le Bayon uint32_t bsec_read_sp_lock(uint32_t otp, bool *value) 697072d7532SNicolas Le Bayon { 698072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 699072d7532SNicolas Le Bayon uint32_t otp_mask = BIT(otp & BSEC_OTP_MASK); 700072d7532SNicolas Le Bayon uint32_t bank_value; 701072d7532SNicolas Le Bayon 702072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 703072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 704072d7532SNicolas Le Bayon } 705072d7532SNicolas Le Bayon 706c7061045SPatrick Delaunay bank_value = mmio_read_32(BSEC_BASE + BSEC_SPLOCK_OFF + bank); 707072d7532SNicolas Le Bayon 708072d7532SNicolas Le Bayon *value = ((bank_value & otp_mask) != 0U); 709072d7532SNicolas Le Bayon 710072d7532SNicolas Le Bayon return BSEC_OK; 711072d7532SNicolas Le Bayon } 712072d7532SNicolas Le Bayon 713072d7532SNicolas Le Bayon /* 714072d7532SNicolas Le Bayon * bsec_read_permanent_lock: Read permanent lock status. 715072d7532SNicolas Le Bayon * otp: OTP number. 716072d7532SNicolas Le Bayon * value: read value (true or false). 717072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 718072d7532SNicolas Le Bayon */ 719c7061045SPatrick Delaunay static uint32_t bsec_read_permanent_lock(uint32_t otp, bool *value) 720072d7532SNicolas Le Bayon { 721072d7532SNicolas Le Bayon uint32_t bank = otp_bank_offset(otp); 722c7061045SPatrick Delaunay uint32_t otp_mask = otp_bit_mask(otp); 723072d7532SNicolas Le Bayon uint32_t bank_value; 724072d7532SNicolas Le Bayon 725072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 726072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 727072d7532SNicolas Le Bayon } 728072d7532SNicolas Le Bayon 729c7061045SPatrick Delaunay bank_value = mmio_read_32(BSEC_BASE + BSEC_WRLOCK_OFF + bank); 730072d7532SNicolas Le Bayon 731072d7532SNicolas Le Bayon *value = ((bank_value & otp_mask) != 0U); 732072d7532SNicolas Le Bayon 733072d7532SNicolas Le Bayon return BSEC_OK; 734072d7532SNicolas Le Bayon } 735072d7532SNicolas Le Bayon 736072d7532SNicolas Le Bayon /* 737072d7532SNicolas Le Bayon * bsec_power_safmem: Activate or deactivate SAFMEM power. 738072d7532SNicolas Le Bayon * power: true to power up, false to power down. 739072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 740072d7532SNicolas Le Bayon */ 741072d7532SNicolas Le Bayon static uint32_t bsec_power_safmem(bool power) 742072d7532SNicolas Le Bayon { 743072d7532SNicolas Le Bayon uint32_t register_val; 744072d7532SNicolas Le Bayon uint32_t timeout = BSEC_TIMEOUT_VALUE; 745072d7532SNicolas Le Bayon 746072d7532SNicolas Le Bayon bsec_lock(); 747072d7532SNicolas Le Bayon 748c7061045SPatrick Delaunay register_val = mmio_read_32(BSEC_BASE + BSEC_OTP_CONF_OFF); 749072d7532SNicolas Le Bayon 750072d7532SNicolas Le Bayon if (power) { 751072d7532SNicolas Le Bayon register_val |= BSEC_CONF_POWER_UP_MASK; 752072d7532SNicolas Le Bayon } else { 753072d7532SNicolas Le Bayon register_val &= ~BSEC_CONF_POWER_UP_MASK; 754072d7532SNicolas Le Bayon } 755072d7532SNicolas Le Bayon 756c7061045SPatrick Delaunay mmio_write_32(BSEC_BASE + BSEC_OTP_CONF_OFF, register_val); 757072d7532SNicolas Le Bayon 758072d7532SNicolas Le Bayon if (power) { 759c7061045SPatrick Delaunay while (((bsec_get_status() & BSEC_OTP_STATUS_PWRON) == 0U) && 760072d7532SNicolas Le Bayon (timeout != 0U)) { 761072d7532SNicolas Le Bayon timeout--; 762072d7532SNicolas Le Bayon } 763072d7532SNicolas Le Bayon } else { 764c7061045SPatrick Delaunay while (((bsec_get_status() & BSEC_OTP_STATUS_PWRON) != 0U) && 765072d7532SNicolas Le Bayon (timeout != 0U)) { 766072d7532SNicolas Le Bayon timeout--; 767072d7532SNicolas Le Bayon } 768072d7532SNicolas Le Bayon } 769072d7532SNicolas Le Bayon 770072d7532SNicolas Le Bayon bsec_unlock(); 771072d7532SNicolas Le Bayon 772072d7532SNicolas Le Bayon if (timeout == 0U) { 773072d7532SNicolas Le Bayon return BSEC_TIMEOUT; 774072d7532SNicolas Le Bayon } 775072d7532SNicolas Le Bayon 776072d7532SNicolas Le Bayon return BSEC_OK; 777072d7532SNicolas Le Bayon } 778072d7532SNicolas Le Bayon 779072d7532SNicolas Le Bayon /* 780072d7532SNicolas Le Bayon * bsec_shadow_read_otp: Load OTP from SAFMEM and provide its value. 781c7061045SPatrick Delaunay * val: read value. 782c7061045SPatrick Delaunay * otp: OTP number. 783072d7532SNicolas Le Bayon * return value: BSEC_OK if no error. 784072d7532SNicolas Le Bayon */ 785c7061045SPatrick Delaunay uint32_t bsec_shadow_read_otp(uint32_t *val, uint32_t otp) 786072d7532SNicolas Le Bayon { 787072d7532SNicolas Le Bayon uint32_t result; 788072d7532SNicolas Le Bayon 789c7061045SPatrick Delaunay result = bsec_shadow_register(otp); 790072d7532SNicolas Le Bayon if (result != BSEC_OK) { 791c7061045SPatrick Delaunay ERROR("BSEC: %u Shadowing Error %u\n", otp, result); 792072d7532SNicolas Le Bayon return result; 793072d7532SNicolas Le Bayon } 794072d7532SNicolas Le Bayon 795c7061045SPatrick Delaunay result = bsec_read_otp(val, otp); 796072d7532SNicolas Le Bayon if (result != BSEC_OK) { 797c7061045SPatrick Delaunay ERROR("BSEC: %u Read Error %u\n", otp, result); 798072d7532SNicolas Le Bayon } 799072d7532SNicolas Le Bayon 800072d7532SNicolas Le Bayon return result; 801072d7532SNicolas Le Bayon } 802072d7532SNicolas Le Bayon 803c7061045SPatrick Delaunay #if defined(IMAGE_BL32) 804072d7532SNicolas Le Bayon /* 805072d7532SNicolas Le Bayon * bsec_check_nsec_access_rights: check non-secure access rights to target OTP. 806072d7532SNicolas Le Bayon * otp: OTP number. 807072d7532SNicolas Le Bayon * return value: BSEC_OK if authorized access. 808072d7532SNicolas Le Bayon */ 809072d7532SNicolas Le Bayon uint32_t bsec_check_nsec_access_rights(uint32_t otp) 810072d7532SNicolas Le Bayon { 811072d7532SNicolas Le Bayon if (otp > STM32MP1_OTP_MAX_ID) { 812072d7532SNicolas Le Bayon return BSEC_INVALID_PARAM; 813072d7532SNicolas Le Bayon } 814072d7532SNicolas Le Bayon 815072d7532SNicolas Le Bayon if (otp >= STM32MP1_UPPER_OTP_START) { 816072d7532SNicolas Le Bayon if (!non_secure_can_access(otp)) { 817072d7532SNicolas Le Bayon return BSEC_ERROR; 818072d7532SNicolas Le Bayon } 819072d7532SNicolas Le Bayon } 820072d7532SNicolas Le Bayon 821072d7532SNicolas Le Bayon return BSEC_OK; 822072d7532SNicolas Le Bayon } 823c7061045SPatrick Delaunay #endif 824072d7532SNicolas Le Bayon 825c7061045SPatrick Delaunay uint32_t bsec_get_secure_state(void) 826c7061045SPatrick Delaunay { 827c7061045SPatrick Delaunay uint32_t status = bsec_get_status(); 828c7061045SPatrick Delaunay uint32_t result = BSEC_STATE_INVALID; 829c7061045SPatrick Delaunay uint32_t otp_enc_id __maybe_unused; 830c7061045SPatrick Delaunay uint32_t otp_bit_len __maybe_unused; 831c7061045SPatrick Delaunay int res __maybe_unused; 832c7061045SPatrick Delaunay 833c7061045SPatrick Delaunay if ((status & BSEC_OTP_STATUS_INVALID) != 0U) { 834c7061045SPatrick Delaunay result = BSEC_STATE_INVALID; 835c7061045SPatrick Delaunay } else { 836c7061045SPatrick Delaunay if ((status & BSEC_OTP_STATUS_SECURE) != 0U) { 8379cd784dbSYann Gautier if (stm32mp_check_closed_device() == STM32MP_CHIP_SEC_CLOSED) { 838c7061045SPatrick Delaunay result = BSEC_STATE_SEC_CLOSED; 839c7061045SPatrick Delaunay } else { 840c7061045SPatrick Delaunay result = BSEC_STATE_SEC_OPEN; 841c7061045SPatrick Delaunay } 842c7061045SPatrick Delaunay } else { 843c7061045SPatrick Delaunay /* OTP modes OPEN1 and OPEN2 are not supported */ 844c7061045SPatrick Delaunay result = BSEC_STATE_INVALID; 845c7061045SPatrick Delaunay } 846c7061045SPatrick Delaunay } 847c7061045SPatrick Delaunay 848c7061045SPatrick Delaunay return result; 849c7061045SPatrick Delaunay } 850