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_stream_format(params->codec.ch_out, bps, params->codec.sample_rate); 144 ret = snd_hdac_stream_set_params(hdac_stream(host_stream), format_val); 145 if (ret < 0) 146 return ret; 147 ret = snd_hdac_stream_setup(hdac_stream(host_stream), false); 148 if (ret < 0) 149 return ret; 150 151 hdac_stream(host_stream)->prepared = 1; 152 153 if (!adev->num_probe_streams) { 154 union avs_connector_node_id node_id; 155 156 /* D0ix not allowed during probing. */ 157 ret = avs_dsp_disable_d0ix(adev); 158 if (ret) 159 return ret; 160 161 node_id.vindex = hdac_stream(host_stream)->stream_tag - 1; 162 node_id.dma_type = AVS_DMA_HDA_HOST_INPUT; 163 164 ret = avs_dsp_init_probe(adev, node_id, rtd->dma_bytes); 165 if (ret < 0) { 166 dev_err(dai->dev, "probe init failed: %d\n", ret); 167 avs_dsp_enable_d0ix(adev); 168 return ret; 169 } 170 } 171 172 adev->num_probe_streams++; 173 return 0; 174 } 175 176 static int avs_probe_compr_trigger(struct snd_compr_stream *cstream, int cmd, 177 struct snd_soc_dai *dai) 178 { 179 struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); 180 struct avs_dev *adev = to_avs_dev(dai->dev); 181 struct hdac_bus *bus = &adev->base.core; 182 unsigned long cookie; 183 184 if (!hdac_stream(host_stream)->prepared) 185 return -EPIPE; 186 187 switch (cmd) { 188 case SNDRV_PCM_TRIGGER_START: 189 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 190 case SNDRV_PCM_TRIGGER_RESUME: 191 spin_lock_irqsave(&bus->reg_lock, cookie); 192 snd_hdac_stream_start(hdac_stream(host_stream)); 193 spin_unlock_irqrestore(&bus->reg_lock, cookie); 194 break; 195 196 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 197 case SNDRV_PCM_TRIGGER_SUSPEND: 198 case SNDRV_PCM_TRIGGER_STOP: 199 spin_lock_irqsave(&bus->reg_lock, cookie); 200 snd_hdac_stream_stop(hdac_stream(host_stream)); 201 spin_unlock_irqrestore(&bus->reg_lock, cookie); 202 break; 203 204 default: 205 return -EINVAL; 206 } 207 208 return 0; 209 } 210 211 static int avs_probe_compr_pointer(struct snd_compr_stream *cstream, 212 struct snd_compr_tstamp *tstamp, struct snd_soc_dai *dai) 213 { 214 struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); 215 struct snd_soc_pcm_stream *pstream; 216 217 pstream = &dai->driver->capture; 218 tstamp->copied_total = hdac_stream(host_stream)->curr_pos; 219 tstamp->sampling_rate = snd_pcm_rate_bit_to_rate(pstream->rates); 220 221 return 0; 222 } 223 224 static int avs_probe_compr_copy(struct snd_soc_component *comp, struct snd_compr_stream *cstream, 225 char __user *buf, size_t count) 226 { 227 struct snd_compr_runtime *rtd = cstream->runtime; 228 unsigned int offset, n; 229 void *ptr; 230 int ret; 231 232 if (count > rtd->buffer_size) 233 count = rtd->buffer_size; 234 235 div_u64_rem(rtd->total_bytes_transferred, rtd->buffer_size, &offset); 236 ptr = rtd->dma_area + offset; 237 n = rtd->buffer_size - offset; 238 239 if (count < n) { 240 ret = copy_to_user(buf, ptr, count); 241 } else { 242 ret = copy_to_user(buf, ptr, n); 243 ret += copy_to_user(buf + n, rtd->dma_area, count - n); 244 } 245 246 if (ret) 247 return count - ret; 248 return count; 249 } 250 251 static const struct snd_soc_cdai_ops avs_probe_cdai_ops = { 252 .startup = avs_probe_compr_open, 253 .shutdown = avs_probe_compr_free, 254 .set_params = avs_probe_compr_set_params, 255 .trigger = avs_probe_compr_trigger, 256 .pointer = avs_probe_compr_pointer, 257 }; 258 259 static const struct snd_soc_dai_ops avs_probe_dai_ops = { 260 .compress_new = snd_soc_new_compress, 261 }; 262 263 static const struct snd_compress_ops avs_probe_compress_ops = { 264 .copy = avs_probe_compr_copy, 265 }; 266 267 static struct snd_soc_dai_driver probe_cpu_dais[] = { 268 { 269 .name = "Probe Extraction CPU DAI", 270 .cops = &avs_probe_cdai_ops, 271 .ops = &avs_probe_dai_ops, 272 .capture = { 273 .stream_name = "Probe Extraction", 274 .channels_min = 1, 275 .channels_max = 8, 276 .rates = SNDRV_PCM_RATE_48000, 277 .rate_min = 48000, 278 .rate_max = 48000, 279 }, 280 }, 281 }; 282 283 static const struct snd_soc_component_driver avs_probe_component_driver = { 284 .name = "avs-probe-compr", 285 .compress_ops = &avs_probe_compress_ops, 286 .module_get_upon_open = 1, /* increment refcount when a stream is opened */ 287 }; 288 289 int avs_probe_platform_register(struct avs_dev *adev, const char *name) 290 { 291 return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver, 292 probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais)); 293 } 294