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 26 #include "uapi/drm/vc4_drm.h" 27 #include "vc4_drv.h" 28 #include "vc4_regs.h" 29 30 enum vc4_scaling_mode { 31 VC4_SCALING_NONE, 32 VC4_SCALING_TPZ, 33 VC4_SCALING_PPF, 34 }; 35 36 struct vc4_plane_state { 37 struct drm_plane_state base; 38 /* System memory copy of the display list for this element, computed 39 * at atomic_check time. 40 */ 41 u32 *dlist; 42 u32 dlist_size; /* Number of dwords allocated for the display list */ 43 u32 dlist_count; /* Number of used dwords in the display list. */ 44 45 /* Offset in the dlist to various words, for pageflip or 46 * cursor updates. 47 */ 48 u32 pos0_offset; 49 u32 pos2_offset; 50 u32 ptr0_offset; 51 52 /* Offset where the plane's dlist was last stored in the 53 * hardware at vc4_crtc_atomic_flush() time. 54 */ 55 u32 __iomem *hw_dlist; 56 57 /* Clipped coordinates of the plane on the display. */ 58 int crtc_x, crtc_y, crtc_w, crtc_h; 59 /* Clipped area being scanned from in the FB. */ 60 u32 src_x, src_y; 61 62 u32 src_w[2], src_h[2]; 63 64 /* Scaling selection for the RGB/Y plane and the Cb/Cr planes. */ 65 enum vc4_scaling_mode x_scaling[2], y_scaling[2]; 66 bool is_unity; 67 bool is_yuv; 68 69 /* Offset to start scanning out from the start of the plane's 70 * BO. 71 */ 72 u32 offsets[3]; 73 74 /* Our allocation in LBM for temporary storage during scaling. */ 75 struct drm_mm_node lbm; 76 }; 77 78 static inline struct vc4_plane_state * 79 to_vc4_plane_state(struct drm_plane_state *state) 80 { 81 return (struct vc4_plane_state *)state; 82 } 83 84 static const struct hvs_format { 85 u32 drm; /* DRM_FORMAT_* */ 86 u32 hvs; /* HVS_FORMAT_* */ 87 u32 pixel_order; 88 } hvs_formats[] = { 89 { 90 .drm = DRM_FORMAT_XRGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 91 .pixel_order = HVS_PIXEL_ORDER_ABGR, 92 }, 93 { 94 .drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 95 .pixel_order = HVS_PIXEL_ORDER_ABGR, 96 }, 97 { 98 .drm = DRM_FORMAT_ABGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 99 .pixel_order = HVS_PIXEL_ORDER_ARGB, 100 }, 101 { 102 .drm = DRM_FORMAT_XBGR8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888, 103 .pixel_order = HVS_PIXEL_ORDER_ARGB, 104 }, 105 { 106 .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565, 107 .pixel_order = HVS_PIXEL_ORDER_XRGB, 108 }, 109 { 110 .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565, 111 .pixel_order = HVS_PIXEL_ORDER_XBGR, 112 }, 113 { 114 .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, 115 .pixel_order = HVS_PIXEL_ORDER_ABGR, 116 }, 117 { 118 .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551, 119 .pixel_order = HVS_PIXEL_ORDER_ABGR, 120 }, 121 { 122 .drm = DRM_FORMAT_RGB888, .hvs = HVS_PIXEL_FORMAT_RGB888, 123 .pixel_order = HVS_PIXEL_ORDER_XRGB, 124 }, 125 { 126 .drm = DRM_FORMAT_BGR888, .hvs = HVS_PIXEL_FORMAT_RGB888, 127 .pixel_order = HVS_PIXEL_ORDER_XBGR, 128 }, 129 { 130 .drm = DRM_FORMAT_YUV422, 131 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, 132 .pixel_order = HVS_PIXEL_ORDER_XYCBCR, 133 }, 134 { 135 .drm = DRM_FORMAT_YVU422, 136 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_3PLANE, 137 .pixel_order = HVS_PIXEL_ORDER_XYCRCB, 138 }, 139 { 140 .drm = DRM_FORMAT_YUV420, 141 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE, 142 .pixel_order = HVS_PIXEL_ORDER_XYCBCR, 143 }, 144 { 145 .drm = DRM_FORMAT_YVU420, 146 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE, 147 .pixel_order = HVS_PIXEL_ORDER_XYCRCB, 148 }, 149 { 150 .drm = DRM_FORMAT_NV12, 151 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE, 152 .pixel_order = HVS_PIXEL_ORDER_XYCBCR, 153 }, 154 { 155 .drm = DRM_FORMAT_NV21, 156 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE, 157 .pixel_order = HVS_PIXEL_ORDER_XYCRCB, 158 }, 159 { 160 .drm = DRM_FORMAT_NV16, 161 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE, 162 .pixel_order = HVS_PIXEL_ORDER_XYCBCR, 163 }, 164 { 165 .drm = DRM_FORMAT_NV61, 166 .hvs = HVS_PIXEL_FORMAT_YCBCR_YUV422_2PLANE, 167 .pixel_order = HVS_PIXEL_ORDER_XYCRCB, 168 }, 169 }; 170 171 static const struct hvs_format *vc4_get_hvs_format(u32 drm_format) 172 { 173 unsigned i; 174 175 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { 176 if (hvs_formats[i].drm == drm_format) 177 return &hvs_formats[i]; 178 } 179 180 return NULL; 181 } 182 183 static enum vc4_scaling_mode vc4_get_scaling_mode(u32 src, u32 dst) 184 { 185 if (dst > src) 186 return VC4_SCALING_PPF; 187 else if (dst < src) 188 return VC4_SCALING_TPZ; 189 else 190 return VC4_SCALING_NONE; 191 } 192 193 static bool plane_enabled(struct drm_plane_state *state) 194 { 195 return state->fb && state->crtc; 196 } 197 198 static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane) 199 { 200 struct vc4_plane_state *vc4_state; 201 202 if (WARN_ON(!plane->state)) 203 return NULL; 204 205 vc4_state = kmemdup(plane->state, sizeof(*vc4_state), GFP_KERNEL); 206 if (!vc4_state) 207 return NULL; 208 209 memset(&vc4_state->lbm, 0, sizeof(vc4_state->lbm)); 210 211 __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); 212 213 if (vc4_state->dlist) { 214 vc4_state->dlist = kmemdup(vc4_state->dlist, 215 vc4_state->dlist_count * 4, 216 GFP_KERNEL); 217 if (!vc4_state->dlist) { 218 kfree(vc4_state); 219 return NULL; 220 } 221 vc4_state->dlist_size = vc4_state->dlist_count; 222 } 223 224 return &vc4_state->base; 225 } 226 227 static void vc4_plane_destroy_state(struct drm_plane *plane, 228 struct drm_plane_state *state) 229 { 230 struct vc4_dev *vc4 = to_vc4_dev(plane->dev); 231 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 232 233 if (vc4_state->lbm.allocated) { 234 unsigned long irqflags; 235 236 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); 237 drm_mm_remove_node(&vc4_state->lbm); 238 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); 239 } 240 241 kfree(vc4_state->dlist); 242 __drm_atomic_helper_plane_destroy_state(&vc4_state->base); 243 kfree(state); 244 } 245 246 /* Called during init to allocate the plane's atomic state. */ 247 static void vc4_plane_reset(struct drm_plane *plane) 248 { 249 struct vc4_plane_state *vc4_state; 250 251 WARN_ON(plane->state); 252 253 vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); 254 if (!vc4_state) 255 return; 256 257 plane->state = &vc4_state->base; 258 vc4_state->base.plane = plane; 259 } 260 261 static void vc4_dlist_write(struct vc4_plane_state *vc4_state, u32 val) 262 { 263 if (vc4_state->dlist_count == vc4_state->dlist_size) { 264 u32 new_size = max(4u, vc4_state->dlist_count * 2); 265 u32 *new_dlist = kmalloc(new_size * 4, GFP_KERNEL); 266 267 if (!new_dlist) 268 return; 269 memcpy(new_dlist, vc4_state->dlist, vc4_state->dlist_count * 4); 270 271 kfree(vc4_state->dlist); 272 vc4_state->dlist = new_dlist; 273 vc4_state->dlist_size = new_size; 274 } 275 276 vc4_state->dlist[vc4_state->dlist_count++] = val; 277 } 278 279 /* Returns the scl0/scl1 field based on whether the dimensions need to 280 * be up/down/non-scaled. 281 * 282 * This is a replication of a table from the spec. 283 */ 284 static u32 vc4_get_scl_field(struct drm_plane_state *state, int plane) 285 { 286 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 287 288 switch (vc4_state->x_scaling[plane] << 2 | vc4_state->y_scaling[plane]) { 289 case VC4_SCALING_PPF << 2 | VC4_SCALING_PPF: 290 return SCALER_CTL0_SCL_H_PPF_V_PPF; 291 case VC4_SCALING_TPZ << 2 | VC4_SCALING_PPF: 292 return SCALER_CTL0_SCL_H_TPZ_V_PPF; 293 case VC4_SCALING_PPF << 2 | VC4_SCALING_TPZ: 294 return SCALER_CTL0_SCL_H_PPF_V_TPZ; 295 case VC4_SCALING_TPZ << 2 | VC4_SCALING_TPZ: 296 return SCALER_CTL0_SCL_H_TPZ_V_TPZ; 297 case VC4_SCALING_PPF << 2 | VC4_SCALING_NONE: 298 return SCALER_CTL0_SCL_H_PPF_V_NONE; 299 case VC4_SCALING_NONE << 2 | VC4_SCALING_PPF: 300 return SCALER_CTL0_SCL_H_NONE_V_PPF; 301 case VC4_SCALING_NONE << 2 | VC4_SCALING_TPZ: 302 return SCALER_CTL0_SCL_H_NONE_V_TPZ; 303 case VC4_SCALING_TPZ << 2 | VC4_SCALING_NONE: 304 return SCALER_CTL0_SCL_H_TPZ_V_NONE; 305 default: 306 case VC4_SCALING_NONE << 2 | VC4_SCALING_NONE: 307 /* The unity case is independently handled by 308 * SCALER_CTL0_UNITY. 309 */ 310 return 0; 311 } 312 } 313 314 static int vc4_plane_setup_clipping_and_scaling(struct drm_plane_state *state) 315 { 316 struct drm_plane *plane = state->plane; 317 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 318 struct drm_framebuffer *fb = state->fb; 319 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); 320 u32 subpixel_src_mask = (1 << 16) - 1; 321 u32 format = fb->format->format; 322 int num_planes = fb->format->num_planes; 323 u32 h_subsample = 1; 324 u32 v_subsample = 1; 325 int i; 326 327 for (i = 0; i < num_planes; i++) 328 vc4_state->offsets[i] = bo->paddr + fb->offsets[i]; 329 330 /* We don't support subpixel source positioning for scaling. */ 331 if ((state->src_x & subpixel_src_mask) || 332 (state->src_y & subpixel_src_mask) || 333 (state->src_w & subpixel_src_mask) || 334 (state->src_h & subpixel_src_mask)) { 335 return -EINVAL; 336 } 337 338 vc4_state->src_x = state->src_x >> 16; 339 vc4_state->src_y = state->src_y >> 16; 340 vc4_state->src_w[0] = state->src_w >> 16; 341 vc4_state->src_h[0] = state->src_h >> 16; 342 343 vc4_state->crtc_x = state->crtc_x; 344 vc4_state->crtc_y = state->crtc_y; 345 vc4_state->crtc_w = state->crtc_w; 346 vc4_state->crtc_h = state->crtc_h; 347 348 vc4_state->x_scaling[0] = vc4_get_scaling_mode(vc4_state->src_w[0], 349 vc4_state->crtc_w); 350 vc4_state->y_scaling[0] = vc4_get_scaling_mode(vc4_state->src_h[0], 351 vc4_state->crtc_h); 352 353 if (num_planes > 1) { 354 vc4_state->is_yuv = true; 355 356 h_subsample = drm_format_horz_chroma_subsampling(format); 357 v_subsample = drm_format_vert_chroma_subsampling(format); 358 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample; 359 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample; 360 361 vc4_state->x_scaling[1] = 362 vc4_get_scaling_mode(vc4_state->src_w[1], 363 vc4_state->crtc_w); 364 vc4_state->y_scaling[1] = 365 vc4_get_scaling_mode(vc4_state->src_h[1], 366 vc4_state->crtc_h); 367 368 /* YUV conversion requires that scaling be enabled, 369 * even on a plane that's otherwise 1:1. Choose TPZ 370 * for simplicity. 371 */ 372 if (vc4_state->x_scaling[0] == VC4_SCALING_NONE) 373 vc4_state->x_scaling[0] = VC4_SCALING_TPZ; 374 if (vc4_state->y_scaling[0] == VC4_SCALING_NONE) 375 vc4_state->y_scaling[0] = VC4_SCALING_TPZ; 376 } 377 378 vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE && 379 vc4_state->y_scaling[0] == VC4_SCALING_NONE && 380 vc4_state->x_scaling[1] == VC4_SCALING_NONE && 381 vc4_state->y_scaling[1] == VC4_SCALING_NONE); 382 383 /* No configuring scaling on the cursor plane, since it gets 384 non-vblank-synced updates, and scaling requires requires 385 LBM changes which have to be vblank-synced. 386 */ 387 if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity) 388 return -EINVAL; 389 390 /* Clamp the on-screen start x/y to 0. The hardware doesn't 391 * support negative y, and negative x wastes bandwidth. 392 */ 393 if (vc4_state->crtc_x < 0) { 394 for (i = 0; i < num_planes; i++) { 395 u32 cpp = fb->format->cpp[i]; 396 u32 subs = ((i == 0) ? 1 : h_subsample); 397 398 vc4_state->offsets[i] += (cpp * 399 (-vc4_state->crtc_x) / subs); 400 } 401 vc4_state->src_w[0] += vc4_state->crtc_x; 402 vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample; 403 vc4_state->crtc_x = 0; 404 } 405 406 if (vc4_state->crtc_y < 0) { 407 for (i = 0; i < num_planes; i++) { 408 u32 subs = ((i == 0) ? 1 : v_subsample); 409 410 vc4_state->offsets[i] += (fb->pitches[i] * 411 (-vc4_state->crtc_y) / subs); 412 } 413 vc4_state->src_h[0] += vc4_state->crtc_y; 414 vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample; 415 vc4_state->crtc_y = 0; 416 } 417 418 return 0; 419 } 420 421 static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) 422 { 423 u32 scale, recip; 424 425 scale = (1 << 16) * src / dst; 426 427 /* The specs note that while the reciprocal would be defined 428 * as (1<<32)/scale, ~0 is close enough. 429 */ 430 recip = ~0 / scale; 431 432 vc4_dlist_write(vc4_state, 433 VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) | 434 VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE)); 435 vc4_dlist_write(vc4_state, 436 VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP)); 437 } 438 439 static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst) 440 { 441 u32 scale = (1 << 16) * src / dst; 442 443 vc4_dlist_write(vc4_state, 444 SCALER_PPF_AGC | 445 VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | 446 VC4_SET_FIELD(0, SCALER_PPF_IPHASE)); 447 } 448 449 static u32 vc4_lbm_size(struct drm_plane_state *state) 450 { 451 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 452 /* This is the worst case number. One of the two sizes will 453 * be used depending on the scaling configuration. 454 */ 455 u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w); 456 u32 lbm; 457 458 if (!vc4_state->is_yuv) { 459 if (vc4_state->is_unity) 460 return 0; 461 else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) 462 lbm = pix_per_line * 8; 463 else { 464 /* In special cases, this multiplier might be 12. */ 465 lbm = pix_per_line * 16; 466 } 467 } else { 468 /* There are cases for this going down to a multiplier 469 * of 2, but according to the firmware source, the 470 * table in the docs is somewhat wrong. 471 */ 472 lbm = pix_per_line * 16; 473 } 474 475 lbm = roundup(lbm, 32); 476 477 return lbm; 478 } 479 480 static void vc4_write_scaling_parameters(struct drm_plane_state *state, 481 int channel) 482 { 483 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 484 485 /* Ch0 H-PPF Word 0: Scaling Parameters */ 486 if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) { 487 vc4_write_ppf(vc4_state, 488 vc4_state->src_w[channel], vc4_state->crtc_w); 489 } 490 491 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ 492 if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) { 493 vc4_write_ppf(vc4_state, 494 vc4_state->src_h[channel], vc4_state->crtc_h); 495 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 496 } 497 498 /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */ 499 if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) { 500 vc4_write_tpz(vc4_state, 501 vc4_state->src_w[channel], vc4_state->crtc_w); 502 } 503 504 /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */ 505 if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) { 506 vc4_write_tpz(vc4_state, 507 vc4_state->src_h[channel], vc4_state->crtc_h); 508 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 509 } 510 } 511 512 /* Writes out a full display list for an active plane to the plane's 513 * private dlist state. 514 */ 515 static int vc4_plane_mode_set(struct drm_plane *plane, 516 struct drm_plane_state *state) 517 { 518 struct vc4_dev *vc4 = to_vc4_dev(plane->dev); 519 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 520 struct drm_framebuffer *fb = state->fb; 521 u32 ctl0_offset = vc4_state->dlist_count; 522 const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); 523 int num_planes = drm_format_num_planes(format->drm); 524 u32 scl0, scl1, pitch0; 525 u32 lbm_size, tiling; 526 unsigned long irqflags; 527 int ret, i; 528 529 ret = vc4_plane_setup_clipping_and_scaling(state); 530 if (ret) 531 return ret; 532 533 /* Allocate the LBM memory that the HVS will use for temporary 534 * storage due to our scaling/format conversion. 535 */ 536 lbm_size = vc4_lbm_size(state); 537 if (lbm_size) { 538 if (!vc4_state->lbm.allocated) { 539 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); 540 ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, 541 &vc4_state->lbm, 542 lbm_size, 32, 0, 0); 543 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); 544 } else { 545 WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); 546 } 547 } 548 549 if (ret) 550 return ret; 551 552 /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB 553 * and 4:4:4, scl1 should be set to scl0 so both channels of 554 * the scaler do the same thing. For YUV, the Y plane needs 555 * to be put in channel 1 and Cb/Cr in channel 0, so we swap 556 * the scl fields here. 557 */ 558 if (num_planes == 1) { 559 scl0 = vc4_get_scl_field(state, 1); 560 scl1 = scl0; 561 } else { 562 scl0 = vc4_get_scl_field(state, 1); 563 scl1 = vc4_get_scl_field(state, 0); 564 } 565 566 switch (fb->modifier) { 567 case DRM_FORMAT_MOD_LINEAR: 568 tiling = SCALER_CTL0_TILING_LINEAR; 569 pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); 570 break; 571 572 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: { 573 /* For T-tiled, the FB pitch is "how many bytes from 574 * one row to the next, such that pitch * tile_h == 575 * tile_size * tiles_per_row." 576 */ 577 u32 tile_size_shift = 12; /* T tiles are 4kb */ 578 u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */ 579 u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift); 580 581 tiling = SCALER_CTL0_TILING_256B_OR_T; 582 583 pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) | 584 VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) | 585 VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R)); 586 break; 587 } 588 589 default: 590 DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx", 591 (long long)fb->modifier); 592 return -EINVAL; 593 } 594 595 /* Control word */ 596 vc4_dlist_write(vc4_state, 597 SCALER_CTL0_VALID | 598 (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | 599 (format->hvs << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | 600 VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | 601 (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) | 602 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | 603 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1)); 604 605 /* Position Word 0: Image Positions and Alpha Value */ 606 vc4_state->pos0_offset = vc4_state->dlist_count; 607 vc4_dlist_write(vc4_state, 608 VC4_SET_FIELD(0xff, SCALER_POS0_FIXED_ALPHA) | 609 VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) | 610 VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y)); 611 612 /* Position Word 1: Scaled Image Dimensions. */ 613 if (!vc4_state->is_unity) { 614 vc4_dlist_write(vc4_state, 615 VC4_SET_FIELD(vc4_state->crtc_w, 616 SCALER_POS1_SCL_WIDTH) | 617 VC4_SET_FIELD(vc4_state->crtc_h, 618 SCALER_POS1_SCL_HEIGHT)); 619 } 620 621 /* Position Word 2: Source Image Size, Alpha Mode */ 622 vc4_state->pos2_offset = vc4_state->dlist_count; 623 vc4_dlist_write(vc4_state, 624 VC4_SET_FIELD(fb->format->has_alpha ? 625 SCALER_POS2_ALPHA_MODE_PIPELINE : 626 SCALER_POS2_ALPHA_MODE_FIXED, 627 SCALER_POS2_ALPHA_MODE) | 628 VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | 629 VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT)); 630 631 /* Position Word 3: Context. Written by the HVS. */ 632 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 633 634 635 /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers 636 * 637 * The pointers may be any byte address. 638 */ 639 vc4_state->ptr0_offset = vc4_state->dlist_count; 640 for (i = 0; i < num_planes; i++) 641 vc4_dlist_write(vc4_state, vc4_state->offsets[i]); 642 643 /* Pointer Context Word 0/1/2: Written by the HVS */ 644 for (i = 0; i < num_planes; i++) 645 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 646 647 /* Pitch word 0 */ 648 vc4_dlist_write(vc4_state, pitch0); 649 650 /* Pitch word 1/2 */ 651 for (i = 1; i < num_planes; i++) { 652 vc4_dlist_write(vc4_state, 653 VC4_SET_FIELD(fb->pitches[i], SCALER_SRC_PITCH)); 654 } 655 656 /* Colorspace conversion words */ 657 if (vc4_state->is_yuv) { 658 vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5); 659 vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5); 660 vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); 661 } 662 663 if (!vc4_state->is_unity) { 664 /* LBM Base Address. */ 665 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE || 666 vc4_state->y_scaling[1] != VC4_SCALING_NONE) { 667 vc4_dlist_write(vc4_state, vc4_state->lbm.start); 668 } 669 670 if (num_planes > 1) { 671 /* Emit Cb/Cr as channel 0 and Y as channel 672 * 1. This matches how we set up scl0/scl1 673 * above. 674 */ 675 vc4_write_scaling_parameters(state, 1); 676 } 677 vc4_write_scaling_parameters(state, 0); 678 679 /* If any PPF setup was done, then all the kernel 680 * pointers get uploaded. 681 */ 682 if (vc4_state->x_scaling[0] == VC4_SCALING_PPF || 683 vc4_state->y_scaling[0] == VC4_SCALING_PPF || 684 vc4_state->x_scaling[1] == VC4_SCALING_PPF || 685 vc4_state->y_scaling[1] == VC4_SCALING_PPF) { 686 u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, 687 SCALER_PPF_KERNEL_OFFSET); 688 689 /* HPPF plane 0 */ 690 vc4_dlist_write(vc4_state, kernel); 691 /* VPPF plane 0 */ 692 vc4_dlist_write(vc4_state, kernel); 693 /* HPPF plane 1 */ 694 vc4_dlist_write(vc4_state, kernel); 695 /* VPPF plane 1 */ 696 vc4_dlist_write(vc4_state, kernel); 697 } 698 } 699 700 vc4_state->dlist[ctl0_offset] |= 701 VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE); 702 703 return 0; 704 } 705 706 /* If a modeset involves changing the setup of a plane, the atomic 707 * infrastructure will call this to validate a proposed plane setup. 708 * However, if a plane isn't getting updated, this (and the 709 * corresponding vc4_plane_atomic_update) won't get called. Thus, we 710 * compute the dlist here and have all active plane dlists get updated 711 * in the CRTC's flush. 712 */ 713 static int vc4_plane_atomic_check(struct drm_plane *plane, 714 struct drm_plane_state *state) 715 { 716 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 717 718 vc4_state->dlist_count = 0; 719 720 if (plane_enabled(state)) 721 return vc4_plane_mode_set(plane, state); 722 else 723 return 0; 724 } 725 726 static void vc4_plane_atomic_update(struct drm_plane *plane, 727 struct drm_plane_state *old_state) 728 { 729 /* No contents here. Since we don't know where in the CRTC's 730 * dlist we should be stored, our dlist is uploaded to the 731 * hardware with vc4_plane_write_dlist() at CRTC atomic_flush 732 * time. 733 */ 734 } 735 736 u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist) 737 { 738 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); 739 int i; 740 741 vc4_state->hw_dlist = dlist; 742 743 /* Can't memcpy_toio() because it needs to be 32-bit writes. */ 744 for (i = 0; i < vc4_state->dlist_count; i++) 745 writel(vc4_state->dlist[i], &dlist[i]); 746 747 return vc4_state->dlist_count; 748 } 749 750 u32 vc4_plane_dlist_size(const struct drm_plane_state *state) 751 { 752 const struct vc4_plane_state *vc4_state = 753 container_of(state, typeof(*vc4_state), base); 754 755 return vc4_state->dlist_count; 756 } 757 758 /* Updates the plane to immediately (well, once the FIFO needs 759 * refilling) scan out from at a new framebuffer. 760 */ 761 void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) 762 { 763 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); 764 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); 765 uint32_t addr; 766 767 /* We're skipping the address adjustment for negative origin, 768 * because this is only called on the primary plane. 769 */ 770 WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); 771 addr = bo->paddr + fb->offsets[0]; 772 773 /* Write the new address into the hardware immediately. The 774 * scanout will start from this address as soon as the FIFO 775 * needs to refill with pixels. 776 */ 777 writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]); 778 779 /* Also update the CPU-side dlist copy, so that any later 780 * atomic updates that don't do a new modeset on our plane 781 * also use our updated address. 782 */ 783 vc4_state->dlist[vc4_state->ptr0_offset] = addr; 784 } 785 786 static int vc4_prepare_fb(struct drm_plane *plane, 787 struct drm_plane_state *state) 788 { 789 struct vc4_bo *bo; 790 struct dma_fence *fence; 791 int ret; 792 793 if ((plane->state->fb == state->fb) || !state->fb) 794 return 0; 795 796 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); 797 798 ret = vc4_bo_inc_usecnt(bo); 799 if (ret) 800 return ret; 801 802 fence = reservation_object_get_excl_rcu(bo->resv); 803 drm_atomic_set_fence_for_plane(state, fence); 804 805 return 0; 806 } 807 808 static void vc4_cleanup_fb(struct drm_plane *plane, 809 struct drm_plane_state *state) 810 { 811 struct vc4_bo *bo; 812 813 if (plane->state->fb == state->fb || !state->fb) 814 return; 815 816 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); 817 vc4_bo_dec_usecnt(bo); 818 } 819 820 static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { 821 .atomic_check = vc4_plane_atomic_check, 822 .atomic_update = vc4_plane_atomic_update, 823 .prepare_fb = vc4_prepare_fb, 824 .cleanup_fb = vc4_cleanup_fb, 825 }; 826 827 static void vc4_plane_destroy(struct drm_plane *plane) 828 { 829 drm_plane_helper_disable(plane); 830 drm_plane_cleanup(plane); 831 } 832 833 /* Implements immediate (non-vblank-synced) updates of the cursor 834 * position, or falls back to the atomic helper otherwise. 835 */ 836 static int 837 vc4_update_plane(struct drm_plane *plane, 838 struct drm_crtc *crtc, 839 struct drm_framebuffer *fb, 840 int crtc_x, int crtc_y, 841 unsigned int crtc_w, unsigned int crtc_h, 842 uint32_t src_x, uint32_t src_y, 843 uint32_t src_w, uint32_t src_h, 844 struct drm_modeset_acquire_ctx *ctx) 845 { 846 struct drm_plane_state *plane_state; 847 struct vc4_plane_state *vc4_state; 848 849 if (plane != crtc->cursor) 850 goto out; 851 852 plane_state = plane->state; 853 vc4_state = to_vc4_plane_state(plane_state); 854 855 if (!plane_state) 856 goto out; 857 858 /* No configuring new scaling in the fast path. */ 859 if (crtc_w != plane_state->crtc_w || 860 crtc_h != plane_state->crtc_h || 861 src_w != plane_state->src_w || 862 src_h != plane_state->src_h) { 863 goto out; 864 } 865 866 if (fb != plane_state->fb) { 867 drm_atomic_set_fb_for_plane(plane->state, fb); 868 vc4_plane_async_set_fb(plane, fb); 869 } 870 871 /* Set the cursor's position on the screen. This is the 872 * expected change from the drm_mode_cursor_universal() 873 * helper. 874 */ 875 plane_state->crtc_x = crtc_x; 876 plane_state->crtc_y = crtc_y; 877 878 /* Allow changing the start position within the cursor BO, if 879 * that matters. 880 */ 881 plane_state->src_x = src_x; 882 plane_state->src_y = src_y; 883 884 /* Update the display list based on the new crtc_x/y. */ 885 vc4_plane_atomic_check(plane, plane_state); 886 887 /* Note that we can't just call vc4_plane_write_dlist() 888 * because that would smash the context data that the HVS is 889 * currently using. 890 */ 891 writel(vc4_state->dlist[vc4_state->pos0_offset], 892 &vc4_state->hw_dlist[vc4_state->pos0_offset]); 893 writel(vc4_state->dlist[vc4_state->pos2_offset], 894 &vc4_state->hw_dlist[vc4_state->pos2_offset]); 895 writel(vc4_state->dlist[vc4_state->ptr0_offset], 896 &vc4_state->hw_dlist[vc4_state->ptr0_offset]); 897 898 return 0; 899 900 out: 901 return drm_atomic_helper_update_plane(plane, crtc, fb, 902 crtc_x, crtc_y, 903 crtc_w, crtc_h, 904 src_x, src_y, 905 src_w, src_h, 906 ctx); 907 } 908 909 static bool vc4_format_mod_supported(struct drm_plane *plane, 910 uint32_t format, 911 uint64_t modifier) 912 { 913 /* Support T_TILING for RGB formats only. */ 914 switch (format) { 915 case DRM_FORMAT_XRGB8888: 916 case DRM_FORMAT_ARGB8888: 917 case DRM_FORMAT_ABGR8888: 918 case DRM_FORMAT_XBGR8888: 919 case DRM_FORMAT_RGB565: 920 case DRM_FORMAT_BGR565: 921 case DRM_FORMAT_ARGB1555: 922 case DRM_FORMAT_XRGB1555: 923 return true; 924 case DRM_FORMAT_YUV422: 925 case DRM_FORMAT_YVU422: 926 case DRM_FORMAT_YUV420: 927 case DRM_FORMAT_YVU420: 928 case DRM_FORMAT_NV12: 929 case DRM_FORMAT_NV16: 930 default: 931 return (modifier == DRM_FORMAT_MOD_LINEAR); 932 } 933 } 934 935 static const struct drm_plane_funcs vc4_plane_funcs = { 936 .update_plane = vc4_update_plane, 937 .disable_plane = drm_atomic_helper_disable_plane, 938 .destroy = vc4_plane_destroy, 939 .set_property = NULL, 940 .reset = vc4_plane_reset, 941 .atomic_duplicate_state = vc4_plane_duplicate_state, 942 .atomic_destroy_state = vc4_plane_destroy_state, 943 .format_mod_supported = vc4_format_mod_supported, 944 }; 945 946 struct drm_plane *vc4_plane_init(struct drm_device *dev, 947 enum drm_plane_type type) 948 { 949 struct drm_plane *plane = NULL; 950 struct vc4_plane *vc4_plane; 951 u32 formats[ARRAY_SIZE(hvs_formats)]; 952 u32 num_formats = 0; 953 int ret = 0; 954 unsigned i; 955 static const uint64_t modifiers[] = { 956 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, 957 DRM_FORMAT_MOD_LINEAR, 958 DRM_FORMAT_MOD_INVALID 959 }; 960 961 vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), 962 GFP_KERNEL); 963 if (!vc4_plane) 964 return ERR_PTR(-ENOMEM); 965 966 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { 967 /* Don't allow YUV in cursor planes, since that means 968 * tuning on the scaler, which we don't allow for the 969 * cursor. 970 */ 971 if (type != DRM_PLANE_TYPE_CURSOR || 972 hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) { 973 formats[num_formats++] = hvs_formats[i].drm; 974 } 975 } 976 plane = &vc4_plane->base; 977 ret = drm_universal_plane_init(dev, plane, 0, 978 &vc4_plane_funcs, 979 formats, num_formats, 980 modifiers, type, NULL); 981 982 drm_plane_helper_add(plane, &vc4_plane_helper_funcs); 983 984 return plane; 985 } 986