brintos

brintos / linux-shallow public Read only

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