1 /*
2 * Copyright (c) 2022, Arm Limited. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /**
18 * \file lcm_drv.c
19 * \brief Driver for Arm LCM.
20 */
21
22 #include "lcm_drv.h"
23 #include <stddef.h>
24 #include <stdint.h>
25
26 static uint8_t dummy_key_value[32] = {0x01, 0x02, 0x03, 0x04,
27 0x01, 0x02, 0x03, 0x04,
28 0x01, 0x02, 0x03, 0x04,
29 0x01, 0x02, 0x03, 0x04,
30 0x01, 0x02, 0x03, 0x04,
31 0x01, 0x02, 0x03, 0x04,
32 0x01, 0x02, 0x03, 0x04,
33 0x01, 0x02, 0x03, 0x04};
34
35 struct _lcm_reg_map_t {
36 volatile uint32_t lcs_value;
37 /*!< Offset: 0x000 (R/ ) LCM Lifecycle state Register */
38 volatile uint32_t key_err;
39 /*!< Offset: 0x004 (R/ ) LCM zero count error status Register */
40 volatile uint32_t tp_mode;
41 /*!< Offset: 0x008 (R/ ) LCM TP Mode (TCI/PCI) Register */
42 volatile uint32_t fatal_err;
43 /*!< Offset: 0x00C (R/W) LCM Fatal Error mode Enable Register */
44 volatile uint32_t dm_rma_lock;
45 /*!< Offset: 0x010 (R/W) LCM DRM RMA Flag lock enable */
46 volatile uint32_t sp_enable;
47 /*!< Offset: 0x014 (R/W) LCM Secure Provisioning enable
48 * Register */
49 volatile uint32_t otp_addr_width;
50 /*!< Offset: 0x018 (R/ ) LCM OTP Address Width Register */
51 volatile uint32_t otp_size_in_bytes;
52 /*!< Offset: 0x01C (R/ ) LCM OTP Size in bytes Register */
53 volatile uint32_t gppc;
54 /*!< Offset: 0x020 (R/ ) LCM General Purpose Persistent
55 * Configuration Register */
56 volatile uint32_t reserved_0[55];
57 /*!< Offset: 0x024-0x0FC Reserved */
58 volatile uint32_t dcu_en[4];
59 /*!< Offset: 0x100 (R/W) LCM DCU enable Registers */
60 volatile uint32_t dcu_lock[4];
61 /*!< Offset: 0x110 (R/W) LCM DCU lock Registers */
62 volatile uint32_t dcu_sp_disable_mask[4];
63 /*!< Offset: 0x120 (R/ ) LCM DCU SP disable mask Registers */
64 volatile uint32_t dcu_disable_mask[4];
65 /*!< Offset: 0x130 (R/ ) LCM DCU disable mask Registers */
66 volatile uint32_t reserved_1[932];
67 /*!< Offset: 0x140-0xFCC Reserved */
68 volatile uint32_t pidr4;
69 /*!< Offset: 0xFD0 (R/ ) Peripheral ID 4 */
70 volatile uint32_t reserved_2[3];
71 /*!< Offset: 0xFD4-0xFDC Reserved */
72 volatile uint32_t pidr0;
73 /*!< Offset: 0xFE0 (R/ ) Peripheral ID 0 */
74 volatile uint32_t pidr1;
75 /*!< Offset: 0xFE4 (R/ ) Peripheral ID 1 */
76 volatile uint32_t pidr2;
77 /*!< Offset: 0xFE8 (R/ ) Peripheral ID 2 */
78 volatile uint32_t pidr3;
79 /*!< Offset: 0xFEC (R/ ) Peripheral ID 3 */
80 volatile uint32_t cidr0;
81 /*!< Offset: 0xFF0 (R/ ) Component ID 0 */
82 volatile uint32_t cidr1;
83 /*!< Offset: 0xFF4 (R/ ) Component ID 1 */
84 volatile uint32_t cidr2;
85 /*!< Offset: 0xFF8 (R/ ) Component ID 2 */
86 volatile uint32_t cidr3;
87 /*!< Offset: 0xFFC (R/ ) Component ID 3 */
88 union {
89 volatile uint32_t raw_otp[16384];
90 /*!< Offset: 0x1000 (R/W) OTP direct access */
91 struct lcm_otp_layout_t otp;
92 };
93 };
94
is_pointer_word_aligned(void * ptr)95 static inline int is_pointer_word_aligned(void *ptr) {
96 return !((uint32_t)ptr & (sizeof(uint32_t) - 1));
97 }
98
lcm_init(struct lcm_dev_t * dev)99 enum lcm_error_t lcm_init(struct lcm_dev_t *dev)
100 {
101 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
102
103 if (p_lcm->key_err) {
104 return LCM_ERROR_INVALID_KEY;
105 }
106
107 return LCM_ERROR_NONE;
108 }
109
lcm_get_tp_mode(struct lcm_dev_t * dev,enum lcm_tp_mode_t * mode)110 enum lcm_error_t lcm_get_tp_mode(struct lcm_dev_t *dev, enum lcm_tp_mode_t *mode)
111 {
112 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
113
114 *mode = (enum lcm_tp_mode_t)p_lcm->tp_mode;
115
116 return LCM_ERROR_NONE;
117 }
118
lcm_set_tp_mode(struct lcm_dev_t * dev,enum lcm_tp_mode_t mode)119 enum lcm_error_t lcm_set_tp_mode(struct lcm_dev_t *dev, enum lcm_tp_mode_t mode)
120 {
121 enum lcm_tp_mode_t curr_mode;
122 enum lcm_lcs_t lcs;
123 uint32_t mode_reg_value;
124 uint32_t readback_reg_value;
125 enum lcm_bool_t fatal_err;
126 enum lcm_error_t err;
127
128 err = lcm_get_lcs(dev, &lcs);
129 if (err != LCM_ERROR_NONE) {
130 return err;
131 }
132
133 if (lcs != LCM_LCS_CM) {
134 return LCM_ERROR_INVALID_LCS;
135 }
136
137 err = lcm_get_tp_mode(dev, &curr_mode);
138 if (err != LCM_ERROR_NONE) {
139 return err;
140 }
141
142 if(curr_mode != LCM_TP_MODE_VIRGIN) {
143 return LCM_ERROR_INVALID_TRANSITION;
144 }
145
146 switch(mode) {
147 case LCM_TP_MODE_TCI:
148 /* High hamming-weight magic constant used to enable TCI mode */
149 mode_reg_value = 0x0000FFFFu;
150 break;
151 case LCM_TP_MODE_PCI:
152 /* High hamming-weight magic constant used to enable PCI mode */
153 mode_reg_value = 0xFFFF0000u;
154 break;
155 default:
156 return LCM_ERROR_INVALID_TRANSITION;
157 }
158
159 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, tp_mode_config),
160 sizeof(uint32_t), (uint8_t *)&mode_reg_value);
161 if (err != LCM_ERROR_NONE) {
162 return err;
163 }
164
165 err = lcm_otp_read(dev, offsetof(struct lcm_otp_layout_t, tp_mode_config),
166 sizeof(uint32_t), (uint8_t *)&readback_reg_value);
167 if (err != LCM_ERROR_NONE) {
168 return err;
169 }
170
171 if (readback_reg_value != mode_reg_value) {
172 return LCM_ERROR_INTERNAL_ERROR;
173 }
174
175 err = lcm_get_fatal_error(dev, &fatal_err);
176 if (err != LCM_ERROR_NONE) {
177 return err;
178 }
179
180 if (fatal_err == LCM_TRUE) {
181 return LCM_ERROR_FATAL_ERR;
182 }
183
184 return LCM_ERROR_NONE;
185 }
186
lcm_get_sp_enabled(struct lcm_dev_t * dev,enum lcm_bool_t * enabled)187 enum lcm_error_t lcm_get_sp_enabled(struct lcm_dev_t *dev, enum lcm_bool_t *enabled)
188 {
189 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
190
191 *enabled = (enum lcm_bool_t)p_lcm->sp_enable;
192
193 return LCM_ERROR_NONE;
194 }
195
lcm_set_sp_enabled(struct lcm_dev_t * dev)196 enum lcm_error_t lcm_set_sp_enabled(struct lcm_dev_t *dev)
197 {
198 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
199 enum lcm_bool_t fatal_err;
200 enum lcm_error_t err;
201
202 /* High hamming-weight magic constant used to trigger secure provisioning
203 * mode
204 */
205 p_lcm->sp_enable = 0x5EC10E1Eu;
206
207 while(p_lcm->sp_enable != LCM_TRUE) {}
208
209 err = lcm_get_fatal_error(dev, &fatal_err);
210 if (err != LCM_ERROR_NONE) {
211 return err;
212 }
213
214 if (fatal_err == LCM_TRUE) {
215 return LCM_ERROR_FATAL_ERR;
216 }
217
218 return LCM_ERROR_NONE;
219 }
220
lcm_get_fatal_error(struct lcm_dev_t * dev,enum lcm_bool_t * error)221 enum lcm_error_t lcm_get_fatal_error(struct lcm_dev_t *dev, enum lcm_bool_t *error)
222 {
223 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
224
225 *error = (enum lcm_bool_t)p_lcm->fatal_err;
226
227 return LCM_ERROR_NONE;
228 }
229
lcm_set_fatal_error(struct lcm_dev_t * dev)230 enum lcm_error_t lcm_set_fatal_error(struct lcm_dev_t *dev)
231 {
232 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
233
234 /* High hamming-weight magic constant used to trigger fatal error state */
235 p_lcm->fatal_err = 0xFA7A1EEEu;
236
237 return LCM_ERROR_NONE;
238 }
239
lcm_get_gppc(struct lcm_dev_t * dev,uint32_t * gppc)240 enum lcm_error_t lcm_get_gppc(struct lcm_dev_t *dev, uint32_t *gppc)
241 {
242 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
243
244 *gppc = p_lcm->gppc;
245
246 return LCM_ERROR_NONE;
247 }
248
lcm_get_otp_size(struct lcm_dev_t * dev,uint32_t * size)249 enum lcm_error_t lcm_get_otp_size(struct lcm_dev_t *dev, uint32_t *size)
250 {
251 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
252
253 *size = p_lcm->otp_size_in_bytes;
254
255 return LCM_ERROR_NONE;
256 }
257
lcm_get_lcs(struct lcm_dev_t * dev,enum lcm_lcs_t * lcs)258 enum lcm_error_t lcm_get_lcs(struct lcm_dev_t *dev, enum lcm_lcs_t *lcs)
259 {
260 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
261 enum lcm_bool_t fatal_err;
262 enum lcm_error_t err;
263
264 err = lcm_get_fatal_error(dev, &fatal_err);
265 if (err != LCM_ERROR_NONE) {
266 return err;
267 }
268
269 if (fatal_err == LCM_TRUE) {
270 return LCM_ERROR_FATAL_ERR;
271 }
272
273
274 *lcs = (enum lcm_lcs_t)p_lcm->lcs_value;
275
276 if (*lcs == LCM_LCS_INVALID) {
277 return LCM_ERROR_INVALID_LCS;
278 }
279
280 return LCM_ERROR_NONE;
281 }
282
count_otp_zero_bits(struct lcm_dev_t * dev,uint32_t offset,uint32_t len,uint32_t * zero_bits)283 static enum lcm_error_t count_otp_zero_bits(struct lcm_dev_t *dev, uint32_t offset,
284 uint32_t len, uint32_t *zero_bits)
285 {
286 enum lcm_error_t err;
287 uint32_t idx;
288 uint32_t word;
289 uint32_t bit_index;
290
291 *zero_bits = 0;
292
293 for (idx = 0; idx < len; idx += sizeof(uint32_t)) {
294 err = lcm_otp_read(dev, offset + idx, sizeof(uint32_t), (uint8_t *)&word);
295 if (err != LCM_ERROR_NONE) {
296 return err;
297 }
298
299 for (bit_index = 0; bit_index < sizeof(word) * 8; bit_index++) {
300 *zero_bits += 1 - ((word >> bit_index) & 1);
301 }
302 }
303
304 return LCM_ERROR_NONE;
305 }
306
cm_to_dm(struct lcm_dev_t * dev,uint16_t gppc_val)307 static enum lcm_error_t cm_to_dm(struct lcm_dev_t *dev, uint16_t gppc_val)
308 {
309 enum lcm_error_t err;
310 uint32_t config_val;
311 uint32_t zero_bits;
312
313 config_val = LCM_TRUE;
314
315 err = count_otp_zero_bits(dev, offsetof(struct lcm_otp_layout_t, huk), 32,
316 &zero_bits);
317 if (err != LCM_ERROR_NONE) {
318 return err;
319 }
320 if (zero_bits == 256) {
321 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, huk), 32,
322 dummy_key_value);
323 if (err != LCM_ERROR_NONE) {
324 return err;
325 }
326 }
327
328 err = count_otp_zero_bits(dev, offsetof(struct lcm_otp_layout_t, guk), 32,
329 &zero_bits);
330 if (err != LCM_ERROR_NONE) {
331 return err;
332 }
333 if (zero_bits == 256) {
334 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, guk), 32,
335 dummy_key_value);
336 if (err != LCM_ERROR_NONE) {
337 return err;
338 }
339 }
340
341 err = count_otp_zero_bits(dev, offsetof(struct lcm_otp_layout_t, kp_cm), 32,
342 &zero_bits);
343 if (err != LCM_ERROR_NONE) {
344 return err;
345 }
346 if (zero_bits == 256) {
347 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, kp_cm), 32,
348 dummy_key_value);
349 if (err != LCM_ERROR_NONE) {
350 return err;
351 }
352 }
353
354 err = count_otp_zero_bits(dev, offsetof(struct lcm_otp_layout_t, kce_cm), 32,
355 &zero_bits);
356 if (err != LCM_ERROR_NONE) {
357 return err;
358 }
359 if (zero_bits == 256) {
360 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, kce_cm), 32,
361 dummy_key_value);
362 if (err != LCM_ERROR_NONE) {
363 return err;
364 }
365 }
366
367 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, cm_config_1),
368 sizeof(uint32_t), (uint8_t *)&config_val);
369 /* This OTP field doesn't read-back as written, but that isn't an error */
370 if (!(err == LCM_ERROR_NONE || err == LCM_ERROR_WRITE_VERIFY_FAIL)) {
371 return err;
372 }
373
374 err = lcm_otp_read(dev, offsetof(struct lcm_otp_layout_t, cm_config_1),
375 sizeof(uint32_t), (uint8_t *)&config_val);
376 if (err != LCM_ERROR_NONE) {
377 return err;
378 }
379
380 if (config_val != 0) {
381 return LCM_ERROR_WRITE_VERIFY_FAIL;
382 }
383
384 config_val = 0;
385
386 err = count_otp_zero_bits(dev, offsetof(struct lcm_otp_layout_t, rotpk),
387 32, &zero_bits);
388 if (err != LCM_ERROR_NONE) {
389 return err;
390 }
391
392 config_val |= (zero_bits & 0xFF) << 0;
393 config_val |= ((uint32_t)gppc_val) << 8;
394
395 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, cm_config_2),
396 sizeof(uint32_t), (uint8_t *)&config_val);
397 if (err != LCM_ERROR_NONE) {
398 return err;
399 }
400
401 return LCM_ERROR_NONE;
402 }
403
dm_to_se(struct lcm_dev_t * dev)404 static enum lcm_error_t dm_to_se(struct lcm_dev_t *dev)
405 {
406 enum lcm_error_t err;
407 uint32_t config_val;
408 uint32_t zero_bits;
409
410 err = count_otp_zero_bits(dev, offsetof(struct lcm_otp_layout_t, kp_dm), 32,
411 &zero_bits);
412 if (err != LCM_ERROR_NONE) {
413 return err;
414 }
415 if (zero_bits == 256) {
416 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, kp_dm), 32,
417 dummy_key_value);
418 if (err != LCM_ERROR_NONE) {
419 return err;
420 }
421 }
422
423 err = count_otp_zero_bits(dev, offsetof(struct lcm_otp_layout_t, kce_dm), 32,
424 &zero_bits);
425 if (err != LCM_ERROR_NONE) {
426 return err;
427 }
428 if (zero_bits == 256) {
429 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, kce_dm), 32,
430 dummy_key_value);
431 if (err != LCM_ERROR_NONE) {
432 return err;
433 }
434 }
435
436 config_val = LCM_TRUE;
437
438 /* This OTP field doesn't read-back as written, but that isn't an error */
439 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, dm_config),
440 sizeof(uint32_t), (uint8_t *)&config_val);
441 if (!(err == LCM_ERROR_NONE || err == LCM_ERROR_WRITE_VERIFY_FAIL)) {
442 return err;
443 }
444
445 /* Manually check that the readback value is what we expect (0x0 means no
446 * key bit count errors).
447 */
448 err = lcm_otp_read(dev, offsetof(struct lcm_otp_layout_t, dm_config),
449 sizeof(uint32_t), (uint8_t *)&config_val);
450 if (err != LCM_ERROR_NONE) {
451 return err;
452 }
453
454 if (config_val != 0) {
455 return LCM_ERROR_WRITE_VERIFY_FAIL;
456 }
457
458 return LCM_ERROR_NONE;
459 }
460
se_to_rma(struct lcm_dev_t * dev)461 static enum lcm_error_t se_to_rma(struct lcm_dev_t *dev)
462 {
463 enum lcm_error_t err;
464 uint32_t rma_flag = LCM_TRUE;
465 uint32_t idx;
466 uint32_t otp_overwrite_val = 0xFFFFFFFFu;
467
468 for (idx = 0; idx < offsetof(struct lcm_otp_layout_t, tp_mode_config);
469 idx += sizeof(uint32_t)) {
470 err = lcm_otp_write(dev, idx, sizeof(otp_overwrite_val),
471 (uint8_t *)&otp_overwrite_val);
472 if (err != LCM_ERROR_NONE) {
473 return err;
474 }
475 }
476
477 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, cm_rma_flag),
478 sizeof(uint32_t), (uint8_t *)&rma_flag);
479 if (err != LCM_ERROR_NONE) {
480 return err;
481 }
482
483 err = lcm_otp_write(dev, offsetof(struct lcm_otp_layout_t, dm_rma_flag),
484 sizeof(uint32_t), (uint8_t *)&rma_flag);
485 if (err != LCM_ERROR_NONE) {
486 return err;
487 }
488
489 return LCM_ERROR_NONE;
490 }
491
lcm_set_lcs(struct lcm_dev_t * dev,enum lcm_lcs_t lcs,uint16_t gppc_val)492 enum lcm_error_t lcm_set_lcs(struct lcm_dev_t *dev, enum lcm_lcs_t lcs,
493 uint16_t gppc_val)
494 {
495 enum lcm_bool_t fatal_err;
496 enum lcm_bool_t sp_enable;
497 enum lcm_tp_mode_t tp_mode;
498 enum lcm_error_t err;
499 enum lcm_lcs_t curr_lcs;
500
501 err = lcm_get_lcs(dev, &curr_lcs);
502 if (err != LCM_ERROR_NONE) {
503 return err;
504 }
505 if (lcs == curr_lcs) {
506 return LCM_ERROR_NONE;
507 }
508
509 err = lcm_get_tp_mode(dev, &tp_mode);
510 if (err != LCM_ERROR_NONE) {
511 return err;
512 }
513 if (!(tp_mode == LCM_TP_MODE_PCI || tp_mode == LCM_TP_MODE_TCI)) {
514 return LCM_ERROR_INVALID_TP_MODE;
515 }
516
517 err = lcm_get_sp_enabled(dev, &sp_enable);
518 if (err != LCM_ERROR_NONE) {
519 return err;
520 }
521 if (sp_enable != LCM_TRUE) {
522 err = lcm_set_sp_enabled(dev);
523 if (err != LCM_ERROR_NONE) {
524 return err;
525 }
526 }
527
528 do {
529 err = lcm_get_sp_enabled(dev, &sp_enable);
530 if (err != LCM_ERROR_NONE) {
531 return err;
532 }
533 err = lcm_get_fatal_error(dev, &fatal_err);
534 if (err != LCM_ERROR_NONE) {
535 return err;
536 }
537 } while (sp_enable == LCM_FALSE && fatal_err == LCM_FALSE);
538
539 if (fatal_err == LCM_TRUE) {
540 return LCM_ERROR_FATAL_ERR;
541 }
542
543 switch (lcs) {
544 case LCM_LCS_CM:
545 /* There's no possible valid transition back to CM */
546 return LCM_ERROR_INVALID_TRANSITION;
547 case LCM_LCS_DM:
548 if (curr_lcs != LCM_LCS_CM) {
549 return LCM_ERROR_INVALID_TRANSITION;
550 }
551
552 return cm_to_dm(dev, gppc_val);
553
554 case LCM_LCS_SE:
555 if (curr_lcs != LCM_LCS_DM) {
556 return LCM_ERROR_INVALID_TRANSITION;
557 }
558
559 return dm_to_se(dev);
560
561 case LCM_LCS_RMA:
562 if (curr_lcs != LCM_LCS_SE) {
563 return LCM_ERROR_INVALID_TRANSITION;
564 }
565
566 return se_to_rma(dev);
567
568 case LCM_LCS_INVALID:
569 return LCM_ERROR_INVALID_LCS;
570 }
571
572 /* Should never get here */
573 return LCM_ERROR_INTERNAL_ERROR;
574 }
575
lcm_otp_write(struct lcm_dev_t * dev,uint32_t offset,uint32_t len,const uint8_t * buf)576 enum lcm_error_t lcm_otp_write(struct lcm_dev_t *dev, uint32_t offset, uint32_t len,
577 const uint8_t *buf)
578 {
579 enum lcm_error_t err;
580 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
581 uint32_t *p_buf_word = (uint32_t *)buf;
582 uint32_t otp_size;
583 uint32_t idx;
584
585 if (!is_pointer_word_aligned(p_buf_word)) {
586 return LCM_ERROR_INVALID_ALIGNMENT;
587 }
588
589 if (offset & (sizeof(uint32_t) - 1)) {
590 return LCM_ERROR_INVALID_OFFSET;
591 }
592
593 if (len & (sizeof(uint32_t) - 1)) {
594 return LCM_ERROR_INVALID_LENGTH;
595 }
596
597 err = lcm_get_otp_size(dev, &otp_size);
598 if (err) {
599 return err;
600 }
601
602 if (otp_size <= (offset + len)) {
603 return LCM_ERROR_INVALID_OFFSET;
604 }
605
606 /* Reject the write if the word is already written and we're not trying to
607 * write the same word
608 */
609 for (idx = 0; idx < len / sizeof(uint32_t); idx++) {
610 if (p_lcm->raw_otp[(offset / sizeof(uint32_t)) + idx] &&
611 p_lcm->raw_otp[(offset / sizeof(uint32_t)) + idx] ^ p_buf_word[idx]) {
612 return LCM_ERROR_INVALID_WRITE;
613 }
614 }
615
616 for (idx = 0; idx < len / sizeof(uint32_t); idx++) {
617 p_lcm->raw_otp[(offset / sizeof(uint32_t)) + idx] = p_buf_word[idx];
618 }
619
620 for (idx = 0; idx < len / sizeof(uint32_t); idx++) {
621 if (p_buf_word[idx] != p_lcm->raw_otp[(offset / sizeof(uint32_t)) + idx]) {
622 return LCM_ERROR_WRITE_VERIFY_FAIL;
623 }
624 }
625
626 return LCM_ERROR_NONE;
627 }
628
lcm_otp_read(struct lcm_dev_t * dev,uint32_t offset,uint32_t len,uint8_t * buf)629 enum lcm_error_t lcm_otp_read(struct lcm_dev_t *dev, uint32_t offset, uint32_t len,
630 uint8_t *buf)
631 {
632 enum lcm_error_t err;
633 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
634 uint32_t *p_buf_word = (uint32_t *)buf;
635 uint32_t otp_size;
636 uint32_t idx;
637
638 if (!is_pointer_word_aligned(p_buf_word)) {
639 return LCM_ERROR_INVALID_ALIGNMENT;
640 }
641
642 if (offset & (sizeof(uint32_t) - 1)) {
643 return LCM_ERROR_INVALID_OFFSET;
644 }
645
646 if (len & (sizeof(uint32_t) - 1)) {
647 return LCM_ERROR_INVALID_LENGTH;
648 }
649
650 err = lcm_get_otp_size(dev, &otp_size);
651 if (err) {
652 return err;
653 }
654
655 if (otp_size <= (offset + len)) {
656 return LCM_ERROR_INVALID_OFFSET;
657 }
658
659 for (idx = 0; idx < len / sizeof(uint32_t); idx++) {
660 p_buf_word[idx] = p_lcm->raw_otp[(offset / sizeof(uint32_t)) + idx];
661 }
662
663 return LCM_ERROR_NONE;
664 }
665
lcm_dcu_get_enabled(struct lcm_dev_t * dev,uint8_t * val)666 enum lcm_error_t lcm_dcu_get_enabled(struct lcm_dev_t *dev, uint8_t *val)
667 {
668 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
669 uint32_t *p_val_word = (uint32_t *)val;
670 uint32_t idx;
671
672 if (!is_pointer_word_aligned(p_val_word)) {
673 return LCM_ERROR_INVALID_ALIGNMENT;
674 }
675
676 for (idx = 0; idx < LCM_DCU_WIDTH_IN_BYTES / sizeof(uint32_t); idx++) {
677 p_val_word[idx] = p_lcm->dcu_en[idx];
678 }
679
680 return LCM_ERROR_NONE;
681 }
682
lcm_dcu_set_enabled(struct lcm_dev_t * dev,uint8_t * val)683 enum lcm_error_t lcm_dcu_set_enabled(struct lcm_dev_t *dev, uint8_t *val)
684 {
685 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
686 uint32_t *p_val_word = (uint32_t *)val;
687 uint32_t idx;
688
689 if (!is_pointer_word_aligned(p_val_word)) {
690 return LCM_ERROR_INVALID_ALIGNMENT;
691 }
692
693 for (idx = 0; idx < LCM_DCU_WIDTH_IN_BYTES / sizeof(uint32_t); idx++) {
694 p_lcm->dcu_en[idx] = p_val_word[idx];
695 }
696
697 for (idx = 0; idx < LCM_DCU_WIDTH_IN_BYTES / sizeof(uint32_t); idx++) {
698 if (p_lcm->dcu_en[idx] != p_val_word[idx]) {
699 return LCM_ERROR_WRITE_VERIFY_FAIL;
700 }
701 }
702
703 return LCM_ERROR_NONE;
704 }
705
lcm_dcu_get_locked(struct lcm_dev_t * dev,uint8_t * val)706 enum lcm_error_t lcm_dcu_get_locked(struct lcm_dev_t *dev, uint8_t *val)
707 {
708 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
709 uint32_t *p_val_word = (uint32_t *)val;
710 uint32_t idx;
711
712 if (!is_pointer_word_aligned(p_val_word)) {
713 return LCM_ERROR_INVALID_ALIGNMENT;
714 }
715
716 for (idx = 0; idx < LCM_DCU_WIDTH_IN_BYTES / sizeof(uint32_t); idx++) {
717 p_val_word[idx] = p_lcm->dcu_lock[idx];
718 }
719
720 return LCM_ERROR_NONE;
721 }
722
lcm_dcu_set_locked(struct lcm_dev_t * dev,uint8_t * val)723 enum lcm_error_t lcm_dcu_set_locked(struct lcm_dev_t *dev, uint8_t *val)
724 {
725 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
726 uint32_t *p_val_word = (uint32_t *)val;
727 uint32_t idx;
728
729 if (!is_pointer_word_aligned(p_val_word)) {
730 return LCM_ERROR_INVALID_ALIGNMENT;
731 }
732
733 for (idx = 0; idx < LCM_DCU_WIDTH_IN_BYTES / sizeof(uint32_t); idx++) {
734 p_lcm->dcu_lock[idx] = p_val_word[idx];
735 }
736
737 return LCM_ERROR_NONE;
738 }
739
lcm_dcu_get_sp_disable_mask(struct lcm_dev_t * dev,uint8_t * val)740 enum lcm_error_t lcm_dcu_get_sp_disable_mask(struct lcm_dev_t *dev, uint8_t *val)
741 {
742 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
743 uint32_t *p_val_word = (uint32_t *)val;
744 uint32_t idx;
745
746 if (!is_pointer_word_aligned(p_val_word)) {
747 return LCM_ERROR_INVALID_ALIGNMENT;
748 }
749
750 for (idx = 0; idx < LCM_DCU_WIDTH_IN_BYTES / sizeof(uint32_t); idx++) {
751 p_val_word[idx] = p_lcm->dcu_sp_disable_mask[idx];
752 }
753
754 return LCM_ERROR_NONE;
755 }
756
lcm_dcu_get_disable_mask(struct lcm_dev_t * dev,uint8_t * val)757 enum lcm_error_t lcm_dcu_get_disable_mask(struct lcm_dev_t *dev, uint8_t *val)
758 {
759 struct _lcm_reg_map_t *p_lcm = (struct _lcm_reg_map_t *)dev->cfg->base;
760 uint32_t *p_val_word = (uint32_t *)val;
761 uint32_t idx;
762
763 if (!is_pointer_word_aligned(p_val_word)) {
764 return LCM_ERROR_INVALID_ALIGNMENT;
765 }
766
767 for (idx = 0; idx < LCM_DCU_WIDTH_IN_BYTES / sizeof(uint32_t); idx++) {
768 p_val_word[idx] = p_lcm->dcu_disable_mask[idx];
769 }
770
771 return LCM_ERROR_NONE;
772 }
773
774