drm/msm/dsi-staging: implement dynamic DSI clock
Dynamic DSI clock setting is implemented by re-calculating
DSI link clocks from DSI bitrate in sysfs interface and
re-enaling the clock with new bitrate while there is no
DSI data transferring.
Currently, the feature is only supported in DSI command
mode.
CRs-Fixed: 2177917
Change-Id: I1192e1980726ad632b619e0fe13034f79c169afa
Signed-off-by: Yujun Zhang <yujunzhang@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index f2c2985..00b8086 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -67,6 +67,8 @@
ctrl->ops.error_intr_ctrl = dsi_ctrl_hw_cmn_error_intr_ctrl;
ctrl->ops.get_error_mask = dsi_ctrl_hw_cmn_get_error_mask;
ctrl->ops.get_hw_version = dsi_ctrl_hw_cmn_get_hw_version;
+ ctrl->ops.wait_for_cmd_mode_mdp_idle =
+ dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle;
switch (version) {
case DSI_CTRL_VERSION_1_4:
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index f7756dc..09f1152 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -186,6 +186,7 @@
void dsi_ctrl_hw_cmn_error_intr_ctrl(struct dsi_ctrl_hw *ctrl, bool en);
u32 dsi_ctrl_hw_cmn_get_error_mask(struct dsi_ctrl_hw *ctrl);
u32 dsi_ctrl_hw_cmn_get_hw_version(struct dsi_ctrl_hw *ctrl);
+int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl);
/* Definitions specific to 1.4 DSI controller hardware */
int dsi_ctrl_hw_14_wait_for_lane_idle(struct dsi_ctrl_hw *ctrl, u32 lanes);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
index fa80317..d89760e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
@@ -232,6 +232,15 @@
int dsi_deregister_clk_handle(void *client);
/**
+ * dsi_display_link_clk_force_update_ctrl() - force to set link clks
+ * @handle: Handle of desired DSI clock client.
+ *
+ * return: error code in case of failure or 0 for success.
+ */
+
+int dsi_display_link_clk_force_update_ctrl(void *handle);
+
+/**
* dsi_display_clk_ctrl() - set frequencies for link clks
* @handle: Handle of desired DSI clock client.
* @clk_type: Clock which is being controlled.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index bff8627..189a5c3 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -1071,6 +1071,76 @@
DEFINE_MUTEX(dsi_mngr_clk_mutex);
+static int dsi_display_link_clk_force_update(void *client)
+{
+ int rc = 0;
+ struct dsi_clk_client_info *c = client;
+ struct dsi_clk_mngr *mngr;
+ struct dsi_link_clks *l_clks;
+
+ if (!client) {
+ pr_err("%s: Invalid arg\n", __func__);
+ return -EINVAL;
+ }
+ mngr = c->mngr;
+
+ mutex_lock(&mngr->clk_mutex);
+
+ l_clks = mngr->link_clks;
+
+ /*
+ * When link_clk_state is DSI_CLK_OFF, don't change DSI clock rate
+ * since it is possible to be overwritten, and return -EAGAIN to
+ * dynamic DSI writing interface to defer the reenabling to the next
+ * drm commit.
+ */
+ if (mngr->link_clk_state == DSI_CLK_OFF) {
+ rc = -EAGAIN;
+ goto error;
+ }
+
+ rc = dsi_display_link_clk_disable(l_clks,
+ mngr->dsi_ctrl_count, mngr->master_ndx);
+ if (rc) {
+ pr_err("%s, failed to stop link clk, rc = %d\n",
+ __func__, rc);
+ goto error;
+ }
+
+ rc = dsi_display_link_clk_enable(l_clks,
+ mngr->dsi_ctrl_count, mngr->master_ndx);
+ if (rc) {
+ pr_err("%s, failed to start link clk rc= %d\n",
+ __func__, rc);
+ goto error;
+ }
+
+error:
+ mutex_unlock(&mngr->clk_mutex);
+ return rc;
+
+}
+
+int dsi_display_link_clk_force_update_ctrl(void *handle)
+{
+ int rc = 0;
+
+ if (!handle) {
+ pr_err("%s: Invalid arg\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&dsi_mngr_clk_mutex);
+
+ rc = dsi_display_link_clk_force_update(handle);
+ if (rc && (rc != -EAGAIN))
+ pr_err("%s: failed set clk state, rc = %d\n", __func__, rc);
+
+ mutex_unlock(&dsi_mngr_clk_mutex);
+
+ return rc;
+}
+
int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state)
{
int rc = 0;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 5b8c910..c9e8a01 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -915,6 +915,27 @@
return rc;
}
+int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl)
+{
+ int rc = 0;
+
+ if (!dsi_ctrl) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (dsi_ctrl->host_config.panel_mode != DSI_OP_CMD_MODE)
+ return -EINVAL;
+
+ mutex_lock(&dsi_ctrl->ctrl_lock);
+
+ rc = dsi_ctrl->hw.ops.wait_for_cmd_mode_mdp_idle(&dsi_ctrl->hw);
+
+ mutex_unlock(&dsi_ctrl->ctrl_lock);
+
+ return rc;
+}
+
static void dsi_ctrl_wait_for_video_done(struct dsi_ctrl *dsi_ctrl)
{
u32 v_total = 0, v_blank = 0, sleep_ms = 0, fps = 0, ret;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index ed3d0eb..4f85cda 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -748,4 +748,11 @@
*/
int dsi_ctrl_update_host_init_state(struct dsi_ctrl *dsi_ctrl, bool en);
+/**
+ * dsi_ctrl_wait_for_cmd_mode_mdp_idle() - Wait for command mode engine not to
+ * be busy sending data from display engine.
+ * @dsi_ctrl: DSI controller handle.
+ */
+int dsi_ctrl_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl *dsi_ctrl);
+
#endif /* _DSI_CTRL_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 567f289..d6fab59 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -798,6 +798,13 @@
* @ctrl: Pointer to the controller host hardware.
*/
u32 (*get_hw_version)(struct dsi_ctrl_hw *ctrl);
+
+ /**
+ * wait_for_cmd_mode_mdp_idle() - wait for command mode engine not to
+ * be busy sending data from display engine
+ * @ctrl: Pointer to the controller host hardware.
+ */
+ int (*wait_for_cmd_mode_mdp_idle)(struct dsi_ctrl_hw *ctrl);
};
/*
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
index 594b3f5..f0e7ba6 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw_cmn.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1476,3 +1476,18 @@
return reg;
}
+
+int dsi_ctrl_hw_cmn_wait_for_cmd_mode_mdp_idle(struct dsi_ctrl_hw *ctrl)
+{
+ int rc = 0, val = 0;
+ u32 cmd_mode_mdp_busy_mask = BIT(2);
+ u32 const sleep_us = 2 * 1000;
+ u32 const timeout_us = 200 * 1000;
+
+ rc = readl_poll_timeout(ctrl->base + DSI_STATUS, val,
+ !(val & cmd_mode_mdp_busy_mask), sleep_us, timeout_us);
+ if (rc)
+ pr_err("%s: waiting failed, ret=%d\n", __func__, rc);
+
+ return rc;
+}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 1682e61..8246488 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -41,6 +41,8 @@
#define MAX_NAME_SIZE 64
+#define DSI_CLOCK_BITRATE_RADIX 10
+
static DEFINE_MUTEX(dsi_display_list_lock);
static LIST_HEAD(dsi_display_list);
static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
@@ -4036,6 +4038,246 @@
return rc;
}
+static int dsi_display_force_update_dsi_clk(struct dsi_display *display)
+{
+ int rc = 0;
+
+ if (!display || !display->panel) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ rc = dsi_display_link_clk_force_update_ctrl(display->dsi_clk_handle);
+
+ if (!rc) {
+ pr_info("dsi bit clk has been configured to %d\n",
+ display->cached_clk_rate);
+
+ atomic_set(&display->clkrate_change_pending, 0);
+ } else if (rc == -EAGAIN) {
+ pr_info("Clock is disabled, update it next time\n");
+ } else {
+ pr_err("Failed to configure dsi bit clock '%d'. rc = %d\n",
+ display->cached_clk_rate, rc);
+ }
+
+ return rc;
+}
+
+static int dsi_display_request_update_dsi_bitrate(struct dsi_display *display,
+ u32 bit_clk_rate)
+{
+ int rc = 0;
+ int i;
+
+ pr_debug("%s:bit rate:%d\n", __func__, bit_clk_rate);
+ if (!display || !display->panel) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ if (bit_clk_rate == 0) {
+ pr_err("Invalid bit clock rate\n");
+ return -EINVAL;
+ }
+
+ display->config.bit_clk_rate_hz = bit_clk_rate;
+
+ for (i = 0; i < display->ctrl_count; i++) {
+ struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i];
+ struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl;
+ u32 num_of_lanes = 0;
+ u32 bpp = 3;
+ u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate;
+ struct dsi_host_common_cfg *host_cfg;
+
+ mutex_lock(&ctrl->ctrl_lock);
+
+ host_cfg = &display->panel->host_config;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_0)
+ num_of_lanes++;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_1)
+ num_of_lanes++;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_2)
+ num_of_lanes++;
+ if (host_cfg->data_lanes & DSI_DATA_LANE_3)
+ num_of_lanes++;
+
+ if (num_of_lanes == 0) {
+ pr_err("Invalid lane count\n");
+ rc = -EINVAL;
+ goto error;
+ }
+
+ bit_rate = display->config.bit_clk_rate_hz * num_of_lanes;
+ bit_rate_per_lane = bit_rate;
+ do_div(bit_rate_per_lane, num_of_lanes);
+ pclk_rate = bit_rate;
+ do_div(pclk_rate, (8 * bpp));
+ byte_clk_rate = bit_rate_per_lane;
+ do_div(byte_clk_rate, 8);
+ pr_debug("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
+ bit_rate, bit_rate_per_lane);
+ pr_debug("byte_clk_rate = %llu, pclk_rate = %llu\n",
+ byte_clk_rate, pclk_rate);
+
+ ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
+ ctrl->clk_freq.pix_clk_rate = pclk_rate;
+ rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle,
+ ctrl->clk_freq, ctrl->cell_index);
+ if (rc) {
+ pr_err("Failed to update link frequencies\n");
+ goto error;
+ }
+
+ ctrl->host_config.bit_clk_rate_hz = bit_clk_rate;
+error:
+ mutex_unlock(&ctrl->ctrl_lock);
+
+ /* TODO: recover ctrl->clk_freq in case of failure */
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static ssize_t sysfs_dynamic_dsi_clk_read(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int rc = 0;
+ struct dsi_display *display;
+ struct dsi_display_ctrl *m_ctrl;
+ struct dsi_ctrl *ctrl;
+
+ if (!dev) {
+ pr_err("Invalid device\n");
+ return -EINVAL;
+ }
+
+ display = dev_get_drvdata(dev);
+ if (!display) {
+ pr_err("Invalid display\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&display->display_lock);
+
+ m_ctrl = &display->ctrl[display->cmd_master_idx];
+ ctrl = m_ctrl->ctrl;
+ if (ctrl)
+ display->cached_clk_rate = ctrl->clk_freq.
+ byte_clk_rate * 8;
+
+ rc = snprintf(buf, PAGE_SIZE, "%d\n", display->cached_clk_rate);
+ pr_info("%s: read dsi clk rate %d\n", __func__,
+ display->cached_clk_rate);
+
+ mutex_unlock(&display->display_lock);
+
+ return rc;
+}
+
+static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int rc = 0;
+ int clk_rate;
+ struct dsi_display *display;
+
+ if (!dev) {
+ pr_err("Invalid device\n");
+ return -EINVAL;
+ }
+
+ display = dev_get_drvdata(dev);
+ if (!display) {
+ pr_err("Invalid display\n");
+ return -EINVAL;
+ }
+
+ rc = kstrtoint(buf, DSI_CLOCK_BITRATE_RADIX, &clk_rate);
+ if (rc) {
+ pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
+ return rc;
+ }
+
+ if (clk_rate <= 0) {
+ pr_err("%s: bitrate should be greater than 0\n", __func__);
+ return -EINVAL;
+ }
+
+ if (clk_rate == display->cached_clk_rate) {
+ pr_info("%s: ignore duplicated DSI clk setting\n", __func__);
+ return count;
+ }
+
+ pr_info("%s: bitrate param value: '%d'\n", __func__, clk_rate);
+
+ mutex_lock(&display->display_lock);
+
+ display->cached_clk_rate = clk_rate;
+ rc = dsi_display_request_update_dsi_bitrate(display, clk_rate);
+ if (!rc) {
+ pr_info("%s: bit clk is ready to be configured to '%d'\n",
+ __func__, clk_rate);
+ } else {
+ pr_err("%s: Failed to prepare to configure '%d'. rc = %d\n",
+ __func__, clk_rate, rc);
+ /*Caching clock failed, so don't go on doing so.*/
+ atomic_set(&display->clkrate_change_pending, 0);
+ display->cached_clk_rate = 0;
+
+ mutex_unlock(&display->display_lock);
+
+ return rc;
+ }
+ atomic_set(&display->clkrate_change_pending, 1);
+
+ mutex_unlock(&display->display_lock);
+
+ return count;
+
+}
+
+static DEVICE_ATTR(dynamic_dsi_clock, 0644,
+ sysfs_dynamic_dsi_clk_read,
+ sysfs_dynamic_dsi_clk_write);
+
+static struct attribute *dynamic_dsi_clock_fs_attrs[] = {
+ &dev_attr_dynamic_dsi_clock.attr,
+ NULL,
+};
+static struct attribute_group dynamic_dsi_clock_fs_attrs_group = {
+ .attrs = dynamic_dsi_clock_fs_attrs,
+};
+
+static int dsi_display_sysfs_init(struct dsi_display *display)
+{
+ int rc = 0;
+ struct device *dev = &display->pdev->dev;
+
+ if (display->panel->panel_mode == DSI_OP_CMD_MODE)
+ rc = sysfs_create_group(&dev->kobj,
+ &dynamic_dsi_clock_fs_attrs_group);
+ pr_debug("[%s] dsi_display_sysfs_init:%d,panel mode:%d\n",
+ display->name, rc, display->panel->panel_mode);
+ return rc;
+
+}
+
+static int dsi_display_sysfs_deinit(struct dsi_display *display)
+{
+ struct device *dev = &display->pdev->dev;
+
+ if (display->panel->panel_mode == DSI_OP_CMD_MODE)
+ sysfs_remove_group(&dev->kobj,
+ &dynamic_dsi_clock_fs_attrs_group);
+
+ return 0;
+
+}
+
/**
* dsi_display_bind - bind dsi device with controlling device
* @dev: Pointer to base of platform device
@@ -4083,6 +4325,15 @@
goto error;
}
+ atomic_set(&display->clkrate_change_pending, 0);
+ display->cached_clk_rate = 0;
+
+ rc = dsi_display_sysfs_init(display);
+ if (rc) {
+ pr_err("[%s] sysfs init failed, rc=%d\n", display->name, rc);
+ goto error;
+ }
+
memset(&info, 0x0, sizeof(info));
for (i = 0; i < display->ctrl_count; i++) {
@@ -4237,6 +4488,7 @@
(void)dsi_phy_drv_deinit(display_ctrl->phy);
(void)dsi_ctrl_drv_deinit(display_ctrl->ctrl);
}
+ (void)dsi_display_sysfs_deinit(display);
(void)dsi_display_debugfs_deinit(display);
error:
mutex_unlock(&display->display_lock);
@@ -4294,6 +4546,9 @@
pr_err("[%s] failed to deinit ctrl%d driver, rc=%d\n",
display->name, i, rc);
}
+
+ atomic_set(&display->clkrate_change_pending, 0);
+ (void)dsi_display_sysfs_deinit(display);
(void)dsi_display_debugfs_deinit(display);
mutex_unlock(&display->display_lock);
@@ -5114,6 +5369,10 @@
adj_mode = *mode;
adjust_timing_by_ctrl_count(display, &adj_mode);
+ /*For dynamic DSI setting, use specified clock rate */
+ if (display->cached_clk_rate > 0)
+ adj_mode.priv_info->clk_rate_hz = display->cached_clk_rate;
+
rc = dsi_display_validate_mode_set(display, &adj_mode, flags);
if (rc) {
pr_err("[%s] mode cannot be set\n", display->name);
@@ -5710,6 +5969,7 @@
struct msm_display_kickoff_params *params)
{
int rc = 0;
+ int i;
/* check and setup MISR */
if (display->misr_enable)
@@ -5717,6 +5977,44 @@
rc = dsi_display_set_roi(display, params->rois);
+ /* dynamic DSI clock setting */
+ if (atomic_read(&display->clkrate_change_pending)) {
+ mutex_lock(&display->display_lock);
+ /*
+ * acquire panel_lock to make sure no commands are in progress
+ */
+ dsi_panel_acquire_panel_lock(display->panel);
+
+ /*
+ * Wait for DSI command engine not to be busy sending data
+ * from display engine.
+ * If waiting fails, return "rc" instead of below "ret" so as
+ * not to impact DRM commit. The clock updating would be
+ * deferred to the next DRM commit.
+ */
+ for (i = 0; i < display->ctrl_count; i++) {
+ struct dsi_ctrl *ctrl = display->ctrl[i].ctrl;
+ int ret = 0;
+
+ ret = dsi_ctrl_wait_for_cmd_mode_mdp_idle(ctrl);
+ if (ret) {
+ pr_info("Failed to wait for cmd engine not to be busy sending data from MDP, rc: %d\n",
+ ret);
+ goto wait_failure;
+ }
+ }
+
+ /*
+ * Don't check the return value so as not to impact DRM commit
+ * when error occurs.
+ */
+ (void)dsi_display_force_update_dsi_clk(display);
+wait_failure:
+ /* release panel_lock */
+ dsi_panel_release_panel_lock(display->panel);
+ mutex_unlock(&display->display_lock);
+ }
+
return rc;
}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index bb6c8c6..8564dcf 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -145,6 +145,8 @@
* index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array.
* @cmd_master_idx: The master controller for sending DSI commands to panel.
* @video_master_idx: The master controller for enabling video engine.
+ * @cached_clk_rate: The cached DSI clock rate set dynamically by sysfs.
+ * @clkrate_change_pending: Flag indicating the pending DSI clock re-enabling.
* @clock_info: Clock sourcing for DSI display.
* @config: DSI host configuration information.
* @lane_map: Lane mapping between DSI host and Panel.
@@ -194,6 +196,10 @@
u32 cmd_master_idx;
u32 video_master_idx;
+ /* dynamic DSI clock info*/
+ u32 cached_clk_rate;
+ atomic_t clkrate_change_pending;
+
struct dsi_display_clk_info clock_info;
struct dsi_host_config config;
struct dsi_lane_map lane_map;