FDT_ERROR_NOTFOUND on Device Tree Overlays

I’m working on building a Raspberry Pi CM4 image using nixos-generators, but I’ve hit a roadblock when it comes to applying several device tree overlays. I’ve been including them individually, but none of them can be applied, as I keep encountering the error FDT_ERR_NOTFOUND:

  Applying overlay mcp4728
Traceback (most recent call last):
  File "/nix/store/206l37y6cvcwl3ck1ppwgnxn4cnm818i-apply_overlays.py", line 102, in <module>
    main()
  File "/nix/store/206l37y6cvcwl3ck1ppwgnxn4cnm818i-apply_overlays.py", line 92, in main
    dt = apply_overlay(dt, overlay.fdt)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/206l37y6cvcwl3ck1ppwgnxn4cnm818i-apply_overlays.py", line 50, in apply_overlay
    raise FdtException(err)
libfdt.FdtException: pylibfdt error -1: FDT_ERR_NOTFOUND

If I enable the option:

hardware.raspberry-pi."4".apply-overlays-dtmerge.enable = true;

The error log will be much more useful. For example, the mcp4728.dts overlay yields:

Applying overlay mcp4728 to bcm2711-rpi-cm4-io.dtb... DTOVERLAY[error]: can't find symbol 'vdd_5v0_reg'

It is trying to apply my overlay against the wrong target: the symbol vdd_5v0_reg is defined in bcm2711-rpi-cm4.dtb, not bcm2711-rpi-cm4-io.dtb

Another example is spi6-1cs shipped in `pkgs.device-tree_rpi.overlays" package:

Applying overlay spi6-1cs to bcm2711-rpi-cm4-io.dtb... DTOVERLAY[error]: can't find symbol 'spi6_cs_pins'

Also, s a side question: what does the option hardware.raspberry-pi."4".apply-overlays-dtmerge.enable do? I cannot find this option in NixOS Search. Is this deprecated?

This is the flake I’m working with. Suggestions and workarounds are greatly appreciated.

I add this option:

hardware.deviceTree.filter = "bcm2711-rpi-cm4.dtb";

as this seems to be the only viable device tree to load, and from there I’m getting

> root module: sun4i-drm
> modprobe: FATAL: Module sun4i-drm not found in directory /nix/store/slc3sgyfafqh1kb6qr25jvffh0dhyqjb-linux-rpi-6.6.31-stable_20240529-modules/lib/modules/6.6.31

Which is closely related to this issue:

I tried to work around it with the suggested overlay but it didn’t help

  let
    pkgs = import nixpkgs { 
      system = "aarch64-linux";
      overlays = [
        (final: super: {
          makeModulesClosure = x:
            super.makeModulesClosure (x // { allowMissing = true; });
        })
      ];
    };

  in
  ...

Kudos to this post, I can successfully build my image, but I still cannot understand why.

My previous understanding of applying overlays to nixpkgs is to be done during the import.

pkgs = import nixpkgs {
  system = "aarch64-linux";
  overlays = [ ... ];
};

On the other hand, the working solution defines a new nixpkgs entry in the configuration module along with other entries such as boot, hardware, service, etc.

nixpkgs = {
  hostPlatform = lib.mkDefault "aarch64-linux";
  config = {
    allowUnfree = true;
  };
  overlays = [
    (final: super: {
      makeModulesClosure = x:
        super.makeModulesClosure (x // {allowMissing = true;});
    })
  ];
};

Maybe this has something to do with nixpkgs.lib.nixosSystem?