0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
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;
0035 u32 hvs;
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
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
0259
0260
0261
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
0287
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
0367
0368
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
0406
0407
0408
0409
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
0429
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
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
0464
0465
0466
0467
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
0479 lbm = pix_per_line * 16;
0480 }
0481 } else {
0482
0483
0484
0485
0486 lbm = pix_per_line * 16;
0487 }
0488
0489
0490 lbm = roundup(lbm, vc4->is_vc5 ? 128 : 64);
0491
0492
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
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
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
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
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
0544
0545
0546
0547
0548
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
0562
0563
0564
0565
0566
0567
0568
0569
0570
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
0600
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
0626
0627
0628
0629 static const u32 colorspace_coeffs[2][DRM_COLOR_ENCODING_MAX][3] = {
0630 {
0631
0632 {
0633
0634 SCALER_CSC0_ITR_R_601_5,
0635 SCALER_CSC1_ITR_R_601_5,
0636 SCALER_CSC2_ITR_R_601_5,
0637 }, {
0638
0639 SCALER_CSC0_ITR_R_709_3,
0640 SCALER_CSC1_ITR_R_709_3,
0641 SCALER_CSC2_ITR_R_709_3,
0642 }, {
0643
0644 SCALER_CSC0_ITR_R_2020,
0645 SCALER_CSC1_ITR_R_2020,
0646 SCALER_CSC2_ITR_R_2020,
0647 }
0648 }, {
0649
0650 {
0651
0652 SCALER_CSC0_JPEG_JFIF,
0653 SCALER_CSC1_JPEG_JFIF,
0654 SCALER_CSC2_JPEG_JFIF,
0655 }, {
0656
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
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
0712
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
0742
0743
0744
0745
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
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
0771
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;
0787
0788 u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5;
0789 u32 tile_h_shift = 5;
0790 u32 tile_w_mask = (1 << tile_w_shift) - 1;
0791
0792
0793
0794 u32 tile_h_mask = (2 << tile_h_shift) - 1;
0795
0796
0797
0798
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
0805
0806
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
0815
0816
0817
0818
0819
0820
0821
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
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
0886
0887
0888
0889
0890
0891
0892
0893
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
0901
0902
0903
0904
0905
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
0954
0955
0956
0957 mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE &&
0958 fb->format->has_alpha;
0959
0960 if (!vc4->is_vc5) {
0961
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
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
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
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
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
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
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
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
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
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
1062 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1063 }
1064
1065
1066
1067
1068
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
1075 for (i = 0; i < num_planes; i++)
1076 vc4_dlist_write(vc4_state, 0xc0c0c0c0);
1077
1078
1079 vc4_dlist_write(vc4_state, pitch0);
1080
1081
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
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
1118
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
1128
1129
1130
1131 vc4_write_scaling_parameters(state, 1);
1132 }
1133 vc4_write_scaling_parameters(state, 0);
1134
1135
1136
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
1146 vc4_dlist_write(vc4_state, kernel);
1147
1148 vc4_dlist_write(vc4_state, kernel);
1149
1150 vc4_dlist_write(vc4_state, kernel);
1151
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
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
1164
1165
1166
1167 vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen ||
1168 state->alpha != DRM_BLEND_ALPHA_OPAQUE;
1169
1170
1171
1172
1173
1174
1175 vc4_state->dlist_initialized = 1;
1176
1177 vc4_plane_calc_load(state);
1178
1179 return 0;
1180 }
1181
1182
1183
1184
1185
1186
1187
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
1213
1214
1215
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
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
1242
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
1251
1252
1253 WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0);
1254 addr = bo->paddr + fb->offsets[0];
1255
1256
1257
1258
1259
1260 writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]);
1261
1262
1263
1264
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
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
1328
1329
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
1366
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
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
1568
1569
1570
1571
1572
1573
1574
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
1589
1590
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 }