1 /* $NetBSD: obio.c,v 1.70 2008/04/28 20:23:35 martin Exp $ */
4 * Copyright (c) 1997,1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: obio.c,v 1.70 2008/04/28 20:23:35 martin Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
44 #include <sys/syslog.h>
47 #include <uvm/uvm_extern.h>
49 #include <machine/bus.h>
50 #include <sparc/dev/sbusvar.h>
51 #include <machine/autoconf.h>
52 #include <machine/oldmon.h>
53 #include <machine/cpu.h>
54 #include <machine/ctlreg.h>
55 #include <sparc/sparc/asm.h>
56 #include <sparc/sparc/vaddrs.h>
57 #include <sparc/sparc/cpuvar.h>
60 device_t sc_dev
; /* base device */
61 bus_space_tag_t sc_bustag
; /* parent bus tag */
62 bus_dma_tag_t sc_dmatag
; /* parent bus DMA tag */
66 struct device sc_dev
; /* base device */
67 struct obio4_softc sc_obio
; /* sun4 obio */
68 struct sbus_softc sc_sbus
; /* sun4m obio is another sbus slot */
72 /* autoconfiguration driver */
73 static int obiomatch(device_t
, struct cfdata
*, void *);
74 static void obioattach(device_t
, struct device
*, void *);
76 CFATTACH_DECL_NEW(obio
, sizeof(union obio_softc
),
77 obiomatch
, obioattach
, NULL
, NULL
);
79 static int obio_attached
;
82 * This `obio4_busattachargs' data structure only exists to pass down
83 * to obiosearch() the name of a device that must be configured early.
85 struct obio4_busattachargs
{
86 struct mainbus_attach_args
*ma
;
91 static int obioprint(void *, const char *);
92 static int obiosearch(device_t
, struct cfdata
*, const int *, void *);
93 static paddr_t
obio_bus_mmap(bus_space_tag_t
, bus_addr_t
, off_t
, int, int);
94 static int _obio_bus_map(bus_space_tag_t
, bus_addr_t
, bus_size_t
, int,
95 vaddr_t
, bus_space_handle_t
*);
97 /* There's at most one obio bus, so we can allocate the bus tag statically */
98 static struct sparc_bus_space_tag obio_space_tag
;
102 * Translate obio `interrupts' property value to processor IPL (see sbus.c)
103 * Apparently, the `interrupts' property on obio devices is just
106 static int intr_obio2ipl
[] = {
107 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
111 obiomatch(device_t parent
, struct cfdata
*cf
, void *aux
)
113 struct mainbus_attach_args
*ma
= aux
;
118 return (strcmp(cf
->cf_name
, ma
->ma_name
) == 0);
122 obioattach(device_t parent
, device_t self
, void *aux
)
124 struct mainbus_attach_args
*ma
= aux
;
132 struct obio4_softc
*sc
=
133 &((union obio_softc
*)device_private(self
))->sc_obio
;
134 struct obio4_busattachargs oa
;
135 const char *const *cpp
;
136 static const char *const special4
[] = {
137 /* find these first */
139 "dma", /* need this before `esp', if any */
144 sc
->sc_bustag
= ma
->ma_bustag
;
145 sc
->sc_dmatag
= ma
->ma_dmatag
;
147 memcpy(&obio_space_tag
, sc
->sc_bustag
, sizeof(obio_space_tag
));
148 obio_space_tag
.cookie
= sc
;
149 obio_space_tag
.parent
= sc
->sc_bustag
;
150 obio_space_tag
.sparc_bus_map
= _obio_bus_map
;
151 obio_space_tag
.sparc_bus_mmap
= obio_bus_mmap
;
155 /* Find all `early' obio devices */
156 for (cpp
= special4
; *cpp
!= NULL
; cpp
++) {
158 config_search_ia(obiosearch
, self
, "obio", &oa
);
161 /* Find all other obio devices */
163 config_search_ia(obiosearch
, self
, "obio", &oa
);
166 } else if (CPU_ISSUN4M
) {
168 * Attach the on-board I/O bus at on a sun4m.
169 * In this case we treat the obio bus as another sbus slot.
171 struct sbus_softc
*sc
=
172 &((union obio_softc
*)device_private(self
))->sc_sbus
;
174 static const char *const special4m
[] = {
175 /* find these first */
178 #if 0 /* Not all sun4m's have an `auxio' */
182 /* place device to ignore here */
188 sc
->sc_bustag
= ma
->ma_bustag
;
189 sc
->sc_dmatag
= ma
->ma_dmatag
;
190 sc
->sc_intr2ipl
= intr_obio2ipl
;
192 sbus_attach_common(sc
, "obio", ma
->ma_node
, special4m
);
194 printf("obio on this machine?\n");
200 obioprint(void *args
, const char *busname
)
202 union obio_attach_args
*uoba
= args
;
203 struct obio4_attach_args
*oba
= &uoba
->uoba_oba4
;
205 aprint_normal(" addr 0x%lx", (u_long
)BUS_ADDR_PADDR(oba
->oba_paddr
));
206 if (oba
->oba_pri
!= -1)
207 aprint_normal(" level %d", oba
->oba_pri
);
213 _obio_bus_map(bus_space_tag_t t
, bus_addr_t ba
, bus_size_t size
, int flags
,
214 vaddr_t va
, bus_space_handle_t
*hp
)
217 if ((flags
& OBIO_BUS_MAP_USE_ROM
) != 0 &&
218 obio_find_rom_map(ba
, size
, hp
) == 0)
221 return (bus_space_map2(t
->parent
, ba
, size
, flags
, va
, hp
));
225 obio_bus_mmap(bus_space_tag_t t
, bus_addr_t ba
, off_t off
, int prot
, int flags
)
228 return (bus_space_mmap(t
->parent
, ba
, off
, prot
, flags
));
232 obiosearch(device_t parent
, struct cfdata
*cf
, const int *ldesc
,
235 struct obio4_busattachargs
*oap
= aux
;
236 union obio_attach_args uoba
;
237 struct obio4_attach_args
*oba
= &uoba
.uoba_oba4
;
240 /* Check whether we're looking for a specifically named device */
241 if (oap
->name
!= NULL
&& strcmp(oap
->name
, cf
->cf_name
) != 0)
245 * Avoid sun4m entries which don't have valid PAs.
246 * no point in even probing them.
248 addr
= cf
->cf_loc
[OBIOCF_ADDR
];
253 * On the 4/100 obio addresses must be mapped at
254 * 0x0YYYYYYY, but alias higher up (we avoid the
255 * alias condition because it causes pmap difficulties)
256 * XXX: We also assume that 4/[23]00 obio addresses
257 * must be 0xZYYYYYYY, where (Z != 0)
259 if (cpuinfo
.cpu_type
== CPUTYP_4_100
&& (addr
& 0xf0000000))
261 if (cpuinfo
.cpu_type
!= CPUTYP_4_100
&& !(addr
& 0xf0000000))
264 uoba
.uoba_isobio4
= 1;
265 oba
->oba_bustag
= &obio_space_tag
;
266 oba
->oba_dmatag
= oap
->ma
->ma_dmatag
;
267 oba
->oba_paddr
= BUS_ADDR(PMAP_OBIO
, addr
);
268 oba
->oba_pri
= cf
->cf_loc
[OBIOCF_LEVEL
];
270 if (config_match(parent
, cf
, &uoba
) == 0)
273 config_attach(parent
, cf
, &uoba
, obioprint
);
279 * If we can find a mapping that was established by the rom, use it.
280 * Else, create a new mapping.
283 obio_find_rom_map(bus_addr_t ba
, int len
, bus_space_handle_t
*hp
)
285 #define getpte(va) lda(va, ASI_PTE)
294 pa
= BUS_ADDR_PADDR(ba
);
296 pgtype
= PMAP_T2PTE_4(PMAP_OBIO
);
298 for (va
= OLDMON_STARTVADDR
; va
< OLDMON_ENDVADDR
; va
+= PAGE_SIZE
) {
300 if ((pte
& PG_V
) == 0 || (pte
& PG_TYPE
) != pgtype
||
301 (pte
& PG_PFNUM
) != pf
)
305 * Found entry in PROM's pagetable
306 * note: preserve page offset
308 *hp
= (bus_space_handle_t
)(va
| (pa
& PGOFSET
));