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