summaryrefslogtreecommitdiffstats
path: root/arch/mips/sni
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/sni')
-rw-r--r--arch/mips/sni/.cvsignore1
-rw-r--r--arch/mips/sni/Makefile2
-rw-r--r--arch/mips/sni/int-handler.S23
-rw-r--r--arch/mips/sni/io.c172
-rw-r--r--arch/mips/sni/pci.c23
-rw-r--r--arch/mips/sni/setup.c25
6 files changed, 210 insertions, 36 deletions
diff --git a/arch/mips/sni/.cvsignore b/arch/mips/sni/.cvsignore
new file mode 100644
index 000000000..4671378ae
--- /dev/null
+++ b/arch/mips/sni/.cvsignore
@@ -0,0 +1 @@
+.depend
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
index f0bc3e600..9bd570ff0 100644
--- a/arch/mips/sni/Makefile
+++ b/arch/mips/sni/Makefile
@@ -13,7 +13,7 @@
all: sni.o
O_TARGET := sni.o
-O_OBJS := hw-access.o int-handler.o pci.o reset.o setup.o
+O_OBJS := hw-access.o int-handler.o io.o pci.o reset.o setup.o
int-handler.o: int-handler.S
diff --git a/arch/mips/sni/int-handler.S b/arch/mips/sni/int-handler.S
index f60c82251..d051c8b13 100644
--- a/arch/mips/sni/int-handler.S
+++ b/arch/mips/sni/int-handler.S
@@ -1,7 +1,7 @@
/*
* SNI RM200 PCI specific interrupt handler code.
*
- * Copyright (C) 1994, 1995, 1996 by Ralf Baechle
+ * Copyright (C) 1994 - 1997 by Ralf Baechle
*/
#include <asm/asm.h>
#include <linux/config.h>
@@ -150,30 +150,17 @@ poll_second: li a0,0x0f
#endif /* CONFIG_PCNET32 */
-/*
- * FIXME: This is definatly wrong but I'll have to do it this way
- * 'till I get more hardware info.
- * XXX: Apparently the NCR is attached to interrupt #2.
- */
#ifdef CONFIG_SCSI_NCR53C8XX
/*
- * FIXME: detect this address
- */
-#define NCR_BASE 0xb8000000
-
-/* Offsets from base I/O address. */
-#define NCR_INTF 0x14
-
-/*
* ... check if we were interrupted by the NCR ...
*/
-3: lb t0,NCR_BASE+NCR_INTF
- andi t0,7
- beqz t0,3f # no NCR interrupt?
+3: lb t0,PCIMT_CSITPEND
+ andi t0,0x40
+ bnez t0,3f # bit 6 == 0 -> SCSI IRQ
nop # delay slot
jal do_fast_IRQ
- li a0,5 # delay slot
+ li a0,PCIMT_IRQ_SCSI # delay slot
j return
nop # delay slot
diff --git a/arch/mips/sni/io.c b/arch/mips/sni/io.c
new file mode 100644
index 000000000..f62fdc2d7
--- /dev/null
+++ b/arch/mips/sni/io.c
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ *
+ * Low level I/O functions for SNI.
+ */
+#include <linux/string.h>
+#include <asm/mipsconfig.h>
+#include <asm/addrspace.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+#include <asm/sni.h>
+
+unsigned char sni_map_isa_cache;
+
+#define unused __attribute__((unused))
+
+/*
+ * The PCIMT_CSMAPISA is shared by all processors; we need locking.
+ *
+ * XXX It's legal to use all the I/O memory access functions in interrupt
+ * code, so we need to use the _irq locking stuff which may result in
+ * significant IRQ latencies.
+ */
+static spinlock_t csmapisa_lock unused = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Urgs... We only can see a 16mb window of the 4gb EISA address space
+ * at PCIMT_EISA_BASE. Maladia segmentitis ...
+ *
+ * XXX Check out if accessing PCIMT_CSMAPISA really is slow.
+ * For now assume so.
+ */
+static inline void update_isa_cache(unsigned long address)
+{
+ unsigned char upper;
+
+ upper = address >> 24;
+ if (sni_map_isa_cache != upper) {
+ sni_map_isa_cache = upper;
+ *(volatile unsigned char *)PCIMT_CSMAPISA = ~upper;
+ }
+}
+
+static unsigned char sni_readb(unsigned long addr)
+{
+ unsigned char res;
+
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
+ spin_unlock_irq(&csmapisa_lock);
+
+ return res;
+}
+
+static unsigned short sni_readw(unsigned long addr)
+{
+ unsigned short res;
+
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
+ spin_unlock_irq(&csmapisa_lock);
+
+ return res;
+}
+
+static unsigned int sni_readl(unsigned long addr)
+{
+ unsigned int res;
+
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ res = *(volatile unsigned char *) (PCIMT_EISA_BASE + addr);
+ spin_unlock_irq(&csmapisa_lock);
+
+ return res;
+}
+
+static void sni_writeb(unsigned char val, unsigned long addr)
+{
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_writew(unsigned short val, unsigned long addr)
+{
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_writel(unsigned int val, unsigned long addr)
+{
+ spin_lock_irq(&csmapisa_lock);
+ update_isa_cache(addr);
+ addr &= 0xffffff;
+ *(volatile unsigned char *) (PCIMT_EISA_BASE + addr) = val;
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_memset_io(unsigned long addr, int val, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = PCIMT_EISA_BASE | (addr & 0xffffff);
+ spin_lock_irq(&csmapisa_lock);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~addr + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ update_isa_cache(addr);
+ memset((char *)waddr, val, fraglen);
+ addr += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_memcpy_fromio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = PCIMT_EISA_BASE | (from & 0xffffff);
+ spin_lock_irq(&csmapisa_lock);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~from + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ update_isa_cache(from);
+ memcpy((void *)to, (void *)waddr, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+ spin_unlock_irq(&csmapisa_lock);
+}
+
+static void sni_memcpy_toio(unsigned long to, unsigned long from, unsigned long len)
+{
+ unsigned long waddr;
+
+ waddr = PCIMT_EISA_BASE | (to & 0xffffff);
+ spin_lock_irq(&csmapisa_lock);
+ while(len) {
+ unsigned long fraglen;
+
+ fraglen = (~to + 1) & 0xffffff;
+ fraglen = (fraglen < len) ? fraglen : len;
+ update_isa_cache(to);
+ memcpy((char *)to + PCIMT_EISA_BASE, (void *)from, fraglen);
+ to += fraglen;
+ from += fraglen;
+ waddr = waddr + fraglen - 0x1000000;
+ len -= fraglen;
+ }
+ spin_unlock_irq(&csmapisa_lock);
+}
diff --git a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c
index 06edb268f..917d07a81 100644
--- a/arch/mips/sni/pci.c
+++ b/arch/mips/sni/pci.c
@@ -7,6 +7,7 @@
*/
#include <linux/config.h>
#include <linux/bios32.h>
+#include <linux/init.h>
#include <linux/pci.h>
#include <linux/types.h>
#include <asm/byteorder.h>
@@ -18,18 +19,26 @@
extern inline u32 mkaddr(unsigned char bus, unsigned char dev_fn,
unsigned char where)
{
- return (((bus & 0xff) << 0x10) |
- ((dev_fn & 0xff) << 0x08) |
- ((where & 0xfc)));
+ return ((bus & 0xff) << 0x10) |
+ ((dev_fn & 0xff) << 0x08) |
+ (where & 0xfc);
}
static unsigned long sni_rm200_pcibios_fixup (unsigned long memory_start,
unsigned long memory_end)
{
- /* I guess it's ok to do exactly nothing. */
+ /*
+ * TODO: Fix PCI_INTERRUPT_LINE register for onboard cards.
+ * Take care of RM300 revision D boards for where the network
+ * slot became an ordinary PCI slot.
+ */
return memory_start;
}
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
static int sni_rm200_pcibios_read_config_byte (unsigned char bus,
unsigned char dev_fn,
unsigned char where,
@@ -39,7 +48,7 @@ static int sni_rm200_pcibios_read_config_byte (unsigned char bus,
*(volatile u32 *)PCIMT_CONFIG_ADDRESS = mkaddr(bus, dev_fn, where);
res = *(volatile u32 *)PCIMT_CONFIG_DATA;
- res = le32_to_cpu(res);
+ res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xff;
*val = res;
return PCIBIOS_SUCCESSFUL;
@@ -56,7 +65,7 @@ static int sni_rm200_pcibios_read_config_word (unsigned char bus,
return PCIBIOS_BAD_REGISTER_NUMBER;
*(volatile u32 *)PCIMT_CONFIG_ADDRESS = mkaddr(bus, dev_fn, where);
res = *(volatile u32 *)PCIMT_CONFIG_DATA;
- res = le32_to_cpu(res);
+ res = (le32_to_cpu(res) >> ((where & 3) << 3)) & 0xffff;
*val = res;
return PCIBIOS_SUCCESSFUL;
@@ -110,7 +119,7 @@ static int sni_rm200_pcibios_write_config_dword (unsigned char bus,
return PCIBIOS_SUCCESSFUL;
}
-unsigned long sni_rm200_pcibios_init(unsigned long memory_start, unsigned long memory_end)
+__initfunc(unsigned long sni_rm200_pcibios_init(unsigned long memory_start, unsigned long memory_end))
{
_pcibios_fixup = sni_rm200_pcibios_fixup;
_pcibios_read_config_byte = sni_rm200_pcibios_read_config_byte;
diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c
index 1a7a1387d..7fa76a490 100644
--- a/arch/mips/sni/setup.c
+++ b/arch/mips/sni/setup.c
@@ -5,11 +5,12 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1997 by Ralf Baechle
*/
#include <asm/ptrace.h>
#include <linux/ioport.h>
#include <linux/sched.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/pci.h>
@@ -40,8 +41,7 @@ extern void sni_machine_restart(char *command);
extern void sni_machine_halt(void);
extern void sni_machine_power_off(void);
-static void
-sni_irq_setup(void)
+__initfunc(static void sni_irq_setup(void))
{
set_except_vector(0, sni_rm200_pci_handle_int);
request_region(0x20,0x20, "pic1");
@@ -57,7 +57,7 @@ sni_irq_setup(void)
void (*board_time_init)(struct irqaction *irq);
-static void sni_rm200_pci_time_init(struct irqaction *irq)
+__initfunc(static void sni_rm200_pci_time_init(struct irqaction *irq))
{
/* set the clock to 100 Hz */
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
@@ -67,8 +67,9 @@ static void sni_rm200_pci_time_init(struct irqaction *irq)
}
unsigned char aux_device_present;
-unsigned long sni_rm200_pcibios_init (unsigned long memory_start,
- unsigned long memory_end);
+extern unsigned long sni_rm200_pcibios_init (unsigned long memory_start,
+ unsigned long memory_end);
+extern unsigned char sni_map_isa_cache;
/*
* A bit more gossip about the iron we're running on ...
@@ -92,8 +93,7 @@ static inline void sni_pcimt_detect(void)
printk("%s.\n", boardtype);
}
-void
-sni_rm200_pci_setup(void)
+__initfunc(void sni_rm200_pci_setup(void))
{
tag *atag;
@@ -127,7 +127,14 @@ sni_rm200_pci_setup(void)
fd_cacheflush = sni_fd_cacheflush; // Will go away
feature = &sni_rm200_pci_feature;
port_base = SNI_PORT_BASE;
+
+ /*
+ * Setup (E)ISA I/O memory access stuff
+ */
isa_slot_offset = 0xb0000000;
+ // sni_map_isa_cache = 0;
+ EISA_bus = 1;
+
request_region(0x00,0x20,"dma1");
request_region(0x40,0x20,"timer");
/* XXX FIXME: CONFIG_RTC */
@@ -140,8 +147,6 @@ sni_rm200_pci_setup(void)
_machine_halt = sni_machine_halt;
_machine_power_off = sni_machine_power_off;
- if (mips_machtype == MACH_SNI_RM200_PCI)
- EISA_bus = 1;
aux_device_present = 0xaa;
/*