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