blob: 97b6e2d4f7cf978c4dda6b75af2f200a7fac436c [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001/* SPDX-License-Identifier: GPL-2.0-only */
T Michael Turney7a3e46d2019-03-21 14:21:26 -07002
T Michael Turney7a3e46d2019-03-21 14:21:26 -07003#include <assert.h>
4#include <arch/mmu.h>
5#include <cbfs.h>
Venkat Thogaru209efcc2022-09-26 17:46:45 +05306#include <cbmem.h>
7#include <commonlib/bsd/mem_chip_info.h>
8#include <console/cbmem_console.h>
T Michael Turney7a3e46d2019-03-21 14:21:26 -07009#include <console/console.h>
Venkat Thogaru209efcc2022-09-26 17:46:45 +053010#include <fmap.h>
Shelley Chenafaa3d02020-10-06 15:50:21 -070011#include <mrc_cache.h>
Venkat Thogaru209efcc2022-09-26 17:46:45 +053012#include <reset.h>
13#include <security/vboot/misc.h>
T Michael Turney7a3e46d2019-03-21 14:21:26 -070014#include <soc/mmu.h>
15#include <soc/mmu_common.h>
16#include <soc/qclib_common.h>
17#include <soc/symbols_common.h>
Venkat Thogaru209efcc2022-09-26 17:46:45 +053018#include <string.h>
Ashwin Kumar16eb4032019-10-29 13:20:06 +053019#include <vb2_api.h>
T Michael Turney7a3e46d2019-03-21 14:21:26 -070020
Shelley Chenafaa3d02020-10-06 15:50:21 -070021#define QCLIB_VERSION 0
22
Kyösti Mälkkifa3bc042022-03-31 07:40:10 +030023/* store QcLib return data until CBMEM_CREATION_HOOK runs */
Julius Werner3460aa32022-10-24 19:06:03 -070024static struct mem_chip_info *mem_chip_info;
Ravi Kumar Bokka4573ca42021-11-10 05:24:17 +053025
26static void write_mem_chip_information(struct qclib_cb_if_table_entry *te)
27{
Julius Werner3460aa32022-10-24 19:06:03 -070028 struct mem_chip_info *info = (void *)te->blob_address;
Ravi Kumar Bokka4f9cb422022-04-06 07:35:53 +053029 if (te->size > sizeof(struct mem_chip_info) &&
Julius Werner3460aa32022-10-24 19:06:03 -070030 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;
Ravi Kumar Bokka4f9cb422022-04-06 07:35:53 +053033 }
Ravi Kumar Bokka4573ca42021-11-10 05:24:17 +053034}
35
36static void add_mem_chip_info(int unused)
37{
38 void *mem_region_base = NULL;
Ravi Kumar Bokka4f9cb422022-04-06 07:35:53 +053039 size_t size;
40
Julius Werner3460aa32022-10-24 19:06:03 -070041 if (!mem_chip_info || !mem_chip_info->num_entries ||
42 mem_chip_info->struct_version != MEM_CHIP_STRUCT_VERSION) {
Yu-Ping Wufae1eb32023-08-21 16:02:57 +080043 printk(BIOS_ERR, "Did not receive valid mem_chip_info from QcLib!\n");
Ravi Kumar Bokka4f9cb422022-04-06 07:35:53 +053044 return;
45 }
46
Julius Werner3460aa32022-10-24 19:06:03 -070047 size = mem_chip_info_size(mem_chip_info->num_entries);
Ravi Kumar Bokka4573ca42021-11-10 05:24:17 +053048
49 /* Add cbmem table */
Ravi Kumar Bokka4f9cb422022-04-06 07:35:53 +053050 mem_region_base = cbmem_add(CBMEM_ID_MEM_CHIP_INFO, size);
Ravi Kumar Bokka4573ca42021-11-10 05:24:17 +053051 ASSERT(mem_region_base != NULL);
52
53 /* Migrate the data into CBMEM */
Julius Werner3460aa32022-10-24 19:06:03 -070054 memcpy(mem_region_base, mem_chip_info, size);
Ravi Kumar Bokka4573ca42021-11-10 05:24:17 +053055}
56
Kyösti Mälkkifa3bc042022-03-31 07:40:10 +030057CBMEM_CREATION_HOOK(add_mem_chip_info);
Ravi Kumar Bokka4573ca42021-11-10 05:24:17 +053058
T Michael Turney7a3e46d2019-03-21 14:21:26 -070059struct 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
Sudheer Kumar Amrabadi58f60312022-05-10 16:43:47 +053068const 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
84const char *qclib_file(enum qclib_cbfs_file file)
85 __attribute__((weak, alias("qclib_file_default")));
86
T Michael Turney7a3e46d2019-03-21 14:21:26 -070087void 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);
Julius Werner096fd0a2019-06-10 13:18:59 -070093 strncpy(te->name, name, sizeof(te->name) - 1);
T Michael Turney7a3e46d2019-03-21 14:21:26 -070094 te->blob_address = (uintptr_t)base;
95 te->size = size;
96 te->blob_attributes = attrs;
97}
98
99static 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 */
Nico Huberf55b7112024-01-11 18:50:50 +0100109 qc_mmu_dram_config_post_dram_init(
110 (void *)(uintptr_t)region_offset(ddr_region), region_sz(ddr_region));
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700111}
112
113static 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
Julius Werner37833fc2023-09-07 13:38:06 -0700118 for (i = 0; i < te->size; i++) {
119 char c = *ptr++;
120 if (c != '\r')
121 __cbmemc_tx_byte(c);
122 }
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700123}
124
125static void write_table_entry(struct qclib_cb_if_table_entry *te)
126{
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700127 if (!strncmp(QCLIB_TE_DDR_INFORMATION, te->name,
128 sizeof(te->name))) {
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700129 write_ddr_information(te);
130
131 } else if (!strncmp(QCLIB_TE_DDR_TRAINING_DATA, te->name,
132 sizeof(te->name))) {
Shelley Chenafaa3d02020-10-06 15:50:21 -0700133 assert(!mrc_cache_stash_data(MRC_TRAINING_DATA, QCLIB_VERSION,
134 (const void *)te->blob_address, te->size));
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700135
136 } else if (!strncmp(QCLIB_TE_LIMITS_CFG_DATA, te->name,
137 sizeof(te->name))) {
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700138 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))) {
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700143 write_qclib_log_to_cbmemc(te);
144
Ravi Kumar Bokka4573ca42021-11-10 05:24:17 +0530145 } else if (!strncmp(QCLIB_TE_MEM_CHIP_INFO, te->name,
146 sizeof(te->name))) {
147 write_mem_chip_information(te);
148
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700149 } else {
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700150 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);
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700153 }
154}
155
156static 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
Sudheer Kumar Amrabadi0225e802023-03-15 15:17:36 +0530169__weak int qclib_soc_override(struct qclib_cb_if_table *table) { return 0; }
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700170
171void qclib_load_and_run(void)
172{
173 int i;
Shelley Chenafaa3d02020-10-06 15:50:21 -0700174 ssize_t data_size;
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700175 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 */
Patrick Georgid9391832019-05-15 21:33:42 +0200181 if (CONFIG(CONSOLE_CBMEM))
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700182 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
Shelley Chen0263e0f2020-10-21 22:46:14 -0700189 /* 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");
Shelley Chenafaa3d02020-10-06 15:50:21 -0700194 memset(_ddr_training, 0, REGION_SIZE(ddr_training));
Shelley Chenafaa3d02020-10-06 15:50:21 -0700195 }
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700196 qclib_add_if_table_entry(QCLIB_TE_DDR_TRAINING_DATA,
Shelley Chenafaa3d02020-10-06 15:50:21 -0700197 _ddr_training, REGION_SIZE(ddr_training), 0);
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700198
Ravi Kumar Bokka4f9cb422022-04-06 07:35:53 +0530199 /* 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);
Ravi Kumar Bokka4573ca42021-11-10 05:24:17 +0530201
Ravi Kumar Bokka1faaa162021-03-31 08:05:24 +0530202 /* Attempt to load PMICCFG Blob */
Sudheer Kumar Amrabadi58f60312022-05-10 16:43:47 +0530203 data_size = cbfs_load(qclib_file(QCLIB_CBFS_PMICCFG),
Ravi Kumar Bokka1faaa162021-03-31 08:05:24 +0530204 _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 */
Sudheer Kumar Amrabadi58f60312022-05-10 16:43:47 +0530212 data_size = cbfs_load(qclib_file(QCLIB_CBFS_DCB),
Ravi Kumar Bokka1faaa162021-03-31 08:05:24 +0530213 _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
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700220 /* Enable QCLib serial output, based on Kconfig */
Patrick Georgid9391832019-05-15 21:33:42 +0200221 if (CONFIG(CONSOLE_SERIAL))
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700222 qclib_cb_if_table.global_attributes =
223 QCLIB_GA_ENABLE_UART_LOGGING;
224
Ashwin Kumar16eb4032019-10-29 13:20:06 +0530225 if (CONFIG(QC_SDI_ENABLE) && (!CONFIG(VBOOT) ||
226 !vboot_is_gbb_flag_set(VB2_GBB_FLAG_RUNNING_FAFT))) {
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700227 struct prog qcsdi =
Ashwin Kumar16eb4032019-10-29 13:20:06 +0530228 PROG_INIT(PROG_REFCODE,
Sudheer Kumar Amrabadi58f60312022-05-10 16:43:47 +0530229 qclib_file(QCLIB_CBFS_QCSDI));
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700230
231 /* Attempt to load QCSDI elf */
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700232 if (cbfs_prog_stage_load(&qcsdi))
233 goto fail;
234
Ashwin Kumar16eb4032019-10-29 13:20:06 +0530235 qclib_add_if_table_entry(QCLIB_TE_QCSDI,
236 prog_entry(&qcsdi), prog_size(&qcsdi), 0);
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700237 printk(BIOS_INFO, "qcsdi.entry[%p]\n", qcsdi.entry);
238 }
239
Sudheer Kumar Amrabadi0225e802023-03-15 15:17:36 +0530240 /* 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
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700246 dump_te_table();
247
248 /* Attempt to load QCLib elf */
249 struct prog qclib =
Sudheer Kumar Amrabadi58f60312022-05-10 16:43:47 +0530250 PROG_INIT(PROG_REFCODE, qclib_file(QCLIB_CBFS_QCLIB));
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700251
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700252 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");
Sudheer Kumar Amrabadi0225e802023-03-15 15:17:36 +0530258 printk(BIOS_DEBUG, "Global Attributes[%#x]..Table Entries Count[%d]\n",
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700259 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
Venkat Thogarufec9abc2022-09-07 17:17:39 +0530279 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
T Michael Turney7a3e46d2019-03-21 14:21:26 -0700284 /* 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
298fail:
299 die("Couldn't run QCLib.\n");
300}