Merge "disp: msm: dsi: disallow backlight update during panel mode switch"
This commit is contained in:

committed by
Gerrit - the friendly Code Review server

commit
34b32d77f8
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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,
|
||||||
|
@@ -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
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -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) &&
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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;
|
||||||
|
|
||||||
|
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -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.
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user