1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Aspeed AST24XX, AST25XX, and AST26XX SCU Interrupt Controller
4 * Copyright 2019 IBM Corporation
6 * Eddie James <eajames@linux.ibm.com>
9 #include <linux/bitops.h>
10 #include <linux/irq.h>
11 #include <linux/irqchip.h>
12 #include <linux/irqchip/chained_irq.h>
13 #include <linux/irqdomain.h>
14 #include <linux/mfd/syscon.h>
15 #include <linux/of_irq.h>
16 #include <linux/regmap.h>
18 #define ASPEED_SCU_IC_REG 0x018
19 #define ASPEED_SCU_IC_SHIFT 0
20 #define ASPEED_SCU_IC_ENABLE GENMASK(15, ASPEED_SCU_IC_SHIFT)
21 #define ASPEED_SCU_IC_NUM_IRQS 7
22 #define ASPEED_SCU_IC_STATUS GENMASK(28, 16)
23 #define ASPEED_SCU_IC_STATUS_SHIFT 16
25 #define ASPEED_AST2600_SCU_IC0_REG 0x560
26 #define ASPEED_AST2600_SCU_IC0_SHIFT 0
27 #define ASPEED_AST2600_SCU_IC0_ENABLE \
28 GENMASK(5, ASPEED_AST2600_SCU_IC0_SHIFT)
29 #define ASPEED_AST2600_SCU_IC0_NUM_IRQS 6
31 #define ASPEED_AST2600_SCU_IC1_REG 0x570
32 #define ASPEED_AST2600_SCU_IC1_SHIFT 4
33 #define ASPEED_AST2600_SCU_IC1_ENABLE \
34 GENMASK(5, ASPEED_AST2600_SCU_IC1_SHIFT)
35 #define ASPEED_AST2600_SCU_IC1_NUM_IRQS 2
37 struct aspeed_scu_ic
{
38 unsigned long irq_enable
;
39 unsigned long irq_shift
;
40 unsigned int num_irqs
;
43 struct irq_domain
*irq_domain
;
46 static void aspeed_scu_ic_irq_handler(struct irq_desc
*desc
)
50 unsigned long enabled
;
53 struct aspeed_scu_ic
*scu_ic
= irq_desc_get_handler_data(desc
);
54 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
55 unsigned int mask
= scu_ic
->irq_enable
<< ASPEED_SCU_IC_STATUS_SHIFT
;
57 chained_irq_enter(chip
, desc
);
60 * The SCU IC has just one register to control its operation and read
61 * status. The interrupt enable bits occupy the lower 16 bits of the
62 * register, while the interrupt status bits occupy the upper 16 bits.
63 * The status bit for a given interrupt is always 16 bits shifted from
64 * the enable bit for the same interrupt.
65 * Therefore, perform the IRQ operations in the enable bit space by
66 * shifting the status down to get the mapping and then back up to
69 regmap_read(scu_ic
->scu
, scu_ic
->reg
, &sts
);
70 enabled
= sts
& scu_ic
->irq_enable
;
71 status
= (sts
>> ASPEED_SCU_IC_STATUS_SHIFT
) & enabled
;
73 bit
= scu_ic
->irq_shift
;
74 max
= scu_ic
->num_irqs
+ bit
;
76 for_each_set_bit_from(bit
, &status
, max
) {
77 generic_handle_domain_irq(scu_ic
->irq_domain
,
78 bit
- scu_ic
->irq_shift
);
80 regmap_write_bits(scu_ic
->scu
, scu_ic
->reg
, mask
,
81 BIT(bit
+ ASPEED_SCU_IC_STATUS_SHIFT
));
84 chained_irq_exit(chip
, desc
);
87 static void aspeed_scu_ic_irq_mask(struct irq_data
*data
)
89 struct aspeed_scu_ic
*scu_ic
= irq_data_get_irq_chip_data(data
);
90 unsigned int mask
= BIT(data
->hwirq
+ scu_ic
->irq_shift
) |
91 (scu_ic
->irq_enable
<< ASPEED_SCU_IC_STATUS_SHIFT
);
94 * Status bits are cleared by writing 1. In order to prevent the mask
95 * operation from clearing the status bits, they should be under the
96 * mask and written with 0.
98 regmap_update_bits(scu_ic
->scu
, scu_ic
->reg
, mask
, 0);
101 static void aspeed_scu_ic_irq_unmask(struct irq_data
*data
)
103 struct aspeed_scu_ic
*scu_ic
= irq_data_get_irq_chip_data(data
);
104 unsigned int bit
= BIT(data
->hwirq
+ scu_ic
->irq_shift
);
105 unsigned int mask
= bit
|
106 (scu_ic
->irq_enable
<< ASPEED_SCU_IC_STATUS_SHIFT
);
109 * Status bits are cleared by writing 1. In order to prevent the unmask
110 * operation from clearing the status bits, they should be under the
111 * mask and written with 0.
113 regmap_update_bits(scu_ic
->scu
, scu_ic
->reg
, mask
, bit
);
116 static int aspeed_scu_ic_irq_set_affinity(struct irq_data
*data
,
117 const struct cpumask
*dest
,
123 static struct irq_chip aspeed_scu_ic_chip
= {
124 .name
= "aspeed-scu-ic",
125 .irq_mask
= aspeed_scu_ic_irq_mask
,
126 .irq_unmask
= aspeed_scu_ic_irq_unmask
,
127 .irq_set_affinity
= aspeed_scu_ic_irq_set_affinity
,
130 static int aspeed_scu_ic_map(struct irq_domain
*domain
, unsigned int irq
,
131 irq_hw_number_t hwirq
)
133 irq_set_chip_and_handler(irq
, &aspeed_scu_ic_chip
, handle_level_irq
);
134 irq_set_chip_data(irq
, domain
->host_data
);
139 static const struct irq_domain_ops aspeed_scu_ic_domain_ops
= {
140 .map
= aspeed_scu_ic_map
,
143 static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic
*scu_ic
,
144 struct device_node
*node
)
154 scu_ic
->scu
= syscon_node_to_regmap(node
->parent
);
155 if (IS_ERR(scu_ic
->scu
)) {
156 rc
= PTR_ERR(scu_ic
->scu
);
159 regmap_write_bits(scu_ic
->scu
, scu_ic
->reg
, ASPEED_SCU_IC_STATUS
, ASPEED_SCU_IC_STATUS
);
160 regmap_write_bits(scu_ic
->scu
, scu_ic
->reg
, ASPEED_SCU_IC_ENABLE
, 0);
162 irq
= irq_of_parse_and_map(node
, 0);
168 scu_ic
->irq_domain
= irq_domain_add_linear(node
, scu_ic
->num_irqs
,
169 &aspeed_scu_ic_domain_ops
,
171 if (!scu_ic
->irq_domain
) {
176 irq_set_chained_handler_and_data(irq
, aspeed_scu_ic_irq_handler
,
187 static int __init
aspeed_scu_ic_of_init(struct device_node
*node
,
188 struct device_node
*parent
)
190 struct aspeed_scu_ic
*scu_ic
= kzalloc(sizeof(*scu_ic
), GFP_KERNEL
);
195 scu_ic
->irq_enable
= ASPEED_SCU_IC_ENABLE
;
196 scu_ic
->irq_shift
= ASPEED_SCU_IC_SHIFT
;
197 scu_ic
->num_irqs
= ASPEED_SCU_IC_NUM_IRQS
;
198 scu_ic
->reg
= ASPEED_SCU_IC_REG
;
200 return aspeed_scu_ic_of_init_common(scu_ic
, node
);
203 static int __init
aspeed_ast2600_scu_ic0_of_init(struct device_node
*node
,
204 struct device_node
*parent
)
206 struct aspeed_scu_ic
*scu_ic
= kzalloc(sizeof(*scu_ic
), GFP_KERNEL
);
211 scu_ic
->irq_enable
= ASPEED_AST2600_SCU_IC0_ENABLE
;
212 scu_ic
->irq_shift
= ASPEED_AST2600_SCU_IC0_SHIFT
;
213 scu_ic
->num_irqs
= ASPEED_AST2600_SCU_IC0_NUM_IRQS
;
214 scu_ic
->reg
= ASPEED_AST2600_SCU_IC0_REG
;
216 return aspeed_scu_ic_of_init_common(scu_ic
, node
);
219 static int __init
aspeed_ast2600_scu_ic1_of_init(struct device_node
*node
,
220 struct device_node
*parent
)
222 struct aspeed_scu_ic
*scu_ic
= kzalloc(sizeof(*scu_ic
), GFP_KERNEL
);
227 scu_ic
->irq_enable
= ASPEED_AST2600_SCU_IC1_ENABLE
;
228 scu_ic
->irq_shift
= ASPEED_AST2600_SCU_IC1_SHIFT
;
229 scu_ic
->num_irqs
= ASPEED_AST2600_SCU_IC1_NUM_IRQS
;
230 scu_ic
->reg
= ASPEED_AST2600_SCU_IC1_REG
;
232 return aspeed_scu_ic_of_init_common(scu_ic
, node
);
235 IRQCHIP_DECLARE(ast2400_scu_ic
, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init
);
236 IRQCHIP_DECLARE(ast2500_scu_ic
, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init
);
237 IRQCHIP_DECLARE(ast2600_scu_ic0
, "aspeed,ast2600-scu-ic0",
238 aspeed_ast2600_scu_ic0_of_init
);
239 IRQCHIP_DECLARE(ast2600_scu_ic1
, "aspeed,ast2600-scu-ic1",
240 aspeed_ast2600_scu_ic1_of_init
);