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