1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Aspeed AST24XX, AST25XX, AST26XX, and AST27XX SCU Interrupt Controller 4 * Copyright 2019 IBM Corporation 5 * 6 * Eddie James <eajames@linux.ibm.com> 7 */ 8 9 #include <linux/bitops.h> 10 #include <linux/io.h> 11 #include <linux/irq.h> 12 #include <linux/irqchip.h> 13 #include <linux/irqchip/chained_irq.h> 14 #include <linux/irqdomain.h> 15 #include <linux/of_address.h> 16 #include <linux/of_irq.h> 17 18 #define ASPEED_SCU_IC_STATUS GENMASK(28, 16) 19 #define ASPEED_SCU_IC_STATUS_SHIFT 16 20 #define AST2700_SCU_IC_STATUS GENMASK(15, 0) 21 22 struct aspeed_scu_ic_variant { 23 const char *compatible; 24 unsigned long irq_enable; 25 unsigned long irq_shift; 26 unsigned int num_irqs; 27 unsigned long ier; 28 unsigned long isr; 29 }; 30 31 #define SCU_VARIANT(_compat, _shift, _enable, _num, _ier, _isr) { \ 32 .compatible = _compat, \ 33 .irq_shift = _shift, \ 34 .irq_enable = _enable, \ 35 .num_irqs = _num, \ 36 .ier = _ier, \ 37 .isr = _isr, \ 38 } 39 40 static const struct aspeed_scu_ic_variant scu_ic_variants[] __initconst = { 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), 49 }; 50 51 struct aspeed_scu_ic { 52 unsigned long irq_enable; 53 unsigned long irq_shift; 54 unsigned int num_irqs; 55 void __iomem *base; 56 struct irq_domain *irq_domain; 57 unsigned long ier; 58 unsigned long isr; 59 }; 60 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) 67 { 68 struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc); 69 struct irq_chip *chip = irq_desc_get_chip(desc); 70 unsigned long bit, enabled, max, status; 71 unsigned int sts, mask; 72 73 chained_irq_enter(chip, desc); 74 75 mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT; 76 /* 77 * The SCU IC has just one register to control its operation and read 78 * status. The interrupt enable bits occupy the lower 16 bits of the 79 * register, while the interrupt status bits occupy the upper 16 bits. 80 * The status bit for a given interrupt is always 16 bits shifted from 81 * the enable bit for the same interrupt. 82 * Therefore, perform the IRQ operations in the enable bit space by 83 * shifting the status down to get the mapping and then back up to 84 * clear the bit. 85 */ 86 sts = readl(scu_ic->base); 87 enabled = sts & scu_ic->irq_enable; 88 status = (sts >> ASPEED_SCU_IC_STATUS_SHIFT) & enabled; 89 90 bit = scu_ic->irq_shift; 91 max = scu_ic->num_irqs + bit; 92 93 for_each_set_bit_from(bit, &status, max) { 94 generic_handle_domain_irq(scu_ic->irq_domain, bit - scu_ic->irq_shift); 95 writel((readl(scu_ic->base) & ~mask) | BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT), 96 scu_ic->base); 97 } 98 99 chained_irq_exit(chip, desc); 100 } 101 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) 130 { 131 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 132 unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); 133 unsigned int mask = bit | (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 134 135 /* 136 * Status bits are cleared by writing 1. In order to prevent the mask 137 * operation from clearing the status bits, they should be under the 138 * mask and written with 0. 139 */ 140 writel(readl(scu_ic->base) & ~mask, scu_ic->base); 141 } 142 143 static void aspeed_scu_ic_irq_unmask_combined(struct irq_data *data) 144 { 145 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 146 unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); 147 unsigned int mask = bit | (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 148 149 /* 150 * Status bits are cleared by writing 1. In order to prevent the unmask 151 * operation from clearing the status bits, they should be under the 152 * mask and written with 0. 153 */ 154 writel((readl(scu_ic->base) & ~mask) | bit, scu_ic->base); 155 } 156 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 173 static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data, 174 const struct cpumask *dest, 175 bool force) 176 { 177 return -EINVAL; 178 } 179 180 static struct irq_chip aspeed_scu_ic_chip_combined = { 181 .name = "aspeed-scu-ic", 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, 192 }; 193 194 static int aspeed_scu_ic_map(struct irq_domain *domain, unsigned int irq, 195 irq_hw_number_t hwirq) 196 { 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); 203 irq_set_chip_data(irq, domain->host_data); 204 205 return 0; 206 } 207 208 static const struct irq_domain_ops aspeed_scu_ic_domain_ops = { 209 .map = aspeed_scu_ic_map, 210 }; 211 212 static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic *scu_ic, 213 struct device_node *node) 214 { 215 int irq, rc = 0; 216 217 scu_ic->base = of_iomap(node, 0); 218 if (IS_ERR(scu_ic->base)) { 219 rc = PTR_ERR(scu_ic->base); 220 goto err; 221 } 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 } 230 231 irq = irq_of_parse_and_map(node, 0); 232 if (!irq) { 233 rc = -EINVAL; 234 goto err; 235 } 236 237 scu_ic->irq_domain = irq_domain_create_linear(of_fwnode_handle(node), scu_ic->num_irqs, 238 &aspeed_scu_ic_domain_ops, scu_ic); 239 if (!scu_ic->irq_domain) { 240 rc = -ENOMEM; 241 goto err; 242 } 243 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, 247 scu_ic); 248 249 return 0; 250 251 err: 252 kfree(scu_ic); 253 return rc; 254 } 255 256 static const struct aspeed_scu_ic_variant *aspeed_scu_ic_find_variant(struct device_node *np) 257 { 258 for (int i = 0; i < ARRAY_SIZE(scu_ic_variants); i++) { 259 if (of_device_is_compatible(np, scu_ic_variants[i].compatible)) 260 return &scu_ic_variants[i]; 261 } 262 return NULL; 263 } 264 265 static int __init aspeed_scu_ic_of_init(struct device_node *node, struct device_node *parent) 266 { 267 const struct aspeed_scu_ic_variant *variant; 268 struct aspeed_scu_ic *scu_ic; 269 270 variant = aspeed_scu_ic_find_variant(node); 271 if (!variant) 272 return -ENODEV; 273 274 scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); 275 if (!scu_ic) 276 return -ENOMEM; 277 278 scu_ic->irq_enable = variant->irq_enable; 279 scu_ic->irq_shift = variant->irq_shift; 280 scu_ic->num_irqs = variant->num_irqs; 281 scu_ic->ier = variant->ier; 282 scu_ic->isr = variant->isr; 283 284 return aspeed_scu_ic_of_init_common(scu_ic, node); 285 } 286 287 IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init); 288 IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init); 289 IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", aspeed_scu_ic_of_init); 290 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); 295