Skip to content

Commit 621fd48

Browse files
ranj063broonie
authored andcommitted
ASoC: SOF: Define hw_params PCM op for IPC3
Add the hw_params op for IPC3 and use it. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://lore.kernel.org/r/20220317175044.1752400-15-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 4123c24 commit 621fd48

2 files changed

Lines changed: 115 additions & 95 deletions

File tree

sound/soc/sof/ipc3-pcm.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,106 @@ static int sof_ipc3_pcm_hw_free(struct snd_soc_component *component,
3838
sizeof(stream), &reply, sizeof(reply));
3939
}
4040

41+
static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component,
42+
struct snd_pcm_substream *substream,
43+
struct snd_pcm_hw_params *params,
44+
struct snd_sof_platform_stream_params *platform_params)
45+
{
46+
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
47+
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
48+
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
49+
struct snd_pcm_runtime *runtime = substream->runtime;
50+
struct sof_ipc_pcm_params_reply ipc_params_reply;
51+
struct sof_ipc_pcm_params pcm;
52+
struct snd_sof_pcm *spcm;
53+
int ret;
54+
55+
spcm = snd_sof_find_spcm_dai(component, rtd);
56+
if (!spcm)
57+
return -EINVAL;
58+
59+
memset(&pcm, 0, sizeof(pcm));
60+
61+
/* number of pages should be rounded up */
62+
pcm.params.buffer.pages = PFN_UP(runtime->dma_bytes);
63+
64+
/* set IPC PCM parameters */
65+
pcm.hdr.size = sizeof(pcm);
66+
pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
67+
pcm.comp_id = spcm->stream[substream->stream].comp_id;
68+
pcm.params.hdr.size = sizeof(pcm.params);
69+
pcm.params.buffer.phy_addr = spcm->stream[substream->stream].page_table.addr;
70+
pcm.params.buffer.size = runtime->dma_bytes;
71+
pcm.params.direction = substream->stream;
72+
pcm.params.sample_valid_bytes = params_width(params) >> 3;
73+
pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
74+
pcm.params.rate = params_rate(params);
75+
pcm.params.channels = params_channels(params);
76+
pcm.params.host_period_bytes = params_period_bytes(params);
77+
78+
/* container size */
79+
ret = snd_pcm_format_physical_width(params_format(params));
80+
if (ret < 0)
81+
return ret;
82+
pcm.params.sample_container_bytes = ret >> 3;
83+
84+
/* format */
85+
switch (params_format(params)) {
86+
case SNDRV_PCM_FORMAT_S16:
87+
pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
88+
break;
89+
case SNDRV_PCM_FORMAT_S24:
90+
pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
91+
break;
92+
case SNDRV_PCM_FORMAT_S32:
93+
pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
94+
break;
95+
case SNDRV_PCM_FORMAT_FLOAT:
96+
pcm.params.frame_fmt = SOF_IPC_FRAME_FLOAT;
97+
break;
98+
default:
99+
return -EINVAL;
100+
}
101+
102+
/* Update the IPC message with information from the platform */
103+
pcm.params.stream_tag = platform_params->stream_tag;
104+
105+
if (platform_params->use_phy_address)
106+
pcm.params.buffer.phy_addr = platform_params->phy_addr;
107+
108+
if (platform_params->no_ipc_position) {
109+
/* For older ABIs set host_period_bytes to zero to inform
110+
* FW we don't want position updates. Newer versions use
111+
* no_stream_position for this purpose.
112+
*/
113+
if (v->abi_version < SOF_ABI_VER(3, 10, 0))
114+
pcm.params.host_period_bytes = 0;
115+
else
116+
pcm.params.no_stream_position = 1;
117+
}
118+
119+
dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
120+
121+
/* send hw_params IPC to the DSP */
122+
ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
123+
&ipc_params_reply, sizeof(ipc_params_reply));
124+
if (ret < 0) {
125+
dev_err(component->dev, "HW params ipc failed for stream %d\n",
126+
pcm.params.stream_tag);
127+
return ret;
128+
}
129+
130+
ret = snd_sof_set_stream_data_offset(sdev, substream, ipc_params_reply.posn_offset);
131+
if (ret < 0) {
132+
dev_err(component->dev, "%s: invalid stream data offset for PCM %d\n",
133+
__func__, spcm->pcm.pcm_id);
134+
return ret;
135+
}
136+
137+
return ret;
138+
}
139+
41140
const struct sof_ipc_pcm_ops ipc3_pcm_ops = {
141+
.hw_params = sof_ipc3_pcm_hw_params,
42142
.hw_free = sof_ipc3_pcm_hw_free,
43143
};

sound/soc/sof/pcm.c

Lines changed: 15 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,12 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
119119
struct snd_pcm_substream *substream,
120120
struct snd_pcm_hw_params *params)
121121
{
122-
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
123-
struct snd_pcm_runtime *runtime = substream->runtime;
124122
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
125-
const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
123+
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
126124
struct snd_sof_platform_stream_params platform_params = { 0 };
127-
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
125+
const struct sof_ipc_pcm_ops *pcm_ops = sdev->ipc->ops->pcm;
126+
struct snd_pcm_runtime *runtime = substream->runtime;
128127
struct snd_sof_pcm *spcm;
129-
struct sof_ipc_pcm_params pcm;
130-
struct sof_ipc_pcm_params_reply ipc_params_reply;
131128
int ret;
132129

133130
/* nothing to do for BE */
@@ -153,117 +150,40 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
153150
dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
154151
spcm->pcm.pcm_id, substream->stream);
155152

156-
memset(&pcm, 0, sizeof(pcm));
153+
/* if this is a repeated hw_params without hw_free, skip setting up widgets */
154+
if (!spcm->stream[substream->stream].list) {
155+
ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, substream->stream);
156+
if (ret < 0)
157+
return ret;
158+
}
157159

158160
/* create compressed page table for audio firmware */
159161
if (runtime->buffer_changed) {
160162
ret = create_page_table(component, substream, runtime->dma_area,
161163
runtime->dma_bytes);
164+
162165
if (ret < 0)
163166
return ret;
164167
}
165168

166-
/* number of pages should be rounded up */
167-
pcm.params.buffer.pages = PFN_UP(runtime->dma_bytes);
168-
169-
/* set IPC PCM parameters */
170-
pcm.hdr.size = sizeof(pcm);
171-
pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
172-
pcm.comp_id = spcm->stream[substream->stream].comp_id;
173-
pcm.params.hdr.size = sizeof(pcm.params);
174-
pcm.params.buffer.phy_addr =
175-
spcm->stream[substream->stream].page_table.addr;
176-
pcm.params.buffer.size = runtime->dma_bytes;
177-
pcm.params.direction = substream->stream;
178-
pcm.params.sample_valid_bytes = params_width(params) >> 3;
179-
pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
180-
pcm.params.rate = params_rate(params);
181-
pcm.params.channels = params_channels(params);
182-
pcm.params.host_period_bytes = params_period_bytes(params);
183-
184-
/* container size */
185-
ret = snd_pcm_format_physical_width(params_format(params));
186-
if (ret < 0)
187-
return ret;
188-
pcm.params.sample_container_bytes = ret >> 3;
189-
190-
/* format */
191-
switch (params_format(params)) {
192-
case SNDRV_PCM_FORMAT_S16:
193-
pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
194-
break;
195-
case SNDRV_PCM_FORMAT_S24:
196-
pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
197-
break;
198-
case SNDRV_PCM_FORMAT_S32:
199-
pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
200-
break;
201-
case SNDRV_PCM_FORMAT_FLOAT:
202-
pcm.params.frame_fmt = SOF_IPC_FRAME_FLOAT;
203-
break;
204-
default:
205-
return -EINVAL;
206-
}
207-
208-
/* firmware already configured host stream */
209-
ret = snd_sof_pcm_platform_hw_params(sdev,
210-
substream,
211-
params,
212-
&platform_params);
169+
ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params);
213170
if (ret < 0) {
214-
dev_err(component->dev, "error: platform hw params failed\n");
171+
dev_err(component->dev, "platform hw params failed\n");
215172
return ret;
216173
}
217174

218-
/* Update the IPC message with information from the platform */
219-
pcm.params.stream_tag = platform_params.stream_tag;
220-
221-
if (platform_params.use_phy_address)
222-
pcm.params.buffer.phy_addr = platform_params.phy_addr;
223-
224-
if (platform_params.no_ipc_position) {
225-
/* For older ABIs set host_period_bytes to zero to inform
226-
* FW we don't want position updates. Newer versions use
227-
* no_stream_position for this purpose.
228-
*/
229-
if (v->abi_version < SOF_ABI_VER(3, 10, 0))
230-
pcm.params.host_period_bytes = 0;
231-
else
232-
pcm.params.no_stream_position = 1;
233-
}
234-
235-
dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
236-
237-
/* if this is a repeated hw_params without hw_free, skip setting up widgets */
238-
if (!spcm->stream[substream->stream].list) {
239-
ret = sof_pcm_setup_connected_widgets(sdev, rtd, spcm, substream->stream);
175+
if (pcm_ops->hw_params) {
176+
ret = pcm_ops->hw_params(component, substream, params, &platform_params);
240177
if (ret < 0)
241178
return ret;
242179
}
243180

244-
/* send hw_params IPC to the DSP */
245-
ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
246-
&ipc_params_reply, sizeof(ipc_params_reply));
247-
if (ret < 0) {
248-
dev_err(component->dev, "error: hw params ipc failed for stream %d\n",
249-
pcm.params.stream_tag);
250-
return ret;
251-
}
252-
253-
ret = snd_sof_set_stream_data_offset(sdev, substream,
254-
ipc_params_reply.posn_offset);
255-
if (ret < 0) {
256-
dev_err(component->dev, "%s: invalid stream data offset for PCM %d\n",
257-
__func__, spcm->pcm.pcm_id);
258-
return ret;
259-
}
260-
261181
spcm->prepared[substream->stream] = true;
262182

263183
/* save pcm hw_params */
264184
memcpy(&spcm->params[substream->stream], params, sizeof(*params));
265185

266-
return ret;
186+
return 0;
267187
}
268188

269189
static int sof_pcm_hw_free(struct snd_soc_component *component,

0 commit comments

Comments
 (0)