1 /* 2 * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch.h> 8 #include <assert.h> 9 #include <bakery_lock.h> 10 #include <ccn.h> 11 #include <debug.h> 12 #include <errno.h> 13 #include <mmio.h> 14 #include <stdbool.h> 15 #include "ccn_private.h" 16 17 static const ccn_desc_t *ccn_plat_desc; 18 #if defined(IMAGE_BL31) || (defined(AARCH32) && defined(IMAGE_BL32)) 19 DEFINE_BAKERY_LOCK(ccn_lock); 20 #endif 21 22 /******************************************************************************* 23 * This function takes the base address of the CCN's programmer's view (PV), a 24 * region ID of one of the 256 regions (0-255) and a register offset within the 25 * region. It converts the first two parameters into a base address and uses it 26 * to read the register at the offset. 27 ******************************************************************************/ 28 static inline unsigned long long ccn_reg_read(uintptr_t periphbase, 29 unsigned int region_id, 30 unsigned int register_offset) 31 { 32 uintptr_t region_base; 33 34 assert(periphbase); 35 assert(region_id < REGION_ID_LIMIT); 36 37 region_base = periphbase + region_id_to_base(region_id); 38 return mmio_read_64(region_base + register_offset); 39 } 40 41 /******************************************************************************* 42 * This function takes the base address of the CCN's programmer's view (PV), a 43 * region ID of one of the 256 regions (0-255), a register offset within the 44 * region and a value. It converts the first two parameters into a base address 45 * and uses it to write the value in the register at the offset. 46 ******************************************************************************/ 47 static inline void ccn_reg_write(uintptr_t periphbase, 48 unsigned int region_id, 49 unsigned int register_offset, 50 unsigned long long value) 51 { 52 uintptr_t region_base; 53 54 assert(periphbase); 55 assert(region_id < REGION_ID_LIMIT); 56 57 region_base = periphbase + region_id_to_base(region_id); 58 mmio_write_64(region_base + register_offset, value); 59 } 60 61 #if ENABLE_ASSERTIONS 62 63 typedef struct rn_info { 64 unsigned char node_desc[MAX_RN_NODES]; 65 } rn_info_t; 66 67 /******************************************************************************* 68 * This function takes the base address of the CCN's programmer's view (PV) and 69 * the node ID of a Request Node (RN-D or RN-I). It returns the maximum number 70 * of master interfaces resident on that node. This number is equal to the least 71 * significant two bits of the node type ID + 1. 72 ******************************************************************************/ 73 static unsigned int ccn_get_rni_mcount(uintptr_t periphbase, 74 unsigned int rn_id) 75 { 76 unsigned int rn_type_id; 77 78 /* Use the node id to find the type of RN-I/D node */ 79 rn_type_id = get_node_type(ccn_reg_read(periphbase, 80 rn_id + RNI_REGION_ID_START, 81 REGION_ID_OFFSET)); 82 83 /* Return the number master interfaces based on node type */ 84 return rn_type_id_to_master_cnt(rn_type_id); 85 } 86 87 /******************************************************************************* 88 * This function reads the CCN registers to find the following information about 89 * the ACE/ACELite/ACELite+DVM/CHI interfaces resident on the various types of 90 * Request Nodes (RN-Fs, RN-Is and RN-Ds) in the system: 91 * 92 * 1. The total number of such interfaces that this CCN IP supports. This is the 93 * cumulative number of interfaces across all Request node types. It is 94 * passed back as the return value of this function. 95 * 96 * 2. The maximum number of interfaces of a type resident on a Request node of 97 * one of the three types. This information is populated in the 'info' 98 * array provided by the caller as described next. 99 * 100 * The array has 64 entries. Each entry corresponds to a Request node. The 101 * Miscellaneous node's programmer's view has RN-F, RN-I and RN-D ID 102 * registers. For each RN-I and RN-D ID indicated as being present in these 103 * registers, its identification register (offset 0xFF00) is read. This 104 * register specifies the maximum number of master interfaces the node 105 * supports. For RN-Fs it is assumed that there can be only a single fully 106 * coherent master resident on each node. The counts for each type of node 107 * are use to populate the array entry at the index corresponding to the node 108 * ID i.e. rn_info[node ID] = <number of master interfaces> 109 ******************************************************************************/ 110 static unsigned int ccn_get_rn_master_info(uintptr_t periphbase, 111 rn_info_t *info) 112 { 113 unsigned int num_masters = 0; 114 rn_types_t rn_type; 115 116 assert (info); 117 118 for (rn_type = RN_TYPE_RNF; rn_type < NUM_RN_TYPES; rn_type++) { 119 unsigned int mn_reg_off, node_id; 120 unsigned long long rn_bitmap; 121 122 /* 123 * RN-F, RN-I, RN-D node registers in the MN region occupy 124 * contiguous 16 byte apart offsets. 125 */ 126 mn_reg_off = MN_RNF_NODEID_OFFSET + (rn_type << 4); 127 rn_bitmap = ccn_reg_read(periphbase, MN_REGION_ID, mn_reg_off); 128 129 FOR_EACH_PRESENT_NODE_ID(node_id, rn_bitmap) { 130 unsigned int node_mcount; 131 132 /* 133 * A RN-F does not have a node type since it does not 134 * export a programmer's interface. It can only have a 135 * single fully coherent master residing on it. If the 136 * offset of the MN(Miscellaneous Node) register points 137 * to a RN-I/D node then the master count is set to the 138 * maximum number of master interfaces that can possibly 139 * reside on the node. 140 */ 141 node_mcount = (mn_reg_off == MN_RNF_NODEID_OFFSET ? 1 : 142 ccn_get_rni_mcount(periphbase, node_id)); 143 144 /* 145 * Use this value to increment the maximum possible 146 * master interfaces in the system. 147 */ 148 num_masters += node_mcount; 149 150 /* 151 * Update the entry in 'info' for this node ID with 152 * the maximum number of masters than can sit on 153 * it. This information will be used to validate the 154 * node information passed by the platform later. 155 */ 156 info->node_desc[node_id] = node_mcount; 157 } 158 } 159 160 return num_masters; 161 } 162 163 /******************************************************************************* 164 * This function validates parameters passed by the platform (in a debug build). 165 * It collects information about the maximum number of master interfaces that: 166 * a) the CCN IP can accommodate and 167 * b) can exist on each Request node. 168 * It compares this with the information provided by the platform to determine 169 * the validity of the latter. 170 ******************************************************************************/ 171 static void __init ccn_validate_plat_params(const ccn_desc_t *plat_desc) 172 { 173 unsigned int master_id, num_rn_masters; 174 rn_info_t info = { {0} }; 175 176 assert(plat_desc); 177 assert(plat_desc->periphbase); 178 assert(plat_desc->master_to_rn_id_map); 179 assert(plat_desc->num_masters); 180 assert(plat_desc->num_masters < CCN_MAX_RN_MASTERS); 181 182 /* 183 * Find the number and properties of fully coherent, IO coherent and IO 184 * coherent + DVM master interfaces 185 */ 186 num_rn_masters = ccn_get_rn_master_info(plat_desc->periphbase, &info); 187 assert(plat_desc->num_masters < num_rn_masters); 188 189 /* 190 * Iterate through the Request nodes specified by the platform. 191 * Decrement the count of the masters in the 'info' array for each 192 * Request node encountered. If the count would drop below 0 then the 193 * platform's view of this aspect of CCN configuration is incorrect. 194 */ 195 for (master_id = 0; master_id < plat_desc->num_masters; master_id++) { 196 unsigned int node_id; 197 198 node_id = plat_desc->master_to_rn_id_map[master_id]; 199 assert(node_id < MAX_RN_NODES); 200 assert(info.node_desc[node_id]); 201 info.node_desc[node_id]--; 202 } 203 } 204 #endif /* ENABLE_ASSERTIONS */ 205 206 /******************************************************************************* 207 * This function validates parameters passed by the platform (in a debug build) 208 * and initialises its internal data structures. A lock is required to prevent 209 * simultaneous CCN operations at runtime (only BL31) to add and remove Request 210 * nodes from coherency. 211 ******************************************************************************/ 212 void __init ccn_init(const ccn_desc_t *plat_desc) 213 { 214 #if ENABLE_ASSERTIONS 215 ccn_validate_plat_params(plat_desc); 216 #endif 217 218 ccn_plat_desc = plat_desc; 219 } 220 221 /******************************************************************************* 222 * This function converts a bit map of master interface IDs to a bit map of the 223 * Request node IDs that they reside on. 224 ******************************************************************************/ 225 static unsigned long long ccn_master_to_rn_id_map(unsigned long long master_map) 226 { 227 unsigned long long rn_id_map = 0; 228 unsigned int node_id, iface_id; 229 230 assert(master_map); 231 assert(ccn_plat_desc); 232 233 FOR_EACH_PRESENT_MASTER_INTERFACE(iface_id, master_map) { 234 assert(iface_id < ccn_plat_desc->num_masters); 235 236 /* Convert the master ID into the node ID */ 237 node_id = ccn_plat_desc->master_to_rn_id_map[iface_id]; 238 239 /* Set the bit corresponding to this node ID */ 240 rn_id_map |= (1ULL << node_id); 241 } 242 243 return rn_id_map; 244 } 245 246 /******************************************************************************* 247 * This function executes the necessary operations to add or remove Request node 248 * IDs specified in the 'rn_id_map' bitmap from the snoop/DVM domains specified 249 * in the 'hn_id_map'. The 'region_id' specifies the ID of the first HN-F/MN 250 * on which the operation should be performed. 'op_reg_offset' specifies the 251 * type of operation (add/remove). 'stat_reg_offset' specifies the register 252 * which should be polled to determine if the operation has completed or not. 253 ******************************************************************************/ 254 static void ccn_snoop_dvm_do_op(unsigned long long rn_id_map, 255 unsigned long long hn_id_map, 256 unsigned int region_id, 257 unsigned int op_reg_offset, 258 unsigned int stat_reg_offset) 259 { 260 unsigned int start_region_id; 261 262 assert(ccn_plat_desc); 263 assert(ccn_plat_desc->periphbase); 264 265 #if defined(IMAGE_BL31) || (defined(AARCH32) && defined(IMAGE_BL32)) 266 bakery_lock_get(&ccn_lock); 267 #endif 268 start_region_id = region_id; 269 FOR_EACH_PRESENT_REGION_ID(start_region_id, hn_id_map) { 270 ccn_reg_write(ccn_plat_desc->periphbase, 271 start_region_id, 272 op_reg_offset, 273 rn_id_map); 274 } 275 276 start_region_id = region_id; 277 278 FOR_EACH_PRESENT_REGION_ID(start_region_id, hn_id_map) { 279 WAIT_FOR_DOMAIN_CTRL_OP_COMPLETION(start_region_id, 280 stat_reg_offset, 281 op_reg_offset, 282 rn_id_map); 283 } 284 285 #if defined(IMAGE_BL31) || (defined(AARCH32) && defined(IMAGE_BL32)) 286 bakery_lock_release(&ccn_lock); 287 #endif 288 } 289 290 /******************************************************************************* 291 * The following functions provide the boot and runtime API to the platform for 292 * adding and removing master interfaces from the snoop/DVM domains. A bitmap of 293 * master interfaces IDs is passed as a parameter. It is converted into a bitmap 294 * of Request node IDs using the mapping provided by the platform while 295 * initialising the driver. 296 * For example, consider a dual cluster system where the clusters have values 0 297 * & 1 in the affinity level 1 field of their respective MPIDRs. While 298 * initialising this driver, the platform provides the mapping between each 299 * cluster and the corresponding Request node. To add or remove a cluster from 300 * the snoop and dvm domain, the bit position corresponding to the cluster ID 301 * should be set in the 'master_iface_map' i.e. to remove both clusters the 302 * bitmap would equal 0x11. 303 ******************************************************************************/ 304 void ccn_enter_snoop_dvm_domain(unsigned long long master_iface_map) 305 { 306 unsigned long long rn_id_map; 307 308 rn_id_map = ccn_master_to_rn_id_map(master_iface_map); 309 ccn_snoop_dvm_do_op(rn_id_map, 310 CCN_GET_HN_NODEID_MAP(ccn_plat_desc->periphbase, 311 MN_HNF_NODEID_OFFSET), 312 HNF_REGION_ID_START, 313 HNF_SDC_SET_OFFSET, 314 HNF_SDC_STAT_OFFSET); 315 316 ccn_snoop_dvm_do_op(rn_id_map, 317 CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase), 318 MN_REGION_ID, 319 MN_DDC_SET_OFFSET, 320 MN_DDC_STAT_OFFSET); 321 } 322 323 void ccn_exit_snoop_dvm_domain(unsigned long long master_iface_map) 324 { 325 unsigned long long rn_id_map; 326 327 rn_id_map = ccn_master_to_rn_id_map(master_iface_map); 328 ccn_snoop_dvm_do_op(rn_id_map, 329 CCN_GET_HN_NODEID_MAP(ccn_plat_desc->periphbase, 330 MN_HNF_NODEID_OFFSET), 331 HNF_REGION_ID_START, 332 HNF_SDC_CLR_OFFSET, 333 HNF_SDC_STAT_OFFSET); 334 335 ccn_snoop_dvm_do_op(rn_id_map, 336 CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase), 337 MN_REGION_ID, 338 MN_DDC_CLR_OFFSET, 339 MN_DDC_STAT_OFFSET); 340 } 341 342 void ccn_enter_dvm_domain(unsigned long long master_iface_map) 343 { 344 unsigned long long rn_id_map; 345 346 rn_id_map = ccn_master_to_rn_id_map(master_iface_map); 347 ccn_snoop_dvm_do_op(rn_id_map, 348 CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase), 349 MN_REGION_ID, 350 MN_DDC_SET_OFFSET, 351 MN_DDC_STAT_OFFSET); 352 } 353 354 void ccn_exit_dvm_domain(unsigned long long master_iface_map) 355 { 356 unsigned long long rn_id_map; 357 358 rn_id_map = ccn_master_to_rn_id_map(master_iface_map); 359 ccn_snoop_dvm_do_op(rn_id_map, 360 CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase), 361 MN_REGION_ID, 362 MN_DDC_CLR_OFFSET, 363 MN_DDC_STAT_OFFSET); 364 } 365 366 /******************************************************************************* 367 * This function returns the run mode of all the L3 cache partitions in the 368 * system. The state is expected to be one of NO_L3, SF_ONLY, L3_HAM or 369 * L3_FAM. Instead of comparing the states reported by all HN-Fs, the state of 370 * the first present HN-F node is reported. Since the driver does not export an 371 * interface to program them seperately, there is no reason to perform this 372 * check. An HN-F could report that the L3 cache is transitioning from one mode 373 * to another e.g. HNF_PM_NOL3_2_SFONLY. In this case, the function waits for 374 * the transition to complete and reports the final state. 375 ******************************************************************************/ 376 unsigned int ccn_get_l3_run_mode(void) 377 { 378 unsigned long long hnf_pstate_stat; 379 380 assert(ccn_plat_desc); 381 assert(ccn_plat_desc->periphbase); 382 383 /* 384 * Wait for a L3 cache paritition to enter any run mode. The pstate 385 * parameter is read from an HN-F P-state status register. A non-zero 386 * value in bits[1:0] means that the cache is transitioning to a run 387 * mode. 388 */ 389 do { 390 hnf_pstate_stat = ccn_reg_read(ccn_plat_desc->periphbase, 391 HNF_REGION_ID_START, 392 HNF_PSTATE_STAT_OFFSET); 393 } while (hnf_pstate_stat & 0x3); 394 395 return PSTATE_TO_RUN_MODE(hnf_pstate_stat); 396 } 397 398 /******************************************************************************* 399 * This function sets the run mode of all the L3 cache partitions in the 400 * system to one of NO_L3, SF_ONLY, L3_HAM or L3_FAM depending upon the state 401 * specified by the 'mode' argument. 402 ******************************************************************************/ 403 void ccn_set_l3_run_mode(unsigned int mode) 404 { 405 unsigned long long mn_hnf_id_map, hnf_pstate_stat; 406 unsigned int region_id; 407 408 assert(ccn_plat_desc); 409 assert(ccn_plat_desc->periphbase); 410 assert(mode <= CCN_L3_RUN_MODE_FAM); 411 412 mn_hnf_id_map = ccn_reg_read(ccn_plat_desc->periphbase, 413 MN_REGION_ID, 414 MN_HNF_NODEID_OFFSET); 415 region_id = HNF_REGION_ID_START; 416 417 /* Program the desired run mode */ 418 FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) { 419 ccn_reg_write(ccn_plat_desc->periphbase, 420 region_id, 421 HNF_PSTATE_REQ_OFFSET, 422 mode); 423 } 424 425 /* Wait for the caches to transition to the run mode */ 426 region_id = HNF_REGION_ID_START; 427 FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) { 428 /* 429 * Wait for a L3 cache paritition to enter a target run 430 * mode. The pstate parameter is read from an HN-F P-state 431 * status register. 432 */ 433 do { 434 hnf_pstate_stat = ccn_reg_read(ccn_plat_desc->periphbase, 435 region_id, 436 HNF_PSTATE_STAT_OFFSET); 437 } while (((hnf_pstate_stat & HNF_PSTATE_MASK) >> 2) != mode); 438 } 439 } 440 441 /******************************************************************************* 442 * This function configures system address map and provides option to enable the 443 * 3SN striping mode of Slave node operation. The Slave node IDs and the Top 444 * Address bit1 and bit0 are provided as parameters to this function. This 445 * configuration is needed only if network contains a single SN-F or 3 SN-F and 446 * must be completed before the first request by the system to normal memory. 447 ******************************************************************************/ 448 void ccn_program_sys_addrmap(unsigned int sn0_id, 449 unsigned int sn1_id, 450 unsigned int sn2_id, 451 unsigned int top_addr_bit0, 452 unsigned int top_addr_bit1, 453 unsigned char three_sn_en) 454 { 455 unsigned long long mn_hnf_id_map, hnf_sam_ctrl_value; 456 unsigned int region_id; 457 458 assert(ccn_plat_desc); 459 assert(ccn_plat_desc->periphbase); 460 461 mn_hnf_id_map = ccn_reg_read(ccn_plat_desc->periphbase, 462 MN_REGION_ID, 463 MN_HNF_NODEID_OFFSET); 464 region_id = HNF_REGION_ID_START; 465 hnf_sam_ctrl_value = MAKE_HNF_SAM_CTRL_VALUE(sn0_id, 466 sn1_id, 467 sn2_id, 468 top_addr_bit0, 469 top_addr_bit1, 470 three_sn_en); 471 472 FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) { 473 474 /* Program the SAM control register */ 475 ccn_reg_write(ccn_plat_desc->periphbase, 476 region_id, 477 HNF_SAM_CTRL_OFFSET, 478 hnf_sam_ctrl_value); 479 } 480 481 } 482 483 /******************************************************************************* 484 * This function returns the part0 id from the peripheralID 0 register 485 * in CCN. This id can be used to distinguish the CCN variant present in the 486 * system. 487 ******************************************************************************/ 488 int ccn_get_part0_id(uintptr_t periphbase) 489 { 490 assert(periphbase); 491 return (int)(mmio_read_64(periphbase 492 + MN_PERIPH_ID_0_1_OFFSET) & 0xFF); 493 } 494 495 /******************************************************************************* 496 * This function returns the region id corresponding to a node_id of node_type. 497 ******************************************************************************/ 498 static unsigned int get_region_id_for_node(node_types_t node_type, 499 unsigned int node_id) 500 { 501 unsigned int mn_reg_off, region_id; 502 unsigned long long node_bitmap; 503 unsigned int loc_node_id, node_pos_in_map = 0; 504 505 assert(node_type < NUM_NODE_TYPES); 506 assert(node_id < MAX_RN_NODES); 507 508 switch (node_type) { 509 case NODE_TYPE_RNI: 510 region_id = RNI_REGION_ID_START; 511 break; 512 case NODE_TYPE_HNF: 513 region_id = HNF_REGION_ID_START; 514 break; 515 case NODE_TYPE_HNI: 516 region_id = HNI_REGION_ID_START; 517 break; 518 case NODE_TYPE_SN: 519 region_id = SBSX_REGION_ID_START; 520 break; 521 default: 522 ERROR("Un-supported Node Type = %d.\n", node_type); 523 assert(false); 524 return REGION_ID_LIMIT; 525 } 526 /* 527 * RN-I, HN-F, HN-I, SN node registers in the MN region 528 * occupy contiguous 16 byte apart offsets. 529 * 530 * RN-F and RN-D node are not supported as 531 * none of them exposes any memory map to 532 * configure any of their offset registers. 533 */ 534 535 mn_reg_off = MN_RNF_NODEID_OFFSET + (node_type << 4); 536 node_bitmap = ccn_reg_read(ccn_plat_desc->periphbase, 537 MN_REGION_ID, mn_reg_off); 538 539 assert((node_bitmap & (1ULL << (node_id))) != 0U); 540 541 542 FOR_EACH_PRESENT_NODE_ID(loc_node_id, node_bitmap) { 543 INFO("Index = %u with loc_nod=%u and input nod=%u\n", 544 node_pos_in_map, loc_node_id, node_id); 545 if (loc_node_id == node_id) 546 break; 547 node_pos_in_map++; 548 } 549 550 if (node_pos_in_map == CCN_MAX_RN_MASTERS) { 551 ERROR("Node Id = %d, is not found.\n", node_id); 552 assert(false); 553 return REGION_ID_LIMIT; 554 } 555 556 region_id += node_pos_in_map; 557 558 return region_id; 559 } 560 561 /******************************************************************************* 562 * This function sets the value 'val' to the register at register_offset from 563 * the base address pointed to by the region_id. 564 * where, region id is mapped to a node_id of node_type. 565 ******************************************************************************/ 566 void ccn_write_node_reg(node_types_t node_type, unsigned int node_id, 567 unsigned int reg_offset, unsigned long long val) 568 { 569 unsigned int region_id = get_region_id_for_node(node_type, node_id); 570 571 if (reg_offset > REGION_ID_OFFSET) { 572 ERROR("Invalid Register offset 0x%x is provided.\n", 573 reg_offset); 574 assert(false); 575 return; 576 } 577 578 /* Setting the value of Auxilary Control Register of the Node */ 579 ccn_reg_write(ccn_plat_desc->periphbase, region_id, reg_offset, val); 580 VERBOSE("Value is successfully written at address 0x%lx.\n", 581 (ccn_plat_desc->periphbase 582 + region_id_to_base(region_id)) 583 + reg_offset); 584 } 585 586 /******************************************************************************* 587 * This function read the value 'val' stored in the register at register_offset 588 * from the base address pointed to by the region_id. 589 * where, region id is mapped to a node_id of node_type. 590 ******************************************************************************/ 591 unsigned long long ccn_read_node_reg(node_types_t node_type, 592 unsigned int node_id, 593 unsigned int reg_offset) 594 { 595 unsigned long long val; 596 unsigned int region_id = get_region_id_for_node(node_type, node_id); 597 598 if (reg_offset > REGION_ID_OFFSET) { 599 ERROR("Invalid Register offset 0x%x is provided.\n", 600 reg_offset); 601 assert(false); 602 return ULL(0); 603 } 604 605 /* Setting the value of Auxilary Control Register of the Node */ 606 val = ccn_reg_read(ccn_plat_desc->periphbase, region_id, reg_offset); 607 VERBOSE("Value is successfully read from address 0x%lx.\n", 608 (ccn_plat_desc->periphbase 609 + region_id_to_base(region_id)) 610 + reg_offset); 611 612 return val; 613 } 614