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>
diff --git a/plat/qti/msm8916/include/msm8916_mmap.h b/plat/qti/msm8916/include/msm8916_mmap.h
index 1696b84..406ae6b 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 4ad26dd..bfade70 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 <drivers/arm/gicv2.h> 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 a27549e..9c4fd06 100644
--- a/plat/qti/msm8916/msm8916_bl31_setup.c
+++ b/plat/qti/msm8916/msm8916_bl31_setup.c
@@ -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 @@
 	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 0000000..25a6628
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_gicv2.c
@@ -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
index 0000000..99db0d3
--- /dev/null
+++ b/plat/qti/msm8916/msm8916_gicv2.h
@@ -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 */
diff --git a/plat/qti/msm8916/platform.mk b/plat/qti/msm8916/platform.mk
index 2d199e0..21ea450 100644
--- a/plat/qti/msm8916/platform.mk
+++ b/plat/qti/msm8916/platform.mk
@@ -19,6 +19,7 @@
 			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	\