1 /*
2 * Renesas SCP/MCP Software
3 * Copyright (c) 2020-2022, Renesas Electronics Corporation. All rights
4 * reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include <mmio.h>
10 #include <rcar_mmap.h>
11 #include <rcar_pwc.h>
12 #include <rcar_scmi.h>
13 #include <rcar_sds.h>
14
15 #include <mod_clock.h>
16 #include <mod_rcar_clock.h>
17 #include <mod_rcar_reg_sensor.h>
18 #include <mod_rcar_scif.h>
19 #include <mod_rcar_system.h>
20 #include <mod_scmi.h>
21 #include <mod_system_power.h>
22
23 #include <fwk_assert.h>
24 #include <fwk_core.h>
25 #include <fwk_element.h>
26 #include <fwk_id.h>
27 #include <fwk_interrupt.h>
28 #include <fwk_macros.h>
29 #include <fwk_mm.h>
30 #include <fwk_module.h>
31 #include <fwk_module_idx.h>
32 #include <fwk_notification.h>
33 #include <fwk_status.h>
34
35 #include <arch_gic.h>
36 #include <arch_helpers.h>
37 #include <arch_system.h>
38
39 /* Device context */
40 struct rcar_system_dev_ctx {
41 const struct mod_rcar_system_dev_config *config;
42 struct mod_rcar_system_drv_api *api;
43 };
44
45 /* Module context */
46 struct rcar_system_ctx {
47 struct rcar_system_dev_ctx *dev_ctx_table;
48 unsigned int dev_count;
49 struct mod_sds_api *sds_api;
50 };
51
52 static struct rcar_system_ctx module_ctx;
53
54 /*-----------------------------------------------------------*/
55 #define P_STATUS (_shutdown_request)
56
57 static fwk_id_t sds_feature_availability_id =
58 FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_SDS, RCAR_SDS_RAM_FEATURES_IDX);
59
60 /* SCMI services required to enable the messaging stack */
61 static unsigned int scmi_notification_table[] = {
62 RCAR_SCMI_SERVICE_IDX_PSCI,
63 RCAR_SCMI_SERVICE_IDX_OSPM,
64 RCAR_SCMI_SERVICE_IDX_VMM,
65 RCAR_SCMI_SERVICE_IDX_VM1,
66 RCAR_SCMI_SERVICE_IDX_VM2,
67 };
68
69 IMPORT_SYM(unsigned long, __system_ram_start__, SYSTEM_RAM_START);
70 IMPORT_SYM(unsigned long, __system_ram_end__, SYSTEM_RAM_END);
71 IMPORT_SYM(unsigned long, __sram_copy_start__, SRAM_COPY_START);
72
73 /*
74 * Static helpers
75 */
76
messaging_stack_ready(void)77 static int messaging_stack_ready(void)
78 {
79 const uint32_t rcar_sys_flags = RCAR_SDS_FEATURE_FIRMWARE_MASK;
80
81 const struct mod_sds_structure_desc *sds_structure_desc =
82 fwk_module_get_data(sds_feature_availability_id);
83
84 if (sds_structure_desc == NULL)
85 return FWK_E_PARAM;
86
87 /*
88 * Write SDS Feature Availability to signal the completion of the messaging
89 * stack
90 */
91 return module_ctx.sds_api->struct_write(sds_structure_desc->id,
92 0, (const void *)(&rcar_sys_flags), sds_structure_desc->size);
93 }
94
is_available_shutdown_req(uint32_t req)95 bool is_available_shutdown_req(uint32_t req)
96 {
97 bool ret;
98
99 switch (req) {
100 case R_WARMBOOT:
101 case R_SUSPEND:
102 case R_RESET:
103 case R_OFF:
104 ret = true;
105 break;
106 default:
107 ret = false;
108 break;
109 }
110 return ret;
111 }
112
rcar_system_code_copy_to_system_ram(void)113 void rcar_system_code_copy_to_system_ram(void)
114 {
115 memcpy(
116 (void *)SCP_SRAM_BASE,
117 (void *)SRAM_COPY_START,
118 (SYSTEM_RAM_END - SYSTEM_RAM_START));
119 }
120
_platform_init(void * params)121 int _platform_init(void *params)
122 {
123 rcar_system_code_copy_to_system_ram();
124 return FWK_SUCCESS;
125 }
126
vApplicationIdleHook(void)127 void vApplicationIdleHook(void)
128 {
129 uint32_t req;
130 struct rcar_system_dev_ctx *ctx;
131 fwk_id_t element_id = FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_CLOCK, 0);
132 uint32_t i;
133 unsigned int flags;
134
135 if (is_available_shutdown_req(P_STATUS)) {
136 flags = fwk_interrupt_global_disable();
137 req = P_STATUS;
138 P_STATUS = R_CLEAR;
139 switch (req) {
140 case R_SUSPEND:
141 _boot_flag = R_WARMBOOT;
142 while (!(mmio_read_32(RCAR_CA57PSTR) & 0x0f))
143 continue;
144
145 _save_system();
146
147 rcar_system_code_copy_to_system_ram();
148
149 for (i = 0; i < module_ctx.dev_count; i++) {
150 element_id.element.element_idx = i;
151 ctx = module_ctx.dev_ctx_table +
152 fwk_id_get_element_idx(element_id);
153 if (ctx->api->resume)
154 ctx->api->resume();
155 }
156
157 messaging_stack_ready();
158 gic_init();
159 vConfigureTickInterrupt();
160 fwk_interrupt_global_enable(flags);
161 break;
162 case R_RESET:
163 rcar_system_reset();
164 break;
165 case R_OFF:
166 rcar_system_off();
167 break;
168 default:
169 break;
170 }
171 }
172 }
173
174 /*
175 * Functions fulfilling the framework's module interface
176 */
177
rcar_system_shutdown(enum mod_pd_system_shutdown system_shutdown)178 static int rcar_system_shutdown(enum mod_pd_system_shutdown system_shutdown)
179 {
180 switch (system_shutdown) {
181 case MOD_PD_SYSTEM_SHUTDOWN:
182 _shutdown_request = R_OFF;
183 break;
184 case MOD_PD_SYSTEM_COLD_RESET:
185 _shutdown_request = R_RESET;
186 break;
187 default:
188 break;
189 }
190
191 return FWK_PENDING;
192 }
193
194 static const struct mod_system_power_driver_api
195 rcar_system_system_power_driver_api = { .system_shutdown =
196 rcar_system_shutdown };
197
198 /*
199 * Functions fulfilling the framework's module interface
200 */
201
rcar_system_init(fwk_id_t module_id,unsigned int element_count,const void * data)202 static int rcar_system_init(
203 fwk_id_t module_id,
204 unsigned int element_count,
205 const void *data)
206 {
207 module_ctx.dev_count = element_count;
208
209 if (element_count == 0)
210 return FWK_SUCCESS;
211
212 module_ctx.dev_ctx_table =
213 fwk_mm_calloc(element_count, sizeof(struct rcar_system_dev_ctx));
214 if (module_ctx.dev_ctx_table == NULL)
215 return FWK_E_NOMEM;
216
217 return FWK_SUCCESS;
218 }
rcar_system_element(fwk_id_t element_id,unsigned int sub_element_count,const void * data)219 static int rcar_system_element(
220 fwk_id_t element_id,
221 unsigned int sub_element_count,
222 const void *data)
223 {
224 struct rcar_system_dev_ctx *ctx;
225 const struct mod_rcar_system_dev_config *dev_config = data;
226
227 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(element_id);
228 ctx->config = dev_config;
229
230 return FWK_SUCCESS;
231 }
232
rcar_system_bind(fwk_id_t id,unsigned int round)233 static int rcar_system_bind(fwk_id_t id, unsigned int round)
234 {
235 struct rcar_system_dev_ctx *ctx;
236
237 if (round == 1)
238 return FWK_SUCCESS;
239
240 if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE))
241 /* Module */
242 return fwk_module_bind(fwk_module_id_sds,
243 FWK_ID_API(FWK_MODULE_IDX_SDS, 0),
244 &module_ctx.sds_api);
245
246 /* Elements */
247 ctx = module_ctx.dev_ctx_table + fwk_id_get_element_idx(id);
248
249 return fwk_module_bind(
250 ctx->config->driver_id, ctx->config->api_id, &ctx->api);
251 }
252
rcar_system_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)253 static int rcar_system_process_bind_request(
254 fwk_id_t source_id,
255 fwk_id_t target_id,
256 fwk_id_t api_id,
257 const void **api)
258 {
259 *api = &rcar_system_system_power_driver_api;
260
261 return FWK_SUCCESS;
262 }
263
rcar_system_start(fwk_id_t id)264 static int rcar_system_start(fwk_id_t id)
265 {
266 int status;
267 unsigned int i;
268
269 /*
270 * Subscribe to these SCMI channels in order to know when they have all
271 * initialized.
272 * At that point we can consider the SCMI stack to be initialized from
273 * the point of view of the PSCI agent.
274 */
275 if (fwk_id_get_type(id) != FWK_ID_TYPE_MODULE)
276 return FWK_SUCCESS;
277
278 for (i = 0; i < FWK_ARRAY_SIZE(scmi_notification_table); i++) {
279 status = fwk_notification_subscribe(
280 mod_scmi_notification_id_initialized,
281 fwk_id_build_element_id(
282 fwk_module_id_scmi, scmi_notification_table[i]),
283 id);
284 if (status != FWK_SUCCESS)
285 return status;
286 }
287
288 /*
289 * Subscribe to the SDS initialized notification so we can correctly let the
290 * PSCI agent know that the SCMI stack is initialized.
291 */
292 return fwk_notification_subscribe(
293 mod_sds_notification_id_initialized,
294 fwk_module_id_sds,
295 id);
296 }
297
rcar_system_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)298 static int rcar_system_process_notification(
299 const struct fwk_event *event,
300 struct fwk_event *resp_event)
301 {
302 static unsigned int scmi_notification_count = 0;
303 static bool sds_notification_received = false;
304
305 if (!fwk_expect(fwk_id_is_type(event->target_id, FWK_ID_TYPE_MODULE)))
306 return FWK_E_PARAM;
307
308 if (fwk_id_is_equal(event->id, mod_scmi_notification_id_initialized))
309 scmi_notification_count++;
310 else if (fwk_id_is_equal(event->id,
311 mod_sds_notification_id_initialized))
312 sds_notification_received = true;
313 else
314 return FWK_E_PARAM;
315
316 sds_notification_received = true;
317 if ((scmi_notification_count == FWK_ARRAY_SIZE(scmi_notification_table)) &&
318 sds_notification_received) {
319 messaging_stack_ready();
320
321 scmi_notification_count = 0;
322 sds_notification_received = false;
323 }
324
325 return FWK_SUCCESS;
326 }
327
328 const struct fwk_module module_rcar_system = {
329 .api_count = MOD_RCAR_SYSTEM_API_COUNT,
330 .type = FWK_MODULE_TYPE_DRIVER,
331 .init = rcar_system_init,
332 .element_init = rcar_system_element,
333 .bind = rcar_system_bind,
334 .start = rcar_system_start,
335 .process_bind_request = rcar_system_process_bind_request,
336 .process_notification = rcar_system_process_notification,
337 };
338