1 // SPDX-License-Identifier: BSD-3-Clause
2 //
3 // Copyright(c) 2016 Intel Corporation. All rights reserved.
4 //
5 // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6
7 #include <cavs/lib/pm_memory.h>
8 #include <rtos/bit.h>
9 #include <rtos/cache.h>
10 #include <sof/lib/io.h>
11 #include <sof/lib/memory.h>
12 #include <sof/lib/shim.h>
13 #include <rtos/wait.h>
14 #include <sof/platform.h>
15 #include <rtos/sof.h>
16 #include <sof/trace/trace.h>
17 #include <ipc/trace.h>
18 #include <rimage/sof/user/manifest.h>
19
20 #include <stdbool.h>
21 #include <stddef.h>
22 #include <stdint.h>
23
24 #define MANIFEST_BASE IMR_BOOT_LDR_MANIFEST_BASE
25 #define MANIFEST_SEGMENT_COUNT 3
26
27 /* generic string compare cloned into the bootloader to
28 * compact code and make it more readable
29 */
strcmp(const char * s1,const char * s2)30 int strcmp(const char *s1, const char *s2)
31 {
32 while (*s1 != 0 && *s2 != 0) {
33 if (*s1 < *s2)
34 return -1;
35 if (*s1 > *s2)
36 return 1;
37 s1++;
38 s2++;
39 }
40
41 /* did both string end */
42 if (*s1 != 0)
43 return 1;
44 if (*s2 != 0)
45 return -1;
46
47 /* match */
48 return 0;
49 }
50
51 /* memcopy used by boot loader */
bmemcpy(void * dest,void * src,size_t bytes)52 static inline void bmemcpy(void *dest, void *src, size_t bytes)
53 {
54 uint32_t *d = dest;
55 uint32_t *s = src;
56 int i;
57
58 for (i = 0; i < (bytes >> 2); i++)
59 d[i] = s[i];
60
61 dcache_writeback_region(dest, bytes);
62 }
63
64 /* bzero used by bootloader */
bbzero(void * dest,size_t bytes)65 static inline void bbzero(void *dest, size_t bytes)
66 {
67 uint32_t *d = dest;
68 int i;
69
70 for (i = 0; i < (bytes >> 2); i++)
71 d[i] = 0;
72
73 dcache_writeback_region(dest, bytes);
74 }
75
parse_module(struct sof_man_fw_header * hdr,struct sof_man_module * mod)76 static void parse_module(struct sof_man_fw_header *hdr,
77 struct sof_man_module *mod)
78 {
79 int i;
80 uint32_t bias;
81
82 /* each module has 3 segments */
83 for (i = 0; i < MANIFEST_SEGMENT_COUNT; i++) {
84 trace_point(TRACE_BOOT_LDR_PARSE_SEGMENT + i);
85 switch (mod->segment[i].flags.r.type) {
86 case SOF_MAN_SEGMENT_TEXT:
87 case SOF_MAN_SEGMENT_DATA:
88 bias = (mod->segment[i].file_offset -
89 SOF_MAN_ELF_TEXT_OFFSET);
90
91 /* copy from IMR to SRAM */
92 bmemcpy((void *)mod->segment[i].v_base_addr,
93 (void *)((int)hdr + bias),
94 mod->segment[i].flags.r.length *
95 HOST_PAGE_SIZE);
96 break;
97 case SOF_MAN_SEGMENT_BSS:
98 /* copy from IMR to SRAM */
99 bbzero((void *)mod->segment[i].v_base_addr,
100 mod->segment[i].flags.r.length *
101 HOST_PAGE_SIZE);
102 break;
103 default:
104 /* ignore */
105 break;
106 }
107 }
108 }
109
110 /* parse FW manifest and copy modules */
parse_manifest(void)111 static void parse_manifest(void)
112 {
113 struct sof_man_fw_desc *desc =
114 (struct sof_man_fw_desc *)MANIFEST_BASE;
115 struct sof_man_fw_header *hdr = &desc->header;
116 struct sof_man_module *mod;
117 int i;
118
119 /* copy module to SRAM - skip bootloader module */
120 for (i = 1; i < hdr->num_module_entries; i++) {
121 trace_point(TRACE_BOOT_LDR_PARSE_MODULE + i);
122 mod = (struct sof_man_module *)((char *)desc +
123 SOF_MAN_MODULE_OFFSET(i));
124 parse_module(hdr, mod);
125 }
126 }
127
128 #if PLATFORM_MEM_INIT_AT_BOOT
129
get_fw_size_in_use(void)130 static uint32_t get_fw_size_in_use(void)
131 {
132 struct sof_man_fw_desc *desc =
133 (struct sof_man_fw_desc *)MANIFEST_BASE;
134 struct sof_man_fw_header *hdr = &desc->header;
135 struct sof_man_module *mod;
136 uint32_t fw_size_in_use = 0xffffffff;
137 int i;
138
139 /* Calculate fw size passed in BASEFW module in MANIFEST */
140 for (i = 1; i < hdr->num_module_entries; i++) {
141 trace_point(TRACE_BOOT_LDR_PARSE_MODULE + i);
142 mod = (struct sof_man_module *)((char *)desc +
143 SOF_MAN_MODULE_OFFSET(i));
144 if (strcmp((char *)mod->name, "BASEFW"))
145 continue;
146 for (i = 0; i < MANIFEST_SEGMENT_COUNT; i++) {
147 if (mod->segment[i].flags.r.type
148 == SOF_MAN_SEGMENT_BSS) {
149 fw_size_in_use = mod->segment[i].v_base_addr
150 - HP_SRAM_BASE
151 + (mod->segment[i].flags.r.length
152 * HOST_PAGE_SIZE);
153 }
154 }
155 }
156
157 return fw_size_in_use;
158 }
159
hp_sram_power_memory(uint32_t memory_size,bool enable)160 static uint32_t hp_sram_power_memory(uint32_t memory_size, bool enable)
161 {
162 uint32_t start_bank;
163 uint32_t end_bank;
164 uint32_t ebb_in_use;
165
166 /* calculate total number of used SRAM banks (EBB)
167 * to power up only necessary banks
168 */
169 ebb_in_use = SOF_DIV_ROUND_UP(memory_size, SRAM_BANK_SIZE);
170
171 start_bank = enable ? 0 : ebb_in_use;
172 end_bank = (enable ? ebb_in_use : PLATFORM_HPSRAM_EBB_COUNT) - 1;
173
174 cavs_pm_memory_hp_sram_banks_power_gate(start_bank, end_bank, enable);
175
176 return 0;
177 }
178
hp_sram_power_off_unused_banks(uint32_t memory_size)179 static int32_t hp_sram_power_off_unused_banks(uint32_t memory_size)
180 {
181 /* keep enabled only memory banks used by FW */
182 return hp_sram_power_memory(memory_size, false);
183 }
184
hp_sram_init(void)185 static int32_t hp_sram_init(void)
186 {
187 return hp_sram_power_memory(HP_SRAM_SIZE, true);
188 }
189
190 #endif
191
192 /* boot primary core */
boot_primary_core(void)193 void boot_primary_core(void)
194 {
195 #if PLATFORM_MEM_INIT_AT_BOOT
196 int32_t result;
197 #endif
198
199 trace_point(TRACE_BOOT_LDR_ENTRY);
200
201 #if PLATFORM_MEM_INIT_AT_BOOT
202 /* init the HPSRAM */
203 trace_point(TRACE_BOOT_LDR_HPSRAM);
204 result = hp_sram_init();
205 if (result < 0) {
206 platform_panic(SOF_IPC_PANIC_MEM);
207 return;
208 }
209 #endif
210
211 #if CONFIG_LP_SRAM
212 /* init the LPSRAM */
213 trace_point(TRACE_BOOT_LDR_LPSRAM);
214
215 cavs_pm_memory_lp_sram_banks_power_gate(0,
216 PLATFORM_LPSRAM_EBB_COUNT - 1,
217 true);
218 #endif
219
220 #if CONFIG_L1_DRAM
221 /* Power ON L1 DRAM memory */
222 trace_point(TRACE_BOOT_LDR_L1DRAM);
223 cavs_pm_memory_l1_dram_banks_power_gate(CONFIG_L1_DRAM_MEMORY_BANKS - 1,
224 0, true);
225 #endif
226
227 /* parse manifest and copy modules */
228 trace_point(TRACE_BOOT_LDR_MANIFEST);
229 parse_manifest();
230
231 #if PLATFORM_MEM_INIT_AT_BOOT
232 hp_sram_power_off_unused_banks(get_fw_size_in_use());
233 #endif
234
235 /* now call SOF entry */
236 trace_point(TRACE_BOOT_LDR_JUMP);
237 _ResetVector();
238 }
239