Site Tools


Sidebar

hardwarerelated:nintendo_switch

What is here?

Some notes regarding running Linux on the Nintendo Switch. First things first, thanks fail0verflow. I did just play a bit on the software side, but fail0verflow was one of the 2 groups who found the way to run Linux, and established all the chain to make this possible, including providing the patched Linux kernel. After the initial release, most contributions/enhancements come from the switchroot project. You guys rock!

20190707_124709_nintendo_switchc.jpg

Nintendo Switch Hardware Specs

  • cpu:
    • Nvidia Tegra X1, model T210: 4x Cortex-A57, 4x Cortex-A53 (big.LITTLE approach, but Linux kernel 4.16 is just presenting the 4 A57 cores)
    • note: several variants of the switch are around, newer ones do not allow to run unsigned code from the RCM. The serial number can be used to check this. CPU variant details
    • Nvidia Maxwell GPU
    • 4GB LPDDR4 RAM
  • wlan:
    • chip: broadcom 4356
    • driver: brcmfmac
  • audio
    • chip: ALC5639
  • power
    • 'upower -d' hands out good data, also 'acpi'
    • charging from linux works

Graphical Demos/Games

What are people actually using the Nintendo switch/Linux setups for? Some use it like a workstation on HDMI output, with the option of undocking and using it on the road. Of course, databases, libreoffice and so on work. Some more graphical ideas to try out:

20190616_184612_switch2s.jpg

  • Use chromium (dnf -y install chromium) to run WebGL code:
  • 'dnf -y install glmark2 extremetuxracer'
  • 'dnf install freedoom2' also runs nicely: 'prboom -window -iwad /usr/share/doom/freedoom.wad'. Explicit OpenGL rendering with '-vidmode gl'.
  • mplayer can play videos fetched with youtube-dl
  • Recompile bb, with the patches from debian. I did not get it compiled with libmikmod though, so no sound: https://packages.debian.org/sid/bb
  • Scummvm with 'Secret of Monkey Island'
  • Amiga emulator https://fs-uae.net/ : packages just build for x86_64. Rebuilding fails, need to try to build directly.
  • moonlight: streaming windows games to the switch, details
  • running emulators:
    • reicast: dreamcast emulator
    • ishiiruka: sega emulator
    • dolphin: gamecube/wii emulator
    • citra: 3DS emulator
  • Karaoke applications like UltraStar Deluxe

What Linux flavour works (not)?

distro wlan xorg plainxorg acceleratedaudiocuda
Lakka (retro game focused) yes yes yes yes no
L4T Ubuntu yes yes yes yes yes
Fedora 28/29/30/31/32yes yes yes yes no
Android 8.1/LineageOS 15.1 yes n/a n/a yes no
  • For a start, setting up Lakka/switch (a distro intended to run emulators) or the L4T Ubuntu is best for most people. These provide most features, for example audio support via the switch speakers. They can also run sshd, you can connect to wlan and look around.
  • With more work you can also bootstrap Fedora32, details are here in the wiki.
  • Note: Newer Nintendo switch can not be brought into RCM, so unsigned payloads via USB can no longer be supplied, this prevents running own code like Linux on these models.

Boot order for Linux@switch

  1. As first step, the switch needs to be booted into RCM, an early debug mode. For doing this for the first time, pins on the switch need to be crossed, for example using this RCM jig device. You can create a Jig yourself, or buy them online. When booting to RCM succeeded, you can use Hekate to set 'autorcm', the switch will then after resets automatically enter RCM instead of booting Nintendos Horizon.
  2. With the switch being in RCM, it will do nothing, the screen will be black. At this state, payload code to be run needs to be supplied via USB. The code can be supplied from a Linux box via Fusee launcher.
  3. What to run as first level payload?
    • Hekate could be used, offered via Fusee launcher. Hekate can then
      • configure 'autorcm'
      • it can verify the switches battery charge state
      • it can run Linux kernels from microsd-cards in the switch (using coreboot)
      • it can poweroff the switch
    • Shovel2 can be used to upload Linux kernels via USB, coreboot is also here used. Userland to be booted could be on the microsd card, or supplied via NFS.
    • ArgonNX has more eyecandy than hekate.
  4. Which kernel to run? There are basically 2 levels of kernel patches.
    • mid-2018 kernel, using the initial patches from Fail0verflow: no audio, problems charging the switch, resets when load is high (compile things only with 'make -j1'), wlan only works after one reset of the system. Yet, on this kernel one can see Linux console output directly on the screen after booting. This kernel is great for initially running for example Fedora30, Opensuse or Debian userlands: because you can use the screen to get debugging output, until you get the userland appropriately configured to log into wlan after booting. From that state on you can work via SSH.
    • mid-2019 kernel from the L4T distro with nvidia patches: audio, charging and wlan work, no resets under high load. But no initial console output. Lakka and the L4T distro use this kernel.
  5. Which userland to run? L4T and Lakka come with kernel/userland together. The kernels with switch patches can be used on other userlands though, like Fedora30, SuSE, Debian.

L4T Ubuntu 3.2 installation

This is also the first step for installing Fedora, L4T will be used to bootstrap. The L4T instructions, for reference, are here. My notes for installing L4T version 3.0 are now here.

  • Requirements:
    • A Nintendo switch which is old enough, switch lite and newer normal switches do not boot into RCM.
    • A microsd-card, 16+ GB
    • A Linux system with usb3 (Fedora31/x86_64 here)
    • A USB-C cable, to connect the switch to the Linux system
  • Software preparations:
# Insert your microsd-card, 32+ GB
# Find the microsd-card device, i.e. /dev/mmcblk0p1

parted
# create make a single partition, 16GB size. No GPT, partition table.
mkfs.vfat /dev/mmcblk0p1

# Now extract hekate, copy contents
cd ~/Downloads
mkdir hekate_ctcaer_5.5.7_Nyx_1.0.4 && cd hekate_ctcaer_5.5.7_Nyx_1.0.4
unzip ../hekate_ctcaer_5.5.7_Nyx_1.0.4.zip
mount /dev/mmcblk0p1 /mnt/tmp
tar cf - bootloader|(cd /mnt/tmp && tar xfv -)

# now insert the card into the Nintendo switch.
  • Ensure the switch is turned off
  • Insert your Jig on the right side
  • Press the 'volume up' button, keep it pressed
  • turn on the switch, in pressing the power button. The screen should stay black, so RCM mode.
  • connect the USB cable to the Linux system
  • Supply the payload from the Linux system: sudo ./fusee-launcher.py hekate_ctcaer_5.5.7.bin
  • When hekate is booted, remove the Jig, and activate “auto RCM” in the menu. With this activated, the switch will boot into RCM without the Jig.
  • enter “Tools”, then partition the card. Move the Linux slider to 16GB, then click “next step”. When done, remove the card and insert it in the Linux system.
# We will extract the archive into the newly created partition
mount /dev/mmcblk0p1 /mpt/tmp
cd /mnt/tmp
7z x /<path-to>/switchroot-ubuntu-3.2.0-2020-10-05.7z
cd ..; umount tmp
  • Insert the card into the nintendo switch, Hekate should recognize it and reload itself. Enter again Tools/partition manager, then “Flash Linux”. The image files we just wrote should be found, flashing to the Linux partition can be started.
  • Connect the 2 joycons. From the hekate main menu, go to “NYX tools”, dump the pairing data.
  • Remove the microsd card, insert it into the Linux system.
# We will extract the update
mount /dev/mmcblk0p1 /mpt/tmp
cd /mnt/tmp
rm -rf bootloader/ini/L4T-bionic.ini switchroot/ubuntu
7z x /<path-to>/switchroot-ubuntu-3.3.0-update_only-2021-04-08.7z
cd ..; umount tmp
  • Move the card to the Nintendo switch again, select “Ubuntu” from “More Configs”
  • Wait some minutes, work through the setup steps. Select “auto login”.
  • Login:
    • If you setup WLAN in the first installation steps, you can login via WLAN.
    • Alternatively, you can login via network over the usb-cable: “modprobe usbnet; ip addr add 192.168.55.2/24 dev enp0s20f0u1; ssh <user>@192.168.55.1”.
  • Use “sudo su -” to become root, and update the installation: “apt update; apt dist-upgrade”

Installing Fedora 32

These steps need an already installed L4T on the microsd card: partitions 1 (vfat) and 2 (ext4, L4T) have been set up. After increasing the second partition to 16GB, I create a third partition and install Fedora 32 there. I use a Fedora31/x86_64 system here as helper.

For installing the Fedora32 aarch64 userland for the switch, I use Fedora-Server-32_Beta-1.2.aarch64.raw.xz. The images for Fedora31/32 do not come with wpa_supplicant, we need to install it manually. Networkmanager-wifi is part of the images.

### The following steps are done on the Fedora31/x86_64 system,
### with the microsd card with L4T installed.
fdisk /dev/mmcblk0
# n / p / 3 / <return> / <return>
mkfs.ext4 /dev/mmcblk0p3
mount /dev/mmcblk0p3 /mnt/tmp3
cd /mnt/tmp3

xz -d Fedora-Server-32_Beta-1.2.aarch64.raw.xz
kpartx -av Fedora-Server-32_Beta-1.2.aarch64.raw
vgscan 
vgchange -ay
mount /dev/fedora/root /mnt/tmp
cd /mnt/tmp
tar cfp - *|pv|(cd /mnt/tmp3 && tar xf -)

# Now, as the copy finished, preparations
cd /mnt/tmp3
echo '/dev/mmcblk0p2 / ext4 defaults 0 0' >etc/fstab

# set a root password, for example one from your /etc/shadow
vi etc/shadow
# Now either add your ssh-pubkey to root/.ssh/authorized_keys,
# or modify etc/ssh/sshd_config to accept password root logins.

echo switch.local >etc/hostname
echo '127.0.0.1   switch.local switch' >>etc/hosts

# disable console on tty1.  We have no input anyway, and can
# see debugmessages that way - via HDMI
mv etc/systemd/system/getty.target.wants/getty@tty1.service root/

### prepare wlan
# I have my wlan already setup on my Fedora30 host system,
# so I can simply copy over the files
cp /etc/sysconfig/network-scripts/keys-mynetwork \
   /etc/sysconfig/network-scripts/ifcfg-mynetwork \
    etc/sysconfig/network-scripts/
    
# Our Fedora-server image lacks package wpa_supplicant.
# The package has to be fetched, and installed.
# Either
# - chroot into the Fedora partition, and "rpm -i <file>"
#   (needs to be done from an aarch64, for example the L4T)
# - or use
#     cd /mnt/tmp2
# rpm2cpio <rpmfile> | cpio --extract --verbose --make-directories --preserve

# We have 2 options:
# a) create an own inifile for Fedora on the boot partition,
#    then we have full control over kernel parameters, but
#    we need to write a new boot.scr file
# b) Or, we just exchange partitions 2 and 3 in the
#    partition table.  Doing that for now.

# twist partitions 2 and 3 with sfdisk
sfdisk /dev/mmcblk0 -l >/root/ptable_normal
cp /root/ptable_normal /root/ptable_twisted
vi /root/ptable_twisted
# change mmcblk0p2 -> mmcblk0p3, and 
# the original mmcblk0p3 -> mmcblk0p2
sfdisk /dev/mmcblk0 --force </root/ptable_twisted

# mount the L4T partition
mount /dev/mmcblk0p2 /mnt/tmp2

echo brcmfmac >etc/modules-load.d/brcmfmac.conf
cp /mnt/tmp2/lib/firmware/brcm/brcmfmac4356-pcie.txt lib/firmware/brcm/
cp -r /mnt/tmp2/lib/modules/4.9.140+/ lib/modules

# Now we can boot the system.  After the reboot, wlan should
# work.  Login via ssh into root, run dnf upgrade,
# remove and install packages
dnf remove iscsi-initiator-utils-iscsiuio iscsi-initiator-utils \
  clevis-luks atmel-firmware
dnf install -y langpacks-ja upower screen
dnf update -y

for i in auditd smartd pcscd ModemManager multipathd mdmonitor \
         dmraid-activation initial-setup lvm2-monitor zram-swap \
         plymouth-start lm_sensors udisks2 ; do
    systemctl disable $i
done

### tuning, seen in the L4T scripts
cat >/etc/rc.local<<EOT
#!/usr/bin/bash
echo 2048 > /sys/block/mmcblk0/queue/read_ahead_kb
echo 0 > "/proc/sys/vm/lazy_vfree_pages"
EOT
chmod +x /etc/rc.local
/etc/rc.local
ln -s /etc/rc.local /etc/rc.d/rc.local

### if you want rpmfusion
dnf install \
  https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \
  https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm

Fedora Xorg/LXDM autologin

ssh root@switch

# Install the basic environment.
dnf -y groupinstall 'Basic Desktop' 'LXDE Desktop'

# Install
# - xvkbd, a virtual keyboard.  'florence' is a further option.
# - synergy, so I can use mouse/keyboard of my linux box
# - f29-backgrounds, because they are awesome :)
# - mplayer: media player, blueman: connect bt headsets etc.
dnf install -y xvkbd synergy f29-backgrounds-base mplayer blueman

# Now copying drivers from an L4T installation on partition2:
mount /dev/mmcblk0p3 /mnt/tmp3/
cd /mnt/tmp3

cp usr/lib/xorg/modules/drivers/nvidia_drv.so \
  /usr/lib64/xorg/modules/drivers/
cp usr/lib/xorg/modules/extensions/libglxserver_nvidia.so \
  /usr/lib64/xorg/modules/extensions/
cp usr/bin/dock-hotplug /usr/bin

mkdir -p /usr/lib/aarch64-linux-gnu
cp -r usr/lib/aarch64-linux-gnu/tegra-egl \
  /usr/lib/aarch64-linux-gnu
ln -s /usr/lib/aarch64-linux-gnu/tegra-egl/ld.so.conf \
  /etc/ld.so.conf.d/aarch64-linux-gnu_EGL.conf
cp -r usr/lib/aarch64-linux-gnu/tegra \
  /usr/lib/aarch64-linux-gnu
ln -s /usr/lib/aarch64-linux-gnu/tegra/ld.so.conf \
  /etc/ld.so.conf.d/aarch64-linux-gnu_GL.conf

ldconfig

cp -r lib/firmware/tegra21x lib/firmware/gm20b /lib/firmware/
cp lib/firmware/bcm4354.hcd /lib/firmware/

# special xorg config
cat >/etc/X11/xorg.conf<<EOT
Section "Module"
    Disable     "dri"
    SubSection  "extmod"
        Option  "omit xfree86-dga"
    EndSubSection
EndSection

Section "Device"
    Identifier  "Tegra0"
    Driver      "nvidia"
    # Allow X server to be started even if no display devices are connected.
    Option      "AllowEmptyInitialConfiguration" "true"
    Option      "Rotate" "CW"
EndSection

Section "InputClass"
    Identifier "evdev touchscreen catchall"
    MatchIsTouchscreen "on"
    MatchDevicePath "/dev/input/event*"
    Driver "evdev"
    Option "InvertX" "no"
    Option "InvertY" "no"
    Option "SwapAxes" "no"
    Option "Calibration" "0 1279 0 719"
EndSection

Section "Monitor"
    Identifier "DFP-0"
    Option "Rotate" "left"
EndSection 
EOT

# MYUSER="lxde"
MYUSER="chris"
useradd -m $MYUSER

# We create a default autostart, including running synergy
# client, trying to connect to a synergy-server on 192.168.0.2
mkdir -p /home/$MYUSER/.config/lxsession/LXDE
cat >/home/$MYUSER/.config/lxsession/LXDE/autostart<<EOT
@lxpanel --profile LXDE
@pcmanfm --desktop --profile LXDE
@synergyc 192.168.0.2
EOT
chown -R $MYUSER /home/$MYUSER/.config

# configure autologin
vi /etc/lxdm/lxdm.conf
# autologin=username  # <- insert the username which you use
# session=/usr/bin/startlxde

# We need to ensure that our user later appears in the 'who' output.
# That is important for the /usr/bin/dock-hotplug script, for
# switching screens.
echo 'sessreg -a -l $DISPLAY -x /etc/X11/xdm/Xservers $USER &' >> \
  /etc/lxdm/PostLogin
echo 'sessreg -d -l $DISPLAY -x /etc/X11/xdm/Xservers $USER &' >> \
  /etc/lxdm/PostLogout

rm -f /etc/systemd/system/display-manager.service
systemctl enable --now lxdm
systemctl set-default graphical.target

Fedora sound

# Now copying drivers from an L4T installation on partition2.
mount /dev/mmcblk0p2 /mnt/tmp2/
cd /mnt/tmp2

dnf install -y alsa-ucm alsa-plugins-pulseaudio alsa-utils \
  pulseaudio pulseaudio-module-x11 pulseaudio-utils pavucontrol
cp -r usr/share/alsa/ucm/tegra-snd-t210ref-mobile-rt565x/ /usr/share/alsa/ucm/
cp usr/share/alsa/cards/tegra-hda.conf /usr/share/alsa/cards

cp -r opt/nvidia/ /opt/
cp usr/sbin/nv* usr/sbin/brcm* /usr/sbin/
cp -r etc/nv* /etc/
cp etc/systemd/nv* /etc/systemd
cp etc/systemd/system/nv*service /etc/systemd/system/

cp etc/asound.conf.* /etc/

# ensure that /etc/asound.conf is linked to
# the appropriate file, depending on whether we are docked or not
cat >/etc/udev/rules.d/92-dp-switch.rules<<EOT
SUBSYSTEM!="switch", GOTO="dp_end"
KERNEL!="dp", GOTO="dp_end"
ATTRS{state}=="1", TEST=="/proc/asound/tegrahda", RUN+="/bin/ln -sf /etc/asound.conf.tegrahda /etc/asound.conf"
ATTRS{state}=="1", TEST=="/usr/bin/dock-hotplug", RUN+="/usr/bin/dock-hotplug"
ATTRS{state}=="0", TEST=="/usr/bin/dock-hotplug", RUN+="/usr/bin/dock-hotplug"
ATTRS{state}=="0", TEST=="/proc/asound/tegrasndt210ref", RUN+="/bin/ln -sf /etc/asound.conf.tegrasndt210ref /etc/asound.conf"
LABEL="dp_end"
EOT

# reboot

# for playing via alsa, this has to be active:
alsamixer # I2S1 Mux -> ADMAIF1

# we should now be able to start X, and have sound output:
mplayer <something> 

# When the switch is docked, the screen should switch to HDMI
# output automatically, via profile switch in /usr/bin/dock-hotplug .
# The profile can also be selected via 'pavucontrol' from X.

# also for output testing: 
# speaker-test –channels 2 –rate 48000 –device hw:0,3​

Fedora/switch FAQ

  • Q: Can I use XFS?
  • A: Not if you use the kernel as compiled by the L4T project. It has no support for XFS.
  • Q: Can I use multiple partitions on one sdcard?
  • A: Yes. You can setup L4T as per instructions, and enlarge the L4T partition, for example to 16GB. You can create further partitions after that area, and later twist the partitions to select what to boot. Alternatively, you could create own boot-inis to easily select which Linux to start from hekate.
  • Q: Can I compile kernels on Fedora?
  • A: I did not succeed to recompile the L4T kernel on Fedora30/switch with the native GCC9. Seems like it does not go well with the tegra-specific patches from nvidia. Maybe with GCC8. Or compile custom kernels on L4T/switch, or crosscompile on Linux/AMD64. As for debugging why a self compiled kernel is not booting: when docked, debug messages can be seen via HDMI output.
  • Q: Why can I not run glxgears?
  • A: Run 'strace -f -o logg glxgears' to see details, might just be a permission issue. Accessing /dev/nvhost-ctrl or /dev/nvmap ?
  • Q: Something is not working..
  • A: You might want to have a look at the L4T-Fedora repo, verify the configfiles and deployment with the one from here.

RHEL8/aarch64

  • RHEL8 userland runs ok with the L4T kernel.
  • Do not use XFS, the L4T kernel does not include the xfs driver.
  • Note: EL8 comes with basic xorg, I was able to run an X and xterm, but no gnome. EPEL8 might have further window managers.
# I used the cloud image as base, mounted and copied
# the contents to the second partition of a microsdcard
guestmount -a /tmp/image.qcow2 -m /dev/sda2 /mnt/tmpimage
mount /dev/mmcblk0p2 /mnt/tmp2/
cd /mnt/tmpimage
tar cfp - *|pv|(cd /mnt/tmp2 && tar xfp -)
guestunmount /mnt

cd /mnt/tmp2
# have to add contents wpa_supplicant and
# NetworkManager-wifi packages
rpm2cpio ..

# move cloudinit
mkdir etc/systemd/system/tmp
mv etc/systemd/system/multi-user.target.wants/cl* etc/systemd/system/tmp
  • For running xorg: the Fedora30 steps for taking over drivers can be used, and 'startx' brings up Xorg. As windowmanagers, these 2 are available as packages:
    • metacity ('exec /usr/bin/metacity' in ~/.xinitrc)
    • matchbox-window-manager ('/usr/bin/matchbox-window-manager in ~/.xinitrc)
  • No virtual keyboard x-application seems to be available. So this, or synergy, would have to be compiled and installed by hand.

Generic hints

Touchscreen detection not in sync

The touchscreen driver will work in horizontal mode by default, but the xorg screen might come up in vertical mode. Above xorgs monitor definition should rotate the monitor for all Xorg windowmanagers, but the rotation could instead also be done at the windowmanager level. Rotating the screen in LXDE:

mkdir -p ~/.config/autostart
cat <<EOT >~/.config/autostart/.desktop 
[Desktop Entry] 
Type=rotater
Exec=xrandr --output DSI-0 --rotate left
EOT

Booting is slow

Use systemd to illustrate what takes time at boot, and consider to disable services. Also comparing the graph from Fedora30 with the one from L4T helps. This helped me tremendously getting boottime down, after turning the switch on, it takes now 29sec until the usable LXDE screen of Fedora30. I supply the kernel via usb instead of reading from disk, that is further potential for optimization, takes 5.2sec until kernel/initrd etc. are transferred and the kernel is booted.

  • Generate graph: `systemd-analyze plot >systemd_plot_fed.svg`
  • Open in firefox: `firefox systemd_plot_fed.svg`

console debugging

With newer kernels, there is no console output any more. After booting the kernel, this switch screen just flashes up. Possible alternate debugging with console over usb, the L4T initrd has usb-debug libraries:

How to run the synergy server?

You are running the synergy client for mouse/keyboard sharing, in the LXDE autostart. But what to run to get the server part? I use this:

[chris@電脳 ~]$ cat .synergy.conf 
section: screens
        dennou.local:
        switch.local:
end
section: links
        dennou.local:
                up = switch.local
        switch.local:
                down = dennou.local

end
[chris@電脳 ~]$ synergys
[chris@電脳 ~]$ 

microsd card benchmark

Do this in the switch, as the reader is quite good, better than the one in my thinkpad.

pv /dev/mmcblk0 >/dev/null
Toshiba 32GB 100MB/sec : 80MB/sec
LAZOS 32GB             : 65MB/sec

dealing with filesystem corruptions

I saw ext4 corruptions on a 32GB card, on both partitions. Using the RPM checksums to verify:

for i in $(rpm -qa|sort); do echo "### $i"; rpm -V $i; done  >>logg
egrep -B1 -v '^#|\.uuid' logg2|grep -c '^#'
egrep -B1 -v '^#|\.uuid' logg2|grep '^#'

overclocking

# enable overclocking
echo 1 >/sys/kernel/tegra_cpufreq/overclock
# set maximum frequency
echo 2091000 >/sys/devices/system/cpu/cpufreq/policy0/scaling_max_freq
# cet current frequency
cat /sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq 
# set governor
echo performance >/sys/devices/system/cpu/cpufreq/policy0/scaling_governor
hardwarerelated/nintendo_switch.txt · Last modified: 2024/03/03 11:46 by chris