2 * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
12 #include <common/debug.h>
13 #include <drivers/arm/ccn.h>
14 #include <lib/bakery_lock.h>
17 #include "ccn_private.h"
19 static const ccn_desc_t
*ccn_plat_desc
;
20 #if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32))
21 DEFINE_BAKERY_LOCK(ccn_lock
);
24 /*******************************************************************************
25 * This function takes the base address of the CCN's programmer's view (PV), a
26 * region ID of one of the 256 regions (0-255) and a register offset within the
27 * region. It converts the first two parameters into a base address and uses it
28 * to read the register at the offset.
29 ******************************************************************************/
30 static inline unsigned long long ccn_reg_read(uintptr_t periphbase
,
31 unsigned int region_id
,
32 unsigned int register_offset
)
34 uintptr_t region_base
;
37 assert(region_id
< REGION_ID_LIMIT
);
39 region_base
= periphbase
+ region_id_to_base(region_id
);
40 return mmio_read_64(region_base
+ register_offset
);
43 /*******************************************************************************
44 * This function takes the base address of the CCN's programmer's view (PV), a
45 * region ID of one of the 256 regions (0-255), a register offset within the
46 * region and a value. It converts the first two parameters into a base address
47 * and uses it to write the value in the register at the offset.
48 ******************************************************************************/
49 static inline void ccn_reg_write(uintptr_t periphbase
,
50 unsigned int region_id
,
51 unsigned int register_offset
,
52 unsigned long long value
)
54 uintptr_t region_base
;
57 assert(region_id
< REGION_ID_LIMIT
);
59 region_base
= periphbase
+ region_id_to_base(region_id
);
60 mmio_write_64(region_base
+ register_offset
, value
);
65 typedef struct rn_info
{
66 unsigned char node_desc
[MAX_RN_NODES
];
69 /*******************************************************************************
70 * This function takes the base address of the CCN's programmer's view (PV) and
71 * the node ID of a Request Node (RN-D or RN-I). It returns the maximum number
72 * of master interfaces resident on that node. This number is equal to the least
73 * significant two bits of the node type ID + 1.
74 ******************************************************************************/
75 static unsigned int ccn_get_rni_mcount(uintptr_t periphbase
,
78 unsigned int rn_type_id
;
80 /* Use the node id to find the type of RN-I/D node */
81 rn_type_id
= get_node_type(ccn_reg_read(periphbase
,
82 rn_id
+ RNI_REGION_ID_START
,
85 /* Return the number master interfaces based on node type */
86 return rn_type_id_to_master_cnt(rn_type_id
);
89 /*******************************************************************************
90 * This function reads the CCN registers to find the following information about
91 * the ACE/ACELite/ACELite+DVM/CHI interfaces resident on the various types of
92 * Request Nodes (RN-Fs, RN-Is and RN-Ds) in the system:
94 * 1. The total number of such interfaces that this CCN IP supports. This is the
95 * cumulative number of interfaces across all Request node types. It is
96 * passed back as the return value of this function.
98 * 2. The maximum number of interfaces of a type resident on a Request node of
99 * one of the three types. This information is populated in the 'info'
100 * array provided by the caller as described next.
102 * The array has 64 entries. Each entry corresponds to a Request node. The
103 * Miscellaneous node's programmer's view has RN-F, RN-I and RN-D ID
104 * registers. For each RN-I and RN-D ID indicated as being present in these
105 * registers, its identification register (offset 0xFF00) is read. This
106 * register specifies the maximum number of master interfaces the node
107 * supports. For RN-Fs it is assumed that there can be only a single fully
108 * coherent master resident on each node. The counts for each type of node
109 * are use to populate the array entry at the index corresponding to the node
110 * ID i.e. rn_info[node ID] = <number of master interfaces>
111 ******************************************************************************/
112 static unsigned int ccn_get_rn_master_info(uintptr_t periphbase
,
115 unsigned int num_masters
= 0;
120 for (rn_type
= RN_TYPE_RNF
; rn_type
< NUM_RN_TYPES
; rn_type
++) {
121 unsigned int mn_reg_off
, node_id
;
122 unsigned long long rn_bitmap
;
125 * RN-F, RN-I, RN-D node registers in the MN region occupy
126 * contiguous 16 byte apart offsets.
128 mn_reg_off
= MN_RNF_NODEID_OFFSET
+ (rn_type
<< 4);
129 rn_bitmap
= ccn_reg_read(periphbase
, MN_REGION_ID
, mn_reg_off
);
131 FOR_EACH_PRESENT_NODE_ID(node_id
, rn_bitmap
) {
132 unsigned int node_mcount
;
135 * A RN-F does not have a node type since it does not
136 * export a programmer's interface. It can only have a
137 * single fully coherent master residing on it. If the
138 * offset of the MN(Miscellaneous Node) register points
139 * to a RN-I/D node then the master count is set to the
140 * maximum number of master interfaces that can possibly
141 * reside on the node.
143 node_mcount
= (mn_reg_off
== MN_RNF_NODEID_OFFSET
? 1 :
144 ccn_get_rni_mcount(periphbase
, node_id
));
147 * Use this value to increment the maximum possible
148 * master interfaces in the system.
150 num_masters
+= node_mcount
;
153 * Update the entry in 'info' for this node ID with
154 * the maximum number of masters than can sit on
155 * it. This information will be used to validate the
156 * node information passed by the platform later.
158 info
->node_desc
[node_id
] = node_mcount
;
165 /*******************************************************************************
166 * This function validates parameters passed by the platform (in a debug build).
167 * It collects information about the maximum number of master interfaces that:
168 * a) the CCN IP can accommodate and
169 * b) can exist on each Request node.
170 * It compares this with the information provided by the platform to determine
171 * the validity of the latter.
172 ******************************************************************************/
173 static void __init
ccn_validate_plat_params(const ccn_desc_t
*plat_desc
)
175 unsigned int master_id
, num_rn_masters
;
176 rn_info_t info
= { {0} };
179 assert(plat_desc
->periphbase
);
180 assert(plat_desc
->master_to_rn_id_map
);
181 assert(plat_desc
->num_masters
);
182 assert(plat_desc
->num_masters
< CCN_MAX_RN_MASTERS
);
185 * Find the number and properties of fully coherent, IO coherent and IO
186 * coherent + DVM master interfaces
188 num_rn_masters
= ccn_get_rn_master_info(plat_desc
->periphbase
, &info
);
189 assert(plat_desc
->num_masters
< num_rn_masters
);
192 * Iterate through the Request nodes specified by the platform.
193 * Decrement the count of the masters in the 'info' array for each
194 * Request node encountered. If the count would drop below 0 then the
195 * platform's view of this aspect of CCN configuration is incorrect.
197 for (master_id
= 0; master_id
< plat_desc
->num_masters
; master_id
++) {
198 unsigned int node_id
;
200 node_id
= plat_desc
->master_to_rn_id_map
[master_id
];
201 assert(node_id
< MAX_RN_NODES
);
202 assert(info
.node_desc
[node_id
]);
203 info
.node_desc
[node_id
]--;
206 #endif /* ENABLE_ASSERTIONS */
208 /*******************************************************************************
209 * This function validates parameters passed by the platform (in a debug build)
210 * and initialises its internal data structures. A lock is required to prevent
211 * simultaneous CCN operations at runtime (only BL31) to add and remove Request
212 * nodes from coherency.
213 ******************************************************************************/
214 void __init
ccn_init(const ccn_desc_t
*plat_desc
)
216 #if ENABLE_ASSERTIONS
217 ccn_validate_plat_params(plat_desc
);
220 ccn_plat_desc
= plat_desc
;
223 /*******************************************************************************
224 * This function converts a bit map of master interface IDs to a bit map of the
225 * Request node IDs that they reside on.
226 ******************************************************************************/
227 static unsigned long long ccn_master_to_rn_id_map(unsigned long long master_map
)
229 unsigned long long rn_id_map
= 0;
230 unsigned int node_id
, iface_id
;
233 assert(ccn_plat_desc
);
235 FOR_EACH_PRESENT_MASTER_INTERFACE(iface_id
, master_map
) {
236 assert(iface_id
< ccn_plat_desc
->num_masters
);
238 /* Convert the master ID into the node ID */
239 node_id
= ccn_plat_desc
->master_to_rn_id_map
[iface_id
];
241 /* Set the bit corresponding to this node ID */
242 rn_id_map
|= (1ULL << node_id
);
248 /*******************************************************************************
249 * This function executes the necessary operations to add or remove Request node
250 * IDs specified in the 'rn_id_map' bitmap from the snoop/DVM domains specified
251 * in the 'hn_id_map'. The 'region_id' specifies the ID of the first HN-F/MN
252 * on which the operation should be performed. 'op_reg_offset' specifies the
253 * type of operation (add/remove). 'stat_reg_offset' specifies the register
254 * which should be polled to determine if the operation has completed or not.
255 ******************************************************************************/
256 static void ccn_snoop_dvm_do_op(unsigned long long rn_id_map
,
257 unsigned long long hn_id_map
,
258 unsigned int region_id
,
259 unsigned int op_reg_offset
,
260 unsigned int stat_reg_offset
)
262 unsigned int start_region_id
;
264 assert(ccn_plat_desc
);
265 assert(ccn_plat_desc
->periphbase
);
267 #if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32))
268 bakery_lock_get(&ccn_lock
);
270 start_region_id
= region_id
;
271 FOR_EACH_PRESENT_REGION_ID(start_region_id
, hn_id_map
) {
272 ccn_reg_write(ccn_plat_desc
->periphbase
,
278 start_region_id
= region_id
;
280 FOR_EACH_PRESENT_REGION_ID(start_region_id
, hn_id_map
) {
281 WAIT_FOR_DOMAIN_CTRL_OP_COMPLETION(start_region_id
,
287 #if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32))
288 bakery_lock_release(&ccn_lock
);
292 /*******************************************************************************
293 * The following functions provide the boot and runtime API to the platform for
294 * adding and removing master interfaces from the snoop/DVM domains. A bitmap of
295 * master interfaces IDs is passed as a parameter. It is converted into a bitmap
296 * of Request node IDs using the mapping provided by the platform while
297 * initialising the driver.
298 * For example, consider a dual cluster system where the clusters have values 0
299 * & 1 in the affinity level 1 field of their respective MPIDRs. While
300 * initialising this driver, the platform provides the mapping between each
301 * cluster and the corresponding Request node. To add or remove a cluster from
302 * the snoop and dvm domain, the bit position corresponding to the cluster ID
303 * should be set in the 'master_iface_map' i.e. to remove both clusters the
304 * bitmap would equal 0x11.
305 ******************************************************************************/
306 void ccn_enter_snoop_dvm_domain(unsigned long long master_iface_map
)
308 unsigned long long rn_id_map
;
310 rn_id_map
= ccn_master_to_rn_id_map(master_iface_map
);
311 ccn_snoop_dvm_do_op(rn_id_map
,
312 CCN_GET_HN_NODEID_MAP(ccn_plat_desc
->periphbase
,
313 MN_HNF_NODEID_OFFSET
),
316 HNF_SDC_STAT_OFFSET
);
318 ccn_snoop_dvm_do_op(rn_id_map
,
319 CCN_GET_MN_NODEID_MAP(ccn_plat_desc
->periphbase
),
325 void ccn_exit_snoop_dvm_domain(unsigned long long master_iface_map
)
327 unsigned long long rn_id_map
;
329 rn_id_map
= ccn_master_to_rn_id_map(master_iface_map
);
330 ccn_snoop_dvm_do_op(rn_id_map
,
331 CCN_GET_HN_NODEID_MAP(ccn_plat_desc
->periphbase
,
332 MN_HNF_NODEID_OFFSET
),
335 HNF_SDC_STAT_OFFSET
);
337 ccn_snoop_dvm_do_op(rn_id_map
,
338 CCN_GET_MN_NODEID_MAP(ccn_plat_desc
->periphbase
),
344 void ccn_enter_dvm_domain(unsigned long long master_iface_map
)
346 unsigned long long rn_id_map
;
348 rn_id_map
= ccn_master_to_rn_id_map(master_iface_map
);
349 ccn_snoop_dvm_do_op(rn_id_map
,
350 CCN_GET_MN_NODEID_MAP(ccn_plat_desc
->periphbase
),
356 void ccn_exit_dvm_domain(unsigned long long master_iface_map
)
358 unsigned long long rn_id_map
;
360 rn_id_map
= ccn_master_to_rn_id_map(master_iface_map
);
361 ccn_snoop_dvm_do_op(rn_id_map
,
362 CCN_GET_MN_NODEID_MAP(ccn_plat_desc
->periphbase
),
368 /*******************************************************************************
369 * This function returns the run mode of all the L3 cache partitions in the
370 * system. The state is expected to be one of NO_L3, SF_ONLY, L3_HAM or
371 * L3_FAM. Instead of comparing the states reported by all HN-Fs, the state of
372 * the first present HN-F node is reported. Since the driver does not export an
373 * interface to program them separately, there is no reason to perform this
374 * check. An HN-F could report that the L3 cache is transitioning from one mode
375 * to another e.g. HNF_PM_NOL3_2_SFONLY. In this case, the function waits for
376 * the transition to complete and reports the final state.
377 ******************************************************************************/
378 unsigned int ccn_get_l3_run_mode(void)
380 unsigned long long hnf_pstate_stat
;
382 assert(ccn_plat_desc
);
383 assert(ccn_plat_desc
->periphbase
);
386 * Wait for a L3 cache partition to enter any run mode. The pstate
387 * parameter is read from an HN-F P-state status register. A non-zero
388 * value in bits[1:0] means that the cache is transitioning to a run
392 hnf_pstate_stat
= ccn_reg_read(ccn_plat_desc
->periphbase
,
394 HNF_PSTATE_STAT_OFFSET
);
395 } while (hnf_pstate_stat
& 0x3);
397 return PSTATE_TO_RUN_MODE(hnf_pstate_stat
);
400 /*******************************************************************************
401 * This function sets the run mode of all the L3 cache partitions in the
402 * system to one of NO_L3, SF_ONLY, L3_HAM or L3_FAM depending upon the state
403 * specified by the 'mode' argument.
404 ******************************************************************************/
405 void ccn_set_l3_run_mode(unsigned int mode
)
407 unsigned long long mn_hnf_id_map
, hnf_pstate_stat
;
408 unsigned int region_id
;
410 assert(ccn_plat_desc
);
411 assert(ccn_plat_desc
->periphbase
);
412 assert(mode
<= CCN_L3_RUN_MODE_FAM
);
414 mn_hnf_id_map
= ccn_reg_read(ccn_plat_desc
->periphbase
,
416 MN_HNF_NODEID_OFFSET
);
417 region_id
= HNF_REGION_ID_START
;
419 /* Program the desired run mode */
420 FOR_EACH_PRESENT_REGION_ID(region_id
, mn_hnf_id_map
) {
421 ccn_reg_write(ccn_plat_desc
->periphbase
,
423 HNF_PSTATE_REQ_OFFSET
,
427 /* Wait for the caches to transition to the run mode */
428 region_id
= HNF_REGION_ID_START
;
429 FOR_EACH_PRESENT_REGION_ID(region_id
, mn_hnf_id_map
) {
431 * Wait for a L3 cache partition to enter a target run
432 * mode. The pstate parameter is read from an HN-F P-state
436 hnf_pstate_stat
= ccn_reg_read(ccn_plat_desc
->periphbase
,
438 HNF_PSTATE_STAT_OFFSET
);
439 } while (((hnf_pstate_stat
& HNF_PSTATE_MASK
) >> 2) != mode
);
443 /*******************************************************************************
444 * This function configures system address map and provides option to enable the
445 * 3SN striping mode of Slave node operation. The Slave node IDs and the Top
446 * Address bit1 and bit0 are provided as parameters to this function. This
447 * configuration is needed only if network contains a single SN-F or 3 SN-F and
448 * must be completed before the first request by the system to normal memory.
449 ******************************************************************************/
450 void ccn_program_sys_addrmap(unsigned int sn0_id
,
453 unsigned int top_addr_bit0
,
454 unsigned int top_addr_bit1
,
455 unsigned char three_sn_en
)
457 unsigned long long mn_hnf_id_map
, hnf_sam_ctrl_value
;
458 unsigned int region_id
;
460 assert(ccn_plat_desc
);
461 assert(ccn_plat_desc
->periphbase
);
463 mn_hnf_id_map
= ccn_reg_read(ccn_plat_desc
->periphbase
,
465 MN_HNF_NODEID_OFFSET
);
466 region_id
= HNF_REGION_ID_START
;
467 hnf_sam_ctrl_value
= MAKE_HNF_SAM_CTRL_VALUE(sn0_id
,
474 FOR_EACH_PRESENT_REGION_ID(region_id
, mn_hnf_id_map
) {
476 /* Program the SAM control register */
477 ccn_reg_write(ccn_plat_desc
->periphbase
,
485 /*******************************************************************************
486 * This function returns the part0 id from the peripheralID 0 register
487 * in CCN. This id can be used to distinguish the CCN variant present in the
489 ******************************************************************************/
490 int ccn_get_part0_id(uintptr_t periphbase
)
493 return (int)(mmio_read_64(periphbase
494 + MN_PERIPH_ID_0_1_OFFSET
) & 0xFF);
497 /*******************************************************************************
498 * This function returns the region id corresponding to a node_id of node_type.
499 ******************************************************************************/
500 static unsigned int get_region_id_for_node(node_types_t node_type
,
501 unsigned int node_id
)
503 unsigned int mn_reg_off
, region_id
;
504 unsigned long long node_bitmap
;
505 unsigned int loc_node_id
, node_pos_in_map
= 0;
507 assert(node_type
< NUM_NODE_TYPES
);
508 assert(node_id
< MAX_RN_NODES
);
512 region_id
= RNI_REGION_ID_START
;
515 region_id
= HNF_REGION_ID_START
;
518 region_id
= HNI_REGION_ID_START
;
521 region_id
= SBSX_REGION_ID_START
;
524 ERROR("Un-supported Node Type = %d.\n", node_type
);
526 return REGION_ID_LIMIT
;
529 * RN-I, HN-F, HN-I, SN node registers in the MN region
530 * occupy contiguous 16 byte apart offsets.
532 * RN-F and RN-D node are not supported as
533 * none of them exposes any memory map to
534 * configure any of their offset registers.
537 mn_reg_off
= MN_RNF_NODEID_OFFSET
+ (node_type
<< 4);
538 node_bitmap
= ccn_reg_read(ccn_plat_desc
->periphbase
,
539 MN_REGION_ID
, mn_reg_off
);
541 assert((node_bitmap
& (1ULL << (node_id
))) != 0U);
544 FOR_EACH_PRESENT_NODE_ID(loc_node_id
, node_bitmap
) {
545 INFO("Index = %u with loc_nod=%u and input nod=%u\n",
546 node_pos_in_map
, loc_node_id
, node_id
);
547 if (loc_node_id
== node_id
)
552 if (node_pos_in_map
== CCN_MAX_RN_MASTERS
) {
553 ERROR("Node Id = %d, is not found.\n", node_id
);
555 return REGION_ID_LIMIT
;
559 * According to section 3.1.1 in CCN specification, region offset for
560 * the RN-I components is calculated as (128 + NodeID of RN-I).
562 if (node_type
== NODE_TYPE_RNI
)
563 region_id
+= node_id
;
565 region_id
+= node_pos_in_map
;
570 /*******************************************************************************
571 * This function sets the value 'val' to the register at register_offset from
572 * the base address pointed to by the region_id.
573 * where, region id is mapped to a node_id of node_type.
574 ******************************************************************************/
575 void ccn_write_node_reg(node_types_t node_type
, unsigned int node_id
,
576 unsigned int reg_offset
, unsigned long long val
)
578 unsigned int region_id
= get_region_id_for_node(node_type
, node_id
);
580 if (reg_offset
> REGION_ID_OFFSET
) {
581 ERROR("Invalid Register offset 0x%x is provided.\n",
587 /* Setting the value of Auxiliary Control Register of the Node */
588 ccn_reg_write(ccn_plat_desc
->periphbase
, region_id
, reg_offset
, val
);
589 VERBOSE("Value is successfully written at address 0x%lx.\n",
590 (ccn_plat_desc
->periphbase
591 + region_id_to_base(region_id
))
595 /*******************************************************************************
596 * This function read the value 'val' stored in the register at register_offset
597 * from the base address pointed to by the region_id.
598 * where, region id is mapped to a node_id of node_type.
599 ******************************************************************************/
600 unsigned long long ccn_read_node_reg(node_types_t node_type
,
601 unsigned int node_id
,
602 unsigned int reg_offset
)
604 unsigned long long val
;
605 unsigned int region_id
= get_region_id_for_node(node_type
, node_id
);
607 if (reg_offset
> REGION_ID_OFFSET
) {
608 ERROR("Invalid Register offset 0x%x is provided.\n",
614 /* Setting the value of Auxiliary Control Register of the Node */
615 val
= ccn_reg_read(ccn_plat_desc
->periphbase
, region_id
, reg_offset
);
616 VERBOSE("Value is successfully read from address 0x%lx.\n",
617 (ccn_plat_desc
->periphbase
618 + region_id_to_base(region_id
))