Retroid Pocket Duo Lite running mainline Debian: gaps left, help needed

I’ve been putting mainline Linux on the Pocket Duo Lite (the SM6125 model, not the QCS8550 Duo) for a while now. It’s at the point where it’s a decent little dual-screen machine: both panels and touch, Plasma, gamepad as the mouse and keyboard, on-screen keyboard, Wi-Fi, BT, lid suspend, fan, chargers, Tailscale, Moonlight streaming. Kernel is 7.2.11 with the ROCKNIX SM6115 patches rebased and a pile of my own fixing.

Everything’s here if you want to look or yell at it: GitHub - testyfishy/duolinux: Debian 13 + KDE Plasma on a Retroid Pocket Duo Lite handheld: dual panels, gamepad input, on-screen keyboard, InputPlumber wheel fork · GitHub

What’s left, and where I’m stuck: mic (works in Android; but I cannot get it to work), speaker level (amps at profile max, but still barely audible), volume slider (is either broken or the speakers are barely audible and I cannot differentiate), and the hardware accelerating encoding engine from Qualcomm ‘Venus’ (cant get it to work).

One thing worth saying plainly: a lot of this was written with DeepSeek helping me. I’m not a kernel developer, this is a far cry from my main profession, I just refused to leave the device on Android. So if any of the above has an obvious answer I’ve missed, that’s why.

Hello Brotha! I dunno much about any of this, but, I can point Fable at it. So, I did. 10 mins of compute from Anthropics flag ship coming at ya. My morning on the internet is filled with neckbeard passive aggressive vitriol possibly rooted in some new AI inferiority complex. So, I don’t wanna be that guy. I hope this helps. “Reviewing a forum post about mainline Linux setup.

Reviewing a forum post about mainline Linux setup.

I’ll pull the repo and look at the actual device tree and audio config before answering, since the SM6125 audio/Venus issues are very configuration-specific.

Ran 21 commands

I cloned the repo and read docs/MICROPHONE.md, docs/SPEAKERS-NEXT.md, docs/HELP-WANTED.md and the gaming/Venus scripts, then checked them against the upstream drivers (lpass-tx-macro.c, lpass-va-macro.c, aw88166.c, venus pm_helpers.c/hfi_venus.c, gcc-sm6125.c). There are a few things he’s missed, and one of them (the mic) looks like a real “obvious in hindsight” answer. Here’s a reply you can post more or less as-is:


Read through the repo — nice work, especially the measured docs. A few things that I think you’ve missed, in order of how confident I am.

1. Mic: you’re asking the wrong macro for the clock — and you don’t need audioreach

Your own disassembly already contains the answer. The vendor bolero_dmic_clk_enable tables (0x3084/0x3088/0x308c/0x3090, enable masks 1/2/4/8) are the VA macro’s DMIC0..3_CTL registers plus the freq-change bits in VA_TOP_CSR_DMIC_CFG. Mainline has that exact sequence already: va_dmic_clk_enable() in sound/soc/codecs/lpass-va-macro.c writes the same registers with the same masks. On Bolero the MSM DMIC clock pads are generated by the VA macro, full stop; the vendor TX macro just calls across into it.

Upstream never wired that cross-call. In lpass-tx-macro.c, "TX DMIC0..7" are plain SND_SOC_DAPM_INPUTs — nothing runs when you capture through them. The SWR_DMICn_CTL register you fought with is only a clock select for SoundWire mics (CDC_TX_SWR_DMIC_CLK_SEL_MASK, bits 3:1), which is why bit 0 never latched: it isn’t an enable. So “TX DMIC2 → TX_CODEC_DMA_TX_3” can never produce a PDM clock on mainline. Not a bug you can patch around in TX.

Why your hand-poke of the VA registers didn’t work either: nothing has voted the VA macro’s core clock with the ADSP (that’s what the bolero_clk_rsc_request_clock layer you found does — it’s an AFE clock request, q6afecc in mainline). Without a bound VA macro driver, MMIO writes to the macro latch fine and nothing clocks. “Values stick, audio doesn’t appear” is exactly that.

The part I think you’ve got wrong: VA_CODEC_DMA_TX_0 is a legacy q6afe port, not an audioreach one. sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c lists VA_CODEC_DMA_TX_0 right next to the TX_CODEC_DMA_TX_3 you already use, and qrb5165-rb5.dts captures DMICs through it with plain q6afe/q6asm — no SPF firmware. Since CDC-DMA ports already work on your ADSP (TX_3 does), VA_0 almost certainly does too; Android uses it for hotword.

So the fix is a DT change, not a sound-card rewrite:

  • Add a VA macro node modelled on sm8250.dtsi’s vamacro (qcom,sm8250-lpass-va-macro, clocks mclk/macro/dcodec from &q6afecc, #clock-cells, clock-output-names = "fsgen"). Take the real reg base and clock IDs from the va-macro node in your extracted Android DTB — you already have extract-android-dtb.sh.

  • qcom,dmic-sample-rate = <2400000> (the driver refuses to probe without it; 9.6 MHz / 4 matches the vendor’s 0x249f00). DMIC pinctrl can stay on your gpio127/128 pair.

  • Add a va-dai-link copied from RB5: cpu <&q6afedai VA_CODEC_DMA_TX_0>, platform <&q6routing>, codec <&vamacro 0>.

  • Routing: "VA DMIC2", "MIC BIAS1" (replacing the "TX DMIC2", "MIC BIAS1" line — same mux index, pair 1, just on the VA side). Then VA DMIC MUX0 = DMIC2 and VA_AIF1_CAP Mixer DEC0 instead of the TX controls.

Retroid’s Duo port doing it through VA wasn’t about audioreach; it’s that VA is the only macro on mainline that owns the DMIC clock.

2. Speakers: the registers match, so the difference is somewhere a register dump can’t see

Two states the vendor driver writes at runtime that live in the AW88166’s DSP RAM, not in registers:

  • Calibrated Re. The vendor driver loads the factory speaker-resistance calibration (persist partition, aw_cali-style file) into the DSP. Mainline only does it if you set the Calib ALSA control, and aw_dev_update_cali_re() silently ignores out-of-range values — so right now the smart-PA algorithm is running on whatever default is baked into dsp_cfg. A protection algorithm with a wrong Re will clamp output.

  • vmax. The vendor aw_monitor code raises the boost-voltage ceiling in DSP memory based on battery level. Mainline aw88166.c doesn’t touch vmax at all. If the ACF default is conservative and Android’s monitor table lifts it at full battery, you’d get exactly “identical registers, much quieter”.

A decisive cheap test before digging: push software gain to 2–4× (PipeWire allows >1.0, e.g. wpctl set-volume <id> 3.0). If it gets much louder (even if it clips), the amps had headroom and your problem is input level on the ADSP side. If it barely changes, the amp’s DSP is limiting, and Re/vmax is where to look. Then find the calibration value on the Android persist partition and feed it to Calib, and have parse-acf.py dump the monitor section for vmax.

The pa stop check fail:0x0330 is consistent with this family: 0x0330 is PLLS/CLKS still set, i.e. the amp is told to stop while the bit clock is still running. Ordering, cosmetic — your note is right.

3. The dead volume slider is almost certainly PipeWire using the broken hardware mixer

“20 % vs 100 % makes no difference” can’t happen with software volume — that’s 14 dB. It means WirePlumber picked a hardware mixer element for this card and the writes are going nowhere. Side-step it:

# /etc/wireplumber/wireplumber.conf.d/50-duo-softmixer.conf
monitor.alsa.rules = [
  { matches = [ { device.name = "~alsa_card.*" } ]
    actions = { update-props = { api.alsa.soft-mixer = true } } }
]

Slider works immediately, and Plasma’s “raise maximum volume” then gives you 150 % for free.

On the amixer crash: rc 134 is abort() from alsa-lib’s own assert in snd_ctl_elem_info() — the element id it was handed has neither a name nor a numid. That’s not the kernel’s ELEM_INFO being broken; it’s the element list containing a blank entry. Run amixer -c0 controls (that only uses ELEM_LIST) and look for an entry with an empty name or numid 0; that control is the culprit, probably from one of the machine-driver or topology patches.

4. Venus: you’re reading post-mortem state, and the bus clocks live in GCC

“venus_gdsc off, zero users, clk_src never enabled” is what you’d read after a failed init — the driver powers everything back down on failure. It doesn’t tell you anything about the moment it failed. failed to reset venus core comes from hfi_venus.c after venus_boot_core() polled CTRL_STATUS and the firmware CPU never signalled init. Which means PAS auth (or the no-TZ load) had already returned OK, the GDSCs were on, and the clocks were enabled by core_power_v4(). The core just didn’t run. Two things to check, in order:

  1. Firmware. On a production (fused) device the TZ only runs a venus image signed by the OEM’s chain, and the load address must be the one Android reserves. Use the device’s own venus.mbn from the firmware partition you already mount for the modem/ADSP, and make sure memory-region matches the Android DTB’s pil_video_mem. Confirm in dmesg which path ran (core->use_tz) and that qcom_pas_auth_and_reset returned 0.

  2. GCC clocks. SM6125 differs from SM6115 here: the video block’s bus clocks are in GCC, separate from the videocc you wrote. Upstream gcc-sm6125.c marks only gcc_video_ahb_clk and gcc_video_xo_clk CLK_IS_CRITICAL; gcc_video_axi0_clk (0x1701c), gcc_video_throttle_core_clk and gcc_qmip_video_vcodec_ahb_clk stay off unless something references them. A firmware CPU with no AXI path to DDR is precisely a boot_core timeout. Quick experiment: temporarily flag those three CLK_IS_CRITICAL in gcc-sm6125.c, or reference GCC_VIDEO_AXI0_CLK as the node’s bus clock the way bengal references GCC_VENUS_CTL_AXI_CLK. The vendor DTB’s qcom,vidc node clock-names list is the authority for which GCC clocks it expects.

Also sample clk_summary and the GDSC state during the probe (blacklist venus_core, modprobe it by hand with a loop reading debugfs in another shell), not after. And the apps_smmu SIDs you have (0x860/0x880) are bengal’s; take trinket’s from the vendor DTB — that won’t cause the boot timeout but it’s the next wall.

Hope that helps — the mic one in particular should be a weekend, not a rewrite.


Two notes for you, Mud Butt: I’m confident on the mic analysis (it’s straight from the upstream source and matches his own vendor disassembly) and on the PipeWire soft-mixer fix. The speaker Re/vmax theory and the Venus GCC-clock theory are well-grounded but unverified — I phrased them as tests to run rather than fixes, and you may want to keep that framing. He also mentions emailing Retroid; nothing above needs them.

Sources: