Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");