mirror of
https://github.com/hardkernel/kernel_common_drivers.git
synced 2026-06-25 12:03:48 +09:00
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:
committed by
codewalkerster
parent
f3b273dfb3
commit
dcc3320ceb
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user