1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * GT641xx IRQ routines. |
4 | * |
5 | * Copyright (C) 2007 Yoichi Yuasa <yuasa@linux-mips.org> |
6 | */ |
7 | #include <linux/hardirq.h> |
8 | #include <linux/init.h> |
9 | #include <linux/irq.h> |
10 | #include <linux/spinlock.h> |
11 | #include <linux/types.h> |
12 | |
13 | #include <asm/gt64120.h> |
14 | |
15 | #define GT641XX_IRQ_TO_BIT(irq) (1U << (irq - GT641XX_IRQ_BASE)) |
16 | |
17 | static DEFINE_RAW_SPINLOCK(gt641xx_irq_lock); |
18 | |
19 | static void ack_gt641xx_irq(struct irq_data *d) |
20 | { |
21 | unsigned long flags; |
22 | u32 cause; |
23 | |
24 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
25 | cause = GT_READ(GT_INTRCAUSE_OFS); |
26 | cause &= ~GT641XX_IRQ_TO_BIT(d->irq); |
27 | GT_WRITE(GT_INTRCAUSE_OFS, cause); |
28 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
29 | } |
30 | |
31 | static void mask_gt641xx_irq(struct irq_data *d) |
32 | { |
33 | unsigned long flags; |
34 | u32 mask; |
35 | |
36 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
37 | mask = GT_READ(GT_INTRMASK_OFS); |
38 | mask &= ~GT641XX_IRQ_TO_BIT(d->irq); |
39 | GT_WRITE(GT_INTRMASK_OFS, mask); |
40 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
41 | } |
42 | |
43 | static void mask_ack_gt641xx_irq(struct irq_data *d) |
44 | { |
45 | unsigned long flags; |
46 | u32 cause, mask; |
47 | |
48 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
49 | mask = GT_READ(GT_INTRMASK_OFS); |
50 | mask &= ~GT641XX_IRQ_TO_BIT(d->irq); |
51 | GT_WRITE(GT_INTRMASK_OFS, mask); |
52 | |
53 | cause = GT_READ(GT_INTRCAUSE_OFS); |
54 | cause &= ~GT641XX_IRQ_TO_BIT(d->irq); |
55 | GT_WRITE(GT_INTRCAUSE_OFS, cause); |
56 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
57 | } |
58 | |
59 | static void unmask_gt641xx_irq(struct irq_data *d) |
60 | { |
61 | unsigned long flags; |
62 | u32 mask; |
63 | |
64 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
65 | mask = GT_READ(GT_INTRMASK_OFS); |
66 | mask |= GT641XX_IRQ_TO_BIT(d->irq); |
67 | GT_WRITE(GT_INTRMASK_OFS, mask); |
68 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
69 | } |
70 | |
71 | static struct irq_chip gt641xx_irq_chip = { |
72 | .name = "GT641xx" , |
73 | .irq_ack = ack_gt641xx_irq, |
74 | .irq_mask = mask_gt641xx_irq, |
75 | .irq_mask_ack = mask_ack_gt641xx_irq, |
76 | .irq_unmask = unmask_gt641xx_irq, |
77 | }; |
78 | |
79 | void gt641xx_irq_dispatch(void) |
80 | { |
81 | u32 cause, mask; |
82 | int i; |
83 | |
84 | cause = GT_READ(GT_INTRCAUSE_OFS); |
85 | mask = GT_READ(GT_INTRMASK_OFS); |
86 | cause &= mask; |
87 | |
88 | /* |
89 | * bit0 : logical or of all the interrupt bits. |
90 | * bit30: logical or of bits[29:26,20:1]. |
91 | * bit31: logical or of bits[25:1]. |
92 | */ |
93 | for (i = 1; i < 30; i++) { |
94 | if (cause & (1U << i)) { |
95 | do_IRQ(GT641XX_IRQ_BASE + i); |
96 | return; |
97 | } |
98 | } |
99 | |
100 | atomic_inc(v: &irq_err_count); |
101 | } |
102 | |
103 | void __init gt641xx_irq_init(void) |
104 | { |
105 | int i; |
106 | |
107 | GT_WRITE(GT_INTRMASK_OFS, 0); |
108 | GT_WRITE(GT_INTRCAUSE_OFS, 0); |
109 | |
110 | /* |
111 | * bit0 : logical or of all the interrupt bits. |
112 | * bit30: logical or of bits[29:26,20:1]. |
113 | * bit31: logical or of bits[25:1]. |
114 | */ |
115 | for (i = 1; i < 30; i++) |
116 | irq_set_chip_and_handler(irq: GT641XX_IRQ_BASE + i, |
117 | chip: >641xx_irq_chip, handle: handle_level_irq); |
118 | } |
119 | |