plat: a8k: enable PMU overflow interrupt handler

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>
This commit is contained in:
Marcin Wojtas 2018-03-21 09:59:59 +01:00 committed by Konstantin Porotchkin
parent 349df242ed
commit fd1718a2ff
5 changed files with 111 additions and 0 deletions

View 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

View 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
*/

View File

@ -134,6 +134,8 @@
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) \
@ -199,4 +201,6 @@
#define BL32_BASE TRUSTED_DRAM_BASE
#define MVEBU_PMU_IRQ_WA
#endif /* __PLATFORM_DEF_H__ */

View 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>
@ -17,6 +21,21 @@
#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();

View 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);