1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <cmn700.h>
9 #include <cmn700_ccg.h>
10 
11 #include <internal/cmn700_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 #include <stdint.h>
21 
22 #define MOD_NAME "[CMN700_CCG] "
23 
24 struct mod_cmn700_ccg_ctx {
25     /* RAID value common to all function */
26     uint8_t raid_value;
27 
28     /* Port Aggregation context flag */
29     bool is_prog_for_port_agg;
30 };
31 
32 static struct mod_cmn700_ccg_ctx cmn700_ccg_ctx;
33 
34 /* Pointer to the current CCG configuration data */
35 static const struct mod_cmn700_ccg_config *config;
36 
get_ldid(struct cmn700_device_ctx * ctx,bool program_for_port_aggregation)37 static unsigned int get_ldid(
38     struct cmn700_device_ctx *ctx,
39     bool program_for_port_aggregation)
40 {
41     unsigned int ldid;
42 
43     ldid = (program_for_port_aggregation) ? config->port_aggregate_ldid :
44                                             config->ldid;
45 
46     if (ldid >= ctx->ccg_node_count) {
47         FWK_LOG_ERR(MOD_NAME "Unexpected ldid: %d", ldid);
48         fwk_trap();
49     }
50 
51     return ldid;
52 }
53 
ccg_link_wait_condition(void * data)54 static bool ccg_link_wait_condition(void *data)
55 {
56     bool ret;
57     uint8_t linkid;
58     uint64_t val1;
59     uint64_t val2;
60     unsigned int ccg_ldid;
61     struct ccg_wait_condition_data *wait_data;
62     struct cmn700_ccg_ra_reg *ccg_ra_reg;
63     struct cmn700_ccg_ha_reg *ccg_ha_reg;
64     struct cmn700_device_ctx *ctx;
65 
66     fwk_assert(data != NULL);
67 
68     wait_data = (struct ccg_wait_condition_data *)data;
69     ctx = wait_data->ctx;
70 
71     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
72     ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
73     ccg_ha_reg = ctx->ccg_ha_reg_table[ccg_ldid].ccg_ha_reg;
74     linkid = wait_data->linkid;
75 
76     switch (wait_data->cond) {
77     case CCG_LINK_CTRL_EN_BIT_SET:
78         val1 = ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL;
79         val2 = ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL;
80         ret = ((val1 & CCG_LINK_CTRL_EN_MASK) > 0) &&
81             ((val2 & CCG_LINK_CTRL_EN_MASK) > 0);
82         break;
83 
84     case CCG_LINK_CTRL_UP_BIT_CLR:
85         val1 = ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL;
86         val2 = ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL;
87         ret =
88             (((val1 & CCG_LINK_CTRL_UP_MASK) == 0) &&
89              ((val2 & CCG_LINK_CTRL_UP_MASK) == 0));
90         break;
91 
92     case CCG_LINK_STATUS_DWN_BIT_SET:
93         val1 = ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
94         val2 = ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
95         ret = ((val1 & CCG_LINK_STATUS_DOWN_MASK) > 0) &&
96             ((val2 & CCG_LINK_STATUS_DOWN_MASK) > 0);
97         break;
98 
99     case CCG_LINK_STATUS_DWN_BIT_CLR:
100         val1 = ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
101         val2 = ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
102         ret =
103             (((val1 & CCG_LINK_STATUS_DOWN_MASK) == 0) &&
104              ((val2 & CCG_LINK_STATUS_DOWN_MASK) == 0));
105         break;
106 
107     case CCG_LINK_STATUS_ACK_BIT_SET:
108         val1 = ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
109         val2 = ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
110         ret = ((val1 & CCG_LINK_STATUS_ACK_MASK) > 0) &&
111             ((val2 & CCG_LINK_STATUS_ACK_MASK) > 0);
112         break;
113 
114     case CCG_LINK_STATUS_ACK_BIT_CLR:
115         val1 = ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
116         val2 = ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
117         ret =
118             (((val1 & CCG_LINK_STATUS_ACK_MASK) == 0) &&
119              ((val2 & CCG_LINK_STATUS_ACK_MASK) == 0));
120         break;
121 
122     case CCG_LINK_STATUS_HA_DVMDOMAIN_ACK_BIT_SET:
123         val1 = ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
124         ret = (((val1 & CCG_LINK_STATUS_DVMDOMAIN_ACK_MASK)) != 0);
125         break;
126 
127     case CCG_LINK_STATUS_RA_DVMDOMAIN_ACK_BIT_SET:
128         val1 = ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_STATUS;
129         ret = (((val1 & CCG_LINK_STATUS_DVMDOMAIN_ACK_MASK)) != 0);
130         break;
131 
132     default:
133         fwk_unexpected();
134         ret = false;
135     }
136 
137     return ret;
138 }
139 
program_ccg_ra_rnf_ldid_to_exp_raid_reg(struct cmn700_device_ctx * ctx,uint8_t ldid_value,uint8_t raid)140 static void program_ccg_ra_rnf_ldid_to_exp_raid_reg(
141     struct cmn700_device_ctx *ctx,
142     uint8_t ldid_value,
143     uint8_t raid)
144 {
145     uint32_t reg_offset = 0;
146     uint32_t ldid_value_offset = 0;
147     unsigned int ccg_ldid;
148     struct cmn700_ccg_ra_reg *ccg_ra_reg;
149 
150     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
151     ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
152 
153     /* Each 64-bit RA RNF LDID-to-RAID register holds 4 LDIDs */
154     reg_offset = ldid_value / 4;
155     ldid_value_offset = ldid_value % 4;
156 
157     /* Adding raid_value into LDID-to-RAID register */
158     ccg_ra_reg->CCG_RA_RNF_LDID_TO_EXP_RAID_REG[reg_offset] |=
159         ((uint64_t)raid << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID));
160 
161     /* Set corresponding valid bit */
162     ccg_ra_reg->CCG_RA_RNF_LDID_TO_EXP_RAID_REG[reg_offset] |=
163         (LDID_TO_EXP_RAID_VALID_MASK)
164         << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID);
165 
166     cmn700_ccg_ctx.raid_value++;
167 }
168 
program_ccg_ra_rni_ldid_to_exp_raid_reg(struct cmn700_device_ctx * ctx,uint8_t ldid_value,uint8_t raid)169 static void program_ccg_ra_rni_ldid_to_exp_raid_reg(
170     struct cmn700_device_ctx *ctx,
171     uint8_t ldid_value,
172     uint8_t raid)
173 {
174     uint32_t reg_offset = 0;
175     uint32_t ldid_value_offset = 0;
176     unsigned int ccg_ldid;
177     struct cmn700_ccg_ra_reg *ccg_ra_reg;
178 
179     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
180     ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
181 
182     /* Each 64-bit RA RNI LDID-to-RAID register holds 4 LDIDs */
183     reg_offset = ldid_value / 4;
184     ldid_value_offset = ldid_value % 4;
185 
186     /* Adding raid_value into LDID-to-RAID register */
187     ccg_ra_reg->CCG_RA_RNI_LDID_TO_EXP_RAID_REG[reg_offset] |=
188         ((uint64_t)raid << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID));
189 
190     /* Set corresponding valid bit */
191     ccg_ra_reg->CCG_RA_RNI_LDID_TO_EXP_RAID_REG[reg_offset] |=
192         (LDID_TO_EXP_RAID_VALID_MASK)
193         << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID);
194 
195     cmn700_ccg_ctx.raid_value++;
196 }
197 
program_ccg_ra_rnd_ldid_to_exp_raid_reg(struct cmn700_device_ctx * ctx,uint8_t ldid_value,uint8_t raid)198 static void program_ccg_ra_rnd_ldid_to_exp_raid_reg(
199     struct cmn700_device_ctx *ctx,
200     uint8_t ldid_value,
201     uint8_t raid)
202 {
203     uint32_t reg_offset = 0;
204     uint32_t ldid_value_offset = 0;
205     unsigned int ccg_ldid;
206     struct cmn700_ccg_ra_reg *ccg_ra_reg;
207 
208     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
209     ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
210 
211     /* Each 64-bit RA RND LDID-to-RAID register holds 4 LDIDs */
212     reg_offset = ldid_value / 4;
213     ldid_value_offset = ldid_value % 4;
214 
215     /* Adding raid_value into LDID-to-RAID register */
216     ccg_ra_reg->CCG_RA_RND_LDID_TO_EXP_RAID_REG[reg_offset] |=
217         ((uint64_t)raid << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID));
218 
219     /* Set corresponding valid bit */
220     ccg_ra_reg->CCG_RA_RND_LDID_TO_EXP_RAID_REG[reg_offset] |=
221         (LDID_TO_EXP_RAID_VALID_MASK)
222         << (ldid_value_offset * NUM_BITS_RESERVED_FOR_RAID);
223 
224     cmn700_ccg_ctx.raid_value++;
225 }
226 
program_agentid_to_linkid_reg(struct cmn700_device_ctx * ctx,const struct mod_cmn700_ccg_config * config)227 static void program_agentid_to_linkid_reg(
228     struct cmn700_device_ctx *ctx,
229     const struct mod_cmn700_ccg_config *config)
230 {
231     uint8_t linkid = 0;
232     uint32_t agentid;
233     uint32_t reg_index = 0;
234     uint32_t agentid_bit_offset = 0;
235     unsigned int ccg_ldid;
236     unsigned int remote_agentid_start;
237     unsigned int remote_agentid_end;
238     struct cmn700_ccg_ra_reg *ccg_ra_reg;
239     struct cmn700_ccg_ha_reg *ccg_ha_reg;
240 
241     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
242     ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
243     ccg_ha_reg = ctx->ccg_ha_reg_table[ccg_ldid].ccg_ha_reg;
244 
245     for (linkid = 0; linkid < CMN700_MAX_CCG_PROTOCOL_LINKS; linkid++) {
246         remote_agentid_start =
247             config->remote_agentid_to_linkid_map[linkid].remote_agentid_start;
248         remote_agentid_end =
249             config->remote_agentid_to_linkid_map[linkid].remote_agentid_end;
250 
251         /*
252          * Skip configuring link if both start and end are 0, indicating
253          * there's no link
254          */
255         if ((remote_agentid_start == 0) && (remote_agentid_end == 0)) {
256             continue;
257         }
258 
259         FWK_LOG_INFO(
260             MOD_NAME "  Remote [AgentID %d - AgentID %d] Link %d",
261             remote_agentid_start,
262             remote_agentid_end,
263             linkid);
264 
265         for (agentid = remote_agentid_start; agentid <= remote_agentid_end;
266              agentid++) {
267             /* Each register is 64 bits and holds 8 AgentID/LinkID mappings */
268             reg_index = agentid / 8;
269             agentid_bit_offset = agentid % 8;
270 
271             /* Writing AgentID-to-LinkID mappings */
272             ccg_ra_reg->CCG_RA_AGENTID_TO_LINKID_REG[reg_index] |=
273                 ((uint64_t)linkid
274                  << (agentid_bit_offset * NUM_BITS_RESERVED_FOR_LINKID));
275 
276             ccg_ha_reg->CCG_HA_AGENTID_TO_LINKID_REG[reg_index] |=
277                 ((uint64_t)linkid
278                  << (agentid_bit_offset * NUM_BITS_RESERVED_FOR_LINKID));
279 
280             /* Setting corresponding valid bits */
281             ccg_ra_reg->CCG_RA_AGENTID_TO_LINKID_VAL |=
282                 (UINT64_C(0x1) << agentid);
283             ccg_ha_reg->CCG_HA_AGENTID_TO_LINKID_VAL |=
284                 (UINT64_C(0x1) << agentid);
285         }
286     }
287 }
288 
program_ccg_ha_id(struct cmn700_device_ctx * ctx)289 static void program_ccg_ha_id(struct cmn700_device_ctx *ctx)
290 {
291     struct cmn700_ccg_ha_reg *ccg_ha_reg;
292     unsigned int ccg_haid;
293     unsigned int ccg_ldid;
294 
295     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
296     ccg_ha_reg = ctx->ccg_ha_reg_table[ccg_ldid].ccg_ha_reg;
297     ccg_haid = cmn700_ccg_ctx.is_prog_for_port_agg ?
298         config->port_aggregate_haid :
299         config->haid;
300     ccg_ha_reg->CCG_HA_ID = ccg_haid;
301 
302     FWK_LOG_INFO(
303         MOD_NAME "HAID for CCG %d with nodeid %d: HAID %d",
304         ccg_ldid,
305         get_node_id(ccg_ha_reg),
306         ccg_haid);
307 }
308 
program_ccg_ha_raid_to_ldid_lut(struct cmn700_device_ctx * ctx,uint8_t raid_id,uint8_t ldid_value)309 static void program_ccg_ha_raid_to_ldid_lut(
310     struct cmn700_device_ctx *ctx,
311     uint8_t raid_id,
312     uint8_t ldid_value)
313 {
314     uint32_t reg_index = 0;
315     uint32_t raid_bit_offset = 0;
316     unsigned int ccg_ldid;
317     struct cmn700_ccg_ha_reg *ccg_ha_reg;
318 
319     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
320     ccg_ha_reg = ctx->ccg_ha_reg_table[ccg_ldid].ccg_ha_reg;
321 
322     /* Each 64-bit RAID-to-LDID register holds 4 mappings, 16 bits each. */
323     reg_index = raid_id / 4;
324     raid_bit_offset = raid_id % 4;
325 
326     /* Write RAID-to-LDID mapping (with RNF bit set) */
327     ccg_ha_reg->CCG_HA_RNF_EXP_RAID_TO_LDID_REG[reg_index] |=
328         ((uint64_t)(
329              ldid_value | CCG_HA_RAID_TO_LDID_RNF_MASK |
330              (EXP_RAID_TO_LDID_VALID_MASK))
331          << (raid_bit_offset * NUM_BITS_RESERVED_FOR_LDID));
332 }
333 
program_hnf_ldid_to_chi_node_id_reg(struct cmn700_device_ctx * ctx,const struct mod_cmn700_ccg_config * config)334 static void program_hnf_ldid_to_chi_node_id_reg(
335     struct cmn700_device_ctx *ctx,
336     const struct mod_cmn700_ccg_config *config)
337 {
338     uint8_t linkid;
339     uint32_t agentid;
340     uint32_t reg_index;
341     uint32_t i;
342     uint32_t nodeid_ra;
343     unsigned int remote_agentid_start;
344     unsigned int remote_agentid_end;
345     struct cmn700_hnf_reg *hnf_reg;
346 
347     linkid = 0;
348     reg_index = 0;
349     i = 0;
350 
351     /* Assign the NodeID of CCHA as the RA's NodeID */
352     nodeid_ra = ctx->ccg_ha_reg_table[config->ldid].node_id;
353 
354     if (cmn700_ccg_ctx.is_prog_for_port_agg) {
355         /*
356          * if programming for port aggregation support, reset the remote rnf
357          * ldid value to the previous iteration in order to program.
358          */
359         ctx->remote_rnf_ldid_value -= ctx->rnf_count;
360     }
361 
362     for (linkid = 0; linkid < CMN700_MAX_CCG_PROTOCOL_LINKS; linkid++) {
363         remote_agentid_start =
364             config->remote_agentid_to_linkid_map[linkid].remote_agentid_start;
365         remote_agentid_end =
366             config->remote_agentid_to_linkid_map[linkid].remote_agentid_end;
367 
368         /*
369          * Skip configuring link if both start and end are 0, indicating
370          * there's no link
371          */
372         if ((remote_agentid_start == 0) && (remote_agentid_end == 0)) {
373             continue;
374         }
375 
376         FWK_LOG_INFO(
377             MOD_NAME "  Remote [AgentID %d - AgentID %d] Node Id: %" PRIu32,
378             remote_agentid_start,
379             remote_agentid_end,
380             nodeid_ra);
381 
382         for (agentid = remote_agentid_start; agentid <= remote_agentid_end;
383              agentid++) {
384             reg_index = ctx->remote_rnf_ldid_value;
385 
386             for (i = 0; i < ctx->hnf_count; i++) {
387                 hnf_reg = (struct cmn700_hnf_reg *)ctx->hnf_node[i];
388                 /* Write CCHA NodeID, local/remote and valid bit */
389                 hnf_reg->HNF_RN_CLUSTER_PHYSID[reg_index][0] |= ((uint64_t)(
390                     nodeid_ra |
391                     (REMOTE_CCG_NODE << HNF_RN_PHYS_RN_LOCAL_REMOTE_SHIFT_VAL) |
392                     (UINT64_C(0x1) << HNF_RN_PHYS_RN_ID_VALID_SHIFT_VAL)));
393             }
394 
395             ctx->remote_rnf_ldid_value++;
396         }
397     }
398 }
399 
enable_smp_mode(struct cmn700_device_ctx * ctx,const struct mod_cmn700_ccg_config * config)400 static void enable_smp_mode(
401     struct cmn700_device_ctx *ctx,
402     const struct mod_cmn700_ccg_config *config)
403 {
404     unsigned int ccg_ldid;
405     struct cmn700_ccg_ra_reg *ccg_ra_reg;
406     struct cmn700_ccg_ha_reg *ccg_ha_reg;
407 
408     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
409     ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
410     ccg_ha_reg = ctx->ccg_ha_reg_table[ccg_ldid].ccg_ha_reg;
411 
412     ccg_ra_reg->LINK_REGS[0].CCG_CCPRTCL_LINK_CTRL |=
413         (1 << CCG_RA_CCPRTCL_LINK_CTRL_SMP_MODE_EN_SHIFT_VAL);
414     ccg_ha_reg->LINK_REGS[0].CCG_CCPRTCL_LINK_CTRL |=
415         (1 << CCG_HA_CCPRTCL_LINK_CTRL_SMP_MODE_EN_SHIFT_VAL);
416 
417     FWK_LOG_INFO(MOD_NAME "SMP Mode Enabled");
418 }
419 
420 /*
421  * Helper function to check the status of the Upper link layer direct connect
422  * (ull to ull) mode
423  */
ccla_ull_status_wait_condition(void * data)424 static bool ccla_ull_status_wait_condition(void *data)
425 {
426     bool ccla_ull_status_rx_in_run;
427     bool ccla_ull_status_tx_in_run;
428     unsigned int ccg_ldid;
429     struct cmn700_ccla_reg *ccla_reg;
430     struct cmn700_device_ctx *ctx;
431 
432     ctx = (struct cmn700_device_ctx *)data;
433     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
434     ccla_reg = ctx->ccla_reg_table[ccg_ldid].ccla_reg;
435 
436     ccla_ull_status_rx_in_run =
437         ((ccla_reg->CCLA_ULL_STATUS & CCLA_ULL_STATUS_SEND_RX_ULL_STATE_MASK) >
438          0);
439 
440     ccla_ull_status_tx_in_run =
441         ((ccla_reg->CCLA_ULL_STATUS & CCLA_ULL_STATUS_SEND_TX_ULL_STATE_MASK) >
442          0);
443 
444     return (ccla_ull_status_rx_in_run && ccla_ull_status_tx_in_run);
445 }
446 
enable_ull_to_ull_mode(struct cmn700_device_ctx * ctx,const struct mod_cmn700_ccg_config * config)447 static int enable_ull_to_ull_mode(
448     struct cmn700_device_ctx *ctx,
449     const struct mod_cmn700_ccg_config *config)
450 {
451     int status;
452     unsigned int ccg_ldid;
453     struct cmn700_ccla_reg *ccla_reg;
454 
455     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
456     ccla_reg = ctx->ccla_reg_table[ccg_ldid].ccla_reg;
457 
458     FWK_LOG_INFO(MOD_NAME "Enabling CCG ULL to ULL mode...");
459 
460     /* Enabling ULL-to-ULL mode */
461     ccla_reg->CCLA_ULL_CTL = (1 << CCLA_ULL_CTL_ULL_TO_ULL_MODE_EN_SHIFT_VAL);
462 
463     /* Setting send_vd_init */
464     ccla_reg->CCLA_ULL_CTL |= (1 << CCLA_ULL_CTL_SEND_VD_INIT_SHIFT_VAL);
465 
466     /* Wait until link enable bits are set */
467     status = ctx->timer_api->wait(
468         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
469         CCLA_ULL_STATUS_TIMEOUT,
470         ccla_ull_status_wait_condition,
471         ctx);
472 
473     if (status != FWK_SUCCESS) {
474         if ((ccla_reg->CCLA_ULL_STATUS &
475              CCLA_ULL_STATUS_SEND_RX_ULL_STATE_MASK) == 0) {
476             FWK_LOG_ERR(MOD_NAME "Rx ULL is in Stop state");
477         }
478 
479         if ((ccla_reg->CCLA_ULL_STATUS &
480              CCLA_ULL_STATUS_SEND_TX_ULL_STATE_MASK) == 0) {
481             FWK_LOG_ERR(MOD_NAME "Tx ULL is in Stop state");
482         }
483 
484         FWK_LOG_ERR(MOD_NAME "Enabling CCG ULL to ULL mode... Failed");
485         return status;
486     }
487 
488     FWK_LOG_INFO(MOD_NAME "Enabling CCG ULL to ULL mode... Done");
489     return status;
490 }
491 
program_ccg_ra_sam_addr_region(struct cmn700_device_ctx * ctx,const struct mod_cmn700_ccg_config * config)492 static void program_ccg_ra_sam_addr_region(
493     struct cmn700_device_ctx *ctx,
494     const struct mod_cmn700_ccg_config *config)
495 {
496     uint64_t blocks;
497     uint64_t size;
498     unsigned int ccg_ldid;
499     unsigned int i;
500     unsigned int remote_haid;
501     struct cmn700_ccg_ra_reg *ccg_ra_reg;
502 
503     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
504     ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
505 
506     FWK_LOG_INFO(
507         MOD_NAME "Configuring RA SAM for CCRA NodeID %d",
508         get_node_id(ccg_ra_reg));
509 
510     for (i = 0; i < CMN700_MAX_RA_SAM_ADDR_REGION; i++) {
511         /* If the size is zero, skip that entry */
512         if (config->ra_mmap_table[i].size == 0) {
513             continue;
514         }
515 
516         /* Size must be a multiple of SAM_GRANULARITY */
517         fwk_assert((config->ra_mmap_table[i].size % (64 * FWK_KIB)) == 0);
518 
519         /* Size also must be a power of two */
520         fwk_assert(
521             (config->ra_mmap_table[i].size &
522              (config->ra_mmap_table[i].size - 1)) == 0);
523 
524         /* Region base should be naturally aligned to the region size */
525         fwk_assert(
526             config->ra_mmap_table[i].base % config->ra_mmap_table[i].size == 0);
527 
528         if (cmn700_ccg_ctx.is_prog_for_port_agg) {
529             remote_haid = config->port_aggregate_remote_haid[i];
530         } else {
531             remote_haid = config->ra_mmap_table[i].remote_haid;
532         }
533 
534         FWK_LOG_INFO(
535             MOD_NAME "  [0x%llx - 0x%llx] HAID %d",
536             config->ra_mmap_table[i].base,
537             config->ra_mmap_table[i].base + config->ra_mmap_table[i].size - 1,
538             remote_haid);
539 
540         blocks = config->ra_mmap_table[i].size / (64 * FWK_KIB);
541         size = fwk_math_log2(blocks);
542 
543         ccg_ra_reg->CCG_RA_SAM_ADDR_REGION_REG[i] = size |
544             (config->ra_mmap_table[i].base) |
545             ((uint64_t)remote_haid << SAM_ADDR_TARGET_HAID_SHIFT) |
546             (SAM_ADDR_REG_VALID_MASK);
547     }
548 }
549 
enable_and_start_ccg_link_up_sequence(struct cmn700_device_ctx * ctx,uint8_t linkid)550 static int enable_and_start_ccg_link_up_sequence(
551     struct cmn700_device_ctx *ctx,
552     uint8_t linkid)
553 {
554     int status;
555     unsigned int ccg_ldid;
556     struct ccg_wait_condition_data wait_data;
557     struct cmn700_ccg_ra_reg *ccg_ra_reg;
558     struct cmn700_ccg_ha_reg *ccg_ha_reg;
559 
560     ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
561     ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
562     ccg_ha_reg = ctx->ccg_ha_reg_table[ccg_ldid].ccg_ha_reg;
563 
564     if (linkid > 2) {
565         return FWK_E_PARAM;
566     }
567 
568     wait_data.ctx = ctx;
569     wait_data.linkid = linkid;
570 
571     FWK_LOG_INFO(MOD_NAME "Enabling CCG link %d...", linkid);
572     /* Set link enable bit to enable the CCG link */
573     ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL |=
574         CCG_LINK_CTRL_EN_MASK;
575     ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL |=
576         CCG_LINK_CTRL_EN_MASK;
577 
578     /* Wait until link enable bits are set */
579     wait_data.cond = CCG_LINK_CTRL_EN_BIT_SET;
580     status = ctx->timer_api->wait(
581         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
582         CCG_CCPRTCL_LINK_CTRL_TIMEOUT,
583         ccg_link_wait_condition,
584         &wait_data);
585     if (status != FWK_SUCCESS) {
586         FWK_LOG_ERR(MOD_NAME "Enabling CCG link %d... Failed", linkid);
587         return status;
588     }
589     FWK_LOG_INFO(MOD_NAME "Enabling CCG link %d... Done", linkid);
590 
591     FWK_LOG_INFO(MOD_NAME "Verifying link down status...");
592     /* Wait till link up bits are cleared in control register */
593     wait_data.cond = CCG_LINK_CTRL_UP_BIT_CLR;
594     status = ctx->timer_api->wait(
595         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
596         CCG_CCPRTCL_LINK_CTRL_TIMEOUT,
597         ccg_link_wait_condition,
598         &wait_data);
599     if (status != FWK_SUCCESS) {
600         FWK_LOG_ERR(MOD_NAME "Verifying link down status... Failed");
601         return status;
602     }
603 
604     /* Wait till link down bits are set in status register */
605     wait_data.cond = CCG_LINK_STATUS_DWN_BIT_SET;
606     status = ctx->timer_api->wait(
607         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
608         CCG_CCPRTCL_LINK_CTRL_TIMEOUT,
609         ccg_link_wait_condition,
610         &wait_data);
611     if (status != FWK_SUCCESS) {
612         FWK_LOG_ERR(MOD_NAME "Verifying link down status... Failed");
613         return status;
614     }
615 
616     /* Wait till link ACK bits are cleared in status register */
617     wait_data.cond = CCG_LINK_STATUS_ACK_BIT_CLR;
618     status = ctx->timer_api->wait(
619         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
620         CCG_CCPRTCL_LINK_CTRL_TIMEOUT,
621         ccg_link_wait_condition,
622         &wait_data);
623     if (status != FWK_SUCCESS) {
624         FWK_LOG_ERR(MOD_NAME "Verifying link down status... Failed");
625         return status;
626     }
627     FWK_LOG_INFO(MOD_NAME "Verifying link down status... Done");
628 
629     FWK_LOG_INFO(MOD_NAME "Bringing up link...");
630     /* Bring up link using link request bit */
631     ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL |=
632         CCG_LINK_CTRL_REQ_MASK;
633     ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL |=
634         CCG_LINK_CTRL_REQ_MASK;
635 
636     /* Wait till link ACK bits are set in status register */
637     wait_data.cond = CCG_LINK_STATUS_ACK_BIT_SET;
638     status = ctx->timer_api->wait(
639         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
640         CCG_CCPRTCL_LINK_CTRL_TIMEOUT,
641         ccg_link_wait_condition,
642         &wait_data);
643     if (status != FWK_SUCCESS) {
644         FWK_LOG_ERR(MOD_NAME "Bringing up link... Failed");
645         return status;
646     }
647 
648     /* Wait till link down bits are cleared in status register */
649     wait_data.cond = CCG_LINK_STATUS_DWN_BIT_CLR;
650     status = ctx->timer_api->wait(
651         FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
652         CCG_CCPRTCL_LINK_CTRL_TIMEOUT,
653         ccg_link_wait_condition,
654         &wait_data);
655     if (status != FWK_SUCCESS) {
656         FWK_LOG_ERR(MOD_NAME "Bringing up link... Failed");
657         return status;
658     }
659     FWK_LOG_INFO(MOD_NAME "Bringing up link... Done");
660 
661     return FWK_SUCCESS;
662 }
663 
ccg_setup(const unsigned int chip_id,struct cmn700_device_ctx * ctx,const struct mod_cmn700_ccg_config * ccg_config)664 int ccg_setup(
665     const unsigned int chip_id,
666     struct cmn700_device_ctx *ctx,
667     const struct mod_cmn700_ccg_config *ccg_config)
668 {
669     int status;
670     uint8_t rnf_ldid;
671     uint8_t rni_ldid;
672     uint8_t rnd_ldid;
673     uint8_t agentid;
674     uint8_t remote_agentid;
675     uint8_t offset_id;
676     uint8_t local_ra_cnt;
677     unsigned int i;
678     unsigned int unique_remote_rnf_ldid_value;
679 
680     FWK_LOG_INFO(MOD_NAME "Programming CCG gateway...");
681 
682     /* Assign the max count among the RNs as local_ra_cnt */
683     if ((ctx->rnf_count > ctx->rnd_count) &&
684         (ctx->rnf_count > ctx->rni_count)) {
685         local_ra_cnt = ctx->rnf_count;
686     } else if (ctx->rnd_count > ctx->rni_count) {
687         local_ra_cnt = ctx->rnd_count;
688     } else {
689         local_ra_cnt = ctx->rni_count;
690     }
691 
692     cmn700_ccg_ctx.is_prog_for_port_agg = false;
693 
694     do {
695         /* Set the global config data */
696         config = ccg_config;
697 
698         if (ccg_config->smp_mode) {
699             enable_smp_mode(ctx, ccg_config);
700         }
701 
702         /*
703          * In order to assign unique AgentIDs across multiple chips, chip_id is
704          * used as factor to offset the AgentID value
705          */
706         cmn700_ccg_ctx.raid_value = 0;
707         offset_id = chip_id * local_ra_cnt;
708 
709         for (rnf_ldid = 0; rnf_ldid < ctx->rnf_count; rnf_ldid++) {
710             agentid = cmn700_ccg_ctx.raid_value + offset_id;
711 
712             /* Program RAID values in CCRA LDID to RAID LUT */
713             program_ccg_ra_rnf_ldid_to_exp_raid_reg(ctx, rnf_ldid, agentid);
714         }
715 
716         /* Program agentid to linkid LUT for remote agents in CCRA/CCHA/CCLA */
717         program_agentid_to_linkid_reg(ctx, ccg_config);
718 
719         /* Program HN-F ldid to CHI NodeID for remote RN-F agents */
720         program_hnf_ldid_to_chi_node_id_reg(ctx, ccg_config);
721 
722         /*
723          * unique_remote_rnf_ldid_value is used to keep track of the
724          * ldid of the remote RNF agents
725          */
726         unique_remote_rnf_ldid_value = ctx->rnf_count;
727 
728         if (ccg_config->remote_rnf_count && (ctx->rnf_count == 0)) {
729             FWK_LOG_ERR(
730                 MOD_NAME
731                 "Remote RN-F Count can't be %u when RN-F count is zero",
732                 ccg_config->remote_rnf_count);
733             fwk_unexpected();
734         }
735 
736         for (i = 0; i < ccg_config->remote_rnf_count; i++) {
737             /*
738              * The remote_agentid (RAID) should not include the current chip's
739              * AgentIDs. If `block` is less than the current chip_id, then
740              * include the AgentIDs starting from chip 0 till (not including)
741              * current chip. If the `block` is equal or greater than the current
742              * chip, then include the AgentIDs from next chip till the max chip.
743              */
744             if ((i / ctx->rnf_count) < chip_id) {
745                 remote_agentid = (i % ctx->rnf_count) +
746                     (local_ra_cnt * (i / ctx->rnf_count));
747             } else {
748                 remote_agentid = (i % ctx->rnf_count) + local_ra_cnt +
749                     (local_ra_cnt * (i / ctx->rnf_count));
750             }
751 
752             /* Program the CCHA raid to ldid LUT */
753             program_ccg_ha_raid_to_ldid_lut(
754                 ctx, remote_agentid, unique_remote_rnf_ldid_value);
755 
756             unique_remote_rnf_ldid_value++;
757         }
758 
759         /* Program the unique HAID for the CCHA block */
760         program_ccg_ha_id(ctx);
761 
762         cmn700_ccg_ctx.raid_value = 0;
763         offset_id = chip_id * local_ra_cnt;
764 
765         for (rnd_ldid = 0; rnd_ldid < ctx->rnd_count; rnd_ldid++) {
766             /* Determine agentid of the remote agents */
767             agentid = cmn700_ccg_ctx.raid_value + offset_id;
768 
769             /* Program RAID values in CCRA LDID to RAID LUT */
770             program_ccg_ra_rnd_ldid_to_exp_raid_reg(ctx, rnd_ldid, agentid);
771         }
772 
773         cmn700_ccg_ctx.raid_value = 0;
774         offset_id = chip_id * local_ra_cnt;
775 
776         for (rni_ldid = 0; rni_ldid < ctx->rni_count; rni_ldid++) {
777             /* Determine agentid of the remote agents */
778             agentid = cmn700_ccg_ctx.raid_value + offset_id;
779 
780             /* Program RAID values in CCRA LDID to RAID LUT */
781             program_ccg_ra_rni_ldid_to_exp_raid_reg(ctx, rni_ldid, agentid);
782         }
783 
784         /*
785          * Program the CCRA SAM with the address range and the corresponding
786          * remote HAID
787          */
788         program_ccg_ra_sam_addr_region(ctx, ccg_config);
789 
790         if (ccg_config->ull_to_ull_mode) {
791             status = enable_ull_to_ull_mode(ctx, ccg_config);
792             if (status != FWK_SUCCESS) {
793                 return status;
794             }
795         }
796         /* Program the Link Control registers present in CCRA/CCHA/CCLA */
797         status = enable_and_start_ccg_link_up_sequence(ctx, 0);
798 
799         if (config->port_aggregate && !cmn700_ccg_ctx.is_prog_for_port_agg) {
800             cmn700_ccg_ctx.is_prog_for_port_agg = true;
801             FWK_LOG_INFO(MOD_NAME
802                          "Programming CCG gateway for Port Aggregation...");
803         } else {
804             cmn700_ccg_ctx.is_prog_for_port_agg = false;
805         }
806     } while (config->port_aggregate && cmn700_ccg_ctx.is_prog_for_port_agg);
807 
808     return status;
809 }
810 
ccg_exchange_protocol_credit(struct cmn700_device_ctx * ctx,const struct mod_cmn700_ccg_config * ccg_config)811 int ccg_exchange_protocol_credit(
812     struct cmn700_device_ctx *ctx,
813     const struct mod_cmn700_ccg_config *ccg_config)
814 {
815     int linkid;
816     unsigned int ccg_ldid;
817     struct cmn700_ccg_ra_reg *ccg_ra_reg;
818     struct cmn700_ccg_ha_reg *ccg_ha_reg;
819 
820     cmn700_ccg_ctx.is_prog_for_port_agg = false;
821 
822     do {
823         config = ccg_config;
824         ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
825         ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
826         ccg_ha_reg = ctx->ccg_ha_reg_table[ccg_ldid].ccg_ha_reg;
827 
828         /* Current support enables Link 0 only */
829         linkid = 0;
830 
831         FWK_LOG_INFO(
832             MOD_NAME "Exchanging protocol credits for link %d...", linkid);
833         /* Exchange protocol credits using link up bit */
834         ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL |=
835             CCG_LINK_CTRL_UP_MASK;
836         ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL |=
837             CCG_LINK_CTRL_UP_MASK;
838         FWK_LOG_INFO(
839             MOD_NAME "Exchanging protocol credits for link %d... Done", linkid);
840 
841         if (config->port_aggregate && !cmn700_ccg_ctx.is_prog_for_port_agg) {
842             cmn700_ccg_ctx.is_prog_for_port_agg = true;
843             FWK_LOG_INFO(MOD_NAME
844                          "Exchange Protocol Credit for Port Aggregation...");
845         } else {
846             cmn700_ccg_ctx.is_prog_for_port_agg = false;
847         }
848     } while (config->port_aggregate && cmn700_ccg_ctx.is_prog_for_port_agg);
849 
850     return FWK_SUCCESS;
851 }
852 
ccg_enter_system_coherency(struct cmn700_device_ctx * ctx,const struct mod_cmn700_ccg_config * ccg_config)853 int ccg_enter_system_coherency(
854     struct cmn700_device_ctx *ctx,
855     const struct mod_cmn700_ccg_config *ccg_config)
856 {
857     int status;
858     int linkid;
859     unsigned int ccg_ldid;
860     struct ccg_wait_condition_data wait_data;
861     struct cmn700_ccg_ha_reg *ccg_ha_reg;
862 
863     cmn700_ccg_ctx.is_prog_for_port_agg = false;
864 
865     do {
866         config = ccg_config;
867         ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
868         ccg_ha_reg = ctx->ccg_ha_reg_table[ccg_ldid].ccg_ha_reg;
869 
870         /* Current support enables Link 0 only */
871         linkid = 0;
872 
873         wait_data.ctx = ctx;
874         wait_data.linkid = linkid;
875 
876         FWK_LOG_INFO(
877             MOD_NAME "Entering system coherency for link %d...", linkid);
878         /* Enter system coherency by setting DVMDOMAIN request bit */
879         ccg_ha_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL |=
880             CCG_LINK_CTRL_DVMDOMAIN_REQ_MASK;
881 
882         /* Wait till DVMDOMAIN ACK bit is set in status register */
883         wait_data.cond = CCG_LINK_STATUS_HA_DVMDOMAIN_ACK_BIT_SET;
884         status = ctx->timer_api->wait(
885             FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
886             CCG_CCPRTCL_LINK_DVMDOMAIN_TIMEOUT,
887             ccg_link_wait_condition,
888             &wait_data);
889         if (status != FWK_SUCCESS) {
890             FWK_LOG_ERR(
891                 MOD_NAME "Entering system coherency for link %d... Failed",
892                 linkid);
893             return status;
894         }
895         FWK_LOG_INFO(
896             MOD_NAME "Entering system coherency for link %d... Done", linkid);
897 
898         if (config->port_aggregate && !cmn700_ccg_ctx.is_prog_for_port_agg) {
899             cmn700_ccg_ctx.is_prog_for_port_agg = true;
900             FWK_LOG_INFO(MOD_NAME
901                          "Enter system coherency for Port Aggregation...");
902         } else {
903             cmn700_ccg_ctx.is_prog_for_port_agg = false;
904         }
905     } while (config->port_aggregate && cmn700_ccg_ctx.is_prog_for_port_agg);
906 
907     return FWK_SUCCESS;
908 }
909 
ccg_enter_dvm_domain(struct cmn700_device_ctx * ctx,const struct mod_cmn700_ccg_config * ccg_config)910 int ccg_enter_dvm_domain(
911     struct cmn700_device_ctx *ctx,
912     const struct mod_cmn700_ccg_config *ccg_config)
913 {
914     int status;
915     int linkid;
916     unsigned int ccg_ldid;
917     struct ccg_wait_condition_data wait_data;
918     struct cmn700_ccg_ra_reg *ccg_ra_reg;
919 
920     cmn700_ccg_ctx.is_prog_for_port_agg = false;
921 
922     do {
923         config = ccg_config;
924         ccg_ldid = get_ldid(ctx, cmn700_ccg_ctx.is_prog_for_port_agg);
925         ccg_ra_reg = ctx->ccg_ra_reg_table[ccg_ldid].ccg_ra_reg;
926 
927         /* Current support enables Link 0 only */
928         linkid = 0;
929 
930         wait_data.ctx = ctx;
931         wait_data.linkid = linkid;
932 
933         FWK_LOG_INFO(MOD_NAME "Entering DVM domain for link %d...", linkid);
934         /* DVM domain entry by setting DVMDOMAIN request bit */
935         ccg_ra_reg->LINK_REGS[linkid].CCG_CCPRTCL_LINK_CTRL |=
936             CCG_LINK_CTRL_DVMDOMAIN_REQ_MASK;
937 
938         /* Wait till DVMDOMAIN ACK bit is set in status register */
939         wait_data.cond = CCG_LINK_STATUS_RA_DVMDOMAIN_ACK_BIT_SET;
940         status = ctx->timer_api->wait(
941             FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
942             CCG_CCPRTCL_LINK_DVMDOMAIN_TIMEOUT,
943             ccg_link_wait_condition,
944             &wait_data);
945         if (status != FWK_SUCCESS) {
946             FWK_LOG_ERR(
947                 MOD_NAME "Entering DVM domain for link %d... Failed", linkid);
948             return status;
949         }
950         FWK_LOG_INFO(
951             MOD_NAME "Entering DVM domain for link %d... Done", linkid);
952 
953         if (config->port_aggregate && !cmn700_ccg_ctx.is_prog_for_port_agg) {
954             cmn700_ccg_ctx.is_prog_for_port_agg = true;
955             FWK_LOG_INFO(MOD_NAME
956                          "Entering DVM domain for Port Aggregation...");
957         } else {
958             cmn700_ccg_ctx.is_prog_for_port_agg = false;
959         }
960     } while (config->port_aggregate && cmn700_ccg_ctx.is_prog_for_port_agg);
961 
962     return FWK_SUCCESS;
963 }
964