Merge "disp: msm: dsi: disallow backlight update during panel mode switch"

This commit is contained in:
qctecmdr
2020-03-20 20:33:23 -07:00
committed by Gerrit - the friendly Code Review server
15 changed files with 642 additions and 104 deletions

View File

@@ -192,6 +192,14 @@ static void dsi_catalog_phy_2_0_init(struct dsi_phy_hw *phy)
dsi_phy_hw_calculate_timing_params; dsi_phy_hw_calculate_timing_params;
phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v2_0; phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v2_0;
phy->ops.clamp_ctrl = dsi_phy_hw_v2_0_clamp_ctrl; phy->ops.clamp_ctrl = dsi_phy_hw_v2_0_clamp_ctrl;
phy->ops.dyn_refresh_ops.dyn_refresh_config =
dsi_phy_hw_v2_0_dyn_refresh_config;
phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay =
dsi_phy_hw_v2_0_dyn_refresh_pipe_delay;
phy->ops.dyn_refresh_ops.dyn_refresh_helper =
dsi_phy_hw_v2_0_dyn_refresh_helper;
phy->ops.dyn_refresh_ops.cache_phy_timings =
dsi_phy_hw_v2_0_cache_phy_timings;
} }
/** /**

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/ */
#ifndef _DSI_CATALOG_H_ #ifndef _DSI_CATALOG_H_
@@ -80,6 +80,13 @@ void dsi_phy_hw_v2_0_idle_off(struct dsi_phy_hw *phy);
int dsi_phy_hw_timing_val_v2_0(struct dsi_phy_per_lane_cfgs *timing_cfg, int dsi_phy_hw_timing_val_v2_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
u32 *timing_val, u32 size); u32 *timing_val, u32 size);
void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable); void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable);
void dsi_phy_hw_v2_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy,
struct dsi_phy_cfg *cfg, bool is_master);
void dsi_phy_hw_v2_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
struct dsi_dyn_clk_delay *delay);
int dsi_phy_hw_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
u32 *dst, u32 size);
/* Definitions for 10nm PHY hardware driver */ /* Definitions for 10nm PHY hardware driver */
void dsi_phy_hw_v3_0_regulator_enable(struct dsi_phy_hw *phy, void dsi_phy_hw_v3_0_regulator_enable(struct dsi_phy_hw *phy,

View File

@@ -106,11 +106,13 @@ struct dsi_link_lp_clk_info {
/** /**
* struct link_clk_freq - Clock frequency information for Link clocks * struct link_clk_freq - Clock frequency information for Link clocks
* @byte_clk_rate: Frequency of DSI byte_clk in KHz. * @byte_clk_rate: Frequency of DSI byte_clk in KHz.
* @byte_intf_clk_rate: Frequency of DSI byte_intf_clk in KHz.
* @pixel_clk_rate: Frequency of DSI pixel_clk in KHz. * @pixel_clk_rate: Frequency of DSI pixel_clk in KHz.
* @esc_clk_rate: Frequency of DSI escape clock in KHz. * @esc_clk_rate: Frequency of DSI escape clock in KHz.
*/ */
struct link_clk_freq { struct link_clk_freq {
u32 byte_clk_rate; u32 byte_clk_rate;
u32 byte_intf_clk_rate;
u32 pix_clk_rate; u32 pix_clk_rate;
u32 esc_clk_rate; u32 esc_clk_rate;
}; };
@@ -292,10 +294,12 @@ 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 * dsi_clk_set_byte_clk_rate() - set frequency for byte clock
* @client: DSI clock client pointer. * @client: DSI clock client pointer.
* @byte_clk: Pixel clock rate in Hz. * @byte_clk: Pixel clock rate in Hz.
* @byte_intf_clk: Byte interface clock rate in Hz.
* @index: Index of the DSI controller. * @index: Index of the DSI controller.
* return: error code in case of failure or 0 for success. * 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); int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk,
u64 byte_intf_clk, u32 index);
/** /**
* dsi_clk_update_parent() - update parent clocks for specified clock * dsi_clk_update_parent() - update parent clocks for specified clock

View File

@@ -130,15 +130,16 @@ 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 * dsi_clk_set_byte_clk_rate() - set frequency for byte clock
* @client: DSI clock client pointer. * @client: DSI clock client pointer.
* @byte_clk: Byte clock rate in Hz. * @byte_clk: Byte clock rate in Hz.
* @byte_intf_clk: Byte interface clock rate in Hz.
* @index: Index of the DSI controller. * @index: Index of the DSI controller.
* return: error code in case of failure or 0 for success. * 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) int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk,
u64 byte_intf_clk, u32 index)
{ {
int rc = 0; int rc = 0;
struct dsi_clk_client_info *c = client; struct dsi_clk_client_info *c = client;
struct dsi_clk_mngr *mngr; struct dsi_clk_mngr *mngr;
u64 byte_intf_rate;
mngr = c->mngr; mngr = c->mngr;
rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk); rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk);
@@ -148,12 +149,14 @@ int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index)
mngr->link_clks[index].freq.byte_clk_rate = byte_clk; mngr->link_clks[index].freq.byte_clk_rate = byte_clk;
if (mngr->link_clks[index].hs_clks.byte_intf_clk) { 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, rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_intf_clk,
byte_intf_rate); byte_intf_clk);
if (rc) if (rc)
DSI_ERR("failed to set clk rate for byte intf clk=%d\n", DSI_ERR("failed to set clk rate for byte intf clk=%d\n",
rc); rc);
else
mngr->link_clks[index].freq.byte_intf_clk_rate =
byte_intf_clk;
} }
return rc; return rc;
@@ -344,12 +347,10 @@ static int dsi_link_hs_clk_set_rate(struct dsi_link_hs_clk_info *link_hs_clks,
/* /*
* If byte_intf_clk is present, set rate for that too. * If byte_intf_clk is present, set rate for that too.
* For DPHY: byte_intf_clk_rate = byte_clk_rate / 2
* todo: this needs to be revisited when support for CPHY is added
*/ */
if (link_hs_clks->byte_intf_clk) { if (link_hs_clks->byte_intf_clk) {
rc = clk_set_rate(link_hs_clks->byte_intf_clk, rc = clk_set_rate(link_hs_clks->byte_intf_clk,
(l_clks->freq.byte_clk_rate / 2)); l_clks->freq.byte_intf_clk_rate);
if (rc) { if (rc) {
DSI_ERR("set_rate failed for byte_intf_clk rc = %d\n", DSI_ERR("set_rate failed for byte_intf_clk rc = %d\n",
rc); rc);

View File

@@ -269,10 +269,6 @@ dsi_ctrl_get_aspace(struct dsi_ctrl *dsi_ctrl,
static void dsi_ctrl_flush_cmd_dma_queue(struct dsi_ctrl *dsi_ctrl) static void dsi_ctrl_flush_cmd_dma_queue(struct dsi_ctrl *dsi_ctrl)
{ {
u32 status;
u32 mask = DSI_CMD_MODE_DMA_DONE;
struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops;
/* /*
* If a command is triggered right after another command, * If a command is triggered right after another command,
* check if the previous command transfer is completed. If * check if the previous command transfer is completed. If
@@ -281,21 +277,8 @@ static void dsi_ctrl_flush_cmd_dma_queue(struct dsi_ctrl *dsi_ctrl)
* completed before triggering the next command by * completed before triggering the next command by
* flushing the workqueue. * flushing the workqueue.
*/ */
status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw);
if (atomic_read(&dsi_ctrl->dma_irq_trig)) { if (atomic_read(&dsi_ctrl->dma_irq_trig)) {
cancel_work_sync(&dsi_ctrl->dma_cmd_wait); cancel_work_sync(&dsi_ctrl->dma_cmd_wait);
} else if (status & mask) {
atomic_set(&dsi_ctrl->dma_irq_trig, 1);
status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE);
dsi_hw_ops.clear_interrupt_status(
&dsi_ctrl->hw,
status);
dsi_ctrl_disable_status_interrupt(dsi_ctrl,
DSI_SINT_CMD_MODE_DMA_DONE);
complete_all(&dsi_ctrl->irq_info.cmd_dma_done);
cancel_work_sync(&dsi_ctrl->dma_cmd_wait);
DSI_CTRL_DEBUG(dsi_ctrl,
"dma_tx done but irq not yet triggered\n");
} else { } else {
flush_workqueue(dsi_ctrl->dma_cmd_workq); flush_workqueue(dsi_ctrl->dma_cmd_workq);
} }
@@ -319,24 +302,11 @@ static void dsi_ctrl_dma_cmd_wait_for_done(struct work_struct *work)
*/ */
if (atomic_read(&dsi_ctrl->dma_irq_trig)) if (atomic_read(&dsi_ctrl->dma_irq_trig))
goto done; goto done;
/*
* If IRQ wasn't triggered check interrupt status register for
* transfer done before waiting.
*/
status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw);
if (status & mask) {
status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE);
dsi_hw_ops.clear_interrupt_status(&dsi_ctrl->hw,
status);
dsi_ctrl_disable_status_interrupt(dsi_ctrl,
DSI_SINT_CMD_MODE_DMA_DONE);
goto done;
}
ret = wait_for_completion_timeout( ret = wait_for_completion_timeout(
&dsi_ctrl->irq_info.cmd_dma_done, &dsi_ctrl->irq_info.cmd_dma_done,
msecs_to_jiffies(DSI_CTRL_TX_TO_MS)); msecs_to_jiffies(DSI_CTRL_TX_TO_MS));
if (ret == 0) { if (ret == 0 && !atomic_read(&dsi_ctrl->dma_irq_trig)) {
status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw); status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw);
if (status & mask) { if (status & mask) {
status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE); status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE);
@@ -877,9 +847,9 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
{ {
int rc = 0; int rc = 0;
u32 num_of_lanes = 0; u32 num_of_lanes = 0;
u32 bpp, frame_time_us; u32 bpp, frame_time_us, byte_intf_clk_div;
u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane, u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane,
byte_clk_rate; byte_clk_rate, byte_intf_clk_rate;
struct dsi_host_common_cfg *host_cfg = &config->common_config; struct dsi_host_common_cfg *host_cfg = &config->common_config;
struct dsi_split_link_config *split_link = &host_cfg->split_link; struct dsi_split_link_config *split_link = &host_cfg->split_link;
struct dsi_mode_info *timing = &config->video_timing; struct dsi_mode_info *timing = &config->video_timing;
@@ -924,14 +894,20 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
do_div(pclk_rate, bpp); do_div(pclk_rate, bpp);
byte_clk_rate = bit_rate_per_lane; byte_clk_rate = bit_rate_per_lane;
do_div(byte_clk_rate, 8); do_div(byte_clk_rate, 8);
byte_intf_clk_rate = byte_clk_rate;
byte_intf_clk_div = host_cfg->byte_intf_clk_div;
do_div(byte_intf_clk_rate, byte_intf_clk_div);
DSI_CTRL_DEBUG(dsi_ctrl, "bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n", DSI_CTRL_DEBUG(dsi_ctrl, "bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
bit_rate, bit_rate_per_lane); bit_rate, bit_rate_per_lane);
DSI_CTRL_DEBUG(dsi_ctrl, "byte_clk_rate = %llu, pclk_rate = %llu\n", DSI_CTRL_DEBUG(dsi_ctrl, "byte_clk_rate = %llu, byte_intf_clk = %llu\n",
byte_clk_rate, pclk_rate); byte_clk_rate, byte_intf_clk_rate);
DSI_CTRL_DEBUG(dsi_ctrl, "pclk_rate = %llu\n", pclk_rate);
dsi_ctrl->clk_freq.byte_clk_rate = byte_clk_rate; dsi_ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
dsi_ctrl->clk_freq.pix_clk_rate = pclk_rate; dsi_ctrl->clk_freq.pix_clk_rate = pclk_rate;
dsi_ctrl->clk_freq.esc_clk_rate = config->esc_clk_rate_hz; dsi_ctrl->clk_freq.esc_clk_rate = config->esc_clk_rate_hz;
dsi_ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate;
config->bit_clk_rate_hz = dsi_ctrl->clk_freq.byte_clk_rate * 8; config->bit_clk_rate_hz = dsi_ctrl->clk_freq.byte_clk_rate * 8;
rc = dsi_clk_set_link_frequencies(clk_handle, dsi_ctrl->clk_freq, rc = dsi_clk_set_link_frequencies(clk_handle, dsi_ctrl->clk_freq,
@@ -1268,23 +1244,33 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
* result in smmu write faults with DSI as client. * result in smmu write faults with DSI as client.
*/ */
if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
dsi_hw_ops.soft_reset(&dsi_ctrl->hw); if (dsi_ctrl->version < DSI_CTRL_VERSION_2_4)
dsi_hw_ops.soft_reset(&dsi_ctrl->hw);
dsi_ctrl->cmd_len = 0; dsi_ctrl->cmd_len = 0;
} }
} }
} }
static u32 dsi_ctrl_validate_msg_flags(const struct mipi_dsi_msg *msg, static u32 dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl,
const struct mipi_dsi_msg *msg,
u32 flags) u32 flags)
{ {
/* /*
* ASYNC command wait mode is not supported for FIFO commands. * ASYNC command wait mode is not supported for
* Waiting after a command is transferred cannot be guaranteed * - commands sent using DSI FIFO memory
* if DSI_CTRL_CMD_ASYNC_WAIT flag is set. * - DSI read commands
* - DCS commands sent in non-embedded mode
* - whenever an explicit wait time is specificed for the command
* since the wait time cannot be guaranteed in async mode
* - video mode panels
*/ */
if ((flags & DSI_CTRL_CMD_FIFO_STORE) || if ((flags & DSI_CTRL_CMD_FIFO_STORE) ||
msg->wait_ms) flags & DSI_CTRL_CMD_READ ||
flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE ||
msg->wait_ms ||
(dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE))
flags &= ~DSI_CTRL_CMD_ASYNC_WAIT; flags &= ~DSI_CTRL_CMD_ASYNC_WAIT;
return flags; return flags;
} }
@@ -1313,7 +1299,7 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
goto error; goto error;
} }
flags = dsi_ctrl_validate_msg_flags(msg, flags); flags = dsi_ctrl_validate_msg_flags(dsi_ctrl, msg, flags);
if (dsi_ctrl->dma_wait_queued) if (dsi_ctrl->dma_wait_queued)
dsi_ctrl_flush_cmd_dma_queue(dsi_ctrl); dsi_ctrl_flush_cmd_dma_queue(dsi_ctrl);
@@ -2692,6 +2678,10 @@ void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw,
dsi_ctrl->irq_info.irq_stat_mask); dsi_ctrl->irq_info.irq_stat_mask);
} }
if (intr_idx == DSI_SINT_CMD_MODE_DMA_DONE)
dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw,
dsi_ctrl->irq_info.irq_stat_mask);
++(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]); ++(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]);
if (event_info) if (event_info)
@@ -3196,7 +3186,8 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
BIT(DSI_FIFO_OVERFLOW), false); BIT(DSI_FIFO_OVERFLOW), false);
if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) { if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
dsi_hw_ops.soft_reset(&dsi_ctrl->hw); if (dsi_ctrl->version < DSI_CTRL_VERSION_2_4)
dsi_hw_ops.soft_reset(&dsi_ctrl->hw);
dsi_ctrl->cmd_len = 0; dsi_ctrl->cmd_len = 0;
} }
} }

View File

@@ -217,6 +217,22 @@ enum dsi_dfps_type {
DSI_DFPS_MAX DSI_DFPS_MAX
}; };
/**
* enum dsi_dyn_clk_feature_type - Dynamic clock feature support type
* @DSI_DYN_CLK_TYPE_LEGACY: Constant FPS is not supported
* @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP: Constant FPS supported with
* change in hfp
* @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP: Constant FPS supported with
* change in vfp
* @DSI_DYN_CLK_TYPE_MAX:
*/
enum dsi_dyn_clk_feature_type {
DSI_DYN_CLK_TYPE_LEGACY = 0,
DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP,
DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP,
DSI_DYN_CLK_TYPE_MAX
};
/** /**
* enum dsi_cmd_set_type - DSI command set type * enum dsi_cmd_set_type - DSI command set type
* @DSI_CMD_SET_PRE_ON: Panel pre on * @DSI_CMD_SET_PRE_ON: Panel pre on
@@ -450,6 +466,7 @@ struct dsi_split_link_config {
* @ext_bridge_mode: External bridge is connected. * @ext_bridge_mode: External bridge is connected.
* @force_hs_clk_lane: Send continuous clock to the panel. * @force_hs_clk_lane: Send continuous clock to the panel.
* @dsi_split_link_config: Split Link Configuration. * @dsi_split_link_config: Split Link Configuration.
* @byte_intf_clk_div: Determines the factor for calculating byte intf clock.
*/ */
struct dsi_host_common_cfg { struct dsi_host_common_cfg {
enum dsi_pixel_format dst_format; enum dsi_pixel_format dst_format;
@@ -473,6 +490,7 @@ struct dsi_host_common_cfg {
bool ext_bridge_mode; bool ext_bridge_mode;
bool force_hs_clk_lane; bool force_hs_clk_lane;
struct dsi_split_link_config split_link; struct dsi_split_link_config split_link;
u32 byte_intf_clk_div;
}; };
/** /**

View File

@@ -801,7 +801,7 @@ int dsi_display_check_status(struct drm_connector *connector, void *display,
struct dsi_display *dsi_display = display; struct dsi_display *dsi_display = display;
struct dsi_panel *panel; struct dsi_panel *panel;
u32 status_mode; u32 status_mode;
int rc = 0x1; int rc = 0x1, ret;
u32 mask; u32 mask;
if (!dsi_display || !dsi_display->panel) if (!dsi_display || !dsi_display->panel)
@@ -839,8 +839,10 @@ int dsi_display_check_status(struct drm_connector *connector, void *display,
goto exit; goto exit;
} }
dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, ret = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
DSI_ALL_CLKS, DSI_CLK_ON); DSI_ALL_CLKS, DSI_CLK_ON);
if (ret)
goto release_panel_lock;
/* Mask error interrupts before attempting ESD read */ /* Mask error interrupts before attempting ESD read */
mask = BIT(DSI_FIFO_OVERFLOW) | BIT(DSI_FIFO_UNDERFLOW); mask = BIT(DSI_FIFO_OVERFLOW) | BIT(DSI_FIFO_UNDERFLOW);
@@ -3861,6 +3863,22 @@ static bool dsi_display_is_seamless_dfps_possible(
return true; return true;
} }
void dsi_display_update_byte_intf_div(struct dsi_display *display)
{
struct dsi_host_common_cfg *config;
struct dsi_display_ctrl *m_ctrl;
int phy_ver;
m_ctrl = &display->ctrl[display->cmd_master_idx];
config = &display->panel->host_config;
phy_ver = dsi_phy_get_version(m_ctrl->phy);
if (phy_ver <= DSI_PHY_VERSION_2_0)
config->byte_intf_clk_div = 1;
else
config->byte_intf_clk_div = 2;
}
static int dsi_display_update_dsi_bitrate(struct dsi_display *display, static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
u32 bit_clk_rate) u32 bit_clk_rate)
{ {
@@ -3883,8 +3901,9 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
display_for_each_ctrl(i, display) { display_for_each_ctrl(i, display) {
struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i]; struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i];
struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl; struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl;
u32 num_of_lanes = 0, bpp; u32 num_of_lanes = 0, bpp, byte_intf_clk_div;
u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate; u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate,
byte_intf_clk_rate;
struct dsi_host_common_cfg *host_cfg; struct dsi_host_common_cfg *host_cfg;
mutex_lock(&ctrl->ctrl_lock); mutex_lock(&ctrl->ctrl_lock);
@@ -3914,12 +3933,18 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
do_div(pclk_rate, bpp); do_div(pclk_rate, bpp);
byte_clk_rate = bit_rate_per_lane; byte_clk_rate = bit_rate_per_lane;
do_div(byte_clk_rate, 8); do_div(byte_clk_rate, 8);
byte_intf_clk_rate = byte_clk_rate;
byte_intf_clk_div = host_cfg->byte_intf_clk_div;
do_div(byte_intf_clk_rate, byte_intf_clk_div);
DSI_DEBUG("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n", DSI_DEBUG("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
bit_rate, bit_rate_per_lane); bit_rate, bit_rate_per_lane);
DSI_DEBUG("byte_clk_rate = %llu, pclk_rate = %llu\n", DSI_DEBUG("byte_clk_rate = %llu, byte_intf_clk_rate = %llu\n",
byte_clk_rate, pclk_rate); byte_clk_rate, byte_intf_clk_rate);
DSI_DEBUG("pclk_rate = %llu\n", pclk_rate);
ctrl->clk_freq.byte_clk_rate = byte_clk_rate; ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate;
ctrl->clk_freq.pix_clk_rate = pclk_rate; ctrl->clk_freq.pix_clk_rate = pclk_rate;
rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle, rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle,
ctrl->clk_freq, ctrl->cell_index); ctrl->clk_freq, ctrl->cell_index);
@@ -4013,7 +4038,8 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
if (!ctrl->ctrl) if (!ctrl->ctrl)
continue; continue;
rc = dsi_clk_set_byte_clk_rate(display->dsi_clk_handle, rc = dsi_clk_set_byte_clk_rate(display->dsi_clk_handle,
ctrl->ctrl->clk_freq.byte_clk_rate, i); ctrl->ctrl->clk_freq.byte_clk_rate,
ctrl->ctrl->clk_freq.byte_intf_clk_rate, i);
if (rc) { if (rc) {
DSI_ERR("failed to set byte rate for index:%d\n", i); DSI_ERR("failed to set byte rate for index:%d\n", i);
goto recover_byte_clk; goto recover_byte_clk;
@@ -4076,7 +4102,8 @@ recover_byte_clk:
if (!ctrl->ctrl) if (!ctrl->ctrl)
continue; continue;
dsi_clk_set_byte_clk_rate(display->dsi_clk_handle, dsi_clk_set_byte_clk_rate(display->dsi_clk_handle,
bkp_freq->byte_clk_rate, i); bkp_freq->byte_clk_rate,
bkp_freq->byte_intf_clk_rate, i);
} }
exit: exit:
@@ -4112,6 +4139,7 @@ static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display,
/* back up existing rates to handle failure case */ /* back up existing rates to handle failure case */
bkp_freq.byte_clk_rate = m_ctrl->ctrl->clk_freq.byte_clk_rate; bkp_freq.byte_clk_rate = m_ctrl->ctrl->clk_freq.byte_clk_rate;
bkp_freq.byte_intf_clk_rate = m_ctrl->ctrl->clk_freq.byte_intf_clk_rate;
bkp_freq.pix_clk_rate = m_ctrl->ctrl->clk_freq.pix_clk_rate; bkp_freq.pix_clk_rate = m_ctrl->ctrl->clk_freq.pix_clk_rate;
bkp_freq.esc_clk_rate = m_ctrl->ctrl->clk_freq.esc_clk_rate; bkp_freq.esc_clk_rate = m_ctrl->ctrl->clk_freq.esc_clk_rate;
@@ -4196,6 +4224,7 @@ static int dsi_display_dfps_update(struct dsi_display *display,
struct dsi_dfps_capabilities dfps_caps; struct dsi_dfps_capabilities dfps_caps;
int rc = 0; int rc = 0;
int i = 0; int i = 0;
struct dsi_dyn_clk_caps *dyn_clk_caps;
if (!display || !dsi_mode || !display->panel) { if (!display || !dsi_mode || !display->panel) {
DSI_ERR("Invalid params\n"); DSI_ERR("Invalid params\n");
@@ -4204,8 +4233,9 @@ static int dsi_display_dfps_update(struct dsi_display *display,
timing = &dsi_mode->timing; timing = &dsi_mode->timing;
dsi_panel_get_dfps_caps(display->panel, &dfps_caps); dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
if (!dfps_caps.dfps_support) { dyn_clk_caps = &(display->panel->dyn_clk_caps);
DSI_ERR("dfps not supported\n"); if (!dfps_caps.dfps_support && !dyn_clk_caps->maintain_const_fps) {
DSI_ERR("dfps or constant fps not supported\n");
return -ENOTSUPP; return -ENOTSUPP;
} }
@@ -4482,7 +4512,32 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
display->name, rc); display->name, rc);
goto error; goto error;
} }
} else if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) { display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
rc = dsi_ctrl_update_host_config(ctrl->ctrl,
&display->config, mode, mode->dsi_mode_flags,
display->dsi_clk_handle);
if (rc) {
DSI_ERR("failed to update ctrl config\n");
goto error;
}
}
if (priv_info->phy_timing_len) {
display_for_each_ctrl(i, display) {
ctrl = &display->ctrl[i];
rc = dsi_phy_set_timing_params(ctrl->phy,
priv_info->phy_timing_val,
priv_info->phy_timing_len,
commit_phy_timing);
if (rc)
DSI_ERR("Fail to add timing params\n");
}
}
if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK))
return rc;
}
if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) {
if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) { if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) {
rc = dsi_display_dynamic_clk_switch_vid(display, mode); rc = dsi_display_dynamic_clk_switch_vid(display, mode);
if (rc) if (rc)
@@ -4939,6 +4994,7 @@ static int dsi_display_bind(struct device *dev,
} }
} }
dsi_display_update_byte_intf_div(display);
rc = dsi_display_mipi_host_init(display); rc = dsi_display_mipi_host_init(display);
if (rc) { if (rc) {
DSI_ERR("[%s] failed to initialize mipi host, rc=%d\n", DSI_ERR("[%s] failed to initialize mipi host, rc=%d\n",
@@ -5872,6 +5928,53 @@ int dsi_display_get_mode_count(struct dsi_display *display,
return 0; return 0;
} }
void dsi_display_adjust_mode_timing(
struct dsi_dyn_clk_caps *dyn_clk_caps,
struct dsi_display_mode *dsi_mode,
int lanes, int bpp)
{
u64 new_htotal, new_vtotal, htotal, vtotal, old_htotal, div;
if (!dyn_clk_caps->maintain_const_fps)
return;
/*
* When there is a dynamic clock switch, there is small change
* in FPS. To compensate for this difference in FPS, hfp or vfp
* is adjusted. It has been assumed that the refined porch values
* are supported by the panel. This logic can be enhanced further
* in future by taking min/max porches supported by the panel.
*/
switch (dyn_clk_caps->type) {
case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP:
vtotal = DSI_V_TOTAL(&dsi_mode->timing);
old_htotal = dsi_h_total_dce(&dsi_mode->timing);
new_htotal = dsi_mode->timing.clk_rate_hz * lanes;
div = bpp * vtotal * dsi_mode->timing.refresh_rate;
do_div(new_htotal, div);
if (old_htotal > new_htotal)
dsi_mode->timing.h_front_porch -=
(old_htotal - new_htotal);
else
dsi_mode->timing.h_front_porch +=
(new_htotal - old_htotal);
break;
case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP:
htotal = dsi_h_total_dce(&dsi_mode->timing);
new_vtotal = dsi_mode->timing.clk_rate_hz * lanes;
div = bpp * htotal * dsi_mode->timing.refresh_rate;
do_div(new_vtotal, div);
dsi_mode->timing.v_front_porch = new_vtotal -
dsi_mode->timing.v_back_porch -
dsi_mode->timing.v_sync_width -
dsi_mode->timing.v_active;
break;
default:
break;
}
}
static void _dsi_display_populate_bit_clks(struct dsi_display *display, static void _dsi_display_populate_bit_clks(struct dsi_display *display,
int start, int end, u32 *mode_idx) int start, int end, u32 *mode_idx)
{ {
@@ -5911,6 +6014,9 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
* be based on user or device tree preferrence. * be based on user or device tree preferrence.
*/ */
src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0]; src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0];
dsi_display_adjust_mode_timing(dyn_clk_caps, src, lanes, bpp);
src->pixel_clk_khz = src->pixel_clk_khz =
div_u64(src->timing.clk_rate_hz * lanes, bpp); div_u64(src->timing.clk_rate_hz * lanes, bpp);
src->pixel_clk_khz /= 1000; src->pixel_clk_khz /= 1000;
@@ -5930,6 +6036,10 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
} }
memcpy(dst, src, sizeof(struct dsi_display_mode)); memcpy(dst, src, sizeof(struct dsi_display_mode));
dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i]; dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i];
dsi_display_adjust_mode_timing(dyn_clk_caps, dst, lanes,
bpp);
dst->pixel_clk_khz = dst->pixel_clk_khz =
div_u64(dst->timing.clk_rate_hz * lanes, bpp); div_u64(dst->timing.clk_rate_hz * lanes, bpp);
dst->pixel_clk_khz /= 1000; dst->pixel_clk_khz /= 1000;
@@ -6224,13 +6334,28 @@ int dsi_display_find_mode(struct dsi_display *display,
return rc; return rc;
} }
static inline bool dsi_display_mode_switch_dfps(struct dsi_display_mode *cur,
struct dsi_display_mode *adj)
{
/*
* If there is a change in the hfp or vfp of the current and adjoining
* mode,then either it is a dfps mode switch or dynamic clk change with
* constant fps.
*/
if ((cur->timing.h_front_porch != adj->timing.h_front_porch) ||
(cur->timing.v_front_porch != adj->timing.v_front_porch))
return true;
else
return false;
}
/** /**
* dsi_display_validate_mode_change() - Validate mode change case. * dsi_display_validate_mode_change() - Validate mode change case.
* @display: DSI display handle. * @display: DSI display handle.
* @cur_mode: Current mode. * @cur_mode: Current mode.
* @adj_mode: Mode to be set. * @adj_mode: Mode to be set.
* MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there * MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there
* is change in fps but vactive and hactive are same. * is change in hfp or vfp but vactive and hactive are same.
* DSI_MODE_FLAG_DYN_CLK flag is set if there * DSI_MODE_FLAG_DYN_CLK flag is set if there
* is change in clk but vactive and hactive are same. * is change in clk but vactive and hactive are same.
* Return: error code. * Return: error code.
@@ -6254,14 +6379,15 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
} }
mutex_lock(&display->display_lock); mutex_lock(&display->display_lock);
dyn_clk_caps = &(display->panel->dyn_clk_caps);
if ((cur_mode->timing.v_active == adj_mode->timing.v_active) && if ((cur_mode->timing.v_active == adj_mode->timing.v_active) &&
(cur_mode->timing.h_active == adj_mode->timing.h_active)) { (cur_mode->timing.h_active == adj_mode->timing.h_active) &&
/* dfps change use case */ (cur_mode->panel_mode == adj_mode->panel_mode)) {
if (cur_mode->timing.refresh_rate != /* dfps and dynamic clock with const fps use case */
adj_mode->timing.refresh_rate) { if (dsi_display_mode_switch_dfps(cur_mode, adj_mode)) {
dsi_panel_get_dfps_caps(display->panel, &dfps_caps); dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
if (dfps_caps.dfps_support) { if (dfps_caps.dfps_support ||
dyn_clk_caps->maintain_const_fps) {
DSI_DEBUG("Mode switch is seamless variable refresh\n"); DSI_DEBUG("Mode switch is seamless variable refresh\n");
adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
SDE_EVT32(cur_mode->timing.refresh_rate, SDE_EVT32(cur_mode->timing.refresh_rate,
@@ -6273,10 +6399,11 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
/* dynamic clk change use case */ /* dynamic clk change use case */
if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) { if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) {
dyn_clk_caps = &(display->panel->dyn_clk_caps);
if (dyn_clk_caps->dyn_clk_support) { if (dyn_clk_caps->dyn_clk_support) {
DSI_DEBUG("dynamic clk change detected\n"); DSI_DEBUG("dynamic clk change detected\n");
if (adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) { if ((adj_mode->dsi_mode_flags &
DSI_MODE_FLAG_VRR) &&
(!dyn_clk_caps->maintain_const_fps)) {
DSI_ERR("dfps and dyn clk not supported in same commit\n"); DSI_ERR("dfps and dyn clk not supported in same commit\n");
rc = -ENOTSUPP; rc = -ENOTSUPP;
goto error; goto error;
@@ -6794,12 +6921,14 @@ int dsi_display_prepare(struct dsi_display *display)
goto error; goto error;
} }
/* update dsi ctrl for new mode */ if (!display->is_cont_splash_enabled) {
rc = dsi_display_pre_switch(display); /* update dsi ctrl for new mode */
if (rc) rc = dsi_display_pre_switch(display);
DSI_ERR("[%s] panel pre-prepare-res-switch failed, rc=%d\n", if (rc)
DSI_ERR("[%s] panel pre-switch failed, rc=%d\n",
display->name, rc); display->name, rc);
goto error; goto error;
}
} }
if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) && if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) &&

View File

@@ -253,6 +253,7 @@ static void dsi_bridge_enable(struct drm_bridge *bridge)
static void dsi_bridge_disable(struct drm_bridge *bridge) static void dsi_bridge_disable(struct drm_bridge *bridge)
{ {
int rc = 0; int rc = 0;
int private_flags;
struct dsi_display *display; struct dsi_display *display;
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
@@ -261,18 +262,14 @@ static void dsi_bridge_disable(struct drm_bridge *bridge)
return; return;
} }
display = c_bridge->display; display = c_bridge->display;
private_flags =
bridge->encoder->crtc->state->adjusted_mode.private_flags;
if (display && display->drm_conn) { if (display && display->drm_conn) {
if (bridge->encoder->crtc->state->adjusted_mode.private_flags & display->poms_pending =
MSM_MODE_FLAG_SEAMLESS_POMS) { private_flags & MSM_MODE_FLAG_SEAMLESS_POMS;
display->poms_pending = true;
/* Disable ESD thread, during panel mode switch */ sde_connector_helper_bridge_disable(display->drm_conn);
sde_connector_schedule_status_work(display->drm_conn,
false);
} else {
display->poms_pending = false;
sde_connector_helper_bridge_disable(display->drm_conn);
}
} }
rc = dsi_display_pre_disable(c_bridge->display); rc = dsi_display_pre_disable(c_bridge->display);
@@ -426,6 +423,7 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
/* Reject seamless transition when active changed */ /* Reject seamless transition when active changed */
if (crtc_state->active_changed && if (crtc_state->active_changed &&
((dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) || ((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))) { (dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK))) {
DSI_ERR("seamless upon active changed 0x%x %d\n", DSI_ERR("seamless upon active changed 0x%x %d\n",
dsi_mode.dsi_mode_flags, crtc_state->active_changed); dsi_mode.dsi_mode_flags, crtc_state->active_changed);

View File

@@ -1175,6 +1175,7 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps; struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps;
struct dsi_parser_utils *utils = &panel->utils; struct dsi_parser_utils *utils = &panel->utils;
const char *name = panel->name; const char *name = panel->name;
const char *type;
supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable"); supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable");
@@ -1207,6 +1208,24 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
dyn_clk_caps->dyn_clk_support = true; dyn_clk_caps->dyn_clk_support = true;
type = utils->get_property(utils->data,
"qcom,dsi-dyn-clk-type", NULL);
if (!type) {
dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY;
dyn_clk_caps->maintain_const_fps = false;
return 0;
}
if (!strcmp(type, "constant-fps-adjust-hfp")) {
dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP;
dyn_clk_caps->maintain_const_fps = true;
} else if (!strcmp(type, "constant-fps-adjust-vfp")) {
dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP;
dyn_clk_caps->maintain_const_fps = true;
} else {
dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY;
dyn_clk_caps->maintain_const_fps = false;
}
DSI_DEBUG("Dynamic clock type is [%s]\n", type);
return 0; return 0;
} }
@@ -3704,9 +3723,11 @@ int dsi_panel_get_mode(struct dsi_panel *panel,
if (panel->panel_mode_switch_enabled) { if (panel->panel_mode_switch_enabled) {
rc = dsi_panel_parse_panel_mode_caps(mode, utils); rc = dsi_panel_parse_panel_mode_caps(mode, utils);
if (rc) { if (rc) {
DSI_ERR("PMS: failed to parse panel mode\n");
rc = 0; rc = 0;
mode->panel_mode = panel->panel_mode; mode->panel_mode = panel->panel_mode;
DSI_INFO(
"POMS: panel mode isn't specified in timing[%d]\n",
child_idx);
} }
} else { } else {
mode->panel_mode = panel->panel_mode; mode->panel_mode = panel->panel_mode;

View File

@@ -82,6 +82,8 @@ struct dsi_dyn_clk_caps {
bool dyn_clk_support; bool dyn_clk_support;
u32 *bit_clk_list; u32 *bit_clk_list;
u32 bit_clk_list_len; u32 bit_clk_list_len;
enum dsi_dyn_clk_feature_type type;
bool maintain_const_fps;
}; };
struct dsi_pinctrl_info { struct dsi_pinctrl_info {

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
*/ */
#include <linux/delay.h> #include <linux/delay.h>
@@ -239,15 +239,18 @@ static bool dsi_parser_parse_prop(struct device *dev,
{ {
bool found = false; bool found = false;
char *out = strsep(&buf, "="); char *out = strsep(&buf, "=");
size_t buf_len;
if (!out || !buf) if (!out || !buf)
goto end; goto end;
prop->raw = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); buf_len = strlen(buf);
prop->raw = devm_kzalloc(dev, buf_len + 1, GFP_KERNEL);
if (!prop->raw) if (!prop->raw)
goto end; goto end;
strlcpy(prop->raw, buf, strlen(buf) + 1); strlcpy(prop->raw, buf, buf_len + 1);
found = true; found = true;

View File

@@ -111,6 +111,11 @@ static const struct of_device_id msm_dsi_phy_of_match[] = {
{} {}
}; };
int dsi_phy_get_version(struct msm_dsi_phy *phy)
{
return phy->ver_info->version;
}
static int dsi_phy_regmap_init(struct platform_device *pdev, static int dsi_phy_regmap_init(struct platform_device *pdev,
struct msm_dsi_phy *phy) struct msm_dsi_phy *phy)
{ {

View File

@@ -125,6 +125,14 @@ struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node);
*/ */
void dsi_phy_put(struct msm_dsi_phy *dsi_phy); void dsi_phy_put(struct msm_dsi_phy *dsi_phy);
/**
* dsi_phy_get_version() - returns dsi phy version
* @dsi_phy: DSI PHY handle.
*
* Return: phy version
*/
int dsi_phy_get_version(struct msm_dsi_phy *phy);
/** /**
* dsi_phy_drv_init() - initialize dsi phy driver * dsi_phy_drv_init() - initialize dsi phy driver
* @dsi_phy: DSI PHY handle. * @dsi_phy: DSI PHY handle.

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
*/ */
#include <linux/math64.h> #include <linux/math64.h>
@@ -64,6 +64,83 @@
#define DSIPHY_PLL_CLKBUFLR_EN 0x041C #define DSIPHY_PLL_CLKBUFLR_EN 0x041C
#define DSIPHY_PLL_PLL_BANDGAP 0x0508 #define DSIPHY_PLL_PLL_BANDGAP 0x0508
/* 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
#define DSIPHY_DLN0_CFG1 0x0104
#define DSIPHY_DLN0_TIMING_CTRL_4 0x0118
#define DSIPHY_DLN0_TIMING_CTRL_5 0x011C
#define DSIPHY_DLN0_TIMING_CTRL_6 0x0120
#define DSIPHY_DLN0_TIMING_CTRL_7 0x0124
#define DSIPHY_DLN0_TIMING_CTRL_8 0x0128
#define DSIPHY_DLN1_CFG1 0x0184
#define DSIPHY_DLN1_TIMING_CTRL_4 0x0198
#define DSIPHY_DLN1_TIMING_CTRL_5 0x019C
#define DSIPHY_DLN1_TIMING_CTRL_6 0x01A0
#define DSIPHY_DLN1_TIMING_CTRL_7 0x01A4
#define DSIPHY_DLN1_TIMING_CTRL_8 0x01A8
#define DSIPHY_DLN2_CFG1 0x0204
#define DSIPHY_DLN2_TIMING_CTRL_4 0x0218
#define DSIPHY_DLN2_TIMING_CTRL_5 0x021C
#define DSIPHY_DLN2_TIMING_CTRL_6 0x0220
#define DSIPHY_DLN2_TIMING_CTRL_7 0x0224
#define DSIPHY_DLN2_TIMING_CTRL_8 0x0228
#define DSIPHY_DLN3_CFG1 0x0284
#define DSIPHY_DLN3_TIMING_CTRL_4 0x0298
#define DSIPHY_DLN3_TIMING_CTRL_5 0x029C
#define DSIPHY_DLN3_TIMING_CTRL_6 0x02A0
#define DSIPHY_DLN3_TIMING_CTRL_7 0x02A4
#define DSIPHY_DLN3_TIMING_CTRL_8 0x02A8
#define DSIPHY_CKLN_CFG1 0x0304
#define DSIPHY_CKLN_TIMING_CTRL_4 0x0318
#define DSIPHY_CKLN_TIMING_CTRL_5 0x031C
#define DSIPHY_CKLN_TIMING_CTRL_6 0x0320
#define DSIPHY_CKLN_TIMING_CTRL_7 0x0324
#define DSIPHY_CKLN_TIMING_CTRL_8 0x0328
#define DSIPHY_PLL_RESETSM_CNTRL5 0x043c
/** /**
* regulator_enable() - enable regulators for DSI PHY * regulator_enable() - enable regulators for DSI PHY
* @phy: Pointer to DSI PHY hardware object. * @phy: Pointer to DSI PHY hardware object.
@@ -299,3 +376,261 @@ void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable)
DSI_PHY_DBG(phy, "clamp disabled\n"); DSI_PHY_DBG(phy, "clamp disabled\n");
} }
} }
void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy,
struct dsi_phy_cfg *cfg, bool is_master)
{
u32 glbl_tst_cntrl;
if (is_master) {
glbl_tst_cntrl = DSI_R32(phy, DSIPHY_CMN_GLBL_TEST_CTRL);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0,
DSIPHY_CMN_GLBL_TEST_CTRL,
DSIPHY_PLL_PLL_BANDGAP,
glbl_tst_cntrl | BIT(1), 0x1);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1,
DSIPHY_PLL_RESETSM_CNTRL5,
DSIPHY_PLL_PLL_BANDGAP, 0x0D, 0x03);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2,
DSIPHY_PLL_RESETSM_CNTRL5,
DSIPHY_CMN_PLL_CNTRL, 0x1D, 0x00);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3,
DSIPHY_CMN_CTRL_1, DSIPHY_DLN0_CFG1, 0x20, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4,
DSIPHY_DLN1_CFG1, DSIPHY_DLN2_CFG1, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5,
DSIPHY_DLN3_CFG1, DSIPHY_CKLN_CFG1, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6,
DSIPHY_DLN0_TIMING_CTRL_4,
DSIPHY_DLN1_TIMING_CTRL_4,
cfg->timing.lane[0][0], cfg->timing.lane[1][0]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7,
DSIPHY_DLN2_TIMING_CTRL_4,
DSIPHY_DLN3_TIMING_CTRL_4,
cfg->timing.lane[2][0], cfg->timing.lane[3][0]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8,
DSIPHY_CKLN_TIMING_CTRL_4,
DSIPHY_DLN0_TIMING_CTRL_5,
cfg->timing.lane[4][0], cfg->timing.lane[0][1]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9,
DSIPHY_DLN1_TIMING_CTRL_5,
DSIPHY_DLN2_TIMING_CTRL_5,
cfg->timing.lane[1][1], cfg->timing.lane[2][1]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10,
DSIPHY_DLN3_TIMING_CTRL_5,
DSIPHY_CKLN_TIMING_CTRL_5,
cfg->timing.lane[3][1], cfg->timing.lane[4][1]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11,
DSIPHY_DLN0_TIMING_CTRL_6,
DSIPHY_DLN1_TIMING_CTRL_6,
cfg->timing.lane[0][2], cfg->timing.lane[1][2]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12,
DSIPHY_DLN2_TIMING_CTRL_6,
DSIPHY_DLN3_TIMING_CTRL_6,
cfg->timing.lane[2][2], cfg->timing.lane[3][2]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13,
DSIPHY_CKLN_TIMING_CTRL_6,
DSIPHY_DLN0_TIMING_CTRL_7,
cfg->timing.lane[4][2], cfg->timing.lane[0][3]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14,
DSIPHY_DLN1_TIMING_CTRL_7,
DSIPHY_DLN2_TIMING_CTRL_7,
cfg->timing.lane[1][3], cfg->timing.lane[2][3]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15,
DSIPHY_DLN3_TIMING_CTRL_7,
DSIPHY_CKLN_TIMING_CTRL_7,
cfg->timing.lane[3][3], cfg->timing.lane[4][3]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base,
DSI_DYN_REFRESH_PLL_CTRL16,
DSIPHY_DLN0_TIMING_CTRL_8,
DSIPHY_DLN1_TIMING_CTRL_8,
cfg->timing.lane[0][4], cfg->timing.lane[1][4]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL17,
DSIPHY_DLN2_TIMING_CTRL_8,
DSIPHY_DLN3_TIMING_CTRL_8,
cfg->timing.lane[2][4], cfg->timing.lane[3][4]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL18,
DSIPHY_CKLN_TIMING_CTRL_8, DSIPHY_CMN_CTRL_1,
cfg->timing.lane[4][4], 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL30,
DSIPHY_CMN_GLBL_TEST_CTRL,
DSIPHY_CMN_GLBL_TEST_CTRL,
((glbl_tst_cntrl) & (~BIT(2))),
((glbl_tst_cntrl) & (~BIT(2))));
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL31,
DSIPHY_CMN_GLBL_TEST_CTRL,
DSIPHY_CMN_GLBL_TEST_CTRL,
((glbl_tst_cntrl) & (~BIT(2))),
((glbl_tst_cntrl) & (~BIT(2))));
} else {
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0,
DSIPHY_DLN0_CFG1, DSIPHY_DLN1_CFG1, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1,
DSIPHY_DLN2_CFG1, DSIPHY_DLN3_CFG1, 0x0, 0x0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2,
DSIPHY_CKLN_CFG1, DSIPHY_DLN0_TIMING_CTRL_4,
0x0, cfg->timing.lane[0][0]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3,
DSIPHY_DLN1_TIMING_CTRL_4,
DSIPHY_DLN2_TIMING_CTRL_4,
cfg->timing.lane[1][0], cfg->timing.lane[2][0]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4,
DSIPHY_DLN3_TIMING_CTRL_4,
DSIPHY_CKLN_TIMING_CTRL_4,
cfg->timing.lane[3][0], cfg->timing.lane[4][0]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5,
DSIPHY_DLN0_TIMING_CTRL_5,
DSIPHY_DLN1_TIMING_CTRL_5,
cfg->timing.lane[0][1], cfg->timing.lane[1][1]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6,
DSIPHY_DLN2_TIMING_CTRL_5,
DSIPHY_DLN3_TIMING_CTRL_5,
cfg->timing.lane[2][1], cfg->timing.lane[3][1]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7,
DSIPHY_CKLN_TIMING_CTRL_5,
DSIPHY_DLN0_TIMING_CTRL_6,
cfg->timing.lane[4][1], cfg->timing.lane[0][2]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8,
DSIPHY_DLN1_TIMING_CTRL_6,
DSIPHY_DLN2_TIMING_CTRL_6,
cfg->timing.lane[1][2], cfg->timing.lane[2][2]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9,
DSIPHY_DLN3_TIMING_CTRL_6,
DSIPHY_CKLN_TIMING_CTRL_6,
cfg->timing.lane[3][2], cfg->timing.lane[4][2]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10,
DSIPHY_DLN0_TIMING_CTRL_7,
DSIPHY_DLN1_TIMING_CTRL_7,
cfg->timing.lane[0][3], cfg->timing.lane[1][3]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11,
DSIPHY_DLN2_TIMING_CTRL_7,
DSIPHY_DLN3_TIMING_CTRL_7,
cfg->timing.lane[2][3], cfg->timing.lane[3][3]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12,
DSIPHY_CKLN_TIMING_CTRL_7,
DSIPHY_DLN0_TIMING_CTRL_8,
cfg->timing.lane[4][3], cfg->timing.lane[0][4]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13,
DSIPHY_DLN1_TIMING_CTRL_8,
DSIPHY_DLN2_TIMING_CTRL_8,
cfg->timing.lane[1][4], cfg->timing.lane[2][4]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14,
DSIPHY_DLN3_TIMING_CTRL_8,
DSIPHY_CKLN_TIMING_CTRL_8,
cfg->timing.lane[3][4], cfg->timing.lane[4][4]);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL16,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL17,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL18,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL19,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL20,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL21,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL22,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL23,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL24,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL25,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL26,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL27,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL28,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL29,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL30,
0x0110, 0x0110, 0, 0);
DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL31,
0x0110, 0x0110, 0, 0);
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR,
0x0);
DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR2,
0x0);
}
wmb(); /* make sure phy timings are updated*/
}
void dsi_phy_hw_v2_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_v2_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_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_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
u32 *dst, u32 size)
{
int i, j, count = 0;
if (!timings || !dst || !size)
return -EINVAL;
if (size != (DSI_LANE_MAX * DSI_MAX_SETTINGS)) {
pr_err("size mis-match\n");
return -EINVAL;
}
for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
for (j = 0; j < DSI_MAX_SETTINGS; j++) {
dst[count] = timings->lane[i][j];
count++;
}
}
return 0;
}

View File

@@ -94,8 +94,7 @@ static int sde_backlight_device_update_status(struct backlight_device *bd)
if (!bl_lvl && brightness) if (!bl_lvl && brightness)
bl_lvl = 1; bl_lvl = 1;
if (display->panel->bl_config.bl_update == if (!c_conn->allow_bl_update) {
BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && !c_conn->allow_bl_update) {
c_conn->unset_bl_level = bl_lvl; c_conn->unset_bl_level = bl_lvl;
return 0; return 0;
} }
@@ -532,9 +531,7 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn)
bl_config = &dsi_display->panel->bl_config; bl_config = &dsi_display->panel->bl_config;
if (dsi_display->panel->bl_config.bl_update == if (!c_conn->allow_bl_update) {
BL_UPDATE_DELAY_UNTIL_FIRST_FRAME &&
!c_conn->allow_bl_update) {
c_conn->unset_bl_level = bl_config->bl_level; c_conn->unset_bl_level = bl_config->bl_level;
return 0; return 0;
} }
@@ -797,21 +794,29 @@ void sde_connector_helper_bridge_disable(struct drm_connector *connector)
{ {
int rc; int rc;
struct sde_connector *c_conn = NULL; struct sde_connector *c_conn = NULL;
struct dsi_display *display;
bool poms_pending = false;
if (!connector) if (!connector)
return; return;
rc = _sde_connector_update_dirty_properties(connector); c_conn = to_sde_connector(connector);
if (rc) { if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) {
SDE_ERROR("conn %d final pre kickoff failed %d\n", display = (struct dsi_display *) c_conn->display;
connector->base.id, rc); poms_pending = display->poms_pending;
SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR);
} }
if (!poms_pending) {
rc = _sde_connector_update_dirty_properties(connector);
if (rc) {
SDE_ERROR("conn %d final pre kickoff failed %d\n",
connector->base.id, rc);
SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR);
}
}
/* Disable ESD thread */ /* Disable ESD thread */
sde_connector_schedule_status_work(connector, false); sde_connector_schedule_status_work(connector, false);
c_conn = to_sde_connector(connector);
if (c_conn->bl_device) { if (c_conn->bl_device) {
c_conn->bl_device->props.power = FB_BLANK_POWERDOWN; c_conn->bl_device->props.power = FB_BLANK_POWERDOWN;
c_conn->bl_device->props.state |= BL_CORE_FBBLANK; c_conn->bl_device->props.state |= BL_CORE_FBBLANK;
@@ -2167,6 +2172,7 @@ static void sde_connector_check_status_work(struct work_struct *work)
{ {
struct sde_connector *conn; struct sde_connector *conn;
int rc = 0; int rc = 0;
struct device *dev;
conn = container_of(to_delayed_work(work), conn = container_of(to_delayed_work(work),
struct sde_connector, status_work); struct sde_connector, status_work);
@@ -2176,7 +2182,9 @@ static void sde_connector_check_status_work(struct work_struct *work)
} }
mutex_lock(&conn->lock); mutex_lock(&conn->lock);
if (!conn->ops.check_status || dev = conn->base.dev->dev;
if (!conn->ops.check_status || dev->power.is_suspended ||
(conn->dpms_mode != DRM_MODE_DPMS_ON)) { (conn->dpms_mode != DRM_MODE_DPMS_ON)) {
SDE_DEBUG("dpms mode: %d\n", conn->dpms_mode); SDE_DEBUG("dpms mode: %d\n", conn->dpms_mode);
mutex_unlock(&conn->lock); mutex_unlock(&conn->lock);