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