1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2021-2022 Intel Corporation 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 "debug.h" 15 #include "messages.h" 16 17 static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id node_id, 18 size_t buffer_size) 19 { 20 struct avs_probe_cfg cfg = {{0}}; 21 struct avs_module_entry mentry; 22 u8 dummy; 23 int ret; 24 25 ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); 26 if (ret) 27 return ret; 28 29 /* 30 * Probe module uses no cycles, audio data format and input and output 31 * frame sizes are unused. It is also not owned by any pipeline. 32 */ 33 cfg.base.ibs = 1; 34 /* BSS module descriptor is always segment of index=2. */ 35 cfg.base.is_pages = mentry.segments[2].flags.length; 36 cfg.gtw_cfg.node_id = node_id; 37 cfg.gtw_cfg.dma_buffer_size = buffer_size; 38 39 return avs_dsp_init_module(adev, mentry.module_id, INVALID_PIPELINE_ID, 0, 0, &cfg, 40 sizeof(cfg), &dummy); 41 } 42 43 static void avs_dsp_delete_probe(struct avs_dev *adev) 44 { 45 struct avs_module_entry mentry; 46 int ret; 47 48 ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); 49 if (!ret) 50 /* There is only ever one probe module instance. */ 51 avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0); 52 } 53 54 static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream) 55 { 56 return cstream->runtime->private_data; 57 } 58 59 static int avs_probe_compr_open(struct snd_compr_stream *cstream, struct snd_soc_dai *dai) 60 { 61 struct avs_dev *adev = to_avs_dev(dai->dev); 62 struct hdac_bus *bus = &adev->base.core; 63 struct hdac_ext_stream *host_stream; 64 65 if (adev->extractor) { 66 dev_err(dai->dev, "Cannot open more than one extractor stream\n"); 67 return -EEXIST; 68 } 69 70 host_stream = snd_hdac_ext_cstream_assign(bus, cstream); 71 if (!host_stream) { 72 dev_err(dai->dev, "Failed to assign HDAudio stream for extraction\n"); 73 return -EBUSY; 74 } 75 76 adev->extractor = host_stream; 77 hdac_stream(host_stream)->curr_pos = 0; 78 cstream->runtime->private_data = host_stream; 79 80 return 0; 81 } 82 83 static int avs_probe_compr_free(struct snd_compr_stream *cstream, struct snd_soc_dai *dai) 84 { 85 struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); 86 struct avs_dev *adev = to_avs_dev(dai->dev); 87 struct avs_probe_point_desc *desc; 88 /* Extractor node identifier. */ 89 unsigned int vindex = INVALID_NODE_ID.vindex; 90 size_t num_desc; 91 int i, ret; 92 93 /* Disconnect all probe points. */ 94 ret = avs_ipc_probe_get_points(adev, &desc, &num_desc); 95 if (ret) { 96 dev_err(dai->dev, "get probe points failed: %d\n", ret); 97 ret = AVS_IPC_RET(ret); 98 goto exit; 99 } 100 101 for (i = 0; i < num_desc; i++) 102 if (desc[i].node_id.vindex == vindex) 103 avs_ipc_probe_disconnect_points(adev, &desc[i].id, 1); 104 kfree(desc); 105 106 exit: 107 if (adev->num_probe_streams) { 108 adev->num_probe_streams--; 109 if (!adev->num_probe_streams) { 110 avs_dsp_delete_probe(adev); 111 avs_dsp_enable_d0ix(adev); 112 } 113 } 114 115 snd_hdac_stream_cleanup(hdac_stream(host_stream)); 116 hdac_stream(host_stream)->prepared = 0; 117 snd_hdac_ext_stream_release(host_stream, HDAC_EXT_STREAM_TYPE_HOST); 118 119 snd_compr_free_pages(cstream); 120 adev->extractor = NULL; 121 122 return ret; 123 } 124 125 static int avs_probe_compr_set_params(struct snd_compr_stream *cstream, 126 struct snd_compr_params *params, struct snd_soc_dai *dai) 127 { 128 struct hdac_ext_stream *host_stream = avs_compr_get_host_stream(cstream); 129 struct snd_compr_runtime *rtd = cstream->runtime; 130 struct avs_dev *adev = to_avs_dev(dai->dev); 131 /* compr params do not store bit depth, default to S32_LE. */ 132 snd_pcm_format_t format = SNDRV_PCM_FORMAT_S32_LE; 133 unsigned int format_val; 134 int bps, ret; 135 136 hdac_stream(host_stream)->bufsize = 0; 137 hdac_stream(host_stream)->period_bytes = 0; 138 hdac_stream(host_stream)->format_val = 0; 139 cstream->dma_buffer.dev.type = SNDRV_DMA_TYPE_DEV_SG; 140 cstream->dma_buffer.dev.dev = adev->dev; 141 142 ret = snd_compr_malloc_pages(cstream, rtd->buffer_size); 143 if (ret < 0) 144 return ret; 145 bps = snd_pcm_format_physical_width(format); 146 if (bps < 0) 147 return bps; 148 format_val = snd_hdac_stream_format(params->codec.ch_out, bps, params->codec.sample_rate); 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), false); 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_tstamp64 *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_register_probe_component(struct avs_dev *adev, const char *name) 295 { 296 struct snd_soc_component *component; 297 int ret; 298 299 component = devm_kzalloc(adev->dev, sizeof(*component), GFP_KERNEL); 300 if (!component) 301 return -ENOMEM; 302 303 component->name = devm_kstrdup(adev->dev, name, GFP_KERNEL); 304 if (!component->name) 305 return -ENOMEM; 306 307 ret = snd_soc_component_initialize(component, &avs_probe_component_driver, adev->dev); 308 if (ret) 309 return ret; 310 311 return snd_soc_add_component(component, probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais)); 312 } 313