OpenWrt – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* |
2 | * Copyright (C) 2010 Scott Nicholas <neutronscott@scottn.us> |
||
3 | * Copyright (C) 2012 Florian Fainelli <florian@openwrt.org> |
||
4 | * |
||
5 | * This file is subject to the terms and conditions of the GNU General Public |
||
6 | * License. See the file "COPYING" in the main directory of this archive |
||
7 | * for more details. |
||
8 | */ |
||
9 | |||
10 | #include <linux/init.h> |
||
11 | #include <linux/kernel_stat.h> |
||
12 | #include <linux/signal.h> |
||
13 | #include <linux/sched.h> |
||
14 | #include <linux/interrupt.h> |
||
15 | #include <linux/slab.h> |
||
16 | #include <linux/random.h> |
||
17 | #include <linux/pm.h> |
||
18 | #include <linux/irq.h> |
||
19 | #include <asm/mipsregs.h> |
||
20 | #include <asm/irq_cpu.h> |
||
21 | #include <asm/irq.h> |
||
22 | #include <adm8668.h> |
||
23 | |||
24 | /* interrupt controller */ |
||
25 | #define IRQ_STATUS_REG 0x00 /* Read */ |
||
26 | #define IRQ_ENABLE_REG 0x08 /* Read/Write */ |
||
27 | #define IRQ_DISABLE_REG 0x0C /* Write */ |
||
28 | |||
29 | #define IRQ_MASK 0xffff |
||
30 | |||
31 | static inline void intc_write_reg(u32 val, unsigned int reg) |
||
32 | { |
||
33 | void __iomem *base = (void __iomem *)KSEG1ADDR(ADM8668_INTC_BASE); |
||
34 | |||
35 | __raw_writel(val, base + reg); |
||
36 | } |
||
37 | |||
38 | static inline u32 intc_read_reg(unsigned int reg) |
||
39 | { |
||
40 | void __iomem *base = (void __iomem *)KSEG1ADDR(ADM8668_INTC_BASE); |
||
41 | |||
42 | return __raw_readl(base + reg); |
||
43 | } |
||
44 | |||
45 | static void adm8668_irq_cascade(void) |
||
46 | { |
||
47 | int irq; |
||
48 | u32 intsrc; |
||
49 | |||
50 | intsrc = intc_read_reg(IRQ_STATUS_REG) & IRQ_MASK; |
||
51 | if (intsrc) { |
||
52 | irq = fls(intsrc) - 1; |
||
53 | do_IRQ(irq); |
||
54 | } else |
||
55 | spurious_interrupt(); |
||
56 | } |
||
57 | |||
58 | /* |
||
59 | * System irq dispatch |
||
60 | */ |
||
61 | void plat_irq_dispatch(void) |
||
62 | { |
||
63 | unsigned int pending; |
||
64 | |||
65 | pending = read_c0_cause() & read_c0_status() & ST0_IM; |
||
66 | |||
67 | /* timer interrupt, that we renumbered */ |
||
68 | if (pending & STATUSF_IP7) |
||
69 | do_IRQ(MIPS_CPU_IRQ_BASE + 7); |
||
70 | else if (pending & STATUSF_IP2) |
||
71 | adm8668_irq_cascade(); |
||
72 | else |
||
73 | spurious_interrupt(); |
||
74 | } |
||
75 | |||
76 | /* |
||
77 | * enable 8668 irq |
||
78 | */ |
||
79 | static void enable_adm8668_irq(struct irq_data *d) |
||
80 | { |
||
81 | intc_write_reg((1 << d->irq), IRQ_ENABLE_REG); |
||
82 | } |
||
83 | |||
84 | |||
85 | static void ack_adm8668_irq(struct irq_data *d) |
||
86 | { |
||
87 | intc_write_reg((1 << d->irq), IRQ_DISABLE_REG); |
||
88 | } |
||
89 | |||
90 | /* |
||
91 | * system irq type |
||
92 | */ |
||
93 | |||
94 | static struct irq_chip adm8668_irq_type = { |
||
95 | .name = "adm8668", |
||
96 | .irq_ack = ack_adm8668_irq, |
||
97 | .irq_mask = ack_adm8668_irq, |
||
98 | .irq_unmask = enable_adm8668_irq |
||
99 | }; |
||
100 | |||
101 | /* |
||
102 | * irq init |
||
103 | */ |
||
104 | static void __init init_adm8668_irqs(void) |
||
105 | { |
||
106 | int i; |
||
107 | |||
108 | /* disable all interrupts for the moment */ |
||
109 | intc_write_reg(IRQ_MASK, IRQ_DISABLE_REG); |
||
110 | |||
111 | for (i = 0; i <= ADM8668_IRQ_MAX; i++) |
||
112 | irq_set_chip_and_handler(i, &adm8668_irq_type, |
||
113 | handle_level_irq); |
||
114 | |||
115 | /* hw0 is where our interrupts are uh.. interrupted at. */ |
||
116 | set_c0_status(IE_IRQ0); |
||
117 | } |
||
118 | |||
119 | /* |
||
120 | * system init |
||
121 | */ |
||
122 | void __init arch_init_irq(void) |
||
123 | { |
||
124 | mips_cpu_irq_init(); |
||
125 | init_adm8668_irqs(); |
||
126 | } |