cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

topology.c (29489B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (c) 2020, Linaro Limited
      3
      4#include <sound/soc.h>
      5#include <sound/soc-dapm.h>
      6#include <sound/pcm.h>
      7#include <sound/control.h>
      8#include <sound/asound.h>
      9#include <linux/firmware.h>
     10#include <sound/soc-topology.h>
     11#include <sound/soc-dpcm.h>
     12#include <uapi/sound/snd_ar_tokens.h>
     13#include <linux/kernel.h>
     14#include <linux/wait.h>
     15#include "q6apm.h"
     16#include "audioreach.h"
     17
     18struct snd_ar_control {
     19	u32 sgid; /* Sub Graph ID */
     20	struct snd_soc_component *scomp;
     21};
     22
     23static struct audioreach_graph_info *audioreach_tplg_alloc_graph_info(struct q6apm *apm,
     24								      uint32_t graph_id,
     25								      bool *found)
     26{
     27	struct audioreach_graph_info *info;
     28	int ret;
     29
     30	mutex_lock(&apm->lock);
     31	info = idr_find(&apm->graph_info_idr, graph_id);
     32	mutex_unlock(&apm->lock);
     33
     34	if (info) {
     35		*found = true;
     36		return info;
     37	}
     38
     39	*found = false;
     40	info = kzalloc(sizeof(*info), GFP_KERNEL);
     41	if (!info)
     42		return ERR_PTR(-ENOMEM);
     43
     44	INIT_LIST_HEAD(&info->sg_list);
     45
     46	mutex_lock(&apm->lock);
     47	ret = idr_alloc(&apm->graph_info_idr, info, graph_id, graph_id + 1, GFP_KERNEL);
     48	mutex_unlock(&apm->lock);
     49
     50	if (ret < 0) {
     51		dev_err(apm->dev, "Failed to allocate Graph ID (%x)\n", graph_id);
     52		kfree(info);
     53		return ERR_PTR(ret);
     54	}
     55
     56	info->id = ret;
     57
     58	return info;
     59}
     60
     61static void audioreach_tplg_add_sub_graph(struct audioreach_sub_graph *sg,
     62					  struct audioreach_graph_info *info)
     63{
     64	list_add_tail(&sg->node, &info->sg_list);
     65	sg->info = info;
     66	info->num_sub_graphs++;
     67}
     68
     69static struct audioreach_sub_graph *audioreach_tplg_alloc_sub_graph(struct q6apm *apm,
     70								    uint32_t sub_graph_id,
     71								    bool *found)
     72{
     73	struct audioreach_sub_graph *sg;
     74	int ret;
     75
     76	if (!sub_graph_id)
     77		return ERR_PTR(-EINVAL);
     78
     79	/* Find if there is already a matching sub-graph */
     80	mutex_lock(&apm->lock);
     81	sg = idr_find(&apm->sub_graphs_idr, sub_graph_id);
     82	mutex_unlock(&apm->lock);
     83
     84	if (sg) {
     85		*found = true;
     86		return sg;
     87	}
     88
     89	*found = false;
     90	sg = kzalloc(sizeof(*sg), GFP_KERNEL);
     91	if (!sg)
     92		return ERR_PTR(-ENOMEM);
     93
     94	INIT_LIST_HEAD(&sg->container_list);
     95
     96	mutex_lock(&apm->lock);
     97	ret = idr_alloc(&apm->sub_graphs_idr, sg, sub_graph_id, sub_graph_id + 1, GFP_KERNEL);
     98	mutex_unlock(&apm->lock);
     99
    100	if (ret < 0) {
    101		dev_err(apm->dev, "Failed to allocate Sub-Graph Instance ID (%x)\n", sub_graph_id);
    102		kfree(sg);
    103		return ERR_PTR(ret);
    104	}
    105
    106	sg->sub_graph_id = ret;
    107
    108	return sg;
    109}
    110
    111static struct audioreach_container *audioreach_tplg_alloc_container(struct q6apm *apm,
    112							    struct audioreach_sub_graph *sg,
    113							    uint32_t container_id,
    114							    bool *found)
    115{
    116	struct audioreach_container *cont;
    117	int ret;
    118
    119	if (!container_id)
    120		return ERR_PTR(-EINVAL);
    121
    122	mutex_lock(&apm->lock);
    123	cont = idr_find(&apm->containers_idr, container_id);
    124	mutex_unlock(&apm->lock);
    125
    126	if (cont) {
    127		*found = true;
    128		return cont;
    129	}
    130	*found = false;
    131
    132	cont = kzalloc(sizeof(*cont), GFP_KERNEL);
    133	if (!cont)
    134		return ERR_PTR(-ENOMEM);
    135
    136	INIT_LIST_HEAD(&cont->modules_list);
    137
    138	mutex_lock(&apm->lock);
    139	ret = idr_alloc(&apm->containers_idr, cont, container_id, container_id + 1, GFP_KERNEL);
    140	mutex_unlock(&apm->lock);
    141
    142	if (ret < 0) {
    143		dev_err(apm->dev, "Failed to allocate Container Instance ID (%x)\n", container_id);
    144		kfree(cont);
    145		return ERR_PTR(ret);
    146	}
    147
    148	cont->container_id = ret;
    149	cont->sub_graph = sg;
    150	/* add to container list */
    151	list_add_tail(&cont->node, &sg->container_list);
    152	sg->num_containers++;
    153
    154	return cont;
    155}
    156
    157static struct audioreach_module *audioreach_tplg_alloc_module(struct q6apm *apm,
    158							      struct audioreach_container *cont,
    159							      struct snd_soc_dapm_widget *w,
    160							      uint32_t module_id, bool *found)
    161{
    162	struct audioreach_module *mod;
    163	int ret;
    164
    165	mutex_lock(&apm->lock);
    166	mod = idr_find(&apm->modules_idr, module_id);
    167	mutex_unlock(&apm->lock);
    168
    169	if (mod) {
    170		*found = true;
    171		return mod;
    172	}
    173	*found = false;
    174	mod = kzalloc(sizeof(*mod), GFP_KERNEL);
    175	if (!mod)
    176		return ERR_PTR(-ENOMEM);
    177
    178	mutex_lock(&apm->lock);
    179	if (!module_id) { /* alloc module id dynamically */
    180		ret = idr_alloc_cyclic(&apm->modules_idr, mod,
    181				       AR_MODULE_DYNAMIC_INSTANCE_ID_START,
    182				       AR_MODULE_DYNAMIC_INSTANCE_ID_END, GFP_KERNEL);
    183	} else {
    184		ret = idr_alloc(&apm->modules_idr, mod, module_id, module_id + 1, GFP_KERNEL);
    185	}
    186	mutex_unlock(&apm->lock);
    187
    188	if (ret < 0) {
    189		dev_err(apm->dev, "Failed to allocate Module Instance ID (%x)\n", module_id);
    190		kfree(mod);
    191		return ERR_PTR(ret);
    192	}
    193
    194	mod->instance_id = ret;
    195	/* add to module list */
    196	list_add_tail(&mod->node, &cont->modules_list);
    197	mod->container = cont;
    198	mod->widget = w;
    199	cont->num_modules++;
    200
    201	return mod;
    202}
    203
    204static struct snd_soc_tplg_vendor_array *audioreach_get_sg_array(
    205							struct snd_soc_tplg_private *private)
    206{
    207	struct snd_soc_tplg_vendor_array *sg_array = NULL;
    208	bool found = false;
    209	int sz;
    210
    211	for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
    212		struct snd_soc_tplg_vendor_value_elem *sg_elem;
    213		int tkn_count = 0;
    214
    215		sg_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
    216		sg_elem = sg_array->value;
    217		sz = sz + le32_to_cpu(sg_array->size);
    218		while (!found && tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) {
    219			switch (le32_to_cpu(sg_elem->token)) {
    220			case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
    221				found = true;
    222				break;
    223			default:
    224				break;
    225			}
    226			tkn_count++;
    227			sg_elem++;
    228		}
    229	}
    230
    231	if (found)
    232		return sg_array;
    233
    234	return NULL;
    235}
    236
    237static struct snd_soc_tplg_vendor_array *audioreach_get_cont_array(
    238							struct snd_soc_tplg_private *private)
    239{
    240	struct snd_soc_tplg_vendor_array *cont_array = NULL;
    241	bool found = false;
    242	int sz;
    243
    244	for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
    245		struct snd_soc_tplg_vendor_value_elem *cont_elem;
    246		int tkn_count = 0;
    247
    248		cont_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
    249		cont_elem = cont_array->value;
    250		sz = sz + le32_to_cpu(cont_array->size);
    251		while (!found && tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) {
    252			switch (le32_to_cpu(cont_elem->token)) {
    253			case AR_TKN_U32_CONTAINER_INSTANCE_ID:
    254				found = true;
    255				break;
    256			default:
    257				break;
    258			}
    259			tkn_count++;
    260			cont_elem++;
    261		}
    262	}
    263
    264	if (found)
    265		return cont_array;
    266
    267	return NULL;
    268}
    269
    270static struct snd_soc_tplg_vendor_array *audioreach_get_module_array(
    271							     struct snd_soc_tplg_private *private)
    272{
    273	struct snd_soc_tplg_vendor_array *mod_array = NULL;
    274	bool found = false;
    275	int sz = 0;
    276
    277	for (sz = 0; !found && (sz < le32_to_cpu(private->size)); ) {
    278		struct snd_soc_tplg_vendor_value_elem *mod_elem;
    279		int tkn_count = 0;
    280
    281		mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
    282		mod_elem = mod_array->value;
    283		sz = sz + le32_to_cpu(mod_array->size);
    284		while (!found && tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
    285			switch (le32_to_cpu(mod_elem->token)) {
    286			case AR_TKN_U32_MODULE_INSTANCE_ID:
    287				found = true;
    288				break;
    289			default:
    290				break;
    291			}
    292			tkn_count++;
    293			mod_elem++;
    294		}
    295	}
    296
    297	if (found)
    298		return mod_array;
    299
    300	return NULL;
    301}
    302
    303static struct audioreach_sub_graph *audioreach_parse_sg_tokens(struct q6apm *apm,
    304						       struct snd_soc_tplg_private *private)
    305{
    306	struct snd_soc_tplg_vendor_value_elem *sg_elem;
    307	struct snd_soc_tplg_vendor_array *sg_array;
    308	struct audioreach_graph_info *info = NULL;
    309	int graph_id, sub_graph_id, tkn_count = 0;
    310	struct audioreach_sub_graph *sg;
    311	bool found;
    312
    313	sg_array = audioreach_get_sg_array(private);
    314	sg_elem = sg_array->value;
    315
    316	while (tkn_count <= (le32_to_cpu(sg_array->num_elems) - 1)) {
    317		switch (le32_to_cpu(sg_elem->token)) {
    318		case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
    319			sub_graph_id = le32_to_cpu(sg_elem->value);
    320			sg = audioreach_tplg_alloc_sub_graph(apm, sub_graph_id, &found);
    321			if (IS_ERR(sg)) {
    322				return sg;
    323			} else if (found) {
    324				/* Already parsed data for this sub-graph */
    325				return sg;
    326			}
    327			break;
    328		case AR_TKN_DAI_INDEX:
    329			/* Sub graph is associated with predefined graph */
    330			graph_id = le32_to_cpu(sg_elem->value);
    331			info = audioreach_tplg_alloc_graph_info(apm, graph_id, &found);
    332			if (IS_ERR(info))
    333				return ERR_CAST(info);
    334			break;
    335		case AR_TKN_U32_SUB_GRAPH_PERF_MODE:
    336			sg->perf_mode = le32_to_cpu(sg_elem->value);
    337			break;
    338		case AR_TKN_U32_SUB_GRAPH_DIRECTION:
    339			sg->direction = le32_to_cpu(sg_elem->value);
    340			break;
    341		case AR_TKN_U32_SUB_GRAPH_SCENARIO_ID:
    342			sg->scenario_id = le32_to_cpu(sg_elem->value);
    343			break;
    344		default:
    345			dev_err(apm->dev, "Not a valid token %d for graph\n", sg_elem->token);
    346			break;
    347
    348		}
    349		tkn_count++;
    350		sg_elem++;
    351	}
    352
    353	/* Sub graph is associated with predefined graph */
    354	if (info)
    355		audioreach_tplg_add_sub_graph(sg, info);
    356
    357	return sg;
    358}
    359
    360static struct audioreach_container *audioreach_parse_cont_tokens(struct q6apm *apm,
    361							 struct audioreach_sub_graph *sg,
    362							 struct snd_soc_tplg_private *private)
    363{
    364	struct snd_soc_tplg_vendor_value_elem *cont_elem;
    365	struct snd_soc_tplg_vendor_array *cont_array;
    366	struct audioreach_container *cont;
    367	int container_id, tkn_count = 0;
    368	bool found = false;
    369
    370	cont_array = audioreach_get_cont_array(private);
    371	cont_elem = cont_array->value;
    372
    373	while (tkn_count <= (le32_to_cpu(cont_array->num_elems) - 1)) {
    374		switch (le32_to_cpu(cont_elem->token)) {
    375		case AR_TKN_U32_CONTAINER_INSTANCE_ID:
    376			container_id = le32_to_cpu(cont_elem->value);
    377			cont = audioreach_tplg_alloc_container(apm, sg, container_id, &found);
    378			if (IS_ERR(cont) || found)/* Error or Already parsed container data */
    379				return cont;
    380			break;
    381		case AR_TKN_U32_CONTAINER_CAPABILITY_ID:
    382			cont->capability_id = le32_to_cpu(cont_elem->value);
    383			break;
    384		case AR_TKN_U32_CONTAINER_STACK_SIZE:
    385			cont->stack_size = le32_to_cpu(cont_elem->value);
    386			break;
    387		case AR_TKN_U32_CONTAINER_GRAPH_POS:
    388			cont->graph_pos = le32_to_cpu(cont_elem->value);
    389			break;
    390		case AR_TKN_U32_CONTAINER_PROC_DOMAIN:
    391			cont->proc_domain = le32_to_cpu(cont_elem->value);
    392			break;
    393		default:
    394			dev_err(apm->dev, "Not a valid token %d for graph\n", cont_elem->token);
    395			break;
    396
    397		}
    398		tkn_count++;
    399		cont_elem++;
    400	}
    401
    402	return cont;
    403}
    404
    405static struct audioreach_module *audioreach_parse_common_tokens(struct q6apm *apm,
    406							struct audioreach_container *cont,
    407							struct snd_soc_tplg_private *private,
    408							struct snd_soc_dapm_widget *w)
    409{
    410	uint32_t max_ip_port = 0, max_op_port = 0, in_port = 0, out_port = 0;
    411	uint32_t src_mod_inst_id = 0, src_mod_op_port_id = 0;
    412	uint32_t dst_mod_inst_id = 0, dst_mod_ip_port_id = 0;
    413	int module_id = 0, instance_id = 0, tkn_count = 0;
    414	struct snd_soc_tplg_vendor_value_elem *mod_elem;
    415	struct snd_soc_tplg_vendor_array *mod_array;
    416	struct audioreach_module *mod = NULL;
    417	bool found;
    418
    419	mod_array = audioreach_get_module_array(private);
    420	mod_elem = mod_array->value;
    421
    422	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
    423		switch (le32_to_cpu(mod_elem->token)) {
    424		/* common module info */
    425		case AR_TKN_U32_MODULE_ID:
    426			module_id = le32_to_cpu(mod_elem->value);
    427			break;
    428		case AR_TKN_U32_MODULE_INSTANCE_ID:
    429			instance_id = le32_to_cpu(mod_elem->value);
    430			mod = audioreach_tplg_alloc_module(apm, cont, w,
    431							   instance_id, &found);
    432			if (IS_ERR(mod)) {
    433				return mod;
    434			} else if (found) {
    435				dev_err(apm->dev, "Duplicate Module Instance ID 0x%08x found\n",
    436					instance_id);
    437				return ERR_PTR(-EINVAL);
    438			}
    439
    440			break;
    441		case AR_TKN_U32_MODULE_MAX_IP_PORTS:
    442			max_ip_port = le32_to_cpu(mod_elem->value);
    443			break;
    444		case AR_TKN_U32_MODULE_MAX_OP_PORTS:
    445			max_op_port = le32_to_cpu(mod_elem->value);
    446			break;
    447		case AR_TKN_U32_MODULE_IN_PORTS:
    448			in_port = le32_to_cpu(mod_elem->value);
    449			break;
    450		case AR_TKN_U32_MODULE_OUT_PORTS:
    451			out_port = le32_to_cpu(mod_elem->value);
    452			break;
    453		case AR_TKN_U32_MODULE_SRC_OP_PORT_ID:
    454			src_mod_op_port_id = le32_to_cpu(mod_elem->value);
    455			break;
    456		case AR_TKN_U32_MODULE_SRC_INSTANCE_ID:
    457			src_mod_inst_id = le32_to_cpu(mod_elem->value);
    458			break;
    459		case AR_TKN_U32_MODULE_DST_INSTANCE_ID:
    460			dst_mod_inst_id = le32_to_cpu(mod_elem->value);
    461			break;
    462		case AR_TKN_U32_MODULE_DST_IN_PORT_ID:
    463			dst_mod_ip_port_id = le32_to_cpu(mod_elem->value);
    464			break;
    465		default:
    466			break;
    467
    468		}
    469		tkn_count++;
    470		mod_elem++;
    471	}
    472
    473	if (mod) {
    474		mod->module_id = module_id;
    475		mod->max_ip_port = max_ip_port;
    476		mod->max_op_port = max_op_port;
    477		mod->in_port = in_port;
    478		mod->out_port = out_port;
    479		mod->src_mod_inst_id = src_mod_inst_id;
    480		mod->src_mod_op_port_id = src_mod_op_port_id;
    481		mod->dst_mod_inst_id = dst_mod_inst_id;
    482		mod->dst_mod_ip_port_id = dst_mod_ip_port_id;
    483	}
    484
    485	return mod;
    486}
    487
    488static int audioreach_widget_load_module_common(struct snd_soc_component *component,
    489						int index, struct snd_soc_dapm_widget *w,
    490						struct snd_soc_tplg_dapm_widget *tplg_w)
    491{
    492	struct q6apm *apm = dev_get_drvdata(component->dev);
    493	struct audioreach_container *cont;
    494	struct audioreach_sub_graph *sg;
    495	struct audioreach_module *mod;
    496	struct snd_soc_dobj *dobj;
    497
    498	sg = audioreach_parse_sg_tokens(apm, &tplg_w->priv);
    499	if (IS_ERR(sg))
    500		return PTR_ERR(sg);
    501
    502	cont = audioreach_parse_cont_tokens(apm, sg, &tplg_w->priv);
    503	if (IS_ERR(cont))
    504		return PTR_ERR(cont);
    505
    506	mod = audioreach_parse_common_tokens(apm, cont, &tplg_w->priv, w);
    507	if (IS_ERR(mod))
    508		return PTR_ERR(mod);
    509
    510	dobj = &w->dobj;
    511	dobj->private = mod;
    512
    513	return 0;
    514}
    515
    516static int audioreach_widget_load_enc_dec_cnv(struct snd_soc_component *component,
    517					      int index, struct snd_soc_dapm_widget *w,
    518					      struct snd_soc_tplg_dapm_widget *tplg_w)
    519{
    520	struct snd_soc_tplg_vendor_value_elem *mod_elem;
    521	struct snd_soc_tplg_vendor_array *mod_array;
    522	struct audioreach_module *mod;
    523	struct snd_soc_dobj *dobj;
    524	int tkn_count = 0;
    525	int ret;
    526
    527	ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
    528	if (ret)
    529		return ret;
    530
    531	dobj = &w->dobj;
    532	mod = dobj->private;
    533	mod_array = audioreach_get_module_array(&tplg_w->priv);
    534	mod_elem = mod_array->value;
    535
    536	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
    537		switch (le32_to_cpu(mod_elem->token)) {
    538		case AR_TKN_U32_MODULE_FMT_INTERLEAVE:
    539			mod->interleave_type = le32_to_cpu(mod_elem->value);
    540			break;
    541		case AR_TKN_U32_MODULE_FMT_SAMPLE_RATE:
    542			mod->rate = le32_to_cpu(mod_elem->value);
    543			break;
    544		case AR_TKN_U32_MODULE_FMT_BIT_DEPTH:
    545			mod->bit_depth = le32_to_cpu(mod_elem->value);
    546			break;
    547		default:
    548			break;
    549		}
    550		tkn_count++;
    551		mod_elem++;
    552	}
    553
    554	return 0;
    555}
    556
    557static int audioreach_widget_log_module_load(struct audioreach_module *mod,
    558					     struct snd_soc_tplg_vendor_array *mod_array)
    559{
    560	struct snd_soc_tplg_vendor_value_elem *mod_elem;
    561	int tkn_count = 0;
    562
    563	mod_elem = mod_array->value;
    564
    565	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
    566		switch (le32_to_cpu(mod_elem->token)) {
    567
    568		case AR_TKN_U32_MODULE_LOG_CODE:
    569			mod->log_code = le32_to_cpu(mod_elem->value);
    570			break;
    571		case AR_TKN_U32_MODULE_LOG_TAP_POINT_ID:
    572			mod->log_tap_point_id = le32_to_cpu(mod_elem->value);
    573			break;
    574		case AR_TKN_U32_MODULE_LOG_MODE:
    575			mod->log_mode = le32_to_cpu(mod_elem->value);
    576			break;
    577		default:
    578			break;
    579		}
    580		tkn_count++;
    581		mod_elem++;
    582	}
    583
    584	return 0;
    585}
    586
    587static int audioreach_widget_dma_module_load(struct audioreach_module *mod,
    588					     struct snd_soc_tplg_vendor_array *mod_array)
    589{
    590	struct snd_soc_tplg_vendor_value_elem *mod_elem;
    591	int tkn_count = 0;
    592
    593	mod_elem = mod_array->value;
    594
    595	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
    596		switch (le32_to_cpu(mod_elem->token)) {
    597		case AR_TKN_U32_MODULE_HW_IF_IDX:
    598			mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
    599			break;
    600		case AR_TKN_U32_MODULE_FMT_DATA:
    601			mod->data_format = le32_to_cpu(mod_elem->value);
    602			break;
    603		case AR_TKN_U32_MODULE_HW_IF_TYPE:
    604			mod->hw_interface_type = le32_to_cpu(mod_elem->value);
    605			break;
    606		default:
    607			break;
    608		}
    609		tkn_count++;
    610		mod_elem++;
    611	}
    612
    613	return 0;
    614}
    615
    616static int audioreach_widget_i2s_module_load(struct audioreach_module *mod,
    617					     struct snd_soc_tplg_vendor_array *mod_array)
    618{
    619	struct snd_soc_tplg_vendor_value_elem *mod_elem;
    620	int tkn_count = 0;
    621
    622	mod_elem = mod_array->value;
    623
    624	while (tkn_count <= (le32_to_cpu(mod_array->num_elems) - 1)) {
    625		switch (le32_to_cpu(mod_elem->token)) {
    626		case AR_TKN_U32_MODULE_HW_IF_IDX:
    627			mod->hw_interface_idx = le32_to_cpu(mod_elem->value);
    628			break;
    629		case AR_TKN_U32_MODULE_FMT_DATA:
    630			mod->data_format = le32_to_cpu(mod_elem->value);
    631			break;
    632		case AR_TKN_U32_MODULE_HW_IF_TYPE:
    633			mod->hw_interface_type = le32_to_cpu(mod_elem->value);
    634			break;
    635		case AR_TKN_U32_MODULE_SD_LINE_IDX:
    636			mod->sd_line_idx = le32_to_cpu(mod_elem->value);
    637			break;
    638		case AR_TKN_U32_MODULE_WS_SRC:
    639			mod->ws_src = le32_to_cpu(mod_elem->value);
    640			break;
    641		default:
    642			break;
    643		}
    644		tkn_count++;
    645		mod_elem++;
    646	}
    647
    648	return 0;
    649}
    650
    651static int audioreach_widget_load_buffer(struct snd_soc_component *component,
    652					 int index, struct snd_soc_dapm_widget *w,
    653					 struct snd_soc_tplg_dapm_widget *tplg_w)
    654{
    655	struct snd_soc_tplg_vendor_array *mod_array;
    656	struct audioreach_module *mod;
    657	struct snd_soc_dobj *dobj;
    658	int ret;
    659
    660	ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
    661	if (ret)
    662		return ret;
    663
    664	dobj = &w->dobj;
    665	mod = dobj->private;
    666
    667	mod_array = audioreach_get_module_array(&tplg_w->priv);
    668
    669	switch (mod->module_id) {
    670	case MODULE_ID_CODEC_DMA_SINK:
    671	case MODULE_ID_CODEC_DMA_SOURCE:
    672		audioreach_widget_dma_module_load(mod, mod_array);
    673		break;
    674	case MODULE_ID_DATA_LOGGING:
    675		audioreach_widget_log_module_load(mod, mod_array);
    676		break;
    677	case MODULE_ID_I2S_SINK:
    678	case MODULE_ID_I2S_SOURCE:
    679		audioreach_widget_i2s_module_load(mod, mod_array);
    680		break;
    681	default:
    682		return -EINVAL;
    683	}
    684
    685	return 0;
    686}
    687
    688static int audioreach_widget_load_mixer(struct snd_soc_component *component,
    689					int index, struct snd_soc_dapm_widget *w,
    690					struct snd_soc_tplg_dapm_widget *tplg_w)
    691{
    692	struct snd_soc_tplg_vendor_value_elem *w_elem;
    693	struct snd_soc_tplg_vendor_array *w_array;
    694	struct snd_ar_control *scontrol;
    695	struct snd_soc_dobj *dobj;
    696	int tkn_count = 0;
    697
    698	w_array = &tplg_w->priv.array[0];
    699
    700	scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
    701	if (!scontrol)
    702		return -ENOMEM;
    703
    704	scontrol->scomp = component;
    705	dobj = &w->dobj;
    706	dobj->private = scontrol;
    707
    708	w_elem = w_array->value;
    709	while (tkn_count <= (le32_to_cpu(w_array->num_elems) - 1)) {
    710		switch (le32_to_cpu(w_elem->token)) {
    711		case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
    712			scontrol->sgid = le32_to_cpu(w_elem->value);
    713			break;
    714		default: /* ignore other tokens */
    715			break;
    716		}
    717		tkn_count++;
    718		w_elem++;
    719	}
    720
    721	return 0;
    722}
    723
    724static int audioreach_pga_event(struct snd_soc_dapm_widget *w,
    725				struct snd_kcontrol *kcontrol, int event)
    726
    727{
    728	struct snd_soc_dapm_context *dapm = w->dapm;
    729	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
    730	struct audioreach_module *mod = w->dobj.private;
    731	struct q6apm *apm = dev_get_drvdata(c->dev);
    732
    733	switch (event) {
    734	case SND_SOC_DAPM_POST_PMU:
    735		/* apply gain after power up of widget */
    736		audioreach_gain_set_vol_ctrl(apm, mod, mod->gain);
    737		break;
    738	default:
    739		break;
    740	}
    741
    742	return 0;
    743}
    744
    745static const struct snd_soc_tplg_widget_events audioreach_widget_ops[] = {
    746	{ AR_PGA_DAPM_EVENT, audioreach_pga_event },
    747};
    748
    749static int audioreach_widget_load_pga(struct snd_soc_component *component,
    750				      int index, struct snd_soc_dapm_widget *w,
    751				      struct snd_soc_tplg_dapm_widget *tplg_w)
    752{
    753	struct audioreach_module *mod;
    754	struct snd_soc_dobj *dobj;
    755	int ret;
    756
    757	ret = audioreach_widget_load_module_common(component, index, w, tplg_w);
    758	if (ret)
    759		return ret;
    760
    761	dobj = &w->dobj;
    762	mod = dobj->private;
    763	mod->gain = VOL_CTRL_DEFAULT_GAIN;
    764
    765	ret = snd_soc_tplg_widget_bind_event(w, audioreach_widget_ops,
    766					     ARRAY_SIZE(audioreach_widget_ops),
    767					     le16_to_cpu(tplg_w->event_type));
    768	if (ret) {
    769		dev_err(component->dev, "matching event handlers NOT found for %d\n",
    770			le16_to_cpu(tplg_w->event_type));
    771		return -EINVAL;
    772	}
    773
    774	return 0;
    775}
    776
    777static int audioreach_widget_ready(struct snd_soc_component *component,
    778				   int index, struct snd_soc_dapm_widget *w,
    779				   struct snd_soc_tplg_dapm_widget *tplg_w)
    780{
    781	switch (w->id) {
    782	case snd_soc_dapm_aif_in:
    783	case snd_soc_dapm_aif_out:
    784		audioreach_widget_load_buffer(component, index, w, tplg_w);
    785		break;
    786	case snd_soc_dapm_decoder:
    787	case snd_soc_dapm_encoder:
    788	case snd_soc_dapm_src:
    789		audioreach_widget_load_enc_dec_cnv(component, index, w, tplg_w);
    790		break;
    791	case snd_soc_dapm_buffer:
    792		audioreach_widget_load_buffer(component, index, w, tplg_w);
    793		break;
    794	case snd_soc_dapm_mixer:
    795		return audioreach_widget_load_mixer(component, index, w, tplg_w);
    796	case snd_soc_dapm_pga:
    797		return audioreach_widget_load_pga(component, index, w, tplg_w);
    798	case snd_soc_dapm_dai_link:
    799	case snd_soc_dapm_scheduler:
    800	case snd_soc_dapm_out_drv:
    801	default:
    802		dev_err(component->dev, "Widget type (0x%x) not yet supported\n", w->id);
    803		break;
    804	}
    805
    806	return 0;
    807}
    808
    809static int audioreach_widget_unload(struct snd_soc_component *scomp,
    810				    struct snd_soc_dobj *dobj)
    811{
    812	struct snd_soc_dapm_widget *w = container_of(dobj, struct snd_soc_dapm_widget, dobj);
    813	struct q6apm *apm = dev_get_drvdata(scomp->dev);
    814	struct audioreach_container *cont;
    815	struct audioreach_module *mod;
    816
    817	mod = dobj->private;
    818	cont = mod->container;
    819
    820	if (w->id == snd_soc_dapm_mixer) {
    821		/* virtual widget */
    822		kfree(dobj->private);
    823		return 0;
    824	}
    825
    826	mutex_lock(&apm->lock);
    827	idr_remove(&apm->modules_idr, mod->instance_id);
    828	cont->num_modules--;
    829
    830	list_del(&mod->node);
    831	kfree(mod);
    832	/* Graph Info has N sub-graphs, sub-graph has N containers, Container has N Modules */
    833	if (list_empty(&cont->modules_list)) { /* if no modules in the container then remove it */
    834		struct audioreach_sub_graph *sg = cont->sub_graph;
    835
    836		idr_remove(&apm->containers_idr, cont->container_id);
    837		list_del(&cont->node);
    838		sg->num_containers--;
    839		kfree(cont);
    840		/* check if there are no more containers in the sub graph and remove it */
    841		if (list_empty(&sg->container_list)) {
    842			struct audioreach_graph_info *info = sg->info;
    843
    844			idr_remove(&apm->sub_graphs_idr, sg->sub_graph_id);
    845			list_del(&sg->node);
    846			info->num_sub_graphs--;
    847			kfree(sg);
    848			/* Check if there are no more sub-graphs left then remove graph info */
    849			if (list_empty(&info->sg_list)) {
    850				idr_remove(&apm->graph_info_idr, info->id);
    851				kfree(info);
    852			}
    853		}
    854	}
    855
    856	mutex_unlock(&apm->lock);
    857
    858	return 0;
    859}
    860
    861static struct audioreach_module *audioreach_find_widget(struct snd_soc_component *comp,
    862							const char *name)
    863{
    864	struct q6apm *apm = dev_get_drvdata(comp->dev);
    865	struct audioreach_module *module;
    866	int id;
    867
    868	idr_for_each_entry(&apm->modules_idr, module, id) {
    869		if (!strcmp(name, module->widget->name))
    870			return module;
    871	}
    872
    873	return NULL;
    874}
    875
    876static int audioreach_route_load(struct snd_soc_component *scomp, int index,
    877				 struct snd_soc_dapm_route *route)
    878{
    879	struct audioreach_module *src, *sink;
    880
    881	src = audioreach_find_widget(scomp, route->source);
    882	sink = audioreach_find_widget(scomp, route->sink);
    883
    884	if (src && sink) {
    885		src->dst_mod_inst_id = sink->instance_id;
    886		sink->src_mod_inst_id = src->instance_id;
    887	}
    888
    889	return 0;
    890}
    891
    892static int audioreach_route_unload(struct snd_soc_component *scomp,
    893				   struct snd_soc_dobj *dobj)
    894{
    895	return 0;
    896}
    897
    898static int audioreach_tplg_complete(struct snd_soc_component *component)
    899{
    900	/* TBD */
    901	return 0;
    902}
    903
    904/* DAI link - used for any driver specific init */
    905static int audioreach_link_load(struct snd_soc_component *component, int index,
    906				struct snd_soc_dai_link *link,
    907				struct snd_soc_tplg_link_config *cfg)
    908{
    909	link->nonatomic = true;
    910	link->dynamic = true;
    911	link->platforms->name = NULL;
    912	link->platforms->of_node = of_get_compatible_child(component->dev->of_node,
    913							   "qcom,q6apm-dais");
    914	return 0;
    915}
    916
    917static int audioreach_get_audio_mixer(struct snd_kcontrol *kcontrol,
    918				      struct snd_ctl_elem_value *ucontrol)
    919{
    920	struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
    921	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
    922	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
    923	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
    924	struct snd_ar_control *dapm_scontrol = dw->dobj.private;
    925	struct snd_ar_control *scontrol = mc->dobj.private;
    926	struct q6apm *data = dev_get_drvdata(c->dev);
    927	bool connected;
    928
    929	connected = q6apm_is_sub_graphs_connected(data, scontrol->sgid, dapm_scontrol->sgid);
    930	if (connected)
    931		ucontrol->value.integer.value[0] = 1;
    932	else
    933		ucontrol->value.integer.value[0] = 0;
    934
    935	return 0;
    936}
    937
    938static int audioreach_put_audio_mixer(struct snd_kcontrol *kcontrol,
    939				      struct snd_ctl_elem_value *ucontrol)
    940{
    941	struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
    942	struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
    943	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
    944	struct snd_soc_component *c = snd_soc_dapm_to_component(dapm);
    945	struct snd_ar_control *dapm_scontrol = dw->dobj.private;
    946	struct snd_ar_control *scontrol = mc->dobj.private;
    947	struct q6apm *data = dev_get_drvdata(c->dev);
    948
    949	if (ucontrol->value.integer.value[0]) {
    950		q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, true);
    951		snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, NULL);
    952	} else {
    953		q6apm_connect_sub_graphs(data, scontrol->sgid, dapm_scontrol->sgid, false);
    954		snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, NULL);
    955	}
    956	return 0;
    957}
    958
    959static int audioreach_get_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
    960					       struct snd_ctl_elem_value *ucontrol)
    961{
    962	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
    963	struct audioreach_module *mod = dw->dobj.private;
    964
    965	ucontrol->value.integer.value[0] = mod->gain;
    966
    967	return 0;
    968}
    969
    970static int audioreach_put_vol_ctrl_audio_mixer(struct snd_kcontrol *kcontrol,
    971					       struct snd_ctl_elem_value *ucontrol)
    972{
    973	struct snd_soc_dapm_widget *dw = snd_soc_dapm_kcontrol_widget(kcontrol);
    974	struct audioreach_module *mod = dw->dobj.private;
    975
    976	mod->gain = ucontrol->value.integer.value[0];
    977
    978	return 1;
    979}
    980
    981static int audioreach_control_load_mix(struct snd_soc_component *scomp,
    982				       struct snd_ar_control *scontrol,
    983				       struct snd_kcontrol_new *kc,
    984				       struct snd_soc_tplg_ctl_hdr *hdr)
    985{
    986	struct snd_soc_tplg_vendor_value_elem *c_elem;
    987	struct snd_soc_tplg_vendor_array *c_array;
    988	struct snd_soc_tplg_mixer_control *mc;
    989	int tkn_count = 0;
    990
    991	mc = container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
    992	c_array = (struct snd_soc_tplg_vendor_array *)mc->priv.data;
    993
    994	c_elem = c_array->value;
    995
    996	while (tkn_count <= (le32_to_cpu(c_array->num_elems) - 1)) {
    997		switch (le32_to_cpu(c_elem->token)) {
    998		case AR_TKN_U32_SUB_GRAPH_INSTANCE_ID:
    999			scontrol->sgid = le32_to_cpu(c_elem->value);
   1000			break;
   1001		default:
   1002			/* Ignore other tokens */
   1003			break;
   1004		}
   1005		c_elem++;
   1006		tkn_count++;
   1007	}
   1008
   1009	return 0;
   1010}
   1011
   1012static int audioreach_control_load(struct snd_soc_component *scomp, int index,
   1013				   struct snd_kcontrol_new *kc,
   1014				   struct snd_soc_tplg_ctl_hdr *hdr)
   1015{
   1016	struct snd_ar_control *scontrol;
   1017	struct soc_mixer_control *sm;
   1018	struct snd_soc_dobj *dobj;
   1019	int ret = 0;
   1020
   1021	scontrol = kzalloc(sizeof(*scontrol), GFP_KERNEL);
   1022	if (!scontrol)
   1023		return -ENOMEM;
   1024
   1025	scontrol->scomp = scomp;
   1026
   1027	switch (le32_to_cpu(hdr->ops.get)) {
   1028	case SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX:
   1029		sm = (struct soc_mixer_control *)kc->private_value;
   1030		dobj = &sm->dobj;
   1031		ret = audioreach_control_load_mix(scomp, scontrol, kc, hdr);
   1032		break;
   1033	case SND_SOC_AR_TPLG_VOL_CTL:
   1034		sm = (struct soc_mixer_control *)kc->private_value;
   1035		dobj = &sm->dobj;
   1036		break;
   1037	default:
   1038		dev_warn(scomp->dev, "control type not supported %d:%d:%d\n",
   1039			 hdr->ops.get, hdr->ops.put, hdr->ops.info);
   1040		kfree(scontrol);
   1041		return -EINVAL;
   1042	}
   1043
   1044	dobj->private = scontrol;
   1045	return ret;
   1046}
   1047
   1048static int audioreach_control_unload(struct snd_soc_component *scomp,
   1049				     struct snd_soc_dobj *dobj)
   1050{
   1051	struct snd_ar_control *scontrol = dobj->private;
   1052
   1053	kfree(scontrol);
   1054
   1055	return 0;
   1056}
   1057
   1058static const struct snd_soc_tplg_kcontrol_ops audioreach_io_ops[] = {
   1059	{SND_SOC_AR_TPLG_FE_BE_GRAPH_CTL_MIX, audioreach_get_audio_mixer,
   1060		audioreach_put_audio_mixer, snd_soc_info_volsw},
   1061	{SND_SOC_AR_TPLG_VOL_CTL, audioreach_get_vol_ctrl_audio_mixer,
   1062		audioreach_put_vol_ctrl_audio_mixer, snd_soc_info_volsw},
   1063};
   1064
   1065static struct snd_soc_tplg_ops audioreach_tplg_ops  = {
   1066	.io_ops = audioreach_io_ops,
   1067	.io_ops_count = ARRAY_SIZE(audioreach_io_ops),
   1068
   1069	.control_load	= audioreach_control_load,
   1070	.control_unload	= audioreach_control_unload,
   1071
   1072	.widget_ready = audioreach_widget_ready,
   1073	.widget_unload = audioreach_widget_unload,
   1074
   1075	.complete = audioreach_tplg_complete,
   1076	.link_load = audioreach_link_load,
   1077
   1078	.dapm_route_load	= audioreach_route_load,
   1079	.dapm_route_unload	= audioreach_route_unload,
   1080};
   1081
   1082int audioreach_tplg_init(struct snd_soc_component *component)
   1083{
   1084	struct snd_soc_card *card = component->card;
   1085	struct device *dev = component->dev;
   1086	const struct firmware *fw;
   1087	char *tplg_fw_name;
   1088	int ret;
   1089
   1090	/* Inline with Qualcomm UCM configs and linux-firmware path */
   1091	tplg_fw_name = kasprintf(GFP_KERNEL, "qcom/%s/%s-tplg.bin", card->driver_name, card->name);
   1092	if (!tplg_fw_name)
   1093		return -ENOMEM;
   1094
   1095	ret = request_firmware(&fw, tplg_fw_name, dev);
   1096	if (ret < 0) {
   1097		dev_err(dev, "tplg firmware loading %s failed %d \n", tplg_fw_name, ret);
   1098		goto err;
   1099	}
   1100
   1101	ret = snd_soc_tplg_component_load(component, &audioreach_tplg_ops, fw);
   1102	if (ret < 0) {
   1103		dev_err(dev, "tplg component load failed%d\n", ret);
   1104		ret = -EINVAL;
   1105	}
   1106
   1107	release_firmware(fw);
   1108err:
   1109	kfree(tplg_fw_name);
   1110
   1111	return ret;
   1112}
   1113EXPORT_SYMBOL_GPL(audioreach_tplg_init);