summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-mvebu-icu.c
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2018-05-08 08:14:32 -0400
committerThomas Gleixner <tglx@linutronix.de>2018-05-13 09:59:00 -0400
commit25eaaabb51c9925dc65f5b54fd9a362bf118e70a (patch)
treea2909723beda59d3fe019ae40bc2076ae1541679 /drivers/irqchip/irq-mvebu-icu.c
parent6988e0e0d28328467e218f59589b2770675a9ebd (diff)
irqchip/mvebu-gicp: Use level-triggered MSIs between ICU and GICP
The ICU and GICP drivers are using an ugly side-band mechanism to find out about the "clear" doorbell when using level interrupts. Let's convert it to level-triggered MSIs, which result in a nice cleanup. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Miquel Raynal <miquel.raynal@bootlin.com> Cc: Rob Herring <robh@kernel.org> Cc: Jason Cooper <jason@lakedaemon.net> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com> Link: https://lkml.kernel.org/r/20180508121438.11301-4-marc.zyngier@arm.com
Diffstat (limited to 'drivers/irqchip/irq-mvebu-icu.c')
-rw-r--r--drivers/irqchip/irq-mvebu-icu.c33
1 files changed, 17 insertions, 16 deletions
diff --git a/drivers/irqchip/irq-mvebu-icu.c b/drivers/irqchip/irq-mvebu-icu.c
index e18c48d3a92e..13063339b416 100644
--- a/drivers/irqchip/irq-mvebu-icu.c
+++ b/drivers/irqchip/irq-mvebu-icu.c
@@ -21,8 +21,6 @@
21 21
22#include <dt-bindings/interrupt-controller/mvebu-icu.h> 22#include <dt-bindings/interrupt-controller/mvebu-icu.h>
23 23
24#include "irq-mvebu-gicp.h"
25
26/* ICU registers */ 24/* ICU registers */
27#define ICU_SETSPI_NSR_AL 0x10 25#define ICU_SETSPI_NSR_AL 0x10
28#define ICU_SETSPI_NSR_AH 0x14 26#define ICU_SETSPI_NSR_AH 0x14
@@ -43,6 +41,7 @@ struct mvebu_icu {
43 void __iomem *base; 41 void __iomem *base;
44 struct irq_domain *domain; 42 struct irq_domain *domain;
45 struct device *dev; 43 struct device *dev;
44 atomic_t initialized;
46}; 45};
47 46
48struct mvebu_icu_irq_data { 47struct mvebu_icu_irq_data {
@@ -51,6 +50,18 @@ struct mvebu_icu_irq_data {
51 unsigned int type; 50 unsigned int type;
52}; 51};
53 52
53static 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
54static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg) 65static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
55{ 66{
56 struct irq_data *d = irq_get_irq_data(desc->irq); 67 struct irq_data *d = irq_get_irq_data(desc->irq);
@@ -59,6 +70,8 @@ static void mvebu_icu_write_msg(struct msi_desc *desc, struct msi_msg *msg)
59 unsigned int icu_int; 70 unsigned int icu_int;
60 71
61 if (msg->address_lo || msg->address_hi) { 72 if (msg->address_lo || msg->address_hi) {
73 /* One off initialization */
74 mvebu_icu_init(icu, msg);
62 /* Configure the ICU with irq number & type */ 75 /* Configure the ICU with irq number & type */
63 icu_int = msg->data | ICU_INT_ENABLE; 76 icu_int = msg->data | ICU_INT_ENABLE;
64 if (icu_irqd->type & IRQ_TYPE_EDGE_RISING) 77 if (icu_irqd->type & IRQ_TYPE_EDGE_RISING)
@@ -197,9 +210,7 @@ static int mvebu_icu_probe(struct platform_device *pdev)
197 struct device_node *node = pdev->dev.of_node; 210 struct device_node *node = pdev->dev.of_node;
198 struct device_node *gicp_dn; 211 struct device_node *gicp_dn;
199 struct resource *res; 212 struct resource *res;
200 phys_addr_t setspi, clrspi; 213 int i;
201 u32 i, icu_int;
202 int ret;
203 214
204 icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu), 215 icu = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_icu),
205 GFP_KERNEL); 216 GFP_KERNEL);
@@ -242,22 +253,12 @@ static int mvebu_icu_probe(struct platform_device *pdev)
242 if (!gicp_dn) 253 if (!gicp_dn)
243 return -ENODEV; 254 return -ENODEV;
244 255
245 ret = mvebu_gicp_get_doorbells(gicp_dn, &setspi, &clrspi);
246 if (ret)
247 return ret;
248
249 /* Set Clear/Set ICU SPI message address in AP */
250 writel_relaxed(upper_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AH);
251 writel_relaxed(lower_32_bits(setspi), icu->base + ICU_SETSPI_NSR_AL);
252 writel_relaxed(upper_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AH);
253 writel_relaxed(lower_32_bits(clrspi), icu->base + ICU_CLRSPI_NSR_AL);
254
255 /* 256 /*
256 * Clean all ICU interrupts with type SPI_NSR, required to 257 * Clean all ICU interrupts with type SPI_NSR, required to
257 * avoid unpredictable SPI assignments done by firmware. 258 * avoid unpredictable SPI assignments done by firmware.
258 */ 259 */
259 for (i = 0 ; i < ICU_MAX_IRQS ; i++) { 260 for (i = 0 ; i < ICU_MAX_IRQS ; i++) {
260 icu_int = readl(icu->base + ICU_INT_CFG(i)); 261 u32 icu_int = readl_relaxed(icu->base + ICU_INT_CFG(i));
261 if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR) 262 if ((icu_int >> ICU_GROUP_SHIFT) == ICU_GRP_NSR)
262 writel_relaxed(0x0, icu->base + ICU_INT_CFG(i)); 263 writel_relaxed(0x0, icu->base + ICU_INT_CFG(i));
263 } 264 }