From fa145398b7efe1d4f5cf520e2ada56ae48f4aeac Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 1 Dec 2021 20:00:00 +0100 Subject: [PATCH 1/5] docs(msm8916): new port for Qualcomm Snapdragon 410 The Qualcomm Snapdragon 410 is Qualcomm's first 64-bit SoC, released in 2014 with four ARM Cortex-A53 cores. There are differents variants (MSM8916, APQ8016(E), ...) that are all very similar. A popular device based on APQ8016E is the DragonBoard 410c single-board computer, but the SoC is also used in various mid-range smartphones/tablets. This commit adds documentation for a minimal, community-maintained port of TF-A/BL31 for MSM8916. The actual platform port is added in the following four separate small commits to simplify the review process. The code is primarily based on the information from the public Snapdragon 410E Technical Reference Manual [1], combined with a lot of trial and error to actually make it work. Note that this port is a pure community effort without any commercial interests and is not related to Qualcomm in any way. The main motivation for this port is to have a minimal, updatable firmware since this old chip does not receive many updates anymore from Qualcomm. It works quite well for many use cases so I am willing to maintain it as a "code owner". I have also added Nikita Travkin as second code owner to help with reviews. The main limitation so far is the lack of memory protection for TF-A. This is similar to the ports for the Raspberry Pi but in this case not a lack of hardware support but rather a lack of documentation. However, this does not limit the usefulness of the port when used as a minimal PSCI implementation. [1]: https://developer.qualcomm.com/download/sd410/snapdragon-410e-technical-reference-manual.pdf Change-Id: I676adf86061638cfc2f3ae8615470d145e84f172 Signed-off-by: Stephan Gerhold --- changelog.yaml | 3 + docs/about/maintainers.rst | 11 ++++ docs/plat/index.rst | 1 + docs/plat/qti-msm8916.rst | 116 +++++++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 docs/plat/qti-msm8916.rst diff --git a/changelog.yaml b/changelog.yaml index 93785a90f..c4ed59b9e 100644 --- a/changelog.yaml +++ b/changelog.yaml @@ -348,6 +348,9 @@ subsections: deprecated: - plat/qti/sc7280 + - title: MSM8916 + scope: msm8916 + - title: Raspberry Pi scope: rpi diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst index e0a758797..94c63f43f 100644 --- a/docs/about/maintainers.rst +++ b/docs/about/maintainers.rst @@ -580,6 +580,15 @@ QTI platform port :|F|: docs/plat/qti.rst :|F|: plat/qti/ +QTI MSM8916 platform port +^^^^^^^^^^^^^^^^^^^^^^^^^ +:|M|: Stephan Gerhold +:|G|: `stephan-gh`_ +:|M|: Nikita Travkin +:|G|: `TravMurav`_ +:|F|: docs/plat/qti-msm8916.rst +:|F|: plat/qti/msm8916/ + Raspberry Pi 3 platform port ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :|M|: Ying-Chun Liu (PaulLiu) @@ -797,9 +806,11 @@ Conventional Changelog Extensions .. _smaeul: https://github.com/smaeul .. _soby-mathew: https://github.com/soby-mathew .. _sreekare: https://github.com/sreekare +.. _stephan-gh: https://github.com/stephan-gh .. _thloh85-intel: https://github.com/thloh85-intel .. _thomas-arm: https://github.com/thomas-arm .. _TonyXie06: https://github.com/TonyXie06 +.. _TravMurav: https://github.com/TravMurav .. _vwadekar: https://github.com/vwadekar .. _venkatesh: https://github.com/vabbarap .. _Yann-lms: https://github.com/Yann-lms diff --git a/docs/plat/index.rst b/docs/plat/index.rst index 57cc48804..0cef16a34 100644 --- a/docs/plat/index.rst +++ b/docs/plat/index.rst @@ -32,6 +32,7 @@ Platform Ports qemu qemu-sbsa qti + qti-msm8916 rpi3 rpi4 rcar-gen3 diff --git a/docs/plat/qti-msm8916.rst b/docs/plat/qti-msm8916.rst new file mode 100644 index 000000000..09a79b75e --- /dev/null +++ b/docs/plat/qti-msm8916.rst @@ -0,0 +1,116 @@ +Qualcomm Snapdragon 410 (MSM8916/APQ8016) +========================================= + +The `Qualcomm Snapdragon 410`_ is Qualcomm's first 64-bit SoC, released in 2014 +with four ARM Cortex-A53 cores. There are differents variants (MSM8916, +APQ8016(E), ...) that are all very similar. A popular device based on APQ8016E +is the `DragonBoard 410c`_ single-board computer, but the SoC is also used in +various mid-range smartphones/tablets. + +The TF-A/BL31 port for MSM8916 provides a minimal, community-maintained +EL3 firmware. It is primarily based on information from the public +`Snapdragon 410E Technical Reference Manual`_ combined with a lot of +trial and error to actually make it work. + +.. note:: + Unlike the :doc:`QTI SC7180/SC7280 ` ports, this port does **not** + make use of a proprietary binary components (QTISECLIB). It is fully + open-source but therefore limited to publicly documented hardware + components. + +Functionality +------------- + +The BL31 port is much more minimal compared to the original firmware and +therefore expects the non-secure world (e.g. Linux) to manage more hardware, +such as the SMMUs and all remote processors (RPM, WCNSS, Venus, Modem). +Everything except modem is currently functional with a slightly modified version +of mainline Linux. + +.. warning:: + This port is **not secure**. There is no special secure memory and the + used DRAM is available from both the non-secure and secure worlds. + Unfortunately, the hardware used for memory protection is not described + in the APQ8016E documentation. + +The port is primarily intended as a minimal PSCI implementation (without a +separate secure world) where this limitation is not a big problem. Booting +secondary CPU cores (PSCI ``CPU_ON``) is supported. Basic CPU core power +management (``CPU_SUSPEND``) is functional but still work-in-progress and +will be added later once ready. + +Boot Flow +--------- +BL31 replaces the original ``tz`` firmware in the boot flow:: + + Boot ROM (PBL) -> SBL -> BL31 (EL3) -> U-Boot (EL2) -> Linux (EL2) + +By default, BL31 enters the non-secure world in EL2 AArch64 state at address +``0x8f600000``. The original hypervisor firmware (``hyp``) is not used, you can +use KVM or another hypervisor. The entry address is fixed in the BL31 binary +but can be changed using the ``PRELOADED_BL33_BASE`` make file parameter. + +Using an AArch64 bootloader (such as `U-Boot for DragonBoard 410c`_) is +recommended. AArch32 bootloaders (such as the original Little Kernel bootloader +from Qualcomm) are not directly supported, although it is possible to use an EL2 +shim loader to temporarily switch to AArch32 state. + +Installation +------------ +First, setup the cross compiler for AArch64 and build TF-A for ``msm8916``:: + + $ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=msm8916 + +The BL31 ELF image is generated in ``build/msm8916/release/bl31/bl31.elf``. +This image must be "signed" before flashing it, even if the board has secure +boot disabled. In this case the signature does not provide any security, +but it provides the firmware with required metadata. + +The `DragonBoard 410c`_ does not have secure boot enabled by default. In this +case you can simply sign the ELF image using a randomly generated key. You can +use e.g. `qtestsign`_:: + + $ ./qtestsign.py tz build/msm8916/release/bl31/bl31.elf + +Then install the resulting ``build/msm8916/release/bl31/bl31-test-signed.mbn`` +to the ``tz`` partition on the device. BL31 should be running after a reboot. + +.. warning:: + Do not flash incorrectly signed firmware on devices that have secure + boot enabled! Make sure that you have a way to recover the board in case + of problems (e.g. using EDL). + +Boot Trace +---------- +BL31 prints some lines on the debug console UART2, which will usually look like +this (with ``DEBUG=1``, otherwise only the ``NOTICE`` lines are shown):: + + ... + S - DDR Frequency, 400 MHz + NOTICE: BL31: v2.6(debug):v2.6 + NOTICE: BL31: Built : 20:00:00, Dec 01 2021 + INFO: BL31: Platform setup start + INFO: ARM GICv2 driver initialized + INFO: BL31: Platform setup done + INFO: BL31: Initializing runtime services + INFO: BL31: cortex_a53: CPU workaround for 819472 was applied + INFO: BL31: cortex_a53: CPU workaround for 824069 was applied + INFO: BL31: cortex_a53: CPU workaround for 826319 was applied + INFO: BL31: cortex_a53: CPU workaround for 827319 was applied + INFO: BL31: cortex_a53: CPU workaround for 835769 was applied + INFO: BL31: cortex_a53: CPU workaround for disable_non_temporal_hint was applied + INFO: BL31: cortex_a53: CPU workaround for 843419 was applied + INFO: BL31: cortex_a53: CPU workaround for 1530924 was applied + INFO: BL31: Preparing for EL3 exit to normal world + INFO: Entry point address = 0x8f600000 + INFO: SPSR = 0x3c9 + + U-Boot 2021.10 (Dec 01 2021 - 20:00:00 +0000) + Qualcomm-DragonBoard 410C + ... + +.. _Qualcomm Snapdragon 410: https://www.qualcomm.com/products/snapdragon-processors-410 +.. _DragonBoard 410c: https://www.96boards.org/product/dragonboard410c/ +.. _Snapdragon 410E Technical Reference Manual: https://developer.qualcomm.com/download/sd410/snapdragon-410e-technical-reference-manual.pdf +.. _U-Boot for DragonBoard 410c: https://u-boot.readthedocs.io/en/latest/board/qualcomm/dragonboard410c.html +.. _qtestsign: https://github.com/msm8916-mainline/qtestsign From dddba19a6a3cb7a1039beaffc3169c4eb3291afd Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 1 Dec 2021 20:01:11 +0100 Subject: [PATCH 2/5] feat(msm8916): initial platform port Introduce the bare mimimum base of the msm8916 BL31 port. This is pretty much just a standard platform "skeleton" with CPU/memory initialization and an UART driver. This allows booting into e.g. U-Boot with working UART output. Note that the plat/qti/msm8916 port is completely separate and does not make use of anything in plat/qti/common at the moment. The main reason for that is that plat/qti/common is heavily focused around having a binary "qtiseclib" component, while the MSM8916 port is fully open-source (and therefore somewhat limited to publicly documented functionality). In the future it might be possible to re-use some of the open-source parts in plat/qti/common (e.g. spmi_arb.c or pm_ps_hold.c) but it's not strictly required for the basic functionality supported so far. Change-Id: I7b4375df0f947b3bd1e55b0b52b21edb6e6d175b Signed-off-by: Stephan Gerhold --- plat/qti/msm8916/aarch64/msm8916_helpers.S | 164 +++++++++++++++++++++ plat/qti/msm8916/aarch64/uartdm_console.S | 154 +++++++++++++++++++ plat/qti/msm8916/include/msm8916_mmap.h | 38 +++++ plat/qti/msm8916/include/plat_macros.S | 27 ++++ plat/qti/msm8916/include/platform_def.h | 50 +++++++ plat/qti/msm8916/include/uartdm_console.h | 12 ++ plat/qti/msm8916/msm8916_bl31_setup.c | 132 +++++++++++++++++ plat/qti/msm8916/msm8916_pm.c | 39 +++++ plat/qti/msm8916/msm8916_topology.c | 35 +++++ plat/qti/msm8916/platform.mk | 60 ++++++++ 10 files changed, 711 insertions(+) create mode 100644 plat/qti/msm8916/aarch64/msm8916_helpers.S create mode 100644 plat/qti/msm8916/aarch64/uartdm_console.S create mode 100644 plat/qti/msm8916/include/msm8916_mmap.h create mode 100644 plat/qti/msm8916/include/plat_macros.S create mode 100644 plat/qti/msm8916/include/platform_def.h create mode 100644 plat/qti/msm8916/include/uartdm_console.h create mode 100644 plat/qti/msm8916/msm8916_bl31_setup.c create mode 100644 plat/qti/msm8916/msm8916_pm.c create mode 100644 plat/qti/msm8916/msm8916_topology.c create mode 100644 plat/qti/msm8916/platform.mk diff --git a/plat/qti/msm8916/aarch64/msm8916_helpers.S b/plat/qti/msm8916/aarch64/msm8916_helpers.S new file mode 100644 index 000000000..dad9968ad --- /dev/null +++ b/plat/qti/msm8916/aarch64/msm8916_helpers.S @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +#define APCS_TCM_START_ADDR 0x10 +#define APCS_TCM_REDIRECT_EN_0 BIT_32(0) + + .globl plat_crash_console_init + .globl plat_crash_console_putc + .globl plat_crash_console_flush + .globl plat_panic_handler + .globl plat_my_core_pos + .globl plat_get_my_entrypoint + .globl plat_reset_handler + .globl platform_mem_init + .globl msm8916_entry_point + + /* ------------------------------------------------- + * int plat_crash_console_init(void) + * Initialize the crash console. + * Out: x0 - 1 on success, 0 on error + * Clobber list : x0 - x4 + * ------------------------------------------------- + */ +func plat_crash_console_init + mov x1, #BLSP_UART2_BASE + + /* + * If the non-secure world has been actively using the UART there might + * be still some characters left to be sent in the FIFO. In that case, + * resetting the transmitter too early might cause all output to become + * corrupted. To avoid that, try to flush (wait until FIFO empty) first. + */ + mov x4, lr + bl console_uartdm_core_flush + mov lr, x4 + + mov x0, #1 + b console_uartdm_core_init +endfunc plat_crash_console_init + + /* ------------------------------------------------- + * int plat_crash_console_putc(int c) + * Print a character on the crash console. + * In : w0 - character to be printed + * Out: w0 - printed character on success + * Clobber list : x1, x2 + * ------------------------------------------------- + */ +func plat_crash_console_putc + mov x1, #BLSP_UART2_BASE + b console_uartdm_core_putc +endfunc plat_crash_console_putc + + /* ------------------------------------------------- + * void plat_crash_console_flush(void) + * Force a write of all buffered data that has not + * been output. + * Clobber list : x1, x2 + * ------------------------------------------------- + */ +func plat_crash_console_flush + mov x1, #BLSP_UART2_BASE + b console_uartdm_core_flush +endfunc plat_crash_console_flush + + /* ------------------------------------------------- + * void plat_panic_handler(void) __dead + * Called when an unrecoverable error occurs. + * ------------------------------------------------- + */ +func plat_panic_handler + /* Try to shutdown/reset */ + mov_imm x0, MPM_PS_HOLD + str wzr, [x0] +1: b 1b +endfunc plat_panic_handler + + /* ------------------------------------------------- + * unsigned int plat_my_core_pos(void) + * Out: x0 - index of the calling CPU + * ------------------------------------------------- + */ +func plat_my_core_pos + /* There is just a single cluster so this is very simple */ + mrs x0, mpidr_el1 + and x0, x0, #MPIDR_CPU_MASK + ret +endfunc plat_my_core_pos + + /* ------------------------------------------------- + * uintptr_t plat_get_my_entrypoint(void) + * Distinguish cold and warm boot and return warm boot + * entry address if available. + * Out: x0 - warm boot entry point or 0 on cold boot + * ------------------------------------------------- + */ +func plat_get_my_entrypoint + ldr x0, msm8916_entry_point + ret +endfunc plat_get_my_entrypoint + + /* ------------------------------------------------- + * void plat_reset_handler(void) + * Perform additional initialization after reset. + * Clobber list : x0 - x18, x30 + * ------------------------------------------------- + */ +func plat_reset_handler + /* + * Check if the CPU is running at the correct address. + * During cold boot the CPU enters here at the wrong address + * using the "boot remapper". (It remaps the BL31_BASE to + * the CPU reset address 0x0). + */ + mov x0, #BL31_BASE + adr x1, bl31_entrypoint + cmp x0, x1 + b.ne _remapped_cold_boot + /* Already running at correct address, just return directly */ + ret + +_remapped_cold_boot: + /* + * The previous boot stage seems to use the L2 cache as TCM. + * Disable the TCM redirect before enabling caches to avoid + * strange crashes. + */ + mov x2, #APCS_CFG + ldr w3, [x2, #APCS_TCM_START_ADDR] + and w3, w3, #~APCS_TCM_REDIRECT_EN_0 + str w3, [x2, #APCS_TCM_START_ADDR] + + /* Enter BL31 again at the real address */ + br x0 +endfunc plat_reset_handler + + /* ------------------------------------------------- + * void platform_mem_init(void) + * Performs additional memory initialization early + * in the boot process. + * ------------------------------------------------- + */ +func platform_mem_init + /* Nothing to do here, all memory is already initialized */ + ret +endfunc platform_mem_init + + .data + .align 3 + + /* ------------------------------------------------- + * Warm boot entry point for CPU. Set by PSCI code. + * ------------------------------------------------- + */ +msm8916_entry_point: + .quad 0 diff --git a/plat/qti/msm8916/aarch64/uartdm_console.S b/plat/qti/msm8916/aarch64/uartdm_console.S new file mode 100644 index 000000000..c69c1932a --- /dev/null +++ b/plat/qti/msm8916/aarch64/uartdm_console.S @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * Based on aarch64/skeleton_console.S: + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +/* UART DM registers */ +#define UART_DM_DMEN 0x03c /* DMA / data packing */ +#define UART_DM_SR 0x0a4 /* status register */ +#define UART_DM_CR 0x0a8 /* command register */ +#define UART_DM_TF 0x100 /* transmit FIFO */ + +#define UART_DM_DMEN_TX_SC BIT_32(4) /* TX single character mode */ + +#define UART_DM_SR_TXRDY_BIT 2 /* TX FIFO has space */ +#define UART_DM_SR_TXEMT_BIT 3 /* TX FIFO is empty */ + +#define UART_DM_CR_RESET_RX (U(0x01) << 4) /* reset receiver */ +#define UART_DM_CR_RESET_TX (U(0x02) << 4) /* reset transmitter */ +#define UART_DM_CR_TX_ENABLE BIT_32(2) /* enable transmitter */ + + .globl console_uartdm_register + .globl console_uartdm_core_init + .globl console_uartdm_putc + .globl console_uartdm_core_putc + .globl console_uartdm_flush + .globl console_uartdm_core_flush + + /* ----------------------------------------------------------- + * int console_uartdm_register(console_t *console, + * uintptr_t base_addr) + * Function to initialize and register the console. The caller + * needs to pass an empty console_t structure in which *MUST* + * be allocated in persistent memory (e.g. a global or static + * local variable, *NOT* on the stack). + * In : x0 - pointer to empty console_t structure + * x1 - base address + * Out: x0 - 1 on success, 0 on error + * Clobber list : x0 - x7 + * ----------------------------------------------------------- + */ +func console_uartdm_register + str x1, [x0, #CONSOLE_T_BASE] + mov x7, lr + bl console_uartdm_core_init + mov lr, x7 + + /* Register the new console */ + finish_console_register uartdm putc=1, flush=1 +endfunc console_uartdm_register + + /* ----------------------------------------------------------- + * void console_uartdm_core_init(unused, uintptr_t base_addr) + * Function to initialize the console. + * In : x0 - unused + * x1 - base address + * Out: void + * Clobber list : x1, x2, x3 + * ----------------------------------------------------------- + */ +func console_uartdm_core_init + /* Reset receiver */ + mov w3, #UART_DM_CR_RESET_RX + str w3, [x1, #UART_DM_CR] + + /* Reset transmitter */ + mov w3, #UART_DM_CR_RESET_TX + str w3, [x1, #UART_DM_CR] + + /* + * Disable BAM/DMA modes but enable single-character mode for TX. + * The single character mode allows simplifying the putc implementation + * since characters can be written directly to the FIFO instead of + * having to initiate a new transfer and waiting for its completion. + */ + mov w3, #UART_DM_DMEN_TX_SC + str w3, [x1, #UART_DM_DMEN] + + /* Enable transmitter */ + mov w3, #UART_DM_CR_TX_ENABLE + str w3, [x1, #UART_DM_CR] + + ret +endfunc console_uartdm_core_init + + /* ----------------------------------------------------------- + * int console_uartdm_putc(int c, console_t *console) + * Function to output a character over the console. + * In : w0 - character to be printed + * x1 - pointer to console_t struct + * Out: w0 - printed character on success, < 0 on error. + * Clobber list : x0, x1, x2 + * ----------------------------------------------------------- + */ +func console_uartdm_putc + ldr x1, [x1, #CONSOLE_T_BASE] + b console_uartdm_core_putc +endfunc console_uartdm_putc + + /* ----------------------------------------------------------- + * int console_uartdm_core_putc(int c, uintptr_t base_addr) + * Function to output a character over the console. + * In : w0 - character to be printed + * x1 - base address + * Out: w0 - printed character on success, < 0 on error. + * Clobber list : x2 + * ----------------------------------------------------------- + */ +func console_uartdm_core_putc +1: /* Loop until TX FIFO has space */ + ldr w2, [x1, #UART_DM_SR] + tbz w2, #UART_DM_SR_TXRDY_BIT, 1b + + /* Write character to FIFO */ + str w0, [x1, #UART_DM_TF] + ret +endfunc console_uartdm_core_putc + + /* ----------------------------------------------------------- + * void console_uartdm_flush(console_t *console) + * Function to force a write of all buffered data + * that has not been output. + * In : x0 - pointer to console_t struct + * Out: void + * Clobber list : x0, x1, x2, x3, x4, x5 + * ----------------------------------------------------------- + */ +func console_uartdm_flush + ldr x1, [x0, #CONSOLE_T_BASE] + b console_uartdm_core_flush +endfunc console_uartdm_flush + + /* ----------------------------------------------------------- + * void console_uartdm_core_flush(unused, uintptr_t base_addr) + * Function to force a write of all buffered data + * that has not been output. + * In : x0 - unused + * x1 - base address + * Out: void + * Clobber list : x2 + * ----------------------------------------------------------- + */ +func console_uartdm_core_flush +1: /* Loop until TX FIFO is empty */ + ldr w2, [x1, #UART_DM_SR] + tbz w2, #UART_DM_SR_TXEMT_BIT, 1b + ret +endfunc console_uartdm_core_flush diff --git a/plat/qti/msm8916/include/msm8916_mmap.h b/plat/qti/msm8916/include/msm8916_mmap.h new file mode 100644 index 000000000..1696b84d1 --- /dev/null +++ b/plat/qti/msm8916/include/msm8916_mmap.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_MMAP_H +#define MSM8916_MMAP_H + +#define PCNOC_BASE 0x00000000 +#define PCNOC_SIZE 0x8000000 /* 128 MiB */ +#define APCS_BASE 0x0b000000 +#define APCS_SIZE 0x800000 /* 8 MiB */ + +#define MPM_BASE (PCNOC_BASE + 0x04a0000) +#define MPM_PS_HOLD (MPM_BASE + 0xb000) + +#define TLMM_BASE (PCNOC_BASE + 0x1000000) +#define TLMM_GPIO_CFG(n) (TLMM_BASE + ((n) * 0x1000)) + +#define GCC_BASE (PCNOC_BASE + 0x1800000) + +#define BLSP_UART1_BASE (PCNOC_BASE + 0x78af000) +#define BLSP_UART2_BASE (PCNOC_BASE + 0x78b0000) + +#define APCS_QGIC2_BASE (APCS_BASE + 0x00000) +#define APCS_QGIC2_GICD (APCS_QGIC2_BASE + 0x0000) +#define APCS_QGIC2_GICC (APCS_QGIC2_BASE + 0x2000) +#define APCS_BANKED_ACS (APCS_BASE + 0x08000) +#define APCS_BANKED_SAW2 (APCS_BASE + 0x09000) +#define APCS_CFG (APCS_BASE + 0x10000) +#define APCS_GLB (APCS_BASE + 0x11000) +#define APCS_L2_SAW2 (APCS_BASE + 0x12000) +#define APCS_QTMR (APCS_BASE + 0x20000) +#define APCS_ALIAS_ACS(cpu) (APCS_BASE + 0x88000 + ((cpu) * 0x10000)) +#define APCS_ALIAS_SAW2(cpu) (APCS_BASE + 0x89000 + ((cpu) * 0x10000)) + +#endif /* MSM8916_MMAP_H */ diff --git a/plat/qti/msm8916/include/plat_macros.S b/plat/qti/msm8916/include/plat_macros.S new file mode 100644 index 000000000..552add20d --- /dev/null +++ b/plat/qti/msm8916/include/plat_macros.S @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_MACROS_S +#define PLAT_MACROS_S + +#include + +#include + + /* --------------------------------------------- + * The below required platform porting macro + * prints out relevant GIC registers whenever + * an unhandled exception is taken in BL31. + * Clobbers: x0 - x10, x16, x17, sp + * --------------------------------------------- + */ + .macro plat_crash_print_regs + mov_imm x16, APCS_QGIC2_GICD + mov_imm x17, APCS_QGIC2_GICC + arm_print_gic_regs + .endm + +#endif /* PLAT_MACROS_S */ diff --git a/plat/qti/msm8916/include/platform_def.h b/plat/qti/msm8916/include/platform_def.h new file mode 100644 index 000000000..4ad26dd83 --- /dev/null +++ b/plat/qti/msm8916/include/platform_def.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include + +/* + * There is at least 1 MiB available for BL31. However, at the moment the + * "msm8916_entry_point" variable in the data section is read through the + * 64 KiB region of the "boot remapper" after reset. For simplicity, limit + * the end of the data section (BL31_PROGBITS_LIMIT) to 64 KiB for now and + * the overall limit to 128 KiB. This could be increased if needed by placing + * the "msm8916_entry_point" variable explicitly in the first 64 KiB of BL31. + */ +#define BL31_LIMIT (BL31_BASE + 0x20000) /* 128 KiB */ +#define BL31_PROGBITS_LIMIT (BL31_BASE + 0x10000) /* 64 KiB */ + +#define CACHE_WRITEBACK_GRANULE U(64) +#define PLATFORM_STACK_SIZE U(0x1000) + +/* CPU topology: single cluster with 4 cores */ +#define PLATFORM_CLUSTER_COUNT U(1) +#define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) +#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \ + PLATFORM_MAX_CPUS_PER_CLUSTER) + +/* Power management */ +#define PLATFORM_SYSTEM_COUNT U(1) +#define PLAT_NUM_PWR_DOMAINS (PLATFORM_SYSTEM_COUNT + \ + PLATFORM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) +#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 +#define PLAT_MAX_RET_STATE U(2) +#define PLAT_MAX_OFF_STATE U(3) + +/* Translation tables */ +#define MAX_MMAP_REGIONS 8 +#define MAX_XLAT_TABLES 4 + +#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) +#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) + +/* Timer frequency */ +#define PLAT_SYSCNT_FREQ 19200000 + +#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 000000000..0f09ba81a --- /dev/null +++ b/plat/qti/msm8916/include/uartdm_console.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef UARTDM_CONSOLE_H +#define UARTDM_CONSOLE_H + +int console_uartdm_register(console_t *console, uintptr_t base_addr); + +#endif /* UARTDM_CONSOLE_H */ diff --git a/plat/qti/msm8916/msm8916_bl31_setup.c b/plat/qti/msm8916/msm8916_bl31_setup.c new file mode 100644 index 000000000..a27549ead --- /dev/null +++ b/plat/qti/msm8916/msm8916_bl31_setup.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static const mmap_region_t msm8916_mmap[] = { + MAP_REGION_FLAT(PCNOC_BASE, PCNOC_SIZE, + MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER), + MAP_REGION_FLAT(APCS_BASE, APCS_SIZE, + MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER), + {}, +}; + +static struct { + entry_point_info_t bl32; + entry_point_info_t bl33; +} image_ep_info = { + /* BL32 entry point */ + SET_STATIC_PARAM_HEAD(bl32, PARAM_EP, VERSION_1, + entry_point_info_t, SECURE), + .bl32.pc = BL32_BASE, + + /* BL33 entry point */ + SET_STATIC_PARAM_HEAD(bl33, PARAM_EP, VERSION_1, + entry_point_info_t, NON_SECURE), + .bl33.pc = PRELOADED_BL33_BASE, + .bl33.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), +}; + +static console_t console; + +unsigned int plat_get_syscnt_freq2(void) +{ + return PLAT_SYSCNT_FREQ; +} + +#define CLK_ENABLE BIT_32(0) +#define CLK_OFF BIT_32(31) + +#define GPIO_BLSP_UART2_TX 4 +#define GPIO_BLSP_UART2_RX 5 +#define GPIO_CFG_FUNC_BLSP_UART2 (U(0x2) << 2) +#define GPIO_CFG_DRV_STRENGTH_16MA (U(0x7) << 6) + +#define GCC_BLSP1_AHB_CBCR (GCC_BASE + 0x01008) +#define GCC_BLSP1_UART2_APPS_CBCR (GCC_BASE + 0x0302c) +#define GCC_APCS_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x45004) +#define BLSP1_AHB_CLK_ENA BIT_32(10) + +/* + * The previous boot stage seems to disable most of the UART setup before exit + * so it must be enabled here again before the UART console can be used. + */ +static void msm8916_enable_blsp_uart2(void) +{ + /* Route GPIOs to BLSP UART2 */ + mmio_write_32(TLMM_GPIO_CFG(GPIO_BLSP_UART2_TX), + GPIO_CFG_FUNC_BLSP_UART2 | GPIO_CFG_DRV_STRENGTH_16MA); + mmio_write_32(TLMM_GPIO_CFG(GPIO_BLSP_UART2_RX), + GPIO_CFG_FUNC_BLSP_UART2 | GPIO_CFG_DRV_STRENGTH_16MA); + + /* Enable AHB clock */ + mmio_setbits_32(GCC_APCS_CLOCK_BRANCH_ENA_VOTE, BLSP1_AHB_CLK_ENA); + while (mmio_read_32(GCC_BLSP1_AHB_CBCR) & CLK_OFF) + ; + + /* Enable BLSP UART2 clock */ + mmio_setbits_32(GCC_BLSP1_UART2_APPS_CBCR, CLK_ENABLE); + while (mmio_read_32(GCC_BLSP1_UART2_APPS_CBCR) & CLK_OFF) + ; +} + +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + /* Initialize the debug console as early as possible */ + msm8916_enable_blsp_uart2(); + console_uartdm_register(&console, BLSP_UART2_BASE); +} + +void bl31_plat_arch_setup(void) +{ + mmap_add_region(BL31_BASE, BL31_BASE, BL31_END - BL31_BASE, + MT_RW_DATA | MT_SECURE); + mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, + BL_CODE_END - BL_CODE_BASE, + MT_CODE | MT_SECURE); + mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE, + BL_RO_DATA_END - BL_RO_DATA_BASE, + MT_RO_DATA | MT_SECURE); + mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE, + BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, + MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER); + + mmap_add(msm8916_mmap); + init_xlat_tables(); + enable_mmu_el3(0); +} + +void bl31_platform_setup(void) +{ + generic_delay_timer_init(); +} + +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_pm.c b/plat/qti/msm8916/msm8916_pm.c new file mode 100644 index 000000000..c9a40f592 --- /dev/null +++ b/plat/qti/msm8916/msm8916_pm.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include + +#include + +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 = { + .system_off = msm8916_system_reset, + .system_reset = msm8916_system_reset, +}; + +/* Defined and used in msm8916_helpers.S */ +extern uintptr_t msm8916_entry_point; + +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + msm8916_entry_point = sec_entrypoint; + *psci_ops = &msm8916_psci_ops; + return 0; +} diff --git a/plat/qti/msm8916/msm8916_topology.c b/plat/qti/msm8916/msm8916_topology.c new file mode 100644 index 000000000..4d0ed8fcc --- /dev/null +++ b/plat/qti/msm8916/msm8916_topology.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include + +static const unsigned char plat_power_domain_tree_desc[PLAT_MAX_PWR_LVL + 1] = { + PLATFORM_SYSTEM_COUNT, + PLATFORM_CLUSTER_COUNT, + PLATFORM_MAX_CPUS_PER_CLUSTER, +}; + +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); + + if (MPIDR_AFFLVL3_VAL(mpidr) > 0 || + MPIDR_AFFLVL2_VAL(mpidr) > 0 || + MPIDR_AFFLVL1_VAL(mpidr) > 0 || + core >= PLATFORM_MAX_CPUS_PER_CLUSTER) { + return -1; + } + + return core; +} + +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + return plat_power_domain_tree_desc; +} diff --git a/plat/qti/msm8916/platform.mk b/plat/qti/msm8916/platform.mk new file mode 100644 index 000000000..2d199e061 --- /dev/null +++ b/plat/qti/msm8916/platform.mk @@ -0,0 +1,60 @@ +# +# Copyright (c) 2021, Stephan Gerhold +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include drivers/arm/gic/v2/gicv2.mk +include lib/xlat_tables_v2/xlat_tables.mk + +PLAT_BL_COMMON_SOURCES := ${XLAT_TABLES_LIB_SRCS} + +PLAT_INCLUDES := -Iinclude/plat/arm/common/${ARCH} \ + -Iplat/qti/msm8916/include + +BL31_SOURCES += ${GICV2_SOURCES} \ + drivers/delay_timer/delay_timer.c \ + drivers/delay_timer/generic_delay_timer.c \ + lib/cpus/${ARCH}/cortex_a53.S \ + plat/common/plat_gicv2.c \ + plat/common/plat_psci_common.c \ + plat/qti/msm8916/msm8916_bl31_setup.c \ + plat/qti/msm8916/msm8916_pm.c \ + plat/qti/msm8916/msm8916_topology.c \ + plat/qti/msm8916/${ARCH}/msm8916_helpers.S \ + plat/qti/msm8916/${ARCH}/uartdm_console.S + +# Only BL31 is supported at the moment and is entered on a single CPU +RESET_TO_BL31 := 1 +COLD_BOOT_SINGLE_CPU := 1 + +# Build config flags +# ------------------ +BL31_BASE ?= 0x86500000 +BL32_BASE ?= 0x86000000 +PRELOADED_BL33_BASE ?= 0x8f600000 + +# Have different sections for code and rodata +SEPARATE_CODE_AND_RODATA := 1 + +# Single cluster +WARMBOOT_ENABLE_DCACHE_EARLY := 1 + +# Disable features unsupported in ARMv8.0 +ENABLE_AMU := 0 +ENABLE_SPE_FOR_LOWER_ELS := 0 +ENABLE_SVE_FOR_NS := 0 + +# MSM8916 uses ARM Cortex-A53 r0p0 so likely all the errata apply +ERRATA_A53_819472 := 1 +ERRATA_A53_824069 := 1 +ERRATA_A53_826319 := 1 +ERRATA_A53_827319 := 1 +ERRATA_A53_835769 := 1 +ERRATA_A53_836870 := 1 +ERRATA_A53_843419 := 1 +ERRATA_A53_855873 := 0 # Workaround works only for >= r0p3 +ERRATA_A53_1530924 := 1 + +$(eval $(call add_define,BL31_BASE)) +$(eval $(call add_define,BL32_BASE)) From a7521bd5d887bfd69d99a55a81416e38ba9ebc97 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 1 Dec 2021 20:02:22 +0100 Subject: [PATCH 3/5] feat(gic): allow overriding GICD_PIDR2_GICV2 address Older Qualcomm SoCs seem to have a custom Qualcomm implementation of the GICv2 specification. It's mostly compliant but unfortunately it looks like a mistake was made with the GICD_PIDR registers. PIDR2 is defined to be at offset 0xFE8, but the Qualcomm implementation has it at 0xFD8. It looks like the entire PIDR0-3/4-7 block is swapped compared to the ARM implementation: PIDR0 starts at 0xFD0 (instead of 0xFE0) and PIDR4 starts at 0xFE0 (instead of 0xFD0). Actually this only breaks a single assert in gicv2_main.c that checks the GIC version: assert((gic_version == ARCH_REV_GICV2) ... In release mode everything seems to work correctly. To keep the code generic, allow affected platforms to override the GICD_PIDR2_GICV2 register address in platform_def.h. Since this header is typically included very early (e.g. from assert.h), add an #ifndef so the definitions from platform_def.h takes priority. Change-Id: I2929a8c1726f8d751bc28796567eb30b81eca2fe Signed-off-by: Stephan Gerhold --- include/drivers/arm/gicv2.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/drivers/arm/gicv2.h b/include/drivers/arm/gicv2.h index ebcb216d6..b960194db 100644 --- a/include/drivers/arm/gicv2.h +++ b/include/drivers/arm/gicv2.h @@ -8,6 +8,7 @@ #define GICV2_H #include +#include /******************************************************************************* * GICv2 miscellaneous definitions @@ -30,7 +31,14 @@ #define GICD_SGIR U(0xF00) #define GICD_CPENDSGIR U(0xF10) #define GICD_SPENDSGIR U(0xF20) + +/* + * Some GICv2 implementations violate the specification and have this register + * at a different address. Allow overriding it in platform_def.h as workaround. + */ +#ifndef GICD_PIDR2_GICV2 #define GICD_PIDR2_GICV2 U(0xFE8) +#endif #define ITARGETSR_SHIFT 2 #define GIC_TARGET_CPU_MASK U(0xff) From af6447315c8534331513ca6b6556af661e0ba88b Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 1 Dec 2021 20:03:33 +0100 Subject: [PATCH 4/5] feat(msm8916): setup hardware for non-secure world Booting e.g. Linux in the non-secure world does not work with the msm8916 port yet because essential hardware is not made available to the non-secure world. Add more platform initialization to: - Initialize the GICv2 and mark secure interrupts. Only secure SGIs/PPIs so far. Override the GICD_PIDR2_GICV2 register address in platform_def.h to avoid a failing assert() because of a (hardware) mistake in Qualcomm's GICv2 implementation. - Make a timer frame available to the non-secure world. The "Qualcomm Timer" (QTMR) implements the ARM generic timer specification, so the standard defines (CNTACR_BASE etc) can be used. - Make parts of the "APCS" register region available to the non-secure world, e.g. for CPU frequency control implemented in Linux. - Initialize a platform-specific register to route all SMMU context bank interrupts to the non-secure interrupt pin, since all control of the SMMUs is left up to the non-secure world for now. Change-Id: Icf676437b8e329dead06658e177107dfd0ba4f9d Signed-off-by: Stephan Gerhold --- plat/qti/msm8916/include/msm8916_mmap.h | 3 + plat/qti/msm8916/include/platform_def.h | 7 +++ plat/qti/msm8916/msm8916_bl31_setup.c | 79 +++++++++++++++++++++++++ plat/qti/msm8916/msm8916_gicv2.c | 59 ++++++++++++++++++ plat/qti/msm8916/msm8916_gicv2.h | 12 ++++ plat/qti/msm8916/platform.mk | 1 + 6 files changed, 161 insertions(+) create mode 100644 plat/qti/msm8916/msm8916_gicv2.c create mode 100644 plat/qti/msm8916/msm8916_gicv2.h diff --git a/plat/qti/msm8916/include/msm8916_mmap.h b/plat/qti/msm8916/include/msm8916_mmap.h index 1696b84d1..406ae6b4e 100644 --- a/plat/qti/msm8916/include/msm8916_mmap.h +++ b/plat/qti/msm8916/include/msm8916_mmap.h @@ -20,6 +20,9 @@ #define GCC_BASE (PCNOC_BASE + 0x1800000) +#define APPS_SMMU_BASE (PCNOC_BASE + 0x1e00000) +#define APPS_SMMU_QCOM (APPS_SMMU_BASE + 0xf0000) + #define BLSP_UART1_BASE (PCNOC_BASE + 0x78af000) #define BLSP_UART2_BASE (PCNOC_BASE + 0x78b0000) diff --git a/plat/qti/msm8916/include/platform_def.h b/plat/qti/msm8916/include/platform_def.h index 4ad26dd83..bfade70a3 100644 --- a/plat/qti/msm8916/include/platform_def.h +++ b/plat/qti/msm8916/include/platform_def.h @@ -47,4 +47,11 @@ /* Timer frequency */ #define PLAT_SYSCNT_FREQ 19200000 +/* + * The Qualcomm QGIC2 implementation seems to have PIDR0-4 and PIDR4-7 + * erroneously swapped for some reason. PIDR2 is actually at 0xFD8. + * Override the address in to avoid a failing assert(). + */ +#define GICD_PIDR2_GICV2 U(0xFD8) + #endif /* PLATFORM_DEF_H */ diff --git a/plat/qti/msm8916/msm8916_bl31_setup.c b/plat/qti/msm8916/msm8916_bl31_setup.c index a27549ead..9c4fd0644 100644 --- a/plat/qti/msm8916/msm8916_bl31_setup.c +++ b/plat/qti/msm8916/msm8916_bl31_setup.c @@ -15,6 +15,7 @@ #include #include +#include "msm8916_gicv2.h" #include #include #include @@ -113,9 +114,87 @@ void bl31_plat_arch_setup(void) enable_mmu_el3(0); } +static void msm8916_configure_timer(void) +{ + /* Set timer frequency */ + mmio_write_32(APCS_QTMR + CNTCTLBASE_CNTFRQ, plat_get_syscnt_freq2()); + + /* Make frame 0 available to non-secure world */ + mmio_write_32(APCS_QTMR + CNTNSAR, BIT_32(CNTNSAR_NS_SHIFT(0))); + mmio_write_32(APCS_QTMR + CNTACR_BASE(0), + BIT_32(CNTACR_RPCT_SHIFT) | BIT_32(CNTACR_RVCT_SHIFT) | + BIT_32(CNTACR_RFRQ_SHIFT) | BIT_32(CNTACR_RVOFF_SHIFT) | + BIT_32(CNTACR_RWVT_SHIFT) | BIT_32(CNTACR_RWPT_SHIFT)); +} + +/* + * The APCS register regions always start with a SECURE register that should + * be cleared to 0 to only allow secure access. Since BL31 handles most of + * the CPU power management, most of them can be cleared to secure access only. + */ +#define APCS_GLB_SECURE_STS_NS BIT_32(0) +#define APCS_GLB_SECURE_PWR_NS BIT_32(1) + +static void msm8916_configure_cpu_pm(void) +{ + unsigned int cpu; + + /* Disallow non-secure access to boot remapper / TCM registers */ + mmio_write_32(APCS_CFG, 0); + + /* + * Disallow non-secure access to power management registers. + * However, allow STS and PWR since those also seem to control access + * to CPU frequency related registers (e.g. APCS_CMD_RCGR). If these + * bits are not set, CPU frequency control fails in the non-secure world. + */ + mmio_write_32(APCS_GLB, APCS_GLB_SECURE_STS_NS | APCS_GLB_SECURE_PWR_NS); + + /* Disallow non-secure access to L2 SAW2 */ + mmio_write_32(APCS_L2_SAW2, 0); + + /* Disallow non-secure access to CPU ACS and SAW2 */ + for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { + mmio_write_32(APCS_ALIAS_ACS(cpu), 0); + mmio_write_32(APCS_ALIAS_SAW2(cpu), 0); + } +} + +/* + * MSM8916 has a special "interrupt aggregation logic" in the APPS SMMU, + * which allows routing context bank interrupts to one of 3 interrupt numbers + * ("TZ/HYP/NS"). Route all interrupts to the non-secure interrupt number + * by default to avoid special setup on the non-secure side. + */ +#define GCC_SMMU_CFG_CBCR (GCC_BASE + 0x12038) +#define GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x4500c) +#define SMMU_CFG_CLK_ENA BIT_32(12) +#define APPS_SMMU_INTR_SEL_NS (APPS_SMMU_QCOM + 0x2000) +#define APPS_SMMU_INTR_SEL_NS_EN_ALL U(0xffffffff) + +static void msm8916_configure_smmu(void) +{ + /* Enable SMMU configuration clock to enable register access */ + mmio_setbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA); + while (mmio_read_32(GCC_SMMU_CFG_CBCR) & CLK_OFF) + ; + + /* Route all context bank interrupts to non-secure interrupt */ + mmio_write_32(APPS_SMMU_INTR_SEL_NS, APPS_SMMU_INTR_SEL_NS_EN_ALL); + + /* Disable configuration clock again */ + mmio_clrbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA); +} + void bl31_platform_setup(void) { + INFO("BL31: Platform setup start\n"); generic_delay_timer_init(); + msm8916_configure_timer(); + msm8916_gicv2_init(); + msm8916_configure_cpu_pm(); + msm8916_configure_smmu(); + INFO("BL31: Platform setup done\n"); } entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) diff --git a/plat/qti/msm8916/msm8916_gicv2.c b/plat/qti/msm8916/msm8916_gicv2.c new file mode 100644 index 000000000..25a66282f --- /dev/null +++ b/plat/qti/msm8916/msm8916_gicv2.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include "msm8916_gicv2.h" +#include + +#define IRQ_SEC_SGI_0 8 +#define IRQ_SEC_SGI_1 9 +#define IRQ_SEC_SGI_2 10 +#define IRQ_SEC_SGI_3 11 +#define IRQ_SEC_SGI_4 12 +#define IRQ_SEC_SGI_5 13 +#define IRQ_SEC_SGI_6 14 +#define IRQ_SEC_SGI_7 15 + +#define IRQ_SEC_PHY_TIMER (16 + 2) /* PPI #2 */ + +static const interrupt_prop_t msm8916_interrupt_props[] = { + INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), + INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, + GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), +}; + +static const gicv2_driver_data_t msm8916_gic_data = { + .gicd_base = APCS_QGIC2_GICD, + .gicc_base = APCS_QGIC2_GICC, + .interrupt_props = msm8916_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(msm8916_interrupt_props), +}; + +void msm8916_gicv2_init(void) +{ + gicv2_driver_init(&msm8916_gic_data); + gicv2_distif_init(); + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} diff --git a/plat/qti/msm8916/msm8916_gicv2.h b/plat/qti/msm8916/msm8916_gicv2.h new file mode 100644 index 000000000..99db0d360 --- /dev/null +++ b/plat/qti/msm8916/msm8916_gicv2.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_GICV2_H +#define MSM8916_GICV2_H + +void msm8916_gicv2_init(void); + +#endif /* MSM8916_GICV2_H */ diff --git a/plat/qti/msm8916/platform.mk b/plat/qti/msm8916/platform.mk index 2d199e061..21ea450a8 100644 --- a/plat/qti/msm8916/platform.mk +++ b/plat/qti/msm8916/platform.mk @@ -19,6 +19,7 @@ BL31_SOURCES += ${GICV2_SOURCES} \ plat/common/plat_gicv2.c \ plat/common/plat_psci_common.c \ plat/qti/msm8916/msm8916_bl31_setup.c \ + plat/qti/msm8916/msm8916_gicv2.c \ plat/qti/msm8916/msm8916_pm.c \ plat/qti/msm8916/msm8916_topology.c \ plat/qti/msm8916/${ARCH}/msm8916_helpers.S \ From a758c0b65c6730fb07846899d6436ba257484d34 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Wed, 1 Dec 2021 20:04:44 +0100 Subject: [PATCH 5/5] feat(msm8916): allow booting secondary CPU cores Add support for the PSCI CPU_ON call to allow booting secondary CPU cores. On cold boot they need to be booted with a special register sequence. Also, the "boot remapper" needs to be configured to point to the BL31_BASE, so the CPUs actually start executing BL31 after reset. Change-Id: I406c508070ccb046bfdefd51554f12e1db671fd4 Signed-off-by: Stephan Gerhold --- plat/qti/msm8916/msm8916_bl31_setup.c | 8 ++++ plat/qti/msm8916/msm8916_cpu_boot.c | 66 +++++++++++++++++++++++++++ plat/qti/msm8916/msm8916_pm.c | 20 ++++++++ plat/qti/msm8916/msm8916_pm.h | 12 +++++ plat/qti/msm8916/platform.mk | 1 + 5 files changed, 107 insertions(+) create mode 100644 plat/qti/msm8916/msm8916_cpu_boot.c create mode 100644 plat/qti/msm8916/msm8916_pm.h diff --git a/plat/qti/msm8916/msm8916_bl31_setup.c b/plat/qti/msm8916/msm8916_bl31_setup.c index 9c4fd0644..638cd09d0 100644 --- a/plat/qti/msm8916/msm8916_bl31_setup.c +++ b/plat/qti/msm8916/msm8916_bl31_setup.c @@ -134,6 +134,9 @@ static void msm8916_configure_timer(void) */ #define APCS_GLB_SECURE_STS_NS BIT_32(0) #define APCS_GLB_SECURE_PWR_NS BIT_32(1) +#define APCS_BOOT_START_ADDR_SEC (APCS_CFG + 0x04) +#define REMAP_EN BIT_32(0) +#define APCS_AA64NAA32_REG (APCS_CFG + 0x0c) static void msm8916_configure_cpu_pm(void) { @@ -158,6 +161,11 @@ static void msm8916_configure_cpu_pm(void) mmio_write_32(APCS_ALIAS_ACS(cpu), 0); mmio_write_32(APCS_ALIAS_SAW2(cpu), 0); } + + /* Make sure all further warm boots end up in BL31 and aarch64 state */ + CASSERT((BL31_BASE & 0xffff) == 0, assert_bl31_base_64k_aligned); + mmio_write_32(APCS_BOOT_START_ADDR_SEC, BL31_BASE | REMAP_EN); + mmio_write_32(APCS_AA64NAA32_REG, 1); } /* diff --git a/plat/qti/msm8916/msm8916_cpu_boot.c b/plat/qti/msm8916/msm8916_cpu_boot.c new file mode 100644 index 000000000..b3f51f69c --- /dev/null +++ b/plat/qti/msm8916/msm8916_cpu_boot.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include "msm8916_pm.h" + +#define CPU_PWR_CTL 0x4 +#define APC_PWR_GATE_CTL 0x14 + +#define CPU_PWR_CTL_CLAMP BIT_32(0) +#define CPU_PWR_CTL_CORE_MEM_CLAMP BIT_32(1) +#define CPU_PWR_CTL_L1_RST_DIS BIT_32(2) +#define CPU_PWR_CTL_CORE_MEM_HS BIT_32(3) +#define CPU_PWR_CTL_CORE_RST BIT_32(4) +#define CPU_PWR_CTL_COREPOR_RST BIT_32(5) +#define CPU_PWR_CTL_GATE_CLK BIT_32(6) +#define CPU_PWR_CTL_CORE_PWRD_UP BIT_32(7) + +#define APC_PWR_GATE_CTL_GHDS_EN BIT_32(0) +#define APC_PWR_GATE_CTL_GHDS_CNT(cnt) ((cnt) << 24) + +/* Boot a secondary CPU core for the first time. */ +void msm8916_cpu_boot(unsigned int core) +{ + uintptr_t acs = APCS_ALIAS_ACS(core); + uint32_t pwr_ctl; + + pwr_ctl = CPU_PWR_CTL_CLAMP | CPU_PWR_CTL_CORE_MEM_CLAMP | + CPU_PWR_CTL_CORE_RST | CPU_PWR_CTL_COREPOR_RST; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + + mmio_write_32(acs + APC_PWR_GATE_CTL, APC_PWR_GATE_CTL_GHDS_EN | + APC_PWR_GATE_CTL_GHDS_CNT(16)); + dsb(); + udelay(2); + + pwr_ctl &= ~CPU_PWR_CTL_CORE_MEM_CLAMP; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + + pwr_ctl |= CPU_PWR_CTL_CORE_MEM_HS; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + udelay(2); + + pwr_ctl &= ~CPU_PWR_CTL_CLAMP; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + udelay(2); + + pwr_ctl &= ~(CPU_PWR_CTL_CORE_RST | CPU_PWR_CTL_COREPOR_RST); + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); + + pwr_ctl |= CPU_PWR_CTL_CORE_PWRD_UP; + mmio_write_32(acs + CPU_PWR_CTL, pwr_ctl); + dsb(); +} diff --git a/plat/qti/msm8916/msm8916_pm.c b/plat/qti/msm8916/msm8916_pm.c index c9a40f592..6891e3800 100644 --- a/plat/qti/msm8916/msm8916_pm.c +++ b/plat/qti/msm8916/msm8916_pm.c @@ -6,12 +6,30 @@ #include #include +#include #include #include #include #include #include +#include "msm8916_pm.h" + +static int msm8916_pwr_domain_on(u_register_t mpidr) +{ + unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); + + VERBOSE("PSCI: Booting CPU %d\n", core); + msm8916_cpu_boot(core); + + return PSCI_E_SUCCESS; +} + +static void msm8916_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + gicv2_pcpu_distif_init(); + gicv2_cpuif_enable(); +} static void __dead2 msm8916_system_reset(void) { @@ -23,6 +41,8 @@ static void __dead2 msm8916_system_reset(void) } 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, }; diff --git a/plat/qti/msm8916/msm8916_pm.h b/plat/qti/msm8916/msm8916_pm.h new file mode 100644 index 000000000..5473bfa2b --- /dev/null +++ b/plat/qti/msm8916/msm8916_pm.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021, Stephan Gerhold + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MSM8916_PM_H +#define MSM8916_PM_H + +void msm8916_cpu_boot(unsigned int core); + +#endif /* MSM8916_PM_H */ diff --git a/plat/qti/msm8916/platform.mk b/plat/qti/msm8916/platform.mk index 21ea450a8..e516ceadb 100644 --- a/plat/qti/msm8916/platform.mk +++ b/plat/qti/msm8916/platform.mk @@ -19,6 +19,7 @@ BL31_SOURCES += ${GICV2_SOURCES} \ plat/common/plat_gicv2.c \ plat/common/plat_psci_common.c \ plat/qti/msm8916/msm8916_bl31_setup.c \ + plat/qti/msm8916/msm8916_cpu_boot.c \ plat/qti/msm8916/msm8916_gicv2.c \ plat/qti/msm8916/msm8916_pm.c \ plat/qti/msm8916/msm8916_topology.c \