xref: /optee_os/core/drivers/imx_snvs.c (revision bcf9ecad78d7a973367b76811d30f48ff7dcb053)
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
27*bcf9ecadSFranck LENORMAND #define SNVS_HPSR_SYS_SECURITY_CFG	  GENMASK_32(14, 12)
285cd93c5aSClement Faure 
29ea4f7ad6SClement Faure #define SNVS_HPSR_OTPMK_SYND	      GENMASK_32(24, 16)
30ea4f7ad6SClement Faure #define SNVS_HPSR_OTPMK_ZERO	      BIT(27)
31ea4f7ad6SClement Faure 
32ea4f7ad6SClement Faure #define SNVS_HPLR_MKS_SL BIT32(9)
33ea4f7ad6SClement Faure 
34ea4f7ad6SClement Faure #define SNVS_LPLR_MKS_HL BIT32(9)
35ea4f7ad6SClement Faure 
36ea4f7ad6SClement Faure #define SNVS_HPCOMR_MKS_EN   BIT32(13)
37ea4f7ad6SClement Faure #define SNVS_HPCOMR_NPSWA_EN BIT32(31)
38ea4f7ad6SClement Faure 
39ea4f7ad6SClement Faure #define SNVS_LPMKCR_MKCR_MKS_SEL GENMASK_32(1, 0)
40916e56edSClement Faure 
41916e56edSClement Faure enum snvs_ssm_mode {
42916e56edSClement Faure 	SNVS_SSM_MODE_INIT,
43916e56edSClement Faure 	SNVS_SSM_MODE_HARD_FAIL,
44916e56edSClement Faure 	SNVS_SSM_MODE_SOFT_FAIL = 3,
45916e56edSClement Faure 	SNVS_SSM_MODE_INIT_INTERMEDIATE = 8,
46916e56edSClement Faure 	SNVS_SSM_MODE_CHECK,
47916e56edSClement Faure 	SNVS_SSM_MODE_NON_SECURE = 11,
48916e56edSClement Faure 	SNVS_SSM_MODE_TRUSTED = 13,
49ec93a5a2SClement Faure 	SNVS_SSM_MODE_SECURE = 15,
50916e56edSClement Faure };
51916e56edSClement Faure 
52916e56edSClement Faure enum snvs_security_cfg {
53916e56edSClement Faure 	SNVS_SECURITY_CFG_FAB,
54916e56edSClement Faure 	SNVS_SECURITY_CFG_OPEN,
55916e56edSClement Faure 	SNVS_SECURITY_CFG_CLOSED,
56916e56edSClement Faure 	SNVS_SECURITY_CFG_FIELD_RETURN,
57916e56edSClement Faure };
58916e56edSClement Faure 
59ea4f7ad6SClement Faure /*
60ea4f7ad6SClement Faure  * Return true if the master key is OTPMK, false otherwise.
61ea4f7ad6SClement Faure  */
62ea4f7ad6SClement Faure static bool is_otpmk_selected(void)
63ea4f7ad6SClement Faure {
64ea4f7ad6SClement Faure 	uint32_t hp_mks = 0;
65ea4f7ad6SClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC, SNVS_SIZE);
66ea4f7ad6SClement Faure 
67ea4f7ad6SClement Faure 	hp_mks = io_read32(base + SNVS_HPCOMR);
68ea4f7ad6SClement Faure 
69ea4f7ad6SClement Faure 	/*
70ea4f7ad6SClement Faure 	 * The master key selection might be done by the MASTER_KEY_SEL field
71ea4f7ad6SClement Faure 	 * of LPMKCR instead.
72ea4f7ad6SClement Faure 	 */
73ea4f7ad6SClement Faure 	if (hp_mks & SNVS_HPCOMR_MKS_EN) {
74ea4f7ad6SClement Faure 		uint32_t lp_mks = io_read32(base + SNVS_LPMKCR);
75ea4f7ad6SClement Faure 
76ea4f7ad6SClement Faure 		if (lp_mks & SNVS_LPMKCR_MKCR_MKS_SEL)
77ea4f7ad6SClement Faure 			return false;
78ea4f7ad6SClement Faure 	}
79ea4f7ad6SClement Faure 
80ea4f7ad6SClement Faure 	return true;
81ea4f7ad6SClement Faure }
82ea4f7ad6SClement Faure 
83ea4f7ad6SClement Faure /*
84ea4f7ad6SClement Faure  * Return true if the master key selection is locked, false otherwise.
85ea4f7ad6SClement Faure  */
86ea4f7ad6SClement Faure static bool is_mks_locked(void)
87ea4f7ad6SClement Faure {
88ea4f7ad6SClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC, SNVS_SIZE);
89ea4f7ad6SClement Faure 
90ea4f7ad6SClement Faure 	return io_read32(base + SNVS_HPLR) & SNVS_HPLR_MKS_SL ||
91ea4f7ad6SClement Faure 	       io_read32(base + SNVS_LPLR) & SNVS_LPLR_MKS_HL;
92ea4f7ad6SClement Faure }
93ea4f7ad6SClement Faure 
94ea4f7ad6SClement Faure /* Set the Master key to use OTPMK and lock it. */
95ea4f7ad6SClement Faure static void set_mks_otpmk(void)
96ea4f7ad6SClement Faure {
97ea4f7ad6SClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC, SNVS_SIZE);
98ea4f7ad6SClement Faure 
99ea4f7ad6SClement Faure 	io_setbits32(base + SNVS_HPCOMR, SNVS_HPCOMR_MKS_EN);
100ea4f7ad6SClement Faure 	io_clrbits32(base + SNVS_LPMKCR, SNVS_LPMKCR_MKCR_MKS_SEL);
101ea4f7ad6SClement Faure 	io_clrbits32(base + SNVS_HPLR, SNVS_HPLR_MKS_SL);
102ea4f7ad6SClement Faure 	io_setbits32(base + SNVS_LPLR, SNVS_LPLR_MKS_HL);
103ea4f7ad6SClement Faure }
104ea4f7ad6SClement Faure 
105ea4f7ad6SClement Faure /*
106ea4f7ad6SClement Faure  * Return true if OTPMK is valid, false otherwise.
107ea4f7ad6SClement Faure  */
108ea4f7ad6SClement Faure static bool is_otpmk_valid(void)
109ea4f7ad6SClement Faure {
110ea4f7ad6SClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC, SNVS_SIZE);
111ea4f7ad6SClement Faure 	uint32_t status = io_read32(base + SNVS_HPSR);
112ea4f7ad6SClement Faure 
113ea4f7ad6SClement Faure 	return !(status & (SNVS_HPSR_OTPMK_ZERO | SNVS_HPSR_OTPMK_SYND));
114ea4f7ad6SClement Faure }
115ea4f7ad6SClement Faure 
1165cd93c5aSClement Faure static enum snvs_security_cfg snvs_get_security_cfg(void)
1175cd93c5aSClement Faure {
1185cd93c5aSClement Faure 	uint32_t val = 0;
1195cd93c5aSClement Faure 	vaddr_t base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC,
1205cd93c5aSClement Faure 				       SNVS_SIZE);
1215cd93c5aSClement Faure 
122de2fcd34SFranck LENORMAND 	val = (io_read32(base + SNVS_HPSR) & SNVS_HPSR_SYS_SECURITY_CFG) >>
123de2fcd34SFranck LENORMAND 	      SNVS_HPSR_SYS_SECURITY_CFG_OFFSET;
1245cd93c5aSClement Faure 
1255cd93c5aSClement Faure 	switch (val) {
1265cd93c5aSClement Faure 	case 0b000:
1275cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_FAB;
1285cd93c5aSClement Faure 	case 0b001:
1295cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_OPEN;
1305cd93c5aSClement Faure 	case 0b011:
1315cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_CLOSED;
1325cd93c5aSClement Faure 	default:
1335cd93c5aSClement Faure 		return SNVS_SECURITY_CFG_FIELD_RETURN;
1345cd93c5aSClement Faure 	}
1355cd93c5aSClement Faure }
136c6ac89bcSPeng Fan 
137ea4f7ad6SClement Faure bool snvs_is_device_closed(void)
138ea4f7ad6SClement Faure {
139ea4f7ad6SClement Faure 	return (snvs_get_security_cfg() == SNVS_SECURITY_CFG_CLOSED);
140ea4f7ad6SClement Faure }
141ea4f7ad6SClement Faure 
142ea4f7ad6SClement Faure #ifdef CFG_RPMB_FS
143916e56edSClement Faure static enum snvs_ssm_mode snvs_get_ssm_mode(void)
144c6ac89bcSPeng Fan {
145c2e4eb43SAnton Rybakov 	vaddr_t snvs = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC,
146c2e4eb43SAnton Rybakov 				       SNVS_HPSR + sizeof(uint32_t));
147599784c7SRouven Czerwinski 	uint32_t val = 0;
148c6ac89bcSPeng Fan 
149599784c7SRouven Czerwinski 	val = io_read32(snvs + SNVS_HPSR);
150599784c7SRouven Czerwinski 	val &= HPSR_SSM_ST_MASK;
151599784c7SRouven Czerwinski 	val = val >> HPSR_SSM_ST_SHIFT;
152599784c7SRouven Czerwinski 	DMSG("HPSR: SSM ST Mode: 0x%01"PRIx32, val);
153599784c7SRouven Czerwinski 	return val;
154c6ac89bcSPeng Fan }
155916e56edSClement Faure 
156916e56edSClement Faure bool plat_rpmb_key_is_ready(void)
157916e56edSClement Faure {
158916e56edSClement Faure 	enum snvs_ssm_mode mode = SNVS_SSM_MODE_INIT;
159916e56edSClement Faure 	bool ssm_secure = false;
160916e56edSClement Faure 
161916e56edSClement Faure 	mode = snvs_get_ssm_mode();
162916e56edSClement Faure 	ssm_secure = (mode == SNVS_SSM_MODE_TRUSTED ||
163916e56edSClement Faure 		      mode == SNVS_SSM_MODE_SECURE);
164916e56edSClement Faure 
165916e56edSClement Faure 	/*
166916e56edSClement Faure 	 * On i.MX6SDL and i.MX6DQ, the security cfg always returns
167916e56edSClement Faure 	 * SNVS_SECURITY_CFG_FAB (000), therefore we ignore the security
168916e56edSClement Faure 	 * configuration for this SoC.
169916e56edSClement Faure 	 */
170916e56edSClement Faure 	if (soc_is_imx6sdl() || soc_is_imx6dq())
171916e56edSClement Faure 		return ssm_secure;
172916e56edSClement Faure 
17348141578SClement Faure 	return ssm_secure && snvs_is_device_closed();
174916e56edSClement Faure }
175916e56edSClement Faure #endif /* CFG_RPMB_FS */
176ea4f7ad6SClement Faure 
177ea4f7ad6SClement Faure TEE_Result imx_snvs_set_master_otpmk(void)
178ea4f7ad6SClement Faure {
179332dec4aSFranck LENORMAND 	if (!is_otpmk_valid())
180ea4f7ad6SClement Faure 		return TEE_ERROR_BAD_STATE;
181ea4f7ad6SClement Faure 
182ea4f7ad6SClement Faure 	if (is_mks_locked()) {
183ea4f7ad6SClement Faure 		if (is_otpmk_selected())
184ea4f7ad6SClement Faure 			return TEE_SUCCESS;
185ea4f7ad6SClement Faure 
186ea4f7ad6SClement Faure 		return TEE_ERROR_BAD_STATE;
187ea4f7ad6SClement Faure 	}
188ea4f7ad6SClement Faure 
189ea4f7ad6SClement Faure 	set_mks_otpmk();
190ea4f7ad6SClement Faure 
191ea4f7ad6SClement Faure 	return TEE_SUCCESS;
192ea4f7ad6SClement Faure }
193