Re: [RFC PATCH 64/77] dtc: Add support for references by path involving orphan nodes

David Gibson <[email protected]> Thu, 15 Jan 2026 18:01:39 +1100
Newsgroups org.kernel.vger.devicetree-spec,org.kernel.vger.devicetree-compiler,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-kernel
Message-ID <aWiQ05zlfPfcIaZk@zatzit>
On Mon, Jan 12, 2026 at 03:19:54PM +0100, Herve Codina wrote:
> Referencing a sub-node from an orphan node using a path is needed.
> 
> Indeed, using the following snippet:
> --- 8< ---
> /addon/;
> 
> &node1 {
> 	subnode {
> 		foo-phandle = <&foo_label>;
> 	};
> };
> 
> &node2 {
> 	foo_label: foo {
> 		prop = <1>;
> 	};
> };
> --- 8< ---
> 
> Even if node2 is an orphan node, foo is a local node. foo-phandle
> references the foo node using a label.

Another option would be to eliminate the idea of local references, and
require a symbol be attached to things that you want to reference by
label.


> 
> Once converted to a dtb, the label is lost. Only the phandle of the foo
> node is used in the foo-phandle property and this property is marked
> FDT_REF_LOCAL.
> 
> Converting back this dtb to a dts, the marked local phandle should be
> translated to a path to the related local node.
> 
> The issue is that this local node is not in a root device tree. We need
> to identify the orphan node the foo node belongs to.
> 
> We cannot use a path starting by '/'. This kind of path identify node in
> the root tree.
> 
> This new syntax allows to identify the orphan node in a path:
>   $<orphan_name>/<path>
> 
> This leads to a reference by path in the form &{$<orphan_name>/<path>}.
> 
> Using the previous example, those both phandles points to the same node:
>   foo-phandle1 = <&foo_label>;    /* Reference by label */
>   foo-phandle2 = <&{$node2/foo}>; /* Reference by path */
> 
> When the dtb is converted back to a dts, the marked local phandle
> involving subnode available from orphan nodes can be translated to a
> reference by path thanks to the new syntax.
> 
> Add support for this &{$<orphan_name>/<path>} syntax to reference by
> path a local node from an orphan node.
> 
> Signed-off-by: Herve Codina <[email protected]>
> ---
>  dtc-lexer.l  |  7 +++++++
>  dtc-parser.y | 19 +++++++++++++++++++
>  dtc.c        | 22 ++++++++++++++++++++--
>  livetree.c   | 14 +++++++++++++-
>  treesource.c |  3 ++-
>  5 files changed, 61 insertions(+), 4 deletions(-)
> 
> diff --git a/dtc-lexer.l b/dtc-lexer.l
> index cb616f9..540bfdf 100644
> --- a/dtc-lexer.l
> +++ b/dtc-lexer.l
> @@ -239,6 +239,13 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...);
>  			return DT_PATH_REF;
>  		}
>  
> +<*>"&{\$"{LABEL}([/]{PATHCHAR}*)?\}  {	/* orphan path reference */
> +			yytext[yyleng-1] = '\0';
> +			DPRINT("Ref orphan path: %s\n", yytext+1);
> +			yylval.labelref = xstrdup(yytext+2);
> +			return DT_ORPHAN_PATH_REF;
> +		}
> +
>  <BYTESTRING>[0-9a-fA-F]{2} {
>  			yylval.byte = strtol(yytext, NULL, 16);
>  			DPRINT("Byte: %02x\n", (int)yylval.byte);
> diff --git a/dtc-parser.y b/dtc-parser.y
> index 7f8c294..9d619cd 100644
> --- a/dtc-parser.y
> +++ b/dtc-parser.y
> @@ -111,6 +111,7 @@ static struct node *parser_get_node_by_ref(struct node *dt, struct node *orphanl
>  %token <labelref> DT_LABEL
>  %token <labelref> DT_LABEL_REF
>  %token <labelref> DT_PATH_REF
> +%token <labelref> DT_ORPHAN_PATH_REF
>  %token DT_INCBIN
>  
>  %type <data> propdata
> @@ -589,6 +590,24 @@ arrayprefix:
>  				ERROR(&@2, "References are only allowed in "
>  					    "arrays with 32-bit elements.");
>  
> +			$$.data = data_append_integer($1.data, val, $1.bits);
> +		}
> +	| arrayprefix DT_ORPHAN_PATH_REF
> +		{
> +			uint64_t val = ~0ULL >> (64 - $1.bits);
> +
> +			if ($1.bits == 32) {
> +				if (!(last_header_flags & DTSF_ADDON))
> +					ERROR(&@2, "Orphan path reference %s supported only in addon", $2);
> +
> +				$1.data = data_add_marker($1.data,
> +							  REF_PHANDLE,
> +							  $2);
> +			} else {
> +				ERROR(&@2, "References are only allowed in "
> +					    "arrays with 32-bit elements.");
> +			}
> +
>  			$$.data = data_append_integer($1.data, val, $1.bits);
>  		}
>  	| arrayprefix DT_LABEL
> diff --git a/dtc.c b/dtc.c
> index 63725bf..72d85e4 100644
> --- a/dtc.c
> +++ b/dtc.c
> @@ -48,13 +48,31 @@ static void fill_fullpaths(struct node *tree, const char *prefix)
>  static void dti_fill_fullpaths(struct dt_info *dti)
>  {
>  	struct node *orphan;
> +	struct node *child;
>  
>  	/* Fill fullpaths for the root node */
>  	if (dti->dt)
>  		fill_fullpaths(dti->dt, "");
>  
> -	for_each_orphan(dti->orphanlist, orphan)
> -		fill_fullpaths(orphan, "__orphan__/");
> +	/* Fill fullpaths for orphan nodes */
> +	for_each_orphan(dti->orphanlist, orphan) {
> +		if (orphan->name[0] == '\0')
> +			die("orphan node has an empty name\n");
> +
> +		/*
> +		 * An orphan node name is set with its reference.
> +		 * Its name is in the form "&xxxxxx".
> +		 * For its full path, we use "$xxxxx" to make a clear
> +		 * distinction between a reference (&xxxx) where a resolution
> +		 * could be involved vs a "simple" path where we just need to
> +		 * identified the orphan ($xxxx).
> +		 */
> +		xasprintf(&orphan->fullpath, "$%s", orphan->name + 1);
> +		orphan->basenamelen = strlen(orphan->name);
> +
> +		for_each_child(orphan, child)
> +			fill_fullpaths(child, orphan->fullpath);
> +	}
>  }
>  
>  /* Usage related data. */
> diff --git a/livetree.c b/livetree.c
> index 59b912d..263da1f 100644
> --- a/livetree.c
> +++ b/livetree.c
> @@ -804,7 +804,19 @@ static struct node *get_node_by_ref(struct node *tree, const char *ref)
>  			path = slash + 1;
>  		}
>  
> -		target = get_node_by_label(tree, label);
> +		if (label[0] == '$' && tree->name[0] == '&') {
> +			/*
> +			 * We search for an orphan and the given tree is an
> +			 * orphan. Use the given tree only if it matches the
> +			 * expected orphan.
> +			 */
> +			if (streq(label + 1, tree->name + 1))
> +				target = tree;
> +			else
> +				target = NULL;
> +		} else {
> +			target = get_node_by_label(tree, label);
> +		}
>  
>  		free(buf);
>  
> diff --git a/treesource.c b/treesource.c
> index 71dbd5f..44de0db 100644
> --- a/treesource.c
> +++ b/treesource.c
> @@ -278,7 +278,8 @@ static void write_propval(FILE *f, struct property *prop)
>  					break;
>  
>  			if (m_phandle) {
> -				if (m_phandle->ref[0] == '/')
> +				if (m_phandle->ref[0] == '/' /* Root node */ ||
> +				    m_phandle->ref[0] == '$' /* Orphan node */)
>  					fprintf(f, "&{%s}", m_phandle->ref);
>  				else
>  					fprintf(f, "&%s", m_phandle->ref);
> -- 
> 2.52.0
> 
> 

-- 
David Gibson (he or they)	| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you, not the other way
				| around.
http://www.ozlabs.org/~dgibson
signature.asc (application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmlokNIACgkQzQJF27ox
2GfW7A//bfWPutOealZSddCNE40ylqEjvnjmn3FYB7MsRaXcMNjzF4lTziEPmx7U
6Mcs+fLEifoplX3o2/pJXNJrELfKe8IpM5EbbHs8XJ5jrv50oJOGfnzu/jzyUgGL
0+Vx/6tMcUnusoF68Rttg7fFwKlupcXYKnX7CTfQgCX+tUXdGSIETBeoRVRuYvM2
xSE1QQrtT4L1y4ykvRuVNY6MieXeUYKFlqM7Azgi5JuVjY2UR/uR/dIgZowoE/kl
plSjQr3t19+EEmANGENKc4ewht9thuQKkeEeYBvNu1AfxZvRV+FmtI/Gy78f+FBX
OHFbP7rIMJ7qXTzWAjV3lPYfWE/OI7CTjeRqLvdjdbkF2LXBAkW2/vfbMjg3JIwv
4e38cfsMPy59ETuFCl7Q/9/gajY+QnYkTvlZeRemJ/hqGS4dXa1Yeq7nJNmkcMcc
yPTv9tCASAW7wQ3ndIZisa/yWEYQOy6/6orr65xlJWVtmUHFMqeuKqapDs9TDmAV
OuDMHZHNzZDRIFc+gxiK81nf98XGQtd+MGc1qwMsGpncmkm9sjTIsUvQK71PF4G+
v9yksgM8BvwAPDT/+XqFltHsr9sA2tv6ctPRFF2KpY2Tgg6Vlf8Nuly4S8B4Wcc4
y2H8rEr3ggMdIKNfVJPrEAidyGFocmV7IVJr4KtCDPBCT62qbHQ=
=gW9P
-----END PGP SIGNATURE-----