drm/i915/mtl: limit second scaler vertical scaling in ver >= 14
authorjsg <jsg@openbsd.org>
Mon, 1 Jan 2024 23:47:01 +0000 (23:47 +0000)
committerjsg <jsg@openbsd.org>
Mon, 1 Jan 2024 23:47:01 +0000 (23:47 +0000)
From Luca Coelho
99767368b7fad6bee30ca89ef96877d86e3181a1 in linux-6.1.y/6.1.70
8d4312e2b228ba7a5ac79154458098274ec61e9b in mainline linux

sys/dev/pci/drm/i915/display/intel_atomic.c

index 18f0a5a..61dda54 100644 (file)
@@ -41,6 +41,7 @@
 #include "intel_global_state.h"
 #include "intel_hdcp.h"
 #include "intel_psr.h"
+#include "intel_fb.h"
 #include "skl_universal_plane.h"
 
 /**
@@ -302,11 +303,11 @@ intel_crtc_destroy_state(struct drm_crtc *crtc,
        kfree(crtc_state);
 }
 
-static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state,
-                                     int num_scalers_need, struct intel_crtc *intel_crtc,
-                                     const char *name, int idx,
-                                     struct intel_plane_state *plane_state,
-                                     int *scaler_id)
+static int intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state,
+                                    int num_scalers_need, struct intel_crtc *intel_crtc,
+                                    const char *name, int idx,
+                                    struct intel_plane_state *plane_state,
+                                    int *scaler_id)
 {
        struct drm_i915_private *dev_priv = to_i915(intel_crtc->base.dev);
        int j;
@@ -326,7 +327,7 @@ static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_sta
 
        if (drm_WARN(&dev_priv->drm, *scaler_id < 0,
                     "Cannot find scaler for %s:%d\n", name, idx))
-               return;
+               return -EINVAL;
 
        /* set scaler mode */
        if (plane_state && plane_state->hw.fb &&
@@ -367,9 +368,71 @@ static void intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_sta
                mode = SKL_PS_SCALER_MODE_DYN;
        }
 
+       /*
+        * FIXME: we should also check the scaler factors for pfit, so
+        * this shouldn't be tied directly to planes.
+        */
+       if (plane_state && plane_state->hw.fb) {
+               const struct drm_framebuffer *fb = plane_state->hw.fb;
+               const struct drm_rect *src = &plane_state->uapi.src;
+               const struct drm_rect *dst = &plane_state->uapi.dst;
+               int hscale, vscale, max_vscale, max_hscale;
+
+               /*
+                * FIXME: When two scalers are needed, but only one of
+                * them needs to downscale, we should make sure that
+                * the one that needs downscaling support is assigned
+                * as the first scaler, so we don't reject downscaling
+                * unnecessarily.
+                */
+
+               if (DISPLAY_VER(dev_priv) >= 14) {
+                       /*
+                        * On versions 14 and up, only the first
+                        * scaler supports a vertical scaling factor
+                        * of more than 1.0, while a horizontal
+                        * scaling factor of 3.0 is supported.
+                        */
+                       max_hscale = 0x30000 - 1;
+                       if (*scaler_id == 0)
+                               max_vscale = 0x30000 - 1;
+                       else
+                               max_vscale = 0x10000;
+
+               } else if (DISPLAY_VER(dev_priv) >= 10 ||
+                          !intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) {
+                       max_hscale = 0x30000 - 1;
+                       max_vscale = 0x30000 - 1;
+               } else {
+                       max_hscale = 0x20000 - 1;
+                       max_vscale = 0x20000 - 1;
+               }
+
+               /*
+                * FIXME: We should change the if-else block above to
+                * support HQ vs dynamic scaler properly.
+                */
+
+               /* Check if required scaling is within limits */
+               hscale = drm_rect_calc_hscale(src, dst, 1, max_hscale);
+               vscale = drm_rect_calc_vscale(src, dst, 1, max_vscale);
+
+               if (hscale < 0 || vscale < 0) {
+                       drm_dbg_kms(&dev_priv->drm,
+                                   "Scaler %d doesn't support required plane scaling\n",
+                                   *scaler_id);
+                       drm_rect_debug_print("src: ", src, true);
+                       drm_rect_debug_print("dst: ", dst, false);
+
+                       return -EINVAL;
+               }
+       }
+
        drm_dbg_kms(&dev_priv->drm, "Attached scaler id %u.%u to %s:%d\n",
                    intel_crtc->pipe, *scaler_id, name, idx);
        scaler_state->scalers[*scaler_id].mode = mode;
+
+       return 0;
 }
 
 /**
@@ -429,7 +492,7 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
        for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) {
                int *scaler_id;
                const char *name;
-               int idx;
+               int idx, ret;
 
                /* skip if scaler not required */
                if (!(scaler_state->scaler_users & (1 << i)))
@@ -486,9 +549,11 @@ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv,
                        scaler_id = &plane_state->scaler_id;
                }
 
-               intel_atomic_setup_scaler(scaler_state, num_scalers_need,
-                                         intel_crtc, name, idx,
-                                         plane_state, scaler_id);
+               ret = intel_atomic_setup_scaler(scaler_state, num_scalers_need,
+                                               intel_crtc, name, idx,
+                                               plane_state, scaler_id);
+               if (ret < 0)
+                       return ret;
        }
 
        return 0;