diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-31 23:56:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-31 23:56:15 -0400 |
commit | b69416b51be0757c82f1c5a0a3f0995a4484dab4 (patch) | |
tree | 94e98fd171093dd4655fa773991ad771b7e43afe /arch/sparc64/kernel/central.c | |
parent | 5843492ccce3568ff6eb6efc52fb793923207d0b (diff) |
sparc64: Rewrite central driver.
This driver is now limited to just doing the basic clock board and FHC
chip initialization and registering the platform devices for the
per-board LEDs, which are driven by the new LEDS_STARFIRE driver.
The IRQ register handling is already confined purely to the device
tree code.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/central.c')
-rw-r--r-- | arch/sparc64/kernel/central.c | 616 |
1 files changed, 213 insertions, 403 deletions
diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c index 68c91b232bec..05f1c916db06 100644 --- a/arch/sparc64/kernel/central.c +++ b/arch/sparc64/kernel/central.c | |||
@@ -1,458 +1,268 @@ | |||
1 | /* central.c: Central FHC driver for Sunfire/Starfire/Wildfire. | 1 | /* central.c: Central FHC driver for Sunfire/Starfire/Wildfire. |
2 | * | 2 | * |
3 | * Copyright (C) 1997, 1999 David S. Miller (davem@davemloft.net) | 3 | * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net) |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/kernel.h> | 6 | #include <linux/kernel.h> |
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | #include <linux/string.h> | 8 | #include <linux/string.h> |
9 | #include <linux/timer.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/init.h> | 9 | #include <linux/init.h> |
13 | #include <linux/bootmem.h> | 10 | #include <linux/of_device.h> |
11 | #include <linux/platform_device.h> | ||
14 | 12 | ||
15 | #include <asm/page.h> | ||
16 | #include <asm/fhc.h> | 13 | #include <asm/fhc.h> |
17 | #include <asm/starfire.h> | 14 | #include <asm/upa.h> |
18 | 15 | ||
19 | static struct linux_central *central_bus = NULL; | 16 | struct clock_board { |
20 | static struct linux_fhc *fhc_list = NULL; | 17 | void __iomem *clock_freq_regs; |
18 | void __iomem *clock_regs; | ||
19 | void __iomem *clock_ver_reg; | ||
20 | int num_slots; | ||
21 | struct resource leds_resource; | ||
22 | struct platform_device leds_pdev; | ||
23 | }; | ||
24 | |||
25 | struct fhc { | ||
26 | void __iomem *pregs; | ||
27 | bool central; | ||
28 | bool jtag_master; | ||
29 | int board_num; | ||
30 | struct resource leds_resource; | ||
31 | struct platform_device leds_pdev; | ||
32 | }; | ||
33 | |||
34 | static int __devinit clock_board_calc_nslots(struct clock_board *p) | ||
35 | { | ||
36 | u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0; | ||
21 | 37 | ||
22 | #define IS_CENTRAL_FHC(__fhc) ((__fhc) == central_bus->child) | 38 | switch (reg) { |
39 | case 0x40: | ||
40 | return 16; | ||
23 | 41 | ||
24 | static void central_probe_failure(int line) | 42 | case 0xc0: |
25 | { | 43 | return 8; |
26 | prom_printf("CENTRAL: Critical device probe failure at central.c:%d\n", | ||
27 | line); | ||
28 | prom_halt(); | ||
29 | } | ||
30 | 44 | ||
31 | static void central_ranges_init(struct linux_central *central) | 45 | case 0x80: |
32 | { | 46 | reg = 0; |
33 | struct device_node *dp = central->prom_node; | 47 | if (p->clock_ver_reg) |
34 | const void *pval; | 48 | reg = upa_readb(p->clock_ver_reg); |
35 | int len; | 49 | if (reg) { |
36 | 50 | if (reg & 0x80) | |
37 | central->num_central_ranges = 0; | 51 | return 4; |
38 | pval = of_get_property(dp, "ranges", &len); | 52 | else |
39 | if (pval) { | 53 | return 5; |
40 | memcpy(central->central_ranges, pval, len); | 54 | } |
41 | central->num_central_ranges = | 55 | /* Fallthrough */ |
42 | (len / sizeof(struct linux_prom_ranges)); | 56 | default: |
57 | return 4; | ||
43 | } | 58 | } |
44 | } | 59 | } |
45 | 60 | ||
46 | static void fhc_ranges_init(struct linux_fhc *fhc) | 61 | static int __devinit clock_board_probe(struct of_device *op, |
62 | const struct of_device_id *match) | ||
47 | { | 63 | { |
48 | struct device_node *dp = fhc->prom_node; | 64 | struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL); |
49 | const void *pval; | 65 | int err = -ENOMEM; |
50 | int len; | ||
51 | |||
52 | fhc->num_fhc_ranges = 0; | ||
53 | pval = of_get_property(dp, "ranges", &len); | ||
54 | if (pval) { | ||
55 | memcpy(fhc->fhc_ranges, pval, len); | ||
56 | fhc->num_fhc_ranges = | ||
57 | (len / sizeof(struct linux_prom_ranges)); | ||
58 | } | ||
59 | } | ||
60 | 66 | ||
61 | /* Range application routines are exported to various drivers, | 67 | if (!p) { |
62 | * so do not __init this. | 68 | printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n"); |
63 | */ | 69 | goto out; |
64 | static void adjust_regs(struct linux_prom_registers *regp, int nregs, | ||
65 | struct linux_prom_ranges *rangep, int nranges) | ||
66 | { | ||
67 | int regc, rngc; | ||
68 | |||
69 | for (regc = 0; regc < nregs; regc++) { | ||
70 | for (rngc = 0; rngc < nranges; rngc++) | ||
71 | if (regp[regc].which_io == rangep[rngc].ot_child_space) | ||
72 | break; /* Fount it */ | ||
73 | if (rngc == nranges) /* oops */ | ||
74 | central_probe_failure(__LINE__); | ||
75 | regp[regc].which_io = rangep[rngc].ot_parent_space; | ||
76 | regp[regc].phys_addr -= rangep[rngc].ot_child_base; | ||
77 | regp[regc].phys_addr += rangep[rngc].ot_parent_base; | ||
78 | } | 70 | } |
79 | } | ||
80 | 71 | ||
81 | /* Apply probed fhc ranges to registers passed, if no ranges return. */ | 72 | p->clock_freq_regs = of_ioremap(&op->resource[0], 0, |
82 | static void apply_fhc_ranges(struct linux_fhc *fhc, | 73 | resource_size(&op->resource[0]), |
83 | struct linux_prom_registers *regs, | 74 | "clock_board_freq"); |
84 | int nregs) | 75 | if (!p->clock_freq_regs) { |
85 | { | 76 | printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n"); |
86 | if (fhc->num_fhc_ranges) | 77 | goto out_free; |
87 | adjust_regs(regs, nregs, fhc->fhc_ranges, | 78 | } |
88 | fhc->num_fhc_ranges); | ||
89 | } | ||
90 | 79 | ||
91 | /* Apply probed central ranges to registers passed, if no ranges return. */ | 80 | p->clock_regs = of_ioremap(&op->resource[1], 0, |
92 | static void apply_central_ranges(struct linux_central *central, | 81 | resource_size(&op->resource[1]), |
93 | struct linux_prom_registers *regs, int nregs) | 82 | "clock_board_regs"); |
94 | { | 83 | if (!p->clock_regs) { |
95 | if (central->num_central_ranges) | 84 | printk(KERN_ERR "clock_board: Cannot map clock_regs\n"); |
96 | adjust_regs(regs, nregs, central->central_ranges, | 85 | goto out_unmap_clock_freq_regs; |
97 | central->num_central_ranges); | 86 | } |
98 | } | ||
99 | 87 | ||
100 | static void * __init central_alloc_bootmem(unsigned long size) | 88 | if (op->resource[2].flags) { |
101 | { | 89 | p->clock_ver_reg = of_ioremap(&op->resource[2], 0, |
102 | void *ret; | 90 | resource_size(&op->resource[2]), |
91 | "clock_ver_reg"); | ||
92 | if (!p->clock_ver_reg) { | ||
93 | printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n"); | ||
94 | goto out_unmap_clock_regs; | ||
95 | } | ||
96 | } | ||
103 | 97 | ||
104 | ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL); | 98 | p->num_slots = clock_board_calc_nslots(p); |
105 | if (ret != NULL) | ||
106 | memset(ret, 0, size); | ||
107 | 99 | ||
108 | return ret; | 100 | p->leds_resource.start = (unsigned long) |
109 | } | 101 | (p->clock_regs + CLOCK_CTRL); |
102 | p->leds_resource.end = p->leds_resource.end; | ||
103 | p->leds_resource.name = "leds"; | ||
110 | 104 | ||
111 | static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r) | 105 | p->leds_pdev.name = "sunfire-clockboard-leds"; |
112 | { | 106 | p->leds_pdev.resource = &p->leds_resource; |
113 | unsigned long ret = ((unsigned long) r->which_io) << 32; | 107 | p->leds_pdev.num_resources = 1; |
108 | p->leds_pdev.dev.parent = &op->dev; | ||
114 | 109 | ||
115 | return ret | (unsigned long) r->phys_addr; | 110 | err = platform_device_register(&p->leds_pdev); |
116 | } | 111 | if (err) { |
117 | 112 | printk(KERN_ERR "clock_board: Could not register LEDS " | |
118 | static void __init probe_other_fhcs(void) | 113 | "platform device\n"); |
119 | { | 114 | goto out_unmap_clock_ver_reg; |
120 | struct device_node *dp; | ||
121 | const struct linux_prom64_registers *fpregs; | ||
122 | |||
123 | for_each_node_by_name(dp, "fhc") { | ||
124 | struct linux_fhc *fhc; | ||
125 | int board; | ||
126 | u32 tmp; | ||
127 | |||
128 | if (dp->parent && | ||
129 | dp->parent->parent != NULL) | ||
130 | continue; | ||
131 | |||
132 | fhc = (struct linux_fhc *) | ||
133 | central_alloc_bootmem(sizeof(struct linux_fhc)); | ||
134 | if (fhc == NULL) | ||
135 | central_probe_failure(__LINE__); | ||
136 | |||
137 | /* Link it into the FHC chain. */ | ||
138 | fhc->next = fhc_list; | ||
139 | fhc_list = fhc; | ||
140 | |||
141 | /* Toplevel FHCs have no parent. */ | ||
142 | fhc->parent = NULL; | ||
143 | |||
144 | fhc->prom_node = dp; | ||
145 | fhc_ranges_init(fhc); | ||
146 | |||
147 | /* Non-central FHC's have 64-bit OBP format registers. */ | ||
148 | fpregs = of_get_property(dp, "reg", NULL); | ||
149 | if (!fpregs) | ||
150 | central_probe_failure(__LINE__); | ||
151 | |||
152 | /* Only central FHC needs special ranges applied. */ | ||
153 | fhc->fhc_regs.pregs = fpregs[0].phys_addr; | ||
154 | fhc->fhc_regs.ireg = fpregs[1].phys_addr; | ||
155 | fhc->fhc_regs.ffregs = fpregs[2].phys_addr; | ||
156 | fhc->fhc_regs.sregs = fpregs[3].phys_addr; | ||
157 | fhc->fhc_regs.uregs = fpregs[4].phys_addr; | ||
158 | fhc->fhc_regs.tregs = fpregs[5].phys_addr; | ||
159 | |||
160 | board = of_getintprop_default(dp, "board#", -1); | ||
161 | fhc->board = board; | ||
162 | |||
163 | tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL); | ||
164 | if ((tmp & FHC_JTAG_CTRL_MENAB) != 0) | ||
165 | fhc->jtag_master = 1; | ||
166 | else | ||
167 | fhc->jtag_master = 0; | ||
168 | |||
169 | tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID); | ||
170 | printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n", | ||
171 | board, | ||
172 | (tmp & FHC_ID_VERS) >> 28, | ||
173 | (tmp & FHC_ID_PARTID) >> 12, | ||
174 | (tmp & FHC_ID_MANUF) >> 1, | ||
175 | (fhc->jtag_master ? "(JTAG Master)" : "")); | ||
176 | |||
177 | /* This bit must be set in all non-central FHC's in | ||
178 | * the system. When it is clear, this identifies | ||
179 | * the central board. | ||
180 | */ | ||
181 | tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); | ||
182 | tmp |= FHC_CONTROL_IXIST; | ||
183 | upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); | ||
184 | } | 115 | } |
185 | } | ||
186 | 116 | ||
187 | static void probe_clock_board(struct linux_central *central, | 117 | printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n", |
188 | struct linux_fhc *fhc, | 118 | p->num_slots); |
189 | struct device_node *fp) | ||
190 | { | ||
191 | struct device_node *dp; | ||
192 | struct linux_prom_registers cregs[3]; | ||
193 | const struct linux_prom_registers *pr; | ||
194 | int nslots, tmp, nregs; | ||
195 | |||
196 | dp = fp->child; | ||
197 | while (dp) { | ||
198 | if (!strcmp(dp->name, "clock-board")) | ||
199 | break; | ||
200 | dp = dp->sibling; | ||
201 | } | ||
202 | if (!dp) | ||
203 | central_probe_failure(__LINE__); | ||
204 | 119 | ||
205 | pr = of_get_property(dp, "reg", &nregs); | 120 | err = 0; |
206 | if (!pr) | 121 | out: |
207 | central_probe_failure(__LINE__); | 122 | return err; |
208 | 123 | ||
209 | memcpy(cregs, pr, nregs); | 124 | out_unmap_clock_ver_reg: |
210 | nregs /= sizeof(struct linux_prom_registers); | 125 | if (p->clock_ver_reg) |
126 | of_iounmap(&op->resource[2], p->clock_ver_reg, | ||
127 | resource_size(&op->resource[2])); | ||
211 | 128 | ||
212 | apply_fhc_ranges(fhc, &cregs[0], nregs); | 129 | out_unmap_clock_regs: |
213 | apply_central_ranges(central, &cregs[0], nregs); | 130 | of_iounmap(&op->resource[1], p->clock_regs, |
214 | central->cfreg = prom_reg_to_paddr(&cregs[0]); | 131 | resource_size(&op->resource[1])); |
215 | central->clkregs = prom_reg_to_paddr(&cregs[1]); | ||
216 | 132 | ||
217 | if (nregs == 2) | 133 | out_unmap_clock_freq_regs: |
218 | central->clkver = 0UL; | 134 | of_iounmap(&op->resource[0], p->clock_freq_regs, |
219 | else | 135 | resource_size(&op->resource[0])); |
220 | central->clkver = prom_reg_to_paddr(&cregs[2]); | ||
221 | 136 | ||
222 | tmp = upa_readb(central->clkregs + CLOCK_STAT1); | 137 | out_free: |
223 | tmp &= 0xc0; | 138 | kfree(p); |
224 | switch(tmp) { | 139 | goto out; |
225 | case 0x40: | ||
226 | nslots = 16; | ||
227 | break; | ||
228 | case 0xc0: | ||
229 | nslots = 8; | ||
230 | break; | ||
231 | case 0x80: | ||
232 | if (central->clkver != 0UL && | ||
233 | upa_readb(central->clkver) != 0) { | ||
234 | if ((upa_readb(central->clkver) & 0x80) != 0) | ||
235 | nslots = 4; | ||
236 | else | ||
237 | nslots = 5; | ||
238 | break; | ||
239 | } | ||
240 | default: | ||
241 | nslots = 4; | ||
242 | break; | ||
243 | }; | ||
244 | central->slots = nslots; | ||
245 | printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n", | ||
246 | central->slots, upa_readb(central->cfreg), | ||
247 | (central->clkver ? upa_readb(central->clkver) : 0x00)); | ||
248 | } | 140 | } |
249 | 141 | ||
250 | static void ZAP(unsigned long iclr, unsigned long imap) | 142 | static struct of_device_id __initdata clock_board_match[] = { |
143 | { | ||
144 | .name = "clock-board", | ||
145 | }, | ||
146 | {}, | ||
147 | }; | ||
148 | |||
149 | static struct of_platform_driver clock_board_driver = { | ||
150 | .match_table = clock_board_match, | ||
151 | .probe = clock_board_probe, | ||
152 | .driver = { | ||
153 | .name = "clock_board", | ||
154 | }, | ||
155 | }; | ||
156 | |||
157 | static int __devinit fhc_probe(struct of_device *op, | ||
158 | const struct of_device_id *match) | ||
251 | { | 159 | { |
252 | u32 imap_tmp; | 160 | struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL); |
253 | 161 | int err = -ENOMEM; | |
254 | upa_writel(0, iclr); | 162 | u32 reg; |
255 | upa_readl(iclr); | ||
256 | imap_tmp = upa_readl(imap); | ||
257 | imap_tmp &= ~(0x80000000); | ||
258 | upa_writel(imap_tmp, imap); | ||
259 | upa_readl(imap); | ||
260 | } | ||
261 | 163 | ||
262 | static void init_all_fhc_hw(void) | 164 | if (!p) { |
263 | { | 165 | printk(KERN_ERR "fhc: Cannot allocate struct fhc\n"); |
264 | struct linux_fhc *fhc; | 166 | goto out; |
265 | |||
266 | for (fhc = fhc_list; fhc != NULL; fhc = fhc->next) { | ||
267 | u32 tmp; | ||
268 | |||
269 | /* Clear all of the interrupt mapping registers | ||
270 | * just in case OBP left them in a foul state. | ||
271 | */ | ||
272 | ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR, | ||
273 | fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP); | ||
274 | ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR, | ||
275 | fhc->fhc_regs.sregs + FHC_SREGS_IMAP); | ||
276 | ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR, | ||
277 | fhc->fhc_regs.uregs + FHC_UREGS_IMAP); | ||
278 | ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR, | ||
279 | fhc->fhc_regs.tregs + FHC_TREGS_IMAP); | ||
280 | |||
281 | /* Setup FHC control register. */ | ||
282 | tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); | ||
283 | |||
284 | /* All non-central boards have this bit set. */ | ||
285 | if (! IS_CENTRAL_FHC(fhc)) | ||
286 | tmp |= FHC_CONTROL_IXIST; | ||
287 | |||
288 | /* For all FHCs, clear the firmware synchronization | ||
289 | * line and both low power mode enables. | ||
290 | */ | ||
291 | tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | | ||
292 | FHC_CONTROL_SLINE); | ||
293 | |||
294 | upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); | ||
295 | upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); | ||
296 | } | 167 | } |
297 | 168 | ||
298 | } | 169 | if (!strcmp(op->node->parent->name, "central")) |
170 | p->central = true; | ||
299 | 171 | ||
300 | void __init central_probe(void) | 172 | p->pregs = of_ioremap(&op->resource[0], 0, |
301 | { | 173 | resource_size(&op->resource[0]), |
302 | struct linux_prom_registers fpregs[6]; | 174 | "fhc_pregs"); |
303 | const struct linux_prom_registers *pr; | 175 | if (!p->pregs) { |
304 | struct linux_fhc *fhc; | 176 | printk(KERN_ERR "fhc: Cannot map pregs\n"); |
305 | struct device_node *dp, *fp; | 177 | goto out_free; |
306 | int err; | ||
307 | |||
308 | dp = of_find_node_by_name(NULL, "central"); | ||
309 | if (!dp) | ||
310 | return; | ||
311 | |||
312 | /* Ok we got one, grab some memory for software state. */ | ||
313 | central_bus = (struct linux_central *) | ||
314 | central_alloc_bootmem(sizeof(struct linux_central)); | ||
315 | if (central_bus == NULL) | ||
316 | central_probe_failure(__LINE__); | ||
317 | |||
318 | fhc = (struct linux_fhc *) | ||
319 | central_alloc_bootmem(sizeof(struct linux_fhc)); | ||
320 | if (fhc == NULL) | ||
321 | central_probe_failure(__LINE__); | ||
322 | |||
323 | /* First init central. */ | ||
324 | central_bus->child = fhc; | ||
325 | central_bus->prom_node = dp; | ||
326 | central_ranges_init(central_bus); | ||
327 | |||
328 | /* And then central's FHC. */ | ||
329 | fhc->next = fhc_list; | ||
330 | fhc_list = fhc; | ||
331 | |||
332 | fhc->parent = central_bus; | ||
333 | fp = dp->child; | ||
334 | while (fp) { | ||
335 | if (!strcmp(fp->name, "fhc")) | ||
336 | break; | ||
337 | fp = fp->sibling; | ||
338 | } | 178 | } |
339 | if (!fp) | ||
340 | central_probe_failure(__LINE__); | ||
341 | |||
342 | fhc->prom_node = fp; | ||
343 | fhc_ranges_init(fhc); | ||
344 | |||
345 | /* Now, map in FHC register set. */ | ||
346 | pr = of_get_property(fp, "reg", NULL); | ||
347 | if (!pr) | ||
348 | central_probe_failure(__LINE__); | ||
349 | memcpy(fpregs, pr, sizeof(fpregs)); | ||
350 | |||
351 | apply_central_ranges(central_bus, &fpregs[0], 6); | ||
352 | |||
353 | fhc->fhc_regs.pregs = prom_reg_to_paddr(&fpregs[0]); | ||
354 | fhc->fhc_regs.ireg = prom_reg_to_paddr(&fpregs[1]); | ||
355 | fhc->fhc_regs.ffregs = prom_reg_to_paddr(&fpregs[2]); | ||
356 | fhc->fhc_regs.sregs = prom_reg_to_paddr(&fpregs[3]); | ||
357 | fhc->fhc_regs.uregs = prom_reg_to_paddr(&fpregs[4]); | ||
358 | fhc->fhc_regs.tregs = prom_reg_to_paddr(&fpregs[5]); | ||
359 | |||
360 | /* Obtain board number from board status register, Central's | ||
361 | * FHC lacks "board#" property. | ||
362 | */ | ||
363 | err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR); | ||
364 | fhc->board = (((err >> 16) & 0x01) | | ||
365 | ((err >> 12) & 0x0e)); | ||
366 | |||
367 | fhc->jtag_master = 0; | ||
368 | |||
369 | /* Attach the clock board registers for CENTRAL. */ | ||
370 | probe_clock_board(central_bus, fhc, fp); | ||
371 | |||
372 | err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID); | ||
373 | printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n", | ||
374 | fhc->board, | ||
375 | ((err & FHC_ID_VERS) >> 28), | ||
376 | ((err & FHC_ID_PARTID) >> 12), | ||
377 | ((err & FHC_ID_MANUF) >> 1)); | ||
378 | |||
379 | probe_other_fhcs(); | ||
380 | |||
381 | init_all_fhc_hw(); | ||
382 | } | ||
383 | 179 | ||
384 | static inline void fhc_ledblink(struct linux_fhc *fhc, int on) | 180 | if (p->central) { |
385 | { | 181 | reg = upa_readl(p->pregs + FHC_PREGS_BSR); |
386 | u32 tmp; | 182 | p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e); |
183 | } else { | ||
184 | p->board_num = of_getintprop_default(op->node, "board#", -1); | ||
185 | if (p->board_num == -1) { | ||
186 | printk(KERN_ERR "fhc: No board# property\n"); | ||
187 | goto out_unmap_pregs; | ||
188 | } | ||
189 | if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB) | ||
190 | p->jtag_master = true; | ||
191 | } | ||
387 | 192 | ||
388 | tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); | 193 | if (!p->central) { |
194 | p->leds_resource.start = (unsigned long) | ||
195 | (p->pregs + FHC_PREGS_CTRL); | ||
196 | p->leds_resource.end = p->leds_resource.end; | ||
197 | p->leds_resource.name = "leds"; | ||
198 | |||
199 | p->leds_pdev.name = "sunfire-fhc-leds"; | ||
200 | p->leds_pdev.resource = &p->leds_resource; | ||
201 | p->leds_pdev.num_resources = 1; | ||
202 | p->leds_pdev.dev.parent = &op->dev; | ||
203 | |||
204 | err = platform_device_register(&p->leds_pdev); | ||
205 | if (err) { | ||
206 | printk(KERN_ERR "fhc: Could not register LEDS " | ||
207 | "platform device\n"); | ||
208 | goto out_unmap_pregs; | ||
209 | } | ||
210 | } | ||
211 | reg = upa_readl(p->pregs + FHC_PREGS_CTRL); | ||
389 | 212 | ||
390 | /* NOTE: reverse logic on this bit */ | 213 | if (!p->central) |
391 | if (on) | 214 | reg |= FHC_CONTROL_IXIST; |
392 | tmp &= ~(FHC_CONTROL_RLED); | ||
393 | else | ||
394 | tmp |= FHC_CONTROL_RLED; | ||
395 | tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE); | ||
396 | 215 | ||
397 | upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL); | 216 | reg &= ~(FHC_CONTROL_AOFF | |
398 | upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL); | 217 | FHC_CONTROL_BOFF | |
399 | } | 218 | FHC_CONTROL_SLINE); |
400 | 219 | ||
401 | static inline void central_ledblink(struct linux_central *central, int on) | 220 | upa_writel(reg, p->pregs + FHC_PREGS_CTRL); |
402 | { | 221 | upa_readl(p->pregs + FHC_PREGS_CTRL); |
403 | u8 tmp; | ||
404 | 222 | ||
405 | tmp = upa_readb(central->clkregs + CLOCK_CTRL); | 223 | reg = upa_readl(p->pregs + FHC_PREGS_ID); |
224 | printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n", | ||
225 | p->board_num, | ||
226 | (reg & FHC_ID_VERS) >> 28, | ||
227 | (reg & FHC_ID_PARTID) >> 12, | ||
228 | (reg & FHC_ID_MANUF) >> 1, | ||
229 | (p->jtag_master ? | ||
230 | "(JTAG Master)" : | ||
231 | (p->central ? "(Central)" : ""))); | ||
406 | 232 | ||
407 | /* NOTE: reverse logic on this bit */ | 233 | err = 0; |
408 | if (on) | ||
409 | tmp &= ~(CLOCK_CTRL_RLED); | ||
410 | else | ||
411 | tmp |= CLOCK_CTRL_RLED; | ||
412 | 234 | ||
413 | upa_writeb(tmp, central->clkregs + CLOCK_CTRL); | 235 | out: |
414 | upa_readb(central->clkregs + CLOCK_CTRL); | 236 | return err; |
415 | } | ||
416 | 237 | ||
417 | static struct timer_list sftimer; | 238 | out_unmap_pregs: |
418 | static int led_state; | 239 | of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0])); |
419 | 240 | ||
420 | static void sunfire_timer(unsigned long __ignored) | 241 | out_free: |
421 | { | 242 | kfree(p); |
422 | struct linux_fhc *fhc; | 243 | goto out; |
423 | |||
424 | central_ledblink(central_bus, led_state); | ||
425 | for (fhc = fhc_list; fhc != NULL; fhc = fhc->next) | ||
426 | if (! IS_CENTRAL_FHC(fhc)) | ||
427 | fhc_ledblink(fhc, led_state); | ||
428 | led_state = ! led_state; | ||
429 | sftimer.expires = jiffies + (HZ >> 1); | ||
430 | add_timer(&sftimer); | ||
431 | } | 244 | } |
432 | 245 | ||
433 | /* After PCI/SBUS busses have been probed, this is called to perform | 246 | static struct of_device_id __initdata fhc_match[] = { |
434 | * final initialization of all FireHose Controllers in the system. | 247 | { |
435 | */ | 248 | .name = "fhc", |
436 | void firetruck_init(void) | 249 | }, |
250 | {}, | ||
251 | }; | ||
252 | |||
253 | static struct of_platform_driver fhc_driver = { | ||
254 | .match_table = fhc_match, | ||
255 | .probe = fhc_probe, | ||
256 | .driver = { | ||
257 | .name = "fhc", | ||
258 | }, | ||
259 | }; | ||
260 | |||
261 | static int __init sunfire_init(void) | ||
437 | { | 262 | { |
438 | struct linux_central *central = central_bus; | 263 | (void) of_register_driver(&fhc_driver, &of_platform_bus_type); |
439 | u8 ctrl; | 264 | (void) of_register_driver(&clock_board_driver, &of_platform_bus_type); |
440 | 265 | return 0; | |
441 | /* No central bus, nothing to do. */ | ||
442 | if (central == NULL) | ||
443 | return; | ||
444 | |||
445 | /* OBP leaves it on, turn it off so clock board timer LED | ||
446 | * is in sync with FHC ones. | ||
447 | */ | ||
448 | ctrl = upa_readb(central->clkregs + CLOCK_CTRL); | ||
449 | ctrl &= ~(CLOCK_CTRL_RLED); | ||
450 | upa_writeb(ctrl, central->clkregs + CLOCK_CTRL); | ||
451 | |||
452 | led_state = 0; | ||
453 | init_timer(&sftimer); | ||
454 | sftimer.data = 0; | ||
455 | sftimer.function = &sunfire_timer; | ||
456 | sftimer.expires = jiffies + (HZ >> 1); | ||
457 | add_timer(&sftimer); | ||
458 | } | 266 | } |
267 | |||
268 | subsys_initcall(sunfire_init); | ||