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_PPF; 134 else if (dst < src) 135 return VC4_SCALING_TPZ; 136 else 137 return VC4_SCALING_NONE; 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 158 __drm_atomic_helper_plane_duplicate_state(plane, &vc4_state->base); 159 160 if (vc4_state->dlist) { 161 vc4_state->dlist = kmemdup(vc4_state->dlist, 162 vc4_state->dlist_count * 4, 163 GFP_KERNEL); 164 if (!vc4_state->dlist) { 165 kfree(vc4_state); 166 return NULL; 167 } 168 vc4_state->dlist_size = vc4_state->dlist_count; 169 } 170 171 return &vc4_state->base; 172 } 173 174 static void vc4_plane_destroy_state(struct drm_plane *plane, 175 struct drm_plane_state *state) 176 { 177 struct vc4_dev *vc4 = to_vc4_dev(plane->dev); 178 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 179 180 if (vc4_state->lbm.allocated) { 181 unsigned long irqflags; 182 183 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); 184 drm_mm_remove_node(&vc4_state->lbm); 185 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); 186 } 187 188 kfree(vc4_state->dlist); 189 __drm_atomic_helper_plane_destroy_state(&vc4_state->base); 190 kfree(state); 191 } 192 193 /* Called during init to allocate the plane's atomic state. */ 194 static void vc4_plane_reset(struct drm_plane *plane) 195 { 196 struct vc4_plane_state *vc4_state; 197 198 WARN_ON(plane->state); 199 200 vc4_state = kzalloc(sizeof(*vc4_state), GFP_KERNEL); 201 if (!vc4_state) 202 return; 203 204 __drm_atomic_helper_plane_reset(plane, &vc4_state->base); 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_array(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 vc4_state->is_unity = (vc4_state->x_scaling[0] == VC4_SCALING_NONE && 300 vc4_state->y_scaling[0] == VC4_SCALING_NONE); 301 302 if (num_planes > 1) { 303 vc4_state->is_yuv = true; 304 305 h_subsample = drm_format_horz_chroma_subsampling(format); 306 v_subsample = drm_format_vert_chroma_subsampling(format); 307 vc4_state->src_w[1] = vc4_state->src_w[0] / h_subsample; 308 vc4_state->src_h[1] = vc4_state->src_h[0] / v_subsample; 309 310 vc4_state->x_scaling[1] = 311 vc4_get_scaling_mode(vc4_state->src_w[1], 312 vc4_state->crtc_w); 313 vc4_state->y_scaling[1] = 314 vc4_get_scaling_mode(vc4_state->src_h[1], 315 vc4_state->crtc_h); 316 317 /* YUV conversion requires that horizontal scaling be enabled, 318 * even on a plane that's otherwise 1:1. Looks like only PPF 319 * works in that case, so let's pick that one. 320 */ 321 if (vc4_state->is_unity) 322 vc4_state->x_scaling[0] = VC4_SCALING_PPF; 323 } else { 324 vc4_state->x_scaling[1] = VC4_SCALING_NONE; 325 vc4_state->y_scaling[1] = VC4_SCALING_NONE; 326 } 327 328 /* No configuring scaling on the cursor plane, since it gets 329 non-vblank-synced updates, and scaling requires requires 330 LBM changes which have to be vblank-synced. 331 */ 332 if (plane->type == DRM_PLANE_TYPE_CURSOR && !vc4_state->is_unity) 333 return -EINVAL; 334 335 /* Clamp the on-screen start x/y to 0. The hardware doesn't 336 * support negative y, and negative x wastes bandwidth. 337 */ 338 if (vc4_state->crtc_x < 0) { 339 for (i = 0; i < num_planes; i++) { 340 u32 cpp = fb->format->cpp[i]; 341 u32 subs = ((i == 0) ? 1 : h_subsample); 342 343 vc4_state->offsets[i] += (cpp * 344 (-vc4_state->crtc_x) / subs); 345 } 346 vc4_state->src_w[0] += vc4_state->crtc_x; 347 vc4_state->src_w[1] += vc4_state->crtc_x / h_subsample; 348 vc4_state->crtc_x = 0; 349 } 350 351 if (vc4_state->crtc_y < 0) { 352 for (i = 0; i < num_planes; i++) { 353 u32 subs = ((i == 0) ? 1 : v_subsample); 354 355 vc4_state->offsets[i] += (fb->pitches[i] * 356 (-vc4_state->crtc_y) / subs); 357 } 358 vc4_state->src_h[0] += vc4_state->crtc_y; 359 vc4_state->src_h[1] += vc4_state->crtc_y / v_subsample; 360 vc4_state->crtc_y = 0; 361 } 362 363 return 0; 364 } 365 366 static void vc4_write_tpz(struct vc4_plane_state *vc4_state, u32 src, u32 dst) 367 { 368 u32 scale, recip; 369 370 scale = (1 << 16) * src / dst; 371 372 /* The specs note that while the reciprocal would be defined 373 * as (1<<32)/scale, ~0 is close enough. 374 */ 375 recip = ~0 / scale; 376 377 vc4_dlist_write(vc4_state, 378 VC4_SET_FIELD(scale, SCALER_TPZ0_SCALE) | 379 VC4_SET_FIELD(0, SCALER_TPZ0_IPHASE)); 380 vc4_dlist_write(vc4_state, 381 VC4_SET_FIELD(recip, SCALER_TPZ1_RECIP)); 382 } 383 384 static void vc4_write_ppf(struct vc4_plane_state *vc4_state, u32 src, u32 dst) 385 { 386 u32 scale = (1 << 16) * src / dst; 387 388 vc4_dlist_write(vc4_state, 389 SCALER_PPF_AGC | 390 VC4_SET_FIELD(scale, SCALER_PPF_SCALE) | 391 VC4_SET_FIELD(0, SCALER_PPF_IPHASE)); 392 } 393 394 static u32 vc4_lbm_size(struct drm_plane_state *state) 395 { 396 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 397 /* This is the worst case number. One of the two sizes will 398 * be used depending on the scaling configuration. 399 */ 400 u32 pix_per_line = max(vc4_state->src_w[0], (u32)vc4_state->crtc_w); 401 u32 lbm; 402 403 if (!vc4_state->is_yuv) { 404 if (vc4_state->is_unity) 405 return 0; 406 else if (vc4_state->y_scaling[0] == VC4_SCALING_TPZ) 407 lbm = pix_per_line * 8; 408 else { 409 /* In special cases, this multiplier might be 12. */ 410 lbm = pix_per_line * 16; 411 } 412 } else { 413 /* There are cases for this going down to a multiplier 414 * of 2, but according to the firmware source, the 415 * table in the docs is somewhat wrong. 416 */ 417 lbm = pix_per_line * 16; 418 } 419 420 lbm = roundup(lbm, 32); 421 422 return lbm; 423 } 424 425 static void vc4_write_scaling_parameters(struct drm_plane_state *state, 426 int channel) 427 { 428 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 429 430 /* Ch0 H-PPF Word 0: Scaling Parameters */ 431 if (vc4_state->x_scaling[channel] == VC4_SCALING_PPF) { 432 vc4_write_ppf(vc4_state, 433 vc4_state->src_w[channel], vc4_state->crtc_w); 434 } 435 436 /* Ch0 V-PPF Words 0-1: Scaling Parameters, Context */ 437 if (vc4_state->y_scaling[channel] == VC4_SCALING_PPF) { 438 vc4_write_ppf(vc4_state, 439 vc4_state->src_h[channel], vc4_state->crtc_h); 440 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 441 } 442 443 /* Ch0 H-TPZ Words 0-1: Scaling Parameters, Recip */ 444 if (vc4_state->x_scaling[channel] == VC4_SCALING_TPZ) { 445 vc4_write_tpz(vc4_state, 446 vc4_state->src_w[channel], vc4_state->crtc_w); 447 } 448 449 /* Ch0 V-TPZ Words 0-2: Scaling Parameters, Recip, Context */ 450 if (vc4_state->y_scaling[channel] == VC4_SCALING_TPZ) { 451 vc4_write_tpz(vc4_state, 452 vc4_state->src_h[channel], vc4_state->crtc_h); 453 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 454 } 455 } 456 457 /* Writes out a full display list for an active plane to the plane's 458 * private dlist state. 459 */ 460 static int vc4_plane_mode_set(struct drm_plane *plane, 461 struct drm_plane_state *state) 462 { 463 struct vc4_dev *vc4 = to_vc4_dev(plane->dev); 464 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 465 struct drm_framebuffer *fb = state->fb; 466 u32 ctl0_offset = vc4_state->dlist_count; 467 const struct hvs_format *format = vc4_get_hvs_format(fb->format->format); 468 u64 base_format_mod = fourcc_mod_broadcom_mod(fb->modifier); 469 int num_planes = drm_format_num_planes(format->drm); 470 bool mix_plane_alpha; 471 bool covers_screen; 472 u32 scl0, scl1, pitch0; 473 u32 lbm_size, tiling; 474 unsigned long irqflags; 475 u32 hvs_format = format->hvs; 476 int ret, i; 477 478 ret = vc4_plane_setup_clipping_and_scaling(state); 479 if (ret) 480 return ret; 481 482 /* Allocate the LBM memory that the HVS will use for temporary 483 * storage due to our scaling/format conversion. 484 */ 485 lbm_size = vc4_lbm_size(state); 486 if (lbm_size) { 487 if (!vc4_state->lbm.allocated) { 488 spin_lock_irqsave(&vc4->hvs->mm_lock, irqflags); 489 ret = drm_mm_insert_node_generic(&vc4->hvs->lbm_mm, 490 &vc4_state->lbm, 491 lbm_size, 32, 0, 0); 492 spin_unlock_irqrestore(&vc4->hvs->mm_lock, irqflags); 493 } else { 494 WARN_ON_ONCE(lbm_size != vc4_state->lbm.size); 495 } 496 } 497 498 if (ret) 499 return ret; 500 501 /* SCL1 is used for Cb/Cr scaling of planar formats. For RGB 502 * and 4:4:4, scl1 should be set to scl0 so both channels of 503 * the scaler do the same thing. For YUV, the Y plane needs 504 * to be put in channel 1 and Cb/Cr in channel 0, so we swap 505 * the scl fields here. 506 */ 507 if (num_planes == 1) { 508 scl0 = vc4_get_scl_field(state, 0); 509 scl1 = scl0; 510 } else { 511 scl0 = vc4_get_scl_field(state, 1); 512 scl1 = vc4_get_scl_field(state, 0); 513 } 514 515 switch (base_format_mod) { 516 case DRM_FORMAT_MOD_LINEAR: 517 tiling = SCALER_CTL0_TILING_LINEAR; 518 pitch0 = VC4_SET_FIELD(fb->pitches[0], SCALER_SRC_PITCH); 519 break; 520 521 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: { 522 /* For T-tiled, the FB pitch is "how many bytes from 523 * one row to the next, such that pitch * tile_h == 524 * tile_size * tiles_per_row." 525 */ 526 u32 tile_size_shift = 12; /* T tiles are 4kb */ 527 u32 tile_h_shift = 5; /* 16 and 32bpp are 32 pixels high */ 528 u32 tiles_w = fb->pitches[0] >> (tile_size_shift - tile_h_shift); 529 530 tiling = SCALER_CTL0_TILING_256B_OR_T; 531 532 pitch0 = (VC4_SET_FIELD(0, SCALER_PITCH0_TILE_Y_OFFSET) | 533 VC4_SET_FIELD(0, SCALER_PITCH0_TILE_WIDTH_L) | 534 VC4_SET_FIELD(tiles_w, SCALER_PITCH0_TILE_WIDTH_R)); 535 break; 536 } 537 538 case DRM_FORMAT_MOD_BROADCOM_SAND64: 539 case DRM_FORMAT_MOD_BROADCOM_SAND128: 540 case DRM_FORMAT_MOD_BROADCOM_SAND256: { 541 uint32_t param = fourcc_mod_broadcom_param(fb->modifier); 542 543 /* Column-based NV12 or RGBA. 544 */ 545 if (fb->format->num_planes > 1) { 546 if (hvs_format != HVS_PIXEL_FORMAT_YCBCR_YUV420_2PLANE) { 547 DRM_DEBUG_KMS("SAND format only valid for NV12/21"); 548 return -EINVAL; 549 } 550 hvs_format = HVS_PIXEL_FORMAT_H264; 551 } else { 552 if (base_format_mod == DRM_FORMAT_MOD_BROADCOM_SAND256) { 553 DRM_DEBUG_KMS("SAND256 format only valid for H.264"); 554 return -EINVAL; 555 } 556 } 557 558 switch (base_format_mod) { 559 case DRM_FORMAT_MOD_BROADCOM_SAND64: 560 tiling = SCALER_CTL0_TILING_64B; 561 break; 562 case DRM_FORMAT_MOD_BROADCOM_SAND128: 563 tiling = SCALER_CTL0_TILING_128B; 564 break; 565 case DRM_FORMAT_MOD_BROADCOM_SAND256: 566 tiling = SCALER_CTL0_TILING_256B_OR_T; 567 break; 568 default: 569 break; 570 } 571 572 if (param > SCALER_TILE_HEIGHT_MASK) { 573 DRM_DEBUG_KMS("SAND height too large (%d)\n", param); 574 return -EINVAL; 575 } 576 577 pitch0 = VC4_SET_FIELD(param, SCALER_TILE_HEIGHT); 578 break; 579 } 580 581 default: 582 DRM_DEBUG_KMS("Unsupported FB tiling flag 0x%16llx", 583 (long long)fb->modifier); 584 return -EINVAL; 585 } 586 587 /* Control word */ 588 vc4_dlist_write(vc4_state, 589 SCALER_CTL0_VALID | 590 VC4_SET_FIELD(SCALER_CTL0_RGBA_EXPAND_ROUND, SCALER_CTL0_RGBA_EXPAND) | 591 (format->pixel_order << SCALER_CTL0_ORDER_SHIFT) | 592 (hvs_format << SCALER_CTL0_PIXEL_FORMAT_SHIFT) | 593 VC4_SET_FIELD(tiling, SCALER_CTL0_TILING) | 594 (vc4_state->is_unity ? SCALER_CTL0_UNITY : 0) | 595 VC4_SET_FIELD(scl0, SCALER_CTL0_SCL0) | 596 VC4_SET_FIELD(scl1, SCALER_CTL0_SCL1)); 597 598 /* Position Word 0: Image Positions and Alpha Value */ 599 vc4_state->pos0_offset = vc4_state->dlist_count; 600 vc4_dlist_write(vc4_state, 601 VC4_SET_FIELD(state->alpha >> 8, SCALER_POS0_FIXED_ALPHA) | 602 VC4_SET_FIELD(vc4_state->crtc_x, SCALER_POS0_START_X) | 603 VC4_SET_FIELD(vc4_state->crtc_y, SCALER_POS0_START_Y)); 604 605 /* Position Word 1: Scaled Image Dimensions. */ 606 if (!vc4_state->is_unity) { 607 vc4_dlist_write(vc4_state, 608 VC4_SET_FIELD(vc4_state->crtc_w, 609 SCALER_POS1_SCL_WIDTH) | 610 VC4_SET_FIELD(vc4_state->crtc_h, 611 SCALER_POS1_SCL_HEIGHT)); 612 } 613 614 /* Don't waste cycles mixing with plane alpha if the set alpha 615 * is opaque or there is no per-pixel alpha information. 616 * In any case we use the alpha property value as the fixed alpha. 617 */ 618 mix_plane_alpha = state->alpha != DRM_BLEND_ALPHA_OPAQUE && 619 fb->format->has_alpha; 620 621 /* Position Word 2: Source Image Size, Alpha */ 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 (mix_plane_alpha ? SCALER_POS2_ALPHA_MIX : 0) | 629 (fb->format->has_alpha ? SCALER_POS2_ALPHA_PREMULT : 0) | 630 VC4_SET_FIELD(vc4_state->src_w[0], SCALER_POS2_WIDTH) | 631 VC4_SET_FIELD(vc4_state->src_h[0], SCALER_POS2_HEIGHT)); 632 633 /* Position Word 3: Context. Written by the HVS. */ 634 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 635 636 637 /* Pointer Word 0/1/2: RGB / Y / Cb / Cr Pointers 638 * 639 * The pointers may be any byte address. 640 */ 641 vc4_state->ptr0_offset = vc4_state->dlist_count; 642 for (i = 0; i < num_planes; i++) 643 vc4_dlist_write(vc4_state, vc4_state->offsets[i]); 644 645 /* Pointer Context Word 0/1/2: Written by the HVS */ 646 for (i = 0; i < num_planes; i++) 647 vc4_dlist_write(vc4_state, 0xc0c0c0c0); 648 649 /* Pitch word 0 */ 650 vc4_dlist_write(vc4_state, pitch0); 651 652 /* Pitch word 1/2 */ 653 for (i = 1; i < num_planes; i++) { 654 if (hvs_format != HVS_PIXEL_FORMAT_H264) { 655 vc4_dlist_write(vc4_state, 656 VC4_SET_FIELD(fb->pitches[i], 657 SCALER_SRC_PITCH)); 658 } else { 659 vc4_dlist_write(vc4_state, pitch0); 660 } 661 } 662 663 /* Colorspace conversion words */ 664 if (vc4_state->is_yuv) { 665 vc4_dlist_write(vc4_state, SCALER_CSC0_ITR_R_601_5); 666 vc4_dlist_write(vc4_state, SCALER_CSC1_ITR_R_601_5); 667 vc4_dlist_write(vc4_state, SCALER_CSC2_ITR_R_601_5); 668 } 669 670 if (vc4_state->x_scaling[0] != VC4_SCALING_NONE || 671 vc4_state->x_scaling[1] != VC4_SCALING_NONE || 672 vc4_state->y_scaling[0] != VC4_SCALING_NONE || 673 vc4_state->y_scaling[1] != VC4_SCALING_NONE) { 674 /* LBM Base Address. */ 675 if (vc4_state->y_scaling[0] != VC4_SCALING_NONE || 676 vc4_state->y_scaling[1] != VC4_SCALING_NONE) { 677 vc4_dlist_write(vc4_state, vc4_state->lbm.start); 678 } 679 680 if (num_planes > 1) { 681 /* Emit Cb/Cr as channel 0 and Y as channel 682 * 1. This matches how we set up scl0/scl1 683 * above. 684 */ 685 vc4_write_scaling_parameters(state, 1); 686 } 687 vc4_write_scaling_parameters(state, 0); 688 689 /* If any PPF setup was done, then all the kernel 690 * pointers get uploaded. 691 */ 692 if (vc4_state->x_scaling[0] == VC4_SCALING_PPF || 693 vc4_state->y_scaling[0] == VC4_SCALING_PPF || 694 vc4_state->x_scaling[1] == VC4_SCALING_PPF || 695 vc4_state->y_scaling[1] == VC4_SCALING_PPF) { 696 u32 kernel = VC4_SET_FIELD(vc4->hvs->mitchell_netravali_filter.start, 697 SCALER_PPF_KERNEL_OFFSET); 698 699 /* HPPF plane 0 */ 700 vc4_dlist_write(vc4_state, kernel); 701 /* VPPF plane 0 */ 702 vc4_dlist_write(vc4_state, kernel); 703 /* HPPF plane 1 */ 704 vc4_dlist_write(vc4_state, kernel); 705 /* VPPF plane 1 */ 706 vc4_dlist_write(vc4_state, kernel); 707 } 708 } 709 710 vc4_state->dlist[ctl0_offset] |= 711 VC4_SET_FIELD(vc4_state->dlist_count, SCALER_CTL0_SIZE); 712 713 /* crtc_* are already clipped coordinates. */ 714 covers_screen = vc4_state->crtc_x == 0 && vc4_state->crtc_y == 0 && 715 vc4_state->crtc_w == state->crtc->mode.hdisplay && 716 vc4_state->crtc_h == state->crtc->mode.vdisplay; 717 /* Background fill might be necessary when the plane has per-pixel 718 * alpha content or a non-opaque plane alpha and could blend from the 719 * background or does not cover the entire screen. 720 */ 721 vc4_state->needs_bg_fill = fb->format->has_alpha || !covers_screen || 722 state->alpha != DRM_BLEND_ALPHA_OPAQUE; 723 724 return 0; 725 } 726 727 /* If a modeset involves changing the setup of a plane, the atomic 728 * infrastructure will call this to validate a proposed plane setup. 729 * However, if a plane isn't getting updated, this (and the 730 * corresponding vc4_plane_atomic_update) won't get called. Thus, we 731 * compute the dlist here and have all active plane dlists get updated 732 * in the CRTC's flush. 733 */ 734 static int vc4_plane_atomic_check(struct drm_plane *plane, 735 struct drm_plane_state *state) 736 { 737 struct vc4_plane_state *vc4_state = to_vc4_plane_state(state); 738 739 vc4_state->dlist_count = 0; 740 741 if (plane_enabled(state)) 742 return vc4_plane_mode_set(plane, state); 743 else 744 return 0; 745 } 746 747 static void vc4_plane_atomic_update(struct drm_plane *plane, 748 struct drm_plane_state *old_state) 749 { 750 /* No contents here. Since we don't know where in the CRTC's 751 * dlist we should be stored, our dlist is uploaded to the 752 * hardware with vc4_plane_write_dlist() at CRTC atomic_flush 753 * time. 754 */ 755 } 756 757 u32 vc4_plane_write_dlist(struct drm_plane *plane, u32 __iomem *dlist) 758 { 759 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); 760 int i; 761 762 vc4_state->hw_dlist = dlist; 763 764 /* Can't memcpy_toio() because it needs to be 32-bit writes. */ 765 for (i = 0; i < vc4_state->dlist_count; i++) 766 writel(vc4_state->dlist[i], &dlist[i]); 767 768 return vc4_state->dlist_count; 769 } 770 771 u32 vc4_plane_dlist_size(const struct drm_plane_state *state) 772 { 773 const struct vc4_plane_state *vc4_state = 774 container_of(state, typeof(*vc4_state), base); 775 776 return vc4_state->dlist_count; 777 } 778 779 /* Updates the plane to immediately (well, once the FIFO needs 780 * refilling) scan out from at a new framebuffer. 781 */ 782 void vc4_plane_async_set_fb(struct drm_plane *plane, struct drm_framebuffer *fb) 783 { 784 struct vc4_plane_state *vc4_state = to_vc4_plane_state(plane->state); 785 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0); 786 uint32_t addr; 787 788 /* We're skipping the address adjustment for negative origin, 789 * because this is only called on the primary plane. 790 */ 791 WARN_ON_ONCE(plane->state->crtc_x < 0 || plane->state->crtc_y < 0); 792 addr = bo->paddr + fb->offsets[0]; 793 794 /* Write the new address into the hardware immediately. The 795 * scanout will start from this address as soon as the FIFO 796 * needs to refill with pixels. 797 */ 798 writel(addr, &vc4_state->hw_dlist[vc4_state->ptr0_offset]); 799 800 /* Also update the CPU-side dlist copy, so that any later 801 * atomic updates that don't do a new modeset on our plane 802 * also use our updated address. 803 */ 804 vc4_state->dlist[vc4_state->ptr0_offset] = addr; 805 } 806 807 static void vc4_plane_atomic_async_update(struct drm_plane *plane, 808 struct drm_plane_state *state) 809 { 810 struct vc4_plane_state *vc4_state, *new_vc4_state; 811 812 if (plane->state->fb != state->fb) { 813 vc4_plane_async_set_fb(plane, state->fb); 814 drm_atomic_set_fb_for_plane(plane->state, state->fb); 815 } 816 817 /* Set the cursor's position on the screen. This is the 818 * expected change from the drm_mode_cursor_universal() 819 * helper. 820 */ 821 plane->state->crtc_x = state->crtc_x; 822 plane->state->crtc_y = state->crtc_y; 823 824 /* Allow changing the start position within the cursor BO, if 825 * that matters. 826 */ 827 plane->state->src_x = state->src_x; 828 plane->state->src_y = state->src_y; 829 830 /* Update the display list based on the new crtc_x/y. */ 831 vc4_plane_atomic_check(plane, state); 832 833 new_vc4_state = to_vc4_plane_state(state); 834 vc4_state = to_vc4_plane_state(plane->state); 835 836 /* Update the current vc4_state pos0, pos2 and ptr0 dlist entries. */ 837 vc4_state->dlist[vc4_state->pos0_offset] = 838 new_vc4_state->dlist[vc4_state->pos0_offset]; 839 vc4_state->dlist[vc4_state->pos2_offset] = 840 new_vc4_state->dlist[vc4_state->pos2_offset]; 841 vc4_state->dlist[vc4_state->ptr0_offset] = 842 new_vc4_state->dlist[vc4_state->ptr0_offset]; 843 844 /* Note that we can't just call vc4_plane_write_dlist() 845 * because that would smash the context data that the HVS is 846 * currently using. 847 */ 848 writel(vc4_state->dlist[vc4_state->pos0_offset], 849 &vc4_state->hw_dlist[vc4_state->pos0_offset]); 850 writel(vc4_state->dlist[vc4_state->pos2_offset], 851 &vc4_state->hw_dlist[vc4_state->pos2_offset]); 852 writel(vc4_state->dlist[vc4_state->ptr0_offset], 853 &vc4_state->hw_dlist[vc4_state->ptr0_offset]); 854 } 855 856 static int vc4_plane_atomic_async_check(struct drm_plane *plane, 857 struct drm_plane_state *state) 858 { 859 /* No configuring new scaling in the fast path. */ 860 if (plane->state->crtc_w != state->crtc_w || 861 plane->state->crtc_h != state->crtc_h || 862 plane->state->src_w != state->src_w || 863 plane->state->src_h != state->src_h) 864 return -EINVAL; 865 866 return 0; 867 } 868 869 static int vc4_prepare_fb(struct drm_plane *plane, 870 struct drm_plane_state *state) 871 { 872 struct vc4_bo *bo; 873 struct dma_fence *fence; 874 int ret; 875 876 if (!state->fb) 877 return 0; 878 879 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); 880 881 fence = reservation_object_get_excl_rcu(bo->resv); 882 drm_atomic_set_fence_for_plane(state, fence); 883 884 if (plane->state->fb == state->fb) 885 return 0; 886 887 ret = vc4_bo_inc_usecnt(bo); 888 if (ret) 889 return ret; 890 891 return 0; 892 } 893 894 static void vc4_cleanup_fb(struct drm_plane *plane, 895 struct drm_plane_state *state) 896 { 897 struct vc4_bo *bo; 898 899 if (plane->state->fb == state->fb || !state->fb) 900 return; 901 902 bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base); 903 vc4_bo_dec_usecnt(bo); 904 } 905 906 static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = { 907 .atomic_check = vc4_plane_atomic_check, 908 .atomic_update = vc4_plane_atomic_update, 909 .prepare_fb = vc4_prepare_fb, 910 .cleanup_fb = vc4_cleanup_fb, 911 .atomic_async_check = vc4_plane_atomic_async_check, 912 .atomic_async_update = vc4_plane_atomic_async_update, 913 }; 914 915 static void vc4_plane_destroy(struct drm_plane *plane) 916 { 917 drm_plane_helper_disable(plane, NULL); 918 drm_plane_cleanup(plane); 919 } 920 921 static bool vc4_format_mod_supported(struct drm_plane *plane, 922 uint32_t format, 923 uint64_t modifier) 924 { 925 /* Support T_TILING for RGB formats only. */ 926 switch (format) { 927 case DRM_FORMAT_XRGB8888: 928 case DRM_FORMAT_ARGB8888: 929 case DRM_FORMAT_ABGR8888: 930 case DRM_FORMAT_XBGR8888: 931 case DRM_FORMAT_RGB565: 932 case DRM_FORMAT_BGR565: 933 case DRM_FORMAT_ARGB1555: 934 case DRM_FORMAT_XRGB1555: 935 switch (fourcc_mod_broadcom_mod(modifier)) { 936 case DRM_FORMAT_MOD_LINEAR: 937 case DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED: 938 case DRM_FORMAT_MOD_BROADCOM_SAND64: 939 case DRM_FORMAT_MOD_BROADCOM_SAND128: 940 return true; 941 default: 942 return false; 943 } 944 case DRM_FORMAT_NV12: 945 case DRM_FORMAT_NV21: 946 switch (fourcc_mod_broadcom_mod(modifier)) { 947 case DRM_FORMAT_MOD_LINEAR: 948 case DRM_FORMAT_MOD_BROADCOM_SAND64: 949 case DRM_FORMAT_MOD_BROADCOM_SAND128: 950 case DRM_FORMAT_MOD_BROADCOM_SAND256: 951 return true; 952 default: 953 return false; 954 } 955 case DRM_FORMAT_YUV422: 956 case DRM_FORMAT_YVU422: 957 case DRM_FORMAT_YUV420: 958 case DRM_FORMAT_YVU420: 959 case DRM_FORMAT_NV16: 960 case DRM_FORMAT_NV61: 961 default: 962 return (modifier == DRM_FORMAT_MOD_LINEAR); 963 } 964 } 965 966 static const struct drm_plane_funcs vc4_plane_funcs = { 967 .update_plane = drm_atomic_helper_update_plane, 968 .disable_plane = drm_atomic_helper_disable_plane, 969 .destroy = vc4_plane_destroy, 970 .set_property = NULL, 971 .reset = vc4_plane_reset, 972 .atomic_duplicate_state = vc4_plane_duplicate_state, 973 .atomic_destroy_state = vc4_plane_destroy_state, 974 .format_mod_supported = vc4_format_mod_supported, 975 }; 976 977 struct drm_plane *vc4_plane_init(struct drm_device *dev, 978 enum drm_plane_type type) 979 { 980 struct drm_plane *plane = NULL; 981 struct vc4_plane *vc4_plane; 982 u32 formats[ARRAY_SIZE(hvs_formats)]; 983 u32 num_formats = 0; 984 int ret = 0; 985 unsigned i; 986 static const uint64_t modifiers[] = { 987 DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED, 988 DRM_FORMAT_MOD_BROADCOM_SAND128, 989 DRM_FORMAT_MOD_BROADCOM_SAND64, 990 DRM_FORMAT_MOD_BROADCOM_SAND256, 991 DRM_FORMAT_MOD_LINEAR, 992 DRM_FORMAT_MOD_INVALID 993 }; 994 995 vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane), 996 GFP_KERNEL); 997 if (!vc4_plane) 998 return ERR_PTR(-ENOMEM); 999 1000 for (i = 0; i < ARRAY_SIZE(hvs_formats); i++) { 1001 /* Don't allow YUV in cursor planes, since that means 1002 * tuning on the scaler, which we don't allow for the 1003 * cursor. 1004 */ 1005 if (type != DRM_PLANE_TYPE_CURSOR || 1006 hvs_formats[i].hvs < HVS_PIXEL_FORMAT_YCBCR_YUV420_3PLANE) { 1007 formats[num_formats++] = hvs_formats[i].drm; 1008 } 1009 } 1010 plane = &vc4_plane->base; 1011 ret = drm_universal_plane_init(dev, plane, 0, 1012 &vc4_plane_funcs, 1013 formats, num_formats, 1014 modifiers, type, NULL); 1015 1016 drm_plane_helper_add(plane, &vc4_plane_helper_funcs); 1017 1018 drm_plane_create_alpha_property(plane); 1019 1020 return plane; 1021 } 1022