| /* | 
 |  * 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 (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; | 
 |  | 
 | 	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; | 
 | } |