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