August 16Aug 16 Mainline Kernel 6.18 (Rock Pi S): rockchip-i2s-tdm registers locked in UNCLAIMED state with passive S/PDIF transverters (m0 mapping) Hardware Setup SoC: Rockchip RK3308 (Radxa Rock Pi S) Audio Extension: 3 separate Wolfson WM8805 boards (I2S to S/PDIF TOSLINK), wired in parallel to the primary I2S0 bus for a multi-channel setup. Pin Mapping (m0): Explicitly hardwired to m0 alternative function: Pin 35 = GPIO2_A4 = I2S0_8CH_MCLK_M0 (pin 68 in pinctrl) Pin 33 = GPIO2_A5 = I2S0_8CH_SCLK_M0 (pin 69 in pinctrl) Software Environment OS: Modern Armbian (Debian Trixie) Kernel: Stable Mainline Linux 6.18.43-current-rockchip64 Sound Card Configuration: Registered via decompiled Device Tree using simple-audio-card with linux,spdif-dit as a passive dummy codec backend. The Problem Description While the ALSA layer registers the multi-channel device flawlessly and playback initiates without any software errors, the physical TOSLINK TX diodes remain completely dark. Live kernel tracing exposes a strict power-gating and pinctrl-locking mechanism inside the mainline rockchip-i2s-tdm driver architecture when facing a headless/passive audio layout. Deep-Dive Diagnostic Logs (Live under Stream Load) When executing an 8-channel stream (speaker-test -D hw:1,0 -c 8), we verified the following states: Clock Subsystem (/sys/kernel/debug/clk/clk_summary) The internal audio PLL dividers calculate and lock perfectly onto the exact target frequency (48kHz multiple), and the reference counter increments from 3 to 4: clk_i2s0_8ch_tx_src 1 1 0 12288000 0 0 50000 Y deviceless no_connection_id clk_i2s0_8ch_tx_mux 1 1 0 12288000 0 0 50000 Y deviceless no_connection_id clk_i2s0_8ch_tx 4 4 0 12288000 0 0 50000 Y i2s@ff300000 no_connection_id clk_i2s0_8ch_tx_out 0 0 0 12288000 0 0 50000 N deviceless no_connection_id However, the physical output gate clk_i2s0_8ch_tx_out remains strictly locked at N (Disabled) and is flagged as deviceless. Pin Controller State (/sys/kernel/debug/pinctrl/.../pinmux-pins) Even during active ALSA playback, the pinmux controller completely refuses to route the active internal clocks out to the physical balls of the SoC: pin 68 (gpio2-4): ff300000.i2s (GPIO UNCLAIMED) function i2s_8ch_0 group i2s-8ch-0-mclk pin 69 (gpio2-5): ff300000.i2s (GPIO UNCLAIMED) function i2s_8ch_0 group i2s-8ch-0-sclktx The alternative functions are assigned correctly (function i2s_8ch_0), but the driver leaves them flagged as GPIO UNCLAIMED. Extensive Troubleshooting & Root Cause Analysis We have thoroughly tested the limits of the Device Tree and Runtime modifications: DTS Bindings Failed: Injecting properties like simple-audio-card,continuous-clock, frame-master, bitclock-master, or explicitly binding the clock output to the codec node via clocks = <&i2s0_8ch 0>; has absolutely zero effect. The primitive spdif_dit.c driver has no .probe or .set_sysclk routines to request the clock. Driver Patching (Trigger Routine): We patched the driver's rockchip_i2s_tdm_trigger routine to forcefully call clk_prepare_enable(i2s_tdm->mclk_tx). The reference counter successfully increments to 4, but the CCF/Power Management layer suppresses the physical output because no hardware handshake is returned from the passive transmitter. Direct Register Override Hack: We deployed a custom runtime kernel module executing a direct iowrite32(0x40000000, cru_reg) onto the CRU hardware register CLKGATE_CON5 (0xff500314). While dmesg confirms the hardware register write is successful and the physical gate opens on the silicon level, the pinctrl layer still isolates the pads in an UNCLAIMED state. 3. Pin Configuration State (`/sys/kernel/debug/pinctrl/.../pinconf-pins`) A live register dump of the pad configurations confirms that the m0-muxing is successfully applied on the silicon layer, and electrical drive stages are actively provisioned: pin 68 (gpio2-4): input bias disabled, output drive strength (2 mA), input schmitt enabled, slew rate (0x0), mux (0x1) pin 69 (gpio2-5): input bias disabled, output drive strength (2 mA), input schmitt enabled, slew rate (0x0), mux (0x1) This proves the issue is purely a logical lock within the ASoC / Pinctrl driver handshake, as the physical multiplexer is correctly set to mux (0x1) for I2S0 m0. The Question to the Maintainers In the old legacy vendor BSP kernels (Linux 4.4/5.10), the Rockchip driver forced the pin configurations blindly into output mode. In Mainline 6.18, the dynamic handshake locks passive audio configurations out completely. What is the officially intended mainline approach to bypass this dynamic power-saving guardrail for headless/passive setups? How can we force rockchip-i2s-tdm to permanently transition the pinctrl states to claimed and enable clk_i2s0_8ch_tx_out without a physical I2C/SPI control loop?
August 17Aug 17 This is a very well researched and thorough bug report. Thank you. Unfortunately, I don't have access to the hardware needed to verify it. I am the maintainer of this particular board. Do you believe this is a board specific problem, or one that is common to all Armbian Rockchip boards? Do you feel it is related to power-saving logic? (Have you tried replicating this problem on another Rockchip board?) To your last questions: I don't know the officially intended mainline policy. Could you explain what you mean by "physical I2C/SPI control loop?" Could you point me to an example of such?
August 17Aug 17 Author Hi brentr, Thank you for your fast response! To answer your questions based on my tests with this specific board: Board-specific vs. common Armbian Rockchip issue: This is very likely an issue common to all modern Mainline Rockchip audio drivers (specifically rockchip-i2s-tdm) when handling a passive/headless configuration. The driver's power-saving/runtime PM logic expects an active digital handshake from a smart codec (usually via I2C/SPI control loops) to fully claim the pins and keep the clocks alive. Power-saving logic: Yes, it is deeply related to the modern Kernel's runtime power management and clock gating. Without an active external codec answering to control commands, the ASoC framework doesn't receive the "active" trigger state back from the passive hardware side, causing the CCF layer to keep clk_i2s0_8ch_tx_out at N (gated) and leaving the pinctrl states at UNCLAIMED even though ALSA reports active playback. What I mean by "physical I2C/SPI control loop": In a standard layout, a smart DAC/Codec (like a Wolfson/Cirrus WM8804 or similar configured as an I2C slave) is actively queried by the kernel during driver initializing. If the kernel probes the device via I2C and it responds, the sound card enters a fully established state, which automatically triggers the pinctrl driver to transition from UNCLAIMED to claimed and signals the CCF to un-gate the MCLK output. In my headless/passive setup, the DAC inputs are purely wire-bound (listening to MCLK/BCLK/Data passively). There is no microcontroller or I2C bus connected to talk back to the Rock Pi S. My main obstacle right now: Since the device tree parser completes successfully and ALSA creates the card device (card 1: rockchip,rk3308-toslink), the parsing stage is fully intact. Is there an official device-tree property or driver flag within the mainline rockchip-i2s-tdm implementation to force a "dummy-handshake" or configure the controller into an un-gated, always-on clock master state for headless designs? Edited August 18Aug 18 by g.coach
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.