1116810Sharti/*- 2116810Sharti * Copyright (c) 1991 The Regents of the University of California. 3116810Sharti * All rights reserved. 4116810Sharti * 5116810Sharti * This code is derived from software contributed to Berkeley by 6116810Sharti * William Jolitz. 7116810Sharti * 8116810Sharti * Redistribution and use in source and binary forms, with or without 9116810Sharti * modification, are permitted provided that the following conditions 10116810Sharti * are met: 11116810Sharti * 1. Redistributions of source code must retain the above copyright 12116810Sharti * notice, this list of conditions and the following disclaimer. 13116810Sharti * 2. Redistributions in binary form must reproduce the above copyright 14116810Sharti * notice, this list of conditions and the following disclaimer in the 15116810Sharti * documentation and/or other materials provided with the distribution. 16116810Sharti * 4. Neither the name of the University nor the names of its contributors 17116810Sharti * may be used to endorse or promote products derived from this software 18116810Sharti * without specific prior written permission. 19116810Sharti * 20116810Sharti * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21116810Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22116810Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23116810Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24116810Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25116810Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26116810Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27131861Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28116810Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29116810Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30116810Sharti * SUCH DAMAGE. 31116810Sharti * 32116810Sharti * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 33242475Sglebius */ 34123943Sru 35131681Sru#include <sys/cdefs.h> 36116810Sharti__FBSDID("$FreeBSD$"); 37116810Sharti 38116810Sharti/* 39116810Sharti * code to manage AT bus 40141350Sru * 41131861Sru * 92/08/18 Frank P. MacLachlan (fpm@crash.cts.com): 42141350Sru * Fixed uninitialized variable problem and added code to deal 43141350Sru * with DMA page boundaries in isa_dmarangecheck(). Fixed word 44131726Sru * mode DMA count compution and reorganized DMA setup code in 45116810Sharti * isa_dmastart() 46131861Sru */ 47116810Sharti 48116810Sharti#include "opt_pc98.h" 49131530Sru 50116810Sharti#include <sys/param.h> 51116810Sharti#include <sys/systm.h> 52116810Sharti#include <sys/bus.h> 53116810Sharti#include <sys/kernel.h> 54131861Sru#include <sys/malloc.h> 55116810Sharti#include <sys/lock.h> 56131530Sru#include <sys/proc.h> 57131530Sru#include <sys/mutex.h> 58131530Sru#include <sys/module.h> 59131861Sru#include <machine/md_var.h> 60116810Sharti#include <vm/vm.h> 61116810Sharti#include <vm/vm_param.h> 62116810Sharti#include <vm/pmap.h> 63116810Sharti#include <isa/isavar.h> 64131861Sru#include <pc98/cbus/cbus.h> 65131861Sru#include <pc98/cbus/cbus_dmareg.h> 66131530Sru 67131530Srustatic int isa_dmarangecheck(caddr_t va, u_int length, int chan); 68131861Sru 69131861Srustatic caddr_t dma_bouncebuf[4]; 70116810Shartistatic u_int dma_bouncebufsize[4]; 71116810Shartistatic u_int8_t dma_bounced = 0; 72131530Srustatic u_int8_t dma_busy = 0; /* Used in isa_dmastart() */ 73131530Srustatic u_int8_t dma_inuse = 0; /* User for acquire/release */ 74116810Shartistatic u_int8_t dma_auto_mode = 0; 75116810Shartistatic struct mtx isa_dma_lock; 76131530SruMTX_SYSINIT(isa_dma_lock, &isa_dma_lock, "isa DMA lock", MTX_DEF); 77131530Sru 78116810Sharti#define VALID_DMA_MASK (3) 79116810Sharti 80116810Sharti/* high byte of address is stored in this port for i-th dma channel */ 81131861Srustatic int dmapageport[4] = { 0x27, 0x21, 0x23, 0x25 }; 82116810Sharti 83116810Sharti/* 84116810Sharti * Setup a DMA channel's bounce buffer. 85131861Sru */ 86131861Sruint 87116810Shartiisa_dma_init(int chan, u_int bouncebufsize, int flag) 88116810Sharti{ 89131530Sru void *buf; 90131861Sru 91131530Sru#ifdef DIAGNOSTIC 92116810Sharti if (chan & ~VALID_DMA_MASK) 93116810Sharti panic("isa_dma_init: channel out of range"); 94131861Sru if (dma_bouncebuf[chan] != NULL) 95116810Sharti panic("isa_dma_init: impossible request"); 96116810Sharti#endif 97131861Sru 98116810Sharti 99116810Sharti /* Try malloc() first. It works better if it works. */ 100116810Sharti buf = malloc(bouncebufsize, M_DEVBUF, flag); 101131861Sru if (buf != NULL) { 102116810Sharti if (isa_dmarangecheck(buf, bouncebufsize, chan) != 0) { 103116810Sharti free(buf, M_DEVBUF); 104130857Smpp buf = NULL; 105116810Sharti } 106116810Sharti } 107131861Sru 108116810Sharti if (buf == NULL) { 109116810Sharti buf = contigmalloc(bouncebufsize, M_DEVBUF, flag, 0ul, 0xfffffful, 110116810Sharti 1ul, chan & 4 ? 0x20000ul : 0x10000ul); 111131861Sru } 112131530Sru 113116810Sharti if (buf == NULL) 114116810Sharti return (ENOMEM); 115116810Sharti 116116810Sharti mtx_lock(&isa_dma_lock); 117116810Sharti 118116810Sharti dma_bouncebufsize[chan] = bouncebufsize; 119116810Sharti dma_bouncebuf[chan] = buf; 120116810Sharti 121131530Sru mtx_unlock(&isa_dma_lock); 122131530Sru 123116810Sharti return (0); 124116810Sharti} 125131861Sru 126116810Sharti/* 127116810Sharti * Register a DMA channel's usage. Usually called from a device driver 128131861Sru * in open() or during its initialization. 129116810Sharti */ 130116810Shartiint 131116810Shartiisa_dma_acquire(chan) 132131861Sru int chan; 133131861Sru{ 134116810Sharti#ifdef DIAGNOSTIC 135116810Sharti if (chan & ~VALID_DMA_MASK) 136116810Sharti panic("isa_dma_acquire: channel out of range"); 137116810Sharti#endif 138131530Sru 139116810Sharti mtx_lock(&isa_dma_lock); 140116810Sharti if (dma_inuse & (1 << chan)) { 141211355Sbrueffer printf("isa_dma_acquire: channel %d already in use\n", chan); 142116810Sharti mtx_unlock(&isa_dma_lock); 143116810Sharti return (EBUSY); 144131530Sru } 145131530Sru dma_inuse |= (1 << chan); 146116810Sharti dma_auto_mode &= ~(1 << chan); 147116810Sharti mtx_unlock(&isa_dma_lock); 148131530Sru 149131861Sru return (0); 150116810Sharti} 151116810Sharti 152116810Sharti/* 153131861Sru * Unregister a DMA channel's usage. Usually called from a device driver 154242475Sglebius * during close() or during its shutdown. 155131861Sru */ 156131861Sruvoid 157131861Sruisa_dma_release(chan) 158116810Sharti int chan; 159242475Sglebius{ 160116810Sharti#ifdef DIAGNOSTIC 161116810Sharti if (chan & ~VALID_DMA_MASK) 162242475Sglebius panic("isa_dma_release: channel out of range"); 163116810Sharti 164242475Sglebius mtx_lock(&isa_dma_lock); 165242475Sglebius if ((dma_inuse & (1 << chan)) == 0) 166116810Sharti printf("isa_dma_release: channel %d not in use\n", chan); 167116810Sharti#else 168116810Sharti mtx_lock(&isa_dma_lock); 169116810Sharti#endif 170242475Sglebius 171131530Sru if (dma_busy & (1 << chan)) { 172131530Sru dma_busy &= ~(1 << chan); 173131861Sru /* 174116810Sharti * XXX We should also do "dma_bounced &= (1 << chan);" 175116810Sharti * because we are acting on behalf of isa_dmadone() which 176116810Sharti * was not called to end the last DMA operation. This does 177116810Sharti * not matter now, but it may in the future. 178116810Sharti */ 179116810Sharti } 180116810Sharti 181116810Sharti dma_inuse &= ~(1 << chan); 182116810Sharti dma_auto_mode &= ~(1 << chan); 183116810Sharti 184116810Sharti mtx_unlock(&isa_dma_lock); 185116810Sharti} 186116810Sharti 187116810Sharti/* 188116810Sharti * isa_dmastart(): program 8237 DMA controller channel, avoid page alignment 189116810Sharti * problems by using a bounce buffer. 190116810Sharti */ 191116810Shartivoid 192116810Shartiisa_dmastart(int flags, caddr_t addr, u_int nbytes, int chan) 193242475Sglebius{ 194116810Sharti vm_paddr_t phys; 195116810Sharti int waport; 196116810Sharti caddr_t newaddr; 197116810Sharti int dma_range_checked; 198116810Sharti 199116810Sharti /* translate to physical */ 200116810Sharti phys = pmap_extract(kernel_pmap, (vm_offset_t)addr); 201116810Sharti dma_range_checked = isa_dmarangecheck(addr, nbytes, chan); 202116810Sharti 203116810Sharti#ifdef DIAGNOSTIC 204116810Sharti if (chan & ~VALID_DMA_MASK) 205131861Sru panic("isa_dmastart: channel out of range"); 206116810Sharti 207131530Sru if ((chan < 4 && nbytes > (1<<16)) 208131530Sru || (chan >= 4 && (nbytes > (1<<17) || (u_int)addr & 1))) 209131530Sru panic("isa_dmastart: impossible request"); 210131530Sru 211131861Sru mtx_lock(&isa_dma_lock); 212116810Sharti if ((dma_inuse & (1 << chan)) == 0) 213131861Sru printf("isa_dmastart: channel %d not acquired\n", chan); 214131861Sru#else 215131861Sru mtx_lock(&isa_dma_lock); 216131861Sru#endif 217131861Sru 218131861Sru#if 0 219131861Sru /* 220131861Sru * XXX This should be checked, but drivers like ad1848 only call 221131861Sru * isa_dmastart() once because they use Auto DMA mode. If we 222131861Sru * leave this in, drivers that do this will print this continuously. 223131861Sru */ 224131861Sru if (dma_busy & (1 << chan)) 225131861Sru printf("isa_dmastart: channel %d busy\n", chan); 226131861Sru#endif 227131861Sru 228131861Sru dma_busy |= (1 << chan); 229116810Sharti 230116810Sharti if (dma_range_checked) { 231116810Sharti if (dma_bouncebuf[chan] == NULL 232116810Sharti || dma_bouncebufsize[chan] < nbytes) 233116810Sharti panic("isa_dmastart: bad bounce buffer"); 234131861Sru dma_bounced |= (1 << chan); 235116810Sharti newaddr = dma_bouncebuf[chan]; 236131861Sru 237116810Sharti /* copy bounce buffer on write */ 238116810Sharti if (!(flags & ISADMA_READ)) 239131861Sru bcopy(addr, newaddr, nbytes); 240131861Sru addr = newaddr; 241131861Sru } 242116810Sharti 243131861Sru if (flags & ISADMA_RAW) { 244131861Sru dma_auto_mode |= (1 << chan); 245131861Sru } else { 246131861Sru dma_auto_mode &= ~(1 << chan); 247131861Sru } 248131861Sru 249131861Sru if (need_pre_dma_flush) 250131861Sru wbinvd(); /* wbinvd (WB cache flush) */ 251131861Sru 252131861Sru /* set dma channel mode, and reset address ff */ 253116810Sharti 254116810Sharti /* If ISADMA_RAW flag is set, then use autoinitialise mode */ 255131861Sru if (flags & ISADMA_RAW) { 256131861Sru if (flags & ISADMA_READ) 257131861Sru outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_WRITE|chan); 258116810Sharti else 259116810Sharti outb(DMA1_MODE, DMA37MD_AUTO|DMA37MD_READ|chan); 260131861Sru } else { 261131861Sru if (flags & ISADMA_READ) 262116810Sharti outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_WRITE|chan); 263116810Sharti else 264116810Sharti outb(DMA1_MODE, DMA37MD_SINGLE|DMA37MD_READ|chan); 265116810Sharti } 266116810Sharti outb(DMA1_FFC, 0); 267242475Sglebius 268131530Sru /* send start address */ 269131530Sru waport = DMA1_CHN(chan); 270116810Sharti outb(waport, phys); 271242475Sglebius outb(waport, phys>>8); 272122758Sharti outb(dmapageport[chan], phys>>16); 273242475Sglebius 274116810Sharti /* send count */ 275116810Sharti outb(waport + 2, --nbytes); 276116810Sharti outb(waport + 2, nbytes>>8); 277116810Sharti 278242475Sglebius /* unmask channel */ 279242475Sglebius outb(DMA1_SMSK, chan); 280116810Sharti 281242475Sglebius mtx_unlock(&isa_dma_lock); 282242475Sglebius} 283242475Sglebius 284116810Shartivoid 285116810Shartiisa_dmadone(int flags, caddr_t addr, int nbytes, int chan) 286116810Sharti{ 287116810Sharti 288116810Sharti if (flags & ISADMA_READ) { 289116810Sharti /* cache flush only after reading 92/12/9 by A.Kojima */ 290116810Sharti if (need_post_dma_flush) 291116810Sharti invd(); 292116810Sharti } 293116810Sharti 294116810Sharti#ifdef DIAGNOSTIC 295131861Sru if (chan & ~VALID_DMA_MASK) 296131861Sru panic("isa_dmadone: channel out of range"); 297131861Sru 298116810Sharti if ((dma_inuse & (1 << chan)) == 0) 299116810Sharti printf("isa_dmadone: channel %d not acquired\n", chan); 300131861Sru#endif 301131861Sru 302116810Sharti mtx_lock(&isa_dma_lock); 303131861Sru if (((dma_busy & (1 << chan)) == 0) && 304131861Sru (dma_auto_mode & (1 << chan)) == 0 ) 305131530Sru printf("isa_dmadone: channel %d not busy\n", chan); 306131530Sru 307131530Sru if ((dma_auto_mode & (1 << chan)) == 0) 308131861Sru outb(DMA1_SMSK, (chan & 3) | 4); 309116810Sharti 310131861Sru if (dma_bounced & (1 << chan)) { 311116810Sharti /* copy bounce buffer on read */ 312131861Sru if (flags & ISADMA_READ) 313116810Sharti bcopy(dma_bouncebuf[chan], addr, nbytes); 314131861Sru 315131861Sru dma_bounced &= ~(1 << chan); 316131861Sru } 317116810Sharti dma_busy &= ~(1 << chan); 318116810Sharti mtx_unlock(&isa_dma_lock); 319242475Sglebius} 320131530Sru 321131530Sru/* 322116810Sharti * Check for problems with the address range of a DMA transfer 323242475Sglebius * (non-contiguous physical pages, outside of bus address space, 324122758Sharti * crossing DMA page boundaries). 325116810Sharti * Return true if special handling needed. 326116810Sharti */ 327242475Sglebius 328301589Straszstatic int 329301589Straszisa_dmarangecheck(caddr_t va, u_int length, int chan) 330242475Sglebius{ 331242475Sglebius vm_paddr_t phys, priorpage = 0; 332242475Sglebius vm_offset_t endva; 333242475Sglebius u_int dma_pgmsk = (chan & 4) ? ~(128*1024-1) : ~(64*1024-1); 334242475Sglebius 335242475Sglebius endva = (vm_offset_t)round_page((vm_offset_t)va + length); 336242475Sglebius for (; va < (caddr_t) endva ; va += PAGE_SIZE) { 337242475Sglebius phys = trunc_page(pmap_extract(kernel_pmap, (vm_offset_t)va)); 338119986Snaddy#ifdef EPSON_BOUNCEDMA 339116810Sharti#define ISARAM_END 0x0f00000 340116810Sharti#else 341131861Sru#define ISARAM_END 0x1000000 342131861Sru#endif 343131530Sru if (phys == 0) 344116810Sharti panic("isa_dmacheck: no physical page present"); 345116810Sharti if (phys >= ISARAM_END) 346131861Sru return (1); 347242475Sglebius if (priorpage) { 348131530Sru if (priorpage + PAGE_SIZE != phys) 349131530Sru return (1); 350131861Sru /* check if crossing a DMA page boundary */ 351131530Sru if (((u_int)priorpage ^ (u_int)phys) & dma_pgmsk) 352131530Sru return (1); 353116810Sharti } 354242475Sglebius priorpage = phys; 355116810Sharti } 356116810Sharti return (0); 357116810Sharti} 358116810Sharti 359116810Sharti/* 360116810Sharti * Query the progress of a transfer on a DMA channel. 361116810Sharti * 362131861Sru * To avoid having to interrupt a transfer in progress, we sample 363131861Sru * each of the high and low databytes twice, and apply the following 364116810Sharti * logic to determine the correct count. 365116810Sharti * 366131861Sru * Reads are performed with interrupts disabled, thus it is to be 367131530Sru * expected that the time between reads is very small. At most 368131530Sru * one rollover in the low count byte can be expected within the 369131861Sru * four reads that are performed. 370116810Sharti * 371131861Sru * There are three gaps in which a rollover can occur : 372116810Sharti * 373131861Sru * - read low1 374131861Sru * gap1 375131861Sru * - read high1 376131530Sru * gap2 377131530Sru * - read low2 378116810Sharti * gap3 379131530Sru * - read high2 380131861Sru * 381116810Sharti * If a rollover occurs in gap1 or gap2, the low2 value will be 382116810Sharti * greater than the low1 value. In this case, low2 and high2 are a 383116810Sharti * corresponding pair. 384116810Sharti * 385116810Sharti * In any other case, low1 and high1 can be considered to be correct. 386131861Sru * 387131530Sru * The function returns the number of bytes remaining in the transfer, 388131861Sru * or -1 if the channel requested is not active. 389131861Sru * 390131861Sru */ 391131861Srustatic int 392116810Shartiisa_dmastatus_locked(int chan) 393116810Sharti{ 394116810Sharti u_long cnt = 0; 395116810Sharti int ffport, waport; 396131861Sru u_long low1, high1, low2, high2; 397131861Sru 398131861Sru mtx_assert(&isa_dma_lock, MA_OWNED); 399116810Sharti 400116810Sharti /* channel active? */ 401131594Sru if ((dma_inuse & (1 << chan)) == 0) { 402116810Sharti printf("isa_dmastatus: channel %d not active\n", chan); 403116810Sharti return(-1); 404116810Sharti } 405116810Sharti /* channel busy? */ 406267938Sbapt 407 if (((dma_busy & (1 << chan)) == 0) && 408 (dma_auto_mode & (1 << chan)) == 0 ) { 409 printf("chan %d not busy\n", chan); 410 return -2 ; 411 } 412 ffport = DMA1_FFC; 413 waport = DMA1_CHN(chan) + 2; 414 415 disable_intr(); /* no interrupts Mr Jones! */ 416 outb(ffport, 0); /* clear register LSB flipflop */ 417 low1 = inb(waport); 418 high1 = inb(waport); 419 outb(ffport, 0); /* clear again */ 420 low2 = inb(waport); 421 high2 = inb(waport); 422 enable_intr(); /* enable interrupts again */ 423 424 /* 425 * Now decide if a wrap has tried to skew our results. 426 * Note that after TC, the count will read 0xffff, while we want 427 * to return zero, so we add and then mask to compensate. 428 */ 429 if (low1 >= low2) { 430 cnt = (low1 + (high1 << 8) + 1) & 0xffff; 431 } else { 432 cnt = (low2 + (high2 << 8) + 1) & 0xffff; 433 } 434 435 if (chan >= 4) /* high channels move words */ 436 cnt *= 2; 437 return(cnt); 438} 439 440int 441isa_dmastatus(int chan) 442{ 443 int status; 444 445 mtx_lock(&isa_dma_lock); 446 status = isa_dmastatus_locked(chan); 447 mtx_unlock(&isa_dma_lock); 448 449 return (status); 450} 451 452/* 453 * Reached terminal count yet ? 454 */ 455int 456isa_dmatc(int chan) 457{ 458 459 return(inb(DMA1_STATUS) & (1 << chan)); 460} 461 462/* 463 * Stop a DMA transfer currently in progress. 464 */ 465int 466isa_dmastop(int chan) 467{ 468 int status; 469 470 mtx_lock(&isa_dma_lock); 471 if ((dma_inuse & (1 << chan)) == 0) 472 printf("isa_dmastop: channel %d not acquired\n", chan); 473 474 if (((dma_busy & (1 << chan)) == 0) && 475 ((dma_auto_mode & (1 << chan)) == 0)) { 476 printf("chan %d not busy\n", chan); 477 mtx_unlock(&isa_dma_lock); 478 return -2 ; 479 } 480 481 if ((chan & 4) == 0) 482 outb(DMA1_SMSK, (chan & 3) | 4 /* disable mask */); 483 484 status = isa_dmastatus_locked(chan); 485 486 mtx_unlock(&isa_dma_lock); 487 488 return (status); 489} 490 491/* 492 * Attach to the ISA PnP descriptor for the AT DMA controller 493 */ 494static struct isa_pnp_id atdma_ids[] = { 495 { 0x0002d041 /* PNP0200 */, "AT DMA controller" }, 496 { 0 } 497}; 498 499static int 500atdma_probe(device_t dev) 501{ 502 int result; 503 504 if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, atdma_ids)) <= 0) 505 device_quiet(dev); 506 return(result); 507} 508 509static int 510atdma_attach(device_t dev) 511{ 512 return(0); 513} 514 515static device_method_t atdma_methods[] = { 516 /* Device interface */ 517 DEVMETHOD(device_probe, atdma_probe), 518 DEVMETHOD(device_attach, atdma_attach), 519 DEVMETHOD(device_detach, bus_generic_detach), 520 DEVMETHOD(device_shutdown, bus_generic_shutdown), 521 DEVMETHOD(device_suspend, bus_generic_suspend), 522 DEVMETHOD(device_resume, bus_generic_resume), 523 { 0, 0 } 524}; 525 526static driver_t atdma_driver = { 527 "atdma", 528 atdma_methods, 529 1, /* no softc */ 530}; 531 532static devclass_t atdma_devclass; 533 534DRIVER_MODULE(atdma, isa, atdma_driver, atdma_devclass, 0, 0); 535