GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / irqchip / irq-mvebu-icu.c
1 /*
2  * Copyright (C) 2017 Marvell
3  *
4  * Hanna Hawa <hannah@marvell.com>
5  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
6  *
7  * This file is licensed under the terms of the GNU General Public
8  * License version 2. This program is licensed "as is" without any
9  * warranty of any kind, whether express or implied.
10  */
11
12 #include <linux/interrupt.h>
13 #include <linux/irq.h>
14 #include <linux/irqchip.h>
15 #include <linux/irqdomain.h>
16 #include <linux/kernel.h>
17 #include <linux/msi.h>
18 #include <linux/of_irq.h>
19 #include <linux/of_platform.h>
20 #include <linux/platform_device.h>
21
22 #include <dt-bindings/interrupt-controller/mvebu-icu.h>
23
24 /* ICU registers */
25 #define ICU_SETSPI_NSR_AL       0x10
26 #define ICU_SETSPI_NSR_AH       0x14
27 #define ICU_CLRSPI_NSR_AL       0x18
28 #define ICU_CLRSPI_NSR_AH       0x1c
29 #define ICU_INT_CFG(x)          (0x100 + 4 * (x))
30 #define   ICU_INT_ENABLE        BIT(24)
31 #define   ICU_IS_EDGE           BIT(28)
32 #define   ICU_GROUP_SHIFT       29
33
34 /* ICU definitions */
35 #define ICU_MAX_IRQS            207
36 #define ICU_SATA0_ICU_ID        109
37 #define ICU_SATA1_ICU_ID        107
38
39 struct mvebu_icu {
40         struct irq_chip irq_chip;
41         void __iomem *base;
42         struct irq_domain *domain;
43         struct device *dev;
44         atomic_t initialized;
45 };
46
47 struct mvebu_icu_irq_data {
48         struct mvebu_icu *icu;
49         unsigned int icu_group;
50         unsigned int type;
51 };
52
53 static void mvebu_icu_init(struct mvebu_icu *icu, struct msi_msg *msg)
54 {
55         if (atomic_cmpxchg(&icu->initialized, false, true))
56                 return;
57
58         /* Set Clear/Set ICU SPI message address in AP */
59         writel_relaxed(msg[0].address_hi, icu->base + ICU_SETSPI_NSR_AH);
60         writel_relaxed(msg[0].address_lo, icu->base + ICU_SETSPI_NSR_AL);
61         writel_relaxed(msg[1].address_hi, icu->base + ICU_CLRSPI_NSR_AH);
62         writel_relaxed(msg[1].address_lo, icu->base + ICU_CLRSPI_NSR_AL);
63 }
64
65 static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
66 {
67         struct irq_data *d = irq_get_irq_data(desc->irq);
68         struct mvebu_icu_irq_data *icu_irqd = d->chip_data;
69         struct mvebu_icu *icu = icu_irqd->icu;
70         unsigned int icu_int;
71
72         if (msg->address_lo || msg->address_hi) {
73                 /* One off initialization */
74                 mvebu_icu_init(icu, msg);
75                 /* Configure the ICU with irq number & type */
76                 icu_int = msg->data | ICU_INT_ENABLE;
77                 if (icu_irqd->type & IRQ_TYPE_EDGE_RISING)
78                         icu_int |= ICU_IS_EDGE;
79                 icu_int |= icu_irqd->icu_group << ICU_GROUP_SHIFT;
80         } else {
81                 /* De-configure the ICU */
82                 icu_int = 0;
83         }
84
85         writel_relaxed(icu_int, icu->base + ICU_INT_CFG(d->hwirq));
86
87         /*
88          * The SATA unit has 2 ports, and a dedicated ICU entry per
89          * port. The ahci sata driver supports only one irq interrupt
90          * per SATA unit. To solve this conflict, we configure the 2
91          * SATA wired interrupts in the south bridge into 1 GIC
92          * interrupt in the north bridge. Even if only a single port
93          * is enabled, if sata node is enabled, both interrupts are
94          * configured (regardless of which port is actually in use).
95          */
96         if (d->hwirq == ICU_SATA0_ICU_ID || d->hwirq == ICU_SATA1_ICU_ID) {
97                 writel_relaxed(icu_int,
98                                icu->base + ICU_INT_CFG(ICU_SATA0_ICU_ID));
99                 writel_relaxed(icu_int,
100                                icu->base + ICU_INT_CFG(ICU_SATA1_ICU_ID));
101         }
102 }
103
104 static int
105 mvebu_icu_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec,
106                                unsigned long *hwirq, unsigned int *type)
107 {
108         struct mvebu_icu *icu = platform_msi_get_host_data(d);
109         unsigned int icu_group;
110
111         /* Check the count of the parameters in dt */
112         if (WARN_ON(fwspec->param_count < 3)) {
113                 dev_err(icu->dev, "wrong ICU parameter count %d\n",
114                         fwspec->param_count);
115                 return -EINVAL;
116         }
117
118         /* Only ICU group type is handled */
119         icu_group = fwspec->param[0];
120         if (icu_group != ICU_GRP_NSR && icu_group != ICU_GRP_SR &&
121             icu_group != ICU_GRP_SEI && icu_group != ICU_GRP_REI) {
122                 dev_err(icu->dev, "wrong ICU group type %x\n", icu_group);
123                 return -EINVAL;
124         }
125
126         *hwirq = fwspec->param[1];
127         if (*hwirq >= ICU_MAX_IRQS) {
128                 dev_err(icu->dev, "invalid interrupt number %ld\n", *hwirq);
129                 return -EINVAL;
130         }
131
132         /* Mask the type to prevent wrong DT configuration */
133         *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
134
135         return 0;
136 }
137
138 static int
139 mvebu_icu_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
140                            unsigned int nr_irqs, void *args)
141 {
142         int err;
143         unsigned long hwirq;
144         struct irq_fwspec *fwspec = args;
145         struct mvebu_icu *icu = platform_msi_get_host_data(domain);
146         struct mvebu_icu_irq_data *icu_irqd;
147
148         icu_irqd = kmalloc(sizeof(*icu_irqd), GFP_KERNEL);
149         if (!icu_irqd)
150                 return -ENOMEM;
151
152         err = mvebu_icu_irq_domain_translate(domain, fwspec, &hwirq,
153                                              &icu_irqd->type);
154         if (err) {
155                 dev_err(icu->dev, "failed to translate ICU parameters\n");
156                 goto free_irqd;
157         }
158
159         icu_irqd->icu_group = fwspec->param[0];
160         icu_irqd->icu = icu;
161
162         err = platform_msi_domain_alloc(domain, virq, nr_irqs);
163         if (err) {
164                 dev_err(icu->dev, "failed to allocate ICU interrupt in parent domain\n");
165                 goto free_irqd;
166         }
167
168         /* Make sure there is no interrupt left pending by the firmware */
169         err = irq_set_irqchip_state(virq, IRQCHIP_STATE_PENDING, false);
170         if (err)
171                 goto free_msi;
172
173         err = irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
174                                             &icu->irq_chip, icu_irqd);
175         if (err) {
176                 dev_err(icu->dev, "failed to set the data to IRQ domain\n");
177                 goto free_msi;
178         }
179
180         return 0;
181
182 free_msi:
183         platform_msi_domain_free(domain, virq, nr_irqs);
184 free_irqd:
185         kfree(icu_irqd);
186         return err;
187 }
188
189 static void
190 mvebu_icu_irq_domain_free(struct irq_domain *domain, unsigned int virq,
191                           unsigned int nr_irqs)
192 {
193         struct irq_data *d = irq_get_irq_data(virq);
194         struct mvebu_icu_irq_data *icu_irqd = d->chip_data;
195
196         kfree(icu_irqd);
197
198         platform_msi_domain_free(domain, virq, nr_irqs);
199 }
200
201 static const struct irq_domain_ops mvebu_icu_domain_ops = {
202         .translate = mvebu_icu_irq_domain_translate,
203         .alloc     = mvebu_icu_irq_domain_alloc,
204         .free      = mvebu_icu_irq_domain_free,
205 };
206
207 static int mvebu_icu_probe(struct platform_device *pdev)
208 {
209         struct mvebu_icu *icu;
210         struct device_node *node = pdev->dev.of_node;
211         struct device_node *gicp_dn;
212         struct resource *res;
213         int i;
214
215         icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu),
216                            GFP_KERNEL);
217         if (!icu)
218                 return -ENOMEM;
219
220         icu->dev = &pdev->dev;
221
222         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
223         icu->base = devm_ioremap_resource(&pdev->dev, res);
224         if (IS_ERR(icu->base)) {
225                 dev_err(&pdev->dev, "Failed to map icu base address.\n");
226                 return PTR_ERR(icu->base);
227         }
228
229         icu->irq_chip.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
230                                             "ICU.%x",
231                                             (unsigned int)res->start);
232         if (!icu->irq_chip.name)
233                 return -ENOMEM;
234
235         icu->irq_chip.irq_mask = irq_chip_mask_parent;
236         icu->irq_chip.irq_unmask = irq_chip_unmask_parent;
237         icu->irq_chip.irq_eoi = irq_chip_eoi_parent;
238         icu->irq_chip.irq_set_type = irq_chip_set_type_parent;
239 #ifdef CONFIG_SMP
240         icu->irq_chip.irq_set_affinity = irq_chip_set_affinity_parent;
241 #endif
242
243         /*
244          * We're probed after MSI domains have been resolved, so force
245          * resolution here.
246          */
247         pdev->dev.msi_domain = of_msi_get_domain(&pdev->dev, node,
248                                                  DOMAIN_BUS_PLATFORM_MSI);
249         if (!pdev->dev.msi_domain)
250                 return -EPROBE_DEFER;
251
252         gicp_dn = irq_domain_get_of_node(pdev->dev.msi_domain);
253         if (!gicp_dn)
254                 return -ENODEV;
255
256         /*
257          * Clean all ICU interrupts with type SPI_NSR, required to
258          * avoid unpredictable SPI assignments done by firmware.
259          */
260         for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
261                 u32 icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i));
262                 if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR)
263                         writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
264         }
265
266         icu->domain =
267                 platform_msi_create_device_domain(&pdev->dev, ICU_MAX_IRQS,
268                                                   mvebu_icu_write_msg,
269                                                   &mvebu_icu_domain_ops, icu);
270         if (!icu->domain) {
271                 dev_err(&pdev->dev, "Failed to create ICU domain\n");
272                 return -ENOMEM;
273         }
274
275         return 0;
276 }
277
278 static const struct of_device_id mvebu_icu_of_match[] = {
279         { .compatible = "marvell,cp110-icu", },
280         {},
281 };
282
283 static struct platform_driver mvebu_icu_driver = {
284         .probe  = mvebu_icu_probe,
285         .driver = {
286                 .name = "mvebu-icu",
287                 .of_match_table = mvebu_icu_of_match,
288         },
289 };
290 builtin_platform_driver(mvebu_icu_driver);