1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2020, Linaro Limited 3 4 #include <linux/kernel.h> 5 #include <linux/slab.h> 6 #include <linux/soc/qcom/apr.h> 7 #include <sound/soc.h> 8 #include <sound/soc-dai.h> 9 #include <sound/pcm.h> 10 #include <sound/pcm_params.h> 11 #include <dt-bindings/soc/qcom,gpr.h> 12 #include "q6apm.h" 13 #include "audioreach.h" 14 15 /* SubGraph Config */ 16 struct apm_sub_graph_data { 17 struct apm_sub_graph_cfg sub_graph_cfg; 18 struct apm_prop_data perf_data; 19 struct apm_sg_prop_id_perf_mode perf; 20 struct apm_prop_data dir_data; 21 struct apm_sg_prop_id_direction dir; 22 struct apm_prop_data sid_data; 23 struct apm_sg_prop_id_scenario_id sid; 24 25 } __packed; 26 27 #define APM_SUB_GRAPH_CFG_NPROP 3 28 29 struct apm_sub_graph_params { 30 struct apm_module_param_data param_data; 31 uint32_t num_sub_graphs; 32 struct apm_sub_graph_data sg_cfg[]; 33 } __packed; 34 35 #define APM_SUB_GRAPH_PSIZE(p, n) ALIGN(struct_size(p, sg_cfg, n), 8) 36 37 /* container config */ 38 struct apm_container_obj { 39 struct apm_container_cfg container_cfg; 40 /* Capability ID list */ 41 struct apm_prop_data cap_data; 42 uint32_t num_capability_id; 43 uint32_t capability_id; 44 45 /* Container graph Position */ 46 struct apm_prop_data pos_data; 47 struct apm_cont_prop_id_graph_pos pos; 48 49 /* Container Stack size */ 50 struct apm_prop_data stack_data; 51 struct apm_cont_prop_id_stack_size stack; 52 53 /* Container proc domain id */ 54 struct apm_prop_data domain_data; 55 struct apm_cont_prop_id_domain domain; 56 } __packed; 57 58 struct apm_container_params { 59 struct apm_module_param_data param_data; 60 uint32_t num_containers; 61 struct apm_container_obj cont_obj[]; 62 } __packed; 63 64 #define APM_CONTAINER_PSIZE(p, n) ALIGN(struct_size(p, cont_obj, n), 8) 65 66 /* Module List config */ 67 struct apm_mod_list_obj { 68 /* Modules list cfg */ 69 uint32_t sub_graph_id; 70 uint32_t container_id; 71 uint32_t num_modules; 72 struct apm_module_obj mod_cfg[]; 73 } __packed; 74 75 #define APM_MOD_LIST_OBJ_PSIZE(p, n) struct_size(p, mod_cfg, n) 76 77 struct apm_module_list_params { 78 struct apm_module_param_data param_data; 79 uint32_t num_modules_list; 80 /* Module list config array */ 81 struct apm_mod_list_obj mod_list_obj[]; 82 } __packed; 83 84 85 /* Module Properties */ 86 struct apm_mod_prop_obj { 87 u32 instance_id; 88 u32 num_props; 89 struct apm_prop_data prop_data_1; 90 struct apm_module_prop_id_port_info prop_id_port; 91 } __packed; 92 93 struct apm_prop_list_params { 94 struct apm_module_param_data param_data; 95 u32 num_modules_prop_cfg; 96 struct apm_mod_prop_obj mod_prop_obj[]; 97 98 } __packed; 99 100 #define APM_MOD_PROP_PSIZE(p, n) ALIGN(struct_size(p, mod_prop_obj, n), 8) 101 102 /* Module Connections */ 103 struct apm_mod_conn_list_params { 104 struct apm_module_param_data param_data; 105 u32 num_connections; 106 struct apm_module_conn_obj conn_obj[]; 107 108 } __packed; 109 110 #define APM_MOD_CONN_PSIZE(p, n) ALIGN(struct_size(p, conn_obj, n), 8) 111 112 struct apm_graph_open_params { 113 struct apm_cmd_header *cmd_header; 114 struct apm_sub_graph_params *sg_data; 115 struct apm_container_params *cont_data; 116 struct apm_module_list_params *mod_list_data; 117 struct apm_prop_list_params *mod_prop_data; 118 struct apm_mod_conn_list_params *mod_conn_list_data; 119 } __packed; 120 121 struct apm_pcm_module_media_fmt_cmd { 122 struct apm_module_param_data param_data; 123 struct param_id_pcm_output_format_cfg header; 124 struct payload_pcm_output_format_cfg media_cfg; 125 } __packed; 126 127 struct apm_rd_shmem_module_config_cmd { 128 struct apm_module_param_data param_data; 129 struct param_id_rd_sh_mem_cfg cfg; 130 } __packed; 131 132 struct apm_sh_module_media_fmt_cmd { 133 struct media_format header; 134 struct payload_media_fmt_pcm cfg; 135 } __packed; 136 137 #define APM_SHMEM_FMT_CFG_PSIZE(ch) ALIGN( \ 138 sizeof(struct apm_sh_module_media_fmt_cmd) + \ 139 ch * sizeof(uint8_t), 8) 140 141 /* num of channels as argument */ 142 #define APM_PCM_MODULE_FMT_CMD_PSIZE(ch) ALIGN( \ 143 sizeof(struct apm_pcm_module_media_fmt_cmd) + \ 144 ch * sizeof(uint8_t), 8) 145 146 #define APM_PCM_OUT_FMT_CFG_PSIZE(p, n) ALIGN(struct_size(p, channel_mapping, n), 4) 147 148 struct apm_i2s_module_intf_cfg { 149 struct apm_module_param_data param_data; 150 struct param_id_i2s_intf_cfg cfg; 151 } __packed; 152 153 #define APM_I2S_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_i2s_module_intf_cfg), 8) 154 155 struct apm_module_hw_ep_mf_cfg { 156 struct apm_module_param_data param_data; 157 struct param_id_hw_ep_mf mf; 158 } __packed; 159 160 #define APM_HW_EP_CFG_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_mf_cfg), 8) 161 162 #define APM_MFC_CFG_PSIZE(p, n) ALIGN(struct_size(p, channel_mapping, n), 4) 163 164 struct apm_module_frame_size_factor_cfg { 165 struct apm_module_param_data param_data; 166 uint32_t frame_size_factor; 167 } __packed; 168 169 #define APM_FS_CFG_PSIZE ALIGN(sizeof(struct apm_module_frame_size_factor_cfg), 8) 170 171 struct apm_module_hw_ep_power_mode_cfg { 172 struct apm_module_param_data param_data; 173 struct param_id_hw_ep_power_mode_cfg power_mode; 174 } __packed; 175 176 #define APM_HW_EP_PMODE_CFG_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_power_mode_cfg), 8) 177 178 struct apm_module_hw_ep_dma_data_align_cfg { 179 struct apm_module_param_data param_data; 180 struct param_id_hw_ep_dma_data_align align; 181 } __packed; 182 183 #define APM_HW_EP_DALIGN_CFG_PSIZE ALIGN(sizeof(struct apm_module_hw_ep_dma_data_align_cfg), 8) 184 185 struct apm_gain_module_cfg { 186 struct apm_module_param_data param_data; 187 struct param_id_gain_cfg gain_cfg; 188 } __packed; 189 190 #define APM_GAIN_CFG_PSIZE ALIGN(sizeof(struct apm_gain_module_cfg), 8) 191 192 struct apm_codec_dma_module_intf_cfg { 193 struct apm_module_param_data param_data; 194 struct param_id_codec_dma_intf_cfg cfg; 195 } __packed; 196 197 #define APM_CDMA_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_codec_dma_module_intf_cfg), 8) 198 199 struct apm_display_port_module_intf_cfg { 200 struct apm_module_param_data param_data; 201 struct param_id_display_port_intf_cfg cfg; 202 } __packed; 203 #define APM_DP_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_display_port_module_intf_cfg), 8) 204 205 struct apm_module_sp_vi_op_mode_cfg { 206 struct apm_module_param_data param_data; 207 struct param_id_sp_vi_op_mode_cfg cfg; 208 } __packed; 209 210 #define APM_SP_VI_OP_MODE_CFG_PSIZE(ch) ALIGN( \ 211 sizeof(struct apm_module_sp_vi_op_mode_cfg) + \ 212 (ch) * sizeof(uint32_t), 8) 213 214 struct apm_module_sp_vi_ex_mode_cfg { 215 struct apm_module_param_data param_data; 216 struct param_id_sp_vi_ex_mode_cfg cfg; 217 } __packed; 218 219 #define APM_SP_VI_EX_MODE_CFG_PSIZE ALIGN(sizeof(struct apm_module_sp_vi_ex_mode_cfg), 8) 220 221 struct apm_module_sp_vi_channel_map_cfg { 222 struct apm_module_param_data param_data; 223 struct param_id_sp_vi_channel_map_cfg cfg; 224 } __packed; 225 226 #define APM_SP_VI_CH_MAP_CFG_PSIZE(ch) ALIGN( \ 227 sizeof(struct apm_module_sp_vi_channel_map_cfg) + \ 228 (ch) * sizeof(uint32_t), 8) 229 230 static void *__audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t token, 231 uint32_t src_port, uint32_t dest_port, bool has_cmd_hdr) 232 { 233 struct gpr_pkt *pkt; 234 void *p; 235 int pkt_size = GPR_HDR_SIZE + payload_size; 236 237 if (has_cmd_hdr) 238 pkt_size += APM_CMD_HDR_SIZE; 239 240 p = kzalloc(pkt_size, GFP_KERNEL); 241 if (!p) 242 return ERR_PTR(-ENOMEM); 243 244 pkt = p; 245 pkt->hdr.version = GPR_PKT_VER; 246 pkt->hdr.hdr_size = GPR_PKT_HEADER_WORD_SIZE; 247 pkt->hdr.pkt_size = pkt_size; 248 pkt->hdr.dest_port = dest_port; 249 pkt->hdr.src_port = src_port; 250 251 pkt->hdr.dest_domain = GPR_DOMAIN_ID_ADSP; 252 pkt->hdr.src_domain = GPR_DOMAIN_ID_APPS; 253 pkt->hdr.token = token; 254 pkt->hdr.opcode = opcode; 255 256 if (has_cmd_hdr) { 257 struct apm_cmd_header *cmd_header; 258 259 p = p + GPR_HDR_SIZE; 260 cmd_header = p; 261 cmd_header->payload_size = payload_size; 262 } 263 264 return pkt; 265 } 266 267 void *audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t token, 268 uint32_t src_port, uint32_t dest_port) 269 { 270 return __audioreach_alloc_pkt(payload_size, opcode, token, src_port, dest_port, false); 271 } 272 EXPORT_SYMBOL_GPL(audioreach_alloc_pkt); 273 274 void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token, uint32_t src_port) 275 { 276 return __audioreach_alloc_pkt(pkt_size, opcode, token, src_port, APM_MODULE_INSTANCE_ID, 277 false); 278 } 279 EXPORT_SYMBOL_GPL(audioreach_alloc_apm_pkt); 280 281 void *audioreach_alloc_cmd_pkt(int payload_size, uint32_t opcode, uint32_t token, 282 uint32_t src_port, uint32_t dest_port) 283 { 284 return __audioreach_alloc_pkt(payload_size, opcode, token, src_port, dest_port, true); 285 } 286 EXPORT_SYMBOL_GPL(audioreach_alloc_cmd_pkt); 287 288 void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token) 289 { 290 return __audioreach_alloc_pkt(pkt_size, opcode, token, GPR_APM_MODULE_IID, 291 APM_MODULE_INSTANCE_ID, true); 292 } 293 EXPORT_SYMBOL_GPL(audioreach_alloc_apm_cmd_pkt); 294 295 void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels) 296 { 297 if (num_channels == 1) { 298 ch_map[0] = PCM_CHANNEL_FL; 299 } else if (num_channels == 2) { 300 ch_map[0] = PCM_CHANNEL_FL; 301 ch_map[1] = PCM_CHANNEL_FR; 302 } else if (num_channels == 4) { 303 ch_map[0] = PCM_CHANNEL_FL; 304 ch_map[1] = PCM_CHANNEL_FR; 305 ch_map[2] = PCM_CHANNEL_LS; 306 ch_map[3] = PCM_CHANNEL_RS; 307 } 308 } 309 EXPORT_SYMBOL_GPL(audioreach_set_default_channel_mapping); 310 311 static void apm_populate_container_config(struct apm_container_obj *cfg, 312 const struct audioreach_container *cont) 313 { 314 315 /* Container Config */ 316 cfg->container_cfg.container_id = cont->container_id; 317 cfg->container_cfg.num_prop = 4; 318 319 /* Capability list */ 320 cfg->cap_data.prop_id = APM_CONTAINER_PROP_ID_CAPABILITY_LIST; 321 cfg->cap_data.prop_size = APM_CONTAINER_PROP_ID_CAPABILITY_SIZE; 322 cfg->num_capability_id = 1; 323 cfg->capability_id = cont->capability_id; 324 325 /* Graph Position */ 326 cfg->pos_data.prop_id = APM_CONTAINER_PROP_ID_GRAPH_POS; 327 cfg->pos_data.prop_size = sizeof(struct apm_cont_prop_id_graph_pos); 328 cfg->pos.graph_pos = cont->graph_pos; 329 330 /* Stack size */ 331 cfg->stack_data.prop_id = APM_CONTAINER_PROP_ID_STACK_SIZE; 332 cfg->stack_data.prop_size = sizeof(struct apm_cont_prop_id_stack_size); 333 cfg->stack.stack_size = cont->stack_size; 334 335 /* Proc domain */ 336 cfg->domain_data.prop_id = APM_CONTAINER_PROP_ID_PROC_DOMAIN; 337 cfg->domain_data.prop_size = sizeof(struct apm_cont_prop_id_domain); 338 cfg->domain.proc_domain = cont->proc_domain; 339 } 340 341 static void apm_populate_sub_graph_config(struct apm_sub_graph_data *cfg, 342 const struct audioreach_sub_graph *sg) 343 { 344 cfg->sub_graph_cfg.sub_graph_id = sg->sub_graph_id; 345 cfg->sub_graph_cfg.num_sub_graph_prop = APM_SUB_GRAPH_CFG_NPROP; 346 347 /* Perf Mode */ 348 cfg->perf_data.prop_id = APM_SUB_GRAPH_PROP_ID_PERF_MODE; 349 cfg->perf_data.prop_size = APM_SG_PROP_ID_PERF_MODE_SIZE; 350 cfg->perf.perf_mode = sg->perf_mode; 351 352 /* Direction */ 353 cfg->dir_data.prop_id = APM_SUB_GRAPH_PROP_ID_DIRECTION; 354 cfg->dir_data.prop_size = APM_SG_PROP_ID_DIR_SIZE; 355 cfg->dir.direction = sg->direction; 356 357 /* Scenario ID */ 358 cfg->sid_data.prop_id = APM_SUB_GRAPH_PROP_ID_SCENARIO_ID; 359 cfg->sid_data.prop_size = APM_SG_PROP_ID_SID_SIZE; 360 cfg->sid.scenario_id = sg->scenario_id; 361 } 362 363 static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj, 364 const struct audioreach_module *module) 365 { 366 367 obj->instance_id = module->instance_id; 368 obj->num_props = 1; 369 obj->prop_data_1.prop_id = APM_MODULE_PROP_ID_PORT_INFO; 370 obj->prop_data_1.prop_size = APM_MODULE_PROP_ID_PORT_INFO_SZ; 371 obj->prop_id_port.max_ip_port = module->max_ip_port; 372 obj->prop_id_port.max_op_port = module->max_op_port; 373 } 374 375 static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj, 376 const struct audioreach_container *container, 377 int sub_graph_id) 378 { 379 struct audioreach_module *module; 380 int i; 381 382 obj->sub_graph_id = sub_graph_id; 383 obj->container_id = container->container_id; 384 obj->num_modules = container->num_modules; 385 i = 0; 386 list_for_each_entry(module, &container->modules_list, node) { 387 obj->mod_cfg[i].module_id = module->module_id; 388 obj->mod_cfg[i].instance_id = module->instance_id; 389 i++; 390 } 391 } 392 393 static void audioreach_populate_graph(struct q6apm *apm, 394 const struct audioreach_graph_info *info, 395 struct apm_graph_open_params *open, 396 const struct list_head *sg_list, 397 int num_sub_graphs) 398 { 399 struct apm_mod_conn_list_params *mc_data = open->mod_conn_list_data; 400 struct apm_module_list_params *ml_data = open->mod_list_data; 401 struct apm_prop_list_params *mp_data = open->mod_prop_data; 402 struct apm_container_params *c_data = open->cont_data; 403 struct apm_sub_graph_params *sg_data = open->sg_data; 404 int ncontainer = 0, nmodule = 0, nconn = 0; 405 struct apm_mod_prop_obj *module_prop_obj; 406 struct audioreach_container *container; 407 struct apm_module_conn_obj *conn_obj; 408 struct audioreach_module *module; 409 struct audioreach_sub_graph *sg; 410 struct apm_container_obj *cobj; 411 struct apm_mod_list_obj *mlobj; 412 int i = 0; 413 414 mlobj = &ml_data->mod_list_obj[0]; 415 416 417 if (info->dst_mod_inst_id && info->src_mod_inst_id) { 418 conn_obj = &mc_data->conn_obj[nconn]; 419 conn_obj->src_mod_inst_id = info->src_mod_inst_id; 420 conn_obj->src_mod_op_port_id = info->src_mod_op_port_id; 421 conn_obj->dst_mod_inst_id = info->dst_mod_inst_id; 422 conn_obj->dst_mod_ip_port_id = info->dst_mod_ip_port_id; 423 nconn++; 424 } 425 426 list_for_each_entry(sg, sg_list, node) { 427 struct apm_sub_graph_data *sg_cfg = &sg_data->sg_cfg[i++]; 428 429 apm_populate_sub_graph_config(sg_cfg, sg); 430 431 list_for_each_entry(container, &sg->container_list, node) { 432 cobj = &c_data->cont_obj[ncontainer]; 433 434 apm_populate_container_config(cobj, container); 435 apm_populate_module_list_obj(mlobj, container, sg->sub_graph_id); 436 437 list_for_each_entry(module, &container->modules_list, node) { 438 int pn; 439 440 module_prop_obj = &mp_data->mod_prop_obj[nmodule++]; 441 apm_populate_module_prop_obj(module_prop_obj, module); 442 443 if (!module->max_op_port) 444 continue; 445 446 for (pn = 0; pn < module->max_op_port; pn++) { 447 if (module->dst_mod_inst_id[pn]) { 448 conn_obj = &mc_data->conn_obj[nconn]; 449 conn_obj->src_mod_inst_id = module->instance_id; 450 conn_obj->src_mod_op_port_id = 451 module->src_mod_op_port_id[pn]; 452 conn_obj->dst_mod_inst_id = 453 module->dst_mod_inst_id[pn]; 454 conn_obj->dst_mod_ip_port_id = 455 module->dst_mod_ip_port_id[pn]; 456 nconn++; 457 } 458 } 459 } 460 mlobj = (void *) mlobj + APM_MOD_LIST_OBJ_PSIZE(mlobj, 461 container->num_modules); 462 463 ncontainer++; 464 } 465 } 466 } 467 468 void *audioreach_alloc_graph_pkt(struct q6apm *apm, 469 const struct audioreach_graph_info *info) 470 { 471 int payload_size, sg_sz, cont_sz, ml_sz, mp_sz, mc_sz; 472 struct apm_module_param_data *param_data; 473 struct apm_container_params *cont_params; 474 struct audioreach_container *container; 475 struct apm_sub_graph_params *sg_params; 476 struct apm_mod_conn_list_params *mcon; 477 struct apm_graph_open_params params; 478 struct apm_prop_list_params *mprop; 479 struct audioreach_module *module; 480 struct audioreach_sub_graph *sgs; 481 struct apm_mod_list_obj *mlobj; 482 const struct list_head *sg_list; 483 int num_connections = 0; 484 int num_containers = 0; 485 int num_sub_graphs = 0; 486 int num_modules = 0; 487 int num_modules_list; 488 struct gpr_pkt *pkt; 489 void *p; 490 491 sg_list = &info->sg_list; 492 ml_sz = 0; 493 494 /* add FE-BE connections */ 495 if (info->dst_mod_inst_id && info->src_mod_inst_id) 496 num_connections++; 497 498 list_for_each_entry(sgs, sg_list, node) { 499 num_sub_graphs++; 500 list_for_each_entry(container, &sgs->container_list, node) { 501 num_containers++; 502 num_modules += container->num_modules; 503 ml_sz = ml_sz + sizeof(struct apm_module_list_params) + 504 APM_MOD_LIST_OBJ_PSIZE(mlobj, container->num_modules); 505 506 list_for_each_entry(module, &container->modules_list, node) { 507 num_connections += module->num_connections; 508 } 509 } 510 } 511 512 num_modules_list = num_containers; 513 sg_sz = APM_SUB_GRAPH_PSIZE(sg_params, num_sub_graphs); 514 cont_sz = APM_CONTAINER_PSIZE(cont_params, num_containers); 515 516 ml_sz = ALIGN(ml_sz, 8); 517 518 mp_sz = APM_MOD_PROP_PSIZE(mprop, num_modules); 519 mc_sz = APM_MOD_CONN_PSIZE(mcon, num_connections); 520 521 payload_size = sg_sz + cont_sz + ml_sz + mp_sz + mc_sz; 522 pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_GRAPH_OPEN, 0); 523 if (IS_ERR(pkt)) 524 return pkt; 525 526 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 527 528 /* SubGraph */ 529 params.sg_data = p; 530 param_data = ¶ms.sg_data->param_data; 531 param_data->module_instance_id = APM_MODULE_INSTANCE_ID; 532 param_data->param_id = APM_PARAM_ID_SUB_GRAPH_CONFIG; 533 param_data->param_size = sg_sz - APM_MODULE_PARAM_DATA_SIZE; 534 params.sg_data->num_sub_graphs = num_sub_graphs; 535 p += sg_sz; 536 537 /* Container */ 538 params.cont_data = p; 539 param_data = ¶ms.cont_data->param_data; 540 param_data->module_instance_id = APM_MODULE_INSTANCE_ID; 541 param_data->param_id = APM_PARAM_ID_CONTAINER_CONFIG; 542 param_data->param_size = cont_sz - APM_MODULE_PARAM_DATA_SIZE; 543 params.cont_data->num_containers = num_containers; 544 p += cont_sz; 545 546 /* Module List*/ 547 params.mod_list_data = p; 548 param_data = ¶ms.mod_list_data->param_data; 549 param_data->module_instance_id = APM_MODULE_INSTANCE_ID; 550 param_data->param_id = APM_PARAM_ID_MODULE_LIST; 551 param_data->param_size = ml_sz - APM_MODULE_PARAM_DATA_SIZE; 552 params.mod_list_data->num_modules_list = num_modules_list; 553 p += ml_sz; 554 555 /* Module Properties */ 556 params.mod_prop_data = p; 557 param_data = ¶ms.mod_prop_data->param_data; 558 param_data->module_instance_id = APM_MODULE_INSTANCE_ID; 559 param_data->param_id = APM_PARAM_ID_MODULE_PROP; 560 param_data->param_size = mp_sz - APM_MODULE_PARAM_DATA_SIZE; 561 params.mod_prop_data->num_modules_prop_cfg = num_modules; 562 p += mp_sz; 563 564 /* Module Connections */ 565 params.mod_conn_list_data = p; 566 param_data = ¶ms.mod_conn_list_data->param_data; 567 param_data->module_instance_id = APM_MODULE_INSTANCE_ID; 568 param_data->param_id = APM_PARAM_ID_MODULE_CONN; 569 param_data->param_size = mc_sz - APM_MODULE_PARAM_DATA_SIZE; 570 params.mod_conn_list_data->num_connections = num_connections; 571 p += mc_sz; 572 573 audioreach_populate_graph(apm, info, ¶ms, sg_list, num_sub_graphs); 574 575 return pkt; 576 } 577 EXPORT_SYMBOL_GPL(audioreach_alloc_graph_pkt); 578 579 int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, 580 struct gpr_ibasic_rsp_result_t *result, struct mutex *cmd_lock, 581 gpr_port_t *port, wait_queue_head_t *cmd_wait, 582 struct gpr_pkt *pkt, uint32_t rsp_opcode) 583 { 584 585 struct gpr_hdr *hdr = &pkt->hdr; 586 int rc; 587 588 mutex_lock(cmd_lock); 589 result->opcode = 0; 590 result->status = 0; 591 592 if (port) 593 rc = gpr_send_port_pkt(port, pkt); 594 else if (gdev) 595 rc = gpr_send_pkt(gdev, pkt); 596 else 597 rc = -EINVAL; 598 599 if (rc < 0) 600 goto err; 601 602 if (rsp_opcode) 603 rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode) || 604 (result->opcode == rsp_opcode), 5 * HZ); 605 else 606 rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode), 5 * HZ); 607 608 if (!rc) { 609 dev_err(dev, "CMD timeout for [%x] opcode\n", hdr->opcode); 610 rc = -ETIMEDOUT; 611 } else if (result->status > 0) { 612 dev_err(dev, "DSP returned error[%x] %x\n", hdr->opcode, result->status); 613 rc = -EINVAL; 614 } else { 615 /* DSP successfully finished the command */ 616 rc = 0; 617 } 618 619 err: 620 mutex_unlock(cmd_lock); 621 return rc; 622 } 623 EXPORT_SYMBOL_GPL(audioreach_send_cmd_sync); 624 625 int audioreach_graph_send_cmd_sync(struct q6apm_graph *graph, struct gpr_pkt *pkt, 626 uint32_t rsp_opcode) 627 { 628 629 return audioreach_send_cmd_sync(graph->dev, NULL, &graph->result, &graph->lock, 630 graph->port, &graph->cmd_wait, pkt, rsp_opcode); 631 } 632 EXPORT_SYMBOL_GPL(audioreach_graph_send_cmd_sync); 633 634 static int audioreach_display_port_set_media_format(struct q6apm_graph *graph, 635 const struct audioreach_module *module, 636 const struct audioreach_module_config *cfg) 637 { 638 struct apm_display_port_module_intf_cfg *intf_cfg; 639 struct apm_module_frame_size_factor_cfg *fs_cfg; 640 struct apm_module_param_data *param_data; 641 struct apm_module_hw_ep_mf_cfg *hw_cfg; 642 int ic_sz = APM_DP_INTF_CFG_PSIZE; 643 int ep_sz = APM_HW_EP_CFG_PSIZE; 644 int fs_sz = APM_FS_CFG_PSIZE; 645 int size = ic_sz + ep_sz + fs_sz; 646 void *p; 647 648 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); 649 if (IS_ERR(pkt)) 650 return PTR_ERR(pkt); 651 652 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 653 654 hw_cfg = p; 655 param_data = &hw_cfg->param_data; 656 param_data->module_instance_id = module->instance_id; 657 param_data->error_code = 0; 658 param_data->param_id = PARAM_ID_HW_EP_MF_CFG; 659 param_data->param_size = ep_sz - APM_MODULE_PARAM_DATA_SIZE; 660 661 hw_cfg->mf.sample_rate = cfg->sample_rate; 662 hw_cfg->mf.bit_width = cfg->bit_width; 663 hw_cfg->mf.num_channels = cfg->num_channels; 664 hw_cfg->mf.data_format = module->data_format; 665 p += ep_sz; 666 667 fs_cfg = p; 668 param_data = &fs_cfg->param_data; 669 param_data->module_instance_id = module->instance_id; 670 param_data->error_code = 0; 671 param_data->param_id = PARAM_ID_HW_EP_FRAME_SIZE_FACTOR; 672 param_data->param_size = fs_sz - APM_MODULE_PARAM_DATA_SIZE; 673 fs_cfg->frame_size_factor = 1; 674 p += fs_sz; 675 676 intf_cfg = p; 677 param_data = &intf_cfg->param_data; 678 param_data->module_instance_id = module->instance_id; 679 param_data->error_code = 0; 680 param_data->param_id = PARAM_ID_DISPLAY_PORT_INTF_CFG; 681 param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE; 682 683 intf_cfg->cfg.channel_allocation = cfg->channel_allocation; 684 intf_cfg->cfg.mst_idx = 0; 685 intf_cfg->cfg.dptx_idx = cfg->dp_idx; 686 687 return q6apm_send_cmd_sync(graph->apm, pkt, 0); 688 } 689 690 /* LPASS Codec DMA port Module Media Format Setup */ 691 static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph, 692 const struct audioreach_module *module, 693 const struct audioreach_module_config *cfg) 694 { 695 struct apm_codec_dma_module_intf_cfg *intf_cfg; 696 struct apm_module_frame_size_factor_cfg *fs_cfg; 697 struct apm_module_hw_ep_power_mode_cfg *pm_cfg; 698 struct apm_module_param_data *param_data; 699 struct apm_module_hw_ep_mf_cfg *hw_cfg; 700 int ic_sz = APM_CDMA_INTF_CFG_PSIZE; 701 int ep_sz = APM_HW_EP_CFG_PSIZE; 702 int fs_sz = APM_FS_CFG_PSIZE; 703 int pm_sz = APM_HW_EP_PMODE_CFG_PSIZE; 704 int size = ic_sz + ep_sz + fs_sz + pm_sz; 705 void *p; 706 707 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); 708 if (IS_ERR(pkt)) 709 return PTR_ERR(pkt); 710 711 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 712 713 hw_cfg = p; 714 param_data = &hw_cfg->param_data; 715 param_data->module_instance_id = module->instance_id; 716 param_data->error_code = 0; 717 param_data->param_id = PARAM_ID_HW_EP_MF_CFG; 718 param_data->param_size = ep_sz - APM_MODULE_PARAM_DATA_SIZE; 719 720 hw_cfg->mf.sample_rate = cfg->sample_rate; 721 hw_cfg->mf.bit_width = cfg->bit_width; 722 hw_cfg->mf.num_channels = cfg->num_channels; 723 hw_cfg->mf.data_format = module->data_format; 724 p += ep_sz; 725 726 fs_cfg = p; 727 param_data = &fs_cfg->param_data; 728 param_data->module_instance_id = module->instance_id; 729 param_data->error_code = 0; 730 param_data->param_id = PARAM_ID_HW_EP_FRAME_SIZE_FACTOR; 731 param_data->param_size = fs_sz - APM_MODULE_PARAM_DATA_SIZE; 732 fs_cfg->frame_size_factor = 1; 733 p += fs_sz; 734 735 intf_cfg = p; 736 param_data = &intf_cfg->param_data; 737 param_data->module_instance_id = module->instance_id; 738 param_data->error_code = 0; 739 param_data->param_id = PARAM_ID_CODEC_DMA_INTF_CFG; 740 param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE; 741 742 intf_cfg->cfg.lpaif_type = module->hw_interface_type; 743 intf_cfg->cfg.intf_index = module->hw_interface_idx; 744 intf_cfg->cfg.active_channels_mask = (1 << cfg->num_channels) - 1; 745 p += ic_sz; 746 747 pm_cfg = p; 748 param_data = &pm_cfg->param_data; 749 param_data->module_instance_id = module->instance_id; 750 param_data->error_code = 0; 751 param_data->param_id = PARAM_ID_HW_EP_POWER_MODE_CFG; 752 param_data->param_size = pm_sz - APM_MODULE_PARAM_DATA_SIZE; 753 pm_cfg->power_mode.power_mode = 0; 754 755 return q6apm_send_cmd_sync(graph->apm, pkt, 0); 756 } 757 758 int audioreach_send_u32_param(struct q6apm_graph *graph, 759 const struct audioreach_module *module, 760 uint32_t param_id, uint32_t param_val) 761 { 762 struct apm_module_param_data *param_data; 763 uint32_t *param; 764 int payload_size = sizeof(uint32_t) + APM_MODULE_PARAM_DATA_SIZE; 765 void *p; 766 767 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); 768 if (IS_ERR(pkt)) 769 return -ENOMEM; 770 771 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 772 773 param_data = p; 774 param_data->module_instance_id = module->instance_id; 775 param_data->error_code = 0; 776 param_data->param_id = param_id; 777 param_data->param_size = sizeof(uint32_t); 778 779 p = p + APM_MODULE_PARAM_DATA_SIZE; 780 param = p; 781 *param = param_val; 782 783 return q6apm_send_cmd_sync(graph->apm, pkt, 0); 784 } 785 EXPORT_SYMBOL_GPL(audioreach_send_u32_param); 786 787 static int audioreach_sal_limiter_enable(struct q6apm_graph *graph, 788 const struct audioreach_module *module, 789 bool enable) 790 { 791 return audioreach_send_u32_param(graph, module, PARAM_ID_SAL_LIMITER_ENABLE, enable); 792 } 793 794 static int audioreach_sal_set_media_format(struct q6apm_graph *graph, 795 const struct audioreach_module *module, 796 const struct audioreach_module_config *cfg) 797 { 798 return audioreach_send_u32_param(graph, module, PARAM_ID_SAL_OUTPUT_CFG, cfg->bit_width); 799 } 800 801 static int audioreach_module_enable(struct q6apm_graph *graph, 802 const struct audioreach_module *module, 803 bool enable) 804 { 805 return audioreach_send_u32_param(graph, module, PARAM_ID_MODULE_ENABLE, enable); 806 } 807 808 static int audioreach_gapless_set_media_format(struct q6apm_graph *graph, 809 const struct audioreach_module *module, 810 const struct audioreach_module_config *cfg) 811 { 812 return audioreach_send_u32_param(graph, module, PARAM_ID_EARLY_EOS_DELAY, 813 EARLY_EOS_DELAY_MS); 814 } 815 816 static int audioreach_set_module_config(struct q6apm_graph *graph, 817 const struct audioreach_module *module, 818 const struct audioreach_module_config *cfg) 819 { 820 int size = le32_to_cpu(module->data->size); 821 void *p; 822 823 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); 824 if (IS_ERR(pkt)) 825 return PTR_ERR(pkt); 826 827 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 828 829 memcpy(p, module->data->data, size); 830 831 return q6apm_send_cmd_sync(graph->apm, pkt, 0); 832 } 833 834 static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, 835 const struct audioreach_module *module, 836 const struct audioreach_module_config *cfg) 837 { 838 struct apm_module_param_data *param_data; 839 struct param_id_mfc_media_format *media_format; 840 uint32_t num_channels = cfg->num_channels; 841 int payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) + 842 APM_MODULE_PARAM_DATA_SIZE; 843 int i; 844 void *p; 845 846 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); 847 if (IS_ERR(pkt)) 848 return PTR_ERR(pkt); 849 850 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 851 852 param_data = p; 853 param_data->module_instance_id = module->instance_id; 854 param_data->error_code = 0; 855 param_data->param_id = PARAM_ID_MFC_OUTPUT_MEDIA_FORMAT; 856 param_data->param_size = APM_MFC_CFG_PSIZE(media_format, num_channels); 857 p = p + APM_MODULE_PARAM_DATA_SIZE; 858 media_format = p; 859 860 media_format->sample_rate = cfg->sample_rate; 861 media_format->bit_width = cfg->bit_width; 862 media_format->num_channels = cfg->num_channels; 863 for (i = 0; i < num_channels; i++) 864 media_format->channel_mapping[i] = cfg->channel_map[i]; 865 866 return q6apm_send_cmd_sync(graph->apm, pkt, 0); 867 } 868 869 static int audioreach_set_compr_media_format(struct media_format *media_fmt_hdr, 870 void *p, 871 const struct audioreach_module_config *mcfg) 872 { 873 struct payload_media_fmt_aac_t *aac_cfg; 874 struct payload_media_fmt_pcm *mp3_cfg; 875 struct payload_media_fmt_flac_t *flac_cfg; 876 struct payload_media_fmt_opus_t *opus_cfg; 877 878 switch (mcfg->fmt) { 879 case SND_AUDIOCODEC_MP3: 880 media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED; 881 media_fmt_hdr->fmt_id = MEDIA_FMT_ID_MP3; 882 media_fmt_hdr->payload_size = 0; 883 p = p + sizeof(*media_fmt_hdr); 884 mp3_cfg = p; 885 mp3_cfg->sample_rate = mcfg->sample_rate; 886 mp3_cfg->bit_width = mcfg->bit_width; 887 mp3_cfg->alignment = PCM_LSB_ALIGNED; 888 mp3_cfg->bits_per_sample = mcfg->bit_width; 889 mp3_cfg->q_factor = mcfg->bit_width - 1; 890 mp3_cfg->endianness = PCM_LITTLE_ENDIAN; 891 mp3_cfg->num_channels = mcfg->num_channels; 892 break; 893 case SND_AUDIOCODEC_AAC: 894 media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED; 895 media_fmt_hdr->fmt_id = MEDIA_FMT_ID_AAC; 896 media_fmt_hdr->payload_size = sizeof(struct payload_media_fmt_aac_t); 897 p = p + sizeof(*media_fmt_hdr); 898 aac_cfg = p; 899 aac_cfg->aac_fmt_flag = 0; 900 aac_cfg->audio_obj_type = 5; 901 aac_cfg->num_channels = mcfg->num_channels; 902 aac_cfg->total_size_of_PCE_bits = 0; 903 aac_cfg->sample_rate = mcfg->sample_rate; 904 break; 905 case SND_AUDIOCODEC_FLAC: 906 media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED; 907 media_fmt_hdr->fmt_id = MEDIA_FMT_ID_FLAC; 908 media_fmt_hdr->payload_size = sizeof(struct payload_media_fmt_flac_t); 909 p = p + sizeof(*media_fmt_hdr); 910 flac_cfg = p; 911 flac_cfg->sample_size = mcfg->codec.options.flac_d.sample_size; 912 flac_cfg->num_channels = mcfg->num_channels; 913 flac_cfg->min_blk_size = mcfg->codec.options.flac_d.min_blk_size; 914 flac_cfg->max_blk_size = mcfg->codec.options.flac_d.max_blk_size; 915 flac_cfg->sample_rate = mcfg->sample_rate; 916 flac_cfg->min_frame_size = mcfg->codec.options.flac_d.min_frame_size; 917 flac_cfg->max_frame_size = mcfg->codec.options.flac_d.max_frame_size; 918 break; 919 case SND_AUDIOCODEC_OPUS_RAW: 920 media_fmt_hdr->data_format = DATA_FORMAT_RAW_COMPRESSED; 921 media_fmt_hdr->fmt_id = MEDIA_FMT_ID_OPUS; 922 media_fmt_hdr->payload_size = sizeof(*opus_cfg); 923 p = p + sizeof(*media_fmt_hdr); 924 opus_cfg = p; 925 /* raw opus packets prepended with 4 bytes of length */ 926 opus_cfg->bitstream_format = 1; 927 /* 928 * payload_type: 929 * 0 -- read metadata from opus stream; 930 * 1 -- metadata is provided by filling in the struct here. 931 */ 932 opus_cfg->payload_type = 1; 933 opus_cfg->version = mcfg->codec.options.opus_d.version; 934 opus_cfg->num_channels = mcfg->codec.options.opus_d.num_channels; 935 opus_cfg->pre_skip = mcfg->codec.options.opus_d.pre_skip; 936 opus_cfg->sample_rate = mcfg->codec.options.opus_d.sample_rate; 937 opus_cfg->output_gain = mcfg->codec.options.opus_d.output_gain; 938 opus_cfg->mapping_family = mcfg->codec.options.opus_d.mapping_family; 939 opus_cfg->stream_count = mcfg->codec.options.opus_d.chan_map.stream_count; 940 opus_cfg->coupled_count = mcfg->codec.options.opus_d.chan_map.coupled_count; 941 memcpy(opus_cfg->channel_mapping, mcfg->codec.options.opus_d.chan_map.channel_map, 942 sizeof(opus_cfg->channel_mapping)); 943 opus_cfg->reserved[0] = opus_cfg->reserved[1] = opus_cfg->reserved[2] = 0; 944 break; 945 default: 946 return -EINVAL; 947 } 948 949 return 0; 950 } 951 952 int audioreach_compr_set_param(struct q6apm_graph *graph, 953 const struct audioreach_module_config *mcfg) 954 { 955 struct media_format *header; 956 int rc; 957 void *p; 958 int iid = q6apm_graph_get_rx_shmem_module_iid(graph); 959 int payload_size = sizeof(struct apm_sh_module_media_fmt_cmd); 960 961 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_cmd_pkt(payload_size, 962 DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT, 963 0, graph->port->id, iid); 964 if (IS_ERR(pkt)) 965 return -ENOMEM; 966 967 p = (void *)pkt + GPR_HDR_SIZE; 968 header = p; 969 rc = audioreach_set_compr_media_format(header, p, mcfg); 970 if (rc) 971 return rc; 972 973 return gpr_send_port_pkt(graph->port, pkt); 974 } 975 EXPORT_SYMBOL_GPL(audioreach_compr_set_param); 976 977 static int audioreach_i2s_set_media_format(struct q6apm_graph *graph, 978 const struct audioreach_module *module, 979 const struct audioreach_module_config *cfg) 980 { 981 struct apm_module_frame_size_factor_cfg *fs_cfg; 982 struct apm_module_param_data *param_data; 983 struct apm_i2s_module_intf_cfg *intf_cfg; 984 struct apm_module_hw_ep_mf_cfg *hw_cfg; 985 int ic_sz = APM_I2S_INTF_CFG_PSIZE; 986 int ep_sz = APM_HW_EP_CFG_PSIZE; 987 int fs_sz = APM_FS_CFG_PSIZE; 988 int size = ic_sz + ep_sz + fs_sz; 989 void *p; 990 991 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); 992 if (IS_ERR(pkt)) 993 return PTR_ERR(pkt); 994 995 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 996 intf_cfg = p; 997 998 param_data = &intf_cfg->param_data; 999 param_data->module_instance_id = module->instance_id; 1000 param_data->error_code = 0; 1001 param_data->param_id = PARAM_ID_I2S_INTF_CFG; 1002 param_data->param_size = ic_sz - APM_MODULE_PARAM_DATA_SIZE; 1003 1004 intf_cfg->cfg.lpaif_type = module->hw_interface_type; 1005 intf_cfg->cfg.intf_idx = module->hw_interface_idx; 1006 intf_cfg->cfg.sd_line_idx = module->sd_line_idx; 1007 1008 switch (cfg->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 1009 case SND_SOC_DAIFMT_BP_FP: 1010 intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_INTERNAL; 1011 break; 1012 case SND_SOC_DAIFMT_BC_FC: 1013 /* CPU is slave */ 1014 intf_cfg->cfg.ws_src = CONFIG_I2S_WS_SRC_EXTERNAL; 1015 break; 1016 default: 1017 break; 1018 } 1019 1020 p += ic_sz; 1021 hw_cfg = p; 1022 param_data = &hw_cfg->param_data; 1023 param_data->module_instance_id = module->instance_id; 1024 param_data->error_code = 0; 1025 param_data->param_id = PARAM_ID_HW_EP_MF_CFG; 1026 param_data->param_size = ep_sz - APM_MODULE_PARAM_DATA_SIZE; 1027 1028 hw_cfg->mf.sample_rate = cfg->sample_rate; 1029 hw_cfg->mf.bit_width = cfg->bit_width; 1030 hw_cfg->mf.num_channels = cfg->num_channels; 1031 hw_cfg->mf.data_format = module->data_format; 1032 1033 p += ep_sz; 1034 fs_cfg = p; 1035 param_data = &fs_cfg->param_data; 1036 param_data->module_instance_id = module->instance_id; 1037 param_data->error_code = 0; 1038 param_data->param_id = PARAM_ID_HW_EP_FRAME_SIZE_FACTOR; 1039 param_data->param_size = fs_sz - APM_MODULE_PARAM_DATA_SIZE; 1040 fs_cfg->frame_size_factor = 1; 1041 1042 return q6apm_send_cmd_sync(graph->apm, pkt, 0); 1043 } 1044 1045 static int audioreach_logging_set_media_format(struct q6apm_graph *graph, 1046 const struct audioreach_module *module) 1047 { 1048 struct apm_module_param_data *param_data; 1049 struct data_logging_config *cfg; 1050 int size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE; 1051 void *p; 1052 1053 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); 1054 if (IS_ERR(pkt)) 1055 return PTR_ERR(pkt); 1056 1057 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 1058 1059 param_data = p; 1060 param_data->module_instance_id = module->instance_id; 1061 param_data->error_code = 0; 1062 param_data->param_id = PARAM_ID_DATA_LOGGING_CONFIG; 1063 param_data->param_size = size - APM_MODULE_PARAM_DATA_SIZE; 1064 1065 p = p + APM_MODULE_PARAM_DATA_SIZE; 1066 cfg = p; 1067 cfg->log_code = module->log_code; 1068 cfg->log_tap_point_id = module->log_tap_point_id; 1069 cfg->mode = module->log_mode; 1070 1071 return q6apm_send_cmd_sync(graph->apm, pkt, 0); 1072 } 1073 1074 static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, 1075 const struct audioreach_module *module, 1076 const struct audioreach_module_config *mcfg) 1077 { 1078 struct payload_pcm_output_format_cfg *media_cfg; 1079 uint32_t num_channels = mcfg->num_channels; 1080 struct apm_pcm_module_media_fmt_cmd *cfg; 1081 struct apm_module_param_data *param_data; 1082 int payload_size; 1083 1084 if (num_channels > 4) { 1085 dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels); 1086 return -EINVAL; 1087 } 1088 1089 payload_size = APM_PCM_MODULE_FMT_CMD_PSIZE(num_channels); 1090 1091 struct gpr_pkt *pkt __free(kfree) = 1092 audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); 1093 if (IS_ERR(pkt)) 1094 return PTR_ERR(pkt); 1095 1096 cfg = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 1097 1098 param_data = &cfg->param_data; 1099 param_data->module_instance_id = module->instance_id; 1100 param_data->error_code = 0; 1101 param_data->param_id = PARAM_ID_PCM_OUTPUT_FORMAT_CFG; 1102 param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE; 1103 1104 cfg->header.data_format = DATA_FORMAT_FIXED_POINT; 1105 cfg->header.fmt_id = MEDIA_FMT_ID_PCM; 1106 cfg->header.payload_size = APM_PCM_OUT_FMT_CFG_PSIZE(media_cfg, num_channels); 1107 1108 media_cfg = &cfg->media_cfg; 1109 media_cfg->alignment = PCM_LSB_ALIGNED; 1110 media_cfg->bit_width = mcfg->bit_width; 1111 media_cfg->endianness = PCM_LITTLE_ENDIAN; 1112 media_cfg->interleaved = module->interleave_type; 1113 media_cfg->num_channels = mcfg->num_channels; 1114 media_cfg->q_factor = mcfg->bit_width - 1; 1115 media_cfg->bits_per_sample = mcfg->bit_width; 1116 memcpy(media_cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); 1117 1118 return q6apm_send_cmd_sync(graph->apm, pkt, 0); 1119 } 1120 1121 static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, 1122 const struct audioreach_module *module, 1123 const struct audioreach_module_config *mcfg) 1124 { 1125 uint32_t num_channels = mcfg->num_channels; 1126 struct apm_module_param_data *param_data; 1127 struct payload_media_fmt_pcm *cfg; 1128 struct media_format *header; 1129 int rc, payload_size; 1130 void *p; 1131 1132 if (num_channels > 4) { 1133 dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels); 1134 return -EINVAL; 1135 } 1136 1137 payload_size = APM_SHMEM_FMT_CFG_PSIZE(num_channels) + APM_MODULE_PARAM_DATA_SIZE; 1138 1139 struct gpr_pkt *pkt __free(kfree) = 1140 audioreach_alloc_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, 1141 graph->port->id, module->instance_id); 1142 if (IS_ERR(pkt)) 1143 return PTR_ERR(pkt); 1144 1145 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 1146 1147 param_data = p; 1148 param_data->module_instance_id = module->instance_id; 1149 param_data->error_code = 0; 1150 param_data->param_id = PARAM_ID_MEDIA_FORMAT; 1151 param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE; 1152 p = p + APM_MODULE_PARAM_DATA_SIZE; 1153 1154 header = p; 1155 if (mcfg->fmt == SND_AUDIOCODEC_PCM) { 1156 header->data_format = DATA_FORMAT_FIXED_POINT; 1157 header->fmt_id = MEDIA_FMT_ID_PCM; 1158 header->payload_size = payload_size - sizeof(*header); 1159 1160 p = p + sizeof(*header); 1161 cfg = p; 1162 cfg->sample_rate = mcfg->sample_rate; 1163 cfg->bit_width = mcfg->bit_width; 1164 cfg->alignment = PCM_LSB_ALIGNED; 1165 cfg->bits_per_sample = mcfg->bit_width; 1166 cfg->q_factor = mcfg->bit_width - 1; 1167 cfg->endianness = PCM_LITTLE_ENDIAN; 1168 cfg->num_channels = mcfg->num_channels; 1169 memcpy(cfg->channel_mapping, mcfg->channel_map, mcfg->num_channels); 1170 } else { 1171 rc = audioreach_set_compr_media_format(header, p, mcfg); 1172 if (rc) 1173 return rc; 1174 } 1175 1176 return audioreach_graph_send_cmd_sync(graph, pkt, 0); 1177 } 1178 1179 int audioreach_gain_set_vol_ctrl(struct q6apm *apm, 1180 const struct audioreach_module *module, int vol) 1181 { 1182 struct param_id_vol_ctrl_master_gain *cfg; 1183 struct apm_module_param_data *param_data; 1184 int size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE; 1185 void *p; 1186 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); 1187 if (IS_ERR(pkt)) 1188 return PTR_ERR(pkt); 1189 1190 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 1191 1192 param_data = p; 1193 param_data->module_instance_id = module->instance_id; 1194 param_data->error_code = 0; 1195 param_data->param_id = PARAM_ID_VOL_CTRL_MASTER_GAIN; 1196 param_data->param_size = size - APM_MODULE_PARAM_DATA_SIZE; 1197 1198 p = p + APM_MODULE_PARAM_DATA_SIZE; 1199 cfg = p; 1200 cfg->master_gain = vol; 1201 return q6apm_send_cmd_sync(apm, pkt, 0); 1202 } 1203 EXPORT_SYMBOL_GPL(audioreach_gain_set_vol_ctrl); 1204 1205 static int audioreach_gain_set(struct q6apm_graph *graph, 1206 const struct audioreach_module *module) 1207 { 1208 struct apm_module_param_data *param_data; 1209 struct apm_gain_module_cfg *cfg; 1210 int size = APM_GAIN_CFG_PSIZE; 1211 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); 1212 if (IS_ERR(pkt)) 1213 return PTR_ERR(pkt); 1214 1215 cfg = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 1216 1217 param_data = &cfg->param_data; 1218 param_data->module_instance_id = module->instance_id; 1219 param_data->error_code = 0; 1220 param_data->param_id = APM_PARAM_ID_GAIN; 1221 param_data->param_size = size - APM_MODULE_PARAM_DATA_SIZE; 1222 1223 cfg->gain_cfg.gain = module->gain; 1224 1225 return q6apm_send_cmd_sync(graph->apm, pkt, 0); 1226 } 1227 1228 static int audioreach_speaker_protection(struct q6apm_graph *graph, 1229 const struct audioreach_module *module, 1230 uint32_t operation_mode) 1231 { 1232 return audioreach_send_u32_param(graph, module, PARAM_ID_SP_OP_MODE, 1233 operation_mode); 1234 } 1235 1236 static int audioreach_speaker_protection_vi(struct q6apm_graph *graph, 1237 const struct audioreach_module *module, 1238 const struct audioreach_module_config *mcfg) 1239 { 1240 u32 num_channels = mcfg->num_channels; 1241 struct apm_module_sp_vi_op_mode_cfg *op_cfg; 1242 struct apm_module_sp_vi_channel_map_cfg *cm_cfg; 1243 struct apm_module_sp_vi_ex_mode_cfg *ex_cfg; 1244 int op_sz, cm_sz, ex_sz; 1245 struct apm_module_param_data *param_data; 1246 int rc, i, payload_size; 1247 struct gpr_pkt *pkt; 1248 void *p; 1249 1250 if (num_channels > 2) { 1251 dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels); 1252 return -EINVAL; 1253 } 1254 1255 op_sz = APM_SP_VI_OP_MODE_CFG_PSIZE(num_channels); 1256 /* Channel mapping for Isense and Vsense, thus twice number of speakers. */ 1257 cm_sz = APM_SP_VI_CH_MAP_CFG_PSIZE(num_channels * 2); 1258 ex_sz = APM_SP_VI_EX_MODE_CFG_PSIZE; 1259 1260 payload_size = op_sz + cm_sz + ex_sz; 1261 1262 pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); 1263 if (IS_ERR(pkt)) 1264 return PTR_ERR(pkt); 1265 1266 p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 1267 1268 op_cfg = p; 1269 param_data = &op_cfg->param_data; 1270 param_data->module_instance_id = module->instance_id; 1271 param_data->error_code = 0; 1272 param_data->param_id = PARAM_ID_SP_VI_OP_MODE_CFG; 1273 param_data->param_size = op_sz - APM_MODULE_PARAM_DATA_SIZE; 1274 1275 op_cfg->cfg.num_channels = num_channels; 1276 op_cfg->cfg.operation_mode = PARAM_ID_SP_VI_OP_MODE_NORMAL; 1277 p += op_sz; 1278 1279 cm_cfg = p; 1280 param_data = &cm_cfg->param_data; 1281 param_data->module_instance_id = module->instance_id; 1282 param_data->error_code = 0; 1283 param_data->param_id = PARAM_ID_SP_VI_CHANNEL_MAP_CFG; 1284 param_data->param_size = cm_sz - APM_MODULE_PARAM_DATA_SIZE; 1285 1286 cm_cfg->cfg.num_channels = num_channels * 2; 1287 for (i = 0; i < num_channels; i++) { 1288 /* 1289 * Map speakers into Vsense and then Isense of each channel. 1290 * E.g. for PCM_CHANNEL_FL and PCM_CHANNEL_FR to: 1291 * [1, 2, 3, 4] 1292 */ 1293 cm_cfg->cfg.channel_mapping[2 * i] = (mcfg->channel_map[i] - 1) * 2 + 1; 1294 cm_cfg->cfg.channel_mapping[2 * i + 1] = (mcfg->channel_map[i] - 1) * 2 + 2; 1295 } 1296 1297 p += cm_sz; 1298 1299 ex_cfg = p; 1300 param_data = &ex_cfg->param_data; 1301 param_data->module_instance_id = module->instance_id; 1302 param_data->error_code = 0; 1303 param_data->param_id = PARAM_ID_SP_VI_EX_MODE_CFG; 1304 param_data->param_size = ex_sz - APM_MODULE_PARAM_DATA_SIZE; 1305 1306 ex_cfg->cfg.factory_mode = 0; 1307 1308 rc = q6apm_send_cmd_sync(graph->apm, pkt, 0); 1309 1310 kfree(pkt); 1311 1312 return rc; 1313 } 1314 1315 int audioreach_set_media_format(struct q6apm_graph *graph, 1316 const struct audioreach_module *module, 1317 const struct audioreach_module_config *cfg) 1318 { 1319 int rc; 1320 1321 switch (module->module_id) { 1322 case MODULE_ID_DATA_LOGGING: 1323 rc = audioreach_module_enable(graph, module, true); 1324 if (!rc) 1325 rc = audioreach_logging_set_media_format(graph, module); 1326 break; 1327 case MODULE_ID_PCM_DEC: 1328 case MODULE_ID_PCM_ENC: 1329 case MODULE_ID_PCM_CNV: 1330 case MODULE_ID_PLACEHOLDER_DECODER: 1331 case MODULE_ID_PLACEHOLDER_ENCODER: 1332 rc = audioreach_pcm_set_media_format(graph, module, cfg); 1333 break; 1334 case MODULE_ID_DISPLAY_PORT_SINK: 1335 rc = audioreach_display_port_set_media_format(graph, module, cfg); 1336 break; 1337 case MODULE_ID_SMECNS_V2: 1338 rc = audioreach_set_module_config(graph, module, cfg); 1339 break; 1340 case MODULE_ID_I2S_SOURCE: 1341 case MODULE_ID_I2S_SINK: 1342 rc = audioreach_i2s_set_media_format(graph, module, cfg); 1343 break; 1344 case MODULE_ID_WR_SHARED_MEM_EP: 1345 rc = audioreach_shmem_set_media_format(graph, module, cfg); 1346 break; 1347 case MODULE_ID_GAIN: 1348 rc = audioreach_gain_set(graph, module); 1349 break; 1350 case MODULE_ID_CODEC_DMA_SINK: 1351 case MODULE_ID_CODEC_DMA_SOURCE: 1352 rc = audioreach_codec_dma_set_media_format(graph, module, cfg); 1353 break; 1354 case MODULE_ID_SAL: 1355 rc = audioreach_sal_set_media_format(graph, module, cfg); 1356 if (!rc) 1357 rc = audioreach_sal_limiter_enable(graph, module, true); 1358 break; 1359 case MODULE_ID_MFC: 1360 rc = audioreach_mfc_set_media_format(graph, module, cfg); 1361 break; 1362 case MODULE_ID_GAPLESS: 1363 rc = audioreach_gapless_set_media_format(graph, module, cfg); 1364 break; 1365 case MODULE_ID_SPEAKER_PROTECTION: 1366 rc = audioreach_speaker_protection(graph, module, 1367 PARAM_ID_SP_OP_MODE_NORMAL); 1368 break; 1369 case MODULE_ID_SPEAKER_PROTECTION_VI: 1370 rc = audioreach_speaker_protection_vi(graph, module, cfg); 1371 break; 1372 1373 default: 1374 rc = 0; 1375 } 1376 1377 return rc; 1378 } 1379 EXPORT_SYMBOL_GPL(audioreach_set_media_format); 1380 1381 void audioreach_graph_free_buf(struct q6apm_graph *graph) 1382 { 1383 struct audioreach_graph_data *port; 1384 1385 mutex_lock(&graph->lock); 1386 port = &graph->rx_data; 1387 port->num_periods = 0; 1388 kfree(port->buf); 1389 port->buf = NULL; 1390 1391 port = &graph->tx_data; 1392 port->num_periods = 0; 1393 kfree(port->buf); 1394 port->buf = NULL; 1395 mutex_unlock(&graph->lock); 1396 } 1397 EXPORT_SYMBOL_GPL(audioreach_graph_free_buf); 1398 1399 int audioreach_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, size_t period_sz, 1400 unsigned int periods, bool is_contiguous) 1401 { 1402 struct apm_shared_map_region_payload *mregions; 1403 struct apm_cmd_shared_mem_map_regions *cmd; 1404 uint32_t num_regions, buf_sz, payload_size; 1405 struct audioreach_graph_data *data; 1406 struct gpr_pkt *pkt __free(kfree) = NULL; 1407 void *p; 1408 int i; 1409 1410 if (dir == SNDRV_PCM_STREAM_PLAYBACK) 1411 data = &graph->rx_data; 1412 else 1413 data = &graph->tx_data; 1414 1415 if (is_contiguous) { 1416 num_regions = 1; 1417 buf_sz = period_sz * periods; 1418 } else { 1419 buf_sz = period_sz; 1420 num_regions = periods; 1421 } 1422 1423 /* DSP expects size should be aligned to 4K */ 1424 buf_sz = ALIGN(buf_sz, 4096); 1425 1426 payload_size = sizeof(*cmd) + (sizeof(*mregions) * num_regions); 1427 1428 pkt = audioreach_alloc_apm_pkt(payload_size, APM_CMD_SHARED_MEM_MAP_REGIONS, dir, 1429 graph->port->id); 1430 if (IS_ERR(pkt)) 1431 return PTR_ERR(pkt); 1432 1433 p = (void *)pkt + GPR_HDR_SIZE; 1434 cmd = p; 1435 cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL; 1436 cmd->num_regions = num_regions; 1437 1438 cmd->property_flag = 0x0; 1439 1440 mregions = p + sizeof(*cmd); 1441 1442 mutex_lock(&graph->lock); 1443 1444 for (i = 0; i < num_regions; i++) { 1445 struct audio_buffer *ab; 1446 1447 ab = &data->buf[i]; 1448 mregions->shm_addr_lsw = lower_32_bits(ab->phys); 1449 mregions->shm_addr_msw = upper_32_bits(ab->phys); 1450 mregions->mem_size_bytes = buf_sz; 1451 ++mregions; 1452 } 1453 mutex_unlock(&graph->lock); 1454 1455 return audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS); 1456 } 1457 EXPORT_SYMBOL_GPL(audioreach_map_memory_regions); 1458 1459 int audioreach_shared_memory_send_eos(struct q6apm_graph *graph) 1460 { 1461 struct data_cmd_wr_sh_mem_ep_eos *eos; 1462 int iid = q6apm_graph_get_rx_shmem_module_iid(graph); 1463 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_cmd_pkt(sizeof(*eos), 1464 DATA_CMD_WR_SH_MEM_EP_EOS, 0, graph->port->id, iid); 1465 if (IS_ERR(pkt)) 1466 return PTR_ERR(pkt); 1467 1468 eos = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; 1469 1470 eos->policy = WR_SH_MEM_EP_EOS_POLICY_LAST; 1471 1472 return gpr_send_port_pkt(graph->port, pkt); 1473 } 1474 EXPORT_SYMBOL_GPL(audioreach_shared_memory_send_eos); 1475