1 /*
2 * Copyright(c) 2016 Intel Corporation. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
7 */
8
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <cavs/version.h>
12
13 #include <soc/platform.h>
14 #include <soc/memory.h>
15 #include <soc/shim.h>
16 #include <adsp/io.h>
17 #include <soc.h>
18 #include <arch/xtensa/cache.h>
19 #include "manifest.h"
20
21 #if CONFIG_SOC_INTEL_S1000
22 #define MANIFEST_BASE BOOT_LDR_MANIFEST_BASE
23 #else
24 #define MANIFEST_BASE IMR_BOOT_LDR_MANIFEST_BASE
25 #endif
26
27 extern void __start(void);
28
29 #if !defined(CONFIG_SOC_INTEL_S1000)
30 #define MANIFEST_SEGMENT_COUNT 3
31 #undef UNUSED_MEMORY_CALCULATION_HAS_BEEN_FIXED
32
idelay(int n)33 static inline void idelay(int n)
34 {
35 while (n--) {
36 __asm__ volatile("nop");
37 }
38 }
39
40 /* generic string compare cloned into the bootloader to
41 * compact code and make it more readable
42 */
strcmp(const char * s1,const char * s2)43 int strcmp(const char *s1, const char *s2)
44 {
45 while (*s1 != 0 && *s2 != 0) {
46 if (*s1 < *s2)
47 return -1;
48 if (*s1 > *s2)
49 return 1;
50 s1++;
51 s2++;
52 }
53
54 /* did both string end */
55 if (*s1 != 0)
56 return 1;
57 if (*s2 != 0)
58 return -1;
59
60 /* match */
61 return 0;
62 }
63
64 /* memcopy used by boot loader */
bmemcpy(void * dest,void * src,size_t bytes)65 static inline void bmemcpy(void *dest, void *src, size_t bytes)
66 {
67 uint32_t *d = dest;
68 uint32_t *s = src;
69 int i;
70
71 for (i = 0; i < (bytes >> 2); i++)
72 d[i] = s[i];
73
74 z_xtensa_cache_flush(dest, bytes);
75 }
76
77 /* bzero used by bootloader */
bbzero(void * dest,size_t bytes)78 static inline void bbzero(void *dest, size_t bytes)
79 {
80 uint32_t *d = dest;
81 int i;
82
83 for (i = 0; i < (bytes >> 2); i++)
84 d[i] = 0;
85
86 z_xtensa_cache_flush(dest, bytes);
87 }
88
parse_module(struct sof_man_fw_header * hdr,struct sof_man_module * mod)89 static void parse_module(struct sof_man_fw_header *hdr,
90 struct sof_man_module *mod)
91 {
92 int i;
93 uint32_t bias;
94
95 /* each module has 3 segments */
96 for (i = 0; i < MANIFEST_SEGMENT_COUNT; i++) {
97
98 switch (mod->segment[i].flags.r.type) {
99 case SOF_MAN_SEGMENT_TEXT:
100 case SOF_MAN_SEGMENT_DATA:
101 bias = (mod->segment[i].file_offset -
102 SOF_MAN_ELF_TEXT_OFFSET);
103
104 /* copy from IMR to SRAM */
105 bmemcpy((void *)mod->segment[i].v_base_addr,
106 (void *)((int)hdr + bias),
107 mod->segment[i].flags.r.length *
108 HOST_PAGE_SIZE);
109 break;
110 case SOF_MAN_SEGMENT_BSS:
111 /* copy from IMR to SRAM */
112 bbzero((void *)mod->segment[i].v_base_addr,
113 mod->segment[i].flags.r.length *
114 HOST_PAGE_SIZE);
115 break;
116 default:
117 /* ignore */
118 break;
119 }
120 }
121 }
122
123 /* On Sue Creek the boot loader is attached separately, no need to skip it */
124 #if CONFIG_SOC_INTEL_S1000
125 #define MAN_SKIP_ENTRIES 0
126 #else
127 #define MAN_SKIP_ENTRIES 1
128 #endif
129
130 #ifdef UNUSED_MEMORY_CALCULATION_HAS_BEEN_FIXED
get_fw_size_in_use(void)131 static uint32_t get_fw_size_in_use(void)
132 {
133 struct sof_man_fw_desc *desc =
134 (struct sof_man_fw_desc *)MANIFEST_BASE;
135 struct sof_man_fw_header *hdr = &desc->header;
136 struct sof_man_module *mod;
137 uint32_t fw_size_in_use = 0xffffffff;
138 int i;
139
140 /* Calculate fw size passed in BASEFW module in MANIFEST */
141 for (i = MAN_SKIP_ENTRIES; i < hdr->num_module_entries; 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 #endif
160
161 /* parse FW manifest and copy modules */
parse_manifest(void)162 static void parse_manifest(void)
163 {
164 struct sof_man_fw_desc *desc =
165 (struct sof_man_fw_desc *)MANIFEST_BASE;
166 struct sof_man_fw_header *hdr = &desc->header;
167 struct sof_man_module *mod;
168 int i;
169
170 /* copy module to SRAM - skip bootloader module */
171 for (i = MAN_SKIP_ENTRIES; i < hdr->num_module_entries; i++) {
172
173 mod = (void *)((uintptr_t)desc + SOF_MAN_MODULE_OFFSET(i));
174 parse_module(hdr, mod);
175 }
176 }
177 #endif
178
179 #if CAVS_VERSION >= CAVS_VERSION_1_8
180 /* function powers up a number of memory banks provided as an argument and
181 * gates remaining memory banks
182 */
hp_sram_pm_banks(uint32_t banks)183 static int32_t hp_sram_pm_banks(uint32_t banks)
184 {
185 int delay_count = 256;
186 uint32_t status;
187 uint32_t ebb_mask0, ebb_mask1, ebb_avail_mask0, ebb_avail_mask1;
188 uint32_t total_banks_count = PLATFORM_HPSRAM_EBB_COUNT;
189
190 shim_write(SHIM_LDOCTL, SHIM_LDOCTL_HPSRAM_LDO_ON);
191
192 /* add some delay before touch power register */
193 idelay(delay_count);
194
195 /* bit masks reflect total number of available EBB (banks) in each
196 * segment; current implementation supports 2 segments 0,1
197 */
198 if (total_banks_count > EBB_SEGMENT_SIZE) {
199 ebb_avail_mask0 = (uint32_t)GENMASK(EBB_SEGMENT_SIZE - 1, 0);
200 ebb_avail_mask1 = (uint32_t)GENMASK(total_banks_count -
201 EBB_SEGMENT_SIZE - 1, 0);
202 } else {
203 ebb_avail_mask0 = (uint32_t)GENMASK(total_banks_count - 1,
204 0);
205 ebb_avail_mask1 = 0;
206 }
207
208 /* bit masks of banks that have to be powered up in each segment */
209 if (banks > EBB_SEGMENT_SIZE) {
210 ebb_mask0 = (uint32_t)GENMASK(EBB_SEGMENT_SIZE - 1, 0);
211 ebb_mask1 = (uint32_t)GENMASK(banks - EBB_SEGMENT_SIZE - 1,
212 0);
213 } else {
214 /* assumption that ebb_in_use is > 0 */
215 ebb_mask0 = (uint32_t)GENMASK(banks - 1, 0);
216 ebb_mask1 = 0;
217 }
218
219 /* HSPGCTL, HSRMCTL use reverse logic - 0 means EBB is power gated */
220 io_reg_write(HSPGCTL0, (~ebb_mask0) & ebb_avail_mask0);
221 io_reg_write(HSRMCTL0, (~ebb_mask0) & ebb_avail_mask0);
222 io_reg_write(HSPGCTL1, (~ebb_mask1) & ebb_avail_mask1);
223 io_reg_write(HSRMCTL1, (~ebb_mask1) & ebb_avail_mask1);
224
225 /* query the power status of first part of HP memory */
226 /* to check whether it has been powered up. A few */
227 /* cycles are needed for it to be powered up */
228 status = io_reg_read(HSPGISTS0);
229 while (status != ((~ebb_mask0) & ebb_avail_mask0)) {
230 idelay(delay_count);
231 status = io_reg_read(HSPGISTS0);
232 }
233 /* query the power status of second part of HP memory */
234 /* and do as above code */
235
236 status = io_reg_read(HSPGISTS1);
237 while (status != ((~ebb_mask1) & ebb_avail_mask1)) {
238 idelay(delay_count);
239 status = io_reg_read(HSPGISTS1);
240 }
241 /* add some delay before touch power register */
242 idelay(delay_count);
243
244 shim_write(SHIM_LDOCTL, SHIM_LDOCTL_HPSRAM_LDO_BYPASS);
245
246 return 0;
247 }
248
hp_sram_power_on_memory(uint32_t memory_size)249 static uint32_t hp_sram_power_on_memory(uint32_t memory_size)
250 {
251 uint32_t ebb_in_use;
252
253 /* calculate total number of used SRAM banks (EBB)
254 * to power up only necessary banks
255 */
256 ebb_in_use = ceiling_fraction(memory_size, SRAM_BANK_SIZE);
257
258 return hp_sram_pm_banks(ebb_in_use);
259 }
260
261 #ifdef UNUSED_MEMORY_CALCULATION_HAS_BEEN_FIXED
hp_sram_power_off_unused_banks(uint32_t memory_size)262 static int32_t hp_sram_power_off_unused_banks(uint32_t memory_size)
263 {
264 /* keep enabled only memory banks used by FW */
265 return hp_sram_power_on_memory(memory_size);
266 }
267 #endif
268
hp_sram_init(void)269 static int32_t hp_sram_init(void)
270 {
271 return hp_sram_power_on_memory(HP_SRAM_SIZE);
272 }
273
274 #else
275
276 #ifdef UNUSED_MEMORY_CALCULATION_HAS_BEEN_FIXED
hp_sram_power_off_unused_banks(uint32_t memory_size)277 static int32_t hp_sram_power_off_unused_banks(uint32_t memory_size)
278 {
279 return 0;
280 }
281 #endif
282
hp_sram_init(void)283 static uint32_t hp_sram_init(void)
284 {
285 return 0;
286 }
287
288 #endif
289
lp_sram_init(void)290 static int32_t lp_sram_init(void)
291 {
292 uint32_t status;
293 uint32_t lspgctl_value;
294 uint32_t timeout_counter, delay_count = 256;
295
296 timeout_counter = delay_count;
297
298 shim_write(SHIM_LDOCTL, SHIM_LDOCTL_LPSRAM_LDO_ON);
299
300 /* add some delay before writing power registers */
301 idelay(delay_count);
302
303 lspgctl_value = io_reg_read(LSPGISTS);
304 io_reg_write(LSPGCTL, lspgctl_value & ~LPSRAM_MASK(0));
305
306 /* add some delay before checking the status */
307 idelay(delay_count);
308
309 /* query the power status of first part of LP memory */
310 /* to check whether it has been powered up. A few */
311 /* cycles are needed for it to be powered up */
312 status = io_reg_read(LSPGISTS);
313 while (status) {
314 if (!timeout_counter--) {
315 break;
316 }
317 idelay(delay_count);
318 status = io_reg_read(LSPGISTS);
319 }
320
321 shim_write(SHIM_LDOCTL, SHIM_LDOCTL_LPSRAM_LDO_BYPASS);
322
323 return status;
324 }
325
326 /* boot master core */
boot_master_core(void)327 void boot_master_core(void)
328 {
329 int32_t result;
330
331
332 /* init the HPSRAM */
333 result = hp_sram_init();
334 if (result < 0) {
335 return;
336 }
337
338 /* init the LPSRAM */
339
340 result = lp_sram_init();
341 if (result < 0) {
342 return;
343 }
344
345 #if !defined(CONFIG_SOC_INTEL_S1000)
346 /* parse manifest and copy modules */
347 parse_manifest();
348
349 #ifdef UNUSED_MEMORY_CALCULATION_HAS_BEEN_FIXED
350 hp_sram_power_off_unused_banks(get_fw_size_in_use());
351 #endif
352 #endif
353 /* now call SOF entry */
354 __start();
355 }
356