From 76e10781fcc16a3fd8dfd0278ad9dc307ed29871 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Thu, 16 Jul 2026 15:49:39 +0200 Subject: [PATCH] audioreach: MILOS-Fairphone-Gen6: working speaker playback + WCD9378 capture Rework the WIP Fairphone (Gen. 6) topology into the state tested on the phone (postmarketOS, self-built 7.1.2 milos kernel): - Rename the backend to SEN_MI2S_RX to match the DAI name the kernel exposes; with SENARY_MI2S_RX the tplg backend never binds. - Route playback through a new i2s-playback-mfc device subgraph that inserts an MFC between the logger and the I2S endpoint: the frontend stream is S16 while the AW88261 boost converter needs 32-bit slots (3.072 MHz BCLK), so the DSP must convert formats on the way out. - Add the capture path for the WCD9378 mics: MultiMedia2 capture stream subgraph, TX_CODEC_DMA_TX_3 device subgraph (RXTX CDC-DMA TX3), and the capture mixer/routes. Note: the CMake entry emits qcom/milos/MILOS-Fairphone-Gen6-tplg.bin, but the kernel requests qcom//-tplg.bin, i.e. "qcom/milos/Fairphone (Gen. 6)-tplg.bin" - install it under that name (CMake target names cannot contain the spaces/parens of the card name). Assisted-by: Claude:claude-fable-5 Signed-off-by: Jorijn van der Graaf --- MILOS-Fairphone-Gen6.m4 | 62 ++++++++++++++-- .../subgraph-device-i2s-playback-mfc.m4 | 70 +++++++++++++++++++ 2 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 audioreach/subgraph-device-i2s-playback-mfc.m4 diff --git a/MILOS-Fairphone-Gen6.m4 b/MILOS-Fairphone-Gen6.m4 index cfd28fd..f28b887 100644 --- a/MILOS-Fairphone-Gen6.m4 +++ b/MILOS-Fairphone-Gen6.m4 @@ -1,19 +1,71 @@ +# Copyright, Linaro Ltd, 2026 # SPDX-License-Identifier: BSD-3-Clause +# +# Fairphone (Gen. 6) — SM7635 "Milos" +# Speaker path: 2x Awinic AW88261 on Senary MI2S (LPASS LPI I2S2). +# The DSP addresses this interface as the WSA LPAIF block's primary I2S +# (downstream PAL backend "MI2S-LPAIF_WSA-RX-PRIMARY"), hence +# LPAIF_INTF_TYPE_WSA + I2S_INTF_TYPE_PRIMARY below. +# 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 +dnl Senary MI2S BE DAI id (dt-bindings qcom,q6dsp-lpass-ports.h, v7.2+); +dnl not yet in audioreach.m4 +define(`SENARY_MI2S_RX', `147') dnl +dnl +# +# Stream SubGraph for MultiMedia1 Playback +# +# ______________________________________________ +# | Sub Graph 1 | +# | [WR_SH] -> [PCM DEC] -> [PCM CONV] -> [LOG] |- Kcontrol +# |______________________________________________| +# 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 Senary MI2S Playback -DEVICE_SG_ADD(audioreach/subgraph-device-i2s-playback.m4, `Senary', SENARY_MI2S_RX, +dnl +dnl Capture MultiMedia2 (WCD9378 mics) +STREAM_SG_PCM_ADD(audioreach/subgraph-stream-capture.m4, FRONTEND_DAI_MULTIMEDIA2, + `S16_LE', 48000, 48000, 1, 2, + 0x00004002, 0x00004002, 0x00006020, `110000') +dnl +# +# Device SubGraph for Senary MI2S RX Backend (stereo AW88261) +# +# ___________________ +# | Sub Graph 2 | +# Mixer -| [LOG] -> [I2S EP] | +# |___________________| +# +dnl Senary MI2S Playback (32-bit slots: AW88261 boost needs 3.072 MHz BCLK) +DEVICE_SG_ADD(audioreach/subgraph-device-i2s-playback-mfc.m4, `Senary', SENARY_MI2S_RX, `S32_LE', 48000, 48000, 2, 2, LPAIF_INTF_TYPE_WSA, I2S_INTF_TYPE_PRIMARY, SD_LINE_IDX_I2S_SD0, DATA_FORMAT_FIXED_POINT, - 0x00004005, 0x00004005, 0x00006050, `SENARY_MI2S_RX') + 0x00004006, 0x00004006, 0x00006060, `SEN_MI2S_RX') -STREAM_DEVICE_PLAYBACK_MIXER(SENARY_MI2S_RX, ``SENARY_MI2S_RX'', ``MultiMedia1'') -STREAM_DEVICE_PLAYBACK_ROUTE(SENARY_MI2S_RX, ``SENARY_MI2S_RX Audio Mixer'', ``MultiMedia1, stream0.logger1'') +# +# Device SubGraph for the WCD9378 TX (mic capture) Backend +# +# _____________________ +# | Sub Graph 3 | +# Mixer -| [CDC-DMA EP] -> [LOG] | +# |_____________________| +# +dnl WCDTX Capture (TX macro decimators via RXTX LPAIF TX3 CDC-DMA) +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, + 0x00004008, 0x00004008, 0x00006130) + +STREAM_DEVICE_PLAYBACK_MIXER(SENARY_MI2S_RX, ``SEN_MI2S_RX'', ``MultiMedia1'') +STREAM_DEVICE_PLAYBACK_ROUTE(SENARY_MI2S_RX, ``SEN_MI2S_RX Audio Mixer'', ``MultiMedia1, stream0.logger1'') + +STREAM_DEVICE_CAPTURE_MIXER(FRONTEND_DAI_MULTIMEDIA2, ``TX_CODEC_DMA_TX_3'') +STREAM_DEVICE_CAPTURE_ROUTE(FRONTEND_DAI_MULTIMEDIA2, ``MultiMedia2 Mixer'', ``TX_CODEC_DMA_TX_3, device120.logger1'') diff --git a/audioreach/subgraph-device-i2s-playback-mfc.m4 b/audioreach/subgraph-device-i2s-playback-mfc.m4 new file mode 100644 index 0000000..8e9b195 --- /dev/null +++ b/audioreach/subgraph-device-i2s-playback-mfc.m4 @@ -0,0 +1,70 @@ +# Copyright, Linaro Ltd, 2026 +# SPDX-License-Identifier: BSD-3-Clause +include(`audioreach/audioreach.m4') dnl +include(`util/pcm.m4') dnl +include(`audioreach/subgraph.m4') dnl +include(`audioreach/container.m4') dnl +include(`audioreach/module_mfc.m4') dnl +include(`audioreach/module_log.m4') dnl +include(`audioreach/module_i2s.m4') dnl +include(`util/mixer.m4') dnl +dnl +# +# SubGraph for Device Backend (with MFC for stream->device format conversion) +# +# _____________________________ +# | Sub Graph | +# | [LOG] -> [MFC] -> [I2S EP] | +# |_____________________________| + +undefine(`LOG_MODULE_IID') dnl +undefine(`MFC_MODULE_IID') dnl +undefine(`I2S_MODULE_IID') dnl +undefine(`SG_INDEX') dnl +undefine(`CONTAINER_INDEX') dnl +undefine(`MOD_INDEX') dnl + +undefine(`DEVICE_PERF_MODE') dnl +undefine(`DEVICE_DIRECTION') dnl +undefine(`CONT_SENARIO_ID') dnl +undefine(`CONT_CAP') dnl +undefine(`CONT_POSITION') dnl +undefine(`DEVICE_DOMAIN_ID') dnl +undefine(`CONT_STACK_SIZE') dnl + +define(`DEVICE_PERF_MODE', APM_SG_PERF_MODE_LOW_LATENCY) dnl' +define(`DEVICE_DIRECTION', APM_SUB_GRAPH_DIRECTION_TX) dnl' +define(`CONT_SENARIO_ID', APM_SUB_GRAPH_SID_AUDIO_PLAYBACK) dnl' +define(`CONT_CAP', `ifelse(LPASS_VER_COMPAT, 110000, APM_CONTAINER_TYPE_ID_GC, APM_CONTAINER_CAP_ID_EP)') dnl' +define(`CONT_POSITION', APM_CONT_GRAPH_POS_STREAM)dnl' +define(`DEVICE_DOMAIN_ID', APM_PROC_DOMAIN_ID_ADSP) dnl' +define(`CONT_STACK_SIZE', 8192) dnl' +dnl +define(`LOG_MODULE_IID', MOD_IID_START) dnl +define(`MFC_MODULE_IID', eval(MOD_IID_START + 1)) dnl +define(`I2S_MODULE_IID', eval(MOD_IID_START + 2)) dnl +define(`SG_INDEX', 1) dnl +define(`CONTAINER_INDEX', 1) dnl +define(`MOD_INDEX', 1) dnl +dnl +dnl DEVICE_PLAYBACK_ROUTE(stream-index, dai-id, mixer-prefix) +define(`DEVICE_PLAYBACK_ROUTE', +`' +`SectionGraph."NAME_PREFIX.$1 $3 Graph" {' +` index STR($1)' +` lines [' +` "NAME_PREFIX.logger$1, , $3 Audio Mixer"' +` "NAME_PREFIX.mfc$1, , NAME_PREFIX.logger$1"' +` "NAME_PREFIX.i2s_rx$1, , NAME_PREFIX.mfc$1"' +` "$2 MI2S Playback, , NAME_PREFIX.i2s_rx$1"' +` ]' +`}') + + +AR_SUBGRAPH(SG_INDEX, DEVICE_DAI_ID, SG_IID_START, DEVICE_PERF_MODE, DEVICE_DIRECTION, CONT_SENARIO_ID) +AR_CONTAINER(CONTAINER_INDEX, CONT_IID_START, CONT_CAP, CONT_STACK_SIZE, CONT_POSITION, DEVICE_DOMAIN_ID) + +AR_MODULE_LOG(MOD_INDEX, SG_INDEX, CONTAINER_INDEX, LOG_MODULE_IID, 1, 1, 1, 2, 0x000019ab, 1, 0, MFC_MODULE_IID) +AR_MODULE_MFC(MOD_INDEX, SG_INDEX, CONTAINER_INDEX, MFC_MODULE_IID, 1, 1, 1, 2, I2S_MODULE_IID) +AR_MODULE_I2S_RX(MOD_INDEX, SG_INDEX, CONTAINER_INDEX, I2S_MODULE_IID, 1, 0, 1, 0, DEVICE_INTF_TYPE, DEVICE_INTF_INDEX, DEVICE_DATA_FORMAT, DEVICE_SD_LINE_IDX, `DEVICE_NAME', NONE_IID) +DEVICE_PLAYBACK_ROUTE(MOD_INDEX, `DEVICE_NAME', `MIXER_PREFIX')