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