linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / ppc / kernel / setup.c
index a74f46d..c08ab43 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * Common prep boot and setup code.
+ * Common prep/chrp boot and setup code.
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/sched.h>
@@ -11,7 +12,7 @@
 #include <linux/delay.h>
 #include <linux/initrd.h>
 #include <linux/ide.h>
-#include <linux/screen_info.h>
+#include <linux/tty.h>
 #include <linux/bootmem.h>
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
@@ -71,12 +72,17 @@ unsigned long ISA_DMA_THRESHOLD;
 unsigned int DMA_MODE_READ;
 unsigned int DMA_MODE_WRITE;
 
-#ifdef CONFIG_PPC_PREP
+#ifdef CONFIG_PPC_MULTIPLATFORM
+int _machine = 0;
+EXPORT_SYMBOL(_machine);
+
 extern void prep_init(unsigned long r3, unsigned long r4,
                unsigned long r5, unsigned long r6, unsigned long r7);
+extern void chrp_init(unsigned long r3, unsigned long r4,
+               unsigned long r5, unsigned long r6, unsigned long r7);
 
 dev_t boot_dev;
-#endif /* CONFIG_PPC_PREP */
+#endif /* CONFIG_PPC_MULTIPLATFORM */
 
 int have_of;
 EXPORT_SYMBOL(have_of);
@@ -162,8 +168,9 @@ int show_cpuinfo(struct seq_file *m, void *v)
                /* Show summary information */
 #ifdef CONFIG_SMP
                unsigned long bogosum = 0;
-               for_each_online_cpu(i)
-                       bogosum += cpu_data[i].loops_per_jiffy;
+               for (i = 0; i < NR_CPUS; ++i)
+                       if (cpu_online(i))
+                               bogosum += cpu_data[i].loops_per_jiffy;
                seq_printf(m, "total bogomips\t: %lu.%02lu\n",
                           bogosum/(500000/HZ), bogosum/(5000/HZ) % 100);
 #endif /* CONFIG_SMP */
@@ -313,12 +320,72 @@ early_init(int r3, int r4, int r5)
        identify_cpu(offset, 0);
        do_cpu_ftr_fixups(offset);
 
+#if defined(CONFIG_PPC_OF)
+       reloc_got2(offset);
+
+       /*
+        * don't do anything on prep
+        * for now, don't use bootinfo because it breaks yaboot 0.5
+        * and assume that if we didn't find a magic number, we have OF
+        */
+       if (*(unsigned long *)(0) != 0xdeadc0de)
+               phys = prom_init(r3, r4, (prom_entry)r5);
+
+       reloc_got2(-offset);
+#endif
+
        return phys;
 }
 
-#ifdef CONFIG_PPC_PREP
+#ifdef CONFIG_PPC_OF
 /*
- * The PPC_PREP version of platform_init...
+ * Assume here that all clock rates are the same in a
+ * smp system.  -- Cort
+ */
+int
+of_show_percpuinfo(struct seq_file *m, int i)
+{
+       struct device_node *cpu_node;
+       u32 *fp;
+       int s;
+       
+       cpu_node = find_type_devices("cpu");
+       if (!cpu_node)
+               return 0;
+       for (s = 0; s < i && cpu_node->next; s++)
+               cpu_node = cpu_node->next;
+       fp = (u32 *)get_property(cpu_node, "clock-frequency", NULL);
+       if (fp)
+               seq_printf(m, "clock\t\t: %dMHz\n", *fp / 1000000);
+       return 0;
+}
+
+void __init
+intuit_machine_type(void)
+{
+       char *model;
+       struct device_node *root;
+       
+       /* ask the OF info if we're a chrp or pmac */
+       root = find_path_device("/");
+       if (root != 0) {
+               /* assume pmac unless proven to be chrp -- Cort */
+               _machine = _MACH_Pmac;
+               model = get_property(root, "device_type", NULL);
+               if (model && !strncmp("chrp", model, 4))
+                       _machine = _MACH_chrp;
+               else {
+                       model = get_property(root, "model", NULL);
+                       if (model && !strncmp(model, "IBM", 3))
+                               _machine = _MACH_chrp;
+               }
+       }
+}
+#endif
+
+#ifdef CONFIG_PPC_MULTIPLATFORM
+/*
+ * The PPC_MULTIPLATFORM version of platform_init...
  */
 void __init
 platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
@@ -333,9 +400,161 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
 
        parse_bootinfo(find_bootinfo());
 
-       prep_init(r3, r4, r5, r6, r7);
+       /* if we didn't get any bootinfo telling us what we are... */
+       if (_machine == 0) {
+               /* prep boot loader tells us if we're prep or not */
+               if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
+                       _machine = _MACH_prep;
+       }
+
+#ifdef CONFIG_PPC_PREP
+       /* not much more to do here, if prep */
+       if (_machine == _MACH_prep) {
+               prep_init(r3, r4, r5, r6, r7);
+               return;
+       }
+#endif
+
+#ifdef CONFIG_PPC_OF
+       have_of = 1;
+
+       /* prom_init has already been called from __start */
+       if (boot_infos)
+               relocate_nodes();
+
+       /* If we aren't PReP, we can find out if we're Pmac
+        * or CHRP with this. */
+       if (_machine == 0)
+               intuit_machine_type();
+
+       /* finish_device_tree may need _machine defined. */
+       finish_device_tree();
+
+       /*
+        * If we were booted via quik, r3 points to the physical
+        * address of the command-line parameters.
+        * If we were booted from an xcoff image (i.e. netbooted or
+        * booted from floppy), we get the command line from the
+        * bootargs property of the /chosen node.
+        * If an initial ramdisk is present, r3 and r4
+        * are used for initrd_start and initrd_size,
+        * otherwise they contain 0xdeadbeef.
+        */
+       if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) {
+               strlcpy(cmd_line, (char *)r3 + KERNELBASE,
+                       sizeof(cmd_line));
+       } else if (boot_infos != 0) {
+               /* booted by BootX - check for ramdisk */
+               if (boot_infos->kernelParamsOffset != 0)
+                       strlcpy(cmd_line, (char *) boot_infos
+                               + boot_infos->kernelParamsOffset,
+                               sizeof(cmd_line));
+#ifdef CONFIG_BLK_DEV_INITRD
+               if (boot_infos->ramDisk) {
+                       initrd_start = (unsigned long) boot_infos
+                               + boot_infos->ramDisk;
+                       initrd_end = initrd_start + boot_infos->ramDiskSize;
+                       initrd_below_start_ok = 1;
+               }
+#endif
+       } else {
+               struct device_node *chosen;
+               char *p;
+       
+#ifdef CONFIG_BLK_DEV_INITRD
+               if (r3 && r4 && r4 != 0xdeadbeef) {
+                       if (r3 < KERNELBASE)
+                               r3 += KERNELBASE;
+                       initrd_start = r3;
+                       initrd_end = r3 + r4;
+                       ROOT_DEV = Root_RAM0;
+                       initrd_below_start_ok = 1;
+               }
+#endif
+               chosen = find_devices("chosen");
+               if (chosen != NULL) {
+                       p = get_property(chosen, "bootargs", NULL);
+                       if (p && *p) {
+                               strlcpy(cmd_line, p, sizeof(cmd_line));
+                       }
+               }
+       }
+#ifdef CONFIG_ADB
+       if (strstr(cmd_line, "adb_sync")) {
+               extern int __adb_probe_sync;
+               __adb_probe_sync = 1;
+       }
+#endif /* CONFIG_ADB */
+
+       switch (_machine) {
+#ifdef CONFIG_PPC_CHRP
+       case _MACH_chrp:
+               chrp_init(r3, r4, r5, r6, r7);
+               break;
+#endif
+       }
+#endif /* CONFIG_PPC_OF */
 }
-#endif /* CONFIG_PPC_PREP */
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
+#ifdef CONFIG_PPC_OF
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+extern char *of_stdout_device;
+
+static int __init set_preferred_console(void)
+{
+       struct device_node *prom_stdout;
+       char *name;
+       int offset = 0;
+
+       if (of_stdout_device == NULL)
+               return -ENODEV;
+
+       /* The user has requested a console so this is already set up. */
+       if (strstr(saved_command_line, "console="))
+               return -EBUSY;
+
+       prom_stdout = find_path_device(of_stdout_device);
+       if (!prom_stdout)
+               return -ENODEV;
+
+       name = (char *)get_property(prom_stdout, "name", NULL);
+       if (!name)
+               return -ENODEV;
+
+       if (strcmp(name, "serial") == 0) {
+               int i;
+               u32 *reg = (u32 *)get_property(prom_stdout, "reg", &i);
+               if (i > 8) {
+                       switch (reg[1]) {
+                               case 0x3f8:
+                                       offset = 0;
+                                       break;
+                               case 0x2f8:
+                                       offset = 1;
+                                       break;
+                               case 0x898:
+                                       offset = 2;
+                                       break;
+                               case 0x890:
+                                       offset = 3;
+                                       break;
+                               default:
+                                       /* We dont recognise the serial port */
+                                       return -ENODEV;
+                       }
+               }
+       } else if (strcmp(name, "ch-a") == 0)
+               offset = 0;
+       else if (strcmp(name, "ch-b") == 0)
+               offset = 1;
+       else
+               return -ENODEV;
+       return add_preferred_console("ttyS", offset, NULL);
+}
+console_initcall(set_preferred_console);
+#endif /* CONFIG_SERIAL_CORE_CONSOLE */
+#endif /* CONFIG_PPC_OF */
 
 struct bi_record *find_bootinfo(void)
 {
@@ -371,6 +590,23 @@ void parse_bootinfo(struct bi_record *rec)
                        initrd_end = data[0] + data[1] + KERNELBASE;
                        break;
 #endif /* CONFIG_BLK_DEV_INITRD */
+#ifdef CONFIG_PPC_MULTIPLATFORM
+               case BI_MACHTYPE:
+                       /* Machine types changed with the merge. Since the
+                        * bootinfo are now deprecated, we can just hard code
+                        * the appropriate conversion here for when we are
+                        * called with yaboot which passes us a machine type
+                        * this way.
+                        */
+                       switch(data[0]) {
+                       case 1: _machine = _MACH_prep; break;
+                       case 2: _machine = _MACH_Pmac; break;
+                       case 4: _machine = _MACH_chrp; break;
+                       default:
+                               _machine = data[0];
+                       }
+                       break;
+#endif
                case BI_MEMSIZE:
                        boot_mem_size = data[0];
                        break;
@@ -396,6 +632,9 @@ machine_init(unsigned long r3, unsigned long r4, unsigned long r5,
 #ifdef CONFIG_6xx
        ppc_md.power_save = ppc6xx_idle;
 #endif
+#ifdef CONFIG_POWER4
+       ppc_md.power_save = power4_idle;
+#endif
 
        platform_init(r3, r4, r5, r6, r7);
 
@@ -473,8 +712,9 @@ int __init ppc_init(void)
        if ( ppc_md.progress ) ppc_md.progress("             ", 0xffff);
 
        /* register CPU devices */
-       for_each_possible_cpu(i)
-               register_cpu(&cpu_devices[i], i);
+       for (i = 0; i < NR_CPUS; i++)
+               if (cpu_possible(i))
+                       register_cpu(&cpu_devices[i], i, NULL);
 
        /* call platform init */
        if (ppc_md.init != NULL) {
@@ -561,4 +801,7 @@ void __init setup_arch(char **cmdline_p)
        if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
        paging_init();
+
+       /* this is for modules since _machine can be a define -- Cort */
+       ppc_md.ppc_machine = _machine;
 }