hdmitx: optimise 10to20 fifo [1/1]

PD#SWPL-201096

Problem:
there's probability 10or18to20 fifo over/under flow
issue during display, and will cause flash screen issue
1.10or18to20 fifo reset itself will cause fifo
spill over again
2.clk_todig(the fifo put clk) is disable when disable phy
3.hpll may be unlock after switch mode, especially when
hpll fractional part is large.

Solution:
optimise 10to20 fifo
1.disable fifo intr before do fifo reset, and add delay
after fifo reset and before enable fifo intr again
2.keep clk_todig always enabled
3.increase pll lock tolerance of hpll fractional part

Verify:
s5

Test:
DRM-TX-78 DRM-TX-79

Change-Id: Ib678d77e205e3dd8e54bd44955c22e4527689e2f
Signed-off-by: hang cheng <hang.cheng@amlogic.com>
This commit is contained in:
hang cheng
2025-02-12 18:21:40 +08:00
committed by codewalkerster
parent f3b273dfb3
commit dcc3320ceb
6 changed files with 87 additions and 20 deletions
@@ -204,6 +204,10 @@ struct hdmitx_dev {
bool not_restart_hdcp;
unsigned long up_hdcp_timeout_sec;
struct delayed_work work_up_hdcp_timeout;
u32 hdcp_debug_delay;
/* ignore fifo intr5 if hdmitx output disabled */
bool ignore_fifo_intr5;
};
struct hdmitx_dev *get_hdmitx21_device(void);
+2
View File
@@ -142,6 +142,8 @@ void hdmitx21_phy_bandgap_en_s5(void);
void hdmitx21_phy_bandgap_en_s7(void);
void hdmitx21_phy_bandgap_en_s7d(void);
void hdmitx_s5_phy_keep_clk_todig(bool en);
void set21_phy_by_mode_t7(u32 mode);
void set21_phy_by_mode_s5(u32 mode);
void set21_phy_by_mode_s1a(u32 mode);
@@ -491,6 +491,7 @@ static void hdmi_hwp_init(struct hdmitx_dev *hdev, u8 reset)
hd21_set_reg_bits(CLKCTRL_ENC_HDMI_CLK_CTRL, 1, 12, 1);
hd21_set_reg_bits(CLKCTRL_ENC_HDMI_CLK_CTRL, 1, 4, 1);
hd21_set_reg_bits(CLKCTRL_HDMI_CLK_CTRL, 7, 8, 3);
/* tmds clk enable */
hd21_set_reg_bits(CLKCTRL_HTX_CLK_CTRL1, 1, 24, 1);
}
@@ -498,6 +499,7 @@ static void hdmi_hwp_init(struct hdmitx_dev *hdev, u8 reset)
if (!reset && hdmitx21_uboot_already_display()) {
HDMITX_INFO("uboot already enabled hdmitx\n");
/* enable fifo intr if uboot hdmitx output ready */
hdev->ignore_fifo_intr5 = false;
fifo_flow_enable_intrs(1);
hdev->frl_rate = get_current_frl_rate();
if (hdev->frl_rate > hdev->tx_hw.base.hdmi_tx_cap.tx_max_frl_rate)
@@ -1601,6 +1603,16 @@ static int hdmitx_set_dispmode(struct hdmitx_hw_common *tx_hw)
__func__, hc_active, ret, tri_bytes_per_line, dfm_type);
} else {
HDMITX_INFO("cts_htx_tmds_clk:%d, hdmi_clk_todig:%d, do 10to20 fifo rst\n",
meson_clk_measure(92), meson_clk_measure(93));
hdmitx_soft_reset(BIT(0));
/* for mode switch flow, add 2ms delay after fifo reset
* before enable fifo intr, to prevent fifo reset operation
* itself trigger new fifo over/under flow
*/
msleep_interruptible(2);
hdev->ignore_fifo_intr5 = false;
/* there's fifo intr state clear before enable fifo intr */
fifo_flow_enable_intrs(1);
}
@@ -3267,6 +3279,7 @@ static int hdmitx_cntl_misc(struct hdmitx_hw_common *tx_hw, u32 cmd,
/* This action will be executed in vsync interrupt */
if (argv == TMDS_PHY_DISABLE) {
fifo_flow_enable_intrs(0);
hdev->ignore_fifo_intr5 = true;
hdmi_phy_suspend();
}
break;
@@ -3489,6 +3502,12 @@ static void hdmi_phy_suspend(void)
hd21_write_reg(phy_cntl3, 0x0);
hd21_write_reg(phy_cntl5, 0x0);
break;
case MESON_CPU_ID_S5:
#ifndef CONFIG_AMLOGIC_ZAPPER_CUT
/* keep clk_todig enabled to optimise 10to20 fifo over/under flow issue */
hdmitx_s5_phy_keep_clk_todig(true);
#endif
break;
default:
hd21_write_reg(phy_cntl3, 0x3);
hd21_write_reg(phy_cntl5, 0x800);
+37 -8
View File
@@ -137,7 +137,10 @@ static void set_s5_htxpll_clk_other(const u32 clk, const bool frl_en)
/* HDMIPLL_CTRL4[25] enable tx_phy_clk1618 */
/* bit16: spll_div_0p5_en */
hd21_write_reg(ANACTRL_HDMIPLL_CTRL4, 0x414412f2 | (frl_en << 25) | (div0p5_en << 16));
hd21_write_reg(ANACTRL_HDMIPLL_CTRL5, 0x00000203);
/* bit5:4 increase pll lock tolerance of frac part
* to prevent hpll unlock after mode set
*/
hd21_write_reg(ANACTRL_HDMIPLL_CTRL5, 0x00000223);
hd21_write_reg(ANACTRL_HDMIPLL_CTRL6, (!!remainder << 31) | remainder);
hd21_set_reg_bits(ANACTRL_HDMIPLL_CTRL3, 1, 0, 1);
hd21_set_reg_bits(ANACTRL_HDMIPLL_CTRL3, 1, 1, 1);
@@ -384,17 +387,43 @@ void hdmitx21_phy_bandgap_en_s5(void)
hd21_write_reg(ANACTRL_HDMIPHY_CTRL0, 0x0b4242);
}
void hdmitx_s5_phy_keep_clk_todig(bool en)
{
/* Stage1: reset registers */
hd21_write_reg(ANACTRL_HDMIPHY_CTRL0, 0x0);
hd21_write_reg(ANACTRL_HDMIPHY_CTRL1, 0x0);
if (en) {
/* keep the registers setting of stage2-5 so that to keep clk_todig enabled */
/* keep bit[31:24] not changed */
hd21_write_reg(ANACTRL_HDMIPHY_CTRL3,
hd21_read_reg(ANACTRL_HDMIPHY_CTRL3) & 0xFF000000);
/* keep bit[15:0] not changed */
hd21_write_reg(ANACTRL_HDMIPHY_CTRL5,
hd21_read_reg(ANACTRL_HDMIPHY_CTRL5) & 0x0000FFFF);
/* keep bit[15:0] not changed */
hd21_write_reg(ANACTRL_HDMIPHY_CTRL6,
hd21_read_reg(ANACTRL_HDMIPHY_CTRL6) & 0x0000FFFF);
ndelay(10);
} else {
/* set bit[31:24] to 0 */
hd21_write_reg(ANACTRL_HDMIPHY_CTRL3,
hd21_read_reg(ANACTRL_HDMIPHY_CTRL3) & 0x00FFFFFF);
/* set bit[15:0] to 0 */
hd21_write_reg(ANACTRL_HDMIPHY_CTRL5,
hd21_read_reg(ANACTRL_HDMIPHY_CTRL5) & 0xFFFF0000);
/* set bit[15:0] to 0 */
hd21_write_reg(ANACTRL_HDMIPHY_CTRL6,
hd21_read_reg(ANACTRL_HDMIPHY_CTRL6) & 0xFFFF0000);
ndelay(10);
}
}
void hdmitx_s5_phy_pre_init(struct hdmitx_dev *hdev)
{
enum frl_rate_enum frl_rate = hdev->frl_rate;
/* Stage1: reset registers */
hd21_write_reg(ANACTRL_HDMIPHY_CTRL0, 0x0);
hd21_write_reg(ANACTRL_HDMIPHY_CTRL1, 0x0);
hd21_write_reg(ANACTRL_HDMIPHY_CTRL3, 0x0);
hd21_write_reg(ANACTRL_HDMIPHY_CTRL5, 0x0);
hd21_write_reg(ANACTRL_HDMIPHY_CTRL6, 0x0);
ndelay(10);
hdmitx_s5_phy_keep_clk_todig(true);
/* Stage2: enable Bandgap */
hd21_set_reg_bits(ANACTRL_HDMIPHY_CTRL5, 0x03, 0, 8);
+24 -12
View File
@@ -157,17 +157,25 @@ static void intr2_sw_handler(struct intr_t *intr)
}
}
/* will handle intr5 in top half of interrupt handle
* as this intr only stop come after reset
/* for fifo intr which come after mode setting done, in order to
* prevent fifo reset operation itself trigger new fifo over/under
* flow, the interrupt process flow:
* disable fifo intr in interrupt top handler-->do
* fifo reset-->clear intr state twice-->
* after enter interrupt bottom handler, do clear intr5 state
* twice-->enable fifo intr.
* there's delay between intr top and bottom half
*/
static void intr5_sw_handler(struct intr_t *intr)
{
/* clear intr state asap */
/* intr->st_data = 0; */
/* hdmitx21_set_reg_bits(PWD_SRST_IVCTX, 1, 2, 1); */
/* hdmitx21_set_reg_bits(INTR5_SW_TPI_IVCTX, 1, 3, 1); */
/* hdmitx21_set_reg_bits(PWD_SRST_IVCTX, 0, 2, 1); */
/* HDMITX_INFO("%s[%d]\n", __func__, __LINE__); */
intr->st_data = 0;
/* clear pfifo intr twice */
hdmitx21_set_reg_bits(INTR5_SW_TPI_IVCTX, 1, 3, 1);
hdmitx21_set_reg_bits(INTR5_SW_TPI_IVCTX, 1, 3, 1);
/* enable fifo intr */
fifo_flow_enable_intrs(true);
HDMITX_INFO("%s INTR5_SW_TPI_IVCTX pfifo rst\n", __func__);
}
static void ddc_stall_req_handler(struct intr_t *intr)
@@ -324,7 +332,9 @@ next:
pint++;
/* HDMITX_INFO("-----i = %d, pint->st_data = 0x%x\n", i, pint->st_data); */
/* only process the enabled interrupt */
if ((hdmitx21_rd_reg(pint->intr_mask_reg) & pint->mask_data) &&
if (((hdmitx21_rd_reg(pint->intr_mask_reg) & pint->mask_data) ||
(pint->intr_mask_reg == INTR5_MASK_SW_TPI_IVCTX &&
!hdev->ignore_fifo_intr5)) &&
(pint->st_data & pint->mask_data)) {
val = pint->st_data;
/* clear st_data asap in callback function */
@@ -378,12 +388,14 @@ static void intr_status_save_and_clear(void)
if (pint->intr_st_reg == INTR5_SW_TPI_IVCTX &&
(hdmitx21_rd_reg(pint->intr_mask_reg) & pint->mask_data) &&
(pint->st_data & pint->mask_data)) {
/* clear pfifo intr and reset asap */
/* disable intr5 */
fifo_flow_enable_intrs(false);
/* reset fifo */
hdmitx21_set_reg_bits(PWD_SRST_IVCTX, 1, 2, 1);
hdmitx21_set_reg_bits(INTR5_SW_TPI_IVCTX, 1, 3, 1);
hdmitx21_set_reg_bits(PWD_SRST_IVCTX, 0, 2, 1);
pint->st_data = 0;
HDMITX_INFO("INTR5_SW_TPI_IVCTX pfifo rst\n");
/* clear pfifo intr twice */
hdmitx21_set_reg_bits(INTR5_SW_TPI_IVCTX, 1, 3, 1);
hdmitx21_set_reg_bits(INTR5_SW_TPI_IVCTX, 1, 3, 1);
} else {
hdmitx21_wr_reg(pint->intr_clr_reg, pint->st_data);
}
@@ -0,0 +1 @@
SWPL-201096