Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: qcom: q6dsp: few fixes and enhancements

Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com> says:

This patchset contains few fixes for the bugs hit during testing with
Monza EVK platform
- around array out of bounds access on dai ids which keep extending but
the drivers seems to have hardcoded some numbers, fix this and clean
the mess up
- fix few issues discovered while trying to shut down dsp.
- flooding rpmsg with write requests due to not resetting queue pointer,
fix this resetting the pointer in trigger stop.
- possible multiple graph opens which can result in open failures.

Apart from this few new enhancements to the dsp side
- add new LPI MI2S and senary dai entries
- handle pipewire and Displayport issues by moving graph start to
trigger level, which should fix outstanding pipewire and DP issues on
Qualcomm SoCs.
- remove some unnessary loops in hot path
- support early memory map on DSP.

Tested this on top of linux-next on VENTUNO-Q platform.

+391 -169
+4 -1
Documentation/devicetree/bindings/sound/qcom,q6dsp-lpass-ports.yaml
··· 126 126 reg: 127 127 contains: 128 128 # MI2S DAI ID range PRIMARY_MI2S_RX - QUATERNARY_MI2S_TX and 129 - # QUINARY_MI2S_RX - QUINARY_MI2S_TX 129 + # QUINARY_MI2S_RX - QUINARY_MI2S_TX and 130 + # LPI_MI2S_RX_0 - SENARY_MI2S_TX 130 131 items: 131 132 oneOf: 132 133 - minimum: 16 133 134 maximum: 23 134 135 - minimum: 127 135 136 maximum: 128 137 + - minimum: 137 138 + maximum: 148 136 139 then: 137 140 required: 138 141 - qcom,sd-lines
+12
include/dt-bindings/sound/qcom,q6dsp-lpass-ports.h
··· 140 140 #define DISPLAY_PORT_RX_6 134 141 141 #define DISPLAY_PORT_RX_7 135 142 142 #define USB_RX 136 143 + #define LPI_MI2S_RX_0 137 144 + #define LPI_MI2S_TX_0 138 145 + #define LPI_MI2S_RX_1 139 146 + #define LPI_MI2S_TX_1 140 147 + #define LPI_MI2S_RX_2 141 148 + #define LPI_MI2S_TX_2 142 149 + #define LPI_MI2S_RX_3 143 150 + #define LPI_MI2S_TX_3 144 151 + #define LPI_MI2S_RX_4 145 152 + #define LPI_MI2S_TX_4 146 153 + #define SENARY_MI2S_RX 147 154 + #define SENARY_MI2S_TX 148 143 155 144 156 #define LPASS_CLK_ID_PRI_MI2S_IBIT 1 145 157 #define LPASS_CLK_ID_PRI_MI2S_EBIT 2
+6
sound/soc/qcom/common.c
··· 120 120 121 121 link->id = args.args[0]; 122 122 123 + if (link->id >= LPASS_MAX_PORT) { 124 + dev_err(dev, "%s: Invalid cpu dai id %d\n", link->name, link->id); 125 + ret = -EINVAL; 126 + goto err; 127 + } 128 + 123 129 if (platform) { 124 130 link->platforms->of_node = of_parse_phandle(platform, 125 131 "sound-dai",
+3
sound/soc/qcom/common.h
··· 4 4 #ifndef __QCOM_SND_COMMON_H__ 5 5 #define __QCOM_SND_COMMON_H__ 6 6 7 + #include <dt-bindings/sound/qcom,q6afe.h> 7 8 #include <sound/soc.h> 9 + 10 + #define LPASS_MAX_PORT (SENARY_MI2S_TX + 1) 8 11 9 12 int qcom_snd_parse_of(struct snd_soc_card *card); 10 13 int qcom_snd_wcd_jack_setup(struct snd_soc_pcm_runtime *rtd,
+2 -1
sound/soc/qcom/lpass.h
··· 14 14 #include <linux/regmap.h> 15 15 #include <dt-bindings/sound/qcom,lpass.h> 16 16 #include <dt-bindings/sound/qcom,q6afe.h> 17 + #include "common.h" 17 18 #include "lpass-hdmi.h" 18 19 19 20 #define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 20 - #define LPASS_MAX_PORTS (DISPLAY_PORT_RX_7 + 1) 21 + #define LPASS_MAX_PORTS (LPASS_MAX_PORT) 21 22 #define LPASS_MAX_MI2S_PORTS (8) 22 23 #define LPASS_MAX_DMA_CHANNELS (8) 23 24 #define LPASS_MAX_HDMI_DMA_CHANNELS (4)
-60
sound/soc/qcom/qdsp6/audioreach.c
··· 1396 1396 } 1397 1397 EXPORT_SYMBOL_GPL(audioreach_graph_free_buf); 1398 1398 1399 - int audioreach_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, size_t period_sz, 1400 - unsigned int periods, bool is_contiguous) 1401 - { 1402 - struct apm_shared_map_region_payload *mregions; 1403 - struct apm_cmd_shared_mem_map_regions *cmd; 1404 - uint32_t num_regions, buf_sz, payload_size; 1405 - struct audioreach_graph_data *data; 1406 - struct gpr_pkt *pkt __free(kfree) = NULL; 1407 - void *p; 1408 - int i; 1409 - 1410 - if (dir == SNDRV_PCM_STREAM_PLAYBACK) 1411 - data = &graph->rx_data; 1412 - else 1413 - data = &graph->tx_data; 1414 - 1415 - if (is_contiguous) { 1416 - num_regions = 1; 1417 - buf_sz = period_sz * periods; 1418 - } else { 1419 - buf_sz = period_sz; 1420 - num_regions = periods; 1421 - } 1422 - 1423 - /* DSP expects size should be aligned to 4K */ 1424 - buf_sz = ALIGN(buf_sz, 4096); 1425 - 1426 - payload_size = sizeof(*cmd) + (sizeof(*mregions) * num_regions); 1427 - 1428 - pkt = audioreach_alloc_apm_pkt(payload_size, APM_CMD_SHARED_MEM_MAP_REGIONS, dir, 1429 - graph->port->id); 1430 - if (IS_ERR(pkt)) 1431 - return PTR_ERR(pkt); 1432 - 1433 - p = (void *)pkt + GPR_HDR_SIZE; 1434 - cmd = p; 1435 - cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL; 1436 - cmd->num_regions = num_regions; 1437 - 1438 - cmd->property_flag = 0x0; 1439 - 1440 - mregions = p + sizeof(*cmd); 1441 - 1442 - mutex_lock(&graph->lock); 1443 - 1444 - for (i = 0; i < num_regions; i++) { 1445 - struct audio_buffer *ab; 1446 - 1447 - ab = &data->buf[i]; 1448 - mregions->shm_addr_lsw = lower_32_bits(ab->phys); 1449 - mregions->shm_addr_msw = upper_32_bits(ab->phys); 1450 - mregions->mem_size_bytes = buf_sz; 1451 - ++mregions; 1452 - } 1453 - mutex_unlock(&graph->lock); 1454 - 1455 - return audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS); 1456 - } 1457 - EXPORT_SYMBOL_GPL(audioreach_map_memory_regions); 1458 - 1459 1399 int audioreach_shared_memory_send_eos(struct q6apm_graph *graph) 1460 1400 { 1461 1401 struct data_cmd_wr_sh_mem_ep_eos *eos;
+1 -4
sound/soc/qcom/qdsp6/audioreach.h
··· 722 722 723 723 struct audioreach_graph_info { 724 724 int id; 725 + uint32_t mem_map_handle; 725 726 uint32_t num_sub_graphs; 726 727 struct list_head sg_list; 727 728 /* DPCM connection from FE Graph to BE graph */ ··· 839 838 840 839 /* Module specific */ 841 840 void audioreach_graph_free_buf(struct q6apm_graph *graph); 842 - int audioreach_map_memory_regions(struct q6apm_graph *graph, 843 - unsigned int dir, size_t period_sz, 844 - unsigned int periods, 845 - bool is_contiguous); 846 841 int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, struct gpr_ibasic_rsp_result_t *result, 847 842 struct mutex *cmd_lock, gpr_port_t *port, wait_queue_head_t *cmd_wait, 848 843 struct gpr_pkt *pkt, uint32_t rsp_opcode);
+6
sound/soc/qcom/qdsp6/q6afe-dai.c
··· 409 409 q6afe_slim_port_prepare(dai_data->port[dai->id], 410 410 &dai_data->port_config[dai->id].slim); 411 411 break; 412 + case SENARY_MI2S_RX ... SENARY_MI2S_TX: 412 413 case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: 413 414 case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: 414 415 rc = q6afe_i2s_port_prepare(dai_data->port[dai->id], ··· 541 540 {"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"}, 542 541 {"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"}, 543 542 {"Quinary MI2S Playback", NULL, "QUIN_MI2S_RX"}, 543 + {"Senary MI2S Playback", NULL, "SEN_MI2S_RX"}, 544 544 545 545 {"Primary TDM0 Playback", NULL, "PRIMARY_TDM_RX_0"}, 546 546 {"Primary TDM1 Playback", NULL, "PRIMARY_TDM_RX_1"}, ··· 638 636 {"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"}, 639 637 {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"}, 640 638 {"QUIN_MI2S_TX", NULL, "Quinary MI2S Capture"}, 639 + {"SEN_MI2S_TX", NULL, "Senary MI2S Capture"}, 641 640 642 641 {"WSA_CODEC_DMA_RX_0 Playback", NULL, "WSA_CODEC_DMA_RX_0"}, 643 642 {"WSA_CODEC_DMA_TX_0", NULL, "WSA_CODEC_DMA_TX_0 Capture"}, ··· 773 770 SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_TX", NULL, 0, SND_SOC_NOPM, 0, 0), 774 771 SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_TX", NULL, 0, SND_SOC_NOPM, 0, 0), 775 772 SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_TX", NULL, 0, SND_SOC_NOPM, 0, 0), 773 + SND_SOC_DAPM_AIF_IN("SEN_MI2S_RX", NULL, 0, SND_SOC_NOPM, 0, 0), 774 + SND_SOC_DAPM_AIF_OUT("SEN_MI2S_TX", NULL, 0, SND_SOC_NOPM, 0, 0), 776 775 SND_SOC_DAPM_AIF_IN("QUIN_MI2S_RX", NULL, 777 776 0, SND_SOC_NOPM, 0, 0), 778 777 SND_SOC_DAPM_AIF_OUT("QUIN_MI2S_TX", NULL, ··· 1042 1037 1043 1038 switch (id) { 1044 1039 /* MI2S specific properties */ 1040 + case SENARY_MI2S_RX ... SENARY_MI2S_TX: 1045 1041 case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: 1046 1042 case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: 1047 1043 priv = &data->priv[id];
+8
sound/soc/qcom/qdsp6/q6afe.c
··· 130 130 #define AFE_PORT_ID_QUATERNARY_MI2S_TX 0x1007 131 131 #define AFE_PORT_ID_QUINARY_MI2S_RX 0x1016 132 132 #define AFE_PORT_ID_QUINARY_MI2S_TX 0x1017 133 + #define AFE_PORT_ID_SENARY_MI2S_RX 0x1018 134 + #define AFE_PORT_ID_SENARY_MI2S_TX 0x1019 133 135 134 136 /* Start of the range of port IDs for TDM devices. */ 135 137 #define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000 ··· 720 718 QUINARY_MI2S_RX, 1, 1}, 721 719 [QUINARY_MI2S_TX] = { AFE_PORT_ID_QUINARY_MI2S_TX, 722 720 QUINARY_MI2S_TX, 0, 1}, 721 + [SENARY_MI2S_RX] = { AFE_PORT_ID_SENARY_MI2S_RX, 722 + SENARY_MI2S_RX, 1, 1}, 723 + [SENARY_MI2S_TX] = { AFE_PORT_ID_SENARY_MI2S_TX, 724 + SENARY_MI2S_TX, 0, 1}, 723 725 [PRIMARY_TDM_RX_0] = { AFE_PORT_ID_PRIMARY_TDM_RX, 724 726 PRIMARY_TDM_RX_0, 1, 1}, 725 727 [PRIMARY_TDM_TX_0] = { AFE_PORT_ID_PRIMARY_TDM_TX, ··· 1783 1777 case AFE_PORT_ID_QUATERNARY_MI2S_TX: 1784 1778 case AFE_PORT_ID_QUINARY_MI2S_RX: 1785 1779 case AFE_PORT_ID_QUINARY_MI2S_TX: 1780 + case AFE_PORT_ID_SENARY_MI2S_RX: 1781 + case AFE_PORT_ID_SENARY_MI2S_TX: 1786 1782 cfg_type = AFE_PARAM_ID_I2S_CONFIG; 1787 1783 break; 1788 1784 case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7:
+2 -1
sound/soc/qcom/qdsp6/q6afe.h
··· 2 2 3 3 #ifndef __Q6AFE_H__ 4 4 #define __Q6AFE_H__ 5 + #include "../common.h" 5 6 6 - #define AFE_PORT_MAX 137 7 + #define AFE_PORT_MAX (LPASS_MAX_PORT) 7 8 8 9 #define MSM_AFE_PORT_TYPE_RX 0 9 10 #define MSM_AFE_PORT_TYPE_TX 1
+100 -13
sound/soc/qcom/qdsp6/q6apm-dai.c
··· 228 228 cfg.bit_width = prtd->bits_per_sample; 229 229 cfg.fmt = SND_AUDIOCODEC_PCM; 230 230 audioreach_set_default_channel_mapping(cfg.channel_map, runtime->channels); 231 - 232 231 if (prtd->state) { 233 232 /* clear the previous setup if any */ 234 233 q6apm_graph_stop(prtd->graph); 235 - q6apm_unmap_memory_regions(prtd->graph, substream->stream); 234 + q6apm_free_fragments(prtd->graph, substream->stream); 236 235 } 237 236 238 237 prtd->pcm_count = snd_pcm_lib_period_bytes(substream); ··· 246 247 if (ret < 0) 247 248 dev_err(dev, "%s: CMD Format block failed\n", __func__); 248 249 249 - ret = q6apm_map_memory_regions(prtd->graph, substream->stream, prtd->phys, 250 - (prtd->pcm_size / prtd->periods), prtd->periods); 250 + ret = q6apm_alloc_fragments(prtd->graph, substream->stream, prtd->phys, 251 + (prtd->pcm_size / prtd->periods), prtd->periods); 251 252 252 253 if (ret < 0) { 253 254 dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n", ret); ··· 316 317 case SNDRV_PCM_TRIGGER_STOP: 317 318 /* TODO support be handled via SoftPause Module */ 318 319 prtd->state = Q6APM_STREAM_STOPPED; 320 + prtd->queue_ptr = 0; 319 321 break; 320 322 case SNDRV_PCM_TRIGGER_SUSPEND: 321 323 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ··· 354 354 355 355 spin_lock_init(&prtd->lock); 356 356 prtd->substream = substream; 357 - prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id); 357 + prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id, substream->stream); 358 358 if (IS_ERR(prtd->graph)) { 359 359 dev_err(dev, "%s: Could not allocate memory\n", __func__); 360 360 ret = PTR_ERR(prtd->graph); ··· 415 415 struct snd_pcm_runtime *runtime = substream->runtime; 416 416 struct q6apm_dai_rtd *prtd = runtime->private_data; 417 417 418 - if (prtd->state) { /* only stop graph that is started */ 418 + if (prtd->state) { 419 + /* only stop graph that is started */ 419 420 q6apm_graph_stop(prtd->graph); 420 - q6apm_unmap_memory_regions(prtd->graph, substream->stream); 421 + q6apm_free_fragments(prtd->graph, substream->stream); 421 422 } 422 423 423 424 q6apm_graph_close(prtd->graph); ··· 467 466 return 0; 468 467 } 469 468 469 + static int q6apm_dai_memory_map(struct snd_soc_component *component, 470 + struct snd_pcm_substream *substream, int graph_id) 471 + { 472 + struct q6apm_dai_data *pdata; 473 + struct device *dev = component->dev; 474 + phys_addr_t phys; 475 + int ret; 476 + 477 + pdata = snd_soc_component_get_drvdata(component); 478 + if (!pdata) { 479 + dev_err(component->dev, "Drv data not found ..\n"); 480 + return -EINVAL; 481 + } 482 + 483 + if (pdata->sid < 0) 484 + phys = substream->dma_buffer.addr; 485 + else 486 + phys = substream->dma_buffer.addr | (pdata->sid << 32); 487 + 488 + ret = q6apm_map_memory_fixed_region(dev, graph_id, phys, BUFFER_BYTES_MAX); 489 + if (ret < 0) 490 + dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n", ret); 491 + 492 + return ret; 493 + } 494 + 470 495 static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd) 471 496 { 497 + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); 498 + struct snd_pcm *pcm = rtd->pcm; 472 499 int size = BUFFER_BYTES_MAX; 500 + int graph_id, ret; 501 + struct snd_pcm_substream *substream; 473 502 474 - return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, size); 503 + graph_id = cpu_dai->driver->id; 504 + 505 + ret = snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, component->dev, size); 506 + if (ret) 507 + return ret; 508 + 509 + /* Note: DSP backend dais are uni-directional ONLY(either playback or capture) */ 510 + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 511 + substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 512 + ret = q6apm_dai_memory_map(component, substream, graph_id); 513 + if (ret) 514 + return ret; 515 + } 516 + 517 + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { 518 + substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 519 + ret = q6apm_dai_memory_map(component, substream, graph_id); 520 + if (ret) 521 + return ret; 522 + } 523 + 524 + return 0; 525 + } 526 + 527 + static void q6apm_dai_memory_unmap(struct snd_soc_component *component, 528 + struct snd_pcm_substream *substream) 529 + { 530 + struct snd_soc_pcm_runtime *soc_prtd; 531 + struct snd_soc_dai *cpu_dai; 532 + int graph_id; 533 + 534 + soc_prtd = snd_soc_substream_to_rtd(substream); 535 + if (!soc_prtd) 536 + return; 537 + 538 + cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0); 539 + if (!cpu_dai) 540 + return; 541 + 542 + graph_id = cpu_dai->driver->id; 543 + q6apm_unmap_memory_fixed_region(component->dev, graph_id); 544 + } 545 + 546 + static void q6apm_dai_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm) 547 + { 548 + struct snd_pcm_substream *substream; 549 + 550 + substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 551 + if (substream) 552 + q6apm_dai_memory_unmap(component, substream); 553 + 554 + substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; 555 + if (substream) 556 + q6apm_dai_memory_unmap(component, substream); 475 557 } 476 558 477 559 static int q6apm_dai_compr_open(struct snd_soc_component *component, ··· 579 495 return -ENOMEM; 580 496 581 497 prtd->cstream = stream; 582 - prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id); 498 + prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id, 499 + SNDRV_PCM_STREAM_PLAYBACK); 583 500 if (IS_ERR(prtd->graph)) { 584 501 ret = PTR_ERR(prtd->graph); 585 502 kfree(prtd); ··· 613 528 struct q6apm_dai_rtd *prtd = runtime->private_data; 614 529 615 530 q6apm_graph_stop(prtd->graph); 616 - q6apm_unmap_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK); 531 + q6apm_free_fragments(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK); 532 + q6apm_unmap_memory_fixed_region(component->dev, prtd->graph->id); 617 533 q6apm_graph_close(prtd->graph); 618 534 snd_dma_free_pages(&prtd->dma_buffer); 619 535 prtd->graph = NULL; ··· 763 677 if (ret) 764 678 return ret; 765 679 766 - ret = q6apm_map_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK, 767 - prtd->phys, (prtd->pcm_size / prtd->periods), 768 - prtd->periods); 680 + ret = q6apm_alloc_fragments(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK, 681 + prtd->phys, (prtd->pcm_size / prtd->periods), 682 + prtd->periods); 769 683 if (ret < 0) 770 684 return -ENOMEM; 771 685 ··· 918 832 .close = q6apm_dai_close, 919 833 .prepare = q6apm_dai_prepare, 920 834 .pcm_new = q6apm_dai_pcm_new, 835 + .pcm_free = q6apm_dai_pcm_free, 921 836 .hw_params = q6apm_dai_hw_params, 922 837 .pointer = q6apm_dai_pointer, 923 838 .trigger = q6apm_dai_trigger,
+32 -16
sound/soc/qcom/qdsp6/q6apm-lpass-dais.c
··· 150 150 rc = q6apm_graph_stop(dai_data->graph[dai->id]); 151 151 dai_data->is_port_started[dai->id] = false; 152 152 if (rc < 0) 153 - dev_err(dai->dev, "fail to close APM port (%d)\n", rc); 153 + dev_err(dai->dev, "failed to stop APM port (%d)\n", rc); 154 154 } 155 155 156 156 if (dai_data->graph[dai->id]) { 157 157 q6apm_graph_close(dai_data->graph[dai->id]); 158 158 dai_data->graph[dai->id] = NULL; 159 159 } 160 + } 161 + 162 + static int q6apm_lpass_dai_trigger(struct snd_pcm_substream *substream, int cmd, 163 + struct snd_soc_dai *dai) 164 + { 165 + struct q6apm_lpass_dai_data *dai_data = dev_get_drvdata(dai->dev); 166 + int ret = 0; 167 + 168 + switch (cmd) { 169 + case SNDRV_PCM_TRIGGER_START: 170 + case SNDRV_PCM_TRIGGER_RESUME: 171 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 172 + if (!dai_data->is_port_started[dai->id]) { 173 + ret = q6apm_graph_start(dai_data->graph[dai->id]); 174 + if (ret < 0) 175 + dev_err(dai->dev, "Failed to start APM port %d\n", dai->id); 176 + else 177 + dai_data->is_port_started[dai->id] = true; 178 + } 179 + break; 180 + default: 181 + break; 182 + } 183 + 184 + return ret; 160 185 } 161 186 162 187 static int q6apm_lpass_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) ··· 196 171 q6apm_graph_stop(dai_data->graph[dai->id]); 197 172 dai_data->is_port_started[dai->id] = false; 198 173 199 - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 200 - q6apm_graph_close(dai_data->graph[dai->id]); 201 - dai_data->graph[dai->id] = NULL; 202 - } 203 174 } 204 175 205 176 /** 206 177 * It is recommend to load DSP with source graph first and then sink 207 178 * graph, so sequence for playback and capture will be different 208 179 */ 209 - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 210 - graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id); 180 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && dai_data->graph[dai->id] == NULL) { 181 + graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id, substream->stream); 211 182 if (IS_ERR(graph)) { 212 183 dev_err(dai->dev, "Failed to open graph (%d)\n", graph_id); 213 184 rc = PTR_ERR(graph); ··· 224 203 dev_err(dai->dev, "Failed to prepare Graph %d\n", rc); 225 204 goto err; 226 205 } 227 - 228 - rc = q6apm_graph_start(dai_data->graph[dai->id]); 229 - if (rc < 0) { 230 - dev_err(dai->dev, "Failed to start APM port %d\n", dai->id); 231 - goto err; 232 - } 233 - dai_data->is_port_started[dai->id] = true; 234 - 235 206 return 0; 236 207 err: 237 208 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { ··· 240 227 int graph_id = dai->id; 241 228 242 229 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 243 - graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id); 230 + graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id, substream->stream); 244 231 if (IS_ERR(graph)) { 245 232 dev_err(dai->dev, "Failed to open graph (%d)\n", graph_id); 246 233 return PTR_ERR(graph); ··· 267 254 .shutdown = q6apm_lpass_dai_shutdown, 268 255 .set_channel_map = q6dma_set_channel_map, 269 256 .hw_params = q6dma_hw_params, 257 + .trigger = q6apm_lpass_dai_trigger, 270 258 }; 271 259 272 260 static const struct snd_soc_dai_ops q6i2s_ops = { ··· 277 263 .set_channel_map = q6dma_set_channel_map, 278 264 .hw_params = q6dma_hw_params, 279 265 .set_fmt = q6i2s_set_fmt, 266 + .trigger = q6apm_lpass_dai_trigger, 280 267 }; 281 268 282 269 static const struct snd_soc_dai_ops q6hdmi_ops = { ··· 286 271 .shutdown = q6apm_lpass_dai_shutdown, 287 272 .hw_params = q6hdmi_hw_params, 288 273 .set_fmt = q6i2s_set_fmt, 274 + .trigger = q6apm_lpass_dai_trigger, 289 275 }; 290 276 291 277 static const struct snd_soc_component_driver q6apm_lpass_dai_component = {
+122 -62
sound/soc/qcom/qdsp6/q6apm.c
··· 200 200 } 201 201 EXPORT_SYMBOL_GPL(q6apm_graph_media_format_shmem); 202 202 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) 203 + int q6apm_map_memory_fixed_region(struct device *dev, unsigned int graph_id, phys_addr_t phys, 204 + size_t sz) 205 + { 206 + struct audioreach_graph_info *info; 207 + struct q6apm *apm = dev_get_drvdata(dev->parent); 208 + struct apm_shared_map_region_payload *mregions; 209 + struct apm_cmd_shared_mem_map_regions *cmd; 210 + int payload_size = sizeof(*cmd) + (sizeof(*mregions)); 211 + uint32_t buf_sz; 212 + void *p; 213 + struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(payload_size, 214 + APM_CMD_SHARED_MEM_MAP_REGIONS, graph_id); 215 + if (IS_ERR(pkt)) 216 + return PTR_ERR(pkt); 217 + 218 + info = idr_find(&apm->graph_info_idr, graph_id); 219 + if (!info) 220 + return -ENODEV; 221 + 222 + if (info->mem_map_handle) 223 + return 0; 224 + 225 + /* DSP expects size should be aligned to 4K */ 226 + buf_sz = ALIGN(sz, 4096); 227 + 228 + p = (void *)pkt + GPR_HDR_SIZE; 229 + cmd = p; 230 + cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL; 231 + cmd->num_regions = 1; 232 + cmd->property_flag = 0x0; 233 + 234 + mregions = p + sizeof(*cmd); 235 + 236 + mregions->shm_addr_lsw = lower_32_bits(phys); 237 + mregions->shm_addr_msw = upper_32_bits(phys); 238 + mregions->mem_size_bytes = buf_sz; 239 + 240 + return q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS); 241 + } 242 + EXPORT_SYMBOL_GPL(q6apm_map_memory_fixed_region); 243 + 244 + int q6apm_alloc_fragments(struct q6apm_graph *graph, unsigned int dir, phys_addr_t phys, 245 + size_t period_sz, unsigned int periods) 205 246 { 206 247 struct audioreach_graph_data *data; 207 248 struct audio_buffer *buf; 208 249 int cnt; 209 - int rc; 210 250 211 251 if (dir == SNDRV_PCM_STREAM_PLAYBACK) 212 252 data = &graph->rx_data; ··· 254 214 data = &graph->tx_data; 255 215 256 216 mutex_lock(&graph->lock); 217 + 218 + data->dsp_buf = 0; 257 219 258 220 if (data->buf) { 259 221 mutex_unlock(&graph->lock); ··· 288 246 289 247 mutex_unlock(&graph->lock); 290 248 291 - rc = audioreach_map_memory_regions(graph, dir, period_sz, periods, 1); 292 - if (rc < 0) { 293 - dev_err(graph->dev, "Memory_map_regions failed\n"); 294 - audioreach_graph_free_buf(graph); 295 - } 296 - 297 - return rc; 249 + return 0; 298 250 } 299 - EXPORT_SYMBOL_GPL(q6apm_map_memory_regions); 251 + EXPORT_SYMBOL_GPL(q6apm_alloc_fragments); 300 252 301 - int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir) 253 + int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id) 302 254 { 303 255 struct apm_cmd_shared_mem_unmap_regions *cmd; 304 - struct audioreach_graph_data *data; 305 - int rc; 306 - 307 - if (dir == SNDRV_PCM_STREAM_PLAYBACK) 308 - data = &graph->rx_data; 309 - else 310 - data = &graph->tx_data; 311 - 312 - if (!data->mem_map_handle) 313 - return 0; 314 - 315 - struct gpr_pkt *pkt __free(kfree) = 316 - audioreach_alloc_apm_pkt(sizeof(*cmd), APM_CMD_SHARED_MEM_UNMAP_REGIONS, 317 - dir, graph->port->id); 256 + struct q6apm *apm = dev_get_drvdata(dev->parent); 257 + struct audioreach_graph_info *info; 258 + struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(sizeof(*cmd), 259 + APM_CMD_SHARED_MEM_UNMAP_REGIONS, graph_id); 318 260 if (IS_ERR(pkt)) 319 261 return PTR_ERR(pkt); 320 262 263 + info = idr_find(&apm->graph_info_idr, graph_id); 264 + if (!info) 265 + return -ENODEV; 266 + 267 + if (!info->mem_map_handle) 268 + return 0; 269 + 321 270 cmd = (void *)pkt + GPR_HDR_SIZE; 322 - cmd->mem_map_handle = data->mem_map_handle; 271 + cmd->mem_map_handle = info->mem_map_handle; 323 272 324 - rc = audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS); 273 + return q6apm_send_cmd_sync(apm, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS); 274 + } 275 + EXPORT_SYMBOL_GPL(q6apm_unmap_memory_fixed_region); 325 276 277 + int q6apm_free_fragments(struct q6apm_graph *graph, unsigned int dir) 278 + { 326 279 audioreach_graph_free_buf(graph); 327 280 328 - return rc; 281 + return 0; 329 282 } 330 - EXPORT_SYMBOL_GPL(q6apm_unmap_memory_regions); 283 + EXPORT_SYMBOL_GPL(q6apm_free_fragments); 331 284 332 285 int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples) 333 286 { ··· 446 409 { 447 410 struct apm_data_cmd_wr_sh_mem_ep_data_buffer_v2 *write_buffer; 448 411 struct audio_buffer *ab; 449 - int iid = q6apm_graph_get_rx_shmem_module_iid(graph); 450 412 451 413 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*write_buffer), 452 414 DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2, 453 415 graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT), 454 - graph->port->id, iid); 416 + graph->port->id, graph->shm_iid); 455 417 if (IS_ERR(pkt)) 456 418 return PTR_ERR(pkt); 457 419 ··· 464 428 write_buffer->buf_size = len; 465 429 write_buffer->timestamp_lsw = lsw_ts; 466 430 write_buffer->timestamp_msw = msw_ts; 467 - write_buffer->mem_map_handle = graph->rx_data.mem_map_handle; 431 + write_buffer->mem_map_handle = graph->info->mem_map_handle; 468 432 write_buffer->flags = wflags; 469 433 470 434 graph->rx_data.dsp_buf++; ··· 483 447 struct data_cmd_rd_sh_mem_ep_data_buffer_v2 *read_buffer; 484 448 struct audioreach_graph_data *port; 485 449 struct audio_buffer *ab; 486 - int iid = q6apm_graph_get_tx_shmem_module_iid(graph); 487 450 488 451 struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_pkt(sizeof(*read_buffer), 489 452 DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2, 490 - graph->tx_data.dsp_buf, graph->port->id, iid); 453 + graph->tx_data.dsp_buf, graph->port->id, graph->shm_iid); 491 454 if (IS_ERR(pkt)) 492 455 return PTR_ERR(pkt); 493 456 ··· 498 463 499 464 read_buffer->buf_addr_lsw = lower_32_bits(ab->phys); 500 465 read_buffer->buf_addr_msw = upper_32_bits(ab->phys); 501 - read_buffer->mem_map_handle = port->mem_map_handle; 466 + read_buffer->mem_map_handle = graph->info->mem_map_handle; 502 467 read_buffer->buf_size = ab->size; 503 468 504 469 port->dsp_buf++; ··· 529 494 { 530 495 struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done; 531 496 struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2 *done; 532 - struct apm_cmd_rsp_shared_mem_map_regions *rsp; 533 497 const struct gpr_ibasic_rsp_result_t *result; 534 498 struct q6apm_graph *graph = priv; 535 499 const struct gpr_hdr *hdr = &data->hdr; ··· 564 530 } 565 531 566 532 break; 567 - case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS: 568 - graph->result.opcode = hdr->opcode; 569 - graph->result.status = 0; 570 - rsp = data->payload; 571 - 572 - if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK) 573 - graph->rx_data.mem_map_handle = rsp->mem_map_handle; 574 - else 575 - graph->tx_data.mem_map_handle = rsp->mem_map_handle; 576 - 577 - wake_up(&graph->cmd_wait); 578 - break; 579 533 case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2: 580 534 if (!graph->ar_graph) 581 535 break; ··· 593 571 break; 594 572 case GPR_BASIC_RSP_RESULT: 595 573 switch (result->opcode) { 596 - case APM_CMD_SHARED_MEM_UNMAP_REGIONS: 597 - graph->result.opcode = result->opcode; 598 - graph->result.status = 0; 599 - if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK) 600 - graph->rx_data.mem_map_handle = 0; 601 - else 602 - graph->tx_data.mem_map_handle = 0; 603 - 604 - wake_up(&graph->cmd_wait); 605 - break; 606 574 case APM_CMD_SHARED_MEM_MAP_REGIONS: 607 575 case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT: 608 576 case APM_CMD_SET_CFG: ··· 614 602 } 615 603 616 604 struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb, 617 - void *priv, int graph_id) 605 + void *priv, int graph_id, int dir) 618 606 { 619 607 struct q6apm *apm = dev_get_drvdata(dev->parent); 620 608 struct audioreach_graph *ar_graph; ··· 640 628 graph->ar_graph = ar_graph; 641 629 graph->id = ar_graph->id; 642 630 graph->dev = dev; 631 + 632 + if (dir == SNDRV_PCM_STREAM_PLAYBACK) 633 + graph->shm_iid = q6apm_graph_get_rx_shmem_module_iid(graph); 634 + else 635 + graph->shm_iid = q6apm_graph_get_tx_shmem_module_iid(graph); 636 + 643 637 644 638 mutex_init(&graph->lock); 645 639 init_waitqueue_head(&graph->cmd_wait); ··· 765 747 766 748 q6apm_get_apm_state(apm); 767 749 768 - ret = devm_snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0); 750 + ret = snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0); 769 751 if (ret < 0) { 770 752 dev_err(dev, "failed to register q6apm: %d\n", ret); 771 753 return ret; 772 754 } 773 755 774 - return of_platform_populate(dev->of_node, NULL, NULL, dev); 756 + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); 757 + if (ret) 758 + snd_soc_unregister_component(dev); 759 + 760 + return ret; 761 + } 762 + 763 + static void apm_remove(gpr_device_t *gdev) 764 + { 765 + of_platform_depopulate(&gdev->dev); 766 + snd_soc_unregister_component(&gdev->dev); 775 767 } 776 768 777 769 struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, uint32_t mid) ··· 796 768 static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op) 797 769 { 798 770 gpr_device_t *gdev = priv; 771 + struct audioreach_graph_info *info; 799 772 struct q6apm *apm = dev_get_drvdata(&gdev->dev); 773 + struct apm_cmd_rsp_shared_mem_map_regions *rsp; 800 774 struct device *dev = &gdev->dev; 801 775 struct gpr_ibasic_rsp_result_t *result; 802 776 const struct gpr_hdr *hdr = &data->hdr; ··· 815 785 break; 816 786 case GPR_BASIC_RSP_RESULT: 817 787 switch (result->opcode) { 788 + case APM_CMD_SHARED_MEM_MAP_REGIONS: 818 789 case APM_CMD_GRAPH_START: 819 790 case APM_CMD_GRAPH_OPEN: 820 791 case APM_CMD_GRAPH_PREPARE: ··· 830 799 result->opcode); 831 800 wake_up(&apm->wait); 832 801 break; 802 + case APM_CMD_SHARED_MEM_UNMAP_REGIONS: 803 + apm->result.opcode = hdr->opcode; 804 + apm->result.status = 0; 805 + rsp = data->payload; 806 + 807 + info = idr_find(&apm->graph_info_idr, hdr->token); 808 + if (info) 809 + info->mem_map_handle = 0; 810 + else 811 + dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status, 812 + result->opcode); 813 + 814 + wake_up(&apm->wait); 815 + break; 833 816 default: 834 817 break; 835 818 } 819 + break; 820 + case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS: 821 + apm->result.opcode = hdr->opcode; 822 + apm->result.status = 0; 823 + rsp = data->payload; 824 + 825 + info = idr_find(&apm->graph_info_idr, hdr->token); 826 + if (info) 827 + info->mem_map_handle = rsp->mem_map_handle; 828 + else 829 + dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status, 830 + result->opcode); 831 + 832 + wake_up(&apm->wait); 836 833 break; 837 834 default: 838 835 break; ··· 879 820 880 821 static gpr_driver_t apm_driver = { 881 822 .probe = apm_probe, 823 + .remove = apm_remove, 882 824 .gpr_callback = apm_callback, 883 825 .driver = { 884 826 .name = "qcom-apm",
+12 -8
sound/soc/qcom/qdsp6/q6apm.h
··· 14 14 #include <linux/of_platform.h> 15 15 #include <linux/jiffies.h> 16 16 #include <linux/soc/qcom/apr.h> 17 + #include "../common.h" 17 18 #include "audioreach.h" 18 19 19 - #define APM_PORT_MAX 127 20 + #define APM_PORT_MAX LPASS_MAX_PORT 20 21 #define APM_PORT_MAX_AUDIO_CHAN_CNT 8 21 22 #define PCM_CHANNEL_NULL 0 22 23 #define PCM_CHANNEL_FL 1 /* Front left channel. */ ··· 78 77 struct audio_buffer *buf; 79 78 uint32_t num_periods; 80 79 uint32_t dsp_buf; 81 - uint32_t mem_map_handle; 82 80 atomic_t hw_ptr; 83 81 }; 84 82 ··· 98 98 void *priv; 99 99 q6apm_cb cb; 100 100 uint32_t id; 101 + uint32_t shm_iid; 101 102 struct device *dev; 102 103 struct q6apm *apm; 103 104 gpr_port_t *port; ··· 113 112 114 113 /* Graph Operations */ 115 114 struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb, 116 - void *priv, int graph_id); 115 + void *priv, int graph_id, int dir); 117 116 int q6apm_graph_close(struct q6apm_graph *graph); 118 117 int q6apm_graph_prepare(struct q6apm_graph *graph); 119 118 int q6apm_graph_start(struct q6apm_graph *graph); ··· 133 132 uint32_t lsw_ts, uint32_t wflags); 134 133 135 134 /* Memory Map related */ 136 - int q6apm_map_memory_regions(struct q6apm_graph *graph, 137 - unsigned int dir, phys_addr_t phys, 138 - size_t period_sz, unsigned int periods); 139 - int q6apm_unmap_memory_regions(struct q6apm_graph *graph, 140 - unsigned int dir); 135 + int q6apm_map_memory_fixed_region(struct device *dev, 136 + unsigned int graph_id, phys_addr_t phys, 137 + size_t sz); 138 + int q6apm_alloc_fragments(struct q6apm_graph *graph, 139 + unsigned int dir, phys_addr_t phys, 140 + size_t period_sz, unsigned int periods); 141 + int q6apm_free_fragments(struct q6apm_graph *graph, unsigned int dir); 142 + int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id); 141 143 /* Helpers */ 142 144 int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, 143 145 uint32_t rsp_opcode);
+76
sound/soc/qcom/qdsp6/q6dsp-lpass-ports.c
··· 96 96 .id = did, \ 97 97 } 98 98 99 + #define Q6AFE_MI2S_RX_DAI(pre, did) { \ 100 + .playback = { \ 101 + .stream_name = pre" MI2S Playback", \ 102 + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ 103 + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ 104 + SNDRV_PCM_RATE_176400, \ 105 + .formats = SNDRV_PCM_FMTBIT_S16_LE | \ 106 + SNDRV_PCM_FMTBIT_S24_LE | \ 107 + SNDRV_PCM_FMTBIT_S32_LE, \ 108 + .channels_min = 1, \ 109 + .channels_max = 8, \ 110 + .rate_min = 8000, \ 111 + .rate_max = 176400, \ 112 + }, \ 113 + .name = #did, \ 114 + .id = did, \ 115 + } 116 + 117 + #define Q6AFE_MI2S_TX_DAI(pre, did) { \ 118 + .capture = { \ 119 + .stream_name = pre" MI2S Capture", \ 120 + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ 121 + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ 122 + SNDRV_PCM_RATE_176400, \ 123 + .formats = SNDRV_PCM_FMTBIT_S16_LE | \ 124 + SNDRV_PCM_FMTBIT_S24_LE | \ 125 + SNDRV_PCM_FMTBIT_S32_LE, \ 126 + .channels_min = 1, \ 127 + .channels_max = 8, \ 128 + .rate_min = 8000, \ 129 + .rate_max = 176400, \ 130 + }, \ 131 + .name = #did, \ 132 + .id = did, \ 133 + } 134 + 99 135 static struct snd_soc_dai_driver q6dsp_audio_fe_dais[] = { 100 136 { 101 137 .playback = { ··· 519 483 }, 520 484 .id = QUINARY_MI2S_TX, 521 485 .name = "QUIN_MI2S_TX", 486 + }, { 487 + .playback = { 488 + .stream_name = "Senary MI2S Playback", 489 + .rates = SNDRV_PCM_RATE_8000_192000, 490 + .formats = SNDRV_PCM_FMTBIT_S16_LE | 491 + SNDRV_PCM_FMTBIT_S24_LE | 492 + SNDRV_PCM_FMTBIT_S32_LE, 493 + .channels_min = 1, 494 + .channels_max = 8, 495 + .rate_min = 8000, 496 + .rate_max = 192000, 497 + }, 498 + .id = SENARY_MI2S_RX, 499 + .name = "SEN_MI2S_RX", 500 + }, { 501 + .capture = { 502 + .stream_name = "Senary MI2S Capture", 503 + .rates = SNDRV_PCM_RATE_8000_192000, 504 + .formats = SNDRV_PCM_FMTBIT_S16_LE | 505 + SNDRV_PCM_FMTBIT_S24_LE | 506 + SNDRV_PCM_FMTBIT_S32_LE, 507 + .channels_min = 1, 508 + .channels_max = 8, 509 + .rate_min = 8000, 510 + .rate_max = 192000, 511 + }, 512 + .id = SENARY_MI2S_TX, 513 + .name = "SEN_MI2S_TX", 522 514 }, 515 + Q6AFE_MI2S_RX_DAI("LPI RX0", LPI_MI2S_RX_0), 516 + Q6AFE_MI2S_RX_DAI("LPI RX1", LPI_MI2S_RX_1), 517 + Q6AFE_MI2S_RX_DAI("LPI RX2", LPI_MI2S_RX_2), 518 + Q6AFE_MI2S_RX_DAI("LPI RX3", LPI_MI2S_RX_3), 519 + Q6AFE_MI2S_RX_DAI("LPI RX4", LPI_MI2S_RX_4), 520 + Q6AFE_MI2S_TX_DAI("LPI TX0", LPI_MI2S_TX_0), 521 + Q6AFE_MI2S_TX_DAI("LPI TX1", LPI_MI2S_TX_1), 522 + Q6AFE_MI2S_TX_DAI("LPI TX2", LPI_MI2S_TX_2), 523 + Q6AFE_MI2S_TX_DAI("LPI TX3", LPI_MI2S_TX_3), 524 + Q6AFE_MI2S_TX_DAI("LPI TX4", LPI_MI2S_TX_4), 523 525 Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0), 524 526 Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1), 525 527 Q6AFE_TDM_PB_DAI("Primary", 2, PRIMARY_TDM_RX_2), ··· 708 634 case SLIMBUS_0_RX ... SLIMBUS_6_TX: 709 635 q6dsp_audio_fe_dais[i].ops = cfg->q6slim_ops; 710 636 break; 637 + case SENARY_MI2S_RX ... SENARY_MI2S_TX: 711 638 case QUINARY_MI2S_RX ... QUINARY_MI2S_TX: 712 639 case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: 640 + case LPI_MI2S_RX_0 ... LPI_MI2S_TX_4: 713 641 q6dsp_audio_fe_dais[i].ops = cfg->q6i2s_ops; 714 642 break; 715 643 case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
+5 -3
sound/soc/qcom/qdsp6/topology.c
··· 952 952 struct audioreach_container *cont; 953 953 struct audioreach_module *mod; 954 954 955 - mod = dobj->private; 956 - cont = mod->container; 957 - 958 955 if (w->id == snd_soc_dapm_mixer) { 959 956 /* virtual widget */ 960 957 struct snd_ar_control *scontrol = dobj->private; ··· 960 963 kfree(scontrol); 961 964 return 0; 962 965 } 966 + mod = dobj->private; 967 + if (!mod) 968 + return 0; 969 + 970 + cont = mod->container; 963 971 964 972 mutex_lock(&apm->lock); 965 973 idr_remove(&apm->modules_idr, mod->instance_id);