add new target 'oxnas'
[librecmc/librecmc.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