xref: /rk3399_ARM-atf/drivers/st/bsec/bsec2.c (revision c7061045072424dc47cc0a12d53bf0fa8a49f1c0)
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