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