1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. 4 */ 5 6 #include <drm/drm_atomic.h> 7 #include <drm/drm_atomic_helper.h> 8 #include <drm/drm_fourcc.h> 9 #include <drm/drm_gem_framebuffer_helper.h> 10 #include <drm/drm_plane_helper.h> 11 12 #include "dc.h" 13 #include "plane.h" 14 15 static void tegra_plane_destroy(struct drm_plane *plane) 16 { 17 struct tegra_plane *p = to_tegra_plane(plane); 18 19 drm_plane_cleanup(plane); 20 kfree(p); 21 } 22 23 static void tegra_plane_reset(struct drm_plane *plane) 24 { 25 struct tegra_plane *p = to_tegra_plane(plane); 26 struct tegra_plane_state *state; 27 unsigned int i; 28 29 if (plane->state) 30 __drm_atomic_helper_plane_destroy_state(plane->state); 31 32 kfree(plane->state); 33 plane->state = NULL; 34 35 state = kzalloc(sizeof(*state), GFP_KERNEL); 36 if (state) { 37 plane->state = &state->base; 38 plane->state->plane = plane; 39 plane->state->zpos = p->index; 40 plane->state->normalized_zpos = p->index; 41 42 for (i = 0; i < 3; i++) 43 state->iova[i] = DMA_MAPPING_ERROR; 44 } 45 } 46 47 static struct drm_plane_state * 48 tegra_plane_atomic_duplicate_state(struct drm_plane *plane) 49 { 50 struct tegra_plane_state *state = to_tegra_plane_state(plane->state); 51 struct tegra_plane_state *copy; 52 unsigned int i; 53 54 copy = kmalloc(sizeof(*copy), GFP_KERNEL); 55 if (!copy) 56 return NULL; 57 58 __drm_atomic_helper_plane_duplicate_state(plane, ©->base); 59 copy->tiling = state->tiling; 60 copy->format = state->format; 61 copy->swap = state->swap; 62 copy->bottom_up = state->bottom_up; 63 copy->opaque = state->opaque; 64 65 for (i = 0; i < 2; i++) 66 copy->blending[i] = state->blending[i]; 67 68 for (i = 0; i < 3; i++) { 69 copy->iova[i] = DMA_MAPPING_ERROR; 70 copy->sgt[i] = NULL; 71 } 72 73 return ©->base; 74 } 75 76 static void tegra_plane_atomic_destroy_state(struct drm_plane *plane, 77 struct drm_plane_state *state) 78 { 79 __drm_atomic_helper_plane_destroy_state(state); 80 kfree(state); 81 } 82 83 static bool tegra_plane_format_mod_supported(struct drm_plane *plane, 84 uint32_t format, 85 uint64_t modifier) 86 { 87 const struct drm_format_info *info = drm_format_info(format); 88 89 if (modifier == DRM_FORMAT_MOD_LINEAR) 90 return true; 91 92 if (info->num_planes == 1) 93 return true; 94 95 return false; 96 } 97 98 const struct drm_plane_funcs tegra_plane_funcs = { 99 .update_plane = drm_atomic_helper_update_plane, 100 .disable_plane = drm_atomic_helper_disable_plane, 101 .destroy = tegra_plane_destroy, 102 .reset = tegra_plane_reset, 103 .atomic_duplicate_state = tegra_plane_atomic_duplicate_state, 104 .atomic_destroy_state = tegra_plane_atomic_destroy_state, 105 .format_mod_supported = tegra_plane_format_mod_supported, 106 }; 107 108 static int tegra_dc_pin(struct tegra_dc *dc, struct tegra_plane_state *state) 109 { 110 unsigned int i; 111 int err; 112 113 for (i = 0; i < state->base.fb->format->num_planes; i++) { 114 struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 115 116 if (!dc->client.group) { 117 struct sg_table *sgt; 118 119 sgt = host1x_bo_pin(dc->dev, &bo->base, NULL); 120 if (IS_ERR(sgt)) { 121 err = PTR_ERR(sgt); 122 goto unpin; 123 } 124 125 err = dma_map_sg(dc->dev, sgt->sgl, sgt->nents, 126 DMA_TO_DEVICE); 127 if (err == 0) { 128 err = -ENOMEM; 129 goto unpin; 130 } 131 132 /* 133 * The display controller needs contiguous memory, so 134 * fail if the buffer is discontiguous and we fail to 135 * map its SG table to a single contiguous chunk of 136 * I/O virtual memory. 137 */ 138 if (err > 1) { 139 err = -EINVAL; 140 goto unpin; 141 } 142 143 state->iova[i] = sg_dma_address(sgt->sgl); 144 state->sgt[i] = sgt; 145 } else { 146 state->iova[i] = bo->iova; 147 } 148 } 149 150 return 0; 151 152 unpin: 153 dev_err(dc->dev, "failed to map plane %u: %d\n", i, err); 154 155 while (i--) { 156 struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 157 struct sg_table *sgt = state->sgt[i]; 158 159 dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE); 160 host1x_bo_unpin(dc->dev, &bo->base, sgt); 161 162 state->iova[i] = DMA_MAPPING_ERROR; 163 state->sgt[i] = NULL; 164 } 165 166 return err; 167 } 168 169 static void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state) 170 { 171 unsigned int i; 172 173 for (i = 0; i < state->base.fb->format->num_planes; i++) { 174 struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 175 176 if (!dc->client.group) { 177 struct sg_table *sgt = state->sgt[i]; 178 179 if (sgt) { 180 dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents, 181 DMA_TO_DEVICE); 182 host1x_bo_unpin(dc->dev, &bo->base, sgt); 183 } 184 } 185 186 state->iova[i] = DMA_MAPPING_ERROR; 187 state->sgt[i] = NULL; 188 } 189 } 190 191 int tegra_plane_prepare_fb(struct drm_plane *plane, 192 struct drm_plane_state *state) 193 { 194 struct tegra_dc *dc = to_tegra_dc(state->crtc); 195 196 if (!state->fb) 197 return 0; 198 199 drm_gem_fb_prepare_fb(plane, state); 200 201 return tegra_dc_pin(dc, to_tegra_plane_state(state)); 202 } 203 204 void tegra_plane_cleanup_fb(struct drm_plane *plane, 205 struct drm_plane_state *state) 206 { 207 struct tegra_dc *dc = to_tegra_dc(state->crtc); 208 209 if (dc) 210 tegra_dc_unpin(dc, to_tegra_plane_state(state)); 211 } 212 213 int tegra_plane_state_add(struct tegra_plane *plane, 214 struct drm_plane_state *state) 215 { 216 struct drm_crtc_state *crtc_state; 217 struct tegra_dc_state *tegra; 218 int err; 219 220 /* Propagate errors from allocation or locking failures. */ 221 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); 222 if (IS_ERR(crtc_state)) 223 return PTR_ERR(crtc_state); 224 225 /* Check plane state for visibility and calculate clipping bounds */ 226 err = drm_atomic_helper_check_plane_state(state, crtc_state, 227 0, INT_MAX, true, true); 228 if (err < 0) 229 return err; 230 231 tegra = to_dc_state(crtc_state); 232 233 tegra->planes |= WIN_A_ACT_REQ << plane->index; 234 235 return 0; 236 } 237 238 int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap) 239 { 240 /* assume no swapping of fetched data */ 241 if (swap) 242 *swap = BYTE_SWAP_NOSWAP; 243 244 switch (fourcc) { 245 case DRM_FORMAT_ARGB4444: 246 *format = WIN_COLOR_DEPTH_B4G4R4A4; 247 break; 248 249 case DRM_FORMAT_ARGB1555: 250 *format = WIN_COLOR_DEPTH_B5G5R5A1; 251 break; 252 253 case DRM_FORMAT_RGB565: 254 *format = WIN_COLOR_DEPTH_B5G6R5; 255 break; 256 257 case DRM_FORMAT_RGBA5551: 258 *format = WIN_COLOR_DEPTH_A1B5G5R5; 259 break; 260 261 case DRM_FORMAT_ARGB8888: 262 *format = WIN_COLOR_DEPTH_B8G8R8A8; 263 break; 264 265 case DRM_FORMAT_ABGR8888: 266 *format = WIN_COLOR_DEPTH_R8G8B8A8; 267 break; 268 269 case DRM_FORMAT_ABGR4444: 270 *format = WIN_COLOR_DEPTH_R4G4B4A4; 271 break; 272 273 case DRM_FORMAT_ABGR1555: 274 *format = WIN_COLOR_DEPTH_R5G5B5A; 275 break; 276 277 case DRM_FORMAT_BGRA5551: 278 *format = WIN_COLOR_DEPTH_AR5G5B5; 279 break; 280 281 case DRM_FORMAT_XRGB1555: 282 *format = WIN_COLOR_DEPTH_B5G5R5X1; 283 break; 284 285 case DRM_FORMAT_RGBX5551: 286 *format = WIN_COLOR_DEPTH_X1B5G5R5; 287 break; 288 289 case DRM_FORMAT_XBGR1555: 290 *format = WIN_COLOR_DEPTH_R5G5B5X1; 291 break; 292 293 case DRM_FORMAT_BGRX5551: 294 *format = WIN_COLOR_DEPTH_X1R5G5B5; 295 break; 296 297 case DRM_FORMAT_BGR565: 298 *format = WIN_COLOR_DEPTH_R5G6B5; 299 break; 300 301 case DRM_FORMAT_BGRA8888: 302 *format = WIN_COLOR_DEPTH_A8R8G8B8; 303 break; 304 305 case DRM_FORMAT_RGBA8888: 306 *format = WIN_COLOR_DEPTH_A8B8G8R8; 307 break; 308 309 case DRM_FORMAT_XRGB8888: 310 *format = WIN_COLOR_DEPTH_B8G8R8X8; 311 break; 312 313 case DRM_FORMAT_XBGR8888: 314 *format = WIN_COLOR_DEPTH_R8G8B8X8; 315 break; 316 317 case DRM_FORMAT_UYVY: 318 *format = WIN_COLOR_DEPTH_YCbCr422; 319 break; 320 321 case DRM_FORMAT_YUYV: 322 if (!swap) 323 return -EINVAL; 324 325 *format = WIN_COLOR_DEPTH_YCbCr422; 326 *swap = BYTE_SWAP_SWAP2; 327 break; 328 329 case DRM_FORMAT_YUV420: 330 *format = WIN_COLOR_DEPTH_YCbCr420P; 331 break; 332 333 case DRM_FORMAT_YUV422: 334 *format = WIN_COLOR_DEPTH_YCbCr422P; 335 break; 336 337 default: 338 return -EINVAL; 339 } 340 341 return 0; 342 } 343 344 bool tegra_plane_format_is_yuv(unsigned int format, bool *planar) 345 { 346 switch (format) { 347 case WIN_COLOR_DEPTH_YCbCr422: 348 case WIN_COLOR_DEPTH_YUV422: 349 if (planar) 350 *planar = false; 351 352 return true; 353 354 case WIN_COLOR_DEPTH_YCbCr420P: 355 case WIN_COLOR_DEPTH_YUV420P: 356 case WIN_COLOR_DEPTH_YCbCr422P: 357 case WIN_COLOR_DEPTH_YUV422P: 358 case WIN_COLOR_DEPTH_YCbCr422R: 359 case WIN_COLOR_DEPTH_YUV422R: 360 case WIN_COLOR_DEPTH_YCbCr422RA: 361 case WIN_COLOR_DEPTH_YUV422RA: 362 if (planar) 363 *planar = true; 364 365 return true; 366 } 367 368 if (planar) 369 *planar = false; 370 371 return false; 372 } 373 374 static bool __drm_format_has_alpha(u32 format) 375 { 376 switch (format) { 377 case DRM_FORMAT_ARGB1555: 378 case DRM_FORMAT_RGBA5551: 379 case DRM_FORMAT_ABGR8888: 380 case DRM_FORMAT_ARGB8888: 381 return true; 382 } 383 384 return false; 385 } 386 387 static int tegra_plane_format_get_alpha(unsigned int opaque, 388 unsigned int *alpha) 389 { 390 if (tegra_plane_format_is_yuv(opaque, NULL)) { 391 *alpha = opaque; 392 return 0; 393 } 394 395 switch (opaque) { 396 case WIN_COLOR_DEPTH_B5G5R5X1: 397 *alpha = WIN_COLOR_DEPTH_B5G5R5A1; 398 return 0; 399 400 case WIN_COLOR_DEPTH_X1B5G5R5: 401 *alpha = WIN_COLOR_DEPTH_A1B5G5R5; 402 return 0; 403 404 case WIN_COLOR_DEPTH_R8G8B8X8: 405 *alpha = WIN_COLOR_DEPTH_R8G8B8A8; 406 return 0; 407 408 case WIN_COLOR_DEPTH_B8G8R8X8: 409 *alpha = WIN_COLOR_DEPTH_B8G8R8A8; 410 return 0; 411 412 case WIN_COLOR_DEPTH_B5G6R5: 413 *alpha = opaque; 414 return 0; 415 } 416 417 return -EINVAL; 418 } 419 420 /* 421 * This is applicable to Tegra20 and Tegra30 only where the opaque formats can 422 * be emulated using the alpha formats and alpha blending disabled. 423 */ 424 static int tegra_plane_setup_opacity(struct tegra_plane *tegra, 425 struct tegra_plane_state *state) 426 { 427 unsigned int format; 428 int err; 429 430 switch (state->format) { 431 case WIN_COLOR_DEPTH_B5G5R5A1: 432 case WIN_COLOR_DEPTH_A1B5G5R5: 433 case WIN_COLOR_DEPTH_R8G8B8A8: 434 case WIN_COLOR_DEPTH_B8G8R8A8: 435 state->opaque = false; 436 break; 437 438 default: 439 err = tegra_plane_format_get_alpha(state->format, &format); 440 if (err < 0) 441 return err; 442 443 state->format = format; 444 state->opaque = true; 445 break; 446 } 447 448 return 0; 449 } 450 451 static int tegra_plane_check_transparency(struct tegra_plane *tegra, 452 struct tegra_plane_state *state) 453 { 454 struct drm_plane_state *old, *plane_state; 455 struct drm_plane *plane; 456 457 old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base); 458 459 /* check if zpos / transparency changed */ 460 if (old->normalized_zpos == state->base.normalized_zpos && 461 to_tegra_plane_state(old)->opaque == state->opaque) 462 return 0; 463 464 /* include all sibling planes into this commit */ 465 drm_for_each_plane(plane, tegra->base.dev) { 466 struct tegra_plane *p = to_tegra_plane(plane); 467 468 /* skip this plane and planes on different CRTCs */ 469 if (p == tegra || p->dc != tegra->dc) 470 continue; 471 472 plane_state = drm_atomic_get_plane_state(state->base.state, 473 plane); 474 if (IS_ERR(plane_state)) 475 return PTR_ERR(plane_state); 476 } 477 478 return 1; 479 } 480 481 static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, 482 struct tegra_plane *other) 483 { 484 unsigned int index = 0, i; 485 486 WARN_ON(plane == other); 487 488 for (i = 0; i < 3; i++) { 489 if (i == plane->index) 490 continue; 491 492 if (i == other->index) 493 break; 494 495 index++; 496 } 497 498 return index; 499 } 500 501 static void tegra_plane_update_transparency(struct tegra_plane *tegra, 502 struct tegra_plane_state *state) 503 { 504 struct drm_plane_state *new; 505 struct drm_plane *plane; 506 unsigned int i; 507 508 for_each_new_plane_in_state(state->base.state, plane, new, i) { 509 struct tegra_plane *p = to_tegra_plane(plane); 510 unsigned index; 511 512 /* skip this plane and planes on different CRTCs */ 513 if (p == tegra || p->dc != tegra->dc) 514 continue; 515 516 index = tegra_plane_get_overlap_index(tegra, p); 517 518 if (new->fb && __drm_format_has_alpha(new->fb->format->format)) 519 state->blending[index].alpha = true; 520 else 521 state->blending[index].alpha = false; 522 523 if (new->normalized_zpos > state->base.normalized_zpos) 524 state->blending[index].top = true; 525 else 526 state->blending[index].top = false; 527 528 /* 529 * Missing framebuffer means that plane is disabled, in this 530 * case mark B / C window as top to be able to differentiate 531 * windows indices order in regards to zPos for the middle 532 * window X / Y registers programming. 533 */ 534 if (!new->fb) 535 state->blending[index].top = (index == 1); 536 } 537 } 538 539 static int tegra_plane_setup_transparency(struct tegra_plane *tegra, 540 struct tegra_plane_state *state) 541 { 542 struct tegra_plane_state *tegra_state; 543 struct drm_plane_state *new; 544 struct drm_plane *plane; 545 int err; 546 547 /* 548 * If planes zpos / transparency changed, sibling planes blending 549 * state may require adjustment and in this case they will be included 550 * into this atom commit, otherwise blending state is unchanged. 551 */ 552 err = tegra_plane_check_transparency(tegra, state); 553 if (err <= 0) 554 return err; 555 556 /* 557 * All planes are now in the atomic state, walk them up and update 558 * transparency state for each plane. 559 */ 560 drm_for_each_plane(plane, tegra->base.dev) { 561 struct tegra_plane *p = to_tegra_plane(plane); 562 563 /* skip planes on different CRTCs */ 564 if (p->dc != tegra->dc) 565 continue; 566 567 new = drm_atomic_get_new_plane_state(state->base.state, plane); 568 tegra_state = to_tegra_plane_state(new); 569 570 /* 571 * There is no need to update blending state for the disabled 572 * plane. 573 */ 574 if (new->fb) 575 tegra_plane_update_transparency(p, tegra_state); 576 } 577 578 return 0; 579 } 580 581 int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, 582 struct tegra_plane_state *state) 583 { 584 int err; 585 586 err = tegra_plane_setup_opacity(tegra, state); 587 if (err < 0) 588 return err; 589 590 err = tegra_plane_setup_transparency(tegra, state); 591 if (err < 0) 592 return err; 593 594 return 0; 595 } 596