xref: /netbsd-src/sys/arch/amiga/dev/ahsc.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*	$NetBSD: ahsc.c,v 1.19 1997/08/27 11:23:03 bouyer 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 <dev/scsipi/scsi_all.h>
43 #include <dev/scsipi/scsipi_all.h>
44 #include <dev/scsipi/scsiconf.h>
45 #include <amiga/amiga/custom.h>
46 #include <amiga/amiga/cc.h>
47 #include <amiga/amiga/device.h>
48 #include <amiga/amiga/isr.h>
49 #include <amiga/dev/dmavar.h>
50 #include <amiga/dev/sbicreg.h>
51 #include <amiga/dev/sbicvar.h>
52 #include <amiga/dev/ahscreg.h>
53 #include <amiga/dev/zbusvar.h>
54 
55 void ahscattach __P((struct device *, struct device *, void *));
56 int ahscmatch __P((struct device *, struct cfdata *, void *));
57 
58 void ahsc_enintr __P((struct sbic_softc *));
59 void ahsc_dmastop __P((struct sbic_softc *));
60 int ahsc_dmanext __P((struct sbic_softc *));
61 int ahsc_dmaintr __P((void *));
62 int ahsc_dmago __P((struct sbic_softc *, char *, int, int));
63 
64 #ifdef DEBUG
65 void ahsc_dump __P((void));
66 #endif
67 
68 struct scsipi_adapter ahsc_scsiswitch = {
69 	sbic_scsicmd,
70 	sbic_minphys,
71 	0,			/* no lun support */
72 	0,			/* no lun support */
73 };
74 
75 struct scsipi_device ahsc_scsidev = {
76 	NULL,		/* use default error handler */
77 	NULL,		/* do not have a start functio */
78 	NULL,		/* have no async handler */
79 	NULL,		/* Use default done routine */
80 };
81 
82 
83 #ifdef DEBUG
84 int	ahsc_dmadebug = 0;
85 #endif
86 
87 struct cfattach ahsc_ca = {
88 	sizeof(struct sbic_softc), ahscmatch, ahscattach
89 };
90 
91 struct cfdriver ahsc_cd = {
92 	NULL, "ahsc", DV_DULL, NULL, 0
93 };
94 
95 /*
96  * if we are an A3000 we are here.
97  */
98 int
99 ahscmatch(pdp, cfp, auxp)
100 	struct device *pdp;
101 	struct cfdata *cfp;
102 	void *auxp;
103 {
104 	char *mbusstr;
105 
106 	mbusstr = auxp;
107 	if (is_a3000() && matchname(auxp, "ahsc"))
108 		return(1);
109 	return(0);
110 }
111 
112 void
113 ahscattach(pdp, dp, auxp)
114 	struct device *pdp, *dp;
115 	void *auxp;
116 {
117 	volatile struct sdmac *rp;
118 	struct sbic_softc *sc;
119 
120 	printf("\n");
121 
122 	sc = (struct sbic_softc *)dp;
123 	sc->sc_cregs = rp = ztwomap(0xdd0000);
124 	/*
125 	 * disable ints and reset bank register
126 	 */
127 	rp->CNTR = CNTR_PDMD;
128 	rp->DAWR = DAWR_AHSC;
129 	sc->sc_enintr = ahsc_enintr;
130 	sc->sc_dmago = ahsc_dmago;
131 	sc->sc_dmanext = ahsc_dmanext;
132 	sc->sc_dmastop = ahsc_dmastop;
133 	sc->sc_dmacmd = 0;
134 
135 	/*
136 	 * eveything is a valid dma address
137 	 */
138 	sc->sc_dmamask = 0;
139 	sc->sc_sbicp = (sbic_regmap_p) ((int)rp + 0x41);
140 	sc->sc_clkfreq = sbic_clock_override ? sbic_clock_override : 143;
141 
142 	sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
143 	sc->sc_link.adapter_softc = sc;
144 	sc->sc_link.scsipi_scsi.adapter_target = 7;
145 	sc->sc_link.adapter = &ahsc_scsiswitch;
146 	sc->sc_link.device = &ahsc_scsidev;
147 	sc->sc_link.openings = 2;
148 	sc->sc_link.scsipi_scsi.max_target = 7;
149 	sc->sc_link.type = BUS_SCSI;
150 
151 	sbicinit(sc);
152 
153 	sc->sc_isr.isr_intr = ahsc_dmaintr;
154 	sc->sc_isr.isr_arg = sc;
155 	sc->sc_isr.isr_ipl = 2;
156 	add_isr (&sc->sc_isr);
157 
158 	/*
159 	 * attach all scsi units on us
160 	 */
161 	config_found(dp, &sc->sc_link, scsiprint);
162 }
163 
164 void
165 ahsc_enintr(dev)
166 	struct sbic_softc *dev;
167 {
168 	volatile struct sdmac *sdp;
169 
170 	sdp = dev->sc_cregs;
171 
172 	dev->sc_flags |= SBICF_INTR;
173 	sdp->CNTR = CNTR_PDMD | CNTR_INTEN;
174 }
175 
176 int
177 ahsc_dmago(dev, addr, count, flags)
178 	struct sbic_softc *dev;
179 	char *addr;
180 	int count, flags;
181 {
182 	volatile struct sdmac *sdp;
183 
184 	sdp = dev->sc_cregs;
185 	/*
186 	 * Set up the command word based on flags
187 	 */
188 	dev->sc_dmacmd = CNTR_PDMD | CNTR_INTEN;
189 	if ((flags & DMAGO_READ) == 0)
190 		dev->sc_dmacmd |= CNTR_DDIR;
191 #ifdef DEBUG
192 	if (ahsc_dmadebug & DDB_IO)
193 		printf("ahsc_dmago: cmd %x\n", dev->sc_dmacmd);
194 #endif
195 
196 	dev->sc_flags |= SBICF_INTR;
197 	sdp->CNTR = dev->sc_dmacmd;
198 	sdp->ACR = (u_int) dev->sc_cur->dc_addr;
199 	sdp->ST_DMA = 1;
200 
201 	return(dev->sc_tcnt);
202 }
203 
204 void
205 ahsc_dmastop(dev)
206 	struct sbic_softc *dev;
207 {
208 	volatile struct sdmac *sdp;
209 	int s;
210 
211 	sdp = dev->sc_cregs;
212 
213 #ifdef DEBUG
214 	if (ahsc_dmadebug & DDB_FOLLOW)
215 		printf("ahsc_dmastop()\n");
216 #endif
217 	if (dev->sc_dmacmd) {
218 		s = splbio();
219 		if ((dev->sc_dmacmd & (CNTR_TCEN | CNTR_DDIR)) == 0) {
220 			/*
221 			 * only FLUSH if terminal count not enabled,
222 			 * and reading from peripheral
223 			 */
224 			sdp->FLUSH = 1;
225 			while ((sdp->ISTR & ISTR_FE_FLG) == 0)
226 				;
227 		}
228 		/*
229 		 * clear possible interrupt and stop dma
230 		 */
231 		sdp->CINT = 1;
232 		sdp->SP_DMA = 1;
233 		dev->sc_dmacmd = 0;
234 		splx(s);
235 	}
236 }
237 
238 int
239 ahsc_dmaintr(arg)
240 	void *arg;
241 {
242 	struct sbic_softc *dev = arg;
243 	volatile struct sdmac *sdp;
244 	int stat, found;
245 
246 	sdp = dev->sc_cregs;
247 	stat = sdp->ISTR;
248 
249 	if ((stat & (ISTR_INT_F|ISTR_INT_P)) == 0)
250 		return (0);
251 
252 #ifdef DEBUG
253 	if (ahsc_dmadebug & DDB_FOLLOW)
254 		printf("%s: dmaintr 0x%x\n", dev->sc_dev.dv_xname, stat);
255 #endif
256 
257 	/*
258 	 * both, SCSI and DMA interrupts arrive here. I chose
259 	 * arbitrarily that DMA interrupts should have higher
260 	 * precedence than SCSI interrupts.
261 	 */
262 	found = 0;
263 	if (stat & ISTR_E_INT) {
264 		++found;
265 
266 		sdp->CINT = 1;	/* clear possible interrupt */
267 
268 		/*
269 		 * check for SCSI ints in the same go and
270 		 * eventually save an interrupt
271 		 */
272 	}
273 
274 	if (dev->sc_flags & SBICF_INTR && stat & ISTR_INTS)
275 		found += sbicintr(dev);
276 	return(found);
277 }
278 
279 
280 int
281 ahsc_dmanext(dev)
282 	struct sbic_softc *dev;
283 {
284 	volatile struct sdmac *sdp;
285 
286 	sdp = dev->sc_cregs;
287 
288 	if (dev->sc_cur > dev->sc_last) {
289 		/* shouldn't happen !! */
290 		printf("ahsc_dmanext at end !!!\n");
291 		ahsc_dmastop(dev);
292 		return(0);
293 	}
294 	if ((dev->sc_dmacmd & (CNTR_TCEN | CNTR_DDIR)) == 0) {
295 		  /*
296 		   * only FLUSH if terminal count not enabled,
297 		   * and reading from peripheral
298 		   */
299 		sdp->FLUSH = 1;
300 		while ((sdp->ISTR & ISTR_FE_FLG) == 0)
301 			;
302         }
303 	/*
304 	 * clear possible interrupt and stop dma
305 	 */
306 	sdp->CINT = 1;	/* clear possible interrupt */
307 	sdp->SP_DMA = 1;	/* stop dma */
308 	sdp->CNTR = dev->sc_dmacmd;
309 	sdp->ACR = (u_int)dev->sc_cur->dc_addr;
310 	sdp->ST_DMA = 1;
311 
312 	dev->sc_tcnt = dev->sc_cur->dc_count << 1;
313 	return(dev->sc_tcnt);
314 }
315 
316 #ifdef DEBUG
317 void
318 ahsc_dump()
319 {
320 	int i;
321 
322 	for (i = 0; i < ahsc_cd.cd_ndevs; ++i)
323 		if (ahsc_cd.cd_devs[i])
324 			sbic_dump(ahsc_cd.cd_devs[i]);
325 }
326 #endif
327