powerpc: Run on old powermacs.
authorPaul Mackerras <paulus@samba.org>
Sun, 23 Oct 2005 07:23:21 +0000 (17:23 +1000)
committerPaul Mackerras <paulus@samba.org>
Sun, 23 Oct 2005 07:23:21 +0000 (17:23 +1000)
Old powermacs have a number of differences from current machines:
- there is no interrupt tree in the device tree, just interrupt
  or AAPL,interrupt properties
- the chosen node in the device tree is called /chosen@0
- the OF claim method doesn't map the memory, so we have to do
  an explicit map call as well
- there is no /chosen/cpu property on SMP machines
- the NVRAM isn't structured as a set of partitions.

This adapts the merged powermac support code to cope with these
issues.

Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/platforms/powermac/setup.c

index c8d2884..69f69c3 100644 (file)
@@ -309,6 +309,37 @@ static int __devinit finish_node_interrupts(struct device_node *np,
        unsigned int *irq, virq;
        struct device_node *ic;
 
+       if (num_interrupt_controllers == 0) {
+               /*
+                * Old machines just have a list of interrupt numbers
+                * and no interrupt-controller nodes.
+                */
+               ints = (unsigned int *) get_property(np, "AAPL,interrupts",
+                                                    &intlen);
+               /* XXX old interpret_pci_props looked in parent too */
+               /* XXX old interpret_macio_props looked for interrupts
+                  before AAPL,interrupts */
+               if (ints == NULL)
+                       ints = (unsigned int *) get_property(np, "interrupts",
+                                                            &intlen);
+               if (ints == NULL)
+                       return 0;
+
+               np->n_intrs = intlen / sizeof(unsigned int);
+               np->intrs = prom_alloc(np->n_intrs * sizeof(np->intrs[0]),
+                                      mem_start);
+               if (!np->intrs)
+                       return -ENOMEM;
+               if (measure_only)
+                       return 0;
+
+               for (i = 0; i < np->n_intrs; ++i) {
+                       np->intrs[i].line = *ints++;
+                       np->intrs[i].sense = 1;
+               }
+               return 0;
+       }
+
        ints = (unsigned int *) get_property(np, "interrupts", &intlen);
        if (ints == NULL)
                return 0;
@@ -1024,6 +1055,8 @@ void __init unflatten_device_tree(void)
 
        /* Get pointer to OF "/chosen" node for use everywhere */
        of_chosen = of_find_node_by_path("/chosen");
+       if (of_chosen == NULL)
+               of_chosen = of_find_node_by_path("/chosen@0");
 
        /* Retreive command line */
        if (of_chosen != NULL) {
@@ -1123,7 +1156,8 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
 
        DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
 
-       if (depth != 1 || strcmp(uname, "chosen") != 0)
+       if (depth != 1 ||
+           (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
                return 0;
 
        /* get platform type */
index 095659d..18d266d 100644 (file)
@@ -132,6 +132,7 @@ struct prom_t {
        ihandle chosen;
        int cpu;
        ihandle stdout;
+       ihandle mmumap;
 };
 
 struct mem_map_entry {
@@ -274,14 +275,6 @@ static int __init call_prom_ret(const char *service, int nargs, int nret,
 }
 
 
-static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
-                               unsigned long align)
-{
-       return (unsigned int)call_prom("claim", 3, 1,
-                                      (prom_arg_t)virt, (prom_arg_t)size,
-                                      (prom_arg_t)align);
-}
-
 static void __init prom_print(const char *msg)
 {
        const char *p, *q;
@@ -363,6 +356,21 @@ static void __init prom_printf(const char *format, ...)
 }
 
 
+static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
+                               unsigned long align)
+{
+       int ret;
+       struct prom_t *_prom = &RELOC(prom);
+
+       ret = call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,
+                       (prom_arg_t)align);
+       if (ret != -1 && _prom->mmumap != 0)
+               /* old pmacs need us to map as well */
+               call_prom("call-method", 6, 1,
+                         ADDR("map"), _prom->mmumap, 0, size, virt, virt);
+       return ret;
+}
+
 static void __init __attribute__((noreturn)) prom_panic(const char *reason)
 {
 #ifdef CONFIG_PPC64
@@ -1323,7 +1331,37 @@ static void __init prom_init_client_services(unsigned long pp)
        _prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
        if (!PHANDLE_VALID(_prom->root))
                prom_panic("cannot find device tree root"); /* msg won't be printed :( */
+
+       _prom->mmumap = 0;
+}
+
+#ifdef CONFIG_PPC32
+/*
+ * For really old powermacs, we need to map things we claim.
+ * For that, we need the ihandle of the mmu.
+ */
+static void __init prom_find_mmu(void)
+{
+       struct prom_t *_prom = &RELOC(prom);
+       phandle oprom;
+       char version[64];
+
+       oprom = call_prom("finddevice", 1, 1, ADDR("/openprom"));
+       if (!PHANDLE_VALID(oprom))
+               return;
+       if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0)
+               return;
+       version[sizeof(version) - 1] = 0;
+       prom_printf("OF version is '%s'\n", version);
+       /* XXX might need to add other versions here */
+       if (strcmp(version, "Open Firmware, 1.0.5") != 0)
+               return;
+       prom_getprop(_prom->chosen, "mmu", &_prom->mmumap,
+                    sizeof(_prom->mmumap));
 }
+#else
+#define prom_find_mmu()
+#endif
 
 static void __init prom_init_stdout(void)
 {
@@ -1379,7 +1417,7 @@ static int __init prom_find_machine_type(void)
                        if (sl == 0)
                                break;
                        if (strstr(p, RELOC("Power Macintosh")) ||
-                           strstr(p, RELOC("MacRISC4")))
+                           strstr(p, RELOC("MacRISC")))
                                return PLATFORM_POWERMAC;
 #ifdef CONFIG_PPC64
                        if (strstr(p, RELOC("Momentum,Maple")))
@@ -1618,22 +1656,17 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
                namep[l] = '\0';
 
                /* Fixup an Apple bug where they have bogus \0 chars in the
-                * middle of the path in some properties
+                * middle of the path in some properties, and extract
+                * the unit name (everything after the last '/').
                 */
-               for (p = namep, ep = namep + l; p < ep; p++)
-                       if (*p == '\0') {
-                               memmove(p, p+1, ep - p);
-                               ep--; l--; p--;
-                       }
-
-               /* now try to extract the unit name in that mess */
-               for (p = namep, lp = NULL; *p; p++)
+               for (lp = p = namep, ep = namep + l; p < ep; p++) {
                        if (*p == '/')
-                               lp = p + 1;
-               if (lp != NULL)
-                       memmove(namep, lp, strlen(lp) + 1);
-               *mem_start = _ALIGN(((unsigned long) namep) +
-                                   strlen(namep) + 1, 4);
+                               lp = namep;
+                       else if (*p != 0)
+                               *lp++ = *p;
+               }
+               *lp = 0;
+               *mem_start = _ALIGN((unsigned long)lp + 1, 4);
        }
 
        /* get it again for debugging */
@@ -1858,8 +1891,9 @@ static void __init prom_find_boot_cpu(void)
        ihandle prom_cpu;
        phandle cpu_pkg;
 
+       _prom->cpu = 0;
        if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0)
-               prom_panic("cannot find boot cpu");
+               return;
 
        cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
 
@@ -1934,6 +1968,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
        prom_init_stdout();
 
        /*
+        * See if this OF is old enough that we need to do explicit maps
+        */
+       prom_find_mmu();
+
+       /*
         * Check for an initrd
         */
        prom_check_initrd(r3, r4);
index 50f5dd7..908e492 100644 (file)
@@ -225,7 +225,7 @@ int find_via_pmu(void)
                return 0;
        printk("WARNING ! Your machine is PMU-based but your kernel\n");
        printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
-       return;
+       return 0;
 }
 #endif
 
@@ -293,7 +293,7 @@ static void __init l2cr_init(void)
 
 void __init pmac_setup_arch(void)
 {
-       struct device_node *cpu;
+       struct device_node *cpu, *ic;
        int *fp;
        unsigned long pvr;
 
@@ -319,6 +319,12 @@ void __init pmac_setup_arch(void)
                of_node_put(cpu);
        }
 
+       /* See if newworld or oldworld */
+       ic = of_find_node_by_name(NULL, "interrupt-controller");
+       pmac_newworld = (ic != NULL);
+       if (ic)
+               of_node_put(ic);
+
        /* Lookup PCI hosts */
        pmac_pci_init();