1dbb15226SJiaxun Yang // SPDX-License-Identifier: GPL-2.0 2dbb15226SJiaxun Yang /* 3dbb15226SJiaxun Yang * Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com> 4dbb15226SJiaxun Yang * Loongson Local IO Interrupt Controller support 5dbb15226SJiaxun Yang */ 6dbb15226SJiaxun Yang 7dbb15226SJiaxun Yang #include <linux/errno.h> 8dbb15226SJiaxun Yang #include <linux/init.h> 9dbb15226SJiaxun Yang #include <linux/types.h> 10dbb15226SJiaxun Yang #include <linux/interrupt.h> 11dbb15226SJiaxun Yang #include <linux/ioport.h> 12dbb15226SJiaxun Yang #include <linux/irqchip.h> 13dbb15226SJiaxun Yang #include <linux/of_address.h> 14dbb15226SJiaxun Yang #include <linux/of_irq.h> 15dbb15226SJiaxun Yang #include <linux/io.h> 16dbb15226SJiaxun Yang #include <linux/smp.h> 17dbb15226SJiaxun Yang #include <linux/irqchip/chained_irq.h> 18dbb15226SJiaxun Yang 19fa84f893SHuacai Chen #ifdef CONFIG_MIPS 2076e0c88dSQing Zhang #include <loongson.h> 21fa84f893SHuacai Chen #else 22fa84f893SHuacai Chen #include <asm/loongson.h> 23fa84f893SHuacai Chen #endif 24dbb15226SJiaxun Yang 25dbb15226SJiaxun Yang #define LIOINTC_CHIP_IRQ 32 26dbb15226SJiaxun Yang #define LIOINTC_NUM_PARENT 4 27b2c4c396SQing Zhang #define LIOINTC_NUM_CORES 4 28dbb15226SJiaxun Yang 29dbb15226SJiaxun Yang #define LIOINTC_INTC_CHIP_START 0x20 30dbb15226SJiaxun Yang 31dbb15226SJiaxun Yang #define LIOINTC_REG_INTC_STATUS (LIOINTC_INTC_CHIP_START + 0x20) 32dbb15226SJiaxun Yang #define LIOINTC_REG_INTC_EN_STATUS (LIOINTC_INTC_CHIP_START + 0x04) 33dbb15226SJiaxun Yang #define LIOINTC_REG_INTC_ENABLE (LIOINTC_INTC_CHIP_START + 0x08) 34dbb15226SJiaxun Yang #define LIOINTC_REG_INTC_DISABLE (LIOINTC_INTC_CHIP_START + 0x0c) 35dbb15226SJiaxun Yang #define LIOINTC_REG_INTC_POL (LIOINTC_INTC_CHIP_START + 0x10) 36dbb15226SJiaxun Yang #define LIOINTC_REG_INTC_EDGE (LIOINTC_INTC_CHIP_START + 0x14) 37dbb15226SJiaxun Yang 38dbb15226SJiaxun Yang #define LIOINTC_SHIFT_INTx 4 39dbb15226SJiaxun Yang 40be09ef09SJiaxun Yang #define LIOINTC_ERRATA_IRQ 10 41be09ef09SJiaxun Yang 426fac824fSJiaxun Yang #if defined(CONFIG_MIPS) 436fac824fSJiaxun Yang #define liointc_core_id get_ebase_cpunum() 446fac824fSJiaxun Yang #else 456fac824fSJiaxun Yang #define liointc_core_id get_csr_cpuid() 466fac824fSJiaxun Yang #endif 476fac824fSJiaxun Yang 48dbb15226SJiaxun Yang struct liointc_handler_data { 49dbb15226SJiaxun Yang struct liointc_priv *priv; 50dbb15226SJiaxun Yang u32 parent_int_map; 51dbb15226SJiaxun Yang }; 52dbb15226SJiaxun Yang 53dbb15226SJiaxun Yang struct liointc_priv { 54dbb15226SJiaxun Yang struct irq_chip_generic *gc; 55dbb15226SJiaxun Yang struct liointc_handler_data handler[LIOINTC_NUM_PARENT]; 56b2c4c396SQing Zhang void __iomem *core_isr[LIOINTC_NUM_CORES]; 57dbb15226SJiaxun Yang u8 map_cache[LIOINTC_CHIP_IRQ]; 58be09ef09SJiaxun Yang bool has_lpc_irq_errata; 59dbb15226SJiaxun Yang }; 60dbb15226SJiaxun Yang 61*0858ed03SHuacai Chen struct fwnode_handle *liointc_handle; 62*0858ed03SHuacai Chen 63dbb15226SJiaxun Yang static void liointc_chained_handle_irq(struct irq_desc *desc) 64dbb15226SJiaxun Yang { 65dbb15226SJiaxun Yang struct liointc_handler_data *handler = irq_desc_get_handler_data(desc); 66dbb15226SJiaxun Yang struct irq_chip *chip = irq_desc_get_chip(desc); 67dbb15226SJiaxun Yang struct irq_chip_generic *gc = handler->priv->gc; 686fac824fSJiaxun Yang int core = liointc_core_id % LIOINTC_NUM_CORES; 69dbb15226SJiaxun Yang u32 pending; 70dbb15226SJiaxun Yang 71dbb15226SJiaxun Yang chained_irq_enter(chip, desc); 72dbb15226SJiaxun Yang 73b2c4c396SQing Zhang pending = readl(handler->priv->core_isr[core]); 74dbb15226SJiaxun Yang 75be09ef09SJiaxun Yang if (!pending) { 76be09ef09SJiaxun Yang /* Always blame LPC IRQ if we have that bug */ 77be09ef09SJiaxun Yang if (handler->priv->has_lpc_irq_errata && 78c9c73a05SHuacai Chen (handler->parent_int_map & gc->mask_cache & 79be09ef09SJiaxun Yang BIT(LIOINTC_ERRATA_IRQ))) 80be09ef09SJiaxun Yang pending = BIT(LIOINTC_ERRATA_IRQ); 81be09ef09SJiaxun Yang else 82dbb15226SJiaxun Yang spurious_interrupt(); 83be09ef09SJiaxun Yang } 84dbb15226SJiaxun Yang 85dbb15226SJiaxun Yang while (pending) { 86dbb15226SJiaxun Yang int bit = __ffs(pending); 87dbb15226SJiaxun Yang 88046a6ee2SMarc Zyngier generic_handle_domain_irq(gc->domain, bit); 89dbb15226SJiaxun Yang pending &= ~BIT(bit); 90dbb15226SJiaxun Yang } 91dbb15226SJiaxun Yang 92dbb15226SJiaxun Yang chained_irq_exit(chip, desc); 93dbb15226SJiaxun Yang } 94dbb15226SJiaxun Yang 95dbb15226SJiaxun Yang static void liointc_set_bit(struct irq_chip_generic *gc, 96dbb15226SJiaxun Yang unsigned int offset, 97dbb15226SJiaxun Yang u32 mask, bool set) 98dbb15226SJiaxun Yang { 99dbb15226SJiaxun Yang if (set) 100dbb15226SJiaxun Yang writel(readl(gc->reg_base + offset) | mask, 101dbb15226SJiaxun Yang gc->reg_base + offset); 102dbb15226SJiaxun Yang else 103dbb15226SJiaxun Yang writel(readl(gc->reg_base + offset) & ~mask, 104dbb15226SJiaxun Yang gc->reg_base + offset); 105dbb15226SJiaxun Yang } 106dbb15226SJiaxun Yang 107dbb15226SJiaxun Yang static int liointc_set_type(struct irq_data *data, unsigned int type) 108dbb15226SJiaxun Yang { 109dbb15226SJiaxun Yang struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 110dbb15226SJiaxun Yang u32 mask = data->mask; 111dbb15226SJiaxun Yang unsigned long flags; 112dbb15226SJiaxun Yang 113dbb15226SJiaxun Yang irq_gc_lock_irqsave(gc, flags); 114dbb15226SJiaxun Yang switch (type) { 115dbb15226SJiaxun Yang case IRQ_TYPE_LEVEL_HIGH: 116dbb15226SJiaxun Yang liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false); 117dbb15226SJiaxun Yang liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true); 118dbb15226SJiaxun Yang break; 119dbb15226SJiaxun Yang case IRQ_TYPE_LEVEL_LOW: 120dbb15226SJiaxun Yang liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, false); 121dbb15226SJiaxun Yang liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false); 122dbb15226SJiaxun Yang break; 123dbb15226SJiaxun Yang case IRQ_TYPE_EDGE_RISING: 124dbb15226SJiaxun Yang liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true); 125dbb15226SJiaxun Yang liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, true); 126dbb15226SJiaxun Yang break; 127dbb15226SJiaxun Yang case IRQ_TYPE_EDGE_FALLING: 128dbb15226SJiaxun Yang liointc_set_bit(gc, LIOINTC_REG_INTC_EDGE, mask, true); 129dbb15226SJiaxun Yang liointc_set_bit(gc, LIOINTC_REG_INTC_POL, mask, false); 130dbb15226SJiaxun Yang break; 131dbb15226SJiaxun Yang default: 132fa03587cSTiezhu Yang irq_gc_unlock_irqrestore(gc, flags); 133dbb15226SJiaxun Yang return -EINVAL; 134dbb15226SJiaxun Yang } 135dbb15226SJiaxun Yang irq_gc_unlock_irqrestore(gc, flags); 136dbb15226SJiaxun Yang 137dbb15226SJiaxun Yang irqd_set_trigger_type(data, type); 138dbb15226SJiaxun Yang return 0; 139dbb15226SJiaxun Yang } 140dbb15226SJiaxun Yang 141dbb15226SJiaxun Yang static void liointc_resume(struct irq_chip_generic *gc) 142dbb15226SJiaxun Yang { 143dbb15226SJiaxun Yang struct liointc_priv *priv = gc->private; 144dbb15226SJiaxun Yang unsigned long flags; 145dbb15226SJiaxun Yang int i; 146dbb15226SJiaxun Yang 147dbb15226SJiaxun Yang irq_gc_lock_irqsave(gc, flags); 148dbb15226SJiaxun Yang /* Disable all at first */ 149dbb15226SJiaxun Yang writel(0xffffffff, gc->reg_base + LIOINTC_REG_INTC_DISABLE); 150c9c73a05SHuacai Chen /* Restore map cache */ 151dbb15226SJiaxun Yang for (i = 0; i < LIOINTC_CHIP_IRQ; i++) 152dbb15226SJiaxun Yang writeb(priv->map_cache[i], gc->reg_base + i); 153c9c73a05SHuacai Chen /* Restore mask cache */ 154c9c73a05SHuacai Chen writel(gc->mask_cache, gc->reg_base + LIOINTC_REG_INTC_ENABLE); 155dbb15226SJiaxun Yang irq_gc_unlock_irqrestore(gc, flags); 156dbb15226SJiaxun Yang } 157dbb15226SJiaxun Yang 158*0858ed03SHuacai Chen static int parent_irq[LIOINTC_NUM_PARENT]; 159*0858ed03SHuacai Chen static u32 parent_int_map[LIOINTC_NUM_PARENT]; 160dbb15226SJiaxun Yang static const char *const parent_names[] = {"int0", "int1", "int2", "int3"}; 161b2c4c396SQing Zhang static const char *const core_reg_names[] = {"isr0", "isr1", "isr2", "isr3"}; 162b2c4c396SQing Zhang 163*0858ed03SHuacai Chen static int liointc_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, 164*0858ed03SHuacai Chen const u32 *intspec, unsigned int intsize, 165*0858ed03SHuacai Chen unsigned long *out_hwirq, unsigned int *out_type) 166b2c4c396SQing Zhang { 167*0858ed03SHuacai Chen if (WARN_ON(intsize < 1)) 168*0858ed03SHuacai Chen return -EINVAL; 169*0858ed03SHuacai Chen *out_hwirq = intspec[0] - GSI_MIN_CPU_IRQ; 170*0858ed03SHuacai Chen *out_type = IRQ_TYPE_NONE; 171*0858ed03SHuacai Chen return 0; 172b2c4c396SQing Zhang } 173dbb15226SJiaxun Yang 174*0858ed03SHuacai Chen static const struct irq_domain_ops acpi_irq_gc_ops = { 175*0858ed03SHuacai Chen .map = irq_map_generic_chip, 176*0858ed03SHuacai Chen .unmap = irq_unmap_generic_chip, 177*0858ed03SHuacai Chen .xlate = liointc_domain_xlate, 178*0858ed03SHuacai Chen }; 179*0858ed03SHuacai Chen 180*0858ed03SHuacai Chen static int liointc_init(phys_addr_t addr, unsigned long size, int revision, 181*0858ed03SHuacai Chen struct fwnode_handle *domain_handle, struct device_node *node) 182dbb15226SJiaxun Yang { 183*0858ed03SHuacai Chen int i, err; 184*0858ed03SHuacai Chen void __iomem *base; 185*0858ed03SHuacai Chen struct irq_chip_type *ct; 186dbb15226SJiaxun Yang struct irq_chip_generic *gc; 187dbb15226SJiaxun Yang struct irq_domain *domain; 188dbb15226SJiaxun Yang struct liointc_priv *priv; 189dbb15226SJiaxun Yang 190dbb15226SJiaxun Yang priv = kzalloc(sizeof(*priv), GFP_KERNEL); 191dbb15226SJiaxun Yang if (!priv) 192dbb15226SJiaxun Yang return -ENOMEM; 193dbb15226SJiaxun Yang 194*0858ed03SHuacai Chen base = ioremap(addr, size); 195*0858ed03SHuacai Chen if (!base) 196b2c4c396SQing Zhang goto out_free_priv; 197dbb15226SJiaxun Yang 198b2c4c396SQing Zhang for (i = 0; i < LIOINTC_NUM_CORES; i++) 199b2c4c396SQing Zhang priv->core_isr[i] = base + LIOINTC_REG_INTC_STATUS; 200dbb15226SJiaxun Yang 201dbb15226SJiaxun Yang for (i = 0; i < LIOINTC_NUM_PARENT; i++) 202*0858ed03SHuacai Chen priv->handler[i].parent_int_map = parent_int_map[i]; 203*0858ed03SHuacai Chen 204*0858ed03SHuacai Chen if (revision > 1) { 205*0858ed03SHuacai Chen for (i = 0; i < LIOINTC_NUM_CORES; i++) { 206*0858ed03SHuacai Chen int index = of_property_match_string(node, 207*0858ed03SHuacai Chen "reg-names", core_reg_names[i]); 208*0858ed03SHuacai Chen 209*0858ed03SHuacai Chen if (index < 0) 210*0858ed03SHuacai Chen return -EINVAL; 211*0858ed03SHuacai Chen 212*0858ed03SHuacai Chen priv->core_isr[i] = of_iomap(node, index); 213*0858ed03SHuacai Chen } 214*0858ed03SHuacai Chen } 215dbb15226SJiaxun Yang 216dbb15226SJiaxun Yang /* Setup IRQ domain */ 217*0858ed03SHuacai Chen if (!acpi_disabled) 218*0858ed03SHuacai Chen domain = irq_domain_create_linear(domain_handle, LIOINTC_CHIP_IRQ, 219*0858ed03SHuacai Chen &acpi_irq_gc_ops, priv); 220*0858ed03SHuacai Chen else 221*0858ed03SHuacai Chen domain = irq_domain_create_linear(domain_handle, LIOINTC_CHIP_IRQ, 222dbb15226SJiaxun Yang &irq_generic_chip_ops, priv); 223dbb15226SJiaxun Yang if (!domain) { 224dbb15226SJiaxun Yang pr_err("loongson-liointc: cannot add IRQ domain\n"); 225*0858ed03SHuacai Chen goto out_iounmap; 226dbb15226SJiaxun Yang } 227dbb15226SJiaxun Yang 228*0858ed03SHuacai Chen err = irq_alloc_domain_generic_chips(domain, LIOINTC_CHIP_IRQ, 1, 229*0858ed03SHuacai Chen (node ? node->full_name : "LIOINTC"), 230*0858ed03SHuacai Chen handle_level_irq, 0, IRQ_NOPROBE, 0); 231dbb15226SJiaxun Yang if (err) { 232dbb15226SJiaxun Yang pr_err("loongson-liointc: unable to register IRQ domain\n"); 233dbb15226SJiaxun Yang goto out_free_domain; 234dbb15226SJiaxun Yang } 235dbb15226SJiaxun Yang 236dbb15226SJiaxun Yang 237dbb15226SJiaxun Yang /* Disable all IRQs */ 238dbb15226SJiaxun Yang writel(0xffffffff, base + LIOINTC_REG_INTC_DISABLE); 239dbb15226SJiaxun Yang /* Set to level triggered */ 240dbb15226SJiaxun Yang writel(0x0, base + LIOINTC_REG_INTC_EDGE); 241dbb15226SJiaxun Yang 242dbb15226SJiaxun Yang /* Generate parent INT part of map cache */ 243dbb15226SJiaxun Yang for (i = 0; i < LIOINTC_NUM_PARENT; i++) { 244dbb15226SJiaxun Yang u32 pending = priv->handler[i].parent_int_map; 245dbb15226SJiaxun Yang 246dbb15226SJiaxun Yang while (pending) { 247dbb15226SJiaxun Yang int bit = __ffs(pending); 248dbb15226SJiaxun Yang 249dbb15226SJiaxun Yang priv->map_cache[bit] = BIT(i) << LIOINTC_SHIFT_INTx; 250dbb15226SJiaxun Yang pending &= ~BIT(bit); 251dbb15226SJiaxun Yang } 252dbb15226SJiaxun Yang } 253dbb15226SJiaxun Yang 254dbb15226SJiaxun Yang for (i = 0; i < LIOINTC_CHIP_IRQ; i++) { 255dbb15226SJiaxun Yang /* Generate core part of map cache */ 256dbb15226SJiaxun Yang priv->map_cache[i] |= BIT(loongson_sysconf.boot_cpu_id); 257dbb15226SJiaxun Yang writeb(priv->map_cache[i], base + i); 258dbb15226SJiaxun Yang } 259dbb15226SJiaxun Yang 260dbb15226SJiaxun Yang gc = irq_get_domain_generic_chip(domain, 0); 261dbb15226SJiaxun Yang gc->private = priv; 262dbb15226SJiaxun Yang gc->reg_base = base; 263dbb15226SJiaxun Yang gc->domain = domain; 264dbb15226SJiaxun Yang gc->resume = liointc_resume; 265dbb15226SJiaxun Yang 266dbb15226SJiaxun Yang ct = gc->chip_types; 267dbb15226SJiaxun Yang ct->regs.enable = LIOINTC_REG_INTC_ENABLE; 268dbb15226SJiaxun Yang ct->regs.disable = LIOINTC_REG_INTC_DISABLE; 269dbb15226SJiaxun Yang ct->chip.irq_unmask = irq_gc_unmask_enable_reg; 270dbb15226SJiaxun Yang ct->chip.irq_mask = irq_gc_mask_disable_reg; 271dbb15226SJiaxun Yang ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; 272dbb15226SJiaxun Yang ct->chip.irq_set_type = liointc_set_type; 273dbb15226SJiaxun Yang 274c9c73a05SHuacai Chen gc->mask_cache = 0; 275dbb15226SJiaxun Yang priv->gc = gc; 276dbb15226SJiaxun Yang 277dbb15226SJiaxun Yang for (i = 0; i < LIOINTC_NUM_PARENT; i++) { 278dbb15226SJiaxun Yang if (parent_irq[i] <= 0) 279dbb15226SJiaxun Yang continue; 280dbb15226SJiaxun Yang 281dbb15226SJiaxun Yang priv->handler[i].priv = priv; 282dbb15226SJiaxun Yang irq_set_chained_handler_and_data(parent_irq[i], 283dbb15226SJiaxun Yang liointc_chained_handle_irq, &priv->handler[i]); 284dbb15226SJiaxun Yang } 285dbb15226SJiaxun Yang 286*0858ed03SHuacai Chen liointc_handle = domain_handle; 287dbb15226SJiaxun Yang return 0; 288dbb15226SJiaxun Yang 289dbb15226SJiaxun Yang out_free_domain: 290dbb15226SJiaxun Yang irq_domain_remove(domain); 291*0858ed03SHuacai Chen out_iounmap: 292dbb15226SJiaxun Yang iounmap(base); 293dbb15226SJiaxun Yang out_free_priv: 294dbb15226SJiaxun Yang kfree(priv); 295dbb15226SJiaxun Yang 296*0858ed03SHuacai Chen return -EINVAL; 297*0858ed03SHuacai Chen } 298*0858ed03SHuacai Chen 299*0858ed03SHuacai Chen #ifdef CONFIG_OF 300*0858ed03SHuacai Chen 301*0858ed03SHuacai Chen static int __init liointc_of_init(struct device_node *node, 302*0858ed03SHuacai Chen struct device_node *parent) 303*0858ed03SHuacai Chen { 304*0858ed03SHuacai Chen bool have_parent = FALSE; 305*0858ed03SHuacai Chen int sz, i, index, revision, err = 0; 306*0858ed03SHuacai Chen struct resource res; 307*0858ed03SHuacai Chen 308*0858ed03SHuacai Chen if (!of_device_is_compatible(node, "loongson,liointc-2.0")) { 309*0858ed03SHuacai Chen index = 0; 310*0858ed03SHuacai Chen revision = 1; 311*0858ed03SHuacai Chen } else { 312*0858ed03SHuacai Chen index = of_property_match_string(node, "reg-names", "main"); 313*0858ed03SHuacai Chen revision = 2; 314*0858ed03SHuacai Chen } 315*0858ed03SHuacai Chen 316*0858ed03SHuacai Chen if (of_address_to_resource(node, index, &res)) 317*0858ed03SHuacai Chen return -EINVAL; 318*0858ed03SHuacai Chen 319*0858ed03SHuacai Chen for (i = 0; i < LIOINTC_NUM_PARENT; i++) { 320*0858ed03SHuacai Chen parent_irq[i] = of_irq_get_byname(node, parent_names[i]); 321*0858ed03SHuacai Chen if (parent_irq[i] > 0) 322*0858ed03SHuacai Chen have_parent = TRUE; 323*0858ed03SHuacai Chen } 324*0858ed03SHuacai Chen if (!have_parent) 325*0858ed03SHuacai Chen return -ENODEV; 326*0858ed03SHuacai Chen 327*0858ed03SHuacai Chen sz = of_property_read_variable_u32_array(node, 328*0858ed03SHuacai Chen "loongson,parent_int_map", 329*0858ed03SHuacai Chen &parent_int_map[0], 330*0858ed03SHuacai Chen LIOINTC_NUM_PARENT, 331*0858ed03SHuacai Chen LIOINTC_NUM_PARENT); 332*0858ed03SHuacai Chen if (sz < 4) { 333*0858ed03SHuacai Chen pr_err("loongson-liointc: No parent_int_map\n"); 334*0858ed03SHuacai Chen return -ENODEV; 335*0858ed03SHuacai Chen } 336*0858ed03SHuacai Chen 337*0858ed03SHuacai Chen err = liointc_init(res.start, resource_size(&res), 338*0858ed03SHuacai Chen revision, of_node_to_fwnode(node), node); 339*0858ed03SHuacai Chen if (err < 0) 340dbb15226SJiaxun Yang return err; 341*0858ed03SHuacai Chen 342*0858ed03SHuacai Chen return 0; 343dbb15226SJiaxun Yang } 344dbb15226SJiaxun Yang 345dbb15226SJiaxun Yang IRQCHIP_DECLARE(loongson_liointc_1_0, "loongson,liointc-1.0", liointc_of_init); 346dbb15226SJiaxun Yang IRQCHIP_DECLARE(loongson_liointc_1_0a, "loongson,liointc-1.0a", liointc_of_init); 347b2c4c396SQing Zhang IRQCHIP_DECLARE(loongson_liointc_2_0, "loongson,liointc-2.0", liointc_of_init); 348*0858ed03SHuacai Chen 349*0858ed03SHuacai Chen #endif 350*0858ed03SHuacai Chen 351*0858ed03SHuacai Chen #ifdef CONFIG_ACPI 352*0858ed03SHuacai Chen int __init liointc_acpi_init(struct irq_domain *parent, struct acpi_madt_lio_pic *acpi_liointc) 353*0858ed03SHuacai Chen { 354*0858ed03SHuacai Chen int ret; 355*0858ed03SHuacai Chen struct fwnode_handle *domain_handle; 356*0858ed03SHuacai Chen 357*0858ed03SHuacai Chen parent_int_map[0] = acpi_liointc->cascade_map[0]; 358*0858ed03SHuacai Chen parent_int_map[1] = acpi_liointc->cascade_map[1]; 359*0858ed03SHuacai Chen 360*0858ed03SHuacai Chen parent_irq[0] = irq_create_mapping(parent, acpi_liointc->cascade[0]); 361*0858ed03SHuacai Chen parent_irq[1] = irq_create_mapping(parent, acpi_liointc->cascade[1]); 362*0858ed03SHuacai Chen 363*0858ed03SHuacai Chen domain_handle = irq_domain_alloc_fwnode((phys_addr_t *)acpi_liointc); 364*0858ed03SHuacai Chen if (!domain_handle) { 365*0858ed03SHuacai Chen pr_err("Unable to allocate domain handle\n"); 366*0858ed03SHuacai Chen return -ENOMEM; 367*0858ed03SHuacai Chen } 368*0858ed03SHuacai Chen ret = liointc_init(acpi_liointc->address, acpi_liointc->size, 369*0858ed03SHuacai Chen 1, domain_handle, NULL); 370*0858ed03SHuacai Chen if (ret) 371*0858ed03SHuacai Chen irq_domain_free_fwnode(domain_handle); 372*0858ed03SHuacai Chen 373*0858ed03SHuacai Chen return ret; 374*0858ed03SHuacai Chen } 375*0858ed03SHuacai Chen #endif 376