diff options
author | lucaswei <lucaswei@google.com> | 2020-06-01 16:12:30 +0800 |
---|---|---|
committer | lucaswei <lucaswei@google.com> | 2020-06-10 22:44:15 +0800 |
commit | 80a1e953b1823fe4b694e8751769edda1faa969f (patch) | |
tree | f1347b758b94e97076d4fe119981d38a1fc560b3 | |
parent | a0bd65d5eafce0c91b3d6be4018ae99cafa4bc25 (diff) | |
parent | d5a91a3fc5c8deaea89235f2cd634935c94bc13b (diff) | |
download | display-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.c | 8 | ||||
-rw-r--r-- | msm/dp/dp_mst_drm.c | 306 | ||||
-rw-r--r-- | msm/dsi/dsi_defs.h | 2 | ||||
-rw-r--r-- | msm/dsi/dsi_display.c | 47 | ||||
-rw-r--r-- | msm/dsi/dsi_drm.c | 10 | ||||
-rw-r--r-- | msm/dsi/dsi_drm.h | 4 | ||||
-rw-r--r-- | msm/msm_drv.c | 7 | ||||
-rw-r--r-- | msm/sde/sde_encoder.c | 7 | ||||
-rw-r--r-- | msm/sde/sde_kms.c | 61 | ||||
-rw-r--r-- | msm/sde/sde_kms.h | 10 | ||||
-rw-r--r-- | pll/dsi_pll_8996_util.c | 6 |
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 */ |