diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml index b767625985a7..1c0ea0f389e4 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-dai.yaml @@ -10,7 +10,11 @@ maintainers: - Srinivas Kandagatla description: | - This binding describes the Qualcomm APM DAIs in DSP + This binding describes the Qualcomm APM DAIs in DSP. + When qcom,vmid is present, the driver performs SCM memory + assignment for PCM DMA buffers and any reserved-memory regions + listed in memory-region, granting the specified VMIDs RW access + while retaining HLOS as a co-owner. properties: compatible: @@ -20,9 +24,21 @@ properties: minItems: 1 maxItems: 2 + memory-region: + description: + List of phandles to reserved-memory regions (shared-dma-pool, + no-map) that must be SCM-assigned to the VMIDs in qcom,vmid. + The first entry is the control-path buffer; subsequent entries + are data-path buffers. Only meaningful when qcom,vmid is present. + minItems: 1 + maxItems: 8 + qcom,vmid: - description: Optional list of destination VMIDs to share PCM DMA buffers with. - HLOS retains RW access as source owner and must not be listed. + description: + Optional list of destination VMIDs to grant RW access to PCM DMA + buffers and any memory-region carveouts. HLOS retains RW access + as source owner and must not be listed. When present, + qcom_scm_is_available() must return true at probe time. $ref: /schemas/types.yaml#/definitions/uint32-array items: minimum: 1 @@ -32,7 +48,10 @@ properties: required: - compatible - - iommus + +dependentRequired: + memory-region: + - qcom,vmid additionalProperties: false @@ -42,3 +61,12 @@ examples: compatible = "qcom,q6apm-dais"; iommus = <&apps_smmu 0x1801 0x0>; }; + - | + #include + dais { + compatible = "qcom,q6apm-dais"; + iommus = <&apps_smmu 0x0c01 0x0>; + /* index 0: control path, index 1: data path */ + memory-region = <&audio_heap_mem &audio_mdsp_carveout_mem>; + qcom,vmid = ; + }; diff --git a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml index 0eae1c382f5e..2c3d4ba30013 100644 --- a/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,q6apm-lpass-dais.yaml @@ -49,14 +49,13 @@ patternProperties: clock-names: minItems: 1 + maxItems: 3 items: - - const: mclk - - const: bclk - - const: eclk + enum: [mclk, bclk, eclk] dependencies: - clocks: [ clock-names ] - clock-names: [ clocks ] + clocks: [clock-names] + clock-names: [clocks] required: - reg diff --git a/arch/arm64/boot/dts/qcom/shikra.dtsi b/arch/arm64/boot/dts/qcom/shikra.dtsi index b8b3b111c2b1..17b581a1631c 100644 --- a/arch/arm64/boot/dts/qcom/shikra.dtsi +++ b/arch/arm64/boot/dts/qcom/shikra.dtsi @@ -380,7 +380,14 @@ }; audio_heap_mem: audio-heap@86200000 { - reg = <0x0 0x86200000 0x0 0x100000>; + compatible = "shared-dma-pool"; + reg = <0x0 0x86200000 0x0 0x40000>; + no-map; + }; + + audio_mdsp_carveout_mem: audio-mdsp-carveout@86240000 { + compatible = "shared-dma-pool"; + reg = <0x0 0x86240000 0x0 0x100000>; no-map; }; @@ -2634,6 +2641,8 @@ q6apmdai: dais { compatible = "qcom,q6apm-dais"; + memory-region = <&audio_heap_mem + &audio_mdsp_carveout_mem>; qcom,vmid = ; }; diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 2eca25478fd4..3b893bbfb03b 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -112,6 +112,7 @@ config SND_SOC_QDSP6_ASM_DAI config SND_SOC_QDSP6_APM_DAI tristate + select QCOM_SCM select SND_SOC_COMPRESS config SND_SOC_QDSP6_APM_LPASS_DAI diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index 5bf1ddd4d587..7dfcde078989 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -217,7 +217,8 @@ struct apm_display_port_module_intf_cfg { #define APM_DP_INTF_CFG_PSIZE ALIGN(sizeof(struct apm_display_port_module_intf_cfg), 8) static void *__audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t token, - uint32_t src_port, uint32_t dest_port, bool has_cmd_hdr) + u32 src_port, u32 dest_port, u16 dest_domain, + bool has_cmd_hdr) { struct gpr_pkt *pkt; void *p; @@ -237,7 +238,10 @@ static void *__audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t pkt->hdr.dest_port = dest_port; pkt->hdr.src_port = src_port; - pkt->hdr.dest_domain = GPR_DOMAIN_ID_ADSP; + if (!dest_domain) + dest_domain = GPR_DOMAIN_ID_ADSP; + + pkt->hdr.dest_domain = dest_domain; pkt->hdr.src_domain = GPR_DOMAIN_ID_APPS; pkt->hdr.token = token; pkt->hdr.opcode = opcode; @@ -254,30 +258,34 @@ static void *__audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t } void *audioreach_alloc_pkt(int payload_size, uint32_t opcode, uint32_t token, - uint32_t src_port, uint32_t dest_port) + u32 src_port, u32 dest_port, u16 dest_domain) { - return __audioreach_alloc_pkt(payload_size, opcode, token, src_port, dest_port, false); + return __audioreach_alloc_pkt(payload_size, opcode, token, src_port, dest_port, + dest_domain, false); } EXPORT_SYMBOL_GPL(audioreach_alloc_pkt); -void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token, uint32_t src_port) +void *audioreach_alloc_apm_pkt(int pkt_size, u32 opcode, u32 token, + u32 src_port, u16 dest_domain) { return __audioreach_alloc_pkt(pkt_size, opcode, token, src_port, APM_MODULE_INSTANCE_ID, - false); + dest_domain, false); } EXPORT_SYMBOL_GPL(audioreach_alloc_apm_pkt); void *audioreach_alloc_cmd_pkt(int payload_size, uint32_t opcode, uint32_t token, - uint32_t src_port, uint32_t dest_port) + u32 src_port, u32 dest_port, u16 dest_domain) { - return __audioreach_alloc_pkt(payload_size, opcode, token, src_port, dest_port, true); + return __audioreach_alloc_pkt(payload_size, opcode, token, src_port, dest_port, + dest_domain, true); } EXPORT_SYMBOL_GPL(audioreach_alloc_cmd_pkt); -void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t token) +void *audioreach_alloc_apm_cmd_pkt(int pkt_size, u32 opcode, u32 token, + u16 dest_domain) { return __audioreach_alloc_pkt(pkt_size, opcode, token, GPR_APM_MODULE_IID, - APM_MODULE_INSTANCE_ID, true); + APM_MODULE_INSTANCE_ID, dest_domain, true); } EXPORT_SYMBOL_GPL(audioreach_alloc_apm_cmd_pkt); @@ -472,6 +480,7 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info int num_sub_graphs = 0; int num_modules = 0; int num_modules_list; + u16 dest_domain = audioreach_gpr_dest_domain(apm->gdev); struct gpr_pkt *pkt; void *p; @@ -506,7 +515,8 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info mc_sz = APM_MOD_CONN_PSIZE(mcon, num_connections); payload_size = sg_sz + cont_sz + ml_sz + mp_sz + mc_sz; - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_GRAPH_OPEN, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_GRAPH_OPEN, 0, + dest_domain); if (IS_ERR(pkt)) return pkt; @@ -630,6 +640,7 @@ static int audioreach_display_port_set_media_format(struct q6apm_graph *graph, int rc, payload_size; struct gpr_pkt *pkt; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); ic_sz = APM_DP_INTF_CFG_PSIZE; ep_sz = APM_HW_EP_CFG_PSIZE; @@ -638,7 +649,8 @@ static int audioreach_display_port_set_media_format(struct q6apm_graph *graph, payload_size = ic_sz + ep_sz + fs_sz + dl_sz; - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -698,6 +710,7 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph, int rc, payload_size; struct gpr_pkt *pkt; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); ic_sz = APM_CDMA_INTF_CFG_PSIZE; ep_sz = APM_HW_EP_CFG_PSIZE; @@ -707,7 +720,8 @@ static int audioreach_codec_dma_set_media_format(struct q6apm_graph *graph, payload_size = ic_sz + ep_sz + fs_sz + pm_sz + dl_sz; - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -770,9 +784,11 @@ int audioreach_send_u32_param(struct q6apm_graph *graph, struct audioreach_modul uint32_t *param; int rc, payload_size; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); payload_size = sizeof(uint32_t) + APM_MODULE_PARAM_DATA_SIZE; - p = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + p = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(p)) return -ENOMEM; @@ -826,15 +842,17 @@ static int audioreach_gapless_set_media_format(struct q6apm_graph *graph, } static int audioreach_set_module_config(struct q6apm_graph *graph, - struct audioreach_module *module, - struct audioreach_module_config *cfg) + struct audioreach_module *module, + struct audioreach_module_config *cfg) { int payload_size = le32_to_cpu(module->data->size); struct gpr_pkt *pkt; int rc; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -860,11 +878,13 @@ static int audioreach_mfc_set_media_format(struct q6apm_graph *graph, struct gpr_pkt *pkt; int rc, i; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); payload_size = APM_MFC_CFG_PSIZE(media_format, num_channels) + APM_MODULE_PARAM_DATA_SIZE; - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -979,12 +999,13 @@ int audioreach_compr_set_param(struct q6apm_graph *graph, struct audioreach_modu struct gpr_pkt *pkt; int iid, payload_size, rc; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); payload_size = sizeof(struct apm_sh_module_media_fmt_cmd); iid = q6apm_graph_get_rx_shmem_module_iid(graph); pkt = audioreach_alloc_cmd_pkt(payload_size, DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT, - 0, graph->port->id, iid); + 0, graph->port->id, iid, dest_domain); if (IS_ERR(pkt)) return -ENOMEM; @@ -1016,6 +1037,7 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph, int rc, payload_size; struct gpr_pkt *pkt; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); ic_sz = APM_I2S_INTF_CFG_PSIZE; ep_sz = APM_HW_EP_CFG_PSIZE; @@ -1023,7 +1045,8 @@ static int audioreach_i2s_set_media_format(struct q6apm_graph *graph, payload_size = ic_sz + ep_sz + fs_sz; - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -1103,7 +1126,10 @@ static int audioreach_audio_if_set_media_format(struct q6apm_graph *graph, u16 slot_width = cfg->slot_width ? (u16)cfg->slot_width : module->slot_width; void *p; - struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0); + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); + struct gpr_pkt *pkt __free(kfree) = + audioreach_alloc_apm_cmd_pkt(size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -1168,9 +1194,11 @@ static int audioreach_logging_set_media_format(struct q6apm_graph *graph, int rc, payload_size; struct gpr_pkt *pkt; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); payload_size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE; - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -1205,6 +1233,7 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, struct apm_module_param_data *param_data; int rc, payload_size; struct gpr_pkt *pkt; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); if (num_channels > 4) { dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels); @@ -1213,7 +1242,8 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, payload_size = APM_PCM_MODULE_FMT_CMD_PSIZE(num_channels); - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -1257,6 +1287,7 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, int rc, payload_size; struct gpr_pkt *pkt; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); if (num_channels > 4) { dev_err(graph->dev, "Error: Invalid channels (%d)!\n", num_channels); @@ -1266,7 +1297,8 @@ static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, payload_size = APM_SHMEM_FMT_CFG_PSIZE(num_channels) + APM_MODULE_PARAM_DATA_SIZE; pkt = audioreach_alloc_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, - graph->port->id, module->instance_id); + graph->port->id, module->instance_id, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -1317,9 +1349,11 @@ int audioreach_gain_set_vol_ctrl(struct q6apm *apm, struct audioreach_module *mo int rc, payload_size; struct gpr_pkt *pkt; void *p; + u16 dest_domain = audioreach_gpr_dest_domain(apm->gdev); payload_size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE; - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -1348,9 +1382,11 @@ static int audioreach_gain_set(struct q6apm_graph *graph, struct audioreach_modu struct apm_gain_module_cfg *cfg; int rc, payload_size; struct gpr_pkt *pkt; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); payload_size = APM_GAIN_CFG_PSIZE; - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0); + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -1449,79 +1485,16 @@ void audioreach_graph_free_buf(struct q6apm_graph *graph) } EXPORT_SYMBOL_GPL(audioreach_graph_free_buf); -int audioreach_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, size_t period_sz, - unsigned int periods, bool is_contiguous) -{ - struct apm_shared_map_region_payload *mregions; - struct apm_cmd_shared_mem_map_regions *cmd; - uint32_t num_regions, buf_sz, payload_size; - struct audioreach_graph_data *data; - struct gpr_pkt *pkt; - void *p; - int rc, i; - - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - data = &graph->rx_data; - else - data = &graph->tx_data; - - if (is_contiguous) { - num_regions = 1; - buf_sz = period_sz * periods; - } else { - buf_sz = period_sz; - num_regions = periods; - } - - /* DSP expects size should be aligned to 4K */ - buf_sz = ALIGN(buf_sz, 4096); - - payload_size = sizeof(*cmd) + (sizeof(*mregions) * num_regions); - - pkt = audioreach_alloc_apm_pkt(payload_size, APM_CMD_SHARED_MEM_MAP_REGIONS, dir, - graph->port->id); - if (IS_ERR(pkt)) - return PTR_ERR(pkt); - - p = (void *)pkt + GPR_HDR_SIZE; - cmd = p; - cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL; - cmd->num_regions = num_regions; - - cmd->property_flag = 0x0; - - mregions = p + sizeof(*cmd); - - mutex_lock(&graph->lock); - - for (i = 0; i < num_regions; i++) { - struct audio_buffer *ab; - - ab = &data->buf[i]; - mregions->shm_addr_lsw = lower_32_bits(ab->phys); - mregions->shm_addr_msw = upper_32_bits(ab->phys); - mregions->mem_size_bytes = buf_sz; - ++mregions; - } - mutex_unlock(&graph->lock); - - rc = audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS); - - kfree(pkt); - - return rc; -} -EXPORT_SYMBOL_GPL(audioreach_map_memory_regions); - int audioreach_shared_memory_send_eos(struct q6apm_graph *graph) { struct data_cmd_wr_sh_mem_ep_eos *eos; struct gpr_pkt *pkt; int rc = 0, iid; + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); iid = q6apm_graph_get_rx_shmem_module_iid(graph); pkt = audioreach_alloc_cmd_pkt(sizeof(*eos), DATA_CMD_WR_SH_MEM_EP_EOS, 0, - graph->port->id, iid); + graph->port->id, iid, dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index 290f8f60bb46..0493eb1c73f9 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -720,6 +720,7 @@ struct audioreach_connection { struct audioreach_graph_info { int id; + u32 mem_map_handle; uint32_t num_sub_graphs; struct list_head sg_list; /* DPCM connection from FE Graph to BE graph */ @@ -843,17 +844,20 @@ struct audioreach_module_config { }; /* Packet Allocation routines */ -void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, uint32_t - token); +static inline u16 audioreach_gpr_dest_domain(gpr_device_t *gdev) +{ + return gdev && gdev->domain_id ? gdev->domain_id : GPR_DOMAIN_ID_ADSP; +} + +void *audioreach_alloc_apm_cmd_pkt(int pkt_size, u32 opcode, u32 token, + u16 dest_domain); void audioreach_set_default_channel_mapping(u8 *ch_map, int num_channels); -void *audioreach_alloc_cmd_pkt(int payload_size, uint32_t opcode, - uint32_t token, uint32_t src_port, - uint32_t dest_port); -void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token, - uint32_t src_port); -void *audioreach_alloc_pkt(int payload_size, uint32_t opcode, - uint32_t token, uint32_t src_port, - uint32_t dest_port); +void *audioreach_alloc_cmd_pkt(int payload_size, u32 opcode, u32 token, + u32 src_port, u32 dest_port, u16 dest_domain); +void *audioreach_alloc_apm_pkt(int pkt_size, u32 opcode, u32 token, + u32 src_port, u16 dest_domain); +void *audioreach_alloc_pkt(int payload_size, u32 opcode, u32 token, + u32 src_port, u32 dest_port, u16 dest_domain); void *audioreach_alloc_graph_pkt(struct q6apm *apm, struct audioreach_graph_info *info); /* Topology specific */ @@ -861,10 +865,6 @@ int audioreach_tplg_init(struct snd_soc_component *component); /* Module specific */ void audioreach_graph_free_buf(struct q6apm_graph *graph); -int audioreach_map_memory_regions(struct q6apm_graph *graph, - unsigned int dir, size_t period_sz, - unsigned int periods, - bool is_contiguous); int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, struct gpr_ibasic_rsp_result_t *result, struct mutex *cmd_lock, gpr_port_t *port, wait_queue_head_t *cmd_wait, struct gpr_pkt *pkt, uint32_t rsp_opcode); diff --git a/sound/soc/qcom/qdsp6/q6apm-dai.c b/sound/soc/qcom/qdsp6/q6apm-dai.c index 54c1a33f9f93..585372a74199 100644 --- a/sound/soc/qcom/qdsp6/q6apm-dai.c +++ b/sound/soc/qcom/qdsp6/q6apm-dai.c @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include "q6apm.h" @@ -33,6 +35,9 @@ #define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4) #define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024) #define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4) +#define Q6APM_SCM_MAX_VMID 31 +#define Q6APM_MAX_VMIDS 8 +#define Q6APM_MAX_CARVEOUTS 8 #define SID_MASK_DEFAULT 0xF static const struct snd_compr_codec_caps q6apm_compr_caps = { @@ -78,10 +83,212 @@ struct q6apm_dai_rtd { bool notify_on_drain; }; +struct q6apm_scm_region { + phys_addr_t dma_addr; + unsigned int size; + u64 src_perms; + bool assigned; +}; + struct q6apm_dai_data { long long sid; + int num_vmids; + u32 vmids[Q6APM_MAX_VMIDS]; + bool use_scm_assign; + struct q6apm_scm_region scm_regions[SNDRV_PCM_STREAM_LAST + 1]; + /* + * carveout regions from memory-region DT property + * (index 0: control path, index 1+: data path) + */ + struct q6apm_scm_region carveout_regions[Q6APM_MAX_CARVEOUTS]; + int num_carveouts; + /* true when memory-region DT property is present and DMA pool attached */ + bool has_reserved_mem; + /* size of the data-path reserved region, capped at BUFFER_BYTES_MAX */ + size_t reserved_buf_size; }; +static int q6apm_dai_assign_memory(struct snd_pcm_substream *substream, + struct q6apm_dai_data *pdata) +{ + struct q6apm_scm_region *scm_region = &pdata->scm_regions[substream->stream]; + struct qcom_scm_vmperm *dst_vmids; + int dst_count = 0; + int ret; + int i; + + if (!pdata->use_scm_assign || pdata->num_vmids <= 0 || scm_region->assigned) + return 0; + + if (!substream->dma_buffer.addr) + return -ENOMEM; + + dst_vmids = kcalloc(pdata->num_vmids + 1, sizeof(*dst_vmids), GFP_KERNEL); + if (!dst_vmids) + return -ENOMEM; + + /* Always keep HLOS RW so CPU can continue buffer access. */ + dst_vmids[dst_count].vmid = QCOM_SCM_VMID_HLOS; + dst_vmids[dst_count].perm = QCOM_SCM_PERM_RW; + dst_count++; + + for (i = 0; i < pdata->num_vmids; i++) { + /* + * Probe-time validation rejects HLOS in qcom,vmid, so this is + * only a defensive check for future non-DT vmids[] population. + */ + if (WARN_ON_ONCE(pdata->vmids[i] == QCOM_SCM_VMID_HLOS)) + continue; + + dst_vmids[dst_count].vmid = pdata->vmids[i]; + dst_vmids[dst_count].perm = QCOM_SCM_PERM_RW; + dst_count++; + } + + /* Nothing to assign beyond HLOS access. */ + if (dst_count == 1) { + kfree(dst_vmids); + return 0; + } + + scm_region->dma_addr = substream->dma_buffer.addr; + scm_region->size = ALIGN(BUFFER_BYTES_MAX, PAGE_SIZE); + scm_region->src_perms = BIT_ULL(QCOM_SCM_VMID_HLOS); + + ret = qcom_scm_assign_mem(scm_region->dma_addr, scm_region->size, + &scm_region->src_perms, dst_vmids, dst_count); + kfree(dst_vmids); + if (ret) + return ret; + + scm_region->assigned = true; + return 0; +} + +static int q6apm_dai_unassign_memory(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct q6apm_dai_data *pdata) +{ + struct q6apm_scm_region *scm_region = &pdata->scm_regions[substream->stream]; + struct qcom_scm_vmperm hlos = { + .vmid = QCOM_SCM_VMID_HLOS, + .perm = QCOM_SCM_PERM_RW, + }; + struct device *dev = component->dev; + int ret; + + if (!pdata->use_scm_assign || !scm_region->assigned) + return 0; + + ret = qcom_scm_assign_mem(scm_region->dma_addr, scm_region->size, + &scm_region->src_perms, &hlos, 1); + if (!ret) { + scm_region->assigned = false; + scm_region->src_perms = BIT_ULL(QCOM_SCM_VMID_HLOS); + } else { + dev_err(dev, "Failed to unassign DMA buffer %pa from VMIDs: %d\n", + &scm_region->dma_addr, ret); + } + + return ret; +} + +static int q6apm_dai_assign_one_region(struct q6apm_scm_region *region, + struct q6apm_dai_data *pdata) +{ + struct qcom_scm_vmperm *dst_vmids; + int dst_count = 0; + int ret, i; + + if (region->assigned) + return 0; + + dst_vmids = kcalloc(pdata->num_vmids + 1, sizeof(*dst_vmids), + GFP_KERNEL); + if (!dst_vmids) + return -ENOMEM; + + /* Always keep HLOS RW so CPU can continue carveout access. */ + dst_vmids[dst_count].vmid = QCOM_SCM_VMID_HLOS; + dst_vmids[dst_count].perm = QCOM_SCM_PERM_RW; + dst_count++; + + for (i = 0; i < pdata->num_vmids; i++) { + if (WARN_ON_ONCE(pdata->vmids[i] == QCOM_SCM_VMID_HLOS)) + continue; + dst_vmids[dst_count].vmid = pdata->vmids[i]; + dst_vmids[dst_count].perm = QCOM_SCM_PERM_RW; + dst_count++; + } + + if (dst_count == 1) { + /* Nothing to assign beyond HLOS access. */ + kfree(dst_vmids); + return 0; + } + + ret = qcom_scm_assign_mem(region->dma_addr, region->size, + ®ion->src_perms, dst_vmids, dst_count); + kfree(dst_vmids); + if (!ret) + region->assigned = true; + return ret; +} + +static int q6apm_dai_assign_carveout(struct q6apm_dai_data *pdata) +{ + int i, ret; + + if (!pdata->use_scm_assign || !pdata->num_carveouts) + return 0; + + for (i = 0; i < pdata->num_carveouts; i++) { + ret = q6apm_dai_assign_one_region(&pdata->carveout_regions[i], + pdata); + if (ret) + return ret; + } + return 0; +} + +static void q6apm_dai_unassign_one_region(struct snd_soc_component *component, + struct q6apm_scm_region *region) +{ + struct device *dev = component->dev; + struct qcom_scm_vmperm hlos = { + .vmid = QCOM_SCM_VMID_HLOS, + .perm = QCOM_SCM_PERM_RW, + }; + int ret; + + if (!region->assigned) + return; + + ret = qcom_scm_assign_mem(region->dma_addr, region->size, + ®ion->src_perms, &hlos, 1); + if (!ret) { + region->assigned = false; + region->src_perms = BIT_ULL(QCOM_SCM_VMID_HLOS); + } else { + dev_err(dev, + "Failed to unassign carveout %pa from VMIDs: %d\n", + ®ion->dma_addr, ret); + } +} + +static void q6apm_dai_unassign_carveout(struct snd_soc_component *component, + struct q6apm_dai_data *pdata) +{ + int i; + + if (!pdata->use_scm_assign || !pdata->num_carveouts) + return; + + for (i = 0; i < pdata->num_carveouts; i++) + q6apm_dai_unassign_one_region(component, + &pdata->carveout_regions[i]); +} + static const struct snd_pcm_hardware q6apm_dai_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | @@ -238,7 +445,7 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, if (prtd->state) { /* clear the previous setup if any */ q6apm_graph_stop(prtd->graph); - q6apm_unmap_memory_regions(prtd->graph, substream->stream); + q6apm_free_fragments(prtd->graph, substream->stream); } prtd->pcm_count = snd_pcm_lib_period_bytes(substream); @@ -253,9 +460,8 @@ static int q6apm_dai_prepare(struct snd_soc_component *component, if (ret < 0) dev_err(dev, "%s: CMD Format block failed\n", __func__); - ret = q6apm_map_memory_regions(prtd->graph, substream->stream, prtd->phys, - (prtd->pcm_size / prtd->periods), prtd->periods); - + ret = q6apm_alloc_fragments(prtd->graph, substream->stream, prtd->phys, + (prtd->pcm_size / prtd->periods), prtd->periods); if (ret < 0) { dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n", ret); return -ENOMEM; @@ -424,7 +630,7 @@ static int q6apm_dai_close(struct snd_soc_component *component, if (prtd->state) { /* only stop graph that is started */ q6apm_graph_stop(prtd->graph); - q6apm_unmap_memory_regions(prtd->graph, substream->stream); + q6apm_free_fragments(prtd->graph, substream->stream); } q6apm_graph_close(prtd->graph); @@ -473,11 +679,146 @@ static int q6apm_dai_hw_params(struct snd_soc_component *component, return 0; } +static void q6apm_dai_memory_unmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + +static int q6apm_dai_memory_map(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int graph_id) +{ + struct q6apm_dai_data *pdata; + struct device *dev = component->dev; + phys_addr_t phys; + int ret; + + pdata = snd_soc_component_get_drvdata(component); + if (!pdata) { + dev_err(component->dev, "Drv data not found ..\n"); + return -EINVAL; + } + + if (pdata->sid < 0) + phys = substream->dma_buffer.addr; + else + phys = substream->dma_buffer.addr | (pdata->sid << 32); + + ret = q6apm_map_memory_fixed_region(dev, graph_id, phys, BUFFER_BYTES_MAX); + if (ret < 0) + dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n", ret); + + return ret; +} + static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd) { + struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + struct q6apm_dai_data *pdata = snd_soc_component_get_drvdata(component); + struct snd_pcm *pcm = rtd->pcm; int size = BUFFER_BYTES_MAX; + int graph_id, ret; + struct snd_pcm_substream *substream; + + if (!pdata) + return -EINVAL; + + graph_id = cpu_dai->driver->id; + + /* + * When a reserved DMA pool is attached (memory-region in DT), allocate + * PCM buffers from it so the DSP accesses the carveout address directly. + * Fall back to the standard fixed system-RAM buffer on other platforms. + */ + if (pdata->has_reserved_mem) + ret = snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, + component->dev, + pdata->reserved_buf_size, + pdata->reserved_buf_size); + else + ret = snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, + component->dev, size); + if (ret) + return ret; + + /* Note: DSP backend dais are uni-directional ONLY(either playback or capture) */ + if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { + substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + ret = q6apm_dai_memory_map(component, substream, graph_id); + if (ret) + return ret; + if (pdata->use_scm_assign) { + ret = q6apm_dai_assign_memory(substream, pdata); + if (ret) { + q6apm_dai_memory_unmap(component, substream); + return ret; + } + } + } + + if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { + substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + ret = q6apm_dai_memory_map(component, substream, graph_id); + if (ret) + return ret; + if (pdata->use_scm_assign) { + ret = q6apm_dai_assign_memory(substream, pdata); + if (ret) { + q6apm_dai_memory_unmap(component, substream); + return ret; + } + } + } + + if (pdata->use_scm_assign && pdata->num_carveouts) { + ret = q6apm_dai_assign_carveout(pdata); + if (ret) + return ret; + } + + return 0; +} + +static void q6apm_dai_memory_unmap(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *soc_prtd; + struct snd_soc_dai *cpu_dai; + int graph_id; - return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, size); + soc_prtd = snd_soc_substream_to_rtd(substream); + if (!soc_prtd) + return; + + cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0); + if (!cpu_dai) + return; + + graph_id = cpu_dai->driver->id; + q6apm_unmap_memory_fixed_region(component->dev, graph_id); +} + +static void q6apm_dai_pcm_free(struct snd_soc_component *component, struct snd_pcm *pcm) +{ + struct q6apm_dai_data *pdata = snd_soc_component_get_drvdata(component); + struct snd_pcm_substream *substream; + + if (!pdata) + return; + + if (pdata->use_scm_assign && pdata->num_carveouts) + q6apm_dai_unassign_carveout(component, pdata); + + substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; + if (substream) { + if (pdata->use_scm_assign) + q6apm_dai_unassign_memory(component, substream, pdata); + q6apm_dai_memory_unmap(component, substream); + } + + substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (substream) { + if (pdata->use_scm_assign) + q6apm_dai_unassign_memory(component, substream, pdata); + q6apm_dai_memory_unmap(component, substream); + } } static int q6apm_dai_compr_open(struct snd_soc_component *component, @@ -535,7 +876,8 @@ static int q6apm_dai_compr_free(struct snd_soc_component *component, struct q6apm_dai_rtd *prtd = runtime->private_data; q6apm_graph_stop(prtd->graph); - q6apm_unmap_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK); + q6apm_free_fragments(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK); + q6apm_unmap_memory_fixed_region(component->dev, prtd->graph->id); q6apm_graph_close(prtd->graph); snd_dma_free_pages(&prtd->dma_buffer); prtd->graph = NULL; @@ -688,9 +1030,9 @@ static int q6apm_dai_compr_set_params(struct snd_soc_component *component, if (ret) return ret; - ret = q6apm_map_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK, - prtd->phys, (prtd->pcm_size / prtd->periods), - prtd->periods); + ret = q6apm_alloc_fragments(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK, + prtd->phys, (prtd->pcm_size / prtd->periods), + prtd->periods); if (ret < 0) return -ENOMEM; @@ -846,6 +1188,7 @@ static const struct snd_soc_component_driver q6apm_fe_dai_component = { .close = q6apm_dai_close, .prepare = q6apm_dai_prepare, .pcm_construct = q6apm_dai_pcm_new, + .pcm_destruct = q6apm_dai_pcm_free, .hw_params = q6apm_dai_hw_params, .pointer = q6apm_dai_pointer, .trigger = q6apm_dai_trigger, @@ -861,6 +1204,7 @@ static int q6apm_dai_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; struct q6apm_dai_data *pdata; struct of_phandle_args args; + int vmids; int rc; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -873,6 +1217,118 @@ static int q6apm_dai_probe(struct platform_device *pdev) else pdata->sid = args.args[0] & SID_MASK_DEFAULT; + vmids = of_property_count_u32_elems(node, "qcom,vmid"); + if (vmids == -EINVAL) { + pdata->num_vmids = 0; + pdata->use_scm_assign = false; + } else if (vmids < 0) { + return vmids; + } else if (vmids == 0) { + dev_err(dev, "qcom,vmid must contain at least one VMID\n"); + return -EINVAL; + } else if (vmids > Q6APM_MAX_VMIDS) { + dev_err(dev, "qcom,vmid: %d VMIDs exceeds maximum of %d\n", + vmids, Q6APM_MAX_VMIDS); + return -EINVAL; + } + + if (vmids > 0) { + int i; + + rc = of_property_read_u32_array(node, "qcom,vmid", + pdata->vmids, vmids); + if (rc) + return rc; + for (i = 0; i < vmids; i++) { + if (pdata->vmids[i] == QCOM_SCM_VMID_HLOS) { + dev_err(dev, "qcom,vmid must not include HLOS VMID (%u)\n", + QCOM_SCM_VMID_HLOS); + return -EINVAL; + } + if (pdata->vmids[i] > Q6APM_SCM_MAX_VMID) { + dev_err(dev, "qcom,vmid[%d]=%u exceeds SCM max VMID %u\n", + i, pdata->vmids[i], Q6APM_SCM_MAX_VMID); + return -EINVAL; + } + } + pdata->num_vmids = vmids; + pdata->use_scm_assign = true; + } + + /* + * Attach the data-path reserved memory region (index 1 in + * memory-region, e.g. audio_mdsp_carveout_mem on shikra) as a DMA + * pool so that snd_pcm_set_managed_buffer_all() allocates PCM + * buffers from the carveout instead of system RAM. The size is read + * from the DT node and capped at BUFFER_BYTES_MAX. + * Index 0 is the control-path carveout (SCM-assigned separately). + * Platforms without memory-region are completely unaffected. + */ + if (of_property_present(node, "memory-region")) { + struct device_node *rmem_node; + struct reserved_mem *rmem = NULL; + + /* index 1 = data path (PCM DMA buffer pool) */ + rmem_node = of_parse_phandle(node, "memory-region", 1); + if (rmem_node) { + rmem = of_reserved_mem_lookup(rmem_node); + of_node_put(rmem_node); + } + + if (rmem) { + rc = of_reserved_mem_device_init_by_idx(dev, node, 1); + if (rc) { + dev_err(dev, + "failed to attach reserved memory pool: %d\n", + rc); + return rc; + } + rc = devm_add_action_or_reset(dev, + (void (*)(void *)) + of_reserved_mem_device_release, + dev); + if (rc) + return rc; + pdata->reserved_buf_size = min_t(size_t, rmem->size, + BUFFER_BYTES_MAX); + pdata->has_reserved_mem = true; + } else { + dev_warn(dev, + "memory-region index 1 not found, using system RAM\n"); + } + } + + if (pdata->use_scm_assign) { + struct device_node *mem_node; + int idx = 0; + + while ((mem_node = of_parse_phandle(node, "memory-region", + idx++))) { + struct reserved_mem *rmem; + struct q6apm_scm_region *r; + + if (pdata->num_carveouts >= Q6APM_MAX_CARVEOUTS) { + dev_warn(dev, + "memory-region: too many entries, ignoring rest\n"); + of_node_put(mem_node); + break; + } + + rmem = of_reserved_mem_lookup(mem_node); + of_node_put(mem_node); + if (!rmem) + continue; + + r = &pdata->carveout_regions[pdata->num_carveouts++]; + r->dma_addr = rmem->base; + r->size = ALIGN(rmem->size, PAGE_SIZE); + r->src_perms = BIT_ULL(QCOM_SCM_VMID_HLOS); + } + } + + if (pdata->use_scm_assign && !qcom_scm_is_available()) + return -EPROBE_DEFER; + dev_set_drvdata(dev, pdata); return devm_snd_soc_register_component(dev, &q6apm_fe_dai_component, NULL, 0); diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index f32af288edd2..15c3ddb03181 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -104,7 +104,10 @@ static int audioreach_graph_mgmt_cmd(struct audioreach_graph *graph, uint32_t op payload_size = APM_GRAPH_MGMT_PSIZE(mgmt_cmd, num_sub_graphs); - pkt = audioreach_alloc_apm_cmd_pkt(payload_size, opcode, 0); + u16 dest_domain = audioreach_gpr_dest_domain(apm->gdev); + + pkt = audioreach_alloc_apm_cmd_pkt(payload_size, opcode, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -150,7 +153,10 @@ static int q6apm_get_apm_state(struct q6apm *apm) { struct gpr_pkt *pkt; - pkt = audioreach_alloc_apm_cmd_pkt(0, APM_CMD_GET_SPF_STATE, 0); + u16 dest_domain = audioreach_gpr_dest_domain(apm->gdev); + + pkt = audioreach_alloc_apm_cmd_pkt(0, APM_CMD_GET_SPF_STATE, 0, + dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -210,13 +216,57 @@ int q6apm_graph_media_format_shmem(struct q6apm_graph *graph, } EXPORT_SYMBOL_GPL(q6apm_graph_media_format_shmem); -int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_addr_t phys, - size_t period_sz, unsigned int periods) +int q6apm_map_memory_fixed_region(struct device *dev, unsigned int graph_id, phys_addr_t phys, + size_t sz) +{ + struct audioreach_graph_info *info; + struct q6apm *apm = dev_get_drvdata(dev->parent); + struct apm_shared_map_region_payload *mregions; + struct apm_cmd_shared_mem_map_regions *cmd; + int payload_size = sizeof(*cmd) + (sizeof(*mregions)); + u32 buf_sz; + void *p; + u16 dest_domain = audioreach_gpr_dest_domain(apm->gdev); + struct gpr_pkt *pkt __free(kfree) = + audioreach_alloc_apm_cmd_pkt(payload_size, + APM_CMD_SHARED_MEM_MAP_REGIONS, + graph_id, dest_domain); + if (IS_ERR(pkt)) + return PTR_ERR(pkt); + + info = idr_find(&apm->graph_info_idr, graph_id); + if (!info) + return -ENODEV; + + if (info->mem_map_handle) + return 0; + + /* DSP expects size should be aligned to 4K */ + buf_sz = ALIGN(sz, 4096); + + p = (void *)pkt + GPR_HDR_SIZE; + cmd = p; + cmd->mem_pool_id = APM_MEMORY_MAP_SHMEM8_4K_POOL; + cmd->num_regions = 1; + cmd->property_flag = 0x0; + + mregions = p + sizeof(*cmd); + + mregions->shm_addr_lsw = lower_32_bits(phys); + mregions->shm_addr_msw = upper_32_bits(phys); + mregions->mem_size_bytes = buf_sz; + + return q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_SHARED_MEM_MAP_REGIONS); +} +EXPORT_SYMBOL_GPL(q6apm_map_memory_fixed_region); + +int q6apm_alloc_fragments(struct q6apm_graph *graph, unsigned int dir, + phys_addr_t phys, size_t period_sz, + unsigned int periods) { struct audioreach_graph_data *data; struct audio_buffer *buf; int cnt; - int rc; if (dir == SNDRV_PCM_STREAM_PLAYBACK) data = &graph->rx_data; @@ -258,47 +308,44 @@ int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_a mutex_unlock(&graph->lock); - rc = audioreach_map_memory_regions(graph, dir, period_sz, periods, 1); - if (rc < 0) { - dev_err(graph->dev, "Memory_map_regions failed\n"); - audioreach_graph_free_buf(graph); - } - - return rc; + return 0; } -EXPORT_SYMBOL_GPL(q6apm_map_memory_regions); +EXPORT_SYMBOL_GPL(q6apm_alloc_fragments); -int q6apm_unmap_memory_regions(struct q6apm_graph *graph, unsigned int dir) +int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id) { struct apm_cmd_shared_mem_unmap_regions *cmd; - struct audioreach_graph_data *data; - struct gpr_pkt *pkt; - int rc; + struct q6apm *apm = dev_get_drvdata(dev->parent); + struct audioreach_graph_info *info; + u16 dest_domain = audioreach_gpr_dest_domain(apm->gdev); + struct gpr_pkt *pkt __free(kfree) = + audioreach_alloc_apm_cmd_pkt(sizeof(*cmd), + APM_CMD_SHARED_MEM_UNMAP_REGIONS, graph_id, + dest_domain); + if (IS_ERR(pkt)) + return PTR_ERR(pkt); - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - data = &graph->rx_data; - else - data = &graph->tx_data; + info = idr_find(&apm->graph_info_idr, graph_id); + if (!info) + return -ENODEV; - if (!data->mem_map_handle) + if (!info->mem_map_handle) return 0; - pkt = audioreach_alloc_apm_pkt(sizeof(*cmd), APM_CMD_SHARED_MEM_UNMAP_REGIONS, dir, - graph->port->id); - if (IS_ERR(pkt)) - return PTR_ERR(pkt); - cmd = (void *)pkt + GPR_HDR_SIZE; - cmd->mem_map_handle = data->mem_map_handle; + cmd->mem_map_handle = info->mem_map_handle; - rc = audioreach_graph_send_cmd_sync(graph, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS); - kfree(pkt); + return q6apm_send_cmd_sync(apm, pkt, APM_CMD_SHARED_MEM_UNMAP_REGIONS); +} +EXPORT_SYMBOL_GPL(q6apm_unmap_memory_fixed_region); +int q6apm_free_fragments(struct q6apm_graph *graph, unsigned int dir) +{ audioreach_graph_free_buf(graph); - return rc; + return 0; } -EXPORT_SYMBOL_GPL(q6apm_unmap_memory_regions); +EXPORT_SYMBOL_GPL(q6apm_free_fragments); int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples) { @@ -426,9 +473,13 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts, int rc, iid; iid = q6apm_graph_get_rx_shmem_module_iid(graph); - pkt = audioreach_alloc_pkt(sizeof(*write_buffer), DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2, - graph->rx_data.dsp_buf | (len << APM_WRITE_TOKEN_LEN_SHIFT), - graph->port->id, iid); + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); + + pkt = audioreach_alloc_pkt(sizeof(*write_buffer), + DATA_CMD_WR_SH_MEM_EP_DATA_BUFFER_V2, + graph->rx_data.dsp_buf | + (len << APM_WRITE_TOKEN_LEN_SHIFT), + graph->port->id, iid, dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -442,7 +493,7 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts, write_buffer->buf_size = len; write_buffer->timestamp_lsw = lsw_ts; write_buffer->timestamp_msw = msw_ts; - write_buffer->mem_map_handle = graph->rx_data.mem_map_handle; + write_buffer->mem_map_handle = graph->info->mem_map_handle; write_buffer->flags = wflags; graph->rx_data.dsp_buf++; @@ -469,8 +520,12 @@ int q6apm_read(struct q6apm_graph *graph) int rc, iid; iid = q6apm_graph_get_tx_shmem_module_iid(graph); - pkt = audioreach_alloc_pkt(sizeof(*read_buffer), DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2, - graph->tx_data.dsp_buf, graph->port->id, iid); + u16 dest_domain = audioreach_gpr_dest_domain(graph->apm->gdev); + + pkt = audioreach_alloc_pkt(sizeof(*read_buffer), + DATA_CMD_RD_SH_MEM_EP_DATA_BUFFER_V2, + graph->tx_data.dsp_buf, + graph->port->id, iid, dest_domain); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -482,7 +537,7 @@ int q6apm_read(struct q6apm_graph *graph) read_buffer->buf_addr_lsw = lower_32_bits(ab->phys); read_buffer->buf_addr_msw = upper_32_bits(ab->phys); - read_buffer->mem_map_handle = port->mem_map_handle; + read_buffer->mem_map_handle = graph->info->mem_map_handle; read_buffer->buf_size = ab->size; port->dsp_buf++; @@ -516,10 +571,9 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op) { struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *rd_done; struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2 *done; - struct apm_cmd_rsp_shared_mem_map_regions *rsp; - struct gpr_ibasic_rsp_result_t *result; + const struct gpr_ibasic_rsp_result_t *result; struct q6apm_graph *graph = priv; - struct gpr_hdr *hdr = &data->hdr; + const struct gpr_hdr *hdr = &data->hdr; struct device *dev = graph->dev; uint32_t client_event; phys_addr_t phys; @@ -551,18 +605,6 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op) done->buf_addr_msw); } - break; - case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS: - graph->result.opcode = hdr->opcode; - graph->result.status = 0; - rsp = data->payload; - - if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK) - graph->rx_data.mem_map_handle = rsp->mem_map_handle; - else - graph->tx_data.mem_map_handle = rsp->mem_map_handle; - - wake_up(&graph->cmd_wait); break; case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2: if (!graph->ar_graph) @@ -593,16 +635,6 @@ static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op) break; case GPR_BASIC_RSP_RESULT: switch (result->opcode) { - case APM_CMD_SHARED_MEM_UNMAP_REGIONS: - graph->result.opcode = result->opcode; - graph->result.status = 0; - if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK) - graph->rx_data.mem_map_handle = 0; - else - graph->tx_data.mem_map_handle = 0; - - wake_up(&graph->cmd_wait); - break; case APM_CMD_SHARED_MEM_MAP_REGIONS: case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT: case APM_CMD_SET_CFG: @@ -800,10 +832,12 @@ struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, ui static int apm_callback(struct gpr_resp_pkt *data, void *priv, int op) { gpr_device_t *gdev = priv; + struct audioreach_graph_info *info; struct q6apm *apm = dev_get_drvdata(&gdev->dev); + struct apm_cmd_rsp_shared_mem_map_regions *rsp; struct device *dev = &gdev->dev; struct gpr_ibasic_rsp_result_t *result; - struct gpr_hdr *hdr = &data->hdr; + const struct gpr_hdr *hdr = &data->hdr; result = data->payload; @@ -817,6 +851,7 @@ static int apm_callback(struct gpr_resp_pkt *data, void *priv, int op) break; case GPR_BASIC_RSP_RESULT: switch (result->opcode) { + case APM_CMD_SHARED_MEM_MAP_REGIONS: case APM_CMD_GRAPH_START: case APM_CMD_GRAPH_OPEN: case APM_CMD_GRAPH_PREPARE: @@ -831,10 +866,38 @@ static int apm_callback(struct gpr_resp_pkt *data, void *priv, int op) result->opcode); wake_up(&apm->wait); break; + case APM_CMD_SHARED_MEM_UNMAP_REGIONS: + apm->result.opcode = hdr->opcode; + apm->result.status = 0; + rsp = data->payload; + + info = idr_find(&apm->graph_info_idr, hdr->token); + if (info) + info->mem_map_handle = 0; + else + dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status, + result->opcode); + + wake_up(&apm->wait); + break; default: break; } break; + case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS: + apm->result.opcode = hdr->opcode; + apm->result.status = 0; + rsp = data->payload; + + info = idr_find(&apm->graph_info_idr, hdr->token); + if (info) + info->mem_map_handle = rsp->mem_map_handle; + else + dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status, + result->opcode); + + wake_up(&apm->wait); + break; default: break; } diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h index 7ce08b401e31..bfb6167eba78 100644 --- a/sound/soc/qcom/qdsp6/q6apm.h +++ b/sound/soc/qcom/qdsp6/q6apm.h @@ -77,7 +77,6 @@ struct audioreach_graph_data { struct audio_buffer *buf; uint32_t num_periods; uint32_t dsp_buf; - uint32_t mem_map_handle; atomic_t hw_ptr; }; @@ -132,11 +131,14 @@ int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts, uint32_t lsw_ts, uint32_t wflags); /* Memory Map related */ -int q6apm_map_memory_regions(struct q6apm_graph *graph, - unsigned int dir, phys_addr_t phys, - size_t period_sz, unsigned int periods); -int q6apm_unmap_memory_regions(struct q6apm_graph *graph, - unsigned int dir); +int q6apm_map_memory_fixed_region(struct device *dev, + unsigned int graph_id, + phys_addr_t phys, size_t sz); +int q6apm_alloc_fragments(struct q6apm_graph *graph, + unsigned int dir, phys_addr_t phys, + size_t period_sz, unsigned int periods); +int q6apm_free_fragments(struct q6apm_graph *graph, unsigned int dir); +int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id); /* Helpers */ int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, uint32_t rsp_opcode); diff --git a/sound/soc/qcom/qdsp6/q6prm.c b/sound/soc/qcom/qdsp6/q6prm.c index 81554d202658..b4029f829ea3 100644 --- a/sound/soc/qcom/qdsp6/q6prm.c +++ b/sound/soc/qcom/qdsp6/q6prm.c @@ -73,7 +73,9 @@ static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool rsp_opcode = PRM_CMD_RSP_RELEASE_HW_RSC; } - pkt = audioreach_alloc_cmd_pkt(sizeof(*req), opcode, 0, gdev->svc.id, GPR_PRM_MODULE_IID); + pkt = audioreach_alloc_cmd_pkt(sizeof(*req), opcode, 0, gdev->svc.id, + GPR_PRM_MODULE_IID, + audioreach_gpr_dest_domain(gdev)); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -120,7 +122,8 @@ static int q6prm_request_lpass_clock(struct device *dev, int clk_id, int clk_att int rc; pkt = audioreach_alloc_cmd_pkt(sizeof(*req), PRM_CMD_REQUEST_HW_RSC, 0, gdev->svc.id, - GPR_PRM_MODULE_IID); + GPR_PRM_MODULE_IID, + audioreach_gpr_dest_domain(gdev)); if (IS_ERR(pkt)) return PTR_ERR(pkt); @@ -157,7 +160,8 @@ static int q6prm_release_lpass_clock(struct device *dev, int clk_id, int clk_att int rc; pkt = audioreach_alloc_cmd_pkt(sizeof(*rel), PRM_CMD_RELEASE_HW_RSC, 0, gdev->svc.id, - GPR_PRM_MODULE_IID); + GPR_PRM_MODULE_IID, + audioreach_gpr_dest_domain(gdev)); if (IS_ERR(pkt)) return PTR_ERR(pkt);