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