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