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 <cmn650.h>
9 #include <cmn650_ccix.h>
10 
11 #include <internal/cmn650_ctx.h>
12 
13 #include <mod_timer.h>
14 
15 #include <fwk_assert.h>
16 #include <fwk_log.h>
17 #include <fwk_math.h>
18 
19 #include <inttypes.h>
20 
21 #define MOD_NAME "[CMN650_CCIX] "
22 
23 struct mod_cmn650_ccix_ctx {
24     /* RAID value common to all function */
25     uint8_t raid_value;
26 
27     /* Port Aggregation context flag */
28     bool is_prog_for_port_agg;
29 };
30 
31 static struct mod_cmn650_ccix_ctx cmn650_ccix_ctx;
32 
33 static uint8_t port_aggregate_group_id;
34 
35 /* Pointer to the current CCIX configuration data */
36 static const struct mod_cmn650_ccix_config *config;
37 
get_ldid(bool program_for_port_aggregation)38 static unsigned int get_ldid(bool program_for_port_aggregation)
39 {
40     return (program_for_port_aggregation) ? config->port_aggregate_ldid :
41                                             config->ldid;
42 }
43 
cxg_link_wait_condition(void * data)44 static bool cxg_link_wait_condition(void *data)
45 {
46     uint64_t val1;
47     uint64_t val2;
48     uint8_t linkid;
49     struct cmn650_cxg_ra_reg *cxg_ra_reg;
50     struct cmn650_cxg_ha_reg *cxg_ha_reg;
51 
52     fwk_assert(data != NULL);
53 
54     struct cxg_wait_condition_data *wait_data =
55         (struct cxg_wait_condition_data *)data;
56     struct cmn650_device_ctx *ctx = wait_data->ctx;
57     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
58     linkid = wait_data->linkid;
59 
60     cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
61     cxg_ha_reg = ctx->cxg_ha_reg_table[cxg_ldid].cxg_ha_reg;
62 
63     switch (wait_data->cond) {
64     case CXG_LINK_CTRL_EN_BIT_SET:
65         val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL;
66         val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL;
67         return (
68             ((val1 & CXG_LINK_CTRL_EN_MASK) &&
69              (val2 & CXG_LINK_CTRL_EN_MASK)) != 0);
70 
71     case CXG_LINK_CTRL_UP_BIT_CLR:
72         val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL;
73         val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL;
74         return (
75             (((val1 & CXG_LINK_CTRL_UP_MASK) == 0) &&
76              ((val2 & CXG_LINK_CTRL_UP_MASK) == 0)) != 0);
77 
78     case CXG_LINK_STATUS_DWN_BIT_SET:
79         val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
80         val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
81         return (
82             ((val1 & CXG_LINK_STATUS_DOWN_MASK) &&
83              (val2 & CXG_LINK_STATUS_DOWN_MASK)) != 0);
84 
85     case CXG_LINK_STATUS_DWN_BIT_CLR:
86         val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
87         val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
88         return (
89             (((val1 & CXG_LINK_STATUS_DOWN_MASK) == 0) &&
90              ((val2 & CXG_LINK_STATUS_DOWN_MASK) == 0)) != 0);
91 
92     case CXG_LINK_STATUS_ACK_BIT_SET:
93         val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
94         val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
95         return (
96             ((val1 & CXG_LINK_STATUS_ACK_MASK) &&
97              (val2 & CXG_LINK_STATUS_ACK_MASK)) != 0);
98 
99     case CXG_LINK_STATUS_ACK_BIT_CLR:
100         val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
101         val2 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
102         return (
103             (((val1 & CXG_LINK_STATUS_ACK_MASK) == 0) &&
104              ((val2 & CXG_LINK_STATUS_ACK_MASK) == 0)) != 0);
105 
106     case CXG_LINK_STATUS_HA_DVMDOMAIN_ACK_BIT_SET:
107         val1 = cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
108         return (((val1 & CXG_LINK_STATUS_DVMDOMAIN_ACK_MASK)) != 0);
109 
110     case CXG_LINK_STATUS_RA_DVMDOMAIN_ACK_BIT_SET:
111         val1 = cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_STATUS;
112         return (((val1 & CXG_LINK_STATUS_DVMDOMAIN_ACK_MASK)) != 0);
113 
114     default:
115         fwk_unexpected();
116         return false;
117     }
118 }
119 
program_cxg_ra_rnf_ldid_to_raid_reg(struct cmn650_device_ctx * ctx,uint8_t ldid_value,uint8_t raid)120 static void program_cxg_ra_rnf_ldid_to_raid_reg(
121     struct cmn650_device_ctx *ctx,
122     uint8_t ldid_value,
123     uint8_t raid)
124 {
125     uint32_t reg_offset = 0;
126     uint32_t ldid_value_offset = 0;
127     struct cmn650_cxg_ra_reg *cxg_ra_reg;
128     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
129 
130     cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
131 
132     /* Each 64-bit RA RNF LDID-to-RAID register holds 8 LDIDs */
133     reg_offset = ldid_value / 8;
134     ldid_value_offset = ldid_value % 8;
135 
136     /* Adding raid_value into LDID-to-RAID register */
137     cxg_ra_reg->CXG_RA_RNF_LDID_TO_RAID_REG[reg_offset] |=
138         ((uint64_t)raid << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID));
139 
140     /* Set corresponding valid bit */
141     cxg_ra_reg->CXG_RA_RNF_LDID_TO_RAID_VAL |= ((uint64_t)0x1 << ldid_value);
142 
143     cmn650_ccix_ctx.raid_value++;
144 }
145 
program_cxg_ra_rni_ldid_to_raid_reg(struct cmn650_device_ctx * ctx,uint8_t ldid_value,uint8_t raid)146 static void program_cxg_ra_rni_ldid_to_raid_reg(
147     struct cmn650_device_ctx *ctx,
148     uint8_t ldid_value,
149     uint8_t raid)
150 {
151     uint32_t reg_offset = 0;
152     uint32_t ldid_value_offset = 0;
153     struct cmn650_cxg_ra_reg *cxg_ra_reg;
154     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
155 
156     cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
157 
158     /* Each 64-bit RA RNI LDID-to-RAID register holds 8 LDIDs */
159     reg_offset = ldid_value / 8;
160     ldid_value_offset = ldid_value % 8;
161 
162     /* Adding raid_value into LDID-to-RAID register */
163     cxg_ra_reg->CXG_RA_RNI_LDID_TO_RAID_REG[reg_offset] |=
164         ((uint64_t)raid << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID));
165 
166     /* Set corresponding valid bit */
167     cxg_ra_reg->CXG_RA_RNI_LDID_TO_RAID_VAL |= ((uint64_t)0x1 << ldid_value);
168 
169     cmn650_ccix_ctx.raid_value++;
170 }
171 
program_cxg_ra_rnd_ldid_to_raid_reg(struct cmn650_device_ctx * ctx,uint8_t ldid_value,uint8_t raid)172 static void program_cxg_ra_rnd_ldid_to_raid_reg(
173     struct cmn650_device_ctx *ctx,
174     uint8_t ldid_value,
175     uint8_t raid)
176 {
177     uint32_t reg_offset = 0;
178     uint32_t ldid_value_offset = 0;
179     struct cmn650_cxg_ra_reg *cxg_ra_reg;
180     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
181 
182     cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
183 
184     /* Each 64-bit RA RND LDID-to-RAID register holds 8 LDIDs */
185     reg_offset = ldid_value / 8;
186     ldid_value_offset = ldid_value % 8;
187 
188     /* Adding raid_value into LDID-to-RAID register */
189     cxg_ra_reg->CXG_RA_RND_LDID_TO_RAID_REG[reg_offset] |=
190         ((uint64_t)raid << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID));
191 
192     /* Set corresponding valid bit */
193     cxg_ra_reg->CXG_RA_RND_LDID_TO_RAID_VAL |= ((uint64_t)0x1 << ldid_value);
194 
195     cmn650_ccix_ctx.raid_value++;
196 }
197 
program_agentid_to_linkid_reg(struct cmn650_device_ctx * ctx,const struct mod_cmn650_ccix_config * config)198 static void program_agentid_to_linkid_reg(
199     struct cmn650_device_ctx *ctx,
200     const struct mod_cmn650_ccix_config *config)
201 {
202     uint32_t agentid;
203     uint32_t reg_index = 0;
204     uint8_t linkid = 0;
205     uint32_t agentid_bit_offset = 0;
206     struct cmn650_cxg_ra_reg *cxg_ra_reg;
207     struct cmn650_cxg_ha_reg *cxg_ha_reg;
208     struct cmn650_cxla_reg *cxla_reg;
209     unsigned int remote_agentid_start;
210     unsigned int remote_agentid_end;
211     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
212 
213     cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
214     cxg_ha_reg = ctx->cxg_ha_reg_table[cxg_ldid].cxg_ha_reg;
215     cxla_reg = ctx->cxla_reg_table[cxg_ldid].cxla_reg;
216 
217     for (linkid = 0; linkid < CMN650_MAX_CCIX_PROTOCOL_LINKS; linkid++) {
218         remote_agentid_start =
219             config->remote_agentid_to_linkid_map[linkid].remote_agentid_start;
220         remote_agentid_end =
221             config->remote_agentid_to_linkid_map[linkid].remote_agentid_end;
222 
223         /*
224          * Skip configuring link if both start and end are 0, indicating
225          * there's no link
226          */
227         if ((remote_agentid_start == 0) && (remote_agentid_end == 0))
228             continue;
229 
230         FWK_LOG_INFO(
231             MOD_NAME "  Remote [AgentID %d - AgentID %d] Link %d",
232             remote_agentid_start,
233             remote_agentid_end,
234             linkid);
235 
236         for (agentid = remote_agentid_start; agentid <= remote_agentid_end;
237              agentid++) {
238             /* Each register is 64 bits and holds 8 AgentID/LinkID mappings */
239             reg_index = agentid / 8;
240             agentid_bit_offset = agentid % 8;
241 
242             /* Writing AgentID-to-LinkID mappings */
243             cxg_ra_reg->CXG_RA_AGENTID_TO_LINKID_REG[reg_index] |=
244                 ((uint64_t)linkid
245                  << (agentid_bit_offset * NUM_BITS_RESERVED_FOR_LINKID));
246 
247             cxg_ha_reg->CXG_HA_AGENTID_TO_LINKID_REG[reg_index] |=
248                 ((uint64_t)linkid
249                  << (agentid_bit_offset * NUM_BITS_RESERVED_FOR_LINKID));
250 
251             cxla_reg->CXLA_AGENTID_TO_LINKID_REG[reg_index] |=
252                 ((uint64_t)linkid
253                  << (agentid_bit_offset * NUM_BITS_RESERVED_FOR_LINKID));
254 
255             /* Setting corresponding valid bits */
256             cxg_ra_reg->CXG_RA_AGENTID_TO_LINKID_VAL |=
257                 ((uint64_t)0x1 << agentid);
258             cxg_ha_reg->CXG_HA_AGENTID_TO_LINKID_VAL |=
259                 ((uint64_t)0x1 << agentid);
260             cxla_reg->CXLA_AGENTID_TO_LINKID_VAL |= ((uint64_t)0x1 << agentid);
261         }
262     }
263 }
264 
program_cxg_ha_id(struct cmn650_device_ctx * ctx)265 static void program_cxg_ha_id(struct cmn650_device_ctx *ctx)
266 {
267     struct cmn650_cxg_ha_reg *cxg_ha_reg;
268     unsigned int cxg_haid;
269     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
270 
271     cxg_ha_reg = ctx->cxg_ha_reg_table[cxg_ldid].cxg_ha_reg;
272     cxg_haid = cmn650_ccix_ctx.is_prog_for_port_agg ?
273         config->port_aggregate_haid :
274         config->haid;
275     cxg_ha_reg->CXG_HA_ID = cxg_haid;
276 
277     FWK_LOG_INFO(
278         MOD_NAME "HAID for CCIX %d with nodeid %d: HAID %d",
279         cxg_ldid,
280         get_node_id(cxg_ha_reg),
281         cxg_haid);
282 }
283 
program_cxg_ha_raid_to_ldid_lut(struct cmn650_device_ctx * ctx,uint8_t raid_id,uint8_t ldid_value)284 static void program_cxg_ha_raid_to_ldid_lut(
285     struct cmn650_device_ctx *ctx,
286     uint8_t raid_id,
287     uint8_t ldid_value)
288 {
289     uint32_t reg_index = 0;
290     uint32_t raid_bit_offset = 0;
291     struct cmn650_cxg_ha_reg *cxg_ha_reg;
292     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
293 
294     cxg_ha_reg = ctx->cxg_ha_reg_table[cxg_ldid].cxg_ha_reg;
295 
296     /* Each 64-bit RAID-to-LDID register holds 8 mappings, 8 bits each. */
297     reg_index = raid_id / 8;
298     raid_bit_offset = raid_id % 8;
299 
300     /* Write RAID-to-LDID mapping (with RNF bit set) */
301     cxg_ha_reg->CXG_HA_RNF_RAID_TO_LDID_REG[reg_index] |=
302         ((uint64_t)(ldid_value | CXG_HA_RAID_TO_LDID_RNF_MASK)
303          << (raid_bit_offset * NUM_BITS_RESERVED_FOR_LDID));
304 
305     /* Set corresponding valid bit */
306     cxg_ha_reg->CXG_HA_RNF_RAID_TO_LDID_VAL |= ((uint64_t)0x1 << raid_id);
307 }
308 
program_hnf_ldid_to_chi_node_id_reg(struct cmn650_device_ctx * ctx,const struct mod_cmn650_ccix_config * config)309 static void program_hnf_ldid_to_chi_node_id_reg(
310     struct cmn650_device_ctx *ctx,
311     const struct mod_cmn650_ccix_config *config)
312 {
313     uint32_t agentid;
314     uint32_t reg_index = 0;
315     uint32_t reg_bit_offset = 0;
316     uint32_t i = 0;
317     struct cmn650_hnf_reg *hnf_reg = NULL;
318     uint32_t nodeid_ra, cpa_nodeid_ra;
319     uint8_t linkid = 0;
320 
321     unsigned int remote_agentid_start;
322     unsigned int remote_agentid_end;
323     unsigned int bit_pos;
324     unsigned int group;
325 
326     /* Assign the NodeID of CXHA as the RA's NodeID */
327     nodeid_ra = ctx->cxg_ha_reg_table[config->ldid].node_id;
328     cpa_nodeid_ra = ctx->cxg_ha_reg_table[config->port_aggregate_ldid].node_id;
329 
330     if (cmn650_ccix_ctx.is_prog_for_port_agg) {
331         /*
332          * if programming for port aggregation support, reset the remote rnf
333          * ldid value to the previous iteration in order to program .
334          */
335         ctx->remote_rnf_ldid_value -= ctx->rnf_count;
336     }
337 
338     for (linkid = 0; linkid < CMN650_MAX_CCIX_PROTOCOL_LINKS; linkid++) {
339         remote_agentid_start =
340             config->remote_agentid_to_linkid_map[linkid].remote_agentid_start;
341         remote_agentid_end =
342             config->remote_agentid_to_linkid_map[linkid].remote_agentid_end;
343 
344         /*
345          * Skip configuring link if both start and end are 0, indicating
346          * there's no link
347          */
348         if ((remote_agentid_start == 0) && (remote_agentid_end == 0))
349             continue;
350 
351         FWK_LOG_INFO(
352             MOD_NAME "  Remote [AgentID %d - AgentID %d] Node Id: %" PRIu32,
353             remote_agentid_start,
354             remote_agentid_end,
355             nodeid_ra);
356 
357         for (agentid = remote_agentid_start; agentid <= remote_agentid_end;
358              agentid++) {
359             /* Each 64-bit register holds 2 sets of config data, 32 bits each */
360             reg_index = ctx->remote_rnf_ldid_value / 2;
361             reg_bit_offset = ctx->remote_rnf_ldid_value % 2;
362 
363             for (i = 0; i < ctx->hnf_count; i++) {
364                 hnf_reg = (struct cmn650_hnf_reg *)ctx->hnf_node[i];
365                 /* Write CXHA NodeID, local/remote and valid bit */
366                 hnf_reg->RN_PHYS_ID[reg_index] |=
367                     ((uint64_t)(
368                          nodeid_ra |
369                          (REMOTE_CCIX_NODE
370                           << HNF_RN_PHYS_RN_LOCAL_REMOTE_SHIFT_VAL) |
371                          (port_aggregate_group_id
372                           << HNF_RN_PHYS_CPA_GRP_RA_SHIFT_VAL) |
373                          ((uint64_t)(config->port_aggregate)
374                           << HNF_RN_PHYS_CPA_EN_RA_SHIFT_VAL) |
375                          (UINT64_C(0x1) << HNF_RN_PHYS_RN_ID_VALID_SHIFT_VAL))
376                      << (reg_bit_offset * NUM_BITS_RESERVED_FOR_PHYS_ID));
377 
378                 if (config->port_aggregate) {
379                     group =
380                         (port_aggregate_group_id * NUM_PORTS_PER_CPA_GROUP) /
381                         CMN_PORT_AGGR_GRP_PAG_TGTID_PER_GROUP;
382                     bit_pos =
383                         ((port_aggregate_group_id * NUM_PORTS_PER_CPA_GROUP) *
384                          CMN_PORT_AGGR_GRP_PAG_TGTID_WIDTH);
385 
386                     hnf_reg->CML_PORT_AGGR_GRP[group] |= ((uint64_t)nodeid_ra)
387                         << bit_pos;
388 
389                     group =
390                         ((port_aggregate_group_id * NUM_PORTS_PER_CPA_GROUP) +
391                          1) /
392                         CMN_PORT_AGGR_GRP_PAG_TGTID_PER_GROUP;
393                     bit_pos =
394                         ((((port_aggregate_group_id * NUM_PORTS_PER_CPA_GROUP) +
395                            1) *
396                           CMN_PORT_AGGR_GRP_PAG_TGTID_WIDTH) %
397                          CMN_PORT_AGGR_GRP_PAG_TGTID_WIDTH_PER_GROUP);
398 
399                     hnf_reg->CML_PORT_AGGR_GRP[group] |= (uint64_t)cpa_nodeid_ra
400                         << bit_pos;
401                 }
402             }
403 
404             ctx->remote_rnf_ldid_value++;
405         }
406     }
407 
408     if (cmn650_ccix_ctx.is_prog_for_port_agg) {
409         for (i = 0; i < ctx->hnf_count; i++) {
410             hnf_reg = (struct cmn650_hnf_reg *)ctx->hnf_node[i];
411 
412             /* Considering only 2 port support */
413             hnf_reg->CML_PORT_AGGR_CTRL |= UINT64_C(0x1)
414                 << (port_aggregate_group_id *
415                     CML_PORT_AGGR_CTRL_NUM_CXG_PAG_WIDTH);
416         }
417 
418         /* Finally increment the group id for the next group utilization */
419         port_aggregate_group_id++;
420     }
421 }
422 
enable_smp_mode(struct cmn650_device_ctx * ctx,const struct mod_cmn650_ccix_config * config)423 static int enable_smp_mode(
424     struct cmn650_device_ctx *ctx,
425     const struct mod_cmn650_ccix_config *config)
426 {
427     struct cmn650_cxg_ra_reg *cxg_ra_reg;
428     struct cmn650_cxg_ha_reg *cxg_ha_reg;
429     struct cmn650_cxla_reg *cxla_reg;
430     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
431 
432     cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
433     cxg_ha_reg = ctx->cxg_ha_reg_table[cxg_ldid].cxg_ha_reg;
434     cxla_reg = ctx->cxla_reg_table[cxg_ldid].cxla_reg;
435 
436     cxg_ra_reg->CXG_RA_AUX_CTRL |= (1 << CXG_RA_AUX_CTRL_SMP_MODE_EN_SHIFT_VAL);
437     cxg_ha_reg->CXG_HA_AUX_CTRL |= (1 << CXG_HA_AUX_CTRL_SMP_MODE_EN_SHIFT_VAL);
438     cxla_reg->CXLA_AUX_CTRL |=
439         (UINT64_C(0x1) << CXLA_AUX_CTRL_SMP_MODE_EN_SHIFT_VAL);
440 
441     FWK_LOG_INFO(MOD_NAME "SMP Mode Enabled");
442     return FWK_SUCCESS;
443 }
444 
program_cxg_ra_sam_addr_region(struct cmn650_device_ctx * ctx,const struct mod_cmn650_ccix_config * config)445 static void program_cxg_ra_sam_addr_region(
446     struct cmn650_device_ctx *ctx,
447     const struct mod_cmn650_ccix_config *config)
448 {
449     unsigned int i, remote_haid;
450     uint64_t blocks;
451     uint64_t size;
452     struct cmn650_cxg_ra_reg *cxg_ra_reg;
453     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
454 
455     cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
456 
457     FWK_LOG_INFO(
458         MOD_NAME "Configuring RA SAM for CXRA NodeID %d",
459         get_node_id(cxg_ra_reg));
460 
461     for (i = 0; i < CMN650_MAX_RA_SAM_ADDR_REGION; i++) {
462         /* If the size is zero, skip that entry */
463         if (config->ra_mmap_table[i].size == 0)
464             continue;
465 
466         /* Size must be a multiple of SAM_GRANULARITY */
467         fwk_assert((config->ra_mmap_table[i].size % (64 * FWK_KIB)) == 0);
468 
469         /* Size also must be a power of two */
470         fwk_assert(
471             (config->ra_mmap_table[i].size &
472              (config->ra_mmap_table[i].size - 1)) == 0);
473 
474         /* Region base should be naturally aligned to the region size */
475         fwk_assert(
476             config->ra_mmap_table[i].base % config->ra_mmap_table[i].size == 0);
477 
478         if (cmn650_ccix_ctx.is_prog_for_port_agg)
479             remote_haid = config->port_aggregate_remote_haid[i];
480         else
481             remote_haid = config->ra_mmap_table[i].remote_haid;
482 
483         FWK_LOG_INFO(
484             MOD_NAME "  [0x%llx - 0x%llx] HAID %d",
485             config->ra_mmap_table[i].base,
486             config->ra_mmap_table[i].base + config->ra_mmap_table[i].size - 1,
487             remote_haid);
488 
489         blocks = config->ra_mmap_table[i].size / (64 * FWK_KIB);
490         size = fwk_math_log2(blocks);
491 
492         cxg_ra_reg->CXG_RA_SAM_ADDR_REGION_REG[i] = size |
493             (config->ra_mmap_table[i].base) |
494             ((uint64_t)remote_haid << SAM_ADDR_TARGET_HAID_SHIFT) |
495             (SAM_ADDR_REG_VALID_MASK);
496 
497         i++;
498     }
499 }
500 
enable_and_start_ccix_link_up_sequence(struct cmn650_device_ctx * ctx,uint8_t linkid)501 static int enable_and_start_ccix_link_up_sequence(
502     struct cmn650_device_ctx *ctx,
503     uint8_t linkid)
504 {
505     int status;
506     struct cxg_wait_condition_data wait_data;
507     struct cmn650_cxg_ra_reg *cxg_ra_reg;
508     struct cmn650_cxg_ha_reg *cxg_ha_reg;
509     unsigned int cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
510 
511     cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
512     cxg_ha_reg = ctx->cxg_ha_reg_table[cxg_ldid].cxg_ha_reg;
513 
514     if (linkid > 2)
515         return FWK_E_PARAM;
516 
517     wait_data.ctx = ctx;
518     wait_data.linkid = linkid;
519 
520     FWK_LOG_INFO(MOD_NAME "Enabling CCIX link %d...", linkid);
521     /* Set link enable bit to enable the CCIX link */
522     cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL = CXG_LINK_CTRL_EN_MASK;
523     cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL = CXG_LINK_CTRL_EN_MASK;
524 
525     /* Wait until link enable bits are set */
526     wait_data.cond = CXG_LINK_CTRL_EN_BIT_SET;
527     status = ctx->timer_api->wait(
528         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
529         CXG_PRTCL_LINK_CTRL_TIMEOUT,
530         cxg_link_wait_condition,
531         &wait_data);
532     if (status != FWK_SUCCESS) {
533         FWK_LOG_ERR(MOD_NAME "Enabling CCIX link %d... Failed", linkid);
534         return status;
535     }
536     FWK_LOG_INFO(MOD_NAME "Enabling CCIX link %d... Done", linkid);
537 
538     FWK_LOG_INFO(MOD_NAME "Verifying link down status...");
539     /* Wait till link up bits are cleared in control register */
540     wait_data.cond = CXG_LINK_CTRL_UP_BIT_CLR;
541     status = ctx->timer_api->wait(
542         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
543         CXG_PRTCL_LINK_CTRL_TIMEOUT,
544         cxg_link_wait_condition,
545         &wait_data);
546     if (status != FWK_SUCCESS) {
547         FWK_LOG_ERR(MOD_NAME "Verifying link down status... Failed");
548         return status;
549     }
550 
551     /* Wait till link down bits are set in status register */
552     wait_data.cond = CXG_LINK_STATUS_DWN_BIT_SET;
553     status = ctx->timer_api->wait(
554         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
555         CXG_PRTCL_LINK_CTRL_TIMEOUT,
556         cxg_link_wait_condition,
557         &wait_data);
558     if (status != FWK_SUCCESS) {
559         FWK_LOG_ERR(MOD_NAME "Verifying link down status... Failed");
560         return status;
561     }
562 
563     /* Wait till link ACK bits are cleared in status register */
564     wait_data.cond = CXG_LINK_STATUS_ACK_BIT_CLR;
565     status = ctx->timer_api->wait(
566         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
567         CXG_PRTCL_LINK_CTRL_TIMEOUT,
568         cxg_link_wait_condition,
569         &wait_data);
570     if (status != FWK_SUCCESS) {
571         FWK_LOG_ERR(MOD_NAME "Verifying link down status... Failed");
572         return status;
573     }
574     FWK_LOG_INFO(MOD_NAME "Verifying link down status... Done");
575 
576     FWK_LOG_INFO(MOD_NAME "Bringing up link...");
577     /* Bring up link using link request bit */
578     cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |= CXG_LINK_CTRL_REQ_MASK;
579     cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |= CXG_LINK_CTRL_REQ_MASK;
580 
581     /* Wait till link ACK bits are set in status register */
582     wait_data.cond = CXG_LINK_STATUS_ACK_BIT_SET;
583     status = ctx->timer_api->wait(
584         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
585         CXG_PRTCL_LINK_CTRL_TIMEOUT,
586         cxg_link_wait_condition,
587         &wait_data);
588     if (status != FWK_SUCCESS) {
589         FWK_LOG_ERR(MOD_NAME "Bringing up link... Failed");
590         return status;
591     }
592 
593     /* Wait till link down bits are cleared in status register */
594     wait_data.cond = CXG_LINK_STATUS_DWN_BIT_CLR;
595     status = ctx->timer_api->wait(
596         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
597         CXG_PRTCL_LINK_CTRL_TIMEOUT,
598         cxg_link_wait_condition,
599         &wait_data);
600     if (status != FWK_SUCCESS) {
601         FWK_LOG_ERR(MOD_NAME "Bringing up link... Failed");
602         return status;
603     }
604     FWK_LOG_INFO(MOD_NAME "Bringing up link... Done");
605 
606     return FWK_SUCCESS;
607 }
608 
ccix_setup(const unsigned int chip_id,struct cmn650_device_ctx * ctx,const struct mod_cmn650_ccix_config * ccix_config)609 int ccix_setup(
610     const unsigned int chip_id,
611     struct cmn650_device_ctx *ctx,
612     const struct mod_cmn650_ccix_config *ccix_config)
613 {
614     unsigned int i;
615     unsigned int unique_remote_rnf_ldid_value;
616     uint8_t rnf_ldid;
617     uint8_t rni_ldid;
618     uint8_t rnd_ldid;
619     uint8_t agentid;
620     uint8_t remote_agentid;
621     uint8_t offset_id;
622     uint8_t local_ra_cnt;
623     int status;
624 
625     FWK_LOG_INFO(MOD_NAME "Programming CCIX gateway...");
626 
627     /* Assign the max count among the RNs as local_ra_cnt */
628     if ((ctx->rnf_count > ctx->rnd_count) && (ctx->rnf_count > ctx->rni_count))
629         local_ra_cnt = ctx->rnf_count;
630     else if (ctx->rnd_count > ctx->rni_count)
631         local_ra_cnt = ctx->rnd_count;
632     else
633         local_ra_cnt = ctx->rni_count;
634 
635     cmn650_ccix_ctx.is_prog_for_port_agg = false;
636 
637     do {
638         /* Set the global config data */
639         config = ccix_config;
640 
641         if (ccix_config->smp_mode) {
642             status = enable_smp_mode(ctx, ccix_config);
643             if (status != FWK_SUCCESS)
644                 return status;
645         }
646 
647         /*
648          * In order to assign unique AgentIDs across multiple chips, chip_id is
649          * used as factor to offset the AgentID value
650          */
651         cmn650_ccix_ctx.raid_value = 0;
652         offset_id = chip_id * local_ra_cnt;
653 
654         for (rnf_ldid = 0; rnf_ldid < ctx->rnf_count; rnf_ldid++) {
655             agentid = cmn650_ccix_ctx.raid_value + offset_id;
656 
657             /* Program RAID values in CXRA LDID to RAID LUT */
658             program_cxg_ra_rnf_ldid_to_raid_reg(ctx, rnf_ldid, agentid);
659         }
660 
661         /* Program agentid to linkid LUT for remote agents in CXRA/CXHA/CXLA */
662         program_agentid_to_linkid_reg(ctx, ccix_config);
663 
664         /* Program HN-F ldid to CHI NodeID for remote RN-F agents */
665         program_hnf_ldid_to_chi_node_id_reg(ctx, ccix_config);
666 
667         /*
668          * unique_remote_rnf_ldid_value is used to keep track of the
669          * ldid of the remote RNF agents
670          */
671         unique_remote_rnf_ldid_value = ctx->rnf_count;
672 
673         if (ccix_config->remote_rnf_count && (ctx->rnf_count == 0)) {
674             FWK_LOG_ERR(
675                 MOD_NAME
676                 "Remote RN-F Count can't be %u when RN-F count is zero",
677                 ccix_config->remote_rnf_count);
678             fwk_unexpected();
679         }
680 
681         for (i = 0; i < ccix_config->remote_rnf_count; i++) {
682             /*
683              * The remote_agentid should not include the current chip's
684              * AgentIDs. If `block` is less than the current chip_id, then
685              * include the AgentIDs starting from chip 0 till (not including)
686              * current chip. If the `block` is equal or greater than the current
687              * chip, then include the AgentIDs from next chip till the max chip.
688              */
689             if ((i / ctx->rnf_count) < chip_id)
690                 remote_agentid = i;
691             else
692                 remote_agentid = i + ctx->rnf_count;
693 
694             /* Program the CXHA raid to ldid LUT */
695             program_cxg_ha_raid_to_ldid_lut(
696                 ctx, remote_agentid, unique_remote_rnf_ldid_value);
697 
698             unique_remote_rnf_ldid_value++;
699         }
700 
701         /* Program the unique HAID for the CXHA block */
702         program_cxg_ha_id(ctx);
703 
704         cmn650_ccix_ctx.raid_value = 0;
705         offset_id = chip_id * local_ra_cnt;
706 
707         for (rnd_ldid = 0; rnd_ldid < ctx->rnd_count; rnd_ldid++) {
708             /* Determine agentid of the remote agents */
709             agentid = cmn650_ccix_ctx.raid_value + offset_id;
710 
711             /* Program RAID values in CXRA LDID to RAID LUT */
712             program_cxg_ra_rnd_ldid_to_raid_reg(ctx, rnd_ldid, agentid);
713         }
714 
715         cmn650_ccix_ctx.raid_value = 0;
716         offset_id = chip_id * local_ra_cnt;
717 
718         for (rni_ldid = 0; rni_ldid < ctx->rni_count; rni_ldid++) {
719             /* Determine agentid of the remote agents */
720             agentid = cmn650_ccix_ctx.raid_value + offset_id;
721 
722             /* Program RAID values in CXRA LDID to RAID LUT */
723             program_cxg_ra_rni_ldid_to_raid_reg(ctx, rni_ldid, agentid);
724         }
725 
726         /*
727          * Program the CXRA SAM with the address range and the corresponding
728          * remote HAID
729          */
730         program_cxg_ra_sam_addr_region(ctx, ccix_config);
731 
732         /* Program the Link Control registers present in CXRA/CXHA/CXLA */
733         status = enable_and_start_ccix_link_up_sequence(ctx, 0);
734 
735         if (config->port_aggregate &&
736             cmn650_ccix_ctx.is_prog_for_port_agg == false) {
737             cmn650_ccix_ctx.is_prog_for_port_agg = true;
738             FWK_LOG_INFO(MOD_NAME
739                          "Programming CCIX gateway for Port Aggregation...");
740         } else
741             cmn650_ccix_ctx.is_prog_for_port_agg = false;
742     } while (config->port_aggregate && cmn650_ccix_ctx.is_prog_for_port_agg);
743 
744     return status;
745 }
746 
ccix_exchange_protocol_credit(struct cmn650_device_ctx * ctx,const struct mod_cmn650_ccix_config * ccix_config)747 int ccix_exchange_protocol_credit(
748     struct cmn650_device_ctx *ctx,
749     const struct mod_cmn650_ccix_config *ccix_config)
750 {
751     int linkid;
752     struct cmn650_cxg_ra_reg *cxg_ra_reg;
753     struct cmn650_cxg_ha_reg *cxg_ha_reg;
754     unsigned int cxg_ldid;
755 
756     cmn650_ccix_ctx.is_prog_for_port_agg = false;
757 
758     do {
759         config = ccix_config;
760         cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
761         cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
762         cxg_ha_reg = ctx->cxg_ha_reg_table[cxg_ldid].cxg_ha_reg;
763 
764         /* TODO Add support to enable multiple links */
765         linkid = 0;
766 
767         FWK_LOG_INFO(
768             MOD_NAME "Exchanging protocol credits for link %d...", linkid);
769         /* Exchange protocol credits using link up bit */
770         cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |=
771             CXG_LINK_CTRL_UP_MASK;
772         cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |=
773             CXG_LINK_CTRL_UP_MASK;
774         FWK_LOG_INFO(
775             MOD_NAME "Exchanging protocol credits for link %d... Done", linkid);
776 
777         if (config->port_aggregate &&
778             cmn650_ccix_ctx.is_prog_for_port_agg == false) {
779             cmn650_ccix_ctx.is_prog_for_port_agg = true;
780             FWK_LOG_INFO(MOD_NAME
781                          "Exchange Protocol Credit for Port Aggregation...");
782         } else
783             cmn650_ccix_ctx.is_prog_for_port_agg = false;
784     } while (config->port_aggregate && cmn650_ccix_ctx.is_prog_for_port_agg);
785 
786     return FWK_SUCCESS;
787 }
788 
ccix_enter_system_coherency(struct cmn650_device_ctx * ctx,const struct mod_cmn650_ccix_config * ccix_config)789 int ccix_enter_system_coherency(
790     struct cmn650_device_ctx *ctx,
791     const struct mod_cmn650_ccix_config *ccix_config)
792 {
793     struct cxg_wait_condition_data wait_data;
794     int status;
795     int linkid;
796     struct cmn650_cxg_ha_reg *cxg_ha_reg;
797     unsigned int cxg_ldid;
798 
799     cmn650_ccix_ctx.is_prog_for_port_agg = false;
800 
801     do {
802         config = ccix_config;
803         cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
804         cxg_ha_reg = ctx->cxg_ha_reg_table[cxg_ldid].cxg_ha_reg;
805 
806         /* TODO Add support to enable multiple links */
807         linkid = 0;
808 
809         wait_data.ctx = ctx;
810         wait_data.linkid = linkid;
811 
812         FWK_LOG_INFO(
813             MOD_NAME "Entering system coherency for link %d...", linkid);
814         /* Enter system coherency by setting DVMDOMAIN request bit */
815         cxg_ha_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |=
816             CXG_LINK_CTRL_DVMDOMAIN_REQ_MASK;
817 
818         /* Wait till DVMDOMAIN ACK bit is set in status register */
819         wait_data.cond = CXG_LINK_STATUS_HA_DVMDOMAIN_ACK_BIT_SET;
820         status = ctx->timer_api->wait(
821             FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
822             CXG_PRTCL_LINK_DVMDOMAIN_TIMEOUT,
823             cxg_link_wait_condition,
824             &wait_data);
825         if (status != FWK_SUCCESS) {
826             FWK_LOG_ERR(
827                 MOD_NAME "Entering system coherency for link %d... Failed",
828                 linkid);
829             return status;
830         }
831         FWK_LOG_INFO(
832             MOD_NAME "Entering system coherency for link %d... Done", linkid);
833 
834         if (config->port_aggregate &&
835             cmn650_ccix_ctx.is_prog_for_port_agg == false) {
836             cmn650_ccix_ctx.is_prog_for_port_agg = true;
837             FWK_LOG_INFO(MOD_NAME
838                          "Enter system coherency for Port Aggregation...");
839         } else
840             cmn650_ccix_ctx.is_prog_for_port_agg = false;
841     } while (config->port_aggregate && cmn650_ccix_ctx.is_prog_for_port_agg);
842 
843     return FWK_SUCCESS;
844 }
845 
ccix_enter_dvm_domain(struct cmn650_device_ctx * ctx,const struct mod_cmn650_ccix_config * ccix_config)846 int ccix_enter_dvm_domain(
847     struct cmn650_device_ctx *ctx,
848     const struct mod_cmn650_ccix_config *ccix_config)
849 {
850     struct cxg_wait_condition_data wait_data;
851     int status;
852     int linkid;
853     struct cmn650_cxg_ra_reg *cxg_ra_reg;
854     unsigned int cxg_ldid;
855 
856     cmn650_ccix_ctx.is_prog_for_port_agg = false;
857 
858     do {
859         config = ccix_config;
860         cxg_ldid = get_ldid(cmn650_ccix_ctx.is_prog_for_port_agg);
861         cxg_ra_reg = ctx->cxg_ra_reg_table[cxg_ldid].cxg_ra_reg;
862 
863         /* TODO Add support to enable multiple links */
864         linkid = 0;
865 
866         wait_data.ctx = ctx;
867         wait_data.linkid = linkid;
868 
869         FWK_LOG_INFO(MOD_NAME "Entering DVM domain for link %d...", linkid);
870         /* DVM domain entry by setting DVMDOMAIN request bit */
871         cxg_ra_reg->LINK_REGS[linkid].CXG_PRTCL_LINK_CTRL |=
872             CXG_LINK_CTRL_DVMDOMAIN_REQ_MASK;
873 
874         /* Wait till DVMDOMAIN ACK bit is set in status register */
875         wait_data.cond = CXG_LINK_STATUS_RA_DVMDOMAIN_ACK_BIT_SET;
876         status = ctx->timer_api->wait(
877             FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
878             CXG_PRTCL_LINK_DVMDOMAIN_TIMEOUT,
879             cxg_link_wait_condition,
880             &wait_data);
881         if (status != FWK_SUCCESS) {
882             FWK_LOG_ERR(
883                 MOD_NAME "Entering DVM domain for link %d... Failed", linkid);
884             return status;
885         }
886         FWK_LOG_INFO(
887             MOD_NAME "Entering DVM domain for link %d... Done", linkid);
888 
889         if (config->port_aggregate &&
890             cmn650_ccix_ctx.is_prog_for_port_agg == false) {
891             cmn650_ccix_ctx.is_prog_for_port_agg = true;
892             FWK_LOG_INFO(MOD_NAME
893                          "Entering DVM domain for Port Aggregation...");
894         } else
895             cmn650_ccix_ctx.is_prog_for_port_agg = false;
896     } while (config->port_aggregate && cmn650_ccix_ctx.is_prog_for_port_agg);
897 
898     return FWK_SUCCESS;
899 }
900