1 | // SPDX-License-Identifier: GPL-2.0 |
2 | |
3 | #include <linux/delay.h> |
4 | #include <linux/interrupt.h> |
5 | #include <linux/irq.h> |
6 | #include <linux/kernel.h> |
7 | #include <linux/sched.h> |
8 | #include <linux/sched/debug.h> |
9 | #include <linux/types.h> |
10 | #include <linux/ioport.h> |
11 | |
12 | #include <asm/hwtest.h> |
13 | #include <asm/irq.h> |
14 | #include <asm/irq_regs.h> |
15 | #include <asm/processor.h> |
16 | #include <asm/virt.h> |
17 | |
18 | #define GFPIC_REG_IRQ_PENDING 0x04 |
19 | #define GFPIC_REG_IRQ_DISABLE_ALL 0x08 |
20 | #define GFPIC_REG_IRQ_DISABLE 0x0c |
21 | #define GFPIC_REG_IRQ_ENABLE 0x10 |
22 | |
23 | static struct resource picres[6]; |
24 | static const char *picname[6] = { |
25 | "goldfish_pic.0" , |
26 | "goldfish_pic.1" , |
27 | "goldfish_pic.2" , |
28 | "goldfish_pic.3" , |
29 | "goldfish_pic.4" , |
30 | "goldfish_pic.5" |
31 | }; |
32 | |
33 | /* |
34 | * 6 goldfish-pic for CPU IRQ #1 to IRQ #6 |
35 | * CPU IRQ #1 -> PIC #1 |
36 | * IRQ #1 to IRQ #31 -> unused |
37 | * IRQ #32 -> goldfish-tty |
38 | * CPU IRQ #2 -> PIC #2 |
39 | * IRQ #1 to IRQ #32 -> virtio-mmio from 1 to 32 |
40 | * CPU IRQ #3 -> PIC #3 |
41 | * IRQ #1 to IRQ #32 -> virtio-mmio from 33 to 64 |
42 | * CPU IRQ #4 -> PIC #4 |
43 | * IRQ #1 to IRQ #32 -> virtio-mmio from 65 to 96 |
44 | * CPU IRQ #5 -> PIC #5 |
45 | * IRQ #1 to IRQ #32 -> virtio-mmio from 97 to 128 |
46 | * CPU IRQ #6 -> PIC #6 |
47 | * IRQ #1 -> goldfish-timer |
48 | * IRQ #2 -> goldfish-rtc |
49 | * IRQ #3 to IRQ #32 -> unused |
50 | * CPU IRQ #7 -> NMI |
51 | */ |
52 | |
53 | static u32 gfpic_read(int pic, int reg) |
54 | { |
55 | void __iomem *base = (void __iomem *)(virt_bi_data.pic.mmio + |
56 | pic * 0x1000); |
57 | |
58 | return ioread32be(base + reg); |
59 | } |
60 | |
61 | static void gfpic_write(u32 value, int pic, int reg) |
62 | { |
63 | void __iomem *base = (void __iomem *)(virt_bi_data.pic.mmio + |
64 | pic * 0x1000); |
65 | |
66 | iowrite32be(value, base + reg); |
67 | } |
68 | |
69 | #define GF_PIC(irq) ((irq - IRQ_USER) / 32) |
70 | #define GF_IRQ(irq) ((irq - IRQ_USER) % 32) |
71 | |
72 | static void virt_irq_enable(struct irq_data *data) |
73 | { |
74 | gfpic_write(BIT(GF_IRQ(data->irq)), GF_PIC(data->irq), |
75 | GFPIC_REG_IRQ_ENABLE); |
76 | } |
77 | |
78 | static void virt_irq_disable(struct irq_data *data) |
79 | { |
80 | gfpic_write(BIT(GF_IRQ(data->irq)), GF_PIC(data->irq), |
81 | GFPIC_REG_IRQ_DISABLE); |
82 | } |
83 | |
84 | static unsigned int virt_irq_startup(struct irq_data *data) |
85 | { |
86 | virt_irq_enable(data); |
87 | return 0; |
88 | } |
89 | |
90 | static irqreturn_t virt_nmi_handler(int irq, void *dev_id) |
91 | { |
92 | static int in_nmi; |
93 | |
94 | if (READ_ONCE(in_nmi)) |
95 | return IRQ_HANDLED; |
96 | WRITE_ONCE(in_nmi, 1); |
97 | |
98 | pr_warn("Non-Maskable Interrupt\n" ); |
99 | show_registers(get_irq_regs()); |
100 | |
101 | WRITE_ONCE(in_nmi, 0); |
102 | return IRQ_HANDLED; |
103 | } |
104 | |
105 | static struct irq_chip virt_irq_chip = { |
106 | .name = "virt" , |
107 | .irq_enable = virt_irq_enable, |
108 | .irq_disable = virt_irq_disable, |
109 | .irq_startup = virt_irq_startup, |
110 | .irq_shutdown = virt_irq_disable, |
111 | }; |
112 | |
113 | static void goldfish_pic_irq(struct irq_desc *desc) |
114 | { |
115 | u32 irq_pending; |
116 | unsigned int irq_num; |
117 | unsigned int pic = desc->irq_data.irq - 1; |
118 | |
119 | irq_pending = gfpic_read(pic, GFPIC_REG_IRQ_PENDING); |
120 | irq_num = IRQ_USER + pic * 32; |
121 | |
122 | do { |
123 | if (irq_pending & 1) |
124 | generic_handle_irq(irq: irq_num); |
125 | ++irq_num; |
126 | irq_pending >>= 1; |
127 | } while (irq_pending); |
128 | } |
129 | |
130 | void __init virt_init_IRQ(void) |
131 | { |
132 | unsigned int i; |
133 | |
134 | m68k_setup_irq_controller(&virt_irq_chip, handle_simple_irq, IRQ_USER, |
135 | NUM_VIRT_SOURCES - IRQ_USER); |
136 | |
137 | for (i = 0; i < 6; i++) { |
138 | |
139 | picres[i] = (struct resource) |
140 | DEFINE_RES_MEM_NAMED(virt_bi_data.pic.mmio + i * 0x1000, |
141 | 0x1000, picname[i]); |
142 | if (request_resource(root: &iomem_resource, new: &picres[i])) { |
143 | pr_err("Cannot allocate %s resource\n" , picname[i]); |
144 | return; |
145 | } |
146 | |
147 | irq_set_chained_handler(irq: virt_bi_data.pic.irq + i, |
148 | handle: goldfish_pic_irq); |
149 | } |
150 | |
151 | if (request_irq(irq: IRQ_AUTO_7, handler: virt_nmi_handler, flags: 0, name: "NMI" , |
152 | dev: virt_nmi_handler)) |
153 | pr_err("Couldn't register NMI\n" ); |
154 | } |
155 | |