xref: /linux/sound/soc/qcom/qdsp6/q6apm.c (revision 2e9261761b35f0b67b7487688cd1365f535be0b3)
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 
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 
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 
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 
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 
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 
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 
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 
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_SH_MEM_PUSH_MODE);
191 		if (!module)
192 			module = q6apm_find_module_by_mid(graph, MODULE_ID_RD_SHARED_MEM_EP);
193 	} else {
194 		module = q6apm_find_module_by_mid(graph, MODULE_ID_SH_MEM_PULL_MODE);
195 		if (!module)
196 			module = q6apm_find_module_by_mid(graph, MODULE_ID_WR_SHARED_MEM_EP);
197 	}
198 
199 	if (!module) {
200 		dev_err(graph->dev, "No SHMEM module found in graph\n");
201 		return -ENODEV;
202 	}
203 
204 	return audioreach_set_media_format(graph, module, cfg);
205 }
206 EXPORT_SYMBOL_GPL(q6apm_graph_media_format_shmem);
207 
208 static int __q6apm_map_memory_fixed_region(struct device *dev, unsigned int graph_id,
209 					   phys_addr_t phys, size_t sz, bool is_pos_buf)
210 {
211 	struct audioreach_graph_info *info;
212 	struct q6apm *apm = dev_get_drvdata(dev->parent);
213 	struct apm_shared_map_region_payload *mregions;
214 	struct apm_cmd_shared_mem_map_regions *cmd;
215 	int payload_size = sizeof(*cmd) + (sizeof(*mregions));
216 	uint32_t buf_sz;
217 	void *p;
218 	uint32_t pos_mask = is_pos_buf ? APM_MMAP_TOKEN_MAP_TYPE_POS_BUF : 0;
219 	struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size,
220 					APM_CMD_SHARED_MEM_MAP_REGIONS, (graph_id | pos_mask));
221 
222 	if (IS_ERR(pkt))
223 		return PTR_ERR(pkt);
224 
225 	info = idr_find(&apm->graph_info_idr, graph_id);
226 	if (!info)
227 		return -ENODEV;
228 
229 	if (is_pos_buf) {
230 		if (info->pos_buf_mem_map_handle)
231 			return 0;
232 	} else {
233 		if (info->mem_map_handle)
234 			return 0;
235 	}
236 
237 	/* DSP expects size should be aligned to 4K */
238 	buf_sz = ALIGN(sz, 4096);
239 
240 	p = (void *)pkt + GPR_HDR_SIZE;
241 	cmd = p;
242 	cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL;
243 	cmd->num_regions = 1;
244 	if (is_pos_buf)
245 		cmd->property_flag = 0x2;
246 	else
247 		cmd->property_flag = 0x0;
248 
249 	mregions = p + sizeof(*cmd);
250 
251 	mregions->shm_addr_lsw = lower_32_bits(phys);
252 	mregions->shm_addr_msw = upper_32_bits(phys);
253 	mregions->mem_size_bytes = buf_sz;
254 
255 	return q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS);
256 }
257 
258 int q6apm_map_pos_buffer(struct device *dev, unsigned int graph_id, phys_addr_t phys, size_t sz)
259 {
260 	return __q6apm_map_memory_fixed_region(dev, graph_id, phys, sz, true);
261 }
262 EXPORT_SYMBOL_GPL(q6apm_map_pos_buffer);
263 
264 int q6apm_map_memory_fixed_region(struct device *dev, unsigned int graph_id,
265 				  phys_addr_t phys, size_t sz)
266 {
267 	return __q6apm_map_memory_fixed_region(dev, graph_id, phys, sz, false);
268 }
269 EXPORT_SYMBOL_GPL(q6apm_map_memory_fixed_region);
270 
271 int q6apm_alloc_fragments(struct q6apm_graph *graph, unsigned int dir, phys_addr_t phys,
272 				size_t period_sz, unsigned int periods)
273 {
274 	struct audioreach_graph_data *data;
275 	struct audio_buffer *buf;
276 	int cnt;
277 
278 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
279 		data = &graph->rx_data;
280 	else
281 		data = &graph->tx_data;
282 
283 	mutex_lock(&graph->lock);
284 
285 	data->dsp_buf = 0;
286 
287 	if (data->buf) {
288 		mutex_unlock(&graph->lock);
289 		return 0;
290 	}
291 
292 	buf = kzalloc_objs(struct audio_buffer, periods);
293 	if (!buf) {
294 		mutex_unlock(&graph->lock);
295 		return -ENOMEM;
296 	}
297 
298 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
299 		data = &graph->rx_data;
300 	else
301 		data = &graph->tx_data;
302 
303 	data->buf = buf;
304 
305 	buf[0].phys = phys;
306 	buf[0].size = period_sz;
307 
308 	for (cnt = 1; cnt < periods; cnt++) {
309 		if (period_sz > 0) {
310 			buf[cnt].phys = buf[0].phys + (cnt * period_sz);
311 			buf[cnt].size = period_sz;
312 		}
313 	}
314 	data->num_periods = periods;
315 
316 	mutex_unlock(&graph->lock);
317 
318 	return 0;
319 }
320 EXPORT_SYMBOL_GPL(q6apm_alloc_fragments);
321 
322 static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id,
323 					     bool is_pos_buf)
324 {
325 	struct apm_cmd_shared_mem_unmap_regions *cmd;
326 	struct q6apm *apm = dev_get_drvdata(dev->parent);
327 	struct audioreach_graph_info *info;
328 	uint32_t mem_map_handle;
329 	struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(sizeof(*cmd),
330 						APM_CMD_SHARED_MEM_UNMAP_REGIONS, graph_id);
331 	if (IS_ERR(pkt))
332 		return PTR_ERR(pkt);
333 
334 	info = idr_find(&apm->graph_info_idr, graph_id);
335 	if (!info)
336 		return -ENODEV;
337 
338 	if (is_pos_buf) {
339 		if (!info->pos_buf_mem_map_handle)
340 			return 0;
341 		mem_map_handle = info->pos_buf_mem_map_handle;
342 	} else {
343 
344 		if (!info->mem_map_handle)
345 			return 0;
346 		mem_map_handle = info->mem_map_handle;
347 	}
348 
349 	cmd = (void *)pkt + GPR_HDR_SIZE;
350 	cmd->mem_map_handle = mem_map_handle;
351 
352 	return q6apm_send_cmd_sync(apm, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS);
353 }
354 
355 int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id)
356 {
357 	return __q6apm_unmap_memory_fixed_region(dev, graph_id, false);
358 }
359 EXPORT_SYMBOL_GPL(q6apm_unmap_memory_fixed_region);
360 
361 int q6apm_unmap_pos_buffer(struct device *dev, unsigned int graph_id)
362 {
363 	return __q6apm_unmap_memory_fixed_region(dev, graph_id, true);
364 }
365 EXPORT_SYMBOL_GPL(q6apm_unmap_pos_buffer);
366 
367 int q6apm_free_fragments(struct q6apm_graph *graph, unsigned int dir)
368 {
369 	audioreach_graph_free_buf(graph);
370 
371 	return 0;
372 }
373 EXPORT_SYMBOL_GPL(q6apm_free_fragments);
374 
375 int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
376 {
377 	struct audioreach_module *module;
378 
379 	module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
380 	if (!module)
381 		return -ENODEV;
382 
383 	return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_INITIAL_SILENCE, samples);
384 }
385 EXPORT_SYMBOL_GPL(q6apm_remove_initial_silence);
386 
387 int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples)
388 {
389 	struct audioreach_module *module;
390 
391 	module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
392 	if (!module)
393 		return -ENODEV;
394 
395 	return audioreach_send_u32_param(graph, module, PARAM_ID_REMOVE_TRAILING_SILENCE, samples);
396 }
397 EXPORT_SYMBOL_GPL(q6apm_remove_trailing_silence);
398 
399 int q6apm_enable_compress_module(struct device *dev, struct q6apm_graph *graph, bool en)
400 {
401 	struct audioreach_module *module;
402 
403 	module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
404 	if (!module)
405 		return -ENODEV;
406 
407 	return audioreach_send_u32_param(graph, module, PARAM_ID_MODULE_ENABLE, en);
408 }
409 EXPORT_SYMBOL_GPL(q6apm_enable_compress_module);
410 
411 int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph,
412 			     uint32_t codec_id)
413 {
414 	struct audioreach_module *module;
415 	uint32_t module_id;
416 
417 	module = q6apm_find_module_by_mid(graph, MODULE_ID_PLACEHOLDER_DECODER);
418 	if (!module)
419 		return -ENODEV;
420 
421 	switch (codec_id) {
422 	case SND_AUDIOCODEC_MP3:
423 		module_id = MODULE_ID_MP3_DECODE;
424 		break;
425 	case SND_AUDIOCODEC_AAC:
426 		module_id = MODULE_ID_AAC_DEC;
427 		break;
428 	case SND_AUDIOCODEC_FLAC:
429 		module_id = MODULE_ID_FLAC_DEC;
430 		break;
431 	case SND_AUDIOCODEC_OPUS_RAW:
432 		module_id = MODULE_ID_OPUS_DEC;
433 		break;
434 	default:
435 		return -EINVAL;
436 	}
437 
438 	return audioreach_send_u32_param(graph, module, PARAM_ID_REAL_MODULE_ID,
439 					 module_id);
440 }
441 EXPORT_SYMBOL_GPL(q6apm_set_real_module_id);
442 
443 int q6apm_graph_media_format_pcm(struct q6apm_graph *graph, struct audioreach_module_config *cfg)
444 {
445 	struct audioreach_graph_info *info = graph->info;
446 	struct audioreach_sub_graph *sgs;
447 	struct audioreach_container *container;
448 	struct audioreach_module *module;
449 	int ret;
450 
451 	list_for_each_entry(sgs, &info->sg_list, node) {
452 		list_for_each_entry(container, &sgs->container_list, node) {
453 			list_for_each_entry(module, &container->modules_list, node) {
454 				if ((module->module_id == MODULE_ID_WR_SHARED_MEM_EP) ||
455 					(module->module_id == MODULE_ID_RD_SHARED_MEM_EP) ||
456 					(module->module_id == MODULE_ID_SH_MEM_PULL_MODE) ||
457 					(module->module_id == MODULE_ID_SH_MEM_PUSH_MODE))
458 					continue;
459 
460 				ret = audioreach_set_media_format(graph, module, cfg);
461 				if (ret)
462 					return ret;
463 			}
464 		}
465 	}
466 
467 	return 0;
468 
469 }
470 EXPORT_SYMBOL_GPL(q6apm_graph_media_format_pcm);
471 
472 int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts,
473 		      uint32_t lsw_ts, uint32_t wflags)
474 {
475 	struct apm_data_cmd_wr_sh_mem_ep_data_buffer_v2 *write_buffer;
476 	struct audio_buffer *ab;
477 
478 	struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*write_buffer),
479 					DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2,
480 					graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT),
481 					graph->port->id, graph->shm_iid);
482 	if (IS_ERR(pkt))
483 		return PTR_ERR(pkt);
484 
485 	write_buffer = (void *)pkt + GPR_HDR_SIZE;
486 
487 	mutex_lock(&graph->lock);
488 	ab = &graph->rx_data.buf[graph->rx_data.dsp_buf];
489 
490 	write_buffer->buf_addr_lsw = lower_32_bits(ab->phys);
491 	write_buffer->buf_addr_msw = upper_32_bits(ab->phys);
492 	write_buffer->buf_size = len;
493 	write_buffer->timestamp_lsw = lsw_ts;
494 	write_buffer->timestamp_msw = msw_ts;
495 	write_buffer->mem_map_handle = graph->info->mem_map_handle;
496 	write_buffer->flags = wflags;
497 
498 	graph->rx_data.dsp_buf++;
499 
500 	if (graph->rx_data.dsp_buf >= graph->rx_data.num_periods)
501 		graph->rx_data.dsp_buf = 0;
502 
503 	mutex_unlock(&graph->lock);
504 
505 	return gpr_send_port_pkt(graph->port, pkt);
506 }
507 EXPORT_SYMBOL_GPL(q6apm_write_async);
508 
509 int q6apm_read(struct q6apm_graph *graph)
510 {
511 	struct data_cmd_rd_sh_mem_ep_data_buffer_v2 *read_buffer;
512 	struct audioreach_graph_data *port;
513 	struct audio_buffer *ab;
514 
515 	struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*read_buffer),
516 					DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2,
517 					graph->tx_data.dsp_buf, graph->port->id, graph->shm_iid);
518 	if (IS_ERR(pkt))
519 		return PTR_ERR(pkt);
520 
521 	read_buffer = (void *)pkt + GPR_HDR_SIZE;
522 
523 	mutex_lock(&graph->lock);
524 	port = &graph->tx_data;
525 	ab = &port->buf[port->dsp_buf];
526 
527 	read_buffer->buf_addr_lsw = lower_32_bits(ab->phys);
528 	read_buffer->buf_addr_msw = upper_32_bits(ab->phys);
529 	read_buffer->mem_map_handle = graph->info->mem_map_handle;
530 	read_buffer->buf_size = ab->size;
531 
532 	port->dsp_buf++;
533 
534 	if (port->dsp_buf >= port->num_periods)
535 		port->dsp_buf = 0;
536 
537 	mutex_unlock(&graph->lock);
538 
539 	return gpr_send_port_pkt(graph->port, pkt);
540 }
541 EXPORT_SYMBOL_GPL(q6apm_read);
542 
543 int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir)
544 {
545 	struct audioreach_graph_data *data;
546 
547 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
548 		data = &graph->rx_data;
549 	else
550 		data = &graph->tx_data;
551 
552 	return (int)atomic_read(&data->hw_ptr);
553 }
554 EXPORT_SYMBOL_GPL(q6apm_get_hw_pointer);
555 
556 static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op)
557 {
558 	struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done;
559 	struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2 *done;
560 	struct apm_module_event *event;
561 	const struct gpr_ibasic_rsp_result_t *result;
562 	struct q6apm_graph *graph = priv;
563 	const struct gpr_hdr *hdr = &data->hdr;
564 	struct device *dev = graph->dev;
565 	uint32_t client_event;
566 	phys_addr_t phys;
567 	int token;
568 
569 	result = data->payload;
570 
571 	switch (hdr->opcode) {
572 	case APM_EVENT_MODULE_TO_CLIENT:
573 		event = data->payload;
574 		switch (event->event_id) {
575 		case EVENT_ID_SH_MEM_PULL_PUSH_MODE_WATERMARK:
576 			client_event = APM_CLIENT_EVENT_WATERMARK_EVENT;
577 			graph->cb(client_event, hdr->token, data->payload, graph->priv);
578 			break;
579 		}
580 
581 		break;
582 	case DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2:
583 		if (!graph->ar_graph)
584 			break;
585 		client_event = APM_CLIENT_EVENT_DATA_WRITE_DONE;
586 		mutex_lock(&graph->lock);
587 		token = hdr->token & APM_WRITE_TOKEN_MASK;
588 
589 		done = data->payload;
590 		if (!graph->rx_data.buf) {
591 			mutex_unlock(&graph->lock);
592 			break;
593 		}
594 		phys = graph->rx_data.buf[token].phys;
595 		mutex_unlock(&graph->lock);
596 		/* token numbering starts at 0 */
597 		atomic_set(&graph->rx_data.hw_ptr, token + 1);
598 		if (lower_32_bits(phys) == done->buf_addr_lsw &&
599 		    upper_32_bits(phys) == done->buf_addr_msw) {
600 			graph->result.opcode = hdr->opcode;
601 			graph->result.status = done->status;
602 			if (graph->cb)
603 				graph->cb(client_event, hdr->token, data->payload, graph->priv);
604 		} else {
605 			dev_err(dev, "WR BUFF Unexpected addr %08x-%08x\n", done->buf_addr_lsw,
606 				done->buf_addr_msw);
607 		}
608 
609 		break;
610 	case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2:
611 		if (!graph->ar_graph)
612 			break;
613 		client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
614 		mutex_lock(&graph->lock);
615 		rd_done = data->payload;
616 		if (!graph->tx_data.buf) {
617 			mutex_unlock(&graph->lock);
618 			break;
619 		}
620 		phys = graph->tx_data.buf[hdr->token].phys;
621 		mutex_unlock(&graph->lock);
622 		/* token numbering starts at 0 */
623 		atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
624 
625 		if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
626 		    lower_32_bits(phys) == rd_done->buf_addr_lsw) {
627 			graph->result.opcode = hdr->opcode;
628 			graph->result.status = rd_done->status;
629 			if (graph->cb)
630 				graph->cb(client_event, hdr->token, data->payload, graph->priv);
631 		} else {
632 			dev_err(dev, "RD BUFF Unexpected addr %08x-%08x\n", rd_done->buf_addr_lsw,
633 				rd_done->buf_addr_msw);
634 		}
635 		break;
636 	case DATA_CMD_WR_SH_MEM_EP_EOS_RENDERED:
637 		client_event = APM_CLIENT_EVENT_CMD_EOS_DONE;
638 		if (graph->cb)
639 			graph->cb(client_event, hdr->token, data->payload, graph->priv);
640 		break;
641 	case GPR_BASIC_RSP_RESULT:
642 		switch (result->opcode) {
643 		case APM_CMD_SHARED_MEM_MAP_REGIONS:
644 		case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT:
645 		case APM_CMD_REGISTER_MODULE_EVENTS:
646 		case APM_CMD_SET_CFG:
647 			graph->result.opcode = result->opcode;
648 			graph->result.status = result->status;
649 			if (result->status)
650 				dev_err(dev, "Error (%d) Processing 0x%08x cmd\n",
651 					result->status, result->opcode);
652 			wake_up(&graph->cmd_wait);
653 			break;
654 		default:
655 			break;
656 		}
657 		break;
658 	default:
659 		break;
660 	}
661 	return 0;
662 }
663 
664 int q6apm_register_watermark_event(struct q6apm_graph *graph, int water_mark_level_bytes,
665 				   int num_levels)
666 {
667 	return audioreach_shmem_register_event(graph, water_mark_level_bytes, num_levels);
668 }
669 EXPORT_SYMBOL_GPL(q6apm_register_watermark_event);
670 
671 int q6apm_push_pull_config(struct q6apm_graph *graph, phys_addr_t bphys,
672 			   phys_addr_t pphys, uint32_t size)
673 {
674 	struct audioreach_graph_info *info = graph->info;
675 
676 	return audioreach_setup_push_pull(graph, bphys, pphys, info->mem_map_handle,
677 					  info->pos_buf_mem_map_handle, size);
678 }
679 EXPORT_SYMBOL_GPL(q6apm_push_pull_config);
680 
681 bool q6apm_is_graph_in_push_pull_mode_from_id(struct device *dev, unsigned int graph_id, int dir)
682 {
683 	struct audioreach_graph_info *info;
684 	struct q6apm *apm = dev_get_drvdata(dev->parent);
685 	struct audioreach_module *module;
686 
687 	info = idr_find(&apm->graph_info_idr, graph_id);
688 	if (!info)
689 		return false;
690 
691 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
692 		module = __q6apm_find_module_by_mid(apm, info, MODULE_ID_SH_MEM_PULL_MODE);
693 	else
694 		module = __q6apm_find_module_by_mid(apm, info, MODULE_ID_SH_MEM_PUSH_MODE);
695 
696 	return !!module;
697 
698 }
699 EXPORT_SYMBOL_GPL(q6apm_is_graph_in_push_pull_mode_from_id);
700 
701 bool q6apm_is_graph_in_push_pull_mode(struct q6apm_graph *graph)
702 {
703 	return graph->info->is_push_pull_mode;
704 }
705 EXPORT_SYMBOL_GPL(q6apm_is_graph_in_push_pull_mode);
706 
707 static int q6apm_graph_get_module_iid(struct q6apm_graph *graph, uint32_t mid)
708 {
709 	struct audioreach_module *module;
710 
711 	module = q6apm_find_module_by_mid(graph, mid);
712 	if (!module)
713 		return -ENODEV;
714 
715 	return module->instance_id;
716 }
717 
718 struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb,
719 				     void *priv, int graph_id, int dir)
720 {
721 	struct q6apm *apm = dev_get_drvdata(dev->parent);
722 	struct audioreach_graph *ar_graph;
723 	struct q6apm_graph *graph;
724 	int ret, iid = 0;
725 
726 	ar_graph = q6apm_get_audioreach_graph(apm, graph_id);
727 	if (IS_ERR(ar_graph)) {
728 		dev_err(dev, "No graph found with id %d\n", graph_id);
729 		return ERR_CAST(ar_graph);
730 	}
731 
732 	graph = kzalloc_obj(*graph);
733 	if (!graph) {
734 		ret = -ENOMEM;
735 		goto put_ar_graph;
736 	}
737 
738 	graph->apm = apm;
739 	graph->priv = priv;
740 	graph->cb = cb;
741 	graph->info = ar_graph->info;
742 	graph->ar_graph = ar_graph;
743 	graph->id = ar_graph->id;
744 	graph->dev = dev;
745 
746 	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
747 		iid = q6apm_graph_get_module_iid(graph, MODULE_ID_SH_MEM_PULL_MODE);
748 		if (iid < 0)
749 			iid = q6apm_graph_get_module_iid(graph, MODULE_ID_WR_SHARED_MEM_EP);
750 		else
751 			graph->info->is_push_pull_mode = true;
752 
753 	} else {
754 		iid = q6apm_graph_get_module_iid(graph, MODULE_ID_SH_MEM_PUSH_MODE);
755 		if (iid < 0)
756 			iid = q6apm_graph_get_module_iid(graph, MODULE_ID_RD_SHARED_MEM_EP);
757 		else
758 			graph->info->is_push_pull_mode = true;
759 	}
760 
761 	if (iid > 0)
762 		graph->shm_iid = iid;
763 
764 	mutex_init(&graph->lock);
765 	init_waitqueue_head(&graph->cmd_wait);
766 
767 	graph->port = gpr_alloc_port(apm->gdev, dev, graph_callback, graph);
768 	if (IS_ERR(graph->port)) {
769 		ret = PTR_ERR(graph->port);
770 		goto free_graph;
771 	}
772 
773 	return graph;
774 
775 free_graph:
776 	kfree(graph);
777 put_ar_graph:
778 	kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
779 	return ERR_PTR(ret);
780 }
781 EXPORT_SYMBOL_GPL(q6apm_graph_open);
782 
783 int q6apm_graph_close(struct q6apm_graph *graph)
784 {
785 	struct audioreach_graph *ar_graph = graph->ar_graph;
786 
787 	graph->ar_graph = NULL;
788 	kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
789 	gpr_free_port(graph->port);
790 	kfree(graph);
791 
792 	return 0;
793 }
794 EXPORT_SYMBOL_GPL(q6apm_graph_close);
795 
796 int q6apm_graph_prepare(struct q6apm_graph *graph)
797 {
798 	return audioreach_graph_mgmt_cmd(graph->ar_graph, APM_CMD_GRAPH_PREPARE);
799 }
800 EXPORT_SYMBOL_GPL(q6apm_graph_prepare);
801 
802 int q6apm_graph_start(struct q6apm_graph *graph)
803 {
804 	struct audioreach_graph *ar_graph = graph->ar_graph;
805 	int ret = 0;
806 
807 	if (ar_graph->start_count == 0)
808 		ret = audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_START);
809 
810 	ar_graph->start_count++;
811 
812 	return ret;
813 }
814 EXPORT_SYMBOL_GPL(q6apm_graph_start);
815 
816 int q6apm_graph_stop(struct q6apm_graph *graph)
817 {
818 	struct audioreach_graph *ar_graph = graph->ar_graph;
819 
820 	if (--ar_graph->start_count > 0)
821 		return 0;
822 
823 	return audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_STOP);
824 }
825 EXPORT_SYMBOL_GPL(q6apm_graph_stop);
826 
827 int q6apm_graph_flush(struct q6apm_graph *graph)
828 {
829 	return audioreach_graph_mgmt_cmd(graph->ar_graph, APM_CMD_GRAPH_FLUSH);
830 }
831 EXPORT_SYMBOL_GPL(q6apm_graph_flush);
832 
833 static int q6apm_audio_probe(struct snd_soc_component *component)
834 {
835 	return audioreach_tplg_init(component);
836 }
837 
838 static void q6apm_audio_remove(struct snd_soc_component *component)
839 {
840 	/* remove topology */
841 	snd_soc_tplg_component_remove(component);
842 }
843 
844 #define APM_AUDIO_DRV_NAME "q6apm-audio"
845 
846 static const struct snd_soc_component_driver q6apm_audio_component = {
847 	.name		= APM_AUDIO_DRV_NAME,
848 	.probe		= q6apm_audio_probe,
849 	.remove		= q6apm_audio_remove,
850 	.remove_order   = SND_SOC_COMP_ORDER_LAST,
851 };
852 
853 static int apm_probe(gpr_device_t *gdev)
854 {
855 	struct device *dev = &gdev->dev;
856 	struct q6apm *apm;
857 	int ret;
858 
859 	apm = devm_kzalloc(dev, sizeof(*apm), GFP_KERNEL);
860 	if (!apm)
861 		return -ENOMEM;
862 
863 	dev_set_drvdata(dev, apm);
864 
865 	mutex_init(&apm->lock);
866 	apm->dev = dev;
867 	apm->gdev = gdev;
868 	init_waitqueue_head(&apm->wait);
869 
870 	INIT_LIST_HEAD(&apm->widget_list);
871 	idr_init(&apm->graph_idr);
872 	idr_init(&apm->graph_info_idr);
873 	idr_init(&apm->sub_graphs_idr);
874 	idr_init(&apm->containers_idr);
875 
876 	idr_init(&apm->modules_idr);
877 
878 	g_apm = apm;
879 
880 	q6apm_get_apm_state(apm);
881 
882 	ret = snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0);
883 	if (ret < 0) {
884 		dev_err(dev, "failed to register q6apm: %d\n", ret);
885 		return ret;
886 	}
887 
888 	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
889 	if (ret)
890 		snd_soc_unregister_component(dev);
891 
892 	return ret;
893 }
894 
895 static void apm_remove(gpr_device_t *gdev)
896 {
897 	of_platform_depopulate(&gdev->dev);
898 	snd_soc_unregister_component(&gdev->dev);
899 }
900 
901 struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, uint32_t mid)
902 {
903 	struct audioreach_graph_info *info = graph->info;
904 	struct q6apm *apm = graph->apm;
905 
906 	return __q6apm_find_module_by_mid(apm, info, mid);
907 
908 }
909 
910 static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
911 {
912 	gpr_device_t *gdev = priv;
913 	struct audioreach_graph_info *info;
914 	struct q6apm *apm = dev_get_drvdata(&gdev->dev);
915 	struct apm_cmd_rsp_shared_mem_map_regions *rsp;
916 	struct device *dev = &gdev->dev;
917 	struct gpr_ibasic_rsp_result_t *result;
918 	const struct gpr_hdr *hdr = &data->hdr;
919 	int graph_id, is_pos_buf;
920 
921 	result = data->payload;
922 
923 	switch (hdr->opcode) {
924 	case APM_CMD_RSP_GET_SPF_STATE:
925 		apm->result.opcode = hdr->opcode;
926 		apm->result.status = 0;
927 		/* First word of result it state */
928 		apm->state = result->opcode;
929 		wake_up(&apm->wait);
930 		break;
931 	case GPR_BASIC_RSP_RESULT:
932 		switch (result->opcode) {
933 		case APM_CMD_SHARED_MEM_MAP_REGIONS:
934 		case APM_CMD_GRAPH_START:
935 		case APM_CMD_GRAPH_OPEN:
936 		case APM_CMD_GRAPH_PREPARE:
937 		case APM_CMD_GRAPH_CLOSE:
938 		case APM_CMD_GRAPH_FLUSH:
939 		case APM_CMD_GRAPH_STOP:
940 		case APM_CMD_SET_CFG:
941 			apm->result.opcode = result->opcode;
942 			apm->result.status = result->status;
943 			if (result->status)
944 				dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
945 					result->opcode);
946 			wake_up(&apm->wait);
947 			break;
948 		case APM_CMD_SHARED_MEM_UNMAP_REGIONS:
949 			apm->result.opcode = hdr->opcode;
950 			apm->result.status = 0;
951 			rsp = data->payload;
952 
953 			info = idr_find(&apm->graph_info_idr, hdr->token);
954 			if (info)
955 				info->mem_map_handle = 0;
956 			else
957 				dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
958 					result->opcode);
959 
960 			wake_up(&apm->wait);
961 			break;
962 		default:
963 			break;
964 		}
965 		break;
966 	case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS:
967 		apm->result.opcode = hdr->opcode;
968 		apm->result.status = 0;
969 		rsp = data->payload;
970 		graph_id = hdr->token & APM_MMAP_TOKEN_GID_MASK;
971 		is_pos_buf = hdr->token & APM_MMAP_TOKEN_MAP_TYPE_POS_BUF;
972 
973 		info = idr_find(&apm->graph_info_idr, graph_id);
974 		if (info) {
975 			if (is_pos_buf)
976 				info->pos_buf_mem_map_handle = rsp->mem_map_handle;
977 			else
978 				info->mem_map_handle = rsp->mem_map_handle;
979 		} else {
980 			dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
981 				result->opcode);
982 		}
983 
984 		wake_up(&apm->wait);
985 		break;
986 	default:
987 		break;
988 	}
989 
990 	return 0;
991 }
992 
993 #ifdef CONFIG_OF
994 static const struct of_device_id apm_device_id[]  = {
995 	{ .compatible = "qcom,q6apm" },
996 	{},
997 };
998 MODULE_DEVICE_TABLE(of, apm_device_id);
999 #endif
1000 
1001 static gpr_driver_t apm_driver = {
1002 	.probe = apm_probe,
1003 	.remove = apm_remove,
1004 	.gpr_callback = apm_callback,
1005 	.driver = {
1006 		.name = "qcom-apm",
1007 		.of_match_table = of_match_ptr(apm_device_id),
1008 	},
1009 };
1010 
1011 module_gpr_driver(apm_driver);
1012 MODULE_DESCRIPTION("Audio Process Manager");
1013 MODULE_LICENSE("GPL");
1014