diff options
Diffstat (limited to '')
73 files changed, 5706 insertions, 0 deletions
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 <drivers/arm/gic_common.h> +#include <drivers/arm/gicv2.h> +#include <drivers/arm/gicv3.h> + +#include <platform_def.h> + +.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 <stdint.h> + +#include <common/bl_common.h> +#include <lib/cassert.h> +#include <lib/el3_runtime/cpu_data.h> +#include <lib/xlat_tables/xlat_tables_v2.h> + +/* + * 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 <stdint.h> + +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 <drivers/console.h> + +#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 <stdint.h> + +/******************************************************************************* + * 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 <arch.h> +#include <asm_macros.S> +#include <drivers/arm/gicv2.h> +#include <drivers/arm/gicv3.h> +#include <drivers/console.h> + +#include <platform_def.h> + + .globl plat_my_core_pos + .globl plat_qti_core_pos_by_mpidr + .globl plat_reset_handler + .globl plat_panic_handler + + /* ----------------------------------------------------- + * unsigned int plat_qti_core_pos_by_mpidr(uint64_t mpidr) + * Helper function to calculate the core position. + * With this function: + * CorePos = (ClusterId * 4) + CoreId + * - In ARM v8 (MPIDR_EL1[24]=0) + * ClusterId = MPIDR_EL1[15:8] + * CoreId = MPIDR_EL1[7:0] + * - In ARM v8.1 (MPIDR_EL1[24]=1) + * ClusterId = MPIDR_EL1[23:15] + * CoreId = MPIDR_EL1[15:8] + * Clobbers: x0 & x1. + * ----------------------------------------------------- + */ +func plat_qti_core_pos_by_mpidr + mrs x1, mpidr_el1 + tst x1, #MPIDR_MT_MASK + beq plat_qti_core_pos_by_mpidr_no_mt + /* Right shift mpidr by one affinity level when MT=1. */ + lsr x0, x0, #MPIDR_AFFINITY_BITS +plat_qti_core_pos_by_mpidr_no_mt: + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #6 + ret +endfunc plat_qti_core_pos_by_mpidr + + /* -------------------------------------------------------------------- + * void plat_panic_handler(void) + * calls SDI and reset system + * -------------------------------------------------------------------- + */ +func plat_panic_handler + msr spsel, #0 + bl plat_set_my_stack + b qtiseclib_panic +endfunc plat_panic_handler + + /* ----------------------------------------------------- + * unsigned int plat_my_core_pos(void) + * This function uses the plat_qti_calc_core_pos() + * definition to get the index of the calling CPU + * Clobbers: x0 & x1. + * ----------------------------------------------------- + */ +func plat_my_core_pos + mrs x0, mpidr_el1 + b plat_qti_core_pos_by_mpidr +endfunc plat_my_core_pos + +func plat_reset_handler + /* save the lr */ + mov x18, x30 + + /* pass cold boot status. */ + ldr w0, g_qti_bl31_cold_booted + /* Execuete CPUSS boot set up on every core. */ + bl qtiseclib_cpuss_reset_asm + + ret x18 +endfunc plat_reset_handler 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 <arch.h> +#include <asm_macros.S> +#include <cpu_macros.S> + +#include <plat_macros.S> +#include <qti_cpu.h> + + .p2align 3 + +/* ------------------------------------------------- + * The CPU Ops reset function for Kryo-3 Gold + * ------------------------------------------------- + */ +func qti_kryo4_gold_reset_func +#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715 + adr x0, wa_cve_2017_5715_bpiall_vbar + msr vbar_el3, x0 + isb +#endif + + mov x19, x30 + + bl qtiseclib_kryo4_gold_reset_asm + mov x30, x19 + b cortex_a76_reset_func + +endfunc qti_kryo4_gold_reset_func + +/* ------------------------------------------------------- + * The CPU Ops cluster power down function for Kryo-3 Gold + * ------------------------------------------------------- + */ +func qti_kryo4_gold_cluster_pwr_dwn + ret +endfunc qti_kryo4_gold_cluster_pwr_dwn + +#if REPORT_ERRATA +/* + * Errata printing function for Kryo4 Gold. Must follow AAPCS. + */ +func qti_kryo4_gold_errata_report + /* TODO : Need to add support. Required only for debug bl31 image.*/ + ret +endfunc qti_kryo4_gold_errata_report +#endif + +/* --------------------------------------------- + * This function provides kryo4_gold specific + * register information for crash reporting. + * It needs to return with x6 pointing to + * a list of register names in ASCII and + * x8 - x15 having values of registers to be + * reported. + * --------------------------------------------- + */ +.section .rodata.qti_kryo4_gold_regs, "aS" +qti_kryo4_gold_regs: /* The ASCII list of register names to be reported */ + .asciz "" + +func qti_kryo4_gold_cpu_reg_dump + adr x6, qti_kryo4_gold_regs + ret +endfunc qti_kryo4_gold_cpu_reg_dump + +declare_cpu_ops_wa qti_kryo4_gold, QTI_KRYO4_GOLD_MIDR, \ + qti_kryo4_gold_reset_func, \ + CPU_NO_EXTRA1_FUNC, \ + cortex_a76_disable_wa_cve_2018_3639, \ + cortex_a76_core_pwr_dwn, \ + qti_kryo4_gold_cluster_pwr_dwn 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 <arch.h> +#include <asm_macros.S> +#include <cpu_macros.S> + +#include <plat_macros.S> +#include <qti_cpu.h> + + .p2align 3 + +/* ------------------------------------------------- + * The CPU Ops reset function for Kryo-3 Silver + * ------------------------------------------------- + */ +func qti_kryo4_silver_reset_func + mov x19, x30 + + bl qtiseclib_kryo4_silver_reset_asm + mov x30, x19 + b cortex_a55_reset_func + +endfunc qti_kryo4_silver_reset_func + +/* --------------------------------------------------------- + * The CPU Ops cluster power down function for Kryo-3 Silver + * --------------------------------------------------------- + */ +func qti_kryo4_silver_cluster_pwr_dwn + ret +endfunc qti_kryo4_silver_cluster_pwr_dwn + +#if REPORT_ERRATA +/* + * Errata printing function for Kryo4 Silver. Must follow AAPCS. + */ +func qti_kryo4_silver_errata_report + /* TODO : Need to add support. Required only for debug bl31 image.*/ + ret +endfunc qti_kryo4_silver_errata_report +#endif + + +/* --------------------------------------------- + * This function provides kryo4_silver specific + * register information for crash reporting. + * It needs to return with x6 pointing to + * a list of register names in ASCII and + * x8 - x15 having values of registers to be + * reported. + * --------------------------------------------- + */ +.section .rodata.qti_kryo4_silver_regs, "aS" +qti_kryo4_silver_regs: /* The ASCII list of register names to be reported */ + .asciz "" + +func qti_kryo4_silver_cpu_reg_dump + adr x6, qti_kryo4_silver_regs + ret +endfunc qti_kryo4_silver_cpu_reg_dump + + +declare_cpu_ops qti_kryo4_silver, QTI_KRYO4_SILVER_MIDR, \ + qti_kryo4_silver_reset_func, \ + cortex_a55_core_pwr_dwn, \ + qti_kryo4_silver_cluster_pwr_dwn 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 <arch.h> +#include <asm_macros.S> +#include <cpu_macros.S> + +#include <plat_macros.S> +#include <qti_cpu.h> + + .p2align 3 + +/* ------------------------------------------------- + * The CPU Ops reset function for Kryo-3 Gold + * ------------------------------------------------- + */ +func qti_kryo6_gold_reset_func +#if IMAGE_BL31 && WORKAROUND_CVE_2017_5715 + adr x0, wa_cve_2017_5715_bpiall_vbar + msr vbar_el3, x0 + isb +#endif + + mov x19, x30 + + bl qtiseclib_kryo6_gold_reset_asm + mov x30, x19 + b cortex_a78_reset_func + +endfunc qti_kryo6_gold_reset_func + +/* ------------------------------------------------------- + * The CPU Ops cluster power down function for Kryo-3 Gold + * ------------------------------------------------------- + */ +func qti_kryo6_gold_cluster_pwr_dwn + ret +endfunc qti_kryo6_gold_cluster_pwr_dwn + +#if REPORT_ERRATA +/* + * Errata printing function for Kryo4 Gold. Must follow AAPCS. + */ +func qti_kryo6_gold_errata_report + /* TODO : Need to add support. Required only for debug bl31 image.*/ + ret +endfunc qti_kryo6_gold_errata_report +#endif + +/* --------------------------------------------- + * This function provides kryo4_gold specific + * register information for crash reporting. + * It needs to return with x6 pointing to + * a list of register names in ASCII and + * x8 - x15 having values of registers to be + * reported. + * --------------------------------------------- + */ +.section .rodata.qti_kryo4_gold_regs, "aS" +qti_kryo6_gold_regs: /* The ASCII list of register names to be reported */ + .asciz "" + +func qti_kryo6_gold_cpu_reg_dump + adr x6, qti_kryo6_gold_regs + ret +endfunc qti_kryo6_gold_cpu_reg_dump + +declare_cpu_ops qti_kryo6_gold, QTI_KRYO6_GOLD_MIDR, \ + qti_kryo6_gold_reset_func, \ + cortex_a78_core_pwr_dwn, \ + qti_kryo6_gold_cluster_pwr_dwn 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 <arch.h> +#include <asm_macros.S> +#include <cpu_macros.S> + +#include <plat_macros.S> +#include <qti_cpu.h> + + .p2align 3 + +/* ------------------------------------------------- + * The CPU Ops reset function for Kryo-3 Silver + * ------------------------------------------------- + */ +func qti_kryo6_silver_reset_func + mov x19, x30 + + bl qtiseclib_kryo6_silver_reset_asm + mov x30, x19 + b cortex_a55_reset_func + +endfunc qti_kryo6_silver_reset_func + +/* --------------------------------------------------------- + * The CPU Ops cluster power down function for Kryo-3 Silver + * --------------------------------------------------------- + */ +func qti_kryo6_silver_cluster_pwr_dwn + ret +endfunc qti_kryo6_silver_cluster_pwr_dwn + +#if REPORT_ERRATA +/* + * Errata printing function for Kryo4 Silver. Must follow AAPCS. + */ +func qti_kryo6_silver_errata_report + /* TODO : Need to add support. Required only for debug bl31 image.*/ + ret +endfunc qti_kryo6_silver_errata_report +#endif + + +/* --------------------------------------------- + * This function provides kryo4_silver specific + * register information for crash reporting. + * It needs to return with x6 pointing to + * a list of register names in ASCII and + * x8 - x15 having values of registers to be + * reported. + * --------------------------------------------- + */ +.section .rodata.qti_kryo4_silver_regs, "aS" +qti_kryo6_silver_regs: /* The ASCII list of register names to be reported */ + .asciz "" + +func qti_kryo6_silver_cpu_reg_dump + adr x6, qti_kryo6_silver_regs + ret +endfunc qti_kryo6_silver_cpu_reg_dump + + +declare_cpu_ops qti_kryo6_silver, QTI_KRYO6_SILVER_MIDR, \ + qti_kryo6_silver_reset_func, \ + cortex_a55_core_pwr_dwn, \ + qti_kryo6_silver_cluster_pwr_dwn 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 <asm_macros.S> +#include <console_macros.S> + +#include <platform_def.h> +#include <qti_uart_console.h> + +/* + * This driver implements console logging into a ring buffer. + */ + + .globl qti_console_uart_register + + /* ----------------------------------------------- + * int qti_console_uart_register(console_t *console, + * uintptr_t uart_base_addr) + * Registers uart console instance. + * In: x0 - pointer to empty console_t struct + * x1 - start address of uart block. + * Out: x0 - 1 to indicate success + * Clobber list: x0, x1, x14 + * ----------------------------------------------- + */ +func qti_console_uart_register + str x1, [x0, #CONSOLE_T_BASE] /* Save UART base. */ + finish_console_register uart putc=1, flush=1 +endfunc qti_console_uart_register + + /* ----------------------------------------------- + * int qti_console_uart_puts(int c, console_t *console) + * Writes a character to the UART console. + * The character must be preserved in x0. + * In: x0 - character to be stored + * x1 - pointer to console_t struct + * Clobber list: x1, x2 + * ----------------------------------------------- + */ +func console_uart_putc + /* set x1 = UART base. */ + ldr x1, [x1, #CONSOLE_T_BASE] + + /* Loop until M_GENI_CMD_ACTIVE bit not clear. */ +1: ldr w2, [x1, #GENI_STATUS_REG] + and w2, w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK + cmp w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK + b.eq 1b + + /* Transmit data. */ + cmp w0, #0xA + b.ne 3f + + /* Add '\r' when input char is '\n' */ + mov w2, #0x1 + mov w0, #0xD + str w2, [x1, #UART_TX_TRANS_LEN_REG] + mov w2, #GENI_M_CMD_TX + str w2, [x1, #GENI_M_CMD0_REG] + str w0, [x1, #GENI_TX_FIFOn_REG] + mov w0, #0xA + + /* Loop until M_GENI_CMD_ACTIVE bit not clear. */ +2: ldr w2, [x1, #GENI_STATUS_REG] + and w2, w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK + cmp w2, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK + b.eq 2b + + /* Transmit i/p data. */ +3: mov w2, #0x1 + str w2, [x1, #UART_TX_TRANS_LEN_REG] + mov w2, #GENI_M_CMD_TX + str w2, [x1, #GENI_M_CMD0_REG] + str w0, [x1, #GENI_TX_FIFOn_REG] + + ret +endfunc console_uart_putc + + /* ----------------------------------------------- + * int qti_console_uart_flush(console_t *console) + * In: x0 - pointer to console_t struct + * Out: x0 - 0 for success + * Clobber list: x0, x1 + * ----------------------------------------------- + */ +func console_uart_flush + /* set x0 = UART base. */ + ldr x0, [x0, #CONSOLE_T_BASE] + + /* Loop until M_GENI_CMD_ACTIVE bit not clear. */ +1: ldr w1, [x0, #GENI_STATUS_REG] + and w1, w1, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK + cmp w1, #GENI_STATUS_M_GENI_CMD_ACTIVE_MASK + b.eq 1b + + mov w0, #0 + ret +endfunc console_uart_flush 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 <drivers/delay_timer.h> + +#include <qti_plat.h> +#include <spmi_arb.h> + +/* + * This driver implements PON support for PM8998-compatible PMICs. This can + * include other part numbers like PM6150. + */ + +#define RESET_TYPE_WARM_RESET 1 +#define RESET_TYPE_SHUTDOWN 4 + +#define S2_RESET_EN BIT(7) + +static void configure_ps_hold(uint32_t reset_type) +{ + /* QTI recommends disabling reset for 10 cycles before reconfiguring. */ + spmi_arb_write8(PON_PS_HOLD_RESET_CTL2, 0); + mdelay(1); + + spmi_arb_write8(PON_PS_HOLD_RESET_CTL, reset_type); + spmi_arb_write8(PON_PS_HOLD_RESET_CTL2, S2_RESET_EN); + mdelay(1); +} + +void qti_pmic_prepare_reset(void) +{ + configure_ps_hold(RESET_TYPE_WARM_RESET); +} + +void qti_pmic_prepare_shutdown(void) +{ + configure_ps_hold(RESET_TYPE_SHUTDOWN); +} 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..a5f5858 --- /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 <assert.h> + +#include <bl31/bl31.h> +#include <common/debug.h> +#include <common/desc_image_load.h> +#include <drivers/console.h> +#include <drivers/generic_delay_timer.h> +#include <lib/bl_aux_params/bl_aux_params.h> +#include <lib/coreboot.h> +#include <lib/spinlock.h> + +#include <platform.h> +#include <qti_interrupt_svc.h> +#include <qti_plat.h> +#include <qti_uart_console.h> +#include <qtiseclib_interface.h> + +/* + * Placeholder variables for copying the arguments that have been passed to + * BL31 from BL2. + */ +static entry_point_info_t bl33_image_ep_info; + +/* + * Variable to hold counter frequency for the CPU's generic timer. In this + * platform coreboot image configure counter frequency for boot core before + * reaching TF-A. + */ +static uint64_t g_qti_cpu_cntfrq; + +/* + * Variable to hold bl31 cold boot status. Default value 0x0 means yet to boot. + * Any other value means cold booted. + */ +uint32_t g_qti_bl31_cold_booted; + +/******************************************************************************* + * Perform any BL31 early platform setup common to ARM standard platforms. + * Here is an opportunity to copy parameters passed by the calling EL (S-EL1 + * in BL2 & S-EL3 in BL1) before they are lost (potentially). This needs to be + * done before the MMU is initialized so that the memory layout can be used + * while creating page tables. BL2 has flushed this information to memory, so + * we are guaranteed to pick up good data. + ******************************************************************************/ +void bl31_early_platform_setup(u_register_t from_bl2, + u_register_t plat_params_from_bl2) +{ + + g_qti_cpu_cntfrq = read_cntfrq_el0(); + + bl_aux_params_parse(plat_params_from_bl2, NULL); + +#if COREBOOT + if (coreboot_serial.baseaddr != 0) { + static console_t g_qti_console_uart; + + qti_console_uart_register(&g_qti_console_uart, + coreboot_serial.baseaddr); + } +#endif + + /* + * Tell BL31 where the non-trusted software image + * is located and the entry state information + */ + bl31_params_parse_helper(from_bl2, NULL, &bl33_image_ep_info); +} + +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + bl31_early_platform_setup(arg0, arg1); +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this only initializes 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 <assert.h> +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> + +#include <common/debug.h> +#include <lib/mmio.h> +#include <lib/smccc.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <services/arm_arch_svc.h> + +#include <platform_def.h> +#include <qti_map_chipinfo.h> +#include <qti_plat.h> +#include <qtiseclib_interface.h> + +/* + * Table of regions for various BL stages to map using the MMU. + * This doesn't include TZRAM as the 'mem_layout' argument passed to + * qti_configure_mmu_elx() will give the available subset of that, + */ + +const mmap_region_t plat_qti_mmap[] = { + MAP_REGION_FLAT(QTI_DEVICE_BASE, QTI_DEVICE_SIZE, + MT_DEVICE | MT_RW | MT_SECURE), + MAP_REGION_FLAT(QTI_AOP_CMD_DB_BASE, QTI_AOP_CMD_DB_SIZE, + MT_NS | MT_RO | MT_EXECUTE_NEVER), + {0} +}; + +CASSERT(ARRAY_SIZE(plat_qti_mmap) <= MAX_MMAP_REGIONS, assert_max_mmap_regions); + + +bool qti_is_overlap_atf_rg(unsigned long long addr, size_t size) +{ + if (addr > addr + size + || (BL31_BASE < addr + size && BL31_LIMIT > addr)) { + return true; + } + return false; +} + +/* + * unsigned int plat_qti_my_cluster_pos(void) + * definition to get the cluster index of the calling CPU. + * - In ARM v8 (MPIDR_EL1[24]=0) + * ClusterId = MPIDR_EL1[15:8] + * - In ARM v8.1 & Later version (MPIDR_EL1[24]=1) + * ClusterId = MPIDR_EL1[23:15] + */ +unsigned int plat_qti_my_cluster_pos(void) +{ + unsigned int mpidr, cluster_id; + + mpidr = read_mpidr_el1(); + if ((mpidr & MPIDR_MT_MASK) == 0) { /* MT not supported */ + cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + } else { /* MT supported */ + cluster_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK; + } + assert(cluster_id < PLAT_CLUSTER_COUNT); + return cluster_id; +} + +/* + * Set up the page tables for the generic and platform-specific memory regions. + * The extents of the generic memory regions are specified by the function + * arguments and consist of: + * - Trusted SRAM seen by the BL image; + * - Code section; + * - Read-only data section; + * - Coherent memory region, if applicable. + */ +void qti_setup_page_tables( + uintptr_t total_base, + size_t total_size, + uintptr_t code_start, + uintptr_t code_limit, + uintptr_t rodata_start, + uintptr_t rodata_limit + ) +{ + /* + * Map the Trusted SRAM with appropriate memory attributes. + * Subsequent mappings will adjust the attributes for specific regions. + */ + VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n", + (void *)total_base, (void *)(total_base + total_size)); + mmap_add_region(total_base, total_base, + total_size, MT_MEMORY | MT_RW | MT_SECURE); + + /* Re-map the code section */ + VERBOSE("Code region: %p - %p\n", + (void *)code_start, (void *)code_limit); + mmap_add_region(code_start, code_start, + code_limit - code_start, MT_CODE | MT_SECURE); + + /* Re-map the read-only data section */ + VERBOSE("Read-only data region: %p - %p\n", + (void *)rodata_start, (void *)rodata_limit); + mmap_add_region(rodata_start, rodata_start, + rodata_limit - rodata_start, MT_RO_DATA | MT_SECURE); + + /* Now (re-)map the platform-specific memory regions */ + mmap_add(plat_qti_mmap); + + /* Create the page tables to reflect the above mappings */ + init_xlat_tables(); +} + +static inline void qti_align_mem_region(uintptr_t addr, size_t size, + uintptr_t *aligned_addr, + size_t *aligned_size) +{ + *aligned_addr = round_down(addr, PAGE_SIZE); + *aligned_size = round_up(addr - *aligned_addr + size, PAGE_SIZE); +} + +int qti_mmap_add_dynamic_region(uintptr_t base_pa, size_t size, + unsigned int attr) +{ + uintptr_t aligned_pa; + size_t aligned_size; + + qti_align_mem_region(base_pa, size, &aligned_pa, &aligned_size); + + if (qti_is_overlap_atf_rg(base_pa, size)) { + /* Memory shouldn't overlap with TF-A range. */ + return -EPERM; + } + + return mmap_add_dynamic_region(aligned_pa, aligned_pa, aligned_size, + attr); +} + +int qti_mmap_remove_dynamic_region(uintptr_t base_va, size_t size) +{ + qti_align_mem_region(base_va, size, &base_va, &size); + return mmap_remove_dynamic_region(base_va, size); +} + +/* + * This function returns soc version which mainly consist of below fields + * + * soc_version[30:24] = JEP-106 continuation code for the SiP + * soc_version[23:16] = JEP-106 identification code with parity bit for the SiP + * soc_version[0:15] = Implementation defined SoC ID + */ +int32_t plat_get_soc_version(void) +{ + int i = 0; + /* Variant other than in mapped g_map_jtag_chipinfo_id variable will have + * default chipinfo id as 0xFFFF + */ + uint32_t soc_version = (QTI_DEFAULT_CHIPINFO_ID & QTI_SOC_VERSION_MASK); + uint32_t jep106az_code = (JEDEC_QTI_BKID << QTI_SOC_CONTINUATION_SHIFT) + | (JEDEC_QTI_MFID << QTI_SOC_IDENTIFICATION_SHIFT); + uint32_t jtag_id = mmio_read_32(QTI_JTAG_ID_REG); + uint32_t jtag_id_val = (jtag_id >> QTI_JTAG_ID_SHIFT) + & QTI_SOC_VERSION_MASK; + + for (i = 0; i < ARRAY_SIZE(g_map_jtag_chipinfo_id); i++) { + if (g_map_jtag_chipinfo_id[i].jtag_id == jtag_id_val) + soc_version = g_map_jtag_chipinfo_id[i].chipinfo_id + & QTI_SOC_VERSION_MASK; + } + return (int32_t)(jep106az_code | (soc_version)); +} + +/* + * This function returns soc revision in below format + * + * soc_revision[0:30] = SOC revision of specific SOC + */ +int32_t plat_get_soc_revision(void) +{ + return mmio_read_32(QTI_SOC_REVISION_REG) & QTI_SOC_REVISION_MASK; +} + +/***************************************************************************** + * plat_is_smccc_feature_available() - This function checks whether SMCCC feature + * is availabile for the platform or not. + * @fid: SMCCC function id + * + * Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and + * SMC_ARCH_CALL_NOT_SUPPORTED otherwise. + *****************************************************************************/ +int32_t plat_is_smccc_feature_available(u_register_t fid) +{ + switch (fid) { + case SMCCC_ARCH_SOC_ID: + return SMC_ARCH_CALL_SUCCESS; + default: + return SMC_ARCH_CALL_NOT_SUPPORTED; + } +} 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 <common/bl_common.h> +#include <drivers/arm/gicv3.h> + +#include <platform.h> +#include <platform_def.h> +#include <qti_plat.h> +#include <qtiseclib_defs.h> +#include <qtiseclib_defs_plat.h> + +/* The GICv3 driver only needs to be initialized in EL3 */ +static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; + +/* Array of interrupts to be configured by the gic driver */ +static const interrupt_prop_t qti_interrupt_props[] = { + INTR_PROP_DESC(QTISECLIB_INT_ID_CPU_WAKEUP_SGI, + GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_RESET_SGI, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_SEC_WDOG_BARK, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_NON_SEC_WDOG_BITE, + GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, + GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_SEC, + GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CLT_NONSEC, + GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CFG_SEC, + GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_VMIDMT_ERR_CFG_NONSEC, + GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_XPU_SEC, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_XPU_NON_SEC, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), +#ifdef QTISECLIB_INT_ID_A1_NOC_ERROR + INTR_PROP_DESC(QTISECLIB_INT_ID_A1_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), +#endif + INTR_PROP_DESC(QTISECLIB_INT_ID_A2_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_CONFIG_NOC_ERROR, + GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_DC_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_MEM_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_SYSTEM_NOC_ERROR, + GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, + GIC_INTR_CFG_EDGE), + INTR_PROP_DESC(QTISECLIB_INT_ID_MMSS_NOC_ERROR, + GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, + GIC_INTR_CFG_EDGE), +#ifdef QTISECLIB_INT_ID_LPASS_AGNOC_ERROR + INTR_PROP_DESC(QTISECLIB_INT_ID_LPASS_AGNOC_ERROR, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), +#endif +#ifdef QTISECLIB_INT_ID_NSP_NOC_ERROR + INTR_PROP_DESC(QTISECLIB_INT_ID_NSP_NOC_ERROR, GIC_HIGHEST_SEC_PRIORITY, + INTR_GROUP0, + GIC_INTR_CFG_EDGE), +#endif +}; + +const gicv3_driver_data_t qti_gic_data = { + .gicd_base = QTI_GICD_BASE, + .gicr_base = QTI_GICR_BASE, + .interrupt_props = qti_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(qti_interrupt_props), + .rdistif_num = PLATFORM_CORE_COUNT, + .rdistif_base_addrs = rdistif_base_addrs, + .mpidr_to_core_pos = plat_qti_core_pos_by_mpidr +}; + +void plat_qti_gic_driver_init(void) +{ + /* + * The GICv3 driver is initialized in EL3 and does not need + * to be initialized again in SEL1. This is because the S-EL1 + * can use GIC system registers to manage interrupts and does + * not need GIC interface base addresses to be configured. + */ + gicv3_driver_init(&qti_gic_data); +} + +/****************************************************************************** + * ARM common helper to initialize the GIC. Only invoked by BL31 + *****************************************************************************/ +void plat_qti_gic_init(void) +{ + unsigned int i; + + gicv3_distif_init(); + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); + + /* Route secure spi interrupt to ANY. */ + for (i = 0; i < ARRAY_SIZE(qti_interrupt_props); i++) { + unsigned int int_id = qti_interrupt_props[i].intr_num; + + if (plat_ic_is_spi(int_id)) { + gicv3_set_spi_routing(int_id, GICV3_IRM_ANY, 0x0); + } + } +} + +void gic_set_spi_routing(unsigned int id, unsigned int irm, u_register_t target) +{ + gicv3_set_spi_routing(id, irm, target); +} + +/****************************************************************************** + * ARM common helper to enable the GIC CPU interface + *****************************************************************************/ +void plat_qti_gic_cpuif_enable(void) +{ + gicv3_cpuif_enable(plat_my_core_pos()); +} + +/****************************************************************************** + * ARM common helper to disable the GIC CPU interface + *****************************************************************************/ +void plat_qti_gic_cpuif_disable(void) +{ + gicv3_cpuif_disable(plat_my_core_pos()); +} + +/****************************************************************************** + * ARM common helper to initialize the per-CPU redistributor interface in GICv3 + *****************************************************************************/ +void plat_qti_gic_pcpu_init(void) +{ + gicv3_rdistif_init(plat_my_core_pos()); +} + +/****************************************************************************** + * ARM common helpers to power GIC redistributor interface + *****************************************************************************/ +void plat_qti_gic_redistif_on(void) +{ + gicv3_rdistif_on(plat_my_core_pos()); +} + +void plat_qti_gic_redistif_off(void) +{ + gicv3_rdistif_off(plat_my_core_pos()); +} 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 <assert.h> +#include <stdint.h> + +#include <arch_helpers.h> +#include <bl31/interrupt_mgmt.h> +#include <drivers/arm/gic_common.h> +#include <lib/el3_runtime/context_mgmt.h> + +#include <platform.h> +#include <qti_interrupt_svc.h> +#include <qtiseclib_interface.h> + +#define QTI_INTR_INVALID_INT_NUM 0xFFFFFFFFU + +/* + * Top-level EL3 interrupt handler. + */ +static uint64_t qti_el3_interrupt_handler(uint32_t id, uint32_t flags, + void *handle, void *cookie) +{ + uint32_t irq = QTI_INTR_INVALID_INT_NUM; + + /* + * EL3 non-interruptible. Interrupt shouldn't occur when we are at + * EL3 / Secure. + */ + assert(handle != cm_get_context(SECURE)); + + irq = plat_ic_acknowledge_interrupt(); + + qtiseclib_invoke_isr(irq, handle); + + /* End of Interrupt. */ + if (irq < 1022U) { + plat_ic_end_of_interrupt(irq); + } + + return (uint64_t) handle; +} + +int qti_interrupt_svc_init(void) +{ + int ret; + uint64_t flags = 0U; + + /* + * Route EL3 interrupts to EL3 when in Non-secure. + * Note: EL3 won't have interrupt enable + * & we don't have S-EL1 support. + */ + set_interrupt_rm_flag(flags, NON_SECURE); + set_interrupt_rm_flag(flags, SECURE); + + /* Register handler for EL3 interrupts */ + ret = register_interrupt_type_handler(INTR_TYPE_EL3, + qti_el3_interrupt_handler, flags); + assert(ret == 0); + + return ret; +} diff --git a/plat/qti/common/src/qti_pm.c b/plat/qti/common/src/qti_pm.c new file mode 100644 index 0000000..1113efc --- /dev/null +++ b/plat/qti/common/src/qti_pm.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <assert.h> + +#include <arch_helpers.h> +#include <bl31/bl31.h> +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> +#include <lib/psci/psci.h> + +#include <platform.h> +#include <platform_def.h> +#include <qti_cpu.h> +#include <qti_plat.h> +#include <qtiseclib_cb_interface.h> +#include <qtiseclib_defs_plat.h> +#include <qtiseclib_interface.h> + +#define QTI_LOCAL_PSTATE_WIDTH 4 +#define QTI_LOCAL_PSTATE_MASK ((1 << QTI_LOCAL_PSTATE_WIDTH) - 1) + +#if PSCI_OS_INIT_MODE +#define QTI_LAST_AT_PLVL_MASK (QTI_LOCAL_PSTATE_MASK << \ + (QTI_LOCAL_PSTATE_WIDTH * \ + (PLAT_MAX_PWR_LVL + 1))) +#endif + +/* 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_RENAME_SYSREG_RW_FUNCS(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 PSCI_OS_INIT_MODE + if ((power_state & ~QTI_LAST_AT_PLVL_MASK) == + qti_pm_idle_states[i]) +#else + if (power_state == qti_pm_idle_states[i]) +#endif + 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 */ + for (i = QTI_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) { + req_state->pwr_domain_state[i] = state_id & + QTI_LOCAL_PSTATE_MASK; + state_id >>= QTI_LOCAL_PSTATE_WIDTH; + } +#if PSCI_OS_INIT_MODE + req_state->last_at_pwrlvl = state_id & QTI_LOCAL_PSTATE_MASK; +#endif + + 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; + } + +#if PSCI_OS_INIT_MODE + req_state->last_at_pwrlvl = PLAT_MAX_PWR_LVL; +#endif +} + +/* + * 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 <stddef.h> + +#include <lib/mmio.h> + +#include <qti_rng.h> +#include <qti_rng_io.h> + +int qti_rng_get_data(uint8_t *out, uint32_t out_len) +{ + uint32_t tmp_rndm = 0; + uint32_t bytes_left = out_len; + int i = 0; + + if (NULL == out || 0 == out_len) { + return -1; + } + + /* + * RNG HW initialized at previous boot image. + * RNG clocks are expected to be ON. + */ + + do { + /* There is no data to read */ + if ((mmio_read_32(SEC_PRNG_STATUS) & + SEC_PRNG_STATUS_DATA_AVAIL_BMSK) == 0) { + continue; + } + + while ((tmp_rndm = mmio_read_32(SEC_PRNG_DATA_OUT)) == 0) { + ; + } + + for (i = 0; i < 4; i++) { + *out = (uint8_t) (tmp_rndm >> (8 * i)); + + out++; + bytes_left--; + + if (bytes_left == 0) { + break; + } + } + + } while (bytes_left != 0); + + return 0; +} 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 <assert.h> +#include <stdint.h> + +#include <platform.h> +#include <platform_def.h> +#include <qti_rng.h> +#include <qtiseclib_interface.h> + +u_register_t plat_get_stack_protector_canary(void) +{ + u_register_t random = 0x0; + + /* + * get random data , the below API doesn't return random = 0 on success + */ + qti_rng_get_data((uint8_t *) &random, sizeof(random)); + assert(random != 0x0); + + return random; +} 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 <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include <common/debug.h> +#include <common/runtime_svc.h> +#include <context.h> +#include <lib/coreboot.h> +#include <lib/utils_def.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <smccc_helpers.h> +#include <tools_share/uuid.h> + +#include <qti_plat.h> +#include <qti_secure_io_cfg.h> +#include <qtiseclib_interface.h> + +/* + * SIP service - SMC function IDs for SiP Service queries + * + */ +#define QTI_SIP_SVC_CALL_COUNT_ID U(0x0200ff00) +#define QTI_SIP_SVC_UID_ID U(0x0200ff01) +/* 0x8200ff02 is reserved*/ +#define QTI_SIP_SVC_VERSION_ID U(0x0200ff03) +#define QTI_SIP_SVC_AVAILABLE_ID U(0x02000601) +/* + * Syscall's to allow Non Secure world accessing peripheral/IO memory + * those are secure/proteced BUT not required to be secure. + */ +#define QTI_SIP_SVC_SECURE_IO_READ_ID U(0x02000501) +#define QTI_SIP_SVC_SECURE_IO_WRITE_ID U(0x02000502) + +/* + * Syscall's to assigns a list of intermediate PAs from a + * source Virtual Machine (VM) to a destination VM. + */ +#define QTI_SIP_SVC_MEM_ASSIGN_ID U(0x02000C16) + +#define QTI_SIP_SVC_SECURE_IO_READ_PARAM_ID U(0x1) +#define QTI_SIP_SVC_SECURE_IO_WRITE_PARAM_ID U(0x2) +#define QTI_SIP_SVC_MEM_ASSIGN_PARAM_ID U(0x1117) + +#define QTI_SIP_SVC_CALL_COUNT U(0x3) +#define QTI_SIP_SVC_VERSION_MAJOR U(0x0) +#define QTI_SIP_SVC_VERSION_MINOR U(0x0) + +#define QTI_VM_LAST U(44) +#define SIZE4K U(0x1000) +#define QTI_VM_MAX_LIST_SIZE U(0x20) + +#define FUNCID_OEN_NUM_MASK ((FUNCID_OEN_MASK << FUNCID_OEN_SHIFT)\ + |(FUNCID_NUM_MASK << FUNCID_NUM_SHIFT)) + +enum { + QTI_SIP_SUCCESS = 0, + QTI_SIP_NOT_SUPPORTED = -1, + QTI_SIP_PREEMPTED = -2, + QTI_SIP_INVALID_PARAM = -3, +}; + +/* QTI SiP Service UUID */ +DEFINE_SVC_UUID2(qti_sip_svc_uid, + 0x43864748, 0x217f, 0x41ad, 0xaa, 0x5a, + 0xba, 0xe7, 0x0f, 0xa5, 0x52, 0xaf); + +static bool qti_is_secure_io_access_allowed(u_register_t addr) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(qti_secure_io_allowed_regs); i++) { + if ((uintptr_t) addr == qti_secure_io_allowed_regs[i]) { + return true; + } + } + + return false; +} + +static bool qti_check_syscall_availability(u_register_t smc_fid) +{ + switch (smc_fid) { + case QTI_SIP_SVC_CALL_COUNT_ID: + case QTI_SIP_SVC_UID_ID: + case QTI_SIP_SVC_VERSION_ID: + case QTI_SIP_SVC_AVAILABLE_ID: + case QTI_SIP_SVC_SECURE_IO_READ_ID: + case QTI_SIP_SVC_SECURE_IO_WRITE_ID: + case QTI_SIP_SVC_MEM_ASSIGN_ID: + return true; + default: + return false; + } +} + +bool qti_mem_assign_validate_param(memprot_info_t *mem_info, + u_register_t u_num_mappings, + uint32_t *source_vm_list, + u_register_t src_vm_list_cnt, + memprot_dst_vm_perm_info_t *dest_vm_list, + u_register_t dst_vm_list_cnt) +{ + int i; + + if (!source_vm_list || !dest_vm_list || !mem_info + || (src_vm_list_cnt == 0) + || (src_vm_list_cnt >= QTI_VM_LAST) || (dst_vm_list_cnt == 0) + || (dst_vm_list_cnt >= QTI_VM_LAST) || (u_num_mappings == 0) + || u_num_mappings > QTI_VM_MAX_LIST_SIZE) { + ERROR("vm count is 0 or more then QTI_VM_LAST or empty list\n"); + ERROR("source_vm_list %p dest_vm_list %p mem_info %p src_vm_list_cnt %u dst_vm_list_cnt %u u_num_mappings %u\n", + source_vm_list, dest_vm_list, mem_info, + (unsigned int)src_vm_list_cnt, + (unsigned int)dst_vm_list_cnt, + (unsigned int)u_num_mappings); + return false; + } + for (i = 0; i < u_num_mappings; i++) { + if ((mem_info[i].mem_addr & (SIZE4K - 1)) + || (mem_info[i].mem_size == 0) + || (mem_info[i].mem_size & (SIZE4K - 1))) { + ERROR("mem_info passed buffer 0x%x or size 0x%x is not 4k aligned\n", + (unsigned int)mem_info[i].mem_addr, + (unsigned int)mem_info[i].mem_size); + return false; + } + + if ((mem_info[i].mem_addr + mem_info[i].mem_size) < + mem_info[i].mem_addr) { + ERROR("overflow in mem_addr 0x%x add mem_size 0x%x\n", + (unsigned int)mem_info[i].mem_addr, + (unsigned int)mem_info[i].mem_size); + return false; + } + coreboot_memory_t mem_type = coreboot_get_memory_type( + mem_info[i].mem_addr, + mem_info[i].mem_size); + if (mem_type != CB_MEM_RAM && mem_type != CB_MEM_RESERVED) { + ERROR("memory region not in CB MEM RAM or RESERVED area: region start 0x%x size 0x%x\n", + (unsigned int)mem_info[i].mem_addr, + (unsigned int)mem_info[i].mem_size); + return false; + } + } + for (i = 0; i < src_vm_list_cnt; i++) { + if (source_vm_list[i] >= QTI_VM_LAST) { + ERROR("source_vm_list[%d] 0x%x is more then QTI_VM_LAST\n", + i, (unsigned int)source_vm_list[i]); + return false; + } + } + for (i = 0; i < dst_vm_list_cnt; i++) { + if (dest_vm_list[i].dst_vm >= QTI_VM_LAST) { + ERROR("dest_vm_list[%d] 0x%x is more then QTI_VM_LAST\n", + i, (unsigned int)dest_vm_list[i].dst_vm); + return false; + } + } + return true; +} + +static uintptr_t qti_sip_mem_assign(void *handle, uint32_t smc_cc, + u_register_t x1, + u_register_t x2, + u_register_t x3, u_register_t x4) +{ + uintptr_t dyn_map_start = 0, dyn_map_end = 0; + size_t dyn_map_size = 0; + u_register_t x6, x7; + int ret = QTI_SIP_NOT_SUPPORTED; + u_register_t x5 = read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X5); + + if (smc_cc == SMC_32) { + x5 = (uint32_t) x5; + } + /* Validate input arg count & retrieve arg3-6 from NS Buffer. */ + if ((x1 != QTI_SIP_SVC_MEM_ASSIGN_PARAM_ID) || (x5 == 0x0)) { + ERROR("invalid mem_assign param id or no mapping info\n"); + goto unmap_return; + } + + /* Map NS Buffer. */ + dyn_map_start = x5; + dyn_map_size = + (smc_cc == + SMC_32) ? (sizeof(uint32_t) * 4) : (sizeof(uint64_t) * 4); + if (qti_mmap_add_dynamic_region(dyn_map_start, dyn_map_size, + (MT_NS | MT_RO_DATA)) != 0) { + ERROR("map failed for params NS Buffer %x %x\n", + (unsigned int)dyn_map_start, (unsigned int)dyn_map_size); + goto unmap_return; + } + /* Retrieve indirect args. */ + if (smc_cc == SMC_32) { + x6 = *((uint32_t *) x5 + 1); + x7 = *((uint32_t *) x5 + 2); + x5 = *(uint32_t *) x5; + } else { + x6 = *((uint64_t *) x5 + 1); + x7 = *((uint64_t *) x5 + 2); + x5 = *(uint64_t *) x5; + } + /* Un-Map NS Buffer. */ + if (qti_mmap_remove_dynamic_region(dyn_map_start, dyn_map_size) != 0) { + ERROR("unmap failed for params NS Buffer %x %x\n", + (unsigned int)dyn_map_start, (unsigned int)dyn_map_size); + goto unmap_return; + } + + /* + * Map NS Buffers. + * arg0,2,4 points to buffers & arg1,3,5 hold sizes. + * MAP api's fail to map if it's already mapped. Let's + * find lowest start & highest end address, then map once. + */ + dyn_map_start = MIN(x2, x4); + dyn_map_start = MIN(dyn_map_start, x6); + dyn_map_end = MAX((x2 + x3), (x4 + x5)); + dyn_map_end = MAX(dyn_map_end, (x6 + x7)); + dyn_map_size = dyn_map_end - dyn_map_start; + + if (qti_mmap_add_dynamic_region(dyn_map_start, dyn_map_size, + (MT_NS | MT_RO_DATA)) != 0) { + ERROR("map failed for params NS Buffer2 %x %x\n", + (unsigned int)dyn_map_start, (unsigned int)dyn_map_size); + goto unmap_return; + } + memprot_info_t *mem_info_p = (memprot_info_t *) x2; + uint32_t u_num_mappings = x3 / sizeof(memprot_info_t); + uint32_t *source_vm_list_p = (uint32_t *) x4; + uint32_t src_vm_list_cnt = x5 / sizeof(uint32_t); + memprot_dst_vm_perm_info_t *dest_vm_list_p = + (memprot_dst_vm_perm_info_t *) x6; + uint32_t dst_vm_list_cnt = + x7 / sizeof(memprot_dst_vm_perm_info_t); + if (qti_mem_assign_validate_param(mem_info_p, u_num_mappings, + source_vm_list_p, src_vm_list_cnt, + dest_vm_list_p, + dst_vm_list_cnt) != true) { + ERROR("Param validation failed\n"); + goto unmap_return; + } + + memprot_info_t mem_info[QTI_VM_MAX_LIST_SIZE]; + /* Populating the arguments */ + for (int i = 0; i < u_num_mappings; i++) { + mem_info[i].mem_addr = mem_info_p[i].mem_addr; + mem_info[i].mem_size = mem_info_p[i].mem_size; + } + + memprot_dst_vm_perm_info_t dest_vm_list[QTI_VM_LAST]; + + for (int i = 0; i < dst_vm_list_cnt; i++) { + dest_vm_list[i].dst_vm = dest_vm_list_p[i].dst_vm; + dest_vm_list[i].dst_vm_perm = dest_vm_list_p[i].dst_vm_perm; + dest_vm_list[i].ctx = dest_vm_list_p[i].ctx; + dest_vm_list[i].ctx_size = dest_vm_list_p[i].ctx_size; + } + + uint32_t source_vm_list[QTI_VM_LAST]; + + for (int i = 0; i < src_vm_list_cnt; i++) { + source_vm_list[i] = source_vm_list_p[i]; + } + /* Un-Map NS Buffers. */ + if (qti_mmap_remove_dynamic_region(dyn_map_start, + dyn_map_size) != 0) { + ERROR("unmap failed for params NS Buffer %x %x\n", + (unsigned int)dyn_map_start, (unsigned int)dyn_map_size); + goto unmap_return; + } + /* Invoke API lib api. */ + ret = qtiseclib_mem_assign(mem_info, u_num_mappings, + source_vm_list, src_vm_list_cnt, + dest_vm_list, dst_vm_list_cnt); + + if (ret == 0) { + SMC_RET2(handle, QTI_SIP_SUCCESS, ret); + } +unmap_return: + /* Un-Map NS Buffers if mapped */ + if (dyn_map_start && dyn_map_size) { + qti_mmap_remove_dynamic_region(dyn_map_start, dyn_map_size); + } + + SMC_RET2(handle, QTI_SIP_INVALID_PARAM, ret); +} + +/* + * This function handles QTI specific syscalls. Currently only SiP calls are present. + * Both FAST & YIELD type call land here. + */ +static uintptr_t qti_sip_handler(uint32_t smc_fid, + u_register_t x1, + u_register_t x2, + u_register_t x3, + u_register_t x4, + void *cookie, void *handle, u_register_t flags) +{ + uint32_t l_smc_fid = smc_fid & FUNCID_OEN_NUM_MASK; + + if (GET_SMC_CC(smc_fid) == SMC_32) { + x1 = (uint32_t) x1; + x2 = (uint32_t) x2; + x3 = (uint32_t) x3; + x4 = (uint32_t) x4; + } + + switch (l_smc_fid) { + case QTI_SIP_SVC_CALL_COUNT_ID: + { + SMC_RET1(handle, QTI_SIP_SVC_CALL_COUNT); + break; + } + case QTI_SIP_SVC_UID_ID: + { + /* Return UID to the caller */ + SMC_UUID_RET(handle, qti_sip_svc_uid); + break; + } + case QTI_SIP_SVC_VERSION_ID: + { + /* Return the version of current implementation */ + SMC_RET2(handle, QTI_SIP_SVC_VERSION_MAJOR, + QTI_SIP_SVC_VERSION_MINOR); + break; + } + case QTI_SIP_SVC_AVAILABLE_ID: + { + if (x1 != 1) { + SMC_RET1(handle, QTI_SIP_INVALID_PARAM); + } + if (qti_check_syscall_availability(x2) == true) { + SMC_RET2(handle, QTI_SIP_SUCCESS, 1); + } else { + SMC_RET2(handle, QTI_SIP_SUCCESS, 0); + } + break; + } + case QTI_SIP_SVC_SECURE_IO_READ_ID: + { + if ((x1 == QTI_SIP_SVC_SECURE_IO_READ_PARAM_ID) && + qti_is_secure_io_access_allowed(x2)) { + SMC_RET2(handle, QTI_SIP_SUCCESS, + *((volatile uint32_t *)x2)); + } + SMC_RET1(handle, QTI_SIP_INVALID_PARAM); + break; + } + case QTI_SIP_SVC_SECURE_IO_WRITE_ID: + { + if ((x1 == QTI_SIP_SVC_SECURE_IO_WRITE_PARAM_ID) && + qti_is_secure_io_access_allowed(x2)) { + *((volatile uint32_t *)x2) = x3; + SMC_RET1(handle, QTI_SIP_SUCCESS); + } + SMC_RET1(handle, QTI_SIP_INVALID_PARAM); + break; + } + case QTI_SIP_SVC_MEM_ASSIGN_ID: + { + return qti_sip_mem_assign(handle, GET_SMC_CC(smc_fid), + x1, x2, x3, x4); + break; + } + default: + { + SMC_RET1(handle, QTI_SIP_NOT_SUPPORTED); + } + } + return (uintptr_t) handle; +} + +/* Define a runtime service descriptor for both fast & yield SiP calls */ +DECLARE_RT_SVC(qti_sip_fast_svc, OEN_SIP_START, + OEN_SIP_END, SMC_TYPE_FAST, NULL, qti_sip_handler); + +DECLARE_RT_SVC(qti_sip_yield_svc, OEN_SIP_START, + OEN_SIP_END, SMC_TYPE_YIELD, NULL, qti_sip_handler); 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 <arch.h> + +#include <platform_def.h> +#include <qti_plat.h> + +/* The QTI power domain tree descriptor */ +const unsigned char qti_power_domain_tree_desc[] = { + /* One domain to represent PDC */ + PLAT_PDC_COUNT, + /* One domain to represent RSC */ + PLAT_RSC_COUNT, + /* There is one top-level FCM cluster */ + PLAT_CLUSTER_COUNT, + /* No. of cores in the FCM cluster */ + PLAT_CLUSTER0_CORE_COUNT +}; + +/******************************************************************************* + * This function returns the ARM default topology tree information. + ******************************************************************************/ +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + return qti_power_domain_tree_desc; +} + +/** Function: plat_core_pos_by_mpidr + * This function implements a part of the critical interface between the psci + * generic layer and the platform that allows the former to query the platform + * to convert an MPIDR to a unique linear index. An error code (-1) is returned + * in case the MPIDR is invalid. + */ +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + int core_linear_index = plat_qti_core_pos_by_mpidr(mpidr); + + if (core_linear_index < PLATFORM_CORE_COUNT) { + return core_linear_index; + } else { + return -1; + } +} 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 <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <spmi_arb.h> + +#define REG_APID_MAP(apid) (0x0C440900U + sizeof(uint32_t) * apid) +#define NUM_APID ((0x1100U - 0x900U) / sizeof(uint32_t)) + +#define PPID_MASK (0xfffU << 8) + +#define REG_ARB_CMD(apid) (0x0C600000U + 0x10000U * apid) +/* These are opcodes specific to this SPMI arbitrator, *not* SPMI commands. */ +#define OPC_EXT_WRITEL 0 +#define OPC_EXT_READL 1 + +#define REG_ARB_STATUS(apid) (0x0C600008U + 0x10000U * apid) +#define ARB_STATUS_DONE BIT(0) +#define ARB_STATUS_FAILURE BIT(1) +#define ARB_STATUS_DENIED BIT(2) +#define ARB_STATUS_DROPPED BIT(3) + +/* Fake status to report driver errors. */ +#define ARB_FAKE_STATUS_TIMEOUT BIT(8) + +#define REG_ARB_RDATA0(apid) (0x0C600018U + 0x10000U * apid) +#define REG_ARB_WDATA0(apid) (0x0C600010U + 0x10000U * apid) + +static int addr_to_apid(uint32_t addr) +{ + unsigned int i; + + for (i = 0U; i < NUM_APID; i++) { + uint32_t reg = mmio_read_32(REG_APID_MAP(i)); + if ((reg != 0U) && ((addr & PPID_MASK) == (reg & PPID_MASK))) { + return i; + } + } + + return -1; +} + +static int wait_for_done(uint16_t apid) +{ + unsigned int timeout = 100; + + while (timeout-- != 0U) { + uint32_t status = mmio_read_32(REG_ARB_STATUS(apid)); + if ((status & ARB_STATUS_DONE) != 0U) { + if ((status & ARB_STATUS_FAILURE) != 0U || + (status & ARB_STATUS_DENIED) != 0U || + (status & ARB_STATUS_DROPPED) != 0U) { + return status & 0xff; + } + return 0; + } + mdelay(1); + } + ERROR("SPMI_ARB timeout!\n"); + return ARB_FAKE_STATUS_TIMEOUT; +} + +static void arb_command(uint16_t apid, uint8_t opcode, uint32_t addr, + uint8_t bytes) +{ + mmio_write_32(REG_ARB_CMD(apid), (uint32_t)opcode << 27 | + (addr & 0xff) << 4 | (bytes - 1)); +} + +int spmi_arb_read8(uint32_t addr) +{ + int apid = addr_to_apid(addr); + + if (apid < 0) { + return apid; + } + + arb_command(apid, OPC_EXT_READL, addr, 1); + + int ret = wait_for_done(apid); + if (ret != 0) { + ERROR("SPMI_ARB read error [0x%x]: 0x%x\n", addr, ret); + return ret; + } + + return mmio_read_32(REG_ARB_RDATA0(apid)) & 0xff; +} + +int spmi_arb_write8(uint32_t addr, uint8_t data) +{ + int apid = addr_to_apid(addr); + + if (apid < 0) { + return apid; + } + + mmio_write_32(REG_ARB_WDATA0(apid), data); + arb_command(apid, OPC_EXT_WRITEL, addr, 1); + + int ret = wait_for_done(apid); + if (ret != 0) { + ERROR("SPMI_ARB write error [0x%x] = 0x%x: 0x%x\n", + addr, data, ret); + } + + return ret; +} diff --git a/plat/qti/mdm9607/platform.mk b/plat/qti/mdm9607/platform.mk new file mode 100644 index 0000000..4c6938c --- /dev/null +++ b/plat/qti/mdm9607/platform.mk @@ -0,0 +1,14 @@ +# +# Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> +# +# SPDX-License-Identifier: BSD-3-Clause +# + +ARM_ARCH_MAJOR := 7 +ARM_CORTEX_A7 := yes + +BL31_BASE ?= 0x87e00000 +PRELOADED_BL33_BASE ?= 0x82900000 +QTI_UART_NUM ?= 5 + +include plat/qti/msm8916/platform.mk diff --git a/plat/qti/mdm9607/sp_min/sp_min-mdm9607.mk b/plat/qti/mdm9607/sp_min/sp_min-mdm9607.mk new file mode 100644 index 0000000..28a6f01 --- /dev/null +++ b/plat/qti/mdm9607/sp_min/sp_min-mdm9607.mk @@ -0,0 +1,7 @@ +# +# Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include plat/qti/msm8916/sp_min/sp_min-msm8916.mk diff --git a/plat/qti/msm8909/platform.mk b/plat/qti/msm8909/platform.mk new file mode 100644 index 0000000..8a88aa5 --- /dev/null +++ b/plat/qti/msm8909/platform.mk @@ -0,0 +1,13 @@ +# +# Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> +# +# SPDX-License-Identifier: BSD-3-Clause +# + +ARM_ARCH_MAJOR := 7 +ARM_CORTEX_A7 := yes + +BL31_BASE ?= 0x87e80000 +QTI_UART_NUM ?= 1 + +include plat/qti/msm8916/platform.mk diff --git a/plat/qti/msm8909/sp_min/sp_min-msm8909.mk b/plat/qti/msm8909/sp_min/sp_min-msm8909.mk new file mode 100644 index 0000000..28a6f01 --- /dev/null +++ b/plat/qti/msm8909/sp_min/sp_min-msm8909.mk @@ -0,0 +1,7 @@ +# +# Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include plat/qti/msm8916/sp_min/sp_min-msm8916.mk diff --git a/plat/qti/msm8916/aarch32/msm8916_helpers.S b/plat/qti/msm8916/aarch32/msm8916_helpers.S new file mode 100644 index 0000000..dc35043 --- /dev/null +++ b/plat/qti/msm8916/aarch32/msm8916_helpers.S @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <platform_def.h> + +#include <msm8916_mmap.h> + +#if PLATFORM_CORE_COUNT > 1 +#define APCS_TCM_START_ADDR 0x10 +#else +#define APCS_TCM_START_ADDR 0x34 +#endif +#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: r0 - 1 on success, 0 on error + * Clobber list : r0 - r4 + * ------------------------------------------------- + */ +func plat_crash_console_init + ldr r1, =BLSP_UART_BASE + mov r0, #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 : r0 - character to be printed + * Out: r0 - printed character on success + * Clobber list : r1, r2 + * ------------------------------------------------- + */ +func plat_crash_console_putc + ldr r1, =BLSP_UART_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 : r1, r2 + * ------------------------------------------------- + */ +func plat_crash_console_flush + ldr r1, =BLSP_UART_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 */ + ldr r0, =MPM_PS_HOLD + mov r1, #0 + str r1, [r0] +1: b 1b +endfunc plat_panic_handler + + /* ------------------------------------------------- + * unsigned int plat_my_core_pos(void) + * Out: r0 - index of the calling CPU + * ------------------------------------------------- + */ +func plat_my_core_pos + .if PLATFORM_CORE_COUNT > 1 + ldcopr r1, MPIDR + and r0, r1, #MPIDR_CPU_MASK + .if PLATFORM_CLUSTER_COUNT > 1 + and r1, r1, #MPIDR_CLUSTER_MASK + orr r0, r0, r1, LSR #(MPIDR_AFFINITY_BITS - \ + PLATFORM_CPU_PER_CLUSTER_SHIFT) + .endif + .else + /* There is just a single core so always 0 */ + mov r0, #0 + .endif + bx lr +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: r0 - warm boot entry point or 0 on cold boot + * ------------------------------------------------- + */ +func plat_get_my_entrypoint + ldr r0, =msm8916_entry_point + ldr r0, [r0] + cmp r0, #0 + bxne lr + + /* + * Cold boot: Disable TCM redirect to L2 cache as early as + * possible to avoid crashes when making use of the cache. + */ + ldr r1, =APCS_CFG(0) + ldr r2, [r1, #APCS_TCM_START_ADDR] + and r2, r2, #~APCS_TCM_REDIRECT_EN_0 + str r2, [r1, #APCS_TCM_START_ADDR] + bx lr +endfunc plat_get_my_entrypoint + + /* ------------------------------------------------- + * 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 */ + bx lr +endfunc platform_mem_init + + .data + .align 3 + + /* ------------------------------------------------- + * Warm boot entry point for CPU. Set by PSCI code. + * ------------------------------------------------- + */ +msm8916_entry_point: + .word 0 diff --git a/plat/qti/msm8916/aarch32/uartdm_console.S b/plat/qti/msm8916/aarch32/uartdm_console.S new file mode 100644 index 0000000..a19776a --- /dev/null +++ b/plat/qti/msm8916/aarch32/uartdm_console.S @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> + * + * Based on aarch32/skeleton_console.S: + * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm_macros.S> +#include <console_macros.S> + +/* 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_32(2) /* TX FIFO has space */ +#define UART_DM_SR_TXEMT BIT_32(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 : r0 - pointer to empty console_t structure + * r1 - base address + * Out: r0 - 1 on success, 0 on error + * Clobber list : r0 - r7 + * ----------------------------------------------------------- + */ +func console_uartdm_register + str r1, [r0, #CONSOLE_T_BASE] + mov r7, lr + bl console_uartdm_core_init + mov lr, r7 + + /* 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 : r0 - unused + * r1 - base address + * Out: void + * Clobber list : r1, r2, r3 + * ----------------------------------------------------------- + */ +func console_uartdm_core_init + /* + * Try to flush remaining characters from the TX FIFO before resetting + * the transmitter. Unfortunately there is no good way to check if + * the transmitter is actually enabled (and will finish eventually), + * so use a timeout to avoid looping forever. + */ + mov r2, #65536 +1: + ldr r3, [r1, #UART_DM_SR] + tst r3, #UART_DM_SR_TXEMT + bne 2f + subs r2, r2, #1 + bne 1b + /* Timeout */ + +2: /* Reset receiver */ + mov r3, #UART_DM_CR_RESET_RX + str r3, [r1, #UART_DM_CR] + + /* Reset transmitter */ + mov r3, #UART_DM_CR_RESET_TX + str r3, [r1, #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 r3, #UART_DM_DMEN_TX_SC + str r3, [r1, #UART_DM_DMEN] + + /* Enable transmitter */ + mov r3, #UART_DM_CR_TX_ENABLE + str r3, [r1, #UART_DM_CR] + + bx lr +endfunc console_uartdm_core_init + + /* ----------------------------------------------------------- + * int console_uartdm_putc(int c, console_t *console) + * Function to output a character over the console. + * In : r0 - character to be printed + * r1 - pointer to console_t struct + * Out: r0 - printed character on success, < 0 on error. + * Clobber list : r0, r1, r2 + * ----------------------------------------------------------- + */ +func console_uartdm_putc + ldr r1, [r1, #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 : r0 - character to be printed + * r1 - base address + * Out: r0 - printed character on success, < 0 on error. + * Clobber list : r2 + * ----------------------------------------------------------- + */ +func console_uartdm_core_putc + cmp r0, #'\n' + bne 2f + +1: /* Loop until TX FIFO has space */ + ldr r2, [r1, #UART_DM_SR] + tst r2, #UART_DM_SR_TXRDY + beq 1b + + /* Prepend '\r' to '\n' */ + mov r2, #'\r' + str r2, [r1, #UART_DM_TF] + +2: /* Loop until TX FIFO has space */ + ldr r2, [r1, #UART_DM_SR] + tst r2, #UART_DM_SR_TXRDY + beq 2b + + /* Write character to FIFO */ + str r0, [r1, #UART_DM_TF] + bx lr +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 : r0 - pointer to console_t struct + * Out: void + * Clobber list : r0, r1, r2, r3, r4, r5 + * ----------------------------------------------------------- + */ +func console_uartdm_flush + ldr r1, [r0, #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 : r0 - unused + * r1 - base address + * Out: void + * Clobber list : r2 + * ----------------------------------------------------------- + */ +func console_uartdm_core_flush +1: /* Loop until TX FIFO is empty */ + ldr r2, [r1, #UART_DM_SR] + tst r2, #UART_DM_SR_TXEMT + beq 1b + bx lr +endfunc console_uartdm_core_flush diff --git a/plat/qti/msm8916/aarch64/msm8916_helpers.S b/plat/qti/msm8916/aarch64/msm8916_helpers.S new file mode 100644 index 0000000..de9438a --- /dev/null +++ b/plat/qti/msm8916/aarch64/msm8916_helpers.S @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <platform_def.h> + +#include <msm8916_mmap.h> + +#if PLATFORM_CORE_COUNT > 1 +#define APCS_TCM_START_ADDR 0x10 +#else +#define APCS_TCM_START_ADDR 0x34 +#endif +#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_imm x1, BLSP_UART_BASE + 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_imm x1, BLSP_UART_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_imm x1, BLSP_UART_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 + .if PLATFORM_CORE_COUNT > 1 + mrs x1, mpidr_el1 + and x0, x1, #MPIDR_CPU_MASK + .if PLATFORM_CLUSTER_COUNT > 1 + and x1, x1, #MPIDR_CLUSTER_MASK + orr x0, x0, x1, LSR #(MPIDR_AFFINITY_BITS - \ + PLATFORM_CPU_PER_CLUSTER_SHIFT) + .endif + .else + /* There is just a single core so always 0 */ + mov x0, #0 + .endif + 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 + cbz x0, 1f + ret +1: + /* + * Cold boot: Disable TCM redirect to L2 cache as early as + * possible to avoid crashes when making use of the cache. + */ + mov_imm x1, APCS_CFG(0) + ldr w2, [x1, #APCS_TCM_START_ADDR] + and w2, w2, #~APCS_TCM_REDIRECT_EN_0 + str w2, [x1, #APCS_TCM_START_ADDR] + + /* + * After reset the CPU always starts executing at the fixed reset + * address (0x0), which does not match the link address of BL31. + * The "boot remapper" redirects all memory accesses to the real + * physical address in DRAM. + * + * For warm boots, this is already handled by loading the real + * entry point address above. + * + * For cold boots, check if the CPU is using the boot remapper, + * i.e. if bl31_entrypoint appears to be at the reset address (0x0). + */ + adr x1, bl31_entrypoint + cbnz x1, 2f + + /* + * Add the real BL31_BASE offset to the return address in the link + * register so the CPU will continue at the real address after return. + */ + mov_imm x1, BL31_BASE + add lr, lr, x1 +2: + ret +endfunc plat_get_my_entrypoint + + /* ------------------------------------------------- + * 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..6c65daf --- /dev/null +++ b/plat/qti/msm8916/aarch64/uartdm_console.S @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> + * + * Based on aarch64/skeleton_console.S: + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm_macros.S> +#include <console_macros.S> + +/* 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 + /* + * Try to flush remaining characters from the TX FIFO before resetting + * the transmitter. Unfortunately there is no good way to check if + * the transmitter is actually enabled (and will finish eventually), + * so use a timeout to avoid looping forever. + */ + mov w2, #65536 +1: + ldr w3, [x1, #UART_DM_SR] + tbnz w3, #UART_DM_SR_TXEMT_BIT, 2f + subs w2, w2, #1 + b.ne 1b + /* Timeout */ + +2: /* 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 + cmp w0, #'\n' + b.ne 2f + +1: /* Loop until TX FIFO has space */ + ldr w2, [x1, #UART_DM_SR] + tbz w2, #UART_DM_SR_TXRDY_BIT, 1b + + /* Prepend '\r' to '\n' */ + mov w2, #'\r' + str w2, [x1, #UART_DM_TF] + +2: /* Loop until TX FIFO has space */ + ldr w2, [x1, #UART_DM_SR] + tbz w2, #UART_DM_SR_TXRDY_BIT, 2b + + /* 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..20c5a57 --- /dev/null +++ b/plat/qti/msm8916/include/msm8916_mmap.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_MMAP_H +#define MSM8916_MMAP_H + +#define PCNOC_BASE 0x00000000 +#define PCNOC_SIZE SZ_128M +#define APCS_BASE 0x0b000000 +#define APCS_SIZE SZ_8M + +#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 GPU_SMMU_BASE (PCNOC_BASE + 0x1f00000) + +#define BLSP1_BASE (PCNOC_BASE + 0x7880000) +#define BLSP1_UART_BASE(n) (BLSP1_BASE + 0x2f000 + (((n) - 1) * 0x1000)) +#define BLSP_UART_BASE BLSP1_UART_BASE(QTI_UART_NUM) + +#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_CLUSTER(cluster) (APCS_BASE + ((cluster) * 0x100000)) +#define _APCS_CPU(cluster, cpu) (_APCS_CLUSTER(cluster) + ((cpu) * 0x10000)) +#define APCS_CFG(cluster) (_APCS_CLUSTER(cluster) + 0x10000) +#define APCS_GLB(cluster) (_APCS_CLUSTER(cluster) + 0x11000) +#define APCS_L2_SAW2(cluster) (_APCS_CLUSTER(cluster) + 0x12000) +#define APCS_QTMR(cluster) (_APCS_CLUSTER(cluster) + 0x20000) +#define APCS_ALIAS_ACS(cluster, cpu) (_APCS_CPU(cluster, cpu) + 0x88000) +#define APCS_ALIAS_SAW2(cluster, cpu) (_APCS_CPU(cluster, cpu) + 0x89000) + +/* Only on platforms with multiple clusters (e.g. MSM8939) */ +#define APCS_CCI_BASE (APCS_BASE + 0x1c0000) +#define APCS_CCI_SAW2 (APCS_BASE + 0x1d2000) +#define APCS_CCI_ACS (APCS_BASE + 0x1d4000) + +#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 <arm_macros.S> + +#include <msm8916_mmap.h> + + /* --------------------------------------------- + * 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..a5baacd --- /dev/null +++ b/plat/qti/msm8916/include/platform_def.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include <plat/common/common_def.h> + +#ifdef __aarch64__ +/* + * 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 + SZ_128K) +#define BL31_PROGBITS_LIMIT (BL31_BASE + SZ_64K) +#endif +#define BL32_LIMIT (BL32_BASE + SZ_128K) + +#define CACHE_WRITEBACK_GRANULE U(64) +#define PLATFORM_STACK_SIZE SZ_4K + +/* CPU topology: one or two clusters with 4 cores each */ +#ifdef PLAT_msm8939 +#define PLATFORM_CLUSTER_COUNT U(2) +#else +#define PLATFORM_CLUSTER_COUNT U(1) +#endif +#if defined(PLAT_mdm9607) +#define PLATFORM_CPU_PER_CLUSTER_SHIFT U(0) /* 1 */ +#else +#define PLATFORM_CPU_PER_CLUSTER_SHIFT U(2) /* 4 */ +#endif +#define PLATFORM_CPUS_PER_CLUSTER (1 << PLATFORM_CPU_PER_CLUSTER_SHIFT) +#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \ + PLATFORM_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 */ +#define PLAT_SYSCNT_FREQ 19200000 +#define IRQ_SEC_PHY_TIMER (16 + 2) /* PPI #2 */ + +/* + * 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 <drivers/arm/gicv2.h> to avoid a failing assert(). + */ +#define GICD_PIDR2_GICV2 U(0xFD8) + +/* TSP */ +#define TSP_IRQ_SEC_PHY_TIMER IRQ_SEC_PHY_TIMER +#define TSP_SEC_MEM_BASE BL32_BASE +#define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE) + +#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 <stephan@gerhold.net> + * + * 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..c588020 --- /dev/null +++ b/plat/qti/msm8916/msm8916_bl31_setup.c @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch.h> +#include <common/debug.h> +#include <plat/common/platform.h> + +#include "msm8916_config.h" +#include "msm8916_setup.h" + +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), +}; + +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + msm8916_early_platform_setup(); + msm8916_configure_early(); +} + +void bl31_plat_arch_setup(void) +{ + msm8916_plat_arch_setup(BL31_BASE, BL31_END - BL31_BASE); + enable_mmu_el3(0); +} + +void bl31_platform_setup(void) +{ + INFO("BL31: Platform setup start\n"); + msm8916_platform_setup(); + msm8916_configure(); + 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_config.c b/plat/qti/msm8916/msm8916_config.c new file mode 100644 index 0000000..0ac604b --- /dev/null +++ b/plat/qti/msm8916/msm8916_config.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch.h> +#include <drivers/arm/cci.h> +#include <lib/mmio.h> + +#include "msm8916_config.h" +#include "msm8916_gicv2.h" +#include <msm8916_mmap.h> +#include <platform_def.h> + +static const int cci_map[] = { 3, 4 }; + +void msm8916_configure_early(void) +{ + if (PLATFORM_CLUSTER_COUNT > 1) { + cci_init(APCS_CCI_BASE, cci_map, ARRAY_SIZE(cci_map)); + cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); + } +} + +static void msm8916_configure_timer(uintptr_t base) +{ + /* Set timer frequency */ + mmio_write_32(base + CNTCTLBASE_CNTFRQ, PLAT_SYSCNT_FREQ); + + /* Make all timer frames available to non-secure world */ + mmio_write_32(base + CNTNSAR, GENMASK_32(7, 0)); +} + +/* + * 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) +#if PLATFORM_CORE_COUNT > 1 +#define APCS_BOOT_START_ADDR_SEC 0x04 +#define APCS_AA64NAA32_REG 0x0c +#else +#define APCS_BOOT_START_ADDR_SEC 0x18 +#endif +#define REMAP_EN BIT_32(0) + +static void msm8916_configure_apcs_cluster(unsigned int cluster) +{ + uintptr_t cfg = APCS_CFG(cluster); + unsigned int cpu; + + /* Disallow non-secure access to boot remapper / TCM registers */ + mmio_write_32(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(cluster), + APCS_GLB_SECURE_STS_NS | APCS_GLB_SECURE_PWR_NS); + + if (PLATFORM_CORE_COUNT > 1) { + /* Disallow non-secure access to L2 SAW2 */ + mmio_write_32(APCS_L2_SAW2(cluster), 0); + + /* Disallow non-secure access to CPU ACS and SAW2 */ + for (cpu = 0; cpu < PLATFORM_CPUS_PER_CLUSTER; cpu++) { + mmio_write_32(APCS_ALIAS_ACS(cluster, cpu), 0); + mmio_write_32(APCS_ALIAS_SAW2(cluster, cpu), 0); + } + } else { + /* There is just one core so no aliases exist */ + mmio_write_32(APCS_BANKED_ACS, 0); + mmio_write_32(APCS_BANKED_SAW2, 0); + } + +#ifdef __aarch64__ + /* 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(cfg + APCS_BOOT_START_ADDR_SEC, BL31_BASE | REMAP_EN); + mmio_write_32(cfg + APCS_AA64NAA32_REG, 1); +#else + /* Make sure all further warm boots end up in BL32 */ + CASSERT((BL32_BASE & 0xffff) == 0, assert_bl32_base_64k_aligned); + mmio_write_32(cfg + APCS_BOOT_START_ADDR_SEC, BL32_BASE | REMAP_EN); +#endif + + msm8916_configure_timer(APCS_QTMR(cluster)); +} + +static void msm8916_configure_apcs(void) +{ + unsigned int cluster; + + for (cluster = 0; cluster < PLATFORM_CLUSTER_COUNT; cluster++) { + msm8916_configure_apcs_cluster(cluster); + } + + if (PLATFORM_CLUSTER_COUNT > 1) { + /* Disallow non-secure access to CCI ACS and SAW2 */ + mmio_write_32(APCS_CCI_ACS, 0); + mmio_write_32(APCS_CCI_SAW2, 0); + } +} + +/* + * 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 CLK_OFF BIT_32(31) +#define GCC_APSS_TCU_CBCR (GCC_BASE + 0x12018) +#define GCC_GFX_TCU_CBCR (GCC_BASE + 0x12020) +#define GCC_SMMU_CFG_CBCR (GCC_BASE + 0x12038) +#define GCC_RPM_SMMU_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x3600c) +#define GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x4500c) +#define APSS_TCU_CLK_ENA BIT_32(1) +#define GFX_TCU_CLK_ENA BIT_32(2) +#define GFX_TBU_CLK_ENA BIT_32(3) +#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) + +#define SMMU_SACR 0x010 +#define SMMU_SACR_CACHE_LOCK BIT_32(26) +#define SMMU_IDR7 0x03c +#define SMMU_IDR7_MINOR(val) (((val) >> 0) & 0xf) +#define SMMU_IDR7_MAJOR(val) (((val) >> 4) & 0xf) + +static void msm8916_smmu_cache_unlock(uintptr_t smmu_base, uintptr_t clk_cbcr) +{ + uint32_t version; + + /* Wait for clock */ + while (mmio_read_32(clk_cbcr) & CLK_OFF) { + } + + version = mmio_read_32(smmu_base + SMMU_IDR7); + VERBOSE("SMMU(0x%lx) r%dp%d\n", smmu_base, + SMMU_IDR7_MAJOR(version), SMMU_IDR7_MINOR(version)); + + /* For SMMU r2p0+ clear CACHE_LOCK to allow writes to CBn_ACTLR */ + if (SMMU_IDR7_MAJOR(version) >= 2) { + mmio_clrbits_32(smmu_base + SMMU_SACR, SMMU_SACR_CACHE_LOCK); + } +} + +static void msm8916_configure_smmu(void) +{ + uint32_t ena_bits = APSS_TCU_CLK_ENA | SMMU_CFG_CLK_ENA; + + /* Single core (MDM) platforms do not have a GPU */ + if (PLATFORM_CORE_COUNT > 1) { + ena_bits |= GFX_TCU_CLK_ENA | GFX_TBU_CLK_ENA; + } + + /* Enable SMMU clocks to enable register access */ + mmio_write_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, ena_bits); + + /* Wait for configuration clock */ + 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); + + /* Clear sACR.CACHE_LOCK bit if needed for MMU-500 r2p0+ */ + msm8916_smmu_cache_unlock(APPS_SMMU_BASE, GCC_APSS_TCU_CBCR); + if (PLATFORM_CORE_COUNT > 1) { + msm8916_smmu_cache_unlock(GPU_SMMU_BASE, GCC_GFX_TCU_CBCR); + } + + /* + * Keep APCS vote for SMMU clocks for rest of booting process, but make + * sure other vote registers (such as RPM) do not keep permanent votes. + */ + VERBOSE("Clearing GCC_RPM_SMMU_CLOCK_BRANCH_ENA_VOTE (was: 0x%x)\n", + mmio_read_32(GCC_RPM_SMMU_CLOCK_BRANCH_ENA_VOTE)); + mmio_write_32(GCC_RPM_SMMU_CLOCK_BRANCH_ENA_VOTE, 0); +} + +void msm8916_configure(void) +{ + msm8916_gicv2_configure(); + msm8916_configure_apcs(); + msm8916_configure_smmu(); +} diff --git a/plat/qti/msm8916/msm8916_config.h b/plat/qti/msm8916/msm8916_config.h new file mode 100644 index 0000000..977d02c --- /dev/null +++ b/plat/qti/msm8916/msm8916_config.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_CONFIG_H +#define MSM8916_CONFIG_H + +void msm8916_configure(void); +void msm8916_configure_early(void); + +#endif /* MSM8916_CONFIG_H */ diff --git a/plat/qti/msm8916/msm8916_cpu_boot.c b/plat/qti/msm8916/msm8916_cpu_boot.c new file mode 100644 index 0000000..d6faa59 --- /dev/null +++ b/plat/qti/msm8916/msm8916_cpu_boot.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2021-2022, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#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) + +#define PWR_CTL_OVERRIDE 0xc +#define L2_PWR_CTL 0x14 +#define L2_PWR_STATUS 0x18 +#define CORE_CBCR 0x58 + +#define PWR_CTL_OVERRIDE_PRESETDBG BIT_32(22) + +#define L2_PWR_CTL_L2_ARRAY_HS BIT_32(0) +#define L2_PWR_CTL_SCU_ARRAY_HS BIT_32(1) +#define L2_PWR_CTL_L2_RST_DIS BIT_32(2) +#define L2_PWR_CTL_L2_HS_CLAMP BIT_32(8) +#define L2_PWR_CTL_L2_HS_EN BIT_32(9) +#define L2_PWR_CTL_L2_HS_RST BIT_32(10) +#define L2_PWR_CTL_L2_SLEEP_STATE BIT_32(11) +#define L2_PWR_CTL_SYS_RESET BIT_32(12) +#define L2_PWR_CTL_L2_RET_SLP BIT_32(13) +#define L2_PWR_CTL_SCU_ARRAY_HS_CLAMP BIT_32(14) +#define L2_PWR_CTL_L2_ARRAY_HS_CLAMP BIT_32(15) +#define L2_PWR_CTL_L2_HS_CNT(cnt) ((cnt) << 16) +#define L2_PWR_CTL_PMIC_APC_ON BIT_32(28) + +#define L2_PWR_STATUS_L2_HS_STS BIT_32(9) + +#define CORE_CBCR_CLK_ENABLE BIT_32(0) +#define CORE_CBCR_HW_CTL BIT_32(1) + +/* Boot a secondary CPU core for the first time. */ +void msm8916_cpu_boot(uintptr_t acs) +{ + uint32_t pwr_ctl; + + VERBOSE("PSCI: Powering on CPU @ 0x%08lx\n", acs); + + 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(); +} + +/* Power on cluster L2 cache for the first time. */ +void msm8916_l2_boot(uintptr_t base) +{ + uint32_t pwr_ctl, cbcr, ovr; + + /* Skip if cluster L2 is already powered on */ + if (mmio_read_32(base + L2_PWR_STATUS) & L2_PWR_STATUS_L2_HS_STS) { + VERBOSE("PSCI: L2 cache @ 0x%08lx is already powered on\n", base); + return; + } + + VERBOSE("PSCI: Powering on L2 cache @ 0x%08lx\n", base); + + pwr_ctl = L2_PWR_CTL_L2_HS_CLAMP | L2_PWR_CTL_L2_HS_EN | + L2_PWR_CTL_L2_HS_RST | L2_PWR_CTL_SYS_RESET | + L2_PWR_CTL_SCU_ARRAY_HS_CLAMP | L2_PWR_CTL_L2_ARRAY_HS_CLAMP | + L2_PWR_CTL_L2_HS_CNT(16); + mmio_write_32(base + L2_PWR_CTL, pwr_ctl); + + ovr = PWR_CTL_OVERRIDE_PRESETDBG; + mmio_write_32(base + PWR_CTL_OVERRIDE, ovr); + dsb(); + udelay(2); + + pwr_ctl &= ~(L2_PWR_CTL_SCU_ARRAY_HS_CLAMP | + L2_PWR_CTL_L2_ARRAY_HS_CLAMP); + mmio_write_32(base + L2_PWR_CTL, pwr_ctl); + + pwr_ctl |= (L2_PWR_CTL_L2_ARRAY_HS | L2_PWR_CTL_SCU_ARRAY_HS); + mmio_write_32(base + L2_PWR_CTL, pwr_ctl); + dsb(); + udelay(2); + + cbcr = CORE_CBCR_CLK_ENABLE; + mmio_write_32(base + CORE_CBCR, cbcr); + + pwr_ctl &= ~L2_PWR_CTL_L2_HS_CLAMP; + mmio_write_32(base + L2_PWR_CTL, pwr_ctl); + dsb(); + udelay(2); + + ovr &= ~PWR_CTL_OVERRIDE_PRESETDBG; + mmio_write_32(base + PWR_CTL_OVERRIDE, ovr); + + pwr_ctl &= ~(L2_PWR_CTL_L2_HS_RST | L2_PWR_CTL_SYS_RESET); + mmio_write_32(base + L2_PWR_CTL, pwr_ctl); + dsb(); + udelay(54); + + pwr_ctl |= L2_PWR_CTL_PMIC_APC_ON; + mmio_write_32(base + L2_PWR_CTL, pwr_ctl); + + cbcr |= CORE_CBCR_HW_CTL; + mmio_write_32(base + CORE_CBCR, cbcr); + dsb(); +} diff --git a/plat/qti/msm8916/msm8916_gicv2.c b/plat/qti/msm8916/msm8916_gicv2.c new file mode 100644 index 0000000..82cecf2 --- /dev/null +++ b/plat/qti/msm8916/msm8916_gicv2.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/debug.h> +#include <drivers/arm/gicv2.h> +#include <lib/mmio.h> + +#include "msm8916_gicv2.h" +#include <msm8916_mmap.h> +#include <platform_def.h> + +#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 + +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); +} + +void msm8916_gicv2_configure(void) +{ + 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..919e294 --- /dev/null +++ b/plat/qti/msm8916/msm8916_gicv2.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_GICV2_H +#define MSM8916_GICV2_H + +void msm8916_gicv2_init(void); +void msm8916_gicv2_configure(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..fd44f04 --- /dev/null +++ b/plat/qti/msm8916/msm8916_pm.c @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2021-2022, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/cci.h> +#include <drivers/arm/gicv2.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> +#include <lib/psci/psci.h> +#include <plat/common/platform.h> + +#include <msm8916_mmap.h> +#include "msm8916_pm.h" + +/* + * On platforms with two clusters the index of the APCS memory region is swapped + * compared to the MPIDR cluster affinity level: APCS cluster 0 manages CPUs + * with cluster affinity level 1, while APCS cluster 1 manages CPUs with level 0. + * + * On platforms with a single cluster there is only one APCS memory region. + */ +#if PLATFORM_CLUSTER_COUNT == 2 +#define MPIDR_APCS_CLUSTER(mpidr) !MPIDR_AFFLVL1_VAL(mpidr) +#else +#define MPIDR_APCS_CLUSTER(mpidr) 0 +#endif + +#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1]) + +static int msm8916_pwr_domain_on(u_register_t mpidr) +{ + /* Should be never called on single-core platforms */ + if (PLATFORM_CORE_COUNT == 1) { + assert(false); + return PSCI_E_ALREADY_ON; + } + + /* Power on L2 cache and secondary CPU core for the first time */ + if (PLATFORM_CLUSTER_COUNT > 1) { + msm8916_l2_boot(APCS_GLB(MPIDR_APCS_CLUSTER(mpidr))); + } + msm8916_cpu_boot(APCS_ALIAS_ACS(MPIDR_APCS_CLUSTER(mpidr), + MPIDR_AFFLVL0_VAL(mpidr))); + return PSCI_E_SUCCESS; +} + +static void msm8916_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + /* Should be never called on single-core platforms */ + if (PLATFORM_CORE_COUNT == 1) { + assert(false); + return; + } + + if (PLATFORM_CLUSTER_COUNT > 1 && + CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { + cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); + } + + 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) +{ + /* + * The entry point is read with caches off (and even from two different + * physical addresses when read through the "boot remapper"), so make + * sure it is flushed to memory. + */ + msm8916_entry_point = sec_entrypoint; + flush_dcache_range((uintptr_t)&msm8916_entry_point, sizeof(uintptr_t)); + + *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..f301d3c --- /dev/null +++ b/plat/qti/msm8916/msm8916_pm.h @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2021-2022, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_PM_H +#define MSM8916_PM_H + +void msm8916_cpu_boot(uintptr_t acs); +void msm8916_l2_boot(uintptr_t base); + +#endif /* MSM8916_PM_H */ diff --git a/plat/qti/msm8916/msm8916_setup.c b/plat/qti/msm8916/msm8916_setup.c new file mode 100644 index 0000000..69c0d78 --- /dev/null +++ b/plat/qti/msm8916/msm8916_setup.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/bl_common.h> +#include <drivers/console.h> +#include <drivers/generic_delay_timer.h> +#include <lib/mmio.h> +#include <lib/xlat_tables/xlat_mmu_helpers.h> +#include <lib/xlat_tables/xlat_tables_v2.h> + +#include "msm8916_gicv2.h" +#include <msm8916_mmap.h> +#include "msm8916_setup.h" +#include <uartdm_console.h> + +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 console_t console; + +unsigned int plat_get_syscnt_freq2(void) +{ + return PLAT_SYSCNT_FREQ; +} + +#define GPIO_CFG_FUNC(n) ((n) << 2) +#define GPIO_CFG_DRV_STRENGTH_MA(ma) (((ma) / 2 - 1) << 6) + +#define CLK_ENABLE BIT_32(0) +#define CLK_OFF BIT_32(31) +#define GCC_BLSP1_AHB_CBCR (GCC_BASE + 0x01008) +#define GCC_BLSP1_UART_APPS_CBCR(n) (GCC_BASE + \ + (((n) == 2) ? (0x0302c) : (0x0203c + (((n) - 1) * 0x1000)))) +#define GCC_APCS_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x45004) +#define BLSP1_AHB_CLK_ENA BIT_32(10) + +struct uartdm_gpios { + unsigned int tx, rx, func; +}; + +static const struct uartdm_gpios uartdm_gpio_map[] = { +#if defined(PLAT_msm8909) + {4, 5, 0x2}, {20, 21, 0x3}, +#elif defined(PLAT_msm8916) || defined(PLAT_msm8939) + {0, 1, 0x2}, {4, 5, 0x2}, +#elif defined(PLAT_mdm9607) + {12, 13, 0x2}, {4, 5, 0x2}, {0, 1, 0x1}, + {16, 17, 0x2}, {8, 9, 0x2}, {20, 21, 0x2}, +#endif +}; + +/* + * 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_uart(void) +{ + const struct uartdm_gpios *gpios = &uartdm_gpio_map[QTI_UART_NUM - 1]; + + CASSERT(QTI_UART_NUM > 0 && QTI_UART_NUM <= ARRAY_SIZE(uartdm_gpio_map), + assert_qti_blsp_uart_valid); + + /* Route GPIOs to BLSP UART */ + mmio_write_32(TLMM_GPIO_CFG(gpios->tx), GPIO_CFG_FUNC(gpios->func) | + GPIO_CFG_DRV_STRENGTH_MA(8)); + mmio_write_32(TLMM_GPIO_CFG(gpios->rx), GPIO_CFG_FUNC(gpios->func) | + GPIO_CFG_DRV_STRENGTH_MA(8)); + + /* 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 UART clock */ + mmio_setbits_32(GCC_BLSP1_UART_APPS_CBCR(QTI_UART_NUM), CLK_ENABLE); + while (mmio_read_32(GCC_BLSP1_UART_APPS_CBCR(QTI_UART_NUM)) & CLK_OFF) { + } +} + +void msm8916_early_platform_setup(void) +{ + /* Initialize the debug console as early as possible */ + msm8916_enable_blsp_uart(); + console_uartdm_register(&console, BLSP_UART_BASE); + + if (QTI_RUNTIME_UART) { + /* Mark UART as runtime usable */ + console_set_scope(&console, CONSOLE_FLAG_BOOT | + CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH); + } +} + +void msm8916_plat_arch_setup(uintptr_t base, size_t size) +{ + mmap_add_region(base, base, size, 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(); +} + +void msm8916_platform_setup(void) +{ + generic_delay_timer_init(); + msm8916_gicv2_init(); +} diff --git a/plat/qti/msm8916/msm8916_setup.h b/plat/qti/msm8916/msm8916_setup.h new file mode 100644 index 0000000..d2de943 --- /dev/null +++ b/plat/qti/msm8916/msm8916_setup.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_SETUP_H +#define MSM8916_SETUP_H + +void msm8916_early_platform_setup(void); +void msm8916_plat_arch_setup(uintptr_t base, size_t size); +void msm8916_platform_setup(void); + +#endif /* MSM8916_SETUP_H */ diff --git a/plat/qti/msm8916/msm8916_topology.c b/plat/qti/msm8916/msm8916_topology.c new file mode 100644 index 0000000..d8cdc0e --- /dev/null +++ b/plat/qti/msm8916/msm8916_topology.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022, Stephan Gerhold <stephan@gerhold.net> + * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <plat/common/platform.h> + +#include <platform_def.h> + +static const unsigned char plat_power_domain_tree_desc[] = { + PLATFORM_SYSTEM_COUNT, + PLATFORM_CLUSTER_COUNT, + PLATFORM_CPUS_PER_CLUSTER, +#if PLATFORM_CLUSTER_COUNT > 1 + PLATFORM_CPUS_PER_CLUSTER, +#endif +}; + +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr); + unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); + + if (MPIDR_AFFLVL3_VAL(mpidr) > 0 || + MPIDR_AFFLVL2_VAL(mpidr) > 0 || + cluster >= PLATFORM_CLUSTER_COUNT || + core >= PLATFORM_CPUS_PER_CLUSTER) { + return -1; + } + return core | (cluster << PLATFORM_CPU_PER_CLUSTER_SHIFT); +} + +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..c71ad94 --- /dev/null +++ b/plat/qti/msm8916/platform.mk @@ -0,0 +1,98 @@ +# +# Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net> +# +# 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 := ${GICV2_SOURCES} \ + ${XLAT_TABLES_LIB_SRCS} \ + drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ + plat/common/plat_gicv2.c \ + plat/qti/msm8916/msm8916_gicv2.c \ + plat/qti/msm8916/msm8916_setup.c \ + plat/qti/msm8916/${ARCH}/msm8916_helpers.S \ + plat/qti/msm8916/${ARCH}/uartdm_console.S + +MSM8916_CPU := $(if ${ARM_CORTEX_A7},cortex_a7,cortex_a53) +MSM8916_PM_SOURCES := drivers/arm/cci/cci.c \ + lib/cpus/${ARCH}/${MSM8916_CPU}.S \ + plat/common/plat_psci_common.c \ + plat/qti/msm8916/msm8916_config.c \ + plat/qti/msm8916/msm8916_cpu_boot.c \ + plat/qti/msm8916/msm8916_pm.c \ + plat/qti/msm8916/msm8916_topology.c + +BL31_SOURCES += ${MSM8916_PM_SOURCES} \ + plat/qti/msm8916/msm8916_bl31_setup.c + +PLAT_INCLUDES := -Iplat/qti/msm8916/include + +ifeq (${ARCH},aarch64) +# arm_macros.S exists only on aarch64 currently +PLAT_INCLUDES += -Iinclude/plat/arm/common/${ARCH} +endif + +# Only BL31 is supported at the moment and is entered on a single CPU +RESET_TO_BL31 := 1 +COLD_BOOT_SINGLE_CPU := 1 + +# 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_SPE_FOR_NS := 0 +ENABLE_SVE_FOR_NS := 0 + +# Disable workarounds unnecessary for Cortex-A7/A53 +WORKAROUND_CVE_2017_5715 := 0 +WORKAROUND_CVE_2022_23960 := 0 + +ifeq (${MSM8916_CPU},cortex_a53) +# The Cortex-A53 revision varies depending on the SoC revision. +# msm8916 uses r0p0, msm8939 uses r0p1 or r0p4. Enable all errata +# and rely on the runtime detection to apply them only if needed. +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 := 1 +ERRATA_A53_1530924 := 1 +endif + +# Build config flags +# ------------------ +BL31_BASE ?= 0x86500000 +PRELOADED_BL33_BASE ?= 0x8f600000 + +ifeq (${ARCH},aarch64) + BL32_BASE ?= BL31_LIMIT + $(eval $(call add_define,BL31_BASE)) +else + ifeq (${AARCH32_SP},none) + $(error Variable AARCH32_SP has to be set for AArch32) + endif + # There is no BL31 on aarch32, so reuse its location for BL32 + BL32_BASE ?= $(BL31_BASE) +endif +$(eval $(call add_define,BL32_BASE)) + +# UART number to use for TF-A output during early boot +QTI_UART_NUM ?= 2 +$(eval $(call assert_numeric,QTI_UART_NUM)) +$(eval $(call add_define,QTI_UART_NUM)) + +# Set to 1 on the command line to keep using UART after early boot. +# Requires reserving the UART and related clocks inside the normal world. +QTI_RUNTIME_UART ?= 0 +$(eval $(call assert_boolean,QTI_RUNTIME_UART)) +$(eval $(call add_define,QTI_RUNTIME_UART)) diff --git a/plat/qti/msm8916/sp_min/msm8916_sp_min_setup.c b/plat/qti/msm8916/sp_min/msm8916_sp_min_setup.c new file mode 100644 index 0000000..3c93305 --- /dev/null +++ b/plat/qti/msm8916/sp_min/msm8916_sp_min_setup.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <common/debug.h> +#include <lib/xlat_tables/xlat_mmu_helpers.h> +#include <platform_sp_min.h> + +#include "../msm8916_config.h" +#include "../msm8916_setup.h" + +static struct { + entry_point_info_t bl33; +} image_ep_info = { + /* 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_MODE32(MODE32_hyp, SPSR_T_ARM, SPSR_E_LITTLE, + DISABLE_ALL_EXCEPTIONS), +}; + +void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + msm8916_early_platform_setup(); + msm8916_configure_early(); +} + +void sp_min_plat_arch_setup(void) +{ + msm8916_plat_arch_setup(BL32_BASE, BL32_END - BL32_BASE); + enable_mmu_svc_mon(0); +} + +void sp_min_platform_setup(void) +{ + INFO("SP_MIN: Platform setup start\n"); + msm8916_platform_setup(); + msm8916_configure(); + INFO("SP_MIN: Platform setup done\n"); +} + +entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) +{ + return &image_ep_info.bl33; +} diff --git a/plat/qti/msm8916/sp_min/sp_min-msm8916.mk b/plat/qti/msm8916/sp_min/sp_min-msm8916.mk new file mode 100644 index 0000000..be07f94 --- /dev/null +++ b/plat/qti/msm8916/sp_min/sp_min-msm8916.mk @@ -0,0 +1,11 @@ +# +# Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> +# +# SPDX-License-Identifier: BSD-3-Clause +# + +BL32_SOURCES += ${MSM8916_PM_SOURCES} \ + plat/common/${ARCH}/platform_mp_stack.S \ + plat/qti/msm8916/sp_min/msm8916_sp_min_setup.c + +override RESET_TO_SP_MIN := 1 diff --git a/plat/qti/msm8916/tsp/msm8916_tsp_setup.c b/plat/qti/msm8916/tsp/msm8916_tsp_setup.c new file mode 100644 index 0000000..218af57 --- /dev/null +++ b/plat/qti/msm8916/tsp/msm8916_tsp_setup.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023, Stephan Gerhold <stephan@gerhold.net> + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/debug.h> +#include <platform_tsp.h> + +#include "../msm8916_setup.h" +#include <platform_def.h> + +void tsp_early_platform_setup(void) +{ + msm8916_early_platform_setup(); +} + +void tsp_plat_arch_setup(void) +{ + msm8916_plat_arch_setup(BL32_BASE, BL32_END - BL32_BASE); + enable_mmu_el1(0); +} + +void tsp_platform_setup(void) +{ + INFO("TSP: Platform setup start\n"); + msm8916_platform_setup(); + INFO("TSP: Platform setup done\n"); + + console_switch_state(CONSOLE_FLAG_RUNTIME); +} diff --git a/plat/qti/msm8916/tsp/tsp-msm8916.mk b/plat/qti/msm8916/tsp/tsp-msm8916.mk new file mode 100644 index 0000000..0d50058 --- /dev/null +++ b/plat/qti/msm8916/tsp/tsp-msm8916.mk @@ -0,0 +1,8 @@ +# +# Copyright (c) 2023, Stephan Gerhold <stephan@gerhold.net> +# +# SPDX-License-Identifier: BSD-3-Clause +# + +BL32_SOURCES += plat/common/${ARCH}/platform_mp_stack.S \ + plat/qti/msm8916/tsp/msm8916_tsp_setup.c diff --git a/plat/qti/msm8939/platform.mk b/plat/qti/msm8939/platform.mk new file mode 100644 index 0000000..9bf6d4d --- /dev/null +++ b/plat/qti/msm8939/platform.mk @@ -0,0 +1,11 @@ +# +# Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# Cache cannot be enabled early on MSM8939 because the CCI-400 must be +# enabled before the CPUs in both clusters become cache-coherent. +override WARMBOOT_ENABLE_DCACHE_EARLY := 0 + +include plat/qti/msm8916/platform.mk diff --git a/plat/qti/msm8939/sp_min/sp_min-msm8939.mk b/plat/qti/msm8939/sp_min/sp_min-msm8939.mk new file mode 100644 index 0000000..28a6f01 --- /dev/null +++ b/plat/qti/msm8939/sp_min/sp_min-msm8939.mk @@ -0,0 +1,7 @@ +# +# Copyright (c) 2022-2023, Stephan Gerhold <stephan@gerhold.net> +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include plat/qti/msm8916/sp_min/sp_min-msm8916.mk diff --git a/plat/qti/msm8939/tsp/tsp-msm8939.mk b/plat/qti/msm8939/tsp/tsp-msm8939.mk new file mode 100644 index 0000000..4eefc64 --- /dev/null +++ b/plat/qti/msm8939/tsp/tsp-msm8939.mk @@ -0,0 +1,7 @@ +# +# Copyright (c) 2023, Stephan Gerhold <stephan@gerhold.net> +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include plat/qti/msm8916/tsp/tsp-msm8916.mk 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 <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include <qtiseclib_defs.h> + +/* 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 <stdint.h> + +#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 <stdbool.h> +#include <stdint.h> + +#include <qtiseclib_defs.h> + +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 <assert.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <bl31/bl31.h> +#include <context.h> +#include <drivers/arm/gicv3.h> +#include <drivers/delay_timer.h> +#include <lib/coreboot.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <lib/spinlock.h> +#include <lib/xlat_tables/xlat_tables_v2.h> + +#include <platform.h> +#include <qti_plat.h> +#include <qtiseclib_cb_interface.h> + +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 <stdbool.h> +#include <stdint.h> + +#include <common/debug.h> + +#include <qtiseclib_defs.h> +#include <qtiseclib_interface.h> + +/* + * 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 <common_def.h> + +#include <qti_board_def.h> +#include <qtiseclib_defs_plat.h> + +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/* + * 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 <stdint.h> + +#include <qti_plat.h> + +#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 <stdint.h> + +/* + * 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..b576649 --- /dev/null +++ b/plat/qti/sc7180/platform.mk @@ -0,0 +1,126 @@ +# +# 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 + +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 <common_def.h> + +#include <qti_board_def.h> +#include <qtiseclib_defs_plat.h> + +/*----------------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------------*/ +/* + * 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 <stdint.h> + +#include <qti_plat.h> + +#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 <stdint.h> + +/* + * 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..3d7d728 --- /dev/null +++ b/plat/qti/sc7280/platform.mk @@ -0,0 +1,129 @@ +# +# 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 +PSCI_OS_INIT_MODE := 1 + +COLD_BOOT_SINGLE_CPU := 1 +PROGRAMMABLE_RESET_ADDRESS := 1 + +RESET_TO_BL31 := 0 + +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 + |