From 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 11:13:47 +0200 Subject: Adding upstream version 2.8.0+dfsg. Signed-off-by: Daniel Baumann --- plat/qti/common/inc/aarch64/plat_macros.S | 106 ++++++ plat/qti/common/inc/qti_board_def.h | 37 ++ plat/qti/common/inc/qti_cpu.h | 22 ++ plat/qti/common/inc/qti_interrupt_svc.h | 12 + plat/qti/common/inc/qti_plat.h | 62 ++++ plat/qti/common/inc/qti_rng.h | 14 + plat/qti/common/inc/qti_uart_console.h | 19 + plat/qti/common/inc/spmi_arb.h | 23 ++ plat/qti/common/src/aarch64/qti_helpers.S | 81 +++++ plat/qti/common/src/aarch64/qti_kryo4_gold.S | 77 ++++ plat/qti/common/src/aarch64/qti_kryo4_silver.S | 71 ++++ plat/qti/common/src/aarch64/qti_kryo6_gold.S | 75 ++++ plat/qti/common/src/aarch64/qti_kryo6_silver.S | 71 ++++ plat/qti/common/src/aarch64/qti_uart_console.S | 102 ++++++ plat/qti/common/src/pm_ps_hold.c | 41 +++ plat/qti/common/src/qti_bl31_setup.c | 150 ++++++++ plat/qti/common/src/qti_common.c | 203 +++++++++++ plat/qti/common/src/qti_gic_v3.c | 169 +++++++++ plat/qti/common/src/qti_interrupt_svc.c | 66 ++++ plat/qti/common/src/qti_pm.c | 287 +++++++++++++++ plat/qti/common/src/qti_rng.c | 53 +++ plat/qti/common/src/qti_stack_protector.c | 26 ++ plat/qti/common/src/qti_syscall.c | 386 +++++++++++++++++++++ plat/qti/common/src/qti_topology.c | 48 +++ plat/qti/common/src/spmi_arb.c | 113 ++++++ plat/qti/msm8916/aarch64/msm8916_helpers.S | 164 +++++++++ plat/qti/msm8916/aarch64/uartdm_console.S | 154 ++++++++ plat/qti/msm8916/include/msm8916_mmap.h | 41 +++ plat/qti/msm8916/include/plat_macros.S | 27 ++ plat/qti/msm8916/include/platform_def.h | 57 +++ plat/qti/msm8916/include/uartdm_console.h | 12 + plat/qti/msm8916/msm8916_bl31_setup.c | 219 ++++++++++++ plat/qti/msm8916/msm8916_cpu_boot.c | 66 ++++ plat/qti/msm8916/msm8916_gicv2.c | 59 ++++ plat/qti/msm8916/msm8916_gicv2.h | 12 + plat/qti/msm8916/msm8916_pm.c | 59 ++++ plat/qti/msm8916/msm8916_pm.h | 12 + plat/qti/msm8916/msm8916_topology.c | 35 ++ plat/qti/msm8916/platform.mk | 62 ++++ plat/qti/qtiseclib/inc/qtiseclib_cb_interface.h | 59 ++++ plat/qti/qtiseclib/inc/qtiseclib_defs.h | 104 ++++++ plat/qti/qtiseclib/inc/qtiseclib_interface.h | 99 ++++++ .../qti/qtiseclib/inc/sc7180/qtiseclib_defs_plat.h | 35 ++ .../qti/qtiseclib/inc/sc7280/qtiseclib_defs_plat.h | 45 +++ plat/qti/qtiseclib/src/qtiseclib_cb_interface.c | 211 +++++++++++ plat/qti/qtiseclib/src/qtiseclib_interface_stub.c | 129 +++++++ plat/qti/sc7180/inc/platform_def.h | 198 +++++++++++ plat/qti/sc7180/inc/qti_map_chipinfo.h | 28 ++ plat/qti/sc7180/inc/qti_rng_io.h | 15 + plat/qti/sc7180/inc/qti_secure_io_cfg.h | 30 ++ plat/qti/sc7180/platform.mk | 128 +++++++ plat/qti/sc7280/inc/platform_def.h | 198 +++++++++++ plat/qti/sc7280/inc/qti_map_chipinfo.h | 34 ++ plat/qti/sc7280/inc/qti_rng_io.h | 15 + plat/qti/sc7280/inc/qti_secure_io_cfg.h | 30 ++ plat/qti/sc7280/platform.mk | 130 +++++++ 56 files changed, 4781 insertions(+) create mode 100644 plat/qti/common/inc/aarch64/plat_macros.S create mode 100644 plat/qti/common/inc/qti_board_def.h create mode 100644 plat/qti/common/inc/qti_cpu.h create mode 100644 plat/qti/common/inc/qti_interrupt_svc.h create mode 100644 plat/qti/common/inc/qti_plat.h create mode 100644 plat/qti/common/inc/qti_rng.h create mode 100644 plat/qti/common/inc/qti_uart_console.h create mode 100644 plat/qti/common/inc/spmi_arb.h create mode 100644 plat/qti/common/src/aarch64/qti_helpers.S create mode 100644 plat/qti/common/src/aarch64/qti_kryo4_gold.S create mode 100644 plat/qti/common/src/aarch64/qti_kryo4_silver.S create mode 100644 plat/qti/common/src/aarch64/qti_kryo6_gold.S create mode 100644 plat/qti/common/src/aarch64/qti_kryo6_silver.S create mode 100644 plat/qti/common/src/aarch64/qti_uart_console.S create mode 100644 plat/qti/common/src/pm_ps_hold.c create mode 100644 plat/qti/common/src/qti_bl31_setup.c create mode 100644 plat/qti/common/src/qti_common.c create mode 100644 plat/qti/common/src/qti_gic_v3.c create mode 100644 plat/qti/common/src/qti_interrupt_svc.c create mode 100644 plat/qti/common/src/qti_pm.c create mode 100644 plat/qti/common/src/qti_rng.c create mode 100644 plat/qti/common/src/qti_stack_protector.c create mode 100644 plat/qti/common/src/qti_syscall.c create mode 100644 plat/qti/common/src/qti_topology.c create mode 100644 plat/qti/common/src/spmi_arb.c create mode 100644 plat/qti/msm8916/aarch64/msm8916_helpers.S create mode 100644 plat/qti/msm8916/aarch64/uartdm_console.S create mode 100644 plat/qti/msm8916/include/msm8916_mmap.h create mode 100644 plat/qti/msm8916/include/plat_macros.S create mode 100644 plat/qti/msm8916/include/platform_def.h create mode 100644 plat/qti/msm8916/include/uartdm_console.h create mode 100644 plat/qti/msm8916/msm8916_bl31_setup.c create mode 100644 plat/qti/msm8916/msm8916_cpu_boot.c create mode 100644 plat/qti/msm8916/msm8916_gicv2.c create mode 100644 plat/qti/msm8916/msm8916_gicv2.h create mode 100644 plat/qti/msm8916/msm8916_pm.c create mode 100644 plat/qti/msm8916/msm8916_pm.h create mode 100644 plat/qti/msm8916/msm8916_topology.c create mode 100644 plat/qti/msm8916/platform.mk create mode 100644 plat/qti/qtiseclib/inc/qtiseclib_cb_interface.h create mode 100644 plat/qti/qtiseclib/inc/qtiseclib_defs.h create mode 100644 plat/qti/qtiseclib/inc/qtiseclib_interface.h create mode 100644 plat/qti/qtiseclib/inc/sc7180/qtiseclib_defs_plat.h create mode 100644 plat/qti/qtiseclib/inc/sc7280/qtiseclib_defs_plat.h create mode 100644 plat/qti/qtiseclib/src/qtiseclib_cb_interface.c create mode 100644 plat/qti/qtiseclib/src/qtiseclib_interface_stub.c create mode 100644 plat/qti/sc7180/inc/platform_def.h create mode 100644 plat/qti/sc7180/inc/qti_map_chipinfo.h create mode 100644 plat/qti/sc7180/inc/qti_rng_io.h create mode 100644 plat/qti/sc7180/inc/qti_secure_io_cfg.h create mode 100644 plat/qti/sc7180/platform.mk create mode 100644 plat/qti/sc7280/inc/platform_def.h create mode 100644 plat/qti/sc7280/inc/qti_map_chipinfo.h create mode 100644 plat/qti/sc7280/inc/qti_rng_io.h create mode 100644 plat/qti/sc7280/inc/qti_secure_io_cfg.h create mode 100644 plat/qti/sc7280/platform.mk (limited to 'plat/qti') diff --git a/plat/qti/common/inc/aarch64/plat_macros.S b/plat/qti/common/inc/aarch64/plat_macros.S new file mode 100644 index 0000000..2e292fb --- /dev/null +++ b/plat/qti/common/inc/aarch64/plat_macros.S @@ -0,0 +1,106 @@ +/* + * 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 + */ + +#ifndef __PLAT_MACROS_S__ +#define __PLAT_MACROS_S__ + +#include +#include +#include + +#include + +.section .rodata.gic_reg_name, "aS" +/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */ +gicc_regs: + .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" + +/* Applicable only to GICv3 with SRE enabled */ +icc_regs: + .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", "" + +/* Registers common to both GICv2 and GICv3 */ +gicd_pend_reg: + .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \ + " Offset:\t\t\tvalue\n" +newline: + .asciz "\n" +spacer: + .asciz ":\t\t0x" + +/** Macro : plat_crash_print_regs + * This macro allows the crash reporting routine to print GIC registers + * in case of an unhandled exception in BL31. This aids in debugging and + * this macro can be defined to be empty in case GIC register reporting is + * not desired. + * The below required platform porting macro + * prints out relevant GIC registers whenever an + * unhandled exception is taken in BL31. + * Clobbers: x0 - x10, x26, x27, sp + * --------------------------------------------- + */ + .macro plat_crash_print_regs +print_gic_regs: + ldr x26, =QTI_GICD_BASE + ldr x27, =QTI_GICC_BASE + + /* Check for GICv3 system register access */ + mrs x7, id_aa64pfr0_el1 + ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH + cmp x7, #1 + b.ne print_gicv2 + + /* Check for SRE enable */ + mrs x8, ICC_SRE_EL3 + tst x8, #ICC_SRE_SRE_BIT + b.eq print_gicv2 + + /* Load the icc reg list to x6 */ + adr x6, icc_regs + /* Load the icc regs to gp regs used by str_in_crash_buf_print */ + mrs x8, ICC_HPPIR0_EL1 + mrs x9, ICC_HPPIR1_EL1 + mrs x10, ICC_CTLR_EL3 + /* Store to the crash buf and print to console */ + bl str_in_crash_buf_print + b print_gic_common + +print_gicv2: + /* Load the gicc reg list to x6 */ + adr x6, gicc_regs + /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ + ldr w8, [x27, #GICC_HPPIR] + ldr w9, [x27, #GICC_AHPPIR] + ldr w10, [x27, #GICC_CTLR] + /* Store to the crash buf and print to console */ + bl str_in_crash_buf_print + +print_gic_common: + /* Print the GICD_ISPENDR regs */ + add x7, x26, #GICD_ISPENDR + adr x4, gicd_pend_reg + bl asm_print_str +gicd_ispendr_loop: + sub x4, x7, x26 + cmp x4, #0x280 + b.eq exit_print_gic_regs + bl asm_print_hex + + adr x4, spacer + bl asm_print_str + + ldr x4, [x7], #8 + bl asm_print_hex + + adr x4, newline + bl asm_print_str + b gicd_ispendr_loop +exit_print_gic_regs: + + .endm + +#endif /* __PLAT_MACROS_S__ */ diff --git a/plat/qti/common/inc/qti_board_def.h b/plat/qti/common/inc/qti_board_def.h new file mode 100644 index 0000000..c95e4c0 --- /dev/null +++ b/plat/qti/common/inc/qti_board_def.h @@ -0,0 +1,37 @@ +/* + * 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 + */ +#ifndef QTI_BOARD_DEF_H +#define QTI_BOARD_DEF_H + +/* + * Required platform porting definitions common to all ARM + * development platforms + */ + +/* + * Defines used to retrieve QTI SOC Version + */ +#define JEDEC_QTI_BKID U(0x0) +#define JEDEC_QTI_MFID U(0x70) +#define QTI_SOC_CONTINUATION_SHIFT U(24) +#define QTI_SOC_IDENTIFICATION_SHIFT U(16) + +/* Size of cacheable stacks */ +#define PLATFORM_STACK_SIZE 0x1000 + +/* + * PLAT_QTI_MMAP_ENTRIES depends on the number of entries in the + * plat_qti_mmap array defined for each BL stage. + */ +#define PLAT_QTI_MMAP_ENTRIES 12 + +/* + * Platform specific page table and MMU setup constants + */ +#define MAX_XLAT_TABLES 12 + +#endif /* QTI_BOARD_DEF_H */ diff --git a/plat/qti/common/inc/qti_cpu.h b/plat/qti/common/inc/qti_cpu.h new file mode 100644 index 0000000..3316f7b --- /dev/null +++ b/plat/qti/common/inc/qti_cpu.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef QTI_CPU_H +#define QTI_CPU_H + +/* KRYO-4xx Gold MIDR */ +#define QTI_KRYO4_GOLD_MIDR 0x517F804D + +/* KRYO-4xx Silver MIDR */ +#define QTI_KRYO4_SILVER_MIDR 0x517F805D + +/* KRYO-6xx Gold MIDR */ +#define QTI_KRYO6_GOLD_MIDR 0x412FD410 + +/* KRYO-6xx Silver MIDR */ +#define QTI_KRYO6_SILVER_MIDR 0x412FD050 + +#endif /* QTI_CPU_H */ diff --git a/plat/qti/common/inc/qti_interrupt_svc.h b/plat/qti/common/inc/qti_interrupt_svc.h new file mode 100644 index 0000000..59bde86 --- /dev/null +++ b/plat/qti/common/inc/qti_interrupt_svc.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2018,2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef QTI_INTERRUPT_SVC_H +#define QTI_INTERRUPT_SVC_H + +int qti_interrupt_svc_init(void); + +#endif /* QTI_INTERRUPT_SVC_H */ diff --git a/plat/qti/common/inc/qti_plat.h b/plat/qti/common/inc/qti_plat.h new file mode 100644 index 0000000..7483c49 --- /dev/null +++ b/plat/qti/common/inc/qti_plat.h @@ -0,0 +1,62 @@ +/* + * 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 + */ + +#ifndef QTI_PLAT_H +#define QTI_PLAT_H + +#include + +#include +#include +#include +#include + +/* + * Utility functions common to QTI platforms + */ +int qti_mmap_add_dynamic_region(uintptr_t base_pa, size_t size, + unsigned int attr); +int qti_mmap_remove_dynamic_region(uintptr_t base_va, size_t size); + +/* + * Utility functions common to ARM standard platforms + */ +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 + ); + +/* + * Mandatory functions required in ARM standard platforms + */ +void plat_qti_gic_driver_init(void); +void plat_qti_gic_init(void); +void plat_qti_gic_cpuif_enable(void); +void plat_qti_gic_cpuif_disable(void); +void plat_qti_gic_pcpu_init(void); + +/* + * Optional functions required in ARM standard platforms + */ +unsigned int plat_qti_core_pos_by_mpidr(u_register_t mpidr); +unsigned int plat_qti_my_cluster_pos(void); + +void gic_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr); + +void qti_pmic_prepare_reset(void); +void qti_pmic_prepare_shutdown(void); + +typedef struct chip_id_info { + uint16_t jtag_id; + uint16_t chipinfo_id; +} chip_id_info_t; + +#endif /* QTI_PLAT_H */ diff --git a/plat/qti/common/inc/qti_rng.h b/plat/qti/common/inc/qti_rng.h new file mode 100644 index 0000000..62c31f3 --- /dev/null +++ b/plat/qti/common/inc/qti_rng.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef QTI_RNG_H +#define QTI_RNG_H + +#include + +int qti_rng_get_data(uint8_t *out, uint32_t out_len); + +#endif /* QTI_RNG_H */ diff --git a/plat/qti/common/inc/qti_uart_console.h b/plat/qti/common/inc/qti_uart_console.h new file mode 100644 index 0000000..c5a65d6 --- /dev/null +++ b/plat/qti/common/inc/qti_uart_console.h @@ -0,0 +1,19 @@ +/* + * 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 + */ + +#ifndef QTI_UART_CONSOLE_H +#define QTI_UART_CONSOLE_H + +#include + +#ifndef __ASSEMBLER__ + +int qti_console_uart_register(console_t *console, uintptr_t uart_base_addr); + +#endif /* __ASSEMBLER__ */ + +#endif /* QTI_UART_CONSOLE_H */ diff --git a/plat/qti/common/inc/spmi_arb.h b/plat/qti/common/inc/spmi_arb.h new file mode 100644 index 0000000..362f740 --- /dev/null +++ b/plat/qti/common/inc/spmi_arb.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2020, Google LLC. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SPMI_ARB_H +#define SPMI_ARB_H + +#include + +/******************************************************************************* + * WARNING: This driver does not arbitrate access with the kernel. These APIs + * must only be called when the kernel is known to be quiesced (such as before + * boot or while the system is shutting down). + ******************************************************************************/ + +/* 32-bit addresses combine (U)SID, PID and register address. */ + +int spmi_arb_read8(uint32_t addr); +int spmi_arb_write8(uint32_t addr, uint8_t data); + +#endif /* SPMI_ARB_H */ diff --git a/plat/qti/common/src/aarch64/qti_helpers.S b/plat/qti/common/src/aarch64/qti_helpers.S new file mode 100644 index 0000000..d34b530 --- /dev/null +++ b/plat/qti/common/src/aarch64/qti_helpers.S @@ -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 +#include +#include +#include +#include + +#include + + .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 diff --git a/plat/qti/common/src/aarch64/qti_kryo4_gold.S b/plat/qti/common/src/aarch64/qti_kryo4_gold.S new file mode 100644 index 0000000..9bcdf54 --- /dev/null +++ b/plat/qti/common/src/aarch64/qti_kryo4_gold.S @@ -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 +#include +#include + +#include +#include + + .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 diff --git a/plat/qti/common/src/aarch64/qti_kryo4_silver.S b/plat/qti/common/src/aarch64/qti_kryo4_silver.S new file mode 100644 index 0000000..36374b7 --- /dev/null +++ b/plat/qti/common/src/aarch64/qti_kryo4_silver.S @@ -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 +#include +#include + +#include +#include + + .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 diff --git a/plat/qti/common/src/aarch64/qti_kryo6_gold.S b/plat/qti/common/src/aarch64/qti_kryo6_gold.S new file mode 100644 index 0000000..577e7ff --- /dev/null +++ b/plat/qti/common/src/aarch64/qti_kryo6_gold.S @@ -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 +#include +#include + +#include +#include + + .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 diff --git a/plat/qti/common/src/aarch64/qti_kryo6_silver.S b/plat/qti/common/src/aarch64/qti_kryo6_silver.S new file mode 100644 index 0000000..6ad0bca --- /dev/null +++ b/plat/qti/common/src/aarch64/qti_kryo6_silver.S @@ -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 +#include +#include + +#include +#include + + .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 diff --git a/plat/qti/common/src/aarch64/qti_uart_console.S b/plat/qti/common/src/aarch64/qti_uart_console.S new file mode 100644 index 0000000..2eb33d9 --- /dev/null +++ b/plat/qti/common/src/aarch64/qti_uart_console.S @@ -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 +#include + +#include +#include + +/* + * 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 diff --git a/plat/qti/common/src/pm_ps_hold.c b/plat/qti/common/src/pm_ps_hold.c new file mode 100644 index 0000000..208345c --- /dev/null +++ b/plat/qti/common/src/pm_ps_hold.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020, Google LLC. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include + +/* + * 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); +} diff --git a/plat/qti/common/src/qti_bl31_setup.c b/plat/qti/common/src/qti_bl31_setup.c new file mode 100644 index 0000000..dac0253 --- /dev/null +++ b/plat/qti/common/src/qti_bl31_setup.c @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * 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; +} diff --git a/plat/qti/common/src/qti_common.c b/plat/qti/common/src/qti_common.c new file mode 100644 index 0000000..74ccb5b --- /dev/null +++ b/plat/qti/common/src/qti_common.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * 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; + } +} diff --git a/plat/qti/common/src/qti_gic_v3.c b/plat/qti/common/src/qti_gic_v3.c new file mode 100644 index 0000000..f00267a --- /dev/null +++ b/plat/qti/common/src/qti_gic_v3.c @@ -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 +#include + +#include +#include +#include +#include +#include + +/* 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()); +} diff --git a/plat/qti/common/src/qti_interrupt_svc.c b/plat/qti/common/src/qti_interrupt_svc.c new file mode 100644 index 0000000..3017dc7 --- /dev/null +++ b/plat/qti/common/src/qti_interrupt_svc.c @@ -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 +#include + +#include +#include +#include +#include + +#include +#include +#include + +#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; +} diff --git a/plat/qti/common/src/qti_pm.c b/plat/qti/common/src/qti_pm.c new file mode 100644 index 0000000..5f1b7aa --- /dev/null +++ b/plat/qti/common/src/qti_pm.c @@ -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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/plat/qti/common/src/qti_rng.c b/plat/qti/common/src/qti_rng.c new file mode 100644 index 0000000..f63f3b8 --- /dev/null +++ b/plat/qti/common/src/qti_rng.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include + +#include + +#include +#include + +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; +} diff --git a/plat/qti/common/src/qti_stack_protector.c b/plat/qti/common/src/qti_stack_protector.c new file mode 100644 index 0000000..572830f --- /dev/null +++ b/plat/qti/common/src/qti_stack_protector.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include + +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; +} diff --git a/plat/qti/common/src/qti_syscall.c b/plat/qti/common/src/qti_syscall.c new file mode 100644 index 0000000..d8e5be9 --- /dev/null +++ b/plat/qti/common/src/qti_syscall.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * 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); diff --git a/plat/qti/common/src/qti_topology.c b/plat/qti/common/src/qti_topology.c new file mode 100644 index 0000000..bf2e3f3 --- /dev/null +++ b/plat/qti/common/src/qti_topology.c @@ -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 + +#include +#include + +/* 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; + } +} diff --git a/plat/qti/common/src/spmi_arb.c b/plat/qti/common/src/spmi_arb.c new file mode 100644 index 0000000..4213ed1 --- /dev/null +++ b/plat/qti/common/src/spmi_arb.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2020, Google LLC. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include + +#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; +} diff --git a/plat/qti/msm8916/aarch64/msm8916_helpers.S b/plat/qti/msm8916/aarch64/msm8916_helpers.S new file mode 100644 index 0000000..dad9968 --- /dev/null +++ b/plat/qti/msm8916/aarch64/msm8916_helpers.S @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +#define APCS_TCM_START_ADDR 0x10 +#define APCS_TCM_REDIRECT_EN_0 BIT_32(0) + + .globl plat_crash_console_init + .globl plat_crash_console_putc + .globl plat_crash_console_flush + .globl plat_panic_handler + .globl plat_my_core_pos + .globl plat_get_my_entrypoint + .globl plat_reset_handler + .globl platform_mem_init + .globl msm8916_entry_point + + /* ------------------------------------------------- + * int plat_crash_console_init(void) + * Initialize the crash console. + * Out: x0 - 1 on success, 0 on error + * Clobber list : x0 - x4 + * ------------------------------------------------- + */ +func plat_crash_console_init + mov x1, #BLSP_UART2_BASE + + /* + * If the non-secure world has been actively using the UART there might + * be still some characters left to be sent in the FIFO. In that case, + * resetting the transmitter too early might cause all output to become + * corrupted. To avoid that, try to flush (wait until FIFO empty) first. + */ + mov x4, lr + bl console_uartdm_core_flush + mov lr, x4 + + mov x0, #1 + b console_uartdm_core_init +endfunc plat_crash_console_init + + /* ------------------------------------------------- + * int plat_crash_console_putc(int c) + * Print a character on the crash console. + * In : w0 - character to be printed + * Out: w0 - printed character on success + * Clobber list : x1, x2 + * ------------------------------------------------- + */ +func plat_crash_console_putc + mov x1, #BLSP_UART2_BASE + b console_uartdm_core_putc +endfunc plat_crash_console_putc + + /* ------------------------------------------------- + * void plat_crash_console_flush(void) + * Force a write of all buffered data that has not + * been output. + * Clobber list : x1, x2 + * ------------------------------------------------- + */ +func plat_crash_console_flush + mov x1, #BLSP_UART2_BASE + b console_uartdm_core_flush +endfunc plat_crash_console_flush + + /* ------------------------------------------------- + * void plat_panic_handler(void) __dead + * Called when an unrecoverable error occurs. + * ------------------------------------------------- + */ +func plat_panic_handler + /* Try to shutdown/reset */ + mov_imm x0, MPM_PS_HOLD + str wzr, [x0] +1: b 1b +endfunc plat_panic_handler + + /* ------------------------------------------------- + * unsigned int plat_my_core_pos(void) + * Out: x0 - index of the calling CPU + * ------------------------------------------------- + */ +func plat_my_core_pos + /* There is just a single cluster so this is very simple */ + mrs x0, mpidr_el1 + and x0, x0, #MPIDR_CPU_MASK + ret +endfunc plat_my_core_pos + + /* ------------------------------------------------- + * uintptr_t plat_get_my_entrypoint(void) + * Distinguish cold and warm boot and return warm boot + * entry address if available. + * Out: x0 - warm boot entry point or 0 on cold boot + * ------------------------------------------------- + */ +func plat_get_my_entrypoint + ldr x0, msm8916_entry_point + ret +endfunc plat_get_my_entrypoint + + /* ------------------------------------------------- + * void plat_reset_handler(void) + * Perform additional initialization after reset. + * Clobber list : x0 - x18, x30 + * ------------------------------------------------- + */ +func plat_reset_handler + /* + * Check if the CPU is running at the correct address. + * During cold boot the CPU enters here at the wrong address + * using the "boot remapper". (It remaps the BL31_BASE to + * the CPU reset address 0x0). + */ + mov x0, #BL31_BASE + adr x1, bl31_entrypoint + cmp x0, x1 + b.ne _remapped_cold_boot + /* Already running at correct address, just return directly */ + ret + +_remapped_cold_boot: + /* + * The previous boot stage seems to use the L2 cache as TCM. + * Disable the TCM redirect before enabling caches to avoid + * strange crashes. + */ + mov x2, #APCS_CFG + ldr w3, [x2, #APCS_TCM_START_ADDR] + and w3, w3, #~APCS_TCM_REDIRECT_EN_0 + str w3, [x2, #APCS_TCM_START_ADDR] + + /* Enter BL31 again at the real address */ + br x0 +endfunc plat_reset_handler + + /* ------------------------------------------------- + * void platform_mem_init(void) + * Performs additional memory initialization early + * in the boot process. + * ------------------------------------------------- + */ +func platform_mem_init + /* Nothing to do here, all memory is already initialized */ + ret +endfunc platform_mem_init + + .data + .align 3 + + /* ------------------------------------------------- + * Warm boot entry point for CPU. Set by PSCI code. + * ------------------------------------------------- + */ +msm8916_entry_point: + .quad 0 diff --git a/plat/qti/msm8916/aarch64/uartdm_console.S b/plat/qti/msm8916/aarch64/uartdm_console.S new file mode 100644 index 0000000..c69c193 --- /dev/null +++ b/plat/qti/msm8916/aarch64/uartdm_console.S @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * Based on aarch64/skeleton_console.S: + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +/* UART DM registers */ +#define UART_DM_DMEN 0x03c /* DMA / data packing */ +#define UART_DM_SR 0x0a4 /* status register */ +#define UART_DM_CR 0x0a8 /* command register */ +#define UART_DM_TF 0x100 /* transmit FIFO */ + +#define UART_DM_DMEN_TX_SC BIT_32(4) /* TX single character mode */ + +#define UART_DM_SR_TXRDY_BIT 2 /* TX FIFO has space */ +#define UART_DM_SR_TXEMT_BIT 3 /* TX FIFO is empty */ + +#define UART_DM_CR_RESET_RX (U(0x01) << 4) /* reset receiver */ +#define UART_DM_CR_RESET_TX (U(0x02) << 4) /* reset transmitter */ +#define UART_DM_CR_TX_ENABLE BIT_32(2) /* enable transmitter */ + + .globl console_uartdm_register + .globl console_uartdm_core_init + .globl console_uartdm_putc + .globl console_uartdm_core_putc + .globl console_uartdm_flush + .globl console_uartdm_core_flush + + /* ----------------------------------------------------------- + * int console_uartdm_register(console_t *console, + * uintptr_t base_addr) + * Function to initialize and register the console. The caller + * needs to pass an empty console_t structure in which *MUST* + * be allocated in persistent memory (e.g. a global or static + * local variable, *NOT* on the stack). + * In : x0 - pointer to empty console_t structure + * x1 - base address + * Out: x0 - 1 on success, 0 on error + * Clobber list : x0 - x7 + * ----------------------------------------------------------- + */ +func console_uartdm_register + str x1, [x0, #CONSOLE_T_BASE] + mov x7, lr + bl console_uartdm_core_init + mov lr, x7 + + /* Register the new console */ + finish_console_register uartdm putc=1, flush=1 +endfunc console_uartdm_register + + /* ----------------------------------------------------------- + * void console_uartdm_core_init(unused, uintptr_t base_addr) + * Function to initialize the console. + * In : x0 - unused + * x1 - base address + * Out: void + * Clobber list : x1, x2, x3 + * ----------------------------------------------------------- + */ +func console_uartdm_core_init + /* Reset receiver */ + mov w3, #UART_DM_CR_RESET_RX + str w3, [x1, #UART_DM_CR] + + /* Reset transmitter */ + mov w3, #UART_DM_CR_RESET_TX + str w3, [x1, #UART_DM_CR] + + /* + * Disable BAM/DMA modes but enable single-character mode for TX. + * The single character mode allows simplifying the putc implementation + * since characters can be written directly to the FIFO instead of + * having to initiate a new transfer and waiting for its completion. + */ + mov w3, #UART_DM_DMEN_TX_SC + str w3, [x1, #UART_DM_DMEN] + + /* Enable transmitter */ + mov w3, #UART_DM_CR_TX_ENABLE + str w3, [x1, #UART_DM_CR] + + ret +endfunc console_uartdm_core_init + + /* ----------------------------------------------------------- + * int console_uartdm_putc(int c, console_t *console) + * Function to output a character over the console. + * In : w0 - character to be printed + * x1 - pointer to console_t struct + * Out: w0 - printed character on success, < 0 on error. + * Clobber list : x0, x1, x2 + * ----------------------------------------------------------- + */ +func console_uartdm_putc + ldr x1, [x1, #CONSOLE_T_BASE] + b console_uartdm_core_putc +endfunc console_uartdm_putc + + /* ----------------------------------------------------------- + * int console_uartdm_core_putc(int c, uintptr_t base_addr) + * Function to output a character over the console. + * In : w0 - character to be printed + * x1 - base address + * Out: w0 - printed character on success, < 0 on error. + * Clobber list : x2 + * ----------------------------------------------------------- + */ +func console_uartdm_core_putc +1: /* Loop until TX FIFO has space */ + ldr w2, [x1, #UART_DM_SR] + tbz w2, #UART_DM_SR_TXRDY_BIT, 1b + + /* Write character to FIFO */ + str w0, [x1, #UART_DM_TF] + ret +endfunc console_uartdm_core_putc + + /* ----------------------------------------------------------- + * void console_uartdm_flush(console_t *console) + * Function to force a write of all buffered data + * that has not been output. + * In : x0 - pointer to console_t struct + * Out: void + * Clobber list : x0, x1, x2, x3, x4, x5 + * ----------------------------------------------------------- + */ +func console_uartdm_flush + ldr x1, [x0, #CONSOLE_T_BASE] + b console_uartdm_core_flush +endfunc console_uartdm_flush + + /* ----------------------------------------------------------- + * void console_uartdm_core_flush(unused, uintptr_t base_addr) + * Function to force a write of all buffered data + * that has not been output. + * In : x0 - unused + * x1 - base address + * Out: void + * Clobber list : x2 + * ----------------------------------------------------------- + */ +func console_uartdm_core_flush +1: /* Loop until TX FIFO is empty */ + ldr w2, [x1, #UART_DM_SR] + tbz w2, #UART_DM_SR_TXEMT_BIT, 1b + ret +endfunc console_uartdm_core_flush diff --git a/plat/qti/msm8916/include/msm8916_mmap.h b/plat/qti/msm8916/include/msm8916_mmap.h new file mode 100644 index 0000000..406ae6b --- /dev/null +++ b/plat/qti/msm8916/include/msm8916_mmap.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_MMAP_H +#define MSM8916_MMAP_H + +#define PCNOC_BASE 0x00000000 +#define PCNOC_SIZE 0x8000000 /* 128 MiB */ +#define APCS_BASE 0x0b000000 +#define APCS_SIZE 0x800000 /* 8 MiB */ + +#define MPM_BASE (PCNOC_BASE + 0x04a0000) +#define MPM_PS_HOLD (MPM_BASE + 0xb000) + +#define TLMM_BASE (PCNOC_BASE + 0x1000000) +#define TLMM_GPIO_CFG(n) (TLMM_BASE + ((n) * 0x1000)) + +#define GCC_BASE (PCNOC_BASE + 0x1800000) + +#define APPS_SMMU_BASE (PCNOC_BASE + 0x1e00000) +#define APPS_SMMU_QCOM (APPS_SMMU_BASE + 0xf0000) + +#define BLSP_UART1_BASE (PCNOC_BASE + 0x78af000) +#define BLSP_UART2_BASE (PCNOC_BASE + 0x78b0000) + +#define APCS_QGIC2_BASE (APCS_BASE + 0x00000) +#define APCS_QGIC2_GICD (APCS_QGIC2_BASE + 0x0000) +#define APCS_QGIC2_GICC (APCS_QGIC2_BASE + 0x2000) +#define APCS_BANKED_ACS (APCS_BASE + 0x08000) +#define APCS_BANKED_SAW2 (APCS_BASE + 0x09000) +#define APCS_CFG (APCS_BASE + 0x10000) +#define APCS_GLB (APCS_BASE + 0x11000) +#define APCS_L2_SAW2 (APCS_BASE + 0x12000) +#define APCS_QTMR (APCS_BASE + 0x20000) +#define APCS_ALIAS_ACS(cpu) (APCS_BASE + 0x88000 + ((cpu) * 0x10000)) +#define APCS_ALIAS_SAW2(cpu) (APCS_BASE + 0x89000 + ((cpu) * 0x10000)) + +#endif /* MSM8916_MMAP_H */ diff --git a/plat/qti/msm8916/include/plat_macros.S b/plat/qti/msm8916/include/plat_macros.S new file mode 100644 index 0000000..552add2 --- /dev/null +++ b/plat/qti/msm8916/include/plat_macros.S @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_MACROS_S +#define PLAT_MACROS_S + +#include + +#include + + /* --------------------------------------------- + * The below required platform porting macro + * prints out relevant GIC registers whenever + * an unhandled exception is taken in BL31. + * Clobbers: x0 - x10, x16, x17, sp + * --------------------------------------------- + */ + .macro plat_crash_print_regs + mov_imm x16, APCS_QGIC2_GICD + mov_imm x17, APCS_QGIC2_GICC + arm_print_gic_regs + .endm + +#endif /* PLAT_MACROS_S */ diff --git a/plat/qti/msm8916/include/platform_def.h b/plat/qti/msm8916/include/platform_def.h new file mode 100644 index 0000000..bfade70 --- /dev/null +++ b/plat/qti/msm8916/include/platform_def.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include + +/* + * There is at least 1 MiB available for BL31. However, at the moment the + * "msm8916_entry_point" variable in the data section is read through the + * 64 KiB region of the "boot remapper" after reset. For simplicity, limit + * the end of the data section (BL31_PROGBITS_LIMIT) to 64 KiB for now and + * the overall limit to 128 KiB. This could be increased if needed by placing + * the "msm8916_entry_point" variable explicitly in the first 64 KiB of BL31. + */ +#define BL31_LIMIT (BL31_BASE + 0x20000) /* 128 KiB */ +#define BL31_PROGBITS_LIMIT (BL31_BASE + 0x10000) /* 64 KiB */ + +#define CACHE_WRITEBACK_GRANULE U(64) +#define PLATFORM_STACK_SIZE U(0x1000) + +/* CPU topology: single cluster with 4 cores */ +#define PLATFORM_CLUSTER_COUNT U(1) +#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) +#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \ + PLATFORM_MAX_CPUS_PER_CLUSTER) + +/* Power management */ +#define PLATFORM_SYSTEM_COUNT U(1) +#define PLAT_NUM_PWR_DOMAINS (PLATFORM_SYSTEM_COUNT + \ + PLATFORM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) +#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 +#define PLAT_MAX_RET_STATE U(2) +#define PLAT_MAX_OFF_STATE U(3) + +/* Translation tables */ +#define MAX_MMAP_REGIONS 8 +#define MAX_XLAT_TABLES 4 + +#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) +#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) + +/* Timer frequency */ +#define PLAT_SYSCNT_FREQ 19200000 + +/* + * The Qualcomm QGIC2 implementation seems to have PIDR0-4 and PIDR4-7 + * erroneously swapped for some reason. PIDR2 is actually at 0xFD8. + * Override the address in to avoid a failing assert(). + */ +#define GICD_PIDR2_GICV2 U(0xFD8) + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/qti/msm8916/include/uartdm_console.h b/plat/qti/msm8916/include/uartdm_console.h new file mode 100644 index 0000000..0f09ba8 --- /dev/null +++ b/plat/qti/msm8916/include/uartdm_console.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef UARTDM_CONSOLE_H +#define UARTDM_CONSOLE_H + +int console_uartdm_register(console_t *console, uintptr_t base_addr); + +#endif /* UARTDM_CONSOLE_H */ diff --git a/plat/qti/msm8916/msm8916_bl31_setup.c b/plat/qti/msm8916/msm8916_bl31_setup.c new file mode 100644 index 0000000..638cd09 --- /dev/null +++ b/plat/qti/msm8916/msm8916_bl31_setup.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm8916_gicv2.h" +#include +#include +#include + +static const mmap_region_t msm8916_mmap[] = { + MAP_REGION_FLAT(PCNOC_BASE, PCNOC_SIZE, + MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER), + MAP_REGION_FLAT(APCS_BASE, APCS_SIZE, + MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER), + {}, +}; + +static struct { + entry_point_info_t bl32; + entry_point_info_t bl33; +} image_ep_info = { + /* BL32 entry point */ + SET_STATIC_PARAM_HEAD(bl32, PARAM_EP, VERSION_1, + entry_point_info_t, SECURE), + .bl32.pc = BL32_BASE, + + /* BL33 entry point */ + SET_STATIC_PARAM_HEAD(bl33, PARAM_EP, VERSION_1, + entry_point_info_t, NON_SECURE), + .bl33.pc = PRELOADED_BL33_BASE, + .bl33.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), +}; + +static console_t console; + +unsigned int plat_get_syscnt_freq2(void) +{ + return PLAT_SYSCNT_FREQ; +} + +#define CLK_ENABLE BIT_32(0) +#define CLK_OFF BIT_32(31) + +#define GPIO_BLSP_UART2_TX 4 +#define GPIO_BLSP_UART2_RX 5 +#define GPIO_CFG_FUNC_BLSP_UART2 (U(0x2) << 2) +#define GPIO_CFG_DRV_STRENGTH_16MA (U(0x7) << 6) + +#define GCC_BLSP1_AHB_CBCR (GCC_BASE + 0x01008) +#define GCC_BLSP1_UART2_APPS_CBCR (GCC_BASE + 0x0302c) +#define GCC_APCS_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x45004) +#define BLSP1_AHB_CLK_ENA BIT_32(10) + +/* + * The previous boot stage seems to disable most of the UART setup before exit + * so it must be enabled here again before the UART console can be used. + */ +static void msm8916_enable_blsp_uart2(void) +{ + /* Route GPIOs to BLSP UART2 */ + mmio_write_32(TLMM_GPIO_CFG(GPIO_BLSP_UART2_TX), + GPIO_CFG_FUNC_BLSP_UART2 | GPIO_CFG_DRV_STRENGTH_16MA); + mmio_write_32(TLMM_GPIO_CFG(GPIO_BLSP_UART2_RX), + GPIO_CFG_FUNC_BLSP_UART2 | GPIO_CFG_DRV_STRENGTH_16MA); + + /* Enable AHB clock */ + mmio_setbits_32(GCC_APCS_CLOCK_BRANCH_ENA_VOTE, BLSP1_AHB_CLK_ENA); + while (mmio_read_32(GCC_BLSP1_AHB_CBCR) & CLK_OFF) + ; + + /* Enable BLSP UART2 clock */ + mmio_setbits_32(GCC_BLSP1_UART2_APPS_CBCR, CLK_ENABLE); + while (mmio_read_32(GCC_BLSP1_UART2_APPS_CBCR) & CLK_OFF) + ; +} + +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + /* Initialize the debug console as early as possible */ + msm8916_enable_blsp_uart2(); + console_uartdm_register(&console, BLSP_UART2_BASE); +} + +void bl31_plat_arch_setup(void) +{ + mmap_add_region(BL31_BASE, BL31_BASE, BL31_END - BL31_BASE, + MT_RW_DATA | MT_SECURE); + mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, + BL_CODE_END - BL_CODE_BASE, + MT_CODE | MT_SECURE); + mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE, + BL_RO_DATA_END - BL_RO_DATA_BASE, + MT_RO_DATA | MT_SECURE); + mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE, + BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, + MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER); + + mmap_add(msm8916_mmap); + init_xlat_tables(); + enable_mmu_el3(0); +} + +static void msm8916_configure_timer(void) +{ + /* Set timer frequency */ + mmio_write_32(APCS_QTMR + CNTCTLBASE_CNTFRQ, plat_get_syscnt_freq2()); + + /* Make frame 0 available to non-secure world */ + mmio_write_32(APCS_QTMR + CNTNSAR, BIT_32(CNTNSAR_NS_SHIFT(0))); + mmio_write_32(APCS_QTMR + CNTACR_BASE(0), + BIT_32(CNTACR_RPCT_SHIFT) | BIT_32(CNTACR_RVCT_SHIFT) | + BIT_32(CNTACR_RFRQ_SHIFT) | BIT_32(CNTACR_RVOFF_SHIFT) | + BIT_32(CNTACR_RWVT_SHIFT) | BIT_32(CNTACR_RWPT_SHIFT)); +} + +/* + * The APCS register regions always start with a SECURE register that should + * be cleared to 0 to only allow secure access. Since BL31 handles most of + * the CPU power management, most of them can be cleared to secure access only. + */ +#define APCS_GLB_SECURE_STS_NS BIT_32(0) +#define APCS_GLB_SECURE_PWR_NS BIT_32(1) +#define APCS_BOOT_START_ADDR_SEC (APCS_CFG + 0x04) +#define REMAP_EN BIT_32(0) +#define APCS_AA64NAA32_REG (APCS_CFG + 0x0c) + +static void msm8916_configure_cpu_pm(void) +{ + unsigned int cpu; + + /* Disallow non-secure access to boot remapper / TCM registers */ + mmio_write_32(APCS_CFG, 0); + + /* + * Disallow non-secure access to power management registers. + * However, allow STS and PWR since those also seem to control access + * to CPU frequency related registers (e.g. APCS_CMD_RCGR). If these + * bits are not set, CPU frequency control fails in the non-secure world. + */ + mmio_write_32(APCS_GLB, APCS_GLB_SECURE_STS_NS | APCS_GLB_SECURE_PWR_NS); + + /* Disallow non-secure access to L2 SAW2 */ + mmio_write_32(APCS_L2_SAW2, 0); + + /* Disallow non-secure access to CPU ACS and SAW2 */ + for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { + mmio_write_32(APCS_ALIAS_ACS(cpu), 0); + mmio_write_32(APCS_ALIAS_SAW2(cpu), 0); + } + + /* Make sure all further warm boots end up in BL31 and aarch64 state */ + CASSERT((BL31_BASE & 0xffff) == 0, assert_bl31_base_64k_aligned); + mmio_write_32(APCS_BOOT_START_ADDR_SEC, BL31_BASE | REMAP_EN); + mmio_write_32(APCS_AA64NAA32_REG, 1); +} + +/* + * MSM8916 has a special "interrupt aggregation logic" in the APPS SMMU, + * which allows routing context bank interrupts to one of 3 interrupt numbers + * ("TZ/HYP/NS"). Route all interrupts to the non-secure interrupt number + * by default to avoid special setup on the non-secure side. + */ +#define GCC_SMMU_CFG_CBCR (GCC_BASE + 0x12038) +#define GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x4500c) +#define SMMU_CFG_CLK_ENA BIT_32(12) +#define APPS_SMMU_INTR_SEL_NS (APPS_SMMU_QCOM + 0x2000) +#define APPS_SMMU_INTR_SEL_NS_EN_ALL U(0xffffffff) + +static void msm8916_configure_smmu(void) +{ + /* Enable SMMU configuration clock to enable register access */ + mmio_setbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA); + while (mmio_read_32(GCC_SMMU_CFG_CBCR) & CLK_OFF) + ; + + /* Route all context bank interrupts to non-secure interrupt */ + mmio_write_32(APPS_SMMU_INTR_SEL_NS, APPS_SMMU_INTR_SEL_NS_EN_ALL); + + /* Disable configuration clock again */ + mmio_clrbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA); +} + +void bl31_platform_setup(void) +{ + INFO("BL31: Platform setup start\n"); + generic_delay_timer_init(); + msm8916_configure_timer(); + msm8916_gicv2_init(); + msm8916_configure_cpu_pm(); + msm8916_configure_smmu(); + INFO("BL31: Platform setup done\n"); +} + +entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) +{ + switch (type) { + case SECURE: + return &image_ep_info.bl32; + case NON_SECURE: + return &image_ep_info.bl33; + default: + assert(sec_state_is_valid(type)); + return NULL; + } +} diff --git a/plat/qti/msm8916/msm8916_cpu_boot.c b/plat/qti/msm8916/msm8916_cpu_boot.c new file mode 100644 index 0000000..b3f51f6 --- /dev/null +++ b/plat/qti/msm8916/msm8916_cpu_boot.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include "msm8916_pm.h" + +#define CPU_PWR_CTL 0x4 +#define APC_PWR_GATE_CTL 0x14 + +#define CPU_PWR_CTL_CLAMP BIT_32(0) +#define CPU_PWR_CTL_CORE_MEM_CLAMP BIT_32(1) +#define CPU_PWR_CTL_L1_RST_DIS BIT_32(2) +#define CPU_PWR_CTL_CORE_MEM_HS BIT_32(3) +#define CPU_PWR_CTL_CORE_RST BIT_32(4) +#define CPU_PWR_CTL_COREPOR_RST BIT_32(5) +#define CPU_PWR_CTL_GATE_CLK BIT_32(6) +#define CPU_PWR_CTL_CORE_PWRD_UP BIT_32(7) + +#define APC_PWR_GATE_CTL_GHDS_EN BIT_32(0) +#define APC_PWR_GATE_CTL_GHDS_CNT(cnt) ((cnt) << 24) + +/* Boot a secondary CPU core for the first time. */ +void msm8916_cpu_boot(unsigned int core) +{ + uintptr_t acs = APCS_ALIAS_ACS(core); + uint32_t pwr_ctl; + + pwr_ctl = CPU_PWR_CTL_CLAMP | CPU_PWR_CTL_CORE_MEM_CLAMP | + CPU_PWR_CTL_CORE_RST | CPU_PWR_CTL_COREPOR_RST; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + + mmio_write_32(acs + APC_PWR_GATE_CTL, APC_PWR_GATE_CTL_GHDS_EN | + APC_PWR_GATE_CTL_GHDS_CNT(16)); + dsb(); + udelay(2); + + pwr_ctl &= ~CPU_PWR_CTL_CORE_MEM_CLAMP; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + + pwr_ctl |= CPU_PWR_CTL_CORE_MEM_HS; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + udelay(2); + + pwr_ctl &= ~CPU_PWR_CTL_CLAMP; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + udelay(2); + + pwr_ctl &= ~(CPU_PWR_CTL_CORE_RST | CPU_PWR_CTL_COREPOR_RST); + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + + pwr_ctl |= CPU_PWR_CTL_CORE_PWRD_UP; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); +} diff --git a/plat/qti/msm8916/msm8916_gicv2.c b/plat/qti/msm8916/msm8916_gicv2.c new file mode 100644 index 0000000..25a6628 --- /dev/null +++ b/plat/qti/msm8916/msm8916_gicv2.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include "msm8916_gicv2.h" +#include + +#define IRQ_SEC_SGI_0 8 +#define IRQ_SEC_SGI_1 9 +#define IRQ_SEC_SGI_2 10 +#define IRQ_SEC_SGI_3 11 +#define IRQ_SEC_SGI_4 12 +#define IRQ_SEC_SGI_5 13 +#define IRQ_SEC_SGI_6 14 +#define IRQ_SEC_SGI_7 15 + +#define IRQ_SEC_PHY_TIMER (16 + 2) /* PPI #2 */ + +static const interrupt_prop_t msm8916_interrupt_props[] = { + INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), +}; + +static const gicv2_driver_data_t msm8916_gic_data = { + .gicd_base = APCS_QGIC2_GICD, + .gicc_base = APCS_QGIC2_GICC, + .interrupt_props = msm8916_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(msm8916_interrupt_props), +}; + +void msm8916_gicv2_init(void) +{ + gicv2_driver_init(&msm8916_gic_data); + gicv2_distif_init(); + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} diff --git a/plat/qti/msm8916/msm8916_gicv2.h b/plat/qti/msm8916/msm8916_gicv2.h new file mode 100644 index 0000000..99db0d3 --- /dev/null +++ b/plat/qti/msm8916/msm8916_gicv2.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_GICV2_H +#define MSM8916_GICV2_H + +void msm8916_gicv2_init(void); + +#endif /* MSM8916_GICV2_H */ diff --git a/plat/qti/msm8916/msm8916_pm.c b/plat/qti/msm8916/msm8916_pm.c new file mode 100644 index 0000000..6891e38 --- /dev/null +++ b/plat/qti/msm8916/msm8916_pm.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "msm8916_pm.h" + +static int msm8916_pwr_domain_on(u_register_t mpidr) +{ + unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); + + VERBOSE("PSCI: Booting CPU %d\n", core); + msm8916_cpu_boot(core); + + return PSCI_E_SUCCESS; +} + +static void msm8916_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} + +static void __dead2 msm8916_system_reset(void) +{ + mmio_write_32(MPM_PS_HOLD, 0); + mdelay(1000); + + ERROR("PSCI: System reset failed\n"); + panic(); +} + +static const plat_psci_ops_t msm8916_psci_ops = { + .pwr_domain_on = msm8916_pwr_domain_on, + .pwr_domain_on_finish = msm8916_pwr_domain_on_finish, + .system_off = msm8916_system_reset, + .system_reset = msm8916_system_reset, +}; + +/* Defined and used in msm8916_helpers.S */ +extern uintptr_t msm8916_entry_point; + +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + msm8916_entry_point = sec_entrypoint; + *psci_ops = &msm8916_psci_ops; + return 0; +} diff --git a/plat/qti/msm8916/msm8916_pm.h b/plat/qti/msm8916/msm8916_pm.h new file mode 100644 index 0000000..5473bfa --- /dev/null +++ b/plat/qti/msm8916/msm8916_pm.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_PM_H +#define MSM8916_PM_H + +void msm8916_cpu_boot(unsigned int core); + +#endif /* MSM8916_PM_H */ diff --git a/plat/qti/msm8916/msm8916_topology.c b/plat/qti/msm8916/msm8916_topology.c new file mode 100644 index 0000000..4d0ed8f --- /dev/null +++ b/plat/qti/msm8916/msm8916_topology.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +static const unsigned char plat_power_domain_tree_desc[PLAT_MAX_PWR_LVL + 1] = { + PLATFORM_SYSTEM_COUNT, + PLATFORM_CLUSTER_COUNT, + PLATFORM_MAX_CPUS_PER_CLUSTER, +}; + +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); + + if (MPIDR_AFFLVL3_VAL(mpidr) > 0 || + MPIDR_AFFLVL2_VAL(mpidr) > 0 || + MPIDR_AFFLVL1_VAL(mpidr) > 0 || + core >= PLATFORM_MAX_CPUS_PER_CLUSTER) { + return -1; + } + + return core; +} + +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + return plat_power_domain_tree_desc; +} diff --git a/plat/qti/msm8916/platform.mk b/plat/qti/msm8916/platform.mk new file mode 100644 index 0000000..e516cea --- /dev/null +++ b/plat/qti/msm8916/platform.mk @@ -0,0 +1,62 @@ +# +# Copyright (c) 2021, Stephan Gerhold +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include drivers/arm/gic/v2/gicv2.mk +include lib/xlat_tables_v2/xlat_tables.mk + +PLAT_BL_COMMON_SOURCES := ${XLAT_TABLES_LIB_SRCS} + +PLAT_INCLUDES := -Iinclude/plat/arm/common/${ARCH} \ + -Iplat/qti/msm8916/include + +BL31_SOURCES += ${GICV2_SOURCES} \ + drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ + lib/cpus/${ARCH}/cortex_a53.S \ + plat/common/plat_gicv2.c \ + plat/common/plat_psci_common.c \ + plat/qti/msm8916/msm8916_bl31_setup.c \ + plat/qti/msm8916/msm8916_cpu_boot.c \ + plat/qti/msm8916/msm8916_gicv2.c \ + plat/qti/msm8916/msm8916_pm.c \ + plat/qti/msm8916/msm8916_topology.c \ + plat/qti/msm8916/${ARCH}/msm8916_helpers.S \ + plat/qti/msm8916/${ARCH}/uartdm_console.S + +# Only BL31 is supported at the moment and is entered on a single CPU +RESET_TO_BL31 := 1 +COLD_BOOT_SINGLE_CPU := 1 + +# Build config flags +# ------------------ +BL31_BASE ?= 0x86500000 +BL32_BASE ?= 0x86000000 +PRELOADED_BL33_BASE ?= 0x8f600000 + +# Have different sections for code and rodata +SEPARATE_CODE_AND_RODATA := 1 + +# Single cluster +WARMBOOT_ENABLE_DCACHE_EARLY := 1 + +# Disable features unsupported in ARMv8.0 +ENABLE_AMU := 0 +ENABLE_SPE_FOR_LOWER_ELS := 0 +ENABLE_SVE_FOR_NS := 0 + +# MSM8916 uses ARM Cortex-A53 r0p0 so likely all the errata apply +ERRATA_A53_819472 := 1 +ERRATA_A53_824069 := 1 +ERRATA_A53_826319 := 1 +ERRATA_A53_827319 := 1 +ERRATA_A53_835769 := 1 +ERRATA_A53_836870 := 1 +ERRATA_A53_843419 := 1 +ERRATA_A53_855873 := 0 # Workaround works only for >= r0p3 +ERRATA_A53_1530924 := 1 + +$(eval $(call add_define,BL31_BASE)) +$(eval $(call add_define,BL32_BASE)) diff --git a/plat/qti/qtiseclib/inc/qtiseclib_cb_interface.h b/plat/qti/qtiseclib/inc/qtiseclib_cb_interface.h new file mode 100644 index 0000000..deef41c --- /dev/null +++ b/plat/qti/qtiseclib/inc/qtiseclib_cb_interface.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef QTISECLIB_CB_INTERFACE_H +#define QTISECLIB_CB_INTERFACE_H + +#include +#include +#include +#include + +#include + +/* Standard Library API's */ +void *qtiseclib_cb_memcpy(void *dst, const void *src, size_t len); +int qtiseclib_cb_strcmp(const char *s1, const char *s2); +void *qtiseclib_cb_memset(void *s, int c, size_t n); +void *qtiseclib_cb_memmove(void *dest, const void *src, size_t n); + +#define QTISECLIB_CB_ERROR(...) qtiseclib_cb_log(QTISECLIB_LOG_LEVEL_ERROR, __VA_ARGS__) +#define QTISECLIB_CB_NOTICE(...) qtiseclib_cb_log(QTISECLIB_LOG_LEVEL_NOTICE, __VA_ARGS__) +#define QTISECLIB_CB_WARN(...) qtiseclib_cb_log(QTISECLIB_LOG_LEVEL_WARNING, __VA_ARGS__) +#define QTISECLIB_CB_INFO(...) qtiseclib_cb_log(QTISECLIB_LOG_LEVEL_INFO, __VA_ARGS__) + +void qtiseclib_cb_log(unsigned int loglvl, const char *fmt, ...); + +void qtiseclib_cb_spin_lock(qtiseclib_cb_spinlock_t *lock); +void qtiseclib_cb_spin_unlock(qtiseclib_cb_spinlock_t *lock); + +unsigned int qtiseclib_cb_plat_my_core_pos(void); +int qtiseclib_cb_plat_core_pos_by_mpidr(u_register_t mpidr); +unsigned int qtiseclib_cb_plat_my_cluster_pos(void); + +/* GIC platform wrappers */ +void qtiseclib_cb_gic_pcpu_init(void); +void qtiseclib_cb_ic_raise_sgi(int sgi_num, u_register_t target); +void qtiseclib_cb_set_spi_routing(unsigned int id, unsigned int irm, + u_register_t target); +/* Crash reporting api's wrappers */ +void qtiseclib_cb_switch_console_to_crash_state(void); + +void qtiseclib_cb_udelay(uint32_t usec); + +void qtiseclib_cb_console_flush(void); + +#if QTI_SDI_BUILD +int qtiseclib_cb_mmap_remove_dynamic_region(uintptr_t base_va, size_t size); +int qtiseclib_cb_mmap_add_dynamic_region(unsigned long long base_pa, + size_t size, + qtiseclib_mmap_attr_t attr); + +void qtiseclib_cb_flush_dcache_all(void); +void qtiseclib_cb_get_ns_ctx(qtiseclib_dbg_a64_ctxt_regs_type *ns_ctx); +#endif + +#endif /* QTISECLIB_CB_INTERFACE_H */ diff --git a/plat/qti/qtiseclib/inc/qtiseclib_defs.h b/plat/qti/qtiseclib/inc/qtiseclib_defs.h new file mode 100644 index 0000000..2afefe1 --- /dev/null +++ b/plat/qti/qtiseclib/inc/qtiseclib_defs.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef QTISECLIB_DEFS_H +#define QTISECLIB_DEFS_H + +#include + +#ifndef u_register_t +typedef uintptr_t u_register_t; +#endif + +/* + * Different Log Level supported in qtiseclib. + * TODO: Currently no filtering done on QTISECLIB logs. + */ +#define QTISECLIB_LOG_LEVEL_NONE 0 +#define QTISECLIB_LOG_LEVEL_ERROR 10 +#define QTISECLIB_LOG_LEVEL_NOTICE 20 +#define QTISECLIB_LOG_LEVEL_WARNING 30 +#define QTISECLIB_LOG_LEVEL_INFO 40 +#define QTISECLIB_LOG_LEVEL_VERBOSE 50 + +#define QTI_GICV3_IRM_PE 0 +#define QTI_GICV3_IRM_ANY 1 + +/* Common interrupt number/ID defs. */ +#define QTISECLIB_INT_ID_RESET_SGI (0xf) +#define QTISECLIB_INT_ID_CPU_WAKEUP_SGI (0x8) + +#define QTISECLIB_INT_INVALID_INT_NUM (0xFFFFFFFFU) + +typedef struct qtiseclib_cb_spinlock { + volatile uint32_t lock; +} qtiseclib_cb_spinlock_t; + +#if QTI_SDI_BUILD +/* External CPU Dump Structure - 64 bit EL */ +typedef struct { + uint64_t x0; + uint64_t x1; + uint64_t x2; + uint64_t x3; + uint64_t x4; + uint64_t x5; + uint64_t x6; + uint64_t x7; + uint64_t x8; + uint64_t x9; + uint64_t x10; + uint64_t x11; + uint64_t x12; + uint64_t x13; + uint64_t x14; + uint64_t x15; + uint64_t x16; + uint64_t x17; + uint64_t x18; + uint64_t x19; + uint64_t x20; + uint64_t x21; + uint64_t x22; + uint64_t x23; + uint64_t x24; + uint64_t x25; + uint64_t x26; + uint64_t x27; + uint64_t x28; + uint64_t x29; + uint64_t x30; + uint64_t pc; + uint64_t currentEL; + uint64_t sp_el3; + uint64_t elr_el3; + uint64_t spsr_el3; + uint64_t sp_el2; + uint64_t elr_el2; + uint64_t spsr_el2; + uint64_t sp_el1; + uint64_t elr_el1; + uint64_t spsr_el1; + uint64_t sp_el0; + uint64_t __reserved1; + uint64_t __reserved2; + uint64_t __reserved3; + uint64_t __reserved4; + uint64_t __reserved5; + uint64_t __reserved6; + uint64_t __reserved7; + uint64_t __reserved8; +} qtiseclib_dbg_a64_ctxt_regs_type; + +typedef enum qtiseclib_mmap_attr_s { + QTISECLIB_MAP_NS_RO_XN_DATA = 1, + QTISECLIB_MAP_RW_XN_NC_DATA = 2, + QTISECLIB_MAP_RW_XN_DATA = 3, +} qtiseclib_mmap_attr_t; + +#endif /* QTI_SDI_BUILD */ + +#endif /* QTISECLIB_DEFS_H */ diff --git a/plat/qti/qtiseclib/inc/qtiseclib_interface.h b/plat/qti/qtiseclib/inc/qtiseclib_interface.h new file mode 100644 index 0000000..babed1b --- /dev/null +++ b/plat/qti/qtiseclib/inc/qtiseclib_interface.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef QTISECLIB_INTERFACE_H +#define QTISECLIB_INTERFACE_H + +#include +#include + +#include + +typedef struct memprot_ipa_info_s { + uint64_t mem_addr; + uint64_t mem_size; +} memprot_info_t; + +typedef struct memprot_dst_vm_perm_info_s { + uint32_t dst_vm; + uint32_t dst_vm_perm; + uint64_t ctx; + uint32_t ctx_size; +} memprot_dst_vm_perm_info_t; + +/* + * QTISECLIB Published API's. + */ + +/* + * Assembly API's + */ + +/* + * CPUSS common reset handler for all CPU wake up (both cold & warm boot). + * Executes on all core. This API assume serialization across CPU + * already taken care before invoking. + * + * Clobbers: x0 - x17, x30 + */ +void qtiseclib_cpuss_reset_asm(uint32_t bl31_cold_boot_state); + +/* + * Execute CPU (Kryo4 gold) specific reset handler / system initialization. + * This takes care of executing required CPU errata's. + * + * Clobbers: x0 - x16 + */ +void qtiseclib_kryo4_gold_reset_asm(void); + +/* + * Execute CPU (Kryo46 gold) specific reset handler / system initialization. + * This takes care of executing required CPU errata's. + * + * Clobbers: x0 - x16 + */ +void qtiseclib_kryo6_gold_reset_asm(void); + +/* + * Execute CPU (Kryo4 silver) specific reset handler / system initialization. + * This takes care of executing required CPU errata's. + * + * Clobbers: x0 - x16 + */ +void qtiseclib_kryo4_silver_reset_asm(void); + +/* + * Execute CPU (Kryo6 silver) specific reset handler / system initialization. + * This takes care of executing required CPU errata's. + * + * Clobbers: x0 - x16 + */ +void qtiseclib_kryo6_silver_reset_asm(void); + +/* + * C Api's + */ +void qtiseclib_bl31_platform_setup(void); +void qtiseclib_invoke_isr(uint32_t irq, void *handle); +void qtiseclib_panic(void); + +int qtiseclib_mem_assign(const memprot_info_t *mem_info, + uint32_t mem_info_list_cnt, + const uint32_t *source_vm_list, + uint32_t src_vm_list_cnt, + const memprot_dst_vm_perm_info_t *dest_vm_list, + uint32_t dst_vm_list_cnt); + +int qtiseclib_psci_init(uintptr_t warmboot_entry); +int qtiseclib_psci_node_power_on(u_register_t mpidr); +void qtiseclib_psci_node_on_finish(const uint8_t *states); +void qtiseclib_psci_cpu_standby(uint8_t pwr_state); +void qtiseclib_psci_node_power_off(const uint8_t *states); +void qtiseclib_psci_node_suspend(const uint8_t *states); +void qtiseclib_psci_node_suspend_finish(const uint8_t *states); +void qtiseclib_disable_cluster_coherency(uint8_t state); + +#endif /* QTISECLIB_INTERFACE_H */ diff --git a/plat/qti/qtiseclib/inc/sc7180/qtiseclib_defs_plat.h b/plat/qti/qtiseclib/inc/sc7180/qtiseclib_defs_plat.h new file mode 100644 index 0000000..3ecee20 --- /dev/null +++ b/plat/qti/qtiseclib/inc/sc7180/qtiseclib_defs_plat.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef QTISECLIB_DEFS_PLAT_H +#define QTISECLIB_DEFS_PLAT_H + +#define QTISECLIB_PLAT_CLUSTER_COUNT 1 +#define QTISECLIB_PLAT_CORE_COUNT 8 + +#define BL31_BASE 0x80b00000 +#define BL31_SIZE 0x00100000 + +/* Chipset specific secure interrupt number/ID defs. */ +#define QTISECLIB_INT_ID_SEC_WDOG_BARK (0x204) +#define QTISECLIB_INT_ID_NON_SEC_WDOG_BITE (0x21) + +#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC (0xE6) +#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC (0xE7) +#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC (0xE8) +#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_NONSEC (0xE9) + +#define QTISECLIB_INT_ID_XPU_SEC (0xE3) +#define QTISECLIB_INT_ID_XPU_NON_SEC (0xE4) + +#define QTISECLIB_INT_ID_A2_NOC_ERROR (0x194) +#define QTISECLIB_INT_ID_CONFIG_NOC_ERROR (0xE2) +#define QTISECLIB_INT_ID_DC_NOC_ERROR (0x122) +#define QTISECLIB_INT_ID_MEM_NOC_ERROR (0x6C) +#define QTISECLIB_INT_ID_SYSTEM_NOC_ERROR (0xC6) +#define QTISECLIB_INT_ID_MMSS_NOC_ERROR (0xBA) + +#endif /* QTISECLIB_DEFS_PLAT_H */ diff --git a/plat/qti/qtiseclib/inc/sc7280/qtiseclib_defs_plat.h b/plat/qti/qtiseclib/inc/sc7280/qtiseclib_defs_plat.h new file mode 100644 index 0000000..b3d309f --- /dev/null +++ b/plat/qti/qtiseclib/inc/sc7280/qtiseclib_defs_plat.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __QTISECLIB_DEFS_PLAT_H__ +#define __QTISECLIB_DEFS_PLAT_H__ + +#define QTISECLIB_PLAT_CLUSTER_COUNT 1 +#define QTISECLIB_PLAT_CORE_COUNT 8 + +#define BL31_BASE 0xC0000000 +#define BL31_SIZE 0x00100000 + +/*----------------------------------------------------------------------------*/ +/* AOP CMD DB address space for mapping */ +/*----------------------------------------------------------------------------*/ +#define QTI_AOP_CMD_DB_BASE 0x80860000 +#define QTI_AOP_CMD_DB_SIZE 0x00020000 + +/* Chipset specific secure interrupt number/ID defs. */ +#define QTISECLIB_INT_ID_SEC_WDOG_BARK (0x204) +#define QTISECLIB_INT_ID_NON_SEC_WDOG_BITE (0x21) + +#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC (0xE6) +#define QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC (0xE7) +#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC (0xE8) +#define QTISECLIB_INT_ID_VMIDMT_ERR_CFG_NONSEC (0xE9) + +#define QTISECLIB_INT_ID_XPU_SEC (0xE3) +#define QTISECLIB_INT_ID_XPU_NON_SEC (0xE4) + +//NOC INterrupt +#define QTISECLIB_INT_ID_A1_NOC_ERROR (0xC9) +#define QTISECLIB_INT_ID_A2_NOC_ERROR (0xEA) +#define QTISECLIB_INT_ID_CONFIG_NOC_ERROR (0xE2) +#define QTISECLIB_INT_ID_DC_NOC_ERROR (0x122) +#define QTISECLIB_INT_ID_MEM_NOC_ERROR (0x6C) +#define QTISECLIB_INT_ID_SYSTEM_NOC_ERROR (0xC8) +#define QTISECLIB_INT_ID_MMSS_NOC_ERROR (0xBA) +#define QTISECLIB_INT_ID_LPASS_AGNOC_ERROR (0x143) +#define QTISECLIB_INT_ID_NSP_NOC_ERROR (0x1CE) + +#endif /* __QTISECLIB_DEFS_PLAT_H__ */ diff --git a/plat/qti/qtiseclib/src/qtiseclib_cb_interface.c b/plat/qti/qtiseclib/src/qtiseclib_cb_interface.c new file mode 100644 index 0000000..c4cd259 --- /dev/null +++ b/plat/qti/qtiseclib/src/qtiseclib_cb_interface.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +void *qtiseclib_cb_memcpy(void *dst, const void *src, size_t len) +{ + return memcpy(dst, src, len); +} + +int qtiseclib_cb_strcmp(const char *s1, const char *s2) +{ + return strcmp(s1, s2); +} + +void *qtiseclib_cb_memset(void *s, int c, size_t n) +{ + return memset(s, c, n); +} + +void *qtiseclib_cb_memmove(void *dest, const void *src, size_t n) +{ + return memmove(dest, src, n); +} + +/* Printing logs below or equal LOG_LEVEL from QTISECLIB. */ +void qtiseclib_cb_log(unsigned int loglvl, const char *fmt, ...) +{ + if (loglvl <= LOG_LEVEL) { + va_list argp; + static spinlock_t qti_log_lock; + uint64_t uptime = read_cntpct_el0(); + + va_start(argp, fmt); + + spin_lock(&qti_log_lock); + printf("QTISECLIB [%x%08x]", + (uint32_t) ((uptime >> 32) & 0xFFFFFFFF), + (uint32_t) (uptime & 0xFFFFFFFF)); + vprintf(fmt, argp); + putchar('\n'); + spin_unlock(&qti_log_lock); + + va_end(argp); + } +} + +void qtiseclib_cb_spin_lock(qtiseclib_cb_spinlock_t *lock) +{ + spin_lock((spinlock_t *) lock); +} + +void qtiseclib_cb_spin_unlock(qtiseclib_cb_spinlock_t *lock) +{ + spin_unlock((spinlock_t *) lock); +} + +unsigned int qtiseclib_cb_plat_my_core_pos(void) +{ + return plat_my_core_pos(); +} + +int qtiseclib_cb_plat_core_pos_by_mpidr(u_register_t mpidr) +{ + return plat_core_pos_by_mpidr(mpidr); +} + +unsigned int qtiseclib_cb_plat_my_cluster_pos(void) +{ + return plat_qti_my_cluster_pos(); +} + +/* GIC platform functions */ +void qtiseclib_cb_gic_pcpu_init(void) +{ + plat_qti_gic_pcpu_init(); +} + +void qtiseclib_cb_ic_raise_sgi(int sgi_num, u_register_t target) +{ + plat_ic_raise_el3_sgi(sgi_num, target); +} + +void qtiseclib_cb_set_spi_routing(unsigned int id, unsigned int irm, + u_register_t target) +{ + assert(QTI_GICV3_IRM_PE == GICV3_IRM_PE); + assert(QTI_GICV3_IRM_ANY == GICV3_IRM_ANY); + gic_set_spi_routing(id, irm, target); +} + +/* Crash reporting api's wrappers */ +void qtiseclib_cb_switch_console_to_crash_state(void) +{ + console_switch_state(CONSOLE_FLAG_CRASH); +} + +void qtiseclib_cb_udelay(uint32_t usec) +{ + udelay(usec); +} + +void qtiseclib_cb_console_flush(void) +{ + return console_flush(); +} + +#if QTI_SDI_BUILD +void qtiseclib_cb_get_ns_ctx(qtiseclib_dbg_a64_ctxt_regs_type *qti_ns_ctx) +{ + void *ctx; + + ctx = cm_get_context(NON_SECURE); + if (ctx) { + /* nothing to be done w/o ns context */ + return; + } + + qti_ns_ctx->spsr_el3 = + read_ctx_reg(get_el3state_ctx(ctx), CTX_SPSR_EL3); + qti_ns_ctx->elr_el3 = read_ctx_reg(get_el3state_ctx(ctx), CTX_ELR_EL3); + + qti_ns_ctx->spsr_el1 = + read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SPSR_EL1); + qti_ns_ctx->elr_el1 = + read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_ELR_EL1); + qti_ns_ctx->sp_el1 = read_ctx_reg(get_el1_sysregs_ctx(ctx), CTX_SP_EL1); + + qti_ns_ctx->x0 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X0); + qti_ns_ctx->x1 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X1); + qti_ns_ctx->x2 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X2); + qti_ns_ctx->x3 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X3); + qti_ns_ctx->x4 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X4); + qti_ns_ctx->x5 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X5); + qti_ns_ctx->x6 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X6); + qti_ns_ctx->x7 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X7); + qti_ns_ctx->x8 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X8); + qti_ns_ctx->x9 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X9); + qti_ns_ctx->x10 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X10); + qti_ns_ctx->x11 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X11); + qti_ns_ctx->x12 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X12); + qti_ns_ctx->x13 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X13); + qti_ns_ctx->x14 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X14); + qti_ns_ctx->x15 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X15); + qti_ns_ctx->x16 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X16); + qti_ns_ctx->x17 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X17); + qti_ns_ctx->x18 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X18); + qti_ns_ctx->x19 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X19); + qti_ns_ctx->x20 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X20); + qti_ns_ctx->x21 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X21); + qti_ns_ctx->x22 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X22); + qti_ns_ctx->x23 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X23); + qti_ns_ctx->x24 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X24); + qti_ns_ctx->x25 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X25); + qti_ns_ctx->x26 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X26); + qti_ns_ctx->x27 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X27); + qti_ns_ctx->x28 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X28); + qti_ns_ctx->x29 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X29); + qti_ns_ctx->x30 = read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_LR); + qti_ns_ctx->sp_el0 = + read_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_SP_EL0); +} + +void qtiseclib_cb_flush_dcache_all(void) +{ + dcsw_op_all(DCCISW); +} + +int qtiseclib_cb_mmap_add_dynamic_region(unsigned long long base_pa, + size_t size, + qtiseclib_mmap_attr_t attr) +{ + unsigned int l_attr = 0; + + if (attr == QTISECLIB_MAP_NS_RO_XN_DATA) { + l_attr = MT_NS | MT_RO | MT_EXECUTE_NEVER; + } else if (attr == QTISECLIB_MAP_RW_XN_NC_DATA) { + l_attr = MT_RW | MT_NON_CACHEABLE | MT_EXECUTE_NEVER; + } else if (attr == QTISECLIB_MAP_RW_XN_DATA) { + l_attr = MT_RW | MT_EXECUTE_NEVER; + } + return qti_mmap_add_dynamic_region(base_pa, size, l_attr); +} + +int qtiseclib_cb_mmap_remove_dynamic_region(uintptr_t base_va, size_t size) +{ + return qti_mmap_remove_dynamic_region(base_va, size); +} +#endif + diff --git a/plat/qti/qtiseclib/src/qtiseclib_interface_stub.c b/plat/qti/qtiseclib/src/qtiseclib_interface_stub.c new file mode 100644 index 0000000..cdaa0a7 --- /dev/null +++ b/plat/qti/qtiseclib/src/qtiseclib_interface_stub.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +#include +#include + +/* + * This file contains dummy implementation of QTISECLIB Published API's. + * which will be used to compile PLATFORM successfully when + * qtiseclib is not available + */ + +/* + * CPUSS common reset handler for all CPU wake up (both cold & warm boot). + * Executes on all core. This API assume serialization across CPU + * already taken care before invoking. + * + * Clobbers: x0 - x17, x30 + */ +void qtiseclib_cpuss_reset_asm(uint32_t bl31_cold_boot_state) +{ +} + +/* + * Execute CPU (Kryo4 gold) specific reset handler / system initialization. + * This takes care of executing required CPU errata's. + * + * Clobbers: x0 - x16 + */ +void qtiseclib_kryo4_gold_reset_asm(void) +{ +} + +/* + * Execute CPU (Kryo4 silver) specific reset handler / system initialization. + * This takes care of executing required CPU errata's. + * + * Clobbers: x0 - x16 + */ +void qtiseclib_kryo4_silver_reset_asm(void) +{ +} + +/* + * Execute CPU (Kryo4 gold) specific reset handler / system initialization. + * This takes care of executing required CPU errata's. + * + * Clobbers: x0 - x16 + */ +void qtiseclib_kryo6_gold_reset_asm(void) +{ +} + + +void qtiseclib_kryo6_silver_reset_asm(void) +{ +} + +/* + * C Api's + */ +void qtiseclib_bl31_platform_setup(void) +{ + ERROR("Please use QTISECLIB_PATH while building TF-A\n"); + ERROR("Please refer docs/plat/qti.rst for more details.\n"); + panic(); +} + +void qtiseclib_invoke_isr(uint32_t irq, void *handle) +{ +} + +void qtiseclib_panic(void) +{ +} + +int +qtiseclib_mem_assign(const memprot_info_t *mem_info, + uint32_t mem_info_list_cnt, + const uint32_t *source_vm_list, + uint32_t src_vm_list_cnt, + const memprot_dst_vm_perm_info_t *dest_vm_list, + uint32_t dst_vm_list_cnt) +{ + return 0; +} + +int qtiseclib_psci_init(uintptr_t warmboot_entry) +{ + return 0; +} + +int qtiseclib_psci_node_power_on(u_register_t mpidr) +{ + return 0; +} + +void qtiseclib_psci_node_on_finish(const uint8_t *states) +{ +} + +void qtiseclib_psci_cpu_standby(uint8_t pwr_state) +{ +} + +void qtiseclib_psci_node_power_off(const uint8_t *states) +{ +} + +void qtiseclib_psci_node_suspend(const uint8_t *states) +{ +} + +void qtiseclib_psci_node_suspend_finish(const uint8_t *states) +{ +} + +void qtiseclib_disable_cluster_coherency(uint8_t state) +{ +} + diff --git a/plat/qti/sc7180/inc/platform_def.h b/plat/qti/sc7180/inc/platform_def.h new file mode 100644 index 0000000..b69dfd9 --- /dev/null +++ b/plat/qti/sc7180/inc/platform_def.h @@ -0,0 +1,198 @@ +/* + * 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 + */ +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +/* Enable the dynamic translation tables library. */ +#define PLAT_XLAT_TABLES_DYNAMIC 1 + +#include + +#include +#include + +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/* + * MPIDR_PRIMARY_CPU + * You just need to have the correct core_affinity_val i.e. [7:0] + * and cluster_affinity_val i.e. [15:8] + * the other bits will be ignored + */ +/*----------------------------------------------------------------------------*/ +#define MPIDR_PRIMARY_CPU 0x0000 +/*----------------------------------------------------------------------------*/ + +#define QTI_PWR_LVL0 MPIDR_AFFLVL0 +#define QTI_PWR_LVL1 MPIDR_AFFLVL1 +#define QTI_PWR_LVL2 MPIDR_AFFLVL2 +#define QTI_PWR_LVL3 MPIDR_AFFLVL3 + +/* + * Macros for local power states encoded by State-ID field + * within the power-state parameter. + */ +/* Local power state for power domains in Run state. */ +#define QTI_LOCAL_STATE_RUN 0 +/* + * Local power state for clock-gating. Valid only for CPU and not cluster power + * domains + */ +#define QTI_LOCAL_STATE_STB 1 +/* + * Local power state for retention. Valid for CPU and cluster power + * domains + */ +#define QTI_LOCAL_STATE_RET 2 +/* + * Local power state for OFF/power down. Valid for CPU, cluster, RSC and PDC + * power domains + */ +#define QTI_LOCAL_STATE_OFF 3 +/* + * Local power state for DEEPOFF/power rail down. Valid for CPU, cluster and RSC + * power domains + */ +#define QTI_LOCAL_STATE_DEEPOFF 4 + +/* + * This macro defines the deepest retention state possible. A higher state + * id will represent an invalid or a power down state. + */ +#define PLAT_MAX_RET_STATE QTI_LOCAL_STATE_RET + +/* + * This macro defines the deepest power down states possible. Any state ID + * higher than this is invalid. + */ +#define PLAT_MAX_OFF_STATE QTI_LOCAL_STATE_DEEPOFF + +/****************************************************************************** + * Required platform porting definitions common to all ARM standard platforms + *****************************************************************************/ + +/* + * Platform specific page table and MMU setup constants. + */ +#define MAX_MMAP_REGIONS (PLAT_QTI_MMAP_ENTRIES) + +#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 36) +#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 36) + +#define ARM_CACHE_WRITEBACK_SHIFT 6 + +/* + * Some data must be aligned on the biggest cache line size in the platform. + * This is known only to the platform as it might have a combination of + * integrated and external caches. + */ +#define CACHE_WRITEBACK_GRANULE (1 << ARM_CACHE_WRITEBACK_SHIFT) + +/* + * One cache line needed for bakery locks on ARM platforms + */ +#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE) + +/*----------------------------------------------------------------------------*/ +/* PSCI power domain topology definitions */ +/*----------------------------------------------------------------------------*/ +/* One domain each to represent RSC and PDC level */ +#define PLAT_PDC_COUNT 1 +#define PLAT_RSC_COUNT 1 + +/* There is one top-level FCM cluster */ +#define PLAT_CLUSTER_COUNT 1 + +/* No. of cores in the FCM cluster */ +#define PLAT_CLUSTER0_CORE_COUNT 8 + +#define PLATFORM_CORE_COUNT (PLAT_CLUSTER0_CORE_COUNT) + +#define PLAT_NUM_PWR_DOMAINS (PLAT_PDC_COUNT +\ + PLAT_RSC_COUNT +\ + PLAT_CLUSTER_COUNT +\ + PLATFORM_CORE_COUNT) + +#define PLAT_MAX_PWR_LVL 3 + +/*****************************************************************************/ +/* Memory mapped Generic timer interfaces */ +/*****************************************************************************/ + +/*----------------------------------------------------------------------------*/ +/* GIC-600 constants */ +/*----------------------------------------------------------------------------*/ +#define BASE_GICD_BASE 0x17A00000 +#define BASE_GICR_BASE 0x17A60000 +#define BASE_GICC_BASE 0x0 +#define BASE_GICH_BASE 0x0 +#define BASE_GICV_BASE 0x0 + +#define QTI_GICD_BASE BASE_GICD_BASE +#define QTI_GICR_BASE BASE_GICR_BASE +#define QTI_GICC_BASE BASE_GICC_BASE + +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/* UART related constants. */ +/*----------------------------------------------------------------------------*/ +/* BASE ADDRESS OF DIFFERENT REGISTER SPACES IN HW */ +#define GENI4_CFG 0x0 +#define GENI4_IMAGE_REGS 0x100 +#define GENI4_DATA 0x600 + +/* COMMON STATUS/CONFIGURATION REGISTERS AND MASKS */ +#define GENI_STATUS_REG (GENI4_CFG + 0x00000040) +#define GENI_STATUS_M_GENI_CMD_ACTIVE_MASK (0x1) +#define UART_TX_TRANS_LEN_REG (GENI4_IMAGE_REGS + 0x00000170) +/* MASTER/TX ENGINE REGISTERS */ +#define GENI_M_CMD0_REG (GENI4_DATA + 0x00000000) +/* FIFO, STATUS REGISTERS AND MASKS */ +#define GENI_TX_FIFOn_REG (GENI4_DATA + 0x00000100) + +#define GENI_M_CMD_TX (0x08000000) + +/*----------------------------------------------------------------------------*/ +/* Device address space for mapping. Excluding starting 4K */ +/*----------------------------------------------------------------------------*/ +#define QTI_DEVICE_BASE 0x1000 +#define QTI_DEVICE_SIZE (0x80000000 - QTI_DEVICE_BASE) + +/******************************************************************************* + * BL31 specific defines. + ******************************************************************************/ +/* + * Put BL31 at DDR as per memory map. BL31_BASE is calculated using the + * current BL31 debug size plus a little space for growth. + */ +#define BL31_LIMIT (BL31_BASE + BL31_SIZE) + +/*----------------------------------------------------------------------------*/ +/* AOSS registers */ +/*----------------------------------------------------------------------------*/ +#define QTI_PS_HOLD_REG 0x0C264000 +/*----------------------------------------------------------------------------*/ +/* AOP CMD DB address space for mapping */ +/*----------------------------------------------------------------------------*/ +#define QTI_AOP_CMD_DB_BASE 0x80820000 +#define QTI_AOP_CMD_DB_SIZE 0x00020000 +/*----------------------------------------------------------------------------*/ +/* SOC hw version register */ +/*----------------------------------------------------------------------------*/ +#define QTI_SOC_VERSION_MASK U(0xFFFF) +#define QTI_SOC_REVISION_REG 0x1FC8000 +#define QTI_SOC_REVISION_MASK U(0xFFFF) +/*----------------------------------------------------------------------------*/ +/* LC PON register offsets */ +/*----------------------------------------------------------------------------*/ +#define PON_PS_HOLD_RESET_CTL 0x85a +#define PON_PS_HOLD_RESET_CTL2 0x85b +/*----------------------------------------------------------------------------*/ + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/qti/sc7180/inc/qti_map_chipinfo.h b/plat/qti/sc7180/inc/qti_map_chipinfo.h new file mode 100644 index 0000000..4ab6191 --- /dev/null +++ b/plat/qti/sc7180/inc/qti_map_chipinfo.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef QTI_MAP_CHIPINFO_H +#define QTI_MAP_CHIPINFO_H + +#include + +#include + +#define QTI_JTAG_ID_REG 0x786130 +#define QTI_SOC_VERSION_MASK U(0xFFFF) +#define QTI_SOC_REVISION_REG 0x1FC8000 +#define QTI_SOC_REVISION_MASK U(0xFFFF) +#define QTI_JTAG_ID_SHIFT 12 +#define QTI_JTAG_ID_SC7180 U(0x012C) +#define QTI_JTAG_ID_SC7180P U(0x0195) +#define QTI_CHIPINFO_ID_SC7180 U(0x01A9) +#define QTI_CHIPINFO_ID_SC7180P U(0x01EF) +#define QTI_DEFAULT_CHIPINFO_ID U(0xFFFF) + +static const chip_id_info_t g_map_jtag_chipinfo_id[] = { + {QTI_JTAG_ID_SC7180, QTI_CHIPINFO_ID_SC7180}, + {QTI_JTAG_ID_SC7180P, QTI_CHIPINFO_ID_SC7180P}, +}; +#endif /* QTI_MAP_CHIPINFO_H */ diff --git a/plat/qti/sc7180/inc/qti_rng_io.h b/plat/qti/sc7180/inc/qti_rng_io.h new file mode 100644 index 0000000..f50234f --- /dev/null +++ b/plat/qti/sc7180/inc/qti_rng_io.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef QTI_RNG_IO_H +#define QTI_RNG_IO_H + +#define SEC_PRNG_STATUS 0x00791004 +#define SEC_PRNG_STATUS_DATA_AVAIL_BMSK 0x1 +#define SEC_PRNG_DATA_OUT 0x00791000 + + +#endif /* QTI_RNG_IO_H */ + diff --git a/plat/qti/sc7180/inc/qti_secure_io_cfg.h b/plat/qti/sc7180/inc/qti_secure_io_cfg.h new file mode 100644 index 0000000..3de636d --- /dev/null +++ b/plat/qti/sc7180/inc/qti_secure_io_cfg.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef QTI_SECURE_IO_CFG_H +#define QTI_SECURE_IO_CFG_H + +#include + +/* + * List of peripheral/IO memory areas that are protected from + * non-secure world but not required to be secure. + */ + +#define APPS_SMMU_TBU_PWR_STATUS 0x15002204 +#define APPS_SMMU_CUSTOM_CFG 0x15002300 +#define APPS_SMMU_STATS_SYNC_INV_TBU_ACK 0x150025DC +#define APPS_SMMU_SAFE_SEC_CFG 0x15002648 +#define APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR 0x15002670 + +static const uintptr_t qti_secure_io_allowed_regs[] = { + APPS_SMMU_TBU_PWR_STATUS, + APPS_SMMU_CUSTOM_CFG, + APPS_SMMU_STATS_SYNC_INV_TBU_ACK, + APPS_SMMU_SAFE_SEC_CFG, + APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR, +}; + +#endif /* QTI_SECURE_IO_CFG_H */ diff --git a/plat/qti/sc7180/platform.mk b/plat/qti/sc7180/platform.mk new file mode 100644 index 0000000..41a08ca --- /dev/null +++ b/plat/qti/sc7180/platform.mk @@ -0,0 +1,128 @@ +# +# 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 +# + +# Make for SC7180 QTI platform. + +QTI_PLAT_PATH := plat/qti +CHIPSET := ${PLAT} + +# Turn On Separate code & data. +SEPARATE_CODE_AND_RODATA := 1 +USE_COHERENT_MEM := 0 +WARMBOOT_ENABLE_DCACHE_EARLY := 1 +HW_ASSISTED_COHERENCY := 1 + +# Disable the PSCI platform compatibility layer +ENABLE_PLAT_COMPAT := 0 + +#Enable errata for cortex_a55 and cortex_a76 +ERRATA_A55_1530923 := 1 +ERRATA_A76_1165522 := 1 + +# Enable PSCI v1.0 extended state ID format +PSCI_EXTENDED_STATE_ID := 1 +ARM_RECOM_STATE_ID_ENC := 1 + +COLD_BOOT_SINGLE_CPU := 1 +PROGRAMMABLE_RESET_ADDRESS := 1 + +RESET_TO_BL31 := 0 + +MULTI_CONSOLE_API := 1 + +QTI_SDI_BUILD := 0 +$(eval $(call assert_boolean,QTI_SDI_BUILD)) +$(eval $(call add_define,QTI_SDI_BUILD)) + +#disable CTX_INCLUDE_AARCH32_REGS to support sc7180 gold cores +override CTX_INCLUDE_AARCH32_REGS := 0 +WORKAROUND_CVE_2017_5715 := 0 +DYNAMIC_WORKAROUND_CVE_2018_3639 := 1 +# Enable stack protector. +ENABLE_STACK_PROTECTOR := strong + + +QTI_EXTERNAL_INCLUDES := -I${QTI_PLAT_PATH}/${CHIPSET}/inc \ + -I${QTI_PLAT_PATH}/common/inc \ + -I${QTI_PLAT_PATH}/common/inc/$(ARCH) \ + -I${QTI_PLAT_PATH}/qtiseclib/inc \ + -I${QTI_PLAT_PATH}/qtiseclib/inc/${CHIPSET} \ + +QTI_BL31_SOURCES := $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_helpers.S \ + $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo4_silver.S \ + $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo4_gold.S \ + $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_uart_console.S \ + $(QTI_PLAT_PATH)/common/src/pm_ps_hold.c \ + $(QTI_PLAT_PATH)/common/src/qti_stack_protector.c \ + $(QTI_PLAT_PATH)/common/src/qti_common.c \ + $(QTI_PLAT_PATH)/common/src/qti_bl31_setup.c \ + $(QTI_PLAT_PATH)/common/src/qti_gic_v3.c \ + $(QTI_PLAT_PATH)/common/src/qti_interrupt_svc.c \ + $(QTI_PLAT_PATH)/common/src/qti_syscall.c \ + $(QTI_PLAT_PATH)/common/src/qti_topology.c \ + $(QTI_PLAT_PATH)/common/src/qti_pm.c \ + $(QTI_PLAT_PATH)/common/src/qti_rng.c \ + $(QTI_PLAT_PATH)/common/src/spmi_arb.c \ + $(QTI_PLAT_PATH)/qtiseclib/src/qtiseclib_cb_interface.c \ + + +PLAT_INCLUDES := -Iinclude/plat/common/ \ + +PLAT_INCLUDES += ${QTI_EXTERNAL_INCLUDES} + +include lib/xlat_tables_v2/xlat_tables.mk +PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} \ + plat/common/aarch64/crash_console_helpers.S \ + common/desc_image_load.c \ + lib/bl_aux_params/bl_aux_params.c \ + +include lib/coreboot/coreboot.mk + +#PSCI Sources. +PSCI_SOURCES := plat/common/plat_psci_common.c \ + +# GIC-600 configuration +GICV3_SUPPORT_GIC600 := 1 +# Include GICv3 driver files +include drivers/arm/gic/v3/gicv3.mk + +#Timer sources +TIMER_SOURCES := drivers/delay_timer/generic_delay_timer.c \ + drivers/delay_timer/delay_timer.c \ + +#GIC sources. +GIC_SOURCES := plat/common/plat_gicv3.c \ + ${GICV3_SOURCES} \ + +CPU_SOURCES := lib/cpus/aarch64/cortex_a76.S \ + lib/cpus/aarch64/cortex_a55.S \ + +BL31_SOURCES += ${QTI_BL31_SOURCES} \ + ${PSCI_SOURCES} \ + ${GIC_SOURCES} \ + ${TIMER_SOURCES} \ + ${CPU_SOURCES} \ + +LIB_QTI_PATH := ${QTI_PLAT_PATH}/qtiseclib/lib/${CHIPSET} + + +# Override this on the command line to point to the qtiseclib library which +# will be available in coreboot.org +QTISECLIB_PATH ?= + +ifeq ($(QTISECLIB_PATH),) +# if No lib then use stub implementation for qtiseclib interface +$(warning QTISECLIB_PATH is not provided while building, using stub implementation. \ + Please refer docs/plat/qti.rst for more details \ + THIS FIRMWARE WILL NOT BOOT!) +BL31_SOURCES += plat/qti/qtiseclib/src/qtiseclib_interface_stub.c +else +# use library provided by QTISECLIB_PATH +LDFLAGS += -L $(dir $(QTISECLIB_PATH)) +LDLIBS += -l$(patsubst lib%.a,%,$(notdir $(QTISECLIB_PATH))) +endif + diff --git a/plat/qti/sc7280/inc/platform_def.h b/plat/qti/sc7280/inc/platform_def.h new file mode 100644 index 0000000..48b48ac --- /dev/null +++ b/plat/qti/sc7280/inc/platform_def.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +/* Enable the dynamic translation tables library. */ +#define PLAT_XLAT_TABLES_DYNAMIC 1 + +#include + +#include +#include + +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/* + * MPIDR_PRIMARY_CPU + * You just need to have the correct core_affinity_val i.e. [7:0] + * and cluster_affinity_val i.e. [15:8] + * the other bits will be ignored + */ +/*----------------------------------------------------------------------------*/ +#define MPIDR_PRIMARY_CPU 0x0000 +/*----------------------------------------------------------------------------*/ + +#define QTI_PWR_LVL0 MPIDR_AFFLVL0 +#define QTI_PWR_LVL1 MPIDR_AFFLVL1 +#define QTI_PWR_LVL2 MPIDR_AFFLVL2 +#define QTI_PWR_LVL3 MPIDR_AFFLVL3 + +/* + * Macros for local power states encoded by State-ID field + * within the power-state parameter. + */ +/* Local power state for power domains in Run state. */ +#define QTI_LOCAL_STATE_RUN 0 +/* + * Local power state for clock-gating. Valid only for CPU and not cluster power + * domains + */ +#define QTI_LOCAL_STATE_STB 1 +/* + * Local power state for retention. Valid for CPU and cluster power + * domains + */ +#define QTI_LOCAL_STATE_RET 2 +/* + * Local power state for OFF/power down. Valid for CPU, cluster, RSC and PDC + * power domains + */ +#define QTI_LOCAL_STATE_OFF 3 +/* + * Local power state for DEEPOFF/power rail down. Valid for CPU, cluster and RSC + * power domains + */ +#define QTI_LOCAL_STATE_DEEPOFF 4 + +/* + * This macro defines the deepest retention state possible. A higher state + * id will represent an invalid or a power down state. + */ +#define PLAT_MAX_RET_STATE QTI_LOCAL_STATE_RET + +/* + * This macro defines the deepest power down states possible. Any state ID + * higher than this is invalid. + */ +#define PLAT_MAX_OFF_STATE QTI_LOCAL_STATE_DEEPOFF + +/****************************************************************************** + * Required platform porting definitions common to all ARM standard platforms + *****************************************************************************/ + +/* + * Platform specific page table and MMU setup constants. + */ +#define MAX_MMAP_REGIONS (PLAT_QTI_MMAP_ENTRIES) + +#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 36) +#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 36) + +#define ARM_CACHE_WRITEBACK_SHIFT 6 + +/* + * Some data must be aligned on the biggest cache line size in the platform. + * This is known only to the platform as it might have a combination of + * integrated and external caches. + */ +#define CACHE_WRITEBACK_GRANULE (1 << ARM_CACHE_WRITEBACK_SHIFT) + +/* + * One cache line needed for bakery locks on ARM platforms + */ +#define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE) + +/*----------------------------------------------------------------------------*/ +/* PSCI power domain topology definitions */ +/*----------------------------------------------------------------------------*/ +/* One domain each to represent RSC and PDC level */ +#define PLAT_PDC_COUNT 1 +#define PLAT_RSC_COUNT 1 + +/* There is one top-level FCM cluster */ +#define PLAT_CLUSTER_COUNT 1 + +/* No. of cores in the FCM cluster */ +#define PLAT_CLUSTER0_CORE_COUNT 8 + +#define PLATFORM_CORE_COUNT (PLAT_CLUSTER0_CORE_COUNT) + +#define PLAT_NUM_PWR_DOMAINS (PLAT_PDC_COUNT +\ + PLAT_RSC_COUNT +\ + PLAT_CLUSTER_COUNT +\ + PLATFORM_CORE_COUNT) + +#define PLAT_MAX_PWR_LVL 3 + +/*****************************************************************************/ +/* Memory mapped Generic timer interfaces */ +/*****************************************************************************/ + +/*----------------------------------------------------------------------------*/ +/* GIC-600 constants */ +/*----------------------------------------------------------------------------*/ +#define BASE_GICD_BASE 0x17A00000 +#define BASE_GICR_BASE 0x17A60000 +#define BASE_GICC_BASE 0x0 +#define BASE_GICH_BASE 0x0 +#define BASE_GICV_BASE 0x0 + +#define QTI_GICD_BASE BASE_GICD_BASE +#define QTI_GICR_BASE BASE_GICR_BASE +#define QTI_GICC_BASE BASE_GICC_BASE + +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/* UART related constants. */ +/*----------------------------------------------------------------------------*/ +/* BASE ADDRESS OF DIFFERENT REGISTER SPACES IN HW */ +#define GENI4_CFG 0x0 +#define GENI4_IMAGE_REGS 0x100 +#define GENI4_DATA 0x600 + +/* COMMON STATUS/CONFIGURATION REGISTERS AND MASKS */ +#define GENI_STATUS_REG (GENI4_CFG + 0x00000040) +#define GENI_STATUS_M_GENI_CMD_ACTIVE_MASK (0x1) +#define UART_TX_TRANS_LEN_REG (GENI4_IMAGE_REGS + 0x00000170) +/* MASTER/TX ENGINE REGISTERS */ +#define GENI_M_CMD0_REG (GENI4_DATA + 0x00000000) +/* FIFO, STATUS REGISTERS AND MASKS */ +#define GENI_TX_FIFOn_REG (GENI4_DATA + 0x00000100) + +#define GENI_M_CMD_TX (0x08000000) + +/*----------------------------------------------------------------------------*/ +/* Device address space for mapping. Excluding starting 4K */ +/*----------------------------------------------------------------------------*/ +#define QTI_DEVICE_BASE 0x1000 +#define QTI_DEVICE_SIZE (0x80000000 - QTI_DEVICE_BASE) + +/******************************************************************************* + * BL31 specific defines. + ******************************************************************************/ +/* + * Put BL31 at DDR as per memory map. BL31_BASE is calculated using the + * current BL31 debug size plus a little space for growth. + */ +#define BL31_LIMIT (BL31_BASE + BL31_SIZE) + +/*----------------------------------------------------------------------------*/ +/* AOSS registers */ +/*----------------------------------------------------------------------------*/ +#define QTI_PS_HOLD_REG 0x0C264000 +/*----------------------------------------------------------------------------*/ +/* AOP CMD DB address space for mapping */ +/*----------------------------------------------------------------------------*/ +#define QTI_AOP_CMD_DB_BASE 0x80860000 +#define QTI_AOP_CMD_DB_SIZE 0x00020000 +/*----------------------------------------------------------------------------*/ +/* SOC hw version register */ +/*----------------------------------------------------------------------------*/ +#define QTI_SOC_VERSION_MASK U(0xFFFF) +#define QTI_SOC_REVISION_REG 0x1FC8000 +#define QTI_SOC_REVISION_MASK U(0xFFFF) +/*----------------------------------------------------------------------------*/ +/* LC PON register offsets */ +/*----------------------------------------------------------------------------*/ +#define PON_PS_HOLD_RESET_CTL 0x852 +#define PON_PS_HOLD_RESET_CTL2 0x853 +/*----------------------------------------------------------------------------*/ + +#endif /* PLATFORM_DEF_H */ diff --git a/plat/qti/sc7280/inc/qti_map_chipinfo.h b/plat/qti/sc7280/inc/qti_map_chipinfo.h new file mode 100644 index 0000000..7303e20 --- /dev/null +++ b/plat/qti/sc7280/inc/qti_map_chipinfo.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef QTI_MAP_CHIPINFO_H +#define QTI_MAP_CHIPINFO_H + +#include + +#include + +#define QTI_JTAG_ID_REG 0x786130 +#define QTI_JTAG_ID_SHIFT 12 +#define QTI_JTAG_ID_SC7280 U(0x0193) +#define QTI_JTAG_ID_SC7280P U(0x01EB) +#define QTI_JTAG_ID_SC8270 U(0x01E3) +#define QTI_JTAG_ID_SC8270P U(0x020A) +#define QTI_JTAG_ID_SC7270P U(0x0215) +#define QTI_CHIPINFO_ID_SC7280 U(0x01E7) +#define QTI_CHIPINFO_ID_SC7280P U(0x0222) +#define QTI_CHIPINFO_ID_SC8270 U(0x0229) +#define QTI_CHIPINFO_ID_SC8270P U(0x0233) +#define QTI_CHIPINFO_ID_SC7270P U(0x0237) +#define QTI_DEFAULT_CHIPINFO_ID U(0xFFFF) + +static const chip_id_info_t g_map_jtag_chipinfo_id[] = { + {QTI_JTAG_ID_SC7280, QTI_CHIPINFO_ID_SC7280}, + {QTI_JTAG_ID_SC7280P, QTI_CHIPINFO_ID_SC7280P}, + {QTI_JTAG_ID_SC8270, QTI_CHIPINFO_ID_SC8270}, + {QTI_JTAG_ID_SC8270P, QTI_CHIPINFO_ID_SC8270P}, + {QTI_JTAG_ID_SC7270P, QTI_CHIPINFO_ID_SC7270P}, +}; +#endif /* QTI_MAP_CHIPINFO_H */ diff --git a/plat/qti/sc7280/inc/qti_rng_io.h b/plat/qti/sc7280/inc/qti_rng_io.h new file mode 100644 index 0000000..0f41fd6 --- /dev/null +++ b/plat/qti/sc7280/inc/qti_rng_io.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef QTI_RNG_IO_H +#define QTI_RNG_IO_H + +#define SEC_PRNG_STATUS 0x10D1004 +#define SEC_PRNG_STATUS_DATA_AVAIL_BMSK 0x1 +#define SEC_PRNG_DATA_OUT 0x10D1000 + + +#endif /* QTI_RNG_IO_H */ + diff --git a/plat/qti/sc7280/inc/qti_secure_io_cfg.h b/plat/qti/sc7280/inc/qti_secure_io_cfg.h new file mode 100644 index 0000000..058c5b5 --- /dev/null +++ b/plat/qti/sc7280/inc/qti_secure_io_cfg.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef QTI_SECURE_IO_CFG_H +#define QTI_SECURE_IO_CFG_H + +#include + +/* + * List of peripheral/IO memory areas that are protected from + * non-secure world but not required to be secure. + */ + +#define APPS_SMMU_TBU_PWR_STATUS 0x15002204 +#define APPS_SMMU_CUSTOM_CFG 0x15002300 +#define APPS_SMMU_STATS_SYNC_INV_TBU_ACK 0x150025DC +#define APPS_SMMU_SAFE_SEC_CFG 0x15002648 +#define APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR 0x15002670 + +static const uintptr_t qti_secure_io_allowed_regs[] = { + APPS_SMMU_TBU_PWR_STATUS, + APPS_SMMU_CUSTOM_CFG, + APPS_SMMU_STATS_SYNC_INV_TBU_ACK, + APPS_SMMU_SAFE_SEC_CFG, + APPS_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR, +}; + +#endif /* QTI_SECURE_IO_CFG_H */ diff --git a/plat/qti/sc7280/platform.mk b/plat/qti/sc7280/platform.mk new file mode 100644 index 0000000..df07bc4 --- /dev/null +++ b/plat/qti/sc7280/platform.mk @@ -0,0 +1,130 @@ +# +# Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved. +# Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# Make for SC7280 QTI platform. + +QTI_PLAT_PATH := plat/qti +CHIPSET := ${PLAT} + +# Turn On Separate code & data. +SEPARATE_CODE_AND_RODATA := 1 +USE_COHERENT_MEM := 0 +WARMBOOT_ENABLE_DCACHE_EARLY := 1 +HW_ASSISTED_COHERENCY := 1 + +#Enable errata configs for cortex_a78 and cortex_a55 +ERRATA_A55_1530923 := 1 +ERRATA_A78_1941498 := 1 +ERRATA_A78_1951500 := 1 +ERRATA_A78_2132060 := 1 + +# Disable the PSCI platform compatibility layer +ENABLE_PLAT_COMPAT := 0 + +# Enable PSCI v1.0 extended state ID format +PSCI_EXTENDED_STATE_ID := 1 +ARM_RECOM_STATE_ID_ENC := 1 + +COLD_BOOT_SINGLE_CPU := 1 +PROGRAMMABLE_RESET_ADDRESS := 1 + +RESET_TO_BL31 := 0 + +MULTI_CONSOLE_API := 1 + +QTI_SDI_BUILD := 0 +$(eval $(call assert_boolean,QTI_SDI_BUILD)) +$(eval $(call add_define,QTI_SDI_BUILD)) + +#disable CTX_INCLUDE_AARCH32_REGS to support sc7280 gold cores +override CTX_INCLUDE_AARCH32_REGS := 0 +WORKAROUND_CVE_2017_5715 := 0 +DYNAMIC_WORKAROUND_CVE_2018_3639 := 1 +# Enable stack protector. +ENABLE_STACK_PROTECTOR := strong + + +QTI_EXTERNAL_INCLUDES := -I${QTI_PLAT_PATH}/${CHIPSET}/inc \ + -I${QTI_PLAT_PATH}/common/inc \ + -I${QTI_PLAT_PATH}/common/inc/$(ARCH) \ + -I${QTI_PLAT_PATH}/qtiseclib/inc \ + -I${QTI_PLAT_PATH}/qtiseclib/inc/${CHIPSET} \ + +QTI_BL31_SOURCES := $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_helpers.S \ + $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo6_silver.S \ + $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_kryo6_gold.S \ + $(QTI_PLAT_PATH)/common/src/$(ARCH)/qti_uart_console.S \ + $(QTI_PLAT_PATH)/common/src/pm_ps_hold.c \ + $(QTI_PLAT_PATH)/common/src/qti_stack_protector.c \ + $(QTI_PLAT_PATH)/common/src/qti_common.c \ + $(QTI_PLAT_PATH)/common/src/qti_bl31_setup.c \ + $(QTI_PLAT_PATH)/common/src/qti_gic_v3.c \ + $(QTI_PLAT_PATH)/common/src/qti_interrupt_svc.c \ + $(QTI_PLAT_PATH)/common/src/qti_syscall.c \ + $(QTI_PLAT_PATH)/common/src/qti_topology.c \ + $(QTI_PLAT_PATH)/common/src/qti_pm.c \ + $(QTI_PLAT_PATH)/common/src/qti_rng.c \ + $(QTI_PLAT_PATH)/common/src/spmi_arb.c \ + $(QTI_PLAT_PATH)/qtiseclib/src/qtiseclib_cb_interface.c \ + + +PLAT_INCLUDES := -Iinclude/plat/common/ \ + +PLAT_INCLUDES += ${QTI_EXTERNAL_INCLUDES} + +include lib/xlat_tables_v2/xlat_tables.mk +PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} \ + plat/common/aarch64/crash_console_helpers.S \ + common/desc_image_load.c \ + lib/bl_aux_params/bl_aux_params.c \ + +include lib/coreboot/coreboot.mk + +#PSCI Sources. +PSCI_SOURCES := plat/common/plat_psci_common.c \ + +# GIC-600 configuration +GICV3_SUPPORT_GIC600 := 1 +# Include GICv3 driver files +include drivers/arm/gic/v3/gicv3.mk + +#Timer sources +TIMER_SOURCES := drivers/delay_timer/generic_delay_timer.c \ + drivers/delay_timer/delay_timer.c \ + +#GIC sources. +GIC_SOURCES := plat/common/plat_gicv3.c \ + ${GICV3_SOURCES} \ + +CPU_SOURCES := lib/cpus/aarch64/cortex_a78.S \ + lib/cpus/aarch64/cortex_a55.S \ + +BL31_SOURCES += ${QTI_BL31_SOURCES} \ + ${PSCI_SOURCES} \ + ${GIC_SOURCES} \ + ${TIMER_SOURCES} \ + ${CPU_SOURCES} \ + +LIB_QTI_PATH := ${QTI_PLAT_PATH}/qtiseclib/lib/${CHIPSET} + + +# Override this on the command line to point to the qtiseclib library which +# will be available in coreboot.org +QTISECLIB_PATH ?= + +ifeq ($(QTISECLIB_PATH),) +# if No lib then use stub implementation for qtiseclib interface +$(warning QTISECLIB_PATH is not provided while building, using stub implementation. \ + Please refer docs/plat/qti.rst for more details \ + THIS FIRMWARE WILL NOT BOOT!) +BL31_SOURCES += plat/qti/qtiseclib/src/qtiseclib_interface_stub.c +else +# use library provided by QTISECLIB_PATH +LDFLAGS += -L $(dir $(QTISECLIB_PATH)) +LDLIBS += -l$(patsubst lib%.a,%,$(notdir $(QTISECLIB_PATH))) +endif + -- cgit v1.2.3