Skip to content

Commit

Permalink
topology: sof-adl-max98357a-rt5682-waves-2way: add new topology
Browse files Browse the repository at this point in the history
Add support for four max98357a speaker amplifiers running in TDM mode
which format is 8 slots with 32 bit slot/sample width on ADL boards.

To implement the 2-way woofer/tweeter speaker function in SOF, there is a demux
to create 2 streams for the branched pipelines. A Waves-codec widget is applied
before the demux for audio quality enhancement, and the other Waves-codec
widgets are located one per branch for EQ/DRC including band-split filters of
Woofer and Tweeter.

There is a mux before DAI to merge the branched Woofer and Tweeter streams into
one 4-channel stream which is fed into DAI then.

The formation of this split-and-merge pipeline is a bit tricky. The topology
graph is as following:

host PCM0 -> WAVES -> DEMUX -> WAVES ---+                         <PIPE#9>
                          |             |
                          +--> WAVES -> MUX -> DAI (Speaker SSP)  <PIPE#1>

There are two pipelines with ID #1 and #9, where PIPE#9 is set DAI#1 as the
scheduled component to make them being scheduled together. They are connected
via DEMUX#9 and MUX#1. The priority of PIPE#9 should be higher than PIPE#1 to
assure PIPE#9 is scheduled first (PCM should be the first component for the
copy process).

Moreover, the commit of mux_params() modification is required to support the
split-and-merge pipeline design.

Signed-off-by: Pin-chih Lin <[email protected]>
  • Loading branch information
johnylin76 committed Jan 25, 2022
1 parent 6c8a7c4 commit f826390
Show file tree
Hide file tree
Showing 4 changed files with 421 additions and 12 deletions.
1 change: 1 addition & 0 deletions tools/topology/topology1/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ set(TPLGS
"sof-ehl-rt5660\;sof-ehl-rt5660-nohdmi"
"sof-tgl-max98357a-rt5682\;sof-tgl-max98357a-rt5682\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=tgl\;-DAMP_SSP=1"
"sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=adl\;-DAMP_SSP=2"
"sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-waves-2way\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DAMP_SSP=2\;-DWAVES\;-D2CH_2WAY"
"sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-rtnr\;-DCODEC=MAX98357A\;-DFMT=s16le\;-DPLATFORM=adl\;-DAMP_SSP=2\;-DCHANNELS=2\;-DRTNR"
"sof-tgl-max98357a-rt5682\;sof-adl-max98357a-rt5682-4ch\;-DCODEC=MAX98360A_TDM\;-DFMT=s32le\;-DPLATFORM=adl\;-DAMP_SSP=2\;-D4CH_PASSTHROUGH"
"sof-tgl-max98357a-rt5682\;sof-adl-max98360a-rt5682\;-DCODEC=MAX98360A\;-DFMT=s32le\;-DPLATFORM=adl\;-DAMP_SSP=1"
Expand Down
94 changes: 82 additions & 12 deletions tools/topology/topology1/sof-tgl-max98357a-rt5682.m4
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,47 @@ define(matrix3, `ROUTE_MATRIX(1,
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)')')

define(matrix4, `ROUTE_MATRIX(1,
`BITS_TO_BYTE(0, 0, 1 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,1 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)')')

define(matrix5, `ROUTE_MATRIX(9,
`BITS_TO_BYTE(1, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 1, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)',
`BITS_TO_BYTE(0, 0, 0 ,0 ,0 ,0 ,0 ,0)')')

dnl name, num_streams, route_matrix list
ifdef(`NO_AMP',`',`
ifdef(`2CH_2WAY',
`MUXDEMUX_CONFIG(demux_priv_1, 1, LIST_NONEWLINE(`', `matrix3'))',
`MUXDEMUX_CONFIG(demux_priv_1, 2, LIST_NONEWLINE(`', `matrix1,', `matrix2'))')')
ifdef(`2CH_2WAY', `
ifdef(`WAVES',
`MUXDEMUX_CONFIG(demux_priv_9, 2, LIST(` ', `matrix1,', `matrix2'))
MUXDEMUX_CONFIG(mux_priv_1, 2, LIST(` ', `matrix4,', `matrix5'))',
`MUXDEMUX_CONFIG(demux_priv_1, 1, LIST(`` '', `matrix3'))')',
`MUXDEMUX_CONFIG(demux_priv_1, 2, LIST(`` '', `matrix1,', `matrix2'))')')

#
# Define the pipelines
#
# PCM0 --> volume --> demux --> SSP$AMP_SSP (Speaker - CODEC)
ifdef(`2CH_2WAY', `
ifdef(`WAVES',
`# PCM0 --> waves --> demux --> waves -----+
# | |
# +----> waves --> mux --> SSP$AMP_SSP (Speaker - CODEC)',
`# PCM0 --> volume --> demux --> eq_iir --> SSP$AMP_SSP (Speaker - CODEC)')',
`# PCM0 --> volume --> demux --> SSP$AMP_SSP (Speaker - CODEC)
# |
# PCM6 <----------------+
# PCM6 <----------------+')
# PCM1 <---> volume <----> SSP0 (Headset - ALC5682)
# PCM99 <---- volume <----- DMIC01 (dmic0 capture)
# PCM2 ----> volume -----> iDisp1
Expand Down Expand Up @@ -135,17 +164,32 @@ dnl pipe id, pcm, max channels, format,
dnl frames, deadline, priority, core)

ifdef(`NO_AMP',`',`
`# Low Latency playback pipeline 1 on PCM 0 using max 'ifdef(`4CH_PASSTHROUGH', `4', `2')` channels of s24le.'
# Schedule 48 frames per 1000us deadline with priority 0 on core 0
define(`ENDPOINT_NAME', `Speakers')
ifdef(`2CH_2WAY', `
ifdef(`WAVES',
`# Low Latency playback pipeline 1 without PCM using max 2 channels of s32le.
# Schedule 48 frames per 1000us deadline with priority 1 on core 0
# The pipeline on PCM 0 will be declared later and connect to this one.
PIPELINE_ADD(sof/pipe-waves-mux-playback.m4,
1, 2, s32le,
1000, 1, 0,
`unused', SCHEDULE_TIME_DOMAIN_TIMER,
48000, 48000, 48000)',
`# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s32le.
# Schedule 48 frames per 1000us deadline with priority 0 on core 0
PIPELINE_PCM_ADD(sof/pipe-demux-eq-iir-playback.m4,
1, 0, 2, s32le,
1000, 0, 0,
48000, 48000, 48000)')',
`# Low Latency playback pipeline 1 on PCM 0 using max 'ifdef(`4CH_PASSTHROUGH', `4', `2')` channels of s32le.
# Schedule 48 frames per 1000us deadline with priority 0 on core 0
PIPELINE_PCM_ADD(
ifdef(`WAVES', sof/pipe-waves-codec-demux-playback.m4,
ifdef(`DRC_EQ', sof/pipe-drc-eq-volume-demux-playback.m4,
ifdef(`2CH_2WAY', sof/pipe-demux-eq-iir-playback.m4,
sof/pipe-volume-demux-playback.m4))),
sof/pipe-volume-demux-playback.m4)),
1, 0, ifdef(`4CH_PASSTHROUGH', `4', `2'), s32le,
1000, 0, 0,
48000, 48000, 48000)
48000, 48000, 48000)')
undefine(`ENDPOINT_NAME')')

# Low Latency playback pipeline 2 on PCM 1 using max 2 channels of s24le.
Expand Down Expand Up @@ -225,7 +269,29 @@ DAI_ADD(sof/pipe-dai-capture.m4,
1000, 0, 0, SCHEDULE_TIME_DOMAIN_TIMER)
',
`
ifdef(`2CH_2WAY',`# No echo reference for 2-way speakers',
ifdef(`2CH_2WAY', `# No echo reference for 2-way speakers
ifdef(`WAVES',
`# Low Latency playback pipeline 9 on PCM 0 using max 2 channels of s32le.
# Schedule 48 frames per 1000us deadline with priority 0 on core 0
define(`ENDPOINT_NAME', `Speakers')
PIPELINE_PCM_ADD(sof/pipe-waves-demux-waves-playback-sched.m4,
9, 0, 2, s32le,
1000, 0, 0,
48000, 48000, 48000,
SCHEDULE_TIME_DOMAIN_TIMER, PIPELINE_PLAYBACK_SCHED_COMP_1)
undefine(`ENDPOINT_NAME')

# Connect pipeline 1 and 9 together through mux and demux
SectionGraph."PIPE_PLAYBACK_SCHED" {
index "0"

lines [
# mux to playback
dapm(PIPELINE_SINK_1, PIPELINE_DEMUX_9)
dapm(PIPELINE_MUX_1, PIPELINE_SOURCE_9)
]
}
')',
`# currently this dai is here as "virtual" capture backend
W_DAI_IN(SSP, SPK_SSP_INDEX, SPK_SSP_NAME, FMT, 3, 0)

Expand Down Expand Up @@ -303,7 +369,11 @@ DAI_ADD(sof/pipe-dai-playback.m4,
# PCM Low Latency, id 0
dnl PCM_PLAYBACK_ADD(name, pcm_id, playback)
ifdef(`NO_AMP',`',`
PCM_PLAYBACK_ADD(Speakers, 0, PIPELINE_PCM_1)')
ifdef(`2CH_2WAY', `
ifdef(`WAVES',
`PCM_PLAYBACK_ADD(Speakers, 0, PIPELINE_PCM_9)',
`PCM_PLAYBACK_ADD(Speakers, 0, PIPELINE_PCM_1)')',
`PCM_PLAYBACK_ADD(Speakers, 0, PIPELINE_PCM_1)')')
PCM_DUPLEX_ADD(Headset, 1, PIPELINE_PCM_2, PIPELINE_PCM_3)
PCM_PLAYBACK_ADD(HDMI1, 2, PIPELINE_PCM_5)
PCM_PLAYBACK_ADD(HDMI2, 3, PIPELINE_PCM_6)
Expand Down
208 changes: 208 additions & 0 deletions tools/topology/topology1/sof/pipe-waves-demux-waves-playback-sched.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# 2-way Pipeline with Waves codec
#
# Low Latency Playback with 2 Waves codecs and Demux between them.
#
# Pipeline Endpoints for connection are :-
#
# Low Latency Playback PCM
# Demux
# B3 (source endpoint)
#
# host PCM_P -B0-> Waves(Stereo) -B1-> Demux -B2-> Waves(Woofer) -B3-> endpoint
#

DECLARE_SOF_RT_UUID("Waves codec", waves_codec_uuid, 0xd944281a, 0xafe9,
0x4695, 0xa0, 0x43, 0xd7, 0xf6, 0x2b, 0x89, 0x53, 0x8e);
define(`CA_UUID', waves_codec_uuid)

# Include topology builder
include(`utils.m4')
include(`buffer.m4')
include(`pcm.m4')
include(`pga.m4')
include(`muxdemux.m4')
include(`mixercontrol.m4')
include(`bytecontrol.m4')
include(`dai.m4')
include(`pipeline.m4')
include(`codec_adapter.m4')

ifdef(`ENDPOINT_NAME',`',`fatal_error(`Pipe requires ENDPOINT_NAME to be defined: Speakers, Headphones, etc.')')

# demux Bytes control with max value of 255
C_CONTROLBYTES(concat(`DEMUX', PIPELINE_ID), PIPELINE_ID,
CONTROLBYTES_OPS(bytes, 258 binds the mixer control to bytes get/put handlers, 258, 258),
CONTROLBYTES_EXTOPS(258 binds the mixer control to bytes get/put handlers, 258, 258),
, , ,
CONTROLBYTES_MAX(, 304),
, concat(`demux_priv_', PIPELINE_ID))

define(`SETUP_PARAMS_NAME_0', `Waves' `ENDPOINT_NAME' `Setup Stereo')

CONTROLBYTES_PRIV(PP_SETUP_CONFIG_0,
` bytes "0x53,0x4f,0x46,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x20,0x00,0x00,0x00,'
` 0x00,0x10,0x00,0x03,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'

` 0x00,0x01,0x41,0x57,'
` 0x00,0x00,0x00,0x00,'
` 0x80,0xBB,0x00,0x00,'
` 0x20,0x00,0x00,0x00,'
` 0x02,0x00,0x00,0x00,'

` 0x00,0x00,0x00,0x00,'
` 0x0c,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00"'
)

# Post process Bytes control for setup config
C_CONTROLBYTES(SETUP_PARAMS_NAME_0, PIPELINE_ID,
CONTROLBYTES_OPS(bytes),
CONTROLBYTES_EXTOPS(void, 258, 258),
, , ,
CONTROLBYTES_MAX(, 8192),
,
PP_SETUP_CONFIG_0)

define(`RUNTIME_PARAMS_NAME_0', `Waves' `ENDPOINT_NAME' `Runtime Stereo')

CONTROLBYTES_PRIV(PP_RUNTIME_PARAMS_0,
` bytes "0x53,0x4f,0x46,0x00,'
` 0x01,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x10,0x00,0x03,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00"'
)

# Post process Bytes control for runtime config
C_CONTROLBYTES(RUNTIME_PARAMS_NAME_0, PIPELINE_ID,
CONTROLBYTES_OPS(bytes),
CONTROLBYTES_EXTOPS(void, 258, 258),
, , ,
CONTROLBYTES_MAX(, 8192),
,
PP_RUNTIME_PARAMS_0)

define(`SETUP_PARAMS_NAME_1', `Waves' `ENDPOINT_NAME' `Setup Woofer')

CONTROLBYTES_PRIV(PP_SETUP_CONFIG_1,
` bytes "0x53,0x4f,0x46,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x20,0x00,0x00,0x00,'
` 0x00,0x10,0x00,0x03,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'

` 0x00,0x01,0x41,0x57,'
` 0x00,0x00,0x00,0x00,'
` 0x80,0xBB,0x00,0x00,'
` 0x20,0x00,0x00,0x00,'
` 0x02,0x00,0x00,0x00,'

` 0x00,0x00,0x00,0x00,'
` 0x0c,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00"'
)

# Post process Bytes control for setup config
C_CONTROLBYTES(SETUP_PARAMS_NAME_1, PIPELINE_ID,
CONTROLBYTES_OPS(bytes),
CONTROLBYTES_EXTOPS(void, 258, 258),
, , ,
CONTROLBYTES_MAX(, 8192),
,
PP_SETUP_CONFIG_1)

define(`RUNTIME_PARAMS_NAME_1', `Waves' `ENDPOINT_NAME' `Runtime Woofer')

CONTROLBYTES_PRIV(PP_RUNTIME_PARAMS_1,
` bytes "0x53,0x4f,0x46,0x00,'
` 0x01,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x10,0x00,0x03,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00,'
` 0x00,0x00,0x00,0x00"'
)

# Post process Bytes control for runtime config
C_CONTROLBYTES(RUNTIME_PARAMS_NAME_1, PIPELINE_ID,
CONTROLBYTES_OPS(bytes),
CONTROLBYTES_EXTOPS(void, 258, 258),
, , ,
CONTROLBYTES_MAX(, 8192),
,
PP_RUNTIME_PARAMS_1)

#
# Components and Buffers
#

# Host "Low latency Playback" PCM
# with 2 sink and 0 source periods
W_PCM_PLAYBACK(PCM_ID, Low Latency Playback, 2, 0, SCHEDULE_CORE)

W_CODEC_ADAPTER(0, PIPELINE_FORMAT, 2, 2, SCHEDULE_CORE,
LIST(` ', "RUNTIME_PARAMS_NAME_0", "SETUP_PARAMS_NAME_0"))

W_CODEC_ADAPTER(1, PIPELINE_FORMAT, 2, 2, SCHEDULE_CORE,
LIST(` ', "RUNTIME_PARAMS_NAME_1", "SETUP_PARAMS_NAME_1"))

# Mux 0 has 2 sink and source periods.
W_MUXDEMUX(0, 1, PIPELINE_FORMAT, 2, 2, SCHEDULE_CORE,
LIST(` ', concat(`DEMUX', PIPELINE_ID)))

# Low Latency Buffers
W_BUFFER(0, COMP_BUFFER_SIZE(2,
COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
PLATFORM_HOST_MEM_CAP)
W_BUFFER(1, COMP_BUFFER_SIZE(2,
COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
PLATFORM_COMP_MEM_CAP)
W_BUFFER(2, COMP_BUFFER_SIZE(2,
COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
PLATFORM_COMP_MEM_CAP)
W_BUFFER(3, COMP_BUFFER_SIZE(2,
COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
PLATFORM_COMP_MEM_CAP)

W_PIPELINE(SCHED_COMP, SCHEDULE_PERIOD, SCHEDULE_PRIORITY, SCHEDULE_CORE, SCHEDULE_TIME_DOMAIN, pipe_dai_schedule_plat)

#
# Pipeline Graph
#
# host PCM_P -B0-> Waves(Stereo) -B1-> Demux -B2-> Waves(Woofer) -B3-> endpoint

P_GRAPH(pipe-ll-playback-PIPELINE_ID, PIPELINE_ID,
LIST(` ',
`dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
`dapm(N_CODEC_ADAPTER(0), N_BUFFER(0))',
`dapm(N_BUFFER(1), N_CODEC_ADAPTER(0))',
`dapm(N_MUXDEMUX(0), N_BUFFER(1))',
`dapm(N_BUFFER(2), N_MUXDEMUX(0))',
`dapm(N_CODEC_ADAPTER(1), N_BUFFER(2))',
`dapm(N_BUFFER(3), N_CODEC_ADAPTER(1))'))
#
# Pipeline Source and Sinks
#
indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(3))
indir(`define', concat(`PIPELINE_DEMUX_', PIPELINE_ID), N_MUXDEMUX(0))
indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Low Latency Playback PCM_ID)

#
# PCM Configuration
#

# PCM capabilities supported by FW
PCM_CAPABILITIES(Low Latency Playback PCM_ID, CAPABILITY_FORMAT_NAME(PIPELINE_FORMAT), 48000, 48000, 2, PIPELINE_CHANNELS, 2, 16, 192, 16384, 65536, 65536)
Loading

0 comments on commit f826390

Please sign in to comment.