Merge "disp: msm: dsi: DSI PHY V4 support of dynamic clock switch"
这个提交包含在:
@@ -62,6 +62,8 @@ static void dsi_catalog_cmn_init(struct dsi_ctrl_hw *ctrl,
|
||||
dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle;
|
||||
ctrl->ops.setup_avr = dsi_ctrl_hw_cmn_setup_avr;
|
||||
ctrl->ops.set_continuous_clk = dsi_ctrl_hw_cmn_set_continuous_clk;
|
||||
ctrl->ops.wait4dynamic_refresh_done =
|
||||
dsi_ctrl_hw_cmn_wait4dynamic_refresh_done;
|
||||
|
||||
switch (version) {
|
||||
case DSI_CTRL_VERSION_1_4:
|
||||
@@ -215,6 +217,14 @@ static void dsi_catalog_phy_3_0_init(struct dsi_phy_hw *phy)
|
||||
phy->ops.clamp_ctrl = dsi_phy_hw_v3_0_clamp_ctrl;
|
||||
phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset;
|
||||
phy->ops.toggle_resync_fifo = dsi_phy_hw_v3_0_toggle_resync_fifo;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_config =
|
||||
dsi_phy_hw_v3_0_dyn_refresh_config;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay =
|
||||
dsi_phy_hw_v3_0_dyn_refresh_pipe_delay;
|
||||
phy->ops.dyn_refresh_ops.dyn_refresh_helper =
|
||||
dsi_phy_hw_v3_0_dyn_refresh_helper;
|
||||
phy->ops.dyn_refresh_ops.cache_phy_timings =
|
||||
dsi_phy_hw_v3_0_cache_phy_timings;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,6 +252,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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -57,15 +57,17 @@ int dsi_phy_timing_calc_init(struct dsi_phy_hw *phy,
|
||||
* @mode: DSI mode information.
|
||||
* @host: DSI host configuration.
|
||||
* @timing: DSI phy lane configurations.
|
||||
* @use_mode_bit_clk: Boolean to indicate whether to recalculate bit clk.
|
||||
*
|
||||
* This function setups the catalog information in the dsi_phy_hw object.
|
||||
*
|
||||
* return: error code for failure and 0 for success.
|
||||
*/
|
||||
int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy,
|
||||
struct dsi_mode_info *mode,
|
||||
struct dsi_host_common_cfg *host,
|
||||
struct dsi_phy_per_lane_cfgs *timing);
|
||||
struct dsi_mode_info *mode,
|
||||
struct dsi_host_common_cfg *host,
|
||||
struct dsi_phy_per_lane_cfgs *timing,
|
||||
bool use_mode_bit_clk);
|
||||
|
||||
/* Definitions for 14nm PHY hardware driver */
|
||||
void dsi_phy_hw_v2_0_regulator_enable(struct dsi_phy_hw *phy,
|
||||
@@ -238,4 +240,23 @@ void dsi_ctrl_hw_22_config_clk_gating(struct dsi_ctrl_hw *ctrl, bool enable,
|
||||
|
||||
void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable);
|
||||
|
||||
/* dynamic refresh specific functions */
|
||||
void dsi_phy_hw_v3_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
|
||||
void dsi_phy_hw_v3_0_dyn_refresh_config(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, bool is_master);
|
||||
void dsi_phy_hw_v3_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
|
||||
struct dsi_dyn_clk_delay *delay);
|
||||
|
||||
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_ */
|
||||
|
@@ -307,4 +307,18 @@ int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index);
|
||||
*/
|
||||
int dsi_clk_update_parent(struct dsi_clk_link_set *parent,
|
||||
struct dsi_clk_link_set *child);
|
||||
|
||||
/**
|
||||
* dsi_clk_prepare_enable() - prepare and enable dsi src clocks
|
||||
* @clk: list of src clocks.
|
||||
*
|
||||
* @return: Zero on success and err no on failure
|
||||
*/
|
||||
int dsi_clk_prepare_enable(struct dsi_clk_link_set *clk);
|
||||
|
||||
/**
|
||||
* dsi_clk_disable_unprepare() - disable and unprepare dsi src clocks
|
||||
* @clk: list of src clocks.
|
||||
*/
|
||||
void dsi_clk_disable_unprepare(struct dsi_clk_link_set *clk);
|
||||
#endif /* _DSI_CLK_H_ */
|
||||
|
@@ -105,8 +105,9 @@ int dsi_clk_set_link_frequencies(void *client, struct link_clk_freq freq,
|
||||
|
||||
/**
|
||||
* dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock
|
||||
* @clks: DSI link clock information.
|
||||
* @pixel_clk: Pixel clock rate in KHz.
|
||||
* @clks: DSI link clock information.
|
||||
* @pixel_clk: Pixel clock rate in KHz.
|
||||
* @index: Index of the DSI controller.
|
||||
*
|
||||
* return: error code in case of failure or 0 for success.
|
||||
*/
|
||||
@@ -128,9 +129,9 @@ int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index)
|
||||
|
||||
/**
|
||||
* dsi_clk_set_byte_clk_rate() - set frequency for byte clock
|
||||
* @client: DSI clock client pointer.
|
||||
* @byte_clk: Pixel clock rate in Hz.
|
||||
* @index: Index of the DSI controller.
|
||||
* @client: DSI clock client pointer.
|
||||
* @byte_clk: Byte clock rate in Hz.
|
||||
* @index: Index of the DSI controller.
|
||||
* return: error code in case of failure or 0 for success.
|
||||
*/
|
||||
int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index)
|
||||
@@ -138,6 +139,7 @@ int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index)
|
||||
int rc = 0;
|
||||
struct dsi_clk_client_info *c = client;
|
||||
struct dsi_clk_mngr *mngr;
|
||||
u64 byte_intf_rate;
|
||||
|
||||
mngr = c->mngr;
|
||||
rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk);
|
||||
@@ -146,8 +148,16 @@ int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index)
|
||||
else
|
||||
mngr->link_clks[index].freq.byte_clk_rate = byte_clk;
|
||||
|
||||
return rc;
|
||||
if (mngr->link_clks[index].hs_clks.byte_intf_clk) {
|
||||
byte_intf_rate = mngr->link_clks[index].freq.byte_clk_rate / 2;
|
||||
rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_intf_clk,
|
||||
byte_intf_rate);
|
||||
if (rc)
|
||||
pr_err("failed to set clk rate for byte intf clk=%d\n",
|
||||
rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,6 +185,41 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_clk_prepare_enable() - prepare and enable dsi src clocks
|
||||
* @clk: list of src clocks.
|
||||
*
|
||||
* @return: Zero on success and err no on failure.
|
||||
*/
|
||||
int dsi_clk_prepare_enable(struct dsi_clk_link_set *clk)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = clk_prepare_enable(clk->byte_clk);
|
||||
if (rc) {
|
||||
pr_err("failed to enable byte src clk %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = clk_prepare_enable(clk->pixel_clk);
|
||||
if (rc) {
|
||||
pr_err("failed to enable pixel src clk %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_clk_disable_unprepare() - disable and unprepare dsi src clocks
|
||||
* @clk: list of src clocks.
|
||||
*/
|
||||
void dsi_clk_disable_unprepare(struct dsi_clk_link_set *clk)
|
||||
{
|
||||
clk_disable_unprepare(clk->pixel_clk);
|
||||
clk_disable_unprepare(clk->byte_clk);
|
||||
}
|
||||
|
||||
int dsi_core_clk_start(struct dsi_core_clks *c_clks)
|
||||
{
|
||||
int rc = 0;
|
||||
|
@@ -2887,7 +2887,12 @@ int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(flags & (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR))) {
|
||||
if (!(flags & (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR |
|
||||
DSI_MODE_FLAG_DYN_CLK))) {
|
||||
/*
|
||||
* for dynamic clk switch case link frequence would
|
||||
* be updated dsi_display_dynamic_clk_switch().
|
||||
*/
|
||||
rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle,
|
||||
mode);
|
||||
if (rc) {
|
||||
@@ -3603,6 +3608,27 @@ void dsi_ctrl_irq_update(struct dsi_ctrl *dsi_ctrl, bool enable)
|
||||
mutex_unlock(&dsi_ctrl->ctrl_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_ctrl_wait4dynamic_refresh_done() - Poll for dynamci refresh
|
||||
* done interrupt.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*/
|
||||
int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!ctrl)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&ctrl->ctrl_lock);
|
||||
|
||||
if (ctrl->hw.ops.wait4dynamic_refresh_done)
|
||||
rc = ctrl->hw.ops.wait4dynamic_refresh_done(&ctrl->hw);
|
||||
|
||||
mutex_unlock(&ctrl->ctrl_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_ctrl_drv_register() - register platform driver for dsi controller
|
||||
*/
|
||||
|
@@ -796,4 +796,11 @@ int dsi_ctrl_pixel_format_to_bpp(enum dsi_pixel_format dst_format);
|
||||
* @enable: variable to control continuous clock.
|
||||
*/
|
||||
void dsi_ctrl_set_continuous_clk(struct dsi_ctrl *dsi_ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* dsi_ctrl_wait4dynamic_refresh_done() - Poll for dynamic refresh done
|
||||
* interrupt.
|
||||
* @dsi_ctrl: DSI controller handle.
|
||||
*/
|
||||
int dsi_ctrl_wait4dynamic_refresh_done(struct dsi_ctrl *ctrl);
|
||||
#endif /* _DSI_CTRL_H_ */
|
||||
|
@@ -817,6 +817,12 @@ struct dsi_ctrl_hw_ops {
|
||||
* @enable: Bool to control continuous clock request.
|
||||
*/
|
||||
void (*set_continuous_clk)(struct dsi_ctrl_hw *ctrl, bool enable);
|
||||
|
||||
/**
|
||||
* hw.ops.wait4dynamic_refresh_done() - Wait for dynamic refresh done
|
||||
* @ctrl: Pointer to the controller host hardware.
|
||||
*/
|
||||
int (*wait4dynamic_refresh_done)(struct dsi_ctrl_hw *ctrl);
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -1472,6 +1472,13 @@ void dsi_ctrl_hw_cmn_mask_error_intr(struct dsi_ctrl_hw *ctrl, u32 idx, bool en)
|
||||
}
|
||||
}
|
||||
|
||||
if (idx & BIT(DSI_PLL_UNLOCK_ERR)) {
|
||||
if (en)
|
||||
reg |= BIT(28);
|
||||
else
|
||||
reg &= ~BIT(28);
|
||||
}
|
||||
|
||||
DSI_W32(ctrl, 0x10c, reg);
|
||||
wmb(); /* ensure error is masked */
|
||||
}
|
||||
@@ -1538,3 +1545,25 @@ void dsi_ctrl_hw_cmn_set_continuous_clk(struct dsi_ctrl_hw *ctrl, bool enable)
|
||||
DSI_W32(ctrl, DSI_LANE_CTRL, reg);
|
||||
wmb(); /* make sure request is set */
|
||||
}
|
||||
|
||||
int dsi_ctrl_hw_cmn_wait4dynamic_refresh_done(struct dsi_ctrl_hw *ctrl)
|
||||
{
|
||||
int rc;
|
||||
u32 const sleep_us = 1000;
|
||||
u32 const timeout_us = 84000; /* approximately 5 vsyncs */
|
||||
u32 reg = 0, dyn_refresh_done = BIT(28);
|
||||
|
||||
rc = readl_poll_timeout(ctrl->base + DSI_INT_CTRL, reg,
|
||||
(reg & dyn_refresh_done), sleep_us, timeout_us);
|
||||
if (rc) {
|
||||
pr_err("wait4dynamic refresh timedout %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* ack dynamic refresh done status */
|
||||
reg = DSI_R32(ctrl, DSI_INT_CTRL);
|
||||
reg |= dyn_refresh_done;
|
||||
DSI_W32(ctrl, DSI_INT_CTRL, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -129,44 +129,7 @@
|
||||
#define DSI_SCRATCH_REGISTER_1 (0x01F8)
|
||||
#define DSI_SCRATCH_REGISTER_2 (0x01FC)
|
||||
#define DSI_DYNAMIC_REFRESH_CTRL (0x0200)
|
||||
#define DSI_DYNAMIC_REFRESH_PIPE_DELAY (0x0204)
|
||||
#define DSI_DYNAMIC_REFRESH_PIPE_DELAY2 (0x0208)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_DELAY (0x020C)
|
||||
#define DSI_DYNAMIC_REFRESH_STATUS (0x0210)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL0 (0x0214)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL1 (0x0218)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL2 (0x021C)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL3 (0x0220)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL4 (0x0224)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL5 (0x0228)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL6 (0x022C)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL7 (0x0230)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL8 (0x0234)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL9 (0x0238)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL10 (0x023C)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL11 (0x0240)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL12 (0x0244)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL13 (0x0248)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL14 (0x024C)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL15 (0x0250)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL16 (0x0254)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL17 (0x0258)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL18 (0x025C)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL19 (0x0260)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL20 (0x0264)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL21 (0x0268)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL22 (0x026C)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL23 (0x0270)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL24 (0x0274)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL25 (0x0278)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL26 (0x027C)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL27 (0x0280)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL28 (0x0284)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL29 (0x0288)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL30 (0x028C)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_CTRL31 (0x0290)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR (0x0294)
|
||||
#define DSI_DYNAMIC_REFRESH_PLL_UPPER_ADDR2 (0x0298)
|
||||
#define DSI_VIDEO_COMPRESSION_MODE_CTRL (0x02A0)
|
||||
#define DSI_VIDEO_COMPRESSION_MODE_CTRL2 (0x02A4)
|
||||
#define DSI_COMMAND_COMPRESSION_MODE_CTRL (0x02A8)
|
||||
|
@@ -87,6 +87,7 @@ enum dsi_op_mode {
|
||||
* New timing values are sent from DAL.
|
||||
* @DSI_MODE_FLAG_POMS:
|
||||
* Seamless transition is dynamic panel operating mode switch
|
||||
* @DSI_MODE_FLAG_DYN_CLK: Seamless transition is dynamic clock change
|
||||
*/
|
||||
enum dsi_mode_flags {
|
||||
DSI_MODE_FLAG_SEAMLESS = BIT(0),
|
||||
@@ -95,6 +96,7 @@ enum dsi_mode_flags {
|
||||
DSI_MODE_FLAG_DMS = BIT(3),
|
||||
DSI_MODE_FLAG_VRR = BIT(4),
|
||||
DSI_MODE_FLAG_POMS = BIT(5),
|
||||
DSI_MODE_FLAG_DYN_CLK = BIT(6),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -660,12 +662,50 @@ struct dsi_event_cb_info {
|
||||
* @DSI_FIFO_OVERFLOW: DSI FIFO Overflow error
|
||||
* @DSI_FIFO_UNDERFLOW: DSI FIFO Underflow error
|
||||
* @DSI_LP_Rx_TIMEOUT: DSI LP/RX Timeout error
|
||||
* @DSI_PLL_UNLOCK_ERR: DSI PLL unlock error
|
||||
*/
|
||||
enum dsi_error_status {
|
||||
DSI_FIFO_OVERFLOW = 1,
|
||||
DSI_FIFO_UNDERFLOW,
|
||||
DSI_LP_Rx_TIMEOUT,
|
||||
DSI_PLL_UNLOCK_ERR,
|
||||
DSI_ERR_INTR_ALL,
|
||||
};
|
||||
|
||||
/* structure containing the delays required for dynamic clk */
|
||||
struct dsi_dyn_clk_delay {
|
||||
u32 pipe_delay;
|
||||
u32 pipe_delay2;
|
||||
u32 pll_delay;
|
||||
};
|
||||
|
||||
/* dynamic refresh control bits */
|
||||
enum dsi_dyn_clk_control_bits {
|
||||
DYN_REFRESH_INTF_SEL = 1,
|
||||
DYN_REFRESH_SYNC_MODE,
|
||||
DYN_REFRESH_SW_TRIGGER,
|
||||
DYN_REFRESH_SWI_CTRL,
|
||||
};
|
||||
|
||||
/* convert dsi pixel format into bits per pixel */
|
||||
static inline int dsi_pixel_format_to_bpp(enum dsi_pixel_format fmt)
|
||||
{
|
||||
switch (fmt) {
|
||||
case DSI_PIXEL_FORMAT_RGB888:
|
||||
case DSI_PIXEL_FORMAT_MAX:
|
||||
return 24;
|
||||
case DSI_PIXEL_FORMAT_RGB666:
|
||||
case DSI_PIXEL_FORMAT_RGB666_LOOSE:
|
||||
return 18;
|
||||
case DSI_PIXEL_FORMAT_RGB565:
|
||||
return 16;
|
||||
case DSI_PIXEL_FORMAT_RGB111:
|
||||
return 3;
|
||||
case DSI_PIXEL_FORMAT_RGB332:
|
||||
return 8;
|
||||
case DSI_PIXEL_FORMAT_RGB444:
|
||||
return 12;
|
||||
}
|
||||
return 24;
|
||||
}
|
||||
#endif /* _DSI_DEFS_H_ */
|
||||
|
文件差异内容过多而无法显示
加载差异
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2015-2019, The Linux Foundation.All rights reserved.
|
||||
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DSI_DISPLAY_H_
|
||||
@@ -410,13 +410,14 @@ int dsi_display_validate_mode(struct dsi_display *display,
|
||||
u32 flags);
|
||||
|
||||
/**
|
||||
* dsi_display_validate_mode_vrr() - validates mode if variable refresh case
|
||||
* dsi_display_validate_mode_change() - validates mode if variable refresh case
|
||||
* or dynamic clk change case
|
||||
* @display: Handle to display.
|
||||
* @mode: Mode to be validated..
|
||||
*
|
||||
* Return: 0 if error code.
|
||||
*/
|
||||
int dsi_display_validate_mode_vrr(struct dsi_display *display,
|
||||
int dsi_display_validate_mode_change(struct dsi_display *display,
|
||||
struct dsi_display_mode *cur_dsi_mode,
|
||||
struct dsi_display_mode *mode);
|
||||
|
||||
|
@@ -73,6 +73,8 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode,
|
||||
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
|
||||
if (msm_is_mode_seamless_poms(drm_mode))
|
||||
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_POMS;
|
||||
if (msm_is_mode_seamless_dyn_clk(drm_mode))
|
||||
dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DYN_CLK;
|
||||
|
||||
dsi_mode->timing.h_sync_polarity =
|
||||
!!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC);
|
||||
@@ -88,6 +90,8 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode,
|
||||
void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
|
||||
struct drm_display_mode *drm_mode)
|
||||
{
|
||||
bool video_mode = (dsi_mode->panel_mode == DSI_OP_VIDEO_MODE);
|
||||
|
||||
memset(drm_mode, 0, sizeof(*drm_mode));
|
||||
|
||||
drm_mode->hdisplay = dsi_mode->timing.h_active;
|
||||
@@ -122,6 +126,8 @@ void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
|
||||
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR;
|
||||
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS)
|
||||
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_POMS;
|
||||
if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)
|
||||
drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYN_CLK;
|
||||
|
||||
if (dsi_mode->timing.h_sync_polarity)
|
||||
drm_mode->flags |= DRM_MODE_FLAG_PHSYNC;
|
||||
@@ -133,7 +139,11 @@ void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
|
||||
if (dsi_mode->panel_mode == DSI_OP_CMD_MODE)
|
||||
drm_mode->flags |= DRM_MODE_FLAG_CMD_MODE_PANEL;
|
||||
|
||||
drm_mode_set_name(drm_mode);
|
||||
/* set mode name */
|
||||
snprintf(drm_mode->name, DRM_DISPLAY_MODE_LEN, "%dx%dx%dx%d%s",
|
||||
drm_mode->hdisplay, drm_mode->vdisplay,
|
||||
drm_mode->vrefresh, drm_mode->clock,
|
||||
video_mode ? "vid" : "cmd");
|
||||
}
|
||||
|
||||
static int dsi_bridge_attach(struct drm_bridge *bridge)
|
||||
@@ -178,7 +188,8 @@ static void dsi_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
}
|
||||
|
||||
if (c_bridge->dsi_mode.dsi_mode_flags &
|
||||
(DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) {
|
||||
(DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR |
|
||||
DSI_MODE_FLAG_DYN_CLK)) {
|
||||
pr_debug("[%d] seamless pre-enable\n", c_bridge->id);
|
||||
return;
|
||||
}
|
||||
@@ -220,7 +231,8 @@ static void dsi_bridge_enable(struct drm_bridge *bridge)
|
||||
}
|
||||
|
||||
if (c_bridge->dsi_mode.dsi_mode_flags &
|
||||
(DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) {
|
||||
(DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR |
|
||||
DSI_MODE_FLAG_DYN_CLK)) {
|
||||
pr_debug("[%d] seamless enable\n", c_bridge->id);
|
||||
return;
|
||||
}
|
||||
@@ -311,6 +323,12 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge,
|
||||
|
||||
memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode));
|
||||
convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode));
|
||||
|
||||
/* restore bit_clk_rate also for dynamic clk use cases */
|
||||
c_bridge->dsi_mode.timing.clk_rate_hz =
|
||||
dsi_drm_find_bit_clk_rate(c_bridge->display, adjusted_mode);
|
||||
|
||||
pr_debug("clk_rate: %llu\n", c_bridge->dsi_mode.timing.clk_rate_hz);
|
||||
}
|
||||
|
||||
static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
|
||||
@@ -379,11 +397,13 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
|
||||
cur_dsi_mode.timing.dsc_enabled =
|
||||
dsi_mode.priv_info->dsc_enabled;
|
||||
cur_dsi_mode.timing.dsc = &dsi_mode.priv_info->dsc;
|
||||
rc = dsi_display_validate_mode_vrr(c_bridge->display,
|
||||
rc = dsi_display_validate_mode_change(c_bridge->display,
|
||||
&cur_dsi_mode, &dsi_mode);
|
||||
if (rc)
|
||||
pr_debug("[%s] vrr mode mismatch failure rc=%d\n",
|
||||
if (rc) {
|
||||
pr_err("[%s] seamless mode mismatch failure rc=%d\n",
|
||||
c_bridge->display->name, rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
cur_mode = crtc_state->crtc->mode;
|
||||
|
||||
@@ -397,6 +417,7 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
|
||||
if (!drm_mode_equal(&cur_mode, adjusted_mode) &&
|
||||
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) &&
|
||||
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS)) &&
|
||||
(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) &&
|
||||
(!crtc_state->active_changed ||
|
||||
display->is_cont_splash_enabled))
|
||||
dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
|
||||
@@ -408,6 +429,33 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
|
||||
return true;
|
||||
}
|
||||
|
||||
u64 dsi_drm_find_bit_clk_rate(void *display,
|
||||
const struct drm_display_mode *drm_mode)
|
||||
{
|
||||
int i = 0, count = 0;
|
||||
struct dsi_display *dsi_display = display;
|
||||
struct dsi_display_mode *dsi_mode;
|
||||
u64 bit_clk_rate = 0;
|
||||
|
||||
if (!dsi_display || !drm_mode)
|
||||
return 0;
|
||||
|
||||
dsi_display_get_mode_count(dsi_display, &count);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
dsi_mode = &dsi_display->modes[i];
|
||||
if ((dsi_mode->timing.v_active == drm_mode->vdisplay) &&
|
||||
(dsi_mode->timing.h_active == drm_mode->hdisplay) &&
|
||||
(dsi_mode->pixel_clk_khz == drm_mode->clock) &&
|
||||
(dsi_mode->timing.refresh_rate == drm_mode->vrefresh)) {
|
||||
bit_clk_rate = dsi_mode->timing.clk_rate_hz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bit_clk_rate;
|
||||
}
|
||||
|
||||
int dsi_conn_get_mode_info(struct drm_connector *connector,
|
||||
const struct drm_display_mode *drm_mode,
|
||||
struct msm_mode_info *mode_info,
|
||||
@@ -432,7 +480,7 @@ int dsi_conn_get_mode_info(struct drm_connector *connector,
|
||||
mode_info->prefill_lines = dsi_mode.priv_info->panel_prefill_lines;
|
||||
mode_info->jitter_numer = dsi_mode.priv_info->panel_jitter_numer;
|
||||
mode_info->jitter_denom = dsi_mode.priv_info->panel_jitter_denom;
|
||||
mode_info->clk_rate = dsi_mode.priv_info->clk_rate_hz;
|
||||
mode_info->clk_rate = dsi_drm_find_bit_clk_rate(display, drm_mode);
|
||||
mode_info->mdp_transfer_time_us =
|
||||
dsi_mode.priv_info->mdp_transfer_time_us;
|
||||
|
||||
@@ -538,6 +586,9 @@ int dsi_conn_set_info_blob(struct drm_connector *connector,
|
||||
panel->dfps_caps.max_refresh_rate);
|
||||
}
|
||||
|
||||
sde_kms_info_add_keystr(info, "dyn bitclk support",
|
||||
panel->dyn_clk_caps.dyn_clk_support ? "true" : "false");
|
||||
|
||||
switch (panel->phy_props.rotation) {
|
||||
case DSI_PANEL_ROTATE_NONE:
|
||||
sde_kms_info_add_keystr(info, "panel orientation", "none");
|
||||
@@ -796,6 +847,9 @@ int dsi_connector_get_modes(struct drm_connector *connector, void *data)
|
||||
}
|
||||
m->width_mm = connector->display_info.width_mm;
|
||||
m->height_mm = connector->display_info.height_mm;
|
||||
/* set the first mode in list as preferred */
|
||||
if (i == 0)
|
||||
m->type |= DRM_MODE_TYPE_PREFERRED;
|
||||
drm_mode_probed_add(connector, m);
|
||||
}
|
||||
|
||||
@@ -915,6 +969,9 @@ int dsi_conn_post_kickoff(struct drm_connector *connector)
|
||||
c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_VRR;
|
||||
}
|
||||
|
||||
/* ensure dynamic clk switch flag is reset */
|
||||
c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_DYN_CLK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -130,4 +130,6 @@ int dsi_conn_post_kickoff(struct drm_connector *connector);
|
||||
void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode,
|
||||
struct drm_display_mode *drm_mode);
|
||||
|
||||
u64 dsi_drm_find_bit_clk_rate(void *display,
|
||||
const struct drm_display_mode *drm_mode);
|
||||
#endif /* _DSI_DRM_H_ */
|
||||
|
@@ -44,4 +44,14 @@
|
||||
#define DSI_R64(dsi_hw, off) readq_relaxed((dsi_hw)->base + (off))
|
||||
#define DSI_W64(dsi_hw, off, val) writeq_relaxed((val), (dsi_hw)->base + (off))
|
||||
|
||||
#define PLL_CALC_DATA(addr0, addr1, data0, data1) \
|
||||
(((data1) << 24) | ((((addr1)/4) & 0xFF) << 16) | \
|
||||
((data0) << 8) | (((addr0)/4) & 0xFF))
|
||||
|
||||
#define DSI_DYN_REF_REG_W(base, offset, addr0, addr1, data0, data1) \
|
||||
writel_relaxed(PLL_CALC_DATA(addr0, addr1, data0, data1), \
|
||||
(base) + (offset))
|
||||
|
||||
#define DSI_GEN_R32(base, offset) readl_relaxed(base + (offset))
|
||||
#define DSI_GEN_W32(base, offset, val) writel_relaxed((val), base + (offset))
|
||||
#endif /* _DSI_HW_H_ */
|
||||
|
@@ -1155,6 +1155,48 @@ static int dsi_panel_parse_qsync_caps(struct dsi_panel *panel,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
|
||||
{
|
||||
int rc = 0;
|
||||
bool supported = false;
|
||||
struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps;
|
||||
struct dsi_parser_utils *utils = &panel->utils;
|
||||
const char *name = panel->name;
|
||||
|
||||
supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable");
|
||||
|
||||
if (!supported) {
|
||||
dyn_clk_caps->dyn_clk_support = false;
|
||||
return rc;
|
||||
}
|
||||
|
||||
dyn_clk_caps->bit_clk_list_len = utils->count_u32_elems(utils->data,
|
||||
"qcom,dsi-dyn-clk-list");
|
||||
|
||||
if (dyn_clk_caps->bit_clk_list_len < 1) {
|
||||
pr_err("[%s] failed to get supported bit clk list\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dyn_clk_caps->bit_clk_list = kcalloc(dyn_clk_caps->bit_clk_list_len,
|
||||
sizeof(u32), GFP_KERNEL);
|
||||
if (!dyn_clk_caps->bit_clk_list)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = utils->read_u32_array(utils->data, "qcom,dsi-dyn-clk-list",
|
||||
dyn_clk_caps->bit_clk_list,
|
||||
dyn_clk_caps->bit_clk_list_len);
|
||||
|
||||
if (rc) {
|
||||
pr_err("[%s] failed to parse supported bit clk list\n", name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dyn_clk_caps->dyn_clk_support = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_panel_parse_dfps_caps(struct dsi_panel *panel)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -1163,7 +1205,7 @@ static int dsi_panel_parse_dfps_caps(struct dsi_panel *panel)
|
||||
struct dsi_parser_utils *utils = &panel->utils;
|
||||
const char *name = panel->name;
|
||||
const char *type;
|
||||
u32 val = 0;
|
||||
u32 i;
|
||||
|
||||
supported = utils->read_bool(utils->data,
|
||||
"qcom,mdss-dsi-pan-enable-dynamic-fps");
|
||||
@@ -1171,66 +1213,64 @@ static int dsi_panel_parse_dfps_caps(struct dsi_panel *panel)
|
||||
if (!supported) {
|
||||
pr_debug("[%s] DFPS is not supported\n", name);
|
||||
dfps_caps->dfps_support = false;
|
||||
return rc;
|
||||
}
|
||||
|
||||
type = utils->get_property(utils->data,
|
||||
"qcom,mdss-dsi-pan-fps-update", NULL);
|
||||
if (!type) {
|
||||
pr_err("[%s] dfps type not defined\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
} else if (!strcmp(type, "dfps_suspend_resume_mode")) {
|
||||
dfps_caps->type = DSI_DFPS_SUSPEND_RESUME;
|
||||
} else if (!strcmp(type, "dfps_immediate_clk_mode")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_CLK;
|
||||
} else if (!strcmp(type, "dfps_immediate_porch_mode_hfp")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_HFP;
|
||||
} else if (!strcmp(type, "dfps_immediate_porch_mode_vfp")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_VFP;
|
||||
} else {
|
||||
pr_err("[%s] dfps type is not recognized\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
type = utils->get_property(utils->data,
|
||||
"qcom,mdss-dsi-pan-fps-update",
|
||||
NULL);
|
||||
if (!type) {
|
||||
pr_err("[%s] dfps type not defined\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
} else if (!strcmp(type, "dfps_suspend_resume_mode")) {
|
||||
dfps_caps->type = DSI_DFPS_SUSPEND_RESUME;
|
||||
} else if (!strcmp(type, "dfps_immediate_clk_mode")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_CLK;
|
||||
} else if (!strcmp(type, "dfps_immediate_porch_mode_hfp")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_HFP;
|
||||
} else if (!strcmp(type, "dfps_immediate_porch_mode_vfp")) {
|
||||
dfps_caps->type = DSI_DFPS_IMMEDIATE_VFP;
|
||||
} else {
|
||||
pr_err("[%s] dfps type is not recognized\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
dfps_caps->dfps_list_len = utils->count_u32_elems(utils->data,
|
||||
"qcom,dsi-supported-dfps-list");
|
||||
if (dfps_caps->dfps_list_len < 1) {
|
||||
pr_err("[%s] dfps refresh list not present\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = utils->read_u32(utils->data,
|
||||
"qcom,mdss-dsi-min-refresh-rate",
|
||||
&val);
|
||||
if (rc) {
|
||||
pr_err("[%s] Min refresh rate is not defined\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
dfps_caps->min_refresh_rate = val;
|
||||
dfps_caps->dfps_list = kcalloc(dfps_caps->dfps_list_len, sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (!dfps_caps->dfps_list) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = utils->read_u32(utils->data,
|
||||
"qcom,mdss-dsi-max-refresh-rate",
|
||||
&val);
|
||||
if (rc) {
|
||||
pr_debug("[%s] Using default refresh rate\n", name);
|
||||
rc = utils->read_u32(utils->data,
|
||||
"qcom,mdss-dsi-panel-framerate",
|
||||
&val);
|
||||
if (rc) {
|
||||
pr_err("[%s] max refresh rate is not defined\n",
|
||||
name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
dfps_caps->max_refresh_rate = val;
|
||||
rc = utils->read_u32_array(utils->data,
|
||||
"qcom,dsi-supported-dfps-list",
|
||||
dfps_caps->dfps_list,
|
||||
dfps_caps->dfps_list_len);
|
||||
if (rc) {
|
||||
pr_err("[%s] dfps refresh rate list parse failed\n", name);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
dfps_caps->dfps_support = true;
|
||||
|
||||
if (dfps_caps->min_refresh_rate > dfps_caps->max_refresh_rate) {
|
||||
pr_err("[%s] min rate > max rate\n", name);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
/* calculate max and min fps */
|
||||
dfps_caps->max_refresh_rate = dfps_caps->dfps_list[0];
|
||||
dfps_caps->min_refresh_rate = dfps_caps->dfps_list[0];
|
||||
|
||||
pr_debug("[%s] DFPS is supported %d-%d, mode %d\n", name,
|
||||
dfps_caps->min_refresh_rate,
|
||||
dfps_caps->max_refresh_rate,
|
||||
dfps_caps->type);
|
||||
dfps_caps->dfps_support = true;
|
||||
for (i = 1; i < dfps_caps->dfps_list_len; i++) {
|
||||
if (dfps_caps->dfps_list[i] < dfps_caps->min_refresh_rate)
|
||||
dfps_caps->min_refresh_rate = dfps_caps->dfps_list[i];
|
||||
else if (dfps_caps->dfps_list[i] > dfps_caps->max_refresh_rate)
|
||||
dfps_caps->max_refresh_rate = dfps_caps->dfps_list[i];
|
||||
}
|
||||
|
||||
error:
|
||||
@@ -3053,6 +3093,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent,
|
||||
pr_err("failed to parse qsync features, rc=%d\n", rc);
|
||||
}
|
||||
|
||||
rc = dsi_panel_parse_dyn_clk_caps(panel);
|
||||
if (rc)
|
||||
pr_err("failed to parse dynamic clk config, rc=%d\n", rc);
|
||||
|
||||
rc = dsi_panel_parse_phy_props(panel);
|
||||
if (rc) {
|
||||
pr_err("failed to parse panel physical dimension, rc=%d\n", rc);
|
||||
@@ -3475,6 +3519,7 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel,
|
||||
struct dsi_host_config *config)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps;
|
||||
|
||||
if (!panel || !mode || !config) {
|
||||
pr_err("invalid params\n");
|
||||
@@ -3502,7 +3547,11 @@ int dsi_panel_get_host_cfg_for_mode(struct dsi_panel *panel,
|
||||
config->video_timing.dsc_enabled = mode->priv_info->dsc_enabled;
|
||||
config->video_timing.dsc = &mode->priv_info->dsc;
|
||||
|
||||
config->bit_clk_rate_hz_override = mode->priv_info->clk_rate_hz;
|
||||
if (dyn_clk_caps->dyn_clk_support)
|
||||
config->bit_clk_rate_hz_override = mode->timing.clk_rate_hz;
|
||||
else
|
||||
config->bit_clk_rate_hz_override = mode->priv_info->clk_rate_hz;
|
||||
|
||||
config->esc_clk_rate_hz = 19200000;
|
||||
mutex_unlock(&panel->panel_lock);
|
||||
return rc;
|
||||
|
@@ -63,10 +63,18 @@ enum dsi_dms_mode {
|
||||
};
|
||||
|
||||
struct dsi_dfps_capabilities {
|
||||
bool dfps_support;
|
||||
enum dsi_dfps_type type;
|
||||
u32 min_refresh_rate;
|
||||
u32 max_refresh_rate;
|
||||
u32 *dfps_list;
|
||||
u32 dfps_list_len;
|
||||
bool dfps_support;
|
||||
};
|
||||
|
||||
struct dsi_dyn_clk_caps {
|
||||
bool dyn_clk_support;
|
||||
u32 *bit_clk_list;
|
||||
u32 bit_clk_list_len;
|
||||
};
|
||||
|
||||
struct dsi_pinctrl_info {
|
||||
@@ -159,6 +167,7 @@ struct dsi_panel {
|
||||
bool panel_mode_switch_enabled;
|
||||
|
||||
struct dsi_dfps_capabilities dfps_caps;
|
||||
struct dsi_dyn_clk_caps dyn_clk_caps;
|
||||
struct dsi_panel_phy_props phy_props;
|
||||
|
||||
struct dsi_display_mode *cur_mode;
|
||||
|
@@ -118,6 +118,9 @@ static int dsi_phy_regmap_init(struct platform_device *pdev,
|
||||
|
||||
phy->hw.base = ptr;
|
||||
|
||||
ptr = msm_ioremap(pdev, "dyn_refresh_base", phy->name);
|
||||
phy->hw.dyn_pll_base = ptr;
|
||||
|
||||
pr_debug("[%s] map dsi_phy registers to %pK\n",
|
||||
phy->name, phy->hw.base);
|
||||
|
||||
@@ -641,11 +644,8 @@ int dsi_phy_validate_mode(struct msm_dsi_phy *dsi_phy,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&dsi_phy->phy_lock);
|
||||
|
||||
pr_debug("[PHY_%d] Skipping validation\n", dsi_phy->index);
|
||||
|
||||
mutex_unlock(&dsi_phy->phy_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -887,7 +887,7 @@ int dsi_phy_enable(struct msm_dsi_phy *phy,
|
||||
rc = phy->hw.ops.calculate_timing_params(&phy->hw,
|
||||
&phy->mode,
|
||||
&config->common_config,
|
||||
&phy->cfg.timing);
|
||||
&phy->cfg.timing, false);
|
||||
if (rc) {
|
||||
pr_err("[%s] failed to set timing, rc=%d\n", phy->name, rc);
|
||||
goto error;
|
||||
@@ -905,6 +905,27 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* update dsi phy timings for dynamic clk switch use case */
|
||||
int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy,
|
||||
struct dsi_host_config *config)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!phy || !config) {
|
||||
pr_err("invalid argument\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&phy->mode, &config->video_timing, sizeof(phy->mode));
|
||||
rc = phy->hw.ops.calculate_timing_params(&phy->hw, &phy->mode,
|
||||
&config->common_config,
|
||||
&phy->cfg.timing, true);
|
||||
if (rc)
|
||||
pr_err("failed to calculate phy timings %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int dsi_phy_lane_reset(struct msm_dsi_phy *phy)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1069,6 +1090,7 @@ int dsi_phy_set_timing_params(struct msm_dsi_phy *phy,
|
||||
rc = phy->hw.ops.phy_timing_val(&phy->cfg.timing, timing, size);
|
||||
if (!rc)
|
||||
phy->cfg.is_phy_timing_present = true;
|
||||
|
||||
mutex_unlock(&phy->phy_lock);
|
||||
return rc;
|
||||
}
|
||||
@@ -1117,6 +1139,106 @@ int dsi_phy_conv_logical_to_phy_lane(
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dsi_phy_config_dynamic_refresh() - Configure dynamic refresh registers
|
||||
* @phy: DSI PHY handle
|
||||
* @delay: pipe delays for dynamic refresh
|
||||
* @is_master: Boolean to indicate if for master or slave.
|
||||
*/
|
||||
void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
|
||||
struct dsi_dyn_clk_delay *delay,
|
||||
bool is_master)
|
||||
{
|
||||
struct dsi_phy_cfg *cfg;
|
||||
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
mutex_lock(&phy->phy_lock);
|
||||
|
||||
cfg = &phy->cfg;
|
||||
if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_config)
|
||||
phy->hw.ops.dyn_refresh_ops.dyn_refresh_config(&phy->hw, cfg,
|
||||
is_master);
|
||||
if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay)
|
||||
phy->hw.ops.dyn_refresh_ops.dyn_refresh_pipe_delay(
|
||||
&phy->hw, delay);
|
||||
|
||||
mutex_unlock(&phy->phy_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh
|
||||
* @phy: DSI PHY handle
|
||||
* @is_master: Boolean to indicate if for master or slave.
|
||||
*/
|
||||
void dsi_phy_dynamic_refresh_trigger(struct msm_dsi_phy *phy, bool is_master)
|
||||
{
|
||||
u32 off;
|
||||
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
mutex_lock(&phy->phy_lock);
|
||||
/*
|
||||
* program PLL_SWI_INTF_SEL and SW_TRIGGER bit only for
|
||||
* master and program SYNC_MODE bit only for slave.
|
||||
*/
|
||||
if (is_master)
|
||||
off = BIT(DYN_REFRESH_INTF_SEL) | BIT(DYN_REFRESH_SWI_CTRL) |
|
||||
BIT(DYN_REFRESH_SW_TRIGGER);
|
||||
else
|
||||
off = BIT(DYN_REFRESH_SYNC_MODE) | BIT(DYN_REFRESH_SWI_CTRL);
|
||||
|
||||
if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper)
|
||||
phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper(&phy->hw, off);
|
||||
|
||||
mutex_unlock(&phy->phy_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_phy_cache_phy_timings - cache the phy timings calculated as part of
|
||||
* dynamic refresh.
|
||||
* @phy: DSI PHY Handle.
|
||||
* @dst: Pointer to cache location.
|
||||
* @size: Number of phy lane settings.
|
||||
*/
|
||||
int dsi_phy_dyn_refresh_cache_phy_timings(struct msm_dsi_phy *phy, u32 *dst,
|
||||
u32 size)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!phy || !dst || !size)
|
||||
return -EINVAL;
|
||||
|
||||
if (phy->hw.ops.dyn_refresh_ops.cache_phy_timings)
|
||||
rc = phy->hw.ops.dyn_refresh_ops.cache_phy_timings(
|
||||
&phy->cfg.timing, dst, size);
|
||||
|
||||
if (rc)
|
||||
pr_err("failed to cache phy timings %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* dsi_phy_dynamic_refresh_clear() - clear dynamic refresh config
|
||||
* @phy: DSI PHY handle
|
||||
*/
|
||||
void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy)
|
||||
{
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
mutex_lock(&phy->phy_lock);
|
||||
|
||||
if (phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper)
|
||||
phy->hw.ops.dyn_refresh_ops.dyn_refresh_helper(&phy->hw, 0);
|
||||
|
||||
mutex_unlock(&phy->phy_lock);
|
||||
}
|
||||
|
||||
void dsi_phy_drv_register(void)
|
||||
{
|
||||
platform_driver_register(&dsi_phy_platform_driver);
|
||||
|
@@ -290,4 +290,45 @@ void dsi_phy_drv_register(void);
|
||||
*/
|
||||
void dsi_phy_drv_unregister(void);
|
||||
|
||||
/**
|
||||
* dsi_phy_update_phy_timings() - Update dsi phy timings
|
||||
* @phy: DSI PHY handle
|
||||
* @config: DSI Host config parameters
|
||||
*
|
||||
* Return: error code.
|
||||
*/
|
||||
int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy,
|
||||
struct dsi_host_config *config);
|
||||
|
||||
/**
|
||||
* dsi_phy_config_dynamic_refresh() - Configure dynamic refresh registers
|
||||
* @phy: DSI PHY handle
|
||||
* @delay: pipe delays for dynamic refresh
|
||||
* @is_master: Boolean to indicate if for master or slave
|
||||
*/
|
||||
void dsi_phy_config_dynamic_refresh(struct msm_dsi_phy *phy,
|
||||
struct dsi_dyn_clk_delay *delay,
|
||||
bool is_master);
|
||||
/**
|
||||
* dsi_phy_dynamic_refresh_trigger() - trigger dynamic refresh
|
||||
* @phy: DSI PHY handle
|
||||
* @is_master: Boolean to indicate if for master or slave.
|
||||
*/
|
||||
void dsi_phy_dynamic_refresh_trigger(struct msm_dsi_phy *phy, bool is_master);
|
||||
|
||||
/**
|
||||
* dsi_phy_dynamic_refresh_clear() - clear dynamic refresh config
|
||||
* @phy: DSI PHY handle
|
||||
*/
|
||||
void dsi_phy_dynamic_refresh_clear(struct msm_dsi_phy *phy);
|
||||
|
||||
/**
|
||||
* dsi_phy_dyn_refresh_cache_phy_timings - cache the phy timings calculated
|
||||
* as part of dynamic refresh.
|
||||
* @phy: DSI PHY Handle.
|
||||
* @dst: Pointer to cache location.
|
||||
* @size: Number of phy lane settings.
|
||||
*/
|
||||
int dsi_phy_dyn_refresh_cache_phy_timings(struct msm_dsi_phy *phy,
|
||||
u32 *dst, u32 size);
|
||||
#endif /* _DSI_PHY_H_ */
|
||||
|
@@ -161,6 +161,43 @@ struct phy_ulps_config_ops {
|
||||
bool (*is_lanes_in_ulps)(u32 ulps, u32 ulps_lanes);
|
||||
};
|
||||
|
||||
struct phy_dyn_refresh_ops {
|
||||
/**
|
||||
* dyn_refresh_helper - helper function to config particular registers
|
||||
* @phy: Pointer to DSI PHY hardware instance.
|
||||
* @offset: register offset to program.
|
||||
*/
|
||||
void (*dyn_refresh_helper)(struct dsi_phy_hw *phy, u32 offset);
|
||||
|
||||
/**
|
||||
* dyn_refresh_config - configure dynamic refresh ctrl registers
|
||||
* @phy: Pointer to DSI PHY hardware instance.
|
||||
* @cfg: Pointer to DSI PHY timings.
|
||||
* @is_master: Boolean to indicate whether for master or slave.
|
||||
*/
|
||||
void (*dyn_refresh_config)(struct dsi_phy_hw *phy,
|
||||
struct dsi_phy_cfg *cfg, bool is_master);
|
||||
|
||||
/**
|
||||
* dyn_refresh_pipe_delay - configure pipe delay registers for dynamic
|
||||
* refresh.
|
||||
* @phy: Pointer to DSI PHY hardware instance.
|
||||
* @delay: structure containing all the delays to be programed.
|
||||
*/
|
||||
void (*dyn_refresh_pipe_delay)(struct dsi_phy_hw *phy,
|
||||
struct dsi_dyn_clk_delay *delay);
|
||||
|
||||
/**
|
||||
* cache_phy_timings - cache the phy timings calculated as part of
|
||||
* dynamic refresh.
|
||||
* @timings: Pointer to calculated phy timing parameters.
|
||||
* @dst: Pointer to cache location.
|
||||
* @size: Number of phy lane settings.
|
||||
*/
|
||||
int (*cache_phy_timings)(struct dsi_phy_per_lane_cfgs *timings,
|
||||
u32 *dst, u32 size);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_phy_hw_ops - Operations for DSI PHY hardware.
|
||||
* @regulator_enable: Enable PHY regulators.
|
||||
@@ -220,11 +257,14 @@ struct dsi_phy_hw_ops {
|
||||
* @mode: Mode information for which timing has to be calculated.
|
||||
* @config: DSI host configuration for this mode.
|
||||
* @timing: Timing parameters for each lane which will be returned.
|
||||
* @use_mode_bit_clk: Boolean to indicate whether reacalculate dsi
|
||||
* bitclk or use the existing bitclk(for dynamic clk case).
|
||||
*/
|
||||
int (*calculate_timing_params)(struct dsi_phy_hw *phy,
|
||||
struct dsi_mode_info *mode,
|
||||
struct dsi_host_common_cfg *config,
|
||||
struct dsi_phy_per_lane_cfgs *timing);
|
||||
struct dsi_phy_per_lane_cfgs *timing,
|
||||
bool use_mode_bit_clk);
|
||||
|
||||
/**
|
||||
* phy_timing_val() - Gets PHY timing values.
|
||||
@@ -265,12 +305,15 @@ struct dsi_phy_hw_ops {
|
||||
|
||||
void *timing_ops;
|
||||
struct phy_ulps_config_ops ulps_ops;
|
||||
struct phy_dyn_refresh_ops dyn_refresh_ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dsi_phy_hw - DSI phy hardware object specific to an instance
|
||||
* @base: VA for the DSI PHY base address.
|
||||
* @length: Length of the DSI PHY register base map.
|
||||
* @dyn_pll_base: VA for the DSI dynamic refresh base address.
|
||||
* @length: Length of the DSI dynamic refresh register base map.
|
||||
* @index: Instance ID of the controller.
|
||||
* @version: DSI PHY version.
|
||||
* @phy_clamp_base: Base address of phy clamp register map.
|
||||
@@ -280,6 +323,8 @@ struct dsi_phy_hw_ops {
|
||||
struct dsi_phy_hw {
|
||||
void __iomem *base;
|
||||
u32 length;
|
||||
void __iomem *dyn_pll_base;
|
||||
u32 dyn_refresh_len;
|
||||
u32 index;
|
||||
|
||||
enum dsi_phy_version version;
|
||||
|
@@ -58,6 +58,47 @@
|
||||
#define DSIPHY_LNX_LPRX_CTRL(n) (0x228 + (0x80 * (n)))
|
||||
#define DSIPHY_LNX_TX_DCTRL(n) (0x22C + (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)
|
||||
|
||||
/**
|
||||
* regulator_enable() - enable regulators for DSI PHY
|
||||
* @phy: Pointer to DSI PHY hardware object.
|
||||
@@ -462,3 +503,163 @@ int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
|
||||
timing_cfg->lane_v3[i] = timing_val[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dsi_phy_hw_v3_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_CTRL9,
|
||||
DSIPHY_CMN_GLBL_CTRL, DSIPHY_CMN_VREG_CTRL,
|
||||
0x10, 0x59);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10,
|
||||
DSIPHY_CMN_TIMING_CTRL_0, DSIPHY_CMN_TIMING_CTRL_1,
|
||||
cfg->timing.lane_v3[0], cfg->timing.lane_v3[1]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11,
|
||||
DSIPHY_CMN_TIMING_CTRL_2, DSIPHY_CMN_TIMING_CTRL_3,
|
||||
cfg->timing.lane_v3[2], cfg->timing.lane_v3[3]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12,
|
||||
DSIPHY_CMN_TIMING_CTRL_4, DSIPHY_CMN_TIMING_CTRL_5,
|
||||
cfg->timing.lane_v3[4], cfg->timing.lane_v3[5]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13,
|
||||
DSIPHY_CMN_TIMING_CTRL_6, DSIPHY_CMN_TIMING_CTRL_7,
|
||||
cfg->timing.lane_v3[6], cfg->timing.lane_v3[7]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14,
|
||||
DSIPHY_CMN_TIMING_CTRL_8, DSIPHY_CMN_TIMING_CTRL_9,
|
||||
cfg->timing.lane_v3[8], cfg->timing.lane_v3[9]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15,
|
||||
DSIPHY_CMN_TIMING_CTRL_10, DSIPHY_CMN_TIMING_CTRL_11,
|
||||
cfg->timing.lane_v3[10], cfg->timing.lane_v3[11]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL16,
|
||||
DSIPHY_CMN_CTRL_0, DSIPHY_CMN_LANE_CTRL0,
|
||||
0x7f, 0x1f);
|
||||
} else {
|
||||
reg = DSI_R32(phy, DSIPHY_CMN_CLK_CFG0);
|
||||
reg &= ~BIT(5);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0,
|
||||
DSIPHY_CMN_CLK_CFG0, 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_GLBL_CTRL,
|
||||
0x0, 0x10);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2,
|
||||
DSIPHY_CMN_VREG_CTRL, DSIPHY_CMN_TIMING_CTRL_0,
|
||||
0x59, cfg->timing.lane_v3[0]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3,
|
||||
DSIPHY_CMN_TIMING_CTRL_1, DSIPHY_CMN_TIMING_CTRL_2,
|
||||
cfg->timing.lane_v3[1], cfg->timing.lane_v3[2]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4,
|
||||
DSIPHY_CMN_TIMING_CTRL_3, DSIPHY_CMN_TIMING_CTRL_4,
|
||||
cfg->timing.lane_v3[3], cfg->timing.lane_v3[4]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5,
|
||||
DSIPHY_CMN_TIMING_CTRL_5, DSIPHY_CMN_TIMING_CTRL_6,
|
||||
cfg->timing.lane_v3[5], cfg->timing.lane_v3[6]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6,
|
||||
DSIPHY_CMN_TIMING_CTRL_7, DSIPHY_CMN_TIMING_CTRL_8,
|
||||
cfg->timing.lane_v3[7], cfg->timing.lane_v3[8]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7,
|
||||
DSIPHY_CMN_TIMING_CTRL_9, DSIPHY_CMN_TIMING_CTRL_10,
|
||||
cfg->timing.lane_v3[9], cfg->timing.lane_v3[10]);
|
||||
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8,
|
||||
DSIPHY_CMN_TIMING_CTRL_11, DSIPHY_CMN_CTRL_0,
|
||||
cfg->timing.lane_v3[11], 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_v3_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_v3_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_v3_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_V3_SIZE) {
|
||||
pr_err("size mis-match\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
dst[i] = timings->lane_v3[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -630,11 +630,14 @@ error:
|
||||
* @mode: Mode information for which timing has to be calculated.
|
||||
* @config: DSI host configuration for this mode.
|
||||
* @timing: Timing parameters for each lane which will be returned.
|
||||
* @use_mode_bit_clk: Boolean to indicate whether reacalculate dsi
|
||||
* bit clk or use the existing bit clk(for dynamic clk case).
|
||||
*/
|
||||
int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy,
|
||||
struct dsi_mode_info *mode,
|
||||
struct dsi_host_common_cfg *host,
|
||||
struct dsi_phy_per_lane_cfgs *timing)
|
||||
struct dsi_mode_info *mode,
|
||||
struct dsi_host_common_cfg *host,
|
||||
struct dsi_phy_per_lane_cfgs *timing,
|
||||
bool use_mode_bit_clk)
|
||||
{
|
||||
/* constants */
|
||||
u32 const esc_clk_mhz = 192; /* TODO: esc clock is hardcoded */
|
||||
@@ -677,7 +680,10 @@ int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy,
|
||||
num_of_lanes++;
|
||||
|
||||
|
||||
x = mult_frac(v_total * h_total, inter_num, num_of_lanes);
|
||||
if (use_mode_bit_clk)
|
||||
x = mode->clk_rate_hz;
|
||||
else
|
||||
x = mult_frac(v_total * h_total, inter_num, num_of_lanes);
|
||||
y = rounddown(x, 1);
|
||||
|
||||
clk_params.bitclk_mbps = rounddown(DIV_ROUND_UP_ULL(y, 1000000), 1);
|
||||
|
在新工单中引用
屏蔽一个用户