/* $NetBSD: bus.c,v 1.69 2016/11/16 19:39:38 macallan Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.69 2016/11/16 19:39:38 macallan Exp $"); #include #include #include #include #include #include #include #include #include #define _MIPS_BUS_DMA_PRIVATE #include #include #include #include #include #include #include #include #include "opt_sgimace.h" struct mips_bus_dma_tag sgimips_default_bus_dma_tag = { ._dmamap_ops = _BUS_DMAMAP_OPS_INITIALIZER, ._dmamem_ops = _BUS_DMAMEM_OPS_INITIALIZER, ._dmatag_ops = _BUS_DMATAG_OPS_INITIALIZER, }; static void normal_bus_mem_init(bus_space_tag_t, void *); static struct mips_bus_space normal_mbst; bus_space_tag_t normal_memt = NULL; /* * XXX * I'm not sure how well the common MIPS bus_dma.c handles MIPS-I and I don't * have any IP1x hardware, so I'll leave this in just in case it needs to be * put back */ void sgimips_bus_dma_init(void) { normal_bus_mem_init(&normal_mbst, NULL); normal_memt = &normal_mbst; #ifdef MIPS1 switch (mach_type) { /* R2000/R3000 */ case MACH_SGI_IP6 | MACH_SGI_IP10: /* same number... */ case MACH_SGI_IP12: sgimips_default_bus_dma_tag._dmamap_ops.dmamap_sync = _bus_dmamap_sync_mips1; break; } #endif } /* * XXX * left in for illustrative purposes */ #if 0 u_int8_t bus_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o) { wbflush(); /* XXX ? */ switch (t) { case SGIMIPS_BUS_SPACE_NORMAL: return *(volatile u_int8_t *)(vaddr_t)(h + o); case SGIMIPS_BUS_SPACE_IP6_DPCLOCK: return *(volatile u_int8_t *)(vaddr_t)(h + (o << 2)); case SGIMIPS_BUS_SPACE_HPC: return *(volatile u_int8_t *)(vaddr_t)(h + (o << 2) + 3); case SGIMIPS_BUS_SPACE_MEM: case SGIMIPS_BUS_SPACE_IO: return *(volatile u_int8_t *)(vaddr_t)(h + (o | 3) - (o & 3)); case SGIMIPS_BUS_SPACE_MACE: return *(volatile u_int8_t *)(vaddr_t)(h + (o << 8) + 7); default: panic("no bus tag"); } } #endif #ifdef MIPS1 /* Common function from DMA map synchronization. May be called * by chipset-specific DMA map synchronization functions. * * This is the R3000 version. */ void _bus_dmamap_sync_mips1(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, bus_size_t len, int ops) { bus_size_t minlen; bus_addr_t addr; int i; /* * Mixing PRE and POST operations is not allowed. */ if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 && (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0) panic("_bus_dmamap_sync_mips1: mix PRE and POST"); #ifdef DIAGNOSTIC if (offset >= map->dm_mapsize) panic("_bus_dmamap_sync_mips1: bad offset %"PRIxPSIZE " (map size is %"PRIxPSIZE")" , offset, map->dm_mapsize); if (len == 0 || (offset + len) > map->dm_mapsize) panic("_bus_dmamap_sync_mips1: bad length"); #endif /* * The R3000 cache is write-through. Therefore, we only need * to drain the write buffer on PREWRITE. The cache is not * coherent, however, so we need to invalidate the data cache * on PREREAD (should we do it POSTREAD instead?). * * POSTWRITE (and POSTREAD, currently) are noops. */ if (ops & BUS_DMASYNC_PREWRITE) { /* * Flush the write buffer. */ wbflush(); } /* * If we're not doing PREREAD, nothing more to do. */ if ((ops & BUS_DMASYNC_PREREAD) == 0) return; /* * No cache invalidation is necessary if the DMA map covers * COHERENT DMA-safe memory (which is mapped un-cached). */ if (map->_dm_flags & SGIMIPS_DMAMAP_COHERENT) return; /* * If we are going to hit something as large or larger * than the entire data cache, just nail the whole thing. * * NOTE: Even though this is `wbinv_all', since the cache is * write-through, it just invalidates it. */ if (len >= mips_cache_info.mci_pdcache_size) { mips_dcache_wbinv_all(); return; } for (i = 0; i < map->dm_nsegs && len != 0; i++) { /* Find the beginning segment. */ if (offset >= map->dm_segs[i].ds_len) { offset -= map->dm_segs[i].ds_len; continue; } /* * Now at the first segment to sync; nail * each segment until we have exhausted the * length. */ minlen = len < map->dm_segs[i].ds_len - offset ? len : map->dm_segs[i].ds_len - offset; addr = map->dm_segs[i].ds_addr; #ifdef BUS_DMA_DEBUG printf("bus_dmamap_sync_mips1: flushing segment %d " "(0x%"PRIxBUSADDR"..0x%"PRIxBUSADDR") ...", i, addr + offset, addr + offset + minlen - 1); #endif mips_dcache_inv_range( MIPS_PHYS_TO_KSEG0(addr + offset), minlen); #ifdef BUS_DMA_DEBUG printf("\n"); #endif offset = 0; len -= minlen; } } #endif #define CHIP normal #define CHIP_MEM /* defined */ #define CHIP_W1_BUS_START(v) 0x00000000UL #define CHIP_W1_BUS_END(v) 0xffffffffUL #define CHIP_W1_SYS_START(v) 0x00000000UL #define CHIP_W1_SYS_END(v) 0xffffffffUL #include