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