ASoC: SOF: partition audio-related parts from SOF core

Move all the audio-specific code in the core,
audio-specific logic in the top-level PM callbacks
and the core header files into a separate file
(sof-audio.*) in preparation for adding an
audio client device.

In the process of moving all structure definitions
for widget, routes, pcm's etc, the snd_sof_dev
member in all these structs is replaced with
the snd_soc_component member. Also, use the component
device instead of the snd_sof_dev device wherever
possible in the PCM component driver,
control IO functions and the topology parser as the
component device will be moved over to the client
device later on.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191204211556.12671-9-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Ranjani Sridharan 2019-12-04 15:15:51 -06:00 committed by Mark Brown
parent 03eec9b4eb
commit ee1e79b72e
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
13 changed files with 861 additions and 801 deletions

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
control.o trace.o utils.o
control.o trace.o utils.o sof-audio.o
snd-sof-pci-objs := sof-pci-dev.o
snd-sof-acpi-objs := sof-acpi-dev.o

View File

@ -13,6 +13,7 @@
#include <linux/pm_runtime.h>
#include <linux/leds.h>
#include "sof-priv.h"
#include "sof-audio.h"
static void update_mute_led(struct snd_sof_control *scontrol,
struct snd_kcontrol *kcontrol,
@ -88,7 +89,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *sm =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
bool change = false;
@ -104,8 +105,8 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
}
/* notify DSP of mixer updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
if (pm_runtime_active(scomp->dev))
snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_VOLUME,
@ -135,7 +136,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *sm =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
bool change = false;
@ -153,8 +154,8 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
update_mute_led(scontrol, kcontrol, ucontrol);
/* notify DSP of mixer updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
if (pm_runtime_active(scomp->dev))
snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_SWITCH,
@ -185,7 +186,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
struct soc_enum *se =
(struct soc_enum *)kcontrol->private_value;
struct snd_sof_control *scontrol = se->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
bool change = false;
@ -200,8 +201,8 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
}
/* notify DSP of enum updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
if (pm_runtime_active(scomp->dev))
snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_ENUM,
@ -216,14 +217,14 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *be =
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size;
int ret = 0;
if (be->max > sizeof(ucontrol->value.bytes.data)) {
dev_err_ratelimited(sdev->dev,
dev_err_ratelimited(scomp->dev,
"error: data max %d exceeds ucontrol data array size\n",
be->max);
return -EINVAL;
@ -231,7 +232,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
size = data->size + sizeof(*data);
if (size > be->max) {
dev_err_ratelimited(sdev->dev,
dev_err_ratelimited(scomp->dev,
"error: DSP sent %zu bytes max is %d\n",
size, be->max);
ret = -EINVAL;
@ -251,20 +252,20 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *be =
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size = data->size + sizeof(*data);
if (be->max > sizeof(ucontrol->value.bytes.data)) {
dev_err_ratelimited(sdev->dev,
dev_err_ratelimited(scomp->dev,
"error: data max %d exceeds ucontrol data array size\n",
be->max);
return -EINVAL;
}
if (size > be->max) {
dev_err_ratelimited(sdev->dev,
dev_err_ratelimited(scomp->dev,
"error: size too big %zu bytes max is %d\n",
size, be->max);
return -EINVAL;
@ -274,8 +275,8 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
memcpy(data, ucontrol->value.bytes.data, size);
/* notify DSP of byte control updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
if (pm_runtime_active(scomp->dev))
snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET,
scontrol->cmd,
@ -291,7 +292,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *be =
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct snd_ctl_tlv header;
const struct snd_ctl_tlv __user *tlvd =
@ -307,14 +308,14 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
/* be->max is coming from topology */
if (header.length > be->max) {
dev_err_ratelimited(sdev->dev, "error: Bytes data size %d exceeds max %d.\n",
dev_err_ratelimited(scomp->dev, "error: Bytes data size %d exceeds max %d.\n",
header.length, be->max);
return -EINVAL;
}
/* Check that header id matches the command */
if (header.numid != scontrol->cmd) {
dev_err_ratelimited(sdev->dev,
dev_err_ratelimited(scomp->dev,
"error: incorrect numid %d\n",
header.numid);
return -EINVAL;
@ -324,26 +325,26 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
return -EFAULT;
if (cdata->data->magic != SOF_ABI_MAGIC) {
dev_err_ratelimited(sdev->dev,
dev_err_ratelimited(scomp->dev,
"error: Wrong ABI magic 0x%08x.\n",
cdata->data->magic);
return -EINVAL;
}
if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
dev_err_ratelimited(sdev->dev, "error: Incompatible ABI version 0x%08x.\n",
dev_err_ratelimited(scomp->dev, "error: Incompatible ABI version 0x%08x.\n",
cdata->data->abi);
return -EINVAL;
}
if (cdata->data->size + sizeof(const struct sof_abi_hdr) > be->max) {
dev_err_ratelimited(sdev->dev, "error: Mismatch in ABI data size (truncated?).\n");
dev_err_ratelimited(scomp->dev, "error: Mismatch in ABI data size (truncated?).\n");
return -EINVAL;
}
/* notify DSP of byte control updates */
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
if (pm_runtime_active(scomp->dev))
snd_sof_ipc_set_get_comp_data(scontrol,
SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET,
scontrol->cmd,
@ -359,7 +360,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
struct soc_bytes_ext *be =
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_sof_dev *sdev = scontrol->sdev;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct snd_ctl_tlv header;
struct snd_ctl_tlv __user *tlvd =
@ -382,7 +383,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
/* check data size doesn't exceed max coming from topology */
if (data_size > be->max) {
dev_err_ratelimited(sdev->dev, "error: user data size %d exceeds max size %d.\n",
dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %d.\n",
data_size, be->max);
ret = -EINVAL;
goto out;

View File

@ -24,126 +24,6 @@ MODULE_PARM_DESC(sof_debug, "SOF core debug options (0x0 all off)");
#define TIMEOUT_DEFAULT_IPC_MS 500
#define TIMEOUT_DEFAULT_BOOT_MS 2000
/*
* Generic object lookup APIs.
*/
struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev,
const char *name)
{
struct snd_sof_pcm *spcm;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
/* match with PCM dai name */
if (strcmp(spcm->pcm.dai_name, name) == 0)
return spcm;
/* match with playback caps name if set */
if (*spcm->pcm.caps[0].name &&
!strcmp(spcm->pcm.caps[0].name, name))
return spcm;
/* match with capture caps name if set */
if (*spcm->pcm.caps[1].name &&
!strcmp(spcm->pcm.caps[1].name, name))
return spcm;
}
return NULL;
}
struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev,
unsigned int comp_id,
int *direction)
{
struct snd_sof_pcm *spcm;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].comp_id == comp_id) {
*direction = SNDRV_PCM_STREAM_PLAYBACK;
return spcm;
}
if (spcm->stream[SNDRV_PCM_STREAM_CAPTURE].comp_id == comp_id) {
*direction = SNDRV_PCM_STREAM_CAPTURE;
return spcm;
}
}
return NULL;
}
struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
unsigned int pcm_id)
{
struct snd_sof_pcm *spcm;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id)
return spcm;
}
return NULL;
}
struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev,
const char *name)
{
struct snd_sof_widget *swidget;
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (strcmp(name, swidget->widget->name) == 0)
return swidget;
}
return NULL;
}
/* find widget by stream name and direction */
struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev,
const char *pcm_name, int dir)
{
struct snd_sof_widget *swidget;
enum snd_soc_dapm_type type;
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
type = snd_soc_dapm_aif_in;
else
type = snd_soc_dapm_aif_out;
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (!strcmp(pcm_name, swidget->widget->sname) && swidget->id == type)
return swidget;
}
return NULL;
}
struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev,
const char *name)
{
struct snd_sof_dai *dai;
list_for_each_entry(dai, &sdev->dai_list, list) {
if (dai->name && (strcmp(name, dai->name) == 0))
return dai;
}
return NULL;
}
bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev)
{
struct snd_sof_pcm *spcm;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored ||
spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored)
return true;
}
return false;
}
/*
* FW Panic/fault handling.
*/

View File

@ -11,6 +11,7 @@
#include <sound/pcm_params.h>
#include <sound/hdaudio_ext.h>
#include "../sof-priv.h"
#include "../sof-audio.h"
#include "hda.h"
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)

View File

@ -17,6 +17,7 @@
#include <sound/hda_register.h>
#include <sound/pcm_params.h>
#include "../sof-audio.h"
#include "../ops.h"
#include "hda.h"
@ -147,12 +148,13 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *scomp = sdev->component;
struct hdac_stream *hstream = substream->runtime->private_data;
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct snd_sof_pcm *spcm;
snd_pcm_uframes_t pos;
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(scomp, rtd);
if (!spcm) {
dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
rtd->dai_link->id);

View File

@ -20,6 +20,7 @@
#include <sound/hda_register.h>
#include <sound/sof.h>
#include "../ops.h"
#include "../sof-audio.h"
#include "hda.h"
/*

View File

@ -15,6 +15,7 @@
#include <linux/types.h>
#include "sof-priv.h"
#include "sof-audio.h"
#include "ops.h"
static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id);
@ -412,12 +413,13 @@ static void ipc_trace_message(struct snd_sof_dev *sdev, u32 msg_id)
static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
{
struct snd_soc_component *scomp = sdev->component;
struct snd_sof_pcm_stream *stream;
struct sof_ipc_stream_posn posn;
struct snd_sof_pcm *spcm;
int direction;
spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction);
spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
if (!spcm) {
dev_err(sdev->dev,
"error: period elapsed for unknown stream, msg_id %d\n",
@ -441,12 +443,13 @@ static void ipc_period_elapsed(struct snd_sof_dev *sdev, u32 msg_id)
/* DSP notifies host of an XRUN within FW */
static void ipc_xrun(struct snd_sof_dev *sdev, u32 msg_id)
{
struct snd_soc_component *scomp = sdev->component;
struct snd_sof_pcm_stream *stream;
struct sof_ipc_stream_posn posn;
struct snd_sof_pcm *spcm;
int direction;
spcm = snd_sof_find_spcm_comp(sdev, msg_id, &direction);
spcm = snd_sof_find_spcm_comp(scomp, msg_id, &direction);
if (!spcm) {
dev_err(sdev->dev, "error: XRUN for unknown stream, msg_id %d\n",
msg_id);
@ -488,10 +491,11 @@ static void ipc_stream_message(struct snd_sof_dev *sdev, u32 msg_cmd)
}
/* get stream position IPC - use faster MMIO method if available on platform */
int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev,
int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp,
struct snd_sof_pcm *spcm, int direction,
struct sof_ipc_stream_posn *posn)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc_stream stream;
int err;
@ -620,15 +624,15 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
/*
* IPC get()/set() for kcontrols.
*/
int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc,
struct snd_sof_control *scontrol,
int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
u32 ipc_cmd,
enum sof_ipc_ctrl_type ctrl_type,
enum sof_ipc_ctrl_cmd ctrl_cmd,
bool send)
{
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct snd_sof_dev *sdev = ipc->sdev;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
struct sof_ipc_fw_version *v = &ready->version;
struct sof_ipc_ctrl_data_params sparams;

View File

@ -14,38 +14,38 @@
#include <sound/pcm_params.h>
#include <sound/sof.h>
#include "sof-priv.h"
#include "sof-audio.h"
#include "ops.h"
#define DRV_NAME "sof-audio-component"
/* Create DMA buffer page table for DSP */
static int create_page_table(struct snd_soc_component *component,
struct snd_pcm_substream *substream,
unsigned char *dma_area, size_t size)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct snd_sof_pcm *spcm;
struct snd_dma_buffer *dmab = snd_pcm_get_dma_buf(substream);
int stream = substream->stream;
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
return snd_sof_create_page_table(sdev->dev, dmab,
return snd_sof_create_page_table(component->dev, dmab,
spcm->stream[stream].page_table.area, size);
}
static int sof_pcm_dsp_params(struct snd_sof_pcm *spcm, struct snd_pcm_substream *substream,
const struct sof_ipc_pcm_params_reply *reply)
{
struct snd_sof_dev *sdev = spcm->sdev;
struct snd_soc_component *scomp = spcm->scomp;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
/* validate offset */
int ret = snd_sof_ipc_pcm_params(sdev, substream, reply);
if (ret < 0)
dev_err(sdev->dev, "error: got wrong reply for PCM %d\n",
dev_err(scomp->dev, "error: got wrong reply for PCM %d\n",
spcm->pcm.pcm_id);
return ret;
@ -70,13 +70,12 @@ void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
struct snd_sof_pcm *spcm;
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm) {
dev_err(sdev->dev,
dev_err(component->dev,
"error: period elapsed for unknown stream!\n");
return;
}
@ -110,11 +109,11 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
dev_dbg(sdev->dev, "pcm: hw params stream %d dir %d\n",
dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
memset(&pcm, 0, sizeof(pcm));
@ -122,7 +121,7 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
/* allocate audio buffer pages */
ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
if (ret < 0) {
dev_err(sdev->dev, "error: could not allocate %d bytes for PCM %d\n",
dev_err(component->dev, "error: could not allocate %d bytes for PCM %d\n",
params_buffer_bytes(params), spcm->pcm.pcm_id);
return ret;
}
@ -187,17 +186,17 @@ static int sof_pcm_hw_params(struct snd_soc_component *component,
params,
&pcm.params);
if (ret < 0) {
dev_err(sdev->dev, "error: platform hw params failed\n");
dev_err(component->dev, "error: platform hw params failed\n");
return ret;
}
dev_dbg(sdev->dev, "stream_tag %d", pcm.params.stream_tag);
dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag);
/* send IPC to the DSP */
ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
&ipc_params_reply, sizeof(ipc_params_reply));
if (ret < 0) {
dev_err(sdev->dev, "error: hw params ipc failed for stream %d\n",
dev_err(component->dev, "error: hw params ipc failed for stream %d\n",
pcm.params.stream_tag);
return ret;
}
@ -247,12 +246,12 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
dev_dbg(sdev->dev, "pcm: free stream %d dir %d\n", spcm->pcm.pcm_id,
substream->stream);
dev_dbg(component->dev, "pcm: free stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
if (spcm->prepared[substream->stream]) {
ret = sof_pcm_dsp_pcm_free(substream, sdev, spcm);
@ -266,7 +265,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component,
ret = snd_sof_pcm_platform_hw_free(sdev, substream);
if (ret < 0) {
dev_err(sdev->dev, "error: platform hw free failed\n");
dev_err(component->dev, "error: platform hw free failed\n");
err = ret;
}
@ -277,7 +276,6 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct snd_sof_pcm *spcm;
int ret;
@ -285,21 +283,22 @@ static int sof_pcm_prepare(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
if (spcm->prepared[substream->stream])
return 0;
dev_dbg(sdev->dev, "pcm: prepare stream %d dir %d\n", spcm->pcm.pcm_id,
substream->stream);
dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
/* set hw_params */
ret = sof_pcm_hw_params(component,
substream, &spcm->params[substream->stream]);
if (ret < 0) {
dev_err(sdev->dev, "error: set pcm hw_params after resume\n");
dev_err(component->dev,
"error: set pcm hw_params after resume\n");
return ret;
}
@ -326,11 +325,11 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
dev_dbg(sdev->dev, "pcm: trigger stream %d dir %d cmd %d\n",
dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n",
spcm->pcm.pcm_id, substream->stream, cmd);
stream.hdr.size = sizeof(stream);
@ -359,7 +358,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
/* set up hw_params */
ret = sof_pcm_prepare(component, substream);
if (ret < 0) {
dev_err(sdev->dev,
dev_err(component->dev,
"error: failed to set up hw_params upon resume\n");
return ret;
}
@ -396,7 +395,8 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
reset_hw_params = true;
break;
default:
dev_err(sdev->dev, "error: unhandled trigger cmd %d\n", cmd);
dev_err(component->dev, "error: unhandled trigger cmd %d\n",
cmd);
return -EINVAL;
}
@ -438,7 +438,7 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component,
if (sof_ops(sdev)->pcm_pointer)
return sof_ops(sdev)->pcm_pointer(sdev, substream);
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
@ -448,7 +448,8 @@ static snd_pcm_uframes_t sof_pcm_pointer(struct snd_soc_component *component,
dai = bytes_to_frames(substream->runtime,
spcm->stream[substream->stream].posn.dai_posn);
dev_dbg(sdev->dev, "PCM: stream %d dir %d DMA position %lu DAI position %lu\n",
dev_dbg(component->dev,
"PCM: stream %d dir %d DMA position %lu DAI position %lu\n",
spcm->pcm.pcm_id, substream->stream, host, dai);
return host;
@ -469,12 +470,12 @@ static int sof_pcm_open(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
dev_dbg(sdev->dev, "pcm: open stream %d dir %d\n", spcm->pcm.pcm_id,
substream->stream);
dev_dbg(component->dev, "pcm: open stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
INIT_WORK(&spcm->stream[substream->stream].period_elapsed_work,
sof_pcm_period_elapsed_work);
@ -504,13 +505,13 @@ static int sof_pcm_open(struct snd_soc_component *component,
*/
runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max);
dev_dbg(sdev->dev, "period min %zd max %zd bytes\n",
dev_dbg(component->dev, "period min %zd max %zd bytes\n",
runtime->hw.period_bytes_min,
runtime->hw.period_bytes_max);
dev_dbg(sdev->dev, "period count %d max %d\n",
dev_dbg(component->dev, "period count %d max %d\n",
runtime->hw.periods_min,
runtime->hw.periods_max);
dev_dbg(sdev->dev, "buffer max %zd bytes\n",
dev_dbg(component->dev, "buffer max %zd bytes\n",
runtime->hw.buffer_bytes_max);
/* set wait time - TODO: come from topology */
@ -523,7 +524,7 @@ static int sof_pcm_open(struct snd_soc_component *component,
ret = snd_sof_pcm_platform_open(sdev, substream);
if (ret < 0)
dev_err(sdev->dev, "error: pcm open failed %d\n", ret);
dev_err(component->dev, "error: pcm open failed %d\n", ret);
return ret;
}
@ -540,16 +541,16 @@ static int sof_pcm_close(struct snd_soc_component *component,
if (rtd->dai_link->no_pcm)
return 0;
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm)
return -EINVAL;
dev_dbg(sdev->dev, "pcm: close stream %d dir %d\n", spcm->pcm.pcm_id,
substream->stream);
dev_dbg(component->dev, "pcm: close stream %d dir %d\n",
spcm->pcm.pcm_id, substream->stream);
err = snd_sof_pcm_platform_close(sdev, substream);
if (err < 0) {
dev_err(sdev->dev, "error: pcm close failed %d\n",
dev_err(component->dev, "error: pcm close failed %d\n",
err);
/*
* keep going, no point in preventing the close
@ -575,14 +576,14 @@ static int sof_pcm_new(struct snd_soc_component *component,
int stream = SNDRV_PCM_STREAM_PLAYBACK;
/* find SOF PCM for this RTD */
spcm = snd_sof_find_spcm_dai(sdev, rtd);
spcm = snd_sof_find_spcm_dai(component, rtd);
if (!spcm) {
dev_warn(sdev->dev, "warn: can't find PCM with DAI ID %d\n",
dev_warn(component->dev, "warn: can't find PCM with DAI ID %d\n",
rtd->dai_link->id);
return 0;
}
dev_dbg(sdev->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
dev_dbg(component->dev, "creating new PCM %s\n", spcm->pcm.pcm_name);
/* do we need to pre-allocate playback audio buffer pages */
if (!spcm->pcm.playback)
@ -591,7 +592,8 @@ static int sof_pcm_new(struct snd_soc_component *component,
caps = &spcm->pcm.caps[stream];
/* pre-allocate playback audio buffer pages */
dev_dbg(sdev->dev, "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
dev_dbg(component->dev,
"spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n",
caps->name, caps->buffer_size_min, caps->buffer_size_max);
snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
@ -608,7 +610,8 @@ capture:
caps = &spcm->pcm.caps[stream];
/* pre-allocate capture audio buffer pages */
dev_dbg(sdev->dev, "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
dev_dbg(component->dev,
"spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n",
caps->name, caps->buffer_size_min, caps->buffer_size_max);
snd_pcm_lib_preallocate_pages(pcm->streams[stream].substream,
@ -629,14 +632,14 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
SNDRV_PCM_HW_PARAM_CHANNELS);
struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(rtd, DRV_NAME);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
struct snd_sof_dai *dai =
snd_sof_find_dai(sdev, (char *)rtd->dai_link->name);
snd_sof_find_dai(component, (char *)rtd->dai_link->name);
/* no topology exists for this BE, try a common configuration */
if (!dai) {
dev_warn(sdev->dev, "warning: no topology found for BE DAI %s config\n",
dev_warn(component->dev,
"warning: no topology found for BE DAI %s config\n",
rtd->dai_link->name);
/* set 48k, stereo, 16bits by default */
@ -666,7 +669,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE);
break;
default:
dev_err(sdev->dev, "error: No available DAI format!\n");
dev_err(component->dev, "error: No available DAI format!\n");
return -EINVAL;
}
@ -678,9 +681,9 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = dai->dai_config->ssp.tdm_slots;
channels->max = dai->dai_config->ssp.tdm_slots;
dev_dbg(sdev->dev,
dev_dbg(component->dev,
"rate_min: %d rate_max: %d\n", rate->min, rate->max);
dev_dbg(sdev->dev,
dev_dbg(component->dev,
"channels_min: %d channels_max: %d\n",
channels->min, channels->max);
@ -688,7 +691,7 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
case SOF_DAI_INTEL_DMIC:
/* DMIC only supports 16 or 32 bit formats */
if (dai->comp_dai.config.frame_fmt == SOF_IPC_FRAME_S24_4LE) {
dev_err(sdev->dev,
dev_err(component->dev,
"error: invalid fmt %d for DAI type %d\n",
dai->comp_dai.config.frame_fmt,
dai->dai_config->type);
@ -704,12 +707,12 @@ static int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = dai->dai_config->esai.tdm_slots;
channels->max = dai->dai_config->esai.tdm_slots;
dev_dbg(sdev->dev,
dev_dbg(component->dev,
"channels_min: %d channels_max: %d\n",
channels->min, channels->max);
break;
default:
dev_err(sdev->dev, "error: invalid DAI type %d\n",
dev_err(component->dev, "error: invalid DAI type %d\n",
dai->dai_config->type);
break;
}
@ -734,9 +737,9 @@ static int sof_pcm_probe(struct snd_soc_component *component)
if (!tplg_filename)
return -ENOMEM;
ret = snd_sof_load_topology(sdev, tplg_filename);
ret = snd_sof_load_topology(component, tplg_filename);
if (ret < 0) {
dev_err(sdev->dev, "error: failed to load DSP topology %d\n",
dev_err(component->dev, "error: failed to load DSP topology %d\n",
ret);
return ret;
}

View File

@ -10,192 +10,7 @@
#include "ops.h"
#include "sof-priv.h"
static int sof_restore_kcontrols(struct snd_sof_dev *sdev)
{
struct snd_sof_control *scontrol;
int ipc_cmd, ctrl_type;
int ret = 0;
/* restore kcontrol values */
list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
/* reset readback offset for scontrol after resuming */
scontrol->readback_offset = 0;
/* notify DSP of kcontrol values */
switch (scontrol->cmd) {
case SOF_CTRL_CMD_VOLUME:
case SOF_CTRL_CMD_ENUM:
case SOF_CTRL_CMD_SWITCH:
ipc_cmd = SOF_IPC_COMP_SET_VALUE;
ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
ipc_cmd, ctrl_type,
scontrol->cmd,
true);
break;
case SOF_CTRL_CMD_BINARY:
ipc_cmd = SOF_IPC_COMP_SET_DATA;
ctrl_type = SOF_CTRL_TYPE_DATA_SET;
ret = snd_sof_ipc_set_get_comp_data(sdev->ipc, scontrol,
ipc_cmd, ctrl_type,
scontrol->cmd,
true);
break;
default:
break;
}
if (ret < 0) {
dev_err(sdev->dev,
"error: failed kcontrol value set for widget: %d\n",
scontrol->comp_id);
return ret;
}
}
return 0;
}
static int sof_restore_pipelines(struct snd_sof_dev *sdev)
{
struct snd_sof_widget *swidget;
struct snd_sof_route *sroute;
struct sof_ipc_pipe_new *pipeline;
struct snd_sof_dai *dai;
struct sof_ipc_comp_dai *comp_dai;
struct sof_ipc_cmd_hdr *hdr;
int ret;
/* restore pipeline components */
list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
struct sof_ipc_comp_reply r;
/* skip if there is no private data */
if (!swidget->private)
continue;
switch (swidget->id) {
case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out:
dai = swidget->private;
comp_dai = &dai->comp_dai;
ret = sof_ipc_tx_message(sdev->ipc,
comp_dai->comp.hdr.cmd,
comp_dai, sizeof(*comp_dai),
&r, sizeof(r));
break;
case snd_soc_dapm_scheduler:
/*
* During suspend, all DSP cores are powered off.
* Therefore upon resume, create the pipeline comp
* and power up the core that the pipeline is
* scheduled on.
*/
pipeline = swidget->private;
ret = sof_load_pipeline_ipc(sdev, pipeline, &r);
break;
default:
hdr = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd,
swidget->private, hdr->size,
&r, sizeof(r));
break;
}
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to load widget type %d with ID: %d\n",
swidget->widget->id, swidget->comp_id);
return ret;
}
}
/* restore pipeline connections */
list_for_each_entry_reverse(sroute, &sdev->route_list, list) {
struct sof_ipc_pipe_comp_connect *connect;
struct sof_ipc_reply reply;
/* skip if there's no private data */
if (!sroute->private)
continue;
connect = sroute->private;
/* send ipc */
ret = sof_ipc_tx_message(sdev->ipc,
connect->hdr.cmd,
connect, sizeof(*connect),
&reply, sizeof(reply));
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to load route sink %s control %s source %s\n",
sroute->route->sink,
sroute->route->control ? sroute->route->control
: "none",
sroute->route->source);
return ret;
}
}
/* restore dai links */
list_for_each_entry_reverse(dai, &sdev->dai_list, list) {
struct sof_ipc_reply reply;
struct sof_ipc_dai_config *config = dai->dai_config;
if (!config) {
dev_err(sdev->dev, "error: no config for DAI %s\n",
dai->name);
continue;
}
/*
* The link DMA channel would be invalidated for running
* streams but not for streams that were in the PAUSED
* state during suspend. So invalidate it here before setting
* the dai config in the DSP.
*/
if (config->type == SOF_DAI_INTEL_HDA)
config->hda.link_dma_ch = DMA_CHAN_INVALID;
ret = sof_ipc_tx_message(sdev->ipc,
config->hdr.cmd, config,
config->hdr.size,
&reply, sizeof(reply));
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to set dai config for %s\n",
dai->name);
return ret;
}
}
/* complete pipeline */
list_for_each_entry(swidget, &sdev->widget_list, list) {
switch (swidget->id) {
case snd_soc_dapm_scheduler:
swidget->complete =
snd_sof_complete_pipeline(sdev, swidget);
break;
default:
break;
}
}
/* restore pipeline kcontrols */
ret = sof_restore_kcontrols(sdev);
if (ret < 0)
dev_err(sdev->dev,
"error: restoring kcontrols after resume\n");
return ret;
}
#include "sof-audio.h"
static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
{
@ -213,34 +28,6 @@ static int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
sizeof(pm_ctx), &reply, sizeof(reply));
}
static int sof_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
struct snd_pcm_substream *substream;
struct snd_sof_pcm *spcm;
snd_pcm_state_t state;
int dir;
/*
* SOF requires hw_params to be set-up internally upon resume.
* So, set the flag to indicate this for those streams that
* have been suspended.
*/
list_for_each_entry(spcm, &sdev->pcm_list, list) {
for (dir = 0; dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
substream = spcm->stream[dir].substream;
if (!substream || !substream->runtime)
continue;
state = substream->runtime->status->state;
if (state == SNDRV_PCM_STATE_SUSPENDED)
spcm->prepared[dir] = false;
}
}
/* set internal flag for BE */
return snd_sof_dsp_hw_params_upon_resume(sdev);
}
#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
static void sof_cache_debugfs(struct snd_sof_dev *sdev)
{
@ -311,7 +98,7 @@ static int sof_resume(struct device *dev, bool runtime_resume)
}
/* restore pipelines */
ret = sof_restore_pipelines(sdev);
ret = sof_restore_pipelines(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to restore pipeline after resume %d\n",
@ -346,7 +133,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
/* set restore_stream for all streams during system suspend */
if (!runtime_suspend) {
ret = sof_set_hw_params_upon_resume(sdev);
ret = sof_set_hw_params_upon_resume(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev,
"error: setting hw_params flag during suspend %d\n",

362
sound/soc/sof/sof-audio.c Normal file
View File

@ -0,0 +1,362 @@
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license. When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2019 Intel Corporation. All rights reserved.
//
// Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
//
#include "sof-audio.h"
#include "ops.h"
bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev)
{
struct snd_sof_pcm *spcm;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
if (spcm->stream[SNDRV_PCM_STREAM_PLAYBACK].suspend_ignored ||
spcm->stream[SNDRV_PCM_STREAM_CAPTURE].suspend_ignored)
return true;
}
return false;
}
int sof_set_hw_params_upon_resume(struct device *dev)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_pcm_substream *substream;
struct snd_sof_pcm *spcm;
snd_pcm_state_t state;
int dir;
/*
* SOF requires hw_params to be set-up internally upon resume.
* So, set the flag to indicate this for those streams that
* have been suspended.
*/
list_for_each_entry(spcm, &sdev->pcm_list, list) {
for (dir = 0; dir <= SNDRV_PCM_STREAM_CAPTURE; dir++) {
substream = spcm->stream[dir].substream;
if (!substream || !substream->runtime)
continue;
state = substream->runtime->status->state;
if (state == SNDRV_PCM_STATE_SUSPENDED)
spcm->prepared[dir] = false;
}
}
/* set internal flag for BE */
return snd_sof_dsp_hw_params_upon_resume(sdev);
}
static int sof_restore_kcontrols(struct device *dev)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_sof_control *scontrol;
int ipc_cmd, ctrl_type;
int ret = 0;
/* restore kcontrol values */
list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
/* reset readback offset for scontrol after resuming */
scontrol->readback_offset = 0;
/* notify DSP of kcontrol values */
switch (scontrol->cmd) {
case SOF_CTRL_CMD_VOLUME:
case SOF_CTRL_CMD_ENUM:
case SOF_CTRL_CMD_SWITCH:
ipc_cmd = SOF_IPC_COMP_SET_VALUE;
ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_SET;
ret = snd_sof_ipc_set_get_comp_data(scontrol,
ipc_cmd, ctrl_type,
scontrol->cmd,
true);
break;
case SOF_CTRL_CMD_BINARY:
ipc_cmd = SOF_IPC_COMP_SET_DATA;
ctrl_type = SOF_CTRL_TYPE_DATA_SET;
ret = snd_sof_ipc_set_get_comp_data(scontrol,
ipc_cmd, ctrl_type,
scontrol->cmd,
true);
break;
default:
break;
}
if (ret < 0) {
dev_err(dev,
"error: failed kcontrol value set for widget: %d\n",
scontrol->comp_id);
return ret;
}
}
return 0;
}
int sof_restore_pipelines(struct device *dev)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_sof_widget *swidget;
struct snd_sof_route *sroute;
struct sof_ipc_pipe_new *pipeline;
struct snd_sof_dai *dai;
struct sof_ipc_comp_dai *comp_dai;
struct sof_ipc_cmd_hdr *hdr;
int ret;
/* restore pipeline components */
list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
struct sof_ipc_comp_reply r;
/* skip if there is no private data */
if (!swidget->private)
continue;
switch (swidget->id) {
case snd_soc_dapm_dai_in:
case snd_soc_dapm_dai_out:
dai = swidget->private;
comp_dai = &dai->comp_dai;
ret = sof_ipc_tx_message(sdev->ipc,
comp_dai->comp.hdr.cmd,
comp_dai, sizeof(*comp_dai),
&r, sizeof(r));
break;
case snd_soc_dapm_scheduler:
/*
* During suspend, all DSP cores are powered off.
* Therefore upon resume, create the pipeline comp
* and power up the core that the pipeline is
* scheduled on.
*/
pipeline = swidget->private;
ret = sof_load_pipeline_ipc(dev, pipeline, &r);
break;
default:
hdr = swidget->private;
ret = sof_ipc_tx_message(sdev->ipc, hdr->cmd,
swidget->private, hdr->size,
&r, sizeof(r));
break;
}
if (ret < 0) {
dev_err(dev,
"error: failed to load widget type %d with ID: %d\n",
swidget->widget->id, swidget->comp_id);
return ret;
}
}
/* restore pipeline connections */
list_for_each_entry_reverse(sroute, &sdev->route_list, list) {
struct sof_ipc_pipe_comp_connect *connect;
struct sof_ipc_reply reply;
/* skip if there's no private data */
if (!sroute->private)
continue;
connect = sroute->private;
/* send ipc */
ret = sof_ipc_tx_message(sdev->ipc,
connect->hdr.cmd,
connect, sizeof(*connect),
&reply, sizeof(reply));
if (ret < 0) {
dev_err(dev,
"error: failed to load route sink %s control %s source %s\n",
sroute->route->sink,
sroute->route->control ? sroute->route->control
: "none",
sroute->route->source);
return ret;
}
}
/* restore dai links */
list_for_each_entry_reverse(dai, &sdev->dai_list, list) {
struct sof_ipc_reply reply;
struct sof_ipc_dai_config *config = dai->dai_config;
if (!config) {
dev_err(dev, "error: no config for DAI %s\n",
dai->name);
continue;
}
/*
* The link DMA channel would be invalidated for running
* streams but not for streams that were in the PAUSED
* state during suspend. So invalidate it here before setting
* the dai config in the DSP.
*/
if (config->type == SOF_DAI_INTEL_HDA)
config->hda.link_dma_ch = DMA_CHAN_INVALID;
ret = sof_ipc_tx_message(sdev->ipc,
config->hdr.cmd, config,
config->hdr.size,
&reply, sizeof(reply));
if (ret < 0) {
dev_err(dev,
"error: failed to set dai config for %s\n",
dai->name);
return ret;
}
}
/* complete pipeline */
list_for_each_entry(swidget, &sdev->widget_list, list) {
switch (swidget->id) {
case snd_soc_dapm_scheduler:
swidget->complete =
snd_sof_complete_pipeline(dev, swidget);
break;
default:
break;
}
}
/* restore pipeline kcontrols */
ret = sof_restore_kcontrols(dev);
if (ret < 0)
dev_err(dev,
"error: restoring kcontrols after resume\n");
return ret;
}
/*
* Generic object lookup APIs.
*/
struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp,
const char *name)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_pcm *spcm;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
/* match with PCM dai name */
if (strcmp(spcm->pcm.dai_name, name) == 0)
return spcm;
/* match with playback caps name if set */
if (*spcm->pcm.caps[0].name &&
!strcmp(spcm->pcm.caps[0].name, name))
return spcm;
/* match with capture caps name if set */
if (*spcm->pcm.caps[1].name &&
!strcmp(spcm->pcm.caps[1].name, name))
return spcm;
}
return NULL;
}
struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
unsigned int comp_id,
int *direction)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_pcm *spcm;
int dir;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
dir = SNDRV_PCM_STREAM_PLAYBACK;
if (spcm->stream[dir].comp_id == comp_id) {
*direction = dir;
return spcm;
}
dir = SNDRV_PCM_STREAM_CAPTURE;
if (spcm->stream[dir].comp_id == comp_id) {
*direction = dir;
return spcm;
}
}
return NULL;
}
struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp,
unsigned int pcm_id)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_pcm *spcm;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
if (le32_to_cpu(spcm->pcm.pcm_id) == pcm_id)
return spcm;
}
return NULL;
}
struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
const char *name)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_widget *swidget;
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (strcmp(name, swidget->widget->name) == 0)
return swidget;
}
return NULL;
}
/* find widget by stream name and direction */
struct snd_sof_widget *
snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
const char *pcm_name, int dir)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_widget *swidget;
enum snd_soc_dapm_type type;
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
type = snd_soc_dapm_aif_in;
else
type = snd_soc_dapm_aif_out;
list_for_each_entry(swidget, &sdev->widget_list, list) {
if (!strcmp(pcm_name, swidget->widget->sname) &&
swidget->id == type)
return swidget;
}
return NULL;
}
struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
const char *name)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_dai *dai;
list_for_each_entry(dai, &sdev->dai_list, list) {
if (dai->name && (strcmp(name, dai->name) == 0))
return dai;
}
return NULL;
}

207
sound/soc/sof/sof-audio.h Normal file
View File

@ -0,0 +1,207 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* Copyright(c) 2019 Intel Corporation. All rights reserved.
*
* Author: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
*/
#ifndef __SOUND_SOC_SOF_AUDIO_H
#define __SOUND_SOC_SOF_AUDIO_H
#include <sound/soc.h>
#include <sound/control.h>
#include <sound/sof/stream.h> /* needs to be included before control.h */
#include <sound/sof/control.h>
#include <sound/sof/dai.h>
#include <sound/sof/topology.h>
#include "sof-priv.h"
#define SOF_AUDIO_PCM_DRV_NAME "sof-audio-component"
/* max number of FE PCMs before BEs */
#define SOF_BE_PCM_BASE 16
#define DMA_CHAN_INVALID 0xFFFFFFFF
/* PCM stream, mapped to FW component */
struct snd_sof_pcm_stream {
u32 comp_id;
struct snd_dma_buffer page_table;
struct sof_ipc_stream_posn posn;
struct snd_pcm_substream *substream;
struct work_struct period_elapsed_work;
bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */
/*
* flag to indicate that the DSP pipelines should be kept
* active or not while suspending the stream
*/
bool suspend_ignored;
};
/* ALSA SOF PCM device */
struct snd_sof_pcm {
struct snd_soc_component *scomp;
struct snd_soc_tplg_pcm pcm;
struct snd_sof_pcm_stream stream[2];
struct list_head list; /* list in sdev pcm list */
struct snd_pcm_hw_params params[2];
bool prepared[2]; /* PCM_PARAMS set successfully */
};
struct snd_sof_led_control {
unsigned int use_led;
unsigned int direction;
unsigned int led_value;
};
/* ALSA SOF Kcontrol device */
struct snd_sof_control {
struct snd_soc_component *scomp;
int comp_id;
int min_volume_step; /* min volume step for volume_table */
int max_volume_step; /* max volume step for volume_table */
int num_channels;
u32 readback_offset; /* offset to mmapped data if used */
struct sof_ipc_ctrl_data *control_data;
u32 size; /* cdata size */
enum sof_ipc_ctrl_cmd cmd;
u32 *volume_table; /* volume table computed from tlv data*/
struct list_head list; /* list in sdev control list */
struct snd_sof_led_control led_ctl;
};
/* ASoC SOF DAPM widget */
struct snd_sof_widget {
struct snd_soc_component *scomp;
int comp_id;
int pipeline_id;
int complete;
int id;
struct snd_soc_dapm_widget *widget;
struct list_head list; /* list in sdev widget list */
void *private; /* core does not touch this */
};
/* ASoC SOF DAPM route */
struct snd_sof_route {
struct snd_soc_component *scomp;
struct snd_soc_dapm_route *route;
struct list_head list; /* list in sdev route list */
void *private;
};
/* ASoC DAI device */
struct snd_sof_dai {
struct snd_soc_component *scomp;
const char *name;
const char *cpu_dai_name;
struct sof_ipc_comp_dai comp_dai;
struct sof_ipc_dai_config *dai_config;
struct list_head list; /* list in sdev dai list */
};
/*
* Kcontrols.
*/
int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
const unsigned int __user *binary_data,
unsigned int size);
int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
unsigned int __user *binary_data,
unsigned int size);
/*
* Topology.
* There is no snd_sof_free_topology since topology components will
* be freed by snd_soc_unregister_component,
*/
int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file);
int snd_sof_complete_pipeline(struct device *dev,
struct snd_sof_widget *swidget);
int sof_load_pipeline_ipc(struct device *dev,
struct sof_ipc_pipe_new *pipeline,
struct sof_ipc_comp_reply *r);
/*
* Stream IPC
*/
int snd_sof_ipc_stream_posn(struct snd_soc_component *scomp,
struct snd_sof_pcm *spcm, int direction,
struct sof_ipc_stream_posn *posn);
struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
const char *name);
struct snd_sof_widget *
snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
const char *pcm_name, int dir);
struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
const char *name);
static inline
struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_soc_component *scomp,
struct snd_soc_pcm_runtime *rtd)
{
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
struct snd_sof_pcm *spcm = NULL;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id)
return spcm;
}
return NULL;
}
struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_soc_component *scomp,
const char *name);
struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp,
unsigned int comp_id,
int *direction);
struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_soc_component *scomp,
unsigned int pcm_id);
void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream);
/*
* Mixer IPC
*/
int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
u32 ipc_cmd,
enum sof_ipc_ctrl_type ctrl_type,
enum sof_ipc_ctrl_cmd ctrl_cmd,
bool send);
/* PM */
int sof_restore_pipelines(struct device *dev);
int sof_set_hw_params_upon_resume(struct device *dev);
bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev);
#endif

View File

@ -12,20 +12,11 @@
#define __SOUND_SOC_SOF_PRIV_H
#include <linux/device.h>
#include <sound/hdaudio.h>
#include <sound/soc.h>
#include <sound/control.h>
#include <sound/sof.h>
#include <sound/sof/stream.h> /* needs to be included before control.h */
#include <sound/sof/control.h>
#include <sound/sof/dai.h>
#include <sound/sof/info.h>
#include <sound/sof/pm.h>
#include <sound/sof/topology.h>
#include <sound/sof/trace.h>
#include <uapi/sound/sof/fw.h>
/* debug flags */
@ -48,9 +39,6 @@ extern int sof_core_debug;
/* DMA buffer size for trace */
#define DMA_BUF_SIZE_FOR_TRACE (PAGE_SIZE * 16)
/* max number of FE PCMs before BEs */
#define SOF_BE_PCM_BASE 16
#define SOF_IPC_DSP_REPLY 0
#define SOF_IPC_HOST_REPLY 1
@ -66,8 +54,6 @@ extern int sof_core_debug;
(IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE) || \
IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_IPC_FLOOD_TEST))
#define DMA_CHAN_INVALID 0xFFFFFFFF
/* DSP D0ix sub-state */
enum sof_d0_substate {
SOF_DSP_D0I0 = 0, /* DSP default D0 substate */
@ -303,90 +289,6 @@ struct snd_sof_ipc_msg {
bool ipc_complete;
};
/* PCM stream, mapped to FW component */
struct snd_sof_pcm_stream {
u32 comp_id;
struct snd_dma_buffer page_table;
struct sof_ipc_stream_posn posn;
struct snd_pcm_substream *substream;
struct work_struct period_elapsed_work;
bool d0i3_compatible; /* DSP can be in D0I3 when this pcm is opened */
/*
* flag to indicate that the DSP pipelines should be kept
* active or not while suspending the stream
*/
bool suspend_ignored;
};
/* ALSA SOF PCM device */
struct snd_sof_pcm {
struct snd_sof_dev *sdev;
struct snd_soc_tplg_pcm pcm;
struct snd_sof_pcm_stream stream[2];
struct list_head list; /* list in sdev pcm list */
struct snd_pcm_hw_params params[2];
bool prepared[2]; /* PCM_PARAMS set successfully */
};
struct snd_sof_led_control {
unsigned int use_led;
unsigned int direction;
unsigned int led_value;
};
/* ALSA SOF Kcontrol device */
struct snd_sof_control {
struct snd_sof_dev *sdev;
int comp_id;
int min_volume_step; /* min volume step for volume_table */
int max_volume_step; /* max volume step for volume_table */
int num_channels;
u32 readback_offset; /* offset to mmaped data if used */
struct sof_ipc_ctrl_data *control_data;
u32 size; /* cdata size */
enum sof_ipc_ctrl_cmd cmd;
u32 *volume_table; /* volume table computed from tlv data*/
struct list_head list; /* list in sdev control list */
struct snd_sof_led_control led_ctl;
};
/* ASoC SOF DAPM widget */
struct snd_sof_widget {
struct snd_sof_dev *sdev;
int comp_id;
int pipeline_id;
int complete;
int id;
struct snd_soc_dapm_widget *widget;
struct list_head list; /* list in sdev widget list */
void *private; /* core does not touch this */
};
/* ASoC SOF DAPM route */
struct snd_sof_route {
struct snd_sof_dev *sdev;
struct snd_soc_dapm_route *route;
struct list_head list; /* list in sdev route list */
void *private;
};
/* ASoC DAI device */
struct snd_sof_dai {
struct snd_sof_dev *sdev;
const char *name;
const char *cpu_dai_name;
struct sof_ipc_comp_dai comp_dai;
struct sof_ipc_dai_config *dai_config;
struct list_head list; /* list in sdev dai list */
};
/*
* SOF Device Level.
*/
@ -531,67 +433,6 @@ int snd_sof_ipc_valid(struct snd_sof_dev *sdev);
int sof_ipc_tx_message(struct snd_sof_ipc *ipc, u32 header,
void *msg_data, size_t msg_bytes, void *reply_data,
size_t reply_bytes);
struct snd_sof_widget *snd_sof_find_swidget(struct snd_sof_dev *sdev,
const char *name);
struct snd_sof_widget *snd_sof_find_swidget_sname(struct snd_sof_dev *sdev,
const char *pcm_name,
int dir);
struct snd_sof_dai *snd_sof_find_dai(struct snd_sof_dev *sdev,
const char *name);
static inline
struct snd_sof_pcm *snd_sof_find_spcm_dai(struct snd_sof_dev *sdev,
struct snd_soc_pcm_runtime *rtd)
{
struct snd_sof_pcm *spcm = NULL;
list_for_each_entry(spcm, &sdev->pcm_list, list) {
if (le32_to_cpu(spcm->pcm.dai_id) == rtd->dai_link->id)
return spcm;
}
return NULL;
}
bool snd_sof_dsp_d0i3_on_suspend(struct snd_sof_dev *sdev);
struct snd_sof_pcm *snd_sof_find_spcm_name(struct snd_sof_dev *sdev,
const char *name);
struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_sof_dev *sdev,
unsigned int comp_id,
int *direction);
struct snd_sof_pcm *snd_sof_find_spcm_pcm_id(struct snd_sof_dev *sdev,
unsigned int pcm_id);
void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream);
/*
* Stream IPC
*/
int snd_sof_ipc_stream_posn(struct snd_sof_dev *sdev,
struct snd_sof_pcm *spcm, int direction,
struct sof_ipc_stream_posn *posn);
/*
* Mixer IPC
*/
int snd_sof_ipc_set_get_comp_data(struct snd_sof_ipc *ipc,
struct snd_sof_control *scontrol, u32 ipc_cmd,
enum sof_ipc_ctrl_type ctrl_type,
enum sof_ipc_ctrl_cmd ctrl_cmd,
bool send);
/*
* Topology.
* There is no snd_sof_free_topology since topology components will
* be freed by snd_soc_unregister_component,
*/
int snd_sof_load_topology(struct snd_sof_dev *sdev, const char *file);
int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
struct snd_sof_widget *swidget);
int sof_load_pipeline_ipc(struct snd_sof_dev *sdev,
struct sof_ipc_pipe_new *pipeline,
struct sof_ipc_comp_reply *r);
/*
* Trace/debug
@ -623,40 +464,12 @@ void snd_sof_handle_fw_exception(struct snd_sof_dev *sdev);
*/
extern struct snd_compr_ops sof_compressed_ops;
/*
* Kcontrols.
*/
int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
const unsigned int __user *binary_data,
unsigned int size);
int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
unsigned int __user *binary_data,
unsigned int size);
/*
* DSP Architectures.
*/
static inline void sof_stack(struct snd_sof_dev *sdev, void *oops, u32 *stack,
u32 stack_words)
{
if (sof_arch_ops(sdev)->dsp_stack)
sof_arch_ops(sdev)->dsp_stack(sdev, oops, stack, stack_words);
}

File diff suppressed because it is too large Load Diff