1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (C) 2018 Marvell International Ltd. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu * https://spdx.org/licenses 6*91f16700Schasinglulu */ 7*91f16700Schasinglulu 8*91f16700Schasinglulu #include <platform_def.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <bl31/interrupt_mgmt.h> 11*91f16700Schasinglulu #include <common/debug.h> 12*91f16700Schasinglulu #include <drivers/arm/gicv2.h> 13*91f16700Schasinglulu #include <lib/bakery_lock.h> 14*91f16700Schasinglulu #include <lib/mmio.h> 15*91f16700Schasinglulu #include <plat/common/platform.h> 16*91f16700Schasinglulu 17*91f16700Schasinglulu #include <plat_marvell.h> 18*91f16700Schasinglulu 19*91f16700Schasinglulu /* 20*91f16700Schasinglulu * The following functions are defined as weak to allow a platform to override 21*91f16700Schasinglulu * the way the GICv2 driver is initialised and used. 22*91f16700Schasinglulu */ 23*91f16700Schasinglulu #pragma weak plat_marvell_gic_driver_init 24*91f16700Schasinglulu #pragma weak plat_marvell_gic_init 25*91f16700Schasinglulu 26*91f16700Schasinglulu #define A7K8K_PIC_CAUSE_REG 0xf03f0100 27*91f16700Schasinglulu #define A7K8K_PIC0_MASK_REG 0xf03f0108 28*91f16700Schasinglulu 29*91f16700Schasinglulu #define A7K8K_PIC_PMUOF_IRQ_MASK (1 << 17) 30*91f16700Schasinglulu 31*91f16700Schasinglulu #define A7K8K_PIC_MAX_IRQS 32 32*91f16700Schasinglulu #define A7K8K_PIC_MAX_IRQ_MASK ((1UL << A7K8K_PIC_MAX_IRQS) - 1) 33*91f16700Schasinglulu 34*91f16700Schasinglulu #define A7K8K_ODMIN_SET_REG 0xf0300040 35*91f16700Schasinglulu #define A7K8K_ODMI_PMU_IRQ(idx) ((2 + idx) << 12) 36*91f16700Schasinglulu 37*91f16700Schasinglulu #define A7K8K_ODMI_PMU_GIC_IRQ(idx) (130 + idx) 38*91f16700Schasinglulu 39*91f16700Schasinglulu static DEFINE_BAKERY_LOCK(a7k8k_irq_lock); 40*91f16700Schasinglulu 41*91f16700Schasinglulu /* 42*91f16700Schasinglulu * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 43*91f16700Schasinglulu * interrupts. 44*91f16700Schasinglulu */ 45*91f16700Schasinglulu static const interrupt_prop_t marvell_interrupt_props[] = { 46*91f16700Schasinglulu PLAT_MARVELL_G1S_IRQ_PROPS(GICV2_INTR_GROUP0), 47*91f16700Schasinglulu PLAT_MARVELL_G0_IRQ_PROPS(GICV2_INTR_GROUP0) 48*91f16700Schasinglulu }; 49*91f16700Schasinglulu 50*91f16700Schasinglulu static unsigned int target_mask_array[PLATFORM_CORE_COUNT]; 51*91f16700Schasinglulu 52*91f16700Schasinglulu /* 53*91f16700Schasinglulu * Ideally `marvell_gic_data` structure definition should be a `const` but it is 54*91f16700Schasinglulu * kept as modifiable for overwriting with different GICD and GICC base when 55*91f16700Schasinglulu * running on FVP with VE memory map. 56*91f16700Schasinglulu */ 57*91f16700Schasinglulu static gicv2_driver_data_t marvell_gic_data = { 58*91f16700Schasinglulu .gicd_base = PLAT_MARVELL_GICD_BASE, 59*91f16700Schasinglulu .gicc_base = PLAT_MARVELL_GICC_BASE, 60*91f16700Schasinglulu .interrupt_props = marvell_interrupt_props, 61*91f16700Schasinglulu .interrupt_props_num = ARRAY_SIZE(marvell_interrupt_props), 62*91f16700Schasinglulu .target_masks = target_mask_array, 63*91f16700Schasinglulu .target_masks_num = ARRAY_SIZE(target_mask_array), 64*91f16700Schasinglulu }; 65*91f16700Schasinglulu 66*91f16700Schasinglulu /* 67*91f16700Schasinglulu * ARM common helper to initialize the GICv2 only driver. 68*91f16700Schasinglulu */ 69*91f16700Schasinglulu void plat_marvell_gic_driver_init(void) 70*91f16700Schasinglulu { 71*91f16700Schasinglulu gicv2_driver_init(&marvell_gic_data); 72*91f16700Schasinglulu } 73*91f16700Schasinglulu 74*91f16700Schasinglulu static uint64_t a7k8k_pmu_interrupt_handler(uint32_t id, 75*91f16700Schasinglulu uint32_t flags, 76*91f16700Schasinglulu void *handle, 77*91f16700Schasinglulu void *cookie) 78*91f16700Schasinglulu { 79*91f16700Schasinglulu unsigned int idx = plat_my_core_pos(); 80*91f16700Schasinglulu uint32_t irq; 81*91f16700Schasinglulu 82*91f16700Schasinglulu bakery_lock_get(&a7k8k_irq_lock); 83*91f16700Schasinglulu 84*91f16700Schasinglulu /* Acknowledge IRQ */ 85*91f16700Schasinglulu irq = plat_ic_acknowledge_interrupt(); 86*91f16700Schasinglulu 87*91f16700Schasinglulu plat_ic_end_of_interrupt(irq); 88*91f16700Schasinglulu 89*91f16700Schasinglulu if (irq != MARVELL_IRQ_PIC0) { 90*91f16700Schasinglulu bakery_lock_release(&a7k8k_irq_lock); 91*91f16700Schasinglulu return 0; 92*91f16700Schasinglulu } 93*91f16700Schasinglulu 94*91f16700Schasinglulu /* Acknowledge PMU overflow IRQ in PIC0 */ 95*91f16700Schasinglulu mmio_setbits_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_PMUOF_IRQ_MASK); 96*91f16700Schasinglulu 97*91f16700Schasinglulu /* Trigger ODMI Frame IRQ */ 98*91f16700Schasinglulu mmio_write_32(A7K8K_ODMIN_SET_REG, A7K8K_ODMI_PMU_IRQ(idx)); 99*91f16700Schasinglulu 100*91f16700Schasinglulu bakery_lock_release(&a7k8k_irq_lock); 101*91f16700Schasinglulu 102*91f16700Schasinglulu return 0; 103*91f16700Schasinglulu } 104*91f16700Schasinglulu 105*91f16700Schasinglulu void mvebu_pmu_interrupt_enable(void) 106*91f16700Schasinglulu { 107*91f16700Schasinglulu unsigned int idx; 108*91f16700Schasinglulu uint32_t flags; 109*91f16700Schasinglulu int32_t rc; 110*91f16700Schasinglulu 111*91f16700Schasinglulu /* Reset PIC */ 112*91f16700Schasinglulu mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK); 113*91f16700Schasinglulu /* Unmask PMU overflow IRQ in PIC0 */ 114*91f16700Schasinglulu mmio_clrbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK); 115*91f16700Schasinglulu 116*91f16700Schasinglulu /* Configure ODMI Frame IRQs as edge triggered */ 117*91f16700Schasinglulu for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++) 118*91f16700Schasinglulu gicv2_interrupt_set_cfg(A7K8K_ODMI_PMU_GIC_IRQ(idx), 119*91f16700Schasinglulu GIC_INTR_CFG_EDGE); 120*91f16700Schasinglulu 121*91f16700Schasinglulu /* 122*91f16700Schasinglulu * Register IRQ handler as INTR_TYPE_S_EL1 as its the only valid type 123*91f16700Schasinglulu * for GICv2 in ARM-TF. 124*91f16700Schasinglulu */ 125*91f16700Schasinglulu flags = 0U; 126*91f16700Schasinglulu set_interrupt_rm_flag((flags), (NON_SECURE)); 127*91f16700Schasinglulu rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, 128*91f16700Schasinglulu a7k8k_pmu_interrupt_handler, 129*91f16700Schasinglulu flags); 130*91f16700Schasinglulu if (rc != 0) 131*91f16700Schasinglulu panic(); 132*91f16700Schasinglulu } 133*91f16700Schasinglulu 134*91f16700Schasinglulu void mvebu_pmu_interrupt_disable(void) 135*91f16700Schasinglulu { 136*91f16700Schasinglulu /* Reset PIC */ 137*91f16700Schasinglulu mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK); 138*91f16700Schasinglulu /* Mask PMU overflow IRQ in PIC0 */ 139*91f16700Schasinglulu mmio_setbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK); 140*91f16700Schasinglulu } 141*91f16700Schasinglulu 142*91f16700Schasinglulu void plat_marvell_gic_init(void) 143*91f16700Schasinglulu { 144*91f16700Schasinglulu gicv2_distif_init(); 145*91f16700Schasinglulu gicv2_pcpu_distif_init(); 146*91f16700Schasinglulu gicv2_set_pe_target_mask(plat_my_core_pos()); 147*91f16700Schasinglulu gicv2_cpuif_enable(); 148*91f16700Schasinglulu } 149