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