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