1 /* 2 * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the 6 * Free Software Foundation; either version 2 of the License, or (at your 7 * option) any later version. 8 */ 9 10 #include <linux/interrupt.h> 11 #include <linux/irq.h> 12 #include <asm/irq_cpu.h> 13 14 #include <loongson1.h> 15 #include <irq.h> 16 17 #define LS1X_INTC_REG(n, x) \ 18 ((void __iomem *)KSEG1ADDR(LS1X_INTC_BASE + (n * 0x18) + (x))) 19 20 #define LS1X_INTC_INTISR(n) LS1X_INTC_REG(n, 0x0) 21 #define LS1X_INTC_INTIEN(n) LS1X_INTC_REG(n, 0x4) 22 #define LS1X_INTC_INTSET(n) LS1X_INTC_REG(n, 0x8) 23 #define LS1X_INTC_INTCLR(n) LS1X_INTC_REG(n, 0xc) 24 #define LS1X_INTC_INTPOL(n) LS1X_INTC_REG(n, 0x10) 25 #define LS1X_INTC_INTEDGE(n) LS1X_INTC_REG(n, 0x14) 26 27 static void ls1x_irq_ack(struct irq_data *d) 28 { 29 unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; 30 unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; 31 32 __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) 33 | (1 << bit), LS1X_INTC_INTCLR(n)); 34 } 35 36 static void ls1x_irq_mask(struct irq_data *d) 37 { 38 unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; 39 unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; 40 41 __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) 42 & ~(1 << bit), LS1X_INTC_INTIEN(n)); 43 } 44 45 static void ls1x_irq_mask_ack(struct irq_data *d) 46 { 47 unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; 48 unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; 49 50 __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) 51 & ~(1 << bit), LS1X_INTC_INTIEN(n)); 52 __raw_writel(__raw_readl(LS1X_INTC_INTCLR(n)) 53 | (1 << bit), LS1X_INTC_INTCLR(n)); 54 } 55 56 static void ls1x_irq_unmask(struct irq_data *d) 57 { 58 unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; 59 unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; 60 61 __raw_writel(__raw_readl(LS1X_INTC_INTIEN(n)) 62 | (1 << bit), LS1X_INTC_INTIEN(n)); 63 } 64 65 static int ls1x_irq_settype(struct irq_data *d, unsigned int type) 66 { 67 unsigned int bit = (d->irq - LS1X_IRQ_BASE) & 0x1f; 68 unsigned int n = (d->irq - LS1X_IRQ_BASE) >> 5; 69 70 switch (type) { 71 case IRQ_TYPE_LEVEL_HIGH: 72 __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) 73 | (1 << bit), LS1X_INTC_INTPOL(n)); 74 __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) 75 & ~(1 << bit), LS1X_INTC_INTEDGE(n)); 76 break; 77 case IRQ_TYPE_LEVEL_LOW: 78 __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) 79 & ~(1 << bit), LS1X_INTC_INTPOL(n)); 80 __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) 81 & ~(1 << bit), LS1X_INTC_INTEDGE(n)); 82 break; 83 case IRQ_TYPE_EDGE_RISING: 84 __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) 85 | (1 << bit), LS1X_INTC_INTPOL(n)); 86 __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) 87 | (1 << bit), LS1X_INTC_INTEDGE(n)); 88 break; 89 case IRQ_TYPE_EDGE_FALLING: 90 __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) 91 & ~(1 << bit), LS1X_INTC_INTPOL(n)); 92 __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) 93 | (1 << bit), LS1X_INTC_INTEDGE(n)); 94 break; 95 case IRQ_TYPE_EDGE_BOTH: 96 __raw_writel(__raw_readl(LS1X_INTC_INTPOL(n)) 97 & ~(1 << bit), LS1X_INTC_INTPOL(n)); 98 __raw_writel(__raw_readl(LS1X_INTC_INTEDGE(n)) 99 | (1 << bit), LS1X_INTC_INTEDGE(n)); 100 break; 101 case IRQ_TYPE_NONE: 102 break; 103 default: 104 return -EINVAL; 105 } 106 107 return 0; 108 } 109 110 static struct irq_chip ls1x_irq_chip = { 111 .name = "LS1X-INTC", 112 .irq_ack = ls1x_irq_ack, 113 .irq_mask = ls1x_irq_mask, 114 .irq_mask_ack = ls1x_irq_mask_ack, 115 .irq_unmask = ls1x_irq_unmask, 116 .irq_set_type = ls1x_irq_settype, 117 }; 118 119 static void ls1x_irq_dispatch(int n) 120 { 121 u32 int_status, irq; 122 123 /* Get pending sources, masked by current enables */ 124 int_status = __raw_readl(LS1X_INTC_INTISR(n)) & 125 __raw_readl(LS1X_INTC_INTIEN(n)); 126 127 if (int_status) { 128 irq = LS1X_IRQ(n, __ffs(int_status)); 129 do_IRQ(irq); 130 } 131 } 132 133 asmlinkage void plat_irq_dispatch(void) 134 { 135 unsigned int pending; 136 137 pending = read_c0_cause() & read_c0_status() & ST0_IM; 138 139 if (pending & CAUSEF_IP7) 140 do_IRQ(TIMER_IRQ); 141 else if (pending & CAUSEF_IP2) 142 ls1x_irq_dispatch(0); /* INT0 */ 143 else if (pending & CAUSEF_IP3) 144 ls1x_irq_dispatch(1); /* INT1 */ 145 else if (pending & CAUSEF_IP4) 146 ls1x_irq_dispatch(2); /* INT2 */ 147 else if (pending & CAUSEF_IP5) 148 ls1x_irq_dispatch(3); /* INT3 */ 149 else if (pending & CAUSEF_IP6) 150 ls1x_irq_dispatch(4); /* INT4 */ 151 else 152 spurious_interrupt(); 153 154 } 155 156 static struct irqaction cascade_irqaction = { 157 .handler = no_action, 158 .name = "cascade", 159 .flags = IRQF_NO_THREAD, 160 }; 161 162 static void __init ls1x_irq_init(int base) 163 { 164 int n; 165 166 /* Disable interrupts and clear pending, 167 * setup all IRQs as high level triggered 168 */ 169 for (n = 0; n < INTN; n++) { 170 __raw_writel(0x0, LS1X_INTC_INTIEN(n)); 171 __raw_writel(0xffffffff, LS1X_INTC_INTCLR(n)); 172 __raw_writel(0xffffffff, LS1X_INTC_INTPOL(n)); 173 /* set DMA0, DMA1 and DMA2 to edge trigger */ 174 __raw_writel(n ? 0x0 : 0xe000, LS1X_INTC_INTEDGE(n)); 175 } 176 177 178 for (n = base; n < NR_IRQS; n++) { 179 irq_set_chip_and_handler(n, &ls1x_irq_chip, 180 handle_level_irq); 181 } 182 183 setup_irq(INT0_IRQ, &cascade_irqaction); 184 setup_irq(INT1_IRQ, &cascade_irqaction); 185 setup_irq(INT2_IRQ, &cascade_irqaction); 186 setup_irq(INT3_IRQ, &cascade_irqaction); 187 #if defined(CONFIG_LOONGSON1_LS1C) 188 setup_irq(INT4_IRQ, &cascade_irqaction); 189 #endif 190 } 191 192 void __init arch_init_irq(void) 193 { 194 mips_cpu_irq_init(); 195 ls1x_irq_init(LS1X_IRQ_BASE); 196 } 197