Skip to content

lopper: assists: fix Zephyr combined-DTS overlay phandle merge - #800

Open
dbingi-amd wants to merge 1 commit into
devicetree-org:masterfrom
dbingi-amd:combined-dt_pr
Open

lopper: assists: fix Zephyr combined-DTS overlay phandle merge#800
dbingi-amd wants to merge 1 commit into
devicetree-org:masterfrom
dbingi-amd:combined-dt_pr

Conversation

@dbingi-amd

Copy link
Copy Markdown
Contributor

PR #790 merges the board .dtsi from the SDT folder directly into the domain tree inside Lopper, instead of emitting a separate board.overlay for Zephyr to apply later. That combined-DTS approach is correct, but it exposed a gap in what the existing lopper overlay APIs actually resolve.

When dtc compiles a plugin overlay, it records two kinds of phandle fixups. Global fixups under fixups (often 0xffffffff pointing at a fragment target like &gem0) are handled by _unwrap_overlay_tree() and _resolve_overlay_fixups(). Local fixups
under local_fixups (references to labels defined inside the same fragment, like phy-handle = <&phy0>) are not handled by those APIs at all.

That did not matter in the old flow, because Zephyr applied the overlay at build time and dtc fixed both kinds in one pass. After #790, the merge happens inside Lopper on an in-memory domain tree, so local fixups never get applied unless we do it explicitly. On top of that, _merge_node_into_tree() resolves properties immediately after copy, which can bind wrong phandle values before the tree is ready, and _unwrap_overlay_tree() leaves nested overlay children on /fragment@N/overlay/... paths instead of real domain paths.

This commit adds three helpers in zephyr_board_dt.py and reorders _merge_plugin_overlay() so local phandles are fixed after merge, without changing Lopper core.

  1. _remap_unwrapped_overlay_nodes() rewrites overlay node paths from fragment space (/fragment@0/overlay/...) to real domain paths before merge, so nested nodes land in the right place.
  2. _merge_overlay_node_deferred() replaces _merge_node_into_tree() for this path. It copies overlay properties onto domain nodes but skips immediate prop.resolve(), so phandles are not finalized too early.
  3. _finalize_plugin_overlay_phandles() applies what core does not: it uses overlay symbols to register labels on domain nodes, reads local_fixups to find which properties need rewriting, runs main_tree.resolve(), then replaces temporary
    overlay phandle numbers with the correct domain phandles — only for properties dtc flagged in local_fixups, so unrelated integer properties are left alone.

Lopper core overlay APIs resolve global fixups but not plugin
__local_fixups__, so in-fragment phandles (e.g. phy-handle) could
point at the wrong node after merging board overlay into the domain
tree. Handle this in zephyr_board_dt only: remap nested unwrapped
fragment paths, defer prop resolve until children are merged, and
apply __symbols__/__local_fixups__ post-merge fixup.

Signed-off-by: Bingi Dinesh kumar <dineshkumar.bingi@amd.com>
@dbingi-amd

Copy link
Copy Markdown
Contributor Author

@kedareswararao, please review the changes

@zeddii

zeddii commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Thanks @dbingi-amd — your diagnosis was right: after #790 merges the board .dtsi in-memory, dtc's __local_fixups__ (in-overlay &label references) were never re-based, because core only handled the global __fixups__. That's a real gap, and it turned out to be a core one rather than something the Zephyr assist should carry — so I've added it to core (on master):

  • _unwrap_overlay_tree now parses __local_fixups__ into (holder, prop, byte_offset, target) entries, and _resolve_overlay_local_fixups rewrites the referenced cell by dtc byte offset (idx = byte_offset // 4) to the target overlay node's phandle in the merged tree. Because it's offset-based, a specifier cell in a multi-cell property (clocks = <&clk0 5>, gpios, interrupt-map) is never touched — the value-match approach in _finalize_plugin_overlay_phandles would silently re-bind those.
  • _resolve_overlay_fixups now resolves global + local in one call, so a caller that unwrapped an overlay can't drop the local set.
  • It runs implicitly wherever an overlay is applied (like the global fixups already do), including the Zephyr combined-DTS path — zephyr_board_dt.py on master already passes local_fixups through, so once you rebase, the in-overlay references resolve for free.

So on this PR you can drop the parallel path entirely — _finalize_plugin_overlay_phandles, _merge_overlay_node_deferred, and _remap_unwrapped_overlay_nodes — and rely on the core resolution (same play as #803's rename()). If there's a case the core path doesn't cover once you've rebased, point me at it and I'll extend it.

Thanks again — these keep surfacing gaps worth fixing at the root.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants