xref: /aosp_15_r20/external/coreboot/src/soc/qualcomm/common/qclib.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <assert.h>
4 #include <arch/mmu.h>
5 #include <cbfs.h>
6 #include <cbmem.h>
7 #include <commonlib/bsd/mem_chip_info.h>
8 #include <console/cbmem_console.h>
9 #include <console/console.h>
10 #include <fmap.h>
11 #include <mrc_cache.h>
12 #include <reset.h>
13 #include <security/vboot/misc.h>
14 #include <soc/mmu.h>
15 #include <soc/mmu_common.h>
16 #include <soc/qclib_common.h>
17 #include <soc/symbols_common.h>
18 #include <string.h>
19 #include <vb2_api.h>
20 
21 #define QCLIB_VERSION 0
22 
23 /* store QcLib return data until CBMEM_CREATION_HOOK runs */
24 static struct mem_chip_info *mem_chip_info;
25 
write_mem_chip_information(struct qclib_cb_if_table_entry * te)26 static void write_mem_chip_information(struct qclib_cb_if_table_entry *te)
27 {
28 	struct mem_chip_info *info = (void *)te->blob_address;
29 	if (te->size > sizeof(struct mem_chip_info) &&
30 	    te->size == mem_chip_info_size(info->num_entries)) {
31 		/* Save mem_chip_info in global variable ahead of hook running */
32 		mem_chip_info = info;
33 	}
34 }
35 
add_mem_chip_info(int unused)36 static void add_mem_chip_info(int unused)
37 {
38 	void *mem_region_base = NULL;
39 	size_t size;
40 
41 	if (!mem_chip_info || !mem_chip_info->num_entries ||
42 	    mem_chip_info->struct_version != MEM_CHIP_STRUCT_VERSION) {
43 		printk(BIOS_ERR, "Did not receive valid mem_chip_info from QcLib!\n");
44 		return;
45 	}
46 
47 	size = mem_chip_info_size(mem_chip_info->num_entries);
48 
49 	/* Add cbmem table */
50 	mem_region_base = cbmem_add(CBMEM_ID_MEM_CHIP_INFO, size);
51 	ASSERT(mem_region_base != NULL);
52 
53 	/* Migrate the data into CBMEM */
54 	memcpy(mem_region_base, mem_chip_info, size);
55 }
56 
57 CBMEM_CREATION_HOOK(add_mem_chip_info);
58 
59 struct qclib_cb_if_table qclib_cb_if_table = {
60 	.magic = QCLIB_MAGIC_NUMBER,
61 	.version = QCLIB_INTERFACE_VERSION,
62 	.num_entries = 0,
63 	.max_entries = QCLIB_MAX_NUMBER_OF_ENTRIES,
64 	.global_attributes = 0,
65 	.reserved = 0,
66 };
67 
qclib_file_default(enum qclib_cbfs_file file)68 const char *qclib_file_default(enum qclib_cbfs_file file)
69 {
70 	switch (file) {
71 	case QCLIB_CBFS_PMICCFG:
72 		return CONFIG_CBFS_PREFIX "/pmiccfg";
73 	case QCLIB_CBFS_QCSDI:
74 		return CONFIG_CBFS_PREFIX "/qcsdi";
75 	case QCLIB_CBFS_QCLIB:
76 		return CONFIG_CBFS_PREFIX "/qclib";
77 	case QCLIB_CBFS_DCB:
78 		return CONFIG_CBFS_PREFIX "/dcb";
79 	default:
80 		die("unknown QcLib file %d", file);
81 	}
82 }
83 
84 const char *qclib_file(enum qclib_cbfs_file file)
85 	__attribute__((weak, alias("qclib_file_default")));
86 
qclib_add_if_table_entry(const char * name,void * base,uint32_t size,uint32_t attrs)87 void qclib_add_if_table_entry(const char *name, void *base,
88 				uint32_t size, uint32_t attrs)
89 {
90 	struct qclib_cb_if_table_entry *te =
91 		&qclib_cb_if_table.te[qclib_cb_if_table.num_entries++];
92 	assert(qclib_cb_if_table.num_entries <= qclib_cb_if_table.max_entries);
93 	strncpy(te->name, name, sizeof(te->name) - 1);
94 	te->blob_address = (uintptr_t)base;
95 	te->size = size;
96 	te->blob_attributes = attrs;
97 }
98 
write_ddr_information(struct qclib_cb_if_table_entry * te)99 static void write_ddr_information(struct qclib_cb_if_table_entry *te)
100 {
101 	uint64_t ddr_size;
102 
103 	/* Save DDR info in SRAM region to share with ramstage */
104 	ddr_region->offset = te->blob_address;
105 	ddr_size = te->size;
106 	ddr_region->size = ddr_size * MiB;
107 
108 	/* Use DDR info to configure MMU */
109 	qc_mmu_dram_config_post_dram_init(
110 		(void *)(uintptr_t)region_offset(ddr_region), region_sz(ddr_region));
111 }
112 
write_qclib_log_to_cbmemc(struct qclib_cb_if_table_entry * te)113 static void write_qclib_log_to_cbmemc(struct qclib_cb_if_table_entry *te)
114 {
115 	int i;
116 	char *ptr = (char *)te->blob_address;
117 
118 	for (i = 0; i < te->size; i++) {
119 		char c = *ptr++;
120 		if (c != '\r')
121 			__cbmemc_tx_byte(c);
122 	}
123 }
124 
write_table_entry(struct qclib_cb_if_table_entry * te)125 static void write_table_entry(struct qclib_cb_if_table_entry *te)
126 {
127 	if (!strncmp(QCLIB_TE_DDR_INFORMATION, te->name,
128 			sizeof(te->name))) {
129 		write_ddr_information(te);
130 
131 	} else if (!strncmp(QCLIB_TE_DDR_TRAINING_DATA, te->name,
132 			sizeof(te->name))) {
133 		assert(!mrc_cache_stash_data(MRC_TRAINING_DATA, QCLIB_VERSION,
134 					     (const void *)te->blob_address, te->size));
135 
136 	} else if (!strncmp(QCLIB_TE_LIMITS_CFG_DATA, te->name,
137 			sizeof(te->name))) {
138 		assert(fmap_overwrite_area(QCLIB_FR_LIMITS_CFG_DATA,
139 			(const void *)te->blob_address, te->size));
140 
141 	} else if (!strncmp(QCLIB_TE_QCLIB_LOG_BUFFER, te->name,
142 			sizeof(te->name))) {
143 		write_qclib_log_to_cbmemc(te);
144 
145 	} else if (!strncmp(QCLIB_TE_MEM_CHIP_INFO, te->name,
146 			sizeof(te->name))) {
147 		write_mem_chip_information(te);
148 
149 	} else {
150 		printk(BIOS_WARNING, "%s write not implemented\n", te->name);
151 		printk(BIOS_WARNING, "  blob_address[%llx]..size[%x]\n",
152 			te->blob_address, te->size);
153 	}
154 }
155 
dump_te_table(void)156 static void dump_te_table(void)
157 {
158 	struct qclib_cb_if_table_entry *te;
159 	int i;
160 
161 	for (i = 0; i < qclib_cb_if_table.num_entries; i++) {
162 		te = &qclib_cb_if_table.te[i];
163 		printk(BIOS_DEBUG, "[%s][%llx][%x][%x]\n",
164 			te->name, te->blob_address,
165 			te->size, te->blob_attributes);
166 	}
167 }
168 
qclib_soc_override(struct qclib_cb_if_table * table)169 __weak int qclib_soc_override(struct qclib_cb_if_table *table) { return 0; }
170 
qclib_load_and_run(void)171 void qclib_load_and_run(void)
172 {
173 	int i;
174 	ssize_t data_size;
175 	struct mmu_context pre_qclib_mmu_context;
176 
177 	/* zero ddr_information SRAM region, needs new data each boot */
178 	memset(ddr_region, 0, sizeof(struct region));
179 
180 	/* output area, QCLib copies console log buffer out */
181 	if (CONFIG(CONSOLE_CBMEM))
182 		qclib_add_if_table_entry(QCLIB_TE_QCLIB_LOG_BUFFER,
183 				_qclib_serial_log,
184 				REGION_SIZE(qclib_serial_log), 0);
185 
186 	/* output area, QCLib fills in DDR details */
187 	qclib_add_if_table_entry(QCLIB_TE_DDR_INFORMATION, NULL, 0, 0);
188 
189 	/* Attempt to load DDR Training Blob */
190 	data_size = mrc_cache_load_current(MRC_TRAINING_DATA, QCLIB_VERSION,
191 					   _ddr_training, REGION_SIZE(ddr_training));
192 	if (data_size < 0) {
193 		printk(BIOS_ERR, "Unable to load previous training data.\n");
194 		memset(_ddr_training, 0, REGION_SIZE(ddr_training));
195 	}
196 	qclib_add_if_table_entry(QCLIB_TE_DDR_TRAINING_DATA,
197 				 _ddr_training, REGION_SIZE(ddr_training), 0);
198 
199 	/* Address and size of this entry will be filled in by QcLib. */
200 	qclib_add_if_table_entry(QCLIB_TE_MEM_CHIP_INFO, NULL, 0, 0);
201 
202 	/* Attempt to load PMICCFG Blob */
203 	data_size = cbfs_load(qclib_file(QCLIB_CBFS_PMICCFG),
204 			_pmic, REGION_SIZE(pmic));
205 	if (!data_size) {
206 		printk(BIOS_ERR, "[%s] /pmiccfg failed\n", __func__);
207 		goto fail;
208 	}
209 	qclib_add_if_table_entry(QCLIB_TE_PMIC_SETTINGS, _pmic, data_size, 0);
210 
211 	/* Attempt to load DCB Blob */
212 	data_size = cbfs_load(qclib_file(QCLIB_CBFS_DCB),
213 			_dcb, REGION_SIZE(dcb));
214 	if (!data_size) {
215 		printk(BIOS_ERR, "[%s] /dcb failed\n", __func__);
216 		goto fail;
217 	}
218 	qclib_add_if_table_entry(QCLIB_TE_DCB_SETTINGS, _dcb, data_size, 0);
219 
220 	/* Enable QCLib serial output, based on Kconfig */
221 	if (CONFIG(CONSOLE_SERIAL))
222 		qclib_cb_if_table.global_attributes =
223 			QCLIB_GA_ENABLE_UART_LOGGING;
224 
225 	if (CONFIG(QC_SDI_ENABLE) && (!CONFIG(VBOOT) ||
226 		!vboot_is_gbb_flag_set(VB2_GBB_FLAG_RUNNING_FAFT))) {
227 		struct prog qcsdi =
228 			PROG_INIT(PROG_REFCODE,
229 				qclib_file(QCLIB_CBFS_QCSDI));
230 
231 		/* Attempt to load QCSDI elf */
232 		if (cbfs_prog_stage_load(&qcsdi))
233 			goto fail;
234 
235 		qclib_add_if_table_entry(QCLIB_TE_QCSDI,
236 			prog_entry(&qcsdi), prog_size(&qcsdi), 0);
237 		printk(BIOS_INFO, "qcsdi.entry[%p]\n", qcsdi.entry);
238 	}
239 
240 	/* hook for SoC specific binary blob loads */
241 	if (qclib_soc_override(&qclib_cb_if_table)) {
242 		printk(BIOS_ERR, "qclib_soc_override failed\n");
243 		goto fail;
244 	}
245 
246 	dump_te_table();
247 
248 	/* Attempt to load QCLib elf */
249 	struct prog qclib =
250 		PROG_INIT(PROG_REFCODE, qclib_file(QCLIB_CBFS_QCLIB));
251 
252 	if (cbfs_prog_stage_load(&qclib))
253 		goto fail;
254 
255 	prog_set_entry(&qclib, prog_entry(&qclib), &qclib_cb_if_table);
256 
257 	printk(BIOS_DEBUG, "\n\n\nQCLib is about to Initialize DDR\n");
258 	printk(BIOS_DEBUG, "Global Attributes[%#x]..Table Entries Count[%d]\n",
259 		qclib_cb_if_table.global_attributes,
260 		qclib_cb_if_table.num_entries);
261 	printk(BIOS_DEBUG, "Jumping to QCLib code at %p(%p)\n",
262 		prog_entry(&qclib), prog_entry_arg(&qclib));
263 
264 	/* back-up mmu context before disabling mmu and executing qclib */
265 	mmu_save_context(&pre_qclib_mmu_context);
266 	/* disable mmu before jumping to qclib. mmu_disable also
267 	   flushes and invalidates caches before disabling mmu. */
268 	mmu_disable();
269 
270 	prog_run(&qclib);
271 
272 	/* Before returning, QCLib flushes cache and disables mmu.
273 	   Explicitly disable mmu (flush, invalidate and disable mmu)
274 	   before re-enabling mmu with backed-up mmu context */
275 	mmu_disable();
276 	mmu_restore_context(&pre_qclib_mmu_context);
277 	mmu_enable();
278 
279 	if (qclib_cb_if_table.global_attributes & QCLIB_GA_FORCE_COLD_REBOOT) {
280 		printk(BIOS_NOTICE, "QcLib requested cold reboot\n");
281 		board_reset();
282 	}
283 
284 	/* step through I/F table, handling return values */
285 	for (i = 0; i < qclib_cb_if_table.num_entries; i++)
286 		if (qclib_cb_if_table.te[i].blob_attributes &
287 				QCLIB_BA_SAVE_TO_STORAGE)
288 			write_table_entry(&qclib_cb_if_table.te[i]);
289 
290 	/* confirm that we received valid ddr information from QCLib */
291 	assert((uintptr_t)_dram == region_offset(ddr_region) &&
292 		region_sz(ddr_region) >= (u8 *)cbmem_top() - _dram);
293 
294 	printk(BIOS_DEBUG, "QCLib completed\n\n\n");
295 
296 	return;
297 
298 fail:
299 	die("Couldn't run QCLib.\n");
300 }
301