xref: /netbsd-src/sys/arch/macppc/macppc/pic_heathrow.c (revision 22c149c8548c1aa3b78f0abba8bb56cd0e17893c)
1 /*	$NetBSD: pic_heathrow.c,v 1.12 2021/01/26 14:49:41 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 Michael Lorenz
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: pic_heathrow.c,v 1.12 2021/01/26 14:49:41 thorpej Exp $");
31 
32 #include "opt_interrupt.h"
33 
34 #include <sys/param.h>
35 #include <sys/kmem.h>
36 #include <sys/kernel.h>
37 
38 #include <machine/pio.h>
39 
40 #include <dev/ofw/openfirm.h>
41 
42 #include <machine/autoconf.h>
43 #include <arch/powerpc/pic/picvar.h>
44 
45 static void heathrow_enable_irq(struct pic_ops *, int, int);
46 static void heathrow_reenable_irq(struct pic_ops *, int, int);
47 static void heathrow_disable_irq(struct pic_ops *, int);
48 static int  heathrow_get_irq(struct pic_ops *, int);
49 static void heathrow_ack_irq(struct pic_ops *, int);
50 static void heathrow_establish_irq(struct pic_ops *, int, int, int);
51 
52 struct heathrow_ops {
53 	struct pic_ops pic;
54 	uint32_t pending_events_h;
55 	uint32_t pending_events_l;
56 	uint32_t enable_mask_h;
57 	uint32_t enable_mask_l;
58 	uint32_t level_mask_h;
59 	uint32_t level_mask_l;
60 };
61 
62 static struct heathrow_ops *setup_heathrow(uint32_t);
63 static inline void heathrow_read_events(struct heathrow_ops *);
64 
65 #define INT_STATE_REG_H		((uint32_t)pic->pic_cookie + 0x10)
66 #define INT_ENABLE_REG_H	((uint32_t)pic->pic_cookie + 0x14)
67 #define INT_CLEAR_REG_H		((uint32_t)pic->pic_cookie + 0x18)
68 #define INT_LEVEL_REG_H		((uint32_t)pic->pic_cookie + 0x1c)
69 #define INT_STATE_REG_L		((uint32_t)pic->pic_cookie + 0x20)
70 #define INT_ENABLE_REG_L	((uint32_t)pic->pic_cookie + 0x24)
71 #define INT_CLEAR_REG_L		((uint32_t)pic->pic_cookie + 0x28)
72 #define INT_LEVEL_REG_L		((uint32_t)pic->pic_cookie + 0x2c)
73 
74 static const char *compat[] = {
75 	"heathrow",
76 	NULL
77 };
78 
init_heathrow(void)79 int init_heathrow(void)
80 {
81 	uint32_t reg[5];
82 	uint32_t obio_base;
83 	int      heathrow;
84 
85 	heathrow = OF_finddevice("/pci/mac-io");
86 	if (heathrow == -1)
87 		heathrow = OF_finddevice("mac-io");
88 	if (heathrow == -1)
89 		return FALSE;
90 
91 	if (! of_compatible(heathrow, compat))
92 		return FALSE;
93 
94 	if (OF_getprop(heathrow, "assigned-addresses", reg, sizeof(reg)) != 20)
95 		return FALSE;
96 
97 	obio_base = reg[2];
98 	aprint_normal("found heathrow PIC at %08x\n", obio_base);
99 	setup_heathrow(obio_base);
100 	/* TODO: look for 2nd Heathrow */
101 	return TRUE;
102 }
103 
104 static struct heathrow_ops *
setup_heathrow(uint32_t addr)105 setup_heathrow(uint32_t addr)
106 {
107 	struct heathrow_ops *heathrow;
108 	struct pic_ops *pic;
109 
110 	heathrow = kmem_zalloc(sizeof(struct heathrow_ops), KM_SLEEP);
111 	pic = &heathrow->pic;
112 
113 	pic->pic_numintrs = 64;
114 	pic->pic_cookie = (void *)addr;
115 	pic->pic_enable_irq = heathrow_enable_irq;
116 	pic->pic_reenable_irq = heathrow_reenable_irq;
117 	pic->pic_disable_irq = heathrow_disable_irq;
118 	pic->pic_get_irq = heathrow_get_irq;
119 	pic->pic_ack_irq = heathrow_ack_irq;
120 	pic->pic_establish_irq = heathrow_establish_irq;
121 	pic->pic_finish_setup = NULL;
122 
123 	strcpy(pic->pic_name, "heathrow");
124 	pic_add(pic);
125 	heathrow->pending_events_l = 0;
126 	heathrow->enable_mask_l = 0;
127 	heathrow->level_mask_l = 0;
128 	heathrow->pending_events_h = 0;
129 	heathrow->enable_mask_h = 0;
130 	heathrow->level_mask_h = 0;
131 	out32rb(INT_ENABLE_REG_L, 0);
132 	out32rb(INT_CLEAR_REG_L, 0xffffffff);
133 	out32rb(INT_ENABLE_REG_H, 0);
134 	out32rb(INT_CLEAR_REG_H, 0xffffffff);
135 	return heathrow;
136 }
137 
138 static void
heathrow_enable_irq(struct pic_ops * pic,int irq,int type)139 heathrow_enable_irq(struct pic_ops *pic, int irq, int type)
140 {
141 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
142 	uint32_t mask = 1 << (irq & 0x1f);
143 
144 	if (irq & 0x20) {
145 		heathrow->enable_mask_h |= mask;
146 		out32rb(INT_ENABLE_REG_H, heathrow->enable_mask_h);
147 	} else {
148 		heathrow->enable_mask_l |= mask;
149 		out32rb(INT_ENABLE_REG_L, heathrow->enable_mask_l);
150 	}
151 }
152 
153 static void
heathrow_reenable_irq(struct pic_ops * pic,int irq,int type)154 heathrow_reenable_irq(struct pic_ops *pic, int irq, int type)
155 {
156 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
157 	uint32_t levels;
158 	uint32_t mask = 1 << (irq  & 0x1f);
159 
160 	if (irq & 0x20) {
161 		heathrow->enable_mask_h |= mask;
162 		out32rb(INT_ENABLE_REG_H, heathrow->enable_mask_h);
163 		levels = in32rb(INT_STATE_REG_H);
164 		if (levels & mask) {
165 			pic_mark_pending(pic->pic_intrbase + irq);
166 			out32rb(INT_CLEAR_REG_H, mask);
167 		}
168 	} else {
169 		heathrow->enable_mask_l |= mask;
170 		out32rb(INT_ENABLE_REG_L, heathrow->enable_mask_l);
171 		levels = in32rb(INT_STATE_REG_L);
172 		if (levels & mask) {
173 			pic_mark_pending(pic->pic_intrbase + irq);
174 			out32rb(INT_CLEAR_REG_L, mask);
175 		}
176 	}
177 }
178 
179 static void
heathrow_disable_irq(struct pic_ops * pic,int irq)180 heathrow_disable_irq(struct pic_ops *pic, int irq)
181 {
182 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
183 	uint32_t mask = 1 << (irq & 0x1f);
184 
185 	if (irq & 0x20) {
186 		heathrow->enable_mask_h &= ~mask;
187 		out32rb(INT_ENABLE_REG_H, heathrow->enable_mask_h);
188 	} else {
189 		heathrow->enable_mask_l &= ~mask;
190 		out32rb(INT_ENABLE_REG_L, heathrow->enable_mask_l);
191 	}
192 }
193 
194 static inline void
heathrow_read_events(struct heathrow_ops * heathrow)195 heathrow_read_events(struct heathrow_ops *heathrow)
196 {
197 	struct pic_ops *pic = &heathrow->pic;
198 	uint32_t irqs, events, levels;
199 
200 	/* first the low 32 IRQs */
201 	irqs = in32rb(INT_STATE_REG_L);
202 	events = irqs & ~heathrow->level_mask_l;
203 
204 	levels = in32rb(INT_LEVEL_REG_L) & heathrow->enable_mask_l;
205 	events |= levels & heathrow->level_mask_l;
206 	out32rb(INT_CLEAR_REG_L, events | irqs);
207 	heathrow->pending_events_l |= events;
208 
209 	/* then the upper 32 */
210 	irqs = in32rb(INT_STATE_REG_H);
211 	events = irqs & ~heathrow->level_mask_h;
212 	levels = in32rb(INT_LEVEL_REG_L) & heathrow->enable_mask_h;
213 	events |= levels & heathrow->level_mask_h;
214 	out32rb(INT_CLEAR_REG_H, events);
215 	heathrow->pending_events_h |= events;
216 }
217 
218 static int
heathrow_get_irq(struct pic_ops * pic,int mode)219 heathrow_get_irq(struct pic_ops *pic, int mode)
220 {
221 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
222 	int bit, mask;
223 
224 	if ((heathrow->pending_events_h == 0) &&
225 	    (heathrow->pending_events_l == 0))
226 		heathrow_read_events(heathrow);
227 
228 	if ((heathrow->pending_events_h == 0) &&
229 	    (heathrow->pending_events_l == 0))
230 		return 255;
231 
232 	if (heathrow->pending_events_l != 0) {
233 		bit = 31 - __builtin_clz(heathrow->pending_events_l);
234 		mask = 1 << bit;
235 		heathrow->pending_events_l &= ~mask;
236 		return bit;
237 	}
238 
239 	if (heathrow->pending_events_h != 0) {
240 		bit = 31 - __builtin_clz(heathrow->pending_events_h);
241 		mask = 1 << bit;
242 		heathrow->pending_events_h &= ~mask;
243 		return bit + 32;
244 	}
245 	/* we should never get here */
246 	return 255;
247 }
248 
249 static void
heathrow_ack_irq(struct pic_ops * pic,int irq)250 heathrow_ack_irq(struct pic_ops *pic, int irq)
251 {
252 }
253 
254 static void
heathrow_establish_irq(struct pic_ops * pic,int irq,int type,int pri)255 heathrow_establish_irq(struct pic_ops *pic, int irq, int type, int pri)
256 {
257 	struct heathrow_ops *heathrow = (struct heathrow_ops *)pic;
258 	uint32_t mask;
259 
260 	KASSERT((irq >= 0) && (irq < 64));
261 
262 	mask = 1 << (irq & 0x1f);
263 	if (irq & 0x20) {
264 		if (type == IST_LEVEL) {
265 
266 			heathrow->level_mask_h |= mask;
267 		} else {
268 
269 			heathrow->level_mask_h &= ~mask;
270 		}
271 	} else {
272 		if (type == IST_LEVEL) {
273 
274 			heathrow->level_mask_l |= mask;
275 		} else {
276 
277 			heathrow->level_mask_l &= ~mask;
278 		}
279 	}
280 	aprint_debug("mask: %08x %08x\n", heathrow->level_mask_h,
281 	    heathrow->level_mask_l);
282 }
283