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