Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3fa8397e authored by Manish Dewangan's avatar Manish Dewangan Committed by Banajit Goswami
Browse files

ASoC: msm: qdsp6v2: Add support for DSP clock recovery



ASM driver changes to apply DSP clock recovery.

Clients can issue clock recovery command with a positive value
to advance the clock or a negative value to delay the clock.

CRs-Fixed: 2036899
Change-Id: If2f10368afafe203ebdea219edcc2227cd381801
Signed-off-by: default avatarManish Dewangan <manish@codeaurora.org>
parent 45963de2
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -10331,10 +10331,33 @@ struct asm_session_mtmx_strtr_param_clk_rec_t {
	u32                  flags;
} __packed;


/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC to
 * realize smoother adjustment of audio session clock for a specified session.
 * The desired audio session clock adjustment(in micro seconds) is specified
 * using the command #ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2.
 * Delaying/Advancing the session clock would be implemented by inserting
 * interpolated/dropping audio samples in the playback path respectively.
 * Also, this parameter has to be configured before the Audio Session is put
 * to RUN state to avoid cold start latency/glitches in the playback.
 */

#define ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL         0x00013217

struct asm_session_mtmx_param_adjust_session_time_ctl_t {
	/* Specifies whether the module is enabled or not
	 * @values
	 * 0 -- disabled
	 * 1 -- enabled
	 */
	u32                 enable;
};

union asm_session_mtmx_strtr_param_config {
	struct asm_session_mtmx_strtr_param_window_v2_t window_param;
	struct asm_session_mtmx_strtr_param_render_mode_t render_param;
	struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
	struct asm_session_mtmx_param_adjust_session_time_ctl_t adj_time_param;
} __packed;

struct asm_mtmx_strtr_params {
+8 −0
Original line number Diff line number Diff line
@@ -654,6 +654,10 @@ int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
		uint32_t clk_rec_mode);

/* Enable adjust session clock in DSP */
int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
		bool enable);

/* Retrieve the current DSP path delay */
int q6asm_get_path_delay(struct audio_client *ac);

@@ -661,4 +665,8 @@ int q6asm_get_path_delay(struct audio_client *ac);
uint8_t q6asm_get_buf_index_from_token(uint32_t token);
uint8_t q6asm_get_stream_id_from_token(uint32_t token);

/* Adjust session clock in DSP */
int q6asm_adjust_session_clock(struct audio_client *ac,
		uint32_t adjust_time_lsw,
		uint32_t adjust_time_msw);
#endif /* __Q6_ASM_H__ */
+142 −0
Original line number Diff line number Diff line
@@ -2056,6 +2056,12 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
			(void *)pp_event_package, ac->priv);
		kfree(pp_event_package);
		return 0;
	case ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2:
		pr_debug("%s: ASM_SESSION_CMDRSP_ADJUST_SESSION_CLOCK_V2 sesion %d status 0x%x msw %u lsw %u\n",
			 __func__, ac->session, payload[0], payload[2],
			 payload[1]);
		wake_up(&ac->cmd_wait);
		break;
	case ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2:
		pr_debug("%s: ASM_SESSION_CMDRSP_GET_PATH_DELAY_V2 session %d status 0x%x msw %u lsw %u\n",
				__func__, ac->session, payload[0], payload[2],
@@ -8026,6 +8032,80 @@ int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
	return rc;
}

int q6asm_send_mtmx_strtr_enable_adjust_session_clock(struct audio_client *ac,
		bool enable)
{
	struct asm_mtmx_strtr_params matrix;
	struct asm_session_mtmx_param_adjust_session_time_ctl_t adjust_time;
	int sz = 0;
	int rc  = 0;

	pr_debug("%s: adjust session enable %d\n", __func__, enable);

	if (!ac) {
		pr_err("%s: audio client handle is NULL\n", __func__);
		rc = -EINVAL;
		goto exit;
	}

	if (ac->apr == NULL) {
		pr_err("%s: ac->apr is NULL\n", __func__);
		rc = -EINVAL;
		goto exit;
	}

	adjust_time.enable = enable;
	memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
	sz = sizeof(struct asm_mtmx_strtr_params);
	q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
	atomic_set(&ac->cmd_state, -1);
	matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;

	matrix.param.data_payload_addr_lsw = 0;
	matrix.param.data_payload_addr_msw = 0;
	matrix.param.mem_map_handle = 0;
	matrix.param.data_payload_size =
		sizeof(struct asm_stream_param_data_v2) +
		sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
	matrix.param.direction = 0; /* RX */
	matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
	matrix.data.param_id = ASM_SESSION_MTMX_PARAM_ADJUST_SESSION_TIME_CTL;
	matrix.data.param_size =
		sizeof(struct asm_session_mtmx_param_adjust_session_time_ctl_t);
	matrix.data.reserved = 0;
	matrix.config.adj_time_param.enable = adjust_time.enable;

	rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
	if (rc < 0) {
		pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
			__func__, matrix.data.param_id);
		rc = -EINVAL;
		goto exit;
	}

	rc = wait_event_timeout(ac->cmd_wait,
			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
	if (!rc) {
		pr_err("%s: enable adjust session failed failed paramid [0x%x]\n",
			__func__, matrix.data.param_id);
		rc = -ETIMEDOUT;
		goto exit;
	}

	if (atomic_read(&ac->cmd_state) > 0) {
		pr_err("%s: DSP returned error[%s]\n",
				__func__, adsp_err_get_err_str(
				atomic_read(&ac->cmd_state)));
		rc = adsp_err_get_lnx_err_code(
				atomic_read(&ac->cmd_state));
		goto exit;
	}
	rc = 0;
exit:
	return rc;
}


static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
{
	struct apr_hdr hdr;
@@ -8415,6 +8495,68 @@ int q6asm_reg_rx_underflow(struct audio_client *ac, uint16_t enable)
	return -EINVAL;
}

int q6asm_adjust_session_clock(struct audio_client *ac,
		uint32_t adjust_time_lsw,
		uint32_t adjust_time_msw)
{
	int rc = 0;
	int sz = 0;
	struct asm_session_cmd_adjust_session_clock_v2 adjust_clock;

	pr_debug("%s: adjust_time_lsw is %x, adjust_time_msw is %x\n", __func__,
		  adjust_time_lsw, adjust_time_msw);

	if (!ac) {
		pr_err("%s: audio client handle is NULL\n", __func__);
		rc = -EINVAL;
		goto fail_cmd;
	}

	if (ac->apr == NULL) {
		pr_err("%s: ac->apr is NULL", __func__);
		rc = -EINVAL;
		goto fail_cmd;
	}

	sz = sizeof(struct asm_session_cmd_adjust_session_clock_v2);
	q6asm_add_hdr(ac, &adjust_clock.hdr, sz, TRUE);
	atomic_set(&ac->cmd_state, -1);
	adjust_clock.hdr.opcode = ASM_SESSION_CMD_ADJUST_SESSION_CLOCK_V2;

	adjust_clock.adjustime_lsw = adjust_time_lsw;
	adjust_clock.adjustime_msw = adjust_time_msw;


	rc = apr_send_pkt(ac->apr, (uint32_t *) &adjust_clock);
	if (rc < 0) {
		pr_err("%s: adjust_clock send failed paramid [0x%x]\n",
			__func__, adjust_clock.hdr.opcode);
		rc = -EINVAL;
		goto fail_cmd;
	}

	rc = wait_event_timeout(ac->cmd_wait,
			(atomic_read(&ac->cmd_state) >= 0), 5*HZ);
	if (!rc) {
		pr_err("%s: timeout, adjust_clock paramid[0x%x]\n",
			__func__, adjust_clock.hdr.opcode);
		rc = -ETIMEDOUT;
		goto fail_cmd;
	}

	if (atomic_read(&ac->cmd_state) > 0) {
		pr_err("%s: DSP returned error[%s]\n",
				__func__, adsp_err_get_err_str(
				atomic_read(&ac->cmd_state)));
		rc = adsp_err_get_lnx_err_code(
				atomic_read(&ac->cmd_state));
		goto fail_cmd;
	}
	rc = 0;
fail_cmd:
	return rc;
}

/*
 * q6asm_get_path_delay() - get the path delay for an audio session
 * @ac: audio client handle