]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
4db8e6d2 SK |
2 | /* |
3 | * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se> | |
4 | * Copyright (C) 2014 Stefan Kristansson <stefan.kristiansson@saunalahti.fi> | |
4db8e6d2 SK |
5 | */ |
6 | ||
7 | #include <linux/irq.h> | |
41a83e06 | 8 | #include <linux/irqchip.h> |
4db8e6d2 SK |
9 | #include <linux/of.h> |
10 | #include <linux/of_irq.h> | |
11 | #include <linux/of_address.h> | |
12 | ||
4db8e6d2 SK |
13 | /* OR1K PIC implementation */ |
14 | ||
15 | struct or1k_pic_dev { | |
16 | struct irq_chip chip; | |
17 | irq_flow_handler_t handle; | |
18 | unsigned long flags; | |
19 | }; | |
20 | ||
21 | /* | |
22 | * We're a couple of cycles faster than the generic implementations with | |
23 | * these 'fast' versions. | |
24 | */ | |
25 | ||
26 | static void or1k_pic_mask(struct irq_data *data) | |
27 | { | |
28 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); | |
29 | } | |
30 | ||
31 | static void or1k_pic_unmask(struct irq_data *data) | |
32 | { | |
33 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq)); | |
34 | } | |
35 | ||
36 | static void or1k_pic_ack(struct irq_data *data) | |
37 | { | |
38 | mtspr(SPR_PICSR, (1UL << data->hwirq)); | |
39 | } | |
40 | ||
41 | static void or1k_pic_mask_ack(struct irq_data *data) | |
42 | { | |
43 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); | |
44 | mtspr(SPR_PICSR, (1UL << data->hwirq)); | |
45 | } | |
46 | ||
47 | /* | |
48 | * There are two oddities with the OR1200 PIC implementation: | |
49 | * i) LEVEL-triggered interrupts are latched and need to be cleared | |
50 | * ii) the interrupt latch is cleared by writing a 0 to the bit, | |
51 | * as opposed to a 1 as mandated by the spec | |
52 | */ | |
53 | static void or1k_pic_or1200_ack(struct irq_data *data) | |
54 | { | |
55 | mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq)); | |
56 | } | |
57 | ||
58 | static void or1k_pic_or1200_mask_ack(struct irq_data *data) | |
59 | { | |
60 | mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq)); | |
61 | mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq)); | |
62 | } | |
63 | ||
64 | static struct or1k_pic_dev or1k_pic_level = { | |
65 | .chip = { | |
66 | .name = "or1k-PIC-level", | |
67 | .irq_unmask = or1k_pic_unmask, | |
68 | .irq_mask = or1k_pic_mask, | |
ca387019 | 69 | .irq_mask_ack = or1k_pic_mask_ack, |
4db8e6d2 SK |
70 | }, |
71 | .handle = handle_level_irq, | |
72 | .flags = IRQ_LEVEL | IRQ_NOPROBE, | |
73 | }; | |
74 | ||
75 | static struct or1k_pic_dev or1k_pic_edge = { | |
76 | .chip = { | |
77 | .name = "or1k-PIC-edge", | |
78 | .irq_unmask = or1k_pic_unmask, | |
79 | .irq_mask = or1k_pic_mask, | |
80 | .irq_ack = or1k_pic_ack, | |
81 | .irq_mask_ack = or1k_pic_mask_ack, | |
82 | }, | |
83 | .handle = handle_edge_irq, | |
84 | .flags = IRQ_LEVEL | IRQ_NOPROBE, | |
85 | }; | |
86 | ||
87 | static struct or1k_pic_dev or1k_pic_or1200 = { | |
88 | .chip = { | |
89 | .name = "or1200-PIC", | |
90 | .irq_unmask = or1k_pic_unmask, | |
91 | .irq_mask = or1k_pic_mask, | |
92 | .irq_ack = or1k_pic_or1200_ack, | |
93 | .irq_mask_ack = or1k_pic_or1200_mask_ack, | |
94 | }, | |
95 | .handle = handle_level_irq, | |
96 | .flags = IRQ_LEVEL | IRQ_NOPROBE, | |
97 | }; | |
98 | ||
99 | static struct irq_domain *root_domain; | |
100 | ||
101 | static inline int pic_get_irq(int first) | |
102 | { | |
103 | int hwirq; | |
104 | ||
105 | hwirq = ffs(mfspr(SPR_PICSR) >> first); | |
106 | if (!hwirq) | |
107 | return NO_IRQ; | |
108 | else | |
109 | hwirq = hwirq + first - 1; | |
110 | ||
b0fee1dc | 111 | return hwirq; |
4db8e6d2 SK |
112 | } |
113 | ||
114 | static void or1k_pic_handle_irq(struct pt_regs *regs) | |
115 | { | |
116 | int irq = -1; | |
117 | ||
118 | while ((irq = pic_get_irq(irq + 1)) != NO_IRQ) | |
b0fee1dc | 119 | handle_domain_irq(root_domain, irq, regs); |
4db8e6d2 SK |
120 | } |
121 | ||
122 | static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | |
123 | { | |
124 | struct or1k_pic_dev *pic = d->host_data; | |
125 | ||
126 | irq_set_chip_and_handler(irq, &pic->chip, pic->handle); | |
127 | irq_set_status_flags(irq, pic->flags); | |
128 | ||
129 | return 0; | |
130 | } | |
131 | ||
132 | static const struct irq_domain_ops or1k_irq_domain_ops = { | |
133 | .xlate = irq_domain_xlate_onecell, | |
134 | .map = or1k_map, | |
135 | }; | |
136 | ||
137 | /* | |
138 | * This sets up the IRQ domain for the PIC built in to the OpenRISC | |
139 | * 1000 CPU. This is the "root" domain as these are the interrupts | |
140 | * that directly trigger an exception in the CPU. | |
141 | */ | |
142 | static int __init or1k_pic_init(struct device_node *node, | |
143 | struct or1k_pic_dev *pic) | |
144 | { | |
145 | /* Disable all interrupts until explicitly requested */ | |
146 | mtspr(SPR_PICMR, (0UL)); | |
147 | ||
148 | root_domain = irq_domain_add_linear(node, 32, &or1k_irq_domain_ops, | |
149 | pic); | |
150 | ||
151 | set_handle_irq(or1k_pic_handle_irq); | |
152 | ||
153 | return 0; | |
154 | } | |
155 | ||
156 | static int __init or1k_pic_or1200_init(struct device_node *node, | |
157 | struct device_node *parent) | |
158 | { | |
159 | return or1k_pic_init(node, &or1k_pic_or1200); | |
160 | } | |
161 | IRQCHIP_DECLARE(or1k_pic_or1200, "opencores,or1200-pic", or1k_pic_or1200_init); | |
162 | IRQCHIP_DECLARE(or1k_pic, "opencores,or1k-pic", or1k_pic_or1200_init); | |
163 | ||
164 | static int __init or1k_pic_level_init(struct device_node *node, | |
165 | struct device_node *parent) | |
166 | { | |
167 | return or1k_pic_init(node, &or1k_pic_level); | |
168 | } | |
169 | IRQCHIP_DECLARE(or1k_pic_level, "opencores,or1k-pic-level", | |
170 | or1k_pic_level_init); | |
171 | ||
172 | static int __init or1k_pic_edge_init(struct device_node *node, | |
173 | struct device_node *parent) | |
174 | { | |
175 | return or1k_pic_init(node, &or1k_pic_edge); | |
176 | } | |
177 | IRQCHIP_DECLARE(or1k_pic_edge, "opencores,or1k-pic-edge", or1k_pic_edge_init); |