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