xref: /netbsd/sys/arch/mac68k/mac68k/psc.c (revision ac1a2037)
1 /*	$NetBSD: psc.c,v 1.11 2019/07/23 15:19:07 rin 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.11 2019/07/23 15:19:07 rin 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 static int	stop_read_psc_dma(int, int, uint32_t *);
55 static int	stop_write_psc_dma(int, int, uint32_t *);
56 
57 void	(*psc3_ihandler)(void *) = psc_lev3_noint;
58 void	*psc3_iarg;
59 
60 int (*psc4_itab[4])(void *) = {
61 	psc_lev4_noint, /* 0 */
62 	psc_lev4_noint, /* 1 */
63 	psc_lev4_noint, /* 2 */
64 	psc_lev4_noint  /* 3 */
65 };
66 
67 void *psc4_iarg[4] = {
68 	(void *)0, (void *)1, (void *)2, (void *)3
69 };
70 
71 void (*psc5_itab[2])(void *) = {
72 	psc_lev5_noint, /* 0 */
73 	psc_lev5_noint  /* 1 */
74 };
75 
76 void *psc5_iarg[2] = {
77 	(void *)0, (void *)1
78 };
79 
80 void (*psc6_itab[3])(void *) = {
81 	psc_lev6_noint, /* 0 */
82 	psc_lev6_noint, /* 1 */
83 	psc_lev6_noint  /* 2 */
84 };
85 
86 void *psc6_iarg[3] = {
87 	(void *)0, (void *)1, (void *)2
88 };
89 
90 /*
91  * Make excessively sure that all PSC DMA is shut down.
92  */
93 void
psc_kill_dma(void)94 psc_kill_dma(void)
95 {
96 	int	i;
97 
98 	for (i = 0; i < 9; i++) {
99 		psc_reg2(PSC_CTLBASE + (i << 4)) = 0x8800;
100 		psc_reg2(PSC_CTLBASE + (i << 4)) = 0x1000;
101 		psc_reg2(PSC_CMDBASE + (i << 5)) = 0x1100;
102 		psc_reg2(PSC_CMDBASE + (i << 5) + PSC_SET1) = 0x1100;
103 	}
104 }
105 
106 /*
107  * Setup the interrupt vectors and disable most of the PSC interrupts
108  */
109 void
psc_init(void)110 psc_init(void)
111 {
112 	int	s, i;
113 
114 	/*
115 	 * Only Quadra AVs have a PSC.
116 	 */
117 	if (current_mac_model->class == MACH_CLASSAV) {
118 		s = splhigh();
119 		psc_kill_dma();
120 		intr_establish(psc_lev3_intr, NULL, 3);
121 		intr_establish(psc_lev4_intr, NULL, 4);
122 		intr_establish(psc_lev5_intr, NULL, 5);
123 		intr_establish(psc_lev6_intr, NULL, 6);
124 		for (i = 3; i < 7; i++) {
125 			/* Clear any flags */
126 			psc_reg1(PSC_ISR_BASE + 0x10 * i) = 0x0F;
127 			/* Clear any interrupt enable */
128 			psc_reg1(PSC_IER_BASE + 0x10 * i) = 0x0F;
129 		}
130 		psc_reg1(PSC_LEV4_IER) = 0x86; /* enable SCC */
131 		splx(s);
132 	}
133 }
134 
135 int
add_psc_lev3_intr(void (* handler)(void *),void * arg)136 add_psc_lev3_intr(void (*handler)(void *), void *arg)
137 {
138 	int s;
139 
140 	s = splhigh();
141 
142 	psc3_ihandler = handler;
143 	psc3_iarg = arg;
144 
145 	splx(s);
146 
147 	return 1;
148 }
149 
150 int
remove_psc_lev3_intr(void)151 remove_psc_lev3_intr(void)
152 {
153 	return add_psc_lev3_intr(psc_lev3_noint, (void *)0);
154 }
155 
156 int
psc_lev3_intr(void * arg)157 psc_lev3_intr(void *arg)
158 {
159 	u_int8_t intbits;
160 
161 	while ((intbits = psc_reg1(PSC_LEV3_ISR)) != psc_reg1(PSC_LEV3_ISR))
162 		;
163 	intbits &= 0x1 & psc_reg1(PSC_LEV3_IER);
164 
165 	if (intbits)
166 		psc3_ihandler(psc3_iarg);
167 
168 	return 0;
169 }
170 
171 static void
psc_lev3_noint(void * arg)172 psc_lev3_noint(void *arg)
173 {
174 	printf("psc_lev3_noint\n");
175 }
176 
177 int
psc_lev4_intr(void * arg)178 psc_lev4_intr(void *arg)
179 {
180 	u_int8_t intbits, bitnum;
181 	u_int mask;
182 
183 	while ((intbits = psc_reg1(PSC_LEV4_ISR)) != psc_reg1(PSC_LEV4_ISR))
184 		;
185 	intbits &= 0xf & psc_reg1(PSC_LEV4_IER);
186 
187 	mask = 1;
188 	bitnum = 0;
189 	do {
190 		if (intbits & mask)
191 			psc4_itab[bitnum](psc4_iarg[bitnum]);
192 		mask <<= 1;
193 	} while (intbits >= mask && ++bitnum);
194 
195 	return 0;
196 }
197 
198 int
add_psc_lev4_intr(int dev,int (* handler)(void *),void * arg)199 add_psc_lev4_intr(int dev, int (*handler)(void *), void *arg)
200 {
201 	int s;
202 
203 	if ((dev < 0) || (dev > 3))
204 		return 0;
205 
206 	s = splhigh();
207 
208 	psc4_itab[dev] = handler;
209 	psc4_iarg[dev] = arg;
210 
211 	splx(s);
212 
213 	return 1;
214 }
215 
216 int
remove_psc_lev4_intr(int dev)217 remove_psc_lev4_intr(int dev)
218 {
219 	return add_psc_lev4_intr(dev, psc_lev4_noint, (void *)dev);
220 }
221 
222 int
psc_lev4_noint(void * arg)223 psc_lev4_noint(void *arg)
224 {
225 	printf("psc_lev4_noint: device %d\n", (int)arg);
226 	return 0;
227 }
228 
229 int
psc_lev5_intr(void * arg)230 psc_lev5_intr(void *arg)
231 {
232 	u_int8_t intbits, bitnum;
233 	u_int mask;
234 
235 	while ((intbits = psc_reg1(PSC_LEV5_ISR)) != psc_reg1(PSC_LEV5_ISR))
236 		;
237 	intbits &= 0x3 & psc_reg1(PSC_LEV5_IER);
238 
239 	mask = 1;
240 	bitnum = 0;
241 	do {
242 		if (intbits & mask)
243 			psc5_itab[bitnum](psc5_iarg[bitnum]);
244 		mask <<= 1;
245 	} while (intbits >= mask && ++bitnum);
246 
247 	return 0;
248 }
249 
250 int
add_psc_lev5_intr(int dev,void (* handler)(void *),void * arg)251 add_psc_lev5_intr(int dev, void (*handler)(void *), void *arg)
252 {
253 	int s;
254 
255 	if ((dev < 0) || (dev > 1))
256 		return 0;
257 
258 	s = splhigh();
259 
260 	psc5_itab[dev] = handler;
261 	psc5_iarg[dev] = arg;
262 
263 	splx(s);
264 
265 	return 1;
266 }
267 
268 int
remove_psc_lev5_intr(int dev)269 remove_psc_lev5_intr(int dev)
270 {
271 	return add_psc_lev5_intr(dev, psc_lev5_noint, (void *)dev);
272 }
273 
274 void
psc_lev5_noint(void * arg)275 psc_lev5_noint(void *arg)
276 {
277 	printf("psc_lev5_noint: device %d\n", (int)arg);
278 }
279 
280 int
psc_lev6_intr(void * arg)281 psc_lev6_intr(void *arg)
282 {
283 	u_int8_t intbits, bitnum;
284 	u_int mask;
285 
286 	while ((intbits = psc_reg1(PSC_LEV6_ISR)) != psc_reg1(PSC_LEV6_ISR))
287 		;
288 	intbits &= 0x7 & psc_reg1(PSC_LEV6_IER);
289 
290 	mask = 1;
291 	bitnum = 0;
292 	do {
293 		if (intbits & mask)
294 			psc6_itab[bitnum](psc6_iarg[bitnum]);
295 		mask <<= 1;
296 	} while (intbits >= mask && ++bitnum);
297 
298 	return 0;
299 }
300 
301 int
add_psc_lev6_intr(int dev,void (* handler)(void *),void * arg)302 add_psc_lev6_intr(int dev, void (*handler)(void *), void *arg)
303 {
304 	int s;
305 
306 	if ((dev < 0) || (dev > 2))
307 		return 0;
308 
309 	s = splhigh();
310 
311 	psc6_itab[dev] = handler;
312 	psc6_iarg[dev] = arg;
313 
314 	splx(s);
315 
316 	return 1;
317 }
318 
319 int
remove_psc_lev6_intr(int dev)320 remove_psc_lev6_intr(int dev)
321 {
322 	return add_psc_lev6_intr(dev, psc_lev6_noint, (void *)dev);
323 }
324 
325 void
psc_lev6_noint(void * arg)326 psc_lev6_noint(void *arg)
327 {
328 	printf("psc_lev6_noint: device %d\n", (int)arg);
329 }
330 
331 /*
332  * DMA Control routines for esp(4).
333  * XXX Need to be merged with DMA engine of mc(4).
334  */
335 
336 int
start_psc_dma(int channel,int * rset,bus_addr_t addr,uint32_t len,int datain)337 start_psc_dma(int channel, int *rset, bus_addr_t addr, uint32_t len, int datain)
338 {
339 	int chan_ctrl, rset_addr, rset_len, rset_cmd, s;
340 
341 	s = splhigh();
342 
343 	chan_ctrl = PSC_CTLBASE + (channel << 4);
344 
345 	pause_psc_dma(channel);
346 
347 	*rset = (psc_reg2(chan_ctrl) & 1) << 4;
348 
349 	rset_addr = PSC_ADDRBASE + (0x20 * channel) + *rset;
350 	rset_len = rset_addr + 4;
351 	rset_cmd = rset_addr + 8;
352 
353 	(void)psc_reg2(rset_cmd);
354 	psc_reg4(rset_len) = len;
355 	psc_reg4(rset_addr) = addr;
356 
357 	if (datain)
358 		psc_reg2(rset_cmd) = 0x8200;
359 	else
360 		psc_reg2(rset_cmd) = 0x200;
361 
362 	psc_reg2(rset_cmd) = 0x100;
363 	psc_reg2(rset_cmd) = 0x8800;
364 	psc_reg2(chan_ctrl) = 0x400;
365 
366 	splx(s);
367 
368 	return 0;
369 }
370 
371 int
pause_psc_dma(int channel)372 pause_psc_dma(int channel)
373 {
374 	int chan_ctrl, s;
375 
376 	s = splhigh();
377 
378 	chan_ctrl = PSC_CTLBASE + (channel << 4);
379 
380 	psc_reg2(chan_ctrl) = 0x8400;
381 
382 	while (!(psc_reg2(chan_ctrl) & 0x4000))
383 		continue;
384 
385 	splx(s);
386 
387 	return 0;
388 }
389 
390 int
wait_psc_dma(int channel,int rset,uint32_t * residual)391 wait_psc_dma(int channel, int rset, uint32_t *residual)
392 {
393 	int rset_addr, rset_len, rset_cmd, s;
394 
395 	s = splhigh();
396 
397 	rset_addr = PSC_ADDRBASE + (0x20 * channel) + rset;
398 	rset_len = rset_addr + 4;
399 	rset_cmd = rset_addr + 8;
400 
401 	while (!(psc_reg2(rset_cmd) & 0x100))
402 		continue;
403 
404 	while (psc_reg2(rset_cmd) & 0x800)
405 		continue;
406 
407 	*residual = psc_reg4(rset_len);
408 
409 	splx(s);
410 
411 	if (*residual)
412 		return -1;
413 	else
414 		return 0;
415 }
416 
417 int
stop_psc_dma(int channel,int rset,uint32_t * residual,int datain)418 stop_psc_dma(int channel, int rset, uint32_t *residual, int datain)
419 {
420 	int rval, s;
421 
422 	s = splhigh();
423 
424 	if (datain)
425 		rval = stop_read_psc_dma(channel, rset, residual);
426 	else
427 		rval = stop_write_psc_dma(channel, rset, residual);
428 
429 	splx(s);
430 
431 	return rval;
432 }
433 
434 static int
stop_read_psc_dma(int channel,int rset,uint32_t * residual)435 stop_read_psc_dma(int channel, int rset, uint32_t *residual)
436 {
437 	int chan_ctrl, rset_addr, rset_len, rset_cmd;
438 
439 	chan_ctrl = PSC_CTLBASE + (channel << 4);
440 	rset_addr = PSC_ADDRBASE + (0x20 * channel) + rset;
441 	rset_len = rset_addr + 4;
442 	rset_cmd = rset_addr + 8;
443 
444 	if (psc_reg2(rset_cmd) & 0x400) {
445 		*residual = 0;
446 		return 0;
447 	}
448 
449 	psc_reg2(chan_ctrl) = 0x8200;
450 
451 	while (psc_reg2(chan_ctrl) & 0x200)
452 		continue;
453 
454 	pause_psc_dma(channel);
455 
456 	*residual = psc_reg4(rset_len);
457 	if (*residual == 0)
458 		return 0;
459 
460 	do {
461 		psc_reg4(rset_len) = 0;
462 	} while (psc_reg4(rset_len));
463 
464 	return 0;
465 }
466 
467 static int
stop_write_psc_dma(int channel,int rset,uint32_t * residual)468 stop_write_psc_dma(int channel, int rset, uint32_t *residual)
469 {
470 	int chan_ctrl, rset_addr, rset_len, rset_cmd;
471 
472 	rset_addr = PSC_ADDRBASE + (0x20 * channel) + rset;
473 	rset_cmd = rset_addr + 8;
474 
475 	if (psc_reg2(rset_cmd) & 0x400) {
476 		*residual = 0;
477 		return 0;
478 	}
479 
480 	chan_ctrl = PSC_CTLBASE + (channel << 4);
481 	rset_len = rset_addr + 4;
482 
483 	pause_psc_dma(channel);
484 
485 	*residual = psc_reg4(rset_len);
486 
487 	psc_reg2(chan_ctrl) = 0x8800;
488 
489 	return 0;
490 }
491