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 state->iova[i] = sg_dma_address(sgt->sgl); 133 state->sgt[i] = sgt; 134 } else { 135 state->iova[i] = bo->iova; 136 } 137 } 138 139 return 0; 140 141 unpin: 142 dev_err(dc->dev, "failed to map plane %u: %d\n", i, err); 143 144 while (i--) { 145 struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 146 struct sg_table *sgt = state->sgt[i]; 147 148 dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE); 149 host1x_bo_unpin(dc->dev, &bo->base, sgt); 150 151 state->iova[i] = DMA_MAPPING_ERROR; 152 state->sgt[i] = NULL; 153 } 154 155 return err; 156 } 157 158 static void tegra_dc_unpin(struct tegra_dc *dc, struct tegra_plane_state *state) 159 { 160 unsigned int i; 161 162 for (i = 0; i < state->base.fb->format->num_planes; i++) { 163 struct tegra_bo *bo = tegra_fb_get_plane(state->base.fb, i); 164 165 if (!dc->client.group) { 166 struct sg_table *sgt = state->sgt[i]; 167 168 if (sgt) { 169 dma_unmap_sg(dc->dev, sgt->sgl, sgt->nents, 170 DMA_TO_DEVICE); 171 host1x_bo_unpin(dc->dev, &bo->base, sgt); 172 } 173 } 174 175 state->iova[i] = DMA_MAPPING_ERROR; 176 state->sgt[i] = NULL; 177 } 178 } 179 180 int tegra_plane_prepare_fb(struct drm_plane *plane, 181 struct drm_plane_state *state) 182 { 183 struct tegra_dc *dc = to_tegra_dc(state->crtc); 184 185 if (!state->fb) 186 return 0; 187 188 drm_gem_fb_prepare_fb(plane, state); 189 190 return tegra_dc_pin(dc, to_tegra_plane_state(state)); 191 } 192 193 void tegra_plane_cleanup_fb(struct drm_plane *plane, 194 struct drm_plane_state *state) 195 { 196 struct tegra_dc *dc = to_tegra_dc(state->crtc); 197 198 if (dc) 199 tegra_dc_unpin(dc, to_tegra_plane_state(state)); 200 } 201 202 int tegra_plane_state_add(struct tegra_plane *plane, 203 struct drm_plane_state *state) 204 { 205 struct drm_crtc_state *crtc_state; 206 struct tegra_dc_state *tegra; 207 int err; 208 209 /* Propagate errors from allocation or locking failures. */ 210 crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); 211 if (IS_ERR(crtc_state)) 212 return PTR_ERR(crtc_state); 213 214 /* Check plane state for visibility and calculate clipping bounds */ 215 err = drm_atomic_helper_check_plane_state(state, crtc_state, 216 0, INT_MAX, true, true); 217 if (err < 0) 218 return err; 219 220 tegra = to_dc_state(crtc_state); 221 222 tegra->planes |= WIN_A_ACT_REQ << plane->index; 223 224 return 0; 225 } 226 227 int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap) 228 { 229 /* assume no swapping of fetched data */ 230 if (swap) 231 *swap = BYTE_SWAP_NOSWAP; 232 233 switch (fourcc) { 234 case DRM_FORMAT_ARGB4444: 235 *format = WIN_COLOR_DEPTH_B4G4R4A4; 236 break; 237 238 case DRM_FORMAT_ARGB1555: 239 *format = WIN_COLOR_DEPTH_B5G5R5A1; 240 break; 241 242 case DRM_FORMAT_RGB565: 243 *format = WIN_COLOR_DEPTH_B5G6R5; 244 break; 245 246 case DRM_FORMAT_RGBA5551: 247 *format = WIN_COLOR_DEPTH_A1B5G5R5; 248 break; 249 250 case DRM_FORMAT_ARGB8888: 251 *format = WIN_COLOR_DEPTH_B8G8R8A8; 252 break; 253 254 case DRM_FORMAT_ABGR8888: 255 *format = WIN_COLOR_DEPTH_R8G8B8A8; 256 break; 257 258 case DRM_FORMAT_ABGR4444: 259 *format = WIN_COLOR_DEPTH_R4G4B4A4; 260 break; 261 262 case DRM_FORMAT_ABGR1555: 263 *format = WIN_COLOR_DEPTH_R5G5B5A; 264 break; 265 266 case DRM_FORMAT_BGRA5551: 267 *format = WIN_COLOR_DEPTH_AR5G5B5; 268 break; 269 270 case DRM_FORMAT_XRGB1555: 271 *format = WIN_COLOR_DEPTH_B5G5R5X1; 272 break; 273 274 case DRM_FORMAT_RGBX5551: 275 *format = WIN_COLOR_DEPTH_X1B5G5R5; 276 break; 277 278 case DRM_FORMAT_XBGR1555: 279 *format = WIN_COLOR_DEPTH_R5G5B5X1; 280 break; 281 282 case DRM_FORMAT_BGRX5551: 283 *format = WIN_COLOR_DEPTH_X1R5G5B5; 284 break; 285 286 case DRM_FORMAT_BGR565: 287 *format = WIN_COLOR_DEPTH_R5G6B5; 288 break; 289 290 case DRM_FORMAT_BGRA8888: 291 *format = WIN_COLOR_DEPTH_A8R8G8B8; 292 break; 293 294 case DRM_FORMAT_RGBA8888: 295 *format = WIN_COLOR_DEPTH_A8B8G8R8; 296 break; 297 298 case DRM_FORMAT_XRGB8888: 299 *format = WIN_COLOR_DEPTH_B8G8R8X8; 300 break; 301 302 case DRM_FORMAT_XBGR8888: 303 *format = WIN_COLOR_DEPTH_R8G8B8X8; 304 break; 305 306 case DRM_FORMAT_UYVY: 307 *format = WIN_COLOR_DEPTH_YCbCr422; 308 break; 309 310 case DRM_FORMAT_YUYV: 311 if (!swap) 312 return -EINVAL; 313 314 *format = WIN_COLOR_DEPTH_YCbCr422; 315 *swap = BYTE_SWAP_SWAP2; 316 break; 317 318 case DRM_FORMAT_YUV420: 319 *format = WIN_COLOR_DEPTH_YCbCr420P; 320 break; 321 322 case DRM_FORMAT_YUV422: 323 *format = WIN_COLOR_DEPTH_YCbCr422P; 324 break; 325 326 default: 327 return -EINVAL; 328 } 329 330 return 0; 331 } 332 333 bool tegra_plane_format_is_yuv(unsigned int format, bool *planar) 334 { 335 switch (format) { 336 case WIN_COLOR_DEPTH_YCbCr422: 337 case WIN_COLOR_DEPTH_YUV422: 338 if (planar) 339 *planar = false; 340 341 return true; 342 343 case WIN_COLOR_DEPTH_YCbCr420P: 344 case WIN_COLOR_DEPTH_YUV420P: 345 case WIN_COLOR_DEPTH_YCbCr422P: 346 case WIN_COLOR_DEPTH_YUV422P: 347 case WIN_COLOR_DEPTH_YCbCr422R: 348 case WIN_COLOR_DEPTH_YUV422R: 349 case WIN_COLOR_DEPTH_YCbCr422RA: 350 case WIN_COLOR_DEPTH_YUV422RA: 351 if (planar) 352 *planar = true; 353 354 return true; 355 } 356 357 if (planar) 358 *planar = false; 359 360 return false; 361 } 362 363 static bool __drm_format_has_alpha(u32 format) 364 { 365 switch (format) { 366 case DRM_FORMAT_ARGB1555: 367 case DRM_FORMAT_RGBA5551: 368 case DRM_FORMAT_ABGR8888: 369 case DRM_FORMAT_ARGB8888: 370 return true; 371 } 372 373 return false; 374 } 375 376 static int tegra_plane_format_get_alpha(unsigned int opaque, 377 unsigned int *alpha) 378 { 379 if (tegra_plane_format_is_yuv(opaque, NULL)) { 380 *alpha = opaque; 381 return 0; 382 } 383 384 switch (opaque) { 385 case WIN_COLOR_DEPTH_B5G5R5X1: 386 *alpha = WIN_COLOR_DEPTH_B5G5R5A1; 387 return 0; 388 389 case WIN_COLOR_DEPTH_X1B5G5R5: 390 *alpha = WIN_COLOR_DEPTH_A1B5G5R5; 391 return 0; 392 393 case WIN_COLOR_DEPTH_R8G8B8X8: 394 *alpha = WIN_COLOR_DEPTH_R8G8B8A8; 395 return 0; 396 397 case WIN_COLOR_DEPTH_B8G8R8X8: 398 *alpha = WIN_COLOR_DEPTH_B8G8R8A8; 399 return 0; 400 401 case WIN_COLOR_DEPTH_B5G6R5: 402 *alpha = opaque; 403 return 0; 404 } 405 406 return -EINVAL; 407 } 408 409 /* 410 * This is applicable to Tegra20 and Tegra30 only where the opaque formats can 411 * be emulated using the alpha formats and alpha blending disabled. 412 */ 413 static int tegra_plane_setup_opacity(struct tegra_plane *tegra, 414 struct tegra_plane_state *state) 415 { 416 unsigned int format; 417 int err; 418 419 switch (state->format) { 420 case WIN_COLOR_DEPTH_B5G5R5A1: 421 case WIN_COLOR_DEPTH_A1B5G5R5: 422 case WIN_COLOR_DEPTH_R8G8B8A8: 423 case WIN_COLOR_DEPTH_B8G8R8A8: 424 state->opaque = false; 425 break; 426 427 default: 428 err = tegra_plane_format_get_alpha(state->format, &format); 429 if (err < 0) 430 return err; 431 432 state->format = format; 433 state->opaque = true; 434 break; 435 } 436 437 return 0; 438 } 439 440 static int tegra_plane_check_transparency(struct tegra_plane *tegra, 441 struct tegra_plane_state *state) 442 { 443 struct drm_plane_state *old, *plane_state; 444 struct drm_plane *plane; 445 446 old = drm_atomic_get_old_plane_state(state->base.state, &tegra->base); 447 448 /* check if zpos / transparency changed */ 449 if (old->normalized_zpos == state->base.normalized_zpos && 450 to_tegra_plane_state(old)->opaque == state->opaque) 451 return 0; 452 453 /* include all sibling planes into this commit */ 454 drm_for_each_plane(plane, tegra->base.dev) { 455 struct tegra_plane *p = to_tegra_plane(plane); 456 457 /* skip this plane and planes on different CRTCs */ 458 if (p == tegra || p->dc != tegra->dc) 459 continue; 460 461 plane_state = drm_atomic_get_plane_state(state->base.state, 462 plane); 463 if (IS_ERR(plane_state)) 464 return PTR_ERR(plane_state); 465 } 466 467 return 1; 468 } 469 470 static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, 471 struct tegra_plane *other) 472 { 473 unsigned int index = 0, i; 474 475 WARN_ON(plane == other); 476 477 for (i = 0; i < 3; i++) { 478 if (i == plane->index) 479 continue; 480 481 if (i == other->index) 482 break; 483 484 index++; 485 } 486 487 return index; 488 } 489 490 static void tegra_plane_update_transparency(struct tegra_plane *tegra, 491 struct tegra_plane_state *state) 492 { 493 struct drm_plane_state *new; 494 struct drm_plane *plane; 495 unsigned int i; 496 497 for_each_new_plane_in_state(state->base.state, plane, new, i) { 498 struct tegra_plane *p = to_tegra_plane(plane); 499 unsigned index; 500 501 /* skip this plane and planes on different CRTCs */ 502 if (p == tegra || p->dc != tegra->dc) 503 continue; 504 505 index = tegra_plane_get_overlap_index(tegra, p); 506 507 if (new->fb && __drm_format_has_alpha(new->fb->format->format)) 508 state->blending[index].alpha = true; 509 else 510 state->blending[index].alpha = false; 511 512 if (new->normalized_zpos > state->base.normalized_zpos) 513 state->blending[index].top = true; 514 else 515 state->blending[index].top = false; 516 517 /* 518 * Missing framebuffer means that plane is disabled, in this 519 * case mark B / C window as top to be able to differentiate 520 * windows indices order in regards to zPos for the middle 521 * window X / Y registers programming. 522 */ 523 if (!new->fb) 524 state->blending[index].top = (index == 1); 525 } 526 } 527 528 static int tegra_plane_setup_transparency(struct tegra_plane *tegra, 529 struct tegra_plane_state *state) 530 { 531 struct tegra_plane_state *tegra_state; 532 struct drm_plane_state *new; 533 struct drm_plane *plane; 534 int err; 535 536 /* 537 * If planes zpos / transparency changed, sibling planes blending 538 * state may require adjustment and in this case they will be included 539 * into this atom commit, otherwise blending state is unchanged. 540 */ 541 err = tegra_plane_check_transparency(tegra, state); 542 if (err <= 0) 543 return err; 544 545 /* 546 * All planes are now in the atomic state, walk them up and update 547 * transparency state for each plane. 548 */ 549 drm_for_each_plane(plane, tegra->base.dev) { 550 struct tegra_plane *p = to_tegra_plane(plane); 551 552 /* skip planes on different CRTCs */ 553 if (p->dc != tegra->dc) 554 continue; 555 556 new = drm_atomic_get_new_plane_state(state->base.state, plane); 557 tegra_state = to_tegra_plane_state(new); 558 559 /* 560 * There is no need to update blending state for the disabled 561 * plane. 562 */ 563 if (new->fb) 564 tegra_plane_update_transparency(p, tegra_state); 565 } 566 567 return 0; 568 } 569 570 int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, 571 struct tegra_plane_state *state) 572 { 573 int err; 574 575 err = tegra_plane_setup_opacity(tegra, state); 576 if (err < 0) 577 return err; 578 579 err = tegra_plane_setup_transparency(tegra, state); 580 if (err < 0) 581 return err; 582 583 return 0; 584 } 585