From d00d481360eeeed5a975629d47e83cb7acd0fedc Mon Sep 17 00:00:00 2001 From: orion brody Date: Tue, 24 Nov 2020 14:19:42 -0800 Subject: [PATCH] disp: msm: move from drm_mode to msm_mode Move away from the private and private_flags fields from drm_mode, as it is being deprecated in latest kernel version. Instead, Add msm_display_mode as a wrapper to be used in downstream to store these parameters. Also, store msm_mode in connector_state to be accessed in commit path. Change-Id: Ia5bdebe75f00aa15fb7db4dc3a0d50c30894a95c Signed-off-by: Orion Brody --- msm/dsi/dsi_drm.c | 219 ++++++++++++++++++++------------- msm/msm_atomic.c | 55 ++++++--- msm/msm_drv.h | 14 ++- msm/msm_kms.h | 18 +-- msm/sde/sde_connector.c | 18 ++- msm/sde/sde_connector.h | 13 +- msm/sde/sde_crtc.c | 89 ++++++++++++-- msm/sde/sde_crtc.h | 9 +- msm/sde/sde_encoder.c | 92 ++++++++------ msm/sde/sde_encoder.h | 10 +- msm/sde/sde_encoder_phys_vid.c | 20 +-- msm/sde/sde_kms.c | 8 +- 12 files changed, 396 insertions(+), 169 deletions(-) diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index a95c869b12..6f49918db9 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -12,6 +12,8 @@ #include "dsi_drm.h" #include "sde_trace.h" #include "sde_dbg.h" +#include "msm_drv.h" +#include "sde_encoder.h" #define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base) #define to_dsi_state(x) container_of((x), struct dsi_connector_state, base) @@ -53,32 +55,6 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode, dsi_mode->pixel_clk_khz = drm_mode->clock; - dsi_mode->priv_info = - (struct dsi_display_mode_priv_info *)drm_mode->private; - - if (dsi_mode->priv_info) { - dsi_mode->timing.dsc_enabled = dsi_mode->priv_info->dsc_enabled; - dsi_mode->timing.dsc = &dsi_mode->priv_info->dsc; - dsi_mode->timing.vdc_enabled = dsi_mode->priv_info->vdc_enabled; - dsi_mode->timing.vdc = &dsi_mode->priv_info->vdc; - dsi_mode->timing.pclk_scale = dsi_mode->priv_info->pclk_scale; - } - - if (msm_is_mode_seamless(drm_mode)) - dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_SEAMLESS; - if (msm_is_mode_dynamic_fps(drm_mode)) - dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DFPS; - if (msm_needs_vblank_pre_modeset(drm_mode)) - dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VBLANK_PRE_MODESET; - if (msm_is_mode_seamless_dms(drm_mode)) - dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS; - if (msm_is_mode_seamless_vrr(drm_mode)) - dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; - if (msm_is_mode_seamless_poms(drm_mode)) - dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_POMS; - if (msm_is_mode_seamless_dyn_clk(drm_mode)) - dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DYN_CLK; - dsi_mode->timing.h_sync_polarity = !!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC); dsi_mode->timing.v_sync_polarity = @@ -90,6 +66,36 @@ static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode, dsi_mode->panel_mode = DSI_OP_CMD_MODE; } +static void msm_parse_mode_priv_info(const struct msm_display_mode *msm_mode, + struct dsi_display_mode *dsi_mode) +{ + dsi_mode->priv_info = + (struct dsi_display_mode_priv_info *)msm_mode->private; + + if (dsi_mode->priv_info) { + dsi_mode->timing.dsc_enabled = dsi_mode->priv_info->dsc_enabled; + dsi_mode->timing.dsc = &dsi_mode->priv_info->dsc; + dsi_mode->timing.vdc_enabled = dsi_mode->priv_info->vdc_enabled; + dsi_mode->timing.vdc = &dsi_mode->priv_info->vdc; + dsi_mode->timing.pclk_scale = dsi_mode->priv_info->pclk_scale; + } + + if (msm_is_mode_seamless(msm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_SEAMLESS; + if (msm_is_mode_dynamic_fps(msm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DFPS; + if (msm_needs_vblank_pre_modeset(msm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VBLANK_PRE_MODESET; + if (msm_is_mode_seamless_dms(msm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS; + if (msm_is_mode_seamless_vrr(msm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; + if (msm_is_mode_seamless_poms(msm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_POMS; + if (msm_is_mode_seamless_dyn_clk(msm_mode)) + dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DYN_CLK; +} + void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, struct drm_display_mode *drm_mode) { @@ -115,23 +121,6 @@ void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, drm_mode->vrefresh = dsi_mode->timing.refresh_rate; drm_mode->clock = dsi_mode->pixel_clk_khz; - drm_mode->private = (int *)dsi_mode->priv_info; - - if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS) - drm_mode->private_flags |= DRM_MODE_FLAG_SEAMLESS; - if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DFPS) - drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS; - if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VBLANK_PRE_MODESET) - drm_mode->private_flags |= MSM_MODE_FLAG_VBLANK_PRE_MODESET; - if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) - drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS; - if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) - drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR; - if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) - drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_POMS; - if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) - drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYN_CLK; - if (dsi_mode->timing.h_sync_polarity) drm_mode->flags |= DRM_MODE_FLAG_PHSYNC; if (dsi_mode->timing.v_sync_polarity) @@ -149,6 +138,28 @@ void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, video_mode ? "vid" : "cmd"); } +static void dsi_convert_to_msm_mode(const struct dsi_display_mode *dsi_mode, + struct msm_display_mode *msm_mode) +{ + msm_mode->private_flags = 0; + msm_mode->private = (int *)dsi_mode->priv_info; + + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS) + msm_mode->private_flags |= DRM_MODE_FLAG_SEAMLESS; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DFPS) + msm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VBLANK_PRE_MODESET) + msm_mode->private_flags |= MSM_MODE_FLAG_VBLANK_PRE_MODESET; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) + msm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) + msm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) + msm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_POMS; + if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) + msm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYN_CLK; +} + static int dsi_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) { @@ -261,8 +272,8 @@ static void dsi_bridge_enable(struct drm_bridge *bridge) static void dsi_bridge_disable(struct drm_bridge *bridge) { int rc = 0; - int private_flags; struct dsi_display *display; + struct sde_connector_state *conn_state; struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); if (!bridge) { @@ -270,15 +281,19 @@ static void dsi_bridge_disable(struct drm_bridge *bridge) return; } display = c_bridge->display; - private_flags = - bridge->encoder->crtc->state->adjusted_mode.private_flags; if (display) display->enabled = false; if (display && display->drm_conn) { - display->poms_pending = - private_flags & MSM_MODE_FLAG_SEAMLESS_POMS; + conn_state = to_sde_connector_state(display->drm_conn->state); + if (!conn_state) { + DSI_ERR("invalid params\n"); + return; + } + + display->poms_pending = msm_is_mode_seamless_poms( + &conn_state->msm_mode); sde_connector_helper_bridge_disable(display->drm_conn); } @@ -326,6 +341,8 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge, const struct drm_display_mode *adjusted_mode) { struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + struct drm_connector *conn; + struct sde_connector_state *conn_state; if (!bridge || !mode || !adjusted_mode) { DSI_ERR("Invalid params\n"); @@ -334,6 +351,18 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge, memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode)); convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode)); + conn = sde_encoder_get_connector(bridge->dev, bridge->encoder); + if (!conn) + return; + + conn_state = to_sde_connector_state(conn->state); + if (!conn_state) { + DSI_ERR("invalid connector state\n"); + return; + } + + msm_parse_mode_priv_info(&conn_state->msm_mode, + &(c_bridge->dsi_mode)); /* restore bit_clk_rate also for dynamic clk use cases */ c_bridge->dsi_mode.timing.clk_rate_hz = @@ -351,17 +380,27 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, struct dsi_display *display; struct dsi_display_mode dsi_mode, cur_dsi_mode, *panel_dsi_mode; struct drm_crtc_state *crtc_state; + struct drm_connector_state *drm_conn_state; + struct sde_connector_state *conn_state; crtc_state = container_of(mode, struct drm_crtc_state, mode); if (!bridge || !mode || !adjusted_mode) { - DSI_ERR("Invalid params\n"); + DSI_ERR("invalid params\n"); return false; } display = c_bridge->display; - if (!display) { - DSI_ERR("Invalid params\n"); + if (!display || !display->drm_conn || !display->drm_conn->state) { + DSI_ERR("invalid params\n"); + return false; + } + + drm_conn_state = drm_atomic_get_new_connector_state(crtc_state->state, + display->drm_conn); + conn_state = to_sde_connector_state(drm_conn_state); + if (!conn_state) { + DSI_ERR("invalid params\n"); return false; } @@ -371,8 +410,9 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, */ if (display->panel && !display->panel->num_timing_nodes) { *adjusted_mode = *mode; - adjusted_mode->private = (int *)&default_priv_info; - adjusted_mode->private_flags = 0; + conn_state->msm_mode.base = adjusted_mode; + conn_state->msm_mode.private = (int *)&default_priv_info; + conn_state->msm_mode.private_flags = 0; return true; } @@ -459,7 +499,7 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, /* convert back to drm mode, propagating the private info & flags */ dsi_convert_to_drm_mode(&dsi_mode, adjusted_mode); - + dsi_convert_to_msm_mode(&dsi_mode, &conn_state->msm_mode); return true; } @@ -517,61 +557,61 @@ int dsi_conn_get_mode_info(struct drm_connector *connector, struct msm_mode_info *mode_info, void *display, const struct msm_resource_caps_info *avail_res) { - struct dsi_display_mode dsi_mode; + struct dsi_display_mode partial_dsi_mode, *dsi_mode = NULL; struct dsi_mode_info *timing; - int src_bpp, tar_bpp; + int src_bpp, tar_bpp, rc = 0; if (!drm_mode || !mode_info) return -EINVAL; - convert_to_dsi_mode(drm_mode, &dsi_mode); - - if (!dsi_mode.priv_info) + convert_to_dsi_mode(drm_mode, &partial_dsi_mode); + rc = dsi_display_find_mode(display, &partial_dsi_mode, &dsi_mode); + if (rc || !dsi_mode->priv_info) return -EINVAL; memset(mode_info, 0, sizeof(*mode_info)); - timing = &dsi_mode.timing; - mode_info->frame_rate = dsi_mode.timing.refresh_rate; + timing = &dsi_mode->timing; + mode_info->frame_rate = dsi_mode->timing.refresh_rate; mode_info->vtotal = DSI_V_TOTAL(timing); - mode_info->prefill_lines = dsi_mode.priv_info->panel_prefill_lines; - mode_info->jitter_numer = dsi_mode.priv_info->panel_jitter_numer; - mode_info->jitter_denom = dsi_mode.priv_info->panel_jitter_denom; - mode_info->clk_rate = dsi_drm_find_bit_clk_rate(display, drm_mode); + mode_info->prefill_lines = dsi_mode->priv_info->panel_prefill_lines; + mode_info->jitter_numer = dsi_mode->priv_info->panel_jitter_numer; + mode_info->jitter_denom = dsi_mode->priv_info->panel_jitter_denom; mode_info->dfps_maxfps = dsi_drm_get_dfps_maxfps(display); + mode_info->clk_rate = dsi_drm_find_bit_clk_rate(display, drm_mode); mode_info->mdp_transfer_time_us = - dsi_mode.priv_info->mdp_transfer_time_us; + dsi_mode->priv_info->mdp_transfer_time_us; - memcpy(&mode_info->topology, &dsi_mode.priv_info->topology, + memcpy(&mode_info->topology, &dsi_mode->priv_info->topology, sizeof(struct msm_display_topology)); - if (dsi_mode.priv_info->dsc_enabled) { + if (dsi_mode->priv_info->dsc_enabled) { mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC; mode_info->topology.comp_type = MSM_DISPLAY_COMPRESSION_DSC; - memcpy(&mode_info->comp_info.dsc_info, &dsi_mode.priv_info->dsc, - sizeof(dsi_mode.priv_info->dsc)); - } else if (dsi_mode.priv_info->vdc_enabled) { + memcpy(&mode_info->comp_info.dsc_info, &dsi_mode->priv_info->dsc, + sizeof(dsi_mode->priv_info->dsc)); + } else if (dsi_mode->priv_info->vdc_enabled) { mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_VDC; mode_info->topology.comp_type = MSM_DISPLAY_COMPRESSION_VDC; - memcpy(&mode_info->comp_info.vdc_info, &dsi_mode.priv_info->vdc, - sizeof(dsi_mode.priv_info->vdc)); + memcpy(&mode_info->comp_info.vdc_info, &dsi_mode->priv_info->vdc, + sizeof(dsi_mode->priv_info->vdc)); } if (mode_info->comp_info.comp_type) { - tar_bpp = dsi_mode.priv_info->pclk_scale.numer; - src_bpp = dsi_mode.priv_info->pclk_scale.denom; + tar_bpp = dsi_mode->priv_info->pclk_scale.numer; + src_bpp = dsi_mode->priv_info->pclk_scale.denom; mode_info->comp_info.comp_ratio = mult_frac(1, src_bpp, tar_bpp); - mode_info->wide_bus_en = dsi_mode.priv_info->widebus_support; + mode_info->wide_bus_en = dsi_mode->priv_info->widebus_support; } - if (dsi_mode.priv_info->roi_caps.enabled) { - memcpy(&mode_info->roi_caps, &dsi_mode.priv_info->roi_caps, - sizeof(dsi_mode.priv_info->roi_caps)); + if (dsi_mode->priv_info->roi_caps.enabled) { + memcpy(&mode_info->roi_caps, &dsi_mode->priv_info->roi_caps, + sizeof(dsi_mode->priv_info->roi_caps)); } mode_info->allowed_mode_switches = - dsi_mode.priv_info->allowed_mode_switch; + dsi_mode->priv_info->allowed_mode_switch; return 0; } @@ -766,15 +806,20 @@ void dsi_connector_put_modes(struct drm_connector *connector, void *display) { struct drm_display_mode *drm_mode; - struct dsi_display_mode dsi_mode; + struct dsi_display_mode dsi_mode, *full_dsi_mode = NULL; struct dsi_display *dsi_display; + int rc = 0; if (!connector || !display) return; list_for_each_entry(drm_mode, &connector->modes, head) { convert_to_dsi_mode(drm_mode, &dsi_mode); - dsi_display_put_mode(display, &dsi_mode); + rc = dsi_display_find_mode(display, &dsi_mode, &full_dsi_mode); + if (rc) + continue; + + dsi_display_put_mode(display, full_dsi_mode); } /* free the display structure modes also */ @@ -964,6 +1009,7 @@ enum drm_mode_status dsi_conn_mode_valid(struct drm_connector *connector, void *display, const struct msm_resource_caps_info *avail_res) { struct dsi_display_mode dsi_mode; + struct dsi_display_mode *full_dsi_mode = NULL; int rc; if (!connector || !mode) { @@ -972,8 +1018,13 @@ enum drm_mode_status dsi_conn_mode_valid(struct drm_connector *connector, } convert_to_dsi_mode(mode, &dsi_mode); + rc = dsi_display_find_mode(display, &dsi_mode, &full_dsi_mode); + if (rc) { + DSI_ERR("could not find mode %s\n", mode->name); + return MODE_ERROR; + } - rc = dsi_display_validate_mode(display, &dsi_mode, + rc = dsi_display_validate_mode(display, full_dsi_mode, DSI_VALIDATE_FLAG_ALLOW_ADJUST); if (rc) { DSI_ERR("mode not supported, rc=%d\n", rc); diff --git a/msm/msm_atomic.c b/msm/msm_atomic.c index aefe75c96b..790bf0f55f 100644 --- a/msm/msm_atomic.c +++ b/msm/msm_atomic.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2014 Red Hat * Author: Rob Clark * @@ -40,16 +40,25 @@ static inline bool _msm_seamless_for_crtc(struct drm_atomic_state *state, { struct drm_connector *connector = NULL; struct drm_connector_state *conn_state = NULL; + struct msm_display_mode *msm_mode; + struct msm_drm_private *priv = state->dev->dev_private; int i = 0; int conn_cnt = 0; - if (msm_is_mode_seamless(&crtc_state->mode) || - msm_is_mode_seamless_vrr(&crtc_state->adjusted_mode) || - msm_is_mode_seamless_poms(&crtc_state->adjusted_mode) || - msm_is_mode_seamless_dyn_clk(&crtc_state->adjusted_mode)) + if (!priv || !priv->kms || !priv->kms->funcs->get_msm_mode) + return false; + + msm_mode = priv->kms->funcs->get_msm_mode(crtc_state); + if (!msm_mode) + return false; + + if (msm_is_mode_seamless(msm_mode) || + msm_is_mode_seamless_vrr(msm_mode) || + msm_is_mode_seamless_poms(msm_mode) || + msm_is_mode_seamless_dyn_clk(msm_mode)) return true; - if (msm_is_mode_seamless_dms(&crtc_state->adjusted_mode) && !enable) + if (msm_is_mode_seamless_dms(msm_mode) && !enable) return true; if (!crtc_state->mode_changed && crtc_state->connectors_changed) { @@ -71,6 +80,9 @@ static inline bool _msm_seamless_for_crtc(struct drm_atomic_state *state, static inline bool _msm_seamless_for_conn(struct drm_connector *connector, struct drm_connector_state *old_conn_state, bool enable) { + struct msm_display_mode *msm_mode; + struct msm_drm_private *priv = connector->dev->dev_private; + if (!old_conn_state || !old_conn_state->crtc) return false; @@ -88,19 +100,17 @@ static inline bool _msm_seamless_for_conn(struct drm_connector *connector, old_conn_state->crtc->state->connectors_changed) return false; - if (msm_is_mode_seamless(&old_conn_state->crtc->state->mode)) - return true; + if (!priv || !priv->kms || !priv->kms->funcs->get_msm_mode) + return false; - if (msm_is_mode_seamless_vrr( - &old_conn_state->crtc->state->adjusted_mode)) - return true; + msm_mode = priv->kms->funcs->get_msm_mode(old_conn_state->crtc->state); + if (!msm_mode) + return false; - if (msm_is_mode_seamless_dyn_clk( - &old_conn_state->crtc->state->adjusted_mode)) - return true; - - if (msm_is_mode_seamless_dms( - &old_conn_state->crtc->state->adjusted_mode)) + if (msm_is_mode_seamless(msm_mode) || + msm_is_mode_seamless_vrr(msm_mode) || + msm_is_mode_seamless_dyn_clk(msm_mode) || + msm_is_mode_seamless_dms(msm_mode)) return true; return false; @@ -359,6 +369,7 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; + struct msm_display_mode *msm_mode; /* Need to filter out CRTCs where only planes change. */ if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) @@ -382,8 +393,14 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, funcs->commit(crtc); } - if (msm_needs_vblank_pre_modeset( - &new_crtc_state->adjusted_mode)) + if (!kms->funcs || !kms->funcs->get_msm_mode) + continue; + + msm_mode = kms->funcs->get_msm_mode(new_crtc_state); + if (!msm_mode) + continue; + + if (msm_needs_vblank_pre_modeset(msm_mode)) drm_crtc_wait_one_vblank(crtc); } diff --git a/msm/msm_drv.h b/msm/msm_drv.h index 3211c46c9c..f3ceffa725 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -295,6 +295,18 @@ enum panel_op_mode { MSM_DISPLAY_MODE_MAX, }; +/** + * struct msm_display_mode - wrapper for drm_display_mode + * @base: drm_display_mode attached to this msm_mode + * @private_flags: integer holding private driver mode flags + * @private: pointer to private driver information + */ +struct msm_display_mode { + struct drm_display_mode *base; + u32 private_flags; + u32 *private; +}; + /** * struct msm_ratio - integer ratio * @numer: numerator diff --git a/msm/msm_kms.h b/msm/msm_kms.h index c395acd310..e7266ab153 100644 --- a/msm/msm_kms.h +++ b/msm/msm_kms.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -67,6 +67,8 @@ struct msm_kms_funcs { void (*commit)(struct msm_kms *kms, struct drm_atomic_state *state); void (*complete_commit)(struct msm_kms *kms, struct drm_atomic_state *state); + struct msm_display_mode *(*get_msm_mode)( + struct drm_crtc_state *c_state); /* functions to wait for atomic commit completed on each CRTC */ void (*wait_for_crtc_commit_done)(struct msm_kms *kms, struct drm_crtc *crtc); @@ -206,45 +208,45 @@ struct msm_kms *sde_kms_init(struct drm_device *dev); /** * Mode Set Utility Functions */ -static inline bool msm_is_mode_seamless(const struct drm_display_mode *mode) +static inline bool msm_is_mode_seamless(const struct msm_display_mode *mode) { return (mode->private_flags & DRM_MODE_FLAG_SEAMLESS); } -static inline bool msm_is_mode_seamless_dms(const struct drm_display_mode *mode) +static inline bool msm_is_mode_seamless_dms(const struct msm_display_mode *mode) { return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DMS) : false; } -static inline bool msm_is_mode_dynamic_fps(const struct drm_display_mode *mode) +static inline bool msm_is_mode_dynamic_fps(const struct msm_display_mode *mode) { return ((mode->private_flags & DRM_MODE_FLAG_SEAMLESS) && (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS)); } -static inline bool msm_is_mode_seamless_vrr(const struct drm_display_mode *mode) +static inline bool msm_is_mode_seamless_vrr(const struct msm_display_mode *mode) { return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_VRR) : false; } static inline bool msm_is_mode_seamless_poms( - const struct drm_display_mode *mode) + const struct msm_display_mode *mode) { return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_POMS) : false; } static inline bool msm_is_mode_seamless_dyn_clk( - const struct drm_display_mode *mode) + const struct msm_display_mode *mode) { return mode ? (mode->private_flags & MSM_MODE_FLAG_SEAMLESS_DYN_CLK) : false; } static inline bool msm_needs_vblank_pre_modeset( - const struct drm_display_mode *mode) + const struct msm_display_mode *mode) { return (mode->private_flags & MSM_MODE_FLAG_VBLANK_PRE_MODESET); } diff --git a/msm/sde/sde_connector.c b/msm/sde/sde_connector.c index aa1bc31e47..817cadb26a 100644 --- a/msm/sde/sde_connector.c +++ b/msm/sde/sde_connector.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -421,6 +421,22 @@ static void sde_connector_get_avail_res_info(struct drm_connector *conn, avail_res->max_mixer_width = sde_kms->catalog->max_mixer_width; } +int sde_connector_set_msm_mode(struct drm_connector_state *conn_state, + struct drm_display_mode *adj_mode) +{ + struct sde_connector_state *c_state; + + c_state = to_sde_connector_state(conn_state); + if (!c_state || !adj_mode) { + SDE_ERROR("invalid params c_state: %d, adj_mode %d\n", + c_state == NULL, adj_mode == NULL); + return -EINVAL; + } + + c_state->msm_mode.base = adj_mode; + return 0; +} + int sde_connector_get_mode_info(struct drm_connector *conn, const struct drm_display_mode *drm_mode, struct msm_mode_info *mode_info) diff --git a/msm/sde/sde_connector.h b/msm/sde/sde_connector.h index 7d7813be6f..f322848057 100644 --- a/msm/sde/sde_connector.h +++ b/msm/sde/sde_connector.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #ifndef _SDE_CONNECTOR_H_ @@ -612,6 +612,7 @@ struct sde_connector { * @mode_info: local copy of msm_mode_info struct * @hdr_meta: HDR metadata info passed from userspace * @dyn_hdr_meta: Dynamic HDR metadata payload and state tracking + * @msm_mode: struct containing drm_mode and downstream private variables * @old_topology_name: topology of previous atomic state. remove this in later * kernel versions which provide drm_atomic_state old_state pointers */ @@ -626,6 +627,7 @@ struct sde_connector_state { struct msm_mode_info mode_info; struct drm_msm_ext_hdr_metadata hdr_meta; struct sde_connector_dyn_hdr_metadata dyn_hdr_meta; + struct msm_display_mode msm_mode; enum sde_rm_topology_name old_topology_name; }; @@ -1026,6 +1028,15 @@ static inline int sde_connector_state_get_compression_info( return 0; } +/** +* sde_connector_set_msm_mode - set msm_mode for connector state +* @conn_state: Pointer to drm connector state structure +* @adj_mode: Pointer to adjusted display mode for display +* Returns: Zero on success +*/ +int sde_connector_set_msm_mode(struct drm_connector_state *conn_state, + struct drm_display_mode *adj_mode); + /** * sde_connector_get_mode_info - retrieve mode info for given mode * @connector: Pointer to drm connector structure diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index e776fe5cf7..3808d10295 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -40,6 +40,7 @@ #include "sde_power_handle.h" #include "sde_core_perf.h" #include "sde_trace.h" +#include "msm_drv.h" #define SDE_PSTATES_MAX (SDE_STAGE_MAX * 4) #define SDE_MULTIRECT_PLANE_MAX (SDE_STAGE_MAX * 2) @@ -455,15 +456,83 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) kfree(sde_crtc); } +struct msm_display_mode *sde_crtc_get_msm_mode(struct drm_crtc_state *c_state) +{ + struct drm_connector *connector; + struct drm_encoder *encoder; + struct sde_connector_state *conn_state; + bool encoder_valid = false; + + drm_for_each_encoder_mask(encoder, c_state->crtc->dev, + c_state->encoder_mask) { + if (!sde_encoder_in_clone_mode(encoder)) { + encoder_valid = true; + break; + } + } + + if (!encoder_valid) + return NULL; + + connector = sde_encoder_get_connector(c_state->crtc->dev, encoder); + if (!connector) + return NULL; + + conn_state = to_sde_connector_state(connector->state); + if (!conn_state) + return NULL; + + return &conn_state->msm_mode; +} + static bool sde_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct msm_display_mode *msm_mode; + struct drm_crtc_state *c_state; + struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_connector_state *new_conn_state; + struct sde_connector_state *c_conn_state; + bool encoder_valid = false; + int i; + SDE_DEBUG("\n"); - if ((msm_is_mode_seamless(adjusted_mode) || - (msm_is_mode_seamless_vrr(adjusted_mode) || - msm_is_mode_seamless_dyn_clk(adjusted_mode))) && + c_state = container_of(adjusted_mode, struct drm_crtc_state, + adjusted_mode); + + drm_for_each_encoder_mask(encoder, c_state->crtc->dev, + c_state->encoder_mask) { + if (!sde_encoder_in_clone_mode(encoder)) { + encoder_valid = true; + break; + } + } + + if (!encoder_valid) { + SDE_ERROR("encoder not found\n"); + return true; + } + + for_each_new_connector_in_state(c_state->state, connector, + new_conn_state, i) { + if (new_conn_state->best_encoder == encoder){ + break; + } + } + + c_conn_state = to_sde_connector_state(new_conn_state); + if (!c_conn_state) { + SDE_ERROR("could not get connector state\n"); + return true; + } + + msm_mode = &c_conn_state->msm_mode; + if ((msm_is_mode_seamless(msm_mode) || + (msm_is_mode_seamless_vrr(msm_mode) || + msm_is_mode_seamless_dyn_clk(msm_mode))) && (!crtc->enabled)) { SDE_ERROR("crtc state prevents seamless transition\n"); return false; @@ -4266,6 +4335,7 @@ static void sde_crtc_enable(struct drm_crtc *crtc, u32 power_on; int ret, i; struct sde_crtc_state *cstate; + struct msm_display_mode *msm_mode; if (!crtc || !crtc->dev || !crtc->dev->dev_private) { SDE_ERROR("invalid crtc\n"); @@ -4302,12 +4372,17 @@ static void sde_crtc_enable(struct drm_crtc *crtc, * change is also consider to enable/disable UIDLE */ sde_core_perf_crtc_update_uidle(crtc, true); + msm_mode = sde_crtc_get_msm_mode(crtc->state); + if (!msm_mode){ + SDE_ERROR("invalid msm mode, %s\n", + crtc->state->adjusted_mode.name); + return; + } /* return early if crtc is already enabled, do this after UIDLE check */ if (sde_crtc->enabled) { - if (msm_is_mode_seamless_dms(&crtc->state->adjusted_mode) || - msm_is_mode_seamless_dyn_clk(&crtc->state->adjusted_mode)) - + if (msm_is_mode_seamless_dms(msm_mode) || + msm_is_mode_seamless_dyn_clk(msm_mode)) SDE_DEBUG("%s extra crtc enable expected during DMS\n", sde_crtc->name); else diff --git a/msm/sde/sde_crtc.h b/msm/sde/sde_crtc.h index bec4d8cd41..2d71ead635 100644 --- a/msm/sde/sde_crtc.h +++ b/msm/sde/sde_crtc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -588,6 +588,13 @@ static inline int sde_crtc_request_frame_reset(struct drm_crtc *crtc) */ int sde_crtc_vblank(struct drm_crtc *crtc, bool en); +/** + * sde_crtc_get_msm_mode - get msm_mode for a given crtc state + * @c_state: Pointer to drm crtc state object + * Returns: msm_display_mode corresponding to this crtc state, or NULL if none + */ +struct msm_display_mode *sde_crtc_get_msm_mode(struct drm_crtc_state *c_state); + /** * sde_crtc_commit_kickoff - trigger kickoff of the commit for this crtc * @crtc: Pointer to drm crtc object diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 6a3af98a15..907c6bb4c1 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -961,6 +961,9 @@ static int sde_encoder_virt_atomic_check( sde_conn = to_sde_connector(conn_state->connector); sde_conn_state = to_sde_connector_state(conn_state); sde_crtc_state = to_sde_crtc_state(crtc_state); + ret = sde_connector_set_msm_mode(conn_state, adj_mode); + if (ret) + return ret; SDE_EVT32(DRMID(drm_enc), crtc_state->mode_changed, crtc_state->active_changed, crtc_state->connectors_changed); @@ -1006,18 +1009,18 @@ static int sde_encoder_virt_atomic_check( CONNECTOR_PROP_QSYNC_MODE); if (has_modeset && qsync_dirty && - (msm_is_mode_seamless_poms(adj_mode) || - msm_is_mode_seamless_dms(adj_mode) || - msm_is_mode_seamless_dyn_clk(adj_mode))) { + (msm_is_mode_seamless_poms(&sde_conn_state->msm_mode) || + msm_is_mode_seamless_dms(&sde_conn_state->msm_mode) || + msm_is_mode_seamless_dyn_clk(&sde_conn_state->msm_mode))) { SDE_ERROR("invalid qsync update during modeset priv flag:%x\n", - adj_mode->private_flags); + sde_conn_state->msm_mode.private_flags); return -EINVAL; } - SDE_EVT32(DRMID(drm_enc), adj_mode->flags, adj_mode->private_flags, - old_top, adj_mode->vrefresh, adj_mode->hdisplay, - adj_mode->vdisplay, adj_mode->htotal, adj_mode->vtotal); - + SDE_EVT32(DRMID(drm_enc), adj_mode->flags, + sde_conn_state->msm_mode.private_flags, + old_top, adj_mode->vrefresh, adj_mode->hdisplay, + adj_mode->vdisplay, adj_mode->htotal, adj_mode->vtotal); return ret; } @@ -2095,7 +2098,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, } static void sde_encoder_virt_mode_switch(struct drm_encoder *drm_enc, - enum sde_intf_mode intf_mode, struct drm_display_mode *adj_mode) + enum sde_intf_mode intf_mode, struct msm_display_mode *adj_mode) { int i = 0; struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); @@ -2112,19 +2115,21 @@ static void sde_encoder_virt_mode_switch(struct drm_encoder *drm_enc, sde_enc->phys_encs[i] = sde_enc->phys_vid_encs[i]; SDE_DEBUG_ENC(sde_enc, "switch to video physical encoder\n"); - SDE_EVT32(DRMID(&sde_enc->base), intf_mode, adj_mode->flags, - adj_mode->private_flags, SDE_EVTLOG_FUNC_CASE1); + SDE_EVT32(DRMID(&sde_enc->base), intf_mode, + adj_mode->base->flags, adj_mode->private_flags, + SDE_EVTLOG_FUNC_CASE1); } else if (intf_mode == INTF_MODE_VIDEO) { for (i = 0; i < sde_enc->num_phys_encs; i++) sde_enc->phys_encs[i] = sde_enc->phys_cmd_encs[i]; SDE_DEBUG_ENC(sde_enc, "switch to command physical encoder\n"); - SDE_EVT32(DRMID(&sde_enc->base), intf_mode, adj_mode->flags, - adj_mode->private_flags, SDE_EVTLOG_FUNC_CASE2); + SDE_EVT32(DRMID(&sde_enc->base), intf_mode, + adj_mode->base->flags, adj_mode->private_flags, + SDE_EVTLOG_FUNC_CASE2); } } -static struct drm_connector *_sde_encoder_get_connector( +struct drm_connector *sde_encoder_get_connector( struct drm_device *dev, struct drm_encoder *drm_enc) { struct drm_connector_list_iter conn_iter; @@ -2227,7 +2232,7 @@ static bool sde_encoder_detect_panel_mode_switch( } static int sde_encoder_virt_modeset_rc(struct drm_encoder *drm_enc, - struct drm_display_mode *adj_mode, bool pre_modeset) + struct msm_display_mode *msm_mode, bool pre_modeset) { struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); enum sde_intf_mode intf_mode; @@ -2239,8 +2244,8 @@ static int sde_encoder_virt_modeset_rc(struct drm_encoder *drm_enc, if (pre_modeset) { intf_mode = sde_encoder_get_intf_mode(drm_enc); - if (msm_is_mode_seamless_dms(adj_mode) || - (msm_is_mode_seamless_dyn_clk(adj_mode) && + if (msm_is_mode_seamless_dms(msm_mode) || + (msm_is_mode_seamless_dyn_clk(msm_mode) && is_cmd_mode)) { /* restore resource state before releasing them */ ret = sde_encoder_resource_control(drm_enc, @@ -2257,20 +2262,20 @@ static int sde_encoder_virt_modeset_rc(struct drm_encoder *drm_enc, * modeset to guarantee previous kickoff has finished. */ sde_encoder_dce_disable(sde_enc); - } else if (sde_encoder_detect_panel_mode_switch(adj_mode, + } else if (sde_encoder_detect_panel_mode_switch(msm_mode->base, intf_mode)) { _sde_encoder_modeset_helper_locked(drm_enc, SDE_ENC_RC_EVENT_PRE_MODESET); sde_encoder_virt_mode_switch(drm_enc, intf_mode, - adj_mode); + msm_mode); } } else { - if (msm_is_mode_seamless_dms(adj_mode) || - (msm_is_mode_seamless_dyn_clk(adj_mode) && + if (msm_is_mode_seamless_dms(msm_mode) || + (msm_is_mode_seamless_dyn_clk(msm_mode) && is_cmd_mode)) sde_encoder_resource_control(&sde_enc->base, SDE_ENC_RC_EVENT_POST_MODESET); - else if (msm_is_mode_seamless_poms(adj_mode)) + else if (msm_is_mode_seamless_poms(msm_mode)) _sde_encoder_modeset_helper_locked(drm_enc, SDE_ENC_RC_EVENT_POST_MODESET); } @@ -2285,6 +2290,8 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, struct sde_encoder_virt *sde_enc; struct sde_kms *sde_kms; struct drm_connector *conn; + struct sde_connector_state *c_state; + struct msm_display_mode *msm_mode; int i = 0, ret; int num_lm, num_intf, num_pp_per_intf; @@ -2319,7 +2326,7 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, sde_crtc_set_qos_dirty(drm_enc->crtc); /* get and store the mode_info */ - conn = _sde_encoder_get_connector(sde_kms->dev, drm_enc); + conn = sde_encoder_get_connector(sde_kms->dev, drm_enc); if (!conn) { SDE_ERROR_ENC(sde_enc, "failed to find attached connector\n"); return; @@ -2330,9 +2337,15 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, sde_connector_state_get_mode_info(conn->state, &sde_enc->mode_info); sde_encoder_dce_set_bpp(sde_enc->mode_info, sde_enc->crtc); + c_state = to_sde_connector_state(conn->state); + if (!c_state) { + SDE_ERROR_ENC(sde_enc, "could not get connector state"); + return; + } /* release resources before seamless mode change */ - ret = sde_encoder_virt_modeset_rc(drm_enc, adj_mode, true); + msm_mode = &c_state->msm_mode; + ret = sde_encoder_virt_modeset_rc(drm_enc, msm_mode, true); if (ret) return; @@ -2374,7 +2387,7 @@ static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc, } /* update resources after seamless mode change */ - sde_encoder_virt_modeset_rc(drm_enc, adj_mode, false); + sde_encoder_virt_modeset_rc(drm_enc, msm_mode, false); } void sde_encoder_control_te(struct drm_encoder *drm_enc, bool enable) @@ -2694,8 +2707,10 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc = NULL; int i, ret = 0; + struct sde_connector_state *c_state; struct msm_compression_info *comp_info = NULL; struct drm_display_mode *cur_mode = NULL; + struct msm_display_mode *msm_mode; struct msm_display_info *disp_info; if (!drm_enc || !drm_enc->crtc) { @@ -2736,12 +2751,18 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) } _sde_encoder_input_handler_register(drm_enc); + c_state = to_sde_connector_state(sde_enc->cur_master->connector->state); + if (!c_state) { + SDE_ERROR("invalid connector state\n"); + return; + } + msm_mode = &c_state->msm_mode; if ((drm_enc->crtc->state->connectors_changed && sde_encoder_in_clone_mode(drm_enc)) || - !(msm_is_mode_seamless_vrr(cur_mode) - || msm_is_mode_seamless_dms(cur_mode) - || msm_is_mode_seamless_dyn_clk(cur_mode))) + !(msm_is_mode_seamless_vrr(msm_mode) + || msm_is_mode_seamless_dms(msm_mode) + || msm_is_mode_seamless_dyn_clk(msm_mode))) kthread_init_delayed_work(&sde_enc->delayed_off_work, sde_encoder_off_work); @@ -2785,8 +2806,8 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) * already. Invoke restore to reconfigure the * new mode. */ - if ((msm_is_mode_seamless_dms(cur_mode) || - msm_is_mode_seamless_dyn_clk(cur_mode)) && + if ((msm_is_mode_seamless_dms(msm_mode) || + msm_is_mode_seamless_dyn_clk(msm_mode)) && phys->ops.restore) phys->ops.restore(phys); else if (phys->ops.enable) @@ -2799,8 +2820,8 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) sde_enc->misr_frame_count); } - if ((msm_is_mode_seamless_dms(cur_mode) || - msm_is_mode_seamless_dyn_clk(cur_mode)) && + if ((msm_is_mode_seamless_dms(msm_mode) || + msm_is_mode_seamless_dyn_clk(msm_mode)) && sde_enc->cur_master->ops.restore) sde_enc->cur_master->ops.restore(sde_enc->cur_master); else if (sde_enc->cur_master->ops.enable) @@ -5285,9 +5306,9 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder, return -EINVAL; } + drm_mode = &encoder->crtc->state->adjusted_mode; ret = sde_connector_get_mode_info(&sde_conn->base, - &encoder->crtc->state->adjusted_mode, - &sde_conn_state->mode_info); + drm_mode, &sde_conn_state->mode_info); if (ret) { SDE_ERROR_ENC(sde_enc, "conn: ->get_mode_info failed. ret=%d\n", ret); @@ -5314,7 +5335,6 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder, SDE_DEBUG_ENC(sde_enc, "connector topology = %llu\n", sde_connector_get_topology_name(conn)); - drm_mode = &encoder->crtc->state->adjusted_mode; SDE_DEBUG_ENC(sde_enc, "hdisplay = %d, vdisplay = %d\n", drm_mode->hdisplay, drm_mode->vdisplay); drm_set_preferred_mode(conn, drm_mode->hdisplay, drm_mode->vdisplay); diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 8edfbe98c9..681eebb4cc 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -559,6 +559,14 @@ void sde_encoder_uidle_enable(struct drm_encoder *drm_enc, bool enable); */ void sde_encoder_irq_control(struct drm_encoder *drm_enc, bool enable); +/**sde_encoder_get_connector - get connector corresponding to encoder + * @dev: Pointer to drm device structure + * @drm_enc: Pointer to drm encoder structure + * Returns: drm connector if found, null if not found + */ +struct drm_connector *sde_encoder_get_connector(struct drm_device *dev, + struct drm_encoder *drm_enc); + /* * sde_encoder_get_dfps_maxfps - get dynamic FPS max frame rate of the given encoder diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index 7e444aa4dc..3533947790 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[drm:%s:%d] " fmt, __func__, __LINE__ @@ -1152,23 +1152,25 @@ static void sde_encoder_phys_vid_handle_post_kickoff( static void sde_encoder_phys_vid_prepare_for_commit( struct sde_encoder_phys *phys_enc) { - struct drm_crtc *crtc; + struct sde_connector_state *c_state; if (!phys_enc || !phys_enc->parent) { SDE_ERROR("invalid encoder parameters\n"); return; } - crtc = phys_enc->parent->crtc; - if (!crtc || !crtc->state) { - SDE_ERROR("invalid crtc state\n"); - return; - } + if (phys_enc->connector && phys_enc->connector->state) { + c_state = to_sde_connector_state(phys_enc->connector->state); + if (!c_state) { + SDE_ERROR("invalid connector state\n"); + return; + } - if (!msm_is_mode_seamless_vrr(&crtc->state->adjusted_mode) + if (!msm_is_mode_seamless_vrr(&c_state->msm_mode) && sde_connector_is_qsync_updated(phys_enc->connector)) - _sde_encoder_phys_vid_avr_ctrl(phys_enc); + _sde_encoder_phys_vid_avr_ctrl(phys_enc); + } } static void sde_encoder_phys_vid_irq_control(struct sde_encoder_phys *phys_enc, diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 299a0b0daf..5a468a09db 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -3507,6 +3507,11 @@ static void _sde_kms_pm_suspend_idle_helper(struct sde_kms *sde_kms, kthread_flush_worker(&priv->pp_event_worker); } +struct msm_display_mode *sde_kms_get_msm_mode(struct drm_crtc_state *c_state) +{ + return sde_crtc_get_msm_mode(c_state); +} + static int sde_kms_pm_suspend(struct device *dev) { struct drm_device *ddev; @@ -3726,6 +3731,7 @@ static const struct msm_kms_funcs kms_funcs = { .prepare_commit = sde_kms_prepare_commit, .commit = sde_kms_commit, .complete_commit = sde_kms_complete_commit, + .get_msm_mode = sde_kms_get_msm_mode, .wait_for_crtc_commit_done = sde_kms_wait_for_commit_done, .wait_for_tx_complete = sde_kms_wait_for_frame_transfer_complete, .check_modified_format = sde_format_check_modified_format,