Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/tegra: hub: Fix YUV support

The driver currently exposes several YUV formats but fails to properly
program all the registers needed to display such formats. Add the right
programming sequences so that overlay windows can be used to accelerate
color format conversions in multimedia playback use-cases.

Signed-off-by: Thierry Reding <treding@nvidia.com>

+78 -9
+1 -1
drivers/gpu/drm/tegra/dc.c
··· 348 348 * For YUV planar modes, the number of bytes per pixel takes into 349 349 * account only the luma component and therefore is 1. 350 350 */ 351 - yuv = tegra_plane_format_is_yuv(window->format, &planar); 351 + yuv = tegra_plane_format_is_yuv(window->format, &planar, NULL); 352 352 if (!yuv) 353 353 bpp = window->bits_per_pixel / 8; 354 354 else
+7
drivers/gpu/drm/tegra/dc.h
··· 696 696 697 697 #define DC_WINBUF_START_ADDR_HI 0x80d 698 698 699 + #define DC_WINBUF_START_ADDR_HI_U 0x80f 700 + #define DC_WINBUF_START_ADDR_HI_V 0x811 701 + 699 702 #define DC_WINBUF_CDE_CONTROL 0x82f 700 703 #define ENABLE_SURFACE (1 << 0) 701 704 ··· 722 719 723 720 #define DC_WIN_PLANAR_STORAGE 0x709 724 721 #define PITCH(x) (((x) >> 6) & 0x1fff) 722 + 723 + #define DC_WIN_PLANAR_STORAGE_UV 0x70a 724 + #define PITCH_U(x) ((((x) >> 6) & 0x1fff) << 0) 725 + #define PITCH_V(x) ((((x) >> 6) & 0x1fff) << 16) 725 726 726 727 #define DC_WIN_SET_PARAMS 0x70d 727 728 #define CLAMP_BEFORE_BLEND (1 << 15)
+47 -5
drivers/gpu/drm/tegra/hub.c
··· 454 454 unsigned int zpos = new_state->normalized_zpos; 455 455 struct drm_framebuffer *fb = new_state->fb; 456 456 struct tegra_plane *p = to_tegra_plane(plane); 457 - dma_addr_t base; 457 + dma_addr_t base, addr_flag = 0; 458 + unsigned int bpc; 459 + bool yuv, planar; 458 460 u32 value; 459 461 int err; 460 462 ··· 474 472 dev_err(dc->dev, "failed to resume: %d\n", err); 475 473 return; 476 474 } 475 + 476 + yuv = tegra_plane_format_is_yuv(tegra_plane_state->format, &planar, &bpc); 477 477 478 478 tegra_dc_assign_shared_plane(dc, p); 479 479 ··· 505 501 /* disable compression */ 506 502 tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL); 507 503 508 - base = tegra_plane_state->iova[0] + fb->offsets[0]; 509 - 510 504 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 511 505 /* 512 506 * Physical address bit 39 in Tegra194 is used as a switch for special ··· 512 510 * dGPU sector layout. 513 511 */ 514 512 if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU) 515 - base |= BIT_ULL(39); 513 + addr_flag = BIT_ULL(39); 516 514 #endif 515 + 516 + base = tegra_plane_state->iova[0] + fb->offsets[0]; 517 + base |= addr_flag; 517 518 518 519 tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH); 519 520 tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS); ··· 540 535 value = PITCH(fb->pitches[0]); 541 536 tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE); 542 537 543 - value = CLAMP_BEFORE_BLEND | DEGAMMA_SRGB | INPUT_RANGE_FULL; 538 + if (yuv && planar) { 539 + base = tegra_plane_state->iova[1] + fb->offsets[1]; 540 + base |= addr_flag; 541 + 542 + tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_U); 543 + tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_U); 544 + 545 + base = tegra_plane_state->iova[2] + fb->offsets[2]; 546 + base |= addr_flag; 547 + 548 + tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI_V); 549 + tegra_plane_writel(p, lower_32_bits(base), DC_WINBUF_START_ADDR_V); 550 + 551 + value = PITCH_U(fb->pitches[2]) | PITCH_V(fb->pitches[2]); 552 + tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE_UV); 553 + } else { 554 + tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_U); 555 + tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_U); 556 + tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_V); 557 + tegra_plane_writel(p, 0, DC_WINBUF_START_ADDR_HI_V); 558 + tegra_plane_writel(p, 0, DC_WIN_PLANAR_STORAGE_UV); 559 + } 560 + 561 + value = CLAMP_BEFORE_BLEND | INPUT_RANGE_FULL; 562 + 563 + if (yuv) { 564 + if (bpc < 12) 565 + value |= DEGAMMA_YUV8_10; 566 + else 567 + value |= DEGAMMA_YUV12; 568 + 569 + /* XXX parameterize */ 570 + value |= COLOR_SPACE_YUV_2020; 571 + } else { 572 + if (!tegra_plane_format_is_indexed(tegra_plane_state->format)) 573 + value |= DEGAMMA_SRGB; 574 + } 575 + 544 576 tegra_plane_writel(p, value, DC_WIN_SET_PARAMS); 545 577 546 578 value = OFFSET_X(new_state->src_y >> 16) |
+21 -2
drivers/gpu/drm/tegra/plane.c
··· 375 375 return 0; 376 376 } 377 377 378 - bool tegra_plane_format_is_yuv(unsigned int format, bool *planar) 378 + bool tegra_plane_format_is_indexed(unsigned int format) 379 + { 380 + switch (format) { 381 + case WIN_COLOR_DEPTH_P1: 382 + case WIN_COLOR_DEPTH_P2: 383 + case WIN_COLOR_DEPTH_P4: 384 + case WIN_COLOR_DEPTH_P8: 385 + return true; 386 + } 387 + 388 + return false; 389 + } 390 + 391 + bool tegra_plane_format_is_yuv(unsigned int format, bool *planar, unsigned int *bpc) 379 392 { 380 393 switch (format) { 381 394 case WIN_COLOR_DEPTH_YCbCr422: 382 395 case WIN_COLOR_DEPTH_YUV422: 383 396 if (planar) 384 397 *planar = false; 398 + 399 + if (bpc) 400 + *bpc = 8; 385 401 386 402 return true; 387 403 ··· 411 395 case WIN_COLOR_DEPTH_YUV422RA: 412 396 if (planar) 413 397 *planar = true; 398 + 399 + if (bpc) 400 + *bpc = 8; 414 401 415 402 return true; 416 403 } ··· 440 421 static int tegra_plane_format_get_alpha(unsigned int opaque, 441 422 unsigned int *alpha) 442 423 { 443 - if (tegra_plane_format_is_yuv(opaque, NULL)) { 424 + if (tegra_plane_format_is_yuv(opaque, NULL, NULL)) { 444 425 *alpha = opaque; 445 426 return 0; 446 427 }
+2 -1
drivers/gpu/drm/tegra/plane.h
··· 74 74 struct drm_plane_state *state); 75 75 76 76 int tegra_plane_format(u32 fourcc, u32 *format, u32 *swap); 77 - bool tegra_plane_format_is_yuv(unsigned int format, bool *planar); 77 + bool tegra_plane_format_is_indexed(unsigned int format); 78 + bool tegra_plane_format_is_yuv(unsigned int format, bool *planar, unsigned int *bpc); 78 79 int tegra_plane_setup_legacy_state(struct tegra_plane *tegra, 79 80 struct tegra_plane_state *state); 80 81