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