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; 108 109 chained_irq_enter(chip, desc); 110 111 sts = readl(scu_ic->base + scu_ic->isr); 112 enabled = sts & scu_ic->irq_enable; 113 sts = readl(scu_ic->base + scu_ic->isr); 114 status = sts & enabled; 115 116 bit = scu_ic->irq_shift; 117 max = scu_ic->num_irqs + bit; 118 119 for_each_set_bit_from(bit, &status, max) { 120 generic_handle_domain_irq(scu_ic->irq_domain, bit - scu_ic->irq_shift); 121 /* Clear interrupt */ 122 writel(BIT(bit), scu_ic->base + scu_ic->isr); 123 } 124 125 chained_irq_exit(chip, desc); 126 } 127 128 static void aspeed_scu_ic_irq_mask_combined(struct irq_data *data) 129 { 130 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 131 unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); 132 unsigned int mask = bit | (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 133 134 /* 135 * Status bits are cleared by writing 1. In order to prevent the mask 136 * operation from clearing the status bits, they should be under the 137 * mask and written with 0. 138 */ 139 writel(readl(scu_ic->base) & ~mask, scu_ic->base); 140 } 141 142 static void aspeed_scu_ic_irq_unmask_combined(struct irq_data *data) 143 { 144 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 145 unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); 146 unsigned int mask = bit | (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 147 148 /* 149 * Status bits are cleared by writing 1. In order to prevent the unmask 150 * operation from clearing the status bits, they should be under the 151 * mask and written with 0. 152 */ 153 writel((readl(scu_ic->base) & ~mask) | bit, scu_ic->base); 154 } 155 156 static void aspeed_scu_ic_irq_mask_split(struct irq_data *data) 157 { 158 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 159 unsigned int mask = BIT(data->hwirq + scu_ic->irq_shift); 160 161 writel(readl(scu_ic->base) & ~mask, scu_ic->base + scu_ic->ier); 162 } 163 164 static void aspeed_scu_ic_irq_unmask_split(struct irq_data *data) 165 { 166 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 167 unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); 168 169 writel(readl(scu_ic->base) | bit, scu_ic->base + scu_ic->ier); 170 } 171 172 static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data, 173 const struct cpumask *dest, 174 bool force) 175 { 176 return -EINVAL; 177 } 178 179 static struct irq_chip aspeed_scu_ic_chip_combined = { 180 .name = "aspeed-scu-ic", 181 .irq_mask = aspeed_scu_ic_irq_mask_combined, 182 .irq_unmask = aspeed_scu_ic_irq_unmask_combined, 183 .irq_set_affinity = aspeed_scu_ic_irq_set_affinity, 184 }; 185 186 static struct irq_chip aspeed_scu_ic_chip_split = { 187 .name = "ast2700-scu-ic", 188 .irq_mask = aspeed_scu_ic_irq_mask_split, 189 .irq_unmask = aspeed_scu_ic_irq_unmask_split, 190 .irq_set_affinity = aspeed_scu_ic_irq_set_affinity, 191 }; 192 193 static int aspeed_scu_ic_map(struct irq_domain *domain, unsigned int irq, 194 irq_hw_number_t hwirq) 195 { 196 struct aspeed_scu_ic *scu_ic = domain->host_data; 197 198 if (scu_has_split_isr(scu_ic)) 199 irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip_split, handle_level_irq); 200 else 201 irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip_combined, handle_level_irq); 202 irq_set_chip_data(irq, domain->host_data); 203 204 return 0; 205 } 206 207 static const struct irq_domain_ops aspeed_scu_ic_domain_ops = { 208 .map = aspeed_scu_ic_map, 209 }; 210 211 static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic *scu_ic, 212 struct device_node *node) 213 { 214 int irq, rc = 0; 215 216 scu_ic->base = of_iomap(node, 0); 217 if (!scu_ic->base) { 218 rc = -ENOMEM; 219 goto err; 220 } 221 222 if (scu_has_split_isr(scu_ic)) { 223 writel(AST2700_SCU_IC_STATUS, scu_ic->base + scu_ic->isr); 224 writel(0, scu_ic->base + scu_ic->ier); 225 } else { 226 writel(ASPEED_SCU_IC_STATUS, scu_ic->base); 227 writel(0, scu_ic->base); 228 } 229 230 irq = irq_of_parse_and_map(node, 0); 231 if (!irq) { 232 rc = -EINVAL; 233 goto err; 234 } 235 236 scu_ic->irq_domain = irq_domain_create_linear(of_fwnode_handle(node), scu_ic->num_irqs, 237 &aspeed_scu_ic_domain_ops, scu_ic); 238 if (!scu_ic->irq_domain) { 239 rc = -ENOMEM; 240 goto err; 241 } 242 243 irq_set_chained_handler_and_data(irq, scu_has_split_isr(scu_ic) ? 244 aspeed_scu_ic_irq_handler_split : 245 aspeed_scu_ic_irq_handler_combined, 246 scu_ic); 247 248 return 0; 249 250 err: 251 kfree(scu_ic); 252 return rc; 253 } 254 255 static const struct aspeed_scu_ic_variant *aspeed_scu_ic_find_variant(struct device_node *np) 256 { 257 for (int i = 0; i < ARRAY_SIZE(scu_ic_variants); i++) { 258 if (of_device_is_compatible(np, scu_ic_variants[i].compatible)) 259 return &scu_ic_variants[i]; 260 } 261 return NULL; 262 } 263 264 static int __init aspeed_scu_ic_of_init(struct device_node *node, struct device_node *parent) 265 { 266 const struct aspeed_scu_ic_variant *variant; 267 struct aspeed_scu_ic *scu_ic; 268 269 variant = aspeed_scu_ic_find_variant(node); 270 if (!variant) 271 return -ENODEV; 272 273 scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); 274 if (!scu_ic) 275 return -ENOMEM; 276 277 scu_ic->irq_enable = variant->irq_enable; 278 scu_ic->irq_shift = variant->irq_shift; 279 scu_ic->num_irqs = variant->num_irqs; 280 scu_ic->ier = variant->ier; 281 scu_ic->isr = variant->isr; 282 283 return aspeed_scu_ic_of_init_common(scu_ic, node); 284 } 285 286 IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init); 287 IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init); 288 IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", aspeed_scu_ic_of_init); 289 IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1", aspeed_scu_ic_of_init); 290 IRQCHIP_DECLARE(ast2700_scu_ic0, "aspeed,ast2700-scu-ic0", aspeed_scu_ic_of_init); 291 IRQCHIP_DECLARE(ast2700_scu_ic1, "aspeed,ast2700-scu-ic1", aspeed_scu_ic_of_init); 292 IRQCHIP_DECLARE(ast2700_scu_ic2, "aspeed,ast2700-scu-ic2", aspeed_scu_ic_of_init); 293 IRQCHIP_DECLARE(ast2700_scu_ic3, "aspeed,ast2700-scu-ic3", aspeed_scu_ic_of_init); 294