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