187 lines
4.0 KiB
C
187 lines
4.0 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|