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