diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /arch/mips/sni | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'arch/mips/sni')
-rw-r--r-- | arch/mips/sni/Makefile | 28 | ||||
-rw-r--r-- | arch/mips/sni/bios32.c | 264 | ||||
-rw-r--r-- | arch/mips/sni/hw-access.c | 157 | ||||
-rw-r--r-- | arch/mips/sni/int-handler.S | 193 | ||||
-rw-r--r-- | arch/mips/sni/reset.c | 38 | ||||
-rw-r--r-- | arch/mips/sni/setup.c | 108 |
6 files changed, 788 insertions, 0 deletions
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile new file mode 100644 index 000000000..bfa8e2cad --- /dev/null +++ b/arch/mips/sni/Makefile @@ -0,0 +1,28 @@ +# +# Makefile for the SNI specific part of the kernel +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +include ../../../.config + +all: sni.o +O_TARGET := sni.o +O_OBJS := hw-access.o int-handler.o reset.o setup.o + +ifdef CONFIG_PCI +O_OBJS += bios32.o +endif + +int-handler.o: int-handler.S + +clean: + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/sni/bios32.c b/arch/mips/sni/bios32.c new file mode 100644 index 000000000..366347902 --- /dev/null +++ b/arch/mips/sni/bios32.c @@ -0,0 +1,264 @@ +/* + * bios32.c - Fake PCI BIOS functions for RM200 C systems. Chainsawed + * from the Alpha version. + * + * Written by Ralf Baechle (ralf@gnu.ai.mit.edu) + * + * For more information, please consult + * + * PCI BIOS Specification Revision + * PCI Local Bus Specification + * PCI System Design Guide + * + * PCI Special Interest Group + * M/S HF3-15A + * 5200 N.E. Elam Young Parkway + * Hillsboro, Oregon 97124-6497 + * +1 (503) 696-2000 + * +1 (800) 433-5177 + * + * Manuals are $25 each or $50 for all three, plus $7 shipping + * within the United States, $35 abroad. + */ +#include <linux/config.h> + +#include <linux/kernel.h> +#include <linux/bios32.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <linux/malloc.h> +#include <linux/mm.h> + +#include <asm/ptrace.h> +#include <asm/system.h> +#include <asm/io.h> + +/* + * This is a table of the onboard PCI devices of the RM200 C + * onboard devices. + */ +static struct board { + unsigned short vendor; + unsigned short device_id; + unsigned int memory; + unsigned int io; + unsigned char irq; + unsigned char revision; + } boards[] = { + { + PCI_VENDOR_ID_NCR, + PCI_DEVICE_ID_NCR_53C810, + 0x1b000000, + 0x00000000, + 5, + 0x11 + }, + { + PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_LANCE, + 0x1b000100, + 0x17beffe0, + 6, + 0x16 + }, + { + PCI_VENDOR_ID_CIRRUS, + PCI_DEVICE_ID_CIRRUS_5434_8, + 0x18000000, + 0x00000000, + 4, + 0x8e + }, + { 0xffff, } +}; + +/* + * Given the vendor and device ids, find the n'th instance of that device + * in the system. + */ +int pcibios_find_device (unsigned short vendor, unsigned short device_id, + unsigned short index, unsigned char *bus, + unsigned char *devfn) +{ + unsigned int curr = 0; + struct board *p; + + for (p = pci_devices; p->vendor != 0xffff; p++) { + if (p->vendor == vendor && p->device == device_id) { + if (curr == index) { + *devfn = p->devfn; + *bus = 0; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + + return PCIBIOS_DEVICE_NOT_FOUND; +} + +/* + * Given the class, find the n'th instance of that device + * in the system. + */ +int pcibios_find_class (unsigned int class_code, unsigned short index, + unsigned char *bus, unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->class == class_code) { + if (curr == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +int pcibios_present(void) +{ + return 1; +} + +unsigned long pcibios_init(unsigned long mem_start, + unsigned long mem_end) +{ + printk("SNI RM200 C BIOS32 fake implementation\n"); + + return mem_start; +} + +const char *pcibios_strerror (int error) +{ + static char buf[80]; + + switch (error) { + case PCIBIOS_SUCCESSFUL: + return "SUCCESSFUL"; + + case PCIBIOS_FUNC_NOT_SUPPORTED: + return "FUNC_NOT_SUPPORTED"; + + case PCIBIOS_BAD_VENDOR_ID: + return "SUCCESSFUL"; + + case PCIBIOS_DEVICE_NOT_FOUND: + return "DEVICE_NOT_FOUND"; + + case PCIBIOS_BAD_REGISTER_NUMBER: + return "BAD_REGISTER_NUMBER"; + + default: + sprintf (buf, "UNKNOWN RETURN 0x%x", error); + return buf; + } +} + +/* + * BIOS32-style PCI interface: + */ + +int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char *value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + *value = 0xff; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x00; + *value = conf_read(addr) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short *value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + *value = 0xffff; + + if (where & 0x1) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x08; + *value = conf_read(addr) >> ((where & 3) * 8); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int *value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + *value = 0xffffffff; + if (where & 0x3) { + return PCIBIOS_BAD_REGISTER_NUMBER; + } + if (mk_conf_addr(bus, device_fn, where, &pci_addr)) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x18; + *value = conf_read(addr); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x00; + conf_write(addr, value << ((where & 3) * 8)); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x08; + conf_write(addr, value << ((where & 3) * 8)); + return PCIBIOS_SUCCESSFUL; +} + + +int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int value) +{ + unsigned long addr = LCA_CONF; + unsigned long pci_addr; + + if (mk_conf_addr(bus, device_fn, where, &pci_addr) < 0) { + return PCIBIOS_SUCCESSFUL; + } + addr |= (pci_addr << 5) + 0x18; + conf_write(addr, value << ((where & 3) * 8)); + return PCIBIOS_SUCCESSFUL; +} diff --git a/arch/mips/sni/hw-access.c b/arch/mips/sni/hw-access.c new file mode 100644 index 000000000..42c69590a --- /dev/null +++ b/arch/mips/sni/hw-access.c @@ -0,0 +1,157 @@ +/* + * Low-level hardware access stuff for SNI RM200 PCI + * + * 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 by Ralf Baechle + */ +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/linkage.h> +#include <linux/types.h> +#include <asm/bootinfo.h> +#include <asm/cache.h> +#include <asm/dma.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/mc146818rtc.h> +#include <asm/vector.h> + +extern int FLOPPY_IRQ; +extern int FLOPPY_DMA; + +/* + * How to access the FDC's registers. + */ +static unsigned char +fd_inb(unsigned int port) +{ + return inb_p(port); +} + +static void +fd_outb(unsigned char value, unsigned int port) +{ + outb_p(value, port); +} + +/* + * How to access the floppy DMA functions. + */ +static void +fd_enable_dma(void) +{ + enable_dma(FLOPPY_DMA); +} + +static void +fd_disable_dma(void) +{ + disable_dma(FLOPPY_DMA); +} + +static int +fd_request_dma(void) +{ + return request_dma(FLOPPY_DMA, "floppy"); +} + +static void +fd_free_dma(void) +{ + free_dma(FLOPPY_DMA); +} + +static void +fd_clear_dma_ff(void) +{ + clear_dma_ff(FLOPPY_DMA); +} + +static void +fd_set_dma_mode(char mode) +{ + set_dma_mode(FLOPPY_DMA, mode); +} + +static void +fd_set_dma_addr(unsigned int addr) +{ + set_dma_addr(FLOPPY_DMA, addr); +} + +static void +fd_set_dma_count(unsigned int count) +{ + set_dma_count(FLOPPY_DMA, count); +} + +static int +fd_get_dma_residue(void) +{ + return get_dma_residue(FLOPPY_DMA); +} + +static void +fd_enable_irq(void) +{ + enable_irq(FLOPPY_IRQ); +} + +static void +fd_disable_irq(void) +{ + disable_irq(FLOPPY_IRQ); +} + +void +sni_fd_cacheflush(const void *addr, size_t size) +{ + cacheflush((unsigned long)addr, (unsigned long)size, CF_DCACHE|CF_ALL); +} + +/* + * RTC stuff (This is a guess on how the RM handles this ...) + */ +static unsigned char +rtc_read_data(unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + return inb_p(RTC_PORT(1)); +} + +static void +rtc_write_data(unsigned char data, unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); +} + +struct feature sni_rm200_pci_feature = { + /* + * How to access the floppy controller's ports + */ + fd_inb, + fd_outb, + /* + * How to access the floppy DMA functions. + */ + fd_enable_dma, + fd_disable_dma, + fd_request_dma, + fd_free_dma, + fd_clear_dma_ff, + fd_set_dma_mode, + fd_set_dma_addr, + fd_set_dma_count, + fd_get_dma_residue, + fd_enable_irq, + fd_disable_irq, + /* + * How to access the RTC functions. + */ + rtc_read_data, + rtc_write_data +}; diff --git a/arch/mips/sni/int-handler.S b/arch/mips/sni/int-handler.S new file mode 100644 index 000000000..367c07d84 --- /dev/null +++ b/arch/mips/sni/int-handler.S @@ -0,0 +1,193 @@ +/* + * SNI RM200 PCI specific interrupt handler code. + * + * Copyright (C) 1994, 1995, 1996 by Ralf Baechle + * + * This is a verbose copy of the Tyne/rPC44 interrupt handler. We + * don't share the code because the SNI machine has some extra interrupt + * features that want to be supported. + */ +#include <asm/asm.h> +#include <linux/config.h> +#include <asm/mipsconfig.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + + .text + .set noreorder + .set noat + .align 5 + NESTED(sni_rm200_pci_handle_int, FR_SIZE, sp) + SAVE_ALL + REG_S sp,FR_ORIG_REG2(sp) + CLI + .set at + lui s0,%hi(PORT_BASE_SNI) + li a0,0x0f + sb a0,%lo(PORT_BASE_SNI+0x20)(s0) # poll command + lb a0,%lo(PORT_BASE_SNI+0x20)(s0) # read result + bgtz a0,poll_second + andi a0,7 + beq a0,2,poll_second # cascade? + li s1,1 # delay slot + /* + * Acknowledge first pic + */ + lb t2,%lo(PORT_BASE_SNI+0x21)(s0) + lui s4,%hi(cache_21) + lb t0,%lo(cache_21)(s4) + sllv s1,s1,a0 + or t0,s1 + sb t0,%lo(cache_21)(s4) + sb t0,%lo(PORT_BASE_SNI+0x21)(s0) + lui s3,%hi(intr_count) + lw s7,%lo(intr_count)(s3) + li t2,0x20 + sb t2,%lo(PORT_BASE_SNI+0x20)(s0) + /* + * Now call the real handler + */ + la t3,IRQ_vectors + sll t2,a0,PTRLOG + addu t3,t2 + LONG_L t3,(t3) + addiu t0,s7,1 + jalr t3 + sw t0,%lo(intr_count)(s3) + sw s7,%lo(intr_count)(s3) + /* + * Unblock first pic + */ + lbu t1,%lo(PORT_BASE_SNI+0x21)(s0) + lb t1,%lo(cache_21)(s4) + nor s1,zero,s1 + and t1,s1 + sb t1,%lo(cache_21)(s4) + jr v0 + sb t1,%lo(PORT_BASE_SNI+0x21)(s0) # delay slot + + /* + * Cascade interrupt from second PIC + */ + .align 5 +poll_second: li a0,0x0f + sb a0,%lo(PORT_BASE_SNI+0xa0)(s0) # poll command + lb a0,%lo(PORT_BASE_SNI+0xa0)(s0) # read result + bgtz a0,3f + andi a0,7 + /* + * Acknowledge second pic + */ + lbu t2,%lo(PORT_BASE_SNI+0xa1)(s0) + lui s4,%hi(cache_A1) + lb t3,%lo(cache_A1)(s4) + sllv s1,s1,a0 + or t3,s1 + sb t3,%lo(cache_A1)(s4) + sb t3,%lo(PORT_BASE_SNI+0xa1)(s0) + li t3,0x20 + sb t3,%lo(PORT_BASE_SNI+0xa0)(s0) + lui s3,%hi(intr_count) + lw s7,%lo(intr_count)(s3) + sb t3,%lo(PORT_BASE_SNI+0x20)(s0) + /* + * Now call the real handler + */ + la t3,IRQ_vectors + addiu a0,8 + sll t2,a0,PTRLOG + addu t3,t2 + LONG_L t3,(t3) + addiu t0,s7,1 + jalr t3 + sw t0,%lo(intr_count)(s3) # delay slot + sw s7,%lo(intr_count)(s3) + /* + * Unblock second pic + */ + lb t1,%lo(PORT_BASE_SNI+0xa1)(s0) + lb t1,%lo(cache_A1)(s4) + subu t0,1 + nor s1,zero,s1 + and t1,t1,s1 + sb t1,%lo(cache_A1)(s4) + jr v0 + sb t1,%lo(PORT_BASE_SNI+0xa1)(s0) # delay slot + +/* + * FIXME: This is definatly wrong but I'll have to do it this way + * 'till I get more hardware info. + */ +#ifdef CONFIG_LANCE32 + +/* + * FIXME: detect this address + */ +#define LANCE_BASE 0xbb000100 + +/* Offsets from base I/O address. */ +#define LANCE_DATA 0x10 +#define LANCE_ADDR 0x12 +#define LANCE_RESET 0x14 +#define LANCE_BUS_IF 0x16 +#define LANCE_TOTAL_SIZE 0x18 + +/* + * ... check if we were interrupted by the Lance ... + */ +3: lh s0,LANCE_BASE+LANCE_ADDR + sh zero,LANCE_BASE+LANCE_ADDR + lh t1,LANCE_BASE+LANCE_DATA + andi t2,t1,0x80 + beqz t1,3f # no Lance interrupt? + mfc0 t0,CP0_STATUS # delay slot + ori t0,0x041f + xori t0,0x041e + mtc0 t0,CP0_STATUS + jal do_IRQ + li a0,10 # delay slot + sh s0,LANCE_BASE+LANCE_ADDR + mfc0 t0,CP0_STATUS + ori t0,0x0401 + xori t0,0x0001 + mtc0 t0,CP0_STATUS + j ret_from_sys_call + nop # delay slot + +#endif /* CONFIG_LANCE32 */ + +/* + * FIXME: This is definatly wrong but I'll have to do it this way + * 'till I get more hardware info. + */ +#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? + nop # delay slot + jal do_fast_IRQ + li a0,5 # delay slot + j return + nop # delay slot + +#endif /* CONFIG_SCSI_NCR53C8XX */ + +/* + * "Jump extender" to reach spurious_interrupt + */ +3: j spurious_interrupt + nop # delay slot + END(sni_rm200_pci_handle_int) diff --git a/arch/mips/sni/reset.c b/arch/mips/sni/reset.c new file mode 100644 index 000000000..9dd017a7c --- /dev/null +++ b/arch/mips/sni/reset.c @@ -0,0 +1,38 @@ +/* + * linux/arch/mips/sni/process.c + * + * Reset a SNI machine. + */ +#include <asm/io.h> +#include <asm/system.h> + +/* + * This routine reboots the machine by asking the keyboard + * 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) +{ + int i; + + for (i=0; i<0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +void +sni_hard_reset_now(void) +{ + int i, j; + + sti(); + for (;;) { + for (i=0; i<100; i++) { + kb_wait(); + for(j = 0; j < 100000 ; j++) + /* nothing */; + outb_p(0xfe,0x64); /* pulse reset low */ + } + } +} diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c new file mode 100644 index 000000000..a4cc4a57f --- /dev/null +++ b/arch/mips/sni/setup.c @@ -0,0 +1,108 @@ +/* + * Setup pointers to hardware dependand routines. + * + * 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 by Ralf Baechle + */ +#include <asm/ptrace.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/timex.h> +#include <asm/bootinfo.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/processor.h> +#include <asm/vector.h> + +/* + * Initial irq handlers. + */ +static void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL}; + +extern asmlinkage void sni_rm200_pci_handle_int(void); +extern asmlinkage void sni_fd_cacheflush(const void *addr, size_t size); +extern struct feature sni_rm200_pci_feature; +extern void sni_hard_reset_now(void); + +static void +sni_irq_setup(void) +{ + set_except_vector(0, sni_rm200_pci_handle_int); + request_region(0x20,0x20, "pic1"); + request_region(0xa0,0x20, "pic2"); + setup_x86_irq(2, &irq2); + /* + * IRQ0 seems to be the irq for PC style stuff. + * I don't know how to handle the debug button interrupt, so + * don't use this button yet or bad things happen ... + */ + set_cp0_status(ST0_IM, IE_IRQ0); +} + +void (*board_time_init)(struct irqaction *irq); + +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 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ + setup_x86_irq(0, irq); +} + +unsigned char aux_device_present; + +void +sni_rm200_pci_setup(void) +{ + tag *atag; + + /* + * We just check if a tag_screen_info can be gathered + * in setup_arch(), if yes we don't proceed futher... + */ + atag = bi_TagFind(tag_screen_info); + if (!atag) { + /* + * If no, we try to find the tag_arc_displayinfo which is + * always created by Milo for an ARC box (for now Milo only + * works on ARC boxes :) -Stoned. + */ + atag = bi_TagFind(tag_arcdisplayinfo); + if (atag) { + screen_info.orig_x = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_x; + screen_info.orig_y = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->cursor_y; + screen_info.orig_video_cols = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->columns; + screen_info.orig_video_lines = + ((mips_arc_DisplayInfo*)TAGVALPTR(atag))->lines; + } + } + + irq_setup = sni_irq_setup; + fd_cacheflush = sni_fd_cacheflush; // Will go away + feature = &sni_rm200_pci_feature; + port_base = PORT_BASE_SNI; + isa_slot_offset = 0xb0000000; + request_region(0x00,0x20,"dma1"); + request_region(0x40,0x20,"timer"); + request_region(0x70,0x10,"rtc"); + board_time_init = sni_rm200_pci_time_init; + + hard_reset_now = sni_hard_reset_now; + + if (mips_machtype == MACH_SNI_RM200_PCI) + EISA_bus = 1; + aux_device_present = 0xaa; +} |