summaryrefslogtreecommitdiff
path: root/drivers/of
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-10 20:45:30 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-10 20:45:30 -0800
commitbdbddf72a2ab1cfea699959795d70df3931eefe7 (patch)
treee3f8018c6e8d0354bf2a2fbd99569790ef521805 /drivers/of
parentf7fae9b4d38f0c52489640c9688e529c4a58e1b6 (diff)
parentcfd00b7e26c8331e3bb0f03ca770888866c15ff4 (diff)
Merge tag 'soc-drivers-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC driver updates from Arnd Bergmann: "There are are a number of to firmware drivers, in particular the TEE subsystem: - a bus callback for TEE firmware that device drivers can register to - sysfs support for tee firmware information - minor updates to platform specific TEE drivers for AMD, NXP, Qualcomm and the generic optee driver - ARM SCMI firmware refactoring to improve the protocol discover among other fixes and cleanups - ARM FF-A firmware interoperability improvements The reset controller and memory controller subsystems gain support for additional hardware platforms from Mediatek, Renesas, NXP, Canaan and SpacemiT. Most of the other changes are for random drivers/soc code. Among a number of cleanups and newly added hardware support, including: - Mediatek MT8196 DVFS power management and mailbox support - Qualcomm SCM firmware and MDT loader refactoring, as part of the new Glymur platform support. - NXP i.MX9 System Manager firmware support for accessing the syslog - Minor updates for TI, Renesas, Samsung, Apple, Marvell and AMD SoCs" * tag 'soc-drivers-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (171 commits) bus: fsl-mc: fix an error handling in fsl_mc_device_add() reset: spacemit: Add SpacemiT K3 reset driver reset: spacemit: Extract common K1 reset code reset: Create subdirectory for SpacemiT drivers dt-bindings: soc: spacemit: Add K3 reset support and IDs reset: canaan: k230: drop OF dependency and enable by default reset: rzg2l-usbphy-ctrl: Add suspend/resume support reset: rzg2l-usbphy-ctrl: Propagate the return value of regmap_field_update_bits() reset: gpio: check the return value of gpiod_set_value_cansleep() reset: imx8mp-audiomix: Support i.MX8ULP SIM LPAV reset: imx8mp-audiomix: Extend the driver usage reset: imx8mp-audiomix: Switch to using regmap API reset: imx8mp-audiomix: Drop unneeded macros soc: fsl: qe: qe_ports_ic: Consolidate chained IRQ handler install/remove soc: mediatek: mtk-cmdq: Add mminfra_offset adjustment for DRAM addresses soc: mediatek: mtk-cmdq: Extend cmdq_pkt_write API for SoCs without subsys ID soc: mediatek: mtk-cmdq: Add pa_base parsing for hardware without subsys ID support soc: mediatek: mtk-cmdq: Add cmdq_get_mbox_priv() in cmdq_pkt_create() mailbox: mtk-cmdq: Add driver data to support for MT8196 mailbox: mtk-cmdq: Add mminfra_offset configuration for DRAM transaction ...
Diffstat (limited to 'drivers/of')
-rw-r--r--drivers/of/irq.c70
-rw-r--r--drivers/of/unittest-data/tests-interrupts.dtsi9
-rw-r--r--drivers/of/unittest.c116
3 files changed, 195 insertions, 0 deletions
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index e3816819dbfe..f374d8b212b8 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -157,6 +157,76 @@ const __be32 *of_irq_parse_imap_parent(const __be32 *imap, int len, struct of_ph
return imap;
}
+int of_imap_parser_init(struct of_imap_parser *parser, struct device_node *node,
+ struct of_imap_item *item)
+{
+ int imaplen;
+ u32 tmp;
+ int ret;
+
+ /*
+ * parent_offset is the offset where the parent part is starting.
+ * In other words, the offset where the parent interrupt controller
+ * phandle is present.
+ *
+ * Compute this offset (child #interrupt-cells + child #address-cells)
+ */
+ parser->parent_offset = of_bus_n_addr_cells(node);
+
+ ret = of_property_read_u32(node, "#interrupt-cells", &tmp);
+ if (ret)
+ return ret;
+
+ parser->parent_offset += tmp;
+
+ if (WARN(parser->parent_offset > ARRAY_SIZE(item->child_imap),
+ "child part size = %u, cannot fit in array of %zu items",
+ parser->parent_offset, ARRAY_SIZE(item->child_imap)))
+ return -EINVAL;
+
+ parser->imap = of_get_property(node, "interrupt-map", &imaplen);
+ if (!parser->imap)
+ return -ENOENT;
+
+ imaplen /= sizeof(*parser->imap);
+ parser->imap_end = parser->imap + imaplen;
+
+ memset(item, 0, sizeof(*item));
+ item->child_imap_count = parser->parent_offset;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_imap_parser_init);
+
+struct of_imap_item *of_imap_parser_one(struct of_imap_parser *parser,
+ struct of_imap_item *item)
+{
+ const __be32 *imap_parent, *imap_next;
+ int i;
+
+ /* Release previously get parent node */
+ of_node_put(item->parent_args.np);
+
+ if (parser->imap + parser->parent_offset + 1 >= parser->imap_end)
+ return NULL;
+
+ imap_parent = parser->imap + parser->parent_offset;
+
+ imap_next = of_irq_parse_imap_parent(imap_parent,
+ parser->imap_end - imap_parent,
+ &item->parent_args);
+ if (!imap_next)
+ return NULL;
+
+ for (i = 0; i < parser->parent_offset; i++)
+ item->child_imap[i] = be32_to_cpu(*(parser->imap + i));
+
+ parser->imap = imap_next;
+
+ return item;
+}
+EXPORT_SYMBOL_GPL(of_imap_parser_one);
+
/**
* of_irq_parse_raw - Low level interrupt tree parsing
* @addr: address specifier (start of "reg" property of the device) in be32 format
diff --git a/drivers/of/unittest-data/tests-interrupts.dtsi b/drivers/of/unittest-data/tests-interrupts.dtsi
index 4ccb54f91c30..974f888c9b15 100644
--- a/drivers/of/unittest-data/tests-interrupts.dtsi
+++ b/drivers/of/unittest-data/tests-interrupts.dtsi
@@ -50,6 +50,15 @@
interrupt-map = <0x5000 1 2 &test_intc0 15>;
};
+ intmap2 {
+ #interrupt-cells = <2>;
+ #address-cells = <0>;
+ interrupt-map = <1 11 &test_intc0 100>,
+ <2 22 &test_intc1 200 201 202>,
+ <3 33 &test_intc2 300 301>,
+ <4 44 &test_intc2 400 401>;
+ };
+
test_intc_intmap0: intc-intmap0 {
#interrupt-cells = <1>;
#address-cells = <1>;
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 3b773aaf9d05..7eccb5d9135f 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -1654,6 +1654,121 @@ static void __init of_unittest_parse_interrupts_extended(void)
of_node_put(np);
}
+struct of_unittest_expected_imap_item {
+ u32 child_imap_count;
+ u32 child_imap[2];
+ const char *parent_path;
+ int parent_args_count;
+ u32 parent_args[3];
+};
+
+static const struct of_unittest_expected_imap_item of_unittest_expected_imap_items[] = {
+ {
+ .child_imap_count = 2,
+ .child_imap = {1, 11},
+ .parent_path = "/testcase-data/interrupts/intc0",
+ .parent_args_count = 1,
+ .parent_args = {100},
+ }, {
+ .child_imap_count = 2,
+ .child_imap = {2, 22},
+ .parent_path = "/testcase-data/interrupts/intc1",
+ .parent_args_count = 3,
+ .parent_args = {200, 201, 202},
+ }, {
+ .child_imap_count = 2,
+ .child_imap = {3, 33},
+ .parent_path = "/testcase-data/interrupts/intc2",
+ .parent_args_count = 2,
+ .parent_args = {300, 301},
+ }, {
+ .child_imap_count = 2,
+ .child_imap = {4, 44},
+ .parent_path = "/testcase-data/interrupts/intc2",
+ .parent_args_count = 2,
+ .parent_args = {400, 401},
+ }
+};
+
+static void __init of_unittest_parse_interrupt_map(void)
+{
+ const struct of_unittest_expected_imap_item *expected_item;
+ struct device_node *imap_np, *expected_parent_np;
+ struct of_imap_parser imap_parser;
+ struct of_imap_item imap_item;
+ int count, ret, i;
+
+ if (of_irq_workarounds & (OF_IMAP_NO_PHANDLE | OF_IMAP_OLDWORLD_MAC))
+ return;
+
+ imap_np = of_find_node_by_path("/testcase-data/interrupts/intmap2");
+ if (!imap_np) {
+ pr_err("missing testcase data\n");
+ return;
+ }
+
+ ret = of_imap_parser_init(&imap_parser, imap_np, &imap_item);
+ if (unittest(!ret, "of_imap_parser_init(%pOF) returned error %d\n",
+ imap_np, ret))
+ goto end;
+
+ expected_item = of_unittest_expected_imap_items;
+ count = 0;
+
+ for_each_of_imap_item(&imap_parser, &imap_item) {
+ if (unittest(count < ARRAY_SIZE(of_unittest_expected_imap_items),
+ "imap item number %d not expected. Max number %zu\n",
+ count, ARRAY_SIZE(of_unittest_expected_imap_items) - 1)) {
+ of_node_put(imap_item.parent_args.np);
+ goto end;
+ }
+
+ expected_parent_np = of_find_node_by_path(expected_item->parent_path);
+ if (unittest(expected_parent_np,
+ "missing dependent testcase data (%s)\n",
+ expected_item->parent_path)) {
+ of_node_put(imap_item.parent_args.np);
+ goto end;
+ }
+
+ unittest(imap_item.child_imap_count == expected_item->child_imap_count,
+ "imap[%d] child_imap_count = %u, expected %u\n",
+ count, imap_item.child_imap_count,
+ expected_item->child_imap_count);
+
+ for (i = 0; i < expected_item->child_imap_count; i++)
+ unittest(imap_item.child_imap[i] == expected_item->child_imap[i],
+ "imap[%d] child_imap[%d] = %u, expected %u\n",
+ count, i, imap_item.child_imap[i],
+ expected_item->child_imap[i]);
+
+ unittest(imap_item.parent_args.np == expected_parent_np,
+ "imap[%d] parent np = %pOF, expected %pOF\n",
+ count, imap_item.parent_args.np, expected_parent_np);
+
+ unittest(imap_item.parent_args.args_count == expected_item->parent_args_count,
+ "imap[%d] parent param_count = %d, expected %d\n",
+ count, imap_item.parent_args.args_count,
+ expected_item->parent_args_count);
+
+ for (i = 0; i < expected_item->parent_args_count; i++)
+ unittest(imap_item.parent_args.args[i] == expected_item->parent_args[i],
+ "imap[%d] parent param[%d] = %u, expected %u\n",
+ count, i, imap_item.parent_args.args[i],
+ expected_item->parent_args[i]);
+
+ of_node_put(expected_parent_np);
+ count++;
+ expected_item++;
+ }
+
+ unittest(count == ARRAY_SIZE(of_unittest_expected_imap_items),
+ "Missing items. %d parsed, expected %zu\n",
+ count, ARRAY_SIZE(of_unittest_expected_imap_items));
+end:
+ of_node_put(imap_np);
+}
+
#if IS_ENABLED(CONFIG_OF_DYNAMIC)
static void __init of_unittest_irq_refcount(void)
{
@@ -4393,6 +4508,7 @@ static int __init of_unittest(void)
of_unittest_changeset_prop();
of_unittest_parse_interrupts();
of_unittest_parse_interrupts_extended();
+ of_unittest_parse_interrupt_map();
of_unittest_irq_refcount();
of_unittest_dma_get_max_cpu_address();
of_unittest_parse_dma_ranges();