diff options
| author | Mel <mel@rnrd.eu> | 2026-07-18 18:51:08 +0200 |
|---|---|---|
| committer | Mel <mel@rnrd.eu> | 2026-07-18 18:51:08 +0200 |
| commit | 7672318e8435164746e0a0d9a4def8be6820c3fa (patch) | |
| tree | 12e5828f236399e7d46afeafa0637dd7a9e90646 | |
| parent | 72a3bfd94fd0dd0983d55e25fd831864e0194f12 (diff) | |
| download | network-7672318e8435164746e0a0d9a4def8be6820c3fa.tar.zst network-7672318e8435164746e0a0d9a4def8be6820c3fa.zip | |
Add support for fourmi display via custom DRM kernel driver flake
Signed-off-by: Mel <mel@rnrd.eu>
| -rw-r--r-- | flake.lock | 21 | ||||
| -rw-r--r-- | flake.nix | 35 | ||||
| -rw-r--r-- | machines/fourmi/devices.nix | 16 | ||||
| -rw-r--r-- | modules/hardware/ads7846.nix | 144 | ||||
| -rw-r--r-- | modules/hardware/ili9486.nix | 91 | ||||
| -rw-r--r-- | modules/klipperscreen.nix | 9 |
6 files changed, 73 insertions, 243 deletions
diff --git a/flake.lock b/flake.lock index 5d953d3..963c1d2 100644 --- a/flake.lock +++ b/flake.lock @@ -153,6 +153,26 @@ "type": "github" } }, + "mhs35-drm": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1783965600, + "narHash": "sha256-oM/h+5G8s46RmOSiY4hnrk1Z3qmQudMbfPdjlkX6tPk=", + "ref": "refs/heads/main", + "rev": "dd8f085fc0232b77f3db885b0670a3e8d3094d36", + "revCount": 7, + "type": "git", + "url": "https://git.rnrd.eu/mhs35-drm" + }, + "original": { + "type": "git", + "url": "https://git.rnrd.eu/mhs35-drm" + } + }, "nixos-hardware": { "inputs": { "nixpkgs": "nixpkgs" @@ -349,6 +369,7 @@ "flake-compat": "flake-compat", "hermes-agent": "hermes-agent", "home-manager": "home-manager", + "mhs35-drm": "mhs35-drm", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable", diff --git a/flake.nix b/flake.nix index c52d5d8..ac30df6 100644 --- a/flake.nix +++ b/flake.nix @@ -39,6 +39,11 @@ url = "github:NousResearch/hermes-agent"; inputs.nixpkgs.follows = "nixpkgs-unstable"; }; + + mhs35-drm = { + url = "git+https://git.rnrd.eu/mhs35-drm"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = inputs @ { self, nixpkgs, nixpkgs-unstable, home-manager, agenix, ... }: @@ -77,7 +82,23 @@ overlays = [ agenix.overlays.default ]; - packageSetsForSystem = system: let + # per-machine overlays. + # as we only work with immutable package sets, we need to make sure + # all injected overlays are correct ourselves right here, which modules + # would mutate our package set to achieve automatically. + machineOverlays = { + fourmi = [ + # `hardware.raspberry-pi."4".apply-overlays-dtmerge.enable`. + (final: prev: { + deviceTree = prev.deviceTree // { + applyOverlays = final.callPackage + "${inputs.nixos-hardware}/raspberry-pi/4/apply-overlays-dtmerge.nix" { }; + }; + }) + ]; + }; + + packageSetsWith = { system, overlays }: let pkgsInputs = i: { inherit system; config = import ./config.nix; } // i; in rec { @@ -88,13 +109,21 @@ auxiliaryPkgs = import ./pkgs (pkgsInputs { inherit pkgs unstablePkgs; }); }; + packageSetsForSystem = system: + packageSetsWith { inherit system overlays; }; + + packageSetsForMachine = machine: packageSetsWith { + inherit (machine) system; + overlays = overlays ++ (machineOverlays.${machine.name} or [ ]); + }; + inherit (nixpkgs) lib; in { nixosConfigurations = lib.mergeAttrsList (map (machine: { ${machine.name} = nixpkgs.lib.nixosSystem { specialArgs = inputs // { - inherit (packageSetsForSystem machine.system) unstablePkgs auxiliaryPkgs; + inherit (packageSetsForMachine machine) unstablePkgs auxiliaryPkgs; inherit machines; me = machine // { is = mkMachineIdentities machines machine; }; keys = import ./secrets/keys.nix; @@ -103,7 +132,7 @@ modules = [ nixpkgs.nixosModules.readOnlyPkgs - { nixpkgs.pkgs = (packageSetsForSystem machine.system).pkgs; } + { nixpkgs.pkgs = (packageSetsForMachine machine).pkgs; } ./machines/${machine.name} diff --git a/machines/fourmi/devices.nix b/machines/fourmi/devices.nix index 56d243f..1e55692 100644 --- a/machines/fourmi/devices.nix +++ b/machines/fourmi/devices.nix @@ -3,6 +3,7 @@ pkgs, lib, nixos-hardware, + mhs35-drm, ... }: @@ -10,10 +11,16 @@ # correctly configure hardware in this pi server. imports = [ nixos-hardware.nixosModules.raspberry-pi-4 - ../../modules/hardware/ads7846.nix - #../../modules/hardware/ili9486.nix + mhs35-drm.nixosModules.default ]; + # gpio display visualizing the goings-on on fourmi! + # this is a weird offbrand ili9486 (maybe?) 3.5" spi panel + # with an ads7846 touch screen which is not actually compatible + # with the normal drm driver, so we have our own! + # see the flake input and associated repo for more! + hardware.mhs35.enable = true; + # boot settings boot = { kernelPackages = lib.mkForce pkgs.linuxPackages_rpi4; @@ -37,7 +44,8 @@ # apply rpi4-specific device tree from nixos-hardware. hardware = { raspberry-pi."4" = { - apply-overlays-dtmerge.enable = true; + # applied in our flake as per-machine overlay. + apply-overlays-dtmerge.enable = false; fkms-3d.enable = true; }; deviceTree = { @@ -66,13 +74,11 @@ name = "end0"; DHCP = "yes"; dhcpV4Config.RouteMetric = 100; - networkConfig.RequiredForOnline = "no"; }; "20-wireless" = { name = "wlan0"; DHCP = "yes"; dhcpV4Config.RouteMetric = 600; - networkConfig.RequiredForOnline = "no"; }; }; }; diff --git a/modules/hardware/ads7846.nix b/modules/hardware/ads7846.nix deleted file mode 100644 index 4d7582a..0000000 --- a/modules/hardware/ads7846.nix +++ /dev/null @@ -1,144 +0,0 @@ -{ ... }: - -{ - # calibration for touchscreen - services = - let - calibrationPoints = "3900 200 200 3900"; - calibrationMatrix = "-1 0 1 0 1 0"; - in - { - libinput.enable = true; - - # xorg configuration - xserver.inputClassSections = [ - '' - Identifier "ads7846 calibration" - MatchProduct "ADS7846 Touchscreen" - Option "Calibration" "${calibrationPoints}" - Option "SwapAxes" "0" - Driver "libinput" - '' - ]; - - # wayland configuration - udev.extraRules = '' - ATTRS{name}=="ADS7846 Touchscreen", ENV{LIBINPUT_CALIBRATION_MATRIX}="${calibrationMatrix}" - ''; - }; - - hardware.deviceTree = - let - cs = 1; - penirq = 25; - penirq_pull = 2; - speed = 50000; - pmin = 0; - pmax = 255; - xohms = 150; - xmin = 200; - xmax = 3900; - ymin = 200; - ymax = 3900; - in - { - overlays = [ - { - name = "ads7846-overlay"; - # taken from raspberry-pi kernel tree: - # https://github.com/raspberrypi/linux/blob/rpi-6.6.y/arch/arm/boot/dts/overlays/ads7846-overlay.dts - dtsText = '' - /* - * Generic Device Tree overlay for the ADS7846 touch controller - * - */ - - /dts-v1/; - /plugin/; - - / { - compatible = "brcm,bcm2711"; - - fragment@0 { - target = <&spi0>; - __overlay__ { - status = "okay"; - }; - }; - - fragment@1 { - target = <&spidev0>; - __overlay__ { - status = "disabled"; - }; - }; - - fragment@2 { - target = <&spidev1>; - __overlay__ { - status = "disabled"; - }; - }; - - fragment@3 { - target = <&gpio>; - __overlay__ { - ads7846_pins: ads7846_pins { - brcm,pins = <${toString penirq}>; /* mel: previously illegal value of 255 */ - brcm,function = <0>; /* in */ - brcm,pull = <${toString penirq_pull}>; /* none */ - }; - }; - }; - - fragment@4 { - target = <&spi0>; - __overlay__ { - /* needed to avoid dtc warning */ - #address-cells = <1>; - #size-cells = <0>; - - ads7846: ads7846@1 { - compatible = "ti,ads7846"; - reg = <${toString cs}>; - pinctrl-names = "default"; - pinctrl-0 = <&ads7846_pins>; - - spi-max-frequency = <${toString speed}>; - interrupts = <${toString penirq} 2>; /* high-to-low edge triggered */ - interrupt-parent = <&gpio>; - pendown-gpio = <&gpio ${toString penirq} 1>; - - /* driver defaults */ - ti,x-min = /bits/ 16 <${toString xmin}>; - ti,y-min = /bits/ 16 <${toString ymin}>; - ti,x-max = /bits/ 16 <${toString xmax}>; - ti,y-max = /bits/ 16 <${toString ymax}>; - ti,pressure-min = /bits/ 16 <${toString pmin}>; - ti,pressure-max = /bits/ 16 <${toString pmax}>; - ti,x-plate-ohms = /bits/ 16 <${toString xohms}>; - }; - }; - }; - __overrides__ { - cs = <&ads7846>,"reg:0"; - speed = <&ads7846>,"spi-max-frequency:0"; - penirq = <&ads7846_pins>,"brcm,pins:0", /* REQUIRED */ - <&ads7846>,"interrupts:0", - <&ads7846>,"pendown-gpio:4"; - penirq_pull = <&ads7846_pins>,"brcm,pull:0"; - swapxy = <&ads7846>,"ti,swap-xy?"; - xmin = <&ads7846>,"ti,x-min;0"; - ymin = <&ads7846>,"ti,y-min;0"; - xmax = <&ads7846>,"ti,x-max;0"; - ymax = <&ads7846>,"ti,y-max;0"; - pmin = <&ads7846>,"ti,pressure-min;0"; - pmax = <&ads7846>,"ti,pressure-max;0"; - xohms = <&ads7846>,"ti,x-plate-ohms;0"; - }; - }; - ''; - } - ]; - }; -} diff --git a/modules/hardware/ili9486.nix b/modules/hardware/ili9486.nix deleted file mode 100644 index 6bab9ea..0000000 --- a/modules/hardware/ili9486.nix +++ /dev/null @@ -1,91 +0,0 @@ -{ ... }: - -{ - hardware.deviceTree = - { - overlays = [ - { - name = "ili9486-overlay"; - # decompiled from mhs35 overlay from: - # https://github.com/goodtft/LCD-show/blob/master/usr/mhs35-overlay.dtb - # with adjustments taken from the piscreen overlay: - # https://github.com/raspberrypi/linux/blob/rpi-6.6.y/arch/arm/boot/dts/overlays/piscreen-overlay.dts - dtsText = '' - /dts-v1/; - /plugin/; - - / { - compatible = "brcm,bcm2711"; - - fragment@0 { - target = <&spi0>; - - __overlay__ { - status = "okay"; - - spidev@0 { - status = "disabled"; - }; - - spidev@1 { - status = "disabled"; - }; - }; - }; - - fragment@1 { - target = <&gpio>; - - __overlay__ { - ili9486_pins: ili9486_pins@0 { - brcm,pins = <17 25 24>; - brcm,function = <0 0 0>; - }; - }; - }; - - fragment@2 { - target = <&spi0>; - - __overlay__ { - #address-cells = <1>; - #size-cells = <0>; - - ili9486: ili9486@0 { - compatible = "ilitek,ili9486"; - reg = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&ili9486_pins>; - - spi-max-frequency = <115000000>; - txbuflen = <0x8000>; - rotate = <90>; - bgr = <0>; - fps = <30>; - buswidth = <8>; - regwidth = <16>; - - reset-gpios = <&gpio 25 1>; - dc-gpios = <&gpio 24 0>; - debug = <0>; - - init = <0x10000f1 0x36 0x04 0x00 0x3c 0x0f 0x8f 0x10000f2 0x18 0xa3 0x12 0x02 0xb2 0x12 0xff 0x10 0x00 0x10000f8 0x21 0x04 0x10000f9 0x00 0x08 0x1000036 0x08 0x10000b4 0x00 0x10000c1 0x41 0x10000c5 0x00 0x91 0x80 0x00 0x10000e0 0x0f 0x1f 0x1c 0x0c 0x0f 0x08 0x48 0x98 0x37 0x0a 0x13 0x04 0x11 0x0d 0x00 0x10000e1 0x0f 0x32 0x2e 0x0b 0x0d 0x05 0x47 0x75 0x37 0x06 0x10 0x03 0x24 0x20 0x00 0x100003a 0x55 0x1000011 0x1000036 0x28 0x20000ff 0x1000029>; - }; - }; - }; - - __overrides__ { - speed = <&ili9486>,"spi-max-frequency:0"; - txbuflen = <&ili9486>,"txbuflen:0"; - rotate = <&ili9486>,"rotate:0", - <&ili9486>,"rotation:0"; - fps = <&ili9486>,"fps:0"; - bgr = <&ili9486>,"bgr:0"; - debug = <&ili9486>,"debug:0"; - }; - }; - ''; - } - ]; - }; -} diff --git a/modules/klipperscreen.nix b/modules/klipperscreen.nix index 9235360..d4d9bfa 100644 --- a/modules/klipperscreen.nix +++ b/modules/klipperscreen.nix @@ -29,6 +29,15 @@ in environment = { # don't fail with no devices found. "WLR_LIBINPUT_NO_DEVICES" = "1"; + + # render onto the SPI panel (see modules/hardware/ili9486.nix), not + # the firmware/HDMI framebuffer. by-path is stable across boots, + # unlike cardN numbering. + "WLR_DRM_DEVICES" = "/dev/dri/by-path/platform-fe204000.spi-cs-0-card"; + + # the SPI panel has no GPU render node, so GLES cannot initialize; + # software rendering into dumb buffers works fine at 480x320. + "WLR_RENDERER" = "pixman"; }; user = "klipper"; }; |
