ASoC: Intel: Skylake: Parse vendor tokens to build module data
Skl topology data is preceded by a descriptor for number of data blocks, the size of the data block and type of data block. The type of the data block can be either a tuple or a binary blob. Private data is parsed based on data block type and module data is filled accordingly. Signed-off-by: Shreyas NC <shreyas.nc@intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
15f0d4f531
commit
6277e83292
2 changed files with 545 additions and 110 deletions
|
@ -21,6 +21,7 @@
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
#include <sound/soc.h>
|
#include <sound/soc.h>
|
||||||
#include <sound/soc-topology.h>
|
#include <sound/soc-topology.h>
|
||||||
|
#include <uapi/sound/snd_sst_tokens.h>
|
||||||
#include "skl-sst-dsp.h"
|
#include "skl-sst-dsp.h"
|
||||||
#include "skl-sst-ipc.h"
|
#include "skl-sst-ipc.h"
|
||||||
#include "skl-topology.h"
|
#include "skl-topology.h"
|
||||||
|
@ -32,6 +33,8 @@
|
||||||
#define SKL_CH_FIXUP_MASK (1 << 0)
|
#define SKL_CH_FIXUP_MASK (1 << 0)
|
||||||
#define SKL_RATE_FIXUP_MASK (1 << 1)
|
#define SKL_RATE_FIXUP_MASK (1 << 1)
|
||||||
#define SKL_FMT_FIXUP_MASK (1 << 2)
|
#define SKL_FMT_FIXUP_MASK (1 << 2)
|
||||||
|
#define SKL_IN_DIR_BIT_MASK BIT(0)
|
||||||
|
#define SKL_PIN_COUNT_MASK GENMASK(7, 4)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SKL DSP driver modelling uses only few DAPM widgets so for rest we will
|
* SKL DSP driver modelling uses only few DAPM widgets so for rest we will
|
||||||
|
@ -1468,85 +1471,570 @@ static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = {
|
||||||
skl_tplg_tlv_control_set},
|
skl_tplg_tlv_control_set},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
static int skl_tplg_fill_pipe_tkn(struct device *dev,
|
||||||
* The topology binary passes the pin info for a module so initialize the pin
|
struct skl_pipe *pipe, u32 tkn,
|
||||||
* info passed into module instance
|
u32 tkn_val)
|
||||||
*/
|
|
||||||
static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin,
|
|
||||||
struct skl_module_pin *m_pin,
|
|
||||||
bool is_dynamic, int max_pin)
|
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < max_pin; i++) {
|
switch (tkn) {
|
||||||
m_pin[i].id.module_id = dfw_pin[i].module_id;
|
case SKL_TKN_U32_PIPE_CONN_TYPE:
|
||||||
m_pin[i].id.instance_id = dfw_pin[i].instance_id;
|
pipe->conn_type = tkn_val;
|
||||||
m_pin[i].in_use = false;
|
break;
|
||||||
m_pin[i].is_dynamic = is_dynamic;
|
|
||||||
m_pin[i].pin_state = SKL_PIN_UNBIND;
|
case SKL_TKN_U32_PIPE_PRIORITY:
|
||||||
|
pipe->pipe_priority = tkn_val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_PIPE_MEM_PGS:
|
||||||
|
pipe->memory_pages = tkn_val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(dev, "Token not handled %d\n", tkn);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add pipeline from topology binary into driver pipeline list
|
* Add pipeline by parsing the relevant tokens
|
||||||
*
|
* Return an existing pipe if the pipe already exists.
|
||||||
* If already added we return that instance
|
|
||||||
* Otherwise we create a new instance and add into driver list
|
|
||||||
*/
|
*/
|
||||||
static struct skl_pipe *skl_tplg_add_pipe(struct device *dev,
|
static int skl_tplg_add_pipe(struct device *dev,
|
||||||
struct skl *skl, struct skl_dfw_pipe *dfw_pipe)
|
struct skl_module_cfg *mconfig, struct skl *skl,
|
||||||
|
struct snd_soc_tplg_vendor_value_elem *tkn_elem)
|
||||||
{
|
{
|
||||||
struct skl_pipeline *ppl;
|
struct skl_pipeline *ppl;
|
||||||
struct skl_pipe *pipe;
|
struct skl_pipe *pipe;
|
||||||
struct skl_pipe_params *params;
|
struct skl_pipe_params *params;
|
||||||
|
|
||||||
list_for_each_entry(ppl, &skl->ppl_list, node) {
|
list_for_each_entry(ppl, &skl->ppl_list, node) {
|
||||||
if (ppl->pipe->ppl_id == dfw_pipe->pipe_id)
|
if (ppl->pipe->ppl_id == tkn_elem->value) {
|
||||||
return ppl->pipe;
|
mconfig->pipe = ppl->pipe;
|
||||||
|
return EEXIST;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
|
ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL);
|
||||||
if (!ppl)
|
if (!ppl)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
|
|
||||||
pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
|
pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL);
|
||||||
if (!pipe)
|
if (!pipe)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
|
|
||||||
params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
|
params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL);
|
||||||
if (!params)
|
if (!params)
|
||||||
return NULL;
|
return -ENOMEM;
|
||||||
|
|
||||||
pipe->ppl_id = dfw_pipe->pipe_id;
|
|
||||||
pipe->memory_pages = dfw_pipe->memory_pages;
|
|
||||||
pipe->pipe_priority = dfw_pipe->pipe_priority;
|
|
||||||
pipe->conn_type = dfw_pipe->conn_type;
|
|
||||||
pipe->state = SKL_PIPE_INVALID;
|
|
||||||
pipe->p_params = params;
|
pipe->p_params = params;
|
||||||
|
pipe->ppl_id = tkn_elem->value;
|
||||||
INIT_LIST_HEAD(&pipe->w_list);
|
INIT_LIST_HEAD(&pipe->w_list);
|
||||||
|
|
||||||
ppl->pipe = pipe;
|
ppl->pipe = pipe;
|
||||||
list_add(&ppl->node, &skl->ppl_list);
|
list_add(&ppl->node, &skl->ppl_list);
|
||||||
|
|
||||||
return ppl->pipe;
|
mconfig->pipe = pipe;
|
||||||
|
mconfig->pipe->state = SKL_PIPE_INVALID;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt,
|
static int skl_tplg_fill_pin(struct device *dev, u32 tkn,
|
||||||
struct skl_dfw_module_fmt *src_fmt,
|
struct skl_module_pin *m_pin,
|
||||||
int pins)
|
int pin_index, u32 value)
|
||||||
|
{
|
||||||
|
switch (tkn) {
|
||||||
|
case SKL_TKN_U32_PIN_MOD_ID:
|
||||||
|
m_pin[pin_index].id.module_id = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_PIN_INST_ID:
|
||||||
|
m_pin[pin_index].id.instance_id = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(dev, "%d Not a pin token\n", value);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse for pin config specific tokens to fill up the
|
||||||
|
* module private data
|
||||||
|
*/
|
||||||
|
static int skl_tplg_fill_pins_info(struct device *dev,
|
||||||
|
struct skl_module_cfg *mconfig,
|
||||||
|
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
|
||||||
|
int dir, int pin_count)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct skl_module_pin *m_pin;
|
||||||
|
|
||||||
|
switch (dir) {
|
||||||
|
case SKL_DIR_IN:
|
||||||
|
m_pin = mconfig->m_in_pin;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_DIR_OUT:
|
||||||
|
m_pin = mconfig->m_out_pin;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(dev, "Invalid direction value");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = skl_tplg_fill_pin(dev, tkn_elem->token,
|
||||||
|
m_pin, pin_count, tkn_elem->value);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
m_pin[pin_count].in_use = false;
|
||||||
|
m_pin[pin_count].pin_state = SKL_PIN_UNBIND;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill up input/output module config format based
|
||||||
|
* on the direction
|
||||||
|
*/
|
||||||
|
static int skl_tplg_fill_fmt(struct device *dev,
|
||||||
|
struct skl_module_cfg *mconfig, u32 tkn,
|
||||||
|
u32 value, u32 dir, u32 pin_count)
|
||||||
|
{
|
||||||
|
struct skl_module_fmt *dst_fmt;
|
||||||
|
|
||||||
|
switch (dir) {
|
||||||
|
case SKL_DIR_IN:
|
||||||
|
dst_fmt = mconfig->in_fmt;
|
||||||
|
dst_fmt += pin_count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_DIR_OUT:
|
||||||
|
dst_fmt = mconfig->out_fmt;
|
||||||
|
dst_fmt += pin_count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(dev, "Invalid direction value");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (tkn) {
|
||||||
|
case SKL_TKN_U32_FMT_CH:
|
||||||
|
dst_fmt->channels = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_FMT_FREQ:
|
||||||
|
dst_fmt->s_freq = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_FMT_BIT_DEPTH:
|
||||||
|
dst_fmt->bit_depth = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_FMT_SAMPLE_SIZE:
|
||||||
|
dst_fmt->valid_bit_depth = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_FMT_CH_CONFIG:
|
||||||
|
dst_fmt->ch_cfg = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_FMT_INTERLEAVE:
|
||||||
|
dst_fmt->interleaving_style = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_FMT_SAMPLE_TYPE:
|
||||||
|
dst_fmt->sample_type = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_FMT_CH_MAP:
|
||||||
|
dst_fmt->ch_map = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(dev, "Invalid token %d", tkn);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int skl_tplg_get_uuid(struct device *dev, struct skl_module_cfg *mconfig,
|
||||||
|
struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn)
|
||||||
|
{
|
||||||
|
if (uuid_tkn->token == SKL_TKN_UUID)
|
||||||
|
memcpy(&mconfig->guid, &uuid_tkn->uuid, 16);
|
||||||
|
else {
|
||||||
|
dev_err(dev, "Not an UUID token tkn %d", uuid_tkn->token);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void skl_tplg_fill_pin_dynamic_val(
|
||||||
|
struct skl_module_pin *mpin, u32 pin_count, u32 value)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < pins; i++) {
|
for (i = 0; i < pin_count; i++)
|
||||||
dst_fmt[i].channels = src_fmt[i].channels;
|
mpin[i].is_dynamic = value;
|
||||||
dst_fmt[i].s_freq = src_fmt[i].freq;
|
}
|
||||||
dst_fmt[i].bit_depth = src_fmt[i].bit_depth;
|
|
||||||
dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth;
|
/*
|
||||||
dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg;
|
* Parse tokens to fill up the module private data
|
||||||
dst_fmt[i].ch_map = src_fmt[i].ch_map;
|
*/
|
||||||
dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style;
|
static int skl_tplg_get_token(struct device *dev,
|
||||||
dst_fmt[i].sample_type = src_fmt[i].sample_type;
|
struct snd_soc_tplg_vendor_value_elem *tkn_elem,
|
||||||
|
struct skl *skl, struct skl_module_cfg *mconfig)
|
||||||
|
{
|
||||||
|
int tkn_count = 0;
|
||||||
|
int ret;
|
||||||
|
static int is_pipe_exists;
|
||||||
|
static int pin_index, dir;
|
||||||
|
|
||||||
|
if (tkn_elem->token > SKL_TKN_MAX)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (tkn_elem->token) {
|
||||||
|
case SKL_TKN_U8_IN_QUEUE_COUNT:
|
||||||
|
mconfig->max_in_queue = tkn_elem->value;
|
||||||
|
mconfig->m_in_pin = devm_kzalloc(dev, mconfig->max_in_queue *
|
||||||
|
sizeof(*mconfig->m_in_pin),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!mconfig->m_in_pin)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U8_OUT_QUEUE_COUNT:
|
||||||
|
mconfig->max_out_queue = tkn_elem->value;
|
||||||
|
mconfig->m_out_pin = devm_kzalloc(dev, mconfig->max_out_queue *
|
||||||
|
sizeof(*mconfig->m_out_pin),
|
||||||
|
GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!mconfig->m_out_pin)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U8_DYN_IN_PIN:
|
||||||
|
if (!mconfig->m_in_pin)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin,
|
||||||
|
mconfig->max_in_queue, tkn_elem->value);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U8_DYN_OUT_PIN:
|
||||||
|
if (!mconfig->m_out_pin)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin,
|
||||||
|
mconfig->max_out_queue, tkn_elem->value);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U8_TIME_SLOT:
|
||||||
|
mconfig->time_slot = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U8_CORE_ID:
|
||||||
|
mconfig->core_id = tkn_elem->value;
|
||||||
|
|
||||||
|
case SKL_TKN_U8_MOD_TYPE:
|
||||||
|
mconfig->m_type = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U8_DEV_TYPE:
|
||||||
|
mconfig->dev_type = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U8_HW_CONN_TYPE:
|
||||||
|
mconfig->hw_conn_type = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U16_MOD_INST_ID:
|
||||||
|
mconfig->id.instance_id =
|
||||||
|
tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_MEM_PAGES:
|
||||||
|
mconfig->mem_pages = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_MAX_MCPS:
|
||||||
|
mconfig->mcps = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_OBS:
|
||||||
|
mconfig->obs = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_IBS:
|
||||||
|
mconfig->ibs = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_VBUS_ID:
|
||||||
|
mconfig->vbus_id = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_PARAMS_FIXUP:
|
||||||
|
mconfig->params_fixup = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_CONVERTER:
|
||||||
|
mconfig->converter = tkn_elem->value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_PIPE_ID:
|
||||||
|
ret = skl_tplg_add_pipe(dev,
|
||||||
|
mconfig, skl, tkn_elem);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return is_pipe_exists;
|
||||||
|
|
||||||
|
if (ret == EEXIST)
|
||||||
|
is_pipe_exists = 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_PIPE_CONN_TYPE:
|
||||||
|
case SKL_TKN_U32_PIPE_PRIORITY:
|
||||||
|
case SKL_TKN_U32_PIPE_MEM_PGS:
|
||||||
|
if (is_pipe_exists) {
|
||||||
|
ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe,
|
||||||
|
tkn_elem->token, tkn_elem->value);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SKL_TKN_U32_DIR_PIN_COUNT token has the value for both
|
||||||
|
* direction and the pin count. The first four bits represent
|
||||||
|
* direction and next four the pin count.
|
||||||
|
*/
|
||||||
|
case SKL_TKN_U32_DIR_PIN_COUNT:
|
||||||
|
dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK;
|
||||||
|
pin_index = (tkn_elem->value &
|
||||||
|
SKL_PIN_COUNT_MASK) >> 4;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_FMT_CH:
|
||||||
|
case SKL_TKN_U32_FMT_FREQ:
|
||||||
|
case SKL_TKN_U32_FMT_BIT_DEPTH:
|
||||||
|
case SKL_TKN_U32_FMT_SAMPLE_SIZE:
|
||||||
|
case SKL_TKN_U32_FMT_CH_CONFIG:
|
||||||
|
case SKL_TKN_U32_FMT_INTERLEAVE:
|
||||||
|
case SKL_TKN_U32_FMT_SAMPLE_TYPE:
|
||||||
|
case SKL_TKN_U32_FMT_CH_MAP:
|
||||||
|
ret = skl_tplg_fill_fmt(dev, mconfig, tkn_elem->token,
|
||||||
|
tkn_elem->value, dir, pin_index);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_PIN_MOD_ID:
|
||||||
|
case SKL_TKN_U32_PIN_INST_ID:
|
||||||
|
ret = skl_tplg_fill_pins_info(dev,
|
||||||
|
mconfig, tkn_elem, dir,
|
||||||
|
pin_index);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_CAPS_SIZE:
|
||||||
|
mconfig->formats_config.caps_size =
|
||||||
|
tkn_elem->value;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U32_PROC_DOMAIN:
|
||||||
|
mconfig->domain =
|
||||||
|
tkn_elem->value;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKL_TKN_U8_IN_PIN_TYPE:
|
||||||
|
case SKL_TKN_U8_OUT_PIN_TYPE:
|
||||||
|
case SKL_TKN_U8_CONN_TYPE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(dev, "Token %d not handled\n",
|
||||||
|
tkn_elem->token);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tkn_count++;
|
||||||
|
|
||||||
|
return tkn_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the vendor array for specific tokens to construct
|
||||||
|
* module private data
|
||||||
|
*/
|
||||||
|
static int skl_tplg_get_tokens(struct device *dev,
|
||||||
|
char *pvt_data, struct skl *skl,
|
||||||
|
struct skl_module_cfg *mconfig, int block_size)
|
||||||
|
{
|
||||||
|
struct snd_soc_tplg_vendor_array *array;
|
||||||
|
struct snd_soc_tplg_vendor_value_elem *tkn_elem;
|
||||||
|
int tkn_count = 0, ret;
|
||||||
|
int off = 0, tuple_size = 0;
|
||||||
|
|
||||||
|
if (block_size <= 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
while (tuple_size < block_size) {
|
||||||
|
array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off);
|
||||||
|
|
||||||
|
off += array->size;
|
||||||
|
|
||||||
|
switch (array->type) {
|
||||||
|
case SND_SOC_TPLG_TUPLE_TYPE_STRING:
|
||||||
|
dev_warn(dev, "no string tokens expected for skl tplg");
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case SND_SOC_TPLG_TUPLE_TYPE_UUID:
|
||||||
|
ret = skl_tplg_get_uuid(dev, mconfig, array->uuid);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
tuple_size += sizeof(*array->uuid);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
|
||||||
|
default:
|
||||||
|
tkn_elem = array->value;
|
||||||
|
tkn_count = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (tkn_count <= (array->num_elems - 1)) {
|
||||||
|
ret = skl_tplg_get_token(dev, tkn_elem,
|
||||||
|
skl, mconfig);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
tkn_count = tkn_count + ret;
|
||||||
|
tkn_elem++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tuple_size += tkn_count * sizeof(*tkn_elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Every data block is preceded by a descriptor to read the number
|
||||||
|
* of data blocks, they type of the block and it's size
|
||||||
|
*/
|
||||||
|
static int skl_tplg_get_desc_blocks(struct device *dev,
|
||||||
|
struct snd_soc_tplg_vendor_array *array)
|
||||||
|
{
|
||||||
|
struct snd_soc_tplg_vendor_value_elem *tkn_elem;
|
||||||
|
|
||||||
|
tkn_elem = array->value;
|
||||||
|
|
||||||
|
switch (tkn_elem->token) {
|
||||||
|
case SKL_TKN_U8_NUM_BLOCKS:
|
||||||
|
case SKL_TKN_U8_BLOCK_TYPE:
|
||||||
|
case SKL_TKN_U16_BLOCK_SIZE:
|
||||||
|
return tkn_elem->value;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dev_err(dev, "Invalid descriptor token %d", tkn_elem->token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse the private data for the token and corresponding value.
|
||||||
|
* The private data can have multiple data blocks. So, a data block
|
||||||
|
* is preceded by a descriptor for number of blocks and a descriptor
|
||||||
|
* for the type and size of the suceeding data block.
|
||||||
|
*/
|
||||||
|
static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w,
|
||||||
|
struct skl *skl, struct device *dev,
|
||||||
|
struct skl_module_cfg *mconfig)
|
||||||
|
{
|
||||||
|
struct snd_soc_tplg_vendor_array *array;
|
||||||
|
int num_blocks, block_size = 0, block_type, off = 0;
|
||||||
|
char *data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Read the NUM_DATA_BLOCKS descriptor */
|
||||||
|
array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data;
|
||||||
|
ret = skl_tplg_get_desc_blocks(dev, array);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
num_blocks = ret;
|
||||||
|
|
||||||
|
off += array->size;
|
||||||
|
array = (struct snd_soc_tplg_vendor_array *)(tplg_w->priv.data + off);
|
||||||
|
|
||||||
|
/* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */
|
||||||
|
while (num_blocks > 0) {
|
||||||
|
ret = skl_tplg_get_desc_blocks(dev, array);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
block_type = ret;
|
||||||
|
off += array->size;
|
||||||
|
|
||||||
|
array = (struct snd_soc_tplg_vendor_array *)
|
||||||
|
(tplg_w->priv.data + off);
|
||||||
|
|
||||||
|
ret = skl_tplg_get_desc_blocks(dev, array);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
block_size = ret;
|
||||||
|
off += array->size;
|
||||||
|
|
||||||
|
array = (struct snd_soc_tplg_vendor_array *)
|
||||||
|
(tplg_w->priv.data + off);
|
||||||
|
|
||||||
|
data = (tplg_w->priv.data + off);
|
||||||
|
|
||||||
|
if (block_type == SKL_TYPE_TUPLE) {
|
||||||
|
ret = skl_tplg_get_tokens(dev, data,
|
||||||
|
skl, mconfig, block_size);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
--num_blocks;
|
||||||
|
} else {
|
||||||
|
if (mconfig->formats_config.caps_size > 0)
|
||||||
|
memcpy(mconfig->formats_config.caps, data,
|
||||||
|
mconfig->formats_config.caps_size);
|
||||||
|
--num_blocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void skl_clear_pin_config(struct snd_soc_platform *platform,
|
static void skl_clear_pin_config(struct snd_soc_platform *platform,
|
||||||
|
@ -1614,9 +2102,6 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
|
||||||
struct skl *skl = ebus_to_skl(ebus);
|
struct skl *skl = ebus_to_skl(ebus);
|
||||||
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
struct hdac_bus *bus = ebus_to_hbus(ebus);
|
||||||
struct skl_module_cfg *mconfig;
|
struct skl_module_cfg *mconfig;
|
||||||
struct skl_pipe *pipe;
|
|
||||||
struct skl_dfw_module *dfw_config =
|
|
||||||
(struct skl_dfw_module *)tplg_w->priv.data;
|
|
||||||
|
|
||||||
if (!tplg_w->priv.size)
|
if (!tplg_w->priv.size)
|
||||||
goto bind_event;
|
goto bind_event;
|
||||||
|
@ -1627,77 +2112,17 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
w->priv = mconfig;
|
w->priv = mconfig;
|
||||||
memcpy(&mconfig->guid, &dfw_config->uuid, 16);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* module binary can be loaded later, so set it to query when
|
* module binary can be loaded later, so set it to query when
|
||||||
* module is load for a use case
|
* module is load for a use case
|
||||||
*/
|
*/
|
||||||
mconfig->id.module_id = -1;
|
mconfig->id.module_id = -1;
|
||||||
mconfig->id.instance_id = dfw_config->instance_id;
|
|
||||||
mconfig->mcps = dfw_config->max_mcps;
|
|
||||||
mconfig->ibs = dfw_config->ibs;
|
|
||||||
mconfig->obs = dfw_config->obs;
|
|
||||||
mconfig->core_id = dfw_config->core_id;
|
|
||||||
mconfig->max_in_queue = dfw_config->max_in_queue;
|
|
||||||
mconfig->max_out_queue = dfw_config->max_out_queue;
|
|
||||||
mconfig->is_loadable = dfw_config->is_loadable;
|
|
||||||
mconfig->domain = dfw_config->proc_domain;
|
|
||||||
skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt,
|
|
||||||
MODULE_MAX_IN_PINS);
|
|
||||||
skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt,
|
|
||||||
MODULE_MAX_OUT_PINS);
|
|
||||||
|
|
||||||
mconfig->params_fixup = dfw_config->params_fixup;
|
|
||||||
mconfig->converter = dfw_config->converter;
|
|
||||||
mconfig->m_type = dfw_config->module_type;
|
|
||||||
mconfig->vbus_id = dfw_config->vbus_id;
|
|
||||||
mconfig->mem_pages = dfw_config->mem_pages;
|
|
||||||
|
|
||||||
pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe);
|
|
||||||
if (pipe)
|
|
||||||
mconfig->pipe = pipe;
|
|
||||||
|
|
||||||
mconfig->dev_type = dfw_config->dev_type;
|
|
||||||
mconfig->hw_conn_type = dfw_config->hw_conn_type;
|
|
||||||
mconfig->time_slot = dfw_config->time_slot;
|
|
||||||
mconfig->formats_config.caps_size = dfw_config->caps.caps_size;
|
|
||||||
|
|
||||||
mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) *
|
|
||||||
sizeof(*mconfig->m_in_pin),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!mconfig->m_in_pin)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
mconfig->m_out_pin = devm_kzalloc(bus->dev, (mconfig->max_out_queue) *
|
|
||||||
sizeof(*mconfig->m_out_pin),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!mconfig->m_out_pin)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
skl_fill_module_pin_info(dfw_config->in_pin, mconfig->m_in_pin,
|
|
||||||
dfw_config->is_dynamic_in_pin,
|
|
||||||
mconfig->max_in_queue);
|
|
||||||
|
|
||||||
skl_fill_module_pin_info(dfw_config->out_pin, mconfig->m_out_pin,
|
|
||||||
dfw_config->is_dynamic_out_pin,
|
|
||||||
mconfig->max_out_queue);
|
|
||||||
|
|
||||||
|
|
||||||
if (mconfig->formats_config.caps_size == 0)
|
|
||||||
goto bind_event;
|
|
||||||
|
|
||||||
mconfig->formats_config.caps = (u32 *)devm_kzalloc(bus->dev,
|
|
||||||
mconfig->formats_config.caps_size, GFP_KERNEL);
|
|
||||||
|
|
||||||
if (mconfig->formats_config.caps == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
memcpy(mconfig->formats_config.caps, dfw_config->caps.caps,
|
|
||||||
dfw_config->caps.caps_size);
|
|
||||||
mconfig->formats_config.param_id = dfw_config->caps.param_id;
|
|
||||||
mconfig->formats_config.set_params = dfw_config->caps.set_params;
|
|
||||||
|
|
||||||
|
/* Parse private data for tuples */
|
||||||
|
ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
bind_event:
|
bind_event:
|
||||||
if (tplg_w->event_type == 0) {
|
if (tplg_w->event_type == 0) {
|
||||||
dev_dbg(bus->dev, "ASoC: No event handler required\n");
|
dev_dbg(bus->dev, "ASoC: No event handler required\n");
|
||||||
|
|
|
@ -241,4 +241,14 @@ struct skl_dfw_manifest {
|
||||||
struct lib_info lib[HDA_MAX_LIB];
|
struct lib_info lib[HDA_MAX_LIB];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
enum skl_tkn_dir {
|
||||||
|
SKL_DIR_IN,
|
||||||
|
SKL_DIR_OUT
|
||||||
|
};
|
||||||
|
|
||||||
|
enum skl_tuple_type {
|
||||||
|
SKL_TYPE_TUPLE,
|
||||||
|
SKL_TYPE_DATA
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue