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 <cmn650.h>
9 #include <cmn650_ccix.h>
10
11 #include <internal/cmn650_ctx.h>
12
13 #include <mod_clock.h>
14 #include <mod_cmn650.h>
15 #include <mod_ppu_v1.h>
16 #include <mod_system_info.h>
17 #include <mod_timer.h>
18
19 #include <fwk_assert.h>
20 #include <fwk_event.h>
21 #include <fwk_id.h>
22 #include <fwk_log.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
31 #define MOD_NAME "[CMN650] "
32
33 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_INFO
34 static const char *const mmap_type_name[] = {
35 [MOD_CMN650_MEM_REGION_TYPE_IO] = "I/O",
36 [MOD_CMN650_MEM_REGION_TYPE_SYSCACHE] = "System Cache",
37 [MOD_CMN650_REGION_TYPE_SYSCACHE_SUB] = "Sub-System Cache",
38 [MOD_CMN650_REGION_TYPE_CCIX] = "CCIX",
39 };
40 #else
41 static const char *const mmap_type_name[] = { "" };
42 #endif
43
44 static struct cmn650_device_ctx *ctx;
45
46 /* Chip Information */
47 static struct mod_system_info_get_info_api *system_info_api;
48 static const struct mod_system_info *system_info;
49
50 /* Initialize default for multi-chip mode and chip-id */
51 static unsigned int chip_id;
52 static bool multi_chip_mode;
53
process_node_hnf(struct cmn650_hnf_reg * hnf)54 static void process_node_hnf(struct cmn650_hnf_reg *hnf)
55 {
56 unsigned int bit_pos;
57 unsigned int group;
58 unsigned int logical_id;
59 unsigned int node_id;
60 unsigned int region_idx;
61 unsigned int region_sub_count = 0;
62 static unsigned int cal_mode_factor = 1;
63 uint64_t base;
64 const struct mod_cmn650_mem_region_map *region;
65 const struct mod_cmn650_config *config = ctx->config;
66
67 logical_id = get_node_logical_id(hnf);
68 node_id = get_node_id(hnf);
69
70 /*
71 * If CAL mode is set, only even numbered hnf node should be added to the
72 * sys_cache_grp_hn_nodeid registers.
73 */
74 if (config->hnf_cal_mode == true && (node_id % 2 == 1)) {
75 /* Factor to manipulate the group and bit_pos */
76 cal_mode_factor = 2;
77 }
78
79 fwk_assert(logical_id < config->snf_count);
80
81 group = logical_id /
82 (CMN650_HNF_CACHE_GROUP_ENTRIES_PER_GROUP * cal_mode_factor);
83 bit_pos = (CMN650_HNF_CACHE_GROUP_ENTRY_BITS_WIDTH / cal_mode_factor) *
84 ((logical_id %
85 (CMN650_HNF_CACHE_GROUP_ENTRIES_PER_GROUP * cal_mode_factor)));
86
87 /*
88 * If CAL mode is set, add only even numbered hnd node to
89 * sys_cache_grp_hn_nodeid registers
90 */
91 if (config->hnf_cal_mode == true) {
92 if (node_id % 2 == 0) {
93 ctx->hnf_cache_group[group] += ((uint64_t)get_node_id(hnf))
94 << bit_pos;
95 ctx->sn_nodeid_group[group] +=
96 ((uint64_t)config->snf_table[logical_id]) << bit_pos;
97 }
98 } else {
99 ctx->hnf_cache_group[group] += ((uint64_t)get_node_id(hnf)) << bit_pos;
100 ctx->sn_nodeid_group[group] += ((uint64_t)config->snf_table[logical_id])
101 << bit_pos;
102 }
103
104 /* Set target node */
105 hnf->SAM_CONTROL = config->snf_table[logical_id];
106
107 /*
108 * Map sub-regions to this HN-F node
109 */
110 for (region_idx = 0; region_idx < config->mmap_count; region_idx++) {
111 region = &config->mmap_table[region_idx];
112
113 /* Skip non sub-regions */
114 if (region->type != MOD_CMN650_REGION_TYPE_SYSCACHE_SUB)
115 continue;
116
117 /* Offset the base with chip address space base on chip-id */
118 base =
119 ((uint64_t)(ctx->config->chip_addr_space * chip_id)) + region->base;
120
121 /* Configure sub-region entry */
122 hnf->SAM_MEMREGION[region_sub_count] = region->node_id |
123 (sam_encode_region_size(region->size)
124 << CMN650_HNF_SAM_MEMREGION_SIZE_POS) |
125 ((base / SAM_GRANULARITY) << CMN650_HNF_SAM_MEMREGION_BASE_POS) |
126 CMN650_HNF_SAM_MEMREGION_VALID;
127
128 region_sub_count++;
129 }
130
131 /* Configure the system cache RAM PPU */
132 hnf->PPU_PWPR = CMN650_PPU_PWPR_POLICY_ON | CMN650_PPU_PWPR_OPMODE_FAM |
133 CMN650_PPU_PWPR_DYN_EN;
134 }
135
136 /*
137 * Discover the topology of the interconnect and identify the number of:
138 * - External RN-SAM nodes
139 * - Internal RN-SAM nodes
140 * - HN-F nodes (cache)
141 */
cmn650_discovery(void)142 static int cmn650_discovery(void)
143 {
144 unsigned int xp_count;
145 unsigned int xp_idx;
146 unsigned int node_count;
147 unsigned int node_idx;
148 unsigned int cxg_ra_reg_count;
149 unsigned int cxg_ha_reg_count;
150 unsigned int cxla_reg_count;
151 bool xp_port;
152 struct cmn650_mxp_reg *xp;
153 struct node_header *node;
154 const struct mod_cmn650_config *config = ctx->config;
155
156 cxg_ra_reg_count = 0;
157 cxg_ha_reg_count = 0;
158 cxla_reg_count = 0;
159
160 FWK_LOG_INFO(
161 MOD_NAME "CMN-650 revision: %s", get_cmn650_revision_name(ctx->root));
162 FWK_LOG_INFO(MOD_NAME "Starting discovery...");
163
164 fwk_assert(get_node_type(ctx->root) == NODE_TYPE_CFG);
165
166 /* Traverse cross points (XP) */
167 xp_count = get_node_child_count(ctx->root);
168 for (xp_idx = 0; xp_idx < xp_count; xp_idx++) {
169 xp = get_child_node(config->base, ctx->root, xp_idx);
170 fwk_assert(get_node_type(xp) == NODE_TYPE_XP);
171
172 FWK_LOG_INFO(
173 MOD_NAME "XP (%d, %d) ID:%d, LID:%d",
174 get_node_pos_x(xp),
175 get_node_pos_y(xp),
176 get_node_id(xp),
177 get_node_logical_id(xp));
178
179 /* Traverse nodes */
180 node_count = get_node_child_count(xp);
181 for (node_idx = 0; node_idx < node_count; node_idx++) {
182 node = get_child_node(config->base, xp, node_idx);
183 if (is_child_external(xp, node_idx)) { /* External nodes */
184 xp_port = get_port_number(get_child_node_id(xp, node_idx));
185
186 /*
187 * If the device type is CXRH, CXHA, or CXRA, then the external
188 * child node is CXLA as every CXRH, CXHA, or CXRA node has a
189 * corresponding external CXLA node.
190 */
191 if ((get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) ||
192 (get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) ||
193 (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) {
194 cxla_reg_count++;
195 FWK_LOG_INFO(
196 MOD_NAME " Found CXLA at node ID: %d",
197 get_child_node_id(xp, node_idx));
198 } else { /* External RN-SAM Node */
199 ctx->external_rnsam_count++;
200 FWK_LOG_INFO(
201 MOD_NAME " Found external node ID: %d",
202 get_child_node_id(xp, node_idx));
203 }
204 } else { /* Internal nodes */
205 switch (get_node_type(node)) {
206 case NODE_TYPE_HN_F:
207 if (ctx->hnf_count >= MAX_HNF_COUNT) {
208 FWK_LOG_INFO(
209 MOD_NAME " hnf count %d >= max limit (%d)",
210 ctx->hnf_count,
211 MAX_HNF_COUNT);
212 return FWK_E_DATA;
213 }
214 ctx->hnf_count++;
215 break;
216
217 case NODE_TYPE_RN_SAM:
218 ctx->internal_rnsam_count++;
219
220 /*
221 * RN-F nodes do not have node type identifier and hence the
222 * count cannot be determined using the node type id.
223 * Alternatively, check if the device type connected to the
224 * Crosspoint (XP) is one of the RNF types and determine the
225 * RN-F count (if CAL connected RN-F, double the count).
226 */
227 xp_port = get_port_number(get_node_id(node));
228
229 if (is_device_type_rnf(xp, xp_port)) {
230 if (is_cal_connected(xp, xp_port)) {
231 ctx->rnf_count += 2;
232 FWK_LOG_INFO(
233 MOD_NAME
234 " RN-F (CAL connected) found at port: %d",
235 xp_port);
236 } else {
237 ctx->rnf_count++;
238 FWK_LOG_INFO(
239 MOD_NAME " RN-F found at port: %d", xp_port);
240 }
241 }
242 break;
243
244 case NODE_TYPE_RN_D:
245 if ((ctx->rnd_count) >= MAX_RND_COUNT) {
246 FWK_LOG_ERR(
247 MOD_NAME " rnd count %d >= max limit (%d)\n",
248 ctx->rnd_count,
249 MAX_RND_COUNT);
250 return FWK_E_DATA;
251 }
252 ctx->rnd_count++;
253 break;
254
255 case NODE_TYPE_RN_I:
256 if ((ctx->rni_count) >= MAX_RNI_COUNT) {
257 FWK_LOG_ERR(
258 MOD_NAME " rni count %d >= max limit (%d)\n",
259 ctx->rni_count,
260 MAX_RNI_COUNT);
261 return FWK_E_DATA;
262 }
263 ctx->rni_count++;
264 break;
265
266 case NODE_TYPE_CXRA:
267 cxg_ra_reg_count++;
268 break;
269
270 case NODE_TYPE_CXHA:
271 cxg_ha_reg_count++;
272 break;
273
274 /* CXLA should not be an internal node */
275 case NODE_TYPE_CXLA:
276 FWK_LOG_ERR(MOD_NAME
277 "CXLA node should not be internal node, "
278 "discovery failed");
279 return FWK_E_DEVICE;
280 break;
281
282 default:
283 /* Nothing to be done for other node types */
284 break;
285 }
286
287 FWK_LOG_INFO(
288 MOD_NAME " %s ID:%d, LID:%d",
289 get_node_type_name(get_node_type(node)),
290 get_node_id(node),
291 get_node_logical_id(node));
292 }
293 }
294 }
295
296 /* When CAL is present, the number of HN-Fs must be even. */
297 if ((ctx->hnf_count % 2 != 0) && (config->hnf_cal_mode == true)) {
298 FWK_LOG_ERR(
299 MOD_NAME "hnf count: %d should be even when CAL mode is set",
300 ctx->hnf_count);
301 return FWK_E_DATA;
302 }
303
304 /* Total number of CXG_RA, CXG_HA and CXLA nodes should be equal */
305 if ((cxg_ra_reg_count != cxg_ha_reg_count) ||
306 (cxg_ha_reg_count != cxla_reg_count)) {
307 FWK_LOG_ERR(
308 MOD_NAME
309 "Inconsistent count of CXG components detected, discovery failed.\n"
310 " CXG_RA count: %d\n"
311 " CXG_HA count: %d\n"
312 " CXLA count: %d\n",
313 cxg_ra_reg_count,
314 cxg_ha_reg_count,
315 cxla_reg_count);
316 return FWK_E_DEVICE;
317 }
318
319 ctx->ccix_node_count = cxg_ra_reg_count;
320
321 if (ctx->rnf_count > MAX_RNF_COUNT) {
322 FWK_LOG_ERR(
323 MOD_NAME "rnf count %d > max limit (%d)\n",
324 ctx->rnf_count,
325 MAX_RNF_COUNT);
326 return FWK_E_RANGE;
327 }
328
329 FWK_LOG_INFO(
330 MOD_NAME "Total internal RN-SAM nodes: %d", ctx->internal_rnsam_count);
331 FWK_LOG_INFO(
332 MOD_NAME "Total external RN-SAM nodes: %d", ctx->external_rnsam_count);
333 FWK_LOG_INFO(MOD_NAME "Total HN-F nodes: %d", ctx->hnf_count);
334 FWK_LOG_INFO(MOD_NAME "Total RN-D nodes: %d\n", ctx->rnd_count);
335 FWK_LOG_INFO(MOD_NAME "Total RN-F nodes: %d\n", ctx->rnf_count);
336 FWK_LOG_INFO(MOD_NAME "Total RN-I nodes: %d\n", ctx->rni_count);
337 FWK_LOG_INFO(
338 MOD_NAME "Total CCIX Request Agent nodes: %d", cxg_ra_reg_count);
339 FWK_LOG_INFO(MOD_NAME "Total CCIX Home Agent nodes: %d", cxg_ha_reg_count);
340 FWK_LOG_INFO(MOD_NAME "Total CCIX Link Agent nodes: %d", cxla_reg_count);
341
342 return FWK_SUCCESS;
343 }
344
cmn650_configure(void)345 static void cmn650_configure(void)
346 {
347 unsigned int node_count;
348 unsigned int node_idx;
349 unsigned int xp_count;
350 unsigned int xp_idx;
351 unsigned int xrnsam_entry;
352 unsigned int irnsam_entry;
353 unsigned int hnf_entry;
354 unsigned int ldid;
355 unsigned int node_id;
356 bool xp_port;
357 void *node;
358 struct cmn650_mxp_reg *xp;
359 const struct mod_cmn650_config *config = ctx->config;
360
361 fwk_assert(get_node_type(ctx->root) == NODE_TYPE_CFG);
362
363 xrnsam_entry = 0;
364 irnsam_entry = 0;
365 hnf_entry = 0;
366
367 /* Traverse cross points (XP) */
368 xp_count = get_node_child_count(ctx->root);
369 for (xp_idx = 0; xp_idx < xp_count; xp_idx++) {
370 xp = get_child_node(config->base, ctx->root, xp_idx);
371 fwk_assert(get_node_type(xp) == NODE_TYPE_XP);
372
373 /* Traverse nodes */
374 node_count = get_node_child_count(xp);
375 for (node_idx = 0; node_idx < node_count; node_idx++) {
376 node = get_child_node(config->base, xp, node_idx);
377 if (is_child_external(xp, node_idx)) {
378 node_id = get_child_node_id(xp, node_idx);
379 xp_port = get_port_number(get_child_node_id(xp, node_idx));
380
381 if ((get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) ||
382 (get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) ||
383 (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) {
384 ldid = get_node_logical_id(node);
385 fwk_assert(ldid < ctx->ccix_node_count);
386
387 ctx->cxla_reg_table[ldid].node_id = node_id;
388 ctx->cxla_reg_table[ldid].cxla_reg =
389 (struct cmn650_cxla_reg *)node;
390 } else {
391 fwk_assert(xrnsam_entry < ctx->external_rnsam_count);
392
393 ctx->external_rnsam_table[xrnsam_entry].node_id = node_id;
394 ctx->external_rnsam_table[xrnsam_entry].node = node;
395
396 xrnsam_entry++;
397 }
398 } else {
399 enum node_type node_type = get_node_type(node);
400 node_id = get_node_id(node);
401
402 if (node_type == NODE_TYPE_RN_SAM) {
403 fwk_assert(irnsam_entry < ctx->internal_rnsam_count);
404
405 ctx->internal_rnsam_table[irnsam_entry] = node;
406
407 irnsam_entry++;
408 } else if (node_type == NODE_TYPE_CXRA) {
409 ldid = get_node_logical_id(node);
410 fwk_assert(ldid < ctx->ccix_node_count);
411
412 /* Use ldid as index of the cxg_ra table */
413 ctx->cxg_ra_reg_table[ldid].node_id = node_id;
414 ctx->cxg_ra_reg_table[ldid].cxg_ra_reg =
415 (struct cmn650_cxg_ra_reg *)node;
416 } else if (node_type == NODE_TYPE_CXHA) {
417 ldid = get_node_logical_id(node);
418 fwk_assert(ldid < ctx->ccix_node_count);
419
420 /* Use ldid as index of the cxg_ra table */
421 ctx->cxg_ha_reg_table[ldid].node_id = node_id;
422 ctx->cxg_ha_reg_table[ldid].cxg_ha_reg =
423 (struct cmn650_cxg_ha_reg *)node;
424 } else if (node_type == NODE_TYPE_HN_F) {
425 fwk_assert(hnf_entry < ctx->hnf_count);
426 ctx->hnf_node[hnf_entry++] = (uintptr_t)(void *)node;
427
428 process_node_hnf(node);
429 }
430 }
431 }
432 }
433 }
434
cmn650_setup_sam(struct cmn650_rnsam_reg * rnsam)435 static int cmn650_setup_sam(struct cmn650_rnsam_reg *rnsam)
436 {
437 unsigned int bit_pos;
438 unsigned int group;
439 unsigned int group_count;
440 unsigned int hnf_count;
441 unsigned int region_idx;
442 unsigned int idx;
443 unsigned int region_io_count = 0;
444 unsigned int region_sys_count = 0;
445 unsigned int cxra_ldid, cpa_cxra_ldid;
446 unsigned int cxra_node_id, cpa_cxra_node_id;
447 unsigned int port_aggregate_group_id = 0;
448 unsigned int scg_regions_enabled[MAX_SCG_COUNT] = { 0, 0, 0, 0 };
449 uint64_t base;
450 const struct mod_cmn650_mem_region_map *region;
451 const struct mod_cmn650_config *config = ctx->config;
452
453 FWK_LOG_INFO(MOD_NAME "Configuring SAM for node %d", get_node_id(rnsam));
454
455 (void)mmap_type_name;
456
457 for (region_idx = 0; region_idx < config->mmap_count; region_idx++) {
458 region = &config->mmap_table[region_idx];
459
460 /* Offset the base with chip address space base on chip-id */
461 base =
462 ((uint64_t)(ctx->config->chip_addr_space * chip_id) + region->base);
463
464 switch (region->type) {
465 case MOD_CMN650_MEM_REGION_TYPE_IO:
466 /*
467 * Configure memory region
468 */
469 FWK_LOG_INFO(
470 MOD_NAME " [0x%x%x - 0x%x%x] %s",
471 HIGH_WORD(base),
472 LOW_WORD(base),
473 HIGH_WORD(base + region->size - 1),
474 LOW_WORD(base + region->size - 1),
475 mmap_type_name[region->type]);
476
477 configure_region(
478 &rnsam->NON_HASH_MEM_REGION[region_io_count],
479 base,
480 region->size,
481 SAM_NODE_TYPE_HN_I);
482
483 /*
484 * Configure target node
485 */
486 group = region_io_count /
487 CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP;
488 bit_pos = CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRY_BITS_WIDTH *
489 (region_io_count %
490 CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP);
491
492 rnsam->NON_HASH_TGT_NODEID[group] &=
493 ~(CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK << bit_pos);
494 rnsam->NON_HASH_TGT_NODEID[group] |=
495 (region->node_id & CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK)
496 << bit_pos;
497
498 region_io_count++;
499 break;
500
501 case MOD_CMN650_MEM_REGION_TYPE_SYSCACHE:
502 /*
503 * Configure memory region
504 */
505 FWK_LOG_INFO(
506 MOD_NAME " [0x%x%x - 0x%x%x] %s",
507 HIGH_WORD(region->base),
508 LOW_WORD(region->base),
509 HIGH_WORD(region->base + region->size - 1),
510 LOW_WORD(region->base + region->size - 1),
511 mmap_type_name[region->type]);
512
513 configure_region(
514 &rnsam->SYS_CACHE_GRP_REGION[region_sys_count],
515 region->base,
516 region->size,
517 SAM_NODE_TYPE_HN_F);
518
519 /* Mark corresponding region as enabled */
520 fwk_assert(region_sys_count < MAX_SCG_COUNT);
521 scg_regions_enabled[region_sys_count] = 1;
522
523 region_sys_count++;
524 break;
525
526 case MOD_CMN650_REGION_TYPE_SYSCACHE_SUB:
527 FWK_LOG_INFO(
528 MOD_NAME " [0x%x%x - 0x%x%x] %s",
529 HIGH_WORD(region->base),
530 LOW_WORD(region->base),
531 HIGH_WORD(region->base + region->size - 1),
532 LOW_WORD(region->base + region->size - 1),
533 mmap_type_name[region->type]);
534
535 /* System cache sub-regions are handled by HN-Fs */
536 break;
537
538 default:
539 fwk_unexpected();
540 return FWK_E_DATA;
541 }
542 }
543
544 /* Do configuration for CCIX Gateway Home Nodes */
545 for (idx = 0; idx < config->ccix_table_count; idx++) {
546 region = &config->ccix_config_table[idx].remote_mmap_table;
547
548 FWK_LOG_INFO(
549 MOD_NAME " [0x%x%x - 0x%x%x] %s",
550 HIGH_WORD(region->base),
551 LOW_WORD(region->base),
552 HIGH_WORD(region->base + region->size - 1),
553 LOW_WORD(region->base + region->size - 1),
554 mmap_type_name[region->type]);
555
556 switch (region->type) {
557 case MOD_CMN650_REGION_TYPE_CCIX:
558 /*
559 * Configure memory region
560 */
561 configure_region(
562 &rnsam->NON_HASH_MEM_REGION[region_io_count],
563 region->base,
564 region->size,
565 SAM_NODE_TYPE_CXRA);
566
567 /*
568 * Configure target node
569 */
570 cxra_ldid = config->ccix_config_table[idx].ldid;
571 cxra_node_id = ctx->cxg_ra_reg_table[cxra_ldid].node_id;
572 group = region_io_count /
573 CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP;
574 bit_pos = CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRY_BITS_WIDTH *
575 (region_io_count %
576 CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP);
577
578 rnsam->NON_HASH_TGT_NODEID[group] &=
579 ~(CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK << bit_pos);
580 rnsam->NON_HASH_TGT_NODEID[group] |=
581 (cxra_node_id & CMN650_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK)
582 << bit_pos;
583
584 /* CPA Programming */
585 if (config->ccix_config_table[idx].port_aggregate) {
586 FWK_LOG_INFO("Enabling CML Port Aggregation:");
587 FWK_LOG_INFO(
588 " CXRA Node ID: %d as CPA Group ID: %d",
589 cxra_node_id,
590 port_aggregate_group_id);
591
592 group =
593 region_io_count / CML_PORT_AGGR_MODE_CTRL_REGIONS_PER_GROUP;
594 bit_pos = region_io_count *
595 CML_PORT_AGGR_MODE_CTRL_PAG_WIDTH_PER_REGION;
596
597 rnsam->CML_PORT_AGGR_MODE_CTRL[group] |=
598 ((UINT64_C(0x1) << (bit_pos)) |
599 ((uint64_t)port_aggregate_group_id
600 << (bit_pos + CML_PORT_AGGR_MODE_CTRL_PAG_GRPID_OFFSET)));
601
602 /* Considering only 2 ports per group */
603 rnsam->CML_PORT_AGGR_CTRL |= UINT64_C(0x1)
604 << (port_aggregate_group_id *
605 CML_PORT_AGGR_CTRL_NUM_CXG_PAG_WIDTH);
606
607 cpa_cxra_ldid =
608 config->ccix_config_table[idx].port_aggregate_ldid;
609 cpa_cxra_node_id = ctx->cxg_ra_reg_table[cpa_cxra_ldid].node_id;
610
611 /* Considering only 2 ports per group */
612 group = (port_aggregate_group_id * NUM_PORTS_PER_CPA_GROUP) /
613 CMN_PORT_AGGR_GRP_PAG_TGTID_PER_GROUP;
614 bit_pos =
615 ((port_aggregate_group_id * NUM_PORTS_PER_CPA_GROUP) *
616 CMN_PORT_AGGR_GRP_PAG_TGTID_WIDTH);
617
618 rnsam->CML_PORT_AGGR_GRP[group] |= ((uint64_t)cxra_node_id)
619 << bit_pos;
620
621 group =
622 ((port_aggregate_group_id * NUM_PORTS_PER_CPA_GROUP) + 1) /
623 CMN_PORT_AGGR_GRP_PAG_TGTID_PER_GROUP;
624 bit_pos =
625 ((((port_aggregate_group_id * NUM_PORTS_PER_CPA_GROUP) +
626 1) *
627 CMN_PORT_AGGR_GRP_PAG_TGTID_WIDTH) %
628 CMN_PORT_AGGR_GRP_PAG_TGTID_WIDTH_PER_GROUP);
629
630 rnsam->CML_PORT_AGGR_GRP[group] |= (uint64_t)cpa_cxra_node_id
631 << bit_pos;
632
633 /* Increment the group id for the next group */
634 port_aggregate_group_id++;
635 }
636
637 region_io_count++;
638 break;
639
640 default:
641 fwk_unexpected();
642 return FWK_E_DATA;
643 }
644 }
645
646 /*
647 * If CAL mode is enabled, then only the even numbered HN-F nodes are
648 * programmed to the SYS_CACHE registers. Hence reduce the HN-F count by
649 * half if CAL mode is enabled.
650 */
651 if (config->hnf_cal_mode)
652 hnf_count = ctx->hnf_count / 2;
653 else
654 hnf_count = ctx->hnf_count;
655
656 group_count = hnf_count / CMN650_HNF_CACHE_GROUP_ENTRIES_PER_GROUP;
657 for (group = 0; group < group_count; group++)
658 rnsam->SYS_CACHE_GRP_HN_NODEID[group] = ctx->hnf_cache_group[group];
659
660 /* Program the number of HNFs */
661 rnsam->SYS_CACHE_GRP_HN_COUNT = hnf_count;
662
663 /*
664 * If CAL mode is enabled by the configuration program the SCG CAL Mode
665 * enable register.
666 */
667 if (config->hnf_cal_mode) {
668 for (region_idx = 0; region_idx < MAX_SCG_COUNT; region_idx++)
669 rnsam->SYS_CACHE_GRP_CAL_MODE |= scg_regions_enabled[region_idx] *
670 (CMN650_RNSAM_SCG_HNF_CAL_MODE_EN
671 << (region_idx * CMN650_RNSAM_SCG_HNF_CAL_MODE_SHIFT));
672
673 /* Program the SYS_CACHE_GRP_SN_NODEID register for PrefetchTgt */
674 group_count = config->snf_count /
675 (CMN650_RNSAM_SYS_CACHE_GRP_SN_NODEID_ENTRIES_PER_GROUP * 2);
676 } else {
677 group_count = config->snf_count /
678 CMN650_RNSAM_SYS_CACHE_GRP_SN_NODEID_ENTRIES_PER_GROUP;
679 }
680
681 for (group = 0; group < group_count; group++)
682 rnsam->SYS_CACHE_GRP_SN_NODEID[group] = ctx->sn_nodeid_group[group];
683
684 /* Enable RNSAM */
685 rnsam->STATUS = ((uint64_t)config->hnd_node_id
686 << CMN650_RNSAM_STATUS_DEFAULT_NODEID_POS) |
687 CMN650_RNSAM_STATUS_UNSTALL;
688 __sync_synchronize();
689
690 return FWK_SUCCESS;
691 }
692
cmn650_setup(void)693 static int cmn650_setup(void)
694 {
695 unsigned int rnsam_idx;
696 int status;
697
698 if (!ctx->initialized) {
699 status = cmn650_discovery();
700 if (status != FWK_SUCCESS)
701 return FWK_SUCCESS;
702
703 /*
704 * Allocate resources based on the discovery
705 */
706
707 /* Pointers for the internal RN-SAM nodes */
708 if (ctx->internal_rnsam_count != 0) {
709 ctx->internal_rnsam_table = fwk_mm_calloc(
710 ctx->internal_rnsam_count, sizeof(*ctx->internal_rnsam_table));
711 }
712
713 /* Tuples for the external RN-RAM nodes (including their node IDs) */
714 if (ctx->external_rnsam_count != 0) {
715 ctx->external_rnsam_table = fwk_mm_calloc(
716 ctx->external_rnsam_count, sizeof(*ctx->external_rnsam_table));
717 }
718
719 /* Cache groups */
720 if (ctx->hnf_count != 0) {
721 /*
722 * Allocate enough group descriptors to accommodate all expected
723 * HN-F nodes in the system.
724 */
725 ctx->hnf_node =
726 fwk_mm_calloc(ctx->hnf_count, sizeof(*ctx->hnf_node));
727 if (ctx->hnf_node == NULL)
728 return FWK_E_NOMEM;
729 ctx->hnf_cache_group = fwk_mm_calloc(
730 ctx->hnf_count / CMN650_HNF_CACHE_GROUP_ENTRIES_PER_GROUP,
731 sizeof(*ctx->hnf_cache_group));
732 ctx->sn_nodeid_group = fwk_mm_calloc(
733 ctx->hnf_count /
734 CMN650_RNSAM_SYS_CACHE_GRP_SN_NODEID_ENTRIES_PER_GROUP,
735 sizeof(*ctx->sn_nodeid_group));
736 }
737
738 /* Allocate resource for the CCIX Gateway nodes */
739 if (ctx->ccix_node_count != 0) {
740 ctx->cxg_ra_reg_table = fwk_mm_calloc(
741 ctx->ccix_node_count, sizeof(*ctx->cxg_ra_reg_table));
742 if (ctx->cxg_ra_reg_table == NULL)
743 return FWK_E_NOMEM;
744
745 ctx->cxg_ha_reg_table = fwk_mm_calloc(
746 ctx->ccix_node_count, sizeof(*ctx->cxg_ha_reg_table));
747 if (ctx->cxg_ha_reg_table == NULL)
748 return FWK_E_NOMEM;
749
750 ctx->cxla_reg_table = fwk_mm_calloc(
751 ctx->ccix_node_count, sizeof(*ctx->cxla_reg_table));
752 if (ctx->cxla_reg_table == NULL)
753 return FWK_E_NOMEM;
754 }
755 }
756
757 cmn650_configure();
758
759 /* Setup internal RN-SAM nodes */
760 for (rnsam_idx = 0; rnsam_idx < ctx->internal_rnsam_count; rnsam_idx++)
761 cmn650_setup_sam(ctx->internal_rnsam_table[rnsam_idx]);
762
763 FWK_LOG_INFO(MOD_NAME "Done");
764
765 ctx->initialized = true;
766
767 return FWK_SUCCESS;
768 }
769
cmn650_ccix_setup(void)770 static int cmn650_ccix_setup(void)
771 {
772 unsigned int idx;
773 const struct mod_cmn650_config *config = ctx->config;
774
775 /* Remote RNF LDID value begins from local chip's last RNF LDID value + 1 */
776 ctx->remote_rnf_ldid_value = ctx->rnf_count;
777
778 /* Do configuration for CCIX Gateway Nodes and enable the links */
779 for (idx = 0; idx < config->ccix_table_count; idx++)
780 ccix_setup(chip_id, ctx, &config->ccix_config_table[idx]);
781
782 /*
783 * Exchange protocol credits and enter system coherecy and dvm domain for
784 * multichip SMP mode operation.
785 */
786 for (idx = 0; idx < config->ccix_table_count; idx++) {
787 ccix_exchange_protocol_credit(ctx, &config->ccix_config_table[idx]);
788 ccix_enter_system_coherency(ctx, &config->ccix_config_table[idx]);
789 ccix_enter_dvm_domain(ctx, &config->ccix_config_table[idx]);
790 }
791 return FWK_SUCCESS;
792 }
793
cmn650_setup_rnsam(unsigned int node_id)794 static int cmn650_setup_rnsam(unsigned int node_id)
795 {
796 unsigned int node_idx;
797
798 for (node_idx = 0; node_idx < ctx->external_rnsam_count; node_idx++) {
799 if (ctx->external_rnsam_table[node_idx].node_id == node_id) {
800 cmn650_setup_sam(ctx->external_rnsam_table[node_idx].node);
801 return FWK_SUCCESS;
802 }
803 }
804
805 return FWK_E_PARAM;
806 }
807
808 /*
809 * PPUv1 State Observer API
810 */
811
post_ppu_on(void * data)812 static void post_ppu_on(void *data)
813 {
814 fwk_assert(data != NULL);
815 cmn650_setup_rnsam(*(unsigned int *)data);
816 }
817
818 static const struct mod_ppu_v1_power_state_observer_api cmn650_observer_api = {
819 .post_ppu_on = post_ppu_on,
820 };
821
822 /*
823 * Framework handlers
824 */
825
cmn650_init(fwk_id_t module_id,unsigned int device_count,const void * data)826 static int cmn650_init(
827 fwk_id_t module_id,
828 unsigned int device_count,
829 const void *data)
830 {
831 /* Atleast one device should be passed as element */
832 if (device_count == 0)
833 return FWK_E_DATA;
834
835 /* Allocate space for the device context table */
836 ctx = fwk_mm_calloc(device_count, sizeof(struct cmn650_device_ctx));
837
838 return FWK_SUCCESS;
839 }
840
cmn650_device_init(fwk_id_t element_id,unsigned int element_count,const void * data)841 static int cmn650_device_init(
842 fwk_id_t element_id,
843 unsigned int element_count,
844 const void *data)
845 {
846 struct cmn650_device_ctx *device_ctx;
847
848 fwk_assert(data != NULL);
849
850 device_ctx = ctx + fwk_id_get_element_idx(element_id);
851 device_ctx->config = data;
852
853 if (device_ctx->config->base == 0)
854 return FWK_E_DATA;
855
856 if ((device_ctx->config->mesh_size_x == 0) ||
857 (device_ctx->config->mesh_size_x > CMN650_MESH_X_MAX))
858 return FWK_E_DATA;
859
860 if ((device_ctx->config->mesh_size_y == 0) ||
861 (device_ctx->config->mesh_size_y > CMN650_MESH_Y_MAX))
862 return FWK_E_DATA;
863
864 if (device_ctx->config->snf_count > CMN650_HNF_CACHE_GROUP_ENTRIES_MAX)
865 return FWK_E_DATA;
866
867 device_ctx->root = get_root_node(
868 device_ctx->config->base,
869 device_ctx->config->hnd_node_id,
870 device_ctx->config->mesh_size_x,
871 device_ctx->config->mesh_size_y);
872
873 return FWK_SUCCESS;
874 }
875
cmn650_bind(fwk_id_t id,unsigned int round)876 static int cmn650_bind(fwk_id_t id, unsigned int round)
877 {
878 int status;
879 struct cmn650_device_ctx *device_ctx;
880
881 if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
882 /* Bind to system info module to obtain multi-chip info */
883 status = fwk_module_bind(
884 FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_INFO),
885 FWK_ID_API(FWK_MODULE_IDX_SYSTEM_INFO, MOD_SYSTEM_INFO_GET_API_IDX),
886 &system_info_api);
887 return status;
888 }
889
890 /* Use second round only (round numbering is zero-indexed) */
891 if (round == 1) {
892 device_ctx = ctx + fwk_id_get_element_idx(id);
893
894 /* Bind to the timer component */
895 status = fwk_module_bind(
896 FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
897 FWK_ID_API(FWK_MODULE_IDX_TIMER, MOD_TIMER_API_IDX_TIMER),
898 &device_ctx->timer_api);
899 if (status != FWK_SUCCESS)
900 return FWK_E_PANIC;
901 }
902
903 return FWK_SUCCESS;
904 }
905
cmn650_process_bind_request(fwk_id_t requester_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)906 static int cmn650_process_bind_request(
907 fwk_id_t requester_id,
908 fwk_id_t target_id,
909 fwk_id_t api_id,
910 const void **api)
911 {
912 *api = &cmn650_observer_api;
913 return FWK_SUCCESS;
914 }
915
cmn650_start(fwk_id_t id)916 int cmn650_start(fwk_id_t id)
917 {
918 int status;
919
920 /* No need to do anything for element */
921 if (!fwk_module_is_valid_element_id(id))
922 return FWK_SUCCESS;
923
924 status = system_info_api->get_system_info(&system_info);
925 if (status == FWK_SUCCESS) {
926 chip_id = system_info->chip_id;
927 multi_chip_mode = system_info->multi_chip_mode;
928 }
929
930 /* No need to anything for other elements */
931 if (fwk_id_get_element_idx(id) != chip_id)
932 return FWK_SUCCESS;
933
934 /* Pickup the context based on the chip_id */
935 ctx = ctx + fwk_id_get_element_idx(id);
936
937 FWK_LOG_INFO(
938 MOD_NAME "Multichip mode: %d Chip ID: %d\n", multi_chip_mode, chip_id);
939
940 if (fwk_id_is_equal(ctx->config->clock_id, FWK_ID_NONE)) {
941 cmn650_setup();
942 cmn650_ccix_setup();
943 return FWK_SUCCESS;
944 }
945
946 /* Register the module for clock state notifications */
947 return fwk_notification_subscribe(
948 mod_clock_notification_id_state_changed, ctx->config->clock_id, id);
949 }
950
cmn650_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)951 static int cmn650_process_notification(
952 const struct fwk_event *event,
953 struct fwk_event *resp_event)
954 {
955 struct clock_notification_params *params;
956
957 fwk_assert(
958 fwk_id_is_equal(event->id, mod_clock_notification_id_state_changed));
959 fwk_assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_ELEMENT));
960
961 params = (struct clock_notification_params *)event->params;
962 if (params->new_state == MOD_CLOCK_STATE_RUNNING) {
963 cmn650_setup();
964 cmn650_ccix_setup();
965 }
966
967 return FWK_SUCCESS;
968 }
969
970 const struct fwk_module module_cmn650 = {
971 .type = FWK_MODULE_TYPE_DRIVER,
972 .api_count = MOD_CMN650_API_COUNT,
973 .init = cmn650_init,
974 .element_init = cmn650_device_init,
975 .bind = cmn650_bind,
976 .start = cmn650_start,
977 .process_bind_request = cmn650_process_bind_request,
978 .process_notification = cmn650_process_notification,
979 };
980