1 /* $NetBSD: sec.c,v 1.10 2008/04/05 20:08:52 cegger Exp $ */ 2 3 /*- 4 * Copyright (c) 2000, 2001, 2006 Ben Harris 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 /* 30 * sec.c -- driver for Acorn SCSI expansion cards (AKA30, AKA31, AKA32) 31 * 32 * These cards are documented in: 33 * Acorn Archimedes 500 series / Acorn R200 series Technical Reference Manual 34 * Published by Acorn Computers Limited 35 * ISBN 1 85250 086 7 36 * Part number 0486,052 37 * Issue 1, November 1990 38 */ 39 40 #include <sys/cdefs.h> 41 __KERNEL_RCSID(0, "$NetBSD: sec.c,v 1.10 2008/04/05 20:08:52 cegger Exp $"); 42 43 #include <sys/param.h> 44 45 #include <sys/buf.h> 46 #include <sys/device.h> 47 #include <sys/malloc.h> 48 #include <sys/reboot.h> /* For bootverbose */ 49 #include <sys/syslog.h> 50 #include <sys/systm.h> 51 52 #include <dev/scsipi/scsi_all.h> 53 #include <dev/scsipi/scsipi_all.h> 54 #include <dev/scsipi/scsiconf.h> 55 56 #include <sys/bus.h> 57 58 #include <dev/ic/wd33c93reg.h> 59 #include <dev/ic/wd33c93var.h> 60 #include <dev/ic/nec71071reg.h> 61 62 #include <dev/podulebus/podulebus.h> 63 #include <dev/podulebus/podules.h> 64 #include <dev/podulebus/powerromreg.h> 65 #include <dev/podulebus/secreg.h> 66 67 #include "opt_ddb.h" 68 69 struct sec_softc { 70 struct wd33c93_softc sc_sbic; 71 bus_space_tag_t sc_pod_t; 72 bus_space_handle_t sc_pod_h; 73 bus_space_tag_t sc_mod_t; 74 bus_space_handle_t sc_mod_h; 75 void *sc_ih; 76 struct evcnt sc_intrcnt; 77 uint8_t sc_mpr; 78 79 /* Details of the current DMA transfer */ 80 bool sc_dmaactive; 81 void * sc_dmaaddr; 82 int sc_dmaoff; 83 size_t sc_dmalen; 84 bool sc_dmain; 85 /* Details of the current block within the above transfer */ 86 size_t sc_dmablk; 87 }; 88 89 #define SEC_DMABLK 16384 90 #define SEC_NBLKS 3 91 #define SEC_DMAMODE MODE_TMODE_DMD 92 93 /* autoconfiguration glue */ 94 static int sec_match(struct device *, struct cfdata *, void *); 95 static void sec_attach(struct device *, struct device *, void *); 96 97 /* shutdown hook */ 98 static void sec_shutdown(void *); 99 100 /* callbacks from MI WD33C93 driver */ 101 static int sec_dmasetup(struct wd33c93_softc *, void **, size_t *, int, 102 size_t *); 103 static int sec_dmago(struct wd33c93_softc *); 104 static void sec_dmastop(struct wd33c93_softc *); 105 static void sec_reset(struct wd33c93_softc *); 106 107 static int sec_intr(void *); 108 static int sec_dmatc(struct sec_softc *sc); 109 110 void sec_dumpdma(void *arg); 111 112 CFATTACH_DECL(sec, sizeof(struct sec_softc), 113 sec_match, sec_attach, NULL, NULL); 114 115 static inline void 116 sec_setpage(struct sec_softc *sc, int page) 117 { 118 119 sc->sc_mpr = (sc->sc_mpr & ~SEC_MPR_PAGE) | page; 120 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 121 } 122 123 static inline void 124 sec_cli(struct sec_softc *sc) 125 { 126 127 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_CLRINT, 0); 128 } 129 130 static inline void 131 dmac_write(struct sec_softc *sc, int reg, uint8_t val) 132 { 133 134 bus_space_write_1(sc->sc_mod_t, sc->sc_mod_h, 135 SEC_DMAC + DMAC(reg), val); 136 } 137 138 static inline uint8_t 139 dmac_read(struct sec_softc *sc, int reg) 140 { 141 142 return bus_space_read_1(sc->sc_mod_t, sc->sc_mod_h, 143 SEC_DMAC + DMAC(reg)); 144 } 145 146 static int 147 sec_match(struct device *parent, struct cfdata *cf, void *aux) 148 { 149 struct podulebus_attach_args *pa = aux; 150 151 /* Standard ROM, skipping the MCS card that used the same ID. */ 152 if (pa->pa_product == PODULE_ACORN_SCSI && 153 strncmp(pa->pa_descr, "MCS", 3) != 0) 154 return 1; 155 156 /* PowerROM */ 157 if (pa->pa_product == PODULE_ALSYSTEMS_SCSI && 158 podulebus_initloader(pa) == 0 && 159 podloader_callloader(pa, 0, 0) == PRID_ACORN_SCSI1) 160 return 1; 161 162 return 0; 163 } 164 165 static void 166 sec_attach(struct device *parent, struct device *self, void *aux) 167 { 168 struct podulebus_attach_args *pa = aux; 169 struct sec_softc *sc = device_private(self); 170 int i; 171 172 /* Set up bus spaces */ 173 sc->sc_pod_t = pa->pa_fast_t; 174 bus_space_map(pa->pa_fast_t, pa->pa_fast_base, 0x1000, 0, 175 &sc->sc_pod_h); 176 sc->sc_mod_t = pa->pa_mod_t; 177 bus_space_map(pa->pa_mod_t, pa->pa_mod_base, 0x1000, 0, 178 &sc->sc_mod_h); 179 180 sc->sc_sbic.sc_regt = sc->sc_mod_t; 181 bus_space_subregion(sc->sc_mod_t, sc->sc_mod_h, SEC_SBIC, 182 0x1000 - SEC_SBIC, &sc->sc_sbic.sc_regh); 183 184 sc->sc_sbic.sc_id = 7; 185 sc->sc_sbic.sc_clkfreq = SEC_CLKFREQ; 186 sc->sc_sbic.sc_dmamode = SBIC_CTL_BURST_DMA; 187 188 sc->sc_sbic.sc_adapter.adapt_request = wd33c93_scsi_request; 189 sc->sc_sbic.sc_adapter.adapt_minphys = minphys; 190 191 sc->sc_sbic.sc_dmasetup = sec_dmasetup; 192 sc->sc_sbic.sc_dmago = sec_dmago; 193 sc->sc_sbic.sc_dmastop = sec_dmastop; 194 sc->sc_sbic.sc_reset = sec_reset; 195 196 sc->sc_mpr = 0; 197 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 198 199 for (i = 0; i < SEC_NPAGES; i++) { 200 sec_setpage(sc, i); 201 bus_space_set_region_2(sc->sc_mod_t, sc->sc_mod_h, 202 SEC_SRAM, 0, SEC_PAGESIZE / 2); 203 } 204 205 wd33c93_attach(&sc->sc_sbic); 206 207 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL, 208 device_xname(self), "intr"); 209 sc->sc_ih = podulebus_irq_establish(pa->pa_ih, IPL_BIO, sec_intr, 210 sc, &sc->sc_intrcnt); 211 sec_cli(sc); 212 sc->sc_mpr |= SEC_MPR_IE; 213 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 214 shutdownhook_establish(sec_shutdown, sc); 215 } 216 217 /* 218 * Before reboot, reset the page register to 0 so that RISC OS can see 219 * the podule ROM. 220 */ 221 static void 222 sec_shutdown(void *cookie) 223 { 224 struct sec_softc *sc = cookie; 225 226 sec_setpage(sc, 0); 227 } 228 229 static void 230 sec_copyin(struct sec_softc *sc, void *dest, int src, size_t size) 231 { 232 uint16_t tmp, *wptr; 233 int cnt, extra_byte; 234 235 KASSERT(src >= 0); 236 KASSERT(src + size <= SEC_MEMSIZE); 237 if (src % 2 != 0) { 238 /* 239 * There's a stray byte at the start. Read the word 240 * containing it. 241 */ 242 sec_setpage(sc, src / SEC_PAGESIZE); 243 tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 244 SEC_SRAM + (src % SEC_PAGESIZE / 2)); 245 *(uint8_t *)dest = tmp >> 8; 246 dest = ((uint8_t *)dest) + 1; 247 src++; size--; 248 } 249 KASSERT(src % 2 == 0); 250 KASSERT(ALIGNED_POINTER(dest, uint16_t)); 251 wptr = dest; 252 extra_byte = size % 2; 253 size -= extra_byte; 254 while (size > 0) { 255 cnt = SEC_PAGESIZE - src % SEC_PAGESIZE; 256 if (cnt > size) 257 cnt = size; 258 sec_setpage(sc, src / SEC_PAGESIZE); 259 /* bus ops are in words */ 260 bus_space_read_region_2(sc->sc_mod_t, sc->sc_mod_h, 261 SEC_SRAM + src % SEC_PAGESIZE / 2, wptr, cnt / 2); 262 src += cnt; 263 wptr += cnt / 2; 264 size -= cnt; 265 } 266 if (extra_byte) { 267 sec_setpage(sc, src / SEC_PAGESIZE); 268 *(u_int8_t *)wptr = 269 bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 270 SEC_SRAM + src % SEC_PAGESIZE / 2) & 0xff; 271 } 272 } 273 274 static void 275 sec_copyout(struct sec_softc *sc, const void *src, int dest, size_t size) 276 { 277 int cnt, extra_byte; 278 const uint16_t *wptr; 279 uint16_t tmp; 280 281 KASSERT(dest >= 0); 282 KASSERT(dest + size <= SEC_MEMSIZE); 283 if (dest % 2 != 0) { 284 /* 285 * There's a stray byte at the start. Read the word 286 * containing it. 287 */ 288 sec_setpage(sc, dest / SEC_PAGESIZE); 289 tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 290 SEC_SRAM + (dest % SEC_PAGESIZE / 2)); 291 tmp &= 0xff; 292 tmp |= *(uint8_t const *)src << 8; 293 bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h, 294 SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp); 295 src = ((uint8_t const *)src) + 1; 296 dest++; size--; 297 } 298 KASSERT(dest % 2 == 0); 299 KASSERT(ALIGNED_POINTER(src, uint16_t)); 300 wptr = src; 301 extra_byte = size % 2; 302 size -= extra_byte; 303 while (size > 0) { 304 cnt = SEC_PAGESIZE - dest % SEC_PAGESIZE; 305 if (cnt > size) 306 cnt = size; 307 sec_setpage(sc, dest / SEC_PAGESIZE); 308 /* bus ops are in words */ 309 bus_space_write_region_2(sc->sc_mod_t, sc->sc_mod_h, 310 dest % SEC_PAGESIZE / 2, wptr, cnt / 2); 311 wptr += cnt / 2; 312 dest += cnt; 313 size -= cnt; 314 } 315 if (extra_byte) { 316 /* 317 * There's a stray byte at the end. Read the word 318 * containing it. 319 */ 320 sec_setpage(sc, dest / SEC_PAGESIZE); 321 tmp = bus_space_read_2(sc->sc_mod_t, sc->sc_mod_h, 322 SEC_SRAM + (dest % SEC_PAGESIZE / 2)); 323 tmp &= 0xff00; 324 tmp |= *(uint8_t const *)wptr; 325 bus_space_write_2(sc->sc_mod_t, sc->sc_mod_h, 326 SEC_SRAM + (dest % SEC_PAGESIZE / 2), tmp); 327 } 328 } 329 330 static void 331 sec_dmablk(struct sec_softc *sc, int blk) 332 { 333 int off; 334 size_t len; 335 336 KASSERT(blk >= 0); 337 KASSERT(blk * SEC_DMABLK < sc->sc_dmalen); 338 off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff; 339 len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK)); 340 dmac_write(sc, NEC71071_ADDRLO, off & 0xff); 341 dmac_write(sc, NEC71071_ADDRMID, off >> 8); 342 dmac_write(sc, NEC71071_ADDRHI, 0); 343 /* 344 * "Note: The number of DMA transfer cycles is actually the 345 * value of the current count register + 1. Therefore, when 346 * programming the count register, specify the number of DMA 347 * transfers minus one." -- uPD71071 datasheet 348 */ 349 dmac_write(sc, NEC71071_COUNTLO, (len - 1) & 0xff); 350 dmac_write(sc, NEC71071_COUNTHI, (len - 1) >> 8); 351 } 352 353 static void 354 sec_copyoutblk(struct sec_softc *sc, int blk) 355 { 356 int off; 357 size_t len; 358 359 KASSERT(blk >= 0); 360 KASSERT(blk * SEC_DMABLK < sc->sc_dmalen); 361 KASSERT(!sc->sc_dmain); 362 off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff; 363 len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK)); 364 sec_copyout(sc, (char*)sc->sc_dmaaddr + (blk * SEC_DMABLK), off, len); 365 } 366 367 static void 368 sec_copyinblk(struct sec_softc *sc, int blk) 369 { 370 int off; 371 size_t len; 372 373 KASSERT(blk >= 0); 374 KASSERT(blk * SEC_DMABLK < sc->sc_dmalen); 375 KASSERT(sc->sc_dmain); 376 off = (blk % SEC_NBLKS) * SEC_DMABLK + sc->sc_dmaoff; 377 len = MIN(SEC_DMABLK, sc->sc_dmalen - (blk * SEC_DMABLK)); 378 sec_copyin(sc, (char*)sc->sc_dmaaddr + (blk * SEC_DMABLK), off, len); 379 } 380 381 static int 382 sec_dmasetup(struct wd33c93_softc *sc_sbic, void **addr, size_t *len, 383 int datain, size_t *dmasize) 384 { 385 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 386 uint8_t mode; 387 388 sc->sc_dmaaddr = *addr; 389 sc->sc_dmaoff = ALIGNED_POINTER(*addr, uint16_t) ? 0 : 1; 390 sc->sc_dmalen = *len; 391 sc->sc_dmain = datain; 392 sc->sc_dmablk = 0; 393 mode = SEC_DMAMODE | (datain ? MODE_TDIR_IOTM : MODE_TDIR_MTIO); 394 /* Program first block into DMAC and queue up second. */ 395 dmac_write(sc, NEC71071_CHANNEL, 0); 396 if (!sc->sc_dmain) 397 sec_copyoutblk(sc, 0); 398 sec_dmablk(sc, 0); 399 /* Mode control register */ 400 dmac_write(sc, NEC71071_MODE, mode); 401 return sc->sc_dmalen; 402 } 403 404 static int 405 sec_dmago(struct wd33c93_softc *sc_sbic) 406 { 407 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 408 409 dmac_write(sc, NEC71071_MASK, 0xe); 410 sc->sc_dmaactive = true; 411 if (!sc->sc_dmain && sc->sc_dmalen > SEC_DMABLK) 412 sec_copyoutblk(sc, 1); 413 return sc->sc_dmalen; 414 } 415 416 static void 417 sec_dmastop(struct wd33c93_softc *sc_sbic) 418 { 419 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 420 421 dmac_write(sc, NEC71071_MASK, 0xf); 422 if (sc->sc_dmaactive && sc->sc_dmain) 423 sec_copyinblk(sc, sc->sc_dmablk); 424 sc->sc_dmaactive = false; 425 } 426 427 /* 428 * Reset the SCSI bus, and incidentally the SBIC and DMAC. 429 */ 430 static void 431 sec_reset(struct wd33c93_softc *sc_sbic) 432 { 433 struct sec_softc *sc = (struct sec_softc *)sc_sbic; 434 uint8_t asr, csr; 435 436 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, 437 sc->sc_mpr | SEC_MPR_UR); 438 DELAY(7); 439 bus_space_write_1(sc->sc_pod_t, sc->sc_pod_h, SEC_MPR, sc->sc_mpr); 440 /* Wait for and clear the reset-complete interrupt */ 441 do 442 GET_SBIC_asr(sc_sbic, asr); 443 while (!(asr & SBIC_ASR_INT)); 444 GET_SBIC_csr(sc_sbic, csr); 445 dmac_write(sc, NEC71071_DCTRL1, DCTRL1_CMP | DCTRL1_RQL); 446 dmac_write(sc, NEC71071_DCTRL2, 0); 447 sec_cli(sc); 448 } 449 450 static int 451 sec_intr(void *arg) 452 { 453 struct sec_softc *sc = arg; 454 u_int8_t isr; 455 456 isr = bus_space_read_1(sc->sc_pod_t, sc->sc_pod_h, SEC_ISR); 457 if (!(isr & SEC_ISR_IRQ)) 458 return 0; 459 if (isr & SEC_ISR_DMAC) 460 sec_dmatc(sc); 461 if (isr & SEC_ISR_SBIC) 462 wd33c93_intr(&sc->sc_sbic); 463 return 1; 464 } 465 466 static int 467 sec_dmatc(struct sec_softc *sc) 468 { 469 470 sec_cli(sc); 471 /* DMAC finished block n-1 and is now working on block n */ 472 sc->sc_dmablk++; 473 if (sc->sc_dmalen > sc->sc_dmablk * SEC_DMABLK) { 474 dmac_write(sc, NEC71071_CHANNEL, 0); 475 sec_dmablk(sc, sc->sc_dmablk); 476 dmac_write(sc, NEC71071_MASK, 0xe); 477 if (!sc->sc_dmain && 478 sc->sc_dmalen > (sc->sc_dmablk + 1) * SEC_DMABLK) 479 sec_copyoutblk(sc, sc->sc_dmablk + 1); 480 } else { 481 /* All blocks fully processed. */ 482 sc->sc_dmaactive = false; 483 } 484 if (sc->sc_dmain) 485 sec_copyinblk(sc, sc->sc_dmablk - 1); 486 return 1; 487 } 488 489 #ifdef DDB 490 void 491 sec_dumpdma(void *arg) 492 { 493 struct sec_softc *sc = arg; 494 495 dmac_write(sc, NEC71071_CHANNEL, 0); 496 printf("%s: DMA state: cur count %02x%02x cur addr %02x%02x%02x ", 497 device_xname(&sc->sc_sbic.sc_dev), 498 dmac_read(sc, NEC71071_COUNTHI), dmac_read(sc, NEC71071_COUNTLO), 499 dmac_read(sc, NEC71071_ADDRHI), dmac_read(sc, NEC71071_ADDRMID), 500 dmac_read(sc, NEC71071_ADDRLO)); 501 dmac_write(sc, NEC71071_CHANNEL, 0 | CHANNEL_WBASE); 502 printf("base count %02x%02x base addr %02x%02x%02x\n", 503 dmac_read(sc, NEC71071_COUNTHI), dmac_read(sc, NEC71071_COUNTLO), 504 dmac_read(sc, NEC71071_ADDRHI), dmac_read(sc, NEC71071_ADDRMID), 505 dmac_read(sc, NEC71071_ADDRLO)); 506 printf("%s: DMA state: dctrl %1x%02x mode %02x status %02x req %02x " 507 "mask %02x\n", 508 device_xname(&sc->sc_sbic.sc_dev), dmac_read(sc, NEC71071_DCTRL2), 509 dmac_read(sc, NEC71071_DCTRL1), dmac_read(sc, NEC71071_MODE), 510 dmac_read(sc, NEC71071_STATUS), dmac_read(sc, NEC71071_REQUEST), 511 dmac_read(sc, NEC71071_MASK)); 512 printf("%s: soft DMA state: %zd@%p%s%d\n", device_xname(&sc->sc_sbic.sc_dev), 513 sc->sc_dmalen, sc->sc_dmaaddr, sc->sc_dmain ? "<-" : "->", 514 sc->sc_dmaoff); 515 } 516 517 void sec_dumpall(void); /* Call from DDB */ 518 519 extern struct cfdriver sec_cd; 520 521 void sec_dumpall(void) 522 { 523 int i; 524 525 for (i = 0; i < sec_cd.cd_ndevs; ++i) 526 if (sec_cd.cd_devs[i]) 527 sec_dumpdma(sec_cd.cd_devs[i]); 528 } 529 #endif 530