xref: /netbsd-src/sys/arch/amiga/dev/ahsc.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*	$NetBSD: ahsc.c,v 1.16 1996/10/13 03:06:46 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Christian E. Hopps
5  * Copyright (c) 1982, 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)dma.c
37  */
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <scsi/scsi_all.h>
43 #include <scsi/scsiconf.h>
44 #include <amiga/amiga/custom.h>
45 #include <amiga/amiga/cc.h>
46 #include <amiga/amiga/device.h>
47 #include <amiga/amiga/isr.h>
48 #include <amiga/dev/dmavar.h>
49 #include <amiga/dev/sbicreg.h>
50 #include <amiga/dev/sbicvar.h>
51 #include <amiga/dev/ahscreg.h>
52 #include <amiga/dev/zbusvar.h>
53 
54 void ahscattach __P((struct device *, struct device *, void *));
55 int ahscmatch __P((struct device *, void *, void *));
56 
57 void ahsc_enintr __P((struct sbic_softc *));
58 void ahsc_dmastop __P((struct sbic_softc *));
59 int ahsc_dmanext __P((struct sbic_softc *));
60 int ahsc_dmaintr __P((void *));
61 int ahsc_dmago __P((struct sbic_softc *, char *, int, int));
62 
63 #ifdef DEBUG
64 void ahsc_dump __P((void));
65 #endif
66 
67 struct scsi_adapter ahsc_scsiswitch = {
68 	sbic_scsicmd,
69 	sbic_minphys,
70 	0,			/* no lun support */
71 	0,			/* no lun support */
72 };
73 
74 struct scsi_device ahsc_scsidev = {
75 	NULL,		/* use default error handler */
76 	NULL,		/* do not have a start functio */
77 	NULL,		/* have no async handler */
78 	NULL,		/* Use default done routine */
79 };
80 
81 
82 #ifdef DEBUG
83 int	ahsc_dmadebug = 0;
84 #endif
85 
86 struct cfattach ahsc_ca = {
87 	sizeof(struct sbic_softc), ahscmatch, ahscattach
88 };
89 
90 struct cfdriver ahsc_cd = {
91 	NULL, "ahsc", DV_DULL, NULL, 0
92 };
93 
94 /*
95  * if we are an A3000 we are here.
96  */
97 int
98 ahscmatch(pdp, match, auxp)
99 	struct device *pdp;
100 	void *match, *auxp;
101 {
102 	char *mbusstr;
103 
104 	mbusstr = auxp;
105 	if (is_a3000() && matchname(auxp, "ahsc"))
106 		return(1);
107 	return(0);
108 }
109 
110 void
111 ahscattach(pdp, dp, auxp)
112 	struct device *pdp, *dp;
113 	void *auxp;
114 {
115 	volatile struct sdmac *rp;
116 	struct sbic_softc *sc;
117 
118 	printf("\n");
119 
120 	sc = (struct sbic_softc *)dp;
121 	sc->sc_cregs = rp = ztwomap(0xdd0000);
122 	/*
123 	 * disable ints and reset bank register
124 	 */
125 	rp->CNTR = CNTR_PDMD;
126 	rp->DAWR = DAWR_AHSC;
127 	sc->sc_enintr = ahsc_enintr;
128 	sc->sc_dmago = ahsc_dmago;
129 	sc->sc_dmanext = ahsc_dmanext;
130 	sc->sc_dmastop = ahsc_dmastop;
131 	sc->sc_dmacmd = 0;
132 
133 	/*
134 	 * eveything is a valid dma address
135 	 */
136 	sc->sc_dmamask = 0;
137 	sc->sc_sbicp = (sbic_regmap_p) ((int)rp + 0x41);
138 	sc->sc_clkfreq = sbic_clock_override ? sbic_clock_override : 143;
139 
140 	sc->sc_link.channel = SCSI_CHANNEL_ONLY_ONE;
141 	sc->sc_link.adapter_softc = sc;
142 	sc->sc_link.adapter_target = 7;
143 	sc->sc_link.adapter = &ahsc_scsiswitch;
144 	sc->sc_link.device = &ahsc_scsidev;
145 	sc->sc_link.openings = 2;
146 
147 	sbicinit(sc);
148 
149 	sc->sc_isr.isr_intr = ahsc_dmaintr;
150 	sc->sc_isr.isr_arg = sc;
151 	sc->sc_isr.isr_ipl = 2;
152 	add_isr (&sc->sc_isr);
153 
154 	/*
155 	 * attach all scsi units on us
156 	 */
157 	config_found(dp, &sc->sc_link, scsiprint);
158 }
159 
160 void
161 ahsc_enintr(dev)
162 	struct sbic_softc *dev;
163 {
164 	volatile struct sdmac *sdp;
165 
166 	sdp = dev->sc_cregs;
167 
168 	dev->sc_flags |= SBICF_INTR;
169 	sdp->CNTR = CNTR_PDMD | CNTR_INTEN;
170 }
171 
172 int
173 ahsc_dmago(dev, addr, count, flags)
174 	struct sbic_softc *dev;
175 	char *addr;
176 	int count, flags;
177 {
178 	volatile struct sdmac *sdp;
179 
180 	sdp = dev->sc_cregs;
181 	/*
182 	 * Set up the command word based on flags
183 	 */
184 	dev->sc_dmacmd = CNTR_PDMD | CNTR_INTEN;
185 	if ((flags & DMAGO_READ) == 0)
186 		dev->sc_dmacmd |= CNTR_DDIR;
187 #ifdef DEBUG
188 	if (ahsc_dmadebug & DDB_IO)
189 		printf("ahsc_dmago: cmd %x\n", dev->sc_dmacmd);
190 #endif
191 
192 	dev->sc_flags |= SBICF_INTR;
193 	sdp->CNTR = dev->sc_dmacmd;
194 	sdp->ACR = (u_int) dev->sc_cur->dc_addr;
195 	sdp->ST_DMA = 1;
196 
197 	return(dev->sc_tcnt);
198 }
199 
200 void
201 ahsc_dmastop(dev)
202 	struct sbic_softc *dev;
203 {
204 	volatile struct sdmac *sdp;
205 	int s;
206 
207 	sdp = dev->sc_cregs;
208 
209 #ifdef DEBUG
210 	if (ahsc_dmadebug & DDB_FOLLOW)
211 		printf("ahsc_dmastop()\n");
212 #endif
213 	if (dev->sc_dmacmd) {
214 		s = splbio();
215 		if ((dev->sc_dmacmd & (CNTR_TCEN | CNTR_DDIR)) == 0) {
216 			/*
217 			 * only FLUSH if terminal count not enabled,
218 			 * and reading from peripheral
219 			 */
220 			sdp->FLUSH = 1;
221 			while ((sdp->ISTR & ISTR_FE_FLG) == 0)
222 				;
223 		}
224 		/*
225 		 * clear possible interrupt and stop dma
226 		 */
227 		sdp->CINT = 1;
228 		sdp->SP_DMA = 1;
229 		dev->sc_dmacmd = 0;
230 		splx(s);
231 	}
232 }
233 
234 int
235 ahsc_dmaintr(arg)
236 	void *arg;
237 {
238 	struct sbic_softc *dev = arg;
239 	volatile struct sdmac *sdp;
240 	int stat, found;
241 
242 	sdp = dev->sc_cregs;
243 	stat = sdp->ISTR;
244 
245 	if ((stat & (ISTR_INT_F|ISTR_INT_P)) == 0)
246 		return (0);
247 
248 #ifdef DEBUG
249 	if (ahsc_dmadebug & DDB_FOLLOW)
250 		printf("%s: dmaintr 0x%x\n", dev->sc_dev.dv_xname, stat);
251 #endif
252 
253 	/*
254 	 * both, SCSI and DMA interrupts arrive here. I chose
255 	 * arbitrarily that DMA interrupts should have higher
256 	 * precedence than SCSI interrupts.
257 	 */
258 	found = 0;
259 	if (stat & ISTR_E_INT) {
260 		++found;
261 
262 		sdp->CINT = 1;	/* clear possible interrupt */
263 
264 		/*
265 		 * check for SCSI ints in the same go and
266 		 * eventually save an interrupt
267 		 */
268 	}
269 
270 	if (dev->sc_flags & SBICF_INTR && stat & ISTR_INTS)
271 		found += sbicintr(dev);
272 	return(found);
273 }
274 
275 
276 int
277 ahsc_dmanext(dev)
278 	struct sbic_softc *dev;
279 {
280 	volatile struct sdmac *sdp;
281 
282 	sdp = dev->sc_cregs;
283 
284 	if (dev->sc_cur > dev->sc_last) {
285 		/* shouldn't happen !! */
286 		printf("ahsc_dmanext at end !!!\n");
287 		ahsc_dmastop(dev);
288 		return(0);
289 	}
290 	if ((dev->sc_dmacmd & (CNTR_TCEN | CNTR_DDIR)) == 0) {
291 		  /*
292 		   * only FLUSH if terminal count not enabled,
293 		   * and reading from peripheral
294 		   */
295 		sdp->FLUSH = 1;
296 		while ((sdp->ISTR & ISTR_FE_FLG) == 0)
297 			;
298         }
299 	/*
300 	 * clear possible interrupt and stop dma
301 	 */
302 	sdp->CINT = 1;	/* clear possible interrupt */
303 	sdp->SP_DMA = 1;	/* stop dma */
304 	sdp->CNTR = dev->sc_dmacmd;
305 	sdp->ACR = (u_int)dev->sc_cur->dc_addr;
306 	sdp->ST_DMA = 1;
307 
308 	dev->sc_tcnt = dev->sc_cur->dc_count << 1;
309 	return(dev->sc_tcnt);
310 }
311 
312 #ifdef DEBUG
313 void
314 ahsc_dump()
315 {
316 	int i;
317 
318 	for (i = 0; i < ahsc_cd.cd_ndevs; ++i)
319 		if (ahsc_cd.cd_devs[i])
320 			sbic_dump(ahsc_cd.cd_devs[i]);
321 }
322 #endif
323