1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2018-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <mod_synquacer_rom.h>
9 
10 #include <fwk_core.h>
11 #include <fwk_event.h>
12 #include <fwk_id.h>
13 #include <fwk_interrupt.h>
14 #include <fwk_log.h>
15 #include <fwk_module.h>
16 #include <fwk_module_idx.h>
17 #include <fwk_status.h>
18 
19 #include <fmw_cmsis.h>
20 
21 #include <stdint.h>
22 #include <string.h>
23 
24 void synquacer_system_init(void);
25 
26 static const struct synquacer_rom_config *rom_config;
27 
28 enum rom_event { ROM_EVENT_RUN, ROM_EVENT_COUNT };
29 
30 /*
31  * This function assumes that the RAM firmware image is located at the beginning
32  * of the SCP SRAM. The reset handler will be at offset 0x4 (the second entry of
33  * the vector table).
34  */
jump_to_ramfw(void)35 static void jump_to_ramfw(void)
36 {
37     uintptr_t const *reset_base = (uintptr_t *)(rom_config->ramfw_base + 0x4);
38     void (*ramfw_reset_handler)(void);
39 
40     /*
41      * Disable interrupts for the duration of the ROM firmware to RAM firmware
42      * transition.
43      */
44     (void)fwk_interrupt_global_disable();
45 
46     ramfw_reset_handler = (void (*)(void))(*reset_base);
47 
48     /* Set the vector table offset register to ramfw vector table */
49     SCB->VTOR = rom_config->ramfw_base;
50 
51     /*
52      * Execute the RAM firmware's reset handler to pass control from ROM
53      * firmware to the RAM firmware.
54      */
55     ramfw_reset_handler();
56 }
57 
58 /*
59  * Framework API
60  */
synquacer_rom_init(fwk_id_t module_id,unsigned int element_count,const void * data)61 static int synquacer_rom_init(
62     fwk_id_t module_id,
63     unsigned int element_count,
64     const void *data)
65 {
66     rom_config = data;
67 
68     synquacer_system_init();
69 
70     return FWK_SUCCESS;
71 }
72 
synquacer_rom_start(fwk_id_t id)73 static int synquacer_rom_start(fwk_id_t id)
74 {
75     int status;
76     struct fwk_event event = {
77         .source_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYNQUACER_ROM),
78         .target_id = FWK_ID_MODULE(FWK_MODULE_IDX_SYNQUACER_ROM),
79         .id = FWK_ID_EVENT(FWK_MODULE_IDX_SYNQUACER_ROM, ROM_EVENT_RUN),
80     };
81 
82     status = fwk_put_event(&event);
83 
84     return status;
85 }
86 
synquacer_rom_process_event(const struct fwk_event * event,struct fwk_event * resp)87 static int synquacer_rom_process_event(
88     const struct fwk_event *event,
89     struct fwk_event *resp)
90 {
91     FWK_LOG_INFO("[scp_romfw] Launch scp_ramfw");
92     FWK_LOG_FLUSH();
93 
94     if (rom_config->load_ram_size != 0) {
95         memcpy(
96             (void *)rom_config->ramfw_base,
97             (uint8_t *)rom_config->nor_base,
98             rom_config->load_ram_size);
99     }
100 
101     jump_to_ramfw();
102 
103     return FWK_SUCCESS;
104 }
105 
106 /* Module descriptor */
107 const struct fwk_module module_synquacer_rom = {
108     .type = FWK_MODULE_TYPE_SERVICE,
109     .event_count = ROM_EVENT_COUNT,
110     .init = synquacer_rom_init,
111     .start = synquacer_rom_start,
112     .process_event = synquacer_rom_process_event,
113 };
114