xref: /netbsd-src/sys/arch/mac68k/mac68k/psc.c (revision 0ed3032a3b0d835e8f67ff7182cdda1275e7addb)
1*0ed3032aSrin /*	$NetBSD: psc.c,v 1.11 2019/07/23 15:19:07 rin Exp $	*/
2c1ed70f0Sbriggs 
3e658b8b4Sbriggs /*-
42837bf7eSwiz  * Copyright (c) 1997 David Huang <khym@azeotrope.org>
5e658b8b4Sbriggs  * All rights reserved.
6e658b8b4Sbriggs  *
7e658b8b4Sbriggs  * Redistribution and use in source and binary forms, with or without
8e658b8b4Sbriggs  * modification, are permitted provided that the following conditions
9e658b8b4Sbriggs  * are met:
10e658b8b4Sbriggs  * 1. Redistributions of source code must retain the above copyright
11e658b8b4Sbriggs  *    notice, this list of conditions and the following disclaimer.
12e658b8b4Sbriggs  * 2. The name of the author may not be used to endorse or promote products
13e658b8b4Sbriggs  *    derived from this software without specific prior written permission
14e658b8b4Sbriggs  *
15e658b8b4Sbriggs  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16e658b8b4Sbriggs  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17e658b8b4Sbriggs  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18e658b8b4Sbriggs  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19e658b8b4Sbriggs  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20e658b8b4Sbriggs  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21e658b8b4Sbriggs  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22e658b8b4Sbriggs  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23e658b8b4Sbriggs  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24e658b8b4Sbriggs  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25e658b8b4Sbriggs  *
26e658b8b4Sbriggs  */
27e658b8b4Sbriggs 
28e658b8b4Sbriggs /*
29e658b8b4Sbriggs  * This handles registration/unregistration of PSC (Peripheral
30e658b8b4Sbriggs  * Subsystem Controller) interrupts. The PSC is used only on the
31e658b8b4Sbriggs  * Centris/Quadra 660av and the Quadra 840av.
32e658b8b4Sbriggs  */
33e658b8b4Sbriggs 
344b2744bfSlukem #include <sys/cdefs.h>
35*0ed3032aSrin __KERNEL_RCSID(0, "$NetBSD: psc.c,v 1.11 2019/07/23 15:19:07 rin Exp $");
364b2744bfSlukem 
37e658b8b4Sbriggs #include <sys/param.h>
38e658b8b4Sbriggs #include <sys/systm.h>
39e658b8b4Sbriggs 
40e658b8b4Sbriggs #include <machine/bus.h>
41e658b8b4Sbriggs #include <machine/cpu.h>
42e658b8b4Sbriggs #include <machine/psc.h>
43e658b8b4Sbriggs 
447acd68b1Schs static void	psc_kill_dma(void);
457acd68b1Schs int		psc_lev3_intr(void *);
467acd68b1Schs static void	psc_lev3_noint(void *);
477acd68b1Schs int		psc_lev4_intr(void *);
487acd68b1Schs static int	psc_lev4_noint(void *);
497acd68b1Schs int		psc_lev5_intr(void *);
507acd68b1Schs static void	psc_lev5_noint(void *);
517acd68b1Schs int		psc_lev6_intr(void *);
527acd68b1Schs static void	psc_lev6_noint(void *);
53e658b8b4Sbriggs 
54*0ed3032aSrin static int	stop_read_psc_dma(int, int, uint32_t *);
55*0ed3032aSrin static int	stop_write_psc_dma(int, int, uint32_t *);
56*0ed3032aSrin 
577acd68b1Schs void	(*psc3_ihandler)(void *) = psc_lev3_noint;
58e658b8b4Sbriggs void	*psc3_iarg;
59e658b8b4Sbriggs 
607acd68b1Schs int (*psc4_itab[4])(void *) = {
61e658b8b4Sbriggs 	psc_lev4_noint, /* 0 */
627d09ad09Sscottr 	psc_lev4_noint, /* 1 */
637d09ad09Sscottr 	psc_lev4_noint, /* 2 */
64e658b8b4Sbriggs 	psc_lev4_noint  /* 3 */
65e658b8b4Sbriggs };
66e658b8b4Sbriggs 
67e658b8b4Sbriggs void *psc4_iarg[4] = {
68e658b8b4Sbriggs 	(void *)0, (void *)1, (void *)2, (void *)3
69e658b8b4Sbriggs };
70e658b8b4Sbriggs 
717acd68b1Schs void (*psc5_itab[2])(void *) = {
72e658b8b4Sbriggs 	psc_lev5_noint, /* 0 */
73e658b8b4Sbriggs 	psc_lev5_noint  /* 1 */
74e658b8b4Sbriggs };
75e658b8b4Sbriggs 
76e658b8b4Sbriggs void *psc5_iarg[2] = {
77e658b8b4Sbriggs 	(void *)0, (void *)1
78e658b8b4Sbriggs };
79e658b8b4Sbriggs 
807acd68b1Schs void (*psc6_itab[3])(void *) = {
81e658b8b4Sbriggs 	psc_lev6_noint, /* 0 */
82e658b8b4Sbriggs 	psc_lev6_noint, /* 1 */
83e658b8b4Sbriggs 	psc_lev6_noint  /* 2 */
84e658b8b4Sbriggs };
85e658b8b4Sbriggs 
86e658b8b4Sbriggs void *psc6_iarg[3] = {
87e658b8b4Sbriggs 	(void *)0, (void *)1, (void *)2
88e658b8b4Sbriggs };
89e658b8b4Sbriggs 
90e658b8b4Sbriggs /*
91f9de0720Sbriggs  * Make excessively sure that all PSC DMA is shut down.
92f9de0720Sbriggs  */
93f9de0720Sbriggs void
psc_kill_dma(void)947acd68b1Schs psc_kill_dma(void)
95f9de0720Sbriggs {
96f9de0720Sbriggs 	int	i;
97f9de0720Sbriggs 
98f9de0720Sbriggs 	for (i = 0; i < 9; i++) {
99f9de0720Sbriggs 		psc_reg2(PSC_CTLBASE + (i << 4)) = 0x8800;
100f9de0720Sbriggs 		psc_reg2(PSC_CTLBASE + (i << 4)) = 0x1000;
101f9de0720Sbriggs 		psc_reg2(PSC_CMDBASE + (i << 5)) = 0x1100;
102f9de0720Sbriggs 		psc_reg2(PSC_CMDBASE + (i << 5) + PSC_SET1) = 0x1100;
103f9de0720Sbriggs 	}
104f9de0720Sbriggs }
105f9de0720Sbriggs 
106f9de0720Sbriggs /*
107e658b8b4Sbriggs  * Setup the interrupt vectors and disable most of the PSC interrupts
108e658b8b4Sbriggs  */
109e658b8b4Sbriggs void
psc_init(void)1107acd68b1Schs psc_init(void)
111e658b8b4Sbriggs {
112f9de0720Sbriggs 	int	s, i;
113f9de0720Sbriggs 
114e658b8b4Sbriggs 	/*
1157d09ad09Sscottr 	 * Only Quadra AVs have a PSC.
116e658b8b4Sbriggs 	 */
117e658b8b4Sbriggs 	if (current_mac_model->class == MACH_CLASSAV) {
118f9de0720Sbriggs 		s = splhigh();
119f9de0720Sbriggs 		psc_kill_dma();
1207d09ad09Sscottr 		intr_establish(psc_lev3_intr, NULL, 3);
1217d09ad09Sscottr 		intr_establish(psc_lev4_intr, NULL, 4);
1227d09ad09Sscottr 		intr_establish(psc_lev5_intr, NULL, 5);
1237d09ad09Sscottr 		intr_establish(psc_lev6_intr, NULL, 6);
124f9de0720Sbriggs 		for (i = 3; i < 7; i++) {
125f9de0720Sbriggs 			/* Clear any flags */
126f9de0720Sbriggs 			psc_reg1(PSC_ISR_BASE + 0x10 * i) = 0x0F;
127f9de0720Sbriggs 			/* Clear any interrupt enable */
128f9de0720Sbriggs 			psc_reg1(PSC_IER_BASE + 0x10 * i) = 0x0F;
129f9de0720Sbriggs 		}
130f9de0720Sbriggs 		psc_reg1(PSC_LEV4_IER) = 0x86; /* enable SCC */
131f9de0720Sbriggs 		splx(s);
132e658b8b4Sbriggs 	}
133e658b8b4Sbriggs }
134e658b8b4Sbriggs 
135e658b8b4Sbriggs int
add_psc_lev3_intr(void (* handler)(void *),void * arg)1367acd68b1Schs add_psc_lev3_intr(void (*handler)(void *), void *arg)
137e658b8b4Sbriggs {
138e658b8b4Sbriggs 	int s;
139e658b8b4Sbriggs 
140e658b8b4Sbriggs 	s = splhigh();
141e658b8b4Sbriggs 
142e658b8b4Sbriggs 	psc3_ihandler = handler;
143e658b8b4Sbriggs 	psc3_iarg = arg;
144e658b8b4Sbriggs 
145e658b8b4Sbriggs 	splx(s);
146e658b8b4Sbriggs 
147e658b8b4Sbriggs 	return 1;
148e658b8b4Sbriggs }
149e658b8b4Sbriggs 
150e658b8b4Sbriggs int
remove_psc_lev3_intr(void)1517acd68b1Schs remove_psc_lev3_intr(void)
152e658b8b4Sbriggs {
153e658b8b4Sbriggs 	return add_psc_lev3_intr(psc_lev3_noint, (void *)0);
154e658b8b4Sbriggs }
155e658b8b4Sbriggs 
1567d09ad09Sscottr int
psc_lev3_intr(void * arg)1577acd68b1Schs psc_lev3_intr(void *arg)
158e658b8b4Sbriggs {
159e658b8b4Sbriggs 	u_int8_t intbits;
160e658b8b4Sbriggs 
161e658b8b4Sbriggs 	while ((intbits = psc_reg1(PSC_LEV3_ISR)) != psc_reg1(PSC_LEV3_ISR))
162e658b8b4Sbriggs 		;
163e658b8b4Sbriggs 	intbits &= 0x1 & psc_reg1(PSC_LEV3_IER);
164e658b8b4Sbriggs 
165e658b8b4Sbriggs 	if (intbits)
166e658b8b4Sbriggs 		psc3_ihandler(psc3_iarg);
1677d09ad09Sscottr 
1687d09ad09Sscottr 	return 0;
169e658b8b4Sbriggs }
170e658b8b4Sbriggs 
171e658b8b4Sbriggs static void
psc_lev3_noint(void * arg)1727acd68b1Schs psc_lev3_noint(void *arg)
173e658b8b4Sbriggs {
174e658b8b4Sbriggs 	printf("psc_lev3_noint\n");
175e658b8b4Sbriggs }
176e658b8b4Sbriggs 
177e658b8b4Sbriggs int
psc_lev4_intr(void * arg)1787acd68b1Schs psc_lev4_intr(void *arg)
179e658b8b4Sbriggs {
180e658b8b4Sbriggs 	u_int8_t intbits, bitnum;
181e658b8b4Sbriggs 	u_int mask;
182e658b8b4Sbriggs 
183e658b8b4Sbriggs 	while ((intbits = psc_reg1(PSC_LEV4_ISR)) != psc_reg1(PSC_LEV4_ISR))
184e658b8b4Sbriggs 		;
185e658b8b4Sbriggs 	intbits &= 0xf & psc_reg1(PSC_LEV4_IER);
186e658b8b4Sbriggs 
187e658b8b4Sbriggs 	mask = 1;
188e658b8b4Sbriggs 	bitnum = 0;
189e658b8b4Sbriggs 	do {
190e658b8b4Sbriggs 		if (intbits & mask)
191e658b8b4Sbriggs 			psc4_itab[bitnum](psc4_iarg[bitnum]);
192e658b8b4Sbriggs 		mask <<= 1;
193e658b8b4Sbriggs 	} while (intbits >= mask && ++bitnum);
194e658b8b4Sbriggs 
195e658b8b4Sbriggs 	return 0;
196e658b8b4Sbriggs }
197e658b8b4Sbriggs 
198e658b8b4Sbriggs int
add_psc_lev4_intr(int dev,int (* handler)(void *),void * arg)1997acd68b1Schs add_psc_lev4_intr(int dev, int (*handler)(void *), void *arg)
200e658b8b4Sbriggs {
201e658b8b4Sbriggs 	int s;
202e658b8b4Sbriggs 
203e658b8b4Sbriggs 	if ((dev < 0) || (dev > 3))
204e658b8b4Sbriggs 		return 0;
205e658b8b4Sbriggs 
206e658b8b4Sbriggs 	s = splhigh();
207e658b8b4Sbriggs 
208e658b8b4Sbriggs 	psc4_itab[dev] = handler;
209e658b8b4Sbriggs 	psc4_iarg[dev] = arg;
210e658b8b4Sbriggs 
211e658b8b4Sbriggs 	splx(s);
212e658b8b4Sbriggs 
213e658b8b4Sbriggs 	return 1;
214e658b8b4Sbriggs }
215e658b8b4Sbriggs 
216e658b8b4Sbriggs int
remove_psc_lev4_intr(int dev)2177acd68b1Schs remove_psc_lev4_intr(int dev)
218e658b8b4Sbriggs {
219e658b8b4Sbriggs 	return add_psc_lev4_intr(dev, psc_lev4_noint, (void *)dev);
220e658b8b4Sbriggs }
221e658b8b4Sbriggs 
222e658b8b4Sbriggs int
psc_lev4_noint(void * arg)2237acd68b1Schs psc_lev4_noint(void *arg)
224e658b8b4Sbriggs {
225e658b8b4Sbriggs 	printf("psc_lev4_noint: device %d\n", (int)arg);
226e658b8b4Sbriggs 	return 0;
227e658b8b4Sbriggs }
228e658b8b4Sbriggs 
2297d09ad09Sscottr int
psc_lev5_intr(void * arg)2307acd68b1Schs psc_lev5_intr(void *arg)
231e658b8b4Sbriggs {
232e658b8b4Sbriggs 	u_int8_t intbits, bitnum;
233e658b8b4Sbriggs 	u_int mask;
234e658b8b4Sbriggs 
235e658b8b4Sbriggs 	while ((intbits = psc_reg1(PSC_LEV5_ISR)) != psc_reg1(PSC_LEV5_ISR))
236e658b8b4Sbriggs 		;
237e658b8b4Sbriggs 	intbits &= 0x3 & psc_reg1(PSC_LEV5_IER);
238e658b8b4Sbriggs 
239e658b8b4Sbriggs 	mask = 1;
240e658b8b4Sbriggs 	bitnum = 0;
241e658b8b4Sbriggs 	do {
242e658b8b4Sbriggs 		if (intbits & mask)
243e658b8b4Sbriggs 			psc5_itab[bitnum](psc5_iarg[bitnum]);
244e658b8b4Sbriggs 		mask <<= 1;
245e658b8b4Sbriggs 	} while (intbits >= mask && ++bitnum);
2467d09ad09Sscottr 
2477d09ad09Sscottr 	return 0;
248e658b8b4Sbriggs }
249e658b8b4Sbriggs 
250e658b8b4Sbriggs int
add_psc_lev5_intr(int dev,void (* handler)(void *),void * arg)2517acd68b1Schs add_psc_lev5_intr(int dev, void (*handler)(void *), void *arg)
252e658b8b4Sbriggs {
253e658b8b4Sbriggs 	int s;
254e658b8b4Sbriggs 
255e658b8b4Sbriggs 	if ((dev < 0) || (dev > 1))
256e658b8b4Sbriggs 		return 0;
257e658b8b4Sbriggs 
258e658b8b4Sbriggs 	s = splhigh();
259e658b8b4Sbriggs 
260e658b8b4Sbriggs 	psc5_itab[dev] = handler;
261e658b8b4Sbriggs 	psc5_iarg[dev] = arg;
262e658b8b4Sbriggs 
263e658b8b4Sbriggs 	splx(s);
264e658b8b4Sbriggs 
265e658b8b4Sbriggs 	return 1;
266e658b8b4Sbriggs }
267e658b8b4Sbriggs 
268e658b8b4Sbriggs int
remove_psc_lev5_intr(int dev)2697acd68b1Schs remove_psc_lev5_intr(int dev)
270e658b8b4Sbriggs {
271e658b8b4Sbriggs 	return add_psc_lev5_intr(dev, psc_lev5_noint, (void *)dev);
272e658b8b4Sbriggs }
273e658b8b4Sbriggs 
274e658b8b4Sbriggs void
psc_lev5_noint(void * arg)2757acd68b1Schs psc_lev5_noint(void *arg)
276e658b8b4Sbriggs {
277e658b8b4Sbriggs 	printf("psc_lev5_noint: device %d\n", (int)arg);
278e658b8b4Sbriggs }
279e658b8b4Sbriggs 
2807d09ad09Sscottr int
psc_lev6_intr(void * arg)2817acd68b1Schs psc_lev6_intr(void *arg)
282e658b8b4Sbriggs {
283e658b8b4Sbriggs 	u_int8_t intbits, bitnum;
284e658b8b4Sbriggs 	u_int mask;
285e658b8b4Sbriggs 
286e658b8b4Sbriggs 	while ((intbits = psc_reg1(PSC_LEV6_ISR)) != psc_reg1(PSC_LEV6_ISR))
287e658b8b4Sbriggs 		;
288e658b8b4Sbriggs 	intbits &= 0x7 & psc_reg1(PSC_LEV6_IER);
289e658b8b4Sbriggs 
290e658b8b4Sbriggs 	mask = 1;
291e658b8b4Sbriggs 	bitnum = 0;
292e658b8b4Sbriggs 	do {
293e658b8b4Sbriggs 		if (intbits & mask)
294e658b8b4Sbriggs 			psc6_itab[bitnum](psc6_iarg[bitnum]);
295e658b8b4Sbriggs 		mask <<= 1;
296e658b8b4Sbriggs 	} while (intbits >= mask && ++bitnum);
2977d09ad09Sscottr 
2987d09ad09Sscottr 	return 0;
299e658b8b4Sbriggs }
300e658b8b4Sbriggs 
301e658b8b4Sbriggs int
add_psc_lev6_intr(int dev,void (* handler)(void *),void * arg)3027acd68b1Schs add_psc_lev6_intr(int dev, void (*handler)(void *), void *arg)
303e658b8b4Sbriggs {
304e658b8b4Sbriggs 	int s;
305e658b8b4Sbriggs 
306e658b8b4Sbriggs 	if ((dev < 0) || (dev > 2))
307e658b8b4Sbriggs 		return 0;
308e658b8b4Sbriggs 
309e658b8b4Sbriggs 	s = splhigh();
310e658b8b4Sbriggs 
311e658b8b4Sbriggs 	psc6_itab[dev] = handler;
312e658b8b4Sbriggs 	psc6_iarg[dev] = arg;
313e658b8b4Sbriggs 
314e658b8b4Sbriggs 	splx(s);
315e658b8b4Sbriggs 
316e658b8b4Sbriggs 	return 1;
317e658b8b4Sbriggs }
318e658b8b4Sbriggs 
319e658b8b4Sbriggs int
remove_psc_lev6_intr(int dev)3207acd68b1Schs remove_psc_lev6_intr(int dev)
321e658b8b4Sbriggs {
322e658b8b4Sbriggs 	return add_psc_lev6_intr(dev, psc_lev6_noint, (void *)dev);
323e658b8b4Sbriggs }
324e658b8b4Sbriggs 
325e658b8b4Sbriggs void
psc_lev6_noint(void * arg)3267acd68b1Schs psc_lev6_noint(void *arg)
327e658b8b4Sbriggs {
328e658b8b4Sbriggs 	printf("psc_lev6_noint: device %d\n", (int)arg);
329e658b8b4Sbriggs }
330*0ed3032aSrin 
331*0ed3032aSrin /*
332*0ed3032aSrin  * DMA Control routines for esp(4).
333*0ed3032aSrin  * XXX Need to be merged with DMA engine of mc(4).
334*0ed3032aSrin  */
335*0ed3032aSrin 
336*0ed3032aSrin int
start_psc_dma(int channel,int * rset,bus_addr_t addr,uint32_t len,int datain)337*0ed3032aSrin start_psc_dma(int channel, int *rset, bus_addr_t addr, uint32_t len, int datain)
338*0ed3032aSrin {
339*0ed3032aSrin 	int chan_ctrl, rset_addr, rset_len, rset_cmd, s;
340*0ed3032aSrin 
341*0ed3032aSrin 	s = splhigh();
342*0ed3032aSrin 
343*0ed3032aSrin 	chan_ctrl = PSC_CTLBASE + (channel << 4);
344*0ed3032aSrin 
345*0ed3032aSrin 	pause_psc_dma(channel);
346*0ed3032aSrin 
347*0ed3032aSrin 	*rset = (psc_reg2(chan_ctrl) & 1) << 4;
348*0ed3032aSrin 
349*0ed3032aSrin 	rset_addr = PSC_ADDRBASE + (0x20 * channel) + *rset;
350*0ed3032aSrin 	rset_len = rset_addr + 4;
351*0ed3032aSrin 	rset_cmd = rset_addr + 8;
352*0ed3032aSrin 
353*0ed3032aSrin 	(void)psc_reg2(rset_cmd);
354*0ed3032aSrin 	psc_reg4(rset_len) = len;
355*0ed3032aSrin 	psc_reg4(rset_addr) = addr;
356*0ed3032aSrin 
357*0ed3032aSrin 	if (datain)
358*0ed3032aSrin 		psc_reg2(rset_cmd) = 0x8200;
359*0ed3032aSrin 	else
360*0ed3032aSrin 		psc_reg2(rset_cmd) = 0x200;
361*0ed3032aSrin 
362*0ed3032aSrin 	psc_reg2(rset_cmd) = 0x100;
363*0ed3032aSrin 	psc_reg2(rset_cmd) = 0x8800;
364*0ed3032aSrin 	psc_reg2(chan_ctrl) = 0x400;
365*0ed3032aSrin 
366*0ed3032aSrin 	splx(s);
367*0ed3032aSrin 
368*0ed3032aSrin 	return 0;
369*0ed3032aSrin }
370*0ed3032aSrin 
371*0ed3032aSrin int
pause_psc_dma(int channel)372*0ed3032aSrin pause_psc_dma(int channel)
373*0ed3032aSrin {
374*0ed3032aSrin 	int chan_ctrl, s;
375*0ed3032aSrin 
376*0ed3032aSrin 	s = splhigh();
377*0ed3032aSrin 
378*0ed3032aSrin 	chan_ctrl = PSC_CTLBASE + (channel << 4);
379*0ed3032aSrin 
380*0ed3032aSrin 	psc_reg2(chan_ctrl) = 0x8400;
381*0ed3032aSrin 
382*0ed3032aSrin 	while (!(psc_reg2(chan_ctrl) & 0x4000))
383*0ed3032aSrin 		continue;
384*0ed3032aSrin 
385*0ed3032aSrin 	splx(s);
386*0ed3032aSrin 
387*0ed3032aSrin 	return 0;
388*0ed3032aSrin }
389*0ed3032aSrin 
390*0ed3032aSrin int
wait_psc_dma(int channel,int rset,uint32_t * residual)391*0ed3032aSrin wait_psc_dma(int channel, int rset, uint32_t *residual)
392*0ed3032aSrin {
393*0ed3032aSrin 	int rset_addr, rset_len, rset_cmd, s;
394*0ed3032aSrin 
395*0ed3032aSrin 	s = splhigh();
396*0ed3032aSrin 
397*0ed3032aSrin 	rset_addr = PSC_ADDRBASE + (0x20 * channel) + rset;
398*0ed3032aSrin 	rset_len = rset_addr + 4;
399*0ed3032aSrin 	rset_cmd = rset_addr + 8;
400*0ed3032aSrin 
401*0ed3032aSrin 	while (!(psc_reg2(rset_cmd) & 0x100))
402*0ed3032aSrin 		continue;
403*0ed3032aSrin 
404*0ed3032aSrin 	while (psc_reg2(rset_cmd) & 0x800)
405*0ed3032aSrin 		continue;
406*0ed3032aSrin 
407*0ed3032aSrin 	*residual = psc_reg4(rset_len);
408*0ed3032aSrin 
409*0ed3032aSrin 	splx(s);
410*0ed3032aSrin 
411*0ed3032aSrin 	if (*residual)
412*0ed3032aSrin 		return -1;
413*0ed3032aSrin 	else
414*0ed3032aSrin 		return 0;
415*0ed3032aSrin }
416*0ed3032aSrin 
417*0ed3032aSrin int
stop_psc_dma(int channel,int rset,uint32_t * residual,int datain)418*0ed3032aSrin stop_psc_dma(int channel, int rset, uint32_t *residual, int datain)
419*0ed3032aSrin {
420*0ed3032aSrin 	int rval, s;
421*0ed3032aSrin 
422*0ed3032aSrin 	s = splhigh();
423*0ed3032aSrin 
424*0ed3032aSrin 	if (datain)
425*0ed3032aSrin 		rval = stop_read_psc_dma(channel, rset, residual);
426*0ed3032aSrin 	else
427*0ed3032aSrin 		rval = stop_write_psc_dma(channel, rset, residual);
428*0ed3032aSrin 
429*0ed3032aSrin 	splx(s);
430*0ed3032aSrin 
431*0ed3032aSrin 	return rval;
432*0ed3032aSrin }
433*0ed3032aSrin 
434*0ed3032aSrin static int
stop_read_psc_dma(int channel,int rset,uint32_t * residual)435*0ed3032aSrin stop_read_psc_dma(int channel, int rset, uint32_t *residual)
436*0ed3032aSrin {
437*0ed3032aSrin 	int chan_ctrl, rset_addr, rset_len, rset_cmd;
438*0ed3032aSrin 
439*0ed3032aSrin 	chan_ctrl = PSC_CTLBASE + (channel << 4);
440*0ed3032aSrin 	rset_addr = PSC_ADDRBASE + (0x20 * channel) + rset;
441*0ed3032aSrin 	rset_len = rset_addr + 4;
442*0ed3032aSrin 	rset_cmd = rset_addr + 8;
443*0ed3032aSrin 
444*0ed3032aSrin 	if (psc_reg2(rset_cmd) & 0x400) {
445*0ed3032aSrin 		*residual = 0;
446*0ed3032aSrin 		return 0;
447*0ed3032aSrin 	}
448*0ed3032aSrin 
449*0ed3032aSrin 	psc_reg2(chan_ctrl) = 0x8200;
450*0ed3032aSrin 
451*0ed3032aSrin 	while (psc_reg2(chan_ctrl) & 0x200)
452*0ed3032aSrin 		continue;
453*0ed3032aSrin 
454*0ed3032aSrin 	pause_psc_dma(channel);
455*0ed3032aSrin 
456*0ed3032aSrin 	*residual = psc_reg4(rset_len);
457*0ed3032aSrin 	if (*residual == 0)
458*0ed3032aSrin 		return 0;
459*0ed3032aSrin 
460*0ed3032aSrin 	do {
461*0ed3032aSrin 		psc_reg4(rset_len) = 0;
462*0ed3032aSrin 	} while (psc_reg4(rset_len));
463*0ed3032aSrin 
464*0ed3032aSrin 	return 0;
465*0ed3032aSrin }
466*0ed3032aSrin 
467*0ed3032aSrin static int
stop_write_psc_dma(int channel,int rset,uint32_t * residual)468*0ed3032aSrin stop_write_psc_dma(int channel, int rset, uint32_t *residual)
469*0ed3032aSrin {
470*0ed3032aSrin 	int chan_ctrl, rset_addr, rset_len, rset_cmd;
471*0ed3032aSrin 
472*0ed3032aSrin 	rset_addr = PSC_ADDRBASE + (0x20 * channel) + rset;
473*0ed3032aSrin 	rset_cmd = rset_addr + 8;
474*0ed3032aSrin 
475*0ed3032aSrin 	if (psc_reg2(rset_cmd) & 0x400) {
476*0ed3032aSrin 		*residual = 0;
477*0ed3032aSrin 		return 0;
478*0ed3032aSrin 	}
479*0ed3032aSrin 
480*0ed3032aSrin 	chan_ctrl = PSC_CTLBASE + (channel << 4);
481*0ed3032aSrin 	rset_len = rset_addr + 4;
482*0ed3032aSrin 
483*0ed3032aSrin 	pause_psc_dma(channel);
484*0ed3032aSrin 
485*0ed3032aSrin 	*residual = psc_reg4(rset_len);
486*0ed3032aSrin 
487*0ed3032aSrin 	psc_reg2(chan_ctrl) = 0x8800;
488*0ed3032aSrin 
489*0ed3032aSrin 	return 0;
490*0ed3032aSrin }
491