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
bsec_lock(void)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
bsec_unlock(void)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
is_otp_invalid_mode(void)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)
bsec_get_dt_node(struct dt_node_info * info)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
enable_non_secure_access(uint32_t otp)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
non_secure_can_access(uint32_t otp)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
bsec_dt_otp_nsec_access(void * fdt,int bsec_node)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
bsec_late_init(void)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
otp_bank_offset(uint32_t otp)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
otp_bit_mask(uint32_t otp)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 */
bsec_check_error(uint32_t otp,bool check_disturbed)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 */
bsec_probe(void)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 */
bsec_shadow_register(uint32_t otp)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 */
bsec_read_otp(uint32_t * val,uint32_t otp)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 */
bsec_write_otp(uint32_t val,uint32_t otp)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 */
bsec_program_otp(uint32_t val,uint32_t otp)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)
bsec_permanent_lock_otp(uint32_t otp)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 */
bsec_read_debug_conf(void)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 */
bsec_write_scratch(uint32_t val)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 */
bsec_get_status(void)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 */
bsec_get_version(void)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 */
bsec_get_id(void)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 */
bsec_set_sr_lock(uint32_t otp)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 */
bsec_read_sr_lock(uint32_t otp,bool * value)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 */
bsec_set_sw_lock(uint32_t otp)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 */
bsec_read_sw_lock(uint32_t otp,bool * value)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 */
bsec_set_sp_lock(uint32_t otp)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 */
bsec_read_sp_lock(uint32_t otp,bool * value)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 */
bsec_read_permanent_lock(uint32_t otp,bool * value)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 */
bsec_power_safmem(bool power)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 */
bsec_shadow_read_otp(uint32_t * val,uint32_t otp)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 */
bsec_check_nsec_access_rights(uint32_t otp)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
bsec_get_secure_state(void)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