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