diff --git a/msm/dp/dp_debug.c b/msm/dp/dp_debug.c index 0696dd5a..fc4c0f8d 100644 --- a/msm/dp/dp_debug.c +++ b/msm/dp/dp_debug.c @@ -74,19 +74,18 @@ static int dp_debug_attach_sim_bridge(struct dp_debug_private *debug) { int ret; - if (debug->sim_bridge) - return 0; + if (!debug->sim_bridge) { + ret = dp_sim_create_bridge(debug->dev, &debug->sim_bridge); + if (ret) + return ret; - ret = dp_sim_create_bridge(debug->dev, &debug->sim_bridge); - if (ret) - return ret; + if (debug->sim_bridge->register_hpd) + debug->sim_bridge->register_hpd(debug->sim_bridge, + dp_debug_sim_hpd_cb, debug); + } dp_sim_update_port_num(debug->sim_bridge, 1); - if (debug->sim_bridge->register_hpd) - debug->sim_bridge->register_hpd(debug->sim_bridge, - dp_debug_sim_hpd_cb, debug); - return 0; } diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index fe073d4b..6b61ea30 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -1646,6 +1646,10 @@ static void dp_display_disconnect_sync(struct dp_display_private *dp) cancel_work_sync(&dp->attention_work); flush_workqueue(dp->wq); + if (!dp->debug->sim_mode && !dp->no_aux_switch + && !dp->parser->gpio_aux_switch) + dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); + /* * Delay the teardown of the mainlink for better interop experience. * It is possible that certain sinks can issue an HPD high immediately @@ -1703,10 +1707,6 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) dp_display_state_remove(DP_STATE_CONFIGURED); mutex_unlock(&dp->session_lock); - if (!dp->debug->sim_mode && !dp->no_aux_switch - && !dp->parser->gpio_aux_switch) - dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); - SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); end: return rc; diff --git a/msm/dp/dp_mst_sim.c b/msm/dp/dp_mst_sim.c index 2ed82571..1be4422e 100644 --- a/msm/dp/dp_mst_sim.c +++ b/msm/dp/dp_mst_sim.c @@ -342,6 +342,7 @@ int dp_sim_update_port_num(struct dp_aux_bridge *bridge, u32 port_num) return -EINVAL; sim_dev = to_dp_sim_dev(bridge); + DP_INFO("Update port count from %d to %d\n", sim_dev->port_num, port_num); if (port_num > sim_dev->port_num) { ports = devm_kzalloc(sim_dev->dev, @@ -361,10 +362,9 @@ int dp_sim_update_port_num(struct dp_aux_bridge *bridge, u32 port_num) memcpy(&ports[i], &output_port, sizeof(*ports)); ports[i].peer_guid[0] = i; } - - sim_dev->port_num = port_num; } + sim_dev->port_num = port_num; rc = dp_mst_sim_update(sim_dev->bridge.mst_ctx, port_num, sim_dev->ports); if (rc) diff --git a/msm/dp/dp_mst_sim_helper.c b/msm/dp/dp_mst_sim_helper.c index 1fe4e916..d0bb5910 100644 --- a/msm/dp/dp_mst_sim_helper.c +++ b/msm/dp/dp_mst_sim_helper.c @@ -1055,6 +1055,18 @@ static void dp_mst_sim_notify(struct dp_mst_sim_context *ctx, queue_work(ctx->wq, &work->base); } +static void dp_mst_sim_free_ports(struct dp_mst_sim_context *ctx) +{ + u32 i; + + for (i = 0; i < ctx->port_num; i++) + kfree(ctx->ports[i].edid); + + kfree(ctx->ports); + ctx->ports = NULL; + ctx->port_num = 0; +} + int dp_mst_sim_update(void *mst_sim_context, u32 port_num, struct dp_mst_sim_port *ports) { @@ -1064,7 +1076,7 @@ int dp_mst_sim_update(void *mst_sim_context, u32 port_num, u32 update_mask = 0; u32 i; - if (!ctx || port_num >= 15) + if (!ctx || port_num >= 15 || !ports) return -EINVAL; mutex_lock(&ctx->session_lock); @@ -1081,10 +1093,10 @@ int dp_mst_sim_update(void *mst_sim_context, u32 port_num, } } - for (i = 0; i < ctx->port_num; i++) - kfree(ctx->ports[i].edid); - kfree(ctx->ports); - ctx->port_num = 0; + dp_mst_sim_free_ports(ctx); + + if (!port_num) + goto end; ctx->ports = kcalloc(port_num, sizeof(*ports), GFP_KERNEL); if (!ctx->ports) { @@ -1114,12 +1126,10 @@ int dp_mst_sim_update(void *mst_sim_context, u32 port_num, } fail: - if (rc) { - for (i = 0; i < ctx->port_num; i++) - kfree(ctx->ports[i].edid); - kfree(ctx->ports); - } + if (rc) + dp_mst_sim_free_ports(ctx); +end: mutex_unlock(&ctx->session_lock); if (update_mask) diff --git a/msm/sde/sde_color_processing.c b/msm/sde/sde_color_processing.c index cc9d10d4..2a7673c7 100644 --- a/msm/sde/sde_color_processing.c +++ b/msm/sde/sde_color_processing.c @@ -112,6 +112,8 @@ static int _sde_cp_crtc_cache_property(struct drm_crtc *crtc, struct drm_property *property, uint64_t val); +static void _sde_cp_mark_active_dirty_internal(struct sde_crtc *crtc); + #define setup_dspp_prop_install_funcs(func) \ do { \ func[SDE_DSPP_PCC] = _dspp_pcc_install_property; \ @@ -2824,6 +2826,7 @@ void sde_cp_disable_features(struct drm_crtc *crtc) mutex_unlock(&sde_crtc->crtc_cp_lock); } + _sde_cp_mark_active_dirty_internal(sde_crtc); } void sde_cp_crtc_clear(struct drm_crtc *crtc) @@ -4751,6 +4754,19 @@ static bool _sde_cp_feature_in_activelist(u32 feature, struct list_head *list) return false; } +/* this func needs to be called within crtc_cp_lock mutex */ +static struct sde_cp_node *_sde_cp_feature_getnode_activelist(u32 feature, struct list_head *list) +{ + struct sde_cp_node *node = NULL; + + list_for_each_entry(node, list, cp_active_list) { + if (feature == node->feature) + return node; + } + + return NULL; +} + void sde_cp_crtc_vm_primary_handoff(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = NULL; @@ -5012,3 +5028,26 @@ void sde_cp_set_skip_blend_plane_info(struct drm_crtc *drm_crtc, mutex_unlock(&crtc->crtc_cp_lock); } +void _sde_cp_mark_active_dirty_internal(struct sde_crtc *crtc) +{ + struct sde_cp_node *prop_node; + u32 i; + enum sde_cp_crtc_features features[] = { + SDE_CP_CRTC_DSPP_DEMURA_INIT, + }; + + mutex_lock(&crtc->crtc_cp_lock); + + for (i = 0; i < ARRAY_SIZE(features); i++) { + if (_sde_cp_feature_in_dirtylist(features[i], + &crtc->cp_dirty_list)) + continue; + prop_node = _sde_cp_feature_getnode_activelist(features[i], + &crtc->cp_active_list); + if (prop_node) { + _sde_cp_update_list(prop_node, crtc, true); + list_del_init(&prop_node->cp_active_list); + } + } + mutex_unlock(&crtc->crtc_cp_lock); +} diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index 9a250086..22ee4e1f 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -57,6 +57,7 @@ static const struct drm_prop_enum_list e_topology_control[] = { {SDE_RM_TOPCTL_DSPP, "dspp"}, {SDE_RM_TOPCTL_DS, "ds"}, {SDE_RM_TOPCTL_DNSC_BLUR, "dnsc_blur"}, + {SDE_RM_TOPCTL_CDM, "cdm"}, }; static const struct drm_prop_enum_list e_power_mode[] = { {SDE_MODE_DPMS_ON, "ON"}, diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index bea70fb8..01e47d9e 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2132,7 +2132,7 @@ static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms) u32 sspp_id[MAX_PLANES]; u32 master_plane_id[MAX_PLANES]; - u32 num_virt_planes = 0; + u32 num_virt_planes = 0, dummy_mixer_count = 0; if (!sde_kms || !sde_kms->dev || !sde_kms->dev->dev) { SDE_ERROR("invalid sde_kms\n"); @@ -2153,7 +2153,11 @@ static int _sde_kms_drm_obj_init(struct sde_kms *sde_kms) if (!_sde_kms_get_displays(sde_kms)) (void)_sde_kms_setup_displays(dev, priv, sde_kms); - max_crtc_count = min(catalog->mixer_count, priv->num_encoders); + for (i = 0; i < catalog->mixer_count; i++) + if (catalog->mixer[i].dummy_mixer) + dummy_mixer_count++; + + max_crtc_count = catalog->mixer_count - dummy_mixer_count; /* Create the planes */ for (i = 0; i < catalog->sspp_count; i++) { @@ -2579,6 +2583,38 @@ static void _sde_kms_plane_force_remove(struct drm_plane *plane, drm_atomic_set_fb_for_plane(plane_state, NULL); } +static int _sde_kms_connector_add_refcount(struct sde_kms *sde_kms, + struct drm_atomic_state *state) +{ + struct drm_device *dev = sde_kms->dev; + struct drm_connector *conn; + struct drm_connector_state *conn_state; + struct drm_connector_list_iter conn_iter; + struct sde_connector_state *c_state; + int ret = 0; + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(conn, &conn_iter) { + /* + * Acquire a connector reference to avoid removing + * connector in drm_release for splash and recovery cases. + */ + conn_state = drm_atomic_get_connector_state(state, conn); + if (IS_ERR(conn_state)) { + ret = PTR_ERR(conn_state); + SDE_ERROR("error %d getting connector %d state\n", + ret, DRMID(conn)); + return ret; + } + c_state = to_sde_connector_state(conn_state); + if (c_state->out_fb) + drm_framebuffer_put(c_state->out_fb); + } + drm_connector_list_iter_end(&conn_iter); + + return ret; +} + static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file, struct drm_atomic_state *state) { @@ -2611,6 +2647,8 @@ static int _sde_kms_remove_fbs(struct sde_kms *sde_kms, struct drm_file *file, if (list_empty(&fbs)) { SDE_DEBUG("skip commit as no fb(s)\n"); + if (sde_kms->dsi_display_count == sde_kms->splash_data.num_splash_displays) + _sde_kms_connector_add_refcount(sde_kms, state); return 0; } diff --git a/msm/sde/sde_rm.c b/msm/sde/sde_rm.c index fc2e2048..cbe5d3ea 100644 --- a/msm/sde/sde_rm.c +++ b/msm/sde/sde_rm.c @@ -37,6 +37,7 @@ #define RM_RQ_CWB(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_CWB)) #define RM_RQ_DCWB(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_DCWB)) #define RM_RQ_DNSC_BLUR(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_DNSC_BLUR)) +#define RM_RQ_CDM(r) ((r)->top_ctrl & BIT(SDE_RM_TOPCTL_CDM)) #define RM_IS_TOPOLOGY_MATCH(t, r) ((t).num_lm == (r).num_lm && \ (t).num_comp_enc == (r).num_enc && \ (t).num_intf == (r).num_intf && \ @@ -1882,8 +1883,11 @@ static int _sde_rm_reserve_intf_or_wb(struct sde_rm *rm, struct sde_rm_rsvp *rsv } /* Expected only one intf or wb will request cdm */ - if (hw_res->needs_cdm) + if (hw_res->needs_cdm || RM_RQ_CDM(reqs)) { ret = _sde_rm_reserve_cdm(rm, rsvp, id, type); + if (ret) + return ret; + } if (RM_RQ_DNSC_BLUR(reqs)) ret = _sde_rm_reserve_dnsc_blur(rm, rsvp, id, type); diff --git a/msm/sde/sde_rm.h b/msm/sde/sde_rm.h index dc39a955..7be8816a 100644 --- a/msm/sde/sde_rm.h +++ b/msm/sde/sde_rm.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -114,6 +115,7 @@ enum sde_rm_topology_group { * @SDE_RM_TOPCTL_CWB : Require layer mixers with CWB capabilities * @SDE_RM_TOPCTL_DCWB : Require layer mixers with DCWB capabilities * @SDE_RM_TOPCTL_DNSC_BLUR : Require writeback with downscale blur capabilities + * @SDE_RM_TOPCTL_CDM : Require writeback with CDM capabilities */ enum sde_rm_topology_control { SDE_RM_TOPCTL_RESERVE_LOCK, @@ -123,6 +125,7 @@ enum sde_rm_topology_control { SDE_RM_TOPCTL_CWB, SDE_RM_TOPCTL_DCWB, SDE_RM_TOPCTL_DNSC_BLUR, + SDE_RM_TOPCTL_CDM, }; /** diff --git a/msm/sde/sde_wb.c b/msm/sde/sde_wb.c index a8f41fe7..27a1537b 100644 --- a/msm/sde/sde_wb.c +++ b/msm/sde/sde_wb.c @@ -545,6 +545,9 @@ int sde_wb_connector_set_info_blob(struct drm_connector *connector, sde_kms_info_add_keyint(info, "has_cwb_dither", test_bit(SDE_FEATURE_CWB_DITHER, catalog->features)); + if (catalog->cdm_count) + sde_kms_info_add_keyint(info, "cdm_count", catalog->cdm_count); + if (catalog->dnsc_blur_count && catalog->dnsc_blur_filters) { sde_kms_info_add_keyint(info, "dnsc_blur_count", catalog->dnsc_blur_count);