]> Git Repo - linux.git/blob - sound/soc/intel/avs/probes.c
Linux 6.14-rc3
[linux.git] / sound / soc / intel / avs / probes.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // Copyright(c) 2021-2022 Intel Corporation
4 //
5 // Authors: Cezary Rojewski <[email protected]>
6 //          Amadeusz Slawinski <[email protected]>
7 //
8
9 #include <sound/compress_driver.h>
10 #include <sound/hdaudio_ext.h>
11 #include <sound/hdaudio.h>
12 #include <sound/soc.h>
13 #include "avs.h"
14 #include "messages.h"
15
16 static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id,
17                               size_t buffer_size)
18 {
19         struct avs_probe_cfg cfg = {{0}};
20         struct avs_module_entry mentry;
21         u8 dummy;
22         int ret;
23
24         ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
25         if (ret)
26                 return ret;
27
28         /*
29          * Probe module uses no cycles, audio data format and input and output
30          * frame sizes are unused. It is also not owned by any pipeline.
31          */
32         cfg.base.ibs = 1;
33         /* BSS module descriptor is always segment of index=2. */
34         cfg.base.is_pages = mentry.segments[2].flags.length;
35         cfg.gtw_cfg.node_id = node_id;
36         cfg.gtw_cfg.dma_buffer_size = buffer_size;
37
38         return avs_dsp_init_module(adev, mentry.module_id, INVALID_PIPELINE_ID, 0, 0, &cfg,
39                                    sizeof(cfg), &dummy);
40 }
41
42 static void avs_dsp_delete_probe(struct avs_dev *adev)
43 {
44         struct avs_module_entry mentry;
45         int ret;
46
47         ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry);
48         if (!ret)
49                 /* There is only ever one probe module instance. */
50                 avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0);
51 }
52
53 static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream)
54 {
55         return cstream->runtime->private_data;
56 }
57
58 static int avs_probe_compr_open(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
59 {
60         struct avs_dev *adev = to_avs_dev(dai->dev);
61         struct hdac_bus *bus = &adev->base.core;
62         struct hdac_ext_stream *host_stream;
63
64         if (adev->extractor) {
65                 dev_err(dai->dev, "Cannot open more than one extractor stream\n");
66                 return -EEXIST;
67         }
68
69         host_stream = snd_hdac_ext_cstream_assign(bus, cstream);
70         if (!host_stream) {
71                 dev_err(dai->dev, "Failed to assign HDAudio stream for extraction\n");
72                 return -EBUSY;
73         }
74
75         adev->extractor = host_stream;
76         hdac_stream(host_stream)->curr_pos = 0;
77         cstream->runtime->private_data = host_stream;
78
79         return 0;
80 }
81
82 static int avs_probe_compr_free(struct snd_compr_stream *cstream, struct snd_soc_dai *dai)
83 {
84         struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
85         struct avs_dev *adev = to_avs_dev(dai->dev);
86         struct avs_probe_point_desc *desc;
87         /* Extractor node identifier. */
88         unsigned int vindex = INVALID_NODE_ID.vindex;
89         size_t num_desc;
90         int i, ret;
91
92         /* Disconnect all probe points. */
93         ret = avs_ipc_probe_get_points(adev, &desc, &num_desc);
94         if (ret) {
95                 dev_err(dai->dev, "get probe points failed: %d\n", ret);
96                 ret = AVS_IPC_RET(ret);
97                 goto exit;
98         }
99
100         for (i = 0; i < num_desc; i++)
101                 if (desc[i].node_id.vindex == vindex)
102                         avs_ipc_probe_disconnect_points(adev, &desc[i].id, 1);
103         kfree(desc);
104
105 exit:
106         if (adev->num_probe_streams) {
107                 adev->num_probe_streams--;
108                 if (!adev->num_probe_streams) {
109                         avs_dsp_delete_probe(adev);
110                         avs_dsp_enable_d0ix(adev);
111                 }
112         }
113
114         snd_hdac_stream_cleanup(hdac_stream(host_stream));
115         hdac_stream(host_stream)->prepared = 0;
116         snd_hdac_ext_stream_release(host_stream, HDAC_EXT_STREAM_TYPE_HOST);
117
118         snd_compr_free_pages(cstream);
119         adev->extractor = NULL;
120
121         return ret;
122 }
123
124 static int avs_probe_compr_set_params(struct snd_compr_stream *cstream,
125                                       struct snd_compr_params *params, struct snd_soc_dai *dai)
126 {
127         struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
128         struct snd_compr_runtime *rtd = cstream->runtime;
129         struct avs_dev *adev = to_avs_dev(dai->dev);
130         /* compr params do not store bit depth, default to S32_LE. */
131         snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE;
132         unsigned int format_val;
133         int bps, ret;
134
135         hdac_stream(host_stream)->bufsize = 0;
136         hdac_stream(host_stream)->period_bytes = 0;
137         hdac_stream(host_stream)->format_val = 0;
138         cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG;
139         cstream->dma_buffer.dev.dev = adev->dev;
140
141         ret = snd_compr_malloc_pages(cstream, rtd->buffer_size);
142         if (ret < 0)
143                 return ret;
144         bps = snd_pcm_format_physical_width(format);
145         if (bps < 0)
146                 return bps;
147         format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate);
148         ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val);
149         if (ret < 0)
150                 return ret;
151         ret = snd_hdac_stream_setup(hdac_stream(host_stream), false);
152         if (ret < 0)
153                 return ret;
154
155         hdac_stream(host_stream)->prepared = 1;
156
157         if (!adev->num_probe_streams) {
158                 union avs_connector_node_id node_id;
159
160                 /* D0ix not allowed during probing. */
161                 ret = avs_dsp_disable_d0ix(adev);
162                 if (ret)
163                         return ret;
164
165                 node_id.vindex = hdac_stream(host_stream)->stream_tag - 1;
166                 node_id.dma_type = AVS_DMA_HDA_HOST_INPUT;
167
168                 ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes);
169                 if (ret < 0) {
170                         dev_err(dai->dev, "probe init failed: %d\n", ret);
171                         avs_dsp_enable_d0ix(adev);
172                         return ret;
173                 }
174         }
175
176         adev->num_probe_streams++;
177         return 0;
178 }
179
180 static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd,
181                                    struct snd_soc_dai *dai)
182 {
183         struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
184         struct avs_dev *adev = to_avs_dev(dai->dev);
185         struct hdac_bus *bus = &adev->base.core;
186         unsigned long cookie;
187
188         if (!hdac_stream(host_stream)->prepared)
189                 return -EPIPE;
190
191         switch (cmd) {
192         case SNDRV_PCM_TRIGGER_START:
193         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
194         case SNDRV_PCM_TRIGGER_RESUME:
195                 spin_lock_irqsave(&bus->reg_lock, cookie);
196                 snd_hdac_stream_start(hdac_stream(host_stream));
197                 spin_unlock_irqrestore(&bus->reg_lock, cookie);
198                 break;
199
200         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
201         case SNDRV_PCM_TRIGGER_SUSPEND:
202         case SNDRV_PCM_TRIGGER_STOP:
203                 spin_lock_irqsave(&bus->reg_lock, cookie);
204                 snd_hdac_stream_stop(hdac_stream(host_stream));
205                 spin_unlock_irqrestore(&bus->reg_lock, cookie);
206                 break;
207
208         default:
209                 return -EINVAL;
210         }
211
212         return 0;
213 }
214
215 static int avs_probe_compr_pointer(struct snd_compr_stream *cstream,
216                                    struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai)
217 {
218         struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream);
219         struct snd_soc_pcm_stream *pstream;
220
221         pstream = &dai->driver->capture;
222         tstamp->copied_total = hdac_stream(host_stream)->curr_pos;
223         tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates);
224
225         return 0;
226 }
227
228 static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr_stream *cstream,
229                                 char __user *buf, size_t count)
230 {
231         struct snd_compr_runtime *rtd = cstream->runtime;
232         unsigned int offset, n;
233         void *ptr;
234         int ret;
235
236         if (count > rtd->buffer_size)
237                 count = rtd->buffer_size;
238
239         div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset);
240         ptr = rtd->dma_area + offset;
241         n = rtd->buffer_size - offset;
242
243         if (count < n) {
244                 ret = copy_to_user(buf, ptr, count);
245         } else {
246                 ret = copy_to_user(buf, ptr, n);
247                 ret += copy_to_user(buf + n, rtd->dma_area, count - n);
248         }
249
250         if (ret)
251                 return count - ret;
252         return count;
253 }
254
255 static const struct snd_soc_cdai_ops avs_probe_cdai_ops = {
256         .startup = avs_probe_compr_open,
257         .shutdown = avs_probe_compr_free,
258         .set_params = avs_probe_compr_set_params,
259         .trigger = avs_probe_compr_trigger,
260         .pointer = avs_probe_compr_pointer,
261 };
262
263 static const struct snd_soc_dai_ops avs_probe_dai_ops = {
264         .compress_new = snd_soc_new_compress,
265 };
266
267 static const struct snd_compress_ops avs_probe_compress_ops = {
268         .copy = avs_probe_compr_copy,
269 };
270
271 static struct snd_soc_dai_driver probe_cpu_dais[] = {
272 {
273         .name = "Probe Extraction CPU DAI",
274         .cops = &avs_probe_cdai_ops,
275         .ops  = &avs_probe_dai_ops,
276         .capture = {
277                 .stream_name = "Probe Extraction",
278                 .channels_min = 1,
279                 .channels_max = 8,
280                 .rates = SNDRV_PCM_RATE_48000,
281                 .rate_min = 48000,
282                 .rate_max = 48000,
283         },
284 },
285 };
286
287 static const struct snd_soc_component_driver avs_probe_component_driver = {
288         .name                   = "avs-probe-compr",
289         .compress_ops           = &avs_probe_compress_ops,
290         .module_get_upon_open   = 1, /* increment refcount when a stream is opened */
291 };
292
293 int avs_probe_platform_register(struct avs_dev *adev, const char *name)
294 {
295         return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver,
296                                           probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais));
297 }
This page took 0.04707 seconds and 4 git commands to generate.