1 /* $NetBSD: si.c,v 1.12 2003/04/19 16:43:59 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 1996 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Adam Glass, David Jones, Gordon W. Ross, and Jens A. Nilsson. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * This file contains the machine-dependent parts of the Sony CXD1180 41 * controller. The machine-independent parts are in ncr5380sbc.c. 42 * Written by Izumi Tsutsui. 43 * 44 * This code is based on arch/vax/vsa/ncr.c and sun3/dev/si.c 45 */ 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/device.h> 50 #include <sys/buf.h> 51 52 #include <machine/cpu.h> 53 #include <m68k/cacheops.h> 54 55 #include <dev/scsipi/scsipi_all.h> 56 #include <dev/scsipi/scsiconf.h> 57 58 #include <dev/ic/ncr5380reg.h> 59 #include <dev/ic/ncr5380var.h> 60 61 #include <news68k/dev/hbvar.h> 62 #include <news68k/dev/dmac_0266.h> 63 64 #define MIN_DMA_LEN 128 65 #define DMAC_BASE 0xe0e80000 /* XXX */ 66 67 struct si_dma_handle { 68 int dh_flags; 69 #define SIDH_BUSY 0x01 70 #define SIDH_OUT 0x02 71 caddr_t dh_addr; 72 int dh_len; 73 }; 74 75 struct si_softc { 76 struct ncr5380_softc ncr_sc; 77 int sc_options; 78 volatile struct dma_regs *sc_regs; 79 struct si_dma_handle ncr_dma[SCI_OPENINGS]; 80 }; 81 82 void si_attach(struct device *, struct device *, void *); 83 int si_match(struct device *, struct cfdata *, void *); 84 int si_intr(int); 85 86 void si_dma_alloc(struct ncr5380_softc *); 87 void si_dma_free(struct ncr5380_softc *); 88 void si_dma_setup(struct ncr5380_softc *); 89 void si_dma_start(struct ncr5380_softc *); 90 void si_dma_poll(struct ncr5380_softc *); 91 void si_dma_eop(struct ncr5380_softc *); 92 void si_dma_stop(struct ncr5380_softc *); 93 94 CFATTACH_DECL(si, sizeof(struct si_softc), 95 si_match, si_attach, NULL, NULL); 96 97 /* 98 * Options for disconnect/reselect, DMA, and interrupts. 99 * By default, allow disconnect/reselect on targets 4-6. 100 * Those are normally tapes that really need it enabled. 101 * The options are taken from the config file. 102 */ 103 #define SI_NO_DISCONNECT 0x000ff 104 #define SI_NO_PARITY_CHK 0x0ff00 105 #define SI_FORCE_POLLING 0x10000 106 #define SI_DISABLE_DMA 0x20000 107 108 int si_options = 0x0f; 109 110 111 int 112 si_match(parent, cf, aux) 113 struct device *parent; 114 struct cfdata *cf; 115 void *aux; 116 { 117 struct hb_attach_args *ha = aux; 118 int addr; 119 120 if (strcmp(ha->ha_name, "si")) 121 return 0; 122 123 addr = IIOV(ha->ha_address); 124 125 if (badaddr((void *)addr, 1)) 126 return 0; 127 128 return 1; 129 } 130 131 /* 132 * Card attach function 133 */ 134 135 void 136 si_attach(parent, self, aux) 137 struct device *parent, *self; 138 void *aux; 139 { 140 struct si_softc *sc = (struct si_softc *)self; 141 struct ncr5380_softc *ncr_sc = &sc->ncr_sc; 142 struct cfdata *cf = self->dv_cfdata; 143 struct hb_attach_args *ha = aux; 144 u_char *addr; 145 146 /* Get options from config flags if specified. */ 147 if (cf->cf_flags) 148 sc->sc_options = cf->cf_flags; 149 else 150 sc->sc_options = si_options; 151 152 printf(": options=0x%x\n", sc->sc_options); 153 154 ncr_sc->sc_no_disconnect = (sc->sc_options & SI_NO_DISCONNECT); 155 ncr_sc->sc_parity_disable = (sc->sc_options & SI_NO_PARITY_CHK) >> 8; 156 if (sc->sc_options & SI_FORCE_POLLING) 157 ncr_sc->sc_flags |= NCR5380_FORCE_POLLING; 158 159 ncr_sc->sc_min_dma_len = MIN_DMA_LEN; 160 ncr_sc->sc_dma_alloc = si_dma_alloc; 161 ncr_sc->sc_dma_free = si_dma_free; 162 ncr_sc->sc_dma_poll = si_dma_poll; 163 ncr_sc->sc_dma_setup = si_dma_setup; 164 ncr_sc->sc_dma_start = si_dma_start; 165 ncr_sc->sc_dma_eop = si_dma_eop; 166 ncr_sc->sc_dma_stop = si_dma_stop; 167 168 if (sc->sc_options & SI_DISABLE_DMA) 169 /* Override this function pointer. */ 170 ncr_sc->sc_dma_alloc = NULL; 171 172 addr = (u_char *)IIOV(ha->ha_address); 173 ncr_sc->sci_r0 = addr + 0; 174 ncr_sc->sci_r1 = addr + 1; 175 ncr_sc->sci_r2 = addr + 2; 176 ncr_sc->sci_r3 = addr + 3; 177 ncr_sc->sci_r4 = addr + 4; 178 ncr_sc->sci_r5 = addr + 5; 179 ncr_sc->sci_r6 = addr + 6; 180 ncr_sc->sci_r7 = addr + 7; 181 182 ncr_sc->sc_rev = NCR_VARIANT_CXD1180; 183 184 ncr_sc->sc_pio_in = ncr5380_pio_in; 185 ncr_sc->sc_pio_out = ncr5380_pio_out; 186 187 ncr_sc->sc_adapter.adapt_minphys = minphys; 188 ncr_sc->sc_channel.chan_id = 7; 189 190 /* soft reset DMAC */ 191 sc->sc_regs = (void *)IIOV(DMAC_BASE); 192 sc->sc_regs->ctl = DC_CTL_RST; 193 194 ncr5380_attach(ncr_sc); 195 } 196 197 int 198 si_intr(unit) 199 int unit; 200 { 201 struct si_softc *sc; 202 extern struct cfdriver si_cd; 203 204 if (unit >= si_cd.cd_ndevs) 205 return 0; 206 207 sc = si_cd.cd_devs[unit]; 208 (void)ncr5380_intr(&sc->ncr_sc); 209 210 return 0; 211 } 212 213 /* 214 * DMA routines for news1700 machines 215 */ 216 217 void 218 si_dma_alloc(ncr_sc) 219 struct ncr5380_softc *ncr_sc; 220 { 221 struct si_softc *sc = (struct si_softc *)ncr_sc; 222 struct sci_req *sr = ncr_sc->sc_current; 223 struct scsipi_xfer *xs = sr->sr_xs; 224 struct si_dma_handle *dh; 225 int xlen, i; 226 227 #ifdef DIAGNOSTIC 228 if (sr->sr_dma_hand != NULL) 229 panic("si_dma_alloc: already have DMA handle"); 230 #endif 231 232 /* Polled transfers shouldn't allocate a DMA handle. */ 233 if (sr->sr_flags & SR_IMMED) 234 return; 235 236 xlen = ncr_sc->sc_datalen; 237 238 /* Make sure our caller checked sc_min_dma_len. */ 239 if (xlen < MIN_DMA_LEN) 240 panic("si_dma_alloc: len=0x%x", xlen); 241 242 /* 243 * Find free DMA handle. Guaranteed to find one since we 244 * have as many DMA handles as the driver has processes. 245 * (instances?) 246 */ 247 for (i = 0; i < SCI_OPENINGS; i++) { 248 if ((sc->ncr_dma[i].dh_flags & SIDH_BUSY) == 0) 249 goto found; 250 } 251 panic("si_dma_alloc(): no free DMA handles"); 252 found: 253 dh = &sc->ncr_dma[i]; 254 dh->dh_flags = SIDH_BUSY; 255 dh->dh_addr = ncr_sc->sc_dataptr; 256 dh->dh_len = xlen; 257 258 /* Remember dest buffer parameters */ 259 if (xs->xs_control & XS_CTL_DATA_OUT) 260 dh->dh_flags |= SIDH_OUT; 261 262 sr->sr_dma_hand = dh; 263 } 264 265 void 266 si_dma_free(ncr_sc) 267 struct ncr5380_softc *ncr_sc; 268 { 269 struct sci_req *sr = ncr_sc->sc_current; 270 struct si_dma_handle *dh = sr->sr_dma_hand; 271 272 if (dh->dh_flags & SIDH_BUSY) 273 dh->dh_flags = 0; 274 else 275 printf("si_dma_free: free'ing unused buffer\n"); 276 277 sr->sr_dma_hand = NULL; 278 } 279 280 void 281 si_dma_setup(ncr_sc) 282 struct ncr5380_softc *ncr_sc; 283 { 284 285 /* Do nothing here */ 286 } 287 288 void 289 si_dma_start(ncr_sc) 290 struct ncr5380_softc *ncr_sc; 291 { 292 struct si_softc *sc = (struct si_softc *)ncr_sc; 293 volatile struct dma_regs *dmac = sc->sc_regs; 294 struct sci_req *sr = ncr_sc->sc_current; 295 struct si_dma_handle *dh = sr->sr_dma_hand; 296 u_int addr, offset, rest; 297 long len; 298 int i; 299 300 /* 301 * Set the news68k-specific registers. 302 */ 303 304 /* reset DMAC */ 305 dmac->ctl = DC_CTL_RST; 306 dmac->ctl = 0; 307 308 addr = (u_int)dh->dh_addr; 309 offset = addr & DMAC_SEG_OFFSET; 310 len = (u_int)dh->dh_len; 311 312 /* set DMA transfer length and offset of first segment */ 313 dmac->tcnt = len; 314 dmac->offset = offset; 315 316 /* set first DMA segment address */ 317 dmac->tag = 0; 318 dmac->mapent = kvtop((caddr_t)addr) >> DMAC_SEG_SHIFT; 319 rest = DMAC_SEG_SIZE - offset; 320 addr += rest; 321 len -= rest; 322 323 /* set all the rest segments */ 324 for (i = 1; len > 0; i++) { 325 dmac->tag = i; 326 dmac->mapent = kvtop((caddr_t)addr) >> DMAC_SEG_SHIFT; 327 len -= DMAC_SEG_SIZE; 328 addr += DMAC_SEG_SIZE; 329 } 330 /* terminate TAG */ 331 dmac->tag = 0; 332 333 /* 334 * Now from the 5380-internal DMA registers. 335 */ 336 if (dh->dh_flags & SIDH_OUT) { 337 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_OUT); 338 NCR5380_WRITE(ncr_sc, sci_icmd, SCI_ICMD_DATA); 339 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 340 | SCI_MODE_DMA); 341 342 /* set Dir */ 343 dmac->ctl = 0; 344 345 /* start DMA */ 346 NCR5380_WRITE(ncr_sc, sci_dma_send, 0); 347 dmac->ctl = DC_CTL_ENB; 348 } else { 349 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_IN); 350 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 351 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 352 | SCI_MODE_DMA); 353 354 /* set Dir */ 355 dmac->ctl = DC_CTL_MOD; 356 357 /* start DMA */ 358 NCR5380_WRITE(ncr_sc, sci_irecv, 0); 359 dmac->ctl = DC_CTL_MOD | DC_CTL_ENB; 360 } 361 ncr_sc->sc_state |= NCR_DOINGDMA; 362 } 363 364 /* 365 * When? 366 */ 367 void 368 si_dma_poll(ncr_sc) 369 struct ncr5380_softc *ncr_sc; 370 { 371 372 printf("si_dma_poll\n"); 373 } 374 375 /* 376 * news68k (probably) does not use the EOP signal. 377 */ 378 void 379 si_dma_eop(ncr_sc) 380 struct ncr5380_softc *ncr_sc; 381 { 382 383 printf("si_dma_eop\n"); 384 } 385 386 void 387 si_dma_stop(ncr_sc) 388 struct ncr5380_softc *ncr_sc; 389 { 390 struct si_softc *sc = (struct si_softc *)ncr_sc; 391 volatile struct dma_regs *dmac = sc->sc_regs; 392 struct sci_req *sr = ncr_sc->sc_current; 393 struct si_dma_handle *dh = sr->sr_dma_hand; 394 int resid, ntrans, i; 395 396 /* check DMAC interrupt status */ 397 if ((dmac->stat & DC_ST_INT) == 0) { 398 #ifdef DEBUG 399 printf("si_dma_stop: no DMA interrupt"); 400 #endif 401 return; /* XXX */ 402 } 403 404 if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { 405 #ifdef DEBUG 406 printf("si_dma_stop: dma not running\n"); 407 #endif 408 return; 409 } 410 ncr_sc->sc_state &= ~NCR_DOINGDMA; 411 412 /* OK, have either phase mis-match or end of DMA. */ 413 /* Set an impossible phase to prevent data movement? */ 414 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_INVALID); 415 416 /* Note that timeout may have set the error flag. */ 417 if (ncr_sc->sc_state & NCR_ABORTING) 418 goto out; 419 420 /* 421 * Sometimes the FIFO buffer isn't drained when the 422 * interrupt is posted. Just loop here and hope that 423 * it will drain soon. 424 */ 425 for (i = 0; i < 200000; i++) { /* 2 sec */ 426 resid = dmac->tcnt; 427 if (resid == 0) 428 break; 429 DELAY(10); 430 } 431 432 if (resid) 433 printf("si_dma_stop: resid=0x%x\n", resid); 434 435 ntrans = dh->dh_len - resid; 436 437 ncr_sc->sc_dataptr += ntrans; 438 ncr_sc->sc_datalen -= ntrans; 439 440 if ((dh->dh_flags & SIDH_OUT) == 0) { 441 PCIA(); 442 } 443 444 out: 445 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & 446 ~(SCI_MODE_DMA)); 447 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 448 } 449