1#include <linux/irqdomain.h>
2#include <linux/irq.h>
3#include <linux/of.h>
4#include <linux/of_address.h>
5#include <linux/of_irq.h>
6#include <linux/irqchip/chained_irq.h>
7#include <linux/err.h>
8#include <linux/io.h>
9#include <linux/version.h>
10
11#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
12# include "irqchip.h"
13#else
14# include <linux/irqchip.h>
15#endif
16
17struct rps_chip_data {
18	void __iomem *base;
19	struct irq_chip chip;
20	struct irq_domain *domain;
21} rps_data;
22
23enum {
24	RPS_IRQ_BASE = 64,
25	RPS_IRQ_COUNT = 32,
26	PRS_HWIRQ_BASE = 0,
27
28	RPS_STATUS = 0,
29	RPS_RAW_STATUS = 4,
30	RPS_UNMASK = 8,
31	RPS_MASK = 0xc,
32};
33
34/*
35 * Routines to acknowledge, disable and enable interrupts
36 */
37static void rps_mask_irq(struct irq_data *d)
38{
39	struct rps_chip_data *chip_data = irq_data_get_irq_chip_data(d);
40	u32 mask = BIT(d->hwirq);
41
42	iowrite32(mask, chip_data->base + RPS_MASK);
43}
44
45static void rps_unmask_irq(struct irq_data *d)
46{
47	struct rps_chip_data *chip_data = irq_data_get_irq_chip_data(d);
48	u32 mask = BIT(d->hwirq);
49
50	iowrite32(mask, chip_data->base + RPS_UNMASK);
51}
52
53static struct irq_chip rps_chip = {
54	.name			= "RPS",
55	.irq_mask		= rps_mask_irq,
56	.irq_unmask		= rps_unmask_irq,
57};
58
59static int rps_irq_domain_xlate(struct irq_domain *d,
60				struct device_node *controller,
61				const u32 *intspec, unsigned int intsize,
62				unsigned long *out_hwirq,
63				unsigned int *out_type)
64{
65#if LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0)
66	if (d->of_node != controller)
67#else
68	if (irq_domain_get_of_node(d) != controller)
69#endif
70		return -EINVAL;
71	if (intsize < 1)
72		return -EINVAL;
73
74	*out_hwirq = intspec[0];
75	/* Honestly I do not know the type */
76	*out_type = IRQ_TYPE_LEVEL_HIGH;
77
78	return 0;
79}
80
81static int rps_irq_domain_map(struct irq_domain *d, unsigned int irq,
82				irq_hw_number_t hw)
83{
84	irq_set_chip_and_handler(irq, &rps_chip, handle_level_irq);
85#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
86	set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
87#else
88	irq_set_probe(irq);
89#endif
90	irq_set_chip_data(irq, d->host_data);
91	return 0;
92}
93
94const struct irq_domain_ops rps_irq_domain_ops = {
95	.map = rps_irq_domain_map,
96	.xlate = rps_irq_domain_xlate,
97};
98
99#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
100static void rps_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
101#else
102static void rps_handle_cascade_irq(struct irq_desc *desc)
103#endif
104{
105	struct rps_chip_data *chip_data = irq_desc_get_handler_data(desc);
106	struct irq_chip *chip = irq_desc_get_chip(desc);
107	unsigned int cascade_irq, rps_irq;
108	u32 status;
109
110	chained_irq_enter(chip, desc);
111
112	status = ioread32(chip_data->base + RPS_STATUS);
113	rps_irq = __ffs(status);
114	cascade_irq = irq_find_mapping(chip_data->domain, rps_irq);
115
116	if (unlikely(rps_irq >= RPS_IRQ_COUNT))
117#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0)
118		handle_bad_irq(cascade_irq, desc);
119#else
120		handle_bad_irq(desc);
121#endif
122	else
123		generic_handle_irq(cascade_irq);
124
125	chained_irq_exit(chip, desc);
126}
127
128#ifdef CONFIG_OF
129int __init rps_of_init(struct device_node *node, struct device_node *parent)
130{
131	void __iomem *rps_base;
132	int irq_start = RPS_IRQ_BASE;
133	int irq_base;
134	int irq;
135
136	if (WARN_ON(!node))
137		return -ENODEV;
138
139	rps_base = of_iomap(node, 0);
140	WARN(!rps_base, "unable to map rps registers\n");
141	rps_data.base = rps_base;
142
143	irq_base = irq_alloc_descs(irq_start, 0, RPS_IRQ_COUNT, numa_node_id());
144	if (IS_ERR_VALUE(irq_base)) {
145		WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
146		     irq_start);
147		irq_base = irq_start;
148	}
149
150	rps_data.domain = irq_domain_add_legacy(node, RPS_IRQ_COUNT, irq_base,
151			PRS_HWIRQ_BASE, &rps_irq_domain_ops, &rps_data);
152
153	if (WARN_ON(!rps_data.domain))
154		return -ENOMEM;
155
156	if (parent) {
157		irq = irq_of_parse_and_map(node, 0);
158		if (irq_set_handler_data(irq, &rps_data) != 0)
159			BUG();
160		irq_set_chained_handler(irq, rps_handle_cascade_irq);
161	}
162	return 0;
163
164}
165
166IRQCHIP_DECLARE(nas782x, "plxtech,nas782x-rps", rps_of_init);
167#endif
168