ocamlPackages.hxd: 0.3.2 -> 0.3.3 (#364231)
[NixPkgs.git] / nixos / modules / services / hardware / display.nix
blob9aeb9d8fab09520296f881b874004057489f34df
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
7 let
8   cfg = config.hardware.display;
9 in
11   meta.doc = ./display.md;
12   meta.maintainers = with lib.maintainers; [
13     nazarewk
14   ];
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     };
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>`.
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     };
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
68         Attribute names will be mapped to EDID filenames `<NAME>.bin`.
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)
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     };
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     };
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:
153                     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
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 = { };
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   };
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;
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   ];