xref: /netbsd-src/sys/arch/amiga/dev/ahsc.c (revision d0fed6c87ddc40a8bffa6f99e7433ddfc864dd83)
1 /*	$NetBSD: ahsc.c,v 1.18 1996/12/23 09:09:51 veego 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 *, struct cfdata *, 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, cfp, auxp)
99 	struct device *pdp;
100 	struct cfdata *cfp;
101 	void *auxp;
102 {
103 	char *mbusstr;
104 
105 	mbusstr = auxp;
106 	if (is_a3000() && matchname(auxp, "ahsc"))
107 		return(1);
108 	return(0);
109 }
110 
111 void
112 ahscattach(pdp, dp, auxp)
113 	struct device *pdp, *dp;
114 	void *auxp;
115 {
116 	volatile struct sdmac *rp;
117 	struct sbic_softc *sc;
118 
119 	printf("\n");
120 
121 	sc = (struct sbic_softc *)dp;
122 	sc->sc_cregs = rp = ztwomap(0xdd0000);
123 	/*
124 	 * disable ints and reset bank register
125 	 */
126 	rp->CNTR = CNTR_PDMD;
127 	rp->DAWR = DAWR_AHSC;
128 	sc->sc_enintr = ahsc_enintr;
129 	sc->sc_dmago = ahsc_dmago;
130 	sc->sc_dmanext = ahsc_dmanext;
131 	sc->sc_dmastop = ahsc_dmastop;
132 	sc->sc_dmacmd = 0;
133 
134 	/*
135 	 * eveything is a valid dma address
136 	 */
137 	sc->sc_dmamask = 0;
138 	sc->sc_sbicp = (sbic_regmap_p) ((int)rp + 0x41);
139 	sc->sc_clkfreq = sbic_clock_override ? sbic_clock_override : 143;
140 
141 	sc->sc_link.channel = SCSI_CHANNEL_ONLY_ONE;
142 	sc->sc_link.adapter_softc = sc;
143 	sc->sc_link.adapter_target = 7;
144 	sc->sc_link.adapter = &ahsc_scsiswitch;
145 	sc->sc_link.device = &ahsc_scsidev;
146 	sc->sc_link.openings = 2;
147 	sc->sc_link.max_target = 7;
148 
149 	sbicinit(sc);
150 
151 	sc->sc_isr.isr_intr = ahsc_dmaintr;
152 	sc->sc_isr.isr_arg = sc;
153 	sc->sc_isr.isr_ipl = 2;
154 	add_isr (&sc->sc_isr);
155 
156 	/*
157 	 * attach all scsi units on us
158 	 */
159 	config_found(dp, &sc->sc_link, scsiprint);
160 }
161 
162 void
163 ahsc_enintr(dev)
164 	struct sbic_softc *dev;
165 {
166 	volatile struct sdmac *sdp;
167 
168 	sdp = dev->sc_cregs;
169 
170 	dev->sc_flags |= SBICF_INTR;
171 	sdp->CNTR = CNTR_PDMD | CNTR_INTEN;
172 }
173 
174 int
175 ahsc_dmago(dev, addr, count, flags)
176 	struct sbic_softc *dev;
177 	char *addr;
178 	int count, flags;
179 {
180 	volatile struct sdmac *sdp;
181 
182 	sdp = dev->sc_cregs;
183 	/*
184 	 * Set up the command word based on flags
185 	 */
186 	dev->sc_dmacmd = CNTR_PDMD | CNTR_INTEN;
187 	if ((flags & DMAGO_READ) == 0)
188 		dev->sc_dmacmd |= CNTR_DDIR;
189 #ifdef DEBUG
190 	if (ahsc_dmadebug & DDB_IO)
191 		printf("ahsc_dmago: cmd %x\n", dev->sc_dmacmd);
192 #endif
193 
194 	dev->sc_flags |= SBICF_INTR;
195 	sdp->CNTR = dev->sc_dmacmd;
196 	sdp->ACR = (u_int) dev->sc_cur->dc_addr;
197 	sdp->ST_DMA = 1;
198 
199 	return(dev->sc_tcnt);
200 }
201 
202 void
203 ahsc_dmastop(dev)
204 	struct sbic_softc *dev;
205 {
206 	volatile struct sdmac *sdp;
207 	int s;
208 
209 	sdp = dev->sc_cregs;
210 
211 #ifdef DEBUG
212 	if (ahsc_dmadebug & DDB_FOLLOW)
213 		printf("ahsc_dmastop()\n");
214 #endif
215 	if (dev->sc_dmacmd) {
216 		s = splbio();
217 		if ((dev->sc_dmacmd & (CNTR_TCEN | CNTR_DDIR)) == 0) {
218 			/*
219 			 * only FLUSH if terminal count not enabled,
220 			 * and reading from peripheral
221 			 */
222 			sdp->FLUSH = 1;
223 			while ((sdp->ISTR & ISTR_FE_FLG) == 0)
224 				;
225 		}
226 		/*
227 		 * clear possible interrupt and stop dma
228 		 */
229 		sdp->CINT = 1;
230 		sdp->SP_DMA = 1;
231 		dev->sc_dmacmd = 0;
232 		splx(s);
233 	}
234 }
235 
236 int
237 ahsc_dmaintr(arg)
238 	void *arg;
239 {
240 	struct sbic_softc *dev = arg;
241 	volatile struct sdmac *sdp;
242 	int stat, found;
243 
244 	sdp = dev->sc_cregs;
245 	stat = sdp->ISTR;
246 
247 	if ((stat & (ISTR_INT_F|ISTR_INT_P)) == 0)
248 		return (0);
249 
250 #ifdef DEBUG
251 	if (ahsc_dmadebug & DDB_FOLLOW)
252 		printf("%s: dmaintr 0x%x\n", dev->sc_dev.dv_xname, stat);
253 #endif
254 
255 	/*
256 	 * both, SCSI and DMA interrupts arrive here. I chose
257 	 * arbitrarily that DMA interrupts should have higher
258 	 * precedence than SCSI interrupts.
259 	 */
260 	found = 0;
261 	if (stat & ISTR_E_INT) {
262 		++found;
263 
264 		sdp->CINT = 1;	/* clear possible interrupt */
265 
266 		/*
267 		 * check for SCSI ints in the same go and
268 		 * eventually save an interrupt
269 		 */
270 	}
271 
272 	if (dev->sc_flags & SBICF_INTR && stat & ISTR_INTS)
273 		found += sbicintr(dev);
274 	return(found);
275 }
276 
277 
278 int
279 ahsc_dmanext(dev)
280 	struct sbic_softc *dev;
281 {
282 	volatile struct sdmac *sdp;
283 
284 	sdp = dev->sc_cregs;
285 
286 	if (dev->sc_cur > dev->sc_last) {
287 		/* shouldn't happen !! */
288 		printf("ahsc_dmanext at end !!!\n");
289 		ahsc_dmastop(dev);
290 		return(0);
291 	}
292 	if ((dev->sc_dmacmd & (CNTR_TCEN | CNTR_DDIR)) == 0) {
293 		  /*
294 		   * only FLUSH if terminal count not enabled,
295 		   * and reading from peripheral
296 		   */
297 		sdp->FLUSH = 1;
298 		while ((sdp->ISTR & ISTR_FE_FLG) == 0)
299 			;
300         }
301 	/*
302 	 * clear possible interrupt and stop dma
303 	 */
304 	sdp->CINT = 1;	/* clear possible interrupt */
305 	sdp->SP_DMA = 1;	/* stop dma */
306 	sdp->CNTR = dev->sc_dmacmd;
307 	sdp->ACR = (u_int)dev->sc_cur->dc_addr;
308 	sdp->ST_DMA = 1;
309 
310 	dev->sc_tcnt = dev->sc_cur->dc_count << 1;
311 	return(dev->sc_tcnt);
312 }
313 
314 #ifdef DEBUG
315 void
316 ahsc_dump()
317 {
318 	int i;
319 
320 	for (i = 0; i < ahsc_cd.cd_ndevs; ++i)
321 		if (ahsc_cd.cd_devs[i])
322 			sbic_dump(ahsc_cd.cd_devs[i]);
323 }
324 #endif
325