]> Git Repo - J-u-boot.git/blob - drivers/misc/imx_ele/fuse.c
Merge patch series "Fix various bugs"
[J-u-boot.git] / drivers / misc / imx_ele / fuse.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2020 NXP
4  */
5
6 #include <console.h>
7 #include <errno.h>
8 #include <fuse.h>
9 #include <asm/arch/sys_proto.h>
10 #include <asm/arch/imx-regs.h>
11 #include <env.h>
12 #include <asm/mach-imx/ele_api.h>
13 #include <asm/global_data.h>
14
15 DECLARE_GLOBAL_DATA_PTR;
16
17 #define FUSE_BANKS      64
18 #define WORDS_PER_BANKS 8
19
20 struct fsb_map_entry {
21         s32 fuse_bank;
22         u32 fuse_words;
23         bool redundancy;
24 };
25
26 struct ele_map_entry {
27         s32 fuse_bank;
28         u32 fuse_words;
29         u32 fuse_offset;
30         u32 ele_index;
31 };
32
33 #if defined(CONFIG_IMX8ULP)
34 #define FSB_OTP_SHADOW  0x800
35
36 struct fsb_map_entry fsb_mapping_table[] = {
37         { 3, 8 },
38         { 4, 8 },
39         { -1, 48 }, /* Reserve 48 words */
40         { 5, 8 },
41         { 6, 8 },
42         { 8,  4, true },
43         { 24, 4, true },
44         { 26, 4, true },
45         { 27, 4, true },
46         { 28, 8 },
47         { 29, 8 },
48         { 30, 8 },
49         { 31, 8 },
50         { 37, 8 },
51         { 38, 8 },
52         { 39, 8 },
53         { 40, 8 },
54         { 41, 8 },
55         { 42, 8 },
56         { 43, 8 },
57         { 44, 8 },
58         { 45, 8 },
59         { 46, 8 },
60 };
61
62 /* None ECC banks such like Redundancy or Bit protect */
63 u32 nonecc_fuse_banks[] = {
64         0, 1, 8, 12, 16, 22, 24, 25, 26, 27, 36, 41, 51, 56
65 };
66
67 struct ele_map_entry ele_api_mapping_table[] = {
68         { 1, 8 },       /* LOCK */
69         { 2, 8 },       /* ECID */
70         { 7, 4, 0, 1 }, /* OTP_UNIQ_ID */
71         { 15, 8 }, /* OEM SRK HASH */
72         { 23, 1, 4, 2 }, /* OTFAD */
73         { 25, 8 }, /* Test config2 */
74         { 26, 8 }, /* PMU */
75         { 27, 8 }, /* Test flow/USB */
76         { 32, 8 }, /* GP1 */
77         { 33, 8 }, /* GP2 */
78         { 34, 8 }, /* GP3 */
79         { 35, 8 }, /* GP4 */
80         { 36, 8 }, /* GP5 */
81         { 49, 8 }, /* GP8 */
82         { 50, 8 }, /* GP9 */
83         { 51, 8 }, /* GP10 */
84 };
85 #elif defined(CONFIG_ARCH_IMX9)
86 #define FSB_OTP_SHADOW  0x8000
87
88 struct fsb_map_entry fsb_mapping_table[] = {
89         { 0, 8 },
90         { 1, 8 },
91         { 2, 8 },
92         { 3, 8 },
93         { 4, 8 },
94         { 5, 8 },
95         { 6, 4 },
96         { -1, 260 },
97         { 39, 8 },
98         { 40, 8 },
99         { 41, 8 },
100         { 42, 8 },
101         { 43, 8 },
102         { 44, 8 },
103         { 45, 8 },
104         { 46, 8 },
105         { 47, 8 },
106         { 48, 8 },
107         { 49, 8 },
108         { 50, 8 },
109         { 51, 8 },
110         { 52, 8 },
111         { 53, 8 },
112         { 54, 8 },
113         { 55, 8 },
114         { 56, 8 },
115         { 57, 8 },
116         { 58, 8 },
117         { 59, 8 },
118         { 60, 8 },
119         { 61, 8 },
120         { 62, 8 },
121         { 63, 8 },
122 };
123
124 struct ele_map_entry ele_api_mapping_table[] = {
125         { 7, 1, 7, 63 },
126         { 16, 8, },
127         { 17, 8, },
128         { 22, 1, 6 },
129         { 23, 1, 4 },
130 };
131 #endif
132
133 static s32 map_fsb_fuse_index(u32 bank, u32 word, bool *redundancy)
134 {
135         s32 size = ARRAY_SIZE(fsb_mapping_table);
136         s32 i, word_pos = 0;
137
138         /* map the fuse from ocotp fuse map to FSB*/
139         for (i = 0; i < size; i++) {
140                 if (fsb_mapping_table[i].fuse_bank != -1 &&
141                     fsb_mapping_table[i].fuse_bank == bank &&
142                     fsb_mapping_table[i].fuse_words > word) {
143                         break;
144                 }
145
146                 word_pos += fsb_mapping_table[i].fuse_words;
147         }
148
149         if (i == size)
150                 return -1; /* Failed to find */
151
152         if (fsb_mapping_table[i].redundancy) {
153                 *redundancy = true;
154                 return (word >> 1) + word_pos;
155         }
156
157         *redundancy = false;
158         return word + word_pos;
159 }
160
161 static s32 map_ele_fuse_index(u32 bank, u32 word)
162 {
163         s32 size = ARRAY_SIZE(ele_api_mapping_table);
164         s32 i;
165
166         /* map the fuse from ocotp fuse map to FSB*/
167         for (i = 0; i < size; i++) {
168                 if (ele_api_mapping_table[i].fuse_bank != -1 &&
169                     ele_api_mapping_table[i].fuse_bank == bank) {
170                         if (word >= ele_api_mapping_table[i].fuse_offset &&
171                             word < (ele_api_mapping_table[i].fuse_offset +
172                             ele_api_mapping_table[i].fuse_words))
173                                 break;
174                 }
175         }
176
177         if (i == size)
178                 return -1; /* Failed to find */
179
180         if (ele_api_mapping_table[i].ele_index != 0)
181                 return ele_api_mapping_table[i].ele_index;
182
183         return ele_api_mapping_table[i].fuse_bank * 8 + word;
184 }
185
186 #if defined(CONFIG_IMX8ULP)
187 int fuse_sense(u32 bank, u32 word, u32 *val)
188 {
189         s32 word_index;
190         bool redundancy;
191
192         if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val)
193                 return -EINVAL;
194
195         word_index = map_fsb_fuse_index(bank, word, &redundancy);
196         if (word_index >= 0) {
197                 *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2));
198                 if (redundancy)
199                         *val = (*val >> ((word % 2) * 16)) & 0xFFFF;
200
201                 return 0;
202         }
203
204         word_index = map_ele_fuse_index(bank, word);
205         if (word_index >= 0) {
206                 u32 data[4];
207                 u32 res, size = 4;
208                 int ret;
209
210                 /* Only UID return 4 words */
211                 if (word_index != 1)
212                         size = 1;
213
214                 ret = ele_read_common_fuse(word_index, data, size, &res);
215                 if (ret) {
216                         printf("ahab read fuse failed %d, 0x%x\n", ret, res);
217                         return ret;
218                 }
219
220                 if (word_index == 1) {
221                         *val = data[word]; /* UID */
222                 } else if (word_index == 2) {
223                         /*
224                          * OTFAD 3 bits as follow:
225                          * bit 0: OTFAD_ENABLE
226                          * bit 1: OTFAD_DISABLE_OVERRIDE
227                          * bit 2: KEY_BLOB_EN
228                          */
229                         *val = data[0] << 3;
230                 } else {
231                         *val = data[0];
232                 }
233
234                 return 0;
235         }
236
237         return -ENOENT;
238 }
239 #elif defined(CONFIG_ARCH_IMX9)
240 int fuse_sense(u32 bank, u32 word, u32 *val)
241 {
242         s32 word_index;
243         bool redundancy;
244
245         if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val)
246                 return -EINVAL;
247
248         word_index = map_fsb_fuse_index(bank, word, &redundancy);
249         if (word_index >= 0) {
250                 *val = readl((ulong)FSB_BASE_ADDR + FSB_OTP_SHADOW + (word_index << 2));
251                 if (redundancy)
252                         *val = (*val >> ((word % 2) * 16)) & 0xFFFF;
253
254                 return 0;
255         }
256
257         word_index = map_ele_fuse_index(bank, word);
258         if (word_index >= 0) {
259                 u32 data;
260                 u32 res, size = 1;
261                 int ret;
262
263                 ret = ele_read_common_fuse(word_index, &data, size, &res);
264                 if (ret) {
265                         printf("ahab read fuse failed %d, 0x%x\n", ret, res);
266                         return ret;
267                 }
268
269                 *val = data;
270
271                 return 0;
272         }
273
274         return -ENOENT;
275 }
276 #endif
277
278 int fuse_read(u32 bank, u32 word, u32 *val)
279 {
280         return fuse_sense(bank, word, val);
281 }
282
283 int fuse_prog(u32 bank, u32 word, u32 val)
284 {
285         u32 res;
286         int ret;
287         bool lock = false;
288
289         if (bank >= FUSE_BANKS || word >= WORDS_PER_BANKS || !val)
290                 return -EINVAL;
291
292         /* Lock 8ULP ECC fuse word, so second programming will return failure.
293          * iMX9 OTP can protect ECC fuse, so not need it
294          */
295 #if defined(CONFIG_IMX8ULP)
296         u32 i;
297         for (i = 0; i < ARRAY_SIZE(nonecc_fuse_banks); i++) {
298                 if (nonecc_fuse_banks[i] == bank)
299                         break;
300         }
301
302         if (i == ARRAY_SIZE(nonecc_fuse_banks))
303                 lock = true;
304 #endif
305
306         ret = ele_write_fuse((bank * 8 + word), val, lock, &res);
307         if (ret) {
308                 printf("ahab write fuse failed %d, 0x%x\n", ret, res);
309                 return ret;
310         }
311
312         return 0;
313 }
314
315 int fuse_override(u32 bank, u32 word, u32 val)
316 {
317         printf("Override fuse to i.MX8ULP in u-boot is forbidden\n");
318         return -EPERM;
319 }
This page took 0.039492 seconds and 4 git commands to generate.