Skip to content

Commit

Permalink
ASoC: SOF: dont wake dsp up in kcontrol IO
Browse files Browse the repository at this point in the history
Always get kcontrol value from cache, set kcontrol value to DSP
when DSP is active. Kcontrol values will be restored when DSP boot up.
Also, we read kcontrol values from firmware in sof_complete to make sure
the value is align with firmware.

Signed-off-by: Bard liao <bard.liao@intel.com>
  • Loading branch information
bardliao committed Nov 6, 2018
1 parent a5ddc3d commit 6056880
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 134 deletions.
159 changes: 25 additions & 134 deletions sound/soc/sof/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,34 +46,15 @@ int snd_sof_volume_get(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 sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
int err, ret;

ret = pm_runtime_get_sync(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev, "error: volume get failed to resume %d\n",
ret);
return ret;
}

/* get all the mixer data from DSP */
snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_VOLUME);

/* read back each channel */
for (i = 0; i < channels; i++)
ucontrol->value.integer.value[i] =
ipc_to_mixer(cdata->chanv[i].value,
scontrol->volume_table, sm->max + 1);

pm_runtime_mark_last_busy(sdev->dev);
err = pm_runtime_put_autosuspend(sdev->dev);
if (err < 0)
dev_err(sdev->dev, "error: volume get failed to idle %d\n",
err);
return 0;
}

Expand All @@ -86,14 +67,6 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
int ret, err;

ret = pm_runtime_get_sync(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev, "error: volume put failed to resume %d\n",
ret);
return ret;
}

/* update each channel */
for (i = 0; i < channels; i++) {
Expand All @@ -104,15 +77,11 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
}

/* notify DSP of mixer updates */
snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_VOLUME);

pm_runtime_mark_last_busy(sdev->dev);
err = pm_runtime_put_autosuspend(sdev->dev);
if (err < 0)
dev_err(sdev->dev, "error: volume put failed to idle %d\n",
err);
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_VOLUME);
return 0;
}

Expand All @@ -122,32 +91,13 @@ int snd_sof_enum_get(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 sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
int err, ret;

ret = pm_runtime_get_sync(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev, "error: enum get failed to resume %d\n",
ret);
return ret;
}

/* get all the mixer data from DSP */
snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_GET,
SOF_CTRL_CMD_ENUM);

/* read back each channel */
for (i = 0; i < channels; i++)
ucontrol->value.integer.value[i] = cdata->chanv[i].value;

pm_runtime_mark_last_busy(sdev->dev);
err = pm_runtime_put_autosuspend(sdev->dev);
if (err < 0)
dev_err(sdev->dev, "error: enum get failed to idle %d\n",
ret);
return 0;
}

Expand All @@ -160,29 +110,18 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
unsigned int i, channels = scontrol->num_channels;
int ret, err;

ret = pm_runtime_get_sync(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev, "error: enum put failed to resume %d\n",
ret);
return ret;
}

/* update each channel */
for (i = 0; i < channels; i++)
cdata->chanv[i].value = ucontrol->value.integer.value[i];

/* notify DSP of mixer updates */
snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_SET,
SOF_CTRL_CMD_ENUM);

pm_runtime_mark_last_busy(sdev->dev);
err = pm_runtime_put_autosuspend(sdev->dev);
if (err < 0)
dev_err(sdev->dev, "error: enum put failed to idle %d\n",
err);
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_SET_VALUE,
SOF_CTRL_TYPE_VALUE_CHAN_SET,
SOF_CTRL_CMD_ENUM);

return 0;
}

Expand All @@ -196,18 +135,8 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size;
int ret, err;

ret = pm_runtime_get_sync(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev, "error: bytes get failed to resume %d\n",
ret);
return ret;
}
int ret = 0;

/* get all the mixer data from DSP */
snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_DATA,
SOF_CTRL_TYPE_DATA_GET, scontrol->cmd);
size = data->size + sizeof(*data);
if (size > be->max) {
dev_err(sdev->dev, "error: DSP sent %zu bytes max is %d\n",
Expand All @@ -220,11 +149,6 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
memcpy(ucontrol->value.bytes.data, data, size);

out:
pm_runtime_mark_last_busy(sdev->dev);
err = pm_runtime_put_autosuspend(sdev->dev);
if (err < 0)
dev_err(sdev->dev, "error: bytes get failed to idle %d\n",
err);
return ret;
}

Expand All @@ -237,14 +161,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_sof_dev *sdev = scontrol->sdev;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_abi_hdr *data = cdata->data;
int ret, err;

ret = pm_runtime_get_sync(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev, "error: bytes put failed to resume %d\n",
ret);
return ret;
}
int ret = 0;

if (data->size > be->max) {
dev_err(sdev->dev, "error: size too big %d bytes max is %d\n",
Expand All @@ -257,15 +174,13 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
memcpy(data, ucontrol->value.bytes.data, data->size);

/* notify DSP of mixer updates */
snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET, scontrol->cmd);
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET,
scontrol->cmd);

out:
pm_runtime_mark_last_busy(sdev->dev);
err = pm_runtime_put_autosuspend(sdev->dev);
if (err < 0)
dev_err(sdev->dev, "error: volume get failed to idle %d\n",
err);
return ret;
}

Expand All @@ -280,19 +195,11 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct snd_ctl_tlv header;
struct snd_ctl_tlv *tlvd = (struct snd_ctl_tlv *)binary_data;
int ret;
int err;
int ret = 0;
int max_length = SOF_IPC_MSG_MAX_SIZE -
sizeof(const struct sof_ipc_ctrl_data) -
sizeof(const struct sof_abi_hdr);

ret = pm_runtime_get_sync(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev, "error: bytes put failed to resume %d\n",
ret);
return ret;
}

/* The beginning of bytes data contains a header from where
* the length (as bytes) is needed to know the correct copy
* length of data from tlvd->tlv.
Expand Down Expand Up @@ -330,15 +237,13 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
cdata->data->comp_abi = SOF_ABI_VERSION;

/* notify DSP of mixer updates */
snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET, scontrol->cmd);
if (pm_runtime_active(sdev->dev))
snd_sof_ipc_set_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_SET_DATA,
SOF_CTRL_TYPE_DATA_SET,
scontrol->cmd);

out:
pm_runtime_mark_last_busy(sdev->dev);
err = pm_runtime_put_autosuspend(sdev->dev);
if (err < 0)
dev_err(sdev->dev, "error: failed to idle %d\n", err);

return ret;
}

Expand All @@ -356,14 +261,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
int max_length = SOF_IPC_MSG_MAX_SIZE -
sizeof(const struct sof_ipc_ctrl_data) -
sizeof(const struct sof_abi_hdr);
int ret;

ret = pm_runtime_get_sync(sdev->dev);
if (ret < 0) {
dev_err(sdev->dev, "error: bytes get failed to resume %d\n",
ret);
return ret;
}
int ret = 0;

/* Decrement size to fit the ext bytes header and get the the
* upper limit from ext bytes control size from topology and
Expand All @@ -388,11 +286,6 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
cdata->data->abi = SOF_ABI_VERSION;
cdata->data->comp_abi = SOF_ABI_VERSION;

/* get all the component data from DSP */
ret = snd_sof_ipc_get_comp_data(sdev->ipc, scontrol,
SOF_IPC_COMP_GET_DATA,
SOF_CTRL_TYPE_DATA_GET, scontrol->cmd);

header.numid = scontrol->cmd;
header.length = size;
if (copy_to_user(tlvd, &header, sizeof(const struct snd_ctl_tlv)))
Expand All @@ -402,7 +295,5 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
return -EFAULT;

out:
pm_runtime_mark_last_busy(sdev->dev);
pm_runtime_put_autosuspend(sdev->dev);
return ret;
}
46 changes: 46 additions & 0 deletions sound/soc/sof/topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -2360,6 +2360,51 @@ int snd_sof_complete_pipeline(struct snd_sof_dev *sdev,
return 1;
}

/* Function to read the initial value of SOF kcontrols.
* The value will be stored in scontrol->control_data
*/
static int snd_sof_get_kcontrol_val(struct snd_sof_dev *sdev)
{
struct snd_sof_control *scontrol = NULL;
int ipc_cmd, ctrl_type;
int ret = 0;

list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {

/* notify DSP of kcontrol values */
switch (scontrol->cmd) {
case SOF_CTRL_CMD_VOLUME:
case SOF_CTRL_CMD_ENUM:
ipc_cmd = SOF_IPC_COMP_GET_VALUE;
ctrl_type = SOF_CTRL_TYPE_VALUE_CHAN_GET;
ret = snd_sof_ipc_get_comp_data(sdev->ipc, scontrol,
ipc_cmd, ctrl_type,
scontrol->cmd);
break;
case SOF_CTRL_CMD_BINARY:
ipc_cmd = SOF_IPC_COMP_GET_DATA;
ctrl_type = SOF_CTRL_TYPE_DATA_GET;
ret = snd_sof_ipc_get_comp_data(sdev->ipc, scontrol,
ipc_cmd, ctrl_type,
scontrol->cmd);
break;

default:
dev_err(sdev->dev,
"error: Invalid scontrol->cmd: %d\n",
scontrol->cmd);
return -EINVAL;
}
if (ret < 0) {
dev_warn(sdev->dev,
"error: kcontrol value get for widget: %d\n",
scontrol->comp_id);
}
}

return ret;
}

/* completion - called at completion of firmware loading */
static void sof_complete(struct snd_soc_component *scomp)
{
Expand All @@ -2380,6 +2425,7 @@ static void sof_complete(struct snd_soc_component *scomp)
break;
}
}
snd_sof_get_kcontrol_val(sdev);
}

/* manifest - optional to inform component of manifest */
Expand Down

0 comments on commit 6056880

Please sign in to comment.