/* $NetBSD: asc_ioasic.c,v 1.2 1996/10/10 20:25:35 christos Exp $ */ /* * Copyright 1996 The Board of Trustees of The Leland Stanford * Junior University. All Rights Reserved. * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies. Stanford University * makes no representations about the suitability of this * software for any purpose. It is provided "as is" without * express or implied warranty. * */ #include #include #include #include #include #include #include /* XXX */ #include /* XXX */ #include /* XXX */ #include #include /* XXX XXX bus.h needs cache-consistency*/ /*XXX*/ #include /* XXX ioasic register defs? */ #include /* XXX ioasic register defs? */ #include extern int pmax_boardtype; /* * Autoconfiguration data for config. */ int asc_ioasic_match __P((struct device *, void *, void *)); void asc_ioasic_attach __P((struct device *, struct device *, void *)); struct cfattach asc_ioasic_ca = { sizeof(struct asc_softc), asc_ioasic_match, asc_ioasic_attach }; /* * DMA callback declarations */ extern u_long asc_iomem; static void asic_dma_start __P((asc_softc_t asc, State *state, caddr_t cp, int flag)); static void asic_dma_end __P((asc_softc_t asc, State *state, int flag)); int asc_ioasic_match(parent, match, aux) struct device *parent; void *match; void *aux; { struct ioasicdev_attach_args *d = aux; void *ascaddr; if (strncmp(d->iada_modname, "asc", TC_ROM_LLEN) && strncmp(d->iada_modname, "PMAZ-AA ", TC_ROM_LLEN)) return (0); /* probe for chip */ ascaddr = (void*)d->iada_addr; if (tc_badaddr(ascaddr + ASC_OFFSET_53C94)) return (0); return (1); } void asc_ioasic_attach(parent, self, aux) struct device *parent; struct device *self; void *aux; { register struct ioasicdev_attach_args *d = aux; register asc_softc_t asc = (asc_softc_t) self; int bufsiz, speed; void *ascaddr; int unit; ascaddr = (void*)MACH_PHYS_TO_UNCACHED(d->iada_addr); unit = asc->sc_dev.dv_unit; /* * Initialize hw descriptor, cache some pointers */ asc->regs = (asc_regmap_t *)(ascaddr + ASC_OFFSET_53C94); /* * Set up machine dependencies. * (1) how to do dma * (2) timing based on turbochannel frequency */ asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem); bufsiz = 8192; *((volatile int *)IOASIC_REG_SCSI_DMAPTR(ioasic_base)) = -1; *((volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base)) = -1; *((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0; asc->dma_start = asic_dma_start; asc->dma_end = asic_dma_end; /* * Now for timing. The 3max has a 25Mhz tb whereas the 3min and * maxine are 12.5Mhz. */ /*kprintf(" (bus speed: %d) ", t->ta_busspeed);*/ /* XXX don't these run at 25MHz on any ioasic??*/ switch (pmax_boardtype) { case DS_3MAX: case DS_3MAXPLUS: speed = ASC_SPEED_25_MHZ; break; case DS_3MIN: case DS_MAXINE: default: speed = ASC_SPEED_12_5_MHZ; break; }; ascattach(asc, bufsiz, speed); /* tie pseudo-slot to device */ ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_BIO, asc_intr, asc); } /* * DMA handling routines. For a turbochannel device, just set the dmar. * For the I/O ASIC, handle the actual DMA interface. */ static void asic_dma_start(asc, state, cp, flag) asc_softc_t asc; State *state; caddr_t cp; int flag; { register volatile u_int *ssr = (volatile u_int *) IOASIC_REG_CSR(ioasic_base); u_int phys, nphys; /* stop DMA engine first */ *ssr &= ~IOASIC_CSR_DMAEN_SCSI; *((volatile int *)IOASIC_REG_SCSI_SCR(ioasic_base)) = 0; phys = MACH_CACHED_TO_PHYS(cp); cp = (caddr_t)mips_trunc_page(cp + NBPG); nphys = MACH_CACHED_TO_PHYS(cp); asc->dma_next = cp; asc->dma_xfer = state->dmalen - (nphys - phys); *(volatile int *)IOASIC_REG_SCSI_DMAPTR(ioasic_base) = IOASIC_DMA_ADDR(phys); *(volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base) = IOASIC_DMA_ADDR(nphys); if (flag == ASCDMA_READ) *ssr |= IOASIC_CSR_SCSI_DIR | IOASIC_CSR_DMAEN_SCSI; else *ssr = (*ssr & ~IOASIC_CSR_SCSI_DIR) | IOASIC_CSR_DMAEN_SCSI; wbflush(); } static void asic_dma_end(asc, state, flag) asc_softc_t asc; State *state; int flag; { register volatile u_int *ssr = (volatile u_int *) IOASIC_REG_CSR(ioasic_base); register volatile u_int *dmap = (volatile u_int *) IOASIC_REG_SCSI_DMAPTR(ioasic_base); register u_short *to; register int w; int nb; *ssr &= ~IOASIC_CSR_DMAEN_SCSI; to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3); *dmap = -1; *((volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base)) = -1; wbflush(); if (flag == ASCDMA_READ) { MachFlushDCache(MACH_PHYS_TO_CACHED( MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen); if ( (nb = *((int *)IOASIC_REG_SCSI_SCR(ioasic_base))) != 0) { /* pick up last upto6 bytes, sigh. */ /* Last byte really xferred is.. */ w = *(int *)IOASIC_REG_SCSI_SDR0(ioasic_base); *to++ = w; if (--nb > 0) { w >>= 16; *to++ = w; } if (--nb > 0) { w = *(int *)IOASIC_REG_SCSI_SDR1(ioasic_base); *to++ = w; } } } } #ifdef notdef /* * Called by asic_intr() for scsi dma pointer update interrupts. */ void asc_dma_intr() { asc_softc_t asc = &asc_cd.cd_devs[0]; /*XXX*/ u_int next_phys; asc->dma_xfer -= NBPG; if (asc->dma_xfer <= -NBPG) { volatile u_int *ssr = (volatile u_int *) IOASIC_REG_CSR(ioasic_base); *ssr &= ~IOASIC_CSR_DMAEN_SCSI; } else { asc->dma_next += NBPG; next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); } *(volatile int *)IOASIC_REG_SCSI_DMANPTR(ioasic_base) = IOASIC_DMA_ADDR(next_phys); wbflush(); } #endif /*notdef*/