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