1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright 2021 NXP
4 */
5 #include <arm.h>
6 #include <initcall.h>
7 #include <mm/core_memprot.h>
8 #include <mm/core_mmu.h>
9 #include <imx.h>
10 #include <io.h>
11 #include <drivers/imx_ocotp.h>
12 #include <kernel/tee_common_otp.h>
13
14 #define OCOTP_CTRL 0x0
15 #define OCOTP_CTRL_ERROR BIT32(9)
16 #define OCOTP_CTRL_BUSY BIT32(8)
17 #define OCOTP_SHADOW_OFFSET(_b, _w) ((_b) * (0x40) + (_w) * (0x10) + 0x400)
18
19 struct ocotp_instance {
20 unsigned char nb_banks;
21 unsigned char nb_words;
22 TEE_Result (*get_die_id)(uint64_t *ret_uid);
23 };
24
25 static vaddr_t g_base_addr;
26 static struct mutex fuse_read = MUTEX_INITIALIZER;
27 static const struct ocotp_instance *g_ocotp;
28
29 #if defined(CFG_MX6)
ocotp_clock_enable(void)30 static void ocotp_clock_enable(void)
31 {
32 vaddr_t va = core_mmu_get_va(CCM_BASE, MEM_AREA_IO_SEC, CCM_SIZE);
33
34 io_setbits32(va + CCM_CCGR2, BM_CCM_CCGR2_OCOTP_CTRL);
35 }
36 #elif defined(CFG_MX7)
ocotp_clock_enable(void)37 static void ocotp_clock_enable(void)
38 {
39 vaddr_t va = core_mmu_get_va(CCM_BASE, MEM_AREA_IO_SEC, CCM_SIZE);
40
41 io_setbits32(va + CCM_CCGRx_SET(CCM_CLOCK_DOMAIN_OCOTP),
42 CCM_CCGRx_ALWAYS_ON(0));
43 }
44 #elif defined(CFG_MX8M)
ocotp_clock_enable(void)45 static void ocotp_clock_enable(void)
46 {
47 vaddr_t va = core_mmu_get_va(CCM_BASE, MEM_AREA_IO_SEC, CCM_SIZE);
48
49 io_setbits32(va + CCM_CCGRx_SET(CCM_CCRG_OCOTP),
50 CCM_CCGRx_ALWAYS_ON(0));
51 }
52 #elif defined(CFG_MX7ULP)
53 /* The i.MX7ULP has the OCOTP always powered on */
ocotp_clock_enable(void)54 static inline void ocotp_clock_enable(void) { }
55 #else
56 #error "Platform not supported"
57 #endif
58
ocotp_ctrl_wait_for(uint32_t mask)59 static TEE_Result ocotp_ctrl_wait_for(uint32_t mask)
60 {
61 unsigned int loop = 0;
62 uint32_t reg = 0;
63
64 assert(g_base_addr);
65
66 /* 20us delay assuming the CPU clock running at 500MHz */
67 for (loop = 10000; loop > 0; loop--) {
68 reg = io_read32(g_base_addr + OCOTP_CTRL) & mask;
69 if (!reg)
70 return TEE_SUCCESS;
71 dsb();
72 isb();
73 }
74
75 return TEE_ERROR_BUSY;
76 }
77
imx_ocotp_read(unsigned int bank,unsigned int word,uint32_t * val)78 TEE_Result imx_ocotp_read(unsigned int bank, unsigned int word, uint32_t *val)
79 {
80 TEE_Result ret = TEE_ERROR_GENERIC;
81
82 if (!val)
83 return TEE_ERROR_BAD_PARAMETERS;
84
85 if (bank > g_ocotp->nb_banks || word > g_ocotp->nb_words)
86 return TEE_ERROR_BAD_PARAMETERS;
87
88 assert(g_base_addr && g_ocotp);
89
90 mutex_lock(&fuse_read);
91
92 ocotp_clock_enable();
93
94 /* Clear error bit */
95 io_clrbits32(g_base_addr + OCOTP_CTRL, OCOTP_CTRL_ERROR);
96
97 /* Wait for busy flag to be cleared */
98 ret = ocotp_ctrl_wait_for(OCOTP_CTRL_BUSY);
99 if (ret) {
100 EMSG("OCOTP is busy");
101 goto out;
102 }
103
104 /* Read shadow register */
105 *val = io_read32(g_base_addr + OCOTP_SHADOW_OFFSET(bank, word));
106
107 DMSG("OCOTP Bank %d Word %d Fuse 0x%" PRIx32, bank, word, *val);
108 out:
109 mutex_unlock(&fuse_read);
110
111 return ret;
112 }
113
ocotp_get_die_id_mx7ulp(uint64_t * ret_uid)114 static TEE_Result ocotp_get_die_id_mx7ulp(uint64_t *ret_uid)
115 {
116 TEE_Result res = TEE_ERROR_GENERIC;
117 uint32_t val = 0;
118 uint64_t uid = 0;
119
120 res = imx_ocotp_read(2, 6, &val);
121 if (res)
122 goto out;
123 uid = val & GENMASK_32(15, 0);
124
125 res = imx_ocotp_read(2, 5, &val);
126 if (res)
127 goto out;
128 uid = SHIFT_U64(uid, 16) | (val & GENMASK_32(15, 0));
129
130 res = imx_ocotp_read(2, 4, &val);
131 if (res)
132 goto out;
133 uid = SHIFT_U64(uid, 16) | (val & GENMASK_32(15, 0));
134
135 res = imx_ocotp_read(2, 3, &val);
136 if (res)
137 goto out;
138 uid = SHIFT_U64(uid, 16) | (val & GENMASK_32(15, 0));
139
140 out:
141 if (res == TEE_SUCCESS)
142 *ret_uid = uid;
143
144 return res;
145 }
146
ocotp_get_die_id_mx(uint64_t * ret_uid)147 static TEE_Result ocotp_get_die_id_mx(uint64_t *ret_uid)
148 {
149 TEE_Result res = TEE_ERROR_GENERIC;
150 uint32_t val = 0;
151 uint64_t uid = 0;
152
153 res = imx_ocotp_read(0, 2, &val);
154 if (res)
155 goto out;
156 uid = val;
157
158 res = imx_ocotp_read(0, 1, &val);
159 if (res)
160 goto out;
161 uid = SHIFT_U64(uid, 32) | val;
162
163 out:
164 if (res == TEE_SUCCESS)
165 *ret_uid = uid;
166
167 return res;
168 }
169
170 static const struct ocotp_instance ocotp_imx6q = {
171 .nb_banks = 16,
172 .nb_words = 8,
173 .get_die_id = ocotp_get_die_id_mx,
174 };
175
176 static const struct ocotp_instance ocotp_imx6sl = {
177 .nb_banks = 8,
178 .nb_words = 8,
179 .get_die_id = ocotp_get_die_id_mx,
180 };
181
182 static const struct ocotp_instance ocotp_imx6sll = {
183 .nb_banks = 16,
184 .nb_words = 8,
185 .get_die_id = ocotp_get_die_id_mx,
186 };
187
188 static const struct ocotp_instance ocotp_imx6sx = {
189 .nb_banks = 16,
190 .nb_words = 8,
191 .get_die_id = ocotp_get_die_id_mx,
192 };
193
194 static const struct ocotp_instance ocotp_imx6ul = {
195 .nb_banks = 16,
196 .nb_words = 8,
197 .get_die_id = ocotp_get_die_id_mx,
198 };
199
200 static const struct ocotp_instance ocotp_imx6ull = {
201 .nb_banks = 8,
202 .nb_words = 8,
203 .get_die_id = ocotp_get_die_id_mx,
204 };
205
206 static const struct ocotp_instance ocotp_imx7d = {
207 .nb_banks = 8,
208 .nb_words = 8,
209 .get_die_id = ocotp_get_die_id_mx,
210 };
211
212 static const struct ocotp_instance ocotp_imx7ulp = {
213 .nb_banks = 32,
214 .nb_words = 8,
215 .get_die_id = ocotp_get_die_id_mx7ulp,
216 };
217
218 static const struct ocotp_instance ocotp_imx8m = {
219 .nb_banks = 32,
220 .nb_words = 8,
221 .get_die_id = ocotp_get_die_id_mx,
222 };
223
224 static const struct ocotp_instance ocotp_imx8mp = {
225 .nb_banks = 48,
226 .nb_words = 8,
227 .get_die_id = ocotp_get_die_id_mx,
228 };
229
tee_otp_get_die_id(uint8_t * buffer,size_t len)230 int tee_otp_get_die_id(uint8_t *buffer, size_t len)
231 {
232 size_t max_size_uid = IMX_UID_SIZE;
233 uint64_t uid = 0;
234
235 assert(buffer);
236 assert(g_base_addr && g_ocotp);
237
238 if (g_ocotp->get_die_id(&uid))
239 goto err;
240
241 memcpy(buffer, &uid, MIN(max_size_uid, len));
242 return 0;
243
244 err:
245 EMSG("Error while getting die ID");
246 return -1;
247 }
248
249 register_phys_mem_pgdir(MEM_AREA_IO_SEC, OCOTP_BASE, CORE_MMU_PGDIR_SIZE);
imx_ocotp_init(void)250 static TEE_Result imx_ocotp_init(void)
251 {
252 g_base_addr = core_mmu_get_va(OCOTP_BASE, MEM_AREA_IO_SEC, OCOTP_SIZE);
253 if (!g_base_addr)
254 return TEE_ERROR_GENERIC;
255
256 if (soc_is_imx6sdl() || soc_is_imx6dq() || soc_is_imx6dqp()) {
257 g_ocotp = &ocotp_imx6q;
258 } else if (soc_is_imx6sl()) {
259 g_ocotp = &ocotp_imx6sl;
260 } else if (soc_is_imx6sll()) {
261 g_ocotp = &ocotp_imx6sll;
262 } else if (soc_is_imx6sx()) {
263 g_ocotp = &ocotp_imx6sx;
264 } else if (soc_is_imx6ul()) {
265 g_ocotp = &ocotp_imx6ul;
266 } else if (soc_is_imx6ull()) {
267 g_ocotp = &ocotp_imx6ull;
268 } else if (soc_is_imx7ds()) {
269 g_ocotp = &ocotp_imx7d;
270 } else if (soc_is_imx7ulp()) {
271 g_ocotp = &ocotp_imx7ulp;
272 } else if (soc_is_imx8mm() || soc_is_imx8mn() || soc_is_imx8mq()) {
273 g_ocotp = &ocotp_imx8m;
274 } else if (soc_is_imx8mp()) {
275 g_ocotp = &ocotp_imx8mp;
276 } else {
277 g_ocotp = NULL;
278 return TEE_ERROR_NOT_SUPPORTED;
279 }
280
281 return TEE_SUCCESS;
282 }
283 driver_init(imx_ocotp_init);
284