xref: /netbsd-src/sys/arch/sun3/sun3/obio.c (revision ae9172d6cd9432a6a1a56760d86b32c57a66c39c)
1 /*	$NetBSD: obio.c,v 1.14 1994/12/12 18:59:22 gwr Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Gordon W. Ross
5  * Copyright (c) 1993 Adam Glass
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by Adam Glass and Gordon Ross.
19  * 4. The name of the authors may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 
38 #include <machine/autoconf.h>
39 #include <machine/pte.h>
40 #include <machine/mon.h>
41 #include <machine/isr.h>
42 #include <machine/obio.h>
43 
44 static void obio_attach __P((struct device *, struct device *, void *));
45 static void obio_scan __P((struct device *, void *));
46 
47 struct cfdriver obiocd = {
48 	NULL, "obio", always_match, obio_attach, DV_DULL,
49 	sizeof(struct device), 0 };
50 
51 static void
52 obio_attach(parent, self, args)
53 	struct device *parent;
54 	struct device *self;
55 	void *args;
56 {
57 	printf("\n");
58 	config_scan(obio_scan, self);
59 }
60 
61 static void
62 obio_scan(parent, child)
63 	struct device *parent;
64 	void *child;
65 {
66 	bus_scan(parent, child, BUS_OBIO);
67 }
68 
69 /*
70  * Spacing of "interesting" OBIO mappings.  We will
71  * record only those with an OBIO address that is a
72  * multiple of SAVE_INCR and below SAVE_LAST.
73  * The saved mappings are just one page each, which
74  * is good enough for all the devices that use this.
75  */
76 #define SAVE_SHIFT 17
77 #define SAVE_INCR (1<<SAVE_SHIFT)
78 #define SAVE_MASK (SAVE_INCR-1)
79 #define SAVE_SLOTS  16
80 #define SAVE_LAST (SAVE_SLOTS * SAVE_INCR)
81 
82 /*
83  * This is our record of "interesting" OBIO mappings that
84  * the PROM has left in the virtual space reserved for it.
85  * Each non-null array element holds the virtual address
86  * of an OBIO mapping where the OBIO address mapped is:
87  *     (array_index * SAVE_INCR)
88  * and the length of the mapping is one page.
89  */
90 static caddr_t prom_mappings[SAVE_SLOTS];
91 
92 caddr_t obio_find_mapping(int pa, int size)
93 {
94 	if ((size <= NBPG) &&
95 		(pa < SAVE_LAST) &&
96 		((pa & SAVE_MASK) == 0))
97 	{
98 		return prom_mappings[pa >> SAVE_SHIFT];
99 	}
100 	return (caddr_t)0;
101 }
102 
103 /*
104  * This defines the permission bits to put in our PTEs.
105  * Device space is never cached, and the PROM appears to
106  * leave off the "no-cache" bit, so we can do the same.
107  */
108 #define PGBITS (PG_VALID|PG_WRITE|PG_SYSTEM)
109 
110 static void save_prom_mappings()
111 {
112 	vm_offset_t pa;
113 	caddr_t segva, pgva;
114 	int pte, sme, i;
115 
116 	segva = (caddr_t)MONSTART;
117 	while (segva < (caddr_t)MONEND) {
118 		sme = get_segmap(segva);
119 		if (sme == SEGINV) {
120 			segva += NBSG;
121 			continue;			/* next segment */
122 		}
123 		/*
124 		 * We have a valid segmap entry, so examine the
125 		 * PTEs for all the pages in this segment.
126 		 */
127 		pgva = segva;	/* starting page */
128 		segva += NBSG;	/* ending page (next seg) */
129 		while (pgva < segva) {
130 			pte = get_pte(pgva);
131 			if ((pte & (PG_VALID | PG_TYPE)) ==
132 				(PG_VALID | PGT_OBIO))
133 			{
134 				/* Have a valid OBIO mapping. */
135 				pa = PG_PA(pte);
136 				/* Is it one we want to record? */
137 				if ((pa < SAVE_LAST) &&
138 					((pa & SAVE_MASK) == 0))
139 				{
140 					i = pa >> SAVE_SHIFT;
141 					if (prom_mappings[i] == NULL) {
142 						prom_mappings[i] = pgva;
143 #ifdef	DEBUG
144 						mon_printf("obio: found pa=0x%x\n", pa);
145 #endif
146 					}
147 				}
148 				/* Make sure it has the right permissions. */
149 				if ((pte & PGBITS) != PGBITS) {
150 #ifdef	DEBUG
151 					mon_printf("obio: fixing pte=0x%x\n", pte);
152 #endif
153 					pte |= PGBITS;
154 					set_pte(pgva, pte);
155 				}
156 			}
157 			pgva += NBPG;		/* next page */
158 		}
159 	}
160 }
161 
162 /*
163  * These are all the OBIO address that are required early
164  * in the life of the kernel.  All are less one page long.
165  */
166 static vm_offset_t required_mappings[] = {
167 	/* Basically the first six OBIO devices. */
168 	OBIO_KEYBD_MS,
169 	OBIO_ZS,
170 	OBIO_EEPROM,
171 	OBIO_CLOCK,
172 	OBIO_MEMERR,
173 	OBIO_INTERREG,
174 	(vm_offset_t)-1,	/* end marker */
175 };
176 
177 static void make_required_mappings()
178 {
179 	vm_offset_t pa, *rmp;
180 	int idx;
181 
182 	rmp = required_mappings;
183 	while (*rmp != (vm_offset_t)-1) {
184 		if (!obio_find_mapping(*rmp, NBPG)) {
185 			/*
186 			 * XXX - Ack! Need to create one!
187 			 * I don't think this can happen, but if
188 			 * it does, we can allocate a PMEG in the
189 			 * "high segment" and add it there. -gwr
190 			 */
191 			mon_printf("obio: no mapping for 0x%x\n", *rmp);
192 			mon_panic("obio: Ancient PROM?\n");
193 		}
194 		rmp++;
195 	}
196 }
197 
198 
199 /*
200  * this routine "configures" any internal OBIO devices which must be
201  * accessible before the mainline OBIO autoconfiguration as part of
202  * configure().
203  */
204 void obio_init()
205 {
206 	save_prom_mappings();
207 	make_required_mappings();
208 }
209 
210 caddr_t obio_alloc(obio_addr, obio_size)
211 	int obio_addr, obio_size;
212 {
213 	int npages;
214 	vm_offset_t va, high_segment_alloc(), obio_pa, obio_va, pte_proto;
215 	caddr_t cp;
216 
217 	cp = obio_find_mapping((vm_offset_t)obio_addr, obio_size);
218 	if (cp) return (cp);
219 
220 	npages = PA_PGNUM(sun3_round_page(obio_size));
221 	if (!npages)
222 		panic("obio_alloc: attempt to allocate 0 pages for obio");
223 	va = high_segment_alloc(npages);
224 	if (!va)
225 		va = (vm_offset_t) obio_vm_alloc(npages);
226 	if (!va)
227 		panic("obio_alloc: unable to allocate va for obio mapping");
228 	/* Drivers always get writable, non-cached mappings. */
229 	pte_proto = PG_VALID | PG_WRITE | PG_SYSTEM | PGT_OBIO | PG_NC;
230 	obio_va = va;
231 	obio_pa = (vm_offset_t) obio_addr;
232 	for (; npages ; npages--, obio_va += NBPG, obio_pa += NBPG)
233 		set_pte(obio_va, pte_proto | PA_PGNUM(obio_pa));
234 	return (caddr_t) va;
235 }
236