162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license. When using or 462306a36Sopenharmony_ci// redistributing this file, you may do so under either license. 562306a36Sopenharmony_ci// 662306a36Sopenharmony_ci// Copyright(c) 2019 Intel Corporation. All rights reserved. 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// Authors: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* Generic SOF IPC code */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/export.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/types.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <sound/pcm.h> 1862306a36Sopenharmony_ci#include <sound/sof/stream.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "ops.h" 2162306a36Sopenharmony_ci#include "sof-priv.h" 2262306a36Sopenharmony_ci#include "sof-audio.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct sof_stream { 2562306a36Sopenharmony_ci size_t posn_offset; 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* Mailbox-based Generic IPC implementation */ 2962306a36Sopenharmony_ciint sof_ipc_msg_data(struct snd_sof_dev *sdev, 3062306a36Sopenharmony_ci struct snd_sof_pcm_stream *sps, 3162306a36Sopenharmony_ci void *p, size_t sz) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci if (!sps || !sdev->stream_box.size) { 3462306a36Sopenharmony_ci snd_sof_dsp_mailbox_read(sdev, sdev->dsp_box.offset, p, sz); 3562306a36Sopenharmony_ci } else { 3662306a36Sopenharmony_ci size_t posn_offset; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (sps->substream) { 3962306a36Sopenharmony_ci struct sof_stream *stream = sps->substream->runtime->private_data; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* The stream might already be closed */ 4262306a36Sopenharmony_ci if (!stream) 4362306a36Sopenharmony_ci return -ESTRPIPE; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci posn_offset = stream->posn_offset; 4662306a36Sopenharmony_ci } else { 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci struct sof_compr_stream *sstream = sps->cstream->runtime->private_data; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (!sstream) 5162306a36Sopenharmony_ci return -ESTRPIPE; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci posn_offset = sstream->posn_offset; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci snd_sof_dsp_mailbox_read(sdev, posn_offset, p, sz); 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ciEXPORT_SYMBOL(sof_ipc_msg_data); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciint sof_set_stream_data_offset(struct snd_sof_dev *sdev, 6462306a36Sopenharmony_ci struct snd_sof_pcm_stream *sps, 6562306a36Sopenharmony_ci size_t posn_offset) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci /* check if offset is overflow or it is not aligned */ 6862306a36Sopenharmony_ci if (posn_offset > sdev->stream_box.size || 6962306a36Sopenharmony_ci posn_offset % sizeof(struct sof_ipc_stream_posn) != 0) 7062306a36Sopenharmony_ci return -EINVAL; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci posn_offset += sdev->stream_box.offset; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (sps->substream) { 7562306a36Sopenharmony_ci struct sof_stream *stream = sps->substream->runtime->private_data; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci stream->posn_offset = posn_offset; 7862306a36Sopenharmony_ci dev_dbg(sdev->dev, "pcm: stream dir %d, posn mailbox offset is %zu", 7962306a36Sopenharmony_ci sps->substream->stream, posn_offset); 8062306a36Sopenharmony_ci } else if (sps->cstream) { 8162306a36Sopenharmony_ci struct sof_compr_stream *sstream = sps->cstream->runtime->private_data; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci sstream->posn_offset = posn_offset; 8462306a36Sopenharmony_ci dev_dbg(sdev->dev, "compr: stream dir %d, posn mailbox offset is %zu", 8562306a36Sopenharmony_ci sps->cstream->direction, posn_offset); 8662306a36Sopenharmony_ci } else { 8762306a36Sopenharmony_ci dev_err(sdev->dev, "No stream opened"); 8862306a36Sopenharmony_ci return -EINVAL; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ciEXPORT_SYMBOL(sof_set_stream_data_offset); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciint sof_stream_pcm_open(struct snd_sof_dev *sdev, 9662306a36Sopenharmony_ci struct snd_pcm_substream *substream) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct sof_stream *stream = kmalloc(sizeof(*stream), GFP_KERNEL); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (!stream) 10162306a36Sopenharmony_ci return -ENOMEM; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* binding pcm substream to hda stream */ 10462306a36Sopenharmony_ci substream->runtime->private_data = stream; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* align to DMA minimum transfer size */ 10762306a36Sopenharmony_ci snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 4); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* avoid circular buffer wrap in middle of period */ 11062306a36Sopenharmony_ci snd_pcm_hw_constraint_integer(substream->runtime, 11162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIODS); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci return 0; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ciEXPORT_SYMBOL(sof_stream_pcm_open); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciint sof_stream_pcm_close(struct snd_sof_dev *sdev, 11862306a36Sopenharmony_ci struct snd_pcm_substream *substream) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct sof_stream *stream = substream->runtime->private_data; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci substream->runtime->private_data = NULL; 12362306a36Sopenharmony_ci kfree(stream); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ciEXPORT_SYMBOL(sof_stream_pcm_close); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 130