1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     RDN1E1 System Support.
9  */
10 
11 #include "config_clock.h"
12 #include "rdn1e1_core.h"
13 #include "rdn1e1_pik_scp.h"
14 #include "rdn1e1_sds.h"
15 #include "scp_rdn1e1_mmap.h"
16 #include "scp_rdn1e1_scmi.h"
17 
18 #include <mod_clock.h>
19 #include <mod_cmn600.h>
20 #include <mod_power_domain.h>
21 #include <mod_ppu_v1.h>
22 #include <mod_rdn1e1_system.h>
23 #include <mod_scmi.h>
24 #include <mod_sds.h>
25 #include <mod_system_info.h>
26 #include <mod_system_power.h>
27 
28 #include <fwk_assert.h>
29 #include <fwk_event.h>
30 #include <fwk_id.h>
31 #include <fwk_interrupt.h>
32 #include <fwk_log.h>
33 #include <fwk_macros.h>
34 #include <fwk_module.h>
35 #include <fwk_module_idx.h>
36 #include <fwk_notification.h>
37 #include <fwk_status.h>
38 
39 #include <fmw_cmsis.h>
40 
41 #include <stdbool.h>
42 #include <stdint.h>
43 
44 /* SCMI services required to enable the messaging stack */
45 static unsigned int scmi_notification_table[] = {
46     SCP_RDN1E1_SCMI_SERVICE_IDX_PSCI,
47     SCP_RDN1E1_SCMI_SERVICE_IDX_OSPM,
48 };
49 
50 /* Module context */
51 struct rdn1e1_system_ctx {
52     /* Pointer to the SCP PIK registers */
53     struct pik_scp_reg *pik_scp_reg;
54 
55     /* Pointer to the Interrupt Service Routine API of the PPU_V1 module */
56     const struct ppu_v1_isr_api *ppu_v1_isr_api;
57 
58     /* Power domain module restricted API pointer */
59     struct mod_pd_restricted_api *mod_pd_restricted_api;
60 
61     /* SDS API pointer */
62     const struct mod_sds_api *sds_api;
63 
64     /* CMN600 CCIX config API pointer */
65     struct mod_cmn600_ccix_config_api *cmn600_api;
66 
67     /* System Information HAL API pointer */
68     struct mod_system_info_get_info_api *system_info_api;
69 };
70 
71 struct rdn1e1_system_isr {
72     unsigned int interrupt;
73     void (*handler)(void);
74 };
75 
76 static struct rdn1e1_system_ctx rdn1e1_system_ctx;
77 const struct fwk_module_config config_rdn1e1_system = { 0 };
78 
79 static const uint32_t feature_flags = (RDN1E1_SDS_FEATURE_FIRMWARE_MASK |
80                                        RDN1E1_SDS_FEATURE_DMC_MASK |
81                                        RDN1E1_SDS_FEATURE_MESSAGING_MASK);
82 
83 static fwk_id_t sds_feature_availability_id =
84     FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SDS, 3);
85 
86 /*
87  *  SCMI Messaging stack
88  */
89 
messaging_stack_ready(void)90 static int messaging_stack_ready(void)
91 {
92     const struct mod_sds_structure_desc *sds_structure_desc =
93         fwk_module_get_data(sds_feature_availability_id);
94 
95     /*
96      * Write SDS Feature Availability to signal the completion of the messaging
97      * stack
98      */
99     return rdn1e1_system_ctx.sds_api->struct_write(sds_structure_desc->id,
100         0, (void *)(&feature_flags), sds_structure_desc->size);
101 }
102 
103 /*
104  *  PPU Interrupt Service Routines for cluster and core power domains
105  */
106 
ppu_cores_isr(unsigned int first,uint32_t status)107 static void ppu_cores_isr(unsigned int first, uint32_t status)
108 {
109     unsigned int core_idx;
110 
111     while (status != 0) {
112         core_idx = __builtin_ctz(status);
113         status &= ~(1 << core_idx);
114 
115         if ((first + core_idx) >= rdn1e1_core_get_core_count())
116             continue;
117 
118         rdn1e1_system_ctx.ppu_v1_isr_api->ppu_interrupt_handler(
119             FWK_ID_ELEMENT(FWK_MODULE_IDX_PPU_V1, first + core_idx));
120     }
121 }
122 
ppu_cores_isr_0(void)123 static void ppu_cores_isr_0(void)
124 {
125     ppu_cores_isr(0, rdn1e1_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[0]);
126     ppu_cores_isr(128, rdn1e1_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[4]);
127 }
128 
ppu_cores_isr_1(void)129 static void ppu_cores_isr_1(void)
130 {
131     ppu_cores_isr(32, rdn1e1_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[1]);
132     ppu_cores_isr(160, rdn1e1_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[5]);
133 }
134 
ppu_cores_isr_2(void)135 static void ppu_cores_isr_2(void)
136 {
137     ppu_cores_isr(64, rdn1e1_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[2]);
138     ppu_cores_isr(192, rdn1e1_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[6]);
139 }
140 
ppu_cores_isr_3(void)141 static void ppu_cores_isr_3(void)
142 {
143     ppu_cores_isr(96, rdn1e1_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[3]);
144     ppu_cores_isr(224, rdn1e1_system_ctx.pik_scp_reg->CPU_PPU_INT_STATUS[7]);
145 }
146 
ppu_clusters_isr(void)147 static void ppu_clusters_isr(void)
148 {
149     uint32_t status = rdn1e1_system_ctx.pik_scp_reg->CLUS_PPU_INT_STATUS;
150     unsigned int cluster_idx;
151 
152     while (status != 0) {
153         cluster_idx = __builtin_ctz(status);
154 
155         rdn1e1_system_ctx.ppu_v1_isr_api->ppu_interrupt_handler(
156             FWK_ID_ELEMENT(FWK_MODULE_IDX_PPU_V1,
157             rdn1e1_core_get_core_count() + cluster_idx));
158 
159         status &= ~(1 << cluster_idx);
160     }
161 }
162 
163 /*
164  *  PPU Interrupt Service Routine table
165  */
166 
167 static struct rdn1e1_system_isr isrs[] = {
168     [0] = { .interrupt = PPU_CORES0_IRQ,
169             .handler = ppu_cores_isr_0 },
170     [1] = { .interrupt = PPU_CORES1_IRQ,
171             .handler = ppu_cores_isr_1 },
172     [2] = { .interrupt = PPU_CORES2_IRQ,
173             .handler = ppu_cores_isr_2 },
174     [3] = { .interrupt = PPU_CORES3_IRQ,
175             .handler = ppu_cores_isr_3 },
176     [4] = { .interrupt = PPU_CLUSTERS_IRQ,
177             .handler = ppu_clusters_isr },
178 };
179 
180 /*
181  * System power's driver API
182  */
183 
rdn1e1_system_shutdown(enum mod_pd_system_shutdown system_shutdown)184 static int rdn1e1_system_shutdown(
185     enum mod_pd_system_shutdown system_shutdown)
186 {
187     NVIC_SystemReset();
188 
189     return FWK_E_DEVICE;
190 }
191 
192 static const struct mod_system_power_driver_api
193     rdn1e1_system_system_power_driver_api = {
194     .system_shutdown = rdn1e1_system_shutdown,
195 };
196 
197 /*
198  * Functions fulfilling the framework's module interface
199  */
200 
rdn1e1_system_mod_init(fwk_id_t module_id,unsigned int unused,const void * unused2)201 static int rdn1e1_system_mod_init(fwk_id_t module_id, unsigned int unused,
202     const void *unused2)
203 {
204     int status;
205     unsigned int idx;
206     struct rdn1e1_system_isr *isr;
207 
208     for (idx = 0; idx < FWK_ARRAY_SIZE(isrs); idx++) {
209         isr = &isrs[idx];
210         status = fwk_interrupt_set_isr(isr->interrupt, isr->handler);
211         if (status != FWK_SUCCESS)
212             return status;
213     }
214 
215     rdn1e1_system_ctx.pik_scp_reg = (struct pik_scp_reg *)SCP_PIK_SCP_BASE;
216 
217     return FWK_SUCCESS;
218 }
219 
rdn1e1_system_bind(fwk_id_t id,unsigned int round)220 static int rdn1e1_system_bind(fwk_id_t id, unsigned int round)
221 {
222     int status;
223 
224     if (round > 0)
225         return FWK_SUCCESS;
226 
227     status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_POWER_DOMAIN),
228         FWK_ID_API(FWK_MODULE_IDX_POWER_DOMAIN, MOD_PD_API_IDX_RESTRICTED),
229         &rdn1e1_system_ctx.mod_pd_restricted_api);
230     if (status != FWK_SUCCESS)
231         return status;
232 
233     status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_PPU_V1),
234         FWK_ID_API(FWK_MODULE_IDX_PPU_V1, MOD_PPU_V1_API_IDX_ISR),
235         &rdn1e1_system_ctx.ppu_v1_isr_api);
236     if (status != FWK_SUCCESS)
237         return status;
238 
239     status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_CMN600),
240                              FWK_ID_API(FWK_MODULE_IDX_CMN600,
241                                         MOD_CMN600_API_IDX_CCIX_CONFIG),
242                              &rdn1e1_system_ctx.cmn600_api);
243     if (status != FWK_SUCCESS)
244         return status;
245 
246     status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_SYSTEM_INFO),
247                              FWK_ID_API(FWK_MODULE_IDX_SYSTEM_INFO,
248                                         MOD_SYSTEM_INFO_GET_API_IDX),
249                              &rdn1e1_system_ctx.system_info_api);
250    if (status != FWK_SUCCESS)
251        return status;
252 
253     return fwk_module_bind(fwk_module_id_sds,
254         FWK_ID_API(FWK_MODULE_IDX_SDS, 0),
255         &rdn1e1_system_ctx.sds_api);
256 }
257 
rdn1e1_system_process_bind_request(fwk_id_t requester_id,fwk_id_t pd_id,fwk_id_t api_id,const void ** api)258 static int rdn1e1_system_process_bind_request(fwk_id_t requester_id,
259     fwk_id_t pd_id, fwk_id_t api_id, const void **api)
260 {
261     *api = &rdn1e1_system_system_power_driver_api;
262     return FWK_SUCCESS;
263 }
264 
rdn1e1_system_start(fwk_id_t id)265 static int rdn1e1_system_start(fwk_id_t id)
266 {
267     int status;
268     unsigned int i;
269 
270     status = fwk_notification_subscribe(
271         mod_clock_notification_id_state_changed,
272         FWK_ID_ELEMENT(FWK_MODULE_IDX_CLOCK, CLOCK_IDX_INTERCONNECT),
273         id);
274     if (status != FWK_SUCCESS)
275         return status;
276 
277     FWK_LOG_INFO("[RDN1E1 SYSTEM] Requesting SYSTOP initialization...");
278 
279     /*
280      * Subscribe to these SCMI channels in order to know when they have all
281      * initialized.
282      * At that point we can consider the SCMI stack to be initialized from
283      * the point of view of the PSCI agent.
284      */
285     for (i = 0; i < FWK_ARRAY_SIZE(scmi_notification_table); i++) {
286         status = fwk_notification_subscribe(
287             mod_scmi_notification_id_initialized,
288             fwk_id_build_element_id(fwk_module_id_scmi,
289                 scmi_notification_table[i]),
290             id);
291         if (status != FWK_SUCCESS)
292             return status;
293     }
294 
295     /*
296      * Subscribe to the SDS initialized notification so we can correctly let the
297      * PSCI agent know that the SCMI stack is initialized.
298      */
299     status = fwk_notification_subscribe(
300         mod_sds_notification_id_initialized,
301         fwk_module_id_sds,
302         id);
303     if (status != FWK_SUCCESS)
304         return status;
305 
306     return rdn1e1_system_ctx.mod_pd_restricted_api->set_state(
307         FWK_ID_ELEMENT(FWK_MODULE_IDX_POWER_DOMAIN, 0),
308         false,
309         MOD_PD_COMPOSITE_STATE(
310             MOD_PD_LEVEL_2,
311             0,
312             MOD_PD_STATE_ON,
313             MOD_PD_STATE_OFF,
314             MOD_PD_STATE_OFF));
315 }
316 
rdn1e1_system_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)317 int rdn1e1_system_process_notification(const struct fwk_event *event,
318     struct fwk_event *resp_event)
319 {
320     int status;
321     struct clock_notification_params *params;
322     struct mod_pd_restricted_api *mod_pd_restricted_api;
323     static unsigned int scmi_notification_count = 0;
324     static bool sds_notification_received = false;
325     struct mod_cmn600_ccix_remote_node_config remote_config;
326     const struct mod_system_info *system_info;
327     uint8_t chip_id = 0;
328     bool mc_mode = false;
329 
330     status = rdn1e1_system_ctx.system_info_api->get_system_info(&system_info);
331     if (status == FWK_SUCCESS) {
332         chip_id = system_info->chip_id;
333         mc_mode = system_info->multi_chip_mode;
334     }
335 
336     fwk_assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_MODULE));
337 
338     if (fwk_id_is_equal(event->id, mod_clock_notification_id_state_changed)) {
339         params = (struct clock_notification_params *)event->params;
340         if (params->new_state != MOD_CLOCK_STATE_RUNNING)
341             return FWK_SUCCESS;
342 
343         /* Perform the CCIX setup if multi-chip mode is detected */
344         if (mc_mode == true) {
345             /* Populate CCIX config data statically */
346             remote_config.remote_rnf_count = 2;
347             remote_config.remote_sa_count = 0;
348             remote_config.remote_ha_count = 1;
349             remote_config.ccix_link_id = 0;
350             remote_config.remote_ha_mmap_count = 1;
351             remote_config.smp_mode = true;
352             if (chip_id == 0) {
353                 remote_config.remote_ha_mmap[0].ha_id = 0x1;
354                 remote_config.remote_ha_mmap[0].base = (4ULL * FWK_TIB);
355             } else {
356                 remote_config.remote_ha_mmap[0].ha_id = 0x0;
357                 remote_config.remote_ha_mmap[0].base = 0x0;
358             }
359             remote_config.remote_ha_mmap[0].size = (4ULL * FWK_TIB);
360 
361             status = rdn1e1_system_ctx.cmn600_api->set_config(&remote_config);
362             if (status != FWK_SUCCESS) {
363                 FWK_LOG_ERR("CCIX Setup Failed for Chip: %d!", chip_id);
364                 return status;
365             }
366             rdn1e1_system_ctx.cmn600_api->exchange_protocol_credit(0);
367             rdn1e1_system_ctx.cmn600_api->enter_system_coherency(0);
368             rdn1e1_system_ctx.cmn600_api->enter_dvm_domain(0);
369         }
370 
371         /*
372          * Initialize primary core when the system is initialized for the first
373          * time only
374          */
375         if (chip_id == 0) {
376             FWK_LOG_INFO("[RDN1E1 SYSTEM] Initializing the primary core...");
377 
378             mod_pd_restricted_api = rdn1e1_system_ctx.mod_pd_restricted_api;
379 
380             status = mod_pd_restricted_api->set_state(
381                 FWK_ID_ELEMENT(FWK_MODULE_IDX_POWER_DOMAIN, 0),
382                 MOD_PD_SET_STATE_NO_RESP,
383                 MOD_PD_COMPOSITE_STATE(
384                     MOD_PD_LEVEL_2,
385                     0,
386                     MOD_PD_STATE_ON,
387                     MOD_PD_STATE_ON,
388                     MOD_PD_STATE_ON));
389             if (status != FWK_SUCCESS)
390                 return status;
391         } else {
392             FWK_LOG_INFO(
393                 "[RDN1E1 SYSTEM] Detected as secondary chip %d, "
394                 "Waiting for SCMI command",
395                 chip_id);
396         }
397 
398         /* Unsubscribe to the notification */
399         return fwk_notification_unsubscribe(event->id, event->source_id,
400                                             event->target_id);
401     } else if (fwk_id_is_equal(event->id,
402                                mod_scmi_notification_id_initialized)) {
403         scmi_notification_count++;
404     } else if (fwk_id_is_equal(event->id,
405                                mod_sds_notification_id_initialized)) {
406         sds_notification_received = true;
407     } else
408         return FWK_E_PARAM;
409 
410     if ((scmi_notification_count == FWK_ARRAY_SIZE(scmi_notification_table)) &&
411         sds_notification_received) {
412         messaging_stack_ready();
413 
414         scmi_notification_count = 0;
415         sds_notification_received = false;
416     }
417 
418     return FWK_SUCCESS;
419 }
420 
421 const struct fwk_module module_rdn1e1_system = {
422     .type = FWK_MODULE_TYPE_DRIVER,
423     .api_count = MOD_RDN1E1_SYSTEM_API_COUNT,
424     .init = rdn1e1_system_mod_init,
425     .bind = rdn1e1_system_bind,
426     .process_bind_request = rdn1e1_system_process_bind_request,
427     .process_notification = rdn1e1_system_process_notification,
428     .start = rdn1e1_system_start,
429 };
430