1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2020-2023, 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
is_region_aligned(struct cmn700_rnsam_reg * rnsam,struct mod_cmn700_mem_region_map * mmap,enum sam_type sam_type)237 bool is_region_aligned(
238 struct cmn700_rnsam_reg *rnsam,
239 struct mod_cmn700_mem_region_map *mmap,
240 enum sam_type sam_type)
241 {
242 uint64_t lsb_addr_mask;
243
244 lsb_addr_mask = get_rnsam_lsb_addr_mask(rnsam, sam_type);
245 return ((mmap->base & lsb_addr_mask) | (mmap->size & lsb_addr_mask)) == 0;
246 }
247
is_non_hash_region_mapped(struct cmn700_rnsam_reg * rnsam,uint32_t region_io_count,struct mod_cmn700_mem_region_map * mmap,uint32_t * region_index)248 bool is_non_hash_region_mapped(
249 struct cmn700_rnsam_reg *rnsam,
250 uint32_t region_io_count,
251 struct mod_cmn700_mem_region_map *mmap,
252 uint32_t *region_index)
253 {
254 int idx;
255 unsigned int programmed_node_id;
256 uint32_t group;
257 uint32_t bit_pos;
258 volatile uint64_t *reg;
259 uint64_t lsb_addr_mask;
260
261 lsb_addr_mask =
262 get_rnsam_lsb_addr_mask(rnsam, SAM_TYPE_NON_HASH_MEM_REGION);
263
264 for (idx = region_io_count - 1; idx >= 0; idx--) {
265 reg = &rnsam->NON_HASH_MEM_REGION[idx];
266 if (mmap->base == (*reg & ~lsb_addr_mask)) {
267 group = idx / CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP;
268 bit_pos = CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRY_BITS_WIDTH *
269 (idx % CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP);
270 programmed_node_id =
271 (rnsam->NON_HASH_TGT_NODEID[group] >> bit_pos) &
272 CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK;
273 mmap->node_id &= CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK;
274
275 if (programmed_node_id == mmap->node_id) {
276 FWK_LOG_INFO(
277 MOD_NAME "Found region: %d mapped for Node: %u ",
278 idx,
279 mmap->node_id);
280 *region_index = idx;
281
282 return true;
283 } else {
284 FWK_LOG_ERR(
285 MOD_NAME
286 "Address: 0x%llx mapped to different node id:"
287 " %u than expected: %u\n",
288 mmap->base,
289 programmed_node_id,
290 mmap->node_id);
291 fwk_unexpected();
292 }
293 }
294 }
295
296 return false;
297 }
298
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)299 void configure_region(
300 void *rnsam_reg,
301 unsigned int region_idx,
302 uint64_t base,
303 uint64_t size,
304 enum sam_node_type node_type,
305 enum sam_type sam_type)
306 {
307 bool prog_start_and_end_addr;
308 uint64_t lsb_addr_mask;
309 uint64_t value;
310 struct cmn700_rnsam_reg *rnsam = rnsam_reg;
311 volatile uint64_t *reg;
312 volatile uint64_t *reg_cfg2;
313
314 fwk_assert(rnsam_reg);
315
316 if (sam_type == SAM_TYPE_NON_HASH_MEM_REGION) {
317 if (region_idx >= MAX_NON_HASH_MEM_COUNT) {
318 FWK_LOG_ERR(
319 MOD_NAME
320 "Region idx: %d should be less than max non hash region count "
321 "of %d",
322 region_idx,
323 MAX_NON_HASH_MEM_COUNT);
324 fwk_unexpected();
325 }
326
327 if (region_idx < NON_HASH_MEM_REG_COUNT) {
328 reg = &rnsam->NON_HASH_MEM_REGION[region_idx];
329 reg_cfg2 = &rnsam->NON_HASH_MEM_REGION_CFG2[region_idx];
330 } else {
331 reg = &rnsam->NON_HASH_MEM_REGION_GRP2
332 [region_idx - NON_HASH_MEM_REG_COUNT];
333 reg_cfg2 = &rnsam->NON_HASH_MEM_REGION_CFG2_GRP2
334 [region_idx - NON_HASH_MEM_REG_COUNT];
335 }
336 } else if (sam_type == SAM_TYPE_SYS_CACHE_GRP_REGION) {
337 if (region_idx >= MAX_SCG_COUNT) {
338 FWK_LOG_ERR(
339 MOD_NAME
340 "Region idx: %d should be less then max SCG region count of %d",
341 region_idx,
342 MAX_SCG_COUNT);
343 fwk_unexpected();
344 }
345 reg = &rnsam->SYS_CACHE_GRP_REGION[region_idx];
346 reg_cfg2 = &rnsam->HASHED_TGT_GRP_CFG2_REGION[region_idx];
347 } else {
348 FWK_LOG_ERR(MOD_NAME "Unexpected sam_type!");
349 fwk_unexpected();
350 return;
351 }
352
353 /* Check if the start and end address has to be programmed */
354 prog_start_and_end_addr = (sam_type == SAM_TYPE_NON_HASH_MEM_REGION) ?
355 get_rnsam_nonhash_range_comp_en_mode(rnsam) :
356 get_rnsam_htg_range_comp_en_mode(rnsam);
357
358 if ((!prog_start_and_end_addr) && ((base % size) != 0)) {
359 FWK_LOG_ERR(
360 MOD_NAME "Base: 0x%" PRIx64 " should align with Size: 0x%" PRIx64,
361 base,
362 size);
363 fwk_unexpected();
364 }
365
366 /* Get the LSB mask from LSB bit position defining minimum region size */
367 lsb_addr_mask = get_rnsam_lsb_addr_mask(rnsam, sam_type);
368
369 value = CMN700_RNSAM_REGION_ENTRY_VALID;
370 value |= node_type << CMN700_RNSAM_REGION_ENTRY_TYPE_POS;
371
372 if (prog_start_and_end_addr) {
373 value |= (base & ~lsb_addr_mask);
374 *reg = value;
375 *reg_cfg2 = (base + size - 1) & ~lsb_addr_mask;
376 } else {
377 value |= sam_encode_region_size(size)
378 << CMN700_RNSAM_REGION_ENTRY_SIZE_POS;
379 value |= (base / SAM_GRANULARITY) << CMN700_RNSAM_REGION_ENTRY_BASE_POS;
380 *reg = value;
381 }
382 }
383
384 static const char *const type_to_name[] = {
385 [NODE_TYPE_INVALID] = "<Invalid>",
386 [NODE_TYPE_DVM] = "DVM",
387 [NODE_TYPE_CFG] = "CFG",
388 [NODE_TYPE_DTC] = "DTC",
389 [NODE_TYPE_HN_I] = "HN-I",
390 [NODE_TYPE_HN_F] = "HN-F",
391 [NODE_TYPE_XP] = "XP",
392 [NODE_TYPE_SBSX] = "SBSX",
393 [NODE_TYPE_MPAM_S] = "MPAM-S",
394 [NODE_TYPE_MPAM_NS] = "MPAM-NS",
395 [NODE_TYPE_RN_I] = "RN-I",
396 [NODE_TYPE_RN_D] = "RN-D",
397 [NODE_TYPE_RN_SAM] = "RN-SAM",
398 [NODE_TYPE_HN_P] = "HN-P",
399 };
400
401 static const char *const type_to_name_cml[] = {
402 [NODE_TYPE_CXRA - NODE_TYPE_CML_BASE] = "CXRA",
403 [NODE_TYPE_CXHA - NODE_TYPE_CML_BASE] = "CXHA",
404 [NODE_TYPE_CXLA - NODE_TYPE_CML_BASE] = "CXLA",
405 [NODE_TYPE_CCRA - NODE_TYPE_CML_BASE] = "CCRA",
406 [NODE_TYPE_CCHA - NODE_TYPE_CML_BASE] = "CCHA",
407 [NODE_TYPE_CCLA - NODE_TYPE_CML_BASE] = "CCLA",
408 };
409
get_node_type_name(enum node_type node_type)410 const char *get_node_type_name(enum node_type node_type)
411 {
412 /* Base node IDs */
413 if (node_type <= NODE_TYPE_HN_P)
414 return type_to_name[node_type];
415
416 /* CML node IDs */
417 if ((node_type >= NODE_TYPE_CML_BASE) && (node_type <= NODE_TYPE_CCLA))
418 return type_to_name_cml[node_type - NODE_TYPE_CML_BASE];
419
420 /* Invalid node IDs */
421 return type_to_name[NODE_TYPE_INVALID];
422 }
423
get_node_pos_x(void * node_base)424 unsigned int get_node_pos_x(void *node_base)
425 {
426 struct node_header *node = node_base;
427 return (get_node_id(node) >> (CMN700_NODE_ID_Y_POS + encoding_bits)) &
428 mask_bits;
429 }
430
get_node_pos_y(void * node_base)431 unsigned int get_node_pos_y(void *node_base)
432 {
433 struct node_header *node = node_base;
434 return (get_node_id(node) >> CMN700_NODE_ID_Y_POS) & mask_bits;
435 }
436
set_encoding_and_masking_bits(const struct mod_cmn700_config * config)437 void set_encoding_and_masking_bits(const struct mod_cmn700_config *config)
438 {
439 unsigned int mesh_size_x;
440 unsigned int mesh_size_y;
441
442 mesh_size_x = config->mesh_size_x;
443 mesh_size_y = config->mesh_size_y;
444
445 /*
446 * Determine the number of bits used to represent each node coordinate based
447 * on the mesh size as per CMN700 specification.
448 */
449 if ((mesh_size_x > 8) || (mesh_size_y > 8)) {
450 encoding_bits = 4;
451 } else {
452 encoding_bits = ((mesh_size_x > 4) || (mesh_size_y > 4)) ? 3 : 2;
453 }
454
455 /* Extract node coordinates from the node identifier */
456
457 mask_bits = (1 << encoding_bits) - 1;
458 }
459