Files
99_7018_lmx/cpu/br28/audio_codec_clock.c
2025-10-29 13:10:02 +08:00

375 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*****************************************************************
>file name : audio_codec_clock.c
>create time : Thu 03 Jun 2021 09:36:12 AM CST
>History :
2021-11-19 : 增加后台叠加时钟的配置,用于满足一些后台运行的
音频处理
*****************************************************************/
#define LOG_TAG "[CODEC_CLK]"
#define LOG_INFO_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_DUMP_ENABLE
#define LOG_ERROR_ENABLE
#define LOG_WARN_ENABLE
#include "debug.h"
#include "app_config.h"
#include "system/includes.h"
#include "audio_codec_clock.h"
#include "audio_dec_eff.h"
#include "asm/dac.h"
#include "avctp_user.h"
#define AUDIO_CODING_ALL (0xffffffff)
#define MAX_CODING_TYPE_NUM 4 //可根据模式的解码格式需求扩展
#define AUDIO_CODEC_BASE_CLK SYS_24M
static LIST_HEAD(codec_clock_head);
struct audio_codec_clock {
u32 coding_type;
u32 clk;
u8 background; //后台运行的时钟
};
struct audio_codec_clk_context {
u8 mode;
struct audio_codec_clock params;
struct list_head entry;
};
#define SYS_60M SYS_64M
const struct audio_codec_clock audio_clock[AUDIO_MAX_MODE][MAX_CODING_TYPE_NUM] = {
{
//A2DP_MODE
{
AUDIO_CODING_SBC,
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG || defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
SYS_76M,
#elif (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)) || (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
SYS_76M,
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) && AUDIO_OUT_EFFECT_ENABLE)) || (AUDIO_VBASS_CONFIG || AUDIO_SURROUND_CONFIG)
SYS_60M,
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE) || TCFG_DRC_ENABLE || TCFG_AUDIO_ANC_ENABLE || TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
SYS_48M,
#else
SYS_32M,
#endif
},
{
AUDIO_CODING_AAC,
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
SYS_96M,
#else
#if defined(AUDIO_SPK_EQ_CONFIG) && AUDIO_SPK_EQ_CONFIG || AUDIO_VBASS_CONFIG || defined(TCFG_AUDIO_MDRC_ENABLE) && TCFG_AUDIO_MDRC_ENABLE
SYS_76M,
#elif (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))|| (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
SYS_64M,
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE)) || AUDIO_SURROUND_CONFIG || TCFG_DRC_ENABLE
#if (TCFG_AUDIO_ANC_ENABLE)
SYS_64M,
#else
SYS_60M,
#endif /*TCFG_AUDIO_ANC_ENABLE*/
#else
SYS_48M,
#endif
#endif
},
{
AUDIO_CODING_LDAC,
#if (AUDIO_SURROUND_CONFIG && (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR))|| (defined(TCFG_AUDIO_DAC_24BIT_MODE) && TCFG_AUDIO_DAC_24BIT_MODE)
SYS_128M,
#elif (TCFG_BT_MUSIC_EQ_ENABLE && ((EQ_SECTION_MAX >= 10) || AUDIO_OUT_EFFECT_ENABLE)) | (AUDIO_VBASS_CONFIG || AUDIO_SURROUND_CONFIG) || TCFG_DRC_ENABLE
#if (TCFG_AUDIO_ANC_ENABLE)
SYS_128M,
#else
SYS_128M,
#endif /*TCFG_AUDIO_ANC_ENABLE*/
#else
#if (TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR)
SYS_128M,
#else
SYS_128M,
#endif /*TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR*/
#endif
}
},
{
//ESCO MODE
{
AUDIO_CODING_MSBC,
#if TCFG_AUDIO_DAC_CONNECT_MODE == DAC_OUTPUT_LR
#if (TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE)
SYS_76M,
#else /*TCFG_AUDIO_CVP_NS_MODE == CVP_DNS_MODE*/
SYS_96M,
#endif /*TCFG_AUDIO_CVP_NS_MODE == CVP_ANS_MODE*/
#else
/* SYS_48M, */
0,
#endif
},
{AUDIO_CODING_CVSD, 0},
},
{
//TONE MODE
{AUDIO_CODING_AAC | AUDIO_CODING_WAV | AUDIO_CODING_WTGV2 | AUDIO_CODING_MP3, SYS_64M},
{AUDIO_CODING_ALL, 0},
},
{
//FILE MODE
{AUDIO_CODING_ALL, 120 * 1000000L},
},
{
//PC MODE
{AUDIO_CODING_ALL, 96 * 1000000L},
},
{
//USB MIC MODE
#if (TCFG_CVP_DEVELOP_ENABLE == CVP_CFG_AIS_3MIC)
{AUDIO_CODING_ALL, 128 * 1000000L},
#else
{AUDIO_CODING_ALL, 96 * 1000000L},
#endif
},
{
//VAD MODE
{AUDIO_CODING_ALL, SYS_32M, 1},
},
{
//SPATIAL EFFECT MODE
#if ((defined TCFG_AUDIO_EFFECT_TASK_EBABLE) && TCFG_AUDIO_EFFECT_TASK_EBABLE)
{AUDIO_CODING_ALL, SYS_32M, 1},
#else
{AUDIO_CODING_ALL, SYS_120M, 1},
#endif /*TCFG_AUDIO_EFFECT_TASK_EBABLE*/
},
{
// SPEAK_TO_CHAT_MODE
{AUDIO_CODING_ALL, 48 * 1000000L}
},
{
// ANC_EAR_ADAPTIVE_MODE
{AUDIO_CODING_ALL, SYS_160M, 0}
},
{
// ANC_DUT_SZ_FFT_MODE
{AUDIO_CODING_ALL, SYS_120M, 0}
},
//TODO
};
static u32 audio_codec_background_clock(void)
{
struct audio_codec_clk_context *ctx;
u32 clk = 0;
if (list_empty(&codec_clock_head)) {
return 0;
}
list_for_each_entry(ctx, &codec_clock_head, entry) {
if (ctx->params.background) {
clk += ctx->params.clk;
}
}
return clk;
}
static void audio_codec_background_clock_add(u32 clk)
{
struct audio_codec_clk_context *ctx;
if (list_empty(&codec_clock_head)) {
return;
}
list_for_each_entry(ctx, &codec_clock_head, entry) {
ctx->params.clk += clk;
}
}
static void audio_codec_background_clock_del(u32 clk)
{
struct audio_codec_clk_context *ctx;
if (list_empty(&codec_clock_head)) {
return;
}
list_for_each_entry(ctx, &codec_clock_head, entry) {
ctx->params.clk -= clk;
}
}
static bool audio_codec_mode_exist(u8 mode)
{
struct audio_codec_clk_context *ctx;
if (list_empty(&codec_clock_head)) {
return false;
}
list_for_each_entry(ctx, &codec_clock_head, entry) {
if (ctx->mode == mode) {
return true;
}
}
return false;
}
int audio_codec_clock_set(u8 mode, u32 coding_type, u8 preemption)
{
u32 new_clk = 0;
u32 background_clk = 0;
if (mode >= AUDIO_MAX_MODE) {
log_error("Not support this mode : %d", mode);
return -EINVAL;
}
if (audio_codec_mode_exist(mode)) {
return 0;
}
const struct audio_codec_clock *params = audio_clock[mode];
int i = 0;
for (i = 0; i < MAX_CODING_TYPE_NUM; i++) {
if (params[i].coding_type & coding_type) {
goto match_clock;
}
}
log_error("Not found right coding type : %d", coding_type);
return -EINVAL;
match_clock:
if (params[i].background) {
/*如果是后台运行的,则需要处理最终时钟为前台+后台时钟总和*/
audio_codec_background_clock_add(params[i].clk);
new_clk = params[i].clk;
struct audio_codec_clk_context *first = list_empty(&codec_clock_head) ? NULL : list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
if (first) {
new_clk = first->params.clk;
} else {
/*后台运行时钟比较接近负载极限容易导致其他跑不过来因此多加12M*/
new_clk += 12 * 1000000L;
}
goto clock_set;
}
background_clk = audio_codec_background_clock();
new_clk = (params[i].clk ? params[i].clk : clk_get("sys")) + background_clk;
if (!preemption) {
struct audio_codec_clk_context *ctx1;
if (!list_empty(&codec_clock_head)) {
ctx1 = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
if (ctx1 && !ctx1->params.background) {
if (new_clk <= ctx1->params.clk) {
/*叠加解码的时钟不可小于在播放的音频时钟*/
new_clk = ctx1->params.clk + 12 * 1000000;
} else {
new_clk += 32 * 1000000;
}
}
}
}
clock_set:
struct audio_codec_clk_context *ctx = (struct audio_codec_clk_context *)zalloc(sizeof(struct audio_codec_clk_context));
ctx->mode = mode;
ctx->params.coding_type = coding_type;
ctx->params.background = params[i].background;
ctx->params.clk = ctx->params.background ? params[i].clk : new_clk;
clk_set("sys", new_clk);
if (ctx->params.background) {
list_add_tail(&ctx->entry, &codec_clock_head);
} else {
list_add(&ctx->entry, &codec_clock_head);
}
return 0;
}
void audio_codec_clock_del(u8 mode)
{
struct audio_codec_clk_context *ctx;
int next_clk = 0;
u32 remove_clk = 0;
list_for_each_entry(ctx, &codec_clock_head, entry) {
if (ctx->mode == mode) {
goto clock_del;
}
}
return;
clock_del:
list_del(&ctx->entry);
if (ctx->params.background) {
audio_codec_background_clock_del(ctx->params.clk);
remove_clk = ctx->params.clk;
}
free(ctx);
if (!list_empty(&codec_clock_head)) {
ctx = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
if (ctx) {
next_clk = ctx->params.clk;
}
} else {
u32 current_clk = clk_get("sys");
#if (TCFG_BD_NUM == 2)&&(TCFG_BT_SUPPORT_AAC==1)
if ((mode == AUDIO_A2DP_MODE) && (get_total_connect_dev() > 1)) {
next_clk = current_clk - remove_clk;
} else {
if (remove_clk) {
next_clk = current_clk - remove_clk;
} else {
next_clk = AUDIO_CODEC_BASE_CLK; //不是后台时钟,设置音频基础时钟
}
}
#else
if (remove_clk) {
next_clk = current_clk - remove_clk;
} else {
next_clk = AUDIO_CODEC_BASE_CLK; //不是后台时钟,设置音频基础时钟
}
#endif
}
if (!next_clk || next_clk < AUDIO_CODEC_BASE_CLK) {
next_clk = list_empty(&codec_clock_head) ? clk_get("sys") : AUDIO_CODEC_BASE_CLK;
}
clk_set("sys", next_clk);
}
void audio_codec_clock_check(void)
{
struct audio_codec_clk_context *ctx;
if (!list_empty(&codec_clock_head)) {
ctx = list_first_entry(&codec_clock_head, struct audio_codec_clk_context, entry);
if (!ctx) {
return;
}
u32 current_clk = clk_get("sys");
u32 expect_clk = ctx->params.background ? (ctx->params.clk + 12 * 1000000L) : ctx->params.clk;
if ((current_clk < 192 * 1000000L) && current_clk < expect_clk) {
log_error("Audio codec clock error : %dM, %dM.", current_clk / 1000000, expect_clk / 1000000);
clk_set("sys", expect_clk);
}
}
}