1 /* $NetBSD: podulebus.c,v 1.17 2009/01/18 22:43:04 bjh21 Exp $ */
4 * Copyright (c) 2000 Ben Harris
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: podulebus.c,v 1.17 2009/01/18 22:43:04 bjh21 Exp $");
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/malloc.h>
36 #include <sys/systm.h>
38 #include <machine/bus.h>
39 #include <machine/intr.h>
40 #include <machine/irq.h>
41 #include <machine/machdep.h>
42 #include <machine/memcreg.h>
44 #include <arch/acorn26/iobus/iocreg.h>
45 #include <arch/acorn26/iobus/iocvar.h>
46 #include <dev/podulebus/podulebus.h>
47 #include <arch/acorn26/podulebus/podulebusreg.h>
51 #include "podloader.h"
55 #include <arch/acorn26/podulebus/unixbpvar.h>
58 static int podulebus_match(device_t
, cfdata_t
, void *);
59 static void podulebus_attach(device_t
, device_t
, void *);
60 static void podulebus_probe_podule(device_t
, int);
61 static int podulebus_print(void *, char const *);
62 static int podulebus_submatch(device_t
, cfdata_t
, const int *, void *);
63 static void podulebus_read_chunks(struct podulebus_attach_args
*, int);
64 static u_int8_t
*podulebus_get_chunk(struct podulebus_attach_args
*, int);
66 void podloader_read_region(struct podulebus_attach_args
*pa
, u_int src
,
67 u_int8_t
*dest
, size_t length
);
68 extern register_t
_podloader_call(register_t
, register_t
, register_t
,
72 struct podulebus_softc
{
74 struct ioc_attach_args sc_ioc
;
77 CFATTACH_DECL_NEW(podulebus
, sizeof(struct podulebus_softc
),
78 podulebus_match
, podulebus_attach
, NULL
, NULL
);
82 podulebus_match(device_t parent
, cfdata_t cf
, void *aux
)
85 /* We can't usefully probe for this */
90 podulebus_attach(device_t parent
, device_t self
, void *aux
)
93 struct podulebus_softc
*sc
= device_private(self
);
94 struct ioc_attach_args
*ioc
= aux
;
100 /* Iterate over the podules attaching them */
101 for (i
= 0; i
< MAX_PODULES
; i
++)
102 podulebus_probe_podule(self
, i
);
106 podulebus_probe_podule(device_t self
, int slotnum
)
108 struct podulebus_softc
*sc
= device_private(self
);
109 bus_space_tag_t id_bst
;
110 bus_space_handle_t id_bsh
;
112 u_int8_t extecid
[EXTECID_SIZE
];
113 struct podulebus_attach_args pa
;
115 memset(&pa
, 0, sizeof(pa
));
116 id_bst
= sc
->sc_ioc
.ioc_sync_t
;
117 bus_space_subregion(id_bst
, sc
->sc_ioc
.ioc_sync_h
,
118 slotnum
* PODULE_GAP
, PODULE_GAP
, &id_bsh
);
119 ecid
= bus_space_read_1(id_bst
, id_bsh
, 0);
120 /* Skip empty or strange slots */
121 if (ecid
& (ECID_NOTPRESENT
| ECID_NONCONF
))
123 if ((ecid
& ECID_ID_MASK
) == ECID_ID_EXTEND
) {
124 pa
.pa_fast_t
= sc
->sc_ioc
.ioc_fast_t
;
125 bus_space_subregion(pa
.pa_fast_t
, sc
->sc_ioc
.ioc_fast_h
,
126 slotnum
* PODULE_GAP
, PODULE_GAP
,
128 pa
.pa_medium_t
= sc
->sc_ioc
.ioc_medium_t
;
129 bus_space_subregion(pa
.pa_medium_t
, sc
->sc_ioc
.ioc_medium_h
,
130 slotnum
* PODULE_GAP
, PODULE_GAP
,
132 pa
.pa_slow_t
= sc
->sc_ioc
.ioc_slow_t
;
133 bus_space_subregion(pa
.pa_slow_t
, sc
->sc_ioc
.ioc_slow_h
,
134 slotnum
* PODULE_GAP
, PODULE_GAP
,
136 pa
.pa_sync_t
= sc
->sc_ioc
.ioc_sync_t
;
137 bus_space_subregion(pa
.pa_sync_t
, sc
->sc_ioc
.ioc_sync_h
,
138 slotnum
* PODULE_GAP
, PODULE_GAP
,
140 /* XXX This is a hack! */
141 pa
.pa_mod_t
= &iobus_bs_tag
;
142 bus_space_map(pa
.pa_mod_t
,
143 (bus_addr_t
)MEMC_IO_BASE
+ slotnum
* (PODULE_GAP
<< 2),
144 (PODULE_GAP
<< 2), 0, &pa
.pa_mod_h
);
145 bus_space_read_region_1(id_bst
, id_bsh
, 0,
146 extecid
, EXTECID_SIZE
);
147 /* XXX If you thought that was a hack... */
148 pa
.pa_mod_base
= pa
.pa_mod_h
;
149 pa
.pa_fast_base
= pa
.pa_fast_h
;
150 pa
.pa_medium_base
= pa
.pa_medium_h
;
151 pa
.pa_slow_base
= pa
.pa_slow_h
;
152 pa
.pa_sync_base
= pa
.pa_sync_h
;
154 pa
.pa_flags1
= extecid
[EXTECID_F1
];
155 pa
.pa_manufacturer
= (extecid
[EXTECID_MLO
] |
156 extecid
[EXTECID_MHI
] << 8);
157 pa
.pa_product
= (extecid
[EXTECID_PLO
] |
158 extecid
[EXTECID_PHI
] << 8);
159 pa
.pa_slotnum
= slotnum
;
161 if (pa
.pa_flags1
& EXTECID_F1_CD
) {
162 w
= pa
.pa_flags1
& EXTECID_F1_W_MASK
;
163 if (w
!= EXTECID_F1_W_8BIT
) {
164 /* RISC OS 3 can't handle this either. */
165 aprint_error("%s:%d: ROM is not 8 bits wide; "
167 device_xname(self
), pa
.pa_slotnum
);
169 podulebus_read_chunks(&pa
, 0);
170 pa
.pa_descr
= podulebus_get_chunk(&pa
,
175 config_found_sm_loc(self
, "podulebus", NULL
, &pa
,
176 podulebus_print
, podulebus_submatch
);
178 free(pa
.pa_chunks
, M_DEVBUF
);
180 free(pa
.pa_descr
, M_DEVBUF
);
182 free(pa
.pa_loader
, M_DEVBUF
);
184 aprint_normal("%s:%d: non-extended podule ignored.\n",
185 device_xname(self
), slotnum
);
189 podulebus_read_chunks(struct podulebus_attach_args
*pa
, int useloader
)
192 u_int ptr
, nchunks
, type
, length
, offset
;
194 nchunks
= pa
->pa_nchunks
;
198 ptr
= EXTECID_SIZE
+ IRQPTR_SIZE
;
202 podloader_read_region(pa
, ptr
, chunk
, 8);
205 bus_space_read_region_1(pa
->pa_sync_t
, pa
->pa_sync_h
,
209 length
= chunk
[1] | chunk
[2] << 8 | chunk
[3] << 16;
212 offset
= chunk
[4] | chunk
[5] << 8 |
213 chunk
[6] << 16 | chunk
[7] << 24;
214 if ((offset
+ length
) > PODULE_GAP
)
217 pa
->pa_chunks
= realloc(pa
->pa_chunks
,
218 nchunks
* sizeof(*pa
->pa_chunks
),
220 pa
->pa_chunks
[nchunks
-1].pc_type
= type
;
221 pa
->pa_chunks
[nchunks
-1].pc_length
= length
;
222 pa
->pa_chunks
[nchunks
-1].pc_offset
= offset
;
223 pa
->pa_chunks
[nchunks
-1].pc_useloader
= useloader
;
225 pa
->pa_nchunks
= nchunks
;
229 podulebus_get_chunk(struct podulebus_attach_args
*pa
, int type
)
232 struct podulebus_chunk
*pc
;
235 for (i
= 0; i
< pa
->pa_nchunks
; i
++) {
236 pc
= &pa
->pa_chunks
[i
];
237 if (pc
->pc_type
== type
) {
238 chunk
= malloc( pc
->pc_length
+ 1, M_DEVBUF
, M_WAITOK
);
240 if (pc
->pc_useloader
)
241 podloader_read_region(pa
, pc
->pc_offset
, chunk
,
245 bus_space_read_region_1(pa
->pa_sync_t
,
246 pa
->pa_sync_h
, pc
->pc_offset
, chunk
,
248 chunk
[pc
->pc_length
] = 0;
257 podulebus_initloader(struct podulebus_attach_args
*pa
)
260 if (pa
->pa_loader
!= NULL
)
262 pa
->pa_loader
= podulebus_get_chunk(pa
, CHUNK_RISCOS_LOADER
);
263 if (pa
->pa_loader
== NULL
)
265 podulebus_read_chunks(pa
, 1);
267 free(pa
->pa_descr
, M_DEVBUF
);
268 pa
->pa_descr
= podulebus_get_chunk(pa
, CHUNK_DEV_DESCR
);
273 podloader_call(register_t r0
, register_t r1
, register_t r11
, void *loader
,
280 result
= _podloader_call(r0
, r1
, r11
, loader
, entry
);
286 podloader_readbyte(struct podulebus_attach_args
*pa
, u_int addr
)
289 return podloader_call(0, addr
, pa
->pa_sync_base
, pa
->pa_loader
, 0);
293 podloader_writebyte(struct podulebus_attach_args
*pa
, u_int addr
, int val
)
296 podloader_call(val
, addr
, pa
->pa_sync_base
, pa
->pa_loader
, 1);
300 podloader_reset(struct podulebus_attach_args
*pa
)
303 podloader_call(0, 0, pa
->pa_sync_base
, pa
->pa_loader
, 2);
307 podloader_callloader(struct podulebus_attach_args
*pa
, u_int r0
, u_int r1
)
310 return podloader_call(r0
, r1
, pa
->pa_sync_base
, pa
->pa_loader
, 3);
314 podloader_read_region(struct podulebus_attach_args
*pa
, u_int src
,
315 u_int8_t
*dest
, size_t length
)
319 *dest
++ = podloader_readbyte(pa
, src
++);
325 podulebus_print(void *aux
, char const *pnp
)
327 struct podulebus_attach_args
*pa
= aux
;
332 /* Restrict description to ASCII graphic characters. */
333 for (p
= q
= pa
->pa_descr
; *p
!= '\0'; p
++)
334 if (*p
>= 32 && *p
< 126)
337 aprint_normal("%s", pa
->pa_descr
);
339 aprint_normal("podule");
340 aprint_normal(" <%04x:%04x> at %s",
341 pa
->pa_manufacturer
, pa
->pa_product
, pnp
);
343 aprint_normal(" slot %d", pa
->pa_slotnum
);
348 podulebus_submatch(device_t parent
, cfdata_t cf
, const int *ldesc
, void *aux
)
350 struct podulebus_attach_args
*pa
= aux
;
352 if (cf
->cf_loc
[PODULEBUSCF_SLOT
] == PODULEBUSCF_SLOT_DEFAULT
||
353 cf
->cf_loc
[PODULEBUSCF_SLOT
] == pa
->pa_slotnum
)
354 return config_match(parent
, cf
, aux
);
359 podulebus_irq_establish(podulebus_intr_handle_t slot
, int ipl
,
360 int (*func
)(void *), void *arg
, struct evcnt
*ev
)
363 /* XXX: support for checking IRQ bit on podule? */
365 if (the_unixbp
!= NULL
)
366 return irq_establish(IRQ_UNIXBP_BASE
+ slot
, ipl
, func
, arg
,
369 return irq_establish(IRQ_PIRQ
, ipl
, func
, arg
, ev
);
373 podulebus_readcmos(struct podulebus_attach_args
*pa
, u_int8_t
*c
)
377 for (i
= 0; i
< 4; i
++)
378 c
[i
] = cmos_read(PODULE_CMOS_BASE
+
379 pa
->pa_slotnum
* PODULE_CMOS_PERSLOT
+ i
);