]> git.baikalelectronics.ru Git - arm-tf.git/commitdiff
feat(msm8916): setup hardware for non-secure world
authorStephan Gerhold <stephan@gerhold.net>
Wed, 1 Dec 2021 19:03:33 +0000 (20:03 +0100)
committerStephan Gerhold <stephan@gerhold.net>
Thu, 3 Feb 2022 14:19:26 +0000 (15:19 +0100)
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>
plat/qti/msm8916/include/msm8916_mmap.h
plat/qti/msm8916/include/platform_def.h
plat/qti/msm8916/msm8916_bl31_setup.c
plat/qti/msm8916/msm8916_gicv2.c [new file with mode: 0644]
plat/qti/msm8916/msm8916_gicv2.h [new file with mode: 0644]
plat/qti/msm8916/platform.mk

index 1696b84d170177cb38a1ef26718c10580078ff72..406ae6b4e46d81e9e8bcd01c0aa4be6b23ad609c 100644 (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)
 
index 4ad26dd832c27e86dd3a87e64e677c6a3946bbee..bfade70a3a631b8df9a391c7a80226c956aacbf6 100644 (file)
 /* 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 */
index a27549ead6229742ef4ce44fe9045a5320485afa..9c4fd064439dd99d7746abda13f93bec2d60f8ae 100644 (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)
diff --git a/plat/qti/msm8916/msm8916_gicv2.c b/plat/qti/msm8916/msm8916_gicv2.c
new file mode 100644 (file)
index 0000000..25a6628
--- /dev/null
@@ -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();
+}
diff --git a/plat/qti/msm8916/msm8916_gicv2.h b/plat/qti/msm8916/msm8916_gicv2.h
new file mode 100644 (file)
index 0000000..99db0d3
--- /dev/null
@@ -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 */
index 2d199e06163dc474efcd10651bb7d2c6a0019716..21ea450a8c248876eac3b0f7c9166f374b698844 100644 (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      \