xref: /arm-trusted-firmware/plat/marvell/armada/common/marvell_gicv2.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
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