diff options
Diffstat (limited to 'arch/mips/sni')
-rw-r--r-- | arch/mips/sni/.cvsignore | 1 | ||||
-rw-r--r-- | arch/mips/sni/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/sni/int-handler.S | 23 | ||||
-rw-r--r-- | arch/mips/sni/io.c | 172 | ||||
-rw-r--r-- | arch/mips/sni/pci.c | 23 | ||||
-rw-r--r-- | arch/mips/sni/setup.c | 25 |
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; /* |