diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-10-12 03:19:41 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-10-12 03:19:41 +0000 |
commit | c4a2a91dd053af588f69a4da0f9408da334869f7 (patch) | |
tree | 6d92a7c9bd79249450d74020d6480d1e5d902e30 /arch/mips | |
parent | 73c5574a141032a6d588b0e25be6d76bbf7b991d (diff) |
DDB5476 support from Jun Sun.
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/Makefile | 13 | ||||
-rw-r--r-- | arch/mips/config.in | 7 | ||||
-rw-r--r-- | arch/mips/ddb5476/Makefile | 26 | ||||
-rw-r--r-- | arch/mips/ddb5476/dbg_io.c | 127 | ||||
-rw-r--r-- | arch/mips/ddb5476/int-handler.S | 128 | ||||
-rw-r--r-- | arch/mips/ddb5476/irq.c | 252 | ||||
-rw-r--r-- | arch/mips/ddb5476/nile4.c | 294 | ||||
-rw-r--r-- | arch/mips/ddb5476/pci-dma.c | 48 | ||||
-rw-r--r-- | arch/mips/ddb5476/pci.c | 454 | ||||
-rw-r--r-- | arch/mips/ddb5476/prom.c | 66 | ||||
-rw-r--r-- | arch/mips/ddb5476/setup.c | 396 | ||||
-rw-r--r-- | arch/mips/ddb5476/time.c | 35 | ||||
-rw-r--r-- | arch/mips/kernel/irq.c | 2 | ||||
-rw-r--r-- | arch/mips/kernel/setup.c | 8 | ||||
-rw-r--r-- | arch/mips/kernel/time.c | 1 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 1 | ||||
-rw-r--r-- | arch/mips/mm/Makefile | 4 | ||||
-rw-r--r-- | arch/mips/mm/loadmmu.c | 4 |
18 files changed, 1862 insertions, 4 deletions
diff --git a/arch/mips/Makefile b/arch/mips/Makefile index 14801d3cb..92c6d81f7 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -61,6 +61,9 @@ endif ifdef CONFIG_CPU_R5000 GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap endif +ifdef CONFIG_CPU_R5432 +GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap +endif ifdef CONFIG_CPU_NEVADA GCCFLAGS += -mcpu=r8000 -mips2 -Wa,--trap -mmad endif @@ -167,6 +170,16 @@ LOADADDR += 0x80080000 endif # +# +# NEC DDB Vrc-5476 +# +ifdef CONFIG_DDB5476 +SUBDIRS += arch/mips/ddb5476 +LIBS += arch/mips/ddb5476/ddb5476.a +LOADADDR += 0x80080000 +endif + +# # Orion Board # ifdef CONFIG_ORION diff --git a/arch/mips/config.in b/arch/mips/config.in index a790a3b52..d8b6d8ab9 100644 --- a/arch/mips/config.in +++ b/arch/mips/config.in @@ -21,6 +21,7 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then fi bool 'Support for DECstations (EXPERIMENTAL)' CONFIG_DECSTATION bool 'Support for NEC DDB Vrc-5074 (EXPERIMENTAL)' CONFIG_DDB5074 + bool 'Support for NEC DDB Vrc-5476 (EXPERIMENTAL)' CONFIG_DDB5476 bool 'Support for Galileo Evaluation board or CoSine Orion' CONFIG_ORION bool 'Support for MIPS Atlas board' CONFIG_MIPS_ATLAS bool 'Support for MIPS Malta board' CONFIG_MIPS_MALTA @@ -94,10 +95,11 @@ if [ "$CONFIG_SNI_RM200_PCI" = "y" ]; then define_bool CONFIG_PC_KEYB y define_bool CONFIG_PCI y fi -if [ "$CONFIG_DDB5074" = "y" ]; then +if [ "$CONFIG_DDB5074" = "y" -o "$CONFIG_DDB5476" = "y" ]; then define_bool CONFIG_I8259 y define_bool CONFIG_ISA y define_bool CONFIG_PCI y + define_bool CONFIG_PC_KEYB y fi if [ "$CONFIG_ISA" != "y" ]; then @@ -131,6 +133,7 @@ choice 'CPU type' \ R4300 CONFIG_CPU_R4300 \ R4x00 CONFIG_CPU_R4X00 \ R5000 CONFIG_CPU_R5000 \ + R5432 CONFIG_CPU_R5432 \ RM7000 CONFIG_CPU_RM7000 \ R56x0 CONFIG_CPU_NEVADA \ R8000 CONFIG_CPU_R8000 \ @@ -159,7 +162,7 @@ endmenu mainmenu_option next_comment comment 'General setup' -if [ "$CONFIG_DECSTATION" = "y" -o "$CONFIG_DDB5074" = "y" ]; then +if [ "$CONFIG_DECSTATION" = "y" -o "$CONFIG_DDB5074" = "y" -o "$CONFIG_DDB5476" = "y" ]; then define_bool CONFIG_CPU_LITTLE_ENDIAN y else bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN diff --git a/arch/mips/ddb5476/Makefile b/arch/mips/ddb5476/Makefile new file mode 100644 index 000000000..df398b0c1 --- /dev/null +++ b/arch/mips/ddb5476/Makefile @@ -0,0 +1,26 @@ +# +# Makefile for the NEC DDB Vrc-5074 specific kernel interface routines +# under Linux. +# +# 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). +# +# Note 2! The CFLAGS definitions are now in the main makefile... +# +# $Id$ +# + +.S.s: + $(CPP) $(CFLAGS) $< -o $*.s +.S.o: + $(CC) $(CFLAGS) -c $< -o $*.o + +O_TARGET = ddb5476.a +O_OBJS = setup.o irq.o time.o prom.o pci.o pci-dma.o int-handler.o nile4.o + +ifdef CONFIG_REMOTE_DEBUG +O_OBJS += dbg_io.o +endif + +include $(TOPDIR)/Rules.make diff --git a/arch/mips/ddb5476/dbg_io.c b/arch/mips/ddb5476/dbg_io.c new file mode 100644 index 000000000..121850a62 --- /dev/null +++ b/arch/mips/ddb5476/dbg_io.c @@ -0,0 +1,127 @@ + +#include <linux/config.h> + +#if (defined(CONFIG_DDB5476) && defined(CONFIG_REMOTE_DEBUG)) + +/* --- CONFIG --- */ + +/* we need uint32 uint8 */ +/* #include "types.h" */ +typedef unsigned char uint8; +typedef unsigned int uint32; + +/* --- END OF CONFIG --- */ + +#define UART16550_BAUD_2400 2400 +#define UART16550_BAUD_4800 4800 +#define UART16550_BAUD_9600 9600 +#define UART16550_BAUD_19200 19200 +#define UART16550_BAUD_38400 38400 +#define UART16550_BAUD_57600 57600 +#define UART16550_BAUD_115200 115200 + +#define UART16550_PARITY_NONE 0 +#define UART16550_PARITY_ODD 0x08 +#define UART16550_PARITY_EVEN 0x18 +#define UART16550_PARITY_MARK 0x28 +#define UART16550_PARITY_SPACE 0x38 + +#define UART16550_DATA_5BIT 0x0 +#define UART16550_DATA_6BIT 0x1 +#define UART16550_DATA_7BIT 0x2 +#define UART16550_DATA_8BIT 0x3 + +#define UART16550_STOP_1BIT 0x0 +#define UART16550_STOP_2BIT 0x4 + +/* ----------------------------------------------------- */ + +/* === CONFIG === */ + +/* [jsun] we use the second serial port for kdb */ +#define BASE 0xa60002f8 +#define MAX_BAUD 115200 + +/* === END OF CONFIG === */ + +/* register offset */ +#define OFS_RCV_BUFFER 0 +#define OFS_TRANS_HOLD 0 +#define OFS_SEND_BUFFER 0 +#define OFS_INTR_ENABLE 1 +#define OFS_INTR_ID 2 +#define OFS_DATA_FORMAT 3 +#define OFS_LINE_CONTROL 3 +#define OFS_MODEM_CONTROL 4 +#define OFS_RS232_OUTPUT 4 +#define OFS_LINE_STATUS 5 +#define OFS_MODEM_STATUS 6 +#define OFS_RS232_INPUT 6 +#define OFS_SCRATCH_PAD 7 + +#define OFS_DIVISOR_LSB 0 +#define OFS_DIVISOR_MSB 1 + + +/* memory-mapped read/write of the port */ +#define UART16550_READ(y) (*((volatile uint8*)(BASE + y))) +#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z) + +void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop) +{ + /* disable interrupts */ + UART16550_WRITE(OFS_INTR_ENABLE, 0); + + /* set up buad rate */ + { + uint32 divisor; + + /* set DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x80); + + /* set divisor */ + divisor = MAX_BAUD / baud; + UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff); + UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00)>>8); + + /* clear DIAB bit */ + UART16550_WRITE(OFS_LINE_CONTROL, 0x0); + } + + /* set data format */ + UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop); +} + +static int remoteDebugInitialized = 0; + +uint8 getDebugChar(void) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_38400, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, + UART16550_STOP_1BIT); + } + + while((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0); + return UART16550_READ(OFS_RCV_BUFFER); +} + + +int putDebugChar(uint8 byte) +{ + if (!remoteDebugInitialized) { + remoteDebugInitialized = 1; + debugInit(UART16550_BAUD_9600, + UART16550_DATA_8BIT, + UART16550_PARITY_NONE, + UART16550_STOP_1BIT); + } + + while ((UART16550_READ(OFS_LINE_STATUS) &0x20) == 0); + UART16550_WRITE(OFS_SEND_BUFFER, byte); + return 1; +} + +#endif diff --git a/arch/mips/ddb5476/int-handler.S b/arch/mips/ddb5476/int-handler.S new file mode 100644 index 000000000..1032b82ca --- /dev/null +++ b/arch/mips/ddb5476/int-handler.S @@ -0,0 +1,128 @@ +/* + * 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 + * + * $Id: int-handler.S,v 1.1 2000/01/26 00:07:44 ralf Exp $ + */ + +#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 s1, CP0_CAUSE # get irq mask + +#if 1 + mfc0 t2,CP0_STATUS # get enabled interrupts + and s0, s1, 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: + /* phamtom interrupt */ + move a0, s1 + jal ddb_phantom_irq + nop + j ret_from_irq + nop + END(ddbIRQ) diff --git a/arch/mips/ddb5476/irq.c b/arch/mips/ddb5476/irq.c new file mode 100644 index 000000000..bfb2118c7 --- /dev/null +++ b/arch/mips/ddb5476/irq.c @@ -0,0 +1,252 @@ +/* + * arch/mips/ddb5476/irq.c -- NEC DDB Vrc-5476 interrupt routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + * + * $Id: irq.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/ptrace.h> +#include <asm/nile4.h> + +extern void __init i8259_init(void); +extern void i8259_disable_irq(unsigned int irq_nr); +extern void i8259_enable_irq(unsigned int irq_nr); + +extern asmlinkage void ddbIRQ(void); +extern asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs); +extern asmlinkage void do_IRQ(int irq, struct pt_regs * regs); + + +void no_action(int cpl, void *dev_id, struct pt_regs *regs) +{ +} + + +#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 struct { + struct resource m1543_config; + struct resource pic_elcr; +} m1543_ioport = { + {"M1543 config", M1543_PNP_CONFIG, M1543_PNP_CONFIG+1, IORESOURCE_BUSY}, + {"pic ELCR", M1543_INT1_MASTER_ELCR, M1543_INT1_MASTER_ELCR+1, + IORESOURCE_BUSY} +}; + +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-5476 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 + * IRQ9 - USB (hardwired in ddb_setup) + * IRQ10 - PMU (hardwired in ddb_setup) + * IRQ12 - mouse + * IRQ14,15 - IDE controller (need to be confirmed, jsun) + */ + + /* + * 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); + + /* Leave configration mode */ + outb(0xbb, M1543_PNP_CONFIG); + + + /* Initialize the 8259 PIC in the M1543 */ + i8259_init(); + + /* Enable the interrupt cascade from M1543*/ + nile4_enable_irq(NILE4_INT_INTC); + + /* request io ports */ + if (request_resource(&ioport_resource, &m1543_ioport.m1543_config) || + request_resource(&ioport_resource, &m1543_ioport.pic_elcr) ) { + printk("m1543_irq_setup : requesting io ports failed.\n"); + for(;;); + } +} + +static void nile4_irq_setup(void) +{ + int i; + + /* Map all interrupts to CPU int #0 */ + nile4_map_irq_all(0); + + /* PCI INTA#-E# must be level triggered */ + nile4_set_pci_irq_level_or_edge(0, 1); + nile4_set_pci_irq_level_or_edge(1, 1); + nile4_set_pci_irq_level_or_edge(2, 1); + nile4_set_pci_irq_level_or_edge(3, 1); + + /* PCI INTA#, B#, D# must be active low, INTC# must be active high */ + nile4_set_pci_irq_polarity(0, 0); + nile4_set_pci_irq_polarity(1, 0); + nile4_set_pci_irq_polarity(2, 1); + nile4_set_pci_irq_polarity(3, 0); + + for (i = 0; i < 16; i++) + nile4_clear_irq(i); + + /* Enable CPU int #0 */ + nile4_enable_irq_output(0); + + /* memory resource acquire in ddb_setup */ +} + + +/* + * IRQ2 is cascade interrupt to second interrupt controller + */ + +static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL }; + + +void disable_irq(unsigned int irq_nr) +{ + if (is_i8259_irq(irq_nr)) + i8259_disable_irq(irq_nr); + else + nile4_disable_irq(irq_to_nile4(irq_nr)); +} + +void enable_irq(unsigned int irq_nr) +{ + if (is_i8259_irq(irq_nr)) + i8259_enable_irq(irq_nr); + else + nile4_enable_irq(irq_to_nile4(irq_nr)); +} + +int table[16] = { 0, }; + +void ddb_local0_irqdispatch(struct pt_regs *regs) +{ + u32 mask; + int nile4_irq; +#if 0 + volatile static int nesting = 0; + if (nesting++ == 0) + ddb5476_led_d3(1); + ddb5476_led_hex(nesting < 16 ? nesting : 15); +#endif + + mask = nile4_get_irq_stat(0); + nile4_clear_irq_mask(mask); + + /* Handle the timer interrupt first */ + if (mask & (1<<NILE4_INT_GPT)) { + nile4_disable_irq(NILE4_INT_GPT); + do_IRQ(nile4_to_irq(NILE4_INT_GPT), regs); + nile4_enable_irq(NILE4_INT_GPT); + mask &= ~(1<<NILE4_INT_GPT); + } + for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) + if (mask & 1) { + nile4_disable_irq(nile4_irq); + if (nile4_irq == NILE4_INT_INTC) { + int i8259_irq = nile4_i8259_iack(); + i8259_do_irq(i8259_irq, regs); + } else { + do_IRQ(nile4_to_irq(nile4_irq), regs); + } + nile4_enable_irq(nile4_irq); + } + +#if 0 + if (--nesting == 0) + ddb5476_led_d3(0); + ddb5476_led_hex(nesting < 16 ? nesting : 15); +#endif +} + +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 ddb_phantom_irq(unsigned long cause) +{ + printk("phantom interrupts detected : \n"); + printk("\tcause \t\t0x%08x\n", cause); + printk("\tcause reg\t0x%08x\n", read_32bit_cp0_register(CP0_CAUSE)); + printk("\tstatus reg\t0x%08x\n", read_32bit_cp0_register(CP0_STATUS)); +} + +void __init ddb_irq_setup(void) +{ +#ifdef CONFIG_REMOTE_DEBUG + printk("Wait for gdb client connection ...\n"); + set_debug_traps(); + breakpoint(); /* you may move this line to whereever you want :-) */ +#endif + i8259_setup_irq(2, &irq2); + + nile4_irq_setup(); + m1543_irq_setup(); + + /* we pin #0 - #4 (no internal timer) */ + set_cp0_status(ST0_IM, IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4); + + set_except_vector(0, ddbIRQ); +} + diff --git a/arch/mips/ddb5476/nile4.c b/arch/mips/ddb5476/nile4.c new file mode 100644 index 000000000..35793b605 --- /dev/null +++ b/arch/mips/ddb5476/nile4.c @@ -0,0 +1,294 @@ +/* + * arch/mips/ddb5074/nile4.c -- NEC Vrc-5074 Nile 4 support routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + * + * $Id$ + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <asm/nile4.h> + + + /* + * Physical Device Address Registers + * + * Note: 32 bit addressing only! + */ + +void nile4_set_pdar(u32 pdar, u32 phys, u32 size, int width, int on_memory_bus, + int visible) +{ + u32 maskbits; + u32 widthbits; + + if (pdar > NILE4_BOOTCS || (pdar & 7)) { + printk("nile4_set_pdar: invalid pdar %d\n", pdar); + return; + } + if (pdar == NILE4_INTCS && size != 0x00200000) { + printk("nile4_set_pdar: INTCS size must be 2 MB\n"); + return; + } + 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: + printk("nile4_set_pdar: unsupported size %p\n", (void *)size); + return; + } + switch (width) { + case 8: + widthbits = 0; + break; + case 16: + widthbits = 1; + break; + case 32: + widthbits = 2; + break; + case 64: + widthbits = 3; + break; + default: + printk("nile4_set_pdar: unsupported width %d\n", width); + return; + } + nile4_out32(pdar, maskbits | (on_memory_bus ? 0x10 : 0) | + (visible ? 0x20 : 0) | (widthbits << 6) | + (phys & 0xffe00000)); + nile4_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. + */ + (void)nile4_in32(pdar); + (void)nile4_in32(pdar+4); +} + + + /* + * PCI Master Registers + * + * Note: 32 bit addressing only! + */ + +void nile4_set_pmr(u32 pmr, u32 type, u32 addr) +{ + if (pmr != NILE4_PCIINIT0 && pmr != NILE4_PCIINIT1) { + printk("nile4_set_pmr: invalid pmr %d\n", pmr); + return; + } + switch (type) { + case NILE4_PCICMD_IACK: /* PCI Interrupt Acknowledge */ + case NILE4_PCICMD_IO: /* PCI I/O Space */ + case NILE4_PCICMD_MEM: /* PCI Memory Space */ + case NILE4_PCICMD_CFG: /* PCI Configuration Space */ + break; + default: + printk("nile4_set_pmr: invalid type %d\n", type); + return; + } + nile4_out32(pmr, (type << 1) | 0x10 | (addr & 0xffe00000)); + nile4_out32(pmr+4, 0); +} + + + /* + * Interrupt Programming + */ + +void nile4_map_irq(int nile4_irq, int cpu_irq) +{ + u32 offset, t; + + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(7 << (nile4_irq*4)); + t |= cpu_irq << (nile4_irq*4); + nile4_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 = nile4_in32(NILE4_INTCTRL); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL, t); + t = nile4_in32(NILE4_INTCTRL+4); + t &= 0x88888888; + t |= all; + nile4_out32(NILE4_INTCTRL+4, t); +} + +void nile4_enable_irq(int nile4_irq) +{ + u32 offset, t; + + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t |= 8 << (nile4_irq*4); + nile4_out32(offset, t); +} + +void nile4_disable_irq(int nile4_irq) +{ + u32 offset, t; + + offset = NILE4_INTCTRL; + if (nile4_irq >= 8) { + offset += 4; + nile4_irq -= 8; + } + t = nile4_in32(offset); + t &= ~(8 << (nile4_irq*4)); + nile4_out32(offset, t); +} + +void nile4_disable_irq_all(void) +{ + nile4_out32(NILE4_INTCTRL, 0); + nile4_out32(NILE4_INTCTRL+4, 0); +} + +u16 nile4_get_irq_stat(int cpu_irq) +{ + return nile4_in16(NILE4_INTSTAT0+cpu_irq*2); +} + +void nile4_enable_irq_output(int cpu_irq) +{ + u32 t; + + t = nile4_in32(NILE4_INTSTAT1+4); + t |= 1 << (16+cpu_irq); + nile4_out32(NILE4_INTSTAT1, t); +} + +void nile4_disable_irq_output(int cpu_irq) +{ + u32 t; + + t = nile4_in32(NILE4_INTSTAT1+4); + t &= ~(1 << (16+cpu_irq)); + nile4_out32(NILE4_INTSTAT1, t); +} + +void nile4_set_pci_irq_polarity(int pci_irq, int high) +{ + u32 t; + + t = nile4_in32(NILE4_INTPPES); + if (high) + t &= ~(1 << (pci_irq*2)); + else + t |= 1 << (pci_irq*2); + nile4_out32(NILE4_INTPPES, t); +} + +void nile4_set_pci_irq_level_or_edge(int pci_irq, int level) +{ + u32 t; + + t = nile4_in32(NILE4_INTPPES); + if (level) + t |= 2 << (pci_irq*2); + else + t &= ~(2 << (pci_irq*2)); + nile4_out32(NILE4_INTPPES, t); +} + +void nile4_clear_irq(int nile4_irq) +{ + nile4_out32(NILE4_INTCLR, 1 << nile4_irq); +} + +void nile4_clear_irq_mask(u32 mask) +{ + nile4_out32(NILE4_INTCLR, mask); +} + +u8 nile4_i8259_iack(void) +{ + u8 irq; + + /* Set window 0 for interrupt acknowledge */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IACK, 0); + irq = *(volatile u8 *)NILE4_PCI_IACK_BASE; + /* Set window 0 for PCI I/O space */ + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); + return irq; +} + +#if 0 +void nile4_dump_irq_status(void) +{ + printk("CPUSTAT = %p:%p\n", (void *)nile4_in32(NILE4_CPUSTAT+4), + (void *)nile4_in32(NILE4_CPUSTAT)); + printk("INTCTRL = %p:%p\n", (void *)nile4_in32(NILE4_INTCTRL+4), + (void *)nile4_in32(NILE4_INTCTRL)); + printk("INTSTAT0 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT0+4), + (void *)nile4_in32(NILE4_INTSTAT0)); + printk("INTSTAT1 = %p:%p\n", (void *)nile4_in32(NILE4_INTSTAT1+4), + (void *)nile4_in32(NILE4_INTSTAT1)); + printk("INTCLR = %p:%p\n", (void *)nile4_in32(NILE4_INTCLR+4), + (void *)nile4_in32(NILE4_INTCLR)); + printk("INTPPES = %p:%p\n", (void *)nile4_in32(NILE4_INTPPES+4), + (void *)nile4_in32(NILE4_INTPPES)); +} +#endif diff --git a/arch/mips/ddb5476/pci-dma.c b/arch/mips/ddb5476/pci-dma.c new file mode 100644 index 000000000..c0f35772c --- /dev/null +++ b/arch/mips/ddb5476/pci-dma.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Ani Joshi <ajoshi@unixbox.com> + * + * + * Dynamic DMA mapping support. + * + * swiped from i386, and cloned for MIPS by Geert. + * + */ + +#include <linux/types.h> +#include <linux/mm.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <asm/io.h> + +/* + * [jsun] We want to return non-cached area so that data can be consistent + * Apparently on x86, this is not an issue because cache is automatically + * invalidated. + * + * To make we are doing the right thing, I add some extra debug macros. + */ + +void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, + dma_addr_t *dma_handle) +{ + void *ret; + int gfp = GFP_ATOMIC; + + if (hwdev == NULL || hwdev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, get_order(size)); + + if (ret != NULL) { + dma_cache_inv((unsigned long)ret, size); + *dma_handle = virt_to_bus(ret); + } + ret = (void*) ((unsigned long)ret | 0x20000000); + return ret; +} + +void pci_free_consistent(struct pci_dev *hwdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + vaddr = (void*) ((unsigned long)vaddr & ~0x20000000); + free_pages((unsigned long)vaddr, get_order(size)); +} diff --git a/arch/mips/ddb5476/pci.c b/arch/mips/ddb5476/pci.c new file mode 100644 index 000000000..451a12027 --- /dev/null +++ b/arch/mips/ddb5476/pci.c @@ -0,0 +1,454 @@ +/* + * arch/mips/ddb5476/pci.c -- NEC DDB Vrc-5074 PCI access routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Albert Dorofeev <albert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + * + * $Id: pci.c,v 1.4 2000/02/18 00:02:17 ralf Exp $ + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <asm-mips/nile4.h> + + +static u32 nile4_pre_pci_access0(int slot_num) +{ + u32 pci_addr = 0; + u32 virt_addr = NILE4_PCI_CFG_BASE; + + /* work around the bug for Vrc5476 */ + if (slot_num == 13) return NILE4_BASE + NILE4_PCI_BASE; + + /* Set window 1 address 08000000 - 32 bit - 128 MB (PCI config space) */ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(virt_addr), 0x08000000, 32, 0, 0); + + // [jsun] we start scanning from addr:10, + // with 128M we can go up to addr:26 (slot 16) + if (slot_num <= 16) { + virt_addr += 0x00000400 << slot_num; + } else { + /* for high slot, we have to set higher PCI base addr */ + pci_addr = 0x00000400 << slot_num; + } + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, pci_addr); + return virt_addr; +} + +static void nile4_post_pci_access0(void) +{ + /* Set window 1 back to address 08000000 - 32 bit - 128 MB (PCI IO space)*/ + nile4_set_pdar(NILE4_PCIW1, PHYSADDR(NILE4_PCI_MEM_BASE), 0x08000000, 32, + 1, 1); + // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000); +} + + +static int nile4_pci_read_config_dword( struct pci_dev *dev, + int where, u32 *val) +{ + int slot_num, func_num; + u32 base; + u32 addr; + + /* + * Do we need to generate type 1 configure transaction? + */ + if (dev->bus->number) { + /* FIXME - not working yet */ + return PCIBIOS_FUNC_NOT_SUPPORTED; + + /* the largest type 1 configuration addr is 16M, < 256M config space */ + slot_num = 0; + addr = (dev->bus->number << 16) | (dev->devfn < 8) | where | 1; + } else { + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + addr = (func_num << 8) + where; + } + + base = nile4_pre_pci_access0(slot_num); + *val = *(volatile u32 *)(base + addr); + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_write_config_dword(struct pci_dev *dev, int where, + u32 val) +{ + int slot_num, func_num; + u32 base; + u32 addr; + + /* + * Do we need to generate type 1 configure transaction? + */ + if (dev->bus->number) { + /* FIXME - not working yet */ + return PCIBIOS_FUNC_NOT_SUPPORTED; + + /* the largest type 1 configuration addr is 16M, < 256M config space */ + slot_num = 0; + addr = (dev->bus->number << 16) | (dev->devfn < 8) | where | 1; + } else { + slot_num = PCI_SLOT(dev->devfn); + func_num = PCI_FUNC(dev->devfn); + addr = (func_num << 8) + where; + } + + base = nile4_pre_pci_access0(slot_num); + *(volatile u32 *)(base + addr) = val; + nile4_post_pci_access0(); + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_read_config_word(struct pci_dev *dev, int where, u16 *val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + result >>= 16; + *val = result & 0xffff; + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_read_config_byte(struct pci_dev *dev, int where, u8 *val) +{ + int status; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 1) + result >>= 8; + if (where & 2) + result >>= 16; + *val = result & 0xff; + return PCIBIOS_SUCCESSFUL; +} + +static int nile4_pci_write_config_word(struct pci_dev *dev, int where, u16 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + result &= ~(0xffff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where & ~3, result); +} + +static int nile4_pci_write_config_byte( struct pci_dev *dev, int where, u8 val) +{ + int status, shift = 0; + u32 result; + + status = nile4_pci_read_config_dword(dev, where & ~3, &result); + if (status != PCIBIOS_SUCCESSFUL) + return status; + if (where & 2) + shift += 16; + if (where & 1) + shift += 8; + result &= ~(0xff << shift); + result |= val << shift; + return nile4_pci_write_config_dword(dev, where & ~3, result); +} + +struct pci_ops nile4_pci_ops = { + nile4_pci_read_config_byte, + nile4_pci_read_config_word, + nile4_pci_read_config_dword, + nile4_pci_write_config_byte, + nile4_pci_write_config_word, + nile4_pci_write_config_dword +}; + +struct { + struct resource ram; + struct resource flash; + struct resource isa_io; + struct resource pci_io; + struct resource isa_mem; + struct resource pci_mem; + struct resource nile4; + struct resource boot; +} ddb5476_resources = { + // { "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, + { "RAM", 0x00000000, 0x03ffffff, IORESOURCE_MEM }, + { "Flash ROM", 0x04000000, 0x043fffff }, + { "Nile4 ISA I/O", 0x06000000, 0x060fffff }, + { "Nile4 PCI I/O", 0x06100000, 0x07ffffff }, + { "Nile4 ISA mem", 0x08000000, 0x08ffffff, IORESOURCE_MEM }, + { "Nile4 PCI mem", 0x09000000, 0x0fffffff, IORESOURCE_MEM }, + // { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM | PCI_BASE_ADDRESS_MEM_TYPE_64 }, + { "Nile4 ctrl", 0x1fa00000, 0x1fbfffff, IORESOURCE_MEM }, + { "Boot ROM", 0x1fc00000, 0x1fffffff } +}; + +struct resource M5229_resources[5] = { + { "M5229 BAR0", 0x1f0, 0x1f3, IORESOURCE_IO }, + { "M5229 BAR1", 0x3f4, 0x3f7, IORESOURCE_IO }, + { "M5229 BAR2", 0x170, 0x173, IORESOURCE_IO }, + { "M5229 BAR3", 0x374, 0x377, IORESOURCE_IO }, + { "M5229 BAR4", 0xf000, 0xf00f, IORESOURCE_IO } +}; + +static void __init ddb5476_pci_fixup(void) +{ + struct pci_dev *dev; + + pci_for_each_dev(dev) { + if (dev->vendor == PCI_VENDOR_ID_NEC && + dev->device == PCI_DEVICE_ID_NEC_VRC5476) { + /* + * The first 64-bit PCI base register should point to the Nile4 + * control registers. Unfortunately this isn't the case, so we fix + * it ourselves. This allows the serial driver to find the UART. + */ + dev->resource[0] = ddb5476_resources.nile4; + request_resource(&iomem_resource, &dev->resource[0]); + /* + * The second 64-bit PCI base register points to the first memory + * bank. Unfortunately the address is wrong, so we fix it (again). + */ + dev->resource[2] = ddb5476_resources.ram; + request_resource(&iomem_resource, &dev->resource[2]); + } else if (dev->vendor == PCI_VENDOR_ID_AL && + dev->device == PCI_DEVICE_ID_AL_M7101) { + /* + * It's nice to have the LEDs on the GPIO pins available for + * debugging + */ + extern struct pci_dev *pci_pmu; + u8 t8; + + pci_pmu = dev; /* for LEDs D2 and D3 */ + /* Program the lines for LEDs D2 and D3 to output */ + nile4_pci_read_config_byte(dev, 0x7d, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7d, t8); + /* Turn LEDs D2 and D3 off */ + nile4_pci_read_config_byte(dev, 0x7e, &t8); + t8 |= 0xc0; + nile4_pci_write_config_byte(dev, 0x7e, t8); + } else if (dev->vendor == PCI_VENDOR_ID_AL && + dev->device == 0x5229) { + int i; + for (i=0; i< 5; i++) { + dev->resource[i] = M5229_resources[i]; + request_resource(&ioport_resource, &dev->resource[i]); + } + } + } +} + +static void __init pcibios_fixup_irqs(void) +{ + struct pci_dev *dev; + int slot_num; + + pci_for_each_dev(dev) { + slot_num = PCI_SLOT(dev->devfn); + switch (slot_num) { + case 3: /* re-programmed to USB */ + dev->irq = 9; /* hard-coded; see irq.c */ + break; + case 4: /* re-programmed to PMU */ + dev->irq = 10; /* hard-coded; see irq.c */ + break; + case 6: /* on-board pci-pci bridge */ + dev->irq = 0xff; + break; + case 7: /* on-board ether */ + dev->irq = nile4_to_irq(NILE4_INT_INTB); + break; + case 8: /* ISA-PCI bridge */ + dev->irq = nile4_to_irq(NILE4_INT_INTC); + break; + case 9: /* ext slot #3 */ + dev->irq = nile4_to_irq(NILE4_INT_INTD); + break; + case 10: /* ext slot #4 */ + dev->irq = nile4_to_irq(NILE4_INT_INTA); + break; + case 13: /* Vrc5476 */ + dev->irq = 0xff; + break; + case 14: /* HD controller, M5229 */ + dev->irq = 14; + break; + default: + printk("JSUN : in pcibios_fixup_irqs - unkown slot %d\n", slot_num); + panic("JSUN : in pcibios_fixup_irqs - unkown slot.\n"); + } + } +} + +void __init pcibios_init(void) +{ + u32 base; + + printk("PCI: Emulate bios initialization \n"); + /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ + *(long*)(NILE4_BASE + NILE4_BAR0) = 0x8; + + printk("PCI: Probing PCI hardware\n"); + ioport_resource.end = 0x1ffffff; /* 32 MB */ + iomem_resource.end = 0x1fffffff; /* 512 MB */ + + /* `ram' and `nile4' are requested through the Nile4 pci_dev */ + request_resource(&iomem_resource, &ddb5476_resources.flash); + request_resource(&iomem_resource, &ddb5476_resources.isa_io); + request_resource(&iomem_resource, &ddb5476_resources.pci_io); + request_resource(&iomem_resource, &ddb5476_resources.isa_mem); + request_resource(&iomem_resource, &ddb5476_resources.pci_mem); + request_resource(&iomem_resource, &ddb5476_resources.boot); + + pci_scan_bus(0, &nile4_pci_ops, NULL); + ddb5476_pci_fixup(); + pci_assign_unassigned_resources(); + pci_set_bus_ranges(); + pcibios_fixup_irqs(); +} + +void __init pcibios_fixup_bus(struct pci_bus *bus) +{ + /* [jsun] we don't know how to fix sub-buses yet */ + if (bus->number == 0) { + bus->resource[1] = &ddb5476_resources.pci_mem; + } +} + +char *pcibios_setup (char *str) +{ + return str; +} + +void __init pcibios_update_irq(struct pci_dev *dev, int irq) +{ + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); +} + +void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, + struct pbus_set_ranges_data *ranges) +{ + /* our caller figure out range by going through the dev structures. + * I guess this is the place to fix things up if the bus is using a + * different view of the addressing space. + */ + + /* original DDB5074 code + if (bus->number == 0) { + ranges->io_start -= bus->resource[0]->start; + ranges->io_end -= bus->resource[0]->start; + ranges->mem_start -= bus->resource[1]->start; + ranges->mem_end -= bus->resource[1]->start; + } + */ +} + +int pcibios_enable_resources(struct pci_dev *dev) +{ + u16 cmd, old_cmd; + int idx; + struct resource *r; + + /* + * Don't touch the Nile 4 + */ + if (dev->vendor == PCI_VENDOR_ID_NEC && + dev->device == PCI_DEVICE_ID_NEC_VRC5476) + return 0; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + old_cmd = cmd; + for(idx=0; idx<6; idx++) { + r = &dev->resource[idx]; + if (!r->start && r->end) { + printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); + return -EINVAL; + } + if (r->flags & IORESOURCE_IO) + cmd |= PCI_COMMAND_IO; + if (r->flags & IORESOURCE_MEM) + cmd |= PCI_COMMAND_MEMORY; + } + if (cmd != old_cmd) { + printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd); + pci_write_config_word(dev, PCI_COMMAND, cmd); + } + return 0; +} + +int pcibios_enable_device(struct pci_dev *dev) +{ + return pcibios_enable_resources(dev); +} + +void pcibios_update_resource(struct pci_dev *dev, struct resource *root, + struct resource *res, int resource) +{ + u32 new, check; + int reg; + + new = res->start | (res->flags & PCI_REGION_FLAG_MASK); + if (resource < 6) { + reg = PCI_BASE_ADDRESS_0 + 4*resource; + } else if (resource == PCI_ROM_RESOURCE) { + res->flags |= PCI_ROM_ADDRESS_ENABLE; + reg = dev->rom_base_reg; + } else { + /* Somebody might have asked allocation of a non-standard resource */ + return; + } + + pci_write_config_dword(dev, reg, new); + pci_read_config_dword(dev, reg, &check); + if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) { + printk(KERN_ERR "PCI: Error while updating region " + "%s/%d (%08x != %08x)\n", dev->slot_name, resource, + new, check); + } +} + +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size) +{ + struct pci_dev *dev = data; + + if (res->flags & IORESOURCE_IO) { + unsigned long start = res->start; + + /* We need to avoid collisions with `mirrored' VGA ports + and other strange ISA hardware, so we always want the + addresses kilobyte aligned. */ + if (size > 0x100) { + printk(KERN_ERR "PCI: I/O Region %s/%d too large" + " (%ld bytes)\n", dev->slot_name, + dev->resource - res, size); + } + + start = (start + 1024 - 1) & ~(1024 - 1); + res->start = start; + } +} + + +struct pci_fixup pcibios_fixups[] = { {0} }; + diff --git a/arch/mips/ddb5476/prom.c b/arch/mips/ddb5476/prom.c new file mode 100644 index 000000000..5edc7f3fa --- /dev/null +++ b/arch/mips/ddb5476/prom.c @@ -0,0 +1,66 @@ +/* + * arch/mips/ddb5476/prom.c -- NEC DDB Vrc-5476 PROM routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + * + * Jun Sun - modified for DDB5476. + * + * $Id: prom.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ + */ + +#include <linux/init.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/bootmem.h> +#include <asm/addrspace.h> +#include <asm/bootinfo.h> + + +char arcs_cmdline[CL_SIZE]; + +extern char _end; + +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) + + +/* [jsun@junsun.net] PMON passes arguments in C main() style */ +void __init prom_init(int argc, const char **arg) +{ + int i; + unsigned long mem_size, free_start, free_end, start_pfn, bootmap_size; + + /* arg[0] is "g", the rest is boot parameters */ + arcs_cmdline[0] = '\0'; + for (i=1; i< argc; i++) { + if (strlen(arcs_cmdline) + strlen(arg[i] + 1) >= CL_SIZE) break; + strcat(arcs_cmdline, arg[i]); + strcat(arcs_cmdline, " "); + } + + mips_machgroup = MACH_GROUP_NEC_DDB; + mips_machtype = MACH_NEC_DDB5476; + /* 64 MB non-upgradable */ + mem_size = 64 << 20; + + free_start = PHYSADDR(PFN_ALIGN(&_end)); + free_end = mem_size; + start_pfn = PFN_UP((unsigned long)&_end); + + /* Register all the contiguous memory with the bootmem allocator + and free it. Be careful about the bootmem freemap. */ + bootmap_size = init_bootmem(start_pfn, mem_size >> PAGE_SHIFT); + + /* Free the entire available memory after the _end symbol. */ + free_start += bootmap_size; + free_bootmem(free_start, free_end-free_start); +} + +void __init prom_fixup_mem_map(unsigned long start, unsigned long end) +{ +} + +void __init prom_free_prom_memory(void) +{ +} diff --git a/arch/mips/ddb5476/setup.c b/arch/mips/ddb5476/setup.c new file mode 100644 index 000000000..53a25a9a2 --- /dev/null +++ b/arch/mips/ddb5476/setup.c @@ -0,0 +1,396 @@ +/* + * arch/mips/ddb5476/setup.c -- NEC DDB Vrc-5476 setup routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + * + * $Id: setup.c,v 1.1 2000/01/26 00:07:44 ralf Exp $ + */ + +#include <linux/config.h> +#include <linux/init.h> +#include <linux/kbd_ll.h> +#include <linux/kernel.h> +#include <linux/kdev_t.h> +#include <linux/types.h> +#include <linux/console.h> +#include <linux/sched.h> +#include <linux/mc146818rtc.h> +#include <linux/pc_keyb.h> +#include <linux/pci.h> +#include <linux/ide.h> + +#include <asm/addrspace.h> +#include <asm/bcache.h> +#include <asm/keyboard.h> +#include <asm/irq.h> +#include <asm/reboot.h> +#include <asm/gdb-stub.h> +#include <asm/nile4.h> + + +#ifdef CONFIG_REMOTE_DEBUG +extern void rs_kgdb_hook(int); +extern void breakpoint(void); +#endif + +#if defined(CONFIG_SERIAL_CONSOLE) +extern void console_setup(char *); +#endif + +extern struct ide_ops std_ide_ops; +extern struct rtc_ops ddb_rtc_ops; +extern struct kbd_ops std_kbd_ops; + +static void (*back_to_prom)(void) = (void (*)(void))0xbfc00000; + +static void ddb_machine_restart(char *command) +{ + u32 t; + + /* PCI cold reset */ + t = nile4_in32(NILE4_PCICTRL+4); + t |= 0x40000000; + nile4_out32(NILE4_PCICTRL+4, t); + /* CPU cold reset */ + t = nile4_in32(NILE4_CPUSTAT); + t |= 1; + nile4_out32(NILE4_CPUSTAT, t); + /* Call the PROM */ + back_to_prom(); +} + +static void ddb_machine_halt(void) +{ + printk("DDB Vrc-5476 halted.\n"); + do {} while (1); +} + +static void ddb_machine_power_off(void) +{ + printk("DDB Vrc-5476 halted. Please turn off the power.\n"); + do {} while (1); +} + +extern void ddb_irq_setup(void); + +void (*board_time_init)(struct irqaction *irq); + + +static void __init ddb_time_init(struct irqaction *irq) +{ + /* set the clock to 1 Hz */ + nile4_out32(NILE4_T2CTRL, 1000000); + /* enable the General-Purpose Timer */ + nile4_out32(NILE4_T2CTRL+4, 0x00000001); + /* reset timer */ + nile4_out32(NILE4_T2CNTR, 0); + /* enable interrupt */ + nile4_enable_irq(NILE4_INT_GPT); + i8259_setup_irq(nile4_to_irq(NILE4_INT_GPT), irq); +} + +static struct { + struct resource dma1; + struct resource pic1; + struct resource timer; + struct resource rtc; + struct resource dma_page_reg; + struct resource pic2; + struct resource dma2; +} ddb5476_ioport = { + {"dma1", 0x00, 0x1f, IORESOURCE_BUSY }, + {"pic1", 0x20, 0x3f, IORESOURCE_BUSY }, + {"timer", 0x40, 0x5f, IORESOURCE_BUSY }, + {"rtc", 0x70, 0x7f, IORESOURCE_BUSY }, + {"dma page reg", 0x80, 0x8f, IORESOURCE_BUSY }, + {"pic2", 0xa0, 0xbf, IORESOURCE_BUSY }, + {"dma2", 0xc0, 0xdf, IORESOURCE_BUSY } +}; + +static struct { + struct resource nile4; +} ddb5476_iomem = { + {"Nile 4", NILE4_BASE, NILE4_BASE + NILE4_SIZE - 1, + IORESOURCE_BUSY} +}; + +void __init ddb_setup(void) +{ + extern int panic_timeout; + + irq_setup = ddb_irq_setup; + mips_io_port_base = NILE4_PCI_IO_BASE; + isa_slot_offset = NILE4_PCI_MEM_BASE; + board_time_init = ddb_time_init; + + _machine_restart = ddb_machine_restart; + _machine_halt = ddb_machine_halt; + _machine_power_off = ddb_machine_power_off; + + /* request io port/mem resources */ + if (request_resource(&ioport_resource, &ddb5476_ioport.dma1) || + request_resource(&ioport_resource, &ddb5476_ioport.pic1) || + request_resource(&ioport_resource, &ddb5476_ioport.timer) || + request_resource(&ioport_resource, &ddb5476_ioport.rtc) || + request_resource(&ioport_resource, &ddb5476_ioport.dma_page_reg) || + request_resource(&ioport_resource, &ddb5476_ioport.pic2) || + request_resource(&ioport_resource, &ddb5476_ioport.dma2) || + request_resource(&iomem_resource, &ddb5476_iomem.nile4) ) { + printk("ddb_setup - requesting oo port resources failed.\n"); + for(;;); + } + +#ifdef CONFIG_BLK_DEV_IDE + ide_ops = &std_ide_ops; +#endif + rtc_ops = &ddb_rtc_ops; + +#ifdef CONFIG_PC_KEYB + kbd_ops = &std_kbd_ops; +#endif + + /* Reboot on panic */ + panic_timeout = 180; + + /* [jsun] we need to set BAR0 so that SDRAM 0 appears at 0x0 in PCI */ + /* *(long*)0xbfa00218 = 0x8; */ + +#ifdef CONFIG_FB + conswitchp = &dummy_con; +#endif + + + /* board initialization stuff - non-fundamental, but need to be set + * before kernel runs */ + + /* setup I/O space */ + nile4_set_pdar(NILE4_PCIW0, + PHYSADDR(NILE4_PCI_IO_BASE), + 0x02000000, + 32, + 0, + 0); + nile4_set_pmr(NILE4_PCIINIT0, NILE4_PCICMD_IO, 0); + + /* map config space to 0xa8000000, 128MB */ + nile4_set_pdar(NILE4_PCIW1, + PHYSADDR(NILE4_PCI_CFG_BASE), + 0x08000000, + 32, + 0, + 0); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_CFG, 0x0); + + /* ----- M1543 PCI setup ------ */ + + /* we know M1543 PCI-ISA controller is at addr:18 */ + /* xxxx1010 makes USB at addr:13 and PMU at addr:14 */ + *(volatile unsigned char*)0xa8040072 &= 0xf0; + *(volatile unsigned char*)0xa8040072 |= 0xa; + + /* setup USB interrupt to IRQ 9, (bit 0:3 - 0001) + * no IOCHRDY signal, (bit 7 - 1) + * M1543C & M7101 VID and Subsys Device ID are read-only (bit 6 - 1) + * Bypass USB Master INTAJ level to edge conversion (bit 4 - 0) + */ + *(unsigned char*)0xa8040074 = 0xc1; + + /* setup PMU(SCI to IRQ 10 (bit 0:3 - 0011) + * SCI routing to IRQ 13 disabled (bit 7 - 1) + * SCI interrupt level to edge conversion bypassed (bit 4 - 0) + */ + *(unsigned char*)0xa8040076 = 0x83; + + /* setup IDE controller + * enable IDE controller (bit 6 - 1) + * IDE IDSEL to be addr:24 (bit 4:5 - 11) + * no IDE ATA Secondary Bus Signal Pad Control (bit 3 - 0) + * no IDE ATA Primary Bus Signal Pad Control (bit 2 - 0) + * primary IRQ is 14, secondary is 15 (bit 1:0 - 01 + */ + // *(unsigned char*)0xa8040058 = 0x71; + // *(unsigned char*)0xa8040058 = 0x79; + // *(unsigned char*)0xa8040058 = 0x74; // use SIRQ, primary tri-state + *(unsigned char*)0xa8040058 = 0x75; // primary tri-state + +#if 0 + /* this is not necessary if M5229 does not use SIRQ */ + *(unsigned char*)0xa8040044 = 0x0d; // primary to IRQ 14 + *(unsigned char*)0xa8040075 = 0x0d; // secondary to IRQ 14 +#endif + + /* enable IDE in the M5229 config register 0x50 (bit 0 - 1) */ + /* M5229 IDSEL is addr:24; see above setting */ + *(unsigned char*)0xa9000050 |= 0x1; + + /* enable bus master (bit 2) and IO decoding (bit 0) */ + *(unsigned char*)0xa9000004 |= 0x5; + + /* enable native, copied from arch/ppc/k2boot/head.S */ + /* TODO - need volatile, need to be portable */ + *(unsigned char*)0xa9000009 = 0xff; + + /* ----- end of M1543 PCI setup ------ */ + + /* ----- reset on-board ether chip ------ */ + *((volatile u32 *)0xa8020004) |= 1; /* decode I/O */ + *((volatile u32 *)0xa8020010) = 0; /* set BAR address */ + + /* send reset command */ + *((volatile u32 *)0xa6000000) = 1; /* do a soft reset */ + + /* disable ether chip */ + *((volatile u32 *)0xa8020004) = 0; /* disable any decoding */ + + /* put it into sleep */ + *((volatile u32 *)0xa8020040) = 0x80000000; + + /* ----- end of reset on-board ether chip ------ */ + + /* ----- set pci window 1 to pci memory space -------- */ + nile4_set_pdar(NILE4_PCIW1, + PHYSADDR(NILE4_PCI_MEM_BASE), + 0x08000000, + 32, + 0, + 0); + // nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0); + nile4_set_pmr(NILE4_PCIINIT1, NILE4_PCICMD_MEM, 0x08000000); + +} + +int __init page_is_ram(unsigned long pagenr) +{ + return 1; +} + + +#define USE_NILE4_SERIAL 0 + +#if USE_NILE4_SERIAL +#define ns16550_in(reg) nile4_in8((reg)*8) +#define ns16550_out(reg, val) nile4_out8((reg)*8, (val)) +#else +#define NS16550_BASE (NILE4_PCI_IO_BASE+0x03f8) +static inline u8 ns16550_in(u32 reg) +{ + return *(volatile u8 *)(NS16550_BASE+reg); +} + +static inline void ns16550_out(u32 reg, u8 val) +{ + *(volatile u8 *)(NS16550_BASE+reg) = val; +} +#endif + +#define NS16550_RBR 0 +#define NS16550_THR 0 +#define NS16550_DLL 0 +#define NS16550_IER 1 +#define NS16550_DLM 1 +#define NS16550_FCR 2 +#define NS16550_IIR 2 +#define NS16550_LCR 3 +#define NS16550_MCR 4 +#define NS16550_LSR 5 +#define NS16550_MSR 6 +#define NS16550_SCR 7 + +#define NS16550_LSR_DR 0x01 /* Data ready */ +#define NS16550_LSR_OE 0x02 /* Overrun */ +#define NS16550_LSR_PE 0x04 /* Parity error */ +#define NS16550_LSR_FE 0x08 /* Framing error */ +#define NS16550_LSR_BI 0x10 /* Break */ +#define NS16550_LSR_THRE 0x20 /* Xmit holding register empty */ +#define NS16550_LSR_TEMT 0x40 /* Xmitter empty */ +#define NS16550_LSR_ERR 0x80 /* Error */ + + +void _serinit(void) +{ +#if USE_NILE4_SERIAL + ns16550_out(NS16550_LCR, 0x80); + ns16550_out(NS16550_DLM, 0x00); + ns16550_out(NS16550_DLL, 0x36); /* 9600 baud */ + ns16550_out(NS16550_LCR, 0x00); + ns16550_out(NS16550_LCR, 0x03); + ns16550_out(NS16550_FCR, 0x47); +#else + /* done by PMON */ +#endif +} + +void _putc(char c) +{ + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); + ns16550_out(NS16550_THR, c); + if (c == '\n') { + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_THRE)); + ns16550_out(NS16550_THR, '\r'); + } +} + +void _puts(const char *s) +{ + char c; + while ((c = *s++)) + _putc(c); +} + +char _getc(void) +{ + while (!(ns16550_in(NS16550_LSR) & NS16550_LSR_DR)); + return ns16550_in(NS16550_RBR); +} + +int _testc(void) +{ + return (ns16550_in(NS16550_LSR) & NS16550_LSR_DR) != 0; +} + + + /* + * Hexadecimal 7-segment LED + */ + +void ddb5476_led_hex(int hex) +{ + outb(hex, 0x80); +} + + + /* + * LEDs D2 and D3, connected to the GPIO pins of the PMU in the ALi M1543 + */ + +struct pci_dev *pci_pmu = NULL; + +void ddb5476_led_d2(int on) +{ + u8 t; + + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0x7f; + else + t |= 0x80; + pci_write_config_byte(pci_pmu, 0x7e, t); + } +} + +void ddb5476_led_d3(int on) +{ + u8 t; + + if (pci_pmu) { + pci_read_config_byte(pci_pmu, 0x7e, &t); + if (on) + t &= 0xbf; + else + t |= 0x40; + pci_write_config_byte(pci_pmu, 0x7e, t); + } +} + diff --git a/arch/mips/ddb5476/time.c b/arch/mips/ddb5476/time.c new file mode 100644 index 000000000..14503c66a --- /dev/null +++ b/arch/mips/ddb5476/time.c @@ -0,0 +1,35 @@ +/* + * arch/mips/ddb5074/time.c -- Timer routines + * + * Copyright (C) 2000 Geert Uytterhoeven <geert@sonycom.com> + * Sony Software Development Center Europe (SDCE), Brussels + * + * $Id* + */ + +#include <linux/init.h> +#include <asm/mc146818rtc.h> + +static unsigned char ddb_rtc_read_data(unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + return inb_p(RTC_PORT(1)); +} + +static void ddb_rtc_write_data(unsigned char data, unsigned long addr) +{ + outb_p(addr, RTC_PORT(0)); + outb_p(data, RTC_PORT(1)); +} + +static int ddb_rtc_bcd_mode(void) +{ + return 1; +} + +struct rtc_ops ddb_rtc_ops = { + ddb_rtc_read_data, + ddb_rtc_write_data, + ddb_rtc_bcd_mode +}; + diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 97226bd59..a00bb48d7 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -262,7 +262,7 @@ int i8259_setup_irq(int irq, struct irqaction * new) if (!shared) { if (is_i8259_irq(irq)) unmask_irq(irq); -#if CONFIG_DDB5074 /* This has no business here */ +#if (defined(CONFIG_DDB5074) || defined(CONFIG_DDB5476)) else nile4_enable_irq(irq_to_nile4(irq)); #endif diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 6ac1c0643..c067218b6 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -186,6 +186,9 @@ static inline void cpu_probe(void) case PRID_IMP_R5000: mips_cputype = CPU_R5000; break; + case PRID_IMP_R5432: + mips_cputype = CPU_R5432; + break; case PRID_IMP_NEVADA: mips_cputype = CPU_NEVADA; break; @@ -318,6 +321,11 @@ void __init setup_arch(char **cmdline_p) ddb_setup(); break; #endif +#ifdef CONFIG_DDB5476 + case MACH_GROUP_NEC_DDB: + ddb_setup(); + break; +#endif #ifdef CONFIG_ORION case MACH_GROUP_ORION: orion_setup(); diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index b662631fe..609593c6b 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c @@ -476,6 +476,7 @@ static inline void init_cycle_counter(void) case CPU_R4650: case CPU_R4700: case CPU_R5000: + case CPU_R5432: case CPU_R5000A: case CPU_R4640: case CPU_NEVADA: diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 1d9284cfa..ebfac0cd2 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -711,6 +711,7 @@ void __init trap_init(void) /* case CPU_R4640: */ case CPU_R4600: case CPU_R5000: + case CPU_R5432: case CPU_NEVADA: case CPU_RM7000: if(mips_cputype == CPU_NEVADA) { diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile index eb17ba7d4..409726924 100644 --- a/arch/mips/mm/Makefile +++ b/arch/mips/mm/Makefile @@ -26,6 +26,10 @@ ifdef CONFIG_CPU_R5000 O_OBJS += r4xx0.o endif +ifdef CONFIG_CPU_R5432 +O_OBJS += r4xx0.o +endif + ifdef CONFIG_CPU_RM7000 O_OBJS += rm7k.o endif diff --git a/arch/mips/mm/loadmmu.c b/arch/mips/mm/loadmmu.c index 5dd412b36..8031297f0 100644 --- a/arch/mips/mm/loadmmu.c +++ b/arch/mips/mm/loadmmu.c @@ -56,7 +56,8 @@ void __init loadmmu(void) #endif #if defined(CONFIG_CPU_R4X00) || defined(CONFIG_CPU_R4300) || \ - defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_NEVADA) + defined(CONFIG_CPU_R5000) || defined(CONFIG_CPU_R5432) || \ + defined(CONFIG_CPU_NEVADA) case CPU_R4000PC: case CPU_R4000SC: case CPU_R4000MC: @@ -71,6 +72,7 @@ void __init loadmmu(void) case CPU_R4700: case CPU_R5000: case CPU_R5000A: + case CPU_R5432: case CPU_NEVADA: printk("Loading R4000 MMU routines.\n"); ld_mmu_r4xx0(); |