at 25.11-pre 7.1 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.hardware.display; 9in 10{ 11 meta.doc = ./display.md; 12 meta.maintainers = with lib.maintainers; [ 13 nazarewk 14 ]; 15 16 options = { 17 hardware.display.edid.enable = lib.mkOption { 18 type = with lib.types; bool; 19 default = cfg.edid.packages != null; 20 defaultText = lib.literalExpression "config.hardware.display.edid.packages != null"; 21 description = '' 22 Enables handling of EDID files 23 ''; 24 }; 25 26 hardware.display.edid.packages = lib.mkOption { 27 type = with lib.types; listOf package; 28 default = [ ]; 29 description = '' 30 List of packages containing EDID binary files at `$out/lib/firmware/edid`. 31 Such files will be available for use in `drm.edid_firmware` kernel 32 parameter as `edid/<filename>`. 33 34 You can craft one directly here or use sibling options `linuxhw` and `modelines`. 35 ''; 36 example = lib.literalExpression '' 37 [ 38 (pkgs.runCommand "edid-custom" {} ''' 39 mkdir -p "$out/lib/firmware/edid" 40 base64 -d > "$out/lib/firmware/edid/custom1.bin" <<'EOF' 41 <insert your base64 encoded EDID file here `base64 < /sys/class/drm/card0-.../edid`> 42 EOF 43 ''') 44 ] 45 ''; 46 apply = 47 list: 48 if list == [ ] then 49 null 50 else 51 (pkgs.buildEnv { 52 name = "firmware-edid"; 53 paths = list; 54 pathsToLink = [ "/lib/firmware/edid" ]; 55 ignoreCollisions = true; 56 }) 57 // { 58 compressFirmware = false; 59 }; 60 }; 61 62 hardware.display.edid.linuxhw = lib.mkOption { 63 type = with lib.types; attrsOf (listOf str); 64 default = { }; 65 description = '' 66 Exposes EDID files from users-sourced database at <https://github.com/linuxhw/EDID> 67 68 Attribute names will be mapped to EDID filenames `<NAME>.bin`. 69 70 Attribute values are lists of `awk` regexp patterns that (together) must match 71 exactly one line in either of: 72 - [AnalogDisplay.md](https://raw.githubusercontent.com/linuxhw/EDID/master/AnalogDisplay.md) 73 - [DigitalDisplay.md](https://raw.githubusercontent.com/linuxhw/EDID/master/DigitalDisplay.md) 74 75 There is no universal way of locating your device config, but here are some practical tips: 76 1. locate your device: 77 - find your model number (second column) 78 - locate manufacturer (first column) and go through the list manually 79 2. narrow down results using other columns until there is only one left: 80 - `Name` column 81 - production date (`Made` column) 82 - resolution `Res` 83 - screen diagonal (`Inch` column) 84 - as a last resort use `ID` from the last column 85 ''; 86 example = lib.literalExpression '' 87 { 88 PG278Q_2014 = [ "PG278Q" "2014" ]; 89 } 90 ''; 91 apply = 92 displays: 93 if displays == { } then null else pkgs.linuxhw-edid-fetcher.override { inherit displays; }; 94 }; 95 96 hardware.display.edid.modelines = lib.mkOption { 97 type = with lib.types; attrsOf str; 98 default = { }; 99 description = '' 100 Attribute set of XFree86 Modelines automatically converted 101 and exposed as `edid/<name>.bin` files in initrd. 102 See for more information: 103 - <https://en.wikipedia.org/wiki/XFree86_Modeline> 104 ''; 105 example = lib.literalExpression '' 106 { 107 "PG278Q_60" = " 241.50 2560 2608 2640 2720 1440 1443 1448 1481 -hsync +vsync"; 108 "PG278Q_120" = " 497.75 2560 2608 2640 2720 1440 1443 1448 1525 +hsync -vsync"; 109 "U2711_60" = " 241.50 2560 2600 2632 2720 1440 1443 1448 1481 -hsync +vsync"; 110 } 111 ''; 112 apply = 113 modelines: 114 if modelines == { } then 115 null 116 else 117 pkgs.edid-generator.overrideAttrs { 118 clean = true; 119 passthru.config = modelines; 120 modelines = lib.trivial.pipe modelines [ 121 (lib.mapAttrsToList ( 122 name: value: 123 lib.throwIfNot ( 124 builtins.stringLength name <= 12 125 ) "Modeline name must be 12 characters or less" ''Modeline "${name}" ${value}'' 126 )) 127 (builtins.map (line: "${line}\n")) 128 (lib.strings.concatStringsSep "") 129 ]; 130 }; 131 }; 132 133 hardware.display.outputs = lib.mkOption { 134 type = lib.types.attrsOf ( 135 lib.types.submodule ({ 136 options = { 137 edid = lib.mkOption { 138 type = with lib.types; nullOr str; 139 default = null; 140 description = '' 141 An EDID filename to be used for configured display, as in `edid/<filename>`. 142 See for more information: 143 - `hardware.display.edid.packages` 144 - https://wiki.archlinux.org/title/Kernel_mode_setting#Forcing_modes_and_EDID 145 ''; 146 }; 147 mode = lib.mkOption { 148 type = with lib.types; nullOr str; 149 default = null; 150 description = '' 151 A `video` kernel parameter (framebuffer mode) configuration for the specific output: 152 153 <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd] 154 155 See for more information: 156 - https://docs.kernel.org/fb/modedb.html 157 - https://wiki.archlinux.org/title/Kernel_mode_setting#Forcing_modes 158 ''; 159 example = lib.literalExpression '' 160 "e" 161 ''; 162 }; 163 }; 164 }) 165 ); 166 description = '' 167 Hardware/kernel-level configuration of specific outputs. 168 ''; 169 default = { }; 170 171 example = lib.literalExpression '' 172 { 173 edid.modelines."PG278Q_60" = "241.50 2560 2608 2640 2720 1440 1443 1448 1481 -hsync +vsync"; 174 outputs."DP-1".edid = "PG278Q_60.bin"; 175 outputs."DP-1".mode = "e"; 176 } 177 ''; 178 }; 179 }; 180 181 config = lib.mkMerge [ 182 { 183 hardware.display.edid.packages = 184 lib.optional (cfg.edid.modelines != null) cfg.edid.modelines 185 ++ lib.optional (cfg.edid.linuxhw != null) cfg.edid.linuxhw; 186 187 boot.kernelParams = 188 # forcing video modes 189 lib.trivial.pipe cfg.outputs [ 190 (lib.attrsets.filterAttrs (_: spec: spec.mode != null)) 191 (lib.mapAttrsToList (output: spec: "video=${output}:${spec.mode}")) 192 ] 193 # selecting EDID for displays 194 ++ lib.trivial.pipe cfg.outputs [ 195 (lib.attrsets.filterAttrs (_: spec: spec.edid != null)) 196 (lib.mapAttrsToList (output: spec: "${output}:edid/${spec.edid}")) 197 (builtins.concatStringsSep ",") 198 (p: lib.optional (p != "") "drm.edid_firmware=${p}") 199 ]; 200 } 201 (lib.mkIf (cfg.edid.packages != null) { 202 # services.udev implements hardware.firmware option 203 services.udev.enable = true; 204 hardware.firmware = [ cfg.edid.packages ]; 205 }) 206 ]; 207}