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