1 /*
2  * Copyright (c) 2021-2023, The TrustedFirmware-M Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "cc3xx_otp.h"
9 
10 #include "cc3xx_dev.h"
11 
12 #include <stdint.h>
13 #include <stddef.h>
14 #include <string.h>
15 
wait_until_fuse_programming_complete(void)16 static void wait_until_fuse_programming_complete(void) {
17 
18     while (! (P_CC3XX->nvm.aib_fuse_prog_completed & 1)) {}
19 }
20 
cc3xx_lowlevel_otp_write(uint8_t * otp_addr,size_t size,const uint8_t * buf)21 cc3xx_err_t cc3xx_lowlevel_otp_write(uint8_t *otp_addr,
22                                      size_t size, const uint8_t *buf)
23 {
24     uint32_t *word_ptr;
25     uint32_t current_word;
26     uint32_t word;
27     uint32_t start_offset;
28     uint8_t in_done = 0;
29     size_t copy_size;
30 
31     /* First iterate through and check all values are valid (will not require a
32      * 1 bit to be unset).
33      */
34     for(in_done = 0; in_done < size;) {
35         start_offset = ((uint32_t)otp_addr + in_done) & 0x3;
36         word_ptr = (uint32_t *)(otp_addr + in_done - start_offset);
37 
38         current_word = *word_ptr;
39         word = 0;
40 
41         copy_size = sizeof(word) - start_offset;
42         if (in_done + copy_size > size) {
43             copy_size = size - in_done;
44         }
45 
46         memcpy(((uint8_t *)&word) + start_offset, buf + in_done, copy_size);
47         word |= current_word;
48 
49         if (memcmp(((uint8_t *)&word) + start_offset, buf + in_done, copy_size)) {
50             return CC3XX_ERR_INVALID_DATA;
51         }
52 
53         in_done += copy_size;
54     }
55 
56     /* Then write the OTP */
57     for(in_done = 0; in_done < size;) {
58         start_offset = ((uint32_t)otp_addr + in_done) & 0x3;
59         word_ptr = (uint32_t *)(otp_addr + in_done - start_offset);
60 
61         word = *word_ptr;
62 
63         copy_size = sizeof(word) - start_offset;
64         if (in_done + copy_size > size) {
65             copy_size = size - in_done;
66         }
67 
68         memcpy(((uint8_t *)&word) + start_offset, buf + in_done, copy_size);
69 
70         *word_ptr = word;
71         wait_until_fuse_programming_complete();
72 
73         in_done += copy_size;
74     }
75 
76     return CC3XX_ERR_SUCCESS;
77 }
78 
cc3xx_lowlevel_otp_read(const uint8_t * otp_addr,size_t size,uint8_t * buf)79 cc3xx_err_t cc3xx_lowlevel_otp_read(const uint8_t *otp_addr,
80                                     size_t size, uint8_t *buf)
81 {
82     uint32_t *word_ptr;
83     uint32_t word;
84     uint32_t start_offset;
85     uint8_t out_done;
86     size_t copy_size;
87 
88     for(out_done = 0; out_done < size;) {
89         start_offset = ((uint32_t)otp_addr + out_done) & 0x3;
90         word_ptr = (uint32_t *)(otp_addr + out_done - start_offset);
91 
92         word = *word_ptr;
93 
94         copy_size = sizeof(word) - start_offset;
95         if (out_done + copy_size > size) {
96             copy_size = size - out_done;
97         }
98 
99         memcpy(buf + out_done, ((uint8_t *)&word) + start_offset, copy_size);
100         out_done += copy_size;
101     }
102 
103     return CC3XX_ERR_SUCCESS;
104 }
105