blob: 6ad335b0dcb788b889f748607f152eacd40af583 [file] [log] [blame]
Bradley Bolen571d3b52018-04-18 12:13:06 +03001/*
2 * Copyright (c) 2018 Marvell
3 * Copyright (c) 2018 Lexmark International, Inc.
Stephanos Ioannidis2b441732019-12-19 14:54:46 +09004 * Copyright (c) 2019 Stephanos Ioannidis <root@stephanos.io>
Bradley Bolen571d3b52018-04-18 12:13:06 +03005 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
Stephanos Ioannidis2b441732019-12-19 14:54:46 +09009/*
Sandeep Tripathybd985dc2020-04-22 01:55:37 +053010 * NOTE: This driver implements the GICv1 and GICv2 interfaces.
Stephanos Ioannidis2b441732019-12-19 14:54:46 +090011 */
12
Bradley Bolen571d3b52018-04-18 12:13:06 +030013#include <sw_isr_table.h>
Bradley Bolen571d3b52018-04-18 12:13:06 +030014#include <dt-bindings/interrupt-controller/arm-gic.h>
Stephanos Ioannidis2b441732019-12-19 14:54:46 +090015#include <drivers/interrupt_controller/gic.h>
Bradley Bolen571d3b52018-04-18 12:13:06 +030016
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +090017void arm_gic_irq_enable(unsigned int irq)
18{
19 int int_grp, int_off;
20
21 int_grp = irq / 32;
22 int_off = irq % 32;
23
24 sys_write32((1 << int_off), (GICD_ISENABLERn + int_grp * 4));
25}
26
27void arm_gic_irq_disable(unsigned int irq)
28{
29 int int_grp, int_off;
30
31 int_grp = irq / 32;
32 int_off = irq % 32;
33
34 sys_write32((1 << int_off), (GICD_ICENABLERn + int_grp * 4));
35}
36
37bool arm_gic_irq_is_enabled(unsigned int irq)
38{
39 int int_grp, int_off;
40 unsigned int enabler;
41
42 int_grp = irq / 32;
43 int_off = irq % 32;
44
45 enabler = sys_read32(GICD_ISENABLERn + int_grp * 4);
46
47 return (enabler & (1 << int_off)) != 0;
48}
49
50void arm_gic_irq_set_priority(
Kumar Galaa1b77fd2020-05-27 11:26:57 -050051 unsigned int irq, unsigned int prio, uint32_t flags)
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +090052{
53 int int_grp, int_off;
Kumar Galaa1b77fd2020-05-27 11:26:57 -050054 uint32_t val;
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +090055
56 /* Set priority */
57 sys_write8(prio & 0xff, GICD_IPRIORITYRn + irq);
58
59 /* Set interrupt type */
Bartlomiej Flakc0be43e2020-04-17 15:09:20 +020060 int_grp = (irq / 16) * 4;
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +090061 int_off = (irq % 16) * 2;
62
Bartlomiej Flakc0be43e2020-04-17 15:09:20 +020063 val = sys_read32(GICD_ICFGRn + int_grp);
Stephanos Ioannidis495407a2020-03-19 14:33:38 +090064 val &= ~(GICD_ICFGR_MASK << int_off);
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +090065 if (flags & IRQ_TYPE_EDGE) {
Stephanos Ioannidis495407a2020-03-19 14:33:38 +090066 val |= (GICD_ICFGR_TYPE << int_off);
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +090067 }
68
Bartlomiej Flakc0be43e2020-04-17 15:09:20 +020069 sys_write32(val, GICD_ICFGRn + int_grp);
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +090070}
71
72unsigned int arm_gic_get_active(void)
73{
74 int irq;
75
76 irq = sys_read32(GICC_IAR) & 0x3ff;
77 return irq;
78}
79
80void arm_gic_eoi(unsigned int irq)
81{
Sandeep Tripathyccb4b1e2020-06-26 17:50:14 +053082 /*
83 * Ensure the write to peripheral registers are *complete* before the write
84 * to GIC_EOIR.
85 *
86 * Note: The completion gurantee depends on various factors of system design
87 * and the barrier is the best core can do by which execution of further
88 * instructions waits till the barrier is alive.
89 */
90 __DSB();
91
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +090092 /* set to inactive */
93 sys_write32(irq, GICC_EOIR);
94}
Bradley Bolen571d3b52018-04-18 12:13:06 +030095
96static void gic_dist_init(void)
97{
98 unsigned int gic_irqs, i;
99
100 gic_irqs = sys_read32(GICD_TYPER) & 0x1f;
101 gic_irqs = (gic_irqs + 1) * 32;
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900102 if (gic_irqs > 1020) {
Bradley Bolen571d3b52018-04-18 12:13:06 +0300103 gic_irqs = 1020;
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900104 }
Bradley Bolen571d3b52018-04-18 12:13:06 +0300105
106 /*
107 * Disable the forwarding of pending interrupts
108 * from the Distributor to the CPU interfaces
109 */
Stephanos Ioannidis2b441732019-12-19 14:54:46 +0900110 sys_write32(0, GICD_CTLR);
Bradley Bolen571d3b52018-04-18 12:13:06 +0300111
112 /*
113 * Set all global interrupts to this CPU only.
114 */
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900115 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) {
Bradley Bolen571d3b52018-04-18 12:13:06 +0300116 sys_write32(0x01010101, GICD_ITARGETSRn + i);
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900117 }
Bradley Bolen571d3b52018-04-18 12:13:06 +0300118
119 /*
120 * Set all global interrupts to be level triggered, active low.
121 */
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900122 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 16) {
Bradley Bolen571d3b52018-04-18 12:13:06 +0300123 sys_write32(0, GICD_ICFGRn + i / 4);
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900124 }
Bradley Bolen571d3b52018-04-18 12:13:06 +0300125
126 /* Set priority on all global interrupts. */
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900127 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) {
Bradley Bolen571d3b52018-04-18 12:13:06 +0300128 sys_write32(0, GICD_IPRIORITYRn + i);
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900129 }
Bradley Bolen571d3b52018-04-18 12:13:06 +0300130
131 /* Set all interrupts to group 0 */
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900132 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) {
Bradley Bolen571d3b52018-04-18 12:13:06 +0300133 sys_write32(0, GICD_IGROUPRn + i / 8);
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900134 }
Bradley Bolen571d3b52018-04-18 12:13:06 +0300135
136 /*
137 * Disable all interrupts. Leave the PPI and SGIs alone
138 * as these enables are banked registers.
139 */
140 for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) {
Stephanos Ioannidis2b441732019-12-19 14:54:46 +0900141#ifndef CONFIG_GIC_V1
Bradley Bolen571d3b52018-04-18 12:13:06 +0300142 sys_write32(0xffffffff, GICD_ICACTIVERn + i / 8);
Stephanos Ioannidis2b441732019-12-19 14:54:46 +0900143#endif
Bradley Bolen571d3b52018-04-18 12:13:06 +0300144 sys_write32(0xffffffff, GICD_ICENABLERn + i / 8);
145 }
146
147 /*
148 * Enable the forwarding of pending interrupts
149 * from the Distributor to the CPU interfaces
150 */
Stephanos Ioannidis2b441732019-12-19 14:54:46 +0900151 sys_write32(1, GICD_CTLR);
Bradley Bolen571d3b52018-04-18 12:13:06 +0300152}
153
154static void gic_cpu_init(void)
155{
156 int i;
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500157 uint32_t val;
Bradley Bolen571d3b52018-04-18 12:13:06 +0300158
159 /*
160 * Deal with the banked PPI and SGI interrupts - disable all
161 * PPI interrupts, ensure all SGI interrupts are enabled.
162 */
Stephanos Ioannidis2b441732019-12-19 14:54:46 +0900163#ifndef CONFIG_GIC_V1
Bradley Bolen571d3b52018-04-18 12:13:06 +0300164 sys_write32(0xffffffff, GICD_ICACTIVERn);
Stephanos Ioannidis2b441732019-12-19 14:54:46 +0900165#endif
Bradley Bolen571d3b52018-04-18 12:13:06 +0300166 sys_write32(0xffff0000, GICD_ICENABLERn);
167 sys_write32(0x0000ffff, GICD_ISENABLERn);
168
169 /*
170 * Set priority on PPI and SGI interrupts
171 */
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900172 for (i = 0; i < 32; i += 4) {
Bradley Bolen571d3b52018-04-18 12:13:06 +0300173 sys_write32(0xa0a0a0a0, GICD_IPRIORITYRn + i);
Stephanos Ioannidis50519ce2020-02-11 15:47:59 +0900174 }
Bradley Bolen571d3b52018-04-18 12:13:06 +0300175
176 sys_write32(0xf0, GICC_PMR);
177
178 /*
179 * Enable interrupts and signal them using the IRQ signal.
180 */
Stephanos Ioannidis2b441732019-12-19 14:54:46 +0900181 val = sys_read32(GICC_CTLR);
182#ifndef CONFIG_GIC_V1
183 val &= ~GICC_CTLR_BYPASS_MASK;
184#endif
185 val |= GICC_CTLR_ENABLE_MASK;
186 sys_write32(val, GICC_CTLR);
Bradley Bolen571d3b52018-04-18 12:13:06 +0300187}
188
Bradley Bolen571d3b52018-04-18 12:13:06 +0300189/**
190 *
191 * @brief Initialize the GIC device driver
192 *
193 *
194 * @return N/A
195 */
196#define GIC_PARENT_IRQ 0
197#define GIC_PARENT_IRQ_PRI 0
198#define GIC_PARENT_IRQ_FLAGS 0
Carlo Caione0d1a6dc2020-12-11 11:03:48 +0100199int arm_gic_init(const struct device *unused)
Bradley Bolen571d3b52018-04-18 12:13:06 +0300200{
Carlo Caione0d1a6dc2020-12-11 11:03:48 +0100201 ARG_UNUSED(unused);
202
Bradley Bolen571d3b52018-04-18 12:13:06 +0300203 /* Init of Distributor interface registers */
204 gic_dist_init();
205
206 /* Init CPU interface registers */
207 gic_cpu_init();
208
209 return 0;
210}
Carlo Caione0d1a6dc2020-12-11 11:03:48 +0100211
212SYS_INIT(arm_gic_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);