xref: /linux/sound/soc/qcom/qdsp6/q6apm.c (revision ed56ac9e5e96e048eb1a98618908539a02431b46)
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 		phys = graph->rx_data.buf[token].phys;
591 		mutex_unlock(&graph->lock);
592 		/* token numbering starts at 0 */
593 		atomic_set(&graph->rx_data.hw_ptr, token + 1);
594 		if (lower_32_bits(phys) == done->buf_addr_lsw &&
595 		    upper_32_bits(phys) == done->buf_addr_msw) {
596 			graph->result.opcode = hdr->opcode;
597 			graph->result.status = done->status;
598 			if (graph->cb)
599 				graph->cb(client_event, hdr->token, data->payload, graph->priv);
600 		} else {
601 			dev_err(dev, "WR BUFF Unexpected addr %08x-%08x\n", done->buf_addr_lsw,
602 				done->buf_addr_msw);
603 		}
604 
605 		break;
606 	case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2:
607 		if (!graph->ar_graph)
608 			break;
609 		client_event = APM_CLIENT_EVENT_DATA_READ_DONE;
610 		mutex_lock(&graph->lock);
611 		rd_done = data->payload;
612 		phys = graph->tx_data.buf[hdr->token].phys;
613 		mutex_unlock(&graph->lock);
614 		/* token numbering starts at 0 */
615 		atomic_set(&graph->tx_data.hw_ptr, hdr->token + 1);
616 
617 		if (upper_32_bits(phys) == rd_done->buf_addr_msw &&
618 		    lower_32_bits(phys) == rd_done->buf_addr_lsw) {
619 			graph->result.opcode = hdr->opcode;
620 			graph->result.status = rd_done->status;
621 			if (graph->cb)
622 				graph->cb(client_event, hdr->token, data->payload, graph->priv);
623 		} else {
624 			dev_err(dev, "RD BUFF Unexpected addr %08x-%08x\n", rd_done->buf_addr_lsw,
625 				rd_done->buf_addr_msw);
626 		}
627 		break;
628 	case DATA_CMD_WR_SH_MEM_EP_EOS_RENDERED:
629 		client_event = APM_CLIENT_EVENT_CMD_EOS_DONE;
630 		if (graph->cb)
631 			graph->cb(client_event, hdr->token, data->payload, graph->priv);
632 		break;
633 	case GPR_BASIC_RSP_RESULT:
634 		switch (result->opcode) {
635 		case APM_CMD_SHARED_MEM_MAP_REGIONS:
636 		case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT:
637 		case APM_CMD_REGISTER_MODULE_EVENTS:
638 		case APM_CMD_SET_CFG:
639 			graph->result.opcode = result->opcode;
640 			graph->result.status = result->status;
641 			if (result->status)
642 				dev_err(dev, "Error (%d) Processing 0x%08x cmd\n",
643 					result->status, result->opcode);
644 			wake_up(&graph->cmd_wait);
645 			break;
646 		default:
647 			break;
648 		}
649 		break;
650 	default:
651 		break;
652 	}
653 	return 0;
654 }
655 
656 int q6apm_register_watermark_event(struct q6apm_graph *graph, int water_mark_level_bytes,
657 				   int num_levels)
658 {
659 	return audioreach_shmem_register_event(graph, water_mark_level_bytes, num_levels);
660 }
661 EXPORT_SYMBOL_GPL(q6apm_register_watermark_event);
662 
663 int q6apm_push_pull_config(struct q6apm_graph *graph, phys_addr_t bphys,
664 			   phys_addr_t pphys, uint32_t size)
665 {
666 	struct audioreach_graph_info *info = graph->info;
667 
668 	return audioreach_setup_push_pull(graph, bphys, pphys, info->mem_map_handle,
669 					  info->pos_buf_mem_map_handle, size);
670 }
671 EXPORT_SYMBOL_GPL(q6apm_push_pull_config);
672 
673 bool q6apm_is_graph_in_push_pull_mode_from_id(struct device *dev, unsigned int graph_id, int dir)
674 {
675 	struct audioreach_graph_info *info;
676 	struct q6apm *apm = dev_get_drvdata(dev->parent);
677 	struct audioreach_module *module;
678 
679 	info = idr_find(&apm->graph_info_idr, graph_id);
680 	if (!info)
681 		return false;
682 
683 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
684 		module = __q6apm_find_module_by_mid(apm, info, MODULE_ID_SH_MEM_PULL_MODE);
685 	else
686 		module = __q6apm_find_module_by_mid(apm, info, MODULE_ID_SH_MEM_PUSH_MODE);
687 
688 	return !!module;
689 
690 }
691 EXPORT_SYMBOL_GPL(q6apm_is_graph_in_push_pull_mode_from_id);
692 
693 bool q6apm_is_graph_in_push_pull_mode(struct q6apm_graph *graph)
694 {
695 	return graph->info->is_push_pull_mode;
696 }
697 EXPORT_SYMBOL_GPL(q6apm_is_graph_in_push_pull_mode);
698 
699 static int q6apm_graph_get_module_iid(struct q6apm_graph *graph, uint32_t mid)
700 {
701 	struct audioreach_module *module;
702 
703 	module = q6apm_find_module_by_mid(graph, mid);
704 	if (!module)
705 		return -ENODEV;
706 
707 	return module->instance_id;
708 }
709 
710 struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb,
711 				     void *priv, int graph_id, int dir)
712 {
713 	struct q6apm *apm = dev_get_drvdata(dev->parent);
714 	struct audioreach_graph *ar_graph;
715 	struct q6apm_graph *graph;
716 	int ret, iid = 0;
717 
718 	ar_graph = q6apm_get_audioreach_graph(apm, graph_id);
719 	if (IS_ERR(ar_graph)) {
720 		dev_err(dev, "No graph found with id %d\n", graph_id);
721 		return ERR_CAST(ar_graph);
722 	}
723 
724 	graph = kzalloc_obj(*graph);
725 	if (!graph) {
726 		ret = -ENOMEM;
727 		goto put_ar_graph;
728 	}
729 
730 	graph->apm = apm;
731 	graph->priv = priv;
732 	graph->cb = cb;
733 	graph->info = ar_graph->info;
734 	graph->ar_graph = ar_graph;
735 	graph->id = ar_graph->id;
736 	graph->dev = dev;
737 
738 	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
739 		iid = q6apm_graph_get_module_iid(graph, MODULE_ID_SH_MEM_PULL_MODE);
740 		if (iid < 0)
741 			iid = q6apm_graph_get_module_iid(graph, MODULE_ID_WR_SHARED_MEM_EP);
742 		else
743 			graph->info->is_push_pull_mode = true;
744 
745 	} else {
746 		iid = q6apm_graph_get_module_iid(graph, MODULE_ID_SH_MEM_PUSH_MODE);
747 		if (iid < 0)
748 			iid = q6apm_graph_get_module_iid(graph, MODULE_ID_RD_SHARED_MEM_EP);
749 		else
750 			graph->info->is_push_pull_mode = true;
751 	}
752 
753 	if (iid > 0)
754 		graph->shm_iid = iid;
755 
756 	mutex_init(&graph->lock);
757 	init_waitqueue_head(&graph->cmd_wait);
758 
759 	graph->port = gpr_alloc_port(apm->gdev, dev, graph_callback, graph);
760 	if (IS_ERR(graph->port)) {
761 		ret = PTR_ERR(graph->port);
762 		goto free_graph;
763 	}
764 
765 	return graph;
766 
767 free_graph:
768 	kfree(graph);
769 put_ar_graph:
770 	kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
771 	return ERR_PTR(ret);
772 }
773 EXPORT_SYMBOL_GPL(q6apm_graph_open);
774 
775 int q6apm_graph_close(struct q6apm_graph *graph)
776 {
777 	struct audioreach_graph *ar_graph = graph->ar_graph;
778 
779 	graph->ar_graph = NULL;
780 	kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph);
781 	gpr_free_port(graph->port);
782 	kfree(graph);
783 
784 	return 0;
785 }
786 EXPORT_SYMBOL_GPL(q6apm_graph_close);
787 
788 int q6apm_graph_prepare(struct q6apm_graph *graph)
789 {
790 	return audioreach_graph_mgmt_cmd(graph->ar_graph, APM_CMD_GRAPH_PREPARE);
791 }
792 EXPORT_SYMBOL_GPL(q6apm_graph_prepare);
793 
794 int q6apm_graph_start(struct q6apm_graph *graph)
795 {
796 	struct audioreach_graph *ar_graph = graph->ar_graph;
797 	int ret = 0;
798 
799 	if (ar_graph->start_count == 0)
800 		ret = audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_START);
801 
802 	ar_graph->start_count++;
803 
804 	return ret;
805 }
806 EXPORT_SYMBOL_GPL(q6apm_graph_start);
807 
808 int q6apm_graph_stop(struct q6apm_graph *graph)
809 {
810 	struct audioreach_graph *ar_graph = graph->ar_graph;
811 
812 	if (--ar_graph->start_count > 0)
813 		return 0;
814 
815 	return audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_STOP);
816 }
817 EXPORT_SYMBOL_GPL(q6apm_graph_stop);
818 
819 int q6apm_graph_flush(struct q6apm_graph *graph)
820 {
821 	return audioreach_graph_mgmt_cmd(graph->ar_graph, APM_CMD_GRAPH_FLUSH);
822 }
823 EXPORT_SYMBOL_GPL(q6apm_graph_flush);
824 
825 static int q6apm_audio_probe(struct snd_soc_component *component)
826 {
827 	return audioreach_tplg_init(component);
828 }
829 
830 static void q6apm_audio_remove(struct snd_soc_component *component)
831 {
832 	/* remove topology */
833 	snd_soc_tplg_component_remove(component);
834 }
835 
836 #define APM_AUDIO_DRV_NAME "q6apm-audio"
837 
838 static const struct snd_soc_component_driver q6apm_audio_component = {
839 	.name		= APM_AUDIO_DRV_NAME,
840 	.probe		= q6apm_audio_probe,
841 	.remove		= q6apm_audio_remove,
842 	.remove_order   = SND_SOC_COMP_ORDER_LAST,
843 };
844 
845 static int apm_probe(gpr_device_t *gdev)
846 {
847 	struct device *dev = &gdev->dev;
848 	struct q6apm *apm;
849 	int ret;
850 
851 	apm = devm_kzalloc(dev, sizeof(*apm), GFP_KERNEL);
852 	if (!apm)
853 		return -ENOMEM;
854 
855 	dev_set_drvdata(dev, apm);
856 
857 	mutex_init(&apm->lock);
858 	apm->dev = dev;
859 	apm->gdev = gdev;
860 	init_waitqueue_head(&apm->wait);
861 
862 	INIT_LIST_HEAD(&apm->widget_list);
863 	idr_init(&apm->graph_idr);
864 	idr_init(&apm->graph_info_idr);
865 	idr_init(&apm->sub_graphs_idr);
866 	idr_init(&apm->containers_idr);
867 
868 	idr_init(&apm->modules_idr);
869 
870 	g_apm = apm;
871 
872 	q6apm_get_apm_state(apm);
873 
874 	ret = snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0);
875 	if (ret < 0) {
876 		dev_err(dev, "failed to register q6apm: %d\n", ret);
877 		return ret;
878 	}
879 
880 	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
881 	if (ret)
882 		snd_soc_unregister_component(dev);
883 
884 	return ret;
885 }
886 
887 static void apm_remove(gpr_device_t *gdev)
888 {
889 	of_platform_depopulate(&gdev->dev);
890 	snd_soc_unregister_component(&gdev->dev);
891 }
892 
893 struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, uint32_t mid)
894 {
895 	struct audioreach_graph_info *info = graph->info;
896 	struct q6apm *apm = graph->apm;
897 
898 	return __q6apm_find_module_by_mid(apm, info, mid);
899 
900 }
901 
902 static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
903 {
904 	gpr_device_t *gdev = priv;
905 	struct audioreach_graph_info *info;
906 	struct q6apm *apm = dev_get_drvdata(&gdev->dev);
907 	struct apm_cmd_rsp_shared_mem_map_regions *rsp;
908 	struct device *dev = &gdev->dev;
909 	struct gpr_ibasic_rsp_result_t *result;
910 	const struct gpr_hdr *hdr = &data->hdr;
911 	int graph_id, is_pos_buf;
912 
913 	result = data->payload;
914 
915 	switch (hdr->opcode) {
916 	case APM_CMD_RSP_GET_SPF_STATE:
917 		apm->result.opcode = hdr->opcode;
918 		apm->result.status = 0;
919 		/* First word of result it state */
920 		apm->state = result->opcode;
921 		wake_up(&apm->wait);
922 		break;
923 	case GPR_BASIC_RSP_RESULT:
924 		switch (result->opcode) {
925 		case APM_CMD_SHARED_MEM_MAP_REGIONS:
926 		case APM_CMD_GRAPH_START:
927 		case APM_CMD_GRAPH_OPEN:
928 		case APM_CMD_GRAPH_PREPARE:
929 		case APM_CMD_GRAPH_CLOSE:
930 		case APM_CMD_GRAPH_FLUSH:
931 		case APM_CMD_GRAPH_STOP:
932 		case APM_CMD_SET_CFG:
933 			apm->result.opcode = result->opcode;
934 			apm->result.status = result->status;
935 			if (result->status)
936 				dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
937 					result->opcode);
938 			wake_up(&apm->wait);
939 			break;
940 		case APM_CMD_SHARED_MEM_UNMAP_REGIONS:
941 			apm->result.opcode = hdr->opcode;
942 			apm->result.status = 0;
943 			rsp = data->payload;
944 
945 			info = idr_find(&apm->graph_info_idr, hdr->token);
946 			if (info)
947 				info->mem_map_handle = 0;
948 			else
949 				dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
950 					result->opcode);
951 
952 			wake_up(&apm->wait);
953 			break;
954 		default:
955 			break;
956 		}
957 		break;
958 	case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS:
959 		apm->result.opcode = hdr->opcode;
960 		apm->result.status = 0;
961 		rsp = data->payload;
962 		graph_id = hdr->token & APM_MMAP_TOKEN_GID_MASK;
963 		is_pos_buf = hdr->token & APM_MMAP_TOKEN_MAP_TYPE_POS_BUF;
964 
965 		info = idr_find(&apm->graph_info_idr, graph_id);
966 		if (info) {
967 			if (is_pos_buf)
968 				info->pos_buf_mem_map_handle = rsp->mem_map_handle;
969 			else
970 				info->mem_map_handle = rsp->mem_map_handle;
971 		} else {
972 			dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
973 				result->opcode);
974 		}
975 
976 		wake_up(&apm->wait);
977 		break;
978 	default:
979 		break;
980 	}
981 
982 	return 0;
983 }
984 
985 #ifdef CONFIG_OF
986 static const struct of_device_id apm_device_id[]  = {
987 	{ .compatible = "qcom,q6apm" },
988 	{},
989 };
990 MODULE_DEVICE_TABLE(of, apm_device_id);
991 #endif
992 
993 static gpr_driver_t apm_driver = {
994 	.probe = apm_probe,
995 	.remove = apm_remove,
996 	.gpr_callback = apm_callback,
997 	.driver = {
998 		.name = "qcom-apm",
999 		.of_match_table = of_match_ptr(apm_device_id),
1000 	},
1001 };
1002 
1003 module_gpr_driver(apm_driver);
1004 MODULE_DESCRIPTION("Audio Process Manager");
1005 MODULE_LICENSE("GPL");
1006