Home | History | Annotate | Download | only in ccn
      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