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 <stephan@gerhold.net>
This commit is contained in:
Stephan Gerhold 2021-12-01 20:03:33 +01:00
parent a7521bd5d8
commit af6447315c
6 changed files with 161 additions and 0 deletions

View File

@ -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)

View File

@ -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 <drivers/arm/gicv2.h> to avoid a failing assert().
*/
#define GICD_PIDR2_GICV2 U(0xFD8)
#endif /* PLATFORM_DEF_H */

View File

@ -15,6 +15,7 @@
#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>
@ -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)

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <drivers/arm/gicv2.h>
#include <lib/mmio.h>
#include "msm8916_gicv2.h"
#include <msm8916_mmap.h>
#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();
}

View File

@ -0,0 +1,12 @@
/*
* Copyright (c) 2021, Stephan Gerhold <stephan@gerhold.net>
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MSM8916_GICV2_H
#define MSM8916_GICV2_H
void msm8916_gicv2_init(void);
#endif /* MSM8916_GICV2_H */

View File

@ -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 \