Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright © 2020 Intel Corporation
0004  */
0005 #include "intel_de.h"
0006 #include "intel_display_types.h"
0007 #include "intel_fb.h"
0008 #include "skl_scaler.h"
0009 #include "skl_universal_plane.h"
0010 
0011 /*
0012  * The hardware phase 0.0 refers to the center of the pixel.
0013  * We want to start from the top/left edge which is phase
0014  * -0.5. That matches how the hardware calculates the scaling
0015  * factors (from top-left of the first pixel to bottom-right
0016  * of the last pixel, as opposed to the pixel centers).
0017  *
0018  * For 4:2:0 subsampled chroma planes we obviously have to
0019  * adjust that so that the chroma sample position lands in
0020  * the right spot.
0021  *
0022  * Note that for packed YCbCr 4:2:2 formats there is no way to
0023  * control chroma siting. The hardware simply replicates the
0024  * chroma samples for both of the luma samples, and thus we don't
0025  * actually get the expected MPEG2 chroma siting convention :(
0026  * The same behaviour is observed on pre-SKL platforms as well.
0027  *
0028  * Theory behind the formula (note that we ignore sub-pixel
0029  * source coordinates):
0030  * s = source sample position
0031  * d = destination sample position
0032  *
0033  * Downscaling 4:1:
0034  * -0.5
0035  * | 0.0
0036  * | |     1.5 (initial phase)
0037  * | |     |
0038  * v v     v
0039  * | s | s | s | s |
0040  * |       d       |
0041  *
0042  * Upscaling 1:4:
0043  * -0.5
0044  * | -0.375 (initial phase)
0045  * | |     0.0
0046  * | |     |
0047  * v v     v
0048  * |       s       |
0049  * | d | d | d | d |
0050  */
0051 static u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited)
0052 {
0053     int phase = -0x8000;
0054     u16 trip = 0;
0055 
0056     if (chroma_cosited)
0057         phase += (sub - 1) * 0x8000 / sub;
0058 
0059     phase += scale / (2 * sub);
0060 
0061     /*
0062      * Hardware initial phase limited to [-0.5:1.5].
0063      * Since the max hardware scale factor is 3.0, we
0064      * should never actually excdeed 1.0 here.
0065      */
0066     WARN_ON(phase < -0x8000 || phase > 0x18000);
0067 
0068     if (phase < 0)
0069         phase = 0x10000 + phase;
0070     else
0071         trip = PS_PHASE_TRIP;
0072 
0073     return ((phase >> 2) & PS_PHASE_MASK) | trip;
0074 }
0075 
0076 #define SKL_MIN_SRC_W 8
0077 #define SKL_MAX_SRC_W 4096
0078 #define SKL_MIN_SRC_H 8
0079 #define SKL_MAX_SRC_H 4096
0080 #define SKL_MIN_DST_W 8
0081 #define SKL_MAX_DST_W 4096
0082 #define SKL_MIN_DST_H 8
0083 #define SKL_MAX_DST_H 4096
0084 #define ICL_MAX_SRC_W 5120
0085 #define ICL_MAX_SRC_H 4096
0086 #define ICL_MAX_DST_W 5120
0087 #define ICL_MAX_DST_H 4096
0088 #define SKL_MIN_YUV_420_SRC_W 16
0089 #define SKL_MIN_YUV_420_SRC_H 16
0090 
0091 static int
0092 skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
0093           unsigned int scaler_user, int *scaler_id,
0094           int src_w, int src_h, int dst_w, int dst_h,
0095           const struct drm_format_info *format,
0096           u64 modifier, bool need_scaler)
0097 {
0098     struct intel_crtc_scaler_state *scaler_state =
0099         &crtc_state->scaler_state;
0100     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0101     struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
0102     const struct drm_display_mode *adjusted_mode =
0103         &crtc_state->hw.adjusted_mode;
0104 
0105     /*
0106      * Src coordinates are already rotated by 270 degrees for
0107      * the 90/270 degree plane rotation cases (to match the
0108      * GTT mapping), hence no need to account for rotation here.
0109      */
0110     if (src_w != dst_w || src_h != dst_h)
0111         need_scaler = true;
0112 
0113     /*
0114      * Scaling/fitting not supported in IF-ID mode in GEN9+
0115      * TODO: Interlace fetch mode doesn't support YUV420 planar formats.
0116      * Once NV12 is enabled, handle it here while allocating scaler
0117      * for NV12.
0118      */
0119     if (DISPLAY_VER(dev_priv) >= 9 && crtc_state->hw.enable &&
0120         need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
0121         drm_dbg_kms(&dev_priv->drm,
0122                 "Pipe/Plane scaling not supported with IF-ID mode\n");
0123         return -EINVAL;
0124     }
0125 
0126     /*
0127      * if plane is being disabled or scaler is no more required or force detach
0128      *  - free scaler binded to this plane/crtc
0129      *  - in order to do this, update crtc->scaler_usage
0130      *
0131      * Here scaler state in crtc_state is set free so that
0132      * scaler can be assigned to other user. Actual register
0133      * update to free the scaler is done in plane/panel-fit programming.
0134      * For this purpose crtc/plane_state->scaler_id isn't reset here.
0135      */
0136     if (force_detach || !need_scaler) {
0137         if (*scaler_id >= 0) {
0138             scaler_state->scaler_users &= ~(1 << scaler_user);
0139             scaler_state->scalers[*scaler_id].in_use = 0;
0140 
0141             drm_dbg_kms(&dev_priv->drm,
0142                     "scaler_user index %u.%u: "
0143                     "Staged freeing scaler id %d scaler_users = 0x%x\n",
0144                     crtc->pipe, scaler_user, *scaler_id,
0145                     scaler_state->scaler_users);
0146             *scaler_id = -1;
0147         }
0148         return 0;
0149     }
0150 
0151     if (format && intel_format_info_is_yuv_semiplanar(format, modifier) &&
0152         (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) {
0153         drm_dbg_kms(&dev_priv->drm,
0154                 "Planar YUV: src dimensions not met\n");
0155         return -EINVAL;
0156     }
0157 
0158     /* range checks */
0159     if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H ||
0160         dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H ||
0161         (DISPLAY_VER(dev_priv) >= 11 &&
0162          (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H ||
0163           dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) ||
0164         (DISPLAY_VER(dev_priv) < 11 &&
0165          (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H ||
0166           dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H))) {
0167         drm_dbg_kms(&dev_priv->drm,
0168                 "scaler_user index %u.%u: src %ux%u dst %ux%u "
0169                 "size is out of scaler range\n",
0170                 crtc->pipe, scaler_user, src_w, src_h,
0171                 dst_w, dst_h);
0172         return -EINVAL;
0173     }
0174 
0175     /* mark this plane as a scaler user in crtc_state */
0176     scaler_state->scaler_users |= (1 << scaler_user);
0177     drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: "
0178             "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n",
0179             crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h,
0180             scaler_state->scaler_users);
0181 
0182     return 0;
0183 }
0184 
0185 int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state)
0186 {
0187     const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
0188     int width, height;
0189 
0190     if (crtc_state->pch_pfit.enabled) {
0191         width = drm_rect_width(&crtc_state->pch_pfit.dst);
0192         height = drm_rect_height(&crtc_state->pch_pfit.dst);
0193     } else {
0194         width = pipe_mode->crtc_hdisplay;
0195         height = pipe_mode->crtc_vdisplay;
0196     }
0197     return skl_update_scaler(crtc_state, !crtc_state->hw.active,
0198                  SKL_CRTC_INDEX,
0199                  &crtc_state->scaler_state.scaler_id,
0200                  drm_rect_width(&crtc_state->pipe_src),
0201                  drm_rect_height(&crtc_state->pipe_src),
0202                  width, height, NULL, 0,
0203                  crtc_state->pch_pfit.enabled);
0204 }
0205 
0206 /**
0207  * skl_update_scaler_plane - Stages update to scaler state for a given plane.
0208  * @crtc_state: crtc's scaler state
0209  * @plane_state: atomic plane state to update
0210  *
0211  * Return
0212  *     0 - scaler_usage updated successfully
0213  *    error - requested scaling cannot be supported or other error condition
0214  */
0215 int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
0216                 struct intel_plane_state *plane_state)
0217 {
0218     struct intel_plane *intel_plane =
0219         to_intel_plane(plane_state->uapi.plane);
0220     struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
0221     struct drm_framebuffer *fb = plane_state->hw.fb;
0222     int ret;
0223     bool force_detach = !fb || !plane_state->uapi.visible;
0224     bool need_scaler = false;
0225 
0226     /* Pre-gen11 and SDR planes always need a scaler for planar formats. */
0227     if (!icl_is_hdr_plane(dev_priv, intel_plane->id) &&
0228         fb && intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
0229         need_scaler = true;
0230 
0231     ret = skl_update_scaler(crtc_state, force_detach,
0232                 drm_plane_index(&intel_plane->base),
0233                 &plane_state->scaler_id,
0234                 drm_rect_width(&plane_state->uapi.src) >> 16,
0235                 drm_rect_height(&plane_state->uapi.src) >> 16,
0236                 drm_rect_width(&plane_state->uapi.dst),
0237                 drm_rect_height(&plane_state->uapi.dst),
0238                 fb ? fb->format : NULL,
0239                 fb ? fb->modifier : 0,
0240                 need_scaler);
0241 
0242     if (ret || plane_state->scaler_id < 0)
0243         return ret;
0244 
0245     /* check colorkey */
0246     if (plane_state->ckey.flags) {
0247         drm_dbg_kms(&dev_priv->drm,
0248                 "[PLANE:%d:%s] scaling with color key not allowed",
0249                 intel_plane->base.base.id,
0250                 intel_plane->base.name);
0251         return -EINVAL;
0252     }
0253 
0254     /* Check src format */
0255     switch (fb->format->format) {
0256     case DRM_FORMAT_RGB565:
0257     case DRM_FORMAT_XBGR8888:
0258     case DRM_FORMAT_XRGB8888:
0259     case DRM_FORMAT_ABGR8888:
0260     case DRM_FORMAT_ARGB8888:
0261     case DRM_FORMAT_XRGB2101010:
0262     case DRM_FORMAT_XBGR2101010:
0263     case DRM_FORMAT_ARGB2101010:
0264     case DRM_FORMAT_ABGR2101010:
0265     case DRM_FORMAT_YUYV:
0266     case DRM_FORMAT_YVYU:
0267     case DRM_FORMAT_UYVY:
0268     case DRM_FORMAT_VYUY:
0269     case DRM_FORMAT_NV12:
0270     case DRM_FORMAT_XYUV8888:
0271     case DRM_FORMAT_P010:
0272     case DRM_FORMAT_P012:
0273     case DRM_FORMAT_P016:
0274     case DRM_FORMAT_Y210:
0275     case DRM_FORMAT_Y212:
0276     case DRM_FORMAT_Y216:
0277     case DRM_FORMAT_XVYU2101010:
0278     case DRM_FORMAT_XVYU12_16161616:
0279     case DRM_FORMAT_XVYU16161616:
0280         break;
0281     case DRM_FORMAT_XBGR16161616F:
0282     case DRM_FORMAT_ABGR16161616F:
0283     case DRM_FORMAT_XRGB16161616F:
0284     case DRM_FORMAT_ARGB16161616F:
0285         if (DISPLAY_VER(dev_priv) >= 11)
0286             break;
0287         fallthrough;
0288     default:
0289         drm_dbg_kms(&dev_priv->drm,
0290                 "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n",
0291                 intel_plane->base.base.id, intel_plane->base.name,
0292                 fb->base.id, fb->format->format);
0293         return -EINVAL;
0294     }
0295 
0296     return 0;
0297 }
0298 
0299 static int glk_coef_tap(int i)
0300 {
0301     return i % 7;
0302 }
0303 
0304 static u16 glk_nearest_filter_coef(int t)
0305 {
0306     return t == 3 ? 0x0800 : 0x3000;
0307 }
0308 
0309 /*
0310  *  Theory behind setting nearest-neighbor integer scaling:
0311  *
0312  *  17 phase of 7 taps requires 119 coefficients in 60 dwords per set.
0313  *  The letter represents the filter tap (D is the center tap) and the number
0314  *  represents the coefficient set for a phase (0-16).
0315  *
0316  *         +------------+------------------------+------------------------+
0317  *         |Index value | Data value coeffient 1 | Data value coeffient 2 |
0318  *         +------------+------------------------+------------------------+
0319  *         |   00h      |          B0            |          A0            |
0320  *         +------------+------------------------+------------------------+
0321  *         |   01h      |          D0            |          C0            |
0322  *         +------------+------------------------+------------------------+
0323  *         |   02h      |          F0            |          E0            |
0324  *         +------------+------------------------+------------------------+
0325  *         |   03h      |          A1            |          G0            |
0326  *         +------------+------------------------+------------------------+
0327  *         |   04h      |          C1            |          B1            |
0328  *         +------------+------------------------+------------------------+
0329  *         |   ...      |          ...           |          ...           |
0330  *         +------------+------------------------+------------------------+
0331  *         |   38h      |          B16           |          A16           |
0332  *         +------------+------------------------+------------------------+
0333  *         |   39h      |          D16           |          C16           |
0334  *         +------------+------------------------+------------------------+
0335  *         |   3Ah      |          F16           |          C16           |
0336  *         +------------+------------------------+------------------------+
0337  *         |   3Bh      |        Reserved        |          G16           |
0338  *         +------------+------------------------+------------------------+
0339  *
0340  *  To enable nearest-neighbor scaling:  program scaler coefficents with
0341  *  the center tap (Dxx) values set to 1 and all other values set to 0 as per
0342  *  SCALER_COEFFICIENT_FORMAT
0343  *
0344  */
0345 
0346 static void glk_program_nearest_filter_coefs(struct drm_i915_private *dev_priv,
0347                          enum pipe pipe, int id, int set)
0348 {
0349     int i;
0350 
0351     intel_de_write_fw(dev_priv, GLK_PS_COEF_INDEX_SET(pipe, id, set),
0352               PS_COEE_INDEX_AUTO_INC);
0353 
0354     for (i = 0; i < 17 * 7; i += 2) {
0355         u32 tmp;
0356         int t;
0357 
0358         t = glk_coef_tap(i);
0359         tmp = glk_nearest_filter_coef(t);
0360 
0361         t = glk_coef_tap(i + 1);
0362         tmp |= glk_nearest_filter_coef(t) << 16;
0363 
0364         intel_de_write_fw(dev_priv, GLK_PS_COEF_DATA_SET(pipe, id, set),
0365                   tmp);
0366     }
0367 
0368     intel_de_write_fw(dev_priv, GLK_PS_COEF_INDEX_SET(pipe, id, set), 0);
0369 }
0370 
0371 static u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set)
0372 {
0373     if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) {
0374         return (PS_FILTER_PROGRAMMED |
0375             PS_Y_VERT_FILTER_SELECT(set) |
0376             PS_Y_HORZ_FILTER_SELECT(set) |
0377             PS_UV_VERT_FILTER_SELECT(set) |
0378             PS_UV_HORZ_FILTER_SELECT(set));
0379     }
0380 
0381     return PS_FILTER_MEDIUM;
0382 }
0383 
0384 static void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
0385                     int id, int set, enum drm_scaling_filter filter)
0386 {
0387     switch (filter) {
0388     case DRM_SCALING_FILTER_DEFAULT:
0389         break;
0390     case DRM_SCALING_FILTER_NEAREST_NEIGHBOR:
0391         glk_program_nearest_filter_coefs(dev_priv, pipe, id, set);
0392         break;
0393     default:
0394         MISSING_CASE(filter);
0395     }
0396 }
0397 
0398 void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
0399 {
0400     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0401     struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
0402     const struct intel_crtc_scaler_state *scaler_state =
0403         &crtc_state->scaler_state;
0404     const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
0405     u16 uv_rgb_hphase, uv_rgb_vphase;
0406     enum pipe pipe = crtc->pipe;
0407     int width = drm_rect_width(dst);
0408     int height = drm_rect_height(dst);
0409     int x = dst->x1;
0410     int y = dst->y1;
0411     int hscale, vscale;
0412     struct drm_rect src;
0413     int id;
0414     u32 ps_ctrl;
0415 
0416     if (!crtc_state->pch_pfit.enabled)
0417         return;
0418 
0419     if (drm_WARN_ON(&dev_priv->drm,
0420             crtc_state->scaler_state.scaler_id < 0))
0421         return;
0422 
0423     drm_rect_init(&src, 0, 0,
0424               drm_rect_width(&crtc_state->pipe_src) << 16,
0425               drm_rect_height(&crtc_state->pipe_src) << 16);
0426 
0427     hscale = drm_rect_calc_hscale(&src, dst, 0, INT_MAX);
0428     vscale = drm_rect_calc_vscale(&src, dst, 0, INT_MAX);
0429 
0430     uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
0431     uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
0432 
0433     id = scaler_state->scaler_id;
0434 
0435     ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0);
0436     ps_ctrl |=  PS_SCALER_EN | scaler_state->scalers[id].mode;
0437 
0438     skl_scaler_setup_filter(dev_priv, pipe, id, 0,
0439                 crtc_state->hw.scaling_filter);
0440 
0441     intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), ps_ctrl);
0442 
0443     intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, id),
0444               PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
0445     intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, id),
0446               PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase));
0447     intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, id),
0448               x << 16 | y);
0449     intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id),
0450               width << 16 | height);
0451 }
0452 
0453 void
0454 skl_program_plane_scaler(struct intel_plane *plane,
0455              const struct intel_crtc_state *crtc_state,
0456              const struct intel_plane_state *plane_state)
0457 {
0458     struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
0459     const struct drm_framebuffer *fb = plane_state->hw.fb;
0460     enum pipe pipe = plane->pipe;
0461     int scaler_id = plane_state->scaler_id;
0462     const struct intel_scaler *scaler =
0463         &crtc_state->scaler_state.scalers[scaler_id];
0464     int crtc_x = plane_state->uapi.dst.x1;
0465     int crtc_y = plane_state->uapi.dst.y1;
0466     u32 crtc_w = drm_rect_width(&plane_state->uapi.dst);
0467     u32 crtc_h = drm_rect_height(&plane_state->uapi.dst);
0468     u16 y_hphase, uv_rgb_hphase;
0469     u16 y_vphase, uv_rgb_vphase;
0470     int hscale, vscale;
0471     u32 ps_ctrl;
0472 
0473     hscale = drm_rect_calc_hscale(&plane_state->uapi.src,
0474                       &plane_state->uapi.dst,
0475                       0, INT_MAX);
0476     vscale = drm_rect_calc_vscale(&plane_state->uapi.src,
0477                       &plane_state->uapi.dst,
0478                       0, INT_MAX);
0479 
0480     /* TODO: handle sub-pixel coordinates */
0481     if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
0482         !icl_is_hdr_plane(dev_priv, plane->id)) {
0483         y_hphase = skl_scaler_calc_phase(1, hscale, false);
0484         y_vphase = skl_scaler_calc_phase(1, vscale, false);
0485 
0486         /* MPEG2 chroma siting convention */
0487         uv_rgb_hphase = skl_scaler_calc_phase(2, hscale, true);
0488         uv_rgb_vphase = skl_scaler_calc_phase(2, vscale, false);
0489     } else {
0490         /* not used */
0491         y_hphase = 0;
0492         y_vphase = 0;
0493 
0494         uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
0495         uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
0496     }
0497 
0498     ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0);
0499     ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode;
0500 
0501     skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0,
0502                 plane_state->hw.scaling_filter);
0503 
0504     intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl);
0505     intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id),
0506               PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase));
0507     intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id),
0508               PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase));
0509     intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, scaler_id),
0510               (crtc_x << 16) | crtc_y);
0511     intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, scaler_id),
0512               (crtc_w << 16) | crtc_h);
0513 }
0514 
0515 static void skl_detach_scaler(struct intel_crtc *crtc, int id)
0516 {
0517     struct drm_device *dev = crtc->base.dev;
0518     struct drm_i915_private *dev_priv = to_i915(dev);
0519 
0520     intel_de_write_fw(dev_priv, SKL_PS_CTRL(crtc->pipe, id), 0);
0521     intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(crtc->pipe, id), 0);
0522     intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(crtc->pipe, id), 0);
0523 }
0524 
0525 /*
0526  * This function detaches (aka. unbinds) unused scalers in hardware
0527  */
0528 void skl_detach_scalers(const struct intel_crtc_state *crtc_state)
0529 {
0530     struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0531     const struct intel_crtc_scaler_state *scaler_state =
0532         &crtc_state->scaler_state;
0533     int i;
0534 
0535     /* loop through and disable scalers that aren't in use */
0536     for (i = 0; i < crtc->num_scalers; i++) {
0537         if (!scaler_state->scalers[i].in_use)
0538             skl_detach_scaler(crtc, i);
0539     }
0540 }
0541 
0542 void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state)
0543 {
0544     struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
0545     int i;
0546 
0547     for (i = 0; i < crtc->num_scalers; i++)
0548         skl_detach_scaler(crtc, i);
0549 }