xref: /netbsd-src/sys/arch/hpcmips/hpcmips/bus_space.c (revision b519c70ad771d0a55b3c2277db6b97a05fa6465d)
1 /*	$NetBSD: bus_space.c,v 1.17 2001/12/02 10:37:53 uch 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  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the NetBSD
22  *	Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/extent.h>
44 
45 #include <uvm/uvm_extern.h>
46 
47 #include <mips/cache.h>
48 #include <mips/pte.h>
49 #include <machine/bus.h>
50 #include <machine/bus_space_hpcmips.h>
51 
52 #ifdef BUS_SPACE_DEBUG
53 #define	DPRINTF(arg) printf arg
54 #else
55 #define	DPRINTF(arg)
56 #endif
57 
58 #define MAX_BUSSPACE_TAG 10
59 
60 /* proto types */
61 bus_space_handle_t __hpcmips_cacheable(struct bus_space_tag_hpcmips*,
62     bus_addr_t, bus_size_t, int);
63 bus_space_protos(_);
64 bus_space_protos(bs_notimpl);
65 
66 /* variables */
67 static  struct bus_space_tag_hpcmips __bus_space[MAX_BUSSPACE_TAG];
68 static int __bus_space_index;
69 static struct bus_space_tag_hpcmips __sys_bus_space = {
70 	{
71 		NULL,
72 		{
73 			/* mapping/unmapping */
74 			__bs_map,
75 			__bs_unmap,
76 			__bs_subregion,
77 
78 			/* allocation/deallocation */
79 			__bs_alloc,
80 			__bs_free,
81 
82 			/* get kernel virtual address */
83 			bs_notimpl_bs_vaddr, /* there is no linear mapping */
84 
85 			/* Mmap bus space for user */
86 			bs_notimpl_bs_mmap,
87 
88 			/* barrier */
89 			__bs_barrier,
90 
91 			/* read (single) */
92 			__bs_r_1,
93 			__bs_r_2,
94 			__bs_r_4,
95 			bs_notimpl_bs_r_8,
96 
97 			/* read multiple */
98 			__bs_rm_1,
99 			__bs_rm_2,
100 			__bs_rm_4,
101 			bs_notimpl_bs_rm_8,
102 
103 			/* read region */
104 			__bs_rr_1,
105 			__bs_rr_2,
106 			__bs_rr_4,
107 			bs_notimpl_bs_rr_8,
108 
109 			/* write (single) */
110 			__bs_w_1,
111 			__bs_w_2,
112 			__bs_w_4,
113 			bs_notimpl_bs_w_8,
114 
115 			/* write multiple */
116 			__bs_wm_1,
117 			__bs_wm_2,
118 			__bs_wm_4,
119 			bs_notimpl_bs_wm_8,
120 
121 			/* write region */
122 			__bs_wr_1,
123 			__bs_wr_2,
124 			__bs_wr_4,
125 			bs_notimpl_bs_wr_8,
126 
127 			/* set multi */
128 			__bs_sm_1,
129 			__bs_sm_2,
130 			__bs_sm_4,
131 			bs_notimpl_bs_sm_8,
132 
133 			/* set region */
134 			__bs_sr_1,
135 			__bs_sr_2,
136 			__bs_sr_4,
137 			bs_notimpl_bs_sr_8,
138 
139 			/* copy */
140 			__bs_c_1,
141 			__bs_c_2,
142 			__bs_c_4,
143 			bs_notimpl_bs_c_8,
144 		},
145 	},
146 
147 	"whole bus space",	/* bus name */
148 	0,			/* extent base */
149 	0xffffffff,		/* extent size */
150 	NULL,			/* pointer for extent structure */
151 };
152 static bus_space_tag_t __sys_bus_space_tag = &__sys_bus_space.bst;
153 
154 bus_space_tag_t
155 hpcmips_system_bus_space()
156 {
157 
158 	return (__sys_bus_space_tag);
159 }
160 
161 struct bus_space_tag_hpcmips *
162 hpcmips_system_bus_space_hpcmips()
163 {
164 
165 	return (&__sys_bus_space);
166 }
167 
168 struct bus_space_tag_hpcmips *
169 hpcmips_alloc_bus_space_tag()
170 {
171 
172 	if (__bus_space_index >= MAX_BUSSPACE_TAG) {
173 		panic("hpcmips_internal_alloc_bus_space_tag: tag full.");
174 	}
175 
176 	return (&__bus_space[__bus_space_index++]);
177 }
178 
179 void
180 hpcmips_init_bus_space(struct bus_space_tag_hpcmips *t,
181     struct bus_space_tag_hpcmips *basetag,
182     char *name, u_int32_t base, u_int32_t size)
183 {
184 	u_int32_t pa, endpa;
185 	vaddr_t va;
186 
187 	if (basetag != NULL)
188 		memcpy(t, basetag, sizeof(struct bus_space_tag_hpcmips));
189 	strncpy(t->name, name, sizeof(t->name));
190 	t->name[sizeof(t->name) - 1] = '\0';
191 	t->base = base;
192 	t->size = size;
193 
194 	/*
195 	 * If request physical address is greater than 512MByte,
196 	 * mapping it to kseg2.
197 	 */
198 	if (t->base >= 0x20000000) {
199 		pa = mips_trunc_page(t->base);
200 		endpa = mips_round_page(t->base + t->size);
201 
202 		if (!(va = uvm_km_valloc(kernel_map, endpa - pa))) {
203 			panic("hpcmips_init_bus_space_extent:"
204 			    "can't allocate kernel virtual");
205 		}
206 		DPRINTF(("pa:0x%08x -> kv:0x%08x+0x%08x",
207 		    (unsigned int)t->base, (unsigned int)va, t->size));
208 		t->base = va; /* kseg2 addr */
209 
210 		for (; pa < endpa; pa += NBPG, va += NBPG) {
211 			pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
212 		}
213 		pmap_update(pmap_kernel());
214 	}
215 
216 	t->extent = (void*)extent_create(t->name, t->base,
217 	    t->base + t->size, M_DEVBUF,
218 	    0, 0, EX_NOWAIT);
219 	if (!t->extent) {
220 		panic("hpcmips_init_bus_space_extent:"
221 		    "unable to allocate %s map", t->name);
222 	}
223 }
224 
225 bus_space_handle_t
226 __hpcmips_cacheable(struct bus_space_tag_hpcmips *t, bus_addr_t bpa,
227     bus_size_t size, int cacheable)
228 {
229 	vaddr_t va, endva;
230 	pt_entry_t *pte;
231 	u_int32_t opte, npte;
232 
233 	if (t->base >= MIPS_KSEG2_START) {
234 		va = mips_trunc_page(bpa);
235 		endva = mips_round_page(bpa + size);
236 		npte = CPUISMIPS3 ? MIPS3_PG_UNCACHED : MIPS1_PG_N;
237 
238 		mips_dcache_wbinv_range(va, endva - va);
239 
240 		for (; va < endva; va += NBPG) {
241 			pte = kvtopte(va);
242 			opte = pte->pt_entry;
243 			if (cacheable) {
244 				opte &= ~npte;
245 			} else {
246 				opte |= npte;
247 			}
248 			pte->pt_entry = opte;
249 			/*
250 			 * Update the same virtual address entry.
251 			 */
252 			MachTLBUpdate(va, opte);
253 		}
254 		return (bpa);
255 	}
256 
257 	return (cacheable ? MIPS_PHYS_TO_KSEG0(bpa) : MIPS_PHYS_TO_KSEG1(bpa));
258 }
259 
260 /* ARGSUSED */
261 int
262 __bs_map(bus_space_tag_t tx, bus_addr_t bpa, bus_size_t size, int flags,
263     bus_space_handle_t *bshp)
264 {
265 	struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx;
266 	int err;
267 	int cacheable = flags & BUS_SPACE_MAP_CACHEABLE;
268 
269 	if (!t->extent) { /* Before autoconfiguration, can't use extent */
270 		DPRINTF(("bus_space_map: map temporary region:"
271 		    "0x%08x-0x%08x\n", bpa, bpa+size));
272 		bpa += t->base;
273 	} else {
274 		bpa += t->base;
275 		if ((err = extent_alloc_region(t->extent, bpa, size,
276 		    EX_NOWAIT|EX_MALLOCOK))) {
277 			return (err);
278 		}
279 	}
280 	*bshp = __hpcmips_cacheable(t, bpa, size, cacheable);
281 
282 	DPRINTF(("\tbus_space_map:%#x(%#x)+%#x\n",
283 	    bpa, bpa - t->base, size));
284 
285 	return (0);
286 }
287 
288 /* ARGSUSED */
289 void
290 __bs_unmap(bus_space_tag_t tx, bus_space_handle_t bsh, bus_size_t size)
291 {
292 	struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx;
293 	int err;
294 	u_int32_t addr;
295 
296 	if (!t->extent) {
297 		return; /* Before autoconfiguration, can't use extent */
298 	}
299 
300 	if (t->base < MIPS_KSEG2_START) {
301 		addr = MIPS_KSEG1_TO_PHYS(bsh);
302 	} else {
303 		addr = bsh;
304 	}
305 
306 	if ((err = extent_free(t->extent, addr, size, EX_NOWAIT))) {
307 		DPRINTF(("warning: %#x-%#x of %s space lost\n",
308 		    bsh, bsh+size, t->name));
309 	}
310 }
311 
312 /* ARGSUSED */
313 int
314 __bs_subregion(bus_space_tag_t t, bus_space_handle_t bsh,
315     bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
316 {
317 
318 	*nbshp = bsh + offset;
319 
320 	return (0);
321 }
322 
323 /* ARGSUSED */
324 int
325 __bs_alloc(bus_space_tag_t tx, bus_addr_t rstart, bus_addr_t rend,
326     bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags,
327     bus_addr_t *bpap, bus_space_handle_t *bshp)
328 {
329 	struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx;
330 	int cacheable = flags & BUS_SPACE_MAP_CACHEABLE;
331 	u_long bpa;
332 	int err;
333 
334 	if (!t->extent)
335 		panic("bus_space_alloc: no extent");
336 
337 	rstart += t->base;
338 	rend += t->base;
339 	if ((err = extent_alloc_subregion(t->extent, rstart, rend, size,
340 	    alignment, boundary, EX_FAST|EX_NOWAIT|EX_MALLOCOK, &bpa))) {
341 		return (err);
342 	}
343 
344 	*bshp = __hpcmips_cacheable(t, bpa, size, cacheable);
345 
346 	if (bpap) {
347 		*bpap = bpa;
348 	}
349 
350 	DPRINTF(("\tbus_space_alloc:%#x(%#x)+%#x\n", (unsigned)bpa,
351 	    (unsigned)(bpa - t->base), size));
352 
353 	return (0);
354 }
355 
356 /* ARGSUSED */
357 void
358 __bs_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
359 {
360 	/* bus_space_unmap() does all that we need to do. */
361 	bus_space_unmap(t, bsh, size);
362 }
363 
364 void
365 __bs_barrier(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
366     bus_size_t len, int flags)
367 {
368 	wbflush();
369 }
370 
371 u_int8_t
372 __bs_r_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
373 {
374 	wbflush();
375 	return (*(volatile u_int8_t *)(bsh + offset));
376 }
377 
378 u_int16_t
379 __bs_r_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
380 {
381 	wbflush();
382 	return (*(volatile u_int16_t *)(bsh + offset));
383 }
384 
385 u_int32_t
386 __bs_r_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
387 {
388 	wbflush();
389 	return (*(volatile u_int32_t *)(bsh + offset));
390 }
391 
392 void
393 __bs_rm_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
394     u_int8_t *addr, bus_size_t count) {
395 	while (count--)
396 		*addr++ = bus_space_read_1(t, bsh, offset);
397 }
398 
399 void
400 __bs_rm_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
401     u_int16_t *addr, bus_size_t count)
402 {
403 	while (count--)
404 		*addr++ = bus_space_read_2(t, bsh, offset);
405 }
406 
407 void
408 __bs_rm_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
409     u_int32_t *addr, bus_size_t count)
410 {
411 	while (count--)
412 		*addr++ = bus_space_read_4(t, bsh, offset);
413 }
414 
415 void
416 __bs_rr_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
417     u_int8_t *addr, bus_size_t count)
418 {
419 	while (count--) {
420 		*addr++ = bus_space_read_1(t, bsh, offset);
421 		offset += sizeof(*addr);
422 	}
423 }
424 
425 void
426 __bs_rr_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
427     u_int16_t *addr, bus_size_t count)
428 {
429 	while (count--) {
430 		*addr++ = bus_space_read_2(t, bsh, offset);
431 		offset += sizeof(*addr);
432 	}
433 }
434 
435 void
436 __bs_rr_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
437     u_int32_t *addr, bus_size_t count)
438 {
439 	while (count--) {
440 		*addr++ = bus_space_read_4(t, bsh, offset);
441 		offset += sizeof(*addr);
442 	}
443 }
444 
445 void
446 __bs_w_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
447     u_int8_t value)
448 {
449 	*(volatile u_int8_t *)(bsh + offset) = value;
450 	wbflush();
451 }
452 
453 void
454 __bs_w_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
455     u_int16_t value)
456 {
457 	*(volatile u_int16_t *)(bsh + offset) = value;
458 	wbflush();
459 }
460 
461 void
462 __bs_w_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
463     u_int32_t value)
464 {
465 	*(volatile u_int32_t *)(bsh + offset) = value;
466 	wbflush();
467 }
468 
469 void
470 __bs_wm_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
471     const u_int8_t *addr, bus_size_t count)
472 {
473 	while (count--)
474 		bus_space_write_1(t, bsh, offset, *addr++);
475 }
476 
477 void
478 __bs_wm_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
479     const u_int16_t *addr, bus_size_t count)
480 {
481 	while (count--)
482 		bus_space_write_2(t, bsh, offset, *addr++);
483 }
484 
485 void
486 __bs_wm_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
487     const u_int32_t *addr, bus_size_t count)
488 {
489 	while (count--)
490 		bus_space_write_4(t, bsh, offset, *addr++);
491 }
492 
493 void
494 __bs_wr_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
495     const u_int8_t *addr, bus_size_t count)
496 {
497 	while (count--) {
498 		bus_space_write_1(t, bsh, offset, *addr++);
499 		offset += sizeof(*addr);
500 	}
501 }
502 
503 void
504 __bs_wr_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
505     const u_int16_t *addr, bus_size_t count)
506 {
507 	while (count--) {
508 		bus_space_write_2(t, bsh, offset, *addr++);
509 		offset += sizeof(*addr);
510 	}
511 }
512 
513 void
514 __bs_wr_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
515     const u_int32_t *addr, bus_size_t count)
516 {
517 	while (count--) {
518 		bus_space_write_4(t, bsh, offset, *addr++);
519 		offset += sizeof(*addr);
520 	}
521 }
522 
523 void
524 __bs_sm_1(bus_space_tag_t t, bus_space_handle_t bsh,
525     bus_size_t offset, u_int8_t value, bus_size_t count)
526 {
527 	while (count--)
528 		bus_space_write_1(t, bsh, offset, value);
529 }
530 
531 void
532 __bs_sm_2(bus_space_tag_t t, bus_space_handle_t bsh,
533     bus_size_t offset, u_int16_t value, bus_size_t count)
534 {
535 	while (count--)
536 		bus_space_write_2(t, bsh, offset, value);
537 }
538 
539 void
540 __bs_sm_4(bus_space_tag_t t, bus_space_handle_t bsh,
541     bus_size_t offset, u_int32_t value, bus_size_t count)
542 {
543 	while (count--)
544 		bus_space_write_4(t, bsh, offset, value);
545 }
546 
547 
548 void
549 __bs_sr_1(bus_space_tag_t t, bus_space_handle_t bsh,
550     bus_size_t offset, u_int8_t value, bus_size_t count)
551 {
552 	while (count--) {
553 		bus_space_write_1(t, bsh, offset, value);
554 		offset += (value);
555 	}
556 }
557 
558 void
559 __bs_sr_2(bus_space_tag_t t, bus_space_handle_t bsh,
560     bus_size_t offset, u_int16_t value, bus_size_t count)
561 {
562 	while (count--) {
563 		bus_space_write_2(t, bsh, offset, value);
564 		offset += (value);
565 	}
566 }
567 
568 void
569 __bs_sr_4(bus_space_tag_t t, bus_space_handle_t bsh,
570     bus_size_t offset, u_int32_t value, bus_size_t count)
571 {
572 	while (count--) {
573 		bus_space_write_4(t, bsh, offset, value);
574 		offset += (value);
575 	}
576 }
577 
578 #define __bs_c_n(n)							\
579 void __CONCAT(__bs_c_,n)(bus_space_tag_t t, bus_space_handle_t h1,	\
580     bus_size_t o1, bus_space_handle_t h2, bus_size_t o2, bus_size_t c)	\
581 {									\
582 	bus_size_t o;							\
583 									\
584 	if ((h1 + o1) >= (h2 + o2)) {					\
585 		/* src after dest: copy forward */			\
586 		for (o = 0; c != 0; c--, o += n)			\
587 			__CONCAT(bus_space_write_,n)(t, h2, o2 + o,	\
588 			    __CONCAT(bus_space_read_,n)(t, h1, o1 + o));\
589 	} else {							\
590 		/* dest after src: copy backwards */			\
591 		for (o = (c - 1) * n; c != 0; c--, o -= n)		\
592 			__CONCAT(bus_space_write_,n)(t, h2, o2 + o,	\
593 			    __CONCAT(bus_space_read_,n)(t, h1, o1 + o));\
594 	}								\
595 }
596 
597 __bs_c_n(1)
598 __bs_c_n(2)
599 __bs_c_n(4)
600