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