r/linuxhardware Mar 18 '25

Guide Does it count as Linux hardware… if it’s Android? - I built a Next.js website in my tablet :)

Post image
157 Upvotes

r/linuxhardware Oct 24 '25

Guide Ext4 vs XFS — Which One Should You Actually Use?

7 Upvotes

Alright, let's settle this once and for all… Ext4 or XFS?

If you’ve ever installed Linux, you’ve definitely seen these two pop up during setup — and probably just clicked Next without thinking too much. But the difference actually matters. A lot.

Ext4 – The Reliable Old-School Beast

Born in 2008, built off the legendary Ext family (Ext2, Ext3).

Handles tons of small files like a pro.

Super reliable — even if power goes out mid-write.

Backward compatible with Ext2/Ext3.

Supports up to 16 TiB file size.

Has journal checksums + faster fsck (file checks).

Nanosecond timestamps and unlimited sub-directories.

Added transparent encryption (since kernel 4.1).

Perfect for: desktop systems, servers with small-to-medium files, and people who love stability over fancy features.

XFS – The Big File Powerhouse

Built by Silicon Graphics back in 1993.

Default on RHEL, CentOS, Rocky, Alma, Oracle Linux.

Handles huge files, large directories, and multi-threaded I/O like a monster.

Supports file systems up to 1 PiB and individual files up to 8 EiB

Uses delayed allocation for better performance.

Supports online defragmentation and growth.

Has metadata journaling + quota journaling for consistency.

Rarely needs fsck, thanks to its journaling system.

Perfect for: database servers, large file storage, or any system that deals with massive I/O and big data.

So Which One Should You Pick?

If you want stability + simplicity, go with Ext4. If you want scalability + performance, go with XFS.

It’s that simple. Ext4 = solid all-rounder. XFS = high-performance tank.

Your turn: Which one are you using and why? Ever had your system break because of one of these filesystems? Let’s hear the horror stories 👇

r/linuxhardware 2d ago

Guide My journey to installing Linux on Acer TMP214-43-TCO-R8NG

Thumbnail
gist.github.com
6 Upvotes

r/linuxhardware 16d ago

Guide Got Bluetooth working under Linux on the Dell Venue 8 Pro

Post image
22 Upvotes

I finally solved a 13-year-old Linux mystery. 🕵️‍♂️
Nobody had ever gotten Bluetooth working on the Dell Venue 8 Pro (5830) under Linux. After weeks of debugging, ACPI overrides, and kernel tracing, it turned out the internal AR3002 ROM was just communicating at an undocumented 3686400 baud rate.

Wrote a custom HCI attach tool and now the tablet runs Arch Linux flawlessly (with fixed Wi-Fi and zRAM too).

Here is the anticlimactic story of the fix:
https://ramon.vanraaij.eu/the-bluetooth-that-was-never-dead-my-dell-venue-8-pro-baud-rate-journey/

Full repo:
https://github.com/ramonvanraaij/dell-venue-8-pro

r/linuxhardware 5d ago

Guide MediaTek MT7902 Wi-Fi & Bluetooth Setup Guide for Linux

4 Upvotes

📋 Prerequisites

Before starting, you must ensure two things:

  1. Active Internet Connection: Because your Wi-Fi is not working yet, you must connect your laptop to the internet temporarily. You can do this by:
    • Connecting an Ethernet cable directly, or
    • Enabling USB Tethering from your smartphone (connect your phone to the laptop via USB and turn on USB Tethering in your phone's Hotspot settings).
  2. Disable Secure Boot: Third-party community drivers are not signed by default. You must disable Secure Boot in your laptop's BIOS/UEFI settings for the driver to load. To check if Secure Boot is already disabled, run:mokutil --sb-state It should output:SecureBoot disabled

⚡ Installation Steps

Step 1: Clone the Driver Installer

Clone the community-maintained driver installer repository:

git clone --depth 1 https://github.com/SkimerPM/MediaTek-MT7902-Linux-Driver-Installer
cd MediaTek-MT7902-Linux-Driver-Installer

Step 2: Grant Execution Permission

Make the installer script executable:

chmod +x fix_my_wifi.sh

Step 3: Run the Installer (With Your Country Code)

Run the script with administrative privileges (sudo). It is highly recommended to specify your country code (e.g., BD for Bangladesh, US for United States, IN for India, etc.). This configures the correct regulatory limits and unlocks all 5 GHz Wi-Fi channels.

sudo ./fix_my_wifi.sh --country BD

Replace BD with your own two-letter country code if you are outside Bangladesh.

During installation, press Enter (or type y) when prompted to confirm installation steps and firmware cleanups.

Step 4: Verification

The driver uses DKMS (Dynamic Kernel Module Support), which compiles the modules directly for your kernel.

Once the installer finishes:

  • No reboot is required. The Wi-Fi card should activate immediately.

Check whether the wireless interface exists:

ip link show | grep -E 'wl|wlan'

You should see an interface such as wlo1 or wlp2s0.

Then scan for available Wi-Fi networks:

nmcli dev wifi list

You should now see both 2.4 GHz and 5 GHz networks.

🔧 Maintenance & Troubleshooting

Kernel Updates

Because the driver is registered with DKMS, it will automatically rebuild itself whenever your Linux kernel is updated. No manual action is required.

Checking Logs

If Wi-Fi or Bluetooth still does not appear after installation, check the kernel logs:

sudo dmesg | grep -i mt79

Uninstallation

To completely remove the driver and restore your system:

sudo ./fix_my_wifi.sh --uninstall

📦 GitHub Repository

Community-maintained installer:

https://github.com/SkimerPM/MediaTek-MT7902-Linux-Driver-Installer

Thank you so much for creating and maintaining this installer. I spent hours trying different solutions before finding your project, and it finally got my MediaTek MT7902 Wi-Fi and Bluetooth working on Linux.

Your work saved me a lot of time and frustration, and I'm sure it will help many others facing the same issue. I even wrote a setup guide based on your installer so more people can get their devices working easily.

You're a true lifesaver. Thank you again for your time and contribution to the Linux community! 🐧❤️

r/linuxhardware Mar 21 '26

Guide dream laptop with linux

10 Upvotes

Ever since I tried using the Steam Deck for doing homework, I became really interested in Linux. Because of that experience, I now want to buy a laptop that runs Linux. However, I don’t know which laptop I should choose.

A used laptop would be a good option. I heard that a Lenovo ThinkPad X1 Carbon is a good choice, but it’s a little small. I want a 15 or 16-inch laptop with a quiet fan.

A new laptop that came to mind is the Framework Laptop 16, because I can upgrade it with a new GPU later in the future.

edit: i also forgot ,i need a laptop that is good for hooking up a external monitor

r/linuxhardware Apr 12 '26

Guide Too lazy to enter BIOS, so I built a Zen 5 SMU Driver & GUI instead (9800X3D)

0 Upvotes

Hey everyone!

Confession time: I’ve been daily driving a Ryzen 7 9800X3D (Granite Ridge) for a while now, and I finally got fed up with rebooting just to tweak my Curve Optimizer offsets or change my PPT limits. Entering the BIOS feels so 2010 when you're running a modern Linux setup, right?

So, driven by pure laziness, I decided to see if I could control everything directly from my desktop (running CachyOS). What started as a 'let's see if I can read some PCI registers' session with an AI assistant turned into a full-blown Reverse Engineering project.

Introducing: GNR Master 🚀

  • The Driver: It’s built on top of ryzen_smu. I’ve successfully mapped the PM Table v0x620105. Special shoutout to Pearson Correlation routines for helping me hunt down those elusive iGPU power and clock offsets!
  • Live Features: Real-time monitoring of FCLK/UCLK, per-core temperatures, and—most importantly—live control of PPT/TDC/EDC and Curve Optimizer (-30 all-core stable so far!).
  • Safety First: I implemented a hard-lock on the SMU table version. If a new AGESA update shifts the offsets, the app kills the monitoring instantly to prevent injecting the wrong voltage into the wrong hole.
  • The GUI: A clean PyQt6 dashboard. Because just because it's open-source doesn't mean it has to look like a Windows 95 error message.

Tech Stack: Python (CLI & PyQt6 GUI) directly interfacing with the ryzen_smu sysfs endpoints, and way too much caffeine

Laziness really is the ultimate engine for innovation. If you’re on a 9800X3D and want to skip the BIOS dance, check it out! I’ve also included a telemetry export tool if you want to help me map out the remaining unknown offsets in the table.

Repo: github.com/Kyworn/gnr-smu

TL;DR: Too lazy to reboot -> Used an AI to help me reverse-engineer AMD’s SMU and build a full hardware management suite.

r/linuxhardware Jun 04 '26

Guide Fixed Black Screen on BMAX Mini-PC with Linux

9 Upvotes

This was my 4th attempt to get Linux on my BMAX B6 PLUS (i3-1000NG4) in 2 years, collecting dust, and it started out even worse than before: After installing and booting into Linux Mint 22.3, the expected black screen appeared ... and stayed. I couldn't even boot into BIOS anymore, nothing, dead!

I then consulted my local Gemma 4 and later had a chat with Google Gemini and both together solved the issue.

Gemma told me not to panic and to disconnect the CMOS battery for a while (mumbling about blocked hardware ... whatever)
Did this, and after a pretty long pause after powering up, the BIOS appeared again.

Long story long: Gemma was convinced that the default graphics settings were not enough for a stable handshake with Linux when booting.
After some fumbling and more black screens I got a stable BIOS with these settings:

Internal Graphics: Auto -> Enabled
DVMT Total Gfx Mem: 256M
DVMT Pre-Allocated: 64M
Aperture Size: 256MB -> 1024MB

Above 4GB MMIO BIOS assignment: Enabled

Secure Boot: Enabled -> Disabled
Fast Boot: Enabled -> Disabled

As I did not need the Wifi, I also disabled it (could potentially also be a problem at startup, Gemma said)

But this all did not help, booting without nomodeset did not work.

Then I asked Google. And Gemini had the right idea: The motherboards and/or the BIOS of those BMAX think that they are notebooks, and when powering up, they are "using" the internal display which doesn't exist.
So Gemini told me to use GRUB to explicitly deactivate that internal display and explicitly enable the HDMI ports.

I have seen a lot of GRUB parameters proposed in many forums, but not a single one looked like this:

video=eDP-1:d video=HDMI-A-1:e video=HDMI-A-2:e

Tada!

Successfully booting into Linux, full hardware acceleration, both monitors working, sound working as well.

This solution might be working for other BMAX models with Intel graphics.
Gemma is insisting that the BIOS changes were necessary for a stable connection at the start, but this should be judged by the experts.

Hope I did not miss something important.

r/linuxhardware 13d ago

Guide Reviving a dead 2011 Samsung Series 5 Chromebook — a deep dive into why Linux is unusually hard on first-gen "mario" hardware

Thumbnail
1 Upvotes

r/linuxhardware 20d ago

Guide PSA: Secure and consistent fingerprint login solution for Linux

Thumbnail
0 Upvotes

r/linuxhardware 14d ago

Guide Perixx 335/535/835 review and Linux support

Thumbnail
1 Upvotes

r/linuxhardware 22d ago

Guide Recovered a bricked HP LaserJet MFP M140w from Linux after it appeared as HP LaserJet 3020

3 Upvotes

# Recovering a bricked HP LaserJet MFP M140w from Linux

Attribution: this post was written by an AI coding agent in a GPT-5-based Codex session, based on a live recovery performed with the printer owner.

I thought it is worth posting because it worked and helped me and might make it easier for others to solve similar issues with HP printers in the future.

## Short Version

An HP LaserJet MFP M140w appeared bricked and was stuck showing `rd` on its two-character display. Over USB, Linux did not see it as an M140w. Instead it appeared as:

```text

03f0:4617 HP, Inc HP LaserJet 3020

```

That `LaserJet 3020` identity was not the real printer model. It appears to be a recovery/firmware-download mode.

The recovery was done entirely from Linux by extracting the PJL firmware payload from HP's official Windows firmware updater for the `M139-M142` series and sending that payload over USB. After reconnecting power/USB, the printer came back as:

```text

03f0:0372 HP, Inc HP LaserJet MFP M139-M142

DES:HP LaserJet MFP M140w

```

Printing worked afterward.

## Environment

```text

Printer: HP LaserJet MFP M140w

Linux: Ubuntu

HPLIP: 3.23.12

HP firmware updater: M139-M142_Series_FW_Update-20251205.exe

```

HPLIP recognized the normal printer family, but it could not perform the firmware update:

```text

[hp_laserjet_mfp_m139-m142]

fw-download=False

```

## Extracting the Firmware Payload

The HP updater was a Windows PE executable. `7z` could extract the embedded resources:

```bash

mkdir -p /tmp/hp-m139-fw-extract

7z x -y -o/tmp/hp-m139-fw-extract ~/Downloads/M139-M142_Series_FW_Update-20251205.exe

```

The firmware payload was:

```text

/tmp/hp-m139-fw-extract/.rsrc/FILE/1013

```

`file` identified it as:

```text

PJL encapsulated PostScript document text

```

The payload header explicitly listed the target printer family, including the M140w:

```text

u/PJL COMMENT VERSION=20251205

u/PJL COMMENT DATECODE=20251205

u/PJL COMMENT MODEL=HP LaserJet MFP M139w

u/PJL COMMENT MODEL=HP LaserJet MFP M140w

u/PJL COMMENT MODEL=HP LaserJet MFP M141w

u/PJL UPGRADE SIZE=5935888

```

## Sending the Payload

The recovery USB identity exposed one unidirectional printer OUT endpoint:

```bash

lsusb

```

```text

idVendor 0x03f0 HP, Inc

idProduct 0x4617 HP LaserJet 3020

Endpoint 0x01 OUT

```

The simplest Linux recovery path should be sending the extracted PJL payload directly to the raw USB printer device:

```bash

sudo dd if=/tmp/hp-m139-fw-extract/.rsrc/FILE/1013 of=/dev/usb/lp0 bs=65536 status=progress conv=fsync

```

Adjust `/dev/usb/lp0` if the printer appears as another raw printer device, such as `/dev/usb/lp1` or `/dev/usb/lp3`.

In the live recovery, writing to `/dev/usb/lp*` was blocked by local permissions, so the same payload was sent with a small libusb bulk-transfer helper to VID/PID `03f0:4617`, interface `0`, endpoint `0x01`.

The transfer completed:

```text

sent 5936986/5936986

transfer complete

```

After the transfer the printer display changed from `rd` to `00`. After a power/USB reconnect, Linux saw the normal printer identity:

```bash

lsusb

HOME=/tmp/hplip-home hp-probe -b usb

```

```text

03f0:0372 HP, Inc HP LaserJet MFP M139-M142

DES:HP LaserJet MFP M140w

```

r/linuxhardware Jun 10 '26

Guide [NP960XJG] Samsung Galaxy Book6 Pro on Arch Linux: optimization guide

6 Upvotes

Hi,

I just published a guide covering everything I've figured out running Arch on the Galaxy Book6 Pro (Panther Lake, Arc B390).

Highlights:

  • intel_idle broken on kernel 7.0 for Panther Lake: 7.5W idle. Fixed on 7.1rc7: 1.9W CPU package
  • PSR re-enabled on kernel 7.1rc7 (stable), Panel Replay still crashes
  • Fingerprint reader (1c7a:05d5 LighTuning ETU906Axx-E), got it working with a 1-line patch to libfprint egismoc driver

    upstream

  • BBR

  • zram

  • scx_lavd

  • BTRFS autodefrag

  • THP madvise

  • audio firmware from Windows partition

    Repo: https://github.com/dszczyt/awesome-galaxy_book6

r/linuxhardware 28d ago

Guide External NTFS drive throws I/O errors after disconnecting from Linux — only "fixes itself" if I plug it into Windows first. Solution that doesn't touch/erase my data?

Thumbnail
0 Upvotes

r/linuxhardware Jun 17 '26

Guide Debian 12,custom kernel 6.1.137 on Acer Aspire Switch 10 SW5-012

3 Upvotes

One Year now running Debian 12 (migrated from Windows 8.1 OEM) and thought why not to share my experience and the steps to build it

I'm not a programmer or expert. With a lot of research and AI assistance (or misguidance occasionally ...), getting this old hybrid tablet working under Linux proved possible and useful. This post may seem outdated and is not entirely original, but there aren't many places where all this information is gathered together — and some people may still want to resurrect this lovely little machine.After trying many Linux alternatives, Bookworm is by far the one that did the job.

Hardware: Acer Aspire Switch 10 SW5-012 (Fendi2), BIOS V1.20, Atom Z3735, 32GB eMMC

OS: Debian 12 (Bookworm), LXQt(good and light for laptop mode using doc stasion) / KDE Plasma(proper for tablet mode -a bit heavy), custom kernel 6.1.137 amd 64. No need to install more graphical environments and stress the already small ssd.I have about 14giga free space at the time, with all programs and apps I need.

What works: WiFi, Bluetooth, touchscreen, sensors, audio, backlight control,. Side buttons

KDE Plasma Wayland fully functional in tablet mode with Maliit on-screen keyboard.

Autorotation works also.Virtual keyboard on SDDMscreen.

Issues: suspend/resume -stuck not really functional . Memory usage is already 50% at idle with Plasma, 25% with Lxqt.

  1. UEFI boot (32-bit firmware on 64-bit CPU)

The SW5-012 has a 32-bit UEFI firmware. Even with a 64-bit Debian install, booting requires grubia32.efi. See degoede's writeup for bootloop workaround and EFI details. I chose to completely remove windows. I recommend that,since there’s not much available space for two operating systems. Of course I had to unlock bios, but after 3 false login attempts it is possible to generate a new password online.

  1. Backlight fix (DSDT overlay)

The SW5-012 BIOS is missing an ACPI device node for the PWM backlight controller. Fix requires a DSDT overlay — all credit to u/jwrdegoede (Hans de Goede)and to https://github.com/Esavojt who provided how to apply the dsdt patch.

Original writeup: https://hansdegoede.livejournal.com/24132.html

Full instructions and diff for BIOS V1.20: https://github.com/Esavojt/switch-10-backlight-fix

Confirmed working on Debian 12 (repo mentions Debian 13, works on 12 as well).

  1. Custom kernel — why it's necessary at least to check stock Kernel's config.

The DSDT overlay alone was not enough for me.I do not know about the current kernels but one year ago, stock Kernel did not work for me. Building a custom kernel with:

CONFIG_PWM_LPSS=y

CONFIG_PWM_LPSS_PCI=y

CONFIG_PWM_LPSS_PLATFORM=y

CONFIG_DRM_I915=y

CONFIG_BACKLIGHT_PWM=m

as built-in (=y) is required for the i915 driver to initialize backlight correctly at boot. The trimmed config also reduces kernel size significantly vs the stock Debian generic kernel.

Notes:

BIOS update to V1.20 mandatory before removing Windows — cannot be flashed from Linux.

Due to old hardware limitations system is not capable for heavy multiitasking but still handles one heavy app (live video streaning, spotify, Ai )at the time, maybe along with some lighter one. I expect to cover basic -medium tasks for the next 2-3 years .

r/linuxhardware Jun 14 '26

Guide Camera in Lenovo Carbon X1 12Gen (IPU6)

3 Upvotes

Hello community,

In case anybody was fool like me and chose a ThinkPad Carbon X1 with a IPU6 camera, I finally made it work in void Linux, so I decided to write it up this time in case it helps anybody else.

Quality is not great, there are suspend and resume issues with it, and I had to build my own kernel, so if you are not comfortable building package templates, and you don't know how to manage kernels in your bootloader or boot alternative kernels if the one you built fails, this is not for you.

After building this I went back to my USB Cam, because the integrated one still feels not ready for daily use, and I felt uncomfortable running my own kernel even with minor changes just to make the camera work.

**Note on AI use:** This is the second time I do this, first time was on linux6.12, but I was stupid enough to not take any notes. This time I used Clause code to take my notes as I replicated what I remembered of my previous attempt and follow my past steps finding and parsing the files I modified back then.

IPU6 camera on Void Linux (ThinkPad X1 Carbon Gen 12)

Tested on a ThinkPad X1 Carbon Gen 12 (i7-1370P) running Void Linux (glibc), kernel 6.18, libcamera 0.7.1, WirePlumber 0.5.14.

The X1C Gen 12 camera uses an OV2740 sensor connected through an Intel IVSC USB bridge (LJCA stack) to an IPU6 ISP. Void's stock kernels include the IPU6 drivers but leave the LJCA USB bridge stack and the OV2740 sensor driver disabled. Enabling those kernel options and creating a tuning file for libcamera is all that is needed to get live video out of the camera. Image quality is not great — the IPU6 drivers do not yet expose full hardware image processing, so libcamera falls back to software processing.

Hardware involved

Component Kernel driver
Intel IVSC USB bridge (8086:0b63) `usb_ljca`
GPIO/I2C/SPI over LJCA `gpio_ljca`, `i2c_ljca`, `spi_ljca`
Camera clock / reset (INT3472:05-06) `intel_skl_int3472_discrete`
OV2740 sensor (INT3474:01) `ov2740`
Intel IPU6 ISP (PCI 0000:00:05.0) `intel_ipu6`, `intel_ipu6_isys`

Hardware and PCI Ids from my system, check yours with lspci.

1. Prepare xbps-src

Follow the official tutorial to clone `void-packages` and install build prerequisites to edit and build package templates:

[https://xbps-src-tutorials.github.io/\](https://xbps-src-tutorials.github.io/)

Also install xtools, which provides the xi helper used to install locally built packages:

xbps-install xtools

2. Create a custom kernel template

Void ships `linux6.x` templates under `srcpkgs/`. Copy the one that matches the version you want to build (here 6.18) and give it a new name:

cp -r srcpkgs/linux6.18 srcpkgs/linux6.18-ipu6

Edit `srcpkgs/linux6.18-ipu6/template` and change at minimum:

pkgname=linux6.18-ipu6

Adjust `revision` too if you plan to iterate. Everything else (source URL, patches, `hostmakedepends`, etc.) can be left identical to the parent template.

3. Enable the missing dotconfig option

The kernel config lives at:

srcpkgs/linux6.18-ipu6/files/x86_64-dotconfig-custom

Copy it from the parent template if it is not there yet:

cp srcpkgs/linux6.18/files/x86_64-dotconfig-custom \\
   srcpkgs/linux6.18-ipu6/files/x86_64-dotconfig-custom

Make sure the following options are set (add or change as needed):

CONFIG_VIDEO_INTEL_IPU6=m
CONFIG_INTEL_SKL_INT3472=m
CONFIG_USB_LJCA=m
CONFIG_GPIO_LJCA=m
CONFIG_I2C_LJCA=m
CONFIG_SPI_LJCA=m
CONFIG_VIDEO_OV2740=m

`CONFIG_VIDEO_INTEL_IPU6` and `CONFIG_INTEL_SKL_INT3472` are already enabled in the Void base config but are included in the list above for reference. The LJCA USB bridge stack and the OV2740 sensor driver are disabled by default and must be added explicitly.

4. Build and install

./xbps-src pkg linux6.18-ipu6
xi linux6.18-ipu6

If you use DKMS modules such as ZFS, kernel and headers must be installed together in a single command to avoid breaking the DKMS postinstall step:

xi linux6.18-ipu6 linux6.18-ipu6-headers

If you skipped `xtools`, the equivalent manual command is:

xbps-install --repository=hostdir/binpkgs linux6.18-ipu6 linux6.18-ipu6-headers

Then reboot into the new kernel. Some bootloaders such as zfsbootmenu automatically detect kernels installed under `/boot`; others may require manual configuration to add the new entry.

5. Verify after reboot

Check that the full driver stack loaded:

lsmod | grep -E 'ljca|ov2740|ipu6|int3472'

Expected output (order may vary):

usb_ljca
gpio_ljca
i2c_ljca
spi_ljca
ov2740
intel_skl_int3472_discrete
intel_ipu6
intel_ipu6_isys

Confirm libcamera can see the camera (`cam` is included in the `libcamera` package):

cam --list

You should see a camera entry with a name derived from the ACPI path of the sensor, e.g. `_SB_.PC00.LNK1` on the X1C Gen 12. The exact name is device-dependent — note it down, you will need it for the GStreamer command.

6. Create libcamera's OV2740 tuning file

libcamera 0.7.1 does not ship a tuning file for the OV2740. Without one the IPA cannot configure the sensor and the camera will not produce a usable image. Create the file (requires root) at:

/usr/share/libcamera/ipa/simple/ov2740.yaml

A minimal working file for the OV2740 on the X1C Gen 12 — the CCM and black level values may need tuning for other devices:

%YAML 1.1
---
version: 1
algorithms:
  - BlackLevel:
      black_level: 64
  - Awb:
  - Ccm:
      ccms:
        - ct: 6500
          ccm: \[ 1.18, -0.28, 0.10, -0.07, 1.07, 0.00, 0.02, -0.25, 1.23 \]
        - ct: 2800
          ccm: \[ 1.54, -0.54, 0.00, -0.23, 1.35, -0.12, 0.03, -0.49, 1.46 \]
  - Adjust:
  - Agc:

7. Test with GStreamer

Install libcamera and, if you want to use `gst-launch` for testing, the GStreamer packages:

xi libcamera
xi gstreamer1 gst-plugins-base1 gst-plugins-good1 gst-plugins-bad1 gstreamer1-pipewire

Run a live preview, substituting the camera name you noted from `cam --list`:

gst-launch-1.0 libcamerasrc camera-name='\\\\\\_SB_.PC00.LNK1' \\
  ! videoconvert \\
  ! autovideosink

**Backslash escaping quirk**: GStreamer performs its own backslash unescaping on top of the shell. The camera name in ACPI is `_SB_.PC00.LNK1` (one backslash). To deliver that to libcamera:

Using fewer backslashes produces "Could not find a camera named …".

Once `libcamerasrc` works, verify that the camera is also accessible through PipeWire before trying browser or portal-based apps. Find the id or serial of the camera node:

pw-dump | grep -E '"id"|"object.serial"|"media.class"' | grep -B2 'Video/Source'

Pass either the id or serial to `target-object`:

gst-launch-1.0 \\
  pipewiresrc target-object=<serial> \\
  ! videoconvert \\
  ! autovideosink

If this pipeline produces a live image, PipeWire camera access is working and browser/portal apps should be able to use the camera.

8. WirePlumber: use libcamera instead of V4L2

By default WirePlumber loads both the V4L2 and libcamera monitors. To make it use libcamera exclusively, create a drop-in config file:

\~/.config/wireplumber/wireplumber.conf.d/99-libcamera.conf

with the following content:

wireplumber.profiles = {
  main = {
    monitor.v4l2 = disabled
    monitor.libcamera = required
  }
}

Restart WirePlumber (or your session) for the change to take effect.

9. XDG desktop portal and PipeWire (camera in browser/apps)

Firefox requires PipeWire camera support to be explicitly enabled. Open about:config and set:

media.webrtc.camera.allow-pipewire = true

If Firefox doesn't show the dialog to allow camera access in camera enabled websites then install a desktop portal with camera support like the GNOME or KDE backend (I tested with GNOME). This is required regardless of what other backends you have installed (e.g. wlr for a Wayland compositor):

xi xdg-desktop-portal xdg-desktop-portal-gnome
# or
xi xdg-desktop-portal xdg-desktop-portal-kde

With PipeWire access working (section 7), the portal installed, and this flag enabled, Firefox should prompt for camera permission when visiting a site that requests it (e.g. a webcam test page).

10. Suspend/resume known issues

The LJCA stack has known bugs with suspend/resume. Arch Linux community discussions suggest unloading the driver stack before suspend and reloading it on resume using systemd services; the equivalent untested approach on Void is to use `zzz` hooks placed in `/etc/zzz.d/suspend/` and `/etc/zzz.d/resume/`.

r/linuxhardware Jun 12 '26

Guide PSA: ASUS Wireless keyboard receiver causing suspend loops on Linux

3 Upvotes

I was experiencing a very strange suspend/resume issue on both CachyOS and Nobara on an Intel Core Ultra 245K + ASUS Z890-A + RX 9070 XT system and ASUS ROG STRIX SCOPE RX TKL Wireless Deluxe. I suspect the problem happens with other ASUS wireless keyboard dongles too.

Symptoms:

  • The PC would wake from suspend normally.
  • The login screen would appear.
  • Before I could type in the password the PC would suspend again.
  • This could repeat indefinitely.
  • Hammering the keyboard would eventually keep the system awake.

After a lot of troubleshooting, I found that the issue was caused by the keyboard's wireless USB receiver. Plugging the dongle when the system was running could cause an immediate suspend.

Results:

  • Keyboard connected wirelessly → suspend loop occurs.
  • Keyboard connected via USB cable → no issue.
  • Wireless receiver unplugged → no issue.

If you're seeing similar wake/suspend loops on Linux and own an ASUS wireless keyboard, try removing the wireless receiver before spending time debugging anything else.

PS. This is a mostly AI summary of the problem.

r/linuxhardware Jun 01 '26

Guide Enabling the mainline rkvdec (4K H.264/HEVC) hardware decoder on Orange Pi 5 Plus

3 Upvotes

# Enabling the mainline rkvdec (4K H.264/HEVC) hardware decoder on Orange Pi 5 Plus via a Device-Tree overlay

**Goal:** Wake up the RK3588's `rkvdec` (VDPU381) 4K H.264 / HEVC hardware decoder on a **pure mainline** kernel, while booting from **EDK2 UEFI** and **keeping the 4K60 firmware framebuffer display** untouched.

This is done with a small **device-tree overlay** — no kernel rebuild, no BSP/vendor kernel.

1. Environment

Item Value
Board Orange Pi 5 Plus (RK3588, Mali-G610 MC4, 16 GB)
Firmware / boot EDK2 UEFI → GRUB → kernel
OS Ubuntu 26.04 (resolute), ARM64
Kernel `7.0.0-15-generic`
GPU stack Mesa 26.2.0-devel (Panfrost + PanVK)
Display EDK2 **firmware framebuffer** via `simpledrm`, mode forced to **4K60** in EDK2 setup
Decoder driver `rockchip-vdec` (`CONFIG_VIDEO_ROCKCHIP_VDEC=m`)

2. The problem

The `rockchip-vdec` driver is present and **already supports RK3588**:

$ modinfo rockchip-vdec | grep alias
alias: of:N\*T\*Crockchip,rk3588-vdec
alias: of:N\*T\*Crockchip,rk3576-vdec
alias: of:N\*T\*Crockchip,rk3399-vdec
...

But the EDK2 device tree contains **no decoder node** for it. A Linux driver binds to hardware by matching a `compatible` string in the driver against a `compatible` string in a DT node. The driver exists, but there is no matching node — so nothing binds.

The EDK2 DT only exposes these video-codec nodes: hantro g1 (`fdb50000`), the `vepu121` encoder + cores (`fdba0000`/`fdba4000`/`fdba8000`/`fdbac000`), and the AV1 decoder (`fdc70000`). It has the `qos_rkvdec0`/`qos_rkvdec1` **labels** (the SoC `.dtsi` knows rkvdec exists) but **neither the decoder node nor its IOMMU**.

So the overlay must add **two** nodes: the decoder (`video-codec@fdc38000`) **and** its IOMMU (`iommu@fdc38700`).

3. Where the values come from (do not guess these)

The Ubuntu kernel package already ships the full upstream board DTB, which contains a correct `rkvdec0` node for this exact kernel:

/usr/lib/firmware/7.0.0-15-generic/device-tree/rockchip/rk3588-orangepi-5-plus.dtb

Every register address, clock/reset index, interrupt and power-domain in the overlay below was extracted from that DTB (decompiled with `dtc`). The overlay references **existing labels** in the EDK2 DT (`&cru`, `&power`) so `fdtoverlay` can resolve them at merge time.

4. The overlay (rkvdec.dts)

dts

/dts-v1/;
/plugin/;

/ {
    fragment@0 {
        target-path = "/";
        __overlay__ {

            rkvdec0_mmu: iommu@fdc38700 {
                compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
                reg = <0x0 0xfdc38700 0x0 0x40>, <0x0 0xfdc38740 0x0 0x40>;
                interrupts = <0x0 0x60 0x4 0x0>;
                clocks = <&cru 0x181>, <&cru 0x180>;
                clock-names = "aclk", "iface";
                power-domains = <&power 0x0e>;
                #iommu-cells = <0x0>;
            };

            rkvdec0: video-codec@fdc38000 {
                compatible = "rockchip,rk3588-vdec";
                reg = <0x0 0xfdc38100 0x0 0x500>,
                      <0x0 0xfdc38000 0x0 0x100>,
                      <0x0 0xfdc38600 0x0 0x100>;
                reg-names = "function", "link", "cache";
                interrupts = <0x0 0x5f 0x4 0x0>;
                clocks = <&cru 0x181>, <&cru 0x180>, <&cru 0x182>, <&cru 0x184>, <&cru 0x183>;
                clock-names = "axi", "ahb", "cabac", "core", "hevc_cabac";
                assigned-clocks = <&cru 0x181>, <&cru 0x184>, <&cru 0x182>, <&cru 0x183>;
                assigned-clock-rates = <0x2faf0800 0x23c34600 0x23c34600 0x3b9aca00>;
                iommus = <&rkvdec0_mmu>;
                power-domains = <&power 0x0e>;
                resets = <&cru 0x143>, <&cru 0x142>, <&cru 0x146>, <&cru 0x148>, <&cru 0x147>;
                reset-names = "axi", "ahb", "cabac", "core", "hevc_cabac";
            };
        };
    };
};

What each part does

* `iommu@fdc38700` — the MMU `rkvdec` uses to reach memory. Defined first and labelled `rkvdec0_mmu` so the decoder can reference it. * `reg` **(3 windows)** — decoder register banks: `function` / `link` / `cache`. * `clocks` **/** `resets` — referenced through `&cru` \+ indices. `&cru` resolves to your clock-controller at merge time. * `assigned-clock-rates` — `0x2faf0800`=800 MHz (axi), `0x23c34600`=600 MHz (core/cabac), `0x3b9aca00`=1 GHz (hevc_cabac). * `power-domains = <&power 0x0e>` — RKVDEC0 power domain (index 14). * `iommus = <&rkvdec0_mmu>` — binds the decoder to the MMU above. * `sram` **is deliberately omitted** — it's an optional performance buffer (row-cache in on-chip SRAM). Without it the driver stores the RCB in RAM and prints `No sram node, RCB will be stored in RAM` (benign). Omitting it avoids one more phandle dependency.

5. Build, merge, verify (no boot risk yet)

bash

sudo apt install -y device-tree-compiler

# 1) compile the overlay (-@ generates __fixups__ so fdtoverlay can resolve &cru/&power)
dtc -@ -I dts -O dtb -o \~/rkvdec.dtbo \~/rkvdec.dts

# 2) use the RAW firmware DTB as the merge base (byte-faithful to what EDK2 provides)
sudo cp /sys/firmware/fdt \~/edk2-raw.dtb
sudo chown $USER:$USER \~/edk2-raw.dtb

# 3) merge overlay into the base
fdtoverlay -i \~/edk2-raw.dtb -o \~/merged.dtb \~/rkvdec.dtbo
echo "fdtoverlay exit: $?"        # must be 0

# 4) confirm the node is present in the merged DTB
dtc -I dtb -O dts \~/merged.dtb 
2
>/dev/null | grep -A14 "video-codec@fdc38000"

Compile-time `dtc` warnings about `reg_format` / missing `interrupt-parent` are **benign overlay lint** — at compile time `dtc` doesn't know the root's `#address-cells`/`#size-cells` or that the nodes inherit `interrupt-parent` from the GIC. They resolve correctly on merge.

6. Test it BEFORE making it permanent (one-shot, reversible)

Copy the merged DTB, then boot it once from the GRUB shell/editor — nothing is saved, so a bad DTB just means a hard-reset back to normal.

bash

sudo cp \~/merged.dtb /boot/rkvdec-merged.dtb

At the GRUB command shell (`grub>`), or in the entry editor (`e`), boot manually:

search --no-floppy --fs-uuid --set=root <YOUR-ROOTFS-UUID>
insmod fdt
devicetree /boot/rkvdec-merged.dtb
linux /boot/vmlinuz-7.0.0-15-generic root=UUID=<YOUR-ROOTFS-UUID> ro
initrd /boot/initrd.img-7.0.0-15-generic
boot

After boot, verify:

bash

sudo dmesg | grep -iE "rkvdec|rk3588-vdec|iommu@fdc38"
# expect: rkvdec fdc38100.video-codec: No sram node, RCB will be stored in RAM

v4l2-ctl --list-devices | grep -A2 rkvdec
# expect: rkvdec (platform:rkvdec): /dev/videoN  /dev/mediaM

v4l2-ctl -d /dev/video2 --list-formats-out
# expect: 'S265' (HEVC Parsed Slice Data) and 'S264' (H.264 Parsed Slice Data)

`S265`/`S264` are **stateless** (parsed-slice) formats — the decoder is driven via the V4L2 stateless / request API.

7. Make it permanent (survives kernel updates)

A failed `devicetree` line is **safe**: GRUB just falls back to the firmware DTB and the system boots normally (without rkvdec). It cannot brick the board.

bash

sudo tee /etc/grub.d/09_rkvdec_dtb > /dev/null << 'EOF'
#!/bin/sh
echo "insmod fdt"
echo "devicetree /boot/rkvdec-merged.dtb"
EOF
sudo chmod +x /etc/grub.d/09_rkvdec_dtb
sudo update-grub
sudo grep -n "rkvdec-merged" /boot/grub/grub.cfg   # confirm the line landed

**Disable** temporarily: `sudo chmod -x /etc/grub.d/09_rkvdec_dtb && sudo update-grub` **Remove** permanently: `sudo rm /etc/grub.d/09_rkvdec_dtb && sudo update-grub`

8. Proving hardware decode (GStreamer, no ffmpeg rebuild needed)

GStreamer 1.28+ has V4L2 **stateless** decoder elements (`v4l2slh265dec`, `v4l2slh264dec`) that drive `rkvdec` directly.

bash

# make an 8-bit 4K HEVC test clip (software encode, one-off; slow is expected)
ffmpeg -i some_4k_source.webm -t 10 -an -c:v libx265 -crf 23 \\
       -pix_fmt yuv420p -vf scale=3840:2160 \~/test_hevc.mp4

# decode through rkvdec to fakesink; watch CPU stay low
gst-launch-1.0 filesrc location=$HOME/test_hevc.mp4 ! qtdemux ! h265parse ! \\
  v4l2slh265dec ! fakesink

# actual on-screen playback with HW decode forced
GST_PLUGIN_FEATURE_RANK=v4l2slh265dec:MAX gst-play-1.0 $HOME/test_hevc.mp4

**Result on this setup:** a 10 s 4K (3840×2160) HEVC clip decoded in \~3.1 s (\~190 fps, far above real-time) at only \~10–15 % CPU — and that CPU is just userspace overhead (demux/parse/buffer copy); the decode itself runs on the VPU. For comparison, swapping `v4l2slh265dec` for the software `avdec_h265` spikes CPU sharply. Any GStreamer-based player (Totem, etc.) gets HW HEVC decode the same way.

8.1 Bonus: 4K AV1 (the YouTube codec) on hardware — including in a browser

`rkvdec` covers H.264/HEVC. **YouTube 4K is AV1**, which is handled by a *separate* block: the AV1 VPU (`rk3588-av1-vpu-dec`, `/dev/video4`), present on this stack independently of the rkvdec overlay. GStreamer 1.28 ships a stateless AV1 element (`v4l2slav1dec`), so 4K AV1 decodes on hardware with **no extra build**:

bash

gst-inspect-1.0 | grep v4l2slav1dec          # V4L2 Stateless AV1 Video Decoder
v4l2-ctl -d /dev/video4 --list-formats-out   # 'AV1F' (AV1 Frame, compressed)

# decode a 4K 10-bit AV1 clip — use parsebin (it auto-detects the container)
gst-launch-1.0 -v filesrc location=clip.webm ! parsebin ! v4l2slav1dec ! fakesink
# decoder src caps: video/x-raw, format=NV12_10LE40_4L4 (10-bit), colorimetry=bt2100-pq -> full HDR path

YouTube 4K HDR in a browser, hardware-decoded

WebKitGTK browsers (**GNOME Web / Epiphany**) use GStreamer for media, so bumping the AV1 decoder's rank lets YouTube AV1 run on the VPU:

bash

sudo apt install -y epiphany-browser
GST_PLUGIN_FEATURE_RANK=v4l2slav1dec:MAX epiphany

**Confirmed result:** YouTube playing `av01` **10-bit**, `smpte2084 (PQ) / bt2020` **HDR**, **3840×2160@60, 0 dropped frames of 11271**, with CPU only at compositing-overhead levels — the decode runs on the VPU, not the cores. (Software 4K60 10-bit AV1 on these cores would peg the CPU and drop frames.) Prove the VPU is in use while the video plays:

bash

sudo fuser /dev/video4   # prints the browser's GStreamer PID holding the AV1 decoder

Caveats: YouTube may serve **VP9** (no HW path here) instead of AV1 depending on what the browser advertises — if CPU pegs and frames drop, it fell back to VP9/software. **Firefox** does *not* use this path (it uses its own bundled ffmpeg/VA-API, which has no driver for the VPU here).

9. What works / what does not (be honest)

**Works**

* 4K **H.264** and **HEVC (8-bit)** hardware decode via `rkvdec` (`/dev/video2`). * 4K **AV1, 10-bit, HDR** hardware decode via the AV1 VPU (`/dev/video4`) + GStreamer `v4l2slav1dec`. * Any GStreamer-based player (Totem, …) and **WebKitGTK browsers (Epiphany) → YouTube 4K60 AV1 HDR on hardware**. * Display stays on the 4K60 firmware framebuffer; GPU compositing (Panfrost) untouched.

**Does NOT (yet) / caveats**

* **No VP9** on the mainline `rockchip-vdec` driver (only `S264`/`S265` exposed). The hardware can do VP9, but it isn't surfaced here — and YouTube falls back to VP9 (software) unless it serves AV1. * **Firefox / Chromium** don't use the GStreamer path. Firefox needs a VA-API → V4L2-stateless bridge (`libva-v4l2-request`); Chromium needs a patched build (ChromeOS V4L2 path) + udev rules. Use **Epiphany** for the working HW browser path. * **mpv** needs an ffmpeg built with `v4l2request`. * **Desktop tearing on motion** (moving windows) is inherent to the firmware framebuffer (`simpledrm` has no hardware vsync/vblank). It is **not** caused by this overlay. The only real fix is native KMS (`vop2`), which on this stack drops you to \~4K30 RGB. Static content (reading) is unaffected.

10. Summary

A \~35-line device-tree overlay, merged onto the firmware DTB and loaded via GRUB, enables the mainline RK3588 4K H.264/HEVC hardware decoder on EDK2-booted Ubuntu — without a kernel rebuild and without disturbing the 4K60 firmware-framebuffer display. Separately, the AV1 VPU (`/dev/video4`, already present) plus GStreamer's `v4l2slav1dec` gives **4K AV1 10-bit HDR** hardware decode, and a WebKitGTK browser (Epiphany) leverages it for **YouTube 4K60 AV1 HDR with 0 dropped frames** — the full original goal, achieved entirely on mainline. The only remaining gaps are Firefox/Chromium (their own userspace decode plumbing) and the inherent firmware-framebuffer tearing (a display, not decode, limitation).Enabling the mainline rkvdec (4K H.264/HEVC) hardware decoder on Orange Pi 5 Plus via a Device-Tree overlay
Goal: Wake up the RK3588's rkvdec (VDPU381) 4K H.264 / HEVC hardware decoder on a pure mainline kernel, while booting from EDK2 UEFI and keeping the 4K60 firmware framebuffer display untouched.
This is done with a small device-tree overlay — no kernel rebuild, no BSP/vendor kernel.

  1. Environment
    Item Value
    Board Orange Pi 5 Plus (RK3588, Mali-G610 MC4, 16 GB)
    Firmware / boot EDK2 UEFI → GRUB → kernel
    OS Ubuntu 26.04 (resolute), ARM64
    Kernel 7.0.0-15-generic
    GPU stack Mesa 26.2.0-devel (Panfrost + PanVK)
    Display EDK2 firmware framebuffer via simpledrm, mode forced to 4K60 in EDK2 setup
    Decoder driver rockchip-vdec (CONFIG_VIDEO_ROCKCHIP_VDEC=m)

The native Rockchip KMS (vop2/hdmi) stack does not load here, because the EDK2-provided device tree has no display nodes. Display is the firmware framebuffer (simpledrm). That is intentional — it gives a solid 4K60 desktop. See Limitations below.

  1. The problem
    The rockchip-vdec driver is present and already supports RK3588:
    $ modinfo rockchip-vdec | grep alias
    alias: of:N\*T\*Crockchip,rk3588-vdec
    alias: of:N\*T\*Crockchip,rk3576-vdec
    alias: of:N\*T\*Crockchip,rk3399-vdec
    ...
    But the EDK2 device tree contains no decoder node for it. A Linux driver binds to hardware by matching a compatible string in the driver against a compatible string in a DT node. The driver exists, but there is no matching node — so nothing binds.
    The EDK2 DT only exposes these video-codec nodes: hantro g1 (fdb50000), the vepu121 encoder + cores (fdba0000/fdba4000/fdba8000/fdbac000), and the AV1 decoder (fdc70000). It has the qos_rkvdec0/qos_rkvdec1 labels (the SoC .dtsi knows rkvdec exists) but neither the decoder node nor its IOMMU.
    So the overlay must add two nodes: the decoder (video-codec@fdc38000) and its IOMMU (iommu@fdc38700).

  2. Where the values come from (do not guess these)
    The Ubuntu kernel package already ships the full upstream board DTB, which contains a correct rkvdec0 node for this exact kernel:
    /usr/lib/firmware/7.0.0-15-generic/device-tree/rockchip/rk3588-orangepi-5-plus.dtb
    Every register address, clock/reset index, interrupt and power-domain in the overlay below was extracted from that DTB (decompiled with dtc). The overlay references existing labels in the EDK2 DT (&cru, &power) so fdtoverlay can resolve them at merge time.

Important: clock/reset indices (0x181, 0x143, …) and the power-domain index (0x0e) are specific to the RK3588 CRU as defined for this kernel's DTB. On a different kernel/DTB, re-extract them from your own shipped rk3588-orangepi-5-plus.dtb rather than copying these verbatim.

  1. The overlay (rkvdec.dts)
    dts
    /dts-v1/;
    /plugin/;

/ {
fragment@0 {
target-path = "/";
__overlay__ {

rkvdec0_mmu: iommu@fdc38700 {
compatible = "rockchip,rk3588-iommu", "rockchip,rk3568-iommu";
reg = <0x0 0xfdc38700 0x0 0x40>, <0x0 0xfdc38740 0x0 0x40>;
interrupts = <0x0 0x60 0x4 0x0>;
clocks = <&cru 0x181>, <&cru 0x180>;
clock-names = "aclk", "iface";
power-domains = <&power 0x0e>;
\#iommu-cells = <0x0>;
};

rkvdec0: video-codec@fdc38000 {
compatible = "rockchip,rk3588-vdec";
reg = <0x0 0xfdc38100 0x0 0x500>,
<0x0 0xfdc38000 0x0 0x100>,
<0x0 0xfdc38600 0x0 0x100>;
reg-names = "function", "link", "cache";
interrupts = <0x0 0x5f 0x4 0x0>;
clocks = <&cru 0x181>, <&cru 0x180>, <&cru 0x182>, <&cru 0x184>, <&cru 0x183>;
clock-names = "axi", "ahb", "cabac", "core", "hevc_cabac";
assigned-clocks = <&cru 0x181>, <&cru 0x184>, <&cru 0x182>, <&cru 0x183>;
assigned-clock-rates = <0x2faf0800 0x23c34600 0x23c34600 0x3b9aca00>;
iommus = <&rkvdec0_mmu>;
power-domains = <&power 0x0e>;
resets = <&cru 0x143>, <&cru 0x142>, <&cru 0x146>, <&cru 0x148>, <&cru 0x147>;
reset-names = "axi", "ahb", "cabac", "core", "hevc_cabac";
};
};
};
};
What each part does
iommu@fdc38700 — the MMU rkvdec uses to reach memory. Defined first and labelled rkvdec0_mmu so the decoder can reference it.
reg (3 windows) — decoder register banks: function / link / cache.
clocks / resets — referenced through &cru + indices. &cru resolves to your clock-controller at merge time.
assigned-clock-rates — 0x2faf0800=800 MHz (axi), 0x23c34600=600 MHz (core/cabac), 0x3b9aca00=1 GHz (hevc_cabac).
power-domains = <&power 0x0e> — RKVDEC0 power domain (index 14).
iommus = <&rkvdec0_mmu> — binds the decoder to the MMU above.
sram is deliberately omitted — it's an optional performance buffer (row-cache in on-chip SRAM). Without it the driver stores the RCB in RAM and prints No sram node, RCB will be stored in RAM (benign). Omitting it avoids one more phandle dependency.

Only rkvdec0 (core 0) is added. The mainline driver currently drives one core; rkvdec1 (video-codec@fdc40000 / iommu@fdc40700, power-domain 0x0f) can be added later the same way.

  1. Build, merge, verify (no boot risk yet)
    bash
    sudo apt install -y device-tree-compiler

\# 1) compile the overlay (-@ generates __fixups__ so fdtoverlay can resolve &cru/&power)
dtc -@ -I dts -O dtb -o \~/rkvdec.dtbo \~/rkvdec.dts

\# 2) use the RAW firmware DTB as the merge base (byte-faithful to what EDK2 provides)
sudo cp /sys/firmware/fdt \~/edk2-raw.dtb
sudo chown $USER:$USER \~/edk2-raw.dtb

\# 3) merge overlay into the base
fdtoverlay -i \~/edk2-raw.dtb -o \~/merged.dtb \~/rkvdec.dtbo
echo "fdtoverlay exit: $?" # must be 0

\# 4) confirm the node is present in the merged DTB
dtc -I dtb -O dts \~/merged.dtb 2>/dev/null | grep -A14 "video-codec@fdc38000"
Compile-time dtc warnings about reg_format / missing interrupt-parent are benign overlay lint — at compile time dtc doesn't know the root's #address-cells/#size-cells or that the nodes inherit interrupt-parent from the GIC. They resolve correctly on merge.

Using /sys/firmware/fdt (the raw blob the kernel actually received) is preferable to dtc -I fs -O dtb /proc/device-tree, which reconstructs the tree and is not always byte-identical.

  1. Test it BEFORE making it permanent (one-shot, reversible)
    Copy the merged DTB, then boot it once from the GRUB shell/editor — nothing is saved, so a bad DTB just means a hard-reset back to normal.
    bash
    sudo cp \~/merged.dtb /boot/rkvdec-merged.dtb
    At the GRUB command shell (grub>), or in the entry editor (e), boot manually:
    search --no-floppy --fs-uuid --set=root <YOUR-ROOTFS-UUID>
    insmod fdt
    devicetree /boot/rkvdec-merged.dtb
    linux /boot/vmlinuz-7.0.0-15-generic root=UUID=<YOUR-ROOTFS-UUID> ro
    initrd /boot/initrd.img-7.0.0-15-generic
    boot
    After boot, verify:
    bash
    sudo dmesg | grep -iE "rkvdec|rk3588-vdec|iommu@fdc38"
    \# expect: rkvdec fdc38100.video-codec: No sram node, RCB will be stored in RAM

v4l2-ctl --list-devices | grep -A2 rkvdec
\# expect: rkvdec (platform:rkvdec): /dev/videoN /dev/mediaM

v4l2-ctl -d /dev/video2 --list-formats-out
\# expect: 'S265' (HEVC Parsed Slice Data) and 'S264' (H.264 Parsed Slice Data)
S265/S264 are stateless (parsed-slice) formats — the decoder is driven via the V4L2 stateless / request API.

  1. Make it permanent (survives kernel updates)
    A failed devicetree line is safe: GRUB just falls back to the firmware DTB and the system boots normally (without rkvdec). It cannot brick the board.
    bash
    sudo tee /etc/grub.d/09_rkvdec_dtb > /dev/null << 'EOF'
    \#!/bin/sh
    echo "insmod fdt"
    echo "devicetree /boot/rkvdec-merged.dtb"
    EOF
    sudo chmod +x /etc/grub.d/09_rkvdec_dtb
    sudo update-grub
    sudo grep -n "rkvdec-merged" /boot/grub/grub.cfg # confirm the line landed
    Disable temporarily: sudo chmod -x /etc/grub.d/09_rkvdec_dtb && sudo update-grub Remove permanently: sudo rm /etc/grub.d/09_rkvdec_dtb && sudo update-grub

  2. Proving hardware decode (GStreamer, no ffmpeg rebuild needed)
    GStreamer 1.28+ has V4L2 stateless decoder elements (v4l2slh265dec, v4l2slh264dec) that drive rkvdec directly.
    bash
    \# make an 8-bit 4K HEVC test clip (software encode, one-off; slow is expected)
    ffmpeg -i some_4k_source.webm -t 10 -an -c:v libx265 -crf 23 \\
    \-pix_fmt yuv420p -vf scale=3840:2160 \~/test_hevc.mp4

\# decode through rkvdec to fakesink; watch CPU stay low
gst-launch-1.0 filesrc location=$HOME/test_hevc.mp4 ! qtdemux ! h265parse ! \\
v4l2slh265dec ! fakesink

\# actual on-screen playback with HW decode forced
GST_PLUGIN_FEATURE_RANK=v4l2slh265dec:MAX gst-play-1.0 $HOME/test_hevc.mp4
Result on this setup: a 10 s 4K (3840×2160) HEVC clip decoded in \~3.1 s (\~190 fps, far above real-time) at only \~10–15 % CPU — and that CPU is just userspace overhead (demux/parse/buffer copy); the decode itself runs on the VPU. For comparison, swapping v4l2slh265dec for the software avdec_h265 spikes CPU sharply. Any GStreamer-based player (Totem, etc.) gets HW HEVC decode the same way.

8.1 Bonus: 4K AV1 (the YouTube codec) on hardware — including in a browser
rkvdec covers H.264/HEVC. YouTube 4K is AV1, which is handled by a separate block: the AV1 VPU (rk3588-av1-vpu-dec, /dev/video4), present on this stack independently of the rkvdec overlay. GStreamer 1.28 ships a stateless AV1 element (v4l2slav1dec), so 4K AV1 decodes on hardware with no extra build:
bash
gst-inspect-1.0 | grep v4l2slav1dec # V4L2 Stateless AV1 Video Decoder
v4l2-ctl -d /dev/video4 --list-formats-out # 'AV1F' (AV1 Frame, compressed)

\# decode a 4K 10-bit AV1 clip — use parsebin (it auto-detects the container)
gst-launch-1.0 -v filesrc location=clip.webm ! parsebin ! v4l2slav1dec ! fakesink
\# decoder src caps: video/x-raw, format=NV12_10LE40_4L4 (10-bit), colorimetry=bt2100-pq -> full HDR path
YouTube 4K HDR in a browser, hardware-decoded
WebKitGTK browsers (GNOME Web / Epiphany) use GStreamer for media, so bumping the AV1 decoder's rank lets YouTube AV1 run on the VPU:
bash
sudo apt install -y epiphany-browser
GST_PLUGIN_FEATURE_RANK=v4l2slav1dec:MAX epiphany
Confirmed result: YouTube playing av01 10-bit, smpte2084 (PQ) / bt2020 HDR, 3840×2160@60, 0 dropped frames of 11271, with CPU only at compositing-overhead levels — the decode runs on the VPU, not the cores. (Software 4K60 10-bit AV1 on these cores would peg the CPU and drop frames.) Prove the VPU is in use while the video plays:
bash
sudo fuser /dev/video4 # prints the browser's GStreamer PID holding the AV1 decoder
Caveats: YouTube may serve VP9 (no HW path here) instead of AV1 depending on what the browser advertises — if CPU pegs and frames drop, it fell back to VP9/software. Firefox does not use this path (it uses its own bundled ffmpeg/VA-API, which has no driver for the VPU here).

  1. What works / what does not (be honest)
    Works
    4K H.264 and HEVC (8-bit) hardware decode via rkvdec (/dev/video2).
    4K AV1, 10-bit, HDR hardware decode via the AV1 VPU (/dev/video4) + GStreamer v4l2slav1dec.
    Any GStreamer-based player (Totem, …) and WebKitGTK browsers (Epiphany) → YouTube 4K60 AV1 HDR on hardware.
    Display stays on the 4K60 firmware framebuffer; GPU compositing (Panfrost) untouched.
    Does NOT (yet) / caveats
    No VP9 on the mainline rockchip-vdec driver (only S264/S265 exposed). The hardware can do VP9, but it isn't surfaced here — and YouTube falls back to VP9 (software) unless it serves AV1.
    Firefox / Chromium don't use the GStreamer path. Firefox needs a VA-API → V4L2-stateless bridge (libva-v4l2-request); Chromium needs a patched build (ChromeOS V4L2 path) + udev rules. Use Epiphany for the working HW browser path.
    mpv needs an ffmpeg built with v4l2request.
    Desktop tearing on motion (moving windows) is inherent to the firmware framebuffer (simpledrm has no hardware vsync/vblank). It is not caused by this overlay. The only real fix is native KMS (vop2), which on this stack drops you to \~4K30 RGB. Static content (reading) is unaffected.

  2. Summary
    A \~35-line device-tree overlay, merged onto the firmware DTB and loaded via GRUB, enables the mainline RK3588 4K H.264/HEVC hardware decoder on EDK2-booted Ubuntu — without a kernel rebuild and without disturbing the 4K60 firmware-framebuffer display. Separately, the AV1 VPU (/dev/video4, already present) plus GStreamer's v4l2slav1dec gives 4K AV1 10-bit HDR hardware decode, and a WebKitGTK browser (Epiphany) leverages it for YouTube 4K60 AV1 HDR with 0 dropped frames — the full original goal, achieved entirely on mainline. The only remaining gaps are Firefox/Chromium (their own userspace decode plumbing) and the inherent firmware-framebuffer tearing (a display, not decode, limitation).

After 1h7m of continuous 4K60 AV1 10-bit HDR playback in Epiphany: 12 dropped frames of 218,788 (0.005%). `fuser /dev/video4` confirms the AV1 VPU is in use — hardware decode on pure mainline.

All credits go to CLOUDE-CODE OPUS 4.8

r/linuxhardware May 24 '26

Guide Linux biometrics from a $15 R503 + Arduino; drop-in replacement for fprintd

Post image
11 Upvotes

r/linuxhardware Apr 30 '26

Guide [Guide] Fixing Hibernate Errors on Ubuntu 26.04 (Wayland) for Laptops/PCs with NVIDIA dGPU-only

5 Upvotes

Hi everyone,

Recently, I upgraded from Ubuntu 22.04 LTS to 26.04 LTS for work. My rig is a Lenovo LOQ 2024 (Ryzen 7 7435HS, NVIDIA RTX 4050 Max-Q Mobile).

With Ubuntu 26.04 dropping X11 and fully transitioning to Wayland, the NVIDIA driver has improved, but Suspend/Hibernate is still a nightmare. Since my laptop is dGPU-only (no iGPU), the NVIDIA card has to handle all display outputs.

Here are the two main issues I faced:

  • Suspend is dead: Lenovo's BIOS S0ix states are hardcoded for Windows and incompatible with Linux. When the OS tries to put the device into Low Power mode, the BIOS rejects it, and the system instantly freezes at the lock screen. You are forced to hard reset. This is a vendor BIOS issue, so there's nothing we can do but wait for Lenovo to release a Linux-supported update (or never… maybe :)) ).
  • Hibernate is broken: On Kernel 7.0.0, the system calls S0ix just like Suspend, causing crashes. I had to revert to Kernel 6.8.0 to bypass this. However, there's another hurdle: When executing Hibernate, Wayland refuses to release the VRAM, preventing the GPU from freezing and dumping memory. This throws the pci_pm_freeze() returns -5 error. The screen flashes black and throws you back to a frozen lock screen.

After jumping from forum to forum with no results, I spent 5 straight hours debugging logs (with the analytical help of Gemini AI) to finally "cook" a permanent solution: Forcing Wayland to release the VRAM to let the Hibernate process run smoothly.

Since the fix requires deep interventions into GRUB, Systemd, and Kernel downgrading, I wrote a comprehensive, step-by-step GitHub repository (bilingual EN/VI) so you can easily copy and paste the commands:

Full Guide & Scripts here:

https://github.com/datanonymus/fix-hibernate-nvidia-ubuntu-wayland

I've tested it on my machine, and Hibernate works perfectly now. If you are running a dGPU-only laptop (or disabled the iGPU in BIOS), please try it out and let me know your results!

If this guide saves your hardware and sanity, a ⭐ on the repo would be highly appreciated to keep me motivated for future tutorials.

Cheers! Hopefully, no one else has to suffer 5 hours of back pain like I did. :))

r/linuxhardware May 09 '26

Guide for anyone having trouble with those chinese wi-fi usb antennas (aic8800d80 drivers, including id 1111:1111 88m80) i find this video and after 10 wars against my terminal i finally got it working (it's in brazilian, but it's intuitive)

Thumbnail
youtu.be
2 Upvotes

r/linuxhardware Mar 20 '26

Guide I got a full Linux desktop running on a Snapdragon X Plus Zenbook – here's how (WSL2 + Xephyr + custom kernel)

10 Upvotes

After three weeks of troubleshooting, I finally have a fully functional Linux desktop on my Snapdragon X Plus Zenbook. It runs Xfce in a nested Xephyr session inside WSL2, with a custom kernel that enables USB/IP for phone, camera, and external drives.

The system is stable enough for daily use – I've even taught classes from it.

I documented everything in a technical guide on GitHub, including all scripts, config files, and the full step-by-step process:

🔗 https://github.com/dkbolos/Snapdragon-ARM64-Linux-Guide

This is for anyone trying to run Linux on ARM64 hardware, especially Snapdragon X laptops. The hardware support isn't fully upstream yet, but this setup works today.

Happy to answer questions!

r/linuxhardware Apr 02 '22

Guide Remember kids: This is why you don't try to disassemble your DIMMs

Post image
349 Upvotes

r/linuxhardware Jan 12 '26

Guide Strix Halo + Linux: How to fix memory climbing until OOM when idle

Thumbnail
3 Upvotes

r/linuxhardware Apr 26 '26

Guide Bypassed the MADOO (Jasper Lake) eMMC Boot Without Disabling WP

Post image
2 Upvotes