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