summaryrefslogtreecommitdiffstats
path: root/arch/mips/mips-boards
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-10-09 00:36:07 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-10-09 00:36:07 +0000
commit1a743e4f5e92fac7d7a2ce9a58e7223d757fdf81 (patch)
tree882ab65737b0a4edfcc45c04d764257ec115b8f2 /arch/mips/mips-boards
parentb4b017ab8e9c41991c8d550b72ca3e9c8616eeed (diff)
Support for MIPS Atlas and Malta evaluation boards. Chainsaw edition;
doesn't compile because it smokes ld ...
Diffstat (limited to 'arch/mips/mips-boards')
-rw-r--r--arch/mips/mips-boards/atlas/Makefile50
-rw-r--r--arch/mips/mips-boards/atlas/atlas_int.c268
-rw-r--r--arch/mips/mips-boards/atlas/atlas_rtc.c57
-rw-r--r--arch/mips/mips-boards/atlas/atlas_setup.c137
-rw-r--r--arch/mips/mips-boards/generic/Makefile49
-rw-r--r--arch/mips/mips-boards/generic/cmdline.c65
-rw-r--r--arch/mips/mips-boards/generic/display.c47
-rw-r--r--arch/mips/mips-boards/generic/init.c126
-rw-r--r--arch/mips/mips-boards/generic/memory.c246
-rw-r--r--arch/mips/mips-boards/generic/mipsIRQ.S127
-rw-r--r--arch/mips/mips-boards/generic/pci.c271
-rw-r--r--arch/mips/mips-boards/generic/printf.c55
-rw-r--r--arch/mips/mips-boards/generic/reset.c72
-rw-r--r--arch/mips/mips-boards/generic/time.c285
-rw-r--r--arch/mips/mips-boards/malta/Makefile50
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c400
-rw-r--r--arch/mips/mips-boards/malta/malta_rtc.c50
-rw-r--r--arch/mips/mips-boards/malta/malta_setup.c155
18 files changed, 2510 insertions, 0 deletions
diff --git a/arch/mips/mips-boards/atlas/Makefile b/arch/mips/mips-boards/atlas/Makefile
new file mode 100644
index 000000000..822946539
--- /dev/null
+++ b/arch/mips/mips-boards/atlas/Makefile
@@ -0,0 +1,50 @@
+# $Id: Makefile,v 1.1 2000/07/07 10:20:28 carstenl Exp $
+#
+# Makefile
+#
+# 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.
+#
+# #######################################################################
+#
+# Makefile for the MIPS Atlas specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+OBJS = atlas_int.o atlas_rtc.o atlas_setup.o
+
+all: atlas.a
+
+atlas.a: $(OBJS)
+ $(AR) rcs atlas.a $(OBJS)
+ sync
+
+dep:
+ $(CPP) -M *.c > .depend
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c
new file mode 100644
index 000000000..ff4e31d07
--- /dev/null
+++ b/arch/mips/mips-boards/atlas/atlas_int.c
@@ -0,0 +1,268 @@
+/*
+ * 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.
+ *
+ * ########################################################################
+ *
+ * Routines for generic manipulation of the interrupts found on the MIPS
+ * Atlas board.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/irq.h>
+#include <asm/mips-boards/atlas.h>
+#include <asm/mips-boards/atlasint.h>
+
+
+struct atlas_ictrl_regs *atlas_hw0_icregs;
+
+extern asmlinkage void mipsIRQ(void);
+
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+unsigned long spurious_count = 0;
+
+static struct irqaction *hw0_irq_action[ATLASINT_END] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+
+static struct irqaction r4ktimer_action = {
+ NULL, 0, 0, "R4000 timer/counter", NULL, NULL,
+};
+
+static struct irqaction *irq_action[8] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, &r4ktimer_action
+};
+
+#if 0
+#define DEBUG_INT(x...) printk(x)
+#else
+#define DEBUG_INT(x...)
+#endif
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ if(irq_nr >= ATLASINT_END) {
+ printk("whee, invalid irq_nr %d\n", irq_nr);
+ panic("IRQ, you lose...");
+ }
+
+ save_and_cli(flags);
+ atlas_hw0_icregs->intrsten = (1 << irq_nr);
+ restore_flags(flags);
+}
+
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ if(irq_nr >= ATLASINT_END) {
+ printk("whee, invalid irq_nr %d\n", irq_nr);
+ panic("IRQ, you lose...");
+ }
+
+ save_and_cli(flags);
+ atlas_hw0_icregs->intseten = (1 << irq_nr);
+ restore_flags(flags);
+}
+
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ int num = 0;
+ struct irqaction *action;
+
+ for (i = 0; i < 8; i++, num++) {
+ action = irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
+ num, kstat.irqs[0][num],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, " [on-chip]\n");
+ }
+ for (i = 0; i < ATLASINT_END; i++, num++) {
+ action = hw0_irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
+ num, kstat.irqs[0][num],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, " [hw0]\n");
+ }
+ return len;
+}
+
+
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
+{
+ struct irqaction *action;
+
+ DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname);
+
+ if (irq >= ATLASINT_END)
+ return -EINVAL;
+ if (!handler)
+ return -EINVAL;
+
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if(!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = 0;
+ hw0_irq_action[irq] = action;
+ enable_irq(irq);
+
+ return 0;
+}
+
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action;
+
+ if (irq >= ATLASINT_END) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+
+ action = hw0_irq_action[irq];
+ hw0_irq_action[irq] = NULL;
+ disable_irq(irq);
+ kfree(action);
+}
+
+
+int (*irq_cannonicalize)(int irq);
+
+static int atlas_irq_cannonicalize(int irq)
+{
+ return irq; /* Sane hardware, sane code ... */
+}
+
+
+void __init init_IRQ(void)
+{
+ irq_cannonicalize = atlas_irq_cannonicalize;
+ irq_setup();
+}
+
+
+void atlas_hw0_irqdispatch(struct pt_regs *regs)
+{
+ struct irqaction *action;
+ int irq, cpu = smp_processor_id();
+ unsigned long int_status;
+ int i;
+
+ DEBUG_INT("atlas_hw0_irqdispatch\n");
+
+ int_status = atlas_hw0_icregs->intstatus;
+
+ /* if int_status == 0, then the interrupt has already been cleared */
+ if (int_status == 0)
+ return;
+
+ for (i=0; i<ATLASINT_END; i++)
+ if (int_status & 1<<i)
+ break;
+
+ irq = i;
+ action = hw0_irq_action[irq];
+
+ DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq);
+
+ /* if action == NULL, then we don't have a handler for the irq */
+ if ( action == NULL ) {
+ printk("No handler for hw0 irq: %i\n", irq);
+ return;
+ }
+
+ hardirq_enter(cpu);
+ kstat.irqs[0][irq + 8]++;
+ action->handler(irq, action->dev_id, regs);
+ hardirq_exit(cpu);
+
+ return;
+}
+
+
+/* Misc. crap just to keep the kernel linking... */
+unsigned long probe_irq_on (void)
+{
+ return 0;
+}
+
+
+int probe_irq_off (unsigned long irqs)
+{
+ return 0;
+}
+
+
+void __init atlasint_init(void)
+{
+ /*
+ * Mask out all interrupt by writing "1" to all bit position in
+ * the interrupt reset reg.
+ */
+ atlas_hw0_icregs = (struct atlas_ictrl_regs *)ATLAS_ICTRL_REGS_BASE;
+ atlas_hw0_icregs->intrsten = 0xffffffff;
+
+ /* Now safe to set the exception vector. */
+ set_except_vector(0, mipsIRQ);
+}
diff --git a/arch/mips/mips-boards/atlas/atlas_rtc.c b/arch/mips/mips-boards/atlas/atlas_rtc.c
new file mode 100644
index 000000000..b2cc1ad47
--- /dev/null
+++ b/arch/mips/mips-boards/atlas/atlas_rtc.c
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ * ########################################################################
+ *
+ * RTC routines for Atlas style attached Dallas chip.
+ *
+ */
+#include <linux/mc146818rtc.h>
+#include <asm/mips-boards/atlas.h>
+
+
+static unsigned char atlas_rtc_read_data(unsigned long addr)
+{
+ volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG;
+ volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG;
+
+ *rtc_adr_reg = addr;
+
+ return *rtc_dat_reg;
+}
+
+static void atlas_rtc_write_data(unsigned char data, unsigned long addr)
+{
+ volatile unsigned int *rtc_adr_reg = (void *)ATLAS_RTC_ADR_REG;
+ volatile unsigned int *rtc_dat_reg = (void *)ATLAS_RTC_DAT_REG;
+
+ *rtc_adr_reg = addr;
+ *rtc_dat_reg = data;
+}
+
+static int atlas_rtc_bcd_mode(void)
+{
+ return 0;
+}
+
+struct rtc_ops atlas_rtc_ops = {
+ &atlas_rtc_read_data,
+ &atlas_rtc_write_data,
+ &atlas_rtc_bcd_mode
+};
diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c
new file mode 100644
index 000000000..948fac6a9
--- /dev/null
+++ b/arch/mips/mips-boards/atlas/atlas_setup.c
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ *
+ * ########################################################################
+ *
+ * Atlas specific setup, including init of the feature struct.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/mips-boards/atlasint.h>
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void rs_kgdb_hook(int);
+extern void saa9730_kgdb_hook(void);
+extern void breakpoint(void);
+static int remote_debug = 0;
+static int kgdb_on_pci = 0;
+#endif
+
+extern struct rtc_ops atlas_rtc_ops;
+
+extern void mips_reboot_setup(void);
+
+
+static void __init atlas_irq_setup(void)
+{
+ atlasint_init();
+
+#ifdef CONFIG_REMOTE_DEBUG
+ /* If local serial I/O used for debug port, enter kgdb at once */
+ /* Otherwise, this will be done after the SAA9730 is up*/
+ if (remote_debug && !kgdb_on_pci) {
+ set_debug_traps();
+ breakpoint();
+ }
+#endif
+}
+
+
+void __init atlas_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+ int rs_putDebugChar(char);
+ char rs_getDebugChar(void);
+ int saa9730_putDebugChar(char);
+ char saa9730_getDebugChar(void);
+ extern int (*putDebugChar)(char);
+ extern char (*getDebugChar)(void);
+#endif
+ char *argptr;
+
+ irq_setup = atlas_irq_setup;
+
+#ifdef CONFIG_SERIAL_CONSOLE
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "console=ttyS0")) == NULL)
+ {
+ int i=0;
+ char *s = prom_getenv("modetty0");
+ while(s[i] >= '0' && s[i] <= '9')
+ i++;
+ strcpy(serial_console, "ttyS0,");
+ strncpy(serial_console + 6, s, i);
+ prom_printf("Config serial console: %s\n", serial_console);
+ console_setup(serial_console, NULL);
+ }
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) {
+ int line;
+ argptr += strlen("kgdb=ttyS");
+ if (*argptr != '0' && *argptr != '1')
+ printk("KGDB: Uknown serial line /dev/ttyS%c, "
+ "falling back to /dev/ttyS1\n", *argptr);
+ line = *argptr == '0' ? 0 : 1;
+ printk("KGDB: Using serial line /dev/ttyS%d for session\n",
+ line ? 1 : 0);
+
+ if(line == 0) {
+ rs_kgdb_hook(line);
+ putDebugChar = rs_putDebugChar;
+ getDebugChar = rs_getDebugChar;
+ } else {
+ saa9730_kgdb_hook();
+ putDebugChar = saa9730_putDebugChar;
+ getDebugChar = saa9730_getDebugChar;
+ kgdb_on_pci = 1;
+ }
+
+ prom_printf("KGDB: Using serial line /dev/ttyS%d for session, "
+ "please connect your debugger\n", line ? 1 : 0);
+
+ remote_debug = 1;
+ /* Breakpoints and stuff are in atlas_irq_setup() */
+ }
+#endif
+ argptr = prom_getcmdline();
+#if 0 /* Later -- Ralf */
+ if ((argptr = strstr(argptr, "nofpu")) != NULL)
+ mips_cpu.options &= ~MIPS_CPU_FPU;
+#endif
+
+ rtc_ops = &atlas_rtc_ops;
+
+ mips_reboot_setup();
+}
diff --git a/arch/mips/mips-boards/generic/Makefile b/arch/mips/mips-boards/generic/Makefile
new file mode 100644
index 000000000..377190c96
--- /dev/null
+++ b/arch/mips/mips-boards/generic/Makefile
@@ -0,0 +1,49 @@
+# $Id: Makefile,v 1.1 2000/07/07 10:21:35 carstenl Exp $
+#
+# Makefile
+#
+# 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.
+#
+# #######################################################################
+#
+# Makefile for the MIPS boards generic routines under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+OBJS = mipsIRQ.o pci.o reset.o display.o init.o memory.o printf.o cmdline.o time.o
+
+all: mipsboards.a
+
+mipsboards.a: $(OBJS)
+ $(AR) rcs mipsboards.a $(OBJS)
+ sync
+
+dep:
+ $(CPP) -M *.c > .depend
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/mips/mips-boards/generic/cmdline.c b/arch/mips/mips-boards/generic/cmdline.c
new file mode 100644
index 000000000..b14650f41
--- /dev/null
+++ b/arch/mips/mips-boards/generic/cmdline.c
@@ -0,0 +1,65 @@
+/*
+ * 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/config.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/bootinfo.h>
+
+/* #define DEBUG_CMDLINE */
+
+extern int prom_argc;
+extern char **prom_argv;
+
+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';
+
+#ifdef DEBUG_CMDLINE
+ prom_printf("prom_init_cmdline: %s\n", &(arcs_cmdline[0]));
+#endif
+}
diff --git a/arch/mips/mips-boards/generic/display.c b/arch/mips/mips-boards/generic/display.c
new file mode 100644
index 000000000..218c4e624
--- /dev/null
+++ b/arch/mips/mips-boards/generic/display.c
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * ########################################################################
+ *
+ * Display routines for display messages in MIPS boards ascii display.
+ *
+ */
+
+#include <asm/mips-boards/generic.h>
+
+
+void mips_display_message(const char *str)
+{
+ volatile unsigned int *display = (void *)ASCII_DISPLAY_POS_BASE;
+ int i;
+
+ for (i = 0; i <= 14; i=i+2) {
+ if (*str)
+ display[i] = *str++;
+ else
+ display[i] = ' ';
+ }
+}
+
+void mips_display_word(unsigned int num)
+{
+ volatile unsigned int *display = (void *)ASCII_DISPLAY_WORD_BASE;
+
+ *display = num;
+}
diff --git a/arch/mips/mips-boards/generic/init.c b/arch/mips/mips-boards/generic/init.c
new file mode 100644
index 000000000..f5b71c020
--- /dev/null
+++ b/arch/mips/mips-boards/generic/init.c
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ *
+ * ########################################################################
+ *
+ * PROM library initialisation code.
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <asm/mips-boards/prom.h>
+
+/* Environment variable */
+typedef struct
+{
+ char *name;
+ char *val;
+}t_env_var;
+
+int prom_argc;
+char **prom_argv, **prom_envp;
+
+int init_debug = 0;
+
+char *prom_getenv(char *envname)
+{
+ /*
+ * Return a pointer to the given environment variable.
+ */
+
+ t_env_var *env = (t_env_var *)prom_envp;
+ int i;
+
+ i = strlen(envname);
+
+ while(env->name) {
+ if(strncmp(envname, env->name, i) == 0) {
+ return(env->val);
+ }
+ env++;
+ }
+ return(NULL);
+}
+
+static inline unsigned char str2hexnum(unsigned char c)
+{
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return 0; /* foo */
+}
+
+static inline void str2eaddr(unsigned char *ea, unsigned char *str)
+{
+ int i;
+
+ for(i = 0; i < 6; i++) {
+ unsigned char num;
+
+ if((*str == '.') || (*str == ':'))
+ str++;
+ num = str2hexnum(*str++) << 4;
+ num |= (str2hexnum(*str++));
+ ea[i] = num;
+ }
+}
+
+int get_ethernet_addr(char *ethernet_addr)
+{
+ char *ethaddr_str;
+
+ ethaddr_str = prom_getenv("ethaddr");
+ if (!ethaddr_str) {
+ printk("ethaddr not set in boot prom\n");
+ return -1;
+ }
+ str2eaddr(ethernet_addr, ethaddr_str);
+
+ if (init_debug > 1)
+ {
+ int i;
+ printk("get_ethernet_addr: ");
+ for (i=0; i<5; i++)
+ printk("%02x:", (unsigned char)*(ethernet_addr+i));
+ printk("%02x\n", *(ethernet_addr+i));
+ }
+
+ return 0;
+}
+
+int __init prom_init(int argc, char **argv, char **envp)
+{
+ prom_argc = argc;
+ prom_argv = argv;
+ prom_envp = envp;
+
+ mips_display_message("LINUX");
+
+ setup_prom_printf();
+ prom_printf("\nLINUX started...\n");
+
+ prom_init_cmdline();
+
+ prom_meminit();
+
+ return 0;
+}
diff --git a/arch/mips/mips-boards/generic/memory.c b/arch/mips/mips-boards/generic/memory.c
new file mode 100644
index 000000000..b8e442f70
--- /dev/null
+++ b/arch/mips/mips-boards/generic/memory.c
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ *
+ * ########################################################################
+ *
+ * PROM library functions for acquiring/using memory descriptors given to
+ * us from the YAMON.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+
+#include <asm/mips-boards/prom.h>
+
+/* #define DEBUG */
+
+enum yamon_memtypes {
+ yamon_dontuse,
+ yamon_prom,
+ yamon_free,
+};
+struct prom_pmemblock mdesc[PROM_MAX_PMEMBLOCKS];
+
+#define MEMTYPE_DONTUSE 0
+#define MEMTYPE_PROM 1
+#define MEMTYPE_FREE 2
+
+#ifdef DEBUG
+static char *mtypes[3] = {
+ "Dont use memory",
+ "YAMON PROM memory",
+ "Free memmory",
+};
+#endif
+
+struct prom_pmemblock * __init prom_getmdesc(void)
+{
+ char *memsize_str;
+ unsigned int memsize;
+
+ memsize_str = prom_getenv("memsize");
+ if (!memsize_str) {
+ prom_printf("memsize not set in boot prom, set to default (32Mb)\n");
+ memsize = 0x02000000;
+ }
+ else
+ {
+#ifdef DEBUG
+ prom_printf("prom_memsize = %s\n", memsize_str);
+#endif
+ memsize = simple_strtol(memsize_str, NULL, 0);
+ }
+
+ memset(mdesc, 0, sizeof(mdesc));
+
+ mdesc[0].type = yamon_dontuse;
+ mdesc[0].base = 0x00000000;
+ mdesc[0].size = 0x00001000;
+
+ mdesc[1].type = yamon_prom;
+ mdesc[1].base = 0x00001000;
+ mdesc[1].size = 0x000ef000;
+
+#if (CONFIG_MIPS_MALTA)
+ /*
+ * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
+ * south bridge and PCI access always forwarded to the ISA Bus and
+ * BIOSCS# is always generated.
+ * This mean that this area can't be used as DMA memory for PCI
+ * devices.
+ */
+ mdesc[2].type = yamon_dontuse;
+ mdesc[2].base = 0x000f0000;
+ mdesc[2].size = 0x00010000;
+#else
+ mdesc[2].type = yamon_prom;
+ mdesc[2].base = 0x000f0000;
+ mdesc[2].size = 0x00010000;
+#endif
+
+ mdesc[3].type = yamon_free;
+ mdesc[3].base = 0x00100000;
+ mdesc[3].size = memsize - mdesc[3].base;
+
+ return &mdesc[0];
+}
+
+static struct prom_pmemblock prom_pblocks[PROM_MAX_PMEMBLOCKS];
+
+struct prom_pmemblock * __init prom_getpblock_array(void)
+{
+ return &prom_pblocks[0];
+}
+
+static int __init prom_memtype_classify (unsigned int type)
+{
+ switch (type) {
+ case yamon_free:
+ return MEMTYPE_FREE;
+ case yamon_prom:
+ return MEMTYPE_PROM;
+ default:
+ return MEMTYPE_DONTUSE;
+ }
+}
+
+static void __init prom_setup_memupper(void)
+{
+ struct prom_pmemblock *p, *highest;
+
+ for(p = prom_getpblock_array(), highest = 0; p->size != 0; p++) {
+ if(p->base == 0xdeadbeef)
+ prom_printf("WHEEE, bogus pmemblock\n");
+ if(!highest || p->base > highest->base)
+ highest = p;
+ }
+ mips_memory_upper = highest->base + highest->size;
+#ifdef DEBUG
+ prom_printf("prom_setup_memupper: mips_memory_upper = %08lx\n",
+ mips_memory_upper);
+#endif
+}
+
+void __init prom_meminit(void)
+{
+ struct prom_pmemblock *p;
+ int totram;
+ int i = 0;
+
+#ifdef DEBUG
+ p = prom_getmdesc();
+ prom_printf("YAMON MEMORY DESCRIPTOR dump:\n");
+ while(p->size) {
+ prom_printf("[%d,%p]: base<%08lx> size<%08lx> type<%s>\n",
+ i, p, p->base, p->size, memtypes[p->type]);
+ p++;
+ i++;
+ }
+#endif
+ p = prom_getmdesc();
+ totram = 0;
+ i = 0;
+ while(p->size) {
+ prom_pblocks[i].type = prom_memtype_classify (p->type);
+ prom_pblocks[i].base = p->base | 0x80000000;
+ prom_pblocks[i].size = p->size;
+ switch (prom_pblocks[i].type) {
+ case MEMTYPE_FREE:
+ totram += prom_pblocks[i].size;
+#ifdef DEBUG
+ prom_printf("free_chunk[%d]: base=%08lx size=%d\n",
+ i, prom_pblocks[i].base,
+ prom_pblocks[i].size);
+#endif
+ i++;
+ break;
+ case MEMTYPE_PROM:
+#ifdef DEBUG
+ prom_printf("prom_chunk[%d]: base=%08lx size=%d\n",
+ i, prom_pblocks[i].base,
+ prom_pblocks[i].size);
+#endif
+ i++;
+ break;
+ default:
+ break;
+ }
+ p++;
+ }
+ prom_pblocks[i].base = 0xdeadbeef;
+ prom_pblocks[i].size = 0; /* indicates last elem. of array */
+ printk("PROMLIB: Total free ram %d bytes (%dK,%dMB)\n",
+ totram, (totram/1024), (totram/1024/1024));
+
+ /* Setup upper physical memory bound. */
+ prom_setup_memupper();
+}
+
+/* Called from mem_init() to fixup the mem_map page settings. */
+void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
+{
+ struct prom_pmemblock *p;
+ int i, nents;
+
+ /* Determine number of pblockarray entries. */
+ p = prom_getpblock_array();
+ for(i = 0; p[i].size; i++)
+ ;
+ nents = i;
+restart:
+ while(start < end) {
+ for(i = 0; i < nents; i++) {
+ if((p[i].type == MEMTYPE_FREE) &&
+ (start >= (p[i].base)) &&
+ (start < (p[i].base + p[i].size))) {
+ start = p[i].base + p[i].size;
+ start &= PAGE_MASK;
+ goto restart;
+ }
+ }
+ set_bit(PG_reserved, &mem_map[MAP_NR(start)].flags);
+ start += PAGE_SIZE;
+ }
+}
+
+void prom_free_prom_memory (void)
+{
+ struct prom_pmemblock *p;
+ unsigned long addr;
+ unsigned long num_pages = 0;
+
+ for (p = prom_getpblock_array(); p->size != 0; p++) {
+ if (p->type != MEMTYPE_PROM)
+ continue;
+
+ for (addr = p->base; addr < p->base + p->size;
+ addr += PAGE_SIZE) {
+ mem_map[MAP_NR(addr)].flags &= ~(1 << PG_reserved);
+ atomic_set(&mem_map[MAP_NR(addr)].count, 1);
+ free_page(addr);
+ num_pages++;
+ }
+ }
+ printk("Freeing prom memory: %ldk freed\n",
+ (num_pages << (PAGE_SHIFT - 10)));
+}
diff --git a/arch/mips/mips-boards/generic/mipsIRQ.S b/arch/mips/mips-boards/generic/mipsIRQ.S
new file mode 100644
index 000000000..110f67fad
--- /dev/null
+++ b/arch/mips/mips-boards/generic/mipsIRQ.S
@@ -0,0 +1,127 @@
+/* $Id: mipsIRQ.S,v 1.2 2000/08/25 06:53:54 carstenl Exp $
+ *
+ * mipsIRQ.S
+ *
+ * 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)
+ *
+ * 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 mask
+
+ /* 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 # delay slot
+
+ j ret_from_irq
+ nop # delay slot
+
+1:
+ beq a0, zero, 1f
+ nop
+
+ /* Wheee, combined hardware level zero interrupt. */
+#if defined(CONFIG_MIPS_ATLAS)
+ jal atlas_hw0_irqdispatch
+#elif defined(CONFIG_MIPS_MALTA)
+ jal malta_hw0_irqdispatch
+#else
+#error "MIPS board not supported\n"
+#endif
+ move a0, sp # delay slot
+
+ j ret_from_irq
+ nop # delay slot
+
+1:
+ /* 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/generic/pci.c b/arch/mips/mips-boards/generic/pci.c
new file mode 100644
index 000000000..0909ca2ae
--- /dev/null
+++ b/arch/mips/mips-boards/generic/pci.c
@@ -0,0 +1,271 @@
+/*
+ * 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.
+ *
+ * ########################################################################
+ *
+ * MIPS boards specific PCI support.
+ *
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_PCI
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/gt64120.h>
+#ifdef CONFIG_MIPS_MALTA
+#include <asm/mips-boards/malta.h>
+#endif
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+static int
+mips_pcibios_config_access(unsigned char access_type, struct pci_dev *dev,
+ unsigned char where, u32 *data)
+{
+ unsigned char bus = dev->bus->number;
+ unsigned char dev_fn = dev->devfn;
+ u32 intr;
+
+ if ((bus == 0) && (dev_fn >= PCI_DEVFN(31,0)))
+ return -1; /* Because of a bug in the galileo (for slot 31). */
+
+ /* Clear cause register bits */
+ GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT) );
+
+ /* Setup address */
+ GT_WRITE( GT_PCI0_CFGADDR_OFS,
+ (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+ (dev_fn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+ ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+ GT_PCI0_CFGADDR_CONFIGEN_BIT );
+
+ if (access_type == PCI_ACCESS_WRITE) {
+ GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+ } else {
+ GT_READ(GT_PCI0_CFGDATA_OFS, *data);
+ }
+
+ /* Check for master or target abort */
+ GT_READ(GT_INTRCAUSE_OFS, intr);
+
+ if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT))
+ {
+ /* Error occured */
+
+ /* Clear bits */
+ GT_WRITE( GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+ GT_INTRCAUSE_TARABORT0_BIT) );
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int
+mips_pcibios_read_config_byte (struct pci_dev *dev, int where, u8 *val)
+{
+ u32 data = 0;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+mips_pcibios_read_config_word (struct pci_dev *dev, int where, u16 *val)
+{
+ u32 data = 0;
+
+ if (where & 1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mips_pcibios_read_config_dword (struct pci_dev *dev, int where, u32 *val)
+{
+ u32 data = 0;
+
+ if (where & 3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int
+mips_pcibios_write_config_byte (struct pci_dev *dev, int where, u8 val)
+{
+ u32 data = 0;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mips_pcibios_write_config_word (struct pci_dev *dev, int where, u16 val)
+{
+ u32 data = 0;
+
+ if (where & 1)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_READ, dev, where, &data))
+ return -1;
+
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+
+ if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &data))
+ return -1;
+
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+mips_pcibios_write_config_dword(struct pci_dev *dev, int where, u32 val)
+{
+ if (where & 3)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ if (mips_pcibios_config_access(PCI_ACCESS_WRITE, dev, where, &val))
+ return -1;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops mips_pci_ops = {
+ mips_pcibios_read_config_byte,
+ mips_pcibios_read_config_word,
+ mips_pcibios_read_config_dword,
+ mips_pcibios_write_config_byte,
+ mips_pcibios_write_config_word,
+ mips_pcibios_write_config_dword
+};
+
+void __init pcibios_init(void)
+{
+#ifdef CONFIG_MIPS_MALTA
+ struct pci_dev *pdev;
+ unsigned char reg_val;
+#endif
+
+ printk("PCI: Probing PCI hardware on host bus 0.\n");
+ pci_scan_bus(0, &mips_pci_ops, NULL);
+
+ /*
+ * Due to a bug in the Galileo system controller, we need to setup
+ * the PCI BAR for the Galileo internal registers.
+ * This should be done in the bios/bootprom and will be fixed in
+ * a later revision of YAMON (the MIPS boards boot prom).
+ */
+ GT_WRITE(GT_PCI0_CFGADDR_OFS,
+ (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
+ (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 device */
+ (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0 */
+ ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4 */
+ GT_PCI0_CFGADDR_CONFIGEN_BIT );
+
+ /* Perform the write */
+ GT_WRITE( GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE));
+
+#ifdef CONFIG_MIPS_MALTA
+ for (pdev = pci_devices; pdev; pdev=pdev->next) {
+ if ((pdev->vendor == PCI_VENDOR_ID_INTEL)
+ && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB)
+ && (PCI_SLOT(pdev->devfn) == 0x0a)) {
+ /*
+ * IDE Decode enable.
+ */
+ pci_read_config_byte(pdev, 0x41, &reg_val);
+ pci_write_config_byte(pdev, 0x41, reg_val | 0x80);
+ pci_read_config_byte(pdev, 0x43, &reg_val);
+ pci_write_config_byte(pdev, 0x43, reg_val | 0x80);
+ }
+
+ if ((pdev->vendor == PCI_VENDOR_ID_INTEL)
+ && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB_0)
+ && (PCI_SLOT(pdev->devfn) == 0x0a)) {
+ /*
+ * Set top of main memory accessible by ISA or DMA
+ * devices to 16 Mb.
+ */
+ pci_read_config_byte(pdev, 0x69, &reg_val);
+ pci_write_config_byte(pdev, 0x69, reg_val | 0xf0);
+ }
+ }
+
+ /*
+ * Activate Floppy Controller in the SMSC FDC37M817 Super I/O
+ * Controller.
+ * This should be done in the bios/bootprom and will be fixed in
+ * a later revision of YAMON (the MIPS boards boot prom).
+ */
+ /* Entering config state. */
+ SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG);
+
+ /* Activate floppy controller. */
+ SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG);
+ SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG);
+ SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG);
+ SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG);
+
+ /* Exit config state. */
+ SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG);
+#endif
+}
+
+#endif /* CONFIG_PCI */
diff --git a/arch/mips/mips-boards/generic/printf.c b/arch/mips/mips-boards/generic/printf.c
new file mode 100644
index 000000000..3c21ae8bf
--- /dev/null
+++ b/arch/mips/mips-boards/generic/printf.c
@@ -0,0 +1,55 @@
+/*
+ * 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/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/addrspace.h>
+#include <asm/mips-boards/generic.h>
+
+static char ppbuf[1024];
+
+void (*prom_print_str)(unsigned int out, char *s, int len);
+
+
+void __init setup_prom_printf(void)
+{
+ prom_print_str = (void *)*(unsigned int *)YAMON_PROM_PRINT_ADDR;
+}
+
+void __init prom_printf(char *fmt, ...)
+{
+ va_list args;
+ int len;
+
+ va_start(args, fmt);
+ vsprintf(ppbuf, fmt, args);
+ len = strlen(ppbuf);
+
+ prom_print_str(0, ppbuf, len);
+
+ va_end(args);
+ return;
+
+}
diff --git a/arch/mips/mips-boards/generic/reset.c b/arch/mips/mips-boards/generic/reset.c
new file mode 100644
index 000000000..83cd0c3ec
--- /dev/null
+++ b/arch/mips/mips-boards/generic/reset.c
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ *
+ * ########################################################################
+ *
+ * Reset the MIPS boards.
+ *
+ */
+#include <linux/config.h>
+
+#include <asm/reboot.h>
+#include <asm/mips-boards/generic.h>
+#if defined(CONFIG_MIPS_ATLAS)
+#include <asm/mips-boards/atlas.h>
+#endif
+
+static void mips_machine_restart(char *command);
+static void mips_machine_halt(void);
+#if defined(CONFIG_MIPS_ATLAS)
+static void atlas_machine_power_off(void);
+#endif
+
+static void mips_machine_restart(char *command)
+{
+ volatile unsigned int *softres_reg = (void *)SOFTRES_REG;
+
+ *softres_reg = GORESET;
+}
+
+static void mips_machine_halt(void)
+{
+ volatile unsigned int *softres_reg = (void *)SOFTRES_REG;
+
+ *softres_reg = GORESET;
+}
+
+#if defined(CONFIG_MIPS_ATLAS)
+static void atlas_machine_power_off(void)
+{
+ volatile unsigned int *psustby_reg = (void *)ATLAS_PSUSTBY_REG;
+
+ *psustby_reg = ATLAS_GOSTBY;
+}
+#endif
+
+void mips_reboot_setup(void)
+{
+ _machine_restart = mips_machine_restart;
+ _machine_halt = mips_machine_halt;
+#if defined(CONFIG_MIPS_ATLAS)
+ _machine_power_off = atlas_machine_power_off;
+#endif
+#if defined(CONFIG_MIPS_MALTA)
+ _machine_power_off = mips_machine_halt;
+#endif
+}
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
new file mode 100644
index 000000000..84592fc2f
--- /dev/null
+++ b/arch/mips/mips-boards/generic/time.c
@@ -0,0 +1,285 @@
+/*
+ * 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.
+ *
+ * ########################################################################
+ *
+ * Setting up the clock on the MIPS boards.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel_stat.h>
+#include <linux/sched.h>
+
+#include <asm/mipsregs.h>
+#include <asm/ptrace.h>
+
+#include <linux/mc146818rtc.h>
+#include <linux/timex.h>
+
+#include <asm/mips-boards/generic.h>
+#include <asm/mips-boards/prom.h>
+
+static long last_rtc_update = 0;
+unsigned long missed_heart_beats = 0;
+
+static unsigned long r4k_offset; /* Amount to increment compare reg each time */
+static unsigned long r4k_cur; /* What counter should be at next timer irq */
+
+#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
+
+#if defined(CONFIG_MIPS_ATLAS)
+static char display_string[] = " LINUX ON ATLAS ";
+#endif
+#if defined(CONFIG_MIPS_MALTA)
+static char display_string[] = " LINUX ON MALTA ";
+#endif
+static unsigned int display_count = 0;
+#define MAX_DISPLAY_COUNT (sizeof(display_string) - 8)
+
+static unsigned int timer_tick_count=0;
+
+
+static inline void ack_r4ktimer(unsigned long newval)
+{
+ write_32bit_cp0_register(CP0_COMPARE, newval);
+}
+
+
+/*
+ * In order to set the CMOS clock precisely, set_rtc_mmss has to be
+ * called 500 ms after the second nowtime has started, because when
+ * nowtime is written into the registers of the CMOS clock, it will
+ * jump to the next second precisely 500 ms later. Check the Motorola
+ * MC146818A or Dallas DS12887 data sheet for details.
+ *
+ * BUG: This routine does not handle hour overflow properly; it just
+ * sets the minutes. Usually you won't notice until after reboot!
+ */
+static int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned char save_control, save_freq_select;
+
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_mmss: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ /* The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+ return retval;
+}
+
+/*
+ * There are a lot of conceptually broken versions of the MIPS timer interrupt
+ * handler floating around. This one is rather different, but the algorithm
+ * is provably more robust.
+ */
+void mips_timer_interrupt(struct pt_regs *regs)
+{
+ int irq = 7;
+
+ if(r4k_offset != 0) {
+ do {
+ kstat.irqs[0][irq]++;
+ do_timer(regs);
+
+ /* Historical comment/code:
+ * RTC time of day s updated approx. every 11
+ * minutes. Because of how the numbers work out
+ * we need to make absolutely sure we do this update
+ * within 500ms before the * next second starts,
+ * thus the following code.
+ */
+ if ((time_status & STA_UNSYNC) == 0
+ && xtime.tv_sec > last_rtc_update + 660
+ && xtime.tv_usec >= 500000 - (tick >> 1)
+ && xtime.tv_usec <= 500000 + (tick >> 1))
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+ else
+ /* do it again in 60 s */
+ last_rtc_update = xtime.tv_sec - 600;
+
+ if ((timer_tick_count++ % HZ) == 0)
+ {
+ mips_display_message(&display_string[display_count++]);
+ if (display_count == MAX_DISPLAY_COUNT)
+ display_count = 0;
+ }
+
+ r4k_cur += r4k_offset;
+ ack_r4ktimer(r4k_cur);
+
+ } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
+ - r4k_cur) < 0x7fffffff);
+ } else ack_r4ktimer(0);
+}
+
+static unsigned long cal_r4koff(void)
+{
+ unsigned long count;
+ unsigned long flags;
+
+ /*
+ * Figure out the r4k offset, the amount to increment the compare
+ * register for each time tick.
+ * Use the RTC to calculate offset.
+ */
+ /* Disable Interrupts */
+ save_and_cli(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_32bit_cp0_register(CP0_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_32bit_cp0_register(CP0_COUNT);
+
+ /* restore interrupts */
+ restore_flags(flags);
+
+ return (count / HZ);
+}
+
+static unsigned long __init get_mips_time(void)
+{
+ unsigned int year, mon, day, hour, min, sec;
+ unsigned char save_control;
+
+ save_control = CMOS_READ(RTC_CONTROL);
+
+ /* Freeze it. */
+ CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);
+
+ /* Read regs. */
+ sec = CMOS_READ(RTC_SECONDS);
+ min = CMOS_READ(RTC_MINUTES);
+ hour = CMOS_READ(RTC_HOURS);
+
+ if (!(save_control & RTC_24H))
+ {
+ if ((hour & 0xf) == 0xc)
+ hour &= 0x80;
+ if (hour & 0x80)
+ hour = (hour & 0xf) + 12;
+ }
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ mon = CMOS_READ(RTC_MONTH);
+ year = CMOS_READ(RTC_YEAR);
+
+ /* Unfreeze clock. */
+ CMOS_WRITE(save_control, RTC_CONTROL);
+
+ if ((year += 1900) < 1970)
+ year += 100;
+
+ return mktime(year, mon, day, hour, min, sec);
+}
+
+void __init time_init(void)
+{
+ unsigned int est_freq;
+
+ /* Set Data mode - binary. */
+ CMOS_WRITE(CMOS_READ(RTC_CONTROL) | RTC_DM_BINARY, RTC_CONTROL);
+
+ printk("calculating r4koff... ");
+ r4k_offset = cal_r4koff();
+ printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
+
+ est_freq = 2*r4k_offset*HZ;
+ est_freq += 5000; /* round */
+ est_freq -= est_freq%10000;
+ printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
+ (est_freq%1000000)*100/1000000);
+ r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
+
+ write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
+ set_cp0_status(ST0_IM, ALLINTS);
+
+ /* Read time from the RTC chipset. */
+ xtime.tv_sec = get_mips_time();
+ xtime.tv_usec = 0;
+}
+
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+
+ save_and_cli(flags);
+ *tv = xtime;
+ restore_flags(flags);
+}
+
+void do_settimeofday(struct timeval *tv)
+{
+ cli();
+ xtime = *tv;
+ time_state = TIME_BAD;
+ time_maxerror = MAXPHASE;
+ time_esterror = MAXPHASE;
+ sti();
+}
diff --git a/arch/mips/mips-boards/malta/Makefile b/arch/mips/mips-boards/malta/Makefile
new file mode 100644
index 000000000..5e8bede22
--- /dev/null
+++ b/arch/mips/mips-boards/malta/Makefile
@@ -0,0 +1,50 @@
+# $Id: Makefile,v 1.1 2000/07/07 10:22:15 carstenl Exp $
+#
+# Makefile
+#
+# Carsten Langgaard, carstenl@mips.com
+# Copyright (C) 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.
+#
+# #######################################################################
+#
+# Makefile for the MIPS Malta specific kernel interface routines
+# under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.s:
+ $(CPP) $(CFLAGS) $< -o $*.s
+.S.o:
+ $(CC) $(CFLAGS) -c $< -o $*.o
+
+OBJS = malta_int.o malta_rtc.o malta_setup.o
+
+all: malta.a
+
+malta.a: $(OBJS)
+ $(AR) rcs malta.a $(OBJS)
+ sync
+
+dep:
+ $(CPP) -M *.c > .depend
+
+include $(TOPDIR)/Rules.make
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
new file mode 100644
index 000000000..d00d68752
--- /dev/null
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -0,0 +1,400 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 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.
+ *
+ * ########################################################################
+ *
+ * Routines for generic manipulation of the interrupts found on the MIPS
+ * Malta board.
+ * The interrupt controller is located in the South Bridge a PIIX4 device
+ * with two internal 82C95 interrupt controllers.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/random.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mips-boards/malta.h>
+#include <asm/mips-boards/maltaint.h>
+#include <asm/mips-boards/piix4.h>
+#include <asm/mips-boards/gt64120.h>
+#include <asm/mips-boards/generic.h>
+
+extern asmlinkage void mipsIRQ(void);
+
+unsigned int local_bh_count[NR_CPUS];
+unsigned int local_irq_count[NR_CPUS];
+unsigned long spurious_count = 0;
+
+static struct irqaction *hw0_irq_action[MALTAINT_END] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
+};
+
+static struct irqaction r4ktimer_action = {
+ NULL, 0, 0, "R4000 timer/counter", NULL, NULL,
+};
+
+static struct irqaction *irq_action[8] = {
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, &r4ktimer_action
+};
+
+#if 0
+#define DEBUG_INT(x...) printk(x)
+#else
+#define DEBUG_INT(x...)
+#endif
+
+/*
+ * This contains the interrupt mask for both 82C59 interrupt controllers.
+ */
+static unsigned int cached_int_mask = 0xffff;
+
+
+void disable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ if(irq_nr >= MALTAINT_END) {
+ printk("whee, invalid irq_nr %d\n", irq_nr);
+ panic("IRQ, you lose...");
+ }
+
+ save_and_cli(flags);
+ cached_int_mask |= (1 << irq_nr);
+ if (irq_nr & 8) {
+ outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
+ } else {
+ outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+ }
+ restore_flags(flags);
+}
+
+
+void enable_irq(unsigned int irq_nr)
+{
+ unsigned long flags;
+
+ if(irq_nr >= MALTAINT_END) {
+ printk("whee, invalid irq_nr %d\n", irq_nr);
+ panic("IRQ, you lose...");
+ }
+
+ save_and_cli(flags);
+ cached_int_mask &= ~(1 << irq_nr);
+ if (irq_nr & 8) {
+ outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
+
+ /* Enable irq 2 (cascade interrupt). */
+ cached_int_mask &= ~(1 << 2);
+ outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+ } else {
+ outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+ }
+ restore_flags(flags);
+}
+
+
+int get_irq_list(char *buf)
+{
+ int i, len = 0;
+ int num = 0;
+ struct irqaction *action;
+
+ for (i = 0; i < 8; i++, num++) {
+ action = irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
+ num, kstat.irqs[0][num],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, " [on-chip]\n");
+ }
+ for (i = 0; i < MALTAINT_END; i++, num++) {
+ action = hw0_irq_action[i];
+ if (!action)
+ continue;
+ len += sprintf(buf+len, "%2d: %8d %c %s",
+ num, kstat.irqs[0][num],
+ (action->flags & SA_INTERRUPT) ? '+' : ' ',
+ action->name);
+ for (action=action->next; action; action = action->next) {
+ len += sprintf(buf+len, ",%s %s",
+ (action->flags & SA_INTERRUPT) ? " +" : "",
+ action->name);
+ }
+ len += sprintf(buf+len, " [hw0]\n");
+ }
+ return len;
+}
+
+
+static int setup_irq(int irq, struct irqaction * new)
+{
+ int shared = 0;
+ struct irqaction *old, **p;
+
+ p = &hw0_irq_action[irq];
+ if ((old = *p) != NULL) {
+ /* Can't share interrupts unless both agree to */
+ if (!(old->flags & new->flags & SA_SHIRQ))
+ return -EBUSY;
+
+ /* Can't share interrupts unless both are same type */
+ if ((old->flags ^ new->flags) & SA_INTERRUPT)
+ return -EBUSY;
+
+ /* add new interrupt at end of irq queue */
+ do {
+ p = &old->next;
+ old = *p;
+ } while (old);
+ shared = 1;
+ }
+
+ if (new->flags & SA_SAMPLE_RANDOM)
+ rand_initialize_irq(irq);
+
+ *p = new;
+ if (!shared)
+ enable_irq(irq);
+
+ return 0;
+}
+
+int request_irq(unsigned int irq,
+ void (*handler)(int, void *, struct pt_regs *),
+ unsigned long irqflags,
+ const char * devname,
+ void *dev_id)
+{
+ struct irqaction *action;
+ int retval;
+
+ DEBUG_INT("request_irq: irq=%d, devname = %s\n", irq, devname);
+
+ if (irq >= MALTAINT_END)
+ return -EINVAL;
+ if (!handler)
+ return -EINVAL;
+
+ action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+ if(!action)
+ return -ENOMEM;
+
+ action->handler = handler;
+ action->flags = irqflags;
+ action->mask = 0;
+ action->name = devname;
+ action->dev_id = dev_id;
+ action->next = 0;
+
+ retval = setup_irq(irq, action);
+ if (retval)
+ kfree(action);
+
+ return retval;
+}
+
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action, **p;
+
+ if (irq >= MALTAINT_END) {
+ printk("Trying to free IRQ%d\n",irq);
+ return;
+ }
+
+ for (p = &hw0_irq_action[irq]; (action = *p) != NULL;
+ p = &action->next)
+ {
+ if (action->dev_id != dev_id)
+ continue;
+
+ /* Found it - now free it */
+ *p = action->next;
+ kfree(action);
+ if (!hw0_irq_action[irq])
+ disable_irq(irq);
+ return;
+ }
+ printk("Trying to free IRQ%d\n",irq);
+}
+
+
+int (*irq_cannonicalize)(int irq);
+
+static int malta_irq_cannonicalize(int irq)
+{
+ return ((irq == 2) ? 9 : irq);
+}
+
+
+void __init init_IRQ(void)
+{
+ irq_cannonicalize = malta_irq_cannonicalize;
+ irq_setup();
+}
+
+
+static inline int get_int(int *irq)
+{
+ /*
+ * Determine highest priority pending interrupt by performing
+ * a PCI Interrupt Acknowledge cycle.
+ */
+ GT_READ(GT_PCI0_IACK_OFS, *irq);
+ *irq &= 0xFF;
+
+ /*
+ * IRQ7 is used to detect spurious interrupts.
+ * The interrupt acknowledge cycle returns IRQ7, if no
+ * interrupts is requested.
+ * We can differentiate between this situation and a
+ * "Normal" IRQ7 by reading the ISR.
+ */
+ if (*irq == 7)
+ {
+ outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR, PIIX4_ICTLR1_OCW3);
+ if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7)))
+ return -1; /* Spurious interrupt. */
+ }
+
+ return 0;
+}
+
+static inline void ack_int(int irq)
+{
+ if (irq & 8) {
+ /* Specific EOI to cascade */
+ outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI | PIIX4_OCW2_ILS_2,
+ PIIX4_ICTLR1_OCW2);
+
+ /* Non specific EOI to cascade */
+ outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR2_OCW2);
+ } else {
+ /* Non specific EOI to cascade */
+ outb(PIIX4_OCW2_SEL | PIIX4_OCW2_NSEOI, PIIX4_ICTLR1_OCW2);
+ }
+}
+
+void malta_hw0_irqdispatch(struct pt_regs *regs)
+{
+ struct irqaction *action;
+ int irq=0, cpu = smp_processor_id();
+
+ DEBUG_INT("malta_hw0_irqdispatch\n");
+
+ if (get_int(&irq))
+ return; /* interrupt has already been cleared */
+
+ disable_irq(irq);
+ ack_int(irq);
+
+ DEBUG_INT("malta_hw0_irqdispatch: irq=%d\n", irq);
+ action = hw0_irq_action[irq];
+
+ /*
+ * if action == NULL, then we don't have a handler
+ * for the irq
+ */
+ if ( action == NULL )
+ return;
+
+ hardirq_enter(cpu);
+ kstat.irqs[0][irq + 8]++;
+ do {
+ action->handler(irq, action->dev_id, regs);
+ action = action->next;
+ } while (action);
+
+ enable_irq(irq);
+ hardirq_exit(cpu);
+
+ return;
+}
+
+
+unsigned long probe_irq_on (void)
+{
+ unsigned int i, irqs = 0;
+ unsigned long delay;
+
+ /* first, enable any unassigned irqs */
+ for (i = MALTAINT_END-1; i > 0; i--) {
+ if (!hw0_irq_action[i]) {
+ enable_irq(i);
+ irqs |= (1 << i);
+ }
+ }
+
+ /* wait for spurious interrupts to mask themselves out again */
+ for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
+ /* about 100ms delay */;
+
+ /* now filter out any obviously spurious interrupts */
+ return irqs & ~cached_int_mask;
+}
+
+
+int probe_irq_off (unsigned long irqs)
+{
+ unsigned int i;
+
+ irqs &= cached_int_mask;
+ if (!irqs)
+ return 0;
+ i = ffz(~irqs);
+ if (irqs != (irqs & (1 << i)))
+ i = -i;
+
+ return i;
+}
+
+
+void __init maltaint_init(void)
+{
+ /*
+ * Mask out all interrupt by writing "1" to all bit position in
+ * the IMR register.
+ */
+ outb(cached_int_mask & 0xff, PIIX4_ICTLR1_OCW1);
+ outb((cached_int_mask >> 8) & 0xff, PIIX4_ICTLR2_OCW1);
+
+ request_region(PIIX4_ICTLR1_ICW1, 0x20, "pic1");
+ request_region(PIIX4_ICTLR2_ICW1, 0x20, "pic2");
+
+ /* Now safe to set the exception vector. */
+ set_except_vector(0, mipsIRQ);
+}
diff --git a/arch/mips/mips-boards/malta/malta_rtc.c b/arch/mips/mips-boards/malta/malta_rtc.c
new file mode 100644
index 000000000..9c23bf38a
--- /dev/null
+++ b/arch/mips/mips-boards/malta/malta_rtc.c
@@ -0,0 +1,50 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 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.
+ *
+ * ########################################################################
+ *
+ * RTC routines for Malta style attached PIIX4 device, which contains a
+ * Motorola MC146818A-compatible Real Time Clock.
+ *
+ */
+#include <linux/mc146818rtc.h>
+#include <asm/mips-boards/malta.h>
+
+static unsigned char malta_rtc_read_data(unsigned long addr)
+{
+ outb(addr, MALTA_RTC_ADR_REG);
+ return inb(MALTA_RTC_DAT_REG);
+}
+
+static void malta_rtc_write_data(unsigned char data, unsigned long addr)
+{
+ outb(addr, MALTA_RTC_ADR_REG);
+ outb(data, MALTA_RTC_DAT_REG);
+}
+
+static int malta_rtc_bcd_mode(void)
+{
+ return 0;
+}
+
+struct rtc_ops malta_rtc_ops = {
+ &malta_rtc_read_data,
+ &malta_rtc_write_data,
+ &malta_rtc_bcd_mode
+};
diff --git a/arch/mips/mips-boards/malta/malta_setup.c b/arch/mips/mips-boards/malta/malta_setup.c
new file mode 100644
index 000000000..1621fa0dd
--- /dev/null
+++ b/arch/mips/mips-boards/malta/malta_setup.c
@@ -0,0 +1,155 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 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.
+ *
+ * ########################################################################
+ *
+ * Malta specific setup, including init of the feature struct.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mc146818rtc.h>
+#include <linux/ioport.h>
+
+#include <asm/cpu.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/mips-boards/prom.h>
+#include <asm/mips-boards/malta.h>
+#include <asm/mips-boards/maltaint.h>
+#ifdef CONFIG_BLK_DEV_IDE
+#include <asm/ide.h>
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+#include <asm/floppy.h>
+#endif
+#include <asm/dma.h>
+
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_PROM_CONSOLE)
+extern void console_setup(char *, int *);
+char serial_console[20];
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+extern void set_debug_traps(void);
+extern void rs_kgdb_hook(int);
+extern void breakpoint(void);
+static int remote_debug = 0;
+static int kgdb_on_pci = 0;
+#endif
+
+#ifdef CONFIG_BLK_DEV_IDE
+extern struct ide_ops std_ide_ops;
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+extern struct fd_ops std_fd_ops;
+#endif
+extern struct rtc_ops malta_rtc_ops;
+
+extern void mips_reboot_setup(void);
+
+
+static void __init malta_irq_setup(void)
+{
+ maltaint_init();
+
+#ifdef CONFIG_REMOTE_DEBUG
+ if (remote_debug && !kgdb_on_pci) {
+ set_debug_traps();
+ breakpoint();
+ }
+#endif
+}
+
+
+void __init malta_setup(void)
+{
+#ifdef CONFIG_REMOTE_DEBUG
+ int rs_putDebugChar(char);
+ char rs_getDebugChar(void);
+ extern int (*putDebugChar)(char);
+ extern char (*getDebugChar)(void);
+#endif
+ char *argptr;
+
+ irq_setup = malta_irq_setup;
+ mips_io_port_base = MALTA_PORT_BASE;
+
+ request_region(0x00,0x20,"dma1");
+ request_region(0x40,0x20,"timer");
+ request_region(0x80,0x10,"dma page reg");
+ request_region(0xc0,0x20,"dma2");
+
+ /*
+ * Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge.
+ */
+ enable_dma(4);
+
+#ifdef CONFIG_SERIAL_CONSOLE
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "console=ttyS0")) == NULL)
+ {
+ int i=0;
+ char *s = prom_getenv("modetty0");
+ while(s[i] >= '0' && s[i] <= '9')
+ i++;
+ strcpy(serial_console, "ttyS0,");
+ strncpy(serial_console + 6, s, i);
+ prom_printf("Config serial console: %s\n", serial_console);
+ console_setup(serial_console, NULL);
+ }
+#endif
+
+#ifdef CONFIG_REMOTE_DEBUG
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "kgdb=ttyS")) != NULL) {
+ int line;
+ argptr += strlen("kgdb=ttyS");
+ if (*argptr != '0' && *argptr != '1')
+ printk("KGDB: Uknown serial line /dev/ttyS%c, "
+ "falling back to /dev/ttyS1\n", *argptr);
+ line = *argptr == '0' ? 0 : 1;
+ printk("KGDB: Using serial line /dev/ttyS%d for session\n",
+ line ? 1 : 0);
+
+ rs_kgdb_hook(line);
+ putDebugChar = rs_putDebugChar;
+ getDebugChar = rs_getDebugChar;
+
+ prom_printf("KGDB: Using serial line /dev/ttyS%d for session, "
+ "please connect your debugger\n", line ? 1 : 0);
+
+ remote_debug = 1;
+ /* Breakpoints and stuff are in malta_irq_setup() */
+ }
+#endif
+ argptr = prom_getcmdline();
+ if ((argptr = strstr(argptr, "nofpu")) != NULL)
+ mips_cpu.options &= ~MIPS_CPU_FPU;
+
+ rtc_ops = &malta_rtc_ops;
+#ifdef CONFIG_BLK_DEV_IDE
+ ide_ops = &std_ide_ops;
+#endif
+#ifdef CONFIG_BLK_DEV_FD
+ fd_ops = &std_fd_ops;
+#endif
+ mips_reboot_setup();
+}