qualcomm: Add QCLib interface support to common/
Change-Id: I38d086c379a3c2f54d1603a2fed5b33860f7f4d7 Signed-off-by: T Michael Turney <mturney@codeaurora.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/32288 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
This commit is contained in:
parent
32851c6df7
commit
7a3e46d767
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
config QC_SDI_ENABLE
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
prompt "Debug Build: enable SDI"
|
|
@ -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_ */
|
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* 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__
|
||||||
|
|
||||||
|
/* 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 qclib_add_if_table_entry(const char *name, void *base,
|
||||||
|
uint32_t size, uint32_t attrs);
|
||||||
|
void qclib_load_and_run(void);
|
||||||
|
int qclib_soc_blob_load(void);
|
||||||
|
|
||||||
|
#endif // _SOC_QUALCOMM_QCLIB_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_
|
|
@ -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();
|
||||||
|
}
|
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
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 qclib_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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++);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_table_entry(struct qclib_cb_if_table_entry *te)
|
||||||
|
{
|
||||||
|
|
||||||
|
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_WARNING, "%s write not implemented\n", te->name);
|
||||||
|
printk(BIOS_WARNING, " blob_address[%llx]..size[%x]\n",
|
||||||
|
te->blob_address, te->size);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static 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_DEBUG, "[%s][%llx][%x][%x]\n",
|
||||||
|
te->name, te->blob_address,
|
||||||
|
te->size, te->blob_attributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__weak int qclib_soc_blob_load(void) { return 0; }
|
||||||
|
|
||||||
|
void qclib_load_and_run(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
ssize_t ssize;
|
||||||
|
struct mmu_context pre_qclib_mmu_context;
|
||||||
|
|
||||||
|
/* 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))
|
||||||
|
qclib_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 */
|
||||||
|
qclib_add_if_table_entry(QCLIB_TE_DDR_INFORMATION, NULL, 0, 0);
|
||||||
|
|
||||||
|
/* Attempt to load DDR Training Blob */
|
||||||
|
ssize = fmap_read_area(QCLIB_FR_DDR_TRAINING_DATA, _ddr_training,
|
||||||
|
REGION_SIZE(ddr_training));
|
||||||
|
if (ssize < 0)
|
||||||
|
goto fail;
|
||||||
|
qclib_add_if_table_entry(QCLIB_TE_DDR_TRAINING_DATA,
|
||||||
|
_ddr_training, ssize, 0);
|
||||||
|
|
||||||
|
/* hook for SoC specific binary blob loads */
|
||||||
|
if (qclib_soc_blob_load()) {
|
||||||
|
printk(BIOS_ERR, "qclib_soc_blob_load failed\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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");
|
||||||
|
|
||||||
|
/* Attempt to load QCSDI elf */
|
||||||
|
if (prog_locate(&qcsdi))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (cbfs_prog_stage_load(&qcsdi))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
qclib_add_if_table_entry(QCLIB_TE_QCSDI, prog_entry(&qcsdi),
|
||||||
|
prog_size(&qcsdi), 0);
|
||||||
|
printk(BIOS_INFO, "qcsdi.entry[%p]\n", qcsdi.entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_te_table();
|
||||||
|
|
||||||
|
/* Attempt to load QCLib elf */
|
||||||
|
struct prog qclib =
|
||||||
|
PROG_INIT(PROG_REFCODE, CONFIG_CBFS_PREFIX "/qclib");
|
||||||
|
|
||||||
|
if (prog_locate(&qclib))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (cbfs_prog_stage_load(&qclib))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
prog_set_entry(&qclib, prog_entry(&qclib), &qclib_cb_if_table);
|
||||||
|
|
||||||
|
printk(BIOS_DEBUG, "\n\n\nQCLib is about to Initialize DDR\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));
|
||||||
|
|
||||||
|
/* 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();
|
||||||
|
|
||||||
|
prog_run(&qclib);
|
||||||
|
|
||||||
|
/* 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();
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
printk(BIOS_DEBUG, "QCLib completed\n\n\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
die("Couldn't run QCLib.\n");
|
||||||
|
}
|
Loading…
Reference in New Issue