Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / acorn26 / podulebus / podulebus.c
blob6cae369c1dd0ca58ebc9118442d6be1b8ccdd6b3
1 /* $NetBSD: podulebus.c,v 1.17 2009/01/18 22:43:04 bjh21 Exp $ */
3 /*-
4 * Copyright (c) 2000 Ben Harris
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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>
49 #include "locators.h"
51 #include "podloader.h"
52 #include "unixbp.h"
54 #if NUNIXBP > 0
55 #include <arch/acorn26/podulebus/unixbpvar.h>
56 #endif
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);
65 #if NPODLOADER > 0
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,
69 void *, int);
70 #endif
72 struct podulebus_softc {
73 device_t sc_dev;
74 struct ioc_attach_args sc_ioc;
77 CFATTACH_DECL_NEW(podulebus, sizeof(struct podulebus_softc),
78 podulebus_match, podulebus_attach, NULL, NULL);
80 /* ARGSUSED */
81 static int
82 podulebus_match(device_t parent, cfdata_t cf, void *aux)
85 /* We can't usefully probe for this */
86 return 1;
89 static void
90 podulebus_attach(device_t parent, device_t self, void *aux)
92 int i;
93 struct podulebus_softc *sc = device_private(self);
94 struct ioc_attach_args *ioc = aux;
96 sc->sc_dev = self;
97 sc->sc_ioc = *ioc;
98 aprint_normal("\n");
100 /* Iterate over the podules attaching them */
101 for (i = 0; i < MAX_PODULES; i++)
102 podulebus_probe_podule(self, i);
105 static void
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;
111 int ecid, w;
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))
122 return;
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,
127 &pa.pa_fast_h);
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,
131 &pa.pa_medium_h);
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,
135 &pa.pa_slow_h);
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,
139 &pa.pa_sync_h);
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;
153 pa.pa_ecid = ecid;
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;
160 pa.pa_ih = 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; "
166 "ignoring it\n",
167 device_xname(self), pa.pa_slotnum);
168 } else {
169 podulebus_read_chunks(&pa, 0);
170 pa.pa_descr = podulebus_get_chunk(&pa,
171 CHUNK_DEV_DESCR);
174 pa.pa_slotflags = 0;
175 config_found_sm_loc(self, "podulebus", NULL, &pa,
176 podulebus_print, podulebus_submatch);
177 if (pa.pa_chunks)
178 free(pa.pa_chunks, M_DEVBUF);
179 if (pa.pa_descr)
180 free(pa.pa_descr, M_DEVBUF);
181 if (pa.pa_loader)
182 free(pa.pa_loader, M_DEVBUF);
183 } else
184 aprint_normal("%s:%d: non-extended podule ignored.\n",
185 device_xname(self), slotnum);
188 static void
189 podulebus_read_chunks(struct podulebus_attach_args *pa, int useloader)
191 u_int8_t chunk[8];
192 u_int ptr, nchunks, type, length, offset;
194 nchunks = pa->pa_nchunks;
195 if (useloader)
196 ptr = 0;
197 else
198 ptr = EXTECID_SIZE + IRQPTR_SIZE;
199 for (;;) {
200 #if NPODLOADER > 0
201 if (useloader)
202 podloader_read_region(pa, ptr, chunk, 8);
203 else
204 #endif
205 bus_space_read_region_1(pa->pa_sync_t, pa->pa_sync_h,
206 ptr, chunk, 8);
207 ptr += 8;
208 type = chunk[0];
209 length = chunk[1] | chunk[2] << 8 | chunk[3] << 16;
210 if (length == 0)
211 break;
212 offset = chunk[4] | chunk[5] << 8 |
213 chunk[6] << 16 | chunk[7] << 24;
214 if ((offset + length) > PODULE_GAP)
215 continue;
216 nchunks++;
217 pa->pa_chunks = realloc(pa->pa_chunks,
218 nchunks * sizeof(*pa->pa_chunks),
219 M_DEVBUF, M_WAITOK);
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;
228 static u_int8_t *
229 podulebus_get_chunk(struct podulebus_attach_args *pa, int type)
231 int i;
232 struct podulebus_chunk *pc;
233 u_int8_t *chunk;
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);
239 #if NPODLOADER > 0
240 if (pc->pc_useloader)
241 podloader_read_region(pa, pc->pc_offset, chunk,
242 pc->pc_length);
243 else
244 #endif
245 bus_space_read_region_1(pa->pa_sync_t,
246 pa->pa_sync_h, pc->pc_offset, chunk,
247 pc->pc_length);
248 chunk[pc->pc_length] = 0;
249 return chunk;
252 return NULL;
255 #if NPODLOADER > 0
257 podulebus_initloader(struct podulebus_attach_args *pa)
260 if (pa->pa_loader != NULL)
261 return 0;
262 pa->pa_loader = podulebus_get_chunk(pa, CHUNK_RISCOS_LOADER);
263 if (pa->pa_loader == NULL)
264 return -1;
265 podulebus_read_chunks(pa, 1);
266 if (pa->pa_descr)
267 free(pa->pa_descr, M_DEVBUF);
268 pa->pa_descr = podulebus_get_chunk(pa, CHUNK_DEV_DESCR);
269 return 0;
272 static register_t
273 podloader_call(register_t r0, register_t r1, register_t r11, void *loader,
274 int entry)
276 int s;
277 register_t result;
279 s = splhigh();
280 result = _podloader_call(r0, r1, r11, loader, entry);
281 splx(s);
282 return result;
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);
292 void
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);
299 void
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);
313 void
314 podloader_read_region(struct podulebus_attach_args *pa, u_int src,
315 u_int8_t *dest, size_t length)
318 while (length--)
319 *dest++ = podloader_readbyte(pa, src++);
320 podloader_reset(pa);
322 #endif
324 static int
325 podulebus_print(void *aux, char const *pnp)
327 struct podulebus_attach_args *pa = aux;
328 char *p, *q;
330 if (pnp) {
331 if (pa->pa_descr) {
332 /* Restrict description to ASCII graphic characters. */
333 for (p = q = pa->pa_descr; *p != '\0'; p++)
334 if (*p >= 32 && *p < 126)
335 *q++ = *p;
336 *q++ = 0;
337 aprint_normal("%s", pa->pa_descr);
338 } else
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);
344 return UNCONF;
347 static int
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);
355 return 0;
358 void *
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? */
364 #if NUNIXBP > 0
365 if (the_unixbp != NULL)
366 return irq_establish(IRQ_UNIXBP_BASE + slot, ipl, func, arg,
367 ev);
368 #endif
369 return irq_establish(IRQ_PIRQ, ipl, func, arg, ev);
372 void
373 podulebus_readcmos(struct podulebus_attach_args *pa, u_int8_t *c)
375 int i;
377 for (i = 0; i < 4; i++)
378 c[i] = cmos_read(PODULE_CMOS_BASE +
379 pa->pa_slotnum * PODULE_CMOS_PERSLOT + i);