ASoC: audio: add APIs to query for AVS version

Add APIs to query for the AVS framework and services versions. Cache
the information retrieved for use by HLOS services.

CRs-Fixed: 2018143
Signed-off-by: Siena Richard <sienar@codeaurora.org>
Change-Id: I6c262e7302a9b69f5fdd22762122a8db72c8c274
This commit is contained in:
Siena Richard 2017-03-16 12:03:53 -07:00 committed by Gerrit - the friendly Code Review server
parent 812c879d35
commit 4edea86ce5
3 changed files with 202 additions and 7 deletions

View file

@ -9349,6 +9349,73 @@ struct asm_aptx_dec_fmt_blk_v2 {
*/
} __packed;
/* Q6Core Specific */
#define AVCS_CMD_GET_FWK_VERSION (0x0001292C)
#define AVCS_CMDRSP_GET_FWK_VERSION (0x0001292D)
#define AVCS_SERVICE_ID_ALL (0xFFFFFFFF)
struct avcs_get_fwk_version {
/*
* Indicates the major version of the AVS build.
* This value is incremented on chipset family boundaries.
*/
uint32_t build_major_version;
/*
* Minor version of the AVS build.
* This value represents the mainline to which the AVS build belongs.
*/
uint32_t build_minor_version;
/* Indicates the AVS branch version to which the image belongs. */
uint32_t build_branch_version;
/* Indicates the AVS sub-branch or customer product line information. */
uint32_t build_subbranch_version;
/* Number of supported AVS services in the current build. */
uint32_t num_services;
};
struct avs_svc_api_info {
/*
* APRV2 service IDs for the individual static services.
*
* @values
* - APRV2_IDS_SERVICE_ID_ADSP_CORE_V
* - APRV2_IDS_SERVICE_ID_ADSP_AFE_V
* - APRV2_IDS_SERVICE_ID_ADSP_ASM_V
* - APRV2_IDS_SERVICE_ID_ADSP_ADM_V
* - APRV2_IDS_SERVICE_ID_ADSP_MVM_V
* - APRV2_IDS_SERVICE_ID_ADSP_CVS_V
* - APRV2_IDS_SERVICE_ID_ADSP_CVP_V
* - APRV2_IDS_SERVICE_ID_ADSP_LSM_V
*/
uint32_t service_id;
/*
* Indicates the API version of the service.
*
* Each new API update that warrants a change on the HLOS side triggers
* an increment in the version.
*/
uint32_t api_version;
/*
* Indicates the API increments on a sub-branch (not on the mainline).
*
* API branch version numbers can increment independently on different
* sub-branches.
*/
uint32_t api_branch_version;
};
struct avcs_fwk_ver_info {
struct avcs_get_fwk_version avcs_build;
struct avs_svc_api_info services[0];
};
/* LSM Specific */
#define VW_FEAT_DIM (39)

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2016, 2017 The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -13,6 +13,7 @@
#ifndef __Q6CORE_H__
#define __Q6CORE_H__
#include <linux/qdsp6v2/apr.h>
#include <sound/apr_audio-v2.h>
@ -23,6 +24,9 @@ bool q6core_is_adsp_ready(void);
int q6core_add_remove_pool_pages(phys_addr_t buf_add, uint32_t bufsz,
uint32_t mempool_id, bool add_pages);
int q6core_get_avcs_fwk_ver_info(uint32_t service_id,
struct avcs_fwk_ver_info *ver_info);
#define ADSP_CMD_SET_DTS_EAGLE_DATA_ID 0x00012919
#define DTS_EAGLE_LICENSE_ID 0x00028346
struct adsp_dts_eagle {

View file

@ -22,6 +22,7 @@
#include <soc/qcom/smd.h>
#include <sound/q6core.h>
#include <sound/audio_cal_utils.h>
#include <sound/adsp_err.h>
#define TIMEOUT_MS 1000
/*
@ -37,16 +38,30 @@ enum {
CORE_MAX_CAL
};
enum ver_query_status {
VER_QUERY_UNATTEMPTED,
VER_QUERY_UNSUPPORTED,
VER_QUERY_SUPPORTED
};
struct q6core_avcs_ver_info {
enum ver_query_status status;
struct avcs_fwk_ver_info avcs_fwk_ver_info;
};
struct q6core_str {
struct apr_svc *core_handle_q;
wait_queue_head_t bus_bw_req_wait;
wait_queue_head_t cmd_req_wait;
wait_queue_head_t avcs_fwk_ver_req_wait;
u32 bus_bw_resp_received;
enum cmd_flags {
FLAG_NONE,
FLAG_CMDRSP_LICENSE_RESULT
} cmd_resp_received_flag;
u32 avcs_fwk_ver_resp_received;
struct mutex cmd_lock;
struct mutex ver_lock;
union {
struct avcs_cmdrsp_get_license_validation_result
cmdrsp_license_result;
@ -55,6 +70,7 @@ struct q6core_str {
struct cal_type_data *cal_data[CORE_MAX_CAL];
uint32_t mem_map_cal_handle;
int32_t adsp_status;
struct q6core_avcs_ver_info q6core_avcs_ver_info;
};
static struct q6core_str q6core_lcl;
@ -131,6 +147,17 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
q6core_lcl.bus_bw_resp_received = 1;
wake_up(&q6core_lcl.bus_bw_req_wait);
break;
case AVCS_CMD_GET_FWK_VERSION:
pr_debug("%s: Cmd = AVCS_CMD_GET_FWK_VERSION status[%s]\n",
__func__, adsp_err_get_err_str(payload1[1]));
/* ADSP status to match Linux error standard */
q6core_lcl.adsp_status = -payload1[1];
if (payload1[1] == ADSP_EUNSUPPORTED)
q6core_lcl.q6core_avcs_ver_info.status =
VER_QUERY_UNSUPPORTED;
q6core_lcl.avcs_fwk_ver_resp_received = 1;
wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
break;
default:
pr_err("%s: Invalid cmd rsp[0x%x][0x%x] opcode %d\n",
__func__,
@ -174,6 +201,13 @@ static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
q6core_lcl.cmd_resp_received_flag = FLAG_CMDRSP_LICENSE_RESULT;
wake_up(&q6core_lcl.cmd_req_wait);
break;
case AVCS_CMDRSP_GET_FWK_VERSION:
pr_debug("%s: Received AVCS_CMDRSP_GET_FWK_VERSION\n",
__func__);
q6core_lcl.q6core_avcs_ver_info.status = VER_QUERY_SUPPORTED;
q6core_lcl.avcs_fwk_ver_resp_received = 1;
wake_up(&q6core_lcl.avcs_fwk_ver_req_wait);
break;
default:
pr_err("%s: Message id from adsp core svc: 0x%x\n",
__func__, data->opcode);
@ -230,6 +264,97 @@ struct cal_block_data *cal_utils_get_cal_block_by_key(
return NULL;
}
static int q6core_send_get_avcs_fwk_ver_cmd(void)
{
struct apr_hdr avcs_ver_cmd;
int ret;
avcs_ver_cmd.hdr_field =
APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
APR_PKT_VER);
avcs_ver_cmd.pkt_size = sizeof(struct apr_hdr);
avcs_ver_cmd.src_port = 0;
avcs_ver_cmd.dest_port = 0;
avcs_ver_cmd.token = 0;
avcs_ver_cmd.opcode = AVCS_CMD_GET_FWK_VERSION;
q6core_lcl.adsp_status = 0;
q6core_lcl.avcs_fwk_ver_resp_received = 0;
ret = apr_send_pkt(q6core_lcl.core_handle_q,
(uint32_t *) &avcs_ver_cmd);
if (ret < 0) {
pr_err("%s: failed to send apr packet, ret=%d\n", __func__,
ret);
goto done;
}
ret = wait_event_timeout(q6core_lcl.avcs_fwk_ver_req_wait,
(q6core_lcl.avcs_fwk_ver_resp_received == 1),
msecs_to_jiffies(TIMEOUT_MS));
if (!ret) {
pr_err("%s: wait_event timeout for AVCS fwk version info\n",
__func__);
ret = -ETIMEDOUT;
goto done;
}
if (q6core_lcl.adsp_status < 0) {
/*
* adsp_err_get_err_str expects a positive value but we store
* the DSP error as negative to match the Linux error standard.
* Pass in the negated value so adsp_err_get_err_str returns
* the correct string.
*/
pr_err("%s: DSP returned error[%s]\n", __func__,
adsp_err_get_err_str(-q6core_lcl.adsp_status));
ret = adsp_err_get_lnx_err_code(q6core_lcl.adsp_status);
goto done;
}
ret = 0;
done:
return ret;
}
int q6core_get_avcs_fwk_ver_info(uint32_t service_id,
struct avcs_fwk_ver_info *ver_info)
{
int ret;
mutex_lock(&(q6core_lcl.ver_lock));
pr_debug("%s: q6core_avcs_ver_info.status(%d)\n", __func__,
q6core_lcl.q6core_avcs_ver_info.status);
switch (q6core_lcl.q6core_avcs_ver_info.status) {
case VER_QUERY_SUPPORTED:
ret = 0;
break;
case VER_QUERY_UNSUPPORTED:
ret = -EOPNOTSUPP;
break;
case VER_QUERY_UNATTEMPTED:
if (q6core_is_adsp_ready()) {
ret = q6core_send_get_avcs_fwk_ver_cmd();
} else {
pr_err("%s: ADSP is not ready to query version\n",
__func__);
ret = -ENODEV;
}
break;
default:
pr_err("%s: Invalid version query status %d\n", __func__,
q6core_lcl.q6core_avcs_ver_info.status);
ret = -EINVAL;
break;
}
mutex_unlock(&(q6core_lcl.ver_lock));
return ret;
}
EXPORT_SYMBOL(q6core_get_avcs_fwk_ver_info);
int32_t core_set_license(uint32_t key, uint32_t module_id)
{
struct avcs_cmd_set_license *cmd_setl = NULL;
@ -887,18 +1012,16 @@ err:
static int __init core_init(void)
{
memset(&q6core_lcl, 0, sizeof(struct q6core_str));
init_waitqueue_head(&q6core_lcl.bus_bw_req_wait);
q6core_lcl.bus_bw_resp_received = 0;
q6core_lcl.core_handle_q = NULL;
init_waitqueue_head(&q6core_lcl.cmd_req_wait);
init_waitqueue_head(&q6core_lcl.avcs_fwk_ver_req_wait);
q6core_lcl.cmd_resp_received_flag = FLAG_NONE;
mutex_init(&q6core_lcl.cmd_lock);
q6core_lcl.mem_map_cal_handle = 0;
q6core_lcl.adsp_status = 0;
mutex_init(&q6core_lcl.ver_lock);
q6core_init_cal_data();
return 0;
}
module_init(core_init);
@ -906,6 +1029,7 @@ module_init(core_init);
static void __exit core_exit(void)
{
mutex_destroy(&q6core_lcl.cmd_lock);
mutex_destroy(&q6core_lcl.ver_lock);
q6core_delete_cal_data();
}
module_exit(core_exit);