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