1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <cmn600.h>
9
10 #include <fwk_assert.h>
11 #include <fwk_math.h>
12
13 #include <stddef.h>
14
15 static unsigned int encoding_bits;
16 static unsigned int mask_bits;
17
18 static const char *const cmn600_rev_to_name[] = {
19 [CMN600_PERIPH_ID_2_REV_R1_P0] = "r1p0",
20 [CMN600_PERIPH_ID_2_REV_R1_P1] = "r1p1",
21 [CMN600_PERIPH_ID_2_REV_R1_P2] = "r1p2",
22 [CMN600_PERIPH_ID_2_REV_R1_P3] = "r1p3",
23 [CMN600_PERIPH_ID_2_REV_R2_P0] = "r2p0",
24 [CMN600_PERIPH_ID_2_REV_R3_P0] = "r3p0",
25 [CMN600_PERIPH_ID_2_REV_R3_P1] = "r3p1",
26 [CMN600_PERIPH_ID_2_REV_R3_P2] = "r3p2",
27 [CMN600_PERIPH_ID_UNKNOWN_REV] = "Unknown!",
28 };
29
get_node_child_count(void * node_base)30 unsigned int get_node_child_count(void *node_base)
31 {
32 struct node_header *node = node_base;
33 return node->CHILD_INFO & CMN600_CHILD_INFO_COUNT;
34 }
35
get_node_type(void * node_base)36 enum node_type get_node_type(void *node_base)
37 {
38 struct node_header *node = node_base;
39 return (enum node_type)(node->NODE_INFO & CMN600_NODE_INFO_TYPE);
40 }
41
get_node_id(void * node_base)42 unsigned int get_node_id(void *node_base)
43 {
44 struct node_header *node = node_base;
45 return (node->NODE_INFO & CMN600_NODE_INFO_ID) >> CMN600_NODE_INFO_ID_POS;
46 }
47
get_node_logical_id(void * node_base)48 unsigned int get_node_logical_id(void *node_base)
49 {
50 struct node_header *node = node_base;
51 return (node->NODE_INFO & CMN600_NODE_INFO_LOGICAL_ID) >>
52 CMN600_NODE_INFO_LOGICAL_ID_POS;
53 }
54
get_child_node(uintptr_t base,void * node_base,unsigned int child_index)55 void *get_child_node(uintptr_t base, void *node_base, unsigned int child_index)
56 {
57 struct node_header *node = node_base;
58 uint32_t child_pointer;
59 unsigned int offset;
60 void *child_node;
61
62 child_pointer = node->CHILD_POINTER[child_index];
63 offset = child_pointer & CMN600_CHILD_POINTER_OFFSET;
64
65 child_node = (void *)(base + offset);
66 return child_node;
67 }
68
get_child_node_id(void * node_base,unsigned int child_index)69 unsigned int get_child_node_id(void *node_base,
70 unsigned int child_index)
71 {
72 struct node_header *node = node_base;
73 uint32_t node_pointer;
74 unsigned int device_id;
75
76 node_pointer = (node->CHILD_POINTER[child_index] &
77 CMN600_CHILD_POINTER_EXT_NODE_POINTER) >>
78 CMN600_CHILD_POINTER_EXT_NODE_POINTER_POS;
79
80 device_id = (((node_pointer >> 6) & 0xff) << 3) |
81 ((node_pointer & 0x1) << 2) |
82 ((node_pointer >> 2) & 0x3);
83
84 return device_id;
85 }
86
get_cmn600_revision(struct cmn600_cfgm_reg * root)87 unsigned int get_cmn600_revision(struct cmn600_cfgm_reg *root)
88 {
89 return (
90 (root->PERIPH_ID[1] & CMN600_PERIPH_ID_2_MASK) >>
91 CMN600_PERIPH_ID_2_REV_POS);
92 }
93
get_cmn600_revision_name(struct cmn600_cfgm_reg * root)94 const char *get_cmn600_revision_name(struct cmn600_cfgm_reg *root)
95 {
96 unsigned int revision;
97
98 revision = get_cmn600_revision(root);
99 if (revision > CMN600_PERIPH_ID_UNKNOWN_REV) {
100 revision = CMN600_PERIPH_ID_UNKNOWN_REV;
101 fwk_unexpected();
102 }
103
104 return cmn600_rev_to_name[revision];
105 }
106
is_cal_mode_supported(struct cmn600_cfgm_reg * root)107 bool is_cal_mode_supported(struct cmn600_cfgm_reg *root)
108 {
109 return (get_cmn600_revision(root) >= CMN600_PERIPH_ID_2_REV_R2_P0) ?
110 true : false;
111 }
112
is_child_external(void * node_base,unsigned int child_index)113 bool is_child_external(void *node_base, unsigned int child_index)
114 {
115 struct node_header *node = node_base;
116 return !!(node->CHILD_POINTER[child_index] & (UINT64_C(1) << 31));
117 }
118
get_port_number(unsigned int child_node_id)119 bool get_port_number(unsigned int child_node_id)
120 {
121 return (child_node_id >> CMN600_NODE_ID_PORT_POS) &
122 CMN600_NODE_ID_PORT_MASK;
123 }
124
get_device_type(void * mxp_base,bool port)125 unsigned int get_device_type(void *mxp_base, bool port)
126 {
127 struct cmn600_mxp_reg *mxp = mxp_base;
128 return mxp->PORT_CONNECT_INFO[port] &
129 CMN600_MXP_PORT_CONNECT_INFO_DEVICE_TYPE_MASK;
130 }
131
sam_encode_region_size(uint64_t size)132 uint64_t sam_encode_region_size(uint64_t size)
133 {
134 uint64_t blocks;
135 uint64_t result;
136
137 /* Size must be a multiple of SAM_GRANULARITY */
138 fwk_assert((size % SAM_GRANULARITY) == 0);
139
140 /* Size also must be a power of two */
141 fwk_assert((size & (size - 1)) == 0);
142
143 blocks = size / SAM_GRANULARITY;
144 result = fwk_math_log2(blocks);
145
146 return result;
147 }
148
configure_region(volatile uint64_t * reg,unsigned int bit_offset,uint64_t base,uint64_t size,enum sam_node_type node_type)149 void configure_region(volatile uint64_t *reg, unsigned int bit_offset,
150 uint64_t base, uint64_t size, enum sam_node_type node_type)
151 {
152 uint64_t value;
153
154 fwk_assert(reg != NULL);
155 fwk_assert((base % size) == 0);
156
157 value = CMN600_RNSAM_REGION_ENTRY_VALID;
158 value |= node_type << CMN600_RNSAM_REGION_ENTRY_TYPE_POS;
159 value |= sam_encode_region_size(size) << CMN600_RNSAM_REGION_ENTRY_SIZE_POS;
160 value |= (base / SAM_GRANULARITY) << CMN600_RNSAM_REGION_ENTRY_BASE_POS;
161
162 *reg &= ~(CMN600_RNSAM_REGION_ENTRY_MASK << bit_offset);
163 *reg |= value << bit_offset;
164 }
165
166 static const char * const type_to_name[] = {
167 [NODE_TYPE_INVALID] = "<Invalid>",
168 [NODE_TYPE_DVM] = "DVM",
169 [NODE_TYPE_CFG] = "CFG",
170 [NODE_TYPE_DTC] = "DTC",
171 [NODE_TYPE_HN_I] = "HN-I",
172 [NODE_TYPE_HN_F] = "HN-F",
173 [NODE_TYPE_XP] = "XP",
174 [NODE_TYPE_SBSX] = "SBSX",
175 [NODE_TYPE_RN_I] = "RN-I",
176 [NODE_TYPE_RN_D] = "RN-D",
177 [NODE_TYPE_RN_SAM] = "RN-SAM",
178 };
179
180 static const char * const type_to_name_cml[] = {
181 [NODE_TYPE_CXRA - NODE_TYPE_CML_BASE] = "CXRA",
182 [NODE_TYPE_CXHA - NODE_TYPE_CML_BASE] = "CXHA",
183 [NODE_TYPE_CXLA - NODE_TYPE_CML_BASE] = "CXLA",
184
185 };
186
get_node_type_name(enum node_type node_type)187 const char *get_node_type_name(enum node_type node_type)
188 {
189 /* Base node IDs */
190 if (node_type <= NODE_TYPE_RN_SAM)
191 return type_to_name[node_type];
192
193 /* CML node IDs */
194 if ((node_type >= NODE_TYPE_CML_BASE) &&
195 (node_type <= NODE_TYPE_CXLA))
196 return type_to_name_cml[node_type - NODE_TYPE_CML_BASE];
197
198 /* Invalid node IDs */
199 return type_to_name[NODE_TYPE_INVALID];
200 }
201
get_node_pos_x(void * node_base)202 unsigned int get_node_pos_x(void *node_base)
203 {
204 struct node_header *node = node_base;
205 return (get_node_id(node) >> (CMN600_NODE_ID_Y_POS + encoding_bits)) &
206 mask_bits;
207 }
208
get_node_pos_y(void * node_base)209 unsigned int get_node_pos_y(void *node_base)
210 {
211 struct node_header *node = node_base;
212 return (get_node_id(node) >> CMN600_NODE_ID_Y_POS) & mask_bits;
213 }
214
get_root_node(uintptr_t base,unsigned int hnd_node_id,unsigned int mesh_size_x,unsigned int mesh_size_y)215 struct cmn600_cfgm_reg *get_root_node(uintptr_t base, unsigned int hnd_node_id,
216 unsigned int mesh_size_x, unsigned int mesh_size_y)
217 {
218 unsigned int node_pos_x;
219 unsigned int node_pos_y;
220 unsigned int node_port;
221 uintptr_t offset;
222
223 /*
224 * Determine the number of bits used to represent each node coordinate based
225 * on the mesh size as per CMN600 specification.
226 */
227 encoding_bits = ((mesh_size_x > 4) || (mesh_size_y > 4)) ? 3 : 2;
228
229 /* Extract node coordinates from the node identifier */
230 mask_bits = (1 << encoding_bits) - 1;
231 node_pos_y = (hnd_node_id >> CMN600_NODE_ID_Y_POS) & mask_bits;
232 node_pos_x = (hnd_node_id >> (CMN600_NODE_ID_Y_POS + encoding_bits)) &
233 mask_bits;
234 node_port = (hnd_node_id >> CMN600_NODE_ID_PORT_POS) &
235 CMN600_NODE_ID_PORT_MASK;
236
237 /* Calculate node address offset */
238 offset = (node_pos_y << CMN600_ROOT_NODE_OFFSET_Y_POS) |
239 (node_pos_x << (CMN600_ROOT_NODE_OFFSET_Y_POS + encoding_bits)) |
240 (node_port << CMN600_ROOT_NODE_OFFSET_PORT_POS);
241
242 return (struct cmn600_cfgm_reg *)(base + offset);
243 }
244