diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/mips/ddb5xxx |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/mips/ddb5xxx')
25 files changed, 3509 insertions, 0 deletions
diff --git a/arch/mips/ddb5xxx/common/Makefile b/arch/mips/ddb5xxx/common/Makefile new file mode 100644 index 00000000000..bc44e303271 --- /dev/null +++ b/arch/mips/ddb5xxx/common/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the common code of NEC DDB-Vrc5xxx board +# + +obj-y += nile4.o prom.o rtc_ds1386.o diff --git a/arch/mips/ddb5xxx/common/nile4.c b/arch/mips/ddb5xxx/common/nile4.c new file mode 100644 index 00000000000..7ec7d903ba9 --- /dev/null +++ b/arch/mips/ddb5xxx/common/nile4.c @@ -0,0 +1,130 @@ +/* + * + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * arch/mips/ddb5xxx/common/nile4.c + * misc low-level routines for vrc-5xxx controllers. + * + * derived from original code by Geert Uytterhoeven <geert@sonycom.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/types.h> +#include <linux/kernel.h> + +#include <asm/ddb5xxx/ddb5xxx.h> + +u32 +ddb_calc_pdar(u32 phys, u32 size, int width, + int on_memory_bus, int pci_visible) +{ + u32 maskbits; + u32 widthbits; + + switch (size) { +#if 0 /* We don't support 4 GB yet */ + case 0x100000000: /* 4 GB */ + maskbits = 4; + break; +#endif + case 0x80000000: /* 2 GB */ + maskbits = 5; + break; + case 0x40000000: /* 1 GB */ + maskbits = 6; + break; + case 0x20000000: /* 512 MB */ + maskbits = 7; + break; + case 0x10000000: /* 256 MB */ + maskbits = 8; + break; + case 0x08000000: /* 128 MB */ + maskbits = 9; + break; + case 0x04000000: /* 64 MB */ + maskbits = 10; + break; + case 0x02000000: /* 32 MB */ + maskbits = 11; + break; + case 0x01000000: /* 16 MB */ + maskbits = 12; + break; + case 0x00800000: /* 8 MB */ + maskbits = 13; + break; + case 0x00400000: /* 4 MB */ + maskbits = 14; + break; + case 0x00200000: /* 2 MB */ + maskbits = 15; + break; + case 0: /* OFF */ + maskbits = 0; + break; + default: + panic("nile4_set_pdar: unsupported size %p", (void *) size); + } + switch (width) { + case 8: + widthbits = 0; + break; + case 16: + widthbits = 1; + break; + case 32: + widthbits = 2; + break; + case 64: + widthbits = 3; + break; + default: + panic("nile4_set_pdar: unsupported width %d", width); + } + + return maskbits | (on_memory_bus ? 0x10 : 0) | + (pci_visible ? 0x20 : 0) | (widthbits << 6) | + (phys & 0xffe00000); +} + +void +ddb_set_pdar(u32 pdar, u32 phys, u32 size, int width, + int on_memory_bus, int pci_visible) +{ + u32 temp= ddb_calc_pdar(phys, size, width, on_memory_bus, pci_visible); + ddb_out32(pdar, temp); + ddb_out32(pdar + 4, 0); + + /* + * When programming a PDAR, the register should be read immediately + * after writing it. This ensures that address decoders are properly + * configured. + * [jsun] is this really necessary? + */ + ddb_in32(pdar); + ddb_in32(pdar + 4); +} + +/* + * routines that mess with PCIINITx registers + */ + +void ddb_set_pmr(u32 pmr, u32 type, u32 addr, u32 options) +{ + switch (type) { + case DDB_PCICMD_IACK: /* PCI Interrupt Acknowledge */ + case DDB_PCICMD_IO: /* PCI I/O Space */ + case DDB_PCICMD_MEM: /* PCI Memory Space */ + case DDB_PCICMD_CFG: /* PCI Configuration Space */ + break; + default: + panic("nile4_set_pmr: invalid type %d", type); + } + ddb_out32(pmr, (type << 1) | (addr & 0xffe00000) | options ); + ddb_out32(pmr + 4, 0); +} diff --git a/arch/mips/ddb5xxx/common/prom.c b/arch/mips/ddb5xxx/common/prom.c new file mode 100644 index 00000000000..b8d1f7489f3 --- /dev/null +++ b/arch/mips/ddb5xxx/common/prom.c @@ -0,0 +1,142 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/bootmem.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <asm/ddb5xxx/ddb5xxx.h> +#include <asm/debug.h> + +const char *get_system_type(void) +{ + switch (mips_machtype) { + case MACH_NEC_DDB5074: return "NEC DDB Vrc-5074"; + case MACH_NEC_DDB5476: return "NEC DDB Vrc-5476"; + case MACH_NEC_DDB5477: return "NEC DDB Vrc-5477"; + case MACH_NEC_ROCKHOPPER: return "NEC Rockhopper"; + case MACH_NEC_ROCKHOPPERII: return "NEC RockhopperII"; + default: return "Unknown NEC board"; + } +} + +#if defined(CONFIG_DDB5477) +void ddb5477_runtime_detection(void); +#endif + +/* [jsun@junsun.net] PMON passes arguments in C main() style */ +void __init prom_init(void) +{ + int argc = fw_arg0; + char **arg = (char**) fw_arg1; + int i; + + /* if user passes kernel args, ignore the default one */ + if (argc > 1) + arcs_cmdline[0] = '\0'; + + /* arg[0] is "g", the rest is boot parameters */ + for (i = 1; i < argc; i++) { + if (strlen(arcs_cmdline) + strlen(arg[i] + 1) + >= sizeof(arcs_cmdline)) + break; + strcat(arcs_cmdline, arg[i]); + strcat(arcs_cmdline, " "); + } + + mips_machgroup = MACH_GROUP_NEC_DDB; + +#if defined(CONFIG_DDB5074) + mips_machtype = MACH_NEC_DDB5074; + add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM); +#elif defined(CONFIG_DDB5476) + mips_machtype = MACH_NEC_DDB5476; + add_memory_region(0, DDB_SDRAM_SIZE, BOOT_MEM_RAM); +#elif defined(CONFIG_DDB5477) + ddb5477_runtime_detection(); + add_memory_region(0, board_ram_size, BOOT_MEM_RAM); +#endif +} + +unsigned long __init prom_free_prom_memory(void) +{ + return 0; +} + +#if defined(CONFIG_DDB5477) + +#define DEFAULT_LCS1_BASE 0x19000000 +#define TESTVAL1 'K' +#define TESTVAL2 'S' + +int board_ram_size; +void ddb5477_runtime_detection(void) +{ + volatile char *test_offset; + char saved_test_byte; + + /* Determine if this is a DDB5477 board, or a BSB-VR0300 + base board. We can tell by checking for the location of + the NVRAM. It lives at the beginning of LCS1 on the DDB5477, + and the beginning of LCS1 on the BSB-VR0300 is flash memory. + The first 2K of the NVRAM are reserved, so don't we'll poke + around just after that. + */ + + /* We can only use the PCI bus to distinquish between + the Rockhopper and RockhopperII backplanes and this must + wait until ddb5477_board_init() in setup.c after the 5477 + is initialized. So, until then handle + both Rockhopper and RockhopperII backplanes as Rockhopper 1 + */ + + test_offset = (char *)KSEG1ADDR(DEFAULT_LCS1_BASE + 0x800); + saved_test_byte = *test_offset; + + *test_offset = TESTVAL1; + if (*test_offset != TESTVAL1) { + /* We couldn't set our test value, so it must not be NVRAM, + so it's a BSB_VR0300 */ + mips_machtype = MACH_NEC_ROCKHOPPER; + } else { + /* We may have gotten lucky, and the TESTVAL1 was already + stored at the test location, so we must check a second + test value */ + *test_offset = TESTVAL2; + if (*test_offset != TESTVAL2) { + /* OK, we couldn't set this value either, so it must + definately be a BSB_VR0300 */ + mips_machtype = MACH_NEC_ROCKHOPPER; + } else { + /* We could change the value twice, so it must be + NVRAM, so it's a DDB_VRC5477 */ + mips_machtype = MACH_NEC_DDB5477; + } + } + /* Restore the original byte */ + *test_offset = saved_test_byte; + + /* before we know a better way, we will trust PMON for getting + * RAM size + */ + board_ram_size = 1 << (36 - (ddb_in32(DDB_SDRAM0) & 0xf)); + + db_run(printk("DDB run-time detection : %s, %d MB RAM\n", + mips_machtype == MACH_NEC_DDB5477 ? + "DDB5477" : "Rockhopper", + board_ram_size >> 20)); + + /* we can't handle ram size > 128 MB */ + db_assert(board_ram_size <= (128 << 20)); +} +#endif diff --git a/arch/mips/ddb5xxx/common/rtc_ds1386.c b/arch/mips/ddb5xxx/common/rtc_ds1386.c new file mode 100644 index 00000000000..f5b11508ff2 --- /dev/null +++ b/arch/mips/ddb5xxx/common/rtc_ds1386.c @@ -0,0 +1,164 @@ +/* + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + * arch/mips/ddb5xxx/common/rtc_ds1386.c + * low-level RTC hookups for s for Dallas 1396 chip. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + + +/* + * This file exports a function, rtc_ds1386_init(), which expects an + * uncached base address as the argument. It will set the two function + * pointers expected by the MIPS generic timer code. + */ + +#include <linux/types.h> +#include <linux/time.h> +#include <linux/bcd.h> + +#include <asm/time.h> +#include <asm/addrspace.h> + +#include <asm/mc146818rtc.h> +#include <asm/debug.h> + +#define EPOCH 2000 + +#define READ_RTC(x) *(volatile unsigned char*)(rtc_base+x) +#define WRITE_RTC(x, y) *(volatile unsigned char*)(rtc_base+x) = y + +static unsigned long rtc_base; + +static unsigned long +rtc_ds1386_get_time(void) +{ + u8 byte; + u8 temp; + unsigned int year, month, day, hour, minute, second; + + /* let us freeze external registers */ + byte = READ_RTC(0xB); + byte &= 0x3f; + WRITE_RTC(0xB, byte); + + /* read time data */ + year = BCD2BIN(READ_RTC(0xA)) + EPOCH; + month = BCD2BIN(READ_RTC(0x9) & 0x1f); + day = BCD2BIN(READ_RTC(0x8)); + minute = BCD2BIN(READ_RTC(0x2)); + second = BCD2BIN(READ_RTC(0x1)); + + /* hour is special - deal with it later */ + temp = READ_RTC(0x4); + + /* enable time transfer */ + byte |= 0x80; + WRITE_RTC(0xB, byte); + + /* calc hour */ + if (temp & 0x40) { + /* 12 hour format */ + hour = BCD2BIN(temp & 0x1f); + if (temp & 0x20) hour += 12; /* PM */ + } else { + /* 24 hour format */ + hour = BCD2BIN(temp & 0x3f); + } + + return mktime(year, month, day, hour, minute, second); +} + +static int +rtc_ds1386_set_time(unsigned long t) +{ + struct rtc_time tm; + u8 byte; + u8 temp; + u8 year, month, day, hour, minute, second; + + /* let us freeze external registers */ + byte = READ_RTC(0xB); + byte &= 0x3f; + WRITE_RTC(0xB, byte); + + /* convert */ + to_tm(t, &tm); + + + /* check each field one by one */ + year = BIN2BCD(tm.tm_year - EPOCH); + if (year != READ_RTC(0xA)) { + WRITE_RTC(0xA, year); + } + + temp = READ_RTC(0x9); + month = BIN2BCD(tm.tm_mon+1); /* tm_mon starts from 0 to 11 */ + if (month != (temp & 0x1f)) { + WRITE_RTC( 0x9, + (month & 0x1f) | (temp & ~0x1f) ); + } + + day = BIN2BCD(tm.tm_mday); + if (day != READ_RTC(0x8)) { + WRITE_RTC(0x8, day); + } + + temp = READ_RTC(0x4); + if (temp & 0x40) { + /* 12 hour format */ + hour = 0x40; + if (tm.tm_hour > 12) { + hour |= 0x20 | (BIN2BCD(hour-12) & 0x1f); + } else { + hour |= BIN2BCD(tm.tm_hour); + } + } else { + /* 24 hour format */ + hour = BIN2BCD(tm.tm_hour) & 0x3f; + } + if (hour != temp) WRITE_RTC(0x4, hour); + + minute = BIN2BCD(tm.tm_min); + if (minute != READ_RTC(0x2)) { + WRITE_RTC(0x2, minute); + } + + second = BIN2BCD(tm.tm_sec); + if (second != READ_RTC(0x1)) { + WRITE_RTC(0x1, second); + } + + return 0; +} + +void +rtc_ds1386_init(unsigned long base) +{ + unsigned char byte; + + /* remember the base */ + rtc_base = base; + db_assert((rtc_base & 0xe0000000) == KSEG1); + + /* turn on RTC if it is not on */ + byte = READ_RTC(0x9); + if (byte & 0x80) { + byte &= 0x7f; + WRITE_RTC(0x9, byte); + } + + /* enable time transfer */ + byte = READ_RTC(0xB); + byte |= 0x80; + WRITE_RTC(0xB, byte); + + /* set the function pointers */ + rtc_get_time = rtc_ds1386_get_time; + rtc_set_time = rtc_ds1386_set_time; +} diff --git a/arch/mips/ddb5xxx/ddb5074/Makefile b/arch/mips/ddb5xxx/ddb5074/Makefile new file mode 100644 index 00000000000..488206b8d94 --- /dev/null +++ b/arch/mips/ddb5xxx/ddb5074/Makefile @@ -0,0 +1,8 @@ +# +# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines +# under Linux. +# + +obj-y += setup.o irq.o int-handler.o nile4_pic.o + +EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/ddb5xxx/ddb5074/int-handler.S b/arch/mips/ddb5xxx/ddb5074/int-handler.S new file mode 100644 index 00000000000..a78644150b3 --- /dev/null +++ b/arch/mips/ddb5xxx/ddb5074/int-handler.S @@ -0,0 +1,120 @@ +/* + * arch/mips/ddb5074/int-handler.S -- NEC DDB Vrc-5074 interrupt handler + * + * Based on arch/mips/sgi/kernel/indyIRQ.S + * + * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <asm/asm.h> +#include <asm/mipsregs.h> +#include <asm/regdef.h> +#include <asm/stackframe.h> + +/* A lot of complication here is taken away because: + * + * 1) We handle one interrupt and return, sitting in a loop and moving across + * all the pending IRQ bits in the cause register is _NOT_ the answer, the + * common case is one pending IRQ so optimize in that direction. + * + * 2) We need not check against bits in the status register IRQ mask, that + * would make this routine slow as hell. + * + * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in + * between like BSD spl() brain-damage. + * + * Furthermore, the IRQs on the INDY look basically (barring software IRQs + * which we don't use at all) like: + * + * MIPS IRQ Source + * -------- ------ + * 0 Software (ignored) + * 1 Software (ignored) + * 2 Local IRQ level zero + * 3 Local IRQ level one + * 4 8254 Timer zero + * 5 8254 Timer one + * 6 Bus Error + * 7 R4k timer (what we use) + * + * We handle the IRQ according to _our_ priority which is: + * + * Highest ---- R4k Timer + * Local IRQ zero + * Local IRQ one + * Bus Error + * 8254 Timer zero + * Lowest ---- 8254 Timer one + * + * then we just return, if multiple IRQs are pending then we will just take + * another exception, big deal. + */ + + .text + .set noreorder + .set noat + .align 5 + NESTED(ddbIRQ, PT_SIZE, sp) + SAVE_ALL + CLI + .set at + mfc0 s0, CP0_CAUSE # get irq mask + +#if 1 + mfc0 t2,CP0_STATUS # get enabled interrupts + and s0,t2 # isolate allowed ones +#endif + /* First we check for r4k counter/timer IRQ. */ + andi a0, s0, CAUSEF_IP2 # delay slot, check local level zero + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP3 # delay slot, check local level one + + /* Wheee, local level zero interrupt. */ + jal ddb_local0_irqdispatch + move a0, sp # delay slot + + j ret_from_irq + nop # delay slot + +1: + beq a0, zero, 1f + andi a0, s0, CAUSEF_IP6 # delay slot, check bus error + + /* Wheee, local level one interrupt. */ + move a0, sp + jal ddb_local1_irqdispatch + nop + + j ret_from_irq + nop + +1: + beq a0, zero, 1f + nop + + /* Wheee, an asynchronous bus error... */ + move a0, sp + jal ddb_buserror_irq + nop + + j ret_from_irq + nop + +1: + /* Here by mistake? This is possible, what can happen + * is that by the time we take the exception the IRQ + * pin goes low, so just leave if this is the case. + */ + andi a0, s0, (CAUSEF_IP4 | CAUSEF_IP5) + beq a0, zero, 1f + + /* Must be one of the 8254 timers... */ + move a0, sp + jal ddb_8254timer_irq + nop +1: + j ret_from_irq + nop + END(ddbIRQ) diff --git a/arch/mips/ddb5xxx/ddb5074/irq.c b/arch/mips/ddb5xxx/ddb5074/irq.c new file mode 100644 index 00000000000..45088a1be41 --- /dev/null +++ b/arch/mips/ddb5xxx/ddb5074/irq.c @@ -0,0 +1,159 @@ +/* + * arch/mips/ddb5074/irq.c -- NEC DDB Vrc-5074 interrupt routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + */ +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> + +#include <asm/i8259.h> +#include <asm/io.h> +#include <asm/irq_cpu.h> +#include <asm/ptrace.h> +#include <asm/nile4.h> +#include <asm/ddb5xxx/ddb5xxx.h> +#include <asm/ddb5xxx/ddb5074.h> + + +extern asmlinkage void ddbIRQ(void); + +static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL }; + +#define M1543_PNP_CONFIG 0x03f0 /* PnP Config Port */ +#define M1543_PNP_INDEX 0x03f0 /* PnP Index Port */ +#define M1543_PNP_DATA 0x03f1 /* PnP Data Port */ + +#define M1543_PNP_ALT_CONFIG 0x0370 /* Alternative PnP Config Port */ +#define M1543_PNP_ALT_INDEX 0x0370 /* Alternative PnP Index Port */ +#define M1543_PNP_ALT_DATA 0x0371 /* Alternative PnP Data Port */ + +#define M1543_INT1_MASTER_CTRL 0x0020 /* INT_1 (master) Control Register */ +#define M1543_INT1_MASTER_MASK 0x0021 /* INT_1 (master) Mask Register */ + +#define M1543_INT1_SLAVE_CTRL 0x00a0 /* INT_1 (slave) Control Register */ +#define M1543_INT1_SLAVE_MASK 0x00a1 /* INT_1 (slave) Mask Register */ + +#define M1543_INT1_MASTER_ELCR 0x04d0 /* INT_1 (master) Edge/Level Control */ +#define M1543_INT1_SLAVE_ELCR 0x04d1 /* INT_1 (slave) Edge/Level Control */ + + +static void m1543_irq_setup(void) +{ + /* + * The ALI M1543 has 13 interrupt inputs, IRQ1..IRQ13. Not all + * the possible IO sources in the M1543 are in use by us. We will + * use the following mapping: + * + * IRQ1 - keyboard (default set by M1543) + * IRQ3 - reserved for UART B (default set by M1543) (note that + * the schematics for the DDB Vrc-5074 board seem to + * indicate that IRQ3 is connected to the DS1386 + * watchdog timer interrupt output so we might have + * a conflict) + * IRQ4 - reserved for UART A (default set by M1543) + * IRQ5 - parallel (default set by M1543) + * IRQ8 - DS1386 time of day (RTC) interrupt + * IRQ12 - mouse + */ + + /* + * Assing mouse interrupt to IRQ12 + */ + + /* Enter configuration mode */ + outb(0x51, M1543_PNP_CONFIG); + outb(0x23, M1543_PNP_CONFIG); + + /* Select logical device 7 (Keyboard) */ + outb(0x07, M1543_PNP_INDEX); + outb(0x07, M1543_PNP_DATA); + + /* Select IRQ12 */ + outb(0x72, M1543_PNP_INDEX); + outb(0x0c, M1543_PNP_DATA); + + outb(0x30, M1543_PNP_INDEX); + printk("device 7, 0x30: %02x\n",inb(M1543_PNP_DATA)); + + outb(0x70, M1543_PNP_INDEX); + printk("device 7, 0x70: %02x\n",inb(M1543_PNP_DATA)); + + /* Leave configration mode */ + outb(0xbb, M1543_PNP_CONFIG); + + +} + +void ddb_local0_irqdispatch(struct pt_regs *regs) +{ + u32 mask; + int nile4_irq; + + mask = nile4_get_irq_stat(0); + + /* Handle the timer interrupt first */ +#if 0 + if (mask & (1 << NILE4_INT_GPT)) { + do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs); + mask &= ~(1 << NILE4_INT_GPT); + } +#endif + for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) + if (mask & 1) { + if (nile4_irq == NILE4_INT_INTE) { + int i8259_irq; + + nile4_clear_irq(NILE4_INT_INTE); + i8259_irq = nile4_i8259_iack(); + do_IRQ(i8259_irq, regs); + } else + do_IRQ(nile4_to_irq(nile4_irq), regs); + + } +} + +void ddb_local1_irqdispatch(void) +{ + printk("ddb_local1_irqdispatch called\n"); +} + +void ddb_buserror_irq(void) +{ + printk("ddb_buserror_irq called\n"); +} + +void ddb_8254timer_irq(void) +{ + printk("ddb_8254timer_irq called\n"); +} + +void __init arch_init_irq(void) +{ + /* setup cascade interrupts */ + setup_irq(NILE4_IRQ_BASE + NILE4_INT_INTE, &irq_cascade); + setup_irq(CPU_IRQ_BASE + CPU_NILE4_CASCADE, &irq_cascade); + + set_except_vector(0, ddbIRQ); + + nile4_irq_setup(NILE4_IRQ_BASE); + m1543_irq_setup(); + init_i8259_irqs(); + + + printk("CPU_IRQ_BASE: %d\n",CPU_IRQ_BASE); + + mips_cpu_irq_init(CPU_IRQ_BASE); + + printk("enabling 8259 cascade\n"); + + ddb5074_led_hex(0); + + /* Enable the interrupt cascade */ + nile4_enable_irq(NILE4_IRQ_BASE+IRQ_I8259_CASCADE); +} diff --git a/arch/mips/ddb5xxx/ddb5074/nile4_pic.c b/arch/mips/ddb5xxx/ddb5074/nile4_pic.c new file mode 100644 index 00000000000..68c127cd70c --- /dev/null +++ b/arch/mips/ddb5xxx/ddb5074/nile4_pic.c @@ -0,0 +1,287 @@ +/* + * arch/mips/ddb5476/nile4.c -- + * low-level PIC code for NEC Vrc-5476 (Nile 4) + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + * + * Copyright 2001 MontaVista Software Inc. + * Author: jsun@mvista.com or jsun@junsun.net + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> + +#include <asm/addrspace.h> + +#include <asm/ddb5xxx/ddb5xxx.h> + +static int irq_base; + +/* + * Interrupt Programming + */ +void nile4_map_irq(int nile4_irq, int cpu_irq) +{ + u32 offset, t; + + offset = DDB_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = ddb_in32(offset); + t &= ~(7 << (nile4_irq * 4)); + t |= cpu_irq << (nile4_irq * 4); + ddb_out32(offset, t); +} + +void nile4_map_irq_all(int cpu_irq) +{ + u32 all, t; + + all = cpu_irq; + all |= all << 4; + all |= all << 8; + all |= all << 16; + t = ddb_in32(DDB_INTCTRL); + t &= 0x88888888; + t |= all; + ddb_out32(DDB_INTCTRL, t); + t = ddb_in32(DDB_INTCTRL + 4); + t &= 0x88888888; + t |= all; + ddb_out32(DDB_INTCTRL + 4, t); +} + +void nile4_enable_irq(unsigned int nile4_irq) +{ + u32 offset, t; + + nile4_irq-=irq_base; + + ddb5074_led_hex(8); + + offset = DDB_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + ddb5074_led_hex(9); + t = ddb_in32(offset); + ddb5074_led_hex(0xa); + t |= 8 << (nile4_irq * 4); + ddb_out32(offset, t); + ddb5074_led_hex(0xb); +} + +void nile4_disable_irq(unsigned int nile4_irq) +{ + u32 offset, t; + + nile4_irq-=irq_base; + + offset = DDB_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = ddb_in32(offset); + t &= ~(8 << (nile4_irq * 4)); + ddb_out32(offset, t); +} + +void nile4_disable_irq_all(void) +{ + ddb_out32(DDB_INTCTRL, 0); + ddb_out32(DDB_INTCTRL + 4, 0); +} + +u16 nile4_get_irq_stat(int cpu_irq) +{ + return ddb_in16(DDB_INTSTAT0 + cpu_irq * 2); +} + +void nile4_enable_irq_output(int cpu_irq) +{ + u32 t; + + t = ddb_in32(DDB_INTSTAT1 + 4); + t |= 1 << (16 + cpu_irq); + ddb_out32(DDB_INTSTAT1, t); +} + +void nile4_disable_irq_output(int cpu_irq) +{ + u32 t; + + t = ddb_in32(DDB_INTSTAT1 + 4); + t &= ~(1 << (16 + cpu_irq)); + ddb_out32(DDB_INTSTAT1, t); +} + +void nile4_set_pci_irq_polarity(int pci_irq, int high) +{ + u32 t; + + t = ddb_in32(DDB_INTPPES); + if (high) + t &= ~(1 << (pci_irq * 2)); + else + t |= 1 << (pci_irq * 2); + ddb_out32(DDB_INTPPES, t); +} + +void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) +{ + u32 t; + + t = ddb_in32(DDB_INTPPES); + if (level) + t |= 2 << (pci_irq * 2); + else + t &= ~(2 << (pci_irq * 2)); + ddb_out32(DDB_INTPPES, t); +} + +void nile4_clear_irq(int nile4_irq) +{ + nile4_irq-=irq_base; + ddb_out32(DDB_INTCLR, 1 << nile4_irq); +} + +void nile4_clear_irq_mask(u32 mask) +{ + ddb_out32(DDB_INTCLR, mask); +} + +u8 nile4_i8259_iack(void) +{ + u8 irq; + u32 reg; + + /* Set window 0 for interrupt acknowledge */ + reg = ddb_in32(DDB_PCIINIT0); + + ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IACK, 0, DDB_PCI_ACCESS_32); + irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE); + /* restore window 0 for PCI I/O space */ + // ddb_set_pmr(DDB_PCIINIT0, DDB_PCICMD_IO, 0, DDB_PCI_ACCESS_32); + ddb_out32(DDB_PCIINIT0, reg); + + /* i8269.c set the base vector to be 0x0 */ + return irq ; +} + +static unsigned int nile4_irq_startup(unsigned int irq) { + + nile4_enable_irq(irq); + return 0; + +} + +static void nile4_ack_irq(unsigned int irq) { + + ddb5074_led_hex(4); + + nile4_clear_irq(irq); + ddb5074_led_hex(2); + nile4_disable_irq(irq); + + ddb5074_led_hex(0); +} + +static void nile4_irq_end(unsigned int irq) { + + ddb5074_led_hex(3); + if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + ddb5074_led_hex(5); + nile4_enable_irq(irq); + ddb5074_led_hex(7); + } + + ddb5074_led_hex(1); +} + +#define nile4_irq_shutdown nile4_disable_irq + |