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