1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     TC2 System Support.
9  */
10 
11 #include "clock_soc.h"
12 #include "scp_pik.h"
13 #include "tc2_core.h"
14 #include "tc2_scmi.h"
15 #include "tc2_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_tc2_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[1] = {
40     (unsigned int)SCP_TC2_SCMI_SERVICE_IDX_PSCI,
41 };
42 
43 /* Module context */
44 struct tc2_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 tc2_system_isr {
56     unsigned int interrupt;
57     void (*handler)(void);
58 };
59 
60 static struct tc2_system_ctx mod_ctx;
61 
62 static const uint32_t feature_flags =
63     (TC2_SDS_FEATURE_FIRMWARE_MASK | TC2_SDS_FEATURE_DMC_MASK |
64      TC2_SDS_FEATURE_MESSAGING_MASK);
65 
66 static fwk_id_t sds_feature_availability_id =
67     FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SDS, 1);
68 
69 /*
70  *  SCMI Messaging stack
71  */
72 
messaging_stack_ready(void)73 static int messaging_stack_ready(void)
74 {
75     const struct mod_sds_structure_desc *sds_structure_desc =
76         fwk_module_get_data(sds_feature_availability_id);
77 
78     /*
79      * Write SDS Feature Availability to signal the completion of the messaging
80      * stack
81      */
82     return mod_ctx.sds_api->struct_write(
83         sds_structure_desc->id,
84         0,
85         (void *)(&feature_flags),
86         sds_structure_desc->size);
87 }
88 
89 /*
90  * System power's driver API
91  */
92 
tc2_system_shutdown(enum mod_pd_system_shutdown system_shutdown)93 static int tc2_system_shutdown(enum mod_pd_system_shutdown system_shutdown)
94 {
95     NVIC_SystemReset();
96 
97     return FWK_E_DEVICE;
98 }
99 
100 static const struct mod_system_power_driver_api
101     tc2_system_system_power_driver_api = {
102         .system_shutdown = tc2_system_shutdown,
103     };
104 
105 /*
106  * Functions fulfilling the framework's module interface
107  */
108 
tc2_system_mod_init(fwk_id_t module_id,unsigned int unused,const void * unused2)109 static int tc2_system_mod_init(
110     fwk_id_t module_id,
111     unsigned int unused,
112     const void *unused2)
113 {
114     return FWK_SUCCESS;
115 }
116 
tc2_system_bind(fwk_id_t id,unsigned int round)117 static int tc2_system_bind(fwk_id_t id, unsigned int round)
118 {
119     int status;
120 
121     if (round > 0) {
122         return FWK_SUCCESS;
123     }
124 
125     status = fwk_module_bind(
126         FWK_ID_MODULE(FWK_MODULE_IDX_POWER_DOMAIN),
127         FWK_ID_API(FWK_MODULE_IDX_POWER_DOMAIN, MOD_PD_API_IDX_RESTRICTED),
128         &mod_ctx.mod_pd_restricted_api);
129     if (status != FWK_SUCCESS) {
130         return status;
131     }
132 
133     status = fwk_module_bind(
134         FWK_ID_MODULE(FWK_MODULE_IDX_PPU_V1),
135         FWK_ID_API(FWK_MODULE_IDX_PPU_V1, MOD_PPU_V1_API_IDX_ISR),
136         &mod_ctx.ppu_v1_isr_api);
137     if (status != FWK_SUCCESS) {
138         return status;
139     }
140 
141     return fwk_module_bind(
142         fwk_module_id_sds, FWK_ID_API(FWK_MODULE_IDX_SDS, 0), &mod_ctx.sds_api);
143 }
144 
tc2_system_process_bind_request(fwk_id_t requester_id,fwk_id_t pd_id,fwk_id_t api_id,const void ** api)145 static int tc2_system_process_bind_request(
146     fwk_id_t requester_id,
147     fwk_id_t pd_id,
148     fwk_id_t api_id,
149     const void **api)
150 {
151     *api = &tc2_system_system_power_driver_api;
152     return FWK_SUCCESS;
153 }
154 
tc2_system_start(fwk_id_t id)155 static int tc2_system_start(fwk_id_t id)
156 {
157     int status;
158     unsigned int i;
159 
160     /*
161      * Subscribe to these SCMI channels in order to know when they have all
162      * initialized.
163      * At that point we can consider the SCMI stack to be initialized from
164      * the point of view of the PSCI agent.
165      */
166     for (i = 0; i < FWK_ARRAY_SIZE(scmi_notification_table); i++) {
167         status = fwk_notification_subscribe(
168             mod_scmi_notification_id_initialized,
169             fwk_id_build_element_id(
170                 fwk_module_id_scmi, scmi_notification_table[i]),
171             id);
172         if (status != FWK_SUCCESS) {
173             return status;
174         }
175     }
176 
177     /*
178      * Subscribe to the SDS initialized notification so we can correctly let the
179      * PSCI agent know that the SCMI stack is initialized.
180      */
181     status = fwk_notification_subscribe(
182         mod_sds_notification_id_initialized, fwk_module_id_sds, id);
183     if (status != FWK_SUCCESS) {
184         return status;
185     }
186 
187     return mod_ctx.mod_pd_restricted_api->set_state(
188         FWK_ID_ELEMENT(FWK_MODULE_IDX_POWER_DOMAIN, 0),
189         MOD_PD_SET_STATE_NO_RESP,
190         MOD_PD_COMPOSITE_STATE(
191             MOD_PD_LEVEL_2,
192             0,
193             MOD_PD_STATE_ON,
194             MOD_PD_STATE_OFF,
195             MOD_PD_STATE_OFF));
196 }
197 
tc2_system_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)198 static int tc2_system_process_notification(
199     const struct fwk_event *event,
200     struct fwk_event *resp_event)
201 {
202     static unsigned int scmi_notification_count = 0;
203     static bool sds_notification_received = false;
204 
205     fwk_assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_MODULE));
206 
207     if (fwk_id_is_equal(event->id, mod_scmi_notification_id_initialized)) {
208         scmi_notification_count++;
209     } else if (fwk_id_is_equal(
210                    event->id, mod_sds_notification_id_initialized)) {
211         sds_notification_received = true;
212     } else {
213         return FWK_E_PARAM;
214     }
215 
216     if ((scmi_notification_count == FWK_ARRAY_SIZE(scmi_notification_table)) &&
217         sds_notification_received) {
218         messaging_stack_ready();
219 
220         scmi_notification_count = 0;
221         sds_notification_received = false;
222     }
223 
224     return FWK_SUCCESS;
225 }
226 
227 const struct fwk_module module_tc2_system = {
228     .type = FWK_MODULE_TYPE_DRIVER,
229     .api_count = MOD_TC2_SYSTEM_API_COUNT,
230     .init = tc2_system_mod_init,
231     .bind = tc2_system_bind,
232     .process_bind_request = tc2_system_process_bind_request,
233     .process_notification = tc2_system_process_notification,
234     .start = tc2_system_start,
235 };
236 
237 const struct fwk_module_config config_tc2_system = { 0 };
238