Clockwork uConsole · Volume 6
Display, Keyboard, Audio, and the Kernel
The Clockwork patch chain, JD9365DA-H3 LCD driver, GD32 keyboard MCU, ALSA path, and the Linux-side glue that makes the hardware work
Contents
1. About this Volume
This volume is the Linux-side counterpart to Volume 2’s hardware-side story. Volume 2 told you what’s on the mainboard schematic — the JD9365DA-H3 LCD driver IC, the GD32F103 keyboard MCU, the OCP8178 audio amplifiers — and Volume 4 told you how the system gets to a running kernel. This volume picks up at the point where Linux is running and walks how the kernel knows about, controls, and exposes those peripherals to user-space.
It is the “why does my keyboard work, and how do I make it work differently” volume. It is also the “why does the screen look slightly off, and how do I fix it” volume. And it is the “what’s the audio quality story, really” volume — because the BCM2711 has no on-die audio codec, and the answer to the audio-quality question depends on knowing exactly what PWM-audio means.
The reader is assumed to be comfortable with Linux device trees, the input subsystem, ALSA terminology (cards, devices, mixers), and basic kernel-build practice. If “device tree overlay” is a foreign phrase, skim the Pi docs section Device Trees, overlays, and parameters1 before continuing.
A scope note: this volume covers only the Linux path. The kernel patches and the userland glue. Vol 2 has the analog and digital schematic side. Vol 11 has the power and thermal envelope. Vol 5 has the OS-image distinctions; this volume is about the kernel that those OS images all share.
2. The Clockwork Kernel Patch Set
The uConsole is hardware that mainline Linux doesn’t know about. The mainboard’s specific peripheral set — the JD9365DA-H3 panel on DSI0, the GD32 keyboard MCU on the GL850G’s USB hub, the OCP8178 amplifier behind the BCM2711’s PWM audio output, the AXP228 PMIC over a non-standard I²C bus — is not a configuration the upstream Pi kernel ships drivers for. The Clockwork patches are a small layer of code and device-tree changes that make these peripherals visible.
2.1 What the patches actually do
The patches2 are smaller and more targeted than you might expect. They cluster into five buckets:
| Patch bucket | What it changes | Why |
|---|---|---|
| Panel driver | New file drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c | DSI command sequence + modeline for the specific panel revision |
| Device-tree overlay | New file arch/arm/boot/dts/overlays/clockwork-uconsole-lcd-overlay.dts | Wires the panel driver to DSI0, sets backlight GPIO, declares power rails |
| AXP228 quirks | Small additions to drivers/mfd/axp20x.c and drivers/power/supply/axp20x_battery.c | Handles the slightly non-standard register layout of the AXP228 vs the AXP223 the upstream driver targets |
| HID quirk for the keyboard | One-line addition to drivers/hid/hid-quirks.c | Tells the kernel the keyboard’s report descriptor is “this specific device” — needed because the keyboard reports as a generic HID and the quirk gives it a stable name for udev rules |
config.txt snippets | Default values that get baked into the OS image’s /boot/firmware/config.txt | Enables the panel overlay by default; sets dtparam=audio=on etc. |
That’s the entirety of the patch set. The bulk is the panel driver — about 600 lines of C with the panel’s DSI initialisation sequence, modeline, and backlight handler. Everything else is configuration-shaped — small edits, mostly two- or three-line additions in existing files.
What the patches don’t do — and shouldn’t:
- No kernel-API changes. The patches use only existing kernel interfaces (the DRM panel framework, the input subsystem, the I²C client API).
- No userland changes. ALSA configs, X11 / Wayland configs,
udevrules — these are layered on top by the OS distribution, not by the kernel patches. - No firmware blobs. The closed-source GPU firmware (
start4.elf) is the same blob that ships with upstream Pi OS; the patches don’t touch it. - No closed-source code. Every patch is GPLv2 source.
2.2 Where the patches live (upstream tracking)
The patches are maintained by Clockwork and re-rebased to match each Pi-Foundation kernel release. The release tag in the Clockwork repo (v6.6.31-clockwork, v6.12.x-clockwork, etc.) corresponds to the Pi kernel release the patches target. As of mid-2026, the relevant tags:
| Tag | Targets Pi kernel | Maintained for | Notes |
|---|---|---|---|
v6.6.y-clockwork | v6.6.x (LTS) | Pi OS Bookworm | Stable; mainline target for 2024-25 |
v6.12.y-clockwork | v6.12.x | Pi OS Trixie | Current as of 2026 |
v6.16.y-clockwork | v6.16.x | Bleeding-edge community Trixie | Experimental |
Rex’s images (Vol 5 / Vol 11) bundle the relevant tag’s pre-built kernel. CrossPlatformDev’s CI builds rebuild from this tag automatically on every Pi-kernel release.
These patches have never been submitted upstream to the mainline Linux kernel. There are two reasons: (1) the JD9365DA-H3 panel driver is generic enough that it could be merged, but the panel timing data is specific to Clockwork’s choice of panel and would need a Clockwork-specific compatible string in the device tree; (2) the AXP228 quirks should arguably be merged into the upstream axp20x driver as a new compatible, but no one has done the rebase work. If you wanted to contribute upstream, the AXP228 driver patch is the highest-value target.
2.3 Building a patched kernel from source
Most users will never need this — the pre-built kernel images are excellent. But if you’re hacking on the panel driver or chasing a kernel bug, the build:
# On a build host (Linux x86_64 with cross-toolchain, or another Pi):
sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev \
crossbuild-essential-arm64 ccache
# Clone the patched kernel:
cd ~/src
git clone --branch v6.6.y-clockwork https://github.com/clockworkpi/RaspberryPi-linux-clockworkpi
cd RaspberryPi-linux-clockworkpi
# Set up cross-build environment:
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
export KERNEL=kernel8
# Get the uConsole-specific config:
make bcm2711_defconfig
# (or for CM5: make bcm2712_defconfig)
# Then merge in the uConsole-specific config diffs:
scripts/kconfig/merge_config.sh -m .config arch/arm64/configs/uconsole.config
# Build kernel + DTBs + modules:
make -j$(nproc) Image modules dtbs
# Install to a mounted target SD card / USB:
sudo mkdir -p /mnt/uconsole-boot /mnt/uconsole-rootfs
sudo mount /dev/sdX1 /mnt/uconsole-boot # boot partition
sudo mount /dev/sdX2 /mnt/uconsole-rootfs # rootfs
sudo cp arch/arm64/boot/Image /mnt/uconsole-boot/kernel8.img
sudo cp arch/arm64/boot/dts/broadcom/*.dtb /mnt/uconsole-boot/
sudo cp arch/arm64/boot/dts/overlays/*.dtb* /mnt/uconsole-boot/overlays/
sudo cp arch/arm64/boot/dts/overlays/README /mnt/uconsole-boot/overlays/
sudo make INSTALL_MOD_PATH=/mnt/uconsole-rootfs modules_install
# Check the resulting kernel version:
ls /mnt/uconsole-rootfs/lib/modules/
# (should show the new version, e.g., 6.6.31-v8+)
sudo umount /mnt/uconsole-boot /mnt/uconsole-rootfs
A clean build on a 12-core Linux box takes ~12 minutes; on the uConsole itself, ~75 minutes (and you really shouldn’t — see Vol 11 thermals).
2.4 When to build vs use a pre-built image
| Use case | Pre-built image | Build from source |
|---|---|---|
| Run the canonical OS | ✅ | |
| Apply a security patch released by Pi | ✅ (waits for Rex) | ✅ (immediate) |
| Custom panel driver work | ✅ | |
| Custom keyboard MCU firmware integration | ✅ | |
| Debug a kernel hang | ✅ (with dynamic-debug) | |
| Add a new device-tree overlay | (sometimes possible via dtoverlay= in config.txt) | ✅ |
| Run on the latest Pi kernel before Rex rebases | ✅ | |
| Educational — understand the boot stack | ✅ |
For 95% of users, pre-built is correct. Building is for hardware hackers and kernel developers — not because it’s hard but because it’s a slow feedback loop on a battery-powered handheld.
3. The JD9365DA-H3 LCD Driver
This is the largest single piece of the patch set and the part that makes the most visible difference. The display works because of this driver.
3.1 The panel — controller + glass
The Clockwork uConsole’s display is a 5-inch IPS panel paired with a Jadard JD9365DA-H3 controller IC.3 The controller is a typical mid-2010s mobile-phone-style DSI IC: 4-lane MIPI DSI input, 1280×720 native resolution, 60 Hz refresh, RGB888 24-bit pixel format, and a backlight control via a separate PWM pin.
What’s notable is what isn’t on the controller:
- No HDMI input. The driver is DSI-only.
- No analog VGA. No surprise — modern mobile IC.
- No on-die scaler. Whatever resolution the host sends, the panel displays. Non-native resolutions get scaled by the host’s GPU, not the panel.
- No on-die touch controller. The uConsole’s panel is non-touch. (Some community mods bolt a USB capacitive touch controller in front; that’s a separate build.)
The panel’s IPS glass is the slow-but-good kind — wide viewing angles, accurate colour at off-axis, but slow pixel response time (~30 ms typical) compared to TN. For text, web, RetroArch, terminal use — fine. For action gaming — visible motion blur. This is intrinsic to the panel choice, not to the kernel driver.
3.2 DSI initialisation sequence
Powering on a DSI panel is not as simple as flipping a power switch. The controller IC needs a sequence of vendor-specific commands sent over the DSI command channel before it’s ready to display incoming pixel data. The JD9365DA-H3’s init sequence is approximately:
- Assert
RESETlow for ≥ 10 ms. - Wait for power supplies to settle (3.3 V logic, 1.8 V signal).
- Release
RESET. - Wait 100 ms for internal PLL to lock.
- Enter LP (Low Power) mode on the DSI bus.
- Send a sequence of ~80 vendor-specific DCS Long Write commands (gamma curves, source-driver timing, panel-specific compensation values).
- Send DCS command
0x11(Sleep Out). - Wait 120 ms.
- Send DCS command
0x29(Display On). - Switch DSI bus to HS (High Speed) mode.
- Begin streaming pixel data.
The driver implements this as a function panel_init_seq(). The “magic” bytes — those 80 vendor-specific commands — come straight from the panel datasheet’s Recommended Initialisation Sequence section. They configure the panel’s source-driver bias, the gate-driver shift register timing, the gamma-correction curve, and the IR-drop compensation. Most of them are opaque without the datasheet’s register reference table.
A good rule of thumb: if your screen comes up but the colours are wrong (red/blue swapped, low contrast, banding), the init sequence is right but a panel-specific gamma/colour parameter is wrong. If the screen is just black, either the init sequence isn’t running (driver not loaded? device tree not picked up?) or the backlight isn’t on (different problem — see §5).
3.3 The driver in the kernel tree
The driver lives at drivers/gpu/drm/panel/panel-jadard-jd9365da-h3.c (the upstream-style filename; some kernel forks call it panel-clockworkpi-uconsole.c). Structurally it follows the standard Linux DRM panel-driver pattern:
struct jd9365da_panel {
struct drm_panel base;
struct mipi_dsi_device *dsi;
struct backlight_device *backlight;
struct regulator *power;
struct gpio_desc *reset_gpio;
bool prepared;
bool enabled;
};
static const struct of_device_id jd9365da_of_match[] = {
{ .compatible = "clockworkpi,uconsole-lcd" },
{ .compatible = "jadard,jd9365da-h3" },
{}
};
static struct mipi_dsi_driver jd9365da_driver = {
.driver = {
.name = "panel-jadard-jd9365da-h3",
.of_match_table = jd9365da_of_match,
},
.probe = jd9365da_probe,
.remove = jd9365da_remove,
.shutdown = jd9365da_shutdown,
};
module_mipi_dsi_driver(jd9365da_driver);
Key methods (the four that the DRM framework calls):
| Method | When it runs | What it does |
|---|---|---|
prepare() | Power-on / wake from blank | Enable power regulator; deassert RESET; run init sequence (DSI cmds) |
enable() | After prepare, before pixel streaming | Send Display On DCS command; turn backlight on |
disable() | Before suspend / blank | Turn backlight off; send Display Off DCS command |
unprepare() | Power-off / deep blank | Disable power regulator; assert RESET; cut clocks |
The DRM framework calls these in a specific order: prepare → enable → (rendering) → disable → unprepare. If your screen flickers on resume from suspend, suspect prepare() — it’s getting called but the init sequence isn’t completing.
3.4 The clockwork-uconsole-lcd device-tree overlay
The overlay tells the kernel:
- “There is a
mipi_dsi_devicewithcompatible = 'clockworkpi,uconsole-lcd'on DSI0.” - “Its RESET line is wired to GPIO 5 (BCM numbering).”
- “Its backlight PWM is on PWM0 channel.”
- “Its power regulator is a fixed 3.3 V LDO from the AXP228’s
DISP_3V3rail.”
In .dts form:
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2711";
fragment@0 {
target = <&dsi0>;
__overlay__ {
status = "okay";
panel: panel@0 {
compatible = "clockworkpi,uconsole-lcd";
reg = <0>;
reset-gpios = <&gpio 5 GPIO_ACTIVE_LOW>;
backlight = <&backlight>;
power-supply = <&disp_3v3>;
status = "okay";
};
};
};
fragment@1 {
target-path = "/";
__overlay__ {
backlight: backlight {
compatible = "pwm-backlight";
pwms = <&pwm 0 1000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <6>;
};
disp_3v3: disp_3v3 {
compatible = "regulator-fixed";
regulator-name = "DISP_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
};
};
};
The overlay is enabled by dtoverlay=clockwork-uconsole-lcd in config.txt (covered in Vol 4 §13.1). The overlay file is compiled to clockwork-uconsole-lcd.dtbo and stored in /boot/firmware/overlays/.
3.5 Pixel timing and the modeline
The panel’s modeline (the timing parameters telling the kernel exactly when to assert HSYNC, VSYNC, and how long each blanking interval lasts) is embedded in the panel driver. The values, from the datasheet:
| Parameter | Value | Notes |
|---|---|---|
| Native resolution | 1280 × 720 | Fixed; panel is 5″ IPS |
| Native refresh | 60 Hz | Configurable down to 30 Hz on lower-power profiles |
| Pixel clock | 74.25 MHz | 1280 × 720 × 60 × 1.075 (blanking) |
| Horizontal front porch | 110 | pixel clocks |
| Horizontal sync width | 40 | pixel clocks |
| Horizontal back porch | 220 | pixel clocks |
| Vertical front porch | 5 | lines |
| Vertical sync width | 5 | lines |
| Vertical back porch | 20 | lines |
| DSI lane count | 4 | 4-lane MIPI DSI |
| DSI bit rate per lane | ~445 Mbps | For 60 Hz operation |
If you change the modeline (e.g., to drive 30 Hz to save power), you must change both the pixel clock and the lane bit rate proportionally. There is no scaling in the panel — it simply reads pixels at the rate the host streams them.
3.6 Common LCD failure modes
| Symptom | Likely cause | First-line fix |
|---|---|---|
| Screen totally black, backlight off | Backlight not enabled (PWM duty 0) | brightnessctl set 50%. Or check dtparam=audio=on not breaking PWM. |
| Screen totally black, backlight on (faint glow) | Panel init sequence not running | `dmesg |
| Screen on but display garbled / wrong colours | DSI init sequence partially broken | Check kernel logs for DSI errors. Re-power-cycle (cold boot, not reboot). |
| Screen flickers periodically | DSI clock mismatch or PSR issue | Disable kernel DRM PSR support: video=DSI-1:e:none in cmdline.txt |
| Half the screen rendered, half black | Panel driver thinks resolution is different than actual | Verify modeline matches the panel datasheet |
| Vertical bands of static | RESET signal glitch on power-up | Check for RC delay on RESET line; if missing, slow the RESET deassertion in driver |
| Display on for ~3 seconds then black | Boot logo OK but kernel can’t take over | DRM/KMS stack failed to bring up. Check dmesg. |
| Resume-from-suspend gives black screen | prepare()/enable() ordering bug in panel driver | Often fixed by upgrading kernel; or workaround systemd-suspend.service to skip display suspend |
| Tearing during full-screen video | No vsync; KMS atomic commit not enabled | Use a Wayland compositor (sway, wayfire) instead of X11; or xrandr --output DSI-1 --primary |
4. Display Stack: Framebuffer, DRM/KMS, Wayland/X11
The kernel makes a screen exist; user-space puts pixels on it. There are several layers in user-space, and choosing the right one matters for performance and feature support.
4.1 The legacy fbdev path
Once upon a time, every Linux screen was a “framebuffer device” — /dev/fb0. The kernel exposed the screen as a memory-mapped region; you wrote bytes; pixels appeared. Tools like fbi (image viewer) and fbterm (terminal) used this directly.
On the uConsole, /dev/fb0 still exists for legacy compatibility, but it’s a compatibility shim over DRM/KMS — the kernel’s modern stack — not a primary path. Writing directly to /dev/fb0:
sudo cat /dev/zero > /dev/fb0 # blanks the screen
sudo cat /dev/urandom > /dev/fb0 # static
These work but bypass DRM’s modesetting, atomic commit, and synchronisation. Tearing is common; performance is limited; modern compositors don’t use this path.
When fbdev is fine: bare-metal embedded loadouts where you want a single full-screen application (a kiosk, a graphing-calculator app, a SDR spectrum display) with no compositor overhead. Use kmscube to verify DRM works, then fbi for static images, mpv for video.
When fbdev isn’t fine: anything wanting hardware-accelerated rendering, multiple windows, or playing nicely with systemd-logind.
4.2 DRM/KMS — the modern stack
The Direct Rendering Manager + Kernel Modesetting (DRM/KMS) is the modern path. The kernel exposes /dev/dri/card0 (the GPU device) and /dev/dri/renderD128 (the rendering node, for headless rendering). User-space talks to these via libdrm or the higher-level mesa graphics library.
DRM/KMS gives:
- Atomic mode-setting — flip resolution / refresh / pixel format in one transaction; either the whole change applies or none of it does.
- Vsync-aware page-flipping — no tearing.
- Hardware planes — overlay a video plane atop a UI plane without copying pixels.
- Multiple consumers — one process can render while another reads back; the GPU arbitrates.
Tools:
kmscube— minimal triangle demo. If it works, your DRM stack is fine.modetest— query and exercise DRM modes from the command line.drm_info— pretty-prints the DRM device’s capabilities.
sudo apt install drm-info modetest
sudo drm_info | head -40
On a working uConsole, drm_info lists “Connector DSI-1” with the JD9365DA-H3’s modeline.
4.3 X11 on the uConsole
X11 (specifically Xorg) runs on the uConsole. The default Pi OS desktop until Bookworm, X11 is well-supported and well-understood. On the uConsole’s stock kernel:
- The Xorg server uses the
modesettingdriver (pure DRM/KMS-based). - Xorg starts via
lightdmorgdm3fromsystemd. - Window manager:
mutter(GNOME default) orfluxbox,i3, anything that runs on Xorg.
X11’s strengths on the uConsole:
- GTK2 / older GNOME / older Qt apps work. Ancient TUIs and bespoke graphing tools just work.
xinputfor input device tuning — granular trackball / keyboard configuration.- Network transparency —
ssh -Xworks, you can run a GUI app from a remote box on your local screen.
X11’s weaknesses:
- Tearing. Without compositor work,
xtermscrolling tears visibly. - HiDPI is ad-hoc. You can scale, but it’s per-application.
- High idle CPU. Xorg + a compositor + a window manager idles at ~3% CPU when nothing’s happening, vs ~0.5% on Wayland.
4.4 Wayland on the uConsole
Wayland is the default on Pi OS Bookworm and later. The compositor on Pi OS Bookworm is wayfire; on Bookworm-Lite it’s whatever you install (sway is popular).
Wayland’s strengths on the uConsole:
- Vsync everywhere. No tearing.
- HiDPI consistent. The compositor scales the whole desktop; apps follow.
- Low idle CPU. ~0.5% with
wayfire. - Better security model. Apps can’t read each other’s input or screen content.
Wayland’s weaknesses:
ssh -Xdoesn’t work in the X11 sense. Need to use VNC orwaypipe.- Some apps don’t run — older GTK2, some Qt5 apps that hardcode X11 paths.
- Input device tuning is per-compositor. The
xinputof the X11 world is replaced by compositor-specific config files.
4.5 Compositor-specific gotchas
Per-compositor notes:
| Compositor | uConsole behaviour |
|---|---|
wayfire | Default on Pi OS Bookworm. Works out of the box. Screen capture: wf-recorder. |
sway | Popular for power-users. Tile-only; no floating windows by default. Good battery life. |
gnome-shell | Works but heavyweight. Idles at ~5% CPU. Not recommended for handheld use. |
kwin_wayland | Plasma’s compositor. Fully featured but heavy. |
cosmic-comp | System76’s compositor. Still maturing in 2026. |
weston | Reference compositor; minimal. Useful for testing the underlying stack. |
For the uConsole as a handheld pen-test / SDR / writing device, sway or wayfire are the right answers. Heavy compositors (gnome-shell, kwin) are overkill for this hardware class.
5. Backlight Control
The screen has two PWM-driven brightness paths and they don’t always coordinate. Worth understanding before you “fix” the brightness.
5.1 Two PWM sources, one knob
The JD9365DA-H3 panel has its own internal PWM that controls the LED backlight intensity. The mainboard also has a PWM signal exported from the BCM2711’s PWM0 channel, routed through a level-shifter, that goes to the panel’s LEDPWM input.
So the actual brightness is: (host PWM duty) × (panel internal PWM duty) × (LED max current).
In normal operation, the panel-internal PWM is set to a fixed maximum (during the init sequence), so changing brightness means changing the host PWM duty. This is what brightnessctl does.
5.2 The keyboard MCU’s role
The keyboard backlight (the white LEDs under each key) is on a separate PWM, this one driven by the GD32F103 keyboard MCU. It is independent of the screen backlight and uses the keyboard MCU’s GPIO PWM peripheral. From the host side, the keyboard backlight is controllable via the GD32 firmware’s USB control endpoint — there’s a small command set (set brightness, get brightness, fade) — and Clockwork ships a userspace tool (uconsole-kbd-bl) that wraps these into shell-callable commands.
5.3 Linux interfaces (sysfs, brightnessctl)
Once the device-tree overlay is loaded, the screen backlight appears under /sys/class/backlight/:
$ ls /sys/class/backlight/
clockwork-uconsole-bl
$ cat /sys/class/backlight/clockwork-uconsole-bl/max_brightness
255
$ cat /sys/class/backlight/clockwork-uconsole-bl/brightness
128
$ echo 200 | sudo tee /sys/class/backlight/clockwork-uconsole-bl/brightness
For higher-level convenience, brightnessctl:
sudo apt install brightnessctl
brightnessctl get # current brightness (raw value)
brightnessctl info # all backlights + current/max
brightnessctl set 50% # set to 50% of max
brightnessctl set +10% # increase by 10%
brightnessctl set 5%- # decrease by 5%
brightnessctl writes to the same sysfs interface but handles the “absolute” vs “relative” semantics cleanly. It’s the recommended tool.
For the keyboard backlight (if you have it):
# Older Clockwork tool:
sudo uconsole-kbd-bl --brightness 100 # 0-255
# Newer (kernel-level) interface, if Rex's image exposes it:
echo 100 | sudo tee /sys/class/leds/clockwork-uconsole-kbd::brightness
The keyboard backlight is not on /sys/class/backlight/ — it’s on /sys/class/leds/. Different kernel subsystem.
5.4 The “screen too dim” community gripe
Several community posts complain about the uConsole’s screen being too dim under bright sunlight. Some context:
- The IPS panel’s max nominal brightness is ~300 nits.
- That is normal for a budget IPS panel from this era.
- Sunlight readability requires 700+ nits, which is in different-class panel territory.
If the screen seems unusually dim indoors (not just sun-washed), check:
- Software brightness:
brightnessctl get— if it reports <max_brightness, raise it. - Panel-internal PWM: if the panel’s own PWM has been set low by a malformed init sequence, you’ll see a low maximum even at host PWM 100%. Re-flash a known-good kernel.
- Backlight LED string degradation: after 5+ years, LED strings dim. This is hardware aging; replacement panel modules are available.
The keyboard-backlight version of this gripe is “the keyboard backlight is useless.” It is not very bright; this is by design (battery life trade-off). You can boost it via the uconsole-kbd-bl tool or by patching the GD32 firmware to allow higher PWM duty cycles (community mod, Vol 11).
6. The Keyboard Subsystem
The 74-key gamepad-style keyboard is one of the uConsole’s distinguishing features. Linux sees it as a USB HID keyboard. This chapter is the Linux-side reference.
6.1 GD32F103 firmware
The GD32F103R8T64 is an ARM Cortex-M3 @ 72 MHz with 64 KB Flash and 20 KB SRAM, in an LQFP-64 package. It runs Clockwork’s open-source firmware (Code/uconsole_keyboard/ in the Clockwork repo, MIT-licensed). The firmware does:
- Scan the 5×16 key matrix every 5 ms (200 Hz scan rate).
- Debounce key events (10 ms typical hold-down requirement).
- Generate USB HID report packets matching the standard 8-byte boot keyboard format + 8 bytes for modifier-keys-as-bitmap.
- Drive the backlight LED PWM from a brightness register.
- Receive USB control transfers for backlight commands.
- Implement a serial/console mode (an unused-by-default debug interface that exposes a tiny shell).
The keyboard board has its own LM1117S-3.3 LDO for the GD32’s 3.3V supply (Vol 2 §8). The USB connection is through the GL850G hub on the mainboard.
Re-flashing the GD32 firmware is possible via SWD (Single-Wire Debug) but requires a JTAG adapter and physically opening the case. Most users never re-flash.
6.2 The USB HID descriptor
The keyboard reports as USB VID 0x28e9 (GigaDevice generic) PID 0x0289 (or a Clockwork-assigned PID — varies by firmware revision). The HID descriptor declares:
- One Report ID 1 — boot-style 8-byte keyboard (modifier byte + 6 keycodes + reserved).
- One Report ID 2 — extended modifier keys (Function key, Ctrl-Function, Alt-Function chord codes).
- Possibly: one Report ID 3 — Consumer Control (volume, brightness, media keys mapped from Function chords).
Linux’s usbhid driver picks this up automatically. You can inspect the device:
$ lsusb | grep -i clockwork
Bus 001 Device 003: ID 28e9:0289 GDMicroelectronics ClockworkPi uConsole Keyboard
$ udevadm info --query=all --name=/dev/input/event4 | head -20
P: /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.4/1-1.4:1.0/0003:28E9:0289.0001/input/input4/event4
N: input/event4
S: input/by-id/usb-ClockworkPi_uConsole_Keyboard-event-kbd
S: input/by-path/platform-fd500000.pcie-pci-0000:01:00.0-usb-0:1.4:1.0-event-kbd
E: ID_BUS=usb
E: ID_INPUT=1
E: ID_INPUT_KEY=1
E: ID_INPUT_KEYBOARD=1
E: ID_VENDOR=ClockworkPi
E: ID_VENDOR_ID=28e9
E: ID_MODEL=uConsole_Keyboard
E: ID_MODEL_ID=0289
The 0003:28E9:0289 in the path is the HID-quirks-required identifier — 0003 is the HID protocol class, then VID:PID. The Clockwork patch adds an entry to hid-quirks.c so the kernel knows to apply specific quirks (mostly: don’t be confused by the F-key chord codes).
6.3 Linux input layer mapping
Linux exposes input devices as event nodes under /dev/input/event*. The keyboard appears as event4 (number varies). The kernel’s input layer translates HID-level keycodes to Linux’s evdev keycodes. Most keys map cleanly:
| Physical key | HID code (hex) | Linux evdev code |
|---|---|---|
A | 0x04 | KEY_A (30) |
Enter | 0x28 | KEY_ENTER (28) |
LeftShift | 0xE1 | KEY_LEFTSHIFT (42) |
Fn (Clockwork) | 0x65 (vendor) | KEY_FN (464) |
Esc | 0x29 | KEY_ESC (1) |
The “Fn” key is the most non-standard part — it’s used to access the F-key row (F1-F12 are accessed as Fn+1, Fn+2, etc.) and the volume/brightness shortcuts. Linux’s input layer handles this via the KEY_FN keycode plus key-chord remapping in user-space.
6.4 Custom keymaps via xkb
Under X11, the X Keyboard Extension (XKB) is the canonical tool. The Clockwork keyboard is detected as a generic 105-key PC keyboard by default; you may want to remap.
A simple example — swap Caps Lock and Esc (the vim user’s first edit):
# Add to ~/.xinitrc or similar:
setxkbmap -option caps:swapescape
# Or system-wide via /etc/default/keyboard:
XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS="caps:swapescape"
For richer customisation, xmodmap:
# Read current map:
xmodmap -pke > my_keymap.txt
# Edit my_keymap.txt to add custom mappings.
# Apply:
xmodmap my_keymap.txt
Or for full custom layouts, write an XKB rule fragment in /usr/share/X11/xkb/symbols/uconsole — out of scope for this volume but documented in the X.org wiki.
6.5 Custom keymaps via Wayland
Under Wayland, each compositor has its own keymap config, but they all use the same XKB syntax internally. For wayfire:
# ~/.config/wayfire.ini
[input]
xkb_layout = us
xkb_options = caps:swapescape
For sway:
# ~/.config/sway/config
input "type:keyboard" {
xkb_layout us
xkb_options caps:swapescape
}
# To find your keyboard's identifier:
swaymsg -t get_inputs | jq '.[] | select(.type=="keyboard")'
6.6 The keyboard backlight LEDs
The white LEDs under the keys are PWM-driven by the GD32 MCU. From Linux:
- Older interface:
uconsole-kbd-bl --brightness N(where N is 0-255). - Newer kernel-level interface (Rex’s images):
/sys/class/leds/clockwork-uconsole-kbd::brightness.
Brightness levels:
| Setting | Backlight perception |
|---|---|
| 0 | Off |
| 64 | Just visible in a dark room |
| 128 | Comfortable indoor |
| 192 | Bright for night use |
| 255 | Maximum (still not very bright) |
The community gripe “keyboard backlight is too dim” is real and stems from a battery-life-vs-brightness trade-off in the firmware. To boost it requires SWD-flashing the GD32 with custom firmware (the source is open).
6.7 Common keyboard issues matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| Specific key requires hard press (e.g., T) | Production variation in switch quality, or hidden key-cap obstruction | First: clean (compressed air, IPA on a Q-tip). If persistent: replace keyboard PCB. |
| Multiple keys fire from one press | Debounce issue or dirty switch | Clean. If persistent: GD32 firmware has a tunable debounce — re-flash if you can. |
Stuck modifier (Shift won’t release) | Firmware bug or stuck switch | setkeycodes reset; or re-flash GD32 firmware |
Fn chord doesn’t work | Quirk not applied | Verify HID quirks loaded: cat /sys/kernel/debug/hid/0003:28E9:*/rdesc |
| Keyboard not detected at all | USB hub or LDO failure | lsusb — if no Clockwork device, hardware fault on keyboard PCB |
| Backlight doesn’t respond | GD32 firmware version too old, or uconsole-kbd-bl not installed | Update firmware; install tool |
| Symbols on different keys than printed | XKB layout mismatch | setxkbmap us (or whatever your physical layout is) |
| Keyboard works in console but not in X | X11 input device hot-plugged after Xorg start | xinput list; if missing, restart Xorg |
7. The Trackball
The right side of the keyboard has a small mechanical trackball with two buttons (left- and right-click). It’s mounted on the keyboard PCB and shares the GD32’s USB endpoint.
7.1 Sensor and buttons
The trackball is an optical-mouse-style sensor (typically a PixArt PAW32xx or similar) reading the rotation of a small ball. The GD32 firmware reads the X/Y motion deltas from the sensor at ~125 Hz (8 ms intervals) and packages them into a HID Mouse report alongside the keyboard scancodes.
Linux sees the trackball as a separate input device from the keyboard, even though they share the same physical USB endpoint. From xinput list:
⎜ ↳ ClockworkPi uConsole Keyboard id=10 [slave pointer (2)]
⎜ ↳ ClockworkPi uConsole Keyboard id=11 [slave keyboard (3)]
The mouse-class (id=10) has the trackball; the keyboard-class (id=11) has the keys.
7.2 The “janky trackball” community gripe
The trackball’s reputation in the community is “janky.” Specifics:
- Pickier than expected. The optical sensor needs the ball to be clean and the ball-cup to be free of dust. Pocket lint accumulates fast.
- Tracking inconsistency. Slow motions sometimes don’t register; fast motions over-shoot.
- Mechanical wear. The ball-cup’s plastic deforms slightly over heavy use; community reports say after a year of daily use, replacement is recommended.
The factory tracking sensitivity is fairly low. xinput-tunable in software (next §). For mechanical mitigation, regular cleaning (~weekly, with a Q-tip and isopropyl alcohol) keeps it usable. Replacement trackball assemblies are sold by Clockwork and several aftermarket vendors (Talking Sasquach mentions community 3D-print upgrades).
7.3 Tuning sensitivity in xinput / Wayland
Under X11:
# List the trackball:
xinput list | grep -i clockwork
# Find the device id (e.g., 10):
xinput list-props 10
# Set acceleration profile (0=flat, 1=adaptive):
xinput set-prop 10 "libinput Accel Profile Enabled" 1, 0 # adaptive
# Set acceleration speed (-1.0 to 1.0):
xinput set-prop 10 "libinput Accel Speed" 0.5
Save in ~/.xinitrc or a script that runs on session start.
Under Wayland (wayfire):
# ~/.config/wayfire.ini
[input]
mouse_accel_profile = adaptive
mouse_accel_speed = 0.5
Under sway:
# ~/.config/sway/config
input "type:pointer" {
accel_profile adaptive
pointer_accel 0.5
}
7.4 Replacement trackball options
Three paths if the stock trackball is unsatisfactory:
- Clean and re-grease. The cheap fix. Disassemble, clean ball + cup with IPA, apply a tiny dab of light oil. Buys 6-12 months.
- Aftermarket trackball. Several Tindie sellers offer drop-in replacement trackball assemblies with better optical sensors. Cost: $15-30. Talking Sasquach (Vol 7 community notes) calls some of these worthwhile.
- External pointing device. Use a USB mouse or trackpad via the USB-A port. Loses the integrated form factor but gains a real pointing device. Best for desk use; impractical for handheld.
8. The Audio Path (Linux-Side)
The audio path’s hardware story (BCM2711 PWM-audio → AS4729 routing → OCP8178 amp → speakers) is in Vol 2 §7. This chapter is the Linux-side: how the kernel exposes audio, what ALSA looks like, what the realistic quality story is.
8.1 ALSA card numbering on the uConsole
ALSA enumerates audio devices as “cards.” On a uConsole running Pi OS, you typically see:
$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Headphones [bcm2835 Headphones], device 0: bcm2835 Headphones [bcm2835 Headphones]
Subdevices: 7/7
Subdevice #0: subdevice #0
...
card 1: vc4hdmi0 [vc4-hdmi-0], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
Subdevices: 1/1
Card 0 is the PWM-audio path — the BCM2711’s “headphone” output, which is what the uConsole’s speakers are connected to. Despite being labelled “Headphones,” this is the path to the OCP8178 amps and the speakers. There is no separate “Speaker” card — audio in / out goes via card 0.
Card 1 is the HDMI audio path (only when HDMI is connected). You can ignore this for most uConsole loadouts.
If a USB audio device is plugged in, it gets a new card number (typically card 2 or 3).
8.2 The PWM-audio driver
The bcm2835-audio driver in the Linux kernel implements PWM-audio. The driver:
- Takes incoming PCM samples from ALSA.
- Runs them through a delta-sigma modulator (in software for low rates, GPU-assisted for higher rates).
- Outputs the modulated bitstream as a PWM duty cycle on a GPIO pin.
- The GPIO is filtered through the AS4729 → OCP8178 → speaker chain (Vol 2 §7).
This is a simple, clever hack from 2012’s Pi 1 era that has aged into “the Pi audio path.” It works. The quality is bounded by the PWM resolution and the analog filter — see §8.3.
8.3 Sample rate, depth, and the realities of PWM-audio
Quoted spec on the Pi PWM-audio path:
| Parameter | Value |
|---|---|
| Sample rate | 44.1 kHz / 48 kHz |
| Bit depth | 11 bits effective |
| Dynamic range | ~50 dB SNR |
| Frequency response | 50 Hz – 18 kHz (at -3 dB) |
Reality (what you actually hear):
- Speech, podcasts, soft music: fine. Listenable.
- Bass-heavy music: thin. The speaker enclosures are small and the bass has little air to move.
- High-fidelity music (chamber music, jazz horns, etc.): listenable but not satisfying. The 50 dB SNR is well below CD-quality (96 dB).
- Synth music from chiptune-era games: surprisingly good. PWM-audio aliasing isn’t a problem for square-wave-heavy material.
Practical implication: if audio quality matters for your loadout (music production, ham-radio digital-mode listening), use a USB DAC instead of the on-device speakers. A $30 SaPlace or $80 Schiit Modi will sound enormously better than the built-in path.
For most loadouts (terminal beep, alarm sounds, occasional notification), the built-in path is fine.
8.4 ALSA → PulseAudio → PipeWire stack
Linux audio stacks layered on ALSA:
| Layer | Role | Status on Pi OS |
|---|---|---|
| ALSA | Kernel-level audio driver + library | Always present |
| PulseAudio | Userland audio server, mixer, app routing | Default on Pi OS Bookworm and earlier |
| PipeWire | Modern replacement for PulseAudio | Default on Pi OS Trixie and later |
| JACK | Pro-audio low-latency server | Optional; for music production |
PulseAudio and PipeWire both expose ALSA cards as “sinks” and “sources” with per-app volume control, mixer routing, automatic device-switching. PipeWire additionally supports JACK clients, so a PipeWire-equipped uConsole can run pro-audio apps.
The transition from PulseAudio to PipeWire is largely painless — pavucontrol (the GUI mixer) works on both via a compatibility shim. For most users, “your audio works” is the same on either.
For a music-production loadout (Vol 1 §6 community archetype):
- PipeWire +
qjackctlfor low-latency audio routing. - LMMS, SunVox, Cardinal, etc. as JACK clients via PipeWire’s compatibility layer.
- Community report: PipeWire’s latency on the BCM2711 is ~5-10 ms with
quantum=512, which is acceptable for non-real-time work and tolerable for tracker-style live sequencing. Real-time monitoring (singing into a mic and hearing it in headphones) is not realistic without a USB audio interface.
8.5 The microphone path
The uConsole has a small electret microphone on the keyboard board, routed through the AS4729’s analog input to the BCM2711’s PWM-audio input (which uses a delta-sigma converter in reverse for input). The microphone is exposed as ALSA card 0 device 0 capture:
arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: Headphones [bcm2835 Headphones], device 0: bcm2835 Headphones [bcm2835 Headphones]
# Test recording:
arecord -D plughw:0,0 -f cd -d 5 test.wav
aplay test.wav
Quality is mediocre — the microphone is unidirectional and far from your mouth, and the analog signal chain isn’t optimised for microphone-class input. Use cases that work: voice memos, simple voice commands. Use cases that don’t: video conferencing without an external mic, voice recording for content creation.
For real microphone work, a USB headset or a USB lavalier is mandatory.
8.6 Common audio issues matrix
| Symptom | Likely cause | Fix |
|---|---|---|
| No sound at all | dtparam=audio=on missing or audio chip not initialised | Check config.txt; reboot. Check `dmesg |
| Sound at very low volume | ALSA mixer or PulseAudio mixer set low | alsamixer, pavucontrol — raise master. |
| Crackling / clipping | PulseAudio buffer too small, or excessive system load | Adjust default-sample-rate in /etc/pulse/daemon.conf; or move to PipeWire. |
| Sound only on HDMI, not built-in | Wrong default card | pavucontrol Output Devices → set Headphones as default. Or pacmd set-default-sink. |
| Hum / buzz | Ground loop or charger PSU noise | Try battery-only operation. If clean, charger PSU is the culprit. |
| Stutter when CPU loaded | Audio thread starved; PWM-audio is CPU-driven | Use chrt -f -p 50 $(pidof pulseaudio) to raise priority. |
| Microphone records silence | ALSA capture muted (default) | alsamixer → F4 (capture view) → unmute mic. |
| USB audio device not switched to | PulseAudio not auto-switching on hot-plug | pacmd set-default-sink to the USB device; or enable module-switch-on-connect. |
9. Display Power Management
A handheld with 2-4 hour battery life lives or dies by good DPMS (Display Power Management Signaling). This chapter is what’s available and how to use it.
9.1 DPMS modes
Standard X11 / DRM DPMS modes:
| Mode | Backlight | Pixel data sent? | Power saved | Wake-up time |
|---|---|---|---|---|
| On | Yes | Yes | 0% | 0 ms |
| Standby | Yes | No | ~5% | <1 ms |
| Suspend | No | No | ~30% | ~50 ms |
| Off (DPMS) | No | No | ~35% | ~200 ms |
Trigger via X11:
xset dpms force off # Power off display
xset dpms force on # Power back on
xset s 60 # Screen blank after 60 seconds idle
xset dpms 600 900 1200 # Standby/Suspend/Off after these many seconds
Under Wayland, the compositor controls DPMS. For wayfire:
[output:DSI-1]
mode = 1280x720@60
For sway:
swaymsg "output DSI-1 dpms off"
swaymsg "output DSI-1 dpms on"
9.2 The systemd-logind path
Modern Linux uses systemd-logind to coordinate power states. It listens for lid-close, power button, and idle events and triggers actions defined in /etc/systemd/logind.conf:
[Login]
HandlePowerKey=suspend # Press power button → suspend
HandleLidSwitch=suspend # Lid close → suspend (no lid on uConsole, but…)
IdleAction=suspend
IdleActionSec=30min
The uConsole has no lid switch and the power button is wired to the AXP228 directly (Vol 2 §3.5), so HandlePowerKey= is what controls the soft-power-off behaviour. Setting it to ignore lets you handle the power button in your own script (useful for “press to dim, hold to suspend, very-long-hold to power off” custom logic).
9.3 Custom blank-and-suspend scripts
A simple “blank screen + reduce CPU + sleep” script:
#!/bin/bash
# /usr/local/bin/uconsole-low-power.sh
# Dim screen
brightnessctl set 5%
# Lower CPU governor
echo powersave | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
# Disable WiFi
sudo nmcli radio wifi off
# Disable Bluetooth
sudo rfkill block bluetooth
Bind to a Fn-chord on the keyboard via xbindkeys (X11) or your compositor’s keybindings (Wayland). Battery life with this active is roughly 6+ hours — more than double the typical “idle, screen on” runtime.
For deeper sleep (suspend-to-RAM), systemctl suspend. But: the AXP228’s idle current in suspend is ~60 mA — non-negligible. For overnight storage, a real shutdown (systemctl poweroff) is more battery-friendly.
10. Rockchip Kernel Differences (Radxa CM5)
If you’ve installed a Radxa CM5, the kernel story changes. Most user-visible behaviour is the same; the implementation underneath is different.
10.1 Different DSI controller
The RK3588S2 has a Rockchip-designed DSI controller, not the Broadcom one. The JD9365DA-H3 panel driver still works (the panel is the same — only the controller is different) but the device-tree entries change:
&dsi0 {
status = "okay";
rockchip,lane-rate = <445>;
panel: panel@0 {
compatible = "clockworkpi,uconsole-lcd";
reg = <0>;
// ... same as before
};
};
The &dsi0 reference is to a different node in the device tree (Rockchip’s, not Broadcom’s), and the rockchip,lane-rate property is Rockchip-specific. If you’ve ported the panel driver from Pi OS to Armbian, you make these adjustments.
10.2 Different ALSA setup
The RK3588S2 has an on-die I²S controller. The uConsole’s mainboard wires the OCP8178/AS4729 audio chain to the I²S bus instead of using PWM-audio. ALSA card numbering shifts:
- Card 0:
rk3588s2-i2s(the audio path; hardware sends bit-stream over I²S, OCP8178 decodes it). - Card 1: HDMI audio (when connected).
- USB cards as before.
Audio quality is significantly better than PWM-audio — full 16-bit / 48 kHz nominal, 80+ dB SNR. The Radxa-CM5 path is the audio-quality upgrade path for users who care.
10.3 Different keyboard PHY enumeration
Same keyboard hardware (GD32F103), same USB HID protocol. But the GL850G hub is on a different USB host root on the Rockchip side, so the device path changes:
# Pi side path:
/devices/platform/scb/fd500000.pcie/.../usb1/1-1/1-1.4/...
# Rockchip side path:
/devices/platform/usb@fc800000/...
udev rules that match by path will need updating; rules matching by VID:PID work unchanged.
10.4 The DTS-porting checklist
If you’re authoring a Radxa-CM5 uConsole image:
- Panel driver: copy the JD9365DA-H3 driver source from the Pi clockwork-kernel tree.
- Panel device tree: rewrite the overlay for Rockchip DSI references (§10.1).
- Audio device tree: wire the RK3588S2’s I²S controller to the AS4729/OCP8178 chain.
- Backlight: Rockchip’s PWM controller is at a different MMIO address; update the
pwms = <&pwm 0 ...>reference. - Power tree: the AXP228 is still on the mainboard, but the I²C controller it sits on is different (different bus number).
- Boot config: make sure U-Boot loads
rk3588s2-uconsole.dtb(the right DTB filename).
This is non-trivial work — typically a weekend for a kernel developer who’s done it before, longer for a first-timer. The community is starting to build this up in the Armbian Radxa CM5 patches.
11. Canonical OS Image Kernels
This chapter is the practical “where does my kernel come from” reference.
11.1 Rex’s Bookworm / Trixie images
Maintained by community member “Rex” on the ClockworkPi forum:
- Bookworm 6.6.y for uConsole/DevTerm:
https://forum.clockworkpi.com/t/bookworm-6-6-y-for-the-uconsole-and-devterm/13235 - Trixie 6.12.y for uConsole/DevTerm:
https://forum.clockworkpi.com/t/trixie-6-12-y-for-the-uconsole-and-devterm/19457
Both are full Pi-OS-derived images with Clockwork patches pre-applied. The kernel is rebuilt periodically when Rex pulls in new Pi-Foundation kernel updates. If you want “the canonical CM5 path on the uConsole,” these are the images to use.
11.2 CrossPlatformDev CI builds
https://github.com/crossplatformdev/uConsole-Image-Builder/releases — automated CI builds of Jammy/Bookworm/Trixie for CM3/CM4/CM5 with multiple desktop environments. Useful if you want a specific DE pre-installed (KDE Plasma, XFCE, MATE, etc.). Built on top of the Clockwork kernel patches, so the panel and keyboard work out of the box.
11.3 Building your own from source
If neither of the above gives you what you want — say, you want a custom XFCE-Lite image with a hand-tuned kernel config and minimal package set — the path:
- Start from a base image (Pi OS Lite or Debian Bookworm minimal).
- Apply the Clockwork patches per §2.3 of this volume.
- Customise package set with
apt. - Add your custom config files.
ddthe result to an SD/eMMC.
pi-gen (Pi-Foundation’s image-build tool) is the standard scaffolding for this — https://github.com/RPi-Distro/pi-gen. Allows scriptable image creation.
Building a full image takes ~45 minutes on a fast workstation. The Clockwork-patches step is the only uConsole-specific bit; everything else is standard Debian/Pi image construction.
12. Vol 12 Cheatsheet Updates
The following one-pagers go into Vol 12:
- §6 (Display):
brightnessctl get/set, DPMS toggles (xset dpms,swaymsg output dpms), modeline reference. - §8 (Keyboard):
xkbandwayfire/swaykeymap snippets, the common keyboard issues matrix from §6.7. - §9 (Audio):
alsamixer,pavucontrol, the audio issues matrix from §8.6, the microphone test command (arecord -D plughw:0,0 -f cd -d 5 test.wav). - §10 (Trackball): tuning commands for
xinput/ wayfire / sway. - §13 (Display power management): the DPMS table from §9.1, the low-power-mode script from §9.3.
- §15 (Error → fix matrix): the LCD failure modes from §3.6, the keyboard issues from §6.7, the audio issues from §8.6.
13. Resources
| Source | URL |
|---|---|
| Clockwork uConsole repo (kernel patches) | https://github.com/clockworkpi/uConsole |
| Pi clockwork-patched kernel | https://github.com/clockworkpi/RaspberryPi-linux-clockworkpi |
| Pi device-tree documentation | https://www.raspberrypi.com/documentation/computers/configuration.html#device-trees-overlays-and-parameters |
| Linux DRM/KMS overview | https://docs.kernel.org/gpu/drm-uapi.html |
Wayland (wayfire) | https://github.com/WayfireWM/wayfire |
Wayland (sway) | https://swaywm.org/ |
Pi OS image build (pi-gen) | https://github.com/RPi-Distro/pi-gen |
| Rex’s Bookworm uConsole image (forum) | https://forum.clockworkpi.com/t/bookworm-6-6-y-for-the-uconsole-and-devterm/13235 |
| Rex’s Trixie uConsole image (forum) | https://forum.clockworkpi.com/t/trixie-6-12-y-for-the-uconsole-and-devterm/19457 |
| CrossPlatformDev image builder | https://github.com/crossplatformdev/uConsole-Image-Builder/releases |
| Armbian Radxa CM5 page | https://www.armbian.com/radxa-cm5/ |
brightnessctl | https://github.com/Hummer12007/brightnessctl |
xkb documentation | https://wiki.archlinux.org/title/X_keyboard_extension |
| GD32F103 datasheet (GigaDevice) | https://www.gigadevice.com/products/microcontrollers/gd32-arm-cortex-m3/ |
| JD9365DA-H3 datasheet | 02-inputs/datasheets/JD9365DA-H3_DS_V0.01_20200819.pdf (also 03-outputs/datasheets/) |
| ALSA documentation | https://www.alsa-project.org/wiki/Main_Page |
| PipeWire documentation | https://pipewire.org/ |
14. Footnotes
(Footnotes are listed inline above; this section is a placeholder anchor for the index.)
15. Index
A — ALSA — §8 (full chapter). Audio issues matrix — §8.6. AXP228 patches — §2.1.
B — Backlight (screen) — §5. Backlight (keyboard) — §6.6. bcm2835-audio driver — §8.2. brightnessctl — §5.3. Buttons (trackball) — §7.1.
C — cmdline.txt (cross-ref Vol 4) — §3.6. Compositor — §4.5. Compatible string (panel) — §3.3. clockwork-uconsole-lcd overlay — §3.4. Cross-platformdev CI — §11.2.
D — DCS commands — §3.2. Debounce — §6.7. Device tree overlay — §3.4, §10. DPMS — §9.1. DRM/KMS — §4.2. DSI controller (Pi) — §3.3. DSI controller (Rockchip) — §10.1. dtoverlay= — §3.4 (cross-ref Vol 4). DLDOs — Vol 2 cross-ref.
E — enable() (DRM) — §3.3. Event nodes (/dev/input/event*) — §6.3.
F — fbdev — §4.1. fbi — §4.1. Framebuffer — §4.1. Function key (Fn) — §6.3, §6.7.
G — Gamma curve — §3.2. GD32F103 — §6.1. GL850G — §6.2 (cross-ref Vol 2 §9). GNOME — §4.5.
H — HID descriptor — §6.2. HID quirks — §2.1, §6.2.
I — init sequence (panel) — §3.2. Input layer (Linux) — §6.3. IPS panel — §3.1. I²S (Radxa) — §10.2.
J — JACK — §8.4. JD9365DA-H3 — §3 (full chapter).
K — Kernel build — §2.3. Kernel patches — §2 (full chapter). Keyboard — §6 (full chapter). Keyboard backlight — §6.6.
L — LM1117S-3.3 — §6.1 (cross-ref Vol 2 §8). LED PWM — §5.1. Lid switch (none) — §9.2.
M — Microphone — §8.5. Modeline — §3.5.
N — Native resolution — §3.5.
O — OCP8178 — Vol 2 cross-ref, §8.2. Open-source firmware (GD32) — §6.1. Overlay — §3.4.
P — Panel driver — §3.3. PCF85063A (cross-ref Vol 7) — §3.6 (recovery context). PinePhone — N/A. PipeWire — §8.4. PulseAudio — §8.4. PWM-audio — §8.2, §8.3. PWM-backlight — §5.
Q — qjackctl — §8.4.
R — RESET (panel) — §3.2. Rex’s images — §11.1. Rockchip — §10 (full chapter). RP2040 — N/A. RTC (cross-ref Vol 4) — §9.
S — Sample rate — §8.3. Schiit Modi — §8.3. SDXC — N/A. setxkbmap — §6.4. SNR — §8.3. Sound issues — §8.6. sway — §4.5, §6.5. systemd-logind — §9.2.
T — T-key (community gripe) — §6.7. Trackball — §7 (full chapter). TrustZone — N/A this volume.
U — uconsole-kbd-bl — §5.3, §6.6. USB DAC — §8.3. USB HID — §6.2.
V — vc4hdmi0 (HDMI audio) — §8.1. Vsync — §3.6.
W — wayfire — §4.4, §6.5. Wayland — §4.4, §6.5.
X — X11 — §4.3. XKB — §6.4. xinput — §7.3.
Y, Z — None.
Footnotes
-
Raspberry Pi device-tree documentation:
https://www.raspberrypi.com/documentation/computers/configuration.html#device-trees-overlays-and-parameters. Lists the overlay system and the syntax fordtparam=anddtoverlay=inconfig.txt. ↩ -
The patches live in the Clockwork uConsole repo:
https://github.com/clockworkpi/uConsole. The relevant subdirectories areCode/uconsole_kernel/(kernel module sources and DTS overlays) andCode/uconsole_keyboard/(GD32 firmware sources). The patches are released under GPLv2 (matching the upstream Linux kernel licence). ↩ -
JD9365DA-H3 datasheet:
02-inputs/datasheets/JD9365DA-H3_DS_V0.01_20200819.pdf. User guide:02-inputs/datasheets/JD9365DA-H3_User_Guide_Preliminary_V0.00_20200827.pdf. Both shipped with the Clockwork uConsole repo athttps://github.com/clockworkpi/uConsole. Note the version stamp — these are early datasheet revisions; some details may differ from the panel that actually ships, but they’re representative. ↩ -
GD32F103 datasheet from GigaDevice:
https://www.gigadevice.com/products/microcontrollers/gd32-arm-cortex-m3/. The R8T6 SKU has 64 KB flash and 20 KB RAM — adequate for a USB HID keyboard with backlight control. ↩