aboutsummaryrefslogtreecommitdiff
path: root/arch/mips/mips-boards
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2005-09-30 13:59:37 +0100
committerRalf Baechle <ralf@linux-mips.org>2005-10-29 19:32:30 +0100
commitc78cbf49c4edf2f9ca9e56d4b87a5d6ef08b7fed (patch)
tree44bee3daac887df59c0d69658b19c21da4e1839f /arch/mips/mips-boards
parentb288f135872b651ebf6cd1565d0709a5e31997f7 (diff)
Support for MIPSsim, the cycle accurate MIPS simulator.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/mips-boards')
-rw-r--r--arch/mips/mips-boards/sim/Makefile20
-rw-r--r--arch/mips/mips-boards/sim/cmdline.c59
-rw-r--r--arch/mips/mips-boards/sim/sim_IRQ.c148
-rw-r--r--arch/mips/mips-boards/sim/sim_cmdline.c33
-rw-r--r--arch/mips/mips-boards/sim/sim_int.c41
-rw-r--r--arch/mips/mips-boards/sim/sim_irq.S99
-rw-r--r--arch/mips/mips-boards/sim/sim_mem.c129
-rw-r--r--arch/mips/mips-boards/sim/sim_printf.c74
-rw-r--r--arch/mips/mips-boards/sim/sim_setup.c101
-rw-r--r--arch/mips/mips-boards/sim/sim_smp.c151
-rw-r--r--arch/mips/mips-boards/sim/sim_time.c215
11 files changed, 1070 insertions, 0 deletions
diff --git a/arch/mips/mips-boards/sim/Makefile b/arch/mips/mips-boards/sim/Makefile
new file mode 100644
index 00000000000..5b977de4ecf
--- /dev/null
+++ b/arch/mips/mips-boards/sim/Makefile
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
+#
+# This program is free software; you can distribute it and/or modify it
+# under the terms of the GNU General Public License (Version 2) as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+
+obj-y := sim_setup.o sim_mem.o sim_time.o sim_printf.o sim_int.o sim_irq.o \
+ sim_cmdline.o
+obj-$(CONFIG_SMP) += sim_smp.o
diff --git a/arch/mips/mips-boards/sim/cmdline.c b/arch/mips/mips-boards/sim/cmdline.c
new file mode 100644
index 00000000000..fef9fbd8e71
--- /dev/null
+++ b/arch/mips/mips-boards/sim/cmdline.c
@@ -0,0 +1,59 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Kernel command line creation using the prom monitor (YAMON) argc/argv.
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+extern int prom_argc;
+extern int *_prom_argv;
+
+/*
+ * YAMON (32-bit PROM) pass arguments and environment as 32-bit pointer.
+ * This macro take care of sign extension.
+ */
+#define prom_argv(index) ((char *)(((int *)(int)_prom_argv)[(index)]))
+
+char arcs_cmdline[CL_SIZE];
+
+char * __init prom_getcmdline(void)
+{
+ return &(arcs_cmdline[0]);
+}
+
+
+void __init prom_init_cmdline(void)
+{
+ char *cp;
+ int actr;
+
+ actr = 1; /* Always ignore argv[0] */
+
+ cp = &(arcs_cmdline[0]);
+ while(actr < prom_argc) {
+ strcpy(cp, prom_argv(actr));
+ cp += strlen(prom_argv(actr));
+ *cp++ = ' ';
+ actr++;
+ }
+ if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
+ --cp;
+ *cp = '\0';
+}
diff --git a/arch/mips/mips-boards/sim/sim_IRQ.c b/arch/mips/mips-boards/sim/sim_IRQ.c
new file mode 100644
index 00000000000..9987a85aabe
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_IRQ.c
@@ -0,0 +1,148 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999, 2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Interrupt exception dispatch code.
+ */
+#include <linux/config.h>
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+/* A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop and moving across
+ * all the pending IRQ bits in the cause register is _NOT_ the answer, the
+ * common case is one pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register IRQ mask, that
+ * would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
+ * between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the MIPS board look basically (barring software
+ * IRQs which we don't use at all and all external interrupt sources are
+ * combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
+ *
+ * MIPS IRQ Source
+ * -------- ------
+ * 0 Software (ignored)
+ * 1 Software (ignored)
+ * 2 Combined hardware interrupt (hw0)
+ * 3 Hardware (ignored)
+ * 4 Hardware (ignored)
+ * 5 Hardware (ignored)
+ * 6 Hardware (ignored)
+ * 7 R4k timer (what we use)
+ *
+ * Note: On the SEAD board thing are a little bit different.
+ * Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
+ * wired to UART1.
+ *
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ---- R4k Timer
+ * Lowest ---- Combined hardware interrupt
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+ .text
+ .set noreorder
+ .set noat
+ .align 5
+ NESTED(mipsIRQ, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+ .set at
+
+ mfc0 s0, CP0_CAUSE # get irq bits
+ mfc0 s1, CP0_STATUS # get irq mask
+ and s0, s1
+
+ /* First we check for r4k counter/timer IRQ. */
+ andi a0, s0, CAUSEF_IP7
+ beq a0, zero, 1f
+ andi a0, s0, CAUSEF_IP2 # delay slot, check hw0 interrupt
+
+ /* Wheee, a timer interrupt. */
+ move a0, sp
+ jal mips_timer_interrupt
+ nop
+
+ j ret_from_irq
+ nop
+
+1:
+#if defined(CONFIG_MIPS_SEAD)
+ beq a0, zero, 1f
+ andi a0, s0, CAUSEF_IP3 # delay slot, check hw1 interrupt
+#else
+ beq a0, zero, 1f # delay slot, check hw3 interrupt
+ andi a0, s0, CAUSEF_IP5
+#endif
+
+ /* Wheee, combined hardware level zero interrupt. */
+#if defined(CONFIG_MIPS_ATLAS)
+ jal atlas_hw0_irqdispatch
+#elif defined(CONFIG_MIPS_MALTA)
+ jal malta_hw0_irqdispatch
+#elif defined(CONFIG_MIPS_SEAD)
+ jal sead_hw0_irqdispatch
+#else
+#error "MIPS board not supported\n"
+#endif
+ move a0, sp # delay slot
+
+ j ret_from_irq
+ nop # delay slot
+
+1:
+#if defined(CONFIG_MIPS_SEAD)
+ beq a0, zero, 1f
+ andi a0, s0, CAUSEF_IP5 # delay slot, check hw3 interrupt
+ jal sead_hw1_irqdispatch
+ move a0, sp # delay slot
+ j ret_from_irq
+ nop # delay slot
+1:
+#endif
+#if defined(CONFIG_MIPS_MALTA)
+ beq a0, zero, 1f # check hw3 (coreHI) interrupt
+ nop
+ jal corehi_irqdispatch
+ move a0, sp
+ j ret_from_irq
+ nop
+1:
+#endif
+ /*
+ * Here by mistake? This is possible, what can happen is that by the
+ * time we take the exception the IRQ pin goes low, so just leave if
+ * this is the case.
+ */
+ move a1,s0
+ PRINT("Got interrupt: c0_cause = %08x\n")
+ mfc0 a1, CP0_EPC
+ PRINT("c0_epc = %08x\n")
+
+ j ret_from_irq
+ nop
+ END(mipsIRQ)
diff --git a/arch/mips/mips-boards/sim/sim_cmdline.c b/arch/mips/mips-boards/sim/sim_cmdline.c
new file mode 100644
index 00000000000..9df37c6fca3
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_cmdline.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <asm/bootinfo.h>
+
+extern char arcs_cmdline[];
+
+char * __init prom_getcmdline(void)
+{
+ return arcs_cmdline;
+}
+
+
+void __init prom_init_cmdline(void)
+{
+ /* nothing to do */
+}
diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c
new file mode 100644
index 00000000000..a4d0a2c0503
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_int.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 1999, 2005 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <asm/mips-boards/simint.h>
+
+
+extern void mips_cpu_irq_init(int);
+
+extern asmlinkage void simIRQ(void);
+
+asmlinkage void sim_hw0_irqdispatch(struct pt_regs *regs)
+{
+ do_IRQ(2, regs);
+}
+
+void __init arch_init_irq(void)
+{
+ /* Now safe to set the exception vector. */
+ set_except_vector(0, simIRQ);
+
+ mips_cpu_irq_init(MIPSCPU_INT_BASE);
+}
diff --git a/arch/mips/mips-boards/sim/sim_irq.S b/arch/mips/mips-boards/sim/sim_irq.S
new file mode 100644
index 00000000000..835f0387fcd
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_irq.S
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 1999, 2005 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Interrupt exception dispatch code.
+ *
+ */
+#include <linux/config.h>
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+#include <asm/mips-boards/simint.h>
+
+
+ .text
+ .set noreorder
+ .set noat
+ .align 5
+ NESTED(simIRQ, PT_SIZE, sp)
+ SAVE_ALL
+ CLI
+ .set at
+
+ mfc0 s0, CP0_CAUSE # get irq bits
+ mfc0 s1, CP0_STATUS # get irq mask
+ andi s0, ST0_IM # CAUSE.CE may be non-zero!
+ and s0, s1
+
+#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
+ .set mips32
+ clz a0, s0
+ .set mips0
+ negu a0
+ addu a0, 31-CAUSEB_IP
+ bltz a0, spurious
+#else
+ beqz s0, spurious
+ li a0, 7
+
+ and t0, s0, 0xf000
+ sltiu t0, t0, 1
+ sll t0, 2
+ subu a0, t0
+ sll s0, t0
+
+ and t0, s0, 0xc000
+ sltiu t0, t0, 1
+ sll t0, 1
+ subu a0, t0
+ sll s0, t0
+
+ and t0, s0, 0x8000
+ sltiu t0, t0, 1
+ # sll t0, 0
+ subu a0, t0
+ # sll s0, t0
+#endif
+
+#ifdef CASCADE_IRQ
+ li a1, CASCADE_IRQ
+ bne a0, a1, 1f
+ addu a0, MIPSCPU_INT_BASE
+
+ jal CASCADE_DISPATCH
+ move a0, sp
+
+ j ret_from_irq
+ nop
+1:
+#else
+ addu a0, MIPSCPU_INT_BASE
+#endif
+
+ jal do_IRQ
+ move a1, sp
+
+ j ret_from_irq
+ nop
+
+
+spurious:
+ j spurious_interrupt
+ nop
+ END(simIRQ)
diff --git a/arch/mips/mips-boards/sim/sim_mem.c b/arch/mips/mips-boards/sim/sim_mem.c
new file mode 100644
index 00000000000..0dbd7435bb2
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_mem.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/bootmem.h>
+
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+
+#include <asm/mips-boards/prom.h>
+
+/*#define DEBUG*/
+
+enum simmem_memtypes {
+ simmem_reserved = 0,
+ simmem_free,
+};
+struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
+
+#ifdef DEBUG
+static char *mtypes[3] = {
+ "SIM reserved memory",
+ "SIM free memory",
+};
+#endif
+
+/* References to section boundaries */
+extern char _end;
+
+#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
+
+
+struct prom_pmemblock * __init prom_getmdesc(void)
+{
+ unsigned int memsize;
+
+ memsize = 0x02000000;
+ prom_printf("Setting default memory size 0x%08x\n", memsize);
+
+ memset(mdesc, 0, sizeof(mdesc));
+
+ mdesc[0].type = simmem_reserved;
+ mdesc[0].base = 0x00000000;
+ mdesc[0].size = 0x00001000;
+
+ mdesc[1].type = simmem_free;
+ mdesc[1].base = 0x00001000;
+ mdesc[1].size = 0x000ff000;
+
+ mdesc[2].type = simmem_reserved;
+ mdesc[2].base = 0x00100000;
+ mdesc[2].size = CPHYSADDR(PFN_ALIGN(&_end)) - mdesc[2].base;
+
+ mdesc[3].type = simmem_free;
+ mdesc[3].base = CPHYSADDR(PFN_ALIGN(&_end));
+ mdesc[3].size = memsize - mdesc[3].base;
+
+ return &mdesc[0];
+}
+
+static int __init prom_memtype_classify (unsigned int type)
+{
+ switch (type) {
+ case simmem_free:
+ return BOOT_MEM_RAM;
+ case simmem_reserved:
+ default:
+ return BOOT_MEM_RESERVED;
+ }
+}
+
+void __init prom_meminit(void)
+{
+ struct prom_pmemblock *p;
+
+ p = prom_getmdesc();
+
+ while (p->size) {
+ long type;
+ unsigned long base, size;
+
+ type = prom_memtype_classify (p->type);
+ base = p->base;
+ size = p->size;
+
+ add_memory_region(base, size, type);
+ p++;
+ }
+}
+
+unsigned long __init prom_free_prom_memory(void)
+{
+ int i;
+ unsigned long freed = 0;
+ unsigned long addr;
+
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
+ if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
+ continue;
+
+ addr = boot_mem_map.map[i].addr;
+ while (addr < boot_mem_map.map[i].addr
+ + boot_mem_map.map[i].size) {
+ ClearPageReserved(virt_to_page(__va(addr)));
+ set_page_count(virt_to_page(__va(addr)), 1);
+ free_page((unsigned long)__va(addr));
+ addr += PAGE_SIZE;
+ freed += PAGE_SIZE;
+ }
+ }
+ printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
+
+ return freed;
+}
diff --git a/arch/mips/mips-boards/sim/sim_printf.c b/arch/mips/mips-boards/sim/sim_printf.c
new file mode 100644
index 00000000000..3ee5a0b501a
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_printf.c
@@ -0,0 +1,74 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Putting things on the screen/serial line using YAMONs facilities.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/serial_reg.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+static inline unsigned int serial_in(int offset)
+{
+ return inb(0x3f8 + offset);
+}
+
+static inline void serial_out(int offset, int value)
+{
+ outb(value, 0x3f8 + offset);
+}
+
+int putPromChar(char c)
+{
+ while ((serial_in(UART_LSR) & UART_LSR_THRE) == 0)
+ ;
+
+ serial_out(UART_TX, c);
+
+ return 1;
+}
+
+char getPromChar(void)
+{
+ while (!(serial_in(UART_LSR) & 1))
+ ;
+
+ return serial_in(UART_RX);
+}
+
+void prom_printf(char *fmt, ...)
+{
+ va_list args;
+ int l;
+ char *p, *buf_end;
+ char buf[1024];
+
+ va_start(args, fmt);
+ l = vsprintf(buf, fmt, args); /* hopefully i < sizeof(buf) */
+ va_end(args);
+
+ buf_end = buf + l;
+
+ for (p = buf; p < buf_end; p++) {
+ /* Crude cr/nl handling is better than none */
+ if (*p == '\n')
+ putPromChar('\r');
+ putPromChar(*p);
+ }
+}
diff --git a/arch/mips/mips-boards/sim/sim_setup.c b/arch/mips/mips-boards/sim/sim_setup.c
new file mode 100644
index 00000000000..485d5a58d9c
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_setup.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/serial.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/mips-boards/sim.h>
+#include <asm/mips-boards/simint.h>
+
+
+extern void sim_time_init(void);
+extern void sim_timer_setup(struct irqaction *irq);
+static void __init serial_init(void);
+unsigned int _isbonito = 0;
+
+extern void __init sanitize_tlb_entries(void);
+
+
+const char *get_system_type(void)
+{
+ return "MIPSsim";
+}
+
+void __init plat_setup(void)
+{
+ set_io_port_base(0xbfd00000);
+
+ serial_init();
+
+ board_time_init = sim_time_init;
+ board_timer_setup = sim_timer_setup;
+ prom_printf("Linux started...\n");
+
+#ifdef CONFIG_MT_SMP
+ sanitize_tlb_entries();
+#endif
+}
+
+void prom_init(void)
+{
+ set_io_port_base(0xbfd00000);
+
+ prom_printf("\nLINUX started...\n");
+ prom_init_cmdline();
+ prom_meminit();
+}
+
+
+static void __init serial_init(void)
+{
+#ifdef CONFIG_SERIAL_8250
+ struct uart_port s;
+
+ memset(&s, 0, sizeof(s));
+
+ s.iobase = 0x3f8;
+
+ /* hardware int 4 - the serial int, is CPU int 6
+ but poll for now */
+ s.irq = 0;
+ s.uartclk = BASE_BAUD * 16;
+ s.flags = ASYNC_BOOT_AUTOCONF | UPF_SKIP_TEST;
+ s.iotype = SERIAL_IO_PORT | ASYNC_SKIP_TEST;
+ s.regshift = 0;
+ s.timeout = 4;
+
+ if (early_serial_setup(&s) != 0) {
+ prom_printf(KERN_ERR "Serial setup failed!\n");
+ }
+
+#endif
+}
diff --git a/arch/mips/mips-boards/sim/sim_smp.c b/arch/mips/mips-boards/sim/sim_smp.c
new file mode 100644
index 00000000000..19824359f5d
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_smp.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+/*
+ * Simulator Platform-specific hooks for SMP operation
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include <asm/cpu.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+#ifdef CONFIG_MIPS_MT_SMTC
+#include <asm/smtc_ipi.h>
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+/* VPE/SMP Prototype implements platform interfaces directly */
+#if !defined(CONFIG_MIPS_MT_SMP)
+
+/*
+ * Cause the specified action to be performed on a targeted "CPU"
+ */
+
+void core_send_ipi(int cpu, unsigned int action)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ void smtc_send_ipi(int, int, unsigned int);
+
+ smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
+#endif /* CONFIG_MIPS_MT_SMTC */
+/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
+
+}
+
+/*
+ * Detect available CPUs/VPEs/TCs and populate phys_cpu_present_map
+ */
+
+void __init prom_build_cpu_map(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ extern int mipsmt_build_cpu_map(int startslot);
+ int nextslot;
+
+ cpus_clear(phys_cpu_present_map);
+
+ /* Register the boot CPU */
+
+ smp_prepare_boot_cpu();
+
+ /*
+ * As of November, 2004, MIPSsim only simulates one core
+ * at a time. However, that core may be a MIPS MT core
+ * with multiple virtual processors and thread contexts.
+ */
+
+ if (read_c0_config3() & (1<<2)) {
+ nextslot = mipsmt_build_cpu_map(1);
+ }
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Platform "CPU" startup hook
+ */
+
+void prom_boot_secondary(int cpu, struct task_struct *idle)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ extern void smtc_boot_secondary(int cpu, struct task_struct *t);
+
+ smtc_boot_secondary(cpu, idle);
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Post-config but pre-boot cleanup entry point
+ */
+
+void prom_init_secondary(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ void smtc_init_secondary(void);
+
+ smtc_init_secondary();
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Platform SMP pre-initialization
+ */
+
+void prom_prepare_cpus(unsigned int max_cpus)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ void mipsmt_prepare_cpus(int c);
+ /*
+ * As noted above, we can assume a single CPU for now
+ * but it may be multithreaded.
+ */
+
+ if (read_c0_config3() & (1<<2)) {
+ mipsmt_prepare_cpus(max_cpus);
+ }
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * SMP initialization finalization entry point
+ */
+
+void prom_smp_finish(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+ void smtc_smp_finish(void);
+
+ smtc_smp_finish();
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+
+/*
+ * Hook for after all CPUs are online
+ */
+
+void prom_cpus_done(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+
+#endif /* CONFIG_MIPS_MT_SMTC */
+}
+#endif /* CONFIG_MIPS32R2_MT_SMP */
diff --git a/arch/mips/mips-boards/sim/sim_time.c b/arch/mips/mips-boards/sim/sim_time.c
new file mode 100644
index 00000000000..18b968c696d
--- /dev/null
+++ b/arch/mips/mips-boards/sim/sim_time.c
@@ -0,0 +1,215 @@
+#include <linux/types.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/hardirq.h>
+#include <asm/div64.h>
+#include <asm/cpu.h>
+#include <asm/time.h>
+
+#include <linux/interrupt.h>
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+#include <asm/hardirq.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+#include <asm/cpu.h>
+#include <asm/time.h>
+#include <asm/mc146818-time.h>
+#include <asm/msc01_ic.h>
+
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/mips-boards/simint.h>
+#include <asm/mc146818-time.h>
+#include <asm/smp.h>
+
+
+unsigned long cpu_khz;
+
+extern asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs);
+
+irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+#ifdef CONFIG_SMP
+ int cpu = smp_processor_id();
+
+ /*
+ * CPU 0 handles the global timer interrupt job
+ * resets count/compare registers to trigger next timer int.
+ */
+#ifndef CONFIG_MIPS_MT_SMTC
+ if (cpu == 0) {
+ timer_interrupt(irq, dev_id, regs);
+ }
+ else {
+ /* Everyone else needs to reset the timer int here as
+ ll_local_timer_interrupt doesn't */
+ /*
+ * FIXME: need to cope with counter underflow.
+ * More support needs to be added to kernel/time for
+ * counter/timer interrupts on multiple CPU's
+ */
+ write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
+ }
+#else /* SMTC */
+ /*
+ * In SMTC system, one Count/Compare set exists per VPE.
+ * Which TC within a VPE gets the interrupt is essentially
+ * random - we only know that it shouldn't be one with
+ * IXMT set. Whichever TC gets the interrupt needs to
+ * send special interprocessor interrupts to the other
+ * TCs to make sure that they schedule, etc.
+ *
+ * That code is specific to the SMTC kernel, not to
+ * the simulation platform, so it's invoked from
+ * the general MIPS timer_interrupt routine.
+ *
+ * We have a problem in that the interrupt vector code
+ * had to turn off the timer IM bit to avoid redundant
+ * entries, but we may never get to mips_cpu_irq_end
+ * to turn it back on again if the scheduler gets
+ * involved. So we clear the pending timer here,
+ * and re-enable the mask...
+ */
+
+ int vpflags = dvpe();
+ write_c0_compare (read_c0_count() - 1);
+ clear_c0_cause(0x100 << MIPSCPU_INT_CPUCTR);
+ set_c0_status(0x100 << MIPSCPU_INT_CPUCTR);
+ irq_enable_hazard();
+ evpe(vpflags);
+
+ if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id, regs);
+ else write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
+ smtc_timer_broadcast(cpu_data[cpu].vpe_id);
+
+#endif /* CONFIG_MIPS_MT_SMTC */
+
+ /*
+ * every CPU should do profiling and process accounting
+ */
+ local_timer_interrupt (irq, dev_id, regs);
+ return IRQ_HANDLED;
+#else
+ return timer_interrupt (irq, dev_id, regs);
+#endif
+}
+
+
+
+/*
+ * Estimate CPU frequency. Sets mips_counter_frequency as a side-effect
+ */
+static unsigned int __init estimate_cpu_frequency(void)
+{
+ unsigned int prid = read_c0_prid() & 0xffff00;
+ unsigned int count;
+
+#if 1
+ /*
+ * hardwire the board frequency to 12MHz.
+ */
+
+ if ((prid == (PRID_COMP_MIPS | PRID_IMP_20KC)) ||
+ (prid == (PRID_COMP_MIPS | PRID_IMP_25KF)))
+ count = 12000000;
+ else
+ count = 6000000;
+#else
+ unsigned int flags;
+
+ local_irq_save(flags);
+
+ /* Start counter exactly on falling edge of update flag */
+ while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+ while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+ /* Start r4k counter. */
+ write_c0_count(0);
+
+ /* Read counter exactly on falling edge of update flag */
+ while (CMOS_READ(RTC_REG_A) & RTC_UIP);
+ while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
+
+ count = read_c0_count();
+
+ /* restore interrupts */
+ local_irq_restore(flags);
+#endif
+
+ mips_hpt_frequency = count;
+
+ if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
+ (prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
+ count *= 2;
+
+ count += 5000; /* round */
+ count -= count%10000;
+
+ return count;
+}
+
+void __init sim_time_init(void)
+{
+ unsigned int est_freq, flags;
+
+ local_irq_save(flags);
+
+
+ /* Set Data mode - binary. */
+ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
+
+
+ est_freq = estimate_cpu_frequency ();
+
+ printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
+ (est_freq%1000000)*100/1000000);
+
+ cpu_khz = est_freq / 1000;
+
+ local_irq_restore(flags);
+}
+
+static int mips_cpu_timer_irq;
+
+static void mips_timer_dispatch (struct pt_regs *regs)
+{
+ do_IRQ (mips_cpu_timer_irq, regs);
+}
+
+
+void __init sim_timer_setup(struct irqaction *irq)
+{
+ if (cpu_has_veic) {
+ set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
+ mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
+ }
+ else {
+ if (cpu_has_vint)
+ set_vi_handler(MIPSCPU_INT_CPUCTR, mips_timer_dispatch);
+ mips_cpu_timer_irq = MIPSCPU_INT_BASE + MIPSCPU_INT_CPUCTR;
+ }
+
+ /* we are using the cpu counter for timer interrupts */
+ irq->handler = sim_timer_interrupt;
+ setup_irq(mips_cpu_timer_irq, irq);
+
+#ifdef CONFIG_SMP
+ /* irq_desc(riptor) is a global resource, when the interrupt overlaps
+ on seperate cpu's the first one tries to handle the second interrupt.
+ The effect is that the int remains disabled on the second cpu.
+ Mark the interrupt with IRQ_PER_CPU to avoid any confusion */
+ irq_desc[mips_cpu_timer_irq].status |= IRQ_PER_CPU;
+#endif
+
+ /* to generate the first timer interrupt */
+ write_c0_compare(read_c0_count() + (mips_hpt_frequency/HZ));
+}