1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <cmn700.h>
9 
10 #include <fwk_assert.h>
11 #include <fwk_log.h>
12 #include <fwk_math.h>
13 
14 #include <inttypes.h>
15 
16 #define MOD_NAME "[CMN700] "
17 
18 /*
19  * Encoding bits size of the X and Y position in the Node info value.
20  * If X and Y dimension are less than 4, encoding bits size will be 2.
21  * If X and Y dimension are between 5 and 8, encoding bits size will be 3.
22  */
23 static unsigned int encoding_bits;
24 static unsigned int mask_bits;
25 
26 static const char *const cmn700_rev_to_name[] = {
27     [CMN700_PERIPH_ID_2_REV_R0_P0] = "r0p0",
28     [CMN700_PERIPH_ID_2_REV_R1_P0] = "r1p0",
29     [CMN700_PERIPH_ID_2_REV_R1_P1] = "r1p1",
30     [CMN700_PERIPH_ID_2_REV_R2_P0] = "r2p0",
31     [CMN700_PERIPH_ID_UNKNOWN_REV] = "Unknown!",
32 };
33 
get_node_device_port_count(void * node_base)34 unsigned int get_node_device_port_count(void *node_base)
35 {
36     struct node_header *node = node_base;
37     return (node->NODE_INFO & CMN700_MXP_NODE_INFO_NUM_DEVICE_PORT_MASK) >>
38         CMN700_MXP_NODE_INFO_NUM_DEVICE_PORT_POS;
39 }
40 
get_node_child_count(void * node_base)41 unsigned int get_node_child_count(void *node_base)
42 {
43     struct node_header *node = node_base;
44     return node->CHILD_INFO & CMN700_CHILD_INFO_COUNT;
45 }
46 
get_node_type(void * node_base)47 enum node_type get_node_type(void *node_base)
48 {
49     struct node_header *node = node_base;
50     return (enum node_type)(node->NODE_INFO & CMN700_NODE_INFO_TYPE);
51 }
52 
get_node_id(void * node_base)53 unsigned int get_node_id(void *node_base)
54 {
55     struct node_header *node = node_base;
56     return (node->NODE_INFO & CMN700_NODE_INFO_ID) >> CMN700_NODE_INFO_ID_POS;
57 }
58 
get_node_logical_id(void * node_base)59 unsigned int get_node_logical_id(void *node_base)
60 {
61     struct node_header *node = node_base;
62     return (node->NODE_INFO & CMN700_NODE_INFO_LOGICAL_ID) >>
63         CMN700_NODE_INFO_LOGICAL_ID_POS;
64 }
65 
get_child_node(uintptr_t base,void * node_base,unsigned int child_index)66 void *get_child_node(uintptr_t base, void *node_base, unsigned int child_index)
67 {
68     struct node_header *node = node_base;
69     uint32_t child_pointer;
70     unsigned int offset;
71     void *child_node;
72 
73     child_pointer = node->CHILD_POINTER[child_index];
74     offset = child_pointer & CMN700_CHILD_POINTER_OFFSET;
75 
76     child_node = (void *)(base + offset);
77     return child_node;
78 }
79 
get_child_node_id(void * node_base,unsigned int child_index)80 unsigned int get_child_node_id(void *node_base, unsigned int child_index)
81 {
82     struct node_header *node = node_base;
83     uint32_t node_pointer;
84     unsigned int node_id;
85 
86     node_pointer = (node->CHILD_POINTER[child_index] &
87                     CMN700_CHILD_POINTER_EXT_NODE_POINTER) >>
88         CMN700_CHILD_POINTER_EXT_NODE_POINTER_POS;
89 
90     /*
91      * For mesh widths using 2 bits each for X,Y encoding:
92      * NodeID[1:0] = DeviceID[3:2]
93      * NodeID[2]   = DeviceID[0]
94      * NodeID[4:3] = NODE POINTER[7:6]
95      * NodeID[6:5] = NODE POINTER[9:8]
96      *
97      * For mesh widths using 3 bits each for X,Y encoding:
98      * NodeID[1:0] = DeviceID[3:2]
99      * NodeID[2]   = DeviceID[0]
100      * NodeID[5:3] = NODE POINTER[8:6]
101      * NodeID[8:6] = NODE POINTER[11:9]
102      */
103     node_id = (((node_pointer >> 6) & 0xff) << 3) |
104         ((node_pointer & 0x1) << 2) | ((node_pointer >> 2) & 0x3);
105 
106     return node_id;
107 }
108 
get_cmn700_revision(struct cmn700_cfgm_reg * root)109 unsigned int get_cmn700_revision(struct cmn700_cfgm_reg *root)
110 {
111     return (root->PERIPH_ID[1] & CMN700_PERIPH_ID_2_MASK) >>
112         CMN700_PERIPH_ID_2_REV_POS;
113 }
114 
get_cmn700_revision_name(struct cmn700_cfgm_reg * root)115 const char *get_cmn700_revision_name(struct cmn700_cfgm_reg *root)
116 {
117     unsigned int revision;
118 
119     revision = get_cmn700_revision(root);
120     if (revision > CMN700_PERIPH_ID_UNKNOWN_REV)
121         revision = CMN700_PERIPH_ID_UNKNOWN_REV;
122 
123     return cmn700_rev_to_name[revision];
124 }
125 
is_child_external(void * node_base,unsigned int child_index)126 bool is_child_external(void *node_base, unsigned int child_index)
127 {
128     struct node_header *node = node_base;
129     return !!(node->CHILD_POINTER[child_index] & (1U << 31));
130 }
131 
get_port_number(unsigned int child_node_id,unsigned int xp_port_cnt)132 unsigned int get_port_number(
133     unsigned int child_node_id,
134     unsigned int xp_port_cnt)
135 {
136     if (xp_port_cnt == 2) {
137         return (child_node_id >> CMN700_NODE_ID_PORT_POS) &
138             CMN700_NODE_ID_PORT_MASK;
139     } else {
140         /* For port counts 3 and 4 */
141         return (child_node_id >> CMN700_MULTI_PORTS_NODE_ID_PORT_POS) &
142             CMN700_MULTI_PORTS_NODE_ID_PORT_MASK;
143     }
144 }
145 
get_device_type(void * mxp_base,int port)146 unsigned int get_device_type(void *mxp_base, int port)
147 {
148     struct cmn700_mxp_reg *mxp = mxp_base;
149     return mxp->PORT_CONNECT_INFO[port] &
150         CMN700_MXP_PORT_CONNECT_INFO_DEVICE_TYPE_MASK;
151 }
152 
is_cal_connected(void * mxp_base,bool port)153 bool is_cal_connected(void *mxp_base, bool port)
154 {
155     struct cmn700_mxp_reg *mxp = mxp_base;
156     return (mxp->PORT_CONNECT_INFO[port] &
157             CMN700_MXP_PORT_CONNECT_INFO_CAL_CONNECTED_MASK) >>
158         CMN700_MXP_PORT_CONNECT_INFO_CAL_CONNECTED_POS;
159 }
160 
is_device_type_rnf(void * mxp_base,bool port)161 bool is_device_type_rnf(void *mxp_base, bool port)
162 {
163     return (
164         (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHIB_ESAM) ||
165         (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHIC_ESAM) ||
166         (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHID_ESAM) ||
167         (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHIE_ESAM));
168 }
169 
get_rnsam_htg_rcomp_lsb_bit_pos(void * rnsam_reg)170 static unsigned int get_rnsam_htg_rcomp_lsb_bit_pos(void *rnsam_reg)
171 {
172     struct cmn700_rnsam_reg *rnsam = rnsam_reg;
173     return (
174         rnsam->UNIT_INFO[1] & CMN700_RNSAM_UNIT_INFO_HTG_RCOMP_LSB_PARAM_MASK);
175 }
176 
get_rnsam_nonhash_rcomp_lsb_bit_pos(void * rnsam_reg)177 static unsigned int get_rnsam_nonhash_rcomp_lsb_bit_pos(void *rnsam_reg)
178 {
179     struct cmn700_rnsam_reg *rnsam = rnsam_reg;
180     return (rnsam->UNIT_INFO[1] &
181             CMN700_RNSAM_UNIT_INFO_NONHASH_RCOMP_LSB_PARAM_MASK) >>
182         CMN700_RNSAM_UNIT_INFO_NONHASH_RCOMP_LSB_PARAM_POS;
183 }
184 
get_rnsam_lsb_addr_mask(void * rnsam_reg,enum sam_type sam_type)185 static uint64_t get_rnsam_lsb_addr_mask(void *rnsam_reg, enum sam_type sam_type)
186 {
187     uint64_t lsb_bit_pos;
188     struct cmn700_rnsam_reg *rnsam = rnsam_reg;
189 
190     lsb_bit_pos = (sam_type == SAM_TYPE_NON_HASH_MEM_REGION) ?
191         get_rnsam_nonhash_rcomp_lsb_bit_pos(rnsam) :
192         get_rnsam_htg_rcomp_lsb_bit_pos(rnsam);
193 
194     return (1 << lsb_bit_pos) - 1;
195 }
196 
get_rnsam_nonhash_range_comp_en_mode(void * rnsam_reg)197 bool get_rnsam_nonhash_range_comp_en_mode(void *rnsam_reg)
198 {
199     struct cmn700_rnsam_reg *rnsam = rnsam_reg;
200     return (rnsam->UNIT_INFO[0] &
201             CMN700_RNSAM_UNIT_INFO_NONHASH_RANGE_COMP_EN_MASK) >>
202         CMN700_RNSAM_UNIT_INFO_NONHASH_RANGE_COMP_EN_POS;
203 }
204 
get_rnsam_htg_range_comp_en_mode(void * rnsam_reg)205 bool get_rnsam_htg_range_comp_en_mode(void *rnsam_reg)
206 {
207     struct cmn700_rnsam_reg *rnsam = rnsam_reg;
208     return (rnsam->UNIT_INFO[0] &
209             CMN700_RNSAM_UNIT_INFO_HTG_RANGE_COMP_EN_MASK) >>
210         CMN700_RNSAM_UNIT_INFO_HTG_RANGE_COMP_EN_POS;
211 }
212 
get_hnsam_range_comp_en_mode(void * hnf_reg)213 bool get_hnsam_range_comp_en_mode(void *hnf_reg)
214 {
215     struct cmn700_hnf_reg *hnf = hnf_reg;
216     return (hnf->UNIT_INFO[1] & CMN700_HNF_UNIT_INFO_HNSAM_RCOMP_EN_MASK) >>
217         CMN700_HNF_UNIT_INFO_HNSAM_RCOMP_EN_POS;
218 }
219 
sam_encode_region_size(uint64_t size)220 uint64_t sam_encode_region_size(uint64_t size)
221 {
222     uint64_t blocks;
223     uint64_t result;
224 
225     /* Size must be a multiple of SAM_GRANULARITY */
226     fwk_assert((size % SAM_GRANULARITY) == 0);
227 
228     /* Size also must be a power of two */
229     fwk_assert((size & (size - 1)) == 0);
230 
231     blocks = size / SAM_GRANULARITY;
232     result = fwk_math_log2(blocks);
233 
234     return result;
235 }
236 
configure_region(void * rnsam_reg,unsigned int region_idx,uint64_t base,uint64_t size,enum sam_node_type node_type,enum sam_type sam_type)237 void configure_region(
238     void *rnsam_reg,
239     unsigned int region_idx,
240     uint64_t base,
241     uint64_t size,
242     enum sam_node_type node_type,
243     enum sam_type sam_type)
244 {
245     bool prog_start_and_end_addr;
246     uint64_t lsb_addr_mask;
247     uint64_t value;
248     struct cmn700_rnsam_reg *rnsam = rnsam_reg;
249     volatile uint64_t *reg;
250     volatile uint64_t *reg_cfg2;
251 
252     fwk_assert(rnsam_reg);
253 
254     if (sam_type == SAM_TYPE_NON_HASH_MEM_REGION) {
255         if (region_idx >= MAX_NON_HASH_MEM_COUNT) {
256             FWK_LOG_ERR(
257                 MOD_NAME
258                 "Region idx: %d should be less than max non hash region count "
259                 "of %d",
260                 region_idx,
261                 MAX_NON_HASH_MEM_COUNT);
262             fwk_unexpected();
263         }
264 
265         if (region_idx < NON_HASH_MEM_REG_COUNT) {
266             reg = &rnsam->NON_HASH_MEM_REGION[region_idx];
267             reg_cfg2 = &rnsam->NON_HASH_MEM_REGION_CFG2[region_idx];
268         } else {
269             reg = &rnsam->NON_HASH_MEM_REGION_GRP2
270                        [region_idx - NON_HASH_MEM_REG_COUNT];
271             reg_cfg2 = &rnsam->NON_HASH_MEM_REGION_CFG2_GRP2
272                             [region_idx - NON_HASH_MEM_REG_COUNT];
273         }
274     } else if (sam_type == SAM_TYPE_SYS_CACHE_GRP_REGION) {
275         if (region_idx >= MAX_SCG_COUNT) {
276             FWK_LOG_ERR(
277                 MOD_NAME
278                 "Region idx: %d should be less then max SCG region count of %d",
279                 region_idx,
280                 MAX_SCG_COUNT);
281             fwk_unexpected();
282         }
283         reg = &rnsam->SYS_CACHE_GRP_REGION[region_idx];
284         reg_cfg2 = &rnsam->HASHED_TGT_GRP_CFG2_REGION[region_idx];
285     } else {
286         FWK_LOG_ERR(MOD_NAME "Unexpected sam_type!");
287         fwk_unexpected();
288         return;
289     }
290 
291     /* Check if the start and end address has to be programmed */
292     prog_start_and_end_addr = (sam_type == SAM_TYPE_NON_HASH_MEM_REGION) ?
293         get_rnsam_nonhash_range_comp_en_mode(rnsam) :
294         get_rnsam_htg_range_comp_en_mode(rnsam);
295 
296     if ((!prog_start_and_end_addr) && ((base % size) != 0)) {
297         FWK_LOG_ERR(
298             MOD_NAME "Base: 0x%" PRIx64 " should align with Size: 0x%" PRIx64,
299             base,
300             size);
301         fwk_unexpected();
302     }
303 
304     /* Get the LSB mask from LSB bit position defining minimum region size */
305     lsb_addr_mask = get_rnsam_lsb_addr_mask(rnsam, sam_type);
306 
307     value = CMN700_RNSAM_REGION_ENTRY_VALID;
308     value |= node_type << CMN700_RNSAM_REGION_ENTRY_TYPE_POS;
309 
310     if (prog_start_and_end_addr) {
311         value |= (base & ~lsb_addr_mask);
312         *reg = value;
313         *reg_cfg2 = (base + size - 1) & ~lsb_addr_mask;
314     } else {
315         value |= sam_encode_region_size(size)
316             << CMN700_RNSAM_REGION_ENTRY_SIZE_POS;
317         value |= (base / SAM_GRANULARITY) << CMN700_RNSAM_REGION_ENTRY_BASE_POS;
318         *reg = value;
319     }
320 }
321 
322 static const char *const type_to_name[] = {
323     [NODE_TYPE_INVALID]     = "<Invalid>",
324     [NODE_TYPE_DVM]         = "DVM",
325     [NODE_TYPE_CFG]         = "CFG",
326     [NODE_TYPE_DTC]         = "DTC",
327     [NODE_TYPE_HN_I]        = "HN-I",
328     [NODE_TYPE_HN_F]        = "HN-F",
329     [NODE_TYPE_XP]          = "XP",
330     [NODE_TYPE_SBSX]        = "SBSX",
331     [NODE_TYPE_MPAM_S]      = "MPAM-S",
332     [NODE_TYPE_MPAM_NS]     = "MPAM-NS",
333     [NODE_TYPE_RN_I]        = "RN-I",
334     [NODE_TYPE_RN_D]        = "RN-D",
335     [NODE_TYPE_RN_SAM]      = "RN-SAM",
336     [NODE_TYPE_HN_P]        = "HN-P",
337 };
338 
339 static const char *const type_to_name_cml[] = {
340     [NODE_TYPE_CXRA - NODE_TYPE_CML_BASE] = "CXRA",
341     [NODE_TYPE_CXHA - NODE_TYPE_CML_BASE] = "CXHA",
342     [NODE_TYPE_CXLA - NODE_TYPE_CML_BASE] = "CXLA",
343     [NODE_TYPE_CCRA - NODE_TYPE_CML_BASE] = "CCRA",
344     [NODE_TYPE_CCHA - NODE_TYPE_CML_BASE] = "CCHA",
345     [NODE_TYPE_CCLA - NODE_TYPE_CML_BASE] = "CCLA",
346 };
347 
get_node_type_name(enum node_type node_type)348 const char *get_node_type_name(enum node_type node_type)
349 {
350     /* Base node IDs */
351     if (node_type <= NODE_TYPE_HN_P)
352         return type_to_name[node_type];
353 
354     /* CML node IDs */
355     if ((node_type >= NODE_TYPE_CML_BASE) && (node_type <= NODE_TYPE_CCLA))
356         return type_to_name_cml[node_type - NODE_TYPE_CML_BASE];
357 
358     /* Invalid node IDs */
359     return type_to_name[NODE_TYPE_INVALID];
360 }
361 
get_node_pos_x(void * node_base)362 unsigned int get_node_pos_x(void *node_base)
363 {
364     struct node_header *node = node_base;
365     return (get_node_id(node) >> (CMN700_NODE_ID_Y_POS + encoding_bits)) &
366         mask_bits;
367 }
368 
get_node_pos_y(void * node_base)369 unsigned int get_node_pos_y(void *node_base)
370 {
371     struct node_header *node = node_base;
372     return (get_node_id(node) >> CMN700_NODE_ID_Y_POS) & mask_bits;
373 }
374 
set_encoding_and_masking_bits(const struct mod_cmn700_config * config)375 void set_encoding_and_masking_bits(const struct mod_cmn700_config *config)
376 {
377     unsigned int mesh_size_x;
378     unsigned int mesh_size_y;
379 
380     mesh_size_x = config->mesh_size_x;
381     mesh_size_y = config->mesh_size_y;
382 
383     /*
384      * Determine the number of bits used to represent each node coordinate based
385      * on the mesh size as per CMN700 specification.
386      */
387     if ((mesh_size_x > 8) || (mesh_size_y > 8)) {
388         encoding_bits = 4;
389     } else {
390         encoding_bits = ((mesh_size_x > 4) || (mesh_size_y > 4)) ? 3 : 2;
391     }
392 
393     /* Extract node coordinates from the node identifier */
394 
395     mask_bits = (1 << encoding_bits) - 1;
396 }
397