1 // SPDX-License-Identifier: GPL-2.0-only
3 * Aspeed Interrupt Controller.
5 * Copyright (C) 2023 ASPEED Technology Inc.
8 #include <linux/bitops.h>
10 #include <linux/irqchip.h>
11 #include <linux/irqchip/chained_irq.h>
12 #include <linux/irqdomain.h>
13 #include <linux/of_address.h>
14 #include <linux/of_irq.h>
16 #include <linux/spinlock.h>
18 #define INTC_INT_ENABLE_REG 0x00
19 #define INTC_INT_STATUS_REG 0x04
20 #define INTC_IRQS_PER_WORD 32
22 struct aspeed_intc_ic
{
24 raw_spinlock_t gic_lock
;
25 raw_spinlock_t intc_lock
;
26 struct irq_domain
*irq_domain
;
29 static void aspeed_intc_ic_irq_handler(struct irq_desc
*desc
)
31 struct aspeed_intc_ic
*intc_ic
= irq_desc_get_handler_data(desc
);
32 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
34 chained_irq_enter(chip
, desc
);
36 scoped_guard(raw_spinlock
, &intc_ic
->gic_lock
) {
37 unsigned long bit
, status
;
39 status
= readl(intc_ic
->base
+ INTC_INT_STATUS_REG
);
40 for_each_set_bit(bit
, &status
, INTC_IRQS_PER_WORD
) {
41 generic_handle_domain_irq(intc_ic
->irq_domain
, bit
);
42 writel(BIT(bit
), intc_ic
->base
+ INTC_INT_STATUS_REG
);
46 chained_irq_exit(chip
, desc
);
49 static void aspeed_intc_irq_mask(struct irq_data
*data
)
51 struct aspeed_intc_ic
*intc_ic
= irq_data_get_irq_chip_data(data
);
52 unsigned int mask
= readl(intc_ic
->base
+ INTC_INT_ENABLE_REG
) & ~BIT(data
->hwirq
);
54 guard(raw_spinlock
)(&intc_ic
->intc_lock
);
55 writel(mask
, intc_ic
->base
+ INTC_INT_ENABLE_REG
);
58 static void aspeed_intc_irq_unmask(struct irq_data
*data
)
60 struct aspeed_intc_ic
*intc_ic
= irq_data_get_irq_chip_data(data
);
61 unsigned int unmask
= readl(intc_ic
->base
+ INTC_INT_ENABLE_REG
) | BIT(data
->hwirq
);
63 guard(raw_spinlock
)(&intc_ic
->intc_lock
);
64 writel(unmask
, intc_ic
->base
+ INTC_INT_ENABLE_REG
);
67 static struct irq_chip aspeed_intc_chip
= {
68 .name
= "ASPEED INTC",
69 .irq_mask
= aspeed_intc_irq_mask
,
70 .irq_unmask
= aspeed_intc_irq_unmask
,
73 static int aspeed_intc_ic_map_irq_domain(struct irq_domain
*domain
, unsigned int irq
,
74 irq_hw_number_t hwirq
)
76 irq_set_chip_and_handler(irq
, &aspeed_intc_chip
, handle_level_irq
);
77 irq_set_chip_data(irq
, domain
->host_data
);
82 static const struct irq_domain_ops aspeed_intc_ic_irq_domain_ops
= {
83 .map
= aspeed_intc_ic_map_irq_domain
,
86 static int __init
aspeed_intc_ic_of_init(struct device_node
*node
,
87 struct device_node
*parent
)
89 struct aspeed_intc_ic
*intc_ic
;
92 intc_ic
= kzalloc(sizeof(*intc_ic
), GFP_KERNEL
);
96 intc_ic
->base
= of_iomap(node
, 0);
98 pr_err("Failed to iomap intc_ic base\n");
102 writel(0xffffffff, intc_ic
->base
+ INTC_INT_STATUS_REG
);
103 writel(0x0, intc_ic
->base
+ INTC_INT_ENABLE_REG
);
105 intc_ic
->irq_domain
= irq_domain_add_linear(node
, INTC_IRQS_PER_WORD
,
106 &aspeed_intc_ic_irq_domain_ops
, intc_ic
);
107 if (!intc_ic
->irq_domain
) {
112 raw_spin_lock_init(&intc_ic
->gic_lock
);
113 raw_spin_lock_init(&intc_ic
->intc_lock
);
115 /* Check all the irq numbers valid. If not, unmaps all the base and frees the data. */
116 for (i
= 0; i
< of_irq_count(node
); i
++) {
117 irq
= irq_of_parse_and_map(node
, i
);
119 pr_err("Failed to get irq number\n");
125 for (i
= 0; i
< of_irq_count(node
); i
++) {
126 irq
= irq_of_parse_and_map(node
, i
);
127 irq_set_chained_handler_and_data(irq
, aspeed_intc_ic_irq_handler
, intc_ic
);
133 iounmap(intc_ic
->base
);
139 IRQCHIP_DECLARE(ast2700_intc_ic
, "aspeed,ast2700-intc-ic", aspeed_intc_ic_of_init
);