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 <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(AARCH32) && 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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(AARCH32) && 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(AARCH32) && 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 ******************************************************************************/ 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 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 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 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 seperately, 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) 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 paritition 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 ******************************************************************************/ 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 paritition 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 ******************************************************************************/ 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 Auxilary 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 ******************************************************************************/ 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 Auxilary 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