summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlucaswei <lucaswei@google.com>2020-06-01 16:12:30 +0800
committerlucaswei <lucaswei@google.com>2020-06-10 22:44:15 +0800
commit80a1e953b1823fe4b694e8751769edda1faa969f (patch)
treef1347b758b94e97076d4fe119981d38a1fc560b3
parenta0bd65d5eafce0c91b3d6be4018ae99cafa4bc25 (diff)
parentd5a91a3fc5c8deaea89235f2cd634935c94bc13b (diff)
downloaddisplay-drivers-80a1e953b1823fe4b694e8751769edda1faa969f.tar.gz
Merge LA.UM.9.12.R2.10.00.00.685.011 via branch 'qcom-msm-4.19-7250' into android-msm-pixel-4.19
Conflicts: msm/sde/sde_kms.h Bug: 157858241 Signed-off-by: lucaswei <lucaswei@google.com> Change-Id: I6be76a3df370fe0b20184922bd35bacad47c901b
-rw-r--r--msm/dp/dp_debug.c8
-rw-r--r--msm/dp/dp_mst_drm.c306
-rw-r--r--msm/dsi/dsi_defs.h2
-rw-r--r--msm/dsi/dsi_display.c47
-rw-r--r--msm/dsi/dsi_drm.c10
-rw-r--r--msm/dsi/dsi_drm.h4
-rw-r--r--msm/msm_drv.c7
-rw-r--r--msm/sde/sde_encoder.c7
-rw-r--r--msm/sde/sde_kms.c61
-rw-r--r--msm/sde/sde_kms.h10
-rw-r--r--pll/dsi_pll_8996_util.c6
11 files changed, 299 insertions, 169 deletions
diff --git a/msm/dp/dp_debug.c b/msm/dp/dp_debug.c
index d8619dfb..0459adce 100644
--- a/msm/dp/dp_debug.c
+++ b/msm/dp/dp_debug.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/debugfs.h>
@@ -1912,6 +1912,12 @@ static int dp_debug_init(struct dp_debug *dp_debug)
struct dp_debug_private, dp_debug);
struct dentry *dir, *file;
+ if (!IS_ENABLED(CONFIG_DEBUG_FS)) {
+ DP_WARN("Not creating debug root dir.");
+ debug->root = NULL;
+ return 0;
+ }
+
dir = debugfs_create_dir(DEBUG_NAME, NULL);
if (IS_ERR_OR_NULL(dir)) {
if (!dir)
diff --git a/msm/dp/dp_mst_drm.c b/msm/dp/dp_mst_drm.c
index 18118310..508e1034 100644
--- a/msm/dp/dp_mst_drm.c
+++ b/msm/dp/dp_mst_drm.c
@@ -1,6 +1,6 @@
// 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.
*/
/*
@@ -110,20 +110,18 @@ struct dp_mst_sim_mode {
struct dp_mst_bridge {
struct drm_bridge base;
+ struct drm_private_obj obj;
u32 id;
bool in_use;
struct dp_display *display;
struct drm_encoder *encoder;
- bool encoder_active_sts;
struct drm_display_mode drm_mode;
struct dp_display_mode dp_mode;
struct drm_connector *connector;
- struct drm_connector *old_connector;
void *dp_panel;
- void *old_dp_panel;
int vcpi;
int pbn;
@@ -135,6 +133,13 @@ struct dp_mst_bridge {
struct drm_connector *fixed_connector;
};
+struct dp_mst_bridge_state {
+ struct drm_private_state base;
+ struct drm_connector *connector;
+ void *dp_panel;
+ int num_slots;
+};
+
struct dp_mst_private {
bool mst_initialized;
struct dp_mst_caps caps;
@@ -154,10 +159,55 @@ struct dp_mst_encoder_info_cache {
};
#define to_dp_mst_bridge(x) container_of((x), struct dp_mst_bridge, base)
+#define to_dp_mst_bridge_priv(x) \
+ container_of((x), struct dp_mst_bridge, obj)
+#define to_dp_mst_bridge_priv_state(x) \
+ container_of((x), struct dp_mst_bridge_state, base)
+#define to_dp_mst_bridge_state(x) \
+ to_dp_mst_bridge_priv_state((x)->obj.state)
struct dp_mst_private dp_mst;
struct dp_mst_encoder_info_cache dp_mst_enc_cache;
+static struct drm_private_state *dp_mst_duplicate_bridge_state(
+ struct drm_private_obj *obj)
+{
+ struct dp_mst_bridge_state *state;
+
+ state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
+
+ return &state->base;
+}
+
+static void dp_mst_destroy_bridge_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
+{
+ struct dp_mst_bridge_state *priv_state =
+ to_dp_mst_bridge_priv_state(state);
+
+ kfree(priv_state);
+}
+
+static const struct drm_private_state_funcs dp_mst_bridge_state_funcs = {
+ .atomic_duplicate_state = dp_mst_duplicate_bridge_state,
+ .atomic_destroy_state = dp_mst_destroy_bridge_state,
+};
+
+static struct dp_mst_bridge_state *dp_mst_get_bridge_atomic_state(
+ struct drm_atomic_state *state, struct dp_mst_bridge *bridge)
+{
+ struct drm_device *dev = bridge->base.dev;
+
+ WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+
+ return to_dp_mst_bridge_priv_state(
+ drm_atomic_get_private_obj_state(state, &bridge->obj));
+}
+
static void dp_mst_sim_destroy_port(struct kref *ref)
{
struct drm_dp_mst_port *port = container_of(ref,
@@ -609,6 +659,8 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge,
struct dp_display_mode dp_mode;
struct dp_mst_bridge *bridge;
struct dp_display *dp;
+ struct drm_crtc_state *crtc_state;
+ struct dp_mst_bridge_state *bridge_state;
DP_MST_DEBUG("enter\n");
@@ -619,13 +671,17 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge,
}
bridge = to_dp_mst_bridge(drm_bridge);
- if (!bridge->connector) {
- DP_ERR("Invalid connector\n");
+
+ crtc_state = container_of(mode, struct drm_crtc_state, mode);
+ bridge_state = dp_mst_get_bridge_atomic_state(crtc_state->state,
+ bridge);
+ if (IS_ERR(bridge_state)) {
+ DP_ERR("invalid bridge state\n");
ret = false;
goto end;
}
- if (!bridge->dp_panel) {
+ if (!bridge_state->dp_panel) {
DP_ERR("Invalid dp_panel\n");
ret = false;
goto end;
@@ -633,7 +689,7 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge,
dp = bridge->display;
- dp->convert_to_dp_mode(dp, bridge->dp_panel, mode, &dp_mode);
+ dp->convert_to_dp_mode(dp, bridge_state->dp_panel, mode, &dp_mode);
convert_to_drm_mode(&dp_mode, adjusted_mode);
DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name);
@@ -647,7 +703,6 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state,
{
int slots = 0, pbn;
struct sde_connector *c_conn = to_sde_connector(connector);
- int rc = 0;
DP_MST_DEBUG("enter\n");
@@ -663,7 +718,7 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state,
DP_MST_DEBUG("exit\n");
- return rc;
+ return slots;
}
static void _dp_mst_update_timeslots(struct dp_mst_private *mst,
@@ -856,9 +911,6 @@ static void dp_mst_bridge_pre_enable(struct drm_bridge *drm_bridge)
bridge = to_dp_mst_bridge(drm_bridge);
dp = bridge->display;
- bridge->old_connector = NULL;
- bridge->old_dp_panel = NULL;
-
if (!bridge->connector) {
DP_ERR("Invalid connector\n");
return;
@@ -1008,17 +1060,8 @@ static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge)
DP_INFO("[%d] DP display unprepare failed, rc=%d\n",
bridge->id, rc);
- /* maintain the connector to encoder link during suspend/resume */
- if (mst->state != PM_SUSPEND) {
- /* Disconnect the connector and panel info from bridge */
- mst->mst_bridge[bridge->id].old_connector =
- mst->mst_bridge[bridge->id].connector;
- mst->mst_bridge[bridge->id].old_dp_panel =
- mst->mst_bridge[bridge->id].dp_panel;
- mst->mst_bridge[bridge->id].connector = NULL;
- mst->mst_bridge[bridge->id].dp_panel = NULL;
- mst->mst_bridge[bridge->id].encoder_active_sts = false;
- }
+ bridge->connector = NULL;
+ bridge->dp_panel = NULL;
DP_MST_INFO_LOG("mst bridge [%d] post disable complete\n",
bridge->id);
@@ -1029,6 +1072,7 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge,
struct drm_display_mode *adjusted_mode)
{
struct dp_mst_bridge *bridge;
+ struct dp_mst_bridge_state *dp_bridge_state;
struct dp_display *dp;
DP_MST_DEBUG("enter\n");
@@ -1039,23 +1083,10 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge,
}
bridge = to_dp_mst_bridge(drm_bridge);
- if (!bridge->connector) {
- if (!bridge->old_connector) {
- DP_ERR("Invalid connector\n");
- return;
- }
- bridge->connector = bridge->old_connector;
- bridge->old_connector = NULL;
- }
- if (!bridge->dp_panel) {
- if (!bridge->old_dp_panel) {
- DP_ERR("Invalid dp_panel\n");
- return;
- }
- bridge->dp_panel = bridge->old_dp_panel;
- bridge->old_dp_panel = NULL;
- }
+ dp_bridge_state = to_dp_mst_bridge_state(bridge);
+ bridge->connector = dp_bridge_state->connector;
+ bridge->dp_panel = dp_bridge_state->dp_panel;
dp = bridge->display;
@@ -1087,6 +1118,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder)
{
int rc = 0;
struct dp_mst_bridge *bridge = NULL;
+ struct dp_mst_bridge_state *state;
struct drm_device *dev;
struct dp_display *display = data;
struct msm_drm_private *priv = NULL;
@@ -1138,6 +1170,16 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder)
encoder->bridge = &bridge->base;
priv->bridges[priv->num_bridges++] = &bridge->base;
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state == NULL) {
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ drm_atomic_private_obj_init(&bridge->obj,
+ &state->base,
+ &dp_mst_bridge_state_funcs);
+
DP_MST_DEBUG("mst drm bridge init. bridge id:%d\n", i);
/*
@@ -1152,6 +1194,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder)
bridge->encoder);
if (bridge->fixed_connector == NULL) {
DP_ERR("failed to create fixed connector\n");
+ kfree(state);
rc = -ENOMEM;
goto end;
}
@@ -1237,8 +1280,9 @@ enum drm_mode_status dp_mst_connector_mode_valid(
struct drm_dp_mst_port *mst_port;
struct dp_display_mode dp_mode;
uint16_t available_pbn, required_pbn;
- int i, slots_in_use = 0, active_enc_cnt = 0;
int available_slots, required_slots;
+ struct dp_mst_bridge_state *dp_bridge_state;
+ int i, slots_in_use = 0, active_enc_cnt = 0;
const u32 tot_slots = 63;
if (!connector || !mode || !display) {
@@ -1250,21 +1294,21 @@ enum drm_mode_status dp_mst_connector_mode_valid(
c_conn = to_sde_connector(connector);
mst_port = c_conn->mst_port;
- mutex_lock(&mst->mst_lock);
- available_pbn = mst_port->available_pbn;
+ /* dp bridge state is protected by drm_mode_config.connection_mutex */
for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
- if (mst->mst_bridge[i].encoder_active_sts &&
- (mst->mst_bridge[i].connector != connector)) {
+ dp_bridge_state = to_dp_mst_bridge_state(&mst->mst_bridge[i]);
+ if (dp_bridge_state->connector &&
+ dp_bridge_state->connector != connector) {
active_enc_cnt++;
- slots_in_use += mst->mst_bridge[i].num_slots;
+ slots_in_use += dp_bridge_state->num_slots;
}
}
- mutex_unlock(&mst->mst_lock);
- if (active_enc_cnt < DP_STREAM_MAX)
+ if (active_enc_cnt < DP_STREAM_MAX) {
+ available_pbn = mst_port->available_pbn;
available_slots = tot_slots - slots_in_use;
- else {
- DP_DEBUG("all mst streams are active\n");
+ } else {
+ pr_debug("all mst streams are active\n");
return MODE_BAD;
}
@@ -1340,24 +1384,38 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector,
struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
struct sde_connector *conn = to_sde_connector(connector);
struct drm_encoder *enc = NULL;
+ struct dp_mst_bridge_state *bridge_state;
u32 i;
+ if (state->best_encoder)
+ return state->best_encoder;
+
for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
- if (mst->mst_bridge[i].connector == connector) {
+ bridge_state = dp_mst_get_bridge_atomic_state(
+ state->state, &mst->mst_bridge[i]);
+ if (IS_ERR(bridge_state))
+ goto end;
+
+ if (bridge_state->connector == connector) {
enc = mst->mst_bridge[i].encoder;
goto end;
}
}
for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
- if (!mst->mst_bridge[i].encoder_active_sts &&
- !mst->mst_bridge[i].fixed_connector) {
- mst->mst_bridge[i].encoder_active_sts = true;
- mst->mst_bridge[i].connector = connector;
- mst->mst_bridge[i].dp_panel = conn->drv_panel;
+ if (mst->mst_bridge[i].fixed_connector)
+ continue;
+
+ bridge_state = dp_mst_get_bridge_atomic_state(
+ state->state, &mst->mst_bridge[i]);
+
+ if (!bridge_state->connector) {
+ bridge_state->connector = connector;
+ bridge_state->dp_panel = conn->drv_panel;
enc = mst->mst_bridge[i].encoder;
break;
}
+
}
end:
@@ -1371,23 +1429,6 @@ end:
return enc;
}
-static struct dp_mst_bridge *_dp_mst_get_bridge_from_encoder(
- struct dp_display *dp_display,
- struct drm_encoder *encoder)
-{
- struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
- int i;
-
- for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
- if (mst->mst_bridge[i].encoder == encoder)
- return &mst->mst_bridge[i];
- }
-
- DP_MST_DEBUG("mst bridge detect for encoder failed\n");
-
- return NULL;
-}
-
static int dp_mst_connector_atomic_check(struct drm_connector *connector,
void *display, struct drm_connector_state *new_conn_state)
{
@@ -1396,7 +1437,8 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector,
struct drm_connector_state *old_conn_state;
struct drm_crtc *old_crtc;
struct drm_crtc_state *crtc_state;
- struct dp_mst_bridge *bridge = NULL;
+ struct dp_mst_bridge *bridge;
+ struct dp_mst_bridge_state *bridge_state;
struct dp_display *dp_display = display;
struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
struct sde_connector *c_conn;
@@ -1404,18 +1446,9 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector,
DP_MST_DEBUG("enter:\n");
- /*
- * Skip atomic check during mst suspend, to avoid mismanagement of
- * available vcpi slots.
- */
- if (mst->state == PM_SUSPEND)
- return rc;
-
if (!new_conn_state)
return rc;
- mutex_lock(&mst->mst_lock);
-
state = new_conn_state->state;
old_conn_state = drm_atomic_get_old_connector_state(state, connector);
@@ -1435,20 +1468,45 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector,
bridge->num_slots);
}
- bridge = _dp_mst_get_bridge_from_encoder(dp_display,
- old_conn_state->best_encoder);
- if (!bridge)
- goto end;
+ if (drm_atomic_crtc_needs_modeset(crtc_state)) {
+ if (WARN_ON(!old_conn_state->best_encoder)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ bridge = to_dp_mst_bridge(
+ old_conn_state->best_encoder->bridge);
+
+ bridge_state = dp_mst_get_bridge_atomic_state(state, bridge);
+ if (IS_ERR(bridge_state)) {
+ rc = PTR_ERR(bridge_state);
+ goto end;
+ }
- slots = bridge->num_slots;
- if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) {
- rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state,
- &mst->mst_mgr, slots);
- if (rc) {
- DP_ERR("failed releasing %d vcpi slots rc:%d\n",
- slots, rc);
+ if (WARN_ON(bridge_state->connector != connector)) {
+ rc = -EINVAL;
goto end;
}
+
+ slots = bridge_state->num_slots;
+ if (slots > 0) {
+ rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state,
+ &mst->mst_mgr, slots);
+ if (rc) {
+ pr_err("failed releasing %d vcpi slots %d\n",
+ slots, rc);
+ goto end;
+ }
+ }
+
+ bridge_state->num_slots = 0;
+
+ if (!new_conn_state->crtc && mst->state != PM_SUSPEND) {
+ bridge_state->connector = NULL;
+ bridge_state->dp_panel = NULL;
+
+ DP_MST_DEBUG("clear best encoder: %d\n", bridge->id);
+ }
}
mode_set:
@@ -1460,28 +1518,45 @@ mode_set:
if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->active) {
c_conn = to_sde_connector(connector);
+ if (WARN_ON(!new_conn_state->best_encoder)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ bridge = to_dp_mst_bridge(
+ new_conn_state->best_encoder->bridge);
+
+ bridge_state = dp_mst_get_bridge_atomic_state(state, bridge);
+ if (IS_ERR(bridge_state)) {
+ rc = PTR_ERR(bridge_state);
+ goto end;
+ }
+
+ if (WARN_ON(bridge_state->connector != connector)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
+ if (WARN_ON(bridge_state->num_slots)) {
+ rc = -EINVAL;
+ goto end;
+ }
+
dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel,
&crtc_state->mode, &dp_mode);
slots = _dp_mst_compute_config(state, mst, connector, &dp_mode);
if (slots < 0) {
rc = slots;
-
- /* Disconnect the conn and panel info from bridge */
- bridge = _dp_mst_get_bridge_from_encoder(dp_display,
- new_conn_state->best_encoder);
- if (!bridge)
- goto end;
-
- bridge->connector = NULL;
- bridge->dp_panel = NULL;
- bridge->encoder_active_sts = false;
+ goto end;
}
+
+ bridge_state->num_slots = slots;
}
end:
- mutex_unlock(&mst->mst_lock);
- DP_MST_DEBUG("mst connector:%d atomic check\n", connector->base.id);
+ DP_MST_DEBUG("mst connector:%d atomic check ret %d\n",
+ connector->base.id, rc);
return rc;
}
@@ -1645,20 +1720,21 @@ dp_mst_fixed_atomic_best_encoder(struct drm_connector *connector,
struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
struct sde_connector *conn = to_sde_connector(connector);
struct drm_encoder *enc = NULL;
+ struct dp_mst_bridge_state *bridge_state;
u32 i;
- for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
- if (mst->mst_bridge[i].connector == connector) {
- enc = mst->mst_bridge[i].encoder;
- goto end;
- }
- }
+ if (state->best_encoder)
+ return state->best_encoder;
for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
if (mst->mst_bridge[i].fixed_connector == connector) {
- mst->mst_bridge[i].encoder_active_sts = true;
- mst->mst_bridge[i].connector = connector;
- mst->mst_bridge[i].dp_panel = conn->drv_panel;
+ bridge_state = dp_mst_get_bridge_atomic_state(
+ state->state, &mst->mst_bridge[i]);
+ if (IS_ERR(bridge_state))
+ goto end;
+
+ bridge_state->connector = connector;
+ bridge_state->dp_panel = conn->drv_panel;
enc = mst->mst_bridge[i].encoder;
break;
}
diff --git a/msm/dsi/dsi_defs.h b/msm/dsi/dsi_defs.h
index d6bd6368..b1c3857c 100644
--- a/msm/dsi/dsi_defs.h
+++ b/msm/dsi/dsi_defs.h
@@ -634,6 +634,7 @@ struct dsi_display_mode_priv_info {
* @pixel_clk_khz: Pixel clock in Khz.
* @dsi_mode_flags: Flags to signal other drm components via private flags
* @panel_mode: Panel mode
+ * @is_preferred: Is mode preferred
* @priv_info: Mode private info
*/
struct dsi_display_mode {
@@ -641,6 +642,7 @@ struct dsi_display_mode {
u32 pixel_clk_khz;
u32 dsi_mode_flags;
enum dsi_op_mode panel_mode;
+ bool is_preferred;
struct dsi_display_mode_priv_info *priv_info;
};
diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c
index bfc77e31..a0de896b 100644
--- a/msm/dsi/dsi_display.c
+++ b/msm/dsi/dsi_display.c
@@ -24,7 +24,6 @@
#define to_dsi_display(x) container_of(x, struct dsi_display, host)
#define INT_BASE_10 10
-#define NO_OVERRIDE -1
#define MISR_BUFF_SIZE 256
#define ESD_MODE_STRING_MAX_LEN 256
@@ -2147,25 +2146,22 @@ static void dsi_display_parse_cmdline_topology(struct dsi_display *display,
display->sw_te_using_wd = true;
str = strnstr(boot_str, ":config", strlen(boot_str));
- if (!str)
- goto end;
-
- if (kstrtol(str + strlen(":config"), INT_BASE_10,
- (unsigned long *)&cmdline_topology)) {
- DSI_ERR("invalid config index override: %s\n", boot_str);
- goto end;
+ if (str) {
+ if (sscanf(str, ":config%lu", &cmdline_topology) != 1) {
+ DSI_ERR("invalid config index override: %s\n",
+ boot_str);
+ goto end;
+ }
}
str = strnstr(boot_str, ":timing", strlen(boot_str));
- if (!str)
- goto end;
-
- if (kstrtol(str + strlen(":timing"), INT_BASE_10,
- (unsigned long *)&cmdline_timing)) {
- DSI_ERR("invalid timing index override: %s. resetting both timing and config\n",
- boot_str);
- cmdline_topology = NO_OVERRIDE;
- goto end;
+ if (str) {
+ if (sscanf(str, ":timing%lu", &cmdline_timing) != 1) {
+ DSI_ERR("invalid timing index override: %s\n",
+ boot_str);
+ cmdline_topology = NO_OVERRIDE;
+ goto end;
+ }
}
DSI_DEBUG("successfully parsed command line topology and timing\n");
end:
@@ -5034,11 +5030,12 @@ static int dsi_display_bind(struct device *dev,
display_for_each_ctrl(i, display) {
display_ctrl = &display->ctrl[i];
- display_ctrl->ctrl->drm_dev = drm;
if (!display_ctrl->phy || !display_ctrl->ctrl)
continue;
+ display_ctrl->ctrl->drm_dev = drm;
+
rc = dsi_phy_set_clk_freq(display_ctrl->phy,
&display_ctrl->ctrl->clk_freq);
if (rc) {
@@ -6116,13 +6113,21 @@ int dsi_display_get_modes(struct dsi_display *display,
timing_mode_count = display->panel->num_timing_nodes;
+ /* Validate command line timing */
+ if ((display->cmdline_timing != NO_OVERRIDE) &&
+ (display->cmdline_timing >= timing_mode_count))
+ display->cmdline_timing = NO_OVERRIDE;
+
for (mode_idx = 0; mode_idx < timing_mode_count; mode_idx++) {
struct dsi_display_mode display_mode;
int topology_override = NO_OVERRIDE;
+ bool is_preferred = false;
u32 frame_threshold_us = ctrl->ctrl->frame_threshold_time_us;
- if (display->cmdline_timing == mode_idx)
+ if (display->cmdline_timing == mode_idx) {
topology_override = display->cmdline_topology;
+ is_preferred = true;
+ }
memset(&display_mode, 0, sizeof(display_mode));
@@ -6212,6 +6217,10 @@ int dsi_display_get_modes(struct dsi_display *display,
continue;
_dsi_display_populate_bit_clks(display, start, end, &array_idx);
+ if (is_preferred) {
+ /* Set first timing sub mode as preferred mode */
+ display->modes[start].is_preferred = true;
+ }
}
exit:
diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c
index 26d7a300..584b37bc 100644
--- a/msm/dsi/dsi_drm.c
+++ b/msm/dsi/dsi_drm.c
@@ -856,9 +856,15 @@ int dsi_connector_get_modes(struct drm_connector *connector, void *data,
}
m->width_mm = connector->display_info.width_mm;
m->height_mm = connector->display_info.height_mm;
- /* set the first mode in list as preferred */
- if (i == 0)
+
+ if (display->cmdline_timing != NO_OVERRIDE) {
+ /* get the preferred mode from dsi display mode */
+ if (modes[i].is_preferred)
+ m->type |= DRM_MODE_TYPE_PREFERRED;
+ } else if (i == 0) {
+ /* set the first mode in list as preferred */
m->type |= DRM_MODE_TYPE_PREFERRED;
+ }
drm_mode_probed_add(connector, m);
}
diff --git a/msm/dsi/dsi_drm.h b/msm/dsi/dsi_drm.h
index 4a6b7c8f..ec012c2c 100644
--- a/msm/dsi/dsi_drm.h
+++ b/msm/dsi/dsi_drm.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _DSI_DRM_H_
@@ -15,6 +15,8 @@
#include "dsi_display.h"
+#define NO_OVERRIDE -1
+
struct dsi_bridge {
struct drm_bridge base;
u32 id;
diff --git a/msm/msm_drv.c b/msm/msm_drv.c
index 33f0094b..9b65de57 100644
--- a/msm/msm_drv.c
+++ b/msm/msm_drv.c
@@ -1173,10 +1173,11 @@ static void msm_lastclose(struct drm_device *dev)
/* check for splash status before triggering cleanup
* if we end up here with splash status ON i.e before first
- * commit then ignore the last close call
+ * commit then ignore the last close call. Also, ignore
+ * if kms module is not yet initialized.
*/
- if (kms && kms->funcs && kms->funcs->check_for_splash
- && kms->funcs->check_for_splash(kms))
+ if (!kms || (kms && kms->funcs && kms->funcs->check_for_splash
+ && kms->funcs->check_for_splash(kms)))
return;
/*
diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c
index e108b8cb..a37f0f1a 100644
--- a/msm/sde/sde_encoder.c
+++ b/msm/sde/sde_encoder.c
@@ -2353,8 +2353,13 @@ static void sde_encoder_idle_hint(const struct drm_encoder *drm_enc,
static int _sde_encoder_rc_kickoff(struct drm_encoder *drm_enc,
u32 sw_event, struct sde_encoder_virt *sde_enc, bool is_vid_mode)
{
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
int ret = 0;
+ priv = drm_enc->dev->dev_private;
+ sde_kms = to_sde_kms(priv->kms);
+
/* cancel delayed off work, if any */
_sde_encoder_rc_cancel_delayed(sde_enc, sw_event);
@@ -2380,6 +2385,7 @@ static int _sde_encoder_rc_kickoff(struct drm_encoder *drm_enc,
if (is_vid_mode && sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) {
_sde_encoder_irq_control(drm_enc, true);
+ sde_kms_update_pm_qos_irq_request(sde_kms, true, false);
} else {
/* enable all the clks and resources */
ret = _sde_encoder_resource_control_helper(drm_enc,
@@ -2698,6 +2704,7 @@ static int _sde_encoder_rc_idle(struct drm_encoder *drm_enc,
if (is_vid_mode) {
_sde_encoder_irq_control(drm_enc, false);
+ sde_kms_update_pm_qos_irq_request(sde_kms, false, false);
} else {
sde_encoder_idle_hint(drm_enc, true);
diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c
index 630e8932..29804065 100644
--- a/msm/sde/sde_kms.c
+++ b/msm/sde/sde_kms.c
@@ -3287,6 +3287,7 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms)
mmu, "sde");
if (IS_ERR(aspace)) {
ret = PTR_ERR(aspace);
+ mmu->funcs->destroy(mmu);
goto fail;
}
@@ -3323,7 +3324,6 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms)
early_map_fail:
_sde_kms_unmap_all_splash_regions(sde_kms);
fail:
- mmu->funcs->destroy(mmu);
_sde_kms_mmu_destroy(sde_kms);
return ret;
@@ -3360,32 +3360,43 @@ static void _sde_kms_set_lutdma_vbif_remap(struct sde_kms *sde_kms)
sde_vbif_set_qos_remap(sde_kms, &qos_params);
}
-static void sde_kms_update_pm_qos_irq_request(struct sde_kms *sde_kms)
+void sde_kms_update_pm_qos_irq_request(struct sde_kms *sde_kms,
+ bool enable, bool skip_lock)
{
- struct pm_qos_request *req;
- u32 cpu_irq_latency;
+ struct msm_drm_private *priv;
- req = &sde_kms->pm_qos_irq_req;
- req->type = PM_QOS_REQ_AFFINE_CORES;
- req->cpus_affine = sde_kms->irq_cpu_mask;
- cpu_irq_latency = sde_kms->catalog->perf.cpu_irq_latency;
+ priv = sde_kms->dev->dev_private;
- if (pm_qos_request_active(req))
- pm_qos_update_request(req, cpu_irq_latency);
- else if (!cpumask_empty(&req->cpus_affine)) {
- /** If request is not active yet and mask is not empty
- * then it needs to be added initially
- */
- pm_qos_add_request(req, PM_QOS_CPU_DMA_LATENCY,
+ if (!skip_lock)
+ mutex_lock(&priv->phandle.phandle_lock);
+
+ if (enable) {
+ struct pm_qos_request *req;
+ u32 cpu_irq_latency;
+
+ req = &sde_kms->pm_qos_irq_req;
+ req->type = PM_QOS_REQ_AFFINE_CORES;
+ req->cpus_affine = sde_kms->irq_cpu_mask;
+ cpu_irq_latency = sde_kms->catalog->perf.cpu_irq_latency;
+
+ if (pm_qos_request_active(req))
+ pm_qos_update_request(req, cpu_irq_latency);
+ else if (!cpumask_empty(&req->cpus_affine)) {
+ /** If request is not active yet and mask is not empty
+ * then it needs to be added initially
+ */
+ pm_qos_add_request(req, PM_QOS_CPU_DMA_LATENCY,
cpu_irq_latency);
+ }
+ } else if (!enable && pm_qos_request_active(&sde_kms->pm_qos_irq_req)) {
+ pm_qos_update_request(&sde_kms->pm_qos_irq_req,
+ PM_QOS_DEFAULT_VALUE);
}
-}
-static void sde_kms_set_default_pm_qos_irq_request(struct sde_kms *sde_kms)
-{
- if (pm_qos_request_active(&sde_kms->pm_qos_irq_req))
- pm_qos_update_request(&sde_kms->pm_qos_irq_req,
- PM_QOS_DEFAULT_VALUE);
+ sde_kms->pm_qos_irq_req_en = enable;
+
+ if (!skip_lock)
+ mutex_unlock(&priv->phandle.phandle_lock);
}
static void sde_kms_irq_affinity_notify(
@@ -3407,8 +3418,8 @@ static void sde_kms_irq_affinity_notify(
sde_kms->irq_cpu_mask = *mask;
// request vote with updated irq cpu mask
- if (sde_kms->irq_enabled)
- sde_kms_update_pm_qos_irq_request(sde_kms);
+ if (sde_kms->pm_qos_irq_req_en)
+ sde_kms_update_pm_qos_irq_request(sde_kms, true, true);
mutex_unlock(&priv->phandle.phandle_lock);
}
@@ -3433,9 +3444,9 @@ static void sde_kms_handle_power_event(u32 event_type, void *usr)
sde_kms_init_shared_hw(sde_kms);
_sde_kms_set_lutdma_vbif_remap(sde_kms);
sde_kms->first_kickoff = true;
- sde_kms_update_pm_qos_irq_request(sde_kms);
+ sde_kms_update_pm_qos_irq_request(sde_kms, true, true);
} else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) {
- sde_kms_set_default_pm_qos_irq_request(sde_kms);
+ sde_kms_update_pm_qos_irq_request(sde_kms, false, true);
sde_irq_update(msm_kms, false);
sde_kms->first_kickoff = false;
}
diff --git a/msm/sde/sde_kms.h b/msm/sde/sde_kms.h
index c9900224..3d61b7de 100644
--- a/msm/sde/sde_kms.h
+++ b/msm/sde/sde_kms.h
@@ -299,6 +299,7 @@ struct sde_kms {
cpumask_t irq_cpu_mask;
struct pm_qos_request pm_qos_irq_req;
struct irq_affinity_notify affinity_notify;
+ bool pm_qos_irq_req_en;
};
/**
@@ -665,4 +666,13 @@ int sde_kms_handle_recovery(struct drm_encoder *encoder);
void sde_kms_trigger_early_wakeup(struct sde_kms *sde_kms,
struct drm_crtc *crtc);
+/**
+ * sde_kms_update_pm_qos_irq_request - Update Qos vote for CPU receiving
+ * display IRQ
+ * @sde_kms : pointer to sde_kms structure
+ * @enable : indicates request to be enabled or disabled
+ * @skip_lock : indicates if lock needs to be acquired
+ */
+void sde_kms_update_pm_qos_irq_request(struct sde_kms *sde_kms,
+ bool enable, bool skip_lock);
#endif /* __sde_kms_H__ */
diff --git a/pll/dsi_pll_8996_util.c b/pll/dsi_pll_8996_util.c
index 543548ea..8ce261ca 100644
--- a/pll/dsi_pll_8996_util.c
+++ b/pll/dsi_pll_8996_util.c
@@ -1,6 +1,6 @@
// 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.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -395,8 +395,8 @@ static void mdss_dsi_pll_8996_input_init(struct mdss_pll_resources *pll,
pdb->in.pll_ip_trim = 4; /* 4, reg: 0x0404 */
pdb->in.pll_cpcset_cur = 1; /* 1, reg: 0x04f0, bit 0 - 2 */
pdb->in.pll_cpmset_cur = 1; /* 1, reg: 0x04f0, bit 3 - 5 */
- pdb->in.pll_icpmset = 4; /* 4, reg: 0x04fc, bit 3 - 5 */
- pdb->in.pll_icpcset = 4; /* 4, reg: 0x04fc, bit 0 - 2 */
+ pdb->in.pll_icpmset = 7; /* 7, reg: 0x04fc, bit 3 - 5 */
+ pdb->in.pll_icpcset = 7; /* 7, reg: 0x04fc, bit 0 - 2 */
pdb->in.pll_icpmset_p = 0; /* 0, reg: 0x04f4, bit 0 - 2 */
pdb->in.pll_icpmset_m = 0; /* 0, reg: 0x04f4, bit 3 - 5 */
pdb->in.pll_icpcset_p = 0; /* 0, reg: 0x04f8, bit 0 - 2 */