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