Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2015 Broadcom
0004  */
0005 
0006 /**
0007  * DOC: VC4 plane module
0008  *
0009  * Each DRM plane is a layer of pixels being scanned out by the HVS.
0010  *
0011  * At atomic modeset check time, we compute the HVS display element
0012  * state that would be necessary for displaying the plane (giving us a
0013  * chance to figure out if a plane configuration is invalid), then at
0014  * atomic flush time the CRTC will ask us to write our element state
0015  * into the region of the HVS that it has allocated for us.
0016  */
0017 
0018 #include <drm/drm_atomic.h>
0019 #include <drm/drm_atomic_helper.h>
0020 #include <drm/drm_atomic_uapi.h>
0021 #include <drm/drm_blend.h>
0022 #include <drm/drm_fb_cma_helper.h>
0023 #include <drm/drm_fourcc.h>
0024 #include <drm/drm_framebuffer.h>
0025 #include <drm/drm_gem_atomic_helper.h>
0026 #include <drm/drm_plane_helper.h>
0027 
0028 #include "uapi/drm/vc4_drm.h"
0029 
0030 #include "vc4_drv.h"
0031 #include "vc4_regs.h"
0032 
0033 static const struct hvs_format {
0034     u32 drm; /* DRM_FORMAT_* */
0035     u32 hvs; /* HVS_FORMAT_* */
0036     u32 pixel_order;
0037     u32 pixel_order_hvs5;
0038     bool hvs5_only;
0039 } hvs_formats[] = {
0040     {
0041         .drm = DRM_FORMAT_XRGB8888,
0042         .hvs = HVS_PIXEL_FORMAT_RGBA8888,
0043         .pixel_order = HVS_PIXEL_ORDER_ABGR,
0044         .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
0045     },
0046     {
0047         .drm = DRM_FORMAT_ARGB8888,
0048         .hvs = HVS_PIXEL_FORMAT_RGBA8888,
0049         .pixel_order = HVS_PIXEL_ORDER_ABGR,
0050         .pixel_order_hvs5 = HVS_PIXEL_ORDER_ARGB,
0051     },
0052     {
0053         .drm = DRM_FORMAT_ABGR8888,
0054         .hvs = HVS_PIXEL_FORMAT_RGBA8888,
0055         .pixel_order = HVS_PIXEL_ORDER_ARGB,
0056         .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
0057     },
0058     {
0059         .drm = DRM_FORMAT_XBGR8888,
0060         .hvs = HVS_PIXEL_FORMAT_RGBA8888,
0061         .pixel_order = HVS_PIXEL_ORDER_ARGB,
0062         .pixel_order_hvs5 = HVS_PIXEL_ORDER_ABGR,
0063     },
0064     {
0065         .drm = DRM_FORMAT_RGB565,
0066         .hvs = HVS_PIXEL_FORMAT_RGB565,
0067         .pixel_order = HVS_PIXEL_ORDER_XRGB,
0068     },
0069     {
0070         .drm = DRM_FORMAT_BGR565,
0071         .hvs = HVS_PIXEL_FORMAT_RGB565,
0072         .pixel_order = HVS_PIXEL_ORDER_XBGR,
0073     },
0074     {
0075         .drm = DRM_FORMAT_ARGB1555,
0076         .hvs = HVS_PIXEL_FORMAT_RGBA5551,
0077         .pixel_order = HVS_PIXEL_ORDER_ABGR,
0078     },
0079     {
0080         .drm = DRM_FORMAT_XRGB1555,
0081         .hvs = HVS_PIXEL_FORMAT_RGBA5551,
0082         .pixel_order = HVS_PIXEL_ORDER_ABGR,
0083     },
0084     {
0085         .drm = DRM_FORMAT_RGB888,
0086         .hvs = HVS_PIXEL_FORMAT_RGB888,
0087         .pixel_order = HVS_PIXEL_ORDER_XRGB,
0088     },
0089     {
0090         .drm = DRM_FORMAT_BGR888,
0091         .hvs = HVS_PIXEL_FORMAT_RGB888,
0092         .pixel_order = HVS_PIXEL_ORDER_XBGR,
0093     },
0094     {
0095         .drm = DRM_FORMAT_YUV422,
0096         .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
0097         .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
0098     },
0099     {
0100         .drm = DRM_FORMAT_YVU422,
0101         .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE,
0102         .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
0103     },
0104     {
0105         .drm = DRM_FORMAT_YUV420,
0106         .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
0107         .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
0108     },
0109     {
0110         .drm = DRM_FORMAT_YVU420,
0111         .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE,
0112         .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
0113     },
0114     {
0115         .drm = DRM_FORMAT_NV12,
0116         .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
0117         .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
0118     },
0119     {
0120         .drm = DRM_FORMAT_NV21,
0121         .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE,
0122         .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
0123     },
0124     {
0125         .drm = DRM_FORMAT_NV16,
0126         .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
0127         .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
0128     },
0129     {
0130         .drm = DRM_FORMAT_NV61,
0131         .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE,
0132         .pixel_order = HVS_PIXEL_ORDER_XYCRCB,
0133     },
0134     {
0135         .drm = DRM_FORMAT_P030,
0136         .hvs = HVS_PIXEL_FORMAT_YCBCR_10BIT,
0137         .pixel_order = HVS_PIXEL_ORDER_XYCBCR,
0138         .hvs5_only = true,
0139     },
0140 };
0141 
0142 static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
0143 {
0144     unsigned i;
0145 
0146     for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
0147         if (hvs_formats[i].drm == drm_format)
0148             return &hvs_formats[i];
0149     }
0150 
0151     return NULL;
0152 }
0153 
0154 static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst)
0155 {
0156     if (dst == src)
0157         return VC4_SCALING_NONE;
0158     if (3 * dst >= 2 * src)
0159         return VC4_SCALING_PPF;
0160     else
0161         return VC4_SCALING_TPZ;
0162 }
0163 
0164 static bool plane_enabled(struct drm_plane_state *state)
0165 {
0166     return state->fb && !WARN_ON(!state->crtc);
0167 }
0168 
0169 static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
0170 {
0171     struct vc4_plane_state *vc4_state;
0172 
0173     if (WARN_ON(!plane->state))
0174         return NULL;
0175 
0176     vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL);
0177     if (!vc4_state)
0178         return NULL;
0179 
0180     memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm));
0181     vc4_state->dlist_initialized = 0;
0182 
0183     __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base);
0184 
0185     if (vc4_state->dlist) {
0186         vc4_state->dlist = kmemdup(vc4_state->dlist,
0187                        vc4_state->dlist_count * 4,
0188                        GFP_KERNEL);
0189         if (!vc4_state->dlist) {
0190             kfree(vc4_state);
0191             return NULL;
0192         }
0193         vc4_state->dlist_size = vc4_state->dlist_count;
0194     }
0195 
0196     return &vc4_state->base;
0197 }
0198 
0199 static void vc4_plane_destroy_state(struct drm_plane *plane,
0200                     struct drm_plane_state *state)
0201 {
0202     struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
0203     struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
0204 
0205     if (drm_mm_node_allocated(&vc4_state->lbm)) {
0206         unsigned long irqflags;
0207 
0208         spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
0209         drm_mm_remove_node(&vc4_state->lbm);
0210         spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
0211     }
0212 
0213     kfree(vc4_state->dlist);
0214     __drm_atomic_helper_plane_destroy_state(&vc4_state->base);
0215     kfree(state);
0216 }
0217 
0218 /* Called during init to allocate the plane's atomic state. */
0219 static void vc4_plane_reset(struct drm_plane *plane)
0220 {
0221     struct vc4_plane_state *vc4_state;
0222 
0223     WARN_ON(plane->state);
0224 
0225     vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL);
0226     if (!vc4_state)
0227         return;
0228 
0229     __drm_atomic_helper_plane_reset(plane, &vc4_state->base);
0230 }
0231 
0232 static void vc4_dlist_counter_increment(struct vc4_plane_state *vc4_state)
0233 {
0234     if (vc4_state->dlist_count == vc4_state->dlist_size) {
0235         u32 new_size = max(4u, vc4_state->dlist_count * 2);
0236         u32 *new_dlist = kmalloc_array(new_size, 4, GFP_KERNEL);
0237 
0238         if (!new_dlist)
0239             return;
0240         memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4);
0241 
0242         kfree(vc4_state->dlist);
0243         vc4_state->dlist = new_dlist;
0244         vc4_state->dlist_size = new_size;
0245     }
0246 
0247     vc4_state->dlist_count++;
0248 }
0249 
0250 static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val)
0251 {
0252     unsigned int idx = vc4_state->dlist_count;
0253 
0254     vc4_dlist_counter_increment(vc4_state);
0255     vc4_state->dlist[idx] = val;
0256 }
0257 
0258 /* Returns the scl0/scl1 field based on whether the dimensions need to
0259  * be up/down/non-scaled.
0260  *
0261  * This is a replication of a table from the spec.
0262  */
0263 static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane)
0264 {
0265     struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
0266 
0267     switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) {
0268     case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF:
0269         return SCALER_CTL0_SCL_H_PPF_V_PPF;
0270     case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF:
0271         return SCALER_CTL0_SCL_H_TPZ_V_PPF;
0272     case VC4_SCALING_PPF << 2 | VC4_SCALING_TPZ:
0273         return SCALER_CTL0_SCL_H_PPF_V_TPZ;
0274     case VC4_SCALING_TPZ << 2 | VC4_SCALING_TPZ:
0275         return SCALER_CTL0_SCL_H_TPZ_V_TPZ;
0276     case VC4_SCALING_PPF << 2 | VC4_SCALING_NONE:
0277         return SCALER_CTL0_SCL_H_PPF_V_NONE;
0278     case VC4_SCALING_NONE << 2 | VC4_SCALING_PPF:
0279         return SCALER_CTL0_SCL_H_NONE_V_PPF;
0280     case VC4_SCALING_NONE << 2 | VC4_SCALING_TPZ:
0281         return SCALER_CTL0_SCL_H_NONE_V_TPZ;
0282     case VC4_SCALING_TPZ << 2 | VC4_SCALING_NONE:
0283         return SCALER_CTL0_SCL_H_TPZ_V_NONE;
0284     default:
0285     case VC4_SCALING_NONE << 2 | VC4_SCALING_NONE:
0286         /* The unity case is independently handled by
0287          * SCALER_CTL0_UNITY.
0288          */
0289         return 0;
0290     }
0291 }
0292 
0293 static int vc4_plane_margins_adj(struct drm_plane_state *pstate)
0294 {
0295     struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate);
0296     unsigned int left, right, top, bottom, adjhdisplay, adjvdisplay;
0297     struct drm_crtc_state *crtc_state;
0298 
0299     crtc_state = drm_atomic_get_new_crtc_state(pstate->state,
0300                            pstate->crtc);
0301 
0302     vc4_crtc_get_margins(crtc_state, &left, &right, &top, &bottom);
0303     if (!left && !right && !top && !bottom)
0304         return 0;
0305 
0306     if (left + right >= crtc_state->mode.hdisplay ||
0307         top + bottom >= crtc_state->mode.vdisplay)
0308         return -EINVAL;
0309 
0310     adjhdisplay = crtc_state->mode.hdisplay - (left + right);
0311     vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x *
0312                            adjhdisplay,
0313                            crtc_state->mode.hdisplay);
0314     vc4_pstate->crtc_x += left;
0315     if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - right)
0316         vc4_pstate->crtc_x = crtc_state->mode.hdisplay - right;
0317 
0318     adjvdisplay = crtc_state->mode.vdisplay - (top + bottom);
0319     vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y *
0320                            adjvdisplay,
0321                            crtc_state->mode.vdisplay);
0322     vc4_pstate->crtc_y += top;
0323     if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - bottom)
0324         vc4_pstate->crtc_y = crtc_state->mode.vdisplay - bottom;
0325 
0326     vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w *
0327                            adjhdisplay,
0328                            crtc_state->mode.hdisplay);
0329     vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h *
0330                            adjvdisplay,
0331                            crtc_state->mode.vdisplay);
0332 
0333     if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h)
0334         return -EINVAL;
0335 
0336     return 0;
0337 }
0338 
0339 static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state)
0340 {
0341     struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
0342     struct drm_framebuffer *fb = state->fb;
0343     struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
0344     int num_planes = fb->format->num_planes;
0345     struct drm_crtc_state *crtc_state;
0346     u32 h_subsample = fb->format->hsub;
0347     u32 v_subsample = fb->format->vsub;
0348     int i, ret;
0349 
0350     crtc_state = drm_atomic_get_existing_crtc_state(state->state,
0351                             state->crtc);
0352     if (!crtc_state) {
0353         DRM_DEBUG_KMS("Invalid crtc state\n");
0354         return -EINVAL;
0355     }
0356 
0357     ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1,
0358                           INT_MAX, true, true);
0359     if (ret)
0360         return ret;
0361 
0362     for (i = 0; i < num_planes; i++)
0363         vc4_state->offsets[i] = bo->paddr + fb->offsets[i];
0364 
0365     /*
0366      * We don't support subpixel source positioning for scaling,
0367      * but fractional coordinates can be generated by clipping
0368      * so just round for now
0369      */
0370     vc4_state->src_x = DIV_ROUND_CLOSEST(state->src.x1, 1 << 16);
0371     vc4_state->src_y = DIV_ROUND_CLOSEST(state->src.y1, 1 << 16);
0372     vc4_state->src_w[0] = DIV_ROUND_CLOSEST(state->src.x2, 1 << 16) - vc4_state->src_x;
0373     vc4_state->src_h[0] = DIV_ROUND_CLOSEST(state->src.y2, 1 << 16) - vc4_state->src_y;
0374 
0375     vc4_state->crtc_x = state->dst.x1;
0376     vc4_state->crtc_y = state->dst.y1;
0377     vc4_state->crtc_w = state->dst.x2 - state->dst.x1;
0378     vc4_state->crtc_h = state->dst.y2 - state->dst.y1;
0379 
0380     ret = vc4_plane_margins_adj(state);
0381     if (ret)
0382         return ret;
0383 
0384     vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0],
0385                                vc4_state->crtc_w);
0386     vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0],
0387                                vc4_state->crtc_h);
0388 
0389     vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE &&
0390                    vc4_state->y_scaling[0] == VC4_SCALING_NONE);
0391 
0392     if (num_planes > 1) {
0393         vc4_state->is_yuv = true;
0394 
0395         vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample;
0396         vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample;
0397 
0398         vc4_state->x_scaling[1] =
0399             vc4_get_scaling_mode(vc4_state->src_w[1],
0400                          vc4_state->crtc_w);
0401         vc4_state->y_scaling[1] =
0402             vc4_get_scaling_mode(vc4_state->src_h[1],
0403                          vc4_state->crtc_h);
0404 
0405         /* YUV conversion requires that horizontal scaling be enabled
0406          * on the UV plane even if vc4_get_scaling_mode() returned
0407          * VC4_SCALING_NONE (which can happen when the down-scaling
0408          * ratio is 0.5). Let's force it to VC4_SCALING_PPF in this
0409          * case.
0410          */
0411         if (vc4_state->x_scaling[1] == VC4_SCALING_NONE)
0412             vc4_state->x_scaling[1] = VC4_SCALING_PPF;
0413     } else {
0414         vc4_state->is_yuv = false;
0415         vc4_state->x_scaling[1] = VC4_SCALING_NONE;
0416         vc4_state->y_scaling[1] = VC4_SCALING_NONE;
0417     }
0418 
0419     return 0;
0420 }
0421 
0422 static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
0423 {
0424     u32 scale, recip;
0425 
0426     scale = (1 << 16) * src / dst;
0427 
0428     /* The specs note that while the reciprocal would be defined
0429      * as (1<<32)/scale, ~0 is close enough.
0430      */
0431     recip = ~0 / scale;
0432 
0433     vc4_dlist_write(vc4_state,
0434             VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) |
0435             VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE));
0436     vc4_dlist_write(vc4_state,
0437             VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP));
0438 }
0439 
0440 static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst)
0441 {
0442     u32 scale = (1 << 16) * src / dst;
0443 
0444     vc4_dlist_write(vc4_state,
0445             SCALER_PPF_AGC |
0446             VC4_SET_FIELD(scale, SCALER_PPF_SCALE) |
0447             VC4_SET_FIELD(0, SCALER_PPF_IPHASE));
0448 }
0449 
0450 static u32 vc4_lbm_size(struct drm_plane_state *state)
0451 {
0452     struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
0453     struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
0454     u32 pix_per_line;
0455     u32 lbm;
0456 
0457     /* LBM is not needed when there's no vertical scaling. */
0458     if (vc4_state->y_scaling[0] == VC4_SCALING_NONE &&
0459         vc4_state->y_scaling[1] == VC4_SCALING_NONE)
0460         return 0;
0461 
0462     /*
0463      * This can be further optimized in the RGB/YUV444 case if the PPF
0464      * decimation factor is between 0.5 and 1.0 by using crtc_w.
0465      *
0466      * It's not an issue though, since in that case since src_w[0] is going
0467      * to be greater than or equal to crtc_w.
0468      */
0469     if (vc4_state->x_scaling[0] == VC4_SCALING_TPZ)
0470         pix_per_line = vc4_state->crtc_w;
0471     else
0472         pix_per_line = vc4_state->src_w[0];
0473 
0474     if (!vc4_state->is_yuv) {
0475         if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ)
0476             lbm = pix_per_line * 8;
0477         else {
0478             /* In special cases, this multiplier might be 12. */
0479             lbm = pix_per_line * 16;
0480         }
0481     } else {
0482         /* There are cases for this going down to a multiplier
0483          * of 2, but according to the firmware source, the
0484          * table in the docs is somewhat wrong.
0485          */
0486         lbm = pix_per_line * 16;
0487     }
0488 
0489     /* Align it to 64 or 128 (hvs5) bytes */
0490     lbm = roundup(lbm, vc4->is_vc5 ? 128 : 64);
0491 
0492     /* Each "word" of the LBM memory contains 2 or 4 (hvs5) pixels */
0493     lbm /= vc4->is_vc5 ? 4 : 2;
0494 
0495     return lbm;
0496 }
0497 
0498 static void vc4_write_scaling_parameters(struct drm_plane_state *state,
0499                      int channel)
0500 {
0501     struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
0502 
0503     /* Ch0 H-PPF Word 0: Scaling Parameters */
0504     if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) {
0505         vc4_write_ppf(vc4_state,
0506                   vc4_state->src_w[channel], vc4_state->crtc_w);
0507     }
0508 
0509     /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */
0510     if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) {
0511         vc4_write_ppf(vc4_state,
0512                   vc4_state->src_h[channel], vc4_state->crtc_h);
0513         vc4_dlist_write(vc4_state, 0xc0c0c0c0);
0514     }
0515 
0516     /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */
0517     if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) {
0518         vc4_write_tpz(vc4_state,
0519                   vc4_state->src_w[channel], vc4_state->crtc_w);
0520     }
0521 
0522     /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */
0523     if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) {
0524         vc4_write_tpz(vc4_state,
0525                   vc4_state->src_h[channel], vc4_state->crtc_h);
0526         vc4_dlist_write(vc4_state, 0xc0c0c0c0);
0527     }
0528 }
0529 
0530 static void vc4_plane_calc_load(struct drm_plane_state *state)
0531 {
0532     unsigned int hvs_load_shift, vrefresh, i;
0533     struct drm_framebuffer *fb = state->fb;
0534     struct vc4_plane_state *vc4_state;
0535     struct drm_crtc_state *crtc_state;
0536     unsigned int vscale_factor;
0537 
0538     vc4_state = to_vc4_plane_state(state);
0539     crtc_state = drm_atomic_get_existing_crtc_state(state->state,
0540                             state->crtc);
0541     vrefresh = drm_mode_vrefresh(&crtc_state->adjusted_mode);
0542 
0543     /* The HVS is able to process 2 pixels/cycle when scaling the source,
0544      * 4 pixels/cycle otherwise.
0545      * Alpha blending step seems to be pipelined and it's always operating
0546      * at 4 pixels/cycle, so the limiting aspect here seems to be the
0547      * scaler block.
0548      * HVS load is expressed in clk-cycles/sec (AKA Hz).
0549      */
0550     if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
0551         vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
0552         vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
0553         vc4_state->y_scaling[1] != VC4_SCALING_NONE)
0554         hvs_load_shift = 1;
0555     else
0556         hvs_load_shift = 2;
0557 
0558     vc4_state->membus_load = 0;
0559     vc4_state->hvs_load = 0;
0560     for (i = 0; i < fb->format->num_planes; i++) {
0561         /* Even if the bandwidth/plane required for a single frame is
0562          *
0563          * vc4_state->src_w[i] * vc4_state->src_h[i] * cpp * vrefresh
0564          *
0565          * when downscaling, we have to read more pixels per line in
0566          * the time frame reserved for a single line, so the bandwidth
0567          * demand can be punctually higher. To account for that, we
0568          * calculate the down-scaling factor and multiply the plane
0569          * load by this number. We're likely over-estimating the read
0570          * demand, but that's better than under-estimating it.
0571          */
0572         vscale_factor = DIV_ROUND_UP(vc4_state->src_h[i],
0573                          vc4_state->crtc_h);
0574         vc4_state->membus_load += vc4_state->src_w[i] *
0575                       vc4_state->src_h[i] * vscale_factor *
0576                       fb->format->cpp[i];
0577         vc4_state->hvs_load += vc4_state->crtc_h * vc4_state->crtc_w;
0578     }
0579 
0580     vc4_state->hvs_load *= vrefresh;
0581     vc4_state->hvs_load >>= hvs_load_shift;
0582     vc4_state->membus_load *= vrefresh;
0583 }
0584 
0585 static int vc4_plane_allocate_lbm(struct drm_plane_state *state)
0586 {
0587     struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev);
0588     struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
0589     unsigned long irqflags;
0590     u32 lbm_size;
0591 
0592     lbm_size = vc4_lbm_size(state);
0593     if (!lbm_size)
0594         return 0;
0595 
0596     if (WARN_ON(!vc4_state->lbm_offset))
0597         return -EINVAL;
0598 
0599     /* Allocate the LBM memory that the HVS will use for temporary
0600      * storage due to our scaling/format conversion.
0601      */
0602     if (!drm_mm_node_allocated(&vc4_state->lbm)) {
0603         int ret;
0604 
0605         spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags);
0606         ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm,
0607                          &vc4_state->lbm,
0608                          lbm_size,
0609                          vc4->is_vc5 ? 64 : 32,
0610                          0, 0);
0611         spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags);
0612 
0613         if (ret)
0614             return ret;
0615     } else {
0616         WARN_ON_ONCE(lbm_size != vc4_state->lbm.size);
0617     }
0618 
0619     vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start;
0620 
0621     return 0;
0622 }
0623 
0624 /*
0625  * The colorspace conversion matrices are held in 3 entries in the dlist.
0626  * Create an array of them, with entries for each full and limited mode, and
0627  * each supported colorspace.
0628  */
0629 static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
0630     {
0631         /* Limited range */
0632         {
0633             /* BT601 */
0634             SCALER_CSC0_ITR_R_601_5,
0635             SCALER_CSC1_ITR_R_601_5,
0636             SCALER_CSC2_ITR_R_601_5,
0637         }, {
0638             /* BT709 */
0639             SCALER_CSC0_ITR_R_709_3,
0640             SCALER_CSC1_ITR_R_709_3,
0641             SCALER_CSC2_ITR_R_709_3,
0642         }, {
0643             /* BT2020 */
0644             SCALER_CSC0_ITR_R_2020,
0645             SCALER_CSC1_ITR_R_2020,
0646             SCALER_CSC2_ITR_R_2020,
0647         }
0648     }, {
0649         /* Full range */
0650         {
0651             /* JFIF */
0652             SCALER_CSC0_JPEG_JFIF,
0653             SCALER_CSC1_JPEG_JFIF,
0654             SCALER_CSC2_JPEG_JFIF,
0655         }, {
0656             /* BT709 */
0657             SCALER_CSC0_ITR_R_709_3_FR,
0658             SCALER_CSC1_ITR_R_709_3_FR,
0659             SCALER_CSC2_ITR_R_709_3_FR,
0660         }, {
0661             /* BT2020 */
0662             SCALER_CSC0_ITR_R_2020_FR,
0663             SCALER_CSC1_ITR_R_2020_FR,
0664             SCALER_CSC2_ITR_R_2020_FR,
0665         }
0666     }
0667 };
0668 
0669 static u32 vc4_hvs4_get_alpha_blend_mode(struct drm_plane_state *state)
0670 {
0671     if (!state->fb->format->has_alpha)
0672         return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED,
0673                      SCALER_POS2_ALPHA_MODE);
0674 
0675     switch (state->pixel_blend_mode) {
0676     case DRM_MODE_BLEND_PIXEL_NONE:
0677         return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_FIXED,
0678                      SCALER_POS2_ALPHA_MODE);
0679     default:
0680     case DRM_MODE_BLEND_PREMULTI:
0681         return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE,
0682                      SCALER_POS2_ALPHA_MODE) |
0683             SCALER_POS2_ALPHA_PREMULT;
0684     case DRM_MODE_BLEND_COVERAGE:
0685         return VC4_SET_FIELD(SCALER_POS2_ALPHA_MODE_PIPELINE,
0686                      SCALER_POS2_ALPHA_MODE);
0687     }
0688 }
0689 
0690 static u32 vc4_hvs5_get_alpha_blend_mode(struct drm_plane_state *state)
0691 {
0692     if (!state->fb->format->has_alpha)
0693         return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED,
0694                      SCALER5_CTL2_ALPHA_MODE);
0695 
0696     switch (state->pixel_blend_mode) {
0697     case DRM_MODE_BLEND_PIXEL_NONE:
0698         return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_FIXED,
0699                      SCALER5_CTL2_ALPHA_MODE);
0700     default:
0701     case DRM_MODE_BLEND_PREMULTI:
0702         return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE,
0703                      SCALER5_CTL2_ALPHA_MODE) |
0704             SCALER5_CTL2_ALPHA_PREMULT;
0705     case DRM_MODE_BLEND_COVERAGE:
0706         return VC4_SET_FIELD(SCALER5_CTL2_ALPHA_MODE_PIPELINE,
0707                      SCALER5_CTL2_ALPHA_MODE);
0708     }
0709 }
0710 
0711 /* Writes out a full display list for an active plane to the plane's
0712  * private dlist state.
0713  */
0714 static int vc4_plane_mode_set(struct drm_plane *plane,
0715                   struct drm_plane_state *state)
0716 {
0717     struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
0718     struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
0719     struct drm_framebuffer *fb = state->fb;
0720     u32 ctl0_offset = vc4_state->dlist_count;
0721     const struct hvs_format *format = vc4_get_hvs_format(fb->format->format);
0722     u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier);
0723     int num_planes = fb->format->num_planes;
0724     u32 h_subsample = fb->format->hsub;
0725     u32 v_subsample = fb->format->vsub;
0726     bool mix_plane_alpha;
0727     bool covers_screen;
0728     u32 scl0, scl1, pitch0;
0729     u32 tiling, src_y;
0730     u32 hvs_format = format->hvs;
0731     unsigned int rotation;
0732     int ret, i;
0733 
0734     if (vc4_state->dlist_initialized)
0735         return 0;
0736 
0737     ret = vc4_plane_setup_clipping_and_scaling(state);
0738     if (ret)
0739         return ret;
0740 
0741     /* SCL1 is used for Cb/Cr scaling of planar formats.  For RGB
0742      * and 4:4:4, scl1 should be set to scl0 so both channels of
0743      * the scaler do the same thing.  For YUV, the Y plane needs
0744      * to be put in channel 1 and Cb/Cr in channel 0, so we swap
0745      * the scl fields here.
0746      */
0747     if (num_planes == 1) {
0748         scl0 = vc4_get_scl_field(state, 0);
0749         scl1 = scl0;
0750     } else {
0751         scl0 = vc4_get_scl_field(state, 1);
0752         scl1 = vc4_get_scl_field(state, 0);
0753     }
0754 
0755     rotation = drm_rotation_simplify(state->rotation,
0756                      DRM_MODE_ROTATE_0 |
0757                      DRM_MODE_REFLECT_X |
0758                      DRM_MODE_REFLECT_Y);
0759 
0760     /* We must point to the last line when Y reflection is enabled. */
0761     src_y = vc4_state->src_y;
0762     if (rotation & DRM_MODE_REFLECT_Y)
0763         src_y += vc4_state->src_h[0] - 1;
0764 
0765     switch (base_format_mod) {
0766     case DRM_FORMAT_MOD_LINEAR:
0767         tiling = SCALER_CTL0_TILING_LINEAR;
0768         pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH);
0769 
0770         /* Adjust the base pointer to the first pixel to be scanned
0771          * out.
0772          */
0773         for (i = 0; i < num_planes; i++) {
0774             vc4_state->offsets[i] += src_y /
0775                          (i ? v_subsample : 1) *
0776                          fb->pitches[i];
0777 
0778             vc4_state->offsets[i] += vc4_state->src_x /
0779                          (i ? h_subsample : 1) *
0780                          fb->format->cpp[i];
0781         }
0782 
0783         break;
0784 
0785     case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: {
0786         u32 tile_size_shift = 12; /* T tiles are 4kb */
0787         /* Whole-tile offsets, mostly for setting the pitch. */
0788         u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
0789         u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */
0790         u32 tile_w_mask = (1 << tile_w_shift) - 1;
0791         /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice
0792          * the height (in pixels) of a 4k tile.
0793          */
0794         u32 tile_h_mask = (2 << tile_h_shift) - 1;
0795         /* For T-tiled, the FB pitch is "how many bytes from one row to
0796          * the next, such that
0797          *
0798          *  pitch * tile_h == tile_size * tiles_per_row
0799          */
0800         u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift);
0801         u32 tiles_l = vc4_state->src_x >> tile_w_shift;
0802         u32 tiles_r = tiles_w - tiles_l;
0803         u32 tiles_t = src_y >> tile_h_shift;
0804         /* Intra-tile offsets, which modify the base address (the
0805          * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that
0806          * base address).
0807          */
0808         u32 tile_y = (src_y >> 4) & 1;
0809         u32 subtile_y = (src_y >> 2) & 3;
0810         u32 utile_y = src_y & 3;
0811         u32 x_off = vc4_state->src_x & tile_w_mask;
0812         u32 y_off = src_y & tile_h_mask;
0813 
0814         /* When Y reflection is requested we must set the
0815          * SCALER_PITCH0_TILE_LINE_DIR flag to tell HVS that all lines
0816          * after the initial one should be fetched in descending order,
0817          * which makes sense since we start from the last line and go
0818          * backward.
0819          * Don't know why we need y_off = max_y_off - y_off, but it's
0820          * definitely required (I guess it's also related to the "going
0821          * backward" situation).
0822          */
0823         if (rotation & DRM_MODE_REFLECT_Y) {
0824             y_off = tile_h_mask - y_off;
0825             pitch0 = SCALER_PITCH0_TILE_LINE_DIR;
0826         } else {
0827             pitch0 = 0;
0828         }
0829 
0830         tiling = SCALER_CTL0_TILING_256B_OR_T;
0831         pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) |
0832                VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) |
0833                VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) |
0834                VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R));
0835         vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift);
0836         vc4_state->offsets[0] += subtile_y << 8;
0837         vc4_state->offsets[0] += utile_y << 4;
0838 
0839         /* Rows of tiles alternate left-to-right and right-to-left. */
0840         if (tiles_t & 1) {
0841             pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR;
0842             vc4_state->offsets[0] += (tiles_w - tiles_l) <<
0843                          tile_size_shift;
0844             vc4_state->offsets[0] -= (1 + !tile_y) << 10;
0845         } else {
0846             vc4_state->offsets[0] += tiles_l << tile_size_shift;
0847             vc4_state->offsets[0] += tile_y << 10;
0848         }
0849 
0850         break;
0851     }
0852 
0853     case DRM_FORMAT_MOD_BROADCOM_SAND64:
0854     case DRM_FORMAT_MOD_BROADCOM_SAND128:
0855     case DRM_FORMAT_MOD_BROADCOM_SAND256: {
0856         uint32_t param = fourcc_mod_broadcom_param(fb->modifier);
0857 
0858         if (param > SCALER_TILE_HEIGHT_MASK) {
0859             DRM_DEBUG_KMS("SAND height too large (%d)\n",
0860                       param);
0861             return -EINVAL;
0862         }
0863 
0864         if (fb->format->format == DRM_FORMAT_P030) {
0865             hvs_format = HVS_PIXEL_FORMAT_YCBCR_10BIT;
0866             tiling = SCALER_CTL0_TILING_128B;
0867         } else {
0868             hvs_format = HVS_PIXEL_FORMAT_H264;
0869 
0870             switch (base_format_mod) {
0871             case DRM_FORMAT_MOD_BROADCOM_SAND64:
0872                 tiling = SCALER_CTL0_TILING_64B;
0873                 break;
0874             case DRM_FORMAT_MOD_BROADCOM_SAND128:
0875                 tiling = SCALER_CTL0_TILING_128B;
0876                 break;
0877             case DRM_FORMAT_MOD_BROADCOM_SAND256:
0878                 tiling = SCALER_CTL0_TILING_256B_OR_T;
0879                 break;
0880             default:
0881                 return -EINVAL;
0882             }
0883         }
0884 
0885         /* Adjust the base pointer to the first pixel to be scanned
0886          * out.
0887          *
0888          * For P030, y_ptr [31:4] is the 128bit word for the start pixel
0889          * y_ptr [3:0] is the pixel (0-11) contained within that 128bit
0890          * word that should be taken as the first pixel.
0891          * Ditto uv_ptr [31:4] vs [3:0], however [3:0] contains the
0892          * element within the 128bit word, eg for pixel 3 the value
0893          * should be 6.
0894          */
0895         for (i = 0; i < num_planes; i++) {
0896             u32 tile_w, tile, x_off, pix_per_tile;
0897 
0898             if (fb->format->format == DRM_FORMAT_P030) {
0899                 /*
0900                  * Spec says: bits [31:4] of the given address
0901                  * should point to the 128-bit word containing
0902                  * the desired starting pixel, and bits[3:0]
0903                  * should be between 0 and 11, indicating which
0904                  * of the 12-pixels in that 128-bit word is the
0905                  * first pixel to be used
0906                  */
0907                 u32 remaining_pixels = vc4_state->src_x % 96;
0908                 u32 aligned = remaining_pixels / 12;
0909                 u32 last_bits = remaining_pixels % 12;
0910 
0911                 x_off = aligned * 16 + last_bits;
0912                 tile_w = 128;
0913                 pix_per_tile = 96;
0914             } else {
0915                 switch (base_format_mod) {
0916                 case DRM_FORMAT_MOD_BROADCOM_SAND64:
0917                     tile_w = 64;
0918                     break;
0919                 case DRM_FORMAT_MOD_BROADCOM_SAND128:
0920                     tile_w = 128;
0921                     break;
0922                 case DRM_FORMAT_MOD_BROADCOM_SAND256:
0923                     tile_w = 256;
0924                     break;
0925                 default:
0926                     return -EINVAL;
0927                 }
0928                 pix_per_tile = tile_w / fb->format->cpp[0];
0929                 x_off = (vc4_state->src_x % pix_per_tile) /
0930                     (i ? h_subsample : 1) *
0931                     fb->format->cpp[i];
0932             }
0933 
0934             tile = vc4_state->src_x / pix_per_tile;
0935 
0936             vc4_state->offsets[i] += param * tile_w * tile;
0937             vc4_state->offsets[i] += src_y /
0938                          (i ? v_subsample : 1) *
0939                          tile_w;
0940             vc4_state->offsets[i] += x_off & ~(i ? 1 : 0);
0941         }
0942 
0943         pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT);
0944         break;
0945     }
0946 
0947     default:
0948         DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx",
0949                   (long long)fb->modifier);
0950         return -EINVAL;
0951     }
0952 
0953     /* Don't waste cycles mixing with plane alpha if the set alpha
0954      * is opaque or there is no per-pixel alpha information.
0955      * In any case we use the alpha property value as the fixed alpha.
0956      */
0957     mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
0958               fb->format->has_alpha;
0959 
0960     if (!vc4->is_vc5) {
0961     /* Control word */
0962         vc4_dlist_write(vc4_state,
0963                 SCALER_CTL0_VALID |
0964                 (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) |
0965                 (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) |
0966                 VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) |
0967                 (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) |
0968                 (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
0969                 VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
0970                 (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) |
0971                 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
0972                 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1));
0973 
0974         /* Position Word 0: Image Positions and Alpha Value */
0975         vc4_state->pos0_offset = vc4_state->dlist_count;
0976         vc4_dlist_write(vc4_state,
0977                 VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) |
0978                 VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) |
0979                 VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y));
0980 
0981         /* Position Word 1: Scaled Image Dimensions. */
0982         if (!vc4_state->is_unity) {
0983             vc4_dlist_write(vc4_state,
0984                     VC4_SET_FIELD(vc4_state->crtc_w,
0985                               SCALER_POS1_SCL_WIDTH) |
0986                     VC4_SET_FIELD(vc4_state->crtc_h,
0987                               SCALER_POS1_SCL_HEIGHT));
0988         }
0989 
0990         /* Position Word 2: Source Image Size, Alpha */
0991         vc4_state->pos2_offset = vc4_state->dlist_count;
0992         vc4_dlist_write(vc4_state,
0993                 (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) |
0994                 vc4_hvs4_get_alpha_blend_mode(state) |
0995                 VC4_SET_FIELD(vc4_state->src_w[0],
0996                           SCALER_POS2_WIDTH) |
0997                 VC4_SET_FIELD(vc4_state->src_h[0],
0998                           SCALER_POS2_HEIGHT));
0999 
1000         /* Position Word 3: Context.  Written by the HVS. */
1001         vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1002 
1003     } else {
1004         u32 hvs_pixel_order = format->pixel_order;
1005 
1006         if (format->pixel_order_hvs5)
1007             hvs_pixel_order = format->pixel_order_hvs5;
1008 
1009         /* Control word */
1010         vc4_dlist_write(vc4_state,
1011                 SCALER_CTL0_VALID |
1012                 (hvs_pixel_order << SCALER_CTL0_ORDER_SHIFT) |
1013                 (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) |
1014                 VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) |
1015                 (vc4_state->is_unity ?
1016                         SCALER5_CTL0_UNITY : 0) |
1017                 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) |
1018                 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1) |
1019                 SCALER5_CTL0_ALPHA_EXPAND |
1020                 SCALER5_CTL0_RGB_EXPAND);
1021 
1022         /* Position Word 0: Image Positions and Alpha Value */
1023         vc4_state->pos0_offset = vc4_state->dlist_count;
1024         vc4_dlist_write(vc4_state,
1025                 (rotation & DRM_MODE_REFLECT_Y ?
1026                         SCALER5_POS0_VFLIP : 0) |
1027                 VC4_SET_FIELD(vc4_state->crtc_x,
1028                           SCALER_POS0_START_X) |
1029                 (rotation & DRM_MODE_REFLECT_X ?
1030                           SCALER5_POS0_HFLIP : 0) |
1031                 VC4_SET_FIELD(vc4_state->crtc_y,
1032                           SCALER5_POS0_START_Y)
1033                    );
1034 
1035         /* Control Word 2 */
1036         vc4_dlist_write(vc4_state,
1037                 VC4_SET_FIELD(state->alpha >> 4,
1038                           SCALER5_CTL2_ALPHA) |
1039                 vc4_hvs5_get_alpha_blend_mode(state) |
1040                 (mix_plane_alpha ?
1041                     SCALER5_CTL2_ALPHA_MIX : 0)
1042                    );
1043 
1044         /* Position Word 1: Scaled Image Dimensions. */
1045         if (!vc4_state->is_unity) {
1046             vc4_dlist_write(vc4_state,
1047                     VC4_SET_FIELD(vc4_state->crtc_w,
1048                               SCALER5_POS1_SCL_WIDTH) |
1049                     VC4_SET_FIELD(vc4_state->crtc_h,
1050                               SCALER5_POS1_SCL_HEIGHT));
1051         }
1052 
1053         /* Position Word 2: Source Image Size */
1054         vc4_state->pos2_offset = vc4_state->dlist_count;
1055         vc4_dlist_write(vc4_state,
1056                 VC4_SET_FIELD(vc4_state->src_w[0],
1057                           SCALER5_POS2_WIDTH) |
1058                 VC4_SET_FIELD(vc4_state->src_h[0],
1059                           SCALER5_POS2_HEIGHT));
1060 
1061         /* Position Word 3: Context.  Written by the HVS. */
1062         vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1063     }
1064 
1065 
1066     /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers
1067      *
1068      * The pointers may be any byte address.
1069      */
1070     vc4_state->ptr0_offset = vc4_state->dlist_count;
1071     for (i = 0; i < num_planes; i++)
1072         vc4_dlist_write(vc4_state, vc4_state->offsets[i]);
1073 
1074     /* Pointer Context Word 0/1/2: Written by the HVS */
1075     for (i = 0; i < num_planes; i++)
1076         vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1077 
1078     /* Pitch word 0 */
1079     vc4_dlist_write(vc4_state, pitch0);
1080 
1081     /* Pitch word 1/2 */
1082     for (i = 1; i < num_planes; i++) {
1083         if (hvs_format != HVS_PIXEL_FORMAT_H264 &&
1084             hvs_format != HVS_PIXEL_FORMAT_YCBCR_10BIT) {
1085             vc4_dlist_write(vc4_state,
1086                     VC4_SET_FIELD(fb->pitches[i],
1087                               SCALER_SRC_PITCH));
1088         } else {
1089             vc4_dlist_write(vc4_state, pitch0);
1090         }
1091     }
1092 
1093     /* Colorspace conversion words */
1094     if (vc4_state->is_yuv) {
1095         enum drm_color_encoding color_encoding = state->color_encoding;
1096         enum drm_color_range color_range = state->color_range;
1097         const u32 *ccm;
1098 
1099         if (color_encoding >= DRM_COLOR_ENCODING_MAX)
1100             color_encoding = DRM_COLOR_YCBCR_BT601;
1101         if (color_range >= DRM_COLOR_RANGE_MAX)
1102             color_range = DRM_COLOR_YCBCR_LIMITED_RANGE;
1103 
1104         ccm = colorspace_coeffs[color_range][color_encoding];
1105 
1106         vc4_dlist_write(vc4_state, ccm[0]);
1107         vc4_dlist_write(vc4_state, ccm[1]);
1108         vc4_dlist_write(vc4_state, ccm[2]);
1109     }
1110 
1111     vc4_state->lbm_offset = 0;
1112 
1113     if (vc4_state->x_scaling[0] != VC4_SCALING_NONE ||
1114         vc4_state->x_scaling[1] != VC4_SCALING_NONE ||
1115         vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
1116         vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
1117         /* Reserve a slot for the LBM Base Address. The real value will
1118          * be set when calling vc4_plane_allocate_lbm().
1119          */
1120         if (vc4_state->y_scaling[0] != VC4_SCALING_NONE ||
1121             vc4_state->y_scaling[1] != VC4_SCALING_NONE) {
1122             vc4_state->lbm_offset = vc4_state->dlist_count;
1123             vc4_dlist_counter_increment(vc4_state);
1124         }
1125 
1126         if (num_planes > 1) {
1127             /* Emit Cb/Cr as channel 0 and Y as channel
1128              * 1. This matches how we set up scl0/scl1
1129              * above.
1130              */
1131             vc4_write_scaling_parameters(state, 1);
1132         }
1133         vc4_write_scaling_parameters(state, 0);
1134 
1135         /* If any PPF setup was done, then all the kernel
1136          * pointers get uploaded.
1137          */
1138         if (vc4_state->x_scaling[0] == VC4_SCALING_PPF ||
1139             vc4_state->y_scaling[0] == VC4_SCALING_PPF ||
1140             vc4_state->x_scaling[1] == VC4_SCALING_PPF ||
1141             vc4_state->y_scaling[1] == VC4_SCALING_PPF) {
1142             u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start,
1143                            SCALER_PPF_KERNEL_OFFSET);
1144 
1145             /* HPPF plane 0 */
1146             vc4_dlist_write(vc4_state, kernel);
1147             /* VPPF plane 0 */
1148             vc4_dlist_write(vc4_state, kernel);
1149             /* HPPF plane 1 */
1150             vc4_dlist_write(vc4_state, kernel);
1151             /* VPPF plane 1 */
1152             vc4_dlist_write(vc4_state, kernel);
1153         }
1154     }
1155 
1156     vc4_state->dlist[ctl0_offset] |=
1157         VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE);
1158 
1159     /* crtc_* are already clipped coordinates. */
1160     covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 &&
1161             vc4_state->crtc_w == state->crtc->mode.hdisplay &&
1162             vc4_state->crtc_h == state->crtc->mode.vdisplay;
1163     /* Background fill might be necessary when the plane has per-pixel
1164      * alpha content or a non-opaque plane alpha and could blend from the
1165      * background or does not cover the entire screen.
1166      */
1167     vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||
1168                    state->alpha != DRM_BLEND_ALPHA_OPAQUE;
1169 
1170     /* Flag the dlist as initialized to avoid checking it twice in case
1171      * the async update check already called vc4_plane_mode_set() and
1172      * decided to fallback to sync update because async update was not
1173      * possible.
1174      */
1175     vc4_state->dlist_initialized = 1;
1176 
1177     vc4_plane_calc_load(state);
1178 
1179     return 0;
1180 }
1181 
1182 /* If a modeset involves changing the setup of a plane, the atomic
1183  * infrastructure will call this to validate a proposed plane setup.
1184  * However, if a plane isn't getting updated, this (and the
1185  * corresponding vc4_plane_atomic_update) won't get called.  Thus, we
1186  * compute the dlist here and have all active plane dlists get updated
1187  * in the CRTC's flush.
1188  */
1189 static int vc4_plane_atomic_check(struct drm_plane *plane,
1190                   struct drm_atomic_state *state)
1191 {
1192     struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1193                                          plane);
1194     struct vc4_plane_state *vc4_state = to_vc4_plane_state(new_plane_state);
1195     int ret;
1196 
1197     vc4_state->dlist_count = 0;
1198 
1199     if (!plane_enabled(new_plane_state))
1200         return 0;
1201 
1202     ret = vc4_plane_mode_set(plane, new_plane_state);
1203     if (ret)
1204         return ret;
1205 
1206     return vc4_plane_allocate_lbm(new_plane_state);
1207 }
1208 
1209 static void vc4_plane_atomic_update(struct drm_plane *plane,
1210                     struct drm_atomic_state *state)
1211 {
1212     /* No contents here.  Since we don't know where in the CRTC's
1213      * dlist we should be stored, our dlist is uploaded to the
1214      * hardware with vc4_plane_write_dlist() at CRTC atomic_flush
1215      * time.
1216      */
1217 }
1218 
1219 u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist)
1220 {
1221     struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
1222     int i;
1223 
1224     vc4_state->hw_dlist = dlist;
1225 
1226     /* Can't memcpy_toio() because it needs to be 32-bit writes. */
1227     for (i = 0; i < vc4_state->dlist_count; i++)
1228         writel(vc4_state->dlist[i], &dlist[i]);
1229 
1230     return vc4_state->dlist_count;
1231 }
1232 
1233 u32 vc4_plane_dlist_size(const struct drm_plane_state *state)
1234 {
1235     const struct vc4_plane_state *vc4_state =
1236         container_of(state, typeof(*vc4_state), base);
1237 
1238     return vc4_state->dlist_count;
1239 }
1240 
1241 /* Updates the plane to immediately (well, once the FIFO needs
1242  * refilling) scan out from at a new framebuffer.
1243  */
1244 void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb)
1245 {
1246     struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state);
1247     struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
1248     uint32_t addr;
1249 
1250     /* We're skipping the address adjustment for negative origin,
1251      * because this is only called on the primary plane.
1252      */
1253     WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);
1254     addr = bo->paddr + fb->offsets[0];
1255 
1256     /* Write the new address into the hardware immediately.  The
1257      * scanout will start from this address as soon as the FIFO
1258      * needs to refill with pixels.
1259      */
1260     writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
1261 
1262     /* Also update the CPU-side dlist copy, so that any later
1263      * atomic updates that don't do a new modeset on our plane
1264      * also use our updated address.
1265      */
1266     vc4_state->dlist[vc4_state->ptr0_offset] = addr;
1267 }
1268 
1269 static void vc4_plane_atomic_async_update(struct drm_plane *plane,
1270                       struct drm_atomic_state *state)
1271 {
1272     struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1273                                          plane);
1274     struct vc4_plane_state *vc4_state, *new_vc4_state;
1275 
1276     swap(plane->state->fb, new_plane_state->fb);
1277     plane->state->crtc_x = new_plane_state->crtc_x;
1278     plane->state->crtc_y = new_plane_state->crtc_y;
1279     plane->state->crtc_w = new_plane_state->crtc_w;
1280     plane->state->crtc_h = new_plane_state->crtc_h;
1281     plane->state->src_x = new_plane_state->src_x;
1282     plane->state->src_y = new_plane_state->src_y;
1283     plane->state->src_w = new_plane_state->src_w;
1284     plane->state->src_h = new_plane_state->src_h;
1285     plane->state->alpha = new_plane_state->alpha;
1286     plane->state->pixel_blend_mode = new_plane_state->pixel_blend_mode;
1287     plane->state->rotation = new_plane_state->rotation;
1288     plane->state->zpos = new_plane_state->zpos;
1289     plane->state->normalized_zpos = new_plane_state->normalized_zpos;
1290     plane->state->color_encoding = new_plane_state->color_encoding;
1291     plane->state->color_range = new_plane_state->color_range;
1292     plane->state->src = new_plane_state->src;
1293     plane->state->dst = new_plane_state->dst;
1294     plane->state->visible = new_plane_state->visible;
1295 
1296     new_vc4_state = to_vc4_plane_state(new_plane_state);
1297     vc4_state = to_vc4_plane_state(plane->state);
1298 
1299     vc4_state->crtc_x = new_vc4_state->crtc_x;
1300     vc4_state->crtc_y = new_vc4_state->crtc_y;
1301     vc4_state->crtc_h = new_vc4_state->crtc_h;
1302     vc4_state->crtc_w = new_vc4_state->crtc_w;
1303     vc4_state->src_x = new_vc4_state->src_x;
1304     vc4_state->src_y = new_vc4_state->src_y;
1305     memcpy(vc4_state->src_w, new_vc4_state->src_w,
1306            sizeof(vc4_state->src_w));
1307     memcpy(vc4_state->src_h, new_vc4_state->src_h,
1308            sizeof(vc4_state->src_h));
1309     memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling,
1310            sizeof(vc4_state->x_scaling));
1311     memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling,
1312            sizeof(vc4_state->y_scaling));
1313     vc4_state->is_unity = new_vc4_state->is_unity;
1314     vc4_state->is_yuv = new_vc4_state->is_yuv;
1315     memcpy(vc4_state->offsets, new_vc4_state->offsets,
1316            sizeof(vc4_state->offsets));
1317     vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill;
1318 
1319     /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */
1320     vc4_state->dlist[vc4_state->pos0_offset] =
1321         new_vc4_state->dlist[vc4_state->pos0_offset];
1322     vc4_state->dlist[vc4_state->pos2_offset] =
1323         new_vc4_state->dlist[vc4_state->pos2_offset];
1324     vc4_state->dlist[vc4_state->ptr0_offset] =
1325         new_vc4_state->dlist[vc4_state->ptr0_offset];
1326 
1327     /* Note that we can't just call vc4_plane_write_dlist()
1328      * because that would smash the context data that the HVS is
1329      * currently using.
1330      */
1331     writel(vc4_state->dlist[vc4_state->pos0_offset],
1332            &vc4_state->hw_dlist[vc4_state->pos0_offset]);
1333     writel(vc4_state->dlist[vc4_state->pos2_offset],
1334            &vc4_state->hw_dlist[vc4_state->pos2_offset]);
1335     writel(vc4_state->dlist[vc4_state->ptr0_offset],
1336            &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
1337 }
1338 
1339 static int vc4_plane_atomic_async_check(struct drm_plane *plane,
1340                     struct drm_atomic_state *state)
1341 {
1342     struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
1343                                          plane);
1344     struct vc4_plane_state *old_vc4_state, *new_vc4_state;
1345     int ret;
1346     u32 i;
1347 
1348     ret = vc4_plane_mode_set(plane, new_plane_state);
1349     if (ret)
1350         return ret;
1351 
1352     old_vc4_state = to_vc4_plane_state(plane->state);
1353     new_vc4_state = to_vc4_plane_state(new_plane_state);
1354 
1355     if (!new_vc4_state->hw_dlist)
1356         return -EINVAL;
1357 
1358     if (old_vc4_state->dlist_count != new_vc4_state->dlist_count ||
1359         old_vc4_state->pos0_offset != new_vc4_state->pos0_offset ||
1360         old_vc4_state->pos2_offset != new_vc4_state->pos2_offset ||
1361         old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset ||
1362         vc4_lbm_size(plane->state) != vc4_lbm_size(new_plane_state))
1363         return -EINVAL;
1364 
1365     /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update
1366      * if anything else has changed, fallback to a sync update.
1367      */
1368     for (i = 0; i < new_vc4_state->dlist_count; i++) {
1369         if (i == new_vc4_state->pos0_offset ||
1370             i == new_vc4_state->pos2_offset ||
1371             i == new_vc4_state->ptr0_offset ||
1372             (new_vc4_state->lbm_offset &&
1373              i == new_vc4_state->lbm_offset))
1374             continue;
1375 
1376         if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i])
1377             return -EINVAL;
1378     }
1379 
1380     return 0;
1381 }
1382 
1383 static int vc4_prepare_fb(struct drm_plane *plane,
1384               struct drm_plane_state *state)
1385 {
1386     struct vc4_bo *bo;
1387 
1388     if (!state->fb)
1389         return 0;
1390 
1391     bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
1392 
1393     drm_gem_plane_helper_prepare_fb(plane, state);
1394 
1395     if (plane->state->fb == state->fb)
1396         return 0;
1397 
1398     return vc4_bo_inc_usecnt(bo);
1399 }
1400 
1401 static void vc4_cleanup_fb(struct drm_plane *plane,
1402                struct drm_plane_state *state)
1403 {
1404     struct vc4_bo *bo;
1405 
1406     if (plane->state->fb == state->fb || !state->fb)
1407         return;
1408 
1409     bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
1410     vc4_bo_dec_usecnt(bo);
1411 }
1412 
1413 static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
1414     .atomic_check = vc4_plane_atomic_check,
1415     .atomic_update = vc4_plane_atomic_update,
1416     .prepare_fb = vc4_prepare_fb,
1417     .cleanup_fb = vc4_cleanup_fb,
1418     .atomic_async_check = vc4_plane_atomic_async_check,
1419     .atomic_async_update = vc4_plane_atomic_async_update,
1420 };
1421 
1422 static const struct drm_plane_helper_funcs vc5_plane_helper_funcs = {
1423     .atomic_check = vc4_plane_atomic_check,
1424     .atomic_update = vc4_plane_atomic_update,
1425     .atomic_async_check = vc4_plane_atomic_async_check,
1426     .atomic_async_update = vc4_plane_atomic_async_update,
1427 };
1428 
1429 static bool vc4_format_mod_supported(struct drm_plane *plane,
1430                      uint32_t format,
1431                      uint64_t modifier)
1432 {
1433     /* Support T_TILING for RGB formats only. */
1434     switch (format) {
1435     case DRM_FORMAT_XRGB8888:
1436     case DRM_FORMAT_ARGB8888:
1437     case DRM_FORMAT_ABGR8888:
1438     case DRM_FORMAT_XBGR8888:
1439     case DRM_FORMAT_RGB565:
1440     case DRM_FORMAT_BGR565:
1441     case DRM_FORMAT_ARGB1555:
1442     case DRM_FORMAT_XRGB1555:
1443         switch (fourcc_mod_broadcom_mod(modifier)) {
1444         case DRM_FORMAT_MOD_LINEAR:
1445         case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED:
1446             return true;
1447         default:
1448             return false;
1449         }
1450     case DRM_FORMAT_NV12:
1451     case DRM_FORMAT_NV21:
1452         switch (fourcc_mod_broadcom_mod(modifier)) {
1453         case DRM_FORMAT_MOD_LINEAR:
1454         case DRM_FORMAT_MOD_BROADCOM_SAND64:
1455         case DRM_FORMAT_MOD_BROADCOM_SAND128:
1456         case DRM_FORMAT_MOD_BROADCOM_SAND256:
1457             return true;
1458         default:
1459             return false;
1460         }
1461     case DRM_FORMAT_P030:
1462         switch (fourcc_mod_broadcom_mod(modifier)) {
1463         case DRM_FORMAT_MOD_BROADCOM_SAND128:
1464             return true;
1465         default:
1466             return false;
1467         }
1468     case DRM_FORMAT_RGBX1010102:
1469     case DRM_FORMAT_BGRX1010102:
1470     case DRM_FORMAT_RGBA1010102:
1471     case DRM_FORMAT_BGRA1010102:
1472     case DRM_FORMAT_YUV422:
1473     case DRM_FORMAT_YVU422:
1474     case DRM_FORMAT_YUV420:
1475     case DRM_FORMAT_YVU420:
1476     case DRM_FORMAT_NV16:
1477     case DRM_FORMAT_NV61:
1478     default:
1479         return (modifier == DRM_FORMAT_MOD_LINEAR);
1480     }
1481 }
1482 
1483 static const struct drm_plane_funcs vc4_plane_funcs = {
1484     .update_plane = drm_atomic_helper_update_plane,
1485     .disable_plane = drm_atomic_helper_disable_plane,
1486     .destroy = drm_plane_cleanup,
1487     .set_property = NULL,
1488     .reset = vc4_plane_reset,
1489     .atomic_duplicate_state = vc4_plane_duplicate_state,
1490     .atomic_destroy_state = vc4_plane_destroy_state,
1491     .format_mod_supported = vc4_format_mod_supported,
1492 };
1493 
1494 struct drm_plane *vc4_plane_init(struct drm_device *dev,
1495                  enum drm_plane_type type)
1496 {
1497     struct vc4_dev *vc4 = to_vc4_dev(dev);
1498     struct drm_plane *plane = NULL;
1499     struct vc4_plane *vc4_plane;
1500     u32 formats[ARRAY_SIZE(hvs_formats)];
1501     int num_formats = 0;
1502     int ret = 0;
1503     unsigned i;
1504     static const uint64_t modifiers[] = {
1505         DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED,
1506         DRM_FORMAT_MOD_BROADCOM_SAND128,
1507         DRM_FORMAT_MOD_BROADCOM_SAND64,
1508         DRM_FORMAT_MOD_BROADCOM_SAND256,
1509         DRM_FORMAT_MOD_LINEAR,
1510         DRM_FORMAT_MOD_INVALID
1511     };
1512 
1513     vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
1514                  GFP_KERNEL);
1515     if (!vc4_plane)
1516         return ERR_PTR(-ENOMEM);
1517 
1518     for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) {
1519         if (!hvs_formats[i].hvs5_only || vc4->is_vc5) {
1520             formats[num_formats] = hvs_formats[i].drm;
1521             num_formats++;
1522         }
1523     }
1524 
1525     plane = &vc4_plane->base;
1526     ret = drm_universal_plane_init(dev, plane, 0,
1527                        &vc4_plane_funcs,
1528                        formats, num_formats,
1529                        modifiers, type, NULL);
1530     if (ret)
1531         return ERR_PTR(ret);
1532 
1533     if (vc4->is_vc5)
1534         drm_plane_helper_add(plane, &vc5_plane_helper_funcs);
1535     else
1536         drm_plane_helper_add(plane, &vc4_plane_helper_funcs);
1537 
1538     drm_plane_create_alpha_property(plane);
1539     drm_plane_create_blend_mode_property(plane,
1540                          BIT(DRM_MODE_BLEND_PIXEL_NONE) |
1541                          BIT(DRM_MODE_BLEND_PREMULTI) |
1542                          BIT(DRM_MODE_BLEND_COVERAGE));
1543     drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0,
1544                        DRM_MODE_ROTATE_0 |
1545                        DRM_MODE_ROTATE_180 |
1546                        DRM_MODE_REFLECT_X |
1547                        DRM_MODE_REFLECT_Y);
1548 
1549     drm_plane_create_color_properties(plane,
1550                       BIT(DRM_COLOR_YCBCR_BT601) |
1551                       BIT(DRM_COLOR_YCBCR_BT709) |
1552                       BIT(DRM_COLOR_YCBCR_BT2020),
1553                       BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
1554                       BIT(DRM_COLOR_YCBCR_FULL_RANGE),
1555                       DRM_COLOR_YCBCR_BT709,
1556                       DRM_COLOR_YCBCR_LIMITED_RANGE);
1557 
1558     return plane;
1559 }
1560 
1561 int vc4_plane_create_additional_planes(struct drm_device *drm)
1562 {
1563     struct drm_plane *cursor_plane;
1564     struct drm_crtc *crtc;
1565     unsigned int i;
1566 
1567     /* Set up some arbitrary number of planes.  We're not limited
1568      * by a set number of physical registers, just the space in
1569      * the HVS (16k) and how small an plane can be (28 bytes).
1570      * However, each plane we set up takes up some memory, and
1571      * increases the cost of looping over planes, which atomic
1572      * modesetting does quite a bit.  As a result, we pick a
1573      * modest number of planes to expose, that should hopefully
1574      * still cover any sane usecase.
1575      */
1576     for (i = 0; i < 16; i++) {
1577         struct drm_plane *plane =
1578             vc4_plane_init(drm, DRM_PLANE_TYPE_OVERLAY);
1579 
1580         if (IS_ERR(plane))
1581             continue;
1582 
1583         plane->possible_crtcs =
1584             GENMASK(drm->mode_config.num_crtc - 1, 0);
1585     }
1586 
1587     drm_for_each_crtc(crtc, drm) {
1588         /* Set up the legacy cursor after overlay initialization,
1589          * since we overlay planes on the CRTC in the order they were
1590          * initialized.
1591          */
1592         cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
1593         if (!IS_ERR(cursor_plane)) {
1594             cursor_plane->possible_crtcs = drm_crtc_mask(crtc);
1595             crtc->cursor = cursor_plane;
1596         }
1597     }
1598 
1599     return 0;
1600 }