irq: Tidy up of-platdata irq support

This function is available but not exported. More generally it does not
really work as intended.

Reimplement it and add a sandbox test too.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index 6cf5f14..1fc9c9b 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -124,6 +124,19 @@
 		#sound-dai-cells = <1>;
 	};
 
+	irq_sandbox: irq-sbox {
+		u-boot,dm-spl;
+		compatible = "sandbox,irq";
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	irq-test {
+		u-boot,dm-spl;
+		compatible = "sandbox,irq-test";
+		interrupts-extended = <&irq_sandbox 3 0>;
+	};
+
 	lcd {
 		u-boot,dm-pre-proper;
 		compatible = "sandbox,lcd-sdl";
diff --git a/arch/sandbox/include/asm/irq.h b/arch/sandbox/include/asm/irq.h
new file mode 100644
index 0000000..f73fec7
--- /dev/null
+++ b/arch/sandbox/include/asm/irq.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2021 Google LLC
+ */
+
+#ifndef __SANDBOX_IRQ_H
+#define __SANDBOX_IRQ_H
+
+/**
+ * struct sandbox_irq_priv - private data for this driver
+ *
+ * @count: Counts the number calls to the read_and_clear() method
+ * @pending: true if an interrupt is pending, else false
+ */
+struct sandbox_irq_priv {
+	int count;
+	bool pending;
+};
+
+#endif /* __SANDBOX_IRQ_H */
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b64cd2a..c16a77c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -42,7 +42,7 @@
 obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
 obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o
 obj-$(CONFIG_IRQ) += irq-uclass.o
-obj-$(CONFIG_SANDBOX) += irq_sandbox.o
+obj-$(CONFIG_SANDBOX) += irq_sandbox.o irq_sandbox_test.o
 obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
 obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
 obj-$(CONFIG_IMX8) += imx8/
diff --git a/drivers/misc/irq-uclass.c b/drivers/misc/irq-uclass.c
index 3aa26f6..eb9f3b9 100644
--- a/drivers/misc/irq-uclass.c
+++ b/drivers/misc/irq-uclass.c
@@ -64,8 +64,8 @@
 }
 
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
-int irq_get_by_driver_info(struct udevice *dev,
-			   struct phandle_1_arg *cells, struct irq *irq)
+int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells,
+		       struct irq *irq)
 {
 	int ret;
 
@@ -74,6 +74,12 @@
 		return ret;
 	irq->id = cells->arg[0];
 
+	/*
+	 * Note: we could call irq_of_xlate_default() here to do this properly.
+	 * For now, this is good enough for existing cases.
+	 */
+	irq->flags = cells->arg[1];
+
 	return 0;
 }
 #else
diff --git a/drivers/misc/irq_sandbox.c b/drivers/misc/irq_sandbox.c
index 1f7e62e..8b5573f 100644
--- a/drivers/misc/irq_sandbox.c
+++ b/drivers/misc/irq_sandbox.c
@@ -9,19 +9,9 @@
 #include <dm.h>
 #include <irq.h>
 #include <acpi/acpi_device.h>
+#include <asm/irq.h>
 #include <asm/test.h>
 
-/**
- * struct sandbox_irq_priv - private data for this driver
- *
- * @count: Counts the number calls to the read_and_clear() method
- * @pending: true if an interrupt is pending, else false
- */
-struct sandbox_irq_priv {
-	int count;
-	bool pending;
-};
-
 static int sandbox_set_polarity(struct udevice *dev, uint irq, bool active_low)
 {
 	if (irq > 10)
@@ -103,10 +93,11 @@
 	{ }
 };
 
-U_BOOT_DRIVER(sandbox_irq_drv) = {
+U_BOOT_DRIVER(sandbox_irq) = {
 	.name		= "sandbox_irq",
 	.id		= UCLASS_IRQ,
 	.of_match	= sandbox_irq_ids,
 	.ops		= &sandbox_irq_ops,
 	.priv_auto	= sizeof(struct sandbox_irq_priv),
+	DM_HEADER(<asm/irq.h>)
 };
diff --git a/drivers/misc/irq_sandbox_test.c b/drivers/misc/irq_sandbox_test.c
new file mode 100644
index 0000000..95c45c2
--- /dev/null
+++ b/drivers/misc/irq_sandbox_test.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sandbox driver for testing interrupts with of-platdata
+ *
+ * Copyright 2021 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <irq.h>
+#include <asm/irq.h>
+
+static const struct udevice_id sandbox_irq_test_ids[] = {
+	{ .compatible = "sandbox,irq-test" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_irq_test) = {
+	.name = "sandbox_irq_test",
+	.id = UCLASS_MISC,
+	.of_match = sandbox_irq_test_ids,
+};
diff --git a/include/irq.h b/include/irq.h
index 8527e4d..a0965e4 100644
--- a/include/irq.h
+++ b/include/irq.h
@@ -200,6 +200,35 @@
  */
 int irq_read_and_clear(struct irq *irq);
 
+struct phandle_2_arg;
+/**
+ * irq_get_by_phandle() - Get an irq by its phandle information (of-platadata)
+ *
+ * This function is used when of-platdata is enabled.
+ *
+ * This looks up an irq using the phandle info. With dtoc, each phandle in the
+ * 'interrupts-extended ' property is transformed into an idx representing the
+ * device. For example:
+ *
+ * interrupts-extended = <&acpi_gpe 0x3c 0>;
+ *
+ * might result in:
+ *
+ *	.interrupts_extended = {6, {0x3c, 0}},},
+ *
+ * indicating that the irq is udevice idx 6 in dt-plat.c with a arguments of
+ * 0x3c and 0.This function can return a valid irq given the above
+ * information. In this example it would return an irq containing the
+ * 'acpi_gpe' device and the irq ID 0x3c.
+ *
+ * @dev: Device containing the phandle
+ * @cells: Phandle info
+ * @irq: A pointer to a irq struct to initialise
+ * @return 0 if OK, or a negative error code
+ */
+int irq_get_by_phandle(struct udevice *dev, const struct phandle_2_arg *cells,
+		       struct irq *irq);
+
 /**
  * irq_get_by_index - Get/request an irq by integer index.
  *
diff --git a/test/dm/of_platdata.c b/test/dm/of_platdata.c
index c4a2d11..0829890 100644
--- a/test/dm/of_platdata.c
+++ b/test/dm/of_platdata.c
@@ -4,6 +4,7 @@
 #include <clk.h>
 #include <dm.h>
 #include <dt-structs.h>
+#include <irq.h>
 #include <dm/test.h>
 #include <test/test.h>
 #include <test/ut.h>
@@ -28,11 +29,9 @@
 	struct udevice *dev;
 	int i;
 
-	/* Skip the clock */
-	ut_assertok(uclass_first_device_err(UCLASS_MISC, &dev));
-	ut_asserteq_str("sandbox_clk_test", dev->name);
+	ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_spl_test",
+					      &dev));
 
-	ut_assertok(uclass_next_device_err(&dev));
 	plat = dev_get_plat(dev);
 	ut_assert(plat->boolval);
 	ut_asserteq(1, plat->intval);
@@ -241,3 +240,22 @@
 	return 0;
 }
 DM_TEST(dm_test_of_plat_clk, UT_TESTF_SCAN_PDATA);
+
+/* Test irqs with of-platdata */
+static int dm_test_of_plat_irq(struct unit_test_state *uts)
+{
+	struct dtd_sandbox_irq_test *plat;
+	struct udevice *dev;
+	struct irq irq;
+
+	ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_irq_test",
+					      &dev));
+	plat = dev_get_plat(dev);
+
+	ut_assertok(irq_get_by_phandle(dev, &plat->interrupts_extended[0],
+				       &irq));
+	ut_asserteq_str("sandbox_irq", irq.dev->name);
+
+	return 0;
+}
+DM_TEST(dm_test_of_plat_irq, UT_TESTF_SCAN_PDATA);
diff --git a/tools/dtoc/dtb_platdata.py b/tools/dtoc/dtb_platdata.py
index 869c92b..3bb5c68 100644
--- a/tools/dtoc/dtb_platdata.py
+++ b/tools/dtoc/dtb_platdata.py
@@ -62,6 +62,7 @@
 # a phandle property.
 PHANDLE_PROPS = {
     'clocks': '#clock-cells',
+    'interrupts-extended': '#interrupt-cells',
     'gpios': '#gpio-cells',
     'sandbox,emul': '#emul-cells',
     }