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