xref: /netbsd/sys/arch/hpcmips/hpcmips/bus_space.c (revision bf9ec67e)
1 /*	$NetBSD: bus_space.c,v 1.19 2002/05/04 05:13:28 takemura 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 			/* probe */
92 			__bs_peek,
93 			__bs_poke,
94 
95 			/* read (single) */
96 			__bs_r_1,
97 			__bs_r_2,
98 			__bs_r_4,
99 			bs_notimpl_bs_r_8,
100 
101 			/* read multiple */
102 			__bs_rm_1,
103 			__bs_rm_2,
104 			__bs_rm_4,
105 			bs_notimpl_bs_rm_8,
106 
107 			/* read region */
108 			__bs_rr_1,
109 			__bs_rr_2,
110 			__bs_rr_4,
111 			bs_notimpl_bs_rr_8,
112 
113 			/* write (single) */
114 			__bs_w_1,
115 			__bs_w_2,
116 			__bs_w_4,
117 			bs_notimpl_bs_w_8,
118 
119 			/* write multiple */
120 			__bs_wm_1,
121 			__bs_wm_2,
122 			__bs_wm_4,
123 			bs_notimpl_bs_wm_8,
124 
125 			/* write region */
126 			__bs_wr_1,
127 			__bs_wr_2,
128 			__bs_wr_4,
129 			bs_notimpl_bs_wr_8,
130 
131 			/* set multi */
132 			__bs_sm_1,
133 			__bs_sm_2,
134 			__bs_sm_4,
135 			bs_notimpl_bs_sm_8,
136 
137 			/* set region */
138 			__bs_sr_1,
139 			__bs_sr_2,
140 			__bs_sr_4,
141 			bs_notimpl_bs_sr_8,
142 
143 			/* copy */
144 			__bs_c_1,
145 			__bs_c_2,
146 			__bs_c_4,
147 			bs_notimpl_bs_c_8,
148 		},
149 	},
150 
151 	"whole bus space",	/* bus name */
152 	0,			/* extent base */
153 	0xffffffff,		/* extent size */
154 	NULL,			/* pointer for extent structure */
155 };
156 static bus_space_tag_t __sys_bus_space_tag = &__sys_bus_space.bst;
157 
158 bus_space_tag_t
159 hpcmips_system_bus_space()
160 {
161 
162 	return (__sys_bus_space_tag);
163 }
164 
165 struct bus_space_tag_hpcmips *
166 hpcmips_system_bus_space_hpcmips()
167 {
168 
169 	return (&__sys_bus_space);
170 }
171 
172 struct bus_space_tag_hpcmips *
173 hpcmips_alloc_bus_space_tag()
174 {
175 
176 	if (__bus_space_index >= MAX_BUSSPACE_TAG) {
177 		panic("hpcmips_internal_alloc_bus_space_tag: tag full.");
178 	}
179 
180 	return (&__bus_space[__bus_space_index++]);
181 }
182 
183 void
184 hpcmips_init_bus_space(struct bus_space_tag_hpcmips *t,
185     struct bus_space_tag_hpcmips *basetag,
186     char *name, u_int32_t base, u_int32_t size)
187 {
188 	u_int32_t pa, endpa;
189 	vaddr_t va;
190 
191 	if (basetag != NULL)
192 		memcpy(t, basetag, sizeof(struct bus_space_tag_hpcmips));
193 	strncpy(t->name, name, sizeof(t->name));
194 	t->name[sizeof(t->name) - 1] = '\0';
195 	t->base = base;
196 	t->size = size;
197 
198 	/*
199 	 * If request physical address is greater than 512MByte,
200 	 * mapping it to kseg2.
201 	 */
202 	if (t->base >= 0x20000000) {
203 		pa = mips_trunc_page(t->base);
204 		endpa = mips_round_page(t->base + t->size);
205 
206 		if (!(va = uvm_km_valloc(kernel_map, endpa - pa))) {
207 			panic("hpcmips_init_bus_space_extent:"
208 			    "can't allocate kernel virtual");
209 		}
210 		DPRINTF(("pa:0x%08x -> kv:0x%08x+0x%08x",
211 		    (unsigned int)t->base, (unsigned int)va, t->size));
212 		t->base = va; /* kseg2 addr */
213 
214 		for (; pa < endpa; pa += NBPG, va += NBPG) {
215 			pmap_kenter_pa(va, pa, VM_PROT_READ | VM_PROT_WRITE);
216 		}
217 		pmap_update(pmap_kernel());
218 	}
219 
220 	t->extent = (void*)extent_create(t->name, t->base,
221 	    t->base + t->size, M_DEVBUF,
222 	    0, 0, EX_NOWAIT);
223 	if (!t->extent) {
224 		panic("hpcmips_init_bus_space_extent:"
225 		    "unable to allocate %s map", t->name);
226 	}
227 }
228 
229 bus_space_handle_t
230 __hpcmips_cacheable(struct bus_space_tag_hpcmips *t, bus_addr_t bpa,
231     bus_size_t size, int cacheable)
232 {
233 	vaddr_t va, endva;
234 	pt_entry_t *pte;
235 	u_int32_t opte, npte;
236 
237 	if (t->base >= MIPS_KSEG2_START) {
238 		va = mips_trunc_page(bpa);
239 		endva = mips_round_page(bpa + size);
240 		npte = CPUISMIPS3 ? MIPS3_PG_UNCACHED : MIPS1_PG_N;
241 
242 		mips_dcache_wbinv_range(va, endva - va);
243 
244 		for (; va < endva; va += NBPG) {
245 			pte = kvtopte(va);
246 			opte = pte->pt_entry;
247 			if (cacheable) {
248 				opte &= ~npte;
249 			} else {
250 				opte |= npte;
251 			}
252 			pte->pt_entry = opte;
253 			/*
254 			 * Update the same virtual address entry.
255 			 */
256 			MachTLBUpdate(va, opte);
257 		}
258 		return (bpa);
259 	}
260 
261 	return (cacheable ? MIPS_PHYS_TO_KSEG0(bpa) : MIPS_PHYS_TO_KSEG1(bpa));
262 }
263 
264 /* ARGSUSED */
265 int
266 __bs_map(bus_space_tag_t tx, bus_addr_t bpa, bus_size_t size, int flags,
267     bus_space_handle_t *bshp)
268 {
269 	struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx;
270 	int err;
271 	int cacheable = flags & BUS_SPACE_MAP_CACHEABLE;
272 
273 	DPRINTF(("\tbus_space_map:%#lx(%#lx)+%#lx\n",
274 	    bpa, bpa + t->base, size));
275 
276 	if (!t->extent) { /* Before autoconfiguration, can't use extent */
277 		DPRINTF(("bus_space_map: map temporary region:"
278 		    "0x%08lx-0x%08lx\n", bpa, bpa+size));
279 		bpa += t->base;
280 	} else {
281 		bpa += t->base;
282 		if ((err = extent_alloc_region(t->extent, bpa, size,
283 		    EX_NOWAIT|EX_MALLOCOK))) {
284 			DPRINTF(("\tbus_space_map: "
285 			    "extent_alloc_regiion() failed\n"));
286 			return (err);
287 		}
288 	}
289 	*bshp = __hpcmips_cacheable(t, bpa, size, cacheable);
290 
291 	return (0);
292 }
293 
294 /* ARGSUSED */
295 void
296 __bs_unmap(bus_space_tag_t tx, bus_space_handle_t bsh, bus_size_t size)
297 {
298 	struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx;
299 	int err;
300 	u_int32_t addr;
301 
302 	if (!t->extent) {
303 		return; /* Before autoconfiguration, can't use extent */
304 	}
305 
306 	if (t->base < MIPS_KSEG2_START) {
307 		addr = MIPS_KSEG1_TO_PHYS(bsh);
308 	} else {
309 		addr = bsh;
310 	}
311 
312 	if ((err = extent_free(t->extent, addr, size, EX_NOWAIT))) {
313 		DPRINTF(("warning: %#lx-%#lx of %s space lost\n",
314 		    bsh, bsh+size, t->name));
315 	}
316 }
317 
318 /* ARGSUSED */
319 int
320 __bs_subregion(bus_space_tag_t t, bus_space_handle_t bsh,
321     bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp)
322 {
323 
324 	*nbshp = bsh + offset;
325 
326 	return (0);
327 }
328 
329 /* ARGSUSED */
330 int
331 __bs_alloc(bus_space_tag_t tx, bus_addr_t rstart, bus_addr_t rend,
332     bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags,
333     bus_addr_t *bpap, bus_space_handle_t *bshp)
334 {
335 	struct bus_space_tag_hpcmips *t = (struct bus_space_tag_hpcmips *)tx;
336 	int cacheable = flags & BUS_SPACE_MAP_CACHEABLE;
337 	u_long bpa;
338 	int err;
339 
340 	if (!t->extent)
341 		panic("bus_space_alloc: no extent");
342 
343 	DPRINTF(("\tbus_space_alloc:%#lx(%#lx)+%#lx\n", bpa,
344 	    bpa - t->base, size));
345 
346 	rstart += t->base;
347 	rend += t->base;
348 	if ((err = extent_alloc_subregion(t->extent, rstart, rend, size,
349 	    alignment, boundary, EX_FAST|EX_NOWAIT|EX_MALLOCOK, &bpa))) {
350 		return (err);
351 	}
352 
353 	*bshp = __hpcmips_cacheable(t, bpa, size, cacheable);
354 
355 	if (bpap) {
356 		*bpap = bpa;
357 	}
358 
359 	return (0);
360 }
361 
362 /* ARGSUSED */
363 void
364 __bs_free(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t size)
365 {
366 	/* bus_space_unmap() does all that we need to do. */
367 	bus_space_unmap(t, bsh, size);
368 }
369 
370 void
371 __bs_barrier(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
372     bus_size_t len, int flags)
373 {
374 	wbflush();
375 }
376 
377 int
378 __bs_peek(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
379     size_t size, void *ptr)
380 {
381 	u_int32_t tmp;
382 
383 	if (badaddr((void *)(bsh + offset), size))
384 		return (-1);
385 
386 	if (ptr == NULL)
387 		ptr = &tmp;
388 
389 	switch(size) {
390 	case 1:
391 		*((u_int8_t *)ptr) = bus_space_read_1(t, bsh, offset);
392 		break;
393 	case 2:
394 		*((u_int16_t *)ptr) = bus_space_read_2(t, bsh, offset);
395 		break;
396 	case 4:
397 		*((u_int32_t *)ptr) = bus_space_read_4(t, bsh, offset);
398 		break;
399 	default:
400 		panic("bus_space_peek: bad size, %d\n", size);
401 	}
402 
403 	return (0);
404 }
405 
406 int
407 __bs_poke(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
408     size_t size, u_int32_t val)
409 {
410 
411 	if (badaddr((void *)(bsh + offset), size))
412 		return (-1);
413 
414 	switch(size) {
415 	case 1:
416 		bus_space_write_1(t, bsh, offset, val);
417 		break;
418 	case 2:
419 		bus_space_write_2(t, bsh, offset, val);
420 		break;
421 	case 4:
422 		bus_space_write_4(t, bsh, offset, val);
423 		break;
424 	default:
425 		panic("bus_space_poke: bad size, %d\n", size);
426 	}
427 
428 	return (0);
429 }
430 
431 u_int8_t
432 __bs_r_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
433 {
434 	wbflush();
435 	return (*(volatile u_int8_t *)(bsh + offset));
436 }
437 
438 u_int16_t
439 __bs_r_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
440 {
441 	wbflush();
442 	return (*(volatile u_int16_t *)(bsh + offset));
443 }
444 
445 u_int32_t
446 __bs_r_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset)
447 {
448 	wbflush();
449 	return (*(volatile u_int32_t *)(bsh + offset));
450 }
451 
452 void
453 __bs_rm_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
454     u_int8_t *addr, bus_size_t count) {
455 	while (count--)
456 		*addr++ = bus_space_read_1(t, bsh, offset);
457 }
458 
459 void
460 __bs_rm_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
461     u_int16_t *addr, bus_size_t count)
462 {
463 	while (count--)
464 		*addr++ = bus_space_read_2(t, bsh, offset);
465 }
466 
467 void
468 __bs_rm_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
469     u_int32_t *addr, bus_size_t count)
470 {
471 	while (count--)
472 		*addr++ = bus_space_read_4(t, bsh, offset);
473 }
474 
475 void
476 __bs_rr_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
477     u_int8_t *addr, bus_size_t count)
478 {
479 	while (count--) {
480 		*addr++ = bus_space_read_1(t, bsh, offset);
481 		offset += sizeof(*addr);
482 	}
483 }
484 
485 void
486 __bs_rr_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
487     u_int16_t *addr, bus_size_t count)
488 {
489 	while (count--) {
490 		*addr++ = bus_space_read_2(t, bsh, offset);
491 		offset += sizeof(*addr);
492 	}
493 }
494 
495 void
496 __bs_rr_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
497     u_int32_t *addr, bus_size_t count)
498 {
499 	while (count--) {
500 		*addr++ = bus_space_read_4(t, bsh, offset);
501 		offset += sizeof(*addr);
502 	}
503 }
504 
505 void
506 __bs_w_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
507     u_int8_t value)
508 {
509 	*(volatile u_int8_t *)(bsh + offset) = value;
510 	wbflush();
511 }
512 
513 void
514 __bs_w_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
515     u_int16_t value)
516 {
517 	*(volatile u_int16_t *)(bsh + offset) = value;
518 	wbflush();
519 }
520 
521 void
522 __bs_w_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
523     u_int32_t value)
524 {
525 	*(volatile u_int32_t *)(bsh + offset) = value;
526 	wbflush();
527 }
528 
529 void
530 __bs_wm_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
531     const u_int8_t *addr, bus_size_t count)
532 {
533 	while (count--)
534 		bus_space_write_1(t, bsh, offset, *addr++);
535 }
536 
537 void
538 __bs_wm_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
539     const u_int16_t *addr, bus_size_t count)
540 {
541 	while (count--)
542 		bus_space_write_2(t, bsh, offset, *addr++);
543 }
544 
545 void
546 __bs_wm_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
547     const u_int32_t *addr, bus_size_t count)
548 {
549 	while (count--)
550 		bus_space_write_4(t, bsh, offset, *addr++);
551 }
552 
553 void
554 __bs_wr_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
555     const u_int8_t *addr, bus_size_t count)
556 {
557 	while (count--) {
558 		bus_space_write_1(t, bsh, offset, *addr++);
559 		offset += sizeof(*addr);
560 	}
561 }
562 
563 void
564 __bs_wr_2(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
565     const u_int16_t *addr, bus_size_t count)
566 {
567 	while (count--) {
568 		bus_space_write_2(t, bsh, offset, *addr++);
569 		offset += sizeof(*addr);
570 	}
571 }
572 
573 void
574 __bs_wr_4(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset,
575     const u_int32_t *addr, bus_size_t count)
576 {
577 	while (count--) {
578 		bus_space_write_4(t, bsh, offset, *addr++);
579 		offset += sizeof(*addr);
580 	}
581 }
582 
583 void
584 __bs_sm_1(bus_space_tag_t t, bus_space_handle_t bsh,
585     bus_size_t offset, u_int8_t value, bus_size_t count)
586 {
587 	while (count--)
588 		bus_space_write_1(t, bsh, offset, value);
589 }
590 
591 void
592 __bs_sm_2(bus_space_tag_t t, bus_space_handle_t bsh,
593     bus_size_t offset, u_int16_t value, bus_size_t count)
594 {
595 	while (count--)
596 		bus_space_write_2(t, bsh, offset, value);
597 }
598 
599 void
600 __bs_sm_4(bus_space_tag_t t, bus_space_handle_t bsh,
601     bus_size_t offset, u_int32_t value, bus_size_t count)
602 {
603 	while (count--)
604 		bus_space_write_4(t, bsh, offset, value);
605 }
606 
607 
608 void
609 __bs_sr_1(bus_space_tag_t t, bus_space_handle_t bsh,
610     bus_size_t offset, u_int8_t value, bus_size_t count)
611 {
612 	while (count--) {
613 		bus_space_write_1(t, bsh, offset, value);
614 		offset += (value);
615 	}
616 }
617 
618 void
619 __bs_sr_2(bus_space_tag_t t, bus_space_handle_t bsh,
620     bus_size_t offset, u_int16_t value, bus_size_t count)
621 {
622 	while (count--) {
623 		bus_space_write_2(t, bsh, offset, value);
624 		offset += (value);
625 	}
626 }
627 
628 void
629 __bs_sr_4(bus_space_tag_t t, bus_space_handle_t bsh,
630     bus_size_t offset, u_int32_t value, bus_size_t count)
631 {
632 	while (count--) {
633 		bus_space_write_4(t, bsh, offset, value);
634 		offset += (value);
635 	}
636 }
637 
638 #define __bs_c_n(n)							\
639 void __CONCAT(__bs_c_,n)(bus_space_tag_t t, bus_space_handle_t h1,	\
640     bus_size_t o1, bus_space_handle_t h2, bus_size_t o2, bus_size_t c)	\
641 {									\
642 	bus_size_t o;							\
643 									\
644 	if ((h1 + o1) >= (h2 + o2)) {					\
645 		/* src after dest: copy forward */			\
646 		for (o = 0; c != 0; c--, o += n)			\
647 			__CONCAT(bus_space_write_,n)(t, h2, o2 + o,	\
648 			    __CONCAT(bus_space_read_,n)(t, h1, o1 + o));\
649 	} else {							\
650 		/* dest after src: copy backwards */			\
651 		for (o = (c - 1) * n; c != 0; c--, o -= n)		\
652 			__CONCAT(bus_space_write_,n)(t, h2, o2 + o,	\
653 			    __CONCAT(bus_space_read_,n)(t, h1, o1 + o));\
654 	}								\
655 }
656 
657 __bs_c_n(1)
658 __bs_c_n(2)
659 __bs_c_n(4)
660