xref: /netbsd/sys/arch/mac68k/mac68k/psc.c (revision 6550d01e)
1 /*	$NetBSD: psc.c,v 1.10 2005/12/11 12:18:03 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 1997 David Huang <khym@azeotrope.org>
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. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 /*
29  * This handles registration/unregistration of PSC (Peripheral
30  * Subsystem Controller) interrupts. The PSC is used only on the
31  * Centris/Quadra 660av and the Quadra 840av.
32  */
33 
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: psc.c,v 1.10 2005/12/11 12:18:03 christos Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 
40 #include <machine/bus.h>
41 #include <machine/cpu.h>
42 #include <machine/psc.h>
43 
44 static void	psc_kill_dma(void);
45 int		psc_lev3_intr(void *);
46 static void	psc_lev3_noint(void *);
47 int		psc_lev4_intr(void *);
48 static int	psc_lev4_noint(void *);
49 int		psc_lev5_intr(void *);
50 static void	psc_lev5_noint(void *);
51 int		psc_lev6_intr(void *);
52 static void	psc_lev6_noint(void *);
53 
54 void	(*psc3_ihandler)(void *) = psc_lev3_noint;
55 void	*psc3_iarg;
56 
57 int (*psc4_itab[4])(void *) = {
58 	psc_lev4_noint, /* 0 */
59 	psc_lev4_noint, /* 1 */
60 	psc_lev4_noint, /* 2 */
61 	psc_lev4_noint  /* 3 */
62 };
63 
64 void *psc4_iarg[4] = {
65 	(void *)0, (void *)1, (void *)2, (void *)3
66 };
67 
68 void (*psc5_itab[2])(void *) = {
69 	psc_lev5_noint, /* 0 */
70 	psc_lev5_noint  /* 1 */
71 };
72 
73 void *psc5_iarg[2] = {
74 	(void *)0, (void *)1
75 };
76 
77 void (*psc6_itab[3])(void *) = {
78 	psc_lev6_noint, /* 0 */
79 	psc_lev6_noint, /* 1 */
80 	psc_lev6_noint  /* 2 */
81 };
82 
83 void *psc6_iarg[3] = {
84 	(void *)0, (void *)1, (void *)2
85 };
86 
87 /*
88  * Make excessively sure that all PSC DMA is shut down.
89  */
90 void
91 psc_kill_dma(void)
92 {
93 	int	i;
94 
95 	for (i = 0; i < 9; i++) {
96 		psc_reg2(PSC_CTLBASE + (i << 4)) = 0x8800;
97 		psc_reg2(PSC_CTLBASE + (i << 4)) = 0x1000;
98 		psc_reg2(PSC_CMDBASE + (i << 5)) = 0x1100;
99 		psc_reg2(PSC_CMDBASE + (i << 5) + PSC_SET1) = 0x1100;
100 	}
101 }
102 
103 /*
104  * Setup the interrupt vectors and disable most of the PSC interrupts
105  */
106 void
107 psc_init(void)
108 {
109 	int	s, i;
110 
111 	/*
112 	 * Only Quadra AVs have a PSC.
113 	 */
114 	if (current_mac_model->class == MACH_CLASSAV) {
115 		s = splhigh();
116 		psc_kill_dma();
117 		intr_establish(psc_lev3_intr, NULL, 3);
118 		intr_establish(psc_lev4_intr, NULL, 4);
119 		intr_establish(psc_lev5_intr, NULL, 5);
120 		intr_establish(psc_lev6_intr, NULL, 6);
121 		for (i = 3; i < 7; i++) {
122 			/* Clear any flags */
123 			psc_reg1(PSC_ISR_BASE + 0x10 * i) = 0x0F;
124 			/* Clear any interrupt enable */
125 			psc_reg1(PSC_IER_BASE + 0x10 * i) = 0x0F;
126 		}
127 		psc_reg1(PSC_LEV4_IER) = 0x86; /* enable SCC */
128 		splx(s);
129 	}
130 }
131 
132 int
133 add_psc_lev3_intr(void (*handler)(void *), void *arg)
134 {
135 	int s;
136 
137 	s = splhigh();
138 
139 	psc3_ihandler = handler;
140 	psc3_iarg = arg;
141 
142 	splx(s);
143 
144 	return 1;
145 }
146 
147 int
148 remove_psc_lev3_intr(void)
149 {
150 	return add_psc_lev3_intr(psc_lev3_noint, (void *)0);
151 }
152 
153 int
154 psc_lev3_intr(void *arg)
155 {
156 	u_int8_t intbits;
157 
158 	while ((intbits = psc_reg1(PSC_LEV3_ISR)) != psc_reg1(PSC_LEV3_ISR))
159 		;
160 	intbits &= 0x1 & psc_reg1(PSC_LEV3_IER);
161 
162 	if (intbits)
163 		psc3_ihandler(psc3_iarg);
164 
165 	return 0;
166 }
167 
168 static void
169 psc_lev3_noint(void *arg)
170 {
171 	printf("psc_lev3_noint\n");
172 }
173 
174 int
175 psc_lev4_intr(void *arg)
176 {
177 	u_int8_t intbits, bitnum;
178 	u_int mask;
179 
180 	while ((intbits = psc_reg1(PSC_LEV4_ISR)) != psc_reg1(PSC_LEV4_ISR))
181 		;
182 	intbits &= 0xf & psc_reg1(PSC_LEV4_IER);
183 
184 	mask = 1;
185 	bitnum = 0;
186 	do {
187 		if (intbits & mask)
188 			psc4_itab[bitnum](psc4_iarg[bitnum]);
189 		mask <<= 1;
190 	} while (intbits >= mask && ++bitnum);
191 
192 	return 0;
193 }
194 
195 int
196 add_psc_lev4_intr(int dev, int (*handler)(void *), void *arg)
197 {
198 	int s;
199 
200 	if ((dev < 0) || (dev > 3))
201 		return 0;
202 
203 	s = splhigh();
204 
205 	psc4_itab[dev] = handler;
206 	psc4_iarg[dev] = arg;
207 
208 	splx(s);
209 
210 	return 1;
211 }
212 
213 int
214 remove_psc_lev4_intr(int dev)
215 {
216 	return add_psc_lev4_intr(dev, psc_lev4_noint, (void *)dev);
217 }
218 
219 int
220 psc_lev4_noint(void *arg)
221 {
222 	printf("psc_lev4_noint: device %d\n", (int)arg);
223 	return 0;
224 }
225 
226 int
227 psc_lev5_intr(void *arg)
228 {
229 	u_int8_t intbits, bitnum;
230 	u_int mask;
231 
232 	while ((intbits = psc_reg1(PSC_LEV5_ISR)) != psc_reg1(PSC_LEV5_ISR))
233 		;
234 	intbits &= 0x3 & psc_reg1(PSC_LEV5_IER);
235 
236 	mask = 1;
237 	bitnum = 0;
238 	do {
239 		if (intbits & mask)
240 			psc5_itab[bitnum](psc5_iarg[bitnum]);
241 		mask <<= 1;
242 	} while (intbits >= mask && ++bitnum);
243 
244 	return 0;
245 }
246 
247 int
248 add_psc_lev5_intr(int dev, void (*handler)(void *), void *arg)
249 {
250 	int s;
251 
252 	if ((dev < 0) || (dev > 1))
253 		return 0;
254 
255 	s = splhigh();
256 
257 	psc5_itab[dev] = handler;
258 	psc5_iarg[dev] = arg;
259 
260 	splx(s);
261 
262 	return 1;
263 }
264 
265 int
266 remove_psc_lev5_intr(int dev)
267 {
268 	return add_psc_lev5_intr(dev, psc_lev5_noint, (void *)dev);
269 }
270 
271 void
272 psc_lev5_noint(void *arg)
273 {
274 	printf("psc_lev5_noint: device %d\n", (int)arg);
275 }
276 
277 int
278 psc_lev6_intr(void *arg)
279 {
280 	u_int8_t intbits, bitnum;
281 	u_int mask;
282 
283 	while ((intbits = psc_reg1(PSC_LEV6_ISR)) != psc_reg1(PSC_LEV6_ISR))
284 		;
285 	intbits &= 0x7 & psc_reg1(PSC_LEV6_IER);
286 
287 	mask = 1;
288 	bitnum = 0;
289 	do {
290 		if (intbits & mask)
291 			psc6_itab[bitnum](psc6_iarg[bitnum]);
292 		mask <<= 1;
293 	} while (intbits >= mask && ++bitnum);
294 
295 	return 0;
296 }
297 
298 int
299 add_psc_lev6_intr(int dev, void (*handler)(void *), void *arg)
300 {
301 	int s;
302 
303 	if ((dev < 0) || (dev > 2))
304 		return 0;
305 
306 	s = splhigh();
307 
308 	psc6_itab[dev] = handler;
309 	psc6_iarg[dev] = arg;
310 
311 	splx(s);
312 
313 	return 1;
314 }
315 
316 int
317 remove_psc_lev6_intr(int dev)
318 {
319 	return add_psc_lev6_intr(dev, psc_lev6_noint, (void *)dev);
320 }
321 
322 void
323 psc_lev6_noint(void *arg)
324 {
325 	printf("psc_lev6_noint: device %d\n", (int)arg);
326 }
327