~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/qcom/qdsp6/q6apm.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php