add idl4k kernel firmware version 1.13.0.105

This commit is contained in:
Jaroslav Kysela
2015-03-26 17:22:37 +01:00
parent 5194d2792e
commit e9070cdc77
31064 changed files with 12769984 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
#
# Makefile for the SNI specific part of the kernel
#
obj-y += irq.o reset.o setup.o a20r.o rm200.o pcimt.o pcit.o time.o
obj-$(CONFIG_EISA) += eisa.o
EXTRA_CFLAGS += -Werror

249
kernel/arch/mips/sni/a20r.c Normal file
View File

@@ -0,0 +1,249 @@
/*
* 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>
#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 a20r_ds1216_rsrc[] = {
{
.start = 0x1c081ffc,
.end = 0x1c081fff,
.flags = IORESOURCE_MEM
}
};
static struct platform_device a20r_ds1216_device = {
.name = "rtc-ds1216",
.num_resources = ARRAY_SIZE(a20r_ds1216_rsrc),
.resource = a20r_ds1216_rsrc
};
static struct resource snirm_82596_rsrc[] = {
{
.start = 0x18000000,
.end = 0x18000004,
.flags = IORESOURCE_MEM
},
{
.start = 0x18010000,
.end = 0x18010004,
.flags = IORESOURCE_MEM
},
{
.start = 0x1ff00000,
.end = 0x1ff00020,
.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 = 0x19000000,
.end = 0x190fffff,
.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 = 0x1c070000,
.end = 0x1c0700ff,
.flags = IORESOURCE_MEM
},
{
.start = 20,
.end = 20,
.flags = IORESOURCE_IRQ
}
};
static unsigned int sc26xx_data[2] = {
/* DTR | RTS | DSR | CTS | DCD | RI */
(8 << 0) | (4 << 4) | (6 << 8) | (0 << 12) | (6 << 16) | (0 << 20),
(3 << 0) | (2 << 4) | (1 << 8) | (2 << 12) | (3 << 16) | (4 << 20)
};
static struct platform_device sc26xx_pdev = {
.name = "SC26xx",
.num_resources = ARRAY_SIZE(sc26xx_rsrc),
.resource = sc26xx_rsrc,
.dev = {
.platform_data = sc26xx_data,
}
};
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_and_handler(i, &a20r_irq_type, handle_level_irq);
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)
{
/* FIXME, remove if not needed */
}
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);
platform_device_register(&a20r_ds1216_device);
sni_eisa_root_init();
break;
}
return 0;
}
device_initcall(snirm_a20r_setup_devinit);

View File

@@ -0,0 +1,50 @@
/*
* Virtual EISA root driver.
* Acts as a placeholder if we don't have a proper EISA bridge.
*
* (C) 2003 Marc Zyngier <maz@wild-wind.fr.eu.org>
* modified for SNI usage by Thomas Bogendoerfer
*
* This code is released under the GPL version 2.
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/eisa.h>
#include <linux/init.h>
/* The default EISA device parent (virtual root device).
* Now use a platform device, since that's the obvious choice. */
static struct platform_device eisa_root_dev = {
.name = "eisa",
.id = 0,
};
static struct eisa_root_device eisa_bus_root = {
.dev = &eisa_root_dev.dev,
.bus_base_addr = 0,
.res = &ioport_resource,
.slots = EISA_MAX_SLOTS,
.dma_mask = 0xffffffff,
.force_probe = 1,
};
int __init sni_eisa_root_init(void)
{
int r;
r = platform_device_register(&eisa_root_dev);
if (!r)
return r;
dev_set_drvdata(&eisa_root_dev.dev, &eisa_bus_root);
if (eisa_root_register(&eisa_bus_root)) {
/* A real bridge may have been registered before
* us. So quietly unregister. */
platform_device_unregister(&eisa_root_dev);
return -1;
}
return 0;
}

View File

@@ -0,0 +1,82 @@
/*
* 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) 1992 Linus Torvalds
* Copyright (C) 1994 - 2000 Ralf Baechle
* Copyright (C) 2006 Thomas Bogendoerfer
*/
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <asm/i8259.h>
#include <asm/io.h>
#include <asm/sni.h>
#include <asm/irq.h>
#include <asm/irq_cpu.h>
void (*sni_hwint)(void);
asmlinkage void plat_irq_dispatch(void)
{
sni_hwint();
}
/* ISA irq handler */
static irqreturn_t sni_isa_irq_handler(int dummy, void *p)
{
int irq;
irq = i8259_irq();
if (unlikely(irq < 0))
return IRQ_NONE;
generic_handle_irq(irq);
return IRQ_HANDLED;
}
struct irqaction sni_isa_irq = {
.handler = sni_isa_irq_handler,
.name = "ISA",
.flags = IRQF_SHARED | IRQF_DISABLED
};
/*
* On systems with i8259-style interrupt controllers we assume for
* driver compatibility reasons interrupts 0 - 15 to be the i8295
* interrupts even if the hardware uses a different interrupt numbering.
*/
void __init arch_init_irq(void)
{
init_i8259_irqs(); /* Integrated i8259 */
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;
}
}

View File

@@ -0,0 +1,338 @@
/*
* 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,2007 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/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 pcimt_cmos_rsrc[] = {
{
.start = 0x70,
.end = 0x71,
.flags = IORESOURCE_IO
},
{
.start = 8,
.end = 8,
.flags = IORESOURCE_IRQ
}
};
static struct platform_device pcimt_cmos_device = {
.name = "rtc_cmos",
.num_resources = ARRAY_SIZE(pcimt_cmos_rsrc),
.resource = pcimt_cmos_rsrc
};
static struct resource sni_io_resource = {
.start = 0x00000000UL,
.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 pcimt_mem_resources[] = {
{
/*
* this region should only be 4 bytes long,
* but it's 16MB on all RM300C I've checked
*/
.start = 0x1a000000,
.end = 0x1affffff,
.name = "PCI INT ACK",
.flags = IORESOURCE_BUSY
}
};
static struct resource sni_mem_resource = {
.start = 0x18000000UL,
.end = 0x1fbfffffUL,
.name = "PCIMT PCI MEM",
.flags = IORESOURCE_MEM
};
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(&sni_io_resource, pcimt_io_resources + i);
/* request MEM space for devices used on all i[345]86 PCs */
for (i = 0; i < ARRAY_SIZE(pcimt_mem_resources); i++)
request_resource(&sni_mem_resource, pcimt_mem_resources + i);
}
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 = 0x00000000UL,
.io_resource = &sni_io_resource,
.io_offset = 0x00000000UL,
.io_map_base = SNI_PORT_BASE
};
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 acknowledge feature is
* broken. Using it may result in loss of some or all i8259
* interrupts, 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(MIPS_CPU_IRQ_BASE + 7);
else if (pending & C_IRQ4)
do_IRQ(MIPS_CPU_IRQ_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_and_handler(i, &pcimt_irq_type, handle_level_irq);
sni_hwint = sni_pcimt_hwint;
change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ3);
}
void __init sni_pcimt_init(void)
{
sni_pcimt_detect();
sni_pcimt_sc_init();
ioport_resource.end = sni_io_resource.end;
#ifdef CONFIG_PCI
PCIBIOS_MIN_IO = 0x9000;
register_pci_controller(&sni_controller);
#endif
sni_pcimt_resource_init();
}
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);
platform_device_register(&pcimt_cmos_device);
break;
}
return 0;
}
device_initcall(snirm_pcimt_setup_devinit);

297
kernel/arch/mips/sni/pcit.c Normal file
View File

@@ -0,0 +1,297 @@
/*
* 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/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, 0),
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 pcit_cmos_rsrc[] = {
{
.start = 0x70,
.end = 0x71,
.flags = IORESOURCE_IO
},
{
.start = 8,
.end = 8,
.flags = IORESOURCE_IRQ
}
};
static struct platform_device pcit_cmos_device = {
.name = "rtc_cmos",
.num_resources = ARRAY_SIZE(pcit_cmos_rsrc),
.resource = pcit_cmos_rsrc
};
static struct platform_device pcit_pcspeaker_pdev = {
.name = "pcspkr",
.id = -1,
};
static struct resource sni_io_resource = {
.start = 0x00000000UL,
.end = 0x03bfffffUL,
.name = "PCIT IO",
.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 = 0xcf8,
.end = 0xcfb,
.name = "PCI config addr",
.flags = IORESOURCE_BUSY
}, {
.start = 0xcfc,
.end = 0xcff,
.name = "PCI config data",
.flags = IORESOURCE_BUSY
}
};
static struct resource sni_mem_resource = {
.start = 0x18000000UL,
.end = 0x1fbfffffUL,
.name = "PCIT PCI MEM",
.flags = IORESOURCE_MEM
};
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(&sni_io_resource, pcit_io_resources + i);
}
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 = 0x00000000UL,
.io_resource = &sni_io_resource,
.io_offset = 0x00000000UL,
.io_map_base = SNI_PORT_BASE
};
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) & 0x3f);
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(MIPS_CPU_IRQ_BASE + 4);
else if (pending & C_IRQ3)
do_IRQ(MIPS_CPU_IRQ_BASE + 5);
else if (pending & C_IRQ5)
do_IRQ(MIPS_CPU_IRQ_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_IRQ1)
do_IRQ(MIPS_CPU_IRQ_BASE + 3);
else if (pending & C_IRQ2)
do_IRQ(MIPS_CPU_IRQ_BASE + 4);
else if (pending & C_IRQ3)
do_IRQ(MIPS_CPU_IRQ_BASE + 5);
else if (pending & C_IRQ5)
do_IRQ(MIPS_CPU_IRQ_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_and_handler(i, &pcit_irq_type, handle_level_irq);
*(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_and_handler(i, &pcit_irq_type, handle_level_irq);
*(volatile u32 *)SNI_PCIT_INT_REG = 0x40000000;
sni_hwint = sni_pcit_hwint_cplus;
change_c0_status(ST0_IM, IE_IRQ0);
setup_irq(MIPS_CPU_IRQ_BASE + 3, &sni_isa_irq);
}
void __init sni_pcit_init(void)
{
ioport_resource.end = sni_io_resource.end;
#ifdef CONFIG_PCI
PCIBIOS_MIN_IO = 0x9000;
register_pci_controller(&sni_pcit_controller);
#endif
sni_pcit_resource_init();
}
static int __init snirm_pcit_setup_devinit(void)
{
switch (sni_brd_type) {
case SNI_BRD_PCI_TOWER:
platform_device_register(&pcit_serial8250_device);
platform_device_register(&pcit_cmos_device);
platform_device_register(&pcit_pcspeaker_pdev);
break;
case SNI_BRD_PCI_TOWER_CPLUS:
platform_device_register(&pcit_cplus_serial8250_device);
platform_device_register(&pcit_cmos_device);
platform_device_register(&pcit_pcspeaker_pdev);
break;
}
return 0;
}
device_initcall(snirm_pcit_setup_devinit);

View File

@@ -0,0 +1,46 @@
/*
* linux/arch/mips/sni/process.c
*
* Reset a SNI machine.
*/
#include <asm/io.h>
#include <asm/reboot.h>
#include <asm/system.h>
#include <asm/sni.h>
/*
* This routine reboots the machine by asking the keyboard
* controller to pulse the reset-line low. We try that for a while,
* and if it doesn't work, we do some other stupid things.
*/
static inline void kb_wait(void)
{
int i;
for (i = 0; i < 0x10000; i++)
if ((inb_p(0x64) & 0x02) == 0)
break;
}
/* XXX This ends up at the ARC firmware prompt ... */
void sni_machine_restart(char *command)
{
int i, j;
/* This does a normal via the keyboard controller like a PC.
We can do that easier ... */
local_irq_disable();
for (;;) {
for (i = 0; i < 100; i++) {
kb_wait();
for (j = 0; j < 100000 ; j++)
/* nothing */;
outb_p(0xfe, 0x64); /* pulse reset low */
}
}
}
void sni_machine_power_off(void)
{
*(volatile unsigned char *)PCIMT_CSWCSM = 0xfd;
}

View File

@@ -0,0 +1,500 @@
/*
* 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,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
*
* i8259 parts ripped out of arch/mips/kernel/i8259.c
*/
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/io.h>
#include <asm/sni.h>
#include <asm/time.h>
#include <asm/irq_cpu.h>
#define RM200_I8259A_IRQ_BASE 32
#define MEMPORT(_base,_irq) \
{ \
.mapbase = _base, \
.irq = _irq, \
.uartclk = 1843200, \
.iotype = UPIO_MEM, \
.flags = UPF_BOOT_AUTOCONF|UPF_IOREMAP, \
}
static struct plat_serial8250_port rm200_data[] = {
MEMPORT(0x160003f8, RM200_I8259A_IRQ_BASE + 4),
MEMPORT(0x160002f8, RM200_I8259A_IRQ_BASE + 3),
{ },
};
static struct platform_device rm200_serial8250_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = {
.platform_data = rm200_data,
},
};
static struct resource rm200_ds1216_rsrc[] = {
{
.start = 0x1cd41ffc,
.end = 0x1cd41fff,
.flags = IORESOURCE_MEM
}
};
static struct platform_device rm200_ds1216_device = {
.name = "rtc-ds1216",
.num_resources = ARRAY_SIZE(rm200_ds1216_rsrc),
.resource = rm200_ds1216_rsrc
};
static struct resource snirm_82596_rm200_rsrc[] = {
{
.start = 0x18000000,
.end = 0x180fffff,
.flags = IORESOURCE_MEM
},
{
.start = 0x1b000000,
.end = 0x1b000004,
.flags = IORESOURCE_MEM
},
{
.start = 0x1ff00000,
.end = 0x1ff00020,
.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 = 0x19000000,
.end = 0x190fffff,
.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(&rm200_ds1216_device);
platform_device_register(&snirm_82596_rm200_pdev);
platform_device_register(&snirm_53c710_rm200_pdev);
sni_eisa_root_init();
}
return 0;
}
device_initcall(snirm_setup_devinit);
/*
* RM200 has an ISA and an EISA bus. The iSA bus is only used
* for onboard devices and also has twi i8259 PICs. Since these
* PICs are no accessible via inb/outb the following code uses
* readb/writeb to access them
*/
DEFINE_SPINLOCK(sni_rm200_i8259A_lock);
#define PIC_CMD 0x00
#define PIC_IMR 0x01
#define PIC_ISR PIC_CMD
#define PIC_POLL PIC_ISR
#define PIC_OCW3 PIC_ISR
/* i8259A PIC related value */
#define PIC_CASCADE_IR 2
#define MASTER_ICW4_DEFAULT 0x01
#define SLAVE_ICW4_DEFAULT 0x01
/*
* This contains the irq mask for both 8259A irq controllers,
*/
static unsigned int rm200_cached_irq_mask = 0xffff;
static __iomem u8 *rm200_pic_master;
static __iomem u8 *rm200_pic_slave;
#define cached_master_mask (rm200_cached_irq_mask)
#define cached_slave_mask (rm200_cached_irq_mask >> 8)
static void sni_rm200_disable_8259A_irq(unsigned int irq)
{
unsigned int mask;
unsigned long flags;
irq -= RM200_I8259A_IRQ_BASE;
mask = 1 << irq;
spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
rm200_cached_irq_mask |= mask;
if (irq & 8)
writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
else
writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
}
static void sni_rm200_enable_8259A_irq(unsigned int irq)
{
unsigned int mask;
unsigned long flags;
irq -= RM200_I8259A_IRQ_BASE;
mask = ~(1 << irq);
spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
rm200_cached_irq_mask &= mask;
if (irq & 8)
writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
else
writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
}
static inline int sni_rm200_i8259A_irq_real(unsigned int irq)
{
int value;
int irqmask = 1 << irq;
if (irq < 8) {
writeb(0x0B, rm200_pic_master + PIC_CMD);
value = readb(rm200_pic_master + PIC_CMD) & irqmask;
writeb(0x0A, rm200_pic_master + PIC_CMD);
return value;
}
writeb(0x0B, rm200_pic_slave + PIC_CMD); /* ISR register */
value = readb(rm200_pic_slave + PIC_CMD) & (irqmask >> 8);
writeb(0x0A, rm200_pic_slave + PIC_CMD);
return value;
}
/*
* Careful! The 8259A is a fragile beast, it pretty
* much _has_ to be done exactly like this (mask it
* first, _then_ send the EOI, and the order of EOI
* to the two 8259s is important!
*/
void sni_rm200_mask_and_ack_8259A(unsigned int irq)
{
unsigned int irqmask;
unsigned long flags;
irq -= RM200_I8259A_IRQ_BASE;
irqmask = 1 << irq;
spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
/*
* Lightweight spurious IRQ detection. We do not want
* to overdo spurious IRQ handling - it's usually a sign
* of hardware problems, so we only do the checks we can
* do without slowing down good hardware unnecessarily.
*
* Note that IRQ7 and IRQ15 (the two spurious IRQs
* usually resulting from the 8259A-1|2 PICs) occur
* even if the IRQ is masked in the 8259A. Thus we
* can check spurious 8259A IRQs without doing the
* quite slow i8259A_irq_real() call for every IRQ.
* This does not cover 100% of spurious interrupts,
* but should be enough to warn the user that there
* is something bad going on ...
*/
if (rm200_cached_irq_mask & irqmask)
goto spurious_8259A_irq;
rm200_cached_irq_mask |= irqmask;
handle_real_irq:
if (irq & 8) {
readb(rm200_pic_slave + PIC_IMR);
writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
writeb(0x60+(irq & 7), rm200_pic_slave + PIC_CMD);
writeb(0x60+PIC_CASCADE_IR, rm200_pic_master + PIC_CMD);
} else {
readb(rm200_pic_master + PIC_IMR);
writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
writeb(0x60+irq, rm200_pic_master + PIC_CMD);
}
spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
return;
spurious_8259A_irq:
/*
* this is the slow path - should happen rarely.
*/
if (sni_rm200_i8259A_irq_real(irq))
/*
* oops, the IRQ _is_ in service according to the
* 8259A - not spurious, go handle it.
*/
goto handle_real_irq;
{
static int spurious_irq_mask;
/*
* At this point we can be sure the IRQ is spurious,
* lets ACK and report it. [once per IRQ]
*/
if (!(spurious_irq_mask & irqmask)) {
printk(KERN_DEBUG
"spurious RM200 8259A interrupt: IRQ%d.\n", irq);
spurious_irq_mask |= irqmask;
}
atomic_inc(&irq_err_count);
/*
* Theoretically we do not have to handle this IRQ,
* but in Linux this does not cause problems and is
* simpler for us.
*/
goto handle_real_irq;
}
}
static struct irq_chip sni_rm200_i8259A_chip = {
.name = "RM200-XT-PIC",
.mask = sni_rm200_disable_8259A_irq,
.unmask = sni_rm200_enable_8259A_irq,
.mask_ack = sni_rm200_mask_and_ack_8259A,
};
/*
* Do the traditional i8259 interrupt polling thing. This is for the few
* cases where no better interrupt acknowledge method is available and we
* absolutely must touch the i8259.
*/
static inline int sni_rm200_i8259_irq(void)
{
int irq;
spin_lock(&sni_rm200_i8259A_lock);
/* Perform an interrupt acknowledge cycle on controller 1. */
writeb(0x0C, rm200_pic_master + PIC_CMD); /* prepare for poll */
irq = readb(rm200_pic_master + PIC_CMD) & 7;
if (irq == PIC_CASCADE_IR) {
/*
* Interrupt is cascaded so perform interrupt
* acknowledge on controller 2.
*/
writeb(0x0C, rm200_pic_slave + PIC_CMD); /* prepare for poll */
irq = (readb(rm200_pic_slave + PIC_CMD) & 7) + 8;
}
if (unlikely(irq == 7)) {
/*
* This may be a spurious interrupt.
*
* Read the interrupt status register (ISR). If the most
* significant bit is not set then there is no valid
* interrupt.
*/
writeb(0x0B, rm200_pic_master + PIC_ISR); /* ISR register */
if (~readb(rm200_pic_master + PIC_ISR) & 0x80)
irq = -1;
}
spin_unlock(&sni_rm200_i8259A_lock);
return likely(irq >= 0) ? irq + RM200_I8259A_IRQ_BASE : irq;
}
void sni_rm200_init_8259A(void)
{
unsigned long flags;
spin_lock_irqsave(&sni_rm200_i8259A_lock, flags);
writeb(0xff, rm200_pic_master + PIC_IMR);
writeb(0xff, rm200_pic_slave + PIC_IMR);
writeb(0x11, rm200_pic_master + PIC_CMD);
writeb(0, rm200_pic_master + PIC_IMR);
writeb(1U << PIC_CASCADE_IR, rm200_pic_master + PIC_IMR);
writeb(MASTER_ICW4_DEFAULT, rm200_pic_master + PIC_IMR);
writeb(0x11, rm200_pic_slave + PIC_CMD);
writeb(8, rm200_pic_slave + PIC_IMR);
writeb(PIC_CASCADE_IR, rm200_pic_slave + PIC_IMR);
writeb(SLAVE_ICW4_DEFAULT, rm200_pic_slave + PIC_IMR);
udelay(100); /* wait for 8259A to initialize */
writeb(cached_master_mask, rm200_pic_master + PIC_IMR);
writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR);
spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags);
}
/*
* IRQ2 is cascade interrupt to second interrupt controller
*/
static struct irqaction sni_rm200_irq2 = {
.handler = no_action,
.name = "cascade",
};
static struct resource sni_rm200_pic1_resource = {
.name = "onboard ISA pic1",
.start = 0x16000020,
.end = 0x16000023,
.flags = IORESOURCE_BUSY
};
static struct resource sni_rm200_pic2_resource = {
.name = "onboard ISA pic2",
.start = 0x160000a0,
.end = 0x160000a3,
.flags = IORESOURCE_BUSY
};
/* ISA irq handler */
static irqreturn_t sni_rm200_i8259A_irq_handler(int dummy, void *p)
{
int irq;
irq = sni_rm200_i8259_irq();
if (unlikely(irq < 0))
return IRQ_NONE;
do_IRQ(irq);
return IRQ_HANDLED;
}
struct irqaction sni_rm200_i8259A_irq = {
.handler = sni_rm200_i8259A_irq_handler,
.name = "onboard ISA",
.flags = IRQF_SHARED
};
void __init sni_rm200_i8259_irqs(void)
{
int i;
rm200_pic_master = ioremap_nocache(0x16000020, 4);
if (!rm200_pic_master)
return;
rm200_pic_slave = ioremap_nocache(0x160000a0, 4);
if (!rm200_pic_master) {
iounmap(rm200_pic_master);
return;
}
insert_resource(&iomem_resource, &sni_rm200_pic1_resource);
insert_resource(&iomem_resource, &sni_rm200_pic2_resource);
sni_rm200_init_8259A();
for (i = RM200_I8259A_IRQ_BASE; i < RM200_I8259A_IRQ_BASE + 16; i++)
set_irq_chip_and_handler(i, &sni_rm200_i8259A_chip,
handle_level_irq);
setup_irq(RM200_I8259A_IRQ_BASE + PIC_CASCADE_IR, &sni_rm200_irq2);
}
#define SNI_RM200_INT_STAT_REG CKSEG1ADDR(0xbc000000)
#define SNI_RM200_INT_ENA_REG CKSEG1ADDR(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(MIPS_CPU_IRQ_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;
sni_rm200_i8259_irqs();
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_and_handler(i, &rm200_irq_type, handle_level_irq);
sni_hwint = sni_rm200_hwint;
change_c0_status(ST0_IM, IE_IRQ0);
setup_irq(SNI_RM200_INT_START + 0, &sni_rm200_i8259A_irq);
setup_irq(SNI_RM200_INT_START + 1, &sni_isa_irq);
}
void __init sni_rm200_init(void)
{
}

View File

@@ -0,0 +1,261 @@
/*
* Setup pointers to hardware-dependent routines.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1996, 97, 98, 2000, 03, 04, 06 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
*/
#include <linux/eisa.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/fb.h>
#include <linux/screen_info.h>
#ifdef CONFIG_ARC
#include <asm/fw/arc/types.h>
#include <asm/sgialib.h>
#endif
#ifdef CONFIG_SNIPROM
#include <asm/mipsprom.h>
#endif
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/reboot.h>
#include <asm/sni.h>
unsigned int sni_brd_type;
EXPORT_SYMBOL(sni_brd_type);
extern void sni_machine_restart(char *command);
extern void sni_machine_power_off(void);
static void __init sni_display_setup(void)
{
#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE) && defined(CONFIG_ARC)
struct screen_info *si = &screen_info;
DISPLAY_STATUS *di;
di = ArcGetDisplayStatus(1);
if (di) {
si->orig_x = di->CursorXPosition;
si->orig_y = di->CursorYPosition;
si->orig_video_cols = di->CursorMaxXPosition;
si->orig_video_lines = di->CursorMaxYPosition;
si->orig_video_isVGA = VIDEO_TYPE_VGAC;
si->orig_video_points = 16;
}
#endif
}
static void __init sni_console_setup(void)
{
#ifndef CONFIG_ARC
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);
if (strncmp(cdev, "tty552", 6) == 0)
add_preferred_console("ttyS", port,
baud ? options : NULL);
else
add_preferred_console("ttySC", port,
baud ? options : NULL);
}
#endif
}
#ifdef DEBUG
static void __init sni_idprom_dump(void)
{
int i;
pr_debug("SNI IDProm dump:\n");
for (i = 0; i < 256; i++) {
if (i%16 == 0)
pr_debug("%04x ", i);
printk("%02x ", *(unsigned char *) (SNI_IDPROM_BASE + i));
if (i % 16 == 15)
printk("\n");
}
}
#endif
void __init plat_mem_setup(void)
{
int cputype;
set_io_port_base(SNI_PORT_BASE);
// ioport_resource.end = sni_io_resource.end;
/*
* Setup (E)ISA I/O memory access stuff
*/
#ifdef CONFIG_EISA
EISA_bus = 1;
#endif
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:
system_type = "RM400-330";
break;
case SNI_CPU_M8031:
system_type = "RM400-430";
break;
case SNI_CPU_M8037:
system_type = "RM400-530";
break;
case SNI_CPU_M8034:
system_type = "RM400-730";
break;
default:
system_type = "RM400-xxx";
break;
}
break;
case SNI_BRD_MINITOWER:
switch (cputype) {
case SNI_CPU_M8021:
case SNI_CPU_M8043:
system_type = "RM400-120";
break;
case SNI_CPU_M8040:
system_type = "RM400-220";
break;
case SNI_CPU_M8053:
system_type = "RM400-225";
break;
case SNI_CPU_M8050:
system_type = "RM400-420";
break;
default:
system_type = "RM400-xxx";
break;
}
break;
case SNI_BRD_PCI_TOWER:
system_type = "RM400-Cxx";
break;
case SNI_BRD_RM200:
system_type = "RM200-xxx";
break;
case SNI_BRD_PCI_MTOWER:
system_type = "RM300-Cxx";
break;
case SNI_BRD_PCI_DESKTOP:
switch (read_c0_prid() & 0xff00) {
case PRID_IMP_R4600:
case PRID_IMP_R4700:
system_type = "RM200-C20";
break;
case PRID_IMP_R5000:
system_type = "RM200-C40";
break;
default:
system_type = "RM200-Cxx";
break;
}
break;
case SNI_BRD_PCI_TOWER_CPLUS:
system_type = "RM400-Exx";
break;
case SNI_BRD_PCI_MTOWER_CPLUS:
system_type = "RM300-Exx";
break;
}
pr_debug("Found SNI brdtype %02x name %s\n", sni_brd_type, system_type);
#ifdef DEBUG
sni_idprom_dump();
#endif
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;
pm_power_off = sni_machine_power_off;
sni_display_setup();
sni_console_setup();
}
#ifdef CONFIG_PCI
#include <linux/pci.h>
#include <video/vga.h>
#include <video/cirrus.h>
static void __devinit quirk_cirrus_ram_size(struct pci_dev *dev)
{
u16 cmd;
/*
* firmware doesn't set the ram size correct, so we
* need to do it here, otherwise we get screen corruption
* on older Cirrus chips
*/
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if ((cmd & (PCI_COMMAND_IO|PCI_COMMAND_MEMORY))
== (PCI_COMMAND_IO|PCI_COMMAND_MEMORY)) {
vga_wseq(NULL, CL_SEQR6, 0x12); /* unlock all extension registers */
vga_wseq(NULL, CL_SEQRF, 0x18);
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5434_8,
quirk_cirrus_ram_size);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5436,
quirk_cirrus_ram_size);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446,
quirk_cirrus_ram_size);
#endif

189
kernel/arch/mips/sni/time.c Normal file
View File

@@ -0,0 +1,189 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/time.h>
#include <linux/clockchips.h>
#include <asm/i8253.h>
#include <asm/sni.h>
#include <asm/time.h>
#include <asm-generic/rtc.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 a20r_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
*(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34;
wmb();
*(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV;
wmb();
*(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8;
wmb();
*(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4;
wmb();
*(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV;
wmb();
*(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8;
wmb();
break;
case CLOCK_EVT_MODE_ONESHOT:
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
break;
case CLOCK_EVT_MODE_RESUME:
break;
}
}
static struct clock_event_device a20r_clockevent_device = {
.name = "a20r-timer",
.features = CLOCK_EVT_FEAT_PERIODIC,
/* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */
.rating = 300,
.irq = SNI_A20R_IRQ_TIMER,
.set_mode = a20r_set_mode,
};
static irqreturn_t a20r_interrupt(int irq, void *dev_id)
{
struct clock_event_device *cd = dev_id;
*(volatile u8 *)A20R_PT_TIM0_ACK = 0;
wmb();
cd->event_handler(cd);
return IRQ_HANDLED;
}
static struct irqaction a20r_irqaction = {
.handler = a20r_interrupt,
.flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
.name = "a20r-timer",
};
/*
* 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(void)
{
struct clock_event_device *cd = &a20r_clockevent_device;
struct irqaction *action = &a20r_irqaction;
unsigned int cpu = smp_processor_id();
cd->cpumask = cpumask_of(cpu);
clockevents_register_device(cd);
action->dev_id = cd;
setup_irq(SNI_A20R_IRQ_TIMER, &a20r_irqaction);
}
#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.
*/
void __init plat_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;
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();
break;
}
setup_pit_timer();
}
void read_persistent_clock(struct timespec *ts)
{
ts->tv_sec = -1;
ts->tv_nsec = 0;
}