1 /*
2  * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #include <assert.h>
7 
8 #include <common/debug.h>
9 #include <common/fdt_wrappers.h>
10 #include <libfdt.h>
11 #include <plat/arm/common/fconf_sec_intr_config.h>
12 
13 #define G0_INTR_NUM(i)		g0_intr_prop[3U * (i)]
14 #define G0_INTR_PRIORITY(i)	g0_intr_prop[3U * (i) + 1]
15 #define G0_INTR_CONFIG(i)	g0_intr_prop[3U * (i) + 2]
16 
17 #define G1S_INTR_NUM(i)		g1s_intr_prop[3U * (i)]
18 #define G1S_INTR_PRIORITY(i)	g1s_intr_prop[3U * (i) + 1]
19 #define G1S_INTR_CONFIG(i)	g1s_intr_prop[3U * (i) + 2]
20 
21 struct sec_intr_prop_t sec_intr_prop;
22 
print_intr_prop(interrupt_prop_t prop)23 static void print_intr_prop(interrupt_prop_t prop)
24 {
25 	VERBOSE("FCONF: Secure Interrupt NUM: %d, PRI: %d, TYPE: %d\n",
26 		prop.intr_num, prop.intr_pri, prop.intr_cfg);
27 }
28 
fconf_populate_sec_intr_config(uintptr_t config)29 int fconf_populate_sec_intr_config(uintptr_t config)
30 {
31 	int node, err;
32 	uint32_t g0_intr_count, g1s_intr_count;
33 	uint32_t g0_intr_prop[SEC_INT_COUNT_MAX * 3];
34 	uint32_t g1s_intr_prop[SEC_INT_COUNT_MAX * 3];
35 
36 	/* Necessary to work with libfdt APIs */
37 	const void *hw_config_dtb = (const void *)config;
38 
39 	node = fdt_node_offset_by_compatible(hw_config_dtb, -1,
40 						"arm,secure_interrupt_desc");
41 	if (node < 0) {
42 		ERROR("FCONF: Unable to locate node with %s compatible property\n",
43 						"arm,secure_interrupt_desc");
44 		return node;
45 	}
46 
47 	/* Read number of Group 0 interrupts specified by platform */
48 	err = fdt_read_uint32(hw_config_dtb, node, "g0_intr_cnt", &g0_intr_count);
49 	if (err < 0) {
50 		ERROR("FCONF: Could not locate g0s_intr_cnt property\n");
51 		return err;
52 	}
53 
54 	/* At least 1 Group 0 interrupt description has to be provided*/
55 	if (g0_intr_count < 1U) {
56 		ERROR("FCONF: Invalid number of Group 0 interrupts count specified\n");
57 		return -1;
58 	}
59 
60 	/* Read number of Group 1 secure interrupts specified by platform */
61 	err = fdt_read_uint32(hw_config_dtb, node, "g1s_intr_cnt",
62 				&g1s_intr_count);
63 	if (err < 0) {
64 		ERROR("FCONF: Could not locate g1s_intr_cnt property\n");
65 		return err;
66 	}
67 
68 	/* At least one Group 1 interrupt description has to be provided*/
69 	if (g1s_intr_count < 1U) {
70 		ERROR("FCONF: Invalid number of Group 1 secure interrupts count specified\n");
71 		return -1;
72 	}
73 
74 	/*
75 	 * Check if the total number of secure interrupts described are within
76 	 * the limit defined statically by the platform.
77 	 */
78 	if ((g0_intr_count + g1s_intr_count) > SEC_INT_COUNT_MAX) {
79 		ERROR("FCONF: Total number of secure interrupts exceed limit the of %d\n",
80 				SEC_INT_COUNT_MAX);
81 		return -1;
82 	}
83 
84 	sec_intr_prop.count = g0_intr_count + g1s_intr_count;
85 
86 	/* Read the Group 0 interrupt descriptors */
87 	err = fdt_read_uint32_array(hw_config_dtb, node, "g0_intr_desc",
88 				g0_intr_count * 3, g0_intr_prop);
89 	if (err < 0) {
90 		ERROR("FCONF: Read cell failed for 'g0s_intr_desc': %d\n", err);
91 		return err;
92 	}
93 
94 	/* Read the Group 1 secure interrupt descriptors */
95 	err = fdt_read_uint32_array(hw_config_dtb, node, "g1s_intr_desc",
96 				g1s_intr_count * 3, g1s_intr_prop);
97 	if (err < 0) {
98 		ERROR("FCONF: Read cell failed for 'g1s_intr_desc': %d\n", err);
99 		return err;
100 	}
101 
102 	/* Populate Group 0 interrupt descriptors into fconf based C struct */
103 	for (uint32_t i = 0; i < g0_intr_count; i++) {
104 		interrupt_prop_t sec_intr_property;
105 
106 		/* Secure Interrupt Group: INTR_GROUP0 i.e., 0x1 */
107 		sec_intr_property.intr_grp = 1;
108 		sec_intr_property.intr_num = G0_INTR_NUM(i);
109 		sec_intr_property.intr_pri = G0_INTR_PRIORITY(i);
110 		sec_intr_property.intr_cfg = G0_INTR_CONFIG(i);
111 		sec_intr_prop.descriptor[i] = sec_intr_property;
112 		print_intr_prop(sec_intr_property);
113 	}
114 
115 	/* Populate G1 secure interrupt descriptors into fconf based C struct */
116 	for (uint32_t i = 0; i < g1s_intr_count; i++) {
117 		interrupt_prop_t sec_intr_property;
118 
119 		/* Secure Interrupt Group: INTR_GROUP1S i.e., 0x0 */
120 		sec_intr_property.intr_grp = 0;
121 		sec_intr_property.intr_num = G1S_INTR_NUM(i);
122 		sec_intr_property.intr_pri = G1S_INTR_PRIORITY(i);
123 		sec_intr_property.intr_cfg = G1S_INTR_CONFIG(i);
124 		sec_intr_prop.descriptor[i + g0_intr_count] = sec_intr_property;
125 		print_intr_prop(sec_intr_property);
126 	}
127 
128 	return 0;
129 }
130 
131 FCONF_REGISTER_POPULATOR(HW_CONFIG, sec_intr_prop, fconf_populate_sec_intr_config);
132