disp: msm: dsi: DSI PHY V4 support of dynamic clock switch
This change adds support for dynamic switching of dsi clocks to avoid RF interference issues. DSI PHY V4 support is added. Change-Id: I5bdbd6d2916692087c0192d23c8e7598238f161f Signed-off-by: Sandeep Panda <spanda@codeaurora.org> Signed-off-by: Yujun Zhang <yujunzhang@codeaurora.org>
This commit is contained in:
@@ -256,6 +256,15 @@ static void dsi_catalog_phy_4_0_init(struct dsi_phy_hw *phy)
|
||||
phy->ops.phy_lane_reset = dsi_phy_hw_v4_0_lane_reset;
|
||||
phy->ops.toggle_resync_fifo = dsi_phy_hw_v4_0_toggle_resync_fifo;
|
||||
phy->ops.reset_clk_en_sel = dsi_phy_hw_v4_0_reset_clk_en_sel;
|
||||
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_config =
|
||||
dsi_phy_hw_v4_0_dyn_refresh_config;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay =
|
||||
dsi_phy_hw_v4_0_dyn_refresh_pipe_delay;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_helper =
|
||||
dsi_phy_hw_v4_0_dyn_refresh_helper;
|
||||
phy->ops.dyn_refresh_ops.cache_phy_timings =
|
||||
dsi_phy_hw_v4_0_cache_phy_timings;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -251,4 +251,13 @@ void dsi_phy_hw_v3_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
|
||||
int dsi_ctrl_hw_cmn_wait4dynamic_refresh_done(struct dsi_ctrl_hw *ctrl);
|
||||
int dsi_phy_hw_v3_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
|
||||
u32 *dst, u32 size);
|
||||
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_config(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, bool is_master);
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
|
||||
struct dsi_dyn_clk_delay *delay);
|
||||
|
||||
int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
|
||||
u32 *dst, u32 size);
|
||||
#endif /* _DSI_CATALOG_H_ */
|
||||
|
@@ -62,7 +62,6 @@
|
||||
#define DSIPHY_CMN_LANE_STATUS0 0x148
|
||||
#define DSIPHY_CMN_LANE_STATUS1 0x14C
|
||||
|
||||
|
||||
/* n = 0..3 for data lanes and n = 4 for clock lane */
|
||||
#define DSIPHY_LNX_CFG0(n) (0x200 + (0x80 * (n)))
|
||||
#define DSIPHY_LNX_CFG1(n) (0x204 + (0x80 * (n)))
|
||||
@@ -72,6 +71,47 @@
|
||||
#define DSIPHY_LNX_LPRX_CTRL(n) (0x214 + (0x80 * (n)))
|
||||
#define DSIPHY_LNX_TX_DCTRL(n) (0x218 + (0x80 * (n)))
|
||||
|
||||
/* dynamic refresh control registers */
|
||||
#define DSI_DYN_REFRESH_CTRL (0x000)
|
||||
#define DSI_DYN_REFRESH_PIPE_DELAY (0x004)
|
||||
#define DSI_DYN_REFRESH_PIPE_DELAY2 (0x008)
|
||||
#define DSI_DYN_REFRESH_PLL_DELAY (0x00C)
|
||||
#define DSI_DYN_REFRESH_STATUS (0x010)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL0 (0x014)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL1 (0x018)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL2 (0x01C)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL3 (0x020)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL4 (0x024)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL5 (0x028)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL6 (0x02C)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL7 (0x030)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL8 (0x034)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL9 (0x038)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL10 (0x03C)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL11 (0x040)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL12 (0x044)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL13 (0x048)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL14 (0x04C)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL15 (0x050)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL16 (0x054)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL17 (0x058)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL18 (0x05C)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL19 (0x060)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL20 (0x064)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL21 (0x068)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL22 (0x06C)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL23 (0x070)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL24 (0x074)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL25 (0x078)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL26 (0x07C)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL27 (0x080)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL28 (0x084)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL29 (0x088)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL30 (0x08C)
|
||||
#define DSI_DYN_REFRESH_PLL_CTRL31 (0x090)
|
||||
#define DSI_DYN_REFRESH_PLL_UPPER_ADDR (0x094)
|
||||
#define DSI_DYN_REFRESH_PLL_UPPER_ADDR2 (0x098)
|
||||
|
||||
static int dsi_phy_hw_v4_0_is_pll_on(struct dsi_phy_hw *phy)
|
||||
{
|
||||
u32 data = 0;
|
||||
@@ -481,3 +521,165 @@ int dsi_phy_hw_timing_val_v4_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
|
||||
timing_cfg->lane_v4[i] = timing_val[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_config(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, bool is_master)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
if (is_master) {
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL19,
|
||||
DSIPHY_CMN_TIMING_CTRL_0, DSIPHY_CMN_TIMING_CTRL_1,
|
||||
cfg->timing.lane_v4[0], cfg->timing.lane_v4[1]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL20,
|
||||
DSIPHY_CMN_TIMING_CTRL_2, DSIPHY_CMN_TIMING_CTRL_3,
|
||||
cfg->timing.lane_v4[2], cfg->timing.lane_v4[3]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL21,
|
||||
DSIPHY_CMN_TIMING_CTRL_4, DSIPHY_CMN_TIMING_CTRL_5,
|
||||
cfg->timing.lane_v4[4], cfg->timing.lane_v4[5]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL22,
|
||||
DSIPHY_CMN_TIMING_CTRL_6, DSIPHY_CMN_TIMING_CTRL_7,
|
||||
cfg->timing.lane_v4[6], cfg->timing.lane_v4[7]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL23,
|
||||
DSIPHY_CMN_TIMING_CTRL_8, DSIPHY_CMN_TIMING_CTRL_9,
|
||||
cfg->timing.lane_v4[8], cfg->timing.lane_v4[9]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL24,
|
||||
DSIPHY_CMN_TIMING_CTRL_10, DSIPHY_CMN_TIMING_CTRL_11,
|
||||
cfg->timing.lane_v4[10], cfg->timing.lane_v4[11]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL25,
|
||||
DSIPHY_CMN_TIMING_CTRL_12, DSIPHY_CMN_TIMING_CTRL_13,
|
||||
cfg->timing.lane_v4[12], cfg->timing.lane_v4[13]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL26,
|
||||
DSIPHY_CMN_CTRL_0, DSIPHY_CMN_LANE_CTRL0,
|
||||
0x7f, 0x1f);
|
||||
|
||||
} else {
|
||||
reg = DSI_R32(phy, DSIPHY_CMN_CLK_CFG1);
|
||||
reg &= ~BIT(5);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0,
|
||||
DSIPHY_CMN_CLK_CFG1, DSIPHY_CMN_PLL_CNTRL,
|
||||
reg, 0x0);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1,
|
||||
DSIPHY_CMN_RBUF_CTRL, DSIPHY_CMN_TIMING_CTRL_0,
|
||||
0x0, cfg->timing.lane_v4[0]);
|
||||
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2,
|
||||
DSIPHY_CMN_TIMING_CTRL_1, DSIPHY_CMN_TIMING_CTRL_2,
|
||||
cfg->timing.lane_v4[1], cfg->timing.lane_v4[2]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3,
|
||||
DSIPHY_CMN_TIMING_CTRL_3, DSIPHY_CMN_TIMING_CTRL_4,
|
||||
cfg->timing.lane_v4[3], cfg->timing.lane_v4[4]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4,
|
||||
DSIPHY_CMN_TIMING_CTRL_5, DSIPHY_CMN_TIMING_CTRL_6,
|
||||
cfg->timing.lane_v4[5], cfg->timing.lane_v4[6]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5,
|
||||
DSIPHY_CMN_TIMING_CTRL_7, DSIPHY_CMN_TIMING_CTRL_8,
|
||||
cfg->timing.lane_v4[7], cfg->timing.lane_v4[8]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6,
|
||||
DSIPHY_CMN_TIMING_CTRL_9, DSIPHY_CMN_TIMING_CTRL_10,
|
||||
cfg->timing.lane_v4[9], cfg->timing.lane_v4[10]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7,
|
||||
DSIPHY_CMN_TIMING_CTRL_11, DSIPHY_CMN_TIMING_CTRL_12,
|
||||
cfg->timing.lane_v4[11], cfg->timing.lane_v4[12]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8,
|
||||
DSIPHY_CMN_TIMING_CTRL_13, DSIPHY_CMN_CTRL_0,
|
||||
cfg->timing.lane_v4[13], 0x7f);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9,
|
||||
DSIPHY_CMN_LANE_CTRL0, DSIPHY_CMN_CTRL_2,
|
||||
0x1f, 0x40);
|
||||
/*
|
||||
* fill with dummy register writes since controller will blindly
|
||||
* send these values to DSI PHY.
|
||||
*/
|
||||
reg = DSI_DYN_REFRESH_PLL_CTRL11;
|
||||
while (reg <= DSI_DYN_REFRESH_PLL_CTRL29) {
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, reg,
|
||||
DSIPHY_CMN_LANE_CTRL0, DSIPHY_CMN_CTRL_0,
|
||||
0x1f, 0x7f);
|
||||
reg += 0x4;
|
||||
}
|
||||
|
||||
DSI_GEN_W32(phy->dyn_pll_base,
|
||||
DSI_DYN_REFRESH_PLL_UPPER_ADDR, 0);
|
||||
DSI_GEN_W32(phy->dyn_pll_base,
|
||||
DSI_DYN_REFRESH_PLL_UPPER_ADDR2, 0);
|
||||
}
|
||||
|
||||
wmb(); /* make sure all registers are updated */
|
||||
}
|
||||
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
|
||||
struct dsi_dyn_clk_delay *delay)
|
||||
{
|
||||
if (!delay)
|
||||
return;
|
||||
|
||||
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY,
|
||||
delay->pipe_delay);
|
||||
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY2,
|
||||
delay->pipe_delay2);
|
||||
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_DELAY,
|
||||
delay->pll_delay);
|
||||
}
|
||||
|
||||
void dsi_phy_hw_v4_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* if no offset is mentioned then this means we want to clear
|
||||
* the dynamic refresh ctrl register which is the last step
|
||||
* of dynamic refresh sequence.
|
||||
*/
|
||||
if (!offset) {
|
||||
reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
|
||||
reg &= ~(BIT(0) | BIT(8));
|
||||
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
|
||||
wmb(); /* ensure dynamic fps is cleared */
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset & BIT(DYN_REFRESH_INTF_SEL)) {
|
||||
reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
|
||||
reg |= BIT(13);
|
||||
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
|
||||
}
|
||||
|
||||
if (offset & BIT(DYN_REFRESH_SYNC_MODE)) {
|
||||
reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
|
||||
reg |= BIT(16);
|
||||
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
|
||||
}
|
||||
|
||||
if (offset & BIT(DYN_REFRESH_SWI_CTRL)) {
|
||||
reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
|
||||
reg |= BIT(0);
|
||||
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
|
||||
}
|
||||
|
||||
if (offset & BIT(DYN_REFRESH_SW_TRIGGER)) {
|
||||
reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
|
||||
reg |= BIT(8);
|
||||
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
|
||||
wmb(); /* ensure dynamic fps is triggered */
|
||||
}
|
||||
}
|
||||
|
||||
int dsi_phy_hw_v4_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
|
||||
u32 *dst, u32 size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!timings || !dst || !size)
|
||||
return -EINVAL;
|
||||
|
||||
if (size != DSI_PHY_TIMING_V4_SIZE) {
|
||||
pr_err("size mis-match\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
dst[i] = timings->lane_v4[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user