18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license.  When using or
48c2ecf20Sopenharmony_ci// redistributing this file, you may do so under either license.
58c2ecf20Sopenharmony_ci//
68c2ecf20Sopenharmony_ci// Copyright(c) 2019 Intel Corporation. All rights reserved.
78c2ecf20Sopenharmony_ci//
88c2ecf20Sopenharmony_ci// Authors: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/* Intel-specific SOF IPC code */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/device.h>
138c2ecf20Sopenharmony_ci#include <linux/export.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/types.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <sound/pcm.h>
188c2ecf20Sopenharmony_ci#include <sound/sof/stream.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "../ops.h"
218c2ecf20Sopenharmony_ci#include "../sof-priv.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistruct intel_stream {
248c2ecf20Sopenharmony_ci	size_t posn_offset;
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* Mailbox-based Intel IPC implementation */
288c2ecf20Sopenharmony_civoid intel_ipc_msg_data(struct snd_sof_dev *sdev,
298c2ecf20Sopenharmony_ci			struct snd_pcm_substream *substream,
308c2ecf20Sopenharmony_ci			void *p, size_t sz)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	if (!substream || !sdev->stream_box.size) {
338c2ecf20Sopenharmony_ci		sof_mailbox_read(sdev, sdev->dsp_box.offset, p, sz);
348c2ecf20Sopenharmony_ci	} else {
358c2ecf20Sopenharmony_ci		struct intel_stream *stream = substream->runtime->private_data;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci		/* The stream might already be closed */
388c2ecf20Sopenharmony_ci		if (stream)
398c2ecf20Sopenharmony_ci			sof_mailbox_read(sdev, stream->posn_offset, p, sz);
408c2ecf20Sopenharmony_ci	}
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_NS(intel_ipc_msg_data, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciint intel_ipc_pcm_params(struct snd_sof_dev *sdev,
458c2ecf20Sopenharmony_ci			 struct snd_pcm_substream *substream,
468c2ecf20Sopenharmony_ci			 const struct sof_ipc_pcm_params_reply *reply)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct intel_stream *stream = substream->runtime->private_data;
498c2ecf20Sopenharmony_ci	size_t posn_offset = reply->posn_offset;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* check if offset is overflow or it is not aligned */
528c2ecf20Sopenharmony_ci	if (posn_offset > sdev->stream_box.size ||
538c2ecf20Sopenharmony_ci	    posn_offset % sizeof(struct sof_ipc_stream_posn) != 0)
548c2ecf20Sopenharmony_ci		return -EINVAL;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	stream->posn_offset = sdev->stream_box.offset + posn_offset;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu",
598c2ecf20Sopenharmony_ci		substream->stream, stream->posn_offset);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	return 0;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_NS(intel_ipc_pcm_params, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciint intel_pcm_open(struct snd_sof_dev *sdev,
668c2ecf20Sopenharmony_ci		   struct snd_pcm_substream *substream)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	struct intel_stream *stream = kmalloc(sizeof(*stream), GFP_KERNEL);
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (!stream)
718c2ecf20Sopenharmony_ci		return -ENOMEM;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* binding pcm substream to hda stream */
748c2ecf20Sopenharmony_ci	substream->runtime->private_data = stream;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return 0;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_NS(intel_pcm_open, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ciint intel_pcm_close(struct snd_sof_dev *sdev,
818c2ecf20Sopenharmony_ci		    struct snd_pcm_substream *substream)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct intel_stream *stream = substream->runtime->private_data;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	substream->runtime->private_data = NULL;
868c2ecf20Sopenharmony_ci	kfree(stream);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	return 0;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_NS(intel_pcm_close, SND_SOC_SOF_INTEL_HIFI_EP_IPC);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
93