Skip to content

Commit

Permalink
ASoC: SOF: topology: Make control parsing IPC agnostic
Browse files Browse the repository at this point in the history
Make the control parser in topology IPC agnostic by introducing 2 new
topology IPC ops, control_setup and control_free. These ops handle
setting up/freeing the control data in the IPC format based on the IPC
version.

Along with this, modify the struct snd_sof_control to remove the
IPC-specific field, control_data and replace it with the void pointer to
ipc_control_data. Also, add a few new fields to store all the
information parsed from topology.

Finally, define and set the control setup/free ops for IPC3.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20220314200520.1233427-18-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Ranjani Sridharan authored and Mark Brown committed Mar 16, 2022
1 parent 909dadf commit b5cee8f
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 141 deletions.
26 changes: 13 additions & 13 deletions sound/soc/sof/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size)

static void snd_sof_refresh_control(struct snd_sof_control *scontrol)
{
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
struct snd_soc_component *scomp = scontrol->scomp;
int ret;

Expand Down Expand Up @@ -97,7 +97,7 @@ 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 sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
unsigned int i, channels = scontrol->num_channels;

snd_sof_refresh_control(scontrol);
Expand All @@ -118,7 +118,7 @@ int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
unsigned int i, channels = scontrol->num_channels;
bool change = false;
u32 value;
Expand Down Expand Up @@ -166,7 +166,7 @@ int snd_sof_switch_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 sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
unsigned int i, channels = scontrol->num_channels;

snd_sof_refresh_control(scontrol);
Expand All @@ -185,7 +185,7 @@ int snd_sof_switch_put(struct snd_kcontrol *kcontrol,
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_sof_control *scontrol = sm->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
unsigned int i, channels = scontrol->num_channels;
bool change = false;
u32 value;
Expand Down Expand Up @@ -214,7 +214,7 @@ 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 sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
unsigned int i, channels = scontrol->num_channels;

snd_sof_refresh_control(scontrol);
Expand All @@ -233,7 +233,7 @@ int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
(struct soc_enum *)kcontrol->private_value;
struct snd_sof_control *scontrol = se->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
unsigned int i, channels = scontrol->num_channels;
bool change = false;
u32 value;
Expand All @@ -260,7 +260,7 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size;

Expand Down Expand Up @@ -296,7 +296,7 @@ int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
struct sof_abi_hdr *data = cdata->data;
size_t size;

Expand Down Expand Up @@ -335,7 +335,7 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol,
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
struct snd_ctl_tlv header;
const struct snd_ctl_tlv __user *tlvd =
(const struct snd_ctl_tlv __user *)binary_data;
Expand Down Expand Up @@ -409,7 +409,7 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _
struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
struct snd_ctl_tlv header;
struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data;
size_t data_size;
Expand Down Expand Up @@ -482,7 +482,7 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol,
(struct soc_bytes_ext *)kcontrol->private_value;
struct snd_sof_control *scontrol = be->dobj.private;
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
struct snd_ctl_tlv header;
struct snd_ctl_tlv __user *tlvd =
(struct snd_ctl_tlv __user *)binary_data;
Expand Down Expand Up @@ -534,7 +534,7 @@ static void snd_sof_update_control(struct snd_sof_control *scontrol,
struct sof_ipc_ctrl_data *local_cdata;
int i;

local_cdata = scontrol->control_data;
local_cdata = scontrol->ipc_control_data;

if (cdata->cmd == SOF_CTRL_CMD_BINARY) {
if (cdata->num_elems != local_cdata->data->size) {
Expand Down
2 changes: 1 addition & 1 deletion sound/soc/sof/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ static int sof_set_get_large_ctrl_data(struct snd_sof_dev *sdev,
int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol, bool set)
{
struct snd_soc_component *scomp = scontrol->scomp;
struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;
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;
Expand Down
151 changes: 149 additions & 2 deletions sound/soc/sof/ipc3-topology.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
#include "sof-audio.h"
#include "ops.h"

/* Full volume for default values */
#define VOL_ZERO_DB BIT(VOLUME_FWL)

struct sof_widget_data {
int ctrl_type;
int ipc_cmd;
Expand Down Expand Up @@ -743,6 +746,7 @@ static int sof_get_control_data(struct snd_soc_component *scomp,
struct sof_widget_data *wdata, size_t *size)
{
const struct snd_kcontrol_new *kc;
struct sof_ipc_ctrl_data *cdata;
struct soc_mixer_control *sm;
struct soc_bytes_ext *sbe;
struct soc_enum *se;
Expand Down Expand Up @@ -777,7 +781,8 @@ static int sof_get_control_data(struct snd_soc_component *scomp,
return -EINVAL;
}

wdata[i].pdata = wdata[i].control->control_data->data;
cdata = wdata[i].control->ipc_control_data;
wdata[i].pdata = cdata->data;
if (!wdata[i].pdata)
return -EINVAL;

Expand All @@ -789,7 +794,7 @@ static int sof_get_control_data(struct snd_soc_component *scomp,
*size += wdata[i].pdata->size;

/* get data type */
switch (wdata[i].control->control_data->cmd) {
switch (cdata->cmd) {
case SOF_CTRL_CMD_VOLUME:
case SOF_CTRL_CMD_ENUM:
case SOF_CTRL_CMD_SWITCH:
Expand Down Expand Up @@ -1553,6 +1558,146 @@ static int sof_ipc3_route_setup(struct snd_sof_dev *sdev, struct snd_sof_route *
return ret;
}

static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
{
struct sof_ipc_ctrl_data *cdata;
int ret;

scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
if (!scontrol->ipc_control_data)
return -ENOMEM;

if (scontrol->max_size < sizeof(*cdata) ||
scontrol->max_size < sizeof(struct sof_abi_hdr)) {
ret = -EINVAL;
goto err;
}

/* init the get/put bytes data */
if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
dev_err(sdev->dev, "err: bytes data size %zu exceeds max %zu.\n",
scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
ret = -EINVAL;
goto err;
}

scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;

cdata = scontrol->ipc_control_data;
cdata->cmd = SOF_CTRL_CMD_BINARY;
cdata->index = scontrol->index;

if (scontrol->priv_size > 0) {
memcpy(cdata->data, scontrol->priv, scontrol->priv_size);
kfree(scontrol->priv);

if (cdata->data->magic != SOF_ABI_MAGIC) {
dev_err(sdev->dev, "Wrong ABI magic 0x%08x.\n", cdata->data->magic);
ret = -EINVAL;
goto err;
}

if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) {
dev_err(sdev->dev, "Incompatible ABI version 0x%08x.\n",
cdata->data->abi);
ret = -EINVAL;
goto err;
}

if (cdata->data->size + sizeof(struct sof_abi_hdr) != scontrol->priv_size) {
dev_err(sdev->dev, "Conflict in bytes vs. priv size.\n");
ret = -EINVAL;
goto err;
}
}

return 0;
err:
kfree(scontrol->ipc_control_data);
return ret;
}

static int sof_ipc3_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
{
struct sof_ipc_ctrl_data *cdata;
int i;

/* init the volume get/put data */
scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);

scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
if (!scontrol->ipc_control_data)
return -ENOMEM;

cdata = scontrol->ipc_control_data;
cdata->index = scontrol->index;

/* set cmd for mixer control */
if (scontrol->max == 1) {
cdata->cmd = SOF_CTRL_CMD_SWITCH;
return 0;
}

cdata->cmd = SOF_CTRL_CMD_VOLUME;

/* set default volume values to 0dB in control */
for (i = 0; i < scontrol->num_channels; i++) {
cdata->chanv[i].channel = i;
cdata->chanv[i].value = VOL_ZERO_DB;
}

return 0;
}

static int sof_ipc3_control_load_enum(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
{
struct sof_ipc_ctrl_data *cdata;

/* init the enum get/put data */
scontrol->size = struct_size(cdata, chanv, scontrol->num_channels);

scontrol->ipc_control_data = kzalloc(scontrol->size, GFP_KERNEL);
if (!scontrol->ipc_control_data)
return -ENOMEM;

cdata = scontrol->ipc_control_data;
cdata->index = scontrol->index;
cdata->cmd = SOF_CTRL_CMD_ENUM;

return 0;
}

static int sof_ipc3_control_setup(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
{
switch (scontrol->info_type) {
case SND_SOC_TPLG_CTL_VOLSW:
case SND_SOC_TPLG_CTL_VOLSW_SX:
case SND_SOC_TPLG_CTL_VOLSW_XR_SX:
return sof_ipc3_control_load_volume(sdev, scontrol);
case SND_SOC_TPLG_CTL_BYTES:
return sof_ipc3_control_load_bytes(sdev, scontrol);
case SND_SOC_TPLG_CTL_ENUM:
case SND_SOC_TPLG_CTL_ENUM_VALUE:
return sof_ipc3_control_load_enum(sdev, scontrol);
default:
break;
}

return 0;
}

static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
{
struct sof_ipc_free fcomp;

fcomp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_FREE;
fcomp.hdr.size = sizeof(fcomp);
fcomp.id = scontrol->comp_id;

/* send IPC to the DSP */
return sof_ipc_tx_message(sdev->ipc, fcomp.hdr.cmd, &fcomp, sizeof(fcomp), NULL, 0);
}

/* token list for each topology object */
static enum sof_tokens host_token_list[] = {
SOF_CORE_TOKENS,
Expand Down Expand Up @@ -1651,6 +1796,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY
static const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
.widget = tplg_ipc3_widget_ops,
.route_setup = sof_ipc3_route_setup,
.control_setup = sof_ipc3_control_setup,
.control_free = sof_ipc3_control_free,
.token_list = ipc3_token_list,
};

Expand Down
20 changes: 19 additions & 1 deletion sound/soc/sof/sof-audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,15 @@

#define WIDGET_IS_DAI(id) ((id) == snd_soc_dapm_dai_in || (id) == snd_soc_dapm_dai_out)

/*
* Volume fractional word length define to 16 sets
* the volume linear gain value to use Qx.16 format
*/
#define VOLUME_FWL 16

struct snd_sof_widget;
struct snd_sof_route;
struct snd_sof_control;

/**
* struct sof_ipc_tplg_widget_ops - IPC-specific ops for topology widgets
Expand Down Expand Up @@ -59,11 +66,15 @@ struct sof_ipc_tplg_widget_ops {
* @token_list: List of all tokens supported by the IPC version. The size of the token_list
* array should be SOF_TOKEN_COUNT. The unused elements in the array will be
* initialized to 0.
* @control_setup: Function pointer for setting up kcontrol IPC-specific data
* @control_free: Function pointer for freeing kcontrol IPC-specific data
*/
struct sof_ipc_tplg_ops {
const struct sof_ipc_tplg_widget_ops *widget;
int (*route_setup)(struct snd_sof_dev *sdev, struct snd_sof_route *sroute);
const struct sof_token_info *token_list;
int (*control_setup)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol);
int (*control_free)(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol);
};

/** struct snd_sof_tuple - Tuple info
Expand Down Expand Up @@ -165,13 +176,20 @@ struct snd_sof_led_control {
/* ALSA SOF Kcontrol device */
struct snd_sof_control {
struct snd_soc_component *scomp;
const char *name;
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;
unsigned int access;
u32 readback_offset; /* offset to mmapped data if used */
struct sof_ipc_ctrl_data *control_data;
int info_type;
int index; /* pipeline ID */
void *priv; /* private data copied from topology */
size_t priv_size; /* size of private data */
size_t max_size;
void *ipc_control_data;
int max; /* applicable to volume controls */
u32 size; /* cdata size */
u32 *volume_table; /* volume table computed from tlv data*/

Expand Down
Loading

0 comments on commit b5cee8f

Please sign in to comment.