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