Skip to content

Commit b2a0c13

Browse files
aspeedtechKAGA-KOKO
authored andcommitted
irqchip/aspeed-scu-ic: Add support for AST2700 SCU interrupt controllers
AST2700 continues the multi-instance SCU interrupt controller model introduced in the AST2600, with four independent interrupt domains (scu-ic0 to 3). Unlike earlier generations which combine interrupt enable and status bits into a single register, AST2700 separates these into distinct IER and ISR registers. Support for this layout is implemented by using register offsets and separate chained IRQ handlers. The variant table is extended to cover AST2700 IC instances, enabling shared initialization logic while preserving support for previous SoCs. [ tglx: Simplified the logic and cleaned up coding style ] Signed-off-by: Ryan Chen <ryan_chen@aspeedtech.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/all/20250908011812.1033858-5-ryan_chen@aspeedtech.com
1 parent ed72404 commit b2a0c13

File tree

1 file changed

+102
-17
lines changed

1 file changed

+102
-17
lines changed

drivers/irqchip/irq-aspeed-scu-ic.c

Lines changed: 102 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: GPL-2.0-or-later
22
/*
3-
* Aspeed AST24XX, AST25XX, and AST26XX SCU Interrupt Controller
3+
* Aspeed AST24XX, AST25XX, AST26XX, and AST27XX SCU Interrupt Controller
44
* Copyright 2019 IBM Corporation
55
*
66
* Eddie James <eajames@linux.ibm.com>
@@ -17,26 +17,35 @@
1717

1818
#define ASPEED_SCU_IC_STATUS GENMASK(28, 16)
1919
#define ASPEED_SCU_IC_STATUS_SHIFT 16
20+
#define AST2700_SCU_IC_STATUS GENMASK(15, 0)
2021

2122
struct aspeed_scu_ic_variant {
2223
const char *compatible;
2324
unsigned long irq_enable;
2425
unsigned long irq_shift;
2526
unsigned int num_irqs;
27+
unsigned long ier;
28+
unsigned long isr;
2629
};
2730

28-
#define SCU_VARIANT(_compat, _shift, _enable, _num) { \
31+
#define SCU_VARIANT(_compat, _shift, _enable, _num, _ier, _isr) { \
2932
.compatible = _compat, \
3033
.irq_shift = _shift, \
3134
.irq_enable = _enable, \
3235
.num_irqs = _num, \
36+
.ier = _ier, \
37+
.isr = _isr, \
3338
}
3439

3540
static const struct aspeed_scu_ic_variant scu_ic_variants[] __initconst = {
36-
SCU_VARIANT("aspeed,ast2400-scu-ic", 0, GENMASK(15, 0), 7),
37-
SCU_VARIANT("aspeed,ast2500-scu-ic", 0, GENMASK(15, 0), 7),
38-
SCU_VARIANT("aspeed,ast2600-scu-ic0", 0, GENMASK(5, 0), 6),
39-
SCU_VARIANT("aspeed,ast2600-scu-ic1", 4, GENMASK(5, 4), 2),
41+
SCU_VARIANT("aspeed,ast2400-scu-ic", 0, GENMASK(15, 0), 7, 0x00, 0x00),
42+
SCU_VARIANT("aspeed,ast2500-scu-ic", 0, GENMASK(15, 0), 7, 0x00, 0x00),
43+
SCU_VARIANT("aspeed,ast2600-scu-ic0", 0, GENMASK(5, 0), 6, 0x00, 0x00),
44+
SCU_VARIANT("aspeed,ast2600-scu-ic1", 4, GENMASK(5, 4), 2, 0x00, 0x00),
45+
SCU_VARIANT("aspeed,ast2700-scu-ic0", 0, GENMASK(3, 0), 4, 0x00, 0x04),
46+
SCU_VARIANT("aspeed,ast2700-scu-ic1", 0, GENMASK(3, 0), 4, 0x00, 0x04),
47+
SCU_VARIANT("aspeed,ast2700-scu-ic2", 0, GENMASK(3, 0), 4, 0x04, 0x00),
48+
SCU_VARIANT("aspeed,ast2700-scu-ic3", 0, GENMASK(1, 0), 2, 0x04, 0x00),
4049
};
4150

4251
struct aspeed_scu_ic {
@@ -45,9 +54,16 @@ struct aspeed_scu_ic {
4554
unsigned int num_irqs;
4655
void __iomem *base;
4756
struct irq_domain *irq_domain;
57+
unsigned long ier;
58+
unsigned long isr;
4859
};
4960

50-
static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
61+
static inline bool scu_has_split_isr(struct aspeed_scu_ic *scu)
62+
{
63+
return scu->ier != scu->isr;
64+
}
65+
66+
static void aspeed_scu_ic_irq_handler_combined(struct irq_desc *desc)
5167
{
5268
struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc);
5369
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -83,7 +99,34 @@ static void aspeed_scu_ic_irq_handler(struct irq_desc *desc)
8399
chained_irq_exit(chip, desc);
84100
}
85101

86-
static void aspeed_scu_ic_irq_mask(struct irq_data *data)
102+
static void aspeed_scu_ic_irq_handler_split(struct irq_desc *desc)
103+
{
104+
struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc);
105+
struct irq_chip *chip = irq_desc_get_chip(desc);
106+
unsigned long bit, enabled, max, status;
107+
unsigned int sts, mask;
108+
109+
chained_irq_enter(chip, desc);
110+
111+
mask = scu_ic->irq_enable;
112+
sts = readl(scu_ic->base + scu_ic->isr);
113+
enabled = sts & scu_ic->irq_enable;
114+
sts = readl(scu_ic->base + scu_ic->isr);
115+
status = sts & enabled;
116+
117+
bit = scu_ic->irq_shift;
118+
max = scu_ic->num_irqs + bit;
119+
120+
for_each_set_bit_from(bit, &status, max) {
121+
generic_handle_domain_irq(scu_ic->irq_domain, bit - scu_ic->irq_shift);
122+
/* Clear interrupt */
123+
writel(BIT(bit), scu_ic->base + scu_ic->isr);
124+
}
125+
126+
chained_irq_exit(chip, desc);
127+
}
128+
129+
static void aspeed_scu_ic_irq_mask_combined(struct irq_data *data)
87130
{
88131
struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
89132
unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift);
@@ -97,7 +140,7 @@ static void aspeed_scu_ic_irq_mask(struct irq_data *data)
97140
writel(readl(scu_ic->base) & ~mask, scu_ic->base);
98141
}
99142

100-
static void aspeed_scu_ic_irq_unmask(struct irq_data *data)
143+
static void aspeed_scu_ic_irq_unmask_combined(struct irq_data *data)
101144
{
102145
struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
103146
unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift);
@@ -111,24 +154,52 @@ static void aspeed_scu_ic_irq_unmask(struct irq_data *data)
111154
writel((readl(scu_ic->base) & ~mask) | bit, scu_ic->base);
112155
}
113156

157+
static void aspeed_scu_ic_irq_mask_split(struct irq_data *data)
158+
{
159+
struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
160+
unsigned int mask = BIT(data->hwirq + scu_ic->irq_shift);
161+
162+
writel(readl(scu_ic->base) & ~mask, scu_ic->base + scu_ic->ier);
163+
}
164+
165+
static void aspeed_scu_ic_irq_unmask_split(struct irq_data *data)
166+
{
167+
struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data);
168+
unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift);
169+
170+
writel(readl(scu_ic->base) | bit, scu_ic->base + scu_ic->ier);
171+
}
172+
114173
static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data,
115174
const struct cpumask *dest,
116175
bool force)
117176
{
118177
return -EINVAL;
119178
}
120179

121-
static struct irq_chip aspeed_scu_ic_chip = {
180+
static struct irq_chip aspeed_scu_ic_chip_combined = {
122181
.name = "aspeed-scu-ic",
123-
.irq_mask = aspeed_scu_ic_irq_mask,
124-
.irq_unmask = aspeed_scu_ic_irq_unmask,
125-
.irq_set_affinity = aspeed_scu_ic_irq_set_affinity,
182+
.irq_mask = aspeed_scu_ic_irq_mask_combined,
183+
.irq_unmask = aspeed_scu_ic_irq_unmask_combined,
184+
.irq_set_affinity = aspeed_scu_ic_irq_set_affinity,
185+
};
186+
187+
static struct irq_chip aspeed_scu_ic_chip_split = {
188+
.name = "ast2700-scu-ic",
189+
.irq_mask = aspeed_scu_ic_irq_mask_split,
190+
.irq_unmask = aspeed_scu_ic_irq_unmask_split,
191+
.irq_set_affinity = aspeed_scu_ic_irq_set_affinity,
126192
};
127193

128194
static int aspeed_scu_ic_map(struct irq_domain *domain, unsigned int irq,
129195
irq_hw_number_t hwirq)
130196
{
131-
irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip, handle_level_irq);
197+
struct aspeed_scu_ic *scu_ic = domain->host_data;
198+
199+
if (scu_has_split_isr(scu_ic))
200+
irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip_split, handle_level_irq);
201+
else
202+
irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip_combined, handle_level_irq);
132203
irq_set_chip_data(irq, domain->host_data);
133204

134205
return 0;
@@ -148,8 +219,14 @@ static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic *scu_ic,
148219
rc = PTR_ERR(scu_ic->base);
149220
goto err;
150221
}
151-
writel(ASPEED_SCU_IC_STATUS, scu_ic->base);
152-
writel(0, scu_ic->base);
222+
223+
if (scu_has_split_isr(scu_ic)) {
224+
writel(AST2700_SCU_IC_STATUS, scu_ic->base + scu_ic->isr);
225+
writel(0, scu_ic->base + scu_ic->ier);
226+
} else {
227+
writel(ASPEED_SCU_IC_STATUS, scu_ic->base);
228+
writel(0, scu_ic->base);
229+
}
153230

154231
irq = irq_of_parse_and_map(node, 0);
155232
if (!irq) {
@@ -164,7 +241,9 @@ static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic *scu_ic,
164241
goto err;
165242
}
166243

167-
irq_set_chained_handler_and_data(irq, aspeed_scu_ic_irq_handler,
244+
irq_set_chained_handler_and_data(irq, scu_has_split_isr(scu_ic) ?
245+
aspeed_scu_ic_irq_handler_split :
246+
aspeed_scu_ic_irq_handler_combined,
168247
scu_ic);
169248

170249
return 0;
@@ -199,6 +278,8 @@ static int __init aspeed_scu_ic_of_init(struct device_node *node, struct device_
199278
scu_ic->irq_enable = variant->irq_enable;
200279
scu_ic->irq_shift = variant->irq_shift;
201280
scu_ic->num_irqs = variant->num_irqs;
281+
scu_ic->ier = variant->ier;
282+
scu_ic->isr = variant->isr;
202283

203284
return aspeed_scu_ic_of_init_common(scu_ic, node);
204285
}
@@ -207,3 +288,7 @@ IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init);
207288
IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init);
208289
IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", aspeed_scu_ic_of_init);
209290
IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1", aspeed_scu_ic_of_init);
291+
IRQCHIP_DECLARE(ast2700_scu_ic0, "aspeed,ast2700-scu-ic0", aspeed_scu_ic_of_init);
292+
IRQCHIP_DECLARE(ast2700_scu_ic1, "aspeed,ast2700-scu-ic1", aspeed_scu_ic_of_init);
293+
IRQCHIP_DECLARE(ast2700_scu_ic2, "aspeed,ast2700-scu-ic2", aspeed_scu_ic_of_init);
294+
IRQCHIP_DECLARE(ast2700_scu_ic3, "aspeed,ast2700-scu-ic3", aspeed_scu_ic_of_init);

0 commit comments

Comments
 (0)