xref: /rk3399_ARM-atf/drivers/qti/accesscontrol/vmidmt/vmidmt.c (revision 5de3e03dbd7c2da6748e294f423c83f9582f459c)
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