Skip to content

Max 6.x#2

Open
ppy2 wants to merge 18 commits intomasterfrom
MAX_6.X
Open

Max 6.x#2
ppy2 wants to merge 18 commits intomasterfrom
MAX_6.X

Conversation

@ppy2
Copy link
Owner

@ppy2 ppy2 commented Nov 10, 2025

No description provided.

ppy2 and others added 18 commits November 8, 2025 14:43
Problem: Audio artifacts/distortion on 44.1 kHz sample rate family due to
MCLKOUT stuck at 12 MHz instead of following calibrated PLL frequencies.

Root cause: Clock multiplexer CLK_I2S0_8CH_TX was not being switched to
CLK_I2S0_8CH_TX_SRC parent at boot, remaining on default xin_osc0_half (12 MHz).

Solution:
- Add CLK_I2S0_8CH_TX to assigned-clocks with parent CLK_I2S0_8CH_TX_SRC
- Add I2S0_8CH_MCLKOUT to assigned-clocks with parent MCLK_I2S0_8CH_TX
- Add rockchip,no-fractional-divider property to prevent fractional divider selection
- Remove MCLKOUT management from driver (managed via device tree only)

Clock path now matches kernel 5.10 behavior:
PLL_GPLL → TX_SRC (calibrated) → CLK_TX → MCLK_TX → MCLKOUT

Verified working:
- 44.1 kHz → MCLKOUT = 45.158 MHz ✓
- 48 kHz → MCLKOUT = 49.152 MHz ✓
- 88.2/96/192 kHz all working correctly ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add assigned-clock-rates to external clock mode DTS configuration to ensure
CLK_I2S0_8CH_TX properly switches to i2s0_mclkin parent at boot.

Without this fix, CLK_I2S0_8CH_TX remains on default xin_osc0_half parent,
preventing external clock mode from working.

In external mode:
- External oscillators (22.579 MHz / 24.576 MHz) provide MCLK
- Driver switches between them via freq-domain-gpios based on sample rate
- CLK_I2S0_8CH_TX must use i2s0_mclkin as parent for this to work

Files updated:
- rv1106_ext-ipc.dtsi (MAX variant)
- rv1106_512_ext-ipc.dtsi (512MB variant)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Enable DWC3 controller by changing status from disabled to okay
- Fix USB2PHY driver to handle missing main IRQ gracefully
- Add support for PHY_MODE_USB_HOST_HS/FS/LS modes for kernel 6.1
- Fix fallthrough issue causing USB PHY to enter invalid mode
- Enhance USB2PHY tuning for better high-speed detection
- Improve signal integrity for USB devices on kernel 6.1

This fixes USB audio device detection and enumeration issues when
upgrading from kernel 5.10 to 6.1 on RV1106 platform.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Added USB2PHY driver fixes for proper IRQ handling
- Enhanced PHY mode support for USB_HOST_HS/FS/LS modes
- Fixed fallthrough bug in mode switching
- Added kernel 6.1 specific USB2PHY tuning parameters
- Resolved USB speed negotiation issues for audio devices

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Eliminated ~200 lines of duplicated DSD/PCM switching code
- Created rockchip_i2s_tdm_handle_dsd_switch() unified function
- Removed temporary //+++ markers and fixed formatting
- Optimized debug logging (dev_info -> dev_dbg for non-critical messages)
- Preserved all functionality: PLL/EXT clocks, PCM/DSD, mute/automute, volume control
- Maintained DSD bit swap and physical pin swap capabilities
- Successfully compiled and tested without breaking changes

Code is now cleaner, more maintainable, and production-ready.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Changes included:
1. Fixed PCM noise in EXT mode by preventing DSD routing from affecting PCM data
2. Updated I2S driver with extensive debugging and clock handling improvements
3. Modified kernel configuration and patches for proper audio support

Key fix: Modified rockchip_i2s_tdm_handle_dsd_switch() to apply DSD routing
only when DSD is being enabled, preventing PCM channel corruption in EXT mode.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add USBtoI2S button to web interface with unique purple style
- Implement USB mode switching via web (host/gadget)
- Remove usb-mode-switch script - not needed anymore
- Add S00usbmodules init script to load USB modules on boot based on mode
- Update post-build.sh to strip and remove duplicate external toolchain libraries (libstdc++, libgcc_s, libatomic, libgfortran, libgomp) - saves ~28MB
- Add uac2_router package with S98uac2 for UAC2 gadget management
- Update ALSA scripts to properly stop services using sh -c '/etc/init.d/S95*'
- Fix I2S TDM DSD routing and BCLK calculation for UAC2 router
- Add dwc3_gadget.ko custom module for USB gadget mode
- Add dwc3_host.ko custom module for USB host mode
- Use standard dwc3-of-simple.ko from kernel for both modes
- Add USBtoI2S state file persistence across reboots
- Web button shows loading spinner and locks/unlocks USB-I2S toggle
- Button stays active after enable and deactivates on player switch
- USB modules load based on /etc/usb_to_i2s.state file at boot
- Fix external toolchain library duplication issue in /lib and /usr/lib
- OTP is identical on all devices, cannot use for unique MAC
- Use Flash ID from /dev/mtd0 (NAND flash chip ID)
- First 4 bytes of flash = unique identifier per chip
- MAC format: BE10E0:74:ce:c4:XX:XX (last 2 bytes from random)
- Flash ID is factory-programmed and survives reflashing
- Read first 6 bytes from /dev/mtd0 for unique flash ID
- Use first 3 bytes from flash + 2 random bytes for NIC
- Format: BE10E0:74:ce:c4:XX:XX (12 hex chars with colons)
- Properly handle hexdump output with tr -d to remove spaces
- Use first 6 bytes from Flash ID for NIC (no random bytes)
- MAC address: BE10E0:74:ce:c4:1f:6d (all from flash)
- MAC remains constant after reflashing firmware
- Removed random byte generation for consistent addresses
- No factory unique ID available on Luckfox Pico Max
- Flash ID is identical on all boards
- OTP is identical on all boards
- CPU Serial is zeros
- Solution: Generate random MAC on first boot
- Save to /data/ethaddr.txt (persists in UBI rootfs)
- File survives reflashing firmware
- Same MAC address across reboots after first generation
- Extract Serial part: dec0a266340399cf → 0a266340399cf
- Use first 12 hex chars from Serial for NIC
- Generate MAC: BE10E0:0a:26:63:40:39:9c:f
- Save to both U-Boot env and /data/ethaddr.txt
- MAC is unique per CPU and persists through reflashing
- No more random bytes!
…actor

I2S/TDM driver (rockchip_i2s_tdm.c):
- Add seamless_transition_active flag to keep MCLK running during
  frequency switches, eliminating ~6.7ms suspend/resume delay
- Add active_playback pointer to track substream for DSD meander fill
- DSD TRIGGER STOP: keep I2S/BCLK/DMA running, fill DMA with 0x55
  meander pattern instead of stopping stream
- DSD TRIGGER START: start only DMA/XFER (I2S already running in DSD)
- Fix calculate_dsd_bclk(): proper BCLK per format type (U8/U16/U32)
  instead of raw sample_rate passthrough
- PLL/SRC tolerance: skip unnecessary clk_set_rate if within ±100Hz/±1kHz
- Cross-domain glitch fix: disable MCLK before PLL domain switch,
  re-enable after PLL is stable
- DSD mute: fill buffer with 0x55 (meander) instead of 0x00
- Add ktime timing instrumentation to DSD switch, params, trigger
- Remove static 50ms/500ms msleep delays from DSD switch path

New package: buffer_daemon
- Buildroot package for buffer management daemon with init script

Kernel & DTS:
- Enable CONFIG_ROCKCHIP_CPUINFO in linux.config for serial number access
- Add nvmem serial-number cell to rv1106_ext.dts and rv1106_pll.dts

System scripts:
- S01RkLunch: simplify MAC generation (remove broken multi-fallback code),
  read /data/ethaddr.txt or generate from last 3 bytes of CPU serial
- usb_to_i2s.sh/usb_unlock.sh: use ln -sf, run statusmonitor in background

Web UI:
- Rename i2s.php → handle_i2s.php
- I2S modal: compact layout (300px), scrollbar, reduced font/padding sizes
- CSS: remove per-toggle selector blocks (moved to JS), remove dissolve animation
- JS: add 'leftjust_title' key to all 5 language dictionaries
- LEFTJUST sysfs hook commented out (driver not yet supporting it)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
calculate_dsd_bclk() was returning raw sample_rate (~88-706 kHz)
instead of the actual DSD bit clock. Roon passes PCM-equivalent
sample rates via uac2_router, not native DSD bit rates.

BCLK = sample_rate * bits_per_word:
  DSD_U32_LE: 88200  * 32 = 2,822,400 Hz (DSD64)
  DSD_U32_LE: 176400 * 32 = 5,644,800 Hz (DSD128)
  DSD_U32_LE: 352800 * 32 = 11,289,600 Hz (DSD256)
  DSD_U32_LE: 705600 * 32 = 22,579,200 Hz (DSD512)

Without this fix div_bclk was computed as ~256 instead of ~8,
resulting in BCLK ~256x too slow and completely wrong I2S timing
in DSD mode.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two fixes for DSD frequencies in the 48kHz family
(DSD64/48=3.072MHz, DSD128/48=6.144MHz, etc.):

1. div_lrck is now derived from DSD format word size, not
   hardcoded to 32. Relationship: LRCK = BCLK / div_lrck = sample_rate,
   so div_lrck = bits_per_word:
     DSD_U8:        div_lrck = 8
     DSD_U16_LE/BE: div_lrck = 16
     DSD_U32_LE/BE: div_lrck = 32  (unchanged, primary Roon format)

2. Expected MCLK check now accounts for both frequency families
   and mclk_multiplier:
     44.1kHz grid: 22,579,200 Hz (x512) / 45,158,400 Hz (x1024)
     48kHz grid:   24,576,000 Hz (x512) / 49,152,000 Hz (x1024)
   Previously the check was hardcoded to 22,579,200 Hz only,
   producing false warnings for every 48kHz DSD stream.

Note: calculate_dsd_bclk (sample_rate * bits_per_word) is already
correct for 48kHz grid — no changes needed there.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rockchip_i2s_tdm.c — calculate_dsd_bclk():
  Support two DSD rate conventions from different callers:
  A) uac2_router: passes native DSD bit rate (>= 1 MHz) → BCLK = rate
     44.1k: 2822400/5644800/11289600/22579200 Hz
     48k:   3072000/6144000/12288000/24576000 Hz
  B) Roon/ALSA: passes PCM frame rate (< 1 MHz) → BCLK = rate * bits_per_word
     DSD_U32_LE 44.1k: 88200*32=2822400 Hz
     DSD_U32_LE 48k:   96000*32=3072000 Hz
  Previous fix (multiply always) broke the uac2_router path:
  2822400*32=90 MHz — completely wrong BCLK.

uac2_router.c — 48kHz DSD family support:
  - Add DSD rate constants for 48kHz grid:
      DSD64/48=3072000  DSD128/48=6144000
      DSD256/48=12288000  DSD512/48=24576000
  - is_dsd_rate(): recognize all 8 DSD rates (44.1k + 48k families)
    Previously 48kHz DSD was treated as PCM → wrong ALSA format on I2S
  - dsd_base_rate(): return DSD64 base rate for the correct family,
    used for period_size calculation
  - get_dsd_name(): names for all 8 DSD variants
  - setup_pcm(): period_size now uses dsd_base_rate() for correct
    ~0.7ms period regardless of frequency family

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The kernel source at buildroot/output/ is a build artifact (in .gitignore)
and should never be tracked. Previous 3 commits (785691f, 9c0a705,
part of 979e01f) incorrectly modified it directly. All changes are now
applied to the proper location: ext_tree/patches/linux_rv1106.patch.

linux_rv1106.patch — calculate_dsd_bclk():
  Two-convention DSD BCLK calculation:
  A) uac2_router: native DSD rate >= 1 MHz -> BCLK = rate (as-is)
  B) Roon/ALSA:   PCM frame rate < 1 MHz   -> BCLK = rate * bits_per_word
  Handles both 44.1kHz and 48kHz DSD families.

linux_rv1106.patch — DSD hw_params:
  - MCLK check accounts for both frequency families and mclk_multiplier
    (was hardcoded to 22579200 Hz, now derives expected value correctly)
  - div_lrck derived from format word size (U8=8, U16=16, U32=32)
    instead of hardcoded 32 — correct for all DSD format types

uac2_router.c — already committed in 979e01f, re-staged to confirm.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DLNA Bridge:
- New dlna_bridge package: C daemon routes ALSA loopback → HTTP WAV → UPnP renderer
- asound.bridge: type route + type multi (I2S + loopback simultaneous output)
- Web UI: DLNA Bridge button with settings icon (APrender pattern), swipe-to-hide
- handle_dlna.php: SSDP discovery via socket_select non-blocking loop (fix break-on-timeout)
- dlna_enable/disable.sh: runtime toggle scripts

USBtoI2S 8-channel:
- S98uac2: c_chmask=255 (8ch TDM, was 2ch stereo)
- uac2_router: I2S_CHANNELS dynamic from UAC2 sysfs (was hardcoded to 2)
- usb_to_i2s.sh: switch to asound.8ch + SUBMODE=8ch

PCM up to 768kHz (kernel patch):
- rockchip_i2s_tdm: all_supported_rate_list constraint in startup (enumerates 705.6/768kHz)
- rockchip_i2s_tdm: hw_params rejects PCM when BCLK > MCLK (needs 1024x multiplier)
- dummy-codec: rate_max=22579200 covers PCM 768kHz + DSD512

Spotify Connect fix:
- nice -n -15 applied directly to librespot (was renice on shell)
- --normalisation-gain-type none (eliminates CPU-heavy loudness scan)
- --cache-size-limit 12M (was 64M, caused memory pressure on 128MB RAM)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant