[POWERPC] Add cputable entry for PowerPC 440SPe Rev. B
[safe/jmp/linux-2.6] / arch / powerpc / kernel / prom_init.c
index ebd501a..a1d582e 100644 (file)
@@ -173,8 +173,8 @@ static unsigned long __initdata dt_string_start, dt_string_end;
 static unsigned long __initdata prom_initrd_start, prom_initrd_end;
 
 #ifdef CONFIG_PPC64
-static int __initdata iommu_force_on;
-static int __initdata ppc64_iommu_off;
+static int __initdata prom_iommu_force_on;
+static int __initdata prom_iommu_off;
 static unsigned long __initdata prom_tce_alloc_start;
 static unsigned long __initdata prom_tce_alloc_end;
 #endif
@@ -557,7 +557,9 @@ unsigned long prom_memparse(const char *ptr, const char **retptr)
 static void __init early_cmdline_parse(void)
 {
        struct prom_t *_prom = &RELOC(prom);
+#ifdef CONFIG_PPC64
        const char *opt;
+#endif
        char *p;
        int l = 0;
 
@@ -580,9 +582,9 @@ static void __init early_cmdline_parse(void)
                while (*opt && *opt == ' ')
                        opt++;
                if (!strncmp(opt, RELOC("off"), 3))
-                       RELOC(ppc64_iommu_off) = 1;
+                       RELOC(prom_iommu_off) = 1;
                else if (!strncmp(opt, RELOC("force"), 5))
-                       RELOC(iommu_force_on) = 1;
+                       RELOC(prom_iommu_force_on) = 1;
        }
 #endif
 }
@@ -625,6 +627,7 @@ static void __init early_cmdline_parse(void)
 /* Option vector 3: processor options supported */
 #define OV3_FP                 0x80    /* floating point */
 #define OV3_VMX                        0x40    /* VMX/Altivec */
+#define OV3_DFP                        0x20    /* decimal FP */
 
 /* Option vector 5: PAPR/OF options supported */
 #define OV5_LPAR               0x80    /* logical partitioning supported */
@@ -632,6 +635,13 @@ static void __init early_cmdline_parse(void)
 /* ibm,dynamic-reconfiguration-memory property supported */
 #define OV5_DRCONF_MEMORY      0x20
 #define OV5_LARGE_PAGES                0x10    /* large pages supported */
+#define OV5_DONATE_DEDICATE_CPU 0x02   /* donate dedicated CPU support */
+/* PCIe/MSI support.  Without MSI full PCIe is not supported */
+#ifdef CONFIG_PCI_MSI
+#define OV5_MSI                        0x01    /* PCIe/MSI support */
+#else
+#define OV5_MSI                        0x00
+#endif /* CONFIG_PCI_MSI */
 
 /*
  * The architecture vector has an array of PVR mask/value pairs,
@@ -640,17 +650,18 @@ static void __init early_cmdline_parse(void)
 static unsigned char ibm_architecture_vec[] = {
        W(0xfffe0000), W(0x003a0000),   /* POWER5/POWER5+ */
        W(0xffff0000), W(0x003e0000),   /* POWER6 */
+       W(0xffffffff), W(0x0f000002),   /* all 2.05-compliant */
        W(0xfffffffe), W(0x0f000001),   /* all 2.04-compliant and earlier */
        5 - 1,                          /* 5 option vectors */
 
        /* option vector 1: processor architectures supported */
-       3 - 1,                          /* length */
+       3 - 2,                          /* length */
        0,                              /* don't ignore, don't halt */
        OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 |
        OV1_PPC_2_04 | OV1_PPC_2_05,
 
        /* option vector 2: Open Firmware options supported */
-       34 - 1,                         /* length */
+       34 - 2,                         /* length */
        OV2_REAL_MODE,
        0, 0,
        W(0xffffffff),                  /* real_base */
@@ -664,18 +675,19 @@ static unsigned char ibm_architecture_vec[] = {
        48,                             /* max log_2(hash table size) */
 
        /* option vector 3: processor options supported */
-       3 - 1,                          /* length */
+       3 - 2,                          /* length */
        0,                              /* don't ignore, don't halt */
-       OV3_FP | OV3_VMX,
+       OV3_FP | OV3_VMX | OV3_DFP,
 
        /* option vector 4: IBM PAPR implementation */
-       2 - 1,                          /* length */
+       2 - 2,                          /* length */
        0,                              /* don't halt */
 
        /* option vector 5: PAPR/OF options */
-       3 - 1,                          /* length */
+       3 - 2,                          /* length */
        0,                              /* don't ignore, don't halt */
-       OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES,
+       OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
+       OV5_DONATE_DEDICATE_CPU | OV5_MSI,
 };
 
 /* Old method - ELF header with PT_NOTE sections */
@@ -963,7 +975,7 @@ static unsigned long __init prom_next_cell(int s, cell_t **cellp)
  * If problems seem to show up, it would be a good start to track
  * them down.
  */
-static void reserve_mem(u64 base, u64 size)
+static void __init reserve_mem(u64 base, u64 size)
 {
        u64 top = base + size;
        unsigned long cnt = RELOC(mem_reserve_cnt);
@@ -1165,7 +1177,7 @@ static void __init prom_initialize_tce_table(void)
        u64 local_alloc_top, local_alloc_bottom;
        u64 i;
 
-       if (RELOC(ppc64_iommu_off))
+       if (RELOC(prom_iommu_off))
                return;
 
        prom_debug("starting prom_initialize_tce_table\n");
@@ -2030,6 +2042,56 @@ static void __init fixup_device_tree_maple(void)
 #define fixup_device_tree_maple()
 #endif
 
+#ifdef CONFIG_PPC_CHRP
+/*
+ * Pegasos and BriQ lacks the "ranges" property in the isa node
+ * Pegasos needs decimal IRQ 14/15, not hexadecimal
+ */
+static void __init fixup_device_tree_chrp(void)
+{
+       phandle ph;
+       u32 prop[6];
+       u32 rloc = 0x01006000; /* IO space; PCI device = 12 */
+       char *name;
+       int rc;
+
+       name = "/pci@80000000/isa@c";
+       ph = call_prom("finddevice", 1, 1, ADDR(name));
+       if (!PHANDLE_VALID(ph)) {
+               name = "/pci@ff500000/isa@6";
+               ph = call_prom("finddevice", 1, 1, ADDR(name));
+               rloc = 0x01003000; /* IO space; PCI device = 6 */
+       }
+       if (PHANDLE_VALID(ph)) {
+               rc = prom_getproplen(ph, "ranges");
+               if (rc == 0 || rc == PROM_ERROR) {
+                       prom_printf("Fixing up missing ISA range on Pegasos...\n");
+
+                       prop[0] = 0x1;
+                       prop[1] = 0x0;
+                       prop[2] = rloc;
+                       prop[3] = 0x0;
+                       prop[4] = 0x0;
+                       prop[5] = 0x00010000;
+                       prom_setprop(ph, name, "ranges", prop, sizeof(prop));
+               }
+       }
+
+       name = "/pci@80000000/ide@C,1";
+       ph = call_prom("finddevice", 1, 1, ADDR(name));
+       if (PHANDLE_VALID(ph)) {
+               prom_printf("Fixing up IDE interrupt on Pegasos...\n");
+               prop[0] = 14;
+               prop[1] = 0x0;
+               prop[2] = 15;
+               prop[3] = 0x0;
+               prom_setprop(ph, name, "interrupts", prop, 4*sizeof(u32));
+       }
+}
+#else
+#define fixup_device_tree_chrp()
+#endif
+
 #if defined(CONFIG_PPC64) && defined(CONFIG_PPC_PMAC)
 static void __init fixup_device_tree_pmac(void)
 {
@@ -2074,10 +2136,92 @@ static void __init fixup_device_tree_pmac(void)
 #define fixup_device_tree_pmac()
 #endif
 
+#ifdef CONFIG_PPC_EFIKA
+/* The current fw of the Efika has a device tree needs quite a few
+ * fixups to be compliant with the mpc52xx bindings. It's currently
+ * unknown if it will ever be compliant (come on bPlan ...) so we do fixups.
+ * NOTE that we (barely) tolerate it because the EFIKA was out before
+ * the bindings were finished, for any new boards -> RTFM ! */
+
+struct subst_entry {
+       char *path;
+       char *property;
+       void *value;
+       int value_len;
+};
+
+static void __init fixup_device_tree_efika(void)
+{
+       /* Substitution table */
+       #define prop_cstr(x) x, sizeof(x)
+       int prop_sound_irq[3] = { 2, 2, 0 };
+       int prop_bcomm_irq[3*16] = { 3,0,0, 3,1,0, 3,2,0, 3,3,0,
+                                    3,4,0, 3,5,0, 3,6,0, 3,7,0,
+                                    3,8,0, 3,9,0, 3,10,0, 3,11,0,
+                                    3,12,0, 3,13,0, 3,14,0, 3,15,0 };
+       struct subst_entry efika_subst_table[] = {
+               { "/",                  "device_type",  prop_cstr("efika") },
+               { "/builtin",           "device_type",  prop_cstr("soc") },
+               { "/builtin/ata",       "compatible",   prop_cstr("mpc5200b-ata\0mpc5200-ata"), },
+               { "/builtin/bestcomm",  "compatible",   prop_cstr("mpc5200b-bestcomm\0mpc5200-bestcomm") },
+               { "/builtin/bestcomm",  "interrupts",   prop_bcomm_irq, sizeof(prop_bcomm_irq) },
+               { "/builtin/ethernet",  "compatible",   prop_cstr("mpc5200b-fec\0mpc5200-fec") },
+               { "/builtin/pic",       "compatible",   prop_cstr("mpc5200b-pic\0mpc5200-pic") },
+               { "/builtin/serial",    "compatible",   prop_cstr("mpc5200b-psc-uart\0mpc5200-psc-uart") },
+               { "/builtin/sound",     "compatible",   prop_cstr("mpc5200b-psc-ac97\0mpc5200-psc-ac97") },
+               { "/builtin/sound",     "interrupts",   prop_sound_irq, sizeof(prop_sound_irq) },
+               { "/builtin/sram",      "compatible",   prop_cstr("mpc5200b-sram\0mpc5200-sram") },
+               { "/builtin/sram",      "device_type",  prop_cstr("sram") },
+               {}
+       };
+       #undef prop_cstr
+
+       /* Vars */
+       u32 node;
+       char prop[64];
+       int rv, i;
+
+       /* Check if we're really running on a EFIKA */
+       node = call_prom("finddevice", 1, 1, ADDR("/"));
+       if (!PHANDLE_VALID(node))
+               return;
+
+       rv = prom_getprop(node, "model", prop, sizeof(prop));
+       if (rv == PROM_ERROR)
+               return;
+       if (strcmp(prop, "EFIKA5K2"))
+               return;
+
+       prom_printf("Applying EFIKA device tree fixups\n");
+
+       /* Process substitution table */
+       for (i=0; efika_subst_table[i].path; i++) {
+               struct subst_entry *se = &efika_subst_table[i];
+
+               node = call_prom("finddevice", 1, 1, ADDR(se->path));
+               if (!PHANDLE_VALID(node)) {
+                       prom_printf("fixup_device_tree_efika: ",
+                               "skipped entry %x - not found\n", i);
+                       continue;
+               }
+
+               rv = prom_setprop(node, se->path, se->property,
+                                       se->value, se->value_len );
+               if (rv == PROM_ERROR)
+                       prom_printf("fixup_device_tree_efika: ",
+                               "skipped entry %x - setprop error\n", i);
+       }
+}
+#else
+#define fixup_device_tree_efika()
+#endif
+
 static void __init fixup_device_tree(void)
 {
        fixup_device_tree_maple();
+       fixup_device_tree_chrp();
        fixup_device_tree_pmac();
+       fixup_device_tree_efika();
 }
 
 static void __init prom_find_boot_cpu(void)
@@ -2241,11 +2385,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
         * Fill in some infos for use by the kernel later on
         */
 #ifdef CONFIG_PPC64
-       if (RELOC(ppc64_iommu_off))
+       if (RELOC(prom_iommu_off))
                prom_setprop(_prom->chosen, "/chosen", "linux,iommu-off",
                             NULL, 0);
 
-       if (RELOC(iommu_force_on))
+       if (RELOC(prom_iommu_force_on))
                prom_setprop(_prom->chosen, "/chosen", "linux,iommu-force-on",
                             NULL, 0);