Skip to content

Commit ecc583e

Browse files
committed
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>
1 parent e16efff commit ecc583e

2 files changed

Lines changed: 144 additions & 5 deletions

File tree

drivers/gpu/drm/tegra/dc.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,19 +714,34 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
714714
#define DC_DISP_PCALC_HEAD_SET_CROPPED_POINT_IN_CURSOR 0x442
715715
#define DC_DISP_PCALC_HEAD_SET_CROPPED_SIZE_IN_CURSOR 0x446
716716

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+
717726
#define DC_WIN_CORE_WINDOWGROUP_SET_CONTROL 0x702
718727
#define OWNER_MASK (0xf << 0)
719728
#define OWNER(x) (((x) & 0xf) << 0)
720729

721730
#define DC_WIN_CROPPED_SIZE 0x706
722731

732+
#define DC_WIN_SET_INPUT_SCALER_H_START_PHASE 0x707
733+
#define DC_WIN_SET_INPUT_SCALER_V_START_PHASE 0x708
734+
723735
#define DC_WIN_PLANAR_STORAGE 0x709
724736
#define PITCH(x) (((x) >> 6) & 0x1fff)
725737

726738
#define DC_WIN_PLANAR_STORAGE_UV 0x70a
727739
#define PITCH_U(x) ((((x) >> 6) & 0x1fff) << 0)
728740
#define PITCH_V(x) ((((x) >> 6) & 0x1fff) << 16)
729741

742+
#define DC_WIN_SET_INPUT_SCALER_HPHASE_INCR 0x70b
743+
#define DC_WIN_SET_INPUT_SCALER_VPHASE_INCR 0x70c
744+
730745
#define DC_WIN_SET_PARAMS 0x70d
731746
#define CLAMP_BEFORE_BLEND (1 << 15)
732747
#define DEGAMMA_NONE (0 << 13)
@@ -747,6 +762,10 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
747762
#define VERTICAL_TAPS_2 (1 << 0)
748763
#define VERTICAL_TAPS_5 (4 << 0)
749764

765+
#define DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF 0x70f
766+
#define COEFF_INDEX(x) (((x) & 0xff) << 15)
767+
#define COEFF_DATA(x) (((x) & 0x3ff) << 0)
768+
750769
#define DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE 0x711
751770
#define INPUT_SCALER_USE422 (1 << 2)
752771
#define INPUT_SCALER_VBYPASS (1 << 1)

drivers/gpu/drm/tegra/hub.c

Lines changed: 125 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "dc.h"
2424
#include "plane.h"
2525

26+
#define NFB 24
27+
2628
static const u32 tegra_shared_plane_formats[] = {
2729
DRM_FORMAT_ARGB1555,
2830
DRM_FORMAT_RGB565,
@@ -292,6 +294,74 @@ static int tegra_shared_plane_set_owner(struct tegra_plane *plane,
292294
return 0;
293295
}
294296

297+
static void tegra_shared_plane_setup_scaler(struct tegra_plane *plane)
298+
{
299+
static const unsigned int coeffs[192] = {
300+
0x00000000, 0x3c70e400, 0x3bb037e4, 0x0c51cc9c,
301+
0x00100001, 0x3bf0dbfa, 0x3d00f406, 0x3fe003ff,
302+
0x00300002, 0x3b80cbf5, 0x3da1040d, 0x3fb003fe,
303+
0x00400002, 0x3b20bff1, 0x3e511015, 0x3f9003fc,
304+
0x00500002, 0x3ad0b3ed, 0x3f21201d, 0x3f5003fb,
305+
0x00500003, 0x3aa0a3e9, 0x3ff13026, 0x3f2007f9,
306+
0x00500403, 0x3a7097e6, 0x00e1402f, 0x3ee007f7,
307+
0x00500403, 0x3a608be4, 0x01d14c38, 0x3ea00bf6,
308+
0x00500403, 0x3a507fe2, 0x02e15c42, 0x3e500ff4,
309+
0x00500402, 0x3a6073e1, 0x03f16c4d, 0x3e000ff2,
310+
0x00400402, 0x3a706be0, 0x05117858, 0x3db013f0,
311+
0x00300402, 0x3a905fe0, 0x06318863, 0x3d6017ee,
312+
0x00300402, 0x3ab057e0, 0x0771986e, 0x3d001beb,
313+
0x00200001, 0x3af04fe1, 0x08a1a47a, 0x3cb023e9,
314+
0x00100001, 0x3b2047e2, 0x09e1b485, 0x3c6027e7,
315+
0x00100000, 0x3b703fe2, 0x0b11c091, 0x3c002fe6,
316+
0x3f203800, 0x0391103f, 0x3ff0a014, 0x0811606c,
317+
0x3f2037ff, 0x0351083c, 0x03e11842, 0x3f203c00,
318+
0x3f302fff, 0x03010439, 0x04311c45, 0x3f104401,
319+
0x3f302fff, 0x02c0fc35, 0x04812448, 0x3f104802,
320+
0x3f4027ff, 0x0270f832, 0x04c1284b, 0x3f205003,
321+
0x3f4023ff, 0x0230f030, 0x0511304e, 0x3f205403,
322+
0x3f601fff, 0x01f0e82d, 0x05613451, 0x3f205c04,
323+
0x3f701bfe, 0x01b0e02a, 0x05a13c54, 0x3f306006,
324+
0x3f7017fe, 0x0170d827, 0x05f14057, 0x3f406807,
325+
0x3f8017ff, 0x0140d424, 0x0641445a, 0x3f406c08,
326+
0x3fa013ff, 0x0100cc22, 0x0681485d, 0x3f507409,
327+
0x3fa00fff, 0x00d0c41f, 0x06d14c60, 0x3f607c0b,
328+
0x3fc00fff, 0x0090bc1c, 0x07115063, 0x3f80840c,
329+
0x3fd00bff, 0x0070b41a, 0x07515465, 0x3f908c0e,
330+
0x3fe007ff, 0x0040b018, 0x07915868, 0x3fb0900f,
331+
0x3ff00400, 0x0010a816, 0x07d15c6a, 0x3fd09811,
332+
0x00a04c0e, 0x0460f442, 0x0240a827, 0x05c15859,
333+
0x0090440d, 0x0440f040, 0x0480fc43, 0x00b05010,
334+
0x0080400c, 0x0410ec3e, 0x04910044, 0x00d05411,
335+
0x0070380b, 0x03f0e83d, 0x04b10846, 0x00e05812,
336+
0x0060340a, 0x03d0e43b, 0x04d10c48, 0x00f06013,
337+
0x00503009, 0x03b0e039, 0x04e11449, 0x01106415,
338+
0x00402c08, 0x0390d838, 0x05011c4b, 0x01206c16,
339+
0x00302807, 0x0370d436, 0x0511204c, 0x01407018,
340+
0x00302406, 0x0340d034, 0x0531244e, 0x01507419,
341+
0x00202005, 0x0320cc32, 0x05412c50, 0x01707c1b,
342+
0x00101c04, 0x0300c431, 0x05613451, 0x0180801d,
343+
0x00101803, 0x02e0c02f, 0x05713853, 0x01a0881e,
344+
0x00101002, 0x02b0bc2d, 0x05814054, 0x01c08c20,
345+
0x00000c02, 0x02a0b82c, 0x05914455, 0x01e09421,
346+
0x00000801, 0x0280b02a, 0x05a14c57, 0x02009c23,
347+
0x00000400, 0x0260ac28, 0x05b15458, 0x0220a025,
348+
};
349+
unsigned int ratio, row, column;
350+
351+
for (ratio = 0; ratio <= 2; ratio++) {
352+
for (row = 0; row <= 15; row++) {
353+
for (column = 0; column <= 3; column++) {
354+
unsigned int index = (ratio << 6) + (row << 2) + column;
355+
u32 value;
356+
357+
value = COEFF_INDEX(index) | COEFF_DATA(coeffs[index]);
358+
tegra_plane_writel(plane, value,
359+
DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_COEFF);
360+
}
361+
}
362+
}
363+
}
364+
295365
static void tegra_dc_assign_shared_plane(struct tegra_dc *dc,
296366
struct tegra_plane *plane)
297367
{
@@ -337,6 +407,8 @@ static void tegra_dc_assign_shared_plane(struct tegra_dc *dc,
337407
value |= THREAD_GROUP_ENABLE;
338408
tegra_plane_writel(plane, value, DC_WIN_CORE_IHUB_THREAD_GROUP);
339409

410+
tegra_shared_plane_setup_scaler(plane);
411+
340412
tegra_shared_plane_update(plane);
341413
tegra_shared_plane_activate(plane);
342414
}
@@ -444,6 +516,18 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane,
444516
host1x_client_suspend(&dc->client);
445517
}
446518

519+
static inline u32 compute_phase_incr(fixed20_12 in, unsigned int out)
520+
{
521+
u64 tmp, tmp1, tmp2;
522+
523+
tmp = (u64)dfixed_trunc(in);
524+
tmp2 = (u64)out;
525+
tmp1 = (tmp << NFB) + (tmp2 >> 1);
526+
do_div(tmp1, tmp2);
527+
528+
return lower_32_bits(tmp1);
529+
}
530+
447531
static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
448532
struct drm_atomic_state *state)
449533
{
@@ -454,10 +538,10 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
454538
unsigned int zpos = new_state->normalized_zpos;
455539
struct drm_framebuffer *fb = new_state->fb;
456540
struct tegra_plane *p = to_tegra_plane(plane);
541+
u32 value, min_width, bypass = 0;
457542
dma_addr_t base, addr_flag = 0;
458543
unsigned int bpc;
459544
bool yuv, planar;
460-
u32 value;
461545
int err;
462546

463547
/* rien ne va plus */
@@ -495,12 +579,48 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
495579
value = K2(255) | K1(255) | WINDOW_LAYER_DEPTH(255 - zpos);
496580
tegra_plane_writel(p, value, DC_WIN_BLEND_LAYER_CONTROL);
497581

498-
/* bypass scaling */
582+
/* scaling */
583+
min_width = min(new_state->src_w >> 16, new_state->crtc_w);
584+
585+
value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPC);
586+
587+
if (min_width < MAX_PIXELS_5TAP444(value)) {
588+
value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5;
589+
} else {
590+
value = tegra_plane_readl(p, DC_WINC_PRECOMP_WGRP_PIPE_CAPE);
591+
592+
if (min_width < MAX_PIXELS_2TAP444(value))
593+
value = HORIZONTAL_TAPS_2 | VERTICAL_TAPS_2;
594+
else
595+
dev_err(dc->dev, "invalid minimum width: %u\n", min_width);
596+
}
597+
499598
value = HORIZONTAL_TAPS_5 | VERTICAL_TAPS_5;
500599
tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_CONTROL_INPUT_SCALER);
501600

502-
value = INPUT_SCALER_VBYPASS | INPUT_SCALER_HBYPASS;
503-
tegra_plane_writel(p, value, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE);
601+
if (new_state->src_w != new_state->crtc_w << 16) {
602+
fixed20_12 width = dfixed_init(new_state->src_w >> 16);
603+
u32 incr = compute_phase_incr(width, new_state->crtc_w) & ~0x1;
604+
u32 init = (1 << (NFB - 1)) + (incr >> 1);
605+
606+
tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_HPHASE_INCR);
607+
tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_H_START_PHASE);
608+
} else {
609+
bypass |= INPUT_SCALER_HBYPASS;
610+
}
611+
612+
if (new_state->src_h != new_state->crtc_h << 16) {
613+
fixed20_12 height = dfixed_init(new_state->src_h >> 16);
614+
u32 incr = compute_phase_incr(height, new_state->crtc_h) & ~0x1;
615+
u32 init = (1 << (NFB - 1)) + (incr >> 1);
616+
617+
tegra_plane_writel(p, incr, DC_WIN_SET_INPUT_SCALER_VPHASE_INCR);
618+
tegra_plane_writel(p, init, DC_WIN_SET_INPUT_SCALER_V_START_PHASE);
619+
} else {
620+
bypass |= INPUT_SCALER_VBYPASS;
621+
}
622+
623+
tegra_plane_writel(p, bypass, DC_WIN_WINDOWGROUP_SET_INPUT_SCALER_USAGE);
504624

505625
/* disable compression */
506626
tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL);
@@ -531,7 +651,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane,
531651
value = WIN_ENABLE | COLOR_EXPAND;
532652
tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS);
533653

534-
value = V_SIZE(new_state->crtc_h) | H_SIZE(new_state->crtc_w);
654+
value = V_SIZE(new_state->src_h >> 16) | H_SIZE(new_state->src_w >> 16);
535655
tegra_plane_writel(p, value, DC_WIN_CROPPED_SIZE);
536656

537657
tegra_plane_writel(p, upper_32_bits(base), DC_WINBUF_START_ADDR_HI);

0 commit comments

Comments
 (0)