Skip to content

Commit

Permalink
ASoC: qdsp6: audioreach: add q6apm support
Browse files Browse the repository at this point in the history
Add support to q6apm (Audio Process Manager) component which is
core Audioreach service running in the DSP.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20211026111655.1702-11-srinivas.kandagatla@linaro.org
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Srinivas Kandagatla authored and Mark Brown committed Oct 26, 2021
1 parent 44c28db commit 5477518
Show file tree
Hide file tree
Showing 4 changed files with 1,082 additions and 0 deletions.
305 changes: 305 additions & 0 deletions sound/soc/qcom/qdsp6/audioreach.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <linux/slab.h>
#include <linux/soc/qcom/apr.h>
#include <dt-bindings/soc/qcom,gpr.h>
#include "q6apm.h"
#include "audioreach.h"

/* SubGraph Config */
Expand Down Expand Up @@ -253,3 +254,307 @@ void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token
APM_MODULE_INSTANCE_ID, true);
}
EXPORT_SYMBOL_GPL(audioreach_alloc_apm_cmd_pkt);

static void apm_populate_container_config(struct apm_container_obj *cfg,
struct audioreach_container *cont)
{

/* Container Config */
cfg->container_cfg.container_id = cont->container_id;
cfg->container_cfg.num_prop = 4;

/* Capability list */
cfg->cap_data.prop_id = APM_CONTAINER_PROP_ID_CAPABILITY_LIST;
cfg->cap_data.prop_size = APM_CONTAINER_PROP_ID_CAPABILITY_SIZE;
cfg->num_capability_id = 1;
cfg->capability_id = cont->capability_id;

/* Graph Position */
cfg->pos_data.prop_id = APM_CONTAINER_PROP_ID_GRAPH_POS;
cfg->pos_data.prop_size = sizeof(struct apm_cont_prop_id_graph_pos);
cfg->pos.graph_pos = cont->graph_pos;

/* Stack size */
cfg->stack_data.prop_id = APM_CONTAINER_PROP_ID_STACK_SIZE;
cfg->stack_data.prop_size = sizeof(struct apm_cont_prop_id_stack_size);
cfg->stack.stack_size = cont->stack_size;

/* Proc domain */
cfg->domain_data.prop_id = APM_CONTAINER_PROP_ID_PROC_DOMAIN;
cfg->domain_data.prop_size = sizeof(struct apm_cont_prop_id_domain);
cfg->domain.proc_domain = cont->proc_domain;
}

static void apm_populate_sub_graph_config(struct apm_sub_graph_data *cfg,
struct audioreach_sub_graph *sg)
{
cfg->sub_graph_cfg.sub_graph_id = sg->sub_graph_id;
cfg->sub_graph_cfg.num_sub_graph_prop = APM_SUB_GRAPH_CFG_NPROP;

/* Perf Mode */
cfg->perf_data.prop_id = APM_SUB_GRAPH_PROP_ID_PERF_MODE;
cfg->perf_data.prop_size = APM_SG_PROP_ID_PERF_MODE_SIZE;
cfg->perf.perf_mode = sg->perf_mode;

/* Direction */
cfg->dir_data.prop_id = APM_SUB_GRAPH_PROP_ID_DIRECTION;
cfg->dir_data.prop_size = APM_SG_PROP_ID_DIR_SIZE;
cfg->dir.direction = sg->direction;

/* Scenario ID */
cfg->sid_data.prop_id = APM_SUB_GRAPH_PROP_ID_SCENARIO_ID;
cfg->sid_data.prop_size = APM_SG_PROP_ID_SID_SIZE;
cfg->sid.scenario_id = sg->scenario_id;
}

static void apm_populate_connection_obj(struct apm_module_conn_obj *obj,
struct audioreach_module *module)
{
obj->src_mod_inst_id = module->src_mod_inst_id;
obj->src_mod_op_port_id = module->src_mod_op_port_id;
obj->dst_mod_inst_id = module->instance_id;
obj->dst_mod_ip_port_id = module->in_port;
}

static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj,
struct audioreach_module *module)
{

obj->instance_id = module->instance_id;
obj->num_props = 1;
obj->prop_data_1.prop_id = APM_MODULE_PROP_ID_PORT_INFO;
obj->prop_data_1.prop_size = APM_MODULE_PROP_ID_PORT_INFO_SZ;
obj->prop_id_port.max_ip_port = module->max_ip_port;
obj->prop_id_port.max_op_port = module->max_op_port;
}

struct audioreach_module *audioreach_get_container_last_module(
struct audioreach_container *container)
{
struct audioreach_module *module;

list_for_each_entry(module, &container->modules_list, node) {
if (module->dst_mod_inst_id == 0)
return module;
}

return NULL;
}
EXPORT_SYMBOL_GPL(audioreach_get_container_last_module);

static bool is_module_in_container(struct audioreach_container *container, int module_iid)
{
struct audioreach_module *module;

list_for_each_entry(module, &container->modules_list, node) {
if (module->instance_id == module_iid)
return true;
}

return false;
}

struct audioreach_module *audioreach_get_container_first_module(
struct audioreach_container *container)
{
struct audioreach_module *module;

/* get the first module from both connected or un-connected containers */
list_for_each_entry(module, &container->modules_list, node) {
if (module->src_mod_inst_id == 0 ||
!is_module_in_container(container, module->src_mod_inst_id))
return module;
}
return NULL;
}
EXPORT_SYMBOL_GPL(audioreach_get_container_first_module);

struct audioreach_module *audioreach_get_container_next_module(
struct audioreach_container *container,
struct audioreach_module *module)
{
int nmodule_iid = module->dst_mod_inst_id;
struct audioreach_module *nmodule;

list_for_each_entry(nmodule, &container->modules_list, node) {
if (nmodule->instance_id == nmodule_iid)
return nmodule;
}

return NULL;
}
EXPORT_SYMBOL_GPL(audioreach_get_container_next_module);

static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj,
struct audioreach_container *container,
int sub_graph_id)
{
struct audioreach_module *module;
int i;

obj->sub_graph_id = sub_graph_id;
obj->container_id = container->container_id;
obj->num_modules = container->num_modules;
i = 0;
list_for_each_container_module(module, container) {
obj->mod_cfg[i].module_id = module->module_id;
obj->mod_cfg[i].instance_id = module->instance_id;
i++;
}
}

static void audioreach_populate_graph(struct apm_graph_open_params *open,
struct list_head *sg_list,
int num_sub_graphs)
{
struct apm_mod_conn_list_params *mc_data = open->mod_conn_list_data;
struct apm_module_list_params *ml_data = open->mod_list_data;
struct apm_prop_list_params *mp_data = open->mod_prop_data;
struct apm_container_params *c_data = open->cont_data;
struct apm_sub_graph_params *sg_data = open->sg_data;
int ncontainer = 0, nmodule = 0, nconn = 0;
struct apm_mod_prop_obj *module_prop_obj;
struct audioreach_container *container;
struct apm_module_conn_obj *conn_obj;
struct audioreach_module *module;
struct audioreach_sub_graph *sg;
struct apm_container_obj *cobj;
struct apm_mod_list_obj *mlobj;
int i = 0;

mlobj = &ml_data->mod_list_obj[0];

list_for_each_entry(sg, sg_list, node) {
struct apm_sub_graph_data *sg_cfg = &sg_data->sg_cfg[i++];

apm_populate_sub_graph_config(sg_cfg, sg);

list_for_each_entry(container, &sg->container_list, node) {
cobj = &c_data->cont_obj[ncontainer];

apm_populate_container_config(cobj, container);
apm_populate_module_list_obj(mlobj, container, sg->sub_graph_id);

list_for_each_container_module(module, container) {
uint32_t src_mod_inst_id;

src_mod_inst_id = module->src_mod_inst_id;

module_prop_obj = &mp_data->mod_prop_obj[nmodule];
apm_populate_module_prop_obj(module_prop_obj, module);

if (src_mod_inst_id) {
conn_obj = &mc_data->conn_obj[nconn];
apm_populate_connection_obj(conn_obj, module);
nconn++;
}

nmodule++;
}
mlobj = (void *) mlobj + APM_MOD_LIST_OBJ_PSIZE(mlobj, container->num_modules);

ncontainer++;
}
}
}

void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct list_head *sg_list, int graph_id)
{
int payload_size, sg_sz, cont_sz, ml_sz, mp_sz, mc_sz;
struct apm_module_param_data *param_data;
struct apm_container_params *cont_params;
struct audioreach_container *container;
struct apm_sub_graph_params *sg_params;
struct apm_mod_conn_list_params *mcon;
struct apm_graph_open_params params;
struct apm_prop_list_params *mprop;
struct audioreach_module *module;
struct audioreach_sub_graph *sgs;
struct apm_mod_list_obj *mlobj;
int num_modules_per_list;
int num_connections = 0;
int num_containers = 0;
int num_sub_graphs = 0;
int num_modules = 0;
int num_modules_list;
struct gpr_pkt *pkt;
void *p;

list_for_each_entry(sgs, sg_list, node) {
num_sub_graphs++;
list_for_each_entry(container, &sgs->container_list, node) {
num_containers++;
num_modules += container->num_modules;
list_for_each_container_module(module, container) {
if (module->src_mod_inst_id)
num_connections++;
}
}
}

num_modules_list = num_containers;
num_modules_per_list = num_modules/num_containers;
sg_sz = APM_SUB_GRAPH_PSIZE(sg_params, num_sub_graphs);
cont_sz = APM_CONTAINER_PSIZE(cont_params, num_containers);
ml_sz = ALIGN(sizeof(struct apm_module_list_params) +
num_modules_list * APM_MOD_LIST_OBJ_PSIZE(mlobj, num_modules_per_list), 8);
mp_sz = APM_MOD_PROP_PSIZE(mprop, num_modules);
mc_sz = APM_MOD_CONN_PSIZE(mcon, num_connections);

payload_size = sg_sz + cont_sz + ml_sz + mp_sz + mc_sz;
pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_GRAPH_OPEN, 0);
if (IS_ERR(pkt))
return pkt;

p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;

/* SubGraph */
params.sg_data = p;
param_data = &params.sg_data->param_data;
param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
param_data->param_id = APM_PARAM_ID_SUB_GRAPH_CONFIG;
param_data->param_size = sg_sz - APM_MODULE_PARAM_DATA_SIZE;
params.sg_data->num_sub_graphs = num_sub_graphs;
p += sg_sz;

/* Container */
params.cont_data = p;
param_data = &params.cont_data->param_data;
param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
param_data->param_id = APM_PARAM_ID_CONTAINER_CONFIG;
param_data->param_size = cont_sz - APM_MODULE_PARAM_DATA_SIZE;
params.cont_data->num_containers = num_containers;
p += cont_sz;

/* Module List*/
params.mod_list_data = p;
param_data = &params.mod_list_data->param_data;
param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
param_data->param_id = APM_PARAM_ID_MODULE_LIST;
param_data->param_size = ml_sz - APM_MODULE_PARAM_DATA_SIZE;
params.mod_list_data->num_modules_list = num_sub_graphs;
p += ml_sz;

/* Module Properties */
params.mod_prop_data = p;
param_data = &params.mod_prop_data->param_data;
param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
param_data->param_id = APM_PARAM_ID_MODULE_PROP;
param_data->param_size = mp_sz - APM_MODULE_PARAM_DATA_SIZE;
params.mod_prop_data->num_modules_prop_cfg = num_modules;
p += mp_sz;

/* Module Connections */
params.mod_conn_list_data = p;
param_data = &params.mod_conn_list_data->param_data;
param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
param_data->param_id = APM_PARAM_ID_MODULE_CONN;
param_data->param_size = mc_sz - APM_MODULE_PARAM_DATA_SIZE;
params.mod_conn_list_data->num_connections = num_connections;
p += mc_sz;

audioreach_populate_graph(&params, sg_list, num_sub_graphs);

return pkt;
}
EXPORT_SYMBOL_GPL(audioreach_alloc_graph_pkt);
29 changes: 29 additions & 0 deletions sound/soc/qcom/qdsp6/audioreach.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <linux/types.h>
#include <linux/soc/qcom/apr.h>
#include <sound/soc.h>
struct q6apm;
struct q6apm_graph;

/* Module IDs */
#define MODULE_ID_WR_SHARED_MEM_EP 0x07001000
Expand Down Expand Up @@ -654,6 +656,20 @@ struct audioreach_module {
struct snd_soc_dapm_widget *widget;
};

struct audioreach_module_config {
int direction;
u32 sample_rate;
u16 bit_width;
u16 bits_per_sample;

u16 data_format;
u16 num_channels;
u16 active_channels_mask;
u32 sd_line_mask;
int fmt;
u8 channel_map[AR_PCM_MAX_NUM_CHANNEL];
};

/* Packet Allocation routines */
void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t
token);
Expand All @@ -665,4 +681,17 @@ void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token,
void *audioreach_alloc_pkt(int payload_size, uint32_t opcode,
uint32_t token, uint32_t src_port,
uint32_t dest_port);
void *audioreach_alloc_graph_pkt(struct q6apm *apm,
struct list_head *sg_list,
int graph_id);
struct audioreach_module *audioreach_get_container_last_module(
struct audioreach_container *container);
struct audioreach_module *audioreach_get_container_first_module(
struct audioreach_container *container);
struct audioreach_module *audioreach_get_container_next_module(
struct audioreach_container *container,
struct audioreach_module *module);
#define list_for_each_container_module(mod, cont) \
for (mod = audioreach_get_container_first_module(cont); mod != NULL; \
mod = audioreach_get_container_next_module(cont, mod))
#endif /* __AUDIOREACH_H__ */
Loading

0 comments on commit 5477518

Please sign in to comment.