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