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 #include "efuse_drv.h"
18
efuse_start_addr_unaligned_read(hi_u16 start_bit,hi_u16 size,hi_u8 diff_head_read,hi_u8 * data)19 hi_u32 efuse_start_addr_unaligned_read(hi_u16 start_bit, hi_u16 size, hi_u8 diff_head_read, hi_u8 *data)
20 {
21 hi_u32 ret = HI_ERR_FAILURE;
22 hi_u32 check_sum;
23
24 if (size == SIZE_8_BITS) {
25 ret = efuse_read_bits(start_bit, size, data);
26 if (ret == HI_ERR_SUCCESS) {
27 data[0] = data[0] >> diff_head_read;
28 }
29 } else if (size == SIZE_16_BITS) {
30 hi_u16 tmp_data = 0;
31 ret = efuse_read_bits(start_bit, size, (hi_u8 *)&tmp_data);
32 if (ret == HI_ERR_SUCCESS) {
33 tmp_data = tmp_data >> diff_head_read;
34 if (start_bit == 0xE0) {
35 *data = (hi_u8)(tmp_data & 0xFF);
36 } else {
37 *(hi_u16 *)data = tmp_data;
38 }
39 }
40 } else if (size == SIZE_24_BITS) {
41 hi_u32 tmp_data = 0;
42 ret = efuse_read_bits(start_bit, SIZE_24_BITS, (hi_u8 *)&tmp_data);
43 if (ret == HI_ERR_SUCCESS) {
44 tmp_data = tmp_data >> diff_head_read;
45 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 }
50 } else if (size == SIZE_72_BITS) {
51 hi_u8 tmp_data[SIZE_72_BITS / SIZE_8_BITS] = { 0 };
52 hi_u32 data_u32[2]; /* U64 is divided into 2 U32 */
53 hi_u8 end_u8;
54 ret = efuse_read_bits(start_bit, SIZE_72_BITS, &tmp_data[0]);
55 if (ret == HI_ERR_SUCCESS) {
56 data_u32[0] = *(hi_u32 *)&tmp_data[0]; /* first U32 offset is 0 */
57 data_u32[1] = *(hi_u32 *)&tmp_data[4]; /* sencond U32 offset is 4 */
58 end_u8 = *(hi_u8 *)&tmp_data[8]; /* the last u8 bit */
59 data_u32[0] = data_u32[0] >> diff_head_read;
60 data_u32[0] = data_u32[0] | (data_u32[1] << (SIZE_32_BITS - diff_head_read));
61 data_u32[1] = data_u32[1] >> diff_head_read;
62 data_u32[1] = data_u32[1] | ((hi_u32)end_u8 << (SIZE_32_BITS - diff_head_read));
63 *(hi_u64 *)data = (((hi_u64)data_u32[1] << SIZE_32_BITS) | data_u32[0]);
64 }
65 }
66 return ret;
67 }
68
efuse_bits_read(hi_u16 start_bit,hi_u16 size,hi_u8 * data,hi_u32 data_len)69 hi_u32 efuse_bits_read(hi_u16 start_bit, hi_u16 size, hi_u8 *data, hi_u32 data_len)
70 {
71 hi_u8 diff_head_read = 0;
72 hi_u32 origine_size;
73 hi_u32 ret;
74 if (data_len > EFUSE_MAX_INDEX_SIZE) {
75 return HI_ERR_FAILURE;
76 }
77
78 origine_size = size;
79 if ((start_bit & 0x7) != 0x0) {
80 diff_head_read = start_bit % SIZE_8_BITS;
81 /* The start address of the chip must be 8-bit aligned. */
82 start_bit = start_bit - diff_head_read;
83 size = size + diff_head_read;
84 }
85
86 if ((size & 0x7) != 0x0) {
87 size = ((size >> THREE_BITS_OFFSET) + 1) << THREE_BITS_OFFSET;
88 }
89
90 if (diff_head_read == 0) {
91 /* The start address is 8-bit aligned. */
92 ret = efuse_read_bits(start_bit, size, data);
93 if (ret != HI_ERR_SUCCESS) {
94 return ret;
95 }
96 } else {
97 /* The start address is 8-bit aligned. */
98 ret = efuse_start_addr_unaligned_read(start_bit, size, diff_head_read, data);
99 if (ret != HI_ERR_SUCCESS) {
100 return ret;
101 }
102 }
103
104 if (origine_size <= SIZE_8_BITS) {
105 *data &= ((1 << origine_size) - 1);
106 } else if (origine_size <= SIZE_16_BITS) {
107 *(hi_u16 *)data &= ((1 << origine_size) - 1);
108 } else if (origine_size < SIZE_32_BITS) {
109 *(hi_u32 *)data &= (((hi_u32)1 << origine_size) - 1);
110 }
111
112 return HI_ERR_SUCCESS;
113 }
114
hi_efuse_read(hi_efuse_idx efuse_id,hi_u8 * data,hi_u8 data_len)115 hi_u32 hi_efuse_read(hi_efuse_idx efuse_id, hi_u8 *data, hi_u8 data_len)
116 {
117 hi_u16 start_bit = 0;
118 hi_u16 size = 0;
119 hi_u16 align_size;
120 hi_u8 flag = EFUSE_IDX_NRW;
121
122 if (efuse_id >= HI_EFUSE_IDX_MAX || data == HI_NULL) {
123 return HI_ERR_EFUSE_INVALIDATE_PARA;
124 }
125
126 get_efuse_cfg_by_id(efuse_id, &start_bit, &size, &flag);
127
128 if (flag == EFUSE_IDX_WO) {
129 return HI_ERR_EFUSE_INVALIDATE_AUTH;
130 }
131
132 align_size = ((size & 0x7) != 0x0) ? (((size >> THREE_BITS_OFFSET) + 1) << THREE_BITS_OFFSET) : size;
133
134 if (align_size > ((hi_u16)data_len * EIGHT_BITS)) {
135 return HI_ERR_EFUSE_INVALIDATE_PARA;
136 }
137
138 return efuse_bits_read(start_bit, size, data, data_len);
139 }
140
hi_efuse_write(hi_efuse_idx efuse_id,const hi_u8 * data)141 hi_u32 hi_efuse_write(hi_efuse_idx efuse_id, const hi_u8 *data)
142 {
143 hi_u16 start_bit = 0;
144 hi_u16 size = 0;
145 hi_u8 flag = EFUSE_IDX_NRW;
146 hi_char err_state[EFUSE_MAX_INDEX_SIZE] = {
147 0,
148 };
149 hi_u32 i;
150 hi_u32 ret;
151
152 if (efuse_id >= HI_EFUSE_IDX_MAX || data == HI_NULL) {
153 boot_msg1("parameter err !", efuse_id);
154 return HI_ERR_EFUSE_INVALIDATE_PARA;
155 }
156
157 get_efuse_cfg_by_id(efuse_id, &start_bit, &size, &flag);
158 if (flag == EFUSE_IDX_RO) {
159 boot_msg1("This section can not be write !flag = ", flag);
160 return HI_ERR_EFUSE_INVALIDATE_AUTH;
161 }
162
163 ret = efuse_write_bits(start_bit, size, data, (hi_u8 *)&err_state[0]);
164 if (ret != HI_ERR_SUCCESS) {
165 boot_msg0("efuse write err");
166 return ret;
167 }
168
169 for (i = 0; i < EFUSE_MAX_INDEX_SIZE; i++) {
170 if (err_state[i]) {
171 boot_msg1("errstate num is", i);
172 return HI_ERR_EFUSE_WRITE_ERR;
173 }
174 }
175
176 return HI_ERR_SUCCESS;
177 }
178
hi_efuse_lock(hi_efuse_lock_id lock_id)179 hi_u32 hi_efuse_lock(hi_efuse_lock_id lock_id)
180 {
181 hi_u16 err_stat = 0;
182 hi_u32 ret;
183 hi_u16 start_bit;
184 hi_u8 lock_val = 1;
185
186 if (lock_id >= HI_EFUSE_LOCK_MAX) {
187 return HI_ERR_EFUSE_INVALIDATE_ID;
188 }
189
190 if (lock_id < HI_EFUSE_LOCK_FLASH_ENCPY_CNT3_ID) {
191 start_bit = EFUSE_LOCK_START_BITS + lock_id;
192 } else {
193 start_bit = EFUSE_LOCK_FIELD2_START_BITS + lock_id - HI_EFUSE_LOCK_FLASH_ENCPY_CNT3_ID;
194 }
195
196 ret = efuse_write_bits(start_bit, 1, &lock_val, (hi_u8 *)&err_stat);
197 if ((ret == HI_ERR_SUCCESS) && (err_stat == 0)) {
198 return HI_ERR_SUCCESS;
199 } else if (err_stat != 0) {
200 return HI_ERR_EFUSE_WRITE_ERR;
201 }
202
203 return ret;
204 }
205
hi_efuse_get_lockstat(hi_u64 * lock_stat)206 hi_u32 hi_efuse_get_lockstat(hi_u64 *lock_stat)
207 {
208 hi_u16 start_bit = EFUSE_LOCK_START_BITS;
209 hi_u16 size = EFUSE_LOCK_SIZE;
210 hi_u8 diff_head_read;
211 hi_u64 tmp_data = 0;
212 hi_u64 tmp_data_filed_two = 0;
213 hi_u32 ret;
214
215 if (lock_stat == HI_NULL) {
216 return HI_ERR_FAILURE;
217 }
218
219 /* start address and size 8 bits align. */
220 diff_head_read = start_bit % EIGHT_BITS;
221 start_bit = start_bit - diff_head_read;
222 size = size + diff_head_read;
223
224 ret = efuse_read_bits(start_bit, size, (hi_u8 *)&tmp_data);
225 if (ret == HI_ERR_SUCCESS) {
226 tmp_data = tmp_data >> diff_head_read;
227 } else {
228 return HI_ERR_FAILURE;
229 }
230
231 start_bit = EFUSE_LOCK_FIELD2_START_BITS;
232 size = EFUSE_LOCK_FIELD2_SIZE;
233
234 /* start address and size 8 bits align. */
235 diff_head_read = start_bit % EIGHT_BITS;
236 start_bit = start_bit - diff_head_read;
237 size = size + diff_head_read;
238
239 ret = efuse_read_bits(start_bit, size, (hi_u8 *)&tmp_data_filed_two);
240 if (ret == HI_ERR_SUCCESS) {
241 tmp_data_filed_two = tmp_data_filed_two >> diff_head_read;
242 } else {
243 return HI_ERR_FAILURE;
244 }
245
246 *lock_stat = (((tmp_data_filed_two << EFUSE_LOCK_SIZE) & 0x1F000000000) | (tmp_data & 0xFFFFFFFFF));
247
248 return HI_ERR_SUCCESS;
249 }
250
hi_efuse_usr_read(hi_u16 start_bit,hi_u16 size,hi_u8 * key_data)251 hi_u32 hi_efuse_usr_read(hi_u16 start_bit, hi_u16 size, hi_u8 *key_data)
252 {
253 hi_u16 real_size = size;
254
255 if ((start_bit >= EFUSE_PGM_ADDR_SIZE) || ((start_bit & 0x7) != 0) || (key_data == HI_NULL) || (size == 0)) {
256 return HI_ERR_FAILURE;
257 }
258
259 /* The start address of the chip must be 8-bit aligned. */
260 if ((size & 0x7) != 0x0) {
261 real_size = ((size >> 3) + 1) << 3; /* right shift 3bit;add;then left shift 3bit */
262 }
263
264 if ((start_bit + real_size) > EFUSE_PGM_ADDR_SIZE) {
265 return HI_ERR_FAILURE;
266 }
267
268 return efuse_read_bits(start_bit, real_size, key_data);
269 }
270
hi_efuse_usr_write(hi_u16 start_bit,hi_u16 size,const hi_u8 * key_data)271 hi_u32 hi_efuse_usr_write(hi_u16 start_bit, hi_u16 size, const hi_u8 *key_data)
272 {
273 hi_u8 usr_err_stat[EFUSE_MAX_INDEX_SIZE];
274 hi_u32 i;
275 hi_u32 ret;
276
277 if (size > (EFUSE_MAX_INDEX_SIZE * SIZE_8_BITS) || key_data == HI_NULL || size == 0) {
278 return HI_ERR_FAILURE;
279 }
280 hi_u32 check_sum = (uintptr_t)usr_err_stat ^ EFUSE_MAX_INDEX_SIZE ^ 0 ^ EFUSE_MAX_INDEX_SIZE;
281 memset_s(usr_err_stat, EFUSE_MAX_INDEX_SIZE, 0, EFUSE_MAX_INDEX_SIZE, check_sum);
282
283 ret = efuse_write_bits(start_bit, size, key_data, (hi_u8 *)&usr_err_stat[0]);
284 if (ret != HI_ERR_SUCCESS) {
285 return ret;
286 }
287
288 for (i = 0; i < EFUSE_MAX_INDEX_SIZE; i++) {
289 if (usr_err_stat[i]) {
290 return HI_ERR_FAILURE;
291 }
292 }
293
294 return HI_ERR_SUCCESS;
295 }
296
297