diff --git a/projects/ROCKNIX/devices/SM8750/audio-topology/README.md b/projects/ROCKNIX/devices/SM8750/audio-topology/README.md new file mode 100644 index 00000000000..2b0b469b2cd --- /dev/null +++ b/projects/ROCKNIX/devices/SM8750/audio-topology/README.md @@ -0,0 +1,49 @@ +# SM8750 AudioReach topologies + +The q6apm sound card gets its DSP graph from a binary topology, requested as +`qcom/sm8750/-tplg.bin`. The blobs themselves live in the +`extra-firmware` repo under `SM8750/qcom/sm8750/`, one per board: + +| card model | board | +|----------------|------------------------| +| `SM8750-KONKR` | KONKR Pocket FIT Elite | + +Only the sources are kept here. The KONKR blob is also built into the kernel via +`CONFIG_EXTRA_FIRMWARE`, see the SM8750 block in +`projects/ROCKNIX/packages/linux/package.mk`; built-in firmware is searched +before the rootfs, so that copy wins. + +Changing a blob means a commit in `extra-firmware` and a `PKG_VERSION` bump in +`projects/ROCKNIX/packages/linux-firmware/extra-firmware/package.mk`. + +## Regenerating + +Sources are the `.m4` files here, built with Linaro's macro library: + +```sh +git clone https://git.codelinaro.org/linaro/qcomlt/audioreach-topology.git +cd audioreach-topology +m4 -I . /SM8750-KONKR.m4 > SM8750-KONKR.conf +alsatplg -c SM8750-KONKR.conf -o SM8750-KONKR-tplg.bin +``` + +`alsatplg -d -o ` decodes a blob back to text, so a regenerated +blob can be diffed against the shipped one before it goes in. + +Two things to know when diffing against pre-2026-08 blobs: the current macros +emit tokens 204/205 (`MODULE_IN_PORTS`/`MODULE_OUT_PORTS`, deprecated and +ignored by the kernel), and the decoder drops per-element `index` values, so a +decode/recompile round trip regroups the blocks. + +## Graph + +| stream | PCM | backend | UCM device | +|--------------|---------|---------------------|-------------| +| MultiMedia1 | hw:0,0 | SECONDARY_MI2S_RX | Speaker | +| MultiMedia2 | hw:0,1 | RX_CODEC_DMA_RX_0 | Headphones | +| MultiMedia3 | hw:0,2 | TX_CODEC_DMA_TX_3 | (capture) | +| MultiMedia4 | hw:0,3 | DISPLAY_PORT_RX_0 | HDMI | + +The board DTS needs a matching `dp-dai-link` (`q6apmbedai DISPLAY_PORT_RX_0` -> +`&mdss_dp0`) for the DP backend to bind, and that link is what makes the +machine driver register the `DP0 Jack` control the UCM HDMI device keys off. diff --git a/projects/ROCKNIX/devices/SM8750/audio-topology/SM8750-KONKR.m4 b/projects/ROCKNIX/devices/SM8750/audio-topology/SM8750-KONKR.m4 new file mode 100644 index 00000000000..9829fe50d4b --- /dev/null +++ b/projects/ROCKNIX/devices/SM8750/audio-topology/SM8750-KONKR.m4 @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: BSD-3-Clause +# AudioReach topology source for the KONKR Pocket FIT Elite (SM8750). +# +# Build with the macro library from +# https://git.codelinaro.org/linaro/qcomlt/audioreach-topology: +# +# m4 -I SM8750-KONKR.m4 > SM8750-KONKR.conf +# alsatplg -c SM8750-KONKR.conf -o SM8750-KONKR-tplg.bin +# +# Streams: MultiMedia1 = speakers, MultiMedia2 = headphones, +# MultiMedia3 = headset mic, MultiMedia4 = DisplayPort. PCM device numbers follow +# the stream index, so DisplayPort is hw:0,3 and that is what the UCM HDMI device +# opens. +# +# DisplayPort gets a stream of its own so the three outputs are three sinks in +# one card profile. Sharing the speaker PCM instead makes pipewire model them as +# alternative card profiles, and switching profiles tears down and rebuilds the +# sinks on signals that do not move in step with the cable, which strands the +# card on an unusable profile. Needs the DP driver to tolerate a prepare while +# the display is off (patch 0618). +# +# The Odin3 topology is the same with the I2S data line on SD0. +include(`audioreach/audioreach.m4') +include(`audioreach/stream-subgraph.m4') +include(`audioreach/device-subgraph.m4') +include(`util/route.m4') +include(`util/mixer.m4') +include(`audioreach/tokens.m4') +dnl Playback MultiMedia1 +STREAM_SG_PCM_ADD(audioreach/subgraph-stream-vol-playback.m4, FRONTEND_DAI_MULTIMEDIA1, + `S16_LE', 48000, 48000, 2, 2, + 0x00004001, 0x00004001, 0x00006001, `110000') +dnl Playback MultiMedia2 +STREAM_SG_PCM_ADD(audioreach/subgraph-stream-vol-playback.m4, FRONTEND_DAI_MULTIMEDIA2, + `S16_LE', 48000, 48000, 2, 2, + 0x00004002, 0x00004002, 0x00006010, `110000') +dnl Capture MultiMedia3 +STREAM_SG_PCM_ADD(audioreach/subgraph-stream-capture.m4, FRONTEND_DAI_MULTIMEDIA3, + `S16_LE', 48000, 48000, 1, 2, + 0x00004003, 0x00004003, 0x00006020, `110000') +dnl Playback MultiMedia4, feeds the DisplayPort backend only +STREAM_SG_PCM_ADD(audioreach/subgraph-stream-vol-playback.m4, FRONTEND_DAI_MULTIMEDIA4, + `S16_LE', 48000, 48000, 2, 2, + 0x00004004, 0x00004004, 0x00006030, `110000') +dnl Speaker amps: 2x AW88261 on SECONDARY MI2S. The populated amps are the +dnl stock quad-design's ch2/ch3, so the DSP has to drive data1 = SD1. +DEVICE_SG_ADD(audioreach/subgraph-device-i2s-playback.m4, `Secondary', SECONDARY_MI2S_RX, + `S16_LE', 48000, 48000, 2, 2, + LPAIF_INTF_TYPE_LPAIF, I2S_INTF_TYPE_SECONDARY, SD_LINE_IDX_I2S_SD1, DATA_FORMAT_FIXED_POINT, + 0x00004005, 0x00004005, 0x00006050, `SECONDARY_MI2S_RX') +dnl WCD939x playback (headphones) +DEVICE_SG_ADD(audioreach/subgraph-device-codec-dma-playback.m4, `RX_CODEC_DMA_RX_0', RX_CODEC_DMA_RX_0, + `S16_LE', 48000, 48000, 2, 2, + LPAIF_INTF_TYPE_RXTX, CODEC_INTF_IDX_RX0, 0, DATA_FORMAT_FIXED_POINT, + 0x00004007, 0x00004007, 0x00006070) +dnl WCD939x capture (headset mic) +DEVICE_SG_ADD(audioreach/subgraph-device-codec-dma-capture.m4, `TX_CODEC_DMA_TX_3', TX_CODEC_DMA_TX_3, + `S16_LE', 48000, 48000, 1, 2, + LPAIF_INTF_TYPE_RXTX, CODEC_INTF_IDX_TX3, 0, DATA_FORMAT_FIXED_POINT, + 0x00004009, 0x00004009, 0x00006090) +dnl DisplayPort over USB-C, fed from MultiMedia4. The DP sink module needs no +dnl interface index, the stream picks its DPTX from the dai id +dnl (DISPLAY_PORT_RX_0 = dai 104). +DEVICE_SG_ADD(audioreach/subgraph-device-display-port-playback.m4, `DISPLAY_PORT_RX_0', DISPLAY_PORT_RX_0, + `S16_LE', 48000, 48000, 2, 2, + 0, 0, 0, DATA_FORMAT_FIXED_POINT, + 0x00004008, 0x00004008, 0x00006080, `DISPLAY_PORT_RX_0') + +STREAM_DEVICE_PLAYBACK_MIXER(SECONDARY_MI2S_RX, ``SECONDARY_MI2S_RX'', ``MultiMedia1'', ``MultiMedia2'') +STREAM_DEVICE_PLAYBACK_MIXER(RX_CODEC_DMA_RX_0, ``RX_CODEC_DMA_RX_0'', ``MultiMedia1'', ``MultiMedia2'') +STREAM_DEVICE_PLAYBACK_MIXER(DISPLAY_PORT_RX_0, ``DISPLAY_PORT_RX_0'', ``MultiMedia4'') + +STREAM_DEVICE_PLAYBACK_ROUTE(SECONDARY_MI2S_RX, ``SECONDARY_MI2S_RX Audio Mixer'', ``MultiMedia1, stream0.logger1'', ``MultiMedia2, stream1.logger1'') +STREAM_DEVICE_PLAYBACK_ROUTE(RX_CODEC_DMA_RX_0, ``RX_CODEC_DMA_RX_0 Audio Mixer'', ``MultiMedia1, stream0.logger1'', ``MultiMedia2, stream1.logger1'') +STREAM_DEVICE_PLAYBACK_ROUTE(DISPLAY_PORT_RX_0, ``DISPLAY_PORT_RX_0 Audio Mixer'', ``MultiMedia4, stream3.logger1'') + +STREAM_DEVICE_CAPTURE_MIXER(FRONTEND_DAI_MULTIMEDIA3, ``TX_CODEC_DMA_TX_3'') +STREAM_DEVICE_CAPTURE_ROUTE(FRONTEND_DAI_MULTIMEDIA3, ``MultiMedia3 Mixer'', ``TX_CODEC_DMA_TX_3, device120.logger1'') diff --git a/projects/ROCKNIX/devices/SM8750/filesystem/usr/share/alsa/ucm2/KONKR/PocketFitElite/HiFi.conf b/projects/ROCKNIX/devices/SM8750/filesystem/usr/share/alsa/ucm2/KONKR/PocketFitElite/HiFi.conf deleted file mode 100644 index 3b7a0cc7464..00000000000 --- a/projects/ROCKNIX/devices/SM8750/filesystem/usr/share/alsa/ucm2/KONKR/PocketFitElite/HiFi.conf +++ /dev/null @@ -1,78 +0,0 @@ -# HiFi use case for the KONKR Pocket FIT Elite (SM8750) -# -# Two things differ from the AYN Odin3 profile this is derived from: -# -# * "Headphones" is defined once, on PlaybackPCM hw:${CardId},1 -- the -# WCD939x HPH path. (The Odin3 profile defines it twice, the second time -# on ,0, which is the MI2S/speaker PCM; ALSA keeps the last definition.) -# -# * The HPH path is switched to PCM (HiFi) mode, matching stock Android. In -# the default PDM mode the codec's legacy PDM receive path puts a constant -# hiss on the 3.5mm jack; in PCM mode the stream rides SoundWire port 9 as -# 384 kHz PCM and the codec runs its own interpolator/compander, which is -# silent. Needs device patches 0072 (lpass-rx-macro), 0073 (wcd939x) and -# 0074 (soundwire qcom PCM port format enable), plus qcom,pcm-ports-mask -# on &swr1 in the board DTS. -# -# Ordering matters: the HPH and COMP switches connect their SoundWire -# ports when set, so the PCM mode flags have to be in place before the -# wcd939x enable sequence brings those switches up -- hence the explicit -# sequence here rather than only the shared includes. - -SectionVerb { - EnableSequence [ - cset "name='SECONDARY_MI2S_RX Audio Mixer MultiMedia1' 1" - cset "name='RX_CODEC_DMA_RX_0 Audio Mixer MultiMedia2' 1" - cset "name='MultiMedia3 Mixer TX_CODEC_DMA_TX_3' 1" - ] - - Include.wcde.File "/codecs/wcd939x/DefaultEnableSeq.conf" - - Value { - TQ "HiFi" - } -} - -SectionDevice."Speaker" { - Comment "Speaker playback" - - Value { - PlaybackChannels 2 - PlaybackPriority 100 - PlaybackPCM "hw:${CardId},0" - PlaybackMixer "default:${CardId}" - } -} - -SectionDevice."Headphones" { - Comment "Headphones playback" - - # rx-macro routing first, then the PCM mode flags, then the wcd939x - # bring-up (which is what actually connects the HPH SoundWire ports). - Include.rxmhpe.File "/codecs/qcom-lpass/rx-macro/HeadphoneEnableSeq.conf" - - EnableSequence [ - cset "name='HPH PCM Switch' 1" - cset "name='RX_HPH PCM Switch' 1" - ] - - Include.wcdhpe.File "/codecs/wcd939x/HeadphoneEnableSeq.conf" - - Include.wcdhpd.File "/codecs/wcd939x/HeadphoneDisableSeq.conf" - Include.rxmhpd.File "/codecs/qcom-lpass/rx-macro/HeadphoneDisableSeq.conf" - - DisableSequence [ - cset "name='HPH PCM Switch' 0" - cset "name='RX_HPH PCM Switch' 0" - ] - - Value { - PlaybackChannels 2 - PlaybackPriority 200 - PlaybackPCM "hw:${CardId},1" - PlaybackMixer "default:${CardId}" - PlaybackMixerElem "HP Digital" - JackControl "Headphone Jack" - JackHWMute "Speaker" - } -} diff --git a/projects/ROCKNIX/devices/SM8750/filesystem/usr/share/alsa/ucm2/KONKR/PocketFitElite/KONKR-PocketFitElite.conf b/projects/ROCKNIX/devices/SM8750/filesystem/usr/share/alsa/ucm2/KONKR/PocketFitElite/KONKR-PocketFitElite.conf deleted file mode 100644 index e8431cd4002..00000000000 --- a/projects/ROCKNIX/devices/SM8750/filesystem/usr/share/alsa/ucm2/KONKR/PocketFitElite/KONKR-PocketFitElite.conf +++ /dev/null @@ -1,33 +0,0 @@ -# Use case configuration for the KONKR Pocket FIT Elite (SM8750) -# -# Derived from the AYN Odin3 profile (same SoC, same WCD939x codec); the -# card-level setup is identical, so only HiFi.conf diverges. - -Syntax 4 - -SectionUseCase."HiFi" { - File "/KONKR/PocketFitElite/HiFi.conf" - Comment "HiFi quality Music." -} - -BootSequence [ - cset "name='RX_RX0 Digital Volume' 84" - cset "name='RX_RX1 Digital Volume' 84" - cset "name='HPHL Volume' 20" - cset "name='HPHR Volume' 20" - cset "name='ADC2 Volume' 10" -] - -LibraryConfig.remap.Config { - - ctl.default.map { - "name='HP Volume'" { - "name='HPHL Volume'".vindex.0 0 - "name='HPHR Volume'".vindex.1 0 - } - } -} - -Include.card-init.File "/lib/card-init.conf" -Include.ctl-remap.File "/lib/ctl-remap.conf" -Include.wcd-init.File "/codecs/wcd939x/init.conf" diff --git a/projects/ROCKNIX/devices/SM8750/filesystem/usr/share/alsa/ucm2/conf.d/sm8750/SM8750-KONKR.conf b/projects/ROCKNIX/devices/SM8750/filesystem/usr/share/alsa/ucm2/conf.d/sm8750/SM8750-KONKR.conf deleted file mode 120000 index a65165e2475..00000000000 --- a/projects/ROCKNIX/devices/SM8750/filesystem/usr/share/alsa/ucm2/conf.d/sm8750/SM8750-KONKR.conf +++ /dev/null @@ -1 +0,0 @@ -../../KONKR/PocketFitElite/KONKR-PocketFitElite.conf \ No newline at end of file diff --git a/projects/ROCKNIX/devices/SM8750/linux/dts/qcom/sm8750-konkr-pf-elite.dts b/projects/ROCKNIX/devices/SM8750/linux/dts/qcom/sm8750-konkr-pf-elite.dts index eba9f434318..b283dfd7fdb 100644 --- a/projects/ROCKNIX/devices/SM8750/linux/dts/qcom/sm8750-konkr-pf-elite.dts +++ b/projects/ROCKNIX/devices/SM8750/linux/dts/qcom/sm8750-konkr-pf-elite.dts @@ -1517,6 +1517,19 @@ cpu { sound-dai = <&q6apmbedai TX_CODEC_DMA_TX_3>; }; platform { sound-dai = <&q6apm>; }; }; + + /* HDMI audio out over USB-C DP alt mode. The codec side is the + * hdmi-codec the DP bridge registers as a child of &mdss_dp0, and + * this link is also what makes the machine driver create the + * "DP0 Jack" control that UCM keys the HDMI device off. + * Needs the DISPLAY_PORT_RX_0 graph in the topology blob, see + * devices/SM8750/audio-topology/. */ + dp-dai-link { + link-name = "DisplayPort Playback"; + codec { sound-dai = <&mdss_dp0>; }; + cpu { sound-dai = <&q6apmbedai DISPLAY_PORT_RX_0>; }; + platform { sound-dai = <&q6apm>; }; + }; }; wcn7860-pmu { diff --git a/projects/ROCKNIX/devices/SM8750/patches/linux/0612-ROCKNIX-odin3-q6apm-start-mi2s-port-at-prepare.patch b/projects/ROCKNIX/devices/SM8750/patches/linux/0612-ROCKNIX-odin3-q6apm-start-mi2s-port-at-prepare.patch index 57087b0fbc0..5667e81d6e4 100644 --- a/projects/ROCKNIX/devices/SM8750/patches/linux/0612-ROCKNIX-odin3-q6apm-start-mi2s-port-at-prepare.patch +++ b/projects/ROCKNIX/devices/SM8750/patches/linux/0612-ROCKNIX-odin3-q6apm-start-mi2s-port-at-prepare.patch @@ -1,33 +1,53 @@ -Subject: [PATCH] ASoC: qdsp6: q6apm-lpass: start RX port at prepare +Subject: [PATCH] ASoC: qdsp6: q6apm-lpass: start MI2S RX port at prepare Port start moved from .prepare to .trigger, so the MI2S bit-clock now -starts after the codec DAPM widgets power up. The Odin3 aw88166 amps -check their PLL against BCLK at DAPM PRE_PMU, before the trigger, and -fail PLL lock with no clock, leaving the speakers silent. +starts after the codec DAPM widgets power up. The Odin3 aw88166 and the +KONKR aw88261 amps check their PLL against BCLK at DAPM PRE_PMU, before +the trigger, and fail PLL lock with no clock, leaving the speakers silent. Start the playback port at prepare again so BCLK is up before PRE_PMU. The trigger's !is_port_started guard no-ops; capture is unchanged. + +MI2S ports only. Starting the DisplayPort endpoint this early makes the +DSP reject APM_CMD_GRAPH_START: the DP controller only enables its audio +path from the codec dai's prepare, which runs after this one. --- --- a/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c +++ b/sound/soc/qcom/qdsp6/q6apm-lpass-dais.c -@@ -224,6 +224,20 @@ +@@ -224,6 +224,36 @@ dev_err(dai->dev, "Failed to prepare Graph %d\n", rc); goto err; } + + /* -+ * aw88166 checks its PLL against BCLK at DAPM PRE_PMU, before the -+ * PCM trigger; start the port here so BCLK is up in time. The -+ * trigger's !is_port_started guard then no-ops. Playback only. ++ * aw88166/aw88261 check their PLL against BCLK at DAPM PRE_PMU, before ++ * the PCM trigger, so the MI2S port has to be running by then. Start it ++ * here and let the trigger's !is_port_started guard no-op. ++ * ++ * MI2S only. The DisplayPort endpoint must not start this early: the DP ++ * controller's audio path is enabled from the codec dai's prepare, which ++ * runs after this one, and the DSP rejects APM_CMD_GRAPH_START on a DP ++ * port whose audio path is still off. Capture is unchanged. + */ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { -+ rc = q6apm_graph_start(dai_data->graph[dai->id]); -+ if (rc < 0) { -+ dev_err(dai->dev, "Failed to start APM port %d\n", dai->id); -+ goto err; ++ switch (dai->id) { ++ case PRIMARY_MI2S_RX: ++ case SECONDARY_MI2S_RX: ++ case TERTIARY_MI2S_RX: ++ case QUATERNARY_MI2S_RX: ++ case QUINARY_MI2S_RX: ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ++ rc = q6apm_graph_start(dai_data->graph[dai->id]); ++ if (rc < 0) { ++ dev_err(dai->dev, "Failed to start APM port %d\n", dai->id); ++ goto err; ++ } ++ dai_data->is_port_started[dai->id] = true; + } -+ dai_data->is_port_started[dai->id] = true; ++ break; ++ default: ++ break; + } ++ return 0; err: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { diff --git a/projects/ROCKNIX/devices/SM8750/patches/linux/0618-drm-msm-dp-dont-fail-audio-prepare-when-display-off.patch b/projects/ROCKNIX/devices/SM8750/patches/linux/0618-drm-msm-dp-dont-fail-audio-prepare-when-display-off.patch new file mode 100644 index 00000000000..5806b6cba2b --- /dev/null +++ b/projects/ROCKNIX/devices/SM8750/patches/linux/0618-drm-msm-dp-dont-fail-audio-prepare-when-display-off.patch @@ -0,0 +1,39 @@ +Subject: [PATCH] drm/msm/dp: don't fail audio prepare while the display is off + +msm_dp_audio_prepare() refuses with -EINVAL when the DP display is not +powered on, to avoid unclocked access to the DP block. Skipping the setup +is right, returning an error is not: userspace prepares the DisplayPort +PCM to find out what it supports long before anything is plugged in +(pipewire does it for every UCM device while it builds the card), and one +failure there makes it discard the whole card profile, so the machine +loses its speaker and headphone sinks too. + +Skip the programming as before and return success. Nothing is touched and +no link is up, so the stream goes nowhere until the display is enabled. + +--- a/drivers/gpu/drm/msm/dp/dp_audio.c ++++ b/drivers/gpu/drm/msm/dp/dp_audio.c +@@ -281,13 +281,18 @@ + * before OR even when DP is not connected . This can cause + * unclocked access as the audio subsystem relies on the DP + * driver to maintain the correct state of clocks. To protect +- * such cases check for connection status and bail out if not +- * connected. ++ * such cases check for connection status and skip the setup if ++ * not connected. ++ * ++ * Don't report an error for it. Userspace prepares this PCM to ++ * find out what it can do long before anything is plugged in ++ * (pipewire does it for every UCM device while it builds the ++ * card), and failing that makes it drop the whole card profile, ++ * taking the speakers down with it. Nothing is programmed here ++ * and no link is up, so the stream simply goes nowhere. + */ +- if (!msm_dp_display->power_on) { +- rc = -EINVAL; ++ if (!msm_dp_display->power_on) + goto end; +- } + + audio = msm_dp_audio_get_data(msm_dp_display); + if (IS_ERR(audio)) { diff --git a/projects/ROCKNIX/packages/audio/alsa-ucm-conf/patches/SM8750/0003_SM8750-KONKR-PocketFitElite.patch b/projects/ROCKNIX/packages/audio/alsa-ucm-conf/patches/SM8750/0003_SM8750-KONKR-PocketFitElite.patch new file mode 100644 index 00000000000..aa0c229204f --- /dev/null +++ b/projects/ROCKNIX/packages/audio/alsa-ucm-conf/patches/SM8750/0003_SM8750-KONKR-PocketFitElite.patch @@ -0,0 +1,164 @@ +diff --git a/ucm2/KONKR/PocketFitElite/KONKR-PocketFitElite.conf b/ucm2/KONKR/PocketFitElite/KONKR-PocketFitElite.conf +new file mode 100644 +--- /dev/null ++++ b/ucm2/KONKR/PocketFitElite/KONKR-PocketFitElite.conf +@@ -0,0 +1,33 @@ ++# Use case configuration for the KONKR Pocket FIT Elite (SM8750) ++# ++# Derived from the AYN Odin3 profile (same SoC, same WCD939x codec); the ++# card-level setup is identical, so only HiFi.conf diverges. ++ ++Syntax 4 ++ ++SectionUseCase."HiFi" { ++ File "/KONKR/PocketFitElite/HiFi.conf" ++ Comment "HiFi quality Music." ++} ++ ++BootSequence [ ++ cset "name='RX_RX0 Digital Volume' 84" ++ cset "name='RX_RX1 Digital Volume' 84" ++ cset "name='HPHL Volume' 20" ++ cset "name='HPHR Volume' 20" ++ cset "name='ADC2 Volume' 10" ++] ++ ++LibraryConfig.remap.Config { ++ ++ ctl.default.map { ++ "name='HP Volume'" { ++ "name='HPHL Volume'".vindex.0 0 ++ "name='HPHR Volume'".vindex.1 0 ++ } ++ } ++} ++ ++Include.card-init.File "/lib/card-init.conf" ++Include.ctl-remap.File "/lib/ctl-remap.conf" ++Include.wcd-init.File "/codecs/wcd939x/init.conf" +diff --git a/ucm2/KONKR/PocketFitElite/HiFi.conf b/ucm2/KONKR/PocketFitElite/HiFi.conf +new file mode 100644 +--- /dev/null ++++ b/ucm2/KONKR/PocketFitElite/HiFi.conf +@@ -0,0 +1,114 @@ ++# HiFi use case for the KONKR Pocket FIT Elite (SM8750) ++# ++# Two things differ from the AYN Odin3 profile this is derived from: ++# ++# * "Headphones" is defined once, on PlaybackPCM hw:${CardId},1 -- the ++# WCD939x HPH path. (The Odin3 profile defines it twice, the second time ++# on ,0, which is the MI2S/speaker PCM; ALSA keeps the last definition.) ++# ++# * The HPH path is switched to PCM (HiFi) mode, matching stock Android. In ++# the default PDM mode the codec's legacy PDM receive path puts a constant ++# hiss on the 3.5mm jack; in PCM mode the stream rides SoundWire port 9 as ++# 384 kHz PCM and the codec runs its own interpolator/compander, which is ++# silent. Needs device patches 0072 (lpass-rx-macro), 0073 (wcd939x) and ++# 0074 (soundwire qcom PCM port format enable), plus qcom,pcm-ports-mask ++# on &swr1 in the board DTS. ++# ++# Ordering matters: the HPH and COMP switches connect their SoundWire ++# ports when set, so the PCM mode flags have to be in place before the ++# wcd939x enable sequence brings those switches up -- hence the explicit ++# sequence here rather than only the shared includes. ++ ++SectionVerb { ++ EnableSequence [ ++ cset "name='SECONDARY_MI2S_RX Audio Mixer MultiMedia1' 1" ++ cset "name='RX_CODEC_DMA_RX_0 Audio Mixer MultiMedia2' 1" ++ cset "name='MultiMedia3 Mixer TX_CODEC_DMA_TX_3' 1" ++ cset "name='DISPLAY_PORT_RX_0 Audio Mixer MultiMedia4' 1" ++ ] ++ ++ Include.wcde.File "/codecs/wcd939x/DefaultEnableSeq.conf" ++ ++ Value { ++ TQ "HiFi" ++ } ++} ++ ++SectionDevice."Speaker" { ++ Comment "Speaker playback" ++ ++ Value { ++ PlaybackChannels 2 ++ PlaybackPriority 100 ++ PlaybackPCM "hw:${CardId},0" ++ PlaybackMixer "default:${CardId}" ++ } ++} ++ ++SectionDevice."Headphones" { ++ Comment "Headphones playback" ++ ++ # rx-macro routing first, then the PCM mode flags, then the wcd939x ++ # bring-up (which is what actually connects the HPH SoundWire ports). ++ Include.rxmhpe.File "/codecs/qcom-lpass/rx-macro/HeadphoneEnableSeq.conf" ++ ++ EnableSequence [ ++ cset "name='HPH PCM Switch' 1" ++ cset "name='RX_HPH PCM Switch' 1" ++ ] ++ ++ Include.wcdhpe.File "/codecs/wcd939x/HeadphoneEnableSeq.conf" ++ ++ Include.wcdhpd.File "/codecs/wcd939x/HeadphoneDisableSeq.conf" ++ Include.rxmhpd.File "/codecs/qcom-lpass/rx-macro/HeadphoneDisableSeq.conf" ++ ++ DisableSequence [ ++ cset "name='HPH PCM Switch' 0" ++ cset "name='RX_HPH PCM Switch' 0" ++ ] ++ ++ Value { ++ PlaybackChannels 2 ++ PlaybackPriority 200 ++ PlaybackPCM "hw:${CardId},1" ++ PlaybackMixer "default:${CardId}" ++ PlaybackMixerElem "HP Digital" ++ JackControl "Headphone Jack" ++ JackHWMute "Speaker HDMI" ++ } ++} ++ ++# HDMI/DisplayPort out over USB-C on its own PCM, so the three outputs are three ++# sinks in one card profile and switching between them is just a default-sink ++# change. Sharing the speaker PCM instead makes pipewire model them as ++# alternative card profiles: switching then destroys and rebuilds sinks, driven ++# by availability that lags the cable, and the card gets stranded on a profile it ++# reports as unavailable with nothing playing. ++# ++# The verb attaches MultiMedia4 to the DisplayPort backend once and leaves it ++# there, and kernel patch 0618 lets that PCM be prepared while the display is ++# off. Both are needed: pipewire opens AND prepares the PCM of every device while ++# it builds the card, an unattached backend fails that open ("no backend DAIs ++# enabled") and the old prepare refused outright with the display off, and either ++# failure costs the whole profile, speakers included. Playing to this sink with no ++# display attached is harmless, the DSP just refuses to start the port. ++# ++# The JackHWMute lines are what give the output order, not PlaybackPriority. ++# Wireplumber picks the default sink by node priority, and its alsa monitor ++# derives that from the PCM device number alone (dev 0 = 1000, then 744 - 16*dev), ++# so the speakers on hw:,0 outrank everything and PlaybackPriority never enters ++# into it. What it does honour is availability, so each output marks the ones it ++# should beat as unavailable: headphones mute Speaker and HDMI, HDMI mutes ++# Speaker. That gives headphones > HDMI > speakers in every combination. ++SectionDevice."HDMI" { ++ Comment "HDMI / DisplayPort playback" ++ ++ Value { ++ PlaybackChannels 2 ++ PlaybackPriority 150 ++ PlaybackPCM "hw:${CardId},3" ++ PlaybackMixer "default:${CardId}" ++ JackControl "DP0 Jack" ++ JackHWMute "Speaker" ++ } ++} +diff --git a/ucm2/conf.d/sm8750/SM8750-KONKR.conf b/ucm2/conf.d/sm8750/SM8750-KONKR.conf +new file mode 120000 +--- /dev/null ++++ b/ucm2/conf.d/sm8750/SM8750-KONKR.conf +@@ -0,0 +1 @@ ++../../KONKR/PocketFitElite/KONKR-PocketFitElite.conf +\ No newline at end of file diff --git a/projects/ROCKNIX/packages/linux-firmware/extra-firmware/package.mk b/projects/ROCKNIX/packages/linux-firmware/extra-firmware/package.mk index 1f9985974c4..db9a0235e3b 100644 --- a/projects/ROCKNIX/packages/linux-firmware/extra-firmware/package.mk +++ b/projects/ROCKNIX/packages/linux-firmware/extra-firmware/package.mk @@ -2,10 +2,13 @@ # Copyright (C) 2024-present ROCKNIX (https://github.com/ROCKNIX) PKG_NAME="extra-firmware" -PKG_VERSION="2b7207cfcb80c53c09dc6e04165789ecaf2d3348" +PKG_VERSION="5a628dba2ff27b692194237eee8ba3730fdbf98a" PKG_LICENSE="proprietary" PKG_SITE="https://github.com/ROCKNIX/extra-firmware" -PKG_URL="https://github.com/ROCKNIX/extra-firmware/archive/${PKG_VERSION}.tar.gz" +# XXX points at slaide/extra-firmware branch sm8750-konkr-dp-audio for the +# KONKR topology with the DisplayPort graph. Repoint at ROCKNIX/extra-firmware +# once https://github.com/ROCKNIX/extra-firmware PR is merged. +PKG_URL="https://github.com/slaide/extra-firmware/archive/${PKG_VERSION}.tar.gz" PKG_LONGDESC="extra-firmware: Extra kernel firmware needed for ROCKNIX devices" PKG_TOOLCHAIN="manual" diff --git a/projects/ROCKNIX/packages/linux/package.mk b/projects/ROCKNIX/packages/linux/package.mk index a452da02873..c1647e736df 100644 --- a/projects/ROCKNIX/packages/linux/package.mk +++ b/projects/ROCKNIX/packages/linux/package.mk @@ -269,10 +269,11 @@ pre_make_target() { mkdir -p ${PKG_BUILD}/external-firmware/qcom/sm8750/konkr/pfe cp -Lv $(get_build_dir extra-firmware)/SM8750/qcom/sm8750/konkr/pfe/aw88261_acf.bin ${PKG_BUILD}/external-firmware/qcom/sm8750/konkr/pfe - # KONKR Pocket FIT Elite: QUAT-MI2S audio topology (the AYN tplg with its - # MI2S backend retargeted SECONDARY->QUATERNARY — the konkr's speaker amps - # are on QUATERNARY MI2S). Built-in firmware is searched before the rootfs, - # so this also overrides any stale copy in the SYSTEM overlay. + # KONKR Pocket FIT Elite: AudioReach topology (SEC MI2S on SD1 for the amps, + # codec DMA for the headphones, DISPLAY_PORT_RX_0 for HDMI audio). The m4 + # source and regen recipe live in devices/SM8750/audio-topology/. Built-in + # firmware is searched before the rootfs, so this also overrides any stale + # copy in the SYSTEM overlay. cp -Lv $(get_build_dir extra-firmware)/SM8750/qcom/sm8750/SM8750-KONKR-tplg.bin ${PKG_BUILD}/external-firmware/qcom/sm8750 FW_LIST="$(find ${PKG_BUILD}/external-firmware -type f | sed 's|.*external-firmware/||' | sort | xargs)"