dsp: Add support to update and store clk src values

Add support to update clk src array from machine driver.
Update clk src for different be ids based on clock
frequency at playback.

Change-Id: Ifa09d556fd50f9e2ddef39b5e3ddd25f579f8f6e
Signed-off-by: Sanjana B <sanjb@codeaurora.org>
This commit is contained in:
Sanjana B 2020-05-08 13:29:39 +05:30
parent 111a7ea848
commit a15df0900e
3 changed files with 165 additions and 99 deletions

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
*/
#include <linux/slab.h>
#include <linux/debugfs.h>
@ -268,9 +268,9 @@ struct afe_ctl {
struct afe_clkinfo_per_port {
u16 port_id; /* AFE port ID */
uint32_t clk_id; /* Clock ID */
uint32_t mclk_src_id; /* MCLK SRC ID */
uint32_t mclk_freq; /* MCLK_FREQ */
char clk_src_name[CLK_SRC_NAME_MAX];
};
struct afe_ext_mclk_cb_info {
@ -279,56 +279,52 @@ struct afe_ext_mclk_cb_info {
};
static struct afe_clkinfo_per_port clkinfo_per_port[] = {
{ AFE_PORT_ID_PRIMARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_SECONDARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_TERTIARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_QUATERNARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_QUINARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_SENARY_MI2S_RX, Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_PRIMARY_PCM_RX, Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_SECONDARY_PCM_RX, Q6AFE_LPASS_CLK_ID_SEC_PCM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_TERTIARY_PCM_RX, Q6AFE_LPASS_CLK_ID_TER_PCM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_QUATERNARY_PCM_RX, Q6AFE_LPASS_CLK_ID_QUAD_PCM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_QUINARY_PCM_RX, Q6AFE_LPASS_CLK_ID_QUIN_PCM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_SENARY_PCM_RX, Q6AFE_LPASS_CLK_ID_SEN_PCM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_PRIMARY_TDM_RX, Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_SECONDARY_TDM_RX, Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_TERTIARY_TDM_RX, Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_QUATERNARY_TDM_RX, Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_QUINARY_TDM_RX, Q6AFE_LPASS_CLK_ID_QUIN_TDM_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_PRIMARY_MI2S_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_SECONDARY_MI2S_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_TERTIARY_MI2S_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_QUATERNARY_MI2S_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_QUINARY_MI2S_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_SENARY_MI2S_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_PRIMARY_PCM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_SECONDARY_PCM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_TERTIARY_PCM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_QUATERNARY_PCM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_QUINARY_PCM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_SENARY_PCM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_PRIMARY_TDM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_SECONDARY_TDM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_TERTIARY_TDM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_QUATERNARY_TDM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_QUINARY_TDM_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_PRIMARY_SPDIF_RX,
AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_OUTPUT_CORE,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_PRIMARY_SPDIF_TX,
AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_INPUT_CORE,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_SECONDARY_SPDIF_RX,
AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_OUTPUT_CORE,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_SECONDARY_SPDIF_TX,
AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_INPUT_CORE,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_PRIMARY_META_MI2S_RX, Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
{ AFE_PORT_ID_SECONDARY_META_MI2S_RX, Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT},
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_PRIMARY_META_MI2S_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
{ AFE_PORT_ID_SECONDARY_META_MI2S_RX,
MCLK_SRC_INT, Q6AFE_EXT_MCLK_FREQ_DEFAULT, ""},
};
static struct afe_ext_mclk_cb_info afe_ext_mclk;
@ -337,6 +333,7 @@ static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
static unsigned long afe_configured_cmd;
static struct afe_ctl this_afe;
static char clk_src_name[CLK_SRC_MAX][CLK_SRC_NAME_MAX];
#define TIMEOUT_MS 1000
#define Q6AFE_MAX_VOLUME 0x3FFF
@ -9209,53 +9206,73 @@ static int afe_get_port_idx(u16 port_id)
return -EINVAL;
}
static int afe_get_clk_id(u16 port_id)
static int afe_get_clk_src(u16 port_id, char *clk_src)
{
u16 afe_port = 0;
uint32_t clk_id = -EINVAL;
int idx = 0;
idx = afe_get_port_idx(port_id);
if (idx < 0) {
pr_err("%s: cannot get clock id for port id 0x%x\n", __func__,
afe_port);
idx);
return -EINVAL;
}
clk_id = clkinfo_per_port[idx].clk_id;
pr_debug("%s: clk id 0x%x port id 0x%x\n", __func__, clk_id,
afe_port);
if (clkinfo_per_port[idx].clk_src_name == NULL)
return -EINVAL;
strlcpy(clk_src, clkinfo_per_port[idx].clk_src_name,
CLK_SRC_NAME_MAX);
pr_debug("%s: clk src name %s port id 0x%x\n", __func__, clk_src,
idx);
return clk_id;
return 0;
}
/**
* afe_set_clk_id - Update clock id for AFE port
* afe_set_source_clk - Set audio interface PLL clock source
*
* @port_id: AFE port id
* @clk_id: CLock ID
* @clk_src: Clock source name for port id
*
* Returns 0 on success, appropriate error code otherwise
*/
int afe_set_clk_id(u16 port_id, uint32_t clk_id)
int afe_set_source_clk(u16 port_id, const char *clk_src)
{
u16 afe_port = 0;
int idx = 0;
idx = afe_get_port_idx(port_id);
if (idx < 0) {
pr_debug("%s: cannot set clock id for port id 0x%x\n", __func__,
afe_port);
idx);
return -EINVAL;
}
clkinfo_per_port[idx].clk_id = clk_id;
pr_debug("%s: updated clk id 0x%x port id 0x%x\n", __func__,
clkinfo_per_port[idx].clk_id, afe_port);
if (clk_src == NULL)
return -EINVAL;
strlcpy(clkinfo_per_port[idx].clk_src_name, clk_src, CLK_SRC_NAME_MAX);
pr_debug("%s: updated clk src name %s port id 0x%x\n", __func__,
clkinfo_per_port[idx].clk_src_name, idx);
return 0;
}
EXPORT_SYMBOL(afe_set_clk_id);
EXPORT_SYMBOL(afe_set_source_clk);
/**
* afe_set_clk_src_array - Set afe clk src array from machine driver
*
* @clk_src_array: clk src array for integral and fract clk src
*
*/
void afe_set_clk_src_array(const char *clk_src_array[CLK_SRC_MAX])
{
int i;
for (i = 0; i < CLK_SRC_MAX; i++) {
if (clk_src_array[i] != NULL)
strlcpy(clk_src_name[i], clk_src_array[i],
CLK_SRC_NAME_MAX);
}
}
EXPORT_SYMBOL(afe_set_clk_src_array);
/**
* afe_set_pll_clk_drift - Set audio interface PLL clock drift
@ -9271,8 +9288,33 @@ int afe_set_pll_clk_drift(u16 port_id, int32_t set_clk_drift,
{
struct afe_set_clk_drift clk_drift;
struct param_hdr_v3 param_hdr;
uint32_t clk_id;
char clk_src_name[CLK_SRC_NAME_MAX];
int index = 0, ret = 0;
uint32_t build_major_version = 0;
uint32_t build_minor_version = 0;
uint32_t build_branch_version = 0;
int afe_api_version = 0;
ret = q6core_get_avcs_avs_build_version_info(
&build_major_version, &build_minor_version,
&build_branch_version);
if (ret < 0) {
pr_err("%s error in retrieving avs build version %d\n",
__func__, ret);
return ret;
}
afe_api_version = q6core_get_avcs_api_version_per_service(
APRV2_IDS_SERVICE_ID_ADSP_AFE_V);
if (afe_api_version < 0) {
pr_err("%s error in retrieving afe api version %d\n",
__func__, afe_api_version);
return afe_api_version;
}
pr_debug("%s: mjor: %u, mnor: %u, brnch: %u, afe_api: %u\n",
__func__, build_major_version, build_minor_version,
build_branch_version, afe_api_version);
memset(&param_hdr, 0, sizeof(param_hdr));
memset(&clk_drift, 0, sizeof(clk_drift));
@ -9290,24 +9332,18 @@ int afe_set_pll_clk_drift(u16 port_id, int32_t set_clk_drift,
return ret;
}
clk_id = afe_get_clk_id(port_id);
if (clk_id < 0) {
pr_err("%s: cannot get clk id for port id 0x%x\n",
ret = afe_get_clk_src(port_id, clk_src_name);
if (ret) {
pr_err("%s: cannot get clk src name for port id 0x%x\n",
__func__, port_id);
return -EINVAL;
}
if (clk_id & 0x01) {
pr_err("%s: cannot adjust clock drift for external clock id 0x%x\n",
__func__, clk_id);
return -EINVAL;
}
clk_drift.clk_drift = set_clk_drift;
clk_drift.clk_reset = clk_reset;
clk_drift.clk_id = clk_id;
pr_debug("%s: clk id = 0x%x clk drift = %d clk reset = %d port id 0x%x\n",
__func__, clk_drift.clk_id, clk_drift.clk_drift,
strlcpy(clk_drift.clk_src_name, clk_src_name, CLK_SRC_NAME_MAX);
pr_debug("%s: clk src= %s clkdrft= %d clkrst= %d port id 0x%x\n",
__func__, clk_drift.clk_src_name, clk_drift.clk_drift,
clk_drift.clk_reset, port_id);
mutex_lock(&this_afe.afe_clk_lock);
@ -9316,12 +9352,22 @@ int afe_set_pll_clk_drift(u16 port_id, int32_t set_clk_drift,
param_hdr.param_id = AFE_PARAM_ID_CLOCK_ADJUST;
param_hdr.param_size = sizeof(struct afe_set_clk_drift);
if ((build_major_version == AVS_BUILD_MAJOR_VERSION_V2) &&
(build_minor_version == AVS_BUILD_MINOR_VERSION_V9) &&
(build_branch_version == AVS_BUILD_BRANCH_VERSION_V3) &&
(afe_api_version >= AFE_API_VERSION_V10)) {
param_hdr.param_size = sizeof(struct afe_set_clk_drift);
ret = q6afe_svc_pack_and_set_param_in_band(index, param_hdr,
(u8 *) &clk_drift);
if (ret < 0)
pr_err_ratelimited("%s: AFE PLL clk drift failed with ret %d\n",
__func__, ret);
} else {
ret = -EINVAL;
pr_err_ratelimited("%s: AFE PLL clk drift failed ver mismatch %d\n",
__func__, ret);
}
mutex_unlock(&this_afe.afe_clk_lock);
return ret;
}
@ -9503,10 +9549,19 @@ int afe_set_lpass_clock_v2(u16 port_id, struct afe_clk_set *cfg)
return -EINVAL;
}
ret = afe_set_clk_id(port_id, cfg->clk_id);
if (clk_src_name != NULL) {
if (cfg->clk_freq_in_hz % AFE_SAMPLING_RATE_8KHZ) {
if (clk_src_name[CLK_SRC_FRACT] != NULL)
ret = afe_set_source_clk(port_id,
clk_src_name[CLK_SRC_FRACT]);
} else if (clk_src_name[CLK_SRC_INTEGRAL] != NULL) {
ret = afe_set_source_clk(port_id,
clk_src_name[CLK_SRC_INTEGRAL]);
}
if (ret < 0)
pr_err("%s: afe_set_clk_id fail %d\n", __func__, ret);
pr_err("%s: afe_set_source_clk fail %d\n",
__func__, ret);
}
idx = afe_get_port_idx(port_id);
if (idx < 0) {
pr_err("%s: cannot get clock id for port id 0x%x\n", __func__,

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
*/
@ -12348,16 +12348,15 @@ struct afe_clk_cfg {
#define AFE_MODULE_CLOCK_SET 0x0001028F
#define AFE_PARAM_ID_CLOCK_SET 0x00010290
struct afe_set_clk_drift {
/*
* Clock ID
* @values
* - 0x100 to 0x10E
* - 0x200 to 0x20C
* - 0x500 to 0x505
*/
uint32_t clk_id;
#define CLK_SRC_NAME_MAX 32
enum {
CLK_SRC_INTEGRAL,
CLK_SRC_FRACT,
CLK_SRC_MAX
};
struct afe_set_clk_drift {
/*
* Clock drift (in PPB) to be set.
* @values
@ -12366,12 +12365,20 @@ struct afe_set_clk_drift {
int32_t clk_drift;
/*
* Clock rest.
* Clock reset.
* @values
* - 1 -- Reset PLL with the original frequency
* - 0 -- Adjust the clock with the clk drift value
*/
uint32_t clk_reset;
/*
* Clock src name.
* @values
* - values to be set from machine driver
* - LPAPLL0 -- integral clk src
* - LPAPLL2 -- fractional clk src
*/
char clk_src_name[CLK_SRC_NAME_MAX];
} __packed;
/* This param id is used to adjust audio interface PLL*/

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
*/
#ifndef __Q6AFE_V2_H__
#define __Q6AFE_V2_H__
@ -53,7 +53,9 @@
#define AFE_API_VERSION_V9 9
/* for external mclk dynamic switch */
#define AFE_API_VERSION_V8 8
#define AFE_API_VERSION_V10 10
#define AFE_SAMPLING_RATE_8KHZ 8000
/* the different modes for data*/
#define BAP_UNICAST 1
@ -545,6 +547,8 @@ enum {
AFE_LPASS_CORE_HW_DCODEC_BLOCK,
AFE_LPASS_CORE_HW_VOTE_MAX
};
int afe_set_source_clk(u16 port_id, const char *clk_src);
void afe_set_clk_src_array(const char *clk_src[CLK_SRC_MAX]);
int afe_set_mclk_src_cfg(u16 port_id, uint32_t mclk_src_id, uint32_t mclk_freq);
typedef int (*afe_enable_mclk_and_get_info_cb_func) (void *private_data,