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  * Description:
8  *     TC0 System Support.
9  */
10 
11 #include "clock_soc.h"
12 #include "scp_pik.h"
13 #include "tc0_core.h"
14 #include "tc0_scmi.h"
15 #include "tc0_sds.h"
16 
17 #include <mod_clock.h>
18 #include <mod_power_domain.h>
19 #include <mod_ppu_v1.h>
20 #include <mod_scmi.h>
21 #include <mod_sds.h>
22 #include <mod_system_power.h>
23 #include <mod_tc0_system.h>
24 
25 #include <fwk_assert.h>
26 #include <fwk_id.h>
27 #include <fwk_interrupt.h>
28 #include <fwk_log.h>
29 #include <fwk_macros.h>
30 #include <fwk_module.h>
31 #include <fwk_module_idx.h>
32 #include <fwk_notification.h>
33 
34 #include <fmw_cmsis.h>
35 
36 #include <stdint.h>
37 
38 /* SCMI services required to enable the messaging stack */
39 static unsigned int scmi_notification_table[] = {
40     SCP_TC0_SCMI_SERVICE_IDX_PSCI,
41 };
42 
43 /* Module context */
44 struct tc0_system_ctx {
45     /* Pointer to the Interrupt Service Routine API of the PPU_V1 module */
46     const struct ppu_v1_isr_api *ppu_v1_isr_api;
47 
48     /* Power domain module restricted API pointer */
49     struct mod_pd_restricted_api *mod_pd_restricted_api;
50 
51     /* SDS API pointer */
52     const struct mod_sds_api *sds_api;
53 };
54 
55 struct tc0_system_isr {
56     unsigned int interrupt;
57     void (*handler)(void);
58 };
59 
60 static struct tc0_system_ctx tc0_system_ctx;
61 const struct fwk_module_config config_tc0_system = { 0 };
62 
63 static const uint32_t feature_flags =
64     (TC0_SDS_FEATURE_FIRMWARE_MASK | TC0_SDS_FEATURE_DMC_MASK |
65      TC0_SDS_FEATURE_MESSAGING_MASK);
66 
67 static fwk_id_t sds_feature_availability_id =
68     FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SDS, 1);
69 
70 /*
71  *  SCMI Messaging stack
72  */
73 
messaging_stack_ready(void)74 static int messaging_stack_ready(void)
75 {
76     const struct mod_sds_structure_desc *sds_structure_desc =
77         fwk_module_get_data(sds_feature_availability_id);
78 
79     /*
80      * Write SDS Feature Availability to signal the completion of the messaging
81      * stack
82      */
83     return tc0_system_ctx.sds_api->struct_write(
84         sds_structure_desc->id,
85         0,
86         (void *)(&feature_flags),
87         sds_structure_desc->size);
88 }
89 
90 /*
91  * System power's driver API
92  */
93 
tc0_system_shutdown(enum mod_pd_system_shutdown system_shutdown)94 static int tc0_system_shutdown(enum mod_pd_system_shutdown system_shutdown)
95 {
96     NVIC_SystemReset();
97 
98     return FWK_E_DEVICE;
99 }
100 
101 static const struct mod_system_power_driver_api
102     tc0_system_system_power_driver_api = {
103         .system_shutdown = tc0_system_shutdown,
104     };
105 
106 /*
107  * Functions fulfilling the framework's module interface
108  */
109 
tc0_system_mod_init(fwk_id_t module_id,unsigned int unused,const void * unused2)110 static int tc0_system_mod_init(
111     fwk_id_t module_id,
112     unsigned int unused,
113     const void *unused2)
114 {
115     return FWK_SUCCESS;
116 }
117 
tc0_system_bind(fwk_id_t id,unsigned int round)118 static int tc0_system_bind(fwk_id_t id, unsigned int round)
119 {
120     int status;
121 
122     if (round > 0) {
123         return FWK_SUCCESS;
124     }
125 
126     status = fwk_module_bind(
127         FWK_ID_MODULE(FWK_MODULE_IDX_POWER_DOMAIN),
128         FWK_ID_API(FWK_MODULE_IDX_POWER_DOMAIN, MOD_PD_API_IDX_RESTRICTED),
129         &tc0_system_ctx.mod_pd_restricted_api);
130     if (status != FWK_SUCCESS) {
131         return status;
132     }
133 
134     status = fwk_module_bind(
135         FWK_ID_MODULE(FWK_MODULE_IDX_PPU_V1),
136         FWK_ID_API(FWK_MODULE_IDX_PPU_V1, MOD_PPU_V1_API_IDX_ISR),
137         &tc0_system_ctx.ppu_v1_isr_api);
138     if (status != FWK_SUCCESS) {
139         return status;
140     }
141 
142     return fwk_module_bind(
143         fwk_module_id_sds,
144         FWK_ID_API(FWK_MODULE_IDX_SDS, 0),
145         &tc0_system_ctx.sds_api);
146 }
147 
tc0_system_process_bind_request(fwk_id_t requester_id,fwk_id_t pd_id,fwk_id_t api_id,const void ** api)148 static int tc0_system_process_bind_request(
149     fwk_id_t requester_id,
150     fwk_id_t pd_id,
151     fwk_id_t api_id,
152     const void **api)
153 {
154     *api = &tc0_system_system_power_driver_api;
155     return FWK_SUCCESS;
156 }
157 
tc0_system_start(fwk_id_t id)158 static int tc0_system_start(fwk_id_t id)
159 {
160     int status;
161     unsigned int i;
162 
163     /*
164      * Subscribe to these SCMI channels in order to know when they have all
165      * initialized.
166      * At that point we can consider the SCMI stack to be initialized from
167      * the point of view of the PSCI agent.
168      */
169     for (i = 0; i < FWK_ARRAY_SIZE(scmi_notification_table); i++) {
170         status = fwk_notification_subscribe(
171             mod_scmi_notification_id_initialized,
172             fwk_id_build_element_id(
173                 fwk_module_id_scmi, scmi_notification_table[i]),
174             id);
175         if (status != FWK_SUCCESS) {
176             return status;
177         }
178     }
179 
180     /*
181      * Subscribe to the SDS initialized notification so we can correctly let the
182      * PSCI agent know that the SCMI stack is initialized.
183      */
184     status = fwk_notification_subscribe(
185         mod_sds_notification_id_initialized, fwk_module_id_sds, id);
186     if (status != FWK_SUCCESS) {
187         return status;
188     }
189 
190     return tc0_system_ctx.mod_pd_restricted_api->set_state(
191         FWK_ID_ELEMENT(FWK_MODULE_IDX_POWER_DOMAIN, 0),
192         MOD_PD_SET_STATE_NO_RESP,
193         MOD_PD_COMPOSITE_STATE(
194             MOD_PD_LEVEL_2,
195             0,
196             MOD_PD_STATE_ON,
197             MOD_PD_STATE_OFF,
198             MOD_PD_STATE_OFF));
199 }
200 
tc0_system_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)201 static int tc0_system_process_notification(
202     const struct fwk_event *event,
203     struct fwk_event *resp_event)
204 {
205     static unsigned int scmi_notification_count = 0;
206     static bool sds_notification_received = false;
207 
208     fwk_assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_MODULE));
209 
210     if (fwk_id_is_equal(event->id, mod_scmi_notification_id_initialized)) {
211         scmi_notification_count++;
212     } else if (fwk_id_is_equal(
213                    event->id, mod_sds_notification_id_initialized)) {
214         sds_notification_received = true;
215     } else {
216         return FWK_E_PARAM;
217     }
218 
219     if ((scmi_notification_count == FWK_ARRAY_SIZE(scmi_notification_table)) &&
220         sds_notification_received) {
221         messaging_stack_ready();
222 
223         scmi_notification_count = 0;
224         sds_notification_received = false;
225     }
226 
227     return FWK_SUCCESS;
228 }
229 
230 const struct fwk_module module_tc0_system = {
231     .type = FWK_MODULE_TYPE_DRIVER,
232     .api_count = MOD_TC0_SYSTEM_API_COUNT,
233     .init = tc0_system_mod_init,
234     .bind = tc0_system_bind,
235     .process_bind_request = tc0_system_process_bind_request,
236     .process_notification = tc0_system_process_notification,
237     .start = tc0_system_start,
238 };
239