xref: /optee_os/core/drivers/qcom/ramblur/ramblur_pimem_v3.c (revision c037ba515a25e93ee78f8d3bf71fc75940668d7a)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4  */
5 
6 #include <assert.h>
7 #include <config.h>
8 #include <drivers/qcom/ramblur/v3/ramblur_pimem_hwio.h>
9 #include <initcall.h>
10 #include <io.h>
11 #include <kernel/panic.h>
12 #include <mm/core_memprot.h>
13 #include <string.h>
14 
15 #define ANTIROLLBACK	(UINT32_C(1) << \
16 	RAMBLUR_WIN0_ALGORITHM_ANTIROLLBACK_ENABLE_SHFT)
17 #define INTEGRITY	(UINT32_C(1) << \
18 	RAMBLUR_WIN0_ALGORITHM_INTEGRITY_ENABLE_SHFT)
19 #define CONFIDENTIALITY	(UINT32_C(1) << \
20 	RAMBLUR_WIN0_ALGORITHM_CONFIDENTIALITY_ENABLE_SHFT)
21 
22 static vaddr_t ramblur_va;
23 static struct {
24 	uint32_t major;
25 	uint32_t minor;
26 	uint32_t step;
27 } ramblur_version;
28 
in_word(uint32_t offset)29 static inline uint16_t in_word(uint32_t offset)
30 {
31 	return io_read16(ramblur_va + (vaddr_t)offset);
32 }
33 
in_dword(uint32_t offset)34 static inline uint32_t in_dword(uint32_t offset)
35 {
36 	return io_read32(ramblur_va + (vaddr_t)offset);
37 }
38 
out_dword(uint32_t offset,uint32_t val)39 static inline void out_dword(uint32_t offset, uint32_t val)
40 {
41 	io_write32(ramblur_va + (vaddr_t)offset, val);
42 }
43 
in_dword_masked(uint32_t offset,uint32_t mask)44 static inline uint32_t in_dword_masked(uint32_t offset, uint32_t mask)
45 {
46 	return in_dword(offset) & mask;
47 }
48 
out_dword_masked_ns(uint32_t offset,uint32_t mask,uint32_t val,uint32_t current_val)49 static inline void out_dword_masked_ns(uint32_t offset, uint32_t mask,
50 				       uint32_t val, uint32_t current_val)
51 {
52 	uint32_t new_val;
53 
54 	new_val = (current_val & ~mask) | (val & mask);
55 	out_dword(offset, new_val);
56 }
57 
readback_sync(uint32_t reg,uint32_t val,uint32_t mask,uint32_t shift)58 static inline void readback_sync(uint32_t reg, uint32_t val, uint32_t mask,
59 				 uint32_t shift)
60 {
61 	if (shift > 31)
62 		panic();
63 
64 	dsb();
65 	while (val != (in_dword_masked(reg, mask) >> shift))
66 		;
67 }
68 
enable(int window)69 static void enable(int window)
70 {
71 	uint32_t mask = RAMBLUR_WINn_CTL_WIN_ENABLE_BMSK;
72 	uint32_t reg = RAMBLUR_WINn_CTL_ADDR(window);
73 	uint32_t val = BIT(RAMBLUR_WINn_CTL_WIN_ENABLE_SHFT);
74 
75 	out_dword_masked_ns(reg, mask, val, RAMBLUR_WINn_CTL_INI(window));
76 
77 	reg = RAMBLUR_WINn_STATUS_ADDR(window);
78 	mask = RAMBLUR_WINn_STATUS_WIN_ENABLE_STATUS_BMSK;
79 	do {
80 		val = in_dword_masked(reg, mask) >>
81 			RAMBLUR_WINn_STATUS_WIN_ENABLE_STATUS_SHFT;
82 	} while (val != 1U);
83 }
84 
disable_sw_init_mode(int window)85 static void disable_sw_init_mode(int window)
86 {
87 	uint32_t mask = RAMBLUR_WINn_CTL_SW_INIT_MODE_BMSK;
88 	uint32_t reg = RAMBLUR_WINn_CTL_ADDR(window);
89 	uint32_t val = 0;
90 
91 	out_dword_masked_ns(reg, mask, val, RAMBLUR_WINn_CTL_INI(window));
92 	readback_sync(reg, val, mask, RAMBLUR_WINn_CTL_SW_INIT_MODE_SHFT);
93 }
94 
disable(int window)95 static void disable(int window)
96 {
97 	uint32_t mask = RAMBLUR_WINn_CTL_WIN_DISABLE_BMSK;
98 	uint32_t reg = RAMBLUR_WINn_CTL_ADDR(window);
99 	uint32_t val = BIT(RAMBLUR_WINn_CTL_WIN_DISABLE_SHFT);
100 
101 	out_dword_masked_ns(reg, mask, val, RAMBLUR_WINn_CTL_INI(window));
102 
103 	mask = RAMBLUR_WINn_STATUS_WIN_ENABLE_STATUS_BMSK;
104 	reg = RAMBLUR_WINn_STATUS_ADDR(window);
105 	do {
106 		val = in_dword_masked(reg, mask) >>
107 			RAMBLUR_WINn_STATUS_WIN_ENABLE_STATUS_SHFT;
108 	} while (val != 0U);
109 }
110 
set_hw_init(int window,uint32_t offset)111 static void set_hw_init(int window, uint32_t offset)
112 {
113 	uint32_t mask = RAMBLUR_WINn_HW_INIT_START_BMSK;
114 	uint32_t reg = RAMBLUR_WINn_HW_INIT_START_ADDR(window);
115 	uint32_t cur = RAMBLUR_WINn_HW_INIT_START_INI(window);
116 	uint32_t val = offset;
117 
118 	out_dword_masked_ns(reg, mask, val, cur);
119 	readback_sync(reg, val & mask, mask, 0);
120 }
121 
initialize_hardware_v3_0(int window)122 static void initialize_hardware_v3_0(int window)
123 {
124 	int skip = 6; /* stabilize output */
125 	uint32_t mask = RAMBLUR_WINn_STATUS_HW_INIT_IN_PROGRESS_BMSK;
126 	uint32_t reg = RAMBLUR_WINn_STATUS_ADDR(window);
127 	uint32_t val = 0;
128 
129 	/*
130 	 * pIMEM 3.0: HW_INIT_IN_PROGRESS updates only after ~6 cycles.
131 	 * Because the first write is posted, the immediate read may return 0.
132 	 * Issuing a few back-to-back reads ensures the bit has settled.
133 	 */
134 	do {
135 		val = in_dword_masked(reg, mask) >>
136 		      RAMBLUR_WINn_STATUS_HW_INIT_IN_PROGRESS_SHFT;
137 
138 		if (skip > 0) {
139 			skip--;
140 			continue;
141 		}
142 
143 	} while (val != 0);
144 }
145 
initialize_hardware_v3_x(int window)146 static void initialize_hardware_v3_x(int window)
147 {
148 	uint32_t mask = RAMBLUR_WINn_STATUS_HW_INIT_DONE_BMSK;
149 	uint32_t reg = RAMBLUR_WINn_STATUS_ADDR(window);
150 	uint32_t val = 0;
151 
152 	do {
153 		val = in_dword_masked(reg, mask) >>
154 			RAMBLUR_WINn_STATUS_HW_INIT_DONE_SHFT;
155 	} while (val != 1U);
156 }
157 
initialize_hardware(int window)158 static void initialize_hardware(int window)
159 {
160 	uint32_t mask = RAMBLUR_WINn_CTL_START_HW_INIT_BMSK;
161 	uint32_t reg = RAMBLUR_WINn_CTL_ADDR(window);
162 	uint32_t val = BIT(RAMBLUR_WINn_CTL_START_HW_INIT_SHFT);
163 
164 	out_dword_masked_ns(reg, mask, val, RAMBLUR_WINn_CTL_INI(window));
165 
166 	if (ramblur_version.minor > 0)
167 		return initialize_hardware_v3_x(window);
168 
169 	return initialize_hardware_v3_0(window);
170 }
171 
initialize(int window)172 static void initialize(int window)
173 {
174 	const uint32_t offset = 0U;
175 
176 	disable_sw_init_mode(window);
177 	disable(window);
178 	set_hw_init(window, offset);
179 	initialize_hardware(window);
180 }
181 
set_security(int window,uint32_t algo)182 static void set_security(int window, uint32_t algo)
183 {
184 	uint32_t reg = RAMBLUR_WINn_ALGORITHM_CONFIG_ADDR(window);
185 
186 	out_dword(reg, algo);
187 	readback_sync(reg, algo, UINT32_MAX, 0);
188 }
189 
get_size(int window)190 static uint32_t get_size(int window)
191 {
192 	uint32_t reg = RAMBLUR_WINn_SIZE_ADDR(window);
193 
194 	return in_dword_masked(reg, RAMBLUR_WINn_SIZE_RMSK);
195 }
196 
set_size(int window,size_t size)197 static void set_size(int window, size_t size)
198 {
199 	uint32_t reg = RAMBLUR_WINn_SIZE_ADDR(window);
200 	uint32_t win_size = get_size(window);
201 
202 	if (!win_size) {
203 		/* Initialize */
204 		out_dword(reg, (uint32_t)size);
205 		readback_sync(reg, size, RAMBLUR_WINn_SIZE_RMSK, 0);
206 	} else if (win_size < size) {
207 		/* We can not resize in this code path */
208 		panic("Can't increase pIMEM");
209 	} else {
210 		/* Requested fits what is already configured */
211 		IMSG("Ramblur pIMEM size reused");
212 	}
213 }
214 
configure_vault(int window,uintptr_t addr)215 static void configure_vault(int window, uintptr_t addr)
216 {
217 	uint32_t hi = (uint32_t)(addr >> 32);
218 	uint32_t lo = (uint32_t)addr;
219 	uint32_t reg = 0;
220 
221 	hi &= RAMBLUR_WINn_DATA_VAULT_ADDR_HI_RMSK;
222 	reg = RAMBLUR_WINn_DATA_VAULT_ADDR_HI_ADDR(window);
223 	out_dword(reg, hi);
224 	readback_sync(reg, hi, UINT32_MAX, 0);
225 
226 	lo &= RAMBLUR_WINn_DATA_VAULT_ADDR_LOW_RMSK;
227 	reg = RAMBLUR_WINn_DATA_VAULT_ADDR_LOW_ADDR(window);
228 	out_dword(reg, lo);
229 	readback_sync(reg, lo, UINT32_MAX, 0);
230 }
231 
get_hardware_version(uint32_t * major,uint32_t * minor,uint32_t * step)232 static void get_hardware_version(uint32_t *major, uint32_t *minor,
233 				 uint32_t *step)
234 {
235 	uint32_t val = in_dword(RAMBLUR_VERSION_ADDR);
236 
237 	*major = (val & RAMBLUR_VERSION_MAJOR_BMSK) >>
238 		RAMBLUR_VERSION_MAJOR_SHFT;
239 	*minor = (val & RAMBLUR_VERSION_MINOR_BMSK) >>
240 		RAMBLUR_VERSION_MINOR_SHFT;
241 	*step = (val & RAMBLUR_VERSION_STEP_BMSK) >>
242 		RAMBLUR_VERSION_STEP_SHFT;
243 }
244 
pre_initialize_3_0_0(int window)245 static void pre_initialize_3_0_0(int window)
246 {
247 	uint32_t regs[2] = {
248 		RAMBLUR_WINn_DATA_TXN_QSB_CTL_ADDR(window),
249 		RAMBLUR_WINn_OVERHEAD_TXN_QSB_CTL_ADDR(window),
250 	};
251 	uint32_t masks[2] = {
252 		RAMBLUR_WINn_DATA_TXN_QSB_CTL_AINNERCACHEABLE_BMSK,
253 		RAMBLUR_WINn_OVERHEAD_TXN_QSB_CTL_AINNERCACHEABLE_BMSK,
254 	};
255 	uint32_t inis[2] = {
256 		RAMBLUR_WINn_DATA_TXN_QSB_CTL_INI(window),
257 		RAMBLUR_WINn_OVERHEAD_TXN_QSB_CTL_INI(window),
258 	};
259 	uint32_t shift[2] = {
260 		RAMBLUR_WINn_DATA_TXN_QSB_CTL_AINNERCACHEABLE_SHFT,
261 		RAMBLUR_WINn_OVERHEAD_TXN_QSB_CTL_AINNERCACHEABLE_SHFT,
262 	};
263 
264 	for (int i = 0; i < 2; i++) {
265 		out_dword_masked_ns(regs[i], masks[i], 0x0, inis[i]);
266 		readback_sync(regs[i], 0, masks[i], shift[i]);
267 	}
268 }
269 
270 /* This function might not return (panic) */
initialize_window(int window,size_t size,uintptr_t vault)271 static TEE_Result initialize_window(int window, size_t size, uintptr_t vault)
272 {
273 	if (ramblur_version.major == 3 &&
274 	    ramblur_version.minor == 0 &&
275 	    ramblur_version.step == 0)
276 		pre_initialize_3_0_0(window);
277 
278 	configure_vault(window, vault);
279 	set_size(window, size);
280 	set_security(window, ANTIROLLBACK | INTEGRITY | CONFIDENTIALITY);
281 
282 	/* Wipes out the full window to 0x0 */
283 	initialize(window);
284 	enable(window);
285 
286 	return TEE_SUCCESS;
287 }
288 
289 /*
290  * Trusted Applications run from protected IMEM.
291  * If this region cannot be configured, abort the boot sequence.
292  */
qti_ramblur_pimem_init(void)293 static TEE_Result qti_ramblur_pimem_init(void)
294 {
295 	if (!core_mmu_add_mapping(MEM_AREA_IO_SEC, RAMBLUR_PIMEM_REG_BASE,
296 				  RAMBLUR_PIMEM_REG_SIZE))
297 		panic("Can't add Ramblur pIMEM");
298 
299 	ramblur_va = (vaddr_t)phys_to_virt(RAMBLUR_PIMEM_REG_BASE,
300 					   MEM_AREA_IO_SEC,
301 					   RAMBLUR_PIMEM_REG_SIZE);
302 	if (!ramblur_va)
303 		panic("Can't get Ramblur virtual");
304 
305 	get_hardware_version(&ramblur_version.major,
306 			     &ramblur_version.minor,
307 			     &ramblur_version.step);
308 
309 	DMSG("Ramblur pIMEM v%d.%d.%d (window=%d)",
310 	     ramblur_version.major,
311 	     ramblur_version.minor,
312 	     ramblur_version.step,
313 	     CFG_QCOM_RAMBLUR_TA_WINDOW_ID);
314 
315 	if (ramblur_version.major != 3)
316 		panic();
317 
318 	return initialize_window(CFG_QCOM_RAMBLUR_TA_WINDOW_ID,
319 				 RAMBLUR_PIMEM_VAULT_TA_SIZE,
320 				 RAMBLUR_PIMEM_VAULT_TA_BASE);
321 }
322 driver_init(qti_ramblur_pimem_init);
323