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