linux/drivers/gpu/drm/i915/display/intel_atomic_plane.c
<<
>>
Prefs
   1/*
   2 * Copyright © 2014 Intel Corporation
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice (including the next
  12 * paragraph) shall be included in all copies or substantial portions of the
  13 * Software.
  14 *
  15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21 * DEALINGS IN THE SOFTWARE.
  22 */
  23
  24/**
  25 * DOC: atomic plane helpers
  26 *
  27 * The functions here are used by the atomic plane helper functions to
  28 * implement legacy plane updates (i.e., drm_plane->update_plane() and
  29 * drm_plane->disable_plane()).  This allows plane updates to use the
  30 * atomic state infrastructure and perform plane updates as separate
  31 * prepare/check/commit/cleanup steps.
  32 */
  33
  34#include <drm/drm_atomic_helper.h>
  35#include <drm/drm_fourcc.h>
  36#include <drm/drm_plane_helper.h>
  37
  38#include "i915_trace.h"
  39#include "intel_atomic_plane.h"
  40#include "intel_cdclk.h"
  41#include "intel_display_types.h"
  42#include "intel_pm.h"
  43#include "intel_sprite.h"
  44
  45static void intel_plane_state_reset(struct intel_plane_state *plane_state,
  46                                    struct intel_plane *plane)
  47{
  48        memset(plane_state, 0, sizeof(*plane_state));
  49
  50        __drm_atomic_helper_plane_state_reset(&plane_state->uapi, &plane->base);
  51
  52        plane_state->scaler_id = -1;
  53}
  54
  55struct intel_plane *intel_plane_alloc(void)
  56{
  57        struct intel_plane_state *plane_state;
  58        struct intel_plane *plane;
  59
  60        plane = kzalloc(sizeof(*plane), GFP_KERNEL);
  61        if (!plane)
  62                return ERR_PTR(-ENOMEM);
  63
  64        plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
  65        if (!plane_state) {
  66                kfree(plane);
  67                return ERR_PTR(-ENOMEM);
  68        }
  69
  70        intel_plane_state_reset(plane_state, plane);
  71
  72        plane->base.state = &plane_state->uapi;
  73
  74        return plane;
  75}
  76
  77void intel_plane_free(struct intel_plane *plane)
  78{
  79        intel_plane_destroy_state(&plane->base, plane->base.state);
  80        kfree(plane);
  81}
  82
  83/**
  84 * intel_plane_duplicate_state - duplicate plane state
  85 * @plane: drm plane
  86 *
  87 * Allocates and returns a copy of the plane state (both common and
  88 * Intel-specific) for the specified plane.
  89 *
  90 * Returns: The newly allocated plane state, or NULL on failure.
  91 */
  92struct drm_plane_state *
  93intel_plane_duplicate_state(struct drm_plane *plane)
  94{
  95        struct intel_plane_state *intel_state;
  96
  97        intel_state = to_intel_plane_state(plane->state);
  98        intel_state = kmemdup(intel_state, sizeof(*intel_state), GFP_KERNEL);
  99
 100        if (!intel_state)
 101                return NULL;
 102
 103        __drm_atomic_helper_plane_duplicate_state(plane, &intel_state->uapi);
 104
 105        intel_state->ggtt_vma = NULL;
 106        intel_state->dpt_vma = NULL;
 107        intel_state->flags = 0;
 108
 109        /* add reference to fb */
 110        if (intel_state->hw.fb)
 111                drm_framebuffer_get(intel_state->hw.fb);
 112
 113        return &intel_state->uapi;
 114}
 115
 116/**
 117 * intel_plane_destroy_state - destroy plane state
 118 * @plane: drm plane
 119 * @state: state object to destroy
 120 *
 121 * Destroys the plane state (both common and Intel-specific) for the
 122 * specified plane.
 123 */
 124void
 125intel_plane_destroy_state(struct drm_plane *plane,
 126                          struct drm_plane_state *state)
 127{
 128        struct intel_plane_state *plane_state = to_intel_plane_state(state);
 129
 130        drm_WARN_ON(plane->dev, plane_state->ggtt_vma);
 131        drm_WARN_ON(plane->dev, plane_state->dpt_vma);
 132
 133        __drm_atomic_helper_plane_destroy_state(&plane_state->uapi);
 134        if (plane_state->hw.fb)
 135                drm_framebuffer_put(plane_state->hw.fb);
 136        kfree(plane_state);
 137}
 138
 139unsigned int intel_adjusted_rate(const struct drm_rect *src,
 140                                 const struct drm_rect *dst,
 141                                 unsigned int rate)
 142{
 143        unsigned int src_w, src_h, dst_w, dst_h;
 144
 145        src_w = drm_rect_width(src) >> 16;
 146        src_h = drm_rect_height(src) >> 16;
 147        dst_w = drm_rect_width(dst);
 148        dst_h = drm_rect_height(dst);
 149
 150        /* Downscaling limits the maximum pixel rate */
 151        dst_w = min(src_w, dst_w);
 152        dst_h = min(src_h, dst_h);
 153
 154        return DIV_ROUND_UP_ULL(mul_u32_u32(rate, src_w * src_h),
 155                                dst_w * dst_h);
 156}
 157
 158unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state,
 159                                    const struct intel_plane_state *plane_state)
 160{
 161        /*
 162         * Note we don't check for plane visibility here as
 163         * we want to use this when calculating the cursor
 164         * watermarks even if the cursor is fully offscreen.
 165         * That depends on the src/dst rectangles being
 166         * correctly populated whenever the watermark code
 167         * considers the cursor to be visible, whether or not
 168         * it is actually visible.
 169         *
 170         * See: intel_wm_plane_visible() and intel_check_cursor()
 171         */
 172
 173        return intel_adjusted_rate(&plane_state->uapi.src,
 174                                   &plane_state->uapi.dst,
 175                                   crtc_state->pixel_rate);
 176}
 177
 178unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
 179                                   const struct intel_plane_state *plane_state)
 180{
 181        const struct drm_framebuffer *fb = plane_state->hw.fb;
 182        unsigned int cpp;
 183        unsigned int pixel_rate;
 184
 185        if (!plane_state->uapi.visible)
 186                return 0;
 187
 188        pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
 189
 190        cpp = fb->format->cpp[0];
 191
 192        /*
 193         * Based on HSD#:1408715493
 194         * NV12 cpp == 4, P010 cpp == 8
 195         *
 196         * FIXME what is the logic behind this?
 197         */
 198        if (fb->format->is_yuv && fb->format->num_planes > 1)
 199                cpp *= 4;
 200
 201        return pixel_rate * cpp;
 202}
 203
 204int intel_plane_calc_min_cdclk(struct intel_atomic_state *state,
 205                               struct intel_plane *plane,
 206                               bool *need_cdclk_calc)
 207{
 208        struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
 209        const struct intel_plane_state *plane_state =
 210                intel_atomic_get_new_plane_state(state, plane);
 211        struct intel_crtc *crtc = to_intel_crtc(plane_state->hw.crtc);
 212        const struct intel_cdclk_state *cdclk_state;
 213        const struct intel_crtc_state *old_crtc_state;
 214        struct intel_crtc_state *new_crtc_state;
 215
 216        if (!plane_state->uapi.visible || !plane->min_cdclk)
 217                return 0;
 218
 219        old_crtc_state = intel_atomic_get_old_crtc_state(state, crtc);
 220        new_crtc_state = intel_atomic_get_new_crtc_state(state, crtc);
 221
 222        new_crtc_state->min_cdclk[plane->id] =
 223                plane->min_cdclk(new_crtc_state, plane_state);
 224
 225        /*
 226         * No need to check against the cdclk state if
 227         * the min cdclk for the plane doesn't increase.
 228         *
 229         * Ie. we only ever increase the cdclk due to plane
 230         * requirements. This can reduce back and forth
 231         * display blinking due to constant cdclk changes.
 232         */
 233        if (new_crtc_state->min_cdclk[plane->id] <=
 234            old_crtc_state->min_cdclk[plane->id])
 235                return 0;
 236
 237        cdclk_state = intel_atomic_get_cdclk_state(state);
 238        if (IS_ERR(cdclk_state))
 239                return PTR_ERR(cdclk_state);
 240
 241        /*
 242         * No need to recalculate the cdclk state if
 243         * the min cdclk for the pipe doesn't increase.
 244         *
 245         * Ie. we only ever increase the cdclk due to plane
 246         * requirements. This can reduce back and forth
 247         * display blinking due to constant cdclk changes.
 248         */
 249        if (new_crtc_state->min_cdclk[plane->id] <=
 250            cdclk_state->min_cdclk[crtc->pipe])
 251                return 0;
 252
 253        drm_dbg_kms(&dev_priv->drm,
 254                    "[PLANE:%d:%s] min cdclk (%d kHz) > [CRTC:%d:%s] min cdclk (%d kHz)\n",
 255                    plane->base.base.id, plane->base.name,
 256                    new_crtc_state->min_cdclk[plane->id],
 257                    crtc->base.base.id, crtc->base.name,
 258                    cdclk_state->min_cdclk[crtc->pipe]);
 259        *need_cdclk_calc = true;
 260
 261        return 0;
 262}
 263
 264static void intel_plane_clear_hw_state(struct intel_plane_state *plane_state)
 265{
 266        if (plane_state->hw.fb)
 267                drm_framebuffer_put(plane_state->hw.fb);
 268
 269        memset(&plane_state->hw, 0, sizeof(plane_state->hw));
 270}
 271
 272void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
 273                                       const struct intel_plane_state *from_plane_state,
 274                                       struct intel_crtc *crtc)
 275{
 276        intel_plane_clear_hw_state(plane_state);
 277
 278        /*
 279         * For the bigjoiner slave uapi.crtc will point at
 280         * the master crtc. So we explicitly assign the right
 281         * slave crtc to hw.crtc. uapi.crtc!=NULL simply indicates
 282         * the plane is logically enabled on the uapi level.
 283         */
 284        plane_state->hw.crtc = from_plane_state->uapi.crtc ? &crtc->base : NULL;
 285
 286        plane_state->hw.fb = from_plane_state->uapi.fb;
 287        if (plane_state->hw.fb)
 288                drm_framebuffer_get(plane_state->hw.fb);
 289
 290        plane_state->hw.alpha = from_plane_state->uapi.alpha;
 291        plane_state->hw.pixel_blend_mode =
 292                from_plane_state->uapi.pixel_blend_mode;
 293        plane_state->hw.rotation = from_plane_state->uapi.rotation;
 294        plane_state->hw.color_encoding = from_plane_state->uapi.color_encoding;
 295        plane_state->hw.color_range = from_plane_state->uapi.color_range;
 296        plane_state->hw.scaling_filter = from_plane_state->uapi.scaling_filter;
 297
 298        plane_state->uapi.src = drm_plane_state_src(&from_plane_state->uapi);
 299        plane_state->uapi.dst = drm_plane_state_dest(&from_plane_state->uapi);
 300}
 301
 302void intel_plane_copy_hw_state(struct intel_plane_state *plane_state,
 303                               const struct intel_plane_state *from_plane_state)
 304{
 305        intel_plane_clear_hw_state(plane_state);
 306
 307        memcpy(&plane_state->hw, &from_plane_state->hw,
 308               sizeof(plane_state->hw));
 309
 310        if (plane_state->hw.fb)
 311                drm_framebuffer_get(plane_state->hw.fb);
 312}
 313
 314void intel_plane_set_invisible(struct intel_crtc_state *crtc_state,
 315                               struct intel_plane_state *plane_state)
 316{
 317        struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
 318
 319        crtc_state->active_planes &= ~BIT(plane->id);
 320        crtc_state->nv12_planes &= ~BIT(plane->id);
 321        crtc_state->c8_planes &= ~BIT(plane->id);
 322        crtc_state->data_rate[plane->id] = 0;
 323        crtc_state->min_cdclk[plane->id] = 0;
 324
 325        plane_state->uapi.visible = false;
 326}
 327
 328int intel_plane_atomic_check_with_state(const struct intel_crtc_state *old_crtc_state,
 329                                        struct intel_crtc_state *new_crtc_state,
 330                                        const struct intel_plane_state *old_plane_state,
 331                                        struct intel_plane_state *new_plane_state)
 332{
 333        struct intel_plane *plane = to_intel_plane(new_plane_state->uapi.plane);
 334        const struct drm_framebuffer *fb = new_plane_state->hw.fb;
 335        int ret;
 336
 337        intel_plane_set_invisible(new_crtc_state, new_plane_state);
 338        new_crtc_state->enabled_planes &= ~BIT(plane->id);
 339
 340        if (!new_plane_state->hw.crtc && !old_plane_state->hw.crtc)
 341                return 0;
 342
 343        ret = plane->check_plane(new_crtc_state, new_plane_state);
 344        if (ret)
 345                return ret;
 346
 347        if (fb)
 348                new_crtc_state->enabled_planes |= BIT(plane->id);
 349
 350        /* FIXME pre-g4x don't work like this */
 351        if (new_plane_state->uapi.visible)
 352                new_crtc_state->active_planes |= BIT(plane->id);
 353
 354        if (new_plane_state->uapi.visible &&
 355            intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
 356                new_crtc_state->nv12_planes |= BIT(plane->id);
 357
 358        if (new_plane_state->uapi.visible &&
 359            fb->format->format == DRM_FORMAT_C8)
 360                new_crtc_state->c8_planes |= BIT(plane->id);
 361
 362        if (new_plane_state->uapi.visible || old_plane_state->uapi.visible)
 363                new_crtc_state->update_planes |= BIT(plane->id);
 364
 365        new_crtc_state->data_rate[plane->id] =
 366                intel_plane_data_rate(new_crtc_state, new_plane_state);
 367
 368        return intel_plane_atomic_calc_changes(old_crtc_state, new_crtc_state,
 369                                               old_plane_state, new_plane_state);
 370}
 371
 372static struct intel_plane *
 373intel_crtc_get_plane(struct intel_crtc *crtc, enum plane_id plane_id)
 374{
 375        struct drm_i915_private *i915 = to_i915(crtc->base.dev);
 376        struct intel_plane *plane;
 377
 378        for_each_intel_plane_on_crtc(&i915->drm, crtc, plane) {
 379                if (plane->id == plane_id)
 380                        return plane;
 381        }
 382
 383        return NULL;
 384}
 385
 386int intel_plane_atomic_check(struct intel_atomic_state *state,
 387                             struct intel_plane *plane)
 388{
 389        struct drm_i915_private *i915 = to_i915(state->base.dev);
 390        struct intel_plane_state *new_plane_state =
 391                intel_atomic_get_new_plane_state(state, plane);
 392        const struct intel_plane_state *old_plane_state =
 393                intel_atomic_get_old_plane_state(state, plane);
 394        const struct intel_plane_state *new_master_plane_state;
 395        struct intel_crtc *crtc = intel_get_crtc_for_pipe(i915, plane->pipe);
 396        const struct intel_crtc_state *old_crtc_state =
 397                intel_atomic_get_old_crtc_state(state, crtc);
 398        struct intel_crtc_state *new_crtc_state =
 399                intel_atomic_get_new_crtc_state(state, crtc);
 400
 401        if (new_crtc_state && new_crtc_state->bigjoiner_slave) {
 402                struct intel_plane *master_plane =
 403                        intel_crtc_get_plane(new_crtc_state->bigjoiner_linked_crtc,
 404                                             plane->id);
 405
 406                new_master_plane_state =
 407                        intel_atomic_get_new_plane_state(state, master_plane);
 408        } else {
 409                new_master_plane_state = new_plane_state;
 410        }
 411
 412        intel_plane_copy_uapi_to_hw_state(new_plane_state,
 413                                          new_master_plane_state,
 414                                          crtc);
 415
 416        new_plane_state->uapi.visible = false;
 417        if (!new_crtc_state)
 418                return 0;
 419
 420        return intel_plane_atomic_check_with_state(old_crtc_state,
 421                                                   new_crtc_state,
 422                                                   old_plane_state,
 423                                                   new_plane_state);
 424}
 425
 426static struct intel_plane *
 427skl_next_plane_to_commit(struct intel_atomic_state *state,
 428                         struct intel_crtc *crtc,
 429                         struct skl_ddb_entry entries_y[I915_MAX_PLANES],
 430                         struct skl_ddb_entry entries_uv[I915_MAX_PLANES],
 431                         unsigned int *update_mask)
 432{
 433        struct intel_crtc_state *crtc_state =
 434                intel_atomic_get_new_crtc_state(state, crtc);
 435        struct intel_plane_state *plane_state;
 436        struct intel_plane *plane;
 437        int i;
 438
 439        if (*update_mask == 0)
 440                return NULL;
 441
 442        for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
 443                enum plane_id plane_id = plane->id;
 444
 445                if (crtc->pipe != plane->pipe ||
 446                    !(*update_mask & BIT(plane_id)))
 447                        continue;
 448
 449                if (skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_y[plane_id],
 450                                                entries_y,
 451                                                I915_MAX_PLANES, plane_id) ||
 452                    skl_ddb_allocation_overlaps(&crtc_state->wm.skl.plane_ddb_uv[plane_id],
 453                                                entries_uv,
 454                                                I915_MAX_PLANES, plane_id))
 455                        continue;
 456
 457                *update_mask &= ~BIT(plane_id);
 458                entries_y[plane_id] = crtc_state->wm.skl.plane_ddb_y[plane_id];
 459                entries_uv[plane_id] = crtc_state->wm.skl.plane_ddb_uv[plane_id];
 460
 461                return plane;
 462        }
 463
 464        /* should never happen */
 465        drm_WARN_ON(state->base.dev, 1);
 466
 467        return NULL;
 468}
 469
 470void intel_update_plane(struct intel_plane *plane,
 471                        const struct intel_crtc_state *crtc_state,
 472                        const struct intel_plane_state *plane_state)
 473{
 474        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 475
 476        trace_intel_update_plane(&plane->base, crtc);
 477
 478        if (crtc_state->uapi.async_flip && plane->async_flip)
 479                plane->async_flip(plane, crtc_state, plane_state, true);
 480        else
 481                plane->update_plane(plane, crtc_state, plane_state);
 482}
 483
 484void intel_disable_plane(struct intel_plane *plane,
 485                         const struct intel_crtc_state *crtc_state)
 486{
 487        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 488
 489        trace_intel_disable_plane(&plane->base, crtc);
 490        plane->disable_plane(plane, crtc_state);
 491}
 492
 493void skl_update_planes_on_crtc(struct intel_atomic_state *state,
 494                               struct intel_crtc *crtc)
 495{
 496        struct intel_crtc_state *old_crtc_state =
 497                intel_atomic_get_old_crtc_state(state, crtc);
 498        struct intel_crtc_state *new_crtc_state =
 499                intel_atomic_get_new_crtc_state(state, crtc);
 500        struct skl_ddb_entry entries_y[I915_MAX_PLANES];
 501        struct skl_ddb_entry entries_uv[I915_MAX_PLANES];
 502        u32 update_mask = new_crtc_state->update_planes;
 503        struct intel_plane *plane;
 504
 505        memcpy(entries_y, old_crtc_state->wm.skl.plane_ddb_y,
 506               sizeof(old_crtc_state->wm.skl.plane_ddb_y));
 507        memcpy(entries_uv, old_crtc_state->wm.skl.plane_ddb_uv,
 508               sizeof(old_crtc_state->wm.skl.plane_ddb_uv));
 509
 510        while ((plane = skl_next_plane_to_commit(state, crtc,
 511                                                 entries_y, entries_uv,
 512                                                 &update_mask))) {
 513                struct intel_plane_state *new_plane_state =
 514                        intel_atomic_get_new_plane_state(state, plane);
 515
 516                if (new_plane_state->uapi.visible ||
 517                    new_plane_state->planar_slave) {
 518                        intel_update_plane(plane, new_crtc_state, new_plane_state);
 519                } else {
 520                        intel_disable_plane(plane, new_crtc_state);
 521                }
 522        }
 523}
 524
 525void i9xx_update_planes_on_crtc(struct intel_atomic_state *state,
 526                                struct intel_crtc *crtc)
 527{
 528        struct intel_crtc_state *new_crtc_state =
 529                intel_atomic_get_new_crtc_state(state, crtc);
 530        u32 update_mask = new_crtc_state->update_planes;
 531        struct intel_plane_state *new_plane_state;
 532        struct intel_plane *plane;
 533        int i;
 534
 535        for_each_new_intel_plane_in_state(state, plane, new_plane_state, i) {
 536                if (crtc->pipe != plane->pipe ||
 537                    !(update_mask & BIT(plane->id)))
 538                        continue;
 539
 540                if (new_plane_state->uapi.visible)
 541                        intel_update_plane(plane, new_crtc_state, new_plane_state);
 542                else
 543                        intel_disable_plane(plane, new_crtc_state);
 544        }
 545}
 546
 547int intel_atomic_plane_check_clipping(struct intel_plane_state *plane_state,
 548                                      struct intel_crtc_state *crtc_state,
 549                                      int min_scale, int max_scale,
 550                                      bool can_position)
 551{
 552        struct drm_framebuffer *fb = plane_state->hw.fb;
 553        struct drm_rect *src = &plane_state->uapi.src;
 554        struct drm_rect *dst = &plane_state->uapi.dst;
 555        unsigned int rotation = plane_state->hw.rotation;
 556        struct drm_rect clip = {};
 557        int hscale, vscale;
 558
 559        if (!fb) {
 560                plane_state->uapi.visible = false;
 561                return 0;
 562        }
 563
 564        drm_rect_rotate(src, fb->width << 16, fb->height << 16, rotation);
 565
 566        /* Check scaling */
 567        hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
 568        vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
 569        if (hscale < 0 || vscale < 0) {
 570                DRM_DEBUG_KMS("Invalid scaling of plane\n");
 571                drm_rect_debug_print("src: ", src, true);
 572                drm_rect_debug_print("dst: ", dst, false);
 573                return -ERANGE;
 574        }
 575
 576        if (crtc_state->hw.enable) {
 577                clip.x2 = crtc_state->pipe_src_w;
 578                clip.y2 = crtc_state->pipe_src_h;
 579        }
 580
 581        /* right side of the image is on the slave crtc, adjust dst to match */
 582        if (crtc_state->bigjoiner_slave)
 583                drm_rect_translate(dst, -crtc_state->pipe_src_w, 0);
 584
 585        /*
 586         * FIXME: This might need further adjustment for seamless scaling
 587         * with phase information, for the 2p2 and 2p1 scenarios.
 588         */
 589        plane_state->uapi.visible = drm_rect_clip_scaled(src, dst, &clip);
 590
 591        drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16, rotation);
 592
 593        if (!can_position && plane_state->uapi.visible &&
 594            !drm_rect_equals(dst, &clip)) {
 595                DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
 596                drm_rect_debug_print("dst: ", dst, false);
 597                drm_rect_debug_print("clip: ", &clip, false);
 598                return -EINVAL;
 599        }
 600
 601        return 0;
 602}
 603
 604static const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
 605        .prepare_fb = intel_prepare_plane_fb,
 606        .cleanup_fb = intel_cleanup_plane_fb,
 607};
 608
 609void intel_plane_helper_add(struct intel_plane *plane)
 610{
 611        drm_plane_helper_add(&plane->base, &intel_plane_helper_funcs);
 612}
 613