From 9965fa5c45f6babb3182886623f660cc725c5a62 Mon Sep 17 00:00:00 2001
From: Sughosh Ganu <sughosh.ganu@linaro.org>
Date: Thu, 22 May 2025 17:57:14 +0100
Subject: [PATCH 34/36] dt: Provide a way to remove non-compliant nodes and
 properties

Add a function which is registered to spy for a EVT_FT_FIXUP event,
and removes the non upstreamed nodes and properties from the
devicetree before it gets passed to the OS.

This allows removing entire nodes, or specific properties under nodes
from the devicetree. The required nodes and properties can be
registered for removal through the DT_NON_COMPLIANT_PURGE and
DT_NON_COMPLIANT_PURGE_LIST macros.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Upstream-Status: Denied [RFC: https://lore.kernel.org/u-boot/aca7e6fa-2dec-a7c5-e47e-84c5ffa6f9b7@gmx.de/T/#m16d14ee960427cc88066bdcdd76f0a26738bb66d]
---
 include/dt-structs.h | 11 +++++++
 lib/Makefile         |  1 +
 lib/dt_purge.c       | 73 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 85 insertions(+)
 create mode 100644 lib/dt_purge.c

diff --git a/include/dt-structs.h b/include/dt-structs.h
index fa1622cb1dc..f535c60471b 100644
--- a/include/dt-structs.h
+++ b/include/dt-structs.h
@@ -57,3 +57,14 @@ struct phandle_2_arg {
 #endif
 
 #endif
+
+struct dt_non_compliant_purge {
+	const char *node_path;
+	const char *prop;
+};
+
+#define DT_NON_COMPLIANT_PURGE(__name)	\
+	ll_entry_declare(struct dt_non_compliant_purge, __name, dt_purge)
+
+#define DT_NON_COMPLIANT_PURGE_LIST(__name)	\
+	ll_entry_declare_list(struct dt_non_compliant_purge, __name, dt_purge)
diff --git a/lib/Makefile b/lib/Makefile
index a7bc2f3134a..82b021562f1 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -70,6 +70,7 @@ endif
 obj-$(CONFIG_$(PHASE_)CRC8) += crc8.o
 obj-$(CONFIG_$(PHASE_)CRC16) += crc16.o
 obj-$(CONFIG_$(PHASE_)CRC16) += crc16-ccitt.o
+obj-y += dt_purge.o
 
 obj-y += crypto/
 
diff --git a/lib/dt_purge.c b/lib/dt_purge.c
new file mode 100644
index 00000000000..abae7c04fc7
--- /dev/null
+++ b/lib/dt_purge.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023, Linaro Limited
+ */
+
+#include <dt-structs.h>
+#include <event.h>
+#include <linker_lists.h>
+
+#include <linux/libfdt.h>
+
+/**
+ * dt_non_compliant_purge() -	Remove non-upstreamed nodes and properties
+ *				from the DT
+ * @ctx: Context for event
+ * @event: Event to process
+ *
+ * Iterate through an array of DT nodes and properties, and remove them
+ * from the device-tree before the DT gets handed over to the kernel.
+ * These are nodes and properties which do not have upstream bindings
+ * and need to be purged before being handed over to the kernel.
+ *
+ * If both the node and property are specified, delete the property. If
+ * only the node is specified, delete the entire node, including it's
+ * subnodes, if any.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+static int dt_non_compliant_purge(void *ctx, struct event *event)
+{
+	int nodeoff = 0;
+	int err = 0;
+	void *fdt;
+	const struct event_ft_fixup *fixup = &event->data.ft_fixup;
+	struct dt_non_compliant_purge *purge_entry;
+	struct dt_non_compliant_purge *purge_start =
+		ll_entry_start(struct dt_non_compliant_purge, dt_purge);
+	int nentries = ll_entry_count(struct dt_non_compliant_purge, dt_purge);
+
+	if (fixup->images)
+		return 0;
+
+	fdt = fixup->tree.fdt;
+	for (purge_entry = purge_start; purge_entry != purge_start + nentries;
+	     purge_entry++) {
+		nodeoff = fdt_path_offset(fdt, purge_entry->node_path);
+		if (nodeoff < 0) {
+			log_debug("Error (%d) getting node offset for %s\n",
+				  nodeoff, purge_entry->node_path);
+			continue;
+		}
+
+		if (purge_entry->prop) {
+			err = fdt_delprop(fdt, nodeoff, purge_entry->prop);
+			if (err < 0 && err != -FDT_ERR_NOTFOUND) {
+				log_debug("Error (%d) deleting %s\n",
+					  err, purge_entry->prop);
+				goto out;
+			}
+		} else {
+			err = fdt_del_node(fdt, nodeoff);
+			if (err) {
+				log_debug("Error (%d) trying to delete node %s\n",
+					  err, purge_entry->node_path);
+				goto out;
+			}
+		}
+	}
+
+out:
+	return err;
+}
+EVENT_SPY_FULL(EVT_FT_FIXUP, dt_non_compliant_purge);
-- 
2.25.1

