1 /* $NetBSD: podulebus.c,v 1.24 2009/03/15 22:18:35 cegger Exp $ */
4 * Copyright (c) 1994-1996 Mark Brinicombe.
5 * Copyright (c) 1994 Brini.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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 Brini.
19 * 4. The name of the company nor the name of the author may be used to
20 * endorse or promote products derived from this software without specific
21 * prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * RiscBSD kernel project
39 * Podule probe and configuration routines
44 #include <sys/param.h>
46 __KERNEL_RCSID(0, "$NetBSD: podulebus.c,v 1.24 2009/03/15 22:18:35 cegger Exp $");
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
51 #include <sys/malloc.h>
52 #include <sys/device.h>
53 #include <uvm/uvm_extern.h>
54 #include <machine/io.h>
55 #include <arm/arm32/katelib.h>
56 #include <machine/intr.h>
57 #include <machine/bootconfig.h>
58 #include <machine/pmap.h>
59 #include <arm/iomd/iomdreg.h>
60 #include <arm/iomd/iomdvar.h>
61 #include <acorn32/podulebus/podulebus.h>
62 #include <dev/podulebus/podules.h>
63 #include <dev/podulebus/podule_data.h>
67 /* Array of podule structures, one per possible podule */
69 podule_t podules
[MAX_PODULES
+ MAX_NETSLOTS
];
71 extern struct bus_space podulebus_bs_tag
;
73 /* Declare prototypes */
75 u_int
poduleread(u_int
, int);
76 int podulebusmatch(struct device
*, struct cfdata
*, void *);
77 void podulebusattach(struct device
*, struct device
*, void *);
78 int podulebusprint(void *, const char *);
79 int podulebussubmatch(struct device
*, struct cfdata
*,
81 void podulechunkdirectory(podule_t
*);
82 void podulescan(struct device
*);
85 * int podulebusmatch(struct device *parent, void *match, void *aux)
87 * Probe for the podule bus. Currently all this does is return 1 to
88 * indicate that the podule bus was found.
92 podulebusmatch(struct device
*parent
, struct cfdata
*cf
, void *aux
)
97 case ARM7500FE_IOC_ID
:
105 podulebusprint(void *aux
, const char *name
)
107 struct podule_attach_args
*pa
= aux
;
110 aprint_normal("podule at %s", name
);
111 if (pa
->pa_podule
->slottype
== SLOT_POD
)
112 aprint_normal(" slot %d", pa
->pa_podule_number
);
113 else if (pa
->pa_podule
->slottype
== SLOT_NET
)
114 aprint_normal(" [ netslot %d ]",
115 pa
->pa_podule_number
- MAX_PODULES
);
118 panic("Invalid slot type");
126 podulebussubmatch(struct device
*parent
, struct cfdata
*cf
, const int *ldesc
, void *aux
)
128 struct podule_attach_args
*pa
= aux
;
130 /* Return priority 0 or 1 for wildcarded podule */
132 if (cf
->cf_loc
[PODULEBUSCF_SLOT
] == PODULEBUSCF_SLOT_DEFAULT
)
133 return(config_match(parent
, cf
, aux
));
135 /* Return higher priority if we match the specific podule */
137 else if (cf
->cf_loc
[PODULEBUSCF_SLOT
] == pa
->pa_podule_number
)
138 return(config_match(parent
, cf
, aux
) * 8);
147 dump_podule(podule_t
*podule
)
149 printf("podule%d: ", podule
->podulenum
);
150 printf("flags0=%02x ", podule
->flags0
);
151 printf("flags1=%02x ", podule
->flags1
);
152 printf("reserved=%02x ", podule
->reserved
);
153 printf("product=%02x ", podule
->product
);
154 printf("manufacturer=%02x ", podule
->manufacturer
);
155 printf("country=%02x ", podule
->country
);
156 printf("irq_addr=%08x ", podule
->irq_addr
);
157 printf("irq_mask=%02x ", podule
->irq_mask
);
158 printf("fiq_addr=%08x ", podule
->fiq_addr
);
159 printf("fiq_mask=%02x ", podule
->fiq_mask
);
160 printf("fast_base=%08x ", podule
->fast_base
);
161 printf("medium_base=%08x ", podule
->medium_base
);
162 printf("slow_base=%08x ", podule
->slow_base
);
163 printf("sync_base=%08x ", podule
->sync_base
);
164 printf("mod_base=%08x ", podule
->mod_base
);
165 printf("easi_base=%08x ", podule
->easi_base
);
166 printf("attached=%d ", podule
->attached
);
167 printf("slottype=%d ", podule
->slottype
);
168 printf("podulenum=%d ", podule
->podulenum
);
169 printf("description=%s ", podule
->description
);
175 podulechunkdirectory(podule_t
*podule
)
188 id
= podule
->read_rom(podule
->sync_base
, address
);
189 size
= podule
->read_rom(podule
->sync_base
, address
+ 4);
190 size
|= (podule
->read_rom(podule
->sync_base
, address
+ 8) << 8);
191 size
|= (podule
->read_rom(podule
->sync_base
, address
+ 12) << 16);
193 addr
= podule
->read_rom(podule
->sync_base
, address
+ 16);
194 addr
|= (podule
->read_rom(podule
->sync_base
, address
+ 20) << 8);
195 addr
|= (podule
->read_rom(podule
->sync_base
, address
+ 24) << 16);
196 addr
|= (podule
->read_rom(podule
->sync_base
, address
+ 28) << 24);
197 if (addr
< 0x800 && done_f5
== 0) {
199 for (loop
= 0; loop
< size
; ++loop
) {
200 if (loop
< PODULE_DESCRIPTION_LENGTH
) {
201 podule
->description
[loop
] =
202 podule
->read_rom(podule
->sync_base
, (addr
+ loop
)*4);
203 podule
->description
[loop
+ 1] = 0;
208 #ifdef DEBUG_CHUNK_DIR
209 if (id
== 0xf5 || id
== 0xf1 || id
== 0xf2 || id
== 0xf3 || id
== 0xf4 || id
== 0xf6) {
210 addr
= podule
->read_rom(podule
->sync_base
, address
+ 16);
211 addr
|= (podule
->read_rom(podule
->sync_base
, address
+ 20) << 8);
212 addr
|= (podule
->read_rom(podule
->sync_base
, address
+ 24) << 16);
213 addr
|= (podule
->read_rom(podule
->sync_base
, address
+ 28) << 24);
214 printf("<%04x.%04x.%04x.%04x>", id
, address
, addr
, size
);
216 for (loop
= 0; loop
< size
; ++loop
) {
217 printf("%c", podule
->read_rom(podule
->sync_base
, (addr
+ loop
)*4));
224 } while (id
!= 0 && address
< 0x800);
229 poduleexamine(podule_t
*podule
, struct device
*dev
, int slottype
)
231 struct manufacturer_description
*man_desc
;
232 struct podule_description
*pod_desc
;
234 /* Test to see if the podule is present */
236 if ((podule
->flags0
& 0x02) == 0x00) {
237 podule
->slottype
= slottype
;
238 if (slottype
== SLOT_NET
)
239 printf("netslot%d at %s : ", podule
->podulenum
- MAX_PODULES
,
242 printf("podule%d at %s : ", podule
->podulenum
,
245 /* Is it Acorn conformant ? */
247 if (podule
->flags0
& 0x80)
248 printf("Non-Acorn conformant expansion card\n");
252 /* Is it a simple podule ? */
254 id
= (podule
->flags0
>> 3) & 0x0f;
256 printf("Simple expansion card <%x>\n", id
);
258 /* Scan the chunk directory if present for tags we use */
259 if (podule
->flags1
& PODULE_FLAGS_CD
)
260 podulechunkdirectory(podule
);
262 /* Do we know this manufacturer ? */
263 man_desc
= known_manufacturers
;
264 while (man_desc
->description
) {
265 if (man_desc
->manufacturer_id
==
266 podule
->manufacturer
)
270 if (!man_desc
->description
)
271 printf("man=%04x : ", podule
->manufacturer
);
273 printf("%s : ", man_desc
->description
);
275 /* Do we know this product ? */
277 pod_desc
= known_podules
;
278 while (pod_desc
->description
) {
279 if (pod_desc
->product_id
== podule
->product
)
283 if (!pod_desc
->description
)
284 printf("prod=%04x : ",
287 printf("%s : ", pod_desc
->description
);
288 printf("%s\n", podule
->description
);
296 poduleread(u_int address
, int offset
)
299 return(ReadByte(address
+ offset
));
303 podulescan(struct device
*dev
)
310 /* Loop round all the podules */
312 for (loop
= 0; loop
< MAX_PODULES
; ++loop
, offset
+= SIMPLE_PODULE_SIZE
) {
313 podule
= &podules
[loop
];
314 podule
->podulenum
= loop
;
315 podule
->attached
= 0;
316 podule
->slottype
= SLOT_NONE
;
317 podule
->interrupt
= IRQ_PODULE
;
318 podule
->read_rom
= poduleread
;
319 podule
->dma_channel
= -1;
320 podule
->dma_interrupt
= -1;
321 podule
->description
[0] = 0;
323 if (loop
== 4) offset
+= PODULE_GAP
;
324 address
= ((u_char
*)SYNC_PODULE_BASE
) + offset
;
326 if ((address
[0] & 0x02) == 0x00) {
327 podule
->fast_base
= FAST_PODULE_BASE
+ offset
;
328 podule
->medium_base
= MEDIUM_PODULE_BASE
+ offset
;
329 podule
->slow_base
= SLOW_PODULE_BASE
+ offset
;
330 podule
->sync_base
= SYNC_PODULE_BASE
+ offset
;
331 podule
->mod_base
= MOD_PODULE_BASE
+ offset
;
332 podule
->easi_base
= EASI_BASE
+ loop
* EASI_SIZE
;
334 address
= ((u_char
*)EASI_BASE
) + loop
* EASI_SIZE
;
335 if ((address
[0] & 0x02) != 0x00)
338 podule
->fast_base
= 0;
339 podule
->medium_base
= 0;
340 podule
->slow_base
= 0;
341 podule
->sync_base
= 0;
342 podule
->mod_base
= 0;
343 podule
->easi_base
= EASI_BASE
+ loop
* EASI_SIZE
;
346 /* XXX - Really needs to be linked to a DMA manager */
347 if (IOMD_ID
== RPC600_IOMD_ID
) {
350 podule
->dma_channel
= 2;
351 podule
->dma_interrupt
= IRQ_DMACH2
;
354 podule
->dma_channel
= 3;
355 podule
->dma_interrupt
= IRQ_DMACH3
;
360 /* Get information from the podule header */
362 podule
->flags0
= address
[0];
363 if ((podule
->flags0
& 0x78) == 0) {
364 podule
->flags1
= address
[4];
365 podule
->reserved
= address
[8];
366 podule
->product
= address
[12] + (address
[16] << 8);
367 podule
->manufacturer
= address
[20] + (address
[24] << 8);
368 podule
->country
= address
[28];
369 if (podule
->flags1
& PODULE_FLAGS_IS
) {
370 podule
->irq_addr
= address
[52] + (address
[56] << 8) + (address
[60] << 16);
371 podule
->irq_addr
+= podule
->slow_base
;
372 podule
->irq_mask
= address
[48];
373 if (podule
->irq_mask
== 0)
374 podule
->irq_mask
= 0x01;
375 podule
->fiq_addr
= address
[36] + (address
[40] << 8) + (address
[44] << 16);
376 podule
->fiq_addr
+= podule
->slow_base
;
377 podule
->fiq_mask
= address
[32];
378 if (podule
->fiq_mask
== 0)
379 podule
->fiq_mask
= 0x04;
381 podule
->irq_addr
= podule
->slow_base
;
382 podule
->irq_mask
= 0x01;
383 podule
->fiq_addr
= podule
->slow_base
;
384 podule
->fiq_mask
= 0x04;
388 poduleexamine(podule
, dev
, SLOT_POD
);
394 * void podulebusattach(struct device *parent, struct device *dev, void *aux)
397 * This probes all the podules and sets up the podules array with
398 * information found in the podule headers.
399 * After identifing all the podules, all the children of the podulebus
400 * are probed and attached.
404 podulebusattach(struct device
*parent
, struct device
*self
, void *aux
)
407 struct podule_attach_args pa
;
416 easi_time
= IOMD_READ_BYTE(IOMD_ECTCR
);
417 printf(": easi timings=");
418 for (bit
= 0x01; bit
< 0x100; bit
= bit
<< 1)
428 /* Ok we need to map in the podulebus */
429 /* with the new pmap mappings have to be done when the L1 tables
430 * are built during initarm
432 /* Map the FAST and SYNC simple podules */
433 pmap_map_section((vm_offset_t
)pmap_kernel()->pm_pdir
,
434 SYNC_PODULE_BASE
& 0xfff00000, SYNC_PODULE_HW_BASE
& 0xfff00000,
435 VM_PROT_READ
|VM_PROT_WRITE
, PTE_NOCACHE
);
437 /* Now map the EASI space */
439 for (loop
= 0; loop
< MAX_PODULES
; ++loop
) {
442 for (loop1
= loop
* EASI_SIZE
; loop1
< ((loop
+ 1) * EASI_SIZE
);
444 pmap_map_section((vm_offset_t
)pmap_kernel()->pm_pdir
,
445 EASI_BASE
+ loop1
, EASI_HW_BASE
+ loop1
,
446 VM_PROT_READ
|VM_PROT_WRITE
, PTE_NOCACHE
);
451 * The MEDIUM and SLOW simple podules and the module space will have been
452 * mapped when the IOMD and COMBO we mapped in for the RPC
455 /* Find out what hardware is bolted on */
460 /* Look for drivers to attach */
462 for (loop
= 0; loop
< MAX_PODULES
+MAX_NETSLOTS
; ++loop
) {
464 /* Provide backwards compat for a while */
465 sprintf(argstring
, "podule%d.disable", loop
);
466 if (get_bootconf_option(boot_args
, argstring
,
467 BOOTOPT_TYPE_BOOLEAN
, &value
)) {
469 if (podules
[loop
].slottype
!= SLOT_NONE
)
470 printf("podule%d: Disabled\n", loop
);
475 sprintf(argstring
, "podule%d=", loop
);
476 if (get_bootconf_option(boot_args
, argstring
,
477 BOOTOPT_TYPE_HEXINT
, &value
)) {
478 /* Override the ID */
479 podules
[loop
].manufacturer
= value
>> 16;
480 podules
[loop
].product
= value
& 0xffff;
481 /* Any old description is now wrong */
482 podules
[loop
].description
[0] = 0;
483 if (value
!= 0xffff) {
484 printf("podule%d: ID overriden man=%04x prod=%04x\n",
485 loop
, podules
[loop
].manufacturer
,
486 podules
[loop
].product
);
487 podules
[loop
].slottype
= SLOT_POD
;
488 pa
.pa_podule_number
= loop
;
489 pa
.pa_ih
= pa
.pa_podule_number
;
490 pa
.pa_podule
= &podules
[loop
];
491 pa
.pa_iot
= &podulebus_bs_tag
;
492 config_found_sm_loc(self
, "podulebus", NULL
, &pa
,
493 podulebusprint
, podulebussubmatch
);
496 if (value
== 0xffff) {
497 printf("podule%d: Disabled\n", loop
);
502 if (podules
[loop
].slottype
!= SLOT_NONE
) {
503 pa
.pa_podule_number
= loop
;
504 pa
.pa_ih
= pa
.pa_podule_number
;
505 pa
.pa_podule
= &podules
[loop
];
506 pa
.pa_iot
= &podulebus_bs_tag
;
507 config_found_sm_loc(self
, "podulebus", NULL
, &pa
,
508 podulebusprint
, podulebussubmatch
);
514 CFATTACH_DECL(podulebus
, sizeof(struct device
),
515 podulebusmatch
, podulebusattach
, NULL
, NULL
);
517 /* Useful functions that drivers may share */
520 * Match a podule structure with the specified parameters
521 * Returns 0 if the match failed
522 * The required_slot is not used at the moment.
526 matchpodule(struct podule_attach_args
*pa
, int manufacturer
, int product
, int required_slot
)
528 if (pa
->pa_podule
->attached
)
529 panic("podulebus: Podule already attached");
531 if (IS_PODULE(pa
, manufacturer
, product
))
538 podulebus_irq_establish(podulebus_intr_handle_t ih
,
539 int ipl
, int (*func
)(void *), void *arg
, struct evcnt
*ev
)
542 /* XXX We don't actually use the evcnt supplied, just its name. */
543 return intr_claim(podules
[ih
].interrupt
, ipl
, ev
->ev_group
, func
,
548 * Generate a bus_space_tag_t with the specified address-bus shift.
551 podulebus_shift_tag(bus_space_tag_t tag
, u_int shift
, bus_space_tag_t
*tagp
)
555 * For the podulebus, the bus tag cookie is the shift to apply
556 * to registers, so duplicate the bus space tag and change the
560 /* XXX never freed, but podules are never detached anyway. */
561 *tagp
= malloc(sizeof(struct bus_space
), M_DEVBUF
, M_WAITOK
);
563 (*tagp
)->bs_cookie
= (void *)shift
;
567 podulebus_initloader(struct podulebus_attach_args
*pa
)
570 /* No loader support at present on arm32, so always fail. */
575 podloader_readbyte(struct podulebus_attach_args
*pa
, u_int addr
)
578 panic("podloader_readbyte");
582 podloader_writebyte(struct podulebus_attach_args
*pa
, u_int addr
, int val
)
585 panic("podloader_writebyte");
589 podloader_reset(struct podulebus_attach_args
*pa
)
592 panic("podloader_reset");
596 podloader_callloader(struct podulebus_attach_args
*pa
, u_int r0
, u_int r1
)
599 panic("podloader_callloader");
602 /* End of podulebus.c */