1 /* $Id: central.c,v 1.15 2001/12/19 00:29:51 davem 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 void central_probe_failure(int line
)
27 prom_printf("CENTRAL: Critical device probe failure at central.c:%d\n",
32 static void central_ranges_init(struct linux_central
*central
)
34 struct device_node
*dp
= central
->prom_node
;
38 central
->num_central_ranges
= 0;
39 pval
= of_get_property(dp
, "ranges", &len
);
41 memcpy(central
->central_ranges
, pval
, len
);
42 central
->num_central_ranges
=
43 (len
/ sizeof(struct linux_prom_ranges
));
47 static void fhc_ranges_init(struct linux_fhc
*fhc
)
49 struct device_node
*dp
= fhc
->prom_node
;
53 fhc
->num_fhc_ranges
= 0;
54 pval
= of_get_property(dp
, "ranges", &len
);
56 memcpy(fhc
->fhc_ranges
, pval
, len
);
58 (len
/ sizeof(struct linux_prom_ranges
));
62 /* Range application routines are exported to various drivers,
63 * so do not __init this.
65 static void adjust_regs(struct linux_prom_registers
*regp
, int nregs
,
66 struct linux_prom_ranges
*rangep
, int nranges
)
70 for (regc
= 0; regc
< nregs
; regc
++) {
71 for (rngc
= 0; rngc
< nranges
; rngc
++)
72 if (regp
[regc
].which_io
== rangep
[rngc
].ot_child_space
)
74 if (rngc
== nranges
) /* oops */
75 central_probe_failure(__LINE__
);
76 regp
[regc
].which_io
= rangep
[rngc
].ot_parent_space
;
77 regp
[regc
].phys_addr
-= rangep
[rngc
].ot_child_base
;
78 regp
[regc
].phys_addr
+= rangep
[rngc
].ot_parent_base
;
82 /* Apply probed fhc ranges to registers passed, if no ranges return. */
83 void apply_fhc_ranges(struct linux_fhc
*fhc
,
84 struct linux_prom_registers
*regs
,
87 if (fhc
->num_fhc_ranges
)
88 adjust_regs(regs
, nregs
, fhc
->fhc_ranges
,
92 /* Apply probed central ranges to registers passed, if no ranges return. */
93 void apply_central_ranges(struct linux_central
*central
,
94 struct linux_prom_registers
*regs
, int nregs
)
96 if (central
->num_central_ranges
)
97 adjust_regs(regs
, nregs
, central
->central_ranges
,
98 central
->num_central_ranges
);
101 static void * __init
central_alloc_bootmem(unsigned long size
)
105 ret
= __alloc_bootmem(size
, SMP_CACHE_BYTES
, 0UL);
107 memset(ret
, 0, size
);
112 static unsigned long prom_reg_to_paddr(struct linux_prom_registers
*r
)
114 unsigned long ret
= ((unsigned long) r
->which_io
) << 32;
116 return ret
| (unsigned long) r
->phys_addr
;
119 static void __init
probe_other_fhcs(void)
121 struct device_node
*dp
;
122 const struct linux_prom64_registers
*fpregs
;
124 for_each_node_by_name(dp
, "fhc") {
125 struct linux_fhc
*fhc
;
130 dp
->parent
->parent
!= NULL
)
133 fhc
= (struct linux_fhc
*)
134 central_alloc_bootmem(sizeof(struct linux_fhc
));
136 central_probe_failure(__LINE__
);
138 /* Link it into the FHC chain. */
139 fhc
->next
= fhc_list
;
142 /* Toplevel FHCs have no parent. */
146 fhc_ranges_init(fhc
);
148 /* Non-central FHC's have 64-bit OBP format registers. */
149 fpregs
= of_get_property(dp
, "reg", NULL
);
151 central_probe_failure(__LINE__
);
153 /* Only central FHC needs special ranges applied. */
154 fhc
->fhc_regs
.pregs
= fpregs
[0].phys_addr
;
155 fhc
->fhc_regs
.ireg
= fpregs
[1].phys_addr
;
156 fhc
->fhc_regs
.ffregs
= fpregs
[2].phys_addr
;
157 fhc
->fhc_regs
.sregs
= fpregs
[3].phys_addr
;
158 fhc
->fhc_regs
.uregs
= fpregs
[4].phys_addr
;
159 fhc
->fhc_regs
.tregs
= fpregs
[5].phys_addr
;
161 board
= of_getintprop_default(dp
, "board#", -1);
164 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_JCTRL
);
165 if ((tmp
& FHC_JTAG_CTRL_MENAB
) != 0)
166 fhc
->jtag_master
= 1;
168 fhc
->jtag_master
= 0;
170 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_ID
);
171 printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n",
173 (tmp
& FHC_ID_VERS
) >> 28,
174 (tmp
& FHC_ID_PARTID
) >> 12,
175 (tmp
& FHC_ID_MANUF
) >> 1,
176 (fhc
->jtag_master
? "(JTAG Master)" : ""));
178 /* This bit must be set in all non-central FHC's in
179 * the system. When it is clear, this identifies
182 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
183 tmp
|= FHC_CONTROL_IXIST
;
184 upa_writel(tmp
, fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
188 static void probe_clock_board(struct linux_central
*central
,
189 struct linux_fhc
*fhc
,
190 struct device_node
*fp
)
192 struct device_node
*dp
;
193 struct linux_prom_registers cregs
[3];
194 const struct linux_prom_registers
*pr
;
195 int nslots
, tmp
, nregs
;
199 if (!strcmp(dp
->name
, "clock-board"))
204 central_probe_failure(__LINE__
);
206 pr
= of_get_property(dp
, "reg", &nregs
);
208 central_probe_failure(__LINE__
);
210 memcpy(cregs
, pr
, nregs
);
211 nregs
/= sizeof(struct linux_prom_registers
);
213 apply_fhc_ranges(fhc
, &cregs
[0], nregs
);
214 apply_central_ranges(central
, &cregs
[0], nregs
);
215 central
->cfreg
= prom_reg_to_paddr(&cregs
[0]);
216 central
->clkregs
= prom_reg_to_paddr(&cregs
[1]);
219 central
->clkver
= 0UL;
221 central
->clkver
= prom_reg_to_paddr(&cregs
[2]);
223 tmp
= upa_readb(central
->clkregs
+ CLOCK_STAT1
);
233 if (central
->clkver
!= 0UL &&
234 upa_readb(central
->clkver
) != 0) {
235 if ((upa_readb(central
->clkver
) & 0x80) != 0)
245 central
->slots
= nslots
;
246 printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n",
247 central
->slots
, upa_readb(central
->cfreg
),
248 (central
->clkver
? upa_readb(central
->clkver
) : 0x00));
251 static void ZAP(unsigned long iclr
, unsigned long imap
)
257 imap_tmp
= upa_readl(imap
);
258 imap_tmp
&= ~(0x80000000);
259 upa_writel(imap_tmp
, imap
);
263 static void init_all_fhc_hw(void)
265 struct linux_fhc
*fhc
;
267 for (fhc
= fhc_list
; fhc
!= NULL
; fhc
= fhc
->next
) {
270 /* Clear all of the interrupt mapping registers
271 * just in case OBP left them in a foul state.
273 ZAP(fhc
->fhc_regs
.ffregs
+ FHC_FFREGS_ICLR
,
274 fhc
->fhc_regs
.ffregs
+ FHC_FFREGS_IMAP
);
275 ZAP(fhc
->fhc_regs
.sregs
+ FHC_SREGS_ICLR
,
276 fhc
->fhc_regs
.sregs
+ FHC_SREGS_IMAP
);
277 ZAP(fhc
->fhc_regs
.uregs
+ FHC_UREGS_ICLR
,
278 fhc
->fhc_regs
.uregs
+ FHC_UREGS_IMAP
);
279 ZAP(fhc
->fhc_regs
.tregs
+ FHC_TREGS_ICLR
,
280 fhc
->fhc_regs
.tregs
+ FHC_TREGS_IMAP
);
282 /* Setup FHC control register. */
283 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
285 /* All non-central boards have this bit set. */
286 if (! IS_CENTRAL_FHC(fhc
))
287 tmp
|= FHC_CONTROL_IXIST
;
289 /* For all FHCs, clear the firmware synchronization
290 * line and both low power mode enables.
292 tmp
&= ~(FHC_CONTROL_AOFF
| FHC_CONTROL_BOFF
|
295 upa_writel(tmp
, fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
296 upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
301 void __init
central_probe(void)
303 struct linux_prom_registers fpregs
[6];
304 const struct linux_prom_registers
*pr
;
305 struct linux_fhc
*fhc
;
306 struct device_node
*dp
, *fp
;
309 dp
= of_find_node_by_name(NULL
, "central");
311 if (this_is_starfire
)
312 starfire_cpu_setup();
316 /* Ok we got one, grab some memory for software state. */
317 central_bus
= (struct linux_central
*)
318 central_alloc_bootmem(sizeof(struct linux_central
));
319 if (central_bus
== NULL
)
320 central_probe_failure(__LINE__
);
322 fhc
= (struct linux_fhc
*)
323 central_alloc_bootmem(sizeof(struct linux_fhc
));
325 central_probe_failure(__LINE__
);
327 /* First init central. */
328 central_bus
->child
= fhc
;
329 central_bus
->prom_node
= dp
;
330 central_ranges_init(central_bus
);
332 /* And then central's FHC. */
333 fhc
->next
= fhc_list
;
336 fhc
->parent
= central_bus
;
339 if (!strcmp(fp
->name
, "fhc"))
344 central_probe_failure(__LINE__
);
347 fhc_ranges_init(fhc
);
349 /* Now, map in FHC register set. */
350 pr
= of_get_property(fp
, "reg", NULL
);
352 central_probe_failure(__LINE__
);
353 memcpy(fpregs
, pr
, sizeof(fpregs
));
355 apply_central_ranges(central_bus
, &fpregs
[0], 6);
357 fhc
->fhc_regs
.pregs
= prom_reg_to_paddr(&fpregs
[0]);
358 fhc
->fhc_regs
.ireg
= prom_reg_to_paddr(&fpregs
[1]);
359 fhc
->fhc_regs
.ffregs
= prom_reg_to_paddr(&fpregs
[2]);
360 fhc
->fhc_regs
.sregs
= prom_reg_to_paddr(&fpregs
[3]);
361 fhc
->fhc_regs
.uregs
= prom_reg_to_paddr(&fpregs
[4]);
362 fhc
->fhc_regs
.tregs
= prom_reg_to_paddr(&fpregs
[5]);
364 /* Obtain board number from board status register, Central's
365 * FHC lacks "board#" property.
367 err
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_BSR
);
368 fhc
->board
= (((err
>> 16) & 0x01) |
369 ((err
>> 12) & 0x0e));
371 fhc
->jtag_master
= 0;
373 /* Attach the clock board registers for CENTRAL. */
374 probe_clock_board(central_bus
, fhc
, fp
);
376 err
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_ID
);
377 printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
379 ((err
& FHC_ID_VERS
) >> 28),
380 ((err
& FHC_ID_PARTID
) >> 12),
381 ((err
& FHC_ID_MANUF
) >> 1));
388 static __inline__
void fhc_ledblink(struct linux_fhc
*fhc
, int on
)
392 tmp
= upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
394 /* NOTE: reverse logic on this bit */
396 tmp
&= ~(FHC_CONTROL_RLED
);
398 tmp
|= FHC_CONTROL_RLED
;
399 tmp
&= ~(FHC_CONTROL_AOFF
| FHC_CONTROL_BOFF
| FHC_CONTROL_SLINE
);
401 upa_writel(tmp
, fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
402 upa_readl(fhc
->fhc_regs
.pregs
+ FHC_PREGS_CTRL
);
405 static __inline__
void central_ledblink(struct linux_central
*central
, int on
)
409 tmp
= upa_readb(central
->clkregs
+ CLOCK_CTRL
);
411 /* NOTE: reverse logic on this bit */
413 tmp
&= ~(CLOCK_CTRL_RLED
);
415 tmp
|= CLOCK_CTRL_RLED
;
417 upa_writeb(tmp
, central
->clkregs
+ CLOCK_CTRL
);
418 upa_readb(central
->clkregs
+ CLOCK_CTRL
);
421 static struct timer_list sftimer
;
422 static int led_state
;
424 static void sunfire_timer(unsigned long __ignored
)
426 struct linux_fhc
*fhc
;
428 central_ledblink(central_bus
, led_state
);
429 for (fhc
= fhc_list
; fhc
!= NULL
; fhc
= fhc
->next
)
430 if (! IS_CENTRAL_FHC(fhc
))
431 fhc_ledblink(fhc
, led_state
);
432 led_state
= ! led_state
;
433 sftimer
.expires
= jiffies
+ (HZ
>> 1);
437 /* After PCI/SBUS busses have been probed, this is called to perform
438 * final initialization of all FireHose Controllers in the system.
440 void firetruck_init(void)
442 struct linux_central
*central
= central_bus
;
445 /* No central bus, nothing to do. */
449 /* OBP leaves it on, turn it off so clock board timer LED
450 * is in sync with FHC ones.
452 ctrl
= upa_readb(central
->clkregs
+ CLOCK_CTRL
);
453 ctrl
&= ~(CLOCK_CTRL_RLED
);
454 upa_writeb(ctrl
, central
->clkregs
+ CLOCK_CTRL
);
457 init_timer(&sftimer
);
459 sftimer
.function
= &sunfire_timer
;
460 sftimer
.expires
= jiffies
+ (HZ
>> 1);