1 /* 2 * Copyright (C) 2015 Broadcom 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 /** 10 * DOC: VC4 plane module 11 * 12 * Each DRM plane is a layer of pixels being scanned out by the HVS. 13 * 14 * At atomic modeset check time, we compute the HVS display element 15 * state that would be necessary for displaying the plane (giving us a 16 * chance to figure out if a plane configuration is invalid), then at 17 * atomic flush time the CRTC will ask us to write our element state 18 * into the region of the HVS that it has allocated for us. 19 */ 20 21 #include <drm/drm_atomic.h> 22 #include <drm/drm_atomic_helper.h> 23 #include <drm/drm_fb_cma_helper.h> 24 #include <drm/drm_plane_helper.h> 25 #include <drm/drm_atomic_uapi.h> 26 27 #include "uapi/drm/vc4_drm.h" 28 #include "vc4_drv.h" 29 #include "vc4_regs.h" 30 31 static const struct hvs_format { 32 u32 drm; /* DRM_FORMAT_* */ 33 u32 hvs; /* HVS_FORMAT_* */ 34 u32 pixel_order; 35 } hvs_formats[] = { 36 { 37 .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 38 .pixel_order = HVS_PIXEL_ORDER_ABGR, 39 }, 40 { 41 .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 42 .pixel_order = HVS_PIXEL_ORDER_ABGR, 43 }, 44 { 45 .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 46 .pixel_order = HVS_PIXEL_ORDER_ARGB, 47 }, 48 { 49 .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 50 .pixel_order = HVS_PIXEL_ORDER_ARGB, 51 }, 52 { 53 .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565, 54 .pixel_order = HVS_PIXEL_ORDER_XRGB, 55 }, 56 { 57 .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565, 58 .pixel_order = HVS_PIXEL_ORDER_XBGR, 59 }, 60 { 61 .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, 62 .pixel_order = HVS_PIXEL_ORDER_ABGR, 63 }, 64 { 65 .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, 66 .pixel_order = HVS_PIXEL_ORDER_ABGR, 67 }, 68 { 69 .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888, 70 .pixel_order = HVS_PIXEL_ORDER_XRGB, 71 }, 72 { 73 .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888, 74 .pixel_order = HVS_PIXEL_ORDER_XBGR, 75 }, 76 { 77 .drm = DRM_FORMAT_YUV422, 78 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, 79 .pixel_order = HVS_PIXEL_ORDER_XYCBCR, 80 }, 81 { 82 .drm = DRM_FORMAT_YVU422, 83 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, 84 .pixel_order = HVS_PIXEL_ORDER_XYCRCB, 85 }, 86 { 87 .drm = DRM_FORMAT_YUV420, 88 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE, 89 .pixel_order = HVS_PIXEL_ORDER_XYCBCR, 90 }, 91 { 92 .drm = DRM_FORMAT_YVU420, 93 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE, 94 .pixel_order = HVS_PIXEL_ORDER_XYCRCB, 95 }, 96 { 97 .drm = DRM_FORMAT_NV12, 98 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE, 99 .pixel_order = HVS_PIXEL_ORDER_XYCBCR, 100 }, 101 { 102 .drm = DRM_FORMAT_NV21, 103 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE, 104 .pixel_order = HVS_PIXEL_ORDER_XYCRCB, 105 }, 106 { 107 .drm = DRM_FORMAT_NV16, 108 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE, 109 .pixel_order = HVS_PIXEL_ORDER_XYCBCR, 110 }, 111 { 112 .drm = DRM_FORMAT_NV61, 113 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE, 114 .pixel_order = HVS_PIXEL_ORDER_XYCRCB, 115 }, 116 }; 117 118 static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) 119 { 120 unsigned i; 121 122 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { 123 if (hvs_formats[i].drm == drm_format) 124 return &hvs_formats[i]; 125 } 126 127 return NULL; 128 } 129 130 static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst) 131 { 132 if (dst == src) 133 return VC4_SCALING_NONE; 134 if (3 * dst >= 2 * src) 135 return VC4_SCALING_PPF; 136 else 137 return VC4_SCALING_TPZ; 138 } 139 140 static bool plane_enabled(struct drm_plane_state *state) 141 { 142 return state->fb && state->crtc; 143 } 144 145 static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) 146 { 147 struct vc4_plane_state *vc4_state; 148 149 if (WARN_ON(!plane->state)) 150 return NULL; 151 152 vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL); 153 if (!vc4_state) 154 return NULL; 155 156 memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); 157 vc4_state->dlist_initialized = 0; 158 159 __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); 160 161 if (vc4_state->dlist) { 162 vc4_state->dlist = kmemdup(vc4_state->dlist, 163 vc4_state->dlist_count * 4, 164 GFP_KERNEL); 165 if (!vc4_state->dlist) { 166 kfree(vc4_state); 167 return NULL; 168 } 169 vc4_state->dlist_size = vc4_state->dlist_count; 170 } 171 172 return &vc4_state->base; 173 } 174 175 static void vc4_plane_destroy_state(struct drm_plane *plane, 176 struct drm_plane_state *state) 177 { 178 struct vc4_dev *vc4 = to_vc4_dev(plane->dev); 179 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 180 181 if (vc4_state->lbm.allocated) { 182 unsigned long irqflags; 183 184 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); 185 drm_mm_remove_node(&vc4_state->lbm); 186 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); 187 } 188 189 kfree(vc4_state->dlist); 190 __drm_atomic_helper_plane_destroy_state(&vc4_state->base); 191 kfree(state); 192 } 193 194 /* Called during init to allocate the plane's atomic state. */ 195 static void vc4_plane_reset(struct drm_plane *plane) 196 { 197 struct vc4_plane_state *vc4_state; 198 199 WARN_ON(plane->state); 200 201 vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); 202 if (!vc4_state) 203 return; 204 205 __drm_atomic_helper_plane_reset(plane, &vc4_state->base); 206 } 207 208 static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val) 209 { 210 if (vc4_state->dlist_count == vc4_state->dlist_size) { 211 u32 new_size = max(4u, vc4_state->dlist_count * 2); 212 u32 *new_dlist = kmalloc_array(new_size, 4, GFP_KERNEL); 213 214 if (!new_dlist) 215 return; 216 memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4); 217 218 kfree(vc4_state->dlist); 219 vc4_state->dlist = new_dlist; 220 vc4_state->dlist_size = new_size; 221 } 222 223 vc4_state->dlist[vc4_state->dlist_count++] = val; 224 } 225 226 /* Returns the scl0/scl1 field based on whether the dimensions need to 227 * be up/down/non-scaled. 228 * 229 * This is a replication of a table from the spec. 230 */ 231 static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane) 232 { 233 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 234 235 switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) { 236 case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF: 237 return SCALER_CTL0_SCL_H_PPF_V_PPF; 238 case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF: 239 return SCALER_CTL0_SCL_H_TPZ_V_PPF; 240 case VC4_SCALING_PPF << 2 | VC4_SCALING_TPZ: 241 return SCALER_CTL0_SCL_H_PPF_V_TPZ; 242 case VC4_SCALING_TPZ << 2 | VC4_SCALING_TPZ: 243 return SCALER_CTL0_SCL_H_TPZ_V_TPZ; 244 case VC4_SCALING_PPF << 2 | VC4_SCALING_NONE: 245 return SCALER_CTL0_SCL_H_PPF_V_NONE; 246 case VC4_SCALING_NONE << 2 | VC4_SCALING_PPF: 247 return SCALER_CTL0_SCL_H_NONE_V_PPF; 248 case VC4_SCALING_NONE << 2 | VC4_SCALING_TPZ: 249 return SCALER_CTL0_SCL_H_NONE_V_TPZ; 250 case VC4_SCALING_TPZ << 2 | VC4_SCALING_NONE: 251 return SCALER_CTL0_SCL_H_TPZ_V_NONE; 252 default: 253 case VC4_SCALING_NONE << 2 | VC4_SCALING_NONE: 254 /* The unity case is independently handled by 255 * SCALER_CTL0_UNITY. 256 */ 257 return 0; 258 } 259 } 260 261 static int vc4_plane_margins_adj(struct drm_plane_state *pstate) 262 { 263 struct vc4_plane_state *vc4_pstate = to_vc4_plane_state(pstate); 264 unsigned int left, right, top, bottom, adjhdisplay, adjvdisplay; 265 struct drm_crtc_state *crtc_state; 266 267 crtc_state = drm_atomic_get_new_crtc_state(pstate->state, 268 pstate->crtc); 269 270 vc4_crtc_get_margins(crtc_state, &left, &right, &top, &bottom); 271 if (!left && !right && !top && !bottom) 272 return 0; 273 274 if (left + right >= crtc_state->mode.hdisplay || 275 top + bottom >= crtc_state->mode.vdisplay) 276 return -EINVAL; 277 278 adjhdisplay = crtc_state->mode.hdisplay - (left + right); 279 vc4_pstate->crtc_x = DIV_ROUND_CLOSEST(vc4_pstate->crtc_x * 280 adjhdisplay, 281 crtc_state->mode.hdisplay); 282 vc4_pstate->crtc_x += left; 283 if (vc4_pstate->crtc_x > crtc_state->mode.hdisplay - left) 284 vc4_pstate->crtc_x = crtc_state->mode.hdisplay - left; 285 286 adjvdisplay = crtc_state->mode.vdisplay - (top + bottom); 287 vc4_pstate->crtc_y = DIV_ROUND_CLOSEST(vc4_pstate->crtc_y * 288 adjvdisplay, 289 crtc_state->mode.vdisplay); 290 vc4_pstate->crtc_y += top; 291 if (vc4_pstate->crtc_y > crtc_state->mode.vdisplay - top) 292 vc4_pstate->crtc_y = crtc_state->mode.vdisplay - top; 293 294 vc4_pstate->crtc_w = DIV_ROUND_CLOSEST(vc4_pstate->crtc_w * 295 adjhdisplay, 296 crtc_state->mode.hdisplay); 297 vc4_pstate->crtc_h = DIV_ROUND_CLOSEST(vc4_pstate->crtc_h * 298 adjvdisplay, 299 crtc_state->mode.vdisplay); 300 301 if (!vc4_pstate->crtc_w || !vc4_pstate->crtc_h) 302 return -EINVAL; 303 304 return 0; 305 } 306 307 static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) 308 { 309 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 310 struct drm_framebuffer *fb = state->fb; 311 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); 312 u32 subpixel_src_mask = (1 << 16) - 1; 313 u32 format = fb->format->format; 314 int num_planes = fb->format->num_planes; 315 struct drm_crtc_state *crtc_state; 316 u32 h_subsample, v_subsample; 317 int i, ret; 318 319 crtc_state = drm_atomic_get_existing_crtc_state(state->state, 320 state->crtc); 321 if (!crtc_state) { 322 DRM_DEBUG_KMS("Invalid crtc state\n"); 323 return -EINVAL; 324 } 325 326 ret = drm_atomic_helper_check_plane_state(state, crtc_state, 1, 327 INT_MAX, true, true); 328 if (ret) 329 return ret; 330 331 h_subsample = drm_format_horz_chroma_subsampling(format); 332 v_subsample = drm_format_vert_chroma_subsampling(format); 333 334 for (i = 0; i < num_planes; i++) 335 vc4_state->offsets[i] = bo->paddr + fb->offsets[i]; 336 337 /* We don't support subpixel source positioning for scaling. */ 338 if ((state->src.x1 & subpixel_src_mask) || 339 (state->src.x2 & subpixel_src_mask) || 340 (state->src.y1 & subpixel_src_mask) || 341 (state->src.y2 & subpixel_src_mask)) { 342 return -EINVAL; 343 } 344 345 vc4_state->src_x = state->src.x1 >> 16; 346 vc4_state->src_y = state->src.y1 >> 16; 347 vc4_state->src_w[0] = (state->src.x2 - state->src.x1) >> 16; 348 vc4_state->src_h[0] = (state->src.y2 - state->src.y1) >> 16; 349 350 vc4_state->crtc_x = state->dst.x1; 351 vc4_state->crtc_y = state->dst.y1; 352 vc4_state->crtc_w = state->dst.x2 - state->dst.x1; 353 vc4_state->crtc_h = state->dst.y2 - state->dst.y1; 354 355 ret = vc4_plane_margins_adj(state); 356 if (ret) 357 return ret; 358 359 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0], 360 vc4_state->crtc_w); 361 vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0], 362 vc4_state->crtc_h); 363 364 vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE && 365 vc4_state->y_scaling[0] == VC4_SCALING_NONE); 366 367 if (num_planes > 1) { 368 vc4_state->is_yuv = true; 369 370 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample; 371 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample; 372 373 vc4_state->x_scaling[1] = 374 vc4_get_scaling_mode(vc4_state->src_w[1], 375 vc4_state->crtc_w); 376 vc4_state->y_scaling[1] = 377 vc4_get_scaling_mode(vc4_state->src_h[1], 378 vc4_state->crtc_h); 379 380 /* YUV conversion requires that horizontal scaling be enabled 381 * on the UV plane even if vc4_get_scaling_mode() returned 382 * VC4_SCALING_NONE (which can happen when the down-scaling 383 * ratio is 0.5). Let's force it to VC4_SCALING_PPF in this 384 * case. 385 */ 386 if (vc4_state->x_scaling[1] == VC4_SCALING_NONE) 387 vc4_state->x_scaling[1] = VC4_SCALING_PPF; 388 } else { 389 vc4_state->is_yuv = false; 390 vc4_state->x_scaling[1] = VC4_SCALING_NONE; 391 vc4_state->y_scaling[1] = VC4_SCALING_NONE; 392 } 393 394 return 0; 395 } 396 397 static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) 398 { 399 u32 scale, recip; 400 401 scale = (1 << 16) * src / dst; 402 403 /* The specs note that while the reciprocal would be defined 404 * as (1<<32)/scale, ~0 is close enough. 405 */ 406 recip = ~0 / scale; 407 408 vc4_dlist_write(vc4_state, 409 VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) | 410 VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE)); 411 vc4_dlist_write(vc4_state, 412 VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP)); 413 } 414 415 static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst) 416 { 417 u32 scale = (1 << 16) * src / dst; 418 419 vc4_dlist_write(vc4_state, 420 SCALER_PPF_AGC | 421 VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | 422 VC4_SET_FIELD(0, SCALER_PPF_IPHASE)); 423 } 424 425 static u32 vc4_lbm_size(struct drm_plane_state *state) 426 { 427 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 428 /* This is the worst case number. One of the two sizes will 429 * be used depending on the scaling configuration. 430 */ 431 u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w); 432 u32 lbm; 433 434 /* LBM is not needed when there's no vertical scaling. */ 435 if (vc4_state->y_scaling[0] == VC4_SCALING_NONE && 436 vc4_state->y_scaling[1] == VC4_SCALING_NONE) 437 return 0; 438 439 if (!vc4_state->is_yuv) { 440 if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) 441 lbm = pix_per_line * 8; 442 else { 443 /* In special cases, this multiplier might be 12. */ 444 lbm = pix_per_line * 16; 445 } 446 } else { 447 /* There are cases for this going down to a multiplier 448 * of 2, but according to the firmware source, the 449 * table in the docs is somewhat wrong. 450 */ 451 lbm = pix_per_line * 16; 452 } 453 454 lbm = roundup(lbm, 32); 455 456 return lbm; 457 } 458 459 static void vc4_write_scaling_parameters(struct drm_plane_state *state, 460 int channel) 461 { 462 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 463 464 /* Ch0 H-PPF Word 0: Scaling Parameters */ 465 if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) { 466 vc4_write_ppf(vc4_state, 467 vc4_state->src_w[channel], vc4_state->crtc_w); 468 } 469 470 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ 471 if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) { 472 vc4_write_ppf(vc4_state, 473 vc4_state->src_h[channel], vc4_state->crtc_h); 474 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 475 } 476 477 /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */ 478 if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) { 479 vc4_write_tpz(vc4_state, 480 vc4_state->src_w[channel], vc4_state->crtc_w); 481 } 482 483 /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */ 484 if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) { 485 vc4_write_tpz(vc4_state, 486 vc4_state->src_h[channel], vc4_state->crtc_h); 487 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 488 } 489 } 490 491 static void vc4_plane_calc_load(struct drm_plane_state *state) 492 { 493 unsigned int hvs_load_shift, vrefresh, i; 494 struct drm_framebuffer *fb = state->fb; 495 struct vc4_plane_state *vc4_state; 496 struct drm_crtc_state *crtc_state; 497 unsigned int vscale_factor; 498 499 vc4_state = to_vc4_plane_state(state); 500 crtc_state = drm_atomic_get_existing_crtc_state(state->state, 501 state->crtc); 502 vrefresh = drm_mode_vrefresh(&crtc_state->adjusted_mode); 503 504 /* The HVS is able to process 2 pixels/cycle when scaling the source, 505 * 4 pixels/cycle otherwise. 506 * Alpha blending step seems to be pipelined and it's always operating 507 * at 4 pixels/cycle, so the limiting aspect here seems to be the 508 * scaler block. 509 * HVS load is expressed in clk-cycles/sec (AKA Hz). 510 */ 511 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || 512 vc4_state->x_scaling[1] != VC4_SCALING_NONE || 513 vc4_state->y_scaling[0] != VC4_SCALING_NONE || 514 vc4_state->y_scaling[1] != VC4_SCALING_NONE) 515 hvs_load_shift = 1; 516 else 517 hvs_load_shift = 2; 518 519 vc4_state->membus_load = 0; 520 vc4_state->hvs_load = 0; 521 for (i = 0; i < fb->format->num_planes; i++) { 522 /* Even if the bandwidth/plane required for a single frame is 523 * 524 * vc4_state->src_w[i] * vc4_state->src_h[i] * cpp * vrefresh 525 * 526 * when downscaling, we have to read more pixels per line in 527 * the time frame reserved for a single line, so the bandwidth 528 * demand can be punctually higher. To account for that, we 529 * calculate the down-scaling factor and multiply the plane 530 * load by this number. We're likely over-estimating the read 531 * demand, but that's better than under-estimating it. 532 */ 533 vscale_factor = DIV_ROUND_UP(vc4_state->src_h[i], 534 vc4_state->crtc_h); 535 vc4_state->membus_load += vc4_state->src_w[i] * 536 vc4_state->src_h[i] * vscale_factor * 537 fb->format->cpp[i]; 538 vc4_state->hvs_load += vc4_state->crtc_h * vc4_state->crtc_w; 539 } 540 541 vc4_state->hvs_load *= vrefresh; 542 vc4_state->hvs_load >>= hvs_load_shift; 543 vc4_state->membus_load *= vrefresh; 544 } 545 546 static int vc4_plane_allocate_lbm(struct drm_plane_state *state) 547 { 548 struct vc4_dev *vc4 = to_vc4_dev(state->plane->dev); 549 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 550 unsigned long irqflags; 551 u32 lbm_size; 552 553 lbm_size = vc4_lbm_size(state); 554 if (!lbm_size) 555 return 0; 556 557 if (WARN_ON(!vc4_state->lbm_offset)) 558 return -EINVAL; 559 560 /* Allocate the LBM memory that the HVS will use for temporary 561 * storage due to our scaling/format conversion. 562 */ 563 if (!vc4_state->lbm.allocated) { 564 int ret; 565 566 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); 567 ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, 568 &vc4_state->lbm, 569 lbm_size, 32, 0, 0); 570 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); 571 572 if (ret) 573 return ret; 574 } else { 575 WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); 576 } 577 578 vc4_state->dlist[vc4_state->lbm_offset] = vc4_state->lbm.start; 579 580 return 0; 581 } 582 583 /* Writes out a full display list for an active plane to the plane's 584 * private dlist state. 585 */ 586 static int vc4_plane_mode_set(struct drm_plane *plane, 587 struct drm_plane_state *state) 588 { 589 struct vc4_dev *vc4 = to_vc4_dev(plane->dev); 590 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 591 struct drm_framebuffer *fb = state->fb; 592 u32 ctl0_offset = vc4_state->dlist_count; 593 const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); 594 u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier); 595 int num_planes = drm_format_num_planes(format->drm); 596 u32 h_subsample, v_subsample; 597 bool mix_plane_alpha; 598 bool covers_screen; 599 u32 scl0, scl1, pitch0; 600 u32 tiling, src_y; 601 u32 hvs_format = format->hvs; 602 unsigned int rotation; 603 int ret, i; 604 605 if (vc4_state->dlist_initialized) 606 return 0; 607 608 ret = vc4_plane_setup_clipping_and_scaling(state); 609 if (ret) 610 return ret; 611 612 /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB 613 * and 4:4:4, scl1 should be set to scl0 so both channels of 614 * the scaler do the same thing. For YUV, the Y plane needs 615 * to be put in channel 1 and Cb/Cr in channel 0, so we swap 616 * the scl fields here. 617 */ 618 if (num_planes == 1) { 619 scl0 = vc4_get_scl_field(state, 0); 620 scl1 = scl0; 621 } else { 622 scl0 = vc4_get_scl_field(state, 1); 623 scl1 = vc4_get_scl_field(state, 0); 624 } 625 626 h_subsample = drm_format_horz_chroma_subsampling(format->drm); 627 v_subsample = drm_format_vert_chroma_subsampling(format->drm); 628 629 rotation = drm_rotation_simplify(state->rotation, 630 DRM_MODE_ROTATE_0 | 631 DRM_MODE_REFLECT_X | 632 DRM_MODE_REFLECT_Y); 633 634 /* We must point to the last line when Y reflection is enabled. */ 635 src_y = vc4_state->src_y; 636 if (rotation & DRM_MODE_REFLECT_Y) 637 src_y += vc4_state->src_h[0] - 1; 638 639 switch (base_format_mod) { 640 case DRM_FORMAT_MOD_LINEAR: 641 tiling = SCALER_CTL0_TILING_LINEAR; 642 pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); 643 644 /* Adjust the base pointer to the first pixel to be scanned 645 * out. 646 */ 647 for (i = 0; i < num_planes; i++) { 648 vc4_state->offsets[i] += src_y / 649 (i ? v_subsample : 1) * 650 fb->pitches[i]; 651 652 vc4_state->offsets[i] += vc4_state->src_x / 653 (i ? h_subsample : 1) * 654 fb->format->cpp[i]; 655 } 656 657 break; 658 659 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: { 660 u32 tile_size_shift = 12; /* T tiles are 4kb */ 661 /* Whole-tile offsets, mostly for setting the pitch. */ 662 u32 tile_w_shift = fb->format->cpp[0] == 2 ? 6 : 5; 663 u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */ 664 u32 tile_w_mask = (1 << tile_w_shift) - 1; 665 /* The height mask on 32-bit-per-pixel tiles is 63, i.e. twice 666 * the height (in pixels) of a 4k tile. 667 */ 668 u32 tile_h_mask = (2 << tile_h_shift) - 1; 669 /* For T-tiled, the FB pitch is "how many bytes from one row to 670 * the next, such that 671 * 672 * pitch * tile_h == tile_size * tiles_per_row 673 */ 674 u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift); 675 u32 tiles_l = vc4_state->src_x >> tile_w_shift; 676 u32 tiles_r = tiles_w - tiles_l; 677 u32 tiles_t = src_y >> tile_h_shift; 678 /* Intra-tile offsets, which modify the base address (the 679 * SCALER_PITCH0_TILE_Y_OFFSET tells HVS how to walk from that 680 * base address). 681 */ 682 u32 tile_y = (src_y >> 4) & 1; 683 u32 subtile_y = (src_y >> 2) & 3; 684 u32 utile_y = src_y & 3; 685 u32 x_off = vc4_state->src_x & tile_w_mask; 686 u32 y_off = src_y & tile_h_mask; 687 688 /* When Y reflection is requested we must set the 689 * SCALER_PITCH0_TILE_LINE_DIR flag to tell HVS that all lines 690 * after the initial one should be fetched in descending order, 691 * which makes sense since we start from the last line and go 692 * backward. 693 * Don't know why we need y_off = max_y_off - y_off, but it's 694 * definitely required (I guess it's also related to the "going 695 * backward" situation). 696 */ 697 if (rotation & DRM_MODE_REFLECT_Y) { 698 y_off = tile_h_mask - y_off; 699 pitch0 = SCALER_PITCH0_TILE_LINE_DIR; 700 } else { 701 pitch0 = 0; 702 } 703 704 tiling = SCALER_CTL0_TILING_256B_OR_T; 705 pitch0 |= (VC4_SET_FIELD(x_off, SCALER_PITCH0_SINK_PIX) | 706 VC4_SET_FIELD(y_off, SCALER_PITCH0_TILE_Y_OFFSET) | 707 VC4_SET_FIELD(tiles_l, SCALER_PITCH0_TILE_WIDTH_L) | 708 VC4_SET_FIELD(tiles_r, SCALER_PITCH0_TILE_WIDTH_R)); 709 vc4_state->offsets[0] += tiles_t * (tiles_w << tile_size_shift); 710 vc4_state->offsets[0] += subtile_y << 8; 711 vc4_state->offsets[0] += utile_y << 4; 712 713 /* Rows of tiles alternate left-to-right and right-to-left. */ 714 if (tiles_t & 1) { 715 pitch0 |= SCALER_PITCH0_TILE_INITIAL_LINE_DIR; 716 vc4_state->offsets[0] += (tiles_w - tiles_l) << 717 tile_size_shift; 718 vc4_state->offsets[0] -= (1 + !tile_y) << 10; 719 } else { 720 vc4_state->offsets[0] += tiles_l << tile_size_shift; 721 vc4_state->offsets[0] += tile_y << 10; 722 } 723 724 break; 725 } 726 727 case DRM_FORMAT_MOD_BROADCOM_SAND64: 728 case DRM_FORMAT_MOD_BROADCOM_SAND128: 729 case DRM_FORMAT_MOD_BROADCOM_SAND256: { 730 uint32_t param = fourcc_mod_broadcom_param(fb->modifier); 731 u32 tile_w, tile, x_off, pix_per_tile; 732 733 hvs_format = HVS_PIXEL_FORMAT_H264; 734 735 switch (base_format_mod) { 736 case DRM_FORMAT_MOD_BROADCOM_SAND64: 737 tiling = SCALER_CTL0_TILING_64B; 738 tile_w = 64; 739 break; 740 case DRM_FORMAT_MOD_BROADCOM_SAND128: 741 tiling = SCALER_CTL0_TILING_128B; 742 tile_w = 128; 743 break; 744 case DRM_FORMAT_MOD_BROADCOM_SAND256: 745 tiling = SCALER_CTL0_TILING_256B_OR_T; 746 tile_w = 256; 747 break; 748 default: 749 break; 750 } 751 752 if (param > SCALER_TILE_HEIGHT_MASK) { 753 DRM_DEBUG_KMS("SAND height too large (%d)\n", param); 754 return -EINVAL; 755 } 756 757 pix_per_tile = tile_w / fb->format->cpp[0]; 758 tile = vc4_state->src_x / pix_per_tile; 759 x_off = vc4_state->src_x % pix_per_tile; 760 761 /* Adjust the base pointer to the first pixel to be scanned 762 * out. 763 */ 764 for (i = 0; i < num_planes; i++) { 765 vc4_state->offsets[i] += param * tile_w * tile; 766 vc4_state->offsets[i] += src_y / 767 (i ? v_subsample : 1) * 768 tile_w; 769 vc4_state->offsets[i] += x_off / 770 (i ? h_subsample : 1) * 771 fb->format->cpp[i]; 772 } 773 774 pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); 775 break; 776 } 777 778 default: 779 DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx", 780 (long long)fb->modifier); 781 return -EINVAL; 782 } 783 784 /* Control word */ 785 vc4_dlist_write(vc4_state, 786 SCALER_CTL0_VALID | 787 (rotation & DRM_MODE_REFLECT_X ? SCALER_CTL0_HFLIP : 0) | 788 (rotation & DRM_MODE_REFLECT_Y ? SCALER_CTL0_VFLIP : 0) | 789 VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) | 790 (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | 791 (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | 792 VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | 793 (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) | 794 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | 795 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1)); 796 797 /* Position Word 0: Image Positions and Alpha Value */ 798 vc4_state->pos0_offset = vc4_state->dlist_count; 799 vc4_dlist_write(vc4_state, 800 VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) | 801 VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) | 802 VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y)); 803 804 /* Position Word 1: Scaled Image Dimensions. */ 805 if (!vc4_state->is_unity) { 806 vc4_dlist_write(vc4_state, 807 VC4_SET_FIELD(vc4_state->crtc_w, 808 SCALER_POS1_SCL_WIDTH) | 809 VC4_SET_FIELD(vc4_state->crtc_h, 810 SCALER_POS1_SCL_HEIGHT)); 811 } 812 813 /* Don't waste cycles mixing with plane alpha if the set alpha 814 * is opaque or there is no per-pixel alpha information. 815 * In any case we use the alpha property value as the fixed alpha. 816 */ 817 mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE && 818 fb->format->has_alpha; 819 820 /* Position Word 2: Source Image Size, Alpha */ 821 vc4_state->pos2_offset = vc4_state->dlist_count; 822 vc4_dlist_write(vc4_state, 823 VC4_SET_FIELD(fb->format->has_alpha ? 824 SCALER_POS2_ALPHA_MODE_PIPELINE : 825 SCALER_POS2_ALPHA_MODE_FIXED, 826 SCALER_POS2_ALPHA_MODE) | 827 (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | 828 (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) | 829 VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | 830 VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT)); 831 832 /* Position Word 3: Context. Written by the HVS. */ 833 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 834 835 836 /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers 837 * 838 * The pointers may be any byte address. 839 */ 840 vc4_state->ptr0_offset = vc4_state->dlist_count; 841 for (i = 0; i < num_planes; i++) 842 vc4_dlist_write(vc4_state, vc4_state->offsets[i]); 843 844 /* Pointer Context Word 0/1/2: Written by the HVS */ 845 for (i = 0; i < num_planes; i++) 846 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 847 848 /* Pitch word 0 */ 849 vc4_dlist_write(vc4_state, pitch0); 850 851 /* Pitch word 1/2 */ 852 for (i = 1; i < num_planes; i++) { 853 if (hvs_format != HVS_PIXEL_FORMAT_H264) { 854 vc4_dlist_write(vc4_state, 855 VC4_SET_FIELD(fb->pitches[i], 856 SCALER_SRC_PITCH)); 857 } else { 858 vc4_dlist_write(vc4_state, pitch0); 859 } 860 } 861 862 /* Colorspace conversion words */ 863 if (vc4_state->is_yuv) { 864 vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5); 865 vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5); 866 vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); 867 } 868 869 vc4_state->lbm_offset = 0; 870 871 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || 872 vc4_state->x_scaling[1] != VC4_SCALING_NONE || 873 vc4_state->y_scaling[0] != VC4_SCALING_NONE || 874 vc4_state->y_scaling[1] != VC4_SCALING_NONE) { 875 /* Reserve a slot for the LBM Base Address. The real value will 876 * be set when calling vc4_plane_allocate_lbm(). 877 */ 878 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE || 879 vc4_state->y_scaling[1] != VC4_SCALING_NONE) 880 vc4_state->lbm_offset = vc4_state->dlist_count++; 881 882 if (num_planes > 1) { 883 /* Emit Cb/Cr as channel 0 and Y as channel 884 * 1. This matches how we set up scl0/scl1 885 * above. 886 */ 887 vc4_write_scaling_parameters(state, 1); 888 } 889 vc4_write_scaling_parameters(state, 0); 890 891 /* If any PPF setup was done, then all the kernel 892 * pointers get uploaded. 893 */ 894 if (vc4_state->x_scaling[0] == VC4_SCALING_PPF || 895 vc4_state->y_scaling[0] == VC4_SCALING_PPF || 896 vc4_state->x_scaling[1] == VC4_SCALING_PPF || 897 vc4_state->y_scaling[1] == VC4_SCALING_PPF) { 898 u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, 899 SCALER_PPF_KERNEL_OFFSET); 900 901 /* HPPF plane 0 */ 902 vc4_dlist_write(vc4_state, kernel); 903 /* VPPF plane 0 */ 904 vc4_dlist_write(vc4_state, kernel); 905 /* HPPF plane 1 */ 906 vc4_dlist_write(vc4_state, kernel); 907 /* VPPF plane 1 */ 908 vc4_dlist_write(vc4_state, kernel); 909 } 910 } 911 912 vc4_state->dlist[ctl0_offset] |= 913 VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE); 914 915 /* crtc_* are already clipped coordinates. */ 916 covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 && 917 vc4_state->crtc_w == state->crtc->mode.hdisplay && 918 vc4_state->crtc_h == state->crtc->mode.vdisplay; 919 /* Background fill might be necessary when the plane has per-pixel 920 * alpha content or a non-opaque plane alpha and could blend from the 921 * background or does not cover the entire screen. 922 */ 923 vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen || 924 state->alpha != DRM_BLEND_ALPHA_OPAQUE; 925 926 /* Flag the dlist as initialized to avoid checking it twice in case 927 * the async update check already called vc4_plane_mode_set() and 928 * decided to fallback to sync update because async update was not 929 * possible. 930 */ 931 vc4_state->dlist_initialized = 1; 932 933 vc4_plane_calc_load(state); 934 935 return 0; 936 } 937 938 /* If a modeset involves changing the setup of a plane, the atomic 939 * infrastructure will call this to validate a proposed plane setup. 940 * However, if a plane isn't getting updated, this (and the 941 * corresponding vc4_plane_atomic_update) won't get called. Thus, we 942 * compute the dlist here and have all active plane dlists get updated 943 * in the CRTC's flush. 944 */ 945 static int vc4_plane_atomic_check(struct drm_plane *plane, 946 struct drm_plane_state *state) 947 { 948 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 949 int ret; 950 951 vc4_state->dlist_count = 0; 952 953 if (!plane_enabled(state)) 954 return 0; 955 956 ret = vc4_plane_mode_set(plane, state); 957 if (ret) 958 return ret; 959 960 return vc4_plane_allocate_lbm(state); 961 } 962 963 static void vc4_plane_atomic_update(struct drm_plane *plane, 964 struct drm_plane_state *old_state) 965 { 966 /* No contents here. Since we don't know where in the CRTC's 967 * dlist we should be stored, our dlist is uploaded to the 968 * hardware with vc4_plane_write_dlist() at CRTC atomic_flush 969 * time. 970 */ 971 } 972 973 u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist) 974 { 975 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); 976 int i; 977 978 vc4_state->hw_dlist = dlist; 979 980 /* Can't memcpy_toio() because it needs to be 32-bit writes. */ 981 for (i = 0; i < vc4_state->dlist_count; i++) 982 writel(vc4_state->dlist[i], &dlist[i]); 983 984 return vc4_state->dlist_count; 985 } 986 987 u32 vc4_plane_dlist_size(const struct drm_plane_state *state) 988 { 989 const struct vc4_plane_state *vc4_state = 990 container_of(state, typeof(*vc4_state), base); 991 992 return vc4_state->dlist_count; 993 } 994 995 /* Updates the plane to immediately (well, once the FIFO needs 996 * refilling) scan out from at a new framebuffer. 997 */ 998 void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) 999 { 1000 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); 1001 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); 1002 uint32_t addr; 1003 1004 /* We're skipping the address adjustment for negative origin, 1005 * because this is only called on the primary plane. 1006 */ 1007 WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); 1008 addr = bo->paddr + fb->offsets[0]; 1009 1010 /* Write the new address into the hardware immediately. The 1011 * scanout will start from this address as soon as the FIFO 1012 * needs to refill with pixels. 1013 */ 1014 writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]); 1015 1016 /* Also update the CPU-side dlist copy, so that any later 1017 * atomic updates that don't do a new modeset on our plane 1018 * also use our updated address. 1019 */ 1020 vc4_state->dlist[vc4_state->ptr0_offset] = addr; 1021 } 1022 1023 static void vc4_plane_atomic_async_update(struct drm_plane *plane, 1024 struct drm_plane_state *state) 1025 { 1026 struct vc4_plane_state *vc4_state, *new_vc4_state; 1027 1028 drm_atomic_set_fb_for_plane(plane->state, state->fb); 1029 plane->state->crtc_x = state->crtc_x; 1030 plane->state->crtc_y = state->crtc_y; 1031 plane->state->crtc_w = state->crtc_w; 1032 plane->state->crtc_h = state->crtc_h; 1033 plane->state->src_x = state->src_x; 1034 plane->state->src_y = state->src_y; 1035 plane->state->src_w = state->src_w; 1036 plane->state->src_h = state->src_h; 1037 plane->state->src_h = state->src_h; 1038 plane->state->alpha = state->alpha; 1039 plane->state->pixel_blend_mode = state->pixel_blend_mode; 1040 plane->state->rotation = state->rotation; 1041 plane->state->zpos = state->zpos; 1042 plane->state->normalized_zpos = state->normalized_zpos; 1043 plane->state->color_encoding = state->color_encoding; 1044 plane->state->color_range = state->color_range; 1045 plane->state->src = state->src; 1046 plane->state->dst = state->dst; 1047 plane->state->visible = state->visible; 1048 1049 new_vc4_state = to_vc4_plane_state(state); 1050 vc4_state = to_vc4_plane_state(plane->state); 1051 1052 vc4_state->crtc_x = new_vc4_state->crtc_x; 1053 vc4_state->crtc_y = new_vc4_state->crtc_y; 1054 vc4_state->crtc_h = new_vc4_state->crtc_h; 1055 vc4_state->crtc_w = new_vc4_state->crtc_w; 1056 vc4_state->src_x = new_vc4_state->src_x; 1057 vc4_state->src_y = new_vc4_state->src_y; 1058 memcpy(vc4_state->src_w, new_vc4_state->src_w, 1059 sizeof(vc4_state->src_w)); 1060 memcpy(vc4_state->src_h, new_vc4_state->src_h, 1061 sizeof(vc4_state->src_h)); 1062 memcpy(vc4_state->x_scaling, new_vc4_state->x_scaling, 1063 sizeof(vc4_state->x_scaling)); 1064 memcpy(vc4_state->y_scaling, new_vc4_state->y_scaling, 1065 sizeof(vc4_state->y_scaling)); 1066 vc4_state->is_unity = new_vc4_state->is_unity; 1067 vc4_state->is_yuv = new_vc4_state->is_yuv; 1068 memcpy(vc4_state->offsets, new_vc4_state->offsets, 1069 sizeof(vc4_state->offsets)); 1070 vc4_state->needs_bg_fill = new_vc4_state->needs_bg_fill; 1071 1072 /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ 1073 vc4_state->dlist[vc4_state->pos0_offset] = 1074 new_vc4_state->dlist[vc4_state->pos0_offset]; 1075 vc4_state->dlist[vc4_state->pos2_offset] = 1076 new_vc4_state->dlist[vc4_state->pos2_offset]; 1077 vc4_state->dlist[vc4_state->ptr0_offset] = 1078 new_vc4_state->dlist[vc4_state->ptr0_offset]; 1079 1080 /* Note that we can't just call vc4_plane_write_dlist() 1081 * because that would smash the context data that the HVS is 1082 * currently using. 1083 */ 1084 writel(vc4_state->dlist[vc4_state->pos0_offset], 1085 &vc4_state->hw_dlist[vc4_state->pos0_offset]); 1086 writel(vc4_state->dlist[vc4_state->pos2_offset], 1087 &vc4_state->hw_dlist[vc4_state->pos2_offset]); 1088 writel(vc4_state->dlist[vc4_state->ptr0_offset], 1089 &vc4_state->hw_dlist[vc4_state->ptr0_offset]); 1090 } 1091 1092 static int vc4_plane_atomic_async_check(struct drm_plane *plane, 1093 struct drm_plane_state *state) 1094 { 1095 struct vc4_plane_state *old_vc4_state, *new_vc4_state; 1096 int ret; 1097 u32 i; 1098 1099 ret = vc4_plane_mode_set(plane, state); 1100 if (ret) 1101 return ret; 1102 1103 old_vc4_state = to_vc4_plane_state(plane->state); 1104 new_vc4_state = to_vc4_plane_state(state); 1105 if (old_vc4_state->dlist_count != new_vc4_state->dlist_count || 1106 old_vc4_state->pos0_offset != new_vc4_state->pos0_offset || 1107 old_vc4_state->pos2_offset != new_vc4_state->pos2_offset || 1108 old_vc4_state->ptr0_offset != new_vc4_state->ptr0_offset || 1109 vc4_lbm_size(plane->state) != vc4_lbm_size(state)) 1110 return -EINVAL; 1111 1112 /* Only pos0, pos2 and ptr0 DWORDS can be updated in an async update 1113 * if anything else has changed, fallback to a sync update. 1114 */ 1115 for (i = 0; i < new_vc4_state->dlist_count; i++) { 1116 if (i == new_vc4_state->pos0_offset || 1117 i == new_vc4_state->pos2_offset || 1118 i == new_vc4_state->ptr0_offset || 1119 (new_vc4_state->lbm_offset && 1120 i == new_vc4_state->lbm_offset)) 1121 continue; 1122 1123 if (new_vc4_state->dlist[i] != old_vc4_state->dlist[i]) 1124 return -EINVAL; 1125 } 1126 1127 return 0; 1128 } 1129 1130 static int vc4_prepare_fb(struct drm_plane *plane, 1131 struct drm_plane_state *state) 1132 { 1133 struct vc4_bo *bo; 1134 struct dma_fence *fence; 1135 int ret; 1136 1137 if (!state->fb) 1138 return 0; 1139 1140 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); 1141 1142 fence = reservation_object_get_excl_rcu(bo->base.base.resv); 1143 drm_atomic_set_fence_for_plane(state, fence); 1144 1145 if (plane->state->fb == state->fb) 1146 return 0; 1147 1148 ret = vc4_bo_inc_usecnt(bo); 1149 if (ret) 1150 return ret; 1151 1152 return 0; 1153 } 1154 1155 static void vc4_cleanup_fb(struct drm_plane *plane, 1156 struct drm_plane_state *state) 1157 { 1158 struct vc4_bo *bo; 1159 1160 if (plane->state->fb == state->fb || !state->fb) 1161 return; 1162 1163 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); 1164 vc4_bo_dec_usecnt(bo); 1165 } 1166 1167 static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { 1168 .atomic_check = vc4_plane_atomic_check, 1169 .atomic_update = vc4_plane_atomic_update, 1170 .prepare_fb = vc4_prepare_fb, 1171 .cleanup_fb = vc4_cleanup_fb, 1172 .atomic_async_check = vc4_plane_atomic_async_check, 1173 .atomic_async_update = vc4_plane_atomic_async_update, 1174 }; 1175 1176 static void vc4_plane_destroy(struct drm_plane *plane) 1177 { 1178 drm_plane_cleanup(plane); 1179 } 1180 1181 static bool vc4_format_mod_supported(struct drm_plane *plane, 1182 uint32_t format, 1183 uint64_t modifier) 1184 { 1185 /* Support T_TILING for RGB formats only. */ 1186 switch (format) { 1187 case DRM_FORMAT_XRGB8888: 1188 case DRM_FORMAT_ARGB8888: 1189 case DRM_FORMAT_ABGR8888: 1190 case DRM_FORMAT_XBGR8888: 1191 case DRM_FORMAT_RGB565: 1192 case DRM_FORMAT_BGR565: 1193 case DRM_FORMAT_ARGB1555: 1194 case DRM_FORMAT_XRGB1555: 1195 switch (fourcc_mod_broadcom_mod(modifier)) { 1196 case DRM_FORMAT_MOD_LINEAR: 1197 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: 1198 return true; 1199 default: 1200 return false; 1201 } 1202 case DRM_FORMAT_NV12: 1203 case DRM_FORMAT_NV21: 1204 switch (fourcc_mod_broadcom_mod(modifier)) { 1205 case DRM_FORMAT_MOD_LINEAR: 1206 case DRM_FORMAT_MOD_BROADCOM_SAND64: 1207 case DRM_FORMAT_MOD_BROADCOM_SAND128: 1208 case DRM_FORMAT_MOD_BROADCOM_SAND256: 1209 return true; 1210 default: 1211 return false; 1212 } 1213 case DRM_FORMAT_YUV422: 1214 case DRM_FORMAT_YVU422: 1215 case DRM_FORMAT_YUV420: 1216 case DRM_FORMAT_YVU420: 1217 case DRM_FORMAT_NV16: 1218 case DRM_FORMAT_NV61: 1219 default: 1220 return (modifier == DRM_FORMAT_MOD_LINEAR); 1221 } 1222 } 1223 1224 static const struct drm_plane_funcs vc4_plane_funcs = { 1225 .update_plane = drm_atomic_helper_update_plane, 1226 .disable_plane = drm_atomic_helper_disable_plane, 1227 .destroy = vc4_plane_destroy, 1228 .set_property = NULL, 1229 .reset = vc4_plane_reset, 1230 .atomic_duplicate_state = vc4_plane_duplicate_state, 1231 .atomic_destroy_state = vc4_plane_destroy_state, 1232 .format_mod_supported = vc4_format_mod_supported, 1233 }; 1234 1235 struct drm_plane *vc4_plane_init(struct drm_device *dev, 1236 enum drm_plane_type type) 1237 { 1238 struct drm_plane *plane = NULL; 1239 struct vc4_plane *vc4_plane; 1240 u32 formats[ARRAY_SIZE(hvs_formats)]; 1241 int ret = 0; 1242 unsigned i; 1243 static const uint64_t modifiers[] = { 1244 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, 1245 DRM_FORMAT_MOD_BROADCOM_SAND128, 1246 DRM_FORMAT_MOD_BROADCOM_SAND64, 1247 DRM_FORMAT_MOD_BROADCOM_SAND256, 1248 DRM_FORMAT_MOD_LINEAR, 1249 DRM_FORMAT_MOD_INVALID 1250 }; 1251 1252 vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), 1253 GFP_KERNEL); 1254 if (!vc4_plane) 1255 return ERR_PTR(-ENOMEM); 1256 1257 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) 1258 formats[i] = hvs_formats[i].drm; 1259 1260 plane = &vc4_plane->base; 1261 ret = drm_universal_plane_init(dev, plane, 0, 1262 &vc4_plane_funcs, 1263 formats, ARRAY_SIZE(formats), 1264 modifiers, type, NULL); 1265 1266 drm_plane_helper_add(plane, &vc4_plane_helper_funcs); 1267 1268 drm_plane_create_alpha_property(plane); 1269 drm_plane_create_rotation_property(plane, DRM_MODE_ROTATE_0, 1270 DRM_MODE_ROTATE_0 | 1271 DRM_MODE_ROTATE_180 | 1272 DRM_MODE_REFLECT_X | 1273 DRM_MODE_REFLECT_Y); 1274 1275 return plane; 1276 } 1277