diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2017-03-07 06:25:01 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-03-07 06:25:01 -0800 |
commit | 5f1177f04affb046216111c7d4a8763262ed4d17 (patch) | |
tree | 0402c906f49632c5acf78a3aaf556bdca4f24f24 | |
parent | 353fafc458aa7080b19b3befcf8cf62ae65c868a (diff) | |
parent | 9da92fae0365f8962ef4ea48051edb4e6f16c2df (diff) |
Merge "ASoC: msm: qdsp6v2: Support to set session start delay"
-rw-r--r-- | include/sound/apr_audio-v2.h | 100 | ||||
-rw-r--r-- | include/sound/q6asm-v2.h | 8 | ||||
-rw-r--r-- | include/uapi/sound/compress_offload.h | 22 | ||||
-rw-r--r-- | sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c | 161 | ||||
-rw-r--r-- | sound/soc/msm/qdsp6v2/q6asm.c | 186 |
5 files changed, 465 insertions, 12 deletions
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index ddc21d0c1bbb..4bfd187095b6 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -10224,12 +10224,108 @@ struct asm_session_cmd_set_mtmx_strstr_params_v2 { */ }; +/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC which allows the + * audio client choose the rendering decision that the audio DSP should use. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD 0x00012F0D + +/* Indicates that rendering decision will be based on default rate + * (session clock based rendering, device driven). + * 1. The default session clock based rendering is inherently driven + * by the timing of the device. + * 2. After the initial decision is made (first buffer after a run + * command), subsequent data rendering decisions are made with + * respect to the rate at which the device is rendering, thus deriving + * its timing from the device. + * 3. While this decision making is simple, it has some inherent limitations + * (mentioned in the next section). + * 4. If this API is not set, the session clock based rendering will be assumed + * and this will ensure that the DSP is backward compatible. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT 0 + +/* Indicates that rendering decision will be based on local clock rate. + * 1. In the DSP loopback/client loopback use cases (frame based + * inputs), the incoming data into audio DSP is time-stamped at the + * local clock rate (STC). + * 2. This TS rate may match the incoming data rate or maybe different + * from the incoming data rate. + * 3. Regardless, the data will be time-stamped with local STC and + * therefore, the client is recommended to set this mode for these + * use cases. This method is inherently more robust to sequencing + * (AFE Start/Stop) and device switches, among other benefits. + * 4. This API will inform the DSP to compare every incoming buffer TS + * against local STC. + * 5. DSP will continue to honor render windows APIs, as before. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC 1 + +/* Structure for rendering decision parameter */ +struct asm_session_mtmx_strtr_param_render_mode_t { + /* Specifies the type of rendering decision the audio DSP should use. + * + * @values + * - #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT + * - #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC + */ + u32 flags; +} __packed; + +/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC which allows the + * audio client to specify the clock recovery mechanism that the audio DSP + * should use. + */ + +#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD 0x00012F0E + +/* Indicates that default clock recovery will be used (no clock recovery). + * If the client wishes that no clock recovery be done, the client can + * choose this. This means that no attempt will made by the DSP to try and + * match the rates of the input and output audio. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE 0 + +/* Indicates that independent clock recovery needs to be used. + * 1. In the DSP loopback/client loopback use cases (frame based inputs), + * the client should choose the independent clock recovery option. + * 2. This basically de-couples the audio and video from knowing each others + * clock sources and lets the audio DSP independently rate match the input + * and output rates. + * 3. After drift detection, the drift correction is achieved by either pulling + * the PLLs (if applicable) or by stream to device rate matching + * (for PCM use cases) by comparing drift with respect to STC. + * 4. For passthrough use cases, since the PLL pulling is the only option, + * a best effort will be made. + * If PLL pulling is not possible / available, the rendering will be + * done without rate matching. + */ +#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO 1 + +/* Payload of the #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC parameter. + */ +struct asm_session_mtmx_strtr_param_clk_rec_t { + /* Specifies the type of clock recovery that the audio DSP should + * use for rate matching. + */ + + /* @values + * #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_DEFAULT + * #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_INDEPENDENT + */ + u32 flags; +} __packed; + +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; +} __packed; + struct asm_mtmx_strtr_params { struct apr_hdr hdr; struct asm_session_cmd_set_mtmx_strstr_params_v2 param; struct asm_stream_param_data_v2 data; - u32 window_lsw; - u32 window_msw; + union asm_session_mtmx_strtr_param_config config; } __packed; #define ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2 0x00010DCF diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h index 76bb795119c2..4947c30287a3 100644 --- a/include/sound/q6asm-v2.h +++ b/include/sound/q6asm-v2.h @@ -642,6 +642,14 @@ int q6asm_send_mtmx_strtr_window(struct audio_client *ac, struct asm_session_mtmx_strtr_param_window_v2_t *window_param, uint32_t param_id); +/* Configure DSP render mode */ +int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac, + uint32_t render_mode); + +/* Configure DSP clock recovery mode */ +int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac, + uint32_t clk_rec_mode); + /* Retrieve the current DSP path delay */ int q6asm_get_path_delay(struct audio_client *ac); diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h index e050bc758b3b..30481056cce1 100644 --- a/include/uapi/sound/compress_offload.h +++ b/include/uapi/sound/compress_offload.h @@ -132,20 +132,42 @@ struct snd_compr_audio_info { __u32 reserved[15]; } __attribute__((packed, aligned(4))); +#define SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER 0 +#define SNDRV_COMPRESS_RENDER_MODE_STC_MASTER 1 + +#define SNDRV_COMPRESS_CLK_REC_MODE_NONE 0 +#define SNDRV_COMPRESS_CLK_REC_MODE_AUTO 1 + /** * enum sndrv_compress_encoder * @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the * end of the track * @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the * beginning of the track + * @SNDRV_COMPRESS_PATH_DELAY: dsp path delay in microseconds + * @SNDRV_COMPRESS_RENDER_MODE: dsp render mode (audio master or stc) + * @SNDRV_COMPRESS_CLK_REC_MODE: clock recovery mode ( none or auto) + * @SNDRV_COMPRESS_RENDER_WINDOW: render window + * @SNDRV_COMPRESS_START_DELAY: start delay */ enum sndrv_compress_encoder { SNDRV_COMPRESS_ENCODER_PADDING = 1, SNDRV_COMPRESS_ENCODER_DELAY = 2, SNDRV_COMPRESS_MIN_BLK_SIZE = 3, SNDRV_COMPRESS_MAX_BLK_SIZE = 4, + SNDRV_COMPRESS_PATH_DELAY = 5, + SNDRV_COMPRESS_RENDER_MODE = 6, + SNDRV_COMPRESS_CLK_REC_MODE = 7, + SNDRV_COMPRESS_RENDER_WINDOW = 8, + SNDRV_COMPRESS_START_DELAY = 9, }; +#define SNDRV_COMPRESS_PATH_DELAY SNDRV_COMPRESS_PATH_DELAY +#define SNDRV_COMPRESS_RENDER_MODE SNDRV_COMPRESS_RENDER_MODE +#define SNDRV_COMPRESS_CLK_REC_MODE SNDRV_COMPRESS_CLK_REC_MODE +#define SNDRV_COMPRESS_RENDER_WINDOW SNDRV_COMPRESS_RENDER_WINDOW +#define SNDRV_COMPRESS_START_DELAY SNDRV_COMPRESS_START_DELAY + /** * struct snd_compr_metadata - compressed stream metadata * @key: key id diff --git a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c index 7f032dcceabd..b4de66ae43c5 100644 --- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c +++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c @@ -160,6 +160,10 @@ struct msm_compr_audio { uint32_t stream_available; uint32_t next_stream; + uint32_t run_mode; + uint32_t start_delay_lsw; + uint32_t start_delay_msw; + uint64_t marker_timestamp; struct msm_compr_gapless_state gapless_state; @@ -215,6 +219,99 @@ static int msm_compr_send_dec_params(struct snd_compr_stream *cstream, struct msm_compr_dec_params *dec_params, int stream_id); +static int msm_compr_set_render_mode(struct msm_compr_audio *prtd, + uint32_t render_mode) { + int ret = -EINVAL; + struct audio_client *ac = prtd->audio_client; + + pr_debug("%s, got render mode %u\n", __func__, render_mode); + + if (render_mode == SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER) { + render_mode = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT; + } else if (render_mode == SNDRV_COMPRESS_RENDER_MODE_STC_MASTER) { + render_mode = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC; + prtd->run_mode = ASM_SESSION_CMD_RUN_STARTIME_RUN_WITH_DELAY; + } else { + pr_err("%s, Invalid render mode %u\n", __func__, + render_mode); + ret = -EINVAL; + goto exit; + } + + ret = q6asm_send_mtmx_strtr_render_mode(ac, render_mode); + if (ret) { + pr_err("%s, Render mode can't be set error %d\n", __func__, + ret); + } +exit: + return ret; +} + +static int msm_compr_set_clk_rec_mode(struct audio_client *ac, + uint32_t clk_rec_mode) { + int ret = -EINVAL; + + pr_debug("%s, got clk rec mode %u\n", __func__, clk_rec_mode); + + if (clk_rec_mode == SNDRV_COMPRESS_CLK_REC_MODE_NONE) { + clk_rec_mode = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE; + } else if (clk_rec_mode == SNDRV_COMPRESS_CLK_REC_MODE_AUTO) { + clk_rec_mode = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO; + } else { + pr_err("%s, Invalid clk rec_mode mode %u\n", __func__, + clk_rec_mode); + ret = -EINVAL; + goto exit; + } + + ret = q6asm_send_mtmx_strtr_clk_rec_mode(ac, clk_rec_mode); + if (ret) { + pr_err("%s, clk rec mode can't be set, error %d\n", __func__, + ret); + } + +exit: + return ret; +} + +static int msm_compr_set_render_window(struct audio_client *ac, + uint32_t ws_lsw, uint32_t ws_msw, + uint32_t we_lsw, uint32_t we_msw) +{ + int ret = -EINVAL; + struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window; + uint32_t param_id; + + pr_debug("%s, ws_lsw 0x%x ws_msw 0x%x we_lsw 0x%x we_ms 0x%x\n", + __func__, ws_lsw, ws_msw, we_lsw, we_msw); + + memset(&asm_mtmx_strtr_window, 0, + sizeof(struct asm_session_mtmx_strtr_param_window_v2_t)); + asm_mtmx_strtr_window.window_lsw = ws_lsw; + asm_mtmx_strtr_window.window_msw = ws_msw; + param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2; + ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window, + param_id); + if (ret) { + pr_err("%s, start window can't be set error %d\n", __func__, + ret); + goto exit; + } + + asm_mtmx_strtr_window.window_lsw = we_lsw; + asm_mtmx_strtr_window.window_msw = we_msw; + param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2; + ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window, + param_id); + if (ret) { + pr_err("%s, end window can't be set error %d\n", __func__, + ret); + } + +exit: + return ret; +} + static int msm_compr_set_volume(struct snd_compr_stream *cstream, uint32_t volume_l, uint32_t volume_r) { @@ -1963,7 +2060,8 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) msm_compr_read_buffer(prtd); } /* issue RUN command for the stream */ - q6asm_run_nowait(prtd->audio_client, 0, 0, 0); + q6asm_run_nowait(prtd->audio_client, prtd->run_mode, + prtd->start_delay_msw, prtd->start_delay_lsw); break; case SNDRV_PCM_TRIGGER_STOP: spin_lock_irqsave(&prtd->lock, flags); @@ -2047,7 +2145,8 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) prtd->gapless_state.gapless_transition); if (!prtd->gapless_state.gapless_transition) { atomic_set(&prtd->start, 1); - q6asm_run_nowait(prtd->audio_client, 0, 0, 0); + q6asm_run_nowait(prtd->audio_client, prtd->run_mode, + 0, 0); } break; case SND_COMPR_TRIGGER_PARTIAL_DRAIN: @@ -2717,11 +2816,14 @@ static int msm_compr_set_metadata(struct snd_compr_stream *cstream, return -EINVAL; } - if (prtd->compr_passthr != LEGACY_PCM) { + if (((metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) || + (metadata->key == SNDRV_COMPRESS_ENCODER_DELAY)) && + (prtd->compr_passthr != LEGACY_PCM)) { pr_debug("%s: No trailing silence for compress_type[%d]\n", __func__, prtd->compr_passthr); return 0; } + ac = prtd->audio_client; if (metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) { pr_debug("%s, got encoder padding %u", __func__, metadata->value[0]); @@ -2729,11 +2831,63 @@ static int msm_compr_set_metadata(struct snd_compr_stream *cstream, } else if (metadata->key == SNDRV_COMPRESS_ENCODER_DELAY) { pr_debug("%s, got encoder delay %u", __func__, metadata->value[0]); prtd->gapless_state.initial_samples_drop = metadata->value[0]; + } else if (metadata->key == SNDRV_COMPRESS_RENDER_MODE) { + return msm_compr_set_render_mode(prtd, metadata->value[0]); + } else if (metadata->key == SNDRV_COMPRESS_CLK_REC_MODE) { + return msm_compr_set_clk_rec_mode(ac, metadata->value[0]); + } else if (metadata->key == SNDRV_COMPRESS_RENDER_WINDOW) { + return msm_compr_set_render_window( + ac, + metadata->value[0], + metadata->value[1], + metadata->value[2], + metadata->value[3]); + } else if (metadata->key == SNDRV_COMPRESS_START_DELAY) { + prtd->start_delay_lsw = metadata->value[0]; + prtd->start_delay_msw = metadata->value[1]; } return 0; } +static int msm_compr_get_metadata(struct snd_compr_stream *cstream, + struct snd_compr_metadata *metadata) +{ + struct msm_compr_audio *prtd; + struct audio_client *ac; + int ret = -EINVAL; + + pr_debug("%s\n", __func__); + + if (!metadata || !cstream || !cstream->runtime) + return ret; + + if (metadata->key != SNDRV_COMPRESS_PATH_DELAY) { + pr_err("%s, unsupported key %d\n", __func__, metadata->key); + return ret; + } + + prtd = cstream->runtime->private_data; + if (!prtd || !prtd->audio_client) { + pr_err("%s: prtd or audio client is NULL\n", __func__); + return ret; + } + + ac = prtd->audio_client; + ret = q6asm_get_path_delay(prtd->audio_client); + if (ret) { + pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret); + return ret; + } + + pr_debug("%s, path delay(in us) %u\n", __func__, ac->path_delay); + + metadata->value[0] = ac->path_delay; + + return ret; +} + + static int msm_compr_set_next_track_param(struct snd_compr_stream *cstream, union snd_codec_options *codec_options) { @@ -3889,6 +4043,7 @@ static struct snd_compr_ops msm_compr_ops = { .pointer = msm_compr_pointer, .set_params = msm_compr_set_params, .set_metadata = msm_compr_set_metadata, + .get_metadata = msm_compr_get_metadata, .set_next_track_param = msm_compr_set_next_track_param, .ack = msm_compr_ack, .copy = msm_compr_copy, diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c index d55c28fab652..c3a4719542ef 100644 --- a/sound/soc/msm/qdsp6v2/q6asm.c +++ b/sound/soc/msm/qdsp6v2/q6asm.c @@ -7934,16 +7934,18 @@ int q6asm_send_mtmx_strtr_window(struct audio_client *ac, 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(matrix) - - sizeof(matrix.hdr) - sizeof(matrix.param); + matrix.param.data_payload_size = + sizeof(struct asm_stream_param_data_v2) + + sizeof(struct asm_session_mtmx_strtr_param_window_v2_t); matrix.param.direction = 0; /* RX */ matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC; matrix.data.param_id = param_id; - matrix.data.param_size = matrix.param.data_payload_size - - sizeof(matrix.data); + matrix.data.param_size = + sizeof(struct asm_session_mtmx_strtr_param_window_v2_t); matrix.data.reserved = 0; - matrix.window_lsw = window_param->window_lsw; - matrix.window_msw = window_param->window_msw; + memcpy(&(matrix.config.window_param), + window_param, + sizeof(struct asm_session_mtmx_strtr_param_window_v2_t)); rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix); if (rc < 0) { @@ -7973,7 +7975,177 @@ int q6asm_send_mtmx_strtr_window(struct audio_client *ac, rc = 0; fail_cmd: return rc; -}; +} + +int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac, + uint32_t render_mode) +{ + struct asm_mtmx_strtr_params matrix; + struct asm_session_mtmx_strtr_param_render_mode_t render_param; + int sz = 0; + int rc = 0; + + pr_debug("%s: render mode is %d\n", __func__, render_mode); + + 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; + } + + if ((render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT) && + (render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC)) { + pr_err("%s: Invalid render mode %d\n", __func__, render_mode); + rc = -EINVAL; + goto exit; + } + + memset(&render_param, 0, + sizeof(struct asm_session_mtmx_strtr_param_render_mode_t)); + render_param.flags = render_mode; + + 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_strtr_param_render_mode_t); + matrix.param.direction = 0; /* RX */ + matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC; + matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD; + matrix.data.param_size = + sizeof(struct asm_session_mtmx_strtr_param_render_mode_t); + matrix.data.reserved = 0; + memcpy(&(matrix.config.render_param), + &render_param, + sizeof(struct asm_session_mtmx_strtr_param_render_mode_t)); + + rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix); + if (rc < 0) { + pr_err("%s: Render mode send 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: timeout, Render mode send 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; +} + +int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac, + uint32_t clk_rec_mode) +{ + struct asm_mtmx_strtr_params matrix; + struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param; + int sz = 0; + int rc = 0; + + pr_debug("%s: clk rec mode is %d\n", __func__, clk_rec_mode); + + 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; + } + + if ((clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE) && + (clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO)) { + pr_err("%s: Invalid clk rec mode %d\n", __func__, clk_rec_mode); + rc = -EINVAL; + goto exit; + } + + memset(&clk_rec_param, 0, + sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t)); + clk_rec_param.flags = clk_rec_mode; + + 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_strtr_param_clk_rec_t); + matrix.param.direction = 0; /* RX */ + matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC; + matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD; + matrix.data.param_size = + sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t); + matrix.data.reserved = 0; + memcpy(&(matrix.config.clk_rec_param), + &clk_rec_param, + sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t)); + + rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix); + if (rc < 0) { + pr_err("%s: clk rec mode send 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: timeout, clk rec mode send 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) { |