]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kernel/prom_init.c
Merge branch 'master'
[karo-tx-linux.git] / arch / powerpc / kernel / prom_init.c
index 911a803f27da210bfc81c7e6879c7b32dcb3b998..c758b6624d7bee6c777c5e0532c8b16553b7f52b 100644 (file)
@@ -41,7 +41,6 @@
 #include <asm/pgtable.h>
 #include <asm/pci.h>
 #include <asm/iommu.h>
-#include <asm/bootinfo.h>
 #include <asm/btext.h>
 #include <asm/sections.h>
 #include <asm/machdep.h>
@@ -132,6 +131,7 @@ struct prom_t {
        ihandle chosen;
        int cpu;
        ihandle stdout;
+       ihandle mmumap;
 };
 
 struct mem_map_entry {
@@ -144,11 +144,11 @@ typedef u32 cell_t;
 extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
 
 #ifdef CONFIG_PPC64
-extern void enter_prom(struct prom_args *args, unsigned long entry);
+extern int enter_prom(struct prom_args *args, unsigned long entry);
 #else
-static inline void enter_prom(struct prom_args *args, unsigned long entry)
+static inline int enter_prom(struct prom_args *args, unsigned long entry)
 {
-       ((void (*)(struct prom_args *))entry)(args);
+       return ((int (*)(struct prom_args *))entry)(args);
 }
 #endif
 
@@ -240,7 +240,8 @@ static int __init call_prom(const char *service, int nargs, int nret, ...)
        for (i = 0; i < nret; i++)
                args.args[nargs+i] = 0;
 
-       enter_prom(&args, RELOC(prom_entry));
+       if (enter_prom(&args, RELOC(prom_entry)) < 0)
+               return PROM_ERROR;
 
        return (nret > 0) ? args.args[nargs] : 0;
 }
@@ -264,7 +265,8 @@ static int __init call_prom_ret(const char *service, int nargs, int nret,
        for (i = 0; i < nret; i++)
                rets[nargs+i] = 0;
 
-       enter_prom(&args, RELOC(prom_entry));
+       if (enter_prom(&args, RELOC(prom_entry)) < 0)
+               return PROM_ERROR;
 
        if (rets != NULL)
                for (i = 1; i < nret; ++i)
@@ -274,14 +276,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 +357,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
@@ -662,9 +671,11 @@ static void __init prom_send_capabilities(void)
  */
 static unsigned long __init alloc_up(unsigned long size, unsigned long align)
 {
-       unsigned long base = _ALIGN_UP(RELOC(alloc_bottom), align);
+       unsigned long base = RELOC(alloc_bottom);
        unsigned long addr = 0;
 
+       if (align)
+               base = _ALIGN_UP(base, align);
        prom_debug("alloc_up(%x, %x)\n", size, align);
        if (RELOC(ram_top) == 0)
                prom_panic("alloc_up() called with mem not initialized\n");
@@ -678,7 +689,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align)
            base = _ALIGN_UP(base + 0x100000, align)) {
                prom_debug("    trying: 0x%x\n\r", base);
                addr = (unsigned long)prom_claim(base, size, 0);
-               if (addr != PROM_ERROR)
+               if (addr != PROM_ERROR && addr != 0)
                        break;
                addr = 0;
                if (align == 0)
@@ -738,7 +749,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align,
             base = _ALIGN_DOWN(base - 0x100000, align))  {
                prom_debug("    trying: 0x%x\n\r", base);
                addr = (unsigned long)prom_claim(base, size, 0);
-               if (addr != PROM_ERROR)
+               if (addr != PROM_ERROR && addr != 0)
                        break;
                addr = 0;
        }
@@ -772,7 +783,7 @@ static unsigned long __init prom_next_cell(int s, cell_t **cellp)
        }
        r = *p++;
 #ifdef CONFIG_PPC64
-       if (s) {
+       if (s > 1) {
                r <<= 32;
                r |= *(p++);
        }
@@ -844,9 +855,16 @@ static void __init prom_init_mem(void)
                type[0] = 0;
                prom_getprop(node, "device_type", type, sizeof(type));
 
+               if (type[0] == 0) {
+                       /*
+                        * CHRP Longtrail machines have no device_type
+                        * on the memory node, so check the name instead...
+                        */
+                       prom_getprop(node, "name", type, sizeof(type));
+               }
                if (strcmp(type, RELOC("memory")))
                        continue;
-       
+
                plen = prom_getprop(node, "reg", RELOC(regbuf), sizeof(regbuf));
                if (plen > sizeof(regbuf)) {
                        prom_printf("memory node too large for buffer !\n");
@@ -1147,9 +1165,18 @@ static void __init prom_initialize_tce_table(void)
  *
  * -- Cort
  */
+extern void __secondary_hold(void);
+extern unsigned long __secondary_hold_spinloop;
+extern unsigned long __secondary_hold_acknowledge;
+
+/*
+ * We want to reference the copy of __secondary_hold_* in the
+ * 0 - 0x100 address range
+ */
+#define LOW_ADDR(x)    (((unsigned long) &(x)) & 0xff)
+
 static void __init prom_hold_cpus(void)
 {
-#ifdef CONFIG_PPC64
        unsigned long i;
        unsigned int reg;
        phandle node;
@@ -1158,20 +1185,18 @@ static void __init prom_hold_cpus(void)
        unsigned int interrupt_server[MAX_CPU_THREADS];
        unsigned int cpu_threads, hw_cpu_num;
        int propsize;
-       extern void __secondary_hold(void);
-       extern unsigned long __secondary_hold_spinloop;
-       extern unsigned long __secondary_hold_acknowledge;
+       struct prom_t *_prom = &RELOC(prom);
        unsigned long *spinloop
-               = (void *) __pa(&__secondary_hold_spinloop);
+               = (void *) LOW_ADDR(__secondary_hold_spinloop);
        unsigned long *acknowledge
-               = (void *) __pa(&__secondary_hold_acknowledge);
+               = (void *) LOW_ADDR(__secondary_hold_acknowledge);
 #ifdef CONFIG_PPC64
+       /* __secondary_hold is actually a descriptor, not the text address */
        unsigned long secondary_hold
                = __pa(*PTRRELOC((unsigned long *)__secondary_hold));
 #else
-       unsigned long secondary_hold = __pa(&__secondary_hold);
+       unsigned long secondary_hold = LOW_ADDR(__secondary_hold);
 #endif
-       struct prom_t *_prom = &RELOC(prom);
 
        prom_debug("prom_hold_cpus: start...\n");
        prom_debug("    1) spinloop       = 0x%x\n", (unsigned long)spinloop);
@@ -1189,9 +1214,8 @@ static void __init prom_hold_cpus(void)
        *spinloop = 0;
 
 #ifdef CONFIG_HMT
-       for (i = 0; i < NR_CPUS; i++) {
+       for (i = 0; i < NR_CPUS; i++)
                RELOC(hmt_thread_data)[i].pir = 0xdeadbeef;
-       }
 #endif
        /* look for cpus */
        for (node = 0; prom_next_node(&node); ) {
@@ -1242,34 +1266,22 @@ static void __init prom_hold_cpus(void)
                        call_prom("start-cpu", 3, 0, node,
                                  secondary_hold, reg);
 
-                       for ( i = 0 ; (i < 100000000) && 
-                             (*acknowledge == ((unsigned long)-1)); i++ )
+                       for (i = 0; (i < 100000000) && 
+                            (*acknowledge == ((unsigned long)-1)); i++ )
                                mb();
 
-                       if (*acknowledge == reg) {
+                       if (*acknowledge == reg)
                                prom_printf("done\n");
-                               /* We have to get every CPU out of OF,
-                                * even if we never start it. */
-                               if (cpuid >= NR_CPUS)
-                                       goto next;
-                       } else {
+                       else
                                prom_printf("failed: %x\n", *acknowledge);
-                       }
                }
 #ifdef CONFIG_SMP
                else
                        prom_printf("%x : boot cpu     %x\n", cpuid, reg);
-#endif
-next:
-#ifdef CONFIG_SMP
-               /* Init paca for secondary threads.   They start later. */
-               for (i=1; i < cpu_threads; i++) {
-                       cpuid++;
-                       if (cpuid >= NR_CPUS)
-                               continue;
-               }
 #endif /* CONFIG_SMP */
-               cpuid++;
+
+               /* Reserve cpu #s for secondary threads.   They start later. */
+               cpuid += cpu_threads;
        }
 #ifdef CONFIG_HMT
        /* Only enable HMT on processors that provide support. */
@@ -1303,7 +1315,6 @@ next:
                            ") exceeded: ignoring extras\n");
 
        prom_debug("prom_hold_cpus: end...\n");
-#endif
 }
 
 
@@ -1323,7 +1334,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 +1420,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")))
@@ -1404,62 +1445,6 @@ static int __init prom_find_machine_type(void)
 #endif
 }
 
-static int __init setup_disp(phandle dp)
-{
-#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
-       int width = 640, height = 480, depth = 8, pitch;
-       unsigned address;
-       u32 addrs[8][5];
-       int i, naddrs;
-       char name[32];
-       char *getprop = "getprop";
-
-       prom_printf("Initializing screen: ");
-
-       memset(name, 0, sizeof(name));
-       call_prom(getprop, 4, 1, dp, "name", name, sizeof(name));
-       name[sizeof(name)-1] = 0;
-       prom_print(name);
-       prom_print("\n");
-       call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width));
-       call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height));
-       call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth));
-       pitch = width * ((depth + 7) / 8);
-       call_prom(getprop, 4, 1, dp, "linebytes",
-                 &pitch, sizeof(pitch));
-       if (pitch == 1)
-               pitch = 0x1000;         /* for strange IBM display */
-       address = 0;
-       call_prom(getprop, 4, 1, dp, "address", &address, sizeof(address));
-       if (address == 0) {
-               /* look for an assigned address with a size of >= 1MB */
-               naddrs = call_prom(getprop, 4, 1, dp, "assigned-addresses",
-                                  addrs, sizeof(addrs));
-               naddrs /= 20;
-               for (i = 0; i < naddrs; ++i) {
-                       if (addrs[i][4] >= (1 << 20)) {
-                               address = addrs[i][2];
-                               /* use the BE aperture if possible */
-                               if (addrs[i][4] >= (16 << 20))
-                                       address += (8 << 20);
-                               break;
-                       }
-               }
-               if (address == 0) {
-                       prom_print("Failed to get address\n");
-                       return 0;
-               }
-       }
-       /* kludge for valkyrie */
-       if (strcmp(name, "valkyrie") == 0)
-               address += 0x1000;
-
-       prom_printf("\n\n\n\naddress = %x\n", address);
-       btext_setup_display(width, height, depth, pitch, address);
-#endif /* CONFIG_BOOTX_TEXT && CONFIG_PPC32 */
-       return 1;
-}
-
 static int __init prom_set_color(ihandle ih, int i, int r, int g, int b)
 {
        return call_prom("call-method", 6, 1, ADDR("color!"), ih, i, b, g, r);
@@ -1479,7 +1464,6 @@ static void __init prom_check_displays(void)
        phandle node;
        ihandle ih;
        int i;
-       int got_display = 0;
 
        static unsigned char default_colors[] = {
                0x00, 0x00, 0x00,
@@ -1546,8 +1530,6 @@ static void __init prom_check_displays(void)
                                           clut[2]) != 0)
                                break;
 #endif /* CONFIG_LOGO_LINUX_CLUT224 */
-               if (!got_display)
-                       got_display = setup_disp(node);
        }
 }
 
@@ -1660,39 +1642,37 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
        unsigned long soff;
        unsigned char *valp;
        static char pname[MAX_PROPERTY_NAME];
-       int l;
+       int l, room;
 
        dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);
 
        /* get the node's full name */
        namep = (char *)*mem_start;
-       l = call_prom("package-to-path", 3, 1, node,
-                     namep, *mem_end - *mem_start);
+       room = *mem_end - *mem_start;
+       if (room > 255)
+               room = 255;
+       l = call_prom("package-to-path", 3, 1, node, namep, room);
        if (l >= 0) {
                /* Didn't fit?  Get more room. */
-               if ((l+1) > (*mem_end - *mem_start)) {
-                       namep = make_room(mem_start, mem_end, l+1, 1);
+               if (l >= room) {
+                       if (l >= *mem_end - *mem_start)
+                               namep = make_room(mem_start, mem_end, l+1, 1);
                        call_prom("package-to-path", 3, 1, node, namep, l);
                }
                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 */
@@ -1917,8 +1897,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);
 
@@ -1965,7 +1946,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
                               unsigned long r6, unsigned long r7)
 {      
                struct prom_t *_prom;
-       extern char _stext[];
        unsigned long hdr;
        u32 getprop_rval;
        unsigned long offset = reloc_offset();
@@ -1992,6 +1972,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
         */
@@ -2014,13 +1999,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
                prom_send_capabilities();
 #endif
 
-#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_BPA)
        /*
-        * On pSeries and BPA, copy the CPU hold code
+        * Copy the CPU hold code
         */
-               if (RELOC(of_platform) & (PLATFORM_PSERIES | PLATFORM_BPA))
+               if (RELOC(of_platform) != PLATFORM_POWERMAC)
                        copy_and_flush(0, KERNELBASE + offset, 0x100, 0);
-#endif
 
        /*
         * Do early parsing of command line
@@ -2120,7 +2103,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
        reloc_got2(-offset);
 #endif
 
-       __start(hdr, 0, 0);
+       __start(hdr, KERNELBASE + offset, 0);
 
        return 0;
 }