xref: /openbmc/linux/sound/soc/intel/avs/pcm.c (revision f1b3b320bd6519b16e3480f74f2926d106e3bcba)
1*f1b3b320SCezary Rojewski // SPDX-License-Identifier: GPL-2.0-only
2*f1b3b320SCezary Rojewski //
3*f1b3b320SCezary Rojewski // Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
4*f1b3b320SCezary Rojewski //
5*f1b3b320SCezary Rojewski // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6*f1b3b320SCezary Rojewski //          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
7*f1b3b320SCezary Rojewski //
8*f1b3b320SCezary Rojewski 
9*f1b3b320SCezary Rojewski #include <linux/debugfs.h>
10*f1b3b320SCezary Rojewski #include <linux/device.h>
11*f1b3b320SCezary Rojewski #include <sound/hda_register.h>
12*f1b3b320SCezary Rojewski #include <sound/hdaudio_ext.h>
13*f1b3b320SCezary Rojewski #include <sound/soc-acpi.h>
14*f1b3b320SCezary Rojewski #include <sound/soc-acpi-intel-match.h>
15*f1b3b320SCezary Rojewski #include <sound/soc-component.h>
16*f1b3b320SCezary Rojewski #include "avs.h"
17*f1b3b320SCezary Rojewski #include "path.h"
18*f1b3b320SCezary Rojewski #include "topology.h"
19*f1b3b320SCezary Rojewski 
20*f1b3b320SCezary Rojewski struct avs_dma_data {
21*f1b3b320SCezary Rojewski 	struct avs_tplg_path_template *template;
22*f1b3b320SCezary Rojewski 	struct avs_path *path;
23*f1b3b320SCezary Rojewski 	/*
24*f1b3b320SCezary Rojewski 	 * link stream is stored within substream's runtime
25*f1b3b320SCezary Rojewski 	 * private_data to fulfill the needs of codec BE path
26*f1b3b320SCezary Rojewski 	 *
27*f1b3b320SCezary Rojewski 	 * host stream assigned
28*f1b3b320SCezary Rojewski 	 */
29*f1b3b320SCezary Rojewski 	struct hdac_ext_stream *host_stream;
30*f1b3b320SCezary Rojewski };
31*f1b3b320SCezary Rojewski 
32*f1b3b320SCezary Rojewski static ssize_t topology_name_read(struct file *file, char __user *user_buf, size_t count,
33*f1b3b320SCezary Rojewski 				  loff_t *ppos)
34*f1b3b320SCezary Rojewski {
35*f1b3b320SCezary Rojewski 	struct snd_soc_component *component = file->private_data;
36*f1b3b320SCezary Rojewski 	struct snd_soc_card *card = component->card;
37*f1b3b320SCezary Rojewski 	struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);
38*f1b3b320SCezary Rojewski 	char buf[64];
39*f1b3b320SCezary Rojewski 	size_t len;
40*f1b3b320SCezary Rojewski 
41*f1b3b320SCezary Rojewski 	len = snprintf(buf, sizeof(buf), "%s/%s\n", component->driver->topology_name_prefix,
42*f1b3b320SCezary Rojewski 		       mach->tplg_filename);
43*f1b3b320SCezary Rojewski 
44*f1b3b320SCezary Rojewski 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
45*f1b3b320SCezary Rojewski }
46*f1b3b320SCezary Rojewski 
47*f1b3b320SCezary Rojewski static const struct file_operations topology_name_fops = {
48*f1b3b320SCezary Rojewski 	.open = simple_open,
49*f1b3b320SCezary Rojewski 	.read = topology_name_read,
50*f1b3b320SCezary Rojewski 	.llseek = default_llseek,
51*f1b3b320SCezary Rojewski };
52*f1b3b320SCezary Rojewski 
53*f1b3b320SCezary Rojewski static int avs_component_load_libraries(struct avs_soc_component *acomp)
54*f1b3b320SCezary Rojewski {
55*f1b3b320SCezary Rojewski 	struct avs_tplg *tplg = acomp->tplg;
56*f1b3b320SCezary Rojewski 	struct avs_dev *adev = to_avs_dev(acomp->base.dev);
57*f1b3b320SCezary Rojewski 	int ret;
58*f1b3b320SCezary Rojewski 
59*f1b3b320SCezary Rojewski 	if (!tplg->num_libs)
60*f1b3b320SCezary Rojewski 		return 0;
61*f1b3b320SCezary Rojewski 
62*f1b3b320SCezary Rojewski 	/* Parent device may be asleep and library loading involves IPCs. */
63*f1b3b320SCezary Rojewski 	ret = pm_runtime_resume_and_get(adev->dev);
64*f1b3b320SCezary Rojewski 	if (ret < 0)
65*f1b3b320SCezary Rojewski 		return ret;
66*f1b3b320SCezary Rojewski 
67*f1b3b320SCezary Rojewski 	avs_hda_clock_gating_enable(adev, false);
68*f1b3b320SCezary Rojewski 	avs_hda_l1sen_enable(adev, false);
69*f1b3b320SCezary Rojewski 
70*f1b3b320SCezary Rojewski 	ret = avs_dsp_load_libraries(adev, tplg->libs, tplg->num_libs);
71*f1b3b320SCezary Rojewski 
72*f1b3b320SCezary Rojewski 	avs_hda_l1sen_enable(adev, true);
73*f1b3b320SCezary Rojewski 	avs_hda_clock_gating_enable(adev, true);
74*f1b3b320SCezary Rojewski 
75*f1b3b320SCezary Rojewski 	if (!ret)
76*f1b3b320SCezary Rojewski 		ret = avs_module_info_init(adev, false);
77*f1b3b320SCezary Rojewski 
78*f1b3b320SCezary Rojewski 	pm_runtime_mark_last_busy(adev->dev);
79*f1b3b320SCezary Rojewski 	pm_runtime_put_autosuspend(adev->dev);
80*f1b3b320SCezary Rojewski 
81*f1b3b320SCezary Rojewski 	return ret;
82*f1b3b320SCezary Rojewski }
83*f1b3b320SCezary Rojewski 
84*f1b3b320SCezary Rojewski static int avs_component_probe(struct snd_soc_component *component)
85*f1b3b320SCezary Rojewski {
86*f1b3b320SCezary Rojewski 	struct snd_soc_card *card = component->card;
87*f1b3b320SCezary Rojewski 	struct snd_soc_acpi_mach *mach;
88*f1b3b320SCezary Rojewski 	struct avs_soc_component *acomp;
89*f1b3b320SCezary Rojewski 	struct avs_dev *adev;
90*f1b3b320SCezary Rojewski 	char *filename;
91*f1b3b320SCezary Rojewski 	int ret;
92*f1b3b320SCezary Rojewski 
93*f1b3b320SCezary Rojewski 	dev_dbg(card->dev, "probing %s card %s\n", component->name, card->name);
94*f1b3b320SCezary Rojewski 	mach = dev_get_platdata(card->dev);
95*f1b3b320SCezary Rojewski 	acomp = to_avs_soc_component(component);
96*f1b3b320SCezary Rojewski 	adev = to_avs_dev(component->dev);
97*f1b3b320SCezary Rojewski 
98*f1b3b320SCezary Rojewski 	acomp->tplg = avs_tplg_new(component);
99*f1b3b320SCezary Rojewski 	if (!acomp->tplg)
100*f1b3b320SCezary Rojewski 		return -ENOMEM;
101*f1b3b320SCezary Rojewski 
102*f1b3b320SCezary Rojewski 	if (!mach->tplg_filename)
103*f1b3b320SCezary Rojewski 		goto finalize;
104*f1b3b320SCezary Rojewski 
105*f1b3b320SCezary Rojewski 	/* Load specified topology and create debugfs for it. */
106*f1b3b320SCezary Rojewski 	filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix,
107*f1b3b320SCezary Rojewski 			     mach->tplg_filename);
108*f1b3b320SCezary Rojewski 	if (!filename)
109*f1b3b320SCezary Rojewski 		return -ENOMEM;
110*f1b3b320SCezary Rojewski 
111*f1b3b320SCezary Rojewski 	ret = avs_load_topology(component, filename);
112*f1b3b320SCezary Rojewski 	kfree(filename);
113*f1b3b320SCezary Rojewski 	if (ret < 0)
114*f1b3b320SCezary Rojewski 		return ret;
115*f1b3b320SCezary Rojewski 
116*f1b3b320SCezary Rojewski 	ret = avs_component_load_libraries(acomp);
117*f1b3b320SCezary Rojewski 	if (ret < 0) {
118*f1b3b320SCezary Rojewski 		dev_err(card->dev, "libraries loading failed: %d\n", ret);
119*f1b3b320SCezary Rojewski 		goto err_load_libs;
120*f1b3b320SCezary Rojewski 	}
121*f1b3b320SCezary Rojewski 
122*f1b3b320SCezary Rojewski finalize:
123*f1b3b320SCezary Rojewski 	debugfs_create_file("topology_name", 0444, component->debugfs_root, component,
124*f1b3b320SCezary Rojewski 			    &topology_name_fops);
125*f1b3b320SCezary Rojewski 
126*f1b3b320SCezary Rojewski 	mutex_lock(&adev->comp_list_mutex);
127*f1b3b320SCezary Rojewski 	list_add_tail(&acomp->node, &adev->comp_list);
128*f1b3b320SCezary Rojewski 	mutex_unlock(&adev->comp_list_mutex);
129*f1b3b320SCezary Rojewski 
130*f1b3b320SCezary Rojewski 	return 0;
131*f1b3b320SCezary Rojewski 
132*f1b3b320SCezary Rojewski err_load_libs:
133*f1b3b320SCezary Rojewski 	avs_remove_topology(component);
134*f1b3b320SCezary Rojewski 	return ret;
135*f1b3b320SCezary Rojewski }
136*f1b3b320SCezary Rojewski 
137*f1b3b320SCezary Rojewski static void avs_component_remove(struct snd_soc_component *component)
138*f1b3b320SCezary Rojewski {
139*f1b3b320SCezary Rojewski 	struct avs_soc_component *acomp = to_avs_soc_component(component);
140*f1b3b320SCezary Rojewski 	struct snd_soc_acpi_mach *mach;
141*f1b3b320SCezary Rojewski 	struct avs_dev *adev = to_avs_dev(component->dev);
142*f1b3b320SCezary Rojewski 	int ret;
143*f1b3b320SCezary Rojewski 
144*f1b3b320SCezary Rojewski 	mach = dev_get_platdata(component->card->dev);
145*f1b3b320SCezary Rojewski 
146*f1b3b320SCezary Rojewski 	mutex_lock(&adev->comp_list_mutex);
147*f1b3b320SCezary Rojewski 	list_del(&acomp->node);
148*f1b3b320SCezary Rojewski 	mutex_unlock(&adev->comp_list_mutex);
149*f1b3b320SCezary Rojewski 
150*f1b3b320SCezary Rojewski 	if (mach->tplg_filename) {
151*f1b3b320SCezary Rojewski 		ret = avs_remove_topology(component);
152*f1b3b320SCezary Rojewski 		if (ret < 0)
153*f1b3b320SCezary Rojewski 			dev_err(component->dev, "unload topology failed: %d\n", ret);
154*f1b3b320SCezary Rojewski 	}
155*f1b3b320SCezary Rojewski }
156*f1b3b320SCezary Rojewski 
157*f1b3b320SCezary Rojewski static int avs_component_open(struct snd_soc_component *component,
158*f1b3b320SCezary Rojewski 			      struct snd_pcm_substream *substream)
159*f1b3b320SCezary Rojewski {
160*f1b3b320SCezary Rojewski 	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
161*f1b3b320SCezary Rojewski 	struct snd_pcm_hardware hwparams;
162*f1b3b320SCezary Rojewski 
163*f1b3b320SCezary Rojewski 	/* only FE DAI links are handled here */
164*f1b3b320SCezary Rojewski 	if (rtd->dai_link->no_pcm)
165*f1b3b320SCezary Rojewski 		return 0;
166*f1b3b320SCezary Rojewski 
167*f1b3b320SCezary Rojewski 	hwparams.info = SNDRV_PCM_INFO_MMAP |
168*f1b3b320SCezary Rojewski 			SNDRV_PCM_INFO_MMAP_VALID |
169*f1b3b320SCezary Rojewski 			SNDRV_PCM_INFO_INTERLEAVED |
170*f1b3b320SCezary Rojewski 			SNDRV_PCM_INFO_PAUSE |
171*f1b3b320SCezary Rojewski 			SNDRV_PCM_INFO_NO_PERIOD_WAKEUP;
172*f1b3b320SCezary Rojewski 
173*f1b3b320SCezary Rojewski 	hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE |
174*f1b3b320SCezary Rojewski 			   SNDRV_PCM_FMTBIT_S24_LE |
175*f1b3b320SCezary Rojewski 			   SNDRV_PCM_FMTBIT_S32_LE;
176*f1b3b320SCezary Rojewski 	hwparams.period_bytes_min = 128;
177*f1b3b320SCezary Rojewski 	hwparams.period_bytes_max = AZX_MAX_BUF_SIZE / 2;
178*f1b3b320SCezary Rojewski 	hwparams.periods_min = 2;
179*f1b3b320SCezary Rojewski 	hwparams.periods_max = AZX_MAX_FRAG;
180*f1b3b320SCezary Rojewski 	hwparams.buffer_bytes_max = AZX_MAX_BUF_SIZE;
181*f1b3b320SCezary Rojewski 	hwparams.fifo_size = 0;
182*f1b3b320SCezary Rojewski 
183*f1b3b320SCezary Rojewski 	return snd_soc_set_runtime_hwparams(substream, &hwparams);
184*f1b3b320SCezary Rojewski }
185*f1b3b320SCezary Rojewski 
186*f1b3b320SCezary Rojewski static unsigned int avs_hda_stream_dpib_read(struct hdac_ext_stream *stream)
187*f1b3b320SCezary Rojewski {
188*f1b3b320SCezary Rojewski 	return readl(hdac_stream(stream)->bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE +
189*f1b3b320SCezary Rojewski 		     (AZX_REG_VS_SDXDPIB_XINTERVAL * hdac_stream(stream)->index));
190*f1b3b320SCezary Rojewski }
191*f1b3b320SCezary Rojewski 
192*f1b3b320SCezary Rojewski static snd_pcm_uframes_t
193*f1b3b320SCezary Rojewski avs_component_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream)
194*f1b3b320SCezary Rojewski {
195*f1b3b320SCezary Rojewski 	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
196*f1b3b320SCezary Rojewski 	struct avs_dma_data *data;
197*f1b3b320SCezary Rojewski 	struct hdac_ext_stream *host_stream;
198*f1b3b320SCezary Rojewski 	unsigned int pos;
199*f1b3b320SCezary Rojewski 
200*f1b3b320SCezary Rojewski 	data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
201*f1b3b320SCezary Rojewski 	if (!data->host_stream)
202*f1b3b320SCezary Rojewski 		return 0;
203*f1b3b320SCezary Rojewski 
204*f1b3b320SCezary Rojewski 	host_stream = data->host_stream;
205*f1b3b320SCezary Rojewski 	pos = avs_hda_stream_dpib_read(host_stream);
206*f1b3b320SCezary Rojewski 
207*f1b3b320SCezary Rojewski 	if (pos >= hdac_stream(host_stream)->bufsize)
208*f1b3b320SCezary Rojewski 		pos = 0;
209*f1b3b320SCezary Rojewski 
210*f1b3b320SCezary Rojewski 	return bytes_to_frames(substream->runtime, pos);
211*f1b3b320SCezary Rojewski }
212*f1b3b320SCezary Rojewski 
213*f1b3b320SCezary Rojewski static int avs_component_mmap(struct snd_soc_component *component,
214*f1b3b320SCezary Rojewski 			      struct snd_pcm_substream *substream,
215*f1b3b320SCezary Rojewski 			      struct vm_area_struct *vma)
216*f1b3b320SCezary Rojewski {
217*f1b3b320SCezary Rojewski 	return snd_pcm_lib_default_mmap(substream, vma);
218*f1b3b320SCezary Rojewski }
219*f1b3b320SCezary Rojewski 
220*f1b3b320SCezary Rojewski #define MAX_PREALLOC_SIZE	(32 * 1024 * 1024)
221*f1b3b320SCezary Rojewski 
222*f1b3b320SCezary Rojewski static int avs_component_construct(struct snd_soc_component *component,
223*f1b3b320SCezary Rojewski 				   struct snd_soc_pcm_runtime *rtd)
224*f1b3b320SCezary Rojewski {
225*f1b3b320SCezary Rojewski 	struct snd_soc_dai *dai = asoc_rtd_to_cpu(rtd, 0);
226*f1b3b320SCezary Rojewski 	struct snd_pcm *pcm = rtd->pcm;
227*f1b3b320SCezary Rojewski 
228*f1b3b320SCezary Rojewski 	if (dai->driver->playback.channels_min)
229*f1b3b320SCezary Rojewski 		snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
230*f1b3b320SCezary Rojewski 					   SNDRV_DMA_TYPE_DEV_SG, component->dev, 0,
231*f1b3b320SCezary Rojewski 					   MAX_PREALLOC_SIZE);
232*f1b3b320SCezary Rojewski 
233*f1b3b320SCezary Rojewski 	if (dai->driver->capture.channels_min)
234*f1b3b320SCezary Rojewski 		snd_pcm_set_managed_buffer(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
235*f1b3b320SCezary Rojewski 					   SNDRV_DMA_TYPE_DEV_SG, component->dev, 0,
236*f1b3b320SCezary Rojewski 					   MAX_PREALLOC_SIZE);
237*f1b3b320SCezary Rojewski 
238*f1b3b320SCezary Rojewski 	return 0;
239*f1b3b320SCezary Rojewski }
240*f1b3b320SCezary Rojewski 
241*f1b3b320SCezary Rojewski static const struct snd_soc_component_driver avs_component_driver = {
242*f1b3b320SCezary Rojewski 	.name			= "avs-pcm",
243*f1b3b320SCezary Rojewski 	.probe			= avs_component_probe,
244*f1b3b320SCezary Rojewski 	.remove			= avs_component_remove,
245*f1b3b320SCezary Rojewski 	.open			= avs_component_open,
246*f1b3b320SCezary Rojewski 	.pointer		= avs_component_pointer,
247*f1b3b320SCezary Rojewski 	.mmap			= avs_component_mmap,
248*f1b3b320SCezary Rojewski 	.pcm_construct		= avs_component_construct,
249*f1b3b320SCezary Rojewski 	.module_get_upon_open	= 1, /* increment refcount when a pcm is opened */
250*f1b3b320SCezary Rojewski 	.topology_name_prefix	= "intel/avs",
251*f1b3b320SCezary Rojewski 	.non_legacy_dai_naming	= true,
252*f1b3b320SCezary Rojewski };
253*f1b3b320SCezary Rojewski 
254*f1b3b320SCezary Rojewski __maybe_unused
255*f1b3b320SCezary Rojewski static int avs_soc_component_register(struct device *dev, const char *name,
256*f1b3b320SCezary Rojewski 				      const struct snd_soc_component_driver *drv,
257*f1b3b320SCezary Rojewski 				      struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais)
258*f1b3b320SCezary Rojewski {
259*f1b3b320SCezary Rojewski 	struct avs_soc_component *acomp;
260*f1b3b320SCezary Rojewski 	int ret;
261*f1b3b320SCezary Rojewski 
262*f1b3b320SCezary Rojewski 	acomp = devm_kzalloc(dev, sizeof(*acomp), GFP_KERNEL);
263*f1b3b320SCezary Rojewski 	if (!acomp)
264*f1b3b320SCezary Rojewski 		return -ENOMEM;
265*f1b3b320SCezary Rojewski 
266*f1b3b320SCezary Rojewski 	ret = snd_soc_component_initialize(&acomp->base, drv, dev);
267*f1b3b320SCezary Rojewski 	if (ret < 0)
268*f1b3b320SCezary Rojewski 		return ret;
269*f1b3b320SCezary Rojewski 
270*f1b3b320SCezary Rojewski 	/* force name change after ASoC is done with its init */
271*f1b3b320SCezary Rojewski 	acomp->base.name = name;
272*f1b3b320SCezary Rojewski 	INIT_LIST_HEAD(&acomp->node);
273*f1b3b320SCezary Rojewski 
274*f1b3b320SCezary Rojewski 	return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais);
275*f1b3b320SCezary Rojewski }
276