Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

irqchip/aspeed-scu-ic: Refactor driver to support variant-based initialization

The SCU IC driver handles each AST2600 instance with separate
initialization functions and hardcoded register definitions, which is
inflexible and creates duplicated code.

Consolidate the implementation by introducing a variant-based structure,
selected via compatible string, and use a unified init path and MMIO access
via of_iomap(). This simplifies the code and prepares for upcoming SoCs
like AST2700, which require split register handling.

[ tglx: Cleaned up coding style and massaged change log ]

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-2-ryan_chen@aspeedtech.com

authored by

Ryan Chen and committed by
Thomas Gleixner
86cd4301 a186120c

+64 -95
+64 -95
drivers/irqchip/irq-aspeed-scu-ic.c
··· 7 7 */ 8 8 9 9 #include <linux/bitops.h> 10 + #include <linux/io.h> 10 11 #include <linux/irq.h> 11 12 #include <linux/irqchip.h> 12 13 #include <linux/irqchip/chained_irq.h> 13 14 #include <linux/irqdomain.h> 14 - #include <linux/mfd/syscon.h> 15 + #include <linux/of_address.h> 15 16 #include <linux/of_irq.h> 16 - #include <linux/regmap.h> 17 17 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 18 #define ASPEED_SCU_IC_STATUS GENMASK(28, 16) 23 19 #define ASPEED_SCU_IC_STATUS_SHIFT 16 24 20 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 21 + struct aspeed_scu_ic_variant { 22 + const char *compatible; 23 + unsigned long irq_enable; 24 + unsigned long irq_shift; 25 + unsigned int num_irqs; 26 + }; 30 27 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 28 + #define SCU_VARIANT(_compat, _shift, _enable, _num) { \ 29 + .compatible = _compat, \ 30 + .irq_shift = _shift, \ 31 + .irq_enable = _enable, \ 32 + .num_irqs = _num, \ 33 + } 34 + 35 + 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), 40 + }; 36 41 37 42 struct aspeed_scu_ic { 38 - unsigned long irq_enable; 39 - unsigned long irq_shift; 40 - unsigned int num_irqs; 41 - unsigned int reg; 42 - struct regmap *scu; 43 - struct irq_domain *irq_domain; 43 + unsigned long irq_enable; 44 + unsigned long irq_shift; 45 + unsigned int num_irqs; 46 + void __iomem *base; 47 + struct irq_domain *irq_domain; 44 48 }; 45 49 46 50 static void aspeed_scu_ic_irq_handler(struct irq_desc *desc) 47 51 { 48 - unsigned int sts; 49 - unsigned long bit; 50 - unsigned long enabled; 51 - unsigned long max; 52 - unsigned long status; 53 52 struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc); 54 53 struct irq_chip *chip = irq_desc_get_chip(desc); 55 - unsigned int mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT; 54 + unsigned long bit, enabled, max, status; 55 + unsigned int sts, mask; 56 56 57 57 chained_irq_enter(chip, desc); 58 58 59 + mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT; 59 60 /* 60 61 * The SCU IC has just one register to control its operation and read 61 62 * status. The interrupt enable bits occupy the lower 16 bits of the ··· 67 66 * shifting the status down to get the mapping and then back up to 68 67 * clear the bit. 69 68 */ 70 - regmap_read(scu_ic->scu, scu_ic->reg, &sts); 69 + sts = readl(scu_ic->base); 71 70 enabled = sts & scu_ic->irq_enable; 72 71 status = (sts >> ASPEED_SCU_IC_STATUS_SHIFT) & enabled; 73 72 ··· 75 74 max = scu_ic->num_irqs + bit; 76 75 77 76 for_each_set_bit_from(bit, &status, max) { 78 - generic_handle_domain_irq(scu_ic->irq_domain, 79 - bit - scu_ic->irq_shift); 80 - 81 - regmap_write_bits(scu_ic->scu, scu_ic->reg, mask, 82 - BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT)); 77 + generic_handle_domain_irq(scu_ic->irq_domain, bit - scu_ic->irq_shift); 78 + writel((readl(scu_ic->base) & ~mask) | BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT), 79 + scu_ic->base); 83 80 } 84 81 85 82 chained_irq_exit(chip, desc); ··· 86 87 static void aspeed_scu_ic_irq_mask(struct irq_data *data) 87 88 { 88 89 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 89 - unsigned int mask = BIT(data->hwirq + scu_ic->irq_shift) | 90 - (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 90 + unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); 91 + unsigned int mask = bit | (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 91 92 92 93 /* 93 94 * Status bits are cleared by writing 1. In order to prevent the mask 94 95 * operation from clearing the status bits, they should be under the 95 96 * mask and written with 0. 96 97 */ 97 - regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, 0); 98 + writel(readl(scu_ic->base) & ~mask, scu_ic->base); 98 99 } 99 100 100 101 static void aspeed_scu_ic_irq_unmask(struct irq_data *data) 101 102 { 102 103 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 103 104 unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); 104 - unsigned int mask = bit | 105 - (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 105 + unsigned int mask = bit | (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 106 106 107 107 /* 108 108 * Status bits are cleared by writing 1. In order to prevent the unmask 109 109 * operation from clearing the status bits, they should be under the 110 110 * mask and written with 0. 111 111 */ 112 - regmap_update_bits(scu_ic->scu, scu_ic->reg, mask, bit); 112 + writel((readl(scu_ic->base) & ~mask) | bit, scu_ic->base); 113 113 } 114 114 115 115 static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data, ··· 141 143 static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic *scu_ic, 142 144 struct device_node *node) 143 145 { 144 - int irq; 145 - int rc = 0; 146 + int irq, rc = 0; 146 147 147 - if (!node->parent) { 148 - rc = -ENODEV; 148 + scu_ic->base = of_iomap(node, 0); 149 + if (IS_ERR(scu_ic->base)) { 150 + rc = PTR_ERR(scu_ic->base); 149 151 goto err; 150 152 } 151 - 152 - scu_ic->scu = syscon_node_to_regmap(node->parent); 153 - if (IS_ERR(scu_ic->scu)) { 154 - rc = PTR_ERR(scu_ic->scu); 155 - goto err; 156 - } 157 - regmap_write_bits(scu_ic->scu, scu_ic->reg, ASPEED_SCU_IC_STATUS, ASPEED_SCU_IC_STATUS); 158 - regmap_write_bits(scu_ic->scu, scu_ic->reg, ASPEED_SCU_IC_ENABLE, 0); 153 + writel(ASPEED_SCU_IC_STATUS, scu_ic->base); 154 + writel(0, scu_ic->base); 159 155 160 156 irq = irq_of_parse_and_map(node, 0); 161 157 if (!irq) { ··· 158 166 } 159 167 160 168 scu_ic->irq_domain = irq_domain_create_linear(of_fwnode_handle(node), scu_ic->num_irqs, 161 - &aspeed_scu_ic_domain_ops, 162 - scu_ic); 169 + &aspeed_scu_ic_domain_ops, scu_ic); 163 170 if (!scu_ic->irq_domain) { 164 171 rc = -ENOMEM; 165 172 goto err; ··· 171 180 172 181 err: 173 182 kfree(scu_ic); 174 - 175 183 return rc; 176 184 } 177 185 178 - static int __init aspeed_scu_ic_of_init(struct device_node *node, 179 - struct device_node *parent) 186 + static const struct aspeed_scu_ic_variant *aspeed_scu_ic_find_variant(struct device_node *np) 180 187 { 181 - struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); 182 - 183 - if (!scu_ic) 184 - return -ENOMEM; 185 - 186 - scu_ic->irq_enable = ASPEED_SCU_IC_ENABLE; 187 - scu_ic->irq_shift = ASPEED_SCU_IC_SHIFT; 188 - scu_ic->num_irqs = ASPEED_SCU_IC_NUM_IRQS; 189 - scu_ic->reg = ASPEED_SCU_IC_REG; 190 - 191 - return aspeed_scu_ic_of_init_common(scu_ic, node); 188 + for (int i = 0; i < ARRAY_SIZE(scu_ic_variants); i++) { 189 + if (of_device_is_compatible(np, scu_ic_variants[i].compatible)) 190 + return &scu_ic_variants[i]; 191 + } 192 + return NULL; 192 193 } 193 194 194 - static int __init aspeed_ast2600_scu_ic0_of_init(struct device_node *node, 195 - struct device_node *parent) 195 + static int __init aspeed_scu_ic_of_init(struct device_node *node, struct device_node *parent) 196 196 { 197 - struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); 197 + const struct aspeed_scu_ic_variant *variant; 198 + struct aspeed_scu_ic *scu_ic; 198 199 200 + variant = aspeed_scu_ic_find_variant(node); 201 + if (!variant) 202 + return -ENODEV; 203 + 204 + scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); 199 205 if (!scu_ic) 200 206 return -ENOMEM; 201 207 202 - scu_ic->irq_enable = ASPEED_AST2600_SCU_IC0_ENABLE; 203 - scu_ic->irq_shift = ASPEED_AST2600_SCU_IC0_SHIFT; 204 - scu_ic->num_irqs = ASPEED_AST2600_SCU_IC0_NUM_IRQS; 205 - scu_ic->reg = ASPEED_AST2600_SCU_IC0_REG; 206 - 207 - return aspeed_scu_ic_of_init_common(scu_ic, node); 208 - } 209 - 210 - static int __init aspeed_ast2600_scu_ic1_of_init(struct device_node *node, 211 - struct device_node *parent) 212 - { 213 - struct aspeed_scu_ic *scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); 214 - 215 - if (!scu_ic) 216 - return -ENOMEM; 217 - 218 - scu_ic->irq_enable = ASPEED_AST2600_SCU_IC1_ENABLE; 219 - scu_ic->irq_shift = ASPEED_AST2600_SCU_IC1_SHIFT; 220 - scu_ic->num_irqs = ASPEED_AST2600_SCU_IC1_NUM_IRQS; 221 - scu_ic->reg = ASPEED_AST2600_SCU_IC1_REG; 208 + scu_ic->irq_enable = variant->irq_enable; 209 + scu_ic->irq_shift = variant->irq_shift; 210 + scu_ic->num_irqs = variant->num_irqs; 222 211 223 212 return aspeed_scu_ic_of_init_common(scu_ic, node); 224 213 } 225 214 226 215 IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init); 227 216 IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init); 228 - IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", 229 - aspeed_ast2600_scu_ic0_of_init); 230 - IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1", 231 - aspeed_ast2600_scu_ic1_of_init); 217 + IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", aspeed_scu_ic_of_init); 218 + IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1", aspeed_scu_ic_of_init);