162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci========================
462306a36Sopenharmony_ciDevicetree Overlay Notes
562306a36Sopenharmony_ci========================
662306a36Sopenharmony_ci
762306a36Sopenharmony_ciThis document describes the implementation of the in-kernel
862306a36Sopenharmony_cidevice tree overlay functionality residing in drivers/of/overlay.c and is a
962306a36Sopenharmony_cicompanion document to Documentation/devicetree/dynamic-resolution-notes.rst[1]
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ciHow overlays work
1262306a36Sopenharmony_ci-----------------
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciA Devicetree's overlay purpose is to modify the kernel's live tree, and
1562306a36Sopenharmony_cihave the modification affecting the state of the kernel in a way that
1662306a36Sopenharmony_ciis reflecting the changes.
1762306a36Sopenharmony_ciSince the kernel mainly deals with devices, any new device node that result
1862306a36Sopenharmony_ciin an active device should have it created while if the device node is either
1962306a36Sopenharmony_cidisabled or removed all together, the affected device should be deregistered.
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciLets take an example where we have a foo board with the following base tree::
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci    ---- foo.dts ---------------------------------------------------------------
2462306a36Sopenharmony_ci	/* FOO platform */
2562306a36Sopenharmony_ci	/dts-v1/;
2662306a36Sopenharmony_ci	/ {
2762306a36Sopenharmony_ci		compatible = "corp,foo";
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci		/* shared resources */
3062306a36Sopenharmony_ci		res: res {
3162306a36Sopenharmony_ci		};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci		/* On chip peripherals */
3462306a36Sopenharmony_ci		ocp: ocp {
3562306a36Sopenharmony_ci			/* peripherals that are always instantiated */
3662306a36Sopenharmony_ci			peripheral1 { ... };
3762306a36Sopenharmony_ci		};
3862306a36Sopenharmony_ci	};
3962306a36Sopenharmony_ci    ---- foo.dts ---------------------------------------------------------------
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ciThe overlay bar.dts,
4262306a36Sopenharmony_ci::
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci    ---- bar.dts - overlay target location by label ----------------------------
4562306a36Sopenharmony_ci	/dts-v1/;
4662306a36Sopenharmony_ci	/plugin/;
4762306a36Sopenharmony_ci	&ocp {
4862306a36Sopenharmony_ci		/* bar peripheral */
4962306a36Sopenharmony_ci		bar {
5062306a36Sopenharmony_ci			compatible = "corp,bar";
5162306a36Sopenharmony_ci			... /* various properties and child nodes */
5262306a36Sopenharmony_ci		};
5362306a36Sopenharmony_ci	};
5462306a36Sopenharmony_ci    ---- bar.dts ---------------------------------------------------------------
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ciwhen loaded (and resolved as described in [1]) should result in foo+bar.dts::
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci    ---- foo+bar.dts -----------------------------------------------------------
5962306a36Sopenharmony_ci	/* FOO platform + bar peripheral */
6062306a36Sopenharmony_ci	/ {
6162306a36Sopenharmony_ci		compatible = "corp,foo";
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		/* shared resources */
6462306a36Sopenharmony_ci		res: res {
6562306a36Sopenharmony_ci		};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		/* On chip peripherals */
6862306a36Sopenharmony_ci		ocp: ocp {
6962306a36Sopenharmony_ci			/* peripherals that are always instantiated */
7062306a36Sopenharmony_ci			peripheral1 { ... };
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci			/* bar peripheral */
7362306a36Sopenharmony_ci			bar {
7462306a36Sopenharmony_ci				compatible = "corp,bar";
7562306a36Sopenharmony_ci				... /* various properties and child nodes */
7662306a36Sopenharmony_ci			};
7762306a36Sopenharmony_ci		};
7862306a36Sopenharmony_ci	};
7962306a36Sopenharmony_ci    ---- foo+bar.dts -----------------------------------------------------------
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciAs a result of the overlay, a new device node (bar) has been created
8262306a36Sopenharmony_ciso a bar platform device will be registered and if a matching device driver
8362306a36Sopenharmony_ciis loaded the device will be created as expected.
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciIf the base DT was not compiled with the -@ option then the "&ocp" label
8662306a36Sopenharmony_ciwill not be available to resolve the overlay node(s) to the proper location
8762306a36Sopenharmony_ciin the base DT. In this case, the target path can be provided. The target
8862306a36Sopenharmony_cilocation by label syntax is preferred because the overlay can be applied to
8962306a36Sopenharmony_ciany base DT containing the label, no matter where the label occurs in the DT.
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciThe above bar.dts example modified to use target path syntax is::
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci    ---- bar.dts - overlay target location by explicit path --------------------
9462306a36Sopenharmony_ci	/dts-v1/;
9562306a36Sopenharmony_ci	/plugin/;
9662306a36Sopenharmony_ci	&{/ocp} {
9762306a36Sopenharmony_ci		/* bar peripheral */
9862306a36Sopenharmony_ci		bar {
9962306a36Sopenharmony_ci			compatible = "corp,bar";
10062306a36Sopenharmony_ci			... /* various properties and child nodes */
10162306a36Sopenharmony_ci		}
10262306a36Sopenharmony_ci	};
10362306a36Sopenharmony_ci    ---- bar.dts ---------------------------------------------------------------
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ciOverlay in-kernel API
10762306a36Sopenharmony_ci--------------------------------
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciThe API is quite easy to use.
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci1) Call of_overlay_fdt_apply() to create and apply an overlay changeset. The
11262306a36Sopenharmony_ci   return value is an error or a cookie identifying this overlay.
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci2) Call of_overlay_remove() to remove and cleanup the overlay changeset
11562306a36Sopenharmony_ci   previously created via the call to of_overlay_fdt_apply(). Removal of an
11662306a36Sopenharmony_ci   overlay changeset that is stacked by another will not be permitted.
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ciFinally, if you need to remove all overlays in one-go, just call
11962306a36Sopenharmony_ciof_overlay_remove_all() which will remove every single one in the correct
12062306a36Sopenharmony_ciorder.
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ciThere is the option to register notifiers that get called on
12362306a36Sopenharmony_cioverlay operations. See of_overlay_notifier_register/unregister and
12462306a36Sopenharmony_cienum of_overlay_notify_action for details.
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ciA notifier callback for OF_OVERLAY_PRE_APPLY, OF_OVERLAY_POST_APPLY, or
12762306a36Sopenharmony_ciOF_OVERLAY_PRE_REMOVE may store pointers to a device tree node in the overlay
12862306a36Sopenharmony_cior its content but these pointers must not persist past the notifier callback
12962306a36Sopenharmony_cifor OF_OVERLAY_POST_REMOVE.  The memory containing the overlay will be
13062306a36Sopenharmony_cikfree()ed after OF_OVERLAY_POST_REMOVE notifiers are called.  Note that the
13162306a36Sopenharmony_cimemory will be kfree()ed even if the notifier for OF_OVERLAY_POST_REMOVE
13262306a36Sopenharmony_cireturns an error.
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ciThe changeset notifiers in drivers/of/dynamic.c are a second type of notifier
13562306a36Sopenharmony_cithat could be triggered by applying or removing an overlay.  These notifiers
13662306a36Sopenharmony_ciare not allowed to store pointers to a device tree node in the overlay
13762306a36Sopenharmony_cior its content.  The overlay code does not protect against such pointers
13862306a36Sopenharmony_ciremaining active when the memory containing the overlay is freed as a result
13962306a36Sopenharmony_ciof removing the overlay.
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciAny other code that retains a pointer to the overlay nodes or data is
14262306a36Sopenharmony_ciconsidered to be a bug because after removing the overlay the pointer
14362306a36Sopenharmony_ciwill refer to freed memory.
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ciUsers of overlays must be especially aware of the overall operations that
14662306a36Sopenharmony_cioccur on the system to ensure that other kernel code does not retain any
14762306a36Sopenharmony_cipointers to the overlay nodes or data.  Any example of an inadvertent use
14862306a36Sopenharmony_ciof such pointers is if a driver or subsystem module is loaded after an
14962306a36Sopenharmony_cioverlay has been applied, and the driver or subsystem scans the entire
15062306a36Sopenharmony_cidevicetree or a large portion of it, including the overlay nodes.
151