Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * arch/ppc/platforms/setup.c | |
3 | * | |
4 | * PowerPC version | |
5 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | |
6 | * | |
7 | * Adapted for Power Macintosh by Paul Mackerras | |
8 | * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au) | |
9 | * | |
10 | * Derived from "arch/alpha/kernel/setup.c" | |
11 | * Copyright (C) 1995 Linus Torvalds | |
12 | * | |
13 | * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or | |
16 | * modify it under the terms of the GNU General Public License | |
17 | * as published by the Free Software Foundation; either version | |
18 | * 2 of the License, or (at your option) any later version. | |
19 | * | |
20 | */ | |
21 | ||
22 | /* | |
23 | * bootup setup stuff.. | |
24 | */ | |
25 | ||
26 | #undef DEBUG | |
27 | ||
28 | #include <linux/config.h> | |
29 | #include <linux/init.h> | |
30 | #include <linux/errno.h> | |
31 | #include <linux/sched.h> | |
32 | #include <linux/kernel.h> | |
33 | #include <linux/mm.h> | |
34 | #include <linux/stddef.h> | |
35 | #include <linux/unistd.h> | |
36 | #include <linux/ptrace.h> | |
37 | #include <linux/slab.h> | |
38 | #include <linux/user.h> | |
39 | #include <linux/a.out.h> | |
40 | #include <linux/tty.h> | |
41 | #include <linux/string.h> | |
42 | #include <linux/delay.h> | |
43 | #include <linux/ioport.h> | |
44 | #include <linux/major.h> | |
45 | #include <linux/initrd.h> | |
46 | #include <linux/vt_kern.h> | |
47 | #include <linux/console.h> | |
48 | #include <linux/ide.h> | |
49 | #include <linux/pci.h> | |
50 | #include <linux/adb.h> | |
51 | #include <linux/cuda.h> | |
52 | #include <linux/pmu.h> | |
53 | #include <linux/irq.h> | |
54 | #include <linux/seq_file.h> | |
55 | #include <linux/root_dev.h> | |
56 | #include <linux/bitops.h> | |
57 | ||
58 | #include <asm/processor.h> | |
59 | #include <asm/sections.h> | |
60 | #include <asm/prom.h> | |
61 | #include <asm/system.h> | |
62 | #include <asm/io.h> | |
63 | #include <asm/pci-bridge.h> | |
64 | #include <asm/iommu.h> | |
65 | #include <asm/machdep.h> | |
66 | #include <asm/dma.h> | |
67 | #include <asm/btext.h> | |
68 | #include <asm/cputable.h> | |
69 | #include <asm/pmac_feature.h> | |
70 | #include <asm/time.h> | |
71 | #include <asm/of_device.h> | |
72 | #include <asm/lmb.h> | |
73 | #include <asm/smu.h> | |
180a3362 | 74 | #include <asm/pmc.h> |
1da177e4 LT |
75 | |
76 | #include "pmac.h" | |
77 | #include "mpic.h" | |
78 | ||
79 | #ifdef DEBUG | |
80 | #define DBG(fmt...) udbg_printf(fmt) | |
81 | #else | |
82 | #define DBG(fmt...) | |
83 | #endif | |
84 | ||
85 | static int current_root_goodness = -1; | |
86 | #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ | |
87 | ||
88 | extern int powersave_nap; | |
89 | int sccdbg; | |
90 | ||
91 | sys_ctrler_t sys_ctrler; | |
92 | EXPORT_SYMBOL(sys_ctrler); | |
93 | ||
94 | #ifdef CONFIG_PMAC_SMU | |
95 | unsigned long smu_cmdbuf_abs; | |
96 | EXPORT_SYMBOL(smu_cmdbuf_abs); | |
97 | #endif | |
98 | ||
99 | extern void udbg_init_scc(struct device_node *np); | |
100 | ||
6fdfb382 | 101 | static void __pmac pmac_show_cpuinfo(struct seq_file *m) |
1da177e4 LT |
102 | { |
103 | struct device_node *np; | |
104 | char *pp; | |
105 | int plen; | |
106 | char* mbname; | |
107 | int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, | |
108 | PMAC_MB_INFO_MODEL, 0); | |
109 | unsigned int mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, | |
110 | PMAC_MB_INFO_FLAGS, 0); | |
111 | ||
112 | if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, | |
113 | (long)&mbname) != 0) | |
114 | mbname = "Unknown"; | |
115 | ||
116 | /* find motherboard type */ | |
117 | seq_printf(m, "machine\t\t: "); | |
118 | np = find_devices("device-tree"); | |
119 | if (np != NULL) { | |
120 | pp = (char *) get_property(np, "model", NULL); | |
121 | if (pp != NULL) | |
122 | seq_printf(m, "%s\n", pp); | |
123 | else | |
124 | seq_printf(m, "PowerMac\n"); | |
125 | pp = (char *) get_property(np, "compatible", &plen); | |
126 | if (pp != NULL) { | |
127 | seq_printf(m, "motherboard\t:"); | |
128 | while (plen > 0) { | |
129 | int l = strlen(pp) + 1; | |
130 | seq_printf(m, " %s", pp); | |
131 | plen -= l; | |
132 | pp += l; | |
133 | } | |
134 | seq_printf(m, "\n"); | |
135 | } | |
136 | } else | |
137 | seq_printf(m, "PowerMac\n"); | |
138 | ||
139 | /* print parsed model */ | |
140 | seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); | |
141 | seq_printf(m, "pmac flags\t: %08x\n", mbflags); | |
142 | ||
143 | /* Indicate newworld */ | |
144 | seq_printf(m, "pmac-generation\t: NewWorld\n"); | |
145 | } | |
146 | ||
147 | ||
6fdfb382 | 148 | static void __init pmac_setup_arch(void) |
1da177e4 LT |
149 | { |
150 | /* init to some ~sane value until calibrate_delay() runs */ | |
151 | loops_per_jiffy = 50000000; | |
152 | ||
153 | /* Probe motherboard chipset */ | |
154 | pmac_feature_init(); | |
155 | #if 0 | |
156 | /* Lock-enable the SCC channel used for debug */ | |
157 | if (sccdbg) { | |
158 | np = of_find_node_by_name(NULL, "escc"); | |
159 | if (np) | |
160 | pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, | |
161 | PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); | |
162 | } | |
163 | #endif | |
164 | /* We can NAP */ | |
165 | powersave_nap = 1; | |
166 | ||
167 | #ifdef CONFIG_ADB_PMU | |
168 | /* Initialize the PMU if any */ | |
169 | find_via_pmu(); | |
170 | #endif | |
171 | #ifdef CONFIG_PMAC_SMU | |
172 | /* Initialize the SMU if any */ | |
173 | smu_init(); | |
174 | #endif | |
175 | ||
176 | /* Init NVRAM access */ | |
177 | pmac_nvram_init(); | |
178 | ||
179 | /* Setup SMP callback */ | |
180 | #ifdef CONFIG_SMP | |
181 | pmac_setup_smp(); | |
182 | #endif | |
183 | ||
184 | /* Lookup PCI hosts */ | |
185 | pmac_pci_init(); | |
186 | ||
187 | #ifdef CONFIG_DUMMY_CONSOLE | |
188 | conswitchp = &dummy_con; | |
189 | #endif | |
62d60e9f ME |
190 | |
191 | printk(KERN_INFO "Using native/NAP idle loop\n"); | |
1da177e4 LT |
192 | } |
193 | ||
194 | #ifdef CONFIG_SCSI | |
195 | void note_scsi_host(struct device_node *node, void *host) | |
196 | { | |
197 | /* Obsolete */ | |
198 | } | |
199 | #endif | |
200 | ||
201 | ||
202 | static int initializing = 1; | |
203 | ||
204 | static int pmac_late_init(void) | |
205 | { | |
206 | initializing = 0; | |
207 | return 0; | |
208 | } | |
209 | ||
210 | late_initcall(pmac_late_init); | |
211 | ||
212 | /* can't be __init - can be called whenever a disk is first accessed */ | |
213 | void __pmac note_bootable_part(dev_t dev, int part, int goodness) | |
214 | { | |
215 | extern dev_t boot_dev; | |
216 | char *p; | |
217 | ||
218 | if (!initializing) | |
219 | return; | |
220 | if ((goodness <= current_root_goodness) && | |
221 | ROOT_DEV != DEFAULT_ROOT_DEVICE) | |
222 | return; | |
223 | p = strstr(saved_command_line, "root="); | |
224 | if (p != NULL && (p == saved_command_line || p[-1] == ' ')) | |
225 | return; | |
226 | ||
227 | if (!boot_dev || dev == boot_dev) { | |
228 | ROOT_DEV = dev + part; | |
229 | boot_dev = 0; | |
230 | current_root_goodness = goodness; | |
231 | } | |
232 | } | |
233 | ||
6fdfb382 | 234 | static void __pmac pmac_restart(char *cmd) |
1da177e4 LT |
235 | { |
236 | switch(sys_ctrler) { | |
237 | #ifdef CONFIG_ADB_PMU | |
238 | case SYS_CTRLER_PMU: | |
239 | pmu_restart(); | |
240 | break; | |
241 | #endif | |
242 | ||
243 | #ifdef CONFIG_PMAC_SMU | |
244 | case SYS_CTRLER_SMU: | |
245 | smu_restart(); | |
246 | break; | |
247 | #endif | |
248 | default: | |
249 | ; | |
250 | } | |
251 | } | |
252 | ||
6fdfb382 | 253 | static void __pmac pmac_power_off(void) |
1da177e4 LT |
254 | { |
255 | switch(sys_ctrler) { | |
256 | #ifdef CONFIG_ADB_PMU | |
257 | case SYS_CTRLER_PMU: | |
258 | pmu_shutdown(); | |
259 | break; | |
260 | #endif | |
261 | #ifdef CONFIG_PMAC_SMU | |
262 | case SYS_CTRLER_SMU: | |
263 | smu_shutdown(); | |
264 | break; | |
265 | #endif | |
266 | default: | |
267 | ; | |
268 | } | |
269 | } | |
270 | ||
6fdfb382 | 271 | static void __pmac pmac_halt(void) |
1da177e4 LT |
272 | { |
273 | pmac_power_off(); | |
274 | } | |
275 | ||
276 | #ifdef CONFIG_BOOTX_TEXT | |
1da177e4 LT |
277 | static void btext_putc(unsigned char c) |
278 | { | |
279 | btext_drawchar(c); | |
280 | } | |
281 | ||
282 | static void __init init_boot_display(void) | |
283 | { | |
284 | char *name; | |
285 | struct device_node *np = NULL; | |
286 | int rc = -ENODEV; | |
287 | ||
288 | printk("trying to initialize btext ...\n"); | |
289 | ||
290 | name = (char *)get_property(of_chosen, "linux,stdout-path", NULL); | |
291 | if (name != NULL) { | |
292 | np = of_find_node_by_path(name); | |
293 | if (np != NULL) { | |
294 | if (strcmp(np->type, "display") != 0) { | |
295 | printk("boot stdout isn't a display !\n"); | |
296 | of_node_put(np); | |
297 | np = NULL; | |
298 | } | |
299 | } | |
300 | } | |
301 | if (np) | |
302 | rc = btext_initialize(np); | |
303 | if (rc == 0) | |
304 | return; | |
305 | ||
306 | for (np = NULL; (np = of_find_node_by_type(np, "display"));) { | |
307 | if (get_property(np, "linux,opened", NULL)) { | |
308 | printk("trying %s ...\n", np->full_name); | |
309 | rc = btext_initialize(np); | |
310 | printk("result: %d\n", rc); | |
311 | } | |
312 | if (rc == 0) | |
313 | return; | |
314 | } | |
315 | } | |
316 | #endif /* CONFIG_BOOTX_TEXT */ | |
317 | ||
318 | /* | |
319 | * Early initialization. | |
320 | */ | |
6fdfb382 | 321 | static void __init pmac_init_early(void) |
1da177e4 LT |
322 | { |
323 | DBG(" -> pmac_init_early\n"); | |
324 | ||
325 | /* Initialize hash table, from now on, we can take hash faults | |
326 | * and call ioremap | |
327 | */ | |
328 | hpte_init_native(); | |
329 | ||
330 | /* Init SCC */ | |
331 | if (strstr(cmd_line, "sccdbg")) { | |
332 | sccdbg = 1; | |
333 | udbg_init_scc(NULL); | |
334 | } | |
1da177e4 | 335 | #ifdef CONFIG_BOOTX_TEXT |
c8f1c8be | 336 | else { |
1da177e4 LT |
337 | init_boot_display(); |
338 | ||
c8f1c8be | 339 | udbg_putc = btext_putc; |
1da177e4 | 340 | } |
c8f1c8be | 341 | #endif /* CONFIG_BOOTX_TEXT */ |
1da177e4 LT |
342 | |
343 | /* Setup interrupt mapping options */ | |
344 | ppc64_interrupt_controller = IC_OPEN_PIC; | |
345 | ||
346 | iommu_init_early_u3(); | |
347 | ||
348 | DBG(" <- pmac_init_early\n"); | |
349 | } | |
350 | ||
351 | static int pmac_u3_cascade(struct pt_regs *regs, void *data) | |
352 | { | |
353 | return mpic_get_one_irq((struct mpic *)data, regs); | |
354 | } | |
355 | ||
356 | static __init void pmac_init_IRQ(void) | |
357 | { | |
358 | struct device_node *irqctrler = NULL; | |
359 | struct device_node *irqctrler2 = NULL; | |
360 | struct device_node *np = NULL; | |
361 | struct mpic *mpic1, *mpic2; | |
362 | ||
363 | /* We first try to detect Apple's new Core99 chipset, since mac-io | |
364 | * is quite different on those machines and contains an IBM MPIC2. | |
365 | */ | |
366 | while ((np = of_find_node_by_type(np, "open-pic")) != NULL) { | |
367 | struct device_node *parent = of_get_parent(np); | |
368 | if (parent && !strcmp(parent->name, "u3")) | |
369 | irqctrler2 = of_node_get(np); | |
370 | else | |
371 | irqctrler = of_node_get(np); | |
372 | of_node_put(parent); | |
373 | } | |
374 | if (irqctrler != NULL && irqctrler->n_addrs > 0) { | |
375 | unsigned char senses[128]; | |
376 | ||
377 | printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n", | |
378 | (unsigned int)irqctrler->addrs[0].address); | |
379 | ||
380 | prom_get_irq_senses(senses, 0, 128); | |
381 | mpic1 = mpic_alloc(irqctrler->addrs[0].address, | |
382 | MPIC_PRIMARY | MPIC_WANTS_RESET, | |
383 | 0, 0, 128, 256, senses, 128, " K2-MPIC "); | |
384 | BUG_ON(mpic1 == NULL); | |
385 | mpic_init(mpic1); | |
386 | ||
387 | if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 && | |
388 | irqctrler2->n_addrs > 0) { | |
389 | printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n", | |
390 | (u32)irqctrler2->addrs[0].address, | |
391 | irqctrler2->intrs[0].line); | |
392 | ||
393 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0); | |
394 | prom_get_irq_senses(senses, 128, 128 + 128); | |
395 | ||
396 | /* We don't need to set MPIC_BROKEN_U3 here since we don't have | |
397 | * hypertransport interrupts routed to it | |
398 | */ | |
399 | mpic2 = mpic_alloc(irqctrler2->addrs[0].address, | |
400 | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET, | |
401 | 0, 128, 128, 0, senses, 128, " U3-MPIC "); | |
402 | BUG_ON(mpic2 == NULL); | |
403 | mpic_init(mpic2); | |
404 | mpic_setup_cascade(irqctrler2->intrs[0].line, | |
405 | pmac_u3_cascade, mpic2); | |
406 | } | |
407 | } | |
408 | of_node_put(irqctrler); | |
409 | of_node_put(irqctrler2); | |
410 | } | |
411 | ||
412 | static void __init pmac_progress(char *s, unsigned short hex) | |
413 | { | |
414 | if (sccdbg) { | |
415 | udbg_puts(s); | |
416 | udbg_puts("\n"); | |
417 | } | |
418 | #ifdef CONFIG_BOOTX_TEXT | |
419 | else if (boot_text_mapped) { | |
420 | btext_drawstring(s); | |
421 | btext_drawstring("\n"); | |
422 | } | |
423 | #endif /* CONFIG_BOOTX_TEXT */ | |
424 | } | |
425 | ||
426 | /* | |
427 | * pmac has no legacy IO, anything calling this function has to | |
428 | * fail or bad things will happen | |
429 | */ | |
430 | static int pmac_check_legacy_ioport(unsigned int baseport) | |
431 | { | |
432 | return -ENODEV; | |
433 | } | |
434 | ||
435 | static int __init pmac_declare_of_platform_devices(void) | |
436 | { | |
437 | struct device_node *np; | |
438 | ||
439 | np = find_devices("u3"); | |
440 | if (np) { | |
441 | for (np = np->child; np != NULL; np = np->sibling) | |
442 | if (strncmp(np->name, "i2c", 3) == 0) { | |
443 | of_platform_device_create(np, "u3-i2c"); | |
444 | break; | |
445 | } | |
446 | } | |
447 | ||
448 | return 0; | |
449 | } | |
450 | ||
451 | device_initcall(pmac_declare_of_platform_devices); | |
452 | ||
453 | /* | |
454 | * Called very early, MMU is off, device-tree isn't unflattened | |
455 | */ | |
456 | static int __init pmac_probe(int platform) | |
457 | { | |
458 | if (platform != PLATFORM_POWERMAC) | |
459 | return 0; | |
460 | /* | |
461 | * On U3, the DART (iommu) must be allocated now since it | |
462 | * has an impact on htab_initialize (due to the large page it | |
463 | * occupies having to be broken up so the DART itself is not | |
464 | * part of the cacheable linar mapping | |
465 | */ | |
466 | alloc_u3_dart_table(); | |
467 | ||
468 | #ifdef CONFIG_PMAC_SMU | |
469 | /* | |
470 | * SMU based G5s need some memory below 2Gb, at least the current | |
471 | * driver needs that. We have to allocate it now. We allocate 4k | |
472 | * (1 small page) for now. | |
473 | */ | |
474 | smu_cmdbuf_abs = lmb_alloc_base(4096, 4096, 0x80000000UL); | |
475 | #endif /* CONFIG_PMAC_SMU */ | |
476 | ||
477 | return 1; | |
478 | } | |
479 | ||
480 | struct machdep_calls __initdata pmac_md = { | |
481 | #ifdef CONFIG_HOTPLUG_CPU | |
482 | .cpu_die = generic_mach_cpu_die, | |
483 | #endif | |
484 | .probe = pmac_probe, | |
485 | .setup_arch = pmac_setup_arch, | |
486 | .init_early = pmac_init_early, | |
487 | .get_cpuinfo = pmac_show_cpuinfo, | |
488 | .init_IRQ = pmac_init_IRQ, | |
489 | .get_irq = mpic_get_irq, | |
490 | .pcibios_fixup = pmac_pcibios_fixup, | |
491 | .restart = pmac_restart, | |
492 | .power_off = pmac_power_off, | |
493 | .halt = pmac_halt, | |
494 | .get_boot_time = pmac_get_boot_time, | |
495 | .set_rtc_time = pmac_set_rtc_time, | |
496 | .get_rtc_time = pmac_get_rtc_time, | |
497 | .calibrate_decr = pmac_calibrate_decr, | |
498 | .feature_call = pmac_do_feature_call, | |
499 | .progress = pmac_progress, | |
62d60e9f ME |
500 | .check_legacy_ioport = pmac_check_legacy_ioport, |
501 | .idle_loop = native_idle, | |
180a3362 | 502 | .enable_pmcs = power4_enable_pmcs, |
1da177e4 | 503 | }; |