xref: /netbsd-src/sys/arch/sgimips/sgimips/bus.c (revision e5fbc36ada28f9b9a5836ecffaf4a06aa1ebb687)
1 /*	$NetBSD: bus.c,v 1.70 2023/12/20 15:29:07 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9  * NASA Ames Research Center.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: bus.c,v 1.70 2023/12/20 15:29:07 thorpej Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/endian.h>
39 #include <sys/bswap.h>
40 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <sys/proc.h>
43 #include <sys/mbuf.h>
44 
45 #define _MIPS_BUS_DMA_PRIVATE
46 
47 #include <sys/bus.h>
48 #include <machine/cpu.h>
49 #include <machine/machtype.h>
50 
51 #include <uvm/uvm_extern.h>
52 
53 #include <mips/cpuregs.h>
54 #include <mips/locore.h>
55 #include <mips/cache.h>
56 
57 #include <sgimips/mace/macereg.h>
58 
59 #include "opt_sgimace.h"
60 
61 struct mips_bus_dma_tag sgimips_default_bus_dma_tag = {
62 	._dmamap_ops = _BUS_DMAMAP_OPS_INITIALIZER,
63 	._dmamem_ops = _BUS_DMAMEM_OPS_INITIALIZER,
64 	._dmatag_ops = _BUS_DMATAG_OPS_INITIALIZER,
65 };
66 
67 static void normal_bus_mem_init(bus_space_tag_t, void *);
68 
69 static struct mips_bus_space	normal_mbst;
70 bus_space_tag_t	normal_memt = NULL;
71 
72 /*
73  * XXX
74  * I'm not sure how well the common MIPS bus_dma.c handles MIPS-I and I don't
75  * have any IP1x hardware, so I'll leave this in just in case it needs to be
76  * put back
77  */
78 
79 void
sgimips_bus_dma_init(void)80 sgimips_bus_dma_init(void)
81 {
82 	normal_bus_mem_init(&normal_mbst, NULL);
83 	normal_memt = &normal_mbst;
84 
85 #ifdef MIPS1
86 	switch (mach_type) {
87 	/* R2000/R3000 */
88 	case MACH_SGI_IP6 | MACH_SGI_IP10: /* same number... */
89 	case MACH_SGI_IP12:
90 		sgimips_default_bus_dma_tag._dmamap_ops.dmamap_sync =
91 		    _bus_dmamap_sync_mips1;
92 		break;
93 	}
94 #endif
95 }
96 
97 /*
98  * XXX
99  * left in for illustrative purposes
100  */
101 
102 #if 0
103 u_int8_t
104 bus_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t o)
105 {
106 	wbflush(); /* XXX ? */
107 
108 	switch (t) {
109 	case SGIMIPS_BUS_SPACE_NORMAL:
110 		return *(volatile u_int8_t *)(vaddr_t)(h + o);
111 	case SGIMIPS_BUS_SPACE_IP6_DPCLOCK:
112 		return *(volatile u_int8_t *)(vaddr_t)(h + (o << 2));
113 	case SGIMIPS_BUS_SPACE_HPC:
114 		return *(volatile u_int8_t *)(vaddr_t)(h + (o << 2) + 3);
115 	case SGIMIPS_BUS_SPACE_MEM:
116 	case SGIMIPS_BUS_SPACE_IO:
117 		return *(volatile u_int8_t *)(vaddr_t)(h + (o | 3) - (o & 3));
118 	case SGIMIPS_BUS_SPACE_MACE:
119 		return *(volatile u_int8_t *)(vaddr_t)(h + (o << 8) + 7);
120 	default:
121 		panic("no bus tag");
122 	}
123 }
124 #endif
125 
126 #ifdef MIPS1
127 /* Common function from DMA map synchronization. May be called
128  * by chipset-specific DMA map synchronization functions.
129  *
130  * This is the R3000 version.
131  */
132 void
_bus_dmamap_sync_mips1(bus_dma_tag_t t,bus_dmamap_t map,bus_addr_t offset,bus_size_t len,int ops)133 _bus_dmamap_sync_mips1(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset,
134 		       bus_size_t len, int ops)
135 {
136 	bus_size_t minlen;
137 	bus_addr_t addr;
138 	int i;
139 
140 	/*
141 	 * Mixing PRE and POST operations is not allowed.
142 	 */
143 	 if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 &&
144 	     (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0)
145 		 panic("_bus_dmamap_sync_mips1: mix PRE and POST");
146 
147 #ifdef DIAGNOSTIC
148 	if (offset >= map->dm_mapsize)
149 		panic("_bus_dmamap_sync_mips1: bad offset %"PRIxPSIZE
150 		" (map size is %"PRIxPSIZE")"
151 		    , offset, map->dm_mapsize);
152 	if (len == 0 || (offset + len) > map->dm_mapsize)
153 		panic("_bus_dmamap_sync_mips1: bad length");
154 #endif
155 
156 	/*
157 	 * The R3000 cache is write-through. Therefore, we only need
158 	 * to drain the write buffer on PREWRITE. The cache is not
159 	 * coherent, however, so we need to invalidate the data cache
160 	 * on PREREAD (should we do it POSTREAD instead?).
161 	 *
162 	 * POSTWRITE (and POSTREAD, currently) are noops.
163 	 */
164 
165 	if (ops & BUS_DMASYNC_PREWRITE) {
166 		/*
167 		 * Flush the write buffer.
168 		 */
169 		 wbflush();
170 	 }
171 
172 	/*
173 	 * If we're not doing PREREAD, nothing more to do.
174 	 */
175 	if ((ops & BUS_DMASYNC_PREREAD) == 0)
176 		return;
177 
178 	/*
179 	 * No cache invalidation is necessary if the DMA map covers
180 	 * COHERENT DMA-safe memory (which is mapped un-cached).
181 	 */
182 	if (map->_dm_flags & SGIMIPS_DMAMAP_COHERENT)
183 		return;
184 
185 	/*
186 	 * If we are going to hit something as large or larger
187 	 * than the entire data cache, just nail the whole thing.
188 	 *
189 	 * NOTE: Even though this is `wbinv_all', since the cache is
190 	 * write-through, it just invalidates it.
191 	 */
192 	if (len >= mips_cache_info.mci_pdcache_size) {
193 		mips_dcache_wbinv_all();
194 		return;
195 	}
196 
197 	for (i = 0; i < map->dm_nsegs && len != 0; i++) {
198 		/* Find the beginning segment. */
199 		if (offset >= map->dm_segs[i].ds_len) {
200 			offset -= map->dm_segs[i].ds_len;
201 			continue;
202 		}
203 
204 		/*
205 		 * Now at the first segment to sync; nail
206 		 * each segment until we have exhausted the
207 		 * length.
208 		 */
209 		minlen = len < map->dm_segs[i].ds_len - offset ?
210 		    len : map->dm_segs[i].ds_len - offset;
211 
212 		addr = map->dm_segs[i].ds_addr;
213 
214 #ifdef BUS_DMA_DEBUG
215 		printf("bus_dmamap_sync_mips1: flushing segment %d "
216 		    "(0x%"PRIxBUSADDR"..0x%"PRIxBUSADDR") ...", i,
217 		    addr + offset, addr + offset + minlen - 1);
218 #endif
219 		mips_dcache_inv_range(
220 		    MIPS_PHYS_TO_KSEG0(addr + offset), minlen);
221 #ifdef BUS_DMA_DEBUG
222 		printf("\n");
223 #endif
224 		offset = 0;
225 		len -= minlen;
226 	}
227 }
228 #endif
229 
230 #define CHIP	   		normal
231 #define	CHIP_MEM		/* defined */
232 #define	CHIP_W1_BUS_START(v)	0x00000000UL
233 #define CHIP_W1_BUS_END(v)	0xffffffffUL
234 #define	CHIP_W1_SYS_START(v)	0x00000000UL
235 #define	CHIP_W1_SYS_END(v)	0xffffffffUL
236 
237 #include <mips/mips/bus_space_alignstride_chipdep.c>
238