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