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 <cmn650.h>
9
10 #include <fwk_assert.h>
11 #include <fwk_math.h>
12
13 /*
14 * Encoding bits size of the X and Y position in the Node info value.
15 * If X and Y dimension are less than 4, encoding bits size will be 2.
16 * If X and Y dimension are between 5 and 8, encoding bits size will be 3.
17 */
18 static unsigned int encoding_bits;
19 static unsigned int mask_bits;
20
21 static const char *const cmn650_rev_to_name[] = {
22 [CMN650_PERIPH_ID_2_REV_R0_P0] = "r0p0",
23 [CMN650_PERIPH_ID_2_REV_R1_P0] = "r1p0",
24 [CMN650_PERIPH_ID_2_REV_R1_P1] = "r1p1",
25 [CMN650_PERIPH_ID_2_REV_R2_P0] = "r2p0",
26 [CMN650_PERIPH_ID_UNKNOWN_REV] = "Unknown!",
27 };
28
get_node_child_count(void * node_base)29 unsigned int get_node_child_count(void *node_base)
30 {
31 struct node_header *node = node_base;
32 return node->CHILD_INFO & CMN650_CHILD_INFO_COUNT;
33 }
34
get_node_type(void * node_base)35 enum node_type get_node_type(void *node_base)
36 {
37 struct node_header *node = node_base;
38 return (enum node_type)(node->NODE_INFO & CMN650_NODE_INFO_TYPE);
39 }
40
get_node_id(void * node_base)41 unsigned int get_node_id(void *node_base)
42 {
43 struct node_header *node = node_base;
44 return (node->NODE_INFO & CMN650_NODE_INFO_ID) >> CMN650_NODE_INFO_ID_POS;
45 }
46
get_node_logical_id(void * node_base)47 unsigned int get_node_logical_id(void *node_base)
48 {
49 struct node_header *node = node_base;
50 return (node->NODE_INFO & CMN650_NODE_INFO_LOGICAL_ID) >>
51 CMN650_NODE_INFO_LOGICAL_ID_POS;
52 }
53
get_child_node(uintptr_t base,void * node_base,unsigned int child_index)54 void *get_child_node(uintptr_t base, void *node_base, unsigned int child_index)
55 {
56 struct node_header *node = node_base;
57 uint32_t child_pointer;
58 unsigned int offset;
59 void *child_node;
60
61 child_pointer = node->CHILD_POINTER[child_index];
62 offset = child_pointer & CMN650_CHILD_POINTER_OFFSET;
63
64 child_node = (void *)(base + offset);
65 return child_node;
66 }
67
get_child_node_id(void * node_base,unsigned int child_index)68 unsigned int get_child_node_id(void *node_base, unsigned int child_index)
69 {
70 struct node_header *node = node_base;
71 uint32_t node_pointer;
72 unsigned int node_id;
73
74 node_pointer = (node->CHILD_POINTER[child_index] &
75 CMN650_CHILD_POINTER_EXT_NODE_POINTER) >>
76 CMN650_CHILD_POINTER_EXT_NODE_POINTER_POS;
77
78 /*
79 * For mesh widths using 2 bits each for X,Y encoding:
80 * NodeID[1:0] = DeviceID[3:2]
81 * NodeID[2] = DeviceID[0]
82 * NodeID[4:3] = NODE POINTER[7:6]
83 * NodeID[6:5] = NODE POINTER[9:8]
84 *
85 * For mesh widths using 3 bits each for X,Y encoding:
86 * NodeID[1:0] = DeviceID[3:2]
87 * NodeID[2] = DeviceID[0]
88 * NodeID[5:3] = NODE POINTER[8:6]
89 * NodeID[8:6] = NODE POINTER[11:9]
90 */
91 node_id = (((node_pointer >> 6) & 0xff) << 3) |
92 ((node_pointer & 0x1) << 2) | ((node_pointer >> 2) & 0x3);
93
94 return node_id;
95 }
96
get_cmn650_revision(struct cmn650_cfgm_reg * root)97 unsigned int get_cmn650_revision(struct cmn650_cfgm_reg *root)
98 {
99 return (root->PERIPH_ID[1] & CMN650_PERIPH_ID_2_MASK) >>
100 CMN650_PERIPH_ID_2_REV_POS;
101 }
102
get_cmn650_revision_name(struct cmn650_cfgm_reg * root)103 const char *get_cmn650_revision_name(struct cmn650_cfgm_reg *root)
104 {
105 unsigned int revision;
106
107 revision = get_cmn650_revision(root);
108 if (revision > CMN650_PERIPH_ID_UNKNOWN_REV)
109 revision = CMN650_PERIPH_ID_UNKNOWN_REV;
110
111 return cmn650_rev_to_name[revision];
112 }
113
is_child_external(void * node_base,unsigned int child_index)114 bool is_child_external(void *node_base, unsigned int child_index)
115 {
116 struct node_header *node = node_base;
117 return !!(node->CHILD_POINTER[child_index] & (1U << 31));
118 }
119
get_port_number(unsigned int child_node_id)120 bool get_port_number(unsigned int child_node_id)
121 {
122 return (child_node_id >> CMN650_NODE_ID_PORT_POS) &
123 CMN650_NODE_ID_PORT_MASK;
124 }
125
get_device_type(void * mxp_base,bool port)126 unsigned int get_device_type(void *mxp_base, bool port)
127 {
128 struct cmn650_mxp_reg *mxp = mxp_base;
129 return mxp->PORT_CONNECT_INFO[port] &
130 CMN650_MXP_PORT_CONNECT_INFO_DEVICE_TYPE_MASK;
131 }
132
is_cal_connected(void * mxp_base,uint8_t port)133 bool is_cal_connected(void *mxp_base, uint8_t port)
134 {
135 struct cmn650_mxp_reg *mxp = mxp_base;
136 return (mxp->PORT_CONNECT_INFO[port] &
137 CMN650_MXP_PORT_CONNECT_INFO_CAL_CONNECTED_MASK) >>
138 CMN650_MXP_PORT_CONNECT_INFO_CAL_CONNECTED_POS;
139 }
140
is_device_type_rnf(void * mxp_base,uint8_t port)141 bool is_device_type_rnf(void *mxp_base, uint8_t port)
142 {
143 return (
144 (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHIB_ESAM) ||
145 (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHIC_ESAM) ||
146 (get_device_type(mxp_base, port) == DEVICE_TYPE_RN_F_CHID_ESAM));
147 }
148
sam_encode_region_size(uint64_t size)149 uint64_t sam_encode_region_size(uint64_t size)
150 {
151 uint64_t blocks;
152 uint64_t result;
153
154 /* Size must be a multiple of SAM_GRANULARITY */
155 fwk_assert((size % SAM_GRANULARITY) == 0);
156
157 /* Size also must be a power of two */
158 fwk_assert((size & (size - 1)) == 0);
159
160 blocks = size / SAM_GRANULARITY;
161 result = fwk_math_log2(blocks);
162
163 return result;
164 }
165
configure_region(volatile uint64_t * reg,uint64_t base,uint64_t size,enum sam_node_type node_type)166 void configure_region(
167 volatile uint64_t *reg,
168 uint64_t base,
169 uint64_t size,
170 enum sam_node_type node_type)
171 {
172 uint64_t value;
173
174 fwk_assert(reg);
175 fwk_assert((base % size) == 0);
176
177 value = CMN650_RNSAM_REGION_ENTRY_VALID;
178 value |= node_type << CMN650_RNSAM_REGION_ENTRY_TYPE_POS;
179 value |= sam_encode_region_size(size) << CMN650_RNSAM_REGION_ENTRY_SIZE_POS;
180 value |= (base / SAM_GRANULARITY) << CMN650_RNSAM_REGION_ENTRY_BASE_POS;
181
182 *reg = value;
183 }
184
185 static const char * const type_to_name[] = {
186 [NODE_TYPE_INVALID] = "<Invalid>",
187 [NODE_TYPE_DVM] = "DVM",
188 [NODE_TYPE_CFG] = "CFG",
189 [NODE_TYPE_DTC] = "DTC",
190 [NODE_TYPE_HN_I] = "HN-I",
191 [NODE_TYPE_HN_F] = "HN-F",
192 [NODE_TYPE_XP] = "XP",
193 [NODE_TYPE_SBSX] = "SBSX",
194 [NODE_TYPE_MPAM_S] = "MPAM-S",
195 [NODE_TYPE_MPAM_NS] = "MPAM-NS",
196 [NODE_TYPE_RN_I] = "RN-I",
197 [NODE_TYPE_RN_D] = "RN-D",
198 [NODE_TYPE_RN_SAM] = "RN-SAM",
199 };
200
201 static const char *const type_to_name_cml[] = {
202 [NODE_TYPE_CXRA - NODE_TYPE_CML_BASE] = "CXRA",
203 [NODE_TYPE_CXHA - NODE_TYPE_CML_BASE] = "CXHA",
204 [NODE_TYPE_CXLA - NODE_TYPE_CML_BASE] = "CXLA",
205
206 };
207
get_node_type_name(enum node_type node_type)208 const char *get_node_type_name(enum node_type node_type)
209 {
210 /* Base node IDs */
211 if (node_type <= NODE_TYPE_RN_SAM)
212 return type_to_name[node_type];
213
214 /* CML node IDs */
215 if ((node_type >= NODE_TYPE_CML_BASE) && (node_type <= NODE_TYPE_CXLA))
216 return type_to_name_cml[node_type - NODE_TYPE_CML_BASE];
217
218 /* Invalid node IDs */
219 return type_to_name[NODE_TYPE_INVALID];
220 }
221
get_node_pos_x(void * node_base)222 unsigned int get_node_pos_x(void *node_base)
223 {
224 struct node_header *node = node_base;
225 return (get_node_id(node) >> (CMN650_NODE_ID_Y_POS + encoding_bits)) &
226 mask_bits;
227 }
228
get_node_pos_y(void * node_base)229 unsigned int get_node_pos_y(void *node_base)
230 {
231 struct node_header *node = node_base;
232 return (get_node_id(node) >> CMN650_NODE_ID_Y_POS) & mask_bits;
233 }
234
get_root_node(uintptr_t base,unsigned int hnd_node_id,unsigned int mesh_size_x,unsigned int mesh_size_y)235 struct cmn650_cfgm_reg *get_root_node(
236 uintptr_t base,
237 unsigned int hnd_node_id,
238 unsigned int mesh_size_x,
239 unsigned int mesh_size_y)
240 {
241 unsigned int node_pos_x;
242 unsigned int node_pos_y;
243 unsigned int node_port;
244 uintptr_t offset;
245
246 /*
247 * Determine the number of bits used to represent each node coordinate based
248 * on the mesh size as per CMN650 specification.
249 */
250 encoding_bits = ((mesh_size_x > 4) || (mesh_size_y > 4)) ? 3 : 2;
251
252 /* Extract node coordinates from the node identifier */
253 mask_bits = (1 << encoding_bits) - 1;
254 node_pos_y = (hnd_node_id >> CMN650_NODE_ID_Y_POS) & mask_bits;
255 node_pos_x =
256 (hnd_node_id >> (CMN650_NODE_ID_Y_POS + encoding_bits)) & mask_bits;
257 node_port =
258 (hnd_node_id >> CMN650_NODE_ID_PORT_POS) & CMN650_NODE_ID_PORT_MASK;
259
260 /* Calculate node address offset */
261 offset = (node_pos_y << CMN650_ROOT_NODE_OFFSET_Y_POS) |
262 (node_pos_x << (CMN650_ROOT_NODE_OFFSET_Y_POS + encoding_bits)) |
263 (node_port << CMN650_ROOT_NODE_OFFSET_PORT_POS);
264
265 return (struct cmn650_cfgm_reg *)(base + offset);
266 }
267