1 /*
2 * Copyright (c) 2026, Qualcomm Technologies, Inc. and/or its subsidiaries.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <string.h>
8
9 #include <arch_helpers.h>
10 #include <common/debug.h>
11 #include <lib/mmio.h>
12 #include <vmidmt.h>
13 #include <vmidmt_hal.h>
14 #include <vmidmt_internal.h>
15 #include <vmidmt_target_hwio.h>
16
17 #include <qti_interrupt_svc.h>
18
19 #define VMIDMT_INSTANCE(xx) ((enum hal_vmidmt_instance)(xx).table)
20
21 /* Maximum value for VMIDMT error status bit position.
22 * Error status register is 32 bit so position ranges
23 * from 0 to 31
24 */
25 #define VMIDMT_ERR_BIT_POS_MAX 31
26
27 extern struct hal_vmidmt_port_map g_vmidmt_info_cfg[];
28
29 extern const uint8_t g_vmidmt_info_cfg_count;
30 extern const struct vmidmt_cfg g_vmidmt_cfg[];
31 extern const struct vmidmt_map g_vmid_map[];
32 extern const uint32_t g_vmidmt_cfg_count;
33 extern const uint32_t g_vmid_map_count;
34
35 extern struct vmidmt_err_pos_to_hal_map
36 vmidmt_err_pos_to_hal_map[ACC_VMIDMT_ERR_INT_STATUS_REG_NUM]
37 [ACC_VMIDMT_ERR_NUM_PER_REG];
38
39 /* No access permissions to VMIDMT config registers to any non secure entity */
40 struct hal_vmidmt_access_config acc_ctl = { { 0xFFFFFFFF }, { 0 } };
41
42 /* Interrupt contexts to distigunish type of error in VMIDMT error ISR */
43 enum vmidmt_err_id { CLT_SEC = 0, CLT_NONSEC, CFG_SEC, CFG_NONSEC };
44
45 static struct vmidmt_err_ctx {
46 enum vmidmt_err_id id;
47 uint32_t addr;
48 uint32_t mask;
49 uint32_t reg;
50 } vmidmt_err[] = {
51 [CLT_SEC] = {
52 .id = CLT_SEC,
53 .addr = HWIO_TCSR_SS_VMIDMT_CLIENT_SEC_INTR_ADDR,
54 .mask = HWIO_TCSR_SS_VMIDMT_CLIENT_SEC_INTR_RMSK,
55 .reg = 0,
56 },
57 [CLT_NONSEC] = {
58 .id = CLT_NONSEC,
59 .addr = HWIO_TCSR_SS_VMIDMT_CLIENT_NON_SEC_INTR_ADDR,
60 .mask = HWIO_TCSR_SS_VMIDMT_CLIENT_NON_SEC_INTR_RMSK,
61 .reg = 0,
62 },
63 [CFG_SEC] = {
64 .id = CFG_SEC,
65 .addr = HWIO_TCSR_SS_VMIDMT_CFG_SEC_INTR_ADDR,
66 .mask = HWIO_TCSR_SS_VMIDMT_CFG_SEC_INTR_RMSK,
67 .reg = 0,
68 },
69 [CFG_NONSEC] = {
70 .id = CFG_NONSEC,
71 .addr = HWIO_TCSR_SS_VMIDMT_CFG_NON_SEC_INTR_ADDR,
72 .mask = HWIO_TCSR_SS_VMIDMT_CFG_NON_SEC_INTR_RMSK,
73 .reg = 0,
74 },
75 };
76
get_info_cfg(uint8_t port)77 static struct hal_vmidmt_port_map *get_info_cfg(uint8_t port)
78 {
79 struct hal_vmidmt_port_map *p = g_vmidmt_info_cfg;
80
81 for (size_t i = 0; i < g_vmidmt_info_cfg_count; i++, p++) {
82 if (p->port != port)
83 continue;
84
85 return p;
86 }
87
88 return NULL;
89 }
90
map_vmid_internal(enum hal_vmidmt_instance master,uint32_t index,const uint32_t * list,uint8_t len,uint32_t vmid,uint32_t mem_type,bool secure)91 static int map_vmid_internal(enum hal_vmidmt_instance master, uint32_t index,
92 const uint32_t *list, uint8_t len, uint32_t vmid,
93 uint32_t mem_type, bool secure)
94 {
95 struct hal_vmidmt_context_config ctx_cfg = { 0 };
96 struct hal_vmidmt_bus_attrib bus_attribs = { 0 };
97 struct hal_vmidmt_port_map *cfg;
98 enum hal_vmidmt_status rc;
99
100 cfg = get_info_cfg(master);
101 if (!cfg)
102 return -1;
103
104 if (mem_type != ACC_VMIDMT_MEMTYPE_DEFAULT) {
105 bus_attribs.e_mtcfg = HAL_VMIDMT_MTCFG_MEMATTR;
106 bus_attribs.mem_attr = mem_type;
107 }
108
109 if (secure)
110 bus_attribs.e_nscfg = HAL_VMIDMT_NSCFG_SECURE;
111
112 ctx_cfg.p_bus_attrib = &bus_attribs;
113 ctx_cfg.u_vmid = vmid;
114
115 rc = vmidmt_hal_config_ctx_ext(&cfg->vmidmt_info, index, list, len,
116 &ctx_cfg);
117 if (rc != HAL_VMIDMT_NO_ERROR)
118 return -1;
119
120 vmidmt_hal_enable_client(&cfg->vmidmt_info, true);
121 vmidmt_hal_enable_client(&cfg->vmidmt_info, false);
122
123 return 0;
124 }
125
configure_vmids(void)126 static int32_t configure_vmids(void)
127 {
128 int ret = 0;
129 uint32_t i;
130
131 for (i = 0; i < g_vmid_map_count; i++) {
132 if (!g_vmid_map[i].static_cfg)
133 continue;
134
135 ret = map_vmid_internal(
136 VMIDMT_INSTANCE(g_vmid_map[i]), g_vmid_map[i].index,
137 g_vmid_map[i].sid_list, g_vmid_map[i].num_sids,
138 g_vmid_map[i].vmid, g_vmid_map[i].memattr, false);
139 if (ret)
140 goto error;
141 }
142
143 return 0;
144 error:
145 ERROR("VMIDMT Config ERROR for g_vmid_map[%d]\n", i);
146 return ret;
147 }
148
config_options_per_master(int index)149 static int config_options_per_master(int index)
150 {
151 struct hal_vmidmt_default_vmid_config vmid_cfg = {
152 .b_vmid_private_namespace_enable = false,
153 .bypass_vmid = ACC_VMID_NOACCESS,
154 .p_access_control = &acc_ctl,
155 .p_bypass_bus_attrib = NULL,
156 .p_bypass_aux_config = NULL,
157 };
158 struct hal_vmidmt_default_secure_vmid_config secure_cfg = {
159 .secure_extensions = HAL_VMIDMT_SECURE_EXT_DEFAULT,
160 .b_glb_addr_space_restricted_acc_enable = 0,
161 .p_default_secure_config = &vmid_cfg,
162 };
163 struct hal_vmidmt_bus_attrib bus_attribs;
164 struct hal_vmidmt_port_map *cfg;
165 enum hal_vmidmt_status rc;
166
167 cfg = get_info_cfg(VMIDMT_INSTANCE(g_vmidmt_cfg[index]));
168 if (!cfg)
169 return -1;
170
171 memset(&bus_attribs, 0, sizeof(bus_attribs));
172
173 if (VMIDMT_INSTANCE(g_vmidmt_cfg[index]) == HAL_VMIDMT_DEHR) {
174 bus_attribs.e_nscfg = HAL_VMIDMT_NSCFG_SECURE;
175 vmid_cfg.p_bypass_bus_attrib = &bus_attribs;
176 vmid_cfg.bypass_vmid = ACC_VMID_NOACCESS;
177 }
178
179 rc = vmidmt_hal_init(&cfg->vmidmt_info, &secure_cfg, NULL, NULL);
180 if (rc != HAL_VMIDMT_NO_ERROR)
181 return -1;
182
183 rc = vmidmt_hal_config_ssdt(&cfg->vmidmt_info,
184 g_vmidmt_cfg[index].ssd_table,
185 g_vmidmt_cfg[index].ssd_table_num_elements);
186 if (rc != HAL_VMIDMT_NO_ERROR)
187 WARN("Vmidmt SSDT configuration failed");
188
189 vmidmt_hal_cfg_err(&cfg->vmidmt_info, false,
190 g_vmidmt_cfg[index].err_opt);
191
192 vmidmt_hal_cfg_err(&cfg->vmidmt_info, true,
193 g_vmidmt_cfg[index].err_opt);
194
195 return 0;
196 }
197
configure_options(void)198 static int32_t configure_options(void)
199 {
200 const struct vmidmt_cfg *p = g_vmidmt_cfg;
201 int ret = 0;
202
203 for (size_t i = 0; i < g_vmidmt_cfg_count; i++, p++) {
204 if (!p->static_cfg)
205 continue;
206
207 ret = config_options_per_master(i);
208 if (ret)
209 return ret;
210 }
211
212 return 0;
213 }
214
log_error(enum hal_vmidmt_instance vmidmt)215 static void log_error(enum hal_vmidmt_instance vmidmt)
216 {
217 struct hal_vmidmt_port_map *cfg = NULL;
218 struct hal_vmidmt_error error = { 0 };
219
220 cfg = get_info_cfg(vmidmt);
221 if (!cfg) {
222 WARN("Unknown Port: 0x%X\n", vmidmt);
223 return;
224 }
225
226 if (!vmidmt_hal_is_error(&cfg->vmidmt_info, true)) {
227 WARN("VMIDMT ERROR: VMIDMT %d discarded error\n", vmidmt);
228 return;
229 }
230
231 vmidmt_hal_get_error(&cfg->vmidmt_info, true, &error);
232
233 ERROR("Error Flags: 0x%X\n", error.u_error_flags);
234 ERROR("Bus Flags: 0x%X\n", error.u_bus_flags);
235 ERROR("SSD Idx: 0x%X SID: 0x%X\n", error.u_ssd_index, error.u_sid);
236 ERROR("MID: 0x%X AVMID: 0x%X\n", error.u_master_id, error.u_avmid);
237 ERROR("ATID: 0x%X ABID: 0x%X APID: 0x%X\n", error.u_atid, error.u_abid,
238 error.u_apid);
239 ERROR("Phys Addr: 0x%X 0x%X\n", error.u_physical_address_upper32,
240 error.u_physical_address_lower32);
241
242 vmidmt_hal_clear_error(&cfg->vmidmt_info, true);
243 }
244
log_errors(uint32_t reg,uint32_t pos)245 static void log_errors(uint32_t reg, uint32_t pos)
246 {
247 const struct vmidmt_err_pos_to_hal_map *row =
248 vmidmt_err_pos_to_hal_map[reg];
249
250 for (size_t i = 0; i < ACC_VMIDMT_ERR_NUM_PER_REG; i++, row++) {
251 if (row->bit_pos != pos)
252 continue;
253
254 if (row->vmidmt != HAL_VMIDMT_COUNT)
255 log_error(row->vmidmt);
256
257 break;
258 }
259 }
260
error_handler(uint32_t int_num,void * ctx)261 static void *error_handler(uint32_t int_num, void *ctx)
262 {
263 struct vmidmt_err_ctx *err_ctx = (struct vmidmt_err_ctx *)ctx;
264 uint32_t err = mmio_read_32(err_ctx->addr) & err_ctx->mask;
265
266 if (err == 0U)
267 return ctx;
268
269 ERROR("VMIDMT INT_REG%d: 0x%08X", err_ctx->reg, err);
270
271 for (uint32_t bit = 0U; bit <= VMIDMT_ERR_BIT_POS_MAX; bit++) {
272 if (err & BIT(bit))
273 log_errors(err_ctx->reg, bit);
274 }
275
276 return ctx;
277 }
278
register_interrupts(void)279 static int32_t register_interrupts(void)
280 {
281 const uint32_t enable = 0xFFFFFFFF;
282 int ret = 0;
283
284 ret = qti_interrupt_svc_register(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC,
285 error_handler, &vmidmt_err[CLT_SEC]);
286 if (ret)
287 return ret;
288
289 ret = qti_interrupt_svc_register(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC,
290 error_handler,
291 &vmidmt_err[CLT_NONSEC]);
292 if (ret)
293 goto error3;
294
295 ret = qti_interrupt_svc_register(QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC,
296 error_handler, &vmidmt_err[CFG_SEC]);
297 if (ret)
298 goto error2;
299
300 ret = qti_interrupt_svc_register(QTISECLIB_INT_ID_VMIDMT_ERR_CFG_NONSEC,
301 error_handler,
302 &vmidmt_err[CFG_NONSEC]);
303 if (ret)
304 goto error1;
305
306 mmio_write_32(HWIO_TCSR_SS_VMIDMT_CFG_SEC_INTR_ENABLE_ADDR, enable);
307 mmio_write_32(HWIO_TCSR_SS_VMIDMT_CFG_NON_SEC_INTR_ENABLE_ADDR, enable);
308 mmio_write_32(HWIO_TCSR_SS_VMIDMT_CLIENT_SEC_INTR_ENABLE_ADDR, enable);
309 mmio_write_32(HWIO_TCSR_SS_VMIDMT_CLIENT_NON_SEC_INTR_ENABLE_ADDR,
310 enable);
311
312 return 0;
313
314 error1:
315 qti_interrupt_svc_unregister(QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC);
316 error2:
317 qti_interrupt_svc_unregister(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC);
318 error3:
319 qti_interrupt_svc_unregister(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC);
320
321 return -1;
322 }
323
vmidmt_configure(void)324 int vmidmt_configure(void)
325 {
326 int rc;
327
328 rc = configure_options();
329 if (rc)
330 return ACC_ERR_VMIDMT_CFG_FAIL;
331
332 rc = configure_vmids();
333 if (rc)
334 return ACC_ERR_VMIDMT_CFG_FAIL;
335
336 rc = register_interrupts();
337 if (rc)
338 return ACC_ERR_VMIDMT_CFG_FAIL;
339
340 return 0;
341 }
342