1 /* $NetBSD: si.c,v 1.13 2003/07/15 02:59:26 lukem 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/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: si.c,v 1.13 2003/07/15 02:59:26 lukem Exp $"); 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/device.h> 53 #include <sys/buf.h> 54 55 #include <machine/cpu.h> 56 #include <m68k/cacheops.h> 57 58 #include <dev/scsipi/scsipi_all.h> 59 #include <dev/scsipi/scsiconf.h> 60 61 #include <dev/ic/ncr5380reg.h> 62 #include <dev/ic/ncr5380var.h> 63 64 #include <news68k/dev/hbvar.h> 65 #include <news68k/dev/dmac_0266.h> 66 67 #define MIN_DMA_LEN 128 68 #define DMAC_BASE 0xe0e80000 /* XXX */ 69 70 struct si_dma_handle { 71 int dh_flags; 72 #define SIDH_BUSY 0x01 73 #define SIDH_OUT 0x02 74 caddr_t dh_addr; 75 int dh_len; 76 }; 77 78 struct si_softc { 79 struct ncr5380_softc ncr_sc; 80 int sc_options; 81 volatile struct dma_regs *sc_regs; 82 struct si_dma_handle ncr_dma[SCI_OPENINGS]; 83 }; 84 85 void si_attach(struct device *, struct device *, void *); 86 int si_match(struct device *, struct cfdata *, void *); 87 int si_intr(int); 88 89 void si_dma_alloc(struct ncr5380_softc *); 90 void si_dma_free(struct ncr5380_softc *); 91 void si_dma_setup(struct ncr5380_softc *); 92 void si_dma_start(struct ncr5380_softc *); 93 void si_dma_poll(struct ncr5380_softc *); 94 void si_dma_eop(struct ncr5380_softc *); 95 void si_dma_stop(struct ncr5380_softc *); 96 97 CFATTACH_DECL(si, sizeof(struct si_softc), 98 si_match, si_attach, NULL, NULL); 99 100 /* 101 * Options for disconnect/reselect, DMA, and interrupts. 102 * By default, allow disconnect/reselect on targets 4-6. 103 * Those are normally tapes that really need it enabled. 104 * The options are taken from the config file. 105 */ 106 #define SI_NO_DISCONNECT 0x000ff 107 #define SI_NO_PARITY_CHK 0x0ff00 108 #define SI_FORCE_POLLING 0x10000 109 #define SI_DISABLE_DMA 0x20000 110 111 int si_options = 0x0f; 112 113 114 int 115 si_match(parent, cf, aux) 116 struct device *parent; 117 struct cfdata *cf; 118 void *aux; 119 { 120 struct hb_attach_args *ha = aux; 121 int addr; 122 123 if (strcmp(ha->ha_name, "si")) 124 return 0; 125 126 addr = IIOV(ha->ha_address); 127 128 if (badaddr((void *)addr, 1)) 129 return 0; 130 131 return 1; 132 } 133 134 /* 135 * Card attach function 136 */ 137 138 void 139 si_attach(parent, self, aux) 140 struct device *parent, *self; 141 void *aux; 142 { 143 struct si_softc *sc = (struct si_softc *)self; 144 struct ncr5380_softc *ncr_sc = &sc->ncr_sc; 145 struct cfdata *cf = self->dv_cfdata; 146 struct hb_attach_args *ha = aux; 147 u_char *addr; 148 149 /* Get options from config flags if specified. */ 150 if (cf->cf_flags) 151 sc->sc_options = cf->cf_flags; 152 else 153 sc->sc_options = si_options; 154 155 printf(": options=0x%x\n", sc->sc_options); 156 157 ncr_sc->sc_no_disconnect = (sc->sc_options & SI_NO_DISCONNECT); 158 ncr_sc->sc_parity_disable = (sc->sc_options & SI_NO_PARITY_CHK) >> 8; 159 if (sc->sc_options & SI_FORCE_POLLING) 160 ncr_sc->sc_flags |= NCR5380_FORCE_POLLING; 161 162 ncr_sc->sc_min_dma_len = MIN_DMA_LEN; 163 ncr_sc->sc_dma_alloc = si_dma_alloc; 164 ncr_sc->sc_dma_free = si_dma_free; 165 ncr_sc->sc_dma_poll = si_dma_poll; 166 ncr_sc->sc_dma_setup = si_dma_setup; 167 ncr_sc->sc_dma_start = si_dma_start; 168 ncr_sc->sc_dma_eop = si_dma_eop; 169 ncr_sc->sc_dma_stop = si_dma_stop; 170 171 if (sc->sc_options & SI_DISABLE_DMA) 172 /* Override this function pointer. */ 173 ncr_sc->sc_dma_alloc = NULL; 174 175 addr = (u_char *)IIOV(ha->ha_address); 176 ncr_sc->sci_r0 = addr + 0; 177 ncr_sc->sci_r1 = addr + 1; 178 ncr_sc->sci_r2 = addr + 2; 179 ncr_sc->sci_r3 = addr + 3; 180 ncr_sc->sci_r4 = addr + 4; 181 ncr_sc->sci_r5 = addr + 5; 182 ncr_sc->sci_r6 = addr + 6; 183 ncr_sc->sci_r7 = addr + 7; 184 185 ncr_sc->sc_rev = NCR_VARIANT_CXD1180; 186 187 ncr_sc->sc_pio_in = ncr5380_pio_in; 188 ncr_sc->sc_pio_out = ncr5380_pio_out; 189 190 ncr_sc->sc_adapter.adapt_minphys = minphys; 191 ncr_sc->sc_channel.chan_id = 7; 192 193 /* soft reset DMAC */ 194 sc->sc_regs = (void *)IIOV(DMAC_BASE); 195 sc->sc_regs->ctl = DC_CTL_RST; 196 197 ncr5380_attach(ncr_sc); 198 } 199 200 int 201 si_intr(unit) 202 int unit; 203 { 204 struct si_softc *sc; 205 extern struct cfdriver si_cd; 206 207 if (unit >= si_cd.cd_ndevs) 208 return 0; 209 210 sc = si_cd.cd_devs[unit]; 211 (void)ncr5380_intr(&sc->ncr_sc); 212 213 return 0; 214 } 215 216 /* 217 * DMA routines for news1700 machines 218 */ 219 220 void 221 si_dma_alloc(ncr_sc) 222 struct ncr5380_softc *ncr_sc; 223 { 224 struct si_softc *sc = (struct si_softc *)ncr_sc; 225 struct sci_req *sr = ncr_sc->sc_current; 226 struct scsipi_xfer *xs = sr->sr_xs; 227 struct si_dma_handle *dh; 228 int xlen, i; 229 230 #ifdef DIAGNOSTIC 231 if (sr->sr_dma_hand != NULL) 232 panic("si_dma_alloc: already have DMA handle"); 233 #endif 234 235 /* Polled transfers shouldn't allocate a DMA handle. */ 236 if (sr->sr_flags & SR_IMMED) 237 return; 238 239 xlen = ncr_sc->sc_datalen; 240 241 /* Make sure our caller checked sc_min_dma_len. */ 242 if (xlen < MIN_DMA_LEN) 243 panic("si_dma_alloc: len=0x%x", xlen); 244 245 /* 246 * Find free DMA handle. Guaranteed to find one since we 247 * have as many DMA handles as the driver has processes. 248 * (instances?) 249 */ 250 for (i = 0; i < SCI_OPENINGS; i++) { 251 if ((sc->ncr_dma[i].dh_flags & SIDH_BUSY) == 0) 252 goto found; 253 } 254 panic("si_dma_alloc(): no free DMA handles"); 255 found: 256 dh = &sc->ncr_dma[i]; 257 dh->dh_flags = SIDH_BUSY; 258 dh->dh_addr = ncr_sc->sc_dataptr; 259 dh->dh_len = xlen; 260 261 /* Remember dest buffer parameters */ 262 if (xs->xs_control & XS_CTL_DATA_OUT) 263 dh->dh_flags |= SIDH_OUT; 264 265 sr->sr_dma_hand = dh; 266 } 267 268 void 269 si_dma_free(ncr_sc) 270 struct ncr5380_softc *ncr_sc; 271 { 272 struct sci_req *sr = ncr_sc->sc_current; 273 struct si_dma_handle *dh = sr->sr_dma_hand; 274 275 if (dh->dh_flags & SIDH_BUSY) 276 dh->dh_flags = 0; 277 else 278 printf("si_dma_free: free'ing unused buffer\n"); 279 280 sr->sr_dma_hand = NULL; 281 } 282 283 void 284 si_dma_setup(ncr_sc) 285 struct ncr5380_softc *ncr_sc; 286 { 287 288 /* Do nothing here */ 289 } 290 291 void 292 si_dma_start(ncr_sc) 293 struct ncr5380_softc *ncr_sc; 294 { 295 struct si_softc *sc = (struct si_softc *)ncr_sc; 296 volatile struct dma_regs *dmac = sc->sc_regs; 297 struct sci_req *sr = ncr_sc->sc_current; 298 struct si_dma_handle *dh = sr->sr_dma_hand; 299 u_int addr, offset, rest; 300 long len; 301 int i; 302 303 /* 304 * Set the news68k-specific registers. 305 */ 306 307 /* reset DMAC */ 308 dmac->ctl = DC_CTL_RST; 309 dmac->ctl = 0; 310 311 addr = (u_int)dh->dh_addr; 312 offset = addr & DMAC_SEG_OFFSET; 313 len = (u_int)dh->dh_len; 314 315 /* set DMA transfer length and offset of first segment */ 316 dmac->tcnt = len; 317 dmac->offset = offset; 318 319 /* set first DMA segment address */ 320 dmac->tag = 0; 321 dmac->mapent = kvtop((caddr_t)addr) >> DMAC_SEG_SHIFT; 322 rest = DMAC_SEG_SIZE - offset; 323 addr += rest; 324 len -= rest; 325 326 /* set all the rest segments */ 327 for (i = 1; len > 0; i++) { 328 dmac->tag = i; 329 dmac->mapent = kvtop((caddr_t)addr) >> DMAC_SEG_SHIFT; 330 len -= DMAC_SEG_SIZE; 331 addr += DMAC_SEG_SIZE; 332 } 333 /* terminate TAG */ 334 dmac->tag = 0; 335 336 /* 337 * Now from the 5380-internal DMA registers. 338 */ 339 if (dh->dh_flags & SIDH_OUT) { 340 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_OUT); 341 NCR5380_WRITE(ncr_sc, sci_icmd, SCI_ICMD_DATA); 342 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 343 | SCI_MODE_DMA); 344 345 /* set Dir */ 346 dmac->ctl = 0; 347 348 /* start DMA */ 349 NCR5380_WRITE(ncr_sc, sci_dma_send, 0); 350 dmac->ctl = DC_CTL_ENB; 351 } else { 352 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_DATA_IN); 353 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 354 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) 355 | SCI_MODE_DMA); 356 357 /* set Dir */ 358 dmac->ctl = DC_CTL_MOD; 359 360 /* start DMA */ 361 NCR5380_WRITE(ncr_sc, sci_irecv, 0); 362 dmac->ctl = DC_CTL_MOD | DC_CTL_ENB; 363 } 364 ncr_sc->sc_state |= NCR_DOINGDMA; 365 } 366 367 /* 368 * When? 369 */ 370 void 371 si_dma_poll(ncr_sc) 372 struct ncr5380_softc *ncr_sc; 373 { 374 375 printf("si_dma_poll\n"); 376 } 377 378 /* 379 * news68k (probably) does not use the EOP signal. 380 */ 381 void 382 si_dma_eop(ncr_sc) 383 struct ncr5380_softc *ncr_sc; 384 { 385 386 printf("si_dma_eop\n"); 387 } 388 389 void 390 si_dma_stop(ncr_sc) 391 struct ncr5380_softc *ncr_sc; 392 { 393 struct si_softc *sc = (struct si_softc *)ncr_sc; 394 volatile struct dma_regs *dmac = sc->sc_regs; 395 struct sci_req *sr = ncr_sc->sc_current; 396 struct si_dma_handle *dh = sr->sr_dma_hand; 397 int resid, ntrans, i; 398 399 /* check DMAC interrupt status */ 400 if ((dmac->stat & DC_ST_INT) == 0) { 401 #ifdef DEBUG 402 printf("si_dma_stop: no DMA interrupt"); 403 #endif 404 return; /* XXX */ 405 } 406 407 if ((ncr_sc->sc_state & NCR_DOINGDMA) == 0) { 408 #ifdef DEBUG 409 printf("si_dma_stop: dma not running\n"); 410 #endif 411 return; 412 } 413 ncr_sc->sc_state &= ~NCR_DOINGDMA; 414 415 /* OK, have either phase mis-match or end of DMA. */ 416 /* Set an impossible phase to prevent data movement? */ 417 NCR5380_WRITE(ncr_sc, sci_tcmd, PHASE_INVALID); 418 419 /* Note that timeout may have set the error flag. */ 420 if (ncr_sc->sc_state & NCR_ABORTING) 421 goto out; 422 423 /* 424 * Sometimes the FIFO buffer isn't drained when the 425 * interrupt is posted. Just loop here and hope that 426 * it will drain soon. 427 */ 428 for (i = 0; i < 200000; i++) { /* 2 sec */ 429 resid = dmac->tcnt; 430 if (resid == 0) 431 break; 432 DELAY(10); 433 } 434 435 if (resid) 436 printf("si_dma_stop: resid=0x%x\n", resid); 437 438 ntrans = dh->dh_len - resid; 439 440 ncr_sc->sc_dataptr += ntrans; 441 ncr_sc->sc_datalen -= ntrans; 442 443 if ((dh->dh_flags & SIDH_OUT) == 0) { 444 PCIA(); 445 } 446 447 out: 448 NCR5380_WRITE(ncr_sc, sci_mode, NCR5380_READ(ncr_sc, sci_mode) & 449 ~(SCI_MODE_DMA)); 450 NCR5380_WRITE(ncr_sc, sci_icmd, 0); 451 } 452