1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020, Linaro Limited
3
4 #include <dt-bindings/soc/qcom,gpr.h>
5 #include <linux/delay.h>
6 #include <linux/jiffies.h>
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/of_platform.h>
11 #include <linux/sched.h>
12 #include <linux/slab.h>
13 #include <linux/soc/qcom/apr.h>
14 #include <linux/wait.h>
15 #include <sound/soc.h>
16 #include <sound/soc-dapm.h>
17 #include <sound/pcm.h>
18 #include "audioreach.h"
19 #include "q6apm.h"
20
21 /* Graph Management */
22 struct apm_graph_mgmt_cmd {
23 struct apm_module_param_data param_data;
24 uint32_t num_sub_graphs;
25 uint32_t sub_graph_id_list[];
26 } __packed;
27
28 #define APM_GRAPH_MGMT_PSIZE(p, n) ALIGN(struct_size(p, sub_graph_id_list, n), 8)
29
30 static struct q6apm *g_apm;
31
q6apm_send_cmd_sync(struct q6apm * apm,const struct gpr_pkt * pkt,uint32_t rsp_opcode)32 int q6apm_send_cmd_sync(struct q6apm *apm, const struct gpr_pkt *pkt,
33 uint32_t rsp_opcode)
34 {
35 gpr_device_t *gdev = apm->gdev;
36
37 return audioreach_send_cmd_sync(&gdev->dev, gdev, &apm->result, &apm->lock,
38 NULL, &apm->wait, pkt, rsp_opcode);
39 }
40
q6apm_get_audioreach_graph(struct q6apm * apm,uint32_t graph_id)41 static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, uint32_t graph_id)
42 {
43 struct audioreach_graph_info *info;
44 struct audioreach_graph *graph;
45 int id;
46
47 mutex_lock(&apm->lock);
48 graph = idr_find(&apm->graph_idr, graph_id);
49 mutex_unlock(&apm->lock);
50
51 if (graph) {
52 kref_get(&graph->refcount);
53 return graph;
54 }
55
56 info = idr_find(&apm->graph_info_idr, graph_id);
57
58 if (!info)
59 return ERR_PTR(-ENODEV);
60
61 graph = kzalloc_obj(*graph);
62 if (!graph)
63 return ERR_PTR(-ENOMEM);
64
65 graph->apm = apm;
66 graph->info = info;
67 graph->id = graph_id;
68
69 graph->graph = audioreach_alloc_graph_pkt(apm, info);
70 if (IS_ERR(graph->graph)) {
71 void *err = graph->graph;
72
73 kfree(graph);
74 return ERR_CAST(err);
75 }
76
77 mutex_lock(&apm->lock);
78 id = idr_alloc(&apm->graph_idr, graph, graph_id, graph_id + 1, GFP_KERNEL);
79 if (id < 0) {
80 dev_err(apm->dev, "Unable to allocate graph id (%d)\n", graph_id);
81 kfree(graph->graph);
82 kfree(graph);
83 mutex_unlock(&apm->lock);
84 return ERR_PTR(id);
85 }
86 mutex_unlock(&apm->lock);
87
88 kref_init(&graph->refcount);
89
90 q6apm_send_cmd_sync(apm, graph->graph, 0);
91
92 return graph;
93 }
94
audioreach_graph_mgmt_cmd(struct audioreach_graph * graph,uint32_t opcode)95 static int audioreach_graph_mgmt_cmd(struct audioreach_graph *graph, uint32_t opcode)
96 {
97 struct audioreach_graph_info *info = graph->info;
98 int num_sub_graphs = info->num_sub_graphs;
99 struct apm_module_param_data *param_data;
100 struct apm_graph_mgmt_cmd *mgmt_cmd;
101 struct audioreach_sub_graph *sg;
102 struct q6apm *apm = graph->apm;
103 int i = 0, payload_size = APM_GRAPH_MGMT_PSIZE(mgmt_cmd, num_sub_graphs);
104
105 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, opcode, 0);
106 if (IS_ERR(pkt))
107 return PTR_ERR(pkt);
108
109 mgmt_cmd = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
110
111 mgmt_cmd->num_sub_graphs = num_sub_graphs;
112
113 param_data = &mgmt_cmd->param_data;
114 param_data->module_instance_id = APM_MODULE_INSTANCE_ID;
115 param_data->param_id = APM_PARAM_ID_SUB_GRAPH_LIST;
116 param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
117
118 list_for_each_entry(sg, &info->sg_list, node)
119 mgmt_cmd->sub_graph_id_list[i++] = sg->sub_graph_id;
120
121 return q6apm_send_cmd_sync(apm, pkt, 0);
122 }
123
q6apm_put_audioreach_graph(struct kref * ref)124 static void q6apm_put_audioreach_graph(struct kref *ref)
125 {
126 struct audioreach_graph *graph;
127 struct q6apm *apm;
128
129 graph = container_of(ref, struct audioreach_graph, refcount);
130 apm = graph->apm;
131
132 audioreach_graph_mgmt_cmd(graph, APM_CMD_GRAPH_CLOSE);
133
134 mutex_lock(&apm->lock);
135 graph = idr_remove(&apm->graph_idr, graph->id);
136 mutex_unlock(&apm->lock);
137
138 kfree(graph->graph);
139 kfree(graph);
140 }
141
142
q6apm_get_apm_state(struct q6apm * apm)143 static int q6apm_get_apm_state(struct q6apm *apm)
144 {
145 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(0,
146 APM_CMD_GET_SPF_STATE, 0);
147 if (IS_ERR(pkt))
148 return PTR_ERR(pkt);
149
150 q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_GET_SPF_STATE);
151
152 return apm->state;
153 }
154
q6apm_is_adsp_ready(void)155 bool q6apm_is_adsp_ready(void)
156 {
157 if (g_apm)
158 return q6apm_get_apm_state(g_apm);
159
160 return false;
161 }
162 EXPORT_SYMBOL_GPL(q6apm_is_adsp_ready);
163
__q6apm_find_module_by_mid(struct q6apm * apm,struct audioreach_graph_info * info,uint32_t mid)164 static struct audioreach_module *__q6apm_find_module_by_mid(struct q6apm *apm,
165 struct audioreach_graph_info *info,
166 uint32_t mid)
167 {
168 struct audioreach_container *container;
169 struct audioreach_sub_graph *sgs;
170 struct audioreach_module *module;
171
172 list_for_each_entry(sgs, &info->sg_list, node) {
173 list_for_each_entry(container, &sgs->container_list, node) {
174 list_for_each_entry(module, &container->modules_list, node) {
175 if (mid == module->module_id)
176 return module;
177 }
178 }
179 }
180
181 return NULL;
182 }
183
q6apm_graph_media_format_shmem(struct q6apm_graph * graph,struct audioreach_module_config * cfg)184 int q6apm_graph_media_format_shmem(struct q6apm_graph *graph,
185 struct audioreach_module_config *cfg)
186 {
187 struct audioreach_module *module;
188
189 if (cfg->direction == SNDRV_PCM_STREAM_CAPTURE)
190 module = q6apm_find_module_by_mid(graph, MODULE_ID_RD_SHARED_MEM_EP);
191 else
192 module = q6apm_find_module_by_mid(graph, MODULE_ID_WR_SHARED_MEM_EP);
193
194 if (!module)
195 return -ENODEV;
196
197 audioreach_set_media_format(graph, module, cfg);
198
199 return 0;
200
201 }
202 EXPORT_SYMBOL_GPL(q6apm_graph_media_format_shmem);
203
q6apm_map_memory_fixed_region(struct device * dev,unsigned int graph_id,phys_addr_t phys,size_t sz)204 int q6apm_map_memory_fixed_region(struct device *dev, unsigned int graph_id, phys_addr_t phys,
205 size_t sz)
206 {
207 struct audioreach_graph_info *info;
208 struct q6apm *apm = dev_get_drvdata(dev->parent);
209 struct apm_shared_map_region_payload *mregions;
210 struct apm_cmd_shared_mem_map_regions *cmd;
211 int payload_size = sizeof(*cmd) + (sizeof(*mregions));
212 uint32_t buf_sz;
213 void *p;
214 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size,
215 APM_CMD_SHARED_MEM_MAP_REGIONS, graph_id);
216 if (IS_ERR(pkt))
217 return PTR_ERR(pkt);
218
219 info = idr_find(&apm->graph_info_idr, graph_id);
220 if (!info)
221 return -ENODEV;
222
223 if (info->mem_map_handle)
224 return 0;
225
226 /* DSP expects size should be aligned to 4K */
227 buf_sz = ALIGN(sz, 4096);
228
229 p = (void *)pkt + GPR_HDR_SIZE;
230 cmd = p;
231 cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL;
232 cmd->num_regions = 1;
233 cmd->property_flag = 0x0;
234
235 mregions = p + sizeof(*cmd);
236
237 mregions->shm_addr_lsw = lower_32_bits(phys);
238 mregions->shm_addr_msw = upper_32_bits(phys);
239 mregions->mem_size_bytes = buf_sz;
240
241 return q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS);
242 }
243 EXPORT_SYMBOL_GPL(q6apm_map_memory_fixed_region);
244
q6apm_alloc_fragments(struct q6apm_graph * graph,unsigned int dir,phys_addr_t phys,size_t period_sz,unsigned int periods)245 int q6apm_alloc_fragments(struct q6apm_graph *graph, unsigned int dir, phys_addr_t phys,
246 size_t period_sz, unsigned int periods)
247 {
248 struct audioreach_graph_data *data;
249 struct audio_buffer *buf;
250 int cnt;
251
252 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
253 data = &graph->rx_data;
254 else
255 data = &graph->tx_data;
256
257 mutex_lock(&graph->lock);
258
259 data->dsp_buf = 0;
260
261 if (data->buf) {
262 mutex_unlock(&graph->lock);
263 return 0;
264 }
265
266 buf = kzalloc_objs(struct audio_buffer, periods);
267 if (!buf) {
268 mutex_unlock(&graph->lock);
269 return -ENOMEM;
270 }
271
272 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
273 data = &graph->rx_data;
274 else
275 data = &graph->tx_data;
276
277 data->buf = buf;
278
279 buf[0].phys = phys;
280 buf[0].size = period_sz;
281
282 for (cnt = 1; cnt < periods; cnt++) {
283 if (period_sz > 0) {
284 buf[cnt].phys = buf[0].phys + (cnt * period_sz);
285 buf[cnt].size = period_sz;
286 }
287 }
288 data->num_periods = periods;
289
290 mutex_unlock(&graph->lock);
291
292 return 0;
293 }
294 EXPORT_SYMBOL_GPL(q6apm_alloc_fragments);
295
q6apm_unmap_memory_fixed_region(struct device * dev,unsigned int graph_id)296 int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id)
297 {
298 struct apm_cmd_shared_mem_unmap_regions *cmd;
299 struct q6apm *apm = dev_get_drvdata(dev->parent);
300 struct audioreach_graph_info *info;
301 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(sizeof(*cmd),
302 APM_CMD_SHARED_MEM_UNMAP_REGIONS, graph_id);
303 if (IS_ERR(pkt))
304 return PTR_ERR(pkt);
305
306 info = idr_find(&apm->graph_info_idr, graph_id);
307 if (!info)
308 return -ENODEV;
309
310 if (!info->mem_map_handle)
311 return 0;
312
313 cmd = (void *)pkt + GPR_HDR_SIZE;
314 cmd->mem_map_handle = info->mem_map_handle;
315
316 return q6apm_send_cmd_sync(apm, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS);
317 }
318 EXPORT_SYMBOL_GPL(q6apm_unmap_memory_fixed_region);
319
q6apm_free_fragments(struct q6apm_graph * graph,unsigned int dir)320 int q6apm_free_fragments(struct q6apm_graph *graph, unsigned int dir)
321 {
322 audioreach_graph_free_buf(graph);
323
324 return 0;
325 }
326 EXPORT_SYMBOL_GPL(q6apm_free_fragments);
327
q6apm_remove_initial_silence(struct device * dev,struct q6apm_graph * graph,uint32_t samples)328 int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
329 {
330 struct audioreach_module *module;
331
332 module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
333 if (!module)
334 return -ENODEV;
335
336 return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_INITIAL_SILENCE, samples);
337 }
338 EXPORT_SYMBOL_GPL(q6apm_remove_initial_silence);
339
q6apm_remove_trailing_silence(struct device * dev,struct q6apm_graph * graph,uint32_t samples)340 int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
341 {
342 struct audioreach_module *module;
343
344 module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
345 if (!module)
346 return -ENODEV;
347
348 return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_TRAILING_SILENCE, samples);
349 }
350 EXPORT_SYMBOL_GPL(q6apm_remove_trailing_silence);
351
q6apm_enable_compress_module(struct device * dev,struct q6apm_graph * graph,bool en)352 int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph, bool en)
353 {
354 struct audioreach_module *module;
355
356 module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
357 if (!module)
358 return -ENODEV;
359
360 return audioreach_send_u32_param(graph, module, PARAM_ID_MODULE_ENABLE, en);
361 }
362 EXPORT_SYMBOL_GPL(q6apm_enable_compress_module);
363
q6apm_set_real_module_id(struct device * dev,struct q6apm_graph * graph,uint32_t codec_id)364 int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph,
365 uint32_t codec_id)
366 {
367 struct audioreach_module *module;
368 uint32_t module_id;
369
370 module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
371 if (!module)
372 return -ENODEV;
373
374 switch (codec_id) {
375 case SND_AUDIOCODEC_MP3:
376 module_id = MODULE_ID_MP3_DECODE;
377 break;
378 case SND_AUDIOCODEC_AAC:
379 module_id = MODULE_ID_AAC_DEC;
380 break;
381 case SND_AUDIOCODEC_FLAC:
382 module_id = MODULE_ID_FLAC_DEC;
383 break;
384 case SND_AUDIOCODEC_OPUS_RAW:
385 module_id = MODULE_ID_OPUS_DEC;
386 break;
387 default:
388 return -EINVAL;
389 }
390
391 return audioreach_send_u32_param(graph, module, PARAM_ID_REAL_MODULE_ID,
392 module_id);
393 }
394 EXPORT_SYMBOL_GPL(q6apm_set_real_module_id);
395
q6apm_graph_media_format_pcm(struct q6apm_graph * graph,struct audioreach_module_config * cfg)396 int q6apm_graph_media_format_pcm(struct q6apm_graph *graph, struct audioreach_module_config *cfg)
397 {
398 struct audioreach_graph_info *info = graph->info;
399 struct audioreach_sub_graph *sgs;
400 struct audioreach_container *container;
401 struct audioreach_module *module;
402
403 list_for_each_entry(sgs, &info->sg_list, node) {
404 list_for_each_entry(container, &sgs->container_list, node) {
405 list_for_each_entry(module, &container->modules_list, node) {
406 if ((module->module_id == MODULE_ID_WR_SHARED_MEM_EP) ||
407 (module->module_id == MODULE_ID_RD_SHARED_MEM_EP))
408 continue;
409
410 audioreach_set_media_format(graph, module, cfg);
411 }
412 }
413 }
414
415 return 0;
416
417 }
418 EXPORT_SYMBOL_GPL(q6apm_graph_media_format_pcm);
419
q6apm_graph_get_tx_shmem_module_iid(struct q6apm_graph * graph)420 static int q6apm_graph_get_tx_shmem_module_iid(struct q6apm_graph *graph)
421 {
422 struct audioreach_module *module;
423
424 module = q6apm_find_module_by_mid(graph, MODULE_ID_RD_SHARED_MEM_EP);
425 if (!module)
426 return -ENODEV;
427
428 return module->instance_id;
429
430 }
431
q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph * graph)432 int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph)
433 {
434 struct audioreach_module *module;
435
436 module = q6apm_find_module_by_mid(graph, MODULE_ID_WR_SHARED_MEM_EP);
437 if (!module)
438 return -ENODEV;
439
440 return module->instance_id;
441
442 }
443 EXPORT_SYMBOL_GPL(q6apm_graph_get_rx_shmem_module_iid);
444
q6apm_write_async(struct q6apm_graph * graph,uint32_t len,uint32_t msw_ts,uint32_t lsw_ts,uint32_t wflags)445 int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
446 uint32_t lsw_ts, uint32_t wflags)
447 {
448 struct apm_data_cmd_wr_sh_mem_ep_data_buffer_v2 *write_buffer;
449 struct audio_buffer *ab;
450
451 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*write_buffer),
452 DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2,
453 graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT),
454 graph->port->id, graph->shm_iid);
455 if (IS_ERR(pkt))
456 return PTR_ERR(pkt);
457
458 write_buffer = (void *)pkt + GPR_HDR_SIZE;
459
460 mutex_lock(&graph->lock);
461 ab = &graph->rx_data.buf[graph->rx_data.dsp_buf];
462
463 write_buffer->buf_addr_lsw = lower_32_bits(ab->phys);
464 write_buffer->buf_addr_msw = upper_32_bits(ab->phys);
465 write_buffer->buf_size = len;
466 write_buffer->timestamp_lsw = lsw_ts;
467 write_buffer->timestamp_msw = msw_ts;
468 write_buffer->mem_map_handle = graph->info->mem_map_handle;
469 write_buffer->flags = wflags;
470
471 graph->rx_data.dsp_buf++;
472
473 if (graph->rx_data.dsp_buf >= graph->rx_data.num_periods)
474 graph->rx_data.dsp_buf = 0;
475
476 mutex_unlock(&graph->lock);
477
478 return gpr_send_port_pkt(graph->port, pkt);
479 }
480 EXPORT_SYMBOL_GPL(q6apm_write_async);
481
q6apm_read(struct q6apm_graph * graph)482 int q6apm_read(struct q6apm_graph *graph)
483 {
484 struct data_cmd_rd_sh_mem_ep_data_buffer_v2 *read_buffer;
485 struct audioreach_graph_data *port;
486 struct audio_buffer *ab;
487
488 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*read_buffer),
489 DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2,
490 graph->tx_data.dsp_buf, graph->port->id, graph->shm_iid);
491 if (IS_ERR(pkt))
492 return PTR_ERR(pkt);
493
494 read_buffer = (void *)pkt + GPR_HDR_SIZE;
495
496 mutex_lock(&graph->lock);
497 port = &graph->tx_data;
498 ab = &port->buf[port->dsp_buf];
499
500 read_buffer->buf_addr_lsw = lower_32_bits(ab->phys);
501 read_buffer->buf_addr_msw = upper_32_bits(ab->phys);
502 read_buffer->mem_map_handle = graph->info->mem_map_handle;
503 read_buffer->buf_size = ab->size;
504
505 port->dsp_buf++;
506
507 if (port->dsp_buf >= port->num_periods)
508 port->dsp_buf = 0;
509
510 mutex_unlock(&graph->lock);
511
512 return gpr_send_port_pkt(graph->port, pkt);
513 }
514 EXPORT_SYMBOL_GPL(q6apm_read);
515
q6apm_get_hw_pointer(struct q6apm_graph * graph,int dir)516 int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir)
517 {
518 struct audioreach_graph_data *data;
519
520 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
521 data = &graph->rx_data;
522 else
523 data = &graph->tx_data;
524
525 return (int)atomic_read(&data->hw_ptr);
526 }
527 EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer);
528
graph_callback(const struct gpr_resp_pkt * data,void * priv,int op)529 static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
530 {
531 struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done;
532 struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2 *done;
533 const struct gpr_ibasic_rsp_result_t *result;
534 struct q6apm_graph *graph = priv;
535 const struct gpr_hdr *hdr = &data->hdr;
536 struct device *dev = graph->dev;
537 uint32_t client_event;
538 phys_addr_t phys;
539 int token;
540
541 result = data->payload;
542
543 switch (hdr->opcode) {
544 case DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2:
545 if (!graph->ar_graph)
546 break;
547 client_event = APM_CLIENT_EVENT_DATA_WRITE_DONE;
548 mutex_lock(&graph->lock);
549 token = hdr->token & APM_WRITE_TOKEN_MASK;
550
551 done = data->payload;
552 phys = graph->rx_data.buf[token].phys;
553 mutex_unlock(&graph->lock);
554 /* token numbering starts at 0 */
555 atomic_set(&graph->rx_data.hw_ptr, token + 1);
556 if (lower_32_bits(phys) == done->buf_addr_lsw &&
557 upper_32_bits(phys) == done->buf_addr_msw) {
558 graph->result.opcode = hdr->opcode;
559 graph->result.status = done->status;
560 if (graph->cb)
561 graph->cb(client_event, hdr->token, data->payload, graph->priv);
562 } else {
563 dev_err(dev, "WR BUFF Unexpected addr %08x-%08x\n", done->buf_addr_lsw,
564 done->buf_addr_msw);
565 }
566
567 break;
568 case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2:
569 if (!graph->ar_graph)
570 break;
571 client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
572 mutex_lock(&graph->lock);
573 rd_done = data->payload;
574 phys = graph->tx_data.buf[hdr->token].phys;
575 mutex_unlock(&graph->lock);
576 /* token numbering starts at 0 */
577 atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
578
579 if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
580 lower_32_bits(phys) == rd_done->buf_addr_lsw) {
581 graph->result.opcode = hdr->opcode;
582 graph->result.status = rd_done->status;
583 if (graph->cb)
584 graph->cb(client_event, hdr->token, data->payload, graph->priv);
585 } else {
586 dev_err(dev, "RD BUFF Unexpected addr %08x-%08x\n", rd_done->buf_addr_lsw,
587 rd_done->buf_addr_msw);
588 }
589 break;
590 case DATA_CMD_WR_SH_MEM_EP_EOS_RENDERED:
591 client_event = APM_CLIENT_EVENT_CMD_EOS_DONE;
592 if (graph->cb)
593 graph->cb(client_event, hdr->token, data->payload, graph->priv);
594 break;
595 case GPR_BASIC_RSP_RESULT:
596 switch (result->opcode) {
597 case APM_CMD_SHARED_MEM_MAP_REGIONS:
598 case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT:
599 case APM_CMD_SET_CFG:
600 graph->result.opcode = result->opcode;
601 graph->result.status = result->status;
602 if (result->status)
603 dev_err(dev, "Error (%d) Processing 0x%08x cmd\n",
604 result->status, result->opcode);
605 wake_up(&graph->cmd_wait);
606 break;
607 default:
608 break;
609 }
610 break;
611 default:
612 break;
613 }
614 return 0;
615 }
616
q6apm_graph_open(struct device * dev,q6apm_cb cb,void * priv,int graph_id,int dir)617 struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb,
618 void *priv, int graph_id, int dir)
619 {
620 struct q6apm *apm = dev_get_drvdata(dev->parent);
621 struct audioreach_graph *ar_graph;
622 struct q6apm_graph *graph;
623 int ret;
624
625 ar_graph = q6apm_get_audioreach_graph(apm, graph_id);
626 if (IS_ERR(ar_graph)) {
627 dev_err(dev, "No graph found with id %d\n", graph_id);
628 return ERR_CAST(ar_graph);
629 }
630
631 graph = kzalloc_obj(*graph);
632 if (!graph) {
633 ret = -ENOMEM;
634 goto put_ar_graph;
635 }
636
637 graph->apm = apm;
638 graph->priv = priv;
639 graph->cb = cb;
640 graph->info = ar_graph->info;
641 graph->ar_graph = ar_graph;
642 graph->id = ar_graph->id;
643 graph->dev = dev;
644
645 if (dir == SNDRV_PCM_STREAM_PLAYBACK)
646 graph->shm_iid = q6apm_graph_get_rx_shmem_module_iid(graph);
647 else
648 graph->shm_iid = q6apm_graph_get_tx_shmem_module_iid(graph);
649
650
651 mutex_init(&graph->lock);
652 init_waitqueue_head(&graph->cmd_wait);
653
654 graph->port = gpr_alloc_port(apm->gdev, dev, graph_callback, graph);
655 if (IS_ERR(graph->port)) {
656 ret = PTR_ERR(graph->port);
657 goto free_graph;
658 }
659
660 return graph;
661
662 free_graph:
663 kfree(graph);
664 put_ar_graph:
665 kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
666 return ERR_PTR(ret);
667 }
668 EXPORT_SYMBOL_GPL(q6apm_graph_open);
669
q6apm_graph_close(struct q6apm_graph * graph)670 int q6apm_graph_close(struct q6apm_graph *graph)
671 {
672 struct audioreach_graph *ar_graph = graph->ar_graph;
673
674 graph->ar_graph = NULL;
675 kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
676 gpr_free_port(graph->port);
677 kfree(graph);
678
679 return 0;
680 }
681 EXPORT_SYMBOL_GPL(q6apm_graph_close);
682
q6apm_graph_prepare(struct q6apm_graph * graph)683 int q6apm_graph_prepare(struct q6apm_graph *graph)
684 {
685 return audioreach_graph_mgmt_cmd(graph->ar_graph, APM_CMD_GRAPH_PREPARE);
686 }
687 EXPORT_SYMBOL_GPL(q6apm_graph_prepare);
688
q6apm_graph_start(struct q6apm_graph * graph)689 int q6apm_graph_start(struct q6apm_graph *graph)
690 {
691 struct audioreach_graph *ar_graph = graph->ar_graph;
692 int ret = 0;
693
694 if (ar_graph->start_count == 0)
695 ret = audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_START);
696
697 ar_graph->start_count++;
698
699 return ret;
700 }
701 EXPORT_SYMBOL_GPL(q6apm_graph_start);
702
q6apm_graph_stop(struct q6apm_graph * graph)703 int q6apm_graph_stop(struct q6apm_graph *graph)
704 {
705 struct audioreach_graph *ar_graph = graph->ar_graph;
706
707 if (--ar_graph->start_count > 0)
708 return 0;
709
710 return audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_STOP);
711 }
712 EXPORT_SYMBOL_GPL(q6apm_graph_stop);
713
q6apm_graph_flush(struct q6apm_graph * graph)714 int q6apm_graph_flush(struct q6apm_graph *graph)
715 {
716 return audioreach_graph_mgmt_cmd(graph->ar_graph, APM_CMD_GRAPH_FLUSH);
717 }
718 EXPORT_SYMBOL_GPL(q6apm_graph_flush);
719
q6apm_audio_probe(struct snd_soc_component * component)720 static int q6apm_audio_probe(struct snd_soc_component *component)
721 {
722 return audioreach_tplg_init(component);
723 }
724
q6apm_audio_remove(struct snd_soc_component * component)725 static void q6apm_audio_remove(struct snd_soc_component *component)
726 {
727 /* remove topology */
728 snd_soc_tplg_component_remove(component);
729 }
730
731 #define APM_AUDIO_DRV_NAME "q6apm-audio"
732
733 static const struct snd_soc_component_driver q6apm_audio_component = {
734 .name = APM_AUDIO_DRV_NAME,
735 .probe = q6apm_audio_probe,
736 .remove = q6apm_audio_remove,
737 .remove_order = SND_SOC_COMP_ORDER_LAST,
738 };
739
apm_probe(gpr_device_t * gdev)740 static int apm_probe(gpr_device_t *gdev)
741 {
742 struct device *dev = &gdev->dev;
743 struct q6apm *apm;
744 int ret;
745
746 apm = devm_kzalloc(dev, sizeof(*apm), GFP_KERNEL);
747 if (!apm)
748 return -ENOMEM;
749
750 dev_set_drvdata(dev, apm);
751
752 mutex_init(&apm->lock);
753 apm->dev = dev;
754 apm->gdev = gdev;
755 init_waitqueue_head(&apm->wait);
756
757 INIT_LIST_HEAD(&apm->widget_list);
758 idr_init(&apm->graph_idr);
759 idr_init(&apm->graph_info_idr);
760 idr_init(&apm->sub_graphs_idr);
761 idr_init(&apm->containers_idr);
762
763 idr_init(&apm->modules_idr);
764
765 g_apm = apm;
766
767 q6apm_get_apm_state(apm);
768
769 ret = snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0);
770 if (ret < 0) {
771 dev_err(dev, "failed to register q6apm: %d\n", ret);
772 return ret;
773 }
774
775 ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
776 if (ret)
777 snd_soc_unregister_component(dev);
778
779 return ret;
780 }
781
apm_remove(gpr_device_t * gdev)782 static void apm_remove(gpr_device_t *gdev)
783 {
784 of_platform_depopulate(&gdev->dev);
785 snd_soc_unregister_component(&gdev->dev);
786 }
787
q6apm_find_module_by_mid(struct q6apm_graph * graph,uint32_t mid)788 struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, uint32_t mid)
789 {
790 struct audioreach_graph_info *info = graph->info;
791 struct q6apm *apm = graph->apm;
792
793 return __q6apm_find_module_by_mid(apm, info, mid);
794
795 }
796
apm_callback(const struct gpr_resp_pkt * data,void * priv,int op)797 static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
798 {
799 gpr_device_t *gdev = priv;
800 struct audioreach_graph_info *info;
801 struct q6apm *apm = dev_get_drvdata(&gdev->dev);
802 struct apm_cmd_rsp_shared_mem_map_regions *rsp;
803 struct device *dev = &gdev->dev;
804 struct gpr_ibasic_rsp_result_t *result;
805 const struct gpr_hdr *hdr = &data->hdr;
806
807 result = data->payload;
808
809 switch (hdr->opcode) {
810 case APM_CMD_RSP_GET_SPF_STATE:
811 apm->result.opcode = hdr->opcode;
812 apm->result.status = 0;
813 /* First word of result it state */
814 apm->state = result->opcode;
815 wake_up(&apm->wait);
816 break;
817 case GPR_BASIC_RSP_RESULT:
818 switch (result->opcode) {
819 case APM_CMD_SHARED_MEM_MAP_REGIONS:
820 case APM_CMD_GRAPH_START:
821 case APM_CMD_GRAPH_OPEN:
822 case APM_CMD_GRAPH_PREPARE:
823 case APM_CMD_GRAPH_CLOSE:
824 case APM_CMD_GRAPH_FLUSH:
825 case APM_CMD_GRAPH_STOP:
826 case APM_CMD_SET_CFG:
827 apm->result.opcode = result->opcode;
828 apm->result.status = result->status;
829 if (result->status)
830 dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
831 result->opcode);
832 wake_up(&apm->wait);
833 break;
834 case APM_CMD_SHARED_MEM_UNMAP_REGIONS:
835 apm->result.opcode = hdr->opcode;
836 apm->result.status = 0;
837 rsp = data->payload;
838
839 info = idr_find(&apm->graph_info_idr, hdr->token);
840 if (info)
841 info->mem_map_handle = 0;
842 else
843 dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
844 result->opcode);
845
846 wake_up(&apm->wait);
847 break;
848 default:
849 break;
850 }
851 break;
852 case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS:
853 apm->result.opcode = hdr->opcode;
854 apm->result.status = 0;
855 rsp = data->payload;
856
857 info = idr_find(&apm->graph_info_idr, hdr->token);
858 if (info)
859 info->mem_map_handle = rsp->mem_map_handle;
860 else
861 dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
862 result->opcode);
863
864 wake_up(&apm->wait);
865 break;
866 default:
867 break;
868 }
869
870 return 0;
871 }
872
873 #ifdef CONFIG_OF
874 static const struct of_device_id apm_device_id[] = {
875 { .compatible = "qcom,q6apm" },
876 {},
877 };
878 MODULE_DEVICE_TABLE(of, apm_device_id);
879 #endif
880
881 static gpr_driver_t apm_driver = {
882 .probe = apm_probe,
883 .remove = apm_remove,
884 .gpr_callback = apm_callback,
885 .driver = {
886 .name = "qcom-apm",
887 .of_match_table = of_match_ptr(apm_device_id),
888 },
889 };
890
891 module_gpr_driver(apm_driver);
892 MODULE_DESCRIPTION("Audio Process Manager");
893 MODULE_LICENSE("GPL");
894