GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018,2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <drivers/arm/gicv2.h>
#include <drivers/arm/gicv3.h>
#include <drivers/console.h>
#include <platform_def.h>
.globl plat_my_core_pos
.globl plat_qti_core_pos_by_mpidr
.globl plat_reset_handler
.globl plat_panic_handler
/* -----------------------------------------------------
* unsigned int plat_qti_core_pos_by_mpidr(uint64_t mpidr)
* Helper function to calculate the core position.
* With this function:
* CorePos = (ClusterId * 4) + CoreId
* - In ARM v8 (MPIDR_EL1[24]=0)
* ClusterId = MPIDR_EL1[15:8]
* CoreId = MPIDR_EL1[7:0]
* - In ARM v8.1 (MPIDR_EL1[24]=1)
* ClusterId = MPIDR_EL1[23:15]
* CoreId = MPIDR_EL1[15:8]
* Clobbers: x0 & x1.
* -----------------------------------------------------
*/
func plat_qti_core_pos_by_mpidr
mrs x1, mpidr_el1
tst x1, #MPIDR_MT_MASK
beq plat_qti_core_pos_by_mpidr_no_mt
/* Right shift mpidr by one affinity level when MT=1. */
lsr x0, x0, #MPIDR_AFFINITY_BITS
plat_qti_core_pos_by_mpidr_no_mt:
and x1, x0, #MPIDR_CPU_MASK
and x0, x0, #MPIDR_CLUSTER_MASK
add x0, x1, x0, LSR #6
ret
endfunc plat_qti_core_pos_by_mpidr
/* --------------------------------------------------------------------
* void plat_panic_handler(void)
* calls SDI and reset system
* --------------------------------------------------------------------
*/
func plat_panic_handler
msr spsel, #0
bl plat_set_my_stack
b qtiseclib_panic
endfunc plat_panic_handler
/* -----------------------------------------------------
* unsigned int plat_my_core_pos(void)
* This function uses the plat_qti_calc_core_pos()
* definition to get the index of the calling CPU
* Clobbers: x0 & x1.
* -----------------------------------------------------
*/
func plat_my_core_pos
mrs x0, mpidr_el1
b plat_qti_core_pos_by_mpidr
endfunc plat_my_core_pos
func plat_reset_handler
/* save the lr */
mov x18, x30
/* pass cold boot status. */
ldr w0, g_qti_bl31_cold_booted
/* Execuete CPUSS boot set up on every core. */
bl qtiseclib_cpuss_reset_asm
ret x18
endfunc plat_reset_handler
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <cpu_macros.S>
#include <plat_macros.S>
#include <qti_cpu.h>
.p2align 3
/* -------------------------------------------------
* The CPU Ops reset function for Kryo-3 Gold
* -------------------------------------------------
*/
func qti_kryo4_gold_reset_func
#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715
adr x0, wa_cve_2017_5715_bpiall_vbar
msr vbar_el3, x0
isb
#endif
mov x19, x30
bl qtiseclib_kryo4_gold_reset_asm
mov x30, x19
b cortex_a76_reset_func
endfunc qti_kryo4_gold_reset_func
/* -------------------------------------------------------
* The CPU Ops cluster power down function for Kryo-3 Gold
* -------------------------------------------------------
*/
func qti_kryo4_gold_cluster_pwr_dwn
ret
endfunc qti_kryo4_gold_cluster_pwr_dwn
#if REPORT_ERRATA
/*
* Errata printing function for Kryo4 Gold. Must follow AAPCS.
*/
func qti_kryo4_gold_errata_report
/* TODO : Need to add support. Required only for debug bl31 image.*/
ret
endfunc qti_kryo4_gold_errata_report
#endif
/* ---------------------------------------------
* This function provides kryo4_gold specific
* register information for crash reporting.
* It needs to return with x6 pointing to
* a list of register names in ASCII and
* x8 - x15 having values of registers to be
* reported.
* ---------------------------------------------
*/
.section .rodata.qti_kryo4_gold_regs, "aS"
qti_kryo4_gold_regs: /* The ASCII list of register names to be reported */
.asciz ""
func qti_kryo4_gold_cpu_reg_dump
adr x6, qti_kryo4_gold_regs
ret
endfunc qti_kryo4_gold_cpu_reg_dump
declare_cpu_ops_wa qti_kryo4_gold, QTI_KRYO4_GOLD_MIDR, \
qti_kryo4_gold_reset_func, \
CPU_NO_EXTRA1_FUNC, \
cortex_a76_disable_wa_cve_2018_3639, \
cortex_a76_core_pwr_dwn, \
qti_kryo4_gold_cluster_pwr_dwn
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <cpu_macros.S>
#include <plat_macros.S>
#include <qti_cpu.h>
.p2align 3
/* -------------------------------------------------
* The CPU Ops reset function for Kryo-3 Silver
* -------------------------------------------------
*/
func qti_kryo4_silver_reset_func
mov x19, x30
bl qtiseclib_kryo4_silver_reset_asm
mov x30, x19
b cortex_a55_reset_func
endfunc qti_kryo4_silver_reset_func
/* ---------------------------------------------------------
* The CPU Ops cluster power down function for Kryo-3 Silver
* ---------------------------------------------------------
*/
func qti_kryo4_silver_cluster_pwr_dwn
ret
endfunc qti_kryo4_silver_cluster_pwr_dwn
#if REPORT_ERRATA
/*
* Errata printing function for Kryo4 Silver. Must follow AAPCS.
*/
func qti_kryo4_silver_errata_report
/* TODO : Need to add support. Required only for debug bl31 image.*/
ret
endfunc qti_kryo4_silver_errata_report
#endif
/* ---------------------------------------------
* This function provides kryo4_silver specific
* register information for crash reporting.
* It needs to return with x6 pointing to
* a list of register names in ASCII and
* x8 - x15 having values of registers to be
* reported.
* ---------------------------------------------
*/
.section .rodata.qti_kryo4_silver_regs, "aS"
qti_kryo4_silver_regs: /* The ASCII list of register names to be reported */
.asciz ""
func qti_kryo4_silver_cpu_reg_dump
adr x6, qti_kryo4_silver_regs
ret
endfunc qti_kryo4_silver_cpu_reg_dump
declare_cpu_ops qti_kryo4_silver, QTI_KRYO4_SILVER_MIDR, \
qti_kryo4_silver_reset_func, \
cortex_a55_core_pwr_dwn, \
qti_kryo4_silver_cluster_pwr_dwn
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <cpu_macros.S>
#include <plat_macros.S>
#include <qti_cpu.h>
.p2align 3
/* -------------------------------------------------
* The CPU Ops reset function for Kryo-3 Gold
* -------------------------------------------------
*/
func qti_kryo6_gold_reset_func
#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715
adr x0, wa_cve_2017_5715_bpiall_vbar
msr vbar_el3, x0
isb
#endif
mov x19, x30
bl qtiseclib_kryo6_gold_reset_asm
mov x30, x19
b cortex_a78_reset_func
endfunc qti_kryo6_gold_reset_func
/* -------------------------------------------------------
* The CPU Ops cluster power down function for Kryo-3 Gold
* -------------------------------------------------------
*/
func qti_kryo6_gold_cluster_pwr_dwn
ret
endfunc qti_kryo6_gold_cluster_pwr_dwn
#if REPORT_ERRATA
/*
* Errata printing function for Kryo4 Gold. Must follow AAPCS.
*/
func qti_kryo6_gold_errata_report
/* TODO : Need to add support. Required only for debug bl31 image.*/
ret
endfunc qti_kryo6_gold_errata_report
#endif
/* ---------------------------------------------
* This function provides kryo4_gold specific
* register information for crash reporting.
* It needs to return with x6 pointing to
* a list of register names in ASCII and
* x8 - x15 having values of registers to be
* reported.
* ---------------------------------------------
*/
.section .rodata.qti_kryo4_gold_regs, "aS"
qti_kryo6_gold_regs: /* The ASCII list of register names to be reported */
.asciz ""
func qti_kryo6_gold_cpu_reg_dump
adr x6, qti_kryo6_gold_regs
ret
endfunc qti_kryo6_gold_cpu_reg_dump
declare_cpu_ops qti_kryo6_gold, QTI_KRYO6_GOLD_MIDR, \
qti_kryo6_gold_reset_func, \
cortex_a78_core_pwr_dwn, \
qti_kryo6_gold_cluster_pwr_dwn
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2015-2018, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <cpu_macros.S>
#include <plat_macros.S>
#include <qti_cpu.h>
.p2align 3
/* -------------------------------------------------
* The CPU Ops reset function for Kryo-3 Silver
* -------------------------------------------------
*/
func qti_kryo6_silver_reset_func
mov x19, x30
bl qtiseclib_kryo6_silver_reset_asm
mov x30, x19
b cortex_a55_reset_func
endfunc qti_kryo6_silver_reset_func
/* ---------------------------------------------------------
* The CPU Ops cluster power down function for Kryo-3 Silver
* ---------------------------------------------------------
*/
func qti_kryo6_silver_cluster_pwr_dwn
ret
endfunc qti_kryo6_silver_cluster_pwr_dwn
#if REPORT_ERRATA
/*
* Errata printing function for Kryo4 Silver. Must follow AAPCS.
*/
func qti_kryo6_silver_errata_report
/* TODO : Need to add support. Required only for debug bl31 image.*/
ret
endfunc qti_kryo6_silver_errata_report
#endif
/* ---------------------------------------------
* This function provides kryo4_silver specific
* register information for crash reporting.
* It needs to return with x6 pointing to
* a list of register names in ASCII and
* x8 - x15 having values of registers to be
* reported.
* ---------------------------------------------
*/
.section .rodata.qti_kryo4_silver_regs, "aS"
qti_kryo6_silver_regs: /* The ASCII list of register names to be reported */
.asciz ""
func qti_kryo6_silver_cpu_reg_dump
adr x6, qti_kryo6_silver_regs
ret
endfunc qti_kryo6_silver_cpu_reg_dump
declare_cpu_ops qti_kryo6_silver, QTI_KRYO6_SILVER_MIDR, \
qti_kryo6_silver_reset_func, \
cortex_a55_core_pwr_dwn, \
qti_kryo6_silver_cluster_pwr_dwn
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018,2020 The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include <console_macros.S>
#include <platform_def.h>
#include <qti_uart_console.h>
/*
* This driver implements console logging into a ring buffer.
*/
.globl qti_console_uart_register
/* -----------------------------------------------
* int qti_console_uart_register(console_t *console,
* uintptr_t uart_base_addr)
* Registers uart console instance.
* In: x0 - pointer to empty console_t struct
* x1 - start address of uart block.
* Out: x0 - 1 to indicate success
* Clobber list: x0, x1, x14
* -----------------------------------------------
*/
func qti_console_uart_register
str x1, [x0, #CONSOLE_T_BASE] /* Save UART base. */
finish_console_register uart putc=1, flush=1
endfunc qti_console_uart_register
/* -----------------------------------------------
* int qti_console_uart_puts(int c, console_t *console)
* Writes a character to the UART console.
* The character must be preserved in x0.
* In: x0 - character to be stored
* x1 - pointer to console_t struct
* Clobber list: x1, x2
* -----------------------------------------------
*/
func console_uart_putc
/* set x1 = UART base. */
ldr x1, [x1, #CONSOLE_T_BASE]
/* Loop until M_GENI_CMD_ACTIVE bit not clear. */
1: ldr w2, [x1, #GENI_STATUS_REG]
and w2, w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
cmp w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
b.eq 1b
/* Transmit data. */
cmp w0, #0xA
b.ne 3f
/* Add '\r' when input char is '\n' */
mov w2, #0x1
mov w0, #0xD
str w2, [x1, #UART_TX_TRANS_LEN_REG]
mov w2, #GENI_M_CMD_TX
str w2, [x1, #GENI_M_CMD0_REG]
str w0, [x1, #GENI_TX_FIFOn_REG]
mov w0, #0xA
/* Loop until M_GENI_CMD_ACTIVE bit not clear. */
2: ldr w2, [x1, #GENI_STATUS_REG]
and w2, w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
cmp w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
b.eq 2b
/* Transmit i/p data. */
3: mov w2, #0x1
str w2, [x1, #UART_TX_TRANS_LEN_REG]
mov w2, #GENI_M_CMD_TX
str w2, [x1, #GENI_M_CMD0_REG]
str w0, [x1, #GENI_TX_FIFOn_REG]
ret
endfunc console_uart_putc
/* -----------------------------------------------
* int qti_console_uart_flush(console_t *console)
* In: x0 - pointer to console_t struct
* Out: x0 - 0 for success
* Clobber list: x0, x1
* -----------------------------------------------
*/
func console_uart_flush
/* set x0 = UART base. */
ldr x0, [x0, #CONSOLE_T_BASE]
/* Loop until M_GENI_CMD_ACTIVE bit not clear. */
1: ldr w1, [x0, #GENI_STATUS_REG]
and w1, w1, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
cmp w1, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK
b.eq 1b
mov w0, #0
ret
endfunc console_uart_flush
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2020, Google LLC. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <drivers/delay_timer.h>
#include <qti_plat.h>
#include <spmi_arb.h>
/*
* This driver implements PON support for PM8998-compatible PMICs. This can
* include other part numbers like PM6150.
*/
#define RESET_TYPE_WARM_RESET 1
#define RESET_TYPE_SHUTDOWN 4
#define S2_RESET_EN BIT(7)
static void configure_ps_hold(uint32_t reset_type)
{
/* QTI recommends disabling reset for 10 cycles before reconfiguring. */
spmi_arb_write8(PON_PS_HOLD_RESET_CTL2, 0);
mdelay(1);
spmi_arb_write8(PON_PS_HOLD_RESET_CTL, reset_type);
spmi_arb_write8(PON_PS_HOLD_RESET_CTL2, S2_RESET_EN);
mdelay(1);
}
void qti_pmic_prepare_reset(void)
{
configure_ps_hold(RESET_TYPE_WARM_RESET);
}
void qti_pmic_prepare_shutdown(void)
{
configure_ps_hold(RESET_TYPE_SHUTDOWN);
}
@@ -0,0 +1,150 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <bl31/bl31.h>
#include <common/debug.h>
#include <common/desc_image_load.h>
#include <drivers/console.h>
#include <drivers/generic_delay_timer.h>
#include <lib/bl_aux_params/bl_aux_params.h>
#include <lib/coreboot.h>
#include <lib/spinlock.h>
#include <platform.h>
#include <qti_interrupt_svc.h>
#include <qti_plat.h>
#include <qti_uart_console.h>
#include <qtiseclib_interface.h>
/*
* Placeholder variables for copying the arguments that have been passed to
* BL31 from BL2.
*/
static entry_point_info_t bl33_image_ep_info;
/*
* Variable to hold counter frequency for the CPU's generic timer. In this
* platform coreboot image configure counter frequency for boot core before
* reaching TF-A.
*/
static uint64_t g_qti_cpu_cntfrq;
/*
* Variable to hold bl31 cold boot status. Default value 0x0 means yet to boot.
* Any other value means cold booted.
*/
uint32_t g_qti_bl31_cold_booted;
/*******************************************************************************
* Perform any BL31 early platform setup common to ARM standard platforms.
* Here is an opportunity to copy parameters passed by the calling EL (S-EL1
* in BL2 & S-EL3 in BL1) before they are lost (potentially). This needs to be
* done before the MMU is initialized so that the memory layout can be used
* while creating page tables. BL2 has flushed this information to memory, so
* we are guaranteed to pick up good data.
******************************************************************************/
void bl31_early_platform_setup(u_register_t from_bl2,
u_register_t plat_params_from_bl2)
{
g_qti_cpu_cntfrq = read_cntfrq_el0();
bl_aux_params_parse(plat_params_from_bl2, NULL);
#if COREBOOT
if (coreboot_serial.baseaddr != 0) {
static console_t g_qti_console_uart;
qti_console_uart_register(&g_qti_console_uart,
coreboot_serial.baseaddr);
}
#endif
/*
* Tell BL31 where the non-trusted software image
* is located and the entry state information
*/
bl31_params_parse_helper(from_bl2, NULL, &bl33_image_ep_info);
}
void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
bl31_early_platform_setup(arg0, arg1);
}
/*******************************************************************************
* Perform the very early platform specific architectural setup here. At the
* moment this only intializes the mmu in a quick and dirty way.
******************************************************************************/
void bl31_plat_arch_setup(void)
{
qti_setup_page_tables(
BL31_START,
BL31_END-BL31_START,
BL_CODE_BASE,
BL_CODE_END,
BL_RO_DATA_BASE,
BL_RO_DATA_END
);
enable_mmu_el3(0);
}
/*******************************************************************************
* Perform any BL31 platform setup common to ARM standard platforms
******************************************************************************/
void bl31_platform_setup(void)
{
generic_delay_timer_init();
/* Initialize the GIC driver, CPU and distributor interfaces */
plat_qti_gic_driver_init();
plat_qti_gic_init();
qti_interrupt_svc_init();
qtiseclib_bl31_platform_setup();
/* set boot state to cold boot complete. */
g_qti_bl31_cold_booted = 0x1;
}
/*******************************************************************************
* Return a pointer to the 'entry_point_info' structure of the next image for the
* security state specified. BL33 corresponds to the non-secure image type
* while BL32 corresponds to the secure image type. A NULL pointer is returned
* if the image does not exist.
******************************************************************************/
entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
{
/* QTI platform don't have BL32 implementation. */
assert(type == NON_SECURE);
assert(bl33_image_ep_info.h.type == PARAM_EP);
assert(bl33_image_ep_info.h.attr == NON_SECURE);
/*
* None of the images on the platforms can have 0x0
* as the entrypoint.
*/
if (bl33_image_ep_info.pc) {
return &bl33_image_ep_info;
} else {
return NULL;
}
}
/*******************************************************************************
* This function is used by the architecture setup code to retrieve the counter
* frequency for the CPU's generic timer. This value will be programmed into the
* CNTFRQ_EL0 register. In Arm standard platforms, it returns the base frequency
* of the system counter, which is retrieved from the first entry in the
* frequency modes table. This will be used later in warm boot (psci_arch_setup)
* of CPUs to set when CPU frequency.
******************************************************************************/
unsigned int plat_get_syscnt_freq2(void)
{
assert(g_qti_cpu_cntfrq != 0);
return g_qti_cpu_cntfrq;
}
@@ -0,0 +1,203 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <lib/smccc.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <services/arm_arch_svc.h>
#include <platform_def.h>
#include <qti_map_chipinfo.h>
#include <qti_plat.h>
#include <qtiseclib_interface.h>
/*
* Table of regions for various BL stages to map using the MMU.
* This doesn't include TZRAM as the 'mem_layout' argument passed to
* qti_configure_mmu_elx() will give the available subset of that,
*/
const mmap_region_t plat_qti_mmap[] = {
MAP_REGION_FLAT(QTI_DEVICE_BASE, QTI_DEVICE_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(QTI_AOP_CMD_DB_BASE, QTI_AOP_CMD_DB_SIZE,
MT_NS | MT_RO | MT_EXECUTE_NEVER),
{0}
};
CASSERT(ARRAY_SIZE(plat_qti_mmap) <= MAX_MMAP_REGIONS, assert_max_mmap_regions);
bool qti_is_overlap_atf_rg(unsigned long long addr, size_t size)
{
if (addr > addr + size
|| (BL31_BASE < addr + size && BL31_LIMIT > addr)) {
return true;
}
return false;
}
/*
* unsigned int plat_qti_my_cluster_pos(void)
* definition to get the cluster index of the calling CPU.
* - In ARM v8 (MPIDR_EL1[24]=0)
* ClusterId = MPIDR_EL1[15:8]
* - In ARM v8.1 & Later version (MPIDR_EL1[24]=1)
* ClusterId = MPIDR_EL1[23:15]
*/
unsigned int plat_qti_my_cluster_pos(void)
{
unsigned int mpidr, cluster_id;
mpidr = read_mpidr_el1();
if ((mpidr & MPIDR_MT_MASK) == 0) { /* MT not supported */
cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
} else { /* MT supported */
cluster_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK;
}
assert(cluster_id < PLAT_CLUSTER_COUNT);
return cluster_id;
}
/*
* Set up the page tables for the generic and platform-specific memory regions.
* The extents of the generic memory regions are specified by the function
* arguments and consist of:
* - Trusted SRAM seen by the BL image;
* - Code section;
* - Read-only data section;
* - Coherent memory region, if applicable.
*/
void qti_setup_page_tables(
uintptr_t total_base,
size_t total_size,
uintptr_t code_start,
uintptr_t code_limit,
uintptr_t rodata_start,
uintptr_t rodata_limit
)
{
/*
* Map the Trusted SRAM with appropriate memory attributes.
* Subsequent mappings will adjust the attributes for specific regions.
*/
VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n",
(void *)total_base, (void *)(total_base + total_size));
mmap_add_region(total_base, total_base,
total_size, MT_MEMORY | MT_RW | MT_SECURE);
/* Re-map the code section */
VERBOSE("Code region: %p - %p\n",
(void *)code_start, (void *)code_limit);
mmap_add_region(code_start, code_start,
code_limit - code_start, MT_CODE | MT_SECURE);
/* Re-map the read-only data section */
VERBOSE("Read-only data region: %p - %p\n",
(void *)rodata_start, (void *)rodata_limit);
mmap_add_region(rodata_start, rodata_start,
rodata_limit - rodata_start, MT_RO_DATA | MT_SECURE);
/* Now (re-)map the platform-specific memory regions */
mmap_add(plat_qti_mmap);
/* Create the page tables to reflect the above mappings */
init_xlat_tables();
}
static inline void qti_align_mem_region(uintptr_t addr, size_t size,
uintptr_t *aligned_addr,
size_t *aligned_size)
{
*aligned_addr = round_down(addr, PAGE_SIZE);
*aligned_size = round_up(addr - *aligned_addr + size, PAGE_SIZE);
}
int qti_mmap_add_dynamic_region(uintptr_t base_pa, size_t size,
unsigned int attr)
{
uintptr_t aligned_pa;
size_t aligned_size;
qti_align_mem_region(base_pa, size, &aligned_pa, &aligned_size);
if (qti_is_overlap_atf_rg(base_pa, size)) {
/* Memory shouldn't overlap with TF-A range. */
return -EPERM;
}
return mmap_add_dynamic_region(aligned_pa, aligned_pa, aligned_size,
attr);
}
int qti_mmap_remove_dynamic_region(uintptr_t base_va, size_t size)
{
qti_align_mem_region(base_va, size, &base_va, &size);
return mmap_remove_dynamic_region(base_va, size);
}
/*
* This function returns soc version which mainly consist of below fields
*
* soc_version[30:24] = JEP-106 continuation code for the SiP
* soc_version[23:16] = JEP-106 identification code with parity bit for the SiP
* soc_version[0:15] = Implementation defined SoC ID
*/
int32_t plat_get_soc_version(void)
{
int i = 0;
/* Variant other than in mapped g_map_jtag_chipinfo_id variable will have
* default chipinfo id as 0xFFFF
*/
uint32_t soc_version = (QTI_DEFAULT_CHIPINFO_ID & QTI_SOC_VERSION_MASK);
uint32_t jep106az_code = (JEDEC_QTI_BKID << QTI_SOC_CONTINUATION_SHIFT)
| (JEDEC_QTI_MFID << QTI_SOC_IDENTIFICATION_SHIFT);
uint32_t jtag_id = mmio_read_32(QTI_JTAG_ID_REG);
uint32_t jtag_id_val = (jtag_id >> QTI_JTAG_ID_SHIFT)
& QTI_SOC_VERSION_MASK;
for (i = 0; i < ARRAY_SIZE(g_map_jtag_chipinfo_id); i++) {
if (g_map_jtag_chipinfo_id[i].jtag_id == jtag_id_val)
soc_version = g_map_jtag_chipinfo_id[i].chipinfo_id
& QTI_SOC_VERSION_MASK;
}
return (int32_t)(jep106az_code | (soc_version));
}
/*
* This function returns soc revision in below format
*
* soc_revision[0:30] = SOC revision of specific SOC
*/
int32_t plat_get_soc_revision(void)
{
return mmio_read_32(QTI_SOC_REVISION_REG) & QTI_SOC_REVISION_MASK;
}
/*****************************************************************************
* plat_is_smccc_feature_available() - This function checks whether SMCCC feature
* is availabile for the platform or not.
* @fid: SMCCC function id
*
* Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and
* SMC_ARCH_CALL_NOT_SUPPORTED otherwise.
*****************************************************************************/
int32_t plat_is_smccc_feature_available(u_register_t fid)
{
switch (fid) {
case SMCCC_ARCH_SOC_ID:
return SMC_ARCH_CALL_SUCCESS;
default:
return SMC_ARCH_CALL_NOT_SUPPORTED;
}
}
@@ -0,0 +1,169 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.h>
#include <drivers/arm/gicv3.h>
#include <platform.h>
#include <platform_def.h>
#include <qti_plat.h>
#include <qtiseclib_defs.h>
#include <qtiseclib_defs_plat.h>
/* The GICv3 driver only needs to be initialized in EL3 */
static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
/* Array of interrupts to be configured by the gic driver */
static const interrupt_prop_t qti_interrupt_props[] = {
INTR_PROP_DESC(QTISECLIB_INT_ID_CPU_WAKEUP_SGI,
GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_RESET_SGI, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_SEC_WDOG_BARK, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_NON_SEC_WDOG_BITE,
GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
GIC_INTR_CFG_LEVEL),
INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC,
GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC,
GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC,
GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CFG_NONSEC,
GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_XPU_SEC, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_XPU_NON_SEC, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
#ifdef QTISECLIB_INT_ID_A1_NOC_ERROR
INTR_PROP_DESC(QTISECLIB_INT_ID_A1_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
#endif
INTR_PROP_DESC(QTISECLIB_INT_ID_A2_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_CONFIG_NOC_ERROR,
GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_DC_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_MEM_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_SYSTEM_NOC_ERROR,
GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(QTISECLIB_INT_ID_MMSS_NOC_ERROR,
GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0,
GIC_INTR_CFG_EDGE),
#ifdef QTISECLIB_INT_ID_LPASS_AGNOC_ERROR
INTR_PROP_DESC(QTISECLIB_INT_ID_LPASS_AGNOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
#endif
#ifdef QTISECLIB_INT_ID_NSP_NOC_ERROR
INTR_PROP_DESC(QTISECLIB_INT_ID_NSP_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY,
INTR_GROUP0,
GIC_INTR_CFG_EDGE),
#endif
};
const gicv3_driver_data_t qti_gic_data = {
.gicd_base = QTI_GICD_BASE,
.gicr_base = QTI_GICR_BASE,
.interrupt_props = qti_interrupt_props,
.interrupt_props_num = ARRAY_SIZE(qti_interrupt_props),
.rdistif_num = PLATFORM_CORE_COUNT,
.rdistif_base_addrs = rdistif_base_addrs,
.mpidr_to_core_pos = plat_qti_core_pos_by_mpidr
};
void plat_qti_gic_driver_init(void)
{
/*
* The GICv3 driver is initialized in EL3 and does not need
* to be initialized again in SEL1. This is because the S-EL1
* can use GIC system registers to manage interrupts and does
* not need GIC interface base addresses to be configured.
*/
gicv3_driver_init(&qti_gic_data);
}
/******************************************************************************
* ARM common helper to initialize the GIC. Only invoked by BL31
*****************************************************************************/
void plat_qti_gic_init(void)
{
unsigned int i;
gicv3_distif_init();
gicv3_rdistif_init(plat_my_core_pos());
gicv3_cpuif_enable(plat_my_core_pos());
/* Route secure spi interrupt to ANY. */
for (i = 0; i < ARRAY_SIZE(qti_interrupt_props); i++) {
unsigned int int_id = qti_interrupt_props[i].intr_num;
if (plat_ic_is_spi(int_id)) {
gicv3_set_spi_routing(int_id, GICV3_IRM_ANY, 0x0);
}
}
}
void gic_set_spi_routing(unsigned int id, unsigned int irm, u_register_t target)
{
gicv3_set_spi_routing(id, irm, target);
}
/******************************************************************************
* ARM common helper to enable the GIC CPU interface
*****************************************************************************/
void plat_qti_gic_cpuif_enable(void)
{
gicv3_cpuif_enable(plat_my_core_pos());
}
/******************************************************************************
* ARM common helper to disable the GIC CPU interface
*****************************************************************************/
void plat_qti_gic_cpuif_disable(void)
{
gicv3_cpuif_disable(plat_my_core_pos());
}
/******************************************************************************
* ARM common helper to initialize the per-CPU redistributor interface in GICv3
*****************************************************************************/
void plat_qti_gic_pcpu_init(void)
{
gicv3_rdistif_init(plat_my_core_pos());
}
/******************************************************************************
* ARM common helpers to power GIC redistributor interface
*****************************************************************************/
void plat_qti_gic_redistif_on(void)
{
gicv3_rdistif_on(plat_my_core_pos());
}
void plat_qti_gic_redistif_off(void)
{
gicv3_rdistif_off(plat_my_core_pos());
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018,2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdint.h>
#include <arch_helpers.h>
#include <bl31/interrupt_mgmt.h>
#include <drivers/arm/gic_common.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <platform.h>
#include <qti_interrupt_svc.h>
#include <qtiseclib_interface.h>
#define QTI_INTR_INVALID_INT_NUM 0xFFFFFFFFU
/*
* Top-level EL3 interrupt handler.
*/
static uint64_t qti_el3_interrupt_handler(uint32_t id, uint32_t flags,
void *handle, void *cookie)
{
uint32_t irq = QTI_INTR_INVALID_INT_NUM;
/*
* EL3 non-interruptible. Interrupt shouldn't occur when we are at
* EL3 / Secure.
*/
assert(handle != cm_get_context(SECURE));
irq = plat_ic_acknowledge_interrupt();
qtiseclib_invoke_isr(irq, handle);
/* End of Interrupt. */
if (irq < 1022U) {
plat_ic_end_of_interrupt(irq);
}
return (uint64_t) handle;
}
int qti_interrupt_svc_init(void)
{
int ret;
uint64_t flags = 0U;
/*
* Route EL3 interrupts to EL3 when in Non-secure.
* Note: EL3 won't have interrupt enable
* & we don't have S-EL1 support.
*/
set_interrupt_rm_flag(flags, NON_SECURE);
set_interrupt_rm_flag(flags, SECURE);
/* Register handler for EL3 interrupts */
ret = register_interrupt_type_handler(INTR_TYPE_EL3,
qti_el3_interrupt_handler, flags);
assert(ret == 0);
return ret;
}
@@ -0,0 +1,287 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <bl31/bl31.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <platform.h>
#include <platform_def.h>
#include <qti_cpu.h>
#include <qti_plat.h>
#include <qtiseclib_cb_interface.h>
#include <qtiseclib_defs_plat.h>
#include <qtiseclib_interface.h>
#define QTI_LOCAL_PSTATE_WIDTH 4
#define QTI_LOCAL_PSTATE_MASK ((1 << QTI_LOCAL_PSTATE_WIDTH) - 1)
/* Make composite power state parameter till level 0 */
#define qti_make_pwrstate_lvl0(lvl0_state, type) \
(((lvl0_state) << PSTATE_ID_SHIFT) | ((type) << PSTATE_TYPE_SHIFT))
/* Make composite power state parameter till level 1 */
#define qti_make_pwrstate_lvl1(lvl1_state, lvl0_state, type) \
(((lvl1_state) << QTI_LOCAL_PSTATE_WIDTH) | \
qti_make_pwrstate_lvl0(lvl0_state, type))
/* Make composite power state parameter till level 2 */
#define qti_make_pwrstate_lvl2(lvl2_state, lvl1_state, lvl0_state, type) \
(((lvl2_state) << (QTI_LOCAL_PSTATE_WIDTH * 2)) | \
qti_make_pwrstate_lvl1(lvl1_state, lvl0_state, type))
/* Make composite power state parameter till level 3 */
#define qti_make_pwrstate_lvl3(lvl3_state, lvl2_state, lvl1_state, lvl0_state, type) \
(((lvl3_state) << (QTI_LOCAL_PSTATE_WIDTH * 3)) | \
qti_make_pwrstate_lvl2(lvl2_state, lvl1_state, lvl0_state, type))
/* QTI_CORE_PWRDN_EN_MASK happens to be same across all CPUs */
#define QTI_CORE_PWRDN_EN_MASK 1
/* cpu power control happens to be same across all CPUs */
_DEFINE_SYSREG_WRITE_FUNC(cpu_pwrctrl_val, S3_0_C15_C2_7)
_DEFINE_SYSREG_READ_FUNC(cpu_pwrctrl_val, S3_0_C15_C2_7)
const unsigned int qti_pm_idle_states[] = {
qti_make_pwrstate_lvl0(QTI_LOCAL_STATE_OFF,
PSTATE_TYPE_POWERDOWN),
qti_make_pwrstate_lvl0(QTI_LOCAL_STATE_DEEPOFF,
PSTATE_TYPE_POWERDOWN),
qti_make_pwrstate_lvl1(QTI_LOCAL_STATE_DEEPOFF,
QTI_LOCAL_STATE_DEEPOFF,
PSTATE_TYPE_POWERDOWN),
qti_make_pwrstate_lvl2(QTI_LOCAL_STATE_OFF,
QTI_LOCAL_STATE_DEEPOFF,
QTI_LOCAL_STATE_DEEPOFF,
PSTATE_TYPE_POWERDOWN),
qti_make_pwrstate_lvl3(QTI_LOCAL_STATE_OFF,
QTI_LOCAL_STATE_DEEPOFF,
QTI_LOCAL_STATE_DEEPOFF,
QTI_LOCAL_STATE_DEEPOFF,
PSTATE_TYPE_POWERDOWN),
0,
};
/*******************************************************************************
* QTI standard platform handler called to check the validity of the power
* state parameter. The power state parameter has to be a composite power
* state.
******************************************************************************/
int qti_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
unsigned int state_id;
int i;
assert(req_state);
/*
* Currently we are using a linear search for finding the matching
* entry in the idle power state array. This can be made a binary
* search if the number of entries justify the additional complexity.
*/
for (i = 0; !!qti_pm_idle_states[i]; i++) {
if (power_state == qti_pm_idle_states[i])
break;
}
/* Return error if entry not found in the idle state array */
if (!qti_pm_idle_states[i])
return PSCI_E_INVALID_PARAMS;
i = 0;
state_id = psci_get_pstate_id(power_state);
/* Parse the State ID and populate the state info parameter */
while (state_id) {
req_state->pwr_domain_state[i++] = state_id &
QTI_LOCAL_PSTATE_MASK;
state_id >>= QTI_LOCAL_PSTATE_WIDTH;
}
return PSCI_E_SUCCESS;
}
/*******************************************************************************
* PLATFORM FUNCTIONS
******************************************************************************/
static void qti_set_cpupwrctlr_val(void)
{
unsigned long val;
val = read_cpu_pwrctrl_val();
val |= QTI_CORE_PWRDN_EN_MASK;
write_cpu_pwrctrl_val(val);
isb();
}
/**
* CPU power on function - ideally we want a wrapper since this function is
* target specific. But to unblock teams.
*/
static int qti_cpu_power_on(u_register_t mpidr)
{
int core_pos = plat_core_pos_by_mpidr(mpidr);
/* If not valid mpidr, return error */
if (core_pos < 0 || core_pos >= QTISECLIB_PLAT_CORE_COUNT) {
return PSCI_E_INVALID_PARAMS;
}
return qtiseclib_psci_node_power_on(mpidr);
}
static bool is_cpu_off(const psci_power_state_t *target_state)
{
if ((target_state->pwr_domain_state[QTI_PWR_LVL0] ==
QTI_LOCAL_STATE_OFF) ||
(target_state->pwr_domain_state[QTI_PWR_LVL0] ==
QTI_LOCAL_STATE_DEEPOFF)) {
return true;
} else {
return false;
}
}
static void qti_cpu_power_on_finish(const psci_power_state_t *target_state)
{
const uint8_t *pwr_states =
(const uint8_t *)target_state->pwr_domain_state;
qtiseclib_psci_node_on_finish(pwr_states);
if (is_cpu_off(target_state)) {
plat_qti_gic_cpuif_enable();
}
}
static void qti_cpu_standby(plat_local_state_t cpu_state)
{
}
static void qti_node_power_off(const psci_power_state_t *target_state)
{
qtiseclib_psci_node_power_off((const uint8_t *)
target_state->pwr_domain_state);
if (is_cpu_off(target_state)) {
plat_qti_gic_cpuif_disable();
qti_set_cpupwrctlr_val();
}
}
static void qti_node_suspend(const psci_power_state_t *target_state)
{
qtiseclib_psci_node_suspend((const uint8_t *)target_state->
pwr_domain_state);
if (is_cpu_off(target_state)) {
plat_qti_gic_cpuif_disable();
qti_set_cpupwrctlr_val();
}
}
static void qti_node_suspend_finish(const psci_power_state_t *target_state)
{
const uint8_t *pwr_states =
(const uint8_t *)target_state->pwr_domain_state;
qtiseclib_psci_node_suspend_finish(pwr_states);
if (is_cpu_off(target_state)) {
plat_qti_gic_cpuif_enable();
}
}
__dead2 void qti_domain_power_down_wfi(const psci_power_state_t *target_state)
{
/* For now just do WFI - add any target specific handling if needed */
psci_power_down_wfi();
/* We should never reach here */
}
static __dead2 void assert_ps_hold(void)
{
mmio_write_32(QTI_PS_HOLD_REG, 0);
mdelay(1000);
/* Should be dead before reaching this. */
panic();
}
__dead2 void qti_system_off(void)
{
qti_pmic_prepare_shutdown();
assert_ps_hold();
}
__dead2 void qti_system_reset(void)
{
qti_pmic_prepare_reset();
assert_ps_hold();
}
void qti_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
int i = 0;
unsigned int state_id, power_state;
int size = ARRAY_SIZE(qti_pm_idle_states);
/*
* Find deepest state.
* The arm_pm_idle_states[] array has last element by default 0,
* so the real deepest state is second last element of that array.
*/
power_state = qti_pm_idle_states[size - 2];
state_id = psci_get_pstate_id(power_state);
/* Parse the State ID and populate the state info parameter */
while (state_id) {
req_state->pwr_domain_state[i++] =
state_id & QTI_LOCAL_PSTATE_MASK;
state_id >>= QTI_LOCAL_PSTATE_WIDTH;
}
}
/*
* Structure containing platform specific PSCI operations. Common
* PSCI layer will use this.
*/
const plat_psci_ops_t plat_qti_psci_pm_ops = {
.pwr_domain_on = qti_cpu_power_on,
.pwr_domain_on_finish = qti_cpu_power_on_finish,
.cpu_standby = qti_cpu_standby,
.pwr_domain_off = qti_node_power_off,
.pwr_domain_suspend = qti_node_suspend,
.pwr_domain_suspend_finish = qti_node_suspend_finish,
.pwr_domain_pwr_down_wfi = qti_domain_power_down_wfi,
.system_off = qti_system_off,
.system_reset = qti_system_reset,
.get_node_hw_state = NULL,
.translate_power_state_by_mpidr = NULL,
.get_sys_suspend_power_state = qti_get_sys_suspend_power_state,
.validate_power_state = qti_validate_power_state,
};
/**
* The QTI Standard platform definition of platform porting API
* `plat_setup_psci_ops`.
*/
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
int err;
err = qtiseclib_psci_init((uintptr_t)bl31_warm_entrypoint);
if (err == PSCI_E_SUCCESS) {
*psci_ops = &plat_qti_psci_pm_ops;
}
return err;
}
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stddef.h>
#include <lib/mmio.h>
#include <qti_rng.h>
#include <qti_rng_io.h>
int qti_rng_get_data(uint8_t *out, uint32_t out_len)
{
uint32_t tmp_rndm = 0;
uint32_t bytes_left = out_len;
int i = 0;
if (NULL == out || 0 == out_len) {
return -1;
}
/*
* RNG HW initialized at previous boot image.
* RNG clocks are expected to be ON.
*/
do {
/* There is no data to read */
if ((mmio_read_32(SEC_PRNG_STATUS) &
SEC_PRNG_STATUS_DATA_AVAIL_BMSK) == 0) {
continue;
}
while ((tmp_rndm = mmio_read_32(SEC_PRNG_DATA_OUT)) == 0) {
;
}
for (i = 0; i < 4; i++) {
*out = (uint8_t) (tmp_rndm >> (8 * i));
out++;
bytes_left--;
if (bytes_left == 0) {
break;
}
}
} while (bytes_left != 0);
return 0;
}
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdint.h>
#include <platform.h>
#include <platform_def.h>
#include <qti_rng.h>
#include <qtiseclib_interface.h>
u_register_t plat_get_stack_protector_canary(void)
{
u_register_t random = 0x0;
/*
* get random data , the below API doesn't return random = 0 on success
*/
qti_rng_get_data((uint8_t *) &random, sizeof(random));
assert(random != 0x0);
return random;
}
@@ -0,0 +1,386 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <context.h>
#include <lib/coreboot.h>
#include <lib/utils_def.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <smccc_helpers.h>
#include <tools_share/uuid.h>
#include <qti_plat.h>
#include <qti_secure_io_cfg.h>
#include <qtiseclib_interface.h>
/*
* SIP service - SMC function IDs for SiP Service queries
*
*/
#define QTI_SIP_SVC_CALL_COUNT_ID U(0x0200ff00)
#define QTI_SIP_SVC_UID_ID U(0x0200ff01)
/* 0x8200ff02 is reserved*/
#define QTI_SIP_SVC_VERSION_ID U(0x0200ff03)
#define QTI_SIP_SVC_AVAILABLE_ID U(0x02000601)
/*
* Syscall's to allow Non Secure world accessing peripheral/IO memory
* those are secure/proteced BUT not required to be secure.
*/
#define QTI_SIP_SVC_SECURE_IO_READ_ID U(0x02000501)
#define QTI_SIP_SVC_SECURE_IO_WRITE_ID U(0x02000502)
/*
* Syscall's to assigns a list of intermediate PAs from a
* source Virtual Machine (VM) to a destination VM.
*/
#define QTI_SIP_SVC_MEM_ASSIGN_ID U(0x02000C16)
#define QTI_SIP_SVC_SECURE_IO_READ_PARAM_ID U(0x1)
#define QTI_SIP_SVC_SECURE_IO_WRITE_PARAM_ID U(0x2)
#define QTI_SIP_SVC_MEM_ASSIGN_PARAM_ID U(0x1117)
#define QTI_SIP_SVC_CALL_COUNT U(0x3)
#define QTI_SIP_SVC_VERSION_MAJOR U(0x0)
#define QTI_SIP_SVC_VERSION_MINOR U(0x0)
#define QTI_VM_LAST U(44)
#define SIZE4K U(0x1000)
#define QTI_VM_MAX_LIST_SIZE U(0x20)
#define FUNCID_OEN_NUM_MASK ((FUNCID_OEN_MASK << FUNCID_OEN_SHIFT)\
|(FUNCID_NUM_MASK << FUNCID_NUM_SHIFT))
enum {
QTI_SIP_SUCCESS = 0,
QTI_SIP_NOT_SUPPORTED = -1,
QTI_SIP_PREEMPTED = -2,
QTI_SIP_INVALID_PARAM = -3,
};
/* QTI SiP Service UUID */
DEFINE_SVC_UUID2(qti_sip_svc_uid,
0x43864748, 0x217f, 0x41ad, 0xaa, 0x5a,
0xba, 0xe7, 0x0f, 0xa5, 0x52, 0xaf);
static bool qti_is_secure_io_access_allowed(u_register_t addr)
{
int i = 0;
for (i = 0; i < ARRAY_SIZE(qti_secure_io_allowed_regs); i++) {
if ((uintptr_t) addr == qti_secure_io_allowed_regs[i]) {
return true;
}
}
return false;
}
static bool qti_check_syscall_availability(u_register_t smc_fid)
{
switch (smc_fid) {
case QTI_SIP_SVC_CALL_COUNT_ID:
case QTI_SIP_SVC_UID_ID:
case QTI_SIP_SVC_VERSION_ID:
case QTI_SIP_SVC_AVAILABLE_ID:
case QTI_SIP_SVC_SECURE_IO_READ_ID:
case QTI_SIP_SVC_SECURE_IO_WRITE_ID:
case QTI_SIP_SVC_MEM_ASSIGN_ID:
return true;
default:
return false;
}
}
bool qti_mem_assign_validate_param(memprot_info_t *mem_info,
u_register_t u_num_mappings,
uint32_t *source_vm_list,
u_register_t src_vm_list_cnt,
memprot_dst_vm_perm_info_t *dest_vm_list,
u_register_t dst_vm_list_cnt)
{
int i;
if (!source_vm_list || !dest_vm_list || !mem_info
|| (src_vm_list_cnt == 0)
|| (src_vm_list_cnt >= QTI_VM_LAST) || (dst_vm_list_cnt == 0)
|| (dst_vm_list_cnt >= QTI_VM_LAST) || (u_num_mappings == 0)
|| u_num_mappings > QTI_VM_MAX_LIST_SIZE) {
ERROR("vm count is 0 or more then QTI_VM_LAST or empty list\n");
ERROR("source_vm_list %p dest_vm_list %p mem_info %p src_vm_list_cnt %u dst_vm_list_cnt %u u_num_mappings %u\n",
source_vm_list, dest_vm_list, mem_info,
(unsigned int)src_vm_list_cnt,
(unsigned int)dst_vm_list_cnt,
(unsigned int)u_num_mappings);
return false;
}
for (i = 0; i < u_num_mappings; i++) {
if ((mem_info[i].mem_addr & (SIZE4K - 1))
|| (mem_info[i].mem_size == 0)
|| (mem_info[i].mem_size & (SIZE4K - 1))) {
ERROR("mem_info passed buffer 0x%x or size 0x%x is not 4k aligned\n",
(unsigned int)mem_info[i].mem_addr,
(unsigned int)mem_info[i].mem_size);
return false;
}
if ((mem_info[i].mem_addr + mem_info[i].mem_size) <
mem_info[i].mem_addr) {
ERROR("overflow in mem_addr 0x%x add mem_size 0x%x\n",
(unsigned int)mem_info[i].mem_addr,
(unsigned int)mem_info[i].mem_size);
return false;
}
coreboot_memory_t mem_type = coreboot_get_memory_type(
mem_info[i].mem_addr,
mem_info[i].mem_size);
if (mem_type != CB_MEM_RAM && mem_type != CB_MEM_RESERVED) {
ERROR("memory region not in CB MEM RAM or RESERVED area: region start 0x%x size 0x%x\n",
(unsigned int)mem_info[i].mem_addr,
(unsigned int)mem_info[i].mem_size);
return false;
}
}
for (i = 0; i < src_vm_list_cnt; i++) {
if (source_vm_list[i] >= QTI_VM_LAST) {
ERROR("source_vm_list[%d] 0x%x is more then QTI_VM_LAST\n",
i, (unsigned int)source_vm_list[i]);
return false;
}
}
for (i = 0; i < dst_vm_list_cnt; i++) {
if (dest_vm_list[i].dst_vm >= QTI_VM_LAST) {
ERROR("dest_vm_list[%d] 0x%x is more then QTI_VM_LAST\n",
i, (unsigned int)dest_vm_list[i].dst_vm);
return false;
}
}
return true;
}
static uintptr_t qti_sip_mem_assign(void *handle, uint32_t smc_cc,
u_register_t x1,
u_register_t x2,
u_register_t x3, u_register_t x4)
{
uintptr_t dyn_map_start = 0, dyn_map_end = 0;
size_t dyn_map_size = 0;
u_register_t x6, x7;
int ret = QTI_SIP_NOT_SUPPORTED;
u_register_t x5 = read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X5);
if (smc_cc == SMC_32) {
x5 = (uint32_t) x5;
}
/* Validate input arg count & retrieve arg3-6 from NS Buffer. */
if ((x1 != QTI_SIP_SVC_MEM_ASSIGN_PARAM_ID) || (x5 == 0x0)) {
ERROR("invalid mem_assign param id or no mapping info\n");
goto unmap_return;
}
/* Map NS Buffer. */
dyn_map_start = x5;
dyn_map_size =
(smc_cc ==
SMC_32) ? (sizeof(uint32_t) * 4) : (sizeof(uint64_t) * 4);
if (qti_mmap_add_dynamic_region(dyn_map_start, dyn_map_size,
(MT_NS | MT_RO_DATA)) != 0) {
ERROR("map failed for params NS Buffer %x %x\n",
(unsigned int)dyn_map_start, (unsigned int)dyn_map_size);
goto unmap_return;
}
/* Retrieve indirect args. */
if (smc_cc == SMC_32) {
x6 = *((uint32_t *) x5 + 1);
x7 = *((uint32_t *) x5 + 2);
x5 = *(uint32_t *) x5;
} else {
x6 = *((uint64_t *) x5 + 1);
x7 = *((uint64_t *) x5 + 2);
x5 = *(uint64_t *) x5;
}
/* Un-Map NS Buffer. */
if (qti_mmap_remove_dynamic_region(dyn_map_start, dyn_map_size) != 0) {
ERROR("unmap failed for params NS Buffer %x %x\n",
(unsigned int)dyn_map_start, (unsigned int)dyn_map_size);
goto unmap_return;
}
/*
* Map NS Buffers.
* arg0,2,4 points to buffers & arg1,3,5 hold sizes.
* MAP api's fail to map if it's already mapped. Let's
* find lowest start & highest end address, then map once.
*/
dyn_map_start = MIN(x2, x4);
dyn_map_start = MIN(dyn_map_start, x6);
dyn_map_end = MAX((x2 + x3), (x4 + x5));
dyn_map_end = MAX(dyn_map_end, (x6 + x7));
dyn_map_size = dyn_map_end - dyn_map_start;
if (qti_mmap_add_dynamic_region(dyn_map_start, dyn_map_size,
(MT_NS | MT_RO_DATA)) != 0) {
ERROR("map failed for params NS Buffer2 %x %x\n",
(unsigned int)dyn_map_start, (unsigned int)dyn_map_size);
goto unmap_return;
}
memprot_info_t *mem_info_p = (memprot_info_t *) x2;
uint32_t u_num_mappings = x3 / sizeof(memprot_info_t);
uint32_t *source_vm_list_p = (uint32_t *) x4;
uint32_t src_vm_list_cnt = x5 / sizeof(uint32_t);
memprot_dst_vm_perm_info_t *dest_vm_list_p =
(memprot_dst_vm_perm_info_t *) x6;
uint32_t dst_vm_list_cnt =
x7 / sizeof(memprot_dst_vm_perm_info_t);
if (qti_mem_assign_validate_param(mem_info_p, u_num_mappings,
source_vm_list_p, src_vm_list_cnt,
dest_vm_list_p,
dst_vm_list_cnt) != true) {
ERROR("Param validation failed\n");
goto unmap_return;
}
memprot_info_t mem_info[QTI_VM_MAX_LIST_SIZE];
/* Populating the arguments */
for (int i = 0; i < u_num_mappings; i++) {
mem_info[i].mem_addr = mem_info_p[i].mem_addr;
mem_info[i].mem_size = mem_info_p[i].mem_size;
}
memprot_dst_vm_perm_info_t dest_vm_list[QTI_VM_LAST];
for (int i = 0; i < dst_vm_list_cnt; i++) {
dest_vm_list[i].dst_vm = dest_vm_list_p[i].dst_vm;
dest_vm_list[i].dst_vm_perm = dest_vm_list_p[i].dst_vm_perm;
dest_vm_list[i].ctx = dest_vm_list_p[i].ctx;
dest_vm_list[i].ctx_size = dest_vm_list_p[i].ctx_size;
}
uint32_t source_vm_list[QTI_VM_LAST];
for (int i = 0; i < src_vm_list_cnt; i++) {
source_vm_list[i] = source_vm_list_p[i];
}
/* Un-Map NS Buffers. */
if (qti_mmap_remove_dynamic_region(dyn_map_start,
dyn_map_size) != 0) {
ERROR("unmap failed for params NS Buffer %x %x\n",
(unsigned int)dyn_map_start, (unsigned int)dyn_map_size);
goto unmap_return;
}
/* Invoke API lib api. */
ret = qtiseclib_mem_assign(mem_info, u_num_mappings,
source_vm_list, src_vm_list_cnt,
dest_vm_list, dst_vm_list_cnt);
if (ret == 0) {
SMC_RET2(handle, QTI_SIP_SUCCESS, ret);
}
unmap_return:
/* Un-Map NS Buffers if mapped */
if (dyn_map_start && dyn_map_size) {
qti_mmap_remove_dynamic_region(dyn_map_start, dyn_map_size);
}
SMC_RET2(handle, QTI_SIP_INVALID_PARAM, ret);
}
/*
* This function handles QTI specific syscalls. Currently only SiP calls are present.
* Both FAST & YIELD type call land here.
*/
static uintptr_t qti_sip_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie, void *handle, u_register_t flags)
{
uint32_t l_smc_fid = smc_fid & FUNCID_OEN_NUM_MASK;
if (GET_SMC_CC(smc_fid) == SMC_32) {
x1 = (uint32_t) x1;
x2 = (uint32_t) x2;
x3 = (uint32_t) x3;
x4 = (uint32_t) x4;
}
switch (l_smc_fid) {
case QTI_SIP_SVC_CALL_COUNT_ID:
{
SMC_RET1(handle, QTI_SIP_SVC_CALL_COUNT);
break;
}
case QTI_SIP_SVC_UID_ID:
{
/* Return UID to the caller */
SMC_UUID_RET(handle, qti_sip_svc_uid);
break;
}
case QTI_SIP_SVC_VERSION_ID:
{
/* Return the version of current implementation */
SMC_RET2(handle, QTI_SIP_SVC_VERSION_MAJOR,
QTI_SIP_SVC_VERSION_MINOR);
break;
}
case QTI_SIP_SVC_AVAILABLE_ID:
{
if (x1 != 1) {
SMC_RET1(handle, QTI_SIP_INVALID_PARAM);
}
if (qti_check_syscall_availability(x2) == true) {
SMC_RET2(handle, QTI_SIP_SUCCESS, 1);
} else {
SMC_RET2(handle, QTI_SIP_SUCCESS, 0);
}
break;
}
case QTI_SIP_SVC_SECURE_IO_READ_ID:
{
if ((x1 == QTI_SIP_SVC_SECURE_IO_READ_PARAM_ID) &&
qti_is_secure_io_access_allowed(x2)) {
SMC_RET2(handle, QTI_SIP_SUCCESS,
*((volatile uint32_t *)x2));
}
SMC_RET1(handle, QTI_SIP_INVALID_PARAM);
break;
}
case QTI_SIP_SVC_SECURE_IO_WRITE_ID:
{
if ((x1 == QTI_SIP_SVC_SECURE_IO_WRITE_PARAM_ID) &&
qti_is_secure_io_access_allowed(x2)) {
*((volatile uint32_t *)x2) = x3;
SMC_RET1(handle, QTI_SIP_SUCCESS);
}
SMC_RET1(handle, QTI_SIP_INVALID_PARAM);
break;
}
case QTI_SIP_SVC_MEM_ASSIGN_ID:
{
return qti_sip_mem_assign(handle, GET_SMC_CC(smc_fid),
x1, x2, x3, x4);
break;
}
default:
{
SMC_RET1(handle, QTI_SIP_NOT_SUPPORTED);
}
}
return (uintptr_t) handle;
}
/* Define a runtime service descriptor for both fast & yield SiP calls */
DECLARE_RT_SVC(qti_sip_fast_svc, OEN_SIP_START,
OEN_SIP_END, SMC_TYPE_FAST, NULL, qti_sip_handler);
DECLARE_RT_SVC(qti_sip_yield_svc, OEN_SIP_START,
OEN_SIP_END, SMC_TYPE_YIELD, NULL, qti_sip_handler);
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2018,2020 The Linux Foundation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <platform_def.h>
#include <qti_plat.h>
/* The QTI power domain tree descriptor */
const unsigned char qti_power_domain_tree_desc[] = {
/* One domain to represent PDC */
PLAT_PDC_COUNT,
/* One domain to represent RSC */
PLAT_RSC_COUNT,
/* There is one top-level FCM cluster */
PLAT_CLUSTER_COUNT,
/* No. of cores in the FCM cluster */
PLAT_CLUSTER0_CORE_COUNT
};
/*******************************************************************************
* This function returns the ARM default topology tree information.
******************************************************************************/
const unsigned char *plat_get_power_domain_tree_desc(void)
{
return qti_power_domain_tree_desc;
}
/** Function: plat_core_pos_by_mpidr
* This function implements a part of the critical interface between the psci
* generic layer and the platform that allows the former to query the platform
* to convert an MPIDR to a unique linear index. An error code (-1) is returned
* in case the MPIDR is invalid.
*/
int plat_core_pos_by_mpidr(u_register_t mpidr)
{
int core_linear_index = plat_qti_core_pos_by_mpidr(mpidr);
if (core_linear_index < PLATFORM_CORE_COUNT) {
return core_linear_index;
} else {
return -1;
}
}
@@ -0,0 +1,113 @@
/*
* Copyright (c) 2020, Google LLC. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <spmi_arb.h>
#define REG_APID_MAP(apid) (0x0C440900U + sizeof(uint32_t) * apid)
#define NUM_APID ((0x1100U - 0x900U) / sizeof(uint32_t))
#define PPID_MASK (0xfffU << 8)
#define REG_ARB_CMD(apid) (0x0C600000U + 0x10000U * apid)
/* These are opcodes specific to this SPMI arbitrator, *not* SPMI commands. */
#define OPC_EXT_WRITEL 0
#define OPC_EXT_READL 1
#define REG_ARB_STATUS(apid) (0x0C600008U + 0x10000U * apid)
#define ARB_STATUS_DONE BIT(0)
#define ARB_STATUS_FAILURE BIT(1)
#define ARB_STATUS_DENIED BIT(2)
#define ARB_STATUS_DROPPED BIT(3)
/* Fake status to report driver errors. */
#define ARB_FAKE_STATUS_TIMEOUT BIT(8)
#define REG_ARB_RDATA0(apid) (0x0C600018U + 0x10000U * apid)
#define REG_ARB_WDATA0(apid) (0x0C600010U + 0x10000U * apid)
static int addr_to_apid(uint32_t addr)
{
unsigned int i;
for (i = 0U; i < NUM_APID; i++) {
uint32_t reg = mmio_read_32(REG_APID_MAP(i));
if ((reg != 0U) && ((addr & PPID_MASK) == (reg & PPID_MASK))) {
return i;
}
}
return -1;
}
static int wait_for_done(uint16_t apid)
{
unsigned int timeout = 100;
while (timeout-- != 0U) {
uint32_t status = mmio_read_32(REG_ARB_STATUS(apid));
if ((status & ARB_STATUS_DONE) != 0U) {
if ((status & ARB_STATUS_FAILURE) != 0U ||
(status & ARB_STATUS_DENIED) != 0U ||
(status & ARB_STATUS_DROPPED) != 0U) {
return status & 0xff;
}
return 0;
}
mdelay(1);
}
ERROR("SPMI_ARB timeout!\n");
return ARB_FAKE_STATUS_TIMEOUT;
}
static void arb_command(uint16_t apid, uint8_t opcode, uint32_t addr,
uint8_t bytes)
{
mmio_write_32(REG_ARB_CMD(apid), (uint32_t)opcode << 27 |
(addr & 0xff) << 4 | (bytes - 1));
}
int spmi_arb_read8(uint32_t addr)
{
int apid = addr_to_apid(addr);
if (apid < 0) {
return apid;
}
arb_command(apid, OPC_EXT_READL, addr, 1);
int ret = wait_for_done(apid);
if (ret != 0) {
ERROR("SPMI_ARB read error [0x%x]: 0x%x\n", addr, ret);
return ret;
}
return mmio_read_32(REG_ARB_RDATA0(apid)) & 0xff;
}
int spmi_arb_write8(uint32_t addr, uint8_t data)
{
int apid = addr_to_apid(addr);
if (apid < 0) {
return apid;
}
mmio_write_32(REG_ARB_WDATA0(apid), data);
arb_command(apid, OPC_EXT_WRITEL, addr, 1);
int ret = wait_for_done(apid);
if (ret != 0) {
ERROR("SPMI_ARB write error [0x%x] = 0x%x: 0x%x\n",
addr, data, ret);
}
return ret;
}