1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
4  *  Loongson PCH PIC support
5  */
6 
7 #define pr_fmt(fmt) "pch-pic: " fmt
8 
9 #include <linux/interrupt.h>
10 #include <linux/irq.h>
11 #include <linux/irqchip.h>
12 #include <linux/irqdomain.h>
13 #include <linux/kernel.h>
14 #include <linux/platform_device.h>
15 #include <linux/of_address.h>
16 #include <linux/of_irq.h>
17 #include <linux/of_platform.h>
18 
19 /* Registers */
20 #define PCH_PIC_MASK		0x20
21 #define PCH_PIC_HTMSI_EN	0x40
22 #define PCH_PIC_EDGE		0x60
23 #define PCH_PIC_CLR		0x80
24 #define PCH_PIC_AUTO0		0xc0
25 #define PCH_PIC_AUTO1		0xe0
26 #define PCH_INT_ROUTE(irq)	(0x100 + irq)
27 #define PCH_INT_HTVEC(irq)	(0x200 + irq)
28 #define PCH_PIC_POL		0x3e0
29 
30 #define PIC_COUNT_PER_REG	32
31 #define PIC_REG_COUNT		2
32 #define PIC_COUNT		(PIC_COUNT_PER_REG * PIC_REG_COUNT)
33 #define PIC_REG_IDX(irq_id)	((irq_id) / PIC_COUNT_PER_REG)
34 #define PIC_REG_BIT(irq_id)	((irq_id) % PIC_COUNT_PER_REG)
35 
36 static int nr_pics;
37 
38 struct pch_pic {
39 	void __iomem		*base;
40 	struct irq_domain	*pic_domain;
41 	u32			ht_vec_base;
42 	raw_spinlock_t		pic_lock;
43 	u32			vec_count;
44 	u32			gsi_base;
45 };
46 
47 static struct pch_pic *pch_pic_priv[MAX_IO_PICS];
48 
49 struct fwnode_handle *pch_pic_handle[MAX_IO_PICS];
50 
51 int find_pch_pic(u32 gsi)
52 {
53 	int i;
54 
55 	/* Find the PCH_PIC that manages this GSI. */
56 	for (i = 0; i < MAX_IO_PICS; i++) {
57 		struct pch_pic *priv = pch_pic_priv[i];
58 
59 		if (!priv)
60 			return -1;
61 
62 		if (gsi >= priv->gsi_base && gsi < (priv->gsi_base + priv->vec_count))
63 			return i;
64 	}
65 
66 	pr_err("ERROR: Unable to locate PCH_PIC for GSI %d\n", gsi);
67 	return -1;
68 }
69 
70 static void pch_pic_bitset(struct pch_pic *priv, int offset, int bit)
71 {
72 	u32 reg;
73 	void __iomem *addr = priv->base + offset + PIC_REG_IDX(bit) * 4;
74 
75 	raw_spin_lock(&priv->pic_lock);
76 	reg = readl(addr);
77 	reg |= BIT(PIC_REG_BIT(bit));
78 	writel(reg, addr);
79 	raw_spin_unlock(&priv->pic_lock);
80 }
81 
82 static void pch_pic_bitclr(struct pch_pic *priv, int offset, int bit)
83 {
84 	u32 reg;
85 	void __iomem *addr = priv->base + offset + PIC_REG_IDX(bit) * 4;
86 
87 	raw_spin_lock(&priv->pic_lock);
88 	reg = readl(addr);
89 	reg &= ~BIT(PIC_REG_BIT(bit));
90 	writel(reg, addr);
91 	raw_spin_unlock(&priv->pic_lock);
92 }
93 
94 static void pch_pic_mask_irq(struct irq_data *d)
95 {
96 	struct pch_pic *priv = irq_data_get_irq_chip_data(d);
97 
98 	pch_pic_bitset(priv, PCH_PIC_MASK, d->hwirq);
99 	irq_chip_mask_parent(d);
100 }
101 
102 static void pch_pic_unmask_irq(struct irq_data *d)
103 {
104 	struct pch_pic *priv = irq_data_get_irq_chip_data(d);
105 
106 	writel(BIT(PIC_REG_BIT(d->hwirq)),
107 			priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
108 
109 	irq_chip_unmask_parent(d);
110 	pch_pic_bitclr(priv, PCH_PIC_MASK, d->hwirq);
111 }
112 
113 static int pch_pic_set_type(struct irq_data *d, unsigned int type)
114 {
115 	struct pch_pic *priv = irq_data_get_irq_chip_data(d);
116 	int ret = 0;
117 
118 	switch (type) {
119 	case IRQ_TYPE_EDGE_RISING:
120 		pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
121 		pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
122 		irq_set_handler_locked(d, handle_edge_irq);
123 		break;
124 	case IRQ_TYPE_EDGE_FALLING:
125 		pch_pic_bitset(priv, PCH_PIC_EDGE, d->hwirq);
126 		pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
127 		irq_set_handler_locked(d, handle_edge_irq);
128 		break;
129 	case IRQ_TYPE_LEVEL_HIGH:
130 		pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
131 		pch_pic_bitclr(priv, PCH_PIC_POL, d->hwirq);
132 		irq_set_handler_locked(d, handle_level_irq);
133 		break;
134 	case IRQ_TYPE_LEVEL_LOW:
135 		pch_pic_bitclr(priv, PCH_PIC_EDGE, d->hwirq);
136 		pch_pic_bitset(priv, PCH_PIC_POL, d->hwirq);
137 		irq_set_handler_locked(d, handle_level_irq);
138 		break;
139 	default:
140 		ret = -EINVAL;
141 		break;
142 	}
143 
144 	return ret;
145 }
146 
147 static void pch_pic_ack_irq(struct irq_data *d)
148 {
149 	unsigned int reg;
150 	struct pch_pic *priv = irq_data_get_irq_chip_data(d);
151 
152 	reg = readl(priv->base + PCH_PIC_EDGE + PIC_REG_IDX(d->hwirq) * 4);
153 	if (reg & BIT(PIC_REG_BIT(d->hwirq))) {
154 		writel(BIT(PIC_REG_BIT(d->hwirq)),
155 			priv->base + PCH_PIC_CLR + PIC_REG_IDX(d->hwirq) * 4);
156 	}
157 	irq_chip_ack_parent(d);
158 }
159 
160 static struct irq_chip pch_pic_irq_chip = {
161 	.name			= "PCH PIC",
162 	.irq_mask		= pch_pic_mask_irq,
163 	.irq_unmask		= pch_pic_unmask_irq,
164 	.irq_ack		= pch_pic_ack_irq,
165 	.irq_set_affinity	= irq_chip_set_affinity_parent,
166 	.irq_set_type		= pch_pic_set_type,
167 };
168 
169 static int pch_pic_domain_translate(struct irq_domain *d,
170 					struct irq_fwspec *fwspec,
171 					unsigned long *hwirq,
172 					unsigned int *type)
173 {
174 	struct pch_pic *priv = d->host_data;
175 	struct device_node *of_node = to_of_node(fwspec->fwnode);
176 
177 	if (fwspec->param_count < 1)
178 		return -EINVAL;
179 
180 	if (of_node) {
181 		*hwirq = fwspec->param[0] + priv->ht_vec_base;
182 		*type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
183 	} else {
184 		*hwirq = fwspec->param[0] - priv->gsi_base;
185 		*type = IRQ_TYPE_NONE;
186 	}
187 
188 	return 0;
189 }
190 
191 static int pch_pic_alloc(struct irq_domain *domain, unsigned int virq,
192 			      unsigned int nr_irqs, void *arg)
193 {
194 	int err;
195 	unsigned int type;
196 	unsigned long hwirq;
197 	struct irq_fwspec *fwspec = arg;
198 	struct irq_fwspec parent_fwspec;
199 	struct pch_pic *priv = domain->host_data;
200 
201 	err = pch_pic_domain_translate(domain, fwspec, &hwirq, &type);
202 	if (err)
203 		return err;
204 
205 	parent_fwspec.fwnode = domain->parent->fwnode;
206 	parent_fwspec.param_count = 1;
207 	parent_fwspec.param[0] = hwirq;
208 
209 	err = irq_domain_alloc_irqs_parent(domain, virq, 1, &parent_fwspec);
210 	if (err)
211 		return err;
212 
213 	irq_domain_set_info(domain, virq, hwirq,
214 			    &pch_pic_irq_chip, priv,
215 			    handle_level_irq, NULL, NULL);
216 	irq_set_probe(virq);
217 
218 	return 0;
219 }
220 
221 static const struct irq_domain_ops pch_pic_domain_ops = {
222 	.translate	= pch_pic_domain_translate,
223 	.alloc		= pch_pic_alloc,
224 	.free		= irq_domain_free_irqs_parent,
225 };
226 
227 static void pch_pic_reset(struct pch_pic *priv)
228 {
229 	int i;
230 
231 	for (i = 0; i < PIC_COUNT; i++) {
232 		/* Write vector ID */
233 		writeb(priv->ht_vec_base + i, priv->base + PCH_INT_HTVEC(i));
234 		/* Hardcode route to HT0 Lo */
235 		writeb(1, priv->base + PCH_INT_ROUTE(i));
236 	}
237 
238 	for (i = 0; i < PIC_REG_COUNT; i++) {
239 		/* Clear IRQ cause registers, mask all interrupts */
240 		writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_MASK + 4 * i);
241 		writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_CLR + 4 * i);
242 		/* Clear auto bounce, we don't need that */
243 		writel_relaxed(0, priv->base + PCH_PIC_AUTO0 + 4 * i);
244 		writel_relaxed(0, priv->base + PCH_PIC_AUTO1 + 4 * i);
245 		/* Enable HTMSI transformer */
246 		writel_relaxed(0xFFFFFFFF, priv->base + PCH_PIC_HTMSI_EN + 4 * i);
247 	}
248 }
249 
250 static int pch_pic_init(phys_addr_t addr, unsigned long size, int vec_base,
251 			struct irq_domain *parent_domain, struct fwnode_handle *domain_handle,
252 			u32 gsi_base)
253 {
254 	struct pch_pic *priv;
255 
256 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
257 	if (!priv)
258 		return -ENOMEM;
259 
260 	raw_spin_lock_init(&priv->pic_lock);
261 	priv->base = ioremap(addr, size);
262 	if (!priv->base)
263 		goto free_priv;
264 
265 	priv->ht_vec_base = vec_base;
266 	priv->vec_count = ((readq(priv->base) >> 48) & 0xff) + 1;
267 	priv->gsi_base = gsi_base;
268 
269 	priv->pic_domain = irq_domain_create_hierarchy(parent_domain, 0,
270 						priv->vec_count, domain_handle,
271 						&pch_pic_domain_ops, priv);
272 
273 	if (!priv->pic_domain) {
274 		pr_err("Failed to create IRQ domain\n");
275 		goto iounmap_base;
276 	}
277 
278 	pch_pic_reset(priv);
279 	pch_pic_handle[nr_pics] = domain_handle;
280 	pch_pic_priv[nr_pics++] = priv;
281 
282 	return 0;
283 
284 iounmap_base:
285 	iounmap(priv->base);
286 free_priv:
287 	kfree(priv);
288 
289 	return -EINVAL;
290 }
291 
292 #ifdef CONFIG_OF
293 
294 static int pch_pic_of_init(struct device_node *node,
295 				struct device_node *parent)
296 {
297 	int err, vec_base;
298 	struct resource res;
299 	struct irq_domain *parent_domain;
300 
301 	if (of_address_to_resource(node, 0, &res))
302 		return -EINVAL;
303 
304 	parent_domain = irq_find_host(parent);
305 	if (!parent_domain) {
306 		pr_err("Failed to find the parent domain\n");
307 		return -ENXIO;
308 	}
309 
310 	if (of_property_read_u32(node, "loongson,pic-base-vec", &vec_base)) {
311 		pr_err("Failed to determine pic-base-vec\n");
312 		return -EINVAL;
313 	}
314 
315 	err = pch_pic_init(res.start, resource_size(&res), vec_base,
316 				parent_domain, of_node_to_fwnode(node), 0);
317 	if (err < 0)
318 		return err;
319 
320 	return 0;
321 }
322 
323 IRQCHIP_DECLARE(pch_pic, "loongson,pch-pic-1.0", pch_pic_of_init);
324 
325 #endif
326 
327 #ifdef CONFIG_ACPI
328 static int __init
329 pch_lpc_parse_madt(union acpi_subtable_headers *header,
330 		       const unsigned long end)
331 {
332 	struct acpi_madt_lpc_pic *pchlpc_entry = (struct acpi_madt_lpc_pic *)header;
333 
334 	return pch_lpc_acpi_init(pch_pic_priv[0]->pic_domain, pchlpc_entry);
335 }
336 
337 static int __init acpi_cascade_irqdomain_init(void)
338 {
339 	acpi_table_parse_madt(ACPI_MADT_TYPE_LPC_PIC,
340 			      pch_lpc_parse_madt, 0);
341 	return 0;
342 }
343 
344 int __init pch_pic_acpi_init(struct irq_domain *parent,
345 					struct acpi_madt_bio_pic *acpi_pchpic)
346 {
347 	int ret, vec_base;
348 	struct fwnode_handle *domain_handle;
349 
350 	vec_base = acpi_pchpic->gsi_base - GSI_MIN_PCH_IRQ;
351 
352 	domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_pchpic);
353 	if (!domain_handle) {
354 		pr_err("Unable to allocate domain handle\n");
355 		return -ENOMEM;
356 	}
357 
358 	ret = pch_pic_init(acpi_pchpic->address, acpi_pchpic->size,
359 				vec_base, parent, domain_handle, acpi_pchpic->gsi_base);
360 
361 	if (ret < 0) {
362 		irq_domain_free_fwnode(domain_handle);
363 		return ret;
364 	}
365 
366 	if (acpi_pchpic->id == 0)
367 		acpi_cascade_irqdomain_init();
368 
369 	return ret;
370 }
371 #endif
372