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

Merge tag 'drm/tegra/for-5.14-rc1' of ssh://git.freedesktop.org/git/tegra/linux into drm-next

drm/tegra: Changes for v5.14-rc1

The two major changes here are fixed YUV support as well as scaling on
Tegra186 and later. This allows Tegra DRM to be used, for example, as a
video sink for the kmssink gstreamer plugin. The remainder of the
changes are minor fixes.

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Thierry Reding <thierry.reding@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210611165157.3569315-1-thierry.reding@gmail.com

+223 -20
+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
+26
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 ··· 714 711 #define DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR 0x442 715 712 #define DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR 0x446 716 713 714 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPA 0x500 715 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPB 0x501 716 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPC 0x502 717 + #define MAX_PIXELS_5TAP444(x) ((x) & 0xffff) 718 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPD 0x503 719 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPE 0x504 720 + #define MAX_PIXELS_2TAP444(x) ((x) & 0xffff) 721 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPF 0x505 722 + 717 723 #define DC_WIN_CORE_WINDOWGROUP_SET_CONTROL 0x702 718 724 #define OWNER_MASK (0xf << 0) 719 725 #define OWNER(x) (((x) & 0xf) << 0) 720 726 721 727 #define DC_WIN_CROPPED_SIZE 0x706 722 728 729 + #define DC_WIN_SET_INPUT_SCALER_H_START_PHASE 0x707 730 + #define DC_WIN_SET_INPUT_SCALER_V_START_PHASE 0x708 731 + 723 732 #define DC_WIN_PLANAR_STORAGE 0x709 724 733 #define PITCH(x) (((x) >> 6) & 0x1fff) 734 + 735 + #define DC_WIN_PLANAR_STORAGE_UV 0x70a 736 + #define PITCH_U(x) ((((x) >> 6) & 0x1fff) << 0) 737 + #define PITCH_V(x) ((((x) >> 6) & 0x1fff) << 16) 738 + 739 + #define DC_WIN_SET_INPUT_SCALER_HPHASE_INCR 0x70b 740 + #define DC_WIN_SET_INPUT_SCALER_VPHASE_INCR 0x70c 725 741 726 742 #define DC_WIN_SET_PARAMS 0x70d 727 743 #define CLAMP_BEFORE_BLEND (1 << 15) ··· 761 739 #define HORIZONTAL_TAPS_5 (4 << 3) 762 740 #define VERTICAL_TAPS_2 (1 << 0) 763 741 #define VERTICAL_TAPS_5 (4 << 0) 742 + 743 + #define DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF 0x70f 744 + #define COEFF_INDEX(x) (((x) & 0xff) << 15) 745 + #define COEFF_DATA(x) (((x) & 0x3ff) << 0) 764 746 765 747 #define DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE 0x711 766 748 #define INPUT_SCALER_USE422 (1 << 2)
+1 -3
drivers/gpu/drm/tegra/dpaux.c
··· 467 467 return PTR_ERR(dpaux->regs); 468 468 469 469 dpaux->irq = platform_get_irq(pdev, 0); 470 - if (dpaux->irq < 0) { 471 - dev_err(&pdev->dev, "failed to get IRQ\n"); 470 + if (dpaux->irq < 0) 472 471 return -ENXIO; 473 - } 474 472 475 473 if (!pdev->dev.pm_domain) { 476 474 dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
+172 -10
drivers/gpu/drm/tegra/hub.c
··· 23 23 #include "dc.h" 24 24 #include "plane.h" 25 25 26 + #define NFB 24 27 + 26 28 static const u32 tegra_shared_plane_formats[] = { 27 29 DRM_FORMAT_ARGB1555, 28 30 DRM_FORMAT_RGB565, ··· 294 292 return 0; 295 293 } 296 294 295 + static void tegra_shared_plane_setup_scaler(struct tegra_plane *plane) 296 + { 297 + static const unsigned int coeffs[192] = { 298 + 0x00000000, 0x3c70e400, 0x3bb037e4, 0x0c51cc9c, 299 + 0x00100001, 0x3bf0dbfa, 0x3d00f406, 0x3fe003ff, 300 + 0x00300002, 0x3b80cbf5, 0x3da1040d, 0x3fb003fe, 301 + 0x00400002, 0x3b20bff1, 0x3e511015, 0x3f9003fc, 302 + 0x00500002, 0x3ad0b3ed, 0x3f21201d, 0x3f5003fb, 303 + 0x00500003, 0x3aa0a3e9, 0x3ff13026, 0x3f2007f9, 304 + 0x00500403, 0x3a7097e6, 0x00e1402f, 0x3ee007f7, 305 + 0x00500403, 0x3a608be4, 0x01d14c38, 0x3ea00bf6, 306 + 0x00500403, 0x3a507fe2, 0x02e15c42, 0x3e500ff4, 307 + 0x00500402, 0x3a6073e1, 0x03f16c4d, 0x3e000ff2, 308 + 0x00400402, 0x3a706be0, 0x05117858, 0x3db013f0, 309 + 0x00300402, 0x3a905fe0, 0x06318863, 0x3d6017ee, 310 + 0x00300402, 0x3ab057e0, 0x0771986e, 0x3d001beb, 311 + 0x00200001, 0x3af04fe1, 0x08a1a47a, 0x3cb023e9, 312 + 0x00100001, 0x3b2047e2, 0x09e1b485, 0x3c6027e7, 313 + 0x00100000, 0x3b703fe2, 0x0b11c091, 0x3c002fe6, 314 + 0x3f203800, 0x0391103f, 0x3ff0a014, 0x0811606c, 315 + 0x3f2037ff, 0x0351083c, 0x03e11842, 0x3f203c00, 316 + 0x3f302fff, 0x03010439, 0x04311c45, 0x3f104401, 317 + 0x3f302fff, 0x02c0fc35, 0x04812448, 0x3f104802, 318 + 0x3f4027ff, 0x0270f832, 0x04c1284b, 0x3f205003, 319 + 0x3f4023ff, 0x0230f030, 0x0511304e, 0x3f205403, 320 + 0x3f601fff, 0x01f0e82d, 0x05613451, 0x3f205c04, 321 + 0x3f701bfe, 0x01b0e02a, 0x05a13c54, 0x3f306006, 322 + 0x3f7017fe, 0x0170d827, 0x05f14057, 0x3f406807, 323 + 0x3f8017ff, 0x0140d424, 0x0641445a, 0x3f406c08, 324 + 0x3fa013ff, 0x0100cc22, 0x0681485d, 0x3f507409, 325 + 0x3fa00fff, 0x00d0c41f, 0x06d14c60, 0x3f607c0b, 326 + 0x3fc00fff, 0x0090bc1c, 0x07115063, 0x3f80840c, 327 + 0x3fd00bff, 0x0070b41a, 0x07515465, 0x3f908c0e, 328 + 0x3fe007ff, 0x0040b018, 0x07915868, 0x3fb0900f, 329 + 0x3ff00400, 0x0010a816, 0x07d15c6a, 0x3fd09811, 330 + 0x00a04c0e, 0x0460f442, 0x0240a827, 0x05c15859, 331 + 0x0090440d, 0x0440f040, 0x0480fc43, 0x00b05010, 332 + 0x0080400c, 0x0410ec3e, 0x04910044, 0x00d05411, 333 + 0x0070380b, 0x03f0e83d, 0x04b10846, 0x00e05812, 334 + 0x0060340a, 0x03d0e43b, 0x04d10c48, 0x00f06013, 335 + 0x00503009, 0x03b0e039, 0x04e11449, 0x01106415, 336 + 0x00402c08, 0x0390d838, 0x05011c4b, 0x01206c16, 337 + 0x00302807, 0x0370d436, 0x0511204c, 0x01407018, 338 + 0x00302406, 0x0340d034, 0x0531244e, 0x01507419, 339 + 0x00202005, 0x0320cc32, 0x05412c50, 0x01707c1b, 340 + 0x00101c04, 0x0300c431, 0x05613451, 0x0180801d, 341 + 0x00101803, 0x02e0c02f, 0x05713853, 0x01a0881e, 342 + 0x00101002, 0x02b0bc2d, 0x05814054, 0x01c08c20, 343 + 0x00000c02, 0x02a0b82c, 0x05914455, 0x01e09421, 344 + 0x00000801, 0x0280b02a, 0x05a14c57, 0x02009c23, 345 + 0x00000400, 0x0260ac28, 0x05b15458, 0x0220a025, 346 + }; 347 + unsigned int ratio, row, column; 348 + 349 + for (ratio = 0; ratio <= 2; ratio++) { 350 + for (row = 0; row <= 15; row++) { 351 + for (column = 0; column <= 3; column++) { 352 + unsigned int index = (ratio << 6) + (row << 2) + column; 353 + u32 value; 354 + 355 + value = COEFF_INDEX(index) | COEFF_DATA(coeffs[index]); 356 + tegra_plane_writel(plane, value, 357 + DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF); 358 + } 359 + } 360 + } 361 + } 362 + 297 363 static void tegra_dc_assign_shared_plane(struct tegra_dc *dc, 298 364 struct tegra_plane *plane) 299 365 { ··· 406 336 value |= THREAD_NUM(plane->base.index); 407 337 value |= THREAD_GROUP_ENABLE; 408 338 tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_THREAD_GROUP); 339 + 340 + tegra_shared_plane_setup_scaler(plane); 409 341 410 342 tegra_shared_plane_update(plane); 411 343 tegra_shared_plane_activate(plane); ··· 516 444 host1x_client_suspend(&dc->client); 517 445 } 518 446 447 + static inline u32 compute_phase_incr(fixed20_12 in, unsigned int out) 448 + { 449 + u64 tmp, tmp1, tmp2; 450 + 451 + tmp = (u64)dfixed_trunc(in); 452 + tmp2 = (u64)out; 453 + tmp1 = (tmp << NFB) + (tmp2 >> 1); 454 + do_div(tmp1, tmp2); 455 + 456 + return lower_32_bits(tmp1); 457 + } 458 + 519 459 static void tegra_shared_plane_atomic_update(struct drm_plane *plane, 520 460 struct drm_atomic_state *state) 521 461 { ··· 538 454 unsigned int zpos = new_state->normalized_zpos; 539 455 struct drm_framebuffer *fb = new_state->fb; 540 456 struct tegra_plane *p = to_tegra_plane(plane); 541 - dma_addr_t base; 542 - u32 value; 457 + u32 value, min_width, bypass = 0; 458 + dma_addr_t base, addr_flag = 0; 459 + unsigned int bpc; 460 + bool yuv, planar; 543 461 int err; 544 462 545 463 /* rien ne va plus */ ··· 558 472 dev_err(dc->dev, "failed to resume: %d\n", err); 559 473 return; 560 474 } 475 + 476 + yuv = tegra_plane_format_is_yuv(tegra_plane_state->format, &planar, &bpc); 561 477 562 478 tegra_dc_assign_shared_plane(dc, p); 563 479 ··· 579 491 value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - zpos); 580 492 tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL); 581 493 582 - /* bypass scaling */ 494 + /* scaling */ 495 + min_width = min(new_state->src_w >> 16, new_state->crtc_w); 496 + 497 + value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPC); 498 + 499 + if (min_width < MAX_PIXELS_5TAP444(value)) { 500 + value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5; 501 + } else { 502 + value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPE); 503 + 504 + if (min_width < MAX_PIXELS_2TAP444(value)) 505 + value = HORIZONTAL_TAPS_2 | VERTICAL_TAPS_2; 506 + else 507 + dev_err(dc->dev, "invalid minimum width: %u\n", min_width); 508 + } 509 + 583 510 value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5; 584 511 tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER); 585 512 586 - value = INPUT_SCALER_VBYPASS | INPUT_SCALER_HBYPASS; 587 - tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE); 513 + if (new_state->src_w != new_state->crtc_w << 16) { 514 + fixed20_12 width = dfixed_init(new_state->src_w >> 16); 515 + u32 incr = compute_phase_incr(width, new_state->crtc_w) & ~0x1; 516 + u32 init = (1 << (NFB - 1)) + (incr >> 1); 517 + 518 + tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_HPHASE_INCR); 519 + tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_H_START_PHASE); 520 + } else { 521 + bypass |= INPUT_SCALER_HBYPASS; 522 + } 523 + 524 + if (new_state->src_h != new_state->crtc_h << 16) { 525 + fixed20_12 height = dfixed_init(new_state->src_h >> 16); 526 + u32 incr = compute_phase_incr(height, new_state->crtc_h) & ~0x1; 527 + u32 init = (1 << (NFB - 1)) + (incr >> 1); 528 + 529 + tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_VPHASE_INCR); 530 + tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_V_START_PHASE); 531 + } else { 532 + bypass |= INPUT_SCALER_VBYPASS; 533 + } 534 + 535 + tegra_plane_writel(p, bypass, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE); 588 536 589 537 /* disable compression */ 590 538 tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL); 591 - 592 - base = tegra_plane_state->iova[0] + fb->offsets[0]; 593 539 594 540 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT 595 541 /* ··· 632 510 * dGPU sector layout. 633 511 */ 634 512 if (tegra_plane_state->tiling.sector_layout == TEGRA_BO_SECTOR_LAYOUT_GPU) 635 - base |= BIT_ULL(39); 513 + addr_flag = BIT_ULL(39); 636 514 #endif 515 + 516 + base = tegra_plane_state->iova[0] + fb->offsets[0]; 517 + base |= addr_flag; 637 518 638 519 tegra_plane_writel(p, tegra_plane_state->format, DC_WIN_COLOR_DEPTH); 639 520 tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS); ··· 651 526 value = WIN_ENABLE | COLOR_EXPAND; 652 527 tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); 653 528 654 - value = V_SIZE(new_state->crtc_h) | H_SIZE(new_state->crtc_w); 529 + value = V_SIZE(new_state->src_h >> 16) | H_SIZE(new_state->src_w >> 16); 655 530 tegra_plane_writel(p, value, DC_WIN_CROPPED_SIZE); 656 531 657 532 tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI); ··· 660 535 value = PITCH(fb->pitches[0]); 661 536 tegra_plane_writel(p, value, DC_WIN_PLANAR_STORAGE); 662 537 663 - 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 + 664 576 tegra_plane_writel(p, value, DC_WIN_SET_PARAMS); 665 577 666 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
-2
drivers/gpu/drm/tegra/vic.c
··· 148 148 hdr = vic->falcon.firmware.virt; 149 149 fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET); 150 150 151 - falcon_execute_method(&vic->falcon, VIC_SET_APPLICATION_ID, 1); 152 - 153 151 /* Old VIC firmware needs kernel help with setting up FCE microcode. */ 154 152 if (fce_bin_data_offset != 0x0 && fce_bin_data_offset != 0xa5a5a5a5) { 155 153 hdr = vic->falcon.firmware.virt +
-1
drivers/gpu/drm/tegra/vic.h
··· 8 8 9 9 /* VIC methods */ 10 10 11 - #define VIC_SET_APPLICATION_ID 0x00000200 12 11 #define VIC_SET_FCE_UCODE_SIZE 0x0000071C 13 12 #define VIC_SET_FCE_UCODE_OFFSET 0x0000072C 14 13