summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-08-30 11:56:54 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-08-30 11:56:54 -0700
commitd2283cdc18d3378587f9d05be4fd1818059a757a (patch)
tree435d7e2d7fbc49e722c257e94bd7f22ae58d99f5 /drivers
parent0063a82de937433ccfffe123e12b4503b9155c96 (diff)
parentceb2465c51195967f11f6507538579816ac67cb8 (diff)
Merge tag 'irq-urgent-2020-08-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq fixes from Thomas Gleixner: "A set of fixes for interrupt chip drivers: - Revert the platform driver conversion of interrupt chip drivers as it turned out to create more problems than it solves. - Fix a trivial typo in the new module helpers which made probing reliably fail. - Small fixes in the STM32 and MIPS Ingenic drivers - The TI firmware rework which had badly managed dependencies and had to wait post rc1" * tag 'irq-urgent-2020-08-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: irqchip/ingenic: Leave parent IRQ unmasked on suspend irqchip/stm32-exti: Avoid losing interrupts due to clearing pending bits by mistake irqchip: Revert modular support for drivers using IRQCHIP_PLATFORM_DRIVER helperse irqchip: Fix probing deferal when using IRQCHIP_PLATFORM_DRIVER helpers arm64: dts: k3-am65: Update the RM resource types arm64: dts: k3-am65: ti-sci-inta/intr: Update to latest bindings arm64: dts: k3-j721e: ti-sci-inta/intr: Update to latest bindings irqchip/ti-sci-inta: Add support for INTA directly connecting to GIC irqchip/ti-sci-inta: Do not store TISCI device id in platform device id field dt-bindings: irqchip: Convert ti, sci-inta bindings to yaml dt-bindings: irqchip: ti, sci-inta: Update docs to support different parent. irqchip/ti-sci-intr: Add support for INTR being a parent to INTR dt-bindings: irqchip: Convert ti, sci-intr bindings to yaml dt-bindings: irqchip: ti, sci-intr: Update bindings to drop the usage of gic as parent firmware: ti_sci: Add support for getting resource with subtype firmware: ti_sci: Drop unused structure ti_sci_rm_type_map firmware: ti_sci: Drop the device id to resource type translation
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firmware/ti_sci.c155
-rw-r--r--drivers/irqchip/Kconfig2
-rw-r--r--drivers/irqchip/irq-ingenic.c2
-rw-r--r--drivers/irqchip/irq-mtk-cirq.c4
-rw-r--r--drivers/irqchip/irq-mtk-sysirq.c4
-rw-r--r--drivers/irqchip/irq-stm32-exti.c14
-rw-r--r--drivers/irqchip/irq-ti-sci-inta.c95
-rw-r--r--drivers/irqchip/irq-ti-sci-intr.c152
-rw-r--r--drivers/irqchip/irqchip.c2
-rw-r--r--drivers/irqchip/qcom-pdc.c8
10 files changed, 258 insertions, 180 deletions
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 53cee17d0115..722af9ee53d6 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -65,36 +65,18 @@ struct ti_sci_xfers_info {
};
/**
- * struct ti_sci_rm_type_map - Structure representing TISCI Resource
- * management representation of dev_ids.
- * @dev_id: TISCI device ID
- * @type: Corresponding id as identified by TISCI RM.
- *
- * Note: This is used only as a work around for using RM range apis
- * for AM654 SoC. For future SoCs dev_id will be used as type
- * for RM range APIs. In order to maintain ABI backward compatibility
- * type is not being changed for AM654 SoC.
- */
-struct ti_sci_rm_type_map {
- u32 dev_id;
- u16 type;
-};
-
-/**
* struct ti_sci_desc - Description of SoC integration
* @default_host_id: Host identifier representing the compute entity
* @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
* @max_msgs: Maximum number of messages that can be pending
* simultaneously in the system
* @max_msg_size: Maximum size of data per message that can be handled.
- * @rm_type_map: RM resource type mapping structure.
*/
struct ti_sci_desc {
u8 default_host_id;
int max_rx_timeout_ms;
int max_msgs;
int max_msg_size;
- struct ti_sci_rm_type_map *rm_type_map;
};
/**
@@ -1710,33 +1692,6 @@ fail:
return ret;
}
-static int ti_sci_get_resource_type(struct ti_sci_info *info, u16 dev_id,
- u16 *type)
-{
- struct ti_sci_rm_type_map *rm_type_map = info->desc->rm_type_map;
- bool found = false;
- int i;
-
- /* If map is not provided then assume dev_id is used as type */
- if (!rm_type_map) {
- *type = dev_id;
- return 0;
- }
-
- for (i = 0; rm_type_map[i].dev_id; i++) {
- if (rm_type_map[i].dev_id == dev_id) {
- *type = rm_type_map[i].type;
- found = true;
- break;
- }
- }
-
- if (!found)
- return -EINVAL;
-
- return 0;
-}
-
/**
* ti_sci_get_resource_range - Helper to get a range of resources assigned
* to a host. Resource is uniquely identified by
@@ -1760,7 +1715,6 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
struct ti_sci_xfer *xfer;
struct ti_sci_info *info;
struct device *dev;
- u16 type;
int ret = 0;
if (IS_ERR(handle))
@@ -1780,15 +1734,9 @@ static int ti_sci_get_resource_range(const struct ti_sci_handle *handle,
return ret;
}
- ret = ti_sci_get_resource_type(info, dev_id, &type);
- if (ret) {
- dev_err(dev, "rm type lookup failed for %u\n", dev_id);
- goto fail;
- }
-
req = (struct ti_sci_msg_req_get_resource_range *)xfer->xfer_buf;
req->secondary_host = s_host;
- req->type = type & MSG_RM_RESOURCE_TYPE_MASK;
+ req->type = dev_id & MSG_RM_RESOURCE_TYPE_MASK;
req->subtype = subtype & MSG_RM_RESOURCE_SUBTYPE_MASK;
ret = ti_sci_do_xfer(info, xfer);
@@ -3260,61 +3208,50 @@ u32 ti_sci_get_num_resources(struct ti_sci_resource *res)
EXPORT_SYMBOL_GPL(ti_sci_get_num_resources);
/**
- * devm_ti_sci_get_of_resource() - Get a TISCI resource assigned to a device
+ * devm_ti_sci_get_resource_sets() - Get a TISCI resources assigned to a device
* @handle: TISCI handle
* @dev: Device pointer to which the resource is assigned
* @dev_id: TISCI device id to which the resource is assigned
- * @of_prop: property name by which the resource are represented
+ * @sub_types: Array of sub_types assigned corresponding to device
+ * @sets: Number of sub_types
*
* Return: Pointer to ti_sci_resource if all went well else appropriate
* error pointer.
*/
-struct ti_sci_resource *
-devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
- struct device *dev, u32 dev_id, char *of_prop)
+static struct ti_sci_resource *
+devm_ti_sci_get_resource_sets(const struct ti_sci_handle *handle,
+ struct device *dev, u32 dev_id, u32 *sub_types,
+ u32 sets)
{
struct ti_sci_resource *res;
bool valid_set = false;
- u32 resource_subtype;
int i, ret;
res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
if (!res)
return ERR_PTR(-ENOMEM);
- ret = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
- sizeof(u32));
- if (ret < 0) {
- dev_err(dev, "%s resource type ids not available\n", of_prop);
- return ERR_PTR(ret);
- }
- res->sets = ret;
-
+ res->sets = sets;
res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
GFP_KERNEL);
if (!res->desc)
return ERR_PTR(-ENOMEM);
for (i = 0; i < res->sets; i++) {
- ret = of_property_read_u32_index(dev_of_node(dev), of_prop, i,
- &resource_subtype);
- if (ret)
- return ERR_PTR(-EINVAL);
-
ret = handle->ops.rm_core_ops.get_range(handle, dev_id,
- resource_subtype,
+ sub_types[i],
&res->desc[i].start,
&res->desc[i].num);
if (ret) {
dev_dbg(dev, "dev = %d subtype %d not allocated for this host\n",
- dev_id, resource_subtype);
+ dev_id, sub_types[i]);
res->desc[i].start = 0;
res->desc[i].num = 0;
continue;
}
dev_dbg(dev, "dev = %d, subtype = %d, start = %d, num = %d\n",
- dev_id, resource_subtype, res->desc[i].start,
+ dev_id, sub_types[i], res->desc[i].start,
res->desc[i].num);
valid_set = true;
@@ -3332,6 +3269,62 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
return ERR_PTR(-EINVAL);
}
+/**
+ * devm_ti_sci_get_of_resource() - Get a TISCI resource assigned to a device
+ * @handle: TISCI handle
+ * @dev: Device pointer to which the resource is assigned
+ * @dev_id: TISCI device id to which the resource is assigned
+ * @of_prop: property name by which the resource are represented
+ *
+ * Return: Pointer to ti_sci_resource if all went well else appropriate
+ * error pointer.
+ */
+struct ti_sci_resource *
+devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
+ struct device *dev, u32 dev_id, char *of_prop)
+{
+ struct ti_sci_resource *res;
+ u32 *sub_types;
+ int sets;
+
+ sets = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
+ sizeof(u32));
+ if (sets < 0) {
+ dev_err(dev, "%s resource type ids not available\n", of_prop);
+ return ERR_PTR(sets);
+ }
+
+ sub_types = kcalloc(sets, sizeof(*sub_types), GFP_KERNEL);
+ if (!sub_types)
+ return ERR_PTR(-ENOMEM);
+
+ of_property_read_u32_array(dev_of_node(dev), of_prop, sub_types, sets);
+ res = devm_ti_sci_get_resource_sets(handle, dev, dev_id, sub_types,
+ sets);
+
+ kfree(sub_types);
+ return res;
+}
+EXPORT_SYMBOL_GPL(devm_ti_sci_get_of_resource);
+
+/**
+ * devm_ti_sci_get_resource() - Get a resource range assigned to the device
+ * @handle: TISCI handle
+ * @dev: Device pointer to which the resource is assigned
+ * @dev_id: TISCI device id to which the resource is assigned
+ * @suub_type: TISCI resource subytpe representing the resource.
+ *
+ * Return: Pointer to ti_sci_resource if all went well else appropriate
+ * error pointer.
+ */
+struct ti_sci_resource *
+devm_ti_sci_get_resource(const struct ti_sci_handle *handle, struct device *dev,
+ u32 dev_id, u32 sub_type)
+{
+ return devm_ti_sci_get_resource_sets(handle, dev, dev_id, &sub_type, 1);
+}
+EXPORT_SYMBOL_GPL(devm_ti_sci_get_resource);
+
static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
void *cmd)
{
@@ -3352,17 +3345,6 @@ static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
/* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
.max_msgs = 20,
.max_msg_size = 64,
- .rm_type_map = NULL,
-};
-
-static struct ti_sci_rm_type_map ti_sci_am654_rm_type_map[] = {
- {.dev_id = 56, .type = 0x00b}, /* GIC_IRQ */
- {.dev_id = 179, .type = 0x000}, /* MAIN_NAV_UDMASS_IA0 */
- {.dev_id = 187, .type = 0x009}, /* MAIN_NAV_RA */
- {.dev_id = 188, .type = 0x006}, /* MAIN_NAV_UDMAP */
- {.dev_id = 194, .type = 0x007}, /* MCU_NAV_UDMAP */
- {.dev_id = 195, .type = 0x00a}, /* MCU_NAV_RA */
- {.dev_id = 0, .type = 0x000}, /* end of table */
};
/* Description for AM654 */
@@ -3373,7 +3355,6 @@ static const struct ti_sci_desc ti_sci_pmmc_am654_desc = {
/* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
.max_msgs = 20,
.max_msg_size = 60,
- .rm_type_map = ti_sci_am654_rm_type_map,
};
static const struct of_device_id ti_sci_of_match[] = {
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index bb70b7177f94..bfc9719dbcdc 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -425,7 +425,7 @@ config GOLDFISH_PIC
for Goldfish based virtual platforms.
config QCOM_PDC
- tristate "QCOM PDC"
+ bool "QCOM PDC"
depends on ARCH_QCOM
select IRQ_DOMAIN_HIERARCHY
help
diff --git a/drivers/irqchip/irq-ingenic.c b/drivers/irqchip/irq-ingenic.c
index 9f3da4260ca6..b61a8901ef72 100644
--- a/drivers/irqchip/irq-ingenic.c
+++ b/drivers/irqchip/irq-ingenic.c
@@ -125,7 +125,7 @@ static int __init ingenic_intc_of_init(struct device_node *node,
irq_reg_writel(gc, IRQ_MSK(32), JZ_REG_INTC_SET_MASK);
}
- if (request_irq(parent_irq, intc_cascade, 0,
+ if (request_irq(parent_irq, intc_cascade, IRQF_NO_SUSPEND,
"SoC intc cascade interrupt", NULL))
pr_err("Failed to register SoC intc cascade interrupt\n");
return 0;
diff --git a/drivers/irqchip/irq-mtk-cirq.c b/drivers/irqchip/irq-mtk-cirq.c
index 62a61275aaa3..69ba8ce3c178 100644
--- a/drivers/irqchip/irq-mtk-cirq.c
+++ b/drivers/irqchip/irq-mtk-cirq.c
@@ -295,6 +295,4 @@ out_free:
return ret;
}
-IRQCHIP_PLATFORM_DRIVER_BEGIN(mtk_cirq)
-IRQCHIP_MATCH("mediatek,mtk-cirq", mtk_cirq_of_init)
-IRQCHIP_PLATFORM_DRIVER_END(mtk_cirq)
+IRQCHIP_DECLARE(mtk_cirq, "mediatek,mtk-cirq", mtk_cirq_of_init);
diff --git a/drivers/irqchip/irq-mtk-sysirq.c b/drivers/irqchip/irq-mtk-sysirq.c
index 7299c5ab4d10..6ff98b87e5c0 100644
--- a/drivers/irqchip/irq-mtk-sysirq.c
+++ b/drivers/irqchip/irq-mtk-sysirq.c
@@ -231,6 +231,4 @@ out_free_chip:
kfree(chip_data);
return ret;
}
-IRQCHIP_PLATFORM_DRIVER_BEGIN(mtk_sysirq)
-IRQCHIP_MATCH("mediatek,mt6577-sysirq", mtk_sysirq_of_init)
-IRQCHIP_PLATFORM_DRIVER_END(mtk_sysirq)
+IRQCHIP_DECLARE(mtk_sysirq, "mediatek,mt6577-sysirq", mtk_sysirq_of_init);
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 03a36be757d8..0c2c61db26b4 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -416,6 +416,16 @@ static void stm32_irq_ack(struct irq_data *d)
irq_gc_unlock(gc);
}
+/* directly set the target bit without reading first. */
+static inline void stm32_exti_write_bit(struct irq_data *d, u32 reg)
+{
+ struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
+ void __iomem *base = chip_data->host_data->base;
+ u32 val = BIT(d->hwirq % IRQS_PER_BANK);
+
+ writel_relaxed(val, base + reg);
+}
+
static inline u32 stm32_exti_set_bit(struct irq_data *d, u32 reg)
{
struct stm32_exti_chip_data *chip_data = irq_data_get_irq_chip_data(d);
@@ -449,9 +459,9 @@ static void stm32_exti_h_eoi(struct irq_data *d)
raw_spin_lock(&chip_data->rlock);
- stm32_exti_set_bit(d, stm32_bank->rpr_ofst);
+ stm32_exti_write_bit(d, stm32_bank->rpr_ofst);
if (stm32_bank->fpr_ofst != UNDEF_REG)
- stm32_exti_set_bit(d, stm32_bank->fpr_ofst);
+ stm32_exti_write_bit(d, stm32_bank->fpr_ofst);
raw_spin_unlock(&chip_data->rlock);
diff --git a/drivers/irqchip/irq-ti-sci-inta.c b/drivers/irqchip/irq-ti-sci-inta.c
index b7cc5d6580d8..d4e97605456b 100644
--- a/drivers/irqchip/irq-ti-sci-inta.c
+++ b/drivers/irqchip/irq-ti-sci-inta.c
@@ -8,6 +8,7 @@
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/interrupt.h>
@@ -83,6 +84,7 @@ struct ti_sci_inta_vint_desc {
* @vint_mutex: Mutex to protect vint_list
* @base: Base address of the memory mapped IO registers
* @pdev: Pointer to platform device.
+ * @ti_sci_id: TI-SCI device identifier
*/
struct ti_sci_inta_irq_domain {
const struct ti_sci_handle *sci;
@@ -93,6 +95,7 @@ struct ti_sci_inta_irq_domain {
struct mutex vint_mutex;
void __iomem *base;
struct platform_device *pdev;
+ u32 ti_sci_id;
};
#define to_vint_desc(e, i) container_of(e, struct ti_sci_inta_vint_desc, \
@@ -129,6 +132,37 @@ static void ti_sci_inta_irq_handler(struct irq_desc *desc)
}
/**
+ * ti_sci_inta_xlate_irq() - Translate hwirq to parent's hwirq.
+ * @inta: IRQ domain corresponding to Interrupt Aggregator
+ * @irq: Hardware irq corresponding to the above irq domain
+ *
+ * Return parent irq number if translation is available else -ENOENT.
+ */
+static int ti_sci_inta_xlate_irq(struct ti_sci_inta_irq_domain *inta,
+ u16 vint_id)
+{
+ struct device_node *np = dev_of_node(&inta->pdev->dev);
+ u32 base, parent_base, size;
+ const __be32 *range;
+ int len;
+
+ range = of_get_property(np, "ti,interrupt-ranges", &len);
+ if (!range)
+ return vint_id;
+
+ for (len /= sizeof(*range); len >= 3; len -= 3) {
+ base = be32_to_cpu(*range++);
+ parent_base = be32_to_cpu(*range++);
+ size = be32_to_cpu(*range++);
+
+ if (base <= vint_id && vint_id < base + size)
+ return vint_id - base + parent_base;
+ }
+
+ return -ENOENT;
+}
+
+/**
* ti_sci_inta_alloc_parent_irq() - Allocate parent irq to Interrupt aggregator
* @domain: IRQ domain corresponding to Interrupt Aggregator
*
@@ -139,30 +173,52 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
struct ti_sci_inta_irq_domain *inta = domain->host_data;
struct ti_sci_inta_vint_desc *vint_desc;
struct irq_fwspec parent_fwspec;
+ struct device_node *parent_node;
unsigned int parent_virq;
- u16 vint_id;
+ u16 vint_id, p_hwirq;
+ int ret;
vint_id = ti_sci_get_free_resource(inta->vint);
if (vint_id == TI_SCI_RESOURCE_NULL)
return ERR_PTR(-EINVAL);
+ p_hwirq = ti_sci_inta_xlate_irq(inta, vint_id);
+ if (p_hwirq < 0) {
+ ret = p_hwirq;
+ goto free_vint;
+ }
+
vint_desc = kzalloc(sizeof(*vint_desc), GFP_KERNEL);
- if (!vint_desc)
- return ERR_PTR(-ENOMEM);
+ if (!vint_desc) {
+ ret = -ENOMEM;
+ goto free_vint;
+ }
vint_desc->domain = domain;
vint_desc->vint_id = vint_id;
INIT_LIST_HEAD(&vint_desc->list);
- parent_fwspec.fwnode = of_node_to_fwnode(of_irq_find_parent(dev_of_node(&inta->pdev->dev)));
- parent_fwspec.param_count = 2;
- parent_fwspec.param[0] = inta->pdev->id;
- parent_fwspec.param[1] = vint_desc->vint_id;
+ parent_node = of_irq_find_parent(dev_of_node(&inta->pdev->dev));
+ parent_fwspec.fwnode = of_node_to_fwnode(parent_node);
+
+ if (of_device_is_compatible(parent_node, "arm,gic-v3")) {
+ /* Parent is GIC */
+ parent_fwspec.param_count = 3;
+ parent_fwspec.param[0] = 0;
+ parent_fwspec.param[1] = p_hwirq - 32;
+ parent_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
+ } else {
+ /* Parent is Interrupt Router */
+ parent_fwspec.param_count = 1;
+ parent_fwspec.param[0] = p_hwirq;
+ }
parent_virq = irq_create_fwspec_mapping(&parent_fwspec);
if (parent_virq == 0) {
- kfree(vint_desc);
- return ERR_PTR(-EINVAL);
+ dev_err(&inta->pdev->dev, "Parent IRQ allocation failed\n");
+ ret = -EINVAL;
+ goto free_vint_desc;
+
}
vint_desc->parent_virq = parent_virq;
@@ -171,6 +227,11 @@ static struct ti_sci_inta_vint_desc *ti_sci_inta_alloc_parent_irq(struct irq_dom
ti_sci_inta_irq_handler, vint_desc);
return vint_desc;
+free_vint_desc:
+ kfree(vint_desc);
+free_vint:
+ ti_sci_release_resource(inta->vint, vint_id);
+ return ERR_PTR(ret);
}
/**
@@ -202,7 +263,7 @@ static struct ti_sci_inta_event_desc *ti_sci_inta_alloc_event(struct ti_sci_inta
err = inta->sci->ops.rm_irq_ops.set_event_map(inta->sci,
dev_id, dev_index,
- inta->pdev->id,
+ inta->ti_sci_id,
vint_desc->vint_id,
event_desc->global_event,
free_bit);
@@ -299,7 +360,7 @@ static void ti_sci_inta_free_irq(struct ti_sci_inta_event_desc *event_desc,
inta->sci->ops.rm_irq_ops.free_event_map(inta->sci,
HWIRQ_TO_DEVID(hwirq),
HWIRQ_TO_IRQID(hwirq),
- inta->pdev->id,
+ inta->ti_sci_id,
vint_desc->vint_id,
event_desc->global_event,
event_desc->vint_bit);
@@ -547,21 +608,21 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
return ret;
}
- ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", &pdev->id);
+ ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", &inta->ti_sci_id);
if (ret) {
dev_err(dev, "missing 'ti,sci-dev-id' property\n");
return -EINVAL;
}
- inta->vint = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
- "ti,sci-rm-range-vint");
+ inta->vint = devm_ti_sci_get_resource(inta->sci, dev, inta->ti_sci_id,
+ TI_SCI_RESASG_SUBTYPE_IA_VINT);
if (IS_ERR(inta->vint)) {
dev_err(dev, "VINT resource allocation failed\n");
return PTR_ERR(inta->vint);
}
- inta->global_event = devm_ti_sci_get_of_resource(inta->sci, dev, pdev->id,
- "ti,sci-rm-range-global-event");
+ inta->global_event = devm_ti_sci_get_resource(inta->sci, dev, inta->ti_sci_id,
+ TI_SCI_RESASG_SUBTYPE_GLOBAL_EVENT_SEVT);
if (IS_ERR(inta->global_event)) {
dev_err(dev, "Global event resource allocation failed\n");
return PTR_ERR(inta->global_event);
@@ -592,6 +653,8 @@ static int ti_sci_inta_irq_domain_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&inta->vint_list);
mutex_init(&inta->vint_mutex);
+ dev_info(dev, "Interrupt Aggregator domain %d created\n", pdev->id);
+
return 0;
}
diff --git a/drivers/irqchip/irq-ti-sci-intr.c b/drivers/irqchip/irq-ti-sci-intr.c
index 5ea148faf2ab..cbc1758228d9 100644
--- a/drivers/irqchip/irq-ti-sci-intr.c
+++ b/drivers/irqchip/irq-ti-sci-intr.c
@@ -17,29 +17,20 @@
#include <linux/of_irq.h>
#include <linux/soc/ti/ti_sci_protocol.h>
-#define TI_SCI_DEV_ID_MASK 0xffff
-#define TI_SCI_DEV_ID_SHIFT 16
-#define TI_SCI_IRQ_ID_MASK 0xffff
-#define TI_SCI_IRQ_ID_SHIFT 0
-#define HWIRQ_TO_DEVID(hwirq) (((hwirq) >> (TI_SCI_DEV_ID_SHIFT)) & \
- (TI_SCI_DEV_ID_MASK))
-#define HWIRQ_TO_IRQID(hwirq) ((hwirq) & (TI_SCI_IRQ_ID_MASK))
-#define TO_HWIRQ(dev, index) ((((dev) & TI_SCI_DEV_ID_MASK) << \
- TI_SCI_DEV_ID_SHIFT) | \
- ((index) & TI_SCI_IRQ_ID_MASK))
-
/**
* struct ti_sci_intr_irq_domain - Structure representing a TISCI based
* Interrupt Router IRQ domain.
* @sci: Pointer to TISCI handle
- * @dst_irq: TISCI resource pointer representing GIC irq controller.
- * @dst_id: TISCI device ID of the GIC irq controller.
+ * @out_irqs: TISCI resource pointer representing INTR irqs.
+ * @dev: Struct device pointer.
+ * @ti_sci_id: TI-SCI device identifier
* @type: Specifies the trigger type supported by this Interrupt Router
*/
struct ti_sci_intr_irq_domain {
const struct ti_sci_handle *sci;
- struct ti_sci_resource *dst_irq;
- u32 dst_id;
+ struct ti_sci_resource *out_irqs;
+ struct device *dev;
+ u32 ti_sci_id;
u32 type;
};
@@ -70,16 +61,45 @@ static int ti_sci_intr_irq_domain_translate(struct irq_domain *domain,
{
struct ti_sci_intr_irq_domain *intr = domain->host_data;
- if (fwspec->param_count != 2)
+ if (fwspec->param_count != 1)
return -EINVAL;
- *hwirq = TO_HWIRQ(fwspec->param[0], fwspec->param[1]);
+ *hwirq = fwspec->param[0];
*type = intr->type;
return 0;
}
/**
+ * ti_sci_intr_xlate_irq() - Translate hwirq to parent's hwirq.
+ * @intr: IRQ domain corresponding to Interrupt Router
+ * @irq: Hardware irq corresponding to the above irq domain
+ *
+ * Return parent irq number if translation is available else -ENOENT.
+ */
+static int ti_sci_intr_xlate_irq(struct ti_sci_intr_irq_domain *intr, u32 irq)
+{
+ struct device_node *np = dev_of_node(intr->dev);
+ u32 base, pbase, size, len;
+ const __be32 *range;
+
+ range = of_get_property(np, "ti,interrupt-ranges", &len);
+ if (!range)
+ return irq;
+
+ for (len /= sizeof(*range); len >= 3; len -= 3) {
+ base = be32_to_cpu(*range++);
+ pbase = be32_to_cpu(*range++);
+ size = be32_to_cpu(*range++);
+
+ if (base <= irq && irq < base + size)
+ return irq - base + pbase;
+ }
+
+ return -ENOENT;
+}
+
+/**
* ti_sci_intr_irq_domain_free() - Free the specified IRQs from the domain.
* @domain: Domain to which the irqs belong
* @virq: Linux virtual IRQ to be freed.
@@ -89,66 +109,76 @@ static void ti_sci_intr_irq_domain_free(struct irq_domain *domain,
unsigned int virq, unsigned int nr_irqs)
{
struct ti_sci_intr_irq_domain *intr = domain->host_data;
- struct irq_data *data, *parent_data;
- u16 dev_id, irq_index;
+ struct irq_data *data;
+ int out_irq;
- parent_data = irq_domain_get_irq_data(domain->parent, virq);
data = irq_domain_get_irq_data(domain, virq);
- irq_index = HWIRQ_TO_IRQID(data->hwirq);
- dev_id = HWIRQ_TO_DEVID(data->hwirq);
+ out_irq = (uintptr_t)data->chip_data;
- intr->sci->ops.rm_irq_ops.free_irq(intr->sci, dev_id, irq_index,
- intr->dst_id, parent_data->hwirq);
- ti_sci_release_resource(intr->dst_irq, parent_data->hwirq);
+ intr->sci->ops.rm_irq_ops.free_irq(intr->sci,
+ intr->ti_sci_id, data->hwirq,
+ intr->ti_sci_id, out_irq);
+ ti_sci_release_resource(intr->out_irqs, out_irq);
irq_domain_free_irqs_parent(domain, virq, 1);
irq_domain_reset_irq_data(data);
}
/**
- * ti_sci_intr_alloc_gic_irq() - Allocate GIC specific IRQ
+ * ti_sci_intr_alloc_parent_irq() - Allocate parent IRQ
* @domain: Pointer to the interrupt router IRQ domain
* @virq: Corresponding Linux virtual IRQ number
* @hwirq: Corresponding hwirq for the IRQ within this IRQ domain
*
- * Returns 0 if all went well else appropriate error pointer.
+ * Returns parent irq if all went well else appropriate error pointer.
*/
-static int ti_sci_intr_alloc_gic_irq(struct irq_domain *domain,
- unsigned int virq, u32 hwirq)
+static int ti_sci_intr_alloc_parent_irq(struct irq_domain *domain,
+ unsigned int virq, u32 hwirq)
{
struct ti_sci_intr_irq_domain *intr = domain->host_data;
+ struct device_node *parent_node;
struct irq_fwspec fwspec;
- u16 dev_id, irq_index;
- u16 dst_irq;
- int err;
-
- dev_id = HWIRQ_TO_DEVID(hwirq);
- irq_index = HWIRQ_TO_IRQID(hwirq);
+ u16 out_irq, p_hwirq;
+ int err = 0;
- dst_irq = ti_sci_get_free_resource(intr->dst_irq);
- if (dst_irq == TI_SCI_RESOURCE_NULL)
+ out_irq = ti_sci_get_free_resource(intr->out_irqs);
+ if (out_irq == TI_SCI_RESOURCE_NULL)
return -EINVAL;
- fwspec.fwnode = domain->parent->fwnode;
- fwspec.param_count = 3;
- fwspec.param[0] = 0; /* SPI */
- fwspec.param[1] = dst_irq - 32; /* SPI offset */
- fwspec.param[2] = intr->type;
+ p_hwirq = ti_sci_intr_xlate_irq(intr, out_irq);
+ if (p_hwirq < 0)
+ goto err_irqs;
+
+ parent_node = of_irq_find_parent(dev_of_node(intr->dev));
+ fwspec.fwnode = of_node_to_fwnode(parent_node);
+
+ if (of_device_is_compatible(parent_node, "arm,gic-v3")) {
+ /* Parent is GIC */
+ fwspec.param_count = 3;
+ fwspec.param[0] = 0; /* SPI */
+ fwspec.param[1] = p_hwirq - 32; /* SPI offset */
+ fwspec.param[2] = intr->type;
+ } else {
+ /* Parent is Interrupt Router */
+ fwspec.param_count = 1;
+ fwspec.param[0] = p_hwirq;
+ }
err = irq_domain_alloc_irqs_parent(domain, virq, 1, &fwspec);
if (err)
goto err_irqs;
- err = intr->sci->ops.rm_irq_ops.set_irq(intr->sci, dev_id, irq_index,
- intr->dst_id, dst_irq);
+ err = intr->sci->ops.rm_irq_ops.set_irq(intr->sci,
+ intr->ti_sci_id, hwirq,
+ intr->ti_sci_id, out_irq);
if (err)
goto err_msg;
- return 0;
+ return p_hwirq;
err_msg:
irq_domain_free_irqs_parent(domain, virq, 1);
err_irqs:
- ti_sci_release_resource(intr->dst_irq, dst_irq);
+ ti_sci_release_resource(intr->out_irqs, out_irq);
return err;
}
@@ -168,18 +198,19 @@ static int ti_sci_intr_irq_domain_alloc(struct irq_domain *domain,
struct irq_fwspec *fwspec = data;
unsigned long hwirq;
unsigned int flags;
- int err;
+ int err, p_hwirq;
err = ti_sci_intr_irq_domain_translate(domain, fwspec, &hwirq, &flags);
if (err)
return err;
- err = ti_sci_intr_alloc_gic_irq(domain, virq, hwirq);
- if (err)
- return err;
+ p_hwirq = ti_sci_intr_alloc_parent_irq(domain, virq, hwirq);
+ if (p_hwirq < 0)
+ return p_hwirq;
irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
- &ti_sci_intr_irq_chip, NULL);
+ &ti_sci_intr_irq_chip,
+ (void *)(uintptr_t)p_hwirq);
return 0;
}
@@ -214,6 +245,7 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
if (!intr)
return -ENOMEM;
+ intr->dev = dev;
ret = of_property_read_u32(dev_of_node(dev), "ti,intr-trigger-type",
&intr->type);
if (ret) {
@@ -230,19 +262,19 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
return ret;
}
- ret = of_property_read_u32(dev_of_node(dev), "ti,sci-dst-id",
- &intr->dst_id);
+ ret = of_property_read_u32(dev_of_node(dev), "ti,sci-dev-id",
+ &intr->ti_sci_id);
if (ret) {
- dev_err(dev, "missing 'ti,sci-dst-id' property\n");
+ dev_err(dev, "missing 'ti,sci-dev-id' property\n");
return -EINVAL;
}
- intr->dst_irq = devm_ti_sci_get_of_resource(intr->sci, dev,
- intr->dst_id,
- "ti,sci-rm-range-girq");
- if (IS_ERR(intr->dst_irq)) {
+ intr->out_irqs = devm_ti_sci_get_resource(intr->sci, dev,
+ intr->ti_sci_id,
+ TI_SCI_RESASG_SUBTYPE_IR_OUTPUT);
+ if (IS_ERR(intr->out_irqs)) {
dev_err(dev, "Destination irq resource allocation failed\n");
- return PTR_ERR(intr->dst_irq);
+ return PTR_ERR(intr->out_irqs);
}
domain = irq_domain_add_hierarchy(parent_domain, 0, 0, dev_of_node(dev),
@@ -252,6 +284,8 @@ static int ti_sci_intr_irq_domain_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ dev_info(dev, "Interrupt Router %d domain created\n", intr->ti_sci_id);
+
return 0;
}
diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c
index 1bb0e36c2bf3..d2341153e181 100644
--- a/drivers/irqchip/irqchip.c
+++ b/drivers/irqchip/irqchip.c
@@ -52,7 +52,7 @@ int platform_irqchip_probe(struct platform_device *pdev)
* interrupt controller. The actual initialization callback of this
* interrupt controller can check for specific domains as necessary.
*/
- if (par_np && !irq_find_matching_host(np, DOMAIN_BUS_ANY))
+ if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY))
return -EPROBE_DEFER;
return irq_init_cb(np, par_np);
diff --git a/drivers/irqchip/qcom-pdc.c b/drivers/irqchip/qcom-pdc.c
index c1c5dfad57cc..6ae9e1f0819d 100644
--- a/drivers/irqchip/qcom-pdc.c
+++ b/drivers/irqchip/qcom-pdc.c
@@ -11,11 +11,9 @@
#include <linux/irqdomain.h>
#include <linux/io.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
-#include <linux/of_irq.h>
#include <linux/soc/qcom/irq.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -432,8 +430,4 @@ fail:
return ret;
}
-IRQCHIP_PLATFORM_DRIVER_BEGIN(qcom_pdc)
-IRQCHIP_MATCH("qcom,pdc", qcom_pdc_init)
-IRQCHIP_PLATFORM_DRIVER_END(qcom_pdc)
-MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Power Domain Controller");
-MODULE_LICENSE("GPL v2");
+IRQCHIP_DECLARE(qcom_pdc, "qcom,pdc", qcom_pdc_init);