Skip to content

Commit 3ef902c

Browse files
committed
ASoC: qcom: qdsp6: add push/pull module support
Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com> says: This patchset adds support for Push/Pull mode modules. Push-pull mode uses dedicated shared-memory modules that allow the DSP to access the PCM circular buffer directly. In addition to reducing fragment queueing and ACK handling in the host driver, This mode exposes a DSP-maintained position buffer that provides fine-grained hardware pointer updates. Unlike the Read/Write Shared Memory endpoitn modules, which are period based, where the reported pointer advances only at period boundaries, where as push-pull mode allows .pointer() to reflect sub-period progress, improving pointer accuracy. Also the driver now can queue buffers which are less than period size, which makes tests like alsa_conformance_test happy. Now the pointer update visibility is around 1ms, compared to min of 10ms with read/write shared memory endpoints. Along with the circular buffer support, this patchset also adds watermark event support to provide a period level event from dsp to notify about period progress. Tested this on T14s, Arduino VENTUNO-Q platforms. Tplg related changes are available at: https://github.com/Srinivas-Kandagatla/audioreach-topology/tree/push/pull Link: https://patch.msgid.link/20260528185806.6316-1-srinivas.kandagatla@oss.qualcomm.com
2 parents 6d23590 + 4cfbd3a commit 3ef902c

5 files changed

Lines changed: 465 additions & 89 deletions

File tree

sound/soc/qcom/qdsp6/audioreach.c

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ int audioreach_compr_set_param(struct q6apm_graph *graph,
955955
struct media_format *header;
956956
int rc;
957957
void *p;
958-
int iid = q6apm_graph_get_rx_shmem_module_iid(graph);
958+
int iid = graph->shm_iid;
959959
int payload_size = sizeof(struct apm_sh_module_media_fmt_cmd);
960960

961961
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_cmd_pkt(payload_size,
@@ -1118,6 +1118,42 @@ static int audioreach_pcm_set_media_format(struct q6apm_graph *graph,
11181118
return q6apm_send_cmd_sync(graph->apm, pkt, 0);
11191119
}
11201120

1121+
int audioreach_shmem_register_event(struct q6apm_graph *graph, int bytes, int num_levels)
1122+
{
1123+
struct apm_module_register_events *event;
1124+
struct event_cfg_sh_mem_pull_push_mode_watermark_t *level;
1125+
int i, payload_size;
1126+
struct gpr_pkt *pkt __free(kfree) = NULL;
1127+
void *p;
1128+
1129+
if (num_levels <= 0 || bytes <= 0)
1130+
return -EINVAL;
1131+
1132+
payload_size = sizeof(*event) + sizeof(*level) + num_levels * sizeof(uint32_t);
1133+
1134+
pkt = audioreach_alloc_cmd_pkt(payload_size, APM_CMD_REGISTER_MODULE_EVENTS, 0,
1135+
graph->port->id, graph->shm_iid);
1136+
if (IS_ERR(pkt))
1137+
return PTR_ERR(pkt);
1138+
1139+
p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
1140+
1141+
event = p;
1142+
event->module_instance_id = graph->shm_iid;
1143+
event->event_id = EVENT_ID_SH_MEM_PULL_PUSH_MODE_WATERMARK;
1144+
event->is_register = 1;
1145+
event->event_config_payload_size = sizeof(*level) + num_levels * sizeof(uint32_t);
1146+
p += sizeof(*event);
1147+
level = p;
1148+
level->num_water_mark_levels = num_levels;
1149+
1150+
for (i = 0; i < num_levels; i++)
1151+
level->level[i] = (i + 1) * bytes;
1152+
1153+
return audioreach_graph_send_cmd_sync(graph, pkt, 0);
1154+
}
1155+
EXPORT_SYMBOL_GPL(audioreach_shmem_register_event);
1156+
11211157
static int audioreach_shmem_set_media_format(struct q6apm_graph *graph,
11221158
const struct audioreach_module *module,
11231159
const struct audioreach_module_config *mcfg)
@@ -1342,6 +1378,7 @@ int audioreach_set_media_format(struct q6apm_graph *graph,
13421378
rc = audioreach_i2s_set_media_format(graph, module, cfg);
13431379
break;
13441380
case MODULE_ID_WR_SHARED_MEM_EP:
1381+
case MODULE_ID_SH_MEM_PULL_MODE:
13451382
rc = audioreach_shmem_set_media_format(graph, module, cfg);
13461383
break;
13471384
case MODULE_ID_GAIN:
@@ -1401,10 +1438,48 @@ void audioreach_graph_free_buf(struct q6apm_graph *graph)
14011438
}
14021439
EXPORT_SYMBOL_GPL(audioreach_graph_free_buf);
14031440

1441+
int audioreach_setup_push_pull(struct q6apm_graph *graph, phys_addr_t bphys,
1442+
phys_addr_t pphys, uint32_t mem_map_handle,
1443+
uint32_t pos_buf_mem_map_handle, uint32_t size)
1444+
{
1445+
struct param_id_sh_mem_pull_push_mode_cfg *cfg;
1446+
struct apm_module_param_data *param_data;
1447+
int payload_size;
1448+
struct gpr_pkt *pkt __free(kfree) = NULL;
1449+
void *p;
1450+
1451+
payload_size = sizeof(*cfg) + APM_MODULE_PARAM_DATA_SIZE;
1452+
pkt = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_SET_CFG, 0);
1453+
if (IS_ERR(pkt))
1454+
return PTR_ERR(pkt);
1455+
1456+
p = (void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE;
1457+
1458+
param_data = p;
1459+
param_data->module_instance_id = graph->shm_iid;
1460+
param_data->error_code = 0;
1461+
param_data->param_id = PARAM_ID_SH_MEM_PULL_PUSH_MODE_CFG;
1462+
param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE;
1463+
1464+
p = p + APM_MODULE_PARAM_DATA_SIZE;
1465+
cfg = p;
1466+
1467+
cfg->shared_circ_buf_addr_lsw = lower_32_bits(bphys);
1468+
cfg->shared_circ_buf_addr_msw = upper_32_bits(bphys);
1469+
cfg->shared_circ_buf_size = size;
1470+
cfg->circ_buf_mem_map_handle = mem_map_handle;
1471+
cfg->shared_pos_buf_addr_lsw = lower_32_bits(pphys);
1472+
cfg->shared_pos_buf_addr_msw = upper_32_bits(pphys);
1473+
cfg->pos_buf_mem_map_handle = pos_buf_mem_map_handle;
1474+
1475+
return q6apm_send_cmd_sync(graph->apm, pkt, 0);
1476+
}
1477+
EXPORT_SYMBOL_GPL(audioreach_setup_push_pull);
1478+
14041479
int audioreach_shared_memory_send_eos(struct q6apm_graph *graph)
14051480
{
14061481
struct data_cmd_wr_sh_mem_ep_eos *eos;
1407-
int iid = q6apm_graph_get_rx_shmem_module_iid(graph);
1482+
int iid = graph->shm_iid;
14081483
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_cmd_pkt(sizeof(*eos),
14091484
DATA_CMD_WR_SH_MEM_EP_EOS, 0, graph->port->id, iid);
14101485
if (IS_ERR(pkt))

sound/soc/qcom/qdsp6/audioreach.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ struct q6apm_graph;
1616
#define MODULE_ID_PCM_CNV 0x07001003
1717
#define MODULE_ID_PCM_ENC 0x07001004
1818
#define MODULE_ID_PCM_DEC 0x07001005
19+
#define MODULE_ID_SH_MEM_PULL_MODE 0x07001006
20+
#define MODULE_ID_SH_MEM_PUSH_MODE 0x07001007
1921
#define MODULE_ID_PLACEHOLDER_ENCODER 0x07001008
2022
#define MODULE_ID_PLACEHOLDER_DECODER 0x07001009
2123
#define MODULE_ID_I2S_SINK 0x0700100A
@@ -60,10 +62,57 @@ struct q6apm_graph;
6062
#define APM_CMD_GET_CFG 0x01001007
6163
#define APM_CMD_SHARED_MEM_MAP_REGIONS 0x0100100C
6264
#define APM_CMD_SHARED_MEM_UNMAP_REGIONS 0x0100100D
65+
#define APM_CMD_REGISTER_MODULE_EVENTS 0x0100100E
66+
#define APM_EVENT_MODULE_TO_CLIENT 0x03001000
6367
#define APM_CMD_RSP_SHARED_MEM_MAP_REGIONS 0x02001001
68+
#define APM_MMAP_TOKEN_GID_MASK GENMASK(15, 0)
69+
#define APM_MMAP_TOKEN_MAP_TYPE_POS_BUF BIT(16)
70+
#define APM_MMAP_TOKEN_MAP_TYPE_SHIFT 16
6471
#define APM_CMD_RSP_GET_CFG 0x02001000
6572
#define APM_CMD_CLOSE_ALL 0x01001013
6673
#define APM_CMD_REGISTER_SHARED_CFG 0x0100100A
74+
#define EVENT_ID_SH_MEM_PULL_PUSH_MODE_WATERMARK 0x0800101C
75+
76+
/**
77+
* struct event_cfg_sh_mem_pull_push_mode_watermark_t - Watermark config
78+
* @num_water_mark_levels: Number of watermark levels.
79+
* @level: Watermark levels.
80+
*
81+
* If @num_water_mark_levels is zero, no watermark levels are specified
82+
* and watermark events are not supported.
83+
*/
84+
struct event_cfg_sh_mem_pull_push_mode_watermark_t {
85+
uint32_t num_water_mark_levels;
86+
uint32_t level[];
87+
} __packed;
88+
89+
/**
90+
* struct apm_module_register_events - Register or unregister module events
91+
* @module_instance_id: Module instance identifier.
92+
* @event_id: Module event identifier.
93+
* @is_register: 1 to register the event, 0 to unregister it.
94+
* @error_code: Error code for out-of-band command mode.
95+
* @event_config_payload_size: Event configuration payload size in bytes.
96+
* @reserved: Reserved for alignment; must be zero.
97+
*/
98+
struct apm_module_register_events {
99+
uint32_t module_instance_id;
100+
uint32_t event_id;
101+
uint32_t is_register;
102+
uint32_t error_code;
103+
uint32_t event_config_payload_size;
104+
uint32_t reserved;
105+
} __packed;
106+
107+
/**
108+
* struct apm_module_event - Module event descriptor
109+
* @event_id: Module event identifier.
110+
* @event_payload_size: Event payload size in bytes.
111+
*/
112+
struct apm_module_event {
113+
uint32_t event_id;
114+
uint32_t event_payload_size;
115+
} __packed;
67116

68117
#define APM_MEMORY_MAP_SHMEM8_4K_POOL 3
69118

@@ -710,6 +759,46 @@ struct param_id_placeholder_real_module_id {
710759
uint32_t real_module_id;
711760
} __packed;
712761

762+
763+
#define PARAM_ID_SH_MEM_PULL_PUSH_MODE_CFG 0x0800100A
764+
765+
/**
766+
* struct param_id_sh_mem_pull_push_mode_cfg - Shared memory push/pull config
767+
* @shared_circ_buf_addr_lsw: Lower 32 bits of the circular buffer address.
768+
* @shared_circ_buf_addr_msw: Upper 32 bits of the circular buffer address.
769+
* @shared_circ_buf_size: Circular buffer size in bytes.
770+
* @circ_buf_mem_map_handle: Circular buffer memory map handle.
771+
* @shared_pos_buf_addr_lsw: Lower 32 bits of the position buffer address.
772+
* @shared_pos_buf_addr_msw: Upper 32 bits of the position buffer address.
773+
* @pos_buf_mem_map_handle: Position buffer memory map handle.
774+
*/
775+
struct param_id_sh_mem_pull_push_mode_cfg {
776+
uint32_t shared_circ_buf_addr_lsw;
777+
uint32_t shared_circ_buf_addr_msw;
778+
uint32_t shared_circ_buf_size;
779+
uint32_t circ_buf_mem_map_handle;
780+
uint32_t shared_pos_buf_addr_lsw;
781+
uint32_t shared_pos_buf_addr_msw;
782+
uint32_t pos_buf_mem_map_handle;
783+
} __packed;
784+
785+
/**
786+
* struct sh_mem_pull_push_mode_position_buffer - Shared position buffer
787+
* @frame_counter: Synchronization counter.
788+
* @index: Current read/write index in bytes.
789+
* @timestamp_us_lsw: Lower 32 bits of the timestamp in microseconds.
790+
* @timestamp_us_msw: Upper 32 bits of the timestamp in microseconds.
791+
*
792+
* The frame counter should be read before and after the other fields to
793+
* ensure the DSP did not update them while they were being read.
794+
*/
795+
struct sh_mem_pull_push_mode_position_buffer {
796+
uint32_t frame_counter;
797+
uint32_t index;
798+
uint32_t timestamp_us_lsw;
799+
uint32_t timestamp_us_msw;
800+
} __packed;
801+
713802
/* Graph */
714803
struct audioreach_connection {
715804
/* Connections */
@@ -723,8 +812,10 @@ struct audioreach_connection {
723812
struct audioreach_graph_info {
724813
int id;
725814
uint32_t mem_map_handle;
815+
uint32_t pos_buf_mem_map_handle;
726816
uint32_t num_sub_graphs;
727817
struct list_head sg_list;
818+
bool is_push_pull_mode;
728819
/* DPCM connection from FE Graph to BE graph */
729820
uint32_t src_mod_inst_id;
730821
uint32_t src_mod_op_port_id;
@@ -855,5 +946,10 @@ int audioreach_send_u32_param(struct q6apm_graph *graph,
855946
uint32_t param_id, uint32_t param_val);
856947
int audioreach_compr_set_param(struct q6apm_graph *graph,
857948
const struct audioreach_module_config *mcfg);
949+
int audioreach_setup_push_pull(struct q6apm_graph *graph, phys_addr_t bphys,
950+
phys_addr_t pphys, uint32_t mem_map_handle,
951+
uint32_t pos_buf_mem_map_handle, uint32_t size);
952+
int audioreach_map_memory_position_buffer(struct q6apm_graph *graph, unsigned int dir);
858953

954+
int audioreach_shmem_register_event(struct q6apm_graph *graph, int bytes, int num_levels);
859955
#endif /* __AUDIOREACH_H__ */

0 commit comments

Comments
 (0)