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 u16 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)); 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_dai_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_compress_ops avs_probe_compress_ops = { 261 .copy = avs_probe_compr_copy, 262 }; 263 264 static struct snd_soc_dai_driver probe_cpu_dais[] = { 265 { 266 .name = "Probe Extraction CPU DAI", 267 .compress_new = snd_soc_new_compress, 268 .cops = &avs_probe_dai_ops, 269 .capture = { 270 .stream_name = "Probe Extraction", 271 .channels_min = 1, 272 .channels_max = 8, 273 .rates = SNDRV_PCM_RATE_48000, 274 .rate_min = 48000, 275 .rate_max = 48000, 276 }, 277 }, 278 }; 279 280 static const struct snd_soc_component_driver avs_probe_component_driver = { 281 .name = "avs-probe-compr", 282 .compress_ops = &avs_probe_compress_ops, 283 .module_get_upon_open = 1, /* increment refcount when a stream is opened */ 284 }; 285 286 int avs_probe_platform_register(struct avs_dev *adev, const char *name) 287 { 288 return avs_soc_component_register(adev->dev, name, &avs_probe_component_driver, 289 probe_cpu_dais, ARRAY_SIZE(probe_cpu_dais)); 290 } 291