1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "efuse.h"
17
efuse_start_addr_unaligned_read(hi_u16 start_bit,hi_u16 size,hi_u8 diff_head_read,hi_u8 * data)18 hi_u32 efuse_start_addr_unaligned_read(hi_u16 start_bit, hi_u16 size, hi_u8 diff_head_read, hi_u8 *data)
19 {
20 if (size == SIZE_8_BITS) {
21 if (efuse_read_bits(start_bit, size, data) != HI_ERR_SUCCESS) {
22 return HI_ERR_FAILURE;
23 }
24
25 data[0] = data[0] >> diff_head_read;
26 } else if (size == SIZE_16_BITS) {
27 hi_u16 tmp_data = 0;
28 if (efuse_read_bits(start_bit, size, (hi_u8 *)&tmp_data) != HI_ERR_SUCCESS) {
29 return HI_ERR_FAILURE;
30 }
31
32 tmp_data = tmp_data >> diff_head_read;
33 if (start_bit == 0xE0) {
34 *data = (hi_u8)(tmp_data & 0xFF);
35 } else {
36 *(hi_u16 *)data = tmp_data;
37 }
38 } else if (size == SIZE_24_BITS) {
39 hi_u32 tmp_data = 0;
40 if (efuse_read_bits(start_bit, SIZE_24_BITS, (hi_u8 *)&tmp_data) != HI_ERR_SUCCESS) {
41 return HI_ERR_FAILURE;
42 }
43
44 tmp_data = tmp_data >> diff_head_read;
45 hi_u32 check_sum = (uintptr_t)data ^ DATA_LENGTH ^ (uintptr_t)(hi_u8 *)&tmp_data ^ DATA_LENGTH;
46 if (memcpy_s(data, DATA_LENGTH, (hi_u8 *)&tmp_data, DATA_LENGTH, check_sum) != EOK) {
47 return HI_ERR_FAILURE;
48 }
49 } else if (size == SIZE_72_BITS) {
50 hi_u8 tmp_data[SIZE_72_BITS / SIZE_8_BITS] = { 0 };
51 hi_u32 data_u32[2]; /* U64 is divided into 2 U32 */
52 hi_u8 end_u8;
53 if (efuse_read_bits(start_bit, SIZE_72_BITS, &tmp_data[0]) != HI_ERR_SUCCESS) {
54 return HI_ERR_FAILURE;
55 }
56
57 data_u32[0] = *(hi_u32 *)&tmp_data[0]; /* first U32 offset is 0 */
58 data_u32[1] = *(hi_u32 *)&tmp_data[4]; /* sencond U32 offset is 4 */
59 end_u8 = *(hi_u8 *)&tmp_data[8]; /* the last u8 bit */
60 data_u32[0] = data_u32[0] >> diff_head_read;
61 data_u32[0] = data_u32[0] | (data_u32[1] << (SIZE_32_BITS - diff_head_read));
62 data_u32[1] = data_u32[1] >> diff_head_read;
63 data_u32[1] = data_u32[1] | ((hi_u32)end_u8 << (SIZE_32_BITS - diff_head_read));
64 *(hi_u64 *)data = (((hi_u64)data_u32[1] << SIZE_32_BITS) | data_u32[0]);
65 } else {
66 return HI_ERR_FAILURE;
67 }
68
69 return HI_ERR_SUCCESS;
70 }
71
efuse_bits_read(hi_u16 start_bit,hi_u16 size,hi_u8 * data,hi_u32 data_len)72 hi_u32 efuse_bits_read(hi_u16 start_bit, hi_u16 size, hi_u8 *data, hi_u32 data_len)
73 {
74 hi_u8 diff_head_read = 0;
75 hi_u32 origine_size;
76 hi_u32 ret;
77 if (data_len > EFUSE_MAX_INDEX_SIZE) {
78 return HI_ERR_FAILURE;
79 }
80
81 origine_size = size;
82 if ((start_bit & 0x7) != 0x0) {
83 diff_head_read = start_bit % SIZE_8_BITS;
84 start_bit = start_bit - diff_head_read; /* Reads the 8-bit aligned start address. */
85 size = size + diff_head_read;
86 }
87
88 if ((size & 0x7) != 0x0) {
89 size = ((size >> THREE_BITS_OFFSET) + 1) << THREE_BITS_OFFSET; /* Reads data in 8-bit unit. */
90 }
91
92 if (diff_head_read == 0) {
93 /* Reads the 8-bit aligned start address. */
94 ret = efuse_read_bits(start_bit, size, data);
95 if (ret != HI_ERR_SUCCESS) {
96 return ret;
97 }
98 } else {
99 /* The start address is not 8-bit-aligned. */
100 ret = efuse_start_addr_unaligned_read(start_bit, size, diff_head_read, data);
101 if (ret != HI_ERR_SUCCESS) {
102 return ret;
103 }
104 }
105
106 if (origine_size <= SIZE_8_BITS) {
107 *data &= ((1 << origine_size) - 1);
108 } else if (origine_size <= SIZE_16_BITS) {
109 *(hi_u16 *)data &= ((1 << origine_size) - 1);
110 } else if (origine_size < SIZE_32_BITS) {
111 *(hi_u32 *)data &= (((hi_u32)1 << origine_size) - 1);
112 }
113
114 return HI_ERR_SUCCESS;
115 }
116
hi_efuse_read(hi_efuse_idx efuse_id,hi_u8 * data,hi_u8 data_len)117 hi_u32 hi_efuse_read(hi_efuse_idx efuse_id, hi_u8 *data, hi_u8 data_len)
118 {
119 hi_u16 start_bit = 0;
120 hi_u16 size = 0;
121 hi_u16 align_size;
122 hi_u8 flag = EFUSE_IDX_NRW;
123
124 if (efuse_id >= HI_EFUSE_IDX_MAX || data == HI_NULL) {
125 return HI_ERR_EFUSE_INVALIDATE_PARA;
126 }
127
128 get_efuse_cfg_by_id(efuse_id, &start_bit, &size, &flag);
129
130 if (flag == EFUSE_IDX_WO) {
131 return HI_ERR_EFUSE_INVALIDATE_AUTH;
132 }
133
134 align_size = ((size & 0x7) != 0x0) ? (((size >> THREE_BITS_OFFSET) + 1) << THREE_BITS_OFFSET) : size;
135
136 if (align_size > ((hi_u16)data_len * EIGHT_BITS)) {
137 return HI_ERR_EFUSE_INVALIDATE_PARA;
138 }
139
140 return efuse_bits_read(start_bit, size, data, data_len);
141 }
142
hi_efuse_write(hi_efuse_idx efuse_id,const hi_u8 * data)143 hi_u32 hi_efuse_write(hi_efuse_idx efuse_id, const hi_u8 *data)
144 {
145 hi_u16 start_bit = 0;
146 hi_u16 size = 0;
147 hi_u8 flag = EFUSE_IDX_NRW;
148 hi_char err_state[EFUSE_MAX_INDEX_SIZE] = {
149 0,
150 };
151 hi_u32 i;
152 hi_u32 ret;
153
154 if (efuse_id >= HI_EFUSE_IDX_MAX || data == HI_NULL) {
155 boot_msg1("parameter err !", efuse_id);
156 return HI_ERR_EFUSE_INVALIDATE_PARA;
157 }
158
159 get_efuse_cfg_by_id(efuse_id, &start_bit, &size, &flag);
160 if (flag == EFUSE_IDX_RO) {
161 boot_msg1("This section can not be write !flag = ", flag);
162 return HI_ERR_EFUSE_INVALIDATE_AUTH;
163 }
164
165 ret = efuse_write_bits(start_bit, size, data, (hi_u8 *)&err_state[0]);
166 if (ret != HI_ERR_SUCCESS) {
167 boot_msg0("efuse write err");
168 return ret;
169 }
170
171 for (i = 0; i < EFUSE_MAX_INDEX_SIZE; i++) {
172 if (err_state[i]) {
173 boot_msg1("errstate num is", i);
174 return HI_ERR_EFUSE_WRITE_ERR;
175 }
176 }
177
178 return HI_ERR_SUCCESS;
179 }
180
efuse_bits_write(hi_u16 start_bit,hi_u16 size,const hi_u8 * key_data)181 hi_u32 efuse_bits_write(hi_u16 start_bit, hi_u16 size, const hi_u8 *key_data)
182 {
183 hi_u8 usr_err_stat[EFUSE_MAX_INDEX_SIZE];
184 hi_u32 i;
185 hi_u32 ret;
186
187 if (size > (EFUSE_MAX_INDEX_SIZE * SIZE_8_BITS) || key_data == HI_NULL || size == 0) {
188 return HI_ERR_FAILURE;
189 }
190 hi_u32 check_sum = (uintptr_t)usr_err_stat ^ EFUSE_MAX_INDEX_SIZE ^ 0 ^ EFUSE_MAX_INDEX_SIZE;
191 memset_s(usr_err_stat, EFUSE_MAX_INDEX_SIZE, 0, EFUSE_MAX_INDEX_SIZE, check_sum);
192
193 ret = efuse_write_bits(start_bit, size, key_data, (hi_u8 *)&usr_err_stat[0]);
194 if (ret != HI_ERR_SUCCESS) {
195 return ret;
196 }
197
198 for (i = 0; i < EFUSE_MAX_INDEX_SIZE; i++) {
199 if (usr_err_stat[i]) {
200 return HI_ERR_FAILURE;
201 }
202 }
203
204 return HI_ERR_SUCCESS;
205 }
206
hi_efuse_get_lockstat(hi_u64 * lock_stat)207 hi_u32 hi_efuse_get_lockstat(hi_u64 *lock_stat)
208 {
209 hi_u16 start_bit = EFUSE_LOCK_START_BITS;
210 hi_u16 size = EFUSE_LOCK_SIZE;
211 hi_u8 diff_head_read;
212 hi_u64 tmp_data = 0;
213 hi_u64 tmp_data_filed_two = 0;
214 hi_u32 ret;
215
216 if (lock_stat == HI_NULL) {
217 return HI_ERR_FAILURE;
218 }
219
220 /* start address and size 8 bits align. */
221 diff_head_read = start_bit % EIGHT_BITS;
222 start_bit = start_bit - diff_head_read;
223 size = size + diff_head_read;
224
225 ret = efuse_read_bits(start_bit, size, (hi_u8 *)&tmp_data);
226 if (ret == HI_ERR_SUCCESS) {
227 tmp_data = tmp_data >> diff_head_read;
228 } else {
229 return HI_ERR_FAILURE;
230 }
231
232 start_bit = EFUSE_LOCK_FIELD2_START_BITS;
233 size = EFUSE_LOCK_FIELD2_SIZE;
234
235 /* start address and size 8 bits align. */
236 diff_head_read = start_bit % EIGHT_BITS;
237 start_bit = start_bit - diff_head_read;
238 size = size + diff_head_read;
239
240 ret = efuse_read_bits(start_bit, size, (hi_u8 *)&tmp_data_filed_two);
241 if (ret == HI_ERR_SUCCESS) {
242 tmp_data_filed_two = tmp_data_filed_two >> diff_head_read;
243 } else {
244 return HI_ERR_FAILURE;
245 }
246
247 *lock_stat = (((tmp_data_filed_two << EFUSE_LOCK_SIZE) & 0x1F000000000) | (tmp_data & 0xFFFFFFFFF));
248
249 return HI_ERR_SUCCESS;
250 }
251