]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - arch/sparc/kernel/setup_32.c
Merge tag 'imx-clk-common-fixes' of git://git.pengutronix.de/git/imx/linux-2.6 into...
[karo-tx-linux.git] / arch / sparc / kernel / setup_32.c
index d444468b27f67c42e0c83058cb06c52a69584271..efe3e64bba38bd80814d51958bdb046b9c8f8a68 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/cpu.h>
 #include <linux/kdebug.h>
 #include <linux/export.h>
+#include <linux/start_kernel.h>
 
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/vaddrs.h>
 #include <asm/mbus.h>
 #include <asm/idprom.h>
-#include <asm/machines.h>
 #include <asm/cpudata.h>
 #include <asm/setup.h>
 #include <asm/cacheflush.h>
+#include <asm/sections.h>
 
 #include "kernel.h"
 
@@ -106,7 +107,6 @@ unsigned long cmdline_memory_size __initdata = 0;
 
 /* which CPU booted us (0xff = not set) */
 unsigned char boot_cpu_id = 0xff; /* 0xff will make it into DATA section... */
-unsigned char boot_cpu_id4; /* boot_cpu_id << 2 */
 
 static void
 prom_console_write(struct console *con, const char *s, unsigned n)
@@ -182,13 +182,6 @@ static void __init boot_flags_init(char *commands)
        }
 }
 
-/* This routine will in the future do all the nasty prom stuff
- * to probe for the mmu type and its parameters, etc. This will
- * also be where SMP things happen.
- */
-
-extern void sun4c_probe_vac(void);
-
 extern unsigned short root_flags;
 extern unsigned short root_dev;
 extern unsigned short ram_flags;
@@ -200,35 +193,91 @@ extern int root_mountflags;
 
 char reboot_command[COMMAND_LINE_SIZE];
 
+struct cpuid_patch_entry {
+       unsigned int    addr;
+       unsigned int    sun4d[3];
+       unsigned int    leon[3];
+};
+extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
+
+static void __init per_cpu_patch(void)
+{
+       struct cpuid_patch_entry *p;
+
+       if (sparc_cpu_model == sun4m) {
+               /* Nothing to do, this is what the unpatched code
+                * targets.
+                */
+               return;
+       }
+
+       p = &__cpuid_patch;
+       while (p < &__cpuid_patch_end) {
+               unsigned long addr = p->addr;
+               unsigned int *insns;
+
+               switch (sparc_cpu_model) {
+               case sun4d:
+                       insns = &p->sun4d[0];
+                       break;
+
+               case sparc_leon:
+                       insns = &p->leon[0];
+                       break;
+               default:
+                       prom_printf("Unknown cpu type, halting.\n");
+                       prom_halt();
+               }
+               *(unsigned int *) (addr + 0) = insns[0];
+               flushi(addr + 0);
+               *(unsigned int *) (addr + 4) = insns[1];
+               flushi(addr + 4);
+               *(unsigned int *) (addr + 8) = insns[2];
+               flushi(addr + 8);
+
+               p++;
+       }
+}
+
+struct leon_1insn_patch_entry {
+       unsigned int addr;
+       unsigned int insn;
+};
+
 enum sparc_cpu sparc_cpu_model;
 EXPORT_SYMBOL(sparc_cpu_model);
 
-struct tt_entry *sparc_ttable;
+static __init void leon_patch(void)
+{
+       struct leon_1insn_patch_entry *start = (void *)__leon_1insn_patch;
+       struct leon_1insn_patch_entry *end = (void *)__leon_1insn_patch_end;
 
-struct pt_regs fake_swapper_regs;
+       /* Default instruction is leon - no patching */
+       if (sparc_cpu_model == sparc_leon)
+               return;
 
-void __init setup_arch(char **cmdline_p)
-{
-       int i;
-       unsigned long highest_paddr;
+       while (start < end) {
+               unsigned long addr = start->addr;
 
-       sparc_ttable = (struct tt_entry *) &trapbase;
+               *(unsigned int *)(addr) = start->insn;
+               flushi(addr);
 
-       /* Initialize PROM console and command line. */
-       *cmdline_p = prom_getbootargs();
-       strcpy(boot_command_line, *cmdline_p);
-       parse_early_param();
+               start++;
+       }
+}
 
-       boot_flags_init(*cmdline_p);
+struct tt_entry *sparc_ttable;
+struct pt_regs fake_swapper_regs;
 
-       register_console(&prom_early_console);
+/* Called from head_32.S - before we have setup anything
+ * in the kernel. Be very careful with what you do here.
+ */
+void __init sparc32_start_kernel(struct linux_romvec *rp)
+{
+       prom_init(rp);
 
        /* Set sparc_cpu_model */
        sparc_cpu_model = sun_unknown;
-       if (!strcmp(&cputypval[0], "sun4 "))
-               sparc_cpu_model = sun4;
-       if (!strcmp(&cputypval[0], "sun4c"))
-               sparc_cpu_model = sun4c;
        if (!strcmp(&cputypval[0], "sun4m"))
                sparc_cpu_model = sun4m;
        if (!strcmp(&cputypval[0], "sun4s"))
@@ -242,14 +291,28 @@ void __init setup_arch(char **cmdline_p)
        if (!strncmp(&cputypval[0], "leon" , 4))
                sparc_cpu_model = sparc_leon;
 
+       leon_patch();
+       start_kernel();
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+       int i;
+       unsigned long highest_paddr;
+
+       sparc_ttable = (struct tt_entry *) &trapbase;
+
+       /* Initialize PROM console and command line. */
+       *cmdline_p = prom_getbootargs();
+       strcpy(boot_command_line, *cmdline_p);
+       parse_early_param();
+
+       boot_flags_init(*cmdline_p);
+
+       register_console(&prom_early_console);
+
        printk("ARCH: ");
        switch(sparc_cpu_model) {
-       case sun4:
-               printk("SUN4\n");
-               break;
-       case sun4c:
-               printk("SUN4C\n");
-               break;
        case sun4m:
                printk("SUN4M\n");
                break;
@@ -275,8 +338,6 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        idprom_init();
-       if (ARCH_SUN4C)
-               sun4c_probe_vac();
        load_mmu();
 
        phys_base = 0xffffffffUL;
@@ -313,6 +374,9 @@ void __init setup_arch(char **cmdline_p)
        init_mm.context = (unsigned long) NO_CONTEXT;
        init_task.thread.kregs = &fake_swapper_regs;
 
+       /* Run-time patch instructions to match the cpu model */
+       per_cpu_patch();
+
        paging_init();
 
        smp_setup_cpu_possible_map();