[MIPS] Support for several more SNI RM models.
authorThomas Bogendoerfer <tsbogend@alpha.franken.de>
Thu, 28 Dec 2006 17:22:32 +0000 (18:22 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Sun, 18 Feb 2007 21:31:37 +0000 (21:31 +0000)
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
17 files changed:
arch/mips/Kconfig
arch/mips/pci/fixup-sni.c
arch/mips/pci/ops-sni.c
arch/mips/sni/Makefile
arch/mips/sni/a20r.c [new file with mode: 0644]
arch/mips/sni/ds1216.c [new file with mode: 0644]
arch/mips/sni/irq.c
arch/mips/sni/pcimt.c [new file with mode: 0644]
arch/mips/sni/pcit.c [new file with mode: 0644]
arch/mips/sni/reset.c
arch/mips/sni/rm200.c [new file with mode: 0644]
arch/mips/sni/setup.c
arch/mips/sni/sniprom.c
arch/mips/sni/time.c [new file with mode: 0644]
include/asm-mips/ds1216.h [new file with mode: 0644]
include/asm-mips/mach-rm/cpu-feature-overrides.h
include/asm-mips/sni.h

index a92ce6bd7cf1c89fa867e08126e8d573b61cbb06..46fa5ca9f5ace4020ce0cb3e8c90f31f44fb18ad 100644 (file)
@@ -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"
 
index a176f2ca8656b1536db9f740c8de822d3340f265..0c9a4732d45506d3495192efbee8029b08575d0b 100644 (file)
@@ -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 */
index 2b0ccd6d9dcd98bc7c6894389dc40a24433ea860..fa2d2c60f7973f69b9fb7ffc9b99e9b6a902b39c 100644 (file)
@@ -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,
+};
index a5eb0adb87c7aa190c1930380f07fe0b9a7b76e6..e30809a921512c30da9eac811ad898d894804e8f 100644 (file)
@@ -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 (file)
index 0000000..31ab80f
--- /dev/null
@@ -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 (file)
index 0000000..1d92732
--- /dev/null
@@ -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;
+}
index 039e8e5405080b42613856346bd845ab25075657..ad5fc471a0046b28f535f71a3b6c30cea87bf3a7 100644 (file)
@@ -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>
 #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 (file)
index 0000000..6c0dad7
--- /dev/null
@@ -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_MTOWER_CPLUS:
+               platform_device_register(&pcimt_serial8250_device);
+               break;
+       }
+
+       return 0;
+}
+
+device_initcall(snirm_pcimt_setup_devinit);
diff --git a/arch/mips/sni/pcit.c b/arch/mips/sni/pcit.c
new file mode 100644 (file)
index 0000000..3921096
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * PCI Tower 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/pci.h>
+#include <linux/serial_8250.h>
+
+#include <asm/mc146818-time.h>
+#include <asm/sni.h>
+#include <asm/time.h>
+#include <asm/irq_cpu.h>
+
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port pcit_data[] = {
+       PORT(0x3f8, 0),
+       PORT(0x2f8, 3),
+       { },
+};
+
+static struct platform_device pcit_serial8250_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = pcit_data,
+       },
+};
+
+static struct plat_serial8250_port pcit_cplus_data[] = {
+       PORT(0x3f8, 4),
+       PORT(0x2f8, 3),
+       PORT(0x3e8, 4),
+       PORT(0x2e8, 3),
+       { },
+};
+
+static struct platform_device pcit_cplus_serial8250_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = pcit_cplus_data,
+       },
+};
+
+static struct resource sni_io_resource = {
+       .start  = 0x00001000UL,
+       .end    = 0x03bfffffUL,
+       .name   = "PCIT IO MEM",
+       .flags  = IORESOURCE_IO,
+};
+
+static struct resource pcit_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   = "PCIT 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 pcit_mem_resources[] = {
+       {
+               .start  = 0x14000000,
+               .end    = 0x17bfffff,
+               .name   = "PCI IO",
+               .flags  = IORESOURCE_BUSY
+       }, {
+               .start  = 0x17c00000,
+               .end    = 0x17ffffff,
+               .name   = "Cache Replacement Area",
+               .flags  = IORESOURCE_BUSY
+       }, {
+               .start  = 0x180a0000,
+               .end    = 0x180bffff,
+               .name   = "Video RAM area",
+               .flags  = IORESOURCE_BUSY
+       }, {
+               .start  = 0x180c0000,
+               .end    = 0x180fffff,
+               .name   = "ISA Reserved",
+               .flags  = IORESOURCE_BUSY
+       }, {
+               .start  = 0x19000000,
+               .end    = 0x1fbfffff,
+               .name   = "PCI MEM",
+               .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   = "MAUI ASIC",
+               .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_pcit_resource_init(void)
+{
+       int i;
+
+       /* request I/O space for devices used on all i[345]86 PCs */
+       for (i = 0; i < ARRAY_SIZE(pcit_io_resources); i++)
+               request_resource(&ioport_resource, pcit_io_resources + i);
+
+       /* request mem space for pcimt-specific devices */
+       for (i = 0; i < ARRAY_SIZE(pcit_mem_resources); i++)
+               request_resource(&sni_mem_resource, pcit_mem_resources + i);
+
+       ioport_resource.end = sni_io_resource.end;
+}
+
+
+extern struct pci_ops sni_pcit_ops;
+
+static struct pci_controller sni_pcit_controller = {
+       .pci_ops        = &sni_pcit_ops,
+       .mem_resource   = &sni_mem_resource,
+       .mem_offset     = 0x10000000UL,
+       .io_resource    = &sni_io_resource,
+       .io_offset      = 0x00000000UL
+};
+
+static void enable_pcit_irq(unsigned int irq)
+{
+       u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
+
+       *(volatile u32 *)SNI_PCIT_INT_REG |= mask;
+}
+
+void disable_pcit_irq(unsigned int irq)
+{
+       u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24);
+
+       *(volatile u32 *)SNI_PCIT_INT_REG &= ~mask;
+}
+
+void end_pcit_irq(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+               enable_pcit_irq(irq);
+}
+
+static struct irq_chip pcit_irq_type = {
+       .typename = "PCIT",
+       .ack = disable_pcit_irq,
+       .mask = disable_pcit_irq,
+       .mask_ack = disable_pcit_irq,
+       .unmask = enable_pcit_irq,
+       .end = end_pcit_irq,
+};
+
+static void pcit_hwint1(void)
+{
+       u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
+       int irq;
+
+       clear_c0_status(IE_IRQ1);
+       irq = ffs((pending >> 16) & 0x7f);
+
+       if (likely(irq > 0))
+               do_IRQ (irq + SNI_PCIT_INT_START - 1);
+       set_c0_status (IE_IRQ1);
+}
+
+static void pcit_hwint0(void)
+{
+       u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG;
+       int irq;
+
+       clear_c0_status(IE_IRQ0);
+       irq = ffs((pending >> 16) & 0x7f);
+
+       if (likely(irq > 0))
+               do_IRQ (irq + SNI_PCIT_INT_START - 1);
+       set_c0_status (IE_IRQ0);
+}
+
+static void sni_pcit_hwint(void)
+{
+       u32 pending = (read_c0_cause() & read_c0_status());
+
+       if (pending & C_IRQ1)
+               pcit_hwint1();
+       else if (pending & C_IRQ2)
+               do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 4);
+       else if (pending & C_IRQ3)
+               do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 5);
+       else if (pending & C_IRQ5)
+               do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7);
+}
+
+static void sni_pcit_hwint_cplus(void)
+{
+       u32 pending = (read_c0_cause() & read_c0_status());
+
+       if (pending & C_IRQ0)
+               pcit_hwint0();
+       else if (pending & C_IRQ2)
+               do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 4);
+       else if (pending & C_IRQ3)
+               do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 5);
+       else if (pending & C_IRQ5)
+               do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7);
+}
+
+void __init sni_pcit_irq_init(void)
+{
+       int i;
+
+       mips_cpu_irq_init();
+       for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
+               set_irq_chip(i, &pcit_irq_type);
+       *(volatile u32 *)SNI_PCIT_INT_REG = 0;
+       sni_hwint = sni_pcit_hwint;
+       change_c0_status(ST0_IM, IE_IRQ1);
+       setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq);
+}
+
+void __init sni_pcit_cplus_irq_init(void)
+{
+       int i;
+
+       mips_cpu_irq_init();
+       for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++)
+               set_irq_chip(i, &pcit_irq_type);
+       *(volatile u32 *)SNI_PCIT_INT_REG = 0;
+       sni_hwint = sni_pcit_hwint_cplus;
+       change_c0_status(ST0_IM, IE_IRQ0);
+       setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq);
+}
+
+void sni_pcit_init(void)
+{
+       sni_pcit_resource_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_pcit_controller);
+#endif
+}
+
+static int __init snirm_pcit_setup_devinit(void)
+{
+       switch (sni_brd_type) {
+       case SNI_BRD_PCI_TOWER:
+               platform_device_register(&pcit_serial8250_device);
+               break;
+
+       case SNI_BRD_PCI_TOWER_CPLUS:
+               platform_device_register(&pcit_cplus_serial8250_device);
+               break;
+       }
+       return 0;
+}
+
+device_initcall(snirm_pcit_setup_devinit);
index be85bec002e1a1bee1acfeff3349e7a4b62ea0a2..2eada8aea68263d5ac6b471802f89f0a3df0d428 100644 (file)
  * controller to pulse the reset-line low. We try that for a while,
  * and if it doesn't work, we do some other stupid things.
  */
-static inline void
-kb_wait(void)
+static inline void kb_wait(void)
 {
        int i;
 
-       for (i=0; i<0x10000; i++)
+       for (i = 0; i < 0x10000; i++)
                if ((inb_p(0x64) & 0x02) == 0)
                        break;
 }
@@ -32,9 +31,9 @@ void sni_machine_restart(char *command)
           We can do that easier ...  */
        local_irq_disable();
        for (;;) {
-               for (i=0; i<100; i++) {
+               for (i = 0; i < 100; i++) {
                        kb_wait();
-                       for(j = 0; j < 100000 ; j++)
+                       for (j = 0; j < 100000 ; j++)
                                /* nothing */;
                        outb_p(0xfe,0x64);       /* pulse reset low */
                }
diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c
new file mode 100644 (file)
index 0000000..517dc69
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * RM200 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>
+#include <asm/irq_cpu.h>
+
+#define PORT(_base,_irq)                               \
+       {                                               \
+               .iobase         = _base,                \
+               .irq            = _irq,                 \
+               .uartclk        = 1843200,              \
+               .iotype         = UPIO_PORT,            \
+               .flags          = UPF_BOOT_AUTOCONF,    \
+       }
+
+static struct plat_serial8250_port rm200_data[] = {
+       PORT(0x3f8, 4),
+       PORT(0x2f8, 3),
+       { },
+};
+
+static struct platform_device rm200_serial8250_device = {
+       .name                   = "serial8250",
+       .id                     = PLAT8250_DEV_PLATFORM,
+       .dev                    = {
+               .platform_data  = rm200_data,
+       },
+};
+
+static struct resource snirm_82596_rm200_rsrc[] = {
+       {
+               .start = 0xb8000000,
+               .end   = 0xb80fffff,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .start = 0xbb000000,
+               .end   = 0xbb000004,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .start = 0xbff00000,
+               .end   = 0xbff00020,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .start = 27,
+               .end   = 27,
+               .flags = IORESOURCE_IRQ
+       },
+       {
+               .flags = 0x00
+       }
+};
+
+static struct platform_device snirm_82596_rm200_pdev = {
+       .name           = "snirm_82596",
+       .num_resources  = ARRAY_SIZE(snirm_82596_rm200_rsrc),
+       .resource       = snirm_82596_rm200_rsrc
+};
+
+static struct resource snirm_53c710_rm200_rsrc[] = {
+       {
+               .start = 0xb9000000,
+               .end   = 0xb90fffff,
+               .flags = IORESOURCE_MEM
+       },
+       {
+               .start = 26,
+               .end   = 26,
+               .flags = IORESOURCE_IRQ
+       }
+};
+
+static struct platform_device snirm_53c710_rm200_pdev = {
+       .name           = "snirm_53c710",
+       .num_resources  = ARRAY_SIZE(snirm_53c710_rm200_rsrc),
+       .resource       = snirm_53c710_rm200_rsrc
+};
+
+static int __init snirm_setup_devinit(void)
+{
+       if (sni_brd_type == SNI_BRD_RM200) {
+               platform_device_register(&rm200_serial8250_device);
+               platform_device_register(&snirm_82596_rm200_pdev);
+               platform_device_register(&snirm_53c710_rm200_pdev);
+       }
+       return 0;
+}
+
+device_initcall(snirm_setup_devinit);
+
+
+#define SNI_RM200_INT_STAT_REG  0xbc000000
+#define SNI_RM200_INT_ENA_REG   0xbc080000
+
+#define SNI_RM200_INT_START  24
+#define SNI_RM200_INT_END    28
+
+static void enable_rm200_irq(unsigned int irq)
+{
+       unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
+
+       *(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask;
+}
+
+void disable_rm200_irq(unsigned int irq)
+{
+       unsigned int mask = 1 << (irq - SNI_RM200_INT_START);
+
+       *(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask;
+}
+
+void end_rm200_irq(unsigned int irq)
+{
+       if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+               enable_rm200_irq(irq);
+}
+
+static struct irq_chip rm200_irq_type = {
+       .typename = "RM200",
+       .ack = disable_rm200_irq,
+       .mask = disable_rm200_irq,
+       .mask_ack = disable_rm200_irq,
+       .unmask = enable_rm200_irq,
+       .end = end_rm200_irq,
+};
+
+static void sni_rm200_hwint(void)
+{
+       u32 pending = read_c0_cause() & read_c0_status();
+       u8 mask;
+       u8 stat;
+       int irq;
+
+       if (pending & C_IRQ5)
+               do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7);
+       else if (pending & C_IRQ0) {
+               clear_c0_status (IE_IRQ0);
+               mask = *(volatile u8 *)SNI_RM200_INT_ENA_REG ^ 0x1f;
+               stat = *(volatile u8 *)SNI_RM200_INT_STAT_REG ^ 0x14;
+               irq = ffs(stat & mask & 0x1f);
+
+               if (likely(irq > 0))
+                       do_IRQ (irq + SNI_RM200_INT_START - 1);
+               set_c0_status (IE_IRQ0);
+       }
+}
+
+void __init sni_rm200_irq_init(void)
+{
+       int i;
+
+       * (volatile u8 *)SNI_RM200_INT_ENA_REG = 0x1f;
+
+       mips_cpu_irq_init();
+       /* Actually we've got more interrupts to handle ...  */
+       for (i = SNI_RM200_INT_START; i <= SNI_RM200_INT_END; i++)
+               set_irq_chip(i, &rm200_irq_type);
+       sni_hwint = sni_rm200_hwint;
+       change_c0_status(ST0_IM, IE_IRQ0);
+       setup_irq (SNI_RM200_INT_START + 0, &sni_isa_irq);
+}
+
+void sni_rm200_init(void)
+{
+       set_io_port_base(SNI_PORT_BASE + 0x02000000);
+       ioport_resource.end += 0x02000000;
+       ds1216_base = (volatile unsigned char *) SNI_DS1216_RM200_BASE;
+       rtc_mips_get_time = ds1216_get_cmos_time;
+       board_time_init = sni_cpu_time_init;
+}
index afeb7f13e5b50a2f290bce79f5209b901fb36bfc..68d7cf609b4fcabd36396ec85c4838b203ff1f89 100644 (file)
@@ -6,16 +6,10 @@
  * 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/eisa.h>
-#include <linux/hdreg.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/mc146818rtc.h>
-#include <linux/pm.h>
-#include <linux/pci.h>
 #include <linux/console.h>
 #include <linux/fb.h>
 #include <linux/screen_info.h>
 #include <asm/sgialib.h>
 #endif
 
-#include <asm/bcache.h>
-#include <asm/bootinfo.h>
 #include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mc146818-time.h>
-#include <asm/processor.h>
 #include <asm/reboot.h>
 #include <asm/sni.h>
-#include <asm/time.h>
-#include <asm/traps.h>
+
+unsigned int sni_brd_type;
 
 extern void sni_machine_restart(char *command);
 extern void sni_machine_halt(void);
 extern void sni_machine_power_off(void);
 
-void __init plat_timer_setup(struct irqaction *irq)
-{
-       /* set the clock to 100 Hz */
-       outb_p(0x34,0x43);              /* binary, mode 2, LSB/MSB, ch 0 */
-       outb_p(LATCH & 0xff , 0x40);    /* LSB */
-       outb(LATCH >> 8 , 0x40);        /* MSB */
-       setup_irq(0, irq);
-}
-
-/*
- * 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);
-}
-
 static void __init sni_display_setup(void)
 {
 #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) && defined(CONFIG_ARC)
@@ -90,175 +48,11 @@ static void __init sni_display_setup(void)
 #endif
 }
 
-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_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_pci_ops;
-
-static struct pci_controller sni_controller = {
-       .pci_ops        = &sni_pci_ops,
-       .mem_resource   = &sni_mem_resource,
-       .mem_offset     = 0x10000000UL,
-       .io_resource    = &sni_io_resource,
-       .io_offset      = 0x00000000UL
-};
-
-static inline void sni_pcimt_time_init(void)
-{
-       rtc_mips_get_time = mc146818_get_cmos_time;
-       rtc_mips_set_time = mc146818_set_rtc_mmss;
-}
 
 void __init plat_mem_setup(void)
 {
-       sni_pcimt_detect();
-       sni_pcimt_sc_init();
-       sni_pcimt_time_init();
-
        set_io_port_base(SNI_PORT_BASE);
-       ioport_resource.end = sni_io_resource.end;
+//     ioport_resource.end = sni_io_resource.end;
 
        /*
         * Setup (E)ISA I/O memory access stuff
@@ -268,15 +62,33 @@ void __init plat_mem_setup(void)
        EISA_bus = 1;
 #endif
 
-       sni_resource_init();
+       switch (sni_brd_type) {
+       case SNI_BRD_10:
+       case SNI_BRD_10NEW:
+       case SNI_BRD_TOWER_OASIC:
+       case SNI_BRD_MINITOWER:
+               sni_a20r_init();
+               break;
+
+       case SNI_BRD_PCI_TOWER:
+       case SNI_BRD_PCI_TOWER_CPLUS:
+               sni_pcit_init();
+               break;
+
+       case SNI_BRD_RM200:
+               sni_rm200_init();
+               break;
+
+       case SNI_BRD_PCI_MTOWER:
+       case SNI_BRD_PCI_DESKTOP:
+       case SNI_BRD_PCI_MTOWER_CPLUS:
+               sni_pcimt_init();
+               break;
+       }
 
        _machine_restart = sni_machine_restart;
        _machine_halt = sni_machine_halt;
        pm_power_off = sni_machine_power_off;
 
        sni_display_setup();
-
-#ifdef CONFIG_PCI
-       register_pci_controller(&sni_controller);
-#endif
 }
index 1213d166f22eba023b273927fcbbbde91e6323ef..6a44bbf0b732e7cab43bfb0d8a8256972c111259 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/string.h>
+#include <linux/console.h>
 
 #include <asm/addrspace.h>
 #include <asm/sni.h>
@@ -31,7 +32,7 @@
 #define PROM_ENTRY(x)          (PROM_VEC + (x))
 
 
-#undef DEBUG
+#define DEBUG
 #ifdef DEBUG
 #define DBG_PRINTF(x...)     prom_printf(x)
 #else
@@ -93,14 +94,14 @@ static void sni_idprom_dump(void)
 {
        int     i;
 
-       prom_printf("SNI IDProm dump (first 128byte):\n");
-       for(i=0;i<128;i++) {
+       prom_printf("SNI IDProm dump:\n");
+       for (i = 0; i < 256; i++) {
                if (i%16 == 0)
                        prom_printf("%04x ", i);
 
-               prom_printf("%02x ", *(unsigned char *) (SNI_IDPROM_BASE+i));
+               prom_printf("%02x ", *(unsigned char *) (SNI_IDPROM_BASE + i));
 
-               if (i%16 == 15)
+               if (i % 16 == 15)
                        prom_printf("\n");
        }
 }
@@ -118,7 +119,7 @@ static void sni_mem_init(void )
        } memconf[8];
 
        /* MemSIZE from prom in 16MByte chunks */
-       memsize=*((unsigned char *) SNI_IDPROM_MEMSIZE) * 16;
+       memsize = *((unsigned char *) SNI_IDPROM_MEMSIZE) * 16;
 
        DBG_PRINTF("IDProm memsize: %lu MByte\n", memsize);
 
@@ -126,26 +127,134 @@ static void sni_mem_init(void )
        __prom_get_memconf(&memconf);
 
        DBG_PRINTF("prom_get_mem_conf memory configuration:\n");
-       for(i=0;i<8 && memconf[i].size;i++) {
-               prom_printf("Bank%d: %08x @ %08x\n", i,
+       for (i = 0;i < 8 && memconf[i].size; i++) {
+               if (sni_brd_type == SNI_BRD_PCI_TOWER ||
+                   sni_brd_type == SNI_BRD_PCI_TOWER_CPLUS) {
+                       if (memconf[i].base >= 0x20000000 &&
+                           memconf[i].base <  0x30000000) {
+                               memconf[i].base -= 0x20000000;
+                       }
+       }
+               DBG_PRINTF("Bank%d: %08x @ %08x\n", i,
                        memconf[i].size, memconf[i].base);
                add_memory_region(memconf[i].base, memconf[i].size, BOOT_MEM_RAM);
        }
 }
 
+static void __init sni_console_setup(void)
+{
+       char *ctype;
+       char *cdev;
+       char *baud;
+       int port;
+       static char options[8];
+
+       cdev = prom_getenv ("console_dev");
+       if (strncmp (cdev, "tty", 3) == 0) {
+               ctype = prom_getenv ("console");
+               switch (*ctype) {
+               default:
+               case 'l':
+                       port = 0;
+                       baud = prom_getenv("lbaud");
+                       break;
+               case 'r':
+                       port = 1;
+                       baud = prom_getenv("rbaud");
+                       break;
+               }
+               if (baud)
+                       strcpy(options, baud);
+               add_preferred_console("ttyS", port, baud ? options : NULL);
+       }
+}
+
 void __init prom_init(void)
 {
        int argc = fw_arg0;
        char **argv = (void *)fw_arg1;
-       unsigned int sni_brd_type = *(unsigned char *) SNI_IDPROM_BRDTYPE;
        int i;
+       int cputype;
 
-       DBG_PRINTF("Found SNI brdtype %02x\n", sni_brd_type);
+       sni_brd_type = *(unsigned char *)SNI_IDPROM_BRDTYPE;
+       cputype = *(unsigned char *)SNI_IDPROM_CPUTYPE;
+       switch (sni_brd_type) {
+       case SNI_BRD_TOWER_OASIC:
+               switch (cputype) {
+               case SNI_CPU_M8030:
+                       systype = "RM400-330";
+                       break;
+               case SNI_CPU_M8031:
+                       systype = "RM400-430";
+                       break;
+               case SNI_CPU_M8037:
+                       systype = "RM400-530";
+                       break;
+               case SNI_CPU_M8034:
+                       systype = "RM400-730";
+                       break;
+               default:
+                       systype = "RM400-xxx";
+                       break;
+               }
+               break;
+       case SNI_BRD_MINITOWER:
+               switch (cputype) {
+               case SNI_CPU_M8021:
+               case SNI_CPU_M8043:
+                       systype = "RM400-120";
+                       break;
+               case SNI_CPU_M8040:
+                       systype = "RM400-220";
+                       break;
+               case SNI_CPU_M8053:
+                       systype = "RM400-225";
+                       break;
+               case SNI_CPU_M8050:
+                       systype = "RM400-420";
+                       break;
+               default:
+                       systype = "RM400-xxx";
+                       break;
+               }
+               break;
+       case SNI_BRD_PCI_TOWER:
+               systype = "RM400-Cxx";
+               break;
+       case SNI_BRD_RM200:
+               systype = "RM200-xxx";
+               break;
+       case SNI_BRD_PCI_MTOWER:
+               systype = "RM300-Cxx";
+               break;
+       case SNI_BRD_PCI_DESKTOP:
+               switch (read_c0_prid() & 0xff00) {
+               case PRID_IMP_R4600:
+               case PRID_IMP_R4700:
+                       systype = "RM200-C20";
+                       break;
+               case PRID_IMP_R5000:
+                       systype = "RM200-C40";
+                       break;
+               default:
+                       systype = "RM200-Cxx";
+                       break;
+               }
+               break;
+       case SNI_BRD_PCI_TOWER_CPLUS:
+               systype = "RM400-Exx";
+               break;
+       case SNI_BRD_PCI_MTOWER_CPLUS:
+               systype = "RM300-Exx";
+               break;
+       }
+       DBG_PRINTF("Found SNI brdtype %02x name %s\n", sni_brd_type,systype);
 
 #ifdef DEBUG
        sni_idprom_dump();
 #endif
        sni_mem_init();
+       sni_console_setup();
 
        /* copy prom cmdline parameters to kernel cmdline */
        for (i = 1; i < argc; i++) {
diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c
new file mode 100644 (file)
index 0000000..20028fc
--- /dev/null
@@ -0,0 +1,148 @@
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+
+#include <asm/sni.h>
+#include <asm/time.h>
+
+#define SNI_CLOCK_TICK_RATE     3686400
+#define SNI_COUNTER2_DIV        64
+#define SNI_COUNTER0_DIV        ((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ)
+
+static void sni_a20r_timer_ack(void)
+{
+        *(volatile u8 *)A20R_PT_TIM0_ACK = 0x0; wmb();
+}
+
+/*
+ * a20r platform uses 2 counters to divide the input frequency.
+ * Counter 2 output is connected to Counter 0 & 1 input.
+ */
+static void __init sni_a20r_timer_setup(struct irqaction *irq)
+{
+        *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; wmb();
+        *(volatile u8 *)(A20R_PT_CLOCK_BASE +  0) = (SNI_COUNTER0_DIV) & 0xff; wmb();
+        *(volatile u8 *)(A20R_PT_CLOCK_BASE +  0) = (SNI_COUNTER0_DIV >> 8) & 0xff; wmb();
+
+        *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; wmb();
+        *(volatile u8 *)(A20R_PT_CLOCK_BASE +  8) = (SNI_COUNTER2_DIV) & 0xff; wmb();
+        *(volatile u8 *)(A20R_PT_CLOCK_BASE +  8) = (SNI_COUNTER2_DIV >> 8) & 0xff; wmb();
+
+        setup_irq(SNI_A20R_IRQ_TIMER, irq);
+        mips_timer_ack = sni_a20r_timer_ack;
+}
+
+#define SNI_8254_TICK_RATE        1193182UL
+
+#define SNI_8254_TCSAMP_COUNTER   ((SNI_8254_TICK_RATE / HZ) + 255)
+
+static __init unsigned long dosample(void)
+{
+       u32 ct0, ct1;
+       volatile u8 msb, lsb;
+
+       /* Start the counter. */
+       outb_p (0x34, 0x43);
+       outb_p(SNI_8254_TCSAMP_COUNTER & 0xff, 0x40);
+       outb (SNI_8254_TCSAMP_COUNTER >> 8, 0x40);
+
+       /* Get initial counter invariant */
+       ct0 = read_c0_count();
+
+       /* Latch and spin until top byte of counter0 is zero */
+       do {
+               outb (0x00, 0x43);
+               lsb = inb (0x40);
+               msb = inb (0x40);
+               ct1 = read_c0_count();
+       } while (msb);
+
+       /* Stop the counter. */
+       outb (0x38, 0x43);
+       /*
+        * Return the difference, this is how far the r4k counter increments
+        * for every 1/HZ seconds. We round off the nearest 1 MHz of master
+        * clock (= 1000000 / HZ / 2).
+        */
+       /*return (ct1 - ct0 + (500000/HZ/2)) / (500000/HZ) * (500000/HZ);*/
+       return (ct1 - ct0) / (500000/HZ) * (500000/HZ);
+}
+
+/*
+ * Here we need to calibrate the cycle counter to at least be close.
+ */
+__init void sni_cpu_time_init(void)
+{
+       unsigned long r4k_ticks[3];
+       unsigned long r4k_tick;
+
+       /*
+        * Figure out the r4k offset, the algorithm is very simple and works in
+        * _all_ cases as long as the 8254 counter register itself works ok (as
+        * an interrupt driving timer it does not because of bug, this is why
+        * we are using the onchip r4k counter/compare register to serve this
+        * purpose, but for r4k_offset calculation it will work ok for us).
+        * There are other very complicated ways of performing this calculation
+        * but this one works just fine so I am not going to futz around. ;-)
+        */
+       printk(KERN_INFO "Calibrating system timer... ");
+       dosample();     /* Prime cache. */
+       dosample();     /* Prime cache. */
+       /* Zero is NOT an option. */
+       do {
+               r4k_ticks[0] = dosample();
+       } while (!r4k_ticks[0]);
+       do {
+               r4k_ticks[1] = dosample();
+       } while (!r4k_ticks[1]);
+
+       if (r4k_ticks[0] != r4k_ticks[1]) {
+               printk("warning: timer counts differ, retrying... ");
+               r4k_ticks[2] = dosample();
+               if (r4k_ticks[2] == r4k_ticks[0]
+                   || r4k_ticks[2] == r4k_ticks[1])
+                       r4k_tick = r4k_ticks[2];
+               else {
+                       printk("disagreement, using average... ");
+                       r4k_tick = (r4k_ticks[0] + r4k_ticks[1]
+                                  + r4k_ticks[2]) / 3;
+               }
+       } else
+               r4k_tick = r4k_ticks[0];
+
+       printk("%d [%d.%04d MHz CPU]\n", (int) r4k_tick,
+               (int) (r4k_tick / (500000 / HZ)),
+               (int) (r4k_tick % (500000 / HZ)));
+
+       mips_hpt_frequency = r4k_tick * HZ;
+}
+
+/*
+ * R4k counter based timer interrupt. Works on RM200-225 and possibly
+ * others but not on RM400
+ */
+static void __init sni_cpu_timer_setup(struct irqaction *irq)
+{
+        setup_irq(SNI_MIPS_IRQ_CPU_TIMER, irq);
+}
+
+void __init plat_timer_setup(struct irqaction *irq)
+{
+       switch (sni_brd_type) {
+       case SNI_BRD_10:
+       case SNI_BRD_10NEW:
+       case SNI_BRD_TOWER_OASIC:
+       case SNI_BRD_MINITOWER:
+               sni_a20r_timer_setup (irq);
+               break;
+
+       case SNI_BRD_PCI_TOWER:
+       case SNI_BRD_RM200:
+       case SNI_BRD_PCI_MTOWER:
+       case SNI_BRD_PCI_DESKTOP:
+       case SNI_BRD_PCI_TOWER_CPLUS:
+       case SNI_BRD_PCI_MTOWER_CPLUS:
+               sni_cpu_timer_setup (irq);
+               break;
+       }
+}
diff --git a/include/asm-mips/ds1216.h b/include/asm-mips/ds1216.h
new file mode 100644 (file)
index 0000000..1ff8b73
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _DS1216_H
+#define _DS1216_H
+
+extern volatile unsigned char *ds1216_base;
+unsigned long ds1216_get_cmos_time(void);
+int ds1216_set_rtc_mmss(unsigned long nowtime);
+
+#define DS1216_SEC_BYTE                1
+#define DS1216_MIN_BYTE                2
+#define DS1216_HOUR_BYTE       3
+#define DS1216_HOUR_MASK       (0x1f)
+#define DS1216_AMPM_MASK       (1<<5)
+#define DS1216_1224_MASK       (1<<7)
+#define DS1216_DAY_BYTE                4
+#define DS1216_DAY_MASK                (0x7)
+#define DS1216_DATE_BYTE       5
+#define DS1216_DATE_MASK       (0x3f)
+#define DS1216_MONTH_BYTE      6
+#define DS1216_MONTH_MASK      (0x1f)
+#define DS1216_YEAR_BYTE       7
+
+#define DS1216_SEC(buf)                (buf[DS1216_SEC_BYTE])
+#define DS1216_MIN(buf)                (buf[DS1216_MIN_BYTE])
+#define DS1216_HOUR(buf)       (buf[DS1216_HOUR_BYTE] & DS1216_HOUR_MASK)
+#define DS1216_AMPM(buf)       (buf[DS1216_HOUR_BYTE] & DS1216_AMPM_MASK)
+#define DS1216_1224(buf)       (buf[DS1216_HOUR_BYTE] & DS1216_1224_MASK)
+#define DS1216_DATE(buf)       (buf[DS1216_DATE_BYTE] & DS1216_DATE_MASK)
+#define DS1216_MONTH(buf)      (buf[DS1216_MONTH_BYTE] & DS1216_MONTH_MASK)
+#define DS1216_YEAR(buf)       (buf[DS1216_YEAR_BYTE])
+
+#endif
index 11410ae10d36236aaaef1cc24d44578d5a570726..7e07283140a3e04f70e7b583f2bb938ab5d6ea5e 100644 (file)
@@ -21,9 +21,7 @@
 #define cpu_has_watch          0
 #define cpu_has_mips16         0
 #define cpu_has_divec          0
-#define cpu_has_vce            0
 #define cpu_has_cache_cdex_p   1
-#define cpu_has_cache_cdex_s   0
 #define cpu_has_prefetch       0
 #define cpu_has_mcheck         0
 #define cpu_has_ejtag          0
@@ -35,9 +33,6 @@
 #define cpu_has_nofpuex                0
 #define cpu_has_64bits         1
 
-#define cpu_dcache_line_size() 32
-#define cpu_icache_line_size() 32
-
 #define cpu_has_mips32r1       0
 #define cpu_has_mips32r2       0
 #define cpu_has_mips64r1       0
index b9ba54d0dd359ebd6bfabfd84da4dcf2e53b4d93..62f9be6f7320f2844ba4dc5a0bac904292233de2 100644 (file)
@@ -6,12 +6,72 @@
  * for more details.
  *
  * Copyright (C) 1997, 1998 by Ralf Baechle
+ * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
  */
 #ifndef __ASM_SNI_H
 #define __ASM_SNI_H
 
+extern unsigned int sni_brd_type;
+
+#define SNI_BRD_10                 2
+#define SNI_BRD_10NEW              3
+#define SNI_BRD_TOWER_OASIC        4
+#define SNI_BRD_MINITOWER          5
+#define SNI_BRD_PCI_TOWER          6
+#define SNI_BRD_RM200              7
+#define SNI_BRD_PCI_MTOWER         8
+#define SNI_BRD_PCI_DESKTOP        9
+#define SNI_BRD_PCI_TOWER_CPLUS   10
+#define SNI_BRD_PCI_MTOWER_CPLUS  11
+
+/* RM400 cpu types */
+#define SNI_CPU_M8021           0x01
+#define SNI_CPU_M8030           0x04
+#define SNI_CPU_M8031           0x06
+#define SNI_CPU_M8034           0x0f
+#define SNI_CPU_M8037           0x07
+#define SNI_CPU_M8040           0x05
+#define SNI_CPU_M8043           0x09
+#define SNI_CPU_M8050           0x0b
+#define SNI_CPU_M8053           0x0d
+
 #define SNI_PORT_BASE          0xb4000000
 
+#ifndef __MIPSEL__
+/*
+ * ASIC PCI registers for big endian configuration.
+ */
+#define PCIMT_UCONF            0xbfff0004
+#define PCIMT_IOADTIMEOUT2     0xbfff000c
+#define PCIMT_IOMEMCONF                0xbfff0014
+#define PCIMT_IOMMU            0xbfff001c
+#define PCIMT_IOADTIMEOUT1     0xbfff0024
+#define PCIMT_DMAACCESS                0xbfff002c
+#define PCIMT_DMAHIT           0xbfff0034
+#define PCIMT_ERRSTATUS                0xbfff003c
+#define PCIMT_ERRADDR          0xbfff0044
+#define PCIMT_SYNDROME         0xbfff004c
+#define PCIMT_ITPEND           0xbfff0054
+#define  IT_INT2               0x01
+#define  IT_INTD               0x02
+#define  IT_INTC               0x04
+#define  IT_INTB               0x08
+#define  IT_INTA               0x10
+#define  IT_EISA               0x20
+#define  IT_SCSI               0x40
+#define  IT_ETH                        0x80
+#define PCIMT_IRQSEL           0xbfff005c
+#define PCIMT_TESTMEM          0xbfff0064
+#define PCIMT_ECCREG           0xbfff006c
+#define PCIMT_CONFIG_ADDRESS   0xbfff0074
+#define PCIMT_ASIC_ID          0xbfff007c      /* read */
+#define PCIMT_SOFT_RESET       0xbfff007c      /* write */
+#define PCIMT_PIA_OE           0xbfff0084
+#define PCIMT_PIA_DATAOUT      0xbfff008c
+#define PCIMT_PIA_DATAIN       0xbfff0094
+#define PCIMT_CACHECONF                0xbfff009c
+#define PCIMT_INVSPACE         0xbfff00a4
+#else
 /*
  * ASIC PCI registers for little endian configuration.
  */
 #define PCIMT_PIA_DATAIN       0xbfff0090
 #define PCIMT_CACHECONF                0xbfff0098
 #define PCIMT_INVSPACE         0xbfff00a0
+#endif
+
 #define PCIMT_PCI_CONF         0xbfff0100
 
 /*
 #define PCIMT_CSTIMER          0xbfde0000
 #define PCIMT_PWDN             0xbfdf0000
 
+/*
+ * A20R based boards
+ */
+#define A20R_PT_CLOCK_BASE      0xbc040000
+#define A20R_PT_TIM0_ACK        0xbc050000
+#define A20R_PT_TIM1_ACK        0xbc060000
+
+#define SNI_MIPS_IRQ_CPU_BASE   16
+#define SNI_MIPS_IRQ_CPU_TIMER  (SNI_MIPS_IRQ_CPU_BASE+7)
+
+#define SNI_A20R_IRQ_BASE       SNI_MIPS_IRQ_CPU_BASE
+#define SNI_A20R_IRQ_TIMER      (SNI_A20R_IRQ_BASE+5)
+
+#define SNI_DS1216_A20R_BASE    0xbc081ffc
+#define SNI_DS1216_RM200_BASE   0xbcd41ffc
+
+#define SNI_PCIT_INT_REG        0xbfff000c
+
+#define SNI_PCIT_INT_START      24
+#define SNI_PCIT_INT_END        30
+
+#define PCIT_IRQ_ETHERNET       (SNI_MIPS_IRQ_CPU_BASE + 5)
+#define PCIT_IRQ_INTA           (SNI_PCIT_INT_START + 0)
+#define PCIT_IRQ_INTB           (SNI_PCIT_INT_START + 1)
+#define PCIT_IRQ_INTC           (SNI_PCIT_INT_START + 2)
+#define PCIT_IRQ_INTD           (SNI_PCIT_INT_START + 3)
+#define PCIT_IRQ_SCSI0          (SNI_PCIT_INT_START + 4)
+#define PCIT_IRQ_SCSI1          (SNI_PCIT_INT_START + 5)
+
+
 /*
  * Interrupt 0-16 are EISA interrupts.  Interrupts from 16 on are assigned
  * to the other interrupts generated by ASIC PCI.
  * ASIC PCI interrupt.
  */
 #define PCIMT_KEYBOARD_IRQ      1
-#define PCIMT_IRQ_INT2         16
-#define PCIMT_IRQ_INTD         17
-#define PCIMT_IRQ_INTC         18
-#define PCIMT_IRQ_INTB         19
-#define PCIMT_IRQ_INTA         20
-#define PCIMT_IRQ_EISA         21
-#define PCIMT_IRQ_SCSI         22
-#define PCIMT_IRQ_ETHERNET     23
+#define PCIMT_IRQ_INT2         24
+#define PCIMT_IRQ_INTD         25
+#define PCIMT_IRQ_INTC         26
+#define PCIMT_IRQ_INTB         27
+#define PCIMT_IRQ_INTA         28
+#define PCIMT_IRQ_EISA         29
+#define PCIMT_IRQ_SCSI         30
+
+#define PCIMT_IRQ_ETHERNET     (SNI_MIPS_IRQ_CPU_BASE+6)
+
+#if 0
 #define PCIMT_IRQ_TEMPERATURE  24
 #define PCIMT_IRQ_EISA_NMI     25
 #define PCIMT_IRQ_POWER_OFF    26
 #define PCIMT_IRQ_BUTTON       27
+#endif
 
 /*
  * Base address for the mapped 16mb EISA bus segment.
 /* PCI EISA Interrupt acknowledge  */
 #define PCIMT_INT_ACKNOWLEDGE  0xba000000
 
+/* board specific init functions */
+extern void sni_a20r_init (void);
+extern void sni_pcit_init (void);
+extern void sni_rm200_init (void);
+extern void sni_pcimt_init (void);
+
+/* board specific irq init functions */
+extern void sni_a20r_irq_init (void);
+extern void sni_pcit_irq_init (void);
+extern void sni_pcit_cplus_irq_init (void);
+extern void sni_rm200_irq_init (void);
+extern void sni_pcimt_irq_init (void);
+
+/* timer inits */
+extern void sni_cpu_time_init(void);
+
+/* common irq stuff */
+extern void (*sni_hwint)(void);
+extern struct irqaction sni_isa_irq;
+
 #endif /* __ASM_SNI_H */