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