From: Srinivas Kandagatla Date: Thu, 28 May 2026 18:58:04 +0000 (+0100) Subject: ASoC: qcom: q6apm: add watermark event support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ed56ac9e5e96e048eb1a98618908539a02431b46;p=thirdparty%2Flinux.git ASoC: qcom: q6apm: add watermark event support Push-pull shared memory modules can report watermark events when the DSP read/write index reaches configured circular buffer levels. Add support for registering watermark levels with the shared memory module and route the resulting module event to q6apm clients using a new APM_CLIENT_EVENT_WATERMARK_EVENT event. Signed-off-by: Srinivas Kandagatla Link: https://patch.msgid.link/20260528185806.6316-6-srinivas.kandagatla@oss.qualcomm.com Signed-off-by: Mark Brown --- diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index c984b12409dd..e6e9eb2e85aa 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -1118,6 +1118,42 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph, return q6apm_send_cmd_sync(graph->apm, pkt, 0); } +int audioreach_shmem_register_event(struct q6apm_graph *graph, int bytes, int num_levels) +{ + struct apm_module_register_events *event; + struct event_cfg_sh_mem_pull_push_mode_watermark_t *level; + int i, payload_size; + struct gpr_pkt *pkt __free(kfree) = NULL; + void *p; + + if (num_levels <= 0 || bytes <= 0) + return -EINVAL; + + payload_size = sizeof(*event) + sizeof(*level) + num_levels * sizeof(uint32_t); + + pkt = audioreach_alloc_cmd_pkt(payload_size, APM_CMD_REGISTER_MODULE_EVENTS, 0, + graph->port->id, graph->shm_iid); + if (IS_ERR(pkt)) + return PTR_ERR(pkt); + + p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; + + event = p; + event->module_instance_id = graph->shm_iid; + event->event_id = EVENT_ID_SH_MEM_PULL_PUSH_MODE_WATERMARK; + event->is_register = 1; + event->event_config_payload_size = sizeof(*level) + num_levels * sizeof(uint32_t); + p += sizeof(*event); + level = p; + level->num_water_mark_levels = num_levels; + + for (i = 0; i < num_levels; i++) + level->level[i] = (i + 1) * bytes; + + return audioreach_graph_send_cmd_sync(graph, pkt, 0); +} +EXPORT_SYMBOL_GPL(audioreach_shmem_register_event); + static int audioreach_shmem_set_media_format(struct q6apm_graph *graph, const struct audioreach_module *module, const struct audioreach_module_config *mcfg) diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index b85c7e5b085e..62a2fd79bbcb 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -62,6 +62,8 @@ struct q6apm_graph; #define APM_CMD_GET_CFG 0x01001007 #define APM_CMD_SHARED_MEM_MAP_REGIONS 0x0100100C #define APM_CMD_SHARED_MEM_UNMAP_REGIONS 0x0100100D +#define APM_CMD_REGISTER_MODULE_EVENTS 0x0100100E +#define APM_EVENT_MODULE_TO_CLIENT 0x03001000 #define APM_CMD_RSP_SHARED_MEM_MAP_REGIONS 0x02001001 #define APM_MMAP_TOKEN_GID_MASK GENMASK(15, 0) #define APM_MMAP_TOKEN_MAP_TYPE_POS_BUF BIT(16) @@ -69,6 +71,48 @@ struct q6apm_graph; #define APM_CMD_RSP_GET_CFG 0x02001000 #define APM_CMD_CLOSE_ALL 0x01001013 #define APM_CMD_REGISTER_SHARED_CFG 0x0100100A +#define EVENT_ID_SH_MEM_PULL_PUSH_MODE_WATERMARK 0x0800101C + +/** + * struct event_cfg_sh_mem_pull_push_mode_watermark_t - Watermark config + * @num_water_mark_levels: Number of watermark levels. + * @level: Watermark levels. + * + * If @num_water_mark_levels is zero, no watermark levels are specified + * and watermark events are not supported. + */ +struct event_cfg_sh_mem_pull_push_mode_watermark_t { + uint32_t num_water_mark_levels; + uint32_t level[]; +} __packed; + +/** + * struct apm_module_register_events - Register or unregister module events + * @module_instance_id: Module instance identifier. + * @event_id: Module event identifier. + * @is_register: 1 to register the event, 0 to unregister it. + * @error_code: Error code for out-of-band command mode. + * @event_config_payload_size: Event configuration payload size in bytes. + * @reserved: Reserved for alignment; must be zero. + */ +struct apm_module_register_events { + uint32_t module_instance_id; + uint32_t event_id; + uint32_t is_register; + uint32_t error_code; + uint32_t event_config_payload_size; + uint32_t reserved; +} __packed; + +/** + * struct apm_module_event - Module event descriptor + * @event_id: Module event identifier. + * @event_payload_size: Event payload size in bytes. + */ +struct apm_module_event { + uint32_t event_id; + uint32_t event_payload_size; +} __packed; #define APM_MEMORY_MAP_SHMEM8_4K_POOL 3 @@ -907,4 +951,5 @@ int audioreach_setup_push_pull(struct q6apm_graph *graph, phys_addr_t bphys, uint32_t pos_buf_mem_map_handle, uint32_t size); int audioreach_map_memory_position_buffer(struct q6apm_graph *graph, unsigned int dir); +int audioreach_shmem_register_event(struct q6apm_graph *graph, int bytes, int num_levels); #endif /* __AUDIOREACH_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 9235089c1b46..2e5b25b8d00f 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -557,6 +557,7 @@ static int graph_callback(const 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_module_event *event; const struct gpr_ibasic_rsp_result_t *result; struct q6apm_graph *graph = priv; const struct gpr_hdr *hdr = &data->hdr; @@ -568,6 +569,16 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op) result = data->payload; switch (hdr->opcode) { + case APM_EVENT_MODULE_TO_CLIENT: + event = data->payload; + switch (event->event_id) { + case EVENT_ID_SH_MEM_PULL_PUSH_MODE_WATERMARK: + client_event = APM_CLIENT_EVENT_WATERMARK_EVENT; + graph->cb(client_event, hdr->token, data->payload, graph->priv); + break; + } + + break; case DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2: if (!graph->ar_graph) break; @@ -623,6 +634,7 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op) switch (result->opcode) { case APM_CMD_SHARED_MEM_MAP_REGIONS: case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT: + case APM_CMD_REGISTER_MODULE_EVENTS: case APM_CMD_SET_CFG: graph->result.opcode = result->opcode; graph->result.status = result->status; @@ -641,6 +653,13 @@ static int graph_callback(const struct gpr_resp_pkt *data, void *priv, int op) return 0; } +int q6apm_register_watermark_event(struct q6apm_graph *graph, int water_mark_level_bytes, + int num_levels) +{ + return audioreach_shmem_register_event(graph, water_mark_level_bytes, num_levels); +} +EXPORT_SYMBOL_GPL(q6apm_register_watermark_event); + int q6apm_push_pull_config(struct q6apm_graph *graph, phys_addr_t bphys, phys_addr_t pphys, uint32_t size) { diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h index 780933ff17e9..5cb51ca491dc 100644 --- a/sound/soc/qcom/qdsp6/q6apm.h +++ b/sound/soc/qcom/qdsp6/q6apm.h @@ -41,6 +41,7 @@ #define APM_CLIENT_EVENT_CMD_RUN_DONE 0x1008 #define APM_CLIENT_EVENT_DATA_WRITE_DONE 0x1009 #define APM_CLIENT_EVENT_DATA_READ_DONE 0x100a +#define APM_CLIENT_EVENT_WATERMARK_EVENT 0x100b #define APM_WRITE_TOKEN_MASK GENMASK(15, 0) #define APM_WRITE_TOKEN_LEN_MASK GENMASK(31, 16) #define APM_WRITE_TOKEN_LEN_SHIFT 16 @@ -164,4 +165,5 @@ bool q6apm_is_graph_in_push_pull_mode_from_id(struct device *dev, unsigned int g int q6apm_push_pull_config(struct q6apm_graph *graph, phys_addr_t bphys, phys_addr_t pphys, uint32_t size); +int q6apm_register_watermark_event(struct q6apm_graph *graph, int watermark_bytes, int num_levels); #endif /* __APM_GRAPH_ */