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