This little device is an awesome replacement for the built-in OS of modern “smart” TVs: it supports all codecs (including 4k60 AV1) and HDR formats, so if you like a pure Kodi experience in a FLOSS dedicated OS, it’s actually much superior to a PC or RaspberryPi setup ! However, the setup instructions are not always clear, and reddit is full of information and counter-information and i felt the need to sum it up here — even just for myself. If it helps anyone, even better ! I’ll try to keep this information updated.
The kernel situation
At the time of writing, there are 3 supported kernels to choose from:
- Amlogic-ng: kernel 4.9, Kodi 21.2, officially EOL but still receiving nightly builds
- pros: the only one able to decode the Dolby Vision FEL layer
- cons: the kernel being too old, if the box is running Android 14, it will not be able to use the eMMC for faster data storage (because Android switched to a new overlay filesystem that is not part of 4.9)
- Amlogic-ne (kernel 5.4, Kodi 21.2) and Amlogic-no (kernel 5.15, Kodi 22 — development branch); for these, Dolby Vision Profile 7 with FEL is converted to Profile 8 in realtime
Note that an unofficial custom build by forum user cpm is available here; it adds experimental features like VS10 Vision Engine support.
Kodi tuning
Buried in the massive amount of reddit information, i ended up with the following tuning:
- LG TV settings for my LG B1 (see rtings tuning guide)
- All Settings > Image format > Original
- Picture Mode: Expert (bright)
- Advanced > Clarity
- Sharpness 0
- All disabled
- TruMotion > User Selection
- De-Judder: 3 (adjust to your liking; above this value, i can’t stand the soap opera effect, but at 0 panning scenes just stutter too much on OLED to my taste)
- De-Blur: 0
- OLED Motion Pro: Disabled
- Settings > System > Display
- Do NOT set resolution to 4K (it may break the picture at least on -ng and -no)
- Refresh Rate: 60 Hz
- Settings > System > Audio
- Audio Output Device: select HDMI
- Allow Passthrough: whatever your receiver / soundbar supports; for my SP8YA, it’s all of them
- Settings > System > Input > Peripherals: Disable at least hibernation (not supported); then adjust to your liking, but i found this not very reliable, it’s a bit obscure
- Settings > System > CoreElec: disable noise reduction
- Settings >Services > NFS client: NFS chunk size to 1MB
- Settings >Services > Caching
- Buffer mode – cache settings to all methods: smb, local, remote, etc (default ignores local playback)
- Read factor – Set ‘Adaptive’ readfactor (default is 4x). This is a multiplier for the bandwidth allocation based on video bitrate. Eg if video bitrate is 50Mbps and multiplier is set to 4x, then Kodi allocates 200Mbps of bandwidth to fill the cache faster. Adaptive is recommended
- Memory size – Set 64mb cache size (default is only 20mb). If unchanged from 20Mb, I found it gives the ‘low-speed connection’ warning when playing high-bitrate 4K. Set a bit higher to prevent warning. Potentially this could be as high as 25% of RAM, but generally doesn’t need to even on high-bitrate 4K
- Chunk size – 1MB
Turning the box on and off
Unfortunately, hibernation is not supported with CoreELEC (for this device, at least); also device does not have any ways to be woken up (no infrared receiver, no Wake on Lan support) except that it will always power on when current is restored. I ended up using a smart plug to power it back on after turning it off.
Android Dual Booting
If the Box is running Android 14, a “Reboot to eMMC” entry is visible in the power menu. It is normal that it does not appear if you are still running Android 12.
To reboot back from Android to CoreELEC, install the Reboot to CoreElec Android APP.
Fixing the default magic remote shortcuts
The default key mapping of Kodi binds to live TV and other stuff i don’t need; i think the remote really lacks a dedicated pause button, and i like to see the technical details of the currently playing media, so i ended up remapping the colored buttons:
# cat ~/.kodi/userdata/keymaps/custom.xml
<keymap>
<global>
<remote>
<red>PlayPause</red>
<green>Fullscreen</green>
<yellow>PlayerProcessInfo</yellow>
<blue>Stop</blue>
</remote>
</global>
</keymap>
Playing YouTube videos
I like to choose a video i want to play from my phone (instead of trying to browse or type on the keyboard on Kodi or Android TV).
Unfortunately, the sendtokodi kodi addon (which uses yt-dlp to stream pretty much anything in theory) can only play SD quality YouTube video since they switched to DASH for anything high quality, the only and last option is to endure the painful Youtube Kodi addon setup process, which requires you to declare a google developer app. Once done, you can use the “Send to Kodi” feature of NewPipe (or share to Kore from the Youtube Android app), which tells the Kore Android App to open the URL.
Typing faster on the virtual keyboard
Who doesn’t hate virtual keyboards ? If you don’t have a physical keyboard hooked to the set-top-box, you can use the incredibly useful Kore “keyboard” top right icon, which allows you to send text from your Android phone (either type or copy-paste).
Fixing corrupted CoreELEC boot splash
It seems that some Android set-top-boxes like the Homatics R 4K Plus do enable Dolby Vision and/or HDR directly on boot (visible on the initial logo splah), which causes such corrupted display when CoreELEC is booting:

This can be fixed by ssh’ing into the box and executing:
# fw_setenv dolby_status 0
# fw_setenv dolby_vision_on 0
Unfortunately, rebooting to Android will require to re-run the above.
While trying to understand what my HDMI source device was outputting (especially problematic with Android TV auto-framerate support which is app-dependent), i discovered that there are two “secret” features on the LG WebOS of my B1 TV which show advanced input informations.
1. Spamming the green button 7 times on the LG Magic Remote will show the VRR information overlay (explaining active colorspace, frequency and resolution); it will appear at a random corner, and disappear after a few dozen seconds or pressing the back button; see this video for details
2. You can access even more HDMI diagnostics by going into Settings / Progammes, then hover over programme tuner and press 11111. Click on the HDMI diagnostics to access low level debug. See this video for more details

With these two, i was able to confirm whether an app running on an Android TV is doing auto-framerate or not.
I use a C920 webcam which is really nice, but tends to lose focus in my setup; i preferred to disable AF entirely by creating the following service (i chose to create /etc/systemd/system/webcam.service):
[Unit]
Description=Disable AF on c920
Requires=sys-devices-pci0000:00-0000:00:14.0-usb1-1\x2d3-1\x2d3.2-1\x2d3.2:1.2-sound-card2-controlC2.device
After=sys-devices-pci0000:00-0000:00:14.0-usb1-1\x2d3-1\x2d3.2-1\x2d3.2:1.2-sound-card2-controlC2.device
[Service]
Type=oneshot
ExecStart=/usr/bin/sleep 5
ExecStart=/usr/bin/v4l2-ctl --set-ctrl=focus_automatic_continuous=0
ExecStart=/usr/bin/v4l2-ctl --set-ctrl=focus_absolute=0
RemainAfterExit=true
StandardOutput=journal
[Install]
WantedBy=multi-user.target
I had it depend on the alsa device provided by the webcam for simplicity, but the V4L device is apparently initialized a bit later, which is why i added an arbitrary sleep before running the commands. To find our the proper sys-devices path, just do:
$ systemctl | grep C920
sys-devices-pci0000:00-0000:00:14.0-usb1-1\x2d3-1\x2d3.2-1\x2d3.2:1.2-sound-card2-controlC2.device loaded active plugged HD_Pro_Webcam_C920
Remember to enable the service with
systemctl daemon-reload
systemctl enable --now webcam.service
If it does not work, check out the output log after boot:
$ journalctl -u webcam.service
mai 30 10:25:10 homepc systemd[1]: Starting Disable AF on c920...
mai 30 10:25:20 homepc v4l2-ctl[1781]: focus_absolute: Invalid or incomplete multibyte or wide character
mai 30 10:25:20 homepc v4l2-ctl[1781]: VIDIOC_S_EXT_CTRLS: failed: Invalid or incomplete multibyte or wide character
mai 30 10:25:20 homepc systemd[1]: webcam.service: Main process exited, code=exited, status=255/EXCEPTION
mai 30 10:25:20 homepc systemd[1]: webcam.service: Failed with result 'exit-code'.
mai 30 10:25:20 homepc systemd[1]: Failed to start Disable AF on c920.
We had a case where multiple servers are using nginx with the exact same configuration to cache short-lived content. And just one of the servers was not caching at all. After a lot of head scratching, we discovered that the server was not synced with NTP, and had a date in the future. As it turns out, “NGINX caches a response only if the origin server includes either the Expires header with a date and time in the future, or the Cache-Control header with the max-age directive set to a non‑zero value.” Because the clock was in the future, it was considering the expiration date as in the past, hence not caching at all. Yet another reason to enable NTP on all your servers !
I was trying to flash a new firmware onto a Xiomi Mi A3 phone on Linux, and i was puzzled by the following problem: adb devices was listing the phone perfectly (and adb reboot fastboot was doing the expected thing), but fastboot devices was not picking up the device despite the device showing the fastboot picture.
After a lot of searching, i eventually found that the cable was the culprit: using the vendor USB cable fixed the problem !
It’s very counter-intuitive to think that the cable produces this situation where adb works but not fastboot (i was expecting both to work — or not at all), so i thought i’d share the solution here. If anyone know how this is possible (4/5 wire USB cables ???), please comment !
The Audeze Penrose is a nice headset that plays quite nice with Linux out of the box; however, as specified in their user manual, “Software based volume controls such as those in Windows or Mac OS will have no effect when connected over the 2.4gHz wireless adapter”, which is not ideal (you have to use the hardware controls which are not very fine-grained).
Pulseaudio
Below is an attempt at a custom udev rule which applies a custom pulseaudio profile which disables hardware volume control (using software volume control).
I did not find a way to fix the icons (the device appears as a PCI device), but it’s working. If someone understands the deep magic required to change the icon, i’m interested !
$ cat /etc/udev/rules.d/90-penrose.rules
SUBSYSTEM=="sound", ACTION=="change", KERNEL=="card*", SUBSYSTEMS=="usb", ATTRS{idVendor}=="3329", ATTRS{idProduct}=="0011", ENV{PULSE_PROFILE_SET}="/etc/pulse/penrose-profile.conf"
$ cat /etc/pulse/penrose-profile.conf
[General]
auto-profiles = no
[Mapping Headphone]
device-strings = hw:%f
channel-map = left,right
paths-output = /etc/pulse/penrose-output.conf
direction = output
[Mapping Mic]
device-strings = hw:%f
channel-map = mono
paths-input = analog-input-mic
direction = input
[Profile default]
input-mappings = Mic
output-mappings = Headphone
skip-probe = yes
$ cat /etc/pulse/penrose-output.conf
[General]
description = Stereo
[Element PCM]
switch = mute
volume = ignore
PS: this helped a lot
[EDIT] Pipewire / wireplumber
Since then, i switched to pipewire as drop-in replacement for pulseaudio. Obviously the previous tweak does not work anymore, but hopefully wireplumber offers a similar fix and the Arch Linux wiki had a suggestion already.
$ cat ~/.config/wireplumber/main.lua.d/51-volume-fix.lua
table.insert (alsa_monitor.rules, {
matches = {
{
-- This matches all cards.
{ "device.name", "matches", "alsa_output.usb-Audeze*" },
},
},
-- Apply properties on the matched object.
apply_properties = {
-- Don't use the hardware mixer for volume control. It
-- will only use software volume. The mixer is still used
-- to mute unused paths based on the selected port.
["api.alsa.soft-mixer"] = true,
}
})
To determine the proper naming, the Arch wiki wireplumber article proves useful:
$ pw-cli list-objects | grep Penr
node.description = "Audeze Penrose Mono"
node.name = "alsa_input.usb-Audeze_Audeze_Penrose_1234567890-01.mono-fallback.2"
node.nick = "Audeze Penrose"
port.alias = "Audeze Penrose:playback_FL"
node.description = "Audeze Penrose Stéréo numérique (IEC958)"
node.name = "alsa_output.usb-Audeze_Audeze_Penrose_1234567890-01.iec958-stereo"
node.nick = "Audeze Penrose"
port.alias = "Audeze Penrose:monitor_FL"
device.description = "Audeze Penrose"
device.name = "alsa_card.usb-Audeze_Audeze_Penrose_1234567890-01"
device.nick = "Audeze Penrose"
port.alias = "Audeze Penrose:playback_FR"
port.alias = "Audeze Penrose:capture_MONO"
port.alias = "Audeze Penrose:monitor_FR"
Between hibernations, pressing media keys (play/pause, next) would stop working in Spotify on Gnome (3.34 at the time of writing).
I finally understood what happens by accidentally discovering that Chrome was actually binding these in place of Spotify. The solution is to disable Hardware Media Key Handling by accessing chrome://flags/#hardware-media-key-handling in your Chrome address bar.

EDIT 27/04/2022: since v100 it seems the flag is not available anymore in the chrome://flags UI, but it still works by adding the following switch to the launch flags (location may depend on your system):
$ cat .config/chrome-flags.conf
–disable-features=HardwareMediaKeyHandling
Edit 13/05/2022: the flag had been dropped unintentionally and has been re-introduced by the chromium team in v101.0.4951.64
Usually, powering off or rebooting a system will require interactive authentication (unless you create a custom sudoer rule to allow specific commands to be run without sudo). The more modern way to achieve this is to send the following signals over DBus (below is a dbus-send example, but you probably want to do this from a program):
$ dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.PowerOff" boolean:true $ dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 "org.freedesktop.login1.Manager.Reboot" boolean:true
Here is a python example
import pydbus
bus = pydbus.SystemBus()
logind = bus.get('.login1')['.Manager']
logind.Reboot()
Note that the above will require interactive user authentication, unless you create a custom polkit rule on e.g. /etc/polkit-1/rules.d/00-reboot-nopassword.rules
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.login1.reboot-multiple-sessions" && subject.user == "myusername"){
return polkit.Result.YES;
}
});
Browsers like Chromium and Firefox used to rely on X11 for sharing apps and the entire desktop on videoconferencing services like Zoom, Google Meet etc…
Now that Gnome/GDM use Wayland by default instead of X11, desktop / app sharing is basically broken (and most websites will suggest to go back to using X by uncommenting #WaylandEnable=false in /etc/gdm/custom.conf).
However, the Pipewire project allows for secure audio/video sharing under Wayland, and support is already in Chromium 53+, but needs to be manually enabled with the chrome://flags/#enable-webrtc-pipewire-capturer flag.

It also requires pipewire to be installed and setup to auto-start (the default on Arch), which you can check with:
$ systemctl --user status pipewire.socket ● pipewire.socket - Multimedia System Loaded: loaded (/usr/lib/systemd/user/pipewire.socket; enabled; vendor preset: ena> Active: active (listening) since Mon 2019-07-08 00:27:55 CEST; 8h ago Listen: /run/user/1000/pipewire-0 (Stream) CGroup: /user.slice/user-1000.slice/user@1000.service/pipewire.socket juil. 08 00:27:55 mymachine systemd[1157]: Listening on Multimedia System.
xdg-desktop-portal-gtk is also required if you use Gnome (or xdg-desktop-portal-kde if you use kde).
Once all requirements are fulfilled, sharing your desktop will offer the following user experience.

After allowing sharing of the desktop with the xdg-desktop-portal-gtk greeter, chromium can fetch and display preview of the desktop:

When hitting “share”, chromium will ask once again for desktop sharing (one of the reasons why this is not enabled by default already), but it’ll work (instead of sharing a black picture) !
Unfortunately, at the time of writing Firefox Pipewire support is only included from version 68 (currently in beta) on Fedora through a custom patch (Fedora/Redhat are the people behind most Pipewire / Wayland / Gnome development) not included on mainline Firefox.
More background info is available on Jan Grulich blog.
Here are my findings on the necessary tweaks to make a better use of the Lenovo X280 laptop on Arch Linux (after an initial EFI-based installation). These tweaks aside, i found no specific issues with it.
Installation-related topics
You need to disable Secure Boot in the BIOS in order to boot the USB drive (type Enter when the Lenovo logo is displayed then F1 to enter the BIOS)
This laptop being the first NVME device i own, i was expecting the NVME SSD to be on /dev/sda, but it is on /dev/nvme0n1 instead.
Invert Fn toggle state
By default you need to hit the Fn key to use e.g. Alt + F4; set Hotkey Mode to Disabled in the BIOS.
Install intel microcode updates
See dedicated wiki article. With systemd-bootctl here is how the entry config file looks:
$ cat /boot/loader/entries/arch.conf title Arch Linux linux vmlinuz-linux initrd /intel-ucode.img initrd /initramfs-linux.img options root...
Optimize Intel graphics
Enable firmware loading (GUC firmware updates GPU scheduler, and HUC updates video acceleration) and fastboot (will reduce early kms flicker when booting) :
echo "options i915 enable_guc=3 fastboot=1" | tee -a /etc/modprobe.d/i915.conf
Add the i915 module to /etc/mkinitcpio.conf so that the module options above are applied (this will also enable early kms) ; regenerate the initrd with:
mkinitcpio -p linux
Install the Xorg intel video driver (i was getting some tearing with the modesetting driver)
pacman -S xf86-video-intel
Enable the TearFree option (see Arch linux wiki article) by creating /etc/X11/xorg.conf.d/20-intel.conf
Section "Device" Identifier "Intel Graphics" Driver "intel" Option "TearFree" "true" EndSection
Fix cpu throttling issues
As described in the related Arch wiki article, “due to wrong configured power management registers the CPU may consume a lot less power than under windows and the thermal throttling occurs at 80°C (97°C when using Windows).”
This results in such error messages in the kernel logs:
déc. 22 22:55:51 archlinux kernel: CPU4: Core temperature above threshold, cpu clock throttled (total events = 1)
Install the lenovo-throttling-fix-git AUR package (package for https://github.com/erpalma/throttled), then run:
sudo systemctl enable --now lenovo_fix.service
This script forces the CPU package power limit and max temperature to higher values than the ones configured by Lenovo.
Power saving
If you do not own the proprietary ethernet dongle, disable it in the BIOS, as well as WOL. Also disable the fingerprint scanner if you don’t have the option on your device or if you don’t use it on Windows (it’s not supported on Linux at the time of writing anyway).
Install TLP:
pacman -S tlp acpi_call smartmontools systemctl mask systemd-rfkill.service systemd-rfkill.socket systemctl enable --now tlp slp-sleep
Install powertop and calibrate it (black screens are expected during the calibration, screen returns to normal when finished):
pacman -S powertop sudo powertop --calibrate
You can now use powertop to troubleshoot what is going on, estimates, and what the current power consumption is (i see 3W with minimum backlight and no network, and 4-6W with 10% backlight and wifi — that would be around 9h of battery according to powertop).
Windows 10 dual boot tweaks
The included Windows 10 recovery image is so bad that it produces error popups on boot after a factory reset ; installing a clean official Windows 10 before installing Arch is way better and after applying Windows Updates everything works perfectly without any bloatware. The Windows license key is embedded into the BIOS, so the install does not prompt for anything and you don’t lose it if you reformat the drive.
If using systemd-bootctl, uncomment the timeout value from loader.conf so that the boot menu does appear (by default it does not show up)
$ cat /boot/loader/loader.conf timeout 5 ...
Be sure to configure Windows 10 clock to use UTC to ensure that both Windows and Arch will stay on the same timezone (Windows uses localtime by default). Do this by running the following in cmd.exe (started in Administrator mode):
reg add "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation" /v RealTimeIsUniversal /d 1 /t REG_DWORD /f
Last, disable Fast Startup in Windows 10 so that there is no risk of data loss when Windows “stops” (i.e. hibernates when Fast Startup is enabled).
Misc rantings
The only criticism i have now against this laptop is the fact that there is no full-size ethernet connector; instead, there is a proprietary connector for which no dongle is provided in the box. It is quite expensive as well (even more expensive than a USB ethernet adapter, which is a shame).
Also, it appears that the LCD touches the keyboard, judging by the marks left visible on the display after reopening the lid.
I have used Thinkpads for 15 years, especially for the famed good Linux support, robustness and I/O versatility. I would have happily swapped a few hundred millimeters and grams for an Ethernet port, an SD card reader and a swappable battery … This X280 is a cheaper copy of the X1 carbon; not a bad device, but not filling the gap that was filled by the X60, X230 and other previous versions of that model.
[EDIT: i now have a T480s which is a bit bigger/heavier but provides a native RJ45 connector as well as an SD-card reader]


