mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-17 10:04:26 +00:00
Merge changes from topic "msm8916-spmin" into integration
* changes: docs(msm8916): document new build options feat(msm8916): allow selecting which UART to use feat(msm8916): add SP_MIN port for AArch32 refactor(msm8916): detect cold boot in plat_get_my_entrypoint feat(msm8916): add Test Secure Payload (TSP) port build(msm8916): place bl32 directly after bl31 refactor(msm8916): separate common platform setup code
This commit is contained in:
commit
c4c7efe79e
18 changed files with 868 additions and 245 deletions
|
@ -7,7 +7,7 @@ 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
|
||||
The TF-A 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.
|
||||
|
@ -20,8 +20,7 @@ trial and error to actually make it work.
|
|||
|
||||
Functionality
|
||||
-------------
|
||||
|
||||
The BL31 port is much more minimal compared to the original firmware and
|
||||
The TF-A 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
|
||||
|
@ -41,28 +40,74 @@ will be added later once ready.
|
|||
|
||||
Boot Flow
|
||||
---------
|
||||
BL31 replaces the original ``tz`` firmware in the boot flow::
|
||||
BL31 (AArch64) or BL32/SP_MIN (AArch32) 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.
|
||||
After initialization the normal world starts at a fixed entry address in EL2/HYP
|
||||
mode, configured using ``PRELOADED_BL33_BASE``. At runtime, it is expected that
|
||||
the normal world bootloader was already loaded into RAM by a previous firmware
|
||||
component (usually SBL) and that it is capable of running in EL2/HYP mode.
|
||||
|
||||
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.
|
||||
`U-Boot for DragonBoard 410c`_ is recommended if possible. The original Little
|
||||
Kernel-based bootloader from Qualcomm does not support EL2/HYP, but can be
|
||||
booted using an additional shim loader such as `tfalkstub`_.
|
||||
|
||||
Build
|
||||
-----
|
||||
It is possible to build for either AArch64 or AArch32. AArch64 is the preferred
|
||||
build option.
|
||||
|
||||
AArch64 (BL31)
|
||||
^^^^^^^^^^^^^^
|
||||
Setup the cross compiler for AArch64 and build BL31 for ``msm8916``::
|
||||
|
||||
$ make CROSS_COMPILE=aarch64-none-elf- PLAT=msm8916
|
||||
|
||||
The BL31 ELF image is generated in ``build/msm8916/release/bl31/bl31.elf``.
|
||||
|
||||
AArch32 (BL32/SP_MIN)
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
Setup the cross compiler for AArch32 and build BL32 with SP_MIN for ``msm8916``::
|
||||
|
||||
$ make CROSS_COMPILE=arm-none-eabi- PLAT=msm8916 ARCH=aarch32 AARCH32_SP=sp_min
|
||||
|
||||
The BL32 ELF image is generated in ``build/msm8916/release/bl32/bl32.elf``.
|
||||
|
||||
Build Options
|
||||
-------------
|
||||
Some options can be changed at build time by adding them to the make command line:
|
||||
|
||||
* ``QTI_UART_NUM``: Number of UART controller to use for debug output and crash
|
||||
reports. This must be the same UART as used by earlier boot firmware since
|
||||
the UART controller does not get fully initialized at the moment. Defaults to
|
||||
the usual debug UART used for the platform (see ``platform.mk``).
|
||||
* ``QTI_RUNTIME_UART``: By default (``0``) the UART is only used for the boot
|
||||
process and critical crashes. If set to ``1`` it is also used for runtime
|
||||
messages. Note that this option can only be used if the UART is reserved in
|
||||
the normal world and the necessary clocks remain enabled.
|
||||
|
||||
The memory region used for the different firmware components is not fixed and
|
||||
can be changed on the make command line. The default values match the addresses
|
||||
used by the original firmware (see ``platform.mk``):
|
||||
|
||||
* ``PRELOADED_BL33_BASE``: The entry address for the normal world. Usually
|
||||
refers to the first bootloader (e.g. U-Boot).
|
||||
* ``BL31_BASE``: Base address for the BL31 firmware component. Must point to
|
||||
a 64K-aligned memory region with at least 128 KiB space that is permanently
|
||||
reserved in the normal world.
|
||||
* ``BL32_BASE``: Base address for the BL32 firmware component.
|
||||
|
||||
* **AArch32:** BL32 is used in place of BL31, so the option is equivalent to
|
||||
``BL31_BASE``.
|
||||
* **AArch64:** Secure-EL1 Payload. Defaults to using 128 KiB of space
|
||||
directly after BL31. For testing only, the port is primarily intended as
|
||||
a minimal PSCI implementation without a separate secure world.
|
||||
|
||||
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
|
||||
The ELF 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.
|
||||
|
||||
|
@ -75,6 +120,10 @@ use e.g. `qtestsign`_::
|
|||
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.
|
||||
|
||||
.. note::
|
||||
On AArch32 the ELF image is called ``bl32.elf``.
|
||||
The installation procedure is identical.
|
||||
|
||||
.. 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
|
||||
|
@ -82,8 +131,11 @@ to the ``tz`` partition on the device. BL31 should be running after a reboot.
|
|||
|
||||
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)::
|
||||
|
||||
AArch64 (BL31)
|
||||
^^^^^^^^^^^^^^
|
||||
BL31 prints some lines on the debug console, which will usually look like this
|
||||
(with ``DEBUG=1``, otherwise only the ``NOTICE`` lines are shown)::
|
||||
|
||||
...
|
||||
S - DDR Frequency, 400 MHz
|
||||
|
@ -109,8 +161,34 @@ this (with ``DEBUG=1``, otherwise only the ``NOTICE`` lines are shown)::
|
|||
Qualcomm-DragonBoard 410C
|
||||
...
|
||||
|
||||
AArch32 (BL32/SP_MIN)
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
BL32/SP_MIN prints some lines on the debug console, which will usually look like
|
||||
this (with ``DEBUG=1``, otherwise only the ``NOTICE`` lines are shown)::
|
||||
|
||||
...
|
||||
S - DDR Frequency, 400 MHz
|
||||
NOTICE: SP_MIN: v2.8(debug):v2.8
|
||||
NOTICE: SP_MIN: Built : 23:03:31, Mar 31 2023
|
||||
INFO: SP_MIN: Platform setup start
|
||||
INFO: ARM GICv2 driver initialized
|
||||
INFO: SP_MIN: Platform setup done
|
||||
INFO: SP_MIN: Initializing runtime services
|
||||
INFO: BL32: cortex_a53: CPU workaround for 819472 was applied
|
||||
INFO: BL32: cortex_a53: CPU workaround for 824069 was applied
|
||||
INFO: BL32: cortex_a53: CPU workaround for 826319 was applied
|
||||
INFO: BL32: cortex_a53: CPU workaround for 827319 was applied
|
||||
INFO: BL32: cortex_a53: CPU workaround for disable_non_temporal_hint was applied
|
||||
INFO: SP_MIN: Preparing exit to normal world
|
||||
INFO: Entry point address = 0x86400000
|
||||
INFO: SPSR = 0x1da
|
||||
Android Bootloader - UART_DM Initialized!!!
|
||||
[0] welcome to lk
|
||||
...
|
||||
|
||||
.. _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
|
||||
.. _tfalkstub: https://github.com/msm8916-mainline/tfalkstub
|
||||
|
|
131
plat/qti/msm8916/aarch32/msm8916_helpers.S
Normal file
131
plat/qti/msm8916/aarch32/msm8916_helpers.S
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch.h>
|
||||
#include <asm_macros.S>
|
||||
|
||||
#include <msm8916_mmap.h>
|
||||
|
||||
#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: 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
|
||||
/* There is just a single cluster so this is very simple */
|
||||
ldcopr r0, MPIDR
|
||||
and r0, r0, #MPIDR_CPU_MASK
|
||||
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
|
||||
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
|
183
plat/qti/msm8916/aarch32/uartdm_console.S
Normal file
183
plat/qti/msm8916/aarch32/uartdm_console.S
Normal file
|
@ -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
|
|
@ -30,7 +30,7 @@
|
|||
* -------------------------------------------------
|
||||
*/
|
||||
func plat_crash_console_init
|
||||
mov x1, #BLSP_UART2_BASE
|
||||
mov_imm x1, BLSP_UART_BASE
|
||||
mov x0, #1
|
||||
b console_uartdm_core_init
|
||||
endfunc plat_crash_console_init
|
||||
|
@ -44,7 +44,7 @@ endfunc plat_crash_console_init
|
|||
* -------------------------------------------------
|
||||
*/
|
||||
func plat_crash_console_putc
|
||||
mov x1, #BLSP_UART2_BASE
|
||||
mov_imm x1, BLSP_UART_BASE
|
||||
b console_uartdm_core_putc
|
||||
endfunc plat_crash_console_putc
|
||||
|
||||
|
@ -56,7 +56,7 @@ endfunc plat_crash_console_putc
|
|||
* -------------------------------------------------
|
||||
*/
|
||||
func plat_crash_console_flush
|
||||
mov x1, #BLSP_UART2_BASE
|
||||
mov_imm x1, BLSP_UART_BASE
|
||||
b console_uartdm_core_flush
|
||||
endfunc plat_crash_console_flush
|
||||
|
||||
|
@ -93,44 +93,43 @@ endfunc plat_my_core_pos
|
|||
*/
|
||||
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
|
||||
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 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
|
||||
* Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -23,8 +23,9 @@
|
|||
#define APPS_SMMU_BASE (PCNOC_BASE + 0x1e00000)
|
||||
#define APPS_SMMU_QCOM (APPS_SMMU_BASE + 0xf0000)
|
||||
|
||||
#define BLSP_UART1_BASE (PCNOC_BASE + 0x78af000)
|
||||
#define BLSP_UART2_BASE (PCNOC_BASE + 0x78b0000)
|
||||
#define 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)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
|
||||
* Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -8,6 +8,7 @@
|
|||
|
||||
#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
|
||||
|
@ -18,6 +19,8 @@
|
|||
*/
|
||||
#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
|
||||
|
@ -44,8 +47,9 @@
|
|||
#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32)
|
||||
#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32)
|
||||
|
||||
/* Timer frequency */
|
||||
/* 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
|
||||
|
@ -54,4 +58,9 @@
|
|||
*/
|
||||
#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 */
|
||||
|
|
|
@ -8,25 +8,10 @@
|
|||
|
||||
#include <arch.h>
|
||||
#include <common/debug.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 <plat/common/platform.h>
|
||||
|
||||
#include "msm8916_gicv2.h"
|
||||
#include <msm8916_mmap.h>
|
||||
#include <platform_def.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),
|
||||
{},
|
||||
};
|
||||
#include "msm8916_config.h"
|
||||
#include "msm8916_setup.h"
|
||||
|
||||
static struct {
|
||||
entry_point_info_t bl32;
|
||||
|
@ -44,160 +29,23 @@ static struct {
|
|||
.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);
|
||||
msm8916_early_platform_setup();
|
||||
}
|
||||
|
||||
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();
|
||||
msm8916_plat_arch_setup(BL31_BASE, BL31_END - BL31_BASE);
|
||||
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 all timer frames available to non-secure world */
|
||||
mmio_write_32(APCS_QTMR + 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)
|
||||
#define APCS_BOOT_START_ADDR_SEC (APCS_CFG + 0x04)
|
||||
#define REMAP_EN BIT_32(0)
|
||||
#define APCS_AA64NAA32_REG (APCS_CFG + 0x0c)
|
||||
|
||||
static void msm8916_configure_cpu_pm(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
/* Disallow non-secure access to boot remapper / TCM registers */
|
||||
mmio_write_32(APCS_CFG, 0);
|
||||
|
||||
/*
|
||||
* Disallow non-secure access to power management registers.
|
||||
* However, allow STS and PWR since those also seem to control access
|
||||
* to CPU frequency related registers (e.g. APCS_CMD_RCGR). If these
|
||||
* bits are not set, CPU frequency control fails in the non-secure world.
|
||||
*/
|
||||
mmio_write_32(APCS_GLB, APCS_GLB_SECURE_STS_NS | APCS_GLB_SECURE_PWR_NS);
|
||||
|
||||
/* Disallow non-secure access to L2 SAW2 */
|
||||
mmio_write_32(APCS_L2_SAW2, 0);
|
||||
|
||||
/* Disallow non-secure access to CPU ACS and SAW2 */
|
||||
for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
|
||||
mmio_write_32(APCS_ALIAS_ACS(cpu), 0);
|
||||
mmio_write_32(APCS_ALIAS_SAW2(cpu), 0);
|
||||
}
|
||||
|
||||
/* Make sure all further warm boots end up in BL31 and aarch64 state */
|
||||
CASSERT((BL31_BASE & 0xffff) == 0, assert_bl31_base_64k_aligned);
|
||||
mmio_write_32(APCS_BOOT_START_ADDR_SEC, BL31_BASE | REMAP_EN);
|
||||
mmio_write_32(APCS_AA64NAA32_REG, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* MSM8916 has a special "interrupt aggregation logic" in the APPS SMMU,
|
||||
* which allows routing context bank interrupts to one of 3 interrupt numbers
|
||||
* ("TZ/HYP/NS"). Route all interrupts to the non-secure interrupt number
|
||||
* by default to avoid special setup on the non-secure side.
|
||||
*/
|
||||
#define GCC_SMMU_CFG_CBCR (GCC_BASE + 0x12038)
|
||||
#define GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE (GCC_BASE + 0x4500c)
|
||||
#define SMMU_CFG_CLK_ENA BIT_32(12)
|
||||
#define APPS_SMMU_INTR_SEL_NS (APPS_SMMU_QCOM + 0x2000)
|
||||
#define APPS_SMMU_INTR_SEL_NS_EN_ALL U(0xffffffff)
|
||||
|
||||
static void msm8916_configure_smmu(void)
|
||||
{
|
||||
/* Enable SMMU configuration clock to enable register access */
|
||||
mmio_setbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA);
|
||||
while (mmio_read_32(GCC_SMMU_CFG_CBCR) & CLK_OFF)
|
||||
;
|
||||
|
||||
/* Route all context bank interrupts to non-secure interrupt */
|
||||
mmio_write_32(APPS_SMMU_INTR_SEL_NS, APPS_SMMU_INTR_SEL_NS_EN_ALL);
|
||||
|
||||
/* Disable configuration clock again */
|
||||
mmio_clrbits_32(GCC_APCS_SMMU_CLOCK_BRANCH_ENA_VOTE, SMMU_CFG_CLK_ENA);
|
||||
}
|
||||
|
||||
void bl31_platform_setup(void)
|
||||
{
|
||||
INFO("BL31: Platform setup start\n");
|
||||
generic_delay_timer_init();
|
||||
msm8916_configure_timer();
|
||||
msm8916_gicv2_init();
|
||||
msm8916_configure_cpu_pm();
|
||||
msm8916_configure_smmu();
|
||||
msm8916_platform_setup();
|
||||
msm8916_configure();
|
||||
INFO("BL31: Platform setup done\n");
|
||||
}
|
||||
|
||||
|
|
106
plat/qti/msm8916/msm8916_config.c
Normal file
106
plat/qti/msm8916/msm8916_config.c
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2023, Stephan Gerhold <stephan@gerhold.net>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <arch.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include "msm8916_config.h"
|
||||
#include "msm8916_gicv2.h"
|
||||
#include <msm8916_mmap.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
static void msm8916_configure_timer(void)
|
||||
{
|
||||
/* Set timer frequency */
|
||||
mmio_write_32(APCS_QTMR + CNTCTLBASE_CNTFRQ, PLAT_SYSCNT_FREQ);
|
||||
|
||||
/* Make all timer frames available to non-secure world */
|
||||
mmio_write_32(APCS_QTMR + 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)
|
||||
#define APCS_BOOT_START_ADDR_SEC (APCS_CFG + 0x04)
|
||||
#define REMAP_EN BIT_32(0)
|
||||
#define APCS_AA64NAA32_REG (APCS_CFG + 0x0c)
|
||||
|
||||
static void msm8916_configure_cpu_pm(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
||||
/* Disallow non-secure access to boot remapper / TCM registers */
|
||||
mmio_write_32(APCS_CFG, 0);
|
||||
|
||||
/*
|
||||
* Disallow non-secure access to power management registers.
|
||||
* However, allow STS and PWR since those also seem to control access
|
||||
* to CPU frequency related registers (e.g. APCS_CMD_RCGR). If these
|
||||
* bits are not set, CPU frequency control fails in the non-secure world.
|
||||
*/
|
||||
mmio_write_32(APCS_GLB, APCS_GLB_SECURE_STS_NS | APCS_GLB_SECURE_PWR_NS);
|
||||
|
||||
/* Disallow non-secure access to L2 SAW2 */
|
||||
mmio_write_32(APCS_L2_SAW2, 0);
|
||||
|
||||
/* Disallow non-secure access to CPU ACS and SAW2 */
|
||||
for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) {
|
||||
mmio_write_32(APCS_ALIAS_ACS(cpu), 0);
|
||||
mmio_write_32(APCS_ALIAS_SAW2(cpu), 0);
|
||||
}
|
||||
|
||||
#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(APCS_BOOT_START_ADDR_SEC, BL31_BASE | REMAP_EN);
|
||||
mmio_write_32(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(APCS_BOOT_START_ADDR_SEC, BL32_BASE | REMAP_EN);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_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 msm8916_configure(void)
|
||||
{
|
||||
msm8916_gicv2_configure();
|
||||
msm8916_configure_timer();
|
||||
msm8916_configure_cpu_pm();
|
||||
msm8916_configure_smmu();
|
||||
}
|
12
plat/qti/msm8916/msm8916_config.h
Normal file
12
plat/qti/msm8916/msm8916_config.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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);
|
||||
|
||||
#endif /* MSM8916_CONFIG_H */
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "msm8916_gicv2.h"
|
||||
#include <msm8916_mmap.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
#define IRQ_SEC_SGI_0 8
|
||||
#define IRQ_SEC_SGI_1 9
|
||||
|
@ -20,8 +21,6 @@
|
|||
#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),
|
||||
|
@ -53,6 +52,10 @@ static const gicv2_driver_data_t msm8916_gic_data = {
|
|||
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();
|
||||
|
|
|
@ -8,5 +8,6 @@
|
|||
#define MSM8916_GICV2_H
|
||||
|
||||
void msm8916_gicv2_init(void);
|
||||
void msm8916_gicv2_configure(void);
|
||||
|
||||
#endif /* MSM8916_GICV2_H */
|
||||
|
|
115
plat/qti/msm8916/msm8916_setup.c
Normal file
115
plat/qti/msm8916/msm8916_setup.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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[] = {
|
||||
{0, 1, 0x2}, {4, 5, 0x2},
|
||||
};
|
||||
|
||||
/*
|
||||
* 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();
|
||||
}
|
14
plat/qti/msm8916/msm8916_setup.h
Normal file
14
plat/qti/msm8916/msm8916_setup.h
Normal file
|
@ -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 */
|
|
@ -7,35 +7,37 @@
|
|||
include drivers/arm/gic/v2/gicv2.mk
|
||||
include lib/xlat_tables_v2/xlat_tables.mk
|
||||
|
||||
PLAT_BL_COMMON_SOURCES := ${XLAT_TABLES_LIB_SRCS}
|
||||
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
|
||||
|
||||
PLAT_INCLUDES := -Iinclude/plat/arm/common/${ARCH} \
|
||||
-Iplat/qti/msm8916/include
|
||||
MSM8916_PM_SOURCES := lib/cpus/${ARCH}/cortex_a53.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 += ${GICV2_SOURCES} \
|
||||
drivers/delay_timer/delay_timer.c \
|
||||
drivers/delay_timer/generic_delay_timer.c \
|
||||
lib/cpus/${ARCH}/cortex_a53.S \
|
||||
plat/common/plat_gicv2.c \
|
||||
plat/common/plat_psci_common.c \
|
||||
plat/qti/msm8916/msm8916_bl31_setup.c \
|
||||
plat/qti/msm8916/msm8916_cpu_boot.c \
|
||||
plat/qti/msm8916/msm8916_gicv2.c \
|
||||
plat/qti/msm8916/msm8916_pm.c \
|
||||
plat/qti/msm8916/msm8916_topology.c \
|
||||
plat/qti/msm8916/${ARCH}/msm8916_helpers.S \
|
||||
plat/qti/msm8916/${ARCH}/uartdm_console.S
|
||||
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
|
||||
|
||||
# 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
|
||||
|
||||
|
@ -61,5 +63,27 @@ ERRATA_A53_843419 := 1
|
|||
ERRATA_A53_855873 := 0 # Workaround works only for >= r0p3
|
||||
ERRATA_A53_1530924 := 1
|
||||
|
||||
# Build config flags
|
||||
# ------------------
|
||||
BL31_BASE ?= 0x86500000
|
||||
PRELOADED_BL33_BASE ?= 0x8f600000
|
||||
|
||||
ifeq (${ARCH},aarch64)
|
||||
BL32_BASE ?= BL31_LIMIT
|
||||
$(eval $(call add_define,BL31_BASE))
|
||||
else
|
||||
# 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))
|
||||
|
|
49
plat/qti/msm8916/sp_min/msm8916_sp_min_setup.c
Normal file
49
plat/qti/msm8916/sp_min/msm8916_sp_min_setup.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
11
plat/qti/msm8916/sp_min/sp_min-msm8916.mk
Normal file
11
plat/qti/msm8916/sp_min/sp_min-msm8916.mk
Normal file
|
@ -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
|
31
plat/qti/msm8916/tsp/msm8916_tsp_setup.c
Normal file
31
plat/qti/msm8916/tsp/msm8916_tsp_setup.c
Normal file
|
@ -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);
|
||||
}
|
8
plat/qti/msm8916/tsp/tsp-msm8916.mk
Normal file
8
plat/qti/msm8916/tsp/tsp-msm8916.mk
Normal file
|
@ -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
|
Loading…
Add table
Reference in a new issue