plat: a8k: enable PMU overflow interrupt handler
authorMarcin Wojtas <mw@semihalf.com>
Wed, 21 Mar 2018 08:59:59 +0000 (09:59 +0100)
committerKonstantin Porotchkin <kostap@marvell.com>
Mon, 3 Sep 2018 12:47:09 +0000 (15:47 +0300)
This patch enables handling PMU overflow IRQ by GIC SPI's
directly in EL3. Also implement additional SMC routine,
which can disable the solution on demand in runtime.

Since it is possible to configure PMU interrupt trigger type
in the MADT ACPI table, it is enough to set it only once in EL3
during initialization.

Change-Id: Ie76aa62ccc4fd7cabfec9e3d5ed9970ada1c1b2a
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Reviewed-by: Kostya Porotchkin <kostap@marvell.com>
include/plat/marvell/a8k/common/marvell_def.h
include/plat/marvell/a8k/common/plat_marvell.h
plat/marvell/a8k/common/include/platform_def.h
plat/marvell/common/marvell_gicv2.c
plat/marvell/common/mrvl_sip_svc.c

index 7dacf820a5b18d195fdb8d9ad90161ede40e469d..9429753ce7d44218a652f341a2e12754895fbc14 100644 (file)
@@ -63,6 +63,7 @@
 #define MARVELL_DRAM_END               (MARVELL_DRAM_BASE + \
                                         MARVELL_DRAM_SIZE - 1)
 
+#define MARVELL_IRQ_PIC0               28
 #define MARVELL_IRQ_SEC_PHY_TIMER      29
 
 #define MARVELL_IRQ_SEC_SGI_0          8
index 81cbf38714e71eae34330ccf7385662c18b14ec6..9ca68d3bc188892a48a28514d58a2f7d9e9a1583 100644 (file)
@@ -93,6 +93,14 @@ int marvell_io_is_toc_valid(void);
 void marvell_psci_arch_init(int ap_idx);
 void plat_marvell_system_reset(void);
 
+/*
+ * Miscellaneous platform SMC routines
+ */
+#ifdef MVEBU_PMU_IRQ_WA
+void mvebu_pmu_interrupt_enable(void);
+void mvebu_pmu_interrupt_disable(void);
+#endif
+
 /*
  * Optional functions required in Marvell standard platforms
  */
index f7bd23fa205d528dc32b8825988b7eef551cf1d3..06d4fa9cf984ede4cb3ff6782e5542b816742084 100644 (file)
        INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
                        GIC_INTR_CFG_LEVEL), \
        INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+                       GIC_INTR_CFG_LEVEL), \
+       INTR_PROP_DESC(MARVELL_IRQ_PIC0, GIC_HIGHEST_SEC_PRIORITY, grp, \
                        GIC_INTR_CFG_LEVEL)
 
 #define PLAT_MARVELL_G1S_IRQ_PROPS(grp) \
 
 #define BL32_BASE                              TRUSTED_DRAM_BASE
 
+#define MVEBU_PMU_IRQ_WA
+
 #endif /* __PLATFORM_DEF_H__ */
index ba8e409611e672bcd324be69cafe4a88b84ddc31..19e1ec0f53b3c9f95d1756d897987923148f14bd 100644 (file)
@@ -5,7 +5,11 @@
  * https://spdx.org/licenses
  */
 
+#include <bakery_lock.h>
+#include <debug.h>
 #include <gicv2.h>
+#include <interrupt_mgmt.h>
+#include <mmio.h>
 #include <plat_marvell.h>
 #include <platform.h>
 #include <platform_def.h>
 #pragma weak plat_marvell_gic_driver_init
 #pragma weak plat_marvell_gic_init
 
+#define A7K8K_PIC_CAUSE_REG            0xf03f0100
+#define A7K8K_PIC0_MASK_REG            0xf03f0108
+
+#define A7K8K_PIC_PMUOF_IRQ_MASK       (1 << 17)
+
+#define A7K8K_PIC_MAX_IRQS             32
+#define A7K8K_PIC_MAX_IRQ_MASK         ((1UL << A7K8K_PIC_MAX_IRQS) - 1)
+
+#define A7K8K_ODMIN_SET_REG            0xf0300040
+#define A7K8K_ODMI_PMU_IRQ(idx)                ((2 + idx) << 12)
+
+#define A7K8K_ODMI_PMU_GIC_IRQ(idx)    (130 + idx)
+
+static DEFINE_BAKERY_LOCK(a7k8k_irq_lock);
+
 /*
  * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0
  * interrupts.
@@ -50,6 +69,74 @@ void plat_marvell_gic_driver_init(void)
        gicv2_driver_init(&marvell_gic_data);
 }
 
+static uint64_t a7k8k_pmu_interrupt_handler(uint32_t id,
+                                         uint32_t flags,
+                                         void *handle,
+                                         void *cookie)
+{
+       unsigned int idx = plat_my_core_pos();
+       uint32_t irq;
+
+       bakery_lock_get(&a7k8k_irq_lock);
+
+       /* Acknowledge IRQ */
+       irq = plat_ic_acknowledge_interrupt();
+
+       plat_ic_end_of_interrupt(irq);
+
+       if (irq != MARVELL_IRQ_PIC0) {
+               bakery_lock_release(&a7k8k_irq_lock);
+               return 0;
+       }
+
+       /* Acknowledge PMU overflow IRQ in PIC0 */
+       mmio_setbits_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
+
+       /* Trigger ODMI Frame IRQ */
+       mmio_write_32(A7K8K_ODMIN_SET_REG, A7K8K_ODMI_PMU_IRQ(idx));
+
+       bakery_lock_release(&a7k8k_irq_lock);
+
+       return 0;
+}
+
+void mvebu_pmu_interrupt_enable(void)
+{
+       unsigned int idx;
+       uint32_t flags;
+       int32_t rc;
+
+       /* Reset PIC */
+       mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK);
+       /* Unmask PMU overflow IRQ in PIC0 */
+       mmio_clrbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
+
+       /* Configure ODMI Frame IRQs as edge triggered */
+       for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++)
+               gicv2_interrupt_set_cfg(A7K8K_ODMI_PMU_GIC_IRQ(idx),
+                                       GIC_INTR_CFG_EDGE);
+
+       /*
+        * Register IRQ handler as INTR_TYPE_S_EL1 as its the only valid type
+        * for GICv2 in ARM-TF.
+        */
+       flags = 0U;
+       set_interrupt_rm_flag((flags), (NON_SECURE));
+       rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
+                                            a7k8k_pmu_interrupt_handler,
+                                            flags);
+       if (rc != 0)
+               panic();
+}
+
+void mvebu_pmu_interrupt_disable(void)
+{
+       /* Reset PIC */
+       mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK);
+       /* Mask PMU overflow IRQ in PIC0 */
+       mmio_setbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK);
+}
+
 void plat_marvell_gic_init(void)
 {
        gicv2_distif_init();
index ec293afa3ec64e09f35c66dc5cc0137b385ff625..a0ca50d0a7c0b9808000338d193a0df2ac1f177d 100644 (file)
@@ -9,6 +9,7 @@
 #include <cache_llc.h>
 #include <debug.h>
 #include <marvell_plat_priv.h>
+#include <plat_marvell.h>
 #include <runtime_svc.h>
 #include <smcc.h>
 #include "comphy/phy-comphy-cp110.h"
@@ -30,6 +31,8 @@
 /* Miscellaneous FID's' */
 #define MV_SIP_DRAM_SIZE       0x82000010
 #define MV_SIP_LLC_ENABLE      0x82000011
+#define MV_SIP_PMU_IRQ_ENABLE  0x82000012
+#define MV_SIP_PMU_IRQ_DISABLE 0x82000013
 
 #define MAX_LANE_NR            6
 #define MVEBU_COMPHY_OFFSET    0x441000
@@ -109,6 +112,14 @@ uintptr_t mrvl_sip_smc_handler(uint32_t smc_fid,
                        llc_runtime_enable(i);
 
                SMC_RET1(handle, 0);
+#ifdef MVEBU_PMU_IRQ_WA
+       case MV_SIP_PMU_IRQ_ENABLE:
+               mvebu_pmu_interrupt_enable();
+               SMC_RET1(handle, 0);
+       case MV_SIP_PMU_IRQ_DISABLE:
+               mvebu_pmu_interrupt_disable();
+               SMC_RET1(handle, 0);
+#endif
 
        default:
                ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);