]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ASoC: qcom: q6apm: add watermark event support
authorSrinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
Thu, 28 May 2026 18:58:04 +0000 (19:58 +0100)
committerMark Brown <broonie@kernel.org>
Mon, 1 Jun 2026 16:19:14 +0000 (17:19 +0100)
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 <srinivas.kandagatla@oss.qualcomm.com>
Link: https://patch.msgid.link/20260528185806.6316-6-srinivas.kandagatla@oss.qualcomm.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/qcom/qdsp6/audioreach.c
sound/soc/qcom/qdsp6/audioreach.h
sound/soc/qcom/qdsp6/q6apm.c
sound/soc/qcom/qdsp6/q6apm.h

index c984b12409ddc352fc2cee99a9f6443eefa8a25d..e6e9eb2e85aa1fea25577b4f52e343849f1292b9 100644 (file)
@@ -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)
index b85c7e5b085ee78c8f89997c5e02527d31fdb231..62a2fd79bbcb933445a295757090c2556221931e 100644 (file)
@@ -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__ */
index 9235089c1b46cfd811edb1ef8f71a0325e033b70..2e5b25b8d00fd3f9b4646b0b4d43c57e99b777c1 100644 (file)
@@ -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)
 {
index 780933ff17e9b7a15be2ba55b3eaac2f7dece84d..5cb51ca491dc4fac7d910c3e26ea36d9831de1ca 100644 (file)
@@ -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_ */