Part II - Modifying the Topology & Driver

Topology

Create tools/topology/m4/amp.m4 and add the following Amp widget definition. Note the highlighted line containing the definition of the type of your new processing component. The Driver section refers to it later.

Code Block 4 tools/topology/m4/amp.m4
 1divert(-1)
 2
 3dnl Define macro for example Amp widget
 4
 5dnl AMP(name)
 6define(`N_AMP', `AMP'PIPELINE_ID`.'$1)
 7
 8dnl W_AMP(name, format, periods_sink, periods_source, kcontrols_list)
 9define(`W_AMP',
10`SectionVendorTuples."'N_AMP($1)`_tuples_w" {'
11`    tokens "sof_comp_tokens"'
12`    tuples."word" {'
13`            SOF_TKN_COMP_PERIOD_SINK_COUNT'         STR($3)
14`            SOF_TKN_COMP_PERIOD_SOURCE_COUNT'       STR($4)
15`            SOF_TKN_COMP_CORE_ID'                   STR($5)
16`    }'
17`}'
18`SectionData."'N_AMP($1)`_data_w" {'
19`    tuples "'N_AMP($1)`_tuples_w"'
20`}'
21`SectionVendorTuples."'N_AMP($1)`_tuples_str" {'
22`    tokens "sof_comp_tokens"'
23`    tuples."string" {'
24`            SOF_TKN_COMP_FORMAT'    STR($2)
25`    }'
26`}'
27`SectionData."'N_AMP($1)`_data_str" {'
28`    tuples "'N_AMP($1)`_tuples_str"'
29`}'
30`SectionVendorTuples."'N_AMP($1)`_tuples_str_type" {'
31`    tokens "sof_process_tokens"'
32`    tuples."string" {'
33`            SOF_TKN_PROCESS_TYPE'   "AMP"
34`    }'
35`}'
36`SectionData."'N_AMP($1)`_data_str_type" {'
37`    tuples "'N_AMP($1)`_tuples_str_type"'
38`}'
39`SectionWidget."'N_AMP($1)`" {'
40`    index "'PIPELINE_ID`"'
41`    type "effect"'
42`    no_pm "true"'
43`    data ['
44`            "'N_AMP($1)`_data_w"'
45`            "'N_AMP($1)`_data_str"'
46`            "'N_AMP($1)`_data_str_type"'
47`    ]'
48`    bytes ['
49             $6
50`    ]'
51`}')
52
53divert(0)dnl

Add a definition of parameters and specify default values for them (handling parameters in the FW code is discussed in the next lesson but you prepare a complete topology upfront). Create tools/topology/amp_bytes.m4 and add the following code.

Note the size of the parameters data and the data highlighted (two 32-bit number set to 1 to unmute both channels by default, little-endian byte ordering). The data begins with struct sof_abi_hdr content, note the SOF magic number in line 3 and the ABI version in line 6. The latter must be set to a version compatible with the SOF stack.

Code Block 5 tools/topology/amp_bytes.m4
 1# AMP Example - Parameters
 2CONTROLBYTES_PRIV(AMP_priv,
 3`       bytes "0x53,0x4f,0x46,0x00,'
 4`       0x00,0x00,0x00,0x00,'
 5`       0x08,0x00,0x00,0x00,'
 6`       0x00,0x00,0x00,0x03,'
 7`       0x00,0x00,0x00,0x00,''
 8`       0x00,0x00,0x00,0x00,'
 9`       0x00,0x00,0x00,0x00,'
10`       0x00,0x00,0x00,0x00,'
11`       0x01,0x00,0x00,0x00,'
12`       0x01,0x00,0x00,0x00"'
13)

Add the Amp widget to a playback pipeline. Create a copy of tools/topology/sof/pipe-volume-playback.m4 and save it as tools/topology/sof/pipe-amp-volume-playback.m4. Add the definitions in your copy as highlighted below.

Code Block 6 tools/topology/sof/pipe-amp-volume-playback.m4
  1# Low Latency Passthrough with volume Pipeline and PCM
  2#
  3# Pipeline Endpoints for connection are :-
  4#
  5#  host PCM_P --> B0 --> Amp -> B1 -> Volume 0 --> B2 --> sink DAI0
  6
  7# Include topology builder
  8include(`utils.m4')
  9include(`buffer.m4')
 10include(`pcm.m4')
 11include(`pga.m4')
 12include(`dai.m4')
 13include(`mixercontrol.m4')
 14include(`bytecontrol.m4')
 15include(`pipeline.m4')
 16include(`amp.m4')
 17
 18#
 19# Controls
 20#
 21# Volume Mixer control with max value of 32
 22C_CONTROLMIXER(Master Playback Volume, PIPELINE_ID,
 23     CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256),
 24     CONTROLMIXER_MAX(, 32),
 25     false,
 26     CONTROLMIXER_TLV(TLV 32 steps from -64dB to 0dB for 2dB, vtlv_m64s2),
 27     Channel register and shift for Front Left/Right,
 28     LIST(`  ', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1)))
 29
 30#
 31# Volume configuration
 32#
 33
 34define(DEF_PGA_TOKENS, concat(`pga_tokens_', PIPELINE_ID))
 35define(DEF_PGA_CONF, concat(`pga_conf_', PIPELINE_ID))
 36
 37W_VENDORTUPLES(DEF_PGA_TOKENS, sof_volume_tokens,
 38LIST(`               ', `SOF_TKN_VOLUME_RAMP_STEP_TYPE       "0"'
 39     `               ', `SOF_TKN_VOLUME_RAMP_STEP_MS         "250"'))
 40
 41W_DATA(DEF_PGA_CONF, DEF_PGA_TOKENS)
 42
 43# Amp Parameters
 44include(`amp_bytes.m4')
 45
 46# Amp Bytes control with max value of 140
 47# The max size needs to also take into account the space required to hold the control data IPC message
 48# struct sof_ipc_ctrl_data requires 92 bytes
 49# AMP priv in amp_bytes.m4 (ABI header (32 bytes) + 2 dwords) requires 40 bytes
 50# Therefore at least 132 bytes are required for this kcontrol
 51# Any value lower than that would end up in a topology load error
 52C_CONTROLBYTES(AMP, PIPELINE_ID,
 53     CONTROLBYTES_OPS(bytes, 258 binds the control to bytes get/put handlers, 258, 258),
 54     CONTROLBYTES_EXTOPS(258 binds the control to bytes get/put handlers, 258, 258),
 55     , , ,
 56     CONTROLBYTES_MAX(, 140),
 57     ,
 58     AMP_priv)
 59
 60#
 61# Components and Buffers
 62#
 63
 64# Host "Passthrough Playback" PCM
 65# with 2 sink and 0 source periods
 66W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, 2, 0, SCHEDULE_CORE)
 67
 68
 69# "Volume" has 2 source and 2 sink periods
 70W_PGA(0, PIPELINE_FORMAT, DAI_PERIODS, 2, DEF_PGA_CONF, SCHEDULE_CORE,
 71     LIST(`          ', "PIPELINE_ID Master Playback Volume"))
 72
 73# "Amp" has 2 sink periods and 2 source periods
 74W_AMP(0, PIPELINE_FORMAT, 2, 2, SCHEDULE_CORE,
 75     LIST(`           ', "AMP"))
 76
 77# Playback Buffers
 78W_BUFFER(0, COMP_BUFFER_SIZE(2,
 79     COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
 80     PLATFORM_HOST_MEM_CAP)
 81W_BUFFER(1, COMP_BUFFER_SIZE(2,
 82     COMP_SAMPLE_SIZE(PIPELINE_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
 83     PLATFORM_HOST_MEM_CAP)
 84W_BUFFER(2, COMP_BUFFER_SIZE(DAI_PERIODS,
 85     COMP_SAMPLE_SIZE(DAI_FORMAT), PIPELINE_CHANNELS, COMP_PERIOD_FRAMES(PCM_MAX_RATE, SCHEDULE_PERIOD)),
 86     PLATFORM_DAI_MEM_CAP)
 87
 88#
 89# Pipeline Graph
 90#
 91#  host PCM_P --> B0 --> Amp -> B1 --> Volume 0 --> B2 --> sink DAI0
 92
 93P_GRAPH(pipe-amp-volume-playback-PIPELINE_ID, PIPELINE_ID,
 94     LIST(`          ',
 95     `dapm(N_BUFFER(0), N_PCMP(PCM_ID))',
 96     `dapm(N_AMP(0), N_BUFFER(0))',
 97     `dapm(N_BUFFER(1), N_AMP(0))',
 98     `dapm(N_PGA(0), N_BUFFER(1))',
 99     `dapm(N_BUFFER(2), N_PGA(0))'))
100
101#
102# Pipeline Source and Sinks
103#
104indir(`define', concat(`PIPELINE_SOURCE_', PIPELINE_ID), N_BUFFER(2))
105indir(`define', concat(`PIPELINE_PCM_', PIPELINE_ID), Passthrough Playback PCM_ID)
106
107
108#
109# PCM Configuration
110
111#
112PCM_CAPABILITIES(Passthrough Playback PCM_ID, `S32_LE,S24_LE,S16_LE', PCM_MIN_RATE, PCM_MAX_RATE, 2, PIPELINE_CHANNELS, 2, 16, 192, 16384, 65536, 65536)

Create a copy of your topology in tools/topology and replace the definition of low latency playback pipeline with the one crated in the previous step.

Code Block 7 Main topology .m4 file
1# Low Latency playback pipeline 1 on PCM 0 using max 2 channels of s24le.
2# Schedule 48 frames per 1000us deadline on core 0 with priority 0
3PIPELINE_PCM_ADD(sof/pipe-amp-volume-playback.m4,
4        1, 0, 2, s24le,
5        1000, 0, 0,
6        48000, 48000, 48000)

Driver

Add a mapping between SOF_TKN_PROCESS_TYPE set to “AMP” in your m4 topology definition and the SOF_COMP_AMP defined in the FW code in lesson 1. Refer to the driver documentation for further details about the topology mappings location and recompilation of the driver.