.. _device_tree_build_developer_note:

Device Tree Build System and Custom Overlays
=============================================

.. IMPORTANT::
    This developer note is applicable to J722S devices with SDP 8.0.0. The device tree build system allows you to customize hardware initialization by enabling or disabling peripherals using device tree overlays.

Introduction
------------

The QNX BSP includes support for building custom startup files that use device tree (DTS) and device tree overlays (DTSO) to configure which peripherals are initialized. This feature allows you to:

- Build with the default hardware configuration (all devices enabled)
- Build with specific peripherals disabled via overlays
- Build with specific peripherals enabled via overlays
- Customize the QNX hardware initialization (``hw_init.c``) based on your device tree configuration

This guide explains how to use the build system to generate a custom startup file with your chosen device tree configuration. It assumes that the device tree source files already exist in your repository.

Device Tree Files Location
---------------------------

For J722S devices, device tree files are located in ``${PSDK_QNX_PATH}/qnx/utils/dt/dts/j722s/``:

**Base Device Tree Files:**

- **Minimal DTS**: ``j722s-hw-init.dts`` — Contains only the nodes required by QNX hardware initialization. This is the default base DTS used when building with device tree overlays.
- **Full Preprocessed DTS**: ``k3-j722s-qnx-preprocessed.dts`` — The complete device tree with all includes expanded. This file is provided for reference and debugging purposes.

**Overlay Files:**

Device tree overlays are located in ``${PSDK_QNX_PATH}/qnx/utils/dt/dts/j722s/overlay/``. Overlay files follow a naming convention:

- **Enable overlays**: ``enable_<device>.dtso`` — Enables the specified device (sets ``status = "okay"``)
- **Disable overlays**: ``disable_<device>.dtso`` — Disables the specified device (sets ``status = "disabled"``)

For example:

- ``enable_dss0.dtso`` and ``disable_dss0.dtso`` — Control the DSS0 display subsystem
- ``enable_gpu.dtso`` and ``disable_gpu.dtso`` — Control the GPU
- ``enable_main_i2c0.dtso`` and ``disable_main_i2c0.dtso`` — Control I2C0 controller

There are approximately 28 enable/disable overlay pairs available for J722S devices, covering common peripherals such as display, GPU, USB, SD card, Ethernet, and serial interfaces.

Available Devices
~~~~~~~~~~~~~~~~~

The following devices can be controlled via overlays for J722S:

- **Display**: dss0, dss1
- **Compute**: gpu
- **USB**: usb0, usb1, usbss0, usbss1
- **Storage**: sdhci0, sdhci1, ospi0
- **Serial**: Main I2C (main_i2c0, main_i2c1, main_i2c2)
- **Networking**: Ethernet (cpsw3g, cpsw3g_mdio)
- **High-Speed**: Serdes (serdes0, serdes_wiz0)
- **Pin Control**: Various peripheral pin configurations
- **Clocks and PHY**: Device clock and PHY configurations

Building Without Device Tree (Default Mode)
--------------------------------------------

By default, the BSP builds without device tree infrastructure. In this mode:

- All devices are enabled (legacy behavior)
- No device tree headers are generated
- Device tree overlays are not applied
- The build is backward compatible with existing configurations

To build without device tree:

.. code:: bash

    cd ${PSDK_QNX_PATH}
    make all SOC=j722s

Alternatively, to build only the BSP:

.. code:: bash

    make bsp SOC=j722s

This generates a startup file with all peripherals initialized in hardware.

Building With Base Device Tree (No Overlays)
---------------------------------------------

To build with the minimal device tree configuration without any overlay modifications, use the sentinel value ``base``:

.. code:: bash

    cd ${PSDK_QNX_PATH}
    make all SOC=j722s DTS_OVERLAY=base

Alternatively, to build only the BSP:

.. code:: bash

    make bsp SOC=j722s DTS_OVERLAY=base

This builds using the minimal device tree (``j722s-hw-init.dts``) without any overlay modifications. The special value ``base`` enables the device tree infrastructure and defines the ``USE_DT`` preprocessor macro, but uses the base DTS directly without applying any overlays.

Building With Device Tree and Overlays
---------------------------------------

To customize the hardware configuration using overlays, specify the overlay files via the ``DTS_OVERLAY`` variable:

**Single overlay:**

.. code:: bash

    cd ${PSDK_QNX_PATH}
    make all SOC=j722s DTS_OVERLAY=disable_dss0.dtso

**Multiple overlays (comma-separated):**

.. code:: bash

    cd ${PSDK_QNX_PATH}
    make all SOC=j722s DTS_OVERLAY=disable_dss0.dtso,disable_gpu.dtso

The overlays are applied in order to the base device tree. The resulting combined device tree is used to generate the hardware initialization header, which is then compiled into the startup file. Specifying ``DTS_OVERLAY`` with overlay files automatically enables device tree infrastructure and defines the ``USE_DT`` preprocessor macro.

Overlay File Selection
----------------------

When selecting which overlays to apply, keep the following in mind:

- **Enable overlays** set a device's status to ``"okay"`` (initialized and functional)
- **Disable overlays** set a device's status to ``"disabled"`` (not initialized)
- Use enable overlays to re-enable devices that should be functional
- Use disable overlays to exclude devices that your system does not require

For example, if you have a minimal system that only requires Ethernet and serial communication, you might build with:

.. code:: bash

    make all SOC=j722s DTS_OVERLAY=disable_dss0.dtso,disable_gpu.dtso,disable_usb0.dtso,disable_usb1.dtso

This disables the display subsystem, GPU, and USB controllers, reducing power consumption and boot time.

Overlay Constraints and Validation
-----------------------------------

**Important Constraint:** You cannot mix an enable overlay and a disable overlay for the same device in a single build. For example, the following command is invalid:

.. code:: bash

    # INVALID - do not mix enable and disable for same device:
    make all SOC=j722s DTS_OVERLAY=enable_dss0.dtso,disable_dss0.dtso

Validating Overlays Before Building
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Before building, you can validate your overlay list to ensure there are no conflicting enable/disable pairs. Use the validation script:

.. code:: bash

    # Validate a single overlay:
    utils/dt/scripts/validate_overlay_conflicts.sh "disable_dss0.dtso"

    # Validate multiple overlays:
    utils/dt/scripts/validate_overlay_conflicts.sh "disable_dss0.dtso disable_gpu.dtso"

    # Using the same format as DTS_OVERLAY (space-separated):
    utils/dt/scripts/validate_overlay_conflicts.sh "disable_dss0.dtso disable_gpu.dtso enable_main_i2c0.dtso"

**Successful validation** (exit code 0):

.. code:: bash

    $ utils/dt/scripts/validate_overlay_conflicts.sh "disable_dss0.dtso enable_main_i2c0.dtso"
    # Script exits silently with code 0
    $ echo $?
    0

**Validation failure with conflicting overlays** (exit code 1):

.. code:: bash

    $ utils/dt/scripts/validate_overlay_conflicts.sh "enable_dss0.dtso disable_dss0.dtso"
    ERROR: Conflicting overlays for node 'dss0':
      - enable_dss0.dtso
      - disable_dss0.dtso

    ERROR: Found 1 conflicting overlay pair(s).
    Remove either the enable_ or disable_ overlay for each conflicting node.
    $ echo $?
    1

If validation fails, revise your overlay list to remove the conflicting pairs and try again.

Make Clean Between Builds
--------------------------

.. IMPORTANT::
    When switching between different build modes (legacy → DT, DT → legacy, or changing overlays), you **MUST** run ``make clean`` to delete previously generated device tree headers. Otherwise, the old ``devicetree_generated.h`` will be used and your new overlay settings will not take effect.

**Example: Switching from overlay mode to legacy mode:**

.. code:: bash

    # Build 1: With overlays
    make all SOC=j722s DTS_OVERLAY=disable_dss0.dtso,disable_gpu.dtso

    # Clean before switching modes
    make clean

    # Build 2: Back to legacy mode (no DT)
    make all SOC=j722s

**Example: Switching from legacy to base DT mode:**

.. code:: bash

    # Build 1: Legacy mode (no DT)
    make all SOC=j722s

    # Clean before enabling DT
    make clean

    # Build 2: With base DT only
    make all SOC=j722s DTS_OVERLAY=base

Build Examples
--------------

**Example 1: Disable Display and GPU**

Disable the display subsystem and GPU to reduce power consumption:

.. code:: bash

    cd ${PSDK_QNX_PATH}
    utils/dt/scripts/validate_overlay_conflicts.sh "disable_dss0.dtso disable_dss1.dtso disable_gpu.dtso"
    make all SOC=j722s DTS_OVERLAY=disable_dss0.dtso,disable_dss1.dtso,disable_gpu.dtso

**Example 2: Enable Minimal Interfaces**

Build with only essential interfaces (Ethernet and UART):

.. code:: bash

    cd ${PSDK_QNX_PATH}
    # Build defaults to enabling basic interfaces; disable others as needed
    utils/dt/scripts/validate_overlay_conflicts.sh "disable_dss0.dtso disable_gpu.dtso disable_usb0.dtso disable_usb1.dtso"
    make all SOC=j722s DTS_OVERLAY=disable_dss0.dtso,disable_gpu.dtso,disable_usb0.dtso,disable_usb1.dtso

**Example 3: Enable Additional Interfaces**

If the default build doesn't enable certain required interfaces, use enable overlays:

.. code:: bash

    cd ${PSDK_QNX_PATH}
    utils/dt/scripts/validate_overlay_conflicts.sh "enable_main_i2c2.dtso enable_sdhci1.dtso"
    make all SOC=j722s DTS_OVERLAY=enable_main_i2c2.dtso,enable_sdhci1.dtso

Configuring Build Files and User Scripts for Disabled Devices
---------------------------------------------------------------

When you build a startup with specific devices disabled via overlays, the corresponding resource manager (RM) processes launched in the build file and user script must be synchronized with your device tree configuration. Mismatches between disabled devices and running RMs will cause errors during boot.

Overview
~~~~~~~~

The device tree overlays define which hardware devices are initialized at the bootloader level. However, QNX processes (resource managers, and display servers) are launched separately:

- **Build file** (``bsp_800_j722s/images/j722s-evm-ti.build``) — Defines RMs that run before QNX boots
- **User script** (``scripts/user_j722s.sh``) — Defines resource managers and services that run after QNX boots

If a resource manager tries to access a disabled device, boot will fail or hang. Therefore, when you disable a device via overlays, you must comment out the corresponding launcher in both the build file and user script.

Device Launcher Mapping
~~~~~~~~~~~~~~~~~~~~~~~

The following table maps each disableable device to its disable overlay and the corresponding launcher lines:


+-------------------+--------------------------+------------------------------------------+---------------------+
| Device Name       | Disable Overlay          | Build File Launcher                      | User.sh RM/         |
+===================+==========================+==========================================+=====================+
| **I2C 0 (Main)**  | disable_main_i2c0.dtso   | ``i2c-tda4 -p0x20000000 -i193``          | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| I2C 0 Pins        | disable_main_i2c0_pins   | (part of i2c0 above)                     | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| I2C 1 (Main)      | disable_main_i2c1.dtso   | (commented - shared with R5F)            | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| I2C 2 (Main)      | disable_main_i2c2.dtso   | (commented - not enabled)                | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| **eMMC**          | disable_sdhci0.dtso      | ``devb-sdmmc-am65x addr=0x0fa10000``     | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| **SD Card**       | disable_sdhci1.dtso      | ``devb-sdmmc-am65x addr=0x0fa00000``     | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| MMC1 Power        | disable_vdd_mmc1.dtso    | (part of sdhci)                          | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| **DSS0 Display**  | disable_dss0.dtso        | (not launched)                           | ``screen -c ...``   |
+-------------------+--------------------------+------------------------------------------+---------------------+
| DSS0 VP1 Clock    | disable_dss0_vp1_clk.dtso| (not launched)                           | ``screen -c ...``   |
+-------------------+--------------------------+------------------------------------------+---------------------+
| **DSS1 Display**  | disable_dss1.dtso        | (not launched)                           | ``screen -c ...``   |
+-------------------+--------------------------+------------------------------------------+---------------------+
| DSS Clock Control | disable_dss_clk_ctrl.dtso| (not launched)                           | ``screen -c ...``   |
+-------------------+--------------------------+------------------------------------------+---------------------+
| **GPU**           | disable_gpu.dtso         | (not launched)                           | ``screen -c ...``   |
+-------------------+--------------------------+------------------------------------------+---------------------+
| **USB3SS0 (DWC3)**| disable_usbss0.dtso      | ``io-usb-otg dwc3 ioport=0x31000000``    | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| USB0 PHY Control  | disable_usb0_phy_ctrl    | (part of usbss0 above)                   | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
|**USB3SS1 (CDNS3)**| disable_usbss1.dtso      | ``io-usb-otg cdns3 ioport=0x31210000``   | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| USB1 Pins         | disable_main_usb1_pins   | (part of usbss1 above)                   | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+
| **OSPI NOR Flash**| disable_ospi0.dtso       | (commented - not enabled)                | (none)              |
+-------------------+--------------------------+------------------------------------------+---------------------+


Build File Configuration Examples
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**Example 1: Disable Display and GPU**

If you build with ``DTS_OVERLAY=disable_dss0.dtso,disable_dss1.dtso,disable_gpu.dtso``, display devices are disabled at the DT level. No changes are needed in the build file since dss and gpu are not launched there. However, if you launch the ``screen`` service in ``user.sh``, it must be disabled:

.. code:: bash

    # user_j722s.sh - comment out the screen service
    # screen -c graphics-virtual-dpy.conf

**Example 2: Disable I2C0**

If you build with ``DTS_OVERLAY=disable_main_i2c0.dtso``, I2C devices will not be initialized. Comment out the i2c RM in the build file:

.. code:: bash

    # j722s-evm-ti.build - comment out i2c0 RM
    # i2c-tda4 -p0x20000000 -i193

After disabling I2C0, any I2C bus operations in applications will fail. The i2c device nodes will not be created.

**Example 3: Minimal Boot - Disable Most Peripherals**

For a minimal system that boots QNX without display, GPUs, or USB:

.. code:: bash

    # Build command
    make all SOC=j722s DTS_OVERLAY=disable_dss0.dtso,disable_dss1.dtso,disable_gpu.dtso,disable_usbss0.dtso,disable_usbss1.dtso

    # j722s-evm-ti.build - comment out USB RMs
    # io-usb-otg dwc3 ioport=0x31000000
    # io-usb-otg cdns3 ioport=0x31210000

    # user_j722s.sh - comment out display service
    # screen -c graphics-virtual-dpy.conf

This configuration keeps only I2C, eMMC, and SD card enabled, suitable for headless embedded systems.

**Example 4: Disable SD Card Only**

If your system uses only eMMC (no removable SD card), disable SD:

.. code:: bash

    # Build command
    make all SOC=j722s DTS_OVERLAY=disable_sdhci1.dtso,disable_vdd_mmc1.dtso

    # j722s-evm-ti.build - comment out SD card RM
    # devb-sdmmc-am65x addr=0x0fa00000

    # Keep eMMC RM enabled
    devb-sdmmc-am65x addr=0x0fa10000

Device Dependencies and Constraints
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Some devices have interdependencies that you should be aware of:

- **eMMC/SD Card**: Both controllers use the same power domain (``vdd_mmc1``). Disabling MMC1 power affects both. Disabling ``sdhci1`` alone (SD card) does not require disabling ``vdd_mmc1`` if eMMC is still in use.

- **USB SerDes**: Both USB3SS controllers depend on shared SerDes PHY resources (``serdes0``, ``serdes_refclk``, ``serdes_wiz0``). Disabling SerDes overlays (``disable_serdes0.dtso``, ``disable_serdes_wiz0.dtso``) will break USB functionality. Conversely, disabling both USB controllers makes SerDes unused, but SerDes overlays should still be managed explicitly.

- **I2C Constraints**: I2C1 and I2C2 are reserved for R5F cores (ARM Cortex-R5F processors) in the default configuration. The code is commented with a TODO note indicating shared access. Do not enable i2c1 or i2c2 unless you have coordinated with R5F firmware to avoid conflicts.

- **Display/GPU**: Display (DSS) and GPU are independent but share the graphics rendering pipeline if both are used. Disabling dss0 without disabling gpu will still consume GPU resources; the opposite is also true.

Failure Modes and Troubleshooting
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

**Symptom: Resource Manager exits with "Permission denied" or "Device not found"**

**Cause**: A RM in the build file or resource manager in user.sh is trying to access a device that has been disabled via DT overlays.

**Resolution**:
1. Check which overlay was applied during build
2. Identify the corresponding RM from the mapping table above
3. Comment out that RM line
4. Run ``make clean`` (important!)
5. Rebuild: ``make all SOC=j722s ...``

**Symptom: QNX boot hangs after device tree initialization**

**Cause**: A launcher is trying to initialize hardware that has been disabled at the DT level. The RM may be waiting indefinitely for a device response.

**Resolution**:
1. Review the build file and user.sh for any RMs matching disabled devices
2. Ensure all disabled device launchers are commented out
3. Run ``make clean`` to remove stale headers
4. Rebuild and reboot

**Symptom: I2C devices not responding even though i2c0 RM is running**

**Cause**: I2C0 pins have been disabled via ``disable_main_i2c0_pins_default.dtso`` while the i2c RM is still launching.

**Resolution**:
1. If you disabled i2c0, comment out the i2c RM
2. If you only disabled pins (not the full i2c0 device), the controller exists but pins are not muxed - enable pin configuration overlay or comment out the i2c RM

Future Automation Consideration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Currently, you must manually synchronize overlay choices with launcher configuration in two separate files. A future enhancement could automate this process:

.. note::

    **Conceptual Automation (Not Implemented Yet)**

    A build system enhancement could:
    1. Parse ``DTS_OVERLAY`` variable to extract disabled devices
    2. Generate a filtered build file (commenting out matching device launchers)
    3. Generate a filtered user.sh (commenting out matching resource managers)
    4. Log all changes for verification

    This would eliminate manual file edits and reduce errors. Implementation would require:
    - Python script to parse overlay filenames and extract device names
    - sed/awk-based filtering of build file and user.sh templates
    - Validation step to ensure all disabled devices have matching commented launchers
    - Integration into the top-level makefile as a pre-build step

Refinement: Limiting Disable-able Nodes to hw_init.c Peripherals
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

A key refinement for future automation should be to limit the available disable overlays to only the device nodes that are actually used by QNX hardware initialization (``hw_init.c``). This ensures users cannot inadvertently disable arbitrary device tree nodes that have no relevance to system boot.

**Current State:**
- The minimal DTS (``j722s-hw-init.dts``) was specifically extracted to contain only nodes required by ``hw_init.c``
- However, the full preprocessed DTS contains many additional nodes that could theoretically be disabled
- Users might disable unrelated nodes without realizing they have no effect on boot or functionality

**Proposed Refinement:**
- Generate disable overlays only for nodes that appear in both:

  1. The minimal DTS (``j722s-hw-init.dts``)
  2. The corresponding ``hw_init.c`` driver initialization code

- Document the 1:1 mapping between each disable overlay and the specific ``hw_init.c`` code section it affects
- Optionally generate a constraint list preventing disabling of critical boot dependencies (e.g., cannot disable main clocks without disabling dependent devices)

**Benefit:**
Users would only see device options relevant to their actual system boot configuration, reducing confusion and preventing accidental misconfiguration. The overlay list would be maintainable and directly traceable to source code.


Troubleshooting
---------------

**Missing overlay file error:**

If you receive an error like "Overlay file not found", verify:

1. The overlay file exists in ``${PSDK_QNX_PATH}/qnx/utils/dt/dts/j722s/overlay/``
2. You spelled the overlay filename correctly
3. You are running the build command from the QNX repository root

**Conflicting overlays error:**

If the build fails with a conflict error, run the validation script to identify which overlays are conflicting, then remove one of the conflicting pairs.

**Device not responding after build:**

If a peripheral that you expected to initialize is not responding:

1. Verify that you did not accidentally disable it with a disable overlay
2. Check that the device's pin configuration overlay is enabled (if one exists)
3. Verify the hardware connections and power supplies

Developer Note: Future Build System Enhancement
------------------------------------------------

.. NOTE::
    The validation script (``validate_overlay_conflicts.sh``) is currently available as a manual step before building. Future versions of the build system should automatically integrate this validation into the build chain to prevent invalid configurations at build time. Users should manually run the validation script before invoking the ``make bsp`` command to catch configuration errors early.

Summary
-------

**QNX BSP Device Tree Build Modes:**

1. **Legacy (default)**: ``make all SOC=j722s`` — All devices enabled, no device tree
2. **Base DT only**: ``make all SOC=j722s DTS_OVERLAY=base`` — Base device tree, no overlays
3. **DT with overlays**: ``make all SOC=j722s DTS_OVERLAY=<overlay_list>`` — Device tree with customization

**For overlay builds:**

1. Choose the devices you want to enable or disable
2. Validate your overlay list: ``utils/dt/scripts/validate_overlay_conflicts.sh "<overlay_list>"``
3. Build with overlays: ``make all SOC=j722s DTS_OVERLAY=<overlay_list>``

**Important reminders:**

- Specifying ``DTS_OVERLAY`` (with ``base`` or overlay filenames) automatically enables the device tree infrastructure and defines the ``USE_DT`` preprocessor macro
- Run ``make clean`` when switching between build modes to ensure old headers are removed
- The resulting startup file will initialize only the peripherals specified in your device tree configuration
- You can build only the BSP with ``make bsp SOC=j722s ...`` instead of the full build with ``make all SOC=j722s ...``

.. seealso::
    - :ref:`developer_notes_device_tree_support` — Additional device tree integration details
    - :ref:`developer_notes_bootloaders` — Boot loader configuration
