Merge "disp: msm: dsi: DSI PHY V4 support of dynamic clock switch"

这个提交包含在:
qctecmdr
2019-06-27 03:34:31 -07:00
提交者 Gerrit - the friendly Code Review server
当前提交 acf755573d
修改 32 个文件,包含 2878 行新增531 行删除

查看文件

@@ -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);