diff options
Diffstat (limited to 'arch/ppc64/kernel/pmac_feature.c')
-rw-r--r-- | arch/ppc64/kernel/pmac_feature.c | 767 |
1 files changed, 0 insertions, 767 deletions
diff --git a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c deleted file mode 100644 index 26075f11db77..000000000000 --- a/arch/ppc64/kernel/pmac_feature.c +++ /dev/null | |||
@@ -1,767 +0,0 @@ | |||
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); | ||
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] ; | ||
66 | |||
67 | struct macio_chip* macio_find(struct device_node* child, int type) | ||
68 | { | ||
69 | while(child) { | ||
70 | int i; | ||
71 | |||
72 | for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++) | ||
73 | if (child == macio_chips[i].of_node && | ||
74 | (!type || macio_chips[i].type == type)) | ||
75 | return &macio_chips[i]; | ||
76 | child = child->parent; | ||
77 | } | ||
78 | return NULL; | ||
79 | } | ||
80 | EXPORT_SYMBOL_GPL(macio_find); | ||
81 | |||
82 | static const char* macio_names[] = | ||
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; | ||
110 | static u32* uninorth_base; | ||
111 | static u32 uninorth_rev; | ||
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; | ||
137 | |||
138 | /* | ||
139 | * Here are the chip specific feature functions | ||
140 | */ | ||
141 | |||
142 | |||
143 | static long 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 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 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 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 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 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 | static long g5_i2s_enable(struct device_node *node, long param, long value) | ||
254 | { | ||
255 | /* Very crude implementation for now */ | ||
256 | struct macio_chip* macio = &macio_chips[0]; | ||
257 | unsigned long flags; | ||
258 | |||
259 | if (value == 0) | ||
260 | return 0; /* don't disable yet */ | ||
261 | |||
262 | LOCK(flags); | ||
263 | MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE | | ||
264 | KL3_I2S0_CLK18_ENABLE); | ||
265 | udelay(10); | ||
266 | MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE | | ||
267 | K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE); | ||
268 | udelay(10); | ||
269 | MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET); | ||
270 | UNLOCK(flags); | ||
271 | udelay(10); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | |||
277 | #ifdef CONFIG_SMP | ||
278 | static long g5_reset_cpu(struct device_node* node, long param, long value) | ||
279 | { | ||
280 | unsigned int reset_io = 0; | ||
281 | unsigned long flags; | ||
282 | struct macio_chip* macio; | ||
283 | struct device_node* np; | ||
284 | |||
285 | macio = &macio_chips[0]; | ||
286 | if (macio->type != macio_keylargo2) | ||
287 | return -ENODEV; | ||
288 | |||
289 | np = find_path_device("/cpus"); | ||
290 | if (np == NULL) | ||
291 | return -ENODEV; | ||
292 | for (np = np->child; np != NULL; np = np->sibling) { | ||
293 | u32* num = (u32 *)get_property(np, "reg", NULL); | ||
294 | u32* rst = (u32 *)get_property(np, "soft-reset", NULL); | ||
295 | if (num == NULL || rst == NULL) | ||
296 | continue; | ||
297 | if (param == *num) { | ||
298 | reset_io = *rst; | ||
299 | break; | ||
300 | } | ||
301 | } | ||
302 | if (np == NULL || reset_io == 0) | ||
303 | return -ENODEV; | ||
304 | |||
305 | LOCK(flags); | ||
306 | MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); | ||
307 | (void)MACIO_IN8(reset_io); | ||
308 | udelay(1); | ||
309 | MACIO_OUT8(reset_io, 0); | ||
310 | (void)MACIO_IN8(reset_io); | ||
311 | UNLOCK(flags); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | #endif /* CONFIG_SMP */ | ||
316 | |||
317 | /* | ||
318 | * This can be called from pmac_smp so isn't static | ||
319 | * | ||
320 | * This takes the second CPU off the bus on dual CPU machines | ||
321 | * running UP | ||
322 | */ | ||
323 | void g5_phy_disable_cpu1(void) | ||
324 | { | ||
325 | UN_OUT(U3_API_PHY_CONFIG_1, 0); | ||
326 | } | ||
327 | |||
328 | static long generic_get_mb_info(struct device_node* node, long param, long value) | ||
329 | { | ||
330 | switch(param) { | ||
331 | case PMAC_MB_INFO_MODEL: | ||
332 | return pmac_mb.model_id; | ||
333 | case PMAC_MB_INFO_FLAGS: | ||
334 | return pmac_mb.board_flags; | ||
335 | case PMAC_MB_INFO_NAME: | ||
336 | /* hack hack hack... but should work */ | ||
337 | *((const char **)value) = pmac_mb.model_name; | ||
338 | return 0; | ||
339 | } | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | |||
343 | |||
344 | /* | ||
345 | * Table definitions | ||
346 | */ | ||
347 | |||
348 | /* Used on any machine | ||
349 | */ | ||
350 | static struct feature_table_entry any_features[] = { | ||
351 | { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, | ||
352 | { 0, NULL } | ||
353 | }; | ||
354 | |||
355 | /* G5 features | ||
356 | */ | ||
357 | static struct feature_table_entry g5_features[] = { | ||
358 | { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, | ||
359 | { PMAC_FTR_1394_ENABLE, g5_fw_enable }, | ||
360 | { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable }, | ||
361 | { PMAC_FTR_READ_GPIO, g5_read_gpio }, | ||
362 | { PMAC_FTR_WRITE_GPIO, g5_write_gpio }, | ||
363 | { PMAC_FTR_GMAC_PHY_RESET, g5_eth_phy_reset }, | ||
364 | { PMAC_FTR_SOUND_CHIP_ENABLE, g5_i2s_enable }, | ||
365 | #ifdef CONFIG_SMP | ||
366 | { PMAC_FTR_RESET_CPU, g5_reset_cpu }, | ||
367 | #endif /* CONFIG_SMP */ | ||
368 | { 0, NULL } | ||
369 | }; | ||
370 | |||
371 | static struct pmac_mb_def pmac_mb_defs[] = { | ||
372 | { "PowerMac7,2", "PowerMac G5", | ||
373 | PMAC_TYPE_POWERMAC_G5, g5_features, | ||
374 | 0, | ||
375 | }, | ||
376 | { "PowerMac7,3", "PowerMac G5", | ||
377 | PMAC_TYPE_POWERMAC_G5, g5_features, | ||
378 | 0, | ||
379 | }, | ||
380 | { "PowerMac8,1", "iMac G5", | ||
381 | PMAC_TYPE_IMAC_G5, g5_features, | ||
382 | 0, | ||
383 | }, | ||
384 | { "PowerMac9,1", "PowerMac G5", | ||
385 | PMAC_TYPE_POWERMAC_G5_U3L, g5_features, | ||
386 | 0, | ||
387 | }, | ||
388 | { "RackMac3,1", "XServe G5", | ||
389 | PMAC_TYPE_XSERVE_G5, g5_features, | ||
390 | 0, | ||
391 | }, | ||
392 | }; | ||
393 | |||
394 | /* | ||
395 | * The toplevel feature_call callback | ||
396 | */ | ||
397 | long pmac_do_feature_call(unsigned int selector, ...) | ||
398 | { | ||
399 | struct device_node* node; | ||
400 | long param, value; | ||
401 | int i; | ||
402 | feature_call func = NULL; | ||
403 | va_list args; | ||
404 | |||
405 | if (pmac_mb.features) | ||
406 | for (i=0; pmac_mb.features[i].function; i++) | ||
407 | if (pmac_mb.features[i].selector == selector) { | ||
408 | func = pmac_mb.features[i].function; | ||
409 | break; | ||
410 | } | ||
411 | if (!func) | ||
412 | for (i=0; any_features[i].function; i++) | ||
413 | if (any_features[i].selector == selector) { | ||
414 | func = any_features[i].function; | ||
415 | break; | ||
416 | } | ||
417 | if (!func) | ||
418 | return -ENODEV; | ||
419 | |||
420 | va_start(args, selector); | ||
421 | node = (struct device_node*)va_arg(args, void*); | ||
422 | param = va_arg(args, long); | ||
423 | value = va_arg(args, long); | ||
424 | va_end(args); | ||
425 | |||
426 | return func(node, param, value); | ||
427 | } | ||
428 | |||
429 | static int __init probe_motherboard(void) | ||
430 | { | ||
431 | int i; | ||
432 | struct macio_chip* macio = &macio_chips[0]; | ||
433 | const char* model = NULL; | ||
434 | struct device_node *dt; | ||
435 | |||
436 | /* Lookup known motherboard type in device-tree. First try an | ||
437 | * exact match on the "model" property, then try a "compatible" | ||
438 | * match is none is found. | ||
439 | */ | ||
440 | dt = find_devices("device-tree"); | ||
441 | if (dt != NULL) | ||
442 | model = (const char *) get_property(dt, "model", NULL); | ||
443 | for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { | ||
444 | if (strcmp(model, pmac_mb_defs[i].model_string) == 0) { | ||
445 | pmac_mb = pmac_mb_defs[i]; | ||
446 | goto found; | ||
447 | } | ||
448 | } | ||
449 | for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { | ||
450 | if (machine_is_compatible(pmac_mb_defs[i].model_string)) { | ||
451 | pmac_mb = pmac_mb_defs[i]; | ||
452 | goto found; | ||
453 | } | ||
454 | } | ||
455 | |||
456 | /* Fallback to selection depending on mac-io chip type */ | ||
457 | switch(macio->type) { | ||
458 | case macio_keylargo2: | ||
459 | pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2; | ||
460 | pmac_mb.model_name = "Unknown K2-based"; | ||
461 | pmac_mb.features = g5_features; | ||
462 | |||
463 | default: | ||
464 | return -ENODEV; | ||
465 | } | ||
466 | found: | ||
467 | /* Check for "mobile" machine */ | ||
468 | if (model && (strncmp(model, "PowerBook", 9) == 0 | ||
469 | || strncmp(model, "iBook", 5) == 0)) | ||
470 | pmac_mb.board_flags |= PMAC_MB_MOBILE; | ||
471 | |||
472 | |||
473 | printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | /* Initialize the Core99 UniNorth host bridge and memory controller | ||
478 | */ | ||
479 | static void __init probe_uninorth(void) | ||
480 | { | ||
481 | uninorth_node = of_find_node_by_name(NULL, "u3"); | ||
482 | if (uninorth_node && uninorth_node->n_addrs > 0) { | ||
483 | /* Small hack until I figure out if parsing in prom.c is correct. I should | ||
484 | * get rid of those pre-parsed junk anyway | ||
485 | */ | ||
486 | unsigned long address = uninorth_node->addrs[0].address; | ||
487 | uninorth_base = ioremap(address, 0x40000); | ||
488 | uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); | ||
489 | u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000); | ||
490 | } else | ||
491 | uninorth_node = NULL; | ||
492 | |||
493 | if (!uninorth_node) | ||
494 | return; | ||
495 | |||
496 | printk(KERN_INFO "Found U3 memory controller & host bridge, revision: %d\n", | ||
497 | uninorth_rev); | ||
498 | printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); | ||
499 | |||
500 | } | ||
501 | |||
502 | static void __init probe_one_macio(const char* name, const char* compat, int type) | ||
503 | { | ||
504 | struct device_node* node; | ||
505 | int i; | ||
506 | volatile u32* base; | ||
507 | u32* revp; | ||
508 | |||
509 | node = find_devices(name); | ||
510 | if (!node || !node->n_addrs) | ||
511 | return; | ||
512 | if (compat) | ||
513 | do { | ||
514 | if (device_is_compatible(node, compat)) | ||
515 | break; | ||
516 | node = node->next; | ||
517 | } while (node); | ||
518 | if (!node) | ||
519 | return; | ||
520 | for(i=0; i<MAX_MACIO_CHIPS; i++) { | ||
521 | if (!macio_chips[i].of_node) | ||
522 | break; | ||
523 | if (macio_chips[i].of_node == node) | ||
524 | return; | ||
525 | } | ||
526 | if (i >= MAX_MACIO_CHIPS) { | ||
527 | printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); | ||
528 | printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); | ||
529 | return; | ||
530 | } | ||
531 | base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size); | ||
532 | if (!base) { | ||
533 | printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); | ||
534 | return; | ||
535 | } | ||
536 | if (type == macio_keylargo) { | ||
537 | u32* did = (u32 *)get_property(node, "device-id", NULL); | ||
538 | if (*did == 0x00000025) | ||
539 | type = macio_pangea; | ||
540 | if (*did == 0x0000003e) | ||
541 | type = macio_intrepid; | ||
542 | } | ||
543 | macio_chips[i].of_node = node; | ||
544 | macio_chips[i].type = type; | ||
545 | macio_chips[i].base = base; | ||
546 | macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; | ||
547 | macio_chips[i].name = macio_names[type]; | ||
548 | revp = (u32 *)get_property(node, "revision-id", NULL); | ||
549 | if (revp) | ||
550 | macio_chips[i].rev = *revp; | ||
551 | printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", | ||
552 | macio_names[type], macio_chips[i].rev, macio_chips[i].base); | ||
553 | } | ||
554 | |||
555 | static int __init | ||
556 | probe_macios(void) | ||
557 | { | ||
558 | probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2); | ||
559 | |||
560 | macio_chips[0].lbus.index = 0; | ||
561 | macio_chips[1].lbus.index = 1; | ||
562 | |||
563 | return (macio_chips[0].of_node == NULL) ? -ENODEV : 0; | ||
564 | } | ||
565 | |||
566 | static void __init | ||
567 | set_initial_features(void) | ||
568 | { | ||
569 | struct device_node *np; | ||
570 | |||
571 | if (macio_chips[0].type == macio_keylargo2) { | ||
572 | #ifndef CONFIG_SMP | ||
573 | /* On SMP machines running UP, we have the second CPU eating | ||
574 | * bus cycles. We need to take it off the bus. This is done | ||
575 | * from pmac_smp for SMP kernels running on one CPU | ||
576 | */ | ||
577 | np = of_find_node_by_type(NULL, "cpu"); | ||
578 | if (np != NULL) | ||
579 | np = of_find_node_by_type(np, "cpu"); | ||
580 | if (np != NULL) { | ||
581 | g5_phy_disable_cpu1(); | ||
582 | of_node_put(np); | ||
583 | } | ||
584 | #endif /* CONFIG_SMP */ | ||
585 | /* Enable GMAC for now for PCI probing. It will be disabled | ||
586 | * later on after PCI probe | ||
587 | */ | ||
588 | np = of_find_node_by_name(NULL, "ethernet"); | ||
589 | while(np) { | ||
590 | if (device_is_compatible(np, "K2-GMAC")) | ||
591 | g5_gmac_enable(np, 0, 1); | ||
592 | np = of_find_node_by_name(np, "ethernet"); | ||
593 | } | ||
594 | |||
595 | /* Enable FW before PCI probe. Will be disabled later on | ||
596 | * Note: We should have a batter way to check that we are | ||
597 | * dealing with uninorth internal cell and not a PCI cell | ||
598 | * on the external PCI. The code below works though. | ||
599 | */ | ||
600 | np = of_find_node_by_name(NULL, "firewire"); | ||
601 | while(np) { | ||
602 | if (device_is_compatible(np, "pci106b,5811")) { | ||
603 | macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; | ||
604 | g5_fw_enable(np, 0, 1); | ||
605 | } | ||
606 | np = of_find_node_by_name(np, "firewire"); | ||
607 | } | ||
608 | } | ||
609 | } | ||
610 | |||
611 | void __init | ||
612 | pmac_feature_init(void) | ||
613 | { | ||
614 | /* Detect the UniNorth memory controller */ | ||
615 | probe_uninorth(); | ||
616 | |||
617 | /* Probe mac-io controllers */ | ||
618 | if (probe_macios()) { | ||
619 | printk(KERN_WARNING "No mac-io chip found\n"); | ||
620 | return; | ||
621 | } | ||
622 | |||
623 | /* Setup low-level i2c stuffs */ | ||
624 | pmac_init_low_i2c(); | ||
625 | |||
626 | /* Probe machine type */ | ||
627 | if (probe_motherboard()) | ||
628 | printk(KERN_WARNING "Unknown PowerMac !\n"); | ||
629 | |||
630 | /* Set some initial features (turn off some chips that will | ||
631 | * be later turned on) | ||
632 | */ | ||
633 | set_initial_features(); | ||
634 | } | ||
635 | |||
636 | int __init pmac_feature_late_init(void) | ||
637 | { | ||
638 | #if 0 | ||
639 | struct device_node* np; | ||
640 | |||
641 | /* Request some resources late */ | ||
642 | if (uninorth_node) | ||
643 | request_OF_resource(uninorth_node, 0, NULL); | ||
644 | np = find_devices("hammerhead"); | ||
645 | if (np) | ||
646 | request_OF_resource(np, 0, NULL); | ||
647 | np = find_devices("interrupt-controller"); | ||
648 | if (np) | ||
649 | request_OF_resource(np, 0, NULL); | ||
650 | #endif | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | device_initcall(pmac_feature_late_init); | ||
655 | |||
656 | #if 0 | ||
657 | static void dump_HT_speeds(char *name, u32 cfg, u32 frq) | ||
658 | { | ||
659 | int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 }; | ||
660 | int bits[8] = { 8,16,0,32,2,4,0,0 }; | ||
661 | int freq = (frq >> 8) & 0xf; | ||
662 | |||
663 | if (freqs[freq] == 0) | ||
664 | printk("%s: Unknown HT link frequency %x\n", name, freq); | ||
665 | else | ||
666 | printk("%s: %d MHz on main link, (%d in / %d out) bits width\n", | ||
667 | name, freqs[freq], | ||
668 | bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]); | ||
669 | } | ||
670 | #endif | ||
671 | |||
672 | void __init pmac_check_ht_link(void) | ||
673 | { | ||
674 | #if 0 /* Disabled for now */ | ||
675 | u32 ufreq, freq, ucfg, cfg; | ||
676 | struct device_node *pcix_node; | ||
677 | struct pci_dn *pdn; | ||
678 | u8 px_bus, px_devfn; | ||
679 | struct pci_controller *px_hose; | ||
680 | |||
681 | (void)in_be32(u3_ht + U3_HT_LINK_COMMAND); | ||
682 | ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG); | ||
683 | ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ); | ||
684 | dump_HT_speeds("U3 HyperTransport", cfg, freq); | ||
685 | |||
686 | pcix_node = of_find_compatible_node(NULL, "pci", "pci-x"); | ||
687 | if (pcix_node == NULL) { | ||
688 | printk("No PCI-X bridge found\n"); | ||
689 | return; | ||
690 | } | ||
691 | pdn = pcix_node->data; | ||
692 | px_hose = pdn->phb; | ||
693 | px_bus = pdn->busno; | ||
694 | px_devfn = pdn->devfn; | ||
695 | |||
696 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg); | ||
697 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq); | ||
698 | dump_HT_speeds("PCI-X HT Uplink", cfg, freq); | ||
699 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg); | ||
700 | early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq); | ||
701 | dump_HT_speeds("PCI-X HT Downlink", cfg, freq); | ||
702 | #endif | ||
703 | } | ||
704 | |||
705 | /* | ||
706 | * Early video resume hook | ||
707 | */ | ||
708 | |||
709 | static void (*pmac_early_vresume_proc)(void *data); | ||
710 | static void *pmac_early_vresume_data; | ||
711 | |||
712 | void pmac_set_early_video_resume(void (*proc)(void *data), void *data) | ||
713 | { | ||
714 | if (_machine != _MACH_Pmac) | ||
715 | return; | ||
716 | preempt_disable(); | ||
717 | pmac_early_vresume_proc = proc; | ||
718 | pmac_early_vresume_data = data; | ||
719 | preempt_enable(); | ||
720 | } | ||
721 | EXPORT_SYMBOL(pmac_set_early_video_resume); | ||
722 | |||
723 | |||
724 | /* | ||
725 | * AGP related suspend/resume code | ||
726 | */ | ||
727 | |||
728 | static struct pci_dev *pmac_agp_bridge; | ||
729 | static int (*pmac_agp_suspend)(struct pci_dev *bridge); | ||
730 | static int (*pmac_agp_resume)(struct pci_dev *bridge); | ||
731 | |||
732 | void pmac_register_agp_pm(struct pci_dev *bridge, | ||
733 | int (*suspend)(struct pci_dev *bridge), | ||
734 | int (*resume)(struct pci_dev *bridge)) | ||
735 | { | ||
736 | if (suspend || resume) { | ||
737 | pmac_agp_bridge = bridge; | ||
738 | pmac_agp_suspend = suspend; | ||
739 | pmac_agp_resume = resume; | ||
740 | return; | ||
741 | } | ||
742 | if (bridge != pmac_agp_bridge) | ||
743 | return; | ||
744 | pmac_agp_suspend = pmac_agp_resume = NULL; | ||
745 | return; | ||
746 | } | ||
747 | EXPORT_SYMBOL(pmac_register_agp_pm); | ||
748 | |||
749 | void pmac_suspend_agp_for_card(struct pci_dev *dev) | ||
750 | { | ||
751 | if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL) | ||
752 | return; | ||
753 | if (pmac_agp_bridge->bus != dev->bus) | ||
754 | return; | ||
755 | pmac_agp_suspend(pmac_agp_bridge); | ||
756 | } | ||
757 | EXPORT_SYMBOL(pmac_suspend_agp_for_card); | ||
758 | |||
759 | void pmac_resume_agp_for_card(struct pci_dev *dev) | ||
760 | { | ||
761 | if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL) | ||
762 | return; | ||
763 | if (pmac_agp_bridge->bus != dev->bus) | ||
764 | return; | ||
765 | pmac_agp_resume(pmac_agp_bridge); | ||
766 | } | ||
767 | EXPORT_SYMBOL(pmac_resume_agp_for_card); | ||