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
aplic_parse_fdt_node(const void * fdt,int nodeoff,struct aplic_data * aplic)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, ®_addr, ®_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
aplic_init_from_device_tree(struct aplic_data * aplic)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
aplic_set_source_mode(struct aplic_data * aplic,uint32_t source,uint32_t type)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