diff options
| author | Manish Dewangan <manish@codeaurora.org> | 2016-12-20 12:56:24 +0530 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-02-12 22:17:21 -0800 |
| commit | 563050b24718d7a099be7a30fa5464e3ae00e5c9 (patch) | |
| tree | c6d3566c3077a8b3262ada49aa636cf0c96b9b77 | |
| parent | 88fee0f3817730e279872a381b760833a146aa5b (diff) | |
ASoC: msm: qdsp6v2: Add support to query Drift.
Afe driver changes to query avtimer vs device drift.
Drift obtained can be used to pull the device pll so
that avtimer and device are in sync.
CRs-Fixed: 1112258
Change-Id: I4d4ddb0dbc06270553d583f266a44ddbe9412d1a
Signed-off-by: Manish Dewangan <manish@codeaurora.org>
| -rw-r--r-- | include/sound/apr_audio-v2.h | 102 | ||||
| -rw-r--r-- | include/sound/q6afe-v2.h | 2 | ||||
| -rw-r--r-- | sound/soc/msm/qdsp6v2/q6afe.c | 134 |
3 files changed, 232 insertions, 6 deletions
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h index 3d3a2022bc04..ff0ee57daf78 100644 --- a/include/sound/apr_audio-v2.h +++ b/include/sound/apr_audio-v2.h @@ -9992,6 +9992,108 @@ struct afe_port_group_create { union afe_port_group_config data; } __packed; +/* ID of the parameter used by #AFE_MODULE_AUDIO_DEV_INTERFACE to specify + * the timing statistics of the corresponding device interface. + * Client can periodically query for the device time statistics to help adjust + * the PLL based on the drift value. The get param command must be sent to + * AFE port ID corresponding to device interface + + * This parameter ID supports following get param commands: + * #AFE_PORT_CMD_GET_PARAM_V2 and + * #AFE_PORT_CMD_GET_PARAM_V3. + */ +#define AFE_PARAM_ID_DEV_TIMING_STATS 0x000102AD + +/* Version information used to handle future additions to AFE device + * interface timing statistics (for backward compatibility). + */ +#define AFE_API_VERSION_DEV_TIMING_STATS 0x1 + +/* Enumeration for specifying a sink(Rx) device */ +#define AFE_SINK_DEVICE 0x0 + +/* Enumeration for specifying a source(Tx) device */ +#define AFE_SOURCE_DEVICE 0x1 + +/* Enumeration for specifying the drift reference is of type AV Timer */ +#define AFE_REF_TIMER_TYPE_AVTIMER 0x0 + +/* Message payload structure for the + * AFE_PARAM_ID_DEV_TIMING_STATS parameter. + */ +struct afe_param_id_dev_timing_stats { + /* Minor version used to track the version of device interface timing + * statistics. Currently, the supported version is 1. + * @values #AFE_API_VERSION_DEV_TIMING_STATS + */ + u32 minor_version; + + /* Indicates the device interface direction as either + * source (Tx) or sink (Rx). + * @values + * #AFE_SINK_DEVICE + * #AFE_SOURCE_DEVICE + */ + u16 device_direction; + + /* Reference timer for drift accumulation and time stamp information. + * @values + * #AFE_REF_TIMER_TYPE_AVTIMER @tablebulletend + */ + u16 reference_timer; + + /* + * Flag to indicate if resync is required on the client side for + * drift correction. Flag is set to TRUE for the first get_param + * response after device interface starts. This flag value can be + * used by client to identify if device interface restart has + * happened and if any re-sync is required at their end for drift + * correction. + * @values + * 0: FALSE (Resync not required) + * 1: TRUE (Resync required) @tablebulletend + */ + u32 resync_flag; + + /* Accumulated drift value in microseconds. This value is updated + * every 100th ms. + * Positive drift value indicates AV timer is running faster than device + * Negative drift value indicates AV timer is running slower than device + * @values Any valid int32 number + */ + s32 acc_drift_value; + + /* Lower 32 bits of the 64-bit absolute timestamp of reference + * timer in microseconds. + + * This timestamp corresponds to the time when the drift values + * are accumlated for every 100th ms. + * @values Any valid uint32 number + */ + u32 ref_timer_abs_ts_lsw; + + /* Upper 32 bits of the 64-bit absolute timestamp of reference + * timer in microseconds. + * This timestamp corresponds to the time when the drift values + * are accumlated for every 100th ms. + * @values Any valid uint32 number + */ + u32 ref_timer_abs_ts_msw; +} __packed; + +struct afe_av_dev_drift_get_param { + struct apr_hdr hdr; + struct afe_port_cmd_get_param_v2 get_param; + struct afe_port_param_data_v2 pdata; + struct afe_param_id_dev_timing_stats timing_stats; +} __packed; + +struct afe_av_dev_drift_get_param_resp { + uint32_t status; + struct afe_port_param_data_v2 pdata; + struct afe_param_id_dev_timing_stats timing_stats; +} __packed; + /* Command for Matrix or Stream Router */ #define ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2 0x00010DCE /* Module for AVSYNC */ diff --git a/include/sound/q6afe-v2.h b/include/sound/q6afe-v2.h index e4033e712804..02d772514222 100644 --- a/include/sound/q6afe-v2.h +++ b/include/sound/q6afe-v2.h @@ -366,4 +366,6 @@ int afe_send_custom_tdm_header_cfg( int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port, u32 rate); void afe_set_routing_callback(routing_cb); +int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats, + u16 port); #endif /* __Q6AFE_V2_H__ */ diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c index be5437a186ea..c52d9425c315 100644 --- a/sound/soc/msm/qdsp6v2/q6afe.c +++ b/sound/soc/msm/qdsp6v2/q6afe.c @@ -113,6 +113,7 @@ struct afe_ctl { struct audio_cal_info_sp_ex_vi_ftm_cfg ex_ftm_cfg; struct afe_sp_th_vi_get_param_resp th_vi_resp; struct afe_sp_ex_vi_get_param_resp ex_vi_resp; + struct afe_av_dev_drift_get_param_resp av_dev_drift_resp; int vi_tx_port; int vi_rx_port; uint32_t afe_sample_rates[AFE_MAX_PORTS]; @@ -189,6 +190,38 @@ static void afe_callback_debug_print(struct apr_client_data *data) __func__, data->opcode, data->payload_size); } +static void av_dev_drift_afe_cb_handler(uint32_t *payload, + uint32_t payload_size) +{ + u32 param_id; + struct afe_av_dev_drift_get_param_resp *resp = + (struct afe_av_dev_drift_get_param_resp *) payload; + + if (!(&(resp->pdata))) { + pr_err("%s: Error: resp pdata is NULL\n", __func__); + return; + } + + param_id = resp->pdata.param_id; + if (param_id == AFE_PARAM_ID_DEV_TIMING_STATS) { + if (payload_size < sizeof(this_afe.av_dev_drift_resp)) { + pr_err("%s: Error: received size %d, resp size %zu\n", + __func__, payload_size, + sizeof(this_afe.av_dev_drift_resp)); + return; + } + memcpy(&this_afe.av_dev_drift_resp, payload, + sizeof(this_afe.av_dev_drift_resp)); + if (!this_afe.av_dev_drift_resp.status) { + atomic_set(&this_afe.state, 0); + } else { + pr_debug("%s: av_dev_drift_resp status: %d", __func__, + this_afe.av_dev_drift_resp.status); + atomic_set(&this_afe.state, -1); + } + } +} + static int32_t sp_make_afe_callback(uint32_t *payload, uint32_t payload_size) { u32 param_id; @@ -309,10 +342,7 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) } afe_callback_debug_print(data); if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V2) { - u8 *payload = data->payload; - - if (rtac_make_afe_callback(data->payload, data->payload_size)) - return 0; + uint32_t *payload = data->payload; if (!payload || (data->token >= AFE_MAX_PORTS)) { pr_err("%s: Error: size %d payload %pK token %d\n", @@ -320,9 +350,19 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) payload, data->token); return -EINVAL; } - if (sp_make_afe_callback(data->payload, data->payload_size)) - return -EINVAL; + if (payload[2] == AFE_PARAM_ID_DEV_TIMING_STATS) { + av_dev_drift_afe_cb_handler(data->payload, + data->payload_size); + } else { + if (rtac_make_afe_callback(data->payload, + data->payload_size)) + return 0; + + if (sp_make_afe_callback(data->payload, + data->payload_size)) + return -EINVAL; + } wake_up(&this_afe.wait[data->token]); } else if (data->payload_size) { uint32_t *payload; @@ -6163,6 +6203,88 @@ done: return ret; } +int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats, + u16 port) +{ + int ret = -EINVAL; + int index = 0; + struct afe_av_dev_drift_get_param av_dev_drift; + + if (!timing_stats) { + pr_err("%s: Invalid params\n", __func__); + goto exit; + } + + ret = q6audio_validate_port(port); + if (ret < 0) { + pr_err("%s: invalid port 0x%x ret %d\n", __func__, port, ret); + ret = -EINVAL; + goto exit; + } + + index = q6audio_get_port_index(port); + if (index < 0 || index >= AFE_MAX_PORTS) { + pr_err("%s: Invalid AFE port index[%d]\n", + __func__, index); + ret = -EINVAL; + goto exit; + } + + memset(&av_dev_drift, 0, sizeof(struct afe_av_dev_drift_get_param)); + + av_dev_drift.hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + av_dev_drift.hdr.pkt_size = sizeof(av_dev_drift); + av_dev_drift.hdr.src_port = 0; + av_dev_drift.hdr.dest_port = 0; + av_dev_drift.hdr.token = index; + av_dev_drift.hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2; + av_dev_drift.get_param.mem_map_handle = 0; + av_dev_drift.get_param.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; + av_dev_drift.get_param.param_id = AFE_PARAM_ID_DEV_TIMING_STATS; + av_dev_drift.get_param.payload_address_lsw = 0; + av_dev_drift.get_param.payload_address_msw = 0; + av_dev_drift.get_param.payload_size = sizeof(av_dev_drift) + - sizeof(av_dev_drift.get_param) - sizeof(av_dev_drift.hdr); + av_dev_drift.get_param.port_id = q6audio_get_port_id(port); + av_dev_drift.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; + av_dev_drift.pdata.param_id = AFE_PARAM_ID_DEV_TIMING_STATS; + av_dev_drift.pdata.param_size = sizeof(av_dev_drift.timing_stats); + atomic_set(&this_afe.status, 0); + atomic_set(&this_afe.state, 1); + ret = apr_send_pkt(this_afe.apr, (uint32_t *)&av_dev_drift); + if (ret < 0) { + pr_err("%s: get param port 0x%x param id[0x%x] failed %d\n", + __func__, port, av_dev_drift.get_param.param_id, ret); + goto exit; + } + + ret = wait_event_timeout(this_afe.wait[index], + (atomic_read(&this_afe.state) == 0), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: wait_event timeout\n", __func__); + ret = -EINVAL; + goto exit; + } + + if (atomic_read(&this_afe.status) > 0) { + pr_err("%s: config cmd failed [%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&this_afe.status))); + ret = adsp_err_get_lnx_err_code( + atomic_read(&this_afe.status)); + goto exit; + } + + memcpy(timing_stats, &this_afe.av_dev_drift_resp.timing_stats, + sizeof(this_afe.av_dev_drift_resp.timing_stats)); + ret = 0; +exit: + return ret; +} + int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp) { int ret = -EINVAL; |
