xref: /optee_os/core/drivers/imx_snvs.c (revision ec93a5a23e53f354d88a31d424973d772cebce93)
11bb92983SJerome Forissier // SPDX-License-Identifier: BSD-2-Clause
2c6ac89bcSPeng Fan /*
3599784c7SRouven Czerwinski  * Copyright (C) 2020 Pengutronix
4599784c7SRouven Czerwinski  * Rouven Czerwinski <entwicklung@pengutronix.de>
5916e56edSClement Faure  * Copyright 2022 NXP
6c6ac89bcSPeng Fan  */
7c6ac89bcSPeng Fan 
8ea4f7ad6SClement Faure #include <drivers/imx_snvs.h>
9c6ac89bcSPeng Fan #include <io.h>
10c6ac89bcSPeng Fan #include <mm/core_memprot.h>
11c6ac89bcSPeng Fan #include <mm/core_mmu.h>
12c6ac89bcSPeng Fan #include <stdint.h>
13916e56edSClement Faure #include <tee/tee_fs.h>
14c6ac89bcSPeng Fan #include <types_ext.h>
15c6ac89bcSPeng Fan #include <trace.h>
16c6ac89bcSPeng Fan 
17ea4f7ad6SClement Faure #define SNVS_HPLR   0x00
18ea4f7ad6SClement Faure #define SNVS_HPCOMR 0x04
19916e56edSClement Faure #define SNVS_HPSR   0x14
20ea4f7ad6SClement Faure #define SNVS_LPLR   0x34
21ea4f7ad6SClement Faure #define SNVS_LPMKCR 0x3C
22916e56edSClement Faure 
23916e56edSClement Faure #define HPSR_SSM_ST_MASK  GENMASK_32(11, 8)
24916e56edSClement Faure #define HPSR_SSM_ST_SHIFT 8
25916e56edSClement Faure 
265cd93c5aSClement Faure #define SNVS_HPSR_SYS_SECURITY_CFG_OFFSET 12
275cd93c5aSClement Faure 
28ea4f7ad6SClement Faure #define SNVS_HPSR_OTPMK_SYND	      GENMASK_32(24, 16)
29ea4f7ad6SClement Faure #define SNVS_HPSR_OTPMK_ZERO	      BIT(27)
30ea4f7ad6SClement Faure 
31ea4f7ad6SClement Faure #define SNVS_HPLR_MKS_SL BIT32(9)
32ea4f7ad6SClement Faure 
33ea4f7ad6SClement Faure #define SNVS_LPLR_MKS_HL BIT32(9)
34ea4f7ad6SClement Faure 
35ea4f7ad6SClement Faure #define SNVS_HPCOMR_MKS_EN   BIT32(13)
36ea4f7ad6SClement Faure #define SNVS_HPCOMR_NPSWA_EN BIT32(31)
37ea4f7ad6SClement Faure 
38ea4f7ad6SClement Faure #define SNVS_LPMKCR_MKCR_MKS_SEL GENMASK_32(1, 0)
39916e56edSClement Faure 
40916e56edSClement Faure enum snvs_ssm_mode {
41916e56edSClement Faure 	SNVS_SSM_MODE_INIT,
42916e56edSClement Faure 	SNVS_SSM_MODE_HARD_FAIL,
43916e56edSClement Faure 	SNVS_SSM_MODE_SOFT_FAIL = 3,
44916e56edSClement Faure 	SNVS_SSM_MODE_INIT_INTERMEDIATE = 8,
45916e56edSClement Faure 	SNVS_SSM_MODE_CHECK,
46916e56edSClement Faure 	SNVS_SSM_MODE_NON_SECURE = 11,
47916e56edSClement Faure 	SNVS_SSM_MODE_TRUSTED = 13,
48*ec93a5a2SClement Faure 	SNVS_SSM_MODE_SECURE = 15,
49916e56edSClement Faure };
50916e56edSClement Faure 
51916e56edSClement Faure enum snvs_security_cfg {
52916e56edSClement Faure 	SNVS_SECURITY_CFG_FAB,
53916e56edSClement Faure 	SNVS_SECURITY_CFG_OPEN,
54916e56edSClement Faure 	SNVS_SECURITY_CFG_CLOSED,
55916e56edSClement Faure 	SNVS_SECURITY_CFG_FIELD_RETURN,
56916e56edSClement Faure };
57916e56edSClement Faure 
58ea4f7ad6SClement Faure /*
59ea4f7ad6SClement Faure  * Return true if the master key is OTPMK, false otherwise.
60ea4f7ad6SClement Faure  */
61ea4f7ad6SClement Faure static bool is_otpmk_selected(void)
62ea4f7ad6SClement Faure {
63ea4f7ad6SClement Faure 	uint32_t hp_mks = 0;
64ea4f7ad6SClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC, SNVS_SIZE);
65ea4f7ad6SClement Faure 
66ea4f7ad6SClement Faure 	hp_mks = io_read32(base + SNVS_HPCOMR);
67ea4f7ad6SClement Faure 
68ea4f7ad6SClement Faure 	/*
69ea4f7ad6SClement Faure 	 * The master key selection might be done by the MASTER_KEY_SEL field
70ea4f7ad6SClement Faure 	 * of LPMKCR instead.
71ea4f7ad6SClement Faure 	 */
72ea4f7ad6SClement Faure 	if (hp_mks & SNVS_HPCOMR_MKS_EN) {
73ea4f7ad6SClement Faure 		uint32_t lp_mks = io_read32(base + SNVS_LPMKCR);
74ea4f7ad6SClement Faure 
75ea4f7ad6SClement Faure 		if (lp_mks & SNVS_LPMKCR_MKCR_MKS_SEL)
76ea4f7ad6SClement Faure 			return false;
77ea4f7ad6SClement Faure 	}
78ea4f7ad6SClement Faure 
79ea4f7ad6SClement Faure 	return true;
80ea4f7ad6SClement Faure }
81ea4f7ad6SClement Faure 
82ea4f7ad6SClement Faure /*
83ea4f7ad6SClement Faure  * Return true if the master key selection is locked, false otherwise.
84ea4f7ad6SClement Faure  */
85ea4f7ad6SClement Faure static bool is_mks_locked(void)
86ea4f7ad6SClement Faure {
87ea4f7ad6SClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC, SNVS_SIZE);
88ea4f7ad6SClement Faure 
89ea4f7ad6SClement Faure 	return io_read32(base + SNVS_HPLR) & SNVS_HPLR_MKS_SL ||
90ea4f7ad6SClement Faure 	       io_read32(base + SNVS_LPLR) & SNVS_LPLR_MKS_HL;
91ea4f7ad6SClement Faure }
92ea4f7ad6SClement Faure 
93ea4f7ad6SClement Faure /* Set the Master key to use OTPMK and lock it. */
94ea4f7ad6SClement Faure static void set_mks_otpmk(void)
95ea4f7ad6SClement Faure {
96ea4f7ad6SClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC, SNVS_SIZE);
97ea4f7ad6SClement Faure 
98ea4f7ad6SClement Faure 	io_setbits32(base + SNVS_HPCOMR, SNVS_HPCOMR_MKS_EN);
99ea4f7ad6SClement Faure 	io_clrbits32(base + SNVS_LPMKCR, SNVS_LPMKCR_MKCR_MKS_SEL);
100ea4f7ad6SClement Faure 	io_clrbits32(base + SNVS_HPLR, SNVS_HPLR_MKS_SL);
101ea4f7ad6SClement Faure 	io_setbits32(base + SNVS_LPLR, SNVS_LPLR_MKS_HL);
102ea4f7ad6SClement Faure }
103ea4f7ad6SClement Faure 
104ea4f7ad6SClement Faure /*
105ea4f7ad6SClement Faure  * Return true if OTPMK is valid, false otherwise.
106ea4f7ad6SClement Faure  */
107ea4f7ad6SClement Faure static bool is_otpmk_valid(void)
108ea4f7ad6SClement Faure {
109ea4f7ad6SClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC, SNVS_SIZE);
110ea4f7ad6SClement Faure 	uint32_t status = io_read32(base + SNVS_HPSR);
111ea4f7ad6SClement Faure 
112ea4f7ad6SClement Faure 	return !(status & (SNVS_HPSR_OTPMK_ZERO | SNVS_HPSR_OTPMK_SYND));
113ea4f7ad6SClement Faure }
114ea4f7ad6SClement Faure 
1155cd93c5aSClement Faure #ifdef CFG_MX8M
1165cd93c5aSClement Faure #define SNVS_HPSR_SYS_SECURITY_CFG GENMASK_32(15, 12)
1175cd93c5aSClement Faure 
118916e56edSClement Faure static enum snvs_security_cfg snvs_get_security_cfg(void)
119c6ac89bcSPeng Fan {
120599784c7SRouven Czerwinski 	uint32_t val = 0;
1215cd93c5aSClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC,
1225cd93c5aSClement Faure 				       SNVS_SIZE);
123c6ac89bcSPeng Fan 
1245cd93c5aSClement Faure 	val = io_read32(base + SNVS_HPSR) &
1255cd93c5aSClement Faure 	      SNVS_HPSR_SYS_SECURITY_CFG >> SNVS_HPSR_SYS_SECURITY_CFG_OFFSET;
126c6ac89bcSPeng Fan 
1275cd93c5aSClement Faure 	switch (val) {
1285cd93c5aSClement Faure 	case 0b0000:
1295cd93c5aSClement Faure 	case 0b1000:
130599784c7SRouven Czerwinski 		return SNVS_SECURITY_CFG_FAB;
1315cd93c5aSClement Faure 	case 0b0001:
1325cd93c5aSClement Faure 	case 0b0010:
1335cd93c5aSClement Faure 	case 0b0011:
1345cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_OPEN;
1355cd93c5aSClement Faure 	case 0b1010:
1365cd93c5aSClement Faure 	case 0b1001:
1375cd93c5aSClement Faure 	case 0b1011:
1385cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_CLOSED;
1395cd93c5aSClement Faure 	default:
1405cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_FIELD_RETURN;
141c6ac89bcSPeng Fan 	}
1425cd93c5aSClement Faure }
1435cd93c5aSClement Faure #else
1445cd93c5aSClement Faure #define SNVS_HPSR_SYS_SECURITY_CFG GENMASK_32(14, 12)
1455cd93c5aSClement Faure 
1465cd93c5aSClement Faure static enum snvs_security_cfg snvs_get_security_cfg(void)
1475cd93c5aSClement Faure {
1485cd93c5aSClement Faure 	uint32_t val = 0;
1495cd93c5aSClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC,
1505cd93c5aSClement Faure 				       SNVS_SIZE);
1515cd93c5aSClement Faure 
1525cd93c5aSClement Faure 	val = io_read32(base + SNVS_HPSR) &
1535cd93c5aSClement Faure 	      SNVS_HPSR_SYS_SECURITY_CFG >> SNVS_HPSR_SYS_SECURITY_CFG_OFFSET;
1545cd93c5aSClement Faure 
1555cd93c5aSClement Faure 	switch (val) {
1565cd93c5aSClement Faure 	case 0b000:
1575cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_FAB;
1585cd93c5aSClement Faure 	case 0b001:
1595cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_OPEN;
1605cd93c5aSClement Faure 	case 0b011:
1615cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_CLOSED;
1625cd93c5aSClement Faure 	default:
1635cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_FIELD_RETURN;
1645cd93c5aSClement Faure 	}
1655cd93c5aSClement Faure }
1665cd93c5aSClement Faure #endif
167c6ac89bcSPeng Fan 
168ea4f7ad6SClement Faure bool snvs_is_device_closed(void)
169ea4f7ad6SClement Faure {
170ea4f7ad6SClement Faure 	return (snvs_get_security_cfg() == SNVS_SECURITY_CFG_CLOSED);
171ea4f7ad6SClement Faure }
172ea4f7ad6SClement Faure 
173ea4f7ad6SClement Faure #ifdef CFG_RPMB_FS
174916e56edSClement Faure static enum snvs_ssm_mode snvs_get_ssm_mode(void)
175c6ac89bcSPeng Fan {
176c2e4eb43SAnton Rybakov 	vaddr_t snvs = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC,
177c2e4eb43SAnton Rybakov 				       SNVS_HPSR + sizeof(uint32_t));
178599784c7SRouven Czerwinski 	uint32_t val = 0;
179c6ac89bcSPeng Fan 
180599784c7SRouven Czerwinski 	val = io_read32(snvs + SNVS_HPSR);
181599784c7SRouven Czerwinski 	val &= HPSR_SSM_ST_MASK;
182599784c7SRouven Czerwinski 	val = val >> HPSR_SSM_ST_SHIFT;
183599784c7SRouven Czerwinski 	DMSG("HPSR: SSM ST Mode: 0x%01"PRIx32, val);
184599784c7SRouven Czerwinski 	return val;
185c6ac89bcSPeng Fan }
186916e56edSClement Faure 
187916e56edSClement Faure bool plat_rpmb_key_is_ready(void)
188916e56edSClement Faure {
189916e56edSClement Faure 	enum snvs_ssm_mode mode = SNVS_SSM_MODE_INIT;
190916e56edSClement Faure 	enum snvs_security_cfg security = SNVS_SECURITY_CFG_OPEN;
191916e56edSClement Faure 	bool ssm_secure = false;
192916e56edSClement Faure 
193916e56edSClement Faure 	mode = snvs_get_ssm_mode();
194916e56edSClement Faure 	security = snvs_get_security_cfg();
195916e56edSClement Faure 	ssm_secure = (mode == SNVS_SSM_MODE_TRUSTED ||
196916e56edSClement Faure 		      mode == SNVS_SSM_MODE_SECURE);
197916e56edSClement Faure 
198916e56edSClement Faure 	/*
199916e56edSClement Faure 	 * On i.MX6SDL and i.MX6DQ, the security cfg always returns
200916e56edSClement Faure 	 * SNVS_SECURITY_CFG_FAB (000), therefore we ignore the security
201916e56edSClement Faure 	 * configuration for this SoC.
202916e56edSClement Faure 	 */
203916e56edSClement Faure 	if (soc_is_imx6sdl() || soc_is_imx6dq())
204916e56edSClement Faure 		return ssm_secure;
205916e56edSClement Faure 
206916e56edSClement Faure 	return ssm_secure && (security == SNVS_SECURITY_CFG_CLOSED);
207916e56edSClement Faure }
208916e56edSClement Faure #endif /* CFG_RPMB_FS */
209ea4f7ad6SClement Faure 
210ea4f7ad6SClement Faure TEE_Result imx_snvs_set_master_otpmk(void)
211ea4f7ad6SClement Faure {
212ea4f7ad6SClement Faure 	if (is_otpmk_valid())
213ea4f7ad6SClement Faure 		return TEE_ERROR_BAD_STATE;
214ea4f7ad6SClement Faure 
215ea4f7ad6SClement Faure 	if (is_mks_locked()) {
216ea4f7ad6SClement Faure 		if (is_otpmk_selected())
217ea4f7ad6SClement Faure 			return TEE_SUCCESS;
218ea4f7ad6SClement Faure 
219ea4f7ad6SClement Faure 		return TEE_ERROR_BAD_STATE;
220ea4f7ad6SClement Faure 	}
221ea4f7ad6SClement Faure 
222ea4f7ad6SClement Faure 	set_mks_otpmk();
223ea4f7ad6SClement Faure 
224ea4f7ad6SClement Faure 	return TEE_SUCCESS;
225ea4f7ad6SClement Faure }
226