xref: /openbmc/linux/sound/soc/intel/avs/pcm.c (revision 9114700b496c6ce16ad6fc0073f0502cd0f46991)
1f1b3b320SCezary Rojewski // SPDX-License-Identifier: GPL-2.0-only
2f1b3b320SCezary Rojewski //
3f1b3b320SCezary Rojewski // Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
4f1b3b320SCezary Rojewski //
5f1b3b320SCezary Rojewski // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6f1b3b320SCezary Rojewski //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
7f1b3b320SCezary Rojewski //
8f1b3b320SCezary Rojewski 
9f1b3b320SCezary Rojewski #include <linux/debugfs.h>
10f1b3b320SCezary Rojewski #include <linux/device.h>
11f1b3b320SCezary Rojewski #include <sound/hda_register.h>
12f1b3b320SCezary Rojewski #include <sound/hdaudio_ext.h>
13*9114700bSCezary Rojewski #include <sound/pcm_params.h>
14f1b3b320SCezary Rojewski #include <sound/soc-acpi.h>
15f1b3b320SCezary Rojewski #include <sound/soc-acpi-intel-match.h>
16f1b3b320SCezary Rojewski #include <sound/soc-component.h>
17f1b3b320SCezary Rojewski #include "avs.h"
18f1b3b320SCezary Rojewski #include "path.h"
19f1b3b320SCezary Rojewski #include "topology.h"
20f1b3b320SCezary Rojewski 
21f1b3b320SCezary Rojewski struct avs_dma_data {
22f1b3b320SCezary Rojewski 	struct avs_tplg_path_template *template;
23f1b3b320SCezary Rojewski 	struct avs_path *path;
24f1b3b320SCezary Rojewski 	/*
25f1b3b320SCezary Rojewski 	 * link stream is stored within substream's runtime
26f1b3b320SCezary Rojewski 	 * private_data to fulfill the needs of codec BE path
27f1b3b320SCezary Rojewski 	 *
28f1b3b320SCezary Rojewski 	 * host stream assigned
29f1b3b320SCezary Rojewski 	 */
30f1b3b320SCezary Rojewski 	struct hdac_ext_stream *host_stream;
31f1b3b320SCezary Rojewski };
32f1b3b320SCezary Rojewski 
33*9114700bSCezary Rojewski static struct avs_tplg_path_template *
34*9114700bSCezary Rojewski avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction)
35*9114700bSCezary Rojewski {
36*9114700bSCezary Rojewski 	struct snd_soc_dapm_widget *dw;
37*9114700bSCezary Rojewski 	struct snd_soc_dapm_path *dp;
38*9114700bSCezary Rojewski 	enum snd_soc_dapm_direction dir;
39*9114700bSCezary Rojewski 
40*9114700bSCezary Rojewski 	if (direction == SNDRV_PCM_STREAM_CAPTURE) {
41*9114700bSCezary Rojewski 		dw = dai->capture_widget;
42*9114700bSCezary Rojewski 		dir = is_fe ? SND_SOC_DAPM_DIR_OUT : SND_SOC_DAPM_DIR_IN;
43*9114700bSCezary Rojewski 	} else {
44*9114700bSCezary Rojewski 		dw = dai->playback_widget;
45*9114700bSCezary Rojewski 		dir = is_fe ? SND_SOC_DAPM_DIR_IN : SND_SOC_DAPM_DIR_OUT;
46*9114700bSCezary Rojewski 	}
47*9114700bSCezary Rojewski 
48*9114700bSCezary Rojewski 	dp = list_first_entry_or_null(&dw->edges[dir], typeof(*dp), list_node[dir]);
49*9114700bSCezary Rojewski 	if (!dp)
50*9114700bSCezary Rojewski 		return NULL;
51*9114700bSCezary Rojewski 
52*9114700bSCezary Rojewski 	/* Get the other widget, with actual path template data */
53*9114700bSCezary Rojewski 	dw = (dp->source == dw) ? dp->sink : dp->source;
54*9114700bSCezary Rojewski 
55*9114700bSCezary Rojewski 	return dw->priv;
56*9114700bSCezary Rojewski }
57*9114700bSCezary Rojewski 
58*9114700bSCezary Rojewski static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe)
59*9114700bSCezary Rojewski {
60*9114700bSCezary Rojewski 	struct avs_tplg_path_template *template;
61*9114700bSCezary Rojewski 	struct avs_dma_data *data;
62*9114700bSCezary Rojewski 
63*9114700bSCezary Rojewski 	template = avs_dai_find_path_template(dai, is_fe, substream->stream);
64*9114700bSCezary Rojewski 	if (!template) {
65*9114700bSCezary Rojewski 		dev_err(dai->dev, "no %s path for dai %s, invalid tplg?\n",
66*9114700bSCezary Rojewski 			snd_pcm_stream_str(substream), dai->name);
67*9114700bSCezary Rojewski 		return -EINVAL;
68*9114700bSCezary Rojewski 	}
69*9114700bSCezary Rojewski 
70*9114700bSCezary Rojewski 	data = kzalloc(sizeof(*data), GFP_KERNEL);
71*9114700bSCezary Rojewski 	if (!data)
72*9114700bSCezary Rojewski 		return -ENOMEM;
73*9114700bSCezary Rojewski 
74*9114700bSCezary Rojewski 	data->template = template;
75*9114700bSCezary Rojewski 	snd_soc_dai_set_dma_data(dai, substream, data);
76*9114700bSCezary Rojewski 
77*9114700bSCezary Rojewski 	return 0;
78*9114700bSCezary Rojewski }
79*9114700bSCezary Rojewski 
80*9114700bSCezary Rojewski static int avs_dai_hw_params(struct snd_pcm_substream *substream,
81*9114700bSCezary Rojewski 			     struct snd_pcm_hw_params *fe_hw_params,
82*9114700bSCezary Rojewski 			     struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai,
83*9114700bSCezary Rojewski 			     int dma_id)
84*9114700bSCezary Rojewski {
85*9114700bSCezary Rojewski 	struct avs_dma_data *data;
86*9114700bSCezary Rojewski 	struct avs_path *path;
87*9114700bSCezary Rojewski 	struct avs_dev *adev = to_avs_dev(dai->dev);
88*9114700bSCezary Rojewski 	int ret;
89*9114700bSCezary Rojewski 
90*9114700bSCezary Rojewski 	data = snd_soc_dai_get_dma_data(dai, substream);
91*9114700bSCezary Rojewski 
92*9114700bSCezary Rojewski 	dev_dbg(dai->dev, "%s FE hw_params str %p rtd %p",
93*9114700bSCezary Rojewski 		__func__, substream, substream->runtime);
94*9114700bSCezary Rojewski 	dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n",
95*9114700bSCezary Rojewski 		params_rate(fe_hw_params), params_channels(fe_hw_params),
96*9114700bSCezary Rojewski 		params_width(fe_hw_params), params_physical_width(fe_hw_params));
97*9114700bSCezary Rojewski 
98*9114700bSCezary Rojewski 	dev_dbg(dai->dev, "%s BE hw_params str %p rtd %p",
99*9114700bSCezary Rojewski 		__func__, substream, substream->runtime);
100*9114700bSCezary Rojewski 	dev_dbg(dai->dev, "rate %d chn %d vbd %d bd %d\n",
101*9114700bSCezary Rojewski 		params_rate(be_hw_params), params_channels(be_hw_params),
102*9114700bSCezary Rojewski 		params_width(be_hw_params), params_physical_width(be_hw_params));
103*9114700bSCezary Rojewski 
104*9114700bSCezary Rojewski 	path = avs_path_create(adev, dma_id, data->template, fe_hw_params, be_hw_params);
105*9114700bSCezary Rojewski 	if (IS_ERR(path)) {
106*9114700bSCezary Rojewski 		ret = PTR_ERR(path);
107*9114700bSCezary Rojewski 		dev_err(dai->dev, "create path failed: %d\n", ret);
108*9114700bSCezary Rojewski 		return ret;
109*9114700bSCezary Rojewski 	}
110*9114700bSCezary Rojewski 
111*9114700bSCezary Rojewski 	data->path = path;
112*9114700bSCezary Rojewski 	return 0;
113*9114700bSCezary Rojewski }
114*9114700bSCezary Rojewski 
115*9114700bSCezary Rojewski static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream,
116*9114700bSCezary Rojewski 			   struct snd_soc_dai *dai)
117*9114700bSCezary Rojewski {
118*9114700bSCezary Rojewski 	struct avs_dma_data *data;
119*9114700bSCezary Rojewski 	int ret;
120*9114700bSCezary Rojewski 
121*9114700bSCezary Rojewski 	data = snd_soc_dai_get_dma_data(dai, substream);
122*9114700bSCezary Rojewski 	if (!data->path)
123*9114700bSCezary Rojewski 		return 0;
124*9114700bSCezary Rojewski 
125*9114700bSCezary Rojewski 	ret = avs_path_reset(data->path);
126*9114700bSCezary Rojewski 	if (ret < 0) {
127*9114700bSCezary Rojewski 		dev_err(dai->dev, "reset path failed: %d\n", ret);
128*9114700bSCezary Rojewski 		return ret;
129*9114700bSCezary Rojewski 	}
130*9114700bSCezary Rojewski 
131*9114700bSCezary Rojewski 	ret = avs_path_pause(data->path);
132*9114700bSCezary Rojewski 	if (ret < 0)
133*9114700bSCezary Rojewski 		dev_err(dai->dev, "pause path failed: %d\n", ret);
134*9114700bSCezary Rojewski 	return ret;
135*9114700bSCezary Rojewski }
136*9114700bSCezary Rojewski 
137*9114700bSCezary Rojewski static const unsigned int rates[] = {
138*9114700bSCezary Rojewski 	8000, 11025, 12000, 16000,
139*9114700bSCezary Rojewski 	22050, 24000, 32000, 44100,
140*9114700bSCezary Rojewski 	48000, 64000, 88200, 96000,
141*9114700bSCezary Rojewski 	128000, 176400, 192000,
142*9114700bSCezary Rojewski };
143*9114700bSCezary Rojewski 
144*9114700bSCezary Rojewski static const struct snd_pcm_hw_constraint_list hw_rates = {
145*9114700bSCezary Rojewski 	.count = ARRAY_SIZE(rates),
146*9114700bSCezary Rojewski 	.list = rates,
147*9114700bSCezary Rojewski 	.mask = 0,
148*9114700bSCezary Rojewski };
149*9114700bSCezary Rojewski 
150*9114700bSCezary Rojewski static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
151*9114700bSCezary Rojewski {
152*9114700bSCezary Rojewski 	struct snd_pcm_runtime *runtime = substream->runtime;
153*9114700bSCezary Rojewski 	struct avs_dma_data *data;
154*9114700bSCezary Rojewski 	struct avs_dev *adev = to_avs_dev(dai->dev);
155*9114700bSCezary Rojewski 	struct hdac_bus *bus = &adev->base.core;
156*9114700bSCezary Rojewski 	struct hdac_ext_stream *host_stream;
157*9114700bSCezary Rojewski 	int ret;
158*9114700bSCezary Rojewski 
159*9114700bSCezary Rojewski 	ret = avs_dai_startup(substream, dai, true);
160*9114700bSCezary Rojewski 	if (ret)
161*9114700bSCezary Rojewski 		return ret;
162*9114700bSCezary Rojewski 
163*9114700bSCezary Rojewski 	data = snd_soc_dai_get_dma_data(dai, substream);
164*9114700bSCezary Rojewski 
165*9114700bSCezary Rojewski 	host_stream = snd_hdac_ext_stream_assign(bus, substream, HDAC_EXT_STREAM_TYPE_HOST);
166*9114700bSCezary Rojewski 	if (!host_stream) {
167*9114700bSCezary Rojewski 		kfree(data);
168*9114700bSCezary Rojewski 		return -EBUSY;
169*9114700bSCezary Rojewski 	}
170*9114700bSCezary Rojewski 
171*9114700bSCezary Rojewski 	data->host_stream = host_stream;
172*9114700bSCezary Rojewski 	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
173*9114700bSCezary Rojewski 	/* avoid wrap-around with wall-clock */
174*9114700bSCezary Rojewski 	snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000);
175*9114700bSCezary Rojewski 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates);
176*9114700bSCezary Rojewski 	snd_pcm_set_sync(substream);
177*9114700bSCezary Rojewski 
178*9114700bSCezary Rojewski 	dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p",
179*9114700bSCezary Rojewski 		__func__, hdac_stream(host_stream)->stream_tag, substream);
180*9114700bSCezary Rojewski 
181*9114700bSCezary Rojewski 	return 0;
182*9114700bSCezary Rojewski }
183*9114700bSCezary Rojewski 
184*9114700bSCezary Rojewski static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
185*9114700bSCezary Rojewski {
186*9114700bSCezary Rojewski 	struct avs_dma_data *data;
187*9114700bSCezary Rojewski 
188*9114700bSCezary Rojewski 	data = snd_soc_dai_get_dma_data(dai, substream);
189*9114700bSCezary Rojewski 
190*9114700bSCezary Rojewski 	snd_soc_dai_set_dma_data(dai, substream, NULL);
191*9114700bSCezary Rojewski 	snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST);
192*9114700bSCezary Rojewski 	kfree(data);
193*9114700bSCezary Rojewski }
194*9114700bSCezary Rojewski 
195*9114700bSCezary Rojewski static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream,
196*9114700bSCezary Rojewski 				struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai)
197*9114700bSCezary Rojewski {
198*9114700bSCezary Rojewski 	struct snd_pcm_hw_params *be_hw_params = NULL;
199*9114700bSCezary Rojewski 	struct snd_soc_pcm_runtime *fe, *be;
200*9114700bSCezary Rojewski 	struct snd_soc_dpcm *dpcm;
201*9114700bSCezary Rojewski 	struct avs_dma_data *data;
202*9114700bSCezary Rojewski 	struct hdac_ext_stream *host_stream;
203*9114700bSCezary Rojewski 	int ret;
204*9114700bSCezary Rojewski 
205*9114700bSCezary Rojewski 	data = snd_soc_dai_get_dma_data(dai, substream);
206*9114700bSCezary Rojewski 	if (data->path)
207*9114700bSCezary Rojewski 		return 0;
208*9114700bSCezary Rojewski 
209*9114700bSCezary Rojewski 	host_stream = data->host_stream;
210*9114700bSCezary Rojewski 
211*9114700bSCezary Rojewski 	hdac_stream(host_stream)->bufsize = 0;
212*9114700bSCezary Rojewski 	hdac_stream(host_stream)->period_bytes = 0;
213*9114700bSCezary Rojewski 	hdac_stream(host_stream)->format_val = 0;
214*9114700bSCezary Rojewski 
215*9114700bSCezary Rojewski 	fe = asoc_substream_to_rtd(substream);
216*9114700bSCezary Rojewski 	for_each_dpcm_be(fe, substream->stream, dpcm) {
217*9114700bSCezary Rojewski 		be = dpcm->be;
218*9114700bSCezary Rojewski 		be_hw_params = &be->dpcm[substream->stream].hw_params;
219*9114700bSCezary Rojewski 	}
220*9114700bSCezary Rojewski 
221*9114700bSCezary Rojewski 	ret = avs_dai_hw_params(substream, hw_params, be_hw_params, dai,
222*9114700bSCezary Rojewski 				hdac_stream(host_stream)->stream_tag - 1);
223*9114700bSCezary Rojewski 	if (ret)
224*9114700bSCezary Rojewski 		goto create_err;
225*9114700bSCezary Rojewski 
226*9114700bSCezary Rojewski 	ret = avs_path_bind(data->path);
227*9114700bSCezary Rojewski 	if (ret < 0) {
228*9114700bSCezary Rojewski 		dev_err(dai->dev, "bind FE <-> BE failed: %d\n", ret);
229*9114700bSCezary Rojewski 		goto bind_err;
230*9114700bSCezary Rojewski 	}
231*9114700bSCezary Rojewski 
232*9114700bSCezary Rojewski 	return 0;
233*9114700bSCezary Rojewski 
234*9114700bSCezary Rojewski bind_err:
235*9114700bSCezary Rojewski 	avs_path_free(data->path);
236*9114700bSCezary Rojewski 	data->path = NULL;
237*9114700bSCezary Rojewski create_err:
238*9114700bSCezary Rojewski 	snd_pcm_lib_free_pages(substream);
239*9114700bSCezary Rojewski 	return ret;
240*9114700bSCezary Rojewski }
241*9114700bSCezary Rojewski 
242*9114700bSCezary Rojewski static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
243*9114700bSCezary Rojewski {
244*9114700bSCezary Rojewski 	struct avs_dma_data *data;
245*9114700bSCezary Rojewski 	struct hdac_ext_stream *host_stream;
246*9114700bSCezary Rojewski 	int ret;
247*9114700bSCezary Rojewski 
248*9114700bSCezary Rojewski 	dev_dbg(dai->dev, "%s fe HW_FREE str %p rtd %p",
249*9114700bSCezary Rojewski 		__func__, substream, substream->runtime);
250*9114700bSCezary Rojewski 
251*9114700bSCezary Rojewski 	data = snd_soc_dai_get_dma_data(dai, substream);
252*9114700bSCezary Rojewski 	if (!data->path)
253*9114700bSCezary Rojewski 		return 0;
254*9114700bSCezary Rojewski 
255*9114700bSCezary Rojewski 	host_stream = data->host_stream;
256*9114700bSCezary Rojewski 
257*9114700bSCezary Rojewski 	ret = avs_path_unbind(data->path);
258*9114700bSCezary Rojewski 	if (ret < 0)
259*9114700bSCezary Rojewski 		dev_err(dai->dev, "unbind FE <-> BE failed: %d\n", ret);
260*9114700bSCezary Rojewski 
261*9114700bSCezary Rojewski 	avs_path_free(data->path);
262*9114700bSCezary Rojewski 	data->path = NULL;
263*9114700bSCezary Rojewski 	snd_hdac_stream_cleanup(hdac_stream(host_stream));
264*9114700bSCezary Rojewski 	hdac_stream(host_stream)->prepared = false;
265*9114700bSCezary Rojewski 
266*9114700bSCezary Rojewski 	ret = snd_pcm_lib_free_pages(substream);
267*9114700bSCezary Rojewski 	if (ret < 0)
268*9114700bSCezary Rojewski 		dev_dbg(dai->dev, "Failed to free pages!\n");
269*9114700bSCezary Rojewski 
270*9114700bSCezary Rojewski 	return ret;
271*9114700bSCezary Rojewski }
272*9114700bSCezary Rojewski 
273*9114700bSCezary Rojewski static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
274*9114700bSCezary Rojewski {
275*9114700bSCezary Rojewski 	struct snd_pcm_runtime *runtime = substream->runtime;
276*9114700bSCezary Rojewski 	struct avs_dma_data *data;
277*9114700bSCezary Rojewski 	struct avs_dev *adev = to_avs_dev(dai->dev);
278*9114700bSCezary Rojewski 	struct hdac_ext_stream *host_stream;
279*9114700bSCezary Rojewski 	struct hdac_bus *bus;
280*9114700bSCezary Rojewski 	unsigned int format_val;
281*9114700bSCezary Rojewski 	int ret;
282*9114700bSCezary Rojewski 
283*9114700bSCezary Rojewski 	data = snd_soc_dai_get_dma_data(dai, substream);
284*9114700bSCezary Rojewski 	host_stream = data->host_stream;
285*9114700bSCezary Rojewski 
286*9114700bSCezary Rojewski 	if (hdac_stream(host_stream)->prepared)
287*9114700bSCezary Rojewski 		return 0;
288*9114700bSCezary Rojewski 
289*9114700bSCezary Rojewski 	bus = hdac_stream(host_stream)->bus;
290*9114700bSCezary Rojewski 	snd_hdac_ext_stream_decouple(bus, data->host_stream, true);
291*9114700bSCezary Rojewski 	snd_hdac_stream_reset(hdac_stream(host_stream));
292*9114700bSCezary Rojewski 
293*9114700bSCezary Rojewski 	format_val = snd_hdac_calc_stream_format(runtime->rate, runtime->channels, runtime->format,
294*9114700bSCezary Rojewski 						 runtime->sample_bits, 0);
295*9114700bSCezary Rojewski 
296*9114700bSCezary Rojewski 	ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);
297*9114700bSCezary Rojewski 	if (ret < 0)
298*9114700bSCezary Rojewski 		return ret;
299*9114700bSCezary Rojewski 
300*9114700bSCezary Rojewski 	ret = snd_hdac_stream_setup(hdac_stream(host_stream));
301*9114700bSCezary Rojewski 	if (ret < 0)
302*9114700bSCezary Rojewski 		return ret;
303*9114700bSCezary Rojewski 
304*9114700bSCezary Rojewski 	ret = avs_dai_prepare(adev, substream, dai);
305*9114700bSCezary Rojewski 	if (ret)
306*9114700bSCezary Rojewski 		return ret;
307*9114700bSCezary Rojewski 
308*9114700bSCezary Rojewski 	hdac_stream(host_stream)->prepared = true;
309*9114700bSCezary Rojewski 	return 0;
310*9114700bSCezary Rojewski }
311*9114700bSCezary Rojewski 
312*9114700bSCezary Rojewski static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
313*9114700bSCezary Rojewski {
314*9114700bSCezary Rojewski 	struct avs_dma_data *data;
315*9114700bSCezary Rojewski 	struct hdac_ext_stream *host_stream;
316*9114700bSCezary Rojewski 	struct hdac_bus *bus;
317*9114700bSCezary Rojewski 	unsigned long flags;
318*9114700bSCezary Rojewski 	int ret = 0;
319*9114700bSCezary Rojewski 
320*9114700bSCezary Rojewski 	data = snd_soc_dai_get_dma_data(dai, substream);
321*9114700bSCezary Rojewski 	host_stream = data->host_stream;
322*9114700bSCezary Rojewski 	bus = hdac_stream(host_stream)->bus;
323*9114700bSCezary Rojewski 
324*9114700bSCezary Rojewski 	switch (cmd) {
325*9114700bSCezary Rojewski 	case SNDRV_PCM_TRIGGER_START:
326*9114700bSCezary Rojewski 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
327*9114700bSCezary Rojewski 		spin_lock_irqsave(&bus->reg_lock, flags);
328*9114700bSCezary Rojewski 		snd_hdac_stream_start(hdac_stream(host_stream), true);
329*9114700bSCezary Rojewski 		spin_unlock_irqrestore(&bus->reg_lock, flags);
330*9114700bSCezary Rojewski 
331*9114700bSCezary Rojewski 		ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO);
332*9114700bSCezary Rojewski 		if (ret < 0)
333*9114700bSCezary Rojewski 			dev_err(dai->dev, "run FE path failed: %d\n", ret);
334*9114700bSCezary Rojewski 		break;
335*9114700bSCezary Rojewski 
336*9114700bSCezary Rojewski 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
337*9114700bSCezary Rojewski 	case SNDRV_PCM_TRIGGER_STOP:
338*9114700bSCezary Rojewski 		ret = avs_path_pause(data->path);
339*9114700bSCezary Rojewski 		if (ret < 0)
340*9114700bSCezary Rojewski 			dev_err(dai->dev, "pause FE path failed: %d\n", ret);
341*9114700bSCezary Rojewski 
342*9114700bSCezary Rojewski 		spin_lock_irqsave(&bus->reg_lock, flags);
343*9114700bSCezary Rojewski 		snd_hdac_stream_stop(hdac_stream(host_stream));
344*9114700bSCezary Rojewski 		spin_unlock_irqrestore(&bus->reg_lock, flags);
345*9114700bSCezary Rojewski 
346*9114700bSCezary Rojewski 		if (cmd == SNDRV_PCM_TRIGGER_STOP) {
347*9114700bSCezary Rojewski 			ret = avs_path_reset(data->path);
348*9114700bSCezary Rojewski 			if (ret < 0)
349*9114700bSCezary Rojewski 				dev_err(dai->dev, "reset FE path failed: %d\n", ret);
350*9114700bSCezary Rojewski 		}
351*9114700bSCezary Rojewski 		break;
352*9114700bSCezary Rojewski 
353*9114700bSCezary Rojewski 	default:
354*9114700bSCezary Rojewski 		ret = -EINVAL;
355*9114700bSCezary Rojewski 		break;
356*9114700bSCezary Rojewski 	}
357*9114700bSCezary Rojewski 
358*9114700bSCezary Rojewski 	return ret;
359*9114700bSCezary Rojewski }
360*9114700bSCezary Rojewski 
361*9114700bSCezary Rojewski const struct snd_soc_dai_ops avs_dai_fe_ops = {
362*9114700bSCezary Rojewski 	.startup = avs_dai_fe_startup,
363*9114700bSCezary Rojewski 	.shutdown = avs_dai_fe_shutdown,
364*9114700bSCezary Rojewski 	.hw_params = avs_dai_fe_hw_params,
365*9114700bSCezary Rojewski 	.hw_free = avs_dai_fe_hw_free,
366*9114700bSCezary Rojewski 	.prepare = avs_dai_fe_prepare,
367*9114700bSCezary Rojewski 	.trigger = avs_dai_fe_trigger,
368*9114700bSCezary Rojewski };
369*9114700bSCezary Rojewski 
370f1b3b320SCezary Rojewski static ssize_t topology_name_read(struct file *file, char __user *user_buf, size_t count,
371f1b3b320SCezary Rojewski 				  loff_t *ppos)
372f1b3b320SCezary Rojewski {
373f1b3b320SCezary Rojewski 	struct snd_soc_component *component = file->private_data;
374f1b3b320SCezary Rojewski 	struct snd_soc_card *card = component->card;
375f1b3b320SCezary Rojewski 	struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
376f1b3b320SCezary Rojewski 	char buf[64];
377f1b3b320SCezary Rojewski 	size_t len;
378f1b3b320SCezary Rojewski 
379f1b3b320SCezary Rojewski 	len = snprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix,
380f1b3b320SCezary Rojewski 		       mach->tplg_filename);
381f1b3b320SCezary Rojewski 
382f1b3b320SCezary Rojewski 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
383f1b3b320SCezary Rojewski }
384f1b3b320SCezary Rojewski 
385f1b3b320SCezary Rojewski static const struct file_operations topology_name_fops = {
386f1b3b320SCezary Rojewski 	.open = simple_open,
387f1b3b320SCezary Rojewski 	.read = topology_name_read,
388f1b3b320SCezary Rojewski 	.llseek = default_llseek,
389f1b3b320SCezary Rojewski };
390f1b3b320SCezary Rojewski 
391f1b3b320SCezary Rojewski static int avs_component_load_libraries(struct avs_soc_component *acomp)
392f1b3b320SCezary Rojewski {
393f1b3b320SCezary Rojewski 	struct avs_tplg *tplg = acomp->tplg;
394f1b3b320SCezary Rojewski 	struct avs_dev *adev = to_avs_dev(acomp->base.dev);
395f1b3b320SCezary Rojewski 	int ret;
396f1b3b320SCezary Rojewski 
397f1b3b320SCezary Rojewski 	if (!tplg->num_libs)
398f1b3b320SCezary Rojewski 		return 0;
399f1b3b320SCezary Rojewski 
400f1b3b320SCezary Rojewski 	/* Parent device may be asleep and library loading involves IPCs. */
401f1b3b320SCezary Rojewski 	ret = pm_runtime_resume_and_get(adev->dev);
402f1b3b320SCezary Rojewski 	if (ret < 0)
403f1b3b320SCezary Rojewski 		return ret;
404f1b3b320SCezary Rojewski 
405f1b3b320SCezary Rojewski 	avs_hda_clock_gating_enable(adev, false);
406f1b3b320SCezary Rojewski 	avs_hda_l1sen_enable(adev, false);
407f1b3b320SCezary Rojewski 
408f1b3b320SCezary Rojewski 	ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
409f1b3b320SCezary Rojewski 
410f1b3b320SCezary Rojewski 	avs_hda_l1sen_enable(adev, true);
411f1b3b320SCezary Rojewski 	avs_hda_clock_gating_enable(adev, true);
412f1b3b320SCezary Rojewski 
413f1b3b320SCezary Rojewski 	if (!ret)
414f1b3b320SCezary Rojewski 		ret = avs_module_info_init(adev, false);
415f1b3b320SCezary Rojewski 
416f1b3b320SCezary Rojewski 	pm_runtime_mark_last_busy(adev->dev);
417f1b3b320SCezary Rojewski 	pm_runtime_put_autosuspend(adev->dev);
418f1b3b320SCezary Rojewski 
419f1b3b320SCezary Rojewski 	return ret;
420f1b3b320SCezary Rojewski }
421f1b3b320SCezary Rojewski 
422f1b3b320SCezary Rojewski static int avs_component_probe(struct snd_soc_component *component)
423f1b3b320SCezary Rojewski {
424f1b3b320SCezary Rojewski 	struct snd_soc_card *card = component->card;
425f1b3b320SCezary Rojewski 	struct snd_soc_acpi_mach *mach;
426f1b3b320SCezary Rojewski 	struct avs_soc_component *acomp;
427f1b3b320SCezary Rojewski 	struct avs_dev *adev;
428f1b3b320SCezary Rojewski 	char *filename;
429f1b3b320SCezary Rojewski 	int ret;
430f1b3b320SCezary Rojewski 
431f1b3b320SCezary Rojewski 	dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name);
432f1b3b320SCezary Rojewski 	mach = dev_get_platdata(card->dev);
433f1b3b320SCezary Rojewski 	acomp = to_avs_soc_component(component);
434f1b3b320SCezary Rojewski 	adev = to_avs_dev(component->dev);
435f1b3b320SCezary Rojewski 
436f1b3b320SCezary Rojewski 	acomp->tplg = avs_tplg_new(component);
437f1b3b320SCezary Rojewski 	if (!acomp->tplg)
438f1b3b320SCezary Rojewski 		return -ENOMEM;
439f1b3b320SCezary Rojewski 
440f1b3b320SCezary Rojewski 	if (!mach->tplg_filename)
441f1b3b320SCezary Rojewski 		goto finalize;
442f1b3b320SCezary Rojewski 
443f1b3b320SCezary Rojewski 	/* Load specified topology and create debugfs for it. */
444f1b3b320SCezary Rojewski 	filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
445f1b3b320SCezary Rojewski 			     mach->tplg_filename);
446f1b3b320SCezary Rojewski 	if (!filename)
447f1b3b320SCezary Rojewski 		return -ENOMEM;
448f1b3b320SCezary Rojewski 
449f1b3b320SCezary Rojewski 	ret = avs_load_topology(component, filename);
450f1b3b320SCezary Rojewski 	kfree(filename);
451f1b3b320SCezary Rojewski 	if (ret < 0)
452f1b3b320SCezary Rojewski 		return ret;
453f1b3b320SCezary Rojewski 
454f1b3b320SCezary Rojewski 	ret = avs_component_load_libraries(acomp);
455f1b3b320SCezary Rojewski 	if (ret < 0) {
456f1b3b320SCezary Rojewski 		dev_err(card->dev, "libraries loading failed: %d\n", ret);
457f1b3b320SCezary Rojewski 		goto err_load_libs;
458f1b3b320SCezary Rojewski 	}
459f1b3b320SCezary Rojewski 
460f1b3b320SCezary Rojewski finalize:
461f1b3b320SCezary Rojewski 	debugfs_create_file("topology_name", 0444, component->debugfs_root, component,
462f1b3b320SCezary Rojewski 			    &topology_name_fops);
463f1b3b320SCezary Rojewski 
464f1b3b320SCezary Rojewski 	mutex_lock(&adev->comp_list_mutex);
465f1b3b320SCezary Rojewski 	list_add_tail(&acomp->node, &adev->comp_list);
466f1b3b320SCezary Rojewski 	mutex_unlock(&adev->comp_list_mutex);
467f1b3b320SCezary Rojewski 
468f1b3b320SCezary Rojewski 	return 0;
469f1b3b320SCezary Rojewski 
470f1b3b320SCezary Rojewski err_load_libs:
471f1b3b320SCezary Rojewski 	avs_remove_topology(component);
472f1b3b320SCezary Rojewski 	return ret;
473f1b3b320SCezary Rojewski }
474f1b3b320SCezary Rojewski 
475f1b3b320SCezary Rojewski static void avs_component_remove(struct snd_soc_component *component)
476f1b3b320SCezary Rojewski {
477f1b3b320SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(component);
478f1b3b320SCezary Rojewski 	struct snd_soc_acpi_mach *mach;
479f1b3b320SCezary Rojewski 	struct avs_dev *adev = to_avs_dev(component->dev);
480f1b3b320SCezary Rojewski 	int ret;
481f1b3b320SCezary Rojewski 
482f1b3b320SCezary Rojewski 	mach = dev_get_platdata(component->card->dev);
483f1b3b320SCezary Rojewski 
484f1b3b320SCezary Rojewski 	mutex_lock(&adev->comp_list_mutex);
485f1b3b320SCezary Rojewski 	list_del(&acomp->node);
486f1b3b320SCezary Rojewski 	mutex_unlock(&adev->comp_list_mutex);
487f1b3b320SCezary Rojewski 
488f1b3b320SCezary Rojewski 	if (mach->tplg_filename) {
489f1b3b320SCezary Rojewski 		ret = avs_remove_topology(component);
490f1b3b320SCezary Rojewski 		if (ret < 0)
491f1b3b320SCezary Rojewski 			dev_err(component->dev, "unload topology failed: %d\n", ret);
492f1b3b320SCezary Rojewski 	}
493f1b3b320SCezary Rojewski }
494f1b3b320SCezary Rojewski 
495f1b3b320SCezary Rojewski static int avs_component_open(struct snd_soc_component *component,
496f1b3b320SCezary Rojewski 			      struct snd_pcm_substream *substream)
497f1b3b320SCezary Rojewski {
498f1b3b320SCezary Rojewski 	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
499f1b3b320SCezary Rojewski 	struct snd_pcm_hardware hwparams;
500f1b3b320SCezary Rojewski 
501f1b3b320SCezary Rojewski 	/* only FE DAI links are handled here */
502f1b3b320SCezary Rojewski 	if (rtd->dai_link->no_pcm)
503f1b3b320SCezary Rojewski 		return 0;
504f1b3b320SCezary Rojewski 
505f1b3b320SCezary Rojewski 	hwparams.info = SNDRV_PCM_INFO_MMAP |
506f1b3b320SCezary Rojewski 			SNDRV_PCM_INFO_MMAP_VALID |
507f1b3b320SCezary Rojewski 			SNDRV_PCM_INFO_INTERLEAVED |
508f1b3b320SCezary Rojewski 			SNDRV_PCM_INFO_PAUSE |
509f1b3b320SCezary Rojewski 			SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
510f1b3b320SCezary Rojewski 
511f1b3b320SCezary Rojewski 	hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE |
512f1b3b320SCezary Rojewski 			   SNDRV_PCM_FMTBIT_S24_LE |
513f1b3b320SCezary Rojewski 			   SNDRV_PCM_FMTBIT_S32_LE;
514f1b3b320SCezary Rojewski 	hwparams.period_bytes_min = 128;
515f1b3b320SCezary Rojewski 	hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2;
516f1b3b320SCezary Rojewski 	hwparams.periods_min = 2;
517f1b3b320SCezary Rojewski 	hwparams.periods_max = AZX_MAX_FRAG;
518f1b3b320SCezary Rojewski 	hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE;
519f1b3b320SCezary Rojewski 	hwparams.fifo_size = 0;
520f1b3b320SCezary Rojewski 
521f1b3b320SCezary Rojewski 	return snd_soc_set_runtime_hwparams(substream, &hwparams);
522f1b3b320SCezary Rojewski }
523f1b3b320SCezary Rojewski 
524f1b3b320SCezary Rojewski static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream)
525f1b3b320SCezary Rojewski {
526f1b3b320SCezary Rojewski 	return readl(hdac_stream(stream)->bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
527f1b3b320SCezary Rojewski 		     (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(stream)->index));
528f1b3b320SCezary Rojewski }
529f1b3b320SCezary Rojewski 
530f1b3b320SCezary Rojewski static snd_pcm_uframes_t
531f1b3b320SCezary Rojewski avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream)
532f1b3b320SCezary Rojewski {
533f1b3b320SCezary Rojewski 	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
534f1b3b320SCezary Rojewski 	struct avs_dma_data *data;
535f1b3b320SCezary Rojewski 	struct hdac_ext_stream *host_stream;
536f1b3b320SCezary Rojewski 	unsigned int pos;
537f1b3b320SCezary Rojewski 
538f1b3b320SCezary Rojewski 	data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
539f1b3b320SCezary Rojewski 	if (!data->host_stream)
540f1b3b320SCezary Rojewski 		return 0;
541f1b3b320SCezary Rojewski 
542f1b3b320SCezary Rojewski 	host_stream = data->host_stream;
543f1b3b320SCezary Rojewski 	pos = avs_hda_stream_dpib_read(host_stream);
544f1b3b320SCezary Rojewski 
545f1b3b320SCezary Rojewski 	if (pos >= hdac_stream(host_stream)->bufsize)
546f1b3b320SCezary Rojewski 		pos = 0;
547f1b3b320SCezary Rojewski 
548f1b3b320SCezary Rojewski 	return bytes_to_frames(substream->runtime, pos);
549f1b3b320SCezary Rojewski }
550f1b3b320SCezary Rojewski 
551f1b3b320SCezary Rojewski static int avs_component_mmap(struct snd_soc_component *component,
552f1b3b320SCezary Rojewski 			      struct snd_pcm_substream *substream,
553f1b3b320SCezary Rojewski 			      struct vm_area_struct *vma)
554f1b3b320SCezary Rojewski {
555f1b3b320SCezary Rojewski 	return snd_pcm_lib_default_mmap(substream, vma);
556f1b3b320SCezary Rojewski }
557f1b3b320SCezary Rojewski 
558f1b3b320SCezary Rojewski #define MAX_PREALLOC_SIZE	(32 * 1024 * 1024)
559f1b3b320SCezary Rojewski 
560f1b3b320SCezary Rojewski static int avs_component_construct(struct snd_soc_component *component,
561f1b3b320SCezary Rojewski 				   struct snd_soc_pcm_runtime *rtd)
562f1b3b320SCezary Rojewski {
563f1b3b320SCezary Rojewski 	struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
564f1b3b320SCezary Rojewski 	struct snd_pcm *pcm = rtd->pcm;
565f1b3b320SCezary Rojewski 
566f1b3b320SCezary Rojewski 	if (dai->driver->playback.channels_min)
567f1b3b320SCezary Rojewski 		snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
568f1b3b320SCezary Rojewski 					   SNDRV_DMA_TYPE_DEV_SG, component->dev, 0,
569f1b3b320SCezary Rojewski 					   MAX_PREALLOC_SIZE);
570f1b3b320SCezary Rojewski 
571f1b3b320SCezary Rojewski 	if (dai->driver->capture.channels_min)
572f1b3b320SCezary Rojewski 		snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
573f1b3b320SCezary Rojewski 					   SNDRV_DMA_TYPE_DEV_SG, component->dev, 0,
574f1b3b320SCezary Rojewski 					   MAX_PREALLOC_SIZE);
575f1b3b320SCezary Rojewski 
576f1b3b320SCezary Rojewski 	return 0;
577f1b3b320SCezary Rojewski }
578f1b3b320SCezary Rojewski 
579f1b3b320SCezary Rojewski static const struct snd_soc_component_driver avs_component_driver = {
580f1b3b320SCezary Rojewski 	.name			= "avs-pcm",
581f1b3b320SCezary Rojewski 	.probe			= avs_component_probe,
582f1b3b320SCezary Rojewski 	.remove			= avs_component_remove,
583f1b3b320SCezary Rojewski 	.open			= avs_component_open,
584f1b3b320SCezary Rojewski 	.pointer		= avs_component_pointer,
585f1b3b320SCezary Rojewski 	.mmap			= avs_component_mmap,
586f1b3b320SCezary Rojewski 	.pcm_construct		= avs_component_construct,
587f1b3b320SCezary Rojewski 	.module_get_upon_open	= 1, /* increment refcount when a pcm is opened */
588f1b3b320SCezary Rojewski 	.topology_name_prefix	= "intel/avs",
589f1b3b320SCezary Rojewski 	.non_legacy_dai_naming	= true,
590f1b3b320SCezary Rojewski };
591f1b3b320SCezary Rojewski 
592f1b3b320SCezary Rojewski __maybe_unused
593f1b3b320SCezary Rojewski static int avs_soc_component_register(struct device *dev, const char *name,
594f1b3b320SCezary Rojewski 				      const struct snd_soc_component_driver *drv,
595f1b3b320SCezary Rojewski 				      struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
596f1b3b320SCezary Rojewski {
597f1b3b320SCezary Rojewski 	struct avs_soc_component *acomp;
598f1b3b320SCezary Rojewski 	int ret;
599f1b3b320SCezary Rojewski 
600f1b3b320SCezary Rojewski 	acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL);
601f1b3b320SCezary Rojewski 	if (!acomp)
602f1b3b320SCezary Rojewski 		return -ENOMEM;
603f1b3b320SCezary Rojewski 
604f1b3b320SCezary Rojewski 	ret = snd_soc_component_initialize(&acomp->base, drv, dev);
605f1b3b320SCezary Rojewski 	if (ret < 0)
606f1b3b320SCezary Rojewski 		return ret;
607f1b3b320SCezary Rojewski 
608f1b3b320SCezary Rojewski 	/* force name change after ASoC is done with its init */
609f1b3b320SCezary Rojewski 	acomp->base.name = name;
610f1b3b320SCezary Rojewski 	INIT_LIST_HEAD(&acomp->node);
611f1b3b320SCezary Rojewski 
612f1b3b320SCezary Rojewski 	return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);
613f1b3b320SCezary Rojewski }
614