xref: /optee_os/core/drivers/aplic_priv.c (revision c3deb3d6f3b13d0e17fc9efe5880aec039e47594)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2021 Western Digital Corporation or its affiliates.
4  * Copyright (c) 2022 Ventana Micro Systems Inc.
5  * Copyright (c) 2025 Beijing Institute of Open Source Chip (BOSC)
6  *
7  * Authors:
8  *   Anup Patel <anup.patel@wdc.com>
9  *   Huang Borong <huangborong@bosc.ac.cn>
10  */
11 
12 #include <drivers/aplic_priv.h>
13 #include <drivers/imsic.h>
14 #include <dt-bindings/interrupt-controller/irq.h>
15 #include <encoding.h>
16 #include <io.h>
17 #include <kernel/dt.h>
18 #include <kernel/dt_driver.h>
19 #include <libfdt.h>
20 #include <tee_api_types.h>
21 #include <trace.h>
22 
23 static TEE_Result aplic_parse_fdt_node(const void *fdt, int nodeoff,
24 				       struct aplic_data *aplic)
25 {
26 	const fdt32_t *val = NULL;
27 	struct imsic_data imsic = { };
28 	int i = 0;
29 	int len = 0;
30 	int noff = -1;
31 	int rc = -1;
32 	paddr_t reg_addr = 0;
33 	size_t reg_size = 0;
34 	TEE_Result res = TEE_ERROR_GENERIC;
35 
36 	if (nodeoff < 0 || !aplic || !fdt)
37 		return TEE_ERROR_BAD_PARAMETERS;
38 
39 	rc = fdt_reg_info(fdt, nodeoff, &reg_addr, &reg_size);
40 	if (rc < 0 || !reg_addr || !reg_size)
41 		return TEE_ERROR_ITEM_NOT_FOUND;
42 	aplic->aplic_base = core_mmu_get_va(reg_addr, MEM_AREA_IO_SEC,
43 					    reg_size);
44 	if (!aplic->aplic_base)
45 		return TEE_ERROR_GENERIC;
46 	aplic->size = reg_size;
47 
48 	val = fdt_getprop(fdt, nodeoff, "riscv,num-sources", &len);
49 	if (len > 0)
50 		aplic->num_source = fdt32_to_cpu(*val);
51 
52 	val = fdt_getprop(fdt, nodeoff, "interrupts-extended", &len);
53 	if (val && (size_t)len >= (2 * sizeof(fdt32_t))) {
54 		len = len / sizeof(fdt32_t);
55 		for (i = 0; i < len; i += 2) {
56 			if (fdt32_to_cpu(val[i + 1]) == IRQ_M_EXT) {
57 				aplic->targets_mmode = true;
58 				break;
59 			}
60 		}
61 		aplic->num_idc = len / 2;
62 
63 		return TEE_SUCCESS;
64 	} else if (!val) {
65 		val = fdt_getprop(fdt, nodeoff, "msi-parent", &len);
66 		if (val && (size_t)len >= sizeof(fdt32_t)) {
67 			noff = fdt_node_offset_by_phandle(fdt,
68 							  fdt32_to_cpu(*val));
69 			if (noff < 0)
70 				return TEE_ERROR_ITEM_NOT_FOUND;
71 
72 			res = imisc_parse_fdt_node(fdt, noff, &imsic);
73 			if (res)
74 				return res;
75 
76 			aplic->targets_mmode = imsic.targets_mmode;
77 
78 			return TEE_SUCCESS;
79 		}
80 	}
81 	return TEE_ERROR_ITEM_NOT_FOUND;
82 }
83 
84 TEE_Result aplic_init_from_device_tree(struct aplic_data *aplic)
85 {
86 	void *fdt = NULL;
87 	int node = FDT_ERR_NOTFOUND;
88 	TEE_Result res = TEE_ERROR_GENERIC;
89 
90 	fdt = get_dt();
91 	if (!fdt) {
92 		EMSG("Unable to get DTB, APLIC init failed");
93 		return TEE_ERROR_ITEM_NOT_FOUND;
94 	}
95 
96 	/*
97 	 * Currently, only the S-level interrupt domain is considered.
98 	 * If the interrupt domain is M-level, continue traversing.
99 	 * If it is S-level, return directly.
100 	 */
101 	node = fdt_node_offset_by_compatible(fdt, -1, APLIC_COMPATIBLE);
102 	while (node != -FDT_ERR_NOTFOUND) {
103 		res = aplic_parse_fdt_node(fdt, node, aplic);
104 		if (res) {
105 			EMSG("Parse APLIC node failed");
106 			return res;
107 		}
108 
109 		if (!aplic->targets_mmode)
110 			return TEE_SUCCESS;
111 
112 		node = fdt_node_offset_by_compatible(fdt, node,
113 						     APLIC_COMPATIBLE);
114 	}
115 
116 	return TEE_ERROR_ITEM_NOT_FOUND;
117 }
118 
119 TEE_Result aplic_set_source_mode(struct aplic_data *aplic, uint32_t source,
120 				 uint32_t type)
121 {
122 	vaddr_t sourcecfg = 0;
123 	uint32_t sm = APLIC_SOURCECFG_SM_INACTIVE;
124 
125 	switch (type) {
126 	case IRQ_TYPE_NONE:
127 		sm = APLIC_SOURCECFG_SM_INACTIVE;
128 		break;
129 	case IRQ_TYPE_EDGE_RISING:
130 		sm = APLIC_SOURCECFG_SM_EDGE_RISE;
131 		break;
132 	case IRQ_TYPE_EDGE_FALLING:
133 		sm = APLIC_SOURCECFG_SM_EDGE_FALL;
134 		break;
135 	case IRQ_TYPE_LEVEL_HIGH:
136 		sm = APLIC_SOURCECFG_SM_LEVEL_HIGH;
137 		break;
138 	case IRQ_TYPE_LEVEL_LOW:
139 		sm = APLIC_SOURCECFG_SM_LEVEL_LOW;
140 		break;
141 	default:
142 		return TEE_ERROR_BAD_PARAMETERS;
143 	}
144 
145 	sourcecfg = aplic->aplic_base + APLIC_SOURCECFG_BASE +
146 				(source - 1) * sizeof(uint32_t);
147 	io_write32(sourcecfg, sm);
148 
149 	return TEE_SUCCESS;
150 }
151