^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Texas Instruments' K3 Interrupt Router irqchip driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2018-2019 Texas Instruments Incorporated - https://www.ti.com/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Lokesh Vutla <lokeshvutla@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/irqchip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/irqdomain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/of_irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/soc/ti/ti_sci_protocol.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * struct ti_sci_intr_irq_domain - Structure representing a TISCI based
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * Interrupt Router IRQ domain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * @sci: Pointer to TISCI handle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * @out_irqs: TISCI resource pointer representing INTR irqs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * @dev: Struct device pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * @ti_sci_id: TI-SCI device identifier
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * @type: Specifies the trigger type supported by this Interrupt Router
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct ti_sci_intr_irq_domain {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) const struct ti_sci_handle *sci;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) struct ti_sci_resource *out_irqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) u32 ti_sci_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) u32 type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static struct irq_chip ti_sci_intr_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) .name = "INTR",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) .irq_eoi = irq_chip_eoi_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) .irq_mask = irq_chip_mask_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) .irq_unmask = irq_chip_unmask_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) .irq_set_type = irq_chip_set_type_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) .irq_retrigger = irq_chip_retrigger_hierarchy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) .irq_set_affinity = irq_chip_set_affinity_parent,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * ti_sci_intr_irq_domain_translate() - Retrieve hwirq and type from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * IRQ firmware specific handler.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * @domain: Pointer to IRQ domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * @fwspec: Pointer to IRQ specific firmware structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * @hwirq: IRQ number identified by hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * @type: IRQ type
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * Return 0 if all went ok else appropriate error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static int ti_sci_intr_irq_domain_translate(struct irq_domain *domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) struct irq_fwspec *fwspec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) unsigned long *hwirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned int *type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct ti_sci_intr_irq_domain *intr = domain->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (fwspec->param_count != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) *hwirq = fwspec->param[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *type = intr->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * ti_sci_intr_xlate_irq() - Translate hwirq to parent's hwirq.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * @intr: IRQ domain corresponding to Interrupt Router
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * @irq: Hardware irq corresponding to the above irq domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * Return parent irq number if translation is available else -ENOENT.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int ti_sci_intr_xlate_irq(struct ti_sci_intr_irq_domain *intr, u32 irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct device_node *np = dev_of_node(intr->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u32 base, pbase, size, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) const __be32 *range;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) range = of_get_property(np, "ti,interrupt-ranges", &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) if (!range)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) return irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) for (len /= sizeof(*range); len >= 3; len -= 3) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) base = be32_to_cpu(*range++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) pbase = be32_to_cpu(*range++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) size = be32_to_cpu(*range++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (base <= irq && irq < base + size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return irq - base + pbase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * ti_sci_intr_irq_domain_free() - Free the specified IRQs from the domain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * @domain: Domain to which the irqs belong
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * @virq: Linux virtual IRQ to be freed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * @nr_irqs: Number of continuous irqs to be freed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static void ti_sci_intr_irq_domain_free(struct irq_domain *domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) unsigned int virq, unsigned int nr_irqs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct ti_sci_intr_irq_domain *intr = domain->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct irq_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) int out_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) data = irq_domain_get_irq_data(domain, virq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) out_irq = (uintptr_t)data->chip_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) intr->sci->ops.rm_irq_ops.free_irq(intr->sci,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) intr->ti_sci_id, data->hwirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) intr->ti_sci_id, out_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) ti_sci_release_resource(intr->out_irqs, out_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) irq_domain_free_irqs_parent(domain, virq, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) irq_domain_reset_irq_data(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * ti_sci_intr_alloc_parent_irq() - Allocate parent IRQ
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) * @domain: Pointer to the interrupt router IRQ domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * @virq: Corresponding Linux virtual IRQ number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * @hwirq: Corresponding hwirq for the IRQ within this IRQ domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * Returns intr output irq if all went well else appropriate error pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) unsigned int virq, u32 hwirq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) struct ti_sci_intr_irq_domain *intr = domain->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct device_node *parent_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct irq_fwspec fwspec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int p_hwirq, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) u16 out_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) out_irq = ti_sci_get_free_resource(intr->out_irqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (out_irq == TI_SCI_RESOURCE_NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) p_hwirq = ti_sci_intr_xlate_irq(intr, out_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (p_hwirq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) goto err_irqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) parent_node = of_irq_find_parent(dev_of_node(intr->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) fwspec.fwnode = of_node_to_fwnode(parent_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (of_device_is_compatible(parent_node, "arm,gic-v3")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* Parent is GIC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) fwspec.param_count = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) fwspec.param[0] = 0; /* SPI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) fwspec.param[1] = p_hwirq - 32; /* SPI offset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) fwspec.param[2] = intr->type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /* Parent is Interrupt Router */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) fwspec.param_count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) fwspec.param[0] = p_hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) goto err_irqs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) err = intr->sci->ops.rm_irq_ops.set_irq(intr->sci,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) intr->ti_sci_id, hwirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) intr->ti_sci_id, out_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) goto err_msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return out_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) err_msg:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) irq_domain_free_irqs_parent(domain, virq, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) err_irqs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) ti_sci_release_resource(intr->out_irqs, out_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * ti_sci_intr_irq_domain_alloc() - Allocate Interrupt router IRQs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * @domain: Point to the interrupt router IRQ domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * @virq: Corresponding Linux virtual IRQ number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * @nr_irqs: Continuous irqs to be allocated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * @data: Pointer to firmware specifier
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) * Return 0 if all went well else appropriate error value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) unsigned int virq, unsigned int nr_irqs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct irq_fwspec *fwspec = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) unsigned long hwirq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) unsigned int flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) int err, out_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) out_irq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (out_irq < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return out_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) &ti_sci_intr_irq_chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) (void *)(uintptr_t)out_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) static const struct irq_domain_ops ti_sci_intr_irq_domain_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) .free = ti_sci_intr_irq_domain_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .alloc = ti_sci_intr_irq_domain_alloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .translate = ti_sci_intr_irq_domain_translate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) struct irq_domain *parent_domain, *domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) struct ti_sci_intr_irq_domain *intr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) struct device_node *parent_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) parent_node = of_irq_find_parent(dev_of_node(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (!parent_node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) dev_err(dev, "Failed to get IRQ parent node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) parent_domain = irq_find_host(parent_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (!parent_domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) dev_err(dev, "Failed to find IRQ parent domain\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) intr = devm_kzalloc(dev, sizeof(*intr), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (!intr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) intr->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) ret = of_property_read_u32(dev_of_node(dev), "ti,intr-trigger-type",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) &intr->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) dev_err(dev, "missing ti,intr-trigger-type property\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) intr->sci = devm_ti_sci_get_by_phandle(dev, "ti,sci");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (IS_ERR(intr->sci))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return dev_err_probe(dev, PTR_ERR(intr->sci),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) "ti,sci read fail\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) ret = of_property_read_u32(dev_of_node(dev), "ti,sci-dev-id",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) &intr->ti_sci_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) dev_err(dev, "missing 'ti,sci-dev-id' property\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) intr->out_irqs = devm_ti_sci_get_resource(intr->sci, dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) intr->ti_sci_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) TI_SCI_RESASG_SUBTYPE_IR_OUTPUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (IS_ERR(intr->out_irqs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) dev_err(dev, "Destination irq resource allocation failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return PTR_ERR(intr->out_irqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) domain = irq_domain_add_hierarchy(parent_domain, 0, 0, dev_of_node(dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) &ti_sci_intr_irq_domain_ops, intr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (!domain) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) dev_err(dev, "Failed to allocate IRQ domain\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) dev_info(dev, "Interrupt Router %d domain created\n", intr->ti_sci_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) static const struct of_device_id ti_sci_intr_irq_domain_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) { .compatible = "ti,sci-intr", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) { /* sentinel */ },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) MODULE_DEVICE_TABLE(of, ti_sci_intr_irq_domain_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static struct platform_driver ti_sci_intr_irq_domain_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) .probe = ti_sci_intr_irq_domain_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) .name = "ti-sci-intr",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .of_match_table = ti_sci_intr_irq_domain_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) module_platform_driver(ti_sci_intr_irq_domain_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) MODULE_AUTHOR("Lokesh Vutla <lokeshvutla@ticom>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) MODULE_DESCRIPTION("K3 Interrupt Router driver over TI SCI protocol");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) MODULE_LICENSE("GPL v2");