diff options
author | Thomas Bogendoerfer <tsbogend@alpha.franken.de> | 2006-12-28 18:22:32 +0100 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-02-18 21:31:37 +0000 |
commit | c066a32a890c50ce59e91f8cea8eb5fd8d5821b9 (patch) | |
tree | d129af235d11d44c649f0743bc38535c3a229e41 /arch/mips | |
parent | 5759906ca9e5201c3fd40d61c861ec1e441d3a24 (diff) | |
download | blackbird-op-linux-c066a32a890c50ce59e91f8cea8eb5fd8d5821b9.tar.gz blackbird-op-linux-c066a32a890c50ce59e91f8cea8eb5fd8d5821b9.zip |
[MIPS] Support for several more SNI RM models.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/Kconfig | 5 | ||||
-rw-r--r-- | arch/mips/pci/fixup-sni.c | 66 | ||||
-rw-r--r-- | arch/mips/pci/ops-sni.c | 77 | ||||
-rw-r--r-- | arch/mips/sni/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/sni/a20r.c | 227 | ||||
-rw-r--r-- | arch/mips/sni/ds1216.c | 81 | ||||
-rw-r--r-- | arch/mips/sni/irq.c | 188 | ||||
-rw-r--r-- | arch/mips/sni/pcimt.c | 390 | ||||
-rw-r--r-- | arch/mips/sni/pcit.c | 351 | ||||
-rw-r--r-- | arch/mips/sni/reset.c | 9 | ||||
-rw-r--r-- | arch/mips/sni/rm200.c | 186 | ||||
-rw-r--r-- | arch/mips/sni/setup.c | 242 | ||||
-rw-r--r-- | arch/mips/sni/sniprom.c | 129 | ||||
-rw-r--r-- | arch/mips/sni/time.c | 148 |
14 files changed, 1719 insertions, 382 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index a92ce6bd7cf1..46fa5ca9f5ac 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -726,15 +726,16 @@ config SNI_RM select BOOT_ELF32 select DMA_NONCOHERENT select GENERIC_ISA_DMA - select HAVE_STD_PC_SERIAL_PORT select HW_HAS_EISA select HW_HAS_PCI + select IRQ_CPU select I8253 select I8259 select ISA select SWAP_IO_SPACE if CPU_BIG_ENDIAN select SYS_HAS_CPU_R4X00 select SYS_HAS_CPU_R5000 + select SYS_HAS_CPU_R10000 select R5000_CPU_SCACHE select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL @@ -1066,7 +1067,7 @@ config BOOT_ELF32 config MIPS_L1_CACHE_SHIFT int - default "4" if MACH_DECSTATION + default "4" if MACH_DECSTATION || SNI_RM default "7" if SGI_IP27 default "5" diff --git a/arch/mips/pci/fixup-sni.c b/arch/mips/pci/fixup-sni.c index a176f2ca8656..0c9a4732d455 100644 --- a/arch/mips/pci/fixup-sni.c +++ b/arch/mips/pci/fixup-sni.c @@ -15,7 +15,7 @@ #include <asm/sni.h> /* - * Shortcuts ... + * PCIMT Shortcuts ... */ #define SCSI PCIMT_IRQ_SCSI #define ETH PCIMT_IRQ_ETHERNET @@ -67,6 +67,50 @@ static char irq_tab_rm300d[8][5] __initdata = { { 0, INTD, INTA, INTB, INTC }, /* Slot 4 */ }; +static char irq_tab_rm300e[5][5] __initdata = { + /* INTA INTB INTC INTD */ + { 0, 0, 0, 0, 0 }, /* HOST bridge */ + { SCSI, SCSI, SCSI, SCSI, SCSI }, /* SCSI */ + { 0, INTC, INTD, INTA, INTB }, /* Bridge/i960 */ + { 0, INTD, INTA, INTB, INTC }, /* Slot 1 */ + { 0, INTA, INTB, INTC, INTD }, /* Slot 2 */ +}; +#undef SCSI +#undef ETH +#undef INTA +#undef INTB +#undef INTC +#undef INTD + + +/* + * PCIT Shortcuts ... + */ +#define SCSI0 PCIT_IRQ_SCSI0 +#define SCSI1 PCIT_IRQ_SCSI1 +#define ETH PCIT_IRQ_ETHERNET +#define INTA PCIT_IRQ_INTA +#define INTB PCIT_IRQ_INTB +#define INTC PCIT_IRQ_INTC +#define INTD PCIT_IRQ_INTD + +static char irq_tab_pcit[13][5] __initdata = { + /* INTA INTB INTC INTD */ + { 0, 0, 0, 0, 0 }, /* HOST bridge */ + { SCSI0, SCSI0, SCSI0, SCSI0, SCSI0 }, /* SCSI */ + { SCSI1, SCSI1, SCSI1, SCSI1, SCSI1 }, /* SCSI */ + { ETH, ETH, ETH, ETH, ETH }, /* Ethernet */ + { 0, INTA, INTB, INTC, INTD }, /* PCI-PCI bridge */ + { 0, 0, 0, 0, 0 }, /* Unused */ + { 0, 0, 0, 0, 0 }, /* Unused */ + { 0, 0, 0, 0, 0 }, /* Unused */ + { 0, INTA, INTB, INTC, INTD }, /* Slot 1 */ + { 0, INTB, INTC, INTD, INTA }, /* Slot 2 */ + { 0, INTC, INTD, INTA, INTB }, /* Slot 3 */ + { 0, INTD, INTA, INTB, INTC }, /* Slot 4 */ + { 0, INTA, INTB, INTC, INTD }, /* Slot 5 */ +}; + static inline int is_rm300_revd(void) { unsigned char csmsr = *(volatile unsigned char *)PCIMT_CSMSR; @@ -76,10 +120,24 @@ static inline int is_rm300_revd(void) int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { - if (is_rm300_revd()) - return irq_tab_rm300d[slot][pin]; + switch (sni_brd_type) { + case SNI_BRD_PCI_TOWER: + case SNI_BRD_PCI_TOWER_CPLUS: + return irq_tab_pcit[slot][pin]; + + case SNI_BRD_PCI_MTOWER: + if (is_rm300_revd()) + return irq_tab_rm300d[slot][pin]; + /* fall through */ - return irq_tab_rm200[slot][pin]; + case SNI_BRD_PCI_DESKTOP: + return irq_tab_rm200[slot][pin]; + + case SNI_BRD_PCI_MTOWER_CPLUS: + return irq_tab_rm300e[slot][pin]; + } + + return 0; } /* Do platform specific device initialization at pci_enable_device() time */ diff --git a/arch/mips/pci/ops-sni.c b/arch/mips/pci/ops-sni.c index 2b0ccd6d9dcd..fa2d2c60f797 100644 --- a/arch/mips/pci/ops-sni.c +++ b/arch/mips/pci/ops-sni.c @@ -83,7 +83,82 @@ static int pcimt_write(struct pci_bus *bus, unsigned int devfn, int reg, return 0; } -struct pci_ops sni_pci_ops = { +struct pci_ops sni_pcimt_ops = { .read = pcimt_read, .write = pcimt_write, }; + +static int pcit_set_config_address(unsigned int busno, unsigned int devfn, int reg) +{ + if ((devfn > 255) || (reg > 255) || (busno > 255)) + return PCIBIOS_BAD_REGISTER_NUMBER; + + outl ((1 << 31) | ((busno & 0xff) << 16) | ((devfn & 0xff) << 8) | (reg & 0xfc), 0xcf8); + return PCIBIOS_SUCCESSFUL; +} + +static int pcit_read(struct pci_bus *bus, unsigned int devfn, int reg, + int size, u32 * val) +{ + int res; + + /* + * on bus 0 we need to check, whether there is a device answering + * for the devfn by doing a config write and checking the result. If + * we don't do it, we will get a data bus error + */ + if (bus->number == 0) { + pcit_set_config_address (0, 0, 0x68); + outl (inl (0xcfc) | 0xc0000000, 0xcfc); + if ((res = pcit_set_config_address(0, devfn, 0))) + return res; + outl (0xffffffff, 0xcfc); + pcit_set_config_address (0, 0, 0x68); + if (inl(0xcfc) & 0x100000) + return PCIBIOS_DEVICE_NOT_FOUND; + } + if ((res = pcit_set_config_address(bus->number, devfn, reg))) + return res; + + switch (size) { + case 1: + *val = inb(PCIMT_CONFIG_DATA + (reg & 3)); + break; + case 2: + *val = inw(PCIMT_CONFIG_DATA + (reg & 2)); + break; + case 4: + *val = inl(PCIMT_CONFIG_DATA); + break; + } + return 0; +} + +static int pcit_write(struct pci_bus *bus, unsigned int devfn, int reg, + int size, u32 val) +{ + int res; + + if ((res = pcit_set_config_address(bus->number, devfn, reg))) + return res; + + switch (size) { + case 1: + outb (val, PCIMT_CONFIG_DATA + (reg & 3)); + break; + case 2: + outw (val, PCIMT_CONFIG_DATA + (reg & 2)); + break; + case 4: + outl (val, PCIMT_CONFIG_DATA); + break; + } + + return 0; +} + + +struct pci_ops sni_pcit_ops = { + .read = pcit_read, + .write = pcit_write, +}; diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile index a5eb0adb87c7..e30809a92151 100644 --- a/arch/mips/sni/Makefile +++ b/arch/mips/sni/Makefile @@ -2,7 +2,7 @@ # Makefile for the SNI specific part of the kernel # -obj-y += irq.o pcimt_scache.o reset.o setup.o +obj-y += irq.o reset.o setup.o ds1216.o a20r.o rm200.o pcimt.o pcit.o time.o obj-$(CONFIG_CPU_BIG_ENDIAN) += sniprom.o EXTRA_AFLAGS := $(CFLAGS) diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c new file mode 100644 index 000000000000..31ab80f1befa --- /dev/null +++ b/arch/mips/sni/a20r.c @@ -0,0 +1,227 @@ +/* + * A20R specific code + * + * 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) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> + +#include <asm/sni.h> +#include <asm/time.h> +#include <asm/ds1216.h> + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF, \ + } + +static struct plat_serial8250_port a20r_data[] = { + PORT(0x3f8, 4), + PORT(0x2f8, 3), + { }, +}; + +static struct platform_device a20r_serial8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = a20r_data, + }, +}; + +static struct resource snirm_82596_rsrc[] = { + { + .start = 0xb8000000, + .end = 0xb8000004, + .flags = IORESOURCE_MEM + }, + { + .start = 0xb8010000, + .end = 0xb8010004, + .flags = IORESOURCE_MEM + }, + { + .start = 0xbff00000, + .end = 0xbff00020, + .flags = IORESOURCE_MEM + }, + { + .start = 22, + .end = 22, + .flags = IORESOURCE_IRQ + }, + { + .flags = 0x01 /* 16bit mpu port access */ + } +}; + +static struct platform_device snirm_82596_pdev = { + .name = "snirm_82596", + .num_resources = ARRAY_SIZE(snirm_82596_rsrc), + .resource = snirm_82596_rsrc +}; + +static struct resource snirm_53c710_rsrc[] = { + { + .start = 0xb9000000, + .end = 0xb90fffff, + .flags = IORESOURCE_MEM + }, + { + .start = 19, + .end = 19, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device snirm_53c710_pdev = { + .name = "snirm_53c710", + .num_resources = ARRAY_SIZE(snirm_53c710_rsrc), + .resource = snirm_53c710_rsrc +}; + +static struct resource sc26xx_rsrc[] = { + { + .start = 0xbc070000, + .end = 0xbc0700ff, + .flags = IORESOURCE_MEM + }, + { + .start = 20, + .end = 20, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device sc26xx_pdev = { + .name = "SC26xx", + .num_resources = ARRAY_SIZE(sc26xx_rsrc), + .resource = sc26xx_rsrc +}; + +static u32 a20r_ack_hwint(void) +{ + u32 status = read_c0_status(); + + write_c0_status (status | 0x00010000); + asm volatile( + " .set push \n" + " .set noat \n" + " .set noreorder \n" + " lw $1, 0(%0) \n" + " sb $0, 0(%1) \n" + " sync \n" + " lb %1, 0(%1) \n" + " b 1f \n" + " ori %1, $1, 2 \n" + " .align 8 \n" + "1: \n" + " nop \n" + " sw %1, 0(%0) \n" + " sync \n" + " li %1, 0x20 \n" + "2: \n" + " nop \n" + " bnez %1,2b \n" + " addiu %1, -1 \n" + " sw $1, 0(%0) \n" + " sync \n" + ".set pop \n" + : + : "Jr" (PCIMT_UCONF), "Jr" (0xbc000000)); + write_c0_status(status); + + return status; +} + +static inline void unmask_a20r_irq(unsigned int irq) +{ + set_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE)); + irq_enable_hazard(); +} + +static inline void mask_a20r_irq(unsigned int irq) +{ + clear_c0_status(0x100 << (irq - SNI_A20R_IRQ_BASE)); + irq_disable_hazard(); +} + +static void end_a20r_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) { + a20r_ack_hwint(); + unmask_a20r_irq(irq); + } +} + +static struct irq_chip a20r_irq_type = { + .typename = "A20R", + .ack = mask_a20r_irq, + .mask = mask_a20r_irq, + .mask_ack = mask_a20r_irq, + .unmask = unmask_a20r_irq, + .end = end_a20r_irq, +}; + +/* + * hwint 0 receive all interrupts + */ +static void a20r_hwint(void) +{ + u32 cause, status; + int irq; + + clear_c0_status (IE_IRQ0); + status = a20r_ack_hwint(); + cause = read_c0_cause(); + + irq = ffs(((cause & status) >> 8) & 0xf8); + if (likely(irq > 0)) + do_IRQ(SNI_A20R_IRQ_BASE + irq - 1); + set_c0_status(IE_IRQ0); +} + +void __init sni_a20r_irq_init(void) +{ + int i; + + for (i = SNI_A20R_IRQ_BASE + 2 ; i < SNI_A20R_IRQ_BASE + 8; i++) + set_irq_chip(i, &a20r_irq_type); + sni_hwint = a20r_hwint; + change_c0_status(ST0_IM, IE_IRQ0); + setup_irq (SNI_A20R_IRQ_BASE + 3, &sni_isa_irq); +} + +void sni_a20r_init(void) +{ + ds1216_base = (volatile unsigned char *) SNI_DS1216_A20R_BASE; + rtc_mips_get_time = ds1216_get_cmos_time; +} + +static int __init snirm_a20r_setup_devinit(void) +{ + switch (sni_brd_type) { + case SNI_BRD_TOWER_OASIC: + case SNI_BRD_MINITOWER: + platform_device_register(&snirm_82596_pdev); + platform_device_register(&snirm_53c710_pdev); + platform_device_register(&sc26xx_pdev); + platform_device_register(&a20r_serial8250_device); + break; + } + + return 0; +} + +device_initcall(snirm_a20r_setup_devinit); diff --git a/arch/mips/sni/ds1216.c b/arch/mips/sni/ds1216.c new file mode 100644 index 000000000000..1d92732c14f1 --- /dev/null +++ b/arch/mips/sni/ds1216.c @@ -0,0 +1,81 @@ + +#include <linux/bcd.h> +#include <linux/time.h> + +#include <asm/ds1216.h> + +volatile unsigned char *ds1216_base; + +/* + * Read the 64 bit we'd like to have - It a series + * of 64 bits showing up in the LSB of the base register. + * + */ +static unsigned char *ds1216_read(void) +{ + static unsigned char rdbuf[8]; + unsigned char c; + int i, j; + + for (i = 0; i < 8; i++) { + c = 0x0; + for (j = 0; j < 8; j++) { + c |= (*ds1216_base & 0x1) << j; + } + rdbuf[i] = c; + } + + return rdbuf; +} + +static void ds1216_switch_ds_to_clock(void) +{ + unsigned char magic[] = { + 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c + }; + int i,j,c; + + /* Reset magic pointer */ + c = *ds1216_base; + + /* Write 64 bit magic to DS1216 */ + for (i = 0; i < 8; i++) { + c = magic[i]; + for (j = 0; j < 8; j++) { + *ds1216_base = c; + c = c >> 1; + } + } +} + +unsigned long ds1216_get_cmos_time(void) +{ + unsigned char *rdbuf; + unsigned int year, month, date, hour, min, sec; + + ds1216_switch_ds_to_clock(); + rdbuf = ds1216_read(); + + sec = BCD2BIN(DS1216_SEC(rdbuf)); + min = BCD2BIN(DS1216_MIN(rdbuf)); + hour = BCD2BIN(DS1216_HOUR(rdbuf)); + date = BCD2BIN(DS1216_DATE(rdbuf)); + month = BCD2BIN(DS1216_MONTH(rdbuf)); + year = BCD2BIN(DS1216_YEAR(rdbuf)); + + if (DS1216_1224(rdbuf) && DS1216_AMPM(rdbuf)) + hour+=12; + + if (year < 70) + year += 2000; + else + year += 1900; + + return mktime(year, month, date, hour, min, sec); +} + +int ds1216_set_rtc_mmss(unsigned long nowtime) +{ + printk("ds1216_set_rtc_mmss called but not implemented\n"); + return -1; +} diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c index 039e8e540508..ad5fc471a004 100644 --- a/arch/mips/sni/irq.c +++ b/arch/mips/sni/irq.c @@ -5,6 +5,7 @@ * * Copyright (C) 1992 Linus Torvalds * Copyright (C) 1994 - 2000 Ralf Baechle + * Copyright (C) 2006 Thomas Bogendoerfer */ #include <linux/delay.h> #include <linux/init.h> @@ -15,152 +16,34 @@ #include <asm/i8259.h> #include <asm/io.h> #include <asm/sni.h> +#include <asm/irq.h> +#include <asm/irq_cpu.h> -static void enable_pciasic_irq(unsigned int irq) -{ - unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2); - - *(volatile u8 *) PCIMT_IRQSEL |= mask; -} - -void disable_pciasic_irq(unsigned int irq) -{ - unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2)); - - *(volatile u8 *) PCIMT_IRQSEL &= mask; -} +void (*sni_hwint)(void); -static void end_pciasic_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_pciasic_irq(irq); -} - -static struct irq_chip pciasic_irq_type = { - .name = "ASIC-PCI", - .ack = disable_pciasic_irq, - .mask = disable_pciasic_irq, - .mask_ack = disable_pciasic_irq, - .unmask = enable_pciasic_irq, - .end = end_pciasic_irq, -}; - -/* - * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug - * button interrupts. Later ... - */ -static void pciasic_hwint0(void) -{ - panic("Received int0 but no handler yet ..."); -} - -/* This interrupt was used for the com1 console on the first prototypes. */ -static void pciasic_hwint2(void) -{ - /* I think this shouldn't happen on production machines. */ - panic("hwint2 and no handler yet"); -} - -/* hwint5 is the r4k count / compare interrupt */ -static void pciasic_hwint5(void) -{ - panic("hwint5 and no handler yet"); -} - -static unsigned int ls1bit8(unsigned int x) -{ - int b = 7, s; - - s = 4; if ((x & 0x0f) == 0) s = 0; b -= s; x <<= s; - s = 2; if ((x & 0x30) == 0) s = 0; b -= s; x <<= s; - s = 1; if ((x & 0x40) == 0) s = 0; b -= s; - - return b; -} - -/* - * hwint 1 deals with EISA and SCSI interrupts, - * - * The EISA_INT bit in CSITPEND is high active, all others are low active. - */ -static void pciasic_hwint1(void) +asmlinkage void plat_irq_dispatch(void) { - u8 pend = *(volatile char *)PCIMT_CSITPEND; - unsigned long flags; - - if (pend & IT_EISA) { - int irq; - /* - * Note: ASIC PCI's builtin interrupt achknowledge feature is - * broken. Using it may result in loss of some or all i8259 - * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ... - */ - irq = i8259_irq(); - if (unlikely(irq < 0)) - return; - - do_IRQ(irq); - } - - if (!(pend & IT_SCSI)) { - flags = read_c0_status(); - clear_c0_status(ST0_IM); - do_IRQ(PCIMT_IRQ_SCSI); - write_c0_status(flags); - } + sni_hwint(); } -/* - * hwint 3 should deal with the PCI A - D interrupts, - */ -static void pciasic_hwint3(void) +/* ISA irq handler */ +static irqreturn_t sni_isa_irq_handler(int dummy, void *p) { - u8 pend = *(volatile char *)PCIMT_CSITPEND; int irq; - pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD); - clear_c0_status(IE_IRQ3); - irq = PCIMT_IRQ_INT2 + ls1bit8(pend); - do_IRQ(irq); - set_c0_status(IE_IRQ3); -} + irq = i8259_irq(); + if (unlikely(irq < 0)) + return IRQ_NONE; -/* - * hwint 4 is used for only the onboard PCnet 32. - */ -static void pciasic_hwint4(void) -{ - clear_c0_status(IE_IRQ4); - do_IRQ(PCIMT_IRQ_ETHERNET); - set_c0_status(IE_IRQ4); -} - -asmlinkage void plat_irq_dispatch(void) -{ - unsigned int pending = read_c0_status() & read_c0_cause(); - static unsigned char led_cache; - - *(volatile unsigned char *) PCIMT_CSLED = ++led_cache; - - if (pending & 0x0800) - pciasic_hwint1(); - else if (pending & 0x4000) - pciasic_hwint4(); - else if (pending & 0x2000) - pciasic_hwint3(); - else if (pending & 0x1000) - pciasic_hwint2(); - else if (pending & 0x8000) - pciasic_hwint5(); - else if (pending & 0x0400) - pciasic_hwint0(); + do_IRQ(irq); + return IRQ_HANDLED; } -void __init init_pciasic(void) -{ - * (volatile u8 *) PCIMT_IRQSEL = - IT_EISA | IT_INTA | IT_INTB | IT_INTC | IT_INTD; -} +struct irqaction sni_isa_irq = { + .handler = sni_isa_irq_handler, + .name = "ISA", + .flags = SA_SHIRQ +}; /* * On systems with i8259-style interrupt controllers we assume for @@ -169,14 +52,31 @@ void __init init_pciasic(void) */ void __init arch_init_irq(void) { - int i; - init_i8259_irqs(); /* Integrated i8259 */ - init_pciasic(); - - /* Actually we've got more interrupts to handle ... */ - for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_ETHERNET; i++) - set_irq_chip(i, &pciasic_irq_type); - - change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4); + switch (sni_brd_type) { + case SNI_BRD_10: + case SNI_BRD_10NEW: + case SNI_BRD_TOWER_OASIC: + case SNI_BRD_MINITOWER: + sni_a20r_irq_init(); + break; + + case SNI_BRD_PCI_TOWER: + sni_pcit_irq_init(); + break; + + case SNI_BRD_PCI_TOWER_CPLUS: + sni_pcit_cplus_irq_init(); + break; + + case SNI_BRD_RM200: + sni_rm200_irq_init(); + break; + + case SNI_BRD_PCI_MTOWER: + case SNI_BRD_PCI_DESKTOP: + case SNI_BRD_PCI_MTOWER_CPLUS: + sni_pcimt_irq_init(); + break; + } } diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c new file mode 100644 index 000000000000..6c0dad7cbf4e --- /dev/null +++ b/arch/mips/sni/pcimt.c @@ -0,0 +1,390 @@ +/* + * PCIMT specific code + * + * 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, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/serial_8250.h> + +#include <asm/mc146818-time.h> +#include <asm/sni.h> +#include <asm/time.h> +#include <asm/i8259.h> +#include <asm/irq_cpu.h> + +#define cacheconf (*(volatile unsigned int *)PCIMT_CACHECONF) +#define invspace (*(volatile unsigned int *)PCIMT_INVSPACE) + +static void __init sni_pcimt_sc_init(void) +{ + unsigned int scsiz, sc_size; + + scsiz = cacheconf & 7; + if (scsiz == 0) { + printk("Second level cache is deactived.\n"); + return; + } + if (scsiz >= 6) { + printk("Invalid second level cache size configured, " + "deactivating second level cache.\n"); + cacheconf = 0; + return; + } + + sc_size = 128 << scsiz; + printk("%dkb second level cache detected, deactivating.\n", sc_size); + cacheconf = 0; +} + + +/* + * A bit more gossip about the iron we're running on ... + */ +static inline void sni_pcimt_detect(void) +{ + char boardtype[80]; + unsigned char csmsr; + char *p = boardtype; + unsigned int asic; + + csmsr = *(volatile unsigned char *)PCIMT_CSMSR; + + p += sprintf(p, "%s PCI", (csmsr & 0x80) ? "RM200" : "RM300"); + if ((csmsr & 0x80) == 0) + p += sprintf(p, ", board revision %s", + (csmsr & 0x20) ? "D" : "C"); + asic = csmsr & 0x80; + asic = (csmsr & 0x08) ? asic : !asic; + p += sprintf(p, ", ASIC PCI Rev %s", asic ? "1.0" : "1.1"); + printk("%s.\n", boardtype); +} + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF, \ + } + +static struct plat_serial8250_port pcimt_data[] = { + PORT(0x3f8, 4), + PORT(0x2f8, 3), + { }, +}; + +static struct platform_device pcimt_serial8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = pcimt_data, + }, +}; + +static struct resource sni_io_resource = { + .start = 0x00001000UL, + .end = 0x03bfffffUL, + .name = "PCIMT IO MEM", + .flags = IORESOURCE_IO, +}; + +static struct resource pcimt_io_resources[] = { + { + .start = 0x00, + .end = 0x1f, + .name = "dma1", + .flags = IORESOURCE_BUSY + }, { + .start = 0x40, + .end = 0x5f, + .name = "timer", + .flags = IORESOURCE_BUSY + }, { + .start = 0x60, + .end = 0x6f, + .name = "keyboard", + .flags = IORESOURCE_BUSY + }, { + .start = 0x80, + .end = 0x8f, + .name = "dma page reg", + .flags = IORESOURCE_BUSY + }, { + .start = 0xc0, + .end = 0xdf, + .name = "dma2", + .flags = IORESOURCE_BUSY + }, { + .start = 0xcfc, + .end = 0xcff, + .name = "PCI config data", + .flags = IORESOURCE_BUSY + } +}; + +static struct resource sni_mem_resource = { + .start = 0x10000000UL, + .end = 0xffffffffUL, + .name = "PCIMT PCI MEM", + .flags = IORESOURCE_MEM +}; + +/* + * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used + * for other purposes. Be paranoid and allocate all of the before the PCI + * code gets a chance to to map anything else there ... + * + * This leaves the following areas available: + * + * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory + * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory + * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory + * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory + * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory + */ +static struct resource pcimt_mem_resources[] = { + { + .start = 0x100a0000, + .end = 0x100bffff, + .name = "Video RAM area", + .flags = IORESOURCE_BUSY + }, { + .start = 0x100c0000, + .end = 0x100fffff, + .name = "ISA Reserved", + .flags = IORESOURCE_BUSY + }, { + .start = 0x14000000, + .end = 0x17bfffff, + .name = "PCI IO", + .flags = IORESOURCE_BUSY + }, { + .start = 0x17c00000, + .end = 0x17ffffff, + .name = "Cache Replacement Area", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1a000000, + .end = 0x1a000003, + .name = "PCI INT Acknowledge", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fc00000, + .end = 0x1fc7ffff, + .name = "Boot PROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fc80000, + .end = 0x1fcfffff, + .name = "Diag PROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fd00000, + .end = 0x1fdfffff, + .name = "X-Bus", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fe00000, + .end = 0x1fefffff, + .name = "BIOS map", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1ff00000, + .end = 0x1ff7ffff, + .name = "NVRAM / EEPROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fff0000, + .end = 0x1fffefff, + .name = "ASIC PCI", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1ffff000, + .end = 0x1fffffff, + .name = "MP Agent", + .flags = IORESOURCE_BUSY + }, { + .start = 0x20000000, + .end = 0x9fffffff, + .name = "Main Memory", + .flags = IORESOURCE_BUSY + } +}; + +static void __init sni_pcimt_resource_init(void) +{ + int i; + + /* request I/O space for devices used on all i[345]86 PCs */ + for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++) + request_resource(&ioport_resource, pcimt_io_resources + i); + + /* request mem space for pcimt-specific devices */ + for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++) + request_resource(&sni_mem_resource, pcimt_mem_resources + i); + + ioport_resource.end = sni_io_resource.end; +} + +extern struct pci_ops sni_pcimt_ops; + +static struct pci_controller sni_controller = { + .pci_ops = &sni_pcimt_ops, + .mem_resource = &sni_mem_resource, + .mem_offset = 0x10000000UL, + .io_resource = &sni_io_resource, + .io_offset = 0x00000000UL +}; + +static void enable_pcimt_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2); + + *(volatile u8 *) PCIMT_IRQSEL |= mask; +} + +void disable_pcimt_irq(unsigned int irq) +{ + unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2)); + + *(volatile u8 *) PCIMT_IRQSEL &= mask; +} + +static void end_pcimt_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_pcimt_irq(irq); +} + +static struct irq_chip pcimt_irq_type = { + .typename = "PCIMT", + .ack = disable_pcimt_irq, + .mask = disable_pcimt_irq, + .mask_ack = disable_pcimt_irq, + .unmask = enable_pcimt_irq, + .end = end_pcimt_irq, +}; + +/* + * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug + * button interrupts. Later ... + */ +static void pcimt_hwint0(void) +{ + panic("Received int0 but no handler yet ..."); +} + +/* + * hwint 1 deals with EISA and SCSI interrupts, + * + * The EISA_INT bit in CSITPEND is high active, all others are low active. + */ +static void pcimt_hwint1(void) +{ + u8 pend = *(volatile char *)PCIMT_CSITPEND; + unsigned long flags; + + if (pend & IT_EISA) { + int irq; + /* + * Note: ASIC PCI's builtin interrupt achknowledge feature is + * broken. Using it may result in loss of some or all i8259 + * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ... + */ + irq = i8259_irq(); + if (unlikely(irq < 0)) + return; + + do_IRQ(irq); + } + + if (!(pend & IT_SCSI)) { + flags = read_c0_status(); + clear_c0_status(ST0_IM); + do_IRQ(PCIMT_IRQ_SCSI); + write_c0_status(flags); + } +} + +/* + * hwint 3 should deal with the PCI A - D interrupts, + */ +static void pcimt_hwint3(void) +{ + u8 pend = *(volatile char *)PCIMT_CSITPEND; + int irq; + + pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD); + pend ^= (IT_INTA | IT_INTB | IT_INTC | IT_INTD); + clear_c0_status(IE_IRQ3); + irq = PCIMT_IRQ_INT2 + ffs(pend) - 1; + do_IRQ(irq); + set_c0_status(IE_IRQ3); +} + +static void sni_pcimt_hwint(void) +{ + u32 pending = (read_c0_cause() & read_c0_status()); + + if (pending & C_IRQ5) + do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7); + else if (pending & C_IRQ4) + do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 6); + else if (pending & C_IRQ3) + pcimt_hwint3(); + else if (pending & C_IRQ1) + pcimt_hwint1(); + else if (pending & C_IRQ0) { + pcimt_hwint0(); + } +} + +void __init sni_pcimt_irq_init(void) +{ + int i; + + *(volatile u8 *) PCIMT_IRQSEL = IT_ETH | IT_EISA; + mips_cpu_irq_init(); + /* Actually we've got more interrupts to handle ... */ + for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_SCSI; i++) + set_irq_chip(i, &pcimt_irq_type); + sni_hwint = sni_pcimt_hwint; + change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ3); +} + +void sni_pcimt_init(void) +{ + sni_pcimt_resource_init(); + sni_pcimt_detect(); + sni_pcimt_sc_init(); + rtc_mips_get_time = mc146818_get_cmos_time; + rtc_mips_set_time = mc146818_set_rtc_mmss; + board_time_init = sni_cpu_time_init; +#ifdef CONFIG_PCI + register_pci_controller(&sni_controller); +#endif +} + +static int __init snirm_pcimt_setup_devinit(void) +{ + switch (sni_brd_type) { + case SNI_BRD_PCI_MTOWER: + case SNI_BRD_PCI_DESKTOP: + case SNI_BRD_PCI_MTOWER_CPLUS: + platform_device_register(&pcimt_serial8250_device); + break; + } + + return 0; +} + +device_initcall(snirm_pcimt_setup_devinit); diff --git a/arch/mips/sni/pcit.c b/arch/mips/sni/pcit.c new file mode 100644 index 000000000000..3921096023c3 --- /dev/null +++ b/arch/mips/sni/pcit.c @@ -0,0 +1,351 @@ +/* + * PCI Tower specific code + * + * 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) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/serial_8250.h> + +#include <asm/mc146818-time.h> +#include <asm/sni.h> +#include <asm/time.h> +#include <asm/irq_cpu.h> + + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF, \ + } + +static struct plat_serial8250_port pcit_data[] = { + PORT(0x3f8, 0), + PORT(0x2f8, 3), + { }, +}; + +static struct platform_device pcit_serial8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = pcit_data, + }, +}; + +static struct plat_serial8250_port pcit_cplus_data[] = { + PORT(0x3f8, 4), + PORT(0x2f8, 3), + PORT(0x3e8, 4), + PORT(0x2e8, 3), + { }, +}; + +static struct platform_device pcit_cplus_serial8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = pcit_cplus_data, + }, +}; + +static struct resource sni_io_resource = { + .start = 0x00001000UL, + .end = 0x03bfffffUL, + .name = "PCIT IO MEM", + .flags = IORESOURCE_IO, +}; + +static struct resource pcit_io_resources[] = { + { + .start = 0x00, + .end = 0x1f, + .name = "dma1", + .flags = IORESOURCE_BUSY + }, { + .start = 0x40, + .end = 0x5f, + .name = "timer", + .flags = IORESOURCE_BUSY + }, { + .start = 0x60, + .end = 0x6f, + .name = "keyboard", + .flags = IORESOURCE_BUSY + }, { + .start = 0x80, + .end = 0x8f, + .name = "dma page reg", + .flags = IORESOURCE_BUSY + }, { + .start = 0xc0, + .end = 0xdf, + .name = "dma2", + .flags = IORESOURCE_BUSY + }, { + .start = 0xcfc, + .end = 0xcff, + .name = "PCI config data", + .flags = IORESOURCE_BUSY + } +}; + +static struct resource sni_mem_resource = { + .start = 0x10000000UL, + .end = 0xffffffffUL, + .name = "PCIT PCI MEM", + .flags = IORESOURCE_MEM +}; + +/* + * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used + * for other purposes. Be paranoid and allocate all of the before the PCI + * code gets a chance to to map anything else there ... + * + * This leaves the following areas available: + * + * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory + * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory + * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory + * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory + * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory + */ +static struct resource pcit_mem_resources[] = { + { + .start = 0x14000000, + .end = 0x17bfffff, + .name = "PCI IO", + .flags = IORESOURCE_BUSY + }, { + .start = 0x17c00000, + .end = 0x17ffffff, + .name = "Cache Replacement Area", + .flags = IORESOURCE_BUSY + }, { + .start = 0x180a0000, + .end = 0x180bffff, + .name = "Video RAM area", + .flags = IORESOURCE_BUSY + }, { + .start = 0x180c0000, + .end = 0x180fffff, + .name = "ISA Reserved", + .flags = IORESOURCE_BUSY + }, { + .start = 0x19000000, + .end = 0x1fbfffff, + .name = "PCI MEM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fc00000, + .end = 0x1fc7ffff, + .name = "Boot PROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fc80000, + .end = 0x1fcfffff, + .name = "Diag PROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fd00000, + .end = 0x1fdfffff, + .name = "X-Bus", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fe00000, + .end = 0x1fefffff, + .name = "BIOS map", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1ff00000, + .end = 0x1ff7ffff, + .name = "NVRAM / EEPROM", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1fff0000, + .end = 0x1fffefff, + .name = "MAUI ASIC", + .flags = IORESOURCE_BUSY + }, { + .start = 0x1ffff000, + .end = 0x1fffffff, + .name = "MP Agent", + .flags = IORESOURCE_BUSY + }, { + .start = 0x20000000, + .end = 0x9fffffff, + .name = "Main Memory", + .flags = IORESOURCE_BUSY + } +}; + +static void __init sni_pcit_resource_init(void) +{ + int i; + + /* request I/O space for devices used on all i[345]86 PCs */ + for (i = 0; i < ARRAY_SIZE(pcit_io_resources); i++) + request_resource(&ioport_resource, pcit_io_resources + i); + + /* request mem space for pcimt-specific devices */ + for (i = 0; i < ARRAY_SIZE(pcit_mem_resources); i++) + request_resource(&sni_mem_resource, pcit_mem_resources + i); + + ioport_resource.end = sni_io_resource.end; +} + + +extern struct pci_ops sni_pcit_ops; + +static struct pci_controller sni_pcit_controller = { + .pci_ops = &sni_pcit_ops, + .mem_resource = &sni_mem_resource, + .mem_offset = 0x10000000UL, + .io_resource = &sni_io_resource, + .io_offset = 0x00000000UL +}; + +static void enable_pcit_irq(unsigned int irq) +{ + u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24); + + *(volatile u32 *)SNI_PCIT_INT_REG |= mask; +} + +void disable_pcit_irq(unsigned int irq) +{ + u32 mask = 1 << (irq - SNI_PCIT_INT_START + 24); + + *(volatile u32 *)SNI_PCIT_INT_REG &= ~mask; +} + +void end_pcit_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_pcit_irq(irq); +} + +static struct irq_chip pcit_irq_type = { + .typename = "PCIT", + .ack = disable_pcit_irq, + .mask = disable_pcit_irq, + .mask_ack = disable_pcit_irq, + .unmask = enable_pcit_irq, + .end = end_pcit_irq, +}; + +static void pcit_hwint1(void) +{ + u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG; + int irq; + + clear_c0_status(IE_IRQ1); + irq = ffs((pending >> 16) & 0x7f); + + if (likely(irq > 0)) + do_IRQ (irq + SNI_PCIT_INT_START - 1); + set_c0_status (IE_IRQ1); +} + +static void pcit_hwint0(void) +{ + u32 pending = *(volatile u32 *)SNI_PCIT_INT_REG; + int irq; + + clear_c0_status(IE_IRQ0); + irq = ffs((pending >> 16) & 0x7f); + + if (likely(irq > 0)) + do_IRQ (irq + SNI_PCIT_INT_START - 1); + set_c0_status (IE_IRQ0); +} + +static void sni_pcit_hwint(void) +{ + u32 pending = (read_c0_cause() & read_c0_status()); + + if (pending & C_IRQ1) + pcit_hwint1(); + else if (pending & C_IRQ2) + do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 4); + else if (pending & C_IRQ3) + do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 5); + else if (pending & C_IRQ5) + do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7); +} + +static void sni_pcit_hwint_cplus(void) +{ + u32 pending = (read_c0_cause() & read_c0_status()); + + if (pending & C_IRQ0) + pcit_hwint0(); + else if (pending & C_IRQ2) + do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 4); + else if (pending & C_IRQ3) + do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 5); + else if (pending & C_IRQ5) + do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7); +} + +void __init sni_pcit_irq_init(void) +{ + int i; + + mips_cpu_irq_init(); + for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++) + set_irq_chip(i, &pcit_irq_type); + *(volatile u32 *)SNI_PCIT_INT_REG = 0; + sni_hwint = sni_pcit_hwint; + change_c0_status(ST0_IM, IE_IRQ1); + setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq); +} + +void __init sni_pcit_cplus_irq_init(void) +{ + int i; + + mips_cpu_irq_init(); + for (i = SNI_PCIT_INT_START; i <= SNI_PCIT_INT_END; i++) + set_irq_chip(i, &pcit_irq_type); + *(volatile u32 *)SNI_PCIT_INT_REG = 0; + sni_hwint = sni_pcit_hwint_cplus; + change_c0_status(ST0_IM, IE_IRQ0); + setup_irq (SNI_PCIT_INT_START + 6, &sni_isa_irq); +} + +void sni_pcit_init(void) +{ + sni_pcit_resource_init(); + rtc_mips_get_time = mc146818_get_cmos_time; + rtc_mips_set_time = mc146818_set_rtc_mmss; + board_time_init = sni_cpu_time_init; +#ifdef CONFIG_PCI + register_pci_controller(&sni_pcit_controller); +#endif +} + +static int __init snirm_pcit_setup_devinit(void) +{ + switch (sni_brd_type) { + case SNI_BRD_PCI_TOWER: + platform_device_register(&pcit_serial8250_device); + break; + + case SNI_BRD_PCI_TOWER_CPLUS: + platform_device_register(&pcit_cplus_serial8250_device); + break; + } + return 0; +} + +device_initcall(snirm_pcit_setup_devinit); diff --git a/arch/mips/sni/reset.c b/arch/mips/sni/reset.c index be85bec002e1..2eada8aea682 100644 --- a/arch/mips/sni/reset.c +++ b/arch/mips/sni/reset.c @@ -13,12 +13,11 @@ * 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) +static inline void kb_wait(void) { int i; - for (i=0; i<0x10000; i++) + for (i = 0; i < 0x10000; i++) if ((inb_p(0x64) & 0x02) == 0) break; } @@ -32,9 +31,9 @@ void sni_machine_restart(char *command) We can do that easier ... */ local_irq_disable(); for (;;) { - for (i=0; i<100; i++) { + for (i = 0; i < 100; i++) { kb_wait(); - for(j = 0; j < 100000 ; j++) + for (j = 0; j < 100000 ; j++) /* nothing */; outb_p(0xfe,0x64); /* pulse reset low */ } diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c new file mode 100644 index 000000000000..517dc698c083 --- /dev/null +++ b/arch/mips/sni/rm200.c @@ -0,0 +1,186 @@ +/* + * RM200 specific code + * + * 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) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> + +#include <asm/sni.h> +#include <asm/time.h> +#include <asm/ds1216.h> +#include <asm/irq_cpu.h> + +#define PORT(_base,_irq) \ + { \ + .iobase = _base, \ + .irq = _irq, \ + .uartclk = 1843200, \ + .iotype = UPIO_PORT, \ + .flags = UPF_BOOT_AUTOCONF, \ + } + +static struct plat_serial8250_port rm200_data[] = { + PORT(0x3f8, 4), + PORT(0x2f8, 3), + { }, +}; + +static struct platform_device rm200_serial8250_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = rm200_data, + }, +}; + +static struct resource snirm_82596_rm200_rsrc[] = { + { + .start = 0xb8000000, + .end = 0xb80fffff, + .flags = IORESOURCE_MEM + }, + { + .start = 0xbb000000, + .end = 0xbb000004, + .flags = IORESOURCE_MEM + }, + { + .start = 0xbff00000, + .end = 0xbff00020, + .flags = IORESOURCE_MEM + }, + { + .start = 27, + .end = 27, + .flags = IORESOURCE_IRQ + }, + { + .flags = 0x00 + } +}; + +static struct platform_device snirm_82596_rm200_pdev = { + .name = "snirm_82596", + .num_resources = ARRAY_SIZE(snirm_82596_rm200_rsrc), + .resource = snirm_82596_rm200_rsrc +}; + +static struct resource snirm_53c710_rm200_rsrc[] = { + { + .start = 0xb9000000, + .end = 0xb90fffff, + .flags = IORESOURCE_MEM + }, + { + .start = 26, + .end = 26, + .flags = IORESOURCE_IRQ + } +}; + +static struct platform_device snirm_53c710_rm200_pdev = { + .name = "snirm_53c710", + .num_resources = ARRAY_SIZE(snirm_53c710_rm200_rsrc), + .resource = snirm_53c710_rm200_rsrc +}; + +static int __init snirm_setup_devinit(void) +{ + if (sni_brd_type == SNI_BRD_RM200) { + platform_device_register(&rm200_serial8250_device); + platform_device_register(&snirm_82596_rm200_pdev); + platform_device_register(&snirm_53c710_rm200_pdev); + } + return 0; +} + +device_initcall(snirm_setup_devinit); + + +#define SNI_RM200_INT_STAT_REG 0xbc000000 +#define SNI_RM200_INT_ENA_REG 0xbc080000 + +#define SNI_RM200_INT_START 24 +#define SNI_RM200_INT_END 28 + +static void enable_rm200_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq - SNI_RM200_INT_START); + + *(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask; +} + +void disable_rm200_irq(unsigned int irq) +{ + unsigned int mask = 1 << (irq - SNI_RM200_INT_START); + + *(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask; +} + +void end_rm200_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) + enable_rm200_irq(irq); +} + +static struct irq_chip rm200_irq_type = { + .typename = "RM200", + .ack = disable_rm200_irq, + .mask = disable_rm200_irq, + .mask_ack = disable_rm200_irq, + .unmask = enable_rm200_irq, + .end = end_rm200_irq, +}; + +static void sni_rm200_hwint(void) +{ + u32 pending = read_c0_cause() & read_c0_status(); + u8 mask; + u8 stat; + int irq; + + if (pending & C_IRQ5) + do_IRQ (SNI_MIPS_IRQ_CPU_BASE + 7); + else if (pending & C_IRQ0) { + clear_c0_status (IE_IRQ0); + mask = *(volatile u8 *)SNI_RM200_INT_ENA_REG ^ 0x1f; + stat = *(volatile u8 *)SNI_RM200_INT_STAT_REG ^ 0x14; + irq = ffs(stat & mask & 0x1f); + + if (likely(irq > 0)) + do_IRQ (irq + SNI_RM200_INT_START - 1); + set_c0_status (IE_IRQ0); + } +} + +void __init sni_rm200_irq_init(void) +{ + int i; + + * (volatile u8 *)SNI_RM200_INT_ENA_REG = 0x1f; + + mips_cpu_irq_init(); + /* Actually we've got more interrupts to handle ... */ + for (i = SNI_RM200_INT_START; i <= SNI_RM200_INT_END; i++) + set_irq_chip(i, &rm200_irq_type); + sni_hwint = sni_rm200_hwint; + change_c0_status(ST0_IM, IE_IRQ0); + setup_irq (SNI_RM200_INT_START + 0, &sni_isa_irq); +} + +void sni_rm200_init(void) +{ + set_io_port_base(SNI_PORT_BASE + 0x02000000); + ioport_resource.end += 0x02000000; + ds1216_base = (volatile unsigned char *) SNI_DS1216_RM200_BASE; + rtc_mips_get_time = ds1216_get_cmos_time; + board_time_init = sni_cpu_time_init; +} diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c index afeb7f13e5b5..68d7cf609b4f 100644 --- a/arch/mips/sni/setup.c +++ b/arch/mips/sni/setup.c @@ -6,16 +6,10 @@ * for more details. * * Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2006 Thomas Bogendoerfer (tsbogend@alpha.franken.de) */ #include <linux/eisa.h> -#include <linux/hdreg.h> -#include <linux/ioport.h> -#include <linux/sched.h> #include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/mc146818rtc.h> -#include <linux/pm.h> -#include <linux/pci.h> #include <linux/console.h> #include <linux/fb.h> #include <linux/screen_info.h> @@ -25,52 +19,16 @@ #include <asm/sgialib.h> #endif -#include <asm/bcache.h> -#include <asm/bootinfo.h> #include <asm/io.h> -#include <asm/irq.h> -#include <asm/mc146818-time.h> -#include <asm/processor.h> #include <asm/reboot.h> #include <asm/sni.h> -#include <asm/time.h> -#include <asm/traps.h> + +unsigned int sni_brd_type; extern void sni_machine_restart(char *command); extern void sni_machine_halt(void); extern void sni_machine_power_off(void); -void __init plat_timer_setup(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_irq(0, irq); -} - -/* - * A bit more gossip about the iron we're running on ... - */ -static inline void sni_pcimt_detect(void) -{ - char boardtype[80]; - unsigned char csmsr; - char *p = boardtype; - unsigned int asic; - - csmsr = *(volatile unsigned char *)PCIMT_CSMSR; - - p += sprintf(p, "%s PCI", (csmsr & 0x80) ? "RM200" : "RM300"); - if ((csmsr & 0x80) == 0) - p += sprintf(p, ", board revision %s", - (csmsr & 0x20) ? "D" : "C"); - asic = csmsr & 0x80; - asic = (csmsr & 0x08) ? asic : !asic; - p += sprintf(p, ", ASIC PCI Rev %s", asic ? "1.0" : "1.1"); - printk("%s.\n", boardtype); -} - static void __init sni_display_setup(void) { #if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) && defined(CONFIG_ARC) @@ -90,175 +48,11 @@ static void __init sni_display_setup(void) #endif } -static struct resource sni_io_resource = { - .start = 0x00001000UL, - .end = 0x03bfffffUL, - .name = "PCIMT IO MEM", - .flags = IORESOURCE_IO, -}; - -static struct resource pcimt_io_resources[] = { - { - .start = 0x00, - .end = 0x1f, - .name = "dma1", - .flags = IORESOURCE_BUSY - }, { - .start = 0x40, - .end = 0x5f, - .name = "timer", - .flags = IORESOURCE_BUSY - }, { - .start = 0x60, - .end = 0x6f, - .name = "keyboard", - .flags = IORESOURCE_BUSY - }, { - .start = 0x80, - .end = 0x8f, - .name = "dma page reg", - .flags = IORESOURCE_BUSY - }, { - .start = 0xc0, - .end = 0xdf, - .name = "dma2", - .flags = IORESOURCE_BUSY - }, { - .start = 0xcfc, - .end = 0xcff, - .name = "PCI config data", - .flags = IORESOURCE_BUSY - } -}; - -static struct resource sni_mem_resource = { - .start = 0x10000000UL, - .end = 0xffffffffUL, - .name = "PCIMT PCI MEM", - .flags = IORESOURCE_MEM -}; - -/* - * The RM200/RM300 has a few holes in it's PCI/EISA memory address space used - * for other purposes. Be paranoid and allocate all of the before the PCI - * code gets a chance to to map anything else there ... - * - * This leaves the following areas available: - * - * 0x10000000 - 0x1009ffff (640kB) PCI/EISA/ISA Bus Memory - * 0x10100000 - 0x13ffffff ( 15MB) PCI/EISA/ISA Bus Memory - * 0x18000000 - 0x1fbfffff (124MB) PCI/EISA Bus Memory - * 0x1ff08000 - 0x1ffeffff (816kB) PCI/EISA Bus Memory - * 0xa0000000 - 0xffffffff (1.5GB) PCI/EISA Bus Memory - */ -static struct resource pcimt_mem_resources[] = { - { - .start = 0x100a0000, - .end = 0x100bffff, - .name = "Video RAM area", - .flags = IORESOURCE_BUSY - }, { - .start = 0x100c0000, - .end = 0x100fffff, - .name = "ISA Reserved", - .flags = IORESOURCE_BUSY - }, { - .start = 0x14000000, - .end = 0x17bfffff, - .name = "PCI IO", - .flags = IORESOURCE_BUSY - }, { - .start = 0x17c00000, - .end = 0x17ffffff, - .name = "Cache Replacement Area", - .flags = IORESOURCE_BUSY - }, { - .start = 0x1a000000, - .end = 0x1a000003, - .name = "PCI INT Acknowledge", - .flags = IORESOURCE_BUSY - }, { - .start = 0x1fc00000, - .end = 0x1fc7ffff, - .name = "Boot PROM", - .flags = IORESOURCE_BUSY - }, { - .start = 0x1fc80000, - .end = 0x1fcfffff, - .name = "Diag PROM", - .flags = IORESOURCE_BUSY - }, { - .start = 0x1fd00000, - .end = 0x1fdfffff, - .name = "X-Bus", - .flags = IORESOURCE_BUSY - }, { - .start = 0x1fe00000, - .end = 0x1fefffff, - .name = "BIOS map", - .flags = IORESOURCE_BUSY - }, { - .start = 0x1ff00000, - .end = 0x1ff7ffff, - .name = "NVRAM / EEPROM", - .flags = IORESOURCE_BUSY - }, { - .start = 0x1fff0000, - .end = 0x1fffefff, - .name = "ASIC PCI", - .flags = IORESOURCE_BUSY - }, { - .start = 0x1ffff000, - .end = 0x1fffffff, - .name = "MP Agent", - .flags = IORESOURCE_BUSY - }, { - .start = 0x20000000, - .end = 0x9fffffff, - .name = "Main Memory", - .flags = IORESOURCE_BUSY - } -}; - -static void __init sni_resource_init(void) -{ - int i; - - /* request I/O space for devices used on all i[345]86 PCs */ - for (i = 0; i < ARRAY_SIZE(pcimt_io_resources); i++) - request_resource(&ioport_resource, pcimt_io_resources + i); - - /* request mem space for pcimt-specific devices */ - for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++) - request_resource(&sni_mem_resource, pcimt_mem_resources + i); - - ioport_resource.end = sni_io_resource.end; -} - -extern struct pci_ops sni_pci_ops; - -static struct pci_controller sni_controller = { - .pci_ops = &sni_pci_ops, - .mem_resource = &sni_mem_resource, - .mem_offset = 0x10000000UL, - .io_resource = &sni_io_resource, - .io_offset = 0x00000000UL -}; - -static inline void sni_pcimt_time_init(void) -{ - rtc_mips_get_time = mc146818_get_cmos_time; - rtc_mips_set_time = mc146818_set_rtc_mmss; -} void __init plat_mem_setup(void) { - sni_pcimt_detect(); - sni_pcimt_sc_init(); - sni_pcimt_time_init(); - set_io_port_base(SNI_PORT_BASE); - ioport_resource.end = sni_io_resource.end; +// ioport_resource.end = sni_io_resource.end; /* * Setup (E)ISA I/O memory access stuff @@ -268,15 +62,33 @@ void __init plat_mem_setup(void) EISA_bus = 1; #endif - sni_resource_init(); + switch (sni_brd_type) { + case SNI_BRD_10: + case SNI_BRD_10NEW: + case SNI_BRD_TOWER_OASIC: + case SNI_BRD_MINITOWER: + sni_a20r_init(); + break; + + case SNI_BRD_PCI_TOWER: + case SNI_BRD_PCI_TOWER_CPLUS: + sni_pcit_init(); + break; + + case SNI_BRD_RM200: + sni_rm200_init(); + break; + + case SNI_BRD_PCI_MTOWER: + case SNI_BRD_PCI_DESKTOP: + case SNI_BRD_PCI_MTOWER_CPLUS: + sni_pcimt_init(); + break; + } _machine_restart = sni_machine_restart; _machine_halt = sni_machine_halt; pm_power_off = sni_machine_power_off; sni_display_setup(); - -#ifdef CONFIG_PCI - register_pci_controller(&sni_controller); -#endif } diff --git a/arch/mips/sni/sniprom.c b/arch/mips/sni/sniprom.c index 1213d166f22e..6a44bbf0b732 100644 --- a/arch/mips/sni/sniprom.c +++ b/arch/mips/sni/sniprom.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> +#include <linux/console.h> #include <asm/addrspace.h> #include <asm/sni.h> @@ -31,7 +32,7 @@ #define PROM_ENTRY(x) (PROM_VEC + (x)) -#undef DEBUG +#define DEBUG #ifdef DEBUG #define DBG_PRINTF(x...) prom_printf(x) #else @@ -93,14 +94,14 @@ static void sni_idprom_dump(void) { int i; - prom_printf("SNI IDProm dump (first 128byte):\n"); - for(i=0;i<128;i++) { + prom_printf("SNI IDProm dump:\n"); + for (i = 0; i < 256; i++) { if (i%16 == 0) prom_printf("%04x ", i); - prom_printf("%02x ", *(unsigned char *) (SNI_IDPROM_BASE+i)); + prom_printf("%02x ", *(unsigned char *) (SNI_IDPROM_BASE + i)); - if (i%16 == 15) + if (i % 16 == 15) prom_printf("\n"); } } @@ -118,7 +119,7 @@ static void sni_mem_init(void ) } memconf[8]; /* MemSIZE from prom in 16MByte chunks */ - memsize=*((unsigned char *) SNI_IDPROM_MEMSIZE) * 16; + memsize = *((unsigned char *) SNI_IDPROM_MEMSIZE) * 16; DBG_PRINTF("IDProm memsize: %lu MByte\n", memsize); @@ -126,26 +127,134 @@ static void sni_mem_init(void ) __prom_get_memconf(&memconf); DBG_PRINTF("prom_get_mem_conf memory configuration:\n"); - for(i=0;i<8 && memconf[i].size;i++) { - prom_printf("Bank%d: %08x @ %08x\n", i, + for (i = 0;i < 8 && memconf[i].size; i++) { + if (sni_brd_type == SNI_BRD_PCI_TOWER || + sni_brd_type == SNI_BRD_PCI_TOWER_CPLUS) { + if (memconf[i].base >= 0x20000000 && + memconf[i].base < 0x30000000) { + memconf[i].base -= 0x20000000; + } + } + DBG_PRINTF("Bank%d: %08x @ %08x\n", i, memconf[i].size, memconf[i].base); add_memory_region(memconf[i].base, memconf[i].size, BOOT_MEM_RAM); } } +static void __init sni_console_setup(void) +{ + char *ctype; + char *cdev; + char *baud; + int port; + static char options[8]; + + cdev = prom_getenv ("console_dev"); + if (strncmp (cdev, "tty", 3) == 0) { + ctype = prom_getenv ("console"); + switch (*ctype) { + default: + case 'l': + port = 0; + baud = prom_getenv("lbaud"); + break; + case 'r': + port = 1; + baud = prom_getenv("rbaud"); + break; + } + if (baud) + strcpy(options, baud); + add_preferred_console("ttyS", port, baud ? options : NULL); + } +} + void __init prom_init(void) { int argc = fw_arg0; char **argv = (void *)fw_arg1; - unsigned int sni_brd_type = *(unsigned char *) SNI_IDPROM_BRDTYPE; int i; + int cputype; - DBG_PRINTF("Found SNI brdtype %02x\n", sni_brd_type); + sni_brd_type = *(unsigned char *)SNI_IDPROM_BRDTYPE; + cputype = *(unsigned char *)SNI_IDPROM_CPUTYPE; + switch (sni_brd_type) { + case SNI_BRD_TOWER_OASIC: + switch (cputype) { + case SNI_CPU_M8030: + systype = "RM400-330"; + break; + case SNI_CPU_M8031: + systype = "RM400-430"; + break; + case SNI_CPU_M8037: + systype = "RM400-530"; + break; + case SNI_CPU_M8034: + systype = "RM400-730"; + break; + default: + systype = "RM400-xxx"; + break; + } + break; + case SNI_BRD_MINITOWER: + switch (cputype) { + case SNI_CPU_M8021: + case SNI_CPU_M8043: + systype = "RM400-120"; + break; + case SNI_CPU_M8040: + systype = "RM400-220"; + break; + case SNI_CPU_M8053: + systype = "RM400-225"; + break; + case SNI_CPU_M8050: + systype = "RM400-420"; + break; + default: + systype = "RM400-xxx"; + break; + } + break; + case SNI_BRD_PCI_TOWER: + systype = "RM400-Cxx"; + break; + case SNI_BRD_RM200: + systype = "RM200-xxx"; + break; + case SNI_BRD_PCI_MTOWER: + systype = "RM300-Cxx"; + break; + case SNI_BRD_PCI_DESKTOP: + switch (read_c0_prid() & 0xff00) { + case PRID_IMP_R4600: + case PRID_IMP_R4700: + systype = "RM200-C20"; + break; + case PRID_IMP_R5000: + systype = "RM200-C40"; + break; + default: + systype = "RM200-Cxx"; + break; + } + break; + case SNI_BRD_PCI_TOWER_CPLUS: + systype = "RM400-Exx"; + break; + case SNI_BRD_PCI_MTOWER_CPLUS: + systype = "RM300-Exx"; + break; + } + DBG_PRINTF("Found SNI brdtype %02x name %s\n", sni_brd_type,systype); #ifdef DEBUG sni_idprom_dump(); #endif sni_mem_init(); + sni_console_setup(); /* copy prom cmdline parameters to kernel cmdline */ for (i = 1; i < argc; i++) { diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c new file mode 100644 index 000000000000..20028fc7757e --- /dev/null +++ b/arch/mips/sni/time.c @@ -0,0 +1,148 @@ +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/time.h> + +#include <asm/sni.h> +#include <asm/time.h> + +#define SNI_CLOCK_TICK_RATE 3686400 +#define SNI_COUNTER2_DIV 64 +#define SNI_COUNTER0_DIV ((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ) + +static void sni_a20r_timer_ack(void) +{ + *(volatile u8 *)A20R_PT_TIM0_ACK = 0x0; wmb(); +} + +/* + * a20r platform uses 2 counters to divide the input frequency. + * Counter 2 output is connected to Counter 0 & 1 input. + */ +static void __init sni_a20r_timer_setup(struct irqaction *irq) +{ + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = (SNI_COUNTER0_DIV) & 0xff; wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = (SNI_COUNTER0_DIV >> 8) & 0xff; wmb(); + + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = (SNI_COUNTER2_DIV) & 0xff; wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = (SNI_COUNTER2_DIV >> 8) & 0xff; wmb(); + + setup_irq(SNI_A20R_IRQ_TIMER, irq); + mips_timer_ack = sni_a20r_timer_ack; +} + +#define SNI_8254_TICK_RATE 1193182UL + +#define SNI_8254_TCSAMP_COUNTER ((SNI_8254_TICK_RATE / HZ) + 255) + +static __init unsigned long dosample(void) +{ + u32 ct0, ct1; + volatile u8 msb, lsb; + + /* Start the counter. */ + outb_p (0x34, 0x43); + outb_p(SNI_8254_TCSAMP_COUNTER & 0xff, 0x40); + outb (SNI_8254_TCSAMP_COUNTER >> 8, 0x40); + + /* Get initial counter invariant */ + ct0 = read_c0_count(); + + /* Latch and spin until top byte of counter0 is zero */ + do { + outb (0x00, 0x43); + lsb = inb (0x40); + msb = inb (0x40); + ct1 = read_c0_count(); + } while (msb); + + /* Stop the counter. */ + outb (0x38, 0x43); + /* + * Return the difference, this is how far the r4k counter increments + * for every 1/HZ seconds. We round off the nearest 1 MHz of master + * clock (= 1000000 / HZ / 2). + */ + /*return (ct1 - ct0 + (500000/HZ/2)) / (500000/HZ) * (500000/HZ);*/ + return (ct1 - ct0) / (500000/HZ) * (500000/HZ); +} + +/* + * Here we need to calibrate the cycle counter to at least be close. + */ +__init void sni_cpu_time_init(void) +{ + unsigned long r4k_ticks[3]; + unsigned long r4k_tick; + + /* + * Figure out the r4k offset, the algorithm is very simple and works in + * _all_ cases as long as the 8254 counter register itself works ok (as + * an interrupt driving timer it does not because of bug, this is why + * we are using the onchip r4k counter/compare register to serve this + * purpose, but for r4k_offset calculation it will work ok for us). + * There are other very complicated ways of performing this calculation + * but this one works just fine so I am not going to futz around. ;-) + */ + printk(KERN_INFO "Calibrating system timer... "); + dosample(); /* Prime cache. */ + dosample(); /* Prime cache. */ + /* Zero is NOT an option. */ + do { + r4k_ticks[0] = dosample(); + } while (!r4k_ticks[0]); + do { + r4k_ticks[1] = dosample(); + } while (!r4k_ticks[1]); + + if (r4k_ticks[0] != r4k_ticks[1]) { + printk("warning: timer counts differ, retrying... "); + r4k_ticks[2] = dosample(); + if (r4k_ticks[2] == r4k_ticks[0] + || r4k_ticks[2] == r4k_ticks[1]) + r4k_tick = r4k_ticks[2]; + else { + printk("disagreement, using average... "); + r4k_tick = (r4k_ticks[0] + r4k_ticks[1] + + r4k_ticks[2]) / 3; + } + } else + r4k_tick = r4k_ticks[0]; + + printk("%d [%d.%04d MHz CPU]\n", (int) r4k_tick, + (int) (r4k_tick / (500000 / HZ)), + (int) (r4k_tick % (500000 / HZ))); + + mips_hpt_frequency = r4k_tick * HZ; +} + +/* + * R4k counter based timer interrupt. Works on RM200-225 and possibly + * others but not on RM400 + */ +static void __init sni_cpu_timer_setup(struct irqaction *irq) +{ + setup_irq(SNI_MIPS_IRQ_CPU_TIMER, irq); +} + +void __init plat_timer_setup(struct irqaction *irq) +{ + switch (sni_brd_type) { + case SNI_BRD_10: + case SNI_BRD_10NEW: + case SNI_BRD_TOWER_OASIC: + case SNI_BRD_MINITOWER: + sni_a20r_timer_setup (irq); + break; + + case SNI_BRD_PCI_TOWER: + case SNI_BRD_RM200: + case SNI_BRD_PCI_MTOWER: + case SNI_BRD_PCI_DESKTOP: + case SNI_BRD_PCI_TOWER_CPLUS: + case SNI_BRD_PCI_MTOWER_CPLUS: + sni_cpu_timer_setup (irq); + break; + } +} |