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 irq_gc_lock(gc); 75 76 /* Map the source interrupt to the destination */ 77 map = irq_reg_readl(gc, chip_regs->reg_off_map); 78 map |= data->mask; 79 irq_reg_writel(gc, map, chip_regs->reg_off_map); 80 81 irq_gc_unlock(gc); 82 83 ct->chip.irq_ack(data); 84 ct->chip.irq_unmask(data); 85 86 return 0; 87 } 88 89 static void lan966x_oic_irq_shutdown(struct irq_data *data) 90 { 91 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 92 struct irq_chip_type *ct = irq_data_get_chip_type(data); 93 struct lan966x_oic_chip_regs *chip_regs = gc->private; 94 u32 map; 95 96 ct->chip.irq_mask(data); 97 98 irq_gc_lock(gc); 99 100 /* Unmap the interrupt */ 101 map = irq_reg_readl(gc, chip_regs->reg_off_map); 102 map &= ~data->mask; 103 irq_reg_writel(gc, map, chip_regs->reg_off_map); 104 105 irq_gc_unlock(gc); 106 } 107 108 static int lan966x_oic_irq_set_type(struct irq_data *data, 109 unsigned int flow_type) 110 { 111 if (flow_type != IRQ_TYPE_LEVEL_HIGH) { 112 pr_err("lan966x oic doesn't support flow type %d\n", flow_type); 113 return -EINVAL; 114 } 115 116 return 0; 117 } 118 119 static void lan966x_oic_irq_handler_domain(struct irq_domain *d, u32 first_irq) 120 { 121 struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, first_irq); 122 struct lan966x_oic_chip_regs *chip_regs = gc->private; 123 unsigned long ident; 124 unsigned int hwirq; 125 126 ident = irq_reg_readl(gc, chip_regs->reg_off_ident); 127 if (!ident) 128 return; 129 130 for_each_set_bit(hwirq, &ident, 32) 131 generic_handle_domain_irq(d, hwirq + first_irq); 132 } 133 134 static void lan966x_oic_irq_handler(struct irq_desc *desc) 135 { 136 struct irq_domain *d = irq_desc_get_handler_data(desc); 137 struct irq_chip *chip = irq_desc_get_chip(desc); 138 139 chained_irq_enter(chip, desc); 140 lan966x_oic_irq_handler_domain(d, 0); 141 lan966x_oic_irq_handler_domain(d, 32); 142 lan966x_oic_irq_handler_domain(d, 64); 143 chained_irq_exit(chip, desc); 144 } 145 146 static struct lan966x_oic_chip_regs lan966x_oic_chip_regs[3] = { 147 { 148 .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET, 149 .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR, 150 .reg_off_sticky = LAN966X_OIC_INTR_STICKY, 151 .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT(0), 152 .reg_off_map = LAN966X_OIC_DST_INTR_MAP(0), 153 }, { 154 .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET1, 155 .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR1, 156 .reg_off_sticky = LAN966X_OIC_INTR_STICKY1, 157 .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT1(0), 158 .reg_off_map = LAN966X_OIC_DST_INTR_MAP1(0), 159 }, { 160 .reg_off_ena_set = LAN966X_OIC_INTR_ENA_SET2, 161 .reg_off_ena_clr = LAN966X_OIC_INTR_ENA_CLR2, 162 .reg_off_sticky = LAN966X_OIC_INTR_STICKY2, 163 .reg_off_ident = LAN966X_OIC_DST_INTR_IDENT2(0), 164 .reg_off_map = LAN966X_OIC_DST_INTR_MAP2(0), 165 } 166 }; 167 168 static int lan966x_oic_chip_init(struct irq_chip_generic *gc) 169 { 170 struct lan966x_oic_data *lan966x_oic = gc->domain->host_data; 171 struct lan966x_oic_chip_regs *chip_regs; 172 173 chip_regs = &lan966x_oic_chip_regs[gc->irq_base / 32]; 174 175 gc->reg_base = lan966x_oic->regs; 176 gc->chip_types[0].regs.enable = chip_regs->reg_off_ena_set; 177 gc->chip_types[0].regs.disable = chip_regs->reg_off_ena_clr; 178 gc->chip_types[0].regs.ack = chip_regs->reg_off_sticky; 179 gc->chip_types[0].chip.irq_startup = lan966x_oic_irq_startup; 180 gc->chip_types[0].chip.irq_shutdown = lan966x_oic_irq_shutdown; 181 gc->chip_types[0].chip.irq_set_type = lan966x_oic_irq_set_type; 182 gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg; 183 gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg; 184 gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit; 185 gc->private = chip_regs; 186 187 /* Disable all interrupts handled by this chip */ 188 irq_reg_writel(gc, ~0U, chip_regs->reg_off_ena_clr); 189 190 return 0; 191 } 192 193 static void lan966x_oic_chip_exit(struct irq_chip_generic *gc) 194 { 195 /* Disable and ack all interrupts handled by this chip */ 196 irq_reg_writel(gc, ~0U, gc->chip_types[0].regs.disable); 197 irq_reg_writel(gc, ~0U, gc->chip_types[0].regs.ack); 198 } 199 200 static int lan966x_oic_domain_init(struct irq_domain *d) 201 { 202 struct lan966x_oic_data *lan966x_oic = d->host_data; 203 204 irq_set_chained_handler_and_data(lan966x_oic->irq, lan966x_oic_irq_handler, d); 205 206 return 0; 207 } 208 209 static void lan966x_oic_domain_exit(struct irq_domain *d) 210 { 211 struct lan966x_oic_data *lan966x_oic = d->host_data; 212 213 irq_set_chained_handler_and_data(lan966x_oic->irq, NULL, NULL); 214 } 215 216 static int lan966x_oic_probe(struct platform_device *pdev) 217 { 218 struct irq_domain_chip_generic_info dgc_info = { 219 .name = "lan966x-oic", 220 .handler = handle_level_irq, 221 .irqs_per_chip = 32, 222 .num_ct = 1, 223 .init = lan966x_oic_chip_init, 224 .exit = lan966x_oic_chip_exit, 225 }; 226 struct irq_domain_info d_info = { 227 .fwnode = of_node_to_fwnode(pdev->dev.of_node), 228 .domain_flags = IRQ_DOMAIN_FLAG_DESTROY_GC, 229 .size = LAN966X_OIC_NR_IRQ, 230 .hwirq_max = LAN966X_OIC_NR_IRQ, 231 .ops = &irq_generic_chip_ops, 232 .dgc_info = &dgc_info, 233 .init = lan966x_oic_domain_init, 234 .exit = lan966x_oic_domain_exit, 235 }; 236 struct lan966x_oic_data *lan966x_oic; 237 struct device *dev = &pdev->dev; 238 struct irq_domain *domain; 239 240 lan966x_oic = devm_kmalloc(dev, sizeof(*lan966x_oic), GFP_KERNEL); 241 if (!lan966x_oic) 242 return -ENOMEM; 243 244 lan966x_oic->regs = devm_platform_ioremap_resource(pdev, 0); 245 if (IS_ERR(lan966x_oic->regs)) 246 return dev_err_probe(dev, PTR_ERR(lan966x_oic->regs), 247 "failed to map resource\n"); 248 249 lan966x_oic->irq = platform_get_irq(pdev, 0); 250 if (lan966x_oic->irq < 0) 251 return dev_err_probe(dev, lan966x_oic->irq, "failed to get the IRQ\n"); 252 253 d_info.host_data = lan966x_oic; 254 domain = devm_irq_domain_instantiate(dev, &d_info); 255 if (IS_ERR(domain)) 256 return dev_err_probe(dev, PTR_ERR(domain), 257 "failed to instantiate the IRQ domain\n"); 258 return 0; 259 } 260 261 static const struct of_device_id lan966x_oic_of_match[] = { 262 { .compatible = "microchip,lan966x-oic" }, 263 {} /* sentinel */ 264 }; 265 MODULE_DEVICE_TABLE(of, lan966x_oic_of_match); 266 267 static struct platform_driver lan966x_oic_driver = { 268 .probe = lan966x_oic_probe, 269 .driver = { 270 .name = "lan966x-oic", 271 .of_match_table = lan966x_oic_of_match, 272 }, 273 }; 274 module_platform_driver(lan966x_oic_driver); 275 276 MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); 277 MODULE_DESCRIPTION("Microchip LAN966x OIC driver"); 278 MODULE_LICENSE("GPL"); 279