1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <cmn_booker.h>
9
10 #include <fwk_assert.h>
11 #include <fwk_math.h>
12
13 #include <stddef.h>
14
15 /*
16 * Encoding bits size of the X and Y position in the Node info value.
17 * If X and Y dimension are less than 4, encoding bits size will be 2.
18 * If X and Y dimension are between 5 and 8, encoding bits size will be 3.
19 */
20 static unsigned int encoding_bits;
21 static unsigned int mask_bits;
22
get_node_child_count(void * node_base)23 unsigned int get_node_child_count(void *node_base)
24 {
25 struct node_header *node = node_base;
26 return node->CHILD_INFO & CMN_BOOKER_CHILD_INFO_COUNT;
27 }
28
get_node_type(void * node_base)29 enum node_type get_node_type(void *node_base)
30 {
31 struct node_header *node = node_base;
32 return (enum node_type)(node->NODE_INFO & CMN_BOOKER_NODE_INFO_TYPE);
33 }
34
get_node_id(void * node_base)35 unsigned int get_node_id(void *node_base)
36 {
37 struct node_header *node = node_base;
38 return (node->NODE_INFO & CMN_BOOKER_NODE_INFO_ID) >>
39 CMN_BOOKER_NODE_INFO_ID_POS;
40 }
41
get_node_logical_id(void * node_base)42 unsigned int get_node_logical_id(void *node_base)
43 {
44 struct node_header *node = node_base;
45 return (node->NODE_INFO & CMN_BOOKER_NODE_INFO_LOGICAL_ID) >>
46 CMN_BOOKER_NODE_INFO_LOGICAL_ID_POS;
47 }
48
get_child_node(uintptr_t base,void * node_base,unsigned int child_index)49 void *get_child_node(uintptr_t base, void *node_base, unsigned int child_index)
50 {
51 struct node_header *node = node_base;
52 uint32_t child_pointer;
53 unsigned int offset;
54 void *child_node;
55
56 child_pointer = node->CHILD_POINTER[child_index];
57 offset = child_pointer & CMN_BOOKER_CHILD_POINTER_OFFSET;
58
59 child_node = (void *)(base + offset);
60 return child_node;
61 }
62
get_child_node_id(void * node_base,unsigned int child_index)63 unsigned int get_child_node_id(void *node_base,
64 unsigned int child_index)
65 {
66 struct node_header *node = node_base;
67 uint32_t node_pointer;
68 unsigned int node_id;
69
70 node_pointer = (node->CHILD_POINTER[child_index] &
71 CMN_BOOKER_CHILD_POINTER_EXT_NODE_POINTER) >>
72 CMN_BOOKER_CHILD_POINTER_EXT_NODE_POINTER_POS;
73
74 /*
75 * For mesh widths using 2 bits each for X,Y encoding:
76 * NodeID[1:0] = DeviceID[3:2]
77 * NodeID[2] = DeviceID[0]
78 * NodeID[4:3] = NODE POINTER[7:6]
79 * NodeID[6:5] = NODE POINTER[9:8]
80 *
81 * For mesh widths using 3 bits each for X,Y encoding:
82 * NodeID[1:0] = DeviceID[3:2]
83 * NodeID[2] = DeviceID[0]
84 * NodeID[5:3] = NODE POINTER[8:6]
85 * NodeID[8:6] = NODE POINTER[11:9]
86 */
87 node_id = (((node_pointer >> 6) & 0xff) << 3) |
88 ((node_pointer & 0x1) << 2) |
89 ((node_pointer >> 2) & 0x3);
90
91 return node_id;
92 }
93
is_child_external(void * node_base,unsigned int child_index)94 bool is_child_external(void *node_base, unsigned int child_index)
95 {
96 struct node_header *node = node_base;
97 return !!(node->CHILD_POINTER[child_index] & (1U << 31));
98 }
99
get_port_number(unsigned int child_node_id)100 bool get_port_number(unsigned int child_node_id)
101 {
102 return (child_node_id >> CMN_BOOKER_NODE_ID_PORT_POS) &
103 CMN_BOOKER_NODE_ID_PORT_MASK;
104 }
105
get_device_type(void * mxp_base,bool port)106 unsigned int get_device_type(void *mxp_base, bool port)
107 {
108 struct cmn_booker_mxp_reg *mxp = mxp_base;
109 return mxp->PORT_CONNECT_INFO[port] &
110 CMN_BOOKER_MXP_PORT_CONNECT_INFO_DEVICE_TYPE_MASK;
111 }
112
sam_encode_region_size(uint64_t size)113 uint64_t sam_encode_region_size(uint64_t size)
114 {
115 uint64_t blocks;
116 uint64_t result;
117
118 /* Size must be a multiple of SAM_GRANULARITY */
119 fwk_assert((size % SAM_GRANULARITY) == 0);
120
121 /* Size also must be a power of two */
122 fwk_assert((size & (size - 1)) == 0);
123
124 blocks = size / SAM_GRANULARITY;
125 result = fwk_math_log2(blocks);
126
127 return result;
128 }
129
configure_region(volatile uint64_t * reg,uint64_t base,uint64_t size,enum sam_node_type node_type)130 void configure_region(volatile uint64_t *reg, uint64_t base, uint64_t size,
131 enum sam_node_type node_type)
132 {
133 uint64_t value;
134
135 fwk_assert(reg != NULL);
136 fwk_assert((base % size) == 0);
137
138 value = CMN_BOOKER_RNSAM_REGION_ENTRY_VALID;
139 value |= node_type << CMN_BOOKER_RNSAM_REGION_ENTRY_TYPE_POS;
140 value |= sam_encode_region_size(size) <<
141 CMN_BOOKER_RNSAM_REGION_ENTRY_SIZE_POS;
142 value |= (base / SAM_GRANULARITY) << CMN_BOOKER_RNSAM_REGION_ENTRY_BASE_POS;
143
144 *reg = value;
145 }
146
147 static const char * const type_to_name[] = {
148 [NODE_TYPE_INVALID] = "<Invalid>",
149 [NODE_TYPE_DVM] = "DVM",
150 [NODE_TYPE_CFG] = "CFG",
151 [NODE_TYPE_DTC] = "DTC",
152 [NODE_TYPE_HN_I] = "HN-I",
153 [NODE_TYPE_HN_F] = "HN-F",
154 [NODE_TYPE_XP] = "XP",
155 [NODE_TYPE_SBSX] = "SBSX",
156 [NODE_TYPE_MPAM_S] = "MPAM-S",
157 [NODE_TYPE_MPAM_NS] = "MPAM-NS",
158 [NODE_TYPE_RN_I] = "RN-I",
159 [NODE_TYPE_RN_D] = "RN-D",
160 [NODE_TYPE_RN_SAM] = "RN-SAM",
161 [NODE_TYPE_MTU] = "MTU",
162 };
163
164 static const char * const type_to_name_cml[] = {
165 [NODE_TYPE_CXRA - NODE_TYPE_CML_BASE] = "CXRA",
166 [NODE_TYPE_CXHA - NODE_TYPE_CML_BASE] = "CXHA",
167 [NODE_TYPE_CXLA - NODE_TYPE_CML_BASE] = "CXLA",
168
169 };
170
get_node_type_name(enum node_type node_type)171 const char *get_node_type_name(enum node_type node_type)
172 {
173 /* Base node IDs */
174 if (node_type <= NODE_TYPE_MTU)
175 return type_to_name[node_type];
176
177 /* CML node IDs */
178 if ((node_type >= NODE_TYPE_CML_BASE) &&
179 (node_type <= NODE_TYPE_CXLA))
180 return type_to_name_cml[node_type - NODE_TYPE_CML_BASE];
181
182 /* Invalid node IDs */
183 return type_to_name[NODE_TYPE_INVALID];
184 }
185
get_node_pos_x(void * node_base)186 unsigned int get_node_pos_x(void *node_base)
187 {
188 struct node_header *node = node_base;
189 return (get_node_id(node) >> (CMN_BOOKER_NODE_ID_Y_POS + encoding_bits)) &
190 mask_bits;
191 }
192
get_node_pos_y(void * node_base)193 unsigned int get_node_pos_y(void *node_base)
194 {
195 struct node_header *node = node_base;
196 return (get_node_id(node) >> CMN_BOOKER_NODE_ID_Y_POS) & mask_bits;
197 }
198
get_root_node(uintptr_t base,unsigned int hnd_node_id,unsigned int mesh_size_x,unsigned int mesh_size_y,unsigned int ports_per_xp)199 struct cmn_booker_cfgm_reg *get_root_node(
200 uintptr_t base,
201 unsigned int hnd_node_id,
202 unsigned int mesh_size_x,
203 unsigned int mesh_size_y,
204 unsigned int ports_per_xp)
205 {
206 unsigned int node_pos_x;
207 unsigned int node_pos_y;
208 unsigned int node_port;
209 uintptr_t offset;
210
211 /*
212 * Determine the number of bits used to represent each node coordinate based
213 * on the mesh size as per CMN_BOOKER specification.
214 */
215 encoding_bits = ((mesh_size_x > 4) || (mesh_size_y > 4)) ? 3 : 2;
216
217 /* Extract node coordinates from the node identifier */
218 mask_bits = (1 << encoding_bits) - 1;
219 node_pos_y = (hnd_node_id >> CMN_BOOKER_NODE_ID_Y_POS) & mask_bits;
220 node_pos_x = (hnd_node_id >> (CMN_BOOKER_NODE_ID_Y_POS + encoding_bits)) &
221 mask_bits;
222 node_port = (hnd_node_id >> CMN_BOOKER_NODE_ID_PORT_POS) &
223 CMN_BOOKER_NODE_ID_PORT_MASK;
224
225 /* Calculate node address offset */
226 if (ports_per_xp > 4) {
227 // Single XP configuration, upto 6 device ports allowed
228 offset = ((node_port & 0x3) << CMN_BOOKER_ROOT_NODE_OFFSET_PORT_POS);
229 } else if (ports_per_xp > 2) {
230 // XPs which have more than 2 device ports
231 offset = (((node_port) >> 1) << CMN_BOOKER_ROOT_NODE_OFFSET_PORT_POS);
232 } else {
233 offset = (node_port << CMN_BOOKER_ROOT_NODE_OFFSET_PORT_POS);
234 }
235 /* Calculate node address offset */
236 offset = (node_pos_y << CMN_BOOKER_ROOT_NODE_OFFSET_Y_POS) |
237 (node_pos_x << (CMN_BOOKER_ROOT_NODE_OFFSET_Y_POS + encoding_bits)) |
238 offset;
239
240 return (struct cmn_booker_cfgm_reg *)(base + offset);
241 }
242