1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description: Module dedicated to the ROM firmware of the mobile platforms to
8  *     initiate the boot of the primary AP core and then to jump to the SCP RAM
9  *     firmware.
10  */
11 
12 #include <mod_bootloader.h>
13 #include <mod_msys_rom.h>
14 #include <mod_power_domain.h>
15 #include <mod_ppu_v1.h>
16 
17 #include <fwk_assert.h>
18 #include <fwk_core.h>
19 #include <fwk_event.h>
20 #include <fwk_id.h>
21 #include <fwk_log.h>
22 #include <fwk_module.h>
23 #include <fwk_module_idx.h>
24 #include <fwk_notification.h>
25 #include <fwk_status.h>
26 
27 #include <stdbool.h>
28 #include <string.h>
29 
30 struct msys_rom_ctx {
31     const struct msys_rom_config *rom_config;
32     struct ppu_v1_boot_api *ppu_boot_api;
33     struct mod_bootloader_api *bootloader_api;
34     unsigned int notification_count; /* Notifications awaiting a response */
35 } ctx;
36 
37 enum rom_event {
38     ROM_EVENT_RUN,
39     ROM_EVENT_COUNT
40 };
41 
msys_deferred_setup(void)42 static int msys_deferred_setup(void)
43 {
44     int status;
45 
46     /* Initialize the AP context area by zeroing it */
47     memset((void *)ctx.rom_config->ap_context_base,
48            0,
49            ctx.rom_config->ap_context_size);
50 
51     /* Power on the primary cluster and cpu */
52     ctx.ppu_boot_api->power_mode_on(ctx.rom_config->id_primary_cluster);
53     ctx.ppu_boot_api->power_mode_on(ctx.rom_config->id_primary_core);
54 
55     status = ctx.bootloader_api->load_image();
56 
57     FWK_LOG_CRIT(
58         "[MSYS-ROM] Failed to load RAM firmware image: %s",
59         fwk_status_str(status));
60 
61     return FWK_E_DATA;
62 }
63 
64 /*
65  * Functions fulfilling the framework's module interface
66  */
67 
msys_rom_init(fwk_id_t module_id,unsigned int element_count,const void * data)68 static int msys_rom_init(fwk_id_t module_id, unsigned int element_count,
69     const void *data)
70 {
71     ctx.rom_config = data;
72 
73     if ((ctx.rom_config->ap_context_base == 0) ||
74         (ctx.rom_config->ap_context_size == 0))
75         return FWK_E_RANGE;
76 
77     return FWK_SUCCESS;
78 }
79 
msys_rom_bind(fwk_id_t id,unsigned int round)80 static int msys_rom_bind(fwk_id_t id, unsigned int round)
81 {
82     int status;
83 
84     /* Use second round only (round numbering is zero-indexed) */
85     if (round == 1) {
86 
87         /* Bind to the PPU module */
88         status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_PPU_V1),
89                                  FWK_ID_API(FWK_MODULE_IDX_PPU_V1,
90                                             MOD_PPU_V1_API_IDX_BOOT),
91                                  &ctx.ppu_boot_api);
92         if (status != FWK_SUCCESS)
93             return FWK_E_PANIC;
94 
95         /* Bind to the bootloader module */
96         status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_BOOTLOADER),
97                                  FWK_ID_API(FWK_MODULE_IDX_BOOTLOADER, 0),
98                                  &ctx.bootloader_api);
99         if (status != FWK_SUCCESS)
100         return FWK_E_PANIC;
101     }
102 
103     return FWK_SUCCESS;
104 }
105 
msys_rom_start(fwk_id_t id)106 static int msys_rom_start(fwk_id_t id)
107 {
108     struct fwk_event event = {
109         .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_MSYS_ROM),
110         .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_MSYS_ROM),
111         .id = FWK_ID_EVENT(FWK_MODULE_IDX_MSYS_ROM, ROM_EVENT_RUN),
112     };
113 
114     return fwk_put_event(&event);
115 }
116 
msys_rom_process_event(const struct fwk_event * event,struct fwk_event * resp)117 static int msys_rom_process_event(const struct fwk_event *event,
118     struct fwk_event *resp)
119 {
120     int status;
121     struct mod_pd_power_state_transition_notification_params
122         *notification_params;
123     struct fwk_event systop_on_event = {
124         .response_requested = true,
125         .id = mod_msys_rom_notification_id_systop,
126         .source_id = FWK_ID_NONE
127     };
128 
129     /* Notify any subscribers of the SYSTOP power domain state change */
130     notification_params =
131         (struct mod_pd_power_state_transition_notification_params *)
132             systop_on_event.params;
133     notification_params->state = MOD_PD_STATE_ON;
134 
135     status = fwk_notification_notify(&systop_on_event, &ctx.notification_count);
136     if (status != FWK_SUCCESS)
137         return status;
138 
139     /* Complete remaining setup now if there are no subscribers to respond */
140     if (ctx.notification_count == 0)
141         return msys_deferred_setup();
142 
143     return FWK_SUCCESS;
144 }
145 
msys_rom_process_notification(const struct fwk_event * event,struct fwk_event * resp_event)146 static int msys_rom_process_notification(
147     const struct fwk_event *event,
148     struct fwk_event *resp_event)
149 {
150     fwk_assert(
151         fwk_id_is_equal(event->id, mod_msys_rom_notification_id_systop));
152     fwk_assert(event->is_response == true);
153 
154     /* At least one notification response must be outstanding */
155     if (ctx.notification_count == 0) {
156         fwk_unexpected();
157         return FWK_E_PANIC;
158     }
159 
160     /* Complete remaining setup now that all subscribers have responded */
161     if ((--ctx.notification_count) == 0)
162         return msys_deferred_setup();
163 
164     return FWK_SUCCESS;
165 }
166 
167 /* Module descriptor */
168 const struct fwk_module module_msys_rom = {
169     .type = FWK_MODULE_TYPE_SERVICE,
170     .event_count = ROM_EVENT_COUNT,
171     .notification_count = MOD_MSYS_ROM_NOTIFICATION_COUNT,
172     .init = msys_rom_init,
173     .bind = msys_rom_bind,
174     .start = msys_rom_start,
175     .process_event = msys_rom_process_event,
176     .process_notification = msys_rom_process_notification,
177 };
178