diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc64/kernel/pmac_feature.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc64/kernel/pmac_feature.c')
-rw-r--r-- | arch/ppc64/kernel/pmac_feature.c | 676 |
1 files changed, 676 insertions, 0 deletions
diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c new file mode 100644 index 000000000000..7f1062d222c9 --- /dev/null +++ b/arch/ppc64/kernel/pmac_feature.c | |||
@@ -0,0 +1,676 @@ | |||
1 | /* | ||
2 | * arch/ppc/platforms/pmac_feature.c | ||
3 | * | ||
4 | * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au) | ||
5 | * Ben. Herrenschmidt (benh@kernel.crashing.org) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | * TODO: | ||
13 | * | ||
14 | * - Replace mdelay with some schedule loop if possible | ||
15 | * - Shorten some obfuscated delays on some routines (like modem | ||
16 | * power) | ||
17 | * - Refcount some clocks (see darwin) | ||
18 | * - Split split split... | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/config.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/adb.h> | ||
29 | #include <linux/pmu.h> | ||
30 | #include <linux/ioport.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <asm/sections.h> | ||
33 | #include <asm/errno.h> | ||
34 | #include <asm/keylargo.h> | ||
35 | #include <asm/uninorth.h> | ||
36 | #include <asm/io.h> | ||
37 | #include <asm/prom.h> | ||
38 | #include <asm/machdep.h> | ||
39 | #include <asm/pmac_feature.h> | ||
40 | #include <asm/dbdma.h> | ||
41 | #include <asm/pci-bridge.h> | ||
42 | #include <asm/pmac_low_i2c.h> | ||
43 | |||
44 | #undef DEBUG_FEATURE | ||
45 | |||
46 | #ifdef DEBUG_FEATURE | ||
47 | #define DBG(fmt...) printk(KERN_DEBUG fmt) | ||
48 | #else | ||
49 | #define DBG(fmt...) | ||
50 | #endif | ||
51 | |||
52 | /* | ||
53 | * We use a single global lock to protect accesses. Each driver has | ||
54 | * to take care of its own locking | ||
55 | */ | ||
56 | static DEFINE_SPINLOCK(feature_lock __pmacdata); | ||
57 | |||
58 | #define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); | ||
59 | #define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); | ||
60 | |||
61 | |||
62 | /* | ||
63 | * Instance of some macio stuffs | ||
64 | */ | ||
65 | struct macio_chip macio_chips[MAX_MACIO_CHIPS] __pmacdata; | ||
66 | |||
67 | struct macio_chip* __pmac | ||
68 | macio_find(struct device_node* child, int type) | ||
69 | { | ||
70 | while(child) { | ||
71 | int i; | ||
72 | |||
73 | for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++) | ||
74 | if (child == macio_chips[i].of_node && | ||
75 | (!type || macio_chips[i].type == type)) | ||
76 | return &macio_chips[i]; | ||
77 | child = child->parent; | ||
78 | } | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | static const char* macio_names[] __pmacdata = | ||
83 | { | ||
84 | "Unknown", | ||
85 | "Grand Central", | ||
86 | "OHare", | ||
87 | "OHareII", | ||
88 | "Heathrow", | ||
89 | "Gatwick", | ||
90 | "Paddington", | ||
91 | "Keylargo", | ||
92 | "Pangea", | ||
93 | "Intrepid", | ||
94 | "K2" | ||
95 | }; | ||
96 | |||
97 | |||
98 | |||
99 | /* | ||
100 | * Uninorth reg. access. Note that Uni-N regs are big endian | ||
101 | */ | ||
102 | |||
103 | #define UN_REG(r) (uninorth_base + ((r) >> 2)) | ||
104 | #define UN_IN(r) (in_be32(UN_REG(r))) | ||
105 | #define UN_OUT(r,v) (out_be32(UN_REG(r), (v))) | ||
106 | #define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v))) | ||
107 | #define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v))) | ||
108 | |||
109 | static struct device_node* uninorth_node __pmacdata; | ||
110 | static u32* uninorth_base __pmacdata; | ||
111 | static u32 uninorth_rev __pmacdata; | ||
112 | static void *u3_ht; | ||
113 | |||
114 | extern struct device_node *k2_skiplist[2]; | ||
115 | |||
116 | /* | ||
117 | * For each motherboard family, we have a table of functions pointers | ||
118 | * that handle the various features. | ||
119 | */ | ||
120 | |||
121 | typedef long (*feature_call)(struct device_node* node, long param, long value); | ||
122 | |||
123 | struct feature_table_entry { | ||
124 | unsigned int selector; | ||
125 | feature_call function; | ||
126 | }; | ||
127 | |||
128 | struct pmac_mb_def | ||
129 | { | ||
130 | const char* model_string; | ||
131 | const char* model_name; | ||
132 | int model_id; | ||
133 | struct feature_table_entry* features; | ||
134 | unsigned long board_flags; | ||
135 | }; | ||
136 | static struct pmac_mb_def pmac_mb __pmacdata; | ||
137 | |||
138 | /* | ||
139 | * Here are the chip specific feature functions | ||
140 | */ | ||
141 | |||
142 | |||
143 | static long __pmac g5_read_gpio(struct device_node* node, long param, long value) | ||
144 | { | ||
145 | struct macio_chip* macio = &macio_chips[0]; | ||
146 | |||
147 | return MACIO_IN8(param); | ||
148 | } | ||
149 | |||
150 | |||
151 | static long __pmac g5_write_gpio(struct device_node* node, long param, long value) | ||
152 | { | ||
153 | struct macio_chip* macio = &macio_chips[0]; | ||
154 | |||
155 | MACIO_OUT8(param, (u8)(value & 0xff)); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static long __pmac g5_gmac_enable(struct device_node* node, long param, long value) | ||
160 | { | ||
161 | struct macio_chip* macio = &macio_chips[0]; | ||
162 | unsigned long flags; | ||
163 | |||
164 | if (node == NULL) | ||
165 | return -ENODEV; | ||
166 | |||
167 | LOCK(flags); | ||
168 | if (value) { | ||
169 | MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); | ||
170 | mb(); | ||
171 | k2_skiplist[0] = NULL; | ||
172 | } else { | ||
173 | k2_skiplist[0] = node; | ||
174 | mb(); | ||
175 | MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); | ||
176 | } | ||
177 | |||
178 | UNLOCK(flags); | ||
179 | mdelay(1); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static long __pmac g5_fw_enable(struct device_node* node, long param, long value) | ||
185 | { | ||
186 | struct macio_chip* macio = &macio_chips[0]; | ||
187 | unsigned long flags; | ||
188 | |||
189 | if (node == NULL) | ||
190 | return -ENODEV; | ||
191 | |||
192 | LOCK(flags); | ||
193 | if (value) { | ||
194 | MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); | ||
195 | mb(); | ||
196 | k2_skiplist[1] = NULL; | ||
197 | } else { | ||
198 | k2_skiplist[1] = node; | ||
199 | mb(); | ||
200 | MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); | ||
201 | } | ||
202 | |||
203 | UNLOCK(flags); | ||
204 | mdelay(1); | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | static long __pmac g5_mpic_enable(struct device_node* node, long param, long value) | ||
210 | { | ||
211 | unsigned long flags; | ||
212 | |||
213 | if (node->parent == NULL || strcmp(node->parent->name, "u3")) | ||
214 | return 0; | ||
215 | |||
216 | LOCK(flags); | ||
217 | UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE); | ||
218 | UNLOCK(flags); | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static long __pmac g5_eth_phy_reset(struct device_node* node, long param, long value) | ||
224 | { | ||
225 | struct macio_chip* macio = &macio_chips[0]; | ||
226 | struct device_node *phy; | ||
227 | int need_reset; | ||
228 | |||
229 | /* | ||
230 | * We must not reset the combo PHYs, only the BCM5221 found in | ||
231 | * the iMac G5. | ||
232 | */ | ||
233 | phy = of_get_next_child(node, NULL); | ||
234 | if (!phy) | ||
235 | return -ENODEV; | ||
236 | need_reset = device_is_compatible(phy, "B5221"); | ||
237 | of_node_put(phy); | ||
238 | if (!need_reset) | ||
239 | return 0; | ||
240 | |||
241 | /* PHY reset is GPIO 29, not in device-tree unfortunately */ | ||
242 | MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, | ||
243 | KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); | ||
244 | /* Thankfully, this is now always called at a time when we can | ||
245 | * schedule by sungem. | ||
246 | */ | ||
247 | msleep(10); | ||
248 | MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0); | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | #ifdef CONFIG_SMP | ||
254 | static long __pmac g5_reset_cpu(struct device_node* node, long param, long value) | ||
255 | { | ||
256 | unsigned int reset_io = 0; | ||
257 | unsigned long flags; | ||
258 | struct macio_chip* macio; | ||
259 | struct device_node* np; | ||
260 | |||
261 | macio = &macio_chips[0]; | ||
262 | if (macio->type != macio_keylargo2) | ||
263 | return -ENODEV; | ||
264 | |||
265 | np = find_path_device("/cpus"); | ||
266 | if (np == NULL) | ||
267 | return -ENODEV; | ||
268 | for (np = np->child; np != NULL; np = np->sibling) { | ||
269 | u32* num = (u32 *)get_property(np, "reg", NULL); | ||
270 | u32* rst = (u32 *)get_property(np, "soft-reset", NULL); | ||
271 | if (num == NULL || rst == NULL) | ||
272 | continue; | ||
273 | if (param == *num) { | ||
274 | reset_io = *rst; | ||
275 | break; | ||
276 | } | ||
277 | } | ||
278 | if (np == NULL || reset_io == 0) | ||
279 | return -ENODEV; | ||
280 | |||
281 | LOCK(flags); | ||
282 | MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); | ||
283 | (void)MACIO_IN8(reset_io); | ||
284 | udelay(1); | ||
285 | MACIO_OUT8(reset_io, 0); | ||
286 | (void)MACIO_IN8(reset_io); | ||
287 | UNLOCK(flags); | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | #endif /* CONFIG_SMP */ | ||
292 | |||
293 | /* | ||
294 | * This can be called from pmac_smp so isn't static | ||
295 | * | ||
296 | * This takes the second CPU off the bus on dual CPU machines | ||
297 | * running UP | ||
298 | */ | ||
299 | void __pmac g5_phy_disable_cpu1(void) | ||
300 | { | ||
301 | UN_OUT(U3_API_PHY_CONFIG_1, 0); | ||
302 | } | ||
303 | |||
304 | static long __pmac generic_get_mb_info(struct device_node* node, long param, long value) | ||
305 | { | ||
306 | switch(param) { | ||
307 | case PMAC_MB_INFO_MODEL: | ||
308 | return pmac_mb.model_id; | ||
309 | case PMAC_MB_INFO_FLAGS: | ||
310 | return pmac_mb.board_flags; | ||
311 | case PMAC_MB_INFO_NAME: | ||
312 | /* hack hack hack... but should work */ | ||
313 | *((const char **)value) = pmac_mb.model_name; | ||
314 | return 0; | ||
315 | } | ||
316 | return -EINVAL; | ||
317 | } | ||
318 | |||
319 | |||
320 | /* | ||
321 | * Table definitions | ||
322 | */ | ||
323 | |||
324 | /* Used on any machine | ||
325 | */ | ||
326 | static struct feature_table_entry any_features[] __pmacdata = { | ||
327 | { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, | ||
328 | { 0, NULL } | ||
329 | }; | ||
330 | |||
331 | /* G5 features | ||
332 | */ | ||
333 | static struct feature_table_entry g5_features[] __pmacdata = { | ||
334 | { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, | ||
335 | { PMAC_FTR_1394_ENABLE, g5_fw_enable }, | ||
336 | { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable }, | ||
337 | { PMAC_FTR_READ_GPIO, g5_read_gpio }, | ||
338 | { PMAC_FTR_WRITE_GPIO, g5_write_gpio }, | ||
339 | { PMAC_FTR_GMAC_PHY_RESET, g5_eth_phy_reset }, | ||
340 | #ifdef CONFIG_SMP | ||
341 | { PMAC_FTR_RESET_CPU, g5_reset_cpu }, | ||
342 | #endif /* CONFIG_SMP */ | ||
343 | { 0, NULL } | ||
344 | }; | ||
345 | |||
346 | static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { | ||
347 | { "PowerMac7,2", "PowerMac G5", | ||
348 | PMAC_TYPE_POWERMAC_G5, g5_features, | ||
349 | 0, | ||
350 | }, | ||
351 | { "PowerMac7,3", "PowerMac G5", | ||
352 | PMAC_TYPE_POWERMAC_G5, g5_features, | ||
353 | 0, | ||
354 | }, | ||
355 | { "PowerMac8,1", "iMac G5", | ||
356 | PMAC_TYPE_IMAC_G5, g5_features, | ||
357 | 0, | ||
358 | }, | ||
359 | { "PowerMac9,1", "PowerMac G5", | ||
360 | PMAC_TYPE_POWERMAC_G5_U3L, g5_features, | ||
361 | 0, | ||
362 | }, | ||
363 | { "RackMac3,1", "XServe G5", | ||
364 | PMAC_TYPE_XSERVE_G5, g5_features, | ||
365 | 0, | ||
366 | }, | ||
367 | }; | ||
368 | |||
369 | /* | ||
370 | * The toplevel feature_call callback | ||
371 | */ | ||
372 | long __pmac pmac_do_feature_call(unsigned int selector, ...) | ||
373 | { | ||
374 | struct device_node* node; | ||
375 | long param, value; | ||
376 | int i; | ||
377 | feature_call func = NULL; | ||
378 | va_list args; | ||
379 | |||
380 | if (pmac_mb.features) | ||
381 | for (i=0; pmac_mb.features[i].function; i++) | ||
382 | if (pmac_mb.features[i].selector == selector) { | ||
383 | func = pmac_mb.features[i].function; | ||
384 | break; | ||
385 | } | ||
386 | if (!func) | ||
387 | for (i=0; any_features[i].function; i++) | ||
388 | if (any_features[i].selector == selector) { | ||
389 | func = any_features[i].function; | ||
390 | break; | ||
391 | } | ||
392 | if (!func) | ||
393 | return -ENODEV; | ||
394 | |||
395 | va_start(args, selector); | ||
396 | node = (struct device_node*)va_arg(args, void*); | ||
397 | param = va_arg(args, long); | ||
398 | value = va_arg(args, long); | ||
399 | va_end(args); | ||
400 | |||
401 | return func(node, param, value); | ||
402 | } | ||
403 | |||
404 | static int __init probe_motherboard(void) | ||
405 | { | ||
406 | int i; | ||
407 | struct macio_chip* macio = &macio_chips[0]; | ||
408 | const char* model = NULL; | ||
409 | struct device_node *dt; | ||
410 | |||
411 | /* Lookup known motherboard type in device-tree. First try an | ||
412 | * exact match on the "model" property, then try a "compatible" | ||
413 | * match is none is found. | ||
414 | */ | ||
415 | dt = find_devices("device-tree"); | ||
416 | if (dt != NULL) | ||
417 | model = (const char *) get_property(dt, "model", NULL); | ||
418 | for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { | ||
419 | if (strcmp(model, pmac_mb_defs[i].model_string) == 0) { | ||
420 | pmac_mb = pmac_mb_defs[i]; | ||
421 | goto found; | ||
422 | } | ||
423 | } | ||
424 | for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { | ||
425 | if (machine_is_compatible(pmac_mb_defs[i].model_string)) { | ||
426 | pmac_mb = pmac_mb_defs[i]; | ||
427 | goto found; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | /* Fallback to selection depending on mac-io chip type */ | ||
432 | switch(macio->type) { | ||
433 | case macio_keylargo2: | ||
434 | pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2; | ||
435 | pmac_mb.model_name = "Unknown K2-based"; | ||
436 | pmac_mb.features = g5_features; | ||
437 | |||
438 | default: | ||
439 | return -ENODEV; | ||
440 | } | ||
441 | found: | ||
442 | /* Check for "mobile" machine */ | ||
443 | if (model && (strncmp(model, "PowerBook", 9) == 0 | ||
444 | || strncmp(model, "iBook", 5) == 0)) | ||
445 | pmac_mb.board_flags |= PMAC_MB_MOBILE; | ||
446 | |||
447 | |||
448 | printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | /* Initialize the Core99 UniNorth host bridge and memory controller | ||
453 | */ | ||
454 | static void __init probe_uninorth(void) | ||
455 | { | ||
456 | uninorth_node = of_find_node_by_name(NULL, "u3"); | ||
457 | if (uninorth_node && uninorth_node->n_addrs > 0) { | ||
458 | /* Small hack until I figure out if parsing in prom.c is correct. I should | ||
459 | * get rid of those pre-parsed junk anyway | ||
460 | */ | ||
461 | unsigned long address = uninorth_node->addrs[0].address; | ||
462 | uninorth_base = ioremap(address, 0x40000); | ||
463 | uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); | ||
464 | u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); | ||
465 | } else | ||
466 | uninorth_node = NULL; | ||
467 | |||
468 | if (!uninorth_node) | ||
469 | return; | ||
470 | |||
471 | printk(KERN_INFO "Found U3 memory controller & host bridge, revision: %d\n", | ||
472 | uninorth_rev); | ||
473 | printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); | ||
474 | |||
475 | } | ||
476 | |||
477 | static void __init probe_one_macio(const char* name, const char* compat, int type) | ||
478 | { | ||
479 | struct device_node* node; | ||
480 | int i; | ||
481 | volatile u32* base; | ||
482 | u32* revp; | ||
483 | |||
484 | node = find_devices(name); | ||
485 | if (!node || !node->n_addrs) | ||
486 | return; | ||
487 | if (compat) | ||
488 | do { | ||
489 | if (device_is_compatible(node, compat)) | ||
490 | break; | ||
491 | node = node->next; | ||
492 | } while (node); | ||
493 | if (!node) | ||
494 | return; | ||
495 | for(i=0; i<MAX_MACIO_CHIPS; i++) { | ||
496 | if (!macio_chips[i].of_node) | ||
497 | break; | ||
498 | if (macio_chips[i].of_node == node) | ||
499 | return; | ||
500 | } | ||
501 | if (i >= MAX_MACIO_CHIPS) { | ||
502 | printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); | ||
503 | printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); | ||
504 | return; | ||
505 | } | ||
506 | base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size); | ||
507 | if (!base) { | ||
508 | printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); | ||
509 | return; | ||
510 | } | ||
511 | if (type == macio_keylargo) { | ||
512 | u32* did = (u32 *)get_property(node, "device-id", NULL); | ||
513 | if (*did == 0x00000025) | ||
514 | type = macio_pangea; | ||
515 | if (*did == 0x0000003e) | ||
516 | type = macio_intrepid; | ||
517 | } | ||
518 | macio_chips[i].of_node = node; | ||
519 | macio_chips[i].type = type; | ||
520 | macio_chips[i].base = base; | ||
521 | macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; | ||
522 | macio_chips[i].name = macio_names[type]; | ||
523 | revp = (u32 *)get_property(node, "revision-id", NULL); | ||
524 | if (revp) | ||
525 | macio_chips[i].rev = *revp; | ||
526 | printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", | ||
527 | macio_names[type], macio_chips[i].rev, macio_chips[i].base); | ||
528 | } | ||
529 | |||
530 | static int __init | ||
531 | probe_macios(void) | ||
532 | { | ||
533 | probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2); | ||
534 | |||
535 | macio_chips[0].lbus.index = 0; | ||
536 | macio_chips[1].lbus.index = 1; | ||
537 | |||
538 | return (macio_chips[0].of_node == NULL) ? -ENODEV : 0; | ||
539 | } | ||
540 | |||
541 | static void __init | ||
542 | set_initial_features(void) | ||
543 | { | ||
544 | struct device_node *np; | ||
545 | |||
546 | if (macio_chips[0].type == macio_keylargo2) { | ||
547 | #ifndef CONFIG_SMP | ||
548 | /* On SMP machines running UP, we have the second CPU eating | ||
549 | * bus cycles. We need to take it off the bus. This is done | ||
550 | * from pmac_smp for SMP kernels running on one CPU | ||
551 | */ | ||
552 | np = of_find_node_by_type(NULL, "cpu"); | ||
553 | if (np != NULL) | ||
554 | np = of_find_node_by_type(np, "cpu"); | ||
555 | if (np != NULL) { | ||
556 | g5_phy_disable_cpu1(); | ||
557 | of_node_put(np); | ||
558 | } | ||
559 | #endif /* CONFIG_SMP */ | ||
560 | /* Enable GMAC for now for PCI probing. It will be disabled | ||
561 | * later on after PCI probe | ||
562 | */ | ||
563 | np = of_find_node_by_name(NULL, "ethernet"); | ||
564 | while(np) { | ||
565 | if (device_is_compatible(np, "K2-GMAC")) | ||
566 | g5_gmac_enable(np, 0, 1); | ||
567 | np = of_find_node_by_name(np, "ethernet"); | ||
568 | } | ||
569 | |||
570 | /* Enable FW before PCI probe. Will be disabled later on | ||
571 | * Note: We should have a batter way to check that we are | ||
572 | * dealing with uninorth internal cell and not a PCI cell | ||
573 | * on the external PCI. The code below works though. | ||
574 | */ | ||
575 | np = of_find_node_by_name(NULL, "firewire"); | ||
576 | while(np) { | ||
577 | if (device_is_compatible(np, "pci106b,5811")) { | ||
578 | macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; | ||
579 | g5_fw_enable(np, 0, 1); | ||
580 | } | ||
581 | np = of_find_node_by_name(np, "firewire"); | ||
582 | } | ||
583 | } | ||
584 | } | ||
585 | |||
586 | void __init | ||
587 | pmac_feature_init(void) | ||
588 | { | ||
589 | /* Detect the UniNorth memory controller */ | ||
590 | probe_uninorth(); | ||
591 | |||
592 | /* Probe mac-io controllers */ | ||
593 | if (probe_macios()) { | ||
594 | printk(KERN_WARNING "No mac-io chip found\n"); | ||
595 | return; | ||
596 | } | ||
597 | |||
598 | /* Setup low-level i2c stuffs */ | ||
599 | pmac_init_low_i2c(); | ||
600 | |||
601 | /* Probe machine type */ | ||
602 | if (probe_motherboard()) | ||
603 | printk(KERN_WARNING "Unknown PowerMac !\n"); | ||
604 | |||
605 | /* Set some initial features (turn off some chips that will | ||
606 | * be later turned on) | ||
607 | */ | ||
608 | set_initial_features(); | ||
609 | } | ||
610 | |||
611 | int __init pmac_feature_late_init(void) | ||
612 | { | ||
613 | #if 0 | ||
614 | struct device_node* np; | ||
615 | |||
616 | /* Request some resources late */ | ||
617 | if (uninorth_node) | ||
618 | request_OF_resource(uninorth_node, 0, NULL); | ||
619 | np = find_devices("hammerhead"); | ||
620 | if (np) | ||
621 | request_OF_resource(np, 0, NULL); | ||
622 | np = find_devices("interrupt-controller"); | ||
623 | if (np) | ||
624 | request_OF_resource(np, 0, NULL); | ||
625 | #endif | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | device_initcall(pmac_feature_late_init); | ||
630 | |||
631 | #if 0 | ||
632 | static void dump_HT_speeds(char *name, u32 cfg, u32 frq) | ||
633 | { | ||
634 | int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 }; | ||
635 | int bits[8] = { 8,16,0,32,2,4,0,0 }; | ||
636 | int freq = (frq >> 8) & 0xf; | ||
637 | |||
638 | if (freqs[freq] == 0) | ||
639 | printk("%s: Unknown HT link frequency %x\n", name, freq); | ||
640 | else | ||
641 | printk("%s: %d MHz on main link, (%d in / %d out) bits width\n", | ||
642 | name, freqs[freq], | ||
643 | bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); | ||
644 | } | ||
645 | #endif | ||
646 | |||
647 | void __init pmac_check_ht_link(void) | ||
648 | { | ||
649 | #if 0 /* Disabled for now */ | ||
650 | u32 ufreq, freq, ucfg, cfg; | ||
651 | struct device_node *pcix_node; | ||
652 | u8 px_bus, px_devfn; | ||
653 | struct pci_controller *px_hose; | ||
654 | |||
655 | (void)in_be32(u3_ht + U3_HT_LINK_COMMAND); | ||
656 | ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG); | ||
657 | ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ); | ||
658 | dump_HT_speeds("U3 HyperTransport", cfg, freq); | ||
659 | |||
660 | pcix_node = of_find_compatible_node(NULL, "pci", "pci-x"); | ||
661 | if (pcix_node == NULL) { | ||
662 | printk("No PCI-X bridge found\n"); | ||
663 | return; | ||
664 | } | ||
665 | px_hose = pcix_node->phb; | ||
666 | px_bus = pcix_node->busno; | ||
667 | px_devfn = pcix_node->devfn; | ||
668 | |||
669 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg); | ||
670 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq); | ||
671 | dump_HT_speeds("PCI-X HT Uplink", cfg, freq); | ||
672 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); | ||
673 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); | ||
674 | dump_HT_speeds("PCI-X HT Downlink", cfg, freq); | ||
675 | #endif | ||
676 | } | ||