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