media: rockchip: hdmirx: fix audio fifo underflow or overflow when working for audio with high jitter

Signed-off-by: Shunhua Lan <lsh@rock-chips.com>
Change-Id: Ibf4dc35997e742119aaae28a9a4deb4bcdf65b7e
This commit is contained in:
Shunhua Lan
2024-10-14 15:12:07 +08:00
committed by 兰顺华
parent fdea02a3ef
commit 4bfb13e85d

View File

@@ -71,7 +71,7 @@ MODULE_PARM_DESC(low_latency, "low_latency en(0-1)");
#define MEMORY_ALIGN_ROUND_UP_BYTES 64
#define HDMIRX_PLANE_Y 0
#define HDMIRX_PLANE_CBCR 1
#define INIT_FIFO_STATE 64
#define INIT_FIFO_STATE 128
#define RK_IRQ_HDMIRX_HDMI 210
#define FILTER_FRAME_CNT 6
#define CPU_LIMIT_FREQ_KHZ 1200000
@@ -3492,12 +3492,43 @@ static void hdmirx_audio_clk_ppm_inc(struct rk_hdmirx_dev *hdmirx_dev, int ppm)
delta = (int)div64_u64((uint64_t)rate * ppm + 500000, 1000000);
delta *= inc;
rate = hdmirx_dev->audio_state.hdmirx_aud_clkrate + delta;
dev_dbg(hdmirx_dev->dev, "%s: %u to %u(delta:%d)\n",
__func__, hdmirx_dev->audio_state.hdmirx_aud_clkrate, rate, delta);
dev_dbg(hdmirx_dev->dev, "%s: %u to %u(delta:%d ppm:%d)\n",
__func__, hdmirx_dev->audio_state.hdmirx_aud_clkrate, rate, delta, ppm);
clk_set_rate(hdmirx_dev->clks[1].clk, rate);
hdmirx_dev->audio_state.hdmirx_aud_clkrate = rate;
}
static int hdmirx_audio_clk_adjust(struct rk_hdmirx_dev *hdmirx_dev,
int total_offset, int single_offset)
{
int shedule_time = 500;
int ppm = 10;
uint32_t offset_abs;
offset_abs = abs(total_offset);
if (offset_abs > 200) {
ppm += 200;
shedule_time -= 100;
}
if (offset_abs > 100) {
ppm += 200;
shedule_time -= 100;
}
if (offset_abs > 32) {
ppm += 20;
shedule_time -= 100;
}
if (offset_abs > 16)
ppm += 20;
if (total_offset > 16 && single_offset > 0)
hdmirx_audio_clk_ppm_inc(hdmirx_dev, ppm);
else if (total_offset < -16 && single_offset < 0)
hdmirx_audio_clk_ppm_inc(hdmirx_dev, -ppm);
if (!hdmirx_dev->audio_present)
shedule_time = 50;
return shedule_time;
}
static void hdmirx_audio_set_state(struct rk_hdmirx_dev *hdmirx_dev, enum audio_stat stat)
{
switch (stat) {
@@ -3730,10 +3761,8 @@ static void hdmirx_delayed_work_audio(struct work_struct *work)
process_audio_change(hdmirx_dev);
hdmirx_dev->audio_present = true;
}
if (cur_state - init_state > 16 && cur_state - pre_state > 0)
hdmirx_audio_clk_ppm_inc(hdmirx_dev, 10);
else if (cur_state - init_state < -16 && cur_state - pre_state < 0)
hdmirx_audio_clk_ppm_inc(hdmirx_dev, -10);
delay = hdmirx_audio_clk_adjust(hdmirx_dev, cur_state - init_state,
cur_state - pre_state);
} else {
if (hdmirx_dev->audio_present) {
dev_info(hdmirx_dev->dev, "audio off");