1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for the Microchip LAN966x outbound interrupt controller 4 * 5 * Copyright (c) 2024 Technology Inc. and its subsidiaries. 6 * 7 * Authors: 8 * Horatiu Vultur <horatiu.vultur@microchip.com> 9 * Clément Léger <clement.leger@bootlin.com> 10 * Herve Codina <herve.codina@bootlin.com> 11 */ 12 13 #include <linux/interrupt.h> 14 #include <linux/irqchip/chained_irq.h> 15 #include <linux/irqchip.h> 16 #include <linux/irq.h> 17 #include <linux/mod_devicetable.h> 18 #include <linux/module.h> 19 #include <linux/platform_device.h> 20 #include <linux/slab.h> 21 22 struct lan966x_oic_chip_regs { 23 int reg_off_ena_set; 24 int reg_off_ena_clr; 25 int reg_off_sticky; 26 int reg_off_ident; 27 int reg_off_map; 28 }; 29 30 struct lan966x_oic_data { 31 void __iomem *regs; 32 int irq; 33 }; 34 35 #define LAN966X_OIC_NR_IRQ 86 36 37 /* Interrupt sticky status */ 38 #define LAN966X_OIC_INTR_STICKY 0x30 39 #define LAN966X_OIC_INTR_STICKY1 0x34 40 #define LAN966X_OIC_INTR_STICKY2 0x38 41 42 /* Interrupt enable */ 43 #define LAN966X_OIC_INTR_ENA 0x48 44 #define LAN966X_OIC_INTR_ENA1 0x4c 45 #define LAN966X_OIC_INTR_ENA2 0x50 46 47 /* Atomic clear of interrupt enable */ 48 #define LAN966X_OIC_INTR_ENA_CLR 0x54 49 #define LAN966X_OIC_INTR_ENA_CLR1 0x58 50 #define LAN966X_OIC_INTR_ENA_CLR2 0x5c 51 52 /* Atomic set of interrupt */ 53 #define LAN966X_OIC_INTR_ENA_SET 0x60 54 #define LAN966X_OIC_INTR_ENA_SET1 0x64 55 #define LAN966X_OIC_INTR_ENA_SET2 0x68 56 57 /* Mapping of source to destination interrupts (_n = 0..8) */ 58 #define LAN966X_OIC_DST_INTR_MAP(_n) (0x78 + (_n) * 4) 59 #define LAN966X_OIC_DST_INTR_MAP1(_n) (0x9c + (_n) * 4) 60 #define LAN966X_OIC_DST_INTR_MAP2(_n) (0xc0 + (_n) * 4) 61 62 /* Currently active interrupt sources per destination (_n = 0..8) */ 63 #define LAN966X_OIC_DST_INTR_IDENT(_n) (0xe4 + (_n) * 4) 64 #define LAN966X_OIC_DST_INTR_IDENT1(_n) (0x108 + (_n) * 4) 65 #define LAN966X_OIC_DST_INTR_IDENT2(_n) (0x12c + (_n) * 4) 66 67 static unsigned int lan966x_oic_irq_startup(struct irq_data *data) 68 { 69 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 70 struct irq_chip_type *ct = irq_data_get_chip_type(data); 71 struct lan966x_oic_chip_regs *chip_regs = gc->private; 72 u32 map; 73 74 scoped_guard (raw_spinlock, &gc->lock) { 75 /* Map the source interrupt to the destination */ 76 map = irq_reg_readl(gc, chip_regs->reg_off_map); 77 map |= data->mask; 78 irq_reg_writel(gc, map, chip_regs->reg_off_map); 79 } 80 81 ct->chip.irq_ack(data); 82 ct->chip.irq_unmask(data); 83 84 return 0; 85 } 86 87 static void lan966x_oic_irq_shutdown(struct irq_data *data) 88 { 89 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 90 struct irq_chip_type *ct = irq_data_get_chip_type(data); 91 struct lan966x_oic_chip_regs *chip_regs = gc->private; 92 u32 map; 93 94 ct->chip.irq_mask(data); 95 96 guard(raw_spinlock)(&gc->lock); 97 98 /* Unmap the interrupt */ 99 map = irq_reg_readl(gc, chip_regs->reg_off_map); 100 map &= ~data->mask; 101 irq_reg_writel(gc, map, chip_regs->reg_off_map); 102 } 103 104 static int lan966x_oic_irq_set_type(struct irq_data *data, 105 unsigned int flow_type) 106 { 107 if (flow_type != IRQ_TYPE_LEVEL_HIGH) { 108 pr_err("lan966x oic doesn't support flow type %d\n", flow_type); 109 return -EINVAL; 110 } 111 112 return 0; 113 } 114 115 static void lan966x_oic_irq_handler_domain(struct irq_domain *d, u32 first_irq) 116 { 117 struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, first_irq); 118 struct lan966x_oic_chip_regs *chip_regs = gc->private; 119 unsigned long ident; 120 unsigned int hwirq; 121 122 ident = irq_reg_readl(gc, chip_regs->reg_off_ident); 123 if (!ident) 124 return; 125 126 for_each_set_bit(hwirq, &ident, 32) 127 generic_handle_domain_irq(d, hwirq + first_irq); 128 } 129 130 static void lan966x_oic_irq_handler(struct irq_desc *desc) 131 { 132 struct irq_domain *d = irq_desc_get_handler_data(desc); 133 struct irq_chip *chip = irq_desc_get_chip(desc); 134 135 chained_irq_enter(chip, desc); 136 lan966x_oic_irq_handler_domain(d, 0); 137 lan966x_oic_irq_handler_domain(d, 32); 138 lan966x_oic_irq_handler_domain(d, 64); 139 chained_irq_exit(chip, desc); 140 } 141 142 static struct lan966x_oic_chip_regs lan966x_oic_chip_regs[3] = { 143 { 144 .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET, 145 .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR, 146 .reg_off_sticky = LAN966X_OIC_INTR_STICKY, 147 .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT(0), 148 .reg_off_map = LAN966X_OIC_DST_INTR_MAP(0), 149 }, { 150 .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET1, 151 .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR1, 152 .reg_off_sticky = LAN966X_OIC_INTR_STICKY1, 153 .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT1(0), 154 .reg_off_map = LAN966X_OIC_DST_INTR_MAP1(0), 155 }, { 156 .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET2, 157 .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR2, 158 .reg_off_sticky = LAN966X_OIC_INTR_STICKY2, 159 .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT2(0), 160 .reg_off_map = LAN966X_OIC_DST_INTR_MAP2(0), 161 } 162 }; 163 164 static int lan966x_oic_chip_init(struct irq_chip_generic *gc) 165 { 166 struct lan966x_oic_data *lan966x_oic = gc->domain->host_data; 167 struct lan966x_oic_chip_regs *chip_regs; 168 169 chip_regs = &lan966x_oic_chip_regs[gc->irq_base / 32]; 170 171 gc->reg_base = lan966x_oic->regs; 172 gc->chip_types[0].regs.enable = chip_regs->reg_off_ena_set; 173 gc->chip_types[0].regs.disable = chip_regs->reg_off_ena_clr; 174 gc->chip_types[0].regs.ack = chip_regs->reg_off_sticky; 175 gc->chip_types[0].chip.irq_startup = lan966x_oic_irq_startup; 176 gc->chip_types[0].chip.irq_shutdown = lan966x_oic_irq_shutdown; 177 gc->chip_types[0].chip.irq_set_type = lan966x_oic_irq_set_type; 178 gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; 179 gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; 180 gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; 181 gc->private = chip_regs; 182 183 /* Disable all interrupts handled by this chip */ 184 irq_reg_writel(gc, ~0U, chip_regs->reg_off_ena_clr); 185 186 return 0; 187 } 188 189 static void lan966x_oic_chip_exit(struct irq_chip_generic *gc) 190 { 191 /* Disable and ack all interrupts handled by this chip */ 192 irq_reg_writel(gc, ~0U, gc->chip_types[0].regs.disable); 193 irq_reg_writel(gc, ~0U, gc->chip_types[0].regs.ack); 194 } 195 196 static int lan966x_oic_domain_init(struct irq_domain *d) 197 { 198 struct lan966x_oic_data *lan966x_oic = d->host_data; 199 200 irq_set_chained_handler_and_data(lan966x_oic->irq, lan966x_oic_irq_handler, d); 201 202 return 0; 203 } 204 205 static void lan966x_oic_domain_exit(struct irq_domain *d) 206 { 207 struct lan966x_oic_data *lan966x_oic = d->host_data; 208 209 irq_set_chained_handler_and_data(lan966x_oic->irq, NULL, NULL); 210 } 211 212 static int lan966x_oic_probe(struct platform_device *pdev) 213 { 214 struct irq_domain_chip_generic_info dgc_info = { 215 .name = "lan966x-oic", 216 .handler = handle_level_irq, 217 .irqs_per_chip = 32, 218 .num_ct = 1, 219 .init = lan966x_oic_chip_init, 220 .exit = lan966x_oic_chip_exit, 221 }; 222 struct irq_domain_info d_info = { 223 .fwnode = of_fwnode_handle(pdev->dev.of_node), 224 .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC, 225 .size = LAN966X_OIC_NR_IRQ, 226 .hwirq_max = LAN966X_OIC_NR_IRQ, 227 .ops = &irq_generic_chip_ops, 228 .dgc_info = &dgc_info, 229 .init = lan966x_oic_domain_init, 230 .exit = lan966x_oic_domain_exit, 231 }; 232 struct lan966x_oic_data *lan966x_oic; 233 struct device *dev = &pdev->dev; 234 struct irq_domain *domain; 235 236 lan966x_oic = devm_kmalloc(dev, sizeof(*lan966x_oic), GFP_KERNEL); 237 if (!lan966x_oic) 238 return -ENOMEM; 239 240 lan966x_oic->regs = devm_platform_ioremap_resource(pdev, 0); 241 if (IS_ERR(lan966x_oic->regs)) 242 return dev_err_probe(dev, PTR_ERR(lan966x_oic->regs), 243 "failed to map resource\n"); 244 245 lan966x_oic->irq = platform_get_irq(pdev, 0); 246 if (lan966x_oic->irq < 0) 247 return dev_err_probe(dev, lan966x_oic->irq, "failed to get the IRQ\n"); 248 249 d_info.host_data = lan966x_oic; 250 domain = devm_irq_domain_instantiate(dev, &d_info); 251 if (IS_ERR(domain)) 252 return dev_err_probe(dev, PTR_ERR(domain), 253 "failed to instantiate the IRQ domain\n"); 254 return 0; 255 } 256 257 static const struct of_device_id lan966x_oic_of_match[] = { 258 { .compatible = "microchip,lan966x-oic" }, 259 {} /* sentinel */ 260 }; 261 MODULE_DEVICE_TABLE(of, lan966x_oic_of_match); 262 263 static struct platform_driver lan966x_oic_driver = { 264 .probe = lan966x_oic_probe, 265 .driver = { 266 .name = "lan966x-oic", 267 .of_match_table = lan966x_oic_of_match, 268 }, 269 }; 270 module_platform_driver(lan966x_oic_driver); 271 272 MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); 273 MODULE_DESCRIPTION("Microchip LAN966x OIC driver"); 274 MODULE_LICENSE("GPL"); 275