Devicetree
 help / color / mirror / Atom feed
* [PATCH v2 04/10] Introduce structured tag value definition
From: Herve Codina @ 2026-04-09 11:54 UTC (permalink / raw)
  To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
	linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
	Thomas Petazzoni, Herve Codina
In-Reply-To: <20260409115426.352214-1-herve.codina@bootlin.com>

The goal of structured tag values is to ease the introduction of new
tags in future releases with the capability for an already existing
release to ignore those structured tags. In order to do that data length
related to the unknown tag needs to be identified.

Also add a flag to tell an old release if this tag can be simply skipped
or must lead to an error.

Structured tag value is defined on 32bit and is defined as follow:

  Bits  | 31 | 30        | 29             28 | 27    0|
  ------+----+-----------+-------------------+--------+
  Fields| 1  | SKIP_SAFE | DATA_LEN_ENCODING | TAG_ID |
  ------+----+-----------+-------------------+--------+

Bit 31 is always set to 1 to identify a structured tag value.

Bit 30 (SKIP_SAFE) is set to 1 if the tag can be safely ignored when its
TAG_ID value is not a known value (unknown tag). If the SKIP_SAFE bit is
set to 0 this tag must not be ignored and an error should be reported
when its TAG_ID value is not a known value (unknown tag).

Bits 29..28 (DATA_LEN_ENCODING) indicates the length of the data related
to the tag. Following values are possible:
  - 0b00: No data.
          The tag is followed by the next tag value.

  - 0b01: 1 cell data
          The tag is followed by a 1 cell (u32) data. The next tag is
          available after this cell.

  - 0b10: 2 cells data
          The tag is followed by a 2 cells (2 * u32) data. The next tag
          is available after those two cells.

  - 0b11: Data length encoding
          The tag is followed by a cell (u32) indicating the size of the
          data. This size is given in bytes. Data are available right
          after this cell.

          The next tag is available after the data. Padding is present
          after the data in order to have the next tag aligned on 32bits.
          This padding is not included in the size of the data.

Bits 27..0 (TAG_ID) is the tag identifier defining a specific tag.

Introduce the structured tag values definition and some specific tags
reserved for tests based on this structure definition.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 libfdt/fdt.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index a07abfc..e6f75e7 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -49,6 +49,7 @@ struct fdt_property {
 
 #define FDT_MAGIC	0xd00dfeed	/* 4: version, 4: total size */
 #define FDT_TAGSIZE	sizeof(fdt32_t)
+#define FDT_CELLSIZE	sizeof(fdt32_t)
 
 #define FDT_BEGIN_NODE	0x1		/* Start node: full name */
 #define FDT_END_NODE	0x2		/* End node */
@@ -57,6 +58,28 @@ struct fdt_property {
 #define FDT_NOP		0x4		/* nop */
 #define FDT_END		0x9
 
+/* Tag values flags */
+#define FDT_TAG_STRUCTURED	(1<<31)
+#define FDT_TAG_SKIP_SAFE	(1<<30)
+#define FDT_TAG_DATA_MASK	(3<<28)
+#define FDT_TAG_DATA_NONE	(0<<28)
+#define FDT_TAG_DATA_1CELL	(1<<28)
+#define FDT_TAG_DATA_2CELLS	(2<<28)
+#define FDT_TAG_DATA_VARLEN	(3<<28)
+
+#define FDT_TAG_NO_SKIP(tag_data, tag_id) \
+		(FDT_TAG_STRUCTURED | tag_data | tag_id)
+
+#define FDT_TAG_CAN_SKIP(tag_data, tag_id) \
+		(FDT_TAG_STRUCTURED | FDT_TAG_SKIP_SAFE | tag_data | tag_id)
+
+/* Tests reserved tags */
+#define FDT_TEST_NONE_CAN_SKIP		FDT_TAG_CAN_SKIP(FDT_TAG_DATA_NONE, 0)
+#define FDT_TEST_1CELL_CAN_SKIP		FDT_TAG_CAN_SKIP(FDT_TAG_DATA_1CELL, 0)
+#define FDT_TEST_2CELLS_CAN_SKIP	FDT_TAG_CAN_SKIP(FDT_TAG_DATA_2CELLS, 0)
+#define FDT_TEST_VARLEN_CAN_SKIP	FDT_TAG_CAN_SKIP(FDT_TAG_DATA_VARLEN, 0)
+#define FDT_TEST_NONE_NO_SKIP		FDT_TAG_NO_SKIP(FDT_TAG_DATA_NONE, 0)
+
 #define FDT_V1_SIZE	(7*sizeof(fdt32_t))
 #define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(fdt32_t))
 #define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(fdt32_t))
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 05/10] fdtdump: Handle unknown tags
From: Herve Codina @ 2026-04-09 11:54 UTC (permalink / raw)
  To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
	linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
	Thomas Petazzoni, Herve Codina
In-Reply-To: <20260409115426.352214-1-herve.codina@bootlin.com>

The structured tag value definition introduced recently gives the
ability to ignore unknown tags without any error when they are read.

Add support for those structured tags in fdtdump and introduce a command
line option to dump unknown tags that should be ignored.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 fdtdump.c                              |  45 +++++++++-
 tests/dumptrees.c                      |   4 +-
 tests/run_tests.sh                     |  41 +++++++++
 tests/testdata.h                       |   2 +
 tests/trees.S                          | 116 +++++++++++++++++++++++++
 tests/unknown_tags_can_skip.dtb.expect |  29 +++++++
 6 files changed, 233 insertions(+), 4 deletions(-)
 create mode 100644 tests/unknown_tags_can_skip.dtb.expect

diff --git a/fdtdump.c b/fdtdump.c
index 0e7a265..7a8b278 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -44,7 +44,7 @@ static const char *tagname(uint32_t tag)
 #define dumpf(fmt, args...) \
 	do { if (debug) printf("// " fmt, ## args); } while (0)
 
-static void dump_blob(void *blob, bool debug)
+static void dump_blob(void *blob, bool debug, int dump_unknown)
 {
 	uintptr_t blob_off = (uintptr_t)blob;
 	struct fdt_header *bph = blob;
@@ -146,20 +146,55 @@ static void dump_blob(void *blob, bool debug)
 			continue;
 		}
 
+		if ((tag & FDT_TAG_STRUCTURED) && (tag & FDT_TAG_SKIP_SAFE)) {
+			sz = 0;
+			switch (tag & FDT_TAG_DATA_MASK) {
+			case FDT_TAG_DATA_NONE:
+				break;
+			case FDT_TAG_DATA_1CELL:
+				sz = FDT_CELLSIZE;
+				break;
+			case FDT_TAG_DATA_2CELLS:
+				sz = 2 * FDT_CELLSIZE;
+				break;
+			case FDT_TAG_DATA_VARLEN:
+				/* Get the length */
+				sz = fdt32_to_cpu(GET_CELL(p));
+				break;
+			}
+
+			if (dump_unknown) {
+				printf("%*s// Unknown tag ignored: 0x%08"PRIx32", data len %d",
+				       depth * shift, "", tag, sz);
+				if (dump_unknown > 1 && sz != 0) {
+					printf(" ");
+					for (i = 0; i < sz; i++)
+						printf("%02hhx", *(p + i));
+				}
+				printf("\n");
+			}
+
+			/* Skip the data bytes */
+			p = PALIGN(p + sz, 4);
+			continue;
+		}
+
 		die("** Unknown tag 0x%08"PRIx32"\n", tag);
 	}
 }
 
 /* Usage related data. */
 static const char usage_synopsis[] = "fdtdump [options] <file>";
-static const char usage_short_opts[] = "ds" USAGE_COMMON_SHORT_OPTS;
+static const char usage_short_opts[] = "dus" USAGE_COMMON_SHORT_OPTS;
 static struct option const usage_long_opts[] = {
 	{"debug",            no_argument, NULL, 'd'},
+	{"unknown",          no_argument, NULL, 'u'},
 	{"scan",             no_argument, NULL, 's'},
 	USAGE_COMMON_LONG_OPTS
 };
 static const char * const usage_opts_help[] = {
 	"Dump debug information while decoding the file",
+	"Dump unknown tags information while decoding the file (-uu to dump data)",
 	"Scan for an embedded fdt in file",
 	USAGE_COMMON_OPTS_HELP
 };
@@ -183,6 +218,7 @@ int main(int argc, char *argv[])
 	const char *file;
 	char *buf;
 	bool debug = false;
+	int dump_unknown = 0;
 	bool scan = false;
 	size_t len;
 
@@ -198,6 +234,9 @@ int main(int argc, char *argv[])
 		case 'd':
 			debug = true;
 			break;
+		case 'u':
+			dump_unknown++;
+			break;
 		case 's':
 			scan = true;
 			break;
@@ -242,7 +281,7 @@ int main(int argc, char *argv[])
 	} else if (!valid_header(buf, len))
 		die("%s: header is not valid\n", file);
 
-	dump_blob(buf, debug);
+	dump_blob(buf, debug, dump_unknown);
 
 	return 0;
 }
diff --git a/tests/dumptrees.c b/tests/dumptrees.c
index 08967b3..4732fff 100644
--- a/tests/dumptrees.c
+++ b/tests/dumptrees.c
@@ -25,7 +25,9 @@ static struct {
 	TREE(truncated_property), TREE(truncated_string),
 	TREE(truncated_memrsv),
 	TREE(two_roots),
-	TREE(named_root)
+	TREE(named_root),
+	TREE(unknown_tags_can_skip),
+	TREE(unknown_tags_no_skip)
 };
 
 #define NUM_TREES	(sizeof(trees) / sizeof(trees[0]))
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index f07092b..f2855dd 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -196,6 +196,40 @@ check_align () {
     )
 }
 
+# $1: f1 file
+# $2: f2 file
+check_diff () {
+    printf "diff $1 $2:	"
+    local f1="$1"
+    local f2="$2"
+    (
+        if diff $f1 $f2 >/dev/null; then
+            PASS
+        else
+            if [ -z "$QUIET_TEST" ]; then
+                echo "DIFF :-:"
+                diff -u $f1 $f2
+            fi
+            FAIL "Results differ from expected"
+        fi
+    )
+}
+
+# $1: dtb file
+# $2: out file
+wrap_fdtdump () {
+    printf "wrap_fdtdump -uu $1:	"
+    local dtb="$1"
+    local out="$2"
+    (
+        if $FDTDUMP -uu ${dtb} 2>/dev/null >${out}; then
+            PASS
+        else
+            FAIL
+        fi
+    )
+}
+
 run_dtc_test () {
     printf "dtc $*:	"
     base_run_test wrap_test $VALGRIND $DTC "$@"
@@ -1007,6 +1041,13 @@ utilfdt_tests () {
 
 fdtdump_tests () {
     run_fdtdump_test "$SRCDIR/fdtdump.dts"
+
+    base_run_test wrap_fdtdump unknown_tags_can_skip.dtb unknown_tags_can_skip.dtb.out
+    # Remove unneeded comments
+    sed -i '/^\/\/ [^U]/d' unknown_tags_can_skip.dtb.out
+    base_run_test check_diff unknown_tags_can_skip.dtb.out "$SRCDIR/unknown_tags_can_skip.dtb.expect"
+
+    run_wrap_error_test $FDTDUMP unknown_tags_no_skip.dtb
 }
 
 fdtoverlay_tests() {
diff --git a/tests/testdata.h b/tests/testdata.h
index fcebc2c..aef04ab 100644
--- a/tests/testdata.h
+++ b/tests/testdata.h
@@ -57,4 +57,6 @@ extern struct fdt_header truncated_string;
 extern struct fdt_header truncated_memrsv;
 extern struct fdt_header two_roots;
 extern struct fdt_header named_root;
+extern struct fdt_header unknown_tags_can_skip;
+extern struct fdt_header unknown_tags_no_skip;
 #endif /* ! __ASSEMBLER__ */
diff --git a/tests/trees.S b/tests/trees.S
index 4db2b9b..ef9a175 100644
--- a/tests/trees.S
+++ b/tests/trees.S
@@ -328,3 +328,119 @@ named_root_strings:
 named_root_strings_end:
 
 named_root_end:
+
+
+	/* Tree with "unknown" tags that can be skipped
+	 * Use a really future dtb version to check version downgrade on
+	 * modification.
+	 */
+	treehdr_vers	unknown_tags_can_skip 0xffffffff 0x10
+	empty_rsvmap	unknown_tags_can_skip
+
+unknown_tags_can_skip_struct:
+	fdtlong	FDT_TEST_1CELL_CAN_SKIP
+	fdtlong	0x1
+
+	beginn	""
+		fdtlong	FDT_TEST_NONE_CAN_SKIP
+
+		propu32	unknown_tags_can_skip, prop_int, 0x3201
+
+		fdtlong	FDT_TEST_1CELL_CAN_SKIP
+		fdtlong	0x110
+
+		propstr	unknown_tags_can_skip, prop_str, "abcd"
+
+		fdtlong	FDT_TEST_2CELLS_CAN_SKIP
+		fdtlong	0x120
+		fdtlong	0x121
+
+		fdtlong	FDT_TEST_VARLEN_CAN_SKIP
+		fdtlong	3
+		.byte 0x10
+		.byte 0x11
+		.byte 0x12
+		.byte 0 /* padding */
+
+		beginn	"subnode1"
+			propu64	unknown_tags_can_skip, prop_int, 0x6401, 0x6402
+			fdtlong	FDT_TEST_NONE_CAN_SKIP
+		endn
+
+		beginn	"subnode2"
+			fdtlong	FDT_TEST_1CELL_CAN_SKIP
+			fdtlong	0x121
+			propu64	unknown_tags_can_skip, prop_int1, 0x64020, 0x64021
+			fdtlong	FDT_TEST_2CELLS_CAN_SKIP
+			fdtlong	0x1220
+			fdtlong	0x1221
+			propu32	unknown_tags_can_skip, prop_int2, 0x32022
+			beginn	"subsubnode"
+				fdtlong	FDT_TEST_2CELLS_CAN_SKIP
+				fdtlong	0x1230
+				fdtlong	0x1231
+				propu64	unknown_tags_can_skip, prop_int, 0x64023, 0x64024
+			endn
+			fdtlong	FDT_TEST_VARLEN_CAN_SKIP
+			fdtlong 3
+			.byte	0x21
+			.byte	0x22
+			.byte	0x23
+			.byte	0x0
+		endn
+
+		fdtlong	FDT_TEST_VARLEN_CAN_SKIP
+		fdtlong	5
+		.byte 0x31
+		.byte 0x32
+		.byte 0x33
+		.byte 0x34
+		.byte 0x35
+		.byte 0 /* padding */
+		.byte 0 /* padding */
+		.byte 0 /* padding */
+	endn
+
+	fdtlong	FDT_TEST_1CELL_CAN_SKIP
+	fdtlong	0x2
+
+	fdtlong	FDT_TEST_VARLEN_CAN_SKIP
+	fdtlong	2
+	.byte 0x40
+	.byte 0x41
+	.byte 0 /* padding */
+	.byte 0 /* padding */
+
+	fdtlong	FDT_END
+
+unknown_tags_can_skip_struct_end:
+
+unknown_tags_can_skip_strings:
+	string	unknown_tags_can_skip, prop_int, "prop-int"
+	string	unknown_tags_can_skip, prop_int1, "prop-int1"
+	string	unknown_tags_can_skip, prop_int2, "prop-int2"
+	string	unknown_tags_can_skip, prop_str, "prop-str"
+unknown_tags_can_skip_strings_end:
+
+unknown_tags_can_skip_end:
+
+
+	/* Tree with "unknown" tags that cannot be skipped */
+	treehdr	unknown_tags_no_skip
+	empty_rsvmap	unknown_tags_no_skip
+
+unknown_tags_no_skip_struct:
+	beginn	""
+	fdtlong	FDT_TEST_NONE_NO_SKIP
+		beginn	"subnode1"
+			propu64	unknown_tags_no_skip, prop_int, 1, 2
+		endn
+	endn
+	fdtlong	FDT_END
+unknown_tags_no_skip_struct_end:
+
+unknown_tags_no_skip_strings:
+	string	unknown_tags_no_skip, prop_int, "prop-int"
+unknown_tags_no_skip_strings_end:
+
+unknown_tags_no_skip_end:
diff --git a/tests/unknown_tags_can_skip.dtb.expect b/tests/unknown_tags_can_skip.dtb.expect
new file mode 100644
index 0000000..bf52e05
--- /dev/null
+++ b/tests/unknown_tags_can_skip.dtb.expect
@@ -0,0 +1,29 @@
+/dts-v1/;
+
+// Unknown tag ignored: 0xd0000000, data len 4 00000001
+/ {
+    // Unknown tag ignored: 0xc0000000, data len 0
+    prop-int = <0x00003201>;
+    // Unknown tag ignored: 0xd0000000, data len 4 00000110
+    prop-str = "abcd";
+    // Unknown tag ignored: 0xe0000000, data len 8 0000012000000121
+    // Unknown tag ignored: 0xf0000000, data len 3 101112
+    subnode1 {
+        prop-int = <0x00006401 0x00006402>;
+        // Unknown tag ignored: 0xc0000000, data len 0
+    };
+    subnode2 {
+        // Unknown tag ignored: 0xd0000000, data len 4 00000121
+        prop-int1 = <0x00064020 0x00064021>;
+        // Unknown tag ignored: 0xe0000000, data len 8 0000122000001221
+        prop-int2 = <0x00032022>;
+        subsubnode {
+            // Unknown tag ignored: 0xe0000000, data len 8 0000123000001231
+            prop-int = <0x00064023 0x00064024>;
+        };
+        // Unknown tag ignored: 0xf0000000, data len 3 212223
+    };
+    // Unknown tag ignored: 0xf0000000, data len 5 3132333435
+};
+// Unknown tag ignored: 0xd0000000, data len 4 00000002
+// Unknown tag ignored: 0xf0000000, data len 2 4041
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 06/10] flattree: Handle unknown tags
From: Herve Codina @ 2026-04-09 11:54 UTC (permalink / raw)
  To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
	linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
	Thomas Petazzoni, Herve Codina
In-Reply-To: <20260409115426.352214-1-herve.codina@bootlin.com>

The structured tag value definition introduced recently gives the
ability to ignore unknown tags without any error when they are read.

Handle those structured tag.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 flattree.c                                 | 65 ++++++++++++++++++++--
 tests/run_tests.sh                         |  5 ++
 tests/unknown_tags_can_skip.dtb.dts.expect | 19 +++++++
 3 files changed, 84 insertions(+), 5 deletions(-)
 create mode 100644 tests/unknown_tags_can_skip.dtb.dts.expect

diff --git a/flattree.c b/flattree.c
index f3b698c..88dbfa7 100644
--- a/flattree.c
+++ b/flattree.c
@@ -579,7 +579,8 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len)
 	if ((inb->ptr + len) > inb->limit)
 		die("Premature end of data parsing flat device tree\n");
 
-	memcpy(p, inb->ptr, len);
+	if (p)
+		memcpy(p, inb->ptr, len);
 
 	inb->ptr += len;
 }
@@ -604,6 +605,61 @@ static void flat_realign(struct inbuf *inb, int align)
 		die("Premature end of data parsing flat device tree\n");
 }
 
+static bool flat_skip_unknown_tag(struct inbuf *inb, uint32_t tag)
+{
+	uint32_t lng;
+
+	if (!(tag & FDT_TAG_STRUCTURED) || !(tag & FDT_TAG_SKIP_SAFE))
+		return false;
+
+	switch (tag & FDT_TAG_DATA_MASK) {
+	case FDT_TAG_DATA_NONE:
+		break;
+
+	case FDT_TAG_DATA_1CELL:
+		flat_read_word(inb);
+		break;
+
+	case FDT_TAG_DATA_2CELLS:
+		flat_read_word(inb);
+		flat_read_word(inb);
+		break;
+
+	case FDT_TAG_DATA_VARLEN:
+		/* Get the length */
+		lng = flat_read_word(inb);
+
+		/* Skip the following length bytes */
+		flat_read_chunk(inb, NULL, lng);
+
+		flat_realign(inb, sizeof(uint32_t));
+		break;
+	}
+
+	return true;
+}
+
+static uint32_t flat_read_tag(struct inbuf *inb)
+{
+	uint32_t tag;
+
+	do {
+		tag = flat_read_word(inb);
+		switch (tag) {
+		case FDT_BEGIN_NODE:
+		case FDT_END_NODE:
+		case FDT_PROP:
+		case FDT_NOP:
+		case FDT_END:
+			return tag;
+		default:
+			break;
+		}
+	} while (flat_skip_unknown_tag(inb, tag));
+
+	die("Cannot skip unknown tag 0x%08x\n", tag);
+}
+
 static const char *flat_read_string(struct inbuf *inb)
 {
 	int len = 0;
@@ -750,7 +806,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
 		struct property *prop;
 		struct node *child;
 
-		val = flat_read_word(dtbuf);
+		val = flat_read_tag(dtbuf);
 		switch (val) {
 		case FDT_PROP:
 			if (node->children)
@@ -905,14 +961,13 @@ struct dt_info *dt_from_blob(const char *fname)
 
 	reservelist = flat_read_mem_reserve(&memresvbuf);
 
-	val = flat_read_word(&dtbuf);
-
+	val = flat_read_tag(&dtbuf);
 	if (val != FDT_BEGIN_NODE)
 		die("Device tree blob doesn't begin with FDT_BEGIN_NODE (begins with 0x%08x)\n", val);
 
 	tree = unflatten_tree(&dtbuf, &strbuf, "", flags);
 
-	val = flat_read_word(&dtbuf);
+	val = flat_read_tag(&dtbuf);
 	if (val != FDT_END)
 		die("Device tree blob doesn't end with FDT_END\n");
 
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index f2855dd..d147011 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -881,6 +881,11 @@ dtc_tests () {
 
     # Tests for overlay/plugin generation
     dtc_overlay_tests
+
+    # Tests with "unknown tags"
+    run_dtc_test -I dtb -O dts -o unknown_tags_can_skip.dtb.dts unknown_tags_can_skip.dtb
+    base_run_test check_diff unknown_tags_can_skip.dtb.dts "$SRCDIR/unknown_tags_can_skip.dtb.dts.expect"
+    run_wrap_error_test $DTC -I dtb -O dts -o unknown_tags_no_skip.dtb.dts unknown_tags_no_skip.dtb
 }
 
 cmp_tests () {
diff --git a/tests/unknown_tags_can_skip.dtb.dts.expect b/tests/unknown_tags_can_skip.dtb.dts.expect
new file mode 100644
index 0000000..a11ee57
--- /dev/null
+++ b/tests/unknown_tags_can_skip.dtb.dts.expect
@@ -0,0 +1,19 @@
+/dts-v1/;
+
+/ {
+	prop-int = <0x3201>;
+	prop-str = "abcd";
+
+	subnode1 {
+		prop-int = <0x6401 0x6402>;
+	};
+
+	subnode2 {
+		prop-int1 = <0x64020 0x64021>;
+		prop-int2 = <0x32022>;
+
+		subsubnode {
+			prop-int = <0x64023 0x64024>;
+		};
+	};
+};
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 07/10] libfdt: Handle unknown tags in fdt_next_tag()
From: Herve Codina @ 2026-04-09 11:54 UTC (permalink / raw)
  To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
	linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
	Thomas Petazzoni, Herve Codina
In-Reply-To: <20260409115426.352214-1-herve.codina@bootlin.com>

The structured tag value definition introduced recently gives the
ability to ignore unknown tags without any error when they are read.

libfdt uses fdt_next_tag() to get a tag.

Filtering out tags that should be ignored in fdt_next_tag() allows to
have the filtering done globally and allows, in future releases, to have
a central place to add new known tags that should not be filtered out.

An already known tag exists with the meaning of "just ignore". This tag
is FDT_NOP. fdt_next_tag() callers already handle the FDT_NOP tag.

Avoid unneeded modification at callers side and use a fake FDT_NOP tag
when an unknown tag that should be ignored is encountered.

Add also fdt_next_tag_() internal function for callers who need to know
if the FDT_NOP tag returned is a real FDT_NOP or a fake FDT_NOP due to
an unknown tag.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 libfdt/fdt.c             | 75 ++++++++++++++++++++++++++++++++++++++--
 libfdt/libfdt_internal.h |  3 ++
 tests/run_tests.sh       |  9 +++--
 3 files changed, 83 insertions(+), 4 deletions(-)

diff --git a/libfdt/fdt.c b/libfdt/fdt.c
index fb4faba..cce1373 100644
--- a/libfdt/fdt.c
+++ b/libfdt/fdt.c
@@ -167,7 +167,7 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
 	return fdt_offset_ptr_(fdt, offset);
 }
 
-uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+static uint32_t fdt_next_tag_all(const void *fdt, int startoffset, int *nextoffset)
 {
 	const fdt32_t *tagp, *lenp;
 	uint32_t tag, len, sum;
@@ -218,7 +218,37 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
 		break;
 
 	default:
-		return FDT_END;
+		if (!(tag & FDT_TAG_STRUCTURED) || !(tag & FDT_TAG_SKIP_SAFE))
+			return FDT_END;
+
+		switch (tag & FDT_TAG_DATA_MASK) {
+		case FDT_TAG_DATA_NONE:
+			break;
+		case FDT_TAG_DATA_1CELL:
+			offset += FDT_CELLSIZE;
+			break;
+		case FDT_TAG_DATA_2CELLS:
+			offset += 2 * FDT_CELLSIZE;
+			break;
+		case FDT_TAG_DATA_VARLEN:
+			/* Get the length */
+			lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+			if (!can_assume(VALID_DTB) && !lenp)
+				return FDT_END; /* premature end */
+			len = fdt32_to_cpu(*lenp);
+			/*
+			 * Skip the cell encoding the length and the
+			 * following length bytes
+			 */
+			len += sizeof(*lenp);
+			sum = len + offset;
+			if (!can_assume(VALID_DTB) &&
+			    (sum >= INT_MAX || sum < (uint32_t) offset))
+				return FDT_END; /* premature end */
+
+			offset += len;
+			break;
+		}
 	}
 
 	if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
@@ -228,6 +258,47 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
 	return tag;
 }
 
+static bool fdt_is_unknown_tag(uint32_t tag)
+{
+	switch (tag) {
+	case FDT_BEGIN_NODE:
+	case FDT_END_NODE:
+	case FDT_PROP:
+	case FDT_NOP:
+	case FDT_END:
+		return false;
+	default:
+		break;
+	}
+	return true;
+}
+
+uint32_t fdt_next_tag_(const void *fdt, int startoffset, int *nextoffset, bool *is_unknown)
+{
+	uint32_t tag;
+	bool unknown = false;
+
+	/* Retrieve next tag */
+	tag = fdt_next_tag_all(fdt, startoffset, nextoffset);
+	if (tag == FDT_END)
+		goto end;
+
+	if (fdt_is_unknown_tag(tag)) {
+		unknown = true;
+		/* Use a known tag that should be skipped by the caller */
+		tag = FDT_NOP;
+	}
+end:
+	if (is_unknown)
+		*is_unknown = unknown;
+	return tag;
+}
+
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+	return fdt_next_tag_(fdt, startoffset, nextoffset, NULL);
+}
+
 int fdt_check_node_offset_(const void *fdt, int offset)
 {
 	if (!can_assume(VALID_INPUT)
diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h
index 4c15264..c1ae306 100644
--- a/libfdt/libfdt_internal.h
+++ b/libfdt/libfdt_internal.h
@@ -20,6 +20,9 @@ int32_t fdt_ro_probe_(const void *fdt);
 		}							\
 	}
 
+uint32_t fdt_next_tag_(const void *fdt, int startoffset, int *nextoffset,
+		       bool *is_unknown);
+
 int fdt_check_node_offset_(const void *fdt, int offset);
 int fdt_check_prop_offset_(const void *fdt, int offset);
 
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index d147011..48ac6fa 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -576,11 +576,12 @@ libfdt_tests () {
     run_test dtbs_equal_ordered cell-overflow.test.dtb cell-overflow-results.test.dtb
 
     # check full tests
-    for good in test_tree1.dtb; do
+    for good in test_tree1.dtb unknown_tags_can_skip.dtb; do
 	run_test check_full $good
     done
     for bad in truncated_property.dtb truncated_string.dtb \
-		truncated_memrsv.dtb two_roots.dtb named_root.dtb; do
+		truncated_memrsv.dtb two_roots.dtb named_root.dtb \
+		unknown_tags_no_skip.dtb; do
 	run_test check_full -n $bad
     done
 }
@@ -961,6 +962,10 @@ fdtget_tests () {
     run_fdtget_test "<the dead silence>" -tx \
 	-d "<the dead silence>" $dtb /randomnode doctor-who
     run_fdtget_test "<blink>" -tx -d "<blink>" $dtb /memory doctor-who
+
+    # test with unknown tags involved
+    run_fdtget_test "25601 25602" unknown_tags_can_skip.dtb /subnode1 prop-int
+    run_wrap_error_test $DTGET unknown_tags_no_skip.dtb /subnode1 prop-int
 }
 
 fdtput_tests () {
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 08/10] libfdt: Introduce fdt_ptr_offset_
From: Herve Codina @ 2026-04-09 11:54 UTC (permalink / raw)
  To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
	linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
	Thomas Petazzoni, Herve Codina
In-Reply-To: <20260409115426.352214-1-herve.codina@bootlin.com>

libfdt provides internal helpers to convert an offset to a pointer but
nothing to do the reverse operation.

Introduce the fdt_ptr_offset_() internal helper to convert a pointer to
an offset.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 libfdt/libfdt_internal.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h
index c1ae306..9fd0012 100644
--- a/libfdt/libfdt_internal.h
+++ b/libfdt/libfdt_internal.h
@@ -47,6 +47,11 @@ static inline void *fdt_offset_ptr_w_(void *fdt, int offset)
 	return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset);
 }
 
+static inline int fdt_ptr_offset_(const void *fdt, const void *ptr)
+{
+	return (const char *)ptr - (const char *)fdt_offset_ptr_(fdt, 0);
+}
+
 static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n)
 {
 	const struct fdt_reserve_entry *rsv_table =
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 09/10] libfdt: Handle unknown tags on dtb modifications
From: Herve Codina @ 2026-04-09 11:54 UTC (permalink / raw)
  To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
	linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
	Thomas Petazzoni, Herve Codina
In-Reply-To: <20260409115426.352214-1-herve.codina@bootlin.com>

The structured tag value definition introduced recently gives the
ability to ignore unknown tags without any error.

When the dtb is modified those unknown tags have to be taken into
account.

First, depending on the unknown tag location, the item associated with
the tag is identified:
  - An unknown tag located just after a FDT_BEGIN_NODE is related to the
    node.

  - An unknown tag located just after a FDT_PROP is related to the
    property.

  - An unknown tag out of any node (i.e located before the first
    FDT_BEGIN_NODE or after the last FDT_END_NODE) is a global tag
    related to the dtb itself.

Then, if we are allowed to write a dtb containing unknown tags, the
following rules are used:
  - When a property is modified, tags related to this property are
    removed and the dtb version is downgraded.

  - When a property is removed, tags related to this property are
    obviously removed. The dtb version is kept unchanged.

  - When a property or a node is added, obviously no unknown tags are
    added and the dtb version is kept unchanged.

  - When a node is removed, tags related to this node are obviously
    removed. The dtb version is kept unchanged.

  - Adding, removing or modifying a property is not considered as a node
    modification and so, those operations have no impacts on unknown
    tags related to the node. Those node related tags are kept unchanged.

  - The only modification considered as a node modification is setting
    its name. We consider that this operation has no impact on tags
    related to the node. Here also, those node related tags and the
    dtb version are kept unchanged.

  - Global (dtb related) unknown tags are kept unchanged regardless the
    modification done.

Implement those rules when a dtb is modified.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
---
 libfdt/fdt_rw.c                               | 118 +++++++++++++++++-
 tests/run_tests.sh                            |  50 ++++++++
 ...own_tags_can_skip.fdtput.test.dtb.0.expect |  31 +++++
 ...own_tags_can_skip.fdtput.test.dtb.1.expect |  35 ++++++
 ...own_tags_can_skip.fdtput.test.dtb.2.expect |  33 +++++
 ...own_tags_can_skip.fdtput.test.dtb.3.expect |  35 ++++++
 ...own_tags_can_skip.fdtput.test.dtb.4.expect |  34 +++++
 ...own_tags_can_skip.fdtput.test.dtb.5.expect |  32 +++++
 ...own_tags_can_skip.fdtput.test.dtb.6.expect |  27 ++++
 9 files changed, 394 insertions(+), 1 deletion(-)
 create mode 100644 tests/unknown_tags_can_skip.fdtput.test.dtb.0.expect
 create mode 100644 tests/unknown_tags_can_skip.fdtput.test.dtb.1.expect
 create mode 100644 tests/unknown_tags_can_skip.fdtput.test.dtb.2.expect
 create mode 100644 tests/unknown_tags_can_skip.fdtput.test.dtb.3.expect
 create mode 100644 tests/unknown_tags_can_skip.fdtput.test.dtb.4.expect
 create mode 100644 tests/unknown_tags_can_skip.fdtput.test.dtb.5.expect
 create mode 100644 tests/unknown_tags_can_skip.fdtput.test.dtb.6.expect

diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
index f5c28fc..a8f53b4 100644
--- a/libfdt/fdt_rw.c
+++ b/libfdt/fdt_rw.c
@@ -188,6 +188,60 @@ int fdt_del_mem_rsv(void *fdt, int n)
 	return fdt_splice_mem_rsv_(fdt, re, 1, 0);
 }
 
+static void fdt_nopify_area(void *fdt, int start_offset, int next_offset)
+{
+	int count = (next_offset - start_offset) / sizeof(fdt32_t);
+	fdt32_t fdt32_nop = cpu_to_fdt32(FDT_NOP);
+	fdt32_t *ptr;
+
+	ptr = fdt_offset_ptr_w_(fdt, start_offset);
+	while (count--)
+		*(ptr++) = fdt32_nop;
+};
+
+static int fdt_property_remove_unknown_tags(void *fdt,
+					    const struct fdt_property *prop,
+					    bool downgrade_version)
+{
+	int nextoffset, offset;
+	bool is_unknown;
+	uint32_t tag;
+
+	tag = fdt_next_tag(fdt, fdt_ptr_offset_(fdt, prop), &nextoffset);
+	if (tag == FDT_END)
+		return nextoffset;
+
+	/*
+	 * Look at all tags related to the current property. I.e. tags after the
+	 * current property and before either the next property, a sub-node  or
+	 * the end of current node
+	 */
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag_(fdt, offset, &nextoffset, &is_unknown);
+		if (tag == FDT_END)
+			return nextoffset;
+
+		/*
+		 * Unknown tags are returned as NOP. Force FDT_NOP to be really
+		 * present in the area to remove the unknown tag and its related
+		 * data. Also, as a tag is removed, downgrade the dtb version
+		 * if asked for.
+		 */
+		if (tag == FDT_NOP) {
+			if (is_unknown) {
+				if (downgrade_version)
+					fdt_downgrade_version(fdt);
+				fdt_nopify_area(fdt, offset, nextoffset);
+			}
+		}
+
+	} while ((tag != FDT_PROP) && (tag != FDT_BEGIN_NODE) &&
+		 (tag != FDT_END_NODE));
+
+	return 0;
+}
+
 static int fdt_resize_property_(void *fdt, int nodeoffset,
 				const char *name, int namelen,
 				int len, struct fdt_property **prop)
@@ -200,6 +254,14 @@ static int fdt_resize_property_(void *fdt, int nodeoffset,
 	if (!*prop)
 		return oldlen;
 
+	/*
+	 * The property is resized. Remove possible unknown tags related to the
+	 * property downgrading the dtb version.
+	 */
+	err = fdt_property_remove_unknown_tags(fdt, *prop, true);
+	if (err)
+		return err;
+
 	if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
 				      FDT_TAGALIGN(len))))
 		return err;
@@ -208,6 +270,29 @@ static int fdt_resize_property_(void *fdt, int nodeoffset,
 	return 0;
 }
 
+static int fdt_node_skip_unknown_tags(void *fdt, int next)
+{
+	int nextoffset = next;
+	int offset;
+	uint32_t tag;
+
+	/*
+	 * Skip all tags related to the current node. I.e. tags after the
+	 * current node and before either the next property, a sub-node or the
+	 * end of current node.
+	 */
+	do {
+		offset = nextoffset;
+		tag = fdt_next_tag(fdt, offset, &nextoffset);
+		if (tag == FDT_END)
+			return nextoffset;
+
+	} while ((tag != FDT_PROP) && (tag != FDT_BEGIN_NODE) &&
+		 (tag != FDT_END_NODE));
+
+	return offset;
+}
+
 static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
 			     int namelen, int len, struct fdt_property **prop)
 {
@@ -220,6 +305,15 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name,
 	if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
 		return nextoffset;
 
+	/*
+	 * nextoffset it at the first tag after the node.
+	 * Skip possible unknown tags related to the node in order to add the
+	 * property after those tags.
+	 */
+	nextoffset = fdt_node_skip_unknown_tags(fdt, nextoffset);
+	if (nextoffset < 0)
+		return nextoffset;
+
 	namestroff = fdt_find_add_string_(fdt, name, namelen, &allocated);
 	if (namestroff < 0)
 		return namestroff;
@@ -309,6 +403,14 @@ int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
 
 	prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
 	if (prop) {
+		/*
+		 * The property is going to be modified. Remove possible unknown
+		 * tags related to this property downgrading the dtb version.
+		 */
+		err = fdt_property_remove_unknown_tags(fdt, prop, true);
+		if (err)
+			return err;
+
 		newlen = len + oldlen;
 		err = fdt_splice_struct_(fdt, prop->data,
 					 FDT_TAGALIGN(oldlen),
@@ -331,6 +433,7 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
 {
 	struct fdt_property *prop;
 	int len, proplen;
+	int err;
 
 	FDT_RW_PROBE(fdt);
 
@@ -338,6 +441,14 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
 	if (!prop)
 		return len;
 
+	/*
+	 * The property is going to be removed. Remove also possible unknown
+	 * tags related to this property. Keep the dtb version unchanged.
+	 */
+	err = fdt_property_remove_unknown_tags(fdt, prop, false);
+	if (err)
+		return err;
+
 	proplen = sizeof(*prop) + FDT_TAGALIGN(len);
 	return fdt_splice_struct_(fdt, prop, proplen, 0);
 }
@@ -366,7 +477,12 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
 	else if (offset != -FDT_ERR_NOTFOUND)
 		return offset;
 
-	/* Try to place the new node after the parent's properties */
+	/*
+	 * Try to place the new node after the parent's properties and unknown
+	 * tags related to those properties.
+	 * Unknown tags are reported as FDT_NOP tags by fdt_next_tag.
+	 * Skipping FDT_NOP tags will correctly skip unknown tags.
+	 */
 	tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
 	/* the fdt_subnode_offset_namelen() should ensure this never hits */
 	if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE))
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 48ac6fa..1ba937d 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1043,6 +1043,56 @@ fdtput_tests () {
     run_wrap_error_test $DTPUT $dtb -d /chosen   non-existent-prop
 
     # TODO: Add tests for verbose mode?
+
+    # Modify a dtb containing some "unknown" tags that can be skipped
+    dtb=unknown_tags_can_skip.fdtput.test.dtb
+    cp unknown_tags_can_skip.dtb $dtb
+    base_run_test wrap_fdtdump $dtb $dtb.0.out
+    # Remove unneeded header fields (keep those related to versions)
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.0.out
+    base_run_test check_diff $dtb.0.out "$SRCDIR/$dtb.0.expect"
+
+    run_fdtput_test "vwxyz" $dtb / prop-str -ts "vwxyz"
+    base_run_test wrap_fdtdump $dtb $dtb.1.out
+    # Remove unneeded header fields (keep those related to versions)
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.1.out
+    base_run_test check_diff $dtb.1.out "$SRCDIR/$dtb.1.expect"
+
+    cp unknown_tags_can_skip.dtb $dtb
+    run_wrap_test $DTPUT $dtb -c /tst-fdtput
+    base_run_test wrap_fdtdump $dtb $dtb.2.out
+    # Remove unneeded header fields (keep those related to versions)
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.2.out
+    base_run_test check_diff $dtb.2.out "$SRCDIR/$dtb.2.expect"
+    run_wrap_test $DTPUT $dtb -c /tst-fdtput/n1 /tst-fdtput/n2 /tst-fdtput/n3
+    run_wrap_test $DTPUT $dtb -r /tst-fdtput/n1 /tst-fdtput/n3
+    run_fdtget_test "n2" $dtb -l  /tst-fdtput
+    base_run_test wrap_fdtdump $dtb $dtb.3.out
+    # Remove unneeded header fields (keep those related to versions)
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.3.out
+    base_run_test check_diff $dtb.3.out "$SRCDIR/$dtb.3.expect"
+
+    cp unknown_tags_can_skip.dtb $dtb
+    run_wrap_test $DTPUT $dtb -d / prop-str
+    run_fdtget_test "prop-int" $dtb -p  /
+    base_run_test wrap_fdtdump $dtb $dtb.4.out
+    # Remove unneeded header fields (keep those related to versions)
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.4.out
+    base_run_test check_diff $dtb.4.out "$SRCDIR/$dtb.4.expect"
+
+    cp unknown_tags_can_skip.dtb $dtb
+    run_wrap_test $DTPUT $dtb /subnode2 prop-tst-fdtput -ts "Test fdtput"
+    base_run_test wrap_fdtdump $dtb $dtb.5.out
+    # Remove unneeded header fields (keep those related to versions)
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.5.out
+    base_run_test check_diff $dtb.5.out "$SRCDIR/$dtb.5.expect"
+
+    cp unknown_tags_can_skip.dtb $dtb
+    run_wrap_test $DTPUT $dtb -r /subnode2/subsubnode
+    base_run_test wrap_fdtdump $dtb $dtb.6.out
+    # Remove unneeded header fields (keep those related to versions)
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.6.out
+    base_run_test check_diff $dtb.6.out "$SRCDIR/$dtb.6.expect"
 }
 
 utilfdt_tests () {
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.0.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.0.expect
new file mode 100644
index 0000000..3cdf448
--- /dev/null
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.0.expect
@@ -0,0 +1,31 @@
+/dts-v1/;
+// version:		4294967295
+// last_comp_version:	16
+
+// Unknown tag ignored: 0xd0000000, data len 4 00000001
+/ {
+    // Unknown tag ignored: 0xc0000000, data len 0
+    prop-int = <0x00003201>;
+    // Unknown tag ignored: 0xd0000000, data len 4 00000110
+    prop-str = "abcd";
+    // Unknown tag ignored: 0xe0000000, data len 8 0000012000000121
+    // Unknown tag ignored: 0xf0000000, data len 3 101112
+    subnode1 {
+        prop-int = <0x00006401 0x00006402>;
+        // Unknown tag ignored: 0xc0000000, data len 0
+    };
+    subnode2 {
+        // Unknown tag ignored: 0xd0000000, data len 4 00000121
+        prop-int1 = <0x00064020 0x00064021>;
+        // Unknown tag ignored: 0xe0000000, data len 8 0000122000001221
+        prop-int2 = <0x00032022>;
+        subsubnode {
+            // Unknown tag ignored: 0xe0000000, data len 8 0000123000001231
+            prop-int = <0x00064023 0x00064024>;
+        };
+        // Unknown tag ignored: 0xf0000000, data len 3 212223
+    };
+    // Unknown tag ignored: 0xf0000000, data len 5 3132333435
+};
+// Unknown tag ignored: 0xd0000000, data len 4 00000002
+// Unknown tag ignored: 0xf0000000, data len 2 4041
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.1.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.1.expect
new file mode 100644
index 0000000..71f2d1c
--- /dev/null
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.1.expect
@@ -0,0 +1,35 @@
+/dts-v1/;
+// version:		17
+// last_comp_version:	16
+
+// Unknown tag ignored: 0xd0000000, data len 4 00000001
+/ {
+    // Unknown tag ignored: 0xc0000000, data len 0
+    prop-int = <0x00003201>;
+    // Unknown tag ignored: 0xd0000000, data len 4 00000110
+    prop-str = "vwxyz";
+    // [NOP]
+    // [NOP]
+    // [NOP]
+    // [NOP]
+    // [NOP]
+    // [NOP]
+    subnode1 {
+        prop-int = <0x00006401 0x00006402>;
+        // Unknown tag ignored: 0xc0000000, data len 0
+    };
+    subnode2 {
+        // Unknown tag ignored: 0xd0000000, data len 4 00000121
+        prop-int1 = <0x00064020 0x00064021>;
+        // Unknown tag ignored: 0xe0000000, data len 8 0000122000001221
+        prop-int2 = <0x00032022>;
+        subsubnode {
+            // Unknown tag ignored: 0xe0000000, data len 8 0000123000001231
+            prop-int = <0x00064023 0x00064024>;
+        };
+        // Unknown tag ignored: 0xf0000000, data len 3 212223
+    };
+    // Unknown tag ignored: 0xf0000000, data len 5 3132333435
+};
+// Unknown tag ignored: 0xd0000000, data len 4 00000002
+// Unknown tag ignored: 0xf0000000, data len 2 4041
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.2.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.2.expect
new file mode 100644
index 0000000..bd3a13b
--- /dev/null
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.2.expect
@@ -0,0 +1,33 @@
+/dts-v1/;
+// version:		17
+// last_comp_version:	16
+
+// Unknown tag ignored: 0xd0000000, data len 4 00000001
+/ {
+    // Unknown tag ignored: 0xc0000000, data len 0
+    prop-int = <0x00003201>;
+    // Unknown tag ignored: 0xd0000000, data len 4 00000110
+    prop-str = "abcd";
+    // Unknown tag ignored: 0xe0000000, data len 8 0000012000000121
+    // Unknown tag ignored: 0xf0000000, data len 3 101112
+    tst-fdtput {
+    };
+    subnode1 {
+        prop-int = <0x00006401 0x00006402>;
+        // Unknown tag ignored: 0xc0000000, data len 0
+    };
+    subnode2 {
+        // Unknown tag ignored: 0xd0000000, data len 4 00000121
+        prop-int1 = <0x00064020 0x00064021>;
+        // Unknown tag ignored: 0xe0000000, data len 8 0000122000001221
+        prop-int2 = <0x00032022>;
+        subsubnode {
+            // Unknown tag ignored: 0xe0000000, data len 8 0000123000001231
+            prop-int = <0x00064023 0x00064024>;
+        };
+        // Unknown tag ignored: 0xf0000000, data len 3 212223
+    };
+    // Unknown tag ignored: 0xf0000000, data len 5 3132333435
+};
+// Unknown tag ignored: 0xd0000000, data len 4 00000002
+// Unknown tag ignored: 0xf0000000, data len 2 4041
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.3.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.3.expect
new file mode 100644
index 0000000..237eb95
--- /dev/null
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.3.expect
@@ -0,0 +1,35 @@
+/dts-v1/;
+// version:		17
+// last_comp_version:	16
+
+// Unknown tag ignored: 0xd0000000, data len 4 00000001
+/ {
+    // Unknown tag ignored: 0xc0000000, data len 0
+    prop-int = <0x00003201>;
+    // Unknown tag ignored: 0xd0000000, data len 4 00000110
+    prop-str = "abcd";
+    // Unknown tag ignored: 0xe0000000, data len 8 0000012000000121
+    // Unknown tag ignored: 0xf0000000, data len 3 101112
+    tst-fdtput {
+        n2 {
+        };
+    };
+    subnode1 {
+        prop-int = <0x00006401 0x00006402>;
+        // Unknown tag ignored: 0xc0000000, data len 0
+    };
+    subnode2 {
+        // Unknown tag ignored: 0xd0000000, data len 4 00000121
+        prop-int1 = <0x00064020 0x00064021>;
+        // Unknown tag ignored: 0xe0000000, data len 8 0000122000001221
+        prop-int2 = <0x00032022>;
+        subsubnode {
+            // Unknown tag ignored: 0xe0000000, data len 8 0000123000001231
+            prop-int = <0x00064023 0x00064024>;
+        };
+        // Unknown tag ignored: 0xf0000000, data len 3 212223
+    };
+    // Unknown tag ignored: 0xf0000000, data len 5 3132333435
+};
+// Unknown tag ignored: 0xd0000000, data len 4 00000002
+// Unknown tag ignored: 0xf0000000, data len 2 4041
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.4.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.4.expect
new file mode 100644
index 0000000..8473040
--- /dev/null
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.4.expect
@@ -0,0 +1,34 @@
+/dts-v1/;
+// version:		17
+// last_comp_version:	16
+
+// Unknown tag ignored: 0xd0000000, data len 4 00000001
+/ {
+    // Unknown tag ignored: 0xc0000000, data len 0
+    prop-int = <0x00003201>;
+    // Unknown tag ignored: 0xd0000000, data len 4 00000110
+    // [NOP]
+    // [NOP]
+    // [NOP]
+    // [NOP]
+    // [NOP]
+    // [NOP]
+    subnode1 {
+        prop-int = <0x00006401 0x00006402>;
+        // Unknown tag ignored: 0xc0000000, data len 0
+    };
+    subnode2 {
+        // Unknown tag ignored: 0xd0000000, data len 4 00000121
+        prop-int1 = <0x00064020 0x00064021>;
+        // Unknown tag ignored: 0xe0000000, data len 8 0000122000001221
+        prop-int2 = <0x00032022>;
+        subsubnode {
+            // Unknown tag ignored: 0xe0000000, data len 8 0000123000001231
+            prop-int = <0x00064023 0x00064024>;
+        };
+        // Unknown tag ignored: 0xf0000000, data len 3 212223
+    };
+    // Unknown tag ignored: 0xf0000000, data len 5 3132333435
+};
+// Unknown tag ignored: 0xd0000000, data len 4 00000002
+// Unknown tag ignored: 0xf0000000, data len 2 4041
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.5.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.5.expect
new file mode 100644
index 0000000..f7806f4
--- /dev/null
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.5.expect
@@ -0,0 +1,32 @@
+/dts-v1/;
+// version:		17
+// last_comp_version:	16
+
+// Unknown tag ignored: 0xd0000000, data len 4 00000001
+/ {
+    // Unknown tag ignored: 0xc0000000, data len 0
+    prop-int = <0x00003201>;
+    // Unknown tag ignored: 0xd0000000, data len 4 00000110
+    prop-str = "abcd";
+    // Unknown tag ignored: 0xe0000000, data len 8 0000012000000121
+    // Unknown tag ignored: 0xf0000000, data len 3 101112
+    subnode1 {
+        prop-int = <0x00006401 0x00006402>;
+        // Unknown tag ignored: 0xc0000000, data len 0
+    };
+    subnode2 {
+        // Unknown tag ignored: 0xd0000000, data len 4 00000121
+        prop-tst-fdtput = "Test fdtput";
+        prop-int1 = <0x00064020 0x00064021>;
+        // Unknown tag ignored: 0xe0000000, data len 8 0000122000001221
+        prop-int2 = <0x00032022>;
+        subsubnode {
+            // Unknown tag ignored: 0xe0000000, data len 8 0000123000001231
+            prop-int = <0x00064023 0x00064024>;
+        };
+        // Unknown tag ignored: 0xf0000000, data len 3 212223
+    };
+    // Unknown tag ignored: 0xf0000000, data len 5 3132333435
+};
+// Unknown tag ignored: 0xd0000000, data len 4 00000002
+// Unknown tag ignored: 0xf0000000, data len 2 4041
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.6.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.6.expect
new file mode 100644
index 0000000..029f3b4
--- /dev/null
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.6.expect
@@ -0,0 +1,27 @@
+/dts-v1/;
+// version:		17
+// last_comp_version:	16
+
+// Unknown tag ignored: 0xd0000000, data len 4 00000001
+/ {
+    // Unknown tag ignored: 0xc0000000, data len 0
+    prop-int = <0x00003201>;
+    // Unknown tag ignored: 0xd0000000, data len 4 00000110
+    prop-str = "abcd";
+    // Unknown tag ignored: 0xe0000000, data len 8 0000012000000121
+    // Unknown tag ignored: 0xf0000000, data len 3 101112
+    subnode1 {
+        prop-int = <0x00006401 0x00006402>;
+        // Unknown tag ignored: 0xc0000000, data len 0
+    };
+    subnode2 {
+        // Unknown tag ignored: 0xd0000000, data len 4 00000121
+        prop-int1 = <0x00064020 0x00064021>;
+        // Unknown tag ignored: 0xe0000000, data len 8 0000122000001221
+        prop-int2 = <0x00032022>;
+        // Unknown tag ignored: 0xf0000000, data len 3 212223
+    };
+    // Unknown tag ignored: 0xf0000000, data len 5 3132333435
+};
+// Unknown tag ignored: 0xd0000000, data len 4 00000002
+// Unknown tag ignored: 0xf0000000, data len 2 4041
-- 
2.53.0


^ permalink raw reply related

* [PATCH v2 10/10] Introduce v18 dtb version
From: Herve Codina @ 2026-04-09 11:54 UTC (permalink / raw)
  To: David Gibson, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Ayush Singh, Geert Uytterhoeven, devicetree-compiler, devicetree,
	linux-kernel, devicetree-spec, Hui Pu, Ian Ray, Luca Ceresoli,
	Thomas Petazzoni, Herve Codina
In-Reply-To: <20260409115426.352214-1-herve.codina@bootlin.com>

This v18 version will add support for
  - Structured tags.
    Those tags value definition will allow "old" libfdt, dtc and other
    tools to skip unknown tags if encountered in future dtb version.

    libfdt, dtc and other tools implementing version v18 will be able to
    skip unknown tags available in dtbd generated with later version of
    dtc.

  - dt_flags header field.
    For now this flag field is set to 0. It is a placeholder for future
    dtb version and could be used to store some dtb related information
    such as the kind of dtb. For instance, the future addons format will
    use this field to clearly identify that the dtb is an addon dtb.

  - last_comp_version_w header field.
    This field is similar to last_comp_version but for writing.
    It contains the lowest version of the devicetree data structure with
    which the version used can safely perform modifications (taking into
    account following rules related to unknown tags).
    If this lowest version is greater than the last known supported
    version, modification are simply forbidden and lead to a
    FDT_ERR_BADVERSION error.

For modification, when an unknown tag that can be skipped is involved
and last_comp_version_w allows modifications, the following rules
apply:
  - When a property is modified, tags related to this property are
    removed and the dtb version is downgraded.

  - When a property is removed, tags related to this property are
    obviously removed. The dtb version is kept unchanged.

  - When a property or a node is added, obviously no unknown tags are
    added and the dtb version is kept unchanged.

  - When a node is removed, tags related to this node are obviously
    removed. The dtb version is kept unchanged.

  - Adding, removing or modifying a property is not considered as a node
    modification and so, those operations have no impacts on unknown
    tags related to the node. Those node related tags are kept
    unchanged.

  - The only modification considered as a node modification is setting
    its name. We consider that this operation has no impact on tags
    related to the node. Here also, those node related tags and the dtb
    version are kept unchanged.

  - Global (dtb related) unknown tags are kept unchanged regardless the
    modification done.

In all cases, if unknown tags are not involved in a modification, the
dtb version is not downgraded when the modification is made.

It is worth noting that with this v18 version, the dtb version is not
downgraded for any modification but only when unknown tags are removed
due to a property modification. In v17 or older version any modification
led to a dtb version downgrade.

Signed-off-by: Herve Codina <herve.codina@bootlin.com>
---
 dtc.h                                         |  2 +-
 fdtdump.c                                     |  8 +++-
 flattree.c                                    | 37 +++++++++++++++----
 libfdt/fdt.h                                  |  5 +++
 libfdt/fdt_rw.c                               | 20 +++++++---
 libfdt/fdt_sw.c                               |  3 ++
 libfdt/libfdt.h                               |  7 +++-
 pylibfdt/libfdt.i                             | 18 +++++++++
 tests/dumptrees.c                             |  3 +-
 tests/pylibfdt_tests.py                       | 10 +++--
 tests/run_tests.sh                            | 26 +++++++++----
 tests/testdata.h                              |  1 +
 tests/testutils.c                             |  2 +-
 tests/trees.S                                 | 29 +++++++++++++--
 ...own_tags_can_skip.fdtput.test.dtb.0.expect |  1 +
 ...own_tags_can_skip.fdtput.test.dtb.1.expect |  3 +-
 ...own_tags_can_skip.fdtput.test.dtb.2.expect |  3 +-
 ...own_tags_can_skip.fdtput.test.dtb.3.expect |  3 +-
 ...own_tags_can_skip.fdtput.test.dtb.4.expect |  3 +-
 ...own_tags_can_skip.fdtput.test.dtb.5.expect |  3 +-
 ...own_tags_can_skip.fdtput.test.dtb.6.expect |  3 +-
 21 files changed, 152 insertions(+), 38 deletions(-)

diff --git a/dtc.h b/dtc.h
index 473552e..f0c2cde 100644
--- a/dtc.h
+++ b/dtc.h
@@ -29,7 +29,7 @@
 #define debug(...)
 #endif
 
-#define DEFAULT_FDT_VERSION	17
+#define DEFAULT_FDT_VERSION	18
 
 /*
  * Command line options
diff --git a/fdtdump.c b/fdtdump.c
index 7a8b278..5994e1d 100644
--- a/fdtdump.c
+++ b/fdtdump.c
@@ -18,7 +18,7 @@
 #include "util.h"
 
 #define FDT_MAGIC_SIZE	4
-#define MAX_VERSION 17U
+#define MAX_VERSION 18U
 
 #define ALIGN(x, a)	(((x) + ((a) - 1)) & ~((a) - 1))
 #define PALIGN(p, a)	((void *)(ALIGN((uintptr_t)(p), (a))))
@@ -86,6 +86,12 @@ static void dump_blob(void *blob, bool debug, int dump_unknown)
 	if (version >= 17)
 		printf("// size_dt_struct:\t0x%"PRIx32"\n",
 		       fdt32_to_cpu(bph->size_dt_struct));
+	if (version >= 18) {
+		printf("// dt_flags:\t\t0x%"PRIx32"\n",
+		       fdt32_to_cpu(bph->dt_flags));
+		printf("// last_comp_version_w:\t%"PRIu32"\n",
+		       fdt32_to_cpu(bph->last_comp_version_w));
+	}
 	printf("\n");
 
 	for (i = 0; ; i++) {
diff --git a/flattree.c b/flattree.c
index 88dbfa7..ff57fc5 100644
--- a/flattree.c
+++ b/flattree.c
@@ -13,23 +13,29 @@
 #define FTF_STRTABSIZE	0x10
 #define FTF_STRUCTSIZE	0x20
 #define FTF_NOPS	0x40
+#define FTF_DTFLAGS	0x80
+#define FTF_LCVERSW	0x100
 
 static struct version_info {
 	int version;
 	int last_comp_version;
+	int last_comp_version_w;
 	int hdr_size;
 	int flags;
 } version_table[] = {
-	{1, 1, FDT_V1_SIZE,
+	{1, 1, 0, FDT_V1_SIZE,
 	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS},
-	{2, 1, FDT_V2_SIZE,
+	{2, 1, 0, FDT_V2_SIZE,
 	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID},
-	{3, 1, FDT_V3_SIZE,
+	{3, 1, 0, FDT_V3_SIZE,
 	 FTF_FULLPATH|FTF_VARALIGN|FTF_NAMEPROPS|FTF_BOOTCPUID|FTF_STRTABSIZE},
-	{16, 16, FDT_V3_SIZE,
+	{16, 16, 0, FDT_V3_SIZE,
 	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_NOPS},
-	{17, 16, FDT_V17_SIZE,
+	{17, 16, 0, FDT_V17_SIZE,
 	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS},
+	{18, 16, 17, FDT_V18_SIZE,
+	 FTF_BOOTCPUID|FTF_STRTABSIZE|FTF_STRUCTSIZE|FTF_NOPS|FTF_DTFLAGS|
+	 FTF_LCVERSW},
 };
 
 struct emitter {
@@ -314,7 +320,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist,
 static void make_fdt_header(struct fdt_header *fdt,
 			    struct version_info *vi,
 			    int reservesize, int dtsize, int strsize,
-			    int boot_cpuid_phys)
+			    int boot_cpuid_phys, uint32_t dt_flags)
 {
 	int reserve_off;
 
@@ -341,6 +347,10 @@ static void make_fdt_header(struct fdt_header *fdt,
 		fdt->size_dt_strings = cpu_to_fdt32(strsize);
 	if (vi->flags & FTF_STRUCTSIZE)
 		fdt->size_dt_struct = cpu_to_fdt32(dtsize);
+	if (vi->flags & FTF_DTFLAGS)
+		fdt->dt_flags = cpu_to_fdt32(dt_flags);
+	if (vi->flags & FTF_LCVERSW)
+		fdt->last_comp_version_w = cpu_to_fdt32(vi->last_comp_version_w);
 }
 
 void dt_to_blob(FILE *f, struct dt_info *dti, int version)
@@ -368,7 +378,7 @@ void dt_to_blob(FILE *f, struct dt_info *dti, int version)
 
 	/* Make header */
 	make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
-			dti->boot_cpuid_phys);
+			dti->boot_cpuid_phys, 0);
 
 	/*
 	 * If the user asked for more space than is used, adjust the totalsize.
@@ -499,6 +509,16 @@ void dt_to_asm(FILE *f, struct dt_info *dti, int version)
 			symprefix, symprefix);
 	}
 
+	if (vi->flags & FTF_DTFLAGS) {
+		fprintf(f, "\t/* dt_flags */\n");
+		asm_emit_cell(f, 0);
+	}
+
+	if (vi->flags & FTF_LCVERSW) {
+		fprintf(f, "\t/* last_comp_version_w */\n");
+		asm_emit_cell(f, vi->last_comp_version_w);
+	}
+
 	/*
 	 * Reserve map entries.
 	 * Align the reserve map to a doubleword boundary.
@@ -955,6 +975,9 @@ struct dt_info *dt_from_blob(const char *fname)
 		flags |= FTF_NOPS;
 	}
 
+	if (version >= 18)
+		flags |= FTF_DTFLAGS | FTF_LCVERSW;
+
 	inbuf_init(&memresvbuf,
 		   blob + off_mem_rsvmap, blob + totalsize);
 	inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
diff --git a/libfdt/fdt.h b/libfdt/fdt.h
index e6f75e7..12d358d 100644
--- a/libfdt/fdt.h
+++ b/libfdt/fdt.h
@@ -26,6 +26,10 @@ struct fdt_header {
 
 	/* version 17 fields below */
 	fdt32_t size_dt_struct;		 /* size of the structure block */
+
+	/* version 18 fields below */
+	fdt32_t dt_flags;		/* Ored value of FDT_FLAG_XXXX */
+	fdt32_t last_comp_version_w;	/* last compatible version for writing */
 };
 
 struct fdt_reserve_entry {
@@ -85,5 +89,6 @@ struct fdt_property {
 #define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(fdt32_t))
 #define FDT_V16_SIZE	FDT_V3_SIZE
 #define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(fdt32_t))
+#define FDT_V18_SIZE	(FDT_V17_SIZE + 2 * sizeof(fdt32_t))
 
 #endif /* FDT_H */
diff --git a/libfdt/fdt_rw.c b/libfdt/fdt_rw.c
index a8f53b4..0a4a03f 100644
--- a/libfdt/fdt_rw.c
+++ b/libfdt/fdt_rw.c
@@ -34,13 +34,17 @@ static int fdt_rw_probe_(void *fdt)
 		return 0;
 	FDT_RO_PROBE(fdt);
 
-	if (!can_assume(LATEST) && fdt_version(fdt) < 17)
-		return -FDT_ERR_BADVERSION;
+	if (!can_assume(LATEST)) {
+		if (fdt_version(fdt) < 17)
+			return -FDT_ERR_BADVERSION;
+		else if (fdt_version(fdt) >= 18 &&
+			 fdt_last_comp_version_w(fdt) > FDT_LAST_SUPPORTED_VERSION)
+			return -FDT_ERR_BADVERSION;
+	}
 	if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry),
 				   fdt_size_dt_struct(fdt)))
 		return -FDT_ERR_BADLAYOUT;
 
-	fdt_downgrade_version(fdt);
 	return 0;
 }
 
@@ -582,7 +586,11 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
 		err = fdt_move(fdt, buf, bufsize);
 		if (err)
 			return err;
-		fdt_set_version(buf, 17);
+		if (can_assume(LATEST) || fdt_version(fdt) < 18) {
+			fdt_set_version(buf, 18);
+			fdt_set_dt_flags(buf, 0);
+			fdt_set_last_comp_version_w(buf, 17);
+		}
 		fdt_set_size_dt_struct(buf, struct_size);
 		fdt_set_totalsize(buf, bufsize);
 		return 0;
@@ -611,8 +619,10 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
 
 	fdt_set_magic(buf, FDT_MAGIC);
 	fdt_set_totalsize(buf, bufsize);
-	fdt_set_version(buf, 17);
+	fdt_set_version(buf, 18);
 	fdt_set_last_comp_version(buf, 16);
+	fdt_set_dt_flags(buf, 0);
+	fdt_set_last_comp_version_w(buf, 17);
 	fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
 
 	return 0;
diff --git a/libfdt/fdt_sw.c b/libfdt/fdt_sw.c
index 4c569ee..10da0d6 100644
--- a/libfdt/fdt_sw.c
+++ b/libfdt/fdt_sw.c
@@ -137,6 +137,9 @@ int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags)
 	fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
 	fdt_set_off_dt_strings(fdt, 0);
 
+	fdt_set_dt_flags(fdt, 0);
+	fdt_set_last_comp_version_w(fdt, FDT_LAST_COMPATIBLE_VERSION_W);
+
 	return 0;
 }
 
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index 7a10f66..71c7de5 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -15,7 +15,8 @@ extern "C" {
 
 #define FDT_FIRST_SUPPORTED_VERSION	0x02
 #define FDT_LAST_COMPATIBLE_VERSION	0x10
-#define FDT_LAST_SUPPORTED_VERSION	0x11
+#define FDT_LAST_COMPATIBLE_VERSION_W	0x11
+#define FDT_LAST_SUPPORTED_VERSION	0x12
 
 /* Error codes: informative error codes */
 #define FDT_ERR_NOTFOUND	1
@@ -284,6 +285,8 @@ int fdt_next_subnode(const void *fdt, int offset);
 #define fdt_boot_cpuid_phys(fdt)	(fdt_get_header(fdt, boot_cpuid_phys))
 #define fdt_size_dt_strings(fdt)	(fdt_get_header(fdt, size_dt_strings))
 #define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct))
+#define fdt_dt_flags(fdt)		(fdt_get_header(fdt, dt_flags))
+#define fdt_last_comp_version_w(fdt)	(fdt_get_header(fdt, last_comp_version_w))
 
 #define fdt_set_hdr_(name) \
 	static inline void fdt_set_##name(void *fdt, uint32_t val) \
@@ -301,6 +304,8 @@ fdt_set_hdr_(last_comp_version)
 fdt_set_hdr_(boot_cpuid_phys)
 fdt_set_hdr_(size_dt_strings)
 fdt_set_hdr_(size_dt_struct)
+fdt_set_hdr_(dt_flags)
+fdt_set_hdr_(last_comp_version_w)
 #undef fdt_set_hdr_
 
 /**
diff --git a/pylibfdt/libfdt.i b/pylibfdt/libfdt.i
index 1f9c047..90966bd 100644
--- a/pylibfdt/libfdt.i
+++ b/pylibfdt/libfdt.i
@@ -281,6 +281,22 @@ class FdtRo(object):
         """
         return fdt_size_dt_struct(self._fdt)
 
+    def dt_flags(self):
+        """Return flags from the header
+
+        Returns:
+            flags value from the header
+        """
+        return fdt_dt_flags(self._fdt)
+
+    def last_comp_version_w(self):
+        """Return the last compatible version for writing of the device tree
+
+        Returns:
+            Last compatible version number for writing of the device tree
+        """
+        return fdt_last_comp_version_w(self._fdt)
+
     def num_mem_rsv(self, quiet=()):
         """Return the number of memory reserve-map records
 
@@ -1215,6 +1231,8 @@ uint32_t fdt_last_comp_version(const void *fdt);
 uint32_t fdt_boot_cpuid_phys(const void *fdt);
 uint32_t fdt_size_dt_strings(const void *fdt);
 uint32_t fdt_size_dt_struct(const void *fdt);
+uint32_t fdt_dt_flags(const void *fdt);
+uint32_t fdt_last_comp_version_w(const void *fdt);
 
 int fdt_property_string(void *fdt, const char *name, const char *val);
 int fdt_property_cell(void *fdt, const char *name, uint32_t val);
diff --git a/tests/dumptrees.c b/tests/dumptrees.c
index 4732fff..c05d216 100644
--- a/tests/dumptrees.c
+++ b/tests/dumptrees.c
@@ -27,7 +27,8 @@ static struct {
 	TREE(two_roots),
 	TREE(named_root),
 	TREE(unknown_tags_can_skip),
-	TREE(unknown_tags_no_skip)
+	TREE(unknown_tags_no_skip),
+	TREE(last_comp_version_w_future)
 };
 
 #define NUM_TREES	(sizeof(trees) / sizeof(trees[0]))
diff --git a/tests/pylibfdt_tests.py b/tests/pylibfdt_tests.py
index a4f73ed..72c98c5 100644
--- a/tests/pylibfdt_tests.py
+++ b/tests/pylibfdt_tests.py
@@ -285,14 +285,16 @@ class PyLibfdtBasicTests(unittest.TestCase):
         """Test that we can access the header values"""
         self.assertEqual(self.fdt.magic(), 0xd00dfeed)
         self.assertEqual(self.fdt.totalsize(), len(self.fdt._fdt))
-        self.assertEqual(self.fdt.off_dt_struct(), 88)
-        self.assertEqual(self.fdt.off_dt_strings(), 652)
-        self.assertEqual(self.fdt.off_mem_rsvmap(), 40)
-        self.assertEqual(self.fdt.version(), 17)
+        self.assertEqual(self.fdt.off_dt_struct(), 96)
+        self.assertEqual(self.fdt.off_dt_strings(), 660)
+        self.assertEqual(self.fdt.off_mem_rsvmap(), 48)
+        self.assertEqual(self.fdt.version(), 18)
         self.assertEqual(self.fdt.last_comp_version(), 16)
         self.assertEqual(self.fdt.boot_cpuid_phys(), 0)
         self.assertEqual(self.fdt.size_dt_strings(), 105)
         self.assertEqual(self.fdt.size_dt_struct(), 564)
+        self.assertEqual(self.fdt.dt_flags(), 0)
+        self.assertEqual(self.fdt.last_comp_version_w(), 17)
 
     def testPack(self):
         """Test that we can pack the tree after deleting something"""
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 1ba937d..90ba558 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -576,7 +576,8 @@ libfdt_tests () {
     run_test dtbs_equal_ordered cell-overflow.test.dtb cell-overflow-results.test.dtb
 
     # check full tests
-    for good in test_tree1.dtb unknown_tags_can_skip.dtb; do
+    for good in test_tree1.dtb unknown_tags_can_skip.dtb \
+		last_comp_version_w_future.dtb; do
 	run_test check_full $good
     done
     for bad in truncated_property.dtb truncated_string.dtb \
@@ -1044,32 +1045,41 @@ fdtput_tests () {
 
     # TODO: Add tests for verbose mode?
 
+    # Not allowed to modify a dtb due to last_comp_version_w
+    # FDT_ERR_BADVERSION error code is returned
+    dtb=last_comp_version_w_future.fdtput.test.dtb
+    cp last_comp_version_w_future.dtb $dtb
+    run_wrap_error_test $DTPUT $dtb /subnode prop-int -tu 123
+    run_wrap_error_test $DTPUT $dtb -d /subnode prop-int
+    run_wrap_error_test $DTPUT $dtb -c /new-node
+    run_wrap_error_test $DTPUT $dtb -r /subnode
+
     # Modify a dtb containing some "unknown" tags that can be skipped
     dtb=unknown_tags_can_skip.fdtput.test.dtb
     cp unknown_tags_can_skip.dtb $dtb
     base_run_test wrap_fdtdump $dtb $dtb.0.out
     # Remove unneeded header fields (keep those related to versions)
-    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.0.out
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\|flags\)/d' $dtb.0.out
     base_run_test check_diff $dtb.0.out "$SRCDIR/$dtb.0.expect"
 
     run_fdtput_test "vwxyz" $dtb / prop-str -ts "vwxyz"
     base_run_test wrap_fdtdump $dtb $dtb.1.out
     # Remove unneeded header fields (keep those related to versions)
-    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.1.out
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\|flags\)/d' $dtb.1.out
     base_run_test check_diff $dtb.1.out "$SRCDIR/$dtb.1.expect"
 
     cp unknown_tags_can_skip.dtb $dtb
     run_wrap_test $DTPUT $dtb -c /tst-fdtput
     base_run_test wrap_fdtdump $dtb $dtb.2.out
     # Remove unneeded header fields (keep those related to versions)
-    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.2.out
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\|flags\)/d' $dtb.2.out
     base_run_test check_diff $dtb.2.out "$SRCDIR/$dtb.2.expect"
     run_wrap_test $DTPUT $dtb -c /tst-fdtput/n1 /tst-fdtput/n2 /tst-fdtput/n3
     run_wrap_test $DTPUT $dtb -r /tst-fdtput/n1 /tst-fdtput/n3
     run_fdtget_test "n2" $dtb -l  /tst-fdtput
     base_run_test wrap_fdtdump $dtb $dtb.3.out
     # Remove unneeded header fields (keep those related to versions)
-    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.3.out
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\|flags\)/d' $dtb.3.out
     base_run_test check_diff $dtb.3.out "$SRCDIR/$dtb.3.expect"
 
     cp unknown_tags_can_skip.dtb $dtb
@@ -1077,21 +1087,21 @@ fdtput_tests () {
     run_fdtget_test "prop-int" $dtb -p  /
     base_run_test wrap_fdtdump $dtb $dtb.4.out
     # Remove unneeded header fields (keep those related to versions)
-    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.4.out
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\|flags\)/d' $dtb.4.out
     base_run_test check_diff $dtb.4.out "$SRCDIR/$dtb.4.expect"
 
     cp unknown_tags_can_skip.dtb $dtb
     run_wrap_test $DTPUT $dtb /subnode2 prop-tst-fdtput -ts "Test fdtput"
     base_run_test wrap_fdtdump $dtb $dtb.5.out
     # Remove unneeded header fields (keep those related to versions)
-    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.5.out
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\|flags\)/d' $dtb.5.out
     base_run_test check_diff $dtb.5.out "$SRCDIR/$dtb.5.expect"
 
     cp unknown_tags_can_skip.dtb $dtb
     run_wrap_test $DTPUT $dtb -r /subnode2/subsubnode
     base_run_test wrap_fdtdump $dtb $dtb.6.out
     # Remove unneeded header fields (keep those related to versions)
-    sed -i '/^\/.*\(magic\|off\|size\|cpu\)/d' $dtb.6.out
+    sed -i '/^\/.*\(magic\|off\|size\|cpu\|flags\)/d' $dtb.6.out
     base_run_test check_diff $dtb.6.out "$SRCDIR/$dtb.6.expect"
 }
 
diff --git a/tests/testdata.h b/tests/testdata.h
index aef04ab..26c7c18 100644
--- a/tests/testdata.h
+++ b/tests/testdata.h
@@ -59,4 +59,5 @@ extern struct fdt_header two_roots;
 extern struct fdt_header named_root;
 extern struct fdt_header unknown_tags_can_skip;
 extern struct fdt_header unknown_tags_no_skip;
+extern struct fdt_header last_comp_version_w_future;
 #endif /* ! __ASSEMBLER__ */
diff --git a/tests/testutils.c b/tests/testutils.c
index 54da2e4..728d89c 100644
--- a/tests/testutils.c
+++ b/tests/testutils.c
@@ -344,7 +344,7 @@ void *open_blob_rw(const void *blob)
 {
 	int err;
 	void *buf;
-	int newsize = fdt_totalsize(blob) + 8;
+	int newsize = fdt_totalsize(blob) + 8 + 2 * 4;
 
 	buf = xmalloc(newsize);
 	err = fdt_open_into(blob, buf, newsize);
diff --git a/tests/trees.S b/tests/trees.S
index ef9a175..9215f3e 100644
--- a/tests/trees.S
+++ b/tests/trees.S
@@ -8,7 +8,7 @@
 	.byte	(\val) & 0xff
 	.endm
 
-	.macro	treehdr_vers	tree vers last_comp_vers
+	.macro	treehdr_vers	tree vers last_comp_vers last_comp_vers_w
 	.balign	8
 	.globl	\tree
 \tree :
@@ -22,10 +22,12 @@
 	fdtlong	0
 	fdtlong	(\tree\()_strings_end - \tree\()_strings)
 	fdtlong	(\tree\()_struct_end - \tree\()_struct)
+	fdtlong	0
+	fdtlong	\last_comp_vers_w
 	.endm
 
 	.macro	treehdr	tree
-	treehdr_vers \tree 0x11 0x10
+	treehdr_vers \tree 0x12 0x10 0x11
 	.endm
 
 	.macro	rsvmape	addrh, addrl, lenh, lenl
@@ -334,7 +336,7 @@ named_root_end:
 	 * Use a really future dtb version to check version downgrade on
 	 * modification.
 	 */
-	treehdr_vers	unknown_tags_can_skip 0xffffffff 0x10
+	treehdr_vers	unknown_tags_can_skip 0xffffffff 0x10 0x11
 	empty_rsvmap	unknown_tags_can_skip
 
 unknown_tags_can_skip_struct:
@@ -444,3 +446,24 @@ unknown_tags_no_skip_strings:
 unknown_tags_no_skip_strings_end:
 
 unknown_tags_no_skip_end:
+
+
+	/* Tree with last_comp_version_w set to avoid any modifications */
+	treehdr_vers	last_comp_version_w_future 0xffffffff 0x10 0xffffffff
+	empty_rsvmap	last_comp_version_w_future
+
+last_comp_version_w_future_struct:
+	beginn	""
+		propu64	last_comp_version_w_future, prop_int, 1, 2
+		beginn	"subnode"
+			propu64	last_comp_version_w_future, prop_int, 1, 2
+		endn
+	endn
+	fdtlong	FDT_END
+last_comp_version_w_future_struct_end:
+
+last_comp_version_w_future_strings:
+	string	last_comp_version_w_future, prop_int, "prop-int"
+last_comp_version_w_future_strings_end:
+
+last_comp_version_w_future_end:
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.0.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.0.expect
index 3cdf448..0d72e1f 100644
--- a/tests/unknown_tags_can_skip.fdtput.test.dtb.0.expect
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.0.expect
@@ -1,6 +1,7 @@
 /dts-v1/;
 // version:		4294967295
 // last_comp_version:	16
+// last_comp_version_w:	17
 
 // Unknown tag ignored: 0xd0000000, data len 4 00000001
 / {
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.1.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.1.expect
index 71f2d1c..d355d5a 100644
--- a/tests/unknown_tags_can_skip.fdtput.test.dtb.1.expect
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.1.expect
@@ -1,6 +1,7 @@
 /dts-v1/;
-// version:		17
+// version:		18
 // last_comp_version:	16
+// last_comp_version_w:	17
 
 // Unknown tag ignored: 0xd0000000, data len 4 00000001
 / {
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.2.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.2.expect
index bd3a13b..69b4465 100644
--- a/tests/unknown_tags_can_skip.fdtput.test.dtb.2.expect
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.2.expect
@@ -1,6 +1,7 @@
 /dts-v1/;
-// version:		17
+// version:		4294967295
 // last_comp_version:	16
+// last_comp_version_w:	17
 
 // Unknown tag ignored: 0xd0000000, data len 4 00000001
 / {
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.3.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.3.expect
index 237eb95..bbdd1c6 100644
--- a/tests/unknown_tags_can_skip.fdtput.test.dtb.3.expect
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.3.expect
@@ -1,6 +1,7 @@
 /dts-v1/;
-// version:		17
+// version:		4294967295
 // last_comp_version:	16
+// last_comp_version_w:	17
 
 // Unknown tag ignored: 0xd0000000, data len 4 00000001
 / {
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.4.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.4.expect
index 8473040..98b0252 100644
--- a/tests/unknown_tags_can_skip.fdtput.test.dtb.4.expect
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.4.expect
@@ -1,6 +1,7 @@
 /dts-v1/;
-// version:		17
+// version:		4294967295
 // last_comp_version:	16
+// last_comp_version_w:	17
 
 // Unknown tag ignored: 0xd0000000, data len 4 00000001
 / {
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.5.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.5.expect
index f7806f4..9738793 100644
--- a/tests/unknown_tags_can_skip.fdtput.test.dtb.5.expect
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.5.expect
@@ -1,6 +1,7 @@
 /dts-v1/;
-// version:		17
+// version:		4294967295
 // last_comp_version:	16
+// last_comp_version_w:	17
 
 // Unknown tag ignored: 0xd0000000, data len 4 00000001
 / {
diff --git a/tests/unknown_tags_can_skip.fdtput.test.dtb.6.expect b/tests/unknown_tags_can_skip.fdtput.test.dtb.6.expect
index 029f3b4..22449ae 100644
--- a/tests/unknown_tags_can_skip.fdtput.test.dtb.6.expect
+++ b/tests/unknown_tags_can_skip.fdtput.test.dtb.6.expect
@@ -1,6 +1,7 @@
 /dts-v1/;
-// version:		17
+// version:		4294967295
 // last_comp_version:	16
+// last_comp_version_w:	17
 
 // Unknown tag ignored: 0xd0000000, data len 4 00000001
 / {
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v2 5/7] soc: samsung: exynos-pmu: add Exynos850 CPU hotplug support
From: Henrik Grimler @ 2026-04-09 11:57 UTC (permalink / raw)
  To: Alexey Klimov
  Cc: Sam Protsenko, linux-samsung-soc, Krzysztof Kozlowski,
	Peter Griffin, André Draszik, Conor Dooley, Alim Akhtar,
	Tudor Ambarus, Rob Herring, Krzysztof Kozlowski, linux-arm-kernel,
	devicetree, linux-kernel
In-Reply-To: <20260401-exynos850-cpuhotplug-v2-5-c5a760a3e259@linaro.org>

Hi Alexey,

This patch breaks compilation for arm(32) exynos devices. Compiling
with exynos_defconfig I get:

[ ... ]
  CC      drivers/soc/samsung/exynos850-pmu.o
  CC [M]  fs/squashfs/page_actor.o
../drivers/soc/samsung/exynos850-pmu.c:17:21: error: call to undeclared function 'MPIDR_AFFINITY_LEVEL'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
   17 |         u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
      |                            ^
../drivers/soc/samsung/exynos850-pmu.c:17:42: error: call to undeclared function 'read_cpuid_mpidr'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
   17 |         u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
      |                                                 ^
../drivers/soc/samsung/exynos850-pmu.c:48:21: error: call to undeclared function 'MPIDR_AFFINITY_LEVEL'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
   48 |         u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
      |                            ^
../drivers/soc/samsung/exynos850-pmu.c:48:42: error: call to undeclared function 'read_cpuid_mpidr'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
   48 |         u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
      |                                                 ^
4 errors generated.
make[6]: *** [../scripts/Makefile.build:289: drivers/soc/samsung/exynos850-pmu.o] Error 1
make[5]: *** [../scripts/Makefile.build:548: drivers/soc/samsung] Error 2
make[4]: *** [../scripts/Makefile.build:548: drivers/soc] Error 2
make[3]: *** [../scripts/Makefile.build:548: drivers] Error 2
make[3]: *** Waiting for unfinished jobs....
[ ... ]

Best regards,
Henrik Grimler

On Wed, Apr 01, 2026 at 05:51:58AM +0100, Alexey Klimov wrote:
> Add cpuhotplug support for Exynos850 platforms. This SoC requires
> its own specific set of writes/updates to PMU and PMU interrupts
> generation block in order to put a CPU or a group of CPUs into
> a different sleep states or prepare these entities for a CPU_OFF
> or wake-up out of idle state or after CPU online.
> Without these writes/updates the CPU(s) wake-up or online fails.
> While at this, also add description of Exynos850 PMU registers.
> 
> Signed-off-by: Alexey Klimov <alexey.klimov@linaro.org>
> ---
>  drivers/soc/samsung/Makefile                |  2 +-
>  drivers/soc/samsung/exynos-pmu.c            |  1 +
>  drivers/soc/samsung/exynos-pmu.h            |  1 +
>  drivers/soc/samsung/exynos850-pmu.c         | 78 +++++++++++++++++++++++++++++
>  include/linux/soc/samsung/exynos-regs-pmu.h |  5 ++
>  5 files changed, 86 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile
> index 636a762608c9..7f544e3c1fcc 100644
> --- a/drivers/soc/samsung/Makefile
> +++ b/drivers/soc/samsung/Makefile
> @@ -7,7 +7,7 @@ exynos_chipid-y			+= exynos-chipid.o exynos-asv.o
>  obj-$(CONFIG_EXYNOS_USI)	+= exynos-usi.o
>  
>  obj-$(CONFIG_EXYNOS_PMU)	+= exynos_pmu.o
> -exynos_pmu-y			+= exynos-pmu.o gs101-pmu.o
> +exynos_pmu-y			+= exynos-pmu.o gs101-pmu.o exynos850-pmu.o
>  
>  obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS)	+= exynos3250-pmu.o exynos4-pmu.o \
>  					exynos5250-pmu.o exynos5420-pmu.o
> diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
> index 4e5fcc01e5e0..daa870ba88f5 100644
> --- a/drivers/soc/samsung/exynos-pmu.c
> +++ b/drivers/soc/samsung/exynos-pmu.c
> @@ -133,6 +133,7 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = {
>  		.compatible = "samsung,exynos7-pmu",
>  	}, {
>  		.compatible = "samsung,exynos850-pmu",
> +		.data = &exynos850_pmu_data,
>  	},
>  	{ /*sentinel*/ },
>  };
> diff --git a/drivers/soc/samsung/exynos-pmu.h b/drivers/soc/samsung/exynos-pmu.h
> index 186299a049a8..4202d3cd94c9 100644
> --- a/drivers/soc/samsung/exynos-pmu.h
> +++ b/drivers/soc/samsung/exynos-pmu.h
> @@ -102,6 +102,7 @@ extern const struct exynos_pmu_data exynos5250_pmu_data;
>  extern const struct exynos_pmu_data exynos5420_pmu_data;
>  #endif
>  extern const struct exynos_pmu_data gs101_pmu_data;
> +extern const struct exynos_pmu_data exynos850_pmu_data;
>  
>  extern void pmu_raw_writel(u32 val, u32 offset);
>  extern u32 pmu_raw_readl(u32 offset);
> diff --git a/drivers/soc/samsung/exynos850-pmu.c b/drivers/soc/samsung/exynos850-pmu.c
> new file mode 100644
> index 000000000000..b3841547577a
> --- /dev/null
> +++ b/drivers/soc/samsung/exynos850-pmu.c
> @@ -0,0 +1,78 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2026 Linaro Ltd.
> + *
> + * Exynos850 PMU support
> + */
> +
> +#include <linux/soc/samsung/exynos-pmu.h>
> +#include <linux/soc/samsung/exynos-regs-pmu.h>
> +#include <linux/regmap.h>
> +
> +#include "exynos-pmu.h"
> +
> +static int exynos850_cpu_pmu_offline(struct exynos_pmu_context *pmu_context, unsigned int cpu)
> +	__must_hold(&pmu_context->cpupm_lock)
> +{
> +	u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
> +	u32 cluster_cpu = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
> +	unsigned int cpuhint = smp_processor_id();
> +	u32 reg, mask;
> +
> +	/* set cpu inform hint */
> +	regmap_write(pmu_context->pmureg, EXYNOS850_CPU_INFORM(cpuhint),
> +		     CPU_INFORM_C2);
> +
> +	mask = BIT(cpu);
> +	regmap_update_bits(pmu_context->pmuintrgen, EXYNOS_GRP2_INTR_BID_ENABLE,
> +			   mask, BIT(cpu));
> +
> +	regmap_read(pmu_context->pmuintrgen, EXYNOS_GRP1_INTR_BID_UPEND, &reg);
> +	regmap_write(pmu_context->pmuintrgen, EXYNOS_GRP1_INTR_BID_CLEAR,
> +		     reg & mask);
> +
> +	mask = (BIT(cpu + 8));
> +	regmap_read(pmu_context->pmuintrgen, EXYNOS_GRP1_INTR_BID_UPEND, &reg);
> +	regmap_write(pmu_context->pmuintrgen, EXYNOS_GRP1_INTR_BID_CLEAR,
> +		     reg & mask);
> +
> +	regmap_update_bits(pmu_context->pmureg,
> +			   EXYNOS850_CLUSTER_CPU_INT_EN(this_cluster, cluster_cpu),
> +			   1 << 3, 1 << 3);
> +	return 0;
> +}
> +
> +static int exynos850_cpu_pmu_online(struct exynos_pmu_context *pmu_context, unsigned int cpu)
> +	__must_hold(&pmu_context->cpupm_lock)
> +{
> +	u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
> +	u32 cluster_cpu = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
> +	unsigned int cpuhint = smp_processor_id();
> +	u32 reg, mask;
> +
> +	/* clear cpu inform hint */
> +	regmap_write(pmu_context->pmureg, EXYNOS850_CPU_INFORM(cpuhint),
> +		     CPU_INFORM_CLEAR);
> +
> +	mask = BIT(cpu);
> +
> +	regmap_update_bits(pmu_context->pmuintrgen, EXYNOS_GRP2_INTR_BID_ENABLE,
> +			   mask, (0 << cpu));
> +
> +	regmap_read(pmu_context->pmuintrgen, EXYNOS_GRP2_INTR_BID_UPEND, &reg);
> +
> +	regmap_write(pmu_context->pmuintrgen, EXYNOS_GRP2_INTR_BID_CLEAR,
> +		     reg & mask);
> +
> +	regmap_update_bits(pmu_context->pmureg,
> +			   EXYNOS850_CLUSTER_CPU_INT_EN(this_cluster, cluster_cpu),
> +			   1 << 3, 0 << 3);
> +	return 0;
> +}
> +
> +const struct exynos_pmu_data exynos850_pmu_data = {
> +	.pmu_cpuhp = true,
> +	.cpu_pmu_offline = exynos850_cpu_pmu_offline,
> +	.cpu_pmu_online = exynos850_cpu_pmu_online,
> +};
> +
> diff --git a/include/linux/soc/samsung/exynos-regs-pmu.h b/include/linux/soc/samsung/exynos-regs-pmu.h
> index 9c4d3da41dbf..93c4d724c8ea 100644
> --- a/include/linux/soc/samsung/exynos-regs-pmu.h
> +++ b/include/linux/soc/samsung/exynos-regs-pmu.h
> @@ -1015,6 +1015,11 @@
>  #define EXYNOS_GRP2_INTR_BID_UPEND				(0x0208)
>  #define EXYNOS_GRP2_INTR_BID_CLEAR				(0x020c)
>  
> +/* Exynos850 PMU Alive */
> +#define EXYNOS850_CPU_INFORM(cpu)		(0x0860 + ((cpu) & 7) * 4)
> +#define EXYNOS850_CLUSTER_CPU_OFFSET(cl, cpu)	(0x1000 + ((cl * 0x400) + ((cpu) * 0x80)))
> +#define EXYNOS850_CLUSTER_CPU_INT_EN(cl, cpu)	(EXYNOS850_CLUSTER_CPU_OFFSET(cl, cpu) + 0x44)
> +
>  /* exynosautov920 */
>  #define EXYNOSAUTOV920_PHY_CTRL_USB20				(0x0710)
>  #define EXYNOSAUTOV920_PHY_CTRL_USB31				(0x0714)
> 
> -- 
> 2.51.0
> 
> 

^ permalink raw reply

* [PATCH 0/3] arm64: dts: imx95: Update for smmu
From: Peng Fan (OSS) @ 2026-04-09 12:00 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Peng Fan

Update smmu reg size
Add SMMU PMU nodes
Enable SMMU by default and add iommus property for sdhc/edma.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
Peng Fan (3):
      arm64: dts: imx95: Correct SMMU reg
      arm64: dts: imx95: Add SMMU PMU nodes
      arm64: dts: imx95: Add iommus property and enable SMMU

 arch/arm64/boot/dts/freescale/imx95.dtsi | 91 +++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 2 deletions(-)
---
base-commit: db7efce4ae23ad5e42f5f55428f529ff62b86fab
change-id: 20260409-imx95-s-dts-e8f12dc94c29

Best regards,
-- 
Peng Fan <peng.fan@nxp.com>


^ permalink raw reply

* [PATCH 1/3] arm64: dts: imx95: Correct SMMU reg
From: Peng Fan (OSS) @ 2026-04-09 12:00 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Peng Fan
In-Reply-To: <20260409-imx95-s-dts-v1-0-858e83ae1a37@nxp.com>

From: Peng Fan <peng.fan@nxp.com>

Update SMMU reg size to 0x40000, because MMU-700 TCU occupies 4 pages with
each page 64KB and the last page is reserved.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 arch/arm64/boot/dts/freescale/imx95.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
index 71394871d8dd0fe80ea244feff4469e536321b1c..28b19a47a59daaff308fecce6e7b9ffe14133f74 100644
--- a/arch/arm64/boot/dts/freescale/imx95.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
@@ -1761,7 +1761,7 @@ aips4: bus@49000000 {
 
 			smmu: iommu@490d0000 {
 				compatible = "arm,smmu-v3";
-				reg = <0x490d0000 0x100000>;
+				reg = <0x490d0000 0x40000>;
 				interrupts = <GIC_SPI 325 IRQ_TYPE_EDGE_RISING>,
 					     <GIC_SPI 328 IRQ_TYPE_EDGE_RISING>,
 					     <GIC_SPI 334 IRQ_TYPE_EDGE_RISING>,

-- 
2.37.1


^ permalink raw reply related

* [PATCH 2/3] arm64: dts: imx95: Add SMMU PMU nodes
From: Peng Fan (OSS) @ 2026-04-09 12:00 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Peng Fan
In-Reply-To: <20260409-imx95-s-dts-v1-0-858e83ae1a37@nxp.com>

From: Peng Fan <peng.fan@nxp.com>

MMU-700 supports TCU PMU and TBU PMU. There are one TCU PMU and
11 TBU PMUs, add them all.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 arch/arm64/boot/dts/freescale/imx95.dtsi | 84 ++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
index 28b19a47a59daaff308fecce6e7b9ffe14133f74..3e35c956a4d7af88310b3dfaef7e3d064f530e07 100644
--- a/arch/arm64/boot/dts/freescale/imx95.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
@@ -1770,6 +1770,90 @@ smmu: iommu@490d0000 {
 				#iommu-cells = <1>;
 				status = "disabled";
 			};
+
+			pmu@490d2000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x490d2000 0x1000>,
+				      <0x490f2000 0x1000>;
+				interrupts = <GIC_SPI 333 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@49112000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x49112000 0x1000>,
+				      <0x49122000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@49132000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x49132000 0x1000>,
+				      <0x49142000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@49152000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x49152000 0x1000>,
+				      <0x49162000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@49172000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x49172000 0x1000>,
+				      <0x49182000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@49192000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x49192000 0x1000>,
+				      <0x491a2000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@491b2000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x491b2000 0x1000>,
+				      <0x491c2000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@491d2000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x491d2000 0x1000>,
+				      <0x491e2000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@491f2000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x491f2000 0x1000>,
+				      <0x49202000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@49212000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x49212000 0x1000>,
+				      <0x49222000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@49232000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x49232000 0x1000>,
+				      <0x49242000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
+
+			pmu@49252000 {
+				compatible = "arm,smmu-v3-pmcg";
+				reg = <0x49252000 0x1000>,
+				      <0x49262000 0x1000>;
+				interrupts = <GIC_SPI 323 IRQ_TYPE_EDGE_RISING>;
+			};
 		};
 
 		usb3: usb@4c010010 {

-- 
2.37.1


^ permalink raw reply related

* [PATCH 3/3] arm64: dts: imx95: Add iommus property and enable SMMU
From: Peng Fan (OSS) @ 2026-04-09 12:00 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam
  Cc: devicetree, imx, linux-arm-kernel, linux-kernel, Peng Fan
In-Reply-To: <20260409-imx95-s-dts-v1-0-858e83ae1a37@nxp.com>

From: Peng Fan <peng.fan@nxp.com>

Add iommus property for SDHC and EDMA
Enable SMMU by default.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 arch/arm64/boot/dts/freescale/imx95.dtsi | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/freescale/imx95.dtsi b/arch/arm64/boot/dts/freescale/imx95.dtsi
index 3e35c956a4d7af88310b3dfaef7e3d064f530e07..adcc0e1d3696b93250ab97fcac7c181b187d3d10 100644
--- a/arch/arm64/boot/dts/freescale/imx95.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx95.dtsi
@@ -777,6 +777,7 @@ edma3: dma-controller@42210000 {
 					     <GIC_SPI 287 IRQ_TYPE_LEVEL_HIGH>;
 				clocks = <&scmi_clk IMX95_CLK_BUSWAKEUP>;
 				clock-names = "dma";
+				iommus = <&smmu 0x0>;
 			};
 
 			mu7: mailbox@42430000 {
@@ -1242,6 +1243,7 @@ usdhc1: mmc@42850000 {
 				bus-width = <8>;
 				fsl,tuning-start-tap = <1>;
 				fsl,tuning-step = <2>;
+				iommus = <&smmu 0x1>;
 				status = "disabled";
 			};
 
@@ -1259,6 +1261,7 @@ usdhc2: mmc@42860000 {
 				bus-width = <4>;
 				fsl,tuning-start-tap = <1>;
 				fsl,tuning-step = <2>;
+				iommus = <&smmu 0x2>;
 				status = "disabled";
 			};
 
@@ -1276,6 +1279,7 @@ usdhc3: mmc@428b0000 {
 				bus-width = <4>;
 				fsl,tuning-start-tap = <1>;
 				fsl,tuning-step = <2>;
+				iommus = <&smmu 0x3>;
 				status = "disabled";
 			};
 		};
@@ -1768,7 +1772,6 @@ smmu: iommu@490d0000 {
 					     <GIC_SPI 326 IRQ_TYPE_EDGE_RISING>;
 				interrupt-names = "eventq", "gerror", "priq", "cmdq-sync";
 				#iommu-cells = <1>;
-				status = "disabled";
 			};
 
 			pmu@490d2000 {

-- 
2.37.1


^ permalink raw reply related

* Re: [PATCH 3/3] arm64: dts: broadcom: bcm2712: Add the otp nodes to firmware
From: Gregor Herburger @ 2026-04-09 12:02 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
	Ray Jui, Scott Branden, Broadcom internal kernel review list,
	Eric Anholt, Stefan Wahren, Srinivas Kandagatla, devicetree,
	linux-rpi-kernel, linux-arm-kernel, linux-kernel
In-Reply-To: <20260409-imposing-strict-snail-5d2a6f@quoll>

Hi Krzysztof,

thanks for reviewing.

On Thu, Apr 09, 2026 at 10:15:12AM +0200, Krzysztof Kozlowski wrote:
> On Wed, Apr 08, 2026 at 10:00:17AM +0200, Gregor Herburger wrote:
> > The Raspberry Pi 5 has two OTP registers (private and customer), add these
> > to the devicetree.
> 
> So this sentence confirms my question on bindings - your device
> raspberrypi,bcm2835-firmware has these, thus you do not need these child
> nodes at all. Neither compatibles.

I dont't think so. In my understanding the bcm2835-firmware does not
provide the otp registers but only provides the interface to the
registers. Though I don't know the details how this is done but [1] says
that only BCM2712 has 512bits and the others (like bcm2711) have
256bits. So both devicetrees have the raspberrypi,bcm2835-firmware node
but only the bcm2712 has the raspberrypi,firmware-otp-private node while the 
raspberrypi,firmware-otp-customer is available in all raspberrys.

> Drop entire DTS and binding patches.

If I drop the binding patch how to distinguish the variants? Should I
add a SoC specific compatible? e.g. `raspberrypi,bcm2712-firmware` and
use it in the firmware/raspberrypi driver to add the second otp region?

Also what I don't understand why we have all the bindings for
'raspberrypi,firmware-clocks', 'raspberrypi,firmware-gpio',
'raspberrypi,firmware-reset', 'raspberrypi,firmware-poe-pwm' and
'raspberrypi,firmware-ts'. What is the difference between these devices
and the otp registers. They are all accessed through the firmware.

[1] https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#device-specific-private-key

Best regards
Gregor

^ permalink raw reply

* Re: [PATCH v1 1/2] dt-bindings: i2c: ls2x-i2c: Add clock- related properties
From: Hongliang Wang @ 2026-04-09 12:03 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Binbin Zhou, Andi Shyti, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-i2c, devicetree, loongarch
In-Reply-To: <a08ac3f9-a770-df48-a95b-4b07cd2c0d58@loongson.cn>

Hi, Krzysztof

On 2026/3/31 下午3:11, Hongliang Wang wrote:
>
> On 2026/3/30 下午3:23, Krzysztof Kozlowski wrote:
>> On 30/03/2026 09:18, Hongliang Wang wrote:
>>> On 2026/3/27 下午2:39, Krzysztof Kozlowski wrote:
>>>> On 27/03/2026 04:09, Hongliang Wang wrote:
>>>>> The initial idea was that this patch could be used for both ACPI 
>>>>> and DTS.
>>>>>>>> The i2c-ls2x driver is compatible with both Loongson 2K and 3A+7A
>>>>>>>> platform, parse
>>>>>>>> the same parameters regardless of dts or acpi parameter 
>>>>>>>> passing, So
>>>>>>>> clock-input
>>>>>>>> and clock-div attributes are defined to describe input clock of 
>>>>>>>> i2c
>>>>>>>> controller and
>>>>>>>> divisor of input clock. It can be used on both 2K and 3A+7A 
>>>>>>>> platform.
>>>>>>> And you cannot use them in DTS.
>>>>> OK
>>>>>> I need to keep guessing what you want to achieve, because neither 
>>>>>> your
>>>>>> message nor commit text was explicit
>>>>> What I want to achieve is to describe the input clock and divisor 
>>>>> of I2C
>>>>> controller
>>>> Input clocks are defined as clock inputs obviously in DT, not as
>>>> integers. Bindings need to describe the hardware, so start with that.
>>> I can describe the hardware in loongson,ls2x-i2c.yaml, and I would 
>>> like to
>>> confirm with you what final implementation plan you agree to? clock
>>> framework
>>> or custom clock-input an clock-div attributes? if clock framework, how
>>> can it
>>> also be used for ACPI?
>> And you ask DT maintainer for that? It's not relevant. You sent DT
>> bindings patch, so this patch must be correct and we discuss this patch
>> here.
> I don't. My idea is that if the clock input attribute can't be used 
> for both
> dts and acpi, then clock framework will be used for dts and new define 
> attribute
> will be used for acpi. I will first implement the hardware description 
> and clock
> framework in Bindings.
>> Best regards,
>> Krzysztof
>
> Best regards,
> Hongliang Wang
>

I have a question, the input clock of i2c controller can be described by 
"clocks",
but there is no existing attribute can describe the divisor of the input 
clock,
Can I define a new attribute named "clock-div" to describe it in DT 
bindings?
or do you have any standard solutions for the divisor problem? Thank you.

Best regards,
Hongliang Wang



^ permalink raw reply

* Re: [PATCH v2 2/3] mailbox: exynos: Add support for Exynos850 mailbox
From: Tudor Ambarus @ 2026-04-09 12:04 UTC (permalink / raw)
  To: Alexey Klimov
  Cc: Krzysztof Kozlowski, Sylwester Nawrocki, Chanwoo Choi,
	Alim Akhtar, Sam Protsenko, Michael Turquette, Stephen Boyd,
	Rob Herring, Conor Dooley, Jassi Brar, Krzysztof Kozlowski,
	Peter Griffin, linux-samsung-soc, linux-arm-kernel, linux-clk,
	devicetree, linux-kernel, Juan Yescas
In-Reply-To: <DHNSP3FVR4ZQ.1PIRHF0KJGKI5@linaro.org>



On 4/8/26 4:08 PM, Alexey Klimov wrote:
> Hi Tudor,

Hi!

>> I find it strange that the SoCs use different registers. Are you sure you're
>> using the right direction? i.e. ring the doorbell to APM and not to AP?
> 
> Well, I am not sure I correctly understood the questions and comment. So,
> this all was tested with ACPM TMU code with 3 temp sensors and it seems
> to work and sensors react in the right way.
> 
> Downstream clearly does the following (see also [1],[2]) when sending
> ACPM msg:
> 
> static void apm_interrupt_gen(unsigned int id)
> {
> 	/* APM NVIC INTERRUPT GENERATE */
> 	writel((1 << id) << 16, acpm_ipc->intr + INTGR0);
> }
> 

Indeed, it looks alright, thanks for the pointers.

> I am aware that gs101 downstream uses INTGR1 in apm_interrupt_gen().
> 
> When I use INTGR1 for e850 then I observe acpm timeouts. Hence, out of
> curiosity, what's the expected behaviour when/if I ring the doorbell to

If you raise your own interrupt the APM remains unaware and the AP times out.
You also have a spurious interrupt on yourself.

> AP (to itself as far as I understand)? My understanding that it won't
> work at all in such case unless APM firmware does some very fast
> polling.
> 
> 
> [1]: https://gitlab.com/Linaro/96boards/e850-96/kernel/-/blob/android-exynos-4.14-linaro/drivers/soc/samsung/acpm/acpm_ipc.c?ref_type=heads#L423
> [2]: https://github.com/samsungexynos850/android_kernel_samsung_exynos850/blob/0af517be2336bf8e09c59d576c4c314446713101/drivers/soc/samsung/acpm/acpm_ipc.c#L426
> 
>>>  static int exynos_mbox_send_data(struct mbox_chan *chan, void *data)
>>> @@ -57,7 +104,8 @@ static int exynos_mbox_send_data(struct mbox_chan *chan, void *data)
>>>  		return -EINVAL;
>>>  	}
>>>  
>>> -	writel(BIT(msg->chan_id), exynos_mbox->regs + EXYNOS_MBOX_INTGR1);
>>> +	writel(BIT(msg->chan_id) << exynos_mbox->data->irq_doorbell_shift,
>>> +	       exynos_mbox->regs + exynos_mbox->data->irq_doorbell_offset);
>>
>> Use FIELD_PREP from <linux/bitfield.h> please. You will use a mask instead of
>> a shift.
>>
>> I would rename irq_doorbell_offset to intgr. It aligns with the register name
>> from the datasheet. You won't need to prepend _offset to the name, we already
>> see it's an offset when doing the writel().
> 
> Sure. Thanks. Let's use FIELD_PREP.
> 
> "doorbell" naming was chosen for readability and maintainability reasons.
> It seems to be more generic enough name that better reflects the workflow
> of what's going on in ACPM+mailbox machinery. We can rename it to just
> "doorbell" for instance.
> 
> From platform data it will be clear to which register it is set, INTGR0
> or INTGR1, to align it with datasheet (which is closed anyway).
> 
> Regarding intgr vs doorbell name, the intgr is a bit unclear for a
> reader if it means interrupt generation register or something else.

interrupt generation registers sounds sane to me

> But if you prefer, I can go with "intgr".

I think I prefer intgr, yes. If you choose doorbell, you'll have:

writel(FIELD_PREP(data->doorbell_mask), BIT(msg->chan_id),
       exynos_mbox->regs + data->doorbell);

or maybe s/doorbell/doorbell_reg? But that would duplicate
exynos_mbox->regs, we already see that doorbell is a reg offset.
Doorbell is too generic for my taste.

And then how would you refer to the interrupt mask register? You
already have a doorbell_mask in the example above. 

I won't push back too hard, I'll let you choose. If you can find a good
naming scheme for the interrupt generation reg and interrupt mask reg,
then fine.

> 
> One more option is add a comment, smth like /* Ring the doorbell */
> before that writel().

I'm okay with such comment.

Cheers,
ta

^ permalink raw reply

* Re: [PATCH v2 5/7] soc: samsung: exynos-pmu: add Exynos850 CPU hotplug support
From: Alexey Klimov @ 2026-04-09 12:07 UTC (permalink / raw)
  To: Henrik Grimler
  Cc: Sam Protsenko, linux-samsung-soc, Krzysztof Kozlowski,
	Peter Griffin, André Draszik, Conor Dooley, Alim Akhtar,
	Tudor Ambarus, Rob Herring, Krzysztof Kozlowski, linux-arm-kernel,
	devicetree, linux-kernel
In-Reply-To: <20260409115630.GA15706@localhost>

Hi Henrik,

On Thu Apr 9, 2026 at 12:57 PM BST, Henrik Grimler wrote:
> Hi Alexey,
>
> This patch breaks compilation for arm(32) exynos devices. Compiling
> with exynos_defconfig I get:
>
> [ ... ]
>   CC      drivers/soc/samsung/exynos850-pmu.o
>   CC [M]  fs/squashfs/page_actor.o
> ../drivers/soc/samsung/exynos850-pmu.c:17:21: error: call to undeclared function 'MPIDR_AFFINITY_LEVEL'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>    17 |         u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
>       |                            ^
> ../drivers/soc/samsung/exynos850-pmu.c:17:42: error: call to undeclared function 'read_cpuid_mpidr'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>    17 |         u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
>       |                                                 ^
> ../drivers/soc/samsung/exynos850-pmu.c:48:21: error: call to undeclared function 'MPIDR_AFFINITY_LEVEL'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>    48 |         u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
>       |                            ^
> ../drivers/soc/samsung/exynos850-pmu.c:48:42: error: call to undeclared function 'read_cpuid_mpidr'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
>    48 |         u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
>       |                                                 ^
> 4 errors generated.
> make[6]: *** [../scripts/Makefile.build:289: drivers/soc/samsung/exynos850-pmu.o] Error 1
> make[5]: *** [../scripts/Makefile.build:548: drivers/soc/samsung] Error 2
> make[4]: *** [../scripts/Makefile.build:548: drivers/soc] Error 2
> make[3]: *** [../scripts/Makefile.build:548: drivers] Error 2
> make[3]: *** Waiting for unfinished jobs....
> [ ... ]

Thank you! My bad.
I will check for the next series what I missed.

Thanks,
Alexey


^ permalink raw reply

* Re: [PATCH 2/2] arm64: dts: imx8dxl: Add SolidRun SoM and HummingBoard
From: Andrew Lunn @ 2026-04-09 12:11 UTC (permalink / raw)
  To: Josua Mayer
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
	Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Yazan Shhady, Mikhail Anikin, Alexander Dahl,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
In-Reply-To: <db41d119-2469-4107-94b5-b09e9bbbe9ec@solid-run.com>

> Would it be correct to change phy-mode on the mac to "rgmii",
> and leave switch port as is?

Yes, that is O.K. Please add a comment, say that the switch is
providing the delay.

	Andrew

^ permalink raw reply

* Re: [PATCH v1 1/2] dt-bindings: i2c: ls2x-i2c: Add clock- related properties
From: Krzysztof Kozlowski @ 2026-04-09 12:11 UTC (permalink / raw)
  To: Hongliang Wang
  Cc: Binbin Zhou, Andi Shyti, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, linux-i2c, devicetree, loongarch
In-Reply-To: <e10017ce-cda0-5b5e-8cd8-3488aef4cdb0@loongson.cn>

On 09/04/2026 14:03, Hongliang Wang wrote:
> 
> I have a question, the input clock of i2c controller can be described by 
> "clocks",
> but there is no existing attribute can describe the divisor of the input 
> clock,
> Can I define a new attribute named "clock-div" to describe it in DT 
> bindings?
> or do you have any standard solutions for the divisor problem? Thank you.
>

You should determine/calculate the divisor in the driver code, depending
on clocks and bus frequencies. You don't need a property for that, usually.

Best regards,
Krzysztof

^ permalink raw reply

* Re: [net-next v1 v1 1/5] dt-bindings: net: starfive,jh7110-dwmac: Remove JH8100
From: Andrew Lunn @ 2026-04-09 12:13 UTC (permalink / raw)
  To: Minda Chen
  Cc: Alexandre Torgue, Andrew Lunn, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Maxime Coquelin,
	Emil Renner Berthing, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-stm32@st-md-mailman.stormreply.com,
	devicetree@vger.kernel.org
In-Reply-To: <SHXPR01MB086305E0C766E8BB17AF18DCE6582@SHXPR01MB0863.CHNPR01.prod.partner.outlook.cn>

> Yes. 
> We (StarFive) stop developing on JH8100 now, And do NOT release the SoC outside.

Please add that to the commit message as the justification of removing
support.

	Andrew

^ permalink raw reply

* Re: [PATCH 3/3] arm64: dts: broadcom: bcm2712: Add the otp nodes to firmware
From: Krzysztof Kozlowski @ 2026-04-09 12:15 UTC (permalink / raw)
  To: Gregor Herburger
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
	Ray Jui, Scott Branden, Broadcom internal kernel review list,
	Eric Anholt, Stefan Wahren, Srinivas Kandagatla, devicetree,
	linux-rpi-kernel, linux-arm-kernel, linux-kernel
In-Reply-To: <adeVWKcQyfkKKY5J@gregor-framework>

On 09/04/2026 14:02, Gregor Herburger wrote:
> Hi Krzysztof,
> 
> thanks for reviewing.
> 
> On Thu, Apr 09, 2026 at 10:15:12AM +0200, Krzysztof Kozlowski wrote:
>> On Wed, Apr 08, 2026 at 10:00:17AM +0200, Gregor Herburger wrote:
>>> The Raspberry Pi 5 has two OTP registers (private and customer), add these
>>> to the devicetree.
>>
>> So this sentence confirms my question on bindings - your device
>> raspberrypi,bcm2835-firmware has these, thus you do not need these child
>> nodes at all. Neither compatibles.
> 
> I dont't think so. In my understanding the bcm2835-firmware does not
> provide the otp registers but only provides the interface to the
> registers. Though I don't know the details how this is done but [1] says
> that only BCM2712 has 512bits and the others (like bcm2711) have

Still the same. s/otp/interface/ so your device provides interface.

> 256bits. So both devicetrees have the raspberrypi,bcm2835-firmware node
> but only the bcm2712 has the raspberrypi,firmware-otp-private node while the 

Why does bcm2712 use bcm2835 compatible?

Nodes and properties are not a solution. See DTS101 question - "...
because my new device, which is compatible with an older one, does not
support ..." and answer: No.



> raspberrypi,firmware-otp-customer is available in all raspberrys.
> 
>> Drop entire DTS and binding patches.
> 
> If I drop the binding patch how to distinguish the variants? Should I
> add a SoC specific compatible? e.g. `raspberrypi,bcm2712-firmware` and
> use it in the firmware/raspberrypi driver to add the second otp region?

So you have different devices/variants? What is the "variant" here?

Writing-bindings asks you to have per device compatible. Why standard
rules do not apply here? (see also DTS101)

> 
> Also what I don't understand why we have all the bindings for

Neither do I.

> 'raspberrypi,firmware-clocks', 'raspberrypi,firmware-gpio',
> 'raspberrypi,firmware-reset', 'raspberrypi,firmware-poe-pwm' and
> 'raspberrypi,firmware-ts'. What is the difference between these devices
> and the otp registers. They are all accessed through the firmware.


Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH 2/2] arm64: dts: imx8dxl: Add SolidRun SoM and HummingBoard
From: Josua Mayer @ 2026-04-09 12:18 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
	Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Yazan Shhady, Mikhail Anikin, Alexander Dahl,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org
In-Reply-To: <aef0a8db-7a16-4620-87dc-d517be946cab@lunn.ch>

Am 09.04.26 um 14:11 schrieb Andrew Lunn:

>> Would it be correct to change phy-mode on the mac to "rgmii",
>> and leave switch port as is?
> Yes, that is O.K. Please add a comment, say that the switch is
> providing the delay.
Thanks!

^ permalink raw reply

* [PATCH v3 0/2] Add device tree binding for ts73xx-fpga
From: Phil Pemberton @ 2026-04-09 12:20 UTC (permalink / raw)
  To: Moritz Fischer, Xu Yilun, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: Tom Rix, Florian Fainelli, linux-fpga, devicetree, linux-kernel,
	Phil Pemberton

The driver for the Technologic Systems (EmbeddedTS) TS-7300 board's
onboard FPGA didn't have an OF match table. This prevented it from being
instantiated from a device tree. This is undesirable given EP93xx is
moving to device tree, and effectively prevents it from being used.
This patch series adds the OF match table and a device tree binding.

Changes since v2:
  - Fix subject line on patch 1 (Krzysztof)
  - Carry forward Reviewed-by tags

Changes since v1:
  - Use specific compatible "technologic,ts7300-fpga" instead of
    wildcard "technologic,ts73xx-fpga" (Krzysztof)
  - Fix subject line for dt-bindings patch (Krzysztof)
  - Simplify example in binding doc (Krzysztof)

Phil Pemberton (2):
  dt-bindings: fpga: Add Technologic Systems TS-7300 FPGA Manager
  fpga: ts73xx-fpga: add OF match table for device tree probing

 .../fpga/technologic,ts7300-fpga.yaml         | 36 +++++++++++++++++++
 drivers/fpga/ts73xx-fpga.c                    |  9 +++++
 2 files changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fpga/technologic,ts7300-fpga.yaml

-- 
2.43.0


^ permalink raw reply

* [PATCH v3 2/2] fpga: ts73xx-fpga: add OF match table for device tree probing
From: Phil Pemberton @ 2026-04-09 12:20 UTC (permalink / raw)
  To: Moritz Fischer, Xu Yilun, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: Tom Rix, Florian Fainelli, linux-fpga, devicetree, linux-kernel,
	Phil Pemberton
In-Reply-To: <20260409122016.3940462-1-philpem@philpem.me.uk>

The ts73xx-fpga driver currently only matches by platform device name,
which prevents it from being probed when the device is described in a
device tree. Add an of_device_id table so the driver can match against
the "technologic,ts7300-fpga" compatible string.

The TS-7350 and TS-7390 use different FPGAs with a different programming
interface, so while the driver is named "ts73xx-fpga", it doesn't apply
to them.

Signed-off-by: Phil Pemberton <philpem@philpem.me.uk>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/fpga/ts73xx-fpga.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/fpga/ts73xx-fpga.c b/drivers/fpga/ts73xx-fpga.c
index 4e1d2a4d3df4..3460e4809f86 100644
--- a/drivers/fpga/ts73xx-fpga.c
+++ b/drivers/fpga/ts73xx-fpga.c
@@ -11,6 +11,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
 #include <linux/iopoll.h>
@@ -119,9 +120,17 @@ static int ts73xx_fpga_probe(struct platform_device *pdev)
 	return PTR_ERR_OR_ZERO(mgr);
 }
 
+static const struct of_device_id ts73xx_fpga_of_match[] = {
+	{ .compatible = "technologic,ts7300-fpga" },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, ts73xx_fpga_of_match);
+
 static struct platform_driver ts73xx_fpga_driver = {
 	.driver	= {
 		.name	= "ts73xx-fpga-mgr",
+		.of_match_table = ts73xx_fpga_of_match,
 	},
 	.probe	= ts73xx_fpga_probe,
 };
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 1/2] dt-bindings: fpga: Add Technologic Systems TS-7300 FPGA Manager
From: Phil Pemberton @ 2026-04-09 12:20 UTC (permalink / raw)
  To: Moritz Fischer, Xu Yilun, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: Tom Rix, Florian Fainelli, linux-fpga, devicetree, linux-kernel,
	Phil Pemberton, Krzysztof Kozlowski
In-Reply-To: <20260409122016.3940462-1-philpem@philpem.me.uk>

Add device tree binding documentation for the Altera Cyclone II FPGA
found on Technologic Systems (now EmbeddedTS) TS-7300 boards, programmed
via the memory-mapped interface in the CPLD.

Signed-off-by: Phil Pemberton <philpem@philpem.me.uk>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
 .../fpga/technologic,ts7300-fpga.yaml         | 36 +++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/fpga/technologic,ts7300-fpga.yaml

diff --git a/Documentation/devicetree/bindings/fpga/technologic,ts7300-fpga.yaml b/Documentation/devicetree/bindings/fpga/technologic,ts7300-fpga.yaml
new file mode 100644
index 000000000000..c93e3a1a135b
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/technologic,ts7300-fpga.yaml
@@ -0,0 +1,36 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/fpga/technologic,ts7300-fpga.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Technologic Systems TS-7300 FPGA Manager
+
+maintainers:
+  - Florian Fainelli <f.fainelli@gmail.com>
+
+description:
+  FPGA manager for the Altera Cyclone II FPGA on Technologic Systems
+  TS-7300 board. The FPGA is programmed via the memory-mapped interface
+  implemented in the CPLD.
+
+properties:
+  compatible:
+    const: technologic,ts7300-fpga
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    fpga-mgr@13c00000 {
+        compatible = "technologic,ts7300-fpga";
+        reg = <0x13c00000 0x2>;
+    };
+...
-- 
2.43.0


^ permalink raw reply related

* [PATCH v1] arm64: dts: qcom: sm8750-mtp: Set sufficient voltage for panel nt37801
From: Ayushi Makhija @ 2026-04-09 12:21 UTC (permalink / raw)
  To: andersson, konrad.dybcio, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, dmitry.baryshkov
  Cc: Ayushi Makhija, linux-arm-msm, devicetree, linux-kernel,
	linux-arm-kernel, quic_rajeevny, quic_vproddut, Dmitry Baryshkov,
	Konrad Dybcio

The NT37801 Sepc V1.0 chapter "5.7.1 Power On Sequence" states
VDDI=1.65V~1.95V, so set sufficient voltage for panel nt37801.

Fixes: 4fca6849864d ("drm/panel: Add Novatek NT37801 panel driver")
Signed-off-by: Ayushi Makhija <ayushi.makhija@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
---
 arch/arm64/boot/dts/qcom/sm8750-mtp.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts
index 3837f6785320..6ba4e69bf377 100644
--- a/arch/arm64/boot/dts/qcom/sm8750-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sm8750-mtp.dts
@@ -462,7 +462,7 @@ vreg_l11b_1p0: ldo11 {
 
 		vreg_l12b_1p8: ldo12 {
 			regulator-name = "vreg_l12b_1p8";
-			regulator-min-microvolt = <1200000>;
+			regulator-min-microvolt = <1650000>;
 			regulator-max-microvolt = <1800000>;
 			regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
 			regulator-allow-set-load;
-- 
2.34.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox