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