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