From dcc3320cebe421a2e2eee771829fbb59c899f73c Mon Sep 17 00:00:00 2001 From: hang cheng Date: Wed, 12 Feb 2025 18:21:40 +0800 Subject: [PATCH] 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 --- drivers/media/vout/hdmitx21/hdmi_tx_module.h | 4 ++ drivers/media/vout/hdmitx21/hw/common.h | 2 + drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c | 19 ++++++++ drivers/media/vout/hdmitx21/hw/hw_s5.c | 45 +++++++++++++++---- drivers/media/vout/hdmitx21/hw/interrupts.c | 36 ++++++++++----- .../Ib678d77e205e3dd8e54bd44955c22e4527689e2f | 1 + 6 files changed, 87 insertions(+), 20 deletions(-) create mode 100644 patchinfo/Ib678d77e205e3dd8e54bd44955c22e4527689e2f diff --git a/drivers/media/vout/hdmitx21/hdmi_tx_module.h b/drivers/media/vout/hdmitx21/hdmi_tx_module.h index d68da3c43..37fb49d36 100644 --- a/drivers/media/vout/hdmitx21/hdmi_tx_module.h +++ b/drivers/media/vout/hdmitx21/hdmi_tx_module.h @@ -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); diff --git a/drivers/media/vout/hdmitx21/hw/common.h b/drivers/media/vout/hdmitx21/hw/common.h index a2122ee33..6432bbc99 100644 --- a/drivers/media/vout/hdmitx21/hw/common.h +++ b/drivers/media/vout/hdmitx21/hw/common.h @@ -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); diff --git a/drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c b/drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c index 8c675c7e6..de4b6c52c 100644 --- a/drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c +++ b/drivers/media/vout/hdmitx21/hw/hdmi_tx_hw.c @@ -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); diff --git a/drivers/media/vout/hdmitx21/hw/hw_s5.c b/drivers/media/vout/hdmitx21/hw/hw_s5.c index 62525fe07..edc9793bc 100644 --- a/drivers/media/vout/hdmitx21/hw/hw_s5.c +++ b/drivers/media/vout/hdmitx21/hw/hw_s5.c @@ -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); diff --git a/drivers/media/vout/hdmitx21/hw/interrupts.c b/drivers/media/vout/hdmitx21/hw/interrupts.c index 16fa57840..475f0fff3 100644 --- a/drivers/media/vout/hdmitx21/hw/interrupts.c +++ b/drivers/media/vout/hdmitx21/hw/interrupts.c @@ -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); } diff --git a/patchinfo/Ib678d77e205e3dd8e54bd44955c22e4527689e2f b/patchinfo/Ib678d77e205e3dd8e54bd44955c22e4527689e2f new file mode 100644 index 000000000..ca0d967dd --- /dev/null +++ b/patchinfo/Ib678d77e205e3dd8e54bd44955c22e4527689e2f @@ -0,0 +1 @@ +SWPL-201096