diff --git a/raspberry-pi/4/apply-overlays-dtmerge.nix b/raspberry-pi/4/apply-overlays-dtmerge.nix new file mode 100644 index 0000000..0d17bb8 --- /dev/null +++ b/raspberry-pi/4/apply-overlays-dtmerge.nix @@ -0,0 +1,30 @@ +{ lib, pkgs, stdenvNoCC, dtc, libraspberrypi }: + +with lib; { + applyOverlays = (base: overlays': stdenvNoCC.mkDerivation { + name = "device-tree-overlays"; + nativeBuildInputs = [ dtc ]; + buildCommand = let + overlays = toList overlays'; + in '' + mkdir -p $out + cd ${base} + find . -type f -name '*.dtb' -print0 \ + | xargs -0 cp -v --no-preserve=mode --target-directory $out --parents + for dtb in $(find $out -type f -name '*.dtb'); do + dtbCompat="$( fdtget -t s $dtb / compatible )" + ${flip (concatMapStringsSep "\n") overlays (o: '' + overlayCompat="$( fdtget -t s ${o.dtboFile} / compatible )" + # overlayCompat in dtbCompat + if [[ "$dtbCompat" =~ "$overlayCompat" ]]; then + echo "Applying overlay ${o.name} to $( basename $dtb )" + mv $dtb{,.in} + cp ${o.dtboFile}{,.dtbo} + ${libraspberrypi}/bin/dtmerge "$dtb.in" "$dtb" ${o.dtboFile}.dtbo; + rm $dtb.in ${o.dtboFile}.dtbo + fi + '')} + done + ''; + }); +} diff --git a/raspberry-pi/4/default.nix b/raspberry-pi/4/default.nix index fcaf5ad..d85063a 100644 --- a/raspberry-pi/4/default.nix +++ b/raspberry-pi/4/default.nix @@ -7,8 +7,10 @@ ./i2c.nix ./modesetting.nix ./poe-hat.nix + ./poe-plus-hat.nix ./tc358743.nix ./pwm0.nix + ./pkgs-overlays.nix ]; boot = { diff --git a/raspberry-pi/4/pkgs-overlays.nix b/raspberry-pi/4/pkgs-overlays.nix new file mode 100644 index 0000000..4b3c16d --- /dev/null +++ b/raspberry-pi/4/pkgs-overlays.nix @@ -0,0 +1,22 @@ +{ config, lib, pkgs, modulesPath, ... }: +let + callPackage = path: overrides: + let f = import path; + in f ((builtins.intersectAttrs (builtins.functionArgs f) pkgs) // overrides); + cfg = config.hardware.raspberry-pi."4".apply-overlays-dtmerge; + dt_ao_overlay = (final: prev: { + deviceTree.applyOverlays = (prev.callPackage ./apply-overlays-dtmerge.nix { }).applyOverlays; + }); +in { + options.hardware = { + raspberry-pi."4".apply-overlays-dtmerge = { + enable = lib.mkEnableOption '' + replace deviceTree.applyOverlays implementation to use dtmerge from libraspberrypi. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + nixpkgs.overlays = [ dt_ao_overlay ]; + }; +} diff --git a/raspberry-pi/4/poe-hat.nix b/raspberry-pi/4/poe-hat.nix index ea19129..bda9925 100644 --- a/raspberry-pi/4/poe-hat.nix +++ b/raspberry-pi/4/poe-hat.nix @@ -1,6 +1,6 @@ { config, lib, pkgs, ... }: -let +let cfg = config.hardware.raspberry-pi."4".poe-hat; in { options.hardware = { @@ -12,10 +12,11 @@ in { }; config = lib.mkIf cfg.enable { - # Configure for modesetting in the device tree + hardware.raspberry-pi."4".apply-overlays-dtmerge.enable = lib.mkDefault true; + hardware.deviceTree = { overlays = [ - # Equivalent to: https://github.com/raspberrypi/linux/blob/rpi-5.10.y/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts + # Equivalent to: https://github.com/raspberrypi/linux/blob/rpi-5.15.y/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts { name = "rpi-poe-overlay"; dtsText = '' @@ -31,14 +32,11 @@ in { fragment@0 { target-path = "/"; __overlay__ { - fan0: rpi-poe-fan@0 { - compatible = "raspberrypi,rpi-poe-fan"; - firmware = <&firmware>; - cooling-min-state = <0>; - cooling-max-state = <4>; - #cooling-cells = <2>; + fan: pwm-fan { + compatible = "pwm-fan"; cooling-levels = <0 1 10 100 255>; - status = "okay"; + #cooling-cells = <2>; + pwms = <&fwpwm 0 80000>; }; }; }; @@ -71,19 +69,19 @@ in { cooling-maps { map0 { trip = <&trip0>; - cooling-device = <&fan0 0 1>; + cooling-device = <&fan 0 1>; }; map1 { trip = <&trip1>; - cooling-device = <&fan0 1 2>; + cooling-device = <&fan 1 2>; }; map2 { trip = <&trip2>; - cooling-device = <&fan0 2 3>; + cooling-device = <&fan 2 3>; }; map3 { trip = <&trip3>; - cooling-device = <&fan0 3 4>; + cooling-device = <&fan 3 4>; }; }; }; @@ -91,7 +89,7 @@ in { fragment@2 { target-path = "/__overrides__"; - __overlay__ { + params: __overlay__ { poe_fan_temp0 = <&trip0>,"temperature:0"; poe_fan_temp0_hyst = <&trip0>,"hysteresis:0"; poe_fan_temp1 = <&trip1>,"temperature:0"; @@ -100,6 +98,54 @@ in { poe_fan_temp2_hyst = <&trip2>,"hysteresis:0"; poe_fan_temp3 = <&trip3>,"temperature:0"; poe_fan_temp3_hyst = <&trip3>,"hysteresis:0"; + poe_fan_i2c = <&fwpwm>,"status=disabled", + <&poe_mfd>,"status=okay", + <&fan>,"pwms:0=",<&poe_mfd_pwm>; + }; + }; + + fragment@3 { + target = <&firmware>; + __overlay__ { + fwpwm: pwm { + compatible = "raspberrypi,firmware-poe-pwm"; + #pwm-cells = <2>; + }; + }; + }; + + fragment@4 { + target = <&i2c0>; + i2c_bus: __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + + poe_mfd: poe@51 { + compatible = "raspberrypi,poe-core"; + reg = <0x51>; + status = "disabled"; + + poe_mfd_pwm: poe_pwm@f0 { + compatible = "raspberrypi,poe-pwm"; + reg = <0xf0>; + status = "okay"; + #pwm-cells = <2>; + }; + }; + }; + }; + + fragment@5 { + target = <&i2c0if>; + __dormant__ { + status = "okay"; + }; + }; + + fragment@6 { + target = <&i2c0mux>; + __dormant__ { + status = "okay"; }; }; @@ -112,6 +158,11 @@ in { poe_fan_temp2_hyst = <&trip2>,"hysteresis:0"; poe_fan_temp3 = <&trip3>,"temperature:0"; poe_fan_temp3_hyst = <&trip3>,"hysteresis:0"; + i2c = <0>, "+5+6", + <&fwpwm>,"status=disabled", + <&i2c_bus>,"status=okay", + <&poe_mfd>,"status=okay", + <&fan>,"pwms:0=",<&poe_mfd_pwm>; }; }; ''; diff --git a/raspberry-pi/4/poe-plus-hat.nix b/raspberry-pi/4/poe-plus-hat.nix new file mode 100644 index 0000000..79177fe --- /dev/null +++ b/raspberry-pi/4/poe-plus-hat.nix @@ -0,0 +1,223 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.hardware.raspberry-pi."4".poe-plus-hat; +in { + options.hardware = { + raspberry-pi."4".poe-plus-hat = { + enable = lib.mkEnableOption '' + support for the Raspberry Pi PoE+ HAT. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + hardware.raspberry-pi."4".apply-overlays-dtmerge.enable = lib.mkDefault true; + + hardware.deviceTree = { + overlays = [ + # Combined equivalent to: + # * https://github.com/raspberrypi/linux/blob/rpi-5.15.y/arch/arm/boot/dts/overlays/rpi-poe-overlay.dts + # * https://github.com/raspberrypi/linux/blob/rpi-5.15.y/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts + { + name = "rpi-poe-plus-overlay"; + dtsText = '' + /* + * Overlay for the Raspberry Pi POE HAT. + */ + /dts-v1/; + /plugin/; + + / { + compatible = "brcm,bcm2711"; + + fragment@0 { + target-path = "/"; + __overlay__ { + fan: pwm-fan { + compatible = "pwm-fan"; + cooling-levels = <0 1 10 100 255>; + #cooling-cells = <2>; + pwms = <&fwpwm 0 80000>; + }; + }; + }; + + fragment@1 { + target = <&cpu_thermal>; + __overlay__ { + trips { + trip0: trip0 { + temperature = <40000>; + hysteresis = <2000>; + type = "active"; + }; + trip1: trip1 { + temperature = <45000>; + hysteresis = <2000>; + type = "active"; + }; + trip2: trip2 { + temperature = <50000>; + hysteresis = <2000>; + type = "active"; + }; + trip3: trip3 { + temperature = <55000>; + hysteresis = <5000>; + type = "active"; + }; + }; + cooling-maps { + map0 { + trip = <&trip0>; + cooling-device = <&fan 0 1>; + }; + map1 { + trip = <&trip1>; + cooling-device = <&fan 1 2>; + }; + map2 { + trip = <&trip2>; + cooling-device = <&fan 2 3>; + }; + map3 { + trip = <&trip3>; + cooling-device = <&fan 3 4>; + }; + }; + }; + }; + + fragment@2 { + target-path = "/__overrides__"; + params: __overlay__ { + poe_fan_temp0 = <&trip0>,"temperature:0"; + poe_fan_temp0_hyst = <&trip0>,"hysteresis:0"; + poe_fan_temp1 = <&trip1>,"temperature:0"; + poe_fan_temp1_hyst = <&trip1>,"hysteresis:0"; + poe_fan_temp2 = <&trip2>,"temperature:0"; + poe_fan_temp2_hyst = <&trip2>,"hysteresis:0"; + poe_fan_temp3 = <&trip3>,"temperature:0"; + poe_fan_temp3_hyst = <&trip3>,"hysteresis:0"; + poe_fan_i2c = <&fwpwm>,"status=disabled", + <&poe_mfd>,"status=okay", + <&fan>,"pwms:0=",<&poe_mfd_pwm>; + }; + }; + + fragment@3 { + target = <&firmware>; + __overlay__ { + fwpwm: pwm { + compatible = "raspberrypi,firmware-poe-pwm"; + #pwm-cells = <2>; + }; + }; + }; + + fragment@4 { + target = <&i2c0>; + i2c_bus: __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + + poe_mfd: poe@51 { + compatible = "raspberrypi,poe-core"; + reg = <0x51>; + status = "disabled"; + + poe_mfd_pwm: poe_pwm@f0 { + compatible = "raspberrypi,poe-pwm"; + reg = <0xf0>; + status = "okay"; + #pwm-cells = <2>; + }; + }; + }; + }; + + fragment@5 { + target = <&i2c0if>; + __dormant__ { + status = "okay"; + }; + }; + + fragment@6 { + target = <&i2c0mux>; + __dormant__ { + status = "okay"; + }; + }; + + __overrides__ { + poe_fan_temp0 = <&trip0>,"temperature:0"; + poe_fan_temp0_hyst = <&trip0>,"hysteresis:0"; + poe_fan_temp1 = <&trip1>,"temperature:0"; + poe_fan_temp1_hyst = <&trip1>,"hysteresis:0"; + poe_fan_temp2 = <&trip2>,"temperature:0"; + poe_fan_temp2_hyst = <&trip2>,"hysteresis:0"; + poe_fan_temp3 = <&trip3>,"temperature:0"; + poe_fan_temp3_hyst = <&trip3>,"hysteresis:0"; + i2c = <0>, "+5+6", + <&fwpwm>,"status=disabled", + <&i2c_bus>,"status=okay", + <&poe_mfd>,"status=okay", + <&fan>,"pwms:0=",<&poe_mfd_pwm>; + }; + }; + + // SPDX-License-Identifier: (GPL-2.0 OR MIT) + // Overlay for the Raspberry Pi PoE+ HAT. + + / { + compatible = "brcm,bcm2711"; + + fragment@10 { + target-path = "/"; + __overlay__ { + rpi_poe_power_supply: rpi-poe-power-supply { + compatible = "raspberrypi,rpi-poe-power-supply"; + firmware = <&firmware>; + status = "okay"; + }; + }; + }; + fragment@11 { + target = <&poe_mfd>; + __overlay__ { + rpi-poe-power-supply@f2 { + compatible = "raspberrypi,rpi-poe-power-supply"; + reg = <0xf2>; + status = "okay"; + }; + }; + }; + + __overrides__ { + i2c = <0>, "+5+6", + <&fwpwm>,"status=disabled", + <&rpi_poe_power_supply>,"status=disabled", + <&i2c_bus>,"status=okay", + <&poe_mfd>,"status=okay", + <&fan>,"pwms:0=",<&poe_mfd_pwm>; + }; + }; + + &fan { + cooling-levels = <0 32 64 128 255>; + }; + + ¶ms { + poe_fan_i2c = <&fwpwm>,"status=disabled", + <&rpi_poe_power_supply>,"status=disabled", + <&poe_mfd>,"status=okay", + <&fan>,"pwms:0=",<&poe_mfd_pwm>; + }; + ''; + } + ]; + }; + }; +}