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