Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
[firefly-linux-kernel-4.4.55.git] / drivers / irqchip / irq-gic-common.c
1 /*
2  * Copyright (C) 2002 ARM Limited, All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <linux/interrupt.h>
18 #include <linux/io.h>
19 #include <linux/irq.h>
20 #include <linux/irqchip/arm-gic.h>
21
22 #include "irq-gic-common.h"
23
24 void gic_configure_irq(unsigned int irq, unsigned int type,
25                        void __iomem *base, void (*sync_access)(void))
26 {
27         u32 enablemask = 1 << (irq % 32);
28         u32 enableoff = (irq / 32) * 4;
29         u32 confmask = 0x2 << ((irq % 16) * 2);
30         u32 confoff = (irq / 16) * 4;
31         bool enabled = false;
32         u32 val;
33
34         /*
35          * Read current configuration register, and insert the config
36          * for "irq", depending on "type".
37          */
38         val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
39         if (type == IRQ_TYPE_LEVEL_HIGH)
40                 val &= ~confmask;
41         else if (type == IRQ_TYPE_EDGE_RISING)
42                 val |= confmask;
43
44         /*
45          * As recommended by the spec, disable the interrupt before changing
46          * the configuration
47          */
48         if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
49                 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
50                 if (sync_access)
51                         sync_access();
52                 enabled = true;
53         }
54
55         /*
56          * Write back the new configuration, and possibly re-enable
57          * the interrupt.
58          */
59         writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
60
61         if (enabled)
62                 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
63
64         if (sync_access)
65                 sync_access();
66 }
67
68 void __init gic_dist_config(void __iomem *base, int gic_irqs,
69                             void (*sync_access)(void))
70 {
71         unsigned int i;
72
73         /*
74          * Set all global interrupts to be level triggered, active low.
75          */
76         for (i = 32; i < gic_irqs; i += 16)
77                 writel_relaxed(0, base + GIC_DIST_CONFIG + i / 4);
78
79         /*
80          * Set priority on all global interrupts.
81          */
82         for (i = 32; i < gic_irqs; i += 4)
83                 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i);
84
85         /*
86          * Disable all interrupts.  Leave the PPI and SGIs alone
87          * as they are enabled by redistributor registers.
88          */
89         for (i = 32; i < gic_irqs; i += 32)
90                 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i / 8);
91
92         if (sync_access)
93                 sync_access();
94 }
95
96 void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
97 {
98         int i;
99
100         /*
101          * Deal with the banked PPI and SGI interrupts - disable all
102          * PPI interrupts, ensure all SGI interrupts are enabled.
103          */
104         writel_relaxed(0xffff0000, base + GIC_DIST_ENABLE_CLEAR);
105         writel_relaxed(0x0000ffff, base + GIC_DIST_ENABLE_SET);
106
107         /*
108          * Set priority on PPI and SGI interrupts
109          */
110         for (i = 0; i < 32; i += 4)
111                 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
112
113         if (sync_access)
114                 sync_access();
115 }