Hello T Michael Turney,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/32288
to review the following change.
Change subject: qualcomm: Add QCLib interface support to common/ ......................................................................
qualcomm: Add QCLib interface support to common/
Change-Id: I38d086c379a3c2f54d1603a2fed5b33860f7f4d7 Signed-off-by: T Michael Turney mturney@codeaurora.org --- A src/soc/qualcomm/common/Kconfig A src/soc/qualcomm/common/include/soc/mmu_common.h A src/soc/qualcomm/common/include/soc/qclib_common.h A src/soc/qualcomm/common/include/soc/symbols_common.h A src/soc/qualcomm/common/mmu.c A src/soc/qualcomm/common/qclib.c 6 files changed, 402 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/88/32288/1
diff --git a/src/soc/qualcomm/common/Kconfig b/src/soc/qualcomm/common/Kconfig new file mode 100644 index 0000000..f3d1262 --- /dev/null +++ b/src/soc/qualcomm/common/Kconfig @@ -0,0 +1,5 @@ + +config QC_SDI_ENABLE + bool + default n + prompt "Debug Build: enable SDI" diff --git a/src/soc/qualcomm/common/include/soc/mmu_common.h b/src/soc/qualcomm/common/include/soc/mmu_common.h new file mode 100644 index 0000000..803c4f3 --- /dev/null +++ b/src/soc/qualcomm/common/include/soc/mmu_common.h @@ -0,0 +1,31 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _SOC_QUALCOMM_MMU_COMMON_H_ +#define _SOC_QUALCOMM_MMU_COMMON_H_ + +#include <commonlib/region.h> +#include <soc/symbols_common.h> + +#define CACHED_RAM (MA_MEM | MA_S | MA_RW) +#define UNCACHED_RAM (MA_MEM | MA_S | MA_RW | MA_MEM_NC) +#define DEV_MEM (MA_DEV | MA_S | MA_RW) + +static struct region * const ddr_region = (struct region *)_ddr_information; + +void soc_mmu_dram_config_post_dram_init(void); +void qc_mmu_dram_config_post_dram_init(void *ddr_base, size_t ddr_size); + +#endif // _SOC_QUALCOMM_MMU_COMMON_H_ diff --git a/src/soc/qualcomm/common/include/soc/qclib_common.h b/src/soc/qualcomm/common/include/soc/qclib_common.h new file mode 100644 index 0000000..08f9d4a --- /dev/null +++ b/src/soc/qualcomm/common/include/soc/qclib_common.h @@ -0,0 +1,81 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _SOC_QUALCOMM_QCLIB_COMMON_H__ +#define _SOC_QUALCOMM_QCLIB_COMMON_H__ + +#include <fmap.h> + +/* coreboot & QCLib I/F definitions */ + +/* string field lengths */ +#define QCLIB_MAGIC_NUMBER_LENGTH 8 +#define QCLIB_FMAP_NAME_LENGTH 24 +#define QCLIB_TE_NAME_LENGTH 24 + +/* FMAP_REGION names */ +#define QCLIB_FR_DDR_TRAINING_DATA "RO_DDR_TRAINING" +#define QCLIB_FR_LIMITS_CFG_DATA "RO_LIMITS_CFG" + +/* TE_NAME (table entry name) */ +#define QCLIB_TE_DDR_INFORMATION "ddr_information" +#define QCLIB_TE_QCLIB_LOG_BUFFER "qclib_log_buffer" +#define QCLIB_TE_DCB_SETTINGS "dcb_settings" +#define QCLIB_TE_CDT_SETTINGS "cdt_settings" +#define QCLIB_TE_PMIC_SETTINGS "pmic_settings" +#define QCLIB_TE_DDR_TRAINING_DATA "ddr_training_data" +#define QCLIB_TE_LIMITS_CFG_DATA "limits_cfg_data" +#define QCLIB_TE_QCSDI "qcsdi" + +/* BA_BMASK_VALUES (blob_attributes bit mask values) */ +#define QCLIB_BA_SAVE_TO_STORAGE 0x00000001 + +struct qclib_cb_if_table_entry { + char name[QCLIB_TE_NAME_LENGTH]; /* 0x00 TE_NAME */ + uint64_t blob_address; /* 0x18 blob addr in SRAM */ + uint32_t size; /* 0x20 blob size in SRAM */ + uint32_t blob_attributes; /* 0x24 BA_BMASK_VALUES */ +}; + +/* GA_BMASK_VALUES (global_attributes bit mask values) */ +#define QCLIB_GA_ENABLE_UART_LOGGING 0x00000001 + +#define QCLIB_INTERFACE_VERSION 0x00000001 +#define QCLIB_MAX_NUMBER_OF_ENTRIES 16 + +#define QCLIB_MAGIC_NUMBER "QCLIB_CB" + +struct qclib_cb_if_table { + char magic[8]; /* 0x00 */ + uint32_t version; /* 0x08 */ + uint32_t num_entries; /* 0x0C */ + uint32_t max_entries; /* 0x10 */ + uint32_t global_attributes; /* 0x14 */ + uint64_t reserved; /* 0x18 */ + struct qclib_cb_if_table_entry + te[QCLIB_MAX_NUMBER_OF_ENTRIES]; /* 0x20 */ +}; + +extern struct qclib_cb_if_table qclib_cb_if_table; + +void add_if_table_entry(const char *, void *, uint32_t, uint32_t); +void write_ddr_information(struct qclib_cb_if_table_entry *); +void write_qclib_log_to_cbmemc(struct qclib_cb_if_table_entry *); +void write_table_entry(struct qclib_cb_if_table_entry *); +void dump_te_table(void); +void qclib_load_and_run(void); +void soc_blob_load(void); + +#endif // _SOC_QUALCOMM_QCLIB_COMMON_H_ diff --git a/src/soc/qualcomm/common/include/soc/symbols_common.h b/src/soc/qualcomm/common/include/soc/symbols_common.h new file mode 100644 index 0000000..ffa535c --- /dev/null +++ b/src/soc/qualcomm/common/include/soc/symbols_common.h @@ -0,0 +1,25 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _SOC_QUALCOMM_SYMBOLS_COMMON_H_ +#define _SOC_QUALCOMM_SYMBOLS_COMMON_H_ + +#include <symbols.h> + +DECLARE_REGION(ddr_training); +DECLARE_REGION(qclib_serial_log); +DECLARE_REGION(ddr_information); + +#endif // _SOC_QUALCOMM_SYMBOLS_COMMON_H_ diff --git a/src/soc/qualcomm/common/mmu.c b/src/soc/qualcomm/common/mmu.c new file mode 100644 index 0000000..79d2eb7 --- /dev/null +++ b/src/soc/qualcomm/common/mmu.c @@ -0,0 +1,26 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/mmu.h> +#include <soc/mmu.h> +#include <soc/mmu_common.h> + +__weak void soc_mmu_dram_config_post_dram_init(void) { /* no-op */ } + +void qc_mmu_dram_config_post_dram_init(void *ddr_base, size_t ddr_size) +{ + mmu_config_range((void *)ddr_base, ddr_size, CACHED_RAM); + soc_mmu_dram_config_post_dram_init(); +} diff --git a/src/soc/qualcomm/common/qclib.c b/src/soc/qualcomm/common/qclib.c new file mode 100644 index 0000000..9feca05 --- /dev/null +++ b/src/soc/qualcomm/common/qclib.c @@ -0,0 +1,234 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <console/cbmem_console.h> +#include <cbmem.h> +#include <boardid.h> +#include <fmap.h> +#include <assert.h> +#include <arch/mmu.h> +#include <cbfs.h> +#include <console/console.h> +#include <soc/mmu.h> +#include <soc/mmu_common.h> +#include <soc/qclib_common.h> +#include <soc/symbols_common.h> + +#define QCLIB_NAME "/qclib" +#define QCSDI_NAME "/qcsdi" + +struct qclib_cb_if_table qclib_cb_if_table = { + .magic = QCLIB_MAGIC_NUMBER, + .version = QCLIB_INTERFACE_VERSION, + .num_entries = 0, + .max_entries = QCLIB_MAX_NUMBER_OF_ENTRIES, + .global_attributes = 0, + .reserved = 0, +}; + +void add_if_table_entry(const char *name, void *base, + uint32_t size, uint32_t attrs) +{ + struct qclib_cb_if_table_entry *te = + &qclib_cb_if_table.te[qclib_cb_if_table.num_entries++]; + assert(qclib_cb_if_table.num_entries <= qclib_cb_if_table.max_entries); + strncpy(te->name, name, sizeof(te->name)); + te->blob_address = (uintptr_t)base; + te->size = size; + te->blob_attributes = attrs; +} + +void write_ddr_information(struct qclib_cb_if_table_entry *te) +{ + uint64_t ddr_size; + + /* Save DDR info in SRAM region to share with ramstage */ + ddr_region->offset = te->blob_address; + ddr_size = te->size; + ddr_region->size = ddr_size * MiB; + + /* Use DDR info to configure MMU */ + qc_mmu_dram_config_post_dram_init((void *)ddr_region->offset, + (size_t)ddr_region->size); +} + +void write_qclib_log_to_cbmemc(struct qclib_cb_if_table_entry *te) +{ + int i; + char *ptr = (char *)te->blob_address; + + for (i = 0; i < te->size; i++) + cbmemc_tx_byte(*ptr++); +} + +void write_table_entry(struct qclib_cb_if_table_entry *te) +{ + printk(BIOS_INFO, "[%s]:[%s]\n", __func__, te->name); + + if (!strncmp(QCLIB_TE_DDR_INFORMATION, te->name, + sizeof(te->name))) { + + write_ddr_information(te); + + } else if (!strncmp(QCLIB_TE_DDR_TRAINING_DATA, te->name, + sizeof(te->name))) { + + assert(fmap_overwrite_area(QCLIB_FR_DDR_TRAINING_DATA, + (const void *)te->blob_address, te->size)); + + } else if (!strncmp(QCLIB_TE_LIMITS_CFG_DATA, te->name, + sizeof(te->name))) { + + assert(fmap_overwrite_area(QCLIB_FR_LIMITS_CFG_DATA, + (const void *)te->blob_address, te->size)); + + } else if (!strncmp(QCLIB_TE_QCLIB_LOG_BUFFER, te->name, + sizeof(te->name))) { + + write_qclib_log_to_cbmemc(te); + + } else { + + printk(BIOS_INFO, " not implemented\n"); + printk(BIOS_INFO, " blob_address[%llx]..size[%x]\n", + te->blob_address, te->size); + + } +} + +void dump_te_table(void) +{ + struct qclib_cb_if_table_entry *te; + int i; + + for (i = 0; i < qclib_cb_if_table.num_entries; i++) { + te = &qclib_cb_if_table.te[i]; + printk(BIOS_INFO, "[%s][%llx][%x][%x]\n", + te->name, te->blob_address, + te->size, te->blob_attributes); + } +} + +__weak void soc_blob_load(void) { /* no-op */ } + +void qclib_load_and_run(void) +{ + int (*doit)(void *param1, void *param2); + void *arg; + int i, ret_code; + size_t size; + struct mmu_context pre_qclib_mmu_context; + + /* print board Rev */ + printk(BIOS_INFO, "Board Rev(0x%x)\n", board_id()); + + /* zero ddr_information SRAM region, needs new data each boot */ + memset(ddr_region, 0, sizeof(struct region)); + + /* output area, QCLib copies console log buffer out */ + if (IS_ENABLED(CONFIG_CONSOLE_CBMEM)) + add_if_table_entry(QCLIB_TE_QCLIB_LOG_BUFFER, _qclib_serial_log, + REGION_SIZE(qclib_serial_log), 0); + + /* output area, QCLib fills in DDR details */ + add_if_table_entry(QCLIB_TE_DDR_INFORMATION, 0, 0, 0); + + /* Attempt to load DDR Training Blob */ + size = fmap_read_area(QCLIB_FR_DDR_TRAINING_DATA, _ddr_training, + REGION_SIZE(ddr_training)); + if (size < 0) + goto fail; + add_if_table_entry(QCLIB_TE_DDR_TRAINING_DATA, _ddr_training, size, 0); + + /* hook for SoC specific binary blob loads */ + soc_blob_load(); + + /* Enable QCLib serial output, based on Kconfig */ + if (IS_ENABLED(CONFIG_CONSOLE_SERIAL)) + qclib_cb_if_table.global_attributes = + QCLIB_GA_ENABLE_UART_LOGGING; + + if (IS_ENABLED(CONFIG_QC_SDI_ENABLE)) { + struct prog qcsdi = + PROG_INIT(PROG_REFCODE, CONFIG_CBFS_PREFIX QCSDI_NAME); + + /* Attempt to load QCSDI elf */ + if (prog_locate(&qcsdi)) + goto fail; + + if (cbfs_prog_stage_load(&qcsdi)) + goto fail; + + add_if_table_entry(QCLIB_TE_QCSDI, qcsdi.entry, + prog_size(&qcsdi), 0); + printk(BIOS_INFO, "qcsdi.entry[%llx]\n", (uint64_t)qcsdi.entry); + } + + dump_te_table(); + + /* Attempt to load QCLib elf */ + struct prog qclib = + PROG_INIT(PROG_REFCODE, CONFIG_CBFS_PREFIX QCLIB_NAME); + + if (prog_locate(&qclib)) + goto fail; + + if (cbfs_prog_stage_load(&qclib)) + goto fail; + + prog_set_entry(&qclib, qclib.entry, NULL); + + printk(BIOS_DEBUG, "\n\n\nQCLib is about to Initialize Private IP\n"); + printk(BIOS_DEBUG, "Global Attributes[%x]..Table Entries Count[%d]\n", + qclib_cb_if_table.global_attributes, + qclib_cb_if_table.num_entries); + printk(BIOS_DEBUG, "Jumping to QCLib code at %p(%p)\n", + prog_entry(&qclib), prog_entry_arg(&qclib)); + + doit = prog_entry(&qclib); + arg = prog_entry_arg(&qclib); + + /* back-up mmu context before disabling mmu and executing qclib */ + mmu_save_context(&pre_qclib_mmu_context); + /* disable mmu before jumping to qclib. mmu_disable also + flushes and invalidates caches before disabling mmu. */ + mmu_disable(); + + ret_code = doit(&qclib_cb_if_table, NULL); + + /* Before returning, QCLib flushes cache and disables mmu. + Explicitly disable mmu (flush, invalidate and disable mmu) + before re-enabling mmu with backed-up mmu context */ + mmu_disable(); + mmu_restore_context(&pre_qclib_mmu_context); + mmu_enable(); + + printk(BIOS_DEBUG, "QCLib completed\n\n\n"); + + /* step through I/F table, handling return values */ + for (i = 0; i < qclib_cb_if_table.num_entries; i++) + if (qclib_cb_if_table.te[i].blob_attributes & + QCLIB_BA_SAVE_TO_STORAGE) + write_table_entry(&qclib_cb_if_table.te[i]); + + /* confirm that we received valid ddr information from QCLib */ + assert((uintptr_t)_dram == region_offset(ddr_region) && + region_sz(ddr_region) >= (u8 *)cbmem_top() - _dram); + + return; + +fail: + die("Couldn't run QCLib.\n"); +}