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