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 #include <cmn700_ccg.h>
10
11 #include <internal/cmn700_ctx.h>
12
13 #include <mod_clock.h>
14 #include <mod_cmn700.h>
15 #include <mod_system_info.h>
16 #include <mod_timer.h>
17
18 #include <fwk_assert.h>
19 #include <fwk_event.h>
20 #include <fwk_id.h>
21 #include <fwk_log.h>
22 #include <fwk_math.h>
23 #include <fwk_mm.h>
24 #include <fwk_module.h>
25 #include <fwk_module_idx.h>
26 #include <fwk_notification.h>
27 #include <fwk_status.h>
28
29 #include <inttypes.h>
30 #include <stdint.h>
31
32 #define MOD_NAME "[CMN700] "
33
34 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_INFO
35 static const char *const mmap_type_name[] = {
36 [MOD_CMN700_MEM_REGION_TYPE_IO] = "I/O",
37 [MOD_CMN700_MEM_REGION_TYPE_SYSCACHE] = "System Cache",
38 [MOD_CMN700_REGION_TYPE_SYSCACHE_SUB] = "Sub-System Cache",
39 [MOD_CMN700_REGION_TYPE_CCG] = "CCG",
40 };
41 #else
42 static const char *const mmap_type_name[] = { "" };
43 #endif
44
45 static struct cmn700_device_ctx *ctx;
46
47 /* Chip Information */
48 static struct mod_system_info_get_info_api *system_info_api;
49 static const struct mod_system_info *system_info;
50
51 /* Initialize default for multi-chip mode and chip-id */
52 static unsigned int chip_id;
53 static bool multi_chip_mode;
54
55 static struct node_pos *hnf_node_pos;
56
cmn700_hnf_cache_group_count(size_t hnf_count)57 static inline size_t cmn700_hnf_cache_group_count(size_t hnf_count)
58 {
59 return (hnf_count + CMN700_HNF_CACHE_GROUP_ENTRIES_PER_GROUP - 1) /
60 CMN700_HNF_CACHE_GROUP_ENTRIES_PER_GROUP;
61 }
62
process_node_hnf(struct cmn700_hnf_reg * hnf)63 static void process_node_hnf(struct cmn700_hnf_reg *hnf)
64 {
65 unsigned int logical_id;
66 unsigned int region_idx;
67 unsigned int region_sub_count = 0;
68 unsigned int hnf_count_per_cluster;
69 unsigned int hnf_cluster_index;
70 unsigned int snf_count_per_cluster;
71 unsigned int snf_idx_in_cluster;
72 unsigned int snf_table_idx;
73 unsigned int top_address_bit0, top_address_bit1;
74 enum mod_cmn700_hnf_to_snf_mem_strip_mode sn_mode;
75 uint64_t base;
76 uint64_t sam_control;
77 const struct mod_cmn700_mem_region_map *region;
78 const struct mod_cmn700_config *config = ctx->config;
79 const struct mod_cmn700_hierarchical_hashing *hier_hash_cfg;
80
81 logical_id = get_node_logical_id(hnf);
82
83 hier_hash_cfg = &(config->hierarchical_hashing_config);
84
85 /* SN mode with Hierarchical Hashing */
86 if (config->hierarchical_hashing_enable && hier_hash_cfg->sn_mode) {
87 sn_mode = hier_hash_cfg->sn_mode;
88 top_address_bit0 = hier_hash_cfg->top_address_bit0;
89 top_address_bit1 = hier_hash_cfg->top_address_bit1;
90
91 snf_count_per_cluster =
92 config->snf_count / hier_hash_cfg->hnf_cluster_count;
93
94 /*
95 * For now, 3-SN mode (three SN-Fs per cluster) is supported, other
96 * modes are not tested.
97 */
98 fwk_assert(snf_count_per_cluster == 3);
99
100 /* Number of HN-Fs in a cluster */
101 hnf_count_per_cluster =
102 ctx->hnf_count / hier_hash_cfg->hnf_cluster_count;
103
104 /* Choose the cluster idx based on the HN-Fs LDID value */
105 hnf_cluster_index = logical_id / hnf_count_per_cluster;
106
107 if (top_address_bit1 <= top_address_bit0) {
108 FWK_LOG_ERR(
109 MOD_NAME
110 "top_address_bit1: %d should be greater than top_address_bit0: "
111 "%d",
112 top_address_bit1,
113 top_address_bit0);
114 fwk_unexpected();
115 }
116
117 sam_control =
118 ((UINT64_C(1) << CMN700_HNF_SAM_CONTROL_SN_MODE_POS(sn_mode)) |
119 ((uint64_t)top_address_bit0
120 << CMN700_HNF_SAM_CONTROL_TOP_ADDR_BIT0_POS) |
121 ((uint64_t)top_address_bit1
122 << CMN700_HNF_SAM_CONTROL_TOP_ADDR_BIT1_POS));
123
124 for (snf_idx_in_cluster = 0; snf_idx_in_cluster < snf_count_per_cluster;
125 snf_idx_in_cluster++) {
126 snf_table_idx = (hnf_cluster_index * snf_count_per_cluster) +
127 snf_idx_in_cluster;
128 sam_control |=
129 ((uint64_t)config->snf_table[snf_table_idx]
130 << CMN700_HNF_SAM_CONTROL_SN_NODE_ID_POS(snf_idx_in_cluster));
131 }
132
133 hnf->SAM_CONTROL = sam_control;
134 } else {
135 fwk_assert(logical_id < config->snf_count);
136
137 /* Set target node */
138 hnf->SAM_CONTROL = config->snf_table[logical_id];
139 }
140
141 /*
142 * Map sub-regions to this HN-F node
143 */
144 for (region_idx = 0; region_idx < config->mmap_count; region_idx++) {
145 region = &config->mmap_table[region_idx];
146
147 /* Skip non sub-regions */
148 if (region->type != MOD_CMN700_REGION_TYPE_SYSCACHE_SUB)
149 continue;
150
151 /* Offset the base with chip address space base on chip-id */
152 base =
153 ((uint64_t)(ctx->config->chip_addr_space * chip_id)) + region->base;
154
155 /* Configure sub-region entry */
156 if (get_hnsam_range_comp_en_mode(hnf)) {
157 hnf->SAM_MEMREGION[region_sub_count] = region->node_id |
158 ((base / SAM_GRANULARITY)
159 << CMN700_HNF_SAM_MEMREGION_BASE_POS) |
160 CMN700_HNF_SAM_MEMREGION_VALID;
161 hnf->SAM_MEMREGION_END_ADDR[region_sub_count] =
162 ((base + region->size - 1));
163 } else {
164 hnf->SAM_MEMREGION[region_sub_count] = region->node_id |
165 (sam_encode_region_size(region->size)
166 << CMN700_HNF_SAM_MEMREGION_SIZE_POS) |
167 ((base / SAM_GRANULARITY)
168 << CMN700_HNF_SAM_MEMREGION_BASE_POS) |
169 CMN700_HNF_SAM_MEMREGION_VALID;
170 }
171 region_sub_count++;
172 }
173
174 /* Configure the system cache RAM PPU */
175 hnf->PPU_PWPR = CMN700_PPU_PWPR_POLICY_ON | CMN700_PPU_PWPR_OPMODE_FAM |
176 CMN700_PPU_PWPR_DYN_EN;
177 }
178
179 /*
180 * Discover the topology of the interconnect and identify the number of:
181 * - External RN-SAM nodes
182 * - Internal RN-SAM nodes
183 * - HN-F nodes (cache)
184 */
cmn700_discovery(void)185 static int cmn700_discovery(void)
186 {
187 unsigned int ccg_ra_reg_count;
188 unsigned int ccg_ha_reg_count;
189 unsigned int ccla_reg_count;
190 unsigned int cxg_ra_reg_count;
191 unsigned int cxg_ha_reg_count;
192 unsigned int cxla_reg_count;
193 unsigned int node_count;
194 unsigned int node_idx;
195 unsigned int xp_count;
196 unsigned int xp_idx;
197 unsigned int xp_port;
198 struct cmn700_mxp_reg *xp;
199 struct node_header *node;
200 const struct mod_cmn700_config *config = ctx->config;
201
202 ccg_ra_reg_count = 0;
203 ccg_ha_reg_count = 0;
204 ccla_reg_count = 0;
205 cxg_ra_reg_count = 0;
206 cxg_ha_reg_count = 0;
207 cxla_reg_count = 0;
208
209 set_encoding_and_masking_bits(config);
210
211 FWK_LOG_INFO(
212 MOD_NAME "CMN-700 revision: %s", get_cmn700_revision_name(ctx->root));
213 FWK_LOG_INFO(MOD_NAME "Starting discovery...");
214 FWK_LOG_DEBUG(MOD_NAME "Rootnode Base address: 0x%x", (uintptr_t)ctx->root);
215
216 fwk_assert(get_node_type(ctx->root) == NODE_TYPE_CFG);
217
218 /* Traverse cross points (XP) */
219 xp_count = get_node_child_count(ctx->root);
220 for (xp_idx = 0; xp_idx < xp_count; xp_idx++) {
221 xp = get_child_node(config->base, ctx->root, xp_idx);
222 fwk_assert(get_node_type(xp) == NODE_TYPE_XP);
223
224 FWK_LOG_INFO(
225 MOD_NAME "XP (%d, %d) ID:%d, LID:%d",
226 get_node_pos_x(xp),
227 get_node_pos_y(xp),
228 get_node_id(xp),
229 get_node_logical_id(xp));
230
231 /* Traverse nodes */
232 node_count = get_node_child_count(xp);
233 for (node_idx = 0; node_idx < node_count; node_idx++) {
234 node = get_child_node(config->base, xp, node_idx);
235
236 if (is_child_external(xp, node_idx)) { /* External nodes */
237 xp_port = get_port_number(
238 get_child_node_id(xp, node_idx),
239 get_node_device_port_count(xp));
240
241 /*
242 * If the device type is CXRH, CXHA, or CXRA, then the external
243 * child node is CXLA as every CXRH, CXHA, or CXRA node has a
244 * corresponding external CXLA node.
245 */
246 if ((get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) ||
247 (get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) ||
248 (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) {
249 cxla_reg_count++;
250 FWK_LOG_INFO(
251 MOD_NAME " Found CXLA at node ID: %d",
252 get_child_node_id(xp, node_idx));
253 } else { /* External RN-SAM Node */
254 ctx->external_rnsam_count++;
255 FWK_LOG_INFO(
256 MOD_NAME " Found external node ID: %d addr: %p",
257 get_child_node_id(xp, node_idx),
258 xp);
259 }
260 } else { /* Internal nodes */
261 switch (get_node_type(node)) {
262 case NODE_TYPE_HN_F:
263 if (ctx->hnf_count >= MAX_HNF_COUNT) {
264 FWK_LOG_INFO(
265 MOD_NAME " hnf count %d >= max limit (%d)",
266 ctx->hnf_count,
267 MAX_HNF_COUNT);
268 return FWK_E_DATA;
269 }
270 ctx->hnf_count++;
271 break;
272
273 case NODE_TYPE_RN_SAM:
274 ctx->internal_rnsam_count++;
275
276 /*
277 * RN-F nodes does not have node type identifier and hence
278 * the count cannot be determined using the node type id.
279 * Alternatively, check if the device type connected to the
280 * Crosspoint (XP) is one of the RNF types and determine the
281 * RN-F count (if CAL connected RN-F, double the count).
282 */
283 xp_port = get_port_number(
284 get_node_id(node), get_node_device_port_count(xp));
285
286 if (is_device_type_rnf(xp, xp_port)) {
287 if (is_cal_connected(xp, xp_port)) {
288 ctx->rnf_count += 2;
289 FWK_LOG_INFO(
290 MOD_NAME
291 " RN-F (CAL connected) found at port: %d",
292 xp_port);
293 } else {
294 ctx->rnf_count++;
295 FWK_LOG_INFO(
296 MOD_NAME " RN-F found at port: %d", xp_port);
297 }
298 }
299 break;
300
301 case NODE_TYPE_RN_D:
302 if ((ctx->rnd_count) >= MAX_RND_COUNT) {
303 FWK_LOG_ERR(
304 MOD_NAME " rnd count %d >= max limit (%d)\n",
305 ctx->rnd_count,
306 MAX_RND_COUNT);
307 return FWK_E_DATA;
308 }
309 ctx->rnd_count++;
310 break;
311
312 case NODE_TYPE_RN_I:
313 if ((ctx->rni_count) >= MAX_RNI_COUNT) {
314 FWK_LOG_ERR(
315 MOD_NAME " rni count %d >= max limit (%d)\n",
316 ctx->rni_count,
317 MAX_RNI_COUNT);
318 return FWK_E_DATA;
319 }
320 ctx->rni_count++;
321 break;
322
323 case NODE_TYPE_CCRA:
324 ccg_ra_reg_count++;
325 break;
326
327 case NODE_TYPE_CCHA:
328 ccg_ha_reg_count++;
329 break;
330
331 case NODE_TYPE_CCLA:
332 ccla_reg_count++;
333 break;
334
335 case NODE_TYPE_CXRA:
336 cxg_ra_reg_count++;
337 break;
338
339 case NODE_TYPE_CXHA:
340 cxg_ha_reg_count++;
341 break;
342
343 /* CXLA should not be an internal node */
344 case NODE_TYPE_CXLA:
345 FWK_LOG_ERR(MOD_NAME
346 "CXLA node should not be internal node, "
347 "discovery failed");
348 return FWK_E_DEVICE;
349 break;
350
351 default:
352 /* Nothing to be done for other node types */
353 break;
354 }
355
356 FWK_LOG_INFO(
357 MOD_NAME " %s ID:%d, LID:%d",
358 get_node_type_name(get_node_type(node)),
359 get_node_id(node),
360 get_node_logical_id(node));
361 }
362 }
363 }
364
365 /* When CAL is present, the number of HN-Fs must be even. */
366 if ((ctx->hnf_count % 2 != 0) && (config->hnf_cal_mode == true)) {
367 FWK_LOG_ERR(
368 MOD_NAME "hnf count: %d should be even when CAL mode is set",
369 ctx->hnf_count);
370 return FWK_E_DATA;
371 }
372
373 ctx->ccg_node_count = ccg_ra_reg_count;
374
375 if (ctx->rnf_count > MAX_RNF_COUNT) {
376 FWK_LOG_ERR(
377 MOD_NAME "rnf count %d > max limit (%d)\n",
378 ctx->rnf_count,
379 MAX_RNF_COUNT);
380 return FWK_E_RANGE;
381 }
382
383 FWK_LOG_INFO(
384 MOD_NAME "Total internal RN-SAM nodes: %d", ctx->internal_rnsam_count);
385 FWK_LOG_INFO(
386 MOD_NAME "Total external RN-SAM nodes: %d", ctx->external_rnsam_count);
387 FWK_LOG_INFO(MOD_NAME "Total HN-F nodes: %d", ctx->hnf_count);
388 FWK_LOG_INFO(MOD_NAME "Total RN-D nodes: %d\n", ctx->rnd_count);
389 FWK_LOG_INFO(MOD_NAME "Total RN-F nodes: %d\n", ctx->rnf_count);
390 FWK_LOG_INFO(MOD_NAME "Total RN-I nodes: %d\n", ctx->rni_count);
391 FWK_LOG_INFO(
392 MOD_NAME "Total CCIX Request Agent nodes: %d", cxg_ra_reg_count);
393 FWK_LOG_INFO(MOD_NAME "Total CCIX Home Agent nodes: %d", cxg_ha_reg_count);
394 FWK_LOG_INFO(MOD_NAME "Total CCIX Link Agent nodes: %d", cxla_reg_count);
395 FWK_LOG_INFO(
396 MOD_NAME "Total CCG Request Agent nodes: %d", ccg_ra_reg_count);
397 FWK_LOG_INFO(MOD_NAME "Total CCG Home Agent nodes: %d", ccg_ha_reg_count);
398 FWK_LOG_INFO(MOD_NAME "Total CCG Link Agent nodes: %d", ccla_reg_count);
399
400 return FWK_SUCCESS;
401 }
402
cmn700_configure(void)403 static void cmn700_configure(void)
404 {
405 unsigned int logical_id;
406 unsigned int node_count;
407 unsigned int ldid;
408 unsigned int node_id;
409 unsigned int node_idx;
410 unsigned int xp_count;
411 unsigned int xp_idx;
412 unsigned int irnsam_entry;
413 unsigned int xrnsam_entry;
414 unsigned int xp_port;
415 void *node;
416 struct cmn700_mxp_reg *xp;
417 const struct mod_cmn700_config *config = ctx->config;
418
419 fwk_assert(get_node_type(ctx->root) == NODE_TYPE_CFG);
420
421 irnsam_entry = 0;
422 xrnsam_entry = 0;
423
424 /* Traverse cross points (XP) */
425 xp_count = get_node_child_count(ctx->root);
426 for (xp_idx = 0; xp_idx < xp_count; xp_idx++) {
427 xp = get_child_node(config->base, ctx->root, xp_idx);
428 fwk_assert(get_node_type(xp) == NODE_TYPE_XP);
429
430 /* Traverse nodes */
431 node_count = get_node_child_count(xp);
432 for (node_idx = 0; node_idx < node_count; node_idx++) {
433 node = get_child_node(config->base, xp, node_idx);
434 xp_port = get_port_number(
435 get_child_node_id(xp, node_idx),
436 get_node_device_port_count(xp));
437 if (is_child_external(xp, node_idx)) {
438 node_id = get_child_node_id(xp, node_idx);
439
440 if (!(get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) &&
441 !(get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) &&
442 !(get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) {
443 fwk_assert(xrnsam_entry < ctx->external_rnsam_count);
444
445 ctx->external_rnsam_table[xrnsam_entry].node_id = node_id;
446 ctx->external_rnsam_table[xrnsam_entry].node = node;
447
448 xrnsam_entry++;
449 }
450 } else {
451 enum node_type node_type = get_node_type(node);
452 node_id = get_node_id(node);
453 if (node_type == NODE_TYPE_RN_SAM) {
454 fwk_assert(irnsam_entry < ctx->internal_rnsam_count);
455
456 ctx->internal_rnsam_table[irnsam_entry] = node;
457
458 irnsam_entry++;
459 } else if (node_type == NODE_TYPE_CCRA) {
460 ldid = get_node_logical_id(node);
461 fwk_assert(ldid < ctx->ccg_node_count);
462
463 /* Use ldid as index of the ccg_ra table */
464 ctx->ccg_ra_reg_table[ldid].node_id = node_id;
465 ctx->ccg_ra_reg_table[ldid].ccg_ra_reg =
466 (struct cmn700_ccg_ra_reg *)node;
467 } else if (node_type == NODE_TYPE_CCHA) {
468 ldid = get_node_logical_id(node);
469 fwk_assert(ldid < ctx->ccg_node_count);
470
471 /* Use ldid as index of the ccg_ra table */
472 ctx->ccg_ha_reg_table[ldid].node_id = node_id;
473 ctx->ccg_ha_reg_table[ldid].ccg_ha_reg =
474 (struct cmn700_ccg_ha_reg *)node;
475 } else if (node_type == NODE_TYPE_CCLA) {
476 ldid = get_node_logical_id(node);
477
478 /* Use ldid as index of the ccla table */
479 ctx->ccla_reg_table[ldid].node_id = node_id;
480 ctx->ccla_reg_table[ldid].ccla_reg =
481 (struct cmn700_ccla_reg *)node;
482 } else if (node_type == NODE_TYPE_HN_F) {
483 logical_id = get_node_logical_id(node);
484 fwk_assert(logical_id < ctx->hnf_count);
485
486 ctx->hnf_node[logical_id] = (uintptr_t)(void *)node;
487
488 hnf_node_pos[logical_id].pos_x = get_node_pos_x(node);
489 hnf_node_pos[logical_id].pos_y = get_node_pos_y(node);
490 hnf_node_pos[logical_id].port_num =
491 get_port_number(node_id, xp_port);
492
493 process_node_hnf(node);
494 }
495 }
496 }
497 }
498 }
499
500 /* Helper function to check if hnf is inside the SCG/HTG square/rectangle */
is_hnf_inside_rect(struct node_pos hnf_node_pos,const struct mod_cmn700_mem_region_map * region)501 bool is_hnf_inside_rect(
502 struct node_pos hnf_node_pos,
503 const struct mod_cmn700_mem_region_map *region)
504 {
505 struct node_pos region_hnf_pos_start;
506 struct node_pos region_hnf_pos_end;
507
508 region_hnf_pos_start = region->hnf_pos_start;
509 region_hnf_pos_end = region->hnf_pos_end;
510
511 if (((hnf_node_pos.pos_x >= region_hnf_pos_start.pos_x) &&
512 (hnf_node_pos.pos_y >= region_hnf_pos_start.pos_y) &&
513 (hnf_node_pos.pos_x <= region_hnf_pos_end.pos_x) &&
514 (hnf_node_pos.pos_y <= region_hnf_pos_end.pos_y) &&
515 (hnf_node_pos.port_num <= region_hnf_pos_end.port_num))) {
516 if (hnf_node_pos.pos_y == region_hnf_pos_start.pos_y) {
517 if (hnf_node_pos.port_num >= region_hnf_pos_start.port_num) {
518 return true;
519 } else {
520 return false;
521 }
522 } else if (hnf_node_pos.pos_y == region_hnf_pos_end.pos_y) {
523 if (hnf_node_pos.port_num <= region_hnf_pos_end.port_num) {
524 return true;
525 } else {
526 return false;
527 }
528 }
529 return true;
530 }
531 return false;
532 }
533
cmn700_setup_sam(struct cmn700_rnsam_reg * rnsam)534 static int cmn700_setup_sam(struct cmn700_rnsam_reg *rnsam)
535 {
536 unsigned int bit_pos;
537 unsigned int cxra_ldid;
538 unsigned int cxra_node_id;
539 unsigned int group;
540 unsigned int hnf_count;
541 unsigned int hnf_count_in_scg;
542 unsigned int hnf_count_per_cluster;
543 unsigned int hnf_cluster_count;
544 unsigned int hnf_nodeid;
545 unsigned int hn_nodeid_reg_bits_idx = 0;
546 unsigned int logical_id;
547 unsigned int region_idx;
548 unsigned int region_io_count = 0;
549 unsigned int region_sys_count = 0;
550 unsigned int scg_regions_enabled[MAX_SCG_COUNT] = { 0, 0, 0, 0 };
551 uint64_t base;
552 const struct mod_cmn700_mem_region_map *region;
553 const struct mod_cmn700_config *config = ctx->config;
554 const struct mod_cmn700_hierarchical_hashing *hier_hash_cfg;
555
556 FWK_LOG_INFO(MOD_NAME "Configuring SAM for node %d", get_node_id(rnsam));
557
558 (void)mmap_type_name;
559
560 for (region_idx = 0; region_idx < config->mmap_count; region_idx++) {
561 region = &config->mmap_table[region_idx];
562
563 /* Offset the base with chip address space base on chip-id */
564 base =
565 ((uint64_t)(ctx->config->chip_addr_space * chip_id) + region->base);
566
567 switch (region->type) {
568 case MOD_CMN700_MEM_REGION_TYPE_IO:
569 /*
570 * Configure memory region
571 */
572 FWK_LOG_INFO(
573 MOD_NAME " [0x%" PRIx64 " - 0x%" PRIx64 "] %s",
574 base,
575 base + region->size - 1,
576 mmap_type_name[region->type]);
577
578 configure_region(
579 rnsam,
580 region_io_count,
581 base,
582 region->size,
583 SAM_NODE_TYPE_HN_I,
584 SAM_TYPE_NON_HASH_MEM_REGION);
585
586 /*
587 * Configure target node
588 */
589 group = region_io_count /
590 CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP;
591 bit_pos = CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRY_BITS_WIDTH *
592 (region_io_count %
593 CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP);
594
595 rnsam->NON_HASH_TGT_NODEID[group] &=
596 ~(CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK << bit_pos);
597 rnsam->NON_HASH_TGT_NODEID[group] |=
598 (region->node_id & CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK)
599 << bit_pos;
600
601 region_io_count++;
602 break;
603
604 case MOD_CMN700_MEM_REGION_TYPE_SYSCACHE:
605 /*
606 * Configure memory region
607 */
608 FWK_LOG_INFO(
609 MOD_NAME " [0x%" PRIx64 " - 0x%" PRIx64 "] %s",
610 base,
611 region->base + region->size - 1,
612 mmap_type_name[region->type]);
613
614 configure_region(
615 rnsam,
616 region_sys_count,
617 base,
618 region->size,
619 SAM_NODE_TYPE_HN_F,
620 SAM_TYPE_SYS_CACHE_GRP_REGION);
621
622 /* Mark corresponding region as enabled */
623 fwk_assert(region_sys_count < MAX_SCG_COUNT);
624 scg_regions_enabled[region_sys_count] = 1;
625
626 region_sys_count++;
627
628 hnf_count_in_scg = 0;
629 for (logical_id = 0; logical_id < ctx->hnf_count; logical_id++) {
630 hnf_nodeid = get_node_id((void *)ctx->hnf_node[logical_id]);
631
632 if ((config->hnf_cal_mode) && (hnf_nodeid % 2 == 1)) {
633 /* No need include odd node ids if cal mode is set */
634 continue;
635 }
636
637 group = hn_nodeid_reg_bits_idx /
638 CMN700_HNF_CACHE_GROUP_ENTRIES_PER_GROUP;
639
640 bit_pos = CMN700_HNF_CACHE_GROUP_ENTRY_BITS_WIDTH *
641 ((hn_nodeid_reg_bits_idx %
642 (CMN700_HNF_CACHE_GROUP_ENTRIES_PER_GROUP)));
643
644 if (is_hnf_inside_rect(hnf_node_pos[logical_id], region)) {
645 if (config->hnf_cal_mode) {
646 /*
647 * If CAL mode is set, add only even numbered hnd node
648 * to sys_cache_grp_hn_nodeid registers.
649 */
650 if (hnf_nodeid % 2 == 0) {
651 rnsam->SYS_CACHE_GRP_HN_NODEID[group] +=
652 (uint64_t)hnf_nodeid << bit_pos;
653 rnsam->SYS_CACHE_GRP_SN_NODEID[group] +=
654 ((uint64_t)config->snf_table[logical_id])
655 << bit_pos;
656 hnf_count_in_scg++;
657 hn_nodeid_reg_bits_idx++;
658 }
659 } else {
660 rnsam->SYS_CACHE_GRP_HN_NODEID[group] +=
661 (uint64_t)hnf_nodeid << bit_pos;
662 rnsam->SYS_CACHE_GRP_SN_NODEID[group] +=
663 ((uint64_t)config->snf_table[logical_id])
664 << bit_pos;
665 hnf_count_in_scg++;
666 hn_nodeid_reg_bits_idx++;
667 }
668 }
669 }
670
671 rnsam->SYS_CACHE_GRP_HN_COUNT |= ((uint64_t)hnf_count_in_scg)
672 << CMN700_RNSAM_SYS_CACHE_GRP_HN_CNT_POS(region_sys_count - 1);
673
674 break;
675
676 case MOD_CMN700_REGION_TYPE_SYSCACHE_SUB:
677 FWK_LOG_INFO(
678 MOD_NAME " [0x%" PRIx64 " - 0x%" PRIx64 "] %s",
679 base,
680 region->base + region->size - 1,
681 mmap_type_name[region->type]);
682
683 /* System cache sub-regions are handled by HN-Fs */
684 break;
685
686 default:
687 fwk_unexpected();
688 return FWK_E_DATA;
689 }
690 }
691
692 /* Do configuration for CCG Nodes */
693 for (size_t idx = 0; idx < config->ccg_table_count; idx++) {
694 region = &config->ccg_config_table[idx].remote_mmap_table;
695
696 FWK_LOG_INFO(
697 MOD_NAME " [0x%" PRIx64 " - 0x%" PRIx64 "] %s",
698 region->base,
699 region->base + region->size - 1,
700 mmap_type_name[region->type]);
701
702 switch (region->type) {
703 case MOD_CMN700_REGION_TYPE_CCG:
704 /*
705 * Configure memory region
706 */
707 configure_region(
708 rnsam,
709 region_io_count,
710 region->base,
711 region->size,
712 SAM_NODE_TYPE_CXRA,
713 SAM_TYPE_NON_HASH_MEM_REGION);
714
715 /*
716 * Configure target node
717 */
718 cxra_ldid = config->ccg_config_table[idx].ldid;
719 cxra_node_id = ctx->ccg_ra_reg_table[cxra_ldid].node_id;
720 group = region_io_count /
721 CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP;
722 bit_pos = CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRY_BITS_WIDTH *
723 (region_io_count %
724 CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP);
725
726 rnsam->NON_HASH_TGT_NODEID[group] &=
727 ~(CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK << bit_pos);
728 rnsam->NON_HASH_TGT_NODEID[group] |=
729 (cxra_node_id & CMN700_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK)
730 << bit_pos;
731
732 region_io_count++;
733 break;
734
735 default:
736 fwk_unexpected();
737 return FWK_E_DATA;
738 }
739 }
740 /*
741 * If CAL mode is enabled, then only the even numbered HN-F nodes are
742 * programmed to the SYS_CACHE registers. Hence reduce the HN-F count by
743 * half if CAL mode is enabled.
744 */
745 if (config->hnf_cal_mode)
746 hnf_count = ctx->hnf_count / 2;
747 else
748 hnf_count = ctx->hnf_count;
749
750 /*
751 * If CAL mode is enabled by the configuration program the SCG CAL Mode
752 * enable register.
753 */
754 if (config->hnf_cal_mode) {
755 for (region_idx = 0; region_idx < MAX_SCG_COUNT; region_idx++)
756 rnsam->SYS_CACHE_GRP_CAL_MODE |= scg_regions_enabled[region_idx] *
757 (CMN700_RNSAM_SCG_HNF_CAL_MODE_EN
758 << (region_idx * CMN700_RNSAM_SCG_HNF_CAL_MODE_SHIFT));
759 }
760
761 /* Hierarchical Hashing support */
762 if (config->hierarchical_hashing_enable) {
763 hier_hash_cfg = &(config->hierarchical_hashing_config);
764
765 /* Total number of HN-F clusters */
766 hnf_cluster_count = hier_hash_cfg->hnf_cluster_count;
767
768 /* Number of HN-Fs in a cluster */
769 hnf_count_per_cluster =
770 (hnf_count / hnf_cluster_count) / region_sys_count;
771
772 /*
773 * For each SCG/HTG region, configure the hierarchical hashing mode with
774 * number of clusters, hnf count per cluster, hashing address bits etc.
775 * and enable hierarchical hashing for each SCG/HTG region.
776 */
777 for (region_idx = 0; region_idx < region_sys_count; region_idx++) {
778 rnsam->HASHED_TARGET_GRP_HASH_CNTL[region_idx] =
779 ((CMN700_RNSAM_HIERARCHICAL_HASH_EN_MASK
780 << CMN700_RNSAM_HIERARCHICAL_HASH_EN_POS) |
781 (fwk_math_log2(hnf_count_per_cluster)
782 << CMN700_RNSAM_HIER_ENABLE_ADDRESS_STRIPING_POS) |
783 (hnf_cluster_count << CMN700_RNSAM_HIER_HASH_CLUSTERS_POS) |
784 (hnf_count_per_cluster << CMN700_RNSAM_HIER_HASH_NODES_POS));
785
786 group =
787 region_idx / CMN700_RNSAM_SYS_CACHE_GRP_SN_ATTR_ENTRIES_PER_GRP;
788 rnsam->SYS_CACHE_GRP_SN_ATTR[group] |= hier_hash_cfg->sn_mode
789 << CMN700_RNSAM_SN_MODE_SYS_CACHE_POS(region_idx);
790
791 group = region_idx /
792 CMN700_RNSAM_SYS_CACHE_GRP_SN_SAM_CFG_ENTRIES_PER_GRP;
793 rnsam->SYS_CACHE_GRP_SN_SAM_CFG[group] |=
794 ((hier_hash_cfg->top_address_bit0
795 << CMN700_RNSAM_TOP_ADDRESS_BIT0_POS(region_idx)) |
796 (hier_hash_cfg->top_address_bit1
797 << CMN700_RNSAM_TOP_ADDRESS_BIT1_POS(region_idx)) |
798 (hier_hash_cfg->top_address_bit2
799 << CMN700_RNSAM_TOP_ADDRESS_BIT2_POS(region_idx)));
800 }
801 }
802
803 /* Enable RNSAM */
804 rnsam->STATUS = (rnsam->STATUS | CMN700_RNSAM_STATUS_UNSTALL) &
805 ~(CMN700_RNSAM_STATUS_USE_DEFAULT_TARGET_ID);
806 __sync_synchronize();
807
808 return FWK_SUCCESS;
809 }
810
cmn700_setup(void)811 static int cmn700_setup(void)
812 {
813 unsigned int rnsam_idx;
814 int status;
815
816 if (!ctx->initialized) {
817 status = cmn700_discovery();
818 if (status != FWK_SUCCESS)
819 return FWK_SUCCESS;
820
821 /*
822 * Allocate resources based on the discovery
823 */
824
825 /* Pointers for the internal RN-SAM nodes */
826 if (ctx->internal_rnsam_count != 0) {
827 ctx->internal_rnsam_table = fwk_mm_calloc(
828 ctx->internal_rnsam_count, sizeof(*ctx->internal_rnsam_table));
829 }
830
831 /* Tuples for the external RN-RAM nodes (including their node IDs) */
832 if (ctx->external_rnsam_count != 0) {
833 ctx->external_rnsam_table = fwk_mm_calloc(
834 ctx->external_rnsam_count, sizeof(*ctx->external_rnsam_table));
835 }
836
837 /* Cache groups */
838 if (ctx->hnf_count != 0) {
839 /*
840 * Allocate enough group descriptors to accommodate all expected
841 * HN-F nodes in the system.
842 */
843 ctx->hnf_node =
844 fwk_mm_calloc(ctx->hnf_count, sizeof(*ctx->hnf_node));
845 hnf_node_pos = fwk_mm_calloc(ctx->hnf_count, sizeof(*hnf_node_pos));
846 if (ctx->hnf_node == NULL)
847 return FWK_E_NOMEM;
848 ctx->hnf_cache_group = fwk_mm_calloc(
849 cmn700_hnf_cache_group_count(ctx->hnf_count),
850 sizeof(*ctx->hnf_cache_group));
851 }
852
853 /* Allocate resource for the CCG nodes */
854 if (ctx->ccg_node_count != 0) {
855 ctx->ccg_ra_reg_table = fwk_mm_calloc(
856 ctx->ccg_node_count, sizeof(*ctx->ccg_ra_reg_table));
857 ctx->ccg_ha_reg_table = fwk_mm_calloc(
858 ctx->ccg_node_count, sizeof(*ctx->ccg_ha_reg_table));
859 ctx->ccla_reg_table = fwk_mm_calloc(
860 ctx->ccg_node_count, sizeof(*ctx->ccla_reg_table));
861 }
862 }
863
864 cmn700_configure();
865
866 /* Setup internal RN-SAM nodes */
867 for (rnsam_idx = 0; rnsam_idx < ctx->internal_rnsam_count; rnsam_idx++)
868 cmn700_setup_sam(ctx->internal_rnsam_table[rnsam_idx]);
869
870 FWK_LOG_INFO(MOD_NAME "Done");
871
872 ctx->initialized = true;
873
874 return FWK_SUCCESS;
875 }
876
cmn700_ccg_setup(void)877 static void cmn700_ccg_setup(void)
878 {
879 unsigned int idx;
880 const struct mod_cmn700_config *config = ctx->config;
881
882 /* Remote RNF LDID value begins from local chip's last RNF LDID value + 1 */
883 ctx->remote_rnf_ldid_value = ctx->rnf_count;
884
885 /* Do configuration for CCG Nodes and enable the links */
886 for (idx = 0; idx < config->ccg_table_count; idx++) {
887 ccg_setup(chip_id, ctx, &config->ccg_config_table[idx]);
888 }
889
890 /*
891 * Exchange protocol credits and enter system coherecy and dvm domain for
892 * multichip SMP mode operation.
893 */
894 for (idx = 0; idx < config->ccg_table_count; idx++) {
895 ccg_exchange_protocol_credit(ctx, &config->ccg_config_table[idx]);
896 ccg_enter_system_coherency(ctx, &config->ccg_config_table[idx]);
897 ccg_enter_dvm_domain(ctx, &config->ccg_config_table[idx]);
898 }
899 }
900
901 /*
902 * Framework handlers
903 */
904
cmn700_init(fwk_id_t module_id,unsigned int device_count,const void * data)905 static int cmn700_init(
906 fwk_id_t module_id,
907 unsigned int device_count,
908 const void *data)
909 {
910 /* Atleast one device should be passed as element */
911 if (device_count == 0)
912 return FWK_E_DATA;
913
914 /* Allocate space for the device context table */
915 ctx = fwk_mm_calloc(device_count, sizeof(struct cmn700_device_ctx));
916
917 return FWK_SUCCESS;
918 }
919
cmn700_device_init(fwk_id_t element_id,unsigned int element_count,const void * data)920 static int cmn700_device_init(
921 fwk_id_t element_id,
922 unsigned int element_count,
923 const void *data)
924 {
925 struct cmn700_device_ctx *device_ctx;
926
927 fwk_assert(data != NULL);
928
929 device_ctx = ctx + fwk_id_get_element_idx(element_id);
930 device_ctx->config = data;
931
932 if (device_ctx->config->base == 0)
933 return FWK_E_DATA;
934
935 if ((device_ctx->config->mesh_size_x == 0) ||
936 (device_ctx->config->mesh_size_x > CMN700_MESH_X_MAX))
937 return FWK_E_DATA;
938
939 if ((device_ctx->config->mesh_size_y == 0) ||
940 (device_ctx->config->mesh_size_y > CMN700_MESH_Y_MAX))
941 return FWK_E_DATA;
942
943 if (device_ctx->config->snf_count > CMN700_HNF_CACHE_GROUP_ENTRIES_MAX)
944 return FWK_E_DATA;
945
946 device_ctx->root = (struct cmn700_cfgm_reg *)device_ctx->config->base;
947
948 return FWK_SUCCESS;
949 }
950
cmn700_bind(fwk_id_t id,unsigned int round)951 static int cmn700_bind(fwk_id_t id, unsigned int round)
952 {
953 int status;
954 struct cmn700_device_ctx *device_ctx;
955
956 if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
957 /* Bind to system info module to obtain multi-chip info */
958 status = fwk_module_bind(
959 FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_INFO),
960 FWK_ID_API(FWK_MODULE_IDX_SYSTEM_INFO, MOD_SYSTEM_INFO_GET_API_IDX),
961 &system_info_api);
962 return status;
963 }
964
965 /* Use second round only (round numbering is zero-indexed) */
966 if (round == 1) {
967 device_ctx = ctx + fwk_id_get_element_idx(id);
968
969 /* Bind to the timer component */
970 status = fwk_module_bind(
971 FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
972 FWK_ID_API(FWK_MODULE_IDX_TIMER, MOD_TIMER_API_IDX_TIMER),
973 &device_ctx->timer_api);
974 if (status != FWK_SUCCESS)
975 return FWK_E_PANIC;
976 }
977
978 return FWK_SUCCESS;
979 }
980
cmn700_start(fwk_id_t id)981 int cmn700_start(fwk_id_t id)
982 {
983 int status;
984
985 /* No need to do anything for element */
986 if (!fwk_module_is_valid_element_id(id))
987 return FWK_SUCCESS;
988
989 status = system_info_api->get_system_info(&system_info);
990 if (status == FWK_SUCCESS) {
991 chip_id = system_info->chip_id;
992 multi_chip_mode = system_info->multi_chip_mode;
993 }
994
995 /* No need to anything for other elements */
996 if (fwk_id_get_element_idx(id) != chip_id)
997 return FWK_SUCCESS;
998
999 /* Pickup the context based on the chip_id */
1000 ctx = ctx + fwk_id_get_element_idx(id);
1001
1002 FWK_LOG_INFO(
1003 MOD_NAME "Multichip mode: %s",
1004 multi_chip_mode ? "Enabled" : "Disabled");
1005 FWK_LOG_INFO(MOD_NAME "Chip ID: %d", chip_id);
1006
1007 if (fwk_id_is_equal(ctx->config->clock_id, FWK_ID_NONE)) {
1008 cmn700_setup();
1009 cmn700_ccg_setup();
1010 return FWK_SUCCESS;
1011 }
1012
1013 /* Register the module for clock state notifications */
1014 return fwk_notification_subscribe(
1015 mod_clock_notification_id_state_changed, ctx->config->clock_id, id);
1016 }
1017
cmn700_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)1018 static int cmn700_process_notification(
1019 const struct fwk_event *event,
1020 struct fwk_event *resp_event)
1021 {
1022 struct clock_notification_params *params;
1023
1024 fwk_assert(
1025 fwk_id_is_equal(event->id, mod_clock_notification_id_state_changed));
1026 fwk_assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_ELEMENT));
1027
1028 params = (struct clock_notification_params *)event->params;
1029 if (params->new_state == MOD_CLOCK_STATE_RUNNING) {
1030 cmn700_setup();
1031 cmn700_ccg_setup();
1032 }
1033
1034 return FWK_SUCCESS;
1035 }
1036
1037 const struct fwk_module module_cmn700 = {
1038 .type = FWK_MODULE_TYPE_DRIVER,
1039 .init = cmn700_init,
1040 .element_init = cmn700_device_init,
1041 .bind = cmn700_bind,
1042 .start = cmn700_start,
1043 .process_notification = cmn700_process_notification,
1044 };
1045