18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * RM200 specific code 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 58c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 68c2ecf20Sopenharmony_ci * for more details. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2006,2007 Thomas Bogendoerfer (tsbogend@alpha.franken.de) 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * i8259 parts ripped out of arch/mips/kernel/i8259.c 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <linux/init.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/irq.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/serial_8250.h> 198c2ecf20Sopenharmony_ci#include <linux/io.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/sni.h> 228c2ecf20Sopenharmony_ci#include <asm/time.h> 238c2ecf20Sopenharmony_ci#include <asm/irq_cpu.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define RM200_I8259A_IRQ_BASE 32 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define MEMPORT(_base,_irq) \ 288c2ecf20Sopenharmony_ci { \ 298c2ecf20Sopenharmony_ci .mapbase = _base, \ 308c2ecf20Sopenharmony_ci .irq = _irq, \ 318c2ecf20Sopenharmony_ci .uartclk = 1843200, \ 328c2ecf20Sopenharmony_ci .iotype = UPIO_MEM, \ 338c2ecf20Sopenharmony_ci .flags = UPF_BOOT_AUTOCONF|UPF_IOREMAP, \ 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic struct plat_serial8250_port rm200_data[] = { 378c2ecf20Sopenharmony_ci MEMPORT(0x160003f8, RM200_I8259A_IRQ_BASE + 4), 388c2ecf20Sopenharmony_ci MEMPORT(0x160002f8, RM200_I8259A_IRQ_BASE + 3), 398c2ecf20Sopenharmony_ci { }, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic struct platform_device rm200_serial8250_device = { 438c2ecf20Sopenharmony_ci .name = "serial8250", 448c2ecf20Sopenharmony_ci .id = PLAT8250_DEV_PLATFORM, 458c2ecf20Sopenharmony_ci .dev = { 468c2ecf20Sopenharmony_ci .platform_data = rm200_data, 478c2ecf20Sopenharmony_ci }, 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic struct resource rm200_ds1216_rsrc[] = { 518c2ecf20Sopenharmony_ci { 528c2ecf20Sopenharmony_ci .start = 0x1cd41ffc, 538c2ecf20Sopenharmony_ci .end = 0x1cd41fff, 548c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic struct platform_device rm200_ds1216_device = { 598c2ecf20Sopenharmony_ci .name = "rtc-ds1216", 608c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(rm200_ds1216_rsrc), 618c2ecf20Sopenharmony_ci .resource = rm200_ds1216_rsrc 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic struct resource snirm_82596_rm200_rsrc[] = { 658c2ecf20Sopenharmony_ci { 668c2ecf20Sopenharmony_ci .start = 0x18000000, 678c2ecf20Sopenharmony_ci .end = 0x180fffff, 688c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM 698c2ecf20Sopenharmony_ci }, 708c2ecf20Sopenharmony_ci { 718c2ecf20Sopenharmony_ci .start = 0x1b000000, 728c2ecf20Sopenharmony_ci .end = 0x1b000004, 738c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM 748c2ecf20Sopenharmony_ci }, 758c2ecf20Sopenharmony_ci { 768c2ecf20Sopenharmony_ci .start = 0x1ff00000, 778c2ecf20Sopenharmony_ci .end = 0x1ff00020, 788c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM 798c2ecf20Sopenharmony_ci }, 808c2ecf20Sopenharmony_ci { 818c2ecf20Sopenharmony_ci .start = 27, 828c2ecf20Sopenharmony_ci .end = 27, 838c2ecf20Sopenharmony_ci .flags = IORESOURCE_IRQ 848c2ecf20Sopenharmony_ci }, 858c2ecf20Sopenharmony_ci { 868c2ecf20Sopenharmony_ci .flags = 0x00 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic struct platform_device snirm_82596_rm200_pdev = { 918c2ecf20Sopenharmony_ci .name = "snirm_82596", 928c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(snirm_82596_rm200_rsrc), 938c2ecf20Sopenharmony_ci .resource = snirm_82596_rm200_rsrc 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic struct resource snirm_53c710_rm200_rsrc[] = { 978c2ecf20Sopenharmony_ci { 988c2ecf20Sopenharmony_ci .start = 0x19000000, 998c2ecf20Sopenharmony_ci .end = 0x190fffff, 1008c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM 1018c2ecf20Sopenharmony_ci }, 1028c2ecf20Sopenharmony_ci { 1038c2ecf20Sopenharmony_ci .start = 26, 1048c2ecf20Sopenharmony_ci .end = 26, 1058c2ecf20Sopenharmony_ci .flags = IORESOURCE_IRQ 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic struct platform_device snirm_53c710_rm200_pdev = { 1108c2ecf20Sopenharmony_ci .name = "snirm_53c710", 1118c2ecf20Sopenharmony_ci .num_resources = ARRAY_SIZE(snirm_53c710_rm200_rsrc), 1128c2ecf20Sopenharmony_ci .resource = snirm_53c710_rm200_rsrc 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int __init snirm_setup_devinit(void) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci if (sni_brd_type == SNI_BRD_RM200) { 1188c2ecf20Sopenharmony_ci platform_device_register(&rm200_serial8250_device); 1198c2ecf20Sopenharmony_ci platform_device_register(&rm200_ds1216_device); 1208c2ecf20Sopenharmony_ci platform_device_register(&snirm_82596_rm200_pdev); 1218c2ecf20Sopenharmony_ci platform_device_register(&snirm_53c710_rm200_pdev); 1228c2ecf20Sopenharmony_ci sni_eisa_root_init(); 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci return 0; 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cidevice_initcall(snirm_setup_devinit); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* 1308c2ecf20Sopenharmony_ci * RM200 has an ISA and an EISA bus. The iSA bus is only used 1318c2ecf20Sopenharmony_ci * for onboard devices and also has twi i8259 PICs. Since these 1328c2ecf20Sopenharmony_ci * PICs are no accessible via inb/outb the following code uses 1338c2ecf20Sopenharmony_ci * readb/writeb to access them 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic DEFINE_RAW_SPINLOCK(sni_rm200_i8259A_lock); 1378c2ecf20Sopenharmony_ci#define PIC_CMD 0x00 1388c2ecf20Sopenharmony_ci#define PIC_IMR 0x01 1398c2ecf20Sopenharmony_ci#define PIC_ISR PIC_CMD 1408c2ecf20Sopenharmony_ci#define PIC_POLL PIC_ISR 1418c2ecf20Sopenharmony_ci#define PIC_OCW3 PIC_ISR 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* i8259A PIC related value */ 1448c2ecf20Sopenharmony_ci#define PIC_CASCADE_IR 2 1458c2ecf20Sopenharmony_ci#define MASTER_ICW4_DEFAULT 0x01 1468c2ecf20Sopenharmony_ci#define SLAVE_ICW4_DEFAULT 0x01 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* 1498c2ecf20Sopenharmony_ci * This contains the irq mask for both 8259A irq controllers, 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_cistatic unsigned int rm200_cached_irq_mask = 0xffff; 1528c2ecf20Sopenharmony_cistatic __iomem u8 *rm200_pic_master; 1538c2ecf20Sopenharmony_cistatic __iomem u8 *rm200_pic_slave; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#define cached_master_mask (rm200_cached_irq_mask) 1568c2ecf20Sopenharmony_ci#define cached_slave_mask (rm200_cached_irq_mask >> 8) 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void sni_rm200_disable_8259A_irq(struct irq_data *d) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci unsigned int mask, irq = d->irq - RM200_I8259A_IRQ_BASE; 1618c2ecf20Sopenharmony_ci unsigned long flags; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci mask = 1 << irq; 1648c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); 1658c2ecf20Sopenharmony_ci rm200_cached_irq_mask |= mask; 1668c2ecf20Sopenharmony_ci if (irq & 8) 1678c2ecf20Sopenharmony_ci writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR); 1688c2ecf20Sopenharmony_ci else 1698c2ecf20Sopenharmony_ci writeb(cached_master_mask, rm200_pic_master + PIC_IMR); 1708c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void sni_rm200_enable_8259A_irq(struct irq_data *d) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci unsigned int mask, irq = d->irq - RM200_I8259A_IRQ_BASE; 1768c2ecf20Sopenharmony_ci unsigned long flags; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci mask = ~(1 << irq); 1798c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); 1808c2ecf20Sopenharmony_ci rm200_cached_irq_mask &= mask; 1818c2ecf20Sopenharmony_ci if (irq & 8) 1828c2ecf20Sopenharmony_ci writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR); 1838c2ecf20Sopenharmony_ci else 1848c2ecf20Sopenharmony_ci writeb(cached_master_mask, rm200_pic_master + PIC_IMR); 1858c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic inline int sni_rm200_i8259A_irq_real(unsigned int irq) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci int value; 1918c2ecf20Sopenharmony_ci int irqmask = 1 << irq; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (irq < 8) { 1948c2ecf20Sopenharmony_ci writeb(0x0B, rm200_pic_master + PIC_CMD); 1958c2ecf20Sopenharmony_ci value = readb(rm200_pic_master + PIC_CMD) & irqmask; 1968c2ecf20Sopenharmony_ci writeb(0x0A, rm200_pic_master + PIC_CMD); 1978c2ecf20Sopenharmony_ci return value; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci writeb(0x0B, rm200_pic_slave + PIC_CMD); /* ISR register */ 2008c2ecf20Sopenharmony_ci value = readb(rm200_pic_slave + PIC_CMD) & (irqmask >> 8); 2018c2ecf20Sopenharmony_ci writeb(0x0A, rm200_pic_slave + PIC_CMD); 2028c2ecf20Sopenharmony_ci return value; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci/* 2068c2ecf20Sopenharmony_ci * Careful! The 8259A is a fragile beast, it pretty 2078c2ecf20Sopenharmony_ci * much _has_ to be done exactly like this (mask it 2088c2ecf20Sopenharmony_ci * first, _then_ send the EOI, and the order of EOI 2098c2ecf20Sopenharmony_ci * to the two 8259s is important! 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_civoid sni_rm200_mask_and_ack_8259A(struct irq_data *d) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci unsigned int irqmask, irq = d->irq - RM200_I8259A_IRQ_BASE; 2148c2ecf20Sopenharmony_ci unsigned long flags; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci irqmask = 1 << irq; 2178c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); 2188c2ecf20Sopenharmony_ci /* 2198c2ecf20Sopenharmony_ci * Lightweight spurious IRQ detection. We do not want 2208c2ecf20Sopenharmony_ci * to overdo spurious IRQ handling - it's usually a sign 2218c2ecf20Sopenharmony_ci * of hardware problems, so we only do the checks we can 2228c2ecf20Sopenharmony_ci * do without slowing down good hardware unnecessarily. 2238c2ecf20Sopenharmony_ci * 2248c2ecf20Sopenharmony_ci * Note that IRQ7 and IRQ15 (the two spurious IRQs 2258c2ecf20Sopenharmony_ci * usually resulting from the 8259A-1|2 PICs) occur 2268c2ecf20Sopenharmony_ci * even if the IRQ is masked in the 8259A. Thus we 2278c2ecf20Sopenharmony_ci * can check spurious 8259A IRQs without doing the 2288c2ecf20Sopenharmony_ci * quite slow i8259A_irq_real() call for every IRQ. 2298c2ecf20Sopenharmony_ci * This does not cover 100% of spurious interrupts, 2308c2ecf20Sopenharmony_ci * but should be enough to warn the user that there 2318c2ecf20Sopenharmony_ci * is something bad going on ... 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci if (rm200_cached_irq_mask & irqmask) 2348c2ecf20Sopenharmony_ci goto spurious_8259A_irq; 2358c2ecf20Sopenharmony_ci rm200_cached_irq_mask |= irqmask; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cihandle_real_irq: 2388c2ecf20Sopenharmony_ci if (irq & 8) { 2398c2ecf20Sopenharmony_ci readb(rm200_pic_slave + PIC_IMR); 2408c2ecf20Sopenharmony_ci writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR); 2418c2ecf20Sopenharmony_ci writeb(0x60+(irq & 7), rm200_pic_slave + PIC_CMD); 2428c2ecf20Sopenharmony_ci writeb(0x60+PIC_CASCADE_IR, rm200_pic_master + PIC_CMD); 2438c2ecf20Sopenharmony_ci } else { 2448c2ecf20Sopenharmony_ci readb(rm200_pic_master + PIC_IMR); 2458c2ecf20Sopenharmony_ci writeb(cached_master_mask, rm200_pic_master + PIC_IMR); 2468c2ecf20Sopenharmony_ci writeb(0x60+irq, rm200_pic_master + PIC_CMD); 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags); 2498c2ecf20Sopenharmony_ci return; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cispurious_8259A_irq: 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * this is the slow path - should happen rarely. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_ci if (sni_rm200_i8259A_irq_real(irq)) 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * oops, the IRQ _is_ in service according to the 2588c2ecf20Sopenharmony_ci * 8259A - not spurious, go handle it. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci goto handle_real_irq; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci { 2638c2ecf20Sopenharmony_ci static int spurious_irq_mask; 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * At this point we can be sure the IRQ is spurious, 2668c2ecf20Sopenharmony_ci * let's ACK and report it. [once per IRQ] 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_ci if (!(spurious_irq_mask & irqmask)) { 2698c2ecf20Sopenharmony_ci printk(KERN_DEBUG 2708c2ecf20Sopenharmony_ci "spurious RM200 8259A interrupt: IRQ%d.\n", irq); 2718c2ecf20Sopenharmony_ci spurious_irq_mask |= irqmask; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci atomic_inc(&irq_err_count); 2748c2ecf20Sopenharmony_ci /* 2758c2ecf20Sopenharmony_ci * Theoretically we do not have to handle this IRQ, 2768c2ecf20Sopenharmony_ci * but in Linux this does not cause problems and is 2778c2ecf20Sopenharmony_ci * simpler for us. 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_ci goto handle_real_irq; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic struct irq_chip sni_rm200_i8259A_chip = { 2848c2ecf20Sopenharmony_ci .name = "RM200-XT-PIC", 2858c2ecf20Sopenharmony_ci .irq_mask = sni_rm200_disable_8259A_irq, 2868c2ecf20Sopenharmony_ci .irq_unmask = sni_rm200_enable_8259A_irq, 2878c2ecf20Sopenharmony_ci .irq_mask_ack = sni_rm200_mask_and_ack_8259A, 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci/* 2918c2ecf20Sopenharmony_ci * Do the traditional i8259 interrupt polling thing. This is for the few 2928c2ecf20Sopenharmony_ci * cases where no better interrupt acknowledge method is available and we 2938c2ecf20Sopenharmony_ci * absolutely must touch the i8259. 2948c2ecf20Sopenharmony_ci */ 2958c2ecf20Sopenharmony_cistatic inline int sni_rm200_i8259_irq(void) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci int irq; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci raw_spin_lock(&sni_rm200_i8259A_lock); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Perform an interrupt acknowledge cycle on controller 1. */ 3028c2ecf20Sopenharmony_ci writeb(0x0C, rm200_pic_master + PIC_CMD); /* prepare for poll */ 3038c2ecf20Sopenharmony_ci irq = readb(rm200_pic_master + PIC_CMD) & 7; 3048c2ecf20Sopenharmony_ci if (irq == PIC_CASCADE_IR) { 3058c2ecf20Sopenharmony_ci /* 3068c2ecf20Sopenharmony_ci * Interrupt is cascaded so perform interrupt 3078c2ecf20Sopenharmony_ci * acknowledge on controller 2. 3088c2ecf20Sopenharmony_ci */ 3098c2ecf20Sopenharmony_ci writeb(0x0C, rm200_pic_slave + PIC_CMD); /* prepare for poll */ 3108c2ecf20Sopenharmony_ci irq = (readb(rm200_pic_slave + PIC_CMD) & 7) + 8; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (unlikely(irq == 7)) { 3148c2ecf20Sopenharmony_ci /* 3158c2ecf20Sopenharmony_ci * This may be a spurious interrupt. 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * Read the interrupt status register (ISR). If the most 3188c2ecf20Sopenharmony_ci * significant bit is not set then there is no valid 3198c2ecf20Sopenharmony_ci * interrupt. 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_ci writeb(0x0B, rm200_pic_master + PIC_ISR); /* ISR register */ 3228c2ecf20Sopenharmony_ci if (~readb(rm200_pic_master + PIC_ISR) & 0x80) 3238c2ecf20Sopenharmony_ci irq = -1; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci raw_spin_unlock(&sni_rm200_i8259A_lock); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return likely(irq >= 0) ? irq + RM200_I8259A_IRQ_BASE : irq; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_civoid sni_rm200_init_8259A(void) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci unsigned long flags; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&sni_rm200_i8259A_lock, flags); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci writeb(0xff, rm200_pic_master + PIC_IMR); 3388c2ecf20Sopenharmony_ci writeb(0xff, rm200_pic_slave + PIC_IMR); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci writeb(0x11, rm200_pic_master + PIC_CMD); 3418c2ecf20Sopenharmony_ci writeb(0, rm200_pic_master + PIC_IMR); 3428c2ecf20Sopenharmony_ci writeb(1U << PIC_CASCADE_IR, rm200_pic_master + PIC_IMR); 3438c2ecf20Sopenharmony_ci writeb(MASTER_ICW4_DEFAULT, rm200_pic_master + PIC_IMR); 3448c2ecf20Sopenharmony_ci writeb(0x11, rm200_pic_slave + PIC_CMD); 3458c2ecf20Sopenharmony_ci writeb(8, rm200_pic_slave + PIC_IMR); 3468c2ecf20Sopenharmony_ci writeb(PIC_CASCADE_IR, rm200_pic_slave + PIC_IMR); 3478c2ecf20Sopenharmony_ci writeb(SLAVE_ICW4_DEFAULT, rm200_pic_slave + PIC_IMR); 3488c2ecf20Sopenharmony_ci udelay(100); /* wait for 8259A to initialize */ 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci writeb(cached_master_mask, rm200_pic_master + PIC_IMR); 3518c2ecf20Sopenharmony_ci writeb(cached_slave_mask, rm200_pic_slave + PIC_IMR); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&sni_rm200_i8259A_lock, flags); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/* 3578c2ecf20Sopenharmony_ci * IRQ2 is cascade interrupt to second interrupt controller 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic struct resource sni_rm200_pic1_resource = { 3618c2ecf20Sopenharmony_ci .name = "onboard ISA pic1", 3628c2ecf20Sopenharmony_ci .start = 0x16000020, 3638c2ecf20Sopenharmony_ci .end = 0x16000023, 3648c2ecf20Sopenharmony_ci .flags = IORESOURCE_BUSY 3658c2ecf20Sopenharmony_ci}; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic struct resource sni_rm200_pic2_resource = { 3688c2ecf20Sopenharmony_ci .name = "onboard ISA pic2", 3698c2ecf20Sopenharmony_ci .start = 0x160000a0, 3708c2ecf20Sopenharmony_ci .end = 0x160000a3, 3718c2ecf20Sopenharmony_ci .flags = IORESOURCE_BUSY 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci/* ISA irq handler */ 3758c2ecf20Sopenharmony_cistatic irqreturn_t sni_rm200_i8259A_irq_handler(int dummy, void *p) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci int irq; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci irq = sni_rm200_i8259_irq(); 3808c2ecf20Sopenharmony_ci if (unlikely(irq < 0)) 3818c2ecf20Sopenharmony_ci return IRQ_NONE; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci do_IRQ(irq); 3848c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_civoid __init sni_rm200_i8259_irqs(void) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci int i; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci rm200_pic_master = ioremap(0x16000020, 4); 3928c2ecf20Sopenharmony_ci if (!rm200_pic_master) 3938c2ecf20Sopenharmony_ci return; 3948c2ecf20Sopenharmony_ci rm200_pic_slave = ioremap(0x160000a0, 4); 3958c2ecf20Sopenharmony_ci if (!rm200_pic_slave) { 3968c2ecf20Sopenharmony_ci iounmap(rm200_pic_master); 3978c2ecf20Sopenharmony_ci return; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci insert_resource(&iomem_resource, &sni_rm200_pic1_resource); 4018c2ecf20Sopenharmony_ci insert_resource(&iomem_resource, &sni_rm200_pic2_resource); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci sni_rm200_init_8259A(); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci for (i = RM200_I8259A_IRQ_BASE; i < RM200_I8259A_IRQ_BASE + 16; i++) 4068c2ecf20Sopenharmony_ci irq_set_chip_and_handler(i, &sni_rm200_i8259A_chip, 4078c2ecf20Sopenharmony_ci handle_level_irq); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (request_irq(RM200_I8259A_IRQ_BASE + PIC_CASCADE_IR, no_action, 4108c2ecf20Sopenharmony_ci IRQF_NO_THREAD, "cascade", NULL)) 4118c2ecf20Sopenharmony_ci pr_err("Failed to register cascade interrupt\n"); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci#define SNI_RM200_INT_STAT_REG CKSEG1ADDR(0xbc000000) 4168c2ecf20Sopenharmony_ci#define SNI_RM200_INT_ENA_REG CKSEG1ADDR(0xbc080000) 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci#define SNI_RM200_INT_START 24 4198c2ecf20Sopenharmony_ci#define SNI_RM200_INT_END 28 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic void enable_rm200_irq(struct irq_data *d) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci unsigned int mask = 1 << (d->irq - SNI_RM200_INT_START); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci *(volatile u8 *)SNI_RM200_INT_ENA_REG &= ~mask; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_civoid disable_rm200_irq(struct irq_data *d) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci unsigned int mask = 1 << (d->irq - SNI_RM200_INT_START); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci *(volatile u8 *)SNI_RM200_INT_ENA_REG |= mask; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic struct irq_chip rm200_irq_type = { 4368c2ecf20Sopenharmony_ci .name = "RM200", 4378c2ecf20Sopenharmony_ci .irq_mask = disable_rm200_irq, 4388c2ecf20Sopenharmony_ci .irq_unmask = enable_rm200_irq, 4398c2ecf20Sopenharmony_ci}; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic void sni_rm200_hwint(void) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci u32 pending = read_c0_cause() & read_c0_status(); 4448c2ecf20Sopenharmony_ci u8 mask; 4458c2ecf20Sopenharmony_ci u8 stat; 4468c2ecf20Sopenharmony_ci int irq; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (pending & C_IRQ5) 4498c2ecf20Sopenharmony_ci do_IRQ(MIPS_CPU_IRQ_BASE + 7); 4508c2ecf20Sopenharmony_ci else if (pending & C_IRQ0) { 4518c2ecf20Sopenharmony_ci clear_c0_status(IE_IRQ0); 4528c2ecf20Sopenharmony_ci mask = *(volatile u8 *)SNI_RM200_INT_ENA_REG ^ 0x1f; 4538c2ecf20Sopenharmony_ci stat = *(volatile u8 *)SNI_RM200_INT_STAT_REG ^ 0x14; 4548c2ecf20Sopenharmony_ci irq = ffs(stat & mask & 0x1f); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (likely(irq > 0)) 4578c2ecf20Sopenharmony_ci do_IRQ(irq + SNI_RM200_INT_START - 1); 4588c2ecf20Sopenharmony_ci set_c0_status(IE_IRQ0); 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_civoid __init sni_rm200_irq_init(void) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci int i; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci * (volatile u8 *)SNI_RM200_INT_ENA_REG = 0x1f; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci sni_rm200_i8259_irqs(); 4698c2ecf20Sopenharmony_ci mips_cpu_irq_init(); 4708c2ecf20Sopenharmony_ci /* Actually we've got more interrupts to handle ... */ 4718c2ecf20Sopenharmony_ci for (i = SNI_RM200_INT_START; i <= SNI_RM200_INT_END; i++) 4728c2ecf20Sopenharmony_ci irq_set_chip_and_handler(i, &rm200_irq_type, handle_level_irq); 4738c2ecf20Sopenharmony_ci sni_hwint = sni_rm200_hwint; 4748c2ecf20Sopenharmony_ci change_c0_status(ST0_IM, IE_IRQ0); 4758c2ecf20Sopenharmony_ci if (request_irq(SNI_RM200_INT_START + 0, sni_rm200_i8259A_irq_handler, 4768c2ecf20Sopenharmony_ci 0, "onboard ISA", NULL)) 4778c2ecf20Sopenharmony_ci pr_err("Failed to register onboard ISA interrupt\n"); 4788c2ecf20Sopenharmony_ci if (request_irq(SNI_RM200_INT_START + 1, sni_isa_irq_handler, 0, "ISA", 4798c2ecf20Sopenharmony_ci NULL)) 4808c2ecf20Sopenharmony_ci pr_err("Failed to register ISA interrupt\n"); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_civoid __init sni_rm200_init(void) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci} 486