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