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

Commit f969b026 authored by Siena Richard's avatar Siena Richard Committed by Gerrit - the friendly Code Review server
Browse files

ASoC: audio: add APIs to determine correct AFE clock version



AFE clock APIs can change depending on the AVS service version.
Provide APIs to determine which clock version should be used.

CRs-Fixed: 2018143
Signed-off-by: default avatarSiena Richard <sienar@codeaurora.org>
Change-Id: I6c262e7302a9b69f5fdd22762122a8db72c8c274
parent 2ba32820
Loading
Loading
Loading
Loading
+68 −0
Original line number Diff line number Diff line
@@ -8353,6 +8353,74 @@ 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)
#define AVCS_SERVICE_ID_AFE                     (0x4)

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)

+6 −0
Original line number Diff line number Diff line
@@ -189,6 +189,11 @@ enum afe_cal_mode {
	AFE_CAL_MODE_NONE,
};

enum lpass_clk_ver {
	LPASS_CLK_VER_1,
	LPASS_CLK_VER_2,
};

struct afe_audio_buffer {
	dma_addr_t phys;
	void       *data;
@@ -234,6 +239,7 @@ struct aanc_data {

int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
int afe_close(int port_id);
enum lpass_clk_ver afe_get_lpass_clk_ver(void);
int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
int afe_loopback_gain(u16 port_id, u16 volume);
+5 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, 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>



@@ -21,6 +22,9 @@

bool q6core_is_adsp_ready(void);

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 {
+34 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <sound/apr_audio-v2.h>
#include <sound/q6afe-v2.h>
#include <sound/q6audio-v2.h>
#include <sound/q6core.h>
#include "msm-pcm-routing-v2.h"
#include <sound/audio_cal_utils.h>
#include <sound/adsp_err.h>
@@ -5130,6 +5131,39 @@ int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg)
	return ret;
}

static int afe_get_service_ver(void)
{
	int ret;

	ret = q6core_get_avcs_fwk_ver_info(AVCS_SERVICE_ID_AFE, NULL);
	if (ret)
		pr_err("%s: failed to get version info for AFE service %d\n",
		       __func__, AVCS_SERVICE_ID_AFE);

	return ret;
}

enum lpass_clk_ver afe_get_lpass_clk_ver(void)
{
	enum lpass_clk_ver lpass_clk_ver;

	/*
	 * Use different APIs to set the LPASS clock depending on the AFE
	 * version. On success afe_get_service_ver returns 0 signyfing the
	 * latest AFE version is supported. Use LPASS clock version 2 if the
	 * latest AFE version is supported, otherwise use LPASS clock version 1.
	 */
	lpass_clk_ver = (afe_get_service_ver() == 0) ?
		LPASS_CLK_VER_2 : LPASS_CLK_VER_1;

	pr_debug("%s: returning %s\n", __func__,
		 (lpass_clk_ver == LPASS_CLK_VER_2) ?
			"LPASS_CLK_VER_2" : "LPASS_CLK_VER_1");

	return lpass_clk_ver;
}
EXPORT_SYMBOL(afe_get_lpass_clk_ver);

int afe_set_lpass_internal_digital_codec_clock(u16 port_id,
			struct afe_digital_clk_cfg *cfg)
{
+132 −7
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, 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
@@ -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;
@@ -119,6 +135,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__,
@@ -162,6 +189,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);
@@ -218,6 +252,98 @@ 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 = -ETIME;
		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 = -ENOSYS;
		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;
@@ -931,18 +1057,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);
@@ -950,6 +1074,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);