xref: /linux/sound/soc/qcom/qdsp6/q6apm.c (revision 9e4e86a604dfd06402933467578c4b79f5412b2c)
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