xref: /optee_os/core/drivers/imx_snvs.c (revision 8e81e2f5366a971afdd2ac47fb8529d1def5feb0)
1 /*
2  * Copyright 2017 NXP
3  * Copyright (c) 2014, 2015 Linaro Limited
4  *
5  * Peng Fan <peng.fan@nxp.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  * this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <initcall.h>
31 #include <io.h>
32 #include <drivers/imx_snvs.h>
33 #include <kernel/misc.h>
34 #include <kernel/tee_time.h>
35 #include <kernel/time_source.h>
36 #include <mm/core_memprot.h>
37 #include <mm/core_mmu.h>
38 #include <mpa.h>
39 #include <utee_defines.h>
40 #include <platform_config.h>
41 #include <stdint.h>
42 #include <tee/tee_cryp_utl.h>
43 #include <types_ext.h>
44 #include <trace.h>
45 
46 #define SNVS_LPLR	0x34
47 #define SNVS_LPCR	0x38
48 #define SNVS_LPMKCR	0x3C
49 #define SNVS_LPSVCR	0x40
50 #define SNVS_LPTGFCR	0x44
51 #define SNVS_LPTDCR	0x48
52 #define SNVS_LPSR	0x4C
53 #define SNVS_LPSRTCMR	0x50
54 #define SNVS_LPSRTCLR	0x54
55 #define SNVS_LPTAR	0x58
56 #define SNVS_LPSMCMR	0x5C
57 #define SNVS_LPSMCLR	0x60
58 #define SNVS_LPPGDR	0x64
59 #define SNVS_LPGPR0_A	0x68
60 #define SNVS_LPZMKR0	0x6C
61 #define SNVS_LPCGR0_30	0x90
62 #define SNVS_LPCGR0_31	0x94
63 #define SNVS_LPCGR0_32	0x98
64 #define SNVS_LPCGR0_33	0x9C
65 #define SNVS_LPTDC2R	0xA0
66 #define SNVS_LPTDSR	0xA4
67 #define SNVS_LPTGF1CR	0xA8
68 #define SNVS_LPTGF2CR	0xAC
69 #define SNVS_LPAT1CR	0xC0
70 #define SNVS_LPAT2CR	0xC4
71 #define SNVS_LPAT3CR	0xC8
72 #define SNVS_LPAT4CR	0xCC
73 #define SNVS_LPAT5CR	0xD0
74 #define SNVS_LPATCTLR	0xE0
75 #define SNVS_LPATCLKR	0xE4
76 #define SNVS_LPATRC1R	0xE8
77 #define SNVS_LPATRC2R	0xEC
78 
79 #define SNVS_LPCR_TOP_MASK		BIT(6)
80 #define SNVS_LPCR_DP_EN_MASK		BIT(5)
81 #define SNVS_LPCR_SRTC_ENV_MASK		BIT(0)
82 
83 /* SNVS LP SRTC takes 32K clock as input */
84 #define SNVS_SRTC_FREQ			0x8000
85 #define CNT_TO_SECS_SHIFT		15
86 #define CNT_TO_SECS_MASK		GENMASK_32(14, 0)
87 
88 static uint64_t snvs_srtc_read_lp_counter(void)
89 {
90 	vaddr_t snvs = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC);
91 	uint64_t val1, val2;
92 	uint32_t val;
93 
94 	do {
95 		val = read32(snvs + SNVS_LPSRTCMR);
96 		val1 = val;
97 		val1 <<= 32;
98 		val = read32(snvs + SNVS_LPSRTCLR);
99 		val1 |= val;
100 
101 		val = read32(snvs + SNVS_LPSRTCMR);
102 		val2 = val;
103 		val2 <<= 32;
104 		val = read32(snvs + SNVS_LPSRTCLR);
105 		val2 |= val;
106 
107 	/*
108 	 * When cpu/bus runs at low freq, we may never get same value
109 	 * during two consecutive read, so only compare the second value.
110 	 */
111 	} while ((val1 >> CNT_TO_SECS_SHIFT) != (val2 >> CNT_TO_SECS_SHIFT));
112 
113 	return val2;
114 }
115 
116 static TEE_Result snvs_srtc_get_sys_time(TEE_Time *time)
117 {
118 	uint64_t cnt = snvs_srtc_read_lp_counter();
119 
120 	time->seconds = cnt >> CNT_TO_SECS_SHIFT;
121 	time->millis = (cnt & CNT_TO_SECS_MASK) /
122 		(SNVS_SRTC_FREQ / TEE_TIME_MILLIS_BASE);
123 
124 	return TEE_SUCCESS;
125 }
126 
127 static const struct time_source snvs_srtc_time_source = {
128 	.name = "snvs srtc",
129 	.protection_level = 1000,
130 	.get_sys_time = snvs_srtc_get_sys_time,
131 };
132 
133 REGISTER_TIME_SOURCE(snvs_srtc_time_source)
134 
135 /* Needs to be invoked before service_init */
136 TEE_Result snvs_srtc_enable(void)
137 {
138 	vaddr_t snvs = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC);
139 	int timeout = 2000;
140 	uint32_t val;
141 
142 	val = read32(snvs + SNVS_LPCR);
143 	val |= SNVS_LPCR_SRTC_ENV_MASK;
144 	write32(val, snvs + SNVS_LPCR);
145 
146 	do {
147 		val = read32(snvs + SNVS_LPCR);
148 		if (val & SNVS_LPCR_SRTC_ENV_MASK)
149 			break;
150 	} while (--timeout);
151 
152 	if (!timeout)
153 		return TEE_ERROR_GENERIC;
154 
155 	return TEE_SUCCESS;
156 }
157 
158 /* Reused from tee_time_arm_cntpct.c */
159 void plat_prng_add_jitter_entropy(void)
160 {
161 	uint64_t tsc = snvs_srtc_read_lp_counter();
162 	int bytes = 0, n;
163 	static uint8_t first, bits;
164 	static uint16_t acc;
165 
166 	if (!first) {
167 		acc = tsc;
168 		bytes = 2;
169 		first = 1;
170 	} else {
171 		acc = (acc << 2) | ((acc >> 6) & 3);
172 		for (n = 0; n < 64; n += 2)
173 			acc ^= (tsc >> n) & 3;
174 		bits += 2;
175 		if (bits >= 8) {
176 			bits = 0;
177 			bytes = 1;
178 		}
179 	}
180 	if (bytes) {
181 		FMSG("%s: 0x%02" PRIX16, __func__,
182 		     acc & GENMASK_32(bytes * 8, 0));
183 		tee_prng_add_entropy((uint8_t *)&acc, bytes);
184 	}
185 }
186