]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
drivers: misc: irq-uclass: Update irq_get_by_index
authorPatrick Rudolph <patrick.rudolph@9elements.com>
Wed, 23 Oct 2024 13:20:05 +0000 (15:20 +0200)
committerTom Rini <trini@konsulko.com>
Sun, 27 Oct 2024 23:24:13 +0000 (17:24 -0600)
Support reading the "interrupts" property from the devicetree in case
the "interrupts-extended" property isn't found. As the "interrupts"
property is commonly used, this allows to parse all existing FDT and
makes irq_get_by_index() more useful.

The "interrupts" property doesn't contain a phandle as "interrupts-extended"
does, so implement a new method to locate the interrupt-parent called
irq_get_interrupt_parent().

TEST: Read the interrupts from the GIC node for ACPI MADT generation.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-by: Moritz Fischer <moritzf@google.com>
arch/sandbox/dts/test.dts
drivers/misc/irq-uclass.c
include/irq.h
test/dm/irq.c

index 8412506c17a638135b1011d5e59c3956017b5e96..9599a8db9c5a365697b990e96641298a03afbc83 100644 (file)
        };
 
        f-test {
+               #interrupt-cells = <2>;
+               interrupt-parent = <&irq>;
+               interrupts = <4 0>;
                compatible = "denx,u-boot-fdt-test";
        };
 
index 79eb7c200dc24aa42ca3855079ebe232d8ad70e7..ac778593c962981cfe8609e6eb1a50c012a0b407 100644 (file)
@@ -62,6 +62,40 @@ int irq_read_and_clear(struct irq *irq)
        return ops->read_and_clear(irq);
 }
 
+int irq_get_interrupt_parent(const struct udevice *dev,
+                            struct udevice **interrupt_parent)
+{
+       struct ofnode_phandle_args phandle_args;
+       struct udevice *irq = NULL;
+       ofnode node;
+       int ret;
+
+       if (!dev || !interrupt_parent)
+               return -EINVAL;
+
+       *interrupt_parent = NULL;
+
+       node = dev_ofnode(dev);
+       if (!ofnode_valid(node))
+               return -EINVAL;
+
+       while (ofnode_valid(node)) {
+               ret = ofnode_parse_phandle_with_args(node, "interrupt-parent",
+                                                    NULL, 0, 0, &phandle_args);
+               if (!ret && !device_get_global_by_ofnode(phandle_args.node, &irq))
+                       break;
+               node = ofnode_get_parent(node);
+       }
+
+       if (!irq) {
+               log_err("Cannot find an interrupt parent for device %s\n", dev->name);
+               return -ENODEV;
+       }
+       *interrupt_parent = irq;
+
+       return 0;
+}
+
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
 int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells,
                       struct irq *irq)
@@ -142,10 +176,40 @@ err:
 int irq_get_by_index(struct udevice *dev, int index, struct irq *irq)
 {
        struct ofnode_phandle_args args;
-       int ret;
+       struct udevice *interrupt_parent;
+       int ret, size, i;
+       const __be32 *list;
+       u32 count;
 
        ret = dev_read_phandle_with_args(dev, "interrupts-extended",
                                         "#interrupt-cells", 0, index, &args);
+       if (ret) {
+               list = dev_read_prop(dev, "interrupts", &size);
+               if (!list)
+                       return -ENOENT;
+
+               ret = irq_get_interrupt_parent(dev, &interrupt_parent);
+               if (ret)
+                       return -ENODEV;
+               args.node = dev_ofnode(interrupt_parent);
+
+               if (dev_read_u32(interrupt_parent, "#interrupt-cells", &count)) {
+                       log_err("%s: could not get #interrupt-cells for %s\n",
+                               __func__, dev->name);
+                       return -ENOENT;
+               }
+
+               if (index * count >= size / sizeof(*list))
+                       return -ENOENT;
+               if (count > OF_MAX_PHANDLE_ARGS)
+                       count = OF_MAX_PHANDLE_ARGS;
+               args.args_count = count;
+               for (i = 0; i < count; i++)
+                       args.args[i] = be32_to_cpup(&list[index * count + i]);
+
+               return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
+                                            "interrupts", index, irq);
+       }
 
        return irq_get_by_index_tail(ret, dev_ofnode(dev), &args,
                                     "interrupts-extended", index > 0, irq);
index 5638c10128e9c3cfda63539d131d7375966dfed0..0fbc1a5f485619f208d81f07f4c671492c1aef1f 100644 (file)
@@ -200,6 +200,20 @@ int irq_restore_polarities(struct udevice *dev);
  */
 int irq_read_and_clear(struct irq *irq);
 
+/**
+ * irq_get_interrupt_parent() - returns the interrupt parent
+ *
+ * Walks the devicetree and returns the interrupt parent's ofnode
+ * for the specified device.
+ *
+ * @dev: device
+ * @interrupt_parent: The interrupt parent's ofnode'
+ * Return: 0 success, or error value
+ *
+ */
+int irq_get_interrupt_parent(const struct udevice *dev,
+                            struct udevice **interrupt_parent);
+
 struct phandle_2_arg;
 /**
  * irq_get_by_phandle() - Get an irq by its phandle information (of-platadata)
index 836f2d82e71f725cfb91295f3f94cc493e64b797..ca3e1880656a03cd6dfc4f9c6bd67d1d96f134fa 100644 (file)
@@ -76,6 +76,21 @@ static int dm_test_request(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_request, UTF_SCAN_PDATA | UTF_SCAN_FDT);
 
+/* Test of irq_get_by_index() */
+static int dm_test_irq_get_by_index(struct unit_test_state *uts)
+{
+       struct udevice *dev;
+       struct irq irq;
+
+       ut_assertok(uclass_get_device_by_name(UCLASS_TEST_FDT, "f-test",
+                                             &dev));
+       ut_assertok(irq_get_by_index(dev, 0, &irq));
+       ut_asserteq(4, irq.id);
+
+       return 0;
+}
+DM_TEST(dm_test_irq_get_by_index, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
 /* Test of irq_get_acpi() */
 static int dm_test_irq_get_acpi(struct unit_test_state *uts)
 {