1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Aspeed AST24XX, AST25XX, and AST26XX 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 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 }; 27 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 }; 41 42 struct aspeed_scu_ic { 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; 48 }; 49 50 static void aspeed_scu_ic_irq_handler(struct irq_desc *desc) 51 { 52 struct aspeed_scu_ic *scu_ic = irq_desc_get_handler_data(desc); 53 struct irq_chip *chip = irq_desc_get_chip(desc); 54 unsigned long bit, enabled, max, status; 55 unsigned int sts, mask; 56 57 chained_irq_enter(chip, desc); 58 59 mask = scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT; 60 /* 61 * The SCU IC has just one register to control its operation and read 62 * status. The interrupt enable bits occupy the lower 16 bits of the 63 * register, while the interrupt status bits occupy the upper 16 bits. 64 * The status bit for a given interrupt is always 16 bits shifted from 65 * the enable bit for the same interrupt. 66 * Therefore, perform the IRQ operations in the enable bit space by 67 * shifting the status down to get the mapping and then back up to 68 * clear the bit. 69 */ 70 sts = readl(scu_ic->base); 71 enabled = sts & scu_ic->irq_enable; 72 status = (sts >> ASPEED_SCU_IC_STATUS_SHIFT) & enabled; 73 74 bit = scu_ic->irq_shift; 75 max = scu_ic->num_irqs + bit; 76 77 for_each_set_bit_from(bit, &status, max) { 78 generic_handle_domain_irq(scu_ic->irq_domain, bit - scu_ic->irq_shift); 79 writel((readl(scu_ic->base) & ~mask) | BIT(bit + ASPEED_SCU_IC_STATUS_SHIFT), 80 scu_ic->base); 81 } 82 83 chained_irq_exit(chip, desc); 84 } 85 86 static void aspeed_scu_ic_irq_mask(struct irq_data *data) 87 { 88 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 89 unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); 90 unsigned int mask = bit | (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 91 92 /* 93 * Status bits are cleared by writing 1. In order to prevent the mask 94 * operation from clearing the status bits, they should be under the 95 * mask and written with 0. 96 */ 97 writel(readl(scu_ic->base) & ~mask, scu_ic->base); 98 } 99 100 static void aspeed_scu_ic_irq_unmask(struct irq_data *data) 101 { 102 struct aspeed_scu_ic *scu_ic = irq_data_get_irq_chip_data(data); 103 unsigned int bit = BIT(data->hwirq + scu_ic->irq_shift); 104 unsigned int mask = bit | (scu_ic->irq_enable << ASPEED_SCU_IC_STATUS_SHIFT); 105 106 /* 107 * Status bits are cleared by writing 1. In order to prevent the unmask 108 * operation from clearing the status bits, they should be under the 109 * mask and written with 0. 110 */ 111 writel((readl(scu_ic->base) & ~mask) | bit, scu_ic->base); 112 } 113 114 static int aspeed_scu_ic_irq_set_affinity(struct irq_data *data, 115 const struct cpumask *dest, 116 bool force) 117 { 118 return -EINVAL; 119 } 120 121 static struct irq_chip aspeed_scu_ic_chip = { 122 .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, 126 }; 127 128 static int aspeed_scu_ic_map(struct irq_domain *domain, unsigned int irq, 129 irq_hw_number_t hwirq) 130 { 131 irq_set_chip_and_handler(irq, &aspeed_scu_ic_chip, handle_level_irq); 132 irq_set_chip_data(irq, domain->host_data); 133 134 return 0; 135 } 136 137 static const struct irq_domain_ops aspeed_scu_ic_domain_ops = { 138 .map = aspeed_scu_ic_map, 139 }; 140 141 static int aspeed_scu_ic_of_init_common(struct aspeed_scu_ic *scu_ic, 142 struct device_node *node) 143 { 144 int irq, rc = 0; 145 146 scu_ic->base = of_iomap(node, 0); 147 if (IS_ERR(scu_ic->base)) { 148 rc = PTR_ERR(scu_ic->base); 149 goto err; 150 } 151 writel(ASPEED_SCU_IC_STATUS, scu_ic->base); 152 writel(0, scu_ic->base); 153 154 irq = irq_of_parse_and_map(node, 0); 155 if (!irq) { 156 rc = -EINVAL; 157 goto err; 158 } 159 160 scu_ic->irq_domain = irq_domain_create_linear(of_fwnode_handle(node), scu_ic->num_irqs, 161 &aspeed_scu_ic_domain_ops, scu_ic); 162 if (!scu_ic->irq_domain) { 163 rc = -ENOMEM; 164 goto err; 165 } 166 167 irq_set_chained_handler_and_data(irq, aspeed_scu_ic_irq_handler, 168 scu_ic); 169 170 return 0; 171 172 err: 173 kfree(scu_ic); 174 return rc; 175 } 176 177 static const struct aspeed_scu_ic_variant *aspeed_scu_ic_find_variant(struct device_node *np) 178 { 179 for (int i = 0; i < ARRAY_SIZE(scu_ic_variants); i++) { 180 if (of_device_is_compatible(np, scu_ic_variants[i].compatible)) 181 return &scu_ic_variants[i]; 182 } 183 return NULL; 184 } 185 186 static int __init aspeed_scu_ic_of_init(struct device_node *node, struct device_node *parent) 187 { 188 const struct aspeed_scu_ic_variant *variant; 189 struct aspeed_scu_ic *scu_ic; 190 191 variant = aspeed_scu_ic_find_variant(node); 192 if (!variant) 193 return -ENODEV; 194 195 scu_ic = kzalloc(sizeof(*scu_ic), GFP_KERNEL); 196 if (!scu_ic) 197 return -ENOMEM; 198 199 scu_ic->irq_enable = variant->irq_enable; 200 scu_ic->irq_shift = variant->irq_shift; 201 scu_ic->num_irqs = variant->num_irqs; 202 203 return aspeed_scu_ic_of_init_common(scu_ic, node); 204 } 205 206 IRQCHIP_DECLARE(ast2400_scu_ic, "aspeed,ast2400-scu-ic", aspeed_scu_ic_of_init); 207 IRQCHIP_DECLARE(ast2500_scu_ic, "aspeed,ast2500-scu-ic", aspeed_scu_ic_of_init); 208 IRQCHIP_DECLARE(ast2600_scu_ic0, "aspeed,ast2600-scu-ic0", aspeed_scu_ic_of_init); 209 IRQCHIP_DECLARE(ast2600_scu_ic1, "aspeed,ast2600-scu-ic1", aspeed_scu_ic_of_init); 210