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