18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright © 2015 Intel Corporation
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation
78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the next
128c2ecf20Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
138c2ecf20Sopenharmony_ci * Software.
148c2ecf20Sopenharmony_ci *
158c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
178c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
188c2ecf20Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
198c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
208c2ecf20Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
218c2ecf20Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/**
258c2ecf20Sopenharmony_ci * DOC: atomic modeset support
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci * The functions here implement the state management and hardware programming
288c2ecf20Sopenharmony_ci * dispatch required by the atomic modeset infrastructure.
298c2ecf20Sopenharmony_ci * See intel_atomic_plane.c for the plane-specific atomic functionality.
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h>
338c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h>
348c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h>
358c2ecf20Sopenharmony_ci#include <drm/drm_plane_helper.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include "intel_atomic.h"
388c2ecf20Sopenharmony_ci#include "intel_cdclk.h"
398c2ecf20Sopenharmony_ci#include "intel_display_types.h"
408c2ecf20Sopenharmony_ci#include "intel_global_state.h"
418c2ecf20Sopenharmony_ci#include "intel_hdcp.h"
428c2ecf20Sopenharmony_ci#include "intel_psr.h"
438c2ecf20Sopenharmony_ci#include "intel_sprite.h"
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/**
468c2ecf20Sopenharmony_ci * intel_digital_connector_atomic_get_property - hook for connector->atomic_get_property.
478c2ecf20Sopenharmony_ci * @connector: Connector to get the property for.
488c2ecf20Sopenharmony_ci * @state: Connector state to retrieve the property from.
498c2ecf20Sopenharmony_ci * @property: Property to retrieve.
508c2ecf20Sopenharmony_ci * @val: Return value for the property.
518c2ecf20Sopenharmony_ci *
528c2ecf20Sopenharmony_ci * Returns the atomic property value for a digital connector.
538c2ecf20Sopenharmony_ci */
548c2ecf20Sopenharmony_ciint intel_digital_connector_atomic_get_property(struct drm_connector *connector,
558c2ecf20Sopenharmony_ci						const struct drm_connector_state *state,
568c2ecf20Sopenharmony_ci						struct drm_property *property,
578c2ecf20Sopenharmony_ci						u64 *val)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
608c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(dev);
618c2ecf20Sopenharmony_ci	struct intel_digital_connector_state *intel_conn_state =
628c2ecf20Sopenharmony_ci		to_intel_digital_connector_state(state);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (property == dev_priv->force_audio_property)
658c2ecf20Sopenharmony_ci		*val = intel_conn_state->force_audio;
668c2ecf20Sopenharmony_ci	else if (property == dev_priv->broadcast_rgb_property)
678c2ecf20Sopenharmony_ci		*val = intel_conn_state->broadcast_rgb;
688c2ecf20Sopenharmony_ci	else {
698c2ecf20Sopenharmony_ci		drm_dbg_atomic(&dev_priv->drm,
708c2ecf20Sopenharmony_ci			       "Unknown property [PROP:%d:%s]\n",
718c2ecf20Sopenharmony_ci			       property->base.id, property->name);
728c2ecf20Sopenharmony_ci		return -EINVAL;
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return 0;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/**
798c2ecf20Sopenharmony_ci * intel_digital_connector_atomic_set_property - hook for connector->atomic_set_property.
808c2ecf20Sopenharmony_ci * @connector: Connector to set the property for.
818c2ecf20Sopenharmony_ci * @state: Connector state to set the property on.
828c2ecf20Sopenharmony_ci * @property: Property to set.
838c2ecf20Sopenharmony_ci * @val: New value for the property.
848c2ecf20Sopenharmony_ci *
858c2ecf20Sopenharmony_ci * Sets the atomic property value for a digital connector.
868c2ecf20Sopenharmony_ci */
878c2ecf20Sopenharmony_ciint intel_digital_connector_atomic_set_property(struct drm_connector *connector,
888c2ecf20Sopenharmony_ci						struct drm_connector_state *state,
898c2ecf20Sopenharmony_ci						struct drm_property *property,
908c2ecf20Sopenharmony_ci						u64 val)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct drm_device *dev = connector->dev;
938c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(dev);
948c2ecf20Sopenharmony_ci	struct intel_digital_connector_state *intel_conn_state =
958c2ecf20Sopenharmony_ci		to_intel_digital_connector_state(state);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (property == dev_priv->force_audio_property) {
988c2ecf20Sopenharmony_ci		intel_conn_state->force_audio = val;
998c2ecf20Sopenharmony_ci		return 0;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if (property == dev_priv->broadcast_rgb_property) {
1038c2ecf20Sopenharmony_ci		intel_conn_state->broadcast_rgb = val;
1048c2ecf20Sopenharmony_ci		return 0;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	drm_dbg_atomic(&dev_priv->drm, "Unknown property [PROP:%d:%s]\n",
1088c2ecf20Sopenharmony_ci		       property->base.id, property->name);
1098c2ecf20Sopenharmony_ci	return -EINVAL;
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic bool blob_equal(const struct drm_property_blob *a,
1138c2ecf20Sopenharmony_ci		       const struct drm_property_blob *b)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	if (a && b)
1168c2ecf20Sopenharmony_ci		return a->length == b->length &&
1178c2ecf20Sopenharmony_ci			!memcmp(a->data, b->data, a->length);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return !a == !b;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ciint intel_digital_connector_atomic_check(struct drm_connector *conn,
1238c2ecf20Sopenharmony_ci					 struct drm_atomic_state *state)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct drm_connector_state *new_state =
1268c2ecf20Sopenharmony_ci		drm_atomic_get_new_connector_state(state, conn);
1278c2ecf20Sopenharmony_ci	struct intel_digital_connector_state *new_conn_state =
1288c2ecf20Sopenharmony_ci		to_intel_digital_connector_state(new_state);
1298c2ecf20Sopenharmony_ci	struct drm_connector_state *old_state =
1308c2ecf20Sopenharmony_ci		drm_atomic_get_old_connector_state(state, conn);
1318c2ecf20Sopenharmony_ci	struct intel_digital_connector_state *old_conn_state =
1328c2ecf20Sopenharmony_ci		to_intel_digital_connector_state(old_state);
1338c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	intel_hdcp_atomic_check(conn, old_state, new_state);
1368c2ecf20Sopenharmony_ci	intel_psr_atomic_check(conn, old_state, new_state);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	if (!new_state->crtc)
1398c2ecf20Sopenharmony_ci		return 0;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	/*
1448c2ecf20Sopenharmony_ci	 * These properties are handled by fastset, and might not end
1458c2ecf20Sopenharmony_ci	 * up in a modeset.
1468c2ecf20Sopenharmony_ci	 */
1478c2ecf20Sopenharmony_ci	if (new_conn_state->force_audio != old_conn_state->force_audio ||
1488c2ecf20Sopenharmony_ci	    new_conn_state->broadcast_rgb != old_conn_state->broadcast_rgb ||
1498c2ecf20Sopenharmony_ci	    new_conn_state->base.colorspace != old_conn_state->base.colorspace ||
1508c2ecf20Sopenharmony_ci	    new_conn_state->base.picture_aspect_ratio != old_conn_state->base.picture_aspect_ratio ||
1518c2ecf20Sopenharmony_ci	    new_conn_state->base.content_type != old_conn_state->base.content_type ||
1528c2ecf20Sopenharmony_ci	    new_conn_state->base.scaling_mode != old_conn_state->base.scaling_mode ||
1538c2ecf20Sopenharmony_ci	    !blob_equal(new_conn_state->base.hdr_output_metadata,
1548c2ecf20Sopenharmony_ci			old_conn_state->base.hdr_output_metadata))
1558c2ecf20Sopenharmony_ci		crtc_state->mode_changed = true;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	return 0;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/**
1618c2ecf20Sopenharmony_ci * intel_digital_connector_duplicate_state - duplicate connector state
1628c2ecf20Sopenharmony_ci * @connector: digital connector
1638c2ecf20Sopenharmony_ci *
1648c2ecf20Sopenharmony_ci * Allocates and returns a copy of the connector state (both common and
1658c2ecf20Sopenharmony_ci * digital connector specific) for the specified connector.
1668c2ecf20Sopenharmony_ci *
1678c2ecf20Sopenharmony_ci * Returns: The newly allocated connector state, or NULL on failure.
1688c2ecf20Sopenharmony_ci */
1698c2ecf20Sopenharmony_cistruct drm_connector_state *
1708c2ecf20Sopenharmony_ciintel_digital_connector_duplicate_state(struct drm_connector *connector)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	struct intel_digital_connector_state *state;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	state = kmemdup(connector->state, sizeof(*state), GFP_KERNEL);
1758c2ecf20Sopenharmony_ci	if (!state)
1768c2ecf20Sopenharmony_ci		return NULL;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	__drm_atomic_helper_connector_duplicate_state(connector, &state->base);
1798c2ecf20Sopenharmony_ci	return &state->base;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/**
1838c2ecf20Sopenharmony_ci * intel_connector_needs_modeset - check if connector needs a modeset
1848c2ecf20Sopenharmony_ci * @state: the atomic state corresponding to this modeset
1858c2ecf20Sopenharmony_ci * @connector: the connector
1868c2ecf20Sopenharmony_ci */
1878c2ecf20Sopenharmony_cibool
1888c2ecf20Sopenharmony_ciintel_connector_needs_modeset(struct intel_atomic_state *state,
1898c2ecf20Sopenharmony_ci			      struct drm_connector *connector)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	const struct drm_connector_state *old_conn_state, *new_conn_state;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	old_conn_state = drm_atomic_get_old_connector_state(&state->base, connector);
1948c2ecf20Sopenharmony_ci	new_conn_state = drm_atomic_get_new_connector_state(&state->base, connector);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	return old_conn_state->crtc != new_conn_state->crtc ||
1978c2ecf20Sopenharmony_ci	       (new_conn_state->crtc &&
1988c2ecf20Sopenharmony_ci		drm_atomic_crtc_needs_modeset(drm_atomic_get_new_crtc_state(&state->base,
1998c2ecf20Sopenharmony_ci									    new_conn_state->crtc)));
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistruct intel_digital_connector_state *
2038c2ecf20Sopenharmony_ciintel_atomic_get_digital_connector_state(struct intel_atomic_state *state,
2048c2ecf20Sopenharmony_ci					 struct intel_connector *connector)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	struct drm_connector_state *conn_state;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	conn_state = drm_atomic_get_connector_state(&state->base,
2098c2ecf20Sopenharmony_ci						    &connector->base);
2108c2ecf20Sopenharmony_ci	if (IS_ERR(conn_state))
2118c2ecf20Sopenharmony_ci		return ERR_CAST(conn_state);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return to_intel_digital_connector_state(conn_state);
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci/**
2178c2ecf20Sopenharmony_ci * intel_crtc_duplicate_state - duplicate crtc state
2188c2ecf20Sopenharmony_ci * @crtc: drm crtc
2198c2ecf20Sopenharmony_ci *
2208c2ecf20Sopenharmony_ci * Allocates and returns a copy of the crtc state (both common and
2218c2ecf20Sopenharmony_ci * Intel-specific) for the specified crtc.
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * Returns: The newly allocated crtc state, or NULL on failure.
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_cistruct drm_crtc_state *
2268c2ecf20Sopenharmony_ciintel_crtc_duplicate_state(struct drm_crtc *crtc)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	const struct intel_crtc_state *old_crtc_state = to_intel_crtc_state(crtc->state);
2298c2ecf20Sopenharmony_ci	struct intel_crtc_state *crtc_state;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	crtc_state = kmemdup(old_crtc_state, sizeof(*crtc_state), GFP_KERNEL);
2328c2ecf20Sopenharmony_ci	if (!crtc_state)
2338c2ecf20Sopenharmony_ci		return NULL;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	__drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->uapi);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/* copy color blobs */
2388c2ecf20Sopenharmony_ci	if (crtc_state->hw.degamma_lut)
2398c2ecf20Sopenharmony_ci		drm_property_blob_get(crtc_state->hw.degamma_lut);
2408c2ecf20Sopenharmony_ci	if (crtc_state->hw.ctm)
2418c2ecf20Sopenharmony_ci		drm_property_blob_get(crtc_state->hw.ctm);
2428c2ecf20Sopenharmony_ci	if (crtc_state->hw.gamma_lut)
2438c2ecf20Sopenharmony_ci		drm_property_blob_get(crtc_state->hw.gamma_lut);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	crtc_state->update_pipe = false;
2468c2ecf20Sopenharmony_ci	crtc_state->disable_lp_wm = false;
2478c2ecf20Sopenharmony_ci	crtc_state->disable_cxsr = false;
2488c2ecf20Sopenharmony_ci	crtc_state->update_wm_pre = false;
2498c2ecf20Sopenharmony_ci	crtc_state->update_wm_post = false;
2508c2ecf20Sopenharmony_ci	crtc_state->fifo_changed = false;
2518c2ecf20Sopenharmony_ci	crtc_state->preload_luts = false;
2528c2ecf20Sopenharmony_ci	crtc_state->inherited = false;
2538c2ecf20Sopenharmony_ci	crtc_state->wm.need_postvbl_update = false;
2548c2ecf20Sopenharmony_ci	crtc_state->fb_bits = 0;
2558c2ecf20Sopenharmony_ci	crtc_state->update_planes = 0;
2568c2ecf20Sopenharmony_ci	crtc_state->dsb = NULL;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	return &crtc_state->uapi;
2598c2ecf20Sopenharmony_ci}
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic void intel_crtc_put_color_blobs(struct intel_crtc_state *crtc_state)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	drm_property_blob_put(crtc_state->hw.degamma_lut);
2648c2ecf20Sopenharmony_ci	drm_property_blob_put(crtc_state->hw.gamma_lut);
2658c2ecf20Sopenharmony_ci	drm_property_blob_put(crtc_state->hw.ctm);
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_civoid intel_crtc_free_hw_state(struct intel_crtc_state *crtc_state)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	intel_crtc_put_color_blobs(crtc_state);
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_civoid intel_crtc_copy_color_blobs(struct intel_crtc_state *crtc_state)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	drm_property_replace_blob(&crtc_state->hw.degamma_lut,
2768c2ecf20Sopenharmony_ci				  crtc_state->uapi.degamma_lut);
2778c2ecf20Sopenharmony_ci	drm_property_replace_blob(&crtc_state->hw.gamma_lut,
2788c2ecf20Sopenharmony_ci				  crtc_state->uapi.gamma_lut);
2798c2ecf20Sopenharmony_ci	drm_property_replace_blob(&crtc_state->hw.ctm,
2808c2ecf20Sopenharmony_ci				  crtc_state->uapi.ctm);
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci/**
2848c2ecf20Sopenharmony_ci * intel_crtc_destroy_state - destroy crtc state
2858c2ecf20Sopenharmony_ci * @crtc: drm crtc
2868c2ecf20Sopenharmony_ci * @state: the state to destroy
2878c2ecf20Sopenharmony_ci *
2888c2ecf20Sopenharmony_ci * Destroys the crtc state (both common and Intel-specific) for the
2898c2ecf20Sopenharmony_ci * specified crtc.
2908c2ecf20Sopenharmony_ci */
2918c2ecf20Sopenharmony_civoid
2928c2ecf20Sopenharmony_ciintel_crtc_destroy_state(struct drm_crtc *crtc,
2938c2ecf20Sopenharmony_ci			 struct drm_crtc_state *state)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	struct intel_crtc_state *crtc_state = to_intel_crtc_state(state);
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	drm_WARN_ON(crtc->dev, crtc_state->dsb);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	__drm_atomic_helper_crtc_destroy_state(&crtc_state->uapi);
3008c2ecf20Sopenharmony_ci	intel_crtc_free_hw_state(crtc_state);
3018c2ecf20Sopenharmony_ci	kfree(crtc_state);
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state,
3058c2ecf20Sopenharmony_ci				      int num_scalers_need, struct intel_crtc *intel_crtc,
3068c2ecf20Sopenharmony_ci				      const char *name, int idx,
3078c2ecf20Sopenharmony_ci				      struct intel_plane_state *plane_state,
3088c2ecf20Sopenharmony_ci				      int *scaler_id)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
3118c2ecf20Sopenharmony_ci	int j;
3128c2ecf20Sopenharmony_ci	u32 mode;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (*scaler_id < 0) {
3158c2ecf20Sopenharmony_ci		/* find a free scaler */
3168c2ecf20Sopenharmony_ci		for (j = 0; j < intel_crtc->num_scalers; j++) {
3178c2ecf20Sopenharmony_ci			if (scaler_state->scalers[j].in_use)
3188c2ecf20Sopenharmony_ci				continue;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci			*scaler_id = j;
3218c2ecf20Sopenharmony_ci			scaler_state->scalers[*scaler_id].in_use = 1;
3228c2ecf20Sopenharmony_ci			break;
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (drm_WARN(&dev_priv->drm, *scaler_id < 0,
3278c2ecf20Sopenharmony_ci		     "Cannot find scaler for %s:%d\n", name, idx))
3288c2ecf20Sopenharmony_ci		return;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* set scaler mode */
3318c2ecf20Sopenharmony_ci	if (plane_state && plane_state->hw.fb &&
3328c2ecf20Sopenharmony_ci	    plane_state->hw.fb->format->is_yuv &&
3338c2ecf20Sopenharmony_ci	    plane_state->hw.fb->format->num_planes > 1) {
3348c2ecf20Sopenharmony_ci		struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
3358c2ecf20Sopenharmony_ci		if (IS_GEN(dev_priv, 9) &&
3368c2ecf20Sopenharmony_ci		    !IS_GEMINILAKE(dev_priv)) {
3378c2ecf20Sopenharmony_ci			mode = SKL_PS_SCALER_MODE_NV12;
3388c2ecf20Sopenharmony_ci		} else if (icl_is_hdr_plane(dev_priv, plane->id)) {
3398c2ecf20Sopenharmony_ci			/*
3408c2ecf20Sopenharmony_ci			 * On gen11+'s HDR planes we only use the scaler for
3418c2ecf20Sopenharmony_ci			 * scaling. They have a dedicated chroma upsampler, so
3428c2ecf20Sopenharmony_ci			 * we don't need the scaler to upsample the UV plane.
3438c2ecf20Sopenharmony_ci			 */
3448c2ecf20Sopenharmony_ci			mode = PS_SCALER_MODE_NORMAL;
3458c2ecf20Sopenharmony_ci		} else {
3468c2ecf20Sopenharmony_ci			struct intel_plane *linked =
3478c2ecf20Sopenharmony_ci				plane_state->planar_linked_plane;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci			mode = PS_SCALER_MODE_PLANAR;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci			if (linked)
3528c2ecf20Sopenharmony_ci				mode |= PS_PLANE_Y_SEL(linked->id);
3538c2ecf20Sopenharmony_ci		}
3548c2ecf20Sopenharmony_ci	} else if (INTEL_GEN(dev_priv) > 9 || IS_GEMINILAKE(dev_priv)) {
3558c2ecf20Sopenharmony_ci		mode = PS_SCALER_MODE_NORMAL;
3568c2ecf20Sopenharmony_ci	} else if (num_scalers_need == 1 && intel_crtc->num_scalers > 1) {
3578c2ecf20Sopenharmony_ci		/*
3588c2ecf20Sopenharmony_ci		 * when only 1 scaler is in use on a pipe with 2 scalers
3598c2ecf20Sopenharmony_ci		 * scaler 0 operates in high quality (HQ) mode.
3608c2ecf20Sopenharmony_ci		 * In this case use scaler 0 to take advantage of HQ mode
3618c2ecf20Sopenharmony_ci		 */
3628c2ecf20Sopenharmony_ci		scaler_state->scalers[*scaler_id].in_use = 0;
3638c2ecf20Sopenharmony_ci		*scaler_id = 0;
3648c2ecf20Sopenharmony_ci		scaler_state->scalers[0].in_use = 1;
3658c2ecf20Sopenharmony_ci		mode = SKL_PS_SCALER_MODE_HQ;
3668c2ecf20Sopenharmony_ci	} else {
3678c2ecf20Sopenharmony_ci		mode = SKL_PS_SCALER_MODE_DYN;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	drm_dbg_kms(&dev_priv->drm, "Attached scaler id %u.%u to %s:%d\n",
3718c2ecf20Sopenharmony_ci		    intel_crtc->pipe, *scaler_id, name, idx);
3728c2ecf20Sopenharmony_ci	scaler_state->scalers[*scaler_id].mode = mode;
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci/**
3768c2ecf20Sopenharmony_ci * intel_atomic_setup_scalers() - setup scalers for crtc per staged requests
3778c2ecf20Sopenharmony_ci * @dev_priv: i915 device
3788c2ecf20Sopenharmony_ci * @intel_crtc: intel crtc
3798c2ecf20Sopenharmony_ci * @crtc_state: incoming crtc_state to validate and setup scalers
3808c2ecf20Sopenharmony_ci *
3818c2ecf20Sopenharmony_ci * This function sets up scalers based on staged scaling requests for
3828c2ecf20Sopenharmony_ci * a @crtc and its planes. It is called from crtc level check path. If request
3838c2ecf20Sopenharmony_ci * is a supportable request, it attaches scalers to requested planes and crtc.
3848c2ecf20Sopenharmony_ci *
3858c2ecf20Sopenharmony_ci * This function takes into account the current scaler(s) in use by any planes
3868c2ecf20Sopenharmony_ci * not being part of this atomic state
3878c2ecf20Sopenharmony_ci *
3888c2ecf20Sopenharmony_ci *  Returns:
3898c2ecf20Sopenharmony_ci *         0 - scalers were setup succesfully
3908c2ecf20Sopenharmony_ci *         error code - otherwise
3918c2ecf20Sopenharmony_ci */
3928c2ecf20Sopenharmony_ciint intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
3938c2ecf20Sopenharmony_ci			       struct intel_crtc *intel_crtc,
3948c2ecf20Sopenharmony_ci			       struct intel_crtc_state *crtc_state)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct drm_plane *plane = NULL;
3978c2ecf20Sopenharmony_ci	struct intel_plane *intel_plane;
3988c2ecf20Sopenharmony_ci	struct intel_plane_state *plane_state = NULL;
3998c2ecf20Sopenharmony_ci	struct intel_crtc_scaler_state *scaler_state =
4008c2ecf20Sopenharmony_ci		&crtc_state->scaler_state;
4018c2ecf20Sopenharmony_ci	struct drm_atomic_state *drm_state = crtc_state->uapi.state;
4028c2ecf20Sopenharmony_ci	struct intel_atomic_state *intel_state = to_intel_atomic_state(drm_state);
4038c2ecf20Sopenharmony_ci	int num_scalers_need;
4048c2ecf20Sopenharmony_ci	int i;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	num_scalers_need = hweight32(scaler_state->scaler_users);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	/*
4098c2ecf20Sopenharmony_ci	 * High level flow:
4108c2ecf20Sopenharmony_ci	 * - staged scaler requests are already in scaler_state->scaler_users
4118c2ecf20Sopenharmony_ci	 * - check whether staged scaling requests can be supported
4128c2ecf20Sopenharmony_ci	 * - add planes using scalers that aren't in current transaction
4138c2ecf20Sopenharmony_ci	 * - assign scalers to requested users
4148c2ecf20Sopenharmony_ci	 * - as part of plane commit, scalers will be committed
4158c2ecf20Sopenharmony_ci	 *   (i.e., either attached or detached) to respective planes in hw
4168c2ecf20Sopenharmony_ci	 * - as part of crtc_commit, scaler will be either attached or detached
4178c2ecf20Sopenharmony_ci	 *   to crtc in hw
4188c2ecf20Sopenharmony_ci	 */
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	/* fail if required scalers > available scalers */
4218c2ecf20Sopenharmony_ci	if (num_scalers_need > intel_crtc->num_scalers){
4228c2ecf20Sopenharmony_ci		drm_dbg_kms(&dev_priv->drm,
4238c2ecf20Sopenharmony_ci			    "Too many scaling requests %d > %d\n",
4248c2ecf20Sopenharmony_ci			    num_scalers_need, intel_crtc->num_scalers);
4258c2ecf20Sopenharmony_ci		return -EINVAL;
4268c2ecf20Sopenharmony_ci	}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* walkthrough scaler_users bits and start assigning scalers */
4298c2ecf20Sopenharmony_ci	for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) {
4308c2ecf20Sopenharmony_ci		int *scaler_id;
4318c2ecf20Sopenharmony_ci		const char *name;
4328c2ecf20Sopenharmony_ci		int idx;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci		/* skip if scaler not required */
4358c2ecf20Sopenharmony_ci		if (!(scaler_state->scaler_users & (1 << i)))
4368c2ecf20Sopenharmony_ci			continue;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		if (i == SKL_CRTC_INDEX) {
4398c2ecf20Sopenharmony_ci			name = "CRTC";
4408c2ecf20Sopenharmony_ci			idx = intel_crtc->base.base.id;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci			/* panel fitter case: assign as a crtc scaler */
4438c2ecf20Sopenharmony_ci			scaler_id = &scaler_state->scaler_id;
4448c2ecf20Sopenharmony_ci		} else {
4458c2ecf20Sopenharmony_ci			name = "PLANE";
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci			/* plane scaler case: assign as a plane scaler */
4488c2ecf20Sopenharmony_ci			/* find the plane that set the bit as scaler_user */
4498c2ecf20Sopenharmony_ci			plane = drm_state->planes[i].ptr;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci			/*
4528c2ecf20Sopenharmony_ci			 * to enable/disable hq mode, add planes that are using scaler
4538c2ecf20Sopenharmony_ci			 * into this transaction
4548c2ecf20Sopenharmony_ci			 */
4558c2ecf20Sopenharmony_ci			if (!plane) {
4568c2ecf20Sopenharmony_ci				struct drm_plane_state *state;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci				/*
4598c2ecf20Sopenharmony_ci				 * GLK+ scalers don't have a HQ mode so it
4608c2ecf20Sopenharmony_ci				 * isn't necessary to change between HQ and dyn mode
4618c2ecf20Sopenharmony_ci				 * on those platforms.
4628c2ecf20Sopenharmony_ci				 */
4638c2ecf20Sopenharmony_ci				if (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv))
4648c2ecf20Sopenharmony_ci					continue;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci				plane = drm_plane_from_index(&dev_priv->drm, i);
4678c2ecf20Sopenharmony_ci				state = drm_atomic_get_plane_state(drm_state, plane);
4688c2ecf20Sopenharmony_ci				if (IS_ERR(state)) {
4698c2ecf20Sopenharmony_ci					drm_dbg_kms(&dev_priv->drm,
4708c2ecf20Sopenharmony_ci						    "Failed to add [PLANE:%d] to drm_state\n",
4718c2ecf20Sopenharmony_ci						    plane->base.id);
4728c2ecf20Sopenharmony_ci					return PTR_ERR(state);
4738c2ecf20Sopenharmony_ci				}
4748c2ecf20Sopenharmony_ci			}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci			intel_plane = to_intel_plane(plane);
4778c2ecf20Sopenharmony_ci			idx = plane->base.id;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci			/* plane on different crtc cannot be a scaler user of this crtc */
4808c2ecf20Sopenharmony_ci			if (drm_WARN_ON(&dev_priv->drm,
4818c2ecf20Sopenharmony_ci					intel_plane->pipe != intel_crtc->pipe))
4828c2ecf20Sopenharmony_ci				continue;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci			plane_state = intel_atomic_get_new_plane_state(intel_state,
4858c2ecf20Sopenharmony_ci								       intel_plane);
4868c2ecf20Sopenharmony_ci			scaler_id = &plane_state->scaler_id;
4878c2ecf20Sopenharmony_ci		}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci		intel_atomic_setup_scaler(scaler_state, num_scalers_need,
4908c2ecf20Sopenharmony_ci					  intel_crtc, name, idx,
4918c2ecf20Sopenharmony_ci					  plane_state, scaler_id);
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	return 0;
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistruct drm_atomic_state *
4988c2ecf20Sopenharmony_ciintel_atomic_state_alloc(struct drm_device *dev)
4998c2ecf20Sopenharmony_ci{
5008c2ecf20Sopenharmony_ci	struct intel_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (!state || drm_atomic_state_init(dev, &state->base) < 0) {
5038c2ecf20Sopenharmony_ci		kfree(state);
5048c2ecf20Sopenharmony_ci		return NULL;
5058c2ecf20Sopenharmony_ci	}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	return &state->base;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_civoid intel_atomic_state_free(struct drm_atomic_state *_state)
5118c2ecf20Sopenharmony_ci{
5128c2ecf20Sopenharmony_ci	struct intel_atomic_state *state = to_intel_atomic_state(_state);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	drm_atomic_state_default_release(&state->base);
5158c2ecf20Sopenharmony_ci	kfree(state->global_objs);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	i915_sw_fence_fini(&state->commit_ready);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	kfree(state);
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_civoid intel_atomic_state_clear(struct drm_atomic_state *s)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct intel_atomic_state *state = to_intel_atomic_state(s);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	drm_atomic_state_default_clear(&state->base);
5278c2ecf20Sopenharmony_ci	intel_atomic_clear_global_state(state);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	state->dpll_set = state->modeset = false;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistruct intel_crtc_state *
5338c2ecf20Sopenharmony_ciintel_atomic_get_crtc_state(struct drm_atomic_state *state,
5348c2ecf20Sopenharmony_ci			    struct intel_crtc *crtc)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	struct drm_crtc_state *crtc_state;
5378c2ecf20Sopenharmony_ci	crtc_state = drm_atomic_get_crtc_state(state, &crtc->base);
5388c2ecf20Sopenharmony_ci	if (IS_ERR(crtc_state))
5398c2ecf20Sopenharmony_ci		return ERR_CAST(crtc_state);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	return to_intel_crtc_state(crtc_state);
5428c2ecf20Sopenharmony_ci}
543