1 /*
2 * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdbool.h>
10
11 #include <arch.h>
12 #include <common/debug.h>
13 #include <drivers/arm/ccn.h>
14 #include <lib/bakery_lock.h>
15 #include <lib/mmio.h>
16
17 #include "ccn_private.h"
18
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);
22 #endif
23
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 ******************************************************************************/
ccn_reg_read(uintptr_t periphbase,unsigned int region_id,unsigned int register_offset)30 static inline unsigned long long ccn_reg_read(uintptr_t periphbase,
31 unsigned int region_id,
32 unsigned int register_offset)
33 {
34 uintptr_t region_base;
35
36 assert(periphbase);
37 assert(region_id < REGION_ID_LIMIT);
38
39 region_base = periphbase + region_id_to_base(region_id);
40 return mmio_read_64(region_base + register_offset);
41 }
42
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 ******************************************************************************/
ccn_reg_write(uintptr_t periphbase,unsigned int region_id,unsigned int register_offset,unsigned long long value)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)
53 {
54 uintptr_t region_base;
55
56 assert(periphbase);
57 assert(region_id < REGION_ID_LIMIT);
58
59 region_base = periphbase + region_id_to_base(region_id);
60 mmio_write_64(region_base + register_offset, value);
61 }
62
63 #if ENABLE_ASSERTIONS
64
65 typedef struct rn_info {
66 unsigned char node_desc[MAX_RN_NODES];
67 } rn_info_t;
68
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 ******************************************************************************/
ccn_get_rni_mcount(uintptr_t periphbase,unsigned int rn_id)75 static unsigned int ccn_get_rni_mcount(uintptr_t periphbase,
76 unsigned int rn_id)
77 {
78 unsigned int rn_type_id;
79
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,
83 REGION_ID_OFFSET));
84
85 /* Return the number master interfaces based on node type */
86 return rn_type_id_to_master_cnt(rn_type_id);
87 }
88
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:
93 *
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.
97 *
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.
101 *
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 ******************************************************************************/
ccn_get_rn_master_info(uintptr_t periphbase,rn_info_t * info)112 static unsigned int ccn_get_rn_master_info(uintptr_t periphbase,
113 rn_info_t *info)
114 {
115 unsigned int num_masters = 0;
116 rn_types_t rn_type;
117
118 assert (info);
119
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;
123
124 /*
125 * RN-F, RN-I, RN-D node registers in the MN region occupy
126 * contiguous 16 byte apart offsets.
127 */
128 mn_reg_off = MN_RNF_NODEID_OFFSET + (rn_type << 4);
129 rn_bitmap = ccn_reg_read(periphbase, MN_REGION_ID, mn_reg_off);
130
131 FOR_EACH_PRESENT_NODE_ID(node_id, rn_bitmap) {
132 unsigned int node_mcount;
133
134 /*
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.
142 */
143 node_mcount = (mn_reg_off == MN_RNF_NODEID_OFFSET ? 1 :
144 ccn_get_rni_mcount(periphbase, node_id));
145
146 /*
147 * Use this value to increment the maximum possible
148 * master interfaces in the system.
149 */
150 num_masters += node_mcount;
151
152 /*
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.
157 */
158 info->node_desc[node_id] = node_mcount;
159 }
160 }
161
162 return num_masters;
163 }
164
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 ******************************************************************************/
ccn_validate_plat_params(const ccn_desc_t * plat_desc)173 static void __init ccn_validate_plat_params(const ccn_desc_t *plat_desc)
174 {
175 unsigned int master_id, num_rn_masters;
176 rn_info_t info = { {0} };
177
178 assert(plat_desc);
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);
183
184 /*
185 * Find the number and properties of fully coherent, IO coherent and IO
186 * coherent + DVM master interfaces
187 */
188 num_rn_masters = ccn_get_rn_master_info(plat_desc->periphbase, &info);
189 assert(plat_desc->num_masters < num_rn_masters);
190
191 /*
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.
196 */
197 for (master_id = 0; master_id < plat_desc->num_masters; master_id++) {
198 unsigned int node_id;
199
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]--;
204 }
205 }
206 #endif /* ENABLE_ASSERTIONS */
207
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 ******************************************************************************/
ccn_init(const ccn_desc_t * plat_desc)214 void __init ccn_init(const ccn_desc_t *plat_desc)
215 {
216 #if ENABLE_ASSERTIONS
217 ccn_validate_plat_params(plat_desc);
218 #endif
219
220 ccn_plat_desc = plat_desc;
221 }
222
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 ******************************************************************************/
ccn_master_to_rn_id_map(unsigned long long master_map)227 static unsigned long long ccn_master_to_rn_id_map(unsigned long long master_map)
228 {
229 unsigned long long rn_id_map = 0;
230 unsigned int node_id, iface_id;
231
232 assert(master_map);
233 assert(ccn_plat_desc);
234
235 FOR_EACH_PRESENT_MASTER_INTERFACE(iface_id, master_map) {
236 assert(iface_id < ccn_plat_desc->num_masters);
237
238 /* Convert the master ID into the node ID */
239 node_id = ccn_plat_desc->master_to_rn_id_map[iface_id];
240
241 /* Set the bit corresponding to this node ID */
242 rn_id_map |= (1ULL << node_id);
243 }
244
245 return rn_id_map;
246 }
247
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 ******************************************************************************/
ccn_snoop_dvm_do_op(unsigned long long rn_id_map,unsigned long long hn_id_map,unsigned int region_id,unsigned int op_reg_offset,unsigned int stat_reg_offset)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)
261 {
262 unsigned int start_region_id;
263
264 assert(ccn_plat_desc);
265 assert(ccn_plat_desc->periphbase);
266
267 #if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32))
268 bakery_lock_get(&ccn_lock);
269 #endif
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,
273 start_region_id,
274 op_reg_offset,
275 rn_id_map);
276 }
277
278 start_region_id = region_id;
279
280 FOR_EACH_PRESENT_REGION_ID(start_region_id, hn_id_map) {
281 WAIT_FOR_DOMAIN_CTRL_OP_COMPLETION(start_region_id,
282 stat_reg_offset,
283 op_reg_offset,
284 rn_id_map);
285 }
286
287 #if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32))
288 bakery_lock_release(&ccn_lock);
289 #endif
290 }
291
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 ******************************************************************************/
ccn_enter_snoop_dvm_domain(unsigned long long master_iface_map)306 void ccn_enter_snoop_dvm_domain(unsigned long long master_iface_map)
307 {
308 unsigned long long rn_id_map;
309
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),
314 HNF_REGION_ID_START,
315 HNF_SDC_SET_OFFSET,
316 HNF_SDC_STAT_OFFSET);
317
318 ccn_snoop_dvm_do_op(rn_id_map,
319 CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase),
320 MN_REGION_ID,
321 MN_DDC_SET_OFFSET,
322 MN_DDC_STAT_OFFSET);
323 }
324
ccn_exit_snoop_dvm_domain(unsigned long long master_iface_map)325 void ccn_exit_snoop_dvm_domain(unsigned long long master_iface_map)
326 {
327 unsigned long long rn_id_map;
328
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),
333 HNF_REGION_ID_START,
334 HNF_SDC_CLR_OFFSET,
335 HNF_SDC_STAT_OFFSET);
336
337 ccn_snoop_dvm_do_op(rn_id_map,
338 CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase),
339 MN_REGION_ID,
340 MN_DDC_CLR_OFFSET,
341 MN_DDC_STAT_OFFSET);
342 }
343
ccn_enter_dvm_domain(unsigned long long master_iface_map)344 void ccn_enter_dvm_domain(unsigned long long master_iface_map)
345 {
346 unsigned long long rn_id_map;
347
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),
351 MN_REGION_ID,
352 MN_DDC_SET_OFFSET,
353 MN_DDC_STAT_OFFSET);
354 }
355
ccn_exit_dvm_domain(unsigned long long master_iface_map)356 void ccn_exit_dvm_domain(unsigned long long master_iface_map)
357 {
358 unsigned long long rn_id_map;
359
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),
363 MN_REGION_ID,
364 MN_DDC_CLR_OFFSET,
365 MN_DDC_STAT_OFFSET);
366 }
367
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 ******************************************************************************/
ccn_get_l3_run_mode(void)378 unsigned int ccn_get_l3_run_mode(void)
379 {
380 unsigned long long hnf_pstate_stat;
381
382 assert(ccn_plat_desc);
383 assert(ccn_plat_desc->periphbase);
384
385 /*
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
389 * mode.
390 */
391 do {
392 hnf_pstate_stat = ccn_reg_read(ccn_plat_desc->periphbase,
393 HNF_REGION_ID_START,
394 HNF_PSTATE_STAT_OFFSET);
395 } while (hnf_pstate_stat & 0x3);
396
397 return PSTATE_TO_RUN_MODE(hnf_pstate_stat);
398 }
399
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 ******************************************************************************/
ccn_set_l3_run_mode(unsigned int mode)405 void ccn_set_l3_run_mode(unsigned int mode)
406 {
407 unsigned long long mn_hnf_id_map, hnf_pstate_stat;
408 unsigned int region_id;
409
410 assert(ccn_plat_desc);
411 assert(ccn_plat_desc->periphbase);
412 assert(mode <= CCN_L3_RUN_MODE_FAM);
413
414 mn_hnf_id_map = ccn_reg_read(ccn_plat_desc->periphbase,
415 MN_REGION_ID,
416 MN_HNF_NODEID_OFFSET);
417 region_id = HNF_REGION_ID_START;
418
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,
422 region_id,
423 HNF_PSTATE_REQ_OFFSET,
424 mode);
425 }
426
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) {
430 /*
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
433 * status register.
434 */
435 do {
436 hnf_pstate_stat = ccn_reg_read(ccn_plat_desc->periphbase,
437 region_id,
438 HNF_PSTATE_STAT_OFFSET);
439 } while (((hnf_pstate_stat & HNF_PSTATE_MASK) >> 2) != mode);
440 }
441 }
442
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 ******************************************************************************/
ccn_program_sys_addrmap(unsigned int sn0_id,unsigned int sn1_id,unsigned int sn2_id,unsigned int top_addr_bit0,unsigned int top_addr_bit1,unsigned char three_sn_en)450 void ccn_program_sys_addrmap(unsigned int sn0_id,
451 unsigned int sn1_id,
452 unsigned int sn2_id,
453 unsigned int top_addr_bit0,
454 unsigned int top_addr_bit1,
455 unsigned char three_sn_en)
456 {
457 unsigned long long mn_hnf_id_map, hnf_sam_ctrl_value;
458 unsigned int region_id;
459
460 assert(ccn_plat_desc);
461 assert(ccn_plat_desc->periphbase);
462
463 mn_hnf_id_map = ccn_reg_read(ccn_plat_desc->periphbase,
464 MN_REGION_ID,
465 MN_HNF_NODEID_OFFSET);
466 region_id = HNF_REGION_ID_START;
467 hnf_sam_ctrl_value = MAKE_HNF_SAM_CTRL_VALUE(sn0_id,
468 sn1_id,
469 sn2_id,
470 top_addr_bit0,
471 top_addr_bit1,
472 three_sn_en);
473
474 FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) {
475
476 /* Program the SAM control register */
477 ccn_reg_write(ccn_plat_desc->periphbase,
478 region_id,
479 HNF_SAM_CTRL_OFFSET,
480 hnf_sam_ctrl_value);
481 }
482
483 }
484
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
488 * system.
489 ******************************************************************************/
ccn_get_part0_id(uintptr_t periphbase)490 int ccn_get_part0_id(uintptr_t periphbase)
491 {
492 assert(periphbase);
493 return (int)(mmio_read_64(periphbase
494 + MN_PERIPH_ID_0_1_OFFSET) & 0xFF);
495 }
496
497 /*******************************************************************************
498 * This function returns the region id corresponding to a node_id of node_type.
499 ******************************************************************************/
get_region_id_for_node(node_types_t node_type,unsigned int node_id)500 static unsigned int get_region_id_for_node(node_types_t node_type,
501 unsigned int node_id)
502 {
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;
506
507 assert(node_type < NUM_NODE_TYPES);
508 assert(node_id < MAX_RN_NODES);
509
510 switch (node_type) {
511 case NODE_TYPE_RNI:
512 region_id = RNI_REGION_ID_START;
513 break;
514 case NODE_TYPE_HNF:
515 region_id = HNF_REGION_ID_START;
516 break;
517 case NODE_TYPE_HNI:
518 region_id = HNI_REGION_ID_START;
519 break;
520 case NODE_TYPE_SN:
521 region_id = SBSX_REGION_ID_START;
522 break;
523 default:
524 ERROR("Un-supported Node Type = %d.\n", node_type);
525 assert(false);
526 return REGION_ID_LIMIT;
527 }
528 /*
529 * RN-I, HN-F, HN-I, SN node registers in the MN region
530 * occupy contiguous 16 byte apart offsets.
531 *
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.
535 */
536
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);
540
541 assert((node_bitmap & (1ULL << (node_id))) != 0U);
542
543
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)
548 break;
549 node_pos_in_map++;
550 }
551
552 if (node_pos_in_map == CCN_MAX_RN_MASTERS) {
553 ERROR("Node Id = %d, is not found.\n", node_id);
554 assert(false);
555 return REGION_ID_LIMIT;
556 }
557
558 /*
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).
561 */
562 if (node_type == NODE_TYPE_RNI)
563 region_id += node_id;
564 else
565 region_id += node_pos_in_map;
566
567 return region_id;
568 }
569
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 ******************************************************************************/
ccn_write_node_reg(node_types_t node_type,unsigned int node_id,unsigned int reg_offset,unsigned long long val)575 void ccn_write_node_reg(node_types_t node_type, unsigned int node_id,
576 unsigned int reg_offset, unsigned long long val)
577 {
578 unsigned int region_id = get_region_id_for_node(node_type, node_id);
579
580 if (reg_offset > REGION_ID_OFFSET) {
581 ERROR("Invalid Register offset 0x%x is provided.\n",
582 reg_offset);
583 assert(false);
584 return;
585 }
586
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))
592 + reg_offset);
593 }
594
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 ******************************************************************************/
ccn_read_node_reg(node_types_t node_type,unsigned int node_id,unsigned int reg_offset)600 unsigned long long ccn_read_node_reg(node_types_t node_type,
601 unsigned int node_id,
602 unsigned int reg_offset)
603 {
604 unsigned long long val;
605 unsigned int region_id = get_region_id_for_node(node_type, node_id);
606
607 if (reg_offset > REGION_ID_OFFSET) {
608 ERROR("Invalid Register offset 0x%x is provided.\n",
609 reg_offset);
610 assert(false);
611 return ULL(0);
612 }
613
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))
619 + reg_offset);
620
621 return val;
622 }
623