1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <cmn700.h>
9
10 #include <fwk_assert.h>
11 #include <fwk_log.h>
12 #include <fwk_math.h>
13
14 #include <inttypes.h>
15
16 #define MOD_NAME "[CMN700] "
17
18 /*
19 * Encoding bits size of the X and Y position in the Node info value.
20 * If X and Y dimension are less than 4, encoding bits size will be 2.
21 * If X and Y dimension are between 5 and 8, encoding bits size will be 3.
22 */
23 static unsigned int encoding_bits;
24 static unsigned int mask_bits;
25
26 static const char *const cmn700_rev_to_name[] = {
27 [CMN700_PERIPH_ID_2_REV_R0_P0] = "r0p0",
28 [CMN700_PERIPH_ID_2_REV_R1_P0] = "r1p0",
29 [CMN700_PERIPH_ID_2_REV_R1_P1] = "r1p1",
30 [CMN700_PERIPH_ID_2_REV_R2_P0] = "r2p0",
31 [CMN700_PERIPH_ID_UNKNOWN_REV] = "Unknown!",
32 };
33
get_node_device_port_count(void * node_base)34 unsigned int get_node_device_port_count(void *node_base)
35 {
36 struct node_header *node = node_base;
37 return (node->NODE_INFO & CMN700_MXP_NODE_INFO_NUM_DEVICE_PORT_MASK) >>
38 CMN700_MXP_NODE_INFO_NUM_DEVICE_PORT_POS;
39 }
40
get_node_child_count(void * node_base)41 unsigned int get_node_child_count(void *node_base)
42 {
43 struct node_header *node = node_base;
44 return node->CHILD_INFO & CMN700_CHILD_INFO_COUNT;
45 }
46
get_node_type(void * node_base)47 enum node_type get_node_type(void *node_base)
48 {
49 struct node_header *node = node_base;
50 return (enum node_type)(node->NODE_INFO & CMN700_NODE_INFO_TYPE);
51 }
52
get_node_id(void * node_base)53 unsigned int get_node_id(void *node_base)
54 {
55 struct node_header *node = node_base;
56 return (node->NODE_INFO & CMN700_NODE_INFO_ID) >> CMN700_NODE_INFO_ID_POS;
57 }
58
get_node_logical_id(void * node_base)59 unsigned int get_node_logical_id(void *node_base)
60 {
61 struct node_header *node = node_base;
62 return (node->NODE_INFO & CMN700_NODE_INFO_LOGICAL_ID) >>
63 CMN700_NODE_INFO_LOGICAL_ID_POS;
64 }
65
get_child_node(uintptr_t base,void * node_base,unsigned int child_index)66 void *get_child_node(uintptr_t base, void *node_base, unsigned int child_index)
67 {
68 struct node_header *node = node_base;
69 uint32_t child_pointer;
70 unsigned int offset;
71 void *child_node;
72
73 child_pointer = node->CHILD_POINTER[child_index];
74 offset = child_pointer & CMN700_CHILD_POINTER_OFFSET;
75
76 child_node = (void *)(base + offset);
77 return child_node;
78 }
79
get_child_node_id(void * node_base,unsigned int child_index)80 unsigned int get_child_node_id(void *node_base, unsigned int child_index)
81 {
82 struct node_header *node = node_base;
83 uint32_t node_pointer;
84 unsigned int node_id;
85
86 node_pointer = (node->CHILD_POINTER[child_index] &
87 CMN700_CHILD_POINTER_EXT_NODE_POINTER) >>
88 CMN700_CHILD_POINTER_EXT_NODE_POINTER_POS;
89
90 /*
91 * For mesh widths using 2 bits each for X,Y encoding:
92 * NodeID[1:0] = DeviceID[3:2]
93 * NodeID[2] = DeviceID[0]
94 * NodeID[4:3] = NODE POINTER[7:6]
95 * NodeID[6:5] = NODE POINTER[9:8]
96 *
97 * For mesh widths using 3 bits each for X,Y encoding:
98 * NodeID[1:0] = DeviceID[3:2]
99 * NodeID[2] = DeviceID[0]
100 * NodeID[5:3] = NODE POINTER[8:6]
101 * NodeID[8:6] = NODE POINTER[11:9]
102 */
103 node_id = (((node_pointer >> 6) & 0xff) << 3) |
104 ((node_pointer & 0x1) << 2) | ((node_pointer >> 2) & 0x3);
105
106 return node_id;
107 }
108
get_cmn700_revision(struct cmn700_cfgm_reg * root)109 unsigned int get_cmn700_revision(struct cmn700_cfgm_reg *root)
110 {
111 return (root->PERIPH_ID[1] & CMN700_PERIPH_ID_2_MASK) >>
112 CMN700_PERIPH_ID_2_REV_POS;
113 }
114
get_cmn700_revision_name(struct cmn700_cfgm_reg * root)115 const char *get_cmn700_revision_name(struct cmn700_cfgm_reg *root)
116 {
117 unsigned int revision;
118
119 revision = get_cmn700_revision(root);
120 if (revision > CMN700_PERIPH_ID_UNKNOWN_REV)
121 revision = CMN700_PERIPH_ID_UNKNOWN_REV;
122
123 return cmn700_rev_to_name[revision];
124 }
125
is_child_external(void * node_base,unsigned int child_index)126 bool is_child_external(void *node_base, unsigned int child_index)
127 {
128 struct node_header *node = node_base;
129 return !!(node->CHILD_POINTER[child_index] & (1U << 31));
130 }
131
get_port_number(unsigned int child_node_id,unsigned int xp_port_cnt)132 unsigned int get_port_number(
133 unsigned int child_node_id,
134 unsigned int xp_port_cnt)
135 {
136 if (xp_port_cnt == 2) {
137 return (child_node_id >> CMN700_NODE_ID_PORT_POS) &
138 CMN700_NODE_ID_PORT_MASK;
139 } else {
140 /* For port counts 3 and 4 */
141 return (child_node_id >> CMN700_MULTI_PORTS_NODE_ID_PORT_POS) &
142 CMN700_MULTI_PORTS_NODE_ID_PORT_MASK;
143 }
144 }
145
get_device_type(void * mxp_base,int port)146 unsigned int get_device_type(void *mxp_base, int port)
147 {
148 struct cmn700_mxp_reg *mxp = mxp_base;
149 return mxp->PORT_CONNECT_INFO[port] &
150 CMN700_MXP_PORT_CONNECT_INFO_DEVICE_TYPE_MASK;
151 }
152
is_cal_connected(void * mxp_base,bool port)153 bool is_cal_connected(void *mxp_base, bool port)
154 {
155 struct cmn700_mxp_reg *mxp = mxp_base;
156 return (mxp->PORT_CONNECT_INFO[port] &
157 CMN700_MXP_PORT_CONNECT_INFO_CAL_CONNECTED_MASK) >>
158 CMN700_MXP_PORT_CONNECT_INFO_CAL_CONNECTED_POS;
159 }
160
is_device_type_rnf(void * mxp_base,bool port)161 bool is_device_type_rnf(void *mxp_base, bool port)
162 {
163 return (
164 (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHIB_ESAM) ||
165 (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHIC_ESAM) ||
166 (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHID_ESAM) ||
167 (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHIE_ESAM));
168 }
169
get_rnsam_htg_rcomp_lsb_bit_pos(void * rnsam_reg)170 static unsigned int get_rnsam_htg_rcomp_lsb_bit_pos(void *rnsam_reg)
171 {
172 struct cmn700_rnsam_reg *rnsam = rnsam_reg;
173 return (
174 rnsam->UNIT_INFO[1] & CMN700_RNSAM_UNIT_INFO_HTG_RCOMP_LSB_PARAM_MASK);
175 }
176
get_rnsam_nonhash_rcomp_lsb_bit_pos(void * rnsam_reg)177 static unsigned int get_rnsam_nonhash_rcomp_lsb_bit_pos(void *rnsam_reg)
178 {
179 struct cmn700_rnsam_reg *rnsam = rnsam_reg;
180 return (rnsam->UNIT_INFO[1] &
181 CMN700_RNSAM_UNIT_INFO_NONHASH_RCOMP_LSB_PARAM_MASK) >>
182 CMN700_RNSAM_UNIT_INFO_NONHASH_RCOMP_LSB_PARAM_POS;
183 }
184
get_rnsam_lsb_addr_mask(void * rnsam_reg,enum sam_type sam_type)185 static uint64_t get_rnsam_lsb_addr_mask(void *rnsam_reg, enum sam_type sam_type)
186 {
187 uint64_t lsb_bit_pos;
188 struct cmn700_rnsam_reg *rnsam = rnsam_reg;
189
190 lsb_bit_pos = (sam_type == SAM_TYPE_NON_HASH_MEM_REGION) ?
191 get_rnsam_nonhash_rcomp_lsb_bit_pos(rnsam) :
192 get_rnsam_htg_rcomp_lsb_bit_pos(rnsam);
193
194 return (1 << lsb_bit_pos) - 1;
195 }
196
get_rnsam_nonhash_range_comp_en_mode(void * rnsam_reg)197 bool get_rnsam_nonhash_range_comp_en_mode(void *rnsam_reg)
198 {
199 struct cmn700_rnsam_reg *rnsam = rnsam_reg;
200 return (rnsam->UNIT_INFO[0] &
201 CMN700_RNSAM_UNIT_INFO_NONHASH_RANGE_COMP_EN_MASK) >>
202 CMN700_RNSAM_UNIT_INFO_NONHASH_RANGE_COMP_EN_POS;
203 }
204
get_rnsam_htg_range_comp_en_mode(void * rnsam_reg)205 bool get_rnsam_htg_range_comp_en_mode(void *rnsam_reg)
206 {
207 struct cmn700_rnsam_reg *rnsam = rnsam_reg;
208 return (rnsam->UNIT_INFO[0] &
209 CMN700_RNSAM_UNIT_INFO_HTG_RANGE_COMP_EN_MASK) >>
210 CMN700_RNSAM_UNIT_INFO_HTG_RANGE_COMP_EN_POS;
211 }
212
get_hnsam_range_comp_en_mode(void * hnf_reg)213 bool get_hnsam_range_comp_en_mode(void *hnf_reg)
214 {
215 struct cmn700_hnf_reg *hnf = hnf_reg;
216 return (hnf->UNIT_INFO[1] & CMN700_HNF_UNIT_INFO_HNSAM_RCOMP_EN_MASK) >>
217 CMN700_HNF_UNIT_INFO_HNSAM_RCOMP_EN_POS;
218 }
219
sam_encode_region_size(uint64_t size)220 uint64_t sam_encode_region_size(uint64_t size)
221 {
222 uint64_t blocks;
223 uint64_t result;
224
225 /* Size must be a multiple of SAM_GRANULARITY */
226 fwk_assert((size % SAM_GRANULARITY) == 0);
227
228 /* Size also must be a power of two */
229 fwk_assert((size & (size - 1)) == 0);
230
231 blocks = size / SAM_GRANULARITY;
232 result = fwk_math_log2(blocks);
233
234 return result;
235 }
236
configure_region(void * rnsam_reg,unsigned int region_idx,uint64_t base,uint64_t size,enum sam_node_type node_type,enum sam_type sam_type)237 void configure_region(
238 void *rnsam_reg,
239 unsigned int region_idx,
240 uint64_t base,
241 uint64_t size,
242 enum sam_node_type node_type,
243 enum sam_type sam_type)
244 {
245 bool prog_start_and_end_addr;
246 uint64_t lsb_addr_mask;
247 uint64_t value;
248 struct cmn700_rnsam_reg *rnsam = rnsam_reg;
249 volatile uint64_t *reg;
250 volatile uint64_t *reg_cfg2;
251
252 fwk_assert(rnsam_reg);
253
254 if (sam_type == SAM_TYPE_NON_HASH_MEM_REGION) {
255 if (region_idx >= MAX_NON_HASH_MEM_COUNT) {
256 FWK_LOG_ERR(
257 MOD_NAME
258 "Region idx: %d should be less than max non hash region count "
259 "of %d",
260 region_idx,
261 MAX_NON_HASH_MEM_COUNT);
262 fwk_unexpected();
263 }
264
265 if (region_idx < NON_HASH_MEM_REG_COUNT) {
266 reg = &rnsam->NON_HASH_MEM_REGION[region_idx];
267 reg_cfg2 = &rnsam->NON_HASH_MEM_REGION_CFG2[region_idx];
268 } else {
269 reg = &rnsam->NON_HASH_MEM_REGION_GRP2
270 [region_idx - NON_HASH_MEM_REG_COUNT];
271 reg_cfg2 = &rnsam->NON_HASH_MEM_REGION_CFG2_GRP2
272 [region_idx - NON_HASH_MEM_REG_COUNT];
273 }
274 } else if (sam_type == SAM_TYPE_SYS_CACHE_GRP_REGION) {
275 if (region_idx >= MAX_SCG_COUNT) {
276 FWK_LOG_ERR(
277 MOD_NAME
278 "Region idx: %d should be less then max SCG region count of %d",
279 region_idx,
280 MAX_SCG_COUNT);
281 fwk_unexpected();
282 }
283 reg = &rnsam->SYS_CACHE_GRP_REGION[region_idx];
284 reg_cfg2 = &rnsam->HASHED_TGT_GRP_CFG2_REGION[region_idx];
285 } else {
286 FWK_LOG_ERR(MOD_NAME "Unexpected sam_type!");
287 fwk_unexpected();
288 return;
289 }
290
291 /* Check if the start and end address has to be programmed */
292 prog_start_and_end_addr = (sam_type == SAM_TYPE_NON_HASH_MEM_REGION) ?
293 get_rnsam_nonhash_range_comp_en_mode(rnsam) :
294 get_rnsam_htg_range_comp_en_mode(rnsam);
295
296 if ((!prog_start_and_end_addr) && ((base % size) != 0)) {
297 FWK_LOG_ERR(
298 MOD_NAME "Base: 0x%" PRIx64 " should align with Size: 0x%" PRIx64,
299 base,
300 size);
301 fwk_unexpected();
302 }
303
304 /* Get the LSB mask from LSB bit position defining minimum region size */
305 lsb_addr_mask = get_rnsam_lsb_addr_mask(rnsam, sam_type);
306
307 value = CMN700_RNSAM_REGION_ENTRY_VALID;
308 value |= node_type << CMN700_RNSAM_REGION_ENTRY_TYPE_POS;
309
310 if (prog_start_and_end_addr) {
311 value |= (base & ~lsb_addr_mask);
312 *reg = value;
313 *reg_cfg2 = (base + size - 1) & ~lsb_addr_mask;
314 } else {
315 value |= sam_encode_region_size(size)
316 << CMN700_RNSAM_REGION_ENTRY_SIZE_POS;
317 value |= (base / SAM_GRANULARITY) << CMN700_RNSAM_REGION_ENTRY_BASE_POS;
318 *reg = value;
319 }
320 }
321
322 static const char *const type_to_name[] = {
323 [NODE_TYPE_INVALID] = "<Invalid>",
324 [NODE_TYPE_DVM] = "DVM",
325 [NODE_TYPE_CFG] = "CFG",
326 [NODE_TYPE_DTC] = "DTC",
327 [NODE_TYPE_HN_I] = "HN-I",
328 [NODE_TYPE_HN_F] = "HN-F",
329 [NODE_TYPE_XP] = "XP",
330 [NODE_TYPE_SBSX] = "SBSX",
331 [NODE_TYPE_MPAM_S] = "MPAM-S",
332 [NODE_TYPE_MPAM_NS] = "MPAM-NS",
333 [NODE_TYPE_RN_I] = "RN-I",
334 [NODE_TYPE_RN_D] = "RN-D",
335 [NODE_TYPE_RN_SAM] = "RN-SAM",
336 [NODE_TYPE_HN_P] = "HN-P",
337 };
338
339 static const char *const type_to_name_cml[] = {
340 [NODE_TYPE_CXRA - NODE_TYPE_CML_BASE] = "CXRA",
341 [NODE_TYPE_CXHA - NODE_TYPE_CML_BASE] = "CXHA",
342 [NODE_TYPE_CXLA - NODE_TYPE_CML_BASE] = "CXLA",
343 [NODE_TYPE_CCRA - NODE_TYPE_CML_BASE] = "CCRA",
344 [NODE_TYPE_CCHA - NODE_TYPE_CML_BASE] = "CCHA",
345 [NODE_TYPE_CCLA - NODE_TYPE_CML_BASE] = "CCLA",
346 };
347
get_node_type_name(enum node_type node_type)348 const char *get_node_type_name(enum node_type node_type)
349 {
350 /* Base node IDs */
351 if (node_type <= NODE_TYPE_HN_P)
352 return type_to_name[node_type];
353
354 /* CML node IDs */
355 if ((node_type >= NODE_TYPE_CML_BASE) && (node_type <= NODE_TYPE_CCLA))
356 return type_to_name_cml[node_type - NODE_TYPE_CML_BASE];
357
358 /* Invalid node IDs */
359 return type_to_name[NODE_TYPE_INVALID];
360 }
361
get_node_pos_x(void * node_base)362 unsigned int get_node_pos_x(void *node_base)
363 {
364 struct node_header *node = node_base;
365 return (get_node_id(node) >> (CMN700_NODE_ID_Y_POS + encoding_bits)) &
366 mask_bits;
367 }
368
get_node_pos_y(void * node_base)369 unsigned int get_node_pos_y(void *node_base)
370 {
371 struct node_header *node = node_base;
372 return (get_node_id(node) >> CMN700_NODE_ID_Y_POS) & mask_bits;
373 }
374
set_encoding_and_masking_bits(const struct mod_cmn700_config * config)375 void set_encoding_and_masking_bits(const struct mod_cmn700_config *config)
376 {
377 unsigned int mesh_size_x;
378 unsigned int mesh_size_y;
379
380 mesh_size_x = config->mesh_size_x;
381 mesh_size_y = config->mesh_size_y;
382
383 /*
384 * Determine the number of bits used to represent each node coordinate based
385 * on the mesh size as per CMN700 specification.
386 */
387 if ((mesh_size_x > 8) || (mesh_size_y > 8)) {
388 encoding_bits = 4;
389 } else {
390 encoding_bits = ((mesh_size_x > 4) || (mesh_size_y > 4)) ? 3 : 2;
391 }
392
393 /* Extract node coordinates from the node identifier */
394
395 mask_bits = (1 << encoding_bits) - 1;
396 }
397