From 50a879cfdb87baad4edb50f7b443177a592998ed Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 14 Jun 2021 15:28:30 +0200 Subject: [PATCH 0010/1085] drm/vc4: hvs: Force modeset on gamma lut change The HVS Gamma block can only be updated when idle, so we need to disable the HVS channel when the gamma property is set in an atomic commit. Since the pixelvalve cannot have its assigned channel halted without stalling unless it's disabled as well, in our case that means forcing a full disable / enable cycle on the pipeline. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 17 +++++++++++++++++ drivers/gpu/drm/vc4/vc4_drv.h | 3 +++ drivers/gpu/drm/vc4/vc4_hvs.c | 32 +++++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -303,6 +303,23 @@ struct drm_encoder *vc4_get_crtc_encoder return NULL; } +#define drm_for_each_connector_mask(connector, dev, connector_mask) \ + list_for_each_entry((connector), &(dev)->mode_config.connector_list, head) \ + for_each_if ((connector_mask) & drm_connector_mask(connector)) + +struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct drm_connector *connector; + + WARN_ON(hweight32(state->connector_mask) > 1); + + drm_for_each_connector_mask(connector, crtc->dev, state->connector_mask) + return connector; + + return NULL; +} + static void vc4_crtc_pixelvalve_reset(struct drm_crtc *crtc) { struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -613,6 +613,9 @@ vc4_crtc_to_vc4_pv_data(const struct vc4 return container_of_const(data, struct vc4_pv_data, base); } +struct drm_connector *vc4_get_crtc_connector(struct drm_crtc *crtc, + struct drm_crtc_state *state); + struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc, struct drm_crtc_state *state); --- a/drivers/gpu/drm/vc4/vc4_hvs.c +++ b/drivers/gpu/drm/vc4/vc4_hvs.c @@ -596,6 +596,36 @@ out: drm_dev_exit(idx); } +static int vc4_hvs_gamma_check(struct drm_crtc *crtc, + struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + struct drm_connector_state *conn_state; + struct drm_connector *connector; + struct drm_device *dev = crtc->dev; + struct vc4_dev *vc4 = to_vc4_dev(dev); + + if (!vc4->is_vc5) + return 0; + + if (!crtc_state->color_mgmt_changed) + return 0; + + connector = vc4_get_crtc_connector(crtc, crtc_state); + if (!connector) + return -EINVAL; + + if (!(connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) + return 0; + + conn_state = drm_atomic_get_connector_state(state, connector); + if (!conn_state) + return -EINVAL; + + crtc_state->mode_changed = true; + return 0; +} + int vc4_hvs_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state) { struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); @@ -626,7 +656,7 @@ int vc4_hvs_atomic_check(struct drm_crtc if (ret) return ret; - return 0; + return vc4_hvs_gamma_check(crtc, state); } static void vc4_hvs_install_dlist(struct drm_crtc *crtc)