summaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorThomas Bogendoerfer <tsbogend@alpha.franken.de>2006-12-28 18:22:32 +0100
committerRalf Baechle <ralf@linux-mips.org>2007-02-18 21:31:37 +0000
commitc066a32a890c50ce59e91f8cea8eb5fd8d5821b9 (patch)
treed129af235d11d44c649f0743bc38535c3a229e41 /arch/mips
parent5759906ca9e5201c3fd40d61c861ec1e441d3a24 (diff)
[MIPS] Support for several more SNI RM models.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kconfig5
-rw-r--r--arch/mips/pci/fixup-sni.c66
-rw-r--r--arch/mips/pci/ops-sni.c77
-rw-r--r--arch/mips/sni/Makefile2
-rw-r--r--arch/mips/sni/a20r.c227
-rw-r--r--arch/mips/sni/ds1216.c81
-rw-r--r--arch/mips/sni/irq.c188
-rw-r--r--arch/mips/sni/pcimt.c390
-rw-r--r--arch/mips/sni/pcit.c351
-rw-r--r--arch/mips/sni/reset.c9
-rw-r--r--arch/mips/sni/rm200.c186
-rw-r--r--arch/mips/sni/setup.c242
-rw-r--r--arch/mips/sni/sniprom.c129
-rw-r--r--arch/mips/sni/time.c148
14 files changed, 1719 insertions, 382 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index a92ce6bd7cf1..46fa5ca9f5ac 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -726,15 +726,16 @@ config SNI_RM
select BOOT_ELF32
select DMA_NONCOHERENT
select GENERIC_ISA_DMA
- select HAVE_STD_PC_SERIAL_PORT
select HW_HAS_EISA
select HW_HAS_PCI
+ select IRQ_CPU
select I8253
select I8259
select ISA
select SWAP_IO_SPACE if CPU_BIG_ENDIAN
select SYS_HAS_CPU_R4X00
select SYS_HAS_CPU_R5000
+ select SYS_HAS_CPU_R10000
select R5000_CPU_SCACHE
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
@@ -1066,7 +1067,7 @@ config BOOT_ELF32
config MIPS_L1_CACHE_SHIFT
int
- default "4" if MACH_DECSTATION
+ default "4" if MACH_DECSTATION || SNI_RM
default "7" if SGI_IP27
default "5"
diff --git a/arch/mips/pci/fixup-sni.c b/arch/mips/pci/fixup-sni.c
index a176f2ca8656..0c9a4732d455 100644
--- a/arch/mips/pci/fixup-sni.c
+++ b/arch/mips/pci/fixup-sni.c
@@ -15,7 +15,7 @@
#include <asm/sni.h>
/*
- * Shortcuts ...
+ * PCIMT Shortcuts ...
*/
#define SCSI PCIMT_IRQ_SCSI
#define ETH PCIMT_IRQ_ETHERNET
@@ -67,6 +67,50 @@ static char irq_tab_rm300d[8][5] __initdata = {
{ 0, INTD, INTA, INTB, INTC }, /* Slot 4 */
};
+static char irq_tab_rm300e[5][5] __initdata = {
+ /* INTA INTB INTC INTD */
+ { 0, 0, 0, 0, 0 }, /* HOST bridge */
+ { SCSI, SCSI, SCSI, SCSI, SCSI }, /* SCSI */
+ { 0, INTC, INTD, INTA, INTB }, /* Bridge/i960 */
+ { 0, INTD, INTA, INTB, INTC }, /* Slot 1 */
+ { 0, INTA, INTB, INTC, INTD }, /* Slot 2 */
+};
+#undef SCSI
+#undef ETH
+#undef INTA
+#undef INTB
+#undef INTC
+#undef INTD
+
+
+/*
+ * PCIT Shortcuts ...
+ */
+#define SCSI0 PCIT_IRQ_SCSI0
+#define SCSI1 PCIT_IRQ_SCSI1
+#define ETH PCIT_IRQ_ETHERNET
+#define INTA PCIT_IRQ_INTA
+#define INTB PCIT_IRQ_INTB
+#define INTC PCIT_IRQ_INTC
+#define INTD PCIT_IRQ_INTD
+
+static char irq_tab_pcit[13][5] __initdata = {
+ /* INTA INTB INTC INTD */
+ { 0, 0, 0, 0, 0 }, /* HOST bridge */
+ { SCSI0, SCSI0, SCSI0, SCSI0, SCSI0 }, /* SCSI */
+ { SCSI1, SCSI1, SCSI1, SCSI1, SCSI1 }, /* SCSI */
+ { ETH, ETH, ETH, ETH, ETH }, /* Ethernet */
+ { 0, INTA, INTB, INTC, INTD }, /* PCI-PCI bridge */
+ { 0, 0, 0, 0, 0 }, /* Unused */
+ { 0, 0, 0, 0, 0 }, /* Unused */
+ { 0, 0, 0, 0, 0 }, /* Unused */
+ { 0, INTA, INTB, INTC, INTD }, /* Slot 1 */
+ { 0, INTB, INTC, INTD, INTA }, /* Slot 2 */
+ { 0, INTC, INTD, INTA, INTB }, /* Slot 3 */
+ { 0, INTD, INTA, INTB, INTC }, /* Slot 4 */
+ { 0, INTA, INTB, INTC, INTD }, /* Slot 5 */
+};
+
static inline int is_rm300_revd(void)
{
unsigned char csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
@@ -76,10 +120,24 @@ static inline int is_rm300_revd(void)
int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
- if (is_rm300_revd())
- return irq_tab_rm300d[slot][pin];
+ switch (sni_brd_type) {
+ case SNI_BRD_PCI_TOWER:
+ case SNI_BRD_PCI_TOWER_CPLUS:
+ return irq_tab_pcit[slot][pin];
+
+ case SNI_BRD_PCI_MTOWER:
+ if (is_rm300_revd())
+ return irq_tab_rm300d[slot][pin];
+ /* fall through */
- return irq_tab_rm200[slot][pin];
+ case SNI_BRD_PCI_DESKTOP:
+ return irq_tab_rm200[slot][pin];
+
+ case SNI_BRD_PCI_MTOWER_CPLUS:
+ return irq_tab_rm300e[slot][pin];
+ }
+
+ return 0;
}
/* Do platform specific device initialization at pci_enable_device() time */
diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c
index 2b0ccd6d9dcd..fa2d2c60f797 100644
--- a/arch/mips/pci/ops-sni.c
+++ b/arch/mips/pci/ops-sni.c
@@ -83,7 +83,82 @@ static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg,
return 0;
}
-struct pci_ops sni_pci_ops = {
+struct pci_ops sni_pcimt_ops = {
.read = pcimt_read,
.write = pcimt_write,
};
+
+static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg)
+{
+ if ((devfn > 255) || (reg > 255) || (busno > 255))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ outl ((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8);
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg,
+ int size, u32 * val)
+{
+ int res;
+
+ /*
+ * on bus 0 we need to check, whether there is a device answering
+ * for the devfn by doing a config write and checking the result. If
+ * we don't do it, we will get a data bus error
+ */
+ if (bus->number == 0) {
+ pcit_set_config_address (0, 0, 0x68);
+ outl (inl (0xcfc) | 0xc0000000, 0xcfc);
+ if ((res = pcit_set_config_address(0, devfn, 0)))
+ return res;
+ outl (0xffffffff, 0xcfc);
+ pcit_set_config_address (0, 0, 0x68);
+ if (inl(0xcfc) & 0x100000)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+ if ((res = pcit_set_config_address(bus->number, devfn, reg)))
+ return res;
+
+ switch (size) {
+ case 1:
+ *val = inb(PCIMT_CONFIG_DATA + (reg & 3));
+ break;
+ case 2:
+ *val = inw(PCIMT_CONFIG_DATA + (reg & 2));
+ break;
+ case 4:
+ *val = inl(PCIMT_CONFIG_DATA);
+ break;
+ }
+ return 0;
+}
+
+static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg,
+ int size, u32 val)
+{
+ int res;
+
+ if ((res = pcit_set_config_address(bus->number, devfn, reg)))
+ return res;
+
+ switch (size) {
+ case 1:
+ outb (val, PCIMT_CONFIG_DATA + (reg & 3));
+ break;
+ case 2:
+ outw (val, PCIMT_CONFIG_DATA + (reg & 2));
+ break;
+ case 4:
+ outl (val, PCIMT_CONFIG_DATA);
+ break;
+ }
+
+ return 0;
+}
+
+
+struct pci_ops sni_pcit_ops = {
+ .read = pcit_read,
+ .write = pcit_write,
+};
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
index a5eb0adb87c7..e30809a92151 100644
--- a/arch/mips/sni/Makefile
+++ b/arch/mips/sni/Makefile
@@ -2,7 +2,7 @@
# Makefile for the SNI specific part of the kernel
#
-obj-y += irq.o pcimt_scache.o reset.o setup.o
+obj-y += irq.o reset.o setup.o ds1216.o a20r.o rm200.o pcimt.o pcit.o time.o
obj-$(CONFIG_CPU_BIG_ENDIAN) += sniprom.o
EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c
new file mode 100644
index 000000000000..31ab80f1befa
--- /dev/null
+++ b/arch/mips/sni/a20r.c
@@ -0,0 +1,227 @@
+/*
+ * A20R specific code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+
+#include <asm/sni.h>
+#include <asm/time.h>
+#include <asm/ds1216.h>
+
+#define PORT(_base,_irq) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF, \
+ }
+
+static struct plat_serial8250_port a20r_data[] = {
+ PORT(0x3f8, 4),
+ PORT(0x2f8, 3),
+ { },
+};
+
+static struct platform_device a20r_serial8250_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = a20r_data,
+ },
+};
+
+static struct resource snirm_82596_rsrc[] = {
+ {
+ .start = 0xb8000000,
+ .end = 0xb8000004,
+ .flags = IORESOURCE_MEM
+ },
+ {
+ .start = 0xb8010000,
+ .end = 0xb8010004,
+ .flags = IORESOURCE_MEM
+ },
+ {
+ .start = 0xbff00000,
+ .end = 0xbff00020,
+ .flags = IORESOURCE_MEM
+ },
+ {
+ .start = 22,
+ .end = 22,
+ .flags = IORESOURCE_IRQ
+ },
+ {
+ .flags = 0x01 /* 16bit mpu port access */
+ }
+};
+
+static struct platform_device snirm_82596_pdev = {
+ .name = "snirm_82596",
+ .num_resources = ARRAY_SIZE(snirm_82596_rsrc),
+ .resource = snirm_82596_rsrc
+};
+
+static struct resource snirm_53c710_rsrc[] = {
+ {
+ .start = 0xb9000000,
+ .end = 0xb90fffff,
+ .flags = IORESOURCE_MEM
+ },
+ {
+ .start = 19,
+ .end = 19,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct platform_device snirm_53c710_pdev = {
+ .name = "snirm_53c710",
+ .num_resources = ARRAY_SIZE(snirm_53c710_rsrc),
+ .resource = snirm_53c710_rsrc
+};
+
+static struct resource sc26xx_rsrc[] = {
+ {
+ .start = 0xbc070000,
+ .end = 0xbc0700ff,
+ .flags = IORESOURCE_MEM
+ },
+ {
+ .start = 20,
+ .end = 20,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct platform_device sc26xx_pdev = {
+ .name = "SC26xx",
+ .num_resources = ARRAY_SIZE(sc26xx_rsrc),
+ .resource = sc26xx_rsrc
+};
+
+static u32 a20r_ack_hwint(void)
+{
+ u32 status = read_c0_status();
+
+ write_c0_status (status | 0x00010000);
+ asm volatile(
+ " .set push \n"
+ " .set noat \n"
+ " .set noreorder \n"
+ " lw $1, 0(%0) \n"
+ " sb $0, 0(%1) \n"
+ " sync \n"
+ " lb %1, 0(%1) \n"
+ " b 1f \n"
+ " ori %1, $1, 2 \n"
+ " .align 8 \n"
+ "1: \n"
+ " nop \n"
+ " sw %1, 0(%0) \n"
+ " sync \n"
+ " li %1, 0x20 \n"
+ "2: \n"
+ " nop \n"
+ " bnez %1,2b \n"
+ " addiu %1, -1 \n"
+ " sw $1, 0(%0) \n"
+ " sync \n"
+ ".set pop \n"
+ :
+ : "Jr" (PCIMT_UCONF), "Jr" (0xbc000000));
+ write_c0_status(status);
+
+ return status;
+}
+
+static inline void unmask_a20r_irq(unsigned int irq)
+{
+ set_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
+ irq_enable_hazard();
+}
+
+static inline void mask_a20r_irq(unsigned int irq)
+{
+ clear_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE));
+ irq_disable_hazard();
+}
+
+static void end_a20r_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+ a20r_ack_hwint();
+ unmask_a20r_irq(irq);
+ }
+}
+
+static struct irq_chip a20r_irq_type = {
+ .typename = "A20R",
+ .ack = mask_a20r_irq,
+ .mask = mask_a20r_irq,
+ .mask_ack = mask_a20r_irq,
+ .unmask = unmask_a20r_irq,
+ .end = end_a20r_irq,
+};
+
+/*
+ * hwint 0 receive all interrupts
+ */
+static void a20r_hwint(void)
+{
+ u32 cause, status;
+ int irq;
+
+ clear_c0_status (IE_IRQ0);
+ status = a20r_ack_hwint();
+ cause = read_c0_cause();
+
+ irq = ffs(((cause & status) >> 8) & 0xf8);
+ if (likely(irq > 0))
+ do_IRQ(SNI_A20R_IRQ_BASE + irq - 1);
+ set_c0_status(IE_IRQ0);
+}
+
+void __init sni_a20r_irq_init(void)
+{
+ int i;
+
+ for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++)
+ set_irq_chip(i, &a20r_irq_type);
+ sni_hwint = a20r_hwint;
+ change_c0_status(ST0_IM, IE_IRQ0);
+ setup_irq (SNI_A20R_IRQ_BASE + 3, &sni_isa_irq);
+}
+
+void sni_a20r_init(void)
+{
+ ds1216_base = (volatile unsigned char *) SNI_DS1216_A20R_BASE;
+ rtc_mips_get_time = ds1216_get_cmos_time;
+}
+
+static int __init snirm_a20r_setup_devinit(void)
+{
+ switch (sni_brd_type) {
+ case SNI_BRD_TOWER_OASIC:
+ case SNI_BRD_MINITOWER:
+ platform_device_register(&snirm_82596_pdev);
+ platform_device_register(&snirm_53c710_pdev);
+ platform_device_register(&sc26xx_pdev);
+ platform_device_register(&a20r_serial8250_device);
+ break;
+ }
+
+ return 0;
+}
+
+device_initcall(snirm_a20r_setup_devinit);
diff --git a/arch/mips/sni/ds1216.c b/arch/mips/sni/ds1216.c
new file mode 100644
index 000000000000..1d92732c14f1
--- /dev/null
+++ b/arch/mips/sni/ds1216.c
@@ -0,0 +1,81 @@
+
+#include <linux/bcd.h>
+#include <linux/time.h>
+
+#include <asm/ds1216.h>
+
+volatile unsigned char *ds1216_base;
+
+/*
+ * Read the 64 bit we'd like to have - It a series
+ * of 64 bits showing up in the LSB of the base register.
+ *
+ */
+static unsigned char *ds1216_read(void)
+{
+ static unsigned char rdbuf[8];
+ unsigned char c;
+ int i, j;
+
+ for (i = 0; i < 8; i++) {
+ c = 0x0;
+ for (j = 0; j < 8; j++) {
+ c |= (*ds1216_base & 0x1) << j;
+ }
+ rdbuf[i] = c;
+ }
+
+ return rdbuf;
+}
+
+static void ds1216_switch_ds_to_clock(void)
+{
+ unsigned char magic[] = {
+ 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c
+ };
+ int i,j,c;
+
+ /* Reset magic pointer */
+ c = *ds1216_base;
+
+ /* Write 64 bit magic to DS1216 */
+ for (i = 0; i < 8; i++) {
+ c = magic[i];
+ for (j = 0; j < 8; j++) {
+ *ds1216_base = c;
+ c = c >> 1;
+ }
+ }
+}
+
+unsigned long ds1216_get_cmos_time(void)
+{
+ unsigned char *rdbuf;
+ unsigned int year, month, date, hour, min, sec;
+
+ ds1216_switch_ds_to_clock();
+ rdbuf = ds1216_read();
+
+ sec = BCD2BIN(DS1216_SEC(rdbuf));
+ min = BCD2BIN(DS1216_MIN(rdbuf));
+ hour = BCD2BIN(DS1216_HOUR(rdbuf));
+ date = BCD2BIN(DS1216_DATE(rdbuf));
+ month = BCD2BIN(DS1216_MONTH(rdbuf));
+ year = BCD2BIN(DS1216_YEAR(rdbuf));
+
+ if (DS1216_1224(rdbuf) && DS1216_AMPM(rdbuf))
+ hour+=12;
+
+ if (year < 70)
+ year += 2000;
+ else
+ year += 1900;
+
+ return mktime(year, month, date, hour, min, sec);
+}
+
+int ds1216_set_rtc_mmss(unsigned long nowtime)
+{
+ printk("ds1216_set_rtc_mmss called but not implemented\n");
+ return -1;
+}
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index 039e8e540508..ad5fc471a004 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -5,6 +5,7 @@
*
* Copyright (C) 1992 Linus Torvalds
* Copyright (C) 1994 - 2000 Ralf Baechle
+ * Copyright (C) 2006 Thomas Bogendoerfer
*/
#include <linux/delay.h>
#include <linux/init.h>
@@ -15,152 +16,34 @@
#include <asm/i8259.h>
#include <asm/io.h>
#include <asm/sni.h>
+#include <asm/irq.h>
+#include <asm/irq_cpu.h>
-static void enable_pciasic_irq(unsigned int irq)
-{
- unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
-
- *(volatile u8 *) PCIMT_IRQSEL |= mask;
-}
-
-void disable_pciasic_irq(unsigned int irq)
-{
- unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2));
-
- *(volatile u8 *) PCIMT_IRQSEL &= mask;
-}
+void (*sni_hwint)(void);
-static void end_pciasic_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_pciasic_irq(irq);
-}
-
-static struct irq_chip pciasic_irq_type = {
- .name = "ASIC-PCI",
- .ack = disable_pciasic_irq,
- .mask = disable_pciasic_irq,
- .mask_ack = disable_pciasic_irq,
- .unmask = enable_pciasic_irq,
- .end = end_pciasic_irq,
-};
-
-/*
- * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
- * button interrupts. Later ...
- */
-static void pciasic_hwint0(void)
-{
- panic("Received int0 but no handler yet ...");
-}
-
-/* This interrupt was used for the com1 console on the first prototypes. */
-static void pciasic_hwint2(void)
-{
- /* I think this shouldn't happen on production machines. */
- panic("hwint2 and no handler yet");
-}
-
-/* hwint5 is the r4k count / compare interrupt */
-static void pciasic_hwint5(void)
-{
- panic("hwint5 and no handler yet");
-}
-
-static unsigned int ls1bit8(unsigned int x)
-{
- int b = 7, s;
-
- s = 4; if ((x & 0x0f) == 0) s = 0; b -= s; x <<= s;
- s = 2; if ((x & 0x30) == 0) s = 0; b -= s; x <<= s;
- s = 1; if ((x & 0x40) == 0) s = 0; b -= s;
-
- return b;
-}
-
-/*
- * hwint 1 deals with EISA and SCSI interrupts,
- *
- * The EISA_INT bit in CSITPEND is high active, all others are low active.
- */
-static void pciasic_hwint1(void)
+asmlinkage void plat_irq_dispatch(void)
{
- u8 pend = *(volatile char *)PCIMT_CSITPEND;
- unsigned long flags;
-
- if (pend & IT_EISA) {
- int irq;
- /*
- * Note: ASIC PCI's builtin interrupt achknowledge feature is
- * broken. Using it may result in loss of some or all i8259
- * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
- */
- irq = i8259_irq();
- if (unlikely(irq < 0))
- return;
-
- do_IRQ(irq);
- }
-
- if (!(pend & IT_SCSI)) {
- flags = read_c0_status();
- clear_c0_status(ST0_IM);
- do_IRQ(PCIMT_IRQ_SCSI);
- write_c0_status(flags);
- }
+ sni_hwint();
}
-/*
- * hwint 3 should deal with the PCI A - D interrupts,
- */
-static void pciasic_hwint3(void)
+/* ISA irq handler */
+static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
{
- u8 pend = *(volatile char *)PCIMT_CSITPEND;
int irq;
- pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
- clear_c0_status(IE_IRQ3);
- irq = PCIMT_IRQ_INT2 + ls1bit8(pend);
- do_IRQ(irq);
- set_c0_status(IE_IRQ3);
-}
+ irq = i8259_irq();
+ if (unlikely(irq < 0))
+ return IRQ_NONE;
-/*
- * hwint 4 is used for only the onboard PCnet 32.
- */
-static void pciasic_hwint4(void)
-{
- clear_c0_status(IE_IRQ4);
- do_IRQ(PCIMT_IRQ_ETHERNET);
- set_c0_status(IE_IRQ4);
-}
-
-asmlinkage void plat_irq_dispatch(void)
-{
- unsigned int pending = read_c0_status() & read_c0_cause();
- static unsigned char led_cache;
-
- *(volatile unsigned char *) PCIMT_CSLED = ++led_cache;
-
- if (pending & 0x0800)
- pciasic_hwint1();
- else if (pending & 0x4000)
- pciasic_hwint4();
- else if (pending & 0x2000)
- pciasic_hwint3();
- else if (pending & 0x1000)
- pciasic_hwint2();
- else if (pending & 0x8000)
- pciasic_hwint5();
- else if (pending & 0x0400)
- pciasic_hwint0();
+ do_IRQ(irq);
+ return IRQ_HANDLED;
}
-void __init init_pciasic(void)
-{
- * (volatile u8 *) PCIMT_IRQSEL =
- IT_EISA | IT_INTA | IT_INTB | IT_INTC | IT_INTD;
-}
+struct irqaction sni_isa_irq = {
+ .handler = sni_isa_irq_handler,
+ .name = "ISA",
+ .flags = SA_SHIRQ
+};
/*
* On systems with i8259-style interrupt controllers we assume for
@@ -169,14 +52,31 @@ void __init init_pciasic(void)
*/
void __init arch_init_irq(void)
{
- int i;
-
init_i8259_irqs(); /* Integrated i8259 */
- init_pciasic();
-
- /* Actually we've got more interrupts to handle ... */
- for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_ETHERNET; i++)
- set_irq_chip(i, &pciasic_irq_type);
-
- change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4);
+ switch (sni_brd_type) {
+ case SNI_BRD_10:
+ case SNI_BRD_10NEW:
+ case SNI_BRD_TOWER_OASIC:
+ case SNI_BRD_MINITOWER:
+ sni_a20r_irq_init();
+ break;
+
+ case SNI_BRD_PCI_TOWER:
+ sni_pcit_irq_init();
+ break;
+
+ case SNI_BRD_PCI_TOWER_CPLUS:
+ sni_pcit_cplus_irq_init();
+ break;
+
+ case SNI_BRD_RM200:
+ sni_rm200_irq_init();
+ break;
+
+ case SNI_BRD_PCI_MTOWER:
+ case SNI_BRD_PCI_DESKTOP:
+ case SNI_BRD_PCI_MTOWER_CPLUS:
+ sni_pcimt_irq_init();
+ break;
+ }
}
diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c
new file mode 100644
index 000000000000..6c0dad7cbf4e
--- /dev/null
+++ b/arch/mips/sni/pcimt.c
@@ -0,0 +1,390 @@
+/*
+ * PCIMT specific code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/serial_8250.h>
+
+#include <asm/mc146818-time.h>
+#include <asm/sni.h>
+#include <asm/time.h>
+#include <asm/i8259.h>
+#include <asm/irq_cpu.h>
+
+#define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF)
+#define invspace (*(volatile unsigned int *)PCIMT_INVSPACE)
+
+static void __init sni_pcimt_sc_init(void)
+{
+ unsigned int scsiz, sc_size;
+
+ scsiz = cacheconf & 7;
+ if (scsiz == 0) {
+ printk("Second level cache is deactived.\n");
+ return;
+ }
+ if (scsiz >= 6) {
+ printk("Invalid second level cache size configured, "
+ "deactivating second level cache.\n");
+ cacheconf = 0;
+ return;
+ }
+
+ sc_size = 128 << scsiz;
+ printk("%dkb second level cache detected, deactivating.\n", sc_size);
+ cacheconf = 0;
+}
+
+
+/*
+ * A bit more gossip about the iron we're running on ...
+ */
+static inline void sni_pcimt_detect(void)
+{
+ char boardtype[80];
+ unsigned char csmsr;
+ char *p = boardtype;
+ unsigned int asic;
+
+ csmsr = *(volatile unsigned char *)PCIMT_CSMSR;
+
+ p += sprintf(p, "%s PCI", (csmsr & 0x80) ? "RM200" : "RM300");
+ if ((csmsr & 0x80) == 0)
+ p += sprintf(p, ", board revision %s",
+ (csmsr & 0x20) ? "D" : "C");
+ asic = csmsr & 0x80;
+ asic = (csmsr & 0x08) ? asic : !asic;
+ p += sprintf(p, ", ASIC PCI Rev %s", asic ? "1.0" : "1.1");
+ printk("%s.\n", boardtype);
+}
+
+#define PORT(_base,_irq) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF, \
+ }
+
+static struct plat_serial8250_port pcimt_data[] = {
+ PORT(0x3f8, 4),
+ PORT(0x2f8, 3),
+ { },
+};
+
+static struct platform_device pcimt_serial8250_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = pcimt_data,
+ },
+};
+
+static struct resource sni_io_resource = {
+ .start = 0x00001000UL,
+ .end = 0x03bfffffUL,
+ .name = "PCIMT IO MEM",
+ .flags = IORESOURCE_IO,
+};
+
+static struct resource pcimt_io_resources[] = {
+ {
+ .start = 0x00,
+ .end = 0x1f,
+ .name = "dma1",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x40,
+ .end = 0x5f,
+ .name = "timer",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x60,
+ .end = 0x6f,
+ .name = "keyboard",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x80,
+ .end = 0x8f,
+ .name = "dma page reg",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0xc0,
+ .end = 0xdf,
+ .name = "dma2",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0xcfc,
+ .end = 0xcff,
+ .name = "PCI config data",
+ .flags = IORESOURCE_BUSY
+ }
+};
+
+static struct resource sni_mem_resource = {
+ .start = 0x10000000UL,
+ .end = 0xffffffffUL,
+ .name = "PCIMT PCI MEM",
+ .flags = IORESOURCE_MEM
+};
+
+/*
+ * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used
+ * for other purposes. Be paranoid and allocate all of the before the PCI
+ * code gets a chance to to map anything else there ...
+ *
+ * This leaves the following areas available:
+ *
+ * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory
+ * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory
+ * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory
+ * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory
+ * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory
+ */
+static struct resource pcimt_mem_resources[] = {
+ {
+ .start = 0x100a0000,
+ .end = 0x100bffff,
+ .name = "Video RAM area",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x100c0000,
+ .end = 0x100fffff,
+ .name = "ISA Reserved",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x14000000,
+ .end = 0x17bfffff,
+ .name = "PCI IO",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x17c00000,
+ .end = 0x17ffffff,
+ .name = "Cache Replacement Area",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x1a000000,
+ .end = 0x1a000003,
+ .name = "PCI INT Acknowledge",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x1fc00000,
+ .end = 0x1fc7ffff,
+ .name = "Boot PROM",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x1fc80000,
+ .end = 0x1fcfffff,
+ .name = "Diag PROM",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x1fd00000,
+ .end = 0x1fdfffff,
+ .name = "X-Bus",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x1fe00000,
+ .end = 0x1fefffff,
+ .name = "BIOS map",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x1ff00000,
+ .end = 0x1ff7ffff,
+ .name = "NVRAM / EEPROM",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x1fff0000,
+ .end = 0x1fffefff,
+ .name = "ASIC PCI",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x1ffff000,
+ .end = 0x1fffffff,
+ .name = "MP Agent",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x20000000,
+ .end = 0x9fffffff,
+ .name = "Main Memory",
+ .flags = IORESOURCE_BUSY
+ }
+};
+
+static void __init sni_pcimt_resource_init(void)
+{
+ int i;
+
+ /* request I/O space for devices used on all i[345]86 PCs */
+ for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++)
+ request_resource(&ioport_resource, pcimt_io_resources + i);
+
+ /* request mem space for pcimt-specific devices */
+ for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++)
+ request_resource(&sni_mem_resource, pcimt_mem_resources + i);
+
+ ioport_resource.end = sni_io_resource.end;
+}
+
+extern struct pci_ops sni_pcimt_ops;
+
+static struct pci_controller sni_controller = {
+ .pci_ops = &sni_pcimt_ops,
+ .mem_resource = &sni_mem_resource,
+ .mem_offset = 0x10000000UL,
+ .io_resource = &sni_io_resource,
+ .io_offset = 0x00000000UL
+};
+
+static void enable_pcimt_irq(unsigned int irq)
+{
+ unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
+
+ *(volatile u8 *) PCIMT_IRQSEL |= mask;
+}
+
+void disable_pcimt_irq(unsigned int irq)
+{
+ unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2));
+
+ *(volatile u8 *) PCIMT_IRQSEL &= mask;
+}
+
+static void end_pcimt_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ enable_pcimt_irq(irq);
+}
+
+static struct irq_chip pcimt_irq_type = {
+ .typename = "PCIMT",
+ .ack = disable_pcimt_irq,
+ .mask = disable_pcimt_irq,
+ .mask_ack = disable_pcimt_irq,
+ .unmask = enable_pcimt_irq,
+ .end = end_pcimt_irq,
+};
+
+/*
+ * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
+ * button interrupts. Later ...
+ */
+static void pcimt_hwint0(void)
+{
+ panic("Received int0 but no handler yet ...");
+}
+
+/*
+ * hwint 1 deals with EISA and SCSI interrupts,
+ *
+ * The EISA_INT bit in CSITPEND is high active, all others are low active.
+ */
+static void pcimt_hwint1(void)
+{
+ u8 pend = *(volatile char *)PCIMT_CSITPEND;
+ unsigned long flags;
+
+ if (pend & IT_EISA) {
+ int irq;
+ /*
+ * Note: ASIC PCI's builtin interrupt achknowledge feature is
+ * broken. Using it may result in loss of some or all i8259
+ * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
+ */
+ irq = i8259_irq();
+ if (unlikely(irq < 0))
+ return;
+
+ do_IRQ(irq);
+ }
+
+ if (!(pend & IT_SCSI)) {
+ flags = read_c0_status();
+ clear_c0_status(ST0_IM);
+ do_IRQ(PCIMT_IRQ_SCSI);
+ write_c0_status(flags);
+ }
+}
+
+/*
+ * hwint 3 should deal with the PCI A - D interrupts,
+ */
+static void pcimt_hwint3(void)
+{
+ u8 pend = *(volatile char *)PCIMT_CSITPEND;
+ int irq;
+
+ pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
+ pend ^= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
+ clear_c0_status(IE_IRQ3);
+ irq = PCIMT_IRQ_INT2 + ffs(pend) - 1;
+ do_IRQ(irq);
+ set_c0_status(IE_IRQ3);
+}
+
+static void sni_pcimt_hwint(void)
+{
+ u32 pending = (read_c0_cause() & read_c0_status());
+
+ if (pending & C_IRQ5)
+ do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7);
+ else if (pending & C_IRQ4)
+ do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 6);
+ else if (pending & C_IRQ3)
+ pcimt_hwint3();
+ else if (pending & C_IRQ1)
+ pcimt_hwint1();
+ else if (pending & C_IRQ0) {
+ pcimt_hwint0();
+ }
+}
+
+void __init sni_pcimt_irq_init(void)
+{
+ int i;
+
+ *(volatile u8 *) PCIMT_IRQSEL = IT_ETH | IT_EISA;
+ mips_cpu_irq_init();
+ /* Actually we've got more interrupts to handle ... */
+ for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_SCSI; i++)
+ set_irq_chip(i, &pcimt_irq_type);
+ sni_hwint = sni_pcimt_hwint;
+ change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ3);
+}
+
+void sni_pcimt_init(void)
+{
+ sni_pcimt_resource_init();
+ sni_pcimt_detect();
+ sni_pcimt_sc_init();
+ rtc_mips_get_time = mc146818_get_cmos_time;
+ rtc_mips_set_time = mc146818_set_rtc_mmss;
+ board_time_init = sni_cpu_time_init;
+#ifdef CONFIG_PCI
+ register_pci_controller(&sni_controller);
+#endif
+}
+
+static int __init snirm_pcimt_setup_devinit(void)
+{
+ switch (sni_brd_type) {
+ case SNI_BRD_PCI_MTOWER:
+ case SNI_BRD_PCI_DESKTOP:
+ case SNI_BRD_PCI_MTO