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

drm/tegra: hub: Implement basic scaling support

Parameterize code in several places to allow scaling of windows. Note
that this currently still relies on static programming of the various
metering and memory pool allocation registers. This seems to work for
the common cases, but may eventually need to be updated to support
use-cases with multiple windows and higher bandwidth and latency
requirements.

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

+144 -5
+19
drivers/gpu/drm/tegra/dc.h
··· 714 714 #define DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR 0x442 715 715 #define DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR 0x446 716 716 717 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPA 0x500 718 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPB 0x501 719 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPC 0x502 720 + #define MAX_PIXELS_5TAP444(x) ((x) & 0xffff) 721 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPD 0x503 722 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPE 0x504 723 + #define MAX_PIXELS_2TAP444(x) ((x) & 0xffff) 724 + #define DC_WINC_PRECOMP_WGRP_PIPE_CAPF 0x505 725 + 717 726 #define DC_WIN_CORE_WINDOWGROUP_SET_CONTROL 0x702 718 727 #define OWNER_MASK (0xf << 0) 719 728 #define OWNER(x) (((x) & 0xf) << 0) 720 729 721 730 #define DC_WIN_CROPPED_SIZE 0x706 731 + 732 + #define DC_WIN_SET_INPUT_SCALER_H_START_PHASE 0x707 733 + #define DC_WIN_SET_INPUT_SCALER_V_START_PHASE 0x708 722 734 723 735 #define DC_WIN_PLANAR_STORAGE 0x709 724 736 #define PITCH(x) (((x) >> 6) & 0x1fff) ··· 738 726 #define DC_WIN_PLANAR_STORAGE_UV 0x70a 739 727 #define PITCH_U(x) ((((x) >> 6) & 0x1fff) << 0) 740 728 #define PITCH_V(x) ((((x) >> 6) & 0x1fff) << 16) 729 + 730 + #define DC_WIN_SET_INPUT_SCALER_HPHASE_INCR 0x70b 731 + #define DC_WIN_SET_INPUT_SCALER_VPHASE_INCR 0x70c 741 732 742 733 #define DC_WIN_SET_PARAMS 0x70d 743 734 #define CLAMP_BEFORE_BLEND (1 << 15) ··· 761 746 #define HORIZONTAL_TAPS_5 (4 << 3) 762 747 #define VERTICAL_TAPS_2 (1 << 0) 763 748 #define VERTICAL_TAPS_5 (4 << 0) 749 + 750 + #define DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF 0x70f 751 + #define COEFF_INDEX(x) (((x) & 0xff) << 15) 752 + #define COEFF_DATA(x) (((x) & 0x3ff) << 0) 764 753 765 754 #define DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE 0x711 766 755 #define INPUT_SCALER_USE422 (1 << 2)
+125 -5
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); 457 + u32 value, min_width, bypass = 0; 541 458 dma_addr_t base, addr_flag = 0; 542 459 unsigned int bpc; 543 460 bool yuv, planar; 544 - u32 value; 545 461 int err; 546 462 547 463 /* rien ne va plus */ ··· 579 495 value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - zpos); 580 496 tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL); 581 497 582 - /* bypass scaling */ 498 + /* scaling */ 499 + min_width = min(new_state->src_w >> 16, new_state->crtc_w); 500 + 501 + value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPC); 502 + 503 + if (min_width < MAX_PIXELS_5TAP444(value)) { 504 + value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5; 505 + } else { 506 + value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPE); 507 + 508 + if (min_width < MAX_PIXELS_2TAP444(value)) 509 + value = HORIZONTAL_TAPS_2 | VERTICAL_TAPS_2; 510 + else 511 + dev_err(dc->dev, "invalid minimum width: %u\n", min_width); 512 + } 513 + 583 514 value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5; 584 515 tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER); 585 516 586 - value = INPUT_SCALER_VBYPASS | INPUT_SCALER_HBYPASS; 587 - tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE); 517 + if (new_state->src_w != new_state->crtc_w << 16) { 518 + fixed20_12 width = dfixed_init(new_state->src_w >> 16); 519 + u32 incr = compute_phase_incr(width, new_state->crtc_w) & ~0x1; 520 + u32 init = (1 << (NFB - 1)) + (incr >> 1); 521 + 522 + tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_HPHASE_INCR); 523 + tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_H_START_PHASE); 524 + } else { 525 + bypass |= INPUT_SCALER_HBYPASS; 526 + } 527 + 528 + if (new_state->src_h != new_state->crtc_h << 16) { 529 + fixed20_12 height = dfixed_init(new_state->src_h >> 16); 530 + u32 incr = compute_phase_incr(height, new_state->crtc_h) & ~0x1; 531 + u32 init = (1 << (NFB - 1)) + (incr >> 1); 532 + 533 + tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_VPHASE_INCR); 534 + tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_V_START_PHASE); 535 + } else { 536 + bypass |= INPUT_SCALER_VBYPASS; 537 + } 538 + 539 + tegra_plane_writel(p, bypass, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE); 588 540 589 541 /* disable compression */ 590 542 tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL); ··· 651 531 value = WIN_ENABLE | COLOR_EXPAND; 652 532 tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); 653 533 654 - value = V_SIZE(new_state->crtc_h) | H_SIZE(new_state->crtc_w); 534 + value = V_SIZE(new_state->src_h >> 16) | H_SIZE(new_state->src_w >> 16); 655 535 tegra_plane_writel(p, value, DC_WIN_CROPPED_SIZE); 656 536 657 537 tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI);