1 /* $Id: central.c,v 1.14 2000/09/21 06:25:14 anton Exp $
2 * central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
4 * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
7 #include <linux/kernel.h>
8 #include <linux/types.h>
9 #include <linux/string.h>
10 #include <linux/timer.h>
11 #include <linux/sched.h>
12 #include <linux/delay.h>
13 #include <linux/init.h>
14 #include <linux/bootmem.h>
18 #include <asm/starfire.h>
20 struct linux_central
*central_bus
= NULL
;
21 struct linux_fhc
*fhc_list
= NULL
;
23 #define IS_CENTRAL_FHC(__fhc) ((__fhc) == central_bus->child)
25 static inline unsigned long long_align(unsigned long addr
)
27 return ((addr
+ (sizeof(unsigned long) - 1)) &
28 ~(sizeof(unsigned long) - 1));
31 static void central_ranges_init(int cnode
, struct linux_central
*central
)
35 central
->num_central_ranges
= 0;
36 success
= prom_getproperty(central
->prom_node
, "ranges",
37 (char *) central
->central_ranges
,
38 sizeof (central
->central_ranges
));
40 central
->num_central_ranges
= (success
/sizeof(struct linux_prom_ranges
));
43 static void fhc_ranges_init(int fnode
, struct linux_fhc
*fhc
)
47 fhc
->num_fhc_ranges
= 0;
48 success
= prom_getproperty(fhc
->prom_node
, "ranges",
49 (char *) fhc
->fhc_ranges
,
50 sizeof (fhc
->fhc_ranges
));
52 fhc
->num_fhc_ranges
= (success
/sizeof(struct linux_prom_ranges
));
55 /* Range application routines are exported to various drivers,
56 * so do not __init this.
58 static void adjust_regs(struct linux_prom_registers
*regp
, int nregs
,
59 struct linux_prom_ranges
*rangep
, int nranges
)
63 for (regc
= 0; regc
< nregs
; regc
++) {
64 for (rngc
= 0; rngc
< nranges
; rngc
++)
65 if (regp
[regc
].which_io
== rangep
[rngc
].ot_child_space
)
67 if (rngc
== nranges
) /* oops */
68 prom_printf("adjust_regs: Could not find range with matching bus type...\n");
69 regp
[regc
].which_io
= rangep
[rngc
].ot_parent_space
;
70 regp
[regc
].phys_addr
+= rangep
[rngc
].ot_parent_base
;
74 /* Apply probed fhc ranges to registers passed, if no ranges return. */
75 void apply_fhc_ranges(struct linux_fhc
*fhc
,
76 struct linux_prom_registers
*regs
,
79 if(fhc
->num_fhc_ranges
)
80 adjust_regs(regs
, nregs
, fhc
->fhc_ranges
,
84 /* Apply probed central ranges to registers passed, if no ranges return. */
85 void apply_central_ranges(struct linux_central
*central
,
86 struct linux_prom_registers
*regs
, int nregs
)
88 if(central
->num_central_ranges
)
89 adjust_regs(regs
, nregs
, central
->central_ranges
,
90 central
->num_central_ranges
);
93 void * __init
central_alloc_bootmem(unsigned long size
)
97 ret
= __alloc_bootmem(size
, SMP_CACHE_BYTES
, 0UL);
104 static void probe_other_fhcs(void)
106 struct linux_prom64_registers fpregs
[6];
110 node
= prom_getchild(prom_root_node
);
111 node
= prom_searchsiblings(node
, "fhc");
113 prom_printf("FHC: Cannot find any toplevel firehose controllers.\n");
117 struct linux_fhc
*fhc
;
121 fhc
= (struct linux_fhc
*)
122 central_alloc_bootmem(sizeof(struct linux_fhc
));
124 prom_printf("probe_other_fhcs: Cannot alloc fhc.\n");
128 /* Link it into the FHC chain. */
129 fhc
->next
= fhc_list
;
132 /* Toplevel FHCs have no parent. */
135 fhc
->prom_node
= node
;
136 prom_getstring(node
, "name", namebuf
, sizeof(namebuf
));
137 strcpy(fhc
->prom_name
, namebuf
);
138 fhc_ranges_init(node
, fhc
);
140 /* Non-central FHC's have 64-bit OBP format registers. */
141 if(prom_getproperty(node
, "reg",
142 (char *)&fpregs
[0], sizeof(fpregs
)) == -1) {
143 prom_printf("FHC: Fatal error, cannot get fhc regs.\n");
147 /* Only central FHC needs special ranges applied. */
148 fhc
->fhc_regs
.pregs
= fpregs
[0].phys_addr
;
149 fhc
->fhc_regs
.ireg
= fpregs
[1].phys_addr
;
150 fhc
->fhc_regs
.ffregs
= fpregs
[2].phys_addr
;
151 fhc
->fhc_regs
.sregs
= fpregs
[3].phys_addr
;
152 fhc
->fhc_regs
.uregs
= fpregs
[4].phys_addr
;
153 fhc
->fhc_regs
.tregs
= fpregs
[5].phys_addr
;
155 board
= prom_getintdefault(node
, "board#", -1);
158 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_JCTRL
);
159 if((tmp
& FHC_JTAG_CTRL_MENAB
) != 0)
160 fhc
->jtag_master
= 1;
162 fhc
->jtag_master
= 0;
164 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_ID
);
165 printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n",
167 (tmp
& FHC_ID_VERS
) >> 28,
168 (tmp
& FHC_ID_PARTID
) >> 12,
169 (tmp
& FHC_ID_MANUF
) >> 1,
170 (fhc
->jtag_master
? "(JTAG Master)" : ""));
172 /* This bit must be set in all non-central FHC's in
173 * the system. When it is clear, this identifies
176 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
177 tmp
|= FHC_CONTROL_IXIST
;
178 upa_writel(tmp
, fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
180 /* Look for the next FHC. */
181 node
= prom_getsibling(node
);
184 node
= prom_searchsiblings(node
, "fhc");
190 static void probe_clock_board(struct linux_central
*central
,
191 struct linux_fhc
*fhc
,
192 int cnode
, int fnode
)
194 struct linux_prom_registers cregs
[3];
195 int clknode
, nslots
, tmp
, nregs
;
197 clknode
= prom_searchsiblings(prom_getchild(fnode
), "clock-board");
198 if(clknode
== 0 || clknode
== -1) {
199 prom_printf("Critical error, central lacks clock-board.\n");
202 nregs
= prom_getproperty(clknode
, "reg", (char *)&cregs
[0], sizeof(cregs
));
204 prom_printf("CENTRAL: Fatal error, cannot map clock-board regs.\n");
207 nregs
/= sizeof(struct linux_prom_registers
);
208 apply_fhc_ranges(fhc
, &cregs
[0], nregs
);
209 apply_central_ranges(central
, &cregs
[0], nregs
);
210 central
->cfreg
= ((((unsigned long)cregs
[0].which_io
) << 32UL) |
211 ((unsigned long)cregs
[0].phys_addr
));
212 central
->clkregs
= ((((unsigned long)cregs
[1].which_io
) << 32UL) |
213 ((unsigned long)cregs
[1].phys_addr
));
216 central
->clkver
= 0UL;
218 central
->clkver
= ((((unsigned long)cregs
[2].which_io
) << 32UL) |
219 ((unsigned long)cregs
[2].phys_addr
));
221 tmp
= upa_readb(central
->clkregs
+ CLOCK_STAT1
);
231 if(central
->clkver
!= 0UL &&
232 upa_readb(central
->clkver
) != 0) {
233 if((upa_readb(central
->clkver
) & 0x80) != 0)
243 central
->slots
= nslots
;
244 printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n",
245 central
->slots
, upa_readb(central
->cfreg
),
246 (central
->clkver
? upa_readb(central
->clkver
) : 0x00));
249 void central_probe(void)
251 struct linux_prom_registers fpregs
[6];
252 struct linux_fhc
*fhc
;
254 int cnode
, fnode
, err
;
256 cnode
= prom_finddevice("/central");
257 if(cnode
== 0 || cnode
== -1) {
258 if (this_is_starfire
)
259 starfire_cpu_setup();
263 /* Ok we got one, grab some memory for software state. */
264 central_bus
= (struct linux_central
*)
265 central_alloc_bootmem(sizeof(struct linux_central
));
266 if (central_bus
== NULL
) {
267 prom_printf("central_probe: Cannot alloc central_bus.\n");
271 fhc
= (struct linux_fhc
*)
272 central_alloc_bootmem(sizeof(struct linux_fhc
));
274 prom_printf("central_probe: Cannot alloc central fhc.\n");
278 /* First init central. */
279 central_bus
->child
= fhc
;
280 central_bus
->prom_node
= cnode
;
282 prom_getstring(cnode
, "name", namebuf
, sizeof(namebuf
));
283 strcpy(central_bus
->prom_name
, namebuf
);
285 central_ranges_init(cnode
, central_bus
);
287 /* And then central's FHC. */
288 fhc
->next
= fhc_list
;
291 fhc
->parent
= central_bus
;
292 fnode
= prom_searchsiblings(prom_getchild(cnode
), "fhc");
293 if(fnode
== 0 || fnode
== -1) {
294 prom_printf("Critical error, central board lacks fhc.\n");
297 fhc
->prom_node
= fnode
;
298 prom_getstring(fnode
, "name", namebuf
, sizeof(namebuf
));
299 strcpy(fhc
->prom_name
, namebuf
);
301 fhc_ranges_init(fnode
, fhc
);
303 /* Now, map in FHC register set. */
304 if (prom_getproperty(fnode
, "reg", (char *)&fpregs
[0], sizeof(fpregs
)) == -1) {
305 prom_printf("CENTRAL: Fatal error, cannot get fhc regs.\n");
308 apply_central_ranges(central_bus
, &fpregs
[0], 6);
310 fhc
->fhc_regs
.pregs
= ((((unsigned long)fpregs
[0].which_io
)<<32UL) |
311 ((unsigned long)fpregs
[0].phys_addr
));
312 fhc
->fhc_regs
.ireg
= ((((unsigned long)fpregs
[1].which_io
)<<32UL) |
313 ((unsigned long)fpregs
[1].phys_addr
));
314 fhc
->fhc_regs
.ffregs
= ((((unsigned long)fpregs
[2].which_io
)<<32UL) |
315 ((unsigned long)fpregs
[2].phys_addr
));
316 fhc
->fhc_regs
.sregs
= ((((unsigned long)fpregs
[3].which_io
)<<32UL) |
317 ((unsigned long)fpregs
[3].phys_addr
));
318 fhc
->fhc_regs
.uregs
= ((((unsigned long)fpregs
[4].which_io
)<<32UL) |
319 ((unsigned long)fpregs
[4].phys_addr
));
320 fhc
->fhc_regs
.tregs
= ((((unsigned long)fpregs
[5].which_io
)<<32UL) |
321 ((unsigned long)fpregs
[5].phys_addr
));
323 /* Obtain board number from board status register, Central's
324 * FHC lacks "board#" property.
326 err
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_BSR
);
327 fhc
->board
= (((err
>> 16) & 0x01) |
328 ((err
>> 12) & 0x0e));
330 fhc
->jtag_master
= 0;
332 /* Attach the clock board registers for CENTRAL. */
333 probe_clock_board(central_bus
, fhc
, cnode
, fnode
);
335 err
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_ID
);
336 printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
338 ((err
& FHC_ID_VERS
) >> 28),
339 ((err
& FHC_ID_PARTID
) >> 12),
340 ((err
& FHC_ID_MANUF
) >> 1));
345 static __inline__
void fhc_ledblink(struct linux_fhc
*fhc
, int on
)
349 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
351 /* NOTE: reverse logic on this bit */
353 tmp
&= ~(FHC_CONTROL_RLED
);
355 tmp
|= FHC_CONTROL_RLED
;
356 tmp
&= ~(FHC_CONTROL_AOFF
| FHC_CONTROL_BOFF
| FHC_CONTROL_SLINE
);
358 upa_writel(tmp
, fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
359 upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
362 static __inline__
void central_ledblink(struct linux_central
*central
, int on
)
366 tmp
= upa_readb(central
->clkregs
+ CLOCK_CTRL
);
368 /* NOTE: reverse logic on this bit */
370 tmp
&= ~(CLOCK_CTRL_RLED
);
372 tmp
|= CLOCK_CTRL_RLED
;
374 upa_writeb(tmp
, central
->clkregs
+ CLOCK_CTRL
);
375 upa_readb(central
->clkregs
+ CLOCK_CTRL
);
378 static struct timer_list sftimer
;
379 static int led_state
;
381 static void sunfire_timer(unsigned long __ignored
)
383 struct linux_fhc
*fhc
;
385 central_ledblink(central_bus
, led_state
);
386 for(fhc
= fhc_list
; fhc
!= NULL
; fhc
= fhc
->next
)
387 if(! IS_CENTRAL_FHC(fhc
))
388 fhc_ledblink(fhc
, led_state
);
389 led_state
= ! led_state
;
390 sftimer
.expires
= jiffies
+ (HZ
>> 1);
394 /* After PCI/SBUS busses have been probed, this is called to perform
395 * final initialization of all FireHose Controllers in the system.
397 void firetruck_init(void)
399 struct linux_central
*central
= central_bus
;
400 struct linux_fhc
*fhc
;
403 /* No central bus, nothing to do. */
407 for(fhc
= fhc_list
; fhc
!= NULL
; fhc
= fhc
->next
) {
410 /* Clear all of the interrupt mapping registers
411 * just in case OBP left them in a foul state.
413 #define ZAP(ICLR, IMAP) \
415 upa_writel(0, (ICLR)); \
417 imap_tmp = upa_readl(IMAP); \
418 imap_tmp &= ~(0x80000000); \
419 upa_writel(imap_tmp, (IMAP)); \
423 ZAP(fhc
->fhc_regs
.ffregs
+ FHC_FFREGS_ICLR
,
424 fhc
->fhc_regs
.ffregs
+ FHC_FFREGS_IMAP
);
425 ZAP(fhc
->fhc_regs
.sregs
+ FHC_SREGS_ICLR
,
426 fhc
->fhc_regs
.sregs
+ FHC_SREGS_IMAP
);
427 ZAP(fhc
->fhc_regs
.uregs
+ FHC_UREGS_ICLR
,
428 fhc
->fhc_regs
.uregs
+ FHC_UREGS_IMAP
);
429 ZAP(fhc
->fhc_regs
.tregs
+ FHC_TREGS_ICLR
,
430 fhc
->fhc_regs
.tregs
+ FHC_TREGS_IMAP
);
434 /* Setup FHC control register. */
435 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
437 /* All non-central boards have this bit set. */
438 if(! IS_CENTRAL_FHC(fhc
))
439 tmp
|= FHC_CONTROL_IXIST
;
441 /* For all FHCs, clear the firmware synchronization
442 * line and both low power mode enables.
444 tmp
&= ~(FHC_CONTROL_AOFF
| FHC_CONTROL_BOFF
| FHC_CONTROL_SLINE
);
446 upa_writel(tmp
, fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
447 upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
450 /* OBP leaves it on, turn it off so clock board timer LED
451 * is in sync with FHC ones.
453 ctrl
= upa_readb(central
->clkregs
+ CLOCK_CTRL
);
454 ctrl
&= ~(CLOCK_CTRL_RLED
);
455 upa_writeb(ctrl
, central
->clkregs
+ CLOCK_CTRL
);
458 init_timer(&sftimer
);
460 sftimer
.function
= &sunfire_timer
;
461 sftimer
.expires
= jiffies
+ (HZ
>> 1);