Steam deck and jovian-nixos flake

hi ever1… noob here :triumph:

deep breaths

previously i asked you guys a bunch of questions so that i could be ready to get into some serious business with flakes… (i was already using them at that time)

well, i didnt learn anything! and oh-so-coincidentally AMD made an whoopsie doodles and messed up the kernel for everybody, and so im stuck with THIS:

and because no one can help me but to wait for official response from AMD (proprietary!), I AM LITERALLY PHYSICALLY UNABLE TO WAIT, i am a very impatient person and i NEED THIS COMPUTER TO WORK IMMEDIATELY.

so i said fuck it, and tried out this flake that was recommended here (yes my only computer is a steam deck that i hacked tf out of it):

i didnt have such a good experience.

i installed it thusly (manually truncated + cleared out a bunch a few thousand lines):

flake.nix

{
  description = "I DONT CARE";
  
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    hyprland.url = "github:hyprwm/hyprland";
    jovian-nixos.url = "github:jovian-experiments/jovian-nixos";
  };

  outputs = {
    self,
    nixpkgs,
    hyprland,
    jovian-nixos,
    ...
  } @inputs: { 

    nixosConfigurations.steamdeck = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      specialArgs = { inherit inputs; }; # hyprland demands this

      modules = [
        ./configuration.nix
        hyprland.nixosModules.default
        jovian-nixos.nixosModules.default
      ];
    };
  };
}

pretty normal stuff, right? well, i have a question that still havent been answered and that i couldnt find an answer to on the internet because anything that has to do with .overlays lead to “undefined variable”, etc. etc.

HOWDOIGETTHETHINGTHATDOESTHETHINGWITHOUTOVERCOMPLICATINGITLIKEIMASOFTWAREENGINEER???

how do i install a package from a flake that consists of multiple packages and options?

this must be the ultimate question. what i mean by this is that i usually install SINGULAR flake packages like this:

programs.helpme.package = inputs.verynice.packages.${pkgs.system}.default;

(where verynice is the name of the flake, e.g. verynice.url = "github:verygood/verynice")

which is a slightly cooler equivalent to

programs.helpme.package = pkgs.verynice;

NOW! were i try to, say, install pkgs.linux_jovian kernel from jovian-nixos flake, thusly so:

boot.kernelPackages = pkgs.jovian-nixos.packages.${pkgs.system}.default;

this would imply that i am literally installing the WHOLE flake with ALL OF ITS packages, and it OBVIOUSLY fails, even though it says that .packages or .inputs is undefined, whatever. THIS IS NOT THE CASE FOR LITERALLY EVERYTHING ELSE! the way that i am installing flake packages right now is FINE and it WORKS, but i dont know what am i supposed to do when the flake has multiple packages with .default paths or whatever!

okay, maybe it’s boot.kernelPackages option ITSELF, right, maybe it doesnt allow you to use a flake package, or maybe not! okay, but how do i, GENERALLY SPEAKING, install SPECIFIC, CERTAIN, perhaps even SINGULAR packages from a flake? e.g. mesa-git from chaotic-cx/nyx? sorry i am repeating myself because i am fighting through this dead GPU hahahaha

a few hours later i realised that, APPARENTLY, this kernel package that i want to install from this jovian-nixos flake is… not a package, and is actually an overlay, I THINK. because i can get every other package (that i need, at least) from this flake’s options, e.g. jovian.devices.steamdeck.enable = true; ANYWAY!!! this makes it infinitely more interesting, but… WHAT DOES ANY OF IT EVEN MEAN?

so this linux_jovian is supposed be declared via jovian.linuxPackages_jovian… and NOT boot.kernelPackages, that i thought would work. UGHHH, why, why WHY??? okay, it doesnt matter HOW this pseudo-flake is made, and nevermind the fact that they want me to unironically overlay may way ouf ot this, i just want to try and get this package the nix-way via a flake… but none of those variants work! once again, it’s either an “undefined variable” or “undefined attribute” or “this option doesnt exist” or whateeeever…

one way that i know, which is imperative, i think, and is a very very very bad idea is… copy the .default nix file of the kernel package in question lol (btw i just noticed that the attribute name of it is linux_jovian but the package name is linux, BUT the overlay path to it is ./pkgs/linux-jovian which made me lose all of my braincells) and then have it as an input (in configuration.nix)… that’s horrible, right? i mean, i wouldnt be able to update… or perhaps do the same but via modules = [ ]; in my flake.nix

:triumph:

…i am very sorry. my computer died 5 times while i was writing this, please understand

so, um, i think that is the only, like, OBSTACLE that i am having so far with nixOS… had to edit a bunch of stuff out cos i was just angry lol

:frog:

Well, firstly, packages != options, and a flake doesn’t really “consist” of them. Flakes have multiple outputs. The ones you as a NixOS user care about are packages and modules.

“Modules” are nix files which get fed to NixOS and define options you can set. “Packages” are nix files which get fed to nix and tell nix how to build software.

They’re very different concepts, and I think understanding the difference is crucial to your confusion.

More concretely, when you do this:

You’re telling NixOS to import the options defined in the module named default in the jovian-nixos flake.

And when you do this:

You’re telling NixOS to change the package option of programs.helpme to a package called default defined in the verynice flake.

Also, note that I’m very explicit about this default thing. default isn’t some kind of special magic word, a flake must deliberately name something default for this to work.

It’s common convention for a package or module to be called that, but there definitely are flakes where there is no reasonable “default”, and they simply will not have that package/module.

Also importantly, it definitely does not mean “please magically grab all packages/modules”.

In other words, this makes absolutely zero sense:


Explanations out of the way, the question still stands: How do you install something/everything from a flake?

There is no generic answer to that question. You need to refer to the documentation of the project in question to find out how it is intended to be used. The flake schema only dictates that arbitrarily named packages exist under packages, and that arbitrarily named modules exist under nixosModules.

The only purpose of the schema is to allow you to run nix flake info and see what’s actually in the flake. This is mostly useful for flakes that are simple package sets, so that you can see which packages are available. If you’re using such a flake, you can take the names from that output and replace default with the respective name for whatever you want to install.

For flakes that do anything else, there’s no escape from reading the docs.

So, your question should be, “how do I use jovian-nixos in a flake”. What do the docs say? Nothing at all!

So you have to read the code, and translate the (arguably awful) non-flake instructions.

What do those say? Well, that fetchTarBall thing just ends up importing the default.nix of the modules directory. If you look at the flake.nix, that’s precisely what adding the default module does, too.

So… You’re already done. Just remove that thing you did to the kernel option. You don’t need to set a kernel.

If you read the rest of the docs, you’ll see the only thing you need to do is set …

jovian.devices.steamdeck.enable = true;

… somewhere. The kernel patches are applied by the module if that setting is true.

Technically there are packages you could install through an overlay. But this flake is not intended to be used that way. Just use the modules, as the documentation instructs you to.

2 Likes

theres no way, or…?

oh.

did i mention im incredibly silly?

INDEED, commenting out the boot.kernelPackages = pkgs.linuxPackages_testing; option (if one is even set, and the one that I THOUGHT is where i put the kernel package), then setting jovian.devices.steamdeck.enable = true; IS ENOUGH, IT WORKS!!! it actually DOWNLOADS the linux-6.11.11-valve17 kernel (even though i have cachix enabled for jovian-nixos flake, this kernel is not in the binary cache, it took me almost 2 hours to build it, but hey, at least i built it on my own machine and not with an ampere altra or something that valve likes to do, iykyk… ALSO its a little bit behind latest kernel version, but personally i feel no difference)… so…

the whole thing should look like this:

  jovian = {
    hardware = {
      has.amd.gpu = true; # linux-firmware & "amdgpu"
      amd.gpu.enableEarlyModesetting = true; 
      amd.gpu.enableBacklightControl = false; # breaks 'brightnessctl'!
    };
    workarounds.ignoreMissingKernelModules = true;
    devices.steamdeck = {
      enable = true; # https://github.com/Jovian-Experiments/Jovian-NixOS/tree/development/modules/devices/steamdeck
      autoUpdate = true; # https://github.com/Jovian-Experiments/Jovian-NixOS/blob/development/modules/devices/steamdeck/firmware.nix
      enableFwupdBiosUpdates = true;
      enableDefaultCmdlineConfig = true;
      enableDefaultStage1Modules = true;
      enableKernelPatches = true;
      enableOsFanControl = false; # optional
      enablePerfControlUdevRules = false; # TDP & clock
      enableGyroDsuService = false; # dock station?
      enableSoundSupport = false; # "hardware.pipewire.enable"? 
      enableXorgRotation = true; # see posts below
    };
  };

this is my setup without the “steamOS” on nixOS session… dont need it, because im using tiling window managers anyway

man, you are once again saving my arse, THANK YOU!!!

this was a nightmare. one of the most difficult pseudoflakes to understand, ffs. this was waaaaaay out of my depth and i got confused very quickly so i made a lot of mistakes, sorry

i say this and watch me get another GPU hang moments later lol… well, in that case i will have to downgrade my firmware. but so far so good!

:heart:

snip

i still have two teeny tiny problems:

  1. i dont have these commands:
    jupiter-biosupdate
    jupiter-controller-update

  2. jovian.devices.steamdeck.enableXorgRotation = true doesnt work (e.g. in leftwm)

edit: jupiter-controller-update.service was fixed by turning back the USB control port in BIOS settings, however, the CLI command is still not there

i have every option that is exposed to their installation set to true, but they seem to be conflicting with some other option (as usual)?

please dont take any of my words literally, i am very confused :slight_smile: :+1:

so, updating the BIOS firmware (not linux-firmware) of a steam deck is a pretty big deal, because afaik the only distro that is able to do that 100% is steamOS. there are also bazzite and nobara, and now - nixOS. now…

there is, indeed, a service called jupiter-biosupdate.service, which launches with systemd, successfully updates and exits, as expected. BUT where is the jupiter-biosupdate CLI command for it? there should be one, which is, once again, mentioned here. now, i found these nix files in jovian-nixos

those are one of the most anti-user-friendly instructions ive ever seen.

jovian.devices.steamdeck.autoUpdate = true
SHOULD be able to download the aforementioned packages with their respective commands TO hardware.firmware = [ ] AND systemd.packages = [ ] - but i get no commands?

okay, to prevent “incompatibilities” i disabled these two, which are apparently using the same options:

hardware.cpu.amd.updateMicrocode = true;
hardware.enableRedistributableFirmware = true;

and… nothing. wow.

wtf, but this:

/nix/store/wb2y38ycg5zayvh26b3v3bxqpwbv4hcp-steamdeck-bios-fwupd-20250521.1

is an orphan. it only has Immediate Parents (1): etc-fwupd-remotes.d-steamdeck-bios.conf

is this normal? WHO KNOWS!!! im basically alone out here

anyway, as for the xorg rotation. before, i was using this to rotate my screen automatically in every x11 session:

  environment.etc."xdg/autostart/xrandr.desktop".text = ''
    [Desktop Entry]
    Type=Application
    Name=xrandr
    Exec=sh -c "xrandr -o right"
    NoDisplay=true
  '';

and it worked well. WELL, i was hoping that jovian.devices.steamdeck.enableXorgRotation = true would do the same, but no, it doesnt do anything.

it did create a file in /etc/X11/xorg.conf.d/90-jovian.conf, but thats about it. could it be that this line:

Option "TransformationMatrix" "0 1 0 -1 0 1 0 0 1"

is wrong? WHAT DO THESE NUMBERS MEAN???

snip

anyway after a long long time rambling about, maaaaybe its the jovian.steamos.* options that i have left out? but i dont believe i need a session which is AGGRESSIVELY DECLARING things that i should disable all of my other sessions just for it!!

edit: im so tired… im not a computer person. maybe i will make a new post about this service here (because i dont want to use github, like ever. especially after i tried to search for a specific piece of code and it wanted me to “log in”, just piss off, mate). will try that steamos.* blahblahblah tomorrow uhhh

P.P.S. I KNOW!!! i can just “boot off of a live steamOS image and update my firmware there” BUT I DONT WANT TO. ffs, i have nixOS that can do the same thing

a bit of progress for screen rotation in x11.

because option jovian.devices.steamdeck.enableXorgRotation has no effect, i did some black magic fuckery (math) and came up with this:

  services.xserver.monitorSection = ''
    Option "Rotate" "right"
    Option "DisplaySize" "160 100"
  '';

imperial variables. imperial lengths. (there was no other way)

for example, services.xserver.dpi = 144;, which is a scale of 1.5 (96 (1.0) + 48 + (0.5) = 144 DPI which is good enough for a for a 7.4" inch screen) DOES NOT WORK for some unknown reason (im not surprised anymore), when i set the monitorSection, so yeah. instead, i got the diagonal size of my screen and put it into a DPI / PPI calculator and i rounded the numbers off in millimeters - 1280p = 160mm, 800p = 100mm. what is interesting is the fact that i managed to do this, since i hate math :slight_smile:

the xrandr in /etc/xdg/autostart way also doesnt really work for me, its just gonna stay active the whole time in the background.

autorandr is 2 difficult 4 me, BUT

  services.xserver.displayManager.setupCommands = ''
    ${pkgs.xorg.xrandr}/bin/xrandr -o right
    ${pkgs.xorg.xrandr}/bin/xrandr --dpi 144
  '';

does the same thing what i did in monitorSection but now its just a matter of preference

now, one might have to set services.xserver.exportConfiguration = true; if they are having no results, but i didnt have to do that, so…

finally, leftwm/config.ron

a snippet:

  workspaces: [(
    output: "eDP-1",
    y: 0,
    x: 0,
    width: 1280,
    height: 800,
    max_window_width: 1280,
  )],
  tags: [ "1", "2", "3", "4", "5", "6", "7", "8", "9", ],
  layouts: [
    "Grid",
  ],
  layout_definitions: [(
    name: "Grid", 
    flip: None, 
    rotate: East, 
    reserve: None, 
    columns: (
      flip: None, 
      rotate: East,
      main: None, 
      stack: (
        flip: None, 
        rotate: East, 
        split: Grid
      ),
      second_stack: None
    )
  )],
  layout_mode: Workspace,

im not sure if this is relevant at all or if it even does anything, but i have set it up like this, i only have one layout (i dont use x11 that often)

now… as for the two commands (jupiter-biosupdate and jupiter-controller-update) - still nothing. my suspicion is that they were mysteriously removed in some pr, i assume.

P.S. yes, once again, i had to comment out every other jovian.* option that may conflict/interfere with whatever i said in this reply

P.P.S. maybe someone will find this useful in the future, but here is how to disable the screen turning off after 10 minutes (spoiler alert: its DPMS)

  services.xserver.serverFlagsSection = ''
    Option "BlankTime" "0"
    Option "StandbyTime" "0"
    Option "SuspendTime" "0"
    Option "OffTime" "0"
  '';

which is (almost) the same as

  environment.extraInit = ''
    ${pkgs.xorg.xset}/bin/xset s off -dpms
  '';

btw, use one or the other, because otherwise -dpms would revert the changes, but its also possible to omit -dpms altogether

P.P.P.S. bonus: this is the (internal) monitor setup for steam deck that i use in hyprland:

monitor = , preferred, auto, 1, transform, 3

where 3 is to turn by 270 degrees (unlike turn by 90 degrees, which jovian.devices.steamdeck.enableXorgRotation HOPELESSLY uses for some reason)

oh, i forgot i was doing this.

so far, my only complaint is that perhaps there should be an (optional) cachix cache, because compiling a kernel is always slow, ESPECIALLY on a steam deck, ESPECIALLY (!!!) when it compiles EVERY SINGLE cpu/gpu platform!

i looked it up and found this:

but i literally dont know what any of that means. i just want a linux_jovian kernel for a steam deck, stripped entirely of nvidia or intel… :sob:

for example, on my steam deck the valve kernel compiles in just under 2 hours (~1h 48m)… and i know its worth it because it’s been compiled on the same hardware, so i get better performance (so ive heard) rather than by a remote builder somewhere else, most likely on another architecture, even… but when it does, steam deck is completely unusable, one can imagine…

That’s false. The kernels you produce non-locally are exactly the same as the kernels you produce on your steamdeck, in a nix context.

Theoretically you can use the -march compile flag to get optimizations for your specific architecture, but this makes your builds by definition unreproducible, so that flag is not enabled on NixOS.

You could change the flags if you really wanted to, but the performance impact is next to zero, especially on more modern architectures, since the number of CPU-specific optimizations is ever-shrinking because almost no software is built with -march anyway, so bonus CPU features aren’t really a selling point anymore (and most people buying them have no clue about any of this anymore either, so it doesn’t help with marketing either).

If you did want to use CPU-specific optimizations, you could still build the software remotely if instead of using -march and building locally you just find the optimization flags that target your CPU and turn them on individually. The result would still be the same, but now reproducible and no longer reliant on you building the software on the target hardware.

A cache would be neat, but if you want to you can also run the build on a proper PC on your local network.

To do that, all you need to do is run an ssh server on the machine you want to build on, and then change the rebuild command slightly:

nixos-rebuild boot --build-host '<username>@<host/ip>' --use-substitutes

As long as you have ssh credentials (ideally you don’t use password auth for ssh), the build will be executed entirely on the build host, and the results will be downloaded to your steamdeck afterwards.

2 Likes

okaaay :roll_eyes:

i will sort the remote building out a tad bit later once i figure out THIS config first…

i actually have completely forgot about other useful flakes in my collection (commented out in similar fashion as the other 7000 lines…), where one of them SEEMS TO HAVE a cachix for jovian-nixos as well… apologies for having such a terrible memory.

and it has this jovian.devices.steamdeck.enable option, which also contains the kernel, linux-6.11.11-valve19, as of now. and with that, i no longer have to compile it for 2 hours every time!

so… that’s pogress right there!

EDIT: OOOOH SNAAAP! look what i found:

https://app.cachix.org/cache/jovian

AND

https://app.cachix.org/cache/jovian-nixos

i just put jovian after app.cachix.org/cache/ in and found cachix for jovian this way, which is… undocumented, i think? well, that’s another way to get cache!

P.S. i keep having this annoying issue with power management, where every time the battery reaches around 30%, it disconnects all USB (i.e. my dock station). and i didnt have this problem before jovian-nixos, but i have also started using services.tlp. since then with everything set to "performance"… and nor "usbcore.autosuspend=-1", neither services.tlp.settings.USB_AUTOSUSPEND helps… but that’s not the end of the world, is it? keeping the steam deck always plugged in will sort it out, surely :sunglasses:

edit: forgot to give an update whether this is true… NO. it does NOT have binary cache for the steam deck kernel even with all of those cachix caches provided, so, compiling for 3 hours every time there is an update? - unfortunately, YES. :sob: BUT!!! cachix from chaotic flake DOES work. so use that

also… the correct way to install a kernel (in my case) wouldve been boot.kernelPackages = inputs.jovian-nixos.packages.${pkgs.system}.linux; (according to this), but it doesnt work… because the flake.nix of jovian-nixos fucking sucks. :smoking:

other than that, its pretty good. so, im not using any of those steamos option features, i find them absolutely useless, cos im not using steam anyway, cos im using a steam DECK with a DOCK station to do DESKTOP things, not necessarily what its supposed to be all about (about valve or steam - no, its just a weird looking LAPTOP with built in joysticks to me, that i have disabled in its BIOS, as well as the touchscreen - just a waste of battery), but as a “tool to do everything else apart from gaming because i dont have anything else really”… though, okay, i do game a little bit, but only when im not hyperfocused on fixing my schisophrenic config. dont mind me haha

EDIT2: now that im thinking about… btw sorry, too many edits of an edit, DONT CARE. listen: the way it downloads the kernel is pretty weird. so it downloads a regular ass linux kernel package, without any binary cache, then it compiles for 2 hours and applies 4 specific patches… the last part? i can do myself. there is an option for it - boot.kernelPatches. and im thinking i can just simply yoink the patches from jovian-nixos and apply them post-factum on a kernel of my own choosing, e.g. zen… is that a good idea? there is only one way to find out!!!1