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