blob: fc39230113cc3a11cf84fabe45ddfb1b64cc5fe3 [file] [log] [blame]
Patrick Delaunay19f58992018-05-17 15:24:05 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4 */
5
6#include <common.h>
7#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -06008#include <log.h>
Patrick Delaunay19f58992018-05-17 15:24:05 +02009#include <misc.h>
10#include <asm/io.h>
Patrick Delaunayd859c612019-02-12 11:44:40 +010011#include <asm/arch/stm32mp1_smc.h>
12#include <linux/arm-smccc.h>
Patrick Delaunayee7d7722019-04-18 17:32:39 +020013#include <linux/iopoll.h>
Patrick Delaunay19f58992018-05-17 15:24:05 +020014
15#define BSEC_OTP_MAX_VALUE 95
Patrick Delaunay19f58992018-05-17 15:24:05 +020016#define BSEC_TIMEOUT_US 10000
17
18/* BSEC REGISTER OFFSET (base relative) */
19#define BSEC_OTP_CONF_OFF 0x000
20#define BSEC_OTP_CTRL_OFF 0x004
21#define BSEC_OTP_WRDATA_OFF 0x008
22#define BSEC_OTP_STATUS_OFF 0x00C
23#define BSEC_OTP_LOCK_OFF 0x010
24#define BSEC_DISTURBED_OFF 0x01C
25#define BSEC_ERROR_OFF 0x034
Patrick Delaunay7ae22d72020-02-12 19:37:38 +010026#define BSEC_WRLOCK_OFF 0x04C /* OTP write permananet lock */
27#define BSEC_SPLOCK_OFF 0x064 /* OTP write sticky lock */
28#define BSEC_SWLOCK_OFF 0x07C /* shadow write sticky lock */
29#define BSEC_SRLOCK_OFF 0x094 /* shadow read sticky lock */
Patrick Delaunay19f58992018-05-17 15:24:05 +020030#define BSEC_OTP_DATA_OFF 0x200
31
32/* BSEC_CONFIGURATION Register MASK */
33#define BSEC_CONF_POWER_UP 0x001
34
35/* BSEC_CONTROL Register */
36#define BSEC_READ 0x000
37#define BSEC_WRITE 0x100
38
39/* LOCK Register */
40#define OTP_LOCK_MASK 0x1F
41#define OTP_LOCK_BANK_SHIFT 0x05
42#define OTP_LOCK_BIT_MASK 0x01
43
44/* STATUS Register */
45#define BSEC_MODE_BUSY_MASK 0x08
46#define BSEC_MODE_PROGFAIL_MASK 0x10
47#define BSEC_MODE_PWR_MASK 0x20
48
49/*
50 * OTP Lock services definition
51 * Value must corresponding to the bit number in the register
52 */
53#define BSEC_LOCK_PROGRAM 0x04
54
55/**
Patrick Delaunay7ae22d72020-02-12 19:37:38 +010056 * bsec_lock() - manage lock for each type SR/SP/SW
57 * @address: address of bsec IP register
58 * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
59 * Return: true if locked else false
60 */
61static bool bsec_read_lock(u32 address, u32 otp)
62{
63 u32 bit;
64 u32 bank;
65
66 bit = 1 << (otp & OTP_LOCK_MASK);
67 bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32);
68
69 return !!(readl(address + bank) & bit);
70}
71
Patrick Delaunay654706b2020-04-01 09:07:33 +020072#ifndef CONFIG_TFABOOT
Patrick Delaunay7ae22d72020-02-12 19:37:38 +010073/**
Patrick Delaunay19f58992018-05-17 15:24:05 +020074 * bsec_check_error() - Check status of one otp
75 * @base: base address of bsec IP
76 * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
77 * Return: 0 if no error, -EAGAIN or -ENOTSUPP
78 */
79static u32 bsec_check_error(u32 base, u32 otp)
80{
81 u32 bit;
82 u32 bank;
83
84 bit = 1 << (otp & OTP_LOCK_MASK);
85 bank = ((otp >> OTP_LOCK_BANK_SHIFT) & OTP_LOCK_MASK) * sizeof(u32);
86
87 if (readl(base + BSEC_DISTURBED_OFF + bank) & bit)
88 return -EAGAIN;
89 else if (readl(base + BSEC_ERROR_OFF + bank) & bit)
90 return -ENOTSUPP;
91
92 return 0;
93}
94
95/**
Patrick Delaunay19f58992018-05-17 15:24:05 +020096 * bsec_read_SR_lock() - read SR lock (Shadowing)
97 * @base: base address of bsec IP
98 * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
99 * Return: true if locked else false
100 */
101static bool bsec_read_SR_lock(u32 base, u32 otp)
102{
103 return bsec_read_lock(base + BSEC_SRLOCK_OFF, otp);
104}
105
106/**
107 * bsec_read_SP_lock() - read SP lock (program Lock)
108 * @base: base address of bsec IP
109 * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
110 * Return: true if locked else false
111 */
112static bool bsec_read_SP_lock(u32 base, u32 otp)
113{
114 return bsec_read_lock(base + BSEC_SPLOCK_OFF, otp);
115}
116
117/**
118 * bsec_SW_lock() - manage SW lock (Write in Shadow)
119 * @base: base address of bsec IP
120 * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
121 * Return: true if locked else false
122 */
123static bool bsec_read_SW_lock(u32 base, u32 otp)
124{
125 return bsec_read_lock(base + BSEC_SWLOCK_OFF, otp);
126}
127
128/**
129 * bsec_power_safmem() - Activate or deactivate safmem power
130 * @base: base address of bsec IP
131 * @power: true to power up , false to power down
132 * Return: 0 if succeed
133 */
134static int bsec_power_safmem(u32 base, bool power)
135{
136 u32 val;
137 u32 mask;
138
139 if (power) {
140 setbits_le32(base + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP);
141 mask = BSEC_MODE_PWR_MASK;
142 } else {
143 clrbits_le32(base + BSEC_OTP_CONF_OFF, BSEC_CONF_POWER_UP);
144 mask = 0;
145 }
146
147 /* waiting loop */
148 return readl_poll_timeout(base + BSEC_OTP_STATUS_OFF,
149 val, (val & BSEC_MODE_PWR_MASK) == mask,
150 BSEC_TIMEOUT_US);
151}
152
153/**
154 * bsec_shadow_register() - copy safmen otp to bsec data
155 * @base: base address of bsec IP
156 * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
157 * Return: 0 if no error
158 */
159static int bsec_shadow_register(u32 base, u32 otp)
160{
161 u32 val;
162 int ret;
163 bool power_up = false;
164
165 /* check if shadowing of otp is locked */
166 if (bsec_read_SR_lock(base, otp))
167 pr_debug("bsec : OTP %d is locked and refreshed with 0\n", otp);
168
169 /* check if safemem is power up */
170 val = readl(base + BSEC_OTP_STATUS_OFF);
171 if (!(val & BSEC_MODE_PWR_MASK)) {
172 ret = bsec_power_safmem(base, true);
173 if (ret)
174 return ret;
Patrick Delaunay815bc8b2019-02-27 17:01:28 +0100175 power_up = true;
Patrick Delaunay19f58992018-05-17 15:24:05 +0200176 }
177 /* set BSEC_OTP_CTRL_OFF with the otp value*/
178 writel(otp | BSEC_READ, base + BSEC_OTP_CTRL_OFF);
179
180 /* check otp status*/
181 ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF,
182 val, (val & BSEC_MODE_BUSY_MASK) == 0,
183 BSEC_TIMEOUT_US);
184 if (ret)
185 return ret;
186
187 ret = bsec_check_error(base, otp);
188
189 if (power_up)
190 bsec_power_safmem(base, false);
191
192 return ret;
193}
194
195/**
196 * bsec_read_shadow() - read an otp data value from shadow
197 * @base: base address of bsec IP
198 * @val: read value
199 * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
200 * Return: 0 if no error
201 */
202static int bsec_read_shadow(u32 base, u32 *val, u32 otp)
203{
204 *val = readl(base + BSEC_OTP_DATA_OFF + otp * sizeof(u32));
205
206 return bsec_check_error(base, otp);
207}
208
209/**
210 * bsec_write_shadow() - write value in BSEC data register in shadow
211 * @base: base address of bsec IP
212 * @val: value to write
213 * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
214 * Return: 0 if no error
215 */
216static int bsec_write_shadow(u32 base, u32 val, u32 otp)
217{
218 /* check if programming of otp is locked */
219 if (bsec_read_SW_lock(base, otp))
220 pr_debug("bsec : OTP %d is lock, write will be ignore\n", otp);
221
222 writel(val, base + BSEC_OTP_DATA_OFF + otp * sizeof(u32));
223
224 return bsec_check_error(base, otp);
225}
226
227/**
228 * bsec_program_otp() - program a bit in SAFMEM
229 * @base: base address of bsec IP
230 * @val: value to program
231 * @otp: otp number (0 - BSEC_OTP_MAX_VALUE)
232 * after the function the otp data is not refreshed in shadow
233 * Return: 0 if no error
234 */
235static int bsec_program_otp(long base, u32 val, u32 otp)
236{
237 u32 ret;
238 bool power_up = false;
239
240 if (bsec_read_SP_lock(base, otp))
241 pr_debug("bsec : OTP %d locked, prog will be ignore\n", otp);
242
243 if (readl(base + BSEC_OTP_LOCK_OFF) & (1 << BSEC_LOCK_PROGRAM))
244 pr_debug("bsec : Global lock, prog will be ignore\n");
245
246 /* check if safemem is power up */
247 if (!(readl(base + BSEC_OTP_STATUS_OFF) & BSEC_MODE_PWR_MASK)) {
248 ret = bsec_power_safmem(base, true);
249 if (ret)
250 return ret;
251
252 power_up = true;
253 }
254 /* set value in write register*/
255 writel(val, base + BSEC_OTP_WRDATA_OFF);
256
257 /* set BSEC_OTP_CTRL_OFF with the otp value */
258 writel(otp | BSEC_WRITE, base + BSEC_OTP_CTRL_OFF);
259
260 /* check otp status*/
261 ret = readl_poll_timeout(base + BSEC_OTP_STATUS_OFF,
262 val, (val & BSEC_MODE_BUSY_MASK) == 0,
263 BSEC_TIMEOUT_US);
264 if (ret)
265 return ret;
266
267 if (val & BSEC_MODE_PROGFAIL_MASK)
268 ret = -EACCES;
269 else
270 ret = bsec_check_error(base, otp);
271
272 if (power_up)
273 bsec_power_safmem(base, false);
274
275 return ret;
276}
Patrick Delaunay654706b2020-04-01 09:07:33 +0200277#endif /* CONFIG_TFABOOT */
Patrick Delaunay19f58992018-05-17 15:24:05 +0200278
279/* BSEC MISC driver *******************************************************/
280struct stm32mp_bsec_platdata {
281 u32 base;
282};
283
284static int stm32mp_bsec_read_otp(struct udevice *dev, u32 *val, u32 otp)
285{
Patrick Delaunay654706b2020-04-01 09:07:33 +0200286#ifdef CONFIG_TFABOOT
Patrick Delaunayd859c612019-02-12 11:44:40 +0100287 return stm32_smc(STM32_SMC_BSEC,
288 STM32_SMC_READ_OTP,
289 otp, 0, val);
290#else
Patrick Delaunay19f58992018-05-17 15:24:05 +0200291 struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
292 u32 tmp_data = 0;
293 int ret;
294
295 /* read current shadow value */
296 ret = bsec_read_shadow(plat->base, &tmp_data, otp);
297 if (ret)
298 return ret;
299
300 /* copy otp in shadow */
301 ret = bsec_shadow_register(plat->base, otp);
302 if (ret)
303 return ret;
304
305 ret = bsec_read_shadow(plat->base, val, otp);
306 if (ret)
307 return ret;
308
309 /* restore shadow value */
310 ret = bsec_write_shadow(plat->base, tmp_data, otp);
311 return ret;
Patrick Delaunayd859c612019-02-12 11:44:40 +0100312#endif
Patrick Delaunay19f58992018-05-17 15:24:05 +0200313}
314
315static int stm32mp_bsec_read_shadow(struct udevice *dev, u32 *val, u32 otp)
316{
Patrick Delaunay654706b2020-04-01 09:07:33 +0200317#ifdef CONFIG_TFABOOT
Patrick Delaunayd859c612019-02-12 11:44:40 +0100318 return stm32_smc(STM32_SMC_BSEC,
319 STM32_SMC_READ_SHADOW,
320 otp, 0, val);
321#else
Patrick Delaunay19f58992018-05-17 15:24:05 +0200322 struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
323
324 return bsec_read_shadow(plat->base, val, otp);
Patrick Delaunayd859c612019-02-12 11:44:40 +0100325#endif
Patrick Delaunay19f58992018-05-17 15:24:05 +0200326}
327
Patrick Delaunay7ae22d72020-02-12 19:37:38 +0100328static int stm32mp_bsec_read_lock(struct udevice *dev, u32 *val, u32 otp)
329{
330 struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
331
332 /* return OTP permanent write lock status */
333 *val = bsec_read_lock(plat->base + BSEC_WRLOCK_OFF, otp);
334
335 return 0;
336}
337
Patrick Delaunay19f58992018-05-17 15:24:05 +0200338static int stm32mp_bsec_write_otp(struct udevice *dev, u32 val, u32 otp)
339{
Patrick Delaunay654706b2020-04-01 09:07:33 +0200340#ifdef CONFIG_TFABOOT
Patrick Delaunayd859c612019-02-12 11:44:40 +0100341 return stm32_smc_exec(STM32_SMC_BSEC,
342 STM32_SMC_PROG_OTP,
343 otp, val);
344#else
Patrick Delaunay19f58992018-05-17 15:24:05 +0200345 struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
346
347 return bsec_program_otp(plat->base, val, otp);
Patrick Delaunayd859c612019-02-12 11:44:40 +0100348#endif
Patrick Delaunay19f58992018-05-17 15:24:05 +0200349}
350
351static int stm32mp_bsec_write_shadow(struct udevice *dev, u32 val, u32 otp)
352{
Patrick Delaunay654706b2020-04-01 09:07:33 +0200353#ifdef CONFIG_TFABOOT
Patrick Delaunayd859c612019-02-12 11:44:40 +0100354 return stm32_smc_exec(STM32_SMC_BSEC,
355 STM32_SMC_WRITE_SHADOW,
356 otp, val);
357#else
Patrick Delaunay19f58992018-05-17 15:24:05 +0200358 struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
359
360 return bsec_write_shadow(plat->base, val, otp);
Patrick Delaunayd859c612019-02-12 11:44:40 +0100361#endif
Patrick Delaunay19f58992018-05-17 15:24:05 +0200362}
363
Patrick Delaunay7ae22d72020-02-12 19:37:38 +0100364static int stm32mp_bsec_write_lock(struct udevice *dev, u32 val, u32 otp)
365{
Patrick Delaunay654706b2020-04-01 09:07:33 +0200366#ifdef CONFIG_TFABOOT
Patrick Delaunay7ae22d72020-02-12 19:37:38 +0100367 if (val == 1)
368 return stm32_smc_exec(STM32_SMC_BSEC,
369 STM32_SMC_WRLOCK_OTP,
370 otp, 0);
371 if (val == 0)
372 return 0; /* nothing to do */
373
374 return -EINVAL;
375#else
376 return -ENOTSUPP;
377#endif
378}
379
Patrick Delaunay19f58992018-05-17 15:24:05 +0200380static int stm32mp_bsec_read(struct udevice *dev, int offset,
381 void *buf, int size)
382{
383 int ret;
384 int i;
Patrick Delaunay7ae22d72020-02-12 19:37:38 +0100385 bool shadow = true, lock = false;
Patrick Delaunay19f58992018-05-17 15:24:05 +0200386 int nb_otp = size / sizeof(u32);
387 int otp;
Patrick Delaunay745b6762019-06-21 15:26:43 +0200388 unsigned int offs = offset;
Patrick Delaunay19f58992018-05-17 15:24:05 +0200389
Patrick Delaunay7ae22d72020-02-12 19:37:38 +0100390 if (offs >= STM32_BSEC_LOCK_OFFSET) {
391 offs -= STM32_BSEC_LOCK_OFFSET;
392 lock = true;
393 } else if (offs >= STM32_BSEC_OTP_OFFSET) {
Patrick Delaunay745b6762019-06-21 15:26:43 +0200394 offs -= STM32_BSEC_OTP_OFFSET;
Patrick Delaunay19f58992018-05-17 15:24:05 +0200395 shadow = false;
396 }
Patrick Delaunay0c8620d2019-08-02 13:08:02 +0200397
Patrick Delaunaydf2d1b82020-02-12 19:37:37 +0100398 if ((offs % 4) || (size % 4))
Patrick Delaunay0c8620d2019-08-02 13:08:02 +0200399 return -EINVAL;
400
Patrick Delaunay745b6762019-06-21 15:26:43 +0200401 otp = offs / sizeof(u32);
Patrick Delaunay19f58992018-05-17 15:24:05 +0200402
Patrick Delaunay0c8620d2019-08-02 13:08:02 +0200403 for (i = otp; i < (otp + nb_otp) && i <= BSEC_OTP_MAX_VALUE; i++) {
Patrick Delaunay19f58992018-05-17 15:24:05 +0200404 u32 *addr = &((u32 *)buf)[i - otp];
405
Patrick Delaunay7ae22d72020-02-12 19:37:38 +0100406 if (lock)
407 ret = stm32mp_bsec_read_lock(dev, addr, i);
408 else if (shadow)
Patrick Delaunay19f58992018-05-17 15:24:05 +0200409 ret = stm32mp_bsec_read_shadow(dev, addr, i);
410 else
411 ret = stm32mp_bsec_read_otp(dev, addr, i);
412
413 if (ret)
414 break;
415 }
Patrick Delaunay0c8620d2019-08-02 13:08:02 +0200416 if (ret)
417 return ret;
418 else
419 return (i - otp) * 4;
Patrick Delaunay19f58992018-05-17 15:24:05 +0200420}
421
422static int stm32mp_bsec_write(struct udevice *dev, int offset,
423 const void *buf, int size)
424{
425 int ret = 0;
426 int i;
Patrick Delaunay7ae22d72020-02-12 19:37:38 +0100427 bool shadow = true, lock = false;
Patrick Delaunay19f58992018-05-17 15:24:05 +0200428 int nb_otp = size / sizeof(u32);
429 int otp;
Patrick Delaunay745b6762019-06-21 15:26:43 +0200430 unsigned int offs = offset;
Patrick Delaunay19f58992018-05-17 15:24:05 +0200431
Patrick Delaunay7ae22d72020-02-12 19:37:38 +0100432 if (offs >= STM32_BSEC_LOCK_OFFSET) {
433 offs -= STM32_BSEC_LOCK_OFFSET;
434 lock = true;
435 } else if (offs >= STM32_BSEC_OTP_OFFSET) {
Patrick Delaunay745b6762019-06-21 15:26:43 +0200436 offs -= STM32_BSEC_OTP_OFFSET;
Patrick Delaunay19f58992018-05-17 15:24:05 +0200437 shadow = false;
438 }
Patrick Delaunay0c8620d2019-08-02 13:08:02 +0200439
Patrick Delaunaydf2d1b82020-02-12 19:37:37 +0100440 if ((offs % 4) || (size % 4))
Patrick Delaunay0c8620d2019-08-02 13:08:02 +0200441 return -EINVAL;
442
Patrick Delaunay745b6762019-06-21 15:26:43 +0200443 otp = offs / sizeof(u32);
Patrick Delaunay19f58992018-05-17 15:24:05 +0200444
Patrick Delaunay0c8620d2019-08-02 13:08:02 +0200445 for (i = otp; i < otp + nb_otp && i <= BSEC_OTP_MAX_VALUE; i++) {
Patrick Delaunay19f58992018-05-17 15:24:05 +0200446 u32 *val = &((u32 *)buf)[i - otp];
447
Patrick Delaunay7ae22d72020-02-12 19:37:38 +0100448 if (lock)
449 ret = stm32mp_bsec_write_lock(dev, *val, i);
450 else if (shadow)
Patrick Delaunay19f58992018-05-17 15:24:05 +0200451 ret = stm32mp_bsec_write_shadow(dev, *val, i);
452 else
453 ret = stm32mp_bsec_write_otp(dev, *val, i);
454 if (ret)
455 break;
456 }
Patrick Delaunay0c8620d2019-08-02 13:08:02 +0200457 if (ret)
458 return ret;
459 else
460 return (i - otp) * 4;
Patrick Delaunay19f58992018-05-17 15:24:05 +0200461}
462
463static const struct misc_ops stm32mp_bsec_ops = {
464 .read = stm32mp_bsec_read,
465 .write = stm32mp_bsec_write,
466};
467
468static int stm32mp_bsec_ofdata_to_platdata(struct udevice *dev)
469{
470 struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
471
472 plat->base = (u32)dev_read_addr_ptr(dev);
473
474 return 0;
475}
476
Patrick Delaunay654706b2020-04-01 09:07:33 +0200477#ifndef CONFIG_TFABOOT
Patrick Delaunay815bc8b2019-02-27 17:01:28 +0100478static int stm32mp_bsec_probe(struct udevice *dev)
479{
480 int otp;
481 struct stm32mp_bsec_platdata *plat = dev_get_platdata(dev);
482
483 /* update unlocked shadow for OTP cleared by the rom code */
484 for (otp = 57; otp <= BSEC_OTP_MAX_VALUE; otp++)
485 if (!bsec_read_SR_lock(plat->base, otp))
486 bsec_shadow_register(plat->base, otp);
487
488 return 0;
489}
490#endif
491
Patrick Delaunay19f58992018-05-17 15:24:05 +0200492static const struct udevice_id stm32mp_bsec_ids[] = {
Patrick Delaunaybfe1f082019-02-27 17:01:27 +0100493 { .compatible = "st,stm32mp15-bsec" },
Patrick Delaunay19f58992018-05-17 15:24:05 +0200494 {}
495};
496
497U_BOOT_DRIVER(stm32mp_bsec) = {
498 .name = "stm32mp_bsec",
499 .id = UCLASS_MISC,
500 .of_match = stm32mp_bsec_ids,
501 .ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata,
502 .platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata),
503 .ops = &stm32mp_bsec_ops,
Patrick Delaunay654706b2020-04-01 09:07:33 +0200504#ifndef CONFIG_TFABOOT
Patrick Delaunay815bc8b2019-02-27 17:01:28 +0100505 .probe = stm32mp_bsec_probe,
506#endif
Patrick Delaunay19f58992018-05-17 15:24:05 +0200507};