xref: /netbsd-src/sys/arch/amiga/dev/bzsc.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*	$NetBSD: bzsc.c,v 1.13 1996/10/13 03:06:50 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1995 Daniel Widenfalk
5  * Copyright (c) 1994 Christian E. Hopps
6  * Copyright (c) 1982, 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *	This product includes software developed by the University of
20  *	California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)dma.c
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/device.h>
44 #include <scsi/scsi_all.h>
45 #include <scsi/scsiconf.h>
46 #include <vm/vm.h>
47 #include <vm/vm_kern.h>
48 #include <vm/vm_page.h>
49 #include <machine/pmap.h>
50 #include <amiga/amiga/custom.h>
51 #include <amiga/amiga/cc.h>
52 #include <amiga/amiga/device.h>
53 #include <amiga/amiga/isr.h>
54 #include <amiga/dev/sfasreg.h>
55 #include <amiga/dev/sfasvar.h>
56 #include <amiga/dev/zbusvar.h>
57 #include <amiga/dev/bzscreg.h>
58 #include <amiga/dev/bzscvar.h>
59 
60 void bzscattach __P((struct device *, struct device *, void *));
61 int  bzscmatch  __P((struct device *, void *, void *));
62 
63 struct scsi_adapter bzsc_scsiswitch = {
64 	sfas_scsicmd,
65 	sfas_minphys,
66 	0,			/* no lun support */
67 	0,			/* no lun support */
68 };
69 
70 struct scsi_device bzsc_scsidev = {
71 	NULL,		/* use default error handler */
72 	NULL,		/* do not have a start functio */
73 	NULL,		/* have no async handler */
74 	NULL,		/* Use default done routine */
75 };
76 
77 struct cfattach bzsc_ca = {
78 	sizeof(struct bzsc_softc), bzscmatch, bzscattach
79 };
80 
81 struct cfdriver bzsc_cd = {
82 	NULL, "bzsc", DV_DULL, NULL, 0
83 };
84 
85 int bzsc_intr		__P((void *));
86 void bzsc_set_dma_adr	__P((struct sfas_softc *sc, vm_offset_t ptr, int mode));
87 void bzsc_set_dma_tc	__P((struct sfas_softc *sc, unsigned int len));
88 int bzsc_setup_dma	__P((struct sfas_softc *sc, vm_offset_t ptr, int len,
89 			     int mode));
90 int bzsc_build_dma_chain __P((struct sfas_softc *sc,
91 				struct sfas_dma_chain *chain, void *p, int l));
92 int bzsc_need_bump	__P((struct sfas_softc *sc, vm_offset_t ptr, int len));
93 void bzsc_led_dummy	__P((struct sfas_softc *sc, int mode));
94 
95 /*
96  * if we are an Advanced Systems & Software FastlaneZ3
97  */
98 int
99 bzscmatch(pdp, match, auxp)
100 	struct device *pdp;
101 	void *match, *auxp;
102 {
103 	struct zbus_args *zap;
104 	vu_char *ta;
105 
106 	if (!is_a1200())
107 		return(0);
108 
109 	zap = auxp;
110 	if (zap->manid != 0x2140 || zap->prodid != 11)
111 		return(0);
112 
113 	ta = (vu_char *)(((char *)zap->va)+0x10010);
114 	if (badbaddr((caddr_t)ta))
115 		return(0);
116 
117 	*ta = 0;
118 	*ta = 1;
119 	DELAY(5);
120 	if (*ta != 1)
121 		return(0);
122 
123 	return(1);
124 }
125 
126 void
127 bzscattach(pdp, dp, auxp)
128 	struct device *pdp;
129 	struct device *dp;
130 	void *auxp;
131 {
132 	struct bzsc_softc *sc;
133 	struct zbus_args  *zap;
134 	bzsc_regmap_p	   rp;
135 	vu_char		  *fas;
136 
137 	zap = auxp;
138 	fas = (vu_char *)(((char *)zap->va)+0x10000);
139 
140 	sc = (struct bzsc_softc *)dp;
141 	rp = &sc->sc_regmap;
142 
143 	rp->FAS216.sfas_tc_low   = &fas[0x00];
144 	rp->FAS216.sfas_tc_mid   = &fas[0x02];
145 	rp->FAS216.sfas_fifo     = &fas[0x04];
146 	rp->FAS216.sfas_command  = &fas[0x06];
147 	rp->FAS216.sfas_dest_id  = &fas[0x08];
148 	rp->FAS216.sfas_timeout  = &fas[0x0A];
149 	rp->FAS216.sfas_syncper  = &fas[0x0C];
150 	rp->FAS216.sfas_syncoff  = &fas[0x0E];
151 	rp->FAS216.sfas_config1  = &fas[0x10];
152 	rp->FAS216.sfas_clkconv  = &fas[0x12];
153 	rp->FAS216.sfas_test     = &fas[0x14];
154 	rp->FAS216.sfas_config2  = &fas[0x16];
155 	rp->FAS216.sfas_config3  = &fas[0x18];
156 	rp->FAS216.sfas_tc_high  = &fas[0x1C];
157 	rp->FAS216.sfas_fifo_bot = &fas[0x1E];
158 	rp->cclkaddr		 = &fas[0x21];
159 	rp->epowaddr		 = &fas[0x31];
160 
161 	sc->sc_softc.sc_fas  = (sfas_regmap_p)rp;
162 	sc->sc_softc.sc_spec = 0;
163 
164 	sc->sc_softc.sc_led  = bzsc_led_dummy;
165 
166 	sc->sc_softc.sc_setup_dma	= bzsc_setup_dma;
167 	sc->sc_softc.sc_build_dma_chain = bzsc_build_dma_chain;
168 	sc->sc_softc.sc_need_bump	= bzsc_need_bump;
169 
170 	sc->sc_softc.sc_clock_freq   = 40; /* BlizzardII 1230 runs at 40MHz? */
171 	sc->sc_softc.sc_timeout      = 250; /* Set default timeout to 250ms */
172 	sc->sc_softc.sc_config_flags = 0;
173 	sc->sc_softc.sc_host_id      = 7;
174 
175 	sc->sc_softc.sc_bump_sz = NBPG;
176 	sc->sc_softc.sc_bump_pa = 0x0;
177 
178 	sfasinitialize((struct sfas_softc *)sc);
179 
180 	sc->sc_softc.sc_link.channel = SCSI_CHANNEL_ONLY_ONE;
181 	sc->sc_softc.sc_link.adapter_softc = sc;
182 	sc->sc_softc.sc_link.adapter_target = sc->sc_softc.sc_host_id;
183 	sc->sc_softc.sc_link.adapter = &bzsc_scsiswitch;
184 	sc->sc_softc.sc_link.device = &bzsc_scsidev;
185 	sc->sc_softc.sc_link.openings = 1;
186 
187 	printf("\n");
188 
189 	sc->sc_softc.sc_isr.isr_intr = bzsc_intr;
190 	sc->sc_softc.sc_isr.isr_arg = &sc->sc_softc;
191 	sc->sc_softc.sc_isr.isr_ipl = 2;
192 	add_isr(&sc->sc_softc.sc_isr);
193 
194 	/* attach all scsi units on us */
195 	config_found(dp, &sc->sc_softc.sc_link, scsiprint);
196 }
197 
198 int
199 bzsc_intr(arg)
200 	void *arg;
201 {
202 	struct sfas_softc *dev = arg;
203 	bzsc_regmap_p	rp;
204 	int		quickints;
205 
206 	rp = (bzsc_regmap_p)dev->sc_fas;
207 
208 	if (!(*rp->FAS216.sfas_status & SFAS_STAT_INTERRUPT_PENDING))
209 		return(0);
210 
211 	quickints = 16;
212 	do {
213 		dev->sc_status = *rp->FAS216.sfas_status;
214 		dev->sc_interrupt = *rp->FAS216.sfas_interrupt;
215 
216 		if (dev->sc_interrupt & SFAS_INT_RESELECTED) {
217 			dev->sc_resel[0] = *rp->FAS216.sfas_fifo;
218 			dev->sc_resel[1] = *rp->FAS216.sfas_fifo;
219 		}
220 		sfasintr(dev);
221 	} while((*rp->FAS216.sfas_status & SFAS_STAT_INTERRUPT_PENDING) &&
222 		--quickints);
223 
224 	return(1);
225 }
226 
227 /* --------- */
228 void
229 bzsc_set_dma_adr(sc, ptr, mode)
230 	struct sfas_softc *sc;
231 	vm_offset_t ptr;
232 	int mode;
233 {
234 	bzsc_regmap_p	rp;
235 	unsigned long	p;
236 
237 	rp = (bzsc_regmap_p)sc->sc_fas;
238 
239 	p = ((unsigned long)ptr)>>1;
240 
241 	if (mode == SFAS_DMA_WRITE)
242 		p |= BZSC_DMA_WRITE;
243 	else
244 		p |= BZSC_DMA_READ;
245 
246 	*rp->epowaddr = (u_char)(p>>24) & 0xFF;
247 	*rp->cclkaddr = (u_char)(p>>16) & 0xFF;
248 	*rp->cclkaddr = (u_char)(p>> 8) & 0xFF;
249 	*rp->cclkaddr = (u_char)(p    ) & 0xFF;
250 }
251 
252 /* Set DMA transfer counter */
253 void
254 bzsc_set_dma_tc(sc, len)
255 	struct sfas_softc *sc;
256 	unsigned int len;
257 {
258 	*sc->sc_fas->sfas_tc_low  = len; len >>= 8;
259 	*sc->sc_fas->sfas_tc_mid  = len; len >>= 8;
260 	*sc->sc_fas->sfas_tc_high = len;
261 }
262 
263 /* Initialize DMA for transfer */
264 int
265 bzsc_setup_dma(sc, ptr, len, mode)
266 	struct sfas_softc *sc;
267 	vm_offset_t ptr;
268 	int len;
269 	int mode;
270 {
271 	int	retval;
272 
273 	retval = 0;
274 
275 	switch(mode) {
276 	case SFAS_DMA_READ:
277 	case SFAS_DMA_WRITE:
278 		bzsc_set_dma_adr(sc, ptr, mode);
279 		bzsc_set_dma_tc(sc, len);
280 		break;
281 	case SFAS_DMA_CLEAR:
282 	default:
283 		retval = (*sc->sc_fas->sfas_tc_high << 16) |
284 			 (*sc->sc_fas->sfas_tc_mid  <<  8) |
285 			  *sc->sc_fas->sfas_tc_low;
286 
287 		bzsc_set_dma_tc(sc, 0);
288 		break;
289 	}
290 
291 	return(retval);
292 }
293 
294 /* Check if address and len is ok for DMA transfer */
295 int
296 bzsc_need_bump(sc, ptr, len)
297 	struct sfas_softc *sc;
298 	vm_offset_t ptr;
299 	int len;
300 {
301 	int	p;
302 
303 	p = (int)ptr & 0x03;
304 
305 	if (p) {
306 		p = 4-p;
307 
308 		if (len < 256)
309 			p = len;
310 	}
311 
312 	return(p);
313 }
314 
315 /* Interrupt driven routines */
316 int
317 bzsc_build_dma_chain(sc, chain, p, l)
318 	struct sfas_softc *sc;
319 	struct sfas_dma_chain *chain;
320 	void *p;
321 	int l;
322 {
323 	int	n;
324 
325 	if (!l)
326 		return(0);
327 
328 #define set_link(n, p, l, f)\
329 do { chain[n].ptr = (p); chain[n].len = (l); chain[n++].flg = (f); } while(0)
330 
331 	n = 0;
332 
333 	if (l < 512)
334 		set_link(n, (vm_offset_t)p, l, SFAS_CHAIN_BUMP);
335 	else if (
336 #if defined(M68040) || defined(M68060)
337 		 ((mmutype == MMU_68040) && ((vm_offset_t)p >= 0xFFFC0000)) &&
338 #endif
339 		 ((vm_offset_t)p >= 0xFF000000)) {
340 		int	len;
341 
342 		while(l) {
343 			len = ((l > sc->sc_bump_sz) ? sc->sc_bump_sz : l);
344 
345 			set_link(n, (vm_offset_t)p, len, SFAS_CHAIN_BUMP);
346 
347 			p += len;
348 			l -= len;
349 		}
350 	} else  {
351 		char		*ptr;
352 		vm_offset_t	 pa, lastpa;
353 		int		 len,  prelen,  max_t;
354 
355 		ptr = p;
356 		len = l;
357 
358 		pa = kvtop(ptr);
359 		prelen = ((int)ptr & 0x03);
360 
361 		if (prelen) {
362 			prelen = 4-prelen;
363 			set_link(n, (vm_offset_t)ptr, prelen, SFAS_CHAIN_BUMP);
364 			ptr += prelen;
365 			len -= prelen;
366 		}
367 
368 		lastpa = 0;
369 		while(len > 3) {
370 			pa = kvtop(ptr);
371 			max_t = NBPG - (pa & PGOFSET);
372 			if (max_t > len)
373 				max_t = len;
374 
375 			max_t &= ~3;
376 
377 			if (lastpa == pa)
378 				sc->sc_chain[n-1].len += max_t;
379 			else
380 				set_link(n, pa, max_t, SFAS_CHAIN_DMA);
381 
382 			lastpa = pa+max_t;
383 
384 			ptr += max_t;
385 			len -= max_t;
386 		}
387 
388 		if (len)
389 			set_link(n, (vm_offset_t)ptr, len, SFAS_CHAIN_BUMP);
390 	}
391 
392 	return(n);
393 }
394 
395 /* Turn on led */
396 void bzsc_led_dummy(sc, mode)
397 	struct sfas_softc *sc;
398 	int mode;
399 {
400 }
401